ab1372662fcfbae2b17ce6e1c523562164b46b34
[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   GpgmeData 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   GpgmeData 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     EngineStatusHandler 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     EngineColonLineHandler 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     int idx;            /* Index in fd_data_map */
113     GpgmeData cb_data;   /* hack to get init the above idx later */
114     GpgmeStatusCode code;  /* last code */
115     char *keyword;       /* what has been requested (malloced) */
116     EngineCommandHandler 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     GpgmeData linked_data;
121     int linked_idx;
122   } cmd;
123
124   struct GpgmeIOCbs io_cbs;
125 };
126
127 typedef struct gpg_object_s *GpgObject;
128
129 \f
130 static void
131 gpg_io_event (void *engine, GpgmeEventIO 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 GpgmeError
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 GpgmeError
208 add_data (GpgObject gpg, GpgmeData 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       free (gpg->arglist);
305       gpg->arglist = next;
306     }
307
308   free (gpg->status.buffer);
309   free (gpg->colon.buffer);
310   if (gpg->argv)
311     free_argv (gpg->argv);
312   gpgme_data_release (gpg->cmd.cb_data);
313   free (gpg->cmd.keyword);
314
315   if (gpg->status.fd[0] != -1)
316     _gpgme_io_close (gpg->status.fd[0]);
317   if (gpg->status.fd[1] != -1)
318     _gpgme_io_close (gpg->status.fd[1]);
319   if (gpg->colon.fd[0] != -1)
320     _gpgme_io_close (gpg->colon.fd[0]);
321   if (gpg->colon.fd[1] != -1)
322     _gpgme_io_close (gpg->colon.fd[1]);
323   free_fd_data_map (gpg->fd_data_map);
324   if (gpg->cmd.fd != -1)
325     _gpgme_io_close (gpg->cmd.fd);
326   free (gpg);
327 }
328
329
330 static GpgmeError
331 gpg_new (void **engine)
332 {
333   GpgObject gpg;
334   int rc = 0;
335
336   gpg = calloc (1, sizeof *gpg);
337   if (!gpg)
338     {
339       rc = GPGME_Out_Of_Core;
340       goto leave;
341     }
342   gpg->argtail = &gpg->arglist;
343
344   gpg->status.fd[0] = -1;
345   gpg->status.fd[1] = -1;
346   gpg->colon.fd[0] = -1;
347   gpg->colon.fd[1] = -1;
348   gpg->cmd.fd = -1;
349   gpg->cmd.idx = -1;
350   gpg->cmd.linked_data = NULL;
351   gpg->cmd.linked_idx = -1;
352
353   /* Allocate the read buffer for the status pipe.  */
354   gpg->status.bufsize = 1024;
355   gpg->status.readpos = 0;
356   gpg->status.buffer = malloc (gpg->status.bufsize);
357   if (!gpg->status.buffer)
358     {
359       rc = GPGME_Out_Of_Core;
360       goto leave;
361     }
362   /* In any case we need a status pipe - create it right here and
363      don't handle it with our generic GpgmeData mechanism.  */
364   if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
365     {
366       rc = GPGME_Pipe_Error;
367       goto leave;
368     }
369   if (_gpgme_io_set_close_notify (gpg->status.fd[0],
370                                   close_notify_handler, gpg)
371       || _gpgme_io_set_close_notify (gpg->status.fd[1],
372                                      close_notify_handler, gpg))
373     {
374       rc = GPGME_General_Error;
375       goto leave;
376     }
377   gpg->status.eof = 0;
378   add_arg (gpg, "--status-fd");
379   {
380     char buf[25];
381     sprintf (buf, "%d", gpg->status.fd[1]);
382     add_arg (gpg, buf);
383   }
384   add_arg (gpg, "--no-tty");
385   add_arg (gpg, "--charset");
386   add_arg (gpg, "utf8");
387
388  leave:
389   if (rc)
390     gpg_release (gpg);
391   else
392     *engine = gpg;
393   return rc;
394 }
395
396
397 /* Note, that the status_handler is allowed to modifiy the args
398    value.  */
399 static void
400 gpg_set_status_handler (void *engine, EngineStatusHandler fnc, void *fnc_value)
401 {
402   GpgObject gpg = engine;
403
404   gpg->status.fnc = fnc;
405   gpg->status.fnc_value = fnc_value;
406 }
407
408 /* Kludge to process --with-colon output.  */
409 static GpgmeError
410 gpg_set_colon_line_handler (void *engine, EngineColonLineHandler fnc,
411                             void *fnc_value)
412 {
413   GpgObject gpg = engine;
414
415   gpg->colon.bufsize = 1024;
416   gpg->colon.readpos = 0;
417   gpg->colon.buffer = malloc (gpg->colon.bufsize);
418   if (!gpg->colon.buffer)
419     return GPGME_Out_Of_Core;
420
421   if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) 
422     {
423       free (gpg->colon.buffer);
424       gpg->colon.buffer = NULL;
425       return GPGME_Pipe_Error;
426     }
427   if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
428       || _gpgme_io_set_close_notify (gpg->colon.fd[1],
429                                      close_notify_handler, gpg))
430     return GPGME_General_Error;
431   gpg->colon.eof = 0;
432   gpg->colon.fnc = fnc;
433   gpg->colon.fnc_value = fnc_value;
434   return 0;
435 }
436
437
438 /* Here we handle --command-fd.  This works closely together with the
439    status handler.  */
440 static GpgmeError
441 command_cb (void *opaque, char *buffer, size_t length, size_t *nread)
442 {
443   GpgmeError err;
444   GpgObject gpg = opaque;
445   const char *value;
446   int value_len;
447
448   DEBUG0 ("command_cb: enter\n");
449   assert (gpg->cmd.used);
450   if (!buffer || !length || !nread)
451     return 0; /* These values are reserved for extensions.  */
452   *nread = 0;
453   if (!gpg->cmd.code)
454     {
455       DEBUG0 ("command_cb: no code\n");
456       return -1;
457     }
458     
459   if (!gpg->cmd.fnc)
460     {
461       DEBUG0 ("command_cb: no user cb\n");
462       return -1;
463     }
464
465   /* FIXME catch error */
466   err = gpg->cmd.fnc (gpg->cmd.fnc_value, 
467                       gpg->cmd.code, gpg->cmd.keyword, &value);
468   if (err)
469     return err;
470
471   if (!value)
472     {
473       DEBUG0 ("command_cb: no data from user cb\n");
474       gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
475       return -1;
476     }
477
478   value_len = strlen (value);
479   if (value_len + 1 > length)
480     {
481       DEBUG0 ("command_cb: too much data from user cb\n");
482       gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
483       return -1;
484     }
485
486   memcpy (buffer, value, value_len);
487   if (!value_len || (value_len && value[value_len-1] != '\n')) 
488     buffer[value_len++] = '\n';
489   *nread = value_len;
490     
491   gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
492   gpg->cmd.code = 0;
493   /* And sleep again until read_status will wake us up again.  */
494   /* XXX We must check if there are any more fds active after removing
495      this one.  */
496   (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
497   gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
498   gpg->fd_data_map[gpg->cmd.idx].fd = -1;
499
500   return 0;
501 }
502
503
504 /* The Fnc will be called to get a value for one of the commands with
505    a key KEY.  If the Code pssed to FNC is 0, the function may release
506    resources associated with the returned value from another call.  To
507    match such a second call to a first call, the returned value from
508    the first call is passed as keyword.  */
509 static GpgmeError
510 gpg_set_command_handler (void *engine, EngineCommandHandler fnc,
511                          void *fnc_value, GpgmeData linked_data)
512 {
513   GpgObject gpg = engine;
514   GpgmeData tmp;
515   GpgmeError err;
516
517   err = gpgme_data_new_with_read_cb (&tmp, command_cb, gpg);
518   if (err)
519     return err;
520         
521   add_arg (gpg, "--command-fd");
522   add_data (gpg, tmp, -2, 0);
523   gpg->cmd.cb_data = tmp;
524   gpg->cmd.fnc = fnc;
525   gpg->cmd.fnc_value = fnc_value;
526   gpg->cmd.linked_data = linked_data;
527   gpg->cmd.used = 1;
528   return 0;
529 }
530
531
532 static GpgmeError
533 build_argv (GpgObject gpg)
534 {
535   struct arg_and_data_s *a;
536   struct fd_data_map_s *fd_data_map;
537   size_t datac=0, argc=0;  
538   char **argv;
539   int need_special = 0;
540   int use_agent = 0;
541   char *p;
542
543   /* We don't want to use the agent with a malformed environment
544      variable.  This is only a very basic test but sufficient to make
545      our life in the regression tests easier. */
546   p = getenv ("GPG_AGENT_INFO");
547   use_agent = (p && strchr (p, ':'));
548        
549   if (gpg->argv)
550     {
551       free_argv (gpg->argv);
552       gpg->argv = NULL;
553     }
554   if (gpg->fd_data_map)
555     {
556       free_fd_data_map (gpg->fd_data_map);
557       gpg->fd_data_map = NULL;
558     }
559
560   argc++;       /* For argv[0].  */
561   for (a = gpg->arglist; a; a = a->next)
562     {
563       argc++;
564       if (a->data)
565         {
566           /*fprintf (stderr, "build_argv: data\n" );*/
567           datac++;
568           if (a->dup_to == -1 && !a->print_fd)
569             need_special = 1;
570         }
571       else
572         {
573           /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
574         }
575     }
576   if (need_special)
577     argc++;
578   if (use_agent)
579     argc++;
580   if (!gpg->cmd.used)
581     argc++;
582   argc += 2; /* --comment */
583
584   argv = calloc (argc + 1, sizeof *argv);
585   if (!argv)
586     return GPGME_Out_Of_Core;
587   fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
588   if (!fd_data_map)
589     {
590       free_argv (argv);
591       return GPGME_Out_Of_Core;
592     }
593
594   argc = datac = 0;
595   argv[argc] = strdup ("gpg"); /* argv[0] */
596   if (!argv[argc])
597     {
598       free (fd_data_map);
599       free_argv (argv);
600       return GPGME_Out_Of_Core;
601     }
602   argc++;
603   if (need_special)
604     {
605       argv[argc] = strdup ("--enable-special-filenames");
606       if (!argv[argc])
607         {
608           free (fd_data_map);
609           free_argv (argv);
610           return GPGME_Out_Of_Core;
611         }
612       argc++;
613     }
614   if (use_agent)
615     {
616       argv[argc] = strdup ("--use-agent");
617       if (!argv[argc])
618         {
619           free (fd_data_map);
620           free_argv (argv);
621           return GPGME_Out_Of_Core;
622         }
623       argc++;
624     }
625   if (!gpg->cmd.used)
626     {
627       argv[argc] = strdup ("--batch");
628       if (!argv[argc])
629         {
630           free (fd_data_map);
631           free_argv (argv);
632           return GPGME_Out_Of_Core;
633         }
634       argc++;
635     }
636   argv[argc] = strdup ("--comment");
637   if (!argv[argc])
638     {
639       free (fd_data_map);
640       free_argv (argv);
641       return GPGME_Out_Of_Core;
642     }
643   argc++;
644   argv[argc] = strdup ("");
645   if (!argv[argc])
646     {
647       free (fd_data_map);
648       free_argv (argv);
649       return GPGME_Out_Of_Core;
650     }
651   argc++;
652   for (a = gpg->arglist; a; a = a->next)
653     {
654       if (a->data)
655         {
656           /* Create a pipe to pass it down to gpg.  */
657           fd_data_map[datac].inbound = a->inbound;
658
659           /* Create a pipe.  */
660           {   
661             int fds[2];
662             
663             if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
664                 == -1)
665               {
666                 free (fd_data_map);
667                 free_argv (argv);
668                 return GPGME_Pipe_Error;
669               }
670             if (_gpgme_io_set_close_notify (fds[0],
671                                             close_notify_handler, gpg)
672                 || _gpgme_io_set_close_notify (fds[1],
673                                                close_notify_handler,
674                                                gpg))
675               {
676                 return GPGME_General_Error;
677               }
678             /* If the data_type is FD, we have to do a dup2 here.  */
679             if (fd_data_map[datac].inbound)
680               {
681                 fd_data_map[datac].fd       = fds[0];
682                 fd_data_map[datac].peer_fd  = fds[1];
683               }
684             else
685               {
686                 fd_data_map[datac].fd       = fds[1];
687                 fd_data_map[datac].peer_fd  = fds[0];
688               }
689           }
690
691           /* Hack to get hands on the fd later.  */
692           if (gpg->cmd.used)
693             {
694               if (gpg->cmd.cb_data == a->data)
695                 {
696                   assert (gpg->cmd.idx == -1);
697                   gpg->cmd.idx = datac;
698                 }
699               else if (gpg->cmd.linked_data == a->data)
700                 {
701                   assert (gpg->cmd.linked_idx == -1);
702                   gpg->cmd.linked_idx = datac;
703                 }
704             }
705
706           fd_data_map[datac].data = a->data;
707           fd_data_map[datac].dup_to = a->dup_to;
708           if (a->dup_to == -1)
709             {
710               argv[argc] = malloc (25);
711               if (!argv[argc])
712                 {
713                   free (fd_data_map);
714                   free_argv (argv);
715                   return GPGME_Out_Of_Core;
716                 }
717               sprintf (argv[argc], 
718                        a->print_fd ? "%d" : "-&%d",
719                        fd_data_map[datac].peer_fd);
720               argc++;
721             }
722           datac++;
723         }
724       else
725         {
726           argv[argc] = strdup (a->arg);
727           if (!argv[argc])
728             {
729               free (fd_data_map);
730               free_argv (argv);
731               return GPGME_Out_Of_Core;
732             }
733             argc++;
734         }
735     }
736
737   gpg->argv = argv;
738   gpg->fd_data_map = fd_data_map;
739   return 0;
740 }
741
742
743 static GpgmeError
744 add_io_cb (GpgObject gpg, int fd, int dir, GpgmeIOCb handler, void *data,
745            void **tag)
746 {
747   GpgmeError err;
748
749   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
750   if (err)
751     return err;
752   if (!dir)
753     /* FIXME Kludge around poll() problem.  */
754     err = _gpgme_io_set_nonblocking (fd);
755   return err;
756 }
757
758
759 static int
760 status_cmp (const void *ap, const void *bp)
761 {
762   const struct status_table_s *a = ap;
763   const struct status_table_s *b = bp;
764
765   return strcmp (a->name, b->name);
766 }
767
768
769 /* Handle the status output of GnuPG.  This function does read entire
770    lines and passes them as C strings to the callback function (we can
771    use C Strings because the status output is always UTF-8 encoded).
772    Of course we have to buffer the lines to cope with long lines
773    e.g. with a large user ID.  Note: We can optimize this to only cope
774    with status line code we know about and skip all other stuff
775    without buffering (i.e. without extending the buffer).  */
776 static GpgmeError
777 read_status (GpgObject gpg)
778 {
779   char *p;
780   int nread;
781   size_t bufsize = gpg->status.bufsize; 
782   char *buffer = gpg->status.buffer;
783   size_t readpos = gpg->status.readpos; 
784
785   assert (buffer);
786   if (bufsize - readpos < 256)
787     { 
788       /* Need more room for the read.  */
789       bufsize += 1024;
790       buffer = realloc (buffer, bufsize);
791       if (!buffer)
792         return GPGME_Out_Of_Core;
793     }
794
795   nread = _gpgme_io_read (gpg->status.fd[0],
796                           buffer + readpos, bufsize-readpos);
797   if (nread == -1)
798     return GPGME_Read_Error;
799
800   if (!nread)
801     {
802       gpg->status.eof = 1;
803       if (gpg->status.fnc)
804         {
805           GpgmeError err;
806           err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
807           if (err)
808             return err;
809         }
810       return 0;
811     }
812
813   while (nread > 0)
814     {
815       for (p = buffer + readpos; nread; nread--, p++)
816         {
817           if (*p == '\n')
818             {
819               /* (we require that the last line is terminated by a LF) */
820               *p = 0;
821               if (!strncmp (buffer, "[GNUPG:] ", 9)
822                   && buffer[9] >= 'A' && buffer[9] <= 'Z')
823                 {
824                   struct status_table_s t, *r;
825                   char *rest;
826
827                   rest = strchr (buffer + 9, ' ');
828                   if (!rest)
829                     rest = p; /* Set to an empty string.  */
830                   else
831                     *rest++ = 0;
832                     
833                   t.name = buffer+9;
834                   /* (the status table has one extra element) */
835                   r = bsearch (&t, status_table, DIM(status_table) - 1,
836                                sizeof t, status_cmp);
837                   if (r)
838                     {
839                       if (gpg->cmd.used
840                           && (r->code == GPGME_STATUS_GET_BOOL
841                               || r->code == GPGME_STATUS_GET_LINE
842                               || r->code == GPGME_STATUS_GET_HIDDEN))
843                         {
844                           gpg->cmd.code = r->code;
845                           free (gpg->cmd.keyword);
846                           gpg->cmd.keyword = strdup (rest);
847                           if (!gpg->cmd.keyword)
848                             return GPGME_Out_Of_Core;
849                           /* This should be the last thing we have
850                              received and the next thing will be that
851                              the command handler does its action.  */
852                           if (nread > 1)
853                             DEBUG0 ("ERROR, unexpected data in read_status");
854
855                           /* Before we can actually add the command
856                              fd, we might have to flush the linked
857                              output data pipe.  */
858                           if (gpg->cmd.linked_idx != -1
859                               && gpg->fd_data_map[gpg->cmd.linked_idx].fd != -1)
860                             {
861                               struct io_select_fd_s fds;
862                               fds.fd = gpg->fd_data_map[gpg->cmd.linked_idx].fd;
863                               fds.for_read = 1;
864                               fds.for_write = 0;
865                               fds.frozen = 0;
866                               fds.opaque = NULL;
867                               do
868                                 {
869                                   fds.signaled = 0;
870                                   _gpgme_io_select (&fds, 1, 1);
871                                   if (fds.signaled)
872                                     _gpgme_data_inbound_handler
873                                       (gpg->cmd.linked_data, fds.fd);
874                                 }
875                               while (fds.signaled);
876                             }
877
878                           add_io_cb (gpg, gpg->cmd.fd, 0,
879                                      _gpgme_data_outbound_handler,
880                                      gpg->fd_data_map[gpg->cmd.idx].data,
881                                      &gpg->fd_data_map[gpg->cmd.idx].tag);
882                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
883                           gpg->cmd.fd = -1;
884                         }
885                       else if (gpg->status.fnc)
886                         {
887                           GpgmeError err;
888                           err = gpg->status.fnc (gpg->status.fnc_value, 
889                                                  r->code, rest);
890                           if (err)
891                             return err;
892                         }
893                     
894                       if (r->code == GPGME_STATUS_END_STREAM)
895                         {
896                           if (gpg->cmd.used)
897                             {
898                               /* XXX We must check if there are any
899                                  more fds active after removing this
900                                  one.  */
901                               (*gpg->io_cbs.remove)
902                                 (gpg->fd_data_map[gpg->cmd.idx].tag);
903                               gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
904                               gpg->fd_data_map[gpg->cmd.idx].fd = -1;
905                             }
906                         }
907                     }
908                 }
909               /* To reuse the buffer for the next line we have to
910                  shift the remaining data to the buffer start and
911                  restart the loop Hmmm: We can optimize this function
912                  by looking forward in the buffer to see whether a
913                  second complete line is available and in this case
914                  avoid the memmove for this line.  */
915               nread--; p++;
916               if (nread)
917                 memmove (buffer, p, nread);
918               readpos = 0;
919               break; /* the for loop */
920             }
921           else
922             readpos++;
923         }
924     } 
925
926   /* Update the gpg object.  */
927   gpg->status.bufsize = bufsize;
928   gpg->status.buffer = buffer;
929   gpg->status.readpos = readpos;
930   return 0;
931 }
932
933
934 static GpgmeError
935 status_handler (void *opaque, int fd)
936 {
937   GpgObject gpg = opaque;
938   int err;
939
940   assert (fd == gpg->status.fd[0]);
941   err = read_status (gpg);
942   if (err)
943     return err;
944   if (gpg->status.eof)
945     _gpgme_io_close (fd);
946   return 0;
947 }
948
949
950 static GpgmeError
951 read_colon_line (GpgObject gpg)
952 {
953   char *p;
954   int nread;
955   size_t bufsize = gpg->colon.bufsize; 
956   char *buffer = gpg->colon.buffer;
957   size_t readpos = gpg->colon.readpos; 
958
959   assert (buffer);
960   if (bufsize - readpos < 256)
961     { 
962       /* Need more room for the read.  */
963       bufsize += 1024;
964       buffer = realloc (buffer, bufsize);
965       if (!buffer) 
966         return GPGME_Out_Of_Core;
967     }
968
969   nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
970   if (nread == -1)
971     return GPGME_Read_Error;
972
973   if (!nread)
974     {
975       gpg->colon.eof = 1;
976       assert (gpg->colon.fnc);
977       gpg->colon.fnc (gpg->colon.fnc_value, NULL);
978       return 0;
979     }
980
981   while (nread > 0)
982     {
983       for (p = buffer + readpos; nread; nread--, p++)
984         {
985           if ( *p == '\n' )
986             {
987               /* (we require that the last line is terminated by a LF)
988                  and we skip empty lines.  Note: we use UTF8 encoding
989                  and escaping of special characters We require at
990                  least one colon to cope with some other printed
991                  information.  */
992               *p = 0;
993               if (*buffer && strchr (buffer, ':'))
994                 {
995                   assert (gpg->colon.fnc);
996                   gpg->colon.fnc (gpg->colon.fnc_value, buffer);
997                 }
998             
999               /* To reuse the buffer for the next line we have to
1000                  shift the remaining data to the buffer start and
1001                  restart the loop Hmmm: We can optimize this function
1002                  by looking forward in the buffer to see whether a
1003                  second complete line is available and in this case
1004                  avoid the memmove for this line.  */
1005               nread--; p++;
1006               if (nread)
1007                 memmove (buffer, p, nread);
1008               readpos = 0;
1009               break; /* The for loop.  */
1010             }
1011           else
1012             readpos++;
1013         }
1014     } 
1015
1016   /* Update the gpg object.  */
1017   gpg->colon.bufsize = bufsize;
1018   gpg->colon.buffer  = buffer;
1019   gpg->colon.readpos = readpos;
1020   return 0;
1021 }
1022
1023
1024 /* This colonline handler thing is not the clean way to do it.  It
1025    might be better to enhance the GpgmeData object to act as a wrapper
1026    for a callback.  Same goes for the status thing.  For now we use
1027    this thing here because it is easier to implement.  */
1028 static GpgmeError
1029 colon_line_handler (void *opaque, int fd)
1030 {
1031   GpgObject gpg = opaque;
1032   GpgmeError rc = 0;
1033
1034   assert (fd == gpg->colon.fd[0]);
1035   rc = read_colon_line (gpg);
1036   if (rc)
1037     return rc;
1038   if (gpg->colon.eof)
1039     _gpgme_io_close (fd);
1040   return 0;
1041 }
1042
1043
1044 static GpgmeError
1045 start (GpgObject gpg)
1046 {
1047   GpgmeError rc;
1048   int i, n;
1049   int status;
1050   struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
1051
1052   if (!gpg)
1053     return GPGME_Invalid_Value;
1054
1055   if (! _gpgme_get_gpg_path ())
1056     return GPGME_Invalid_Engine;
1057
1058   /* Kludge, so that we don't need to check the return code of all the
1059      add_arg ().  We bail out here instead.  */
1060   if (gpg->arg_error)
1061     return GPGME_Out_Of_Core;
1062
1063   rc = build_argv (gpg);
1064   if (rc)
1065     return rc;
1066
1067   n = 3; /* status_fd, colon_fd and end of list */
1068   for (i = 0; gpg->fd_data_map[i].data; i++) 
1069     n++;
1070   fd_child_list = calloc (n + n, sizeof *fd_child_list);
1071   if (!fd_child_list)
1072     return GPGME_Out_Of_Core;
1073   fd_parent_list = fd_child_list + n;
1074
1075   /* build the fd list for the child */
1076   n = 0;
1077   if (gpg->colon.fnc)
1078     {
1079       fd_child_list[n].fd = gpg->colon.fd[1]; 
1080       fd_child_list[n].dup_to = 1; /* dup to stdout */
1081       n++;
1082     }
1083   for (i = 0; gpg->fd_data_map[i].data; i++)
1084     {
1085       if (gpg->fd_data_map[i].dup_to != -1)
1086         {
1087           fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
1088           fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
1089           n++;
1090         }
1091     }
1092   fd_child_list[n].fd = -1;
1093   fd_child_list[n].dup_to = -1;
1094
1095   /* Build the fd list for the parent.  */
1096   n = 0;
1097   if (gpg->status.fd[1] != -1)
1098     {
1099       fd_parent_list[n].fd = gpg->status.fd[1];
1100       fd_parent_list[n].dup_to = -1;
1101       n++;
1102     }
1103   if (gpg->colon.fd[1] != -1)
1104     {
1105       fd_parent_list[n].fd = gpg->colon.fd[1];
1106       fd_parent_list[n].dup_to = -1;
1107       n++;
1108     }
1109   for (i = 0; gpg->fd_data_map[i].data; i++)
1110     {
1111       fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
1112       fd_parent_list[n].dup_to = -1;
1113       n++;
1114     }        
1115   fd_parent_list[n].fd = -1;
1116   fd_parent_list[n].dup_to = -1;
1117
1118   status = _gpgme_io_spawn (_gpgme_get_gpg_path (),
1119                             gpg->argv, fd_child_list, fd_parent_list);
1120   free (fd_child_list);
1121   if (status == -1)
1122     return GPGME_Exec_Error;
1123
1124   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
1125
1126   rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
1127                   &gpg->status.tag);
1128   if (rc)
1129     /* FIXME: kill the child */
1130     return rc;
1131
1132   if (gpg->colon.fnc)
1133     {
1134       assert (gpg->colon.fd[0] != -1);
1135       rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
1136                       &gpg->colon.tag);
1137       if (rc)
1138         /* FIXME: kill the child */
1139         return rc;
1140     }
1141
1142   for (i = 0; gpg->fd_data_map[i].data; i++)
1143     {
1144       if (gpg->cmd.used && i == gpg->cmd.idx)
1145         {
1146           /* Park the cmd fd.  */
1147           gpg->cmd.fd = gpg->fd_data_map[i].fd;
1148           gpg->fd_data_map[i].fd = -1;
1149         }
1150       else
1151         {
1152           rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
1153                           gpg->fd_data_map[i].inbound,
1154                           gpg->fd_data_map[i].inbound
1155                           ? _gpgme_data_inbound_handler
1156                           : _gpgme_data_outbound_handler,
1157                           gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
1158           
1159           if (rc)
1160             /* FIXME: kill the child */
1161             return rc;
1162         }
1163     }
1164
1165   (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_START, NULL);
1166   
1167   /* fixme: check what data we can release here */
1168   return 0;
1169 }
1170
1171
1172 static GpgmeError
1173 gpg_decrypt (void *engine, GpgmeData ciph, GpgmeData plain)
1174 {
1175   GpgObject gpg = engine;
1176   GpgmeError err;
1177
1178   err = add_arg (gpg, "--decrypt");
1179
1180   /* Tell the gpg object about the data.  */
1181   if (!err)
1182     err = add_arg (gpg, "--output");
1183   if (!err)
1184     err = add_arg (gpg, "-");
1185   if (!err)
1186     err = add_data (gpg, plain, 1, 1);
1187   if (!err)
1188     err = add_data (gpg, ciph, 0, 0);
1189
1190   if (!err)
1191     start (gpg);
1192   return err;
1193 }
1194
1195 static GpgmeError
1196 gpg_delete (void *engine, GpgmeKey key, int allow_secret)
1197 {
1198   GpgObject gpg = engine;
1199   GpgmeError err;
1200
1201   err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
1202                  : "--delete-key");
1203   if (!err)
1204     err = add_arg (gpg, "--");
1205   if (!err)
1206     {
1207       if (!key->subkeys || !key->subkeys->fpr)
1208         err = GPGME_Invalid_Key;
1209       else
1210         err = add_arg (gpg, key->subkeys->fpr);
1211     }
1212
1213   if (!err)
1214     start (gpg);
1215   return err;
1216 }
1217
1218
1219 static GpgmeError
1220 append_args_from_signers (GpgObject gpg, GpgmeCtx ctx /* FIXME */)
1221 {
1222   GpgmeError err = 0;
1223   int i;
1224   GpgmeKey key;
1225
1226   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1227     {
1228       const char *s = key->subkeys ? key->subkeys->keyid : NULL;
1229       if (s)
1230         {
1231           if (!err)
1232             err = add_arg (gpg, "-u");
1233           if (!err)
1234             err = add_arg (gpg, s);
1235         }
1236       gpgme_key_unref (key);
1237       if (err) break;
1238     }
1239   return err;
1240 }
1241
1242
1243 static GpgmeError
1244 gpg_edit (void *engine, GpgmeKey key, GpgmeData out, GpgmeCtx ctx /* FIXME */)
1245 {
1246   GpgObject gpg = engine;
1247   GpgmeError err;
1248
1249   err = add_arg (gpg, "--with-colons");
1250   if (!err)
1251     err = append_args_from_signers (gpg, ctx);
1252   if (!err)
1253   err = add_arg (gpg, "--edit-key");
1254   if (!err)
1255     err = add_data (gpg, out, 1, 1);
1256   if (!err)
1257     err = add_arg (gpg, "--");
1258   if (!err)
1259     {
1260       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1261       if (!s)
1262         err = GPGME_Invalid_Key;
1263       else
1264         err = add_arg (gpg, s);
1265     }
1266   if (!err)
1267     err = start (gpg);
1268
1269   return err;
1270 }
1271
1272
1273 static GpgmeError
1274 append_args_from_recipients (GpgObject gpg, const GpgmeRecipients rset)
1275 {
1276   GpgmeError err = 0;
1277   GpgmeUserID uid;
1278
1279   assert (rset);
1280   for (uid = rset->list; uid; uid = uid->next)
1281     {
1282       err = add_arg (gpg, "-r");
1283       if (!err)
1284         err = add_arg (gpg, uid->uid);
1285       if (err)
1286         break;
1287     }    
1288   return err;
1289 }
1290
1291
1292 static GpgmeError
1293 gpg_encrypt (void *engine, GpgmeRecipients recp, GpgmeData plain,
1294              GpgmeData ciph, int use_armor)
1295 {
1296   GpgObject gpg = engine;
1297   GpgmeError err;
1298   int symmetric = !recp;
1299
1300   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1301
1302   if (!err && use_armor)
1303     err = add_arg (gpg, "--armor");
1304
1305   if (!symmetric)
1306     {
1307       /* If we know that all recipients are valid (full or ultimate trust)
1308          we can suppress further checks.  */
1309       if (!err && !symmetric && _gpgme_recipients_all_valid (recp))
1310         err = add_arg (gpg, "--always-trust");
1311
1312       if (!err)
1313         err = append_args_from_recipients (gpg, recp);
1314     }
1315
1316   /* Tell the gpg object about the data.  */
1317   if (!err)
1318     err = add_arg (gpg, "--output");
1319   if (!err)
1320     err = add_arg (gpg, "-");
1321   if (!err)
1322     err = add_data (gpg, ciph, 1, 1);
1323   if (!err)
1324     err = add_arg (gpg, "--");
1325   if (!err)
1326     err = add_data (gpg, plain, 0, 0);
1327
1328   if (!err)
1329     err = start (gpg);
1330
1331   return err;
1332 }
1333
1334
1335 static GpgmeError
1336 gpg_encrypt_sign (void *engine, GpgmeRecipients recp, GpgmeData plain,
1337                   GpgmeData ciph, int use_armor, GpgmeCtx ctx /* FIXME */)
1338 {
1339   GpgObject gpg = engine;
1340   GpgmeError err;
1341
1342   err = add_arg (gpg, "--encrypt");
1343   if (!err)
1344     err = add_arg (gpg, "--sign");
1345   if (!err && use_armor)
1346     err = add_arg (gpg, "--armor");
1347
1348   /* If we know that all recipients are valid (full or ultimate trust)
1349    * we can suppress further checks */
1350   if (!err && _gpgme_recipients_all_valid (recp))
1351     err = add_arg (gpg, "--always-trust");
1352
1353   if (!err)
1354     err = append_args_from_recipients (gpg, recp);
1355
1356   if (!err)
1357     err = append_args_from_signers (gpg, ctx);
1358
1359   /* Tell the gpg object about the data.  */
1360   if (!err)
1361     err = add_arg (gpg, "--output");
1362   if (!err)
1363     err = add_arg (gpg, "-");
1364   if (!err)
1365     err = add_data (gpg, ciph, 1, 1);
1366   if (!err)
1367     err = add_arg (gpg, "--");
1368   if (!err)
1369     err = add_data (gpg, plain, 0, 0);
1370
1371   if (!err)
1372     err = start (gpg);
1373
1374   return err;
1375 }
1376
1377
1378 static GpgmeError
1379 gpg_export (void *engine, GpgmeRecipients recp, GpgmeData keydata,
1380             int use_armor)
1381 {
1382   GpgObject gpg = engine;
1383   GpgmeError err;
1384
1385   err = add_arg (gpg, "--export");
1386   if (!err && use_armor)
1387     err = add_arg (gpg, "--armor");
1388   if (!err)
1389     err = add_data (gpg, keydata, 1, 1);
1390   if (!err)
1391     err = add_arg (gpg, "--");
1392
1393   if (!err)
1394     {
1395       void *ec;
1396       const char *s;
1397
1398       err = gpgme_recipients_enum_open (recp, &ec);
1399       while (!err && (s = gpgme_recipients_enum_read (recp, &ec)))
1400         err = add_arg (gpg, s);
1401       if (!err)
1402         err = gpgme_recipients_enum_close (recp, &ec);
1403     }
1404
1405   if (!err)
1406     err = start (gpg);
1407
1408   return err;
1409 }
1410
1411
1412 static GpgmeError
1413 gpg_genkey (void *engine, GpgmeData help_data, int use_armor,
1414             GpgmeData pubkey, GpgmeData seckey)
1415 {
1416   GpgObject gpg = engine;
1417   GpgmeError err;
1418
1419   if (!gpg)
1420     return GPGME_Invalid_Value;
1421
1422   /* We need a special mechanism to get the fd of a pipe here, so that
1423      we can use this for the %pubring and %secring parameters.  We
1424      don't have this yet, so we implement only the adding to the
1425      standard keyrings.  */
1426   if (pubkey || seckey)
1427     return err = GPGME_Not_Implemented;
1428
1429   err = add_arg (gpg, "--gen-key");
1430   if (!err && use_armor)
1431     err = add_arg (gpg, "--armor");
1432   if (!err)
1433     err = add_data (gpg, help_data, 0, 0);
1434
1435   if (!err)
1436     err = start (gpg);
1437
1438   return err;
1439 }
1440
1441
1442 static GpgmeError
1443 gpg_import (void *engine, GpgmeData keydata)
1444 {
1445   GpgObject gpg = engine;
1446   GpgmeError err;
1447
1448   err = add_arg (gpg, "--import");
1449   if (!err)
1450     err = add_data (gpg, keydata, 0, 0);
1451
1452   if (!err)
1453     err = start (gpg);
1454
1455   return err;
1456 }
1457
1458
1459 static GpgmeError
1460 gpg_keylist (void *engine, const char *pattern, int secret_only,
1461              int keylist_mode)
1462 {
1463   GpgObject gpg = engine;
1464   GpgmeError err;
1465
1466   err = add_arg (gpg, "--with-colons");
1467   if (!err)
1468     err = add_arg (gpg, "--fixed-list-mode");
1469   if (!err)
1470     err = add_arg (gpg, "--with-fingerprint");
1471   if (!err)
1472     err = add_arg (gpg, "--with-fingerprint");
1473   if (!err)
1474     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1475                    : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1476                       ? "--check-sigs" : "--list-keys"));
1477   
1478   /* Tell the gpg object about the data.  */
1479   if (!err)
1480     err = add_arg (gpg, "--");
1481   if (!err && pattern && *pattern)
1482     err = add_arg (gpg, pattern);
1483
1484   if (!err)
1485     err = start (gpg);
1486
1487   return err;
1488 }
1489
1490
1491 static GpgmeError
1492 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
1493                  int reserved, int keylist_mode)
1494 {
1495   GpgObject gpg = engine;
1496   GpgmeError err;
1497
1498   if (reserved)
1499     return GPGME_Invalid_Value;
1500
1501   err = add_arg (gpg, "--with-colons");
1502   if (!err)
1503     err = add_arg (gpg, "--fixed-list-mode");
1504   if (!err)
1505     err = add_arg (gpg, "--with-fingerprint");
1506   if (!err)
1507     err = add_arg (gpg, "--with-fingerprint");
1508   if (!err)
1509     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1510                    : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1511                       ? "--check-sigs" : "--list-keys"));
1512
1513   /* Tell the gpg object about the data.  */
1514   if (!err)
1515     err = add_arg (gpg, "--");
1516   if (!err && pattern && *pattern)
1517     {
1518       while (*pattern && **pattern)
1519         err = add_arg (gpg, *(pattern++));
1520     }
1521
1522   if (!err)
1523     err = start (gpg);
1524
1525   return err;
1526 }
1527
1528
1529 static GpgmeError
1530 gpg_sign (void *engine, GpgmeData in, GpgmeData out, GpgmeSigMode mode,
1531           int use_armor, int use_textmode, int include_certs,
1532           GpgmeCtx ctx /* FIXME */)
1533 {
1534   GpgObject gpg = engine;
1535   GpgmeError err;
1536
1537   if (mode == GPGME_SIG_MODE_CLEAR)
1538     err = add_arg (gpg, "--clearsign");
1539   else
1540     {
1541       err = add_arg (gpg, "--sign");
1542       if (!err && mode == GPGME_SIG_MODE_DETACH)
1543         err = add_arg (gpg, "--detach");
1544       if (!err && use_armor)
1545         err = add_arg (gpg, "--armor");
1546       if (!err && use_textmode)
1547         add_arg (gpg, "--textmode");
1548     }
1549
1550   if (!err)
1551     err = append_args_from_signers (gpg, ctx);
1552
1553   /* Tell the gpg object about the data.  */
1554   if (!err)
1555     err = add_data (gpg, in, 0, 0);
1556   if (!err)
1557     err = add_data (gpg, out, 1, 1);
1558
1559   if (!err)
1560     start (gpg);
1561
1562   return err;
1563 }
1564
1565 static GpgmeError
1566 gpg_trustlist (void *engine, const char *pattern)
1567 {
1568   GpgObject gpg = engine;
1569   GpgmeError err;
1570
1571   err = add_arg (gpg, "--with-colons");
1572   if (!err)
1573     err = add_arg (gpg, "--list-trust-path");
1574   
1575   /* Tell the gpg object about the data.  */
1576   if (!err)
1577     err = add_arg (gpg, "--");
1578   if (!err)
1579     err = add_arg (gpg, pattern);
1580
1581   if (!err)
1582     err = start (gpg);
1583
1584   return err;
1585 }
1586
1587
1588 static GpgmeError
1589 gpg_verify (void *engine, GpgmeData sig, GpgmeData signed_text,
1590             GpgmeData plaintext)
1591 {
1592   GpgObject gpg = engine;
1593   GpgmeError err = 0;
1594
1595   if (plaintext)
1596     {
1597       /* Normal or cleartext signature.  */
1598
1599       err = add_arg (gpg, "--output");
1600       if (!err)
1601         err = add_arg (gpg, "-");
1602       if (!err)
1603         err = add_arg (gpg, "--");
1604       if (!err)
1605         err = add_data (gpg, sig, 0, 0);
1606       if (!err)
1607         err = add_data (gpg, plaintext, 1, 1);
1608     }
1609   else
1610     {
1611       err = add_arg (gpg, "--verify");
1612       if (!err)
1613         err = add_arg (gpg, "--");
1614       if (!err)
1615         err = add_data (gpg, sig, -1, 0);
1616       if (signed_text)
1617         {
1618           if (!err)
1619             err = add_arg (gpg, "-");
1620           if (!err)
1621             err = add_data (gpg, signed_text, 0, 0);
1622         }
1623     }
1624
1625   if (!err)
1626     err = start (gpg);
1627
1628   return err;
1629 }
1630
1631
1632 static void
1633 gpg_set_io_cbs (void *engine, struct GpgmeIOCbs *io_cbs)
1634 {
1635   GpgObject gpg = engine;
1636
1637   gpg->io_cbs = *io_cbs;
1638 }
1639
1640 \f
1641 struct engine_ops _gpgme_engine_ops_gpg =
1642   {
1643     /* Static functions.  */
1644     _gpgme_get_gpg_path,
1645     gpg_get_version,
1646     gpg_get_req_version,
1647     gpg_new,
1648
1649     /* Member functions.  */
1650     gpg_release,
1651     gpg_set_status_handler,
1652     gpg_set_command_handler,
1653     gpg_set_colon_line_handler,
1654     gpg_decrypt,
1655     gpg_delete,
1656     gpg_edit,
1657     gpg_encrypt,
1658     gpg_encrypt_sign,
1659     gpg_export,
1660     gpg_genkey,
1661     gpg_import,
1662     gpg_keylist,
1663     gpg_keylist_ext,
1664     gpg_sign,
1665     gpg_trustlist,
1666     gpg_verify,
1667     gpg_set_io_cbs,
1668     gpg_io_event
1669   };