c89e39edbf37c4922da2c04bfa6d40d382d0f8c2
[gpgme.git] / gpgme / rungpg.c
1 /* rungpg.c - Gpg Engine.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 g10 Code GmbH
4  
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11  
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <sys/time.h>
31 #include <sys/types.h>
32 #include <signal.h>
33 #include <fcntl.h>
34 #include "unistd.h"
35
36 #include "gpgme.h"
37 #include "util.h"
38 #include "ops.h"
39 #include "wait.h"
40 #include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
41 #include "io.h"
42 #include "sema.h"
43 #include "debug.h"
44
45 #include "status-table.h"
46 #include "engine-backend.h"
47
48
49 /* This type is used to build a list of gpg arguments and data
50    sources/sinks.  */
51 struct arg_and_data_s
52 {
53   struct arg_and_data_s *next;
54   gpgme_data_t data;  /* If this is not NULL, use arg below.  */
55   int inbound;     /* True if this is used for reading from gpg.  */
56   int dup_to;
57   int print_fd;    /* Print the fd number and not the special form of it.  */
58   char arg[1];     /* Used if data above is not used.  */
59 };
60
61
62 struct fd_data_map_s
63 {
64   gpgme_data_t data;
65   int inbound;  /* true if this is used for reading from gpg */
66   int dup_to;
67   int fd;       /* the fd to use */
68   int peer_fd;  /* the outher side of the pipe */
69   void *tag;
70 };
71
72
73 struct 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     EngineStatusHandler 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     EngineColonLineHandler 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     gpgme_data_t cb_data;   /* hack to get init the above idx later */
114     gpgme_status_code_t code;  /* last code */
115     char *keyword;       /* what has been requested (malloced) */
116     EngineCommandHandler 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     gpgme_data_t linked_data;
121     int linked_idx;
122   } cmd;
123
124   struct gpgme_io_cbs io_cbs;
125 };
126
127 typedef struct gpg_object_s *GpgObject;
128
129 \f
130 static void
131 gpg_io_event (void *engine, gpgme_event_io_t 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 gpgme_error_t
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 gpgme_error_t
208 add_data (GpgObject gpg, gpgme_data_t 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 gpgme_error_t
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 gpgme_data_t 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   add_arg (gpg, "--enable-progress-filter");
388
389  leave:
390   if (rc)
391     gpg_release (gpg);
392   else
393     *engine = gpg;
394   return rc;
395 }
396
397
398 /* Note, that the status_handler is allowed to modifiy the args
399    value.  */
400 static void
401 gpg_set_status_handler (void *engine, EngineStatusHandler fnc, void *fnc_value)
402 {
403   GpgObject gpg = engine;
404
405   gpg->status.fnc = fnc;
406   gpg->status.fnc_value = fnc_value;
407 }
408
409 /* Kludge to process --with-colon output.  */
410 static gpgme_error_t
411 gpg_set_colon_line_handler (void *engine, EngineColonLineHandler fnc,
412                             void *fnc_value)
413 {
414   GpgObject gpg = engine;
415
416   gpg->colon.bufsize = 1024;
417   gpg->colon.readpos = 0;
418   gpg->colon.buffer = malloc (gpg->colon.bufsize);
419   if (!gpg->colon.buffer)
420     return GPGME_Out_Of_Core;
421
422   if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) 
423     {
424       free (gpg->colon.buffer);
425       gpg->colon.buffer = NULL;
426       return GPGME_Pipe_Error;
427     }
428   if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
429       || _gpgme_io_set_close_notify (gpg->colon.fd[1],
430                                      close_notify_handler, gpg))
431     return GPGME_General_Error;
432   gpg->colon.eof = 0;
433   gpg->colon.fnc = fnc;
434   gpg->colon.fnc_value = fnc_value;
435   return 0;
436 }
437
438
439 /* Here we handle --command-fd.  This works closely together with the
440    status handler.  */
441 static gpgme_error_t
442 command_cb (void *opaque, char *buffer, size_t length, size_t *nread)
443 {
444   gpgme_error_t err;
445   GpgObject gpg = opaque;
446   const char *value;
447   int value_len;
448
449   DEBUG0 ("command_cb: enter\n");
450   assert (gpg->cmd.used);
451   if (!buffer || !length || !nread)
452     return 0; /* These values are reserved for extensions.  */
453   *nread = 0;
454   if (!gpg->cmd.code)
455     {
456       DEBUG0 ("command_cb: no code\n");
457       return -1;
458     }
459     
460   if (!gpg->cmd.fnc)
461     {
462       DEBUG0 ("command_cb: no user cb\n");
463       return -1;
464     }
465
466   /* FIXME catch error */
467   err = gpg->cmd.fnc (gpg->cmd.fnc_value, 
468                       gpg->cmd.code, gpg->cmd.keyword, &value);
469   if (err)
470     return err;
471
472   if (!value)
473     {
474       DEBUG0 ("command_cb: no data from user cb\n");
475       gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
476       return -1;
477     }
478
479   value_len = strlen (value);
480   if (value_len + 1 > length)
481     {
482       DEBUG0 ("command_cb: too much data from user cb\n");
483       gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
484       return -1;
485     }
486
487   memcpy (buffer, value, value_len);
488   if (!value_len || (value_len && value[value_len-1] != '\n')) 
489     buffer[value_len++] = '\n';
490   *nread = value_len;
491     
492   gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
493   gpg->cmd.code = 0;
494   /* And sleep again until read_status will wake us up again.  */
495   /* XXX We must check if there are any more fds active after removing
496      this one.  */
497   (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
498   gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
499   gpg->fd_data_map[gpg->cmd.idx].fd = -1;
500
501   return 0;
502 }
503
504
505 /* The Fnc will be called to get a value for one of the commands with
506    a key KEY.  If the Code pssed to FNC is 0, the function may release
507    resources associated with the returned value from another call.  To
508    match such a second call to a first call, the returned value from
509    the first call is passed as keyword.  */
510 static gpgme_error_t
511 gpg_set_command_handler (void *engine, EngineCommandHandler fnc,
512                          void *fnc_value, gpgme_data_t linked_data)
513 {
514   GpgObject gpg = engine;
515   gpgme_data_t tmp;
516   gpgme_error_t err;
517
518   err = gpgme_data_new_with_read_cb (&tmp, command_cb, gpg);
519   if (err)
520     return err;
521         
522   add_arg (gpg, "--command-fd");
523   add_data (gpg, tmp, -2, 0);
524   gpg->cmd.cb_data = tmp;
525   gpg->cmd.fnc = fnc;
526   gpg->cmd.fnc_value = fnc_value;
527   gpg->cmd.linked_data = linked_data;
528   gpg->cmd.used = 1;
529   return 0;
530 }
531
532
533 static gpgme_error_t
534 build_argv (GpgObject gpg)
535 {
536   struct arg_and_data_s *a;
537   struct fd_data_map_s *fd_data_map;
538   size_t datac=0, argc=0;  
539   char **argv;
540   int need_special = 0;
541   int use_agent = 0;
542   char *p;
543
544   /* We don't want to use the agent with a malformed environment
545      variable.  This is only a very basic test but sufficient to make
546      our life in the regression tests easier. */
547   p = getenv ("GPG_AGENT_INFO");
548   use_agent = (p && strchr (p, ':'));
549        
550   if (gpg->argv)
551     {
552       free_argv (gpg->argv);
553       gpg->argv = NULL;
554     }
555   if (gpg->fd_data_map)
556     {
557       free_fd_data_map (gpg->fd_data_map);
558       gpg->fd_data_map = NULL;
559     }
560
561   argc++;       /* For argv[0].  */
562   for (a = gpg->arglist; a; a = a->next)
563     {
564       argc++;
565       if (a->data)
566         {
567           /*fprintf (stderr, "build_argv: data\n" );*/
568           datac++;
569           if (a->dup_to == -1 && !a->print_fd)
570             need_special = 1;
571         }
572       else
573         {
574           /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
575         }
576     }
577   if (need_special)
578     argc++;
579   if (use_agent)
580     argc++;
581   if (!gpg->cmd.used)
582     argc++;
583   argc += 2; /* --comment */
584
585   argv = calloc (argc + 1, sizeof *argv);
586   if (!argv)
587     return GPGME_Out_Of_Core;
588   fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
589   if (!fd_data_map)
590     {
591       free_argv (argv);
592       return GPGME_Out_Of_Core;
593     }
594
595   argc = datac = 0;
596   argv[argc] = strdup ("gpg"); /* argv[0] */
597   if (!argv[argc])
598     {
599       free (fd_data_map);
600       free_argv (argv);
601       return GPGME_Out_Of_Core;
602     }
603   argc++;
604   if (need_special)
605     {
606       argv[argc] = strdup ("--enable-special-filenames");
607       if (!argv[argc])
608         {
609           free (fd_data_map);
610           free_argv (argv);
611           return GPGME_Out_Of_Core;
612         }
613       argc++;
614     }
615   if (use_agent)
616     {
617       argv[argc] = strdup ("--use-agent");
618       if (!argv[argc])
619         {
620           free (fd_data_map);
621           free_argv (argv);
622           return GPGME_Out_Of_Core;
623         }
624       argc++;
625     }
626   if (!gpg->cmd.used)
627     {
628       argv[argc] = strdup ("--batch");
629       if (!argv[argc])
630         {
631           free (fd_data_map);
632           free_argv (argv);
633           return GPGME_Out_Of_Core;
634         }
635       argc++;
636     }
637   argv[argc] = strdup ("--comment");
638   if (!argv[argc])
639     {
640       free (fd_data_map);
641       free_argv (argv);
642       return GPGME_Out_Of_Core;
643     }
644   argc++;
645   argv[argc] = strdup ("");
646   if (!argv[argc])
647     {
648       free (fd_data_map);
649       free_argv (argv);
650       return GPGME_Out_Of_Core;
651     }
652   argc++;
653   for (a = gpg->arglist; a; a = a->next)
654     {
655       if (a->data)
656         {
657           /* Create a pipe to pass it down to gpg.  */
658           fd_data_map[datac].inbound = a->inbound;
659
660           /* Create a pipe.  */
661           {   
662             int fds[2];
663             
664             if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
665                 == -1)
666               {
667                 free (fd_data_map);
668                 free_argv (argv);
669                 return GPGME_Pipe_Error;
670               }
671             if (_gpgme_io_set_close_notify (fds[0],
672                                             close_notify_handler, gpg)
673                 || _gpgme_io_set_close_notify (fds[1],
674                                                close_notify_handler,
675                                                gpg))
676               {
677                 return GPGME_General_Error;
678               }
679             /* If the data_type is FD, we have to do a dup2 here.  */
680             if (fd_data_map[datac].inbound)
681               {
682                 fd_data_map[datac].fd       = fds[0];
683                 fd_data_map[datac].peer_fd  = fds[1];
684               }
685             else
686               {
687                 fd_data_map[datac].fd       = fds[1];
688                 fd_data_map[datac].peer_fd  = fds[0];
689               }
690           }
691
692           /* Hack to get hands on the fd later.  */
693           if (gpg->cmd.used)
694             {
695               if (gpg->cmd.cb_data == a->data)
696                 {
697                   assert (gpg->cmd.idx == -1);
698                   gpg->cmd.idx = datac;
699                 }
700               else if (gpg->cmd.linked_data == a->data)
701                 {
702                   assert (gpg->cmd.linked_idx == -1);
703                   gpg->cmd.linked_idx = datac;
704                 }
705             }
706
707           fd_data_map[datac].data = a->data;
708           fd_data_map[datac].dup_to = a->dup_to;
709           if (a->dup_to == -1)
710             {
711               argv[argc] = malloc (25);
712               if (!argv[argc])
713                 {
714                   free (fd_data_map);
715                   free_argv (argv);
716                   return GPGME_Out_Of_Core;
717                 }
718               sprintf (argv[argc], 
719                        a->print_fd ? "%d" : "-&%d",
720                        fd_data_map[datac].peer_fd);
721               argc++;
722             }
723           datac++;
724         }
725       else
726         {
727           argv[argc] = strdup (a->arg);
728           if (!argv[argc])
729             {
730               free (fd_data_map);
731               free_argv (argv);
732               return GPGME_Out_Of_Core;
733             }
734             argc++;
735         }
736     }
737
738   gpg->argv = argv;
739   gpg->fd_data_map = fd_data_map;
740   return 0;
741 }
742
743
744 static gpgme_error_t
745 add_io_cb (GpgObject gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
746            void **tag)
747 {
748   gpgme_error_t err;
749
750   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
751   if (err)
752     return err;
753   if (!dir)
754     /* FIXME Kludge around poll() problem.  */
755     err = _gpgme_io_set_nonblocking (fd);
756   return err;
757 }
758
759
760 static int
761 status_cmp (const void *ap, const void *bp)
762 {
763   const struct status_table_s *a = ap;
764   const struct status_table_s *b = bp;
765
766   return strcmp (a->name, b->name);
767 }
768
769
770 /* Handle the status output of GnuPG.  This function does read entire
771    lines and passes them as C strings to the callback function (we can
772    use C Strings because the status output is always UTF-8 encoded).
773    Of course we have to buffer the lines to cope with long lines
774    e.g. with a large user ID.  Note: We can optimize this to only cope
775    with status line code we know about and skip all other stuff
776    without buffering (i.e. without extending the buffer).  */
777 static gpgme_error_t
778 read_status (GpgObject gpg)
779 {
780   char *p;
781   int nread;
782   size_t bufsize = gpg->status.bufsize; 
783   char *buffer = gpg->status.buffer;
784   size_t readpos = gpg->status.readpos; 
785
786   assert (buffer);
787   if (bufsize - readpos < 256)
788     { 
789       /* Need more room for the read.  */
790       bufsize += 1024;
791       buffer = realloc (buffer, bufsize);
792       if (!buffer)
793         return GPGME_Out_Of_Core;
794     }
795
796   nread = _gpgme_io_read (gpg->status.fd[0],
797                           buffer + readpos, bufsize-readpos);
798   if (nread == -1)
799     return GPGME_Read_Error;
800
801   if (!nread)
802     {
803       gpg->status.eof = 1;
804       if (gpg->status.fnc)
805         {
806           gpgme_error_t err;
807           err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
808           if (err)
809             return err;
810         }
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                           gpgme_error_t err;
889                           err = gpg->status.fnc (gpg->status.fnc_value, 
890                                                  r->code, rest);
891                           if (err)
892                             return err;
893                         }
894                     
895                       if (r->code == GPGME_STATUS_END_STREAM)
896                         {
897                           if (gpg->cmd.used)
898                             {
899                               /* XXX We must check if there are any
900                                  more fds active after removing this
901                                  one.  */
902                               (*gpg->io_cbs.remove)
903                                 (gpg->fd_data_map[gpg->cmd.idx].tag);
904                               gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
905                               gpg->fd_data_map[gpg->cmd.idx].fd = -1;
906                             }
907                         }
908                     }
909                 }
910               /* To reuse the buffer for the next line we have to
911                  shift the remaining data to the buffer start and
912                  restart the loop Hmmm: We can optimize this function
913                  by looking forward in the buffer to see whether a
914                  second complete line is available and in this case
915                  avoid the memmove for this line.  */
916               nread--; p++;
917               if (nread)
918                 memmove (buffer, p, nread);
919               readpos = 0;
920               break; /* the for loop */
921             }
922           else
923             readpos++;
924         }
925     } 
926
927   /* Update the gpg object.  */
928   gpg->status.bufsize = bufsize;
929   gpg->status.buffer = buffer;
930   gpg->status.readpos = readpos;
931   return 0;
932 }
933
934
935 static gpgme_error_t
936 status_handler (void *opaque, int fd)
937 {
938   GpgObject gpg = opaque;
939   int err;
940
941   assert (fd == gpg->status.fd[0]);
942   err = read_status (gpg);
943   if (err)
944     return err;
945   if (gpg->status.eof)
946     _gpgme_io_close (fd);
947   return 0;
948 }
949
950
951 static gpgme_error_t
952 read_colon_line (GpgObject gpg)
953 {
954   char *p;
955   int nread;
956   size_t bufsize = gpg->colon.bufsize; 
957   char *buffer = gpg->colon.buffer;
958   size_t readpos = gpg->colon.readpos; 
959
960   assert (buffer);
961   if (bufsize - readpos < 256)
962     { 
963       /* Need more room for the read.  */
964       bufsize += 1024;
965       buffer = realloc (buffer, bufsize);
966       if (!buffer) 
967         return GPGME_Out_Of_Core;
968     }
969
970   nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
971   if (nread == -1)
972     return GPGME_Read_Error;
973
974   if (!nread)
975     {
976       gpg->colon.eof = 1;
977       assert (gpg->colon.fnc);
978       gpg->colon.fnc (gpg->colon.fnc_value, NULL);
979       return 0;
980     }
981
982   while (nread > 0)
983     {
984       for (p = buffer + readpos; nread; nread--, p++)
985         {
986           if ( *p == '\n' )
987             {
988               /* (we require that the last line is terminated by a LF)
989                  and we skip empty lines.  Note: we use UTF8 encoding
990                  and escaping of special characters We require at
991                  least one colon to cope with some other printed
992                  information.  */
993               *p = 0;
994               if (*buffer && strchr (buffer, ':'))
995                 {
996                   assert (gpg->colon.fnc);
997                   gpg->colon.fnc (gpg->colon.fnc_value, buffer);
998                 }
999             
1000               /* To reuse the buffer for the next line we have to
1001                  shift the remaining data to the buffer start and
1002                  restart the loop Hmmm: We can optimize this function
1003                  by looking forward in the buffer to see whether a
1004                  second complete line is available and in this case
1005                  avoid the memmove for this line.  */
1006               nread--; p++;
1007               if (nread)
1008                 memmove (buffer, p, nread);
1009               readpos = 0;
1010               break; /* The for loop.  */
1011             }
1012           else
1013             readpos++;
1014         }
1015     } 
1016
1017   /* Update the gpg object.  */
1018   gpg->colon.bufsize = bufsize;
1019   gpg->colon.buffer  = buffer;
1020   gpg->colon.readpos = readpos;
1021   return 0;
1022 }
1023
1024
1025 /* This colonline handler thing is not the clean way to do it.  It
1026    might be better to enhance the gpgme_data_t object to act as a wrapper
1027    for a callback.  Same goes for the status thing.  For now we use
1028    this thing here because it is easier to implement.  */
1029 static gpgme_error_t
1030 colon_line_handler (void *opaque, int fd)
1031 {
1032   GpgObject gpg = opaque;
1033   gpgme_error_t rc = 0;
1034
1035   assert (fd == gpg->colon.fd[0]);
1036   rc = read_colon_line (gpg);
1037   if (rc)
1038     return rc;
1039   if (gpg->colon.eof)
1040     _gpgme_io_close (fd);
1041   return 0;
1042 }
1043
1044
1045 static gpgme_error_t
1046 start (GpgObject gpg)
1047 {
1048   gpgme_error_t rc;
1049   int i, n;
1050   int status;
1051   struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
1052
1053   if (!gpg)
1054     return GPGME_Invalid_Value;
1055
1056   if (! _gpgme_get_gpg_path ())
1057     return GPGME_Invalid_Engine;
1058
1059   /* Kludge, so that we don't need to check the return code of all the
1060      add_arg ().  We bail out here instead.  */
1061   if (gpg->arg_error)
1062     return GPGME_Out_Of_Core;
1063
1064   rc = build_argv (gpg);
1065   if (rc)
1066     return rc;
1067
1068   n = 3; /* status_fd, colon_fd and end of list */
1069   for (i = 0; gpg->fd_data_map[i].data; i++) 
1070     n++;
1071   fd_child_list = calloc (n + n, sizeof *fd_child_list);
1072   if (!fd_child_list)
1073     return GPGME_Out_Of_Core;
1074   fd_parent_list = fd_child_list + n;
1075
1076   /* build the fd list for the child */
1077   n = 0;
1078   if (gpg->colon.fnc)
1079     {
1080       fd_child_list[n].fd = gpg->colon.fd[1]; 
1081       fd_child_list[n].dup_to = 1; /* dup to stdout */
1082       n++;
1083     }
1084   for (i = 0; gpg->fd_data_map[i].data; i++)
1085     {
1086       if (gpg->fd_data_map[i].dup_to != -1)
1087         {
1088           fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
1089           fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
1090           n++;
1091         }
1092     }
1093   fd_child_list[n].fd = -1;
1094   fd_child_list[n].dup_to = -1;
1095
1096   /* Build the fd list for the parent.  */
1097   n = 0;
1098   if (gpg->status.fd[1] != -1)
1099     {
1100       fd_parent_list[n].fd = gpg->status.fd[1];
1101       fd_parent_list[n].dup_to = -1;
1102       n++;
1103     }
1104   if (gpg->colon.fd[1] != -1)
1105     {
1106       fd_parent_list[n].fd = gpg->colon.fd[1];
1107       fd_parent_list[n].dup_to = -1;
1108       n++;
1109     }
1110   for (i = 0; gpg->fd_data_map[i].data; i++)
1111     {
1112       fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
1113       fd_parent_list[n].dup_to = -1;
1114       n++;
1115     }        
1116   fd_parent_list[n].fd = -1;
1117   fd_parent_list[n].dup_to = -1;
1118
1119   status = _gpgme_io_spawn (_gpgme_get_gpg_path (),
1120                             gpg->argv, fd_child_list, fd_parent_list);
1121   free (fd_child_list);
1122   if (status == -1)
1123     return GPGME_Exec_Error;
1124
1125   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
1126
1127   rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
1128                   &gpg->status.tag);
1129   if (rc)
1130     /* FIXME: kill the child */
1131     return rc;
1132
1133   if (gpg->colon.fnc)
1134     {
1135       assert (gpg->colon.fd[0] != -1);
1136       rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
1137                       &gpg->colon.tag);
1138       if (rc)
1139         /* FIXME: kill the child */
1140         return rc;
1141     }
1142
1143   for (i = 0; gpg->fd_data_map[i].data; i++)
1144     {
1145       if (gpg->cmd.used && i == gpg->cmd.idx)
1146         {
1147           /* Park the cmd fd.  */
1148           gpg->cmd.fd = gpg->fd_data_map[i].fd;
1149           gpg->fd_data_map[i].fd = -1;
1150         }
1151       else
1152         {
1153           rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
1154                           gpg->fd_data_map[i].inbound,
1155                           gpg->fd_data_map[i].inbound
1156                           ? _gpgme_data_inbound_handler
1157                           : _gpgme_data_outbound_handler,
1158                           gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
1159           
1160           if (rc)
1161             /* FIXME: kill the child */
1162             return rc;
1163         }
1164     }
1165
1166   (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_START, NULL);
1167   
1168   /* fixme: check what data we can release here */
1169   return 0;
1170 }
1171
1172
1173 static gpgme_error_t
1174 gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1175 {
1176   GpgObject gpg = engine;
1177   gpgme_error_t err;
1178
1179   err = add_arg (gpg, "--decrypt");
1180
1181   /* Tell the gpg object about the data.  */
1182   if (!err)
1183     err = add_arg (gpg, "--output");
1184   if (!err)
1185     err = add_arg (gpg, "-");
1186   if (!err)
1187     err = add_data (gpg, plain, 1, 1);
1188   if (!err)
1189     err = add_data (gpg, ciph, 0, 0);
1190
1191   if (!err)
1192     start (gpg);
1193   return err;
1194 }
1195
1196 static gpgme_error_t
1197 gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
1198 {
1199   GpgObject gpg = engine;
1200   gpgme_error_t err;
1201
1202   err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
1203                  : "--delete-key");
1204   if (!err)
1205     err = add_arg (gpg, "--");
1206   if (!err)
1207     {
1208       if (!key->subkeys || !key->subkeys->fpr)
1209         err = GPGME_Invalid_Key;
1210       else
1211         err = add_arg (gpg, key->subkeys->fpr);
1212     }
1213
1214   if (!err)
1215     start (gpg);
1216   return err;
1217 }
1218
1219
1220 static gpgme_error_t
1221 append_args_from_signers (GpgObject gpg, gpgme_ctx_t ctx /* FIXME */)
1222 {
1223   gpgme_error_t err = 0;
1224   int i;
1225   gpgme_key_t key;
1226
1227   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1228     {
1229       const char *s = key->subkeys ? key->subkeys->keyid : NULL;
1230       if (s)
1231         {
1232           if (!err)
1233             err = add_arg (gpg, "-u");
1234           if (!err)
1235             err = add_arg (gpg, s);
1236         }
1237       gpgme_key_unref (key);
1238       if (err) break;
1239     }
1240   return err;
1241 }
1242
1243
1244 static gpgme_error_t
1245 gpg_edit (void *engine, gpgme_key_t key, gpgme_data_t out,
1246           gpgme_ctx_t ctx /* FIXME */)
1247 {
1248   GpgObject gpg = engine;
1249   gpgme_error_t err;
1250
1251   err = add_arg (gpg, "--with-colons");
1252   if (!err)
1253     err = append_args_from_signers (gpg, ctx);
1254   if (!err)
1255   err = add_arg (gpg, "--edit-key");
1256   if (!err)
1257     err = add_data (gpg, out, 1, 1);
1258   if (!err)
1259     err = add_arg (gpg, "--");
1260   if (!err)
1261     {
1262       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1263       if (!s)
1264         err = GPGME_Invalid_Key;
1265       else
1266         err = add_arg (gpg, s);
1267     }
1268   if (!err)
1269     err = start (gpg);
1270
1271   return err;
1272 }
1273
1274
1275 static gpgme_error_t
1276 append_args_from_recipients (GpgObject gpg, const gpgme_recipients_t rset)
1277 {
1278   gpgme_error_t err = 0;
1279   gpgme_user_id_t uid;
1280
1281   assert (rset);
1282   for (uid = rset->list; uid; uid = uid->next)
1283     {
1284       err = add_arg (gpg, "-r");
1285       if (!err)
1286         err = add_arg (gpg, uid->uid);
1287       if (err)
1288         break;
1289     }    
1290   return err;
1291 }
1292
1293
1294 static gpgme_error_t
1295 gpg_encrypt (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
1296              gpgme_data_t ciph, int use_armor)
1297 {
1298   GpgObject gpg = engine;
1299   gpgme_error_t err;
1300   int symmetric = !recp;
1301
1302   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1303
1304   if (!err && use_armor)
1305     err = add_arg (gpg, "--armor");
1306
1307   if (!symmetric)
1308     {
1309       /* If we know that all recipients are valid (full or ultimate trust)
1310          we can suppress further checks.  */
1311       if (!err && !symmetric && _gpgme_recipients_all_valid (recp))
1312         err = add_arg (gpg, "--always-trust");
1313
1314       if (!err)
1315         err = append_args_from_recipients (gpg, recp);
1316     }
1317
1318   /* Tell the gpg object about the data.  */
1319   if (!err)
1320     err = add_arg (gpg, "--output");
1321   if (!err)
1322     err = add_arg (gpg, "-");
1323   if (!err)
1324     err = add_data (gpg, ciph, 1, 1);
1325   if (!err)
1326     err = add_arg (gpg, "--");
1327   if (!err)
1328     err = add_data (gpg, plain, 0, 0);
1329
1330   if (!err)
1331     err = start (gpg);
1332
1333   return err;
1334 }
1335
1336
1337 static gpgme_error_t
1338 gpg_encrypt_sign (void *engine, gpgme_recipients_t recp, gpgme_data_t plain,
1339                   gpgme_data_t ciph, int use_armor,
1340                   gpgme_ctx_t ctx /* FIXME */)
1341 {
1342   GpgObject gpg = engine;
1343   gpgme_error_t err;
1344
1345   err = add_arg (gpg, "--encrypt");
1346   if (!err)
1347     err = add_arg (gpg, "--sign");
1348   if (!err && use_armor)
1349     err = add_arg (gpg, "--armor");
1350
1351   /* If we know that all recipients are valid (full or ultimate trust)
1352    * we can suppress further checks */
1353   if (!err && _gpgme_recipients_all_valid (recp))
1354     err = add_arg (gpg, "--always-trust");
1355
1356   if (!err)
1357     err = append_args_from_recipients (gpg, recp);
1358
1359   if (!err)
1360     err = append_args_from_signers (gpg, ctx);
1361
1362   /* Tell the gpg object about the data.  */
1363   if (!err)
1364     err = add_arg (gpg, "--output");
1365   if (!err)
1366     err = add_arg (gpg, "-");
1367   if (!err)
1368     err = add_data (gpg, ciph, 1, 1);
1369   if (!err)
1370     err = add_arg (gpg, "--");
1371   if (!err)
1372     err = add_data (gpg, plain, 0, 0);
1373
1374   if (!err)
1375     err = start (gpg);
1376
1377   return err;
1378 }
1379
1380
1381 static gpgme_error_t
1382 gpg_export (void *engine, gpgme_recipients_t recp, gpgme_data_t keydata,
1383             int use_armor)
1384 {
1385   GpgObject gpg = engine;
1386   gpgme_error_t err;
1387
1388   err = add_arg (gpg, "--export");
1389   if (!err && use_armor)
1390     err = add_arg (gpg, "--armor");
1391   if (!err)
1392     err = add_data (gpg, keydata, 1, 1);
1393   if (!err)
1394     err = add_arg (gpg, "--");
1395
1396   if (!err)
1397     {
1398       void *ec;
1399       const char *s;
1400
1401       err = gpgme_recipients_enum_open (recp, &ec);
1402       while (!err && (s = gpgme_recipients_enum_read (recp, &ec)))
1403         err = add_arg (gpg, s);
1404       if (!err)
1405         err = gpgme_recipients_enum_close (recp, &ec);
1406     }
1407
1408   if (!err)
1409     err = start (gpg);
1410
1411   return err;
1412 }
1413
1414
1415 static gpgme_error_t
1416 gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1417             gpgme_data_t pubkey, gpgme_data_t seckey)
1418 {
1419   GpgObject gpg = engine;
1420   gpgme_error_t err;
1421
1422   if (!gpg)
1423     return GPGME_Invalid_Value;
1424
1425   /* We need a special mechanism to get the fd of a pipe here, so that
1426      we can use this for the %pubring and %secring parameters.  We
1427      don't have this yet, so we implement only the adding to the
1428      standard keyrings.  */
1429   if (pubkey || seckey)
1430     return err = GPGME_Not_Implemented;
1431
1432   err = add_arg (gpg, "--gen-key");
1433   if (!err && use_armor)
1434     err = add_arg (gpg, "--armor");
1435   if (!err)
1436     err = add_data (gpg, help_data, 0, 0);
1437
1438   if (!err)
1439     err = start (gpg);
1440
1441   return err;
1442 }
1443
1444
1445 static gpgme_error_t
1446 gpg_import (void *engine, gpgme_data_t keydata)
1447 {
1448   GpgObject gpg = engine;
1449   gpgme_error_t err;
1450
1451   err = add_arg (gpg, "--import");
1452   if (!err)
1453     err = add_data (gpg, keydata, 0, 0);
1454
1455   if (!err)
1456     err = start (gpg);
1457
1458   return err;
1459 }
1460
1461
1462 static gpgme_error_t
1463 gpg_keylist (void *engine, const char *pattern, int secret_only,
1464              int keylist_mode)
1465 {
1466   GpgObject gpg = engine;
1467   gpgme_error_t err;
1468
1469   err = add_arg (gpg, "--with-colons");
1470   if (!err)
1471     err = add_arg (gpg, "--fixed-list-mode");
1472   if (!err)
1473     err = add_arg (gpg, "--with-fingerprint");
1474   if (!err)
1475     err = add_arg (gpg, "--with-fingerprint");
1476   if (!err)
1477     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1478                    : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1479                       ? "--check-sigs" : "--list-keys"));
1480   
1481   /* Tell the gpg object about the data.  */
1482   if (!err)
1483     err = add_arg (gpg, "--");
1484   if (!err && pattern && *pattern)
1485     err = add_arg (gpg, pattern);
1486
1487   if (!err)
1488     err = start (gpg);
1489
1490   return err;
1491 }
1492
1493
1494 static gpgme_error_t
1495 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
1496                  int reserved, int keylist_mode)
1497 {
1498   GpgObject gpg = engine;
1499   gpgme_error_t err;
1500
1501   if (reserved)
1502     return GPGME_Invalid_Value;
1503
1504   err = add_arg (gpg, "--with-colons");
1505   if (!err)
1506     err = add_arg (gpg, "--fixed-list-mode");
1507   if (!err)
1508     err = add_arg (gpg, "--with-fingerprint");
1509   if (!err)
1510     err = add_arg (gpg, "--with-fingerprint");
1511   if (!err)
1512     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1513                    : ((keylist_mode & GPGME_KEYLIST_MODE_SIGS)
1514                       ? "--check-sigs" : "--list-keys"));
1515
1516   /* Tell the gpg object about the data.  */
1517   if (!err)
1518     err = add_arg (gpg, "--");
1519   if (!err && pattern && *pattern)
1520     {
1521       while (*pattern && **pattern)
1522         err = add_arg (gpg, *(pattern++));
1523     }
1524
1525   if (!err)
1526     err = start (gpg);
1527
1528   return err;
1529 }
1530
1531
1532 static gpgme_error_t
1533 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1534           gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1535           int include_certs, gpgme_ctx_t ctx /* FIXME */)
1536 {
1537   GpgObject gpg = engine;
1538   gpgme_error_t err;
1539
1540   if (mode == GPGME_SIG_MODE_CLEAR)
1541     err = add_arg (gpg, "--clearsign");
1542   else
1543     {
1544       err = add_arg (gpg, "--sign");
1545       if (!err && mode == GPGME_SIG_MODE_DETACH)
1546         err = add_arg (gpg, "--detach");
1547       if (!err && use_armor)
1548         err = add_arg (gpg, "--armor");
1549       if (!err && use_textmode)
1550         add_arg (gpg, "--textmode");
1551     }
1552
1553   if (!err)
1554     err = append_args_from_signers (gpg, ctx);
1555
1556   /* Tell the gpg object about the data.  */
1557   if (!err)
1558     err = add_data (gpg, in, 0, 0);
1559   if (!err)
1560     err = add_data (gpg, out, 1, 1);
1561
1562   if (!err)
1563     start (gpg);
1564
1565   return err;
1566 }
1567
1568 static gpgme_error_t
1569 gpg_trustlist (void *engine, const char *pattern)
1570 {
1571   GpgObject gpg = engine;
1572   gpgme_error_t err;
1573
1574   err = add_arg (gpg, "--with-colons");
1575   if (!err)
1576     err = add_arg (gpg, "--list-trust-path");
1577   
1578   /* Tell the gpg object about the data.  */
1579   if (!err)
1580     err = add_arg (gpg, "--");
1581   if (!err)
1582     err = add_arg (gpg, pattern);
1583
1584   if (!err)
1585     err = start (gpg);
1586
1587   return err;
1588 }
1589
1590
1591 static gpgme_error_t
1592 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1593             gpgme_data_t plaintext)
1594 {
1595   GpgObject gpg = engine;
1596   gpgme_error_t err = 0;
1597
1598   if (plaintext)
1599     {
1600       /* Normal or cleartext signature.  */
1601
1602       err = add_arg (gpg, "--output");
1603       if (!err)
1604         err = add_arg (gpg, "-");
1605       if (!err)
1606         err = add_arg (gpg, "--");
1607       if (!err)
1608         err = add_data (gpg, sig, 0, 0);
1609       if (!err)
1610         err = add_data (gpg, plaintext, 1, 1);
1611     }
1612   else
1613     {
1614       err = add_arg (gpg, "--verify");
1615       if (!err)
1616         err = add_arg (gpg, "--");
1617       if (!err)
1618         err = add_data (gpg, sig, -1, 0);
1619       if (signed_text)
1620         {
1621           if (!err)
1622             err = add_arg (gpg, "-");
1623           if (!err)
1624             err = add_data (gpg, signed_text, 0, 0);
1625         }
1626     }
1627
1628   if (!err)
1629     err = start (gpg);
1630
1631   return err;
1632 }
1633
1634
1635 static void
1636 gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1637 {
1638   GpgObject gpg = engine;
1639
1640   gpg->io_cbs = *io_cbs;
1641 }
1642
1643 \f
1644 struct engine_ops _gpgme_engine_ops_gpg =
1645   {
1646     /* Static functions.  */
1647     _gpgme_get_gpg_path,
1648     gpg_get_version,
1649     gpg_get_req_version,
1650     gpg_new,
1651
1652     /* Member functions.  */
1653     gpg_release,
1654     gpg_set_status_handler,
1655     gpg_set_command_handler,
1656     gpg_set_colon_line_handler,
1657     gpg_decrypt,
1658     gpg_delete,
1659     gpg_edit,
1660     gpg_encrypt,
1661     gpg_encrypt_sign,
1662     gpg_export,
1663     gpg_genkey,
1664     gpg_import,
1665     gpg_keylist,
1666     gpg_keylist_ext,
1667     gpg_sign,
1668     gpg_trustlist,
1669     gpg_verify,
1670     gpg_set_io_cbs,
1671     gpg_io_event
1672   };