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