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