~noskcaj/ubuntu/trusty/gpgme1.0/1.4.3

« back to all changes in this revision

Viewing changes to gpgme/engine-gpgconf.c

  • Committer: Bazaar Package Importer
  • Author(s): Jose Carlos Garcia Sogo
  • Date: 2008-03-08 14:06:34 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20080308140634-dom8okim5mdkz22o
Tags: 1.1.6-2
* Bump shlibs info, as this version added some new symbols (Closes: #469534)
* Urgency set to medium, as this package has yet transitioned to lenny.
* debian/control: add Vcs-Browser info 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Check protocol.
 
2
// IMPLEMENT NO_ARG_DESC!!!!
 
3
 
 
4
/* engine-gpgconf.c - gpg-conf engine.
 
5
   Copyright (C) 2000 Werner Koch (dd9jn)
 
6
   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
 
7
 
 
8
   This file is part of GPGME.
 
9
 
 
10
   GPGME is free software; you can redistribute it and/or modify it
 
11
   under the terms of the GNU Lesser General Public License as
 
12
   published by the Free Software Foundation; either version 2.1 of
 
13
   the License, or (at your option) any later version.
 
14
   
 
15
   GPGME is distributed in the hope that it will be useful, but
 
16
   WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
18
   Lesser General Public License for more details.
 
19
   
 
20
   You should have received a copy of the GNU Lesser General Public
 
21
   License along with this program; if not, write to the Free Software
 
22
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 
23
   02111-1307, USA.  */
 
24
 
 
25
#if HAVE_CONFIG_H
 
26
#include <config.h>
 
27
#endif
 
28
 
 
29
#include <stdlib.h>
 
30
#include <string.h>
 
31
#include <sys/types.h>
 
32
#include <assert.h>
 
33
#include <unistd.h>
 
34
#include <locale.h>
 
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
 
 
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
 
 
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_gpgconf_path ());
 
65
}
 
66
 
 
67
 
 
68
static const char *
 
69
gpgconf_get_req_version (void)
 
70
{
 
71
  return NEED_GPGCONF_VERSION;
 
72
}
 
73
 
 
74
 
 
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_errno (errno);
 
101
 
 
102
  gpgconf->file_name = strdup (file_name ? file_name
 
103
                               : _gpgme_get_gpgconf_path ());
 
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
 
 
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
 
 
196
static gpgme_error_t
 
197
gpgconf_read (void *engine, char *arg1, char *arg2,
 
198
              gpgme_error_t (*cb) (void *hook, char *line),
 
199
              void *hook)
 
200
{
 
201
  struct engine_gpgconf *gpgconf = engine;
 
202
  gpgme_error_t err = 0;
 
203
#define LINELENGTH 1024
 
204
  char line[LINELENGTH] = "";
 
205
  int linelen = 0;
 
206
  char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
 
207
  int rp[2];
 
208
  struct spawn_fd_item_s pfd[] = { {0, -1}, {-1, -1} };
 
209
  struct spawn_fd_item_s cfd[] = { {-1, 1 /* STDOUT_FILENO */}, {-1, -1} };
 
210
  int status;
 
211
  int nread;
 
212
  char *mark = NULL;
 
213
 
 
214
  /* FIXME: Deal with engine->home_dir.  */
 
215
 
 
216
  /* _gpgme_engine_new guarantees that this is not NULL.  */
 
217
  argv[0] = gpgconf->file_name;
 
218
  
 
219
  if (_gpgme_io_pipe (rp, 1) < 0)
 
220
    return gpg_error_from_syserror ();
 
221
 
 
222
  pfd[0].fd = rp[1];
 
223
  cfd[0].fd = rp[1];
 
224
 
 
225
  status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, pfd);
 
226
  if (status < 0)
 
227
    {
 
228
      _gpgme_io_close (rp[0]);
 
229
      _gpgme_io_close (rp[1]);
 
230
      return gpg_error_from_syserror ();
 
231
    }
 
