1/*
2 context.cpp - wraps a gpgme key context
3 Copyright (C) 2003, 2007 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++/context.h>
26#include <gpgme++/eventloopinteractor.h>
27#include <gpgme++/trustitem.h>
28#include <gpgme++/assuanresult.h>
29#include <gpgme++/keylistresult.h>
30#include <gpgme++/keygenerationresult.h>
31#include <gpgme++/importresult.h>
32#include <gpgme++/decryptionresult.h>
33#include <gpgme++/verificationresult.h>
34#include <gpgme++/signingresult.h>
35#include <gpgme++/encryptionresult.h>
36#include <gpgme++/engineinfo.h>
37#include <gpgme++/editinteractor.h>
38#include <gpgme++/vfsmountresult.h>
39
40#include <gpgme++/interfaces/assuantransaction.h>
41#include <gpgme++/defaultassuantransaction.h>
42
43#include "callbacks.h"
44#include "data_p.h"
45#include "context_p.h"
46#include "util.h"
47
48#include <gpgme.h>
49
50#include <boost/scoped_array.hpp>
51
52#include <istream>
53#ifndef NDEBUG
54#include <iostream>
55using std::cerr;
56using std::endl;
57#endif
58
59#include <cassert>
60
61#include <qglobal.h>
62
63namespace GpgME {
64
65 static inline unsigned int xtoi_1( const char * str ) {
66 const unsigned int ch = *str;
67 const unsigned int result =
68 ch <= '9' ? ch - '0' :
69 ch <= 'F' ? ch - 'A' + 10 :
70 /* else */ ch - 'a' + 10 ;
71 return result < 16 ? result : 0 ;
72 }
73 static inline int xtoi_2( const char * str ) {
74 return xtoi_1( str ) * 16U + xtoi_1( str + 1 );
75 }
76
77#ifdef HAVE_GPGME_ASSUAN_ENGINE
78 static void percent_unescape( std::string & s, bool plus2space ) {
79 std::string::iterator src = s.begin(), dest = s.begin(), end = s.end();
80 while ( src != end ) {
81 if ( *src == '%' && end - src > 2 ) {
82 *dest++ = xtoi_2( &*++src );
83 src += 2;
84 } else if ( *src == '+' && plus2space ) {
85 *dest++ = ' ';
86 ++src;
87 } else {
88 *dest++ = *src++;
89 }
90 }
91 s.erase( dest, end );
92 }
93#endif
94
95 void initializeLibrary() {
96 gpgme_check_version( 0 );
97 }
98
99 Error initializeLibrary( int ) {
100 if ( gpgme_check_version( GPGME_VERSION ) ) {
101 return Error();
102 } else {
103 return Error::fromCode( GPG_ERR_USER_1 );
104 }
105 }
106
107 static void format_error( gpgme_error_t err, std::string & str ) {
108 char buffer[ 1024 ];
109 gpgme_strerror_r( err, buffer, sizeof buffer );
110 buffer[ sizeof buffer - 1 ] = '\0';
111 str = buffer;
112 }
113
114 const char * Error::source() const {
115 return gpgme_strsource( (gpgme_error_t)mErr );
116 }
117
118 const char * Error::asString() const {
119 if ( mMessage.empty() ) {
120 format_error( static_cast<gpgme_error_t>( mErr ), mMessage );
121 }
122 return mMessage.c_str();
123 }
124
125 int Error::code() const {
126 return gpgme_err_code( mErr );
127 }
128
129 int Error::sourceID() const {
130 return gpgme_err_source( mErr );
131 }
132
133 bool Error::isCanceled() const {
134 return code() == GPG_ERR_CANCELED;
135 }
136
137 int Error::toErrno() const {
138//#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
139 return gpgme_err_code_to_errno( static_cast<gpgme_err_code_t>( code() ) );
140//#else
141// return gpg_err_code_to_errno( static_cast<gpg_err_code_t>( code() ) );
142//#endif
143 }
144
145 // static
146 bool Error::hasSystemError() {
147#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
148 return gpgme_err_code_from_syserror() == GPG_ERR_MISSING_ERRNO ;
149#else
150 return gpg_err_code_from_syserror() == GPG_ERR_MISSING_ERRNO ;
151#endif
152 }
153
154 // static
155 void Error::setSystemError( gpg_err_code_t err ) {
156 setErrno( gpgme_err_code_to_errno( err ) );
157 }
158
159 // static
160 void Error::setErrno( int err ) {
161#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
162 gpgme_err_set_errno( err );
163#else
164 gpg_err_set_errno( err );
165#endif
166 }
167
168 // static
169 Error Error::fromSystemError( unsigned int src ) {
170#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
171 return Error( gpgme_err_make( static_cast<gpgme_err_source_t>( src ), gpgme_err_code_from_syserror() ) );
172#else
173 return Error( gpg_err_make( static_cast<gpg_err_source_t>( src ), gpg_err_code_from_syserror() ) );
174#endif
175 }
176
177 // static
178 Error Error::fromErrno( int err, unsigned int src ) {
179//#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
180 return Error( gpgme_err_make( static_cast<gpgme_err_source_t>( src ), gpgme_err_code_from_errno( err ) ) );
181//#else
182// return Error( gpg_err_make( static_cast<gpg_err_source_t>( src ), gpg_err_from_from_errno( err ) ) );
183//#endif
184 }
185
186 // static
187 Error Error::fromCode( unsigned int err, unsigned int src ) {
188//#ifdef HAVE_GPGME_GPG_ERROR_WRAPPERS
189 return Error( gpgme_err_make( static_cast<gpgme_err_source_t>( src ), static_cast<gpgme_err_code_t>( err ) ) );
190//#else
191// return Error( gpg_err_make( static_cast<gpg_err_source_t>( src ), static_cast<gpgme_err_code_t>( err ) ) );
192//#endif
193 }
194
195 std::ostream & operator<<( std::ostream & os, const Error & err ) {
196 return os << "GpgME::Error(" << err.encodedError() << " (" << err.asString() << "))";
197 }
198
199 Context::Context( gpgme_ctx_t ctx ) : d( new Private( ctx ) ) {
200 }
201
202 Context::~Context() {
203 delete d;
204 }
205
206 Context * Context::createForProtocol( Protocol proto ) {
207 gpgme_ctx_t ctx = 0;
208 if ( gpgme_new ( &ctx ) != 0 ) {
209 return 0;
210 }
211
212 switch ( proto ) {
213 case OpenPGP:
214 if ( gpgme_set_protocol( ctx, GPGME_PROTOCOL_OpenPGP ) != 0 ) {
215 gpgme_release( ctx );
216 return 0;
217 }
218 break;
219 case CMS:
220 if ( gpgme_set_protocol( ctx, GPGME_PROTOCOL_CMS ) != 0 ) {
221 gpgme_release( ctx );
222 return 0;
223 }
224 break;
225 default:
226 return 0;
227 }
228
229 return new Context( ctx );
230 }
231
232 std::auto_ptr<Context> Context::createForEngine( Engine eng, Error * error ) {
233 gpgme_ctx_t ctx = 0;
234 if ( const gpgme_error_t err = gpgme_new( &ctx ) ) {
235 if ( error ) {
236 *error = Error( err );
237 }
238 return std::auto_ptr<Context>();
239 }
240
241 switch ( eng ) {
242 case AssuanEngine:
243#ifdef HAVE_GPGME_ASSUAN_ENGINE
244 if ( const gpgme_error_t err = gpgme_set_protocol( ctx, GPGME_PROTOCOL_ASSUAN ) ) {
245 gpgme_release( ctx );
246 if ( error ) {
247 *error = Error( err );
248 }
249 return std::auto_ptr<Context>();
250 }
251 break;
252#else
253 if ( error ) {
254 *error = Error::fromCode( GPG_ERR_NOT_SUPPORTED );
255 }
256 return std::auto_ptr<Context>();
257#endif
258 case G13Engine:
259#ifdef HAVE_GPGME_G13_VFS
260 if ( const gpgme_error_t err = gpgme_set_protocol( ctx, GPGME_PROTOCOL_G13 ) ) {
261 gpgme_release( ctx );
262 if ( error ) {
263 *error = Error( err );
264 }
265 return std::auto_ptr<Context>();
266 }
267 break;
268#else
269 if ( error ) {
270 *error = Error::fromCode( GPG_ERR_NOT_SUPPORTED );
271 }
272 return std::auto_ptr<Context>();
273#endif
274 default:
275 if ( error ) {
276 *error = Error::fromCode( GPG_ERR_INV_ARG );
277 }
278 return std::auto_ptr<Context>();
279 }
280
281 if ( error ) {
282 *error = Error();
283 }
284
285 return std::auto_ptr<Context>( new Context( ctx ) );
286 }
287
288 //
289 //
290 // Context::Private
291 //
292 //
293
294 Context::Private::Private( gpgme_ctx_t c )
295 : ctx( c ),
296 iocbs( 0 ),
297 lastop( None ),
298 lasterr( GPG_ERR_NO_ERROR ),
299 lastAssuanInquireData( Data::null ),
300 lastAssuanTransaction(),
301 lastEditInteractor(),
302 lastCardEditInteractor()
303 {
304
305 }
306
307 Context::Private::~Private() {
308 if ( ctx ) {
309 gpgme_release( ctx );
310 }
311 ctx = 0;
312 delete iocbs;
313 }
314
315 //
316 //
317 // Context attributes:
318 //
319 //
320
321 Protocol Context::protocol() const {
322 gpgme_protocol_t p = gpgme_get_protocol( d->ctx );
323 switch ( p ) {
324 case GPGME_PROTOCOL_OpenPGP: return OpenPGP;
325 case GPGME_PROTOCOL_CMS: return CMS;
326 default: return UnknownProtocol;
327 }
328 }
329
330
331 void Context::setArmor( bool useArmor ) {
332 gpgme_set_armor( d->ctx, int( useArmor ) );
333 }
334 bool Context::armor() const {
335 return gpgme_get_armor( d->ctx );
336 }
337
338 void Context::setTextMode( bool useTextMode ) {
339 gpgme_set_textmode( d->ctx, int( useTextMode ) );
340 }
341 bool Context::textMode() const {
342 return gpgme_get_textmode( d->ctx );
343 }
344
345 void Context::setIncludeCertificates( int which ) {
346 if ( which == DefaultCertificates ) {
347#ifdef HAVE_GPGME_INCLUDE_CERTS_DEFAULT
348 which = GPGME_INCLUDE_CERTS_DEFAULT;
349#else
350 which = 1;
351#endif
352 }
353 gpgme_set_include_certs( d->ctx, which );
354 }
355
356 int Context::includeCertificates() const {
357 return gpgme_get_include_certs( d->ctx );
358 }
359
360 void Context::setKeyListMode( unsigned int mode ) {
361 gpgme_set_keylist_mode( d->ctx, add_to_gpgme_keylist_mode_t( 0, mode ) );
362 }
363
364 void Context::addKeyListMode( unsigned int mode ) {
365 const unsigned int cur = gpgme_get_keylist_mode( d->ctx );
366 gpgme_set_keylist_mode( d->ctx, add_to_gpgme_keylist_mode_t( cur, mode ) );
367 }
368
369
370 unsigned int Context::keyListMode() const {
371 return convert_from_gpgme_keylist_mode_t( gpgme_get_keylist_mode( d->ctx ) );
372 }
373
374 void Context::setProgressProvider( ProgressProvider * provider ) {
375 gpgme_set_progress_cb( d->ctx, provider ? &progress_callback : 0, provider );
376 }
377 ProgressProvider * Context::progressProvider() const {
378 void * pp = 0;
379 gpgme_progress_cb_t pcb = &progress_callback;
380 gpgme_get_progress_cb( d->ctx, &pcb, &pp );
381 return static_cast<ProgressProvider*>( pp );
382 }
383
384 void Context::setPassphraseProvider( PassphraseProvider * provider ) {
385 gpgme_set_passphrase_cb( d->ctx, provider ? &passphrase_callback : 0, provider );
386 }
387
388 PassphraseProvider * Context::passphraseProvider() const {
389 void * pp = 0;
390 gpgme_passphrase_cb_t pcb = &passphrase_callback;
391 gpgme_get_passphrase_cb( d->ctx, &pcb, &pp );
392 return static_cast<PassphraseProvider*>( pp );
393 }
394
395 void Context::setManagedByEventLoopInteractor( bool manage ) {
396 if ( !EventLoopInteractor::instance() ) {
397#ifndef NDEBUG
398 cerr << "Context::setManagedByEventLoopInteractor(): "
399 "You must create an instance of EventLoopInteractor "
400 "before using anything that needs one." << endl;
401#endif
402 return;
403 }
404 if ( manage ) {
405 EventLoopInteractor::instance()->manage( this );
406 } else {
407 EventLoopInteractor::instance()->unmanage( this );
408 }
409 }
410 bool Context::managedByEventLoopInteractor() const {
411 return d->iocbs != 0;
412 }
413
414
415 void Context::installIOCallbacks( gpgme_io_cbs * iocbs ) {
416 if ( !iocbs ) {
417 uninstallIOCallbacks();
418 return;
419 }
420 gpgme_set_io_cbs( d->ctx, iocbs );
421 delete d->iocbs; d->iocbs = iocbs;
422 }
423
424 void Context::uninstallIOCallbacks() {
425 static gpgme_io_cbs noiocbs = { 0, 0, 0, 0, 0 };
426 // io.add == 0 means disable io callbacks:
427 gpgme_set_io_cbs( d->ctx, &noiocbs );
428 delete d->iocbs; d->iocbs = 0;
429 }
430
431 Error Context::setLocale( int cat, const char * val ) {
432 return Error( d->lasterr = gpgme_set_locale( d->ctx, cat, val ) );
433 }
434
435 EngineInfo Context::engineInfo() const {
436#ifdef HAVE_GPGME_CTX_GETSET_ENGINE_INFO
437 return EngineInfo( gpgme_ctx_get_engine_info( d->ctx ) );
438#else
439 return EngineInfo();
440#endif
441 }
442
443 Error Context::setEngineFileName( const char * filename ) {
444#ifdef HAVE_GPGME_CTX_GETSET_ENGINE_INFO
445 const char * const home_dir = engineInfo().homeDirectory();
446 return Error( gpgme_ctx_set_engine_info( d->ctx, gpgme_get_protocol( d->ctx ), filename, home_dir ) );
447#else
448 return Error::fromCode( GPG_ERR_NOT_IMPLEMENTED );
449#endif
450 }
451
452 Error Context::setEngineHomeDirectory( const char * home_dir ) {
453#ifdef HAVE_GPGME_CTX_GETSET_ENGINE_INFO
454 const char * const filename = engineInfo().fileName();
455 return Error( gpgme_ctx_set_engine_info( d->ctx, gpgme_get_protocol( d->ctx ), filename, home_dir ) );
456#else
457 return Error::fromCode( GPG_ERR_NOT_IMPLEMENTED );
458#endif
459 }
460
461 //
462 //
463 // Key Management
464 //
465 //
466
467 Error Context::startKeyListing( const char * pattern, bool secretOnly ) {
468 d->lastop = Private::KeyList;
469 return Error( d->lasterr = gpgme_op_keylist_start( d->ctx, pattern, int( secretOnly ) ) );
470 }
471
472 Error Context::startKeyListing( const char * patterns[], bool secretOnly ) {
473 d->lastop = Private::KeyList;
474#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
475 if ( !patterns || !patterns[0] || !patterns[1] ) {
476 // max. one pattern -> use the non-ext version
477 return startKeyListing( patterns ? patterns[0] : 0, secretOnly );
478 }
479#endif
480 return Error( d->lasterr = gpgme_op_keylist_ext_start( d->ctx, patterns, int( secretOnly ), 0 ) );
481 }
482
483 Key Context::nextKey( GpgME::Error & e ) {
484 d->lastop = Private::KeyList;
485 gpgme_key_t key;
486 e = Error( d->lasterr = gpgme_op_keylist_next( d->ctx, &key ) );
487 return Key( key, false );
488 }
489
490 KeyListResult Context::endKeyListing() {
491 d->lasterr = gpgme_op_keylist_end( d->ctx );
492 return keyListResult();
493 }
494
495 KeyListResult Context::keyListResult() const {
496 return KeyListResult( d->ctx, Error( d->lasterr ) );
497 }
498
499 Key Context::key( const char * fingerprint, GpgME::Error & e , bool secret /*, bool forceUpdate*/ ) {
500 d->lastop = Private::KeyList;
501 gpgme_key_t key;
502 e = Error( d->lasterr = gpgme_get_key( d->ctx, fingerprint, &key, int( secret )/*, int( forceUpdate )*/ ) );
503 return Key( key, false );
504 }
505
506 KeyGenerationResult Context::generateKey( const char * parameters, Data & pubKey ) {
507 d->lastop = Private::KeyGen;
508 Data::Private * const dp = pubKey.impl();
509 d->lasterr = gpgme_op_genkey( d->ctx, parameters, dp ? dp->data : 0, 0 );
510 return KeyGenerationResult( d->ctx, Error( d->lasterr ) );
511 }
512
513 Error Context::startKeyGeneration( const char * parameters, Data & pubKey ) {
514 d->lastop = Private::KeyGen;
515 Data::Private * const dp = pubKey.impl();
516 return Error( d->lasterr = gpgme_op_genkey_start( d->ctx, parameters, dp ? dp->data : 0, 0 ) );
517 }
518
519 KeyGenerationResult Context::keyGenerationResult() const {
520 if ( d->lastop & Private::KeyGen ) {
521 return KeyGenerationResult( d->ctx, Error( d->lasterr ) );
522 } else {
523 return KeyGenerationResult();
524 }
525 }
526
527 Error Context::exportPublicKeys( const char * pattern, Data & keyData ) {
528 d->lastop = Private::Export;
529 Data::Private * const dp = keyData.impl();
530 return Error( d->lasterr = gpgme_op_export( d->ctx, pattern, 0, dp ? dp->data : 0 ) );
531 }
532
533 Error Context::exportPublicKeys( const char * patterns[], Data & keyData ) {
534 d->lastop = Private::Export;
535#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
536 if ( !patterns || !patterns[0] || !patterns[1] ) {
537 // max. one pattern -> use the non-ext version
538 return exportPublicKeys( patterns ? patterns[0] : 0, keyData );
539 }
540#endif
541 Data::Private * const dp = keyData.impl();
542 return Error( d->lasterr = gpgme_op_export_ext( d->ctx, patterns, 0, dp ? dp->data : 0 ) );
543 }
544
545 Error Context::startPublicKeyExport( const char * pattern, Data & keyData ) {
546 d->lastop = Private::Export;
547 Data::Private * const dp = keyData.impl();
548 return Error( d->lasterr = gpgme_op_export_start( d->ctx, pattern, 0, dp ? dp->data : 0 ) );
549 }
550
551 Error Context::startPublicKeyExport( const char * patterns[], Data & keyData ) {
552 d->lastop = Private::Export;
553#ifndef HAVE_GPGME_EXT_KEYLIST_MODE_EXTERNAL_NONBROKEN
554 if ( !patterns || !patterns[0] || !patterns[1] ) {
555 // max. one pattern -> use the non-ext version
556 return startPublicKeyExport( patterns ? patterns[0] : 0, keyData );
557 }
558#endif
559 Data::Private * const dp = keyData.impl();
560 return Error( d->lasterr = gpgme_op_export_ext_start( d->ctx, patterns, 0, dp ? dp->data : 0 ) );
561 }
562
563
564 ImportResult Context::importKeys( const Data & data ) {
565 d->lastop = Private::Import;
566 const Data::Private * const dp = data.impl();
567 d->lasterr = gpgme_op_import( d->ctx, dp ? dp->data : 0 );
568 return ImportResult( d->ctx, Error( d->lasterr ) );
569 }
570
571 ImportResult Context::importKeys( const std::vector<Key> & kk ) {
572 d->lastop = Private::Import;
573 d->lasterr = make_error( GPG_ERR_NOT_IMPLEMENTED );
574
575 bool shouldHaveResult = false;
576#ifdef HAVE_GPGME_OP_IMPORT_KEYS
577 const boost::scoped_array<gpgme_key_t> keys( new gpgme_key_t[ kk.size() + 1 ] );
578 gpgme_key_t * keys_it = &keys[0];
579 for ( std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it ) {
580 if ( it->impl() ) {
581 *keys_it++ = it->impl();
582 }
583 }
584 *keys_it++ = 0;
585 d->lasterr = gpgme_op_import_keys( d->ctx, keys.get() );
586 shouldHaveResult = true;
587#endif
588 if ( ( gpgme_err_code( d->lasterr ) == GPG_ERR_NOT_IMPLEMENTED ||
589 gpgme_err_code( d->lasterr ) == GPG_ERR_NOT_SUPPORTED ) &&
590 protocol() == CMS ) {
591 // ok, try the workaround (export+import):
592 std::vector<const char*> fprs;
593 for ( std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it ) {
594 if ( const char * fpr = it->primaryFingerprint() ) {
595 if ( *fpr ) {
596 fprs.push_back( fpr );
597 }
598 } else if ( const char * keyid = it->keyID() ) {
599 if ( *keyid ) {
600 fprs.push_back( keyid );
601 }
602 }
603 }
604 fprs.push_back( 0 );
605 Data data;
606 Data::Private * const dp = data.impl();
607 const gpgme_keylist_mode_t oldMode = gpgme_get_keylist_mode( d->ctx );
608 gpgme_set_keylist_mode( d->ctx, GPGME_KEYLIST_MODE_EXTERN );
609 d->lasterr = gpgme_op_export_ext( d->ctx, &fprs[0], 0, dp ? dp->data : 0 );
610 gpgme_set_keylist_mode( d->ctx, oldMode );
611 if ( !d->lasterr ) {
612 data.seek( 0, SEEK_SET );
613 d->lasterr = gpgme_op_import( d->ctx, dp ? dp->data : 0 );
614 shouldHaveResult = true;
615 }
616 }
617 if ( shouldHaveResult ) {
618 return ImportResult( d->ctx, Error( d->lasterr ) );
619 } else {
620 return ImportResult( Error( d->lasterr ) );
621 }
622 }
623
624 Error Context::startKeyImport( const Data & data ) {
625 d->lastop = Private::Import;
626 const Data::Private * const dp = data.impl();
627 return Error( d->lasterr = gpgme_op_import_start( d->ctx, dp ? dp->data : 0 ) );
628 }
629
630 Error Context::startKeyImport( const std::vector<Key> & kk ) {
631 d->lastop = Private::Import;
632#ifdef HAVE_GPGME_OP_IMPORT_KEYS
633 const boost::scoped_array<gpgme_key_t> keys( new gpgme_key_t[ kk.size() + 1 ] );
634 gpgme_key_t * keys_it = &keys[0];
635 for ( std::vector<Key>::const_iterator it = kk.begin(), end = kk.end() ; it != end ; ++it ) {
636 if ( it->impl() ) {
637 *keys_it++ = it->impl();
638 }
639 }
640 *keys_it++ = 0;
641 return Error( d->lasterr = gpgme_op_import_keys_start( d->ctx, keys.get() ) );
642#else
643 (void)kk;
644 return Error( d->lasterr = make_error( GPG_ERR_NOT_IMPLEMENTED ) );
645#endif
646 }
647
648 ImportResult Context::importResult() const {
649 if ( d->lastop & Private::Import ) {
650 return ImportResult( d->ctx, Error( d->lasterr ) );
651 } else {
652 return ImportResult();
653 }
654 }
655
656 Error Context::deleteKey( const Key & key, bool allowSecretKeyDeletion ) {
657 d->lastop = Private::Delete;
658 return Error( d->lasterr = gpgme_op_delete( d->ctx, key.impl(), int( allowSecretKeyDeletion ) ) );
659 }
660
661 Error Context::startKeyDeletion( const Key & key, bool allowSecretKeyDeletion ) {
662 d->lastop = Private::Delete;
663 return Error( d->lasterr = gpgme_op_delete_start( d->ctx, key.impl(), int( allowSecretKeyDeletion ) ) );
664 }
665
666 Error Context::passwd( const Key & key ) {
667 d->lastop = Private::Passwd;
668#ifdef HAVE_GPGME_OP_PASSWD
669 return Error( d->lasterr = gpgme_op_passwd( d->ctx, key.impl(), 0U ) );
670#else
671 (void)key;
672 return Error( d->lasterr = make_error( GPG_ERR_NOT_IMPLEMENTED ) );
673#endif
674 }
675
676 Error Context::startPasswd( const Key & key ) {
677 d->lastop = Private::Passwd;
678#ifdef HAVE_GPGME_OP_PASSWD
679 return Error( d->lasterr = gpgme_op_passwd_start( d->ctx, key.impl(), 0U ) );
680#else
681 (void)key;
682 return Error( d->lasterr = make_error( GPG_ERR_NOT_IMPLEMENTED ) );
683#endif
684 }
685
686 Error Context::edit( const Key & key, std::auto_ptr<EditInteractor> func, Data & data ) {
687 d->lastop = Private::Edit;
688 d->lastEditInteractor = func;
689 Data::Private * const dp = data.impl();
690 return Error( d->lasterr = gpgme_op_edit( d->ctx, key.impl(),
691 d->lastEditInteractor.get() ? edit_interactor_callback : 0,
692 d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
693 dp ? dp->data : 0 ) );
694 }
695
696 Error Context::startEditing( const Key & key, std::auto_ptr<EditInteractor> func, Data & data ) {
697 d->lastop = Private::Edit;
698 d->lastEditInteractor = func;
699 Data::Private * const dp = data.impl();
700 return Error( d->lasterr = gpgme_op_edit_start( d->ctx, key.impl(),
701 d->lastEditInteractor.get() ? edit_interactor_callback : 0,
702 d->lastEditInteractor.get() ? d->lastEditInteractor->d : 0,
703 dp ? dp->data : 0 ) );
704 }
705
706 EditInteractor * Context::lastEditInteractor() const {
707 return d->lastEditInteractor.get();
708 }
709
710 std::auto_ptr<EditInteractor> Context::takeLastEditInteractor() {
711 return d->lastEditInteractor;
712 }
713
714 Error Context::cardEdit( const Key & key, std::auto_ptr<EditInteractor> func, Data & data ) {
715 d->lastop = Private::CardEdit;
716 d->lastCardEditInteractor = func;
717 Data::Private * const dp = data.impl();
718 return Error( d->lasterr = gpgme_op_card_edit( d->ctx, key.impl(),
719 d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
720 d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
721 dp ? dp->data : 0 ) );
722 }
723
724 Error Context::startCardEditing( const Key & key, std::auto_ptr<EditInteractor> func, Data & data ) {
725 d->lastop = Private::CardEdit;
726 d->lastCardEditInteractor = func;
727 Data::Private * const dp = data.impl();
728 return Error( d->lasterr = gpgme_op_card_edit_start( d->ctx, key.impl(),
729 d->lastCardEditInteractor.get() ? edit_interactor_callback : 0,
730 d->lastCardEditInteractor.get() ? d->lastCardEditInteractor->d : 0,
731 dp ? dp->data : 0 ) );
732 }
733
734 EditInteractor * Context::lastCardEditInteractor() const {
735 return d->lastCardEditInteractor.get();
736 }
737
738 std::auto_ptr<EditInteractor> Context::takeLastCardEditInteractor() {
739 return d->lastCardEditInteractor;
740 }
741
742 Error Context::startTrustItemListing( const char * pattern, int maxLevel ) {
743 d->lastop = Private::TrustList;
744 return Error( d->lasterr = gpgme_op_trustlist_start( d->ctx, pattern, maxLevel ) );
745 }
746
747 TrustItem Context::nextTrustItem( Error & e ) {
748 gpgme_trust_item_t ti = 0;
749 e = Error( d->lasterr = gpgme_op_trustlist_next( d->ctx, &ti ) );
750 return TrustItem( ti );
751 }
752
753 Error Context::endTrustItemListing() {
754 return Error( d->lasterr = gpgme_op_trustlist_end( d->ctx ) );
755 }
756
757#ifdef HAVE_GPGME_ASSUAN_ENGINE
758 static gpgme_error_t assuan_transaction_data_callback( void * opaque, const void * data, size_t datalen ) {
759 assert( opaque );
760 AssuanTransaction * t = static_cast<AssuanTransaction*>( opaque );
761 return t->data( static_cast<const char*>( data ), datalen ).encodedError();
762 }
763
764 static gpgme_error_t assuan_transaction_inquire_callback( void * opaque, const char * name, const char * args, gpgme_data_t * r_data ) {
765 assert( opaque );
766 Context::Private * p = static_cast<Context::Private*>( opaque );
767 AssuanTransaction * t = p->lastAssuanTransaction.get();
768 assert( t );
769 Error err;
770 if ( name ) {
771 p->lastAssuanInquireData = t->inquire( name, args, err );
772 } else {
773 p->lastAssuanInquireData = Data::null;
774 }
775 if ( !p->lastAssuanInquireData.isNull() ) {
776 *r_data = p->lastAssuanInquireData.impl()->data;
777 }
778 return err.encodedError();
779 }
780
781 static gpgme_error_t assuan_transaction_status_callback( void * opaque, const char * status, const char * args ) {
782 assert( opaque );
783 AssuanTransaction * t = static_cast<AssuanTransaction*>( opaque );
784 std::string a = args;
785 percent_unescape( a, true ); // ### why doesn't gpgme do this??
786 return t->status( status, a.c_str() ).encodedError();
787 }
788#endif
789
790 AssuanResult Context::assuanTransact( const char * command ) {
791 return assuanTransact( command, std::auto_ptr<AssuanTransaction>( new DefaultAssuanTransaction ) );
792 }
793
794 AssuanResult Context::assuanTransact( const char * command, std::auto_ptr<AssuanTransaction> transaction ) {
795 d->lastop = Private::AssuanTransact;
796 d->lastAssuanTransaction = transaction;
797 if ( !d->lastAssuanTransaction.get() ) {
798 return AssuanResult( Error( d->lasterr = make_error( GPG_ERR_INV_ARG ) ) );
799 }
800#ifdef HAVE_GPGME_ASSUAN_ENGINE
801 d->lasterr = gpgme_op_assuan_transact( d->ctx, command,
802 assuan_transaction_data_callback,
803 d->lastAssuanTransaction.get(),
804 assuan_transaction_inquire_callback,
805 d, // sic!
806 assuan_transaction_status_callback,
807 d->lastAssuanTransaction.get() );
808#else
809 (void)command;
810 d->lasterr = make_error( GPG_ERR_NOT_SUPPORTED );
811#endif
812 return AssuanResult( d->ctx, d->lasterr );
813 }
814
815 Error Context::startAssuanTransaction( const char * command ) {
816 return startAssuanTransaction( command, std::auto_ptr<AssuanTransaction>( new DefaultAssuanTransaction ) );
817 }
818
819 Error Context::startAssuanTransaction( const char * command, std::auto_ptr<AssuanTransaction> transaction ) {
820 d->lastop = Private::AssuanTransact;
821 d->lastAssuanTransaction = transaction;
822 if ( !d->lastAssuanTransaction.get() ) {
823 return Error( d->lasterr = make_error( GPG_ERR_INV_ARG ) );
824 }
825#ifdef HAVE_GPGME_ASSUAN_ENGINE
826 return Error( d->lasterr = gpgme_op_assuan_transact_start( d->ctx, command,
827 assuan_transaction_data_callback,
828 d->lastAssuanTransaction.get(),
829 assuan_transaction_inquire_callback,
830 d, // sic!
831 assuan_transaction_status_callback,
832 d->lastAssuanTransaction.get() ) );
833#else
834 (void)command;
835 return Error( d->lasterr = make_error( GPG_ERR_NOT_SUPPORTED ) );
836#endif
837 }
838
839 AssuanResult Context::assuanResult() const {
840 if ( d->lastop & Private::AssuanTransact ) {
841 return AssuanResult( d->ctx, d->lasterr );
842 } else {
843 return AssuanResult();
844 }
845 }
846
847 AssuanTransaction * Context::lastAssuanTransaction() const {
848 return d->lastAssuanTransaction.get();
849 }
850
851 std::auto_ptr<AssuanTransaction> Context::takeLastAssuanTransaction() {
852 return d->lastAssuanTransaction;
853 }
854
855 DecryptionResult Context::decrypt( const Data & cipherText, Data & plainText ) {
856 d->lastop = Private::Decrypt;
857 const Data::Private * const cdp = cipherText.impl();
858 Data::Private * const pdp = plainText.impl();
859 d->lasterr = gpgme_op_decrypt( d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0 );
860 return DecryptionResult( d->ctx, Error( d->lasterr ) );
861 }
862
863 Error Context::startDecryption( const Data & cipherText, Data & plainText ) {
864 d->lastop = Private::Decrypt;
865 const Data::Private * const cdp = cipherText.impl();
866 Data::Private * const pdp = plainText.impl();
867 return Error( d->lasterr = gpgme_op_decrypt_start( d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0 ) );
868 }
869
870 DecryptionResult Context::decryptionResult() const {
871 if ( d->lastop & Private::Decrypt ) {
872 return DecryptionResult( d->ctx, Error( d->lasterr ) );
873 } else {
874 return DecryptionResult();
875 }
876 }
877
878
879
880 VerificationResult Context::verifyDetachedSignature( const Data & signature, const Data & signedText ) {
881 d->lastop = Private::Verify;
882 const Data::Private * const sdp = signature.impl();
883 const Data::Private * const tdp = signedText.impl();
884 d->lasterr = gpgme_op_verify( d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0 );
885 return VerificationResult( d->ctx, Error( d->lasterr ) );
886 }
887
888 VerificationResult Context::verifyOpaqueSignature( const Data & signedData, Data & plainText ) {
889 d->lastop = Private::Verify;
890 const Data::Private * const sdp = signedData.impl();
891 Data::Private * const pdp = plainText.impl();
892 d->lasterr = gpgme_op_verify( d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0 );
893 return VerificationResult( d->ctx, Error( d->lasterr ) );
894 }
895
896 Error Context::startDetachedSignatureVerification( const Data & signature, const Data & signedText ) {
897 d->lastop = Private::Verify;
898 const Data::Private * const sdp = signature.impl();
899 const Data::Private * const tdp = signedText.impl();
900 return Error( d->lasterr = gpgme_op_verify_start( d->ctx, sdp ? sdp->data : 0, tdp ? tdp->data : 0, 0 ) );
901 }
902
903 Error Context::startOpaqueSignatureVerification( const Data & signedData, Data & plainText ) {
904 d->lastop = Private::Verify;
905 const Data::Private * const sdp = signedData.impl();
906 Data::Private * const pdp = plainText.impl();
907 return Error( d->lasterr = gpgme_op_verify_start( d->ctx, sdp ? sdp->data : 0, 0, pdp ? pdp->data : 0 ) );
908 }
909
910 VerificationResult Context::verificationResult() const {
911 if ( d->lastop & Private::Verify ) {
912 return VerificationResult( d->ctx, Error( d->lasterr ) );
913 } else {
914 return VerificationResult();
915 }
916 }
917
918 std::pair<DecryptionResult,VerificationResult> Context::decryptAndVerify( const Data & cipherText, Data & plainText ) {
919 d->lastop = Private::DecryptAndVerify;
920 const Data::Private * const cdp = cipherText.impl();
921 Data::Private * const pdp = plainText.impl();
922 d->lasterr = gpgme_op_decrypt_verify( d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0 );
923 return std::make_pair( DecryptionResult( d->ctx, Error( d->lasterr ) ),
924 VerificationResult( d->ctx, Error( d->lasterr ) ) );
925 }
926
927 Error Context::startCombinedDecryptionAndVerification( const Data & cipherText, Data & plainText ) {
928 d->lastop = Private::DecryptAndVerify;
929 const Data::Private * const cdp = cipherText.impl();
930 Data::Private * const pdp = plainText.impl();
931 return Error( d->lasterr = gpgme_op_decrypt_verify_start( d->ctx, cdp ? cdp->data : 0, pdp ? pdp->data : 0 ) );
932 }
933
934#ifdef HAVE_GPGME_OP_GETAUDITLOG
935 unsigned int to_auditlog_flags( unsigned int flags ) {
936 unsigned int result = 0;
937 if ( flags & Context::HtmlAuditLog ) {
938 result |= GPGME_AUDITLOG_HTML;
939 }
940 if ( flags & Context::AuditLogWithHelp ) {
941 result |= GPGME_AUDITLOG_WITH_HELP;
942 }
943 return result;
944 }
945#endif // HAVE_GPGME_OP_GETAUDITLOG
946
947 Error Context::startGetAuditLog( Data & output, unsigned int flags ) {
948 d->lastop = Private::GetAuditLog;
949#ifdef HAVE_GPGME_OP_GETAUDITLOG
950 Data::Private * const odp = output.impl();
951 return Error( d->lasterr = gpgme_op_getauditlog_start( d->ctx, odp ? odp->data : 0, to_auditlog_flags( flags ) ) );
952#else
953 (void)output; (void)flags;
954 return Error( d->lasterr = make_error( GPG_ERR_NOT_IMPLEMENTED ) );
955#endif
956 }
957
958 Error Context::getAuditLog( Data & output, unsigned int flags ) {
959 d->lastop = Private::GetAuditLog;
960#ifdef HAVE_GPGME_OP_GETAUDITLOG
961 Data::Private * const odp = output.impl();
962 return Error( d->lasterr = gpgme_op_getauditlog( d->ctx, odp ? odp->data : 0, to_auditlog_flags( flags ) ) );
963#else
964 (void)output; (void)flags;
965 return Error( d->lasterr = make_error( GPG_ERR_NOT_IMPLEMENTED ) );
966#endif
967 }
968
969 void Context::clearSigningKeys() {
970 gpgme_signers_clear( d->ctx );
971 }
972
973 Error Context::addSigningKey( const Key & key ) {
974 return Error( d->lasterr = gpgme_signers_add( d->ctx, key.impl() ) );
975 }
976
977 Key Context::signingKey( unsigned int idx ) const {
978 gpgme_key_t key = gpgme_signers_enum( d->ctx, idx );
979 return Key( key, false );
980 }
981
982 std::vector<Key> Context::signingKeys() const {
983 std::vector<Key> result;
984 gpgme_key_t key;
985 for ( unsigned int i = 0 ; ( key = gpgme_signers_enum( d->ctx, i ) ) ; ++i ) {
986 result.push_back( Key( key, false ) );
987 }
988 return result;
989 }
990
991 void Context::clearSignatureNotations() {
992#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
993 gpgme_sig_notation_clear( d->ctx );
994#endif
995 }
996
997 GpgME::Error Context::addSignatureNotation( const char * name, const char * value, unsigned int flags ) {
998#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
999 return Error( gpgme_sig_notation_add( d->ctx, name, value, add_to_gpgme_sig_notation_flags_t( 0, flags ) ) );
1000#else
1001 (void)name; (void)value; (void)flags;
1002 return Error( make_error( GPG_ERR_NOT_IMPLEMENTED ) );
1003#endif
1004 }
1005
1006 GpgME::Error Context::addSignaturePolicyURL( const char * url, bool critical ) {
1007#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
1008 return Error( gpgme_sig_notation_add( d->ctx, 0, url, critical ? GPGME_SIG_NOTATION_CRITICAL : 0 ) );
1009#else
1010 (void)url; (void)critical;
1011 return Error( make_error( GPG_ERR_NOT_IMPLEMENTED ) );
1012#endif
1013 }
1014
1015 const char * Context::signaturePolicyURL() const {
1016#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
1017 for ( gpgme_sig_notation_t n = gpgme_sig_notation_get( d->ctx ) ; n ; n = n->next ) {
1018 if ( !n->name ) {
1019 return n->value;
1020 }
1021 }
1022#endif
1023 return 0;
1024 }
1025
1026 Notation Context::signatureNotation( unsigned int idx ) const {
1027#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
1028 for ( gpgme_sig_notation_t n = gpgme_sig_notation_get( d->ctx ) ; n ; n = n->next ) {
1029 if ( n->name ) {
1030 if ( idx-- == 0 ) {
1031 return Notation( n );
1032 }
1033 }
1034 }
1035#endif
1036 return Notation();
1037 }
1038
1039 std::vector<Notation> Context::signatureNotations() const {
1040 std::vector<Notation> result;
1041#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
1042 for ( gpgme_sig_notation_t n = gpgme_sig_notation_get( d->ctx ) ; n ; n = n->next ) {
1043 if ( n->name ) {
1044 result.push_back( Notation( n ) );
1045 }
1046 }
1047#endif
1048 return result;
1049 }
1050
1051 static gpgme_sig_mode_t sigmode2sigmode( SignatureMode mode ) {
1052 switch ( mode ) {
1053 default:
1054 case NormalSignatureMode: return GPGME_SIG_MODE_NORMAL;
1055 case Detached: return GPGME_SIG_MODE_DETACH;
1056 case Clearsigned: return GPGME_SIG_MODE_CLEAR;
1057 }
1058 }
1059
1060 SigningResult Context::sign( const Data & plainText, Data & signature, SignatureMode mode ) {
1061 d->lastop = Private::Sign;
1062 const Data::Private * const pdp = plainText.impl();
1063 Data::Private * const sdp = signature.impl();
1064 d->lasterr = gpgme_op_sign( d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode( mode ) );
1065 return SigningResult( d->ctx, Error( d->lasterr ) );
1066 }
1067
1068
1069 Error Context::startSigning( const Data & plainText, Data & signature, SignatureMode mode ) {
1070 d->lastop = Private::Sign;
1071 const Data::Private * const pdp = plainText.impl();
1072 Data::Private * const sdp = signature.impl();
1073 return Error( d->lasterr = gpgme_op_sign_start( d->ctx, pdp ? pdp->data : 0, sdp ? sdp->data : 0, sigmode2sigmode( mode ) ) );
1074 }
1075
1076 SigningResult Context::signingResult() const {
1077 if ( d->lastop & Private::Sign ) {
1078 return SigningResult( d->ctx, Error( d->lasterr ) );
1079 } else {
1080 return SigningResult();
1081 }
1082 }
1083
1084 static gpgme_encrypt_flags_t encryptflags2encryptflags( Context::EncryptionFlags flags ) {
1085 unsigned int result = 0;
1086 if ( flags & Context::AlwaysTrust ) {
1087 result |= GPGME_ENCRYPT_ALWAYS_TRUST;
1088 }
1089#ifdef HAVE_GPGME_ENCRYPT_NO_ENCRYPT_TO
1090 if ( flags & Context::NoEncryptTo ) {
1091 result |= GPGME_ENCRYPT_NO_ENCRYPT_TO;
1092 }
1093#endif
1094 return static_cast<gpgme_encrypt_flags_t>( result );
1095 }
1096
1097 EncryptionResult Context::encrypt( const std::vector<Key> & recipients, const Data & plainText, Data & cipherText, EncryptionFlags flags ) {
1098 d->lastop = Private::Encrypt;
1099#ifndef HAVE_GPGME_ENCRYPT_NO_ENCRYPT_TO
1100 if ( flags & NoEncryptTo ) {
1101 return EncryptionResult( Error( d->lasterr = make_error( GPG_ERR_NOT_IMPLEMENTED ) ) );
1102 }
1103#endif
1104 const Data::Private * const pdp = plainText.impl();
1105 Data::Private * const cdp = cipherText.impl();
1106 gpgme_key_t * const keys = new gpgme_key_t[ recipients.size() + 1 ];
1107 gpgme_key_t * keys_it = keys;
1108 for ( std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it ) {
1109 if ( it->impl() ) {
1110 *keys_it++ = it->impl();
1111 }
1112 }
1113 *keys_it++ = 0;
1114 d->lasterr = gpgme_op_encrypt( d->ctx, keys, encryptflags2encryptflags( flags ),
1115 pdp ? pdp->data : 0, cdp ? cdp->data : 0 );
1116 delete[] keys;
1117 return EncryptionResult( d->ctx, Error( d->lasterr ) );
1118 }
1119
1120 Error Context::encryptSymmetrically( const Data & plainText, Data & cipherText ) {
1121 d->lastop = Private::Encrypt;
1122 const Data::Private * const pdp = plainText.impl();
1123 Data::Private * const cdp = cipherText.impl();
1124 return Error( d->lasterr = gpgme_op_encrypt( d->ctx, 0, (gpgme_encrypt_flags_t)0,
1125 pdp ? pdp->data : 0, cdp ? cdp->data : 0 ) );
1126 }
1127
1128 Error Context::startEncryption( const std::vector<Key> & recipients, const Data & plainText, Data & cipherText, EncryptionFlags flags ) {
1129 d->lastop = Private::Encrypt;
1130#ifndef HAVE_GPGME_ENCRYPT_NO_ENCRYPT_TO
1131 if ( flags & NoEncryptTo ) {
1132 return Error( d->lasterr = make_error( GPG_ERR_NOT_IMPLEMENTED ) );
1133 }
1134#endif
1135 const Data::Private * const pdp = plainText.impl();
1136 Data::Private * const cdp = cipherText.impl();
1137 gpgme_key_t * const keys = new gpgme_key_t[ recipients.size() + 1 ];
1138 gpgme_key_t * keys_it = keys;
1139 for ( std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it ) {
1140 if ( it->impl() ) {
1141 *keys_it++ = it->impl();
1142 }
1143 }
1144 *keys_it++ = 0;
1145 d->lasterr = gpgme_op_encrypt_start( d->ctx, keys, encryptflags2encryptflags( flags ),
1146 pdp ? pdp->data : 0, cdp ? cdp->data : 0 );
1147 delete[] keys;
1148 return Error( d->lasterr );
1149 }
1150
1151 EncryptionResult Context::encryptionResult() const {
1152 if ( d->lastop & Private::Encrypt ) {
1153 return EncryptionResult( d->ctx, Error( d->lasterr ) );
1154 } else {
1155 return EncryptionResult();
1156 }
1157 }
1158
1159 std::pair<SigningResult,EncryptionResult> Context::signAndEncrypt( const std::vector<Key> & recipients, const Data & plainText, Data & cipherText, EncryptionFlags flags ) {
1160 d->lastop = Private::SignAndEncrypt;
1161 const Data::Private * const pdp = plainText.impl();
1162 Data::Private * const cdp = cipherText.impl();
1163 gpgme_key_t * const keys = new gpgme_key_t[ recipients.size() + 1 ];
1164 gpgme_key_t * keys_it = keys;
1165 for ( std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it ) {
1166 if ( it->impl() ) {
1167 *keys_it++ = it->impl();
1168 }
1169 }
1170 *keys_it++ = 0;
1171 d->lasterr = gpgme_op_encrypt_sign( d->ctx, keys, encryptflags2encryptflags( flags ),
1172 pdp ? pdp->data : 0, cdp ? cdp->data : 0 );
1173 delete[] keys;
1174 return std::make_pair( SigningResult( d->ctx, Error( d->lasterr ) ),
1175 EncryptionResult( d->ctx, Error( d->lasterr ) ) );
1176 }
1177
1178 Error Context::startCombinedSigningAndEncryption( const std::vector<Key> & recipients, const Data & plainText, Data & cipherText, EncryptionFlags flags ) {
1179 d->lastop = Private::SignAndEncrypt;
1180 const Data::Private * const pdp = plainText.impl();
1181 Data::Private * const cdp = cipherText.impl();
1182 gpgme_key_t * const keys = new gpgme_key_t[ recipients.size() + 1 ];
1183 gpgme_key_t * keys_it = keys;
1184 for ( std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it ) {
1185 if ( it->impl() ) {
1186 *keys_it++ = it->impl();
1187 }
1188 }
1189 *keys_it++ = 0;
1190 d->lasterr = gpgme_op_encrypt_sign_start( d->ctx, keys, encryptflags2encryptflags( flags ),
1191 pdp ? pdp->data : 0, cdp ? cdp->data : 0 );
1192 delete[] keys;
1193 return Error( d->lasterr );
1194 }
1195
1196 Error Context::createVFS(const char* containerFile, const std::vector< Key >& recipients) {
1197 d->lastop = Private::CreateVFS;
1198#ifdef HAVE_GPGME_G13_VFS
1199 gpgme_key_t * const keys = new gpgme_key_t[ recipients.size() + 1 ];
1200 gpgme_key_t * keys_it = keys;
1201 for ( std::vector<Key>::const_iterator it = recipients.begin() ; it != recipients.end() ; ++it ) {
1202 if ( it->impl() ) {
1203 *keys_it++ = it->impl();
1204 }
1205 }
1206 *keys_it++ = 0;
1207
1208 gpgme_error_t op_err;
1209 d->lasterr = gpgme_op_vfs_create( d->ctx, keys, containerFile, 0, &op_err );
1210 delete[] keys;
1211 Error error( d->lasterr );
1212 if ( error ) {
1213 return error;
1214 }
1215 return Error( d->lasterr = op_err );
1216#else
1217 Q_UNUSED( containerFile );
1218 Q_UNUSED( recipients );
1219 return Error( d->lasterr = make_error( GPG_ERR_NOT_SUPPORTED ) );
1220#endif
1221 }
1222
1223 VfsMountResult Context::mountVFS(const char* containerFile, const char* mountDir) {
1224 d->lastop = Private::MountVFS;
1225#ifdef HAVE_GPGME_G13_VFS
1226 gpgme_error_t op_err;
1227 d->lasterr = gpgme_op_vfs_mount( d->ctx, containerFile, mountDir, 0, &op_err );
1228 return VfsMountResult( d->ctx, Error( d->lasterr ), Error( op_err ) );
1229#else
1230 Q_UNUSED( containerFile );
1231 Q_UNUSED( mountDir );
1232 return VfsMountResult( d->ctx, Error( d->lasterr = make_error( GPG_ERR_NOT_SUPPORTED ) ), Error() );
1233#endif
1234 }
1235
1236 Error Context::cancelPendingOperation() {
1237#ifdef HAVE_GPGME_CANCEL_ASYNC
1238 return Error( gpgme_cancel_async( d->ctx ) );
1239#else
1240 return Error( gpgme_cancel( d->ctx ) );
1241#endif
1242 }
1243
1244 bool Context::poll() {
1245 gpgme_error_t e = GPG_ERR_NO_ERROR;
1246 const bool finished = gpgme_wait( d->ctx, &e, 0 );
1247 if ( finished ) {
1248 d->lasterr = e;
1249 }
1250 return finished;
1251 }
1252
1253 Error Context::wait() {
1254 gpgme_error_t e = GPG_ERR_NO_ERROR;
1255 gpgme_wait( d->ctx, &e, 1 );
1256 return Error( d->lasterr = e );
1257 }
1258
1259 Error Context::lastError() const {
1260 return Error( d->lasterr );
1261 }
1262
1263 std::ostream & operator<<( std::ostream & os, Protocol proto ) {
1264 os << "GpgME::Protocol(";
1265 switch ( proto ) {
1266 case OpenPGP:
1267 os << "OpenPGP";
1268 break;
1269 case CMS:
1270 os << "CMS";
1271 break;
1272 default:
1273 case UnknownProtocol:
1274 os << "UnknownProtocol";
1275 break;
1276 }
1277 return os << ')';
1278 }
1279
1280 std::ostream & operator<<( std::ostream & os, Engine eng ) {
1281 os << "GpgME::Engine(";
1282 switch ( eng ) {
1283 case GpgEngine:
1284 os << "GpgEngine";
1285 break;
1286 case GpgSMEngine:
1287 os << "GpgSMEngine";
1288 break;
1289 case GpgConfEngine:
1290 os << "GpgConfEngine";
1291 break;
1292 case AssuanEngine:
1293 os << "AssuanEngine";
1294 break;
1295 default:
1296 case UnknownEngine:
1297 os << "UnknownEngine";
1298 break;
1299 }
1300 return os << ')';
1301 }
1302
1303 std::ostream & operator<<( std::ostream & os, Context::CertificateInclusion incl ) {
1304 os << "GpgME::Context::CertificateInclusion(" << static_cast<int>( incl );
1305 switch ( incl ) {
1306 case Context::DefaultCertificates:
1307 os << "(DefaultCertificates)";
1308 break;
1309 case Context::AllCertificatesExceptRoot:
1310 os << "(AllCertificatesExceptRoot)";
1311 break;
1312 case Context::AllCertificates:
1313 os << "(AllCertificates)";
1314 break;
1315 case Context::NoCertificates:
1316 os << "(NoCertificates)";
1317 break;
1318 case Context::OnlySenderCertificate:
1319 os << "(OnlySenderCertificate)";
1320 break;
1321 }
1322 return os << ')';
1323 }
1324
1325 std::ostream & operator<<( std::ostream & os, KeyListMode mode ) {
1326 os << "GpgME::KeyListMode(";
1327#define CHECK( x ) if ( !(mode & (x)) ) {} else do { os << #x " "; } while (0)
1328 CHECK( Local );
1329 CHECK( Extern );
1330 CHECK( Signatures );
1331 CHECK( Validate );
1332 CHECK( Ephemeral );
1333#undef CHECK
1334 return os << ')';
1335 }
1336
1337 std::ostream & operator<<( std::ostream & os, SignatureMode mode ) {
1338 os << "GpgME::SignatureMode(";
1339 switch ( mode ) {
1340#define CHECK( x ) case x: os << #x; break
1341 CHECK( NormalSignatureMode );
1342 CHECK( Detached );
1343 CHECK( Clearsigned );
1344#undef CHECK
1345 default:
1346 os << "???" "(" << static_cast<int>( mode ) << ')';
1347 break;
1348 }
1349 return os << ')';
1350 }
1351
1352 std::ostream & operator<<( std::ostream & os, Context::EncryptionFlags flags ) {
1353 os << "GpgME::Context::EncryptionFlags(";
1354#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
1355 CHECK( AlwaysTrust );
1356#undef CHECK
1357 return os << ')';
1358 }
1359
1360 std::ostream & operator<<( std::ostream & os, Context::AuditLogFlags flags ) {
1361 os << "GpgME::Context::AuditLogFlags(";
1362#define CHECK( x ) if ( !(flags & (Context::x)) ) {} else do { os << #x " "; } while (0)
1363 CHECK( HtmlAuditLog );
1364 CHECK( AuditLogWithHelp );
1365#undef CHECK
1366 return os << ')';
1367 }
1368
1369} // namespace GpgME
1370
1371GpgME::Error GpgME::setDefaultLocale( int cat, const char * val ) {
1372 return Error( gpgme_set_locale( 0, cat, val ) );
1373}
1374
1375GpgME::EngineInfo GpgME::engineInfo( GpgME::Protocol proto ) {
1376 gpgme_engine_info_t ei = 0;
1377 if ( gpgme_get_engine_info( &ei ) ) {
1378 return EngineInfo();
1379 }
1380
1381 const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
1382
1383 for ( gpgme_engine_info_t i = ei ; i ; i = i->next ) {
1384 if ( i->protocol == p ) {
1385 return EngineInfo( i );
1386 }
1387 }
1388
1389 return EngineInfo();
1390}
1391
1392GpgME::Error GpgME::checkEngine( GpgME::Protocol proto ) {
1393 const gpgme_protocol_t p = proto == CMS ? GPGME_PROTOCOL_CMS : GPGME_PROTOCOL_OpenPGP ;
1394
1395 return Error( gpgme_engine_check_version( p ) );
1396}
1397
1398static gpgme_protocol_t UNKNOWN_PROTOCOL = static_cast<gpgme_protocol_t>( 255 );
1399
1400static gpgme_protocol_t engine2protocol( const GpgME::Engine engine ) {
1401 switch ( engine ) {
1402 case GpgME::GpgEngine: return GPGME_PROTOCOL_OpenPGP;
1403 case GpgME::GpgSMEngine: return GPGME_PROTOCOL_CMS;
1404 case GpgME::GpgConfEngine:
1405#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
1406 return GPGME_PROTOCOL_GPGCONF;
1407#else
1408 break;
1409#endif
1410 case GpgME::AssuanEngine:
1411#ifdef HAVE_GPGME_ASSUAN_ENGINE
1412 return GPGME_PROTOCOL_ASSUAN;
1413#else
1414 break;
1415#endif
1416 case GpgME::G13Engine:
1417#ifdef HAVE_GPGME_G13_VFS
1418 return GPGME_PROTOCOL_G13;
1419#else
1420 break;
1421#endif
1422 case GpgME::UnknownEngine:
1423 ;
1424 }
1425 return UNKNOWN_PROTOCOL;
1426}
1427
1428GpgME::EngineInfo GpgME::engineInfo( GpgME::Engine engine ) {
1429 gpgme_engine_info_t ei = 0;
1430 if ( gpgme_get_engine_info( &ei ) ) {
1431 return EngineInfo();
1432 }
1433
1434 const gpgme_protocol_t p = engine2protocol( engine );
1435
1436 for ( gpgme_engine_info_t i = ei ; i ; i = i->next ) {
1437 if ( i->protocol == p ) {
1438 return EngineInfo( i );
1439 }
1440 }
1441
1442 return EngineInfo();
1443}
1444
1445GpgME::Error GpgME::checkEngine( GpgME::Engine engine ) {
1446 const gpgme_protocol_t p = engine2protocol( engine );
1447
1448 return Error( gpgme_engine_check_version( p ) );
1449}
1450
1451static const unsigned long supported_features = 0
1452 | GpgME::ValidatingKeylistModeFeature
1453 | GpgME::CancelOperationFeature
1454 | GpgME::WrongKeyUsageFeature
1455#ifdef HAVE_GPGME_INCLUDE_CERTS_DEFAULT
1456 | GpgME::DefaultCertificateInclusionFeature
1457#endif
1458#ifdef HAVE_GPGME_CTX_GETSET_ENGINE_INFO
1459 | GpgME::GetSetEngineInfoFeature
1460#endif
1461#ifdef HAVE_GPGME_SIG_NOTATION_CLEARADDGET
1462 | GpgME::ClearAddGetSignatureNotationsFeature
1463#endif
1464#ifdef HAVE_GPGME_DATA_SET_FILE_NAME
1465 | GpgME::SetDataFileNameFeeature
1466#endif
1467#ifdef HAVE_GPGME_KEYLIST_MODE_SIG_NOTATIONS
1468 | GpgME::SignatureNotationsKeylistModeFeature
1469#endif
1470#ifdef HAVE_GPGME_KEY_SIG_NOTATIONS
1471 | GpgME::KeySignatureNotationsFeature
1472#endif
1473#ifdef HAVE_GPGME_KEY_T_IS_QUALIFIED
1474 | GpgME::KeyIsQualifiedFeature
1475#endif
1476#ifdef HAVE_GPGME_SIG_NOTATION_CRITICAL
1477 | GpgME::SignatureNotationsCriticalFlagFeature
1478#endif
1479#ifdef HAVE_GPGME_SIG_NOTATION_FLAGS_T
1480 | GpgME::SignatureNotationsFlagsFeature
1481#endif
1482#ifdef HAVE_GPGME_SIG_NOTATION_HUMAN_READABLE
1483 | GpgME::SignatureNotationsHumanReadableFlagFeature
1484#endif
1485#ifdef HAVE_GPGME_SUBKEY_T_IS_QUALIFIED
1486 | GpgME::SubkeyIsQualifiedFeature
1487#endif
1488#ifdef HAVE_GPGME_ENGINE_INFO_T_HOME_DIR
1489 | GpgME::EngineInfoHomeDirFeature
1490#endif
1491#ifdef HAVE_GPGME_DECRYPT_RESULT_T_FILE_NAME
1492 | GpgME::DecryptionResultFileNameFeature
1493#endif
1494#ifdef HAVE_GPGME_DECRYPT_RESULT_T_RECIPIENTS
1495 | GpgME::DecryptionResultRecipientsFeature
1496#endif
1497#ifdef HAVE_GPGME_VERIFY_RESULT_T_FILE_NAME
1498 | GpgME::VerificationResultFileNameFeature
1499#endif
1500#ifdef HAVE_GPGME_SIGNATURE_T_PKA_FIELDS
1501 | GpgME::SignaturePkaFieldsFeature
1502#endif
1503#ifdef HAVE_GPGME_SIGNATURE_T_ALGORITHM_FIELDS
1504 | GpgME::SignatureAlgorithmFieldsFeature
1505#endif
1506#ifdef HAVE_GPGME_GET_FDPTR
1507 | GpgME::FdPointerFeature
1508#endif
1509#ifdef HAVE_GPGME_OP_GETAUDITLOG
1510 | GpgME::AuditLogFeature
1511#endif
1512#ifdef HAVE_GPGME_PROTOCOL_GPGCONF
1513 | GpgME::GpgConfEngineFeature
1514#endif
1515#ifdef HAVE_GPGME_CANCEL_ASYNC
1516 | GpgME::CancelOperationAsyncFeature
1517#endif
1518#ifdef HAVE_GPGME_ENCRYPT_NO_ENCRYPT_TO
1519 | GpgME::NoEncryptToEncryptionFlagFeature
1520#endif
1521#ifdef HAVE_GPGME_SUBKEY_T_IS_CARDKEY
1522 | GpgME::CardKeyFeature
1523#endif
1524#ifdef HAVE_GPGME_ASSUAN_ENGINE
1525 | GpgME::AssuanEngineFeature
1526#endif
1527#ifdef HAVE_GPGME_KEYLIST_MODE_EPHEMERAL
1528 | GpgME::EphemeralKeylistModeFeature
1529#endif
1530#ifdef HAVE_GPGME_OP_IMPORT_KEYS
1531 | GpgME::ImportFromKeyserverFeature
1532#endif
1533#ifdef HAVE_GPGME_G13_VFS
1534 | GpgME::G13VFSFeature
1535#endif
1536#ifdef HAVE_GPGME_OP_PASSWD
1537 | GpgME::PasswdFeature
1538#endif
1539 ;
1540
1541static const unsigned long supported_features2 = 0
1542 ;
1543
1544bool GpgME::hasFeature( unsigned long features ) {
1545 return features == ( features & supported_features );
1546}
1547
1548bool GpgME::hasFeature( unsigned long features, unsigned long features2 ) {
1549 return features == ( features & supported_features )
1550 && features2 == ( features2 & supported_features2 )
1551 ;
1552}
1553