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