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