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