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