core: Pass the engine's version string to the engine's new function.
[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                                  info->version);
468       if (err)
469         {
470           free (engine);
471           return err;
472         }
473     }
474   else
475     engine->engine = NULL;
476
477   *r_engine = engine;
478   return 0;
479 }
480
481
482 gpgme_error_t
483 _gpgme_engine_reset (engine_t engine)
484 {
485   if (!engine)
486     return gpg_error (GPG_ERR_INV_VALUE);
487
488   if (!engine->ops->reset)
489     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
490
491   return (*engine->ops->reset) (engine->engine);
492 }
493
494
495 void
496 _gpgme_engine_release (engine_t engine)
497 {
498   if (!engine)
499     return;
500
501   if (engine->ops->release)
502     (*engine->ops->release) (engine->engine);
503   free (engine);
504 }
505
506
507 /* Set a status callback which is used to monitor the status values
508  * before they are passed to a handler set with
509  * _gpgme_engine_set_status_handler.  */
510 void
511 _gpgme_engine_set_status_cb (engine_t engine,
512                              gpgme_status_cb_t cb, void *cb_value)
513 {
514   if (!engine)
515     return;
516
517   if (engine->ops->set_status_cb)
518     (*engine->ops->set_status_cb) (engine->engine, cb, cb_value);
519 }
520
521
522 void
523 _gpgme_engine_set_status_handler (engine_t engine,
524                                   engine_status_handler_t fnc, void *fnc_value)
525 {
526   if (!engine)
527     return;
528
529   if (engine->ops->set_status_handler)
530     (*engine->ops->set_status_handler) (engine->engine, fnc, fnc_value);
531 }
532
533
534 gpgme_error_t
535 _gpgme_engine_set_command_handler (engine_t engine,
536                                    engine_command_handler_t fnc,
537                                    void *fnc_value,
538                                    gpgme_data_t linked_data)
539 {
540   if (!engine)
541     return gpg_error (GPG_ERR_INV_VALUE);
542
543   if (!engine->ops->set_command_handler)
544     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
545
546   return (*engine->ops->set_command_handler) (engine->engine,
547                                               fnc, fnc_value, linked_data);
548 }
549
550 gpgme_error_t
551 _gpgme_engine_set_colon_line_handler (engine_t engine,
552                                       engine_colon_line_handler_t fnc,
553                                       void *fnc_value)
554 {
555   if (!engine)
556     return gpg_error (GPG_ERR_INV_VALUE);
557
558   if (!engine->ops->set_colon_line_handler)
559     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
560
561   return (*engine->ops->set_colon_line_handler) (engine->engine,
562                                                  fnc, fnc_value);
563 }
564
565 gpgme_error_t
566 _gpgme_engine_set_locale (engine_t engine, int category,
567                           const char *value)
568 {
569   if (!engine)
570     return gpg_error (GPG_ERR_INV_VALUE);
571
572   if (!engine->ops->set_locale)
573     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
574
575   return (*engine->ops->set_locale) (engine->engine, category, value);
576 }
577
578
579 gpgme_error_t
580 _gpgme_engine_set_protocol (engine_t engine, gpgme_protocol_t protocol)
581 {
582   if (!engine)
583     return gpg_error (GPG_ERR_INV_VALUE);
584
585   if (!engine->ops->set_protocol)
586     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
587
588   return (*engine->ops->set_protocol) (engine->engine, protocol);
589 }
590
591
592 gpgme_error_t
593 _gpgme_engine_op_decrypt (engine_t engine, gpgme_data_t ciph,
594                           gpgme_data_t plain)
595 {
596   if (!engine)
597     return gpg_error (GPG_ERR_INV_VALUE);
598
599   if (!engine->ops->decrypt)
600     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
601
602   return (*engine->ops->decrypt) (engine->engine, ciph, plain);
603 }
604
605
606 gpgme_error_t
607 _gpgme_engine_op_decrypt_verify (engine_t engine, gpgme_data_t ciph,
608                                  gpgme_data_t plain)
609 {
610   if (!engine)
611     return gpg_error (GPG_ERR_INV_VALUE);
612
613   if (!engine->ops->decrypt_verify)
614     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
615
616   return (*engine->ops->decrypt_verify) (engine->engine, ciph, plain);
617 }
618
619
620 gpgme_error_t
621 _gpgme_engine_op_delete (engine_t engine, gpgme_key_t key,
622                          int allow_secret)
623 {
624   if (!engine)
625     return gpg_error (GPG_ERR_INV_VALUE);
626
627   if (!engine->ops->delete)
628     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
629
630   return (*engine->ops->delete) (engine->engine, key, allow_secret);
631 }
632
633
634 gpgme_error_t
635 _gpgme_engine_op_edit (engine_t engine, int type, gpgme_key_t key,
636                        gpgme_data_t out, gpgme_ctx_t ctx /* FIXME */)
637 {
638   if (!engine)
639     return gpg_error (GPG_ERR_INV_VALUE);
640
641   if (!engine->ops->edit)
642     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
643
644   return (*engine->ops->edit) (engine->engine, type, key, out, ctx);
645 }
646
647
648 gpgme_error_t
649 _gpgme_engine_op_encrypt (engine_t engine, gpgme_key_t recp[],
650                           gpgme_encrypt_flags_t flags,
651                           gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
652 {
653   if (!engine)
654     return gpg_error (GPG_ERR_INV_VALUE);
655
656   if (!engine->ops->encrypt)
657     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
658
659   return (*engine->ops->encrypt) (engine->engine, recp, flags, plain, ciph,
660                                   use_armor);
661 }
662
663
664 gpgme_error_t
665 _gpgme_engine_op_encrypt_sign (engine_t engine, gpgme_key_t recp[],
666                                gpgme_encrypt_flags_t flags,
667                                gpgme_data_t plain, gpgme_data_t ciph,
668                                int use_armor, gpgme_ctx_t ctx /* FIXME */)
669 {
670   if (!engine)
671     return gpg_error (GPG_ERR_INV_VALUE);
672
673   if (!engine->ops->encrypt_sign)
674     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
675
676   return (*engine->ops->encrypt_sign) (engine->engine, recp, flags,
677                                        plain, ciph, use_armor, ctx);
678 }
679
680
681 gpgme_error_t
682 _gpgme_engine_op_export (engine_t engine, const char *pattern,
683                          gpgme_export_mode_t mode, gpgme_data_t keydata,
684                          int use_armor)
685 {
686   if (!engine)
687     return gpg_error (GPG_ERR_INV_VALUE);
688
689   if (!engine->ops->export)
690     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
691
692   return (*engine->ops->export) (engine->engine, pattern, mode,
693                                  keydata, use_armor);
694 }
695
696
697 gpgme_error_t
698 _gpgme_engine_op_export_ext (engine_t engine, const char *pattern[],
699                              unsigned int reserved, gpgme_data_t keydata,
700                              int use_armor)
701 {
702   if (!engine)
703     return gpg_error (GPG_ERR_INV_VALUE);
704
705   if (!engine->ops->export_ext)
706     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
707
708   return (*engine->ops->export_ext) (engine->engine, pattern, reserved,
709                                      keydata, use_armor);
710 }
711
712
713 gpgme_error_t
714 _gpgme_engine_op_genkey (engine_t engine, gpgme_data_t help_data,
715                          int use_armor, gpgme_data_t pubkey,
716                          gpgme_data_t seckey)
717 {
718   if (!engine)
719     return gpg_error (GPG_ERR_INV_VALUE);
720
721   if (!engine->ops->genkey)
722     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
723
724   return (*engine->ops->genkey) (engine->engine, help_data, use_armor,
725                                  pubkey, seckey);
726 }
727
728
729 gpgme_error_t
730 _gpgme_engine_op_import (engine_t engine, gpgme_data_t keydata,
731                          gpgme_key_t *keyarray)
732 {
733   if (!engine)
734     return gpg_error (GPG_ERR_INV_VALUE);
735
736   if (!engine->ops->import)
737     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
738
739   return (*engine->ops->import) (engine->engine, keydata, keyarray);
740 }
741
742
743 gpgme_error_t
744 _gpgme_engine_op_keylist (engine_t engine, const char *pattern,
745                           int secret_only, gpgme_keylist_mode_t mode,
746                           int engine_flags)
747 {
748   if (!engine)
749     return gpg_error (GPG_ERR_INV_VALUE);
750
751   if (!engine->ops->keylist)
752     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
753
754   return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode,
755                                   engine_flags);
756 }
757
758
759 gpgme_error_t
760 _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[],
761                               int secret_only, int reserved,
762                               gpgme_keylist_mode_t mode, int engine_flags)
763 {
764   if (!engine)
765     return gpg_error (GPG_ERR_INV_VALUE);
766
767   if (!engine->ops->keylist_ext)
768     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
769
770   return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only,
771                                       reserved, mode, engine_flags);
772 }
773
774
775 gpgme_error_t
776 _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out,
777                        gpgme_sig_mode_t mode, int use_armor,
778                        int use_textmode, int include_certs,
779                        gpgme_ctx_t ctx /* FIXME */)
780 {
781   if (!engine)
782     return gpg_error (GPG_ERR_INV_VALUE);
783
784   if (!engine->ops->sign)
785     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
786
787   return (*engine->ops->sign) (engine->engine, in, out, mode, use_armor,
788                                use_textmode, include_certs, ctx);
789 }
790
791
792 gpgme_error_t
793 _gpgme_engine_op_trustlist (engine_t engine, const char *pattern)
794 {
795   if (!engine)
796     return gpg_error (GPG_ERR_INV_VALUE);
797
798   if (!engine->ops->trustlist)
799     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
800
801   return (*engine->ops->trustlist) (engine->engine, pattern);
802 }
803
804
805 gpgme_error_t
806 _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
807                          gpgme_data_t signed_text, gpgme_data_t plaintext)
808 {
809   if (!engine)
810     return gpg_error (GPG_ERR_INV_VALUE);
811
812   if (!engine->ops->verify)
813     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
814
815   return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext);
816 }
817
818
819 gpgme_error_t
820 _gpgme_engine_op_getauditlog (engine_t engine, gpgme_data_t output,
821                               unsigned int flags)
822 {
823   if (!engine)
824     return gpg_error (GPG_ERR_INV_VALUE);
825
826   if (!engine->ops->getauditlog)
827     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
828
829   return (*engine->ops->getauditlog) (engine->engine, output, flags);
830 }
831
832
833 gpgme_error_t
834 _gpgme_engine_op_assuan_transact (engine_t engine,
835                                   const char *command,
836                                   gpgme_assuan_data_cb_t data_cb,
837                                   void *data_cb_value,
838                                   gpgme_assuan_inquire_cb_t inq_cb,
839                                   void *inq_cb_value,
840                                   gpgme_assuan_status_cb_t status_cb,
841                                   void *status_cb_value)
842 {
843   if (!engine)
844     return gpg_error (GPG_ERR_INV_VALUE);
845
846   if (!engine->ops->opassuan_transact)
847     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
848
849   return (*engine->ops->opassuan_transact) (engine->engine,
850                                             command,
851                                             data_cb, data_cb_value,
852                                             inq_cb, inq_cb_value,
853                                             status_cb, status_cb_value);
854 }
855
856
857 gpgme_error_t
858 _gpgme_engine_op_conf_load (engine_t engine, gpgme_conf_comp_t *conf_p)
859 {
860   if (!engine)
861     return gpg_error (GPG_ERR_INV_VALUE);
862
863   if (!engine->ops->conf_load)
864     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
865
866   return (*engine->ops->conf_load) (engine->engine, conf_p);
867 }
868
869
870 gpgme_error_t
871 _gpgme_engine_op_conf_save (engine_t engine, gpgme_conf_comp_t conf)
872 {
873   if (!engine)
874     return gpg_error (GPG_ERR_INV_VALUE);
875
876   if (!engine->ops->conf_save)
877     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
878
879   return (*engine->ops->conf_save) (engine->engine, conf);
880 }
881
882
883 void
884 _gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
885 {
886   if (!engine)
887     return;
888
889   (*engine->ops->set_io_cbs) (engine->engine, io_cbs);
890 }
891
892
893 void
894 _gpgme_engine_io_event (engine_t engine,
895                         gpgme_event_io_t type, void *type_data)
896 {
897   if (!engine)
898     return;
899
900   (*engine->ops->io_event) (engine->engine, type, type_data);
901 }
902
903
904 /* Cancel the session and the pending operation if any.  */
905 gpgme_error_t
906 _gpgme_engine_cancel (engine_t engine)
907 {
908   if (!engine)
909     return gpg_error (GPG_ERR_INV_VALUE);
910
911   if (!engine->ops->cancel)
912     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
913
914   return (*engine->ops->cancel) (engine->engine);
915 }
916
917
918 /* Cancel the pending operation, but not the complete session.  */
919 gpgme_error_t
920 _gpgme_engine_cancel_op (engine_t engine)
921 {
922   if (!engine)
923     return gpg_error (GPG_ERR_INV_VALUE);
924
925   if (!engine->ops->cancel_op)
926     return 0;
927
928   return (*engine->ops->cancel_op) (engine->engine);
929 }
930
931
932 /* Change the passphrase for KEY.  */
933 gpgme_error_t
934 _gpgme_engine_op_passwd (engine_t engine, gpgme_key_t key,
935                          unsigned int flags)
936 {
937   if (!engine)
938     return gpg_error (GPG_ERR_INV_VALUE);
939
940   if (!engine->ops->passwd)
941     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
942
943   return (*engine->ops->passwd) (engine->engine, key, flags);
944 }
945
946
947 /* Set the pinentry mode for ENGINE to MODE.  */
948 gpgme_error_t
949 _gpgme_engine_set_pinentry_mode (engine_t engine, gpgme_pinentry_mode_t mode)
950 {
951   if (!engine)
952     return gpg_error (GPG_ERR_INV_VALUE);
953
954   if (!engine->ops->set_pinentry_mode)
955     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
956
957   return (*engine->ops->set_pinentry_mode) (engine->engine, mode);
958 }
959
960
961 gpgme_error_t
962 _gpgme_engine_op_spawn (engine_t engine,
963                         const char *file, const char *argv[],
964                         gpgme_data_t datain,
965                         gpgme_data_t dataout, gpgme_data_t dataerr,
966                         unsigned int flags)
967 {
968   if (!engine)
969     return gpg_error (GPG_ERR_INV_VALUE);
970
971   if (!engine->ops->opspawn)
972     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
973
974   return (*engine->ops->opspawn) (engine->engine, file, argv,
975                                   datain, dataout, dataerr, flags);
976 }