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