232
 
 
233
  do
 
234
    {
 
235
      nread = _gpgme_io_read (rp[0], &line[linelen], LINELENGTH - linelen - 1);
 
236
      if (nread > 0)
 
237
        {
 
238
          line[linelen + nread] = '\0';
 
239
          linelen += nread;
 
240
 
 
241
          while ((mark = strchr (line, '\n')))
 
242
            {
 
243
              char *eol = mark;
 
244
              
 
245
              if (eol > &line[0] && *eol == '\r')
 
246
                eol--;
 
247
              *eol = '\0';
 
248
              
 
249
              /* Got a full line.  */
 
250
              err = (*cb) (hook, line);
 
251
              if (err)
 
252
                break;
 
253
              
 
254
              linelen -= mark - line;
 
255
              memmove (line, eol + 1, linelen);
 
256
            }
 
257
        }
 
258
    }
 
259
  while (nread > 0 && linelen < LINELENGTH - 1);
 
260
  
 
261
  if (!err && nread < 0)
 
262
    err = gpg_error_from_syserror ();
 
263
  if (!err && nread > 0)
 
264
    err = gpg_error (GPG_ERR_LINE_TOO_LONG);
 
265
 
 
266
  _gpgme_io_close (rp[0]);
 
267
 
 
268
  return err;
 
269
}
 
270
 
 
271
 
 
272
static gpgme_error_t
 
273
gpgconf_config_load_cb (void *hook, char *line)
 
274
{
 
275
  gpgme_conf_comp_t *comp_p = hook;
 
276
  gpgme_conf_comp_t comp = *comp_p;
 
277
#define NR_FIELDS 16
 
278
  char *field[NR_FIELDS];
 
279
  int fields = 0;
 
280
 
 
281
  while (line && fields < NR_FIELDS)
 
282
    {
 
283
      field[fields++] = line;
 
284
      line = strchr (line, ':');
 
285
      if (line)
 
286
        *(line++) = '\0';
 
287
    }
 
288
 
 
289
  /* We require at least the first 3 fields.  */
 
290
  if (fields < 2)
 
291
    return gpg_error (GPG_ERR_INV_ENGINE);
 
292
 
 
293
  /* Find the pointer to the new component in the list.  */
 
294
  while (comp && comp->next)
 
295
    comp = comp->next;
 
296
  if (comp)
 
297
    comp_p = &comp->next;
 
298
 
 
299
  comp = calloc (1, sizeof (*comp));
 
300
  if (!comp)
 
301
    return gpg_error_from_syserror ();
 
302
  /* Prepare return value.  */
 
303
  comp->_last_opt_p = &comp->options;
 
304
  *comp_p = comp;
 
305
 
 
306
  comp->name = strdup (field[0]);
 
307
  if (!comp->name)
 
308
    return gpg_error_from_syserror ();
 
309
 
 
310
  comp->description = strdup (field[1]);
 
311
  if (!comp->description)
 
312
    return gpg_error_from_syserror ();
 
313
 
 
314
  if (fields >= 3)
 
315
    {
 
316
      comp->description = strdup (field[2]);
 
317
      if (!comp->description)
 
318
        return gpg_error_from_syserror ();
 
319
    }
 
320
 
 
321
  return 0;
 
322
}
 
323
 
 
324
 
 
325
static gpgme_error_t
 
326
gpgconf_parse_option (gpgme_conf_opt_t opt,
 
327
                      gpgme_conf_arg_t *arg_p, char *line)
 
