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