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