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