Locate engine names only at runtime and prefer GnuPG-2.
[gpgme.git] / src / engine.c
1 /* engine.c - GPGME engine support.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2006, 2009, 2010 g10 Code GmbH
4
5    This file is part of GPGME.
6
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (at your option) any later version.
11
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <assert.h>
28
29 #include "gpgme.h"
30 #include "util.h"
31 #include "sema.h"
32 #include "ops.h"
33 #include "debug.h"
34
35 #include "engine.h"
36 #include "engine-backend.h"
37
38
39 struct engine
40 {
41   struct engine_ops *ops;
42   void *engine;
43 };
44
45
46 static struct engine_ops *engine_ops[] =
47   {
48     &_gpgme_engine_ops_gpg,             /* OpenPGP.  */
49     &_gpgme_engine_ops_gpgsm,           /* CMS.  */
50     &_gpgme_engine_ops_gpgconf,         /* gpg-conf.  */
51     &_gpgme_engine_ops_assuan,          /* Low-Level Assuan.  */
52     &_gpgme_engine_ops_g13,             /* Crypto VFS.  */
53 #ifdef ENABLE_UISERVER
54     &_gpgme_engine_ops_uiserver         /* UI-Server.  */
55 #else
56     NULL
57 #endif
58   };
59
60
61 /* The engine info.  */
62 static gpgme_engine_info_t engine_info;
63 DEFINE_STATIC_LOCK (engine_info_lock);
64
65 \f
66 /* Get the file name of the engine for PROTOCOL.  */
67 static const char *
68 engine_get_file_name (gpgme_protocol_t proto)
69 {
70   if (proto > DIM (engine_ops))
71     return NULL;
72
73   if (engine_ops[proto] && engine_ops[proto]->get_file_name)
74     return (*engine_ops[proto]->get_file_name) ();
75   else
76     return NULL;
77 }
78
79
80 /* Get the standard home dir of the engine for PROTOCOL.  */
81 static const char *
82 engine_get_home_dir (gpgme_protocol_t proto)
83 {
84   if (proto > DIM (engine_ops))
85     return NULL;
86
87   if (engine_ops[proto] && engine_ops[proto]->get_home_dir)
88     return (*engine_ops[proto]->get_home_dir) ();
89   else
90     return NULL;
91 }
92
93
94 /* Get a malloced string containing the version number of the engine
95    for PROTOCOL.  */
96 static char *
97 engine_get_version (gpgme_protocol_t proto, const char *file_name)
98 {
99   if (proto > DIM (engine_ops))
100     return NULL;
101
102   if (engine_ops[proto] && engine_ops[proto]->get_version)
103     return (*engine_ops[proto]->get_version) (file_name);
104   else
105     return NULL;
106 }
107
108
109 /* Get the required version number of the engine for PROTOCOL.  */
110 static const char *
111 engine_get_req_version (gpgme_protocol_t proto)
112 {
113   if (proto > DIM (engine_ops))
114     return NULL;
115
116   if (engine_ops[proto] && engine_ops[proto]->get_req_version)
117     return (*engine_ops[proto]->get_req_version) ();
118   else
119     return NULL;
120 }
121
122
123 /* Verify the version requirement for the engine for PROTOCOL.  */
124 gpgme_error_t
125 gpgme_engine_check_version (gpgme_protocol_t proto)
126 {
127   gpgme_error_t err;
128   gpgme_engine_info_t info;
129   int result;
130
131   LOCK (engine_info_lock);
132   info = engine_info;
133   if (!info)
134     {
135       /* Make sure it is initialized.  */
136       UNLOCK (engine_info_lock);
137       err = gpgme_get_engine_info (&info);
138       if (err)
139         return err;
140
141       LOCK (engine_info_lock);
142     }
143
144   while (info && info->protocol != proto)
145     info = info->next;
146
147   if (!info)
148     result = 0;
149   else
150     result = _gpgme_compare_versions (info->version,
151                                       info->req_version);
152
153   UNLOCK (engine_info_lock);
154   return result ? 0 : trace_gpg_error (GPG_ERR_INV_ENGINE);
155 }
156
157
158 /* Release the engine info INFO.  */
159 void
160 _gpgme_engine_info_release (gpgme_engine_info_t info)
161 {
162   while (info)
163     {
164       gpgme_engine_info_t next_info = info->next;
165
166       assert (info->file_name);
167       free (info->file_name);
168       if (info->home_dir)
169         free (info->home_dir);
170       if (info->version)
171         free (info->version);
172       free (info);
173       info = next_info;
174     }
175 }
176
177
178 /* Get the information about the configured and installed engines.  A
179    pointer to the first engine in the statically allocated linked list
180    is returned in *INFO.  If an error occurs, it is returned.  The
181    returned data is valid until the next gpgme_set_engine_info.  */
182 gpgme_error_t
183 gpgme_get_engine_info (gpgme_engine_info_t *info)
184 {
185   LOCK (engine_info_lock);
186   if (!engine_info)
187     {
188       gpgme_engine_info_t *lastp = &engine_info;
189       gpgme_protocol_t proto_list[] = { GPGME_PROTOCOL_OpenPGP,
190                                         GPGME_PROTOCOL_CMS,
191                                         GPGME_PROTOCOL_GPGCONF,
192                                         GPGME_PROTOCOL_ASSUAN,
193                                         GPGME_PROTOCOL_G13,
194                                         GPGME_PROTOCOL_UISERVER };
195       unsigned int proto;
196
197       for (proto = 0; proto < DIM (proto_list); proto++)
198         {
199           const char *ofile_name = engine_get_file_name (proto_list[proto]);
200           const char *ohome_dir  = engine_get_home_dir (proto_list[proto]);
201           char *file_name;
202           char *home_dir;
203
204           if (!ofile_name)
205             continue;
206
207           file_name = strdup (ofile_name);
208           home_dir = ohome_dir? strdup (ohome_dir): NULL;
209
210           *lastp = malloc (sizeof (*engine_info));
211           if (!*lastp || !file_name)
212             {
213               int saved_err = gpg_error_from_syserror ();
214
215               _gpgme_engine_info_release (engine_info);
216               engine_info = NULL;
217
218               if (file_name)
219                 free (file_name);
220               if (home_dir)
221                 free (home_dir);
222
223               UNLOCK (engine_info_lock);
224               return saved_err;
225             }
226
227           (*lastp)->protocol = proto_list[proto];
228           (*lastp)->file_name = file_name;
229           (*lastp)->home_dir = home_dir;
230           (*lastp)->version = engine_get_version (proto_list[proto], NULL);
231           (*lastp)->req_version = engine_get_req_version (proto_list[proto]);
232           (*lastp)->next = NULL;
233           lastp = &(*lastp)->next;
234         }
235     }
236
237   *info = engine_info;
238   UNLOCK (engine_info_lock);
239   return 0;
240 }
241
242
243 /* Get a deep copy of the engine info and return it in INFO.  */
244 gpgme_error_t
245 _gpgme_engine_info_copy (gpgme_engine_info_t *r_info)
246 {
247   gpgme_error_t err = 0;
248   gpgme_engine_info_t info;
249   gpgme_engine_info_t new_info;
250   gpgme_engine_info_t *lastp;
251
252   LOCK (engine_info_lock);
253   info = engine_info;
254   if (!info)
255     {
256       /* Make sure it is initialized.  */
257       UNLOCK (engine_info_lock);
258       err = gpgme_get_engine_info (&info);
259       if (err)
260         return err;
261
262       LOCK (engine_info_lock);
263     }
264
265   new_info = NULL;
266   lastp = &new_info;
267
268   while (info)
269     {
270       char *file_name;
271       char *home_dir;
272       char *version;
273
274       assert (info->file_name);
275       file_name = strdup (info->file_name);
276
277       if (info->home_dir)
278         {
279           home_dir = strdup (info->home_dir);
280           if (!home_dir)
281             err = gpg_error_from_syserror ();
282         }
283       else
284         home_dir = NULL;
285
286       if (info->version)
287         {
288           version = strdup (info->version);
289           if (!version)
290             err = gpg_error_from_syserror ();
291         }
292       else
293         version = NULL;
294
295       *lastp = malloc (sizeof (*engine_info));
296       if (!*lastp || !file_name || err)
297         {
298           int saved_err = gpg_error_from_syserror ();
299
300           _gpgme_engine_info_release (new_info);
301
302           if (file_name)
303             free (file_name);
304           if (home_dir)
305             free (home_dir);
306           if (version)
307             free (version);
308
309           UNLOCK (engine_info_lock);
310           return saved_err;
311         }
312
313       (*lastp)->protocol = info->protocol;
314       (*lastp)->file_name = file_name;
315       (*lastp)->home_dir = home_dir;
316       (*lastp)->version = version;
317       (*lastp)->req_version = info->req_version;
318       (*lastp)->next = NULL;
319       lastp = &(*lastp)->next;
320
321       info = info->next;
322     }
323
324   *r_info = new_info;
325   UNLOCK (engine_info_lock);
326   return 0;
327 }
328
329
330 /* Set the engine info for the info list INFO, protocol PROTO, to the
331    file name FILE_NAME and the home directory HOME_DIR.  */
332 gpgme_error_t
333 _gpgme_set_engine_info (gpgme_engine_info_t info, gpgme_protocol_t proto,
334                         const char *file_name, const char *home_dir)
335 {
336   char *new_file_name;
337   char *new_home_dir;
338
339   /* FIXME: Use some PROTO_MAX definition.  */
340   if (proto > DIM (engine_ops))
341     return gpg_error (GPG_ERR_INV_VALUE);
342
343   while (info && info->protocol != proto)
344     info = info->next;
345
346   if (!info)
347     return trace_gpg_error (GPG_ERR_INV_ENGINE);
348
349   /* Prepare new members.  */
350   if (file_name)
351     new_file_name = strdup (file_name);
352   else
353     {
354       const char *ofile_name = engine_get_file_name (proto);
355       assert (ofile_name);
356       new_file_name = strdup (ofile_name);
357     }
358   if (!new_file_name)
359     return gpg_error_from_syserror ();
360
361   if (home_dir)
362     {
363       new_home_dir = strdup (home_dir);
364       if (!new_home_dir)
365         {
366           free (new_file_name);
367           return gpg_error_from_syserror ();
368         }
369     }
370   else
371     {
372       const char *ohome_dir = engine_get_home_dir (proto);
373       if (ohome_dir)
374         {
375           new_home_dir = strdup (ohome_dir);
376           if (!new_home_dir)
377             {
378               free (new_file_name);
379               return gpg_error_from_syserror ();
380             }
381         }
382       else
383         new_home_dir = NULL;
384     }
385
386   /* Remove the old members.  */
387   assert (info->file_name);
388   free (info->file_name);
389   if (info->home_dir)
390     free (info->home_dir);
391   if (info->version)
392     free (info->version);
393
394   /* Install the new members.  */
395   info->file_name = new_file_name;
396   info->home_dir = new_home_dir;
397   info->version = engine_get_version (proto, new_file_name);
398
399   return 0;
400 }
401
402
403 /* Set the default engine info for the protocol PROTO to the file name
404    FILE_NAME and the home directory HOME_DIR.  */
405 gpgme_error_t
406 gpgme_set_engine_info (gpgme_protocol_t proto,
407                        const char *file_name, const char *home_dir)
408 {
409   gpgme_error_t err;
410   gpgme_engine_info_t info;
411
412   LOCK (engine_info_lock);
413   info = engine_info;
414   if (!info)
415     {
416       /* Make sure it is initialized.  */
417       UNLOCK (engine_info_lock);
418       err = gpgme_get_engine_info (&info);
419       if (err)
420         return err;
421
422       LOCK (engine_info_lock);
423     }
424
425   err = _gpgme_set_engine_info (info, proto, file_name, home_dir);
426   UNLOCK (engine_info_lock);
427   return err;
428 }
429
430 \f
431 gpgme_error_t
432 _gpgme_engine_new (gpgme_engine_info_t info, engine_t *r_engine)
433 {
434   engine_t engine;
435
436   if (!info->file_name || !info->version)
437     return trace_gpg_error (GPG_ERR_INV_ENGINE);
438
439   engine = calloc (1, sizeof *engine);
440   if (!engine)
441     return gpg_error_from_syserror ();
442
443   engine->ops = engine_ops[info->protocol];
444   if (engine->ops->new)
445     {
446       gpgme_error_t err;
447       err = (*engine->ops->new) (&engine->engine,
448                                  info->file_name, info->home_dir);
449       if (err)
450         {
451           free (engine);
452           return err;
453         }
454     }
455   else
456     engine->engine = NULL;
457
458   *r_engine = engine;
459   return 0;
460 }
461
462
463 gpgme_error_t
464 _gpgme_engine_reset (engine_t engine)
465 {
466   if (!engine)
467     return gpg_error (GPG_ERR_INV_VALUE);
468
469   if (!engine->ops->reset)
470     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
471
472   return (*engine->ops->reset) (engine->engine);
473 }
474
475
476 void
477 _gpgme_engine_release (engine_t engine)
478 {
479   if (!engine)
480     return;
481
482   if (engine->ops->release)
483     (*engine->ops->release) (engine->engine);
484   free (engine);
485 }
486
487
488 void
489 _gpgme_engine_set_status_handler (engine_t engine,
490                                   engine_status_handler_t fnc, void *fnc_value)
491 {
492   if (!engine)
493     return;
494
495   if (engine->ops->set_status_handler)
496     (*engine->ops->set_status_handler) (engine->engine, fnc, fnc_value);
497 }
498
499
500 gpgme_error_t
501 _gpgme_engine_set_command_handler (engine_t engine,
502                                    engine_command_handler_t fnc,
503                                    void *fnc_value,
504                                    gpgme_data_t linked_data)
505 {
506   if (!engine)
507     return gpg_error (GPG_ERR_INV_VALUE);
508
509   if (!engine->ops->set_command_handler)
510     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
511
512   return (*engine->ops->set_command_handler) (engine->engine,
513                                               fnc, fnc_value, linked_data);
514 }
515
516 gpgme_error_t
517 _gpgme_engine_set_colon_line_handler (engine_t engine,
518                                       engine_colon_line_handler_t fnc,
519                                       void *fnc_value)
520 {
521   if (!engine)
522     return gpg_error (GPG_ERR_INV_VALUE);
523
524   if (!engine->ops->set_colon_line_handler)
525     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
526
527   return (*engine->ops->set_colon_line_handler) (engine->engine,
528                                                  fnc, fnc_value);
529 }
530
531 gpgme_error_t
532 _gpgme_engine_set_locale (engine_t engine, int category,
533                           const char *value)
534 {
535   if (!engine)
536     return gpg_error (GPG_ERR_INV_VALUE);
537
538   if (!engine->ops->set_locale)
539     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
540
541   return (*engine->ops->set_locale) (engine->engine, category, value);
542 }
543
544
545 gpgme_error_t
546 _gpgme_engine_set_protocol (engine_t engine, gpgme_protocol_t protocol)
547 {
548   if (!engine)
549     return gpg_error (GPG_ERR_INV_VALUE);
550
551   if (!engine->ops->set_protocol)
552     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
553
554   return (*engine->ops->set_protocol) (engine->engine, protocol);
555 }
556
557
558 gpgme_error_t
559 _gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph,
560                           gpgme_data_t plain)
561 {
562   if (!engine)
563     return gpg_error (GPG_ERR_INV_VALUE);
564
565   if (!engine->ops->decrypt)
566     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
567
568   return (*engine->ops->decrypt) (engine->engine, ciph, plain);
569 }
570
571
572 gpgme_error_t
573 _gpgme_engine_op_decrypt_verify (engine_t engine, gpgme_data_t ciph,
574                                  gpgme_data_t plain)
575 {
576   if (!engine)
577     return gpg_error (GPG_ERR_INV_VALUE);
578
579   if (!engine->ops->decrypt_verify)
580     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
581
582   return (*engine->ops->decrypt_verify) (engine->engine, ciph, plain);
583 }
584
585
586 gpgme_error_t
587 _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key,
588                          int allow_secret)
589 {
590   if (!engine)
591     return gpg_error (GPG_ERR_INV_VALUE);
592
593   if (!engine->ops->delete)
594     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
595
596   return (*engine->ops->delete) (engine->engine, key, allow_secret);
597 }
598
599
600 gpgme_error_t
601 _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key,
602                        gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */)
603 {
604   if (!engine)
605     return gpg_error (GPG_ERR_INV_VALUE);
606
607   if (!engine->ops->edit)
608     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
609
610   return (*engine->ops->edit) (engine->engine, type, key, out, ctx);
611 }
612
613
614 gpgme_error_t
615 _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
616                           gpgme_encrypt_flags_t flags,
617                           gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
618 {
619   if (!engine)
620     return gpg_error (GPG_ERR_INV_VALUE);
621
622   if (!engine->ops->encrypt)
623     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
624
625   return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph,
626                                   use_armor);
627 }
628
629
630 gpgme_error_t
631 _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
632                                gpgme_encrypt_flags_t flags,
633                                gpgme_data_t plain, gpgme_data_t ciph,
634                                int use_armor, gpgme_ctx_t ctx /* FIXME */)
635 {
636   if (!engine)
637     return gpg_error (GPG_ERR_INV_VALUE);
638
639   if (!engine->ops->encrypt_sign)
640     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
641
642   return (*engine->ops->encrypt_sign) (engine->engine, recp, flags,
643                                        plain, ciph, use_armor, ctx);
644 }
645
646
647 gpgme_error_t
648 _gpgme_engine_op_export (engine_t engine, const char *pattern,
649                          gpgme_export_mode_t mode, gpgme_data_t keydata,
650                          int use_armor)
651 {
652   if (!engine)
653     return gpg_error (GPG_ERR_INV_VALUE);
654
655   if (!engine->ops->export)
656     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
657
658   return (*engine->ops->export) (engine->engine, pattern, mode,
659                                  keydata, use_armor);
660 }
661
662
663 gpgme_error_t
664 _gpgme_engine_op_export_ext (engine_t engine, const char *pattern[],
665                              unsigned int reserved, gpgme_data_t keydata,
666                              int use_armor)
667 {
668   if (!engine)
669     return gpg_error (GPG_ERR_INV_VALUE);
670
671   if (!engine->ops->export_ext)
672     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
673
674   return (*engine->ops->export_ext) (engine->engine, pattern, reserved,
675                                      keydata, use_armor);
676 }
677
678
679 gpgme_error_t
680 _gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
681                          int use_armor, gpgme_data_t pubkey,
682                          gpgme_data_t seckey)
683 {
684   if (!engine)
685     return gpg_error (GPG_ERR_INV_VALUE);
686
687   if (!engine->ops->genkey)
688     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
689
690   return (*engine->ops->genkey) (engine->engine, help_data, use_armor,
691                                  pubkey, seckey);
692 }
693
694
695 gpgme_error_t
696 _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata,
697                          gpgme_key_t *keyarray)
698 {
699   if (!engine)
700     return gpg_error (GPG_ERR_INV_VALUE);
701
702   if (!engine->ops->import)
703     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
704
705   return (*engine->ops->import) (engine->engine, keydata, keyarray);
706 }
707
708
709 gpgme_error_t
710 _gpgme_engine_op_keylist (engine_t engine, const char *pattern,
711                           int secret_only, gpgme_keylist_mode_t mode)
712 {
713   if (!engine)
714     return gpg_error (GPG_ERR_INV_VALUE);
715
716   if (!engine->ops->keylist)
717     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
718
719   return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode);
720 }
721
722
723 gpgme_error_t
724 _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[],
725                               int secret_only, int reserved,
726                               gpgme_keylist_mode_t mode)
727 {
728   if (!engine)
729     return gpg_error (GPG_ERR_INV_VALUE);
730
731   if (!engine->ops->keylist_ext)
732     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
733
734   return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only,
735                                       reserved, mode);
736 }
737
738
739 gpgme_error_t
740 _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out,
741                        gpgme_sig_mode_t mode, int use_armor,
742                        int use_textmode, int include_certs,
743                        gpgme_ctx_t ctx /* FIXME */)
744 {
745   if (!engine)
746     return gpg_error (GPG_ERR_INV_VALUE);
747
748   if (!engine->ops->sign)
749     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
750
751   return (*engine->ops->sign) (engine->engine, in, out, mode, use_armor,
752                                use_textmode, include_certs, ctx);
753 }
754
755
756 gpgme_error_t
757 _gpgme_engine_op_trustlist (engine_t engine, const char *pattern)
758 {
759   if (!engine)
760     return gpg_error (GPG_ERR_INV_VALUE);
761
762   if (!engine->ops->trustlist)
763     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
764
765   return (*engine->ops->trustlist) (engine->engine, pattern);
766 }
767
768
769 gpgme_error_t
770 _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
771                          gpgme_data_t signed_text, gpgme_data_t plaintext)
772 {
773   if (!engine)
774     return gpg_error (GPG_ERR_INV_VALUE);
775
776   if (!engine->ops->verify)
777     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
778
779   return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext);
780 }
781
782
783 gpgme_error_t
784 _gpgme_engine_op_getauditlog (engine_t engine, gpgme_data_t output,
785                               unsigned int flags)
786 {
787   if (!engine)
788     return gpg_error (GPG_ERR_INV_VALUE);
789
790   if (!engine->ops->getauditlog)
791     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
792
793   return (*engine->ops->getauditlog) (engine->engine, output, flags);
794 }
795
796
797 gpgme_error_t
798 _gpgme_engine_op_assuan_transact (engine_t engine,
799                                   const char *command,
800                                   gpgme_assuan_data_cb_t data_cb,
801                                   void *data_cb_value,
802                                   gpgme_assuan_inquire_cb_t inq_cb,
803                                   void *inq_cb_value,
804                                   gpgme_assuan_status_cb_t status_cb,
805                                   void *status_cb_value)
806 {
807   if (!engine)
808     return gpg_error (GPG_ERR_INV_VALUE);
809
810   if (!engine->ops->opassuan_transact)
811     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
812
813   return (*engine->ops->opassuan_transact) (engine->engine,
814                                             command,
815                                             data_cb, data_cb_value,
816                                             inq_cb, inq_cb_value,
817                                             status_cb, status_cb_value);
818 }
819
820
821 gpgme_error_t
822 _gpgme_engine_op_conf_load (engine_t engine, gpgme_conf_comp_t *conf_p)
823 {
824   if (!engine)
825     return gpg_error (GPG_ERR_INV_VALUE);
826
827   if (!engine->ops->conf_load)
828     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
829
830   return (*engine->ops->conf_load) (engine->engine, conf_p);
831 }
832
833
834 gpgme_error_t
835 _gpgme_engine_op_conf_save (engine_t engine, gpgme_conf_comp_t conf)
836 {
837   if (!engine)
838     return gpg_error (GPG_ERR_INV_VALUE);
839
840   if (!engine->ops->conf_save)
841     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
842
843   return (*engine->ops->conf_save) (engine->engine, conf);
844 }
845
846
847 void
848 _gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
849 {
850   if (!engine)
851     return;
852
853   (*engine->ops->set_io_cbs) (engine->engine, io_cbs);
854 }
855
856
857 void
858 _gpgme_engine_io_event (engine_t engine,
859                         gpgme_event_io_t type, void *type_data)
860 {
861   if (!engine)
862     return;
863
864   (*engine->ops->io_event) (engine->engine, type, type_data);
865 }
866
867
868 /* Cancel the session and the pending operation if any.  */
869 gpgme_error_t
870 _gpgme_engine_cancel (engine_t engine)
871 {
872   if (!engine)
873     return gpg_error (GPG_ERR_INV_VALUE);
874
875   if (!engine->ops->cancel)
876     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
877
878   return (*engine->ops->cancel) (engine->engine);
879 }
880
881
882 /* Cancel the pending operation, but not the complete session.  */
883 gpgme_error_t
884 _gpgme_engine_cancel_op (engine_t engine)
885 {
886   if (!engine)
887     return gpg_error (GPG_ERR_INV_VALUE);
888
889   if (!engine->ops->cancel_op)
890     return 0;
891
892   return (*engine->ops->cancel_op) (engine->engine);
893 }
894
895
896 /* Change the passphrase for KEY.  */
897 gpgme_error_t
898 _gpgme_engine_op_passwd (engine_t engine, gpgme_key_t key,
899                          unsigned int flags)
900 {
901   if (!engine)
902     return gpg_error (GPG_ERR_INV_VALUE);
903
904   if (!engine->ops->passwd)
905     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
906
907   return (*engine->ops->passwd) (engine->engine, key, flags);
908 }
909
910
911 /* Set the pinentry mode for ENGINE to MODE.  */
912 gpgme_error_t
913 _gpgme_engine_set_pinentry_mode (engine_t engine, gpgme_pinentry_mode_t mode)
914 {
915   if (!engine)
916     return gpg_error (GPG_ERR_INV_VALUE);
917
918   if (!engine->ops->set_pinentry_mode)
919     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
920
921   return (*engine->ops->set_pinentry_mode) (engine->engine, mode);
922 }