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