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