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