2009-10-26 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / src / engine-gpg.c
1 /* engine-gpg.c - Gpg Engine.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
4                  2009 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 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <locale.h>
32
33 #include "gpgme.h"
34 #include "util.h"
35 #include "ops.h"
36 #include "wait.h"
37 #include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
38 #include "priv-io.h"
39 #include "sema.h"
40 #include "debug.h"
41
42 #include "status-table.h"
43 #include "engine-backend.h"
44
45
46 /* This type is used to build a list of gpg arguments and data
47    sources/sinks.  */
48 struct arg_and_data_s
49 {
50   struct arg_and_data_s *next;
51   gpgme_data_t data;  /* If this is not NULL, use arg below.  */
52   int inbound;     /* True if this is used for reading from gpg.  */
53   int dup_to;
54   int print_fd;    /* Print the fd number and not the special form of it.  */
55   int *arg_locp;   /* Write back the argv idx of this argument when
56                       building command line to this location.  */
57   char arg[1];     /* Used if data above is not used.  */
58 };
59
60
61 struct fd_data_map_s
62 {
63   gpgme_data_t data;
64   int inbound;  /* true if this is used for reading from gpg */
65   int dup_to;
66   int fd;       /* the fd to use */
67   int peer_fd;  /* the other side of the pipe */
68   int arg_loc;  /* The index into the argv for translation purposes.  */
69   void *tag;
70 };
71
72
73 typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline);
74
75 struct engine_gpg
76 {
77   char *file_name;
78
79   char *lc_messages;
80   char *lc_ctype;
81
82   struct arg_and_data_s *arglist;
83   struct arg_and_data_s **argtail;
84
85   struct
86   {
87     int fd[2];  
88     int arg_loc;
89     size_t bufsize;
90     char *buffer;
91     size_t readpos;
92     int eof;
93     engine_status_handler_t fnc;
94     void *fnc_value;
95     void *tag;
96   } status;
97
98   /* This is a kludge - see the comment at colon_line_handler.  */
99   struct
100   {
101     int fd[2];  
102     int arg_loc;
103     size_t bufsize;
104     char *buffer;
105     size_t readpos;
106     int eof;
107     engine_colon_line_handler_t fnc;  /* this indicate use of this structrue */
108     void *fnc_value;
109     void *tag;
110     colon_preprocessor_t preprocess_fnc;
111   } colon;
112
113   char **argv;  
114   struct fd_data_map_s *fd_data_map;
115
116   /* stuff needed for interactive (command) mode */
117   struct
118   {
119     int used;
120     int fd;
121     void *cb_data;
122     int idx;            /* Index in fd_data_map */
123     gpgme_status_code_t code;  /* last code */
124     char *keyword;       /* what has been requested (malloced) */
125     engine_command_handler_t fnc; 
126     void *fnc_value;
127     /* The kludges never end.  This is used to couple command handlers
128        with output data in edit key mode.  */
129     gpgme_data_t linked_data;
130     int linked_idx;
131   } cmd;
132
133   struct gpgme_io_cbs io_cbs;
134 };
135
136 typedef struct engine_gpg *engine_gpg_t;
137
138 \f
139 static void
140 gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
141 {
142   engine_gpg_t gpg = engine;
143
144   TRACE3 (DEBUG_ENGINE, "gpgme:gpg_io_event", gpg,
145           "event %p, type %d, type_data %p",
146           gpg->io_cbs.event, type, type_data);
147   if (gpg->io_cbs.event)
148     (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
149 }
150
151
152 static void
153 close_notify_handler (int fd, void *opaque)
154 {
155   engine_gpg_t gpg = opaque;
156   assert (fd != -1);
157
158   if (gpg->status.fd[0] == fd)
159     {
160       if (gpg->status.tag)
161         (*gpg->io_cbs.remove) (gpg->status.tag);
162       gpg->status.fd[0] = -1;
163     }
164   else if (gpg->status.fd[1] == fd)
165     gpg->status.fd[1] = -1;
166   else if (gpg->colon.fd[0] == fd)
167     {
168       if (gpg->colon.tag)
169         (*gpg->io_cbs.remove) (gpg->colon.tag);
170       gpg->colon.fd[0] = -1;
171     }
172   else if (gpg->colon.fd[1] == fd)
173     gpg->colon.fd[1] = -1;
174   else if (gpg->cmd.fd == fd)
175     gpg->cmd.fd = -1;
176   else if (gpg->fd_data_map)
177     {
178       int i;
179
180       for (i = 0; gpg->fd_data_map[i].data; i++)
181         {
182           if (gpg->fd_data_map[i].fd == fd)
183             {
184               if (gpg->fd_data_map[i].tag)
185                 (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
186               gpg->fd_data_map[i].fd = -1;
187               break;
188             }
189           if (gpg->fd_data_map[i].peer_fd == fd)
190             {
191               gpg->fd_data_map[i].peer_fd = -1;
192               break;
193             }
194         }
195     }
196 }
197
198 /* If FRONT is true, push at the front of the list.  Use this for
199    options added late in the process.  */
200 static gpgme_error_t
201 _add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
202 {
203   struct arg_and_data_s *a;
204
205   assert (gpg);
206   assert (arg);
207
208   a = malloc (sizeof *a + strlen (arg));
209   if (!a)
210     return gpg_error_from_errno (errno);
211
212   a->data = NULL;
213   a->dup_to = -1;
214   a->arg_locp = arg_locp;
215
216   strcpy (a->arg, arg);
217   if (front)
218     {
219       a->next = gpg->arglist;
220       if (!gpg->arglist)
221         {
222           /* If this is the first argument, we need to update the tail
223              pointer.  */
224           gpg->argtail = &a->next;
225         }
226       gpg->arglist = a;
227     }
228   else
229     {
230       a->next = NULL;
231       *gpg->argtail = a;
232       gpg->argtail = &a->next;
233     }
234
235   return 0;
236 }
237
238 static gpgme_error_t
239 add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
240 {
241   return _add_arg (gpg, arg, front, NULL);
242 }
243
244
245 static gpgme_error_t
246 add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp)
247 {
248   return _add_arg (gpg, arg, 0, locp);
249 }
250
251
252 static gpgme_error_t
253 add_arg (engine_gpg_t gpg, const char *arg)
254 {
255   return add_arg_ext (gpg, arg, 0);
256 }
257
258
259 static gpgme_error_t
260 add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
261 {
262   struct arg_and_data_s *a;
263
264   assert (gpg);
265   assert (data);
266
267   a = malloc (sizeof *a - 1);
268   if (!a)
269     return gpg_error_from_errno (errno);
270   a->next = NULL;
271   a->data = data;
272   a->inbound = inbound;
273   a->arg_locp = NULL;
274
275   if (dup_to == -2)
276     {
277       a->print_fd = 1;
278       a->dup_to = -1;
279     }
280   else
281     {
282       a->print_fd = 0;
283       a->dup_to = dup_to;
284     }
285   *gpg->argtail = a;
286   gpg->argtail = &a->next;
287   return 0;
288 }
289
290 \f
291 static char *
292 gpg_get_version (const char *file_name)
293 {
294   return _gpgme_get_program_version (file_name ? file_name
295                                      : _gpgme_get_gpg_path ());
296 }
297
298
299 static const char *
300 gpg_get_req_version (void)
301 {
302   return NEED_GPG_VERSION;
303 }
304
305
306 static void
307 free_argv (char **argv)
308 {
309   int i;
310
311   for (i = 0; argv[i]; i++)
312     free (argv[i]);
313   free (argv);
314 }
315
316
317 static void
318 free_fd_data_map (struct fd_data_map_s *fd_data_map)
319 {
320   int i;
321
322   if (!fd_data_map)
323     return;
324
325   for (i = 0; fd_data_map[i].data; i++)
326     {
327       if (fd_data_map[i].fd != -1)
328         _gpgme_io_close (fd_data_map[i].fd);
329       if (fd_data_map[i].peer_fd != -1)
330         _gpgme_io_close (fd_data_map[i].peer_fd);
331       /* Don't release data because this is only a reference.  */
332     }
333   free (fd_data_map);
334 }
335
336
337 static gpgme_error_t
338 gpg_cancel (void *engine)
339 {
340   engine_gpg_t gpg = engine;
341
342   if (!gpg)
343     return gpg_error (GPG_ERR_INV_VALUE);
344
345   /* If gpg may be waiting for a cmd, close the cmd fd first.  On
346      Windows, close operations block on the reader/writer thread.  */
347   if (gpg->cmd.used)
348     {
349       if (gpg->cmd.fd != -1)
350         _gpgme_io_close (gpg->cmd.fd);
351       else if (gpg->fd_data_map
352                && gpg->fd_data_map[gpg->cmd.idx].fd != -1)
353         _gpgme_io_close (gpg->fd_data_map[gpg->cmd.idx].fd);
354     }
355
356   if (gpg->status.fd[0] != -1)
357     _gpgme_io_close (gpg->status.fd[0]);
358   if (gpg->status.fd[1] != -1)
359     _gpgme_io_close (gpg->status.fd[1]);
360   if (gpg->colon.fd[0] != -1)
361     _gpgme_io_close (gpg->colon.fd[0]);
362   if (gpg->colon.fd[1] != -1)
363     _gpgme_io_close (gpg->colon.fd[1]);
364   if (gpg->fd_data_map)
365     {
366       free_fd_data_map (gpg->fd_data_map);
367       gpg->fd_data_map = NULL;
368     }
369
370   return 0;
371 }
372
373 static void
374 gpg_release (void *engine)
375 {
376   engine_gpg_t gpg = engine;
377
378   if (!gpg)
379     return;
380
381   gpg_cancel (engine);
382
383   if (gpg->file_name)
384     free (gpg->file_name);
385
386   if (gpg->lc_messages)
387     free (gpg->lc_messages);
388   if (gpg->lc_ctype)
389     free (gpg->lc_ctype);
390
391   while (gpg->arglist)
392     {
393       struct arg_and_data_s *next = gpg->arglist->next;
394
395       if (gpg->arglist)
396         free (gpg->arglist);
397       gpg->arglist = next;
398     }
399
400   if (gpg->status.buffer)
401     free (gpg->status.buffer);
402   if (gpg->colon.buffer)
403     free (gpg->colon.buffer);
404   if (gpg->argv)
405     free_argv (gpg->argv);
406   if (gpg->cmd.keyword)
407     free (gpg->cmd.keyword);
408
409   free (gpg);
410 }
411
412
413 static gpgme_error_t
414 gpg_new (void **engine, const char *file_name, const char *home_dir)
415 {
416   engine_gpg_t gpg;
417   gpgme_error_t rc = 0;
418   char *dft_display = NULL;
419   char dft_ttyname[64];
420   char *dft_ttytype = NULL;
421
422   gpg = calloc (1, sizeof *gpg);
423   if (!gpg)
424     return gpg_error_from_errno (errno);
425
426   if (file_name)
427     {
428       gpg->file_name = strdup (file_name);
429       if (!gpg->file_name)
430         {
431           rc = gpg_error_from_errno (errno);
432           goto leave;
433         }
434     }
435
436   gpg->argtail = &gpg->arglist;
437   gpg->status.fd[0] = -1;
438   gpg->status.fd[1] = -1;
439   gpg->colon.fd[0] = -1;
440   gpg->colon.fd[1] = -1;
441   gpg->cmd.fd = -1;
442   gpg->cmd.idx = -1;
443   gpg->cmd.linked_data = NULL;
444   gpg->cmd.linked_idx = -1;
445
446   /* Allocate the read buffer for the status pipe.  */
447   gpg->status.bufsize = 1024;
448   gpg->status.readpos = 0;
449   gpg->status.buffer = malloc (gpg->status.bufsize);
450   if (!gpg->status.buffer)
451     {
452       rc = gpg_error_from_errno (errno);
453       goto leave;
454     }
455   /* In any case we need a status pipe - create it right here and
456      don't handle it with our generic gpgme_data_t mechanism.  */
457   if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
458     {
459       rc = gpg_error_from_errno (errno);
460       goto leave;
461     }
462   if (_gpgme_io_set_close_notify (gpg->status.fd[0],
463                                   close_notify_handler, gpg)
464       || _gpgme_io_set_close_notify (gpg->status.fd[1],
465                                      close_notify_handler, gpg))
466     {
467       rc = gpg_error (GPG_ERR_GENERAL);
468       goto leave;
469     }
470   gpg->status.eof = 0;
471
472   if (home_dir)
473     {
474       rc = add_arg (gpg, "--homedir");
475       if (!rc)
476         rc = add_arg (gpg, home_dir);
477       if (rc)
478         goto leave;
479     }
480
481   rc = add_arg (gpg, "--status-fd");
482   if (rc)
483     goto leave;
484
485   {
486     char buf[25];
487     _gpgme_io_fd2str (buf, sizeof (buf), gpg->status.fd[1]);
488     rc = add_arg_with_locp (gpg, buf, &gpg->status.arg_loc);
489     if (rc)
490       goto leave;
491   }
492
493   rc = add_arg (gpg, "--no-tty");
494   if (!rc)
495     rc = add_arg (gpg, "--charset");
496   if (!rc)
497     rc = add_arg (gpg, "utf8");
498   if (!rc)
499     rc = add_arg (gpg, "--enable-progress-filter");
500   if (rc)
501     goto leave;
502
503   rc = _gpgme_getenv ("DISPLAY", &dft_display);
504   if (rc)
505     goto leave;
506   if (dft_display)
507     {
508       rc = add_arg (gpg, "--display");
509       if (!rc)
510         rc = add_arg (gpg, dft_display);
511
512       free (dft_display);
513     }
514
515   if (isatty (1))
516     {
517       int err;
518
519       err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
520       if (err)
521         rc = gpg_error_from_errno (err);
522       else
523         {
524           if (*dft_ttyname)
525             {
526               rc = add_arg (gpg, "--ttyname");
527               if (!rc)
528                 rc = add_arg (gpg, dft_ttyname);
529             }
530           else
531             rc = 0;
532           if (!rc)
533             {
534               rc = _gpgme_getenv ("TERM", &dft_ttytype);
535               if (rc)
536                 goto leave;
537               
538               if (dft_ttytype)
539                 {
540                   rc = add_arg (gpg, "--ttytype");
541                   if (!rc)
542                     rc = add_arg (gpg, dft_ttytype);
543                 }
544
545               free (dft_ttytype);
546             }
547         }
548       if (rc)
549         goto leave;
550     }
551
552  leave:
553   if (rc)
554     gpg_release (gpg);
555   else
556     *engine = gpg;
557   return rc;
558 }
559
560
561 static gpgme_error_t
562 gpg_set_locale (void *engine, int category, const char *value)
563 {
564   engine_gpg_t gpg = engine;
565
566   if (category == LC_CTYPE)
567     {
568       if (gpg->lc_ctype)
569         {
570           free (gpg->lc_ctype);
571           gpg->lc_ctype = NULL;
572         }
573       if (value)
574         {
575           gpg->lc_ctype = strdup (value);
576           if (!gpg->lc_ctype)
577             return gpg_error_from_syserror ();
578         }
579     }
580 #ifdef LC_MESSAGES
581   else if (category == LC_MESSAGES)
582     {
583       if (gpg->lc_messages)
584         {
585           free (gpg->lc_messages);
586           gpg->lc_messages = NULL;
587         }
588       if (value)
589         {
590           gpg->lc_messages = strdup (value);
591           if (!gpg->lc_messages)
592             return gpg_error_from_syserror ();
593         }
594     }
595 #endif /* LC_MESSAGES */
596   else
597     return gpg_error (GPG_ERR_INV_VALUE);
598
599   return 0;
600 }
601
602
603 /* Note, that the status_handler is allowed to modifiy the args
604    value.  */
605 static void
606 gpg_set_status_handler (void *engine, engine_status_handler_t fnc,
607                         void *fnc_value)
608 {
609   engine_gpg_t gpg = engine;
610
611   gpg->status.fnc = fnc;
612   gpg->status.fnc_value = fnc_value;
613 }
614
615 /* Kludge to process --with-colon output.  */
616 static gpgme_error_t
617 gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
618                             void *fnc_value)
619 {
620   engine_gpg_t gpg = engine;
621
622   gpg->colon.bufsize = 1024;
623   gpg->colon.readpos = 0;
624   gpg->colon.buffer = malloc (gpg->colon.bufsize);
625   if (!gpg->colon.buffer)
626     return gpg_error_from_errno (errno);
627
628   if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) 
629     {
630       int saved_errno = errno;
631       free (gpg->colon.buffer);
632       gpg->colon.buffer = NULL;
633       return gpg_error_from_errno (saved_errno);
634     }
635   if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
636       || _gpgme_io_set_close_notify (gpg->colon.fd[1],
637                                      close_notify_handler, gpg))
638     return gpg_error (GPG_ERR_GENERAL);
639   gpg->colon.eof = 0;
640   gpg->colon.fnc = fnc;
641   gpg->colon.fnc_value = fnc_value;
642   return 0;
643 }
644
645
646 static gpgme_error_t
647 command_handler (void *opaque, int fd)
648 {
649   struct io_cb_data *data = (struct io_cb_data *) opaque;
650   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
651   gpgme_error_t err;
652   int processed = 0;
653   assert (gpg->cmd.used);
654   assert (gpg->cmd.code);
655   assert (gpg->cmd.fnc);
656
657   err = gpg->cmd.fnc (gpg->cmd.fnc_value, gpg->cmd.code, gpg->cmd.keyword, fd,
658                       &processed);
659
660   gpg->cmd.code = 0;
661   /* And sleep again until read_status will wake us up again.  */
662   /* XXX We must check if there are any more fds active after removing
663      this one.  */
664   (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
665   gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
666   gpg->fd_data_map[gpg->cmd.idx].fd = -1;
667
668   if (err)
669     return err;
670
671   /* We always need to send at least a newline character.  */
672   if (!processed)
673     _gpgme_io_write (fd, "\n", 1);
674
675   return 0;
676 }
677
678
679
680 /* The Fnc will be called to get a value for one of the commands with
681    a key KEY.  If the Code passed to FNC is 0, the function may release
682    resources associated with the returned value from another call.  To
683    match such a second call to a first call, the returned value from
684    the first call is passed as keyword.  */
685 static gpgme_error_t
686 gpg_set_command_handler (void *engine, engine_command_handler_t fnc,
687                          void *fnc_value, gpgme_data_t linked_data)
688 {
689   engine_gpg_t gpg = engine;
690   gpgme_error_t rc;
691
692   rc = add_arg (gpg, "--command-fd");
693   if (rc)
694     return rc;
695
696   /* This is a hack.  We don't have a real data object.  The only
697      thing that matters is that we use something unique, so we use the
698      address of the cmd structure in the gpg object.  */
699   rc = add_data (gpg, (void *) &gpg->cmd, -2, 0);
700   if (rc)
701     return rc;
702
703   gpg->cmd.fnc = fnc;
704   gpg->cmd.cb_data = (void *) &gpg->cmd;
705   gpg->cmd.fnc_value = fnc_value;
706   gpg->cmd.linked_data = linked_data;
707   gpg->cmd.used = 1;
708   return 0;
709 }
710
711
712 static gpgme_error_t
713 build_argv (engine_gpg_t gpg)
714 {
715   gpgme_error_t err;
716   struct arg_and_data_s *a;
717   struct fd_data_map_s *fd_data_map;
718   size_t datac=0, argc=0;  
719   char **argv;
720   int need_special = 0;
721   int use_agent = 0;
722   char *p;
723
724   /* We don't want to use the agent with a malformed environment
725      variable.  This is only a very basic test but sufficient to make
726      our life in the regression tests easier. */
727   err = _gpgme_getenv ("GPG_AGENT_INFO", &p);
728   if (err)
729     return err;
730   use_agent = (p && strchr (p, ':'));
731   if (p)
732     free (p);
733
734   if (gpg->argv)
735     {
736       free_argv (gpg->argv);
737       gpg->argv = NULL;
738     }
739   if (gpg->fd_data_map)
740     {
741       free_fd_data_map (gpg->fd_data_map);
742       gpg->fd_data_map = NULL;
743     }
744
745   argc++;       /* For argv[0].  */
746   for (a = gpg->arglist; a; a = a->next)
747     {
748       argc++;
749       if (a->data)
750         {
751           /*fprintf (stderr, "build_argv: data\n" );*/
752           datac++;
753           if (a->dup_to == -1 && !a->print_fd)
754             need_special = 1;
755         }
756       else
757         {
758           /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
759         }
760     }
761   if (need_special)
762     argc++;
763   if (use_agent)
764     argc++;
765   if (!gpg->cmd.used)
766     argc++;     /* --batch */
767   argc += 1;    /* --no-sk-comment */
768
769   argv = calloc (argc + 1, sizeof *argv);
770   if (!argv)
771     return gpg_error_from_errno (errno);
772   fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
773   if (!fd_data_map)
774     {
775       int saved_errno = errno;
776       free_argv (argv);
777       return gpg_error_from_errno (saved_errno);
778     }
779
780   argc = datac = 0;
781   argv[argc] = strdup ("gpg"); /* argv[0] */
782   if (!argv[argc])
783     {
784       int saved_errno = errno;
785       free (fd_data_map);
786       free_argv (argv);
787       return gpg_error_from_errno (saved_errno);
788     }
789   argc++;
790   if (need_special)
791     {
792       argv[argc] = strdup ("--enable-special-filenames");
793       if (!argv[argc])
794         {
795           int saved_errno = errno;
796           free (fd_data_map);
797           free_argv (argv);
798           return gpg_error_from_errno (saved_errno);
799         }
800       argc++;
801     }
802   if (use_agent)
803     {
804       argv[argc] = strdup ("--use-agent");
805       if (!argv[argc])
806         {
807           int saved_errno = errno;
808           free (fd_data_map);
809           free_argv (argv);
810           return gpg_error_from_errno (saved_errno);
811         }
812       argc++;
813     }
814   if (!gpg->cmd.used)
815     {
816       argv[argc] = strdup ("--batch");
817       if (!argv[argc])
818         {
819           int saved_errno = errno;
820           free (fd_data_map);
821           free_argv (argv);
822           return gpg_error_from_errno (saved_errno);
823         }
824       argc++;
825     }
826   argv[argc] = strdup ("--no-sk-comment");
827   if (!argv[argc])
828     {
829       int saved_errno = errno;
830       free (fd_data_map);
831       free_argv (argv);
832       return gpg_error_from_errno (saved_errno);
833     }
834   argc++;
835   for (a = gpg->arglist; a; a = a->next)
836     {
837       if (a->arg_locp)
838         *(a->arg_locp) = argc;
839
840       if (a->data)
841         {
842           /* Create a pipe to pass it down to gpg.  */
843           fd_data_map[datac].inbound = a->inbound;
844
845           /* Create a pipe.  */
846           {   
847             int fds[2];
848             
849             if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
850                 == -1)
851               {
852                 int saved_errno = errno;
853                 free (fd_data_map);
854                 free_argv (argv);
855                 return gpg_error (saved_errno);
856               }
857             if (_gpgme_io_set_close_notify (fds[0],
858                                             close_notify_handler, gpg)
859                 || _gpgme_io_set_close_notify (fds[1],
860                                                close_notify_handler,
861                                                gpg))
862               {
863                 return gpg_error (GPG_ERR_GENERAL);
864               }
865             /* If the data_type is FD, we have to do a dup2 here.  */
866             if (fd_data_map[datac].inbound)
867               {
868                 fd_data_map[datac].fd       = fds[0];
869                 fd_data_map[datac].peer_fd  = fds[1];
870               }
871             else
872               {
873                 fd_data_map[datac].fd       = fds[1];
874                 fd_data_map[datac].peer_fd  = fds[0];
875               }
876           }
877
878           /* Hack to get hands on the fd later.  */
879           if (gpg->cmd.used)
880             {
881               if (gpg->cmd.cb_data == a->data)
882                 {
883                   assert (gpg->cmd.idx == -1);
884                   gpg->cmd.idx = datac;
885                 }
886               else if (gpg->cmd.linked_data == a->data)
887                 {
888                   assert (gpg->cmd.linked_idx == -1);
889                   gpg->cmd.linked_idx = datac;
890                 }
891             }
892
893           fd_data_map[datac].data = a->data;
894           fd_data_map[datac].dup_to = a->dup_to;
895
896           if (a->dup_to == -1)
897             {
898               char *ptr;
899               int buflen = 25;
900
901               argv[argc] = malloc (buflen);
902               if (!argv[argc])
903                 {
904                   int saved_errno = errno;
905                   free (fd_data_map);
906                   free_argv (argv);
907                   return gpg_error_from_errno (saved_errno);
908                 }
909
910               ptr = argv[argc];
911               if (!a->print_fd)
912                 {
913                   *(ptr++) = '-';
914                   *(ptr++) = '&';
915                   buflen -= 2;
916                 }
917
918               _gpgme_io_fd2str (ptr, buflen, fd_data_map[datac].peer_fd);
919               fd_data_map[datac].arg_loc = argc;
920               argc++;
921             }
922           datac++;
923         }
924       else
925         {
926           argv[argc] = strdup (a->arg);
927           if (!argv[argc])
928             {
929               int saved_errno = errno;
930               free (fd_data_map);
931               free_argv (argv);
932               return gpg_error_from_errno (saved_errno);
933             }
934             argc++;
935         }
936     }
937
938   gpg->argv = argv;
939   gpg->fd_data_map = fd_data_map;
940   return 0;
941 }
942
943
944 static gpgme_error_t
945 add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
946            void **tag)
947 {
948   gpgme_error_t err;
949
950   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
951   if (err)
952     return err;
953   if (!dir)
954     /* FIXME Kludge around poll() problem.  */
955     err = _gpgme_io_set_nonblocking (fd);
956   return err;
957 }
958
959
960 static int
961 status_cmp (const void *ap, const void *bp)
962 {
963   const struct status_table_s *a = ap;
964   const struct status_table_s *b = bp;
965
966   return strcmp (a->name, b->name);
967 }
968
969
970 /* Handle the status output of GnuPG.  This function does read entire
971    lines and passes them as C strings to the callback function (we can
972    use C Strings because the status output is always UTF-8 encoded).
973    Of course we have to buffer the lines to cope with long lines
974    e.g. with a large user ID.  Note: We can optimize this to only cope
975    with status line code we know about and skip all other stuff
976    without buffering (i.e. without extending the buffer).  */
977 static gpgme_error_t
978 read_status (engine_gpg_t gpg)
979 {
980   char *p;
981   int nread;
982   size_t bufsize = gpg->status.bufsize; 
983   char *buffer = gpg->status.buffer;
984   size_t readpos = gpg->status.readpos; 
985
986   assert (buffer);
987   if (bufsize - readpos < 256)
988     { 
989       /* Need more room for the read.  */
990       bufsize += 1024;
991       buffer = realloc (buffer, bufsize);
992       if (!buffer)
993         return gpg_error_from_errno (errno);
994     }
995
996   nread = _gpgme_io_read (gpg->status.fd[0],
997                           buffer + readpos, bufsize-readpos);
998   if (nread == -1)
999     return gpg_error_from_errno (errno);
1000
1001   if (!nread)
1002     {
1003       gpg->status.eof = 1;
1004       if (gpg->status.fnc)
1005         {
1006           gpgme_error_t err;
1007           err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
1008           if (err)
1009             return err;
1010         }
1011       return 0;
1012     }
1013
1014   while (nread > 0)
1015     {
1016       for (p = buffer + readpos; nread; nread--, p++)
1017         {
1018           if (*p == '\n')
1019             {
1020               /* (we require that the last line is terminated by a LF) */
1021               if (p > buffer && p[-1] == '\r')
1022                 p[-1] = 0;
1023               *p = 0;
1024               if (!strncmp (buffer, "[GNUPG:] ", 9)
1025                   && buffer[9] >= 'A' && buffer[9] <= 'Z')
1026                 {
1027                   struct status_table_s t, *r;
1028                   char *rest;
1029
1030                   rest = strchr (buffer + 9, ' ');
1031                   if (!rest)
1032                     rest = p; /* Set to an empty string.  */
1033                   else
1034                     *rest++ = 0;
1035                     
1036                   t.name = buffer+9;
1037                   /* (the status table has one extra element) */
1038                   r = bsearch (&t, status_table, DIM(status_table) - 1,
1039                                sizeof t, status_cmp);
1040                   if (r)
1041                     {
1042                       if (gpg->cmd.used
1043                           && (r->code == GPGME_STATUS_GET_BOOL
1044                               || r->code == GPGME_STATUS_GET_LINE
1045                               || r->code == GPGME_STATUS_GET_HIDDEN))
1046                         {
1047                           gpg->cmd.code = r->code;
1048                           if (gpg->cmd.keyword)
1049                             free (gpg->cmd.keyword);
1050                           gpg->cmd.keyword = strdup (rest);
1051                           if (!gpg->cmd.keyword)
1052                             return gpg_error_from_errno (errno);
1053                           /* This should be the last thing we have
1054                              received and the next thing will be that
1055                              the command handler does its action.  */
1056                           if (nread > 1)
1057                             TRACE0 (DEBUG_CTX, "gpgme:read_status", 0,
1058                                     "error: unexpected data");
1059
1060                           add_io_cb (gpg, gpg->cmd.fd, 0,
1061                                      command_handler, gpg,
1062                                      &gpg->fd_data_map[gpg->cmd.idx].tag);
1063                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
1064                           gpg->cmd.fd = -1;
1065                         }
1066                       else if (gpg->status.fnc)
1067                         {
1068                           gpgme_error_t err;
1069                           err = gpg->status.fnc (gpg->status.fnc_value, 
1070                                                  r->code, rest);
1071                           if (err)
1072                             return err;
1073                         }
1074                     
1075                       if (r->code == GPGME_STATUS_END_STREAM)
1076                         {
1077                           if (gpg->cmd.used)
1078                             {
1079                               /* Before we can actually add the
1080                                  command fd, we might have to flush
1081                                  the linked output data pipe.  */
1082                               if (gpg->cmd.linked_idx != -1
1083                                   && gpg->fd_data_map[gpg->cmd.linked_idx].fd
1084                                   != -1)
1085                                 {
1086                                   struct io_select_fd_s fds;
1087                                   fds.fd =
1088                                     gpg->fd_data_map[gpg->cmd.linked_idx].fd;
1089                                   fds.for_read = 1;
1090                                   fds.for_write = 0;
1091                                   fds.opaque = NULL;
1092                                   do
1093                                     {
1094                                       fds.signaled = 0;
1095                                       _gpgme_io_select (&fds, 1, 1);
1096                                       if (fds.signaled)
1097                                         _gpgme_data_inbound_handler
1098                                           (gpg->cmd.linked_data, fds.fd);
1099                                     }
1100                                   while (fds.signaled);
1101                                 }
1102
1103                               /* XXX We must check if there are any
1104                                  more fds active after removing this
1105                                  one.  */
1106                               (*gpg->io_cbs.remove)
1107                                 (gpg->fd_data_map[gpg->cmd.idx].tag);
1108                               gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
1109                               gpg->fd_data_map[gpg->cmd.idx].fd = -1;
1110                             }
1111                         }
1112                     }
1113                 }
1114               /* To reuse the buffer for the next line we have to
1115                  shift the remaining data to the buffer start and
1116                  restart the loop Hmmm: We can optimize this function
1117                  by looking forward in the buffer to see whether a
1118                  second complete line is available and in this case
1119                  avoid the memmove for this line.  */
1120               nread--; p++;
1121               if (nread)
1122                 memmove (buffer, p, nread);
1123               readpos = 0;
1124               break; /* the for loop */
1125             }
1126           else
1127             readpos++;
1128         }
1129     } 
1130
1131   /* Update the gpg object.  */
1132   gpg->status.bufsize = bufsize;
1133   gpg->status.buffer = buffer;
1134   gpg->status.readpos = readpos;
1135   return 0;
1136 }
1137
1138
1139 static gpgme_error_t
1140 status_handler (void *opaque, int fd)
1141 {
1142   struct io_cb_data *data = (struct io_cb_data *) opaque;
1143   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
1144   int err;
1145
1146   assert (fd == gpg->status.fd[0]);
1147   err = read_status (gpg);
1148   if (err)
1149     return err;
1150   if (gpg->status.eof)
1151     _gpgme_io_close (fd);
1152   return 0;
1153 }
1154
1155
1156 static gpgme_error_t
1157 read_colon_line (engine_gpg_t gpg)
1158 {
1159   char *p;
1160   int nread;
1161   size_t bufsize = gpg->colon.bufsize; 
1162   char *buffer = gpg->colon.buffer;
1163   size_t readpos = gpg->colon.readpos; 
1164
1165   assert (buffer);
1166   if (bufsize - readpos < 256)
1167     { 
1168       /* Need more room for the read.  */
1169       bufsize += 1024;
1170       buffer = realloc (buffer, bufsize);
1171       if (!buffer) 
1172         return gpg_error_from_errno (errno);
1173     }
1174
1175   nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
1176   if (nread == -1)
1177     return gpg_error_from_errno (errno);
1178
1179   if (!nread)
1180     {
1181       gpg->colon.eof = 1;
1182       assert (gpg->colon.fnc);
1183       gpg->colon.fnc (gpg->colon.fnc_value, NULL);
1184       return 0;
1185     }
1186
1187   while (nread > 0)
1188     {
1189       for (p = buffer + readpos; nread; nread--, p++)
1190         {
1191           if ( *p == '\n' )
1192             {
1193               /* (we require that the last line is terminated by a LF)
1194                  and we skip empty lines.  Note: we use UTF8 encoding
1195                  and escaping of special characters.  We require at
1196                  least one colon to cope with some other printed
1197                  information.  */
1198               *p = 0;
1199               if (*buffer && strchr (buffer, ':'))
1200                 {
1201                   char *line = NULL;
1202
1203                   if (gpg->colon.preprocess_fnc)
1204                     {
1205                       gpgme_error_t err;
1206
1207                       err = gpg->colon.preprocess_fnc (buffer, &line);
1208                       if (err)
1209                         return err;
1210                     }
1211
1212                   assert (gpg->colon.fnc);
1213                   gpg->colon.fnc (gpg->colon.fnc_value, line ? line : buffer);
1214                   if (line)
1215                     free (line);
1216                 }
1217             
1218               /* To reuse the buffer for the next line we have to
1219                  shift the remaining data to the buffer start and
1220                  restart the loop Hmmm: We can optimize this function
1221                  by looking forward in the buffer to see whether a
1222                  second complete line is available and in this case
1223                  avoid the memmove for this line.  */
1224               nread--; p++;
1225               if (nread)
1226                 memmove (buffer, p, nread);
1227               readpos = 0;
1228               break; /* The for loop.  */
1229             }
1230           else
1231             readpos++;
1232         }
1233     } 
1234
1235   /* Update the gpg object.  */
1236   gpg->colon.bufsize = bufsize;
1237   gpg->colon.buffer  = buffer;
1238   gpg->colon.readpos = readpos;
1239   return 0;
1240 }
1241
1242
1243 /* This colonline handler thing is not the clean way to do it.  It
1244    might be better to enhance the gpgme_data_t object to act as a wrapper
1245    for a callback.  Same goes for the status thing.  For now we use
1246    this thing here because it is easier to implement.  */
1247 static gpgme_error_t
1248 colon_line_handler (void *opaque, int fd)
1249 {
1250   struct io_cb_data *data = (struct io_cb_data *) opaque;
1251   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
1252   gpgme_error_t rc = 0;
1253
1254   assert (fd == gpg->colon.fd[0]);
1255   rc = read_colon_line (gpg);
1256   if (rc)
1257     return rc;
1258   if (gpg->colon.eof)
1259     _gpgme_io_close (fd);
1260   return 0;
1261 }
1262
1263
1264 static gpgme_error_t
1265 start (engine_gpg_t gpg)
1266 {
1267   gpgme_error_t rc;
1268   int saved_errno;
1269   int i, n;
1270   int status;
1271   struct spawn_fd_item_s *fd_list;
1272   pid_t pid;
1273
1274   if (!gpg)
1275     return gpg_error (GPG_ERR_INV_VALUE);
1276
1277   if (!gpg->file_name && !_gpgme_get_gpg_path ())
1278     return gpg_error (GPG_ERR_INV_ENGINE);
1279
1280   if (gpg->lc_ctype)
1281     {
1282       rc = add_arg_ext (gpg, gpg->lc_ctype, 1);
1283       if (!rc)
1284         rc = add_arg_ext (gpg, "--lc-ctype", 1);
1285       if (rc)
1286         return rc;
1287     }
1288
1289   if (gpg->lc_messages)
1290     {
1291       rc = add_arg_ext (gpg, gpg->lc_messages, 1);
1292       if (!rc)
1293         rc = add_arg_ext (gpg, "--lc-messages", 1);
1294       if (rc)
1295         return rc;
1296     }
1297
1298   rc = build_argv (gpg);
1299   if (rc)
1300     return rc;
1301
1302   /* status_fd, colon_fd and end of list.  */
1303   n = 3;
1304   for (i = 0; gpg->fd_data_map[i].data; i++) 
1305     n++;
1306   fd_list = calloc (n, sizeof *fd_list);
1307   if (! fd_list)
1308     return gpg_error_from_errno (errno);
1309
1310   /* Build the fd list for the child.  */
1311   n = 0;
1312   fd_list[n].fd = gpg->status.fd[1];
1313   fd_list[n].dup_to = -1;
1314   fd_list[n].arg_loc = gpg->status.arg_loc;
1315   n++;
1316   if (gpg->colon.fnc)
1317     {
1318       fd_list[n].fd = gpg->colon.fd[1]; 
1319       fd_list[n].dup_to = 1;
1320       n++;
1321     }
1322   for (i = 0; gpg->fd_data_map[i].data; i++)
1323     {
1324       fd_list[n].fd = gpg->fd_data_map[i].peer_fd;
1325       fd_list[n].dup_to = gpg->fd_data_map[i].dup_to;
1326       fd_list[n].arg_loc = gpg->fd_data_map[i].arg_loc;
1327       n++;
1328     }
1329   fd_list[n].fd = -1;
1330   fd_list[n].dup_to = -1;
1331
1332   status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name :
1333                             _gpgme_get_gpg_path (), gpg->argv,
1334                             IOSPAWN_FLAG_ALLOW_SET_FG,
1335                             fd_list, &pid);
1336   saved_errno = errno;
1337
1338   free (fd_list);
1339   if (status == -1)
1340     return gpg_error_from_errno (saved_errno);
1341
1342   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
1343
1344   rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
1345                   &gpg->status.tag);
1346   if (rc)
1347     /* FIXME: kill the child */
1348     return rc;
1349
1350   if (gpg->colon.fnc)
1351     {
1352       assert (gpg->colon.fd[0] != -1);
1353       rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
1354                       &gpg->colon.tag);
1355       if (rc)
1356         /* FIXME: kill the child */
1357         return rc;
1358     }
1359
1360   for (i = 0; gpg->fd_data_map[i].data; i++)
1361     {
1362       if (gpg->cmd.used && i == gpg->cmd.idx)
1363         {
1364           /* Park the cmd fd.  */
1365           gpg->cmd.fd = gpg->fd_data_map[i].fd;
1366           gpg->fd_data_map[i].fd = -1;
1367         }
1368       else
1369         {
1370           rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
1371                           gpg->fd_data_map[i].inbound,
1372                           gpg->fd_data_map[i].inbound
1373                           ? _gpgme_data_inbound_handler
1374                           : _gpgme_data_outbound_handler,
1375                           gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
1376           
1377           if (rc)
1378             /* FIXME: kill the child */
1379             return rc;
1380         }
1381     }
1382
1383   gpg_io_event (gpg, GPGME_EVENT_START, NULL);
1384   
1385   /* fixme: check what data we can release here */
1386   return 0;
1387 }
1388
1389
1390 static gpgme_error_t
1391 gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1392 {
1393   engine_gpg_t gpg = engine;
1394   gpgme_error_t err;
1395
1396   err = add_arg (gpg, "--decrypt");
1397
1398   /* Tell the gpg object about the data.  */
1399   if (!err)
1400     err = add_arg (gpg, "--output");
1401   if (!err)
1402     err = add_arg (gpg, "-");
1403   if (!err)
1404     err = add_data (gpg, plain, 1, 1);
1405   if (!err)
1406     err = add_arg (gpg, "--");
1407   if (!err)
1408     err = add_data (gpg, ciph, -1, 0);
1409
1410   if (!err)
1411     start (gpg);
1412   return err;
1413 }
1414
1415 static gpgme_error_t
1416 gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
1417 {
1418   engine_gpg_t gpg = engine;
1419   gpgme_error_t err;
1420
1421   err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
1422                  : "--delete-key");
1423   if (!err)
1424     err = add_arg (gpg, "--");
1425   if (!err)
1426     {
1427       if (!key->subkeys || !key->subkeys->fpr)
1428         return gpg_error (GPG_ERR_INV_VALUE);
1429       else
1430         err = add_arg (gpg, key->subkeys->fpr);
1431     }
1432
1433   if (!err)
1434     start (gpg);
1435   return err;
1436 }
1437
1438
1439 static gpgme_error_t
1440 append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1441 {
1442   gpgme_error_t err = 0;
1443   int i;
1444   gpgme_key_t key;
1445
1446   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1447     {
1448       const char *s = key->subkeys ? key->subkeys->keyid : NULL;
1449       if (s)
1450         {
1451           if (!err)
1452             err = add_arg (gpg, "-u");
1453           if (!err)
1454             err = add_arg (gpg, s);
1455         }
1456       gpgme_key_unref (key);
1457       if (err) break;
1458     }
1459   return err;
1460 }
1461
1462
1463 static gpgme_error_t
1464 append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1465 {
1466   gpgme_error_t err = 0;
1467   gpgme_sig_notation_t notation;
1468
1469   notation = gpgme_sig_notation_get (ctx);
1470
1471   while (!err && notation)
1472     {
1473       if (notation->name
1474           && !(notation->flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
1475         err = gpg_error (GPG_ERR_INV_VALUE);
1476       else if (notation->name)
1477         {
1478           char *arg;
1479
1480           /* Maximum space needed is one byte for the "critical" flag,
1481              the name, one byte for '=', the value, and a terminating
1482              '\0'.  */
1483
1484           arg = malloc (1 + notation->name_len + 1 + notation->value_len + 1);
1485           if (!arg)
1486             err = gpg_error_from_errno (errno);
1487
1488           if (!err)
1489             {
1490               char *argp = arg;
1491
1492               if (notation->critical)
1493                 *(argp++) = '!';
1494
1495               memcpy (argp, notation->name, notation->name_len);
1496               argp += notation->name_len;
1497
1498               *(argp++) = '=';
1499
1500               /* We know that notation->name is '\0' terminated.  */
1501               strcpy (argp, notation->value);
1502             }
1503
1504           if (!err)
1505             err = add_arg (gpg, "--sig-notation");
1506           if (!err)
1507             err = add_arg (gpg, arg);
1508
1509           if (arg)
1510             free (arg);
1511         }
1512       else
1513         {
1514           /* This is a policy URL.  */
1515
1516           char *value;
1517
1518           if (notation->critical)
1519             {
1520               value = malloc (1 + notation->value_len + 1);
1521               if (!value)
1522                 err = gpg_error_from_errno (errno);
1523               else
1524                 {
1525                   value[0] = '!';
1526                   /* We know that notation->value is '\0' terminated.  */
1527                   strcpy (&value[1], notation->value);
1528                 }
1529             }
1530           else
1531             value = notation->value;
1532
1533           if (!err)
1534             err = add_arg (gpg, "--sig-policy-url");
1535           if (!err)
1536             err = add_arg (gpg, value);
1537
1538           if (value != notation->value)
1539             free (value);
1540         }
1541
1542       notation = notation->next;
1543     }
1544   return err;
1545 }
1546
1547
1548 static gpgme_error_t
1549 gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
1550           gpgme_ctx_t ctx /* FIXME */)
1551 {
1552   engine_gpg_t gpg = engine;
1553   gpgme_error_t err;
1554
1555   err = add_arg (gpg, "--with-colons");
1556   if (!err)
1557     err = append_args_from_signers (gpg, ctx);
1558   if (!err)
1559   err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
1560   if (!err)
1561     err = add_data (gpg, out, 1, 1);
1562   if (!err)
1563     err = add_arg (gpg, "--");
1564   if (!err && type == 0)
1565     {
1566       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1567       if (!s)
1568         err = gpg_error (GPG_ERR_INV_VALUE);
1569       else
1570         err = add_arg (gpg, s);
1571     }
1572   if (!err)
1573     err = start (gpg);
1574
1575   return err;
1576 }
1577
1578
1579 static gpgme_error_t
1580 append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
1581 {
1582   gpgme_error_t err = 0;
1583   int i = 0;
1584
1585   while (recp[i])
1586     {
1587       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1588         err = gpg_error (GPG_ERR_INV_VALUE);
1589       if (!err)
1590         err = add_arg (gpg, "-r");
1591       if (!err)
1592         err = add_arg (gpg, recp[i]->subkeys->fpr);
1593       if (err)
1594         break;
1595       i++;
1596     }    
1597   return err;
1598 }
1599
1600
1601 static gpgme_error_t
1602 gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1603              gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1604 {
1605   engine_gpg_t gpg = engine;
1606   gpgme_error_t err;
1607   int symmetric = !recp;
1608
1609   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1610
1611   if (!err && use_armor)
1612     err = add_arg (gpg, "--armor");
1613
1614   if (!symmetric)
1615     {
1616       /* If we know that all recipients are valid (full or ultimate trust)
1617          we can suppress further checks.  */
1618       if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1619         err = add_arg (gpg, "--always-trust");
1620
1621       if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
1622         err = add_arg (gpg, "--no-encrypt-to");
1623
1624       if (!err)
1625         err = append_args_from_recipients (gpg, recp);
1626     }
1627
1628   /* Tell the gpg object about the data.  */
1629   if (!err)
1630     err = add_arg (gpg, "--output");
1631   if (!err)
1632     err = add_arg (gpg, "-");
1633   if (!err)
1634     err = add_data (gpg, ciph, 1, 1);
1635   if (gpgme_data_get_file_name (plain))
1636     {
1637       if (!err)
1638         err = add_arg (gpg, "--set-filename");
1639       if (!err)
1640         err = add_arg (gpg, gpgme_data_get_file_name (plain));
1641     }
1642   if (!err)
1643     err = add_arg (gpg, "--");
1644   if (!err)
1645     err = add_data (gpg, plain, -1, 0);
1646
1647   if (!err)
1648     err = start (gpg);
1649
1650   return err;
1651 }
1652
1653
1654 static gpgme_error_t
1655 gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
1656                   gpgme_encrypt_flags_t flags, gpgme_data_t plain,
1657                   gpgme_data_t ciph, int use_armor,
1658                   gpgme_ctx_t ctx /* FIXME */)
1659 {
1660   engine_gpg_t gpg = engine;
1661   gpgme_error_t err;
1662
1663   err = add_arg (gpg, "--encrypt");
1664   if (!err)
1665     err = add_arg (gpg, "--sign");
1666   if (!err && use_armor)
1667     err = add_arg (gpg, "--armor");
1668
1669   /* If we know that all recipients are valid (full or ultimate trust)
1670      we can suppress further checks.  */
1671   if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1672     err = add_arg (gpg, "--always-trust");
1673
1674   if (!err)
1675     err = append_args_from_recipients (gpg, recp);
1676
1677   if (!err)
1678     err = append_args_from_signers (gpg, ctx);
1679   if (!err)
1680     err = append_args_from_sig_notations (gpg, ctx);
1681
1682   /* Tell the gpg object about the data.  */
1683   if (!err)
1684     err = add_arg (gpg, "--output");
1685   if (!err)
1686     err = add_arg (gpg, "-");
1687   if (!err)
1688     err = add_data (gpg, ciph, 1, 1);
1689   if (gpgme_data_get_file_name (plain))
1690     {
1691       if (!err)
1692         err = add_arg (gpg, "--set-filename");
1693       if (!err)
1694         err = add_arg (gpg, gpgme_data_get_file_name (plain));
1695     }
1696   if (!err)
1697     err = add_arg (gpg, "--");
1698   if (!err)
1699     err = add_data (gpg, plain, -1, 0);
1700
1701   if (!err)
1702     err = start (gpg);
1703
1704   return err;
1705 }
1706
1707
1708 static gpgme_error_t
1709 export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
1710                gpgme_data_t keydata, int use_armor)
1711 {
1712   gpgme_error_t err;
1713
1714   if ((mode & ~GPGME_EXPORT_MODE_EXTERN))
1715     return gpg_error (GPG_ERR_NOT_SUPPORTED);
1716
1717   if ((mode & GPGME_EXPORT_MODE_EXTERN))
1718     {
1719       err = add_arg (gpg, "--send-keys");
1720     }
1721   else
1722     {
1723       err = add_arg (gpg, "--export");
1724       if (!err && use_armor)
1725         err = add_arg (gpg, "--armor");
1726       if (!err)
1727         err = add_data (gpg, keydata, 1, 1);
1728     }
1729   if (!err)
1730     err = add_arg (gpg, "--");
1731
1732   return err;
1733 }
1734
1735
1736 static gpgme_error_t
1737 gpg_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1738             gpgme_data_t keydata, int use_armor)
1739 {
1740   engine_gpg_t gpg = engine;
1741   gpgme_error_t err;
1742
1743   err = export_common (gpg, mode, keydata, use_armor);
1744
1745   if (!err && pattern && *pattern)
1746     err = add_arg (gpg, pattern);
1747
1748   if (!err)
1749     err = start (gpg);
1750
1751   return err;
1752 }
1753
1754
1755 static gpgme_error_t
1756 gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1757                 gpgme_data_t keydata, int use_armor)
1758 {
1759   engine_gpg_t gpg = engine;
1760   gpgme_error_t err;
1761
1762   err = export_common (gpg, mode, keydata, use_armor);
1763
1764   if (pattern)
1765     {
1766       while (!err && *pattern && **pattern)
1767         err = add_arg (gpg, *(pattern++));
1768     }
1769
1770   if (!err)
1771     err = start (gpg);
1772
1773   return err;
1774 }
1775
1776
1777 static gpgme_error_t
1778 gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1779             gpgme_data_t pubkey, gpgme_data_t seckey)
1780 {
1781   engine_gpg_t gpg = engine;
1782   gpgme_error_t err;
1783
1784   if (!gpg)
1785     return gpg_error (GPG_ERR_INV_VALUE);
1786
1787   /* We need a special mechanism to get the fd of a pipe here, so that
1788      we can use this for the %pubring and %secring parameters.  We
1789      don't have this yet, so we implement only the adding to the
1790      standard keyrings.  */
1791   if (pubkey || seckey)
1792     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1793
1794   err = add_arg (gpg, "--gen-key");
1795   if (!err && use_armor)
1796     err = add_arg (gpg, "--armor");
1797   if (!err)
1798     err = add_arg (gpg, "--");
1799   if (!err)
1800     err = add_data (gpg, help_data, -1, 0);
1801
1802   if (!err)
1803     err = start (gpg);
1804
1805   return err;
1806 }
1807
1808 /* Return the next DELIM delimited string from DATA as a C-string.
1809    The caller needs to provide the address of a pointer variable which
1810    he has to set to NULL before the first call.  After the last call
1811    to this function, this function needs to be called once more with
1812    DATA set to NULL so that the function can release its internal
1813    state.  After that the pointer variable is free for use again.
1814    Note that we use a delimiter and thus a trailing delimiter is not
1815    required.  DELIM may not be changed after the first call. */
1816 static const char *
1817 string_from_data (gpgme_data_t data, int delim, 
1818                   void **helpptr, gpgme_error_t *r_err)
1819 {
1820 #define MYBUFLEN 2000 /* Fixme: We don't support URLs longer than that.  */
1821   struct {
1822     int  eof_seen;
1823     int  nbytes;      /* Length of the last returned string including
1824                          the delimiter. */
1825     int  buflen;      /* Valid length of BUF.  */
1826     char buf[MYBUFLEN+1];  /* Buffer with one byte extra space.  */
1827   } *self;
1828   char *p;
1829   int nread;
1830
1831   *r_err = 0;
1832   if (!data)
1833     {
1834       if (*helpptr)
1835         {
1836           free (*helpptr);
1837           *helpptr = NULL;
1838         }
1839       return NULL;
1840     }
1841
1842   if (*helpptr)
1843     self = *helpptr;
1844   else
1845     {
1846       self = malloc (sizeof *self);
1847       if (!self)
1848         {
1849           *r_err = gpg_error_from_syserror ();
1850           return NULL;
1851         }
1852       *helpptr = self;
1853       self->eof_seen = 0;
1854       self->nbytes = 0;
1855       self->buflen = 0;
1856     }
1857
1858   if (self->eof_seen)
1859     return NULL;
1860
1861   assert (self->nbytes <= self->buflen);
1862   memmove (self->buf, self->buf + self->nbytes, self->buflen - self->nbytes);
1863   self->buflen -= self->nbytes;
1864   self->nbytes = 0;
1865
1866   do
1867     {
1868       /* Fixme: This is fairly infective scanning because we may scan
1869          the buffer several times.  */
1870       p = memchr (self->buf, delim, self->buflen);
1871       if (p)
1872         {
1873           *p = 0;
1874           self->nbytes = p - self->buf + 1;
1875           return self->buf;
1876         }
1877
1878       if ( !(MYBUFLEN - self->buflen) )
1879         {
1880           /* Not enough space - URL too long.  */
1881           *r_err = gpg_error (GPG_ERR_TOO_LARGE);
1882           return NULL;
1883         }
1884
1885       nread = gpgme_data_read (data, self->buf + self->buflen, 
1886                                MYBUFLEN - self->buflen);
1887       if (nread < 0)
1888         {
1889           *r_err = gpg_error_from_syserror ();
1890           return NULL;
1891         }
1892       self->buflen += nread;
1893     }
1894   while (nread);
1895
1896   /* EOF reached.  If we have anything in the buffer, append a Nul and
1897      return it. */
1898   self->eof_seen = 1;
1899   if (self->buflen)
1900     {
1901       self->buf[self->buflen] = 0;  /* (we allocated one extra byte)  */
1902       return self->buf;
1903     }
1904   return NULL;
1905 #undef MYBUFLEN
1906 }
1907
1908
1909
1910 static gpgme_error_t
1911 gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1912 {
1913   engine_gpg_t gpg = engine;
1914   gpgme_error_t err;
1915   int idx;
1916   gpgme_data_encoding_t dataenc;
1917
1918   if (keydata && keyarray)
1919     return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
1920
1921   dataenc = gpgme_data_get_encoding (keydata);
1922
1923   if (keyarray)
1924     {
1925       err = add_arg (gpg, "--recv-keys");
1926       if (!err)
1927         err = add_arg (gpg, "--");
1928       for (idx=0; !err && keyarray[idx]; idx++)
1929         {
1930           if (keyarray[idx]->protocol != GPGME_PROTOCOL_OpenPGP)
1931             ;
1932           else if (!keyarray[idx]->subkeys)
1933             ;
1934           else if (keyarray[idx]->subkeys->fpr && *keyarray[idx]->subkeys->fpr)
1935             err = add_arg (gpg, keyarray[idx]->subkeys->fpr);
1936           else if (*keyarray[idx]->subkeys->keyid)
1937             err = add_arg (gpg, keyarray[idx]->subkeys->keyid);
1938         }
1939     }
1940   else if (dataenc == GPGME_DATA_ENCODING_URL
1941            || dataenc == GPGME_DATA_ENCODING_URL0)
1942     {
1943       void *helpptr;
1944       const char *string;
1945       gpgme_error_t xerr;
1946       int delim = (dataenc == GPGME_DATA_ENCODING_URL)? '\n': 0;
1947
1948       /* FIXME: --fetch-keys is probably not correct because it can't
1949          grok all kinds of URLs.  On Unix it should just work but on
1950          Windows we will build the command line and that may fail for
1951          some embedded control characters.  It is anyway limited to
1952          the maximum size of the command line.  We need another
1953          command which can take its input from a file.  Maybe we
1954          should use an option to gpg to modify such commands (ala
1955          --multifile).  */
1956       err = add_arg (gpg, "--fetch-keys");
1957       if (!err)
1958         err = add_arg (gpg, "--");
1959       helpptr = NULL;
1960       while (!err
1961              && (string = string_from_data (keydata, delim, &helpptr, &xerr)))
1962         err = add_arg (gpg, string);
1963       if (!err)
1964         err = xerr;
1965       string_from_data (NULL, delim, &helpptr, &xerr);
1966     }
1967   else if (dataenc == GPGME_DATA_ENCODING_URLESC)
1968     {
1969       /* Already escaped URLs are not yet supported.  */
1970       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1971     }
1972   else
1973     {
1974       err = add_arg (gpg, "--import");
1975       if (!err)
1976         err = add_arg (gpg, "--");
1977       if (!err)
1978         err = add_data (gpg, keydata, -1, 0);
1979     }
1980
1981   if (!err)
1982     err = start (gpg);
1983
1984   return err;
1985 }
1986
1987
1988 /* The output for external keylistings in GnuPG is different from all
1989    the other key listings.  We catch this here with a special
1990    preprocessor that reformats the colon handler lines.  */
1991 static gpgme_error_t
1992 gpg_keylist_preprocess (char *line, char **r_line)
1993 {
1994   enum
1995     {
1996       RT_NONE, RT_INFO, RT_PUB, RT_UID
1997     }
1998   rectype = RT_NONE;
1999 #define NR_FIELDS 16
2000   char *field[NR_FIELDS];
2001   int fields = 0;
2002
2003   *r_line = NULL;
2004
2005   while (line && fields < NR_FIELDS)
2006     {
2007       field[fields++] = line;
2008       line = strchr (line, ':');
2009       if (line)
2010         *(line++) = '\0';
2011     }
2012
2013   if (!strcmp (field[0], "info"))
2014     rectype = RT_INFO;
2015   else if (!strcmp (field[0], "pub"))
2016     rectype = RT_PUB;
2017   else if (!strcmp (field[0], "uid"))
2018     rectype = RT_UID;
2019   else 
2020     rectype = RT_NONE;
2021
2022   switch (rectype)
2023     {
2024     case RT_INFO:
2025       /* FIXME: Eventually, check the version number at least.  */
2026       return 0;
2027
2028     case RT_PUB:
2029       if (fields < 7)
2030         return 0;
2031
2032       /* The format is:
2033
2034          pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags>
2035
2036          as defined in 5.2. Machine Readable Indexes of the OpenPGP
2037          HTTP Keyserver Protocol (draft). 
2038
2039          We want:
2040          pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>::::::::
2041       */
2042
2043       if (asprintf (r_line, "pub:o%s:%s:%s:%s:%s:%s::::::::",
2044                     field[6], field[3], field[2], field[1],
2045                     field[4], field[5]) < 0)
2046         return gpg_error_from_errno (errno);
2047       return 0;
2048
2049     case RT_UID:
2050       /* The format is:
2051
2052          uid:<escaped uid string>:<creationdate>:<expirationdate>:<flags>
2053
2054          as defined in 5.2. Machine Readable Indexes of the OpenPGP
2055          HTTP Keyserver Protocol (draft). 
2056
2057          We want:
2058          uid:o<flags>::::<creatdate>:<expdate>:::<c-coded uid>:
2059       */
2060
2061       {
2062         /* The user ID is percent escaped, but we want c-coded.
2063            Because we have to replace each '%HL' by '\xHL', we need at
2064            most 4/3 th the number of bytes.  But because we also need
2065            to escape the backslashes we allocate twice as much.  */
2066         char *uid = malloc (2 * strlen (field[1]) + 1);
2067         char *src;
2068         char *dst;
2069
2070         if (! uid)
2071           return gpg_error_from_errno (errno);
2072         src = field[1];
2073         dst = uid;
2074         while (*src)
2075           {
2076             if (*src == '%')
2077               {
2078                 *(dst++) = '\\';
2079                 *(dst++) = 'x';
2080                 src++;
2081                 /* Copy the next two bytes unconditionally.  */
2082                 if (*src)
2083                   *(dst++) = *(src++);
2084                 if (*src)
2085                   *(dst++) = *(src++);
2086               }
2087             else if (*src == '\\')
2088               {
2089                 *dst++ = '\\';
2090                 *dst++ = '\\';
2091               }
2092             else
2093               *(dst++) = *(src++);
2094           }
2095         *dst = '\0';
2096
2097         if (asprintf (r_line, "uid:o%s::::%s:%s:::%s:",
2098                       field[4], field[2], field[3], uid) < 0)
2099           return gpg_error_from_errno (errno);
2100       }
2101       return 0;
2102
2103     case RT_NONE:
2104       /* Unknown record.  */
2105       break;
2106     }
2107   return 0;
2108
2109 }
2110
2111
2112 static gpg_error_t
2113 gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
2114                            gpgme_keylist_mode_t mode)
2115 {
2116   gpg_error_t err;
2117
2118   err = add_arg (gpg, "--with-colons");
2119   if (!err)
2120     err = add_arg (gpg, "--fixed-list-mode");
2121   if (!err)
2122     err = add_arg (gpg, "--with-fingerprint");
2123   if (!err)
2124     err = add_arg (gpg, "--with-fingerprint");
2125   if (!err
2126       && (mode & GPGME_KEYLIST_MODE_SIGS)
2127       && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
2128     {
2129       err = add_arg (gpg, "--list-options");
2130       if (!err)
2131         err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
2132     }
2133   if (!err)
2134     {
2135       if ( (mode & GPGME_KEYLIST_MODE_EXTERN) )
2136         {
2137           if (secret_only)
2138             err = gpg_error (GPG_ERR_NOT_SUPPORTED);
2139           else if ( (mode & GPGME_KEYLIST_MODE_LOCAL))
2140             {
2141               /* The local+extern mode is special.  It works only with
2142                  gpg >= 2.0.10.  FIXME: We should check that we have
2143                  such a version to that we can return a proper error
2144                  code.  The problem is that we don't know the context
2145                  here and thus can't access the cached version number
2146                  for the engine info structure.  */
2147               err = add_arg (gpg, "--locate-keys");
2148               if ((mode & GPGME_KEYLIST_MODE_SIGS))
2149                 err = add_arg (gpg, "--with-sig-check");
2150             }
2151           else
2152             {
2153               err = add_arg (gpg, "--search-keys");
2154               gpg->colon.preprocess_fnc = gpg_keylist_preprocess;
2155             }
2156         }
2157       else
2158         {
2159           err = add_arg (gpg, secret_only ? "--list-secret-keys"
2160                          : ((mode & GPGME_KEYLIST_MODE_SIGS)
2161                             ? "--check-sigs" : "--list-keys"));
2162         }
2163     }
2164   if (!err)
2165     err = add_arg (gpg, "--");
2166   
2167   return err;
2168 }
2169                            
2170
2171 static gpgme_error_t
2172 gpg_keylist (void *engine, const char *pattern, int secret_only,
2173              gpgme_keylist_mode_t mode)
2174 {
2175   engine_gpg_t gpg = engine;
2176   gpgme_error_t err;
2177
2178   err = gpg_keylist_build_options (gpg, secret_only, mode);
2179
2180   if (!err && pattern && *pattern)
2181     err = add_arg (gpg, pattern);
2182
2183   if (!err)
2184     err = start (gpg);
2185
2186   return err;
2187 }
2188
2189
2190 static gpgme_error_t
2191 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
2192                  int reserved, gpgme_keylist_mode_t mode)
2193 {
2194   engine_gpg_t gpg = engine;
2195   gpgme_error_t err;
2196
2197   if (reserved)
2198     return gpg_error (GPG_ERR_INV_VALUE);
2199
2200   err = gpg_keylist_build_options (gpg, secret_only, mode);
2201
2202   if (pattern)
2203     {
2204       while (!err && *pattern && **pattern)
2205         err = add_arg (gpg, *(pattern++));
2206     }
2207
2208   if (!err)
2209     err = start (gpg);
2210
2211   return err;
2212 }
2213
2214
2215 static gpgme_error_t
2216 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
2217           gpgme_sig_mode_t mode, int use_armor, int use_textmode,
2218           int include_certs, gpgme_ctx_t ctx /* FIXME */)
2219 {
2220   engine_gpg_t gpg = engine;
2221   gpgme_error_t err;
2222
2223   if (mode == GPGME_SIG_MODE_CLEAR)
2224     err = add_arg (gpg, "--clearsign");
2225   else
2226     {
2227       err = add_arg (gpg, "--sign");
2228       if (!err && mode == GPGME_SIG_MODE_DETACH)
2229         err = add_arg (gpg, "--detach");
2230       if (!err && use_armor)
2231         err = add_arg (gpg, "--armor");
2232       if (!err && use_textmode)
2233         err = add_arg (gpg, "--textmode");
2234     }
2235
2236   if (!err)
2237     err = append_args_from_signers (gpg, ctx);
2238   if (!err)
2239     err = append_args_from_sig_notations (gpg, ctx);
2240
2241   if (gpgme_data_get_file_name (in))
2242     {
2243       if (!err)
2244         err = add_arg (gpg, "--set-filename");
2245       if (!err)
2246         err = add_arg (gpg, gpgme_data_get_file_name (in));
2247     }
2248
2249   /* Tell the gpg object about the data.  */
2250   if (!err)
2251     err = add_arg (gpg, "--");
2252   if (!err)
2253     err = add_data (gpg, in, -1, 0);
2254   if (!err)
2255     err = add_data (gpg, out, 1, 1);
2256
2257   if (!err)
2258     start (gpg);
2259
2260   return err;
2261 }
2262
2263 static gpgme_error_t
2264 gpg_trustlist (void *engine, const char *pattern)
2265 {
2266   engine_gpg_t gpg = engine;
2267   gpgme_error_t err;
2268
2269   err = add_arg (gpg, "--with-colons");
2270   if (!err)
2271     err = add_arg (gpg, "--list-trust-path");
2272   
2273   /* Tell the gpg object about the data.  */
2274   if (!err)
2275     err = add_arg (gpg, "--");
2276   if (!err)
2277     err = add_arg (gpg, pattern);
2278
2279   if (!err)
2280     err = start (gpg);
2281
2282   return err;
2283 }
2284
2285
2286 static gpgme_error_t
2287 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
2288             gpgme_data_t plaintext)
2289 {
2290   engine_gpg_t gpg = engine;
2291   gpgme_error_t err = 0;
2292
2293   if (plaintext)
2294     {
2295       /* Normal or cleartext signature.  */
2296
2297       err = add_arg (gpg, "--output");
2298       if (!err)
2299         err = add_arg (gpg, "-");
2300       if (!err)
2301         err = add_arg (gpg, "--");
2302       if (!err)
2303         err = add_data (gpg, sig, -1, 0);
2304       if (!err)
2305         err = add_data (gpg, plaintext, 1, 1);
2306     }
2307   else
2308     {
2309       err = add_arg (gpg, "--verify");
2310       if (!err)
2311         err = add_arg (gpg, "--");
2312       if (!err)
2313         err = add_data (gpg, sig, -1, 0);
2314       if (!err && signed_text)
2315         err = add_data (gpg, signed_text, -1, 0);
2316     }
2317
2318   if (!err)
2319     err = start (gpg);
2320
2321   return err;
2322 }
2323
2324
2325 static void
2326 gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
2327 {
2328   engine_gpg_t gpg = engine;
2329
2330   gpg->io_cbs = *io_cbs;
2331 }
2332
2333 \f
2334 struct engine_ops _gpgme_engine_ops_gpg =
2335   {
2336     /* Static functions.  */
2337     _gpgme_get_gpg_path,
2338     NULL,               
2339     gpg_get_version,
2340     gpg_get_req_version,
2341     gpg_new,
2342
2343     /* Member functions.  */
2344     gpg_release,
2345     NULL,                               /* reset */
2346     gpg_set_status_handler,
2347     gpg_set_command_handler,
2348     gpg_set_colon_line_handler,
2349     gpg_set_locale,
2350     gpg_decrypt,
2351     gpg_delete,
2352     gpg_edit,
2353     gpg_encrypt,
2354     gpg_encrypt_sign,
2355     gpg_export,
2356     gpg_export_ext,
2357     gpg_genkey,
2358     gpg_import,
2359     gpg_keylist,
2360     gpg_keylist_ext,
2361     gpg_sign,
2362     gpg_trustlist,
2363     gpg_verify,
2364     NULL,               /* getauditlog */
2365     NULL,               /* opassuan_transact */
2366     NULL,               /* conf_load */
2367     NULL,               /* conf_save */
2368     gpg_set_io_cbs,
2369     gpg_io_event,
2370     gpg_cancel,
2371     NULL                /* cancel_op */
2372   };