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