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