328
{
 
329
  gpgme_error_t err;
 
330
  char *mark;
 
331
 
 
332
  if (!line[0])
 
333
    return 0;
 
334
 
 
335
  mark = strchr (line, ',');
 
336
  if (mark)
 
337
    *mark = '\0';
 
338
 
 
339
  while (line)
 
340
    {
 
341
      gpgme_conf_arg_t arg = calloc (1, sizeof (*arg));
 
342
      if (!arg)
 
343
        return gpg_error_from_syserror ();
 
344
      *arg_p = arg;
 
345
      arg_p = &arg->next;
 
346
 
 
347
      if (*line == '\0')
 
348
        arg->no_arg = 1;
 
349
      else
 
350
        {
 
351
          switch (opt->alt_type)
 
352
            {
 
353
              /* arg->value.count is an alias for arg->value.uint32.  */
 
354
            case GPGME_CONF_NONE:
 
355
            case GPGME_CONF_UINT32:
 
356
              arg->value.uint32 = strtoul (line, NULL, 0);
 
357
              break;
 
358
              
 
359
            case GPGME_CONF_INT32:
 
360
              arg->value.uint32 = strtol (line, NULL, 0);
 
361
              break;
 
362
              
 
363
            case GPGME_CONF_STRING:
 
364
            case GPGME_CONF_PATHNAME:
 
365
            case GPGME_CONF_LDAP_SERVER:
 
366
              /* Skip quote character.  */
 
367
              line++;
 
368
              
 
369
              err = _gpgme_decode_percent_string (line, &arg->value.string,
 
370
                                                  0, 0);
 
371
              if (err)
 
372
                return err;
 
373
              break;
 
374
            }
 
375
        }
 
376
 
 
377
      /* Find beginning of next value.  */
 
378
      if (mark++ && *mark)
 
379
        line = mark;
 
380
      else
 
381
        line = NULL;
 
382
    }
 
383
 
 
384
  return 0;
 
385
}
 
386
 
 
387
 
 
388
static gpgme_error_t
 
389
gpgconf_config_load_cb2 (void *hook, char *line)
 
390
{
 
391
  gpgme_error_t err;
 
392
  gpgme_conf_comp_t comp = hook;
 
393
  gpgme_conf_opt_t *opt_p = comp->_last_opt_p;
 
394
  gpgme_conf_opt_t opt;
 
395
#define NR_FIELDS 16
 
396
  char *field[NR_FIELDS];
 
397
  int fields = 0;
 
398
 
 
399
  while (line && fields < NR_FIELDS)
 
400
    {
 
401
      field[fields++] = line;
 
402
      line = strchr (line, ':');
 
403
      if (line)
 
404
        *(line++) = '\0';
 
405
    }
 
406
 
 
407
  /* We require at least the first 10 fields.  */
 
408
  if (fields < 10)
 
409
    return gpg_error (GPG_ERR_INV_ENGINE);
 
410
 
 
411
  opt = calloc (1, sizeof (*opt));
 
412
  if (!opt)
 
413
    return gpg_error_from_syserror ();
 
414
 
 
415
  comp->_last_opt_p = &opt->next;
 
416
  *opt_p = opt;
 
417
 
 
418
  if (field[0][0])
 
419
    {
 
420
      opt->name = strdup (field[0]);
 
421
      if (!opt->name)
 
422
        return gpg_error_from_syserror ();
 
423
    }
 
424
 
 
425
  opt->flags = strtoul (field[1], NULL, 0);
 
426
 
 
427
  opt->level = strtoul (field[2], NULL, 0);
 
428
 
 
429
  if (field[3][0])
 
430
    {
 
431
      opt->description = strdup (field[3]);
 
432
      if (!opt->description)
 
433
        return gpg_error_from_syserror ();
 
434
    }
 
435
 
 
436
  opt->type = strtoul (field[4], NULL, 0);
 
437
 
 
438
  opt->alt_type = strtoul (field[5], NULL, 0);
 
439
 
 
440
  if (field[6][0])
 
441
    {
 
442
      opt->argname = strdup (field[6]);
 
443
      if (!opt->argname)
 
444
        return gpg_error_from_syserror ();
 
445
    }
 
446
 
 
447
  if (opt->flags & GPGME_CONF_DEFAULT)
 
448
    {
 
449
      err = gpgconf_parse_option (opt, &opt->default_value, field[7]);
 
450
      if (err)
 
451
        return err;
 
452
    }
 
453
  else if ((opt->flags & GPGME_CONF_DEFAULT_DESC) && field[7][0])
 
454
    {
 
455
      opt->default_description = strdup (field[7]);
 
456
      if (!opt->default_description)
 
457
        return gpg_error_from_syserror ();
 
458
    }
 
459
 
 
460
  err = gpgconf_parse_option (opt, &opt->no_arg_value, field[8]);
 
461
  if (err)
 
462
    return err;
 
463
 
 
464
  err = gpgconf_parse_option (opt, &opt->value, field[9]);
 
465
  if (err)
 
466
    return err;
 
467
 
 
468
  return 0;
 
469
}
 
