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