7a91444547229331e2519afa17e507b73ff395c9
[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     if (! _gpgme_get_gpg_path ())
793       return mk_error (Invalid_Engine);
794
795     /* Kludge, so that we don't need to check the return code of
796      * all the gpgme_gpg_add_arg().  we bail out here instead */
797     if ( gpg->arg_error )
798         return mk_error (Out_Of_Core);
799
800     if (gpg->pm.active)
801         return 0;
802
803     rc = build_argv ( gpg );
804     if ( rc )
805         return rc;
806
807     n = 4; /* status fd, 2*colon_fd and end of list */
808     for (i=0; gpg->fd_data_map[i].data; i++ ) 
809         n += 2;
810     fd_child_list = xtrycalloc ( n+n, sizeof *fd_child_list );
811     if (!fd_child_list)
812         return mk_error (Out_Of_Core);
813     fd_parent_list = fd_child_list + n;
814
815     /* build the fd list for the child */
816     n=0;
817     fd_child_list[n].fd = gpg->status.fd[0]; 
818     fd_child_list[n].dup_to = -1;
819     n++;
820     if ( gpg->colon.fnc ) {
821         fd_child_list[n].fd = gpg->colon.fd[0];
822         fd_child_list[n].dup_to = -1;
823         n++;
824         fd_child_list[n].fd = gpg->colon.fd[1]; 
825         fd_child_list[n].dup_to = 1; /* dup to stdout */
826         n++;
827     }
828     for (i=0; gpg->fd_data_map[i].data; i++ ) {
829         fd_child_list[n].fd = gpg->fd_data_map[i].fd;
830         fd_child_list[n].dup_to = -1;
831         n++;
832         if (gpg->fd_data_map[i].dup_to != -1) {
833             fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
834             fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
835             n++;
836         }
837     }
838     fd_child_list[n].fd = -1;
839     fd_child_list[n].dup_to = -1;
840
841     /* build the fd list for the parent */
842     n=0;
843     if ( gpg->status.fd[1] != -1 ) {
844         fd_parent_list[n].fd = gpg->status.fd[1];
845         fd_parent_list[n].dup_to = -1;
846         n++;
847         gpg->status.fd[1] = -1;
848     }
849     if ( gpg->colon.fd[1] != -1 ) {
850         fd_parent_list[n].fd = gpg->colon.fd[1];
851         fd_parent_list[n].dup_to = -1;
852         n++;
853         gpg->colon.fd[1] = -1;
854     }
855     for (i=0; gpg->fd_data_map[i].data; i++ ) {
856         fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
857         fd_parent_list[n].dup_to = -1;
858         n++;
859         gpg->fd_data_map[i].peer_fd = -1;
860     }        
861     fd_parent_list[n].fd = -1;
862     fd_parent_list[n].dup_to = -1;
863
864
865     pid = _gpgme_io_spawn (_gpgme_get_gpg_path (),
866                            gpg->argv, fd_child_list, fd_parent_list);
867     xfree (fd_child_list);
868     if (pid == -1) {
869         return mk_error (Exec_Error);
870     }
871
872     gpg->pid = pid;
873     if (gpg->pm.used)
874         gpg->pm.active = 1;
875
876     /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
877
878     if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler,
879                                         gpg, pid, gpg->status.fd[0], 1 ) ) {
880         /* FIXME: kill the child */
881         return mk_error (General_Error);
882
883     }
884
885     if ( gpg->colon.fnc ) {
886         assert ( gpg->colon.fd[0] != -1 );
887         if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler,
888                                             gpg, pid, gpg->colon.fd[0], 1 ) ) {
889             /* FIXME: kill the child */
890             return mk_error (General_Error);
891             
892         }
893     }
894
895     for (i=0; gpg->fd_data_map[i].data; i++ ) {
896         /* Due to problems with select and write we set outbound pipes
897          * to non-blocking */
898         if (!gpg->fd_data_map[i].inbound) {
899             _gpgme_io_set_nonblocking (gpg->fd_data_map[i].fd);
900         }
901
902         if ( _gpgme_register_pipe_handler (
903                  opaque, 
904                  gpg->fd_data_map[i].inbound?
905                        gpg_inbound_handler:gpg_outbound_handler,
906                  gpg->fd_data_map[i].data,
907                  pid, gpg->fd_data_map[i].fd,
908                  gpg->fd_data_map[i].inbound )
909            ) {
910             /* FIXME: kill the child */
911             return mk_error (General_Error);
912         }
913     }
914
915     if ( gpg->cmd.used )
916         _gpgme_freeze_fd ( gpg->cmd.fd );
917
918     /* fixme: check what data we can release here */
919     
920     gpg->running = 1;
921     return 0;
922 }
923
924
925 static int
926 gpg_inbound_handler ( void *opaque, int pid, int fd )
927 {
928     GpgmeData dh = opaque;
929     GpgmeError err;
930     int nread;
931     char buf[200];
932
933     assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_IN );
934
935     nread = _gpgme_io_read (fd, buf, 200 );
936     if ( nread < 0 ) {
937         DEBUG3 ("read_mem_data: read failed on fd %d (n=%d): %s",
938                  fd, nread, strerror (errno) );
939         return 1;
940     }
941     else if (!nread)
942         return 1; /* eof */
943
944     /* We could improve this with a GpgmeData function which takes
945      * the read function or provides a memory area for writing to it.
946      */
947     
948     err = _gpgme_data_append ( dh, buf, nread );
949     if ( err ) {
950         DEBUG1 ("_gpgme_append_data failed: %s\n",
951                  gpgme_strerror(err));
952         /* Fixme: we should close the pipe or read it to /dev/null in
953          * this case. Returnin EOF is not sufficient */
954         return 1;
955     }
956
957     return 0;
958 }
959
960
961 static int
962 write_mem_data ( GpgmeData dh, int fd )
963 {
964     size_t nbytes;
965     int  nwritten; 
966
967     nbytes = dh->len - dh->readpos;
968     if ( !nbytes ) {
969         _gpgme_io_close (fd);
970         return 1;
971     }
972     
973     /* FIXME: Arggg, the pipe blocks on large write request, although
974      * select told us that it is okay to write - need to figure out
975      * why this happens?  Stevens says nothing about this problem (or
976      * is it my Linux kernel 2.4.0test1)
977      * To avoid that we have set the pipe to nonblocking.
978      */
979
980     nwritten = _gpgme_io_write ( fd, dh->data+dh->readpos, nbytes );
981     if (nwritten == -1 && errno == EAGAIN )
982         return 0;
983     if ( nwritten < 1 ) {
984         DEBUG3 ("write_mem_data(%d): write failed (n=%d): %s",
985                 fd, nwritten, strerror (errno) );
986         _gpgme_io_close (fd);
987         return 1;
988     }
989
990     dh->readpos += nwritten;
991     return 0;
992 }
993
994 static int
995 write_cb_data ( GpgmeData dh, int fd )
996 {
997     size_t nbytes;
998     int  err, nwritten; 
999     char buffer[512];
1000
1001     err = gpgme_data_read ( dh, buffer, DIM(buffer), &nbytes );
1002     if (err == GPGME_EOF) {
1003         _gpgme_io_close (fd);
1004         return 1;
1005     }
1006     
1007     nwritten = _gpgme_io_write ( fd, buffer, nbytes );
1008     if (nwritten == -1 && errno == EAGAIN )
1009         return 0;
1010     if ( nwritten < 1 ) {
1011         DEBUG3 ("write_cb_data(%d): write failed (n=%d): %s",
1012                 fd, nwritten, strerror (errno) );
1013         _gpgme_io_close (fd);
1014         return 1;
1015     }
1016
1017     if ( nwritten < nbytes ) {
1018         /* ugly, ugly: It does currently only for for MEM type data */
1019         if ( _gpgme_data_unread (dh, buffer + nwritten, nbytes - nwritten ) )
1020             DEBUG1 ("wite_cb_data: unread of %d bytes failed\n",
1021                      nbytes - nwritten );
1022         _gpgme_io_close (fd);
1023         return 1;
1024     }
1025
1026     return 0;
1027 }
1028
1029
1030 static int
1031 gpg_outbound_handler ( void *opaque, int pid, int fd )
1032 {
1033     GpgmeData dh = opaque;
1034
1035     assert ( _gpgme_data_get_mode (dh) == GPGME_DATA_MODE_OUT );
1036     switch ( gpgme_data_get_type (dh) ) {
1037       case GPGME_DATA_TYPE_MEM:
1038         if ( write_mem_data ( dh, fd ) )
1039             return 1; /* ready */
1040         break;
1041       case GPGME_DATA_TYPE_CB:
1042         if (write_cb_data (dh, fd))
1043             return 1; /* ready */
1044         break;
1045       default:
1046         assert (0);
1047     }
1048
1049     return 0;
1050 }
1051
1052
1053
1054 static int
1055 gpg_status_handler ( void *opaque, int pid, int fd )
1056 {
1057     GpgObject gpg = opaque;
1058     int rc = 0;
1059
1060     assert ( fd == gpg->status.fd[0] );
1061     rc = read_status ( gpg );
1062     if ( rc ) {
1063         DEBUG1 ("gpg_handler: read_status problem %d\n - stop", rc);
1064         return 1;
1065     }
1066
1067     return gpg->status.eof;
1068 }
1069
1070
1071 static int
1072 status_cmp (const void *ap, const void *bp)
1073 {
1074     const struct status_table_s *a = ap;
1075     const struct status_table_s *b = bp;
1076
1077     return strcmp (a->name, b->name);
1078 }
1079
1080
1081
1082 /*
1083  * Handle the status output of GnuPG.  This function does read entire
1084  * lines and passes them as C strings to the callback function (we can
1085  * use C Strings because the status output is always UTF-8 encoded).
1086  * Of course we have to buffer the lines to cope with long lines
1087  * e.g. with a large user ID.  Note: We can optimize this to only cope
1088  * with status line code we know about and skip all other stuff
1089  * without buffering (i.e. without extending the buffer).  */
1090 static GpgmeError
1091 read_status ( GpgObject gpg )
1092 {
1093     char *p;
1094     int nread;
1095     size_t bufsize = gpg->status.bufsize; 
1096     char *buffer = gpg->status.buffer;
1097     size_t readpos = gpg->status.readpos; 
1098
1099     assert (buffer);
1100     if (bufsize - readpos < 256) { 
1101         /* need more room for the read */
1102         bufsize += 1024;
1103         buffer = xtryrealloc (buffer, bufsize);
1104         if ( !buffer ) 
1105             return mk_error (Out_Of_Core);
1106     }
1107     
1108
1109     nread = _gpgme_io_read ( gpg->status.fd[0],
1110                              buffer+readpos, bufsize-readpos );
1111     if (nread == -1)
1112         return mk_error(Read_Error);
1113
1114     if (!nread) {
1115         gpg->status.eof = 1;
1116         if (gpg->status.fnc)
1117             gpg->status.fnc ( gpg->status.fnc_value, STATUS_EOF, "" );
1118         return 0;
1119     }
1120
1121     while (nread > 0) {
1122         for (p = buffer + readpos; nread; nread--, p++) {
1123             if ( *p == '\n' ) {
1124                 /* (we require that the last line is terminated by a LF) */
1125                 *p = 0;
1126                 if (!strncmp (buffer, "[GNUPG:] ", 9 )
1127                     && buffer[9] >= 'A' && buffer[9] <= 'Z' ) {
1128                     struct status_table_s t, *r;
1129                     char *rest;
1130
1131                     rest = strchr (buffer+9, ' ');
1132                     if ( !rest )
1133                         rest = p; /* set to an empty string */
1134                     else
1135                         *rest++ = 0;
1136                     
1137                     t.name = buffer+9;
1138                     /* (the status table as one extra element) */
1139                     r = bsearch ( &t, status_table, DIM(status_table)-1,
1140                                   sizeof t, status_cmp );
1141                     if ( r ) {
1142                         if ( gpg->cmd.used
1143                              && ( r->code == STATUS_GET_BOOL
1144                                   || r->code == STATUS_GET_LINE
1145                                   || r->code == STATUS_GET_HIDDEN )) {
1146                             gpg->cmd.code = r->code;
1147                             xfree (gpg->cmd.keyword);
1148                             gpg->cmd.keyword = xtrystrdup (rest);
1149                             if ( !gpg->cmd.keyword )
1150                                 return mk_error (Out_Of_Core);
1151                             /* this should be the last thing we have received
1152                              * and the next thing will be that the command
1153                              * handler does its action */
1154                             if ( nread > 1 )
1155                                 DEBUG0 ("ERROR, unexpected data in read_status");
1156                             _gpgme_thaw_fd (gpg->cmd.fd);
1157                         }
1158                         else if ( gpg->status.fnc ) {
1159                             gpg->status.fnc ( gpg->status.fnc_value, 
1160                                               r->code, rest);
1161                         }
1162                     
1163                         if ( r->code == STATUS_END_STREAM ) {
1164                             if ( gpg->cmd.used )
1165                                 _gpgme_freeze_fd ( gpg->cmd.fd );
1166                         }
1167                     }
1168                 }
1169                 /* To reuse the buffer for the next line we have to
1170                  * shift the remaining data to the buffer start and
1171                  * restart the loop Hmmm: We can optimize this
1172                  * function by looking forward in the buffer to see
1173                  * whether a second complete line is available and in
1174                  * this case avoid the memmove for this line.  */
1175                 nread--; p++;
1176                 if (nread)
1177                     memmove (buffer, p, nread);
1178                 readpos = 0;
1179                 break; /* the for loop */
1180             }
1181             else
1182                 readpos++;
1183         }
1184     } 
1185
1186     /* Update the gpg object.  */
1187     gpg->status.bufsize = bufsize;
1188     gpg->status.buffer = buffer;
1189     gpg->status.readpos = readpos;
1190     return 0;
1191 }
1192
1193
1194 /*
1195  * This colonline handler thing is not the clean way to do it.
1196  * It might be better to enhance the GpgmeData object to act as
1197  * a wrapper for a callback.  Same goes for the status thing.
1198  * For now we use this thing here becuase it is easier to implement.
1199  */
1200 static int
1201 gpg_colon_line_handler ( void *opaque, int pid, int fd )
1202 {
1203     GpgObject gpg = opaque;
1204     GpgmeError rc = 0;
1205
1206     assert ( fd == gpg->colon.fd[0] );
1207     rc = read_colon_line ( gpg );
1208     if ( rc ) {
1209         DEBUG1 ("gpg_colon_line_handler: "
1210                  "read problem %d\n - stop", rc);
1211         return 1;
1212     }
1213
1214     return gpg->colon.eof;
1215 }
1216
1217 static GpgmeError
1218 read_colon_line ( GpgObject gpg )
1219 {
1220     char *p;
1221     int nread;
1222     size_t bufsize = gpg->colon.bufsize; 
1223     char *buffer = gpg->colon.buffer;
1224     size_t readpos = gpg->colon.readpos; 
1225
1226     assert (buffer);
1227     if (bufsize - readpos < 256) { 
1228         /* need more room for the read */
1229         bufsize += 1024;
1230         buffer = xtryrealloc (buffer, bufsize);
1231         if ( !buffer ) 
1232             return mk_error (Out_Of_Core);
1233     }
1234     
1235
1236     nread = _gpgme_io_read ( gpg->colon.fd[0],
1237                              buffer+readpos, bufsize-readpos );
1238     if (nread == -1)
1239         return mk_error(Read_Error);
1240
1241     if (!nread) {
1242         gpg->colon.eof = 1;
1243         assert (gpg->colon.fnc);
1244         gpg->colon.fnc ( gpg->colon.fnc_value, NULL );
1245         return 0;
1246     }
1247
1248     while (nread > 0) {
1249         for (p = buffer + readpos; nread; nread--, p++) {
1250             if ( *p == '\n' ) {
1251                 /* (we require that the last line is terminated by a
1252                  * LF) and we skip empty lines.  Note: we use UTF8
1253                  * encoding and escaping of special characters
1254                  * We require at least one colon to cope with
1255                  * some other printed information.
1256                  */
1257                 *p = 0;
1258                 if ( gpg->colon.simple
1259                      || (*buffer && strchr (buffer, ':')) ) {
1260                     assert (gpg->colon.fnc);
1261                     gpg->colon.fnc ( gpg->colon.fnc_value, buffer );
1262                 }
1263             
1264                 /* To reuse the buffer for the next line we have to
1265                  * shift the remaining data to the buffer start and
1266                  * restart the loop Hmmm: We can optimize this
1267                  * function by looking forward in the buffer to see
1268                  * whether a second complete line is available and in
1269                  * this case avoid the memmove for this line.  */
1270                 nread--; p++;
1271                 if (nread)
1272                     memmove (buffer, p, nread);
1273                 readpos = 0;
1274                 break; /* the for loop */
1275             }
1276             else
1277                 readpos++;
1278         }
1279     } 
1280     
1281     /* Update the gpg object.  */
1282     gpg->colon.bufsize = bufsize;
1283     gpg->colon.buffer  = buffer;
1284     gpg->colon.readpos = readpos;
1285     return 0;
1286 }
1287
1288 static GpgmeError
1289 pipemode_copy (char *buffer, size_t length, size_t *nread, GpgmeData data )
1290 {
1291     GpgmeError err;
1292     size_t nbytes;
1293     char tmp[1000], *s, *d;
1294
1295     /* we can optimize this whole thing but for now we just
1296      * return after each escape character */
1297     if (length > 990)
1298         length = 990;
1299
1300     err = gpgme_data_read ( data, tmp, length, &nbytes );
1301     if (err)
1302         return err;
1303     for (s=tmp, d=buffer; nbytes; s++, nbytes--) {
1304         *d++ = *s;
1305         if (*s == '@' ) {
1306             *d++ = '@';
1307             break;
1308         }
1309     }
1310     *nread = d - buffer;
1311     return 0;
1312 }
1313
1314
1315 static int
1316 pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
1317 {
1318     GpgObject gpg = opaque;
1319     GpgmeError err;
1320
1321     if ( !buffer || !length || !nread )
1322         return 0; /* those values are reserved for extensions */
1323     *nread =0;
1324     if ( !gpg->pm.stream_started ) {
1325         assert (length > 4 );
1326         strcpy (buffer, "@<@B" );
1327         *nread = 4;
1328         gpg->pm.stream_started = 1;
1329     }
1330     else if ( gpg->pm.sig ) {
1331         err = pipemode_copy ( buffer, length, nread, gpg->pm.sig );
1332         if ( err == GPGME_EOF ) {
1333             gpg->pm.sig = NULL;
1334             assert (length > 4 );
1335             strcpy (buffer, "@t" );
1336             *nread = 2;
1337         }
1338         else if (err) {
1339             DEBUG1 ("pipemode_cb: copy sig failed: %s\n",
1340                      gpgme_strerror (err) );
1341             return -1;
1342         }
1343     }
1344     else if ( gpg->pm.text ) {
1345         err = pipemode_copy ( buffer, length, nread, gpg->pm.text );
1346         if ( err == GPGME_EOF ) {
1347             gpg->pm.text = NULL;
1348             assert (length > 4 );
1349             strcpy (buffer, "@.@>" );
1350             *nread = 4;
1351         }
1352         else if (err) {
1353             DEBUG1 ("pipemode_cb: copy data failed: %s\n",
1354                      gpgme_strerror (err) );
1355             return -1;
1356         }
1357     }
1358     else {
1359         return 0; /* eof */
1360     }
1361
1362     return 0;
1363 }
1364
1365
1366 /* 
1367  * Here we handle --command-fd.  This works closely together with
1368  * the status handler.  
1369  */
1370
1371 static int
1372 command_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
1373 {
1374     GpgObject gpg = opaque;
1375     const char *value;
1376     int value_len;
1377
1378     DEBUG0 ("command_cb: enter\n");
1379     assert (gpg->cmd.used);
1380     if ( !buffer || !length || !nread )
1381         return 0; /* those values are reserved for extensions */
1382     *nread =0;
1383     if ( !gpg->cmd.code ) {
1384         DEBUG0 ("command_cb: no code\n");
1385         return -1;
1386     }
1387     
1388     if ( !gpg->cmd.fnc ) {
1389         DEBUG0 ("command_cb: no user cb\n");
1390         return -1;
1391     }
1392
1393     value = gpg->cmd.fnc ( gpg->cmd.fnc_value, 
1394                            gpg->cmd.code, gpg->cmd.keyword );
1395     if ( !value ) {
1396         DEBUG0 ("command_cb: no data from user cb\n");
1397         gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
1398         return -1;
1399     }
1400
1401     value_len = strlen (value);
1402     if ( value_len+1 > length ) {
1403         DEBUG0 ("command_cb: too much data from user cb\n");
1404         gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
1405         return -1;
1406     }
1407
1408     memcpy ( buffer, value, value_len );
1409     if ( !value_len || (value_len && value[value_len-1] != '\n') ) 
1410         buffer[value_len++] = '\n';
1411     *nread = value_len;
1412     
1413     gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value);
1414     gpg->cmd.code = 0;
1415     /* and sleep again until read_status will wake us up again */
1416     _gpgme_freeze_fd ( gpg->cmd.fd );
1417     return 0;
1418 }
1419
1420
1421
1422