Trace the use of GPG_ERR_INV_ENGINE.
[gpgme.git] / src / engine-gpg.c
1 /* engine-gpg.c - Gpg Engine.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007,
4                  2009, 2010, 2012 g10 Code GmbH
5
6    This file is part of GPGME.
7
8    GPGME is free software; you can redistribute it and/or modify it
9    under the terms of the GNU Lesser General Public License as
10    published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    GPGME is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with this program; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <errno.h>
30 #ifdef HAVE_UNISTD_H
31 # include <unistd.h>
32 #endif
33 #ifdef HAVE_LOCALE_H
34 #include <locale.h>
35 #endif
36
37 #include "gpgme.h"
38 #include "util.h"
39 #include "ops.h"
40 #include "wait.h"
41 #include "context.h"  /*temp hack until we have GpmeData methods to do I/O */
42 #include "priv-io.h"
43 #include "sema.h"
44 #include "debug.h"
45
46 #include "engine-backend.h"
47
48
49 /* This type is used to build a list of gpg arguments and data
50    sources/sinks.  */
51 struct arg_and_data_s
52 {
53   struct arg_and_data_s *next;
54   gpgme_data_t data;  /* If this is not NULL, use arg below.  */
55   int inbound;     /* True if this is used for reading from gpg.  */
56   int dup_to;
57   int print_fd;    /* Print the fd number and not the special form of it.  */
58   int *arg_locp;   /* Write back the argv idx of this argument when
59                       building command line to this location.  */
60   char arg[1];     /* Used if data above is not used.  */
61 };
62
63
64 struct fd_data_map_s
65 {
66   gpgme_data_t data;
67   int inbound;  /* true if this is used for reading from gpg */
68   int dup_to;
69   int fd;       /* the fd to use */
70   int peer_fd;  /* the other side of the pipe */
71   int arg_loc;  /* The index into the argv for translation purposes.  */
72   void *tag;
73 };
74
75
76 typedef gpgme_error_t (*colon_preprocessor_t) (char *line, char **rline);
77
78 struct engine_gpg
79 {
80   char *file_name;
81
82   char *lc_messages;
83   char *lc_ctype;
84
85   struct arg_and_data_s *arglist;
86   struct arg_and_data_s **argtail;
87
88   struct
89   {
90     int fd[2];
91     int arg_loc;
92     size_t bufsize;
93     char *buffer;
94     size_t readpos;
95     int eof;
96     engine_status_handler_t fnc;
97     void *fnc_value;
98     void *tag;
99   } status;
100
101   /* This is a kludge - see the comment at colon_line_handler.  */
102   struct
103   {
104     int fd[2];
105     int arg_loc;
106     size_t bufsize;
107     char *buffer;
108     size_t readpos;
109     int eof;
110     engine_colon_line_handler_t fnc;  /* this indicate use of this structrue */
111     void *fnc_value;
112     void *tag;
113     colon_preprocessor_t preprocess_fnc;
114   } colon;
115
116   char **argv;
117   struct fd_data_map_s *fd_data_map;
118
119   /* stuff needed for interactive (command) mode */
120   struct
121   {
122     int used;
123     int fd;
124     void *cb_data;
125     int idx;            /* Index in fd_data_map */
126     gpgme_status_code_t code;  /* last code */
127     char *keyword;       /* what has been requested (malloced) */
128     engine_command_handler_t fnc;
129     void *fnc_value;
130     /* The kludges never end.  This is used to couple command handlers
131        with output data in edit key mode.  */
132     gpgme_data_t linked_data;
133     int linked_idx;
134   } cmd;
135
136   struct gpgme_io_cbs io_cbs;
137 };
138
139 typedef struct engine_gpg *engine_gpg_t;
140
141 \f
142 static void
143 gpg_io_event (void *engine, gpgme_event_io_t type, void *type_data)
144 {
145   engine_gpg_t gpg = engine;
146
147   TRACE3 (DEBUG_ENGINE, "gpgme:gpg_io_event", gpg,
148           "event %p, type %d, type_data %p",
149           gpg->io_cbs.event, type, type_data);
150   if (gpg->io_cbs.event)
151     (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, type, type_data);
152 }
153
154
155 static void
156 close_notify_handler (int fd, void *opaque)
157 {
158   engine_gpg_t gpg = opaque;
159   assert (fd != -1);
160
161   if (gpg->status.fd[0] == fd)
162     {
163       if (gpg->status.tag)
164         (*gpg->io_cbs.remove) (gpg->status.tag);
165       gpg->status.fd[0] = -1;
166     }
167   else if (gpg->status.fd[1] == fd)
168     gpg->status.fd[1] = -1;
169   else if (gpg->colon.fd[0] == fd)
170     {
171       if (gpg->colon.tag)
172         (*gpg->io_cbs.remove) (gpg->colon.tag);
173       gpg->colon.fd[0] = -1;
174     }
175   else if (gpg->colon.fd[1] == fd)
176     gpg->colon.fd[1] = -1;
177   else if (gpg->cmd.fd == fd)
178     gpg->cmd.fd = -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                 (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag);
189               gpg->fd_data_map[i].fd = -1;
190               break;
191             }
192           if (gpg->fd_data_map[i].peer_fd == fd)
193             {
194               gpg->fd_data_map[i].peer_fd = -1;
195               break;
196             }
197         }
198     }
199 }
200
201 /* If FRONT is true, push at the front of the list.  Use this for
202    options added late in the process.  */
203 static gpgme_error_t
204 _add_arg (engine_gpg_t gpg, const char *arg, int front, int *arg_locp)
205 {
206   struct arg_and_data_s *a;
207
208   assert (gpg);
209   assert (arg);
210
211   a = malloc (sizeof *a + strlen (arg));
212   if (!a)
213     return gpg_error_from_errno (errno);
214
215   a->data = NULL;
216   a->dup_to = -1;
217   a->arg_locp = arg_locp;
218
219   strcpy (a->arg, arg);
220   if (front)
221     {
222       a->next = gpg->arglist;
223       if (!gpg->arglist)
224         {
225           /* If this is the first argument, we need to update the tail
226              pointer.  */
227           gpg->argtail = &a->next;
228         }
229       gpg->arglist = a;
230     }
231   else
232     {
233       a->next = NULL;
234       *gpg->argtail = a;
235       gpg->argtail = &a->next;
236     }
237
238   return 0;
239 }
240
241 static gpgme_error_t
242 add_arg_ext (engine_gpg_t gpg, const char *arg, int front)
243 {
244   return _add_arg (gpg, arg, front, NULL);
245 }
246
247
248 static gpgme_error_t
249 add_arg_with_locp (engine_gpg_t gpg, const char *arg, int *locp)
250 {
251   return _add_arg (gpg, arg, 0, locp);
252 }
253
254
255 static gpgme_error_t
256 add_arg (engine_gpg_t gpg, const char *arg)
257 {
258   return add_arg_ext (gpg, arg, 0);
259 }
260
261
262 static gpgme_error_t
263 add_data (engine_gpg_t gpg, gpgme_data_t data, int dup_to, int inbound)
264 {
265   struct arg_and_data_s *a;
266
267   assert (gpg);
268   assert (data);
269
270   a = malloc (sizeof *a - 1);
271   if (!a)
272     return gpg_error_from_errno (errno);
273   a->next = NULL;
274   a->data = data;
275   a->inbound = inbound;
276   a->arg_locp = NULL;
277
278   if (dup_to == -2)
279     {
280       a->print_fd = 1;
281       a->dup_to = -1;
282     }
283   else
284     {
285       a->print_fd = 0;
286       a->dup_to = dup_to;
287     }
288   *gpg->argtail = a;
289   gpg->argtail = &a->next;
290   return 0;
291 }
292
293 \f
294 static char *
295 gpg_get_version (const char *file_name)
296 {
297   return _gpgme_get_program_version (file_name ? file_name
298                                      : _gpgme_get_gpg_path ());
299 }
300
301
302 static const char *
303 gpg_get_req_version (void)
304 {
305   return NEED_GPG_VERSION;
306 }
307
308
309 static void
310 free_argv (char **argv)
311 {
312   int i;
313
314   for (i = 0; argv[i]; i++)
315     free (argv[i]);
316   free (argv);
317 }
318
319
320 static void
321 free_fd_data_map (struct fd_data_map_s *fd_data_map)
322 {
323   int i;
324
325   if (!fd_data_map)
326     return;
327
328   for (i = 0; fd_data_map[i].data; i++)
329     {
330       if (fd_data_map[i].fd != -1)
331         _gpgme_io_close (fd_data_map[i].fd);
332       if (fd_data_map[i].peer_fd != -1)
333         _gpgme_io_close (fd_data_map[i].peer_fd);
334       /* Don't release data because this is only a reference.  */
335     }
336   free (fd_data_map);
337 }
338
339
340 static gpgme_error_t
341 gpg_cancel (void *engine)
342 {
343   engine_gpg_t gpg = engine;
344
345   if (!gpg)
346     return gpg_error (GPG_ERR_INV_VALUE);
347
348   /* If gpg may be waiting for a cmd, close the cmd fd first.  On
349      Windows, close operations block on the reader/writer thread.  */
350   if (gpg->cmd.used)
351     {
352       if (gpg->cmd.fd != -1)
353         _gpgme_io_close (gpg->cmd.fd);
354       else if (gpg->fd_data_map
355                && gpg->fd_data_map[gpg->cmd.idx].fd != -1)
356         _gpgme_io_close (gpg->fd_data_map[gpg->cmd.idx].fd);
357     }
358
359   if (gpg->status.fd[0] != -1)
360     _gpgme_io_close (gpg->status.fd[0]);
361   if (gpg->status.fd[1] != -1)
362     _gpgme_io_close (gpg->status.fd[1]);
363   if (gpg->colon.fd[0] != -1)
364     _gpgme_io_close (gpg->colon.fd[0]);
365   if (gpg->colon.fd[1] != -1)
366     _gpgme_io_close (gpg->colon.fd[1]);
367   if (gpg->fd_data_map)
368     {
369       free_fd_data_map (gpg->fd_data_map);
370       gpg->fd_data_map = NULL;
371     }
372
373   return 0;
374 }
375
376 static void
377 gpg_release (void *engine)
378 {
379   engine_gpg_t gpg = engine;
380
381   if (!gpg)
382     return;
383
384   gpg_cancel (engine);
385
386   if (gpg->file_name)
387     free (gpg->file_name);
388
389   if (gpg->lc_messages)
390     free (gpg->lc_messages);
391   if (gpg->lc_ctype)
392     free (gpg->lc_ctype);
393
394   while (gpg->arglist)
395     {
396       struct arg_and_data_s *next = gpg->arglist->next;
397
398       if (gpg->arglist)
399         free (gpg->arglist);
400       gpg->arglist = next;
401     }
402
403   if (gpg->status.buffer)
404     free (gpg->status.buffer);
405   if (gpg->colon.buffer)
406     free (gpg->colon.buffer);
407   if (gpg->argv)
408     free_argv (gpg->argv);
409   if (gpg->cmd.keyword)
410     free (gpg->cmd.keyword);
411
412   free (gpg);
413 }
414
415
416 static gpgme_error_t
417 gpg_new (void **engine, const char *file_name, const char *home_dir)
418 {
419   engine_gpg_t gpg;
420   gpgme_error_t rc = 0;
421   char *dft_display = NULL;
422   char dft_ttyname[64];
423   char *dft_ttytype = NULL;
424
425   gpg = calloc (1, sizeof *gpg);
426   if (!gpg)
427     return gpg_error_from_errno (errno);
428
429   if (file_name)
430     {
431       gpg->file_name = strdup (file_name);
432       if (!gpg->file_name)
433         {
434           rc = gpg_error_from_errno (errno);
435           goto leave;
436         }
437     }
438
439   gpg->argtail = &gpg->arglist;
440   gpg->status.fd[0] = -1;
441   gpg->status.fd[1] = -1;
442   gpg->colon.fd[0] = -1;
443   gpg->colon.fd[1] = -1;
444   gpg->cmd.fd = -1;
445   gpg->cmd.idx = -1;
446   gpg->cmd.linked_data = NULL;
447   gpg->cmd.linked_idx = -1;
448
449   /* Allocate the read buffer for the status pipe.  */
450   gpg->status.bufsize = 1024;
451   gpg->status.readpos = 0;
452   gpg->status.buffer = malloc (gpg->status.bufsize);
453   if (!gpg->status.buffer)
454     {
455       rc = gpg_error_from_errno (errno);
456       goto leave;
457     }
458   /* In any case we need a status pipe - create it right here and
459      don't handle it with our generic gpgme_data_t mechanism.  */
460   if (_gpgme_io_pipe (gpg->status.fd, 1) == -1)
461     {
462       rc = gpg_error_from_errno (errno);
463       goto leave;
464     }
465   if (_gpgme_io_set_close_notify (gpg->status.fd[0],
466                                   close_notify_handler, gpg)
467       || _gpgme_io_set_close_notify (gpg->status.fd[1],
468                                      close_notify_handler, gpg))
469     {
470       rc = gpg_error (GPG_ERR_GENERAL);
471       goto leave;
472     }
473   gpg->status.eof = 0;
474
475   if (home_dir)
476     {
477       rc = add_arg (gpg, "--homedir");
478       if (!rc)
479         rc = add_arg (gpg, home_dir);
480       if (rc)
481         goto leave;
482     }
483
484   rc = add_arg (gpg, "--status-fd");
485   if (rc)
486     goto leave;
487
488   {
489     char buf[25];
490     _gpgme_io_fd2str (buf, sizeof (buf), gpg->status.fd[1]);
491     rc = add_arg_with_locp (gpg, buf, &gpg->status.arg_loc);
492     if (rc)
493       goto leave;
494   }
495
496   rc = add_arg (gpg, "--no-tty");
497   if (!rc)
498     rc = add_arg (gpg, "--charset");
499   if (!rc)
500     rc = add_arg (gpg, "utf8");
501   if (!rc)
502     rc = add_arg (gpg, "--enable-progress-filter");
503   if (rc)
504     goto leave;
505
506   rc = _gpgme_getenv ("DISPLAY", &dft_display);
507   if (rc)
508     goto leave;
509   if (dft_display)
510     {
511       rc = add_arg (gpg, "--display");
512       if (!rc)
513         rc = add_arg (gpg, dft_display);
514
515       free (dft_display);
516     }
517
518   if (isatty (1))
519     {
520       int err;
521
522       err = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
523       if (err)
524         rc = gpg_error_from_errno (err);
525       else
526         {
527           if (*dft_ttyname)
528             {
529               rc = add_arg (gpg, "--ttyname");
530               if (!rc)
531                 rc = add_arg (gpg, dft_ttyname);
532             }
533           else
534             rc = 0;
535           if (!rc)
536             {
537               rc = _gpgme_getenv ("TERM", &dft_ttytype);
538               if (rc)
539                 goto leave;
540
541               if (dft_ttytype)
542                 {
543                   rc = add_arg (gpg, "--ttytype");
544                   if (!rc)
545                     rc = add_arg (gpg, dft_ttytype);
546                 }
547
548               free (dft_ttytype);
549             }
550         }
551       if (rc)
552         goto leave;
553     }
554
555  leave:
556   if (rc)
557     gpg_release (gpg);
558   else
559     *engine = gpg;
560   return rc;
561 }
562
563
564 static gpgme_error_t
565 gpg_set_locale (void *engine, int category, const char *value)
566 {
567   engine_gpg_t gpg = engine;
568
569   if (0)
570     ;
571 #ifdef LC_CTYPE
572   else if (category == LC_CTYPE)
573     {
574       if (gpg->lc_ctype)
575         {
576           free (gpg->lc_ctype);
577           gpg->lc_ctype = NULL;
578         }
579       if (value)
580         {
581           gpg->lc_ctype = strdup (value);
582           if (!gpg->lc_ctype)
583             return gpg_error_from_syserror ();
584         }
585     }
586 #endif
587 #ifdef LC_MESSAGES
588   else if (category == LC_MESSAGES)
589     {
590       if (gpg->lc_messages)
591         {
592           free (gpg->lc_messages);
593           gpg->lc_messages = NULL;
594         }
595       if (value)
596         {
597           gpg->lc_messages = strdup (value);
598           if (!gpg->lc_messages)
599             return gpg_error_from_syserror ();
600         }
601     }
602 #endif /* LC_MESSAGES */
603   else
604     return gpg_error (GPG_ERR_INV_VALUE);
605
606   return 0;
607 }
608
609
610 /* Note, that the status_handler is allowed to modifiy the args
611    value.  */
612 static void
613 gpg_set_status_handler (void *engine, engine_status_handler_t fnc,
614                         void *fnc_value)
615 {
616   engine_gpg_t gpg = engine;
617
618   gpg->status.fnc = fnc;
619   gpg->status.fnc_value = fnc_value;
620 }
621
622 /* Kludge to process --with-colon output.  */
623 static gpgme_error_t
624 gpg_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
625                             void *fnc_value)
626 {
627   engine_gpg_t gpg = engine;
628
629   gpg->colon.bufsize = 1024;
630   gpg->colon.readpos = 0;
631   gpg->colon.buffer = malloc (gpg->colon.bufsize);
632   if (!gpg->colon.buffer)
633     return gpg_error_from_errno (errno);
634
635   if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1)
636     {
637       int saved_errno = errno;
638       free (gpg->colon.buffer);
639       gpg->colon.buffer = NULL;
640       return gpg_error_from_errno (saved_errno);
641     }
642   if (_gpgme_io_set_close_notify (gpg->colon.fd[0], close_notify_handler, gpg)
643       || _gpgme_io_set_close_notify (gpg->colon.fd[1],
644                                      close_notify_handler, gpg))
645     return gpg_error (GPG_ERR_GENERAL);
646   gpg->colon.eof = 0;
647   gpg->colon.fnc = fnc;
648   gpg->colon.fnc_value = fnc_value;
649   return 0;
650 }
651
652
653 static gpgme_error_t
654 command_handler (void *opaque, int fd)
655 {
656   struct io_cb_data *data = (struct io_cb_data *) opaque;
657   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
658   gpgme_error_t err;
659   int processed = 0;
660   assert (gpg->cmd.used);
661   assert (gpg->cmd.code);
662   assert (gpg->cmd.fnc);
663
664   err = gpg->cmd.fnc (gpg->cmd.fnc_value, gpg->cmd.code, gpg->cmd.keyword, fd,
665                       &processed);
666
667   gpg->cmd.code = 0;
668   /* And sleep again until read_status will wake us up again.  */
669   /* XXX We must check if there are any more fds active after removing
670      this one.  */
671   (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag);
672   gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
673   gpg->fd_data_map[gpg->cmd.idx].fd = -1;
674
675   if (err)
676     return err;
677
678   /* We always need to send at least a newline character.  */
679   if (!processed)
680     _gpgme_io_write (fd, "\n", 1);
681
682   return 0;
683 }
684
685
686
687 /* The Fnc will be called to get a value for one of the commands with
688    a key KEY.  If the Code passed to FNC is 0, the function may release
689    resources associated with the returned value from another call.  To
690    match such a second call to a first call, the returned value from
691    the first call is passed as keyword.  */
692 static gpgme_error_t
693 gpg_set_command_handler (void *engine, engine_command_handler_t fnc,
694                          void *fnc_value, gpgme_data_t linked_data)
695 {
696   engine_gpg_t gpg = engine;
697   gpgme_error_t rc;
698
699   rc = add_arg (gpg, "--command-fd");
700   if (rc)
701     return rc;
702
703   /* This is a hack.  We don't have a real data object.  The only
704      thing that matters is that we use something unique, so we use the
705      address of the cmd structure in the gpg object.  */
706   rc = add_data (gpg, (void *) &gpg->cmd, -2, 0);
707   if (rc)
708     return rc;
709
710   gpg->cmd.fnc = fnc;
711   gpg->cmd.cb_data = (void *) &gpg->cmd;
712   gpg->cmd.fnc_value = fnc_value;
713   gpg->cmd.linked_data = linked_data;
714   gpg->cmd.used = 1;
715   return 0;
716 }
717
718
719 static gpgme_error_t
720 build_argv (engine_gpg_t gpg)
721 {
722   gpgme_error_t err;
723   struct arg_and_data_s *a;
724   struct fd_data_map_s *fd_data_map;
725   size_t datac=0, argc=0;
726   char **argv;
727   int need_special = 0;
728   int use_agent = 0;
729   char *p;
730
731   /* We don't want to use the agent with a malformed environment
732      variable.  This is only a very basic test but sufficient to make
733      our life in the regression tests easier. */
734   err = _gpgme_getenv ("GPG_AGENT_INFO", &p);
735   if (err)
736     return err;
737   use_agent = (p && strchr (p, ':'));
738   if (p)
739     free (p);
740
741   if (gpg->argv)
742     {
743       free_argv (gpg->argv);
744       gpg->argv = NULL;
745     }
746   if (gpg->fd_data_map)
747     {
748       free_fd_data_map (gpg->fd_data_map);
749       gpg->fd_data_map = NULL;
750     }
751
752   argc++;       /* For argv[0].  */
753   for (a = gpg->arglist; a; a = a->next)
754     {
755       argc++;
756       if (a->data)
757         {
758           /*fprintf (stderr, "build_argv: data\n" );*/
759           datac++;
760           if (a->dup_to == -1 && !a->print_fd)
761             need_special = 1;
762         }
763       else
764         {
765           /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/
766         }
767     }
768   if (need_special)
769     argc++;
770   if (use_agent)
771     argc++;
772   if (!gpg->cmd.used)
773     argc++;     /* --batch */
774   argc += 1;    /* --no-sk-comment */
775
776   argv = calloc (argc + 1, sizeof *argv);
777   if (!argv)
778     return gpg_error_from_errno (errno);
779   fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
780   if (!fd_data_map)
781     {
782       int saved_errno = errno;
783       free_argv (argv);
784       return gpg_error_from_errno (saved_errno);
785     }
786
787   argc = datac = 0;
788   argv[argc] = strdup ("gpg"); /* argv[0] */
789   if (!argv[argc])
790     {
791       int saved_errno = errno;
792       free (fd_data_map);
793       free_argv (argv);
794       return gpg_error_from_errno (saved_errno);
795     }
796   argc++;
797   if (need_special)
798     {
799       argv[argc] = strdup ("--enable-special-filenames");
800       if (!argv[argc])
801         {
802           int saved_errno = errno;
803           free (fd_data_map);
804           free_argv (argv);
805           return gpg_error_from_errno (saved_errno);
806         }
807       argc++;
808     }
809   if (use_agent)
810     {
811       argv[argc] = strdup ("--use-agent");
812       if (!argv[argc])
813         {
814           int saved_errno = errno;
815           free (fd_data_map);
816           free_argv (argv);
817           return gpg_error_from_errno (saved_errno);
818         }
819       argc++;
820     }
821   if (!gpg->cmd.used)
822     {
823       argv[argc] = strdup ("--batch");
824       if (!argv[argc])
825         {
826           int saved_errno = errno;
827           free (fd_data_map);
828           free_argv (argv);
829           return gpg_error_from_errno (saved_errno);
830         }
831       argc++;
832     }
833   argv[argc] = strdup ("--no-sk-comment");
834   if (!argv[argc])
835     {
836       int saved_errno = errno;
837       free (fd_data_map);
838       free_argv (argv);
839       return gpg_error_from_errno (saved_errno);
840     }
841   argc++;
842   for (a = gpg->arglist; a; a = a->next)
843     {
844       if (a->arg_locp)
845         *(a->arg_locp) = argc;
846
847       if (a->data)
848         {
849           /* Create a pipe to pass it down to gpg.  */
850           fd_data_map[datac].inbound = a->inbound;
851
852           /* Create a pipe.  */
853           {
854             int fds[2];
855
856             if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
857                 == -1)
858               {
859                 int saved_errno = errno;
860                 free (fd_data_map);
861                 free_argv (argv);
862                 return gpg_error (saved_errno);
863               }
864             if (_gpgme_io_set_close_notify (fds[0],
865                                             close_notify_handler, gpg)
866                 || _gpgme_io_set_close_notify (fds[1],
867                                                close_notify_handler,
868                                                gpg))
869               {
870                 return gpg_error (GPG_ERR_GENERAL);
871               }
872             /* If the data_type is FD, we have to do a dup2 here.  */
873             if (fd_data_map[datac].inbound)
874               {
875                 fd_data_map[datac].fd       = fds[0];
876                 fd_data_map[datac].peer_fd  = fds[1];
877               }
878             else
879               {
880                 fd_data_map[datac].fd       = fds[1];
881                 fd_data_map[datac].peer_fd  = fds[0];
882               }
883           }
884
885           /* Hack to get hands on the fd later.  */
886           if (gpg->cmd.used)
887             {
888               if (gpg->cmd.cb_data == a->data)
889                 {
890                   assert (gpg->cmd.idx == -1);
891                   gpg->cmd.idx = datac;
892                 }
893               else if (gpg->cmd.linked_data == a->data)
894                 {
895                   assert (gpg->cmd.linked_idx == -1);
896                   gpg->cmd.linked_idx = datac;
897                 }
898             }
899
900           fd_data_map[datac].data = a->data;
901           fd_data_map[datac].dup_to = a->dup_to;
902
903           if (a->dup_to == -1)
904             {
905               char *ptr;
906               int buflen = 25;
907
908               argv[argc] = malloc (buflen);
909               if (!argv[argc])
910                 {
911                   int saved_errno = errno;
912                   free (fd_data_map);
913                   free_argv (argv);
914                   return gpg_error_from_errno (saved_errno);
915                 }
916
917               ptr = argv[argc];
918               if (!a->print_fd)
919                 {
920                   *(ptr++) = '-';
921                   *(ptr++) = '&';
922                   buflen -= 2;
923                 }
924
925               _gpgme_io_fd2str (ptr, buflen, fd_data_map[datac].peer_fd);
926               fd_data_map[datac].arg_loc = argc;
927               argc++;
928             }
929           datac++;
930         }
931       else
932         {
933           argv[argc] = strdup (a->arg);
934           if (!argv[argc])
935             {
936               int saved_errno = errno;
937               free (fd_data_map);
938               free_argv (argv);
939               return gpg_error_from_errno (saved_errno);
940             }
941             argc++;
942         }
943     }
944
945   gpg->argv = argv;
946   gpg->fd_data_map = fd_data_map;
947   return 0;
948 }
949
950
951 static gpgme_error_t
952 add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
953            void **tag)
954 {
955   gpgme_error_t err;
956
957   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
958   if (err)
959     return err;
960   if (!dir)
961     /* FIXME Kludge around poll() problem.  */
962     err = _gpgme_io_set_nonblocking (fd);
963   return err;
964 }
965
966
967 /* Handle the status output of GnuPG.  This function does read entire
968    lines and passes them as C strings to the callback function (we can
969    use C Strings because the status output is always UTF-8 encoded).
970    Of course we have to buffer the lines to cope with long lines
971    e.g. with a large user ID.  Note: We can optimize this to only cope
972    with status line code we know about and skip all other stuff
973    without buffering (i.e. without extending the buffer).  */
974 static gpgme_error_t
975 read_status (engine_gpg_t gpg)
976 {
977   char *p;
978   int nread;
979   size_t bufsize = gpg->status.bufsize;
980   char *buffer = gpg->status.buffer;
981   size_t readpos = gpg->status.readpos;
982
983   assert (buffer);
984   if (bufsize - readpos < 256)
985     {
986       /* Need more room for the read.  */
987       bufsize += 1024;
988       buffer = realloc (buffer, bufsize);
989       if (!buffer)
990         return gpg_error_from_errno (errno);
991     }
992
993   nread = _gpgme_io_read (gpg->status.fd[0],
994                           buffer + readpos, bufsize-readpos);
995   if (nread == -1)
996     return gpg_error_from_errno (errno);
997
998   if (!nread)
999     {
1000       gpg->status.eof = 1;
1001       if (gpg->status.fnc)
1002         {
1003           gpgme_error_t err;
1004           err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
1005           if (err)
1006             return err;
1007         }
1008       return 0;
1009     }
1010
1011   while (nread > 0)
1012     {
1013       for (p = buffer + readpos; nread; nread--, p++)
1014         {
1015           if (*p == '\n')
1016             {
1017               /* (we require that the last line is terminated by a LF) */
1018               if (p > buffer && p[-1] == '\r')
1019                 p[-1] = 0;
1020               *p = 0;
1021               if (!strncmp (buffer, "[GNUPG:] ", 9)
1022                   && buffer[9] >= 'A' && buffer[9] <= 'Z')
1023                 {
1024                   char *rest;
1025                   gpgme_status_code_t r;
1026
1027                   rest = strchr (buffer + 9, ' ');
1028                   if (!rest)
1029                     rest = p; /* Set to an empty string.  */
1030                   else
1031                     *rest++ = 0;
1032
1033                   r = _gpgme_parse_status (buffer + 9);
1034                   if (r >= 0)
1035                     {
1036                       if (gpg->cmd.used
1037                           && (r == GPGME_STATUS_GET_BOOL
1038                               || r == GPGME_STATUS_GET_LINE
1039                               || r == GPGME_STATUS_GET_HIDDEN))
1040                         {
1041                           gpg->cmd.code = r;
1042                           if (gpg->cmd.keyword)
1043                             free (gpg->cmd.keyword);
1044                           gpg->cmd.keyword = strdup (rest);
1045                           if (!gpg->cmd.keyword)
1046                             return gpg_error_from_errno (errno);
1047                           /* This should be the last thing we have
1048                              received and the next thing will be that
1049                              the command handler does its action.  */
1050                           if (nread > 1)
1051                             TRACE0 (DEBUG_CTX, "gpgme:read_status", 0,
1052                                     "error: unexpected data");
1053
1054                           add_io_cb (gpg, gpg->cmd.fd, 0,
1055                                      command_handler, gpg,
1056                                      &gpg->fd_data_map[gpg->cmd.idx].tag);
1057                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
1058                           gpg->cmd.fd = -1;
1059                         }
1060                       else if (gpg->status.fnc)
1061                         {
1062                           gpgme_error_t err;
1063                           err = gpg->status.fnc (gpg->status.fnc_value,
1064                                                  r, rest);
1065                           if (err)
1066                             return err;
1067                         }
1068
1069                       if (r == GPGME_STATUS_END_STREAM)
1070                         {
1071                           if (gpg->cmd.used)
1072                             {
1073                               /* Before we can actually add the
1074                                  command fd, we might have to flush
1075                                  the linked output data pipe.  */
1076                               if (gpg->cmd.linked_idx != -1
1077                                   && gpg->fd_data_map[gpg->cmd.linked_idx].fd
1078                                   != -1)
1079                                 {
1080                                   struct io_select_fd_s fds;
1081                                   fds.fd =
1082                                     gpg->fd_data_map[gpg->cmd.linked_idx].fd;
1083                                   fds.for_read = 1;
1084                                   fds.for_write = 0;
1085                                   fds.opaque = NULL;
1086                                   do
1087                                     {
1088                                       fds.signaled = 0;
1089                                       _gpgme_io_select (&fds, 1, 1);
1090                                       if (fds.signaled)
1091                                         _gpgme_data_inbound_handler
1092                                           (gpg->cmd.linked_data, fds.fd);
1093                                     }
1094                                   while (fds.signaled);
1095                                 }
1096
1097                               /* XXX We must check if there are any
1098                                  more fds active after removing this
1099                                  one.  */
1100                               (*gpg->io_cbs.remove)
1101                                 (gpg->fd_data_map[gpg->cmd.idx].tag);
1102                               gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
1103                               gpg->fd_data_map[gpg->cmd.idx].fd = -1;
1104                             }
1105                         }
1106                     }
1107                 }
1108               /* To reuse the buffer for the next line we have to
1109                  shift the remaining data to the buffer start and
1110                  restart the loop Hmmm: We can optimize this function
1111                  by looking forward in the buffer to see whether a
1112                  second complete line is available and in this case
1113                  avoid the memmove for this line.  */
1114               nread--; p++;
1115               if (nread)
1116                 memmove (buffer, p, nread);
1117               readpos = 0;
1118               break; /* the for loop */
1119             }
1120           else
1121             readpos++;
1122         }
1123     }
1124
1125   /* Update the gpg object.  */
1126   gpg->status.bufsize = bufsize;
1127   gpg->status.buffer = buffer;
1128   gpg->status.readpos = readpos;
1129   return 0;
1130 }
1131
1132
1133 static gpgme_error_t
1134 status_handler (void *opaque, int fd)
1135 {
1136   struct io_cb_data *data = (struct io_cb_data *) opaque;
1137   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
1138   int err;
1139
1140   assert (fd == gpg->status.fd[0]);
1141   err = read_status (gpg);
1142   if (err)
1143     return err;
1144   if (gpg->status.eof)
1145     _gpgme_io_close (fd);
1146   return 0;
1147 }
1148
1149
1150 static gpgme_error_t
1151 read_colon_line (engine_gpg_t gpg)
1152 {
1153   char *p;
1154   int nread;
1155   size_t bufsize = gpg->colon.bufsize;
1156   char *buffer = gpg->colon.buffer;
1157   size_t readpos = gpg->colon.readpos;
1158
1159   assert (buffer);
1160   if (bufsize - readpos < 256)
1161     {
1162       /* Need more room for the read.  */
1163       bufsize += 1024;
1164       buffer = realloc (buffer, bufsize);
1165       if (!buffer)
1166         return gpg_error_from_errno (errno);
1167     }
1168
1169   nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
1170   if (nread == -1)
1171     return gpg_error_from_errno (errno);
1172
1173   if (!nread)
1174     {
1175       gpg->colon.eof = 1;
1176       assert (gpg->colon.fnc);
1177       gpg->colon.fnc (gpg->colon.fnc_value, NULL);
1178       return 0;
1179     }
1180
1181   while (nread > 0)
1182     {
1183       for (p = buffer + readpos; nread; nread--, p++)
1184         {
1185           if ( *p == '\n' )
1186             {
1187               /* (we require that the last line is terminated by a LF)
1188                  and we skip empty lines.  Note: we use UTF8 encoding
1189                  and escaping of special characters.  We require at
1190                  least one colon to cope with some other printed
1191                  information.  */
1192               *p = 0;
1193               if (*buffer && strchr (buffer, ':'))
1194                 {
1195                   char *line = NULL;
1196
1197                   if (gpg->colon.preprocess_fnc)
1198                     {
1199                       gpgme_error_t err;
1200
1201                       err = gpg->colon.preprocess_fnc (buffer, &line);
1202                       if (err)
1203                         return err;
1204                     }
1205
1206                   assert (gpg->colon.fnc);
1207                   gpg->colon.fnc (gpg->colon.fnc_value, line ? line : buffer);
1208                   if (line)
1209                     free (line);
1210                 }
1211
1212               /* To reuse the buffer for the next line we have to
1213                  shift the remaining data to the buffer start and
1214                  restart the loop Hmmm: We can optimize this function
1215                  by looking forward in the buffer to see whether a
1216                  second complete line is available and in this case
1217                  avoid the memmove for this line.  */
1218               nread--; p++;
1219               if (nread)
1220                 memmove (buffer, p, nread);
1221               readpos = 0;
1222               break; /* The for loop.  */
1223             }
1224           else
1225             readpos++;
1226         }
1227     }
1228
1229   /* Update the gpg object.  */
1230   gpg->colon.bufsize = bufsize;
1231   gpg->colon.buffer  = buffer;
1232   gpg->colon.readpos = readpos;
1233   return 0;
1234 }
1235
1236
1237 /* This colonline handler thing is not the clean way to do it.  It
1238    might be better to enhance the gpgme_data_t object to act as a wrapper
1239    for a callback.  Same goes for the status thing.  For now we use
1240    this thing here because it is easier to implement.  */
1241 static gpgme_error_t
1242 colon_line_handler (void *opaque, int fd)
1243 {
1244   struct io_cb_data *data = (struct io_cb_data *) opaque;
1245   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
1246   gpgme_error_t rc = 0;
1247
1248   assert (fd == gpg->colon.fd[0]);
1249   rc = read_colon_line (gpg);
1250   if (rc)
1251     return rc;
1252   if (gpg->colon.eof)
1253     _gpgme_io_close (fd);
1254   return 0;
1255 }
1256
1257
1258 static gpgme_error_t
1259 start (engine_gpg_t gpg)
1260 {
1261   gpgme_error_t rc;
1262   int saved_errno;
1263   int i, n;
1264   int status;
1265   struct spawn_fd_item_s *fd_list;
1266   pid_t pid;
1267
1268   if (!gpg)
1269     return gpg_error (GPG_ERR_INV_VALUE);
1270
1271   if (!gpg->file_name && !_gpgme_get_gpg_path ())
1272     return trace_gpg_error (GPG_ERR_INV_ENGINE);
1273
1274   if (gpg->lc_ctype)
1275     {
1276       rc = add_arg_ext (gpg, gpg->lc_ctype, 1);
1277       if (!rc)
1278         rc = add_arg_ext (gpg, "--lc-ctype", 1);
1279       if (rc)
1280         return rc;
1281     }
1282
1283   if (gpg->lc_messages)
1284     {
1285       rc = add_arg_ext (gpg, gpg->lc_messages, 1);
1286       if (!rc)
1287         rc = add_arg_ext (gpg, "--lc-messages", 1);
1288       if (rc)
1289         return rc;
1290     }
1291
1292   rc = build_argv (gpg);
1293   if (rc)
1294     return rc;
1295
1296   /* status_fd, colon_fd and end of list.  */
1297   n = 3;
1298   for (i = 0; gpg->fd_data_map[i].data; i++)
1299     n++;
1300   fd_list = calloc (n, sizeof *fd_list);
1301   if (! fd_list)
1302     return gpg_error_from_errno (errno);
1303
1304   /* Build the fd list for the child.  */
1305   n = 0;
1306   fd_list[n].fd = gpg->status.fd[1];
1307   fd_list[n].dup_to = -1;
1308   fd_list[n].arg_loc = gpg->status.arg_loc;
1309   n++;
1310   if (gpg->colon.fnc)
1311     {
1312       fd_list[n].fd = gpg->colon.fd[1];
1313       fd_list[n].dup_to = 1;
1314       n++;
1315     }
1316   for (i = 0; gpg->fd_data_map[i].data; i++)
1317     {
1318       fd_list[n].fd = gpg->fd_data_map[i].peer_fd;
1319       fd_list[n].dup_to = gpg->fd_data_map[i].dup_to;
1320       fd_list[n].arg_loc = gpg->fd_data_map[i].arg_loc;
1321       n++;
1322     }
1323   fd_list[n].fd = -1;
1324   fd_list[n].dup_to = -1;
1325
1326   status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name :
1327                             _gpgme_get_gpg_path (), gpg->argv,
1328                             IOSPAWN_FLAG_ALLOW_SET_FG,
1329                             fd_list, NULL, NULL, &pid);
1330   saved_errno = errno;
1331
1332   free (fd_list);
1333   if (status == -1)
1334     return gpg_error_from_errno (saved_errno);
1335
1336   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
1337
1338   rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
1339                   &gpg->status.tag);
1340   if (rc)
1341     /* FIXME: kill the child */
1342     return rc;
1343
1344   if (gpg->colon.fnc)
1345     {
1346       assert (gpg->colon.fd[0] != -1);
1347       rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
1348                       &gpg->colon.tag);
1349       if (rc)
1350         /* FIXME: kill the child */
1351         return rc;
1352     }
1353
1354   for (i = 0; gpg->fd_data_map[i].data; i++)
1355     {
1356       if (gpg->cmd.used && i == gpg->cmd.idx)
1357         {
1358           /* Park the cmd fd.  */
1359           gpg->cmd.fd = gpg->fd_data_map[i].fd;
1360           gpg->fd_data_map[i].fd = -1;
1361         }
1362       else
1363         {
1364           rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
1365                           gpg->fd_data_map[i].inbound,
1366                           gpg->fd_data_map[i].inbound
1367                           ? _gpgme_data_inbound_handler
1368                           : _gpgme_data_outbound_handler,
1369                           gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
1370
1371           if (rc)
1372             /* FIXME: kill the child */
1373             return rc;
1374         }
1375     }
1376
1377   gpg_io_event (gpg, GPGME_EVENT_START, NULL);
1378
1379   /* fixme: check what data we can release here */
1380   return 0;
1381 }
1382
1383
1384 static gpgme_error_t
1385 gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1386 {
1387   engine_gpg_t gpg = engine;
1388   gpgme_error_t err;
1389
1390   err = add_arg (gpg, "--decrypt");
1391
1392   /* Tell the gpg object about the data.  */
1393   if (!err)
1394     err = add_arg (gpg, "--output");
1395   if (!err)
1396     err = add_arg (gpg, "-");
1397   if (!err)
1398     err = add_data (gpg, plain, 1, 1);
1399   if (!err)
1400     err = add_arg (gpg, "--");
1401   if (!err)
1402     err = add_data (gpg, ciph, -1, 0);
1403
1404   if (!err)
1405     start (gpg);
1406   return err;
1407 }
1408
1409 static gpgme_error_t
1410 gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
1411 {
1412   engine_gpg_t gpg = engine;
1413   gpgme_error_t err;
1414
1415   err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
1416                  : "--delete-key");
1417   if (!err)
1418     err = add_arg (gpg, "--");
1419   if (!err)
1420     {
1421       if (!key->subkeys || !key->subkeys->fpr)
1422         return gpg_error (GPG_ERR_INV_VALUE);
1423       else
1424         err = add_arg (gpg, key->subkeys->fpr);
1425     }
1426
1427   if (!err)
1428     start (gpg);
1429   return err;
1430 }
1431
1432
1433 static gpgme_error_t
1434 gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1435 {
1436   engine_gpg_t gpg = engine;
1437   gpgme_error_t err;
1438
1439   if (!key || !key->subkeys || !key->subkeys->fpr)
1440     return gpg_error (GPG_ERR_INV_CERT_OBJ);
1441
1442   err = add_arg (gpg, "--passwd");
1443   if (!err)
1444     err = add_arg (gpg, key->subkeys->fpr);
1445   if (!err)
1446     start (gpg);
1447   return err;
1448 }
1449
1450
1451 static gpgme_error_t
1452 append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1453 {
1454   gpgme_error_t err = 0;
1455   int i;
1456   gpgme_key_t key;
1457
1458   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1459     {
1460       const char *s = key->subkeys ? key->subkeys->keyid : NULL;
1461       if (s)
1462         {
1463           if (!err)
1464             err = add_arg (gpg, "-u");
1465           if (!err)
1466             err = add_arg (gpg, s);
1467         }
1468       gpgme_key_unref (key);
1469       if (err) break;
1470     }
1471   return err;
1472 }
1473
1474
1475 static gpgme_error_t
1476 append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1477 {
1478   gpgme_error_t err = 0;
1479   gpgme_sig_notation_t notation;
1480
1481   notation = gpgme_sig_notation_get (ctx);
1482
1483   while (!err && notation)
1484     {
1485       if (notation->name
1486           && !(notation->flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
1487         err = gpg_error (GPG_ERR_INV_VALUE);
1488       else if (notation->name)
1489         {
1490           char *arg;
1491
1492           /* Maximum space needed is one byte for the "critical" flag,
1493              the name, one byte for '=', the value, and a terminating
1494              '\0'.  */
1495
1496           arg = malloc (1 + notation->name_len + 1 + notation->value_len + 1);
1497           if (!arg)
1498             err = gpg_error_from_errno (errno);
1499
1500           if (!err)
1501             {
1502               char *argp = arg;
1503
1504               if (notation->critical)
1505                 *(argp++) = '!';
1506
1507               memcpy (argp, notation->name, notation->name_len);
1508               argp += notation->name_len;
1509
1510               *(argp++) = '=';
1511
1512               /* We know that notation->name is '\0' terminated.  */
1513               strcpy (argp, notation->value);
1514             }
1515
1516           if (!err)
1517             err = add_arg (gpg, "--sig-notation");
1518           if (!err)
1519             err = add_arg (gpg, arg);
1520
1521           if (arg)
1522             free (arg);
1523         }
1524       else
1525         {
1526           /* This is a policy URL.  */
1527
1528           char *value;
1529
1530           if (notation->critical)
1531             {
1532               value = malloc (1 + notation->value_len + 1);
1533               if (!value)
1534                 err = gpg_error_from_errno (errno);
1535               else
1536                 {
1537                   value[0] = '!';
1538                   /* We know that notation->value is '\0' terminated.  */
1539                   strcpy (&value[1], notation->value);
1540                 }
1541             }
1542           else
1543             value = notation->value;
1544
1545           if (!err)
1546             err = add_arg (gpg, "--sig-policy-url");
1547           if (!err)
1548             err = add_arg (gpg, value);
1549
1550           if (value != notation->value)
1551             free (value);
1552         }
1553
1554       notation = notation->next;
1555     }
1556   return err;
1557 }
1558
1559
1560 static gpgme_error_t
1561 gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
1562           gpgme_ctx_t ctx /* FIXME */)
1563 {
1564   engine_gpg_t gpg = engine;
1565   gpgme_error_t err;
1566
1567   err = add_arg (gpg, "--with-colons");
1568   if (!err)
1569     err = append_args_from_signers (gpg, ctx);
1570   if (!err)
1571   err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
1572   if (!err)
1573     err = add_data (gpg, out, 1, 1);
1574   if (!err)
1575     err = add_arg (gpg, "--");
1576   if (!err && type == 0)
1577     {
1578       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1579       if (!s)
1580         err = gpg_error (GPG_ERR_INV_VALUE);
1581       else
1582         err = add_arg (gpg, s);
1583     }
1584   if (!err)
1585     err = start (gpg);
1586
1587   return err;
1588 }
1589
1590
1591 static gpgme_error_t
1592 append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
1593 {
1594   gpgme_error_t err = 0;
1595   int i = 0;
1596
1597   while (recp[i])
1598     {
1599       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1600         err = gpg_error (GPG_ERR_INV_VALUE);
1601       if (!err)
1602         err = add_arg (gpg, "-r");
1603       if (!err)
1604         err = add_arg (gpg, recp[i]->subkeys->fpr);
1605       if (err)
1606         break;
1607       i++;
1608     }
1609   return err;
1610 }
1611
1612
1613 static gpgme_error_t
1614 gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1615              gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1616 {
1617   engine_gpg_t gpg = engine;
1618   gpgme_error_t err;
1619   int symmetric = !recp;
1620
1621   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1622
1623   if (!err && use_armor)
1624     err = add_arg (gpg, "--armor");
1625
1626   if (!symmetric)
1627     {
1628       /* If we know that all recipients are valid (full or ultimate trust)
1629          we can suppress further checks.  */
1630       if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1631         err = add_arg (gpg, "--always-trust");
1632
1633       if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
1634         err = add_arg (gpg, "--no-encrypt-to");
1635
1636       if (!err)
1637         err = append_args_from_recipients (gpg, recp);
1638     }
1639
1640   /* Tell the gpg object about the data.  */
1641   if (!err)
1642     err = add_arg (gpg, "--output");
1643   if (!err)
1644     err = add_arg (gpg, "-");
1645   if (!err)
1646     err = add_data (gpg, ciph, 1, 1);
1647   if (gpgme_data_get_file_name (plain))
1648     {
1649       if (!err)
1650         err = add_arg (gpg, "--set-filename");
1651       if (!err)
1652         err = add_arg (gpg, gpgme_data_get_file_name (plain));
1653     }
1654   if (!err)
1655     err = add_arg (gpg, "--");
1656   if (!err)
1657     err = add_data (gpg, plain, -1, 0);
1658
1659   if (!err)
1660     err = start (gpg);
1661
1662   return err;
1663 }
1664
1665
1666 static gpgme_error_t
1667 gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
1668                   gpgme_encrypt_flags_t flags, gpgme_data_t plain,
1669                   gpgme_data_t ciph, int use_armor,
1670                   gpgme_ctx_t ctx /* FIXME */)
1671 {
1672   engine_gpg_t gpg = engine;
1673   gpgme_error_t err;
1674
1675   err = add_arg (gpg, "--encrypt");
1676   if (!err)
1677     err = add_arg (gpg, "--sign");
1678   if (!err && use_armor)
1679     err = add_arg (gpg, "--armor");
1680
1681   /* If we know that all recipients are valid (full or ultimate trust)
1682      we can suppress further checks.  */
1683   if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1684     err = add_arg (gpg, "--always-trust");
1685
1686   if (!err)
1687     err = append_args_from_recipients (gpg, recp);
1688
1689   if (!err)
1690     err = append_args_from_signers (gpg, ctx);
1691   if (!err)
1692     err = append_args_from_sig_notations (gpg, ctx);
1693
1694   /* Tell the gpg object about the data.  */
1695   if (!err)
1696     err = add_arg (gpg, "--output");
1697   if (!err)
1698     err = add_arg (gpg, "-");
1699   if (!err)
1700     err = add_data (gpg, ciph, 1, 1);
1701   if (gpgme_data_get_file_name (plain))
1702     {
1703       if (!err)
1704         err = add_arg (gpg, "--set-filename");
1705       if (!err)
1706         err = add_arg (gpg, gpgme_data_get_file_name (plain));
1707     }
1708   if (!err)
1709     err = add_arg (gpg, "--");
1710   if (!err)
1711     err = add_data (gpg, plain, -1, 0);
1712
1713   if (!err)
1714     err = start (gpg);
1715
1716   return err;
1717 }
1718
1719
1720 static gpgme_error_t
1721 export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
1722                gpgme_data_t keydata, int use_armor)
1723 {
1724   gpgme_error_t err = 0;
1725
1726   if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
1727                 |GPGME_EXPORT_MODE_MINIMAL)))
1728     return gpg_error (GPG_ERR_NOT_SUPPORTED);
1729
1730   if ((mode & GPGME_EXPORT_MODE_MINIMAL))
1731     err = add_arg (gpg, "--export-options=export-minimal");
1732
1733   if (err)
1734     ;
1735   else if ((mode & GPGME_EXPORT_MODE_EXTERN))
1736     {
1737       err = add_arg (gpg, "--send-keys");
1738     }
1739   else
1740     {
1741       err = add_arg (gpg, "--export");
1742       if (!err && use_armor)
1743         err = add_arg (gpg, "--armor");
1744       if (!err)
1745         err = add_data (gpg, keydata, 1, 1);
1746     }
1747   if (!err)
1748     err = add_arg (gpg, "--");
1749
1750   return err;
1751 }
1752
1753
1754 static gpgme_error_t
1755 gpg_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1756             gpgme_data_t keydata, int use_armor)
1757 {
1758   engine_gpg_t gpg = engine;
1759   gpgme_error_t err;
1760
1761   err = export_common (gpg, mode, keydata, use_armor);
1762
1763   if (!err && pattern && *pattern)
1764     err = add_arg (gpg, pattern);
1765
1766   if (!err)
1767     err = start (gpg);
1768
1769   return err;
1770 }
1771
1772
1773 static gpgme_error_t
1774 gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1775                 gpgme_data_t keydata, int use_armor)
1776 {
1777   engine_gpg_t gpg = engine;
1778   gpgme_error_t err;
1779
1780   err = export_common (gpg, mode, keydata, use_armor);
1781
1782   if (pattern)
1783     {
1784       while (!err && *pattern && **pattern)
1785         err = add_arg (gpg, *(pattern++));
1786     }
1787
1788   if (!err)
1789     err = start (gpg);
1790
1791   return err;
1792 }
1793
1794
1795 static gpgme_error_t
1796 gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1797             gpgme_data_t pubkey, gpgme_data_t seckey)
1798 {
1799   engine_gpg_t gpg = engine;
1800   gpgme_error_t err;
1801
1802   if (!gpg)
1803     return gpg_error (GPG_ERR_INV_VALUE);
1804
1805   /* We need a special mechanism to get the fd of a pipe here, so that
1806      we can use this for the %pubring and %secring parameters.  We
1807      don't have this yet, so we implement only the adding to the
1808      standard keyrings.  */
1809   if (pubkey || seckey)
1810     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1811
1812   err = add_arg (gpg, "--gen-key");
1813   if (!err && use_armor)
1814     err = add_arg (gpg, "--armor");
1815   if (!err)
1816     err = add_arg (gpg, "--");
1817   if (!err)
1818     err = add_data (gpg, help_data, -1, 0);
1819
1820   if (!err)
1821     err = start (gpg);
1822
1823   return err;
1824 }
1825
1826 /* Return the next DELIM delimited string from DATA as a C-string.
1827    The caller needs to provide the address of a pointer variable which
1828    he has to set to NULL before the first call.  After the last call
1829    to this function, this function needs to be called once more with
1830    DATA set to NULL so that the function can release its internal
1831    state.  After that the pointer variable is free for use again.
1832    Note that we use a delimiter and thus a trailing delimiter is not
1833    required.  DELIM may not be changed after the first call. */
1834 static const char *
1835 string_from_data (gpgme_data_t data, int delim,
1836                   void **helpptr, gpgme_error_t *r_err)
1837 {
1838 #define MYBUFLEN 2000 /* Fixme: We don't support URLs longer than that.  */
1839   struct {
1840     int  eof_seen;
1841     int  nbytes;      /* Length of the last returned string including
1842                          the delimiter. */
1843     int  buflen;      /* Valid length of BUF.  */
1844     char buf[MYBUFLEN+1];  /* Buffer with one byte extra space.  */
1845   } *self;
1846   char *p;
1847   int nread;
1848
1849   *r_err = 0;
1850   if (!data)
1851     {
1852       if (*helpptr)
1853         {
1854           free (*helpptr);
1855           *helpptr = NULL;
1856         }
1857       return NULL;
1858     }
1859
1860   if (*helpptr)
1861     self = *helpptr;
1862   else
1863     {
1864       self = malloc (sizeof *self);
1865       if (!self)
1866         {
1867           *r_err = gpg_error_from_syserror ();
1868           return NULL;
1869         }
1870       *helpptr = self;
1871       self->eof_seen = 0;
1872       self->nbytes = 0;
1873       self->buflen = 0;
1874     }
1875
1876   if (self->eof_seen)
1877     return NULL;
1878
1879   assert (self->nbytes <= self->buflen);
1880   memmove (self->buf, self->buf + self->nbytes, self->buflen - self->nbytes);
1881   self->buflen -= self->nbytes;
1882   self->nbytes = 0;
1883
1884   do
1885     {
1886       /* Fixme: This is fairly infective scanning because we may scan
1887          the buffer several times.  */
1888       p = memchr (self->buf, delim, self->buflen);
1889       if (p)
1890         {
1891           *p = 0;
1892           self->nbytes = p - self->buf + 1;
1893           return self->buf;
1894         }
1895
1896       if ( !(MYBUFLEN - self->buflen) )
1897         {
1898           /* Not enough space - URL too long.  */
1899           *r_err = gpg_error (GPG_ERR_TOO_LARGE);
1900           return NULL;
1901         }
1902
1903       nread = gpgme_data_read (data, self->buf + self->buflen,
1904                                MYBUFLEN - self->buflen);
1905       if (nread < 0)
1906         {
1907           *r_err = gpg_error_from_syserror ();
1908           return NULL;
1909         }
1910       self->buflen += nread;
1911     }
1912   while (nread);
1913
1914   /* EOF reached.  If we have anything in the buffer, append a Nul and
1915      return it. */
1916   self->eof_seen = 1;
1917   if (self->buflen)
1918     {
1919       self->buf[self->buflen] = 0;  /* (we allocated one extra byte)  */
1920       return self->buf;
1921     }
1922   return NULL;
1923 #undef MYBUFLEN
1924 }
1925
1926
1927
1928 static gpgme_error_t
1929 gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1930 {
1931   engine_gpg_t gpg = engine;
1932   gpgme_error_t err;
1933   int idx;
1934   gpgme_data_encoding_t dataenc;
1935
1936   if (keydata && keyarray)
1937     return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
1938
1939   dataenc = gpgme_data_get_encoding (keydata);
1940
1941   if (keyarray)
1942     {
1943       err = add_arg (gpg, "--recv-keys");
1944       if (!err)
1945         err = add_arg (gpg, "--");
1946       for (idx=0; !err && keyarray[idx]; idx++)
1947         {
1948           if (keyarray[idx]->protocol != GPGME_PROTOCOL_OpenPGP)
1949             ;
1950           else if (!keyarray[idx]->subkeys)
1951             ;
1952           else if (keyarray[idx]->subkeys->fpr && *keyarray[idx]->subkeys->fpr)
1953             err = add_arg (gpg, keyarray[idx]->subkeys->fpr);
1954           else if (*keyarray[idx]->subkeys->keyid)
1955             err = add_arg (gpg, keyarray[idx]->subkeys->keyid);
1956         }
1957     }
1958   else if (dataenc == GPGME_DATA_ENCODING_URL
1959            || dataenc == GPGME_DATA_ENCODING_URL0)
1960     {
1961       void *helpptr;
1962       const char *string;
1963       gpgme_error_t xerr;
1964       int delim = (dataenc == GPGME_DATA_ENCODING_URL)? '\n': 0;
1965
1966       /* FIXME: --fetch-keys is probably not correct because it can't
1967          grok all kinds of URLs.  On Unix it should just work but on
1968          Windows we will build the command line and that may fail for
1969          some embedded control characters.  It is anyway limited to
1970          the maximum size of the command line.  We need another
1971          command which can take its input from a file.  Maybe we
1972          should use an option to gpg to modify such commands (ala
1973          --multifile).  */
1974       err = add_arg (gpg, "--fetch-keys");
1975       if (!err)
1976         err = add_arg (gpg, "--");
1977       helpptr = NULL;
1978       while (!err
1979              && (string = string_from_data (keydata, delim, &helpptr, &xerr)))
1980         err = add_arg (gpg, string);
1981       if (!err)
1982         err = xerr;
1983       string_from_data (NULL, delim, &helpptr, &xerr);
1984     }
1985   else if (dataenc == GPGME_DATA_ENCODING_URLESC)
1986     {
1987       /* Already escaped URLs are not yet supported.  */
1988       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1989     }
1990   else
1991     {
1992       err = add_arg (gpg, "--import");
1993       if (!err)
1994         err = add_arg (gpg, "--");
1995       if (!err)
1996         err = add_data (gpg, keydata, -1, 0);
1997     }
1998
1999   if (!err)
2000     err = start (gpg);
2001
2002   return err;
2003 }
2004
2005
2006 /* The output for external keylistings in GnuPG is different from all
2007    the other key listings.  We catch this here with a special
2008    preprocessor that reformats the colon handler lines.  */
2009 static gpgme_error_t
2010 gpg_keylist_preprocess (char *line, char **r_line)
2011 {
2012   enum
2013     {
2014       RT_NONE, RT_INFO, RT_PUB, RT_UID
2015     }
2016   rectype = RT_NONE;
2017 #define NR_FIELDS 16
2018   char *field[NR_FIELDS];
2019   int fields = 0;
2020
2021   *r_line = NULL;
2022
2023   while (line && fields < NR_FIELDS)
2024     {
2025       field[fields++] = line;
2026       line = strchr (line, ':');
2027       if (line)
2028         *(line++) = '\0';
2029     }
2030
2031   if (!strcmp (field[0], "info"))
2032     rectype = RT_INFO;
2033   else if (!strcmp (field[0], "pub"))
2034     rectype = RT_PUB;
2035   else if (!strcmp (field[0], "uid"))
2036     rectype = RT_UID;
2037   else
2038     rectype = RT_NONE;
2039
2040   switch (rectype)
2041     {
2042     case RT_INFO:
2043       /* FIXME: Eventually, check the version number at least.  */
2044       return 0;
2045
2046     case RT_PUB:
2047       if (fields < 7)
2048         return 0;
2049
2050       /* The format is:
2051
2052          pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags>
2053
2054          as defined in 5.2. Machine Readable Indexes of the OpenPGP
2055          HTTP Keyserver Protocol (draft).
2056
2057          We want:
2058          pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>::::::::
2059       */
2060
2061       if (asprintf (r_line, "pub:o%s:%s:%s:%s:%s:%s::::::::",
2062                     field[6], field[3], field[2], field[1],
2063                     field[4], field[5]) < 0)
2064         return gpg_error_from_errno (errno);
2065       return 0;
2066
2067     case RT_UID:
2068       /* The format is:
2069
2070          uid:<escaped uid string>:<creationdate>:<expirationdate>:<flags>
2071
2072          as defined in 5.2. Machine Readable Indexes of the OpenPGP
2073          HTTP Keyserver Protocol (draft).
2074
2075          We want:
2076          uid:o<flags>::::<creatdate>:<expdate>:::<c-coded uid>:
2077       */
2078
2079       {
2080         /* The user ID is percent escaped, but we want c-coded.
2081            Because we have to replace each '%HL' by '\xHL', we need at
2082            most 4/3 th the number of bytes.  But because we also need
2083            to escape the backslashes we allocate twice as much.  */
2084         char *uid = malloc (2 * strlen (field[1]) + 1);
2085         char *src;
2086         char *dst;
2087
2088         if (! uid)
2089           return gpg_error_from_errno (errno);
2090         src = field[1];
2091         dst = uid;
2092         while (*src)
2093           {
2094             if (*src == '%')
2095               {
2096                 *(dst++) = '\\';
2097                 *(dst++) = 'x';
2098                 src++;
2099                 /* Copy the next two bytes unconditionally.  */
2100                 if (*src)
2101                   *(dst++) = *(src++);
2102                 if (*src)
2103                   *(dst++) = *(src++);
2104               }
2105             else if (*src == '\\')
2106               {
2107                 *dst++ = '\\';
2108                 *dst++ = '\\';
2109               }
2110             else
2111               *(dst++) = *(src++);
2112           }
2113         *dst = '\0';
2114
2115         if (asprintf (r_line, "uid:o%s::::%s:%s:::%s:",
2116                       field[4], field[2], field[3], uid) < 0)
2117           return gpg_error_from_errno (errno);
2118       }
2119       return 0;
2120
2121     case RT_NONE:
2122       /* Unknown record.  */
2123       break;
2124     }
2125   return 0;
2126
2127 }
2128
2129
2130 static gpg_error_t
2131 gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
2132                            gpgme_keylist_mode_t mode)
2133 {
2134   gpg_error_t err;
2135
2136   err = add_arg (gpg, "--with-colons");
2137   if (!err)
2138     err = add_arg (gpg, "--fixed-list-mode");
2139   if (!err)
2140     err = add_arg (gpg, "--with-fingerprint");
2141   if (!err)
2142     err = add_arg (gpg, "--with-fingerprint");
2143   if (!err
2144       && (mode & GPGME_KEYLIST_MODE_SIGS)
2145       && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
2146     {
2147       err = add_arg (gpg, "--list-options");
2148       if (!err)
2149         err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
2150     }
2151   if (!err)
2152     {
2153       if ( (mode & GPGME_KEYLIST_MODE_EXTERN) )
2154         {
2155           if (secret_only)
2156             err = gpg_error (GPG_ERR_NOT_SUPPORTED);
2157           else if ( (mode & GPGME_KEYLIST_MODE_LOCAL))
2158             {
2159               /* The local+extern mode is special.  It works only with
2160                  gpg >= 2.0.10.  FIXME: We should check that we have
2161                  such a version to that we can return a proper error
2162                  code.  The problem is that we don't know the context
2163                  here and thus can't access the cached version number
2164                  for the engine info structure.  */
2165               err = add_arg (gpg, "--locate-keys");
2166               if ((mode & GPGME_KEYLIST_MODE_SIGS))
2167                 err = add_arg (gpg, "--with-sig-check");
2168             }
2169           else
2170             {
2171               err = add_arg (gpg, "--search-keys");
2172               gpg->colon.preprocess_fnc = gpg_keylist_preprocess;
2173             }
2174         }
2175       else
2176         {
2177           err = add_arg (gpg, secret_only ? "--list-secret-keys"
2178                          : ((mode & GPGME_KEYLIST_MODE_SIGS)
2179                             ? "--check-sigs" : "--list-keys"));
2180         }
2181     }
2182   if (!err)
2183     err = add_arg (gpg, "--");
2184
2185   return err;
2186 }
2187
2188
2189 static gpgme_error_t
2190 gpg_keylist (void *engine, const char *pattern, int secret_only,
2191              gpgme_keylist_mode_t mode)
2192 {
2193   engine_gpg_t gpg = engine;
2194   gpgme_error_t err;
2195
2196   err = gpg_keylist_build_options (gpg, secret_only, mode);
2197
2198   if (!err && pattern && *pattern)
2199     err = add_arg (gpg, pattern);
2200
2201   if (!err)
2202     err = start (gpg);
2203
2204   return err;
2205 }
2206
2207
2208 static gpgme_error_t
2209 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
2210                  int reserved, gpgme_keylist_mode_t mode)
2211 {
2212   engine_gpg_t gpg = engine;
2213   gpgme_error_t err;
2214
2215   if (reserved)
2216     return gpg_error (GPG_ERR_INV_VALUE);
2217
2218   err = gpg_keylist_build_options (gpg, secret_only, mode);
2219
2220   if (pattern)
2221     {
2222       while (!err && *pattern && **pattern)
2223         err = add_arg (gpg, *(pattern++));
2224     }
2225
2226   if (!err)
2227     err = start (gpg);
2228
2229   return err;
2230 }
2231
2232
2233 static gpgme_error_t
2234 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
2235           gpgme_sig_mode_t mode, int use_armor, int use_textmode,
2236           int include_certs, gpgme_ctx_t ctx /* FIXME */)
2237 {
2238   engine_gpg_t gpg = engine;
2239   gpgme_error_t err;
2240
2241   if (mode == GPGME_SIG_MODE_CLEAR)
2242     err = add_arg (gpg, "--clearsign");
2243   else
2244     {
2245       err = add_arg (gpg, "--sign");
2246       if (!err && mode == GPGME_SIG_MODE_DETACH)
2247         err = add_arg (gpg, "--detach");
2248       if (!err && use_armor)
2249         err = add_arg (gpg, "--armor");
2250       if (!err && use_textmode)
2251         err = add_arg (gpg, "--textmode");
2252     }
2253
2254   if (!err)
2255     err = append_args_from_signers (gpg, ctx);
2256   if (!err)
2257     err = append_args_from_sig_notations (gpg, ctx);
2258
2259   if (gpgme_data_get_file_name (in))
2260     {
2261       if (!err)
2262         err = add_arg (gpg, "--set-filename");
2263       if (!err)
2264         err = add_arg (gpg, gpgme_data_get_file_name (in));
2265     }
2266
2267   /* Tell the gpg object about the data.  */
2268   if (!err)
2269     err = add_arg (gpg, "--");
2270   if (!err)
2271     err = add_data (gpg, in, -1, 0);
2272   if (!err)
2273     err = add_data (gpg, out, 1, 1);
2274
2275   if (!err)
2276     start (gpg);
2277
2278   return err;
2279 }
2280
2281 static gpgme_error_t
2282 gpg_trustlist (void *engine, const char *pattern)
2283 {
2284   engine_gpg_t gpg = engine;
2285   gpgme_error_t err;
2286
2287   err = add_arg (gpg, "--with-colons");
2288   if (!err)
2289     err = add_arg (gpg, "--list-trust-path");
2290
2291   /* Tell the gpg object about the data.  */
2292   if (!err)
2293     err = add_arg (gpg, "--");
2294   if (!err)
2295     err = add_arg (gpg, pattern);
2296
2297   if (!err)
2298     err = start (gpg);
2299
2300   return err;
2301 }
2302
2303
2304 static gpgme_error_t
2305 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
2306             gpgme_data_t plaintext)
2307 {
2308   engine_gpg_t gpg = engine;
2309   gpgme_error_t err = 0;
2310
2311   if (plaintext)
2312     {
2313       /* Normal or cleartext signature.  */
2314
2315       err = add_arg (gpg, "--output");
2316       if (!err)
2317         err = add_arg (gpg, "-");
2318       if (!err)
2319         err = add_arg (gpg, "--");
2320       if (!err)
2321         err = add_data (gpg, sig, -1, 0);
2322       if (!err)
2323         err = add_data (gpg, plaintext, 1, 1);
2324     }
2325   else
2326     {
2327       err = add_arg (gpg, "--verify");
2328       if (!err)
2329         err = add_arg (gpg, "--");
2330       if (!err)
2331         err = add_data (gpg, sig, -1, 0);
2332       if (!err && signed_text)
2333         err = add_data (gpg, signed_text, -1, 0);
2334     }
2335
2336   if (!err)
2337     err = start (gpg);
2338
2339   return err;
2340 }
2341
2342
2343 static void
2344 gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
2345 {
2346   engine_gpg_t gpg = engine;
2347
2348   gpg->io_cbs = *io_cbs;
2349 }
2350
2351 \f
2352 struct engine_ops _gpgme_engine_ops_gpg =
2353   {
2354     /* Static functions.  */
2355     _gpgme_get_gpg_path,
2356     NULL,
2357     gpg_get_version,
2358     gpg_get_req_version,
2359     gpg_new,
2360
2361     /* Member functions.  */
2362     gpg_release,
2363     NULL,                               /* reset */
2364     gpg_set_status_handler,
2365     gpg_set_command_handler,
2366     gpg_set_colon_line_handler,
2367     gpg_set_locale,
2368     NULL,                               /* set_protocol */
2369     gpg_decrypt,
2370     gpg_decrypt,                        /* decrypt_verify */
2371     gpg_delete,
2372     gpg_edit,
2373     gpg_encrypt,
2374     gpg_encrypt_sign,
2375     gpg_export,
2376     gpg_export_ext,
2377     gpg_genkey,
2378     gpg_import,
2379     gpg_keylist,
2380     gpg_keylist_ext,
2381     gpg_sign,
2382     gpg_trustlist,
2383     gpg_verify,
2384     NULL,               /* getauditlog */
2385     NULL,               /* opassuan_transact */
2386     NULL,               /* conf_load */
2387     NULL,               /* conf_save */
2388     gpg_set_io_cbs,
2389     gpg_io_event,
2390     gpg_cancel,
2391     NULL,               /* cancel_op */
2392     gpg_passwd
2393   };