698d0ca01edc630daf6df9fd48de379188e1cb6c
[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     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     gpgme_data_t cb_data;   /* hack to get init the above idx later */
114     gpgme_status_code_t 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     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       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 gpgme_error_t
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 gpgme_data_t 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 gpgme_error_t
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 gpgme_error_t
441 command_cb (void *opaque, char *buffer, size_t length, size_t *nread)
442 {
443   gpgme_error_t 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 gpgme_error_t
510 gpg_set_command_handler (void *engine, EngineCommandHandler fnc,
511                          void *fnc_value, gpgme_data_t linked_data)
512 {
513   GpgObject gpg = engine;
514   gpgme_data_t tmp;
515   gpgme_error_t 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 gpgme_error_t
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 gpgme_error_t
744 add_io_cb (GpgObject gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
745            void **tag)
746 {
747   gpgme_error_t 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 gpgme_error_t
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           gpgme_error_t 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                           gpgme_error_t 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 gpgme_error_t
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 gpgme_error_t
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 gpgme_data_t 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 gpgme_error_t
1029 colon_line_handler (void *opaque, int fd)
1030 {
1031   GpgObject gpg = opaque;
1032   gpgme_error_t 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 gpgme_error_t
1045 start (GpgObject gpg)
1046 {
1047   gpgme_error_t 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 gpgme_error_t
1173 gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1174 {
1175   GpgObject gpg = engine;
1176   gpgme_error_t 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 gpgme_error_t
1196 gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
1197 {
1198   GpgObject gpg = engine;
1199   gpgme_error_t 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 gpgme_error_t
1220 append_args_from_signers (GpgObject gpg, gpgme_ctx_t ctx /* FIXME */)
1221 {
1222   gpgme_error_t err = 0;
1223   int i;
1224   gpgme_key_t 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 gpgme_error_t
1244 gpg_edit (void *engine, gpgme_key_t key, gpgme_data_t out,
1245           gpgme_ctx_t ctx /* FIXME */)
1246 {
1247   GpgObject gpg = engine;
1248   gpgme_error_t err;
1249
1250   err = add_arg (gpg, "--with-colons");
1251   if (!err)
1252     err = append_args_from_signers (gpg, ctx);
1253   if (!err)
1254   err = add_arg (gpg, "--edit-key");
1255   if (!err)
1256     err = add_data (gpg, out, 1, 1);
1257   if (!err)
1258     err = add_arg (gpg, "--");
1259   if (!err)
1260     {
1261       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1262       if (!s)
1263         err = GPGME_Invalid_Key;
1264       else
1265         err = add_arg (gpg, s);
1266     }
1267   if (!err)
1268     err = start (gpg);
1269
1270   return err;
1271 }
1272
1273
1274 static gpgme_error_t
1275 append_args_from_recipients (GpgObject gpg, const gpgme_recipients_t rset)
1276 {
1277   gpgme_error_t err = 0;
1278   gpgme_user_id_t uid;
1279
1280   assert (rset);
1281   for (uid = rset->list; uid; uid = uid->next)
1282     {
1283       err = add_arg (gpg, "-r");
1284       if (!err)
1285         err = add_arg (gpg, uid->uid);
1286       if (err)
1287         break;
1288     }    
1289   return err;
1290 }
1291
1292
1293 static gpgme_error_t
1294 gpg_encrypt (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
1295              gpgme_data_t ciph, int use_armor)
1296 {
1297   GpgObject gpg = engine;
1298   gpgme_error_t err;
1299   int symmetric = !recp;
1300
1301   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1302
1303   if (!err && use_armor)
1304     err = add_arg (gpg, "--armor");
1305
1306   if (!symmetric)
1307     {
1308       /* If we know that all recipients are valid (full or ultimate trust)
1309          we can suppress further checks.  */
1310       if (!err && !symmetric && _gpgme_recipients_all_valid (recp))
1311         err = add_arg (gpg, "--always-trust");
1312
1313       if (!err)
1314         err = append_args_from_recipients (gpg, recp);
1315     }
1316
1317   /* Tell the gpg object about the data.  */
1318   if (!err)
1319     err = add_arg (gpg, "--output");
1320   if (!err)
1321     err = add_arg (gpg, "-");
1322   if (!err)
1323     err = add_data (gpg, ciph, 1, 1);
1324   if (!err)
1325     err = add_arg (gpg, "--");
1326   if (!err)
1327     err = add_data (gpg, plain, 0, 0);
1328
1329   if (!err)
1330     err = start (gpg);
1331
1332   return err;
1333 }
1334
1335
1336 static gpgme_error_t
1337 gpg_encrypt_sign (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
1338                   gpgme_data_t ciph, int use_armor,
1339                   gpgme_ctx_t ctx /* FIXME */)
1340 {
1341   GpgObject gpg = engine;
1342   gpgme_error_t err;
1343
1344   err = add_arg (gpg, "--encrypt");
1345   if (!err)
1346     err = add_arg (gpg, "--sign");
1347   if (!err && use_armor)
1348     err = add_arg (gpg, "--armor");
1349
1350   /* If we know that all recipients are valid (full or ultimate trust)
1351    * we can suppress further checks */
1352   if (!err && _gpgme_recipients_all_valid (recp))
1353     err = add_arg (gpg, "--always-trust");
1354
1355   if (!err)
1356     err = append_args_from_recipients (gpg, recp);
1357
1358   if (!err)
1359     err = append_args_from_signers (gpg, ctx);
1360
1361   /* Tell the gpg object about the data.  */
1362   if (!err)
1363     err = add_arg (gpg, "--output");
1364   if (!err)
1365     err = add_arg (gpg, "-");
1366   if (!err)
1367     err = add_data (gpg, ciph, 1, 1);
1368   if (!err)
1369     err = add_arg (gpg, "--");
1370   if (!err)
1371     err = add_data (gpg, plain, 0, 0);
1372
1373   if (!err)
1374     err = start (gpg);
1375
1376   return err;
1377 }
1378
1379
1380 static gpgme_error_t
1381 gpg_export (void *engine, gpgme_recipients_t recp, gpgme_data_t keydata,
1382             int use_armor)
1383 {
1384   GpgObject gpg = engine;
1385   gpgme_error_t err;
1386
1387   err = add_arg (gpg, "--export");
1388   if (!err && use_armor)
1389     err = add_arg (gpg, "--armor");
1390   if (!err)
1391     err = add_data (gpg, keydata, 1, 1);
1392   if (!err)
1393     err = add_arg (gpg, "--");
1394
1395   if (!err)
1396     {
1397       void *ec;
1398       const char *s;
1399
1400       err = gpgme_recipients_enum_open (recp, &ec);
1401       while (!err && (s = gpgme_recipients_enum_read (recp, &ec)))
1402         err = add_arg (gpg, s);
1403       if (!err)
1404         err = gpgme_recipients_enum_close (recp, &ec);
1405     }
1406
1407   if (!err)
1408     err = start (gpg);
1409
1410   return err;
1411 }
1412
1413
1414 static gpgme_error_t
1415 gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1416             gpgme_data_t pubkey, gpgme_data_t seckey)
1417 {
1418   GpgObject gpg = engine;
1419   gpgme_error_t err;
1420
1421   if (!gpg)
1422     return GPGME_Invalid_Value;
1423
1424   /* We need a special mechanism to get the fd of a pipe here, so that
1425      we can use this for the %pubring and %secring parameters.  We
1426      don't have this yet, so we implement only the adding to the
1427      standard keyrings.  */
1428   if (pubkey || seckey)
1429     return err = GPGME_Not_Implemented;
1430
1431   err = add_arg (gpg, "--gen-key");
1432   if (!err && use_armor)
1433     err = add_arg (gpg, "--armor");
1434   if (!err)
1435     err = add_data (gpg, help_data, 0, 0);
1436
1437   if (!err)
1438     err = start (gpg);
1439
1440   return err;
1441 }
1442
1443
1444 static gpgme_error_t
1445 gpg_import (void *engine, gpgme_data_t keydata)
1446 {
1447   GpgObject gpg = engine;
1448   gpgme_error_t err;
1449
1450   err = add_arg (gpg, "--import");
1451   if (!err)
1452     err = add_data (gpg, keydata, 0, 0);
1453
1454   if (!err)
1455     err = start (gpg);
1456
1457   return err;
1458 }
1459
1460
1461 static gpgme_error_t
1462 gpg_keylist (void *engine, const char *pattern, int secret_only,
1463              int keylist_mode)
1464 {
1465   GpgObject gpg = engine;
1466   gpgme_error_t err;
1467
1468   err = add_arg (gpg, "--with-colons");
1469   if (!err)
1470     err = add_arg (gpg, "--fixed-list-mode");
1471   if (!err)
1472     err = add_arg (gpg, "--with-fingerprint");
1473   if (!err)
1474     err = add_arg (gpg, "--with-fingerprint");
1475   if (!err)
1476     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1477                    : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1478                       ? "--check-sigs" : "--list-keys"));
1479   
1480   /* Tell the gpg object about the data.  */
1481   if (!err)
1482     err = add_arg (gpg, "--");
1483   if (!err && pattern && *pattern)
1484     err = add_arg (gpg, pattern);
1485
1486   if (!err)
1487     err = start (gpg);
1488
1489   return err;
1490 }
1491
1492
1493 static gpgme_error_t
1494 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
1495                  int reserved, int keylist_mode)
1496 {
1497   GpgObject gpg = engine;
1498   gpgme_error_t err;
1499
1500   if (reserved)
1501     return GPGME_Invalid_Value;
1502
1503   err = add_arg (gpg, "--with-colons");
1504   if (!err)
1505     err = add_arg (gpg, "--fixed-list-mode");
1506   if (!err)
1507     err = add_arg (gpg, "--with-fingerprint");
1508   if (!err)
1509     err = add_arg (gpg, "--with-fingerprint");
1510   if (!err)
1511     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1512                    : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1513                       ? "--check-sigs" : "--list-keys"));
1514
1515   /* Tell the gpg object about the data.  */
1516   if (!err)
1517     err = add_arg (gpg, "--");
1518   if (!err && pattern && *pattern)
1519     {
1520       while (*pattern && **pattern)
1521         err = add_arg (gpg, *(pattern++));
1522     }
1523
1524   if (!err)
1525     err = start (gpg);
1526
1527   return err;
1528 }
1529
1530
1531 static gpgme_error_t
1532 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1533           gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1534           int include_certs, gpgme_ctx_t ctx /* FIXME */)
1535 {
1536   GpgObject gpg = engine;
1537   gpgme_error_t err;
1538
1539   if (mode == GPGME_SIG_MODE_CLEAR)
1540     err = add_arg (gpg, "--clearsign");
1541   else
1542     {
1543       err = add_arg (gpg, "--sign");
1544       if (!err && mode == GPGME_SIG_MODE_DETACH)
1545         err = add_arg (gpg, "--detach");
1546       if (!err && use_armor)
1547         err = add_arg (gpg, "--armor");
1548       if (!err && use_textmode)
1549         add_arg (gpg, "--textmode");
1550     }
1551
1552   if (!err)
1553     err = append_args_from_signers (gpg, ctx);
1554
1555   /* Tell the gpg object about the data.  */
1556   if (!err)
1557     err = add_data (gpg, in, 0, 0);
1558   if (!err)
1559     err = add_data (gpg, out, 1, 1);
1560
1561   if (!err)
1562     start (gpg);
1563
1564   return err;
1565 }
1566
1567 static gpgme_error_t
1568 gpg_trustlist (void *engine, const char *pattern)
1569 {
1570   GpgObject gpg = engine;
1571   gpgme_error_t err;
1572
1573   err = add_arg (gpg, "--with-colons");
1574   if (!err)
1575     err = add_arg (gpg, "--list-trust-path");
1576   
1577   /* Tell the gpg object about the data.  */
1578   if (!err)
1579     err = add_arg (gpg, "--");
1580   if (!err)
1581     err = add_arg (gpg, pattern);
1582
1583   if (!err)
1584     err = start (gpg);
1585
1586   return err;
1587 }
1588
1589
1590 static gpgme_error_t
1591 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1592             gpgme_data_t plaintext)
1593 {
1594   GpgObject gpg = engine;
1595   gpgme_error_t err = 0;
1596
1597   if (plaintext)
1598     {
1599       /* Normal or cleartext signature.  */
1600
1601       err = add_arg (gpg, "--output");
1602       if (!err)
1603         err = add_arg (gpg, "-");
1604       if (!err)
1605         err = add_arg (gpg, "--");
1606       if (!err)
1607         err = add_data (gpg, sig, 0, 0);
1608       if (!err)
1609         err = add_data (gpg, plaintext, 1, 1);
1610     }
1611   else
1612     {
1613       err = add_arg (gpg, "--verify");
1614       if (!err)
1615         err = add_arg (gpg, "--");
1616       if (!err)
1617         err = add_data (gpg, sig, -1, 0);
1618       if (signed_text)
1619         {
1620           if (!err)
1621             err = add_arg (gpg, "-");
1622           if (!err)
1623             err = add_data (gpg, signed_text, 0, 0);
1624         }
1625     }
1626
1627   if (!err)
1628     err = start (gpg);
1629
1630   return err;
1631 }
1632
1633
1634 static void
1635 gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1636 {
1637   GpgObject gpg = engine;
1638
1639   gpg->io_cbs = *io_cbs;
1640 }
1641
1642 \f
1643 struct engine_ops _gpgme_engine_ops_gpg =
1644   {
1645     /* Static functions.  */
1646     _gpgme_get_gpg_path,
1647     gpg_get_version,
1648     gpg_get_req_version,
1649     gpg_new,
1650
1651     /* Member functions.  */
1652     gpg_release,
1653     gpg_set_status_handler,
1654     gpg_set_command_handler,
1655     gpg_set_colon_line_handler,
1656     gpg_decrypt,
1657     gpg_delete,
1658     gpg_edit,
1659     gpg_encrypt,
1660     gpg_encrypt_sign,
1661     gpg_export,
1662     gpg_genkey,
1663     gpg_import,
1664     gpg_keylist,
1665     gpg_keylist_ext,
1666     gpg_sign,
1667     gpg_trustlist,
1668     gpg_verify,
1669     gpg_set_io_cbs,
1670     gpg_io_event
1671   };