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