470
 
 
471
 
 
472
static gpgme_error_t
 
473
gpgconf_conf_load (void *engine, gpgme_conf_comp_t *comp_p)
 
474
{
 
475
  gpgme_error_t err;
 
476
  gpgme_conf_comp_t comp = NULL;
 
477
  gpgme_conf_comp_t cur_comp;
 
478
 
 
479
  *comp_p = NULL;
 
480
 
 
481
  err = gpgconf_read (engine, "--list-components", NULL,
 
482
                      gpgconf_config_load_cb, &comp);
 
483
  if (err)
 
484
    {
 
485
      gpgconf_release (comp);
 
486
      return err;
 
487
    }
 
488
 
 
489
  cur_comp = comp;
 
490
  while (!err && cur_comp)
 
491
    {
 
492
      err = gpgconf_read (engine, "--list-options", cur_comp->name,
 
493
                          gpgconf_config_load_cb2, cur_comp);
 
494
      cur_comp = cur_comp->next;
 
495
    }
 
496
 
 
497
  if (err)
 
498
    {
 
499
      gpgconf_release (comp);
 
500
      return err;
 
501
    }
 
502
 
 
503
  *comp_p = comp;
 
504
  return 0;
 
505
}
 
506
 
 
507
 
 
508
 
 
509
gpgme_error_t
 
510
_gpgme_conf_arg_new (gpgme_conf_arg_t *arg_p,
 
511
                     gpgme_conf_type_t type, void *value)
 
512
{
 
513
  gpgme_conf_arg_t arg;
 
514
 
 
515
  arg = calloc (1, sizeof (*arg));
 
516
  if (!arg)
 
517
    return gpg_error_from_syserror ();
 
518
 
 
519
  if (!value)
 
520
    arg->no_arg = 1;
 
521
  else
 
522
    {
 
523
      switch (type)
 
524
        {
 
525
        case GPGME_CONF_NONE:
 
526
        case GPGME_CONF_UINT32:
 
527
          arg->value.uint32 = *((unsigned int *) value);
 
528
          break;
 
529
          
 
530
        case GPGME_CONF_INT32:
 
531
          arg->value.int32 = *((int *) value);
 
532
          break;
 
533
          
 
534
        case GPGME_CONF_STRING:
 
535
        case GPGME_CONF_PATHNAME:
 
536
        case GPGME_CONF_LDAP_SERVER:
 
537
          arg->value.string = strdup (value);
 
538
          if (!arg->value.string)
 
539
            {
 
540
              free (arg);
 
541
              return gpg_error_from_syserror ();
 
542
            }
 
543
          break;
 
544
          
 
545
        default:
 
546
          free (arg);
 
547
          return gpg_error (GPG_ERR_INV_VALUE);
 
548
        }
 
549
    }
 
550
 
 
551
  *arg_p = arg;
 
552
  return 0;
 
553
}
 
554
 
 
555
 
 
556
void
 
557
_gpgme_conf_arg_release (gpgme_conf_arg_t arg, gpgme_conf_type_t type)
 
