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