f67f68fdebc73a6d61982bde2cfea0ed3ea3f488
[gpgme.git] / gpgme / rungpg.c
1 /* rungpg.c 
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001, 2002 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 {
59   GpgmeData data;
60   int inbound;  /* true if this is used for reading from gpg */
61   int dup_to;
62   int fd;       /* the fd to use */
63   int peer_fd;  /* the outher side of the pipe */
64   void *tag;
65 };
66
67
68 struct gpg_object_s
69 {
70   struct arg_and_data_s *arglist;
71   struct arg_and_data_s **argtail;
72   int arg_error;  
73
74   struct
75   {
76     int fd[2];  
77     size_t bufsize;
78     char *buffer;
79     size_t readpos;
80     int eof;
81     GpgStatusHandler fnc;
82     void *fnc_value;
83     void *tag;
84   } status;
85
86   /* This is a kludge - see the comment at gpg_colon_line_handler */
87   struct
88   {
89     int fd[2];  
90     size_t bufsize;
91     char *buffer;
92     size_t readpos;
93     int eof;
94     GpgColonLineHandler fnc;  /* this indicate use of this structrue */
95     void *fnc_value;
96     void *tag;
97     int simple;
98   } colon;
99
100   char **argv;  
101   struct fd_data_map_s *fd_data_map;
102
103   /* stuff needed for pipemode */
104   struct
105   {
106     int used;
107     int active;
108     GpgmeData sig;
109     GpgmeData text;
110     int stream_started;
111   } pm;
112
113   /* stuff needed for interactive (command) mode */
114   struct
115   {
116     int used;
117     int fd;
118     int idx;            /* Index in fd_data_map */
119     GpgmeData cb_data;   /* hack to get init the above idx later */
120     GpgmeStatusCode code;  /* last code */
121     char *keyword;       /* what has been requested (malloced) */
122     GpgCommandHandler fnc; 
123     void *fnc_value;
124     /* The kludges never end.  This is used to couple command handlers
125        with output data in edit key mode.  */
126     GpgmeData linked_data;
127     int linked_idx;
128   } cmd;
129
130   struct GpgmeIOCbs io_cbs;
131 };
132
133 static void free_argv (char **argv);
134 static void free_fd_data_map (struct fd_data_map_s *fd_data_map);
135
136 static void gpg_status_handler (void *opaque, int fd);
137 static GpgmeError read_status (GpgObject gpg);
138
139 static void gpg_colon_line_handler (void *opaque, int fd);
140 static GpgmeError read_colon_line (GpgObject gpg);
141
142 static int pipemode_cb (void *opaque, char *buffer, size_t length,
143                         size_t *nread);
144 static int command_cb (void *opaque, char *buffer, size_t length,
145                        size_t *nread);
146
147 static void
148 close_notify_handler (int fd, void *opaque)
149 {
150   GpgObject gpg = opaque;
151   int possibly_done = 0;
152   int not_done = 0;
153   assert (fd != -1);
154
155   if (gpg->status.fd[0] == fd)
156     {
157       if (gpg->status.tag)
158         {
159           (*gpg->io_cbs.remove) (gpg->status.tag);
160           possibly_done = 1;
161         }
162       gpg->status.fd[0] = -1;
163     }
164   else if (gpg->status.fd[1] == fd)
165     gpg->status.fd[1] = -1;
166   else if (gpg->colon.fd[0] == fd)
167     {
168       if (gpg->colon.tag)
169         {
170           (*gpg->io_cbs.remove) (gpg->colon.tag);
171           possibly_done = 1;
172         }
173       gpg->colon.fd[0] = -1;
174     }
175   else if (gpg->colon.fd[1] == fd)
176     gpg->colon.fd[1] = -1;
177   else if (gpg->fd_data_map)
178     {
179       int i;
180
181       for (i = 0; gpg->fd_data_map[i].data; i++)
182         {
183           if (gpg->fd_data_map[i].fd == fd)
184             {
185               if (gpg->fd_data_map[i].tag)
186                 {
187                   (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
188                   possibly_done = 1;
189                 }
190               gpg->fd_data_map[i].fd = -1;
191               break;
192             }
193           if (gpg->fd_data_map[i].peer_fd == fd)
194             {
195               gpg->fd_data_map[i].peer_fd = -1;
196               break;
197             }
198         }
199     }
200   if (!possibly_done)
201     not_done = 1;
202   else if (gpg->status.fd[0] != -1)
203     not_done = 1;
204   else if (gpg->colon.fd[0] != -1)
205     not_done = 1;
206   else if (gpg->fd_data_map)
207     {
208       int i;
209
210       for (i = 0; gpg->fd_data_map[i].data; i++)
211         if (gpg->fd_data_map[i].fd != -1)
212           {
213             not_done = 1;
214             break;
215           }
216     }
217   if (!not_done)
218     _gpgme_gpg_io_event (gpg, GPGME_EVENT_DONE, NULL);
219 }
220
221 const char *
222 _gpgme_gpg_get_version (void)
223 {
224   static const char *gpg_version;
225   DEFINE_STATIC_LOCK (gpg_version_lock);
226
227   LOCK (gpg_version_lock);
228   if (!gpg_version)
229     gpg_version = _gpgme_get_program_version (_gpgme_get_gpg_path ());
230   UNLOCK (gpg_version_lock);
231   return gpg_version;
232 }
233
234 GpgmeError
235 _gpgme_gpg_check_version (void)
236 {
237   return _gpgme_compare_versions (_gpgme_gpg_get_version (),
238                                   NEED_GPG_VERSION)
239     ? 0 : mk_error (Invalid_Engine);
240 }
241
242 GpgmeError
243 _gpgme_gpg_new (GpgObject *r_gpg)
244 {
245   GpgObject gpg;
246   int rc = 0;
247
248   gpg = xtrycalloc (1, sizeof *gpg);
249   if (!gpg)
250     {
251       rc = mk_error (Out_Of_Core);
252       goto leave;
253     }
254   gpg->argtail = &gpg->arglist;
255
256   gpg->status.fd[0] = -1;
257   gpg->status.fd[1] = -1;
258   gpg->colon.fd[0] = -1;
259   gpg->colon.fd[1] = -1;
260   gpg->cmd.fd = -1;
261   gpg->cmd.idx = -1;
262   gpg->cmd.linked_data = NULL;
263   gpg->cmd.linked_idx = -1;
264
265   /* Allocate the read buffer for the status pipe.  */
266   gpg->status.bufsize = 1024;
267   gpg->status.readpos = 0;
268   gpg->status.buffer = xtrymalloc (gpg->status.bufsize);
269   if (!gpg->status.buffer)
270     {
271       rc = mk_error (Out_Of_Core);
272       goto leave;
273     }
274   /* In any case we need a status pipe - create it right here and
275      don't handle it with our generic GpgmeData mechanism.  */
276   if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
277     {
278       rc = mk_error (Pipe_Error);
279       goto leave;
280     }
281   if (_gpgme_io_set_close_notify (gpg->status.fd[0],
282                                   close_notify_handler, gpg)
283       || _gpgme_io_set_close_notify (gpg->status.fd[1],
284                                      close_notify_handler, gpg))
285     {
286       rc = mk_error (General_Error);
287       goto leave;
288     }
289   gpg->status.eof = 0;
290   _gpgme_gpg_add_arg (gpg, "--status-fd");
291   {
292     char buf[25];
293     sprintf (buf, "%d", gpg->status.fd[1]);
294     _gpgme_gpg_add_arg (gpg, buf);
295   }
296   _gpgme_gpg_add_arg (gpg, "--no-tty");
297   _gpgme_gpg_add_arg (gpg, "--charset");
298   _gpgme_gpg_add_arg (gpg, "utf8");
299
300  leave:
301   if (rc)
302     {
303       _gpgme_gpg_release (gpg);
304       *r_gpg = NULL;
305     }
306   else
307     *r_gpg = gpg;
308   return rc;
309 }
310
311
312 void
313 _gpgme_gpg_release (GpgObject gpg)
314 {
315   if (!gpg)
316     return;
317
318   while (gpg->arglist)
319     {
320       struct arg_and_data_s *next = gpg->arglist->next;
321
322       xfree (gpg->arglist);
323       gpg->arglist = next;
324     }
325
326   xfree (gpg->status.buffer);
327   xfree (gpg->colon.buffer);
328   if (gpg->argv)
329     free_argv (gpg->argv);
330   gpgme_data_release (gpg->cmd.cb_data);
331   xfree (gpg->cmd.keyword);
332
333   if (gpg->status.fd[0] != -1)
334     _gpgme_io_close (gpg->status.fd[0]);
335   if (gpg->status.fd[1] != -1)
336     _gpgme_io_close (gpg->status.fd[1]);
337   if (gpg->colon.fd[0] != -1)
338     _gpgme_io_close (gpg->colon.fd[0]);
339   if (gpg->colon.fd[1] != -1)
340     _gpgme_io_close (gpg->colon.fd[1]);
341   free_fd_data_map (gpg->fd_data_map);
342   if (gpg->cmd.fd != -1)
343     _gpgme_io_close (gpg->cmd.fd);
344   xfree (gpg);
345 }
346
347 void
348 _gpgme_gpg_enable_pipemode ( GpgObject gpg )
349 {
350     gpg->pm.used = 1;
351     assert ( !gpg->pm.sig );
352     assert ( !gpg->pm.text );
353 }
354     
355 GpgmeError
356 _gpgme_gpg_add_arg ( GpgObject gpg, const char *arg )
357 {
358     struct arg_and_data_s *a;
359
360     assert (gpg);
361     assert (arg);
362
363     if (gpg->pm.active)
364         return 0;
365
366     a = xtrymalloc ( sizeof *a + strlen (arg) );
367     if ( !a ) {
368         gpg->arg_error = 1;
369         return mk_error(Out_Of_Core);
370     }
371     a->next = NULL;
372     a->data = NULL;
373     a->dup_to = -1;
374     strcpy ( a->arg, arg );
375     *gpg->argtail = a;
376     gpg->argtail = &a->next;
377     return 0;
378 }
379
380 GpgmeError
381 _gpgme_gpg_add_data ( GpgObject gpg, GpgmeData data, int dup_to )
382 {
383     struct arg_and_data_s *a;
384
385     assert (gpg);
386     assert (data);
387     if (gpg->pm.active)
388         return 0;
389
390     a = xtrymalloc ( sizeof *a - 1 );
391     if ( !a ) {
392         gpg->arg_error = 1;
393         return mk_error(Out_Of_Core);
394     }
395     a->next = NULL;
396     a->data = data;
397     if ( dup_to == -2 ) {
398         a->print_fd = 1;
399         a->dup_to = -1;
400     }
401     else {
402         a->print_fd = 0;
403         a->dup_to = dup_to;
404     }
405     *gpg->argtail = a;
406     gpg->argtail = &a->next;
407     return 0;
408 }
409
410 GpgmeError
411 _gpgme_gpg_add_pm_data ( GpgObject gpg, GpgmeData data, int what )
412 {
413     GpgmeError rc=0;
414
415     assert ( gpg->pm.used );
416     
417     if ( !what ) {
418         /* the signature */
419         assert ( !gpg->pm.sig );
420         gpg->pm.sig = data;
421     }
422     else if (what == 1) {
423         /* the signed data */
424         assert ( !gpg->pm.text );
425         gpg->pm.text = data;
426     }
427     else {
428         assert (0);
429     }
430
431     if ( gpg->pm.sig && gpg->pm.text ) {
432         if ( !gpg->pm.active ) {
433             /* create the callback handler and connect it to stdin */
434             GpgmeData tmp;
435             
436             rc = gpgme_data_new_with_read_cb ( &tmp, pipemode_cb, gpg );
437             if (!rc )
438                 rc = _gpgme_gpg_add_data (gpg, tmp, 0);
439         }
440         if ( !rc ) {
441             /* here we can reset the handler stuff */
442             gpg->pm.stream_started = 0;
443         }
444     }
445
446     return rc;
447 }
448
449 /*
450  * Note, that the status_handler is allowed to modifiy the args value
451  */
452 void
453 _gpgme_gpg_set_status_handler ( GpgObject gpg,
454                                 GpgStatusHandler fnc, void *fnc_value ) 
455 {
456     assert (gpg);
457     if (gpg->pm.active)
458         return;
459
460     gpg->status.fnc = fnc;
461     gpg->status.fnc_value = fnc_value;
462 }
463
464 /* Kludge to process --with-colon output */
465 GpgmeError
466 _gpgme_gpg_set_colon_line_handler ( GpgObject gpg,
467                                     GpgColonLineHandler fnc, void *fnc_value ) 
468 {
469     assert (gpg);
470     if (gpg->pm.active)
471         return 0;
472
473     gpg->colon.bufsize = 1024;
474     gpg->colon.readpos = 0;
475     gpg->colon.buffer = xtrymalloc (gpg->colon.bufsize);
476     if (!gpg->colon.buffer) {
477         return mk_error (Out_Of_Core);
478     }
479     if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1) {
480         xfree (gpg->colon.buffer); gpg->colon.buffer = NULL;
481         return mk_error (Pipe_Error);
482     }
483     if ( _gpgme_io_set_close_notify (gpg->colon.fd[0],
484                                      close_notify_handler, gpg)
485          ||  _gpgme_io_set_close_notify (gpg->colon.fd[1],
486                                          close_notify_handler, gpg) ) {
487         return mk_error (General_Error);
488     }
489     gpg->colon.eof = 0;
490     gpg->colon.fnc = fnc;
491     gpg->colon.fnc_value = fnc_value;
492     gpg->colon.simple = 0;
493     return 0;
494 }
495
496
497 GpgmeError
498 _gpgme_gpg_set_simple_line_handler ( GpgObject gpg,
499                                      GpgColonLineHandler fnc,
500                                      void *fnc_value ) 
501 {
502     GpgmeError err;
503
504     err = _gpgme_gpg_set_colon_line_handler (gpg, fnc, fnc_value);
505     if (!err)
506         gpg->colon.simple = 1;
507     return err;
508 }
509
510
511 /* 
512  * The Fnc will be called to get a value for one of the commands with
513  * a key KEY.  If the Code pssed to FNC is 0, the function may release
514  * resources associated with the returned value from another call.  To
515  * match such a second call to a first call, the returned value from
516  * the first call is passed as keyword.
517  */
518
519 GpgmeError
520 _gpgme_gpg_set_command_handler (GpgObject gpg,
521                                 GpgCommandHandler fnc, void *fnc_value,
522                                 GpgmeData linked_data)
523 {
524   GpgmeData tmp;
525   GpgmeError err;
526
527   assert (gpg);
528   if (gpg->pm.active)
529     return 0;
530
531   err = gpgme_data_new_with_read_cb (&tmp, command_cb, gpg);
532   if (err)
533     return err;
534         
535   _gpgme_gpg_add_arg ( gpg, "--command-fd" );
536   _gpgme_gpg_add_data (gpg, tmp, -2);
537   gpg->cmd.cb_data = tmp;
538   gpg->cmd.fnc = fnc;
539   gpg->cmd.fnc_value = fnc_value;
540   gpg->cmd.linked_data = linked_data;
541   gpg->cmd.used = 1;
542   return 0;
543 }
544
545
546 static void
547 free_argv ( char **argv )
548 {
549     int i;
550
551     for (i=0; argv[i]; i++ )
552         xfree (argv[i]);
553     xfree (argv);
554 }
555
556 static void
557 free_fd_data_map ( struct fd_data_map_s *fd_data_map )
558 {
559     int i;
560
561     if ( !fd_data_map )
562         return;
563
564     for (i=0; fd_data_map[i].data; i++ ) {
565         if ( fd_data_map[i].fd != -1 )
566             _gpgme_io_close (fd_data_map[i].fd);
567         if ( fd_data_map[i].peer_fd != -1 )
568             _gpgme_io_close (fd_data_map[i].peer_fd);
569         /* don't release data because this is only a reference */
570     }
571     xfree (fd_data_map);
572 }
573
574
575 static GpgmeError
576 build_argv (GpgObject gpg)
577 {
578   struct arg_and_data_s *a;
579   struct fd_data_map_s *fd_data_map;
580   size_t datac=0, argc=0;  
581   char **argv;
582   int need_special = 0;
583   int use_agent = 0;
584   char *p;
585
586   /* We don't want to use the agent with a malformed environment
587      variable.  This is only a very basic test but sufficient to make
588      our life in the regression tests easier. */
589   p = getenv ("GPG_AGENT_INFO");
590   use_agent = (p && strchr (p, ':'));
591        
592   if (gpg->argv)
593     {
594       free_argv (gpg->argv);
595       gpg->argv = NULL;
596     }
597   if (gpg->fd_data_map)
598     {
599       free_fd_data_map (gpg->fd_data_map);
600       gpg->fd_data_map = NULL;
601     }
602
603   argc++;       /* For argv[0].  */
604   for (a = gpg->arglist; a; a = a->next)
605     {
606       argc++;
607       if (a->data)
608         {
609           /*fprintf (stderr, "build_argv: data\n" );*/
610           datac++;
611           if (a->dup_to == -1 && !a->print_fd)
612             need_special = 1;
613         }
614       else
615         {
616           /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
617         }
618     }
619   if (need_special)
620     argc++;
621   if (use_agent)
622     argc++;
623   if (!gpg->cmd.used)
624     argc++;
625   argc += 2; /* --comment */
626
627   argv = xtrycalloc (argc + 1, sizeof *argv);
628   if (!argv)
629     return mk_error (Out_Of_Core);
630   fd_data_map = xtrycalloc (datac + 1, sizeof *fd_data_map);
631   if (!fd_data_map)
632     {
633       free_argv (argv);
634       return mk_error (Out_Of_Core);
635     }
636
637   argc = datac = 0;
638   argv[argc] = xtrystrdup ("gpg"); /* argv[0] */
639   if (!argv[argc])
640     {
641       xfree (fd_data_map);
642       free_argv (argv);
643       return mk_error (Out_Of_Core);
644     }
645   argc++;
646   if (need_special)
647     {
648       argv[argc] = xtrystrdup ("--enable-special-filenames");
649       if (!argv[argc])
650         {
651           xfree (fd_data_map);
652           free_argv (argv);
653           return mk_error (Out_Of_Core);
654         }
655       argc++;
656     }
657   if (use_agent)
658     {
659       argv[argc] = xtrystrdup ("--use-agent");
660       if (!argv[argc])
661         {
662           xfree (fd_data_map);
663           free_argv (argv);
664           return mk_error (Out_Of_Core);
665         }
666       argc++;
667     }
668   if (!gpg->cmd.used)
669     {
670       argv[argc] = xtrystrdup ("--batch");
671       if (!argv[argc])
672         {
673           xfree (fd_data_map);
674           free_argv (argv);
675           return mk_error (Out_Of_Core);
676         }
677       argc++;
678     }
679   argv[argc] = xtrystrdup ("--comment");
680   if (!argv[argc])
681     {
682       xfree (fd_data_map);
683       free_argv (argv);
684       return mk_error (Out_Of_Core);
685     }
686   argc++;
687   argv[argc] = xtrystrdup ("");
688   if (!argv[argc])
689     {
690       xfree (fd_data_map);
691       free_argv (argv);
692       return mk_error (Out_Of_Core);
693     }
694   argc++;
695   for (a = gpg->arglist; a; a = a->next)
696     {
697       if (a->data)
698         {
699           switch (_gpgme_data_get_mode (a->data))
700             {
701             case GPGME_DATA_MODE_NONE:
702             case GPGME_DATA_MODE_INOUT:
703               xfree (fd_data_map);
704               free_argv (argv);
705               return mk_error (Invalid_Mode);
706             case GPGME_DATA_MODE_IN:
707               /* Create a pipe to read from gpg.  */
708               fd_data_map[datac].inbound = 1;
709               break;
710             case GPGME_DATA_MODE_OUT:
711               /* Create a pipe to pass it down to gpg.  */
712               fd_data_map[datac].inbound = 0;
713               break;
714             }
715
716           switch (gpgme_data_get_type (a->data))
717             {
718             case GPGME_DATA_TYPE_NONE:
719               if (fd_data_map[datac].inbound)
720                 break;  /* Allowed.  */
721               xfree (fd_data_map);
722               free_argv (argv);
723               return mk_error (Invalid_Type);
724             case GPGME_DATA_TYPE_MEM:
725             case GPGME_DATA_TYPE_CB:
726               break;
727             case GPGME_DATA_TYPE_FD:
728             case GPGME_DATA_TYPE_FILE:
729               xfree (fd_data_map);
730               free_argv (argv);
731               return mk_error (Not_Implemented);
732             }
733   
734           /* Create a pipe.  */
735           {   
736             int fds[2];
737             
738             if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
739                 == -1)
740               {
741                 xfree (fd_data_map);
742                 free_argv (argv);
743                 return mk_error (Pipe_Error);
744               }
745             if (_gpgme_io_set_close_notify (fds[0],
746                                             close_notify_handler, gpg)
747                 || _gpgme_io_set_close_notify (fds[1],
748                                                close_notify_handler,
749                                                gpg))
750               {
751                 return mk_error (General_Error);
752               }
753             /* If the data_type is FD, we have to do a dup2 here.  */
754             if (fd_data_map[datac].inbound)
755               {
756                 fd_data_map[datac].fd       = fds[0];
757                 fd_data_map[datac].peer_fd  = fds[1];
758               }
759             else
760               {
761                 fd_data_map[datac].fd       = fds[1];
762                 fd_data_map[datac].peer_fd  = fds[0];
763               }
764           }
765
766           /* Hack to get hands on the fd later.  */
767           if (gpg->cmd.used)
768             {
769               if (gpg->cmd.cb_data == a->data)
770                 {
771                   assert (gpg->cmd.idx == -1);
772                   gpg->cmd.idx = datac;
773                 }
774               else if (gpg->cmd.linked_data == a->data)
775                 {
776                   assert (gpg->cmd.linked_idx == -1);
777                   gpg->cmd.linked_idx = datac;
778                 }
779             }
780
781           fd_data_map[datac].data = a->data;
782           fd_data_map[datac].dup_to = a->dup_to;
783           if (a->dup_to == -1)
784             {
785               argv[argc] = xtrymalloc (25);
786               if (!argv[argc])
787                 {
788                   xfree (fd_data_map);
789                   free_argv (argv);
790                   return mk_error (Out_Of_Core);
791                 }
792               sprintf (argv[argc], 
793                        a->print_fd ? "%d" : "-&%d",
794                        fd_data_map[datac].peer_fd);
795               argc++;
796             }
797           datac++;
798         }
799       else
800         {
801           argv[argc] = xtrystrdup (a->arg);
802           if (!argv[argc])
803             {
804               xfree (fd_data_map);
805               free_argv (argv);
806               return mk_error (Out_Of_Core);
807             }
808             argc++;
809         }
810     }
811
812   gpg->argv = argv;
813   gpg->fd_data_map = fd_data_map;
814   return 0;
815 }
816
817 static GpgmeError
818 _gpgme_gpg_add_io_cb (GpgObject gpg, int fd, int dir,
819                       GpgmeIOCb handler, void *data, void **tag)
820 {
821   GpgmeError err;
822
823   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
824   if (err)
825     return err;
826   if (!dir)
827     /* FIXME Kludge around poll() problem.  */
828     err = _gpgme_io_set_nonblocking (fd);
829   return err;
830 }
831
832 GpgmeError
833 _gpgme_gpg_spawn (GpgObject gpg, void *opaque)
834 {
835   GpgmeError rc;
836   int i, n;
837   int status;
838   struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
839
840   if (!gpg)
841     return mk_error (Invalid_Value);
842
843   if (! _gpgme_get_gpg_path ())
844     return mk_error (Invalid_Engine);
845
846   /* Kludge, so that we don't need to check the return code of all the
847      gpgme_gpg_add_arg().  we bail out here instead */
848   if (gpg->arg_error)
849     return mk_error (Out_Of_Core);
850
851   if (gpg->pm.active)
852     return 0;
853
854   rc = build_argv (gpg);
855   if (rc)
856     return rc;
857
858   n = 3; /* status_fd, colon_fd and end of list */
859   for (i = 0; gpg->fd_data_map[i].data; i++) 
860     n++;
861   fd_child_list = xtrycalloc (n + n, sizeof *fd_child_list);
862   if (!fd_child_list)
863     return mk_error (Out_Of_Core);
864   fd_parent_list = fd_child_list + n;
865
866   /* build the fd list for the child */
867   n = 0;
868   if (gpg->colon.fnc)
869     {
870       fd_child_list[n].fd = gpg->colon.fd[1]; 
871       fd_child_list[n].dup_to = 1; /* dup to stdout */
872       n++;
873     }
874   for (i = 0; gpg->fd_data_map[i].data; i++)
875     {
876       if (gpg->fd_data_map[i].dup_to != -1)
877         {
878           fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
879           fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
880           n++;
881         }
882     }
883   fd_child_list[n].fd = -1;
884   fd_child_list[n].dup_to = -1;
885
886   /* Build the fd list for the parent.  */
887   n = 0;
888   if (gpg->status.fd[1] != -1)
889     {
890       fd_parent_list[n].fd = gpg->status.fd[1];
891       fd_parent_list[n].dup_to = -1;
892       n++;
893       gpg->status.fd[1] = -1;
894     }
895   if (gpg->colon.fd[1] != -1)
896     {
897       fd_parent_list[n].fd = gpg->colon.fd[1];
898       fd_parent_list[n].dup_to = -1;
899       n++;
900       gpg->colon.fd[1] = -1;
901     }
902   for (i = 0; gpg->fd_data_map[i].data; i++)
903     {
904       fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
905       fd_parent_list[n].dup_to = -1;
906       n++;
907       gpg->fd_data_map[i].peer_fd = -1;
908     }        
909   fd_parent_list[n].fd = -1;
910   fd_parent_list[n].dup_to = -1;
911
912   status = _gpgme_io_spawn (_gpgme_get_gpg_path (),
913                             gpg->argv, fd_child_list, fd_parent_list);
914   xfree (fd_child_list);
915   if (status == -1)
916     return mk_error (Exec_Error);
917
918   if (gpg->pm.used)
919     gpg->pm.active = 1;
920
921   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
922
923   rc = _gpgme_gpg_add_io_cb (gpg, gpg->status.fd[0], 1,
924                              gpg_status_handler, gpg, &gpg->status.tag);
925   if (rc)
926     /* FIXME: kill the child */
927     return rc;
928
929   if (gpg->colon.fnc)
930     {
931       assert (gpg->colon.fd[0] != -1);
932       rc = _gpgme_gpg_add_io_cb (gpg, gpg->colon.fd[0], 1,
933                                  gpg_colon_line_handler, gpg,
934                                  &gpg->colon.tag);
935       if (rc)
936         /* FIXME: kill the child */
937         return rc;
938     }
939
940   for (i = 0; gpg->fd_data_map[i].data; i++)
941     {
942       if (gpg->cmd.used && i == gpg->cmd.idx)
943         {
944           /* Park the cmd fd.  */
945           gpg->cmd.fd = gpg->fd_data_map[i].fd;
946           gpg->fd_data_map[i].fd = -1;
947         }
948       else
949         {
950           rc = _gpgme_gpg_add_io_cb (gpg, gpg->fd_data_map[i].fd,
951                                      gpg->fd_data_map[i].inbound,
952                                      gpg->fd_data_map[i].inbound
953                                      ? _gpgme_data_inbound_handler
954                                      : _gpgme_data_outbound_handler,
955                                      gpg->fd_data_map[i].data,
956                                      &gpg->fd_data_map[i].tag);
957           
958           if (rc)
959             /* FIXME: kill the child */
960             return rc;
961         }
962     }
963   
964   /* fixme: check what data we can release here */
965   return 0;
966 }
967
968
969 static void
970 gpg_status_handler (void *opaque, int fd)
971 {
972   GpgObject gpg = opaque;
973   int err;
974
975   assert (fd == gpg->status.fd[0]);
976   err = read_status (gpg);
977   if (err)
978     {
979       /* XXX Horrible kludge.  We really must not make use of
980          fnc_value.  */
981       GpgmeCtx ctx = (GpgmeCtx) gpg->status.fnc_value;
982       ctx->error = err;
983       DEBUG1 ("gpg_handler: read_status problem %d\n - stop", err);
984       _gpgme_io_close (fd);
985       return;
986     }
987   if (gpg->status.eof)
988     _gpgme_io_close (fd);
989 }
990
991
992 static int
993 status_cmp (const void *ap, const void *bp)
994 {
995     const struct status_table_s *a = ap;
996     const struct status_table_s *b = bp;
997
998     return strcmp (a->name, b->name);
999 }
1000
1001
1002
1003 /*
1004  * Handle the status output of GnuPG.  This function does read entire
1005  * lines and passes them as C strings to the callback function (we can
1006  * use C Strings because the status output is always UTF-8 encoded).
1007  * Of course we have to buffer the lines to cope with long lines
1008  * e.g. with a large user ID.  Note: We can optimize this to only cope
1009  * with status line code we know about and skip all other stuff
1010  * without buffering (i.e. without extending the buffer).  */
1011 static GpgmeError
1012 read_status (GpgObject gpg)
1013 {
1014   char *p;
1015   int nread;
1016   size_t bufsize = gpg->status.bufsize; 
1017   char *buffer = gpg->status.buffer;
1018   size_t readpos = gpg->status.readpos; 
1019
1020   assert (buffer);
1021   if (bufsize - readpos < 256)
1022     { 
1023       /* Need more room for the read.  */
1024       bufsize += 1024;
1025       buffer = xtryrealloc (buffer, bufsize);
1026       if (!buffer)
1027         return mk_error (Out_Of_Core);
1028     }
1029
1030   nread = _gpgme_io_read (gpg->status.fd[0],
1031                           buffer + readpos, bufsize-readpos);
1032   if (nread == -1)
1033     return mk_error(Read_Error);
1034
1035   if (!nread)
1036     {
1037       gpg->status.eof = 1;
1038       if (gpg->status.fnc)
1039         gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
1040       return 0;
1041     }
1042
1043   while (nread > 0)
1044     {
1045       for (p = buffer + readpos; nread; nread--, p++)
1046         {
1047           if (*p == '\n')
1048             {
1049               /* (we require that the last line is terminated by a LF) */
1050               *p = 0;
1051               if (!strncmp (buffer, "[GNUPG:] ", 9)
1052                   && buffer[9] >= 'A' && buffer[9] <= 'Z')
1053                 {
1054                   struct status_table_s t, *r;
1055                   char *rest;
1056
1057                   rest = strchr (buffer + 9, ' ');
1058                   if (!rest)
1059                     rest = p; /* Set to an empty string.  */
1060                   else
1061                     *rest++ = 0;
1062                     
1063                   t.name = buffer+9;
1064                   /* (the status table has one extra element) */
1065                   r = bsearch (&t, status_table, DIM(status_table) - 1,
1066                                sizeof t, status_cmp);
1067                   if (r)
1068                     {
1069                       if (gpg->cmd.used
1070                           && (r->code == GPGME_STATUS_GET_BOOL
1071                               || r->code == GPGME_STATUS_GET_LINE
1072                               || r->code == GPGME_STATUS_GET_HIDDEN))
1073                         {
1074                           gpg->cmd.code = r->code;
1075                           xfree (gpg->cmd.keyword);
1076                           gpg->cmd.keyword = xtrystrdup (rest);
1077                           if (!gpg->cmd.keyword)
1078                             return mk_error (Out_Of_Core);
1079                           /* This should be the last thing we have
1080                              received and the next thing will be that
1081                              the command handler does its action.  */
1082                           if (nread > 1)
1083                             DEBUG0 ("ERROR, unexpected data in read_status");
1084
1085                           /* Before we can actually add the command
1086                              fd, we might have to flush the linked
1087                              output data pipe.  */
1088                           if (gpg->cmd.linked_idx != -1
1089                               && gpg->fd_data_map[gpg->cmd.linked_idx].fd != -1)
1090                             {
1091                               struct io_select_fd_s fds;
1092                               fds.fd = gpg->fd_data_map[gpg->cmd.linked_idx].fd;
1093                               fds.for_read = 1;
1094                               fds.for_write = 0;
1095                               fds.frozen = 0;
1096                               fds.opaque = NULL;
1097                               do
1098                                 {
1099                                   fds.signaled = 0;
1100                                   _gpgme_io_select (&fds, 1, 1);
1101                                   if (fds.signaled)
1102                                     _gpgme_data_inbound_handler
1103                                       (gpg->cmd.linked_data, fds.fd);
1104                                 }
1105                               while (fds.signaled);
1106                             }
1107
1108                           _gpgme_gpg_add_io_cb
1109                             (gpg, gpg->cmd.fd,
1110                              0, _gpgme_data_outbound_handler,
1111                              gpg->fd_data_map[gpg->cmd.idx].data,
1112                              &gpg->fd_data_map[gpg->cmd.idx].tag);
1113                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
1114                           gpg->cmd.fd = -1;
1115                         }
1116                       else if (gpg->status.fnc)
1117                         {
1118                           gpg->status.fnc (gpg->status.fnc_value, 
1119                                            r->code, rest);
1120                         }
1121                     
1122                       if (r->code == GPGME_STATUS_END_STREAM)
1123                         {
1124                           if (gpg->cmd.used)
1125                             {
1126                               /* XXX We must check if there are any
1127                                  more fds active after removing this
1128                                  one.  */
1129                               (*gpg->io_cbs.remove)
1130                                 (gpg->fd_data_map[gpg->cmd.idx].tag);
1131                               gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
1132                               gpg->fd_data_map[gpg->cmd.idx].fd = -1;
1133                             }
1134                         }
1135                     }
1136                 }
1137               /* To reuse the buffer for the next line we have to
1138                  shift the remaining data to the buffer start and
1139                  restart the loop Hmmm: We can optimize this function
1140                  by looking forward in the buffer to see whether a
1141                  second complete line is available and in this case
1142                  avoid the memmove for this line.  */
1143               nread--; p++;
1144               if (nread)
1145                 memmove (buffer, p, nread);
1146               readpos = 0;
1147               break; /* the for loop */
1148             }
1149           else
1150             readpos++;
1151         }
1152     } 
1153
1154   /* Update the gpg object.  */
1155   gpg->status.bufsize = bufsize;
1156   gpg->status.buffer = buffer;
1157   gpg->status.readpos = readpos;
1158   return 0;
1159 }
1160
1161
1162 /*
1163  * This colonline handler thing is not the clean way to do it.
1164  * It might be better to enhance the GpgmeData object to act as
1165  * a wrapper for a callback.  Same goes for the status thing.
1166  * For now we use this thing here becuase it is easier to implement.
1167  */
1168 static void
1169 gpg_colon_line_handler (void *opaque, int fd)
1170 {
1171   GpgObject gpg = opaque;
1172   GpgmeError rc = 0;
1173
1174   assert (fd == gpg->colon.fd[0]);
1175   rc = read_colon_line (gpg);
1176   if (rc)
1177     {
1178       DEBUG1 ("gpg_colon_line_handler: "
1179               "read problem %d\n - stop", rc);
1180       _gpgme_io_close (fd);
1181       return;
1182     }
1183   if (gpg->colon.eof)
1184     _gpgme_io_close (fd);
1185 }
1186
1187 static GpgmeError
1188 read_colon_line ( GpgObject gpg )
1189 {
1190     char *p;
1191     int nread;
1192     size_t bufsize = gpg->colon.bufsize; 
1193     char *buffer = gpg->colon.buffer;
1194     size_t readpos = gpg->colon.readpos; 
1195
1196     assert (buffer);
1197     if (bufsize - readpos < 256) { 
1198         /* need more room for the read */
1199         bufsize += 1024;
1200         buffer = xtryrealloc (buffer, bufsize);
1201         if ( !buffer ) 
1202             return mk_error (Out_Of_Core);
1203     }
1204     
1205
1206     nread = _gpgme_io_read ( gpg->colon.fd[0],
1207                              buffer+readpos, bufsize-readpos );
1208     if (nread == -1)
1209         return mk_error(Read_Error);
1210
1211     if (!nread) {
1212         gpg->colon.eof = 1;
1213         assert (gpg->colon.fnc);
1214         gpg->colon.fnc ( gpg->colon.fnc_value, NULL );
1215         return 0;
1216     }
1217
1218     while (nread > 0) {
1219         for (p = buffer + readpos; nread; nread--, p++) {
1220             if ( *p == '\n' ) {
1221                 /* (we require that the last line is terminated by a
1222                  * LF) and we skip empty lines.  Note: we use UTF8
1223                  * encoding and escaping of special characters
1224                  * We require at least one colon to cope with
1225                  * some other printed information.
1226                  */
1227                 *p = 0;
1228                 if ( gpg->colon.simple
1229                      || (*buffer && strchr (buffer, ':')) ) {
1230                     assert (gpg->colon.fnc);
1231                     gpg->colon.fnc ( gpg->colon.fnc_value, buffer );
1232                 }
1233             
1234                 /* To reuse the buffer for the next line we have to
1235                  * shift the remaining data to the buffer start and
1236                  * restart the loop Hmmm: We can optimize this
1237                  * function by looking forward in the buffer to see
1238                  * whether a second complete line is available and in
1239                  * this case avoid the memmove for this line.  */
1240                 nread--; p++;
1241                 if (nread)
1242                     memmove (buffer, p, nread);
1243                 readpos = 0;
1244                 break; /* the for loop */
1245             }
1246             else
1247                 readpos++;
1248         }
1249     } 
1250     
1251     /* Update the gpg object.  */
1252     gpg->colon.bufsize = bufsize;
1253     gpg->colon.buffer  = buffer;
1254     gpg->colon.readpos = readpos;
1255     return 0;
1256 }
1257
1258 static GpgmeError
1259 pipemode_copy (char *buffer, size_t length, size_t *nread, GpgmeData data )
1260 {
1261     GpgmeError err;
1262     size_t nbytes;
1263     char tmp[1000], *s, *d;
1264
1265     /* we can optimize this whole thing but for now we just
1266      * return after each escape character */
1267     if (length > 990)
1268         length = 990;
1269
1270     err = gpgme_data_read ( data, tmp, length, &nbytes );
1271     if (err)
1272         return err;
1273     for (s=tmp, d=buffer; nbytes; s++, nbytes--) {
1274         *d++ = *s;
1275         if (*s == '@' ) {
1276             *d++ = '@';
1277             break;
1278         }
1279     }
1280     *nread = d - buffer;
1281     return 0;
1282 }
1283
1284
1285 static int
1286 pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread )
1287 {
1288     GpgObject gpg = opaque;
1289     GpgmeError err;
1290
1291     if ( !buffer || !length || !nread )
1292         return 0; /* those values are reserved for extensions */
1293     *nread =0;
1294     if ( !gpg->pm.stream_started ) {
1295         assert (length > 4 );
1296         strcpy (buffer, "@<@B" );
1297         *nread = 4;
1298         gpg->pm.stream_started = 1;
1299     }
1300     else if ( gpg->pm.sig ) {
1301         err = pipemode_copy ( buffer, length, nread, gpg->pm.sig );
1302         if ( err == GPGME_EOF ) {
1303             gpg->pm.sig = NULL;
1304             assert (length > 4 );
1305             strcpy (buffer, "@t" );
1306             *nread = 2;
1307         }
1308         else if (err) {
1309             DEBUG1 ("pipemode_cb: copy sig failed: %s\n",
1310                      gpgme_strerror (err) );
1311             return -1;
1312         }
1313     }
1314     else if ( gpg->pm.text ) {
1315         err = pipemode_copy ( buffer, length, nread, gpg->pm.text );
1316         if ( err == GPGME_EOF ) {
1317             gpg->pm.text = NULL;
1318             assert (length > 4 );
1319             strcpy (buffer, "@.@>" );
1320             *nread = 4;
1321         }
1322         else if (err) {
1323             DEBUG1 ("pipemode_cb: copy data failed: %s\n",
1324                      gpgme_strerror (err) );
1325             return -1;
1326         }
1327     }
1328     else {
1329         return 0; /* eof */
1330     }
1331
1332     return 0;
1333 }
1334
1335
1336 /* 
1337  * Here we handle --command-fd.  This works closely together with
1338  * the status handler.  
1339  */
1340
1341 static int
1342 command_cb (void *opaque, char *buffer, size_t length, size_t *nread)
1343 {
1344   GpgObject gpg = opaque;
1345   const char *value;
1346   int value_len;
1347
1348   DEBUG0 ("command_cb: enter\n");
1349   assert (gpg->cmd.used);
1350   if (!buffer || !length || !nread)
1351     return 0; /* These values are reserved for extensions.  */
1352   *nread = 0;
1353   if (!gpg->cmd.code)
1354     {
1355       DEBUG0 ("command_cb: no code\n");
1356       return -1;
1357     }
1358     
1359   if (!gpg->cmd.fnc)
1360     {
1361       DEBUG0 ("command_cb: no user cb\n");
1362       return -1;
1363     }
1364
1365   value = gpg->cmd.fnc (gpg->cmd.fnc_value, 
1366                         gpg->cmd.code, gpg->cmd.keyword);
1367   if (!value)
1368     {
1369       DEBUG0 ("command_cb: no data from user cb\n");
1370       gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value);
1371       return -1;
1372     }
1373
1374   value_len = strlen (value);
1375   if (value_len + 1 > length)
1376     {
1377       DEBUG0 ("command_cb: too much data from user cb\n");
1378       gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value);
1379       return -1;
1380     }
1381
1382   memcpy (buffer, value, value_len);
1383   if (!value_len || (value_len && value[value_len-1] != '\n')) 
1384     buffer[value_len++] = '\n';
1385   *nread = value_len;
1386     
1387   gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value);
1388   gpg->cmd.code = 0;
1389   /* And sleep again until read_status will wake us up again.  */
1390   /* XXX We must check if there are any more fds active after removing
1391      this one.  */
1392   (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
1393   gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
1394   gpg->fd_data_map[gpg->cmd.idx].fd = -1;
1395
1396   return 0;
1397 }
1398
1399 GpgmeError
1400 _gpgme_gpg_op_decrypt (GpgObject gpg, GpgmeData ciph, GpgmeData plain)
1401 {
1402   GpgmeError err;
1403
1404   err = _gpgme_gpg_add_arg (gpg, "--decrypt");
1405
1406   /* Tell the gpg object about the data.  */
1407   if (!err)
1408     err = _gpgme_gpg_add_arg (gpg, "--output");
1409   if (!err)
1410     err = _gpgme_gpg_add_arg (gpg, "-");
1411   if (!err)
1412     err = _gpgme_gpg_add_data (gpg, plain, 1);
1413   if (!err)
1414     err = _gpgme_gpg_add_data (gpg, ciph, 0);
1415
1416   return err;
1417 }
1418
1419 GpgmeError
1420 _gpgme_gpg_op_delete (GpgObject gpg, GpgmeKey key, int allow_secret)
1421 {
1422   GpgmeError err;
1423
1424   err = _gpgme_gpg_add_arg (gpg, allow_secret
1425                             ? "--delete-secret-and-public-key"
1426                             : "--delete-key");
1427   if (!err)
1428     err = _gpgme_gpg_add_arg (gpg, "--");
1429   if (!err)
1430     {
1431       const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, NULL, 0);
1432       if (!s)
1433         err = mk_error (Invalid_Key);
1434       else
1435         err = _gpgme_gpg_add_arg (gpg, s);
1436     }
1437
1438   return err;
1439 }
1440
1441
1442 static GpgmeError
1443 _gpgme_append_gpg_args_from_signers (GpgObject gpg,
1444                                      GpgmeCtx ctx /* FIXME */)
1445 {
1446   GpgmeError err = 0;
1447   int i;
1448   GpgmeKey key;
1449
1450   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1451     {
1452       const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_KEYID,
1453                                                  NULL, 0);
1454       if (s)
1455         {
1456           if (!err)
1457             err = _gpgme_gpg_add_arg (gpg, "-u");
1458           if (!err)
1459             err = _gpgme_gpg_add_arg (gpg, s);
1460         }
1461       gpgme_key_unref (key);
1462       if (err) break;
1463     }
1464   return err;
1465 }
1466
1467
1468 GpgmeError
1469 _gpgme_gpg_op_edit (GpgObject gpg, GpgmeKey key, GpgmeData out,
1470                     GpgmeCtx ctx /* FIXME */)
1471 {
1472   GpgmeError err;
1473
1474   err = _gpgme_gpg_add_arg (gpg, "--with-colons");
1475   if (!err)
1476     err = _gpgme_append_gpg_args_from_signers (gpg, ctx);
1477   if (!err)
1478   err = _gpgme_gpg_add_arg (gpg, "--edit-key");
1479   if (!err)
1480     err = _gpgme_gpg_add_data (gpg, out, 1);
1481   if (!err)
1482     err = _gpgme_gpg_add_arg (gpg, "--");
1483   if (!err)
1484     {
1485       const char *s = gpgme_key_get_string_attr (key, GPGME_ATTR_FPR, NULL, 0);
1486       if (!s)
1487         err = mk_error (Invalid_Key);
1488       else
1489         err = _gpgme_gpg_add_arg (gpg, s);
1490     }
1491
1492   return err;
1493 }
1494
1495
1496 static GpgmeError
1497 _gpgme_append_gpg_args_from_recipients (GpgObject gpg,
1498                                         const GpgmeRecipients rset)
1499 {
1500   GpgmeError err = 0;
1501   struct user_id_s *r;
1502
1503   assert (rset);
1504   for (r = rset->list; r; r = r->next)
1505     {
1506       err = _gpgme_gpg_add_arg (gpg, "-r");
1507       if (!err)
1508         _gpgme_gpg_add_arg (gpg, r->name);
1509       if (err)
1510         break;
1511     }    
1512   return err;
1513 }
1514
1515
1516 GpgmeError
1517 _gpgme_gpg_op_encrypt (GpgObject gpg, GpgmeRecipients recp,
1518                        GpgmeData plain, GpgmeData ciph, int use_armor)
1519 {
1520   GpgmeError err;
1521   int symmetric = !recp;
1522
1523   err = _gpgme_gpg_add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1524
1525   if (!err && use_armor)
1526     err = _gpgme_gpg_add_arg (gpg, "--armor");
1527
1528   if (!symmetric)
1529     {
1530       /* If we know that all recipients are valid (full or ultimate trust)
1531          we can suppress further checks.  */
1532       if (!err && !symmetric && _gpgme_recipients_all_valid (recp))
1533         err = _gpgme_gpg_add_arg (gpg, "--always-trust");
1534
1535       if (!err)
1536         err = _gpgme_append_gpg_args_from_recipients (gpg, recp);
1537     }
1538
1539   /* Tell the gpg object about the data.  */
1540   if (!err)
1541     err = _gpgme_gpg_add_arg (gpg, "--output");
1542   if (!err)
1543     err = _gpgme_gpg_add_arg (gpg, "-");
1544   if (!err)
1545     err = _gpgme_gpg_add_data (gpg, ciph, 1);
1546   if (!err)
1547     err = _gpgme_gpg_add_arg (gpg, "--");
1548   if (!err)
1549     err = _gpgme_gpg_add_data (gpg, plain, 0);
1550
1551   return err;
1552 }
1553
1554 GpgmeError
1555 _gpgme_gpg_op_encrypt_sign (GpgObject gpg, GpgmeRecipients recp,
1556                             GpgmeData plain, GpgmeData ciph, int use_armor,
1557                             GpgmeCtx ctx /* FIXME */)
1558 {
1559   GpgmeError err;
1560
1561   err = _gpgme_gpg_add_arg (gpg, "--encrypt");
1562   if (!err)
1563     err = _gpgme_gpg_add_arg (gpg, "--sign");
1564   if (!err && use_armor)
1565     err = _gpgme_gpg_add_arg (gpg, "--armor");
1566
1567   /* If we know that all recipients are valid (full or ultimate trust)
1568    * we can suppress further checks */
1569   if (!err && _gpgme_recipients_all_valid (recp))
1570     err = _gpgme_gpg_add_arg (gpg, "--always-trust");
1571
1572   if (!err)
1573     err = _gpgme_append_gpg_args_from_recipients (gpg, recp);
1574
1575   if (!err)
1576     err = _gpgme_append_gpg_args_from_signers (gpg, ctx);
1577
1578   /* Tell the gpg object about the data.  */
1579   if (!err)
1580     err = _gpgme_gpg_add_arg (gpg, "--output");
1581   if (!err)
1582     err = _gpgme_gpg_add_arg (gpg, "-");
1583   if (!err)
1584     err = _gpgme_gpg_add_data (gpg, ciph, 1);
1585   if (!err)
1586     err = _gpgme_gpg_add_arg (gpg, "--");
1587   if (!err)
1588     err = _gpgme_gpg_add_data (gpg, plain, 0);
1589
1590   return err;
1591 }
1592
1593 GpgmeError
1594 _gpgme_gpg_op_export (GpgObject gpg, GpgmeRecipients recp,
1595                       GpgmeData keydata, int use_armor)
1596 {
1597   GpgmeError err;
1598
1599   err = _gpgme_gpg_add_arg (gpg, "--export");
1600   if (!err && use_armor)
1601     err = _gpgme_gpg_add_arg (gpg, "--armor");
1602   if (!err)
1603     err = _gpgme_gpg_add_data (gpg, keydata, 1);
1604   if (!err)
1605     err = _gpgme_gpg_add_arg (gpg, "--");
1606
1607   if (!err)
1608     {
1609       void *ec;
1610       const char *s;
1611
1612       err = gpgme_recipients_enum_open (recp, &ec);
1613       while (!err && (s = gpgme_recipients_enum_read (recp, &ec)))
1614         err = _gpgme_gpg_add_arg (gpg, s);
1615       if (!err)
1616         err = gpgme_recipients_enum_close (recp, &ec);
1617     }
1618
1619   return err;
1620 }
1621
1622 GpgmeError
1623 _gpgme_gpg_op_genkey (GpgObject gpg, GpgmeData help_data, int use_armor,
1624                       GpgmeData pubkey, GpgmeData seckey)
1625 {
1626   GpgmeError err;
1627
1628   if (!gpg)
1629     return mk_error (Invalid_Value);
1630
1631   /* We need a special mechanism to get the fd of a pipe here, so
1632    * that we can use this for the %pubring and %secring parameters.
1633    * We don't have this yet, so we implement only the adding to the
1634    * standard keyrings */
1635   if (pubkey || seckey)
1636     return err = mk_error (Not_Implemented);
1637
1638   err = _gpgme_gpg_add_arg (gpg, "--gen-key");
1639   if (!err && use_armor)
1640     err = _gpgme_gpg_add_arg (gpg, "--armor");
1641   if (!err)
1642     err = _gpgme_gpg_add_data (gpg, help_data, 0);
1643
1644   return err;
1645 }
1646
1647 GpgmeError
1648 _gpgme_gpg_op_import (GpgObject gpg, GpgmeData keydata)
1649 {
1650   GpgmeError err;
1651
1652   err = _gpgme_gpg_add_arg (gpg, "--import");
1653   if (!err)
1654     err = _gpgme_gpg_add_data (gpg, keydata, 0);
1655
1656   return err;
1657 }
1658
1659
1660 GpgmeError
1661 _gpgme_gpg_op_keylist (GpgObject gpg, const char *pattern, int secret_only,
1662                        int keylist_mode)
1663 {
1664   GpgmeError err;
1665
1666   err = _gpgme_gpg_add_arg (gpg, "--with-colons");
1667   if (!err)
1668     err = _gpgme_gpg_add_arg (gpg, "--fixed-list-mode");
1669   if (!err)
1670     err = _gpgme_gpg_add_arg (gpg, "--with-fingerprint");
1671   if (!err)
1672     err = _gpgme_gpg_add_arg (gpg, 
1673                               (keylist_mode & GPGME_KEYLIST_MODE_SIGS)?
1674                               "--check-sigs" :
1675                               secret_only ? "--list-secret-keys"
1676                               : "--list-keys");
1677   
1678   /* Tell the gpg object about the data */
1679   if (!err)
1680     err = _gpgme_gpg_add_arg (gpg, "--");
1681   if (!err && pattern && *pattern)
1682     err = _gpgme_gpg_add_arg (gpg, pattern);
1683
1684   return err;
1685 }
1686
1687
1688 GpgmeError
1689 _gpgme_gpg_op_keylist_ext (GpgObject gpg, const char *pattern[],
1690                            int secret_only, int reserved, int keylist_mode)
1691 {
1692   GpgmeError err;
1693
1694   if (reserved)
1695     return mk_error (Invalid_Value);
1696
1697   err = _gpgme_gpg_add_arg (gpg, "--with-colons");
1698   if (!err)
1699     err = _gpgme_gpg_add_arg (gpg, "--fixed-list-mode");
1700   if (!err)
1701     err = _gpgme_gpg_add_arg (gpg, "--with-fingerprint");
1702   if (!err)
1703     err = _gpgme_gpg_add_arg (gpg, secret_only ? "--list-secret-keys"
1704                               : "--list-keys");
1705   
1706   /* Tell the gpg object about the data */
1707   if (!err)
1708     err = _gpgme_gpg_add_arg (gpg, "--");
1709   if (!err && pattern && *pattern)
1710     {
1711       while (*pattern && **pattern)
1712         err = _gpgme_gpg_add_arg (gpg, *(pattern++));
1713     }
1714
1715   return err;
1716 }
1717
1718
1719 GpgmeError
1720 _gpgme_gpg_op_sign (GpgObject gpg, GpgmeData in, GpgmeData out,
1721                     GpgmeSigMode mode, int use_armor,
1722                     int use_textmode, GpgmeCtx ctx /* FIXME */)
1723 {
1724   GpgmeError err;
1725
1726   if (mode == GPGME_SIG_MODE_CLEAR)
1727     err = _gpgme_gpg_add_arg (gpg, "--clearsign");
1728   else
1729     {
1730       err = _gpgme_gpg_add_arg (gpg, "--sign");
1731       if (!err && mode == GPGME_SIG_MODE_DETACH)
1732         err = _gpgme_gpg_add_arg (gpg, "--detach");
1733       if (!err && use_armor)
1734         err = _gpgme_gpg_add_arg (gpg, "--armor");
1735       if (!err && use_textmode)
1736         _gpgme_gpg_add_arg (gpg, "--textmode");
1737     }
1738
1739   if (!err)
1740     err = _gpgme_append_gpg_args_from_signers (gpg, ctx);
1741
1742   /* Tell the gpg object about the data.  */
1743   if (!err)
1744     err = _gpgme_gpg_add_data (gpg, in, 0);
1745   if (!err)
1746     err = _gpgme_gpg_add_data (gpg, out, 1);
1747
1748   return err;
1749 }
1750
1751 GpgmeError
1752 _gpgme_gpg_op_trustlist (GpgObject gpg, const char *pattern)
1753 {
1754   GpgmeError err;
1755
1756   err = _gpgme_gpg_add_arg (gpg, "--with-colons");
1757   if (!err)
1758     err = _gpgme_gpg_add_arg (gpg, "--list-trust-path");
1759   
1760   /* Tell the gpg object about the data */
1761   if (!err)
1762     err = _gpgme_gpg_add_arg (gpg, "--");
1763   if (!err)
1764     err = _gpgme_gpg_add_arg (gpg, pattern);
1765
1766   return err;
1767 }
1768
1769 GpgmeError
1770 _gpgme_gpg_op_verify (GpgObject gpg, GpgmeData sig, GpgmeData text)
1771 {
1772   GpgmeError err = 0;
1773
1774   if (_gpgme_data_get_mode (text) == GPGME_DATA_MODE_IN)
1775     {
1776       /* Normal or cleartext signature.  */
1777
1778       err = _gpgme_gpg_add_arg (gpg, "--output");
1779       if (!err)
1780         err = _gpgme_gpg_add_arg (gpg, "-");
1781       if (!err)
1782         err = _gpgme_gpg_add_arg (gpg, "--");
1783       if (!err)
1784         err = _gpgme_gpg_add_data (gpg, sig, 0);
1785       if (!err)
1786         err = _gpgme_gpg_add_data (gpg, text, 1);
1787     }
1788   else
1789     {
1790       if (gpg->pm.used)
1791         {
1792           err = _gpgme_gpg_add_arg (gpg, gpg->pm.used ? "--pipemode" : "--verify");
1793           if (!err)
1794             err = _gpgme_gpg_add_arg (gpg, "--");
1795           if (!err)
1796             err = _gpgme_gpg_add_pm_data (gpg, sig, 0);
1797           if (!err)
1798             err = _gpgme_gpg_add_pm_data (gpg, text, 1);
1799         }
1800       else
1801         {
1802           err = _gpgme_gpg_add_arg (gpg, "--verify");
1803           if (!err)
1804             err = _gpgme_gpg_add_arg (gpg, "--");
1805           if (!err)
1806             err = _gpgme_gpg_add_data (gpg, sig, -1);
1807           if (text)
1808             {
1809               if (!err)
1810                 err = _gpgme_gpg_add_arg (gpg, "-");
1811               if (!err)
1812                 err = _gpgme_gpg_add_data (gpg, text, 0);
1813             }
1814         }
1815     }
1816   return err;
1817 }
1818
1819
1820 void
1821 _gpgme_gpg_set_io_cbs (GpgObject gpg, struct GpgmeIOCbs *io_cbs)
1822 {
1823   gpg->io_cbs = *io_cbs;
1824 }
1825
1826
1827 void
1828 _gpgme_gpg_io_event (GpgObject gpg, GpgmeEventIO type, void *type_data)
1829 {
1830   if (gpg->io_cbs.event)
1831     (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
1832 }