Merge branch 'gpgmepp'
[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,
232                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
233   if (status < 0)
234     {
235       _gpgme_io_close (rp[0]);
236       _gpgme_io_close (rp[1]);
237       return gpg_error_from_syserror ();
238     }
239
240   linebufsize = 1024; /* Usually enough for conf lines.  */
241   linebuf = malloc (linebufsize);
242   if (!linebuf)
243     {
244       err = gpg_error_from_syserror ();
245       goto leave;
246     }
247   linelen = 0;
248
249   while ((nread = _gpgme_io_read (rp[0], linebuf + linelen,
250                                   linebufsize - linelen - 1)))
251     {
252       char *line;
253       const char *lastmark = NULL;
254       size_t nused;
255
256       if (nread < 0)
257         {
258           err = gpg_error_from_syserror ();
259           goto leave;
260         }
261
262       linelen += nread;
263       linebuf[linelen] = '\0';
264
265       for (line=linebuf; (mark = strchr (line, '\n')); line = mark+1 )
266         {
267           lastmark = mark;
268           if (mark > line && mark[-1] == '\r')
269             mark[-1] = '\0';
270           else
271             mark[0] = '\0';
272
273           /* Got a full line.  Due to the CR removal code (which
274              occurs only on Windows) we might be one-off and thus
275              would see empty lines.  Don't pass them to the
276              callback. */
277           err = *line? (*cb) (hook, line) : 0;
278           if (err)
279             goto leave;
280         }
281
282       nused = lastmark? (lastmark + 1 - linebuf) : 0;
283       memmove (linebuf, linebuf + nused, linelen - nused);
284       linelen -= nused;
285
286       if (!(linelen < linebufsize - 1))
287         {
288           char *newlinebuf;
289
290           if (linelen <  8 * 1024 - 1)
291             linebufsize = 8 * 1024;
292           else if (linelen < 64 * 1024 - 1)
293             linebufsize = 64 * 1024;
294           else
295             {
296               /* We reached our limit - give up.  */
297               err = gpg_error (GPG_ERR_LINE_TOO_LONG);
298               goto leave;
299             }
300
301           newlinebuf = realloc (linebuf, linebufsize);
302           if (!newlinebuf)
303             {
304               err = gpg_error_from_syserror ();
305               goto leave;
306             }
307           linebuf = newlinebuf;
308         }
309     }
310
311  leave:
312   free (linebuf);
313   _gpgme_io_close (rp[0]);
314   return err;
315 }
316
317
318 static gpgme_error_t
319 gpgconf_config_load_cb (void *hook, char *line)
320 {
321   gpgme_conf_comp_t *comp_p = hook;
322   gpgme_conf_comp_t comp = *comp_p;
323 #define NR_FIELDS 16
324   char *field[NR_FIELDS];
325   int fields = 0;
326
327   while (line && fields < NR_FIELDS)
328     {
329       field[fields++] = line;
330       line = strchr (line, ':');
331       if (line)
332         *(line++) = '\0';
333     }
334
335   /* We require at least the first 3 fields.  */
336   if (fields < 2)
337     return trace_gpg_error (GPG_ERR_INV_ENGINE);
338
339   /* Find the pointer to the new component in the list.  */
340   while (comp && comp->next)
341     comp = comp->next;
342   if (comp)
343     comp_p = &comp->next;
344
345   comp = calloc (1, sizeof (*comp));
346   if (!comp)
347     return gpg_error_from_syserror ();
348   /* Prepare return value.  */
349   comp->_last_opt_p = &comp->options;
350   *comp_p = comp;
351
352   comp->name = strdup (field[0]);
353   if (!comp->name)
354     return gpg_error_from_syserror ();
355
356   comp->description = strdup (field[1]);
357   if (!comp->description)
358     return gpg_error_from_syserror ();
359
360   if (fields >= 3)
361     {
362       comp->program_name = strdup (field[2]);
363       if (!comp->program_name)
364         return gpg_error_from_syserror ();
365     }
366
367   return 0;
368 }
369
370
371 static gpgme_error_t
372 gpgconf_parse_option (gpgme_conf_opt_t opt,
373                       gpgme_conf_arg_t *arg_p, char *line)
374 {
375   gpgme_error_t err;
376   char *mark;
377
378   if (!line[0])
379     return 0;
380
381   while (line)
382     {
383       gpgme_conf_arg_t arg;
384
385       mark = strchr (line, ',');
386       if (mark)
387         *mark = '\0';
388
389       arg = calloc (1, sizeof (*arg));
390       if (!arg)
391         return gpg_error_from_syserror ();
392       *arg_p = arg;
393       arg_p = &arg->next;
394
395       if (*line == '\0')
396         arg->no_arg = 1;
397       else
398         {
399           switch (opt->alt_type)
400             {
401               /* arg->value.count is an alias for arg->value.uint32.  */
402             case GPGME_CONF_NONE:
403             case GPGME_CONF_UINT32:
404               arg->value.uint32 = strtoul (line, NULL, 0);
405               break;
406
407             case GPGME_CONF_INT32:
408               arg->value.uint32 = strtol (line, NULL, 0);
409               break;
410
411             case GPGME_CONF_STRING:
412               /* The complex types below are only here to silent the
413                  compiler warning. */
414             case GPGME_CONF_FILENAME:
415             case GPGME_CONF_LDAP_SERVER:
416             case GPGME_CONF_KEY_FPR:
417             case GPGME_CONF_PUB_KEY:
418             case GPGME_CONF_SEC_KEY:
419             case GPGME_CONF_ALIAS_LIST:
420               /* Skip quote character.  */
421               line++;
422
423               err = _gpgme_decode_percent_string (line, &arg->value.string,
424                                                   0, 0);
425               if (err)
426                 return err;
427               break;
428             }
429         }
430
431       /* Find beginning of next value.  */
432       if (mark++ && *mark)
433         line = mark;
434       else
435         line = NULL;
436     }
437
438   return 0;
439 }
440
441
442 static gpgme_error_t
443 gpgconf_config_load_cb2 (void *hook, char *line)
444 {
445   gpgme_error_t err;
446   gpgme_conf_comp_t comp = hook;
447   gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
448   gpgme_conf_opt_t opt;
449 #define NR_FIELDS 16
450   char *field[NR_FIELDS];
451   int fields = 0;
452
453   while (line && fields < NR_FIELDS)
454     {
455       field[fields++] = line;
456       line = strchr (line, ':');
457       if (line)
458         *(line++) = '\0';
459     }
460
461   /* We require at least the first 10 fields.  */
462   if (fields < 10)
463     return trace_gpg_error (GPG_ERR_INV_ENGINE);
464
465   opt = calloc (1, sizeof (*opt));
466   if (!opt)
467     return gpg_error_from_syserror ();
468
469   comp->_last_opt_p = &opt->next;
470   *opt_p = opt;
471
472   if (field[0][0])
473     {
474       opt->name = strdup (field[0]);
475       if (!opt->name)
476         return gpg_error_from_syserror ();
477     }
478
479   opt->flags = strtoul (field[1], NULL, 0);
480
481   opt->level = strtoul (field[2], NULL, 0);
482
483   if (field[3][0])
484     {
485       opt->description = strdup (field[3]);
486       if (!opt->description)
487         return gpg_error_from_syserror ();
488     }
489
490   opt->type = strtoul (field[4], NULL, 0);
491
492   opt->alt_type = strtoul (field[5], NULL, 0);
493
494   if (field[6][0])
495     {
496       opt->argname = strdup (field[6]);
497       if (!opt->argname)
498         return gpg_error_from_syserror ();
499     }
500
501   if (opt->flags & GPGME_CONF_DEFAULT)
502     {
503       err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
504       if (err)
505         return err;
506     }
507   else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
508     {
509       opt->default_description = strdup (field[7]);
510       if (!opt->default_description)
511         return gpg_error_from_syserror ();
512     }
513
514   if (opt->flags & GPGME_CONF_NO_ARG_DESC)
515     {
516       opt->no_arg_description = strdup (field[8]);
517       if (!opt->no_arg_description)
518         return gpg_error_from_syserror ();
519     }
520   else
521     {
522       err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
523       if (err)
524         return err;
525     }
526
527   err = gpgconf_parse_option (opt, &opt->value, field[9]);
528   if (err)
529     return err;
530
531   return 0;
532 }
533
534
535 static gpgme_error_t
536 gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
537 {
538   gpgme_error_t err;
539   gpgme_conf_comp_t comp = NULL;
540   gpgme_conf_comp_t cur_comp;
541
542   *comp_p = NULL;
543
544   err = gpgconf_read (engine, "--list-components", NULL,
545                       gpgconf_config_load_cb, &comp);
546   if (err)
547     {
548       gpgconf_release (comp);
549       return err;
550     }
551
552   cur_comp = comp;
553   while (!err && cur_comp)
554     {
555       err = gpgconf_read (engine, "--list-options", cur_comp->name,
556                           gpgconf_config_load_cb2, cur_comp);
557       cur_comp = cur_comp->next;
558     }
559
560   if (err)
561     {
562       gpgconf_release (comp);
563       return err;
564     }
565
566   *comp_p = comp;
567   return 0;
568 }
569
570
571 \f
572 gpgme_error_t
573 _gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
574                      gpgme_conf_type_t type, const void *value)
575 {
576   gpgme_conf_arg_t arg;
577
578   arg = calloc (1, sizeof (*arg));
579   if (!arg)
580     return gpg_error_from_syserror ();
581
582   if (!value)
583     arg->no_arg = 1;
584   else
585     {
586       /* We need to switch on type here because the alt-type is not
587          yet known.  */
588       switch (type)
589         {
590         case GPGME_CONF_NONE:
591         case GPGME_CONF_UINT32:
592           arg->value.uint32 = *((unsigned int *) value);
593           break;
594
595         case GPGME_CONF_INT32:
596           arg->value.int32 = *((int *) value);
597           break;
598
599         case GPGME_CONF_STRING:
600         case GPGME_CONF_FILENAME:
601         case GPGME_CONF_LDAP_SERVER:
602         case GPGME_CONF_KEY_FPR:
603         case GPGME_CONF_PUB_KEY:
604         case GPGME_CONF_SEC_KEY:
605         case GPGME_CONF_ALIAS_LIST:
606           arg->value.string = strdup (value);
607           if (!arg->value.string)
608             {
609               free (arg);
610               return gpg_error_from_syserror ();
611             }
612           break;
613
614         default:
615           free (arg);
616           return gpg_error (GPG_ERR_INV_VALUE);
617         }
618     }
619
620   *arg_p = arg;
621   return 0;
622 }
623
624
625 void
626 _gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
627 {
628   /* Lacking the alt_type we need to switch on type here.  */
629   switch (type)
630     {
631     case GPGME_CONF_NONE:
632     case GPGME_CONF_UINT32:
633     case GPGME_CONF_INT32:
634     case GPGME_CONF_STRING:
635     default:
636       break;
637
638     case GPGME_CONF_FILENAME:
639     case GPGME_CONF_LDAP_SERVER:
640     case GPGME_CONF_KEY_FPR:
641     case GPGME_CONF_PUB_KEY:
642     case GPGME_CONF_SEC_KEY:
643     case GPGME_CONF_ALIAS_LIST:
644       type = GPGME_CONF_STRING;
645       break;
646     }
647
648   release_arg (arg, type);
649 }
650
651
652 gpgme_error_t
653 _gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
654 {
655   if (reset)
656     {
657       if (opt->new_value)
658         release_arg (opt->new_value, opt->alt_type);
659       opt->new_value = NULL;
660       opt->change_value = 0;
661     }
662   else
663     {
664       /* Support self-assignment, for example for adding an item to an
665          existing list.  */
666       if (opt->new_value && arg != opt->new_value)
667         release_arg (opt->new_value, opt->alt_type);
668       opt->new_value = arg;
669       opt->change_value = 1;
670     }
671   return 0;
672 }
673
674 \f
675 /* FIXME: Major problem: We don't get errors from gpgconf.  */
676
677 static gpgme_error_t
678 gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
679 {
680   struct engine_gpgconf *gpgconf = engine;
681   gpgme_error_t err = 0;
682 #define BUFLEN 1024
683   char buf[BUFLEN];
684   int buflen = 0;
685   char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
686   int rp[2];
687   struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
688   int status;
689   int nwrite;
690
691   /* FIXME: Deal with engine->home_dir.  */
692
693   /* _gpgme_engine_new guarantees that this is not NULL.  */
694   argv[0] = gpgconf->file_name;
695
696   if (_gpgme_io_pipe (rp, 0) < 0)
697     return gpg_error_from_syserror ();
698
699   cfd[0].fd = rp[0];
700
701   status = _gpgme_io_spawn (gpgconf->file_name, argv,
702                             IOSPAWN_FLAG_DETACHED, cfd, NULL, NULL, NULL);
703   if (status < 0)
704     {
705       _gpgme_io_close (rp[0]);
706       _gpgme_io_close (rp[1]);
707       return gpg_error_from_syserror ();
708     }
709
710   for (;;)
711     {
712       if (buflen == 0)
713         {
714           do
715             {
716               buflen = gpgme_data_read (conf, buf, BUFLEN);
717             }
718           while (buflen < 0 && errno == EAGAIN);
719
720           if (buflen < 0)
721             {
722               err = gpg_error_from_syserror ();
723               _gpgme_io_close (rp[1]);
724               return err;
725             }
726           else if (buflen == 0)
727             {
728               /* All is written.  */
729               _gpgme_io_close (rp[1]);
730               return 0;
731             }
732         }
733
734       do
735         {
736           nwrite = _gpgme_io_write (rp[1], buf, buflen);
737         }
738       while (nwrite < 0 && errno == EAGAIN);
739
740       if (nwrite > 0)
741         {
742           buflen -= nwrite;
743           if (buflen > 0)
744             memmove (&buf[0], &buf[nwrite], buflen);
745         }
746       else if (nwrite < 0)
747         {
748           _gpgme_io_close (rp[1]);
749           return gpg_error_from_syserror ();
750         }
751     }
752
753   return 0;
754 }
755
756
757 static gpgme_error_t
758 arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
759 {
760   gpgme_error_t err = 0;
761   int amt = 0;
762   char buf[16];
763
764   while (amt >= 0 && arg)
765     {
766       switch (option->alt_type)
767         {
768         case GPGME_CONF_NONE:
769         case GPGME_CONF_UINT32:
770         default:
771           snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
772           buf[sizeof (buf) - 1] = '\0';
773           amt = gpgme_data_write (conf, buf, strlen (buf));
774           break;
775
776         case GPGME_CONF_INT32:
777           snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
778           buf[sizeof (buf) - 1] = '\0';
779           amt = gpgme_data_write (conf, buf, strlen (buf));
780           break;
781
782
783         case GPGME_CONF_STRING:
784           /* The complex types below are only here to silent the
785              compiler warning. */
786         case GPGME_CONF_FILENAME:
787         case GPGME_CONF_LDAP_SERVER:
788         case GPGME_CONF_KEY_FPR:
789         case GPGME_CONF_PUB_KEY:
790         case GPGME_CONF_SEC_KEY:
791         case GPGME_CONF_ALIAS_LIST:
792           if (arg->value.string)
793             {
794               /* One quote character, and three times to allow for
795                  percent escaping.  */
796               char *ptr = arg->value.string;
797               amt = gpgme_data_write (conf, "\"", 1);
798               if (amt < 0)
799                 break;
800
801               while (!err && *ptr)
802                 {
803                   switch (*ptr)
804                     {
805                     case '%':
806                       amt = gpgme_data_write (conf, "%25", 3);
807                       break;
808
809                     case ':':
810                       amt = gpgme_data_write (conf, "%3a", 3);
811                       break;
812
813                     case ',':
814                       amt = gpgme_data_write (conf, "%2c", 3);
815                       break;
816
817                     default:
818                       amt = gpgme_data_write (conf, ptr, 1);
819                     }
820                   ptr++;
821                 }
822             }
823           break;
824         }
825
826       if (amt < 0)
827         break;
828
829       arg = arg->next;
830       /* Comma separator.  */
831       if (arg)
832         amt = gpgme_data_write (conf, ",", 1);
833     }
834
835   if (amt < 0)
836     return gpg_error_from_syserror ();
837
838   return 0;
839 }
840
841
842 static gpgme_error_t
843 gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
844 {
845   gpgme_error_t err;
846   int amt = 0;
847   /* We use a data object to store the new configuration.  */
848   gpgme_data_t conf;
849   gpgme_conf_opt_t option;
850   int something_changed = 0;
851
852   err = gpgme_data_new (&conf);
853   if (err)
854     return err;
855
856   option = comp->options;
857   while (!err && amt >= 0 && option)
858     {
859       if (option->change_value)
860         {
861           unsigned int flags = 0;
862           char buf[16];
863
864           something_changed = 1;
865
866           amt = gpgme_data_write (conf, option->name, strlen (option->name));
867           if (amt >= 0)
868             amt = gpgme_data_write (conf, ":", 1);
869           if (amt < 0)
870             break;
871
872           if (!option->new_value)
873             flags |= GPGME_CONF_DEFAULT;
874           snprintf (buf, sizeof (buf), "%u", flags);
875           buf[sizeof (buf) - 1] = '\0';
876
877           amt = gpgme_data_write (conf, buf, strlen (buf));
878           if (amt >= 0)
879             amt = gpgme_data_write (conf, ":", 1);
880           if (amt < 0)
881             break;
882
883           if (option->new_value)
884             {
885               err = arg_to_data (conf, option, option->new_value);
886               if (err)
887                 break;
888             }
889           amt = gpgme_data_write (conf, "\n", 1);
890         }
891       option = option->next;
892     }
893   if (!err && amt < 0)
894     err = gpg_error_from_syserror ();
895   if (err || !something_changed)
896     goto bail;
897
898   err = gpgme_data_seek (conf, 0, SEEK_SET);
899   if (err)
900     goto bail;
901
902   err = gpgconf_write (engine, "--change-options", comp->name, conf);
903  bail:
904   gpgme_data_release (conf);
905   return err;
906 }
907
908
909 static void
910 gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
911 {
912   /* Nothing to do.  */
913 }
914
915 \f
916 /* Currently, we do not use the engine interface for the various
917    operations.  */
918 void
919 _gpgme_conf_release (gpgme_conf_comp_t conf)
920 {
921   gpgconf_config_release (conf);
922 }
923
924 \f
925 struct engine_ops _gpgme_engine_ops_gpgconf =
926   {
927     /* Static functions.  */
928     _gpgme_get_default_gpgconf_name,
929     NULL,
930     gpgconf_get_version,
931     gpgconf_get_req_version,
932     gpgconf_new,
933
934     /* Member functions.  */
935     gpgconf_release,
936     NULL,               /* reset */
937     NULL,               /* set_status_handler */
938     NULL,               /* set_command_handler */
939     NULL,               /* set_colon_line_handler */
940     NULL,               /* set_locale */
941     NULL,               /* set_protocol */
942     NULL,               /* decrypt */
943     NULL,               /* decrypt_verify */
944     NULL,               /* delete */
945     NULL,               /* edit */
946     NULL,               /* encrypt */
947     NULL,               /* encrypt_sign */
948     NULL,               /* export */
949     NULL,               /* export_ext */
950     NULL,               /* genkey */
951     NULL,               /* import */
952     NULL,               /* keylist */
953     NULL,               /* keylist_ext */
954     NULL,               /* sign */
955     NULL,               /* trustlist */
956     NULL,               /* verify */
957     NULL,               /* getauditlog */
958     NULL,               /* opassuan_transact */
959     gpgconf_conf_load,
960     gpgconf_conf_save,
961     gpgconf_set_io_cbs,
962     NULL,               /* io_event */
963     NULL,               /* cancel */
964     NULL,               /* cancel_op */
965     NULL,               /* passwd */
966     NULL,               /* set_pinentry_mode */
967     NULL                /* opspawn */
968   };