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