558
{
 
559
  switch (type)
 
560
    {
 
561
    case GPGME_CONF_NONE:
 
562
    case GPGME_CONF_UINT32:
 
563
    case GPGME_CONF_INT32:
 
564
    case GPGME_CONF_STRING:
 
565
    default:
 
566
      break;
 
567
       
 
568
    case GPGME_CONF_PATHNAME:
 
569
    case GPGME_CONF_LDAP_SERVER:
 
570
      type = GPGME_CONF_STRING;
 
571
      break;
 
572
    }
 
573
 
 
574
  release_arg (arg, type);
 
575
}
 
576
 
 
577
 
 
578
gpgme_error_t
 
579
_gpgme_conf_opt_change (gpgme_conf_opt_t opt, int reset, gpgme_conf_arg_t arg)
 
580
{
 
581
  if (opt->new_value)
 
582
    release_arg (opt->new_value, opt->alt_type);
 
583
 
 
584
  if (reset)
 
585
    {
 
586
      opt->new_value = NULL;
 
587
      opt->change_value = 0;
 
588
    }
 
589
  else
 
590
    {
 
591
      opt->new_value = arg;
 
592
      opt->change_value = 1;
 
593
    }
 
594
  return 0;
 
595
}
 
596
 
 
597
 
 
598
/* FIXME: Major problem: We don't get errors from gpgconf.  */
 
599
 
 
600
static gpgme_error_t
 
601
gpgconf_write (void *engine, char *arg1, char *arg2, gpgme_data_t conf)
 
602
{
 
603
  struct engine_gpgconf *gpgconf = engine;
 
604
  gpgme_error_t err = 0;
 
605
#define BUFLEN 1024
 
606
  char buf[BUFLEN];
 
607
  int buflen = 0;
 
608
  char *argv[] = { NULL /* file_name */, arg1, arg2, 0 };
 
609
  int rp[2];
 
610
  struct spawn_fd_item_s pfd[] = { {1, -1}, {-1, -1} };
 
611
  struct spawn_fd_item_s cfd[] = { {-1, 0 /* STDIN_FILENO */}, {-1, -1} };
 
612
  int status;
 
613
  int nwrite;
 
614
 
 
615
  /* FIXME: Deal with engine->home_dir.  */
 
616
 
 
617
  /* _gpgme_engine_new guarantees that this is not NULL.  */
 
618
  argv[0] = gpgconf->file_name;
 
619
  argv[0] = "/home/marcus/g10/install/bin/gpgconf";
 
620
 
 
621
  if (_gpgme_io_pipe (rp, 0) < 0)
 
622
    return gpg_error_from_syserror ();
 
623
 
 
624
  pfd[0].fd = rp[0];
 
625
  cfd[0].fd = rp[0];
 
626
 
 
627
  status = _gpgme_io_spawn (gpgconf->file_name, argv, cfd, pfd);
 
628
  if (status < 0)
 
629
    {
 
630
      _gpgme_io_close (rp[0]);
 
631
      _gpgme_io_close (rp[1]);
 
632
      return gpg_error_from_syserror ();
 
633
    }
 
634
 
 
635
  for (;;)
 
636
    {
 
637
      if (buflen == 0)
 
638
        {
 
639
          do
 
640
            {
 
641
              buflen = gpgme_data_read (conf, buf, BUFLEN);
 
642
            }
 
643
          while (buflen < 0 && errno == EAGAIN);
 
644
 
 
645
          if (buflen < 0)
 
646
            {
 
647
              err = gpg_error_from_syserror ();
 
648
              _gpgme_io_close (rp[1]);
 
649
              return err;
 
650
            }
 
651
          else if (buflen == 0)
 
652
            {
 
653
              /* All is written.  */
 
654
              _gpgme_io_close (rp[1]);
 
655
              return 0;
 
656
            }
 
657
        }
 
658
 
 
659
      do
 
660
        {
 
661
          nwrite = _gpgme_io_write (rp[1], buf, buflen);
 
662
        }
 
663
      while (nwrite < 0 && errno == EAGAIN);
 
664
 
 
665
      if (nwrite > 0)
 
666
        {
 
667
          buflen -= nwrite;
 
668
          if (buflen > 0)
 
669
            memmove (&buf[0], &buf[nwrite], buflen);
 
670
        }
 
671
      else if (nwrite < 0)
 
672
        {
 
673
          _gpgme_io_close (rp[1]);
 
674
          return gpg_error_from_syserror ();
 
675
        }
 
676
    }
 
677
 
 
678
  return 0;
 
679
}
 
