2003-05-28 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / rungpg.c
1 /* rungpg.c - Gpg Engine.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 g10 Code GmbH
4  
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11  
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <sys/time.h>
31 #include <sys/types.h>
32 #include <signal.h>
33 #include <fcntl.h>
34 #include "unistd.h"
35
36 #include "gpgme.h"
37 #include "util.h"
38 #include "ops.h"
39 #include "wait.h"
40 #include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
41 #include "io.h"
42 #include "sema.h"
43 #include "debug.h"
44
45 #include "status-table.h"
46 #include "engine-backend.h"
47
48
49 /* This type is used to build a list of gpg arguments and data
50    sources/sinks.  */
51 struct arg_and_data_s
52 {
53   struct arg_and_data_s *next;
54   gpgme_data_t data;  /* If this is not NULL, use arg below.  */
55   int inbound;     /* True if this is used for reading from gpg.  */
56   int dup_to;
57   int print_fd;    /* Print the fd number and not the special form of it.  */
58   char arg[1];     /* Used if data above is not used.  */
59 };
60
61
62 struct fd_data_map_s
63 {
64   gpgme_data_t data;
65   int inbound;  /* true if this is used for reading from gpg */
66   int dup_to;
67   int fd;       /* the fd to use */
68   int peer_fd;  /* the outher side of the pipe */
69   void *tag;
70 };
71
72
73 struct gpg_object_s
74 {
75   struct arg_and_data_s *arglist;
76   struct arg_and_data_s **argtail;
77   int arg_error;
78
79   struct
80   {
81     int fd[2];  
82     size_t bufsize;
83     char *buffer;
84     size_t readpos;
85     int eof;
86     engine_status_handler_t fnc;
87     void *fnc_value;
88     void *tag;
89   } status;
90
91   /* This is a kludge - see the comment at colon_line_handler.  */
92   struct
93   {
94     int fd[2];  
95     size_t bufsize;
96     char *buffer;
97     size_t readpos;
98     int eof;
99     engine_colon_line_handler_t fnc;  /* this indicate use of this structrue */
100     void *fnc_value;
101     void *tag;
102   } colon;
103
104   char **argv;  
105   struct fd_data_map_s *fd_data_map;
106
107   /* stuff needed for interactive (command) mode */
108   struct
109   {
110     int used;
111     int fd;
112     void *cb_data;
113     int idx;            /* Index in fd_data_map */
114     gpgme_status_code_t code;  /* last code */
115     char *keyword;       /* what has been requested (malloced) */
116     engine_command_handler_t fnc; 
117     void *fnc_value;
118     /* The kludges never end.  This is used to couple command handlers
119        with output data in edit key mode.  */
120     gpgme_data_t linked_data;
121     int linked_idx;
122   } cmd;
123
124   struct gpgme_io_cbs io_cbs;
125 };
126
127 typedef struct gpg_object_s *GpgObject;
128
129 \f
130 static void
131 gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
132 {
133   GpgObject gpg = engine;
134
135   if (gpg->io_cbs.event)
136     (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
137 }
138
139
140 static void
141 close_notify_handler (int fd, void *opaque)
142 {
143   GpgObject gpg = opaque;
144   assert (fd != -1);
145
146   if (gpg->status.fd[0] == fd)
147     {
148       if (gpg->status.tag)
149         (*gpg->io_cbs.remove) (gpg->status.tag);
150       gpg->status.fd[0] = -1;
151     }
152   else if (gpg->status.fd[1] == fd)
153     gpg->status.fd[1] = -1;
154   else if (gpg->colon.fd[0] == fd)
155     {
156       if (gpg->colon.tag)
157         (*gpg->io_cbs.remove) (gpg->colon.tag);
158       gpg->colon.fd[0] = -1;
159     }
160   else if (gpg->colon.fd[1] == fd)
161     gpg->colon.fd[1] = -1;
162   else if (gpg->fd_data_map)
163     {
164       int i;
165
166       for (i = 0; gpg->fd_data_map[i].data; i++)
167         {
168           if (gpg->fd_data_map[i].fd == fd)
169             {
170               if (gpg->fd_data_map[i].tag)
171                 (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
172               gpg->fd_data_map[i].fd = -1;
173               break;
174             }
175           if (gpg->fd_data_map[i].peer_fd == fd)
176             {
177               gpg->fd_data_map[i].peer_fd = -1;
178               break;
179             }
180         }
181     }
182 }
183
184 static gpgme_error_t
185 add_arg (GpgObject gpg, const char *arg)
186 {
187   struct arg_and_data_s *a;
188
189   assert (gpg);
190   assert (arg);
191
192   a = malloc (sizeof *a + strlen (arg));
193   if (!a)
194     {
195       gpg->arg_error = 1;
196       return GPGME_Out_Of_Core;
197     }
198   a->next = NULL;
199   a->data = NULL;
200   a->dup_to = -1;
201   strcpy (a->arg, arg);
202   *gpg->argtail = a;
203   gpg->argtail = &a->next;
204   return 0;
205 }
206
207 static gpgme_error_t
208 add_data (GpgObject gpg, gpgme_data_t data, int dup_to, int inbound)
209 {
210   struct arg_and_data_s *a;
211
212   assert (gpg);
213   assert (data);
214
215   a = malloc (sizeof *a - 1);
216   if (!a)
217     {
218       gpg->arg_error = 1;
219       return GPGME_Out_Of_Core;
220     }
221   a->next = NULL;
222   a->data = data;
223   a->inbound = inbound;
224   if (dup_to == -2)
225     {
226       a->print_fd = 1;
227       a->dup_to = -1;
228     }
229   else
230     {
231       a->print_fd = 0;
232       a->dup_to = dup_to;
233     }
234   *gpg->argtail = a;
235   gpg->argtail = &a->next;
236   return 0;
237 }
238
239 \f
240 static const char *
241 gpg_get_version (void)
242 {
243   static const char *gpg_version;
244   DEFINE_STATIC_LOCK (gpg_version_lock);
245
246   LOCK (gpg_version_lock);
247   if (!gpg_version)
248     gpg_version = _gpgme_get_program_version (_gpgme_get_gpg_path ());
249   UNLOCK (gpg_version_lock);
250   return gpg_version;
251 }
252
253
254 static const char *
255 gpg_get_req_version (void)
256 {
257   return NEED_GPG_VERSION;
258 }
259
260
261 static void
262 free_argv (char **argv)
263 {
264   int i;
265
266   for (i = 0; argv[i]; i++)
267     free (argv[i]);
268   free (argv);
269 }
270
271
272 static void
273 free_fd_data_map (struct fd_data_map_s *fd_data_map)
274 {
275   int i;
276
277   if (!fd_data_map)
278     return;
279
280   for (i = 0; fd_data_map[i].data; i++)
281     {
282       if (fd_data_map[i].fd != -1)
283         _gpgme_io_close (fd_data_map[i].fd);
284       if (fd_data_map[i].peer_fd != -1)
285         _gpgme_io_close (fd_data_map[i].peer_fd);
286       /* Don't release data because this is only a reference.  */
287     }
288   free (fd_data_map);
289 }
290
291
292 static void
293 gpg_release (void *engine)
294 {
295   GpgObject gpg = engine;
296
297   if (!gpg)
298     return;
299
300   while (gpg->arglist)
301     {
302       struct arg_and_data_s *next = gpg->arglist->next;
303
304       if (gpg->arglist)
305         free (gpg->arglist);
306       gpg->arglist = next;
307     }
308
309   if (gpg->status.buffer)
310     free (gpg->status.buffer);
311   if (gpg->colon.buffer)
312     free (gpg->colon.buffer);
313   if (gpg->argv)
314     free_argv (gpg->argv);
315   if (gpg->cmd.keyword)
316     free (gpg->cmd.keyword);
317
318   if (gpg->status.fd[0] != -1)
319     _gpgme_io_close (gpg->status.fd[0]);
320   if (gpg->status.fd[1] != -1)
321     _gpgme_io_close (gpg->status.fd[1]);
322   if (gpg->colon.fd[0] != -1)
323     _gpgme_io_close (gpg->colon.fd[0]);
324   if (gpg->colon.fd[1] != -1)
325     _gpgme_io_close (gpg->colon.fd[1]);
326   if (gpg->fd_data_map)
327     free_fd_data_map (gpg->fd_data_map);
328   if (gpg->cmd.fd != -1)
329     _gpgme_io_close (gpg->cmd.fd);
330   free (gpg);
331 }
332
333
334 static gpgme_error_t
335 gpg_new (void **engine)
336 {
337   GpgObject gpg;
338   int rc = 0;
339
340   gpg = calloc (1, sizeof *gpg);
341   if (!gpg)
342     {
343       rc = GPGME_Out_Of_Core;
344       goto leave;
345     }
346   gpg->argtail = &gpg->arglist;
347
348   gpg->status.fd[0] = -1;
349   gpg->status.fd[1] = -1;
350   gpg->colon.fd[0] = -1;
351   gpg->colon.fd[1] = -1;
352   gpg->cmd.fd = -1;
353   gpg->cmd.idx = -1;
354   gpg->cmd.linked_data = NULL;
355   gpg->cmd.linked_idx = -1;
356
357   /* Allocate the read buffer for the status pipe.  */
358   gpg->status.bufsize = 1024;
359   gpg->status.readpos = 0;
360   gpg->status.buffer = malloc (gpg->status.bufsize);
361   if (!gpg->status.buffer)
362     {
363       rc = GPGME_Out_Of_Core;
364       goto leave;
365     }
366   /* In any case we need a status pipe - create it right here and
367      don't handle it with our generic gpgme_data_t mechanism.  */
368   if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
369     {
370       rc = GPGME_Pipe_Error;
371       goto leave;
372     }
373   if (_gpgme_io_set_close_notify (gpg->status.fd[0],
374                                   close_notify_handler, gpg)
375       || _gpgme_io_set_close_notify (gpg->status.fd[1],
376                                      close_notify_handler, gpg))
377     {
378       rc = GPGME_General_Error;
379       goto leave;
380     }
381   gpg->status.eof = 0;
382   add_arg (gpg, "--status-fd");
383   {
384     char buf[25];
385     sprintf (buf, "%d", gpg->status.fd[1]);
386     add_arg (gpg, buf);
387   }
388   add_arg (gpg, "--no-tty");
389   add_arg (gpg, "--charset");
390   add_arg (gpg, "utf8");
391   add_arg (gpg, "--enable-progress-filter");
392
393  leave:
394   if (rc)
395     gpg_release (gpg);
396   else
397     *engine = gpg;
398   return rc;
399 }
400
401
402 /* Note, that the status_handler is allowed to modifiy the args
403    value.  */
404 static void
405 gpg_set_status_handler (void *engine, engine_status_handler_t fnc,
406                         void *fnc_value)
407 {
408   GpgObject gpg = engine;
409
410   gpg->status.fnc = fnc;
411   gpg->status.fnc_value = fnc_value;
412 }
413
414 /* Kludge to process --with-colon output.  */
415 static gpgme_error_t
416 gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
417                             void *fnc_value)
418 {
419   GpgObject gpg = engine;
420
421   gpg->colon.bufsize = 1024;
422   gpg->colon.readpos = 0;
423   gpg->colon.buffer = malloc (gpg->colon.bufsize);
424   if (!gpg->colon.buffer)
425     return GPGME_Out_Of_Core;
426
427   if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) 
428     {
429       free (gpg->colon.buffer);
430       gpg->colon.buffer = NULL;
431       return GPGME_Pipe_Error;
432     }
433   if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
434       || _gpgme_io_set_close_notify (gpg->colon.fd[1],
435                                      close_notify_handler, gpg))
436     return GPGME_General_Error;
437   gpg->colon.eof = 0;
438   gpg->colon.fnc = fnc;
439   gpg->colon.fnc_value = fnc_value;
440   return 0;
441 }
442
443
444 static gpgme_error_t
445 command_handler (void *opaque, int fd)
446 {
447   gpgme_error_t err;
448   GpgObject gpg = (GpgObject) opaque;
449
450   assert (gpg->cmd.used);
451   assert (gpg->cmd.code);
452   assert (gpg->cmd.fnc);
453
454   err = gpg->cmd.fnc (gpg->cmd.fnc_value, gpg->cmd.code, gpg->cmd.keyword, fd);
455   if (err)
456     return err;
457
458   gpg->cmd.code = 0;
459   /* And sleep again until read_status will wake us up again.  */
460   /* XXX We must check if there are any more fds active after removing
461      this one.  */
462   (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
463   gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
464   gpg->fd_data_map[gpg->cmd.idx].fd = -1;
465
466   return 0;
467 }
468
469
470
471 /* The Fnc will be called to get a value for one of the commands with
472    a key KEY.  If the Code pssed to FNC is 0, the function may release
473    resources associated with the returned value from another call.  To
474    match such a second call to a first call, the returned value from
475    the first call is passed as keyword.  */
476 static gpgme_error_t
477 gpg_set_command_handler (void *engine, engine_command_handler_t fnc,
478                          void *fnc_value, gpgme_data_t linked_data)
479 {
480   GpgObject gpg = engine;
481
482   add_arg (gpg, "--command-fd");
483   /* This is a hack.  We don't have a real data object.  The only
484      thing that matters is that we use something unique, so we use the
485      address of the cmd structure in the gpg object.  */
486   add_data (gpg, (void *) &gpg->cmd, -2, 0);
487   gpg->cmd.fnc = fnc;
488   gpg->cmd.cb_data = (void *) &gpg->cmd;
489   gpg->cmd.fnc_value = fnc_value;
490   gpg->cmd.linked_data = linked_data;
491   gpg->cmd.used = 1;
492   return 0;
493 }
494
495
496 static gpgme_error_t
497 build_argv (GpgObject gpg)
498 {
499   struct arg_and_data_s *a;
500   struct fd_data_map_s *fd_data_map;
501   size_t datac=0, argc=0;  
502   char **argv;
503   int need_special = 0;
504   int use_agent = 0;
505   char *p;
506
507   /* We don't want to use the agent with a malformed environment
508      variable.  This is only a very basic test but sufficient to make
509      our life in the regression tests easier. */
510   p = getenv ("GPG_AGENT_INFO");
511   use_agent = (p && strchr (p, ':'));
512        
513   if (gpg->argv)
514     {
515       free_argv (gpg->argv);
516       gpg->argv = NULL;
517     }
518   if (gpg->fd_data_map)
519     {
520       free_fd_data_map (gpg->fd_data_map);
521       gpg->fd_data_map = NULL;
522     }
523
524   argc++;       /* For argv[0].  */
525   for (a = gpg->arglist; a; a = a->next)
526     {
527       argc++;
528       if (a->data)
529         {
530           /*fprintf (stderr, "build_argv: data\n" );*/
531           datac++;
532           if (a->dup_to == -1 && !a->print_fd)
533             need_special = 1;
534         }
535       else
536         {
537           /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
538         }
539     }
540   if (need_special)
541     argc++;
542   if (use_agent)
543     argc++;
544   if (!gpg->cmd.used)
545     argc++;     /* --batch */
546   argc += 2; /* --comment */
547
548   argv = calloc (argc + 1, sizeof *argv);
549   if (!argv)
550     return GPGME_Out_Of_Core;
551   fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
552   if (!fd_data_map)
553     {
554       free_argv (argv);
555       return GPGME_Out_Of_Core;
556     }
557
558   argc = datac = 0;
559   argv[argc] = strdup ("gpg"); /* argv[0] */
560   if (!argv[argc])
561     {
562       free (fd_data_map);
563       free_argv (argv);
564       return GPGME_Out_Of_Core;
565     }
566   argc++;
567   if (need_special)
568     {
569       argv[argc] = strdup ("--enable-special-filenames");
570       if (!argv[argc])
571         {
572           free (fd_data_map);
573           free_argv (argv);
574           return GPGME_Out_Of_Core;
575         }
576       argc++;
577     }
578   if (use_agent)
579     {
580       argv[argc] = strdup ("--use-agent");
581       if (!argv[argc])
582         {
583           free (fd_data_map);
584           free_argv (argv);
585           return GPGME_Out_Of_Core;
586         }
587       argc++;
588     }
589   if (!gpg->cmd.used)
590     {
591       argv[argc] = strdup ("--batch");
592       if (!argv[argc])
593         {
594           free (fd_data_map);
595           free_argv (argv);
596           return GPGME_Out_Of_Core;
597         }
598       argc++;
599     }
600   argv[argc] = strdup ("--comment");
601   if (!argv[argc])
602     {
603       free (fd_data_map);
604       free_argv (argv);
605       return GPGME_Out_Of_Core;
606     }
607   argc++;
608   argv[argc] = strdup ("");
609   if (!argv[argc])
610     {
611       free (fd_data_map);
612       free_argv (argv);
613       return GPGME_Out_Of_Core;
614     }
615   argc++;
616   for (a = gpg->arglist; a; a = a->next)
617     {
618       if (a->data)
619         {
620           /* Create a pipe to pass it down to gpg.  */
621           fd_data_map[datac].inbound = a->inbound;
622
623           /* Create a pipe.  */
624           {   
625             int fds[2];
626             
627             if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
628                 == -1)
629               {
630                 free (fd_data_map);
631                 free_argv (argv);
632                 return GPGME_Pipe_Error;
633               }
634             if (_gpgme_io_set_close_notify (fds[0],
635                                             close_notify_handler, gpg)
636                 || _gpgme_io_set_close_notify (fds[1],
637                                                close_notify_handler,
638                                                gpg))
639               {
640                 return GPGME_General_Error;
641               }
642             /* If the data_type is FD, we have to do a dup2 here.  */
643             if (fd_data_map[datac].inbound)
644               {
645                 fd_data_map[datac].fd       = fds[0];
646                 fd_data_map[datac].peer_fd  = fds[1];
647               }
648             else
649               {
650                 fd_data_map[datac].fd       = fds[1];
651                 fd_data_map[datac].peer_fd  = fds[0];
652               }
653           }
654
655           /* Hack to get hands on the fd later.  */
656           if (gpg->cmd.used)
657             {
658               if (gpg->cmd.cb_data == a->data)
659                 {
660                   assert (gpg->cmd.idx == -1);
661                   gpg->cmd.idx = datac;
662                 }
663               else if (gpg->cmd.linked_data == a->data)
664                 {
665                   assert (gpg->cmd.linked_idx == -1);
666                   gpg->cmd.linked_idx = datac;
667                 }
668             }
669
670           fd_data_map[datac].data = a->data;
671           fd_data_map[datac].dup_to = a->dup_to;
672           if (a->dup_to == -1)
673             {
674               argv[argc] = malloc (25);
675               if (!argv[argc])
676                 {
677                   free (fd_data_map);
678                   free_argv (argv);
679                   return GPGME_Out_Of_Core;
680                 }
681               sprintf (argv[argc], 
682                        a->print_fd ? "%d" : "-&%d",
683                        fd_data_map[datac].peer_fd);
684               argc++;
685             }
686           datac++;
687         }
688       else
689         {
690           argv[argc] = strdup (a->arg);
691           if (!argv[argc])
692             {
693               free (fd_data_map);
694               free_argv (argv);
695               return GPGME_Out_Of_Core;
696             }
697             argc++;
698         }
699     }
700
701   gpg->argv = argv;
702   gpg->fd_data_map = fd_data_map;
703   return 0;
704 }
705
706
707 static gpgme_error_t
708 add_io_cb (GpgObject gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
709            void **tag)
710 {
711   gpgme_error_t err;
712
713   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
714   if (err)
715     return err;
716   if (!dir)
717     /* FIXME Kludge around poll() problem.  */
718     err = _gpgme_io_set_nonblocking (fd);
719   return err;
720 }
721
722
723 static int
724 status_cmp (const void *ap, const void *bp)
725 {
726   const struct status_table_s *a = ap;
727   const struct status_table_s *b = bp;
728
729   return strcmp (a->name, b->name);
730 }
731
732
733 /* Handle the status output of GnuPG.  This function does read entire
734    lines and passes them as C strings to the callback function (we can
735    use C Strings because the status output is always UTF-8 encoded).
736    Of course we have to buffer the lines to cope with long lines
737    e.g. with a large user ID.  Note: We can optimize this to only cope
738    with status line code we know about and skip all other stuff
739    without buffering (i.e. without extending the buffer).  */
740 static gpgme_error_t
741 read_status (GpgObject gpg)
742 {
743   char *p;
744   int nread;
745   size_t bufsize = gpg->status.bufsize; 
746   char *buffer = gpg->status.buffer;
747   size_t readpos = gpg->status.readpos; 
748
749   assert (buffer);
750   if (bufsize - readpos < 256)
751     { 
752       /* Need more room for the read.  */
753       bufsize += 1024;
754       buffer = realloc (buffer, bufsize);
755       if (!buffer)
756         return GPGME_Out_Of_Core;
757     }
758
759   nread = _gpgme_io_read (gpg->status.fd[0],
760                           buffer + readpos, bufsize-readpos);
761   if (nread == -1)
762     return GPGME_Read_Error;
763
764   if (!nread)
765     {
766       gpg->status.eof = 1;
767       if (gpg->status.fnc)
768         {
769           gpgme_error_t err;
770           err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
771           if (err)
772             return err;
773         }
774       return 0;
775     }
776
777   while (nread > 0)
778     {
779       for (p = buffer + readpos; nread; nread--, p++)
780         {
781           if (*p == '\n')
782             {
783               /* (we require that the last line is terminated by a LF) */
784               *p = 0;
785               if (!strncmp (buffer, "[GNUPG:] ", 9)
786                   && buffer[9] >= 'A' && buffer[9] <= 'Z')
787                 {
788                   struct status_table_s t, *r;
789                   char *rest;
790
791                   rest = strchr (buffer + 9, ' ');
792                   if (!rest)
793                     rest = p; /* Set to an empty string.  */
794                   else
795                     *rest++ = 0;
796                     
797                   t.name = buffer+9;
798                   /* (the status table has one extra element) */
799                   r = bsearch (&t, status_table, DIM(status_table) - 1,
800                                sizeof t, status_cmp);
801                   if (r)
802                     {
803                       if (gpg->cmd.used
804                           && (r->code == GPGME_STATUS_GET_BOOL
805                               || r->code == GPGME_STATUS_GET_LINE
806                               || r->code == GPGME_STATUS_GET_HIDDEN))
807                         {
808                           gpg->cmd.code = r->code;
809                           if (gpg->cmd.keyword)
810                             free (gpg->cmd.keyword);
811                           gpg->cmd.keyword = strdup (rest);
812                           if (!gpg->cmd.keyword)
813                             return GPGME_Out_Of_Core;
814                           /* This should be the last thing we have
815                              received and the next thing will be that
816                              the command handler does its action.  */
817                           if (nread > 1)
818                             DEBUG0 ("ERROR, unexpected data in read_status");
819
820                           /* Before we can actually add the command
821                              fd, we might have to flush the linked
822                              output data pipe.  */
823                           if (gpg->cmd.linked_idx != -1
824                               && gpg->fd_data_map[gpg->cmd.linked_idx].fd != -1)
825                             {
826                               struct io_select_fd_s fds;
827                               fds.fd = gpg->fd_data_map[gpg->cmd.linked_idx].fd;
828                               fds.for_read = 1;
829                               fds.for_write = 0;
830                               fds.frozen = 0;
831                               fds.opaque = NULL;
832                               do
833                                 {
834                                   fds.signaled = 0;
835                                   _gpgme_io_select (&fds, 1, 1);
836                                   if (fds.signaled)
837                                     _gpgme_data_inbound_handler
838                                       (gpg->cmd.linked_data, fds.fd);
839                                 }
840                               while (fds.signaled);
841                             }
842
843                           add_io_cb (gpg, gpg->cmd.fd, 0,
844                                      command_handler, gpg,
845                                      &gpg->fd_data_map[gpg->cmd.idx].tag);
846                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
847                           gpg->cmd.fd = -1;
848                         }
849                       else if (gpg->status.fnc)
850                         {
851                           gpgme_error_t err;
852                           err = gpg->status.fnc (gpg->status.fnc_value, 
853                                                  r->code, rest);
854                           if (err)
855                             return err;
856                         }
857                     
858                       if (r->code == GPGME_STATUS_END_STREAM)
859                         {
860                           if (gpg->cmd.used)
861                             {
862                               /* XXX We must check if there are any
863                                  more fds active after removing this
864                                  one.  */
865                               (*gpg->io_cbs.remove)
866                                 (gpg->fd_data_map[gpg->cmd.idx].tag);
867                               gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
868                               gpg->fd_data_map[gpg->cmd.idx].fd = -1;
869                             }
870                         }
871                     }
872                 }
873               /* To reuse the buffer for the next line we have to
874                  shift the remaining data to the buffer start and
875                  restart the loop Hmmm: We can optimize this function
876                  by looking forward in the buffer to see whether a
877                  second complete line is available and in this case
878                  avoid the memmove for this line.  */
879               nread--; p++;
880               if (nread)
881                 memmove (buffer, p, nread);
882               readpos = 0;
883               break; /* the for loop */
884             }
885           else
886             readpos++;
887         }
888     } 
889
890   /* Update the gpg object.  */
891   gpg->status.bufsize = bufsize;
892   gpg->status.buffer = buffer;
893   gpg->status.readpos = readpos;
894   return 0;
895 }
896
897
898 static gpgme_error_t
899 status_handler (void *opaque, int fd)
900 {
901   GpgObject gpg = opaque;
902   int err;
903
904   assert (fd == gpg->status.fd[0]);
905   err = read_status (gpg);
906   if (err)
907     return err;
908   if (gpg->status.eof)
909     _gpgme_io_close (fd);
910   return 0;
911 }
912
913
914 static gpgme_error_t
915 read_colon_line (GpgObject gpg)
916 {
917   char *p;
918   int nread;
919   size_t bufsize = gpg->colon.bufsize; 
920   char *buffer = gpg->colon.buffer;
921   size_t readpos = gpg->colon.readpos; 
922
923   assert (buffer);
924   if (bufsize - readpos < 256)
925     { 
926       /* Need more room for the read.  */
927       bufsize += 1024;
928       buffer = realloc (buffer, bufsize);
929       if (!buffer) 
930         return GPGME_Out_Of_Core;
931     }
932
933   nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
934   if (nread == -1)
935     return GPGME_Read_Error;
936
937   if (!nread)
938     {
939       gpg->colon.eof = 1;
940       assert (gpg->colon.fnc);
941       gpg->colon.fnc (gpg->colon.fnc_value, NULL);
942       return 0;
943     }
944
945   while (nread > 0)
946     {
947       for (p = buffer + readpos; nread; nread--, p++)
948         {
949           if ( *p == '\n' )
950             {
951               /* (we require that the last line is terminated by a LF)
952                  and we skip empty lines.  Note: we use UTF8 encoding
953                  and escaping of special characters We require at
954                  least one colon to cope with some other printed
955                  information.  */
956               *p = 0;
957               if (*buffer && strchr (buffer, ':'))
958                 {
959                   assert (gpg->colon.fnc);
960                   gpg->colon.fnc (gpg->colon.fnc_value, buffer);
961                 }
962             
963               /* To reuse the buffer for the next line we have to
964                  shift the remaining data to the buffer start and
965                  restart the loop Hmmm: We can optimize this function
966                  by looking forward in the buffer to see whether a
967                  second complete line is available and in this case
968                  avoid the memmove for this line.  */
969               nread--; p++;
970               if (nread)
971                 memmove (buffer, p, nread);
972               readpos = 0;
973               break; /* The for loop.  */
974             }
975           else
976             readpos++;
977         }
978     } 
979
980   /* Update the gpg object.  */
981   gpg->colon.bufsize = bufsize;
982   gpg->colon.buffer  = buffer;
983   gpg->colon.readpos = readpos;
984   return 0;
985 }
986
987
988 /* This colonline handler thing is not the clean way to do it.  It
989    might be better to enhance the gpgme_data_t object to act as a wrapper
990    for a callback.  Same goes for the status thing.  For now we use
991    this thing here because it is easier to implement.  */
992 static gpgme_error_t
993 colon_line_handler (void *opaque, int fd)
994 {
995   GpgObject gpg = opaque;
996   gpgme_error_t rc = 0;
997
998   assert (fd == gpg->colon.fd[0]);
999   rc = read_colon_line (gpg);
1000   if (rc)
1001     return rc;
1002   if (gpg->colon.eof)
1003     _gpgme_io_close (fd);
1004   return 0;
1005 }
1006
1007
1008 static gpgme_error_t
1009 start (GpgObject gpg)
1010 {
1011   gpgme_error_t rc;
1012   int i, n;
1013   int status;
1014   struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
1015
1016   if (!gpg)
1017     return GPGME_Invalid_Value;
1018
1019   if (! _gpgme_get_gpg_path ())
1020     return GPGME_Invalid_Engine;
1021
1022   /* Kludge, so that we don't need to check the return code of all the
1023      add_arg ().  We bail out here instead.  */
1024   if (gpg->arg_error)
1025     return GPGME_Out_Of_Core;
1026
1027   rc = build_argv (gpg);
1028   if (rc)
1029     return rc;
1030
1031   n = 3; /* status_fd, colon_fd and end of list */
1032   for (i = 0; gpg->fd_data_map[i].data; i++) 
1033     n++;
1034   fd_child_list = calloc (n + n, sizeof *fd_child_list);
1035   if (!fd_child_list)
1036     return GPGME_Out_Of_Core;
1037   fd_parent_list = fd_child_list + n;
1038
1039   /* build the fd list for the child */
1040   n = 0;
1041   if (gpg->colon.fnc)
1042     {
1043       fd_child_list[n].fd = gpg->colon.fd[1]; 
1044       fd_child_list[n].dup_to = 1; /* dup to stdout */
1045       n++;
1046     }
1047   for (i = 0; gpg->fd_data_map[i].data; i++)
1048     {
1049       if (gpg->fd_data_map[i].dup_to != -1)
1050         {
1051           fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
1052           fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
1053           n++;
1054         }
1055     }
1056   fd_child_list[n].fd = -1;
1057   fd_child_list[n].dup_to = -1;
1058
1059   /* Build the fd list for the parent.  */
1060   n = 0;
1061   if (gpg->status.fd[1] != -1)
1062     {
1063       fd_parent_list[n].fd = gpg->status.fd[1];
1064       fd_parent_list[n].dup_to = -1;
1065       n++;
1066     }
1067   if (gpg->colon.fd[1] != -1)
1068     {
1069       fd_parent_list[n].fd = gpg->colon.fd[1];
1070       fd_parent_list[n].dup_to = -1;
1071       n++;
1072     }
1073   for (i = 0; gpg->fd_data_map[i].data; i++)
1074     {
1075       fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
1076       fd_parent_list[n].dup_to = -1;
1077       n++;
1078     }        
1079   fd_parent_list[n].fd = -1;
1080   fd_parent_list[n].dup_to = -1;
1081
1082   status = _gpgme_io_spawn (_gpgme_get_gpg_path (),
1083                             gpg->argv, fd_child_list, fd_parent_list);
1084   free (fd_child_list);
1085   if (status == -1)
1086     return GPGME_Exec_Error;
1087
1088   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
1089
1090   rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
1091                   &gpg->status.tag);
1092   if (rc)
1093     /* FIXME: kill the child */
1094     return rc;
1095
1096   if (gpg->colon.fnc)
1097     {
1098       assert (gpg->colon.fd[0] != -1);
1099       rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
1100                       &gpg->colon.tag);
1101       if (rc)
1102         /* FIXME: kill the child */
1103         return rc;
1104     }
1105
1106   for (i = 0; gpg->fd_data_map[i].data; i++)
1107     {
1108       if (gpg->cmd.used && i == gpg->cmd.idx)
1109         {
1110           /* Park the cmd fd.  */
1111           gpg->cmd.fd = gpg->fd_data_map[i].fd;
1112           gpg->fd_data_map[i].fd = -1;
1113         }
1114       else
1115         {
1116           rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
1117                           gpg->fd_data_map[i].inbound,
1118                           gpg->fd_data_map[i].inbound
1119                           ? _gpgme_data_inbound_handler
1120                           : _gpgme_data_outbound_handler,
1121                           gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
1122           
1123           if (rc)
1124             /* FIXME: kill the child */
1125             return rc;
1126         }
1127     }
1128
1129   (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_START, NULL);
1130   
1131   /* fixme: check what data we can release here */
1132   return 0;
1133 }
1134
1135
1136 static gpgme_error_t
1137 gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1138 {
1139   GpgObject gpg = engine;
1140   gpgme_error_t err;
1141
1142   err = add_arg (gpg, "--decrypt");
1143
1144   /* Tell the gpg object about the data.  */
1145   if (!err)
1146     err = add_arg (gpg, "--output");
1147   if (!err)
1148     err = add_arg (gpg, "-");
1149   if (!err)
1150     err = add_data (gpg, plain, 1, 1);
1151   if (!err)
1152     err = add_data (gpg, ciph, 0, 0);
1153
1154   if (!err)
1155     start (gpg);
1156   return err;
1157 }
1158
1159 static gpgme_error_t
1160 gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
1161 {
1162   GpgObject gpg = engine;
1163   gpgme_error_t err;
1164
1165   err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
1166                  : "--delete-key");
1167   if (!err)
1168     err = add_arg (gpg, "--");
1169   if (!err)
1170     {
1171       if (!key->subkeys || !key->subkeys->fpr)
1172         err = GPGME_Invalid_Key;
1173       else
1174         err = add_arg (gpg, key->subkeys->fpr);
1175     }
1176
1177   if (!err)
1178     start (gpg);
1179   return err;
1180 }
1181
1182
1183 static gpgme_error_t
1184 append_args_from_signers (GpgObject gpg, gpgme_ctx_t ctx /* FIXME */)
1185 {
1186   gpgme_error_t err = 0;
1187   int i;
1188   gpgme_key_t key;
1189
1190   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1191     {
1192       const char *s = key->subkeys ? key->subkeys->keyid : NULL;
1193       if (s)
1194         {
1195           if (!err)
1196             err = add_arg (gpg, "-u");
1197           if (!err)
1198             err = add_arg (gpg, s);
1199         }
1200       gpgme_key_unref (key);
1201       if (err) break;
1202     }
1203   return err;
1204 }
1205
1206
1207 static gpgme_error_t
1208 gpg_edit (void *engine, gpgme_key_t key, gpgme_data_t out,
1209           gpgme_ctx_t ctx /* FIXME */)
1210 {
1211   GpgObject gpg = engine;
1212   gpgme_error_t err;
1213
1214   err = add_arg (gpg, "--with-colons");
1215   if (!err)
1216     err = append_args_from_signers (gpg, ctx);
1217   if (!err)
1218   err = add_arg (gpg, "--edit-key");
1219   if (!err)
1220     err = add_data (gpg, out, 1, 1);
1221   if (!err)
1222     err = add_arg (gpg, "--");
1223   if (!err)
1224     {
1225       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1226       if (!s)
1227         err = GPGME_Invalid_Key;
1228       else
1229         err = add_arg (gpg, s);
1230     }
1231   if (!err)
1232     err = start (gpg);
1233
1234   return err;
1235 }
1236
1237
1238 static gpgme_error_t
1239 append_args_from_recipients (GpgObject gpg, gpgme_user_id_t uid)
1240 {
1241   gpgme_error_t err = 0;
1242
1243   while (uid)
1244     {
1245       err = add_arg (gpg, "-r");
1246       if (!err)
1247         err = add_arg (gpg, uid->uid);
1248       if (err)
1249         break;
1250       uid = uid->next;
1251     }    
1252   return err;
1253 }
1254
1255
1256 static gpgme_error_t
1257 gpg_encrypt (void *engine, gpgme_user_id_t recp, gpgme_data_t plain,
1258              gpgme_data_t ciph, int use_armor)
1259 {
1260   GpgObject gpg = engine;
1261   gpgme_error_t err;
1262   int symmetric = !recp;
1263
1264   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1265
1266   if (!err && use_armor)
1267     err = add_arg (gpg, "--armor");
1268
1269   if (!symmetric)
1270     {
1271       /* If we know that all recipients are valid (full or ultimate trust)
1272          we can suppress further checks.  */
1273       if (!err && !symmetric && _gpgme_user_ids_all_valid (recp))
1274         err = add_arg (gpg, "--always-trust");
1275
1276       if (!err)
1277         err = append_args_from_recipients (gpg, recp);
1278     }
1279
1280   /* Tell the gpg object about the data.  */
1281   if (!err)
1282     err = add_arg (gpg, "--output");
1283   if (!err)
1284     err = add_arg (gpg, "-");
1285   if (!err)
1286     err = add_data (gpg, ciph, 1, 1);
1287   if (!err)
1288     err = add_arg (gpg, "--");
1289   if (!err)
1290     err = add_data (gpg, plain, 0, 0);
1291
1292   if (!err)
1293     err = start (gpg);
1294
1295   return err;
1296 }
1297
1298
1299 static gpgme_error_t
1300 gpg_encrypt_sign (void *engine, gpgme_user_id_t recp, gpgme_data_t plain,
1301                   gpgme_data_t ciph, int use_armor,
1302                   gpgme_ctx_t ctx /* FIXME */)
1303 {
1304   GpgObject gpg = engine;
1305   gpgme_error_t err;
1306
1307   err = add_arg (gpg, "--encrypt");
1308   if (!err)
1309     err = add_arg (gpg, "--sign");
1310   if (!err && use_armor)
1311     err = add_arg (gpg, "--armor");
1312
1313   /* If we know that all recipients are valid (full or ultimate trust)
1314    * we can suppress further checks */
1315   if (!err && _gpgme_user_ids_all_valid (recp))
1316     err = add_arg (gpg, "--always-trust");
1317
1318   if (!err)
1319     err = append_args_from_recipients (gpg, recp);
1320
1321   if (!err)
1322     err = append_args_from_signers (gpg, ctx);
1323
1324   /* Tell the gpg object about the data.  */
1325   if (!err)
1326     err = add_arg (gpg, "--output");
1327   if (!err)
1328     err = add_arg (gpg, "-");
1329   if (!err)
1330     err = add_data (gpg, ciph, 1, 1);
1331   if (!err)
1332     err = add_arg (gpg, "--");
1333   if (!err)
1334     err = add_data (gpg, plain, 0, 0);
1335
1336   if (!err)
1337     err = start (gpg);
1338
1339   return err;
1340 }
1341
1342
1343 static gpgme_error_t
1344 gpg_export (void *engine, gpgme_user_id_t uids, gpgme_data_t keydata,
1345             int use_armor)
1346 {
1347   GpgObject gpg = engine;
1348   gpgme_error_t err;
1349
1350   err = add_arg (gpg, "--export");
1351   if (!err && use_armor)
1352     err = add_arg (gpg, "--armor");
1353   if (!err)
1354     err = add_data (gpg, keydata, 1, 1);
1355   if (!err)
1356     err = add_arg (gpg, "--");
1357
1358   while (!err && uids)
1359     {
1360       err = add_arg (gpg, uids->uid);
1361       uids = uids->next;
1362     }
1363
1364   if (!err)
1365     err = start (gpg);
1366
1367   return err;
1368 }
1369
1370
1371 static gpgme_error_t
1372 gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1373             gpgme_data_t pubkey, gpgme_data_t seckey)
1374 {
1375   GpgObject gpg = engine;
1376   gpgme_error_t err;
1377
1378   if (!gpg)
1379     return GPGME_Invalid_Value;
1380
1381   /* We need a special mechanism to get the fd of a pipe here, so that
1382      we can use this for the %pubring and %secring parameters.  We
1383      don't have this yet, so we implement only the adding to the
1384      standard keyrings.  */
1385   if (pubkey || seckey)
1386     return err = GPGME_Not_Implemented;
1387
1388   err = add_arg (gpg, "--gen-key");
1389   if (!err && use_armor)
1390     err = add_arg (gpg, "--armor");
1391   if (!err)
1392     err = add_data (gpg, help_data, 0, 0);
1393
1394   if (!err)
1395     err = start (gpg);
1396
1397   return err;
1398 }
1399
1400
1401 static gpgme_error_t
1402 gpg_import (void *engine, gpgme_data_t keydata)
1403 {
1404   GpgObject gpg = engine;
1405   gpgme_error_t err;
1406
1407   err = add_arg (gpg, "--import");
1408   if (!err)
1409     err = add_data (gpg, keydata, 0, 0);
1410
1411   if (!err)
1412     err = start (gpg);
1413
1414   return err;
1415 }
1416
1417
1418 static gpgme_error_t
1419 gpg_keylist (void *engine, const char *pattern, int secret_only,
1420              int keylist_mode)
1421 {
1422   GpgObject gpg = engine;
1423   gpgme_error_t err;
1424
1425   err = add_arg (gpg, "--with-colons");
1426   if (!err)
1427     err = add_arg (gpg, "--fixed-list-mode");
1428   if (!err)
1429     err = add_arg (gpg, "--with-fingerprint");
1430   if (!err)
1431     err = add_arg (gpg, "--with-fingerprint");
1432   if (!err)
1433     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1434                    : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1435                       ? "--check-sigs" : "--list-keys"));
1436   
1437   /* Tell the gpg object about the data.  */
1438   if (!err)
1439     err = add_arg (gpg, "--");
1440   if (!err && pattern && *pattern)
1441     err = add_arg (gpg, pattern);
1442
1443   if (!err)
1444     err = start (gpg);
1445
1446   return err;
1447 }
1448
1449
1450 static gpgme_error_t
1451 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
1452                  int reserved, int keylist_mode)
1453 {
1454   GpgObject gpg = engine;
1455   gpgme_error_t err;
1456
1457   if (reserved)
1458     return GPGME_Invalid_Value;
1459
1460   err = add_arg (gpg, "--with-colons");
1461   if (!err)
1462     err = add_arg (gpg, "--fixed-list-mode");
1463   if (!err)
1464     err = add_arg (gpg, "--with-fingerprint");
1465   if (!err)
1466     err = add_arg (gpg, "--with-fingerprint");
1467   if (!err)
1468     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1469                    : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1470                       ? "--check-sigs" : "--list-keys"));
1471
1472   /* Tell the gpg object about the data.  */
1473   if (!err)
1474     err = add_arg (gpg, "--");
1475   if (!err && pattern && *pattern)
1476     {
1477       while (*pattern && **pattern)
1478         err = add_arg (gpg, *(pattern++));
1479     }
1480
1481   if (!err)
1482     err = start (gpg);
1483
1484   return err;
1485 }
1486
1487
1488 static gpgme_error_t
1489 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1490           gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1491           int include_certs, gpgme_ctx_t ctx /* FIXME */)
1492 {
1493   GpgObject gpg = engine;
1494   gpgme_error_t err;
1495
1496   if (mode == GPGME_SIG_MODE_CLEAR)
1497     err = add_arg (gpg, "--clearsign");
1498   else
1499     {
1500       err = add_arg (gpg, "--sign");
1501       if (!err && mode == GPGME_SIG_MODE_DETACH)
1502         err = add_arg (gpg, "--detach");
1503       if (!err && use_armor)
1504         err = add_arg (gpg, "--armor");
1505       if (!err && use_textmode)
1506         add_arg (gpg, "--textmode");
1507     }
1508
1509   if (!err)
1510     err = append_args_from_signers (gpg, ctx);
1511
1512   /* Tell the gpg object about the data.  */
1513   if (!err)
1514     err = add_data (gpg, in, 0, 0);
1515   if (!err)
1516     err = add_data (gpg, out, 1, 1);
1517
1518   if (!err)
1519     start (gpg);
1520
1521   return err;
1522 }
1523
1524 static gpgme_error_t
1525 gpg_trustlist (void *engine, const char *pattern)
1526 {
1527   GpgObject gpg = engine;
1528   gpgme_error_t err;
1529
1530   err = add_arg (gpg, "--with-colons");
1531   if (!err)
1532     err = add_arg (gpg, "--list-trust-path");
1533   
1534   /* Tell the gpg object about the data.  */
1535   if (!err)
1536     err = add_arg (gpg, "--");
1537   if (!err)
1538     err = add_arg (gpg, pattern);
1539
1540   if (!err)
1541     err = start (gpg);
1542
1543   return err;
1544 }
1545
1546
1547 static gpgme_error_t
1548 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1549             gpgme_data_t plaintext)
1550 {
1551   GpgObject gpg = engine;
1552   gpgme_error_t err = 0;
1553
1554   if (plaintext)
1555     {
1556       /* Normal or cleartext signature.  */
1557
1558       err = add_arg (gpg, "--output");
1559       if (!err)
1560         err = add_arg (gpg, "-");
1561       if (!err)
1562         err = add_arg (gpg, "--");
1563       if (!err)
1564         err = add_data (gpg, sig, 0, 0);
1565       if (!err)
1566         err = add_data (gpg, plaintext, 1, 1);
1567     }
1568   else
1569     {
1570       err = add_arg (gpg, "--verify");
1571       if (!err)
1572         err = add_arg (gpg, "--");
1573       if (!err)
1574         err = add_data (gpg, sig, -1, 0);
1575       if (signed_text)
1576         {
1577           if (!err)
1578             err = add_arg (gpg, "-");
1579           if (!err)
1580             err = add_data (gpg, signed_text, 0, 0);
1581         }
1582     }
1583
1584   if (!err)
1585     err = start (gpg);
1586
1587   return err;
1588 }
1589
1590
1591 static void
1592 gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1593 {
1594   GpgObject gpg = engine;
1595
1596   gpg->io_cbs = *io_cbs;
1597 }
1598
1599 \f
1600 struct engine_ops _gpgme_engine_ops_gpg =
1601   {
1602     /* Static functions.  */
1603     _gpgme_get_gpg_path,
1604     gpg_get_version,
1605     gpg_get_req_version,
1606     gpg_new,
1607
1608     /* Member functions.  */
1609     gpg_release,
1610     gpg_set_status_handler,
1611     gpg_set_command_handler,
1612     gpg_set_colon_line_handler,
1613     gpg_decrypt,
1614     gpg_delete,
1615     gpg_edit,
1616     gpg_encrypt,
1617     gpg_encrypt_sign,
1618     gpg_export,
1619     gpg_genkey,
1620     gpg_import,
1621     gpg_keylist,
1622     gpg_keylist_ext,
1623     gpg_sign,
1624     gpg_trustlist,
1625     gpg_verify,
1626     gpg_set_io_cbs,
1627     gpg_io_event
1628   };