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