2f59bb9ae59d0c435ebe5d5c36a6fe5fdbcdd88c
[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, 2013 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   gpgme_pinentry_mode_t pinentry_mode;
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_syserror ();
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_syserror ();
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_default_gpg_name ());
300 }
301
302
303 static const char *
304 gpg_get_req_version (void)
305 {
306   return "1.4.0";
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_syserror ();
429
430   if (file_name)
431     {
432       gpg->file_name = strdup (file_name);
433       if (!gpg->file_name)
434         {
435           rc = gpg_error_from_syserror ();
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_syserror ();
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_syserror ();
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_syserror ();
635
636   if (_gpgme_io_pipe (gpg->colon.fd, 1) == -1)
637     {
638       int saved_err = gpg_error_from_syserror ();
639       free (gpg->colon.buffer);
640       gpg->colon.buffer = NULL;
641       return saved_err;
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->pinentry_mode)
774     argc++;
775   if (!gpg->cmd.used)
776     argc++;     /* --batch */
777   argc += 1;    /* --no-sk-comment */
778
779   argv = calloc (argc + 1, sizeof *argv);
780   if (!argv)
781     return gpg_error_from_syserror ();
782   fd_data_map = calloc (datac + 1, sizeof *fd_data_map);
783   if (!fd_data_map)
784     {
785       int saved_err = gpg_error_from_syserror ();
786       free_argv (argv);
787       return saved_err;
788     }
789
790   argc = datac = 0;
791   argv[argc] = strdup ("gpg"); /* argv[0] */
792   if (!argv[argc])
793     {
794       int saved_err = gpg_error_from_syserror ();
795       free (fd_data_map);
796       free_argv (argv);
797       return saved_err;
798     }
799   argc++;
800   if (need_special)
801     {
802       argv[argc] = strdup ("--enable-special-filenames");
803       if (!argv[argc])
804         {
805           int saved_err = gpg_error_from_syserror ();
806           free (fd_data_map);
807           free_argv (argv);
808           return saved_err;
809         }
810       argc++;
811     }
812   if (use_agent)
813     {
814       argv[argc] = strdup ("--use-agent");
815       if (!argv[argc])
816         {
817           int saved_err = gpg_error_from_syserror ();
818           free (fd_data_map);
819           free_argv (argv);
820           return saved_err;
821         }
822       argc++;
823     }
824
825   if (gpg->pinentry_mode)
826     {
827       const char *s = NULL;
828       switch (gpg->pinentry_mode)
829         {
830         case GPGME_PINENTRY_MODE_DEFAULT: break;
831         case GPGME_PINENTRY_MODE_ASK:     s = "--pinentry-mode=ask"; break;
832         case GPGME_PINENTRY_MODE_CANCEL:  s = "--pinentry-mode=cancel"; break;
833         case GPGME_PINENTRY_MODE_ERROR:   s = "--pinentry-mode=error"; break;
834         case GPGME_PINENTRY_MODE_LOOPBACK:s = "--pinentry-mode=loopback"; break;
835         }
836       if (s)
837         {
838           argv[argc] = strdup (s);
839           if (!argv[argc])
840             {
841               int saved_err = gpg_error_from_syserror ();
842               free (fd_data_map);
843               free_argv (argv);
844               return saved_err;
845             }
846           argc++;
847         }
848     }
849
850   if (!gpg->cmd.used)
851     {
852       argv[argc] = strdup ("--batch");
853       if (!argv[argc])
854         {
855           int saved_err = gpg_error_from_syserror ();
856           free (fd_data_map);
857           free_argv (argv);
858           return saved_err;
859         }
860       argc++;
861     }
862   argv[argc] = strdup ("--no-sk-comment");
863   if (!argv[argc])
864     {
865       int saved_err = gpg_error_from_syserror ();
866       free (fd_data_map);
867       free_argv (argv);
868       return saved_err;
869     }
870   argc++;
871   for (a = gpg->arglist; a; a = a->next)
872     {
873       if (a->arg_locp)
874         *(a->arg_locp) = argc;
875
876       if (a->data)
877         {
878           /* Create a pipe to pass it down to gpg.  */
879           fd_data_map[datac].inbound = a->inbound;
880
881           /* Create a pipe.  */
882           {
883             int fds[2];
884
885             if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0)
886                 == -1)
887               {
888                 int saved_errno = errno;
889                 free (fd_data_map);
890                 free_argv (argv);
891                 return gpg_error (saved_errno);
892               }
893             if (_gpgme_io_set_close_notify (fds[0],
894                                             close_notify_handler, gpg)
895                 || _gpgme_io_set_close_notify (fds[1],
896                                                close_notify_handler,
897                                                gpg))
898               {
899                 return gpg_error (GPG_ERR_GENERAL);
900               }
901             /* If the data_type is FD, we have to do a dup2 here.  */
902             if (fd_data_map[datac].inbound)
903               {
904                 fd_data_map[datac].fd       = fds[0];
905                 fd_data_map[datac].peer_fd  = fds[1];
906               }
907             else
908               {
909                 fd_data_map[datac].fd       = fds[1];
910                 fd_data_map[datac].peer_fd  = fds[0];
911               }
912           }
913
914           /* Hack to get hands on the fd later.  */
915           if (gpg->cmd.used)
916             {
917               if (gpg->cmd.cb_data == a->data)
918                 {
919                   assert (gpg->cmd.idx == -1);
920                   gpg->cmd.idx = datac;
921                 }
922               else if (gpg->cmd.linked_data == a->data)
923                 {
924                   assert (gpg->cmd.linked_idx == -1);
925                   gpg->cmd.linked_idx = datac;
926                 }
927             }
928
929           fd_data_map[datac].data = a->data;
930           fd_data_map[datac].dup_to = a->dup_to;
931
932           if (a->dup_to == -1)
933             {
934               char *ptr;
935               int buflen = 25;
936
937               argv[argc] = malloc (buflen);
938               if (!argv[argc])
939                 {
940                   int saved_err = gpg_error_from_syserror ();
941                   free (fd_data_map);
942                   free_argv (argv);
943                   return saved_err;
944                 }
945
946               ptr = argv[argc];
947               if (!a->print_fd)
948                 {
949                   *(ptr++) = '-';
950                   *(ptr++) = '&';
951                   buflen -= 2;
952                 }
953
954               _gpgme_io_fd2str (ptr, buflen, fd_data_map[datac].peer_fd);
955               fd_data_map[datac].arg_loc = argc;
956               argc++;
957             }
958           datac++;
959         }
960       else
961         {
962           argv[argc] = strdup (a->arg);
963           if (!argv[argc])
964             {
965               int saved_err = gpg_error_from_syserror ();
966               free (fd_data_map);
967               free_argv (argv);
968               return saved_err;
969             }
970             argc++;
971         }
972     }
973
974   gpg->argv = argv;
975   gpg->fd_data_map = fd_data_map;
976   return 0;
977 }
978
979
980 static gpgme_error_t
981 add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
982            void **tag)
983 {
984   gpgme_error_t err;
985
986   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
987   if (err)
988     return err;
989   if (!dir)
990     /* FIXME Kludge around poll() problem.  */
991     err = _gpgme_io_set_nonblocking (fd);
992   return err;
993 }
994
995
996 /* Handle the status output of GnuPG.  This function does read entire
997    lines and passes them as C strings to the callback function (we can
998    use C Strings because the status output is always UTF-8 encoded).
999    Of course we have to buffer the lines to cope with long lines
1000    e.g. with a large user ID.  Note: We can optimize this to only cope
1001    with status line code we know about and skip all other stuff
1002    without buffering (i.e. without extending the buffer).  */
1003 static gpgme_error_t
1004 read_status (engine_gpg_t gpg)
1005 {
1006   char *p;
1007   int nread;
1008   size_t bufsize = gpg->status.bufsize;
1009   char *buffer = gpg->status.buffer;
1010   size_t readpos = gpg->status.readpos;
1011
1012   assert (buffer);
1013   if (bufsize - readpos < 256)
1014     {
1015       /* Need more room for the read.  */
1016       bufsize += 1024;
1017       buffer = realloc (buffer, bufsize);
1018       if (!buffer)
1019         return gpg_error_from_syserror ();
1020     }
1021
1022   nread = _gpgme_io_read (gpg->status.fd[0],
1023                           buffer + readpos, bufsize-readpos);
1024   if (nread == -1)
1025     return gpg_error_from_syserror ();
1026
1027   if (!nread)
1028     {
1029       gpg->status.eof = 1;
1030       if (gpg->status.fnc)
1031         {
1032           gpgme_error_t err;
1033           err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
1034           if (err)
1035             return err;
1036         }
1037       return 0;
1038     }
1039
1040   while (nread > 0)
1041     {
1042       for (p = buffer + readpos; nread; nread--, p++)
1043         {
1044           if (*p == '\n')
1045             {
1046               /* (we require that the last line is terminated by a LF) */
1047               if (p > buffer && p[-1] == '\r')
1048                 p[-1] = 0;
1049               *p = 0;
1050               if (!strncmp (buffer, "[GNUPG:] ", 9)
1051                   && buffer[9] >= 'A' && buffer[9] <= 'Z')
1052                 {
1053                   char *rest;
1054                   gpgme_status_code_t r;
1055
1056                   rest = strchr (buffer + 9, ' ');
1057                   if (!rest)
1058                     rest = p; /* Set to an empty string.  */
1059                   else
1060                     *rest++ = 0;
1061
1062                   r = _gpgme_parse_status (buffer + 9);
1063                   if (r >= 0)
1064                     {
1065                       if (gpg->cmd.used
1066                           && (r == GPGME_STATUS_GET_BOOL
1067                               || r == GPGME_STATUS_GET_LINE
1068                               || r == GPGME_STATUS_GET_HIDDEN))
1069                         {
1070                           gpg->cmd.code = r;
1071                           if (gpg->cmd.keyword)
1072                             free (gpg->cmd.keyword);
1073                           gpg->cmd.keyword = strdup (rest);
1074                           if (!gpg->cmd.keyword)
1075                             return gpg_error_from_syserror ();
1076                           /* This should be the last thing we have
1077                              received and the next thing will be that
1078                              the command handler does its action.  */
1079                           if (nread > 1)
1080                             TRACE0 (DEBUG_CTX, "gpgme:read_status", 0,
1081                                     "error: unexpected data");
1082
1083                           add_io_cb (gpg, gpg->cmd.fd, 0,
1084                                      command_handler, gpg,
1085                                      &gpg->fd_data_map[gpg->cmd.idx].tag);
1086                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
1087                           gpg->cmd.fd = -1;
1088                         }
1089                       else if (gpg->status.fnc)
1090                         {
1091                           gpgme_error_t err;
1092                           err = gpg->status.fnc (gpg->status.fnc_value,
1093                                                  r, rest);
1094                           if (err)
1095                             return err;
1096                         }
1097
1098                       if (r == GPGME_STATUS_END_STREAM)
1099                         {
1100                           if (gpg->cmd.used)
1101                             {
1102                               /* Before we can actually add the
1103                                  command fd, we might have to flush
1104                                  the linked output data pipe.  */
1105                               if (gpg->cmd.linked_idx != -1
1106                                   && gpg->fd_data_map[gpg->cmd.linked_idx].fd
1107                                   != -1)
1108                                 {
1109                                   struct io_select_fd_s fds;
1110                                   fds.fd =
1111                                     gpg->fd_data_map[gpg->cmd.linked_idx].fd;
1112                                   fds.for_read = 1;
1113                                   fds.for_write = 0;
1114                                   fds.opaque = NULL;
1115                                   do
1116                                     {
1117                                       fds.signaled = 0;
1118                                       _gpgme_io_select (&fds, 1, 1);
1119                                       if (fds.signaled)
1120                                         _gpgme_data_inbound_handler
1121                                           (gpg->cmd.linked_data, fds.fd);
1122                                     }
1123                                   while (fds.signaled);
1124                                 }
1125
1126                               /* XXX We must check if there are any
1127                                  more fds active after removing this
1128                                  one.  */
1129                               (*gpg->io_cbs.remove)
1130                                 (gpg->fd_data_map[gpg->cmd.idx].tag);
1131                               gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
1132                               gpg->fd_data_map[gpg->cmd.idx].fd = -1;
1133                             }
1134                         }
1135                     }
1136                 }
1137               /* To reuse the buffer for the next line we have to
1138                  shift the remaining data to the buffer start and
1139                  restart the loop Hmmm: We can optimize this function
1140                  by looking forward in the buffer to see whether a
1141                  second complete line is available and in this case
1142                  avoid the memmove for this line.  */
1143               nread--; p++;
1144               if (nread)
1145                 memmove (buffer, p, nread);
1146               readpos = 0;
1147               break; /* the for loop */
1148             }
1149           else
1150             readpos++;
1151         }
1152     }
1153
1154   /* Update the gpg object.  */
1155   gpg->status.bufsize = bufsize;
1156   gpg->status.buffer = buffer;
1157   gpg->status.readpos = readpos;
1158   return 0;
1159 }
1160
1161
1162 static gpgme_error_t
1163 status_handler (void *opaque, int fd)
1164 {
1165   struct io_cb_data *data = (struct io_cb_data *) opaque;
1166   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
1167   int err;
1168
1169   assert (fd == gpg->status.fd[0]);
1170   err = read_status (gpg);
1171   if (err)
1172     return err;
1173   if (gpg->status.eof)
1174     _gpgme_io_close (fd);
1175   return 0;
1176 }
1177
1178
1179 static gpgme_error_t
1180 read_colon_line (engine_gpg_t gpg)
1181 {
1182   char *p;
1183   int nread;
1184   size_t bufsize = gpg->colon.bufsize;
1185   char *buffer = gpg->colon.buffer;
1186   size_t readpos = gpg->colon.readpos;
1187
1188   assert (buffer);
1189   if (bufsize - readpos < 256)
1190     {
1191       /* Need more room for the read.  */
1192       bufsize += 1024;
1193       buffer = realloc (buffer, bufsize);
1194       if (!buffer)
1195         return gpg_error_from_syserror ();
1196     }
1197
1198   nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
1199   if (nread == -1)
1200     return gpg_error_from_syserror ();
1201
1202   if (!nread)
1203     {
1204       gpg->colon.eof = 1;
1205       assert (gpg->colon.fnc);
1206       gpg->colon.fnc (gpg->colon.fnc_value, NULL);
1207       return 0;
1208     }
1209
1210   while (nread > 0)
1211     {
1212       for (p = buffer + readpos; nread; nread--, p++)
1213         {
1214           if ( *p == '\n' )
1215             {
1216               /* (we require that the last line is terminated by a LF)
1217                  and we skip empty lines.  Note: we use UTF8 encoding
1218                  and escaping of special characters.  We require at
1219                  least one colon to cope with some other printed
1220                  information.  */
1221               *p = 0;
1222               if (*buffer && strchr (buffer, ':'))
1223                 {
1224                   char *line = NULL;
1225
1226                   if (gpg->colon.preprocess_fnc)
1227                     {
1228                       gpgme_error_t err;
1229
1230                       err = gpg->colon.preprocess_fnc (buffer, &line);
1231                       if (err)
1232                         return err;
1233                     }
1234
1235                   assert (gpg->colon.fnc);
1236                   gpg->colon.fnc (gpg->colon.fnc_value, line ? line : buffer);
1237                   if (line)
1238                     free (line);
1239                 }
1240
1241               /* To reuse the buffer for the next line we have to
1242                  shift the remaining data to the buffer start and
1243                  restart the loop Hmmm: We can optimize this function
1244                  by looking forward in the buffer to see whether a
1245                  second complete line is available and in this case
1246                  avoid the memmove for this line.  */
1247               nread--; p++;
1248               if (nread)
1249                 memmove (buffer, p, nread);
1250               readpos = 0;
1251               break; /* The for loop.  */
1252             }
1253           else
1254             readpos++;
1255         }
1256     }
1257
1258   /* Update the gpg object.  */
1259   gpg->colon.bufsize = bufsize;
1260   gpg->colon.buffer  = buffer;
1261   gpg->colon.readpos = readpos;
1262   return 0;
1263 }
1264
1265
1266 /* This colonline handler thing is not the clean way to do it.  It
1267    might be better to enhance the gpgme_data_t object to act as a wrapper
1268    for a callback.  Same goes for the status thing.  For now we use
1269    this thing here because it is easier to implement.  */
1270 static gpgme_error_t
1271 colon_line_handler (void *opaque, int fd)
1272 {
1273   struct io_cb_data *data = (struct io_cb_data *) opaque;
1274   engine_gpg_t gpg = (engine_gpg_t) data->handler_value;
1275   gpgme_error_t rc = 0;
1276
1277   assert (fd == gpg->colon.fd[0]);
1278   rc = read_colon_line (gpg);
1279   if (rc)
1280     return rc;
1281   if (gpg->colon.eof)
1282     _gpgme_io_close (fd);
1283   return 0;
1284 }
1285
1286
1287 static gpgme_error_t
1288 start (engine_gpg_t gpg)
1289 {
1290   gpgme_error_t rc;
1291   int i, n;
1292   int status;
1293   struct spawn_fd_item_s *fd_list;
1294   pid_t pid;
1295
1296   if (!gpg)
1297     return gpg_error (GPG_ERR_INV_VALUE);
1298
1299   if (!gpg->file_name && !_gpgme_get_default_gpg_name ())
1300     return trace_gpg_error (GPG_ERR_INV_ENGINE);
1301
1302   if (gpg->lc_ctype)
1303     {
1304       rc = add_arg_ext (gpg, gpg->lc_ctype, 1);
1305       if (!rc)
1306         rc = add_arg_ext (gpg, "--lc-ctype", 1);
1307       if (rc)
1308         return rc;
1309     }
1310
1311   if (gpg->lc_messages)
1312     {
1313       rc = add_arg_ext (gpg, gpg->lc_messages, 1);
1314       if (!rc)
1315         rc = add_arg_ext (gpg, "--lc-messages", 1);
1316       if (rc)
1317         return rc;
1318     }
1319
1320   rc = build_argv (gpg);
1321   if (rc)
1322     return rc;
1323
1324   /* status_fd, colon_fd and end of list.  */
1325   n = 3;
1326   for (i = 0; gpg->fd_data_map[i].data; i++)
1327     n++;
1328   fd_list = calloc (n, sizeof *fd_list);
1329   if (! fd_list)
1330     return gpg_error_from_syserror ();
1331
1332   /* Build the fd list for the child.  */
1333   n = 0;
1334   fd_list[n].fd = gpg->status.fd[1];
1335   fd_list[n].dup_to = -1;
1336   fd_list[n].arg_loc = gpg->status.arg_loc;
1337   n++;
1338   if (gpg->colon.fnc)
1339     {
1340       fd_list[n].fd = gpg->colon.fd[1];
1341       fd_list[n].dup_to = 1;
1342       n++;
1343     }
1344   for (i = 0; gpg->fd_data_map[i].data; i++)
1345     {
1346       fd_list[n].fd = gpg->fd_data_map[i].peer_fd;
1347       fd_list[n].dup_to = gpg->fd_data_map[i].dup_to;
1348       fd_list[n].arg_loc = gpg->fd_data_map[i].arg_loc;
1349       n++;
1350     }
1351   fd_list[n].fd = -1;
1352   fd_list[n].dup_to = -1;
1353
1354   status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name :
1355                             _gpgme_get_default_gpg_name (), gpg->argv,
1356                             IOSPAWN_FLAG_ALLOW_SET_FG,
1357                             fd_list, NULL, NULL, &pid);
1358   {
1359     int saved_err = gpg_error_from_syserror ();
1360     free (fd_list);
1361     if (status == -1)
1362       return saved_err;
1363   }
1364
1365   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
1366
1367   rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
1368                   &gpg->status.tag);
1369   if (rc)
1370     /* FIXME: kill the child */
1371     return rc;
1372
1373   if (gpg->colon.fnc)
1374     {
1375       assert (gpg->colon.fd[0] != -1);
1376       rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
1377                       &gpg->colon.tag);
1378       if (rc)
1379         /* FIXME: kill the child */
1380         return rc;
1381     }
1382
1383   for (i = 0; gpg->fd_data_map[i].data; i++)
1384     {
1385       if (gpg->cmd.used && i == gpg->cmd.idx)
1386         {
1387           /* Park the cmd fd.  */
1388           gpg->cmd.fd = gpg->fd_data_map[i].fd;
1389           gpg->fd_data_map[i].fd = -1;
1390         }
1391       else
1392         {
1393           rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
1394                           gpg->fd_data_map[i].inbound,
1395                           gpg->fd_data_map[i].inbound
1396                           ? _gpgme_data_inbound_handler
1397                           : _gpgme_data_outbound_handler,
1398                           gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
1399
1400           if (rc)
1401             /* FIXME: kill the child */
1402             return rc;
1403         }
1404     }
1405
1406   gpg_io_event (gpg, GPGME_EVENT_START, NULL);
1407
1408   /* fixme: check what data we can release here */
1409   return 0;
1410 }
1411
1412
1413 static gpgme_error_t
1414 gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1415 {
1416   engine_gpg_t gpg = engine;
1417   gpgme_error_t err;
1418
1419   err = add_arg (gpg, "--decrypt");
1420
1421   /* Tell the gpg object about the data.  */
1422   if (!err)
1423     err = add_arg (gpg, "--output");
1424   if (!err)
1425     err = add_arg (gpg, "-");
1426   if (!err)
1427     err = add_data (gpg, plain, 1, 1);
1428   if (!err)
1429     err = add_arg (gpg, "--");
1430   if (!err)
1431     err = add_data (gpg, ciph, -1, 0);
1432
1433   if (!err)
1434     start (gpg);
1435   return err;
1436 }
1437
1438 static gpgme_error_t
1439 gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
1440 {
1441   engine_gpg_t gpg = engine;
1442   gpgme_error_t err;
1443
1444   err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
1445                  : "--delete-key");
1446   if (!err)
1447     err = add_arg (gpg, "--");
1448   if (!err)
1449     {
1450       if (!key->subkeys || !key->subkeys->fpr)
1451         return gpg_error (GPG_ERR_INV_VALUE);
1452       else
1453         err = add_arg (gpg, key->subkeys->fpr);
1454     }
1455
1456   if (!err)
1457     start (gpg);
1458   return err;
1459 }
1460
1461
1462 static gpgme_error_t
1463 gpg_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1464 {
1465   engine_gpg_t gpg = engine;
1466   gpgme_error_t err;
1467
1468   if (!key || !key->subkeys || !key->subkeys->fpr)
1469     return gpg_error (GPG_ERR_INV_CERT_OBJ);
1470
1471   err = add_arg (gpg, "--passwd");
1472   if (!err)
1473     err = add_arg (gpg, key->subkeys->fpr);
1474   if (!err)
1475     start (gpg);
1476   return err;
1477 }
1478
1479
1480 static gpgme_error_t
1481 append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1482 {
1483   gpgme_error_t err = 0;
1484   int i;
1485   gpgme_key_t key;
1486
1487   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1488     {
1489       const char *s = key->subkeys ? key->subkeys->keyid : NULL;
1490       if (s)
1491         {
1492           if (!err)
1493             err = add_arg (gpg, "-u");
1494           if (!err)
1495             err = add_arg (gpg, s);
1496         }
1497       gpgme_key_unref (key);
1498       if (err) break;
1499     }
1500   return err;
1501 }
1502
1503
1504 static gpgme_error_t
1505 append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1506 {
1507   gpgme_error_t err = 0;
1508   gpgme_sig_notation_t notation;
1509
1510   notation = gpgme_sig_notation_get (ctx);
1511
1512   while (!err && notation)
1513     {
1514       if (notation->name
1515           && !(notation->flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
1516         err = gpg_error (GPG_ERR_INV_VALUE);
1517       else if (notation->name)
1518         {
1519           char *arg;
1520
1521           /* Maximum space needed is one byte for the "critical" flag,
1522              the name, one byte for '=', the value, and a terminating
1523              '\0'.  */
1524
1525           arg = malloc (1 + notation->name_len + 1 + notation->value_len + 1);
1526           if (!arg)
1527             err = gpg_error_from_syserror ();
1528
1529           if (!err)
1530             {
1531               char *argp = arg;
1532
1533               if (notation->critical)
1534                 *(argp++) = '!';
1535
1536               memcpy (argp, notation->name, notation->name_len);
1537               argp += notation->name_len;
1538
1539               *(argp++) = '=';
1540
1541               /* We know that notation->name is '\0' terminated.  */
1542               strcpy (argp, notation->value);
1543             }
1544
1545           if (!err)
1546             err = add_arg (gpg, "--sig-notation");
1547           if (!err)
1548             err = add_arg (gpg, arg);
1549
1550           if (arg)
1551             free (arg);
1552         }
1553       else
1554         {
1555           /* This is a policy URL.  */
1556
1557           char *value;
1558
1559           if (notation->critical)
1560             {
1561               value = malloc (1 + notation->value_len + 1);
1562               if (!value)
1563                 err = gpg_error_from_syserror ();
1564               else
1565                 {
1566                   value[0] = '!';
1567                   /* We know that notation->value is '\0' terminated.  */
1568                   strcpy (&value[1], notation->value);
1569                 }
1570             }
1571           else
1572             value = notation->value;
1573
1574           if (!err)
1575             err = add_arg (gpg, "--sig-policy-url");
1576           if (!err)
1577             err = add_arg (gpg, value);
1578
1579           if (value != notation->value)
1580             free (value);
1581         }
1582
1583       notation = notation->next;
1584     }
1585   return err;
1586 }
1587
1588
1589 static gpgme_error_t
1590 gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
1591           gpgme_ctx_t ctx /* FIXME */)
1592 {
1593   engine_gpg_t gpg = engine;
1594   gpgme_error_t err;
1595
1596   err = add_arg (gpg, "--with-colons");
1597   if (!err)
1598     err = append_args_from_signers (gpg, ctx);
1599   if (!err)
1600   err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
1601   if (!err)
1602     err = add_data (gpg, out, 1, 1);
1603   if (!err)
1604     err = add_arg (gpg, "--");
1605   if (!err && type == 0)
1606     {
1607       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1608       if (!s)
1609         err = gpg_error (GPG_ERR_INV_VALUE);
1610       else
1611         err = add_arg (gpg, s);
1612     }
1613   if (!err)
1614     err = start (gpg);
1615
1616   return err;
1617 }
1618
1619
1620 static gpgme_error_t
1621 append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
1622 {
1623   gpgme_error_t err = 0;
1624   int i = 0;
1625
1626   while (recp[i])
1627     {
1628       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1629         err = gpg_error (GPG_ERR_INV_VALUE);
1630       if (!err)
1631         err = add_arg (gpg, "-r");
1632       if (!err)
1633         err = add_arg (gpg, recp[i]->subkeys->fpr);
1634       if (err)
1635         break;
1636       i++;
1637     }
1638   return err;
1639 }
1640
1641
1642 static gpgme_error_t
1643 gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1644              gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1645 {
1646   engine_gpg_t gpg = engine;
1647   gpgme_error_t err;
1648   int symmetric = !recp;
1649
1650   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1651
1652   if (!err && use_armor)
1653     err = add_arg (gpg, "--armor");
1654
1655   if (!symmetric)
1656     {
1657       /* If we know that all recipients are valid (full or ultimate trust)
1658          we can suppress further checks.  */
1659       if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1660         err = add_arg (gpg, "--always-trust");
1661
1662       if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
1663         err = add_arg (gpg, "--no-encrypt-to");
1664
1665       if (!err)
1666         err = append_args_from_recipients (gpg, recp);
1667     }
1668
1669   /* Tell the gpg object about the data.  */
1670   if (!err)
1671     err = add_arg (gpg, "--output");
1672   if (!err)
1673     err = add_arg (gpg, "-");
1674   if (!err)
1675     err = add_data (gpg, ciph, 1, 1);
1676   if (gpgme_data_get_file_name (plain))
1677     {
1678       if (!err)
1679         err = add_arg (gpg, "--set-filename");
1680       if (!err)
1681         err = add_arg (gpg, gpgme_data_get_file_name (plain));
1682     }
1683   if (!err)
1684     err = add_arg (gpg, "--");
1685   if (!err)
1686     err = add_data (gpg, plain, -1, 0);
1687
1688   if (!err)
1689     err = start (gpg);
1690
1691   return err;
1692 }
1693
1694
1695 static gpgme_error_t
1696 gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
1697                   gpgme_encrypt_flags_t flags, gpgme_data_t plain,
1698                   gpgme_data_t ciph, int use_armor,
1699                   gpgme_ctx_t ctx /* FIXME */)
1700 {
1701   engine_gpg_t gpg = engine;
1702   gpgme_error_t err;
1703   int symmetric = !recp;
1704
1705   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1706
1707   if (!err)
1708     err = add_arg (gpg, "--sign");
1709   if (!err && use_armor)
1710     err = add_arg (gpg, "--armor");
1711
1712   if (!symmetric)
1713     {
1714       /* If we know that all recipients are valid (full or ultimate trust)
1715          we can suppress further checks.  */
1716       if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1717         err = add_arg (gpg, "--always-trust");
1718
1719       if (!err && (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO))
1720         err = add_arg (gpg, "--no-encrypt-to");
1721
1722       if (!err)
1723         err = append_args_from_recipients (gpg, recp);
1724     }
1725
1726   if (!err)
1727     err = append_args_from_signers (gpg, ctx);
1728
1729   if (!err)
1730     err = append_args_from_sig_notations (gpg, ctx);
1731
1732   /* Tell the gpg object about the data.  */
1733   if (!err)
1734     err = add_arg (gpg, "--output");
1735   if (!err)
1736     err = add_arg (gpg, "-");
1737   if (!err)
1738     err = add_data (gpg, ciph, 1, 1);
1739   if (gpgme_data_get_file_name (plain))
1740     {
1741       if (!err)
1742         err = add_arg (gpg, "--set-filename");
1743       if (!err)
1744         err = add_arg (gpg, gpgme_data_get_file_name (plain));
1745     }
1746   if (!err)
1747     err = add_arg (gpg, "--");
1748   if (!err)
1749     err = add_data (gpg, plain, -1, 0);
1750
1751   if (!err)
1752     err = start (gpg);
1753
1754   return err;
1755 }
1756
1757
1758 static gpgme_error_t
1759 export_common (engine_gpg_t gpg, gpgme_export_mode_t mode,
1760                gpgme_data_t keydata, int use_armor)
1761 {
1762   gpgme_error_t err = 0;
1763
1764   if ((mode & ~(GPGME_EXPORT_MODE_EXTERN
1765                 |GPGME_EXPORT_MODE_MINIMAL)))
1766     return gpg_error (GPG_ERR_NOT_SUPPORTED);
1767
1768   if ((mode & GPGME_EXPORT_MODE_MINIMAL))
1769     err = add_arg (gpg, "--export-options=export-minimal");
1770
1771   if (err)
1772     ;
1773   else if ((mode & GPGME_EXPORT_MODE_EXTERN))
1774     {
1775       err = add_arg (gpg, "--send-keys");
1776     }
1777   else
1778     {
1779       err = add_arg (gpg, "--export");
1780       if (!err && use_armor)
1781         err = add_arg (gpg, "--armor");
1782       if (!err)
1783         err = add_data (gpg, keydata, 1, 1);
1784     }
1785   if (!err)
1786     err = add_arg (gpg, "--");
1787
1788   return err;
1789 }
1790
1791
1792 static gpgme_error_t
1793 gpg_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1794             gpgme_data_t keydata, int use_armor)
1795 {
1796   engine_gpg_t gpg = engine;
1797   gpgme_error_t err;
1798
1799   err = export_common (gpg, mode, keydata, use_armor);
1800
1801   if (!err && pattern && *pattern)
1802     err = add_arg (gpg, pattern);
1803
1804   if (!err)
1805     err = start (gpg);
1806
1807   return err;
1808 }
1809
1810
1811 static gpgme_error_t
1812 gpg_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1813                 gpgme_data_t keydata, int use_armor)
1814 {
1815   engine_gpg_t gpg = engine;
1816   gpgme_error_t err;
1817
1818   err = export_common (gpg, mode, keydata, use_armor);
1819
1820   if (pattern)
1821     {
1822       while (!err && *pattern && **pattern)
1823         err = add_arg (gpg, *(pattern++));
1824     }
1825
1826   if (!err)
1827     err = start (gpg);
1828
1829   return err;
1830 }
1831
1832
1833 static gpgme_error_t
1834 gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1835             gpgme_data_t pubkey, gpgme_data_t seckey)
1836 {
1837   engine_gpg_t gpg = engine;
1838   gpgme_error_t err;
1839
1840   if (!gpg)
1841     return gpg_error (GPG_ERR_INV_VALUE);
1842
1843   /* We need a special mechanism to get the fd of a pipe here, so that
1844      we can use this for the %pubring and %secring parameters.  We
1845      don't have this yet, so we implement only the adding to the
1846      standard keyrings.  */
1847   if (pubkey || seckey)
1848     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1849
1850   err = add_arg (gpg, "--gen-key");
1851   if (!err && use_armor)
1852     err = add_arg (gpg, "--armor");
1853   if (!err)
1854     err = add_arg (gpg, "--");
1855   if (!err)
1856     err = add_data (gpg, help_data, -1, 0);
1857
1858   if (!err)
1859     err = start (gpg);
1860
1861   return err;
1862 }
1863
1864 /* Return the next DELIM delimited string from DATA as a C-string.
1865    The caller needs to provide the address of a pointer variable which
1866    he has to set to NULL before the first call.  After the last call
1867    to this function, this function needs to be called once more with
1868    DATA set to NULL so that the function can release its internal
1869    state.  After that the pointer variable is free for use again.
1870    Note that we use a delimiter and thus a trailing delimiter is not
1871    required.  DELIM may not be changed after the first call. */
1872 static const char *
1873 string_from_data (gpgme_data_t data, int delim,
1874                   void **helpptr, gpgme_error_t *r_err)
1875 {
1876 #define MYBUFLEN 2000 /* Fixme: We don't support URLs longer than that.  */
1877   struct {
1878     int  eof_seen;
1879     int  nbytes;      /* Length of the last returned string including
1880                          the delimiter. */
1881     int  buflen;      /* Valid length of BUF.  */
1882     char buf[MYBUFLEN+1];  /* Buffer with one byte extra space.  */
1883   } *self;
1884   char *p;
1885   int nread;
1886
1887   *r_err = 0;
1888   if (!data)
1889     {
1890       if (*helpptr)
1891         {
1892           free (*helpptr);
1893           *helpptr = NULL;
1894         }
1895       return NULL;
1896     }
1897
1898   if (*helpptr)
1899     self = *helpptr;
1900   else
1901     {
1902       self = malloc (sizeof *self);
1903       if (!self)
1904         {
1905           *r_err = gpg_error_from_syserror ();
1906           return NULL;
1907         }
1908       *helpptr = self;
1909       self->eof_seen = 0;
1910       self->nbytes = 0;
1911       self->buflen = 0;
1912     }
1913
1914   if (self->eof_seen)
1915     return NULL;
1916
1917   assert (self->nbytes <= self->buflen);
1918   memmove (self->buf, self->buf + self->nbytes, self->buflen - self->nbytes);
1919   self->buflen -= self->nbytes;
1920   self->nbytes = 0;
1921
1922   do
1923     {
1924       /* Fixme: This is fairly infective scanning because we may scan
1925          the buffer several times.  */
1926       p = memchr (self->buf, delim, self->buflen);
1927       if (p)
1928         {
1929           *p = 0;
1930           self->nbytes = p - self->buf + 1;
1931           return self->buf;
1932         }
1933
1934       if ( !(MYBUFLEN - self->buflen) )
1935         {
1936           /* Not enough space - URL too long.  */
1937           *r_err = gpg_error (GPG_ERR_TOO_LARGE);
1938           return NULL;
1939         }
1940
1941       nread = gpgme_data_read (data, self->buf + self->buflen,
1942                                MYBUFLEN - self->buflen);
1943       if (nread < 0)
1944         {
1945           *r_err = gpg_error_from_syserror ();
1946           return NULL;
1947         }
1948       self->buflen += nread;
1949     }
1950   while (nread);
1951
1952   /* EOF reached.  If we have anything in the buffer, append a Nul and
1953      return it. */
1954   self->eof_seen = 1;
1955   if (self->buflen)
1956     {
1957       self->buf[self->buflen] = 0;  /* (we allocated one extra byte)  */
1958       return self->buf;
1959     }
1960   return NULL;
1961 #undef MYBUFLEN
1962 }
1963
1964
1965
1966 static gpgme_error_t
1967 gpg_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1968 {
1969   engine_gpg_t gpg = engine;
1970   gpgme_error_t err;
1971   int idx;
1972   gpgme_data_encoding_t dataenc;
1973
1974   if (keydata && keyarray)
1975     return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
1976
1977   dataenc = gpgme_data_get_encoding (keydata);
1978
1979   if (keyarray)
1980     {
1981       err = add_arg (gpg, "--recv-keys");
1982       if (!err)
1983         err = add_arg (gpg, "--");
1984       for (idx=0; !err && keyarray[idx]; idx++)
1985         {
1986           if (keyarray[idx]->protocol != GPGME_PROTOCOL_OpenPGP)
1987             ;
1988           else if (!keyarray[idx]->subkeys)
1989             ;
1990           else if (keyarray[idx]->subkeys->fpr && *keyarray[idx]->subkeys->fpr)
1991             err = add_arg (gpg, keyarray[idx]->subkeys->fpr);
1992           else if (*keyarray[idx]->subkeys->keyid)
1993             err = add_arg (gpg, keyarray[idx]->subkeys->keyid);
1994         }
1995     }
1996   else if (dataenc == GPGME_DATA_ENCODING_URL
1997            || dataenc == GPGME_DATA_ENCODING_URL0)
1998     {
1999       void *helpptr;
2000       const char *string;
2001       gpgme_error_t xerr;
2002       int delim = (dataenc == GPGME_DATA_ENCODING_URL)? '\n': 0;
2003
2004       /* FIXME: --fetch-keys is probably not correct because it can't
2005          grok all kinds of URLs.  On Unix it should just work but on
2006          Windows we will build the command line and that may fail for
2007          some embedded control characters.  It is anyway limited to
2008          the maximum size of the command line.  We need another
2009          command which can take its input from a file.  Maybe we
2010          should use an option to gpg to modify such commands (ala
2011          --multifile).  */
2012       err = add_arg (gpg, "--fetch-keys");
2013       if (!err)
2014         err = add_arg (gpg, "--");
2015       helpptr = NULL;
2016       while (!err
2017              && (string = string_from_data (keydata, delim, &helpptr, &xerr)))
2018         err = add_arg (gpg, string);
2019       if (!err)
2020         err = xerr;
2021       string_from_data (NULL, delim, &helpptr, &xerr);
2022     }
2023   else if (dataenc == GPGME_DATA_ENCODING_URLESC)
2024     {
2025       /* Already escaped URLs are not yet supported.  */
2026       err = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
2027     }
2028   else
2029     {
2030       err = add_arg (gpg, "--import");
2031       if (!err)
2032         err = add_arg (gpg, "--");
2033       if (!err)
2034         err = add_data (gpg, keydata, -1, 0);
2035     }
2036
2037   if (!err)
2038     err = start (gpg);
2039
2040   return err;
2041 }
2042
2043
2044 /* The output for external keylistings in GnuPG is different from all
2045    the other key listings.  We catch this here with a special
2046    preprocessor that reformats the colon handler lines.  */
2047 static gpgme_error_t
2048 gpg_keylist_preprocess (char *line, char **r_line)
2049 {
2050   enum
2051     {
2052       RT_NONE, RT_INFO, RT_PUB, RT_UID
2053     }
2054   rectype = RT_NONE;
2055 #define NR_FIELDS 16
2056   char *field[NR_FIELDS];
2057   int fields = 0;
2058
2059   *r_line = NULL;
2060
2061   while (line && fields < NR_FIELDS)
2062     {
2063       field[fields++] = line;
2064       line = strchr (line, ':');
2065       if (line)
2066         *(line++) = '\0';
2067     }
2068
2069   if (!strcmp (field[0], "info"))
2070     rectype = RT_INFO;
2071   else if (!strcmp (field[0], "pub"))
2072     rectype = RT_PUB;
2073   else if (!strcmp (field[0], "uid"))
2074     rectype = RT_UID;
2075   else
2076     rectype = RT_NONE;
2077
2078   switch (rectype)
2079     {
2080     case RT_INFO:
2081       /* FIXME: Eventually, check the version number at least.  */
2082       return 0;
2083
2084     case RT_PUB:
2085       if (fields < 7)
2086         return 0;
2087
2088       /* The format is:
2089
2090          pub:<keyid>:<algo>:<keylen>:<creationdate>:<expirationdate>:<flags>
2091
2092          as defined in 5.2. Machine Readable Indexes of the OpenPGP
2093          HTTP Keyserver Protocol (draft).
2094
2095          We want:
2096          pub:o<flags>:<keylen>:<algo>:<keyid>:<creatdate>:<expdate>::::::::
2097       */
2098
2099       if (asprintf (r_line, "pub:o%s:%s:%s:%s:%s:%s::::::::",
2100                     field[6], field[3], field[2], field[1],
2101                     field[4], field[5]) < 0)
2102         return gpg_error_from_syserror ();
2103       return 0;
2104
2105     case RT_UID:
2106       /* The format is:
2107
2108          uid:<escaped uid string>:<creationdate>:<expirationdate>:<flags>
2109
2110          as defined in 5.2. Machine Readable Indexes of the OpenPGP
2111          HTTP Keyserver Protocol (draft).
2112
2113          We want:
2114          uid:o<flags>::::<creatdate>:<expdate>:::<c-coded uid>:
2115       */
2116
2117       {
2118         /* The user ID is percent escaped, but we want c-coded.
2119            Because we have to replace each '%HL' by '\xHL', we need at
2120            most 4/3 th the number of bytes.  But because we also need
2121            to escape the backslashes we allocate twice as much.  */
2122         char *uid = malloc (2 * strlen (field[1]) + 1);
2123         char *src;
2124         char *dst;
2125
2126         if (! uid)
2127           return gpg_error_from_syserror ();
2128         src = field[1];
2129         dst = uid;
2130         while (*src)
2131           {
2132             if (*src == '%')
2133               {
2134                 *(dst++) = '\\';
2135                 *(dst++) = 'x';
2136                 src++;
2137                 /* Copy the next two bytes unconditionally.  */
2138                 if (*src)
2139                   *(dst++) = *(src++);
2140                 if (*src)
2141                   *(dst++) = *(src++);
2142               }
2143             else if (*src == '\\')
2144               {
2145                 *dst++ = '\\';
2146                 *dst++ = '\\';
2147               }
2148             else
2149               *(dst++) = *(src++);
2150           }
2151         *dst = '\0';
2152
2153         if (asprintf (r_line, "uid:o%s::::%s:%s:::%s:",
2154                       field[4], field[2], field[3], uid) < 0)
2155           return gpg_error_from_syserror ();
2156       }
2157       return 0;
2158
2159     case RT_NONE:
2160       /* Unknown record.  */
2161       break;
2162     }
2163   return 0;
2164
2165 }
2166
2167
2168 static gpg_error_t
2169 gpg_keylist_build_options (engine_gpg_t gpg, int secret_only,
2170                            gpgme_keylist_mode_t mode)
2171 {
2172   gpg_error_t err;
2173
2174   err = add_arg (gpg, "--with-colons");
2175   if (!err)
2176     err = add_arg (gpg, "--fixed-list-mode");
2177   if (!err)
2178     err = add_arg (gpg, "--with-fingerprint");
2179   if (!err)
2180     err = add_arg (gpg, "--with-fingerprint");
2181   if (!err
2182       && (mode & GPGME_KEYLIST_MODE_SIGS)
2183       && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
2184     {
2185       err = add_arg (gpg, "--list-options");
2186       if (!err)
2187         err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
2188     }
2189   if (!err)
2190     {
2191       if ( (mode & GPGME_KEYLIST_MODE_EXTERN) )
2192         {
2193           if (secret_only)
2194             err = gpg_error (GPG_ERR_NOT_SUPPORTED);
2195           else if ( (mode & GPGME_KEYLIST_MODE_LOCAL))
2196             {
2197               /* The local+extern mode is special.  It works only with
2198                  gpg >= 2.0.10.  FIXME: We should check that we have
2199                  such a version to that we can return a proper error
2200                  code.  The problem is that we don't know the context
2201                  here and thus can't access the cached version number
2202                  for the engine info structure.  */
2203               err = add_arg (gpg, "--locate-keys");
2204               if ((mode & GPGME_KEYLIST_MODE_SIGS))
2205                 err = add_arg (gpg, "--with-sig-check");
2206             }
2207           else
2208             {
2209               err = add_arg (gpg, "--search-keys");
2210               gpg->colon.preprocess_fnc = gpg_keylist_preprocess;
2211             }
2212         }
2213       else
2214         {
2215           err = add_arg (gpg, secret_only ? "--list-secret-keys"
2216                          : ((mode & GPGME_KEYLIST_MODE_SIGS)
2217                             ? "--check-sigs" : "--list-keys"));
2218         }
2219     }
2220   if (!err)
2221     err = add_arg (gpg, "--");
2222
2223   return err;
2224 }
2225
2226
2227 static gpgme_error_t
2228 gpg_keylist (void *engine, const char *pattern, int secret_only,
2229              gpgme_keylist_mode_t mode)
2230 {
2231   engine_gpg_t gpg = engine;
2232   gpgme_error_t err;
2233
2234   err = gpg_keylist_build_options (gpg, secret_only, mode);
2235
2236   if (!err && pattern && *pattern)
2237     err = add_arg (gpg, pattern);
2238
2239   if (!err)
2240     err = start (gpg);
2241
2242   return err;
2243 }
2244
2245
2246 static gpgme_error_t
2247 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
2248                  int reserved, gpgme_keylist_mode_t mode)
2249 {
2250   engine_gpg_t gpg = engine;
2251   gpgme_error_t err;
2252
2253   if (reserved)
2254     return gpg_error (GPG_ERR_INV_VALUE);
2255
2256   err = gpg_keylist_build_options (gpg, secret_only, mode);
2257
2258   if (pattern)
2259     {
2260       while (!err && *pattern && **pattern)
2261         err = add_arg (gpg, *(pattern++));
2262     }
2263
2264   if (!err)
2265     err = start (gpg);
2266
2267   return err;
2268 }
2269
2270
2271 static gpgme_error_t
2272 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
2273           gpgme_sig_mode_t mode, int use_armor, int use_textmode,
2274           int include_certs, gpgme_ctx_t ctx /* FIXME */)
2275 {
2276   engine_gpg_t gpg = engine;
2277   gpgme_error_t err;
2278
2279   if (mode == GPGME_SIG_MODE_CLEAR)
2280     err = add_arg (gpg, "--clearsign");
2281   else
2282     {
2283       err = add_arg (gpg, "--sign");
2284       if (!err && mode == GPGME_SIG_MODE_DETACH)
2285         err = add_arg (gpg, "--detach");
2286       if (!err && use_armor)
2287         err = add_arg (gpg, "--armor");
2288       if (!err && use_textmode)
2289         err = add_arg (gpg, "--textmode");
2290     }
2291
2292   if (!err)
2293     err = append_args_from_signers (gpg, ctx);
2294   if (!err)
2295     err = append_args_from_sig_notations (gpg, ctx);
2296
2297   if (gpgme_data_get_file_name (in))
2298     {
2299       if (!err)
2300         err = add_arg (gpg, "--set-filename");
2301       if (!err)
2302         err = add_arg (gpg, gpgme_data_get_file_name (in));
2303     }
2304
2305   /* Tell the gpg object about the data.  */
2306   if (!err)
2307     err = add_arg (gpg, "--");
2308   if (!err)
2309     err = add_data (gpg, in, -1, 0);
2310   if (!err)
2311     err = add_data (gpg, out, 1, 1);
2312
2313   if (!err)
2314     start (gpg);
2315
2316   return err;
2317 }
2318
2319 static gpgme_error_t
2320 gpg_trustlist (void *engine, const char *pattern)
2321 {
2322   engine_gpg_t gpg = engine;
2323   gpgme_error_t err;
2324
2325   err = add_arg (gpg, "--with-colons");
2326   if (!err)
2327     err = add_arg (gpg, "--list-trust-path");
2328
2329   /* Tell the gpg object about the data.  */
2330   if (!err)
2331     err = add_arg (gpg, "--");
2332   if (!err)
2333     err = add_arg (gpg, pattern);
2334
2335   if (!err)
2336     err = start (gpg);
2337
2338   return err;
2339 }
2340
2341
2342 static gpgme_error_t
2343 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
2344             gpgme_data_t plaintext)
2345 {
2346   engine_gpg_t gpg = engine;
2347   gpgme_error_t err = 0;
2348
2349   if (plaintext)
2350     {
2351       /* Normal or cleartext signature.  */
2352
2353       err = add_arg (gpg, "--output");
2354       if (!err)
2355         err = add_arg (gpg, "-");
2356       if (!err)
2357         err = add_arg (gpg, "--");
2358       if (!err)
2359         err = add_data (gpg, sig, -1, 0);
2360       if (!err)
2361         err = add_data (gpg, plaintext, 1, 1);
2362     }
2363   else
2364     {
2365       err = add_arg (gpg, "--verify");
2366       if (!err)
2367         err = add_arg (gpg, "--");
2368       if (!err)
2369         err = add_data (gpg, sig, -1, 0);
2370       if (!err && signed_text)
2371         err = add_data (gpg, signed_text, -1, 0);
2372     }
2373
2374   if (!err)
2375     err = start (gpg);
2376
2377   return err;
2378 }
2379
2380
2381 static void
2382 gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
2383 {
2384   engine_gpg_t gpg = engine;
2385
2386   gpg->io_cbs = *io_cbs;
2387 }
2388
2389
2390 static gpgme_error_t
2391 gpg_set_pinentry_mode (void *engine, gpgme_pinentry_mode_t mode)
2392 {
2393   engine_gpg_t gpg = engine;
2394
2395   gpg->pinentry_mode = mode;
2396   return 0;
2397 }
2398
2399
2400 \f
2401 struct engine_ops _gpgme_engine_ops_gpg =
2402   {
2403     /* Static functions.  */
2404     _gpgme_get_default_gpg_name,
2405     NULL,
2406     gpg_get_version,
2407     gpg_get_req_version,
2408     gpg_new,
2409
2410     /* Member functions.  */
2411     gpg_release,
2412     NULL,                               /* reset */
2413     gpg_set_status_handler,
2414     gpg_set_command_handler,
2415     gpg_set_colon_line_handler,
2416     gpg_set_locale,
2417     NULL,                               /* set_protocol */
2418     gpg_decrypt,
2419     gpg_decrypt,                        /* decrypt_verify */
2420     gpg_delete,
2421     gpg_edit,
2422     gpg_encrypt,
2423     gpg_encrypt_sign,
2424     gpg_export,
2425     gpg_export_ext,
2426     gpg_genkey,
2427     gpg_import,
2428     gpg_keylist,
2429     gpg_keylist_ext,
2430     gpg_sign,
2431     gpg_trustlist,
2432     gpg_verify,
2433     NULL,               /* getauditlog */
2434     NULL,               /* opassuan_transact */
2435     NULL,               /* conf_load */
2436     NULL,               /* conf_save */
2437     gpg_set_io_cbs,
2438     gpg_io_event,
2439     gpg_cancel,
2440     NULL,               /* cancel_op */
2441     gpg_passwd,
2442     gpg_set_pinentry_mode
2443   };