680
 
 
681
 
 
682
static gpgme_error_t
 
683
arg_to_data (gpgme_data_t conf, gpgme_conf_opt_t option, gpgme_conf_arg_t arg)
 
684
{
 
685
  gpgme_error_t err = 0;
 
686
  int amt = 0;
 
687
  char buf[16];
 
688
 
 
689
  while (amt >= 0 && arg)
 
690
    {
 
691
      switch (option->alt_type)
 
692
        {
 
693
        case GPGME_CONF_NONE:
 
694
        case GPGME_CONF_UINT32:
 
695
        default:
 
696
          snprintf (buf, sizeof (buf), "%u", arg->value.uint32);
 
697
          buf[sizeof (buf) - 1] = '\0';
 
698
          amt = gpgme_data_write (conf, buf, strlen (buf));
 
699
          break;
 
700
          
 
701
        case GPGME_CONF_INT32:
 
702
          snprintf (buf, sizeof (buf), "%i", arg->value.uint32);
 
703
          buf[sizeof (buf) - 1] = '\0';
 
704
          amt = gpgme_data_write (conf, buf, strlen (buf));
 
705
          break;
 
706
          
 
707
        case GPGME_CONF_STRING:
 
708
        case GPGME_CONF_PATHNAME:
 
709
        case GPGME_CONF_LDAP_SERVER:
 
710
          /* One quote character, and three times to allow
 
711
             for percent escaping.  */
 
712
          {
 
713
            char *ptr = arg->value.string;
 
714
            amt = gpgme_data_write (conf, "\"", 1);
 
715
            if (amt < 0)
 
716
              break;
 
717
 
 
718
            while (!err && *ptr)
 
719
              {
 
720
                switch (*ptr)
 
721
                  {
 
722
                  case '%':
 
723
                    amt = gpgme_data_write (conf, "%25", 3);
 
724
                    break;
 
725
 
 
726
                  case ':':
 
727
                    amt = gpgme_data_write (conf, "%3a", 3);
 
728
                    break;
 
729
 
 
730
                  case ',':
 
731
                    amt = gpgme_data_write (conf, "%2c", 3);
 
732
                    break;
 
733
 
 
734
                  default:
 
735
                    amt = gpgme_data_write (conf, ptr, 1);
 
736
                  }
 
737
                ptr++;
 
738
              }
 
739
          }
 
740
          break;
 
741
        }
 
742
 
 
743
      if (amt < 0)
 
744
        break;
 
745
 
 
746
      arg = arg->next;
 
747
      /* Comma separator.  */
 
748
      if (arg)
 
749
        amt = gpgme_data_write (conf, ",", 1);
 
750
    }
 
751
 
 
752
  if (amt < 0)
 
753
    return gpg_error_from_syserror ();
 
754
  
 
755
  return 0;
 
756
}
 
757
 
 
758
 
 
759
static gpgme_error_t
 
760
gpgconf_conf_save (void *engine, gpgme_conf_comp_t comp)
 
