Fix copyright year.
[gpgme.git] / gpgme / rungpg.c
1 /* rungpg.c - Gpg Engine.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003 g10 Code GmbH
4  
5    This file is part of GPGME.
6  
7    GPGME is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11  
12    GPGME is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    General Public License for more details.
16  
17    You should have received a copy of the GNU General Public License
18    along with GPGME; if not, write to the Free Software Foundation,
19    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #if HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <sys/time.h>
31 #include <sys/types.h>
32 #include <signal.h>
33 #include <fcntl.h>
34 #include "unistd.h"
35
36 #include "gpgme.h"
37 #include "util.h"
38 #include "ops.h"
39 #include "wait.h"
40 #include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
41 #include "io.h"
42 #include "sema.h"
43
44 #include "status-table.h"
45 #include "engine-backend.h"
46
47
48 /* This type is used to build a list of gpg arguments and data
49    sources/sinks.  */
50 struct arg_and_data_s
51 {
52   struct arg_and_data_s *next;
53   GpgmeData data;  /* If this is not NULL, use arg below.  */
54   int inbound;     /* True if this is used for reading from gpg.  */
55   int dup_to;
56   int print_fd;    /* Print the fd number and not the special form of it.  */
57   char arg[1];     /* Used if data above is not used.  */
58 };
59
60
61 struct fd_data_map_s
62 {
63   GpgmeData data;
64   int inbound;  /* true if this is used for reading from gpg */
65   int dup_to;
66   int fd;       /* the fd to use */
67   int peer_fd;  /* the outher side of the pipe */
68   void *tag;
69 };
70
71
72 struct gpg_object_s
73 {
74   struct arg_and_data_s *arglist;
75   struct arg_and_data_s **argtail;
76   int arg_error;
77
78   struct
79   {
80     int fd[2];  
81     size_t bufsize;
82     char *buffer;
83     size_t readpos;
84     int eof;
85     GpgmeStatusHandler fnc;
86     void *fnc_value;
87     void *tag;
88   } status;
89
90   /* This is a kludge - see the comment at colon_line_handler.  */
91   struct
92   {
93     int fd[2];  
94     size_t bufsize;
95     char *buffer;
96     size_t readpos;
97     int eof;
98     GpgmeColonLineHandler fnc;  /* this indicate use of this structrue */
99     void *fnc_value;
100     void *tag;
101   } colon;
102
103   char **argv;  
104   struct fd_data_map_s *fd_data_map;
105
106   /* stuff needed for interactive (command) mode */
107   struct
108   {
109     int used;
110     int fd;
111     int idx;            /* Index in fd_data_map */
112     GpgmeData cb_data;   /* hack to get init the above idx later */
113     GpgmeStatusCode code;  /* last code */
114     char *keyword;       /* what has been requested (malloced) */
115     GpgmeCommandHandler fnc; 
116     void *fnc_value;
117     /* The kludges never end.  This is used to couple command handlers
118        with output data in edit key mode.  */
119     GpgmeData linked_data;
120     int linked_idx;
121   } cmd;
122
123   struct GpgmeIOCbs io_cbs;
124 };
125
126
127 static void
128 gpg_io_event (void *engine, GpgmeEventIO type, void *type_data)
129 {
130   GpgObject gpg = engine;
131
132   if (gpg->io_cbs.event)
133     (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
134 }
135
136
137 static void
138 close_notify_handler (int fd, void *opaque)
139 {
140   GpgObject gpg = opaque;
141   assert (fd != -1);
142
143   if (gpg->status.fd[0] == fd)
144     {
145       if (gpg->status.tag)
146         (*gpg->io_cbs.remove) (gpg->status.tag);
147       gpg->status.fd[0] = -1;
148     }
149   else if (gpg->status.fd[1] == fd)
150     gpg->status.fd[1] = -1;
151   else if (gpg->colon.fd[0] == fd)
152     {
153       if (gpg->colon.tag)
154         (*gpg->io_cbs.remove) (gpg->colon.tag);
155       gpg->colon.fd[0] = -1;
156     }
157   else if (gpg->colon.fd[1] == fd)
158     gpg->colon.fd[1] = -1;
159   else if (gpg->fd_data_map)
160     {
161       int i;
162
163       for (i = 0; gpg->fd_data_map[i].data; i++)
164         {
165           if (gpg->fd_data_map[i].fd == fd)
166             {
167               if (gpg->fd_data_map[i].tag)
168                 (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
169               gpg->fd_data_map[i].fd = -1;
170               break;
171             }
172           if (gpg->fd_data_map[i].peer_fd == fd)
173             {
174               gpg->fd_data_map[i].peer_fd = -1;
175               break;
176             }
177         }
178     }
179 }
180
181 static GpgmeError
182 add_arg (GpgObject gpg, const char *arg)
183 {
184   struct arg_and_data_s *a;
185
186   assert (gpg);
187   assert (arg);
188
189   a = malloc (sizeof *a + strlen (arg));
190   if (!a)
191     {
192       gpg->arg_error = 1;
193       return GPGME_Out_Of_Core;
194     }
195   a->next = NULL;
196   a->data = NULL;
197   a->dup_to = -1;
198   strcpy (a->arg, arg);
199   *gpg->argtail = a;
200   gpg->argtail = &a->next;
201   return 0;
202 }
203
204 static GpgmeError
205 add_data (GpgObject gpg, GpgmeData data, int dup_to, int inbound)
206 {
207   struct arg_and_data_s *a;
208
209   assert (gpg);
210   assert (data);
211
212   a = malloc (sizeof *a - 1);
213   if (!a)
214     {
215       gpg->arg_error = 1;
216       return GPGME_Out_Of_Core;
217     }
218   a->next = NULL;
219   a->data = data;
220   a->inbound = inbound;
221   if (dup_to == -2)
222     {
223       a->print_fd = 1;
224       a->dup_to = -1;
225     }
226   else
227     {
228       a->print_fd = 0;
229       a->dup_to = dup_to;
230     }
231   *gpg->argtail = a;
232   gpg->argtail = &a->next;
233   return 0;
234 }
235
236 \f
237 static const char *
238 gpg_get_version (void)
239 {
240   static const char *gpg_version;
241   DEFINE_STATIC_LOCK (gpg_version_lock);
242
243   LOCK (gpg_version_lock);
244   if (!gpg_version)
245     gpg_version = _gpgme_get_program_version (_gpgme_get_gpg_path ());
246   UNLOCK (gpg_version_lock);
247   return gpg_version;
248 }
249
250
251 static GpgmeError
252 gpg_check_version (void)
253 {
254   return _gpgme_compare_versions (gpg_get_version (), NEED_GPG_VERSION)
255     ? 0 : GPGME_Invalid_Engine;
256 }
257
258
259 static void
260 free_argv (char **argv)
261 {
262   int i;
263
264   for (i = 0; argv[i]; i++)
265     free (argv[i]);
266   free (argv);
267 }
268
269
270 static void
271 free_fd_data_map (struct fd_data_map_s *fd_data_map)
272 {
273   int i;
274
275   if (!fd_data_map)
276     return;
277
278   for (i = 0; fd_data_map[i].data; i++)
279     {
280       if (fd_data_map[i].fd != -1)
281         _gpgme_io_close (fd_data_map[i].fd);
282       if (fd_data_map[i].peer_fd != -1)
283         _gpgme_io_close (fd_data_map[i].peer_fd);
284       /* Don't release data because this is only a reference.  */
285     }
286   free (fd_data_map);
287 }
288
289
290 static void
291 gpg_release (void *engine)
292 {
293   GpgObject gpg = engine;
294
295   if (!gpg)
296     return;
297
298   while (gpg->arglist)
299     {
300       struct arg_and_data_s *next = gpg->arglist->next;
301
302       free (gpg->arglist);
303       gpg->arglist = next;
304     }
305
306   free (gpg->status.buffer);
307   free (gpg->colon.buffer);
308   if (gpg->argv)
309     free_argv (gpg->argv);
310   gpgme_data_release (gpg->cmd.cb_data);
311   free (gpg->cmd.keyword);
312
313   if (gpg->status.fd[0] != -1)
314     _gpgme_io_close (gpg->status.fd[0]);
315   if (gpg->status.fd[1] != -1)
316     _gpgme_io_close (gpg->status.fd[1]);
317   if (gpg->colon.fd[0] != -1)
318     _gpgme_io_close (gpg->colon.fd[0]);
319   if (gpg->colon.fd[1] != -1)
320     _gpgme_io_close (gpg->colon.fd[1]);
321   free_fd_data_map (gpg->fd_data_map);
322   if (gpg->cmd.fd != -1)
323     _gpgme_io_close (gpg->cmd.fd);
324   free (gpg);
325 }
326
327
328 static GpgmeError
329 gpg_new (void **engine)
330 {
331   GpgObject gpg;
332   int rc = 0;
333
334   gpg = calloc (1, sizeof *gpg);
335   if (!gpg)
336     {
337       rc = GPGME_Out_Of_Core;
338       goto leave;
339     }
340   gpg->argtail = &gpg->arglist;
341
342   gpg->status.fd[0] = -1;
343   gpg->status.fd[1] = -1;
344   gpg->colon.fd[0] = -1;
345   gpg->colon.fd[1] = -1;
346   gpg->cmd.fd = -1;
347   gpg->cmd.idx = -1;
348   gpg->cmd.linked_data = NULL;
349   gpg->cmd.linked_idx = -1;
350
351   /* Allocate the read buffer for the status pipe.  */
352   gpg->status.bufsize = 1024;
353   gpg->status.readpos = 0;
354   gpg->status.buffer = malloc (gpg->status.bufsize);
355   if (!gpg->status.buffer)
356     {
357       rc = GPGME_Out_Of_Core;
358       goto leave;
359     }
360   /* In any case we need a status pipe - create it right here and
361      don't handle it with our generic GpgmeData mechanism.  */
362   if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
363     {
364       rc = GPGME_Pipe_Error;
365       goto leave;
366     }
367   if (_gpgme_io_set_close_notify (gpg->status.fd[0],
368                                   close_notify_handler, gpg)
369       || _gpgme_io_set_close_notify (gpg->status.fd[1],
370                                      close_notify_handler, gpg))
371     {
372       rc = GPGME_General_Error;
373       goto leave;
374     }
375   gpg->status.eof = 0;
376   add_arg (gpg, "--status-fd");
377   {
378     char buf[25];
379     sprintf (buf, "%d", gpg->status.fd[1]);
380     add_arg (gpg, buf);
381   }
382   add_arg (gpg, "--no-tty");
383   add_arg (gpg, "--charset");
384   add_arg (gpg, "utf8");
385
386  leave:
387   if (rc)
388     gpg_release (gpg);
389   else
390     *engine = gpg;
391   return rc;
392 }
393
394
395 static GpgmeError
396 gpg_set_verbosity (void *engine, int verbosity)
397 {
398   GpgObject gpg = engine;
399
400   GpgmeError err = 0;
401   while (!err && verbosity-- > 0)
402     err = add_arg (gpg, "--verbose");
403   return err;
404 }
405
406 /* Note, that the status_handler is allowed to modifiy the args
407    value.  */
408 static void
409 gpg_set_status_handler (void *engine, GpgmeStatusHandler fnc, void *fnc_value)
410 {
411   GpgObject gpg = engine;
412
413   gpg->status.fnc = fnc;
414   gpg->status.fnc_value = fnc_value;
415 }
416
417 /* Kludge to process --with-colon output.  */
418 static GpgmeError
419 gpg_set_colon_line_handler (void *engine, GpgmeColonLineHandler fnc,
420                             void *fnc_value)
421 {
422   GpgObject gpg = engine;
423
424   gpg->colon.bufsize = 1024;
425   gpg->colon.readpos = 0;
426   gpg->colon.buffer = malloc (gpg->colon.bufsize);
427   if (!gpg->colon.buffer)
428     return GPGME_Out_Of_Core;
429
430   if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) 
431     {
432       free (gpg->colon.buffer);
433       gpg->colon.buffer = NULL;
434       return GPGME_Pipe_Error;
435     }
436   if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
437       || _gpgme_io_set_close_notify (gpg->colon.fd[1],
438                                      close_notify_handler, gpg))
439     return GPGME_General_Error;
440   gpg->colon.eof = 0;
441   gpg->colon.fnc = fnc;
442   gpg->colon.fnc_value = fnc_value;
443   return 0;
444 }
445
446
447 /* Here we handle --command-fd.  This works closely together with the
448    status handler.  */
449 static int
450 command_cb (void *opaque, char *buffer, size_t length, size_t *nread)
451 {
452   GpgObject gpg = opaque;
453   const char *value;
454   int value_len;
455
456   DEBUG0 ("command_cb: enter\n");
457   assert (gpg->cmd.used);
458   if (!buffer || !length || !nread)
459     return 0; /* These values are reserved for extensions.  */
460   *nread = 0;
461   if (!gpg->cmd.code)
462     {
463       DEBUG0 ("command_cb: no code\n");
464       return -1;
465     }
466     
467   if (!gpg->cmd.fnc)
468     {
469       DEBUG0 ("command_cb: no user cb\n");
470       return -1;
471     }
472
473   /* FIXME catch error */
474   gpg->cmd.fnc (gpg->cmd.fnc_value, 
475                 gpg->cmd.code, gpg->cmd.keyword, &value);
476   if (!value)
477     {
478       DEBUG0 ("command_cb: no data from user cb\n");
479       gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
480       return -1;
481     }
482
483   value_len = strlen (value);
484   if (value_len + 1 > length)
485     {
486       DEBUG0 ("command_cb: too much data from user cb\n");
487       gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
488       return -1;
489     }
490
491   memcpy (buffer, value, value_len);
492   if (!value_len || (value_len && value[value_len-1] != '\n')) 
493     buffer[value_len++] = '\n';
494   *nread = value_len;
495     
496   gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value, &value);
497   gpg->cmd.code = 0;
498   /* And sleep again until read_status will wake us up again.  */
499   /* XXX We must check if there are any more fds active after removing
500      this one.  */
501   (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
502   gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
503   gpg->fd_data_map[gpg->cmd.idx].fd = -1;
504
505   return 0;
506 }
507
508
509 /* The Fnc will be called to get a value for one of the commands with
510    a key KEY.  If the Code pssed to FNC is 0, the function may release
511    resources associated with the returned value from another call.  To
512    match such a second call to a first call, the returned value from
513    the first call is passed as keyword.  */
514 static GpgmeError
515 gpg_set_command_handler (void *engine, GpgmeCommandHandler fnc,
516                          void *fnc_value, GpgmeData linked_data)
517 {
518   GpgObject gpg = engine;
519   GpgmeData tmp;
520   GpgmeError err;
521
522   err = gpgme_data_new_with_read_cb (&tmp, command_cb, gpg);
523   if (err)
524     return err;
525         
526   add_arg (gpg, "--command-fd");
527   add_data (gpg, tmp, -2, 0);
528   gpg->cmd.cb_data = tmp;
529   gpg->cmd.fnc = fnc;
530   gpg->cmd.fnc_value = fnc_value;
531   gpg->cmd.linked_data = linked_data;
532   gpg->cmd.used = 1;
533   return 0;
534 }
535
536
537 static GpgmeError
538 build_argv (GpgObject gpg)
539 {
540   struct arg_and_data_s *a;
541   struct fd_data_map_s *fd_data_map;
542   size_t datac=0, argc=0;  
543   char **argv;
544   int need_special = 0;
545   int use_agent = 0;
546   char *p;
547
548   /* We don't want to use the agent with a malformed environment
549      variable.  This is only a very basic test but sufficient to make
550      our life in the regression tests easier. */
551   p = getenv ("GPG_AGENT_INFO");
552   use_agent = (p && strchr (p, ':'));
553        
554   if (gpg->argv)
555     {
556       free_argv (gpg->argv);
557       gpg->argv = NULL;
558     }
559   if (gpg->fd_data_map)
560     {
561       free_fd_data_map (gpg->fd_data_map);
562       gpg->fd_data_map = NULL;
563     }
564
565   argc++;       /* For argv[0].  */
566   for (a = gpg->arglist; a; a = a->next)
567     {
568       argc++;
569       if (a->data)
570         {
571           /*fprintf (stderr, "build_argv: data\n" );*/
572           datac++;
573           if (a->dup_to == -1 && !a->print_fd)
574             need_special = 1;
575         }
576       else
577         {
578           /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
579         }
580     }
581   if (need_special)
582     argc++;
583   if (use_agent)
584     argc++;
585   if (!gpg->cmd.used)
586     argc++;
587   argc += 2; /* --comment */
588
589   argv = calloc (argc + 1, sizeof *argv);
590   if (!argv)
591     return GPGME_Out_Of_Core;
592   fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
593   if (!fd_data_map)
594     {
595       free_argv (argv);
596       return GPGME_Out_Of_Core;
597     }
598
599   argc = datac = 0;
600   argv[argc] = strdup ("gpg"); /* argv[0] */
601   if (!argv[argc])
602     {
603       free (fd_data_map);
604       free_argv (argv);
605       return GPGME_Out_Of_Core;
606     }
607   argc++;
608   if (need_special)
609     {
610       argv[argc] = strdup ("--enable-special-filenames");
611       if (!argv[argc])
612         {
613           free (fd_data_map);
614           free_argv (argv);
615           return GPGME_Out_Of_Core;
616         }
617       argc++;
618     }
619   if (use_agent)
620     {
621       argv[argc] = strdup ("--use-agent");
622       if (!argv[argc])
623         {
624           free (fd_data_map);
625           free_argv (argv);
626           return GPGME_Out_Of_Core;
627         }
628       argc++;
629     }
630   if (!gpg->cmd.used)
631     {
632       argv[argc] = strdup ("--batch");
633       if (!argv[argc])
634         {
635           free (fd_data_map);
636           free_argv (argv);
637           return GPGME_Out_Of_Core;
638         }
639       argc++;
640     }
641   argv[argc] = strdup ("--comment");
642   if (!argv[argc])
643     {
644       free (fd_data_map);
645       free_argv (argv);
646       return GPGME_Out_Of_Core;
647     }
648   argc++;
649   argv[argc] = strdup ("");
650   if (!argv[argc])
651     {
652       free (fd_data_map);
653       free_argv (argv);
654       return GPGME_Out_Of_Core;
655     }
656   argc++;
657   for (a = gpg->arglist; a; a = a->next)
658     {
659       if (a->data)
660         {
661           /* Create a pipe to pass it down to gpg.  */
662           fd_data_map[datac].inbound = a->inbound;
663
664           /* Create a pipe.  */
665           {   
666             int fds[2];
667             
668             if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
669                 == -1)
670               {
671                 free (fd_data_map);
672                 free_argv (argv);
673                 return GPGME_Pipe_Error;
674               }
675             if (_gpgme_io_set_close_notify (fds[0],
676                                             close_notify_handler, gpg)
677                 || _gpgme_io_set_close_notify (fds[1],
678                                                close_notify_handler,
679                                                gpg))
680               {
681                 return GPGME_General_Error;
682               }
683             /* If the data_type is FD, we have to do a dup2 here.  */
684             if (fd_data_map[datac].inbound)
685               {
686                 fd_data_map[datac].fd       = fds[0];
687                 fd_data_map[datac].peer_fd  = fds[1];
688               }
689             else
690               {
691                 fd_data_map[datac].fd       = fds[1];
692                 fd_data_map[datac].peer_fd  = fds[0];
693               }
694           }
695
696           /* Hack to get hands on the fd later.  */
697           if (gpg->cmd.used)
698             {
699               if (gpg->cmd.cb_data == a->data)
700                 {
701                   assert (gpg->cmd.idx == -1);
702                   gpg->cmd.idx = datac;
703                 }
704               else if (gpg->cmd.linked_data == a->data)
705                 {
706                   assert (gpg->cmd.linked_idx == -1);
707                   gpg->cmd.linked_idx = datac;
708                 }
709             }
710
711           fd_data_map[datac].data = a->data;
712           fd_data_map[datac].dup_to = a->dup_to;
713           if (a->dup_to == -1)
714             {
715               argv[argc] = malloc (25);
716               if (!argv[argc])
717                 {
718                   free (fd_data_map);
719                   free_argv (argv);
720                   return GPGME_Out_Of_Core;
721                 }
722               sprintf (argv[argc], 
723                        a->print_fd ? "%d" : "-&%d",
724                        fd_data_map[datac].peer_fd);
725               argc++;
726             }
727           datac++;
728         }
729       else
730         {
731           argv[argc] = strdup (a->arg);
732           if (!argv[argc])
733             {
734               free (fd_data_map);
735               free_argv (argv);
736               return GPGME_Out_Of_Core;
737             }
738             argc++;
739         }
740     }
741
742   gpg->argv = argv;
743   gpg->fd_data_map = fd_data_map;
744   return 0;
745 }
746
747
748 static GpgmeError
749 add_io_cb (GpgObject gpg, int fd, int dir, GpgmeIOCb handler, void *data,
750            void **tag)
751 {
752   GpgmeError err;
753
754   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
755   if (err)
756     return err;
757   if (!dir)
758     /* FIXME Kludge around poll() problem.  */
759     err = _gpgme_io_set_nonblocking (fd);
760   return err;
761 }
762
763
764 static int
765 status_cmp (const void *ap, const void *bp)
766 {
767   const struct status_table_s *a = ap;
768   const struct status_table_s *b = bp;
769
770   return strcmp (a->name, b->name);
771 }
772
773
774 /* Handle the status output of GnuPG.  This function does read entire
775    lines and passes them as C strings to the callback function (we can
776    use C Strings because the status output is always UTF-8 encoded).
777    Of course we have to buffer the lines to cope with long lines
778    e.g. with a large user ID.  Note: We can optimize this to only cope
779    with status line code we know about and skip all other stuff
780    without buffering (i.e. without extending the buffer).  */
781 static GpgmeError
782 read_status (GpgObject gpg)
783 {
784   char *p;
785   int nread;
786   size_t bufsize = gpg->status.bufsize; 
787   char *buffer = gpg->status.buffer;
788   size_t readpos = gpg->status.readpos; 
789
790   assert (buffer);
791   if (bufsize - readpos < 256)
792     { 
793       /* Need more room for the read.  */
794       bufsize += 1024;
795       buffer = realloc (buffer, bufsize);
796       if (!buffer)
797         return GPGME_Out_Of_Core;
798     }
799
800   nread = _gpgme_io_read (gpg->status.fd[0],
801                           buffer + readpos, bufsize-readpos);
802   if (nread == -1)
803     return GPGME_Read_Error;
804
805   if (!nread)
806     {
807       gpg->status.eof = 1;
808       if (gpg->status.fnc)
809         gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
810       return 0;
811     }
812
813   while (nread > 0)
814     {
815       for (p = buffer + readpos; nread; nread--, p++)
816         {
817           if (*p == '\n')
818             {
819               /* (we require that the last line is terminated by a LF) */
820               *p = 0;
821               if (!strncmp (buffer, "[GNUPG:] ", 9)
822                   && buffer[9] >= 'A' && buffer[9] <= 'Z')
823                 {
824                   struct status_table_s t, *r;
825                   char *rest;
826
827                   rest = strchr (buffer + 9, ' ');
828                   if (!rest)
829                     rest = p; /* Set to an empty string.  */
830                   else
831                     *rest++ = 0;
832                     
833                   t.name = buffer+9;
834                   /* (the status table has one extra element) */
835                   r = bsearch (&t, status_table, DIM(status_table) - 1,
836                                sizeof t, status_cmp);
837                   if (r)
838                     {
839                       if (gpg->cmd.used
840                           && (r->code == GPGME_STATUS_GET_BOOL
841                               || r->code == GPGME_STATUS_GET_LINE
842                               || r->code == GPGME_STATUS_GET_HIDDEN))
843                         {
844                           gpg->cmd.code = r->code;
845                           free (gpg->cmd.keyword);
846                           gpg->cmd.keyword = strdup (rest);
847                           if (!gpg->cmd.keyword)
848                             return GPGME_Out_Of_Core;
849                           /* This should be the last thing we have
850                              received and the next thing will be that
851                              the command handler does its action.  */
852                           if (nread > 1)
853                             DEBUG0 ("ERROR, unexpected data in read_status");
854
855                           /* Before we can actually add the command
856                              fd, we might have to flush the linked
857                              output data pipe.  */
858                           if (gpg->cmd.linked_idx != -1
859                               && gpg->fd_data_map[gpg->cmd.linked_idx].fd != -1)
860                             {
861                               struct io_select_fd_s fds;
862                               fds.fd = gpg->fd_data_map[gpg->cmd.linked_idx].fd;
863                               fds.for_read = 1;
864                               fds.for_write = 0;
865                               fds.frozen = 0;
866                               fds.opaque = NULL;
867                               do
868                                 {
869                                   fds.signaled = 0;
870                                   _gpgme_io_select (&fds, 1, 1);
871                                   if (fds.signaled)
872                                     _gpgme_data_inbound_handler
873                                       (gpg->cmd.linked_data, fds.fd);
874                                 }
875                               while (fds.signaled);
876                             }
877
878                           add_io_cb (gpg, gpg->cmd.fd, 0,
879                                      _gpgme_data_outbound_handler,
880                                      gpg->fd_data_map[gpg->cmd.idx].data,
881                                      &gpg->fd_data_map[gpg->cmd.idx].tag);
882                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
883                           gpg->cmd.fd = -1;
884                         }
885                       else if (gpg->status.fnc)
886                         {
887                           gpg->status.fnc (gpg->status.fnc_value, 
888                                            r->code, rest);
889                         }
890                     
891                       if (r->code == GPGME_STATUS_END_STREAM)
892                         {
893                           if (gpg->cmd.used)
894                             {
895                               /* XXX We must check if there are any
896                                  more fds active after removing this
897                                  one.  */
898                               (*gpg->io_cbs.remove)
899                                 (gpg->fd_data_map[gpg->cmd.idx].tag);
900                               gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
901                               gpg->fd_data_map[gpg->cmd.idx].fd = -1;
902                             }
903                         }
904                     }
905                 }
906               /* To reuse the buffer for the next line we have to
907                  shift the remaining data to the buffer start and
908                  restart the loop Hmmm: We can optimize this function
909                  by looking forward in the buffer to see whether a
910                  second complete line is available and in this case
911                  avoid the memmove for this line.  */
912               nread--; p++;
913               if (nread)
914                 memmove (buffer, p, nread);
915               readpos = 0;
916               break; /* the for loop */
917             }
918           else
919             readpos++;
920         }
921     } 
922
923   /* Update the gpg object.  */
924   gpg->status.bufsize = bufsize;
925   gpg->status.buffer = buffer;
926   gpg->status.readpos = readpos;
927   return 0;
928 }
929
930
931 static GpgmeError
932 status_handler (void *opaque, int fd)
933 {
934   GpgObject gpg = opaque;
935   int err;
936
937   assert (fd == gpg->status.fd[0]);
938   err = read_status (gpg);
939   if (err)
940     {
941       DEBUG1 ("gpg_handler: read_status problem %d\n - stop", err);
942       _gpgme_io_close (fd);
943       return err;
944     }
945   if (gpg->status.eof)
946     _gpgme_io_close (fd);
947   return 0;
948 }
949
950
951 static GpgmeError
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 GpgmeData 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 GpgmeError
1030 colon_line_handler (void *opaque, int fd)
1031 {
1032   GpgObject gpg = opaque;
1033   GpgmeError 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 GpgmeError
1046 start (GpgObject gpg)
1047 {
1048   GpgmeError 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 GpgmeError
1174 gpg_decrypt (void *engine, GpgmeData ciph, GpgmeData plain)
1175 {
1176   GpgObject gpg = engine;
1177   GpgmeError 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 GpgmeError
1197 gpg_delete (void *engine, GpgmeKey key, int allow_secret)
1198 {
1199   GpgObject gpg = engine;
1200   GpgmeError 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       const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, NULL, 0);
1209       if (!s)
1210         err = GPGME_Invalid_Key;
1211       else
1212         err = add_arg (gpg, s);
1213     }
1214
1215   if (!err)
1216     start (gpg);
1217   return err;
1218 }
1219
1220
1221 static GpgmeError
1222 append_args_from_signers (GpgObject gpg, GpgmeCtx ctx /* FIXME */)
1223 {
1224   GpgmeError err = 0;
1225   int i;
1226   GpgmeKey key;
1227
1228   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1229     {
1230       const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID,
1231                                                  NULL, 0);
1232       if (s)
1233         {
1234           if (!err)
1235             err = add_arg (gpg, "-u");
1236           if (!err)
1237             err = add_arg (gpg, s);
1238         }
1239       gpgme_key_unref (key);
1240       if (err) break;
1241     }
1242   return err;
1243 }
1244
1245
1246 static GpgmeError
1247 gpg_edit (void *engine, GpgmeKey key, GpgmeData out, GpgmeCtx ctx /* FIXME */)
1248 {
1249   GpgObject gpg = engine;
1250   GpgmeError err;
1251
1252   err = add_arg (gpg, "--with-colons");
1253   if (!err)
1254     err = append_args_from_signers (gpg, ctx);
1255   if (!err)
1256   err = add_arg (gpg, "--edit-key");
1257   if (!err)
1258     err = add_data (gpg, out, 1, 1);
1259   if (!err)
1260     err = add_arg (gpg, "--");
1261   if (!err)
1262     {
1263       const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, NULL, 0);
1264       if (!s)
1265         err = GPGME_Invalid_Key;
1266       else
1267         err = add_arg (gpg, s);
1268     }
1269   if (!err)
1270     err = start (gpg);
1271
1272   return err;
1273 }
1274
1275
1276 static GpgmeError
1277 append_args_from_recipients (GpgObject gpg, const GpgmeRecipients rset)
1278 {
1279   GpgmeError err = 0;
1280   struct user_id_s *r;
1281
1282   assert (rset);
1283   for (r = rset->list; r; r = r->next)
1284     {
1285       err = add_arg (gpg, "-r");
1286       if (!err)
1287         err = add_arg (gpg, r->name);
1288       if (err)
1289         break;
1290     }    
1291   return err;
1292 }
1293
1294
1295 static GpgmeError
1296 gpg_encrypt (void *engine, GpgmeRecipients recp, GpgmeData plain,
1297              GpgmeData ciph, int use_armor)
1298 {
1299   GpgObject gpg = engine;
1300   GpgmeError err;
1301   int symmetric = !recp;
1302
1303   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1304
1305   if (!err && use_armor)
1306     err = add_arg (gpg, "--armor");
1307
1308   if (!symmetric)
1309     {
1310       /* If we know that all recipients are valid (full or ultimate trust)
1311          we can suppress further checks.  */
1312       if (!err && !symmetric && _gpgme_recipients_all_valid (recp))
1313         err = add_arg (gpg, "--always-trust");
1314
1315       if (!err)
1316         err = append_args_from_recipients (gpg, recp);
1317     }
1318
1319   /* Tell the gpg object about the data.  */
1320   if (!err)
1321     err = add_arg (gpg, "--output");
1322   if (!err)
1323     err = add_arg (gpg, "-");
1324   if (!err)
1325     err = add_data (gpg, ciph, 1, 1);
1326   if (!err)
1327     err = add_arg (gpg, "--");
1328   if (!err)
1329     err = add_data (gpg, plain, 0, 0);
1330
1331   if (!err)
1332     err = start (gpg);
1333
1334   return err;
1335 }
1336
1337
1338 static GpgmeError
1339 gpg_encrypt_sign (void *engine, GpgmeRecipients recp, GpgmeData plain,
1340                   GpgmeData ciph, int use_armor, GpgmeCtx ctx /* FIXME */)
1341 {
1342   GpgObject gpg = engine;
1343   GpgmeError 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 GpgmeError
1382 gpg_export (void *engine, GpgmeRecipients recp, GpgmeData keydata,
1383             int use_armor)
1384 {
1385   GpgObject gpg = engine;
1386   GpgmeError 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 GpgmeError
1416 gpg_genkey (void *engine, GpgmeData help_data, int use_armor,
1417             GpgmeData pubkey, GpgmeData seckey)
1418 {
1419   GpgObject gpg = engine;
1420   GpgmeError 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 GpgmeError
1446 gpg_import (void *engine, GpgmeData keydata)
1447 {
1448   GpgObject gpg = engine;
1449   GpgmeError 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 GpgmeError
1463 gpg_keylist (void *engine, const char *pattern, int secret_only,
1464              int keylist_mode)
1465 {
1466   GpgObject gpg = engine;
1467   GpgmeError 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 GpgmeError
1495 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
1496                  int reserved, int keylist_mode)
1497 {
1498   GpgObject gpg = engine;
1499   GpgmeError 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 GpgmeError
1533 gpg_sign (void *engine, GpgmeData in, GpgmeData out, GpgmeSigMode mode,
1534           int use_armor, int use_textmode, int include_certs,
1535           GpgmeCtx ctx /* FIXME */)
1536 {
1537   GpgObject gpg = engine;
1538   GpgmeError 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 GpgmeError
1569 gpg_trustlist (void *engine, const char *pattern)
1570 {
1571   GpgObject gpg = engine;
1572   GpgmeError 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 GpgmeError
1592 gpg_verify (void *engine, GpgmeData sig, GpgmeData signed_text,
1593             GpgmeData plaintext)
1594 {
1595   GpgObject gpg = engine;
1596   GpgmeError 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, struct GpgmeIOCbs *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_check_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_set_verbosity,
1658     gpg_decrypt,
1659     gpg_delete,
1660     gpg_edit,
1661     gpg_encrypt,
1662     gpg_encrypt_sign,
1663     gpg_export,
1664     gpg_genkey,
1665     gpg_import,
1666     gpg_keylist,
1667     gpg_keylist_ext,
1668     gpg_sign,
1669     gpg_trustlist,
1670     gpg_verify,
1671     gpg_set_io_cbs,
1672     gpg_io_event
1673   };