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