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