87d39392fe13a45f3e5accdc005b54ae4108e5ef
[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                          unsigned int reserved, 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, reserved,
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 {
672   if (!engine)
673     return gpg_error (GPG_ERR_INV_VALUE);
674
675   if (!engine->ops->import)
676     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
677
678   return (*engine->ops->import) (engine->engine, keydata);
679 }
680
681
682 gpgme_error_t
683 _gpgme_engine_op_keylist (engine_t engine, const char *pattern,
684                           int secret_only, gpgme_keylist_mode_t mode)
685 {
686   if (!engine)
687     return gpg_error (GPG_ERR_INV_VALUE);
688
689   if (!engine->ops->keylist)
690     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
691
692   return (*engine->ops->keylist) (engine->engine, pattern, secret_only, mode);
693 }
694
695
696 gpgme_error_t
697 _gpgme_engine_op_keylist_ext (engine_t engine, const char *pattern[],
698                               int secret_only, int reserved,
699                               gpgme_keylist_mode_t mode)
700 {
701   if (!engine)
702     return gpg_error (GPG_ERR_INV_VALUE);
703
704   if (!engine->ops->keylist_ext)
705     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
706
707   return (*engine->ops->keylist_ext) (engine->engine, pattern, secret_only,
708                                       reserved, mode);
709 }
710
711
712 gpgme_error_t
713 _gpgme_engine_op_sign (engine_t engine, gpgme_data_t in, gpgme_data_t out,
714                        gpgme_sig_mode_t mode, int use_armor,
715                        int use_textmode, int include_certs,
716                        gpgme_ctx_t ctx /* FIXME */)
717 {
718   if (!engine)
719     return gpg_error (GPG_ERR_INV_VALUE);
720
721   if (!engine->ops->sign)
722     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
723
724   return (*engine->ops->sign) (engine->engine, in, out, mode, use_armor,
725                                use_textmode, include_certs, ctx);
726 }
727
728
729 gpgme_error_t
730 _gpgme_engine_op_trustlist (engine_t engine, const char *pattern)
731 {
732   if (!engine)
733     return gpg_error (GPG_ERR_INV_VALUE);
734
735   if (!engine->ops->trustlist)
736     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
737
738   return (*engine->ops->trustlist) (engine->engine, pattern);
739 }
740
741
742 gpgme_error_t
743 _gpgme_engine_op_verify (engine_t engine, gpgme_data_t sig,
744                          gpgme_data_t signed_text, gpgme_data_t plaintext)
745 {
746   if (!engine)
747     return gpg_error (GPG_ERR_INV_VALUE);
748
749   if (!engine->ops->verify)
750     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
751
752   return (*engine->ops->verify) (engine->engine, sig, signed_text, plaintext);
753 }
754
755
756 gpgme_error_t
757 _gpgme_engine_op_getauditlog (engine_t engine, gpgme_data_t output,
758                               unsigned int flags)
759 {
760   if (!engine)
761     return gpg_error (GPG_ERR_INV_VALUE);
762
763   if (!engine->ops->getauditlog)
764     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
765
766   return (*engine->ops->getauditlog) (engine->engine, output, flags);
767 }
768
769
770 gpgme_error_t
771 _gpgme_engine_op_assuan_transact (engine_t engine, 
772                                   const char *command,
773                                   engine_assuan_result_cb_t result_cb,
774                                   void *result_cb_value,
775                                   gpgme_assuan_data_cb_t data_cb,
776                                   void *data_cb_value,
777                                   gpgme_assuan_inquire_cb_t inq_cb,
778                                   void *inq_cb_value,
779                                   gpgme_assuan_status_cb_t status_cb,
780                                   void *status_cb_value)
781 {
782   if (!engine)
783     return gpg_error (GPG_ERR_INV_VALUE);
784
785   if (!engine->ops->opassuan_transact)
786     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
787
788   return (*engine->ops->opassuan_transact) (engine->engine, 
789                                             command,
790                                             result_cb, result_cb_value,
791                                             data_cb, data_cb_value,
792                                             inq_cb, inq_cb_value,
793                                             status_cb, status_cb_value);
794 }
795
796
797 gpgme_error_t
798 _gpgme_engine_op_conf_load (engine_t engine, gpgme_conf_comp_t *conf_p)
799 {
800   if (!engine)
801     return gpg_error (GPG_ERR_INV_VALUE);
802
803   if (!engine->ops->conf_load)
804     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
805
806   return (*engine->ops->conf_load) (engine->engine, conf_p);
807 }
808
809
810 gpgme_error_t
811 _gpgme_engine_op_conf_save (engine_t engine, gpgme_conf_comp_t conf)
812 {
813   if (!engine)
814     return gpg_error (GPG_ERR_INV_VALUE);
815
816   if (!engine->ops->conf_save)
817     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
818
819   return (*engine->ops->conf_save) (engine->engine, conf);
820 }
821
822
823 void
824 _gpgme_engine_set_io_cbs (engine_t engine, gpgme_io_cbs_t io_cbs)
825 {
826   if (!engine)
827     return;
828
829   (*engine->ops->set_io_cbs) (engine->engine, io_cbs);
830 }
831
832
833 void
834 _gpgme_engine_io_event (engine_t engine,
835                         gpgme_event_io_t type, void *type_data)
836 {
837   if (!engine)
838     return;
839
840   (*engine->ops->io_event) (engine->engine, type, type_data);
841 }
842
843
844 gpgme_error_t
845 _gpgme_engine_cancel (engine_t engine)
846 {
847   if (!engine)
848     return gpg_error (GPG_ERR_INV_VALUE);
849
850   if (!engine->ops->cancel)
851     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
852
853   return (*engine->ops->cancel) (engine->engine);
854 }