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