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