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