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