761
{
 
762
  gpgme_error_t err;
 
763
  int amt = 0;
 
764
  /* We use a data object to store the new configuration.  */
 
765
  gpgme_data_t conf;
 
766
  gpgme_conf_opt_t option;
 
767
  int something_changed = 0;
 
768
 
 
769
  err = gpgme_data_new (&conf);
 
770
  if (err)
 
771
    return err;
 
772
 
 
773
  option = comp->options;
 
774
  while (!err && amt >= 0 && option)
 
775
    {
 
776
      if (option->change_value)
 
777
        {
 
778
          unsigned int flags = 0;
 
779
          char buf[16];
 
780
 
 
781
          something_changed = 1;
 
782
 
 
783
          amt = gpgme_data_write (conf, option->name, strlen (option->name));
 
784
          if (amt >= 0)
 
785
            amt = gpgme_data_write (conf, ":", 1);
 
786
          if (amt < 0)
 
787
            break;
 
788
 
 
789
          if (!option->new_value)
 
790
            flags |= GPGME_CONF_DEFAULT;
 
791
          snprintf (buf, sizeof (buf), "%u", flags);
 
792
          buf[sizeof (buf) - 1] = '\0';
 
793
 
 
794
          amt = gpgme_data_write (conf, buf, strlen (buf));
 
795
          if (amt >= 0)
 
796
            amt = gpgme_data_write (conf, ":", 1);
 
797
          if (amt < 0)
 
798
            break;
 
799
 
 
800
          if (option->new_value)
 
801
            {
 
802
              err = arg_to_data (conf, option, option->new_value);
 
803
              if (err)
 
804
                break;
 
805
            }
 
806
          amt = gpgme_data_write (conf, "\n", 1);
 
807
        }
 
808
      option = option->next;
 
809
    }
 
810
  if (!err && amt < 0)
 
811
    err = gpg_error_from_syserror ();
 
812
  if (err || !something_changed)
 
813
    goto bail;
 
814
 
 
815
  err = gpgme_data_seek (conf, 0, SEEK_SET);
 
816
  if (err)
 
817
    goto bail;
 
818
 
 
819
  err = gpgconf_write (engine, "--change-options", comp->name, conf);
 
820
 bail:
 
821
  gpgme_data_release (conf);
 
822
  return err;
 
823
}
 
824
 
 
825
 
 
826
static void
 
827
gpgconf_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
 
828
{
 
829
  /* Nothing to do.  */
 
830
}
 
831
 
 
832
 
 
833
/* Currently, we do not use the engine interface for the various
 
834
   operations.  */
 
835
void
 
836
_gpgme_conf_release (gpgme_conf_comp_t conf)
 
837
{
 
838
  gpgconf_config_release (conf);
 
839
}
 
840
 
 
841
 
 
842
struct engine_ops _gpgme_engine_ops_gpgconf =
 
843
  {
 
844
    /* Static functions.  */
 
845
    _gpgme_get_gpgconf_path,
 
846
    gpgconf_get_version,
 
847
    gpgconf_get_req_version,
 
848
    gpgconf_new,
 
849
 
 
850
    /* Member functions.  */
 
851
    gpgconf_release,
 
852
    NULL,               /* reset */
 
853
    NULL,               /* set_status_handler */
 
854
    NULL,               /* set_command_handler */
 
855
    NULL,               /* set_colon_line_handler */
 
856
    NULL,               /* set_locale */
 
857
    NULL,               /* decrypt */
 
858
    NULL,               /* delete */
 
859
    NULL,               /* edit */
 
860
    NULL,               /* encrypt */
 
861
    NULL,               /* encrypt_sign */
 
862
    NULL,               /* export */
 
863
    NULL,               /* export_ext */
 
864
    NULL,               /* genkey */
 
865
    NULL,               /* import */
 
866
    NULL,               /* keylist */
 
867
    NULL,               /* keylist_ext */
 
868
    NULL,               /* sign */
 
869
    NULL,               /* trustlist */
 
870
    NULL,               /* verify */
 
871
    NULL,               /* getauditlog */
 
872
    gpgconf_conf_load,
 
873
    gpgconf_conf_save,
 
874
    gpgconf_set_io_cbs,
 
875
    NULL,               /* io_event */
 
876
    NULL                /* cancel */
 
877
  };