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