2010-11-19 Marcus Brinkmann <mb@g10code.com>
[gpgme.git] / src / engine-gpgconf.c
1 /* engine-gpgconf.c - gpg-conf engine.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2008 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 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <stdlib.h>
26 #include <string.h>
27 #ifdef HAVE_SYS_TYPES_H
28 # include <sys/types.h>
29 #endif
30 #include <assert.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 #include <fcntl.h> /* FIXME */
35 #include <errno.h>
36
37 #include "gpgme.h"
38 #include "util.h"
39 #include "ops.h"
40 #include "wait.h"
41 #include "priv-io.h"
42 #include "sema.h"
43
44 #include "assuan.h"
45 #include "debug.h"
46
47 #include "engine-backend.h"
48
49 \f
50 struct engine_gpgconf
51 {
52   char *file_name;
53   char *home_dir;
54 };
55
56 typedef struct engine_gpgconf *engine_gpgconf_t;
57
58 \f
59 static char *
60 gpgconf_get_version (const char *file_name)
61 {
62   return _gpgme_get_program_version (file_name ? file_name
63                                      : _gpgme_get_gpgconf_path ());
64 }
65
66
67 static const char *
68 gpgconf_get_req_version (void)
69 {
70   return NEED_GPGCONF_VERSION;
71 }
72
73 \f
74 static void
75 gpgconf_release (void *engine)
76 {
77   engine_gpgconf_t gpgconf = engine;
78
79   if (!gpgconf)
80     return;
81
82   if (gpgconf->file_name)
83     free (gpgconf->file_name);
84   if (gpgconf->home_dir)
85     free (gpgconf->home_dir);
86
87   free (gpgconf);
88 }
89
90
91 static gpgme_error_t
92 gpgconf_new (void **engine, const char *file_name, const char *home_dir)
93 {
94   gpgme_error_t err = 0;
95   engine_gpgconf_t gpgconf;
96
97   gpgconf = calloc (1, sizeof *gpgconf);
98   if (!gpgconf)
99     return gpg_error_from_errno (errno);
100
101   gpgconf->file_name = strdup (file_name ? file_name
102                                : _gpgme_get_gpgconf_path ());
103   if (!gpgconf->file_name)
104     err = gpg_error_from_syserror ();
105
106   if (!err && home_dir)
107     {
108       gpgconf->home_dir = strdup (home_dir);
109       if (!gpgconf->home_dir)
110         err = gpg_error_from_syserror ();
111     }
112
113   if (err)
114     gpgconf_release (gpgconf);
115   else
116     *engine = gpgconf;
117
118   return err;
119 }
120
121 \f
122 static void
123 release_arg (gpgme_conf_arg_t arg, gpgme_conf_type_t alt_type)
124 {
125   while (arg)
126     {
127       gpgme_conf_arg_t next = arg->next;
128
129       if (alt_type == GPGME_CONF_STRING)
130         free (arg->value.string);
131       free (arg);
132       arg = next;
133     }
134 }
135
136
137 static void
138 release_opt (gpgme_conf_opt_t opt)
139 {
140   if (opt->name)
141     free (opt->name);
142   if (opt->description)
143     free (opt->description);
144   if (opt->argname)
145     free (opt->argname);
146
147   release_arg (opt->default_value, opt->alt_type);
148   if (opt->default_description)
149     free (opt->default_description);
150   
151   release_arg (opt->no_arg_value, opt->alt_type);
152   release_arg (opt->value, opt->alt_type);
153   release_arg (opt->new_value, opt->alt_type);
154
155   free (opt);
156 }
157
158
159 static void
160 release_comp (gpgme_conf_comp_t comp)
161 {
162   gpgme_conf_opt_t opt;
163
164   if (comp->name)
165     free (comp->name);
166   if (comp->description)
167     free (comp->description);
168   if (comp->program_name)
169     free (comp->program_name);
170
171   opt = comp->options;
172   while (opt)
173     {
174       gpgme_conf_opt_t next = opt->next;
175       release_opt (opt);
176       opt = next;
177     }
178
179   free (comp);
180 }
181
182
183 static void
184 gpgconf_config_release (gpgme_conf_comp_t conf)
185 {
186   while (conf)
187     {
188       gpgme_conf_comp_t next = conf->next;
189       release_comp (conf);
190       conf = next;
191     }
192 }
193
194
195 static gpgme_error_t
196 gpgconf_read (void *engine, char *arg1, char *arg2,
197               gpgme_error_t (*cb) (void *hook, char *line),
198               void *hook)
199 {
200   struct engine_gpgconf *gpgconf = engine;
201   gpgme_error_t err = 0;
202 #define LINELENGTH 1024
203   char linebuf[LINELENGTH] = "";
204   int linelen = 0;
205   char *argv[4] = { NULL /* file_name */, NULL, NULL, NULL };
206   int rp[2];
207   struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */, -1, 0},
208                                    {-1, -1} };
209   int status;
210   int nread;
211   char *mark = NULL;
212
213   argv[1] = arg1;
214   argv[2] = arg2;
215
216
217   /* FIXME: Deal with engine->home_dir.  */
218
219   /* _gpgme_engine_new guarantees that this is not NULL.  */
220   argv[0] = gpgconf->file_name;
221   
222   if (_gpgme_io_pipe (rp, 1) < 0)
223     return gpg_error_from_syserror ();
224
225   cfd[0].fd = rp[1];
226
227   status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
228   if (status < 0)
229     {
230       _gpgme_io_close (rp[0]);
231       _gpgme_io_close (rp[1]);
232       return gpg_error_from_syserror ();
233     }
234
235   do
236     {
237       nread = _gpgme_io_read (rp[0], 
238                               linebuf + linelen, LINELENGTH - linelen - 1);
239       if (nread > 0)
240         {
241           char *line;
242           const char *lastmark = NULL;
243           size_t nused;
244
245           linelen += nread;
246           linebuf[linelen] = '\0';
247
248           for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
249             {
250               lastmark = mark;
251               if (mark > line && mark[-1] == '\r')
252                 mark[-1] = '\0';
253               else
254                 mark[0] = '\0';
255
256               /* Got a full line.  Due to the CR removal code (which
257                  occurs only on Windows) we might be one-off and thus
258                  would see empty lines.  Don't pass them to the
259                  callback. */
260               err = *line? (*cb) (hook, line) : 0;
261               if (err)
262                 goto leave;
263             }
264
265           nused = lastmark? (lastmark + 1 - linebuf) : 0;
266           memmove (linebuf, linebuf + nused, linelen - nused);
267           linelen -= nused;
268         }
269     }
270   while (nread > 0 && linelen < LINELENGTH - 1);
271   
272   if (!err && nread < 0)
273     err = gpg_error_from_syserror ();
274   if (!err && nread > 0)
275     err = gpg_error (GPG_ERR_LINE_TOO_LONG);
276
277  leave:
278   _gpgme_io_close (rp[0]);
279
280   return err;
281 }
282
283
284 static gpgme_error_t
285 gpgconf_config_load_cb (void *hook, char *line)
286 {
287   gpgme_conf_comp_t *comp_p = hook;
288   gpgme_conf_comp_t comp = *comp_p;
289 #define NR_FIELDS 16
290   char *field[NR_FIELDS];
291   int fields = 0;
292
293   while (line && fields < NR_FIELDS)
294     {
295       field[fields++] = line;
296       line = strchr (line, ':');
297       if (line)
298         *(line++) = '\0';
299     }
300
301   /* We require at least the first 3 fields.  */
302   if (fields < 2)
303     return gpg_error (GPG_ERR_INV_ENGINE);
304
305   /* Find the pointer to the new component in the list.  */
306   while (comp && comp->next)
307     comp = comp->next;
308   if (comp)
309     comp_p = &comp->next;
310
311   comp = calloc (1, sizeof (*comp));
312   if (!comp)
313     return gpg_error_from_syserror ();
314   /* Prepare return value.  */
315   comp->_last_opt_p = &comp->options;
316   *comp_p = comp;
317
318   comp->name = strdup (field[0]);
319   if (!comp->name)
320     return gpg_error_from_syserror ();
321
322   comp->description = strdup (field[1]);
323   if (!comp->description)
324     return gpg_error_from_syserror ();
325
326   if (fields >= 3)
327     {
328       comp->program_name = strdup (field[2]);
329       if (!comp->program_name)
330         return gpg_error_from_syserror ();
331     }
332
333   return 0;
334 }
335
336
337 static gpgme_error_t
338 gpgconf_parse_option (gpgme_conf_opt_t opt,
339                       gpgme_conf_arg_t *arg_p, char *line)
340 {
341   gpgme_error_t err;
342   char *mark;
343
344   if (!line[0])
345     return 0;
346
347   while (line)
348     {
349       gpgme_conf_arg_t arg;
350
351       mark = strchr (line, ',');
352       if (mark)
353         *mark = '\0';
354
355       arg = calloc (1, sizeof (*arg));
356       if (!arg)
357         return gpg_error_from_syserror ();
358       *arg_p = arg;
359       arg_p = &arg->next;
360
361       if (*line == '\0')
362         arg->no_arg = 1;
363       else
364         {
365           switch (opt->alt_type)
366             {
367               /* arg->value.count is an alias for arg->value.uint32.  */
368             case GPGME_CONF_NONE:
369             case GPGME_CONF_UINT32:
370               arg->value.uint32 = strtoul (line, NULL, 0);
371               break;
372               
373             case GPGME_CONF_INT32:
374               arg->value.uint32 = strtol (line, NULL, 0);
375               break;
376               
377             case GPGME_CONF_STRING:
378               /* The complex types below are only here to silent the
379                  compiler warning. */
380             case GPGME_CONF_FILENAME: 
381             case GPGME_CONF_LDAP_SERVER:
382             case GPGME_CONF_KEY_FPR:
383             case GPGME_CONF_PUB_KEY:
384             case GPGME_CONF_SEC_KEY:
385             case GPGME_CONF_ALIAS_LIST:
386               /* Skip quote character.  */
387               line++;
388               
389               err = _gpgme_decode_percent_string (line, &arg->value.string,
390                                                   0, 0);
391               if (err)
392                 return err;
393               break;
394             }
395         }
396
397       /* Find beginning of next value.  */
398       if (mark++ && *mark)
399         line = mark;
400       else
401         line = NULL;
402     }
403
404   return 0;
405 }
406
407
408 static gpgme_error_t
409 gpgconf_config_load_cb2 (void *hook, char *line)
410 {
411   gpgme_error_t err;
412   gpgme_conf_comp_t comp = hook;
413   gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
414   gpgme_conf_opt_t opt;
415 #define NR_FIELDS 16
416   char *field[NR_FIELDS];
417   int fields = 0;
418
419   while (line && fields < NR_FIELDS)
420     {
421       field[fields++] = line;
422       line = strchr (line, ':');
423       if (line)
424         *(line++) = '\0';
425     }
426
427   /* We require at least the first 10 fields.  */
428   if (fields < 10)
429     return gpg_error (GPG_ERR_INV_ENGINE);
430
431   opt = calloc (1, sizeof (*opt));
432   if (!opt)
433     return gpg_error_from_syserror ();
434
435   comp->_last_opt_p = &opt->next;
436   *opt_p = opt;
437
438   if (field[0][0])
439     {
440       opt->name = strdup (field[0]);
441       if (!opt->name)
442         return gpg_error_from_syserror ();
443     }
444
445   opt->flags = strtoul (field[1], NULL, 0);
446
447   opt->level = strtoul (field[2], NULL, 0);
448
449   if (field[3][0])
450     {
451       opt->description = strdup (field[3]);
452       if (!opt->description)
453         return gpg_error_from_syserror ();
454     }
455
456   opt->type = strtoul (field[4], NULL, 0);
457
458   opt->alt_type = strtoul (field[5], NULL, 0);
459
460   if (field[6][0])
461     {
462       opt->argname = strdup (field[6]);
463       if (!opt->argname)
464         return gpg_error_from_syserror ();
465     }
466
467   if (opt->flags & GPGME_CONF_DEFAULT)
468     {
469       err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
470       if (err)
471         return err;
472     }
473   else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
474     {
475       opt->default_description = strdup (field[7]);
476       if (!opt->default_description)
477         return gpg_error_from_syserror ();
478     }
479
480   if (opt->flags & GPGME_CONF_NO_ARG_DESC)
481     {
482       opt->no_arg_description = strdup (field[8]);
483       if (!opt->no_arg_description)
484         return gpg_error_from_syserror ();
485     }
486   else
487     {
488       err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
489       if (err)
490         return err;
491     }
492
493   err = gpgconf_parse_option (opt, &opt->value, field[9]);
494   if (err)
495     return err;
496
497   return 0;
498 }
499
500
501 static gpgme_error_t
502 gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
503 {
504   gpgme_error_t err;
505   gpgme_conf_comp_t comp = NULL;
506   gpgme_conf_comp_t cur_comp;
507
508   *comp_p = NULL;
509
510   err = gpgconf_read (engine, "--list-components", NULL,
511                       gpgconf_config_load_cb, &comp);
512   if (err)
513     {
514       gpgconf_release (comp);
515       return err;
516     }
517
518   cur_comp = comp;
519   while (!err && cur_comp)
520     {
521       err = gpgconf_read (engine, "--list-options", cur_comp->name,
522                           gpgconf_config_load_cb2, cur_comp);
523       cur_comp = cur_comp->next;
524     }
525
526   if (err)
527     {
528       gpgconf_release (comp);
529       return err;
530     }
531
532   *comp_p = comp;
533   return 0;
534 }
535
536
537 \f
538 gpgme_error_t
539 _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
540                      gpgme_conf_type_t type, void *value)
541 {
542   gpgme_conf_arg_t arg;
543
544   arg = calloc (1, sizeof (*arg));
545   if (!arg)
546     return gpg_error_from_syserror ();
547
548   if (!value)
549     arg->no_arg = 1;
550   else
551     {
552       /* We need to switch on type here because the alt-type is not
553          yet known.  */
554       switch (type)
555         {
556         case GPGME_CONF_NONE:
557         case GPGME_CONF_UINT32:
558           arg->value.uint32 = *((unsigned int *) value);
559           break;
560           
561         case GPGME_CONF_INT32:
562           arg->value.int32 = *((int *) value);
563           break;
564           
565         case GPGME_CONF_STRING:
566         case GPGME_CONF_FILENAME:
567         case GPGME_CONF_LDAP_SERVER:
568         case GPGME_CONF_KEY_FPR:
569         case GPGME_CONF_PUB_KEY:
570         case GPGME_CONF_SEC_KEY:
571         case GPGME_CONF_ALIAS_LIST:
572           arg->value.string = strdup (value);
573           if (!arg->value.string)
574             {
575               free (arg);
576               return gpg_error_from_syserror ();
577             }
578           break;
579           
580         default:
581           free (arg);
582           return gpg_error (GPG_ERR_INV_VALUE);
583         }
584     }
585
586   *arg_p = arg;
587   return 0;
588 }
589
590
591 void
592 _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
593 {
594   /* Lacking the alt_type we need to switch on type here.  */
595   switch (type)
596     {
597     case GPGME_CONF_NONE:
598     case GPGME_CONF_UINT32:
599     case GPGME_CONF_INT32:
600     case GPGME_CONF_STRING:
601     default:
602       break;
603        
604     case GPGME_CONF_FILENAME:
605     case GPGME_CONF_LDAP_SERVER:
606     case GPGME_CONF_KEY_FPR:
607     case GPGME_CONF_PUB_KEY:
608     case GPGME_CONF_SEC_KEY:
609     case GPGME_CONF_ALIAS_LIST:
610       type = GPGME_CONF_STRING;
611       break;
612     }
613
614   release_arg (arg, type);
615 }
616
617
618 gpgme_error_t
619 _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
620 {
621   if (reset)
622     {
623       if (opt->new_value)
624         release_arg (opt->new_value, opt->alt_type);
625      opt->new_value = NULL;
626       opt->change_value = 0;
627     }
628   else
629     {
630       /* Support self-assignment, for example for adding an item to an
631          existing list.  */
632       if (opt->new_value && arg != opt->new_value)
633         {
634           release_arg (opt->new_value, opt->alt_type);
635           opt->new_value = arg;
636         }
637       opt->change_value = 1;
638     }
639   return 0;
640 }
641
642 \f
643 /* FIXME: Major problem: We don't get errors from gpgconf.  */
644
645 static gpgme_error_t
646 gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
647 {
648   struct engine_gpgconf *gpgconf = engine;
649   gpgme_error_t err = 0;
650 #define BUFLEN 1024
651   char buf[BUFLEN];
652   int buflen = 0;
653   char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
654   int rp[2];
655   struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
656   int status;
657   int nwrite;
658
659   /* FIXME: Deal with engine->home_dir.  */
660
661   /* _gpgme_engine_new guarantees that this is not NULL.  */
662   argv[0] = gpgconf->file_name;
663   argv[0] = "/nowhere/path-needs-to-be-fixed/gpgconf";
664
665   if (_gpgme_io_pipe (rp, 0) < 0)
666     return gpg_error_from_syserror ();
667
668   cfd[0].fd = rp[0];
669
670   status = _gpgme_io_spawn (gpgconf->file_name, argv, 0, cfd, NULL, NULL, NULL);
671   if (status < 0)
672     {
673       _gpgme_io_close (rp[0]);
674       _gpgme_io_close (rp[1]);
675       return gpg_error_from_syserror ();
676     }
677
678   for (;;)
679     {
680       if (buflen == 0)
681         {
682           do
683             {
684               buflen = gpgme_data_read (conf, buf, BUFLEN);
685             }
686           while (buflen < 0 && errno == EAGAIN);
687
688           if (buflen < 0)
689             {
690               err = gpg_error_from_syserror ();
691               _gpgme_io_close (rp[1]);
692               return err;
693             }
694           else if (buflen == 0)
695             {
696               /* All is written.  */
697               _gpgme_io_close (rp[1]);
698               return 0;
699             }
700         }
701
702       do
703         {
704           nwrite = _gpgme_io_write (rp[1], buf, buflen);
705         }
706       while (nwrite < 0 && errno == EAGAIN);
707
708       if (nwrite > 0)
709         {
710           buflen -= nwrite;
711           if (buflen > 0)
712             memmove (&buf[0], &buf[nwrite], buflen);
713         }
714       else if (nwrite < 0)
715         {
716           _gpgme_io_close (rp[1]);
717           return gpg_error_from_syserror ();
718         }
719     }
720
721   return 0;
722 }
723
724
725 static gpgme_error_t
726 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
727 {
728   gpgme_error_t err = 0;
729   int amt = 0;
730   char buf[16];
731
732   while (amt >= 0 && arg)
733     {
734       switch (option->alt_type)
735         {
736         case GPGME_CONF_NONE:
737         case GPGME_CONF_UINT32:
738         default:
739           snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
740           buf[sizeof (buf) - 1] = '\0';
741           amt = gpgme_data_write (conf, buf, strlen (buf));
742           break;
743           
744         case GPGME_CONF_INT32:
745           snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
746           buf[sizeof (buf) - 1] = '\0';
747           amt = gpgme_data_write (conf, buf, strlen (buf));
748           break;
749         
750           
751         case GPGME_CONF_STRING:
752           /* The complex types below are only here to silent the
753              compiler warning. */
754         case GPGME_CONF_FILENAME: 
755         case GPGME_CONF_LDAP_SERVER:
756         case GPGME_CONF_KEY_FPR:
757         case GPGME_CONF_PUB_KEY:
758         case GPGME_CONF_SEC_KEY:
759         case GPGME_CONF_ALIAS_LIST:
760           /* One quote character, and three times to allow
761              for percent escaping.  */
762           {
763             char *ptr = arg->value.string;
764             amt = gpgme_data_write (conf, "\"", 1);
765             if (amt < 0)
766               break;
767
768             while (!err && *ptr)
769               {
770                 switch (*ptr)
771                   {
772                   case '%':
773                     amt = gpgme_data_write (conf, "%25", 3);
774                     break;
775
776                   case ':':
777                     amt = gpgme_data_write (conf, "%3a", 3);
778                     break;
779
780                   case ',':
781                     amt = gpgme_data_write (conf, "%2c", 3);
782                     break;
783
784                   default:
785                     amt = gpgme_data_write (conf, ptr, 1);
786                   }
787                 ptr++;
788               }
789           }
790           break;
791         }
792
793       if (amt < 0)
794         break;
795
796       arg = arg->next;
797       /* Comma separator.  */
798       if (arg)
799         amt = gpgme_data_write (conf, ",", 1);
800     }
801
802   if (amt < 0)
803     return gpg_error_from_syserror ();
804   
805   return 0;
806 }
807
808
809 static gpgme_error_t
810 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
811 {
812   gpgme_error_t err;
813   int amt = 0;
814   /* We use a data object to store the new configuration.  */
815   gpgme_data_t conf;
816   gpgme_conf_opt_t option;
817   int something_changed = 0;
818
819   err = gpgme_data_new (&conf);
820   if (err)
821     return err;
822
823   option = comp->options;
824   while (!err && amt >= 0 && option)
825     {
826       if (option->change_value)
827         {
828           unsigned int flags = 0;
829           char buf[16];
830
831           something_changed = 1;
832
833           amt = gpgme_data_write (conf, option->name, strlen (option->name));
834           if (amt >= 0)
835             amt = gpgme_data_write (conf, ":", 1);
836           if (amt < 0)
837             break;
838
839           if (!option->new_value)
840             flags |= GPGME_CONF_DEFAULT;
841           snprintf (buf, sizeof (buf), "%u", flags);
842           buf[sizeof (buf) - 1] = '\0';
843
844           amt = gpgme_data_write (conf, buf, strlen (buf));
845           if (amt >= 0)
846             amt = gpgme_data_write (conf, ":", 1);
847           if (amt < 0)
848             break;
849
850           if (option->new_value)
851             {
852               err = arg_to_data (conf, option, option->new_value);
853               if (err)
854                 break;
855             }
856           amt = gpgme_data_write (conf, "\n", 1);
857         }
858       option = option->next;
859     }
860   if (!err && amt < 0)
861     err = gpg_error_from_syserror ();
862   if (err || !something_changed)
863     goto bail;
864
865   err = gpgme_data_seek (conf, 0, SEEK_SET);
866   if (err)
867     goto bail;
868
869   err = gpgconf_write (engine, "--change-options", comp->name, conf);
870  bail:
871   gpgme_data_release (conf);
872   return err;
873 }
874
875
876 static void
877 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
878 {
879   /* Nothing to do.  */
880 }
881
882 \f
883 /* Currently, we do not use the engine interface for the various
884    operations.  */
885 void
886 _gpgme_conf_release (gpgme_conf_comp_t conf)
887 {
888   gpgconf_config_release (conf);
889 }
890
891 \f
892 struct engine_ops _gpgme_engine_ops_gpgconf =
893   {
894     /* Static functions.  */
895     _gpgme_get_gpgconf_path,
896     NULL,
897     gpgconf_get_version,
898     gpgconf_get_req_version,
899     gpgconf_new,
900
901     /* Member functions.  */
902     gpgconf_release,
903     NULL,               /* reset */
904     NULL,               /* set_status_handler */
905     NULL,               /* set_command_handler */
906     NULL,               /* set_colon_line_handler */
907     NULL,               /* set_locale */
908     NULL,               /* set_protocol */
909     NULL,               /* decrypt */
910     NULL,               /* decrypt_verify */
911     NULL,               /* delete */
912     NULL,               /* edit */
913     NULL,               /* encrypt */
914     NULL,               /* encrypt_sign */
915     NULL,               /* export */
916     NULL,               /* export_ext */
917     NULL,               /* genkey */
918     NULL,               /* import */
919     NULL,               /* keylist */
920     NULL,               /* keylist_ext */
921     NULL,               /* sign */
922     NULL,               /* trustlist */
923     NULL,               /* verify */
924     NULL,               /* getauditlog */
925     NULL,               /* opassuan_transact */
926     gpgconf_conf_load,
927     gpgconf_conf_save,
928     gpgconf_set_io_cbs,
929     NULL,               /* io_event */
930     NULL                /* cancel */
931   };