404f7feccadffae0d2ecf10bf88660ea22effefe
[gpgme.git] / gpgme / rungpg.c
1 /* rungpg.c 
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26 #include <errno.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <signal.h>
30 #include <fcntl.h>
31 #include "unistd.h"
32
33 #include "gpgme.h"
34 #include "util.h"
35 #include "ops.h"
36 #include "wait.h"
37 #include "rungpg.h"
38 #include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
39 #include "io.h"
40 #include "sema.h"
41
42 #include "status-table.h"
43
44
45 /* This type is used to build a list of gpg arguments and
46  * data sources/sinks */
47 struct arg_and_data_s {
48     struct arg_and_data_s *next;
49     GpgmeData data;  /* If this is not NULL .. */
50     int dup_to;
51     int print_fd;    /* print the fd number and not the special form of it */
52     char arg[1];     /* .. this is used */
53 };
54
55 struct fd_data_map_s {
56     GpgmeData data;
57     int inbound;  /* true if this is used for reading from gpg */
58     int dup_to;
59     int fd;       /* the fd to use */
60     int peer_fd;  /* the outher side of the pipe */
61 };
62
63
64 struct gpg_object_s {
65     struct arg_and_data_s *arglist;
66     struct arg_and_data_s **argtail;
67     int arg_error;  
68
69     struct {
70         int fd[2];  
71         size_t bufsize;
72         char *buffer;
73         size_t readpos;
74         int eof;
75         GpgStatusHandler fnc;
76         void *fnc_value;
77     } status;
78
79     /* This is a kludge - see the comment at gpg_colon_line_handler */
80     struct {
81         int fd[2];  
82         size_t bufsize;
83         char *buffer;
84         size_t readpos;
85         int eof;
86         GpgColonLineHandler fnc;  /* this indicate use of this structrue */
87         void *fnc_value;
88         int simple;
89     } colon;
90
91     char **argv;  
92     struct fd_data_map_s *fd_data_map;
93
94     int pid; /* we can't use pid_t because we don't use it in Windoze */
95
96     int running;
97     
98     /* stuff needed for pipemode */
99     struct {
100         int used;
101         int active;
102         GpgmeData sig;
103         GpgmeData text;
104         int stream_started;
105     } pm;
106
107     /* stuff needed for interactive (command) mode */
108     struct {
109         int used;
110         int fd;
111         GpgmeData cb_data;   /* hack to get init the above fd later */
112         GpgStatusCode code;  /* last code */
113         char *keyword;       /* what has been requested (malloced) */
114         GpgCommandHandler fnc; 
115         void *fnc_value;
116     } cmd;
117 };
118
119 struct reap_s {
120     struct reap_s *next;
121     int pid;
122     time_t entered;
123     int term_send;
124 };
125
126 static struct reap_s *reap_list;
127 DEFINE_STATIC_LOCK (reap_list_lock);
128
129
130 static void free_argv ( char **argv );
131 static void free_fd_data_map ( struct fd_data_map_s *fd_data_map );
132
133 static int gpg_inbound_handler ( void *opaque, int pid, int fd );
134 static int gpg_outbound_handler ( void *opaque, int pid, int fd );
135
136 static int gpg_status_handler ( void *opaque, int pid, int fd );
137 static GpgmeError read_status ( GpgObject gpg );
138
139 static int gpg_colon_line_handler ( void *opaque, int pid, int fd );
140 static GpgmeError read_colon_line ( GpgObject gpg );
141
142 static int pipemode_cb ( void *opaque,
143                          char *buffer, size_t length, size_t *nread );
144 static int command_cb ( void *opaque,
145                         char *buffer, size_t length, size_t *nread );
146
147
148 static void
149 close_notify_handler ( int fd, void *opaque )
150 {
151     GpgObject gpg = opaque;
152
153     assert (fd != -1);
154     if (gpg->status.fd[0] == fd )
155         gpg->status.fd[0] = -1;
156     else if (gpg->status.fd[1] == fd )
157         gpg->status.fd[1] = -1;
158     else if (gpg->colon.fd[0] == fd )
159         gpg->colon.fd[0] = -1;
160     else if (gpg->colon.fd[1] == fd )
161         gpg->colon.fd[1] = -1;
162     else if (gpg->fd_data_map) {
163         int i;
164
165         for (i=0; gpg->fd_data_map[i].data; i++ ) {
166             if ( gpg->fd_data_map[i].fd == fd ) {
167                 gpg->fd_data_map[i].fd = -1;
168                 break;
169             }
170             if ( gpg->fd_data_map[i].peer_fd == fd ) {
171                 gpg->fd_data_map[i].peer_fd = -1;
172                 break;
173             }
174         }
175     }
176 }
177
178
179
180
181 GpgmeError
182 _gpgme_gpg_new ( GpgObject *r_gpg )
183 {
184     GpgObject gpg;
185     int rc = 0;
186
187     gpg = xtrycalloc ( 1, sizeof *gpg );
188     if ( !gpg ) {
189         rc = mk_error (Out_Of_Core);
190         goto leave;
191     }
192     gpg->argtail = &gpg->arglist;
193
194     gpg->status.fd[0] = -1;
195     gpg->status.fd[1] = -1;
196     gpg->colon.fd[0] = -1;
197     gpg->colon.fd[1] = -1;
198     gpg->cmd.fd = -1;
199
200     gpg->pid = -1;
201
202     /* allocate the read buffer for the status pipe */
203     gpg->status.bufsize = 1024;
204     gpg->status.readpos = 0;
205     gpg->status.buffer = xtrymalloc (gpg->status.bufsize);
206     if (!gpg->status.buffer) {
207         rc = mk_error (Out_Of_Core);
208         goto leave;
209     }
210     /* In any case we need a status pipe - create it right here  and
211      * don't handle it with our generic GpgmeData mechanism */
212     if (_gpgme_io_pipe (gpg->status.fd, 1) == -1) {
213         rc = mk_error (Pipe_Error);
214         goto leave;
215     }
216     if ( _gpgme_io_set_close_notify (gpg->status.fd[0],
217                                      close_notify_handler, gpg)
218          || _gpgme_io_set_close_notify (gpg->status.fd[1],
219                                         close_notify_handler, gpg) ) {
220         rc = mk_error (General_Error);
221         goto leave;
222     }
223     gpg->status.eof = 0;
224     _gpgme_gpg_add_arg ( gpg, "--status-fd" );
225     {
226         char buf[25];
227         sprintf ( buf, "%d", gpg->status.fd[1]);
228         _gpgme_gpg_add_arg ( gpg, buf );
229     }
230     _gpgme_gpg_add_arg ( gpg, "--no-tty" );
231
232
233  leave:
234     if (rc) {
235         _gpgme_gpg_release (gpg);
236         *r_gpg = NULL;
237     }
238     else
239         *r_gpg = gpg;
240     return rc;
241 }
242
243
244 void
245 _gpgme_gpg_release ( GpgObject gpg )
246 {
247     if ( !gpg )
248         return;
249     xfree (gpg->status.buffer);
250     xfree (gpg->colon.buffer);
251     if ( gpg->argv )
252         free_argv (gpg->argv);
253     xfree (gpg->cmd.keyword);
254
255     if (gpg->pid != -1) 
256         _gpgme_remove_proc_from_wait_queue ( gpg->pid );
257     if (gpg->status.fd[0] != -1 )
258         _gpgme_io_close (gpg->status.fd[0]);
259     if (gpg->status.fd[1] != -1 )
260         _gpgme_io_close (gpg->status.fd[1]);
261     if (gpg->colon.fd[0] != -1 )
262         _gpgme_io_close (gpg->colon.fd[0]);
263     if (gpg->colon.fd[1] != -1 )
264         _gpgme_io_close (gpg->colon.fd[1]);
265     free_fd_data_map (gpg->fd_data_map);
266     if (gpg->running) {
267         int pid = gpg->pid;
268         struct reap_s *r;
269
270         /* resuse the memory, so that we don't need to allocate another
271          * mem block and have to handle errors */
272         assert (sizeof *r < sizeof *gpg );
273         r = (void*)gpg;
274         memset (r, 0, sizeof *r);
275         r->pid = pid;
276         r->entered = time (NULL);
277         LOCK(reap_list_lock);
278         r->next = reap_list;
279         reap_list = r;
280         UNLOCK(reap_list_lock);
281     }
282     else
283         xfree (gpg);
284 }
285
286
287 static void
288 do_reaping (void)
289 {
290     struct reap_s *r, *rlast;
291     static time_t last_check;
292     time_t cur_time = time (NULL);
293
294     /* a race does not matter here */
295     if (!last_check)
296         last_check = time(NULL);
297
298     if (last_check >= cur_time)
299         return;  /* we check only every second */
300
301     /* fixme: it would be nice if to have a TRYLOCK here */
302     LOCK (reap_list_lock);  
303     for (r=reap_list,rlast=NULL; r ; rlast=r, r=r?r->next:NULL) {
304         int dummy1, dummy2;
305
306         if ( _gpgme_io_waitpid (r->pid, 0, &dummy1, &dummy2) ) {
307             /* process has terminated - remove it from the queue */
308             void *p = r;
309             if (!rlast) {
310                 reap_list = r->next;
311                 r = reap_list;
312             }
313             else {
314                 rlast->next = r->next;
315                 r = rlast;
316             }
317             xfree (p);
318         }
319         else if ( !r->term_send ) {
320             if( r->entered+1 >= cur_time ) {
321                 _gpgme_io_kill ( r->pid, 0);
322                 r->term_send = 1;
323                 r->entered = cur_time;
324             }
325         }
326         else {
327             /* give it 5 second before we are going to send the killer */
328             if ( r->entered+5 >= cur_time ) {
329                 _gpgme_io_kill (r->pid, 1);
330                 r->entered = cur_time; /* just in case we have to repat it */
331             }
332         }
333     }
334     UNLOCK (reap_list_lock);  
335 }
336
337 void
338 _gpgme_gpg_housecleaning ()
339 {
340     do_reaping ();
341 }
342
343 void
344 _gpgme_gpg_enable_pipemode ( GpgObject gpg )
345 {
346     gpg->pm.used = 1;
347     assert ( !gpg->pm.sig );
348     assert ( !gpg->pm.text );
349 }
350     
351 GpgmeError
352 _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg )
353 {
354     struct arg_and_data_s *a;
355
356     assert (gpg);
357     assert (arg);
358
359     if (gpg->pm.active)
360         return 0;
361
362     a = xtrymalloc ( sizeof *a + strlen (arg) );
363     if ( !a ) {
364         gpg->arg_error = 1;
365         return mk_error(Out_Of_Core);
366     }
367     a->next = NULL;
368     a->data = NULL;
369     a->dup_to = -1;
370     strcpy ( a->arg, arg );
371     *gpg->argtail = a;
372     gpg->argtail = &a->next;
373     return 0;
374 }
375
376 GpgmeError
377 _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to )
378 {
379     struct arg_and_data_s *a;
380
381     assert (gpg);
382     assert (data);
383     if (gpg->pm.active)
384         return 0;
385
386     a = xtrymalloc ( sizeof *a - 1 );
387     if ( !a ) {
388         gpg->arg_error = 1;
389         return mk_error(Out_Of_Core);
390     }
391     a->next = NULL;
392     a->data = data;
393     if ( dup_to == -2 ) {
394         a->print_fd = 1;
395         a->dup_to = -1;
396     }
397     else {
398         a->print_fd = 0;
399         a->dup_to = dup_to;
400     }
401     *gpg->argtail = a;
402     gpg->argtail = &a->next;
403     return 0;
404 }
405
406 GpgmeError
407 _gpgme_gpg_add_pm_data ( GpgObject gpg, GpgmeData data, int what )
408 {
409     GpgmeError rc=0;
410
411     assert ( gpg->pm.used );
412     
413     if ( !what ) {
414         /* the signature */
415         assert ( !gpg->pm.sig );
416         gpg->pm.sig = data;
417     }
418     else if (what == 1) {
419         /* the signed data */
420         assert ( !gpg->pm.text );
421         gpg->pm.text = data;
422     }
423     else {
424         assert (0);
425     }
426
427     if ( gpg->pm.sig && gpg->pm.text ) {
428         if ( !gpg->pm.active ) {
429             /* create the callback handler and connect it to stdin */
430             GpgmeData tmp;
431             
432             rc = gpgme_data_new_with_read_cb ( &tmp, pipemode_cb, gpg );
433             if (!rc )
434                 rc = _gpgme_gpg_add_data (gpg, tmp, 0);
435         }
436         if ( !rc ) {
437             /* here we can reset the handler stuff */
438             gpg->pm.stream_started = 0;
439         }
440     }
441
442     return rc;
443 }
444
445 /*
446  * Note, that the status_handler is allowed to modifiy the args value
447  */
448 void
449 _gpgme_gpg_set_status_handler ( GpgObject gpg,
450                                 GpgStatusHandler fnc, void *fnc_value ) 
451 {
452     assert (gpg);
453     if (gpg->pm.active)
454         return;
455
456     gpg->status.fnc = fnc;
457     gpg->status.fnc_value = fnc_value;
458 }
459
460 /* Kludge to process --with-colon output */
461 GpgmeError
462 _gpgme_gpg_set_colon_line_handler ( GpgObject gpg,
463                                     GpgColonLineHandler fnc, void *fnc_value ) 
464 {
465     assert (gpg);
466     if (gpg->pm.active)
467         return 0;
468
469     gpg->colon.bufsize = 1024;
470     gpg->colon.readpos = 0;
471     gpg->colon.buffer = xtrymalloc (gpg->colon.bufsize);
472     if (!gpg->colon.buffer) {
473         return mk_error (Out_Of_Core);
474     }
475     if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) {
476         xfree (gpg->colon.buffer); gpg->colon.buffer = NULL;
477         return mk_error (Pipe_Error);
478     }
479     if ( _gpgme_io_set_close_notify (gpg->colon.fd[0],
480                                      close_notify_handler, gpg)
481          ||  _gpgme_io_set_close_notify (gpg->colon.fd[1],
482                                          close_notify_handler, gpg) ) {
483         return mk_error (General_Error);
484     }
485     gpg->colon.eof = 0;
486     gpg->colon.fnc = fnc;
487     gpg->colon.fnc_value = fnc_value;
488     gpg->colon.simple = 0;
489     return 0;
490 }
491
492
493 GpgmeError
494 _gpgme_gpg_set_simple_line_handler ( GpgObject gpg,
495                                      GpgColonLineHandler fnc,
496                                      void *fnc_value ) 
497 {
498     GpgmeError err;
499
500     err = _gpgme_gpg_set_colon_line_handler (gpg, fnc, fnc_value);
501     if (!err)
502         gpg->colon.simple = 1;
503     return err;
504 }
505
506
507 /* 
508  * The Fnc will be called to get a value for one of the commands with
509  * a key KEY.  If the Code pssed to FNC is 0, the function may release
510  * resources associated with the returned value from another call.  To
511  * match such a second call to a first call, the returned value from
512  * the first call is passed as keyword.
513  */
514
515 GpgmeError
516 _gpgme_gpg_set_command_handler ( GpgObject gpg,
517                                  GpgCommandHandler fnc, void *fnc_value ) 
518 {
519     GpgmeData tmp;
520     GpgmeError err;
521
522     assert (gpg);
523     if (gpg->pm.active)
524         return 0;
525
526     err = gpgme_data_new_with_read_cb ( &tmp, command_cb, gpg );
527     if (err)
528         return err;
529         
530     _gpgme_gpg_add_arg ( gpg, "--command-fd" );
531     _gpgme_gpg_add_data (gpg, tmp, -2);
532     gpg->cmd.cb_data = tmp;
533     gpg->cmd.fnc = fnc;
534     gpg->cmd.fnc_value = fnc_value;
535     gpg->cmd.used = 1;
536     return 0;
537 }
538
539
540 static void
541 free_argv ( char **argv )
542 {
543     int i;
544
545     for (i=0; argv[i]; i++ )
546         xfree (argv[i]);
547     xfree (argv);
548 }
549
550 static void
551 free_fd_data_map ( struct fd_data_map_s *fd_data_map )
552 {
553     int i;
554
555     if ( !fd_data_map )
556         return;
557
558     for (i=0; fd_data_map[i].data; i++ ) {
559         if ( fd_data_map[i].fd != -1 )
560             _gpgme_io_close (fd_data_map[i].fd);
561         if ( fd_data_map[i].peer_fd != -1 )
562             _gpgme_io_close (fd_data_map[i].peer_fd);
563         /* don't release data because this is only a reference */
564     }
565     xfree (fd_data_map);
566 }
567
568
569 static GpgmeError
570 build_argv ( GpgObject gpg )
571 {
572     struct arg_and_data_s *a;
573     struct fd_data_map_s *fd_data_map;
574     size_t datac=0, argc=0;  
575     char **argv;
576     int need_special = 0;
577     int use_agent = !!getenv ("GPG_AGENT_INFO");
578        
579     if ( gpg->argv ) {
580         free_argv ( gpg->argv );
581         gpg->argv = NULL;
582     }
583     if (gpg->fd_data_map) {
584         free_fd_data_map (gpg->fd_data_map);
585         gpg->fd_data_map = NULL;
586     }
587
588     argc++; /* for argv[0] */
589     for ( a=gpg->arglist; a; a = a->next ) {
590         argc++;
591         if (a->data) {
592             /*fprintf (stderr, "build_argv: data\n" );*/
593             datac++;
594             if ( a->dup_to == -1 && !a->print_fd )
595                 need_special = 1;
596         }
597         else {
598             /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
599         }
600     }
601     if ( need_special )
602         argc++;
603     if (use_agent)
604         argc++;
605     if (!gpg->cmd.used)
606         argc++;
607
608     argv = xtrycalloc ( argc+1, sizeof *argv );
609     if (!argv)
610         return mk_error (Out_Of_Core);
611     fd_data_map = xtrycalloc ( datac+1, sizeof *fd_data_map );
612     if (!fd_data_map) {
613         free_argv (argv);
614         return mk_error (Out_Of_Core);
615     }
616
617     argc = datac = 0;
618     argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */
619     if (!argv[argc]) {
620         xfree (fd_data_map);
621         free_argv (argv);
622         return mk_error (Out_Of_Core);
623     }
624     argc++;
625     if ( need_special ) {
626         argv[argc] = xtrystrdup ( "--enable-special-filenames" );
627         if (!argv[argc]) {
628             xfree (fd_data_map);
629             free_argv (argv);
630             return mk_error (Out_Of_Core);
631         }
632         argc++;
633     }
634     if ( use_agent ) {
635         argv[argc] = xtrystrdup ( "--use-agent" );
636         if (!argv[argc]) {
637             xfree (fd_data_map);
638             free_argv (argv);
639             return mk_error (Out_Of_Core);
640         }
641         argc++;
642     }
643     if ( !gpg->cmd.used ) {
644         argv[argc] = xtrystrdup ( "--batch" );
645         if (!argv[argc]) {
646             xfree (fd_data_map);
647             free_argv (argv);
648             return mk_error (Out_Of_Core);
649         }
650         argc++;
651     }
652     for ( a=gpg->arglist; a; a = a->next ) {
653         if ( a->data ) {
654             switch ( _gpgme_data_get_mode (a->data) ) {
655               case GPGME_DATA_MODE_NONE:
656               case GPGME_DATA_MODE_INOUT:
657                 xfree (fd_data_map);
658                 free_argv (argv);
659                 return mk_error (Invalid_Mode);
660               case GPGME_DATA_MODE_IN:
661                 /* create a pipe to read from gpg */
662                 fd_data_map[datac].inbound = 1;
663                 break;
664               case GPGME_DATA_MODE_OUT:
665                 /* create a pipe to pass it down to gpg */
666                 fd_data_map[datac].inbound = 0;
667                 break;
668             }
669
670             switch ( gpgme_data_get_type (a->data) ) {
671               case GPGME_DATA_TYPE_NONE:
672                 if ( fd_data_map[datac].inbound )
673                     break;  /* allowed */
674                 xfree (fd_data_map);
675                 free_argv (argv);
676                 return mk_error (Invalid_Type);
677               case GPGME_DATA_TYPE_MEM:
678               case GPGME_DATA_TYPE_CB:
679                 break;
680               case GPGME_DATA_TYPE_FD:
681               case GPGME_DATA_TYPE_FILE:
682                 xfree (fd_data_map);
683                 free_argv (argv);
684                 return mk_error (Not_Implemented);
685             }
686   
687             /* create a pipe */
688             {   
689                 int fds[2];
690                 
691                 if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound?1:0 )
692                     == -1) {
693                     xfree (fd_data_map);
694                     free_argv (argv);
695                     return mk_error (Pipe_Error);
696                 }
697                 if ( _gpgme_io_set_close_notify (fds[0],
698                                                  close_notify_handler, gpg)
699                      || _gpgme_io_set_close_notify (fds[1],
700                                                     close_notify_handler,
701                                                     gpg)) {
702                     return mk_error (General_Error);
703                 }
704                 /* if the data_type is FD, we have to do a dup2 here */
705                 if (fd_data_map[datac].inbound) {
706                     fd_data_map[datac].fd       = fds[0];
707                     fd_data_map[datac].peer_fd  = fds[1];
708                 }
709                 else {
710                     fd_data_map[datac].fd       = fds[1];
711                     fd_data_map[datac].peer_fd  = fds[0];
712                 }
713             }
714
715             /* Hack to get hands on the fd later */
716             if ( gpg->cmd.used && gpg->cmd.cb_data == a->data ) {
717                 assert (gpg->cmd.fd == -1);
718                 gpg->cmd.fd = fd_data_map[datac].fd;
719             }
720
721             fd_data_map[datac].data = a->data;
722             fd_data_map[datac].dup_to = a->dup_to;
723             if ( a->dup_to == -1 ) {
724                 argv[argc] = xtrymalloc ( 25 );
725                 if (!argv[argc]) {
726                     xfree (fd_data_map);
727                     free_argv (argv);
728                     return mk_error (Out_Of_Core);
729                 }
730                 sprintf ( argv[argc], 
731                           a->print_fd? "%d" : "-&%d",
732                           fd_data_map[datac].peer_fd );
733                 argc++;
734             }
735             datac++;
736         }
737         else {
738             argv[argc] = xtrystrdup ( a->arg );
739             if (!argv[argc]) {
740                 xfree (fd_data_map);
741                 free_argv (argv);
742                 return mk_error (Out_Of_Core);
743             }
744             argc++;
745         }
746     }
747
748     gpg->argv = argv;
749     gpg->fd_data_map = fd_data_map;
750     return 0;
751 }
752
753 GpgmeError
754 _gpgme_gpg_spawn( GpgObject gpg, void *opaque )
755 {
756     int rc;
757     int i, n;
758     int pid;
759     struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
760
761     if ( !gpg )
762         return mk_error (Invalid_Value);
763
764     /* Kludge, so that we don't need to check the return code of
765      * all the gpgme_gpg_add_arg().  we bail out here instead */
766     if ( gpg->arg_error )
767         return mk_error (Out_Of_Core);
768
769     if (gpg->pm.active)
770         return 0;
771
772     rc = build_argv ( gpg );
773     if ( rc )
774         return rc;
775
776     n = 4; /* status fd, 2*colon_fd and end of list */
777     for (i=0; gpg->fd_data_map[i].data; i++ ) 
778         n += 2;
779     fd_child_list = xtrycalloc ( n+n, sizeof *fd_child_list );
780     if (!fd_child_list)
781         return mk_error (Out_Of_Core);
782     fd_parent_list = fd_child_list + n;
783
784     /* build the fd list for the child */
785     n=0;
786     fd_child_list[n].fd = gpg->status.fd[0]; 
787     fd_child_list[n].dup_to = -1;
788     n++;
789     if ( gpg->colon.fnc ) {
790         fd_child_list[n].fd = gpg->colon.fd[0];
791         fd_child_list[n].dup_to = -1;
792         n++;
793         fd_child_list[n].fd = gpg->colon.fd[1]; 
794         fd_child_list[n].dup_to = 1; /* dup to stdout */
795         n++;
796     }
797     for (i=0; gpg->fd_data_map[i].data; i++ ) {
798         fd_child_list[n].fd = gpg->fd_data_map[i].fd;
799         fd_child_list[n].dup_to = -1;
800         n++;
801         if (gpg->fd_data_map[i].dup_to != -1) {
802             fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
803             fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
804             n++;
805         }
806     }
807     fd_child_list[n].fd = -1;
808     fd_child_list[n].dup_to = -1;
809
810     /* build the fd list for the parent */
811     n=0;
812     if ( gpg->status.fd[1] != -1 ) {
813         fd_parent_list[n].fd = gpg->status.fd[1];
814         fd_parent_list[n].dup_to = -1;
815         n++;
816         gpg->status.fd[1] = -1;
817     }
818     if ( gpg->colon.fd[1] != -1 ) {
819         fd_parent_list[n].fd = gpg->colon.fd[1];
820         fd_parent_list[n].dup_to = -1;
821         n++;
822         gpg->colon.fd[1] = -1;
823     }
824     for (i=0; gpg->fd_data_map[i].data; i++ ) {
825         fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
826         fd_parent_list[n].dup_to = -1;
827         n++;
828         gpg->fd_data_map[i].peer_fd = -1;
829     }        
830     fd_parent_list[n].fd = -1;
831     fd_parent_list[n].dup_to = -1;
832
833
834     pid = _gpgme_io_spawn (_gpgme_get_gpg_path (),
835                            gpg->argv, fd_child_list, fd_parent_list);
836     xfree (fd_child_list);
837     if (pid == -1) {
838         return mk_error (Exec_Error);
839     }
840
841     gpg->pid = pid;
842     if (gpg->pm.used)
843         gpg->pm.active = 1;
844
845     /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
846
847     if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler,
848                                         gpg, pid, gpg->status.fd[0], 1 ) ) {
849         /* FIXME: kill the child */
850         return mk_error (General_Error);
851
852     }
853
854     if ( gpg->colon.fnc ) {
855         assert ( gpg->colon.fd[0] != -1 );
856         if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler,
857                                             gpg, pid, gpg->colon.fd[0], 1 ) ) {
858             /* FIXME: kill the child */
859             return mk_error (General_Error);
860             
861         }
862     }
863
864     for (i=0; gpg->fd_data_map[i].data; i++ ) {
865         /* Due to problems with select and write we set outbound pipes
866          * to non-blocking */
867         if (!gpg->fd_data_map[i].inbound) {
868             _gpgme_io_set_nonblocking (gpg->fd_data_map[i].fd);
869         }
870
871         if ( _gpgme_register_pipe_handler (
872                  opaque, 
873                  gpg->fd_data_map[i].inbound?
874                        gpg_inbound_handler:gpg_outbound_handler,
875                  gpg->fd_data_map[i].data,
876                  pid, gpg->fd_data_map[i].fd,
877                  gpg->fd_data_map[i].inbound )
878            ) {
879             /* FIXME: kill the child */
880             return mk_error (General_Error);
881         }
882     }
883
884     if ( gpg->cmd.used )
885         _gpgme_freeze_fd ( gpg->cmd.fd );
886
887     /* fixme: check what data we can release here */
888     
889     gpg->running = 1;
890     return 0;
891 }
892
893
894 static int
895 gpg_inbound_handler ( void *opaque, int pid, int fd )
896 {
897     GpgmeData dh = opaque;
898     GpgmeError err;
899     int nread;
900     char buf[200];
901
902     assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN );
903
904     nread = _gpgme_io_read (fd, buf, 200 );
905     if ( nread < 0 ) {
906         DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
907                  fd, nread, strerror (errno) );
908         return 1;
909     }
910     else if (!nread)
911         return 1; /* eof */
912
913     /* We could improve this with a GpgmeData function which takes
914      * the read function or provides a memory area for writing to it.
915      */
916     
917     err = _gpgme_data_append ( dh, buf, nread );
918     if ( err ) {
919         DEBUG1 ("_gpgme_append_data failed: %s\n",
920                  gpgme_strerror(err));
921         /* Fixme: we should close the pipe or read it to /dev/null in
922          * this case. Returnin EOF is not sufficient */
923         return 1;
924     }
925
926     return 0;
927 }
928
929
930 static int
931 write_mem_data ( GpgmeData dh, int fd )
932 {
933     size_t nbytes;
934     int  nwritten; 
935
936     nbytes = dh->len - dh->readpos;
937     if ( !nbytes ) {
938         _gpgme_io_close (fd);
939         return 1;
940     }
941     
942     /* FIXME: Arggg, the pipe blocks on large write request, although
943      * select told us that it is okay to write - need to figure out
944      * why this happens?  Stevens says nothing about this problem (or
945      * is it my Linux kernel 2.4.0test1)
946      * To avoid that we have set the pipe to nonblocking.
947      */
948
949     nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
950     if (nwritten == -1 && errno == EAGAIN )
951         return 0;
952     if ( nwritten < 1 ) {
953         DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
954                 fd, nwritten, strerror (errno) );
955         _gpgme_io_close (fd);
956         return 1;
957     }
958
959     dh->readpos += nwritten;
960     return 0;
961 }
962
963 static int
964 write_cb_data ( GpgmeData dh, int fd )
965 {
966     size_t nbytes;
967     int  err, nwritten; 
968     char buffer[512];
969
970     err = gpgme_data_read ( dh, buffer, DIM(buffer), &nbytes );
971     if (err == GPGME_EOF) {
972         _gpgme_io_close (fd);
973         return 1;
974     }
975     
976     nwritten = _gpgme_io_write ( fd, buffer, nbytes );
977     if (nwritten == -1 && errno == EAGAIN )
978         return 0;
979     if ( nwritten < 1 ) {
980         DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
981                 fd, nwritten, strerror (errno) );
982         _gpgme_io_close (fd);
983         return 1;
984     }
985
986     if ( nwritten < nbytes ) {
987         /* ugly, ugly: It does currently only for for MEM type data */
988         if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) )
989             DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
990                      nbytes - nwritten );
991         _gpgme_io_close (fd);
992         return 1;
993     }
994
995     return 0;
996 }
997
998
999 static int
1000 gpg_outbound_handler ( void *opaque, int pid, int fd )
1001 {
1002     GpgmeData dh = opaque;
1003
1004     assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT );
1005     switch ( gpgme_data_get_type (dh) ) {
1006       case GPGME_DATA_TYPE_MEM:
1007         if ( write_mem_data ( dh, fd ) )
1008             return 1; /* ready */
1009         break;
1010       case GPGME_DATA_TYPE_CB:
1011         if (write_cb_data (dh, fd))
1012             return 1; /* ready */
1013         break;
1014       default:
1015         assert (0);
1016     }
1017
1018     return 0;
1019 }
1020
1021
1022
1023 static int
1024 gpg_status_handler ( void *opaque, int pid, int fd )
1025 {
1026     GpgObject gpg = opaque;
1027     int rc = 0;
1028
1029     assert ( fd == gpg->status.fd[0] );
1030     rc = read_status ( gpg );
1031     if ( rc ) {
1032         DEBUG1 ("gpg_handler: read_status problem %d\n - stop", rc);
1033         return 1;
1034     }
1035
1036     return gpg->status.eof;
1037 }
1038
1039
1040 static int
1041 status_cmp (const void *ap, const void *bp)
1042 {
1043     const struct status_table_s *a = ap;
1044     const struct status_table_s *b = bp;
1045
1046     return strcmp (a->name, b->name);
1047 }
1048
1049
1050
1051 /*
1052  * Handle the status output of GnuPG.  This function does read entire
1053  * lines and passes them as C strings to the callback function (we can
1054  * use C Strings because the status output is always UTF-8 encoded).
1055  * Of course we have to buffer the lines to cope with long lines
1056  * e.g. with a large user ID.  Note: We can optimize this to only cope
1057  * with status line code we know about and skip all other stuff
1058  * without buffering (i.e. without extending the buffer).  */
1059 static GpgmeError
1060 read_status ( GpgObject gpg )
1061 {
1062     char *p;
1063     int nread;
1064     size_t bufsize = gpg->status.bufsize; 
1065     char *buffer = gpg->status.buffer;
1066     size_t readpos = gpg->status.readpos; 
1067
1068     assert (buffer);
1069     if (bufsize - readpos < 256) { 
1070         /* need more room for the read */
1071         bufsize += 1024;
1072         buffer = xtryrealloc (buffer, bufsize);
1073         if ( !buffer ) 
1074             return mk_error (Out_Of_Core);
1075     }
1076     
1077
1078     nread = _gpgme_io_read ( gpg->status.fd[0],
1079                              buffer+readpos, bufsize-readpos );
1080     if (nread == -1)
1081         return mk_error(Read_Error);
1082
1083     if (!nread) {
1084         gpg->status.eof = 1;
1085         if (gpg->status.fnc)
1086             gpg->status.fnc ( gpg->status.fnc_value, STATUS_EOF, "" );
1087         return 0;
1088     }
1089
1090     while (nread > 0) {
1091         for (p = buffer + readpos; nread; nread--, p++) {
1092             if ( *p == '\n' ) {
1093                 /* (we require that the last line is terminated by a LF) */
1094                 *p = 0;
1095                 /* fprintf (stderr, "read_status: `%s'\n", buffer); */
1096                 if (!strncmp (buffer, "[GNUPG:] ", 9 )
1097                     && buffer[9] >= 'A' && buffer[9] <= 'Z' ) {
1098                     struct status_table_s t, *r;
1099                     char *rest;
1100
1101                     rest = strchr (buffer+9, ' ');
1102                     if ( !rest )
1103                         rest = p; /* set to an empty string */
1104                     else
1105                         *rest++ = 0;
1106                     
1107                     t.name = buffer+9;
1108                     /* (the status table as one extra element) */
1109                     r = bsearch ( &t, status_table, DIM(status_table)-1,
1110                                   sizeof t, status_cmp );
1111                     if ( r ) {
1112                         if ( gpg->cmd.used
1113                              && ( r->code == STATUS_GET_BOOL
1114                                   || r->code == STATUS_GET_LINE
1115                                   || r->code == STATUS_GET_HIDDEN )) {
1116                             gpg->cmd.code = r->code;
1117                             xfree (gpg->cmd.keyword);
1118                             gpg->cmd.keyword = xtrystrdup (rest);
1119                             if ( !gpg->cmd.keyword )
1120                                 return mk_error (Out_Of_Core);
1121                             /* this should be the last thing we have received
1122                              * and the next thing will be that the command
1123                              * handler does its action */
1124                             if ( nread > 1 )
1125                                 DEBUG0 ("ERROR, unexpected data in read_status");
1126                             _gpgme_thaw_fd (gpg->cmd.fd);
1127                         }
1128                         else if ( gpg->status.fnc ) {
1129                             gpg->status.fnc ( gpg->status.fnc_value, 
1130                                               r->code, rest);
1131                         }
1132                     
1133                         if ( r->code == STATUS_END_STREAM ) {
1134                             if ( gpg->cmd.used )
1135                                 _gpgme_freeze_fd ( gpg->cmd.fd );
1136                         }
1137                     }
1138                 }
1139                 /* To reuse the buffer for the next line we have to
1140                  * shift the remaining data to the buffer start and
1141                  * restart the loop Hmmm: We can optimize this
1142                  * function by looking forward in the buffer to see
1143                  * whether a second complete line is available and in
1144                  * this case avoid the memmove for this line.  */
1145                 nread--; p++;
1146                 if (nread)
1147                     memmove (buffer, p, nread);
1148                 readpos = 0;
1149                 break; /* the for loop */
1150             }
1151             else
1152                 readpos++;
1153         }
1154     } 
1155
1156     /* Update the gpg object.  */
1157     gpg->status.bufsize = bufsize;
1158     gpg->status.buffer = buffer;
1159     gpg->status.readpos = readpos;
1160     return 0;
1161 }
1162
1163
1164 /*
1165  * This colonline handler thing is not the clean way to do it.
1166  * It might be better to enhance the GpgmeData object to act as
1167  * a wrapper for a callback.  Same goes for the status thing.
1168  * For now we use this thing here becuase it is easier to implement.
1169  */
1170 static int
1171 gpg_colon_line_handler ( void *opaque, int pid, int fd )
1172 {
1173     GpgObject gpg = opaque;
1174     GpgmeError rc = 0;
1175
1176     assert ( fd == gpg->colon.fd[0] );
1177     rc = read_colon_line ( gpg );
1178     if ( rc ) {
1179         DEBUG1 ("gpg_colon_line_handler: "
1180                  "read problem %d\n - stop", rc);
1181         return 1;
1182     }
1183
1184     return gpg->colon.eof;
1185 }
1186
1187 static GpgmeError
1188 read_colon_line ( GpgObject gpg )
1189 {
1190     char *p;
1191     int nread;
1192     size_t bufsize = gpg->colon.bufsize; 
1193     char *buffer = gpg->colon.buffer;
1194     size_t readpos = gpg->colon.readpos; 
1195
1196     assert (buffer);
1197     if (bufsize - readpos < 256) { 
1198         /* need more room for the read */
1199         bufsize += 1024;
1200         buffer = xtryrealloc (buffer, bufsize);
1201         if ( !buffer ) 
1202             return mk_error (Out_Of_Core);
1203     }
1204     
1205
1206     nread = _gpgme_io_read ( gpg->colon.fd[0],
1207                              buffer+readpos, bufsize-readpos );
1208     if (nread == -1)
1209         return mk_error(Read_Error);
1210
1211     if (!nread) {
1212         gpg->colon.eof = 1;
1213         assert (gpg->colon.fnc);
1214         gpg->colon.fnc ( gpg->colon.fnc_value, NULL );
1215         return 0;
1216     }
1217
1218     while (nread > 0) {
1219         for (p = buffer + readpos; nread; nread--, p++) {
1220             if ( *p == '\n' ) {
1221                 /* (we require that the last line is terminated by a
1222                  * LF) and we skip empty lines.  Note: we use UTF8
1223                  * encoding and escaping of special characters
1224                  * We require at least one colon to cope with
1225                  * some other printed information.
1226                  */
1227                 *p = 0;
1228                 if ( gpg->colon.simple
1229                      || (*buffer && strchr (buffer, ':')) ) {
1230                     assert (gpg->colon.fnc);
1231                     gpg->colon.fnc ( gpg->colon.fnc_value, buffer );
1232                 }
1233             
1234                 /* To reuse the buffer for the next line we have to
1235                  * shift the remaining data to the buffer start and
1236                  * restart the loop Hmmm: We can optimize this
1237                  * function by looking forward in the buffer to see
1238                  * whether a second complete line is available and in
1239                  * this case avoid the memmove for this line.  */
1240                 nread--; p++;
1241                 if (nread)
1242                     memmove (buffer, p, nread);
1243                 readpos = 0;
1244                 break; /* the for loop */
1245             }
1246             else
1247                 readpos++;
1248         }
1249     } 
1250     
1251     /* Update the gpg object.  */
1252     gpg->colon.bufsize = bufsize;
1253     gpg->colon.buffer  = buffer;
1254     gpg->colon.readpos = readpos;
1255     return 0;
1256 }
1257
1258 static GpgmeError
1259 pipemode_copy (char *buffer, size_t length, size_t *nread, GpgmeData data )
1260 {
1261     GpgmeError err;
1262     int nbytes;
1263     char tmp[1000], *s, *d;
1264
1265     /* we can optimize this whole thing but for now we just
1266      * return after each escape character */
1267     if (length > 990)
1268         length = 990;
1269
1270     err = gpgme_data_read ( data, tmp, length, &nbytes );
1271     if (err)
1272         return err;
1273     for (s=tmp, d=buffer; nbytes; s++, nbytes--) {
1274         *d++ = *s;
1275         if (*s == '@' ) {
1276             *d++ = '@';
1277             break;
1278         }
1279     }
1280     *nread = d - buffer;
1281     return 0;
1282 }
1283
1284
1285 static int
1286 pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
1287 {
1288     GpgObject gpg = opaque;
1289     GpgmeError err;
1290
1291     if ( !buffer || !length || !nread )
1292         return 0; /* those values are reserved for extensions */
1293     *nread =0;
1294     if ( !gpg->pm.stream_started ) {
1295         assert (length > 4 );
1296         strcpy (buffer, "@<@B" );
1297         *nread = 4;
1298         gpg->pm.stream_started = 1;
1299     }
1300     else if ( gpg->pm.sig ) {
1301         err = pipemode_copy ( buffer, length, nread, gpg->pm.sig );
1302         if ( err == GPGME_EOF ) {
1303             gpg->pm.sig = NULL;
1304             assert (length > 4 );
1305             strcpy (buffer, "@t" );
1306             *nread = 2;
1307         }
1308         else if (err) {
1309             DEBUG1 ("pipemode_cb: copy sig failed: %s\n",
1310                      gpgme_strerror (err) );
1311             return -1;
1312         }
1313     }
1314     else if ( gpg->pm.text ) {
1315         err = pipemode_copy ( buffer, length, nread, gpg->pm.text );
1316         if ( err == GPGME_EOF ) {
1317             gpg->pm.text = NULL;
1318             assert (length > 4 );
1319             strcpy (buffer, "@.@>" );
1320             *nread = 4;
1321         }
1322         else if (err) {
1323             DEBUG1 ("pipemode_cb: copy data failed: %s\n",
1324                      gpgme_strerror (err) );
1325             return -1;
1326         }
1327     }
1328     else {
1329         return 0; /* eof */
1330     }
1331
1332     return 0;
1333 }
1334
1335
1336 /* 
1337  * Here we handle --command-fd.  This works closely together with
1338  * the status handler.  
1339  */
1340
1341 static int
1342 command_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
1343 {
1344     GpgObject gpg = opaque;
1345     const char *value;
1346     int value_len;
1347
1348     DEBUG0 ("command_cb: enter\n");
1349     assert (gpg->cmd.used);
1350     if ( !buffer || !length || !nread )
1351         return 0; /* those values are reserved for extensions */
1352     *nread =0;
1353     if ( !gpg->cmd.code ) {
1354         DEBUG0 ("command_cb: no code\n");
1355         return -1;
1356     }
1357     
1358     if ( !gpg->cmd.fnc ) {
1359         DEBUG0 ("command_cb: no user cb\n");
1360         return -1;
1361     }
1362
1363     value = gpg->cmd.fnc ( gpg->cmd.fnc_value, 
1364                            gpg->cmd.code, gpg->cmd.keyword );
1365     if ( !value ) {
1366         DEBUG0 ("command_cb: no data from user cb\n");
1367         gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
1368         return -1;
1369     }
1370
1371     value_len = strlen (value);
1372     if ( value_len+1 > length ) {
1373         DEBUG0 ("command_cb: too much data from user cb\n");
1374         gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
1375         return -1;
1376     }
1377
1378     memcpy ( buffer, value, value_len );
1379     if ( !value_len || (value_len && value[value_len-1] != '\n') ) 
1380         buffer[value_len++] = '\n';
1381     *nread = value_len;
1382     
1383     gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
1384     gpg->cmd.code = 0;
1385     /* and sleep again until read_status will wake us up again */
1386     _gpgme_freeze_fd ( gpg->cmd.fd );
1387     return 0;
1388 }
1389
1390
1391
1392