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