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