doc/
[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     sprintf (buf, "%d", 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               argv[argc] = malloc (25);
724               if (!argv[argc])
725                 {
726                   int saved_errno = errno;
727                   free (fd_data_map);
728                   free_argv (argv);
729                   return gpg_error_from_errno (saved_errno);
730                 }
731               sprintf (argv[argc], 
732                        a->print_fd ? "%d" : "-&%d",
733                        fd_data_map[datac].peer_fd);
734               argc++;
735             }
736           datac++;
737         }
738       else
739         {
740           argv[argc] = strdup (a->arg);
741           if (!argv[argc])
742             {
743               int saved_errno = errno;
744               free (fd_data_map);
745               free_argv (argv);
746               return gpg_error_from_errno (saved_errno);
747             }
748             argc++;
749         }
750     }
751
752   gpg->argv = argv;
753   gpg->fd_data_map = fd_data_map;
754   return 0;
755 }
756
757
758 static gpgme_error_t
759 add_io_cb (engine_gpg_t gpg, int fd, int dir, gpgme_io_cb_t handler, void *data,
760            void **tag)
761 {
762   gpgme_error_t err;
763
764   err = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data, tag);
765   if (err)
766     return err;
767   if (!dir)
768     /* FIXME Kludge around poll() problem.  */
769     err = _gpgme_io_set_nonblocking (fd);
770   return err;
771 }
772
773
774 static int
775 status_cmp (const void *ap, const void *bp)
776 {
777   const struct status_table_s *a = ap;
778   const struct status_table_s *b = bp;
779
780   return strcmp (a->name, b->name);
781 }
782
783
784 /* Handle the status output of GnuPG.  This function does read entire
785    lines and passes them as C strings to the callback function (we can
786    use C Strings because the status output is always UTF-8 encoded).
787    Of course we have to buffer the lines to cope with long lines
788    e.g. with a large user ID.  Note: We can optimize this to only cope
789    with status line code we know about and skip all other stuff
790    without buffering (i.e. without extending the buffer).  */
791 static gpgme_error_t
792 read_status (engine_gpg_t gpg)
793 {
794   char *p;
795   int nread;
796   size_t bufsize = gpg->status.bufsize; 
797   char *buffer = gpg->status.buffer;
798   size_t readpos = gpg->status.readpos; 
799
800   assert (buffer);
801   if (bufsize - readpos < 256)
802     { 
803       /* Need more room for the read.  */
804       bufsize += 1024;
805       buffer = realloc (buffer, bufsize);
806       if (!buffer)
807         return gpg_error_from_errno (errno);
808     }
809
810   nread = _gpgme_io_read (gpg->status.fd[0],
811                           buffer + readpos, bufsize-readpos);
812   if (nread == -1)
813     return gpg_error_from_errno (errno);
814
815   if (!nread)
816     {
817       gpg->status.eof = 1;
818       if (gpg->status.fnc)
819         {
820           gpgme_error_t err;
821           err = gpg->status.fnc (gpg->status.fnc_value, GPGME_STATUS_EOF, "");
822           if (err)
823             return err;
824         }
825       return 0;
826     }
827
828   while (nread > 0)
829     {
830       for (p = buffer + readpos; nread; nread--, p++)
831         {
832           if (*p == '\n')
833             {
834               /* (we require that the last line is terminated by a LF) */
835               *p = 0;
836               if (!strncmp (buffer, "[GNUPG:] ", 9)
837                   && buffer[9] >= 'A' && buffer[9] <= 'Z')
838                 {
839                   struct status_table_s t, *r;
840                   char *rest;
841
842                   rest = strchr (buffer + 9, ' ');
843                   if (!rest)
844                     rest = p; /* Set to an empty string.  */
845                   else
846                     *rest++ = 0;
847                     
848                   t.name = buffer+9;
849                   /* (the status table has one extra element) */
850                   r = bsearch (&t, status_table, DIM(status_table) - 1,
851                                sizeof t, status_cmp);
852                   if (r)
853                     {
854                       if (gpg->cmd.used
855                           && (r->code == GPGME_STATUS_GET_BOOL
856                               || r->code == GPGME_STATUS_GET_LINE
857                               || r->code == GPGME_STATUS_GET_HIDDEN))
858                         {
859                           gpg->cmd.code = r->code;
860                           if (gpg->cmd.keyword)
861                             free (gpg->cmd.keyword);
862                           gpg->cmd.keyword = strdup (rest);
863                           if (!gpg->cmd.keyword)
864                             return gpg_error_from_errno (errno);
865                           /* This should be the last thing we have
866                              received and the next thing will be that
867                              the command handler does its action.  */
868                           if (nread > 1)
869                             DEBUG0 ("ERROR, unexpected data in read_status");
870
871                           add_io_cb (gpg, gpg->cmd.fd, 0,
872                                      command_handler, gpg,
873                                      &gpg->fd_data_map[gpg->cmd.idx].tag);
874                           gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd;
875                           gpg->cmd.fd = -1;
876                         }
877                       else if (gpg->status.fnc)
878                         {
879                           gpgme_error_t err;
880                           err = gpg->status.fnc (gpg->status.fnc_value, 
881                                                  r->code, rest);
882                           if (err)
883                             return err;
884                         }
885                     
886                       if (r->code == GPGME_STATUS_END_STREAM)
887                         {
888                           if (gpg->cmd.used)
889                             {
890                               /* Before we can actually add the
891                                  command fd, we might have to flush
892                                  the linked output data pipe.  */
893                               if (gpg->cmd.linked_idx != -1
894                                   && gpg->fd_data_map[gpg->cmd.linked_idx].fd
895                                   != -1)
896                                 {
897                                   struct io_select_fd_s fds;
898                                   fds.fd =
899                                     gpg->fd_data_map[gpg->cmd.linked_idx].fd;
900                                   fds.for_read = 1;
901                                   fds.for_write = 0;
902                                   fds.frozen = 0;
903                                   fds.opaque = NULL;
904                                   do
905                                     {
906                                       fds.signaled = 0;
907                                       _gpgme_io_select (&fds, 1, 1);
908                                       if (fds.signaled)
909                                         _gpgme_data_inbound_handler
910                                           (gpg->cmd.linked_data, fds.fd);
911                                     }
912                                   while (fds.signaled);
913                                 }
914
915                               /* XXX We must check if there are any
916                                  more fds active after removing this
917                                  one.  */
918                               (*gpg->io_cbs.remove)
919                                 (gpg->fd_data_map[gpg->cmd.idx].tag);
920                               gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd;
921                               gpg->fd_data_map[gpg->cmd.idx].fd = -1;
922                             }
923                         }
924                     }
925                 }
926               /* To reuse the buffer for the next line we have to
927                  shift the remaining data to the buffer start and
928                  restart the loop Hmmm: We can optimize this function
929                  by looking forward in the buffer to see whether a
930                  second complete line is available and in this case
931                  avoid the memmove for this line.  */
932               nread--; p++;
933               if (nread)
934                 memmove (buffer, p, nread);
935               readpos = 0;
936               break; /* the for loop */
937             }
938           else
939             readpos++;
940         }
941     } 
942
943   /* Update the gpg object.  */
944   gpg->status.bufsize = bufsize;
945   gpg->status.buffer = buffer;
946   gpg->status.readpos = readpos;
947   return 0;
948 }
949
950
951 static gpgme_error_t
952 status_handler (void *opaque, int fd)
953 {
954   engine_gpg_t gpg = opaque;
955   int err;
956
957   assert (fd == gpg->status.fd[0]);
958   err = read_status (gpg);
959   if (err)
960     return err;
961   if (gpg->status.eof)
962     _gpgme_io_close (fd);
963   return 0;
964 }
965
966
967 static gpgme_error_t
968 read_colon_line (engine_gpg_t gpg)
969 {
970   char *p;
971   int nread;
972   size_t bufsize = gpg->colon.bufsize; 
973   char *buffer = gpg->colon.buffer;
974   size_t readpos = gpg->colon.readpos; 
975
976   assert (buffer);
977   if (bufsize - readpos < 256)
978     { 
979       /* Need more room for the read.  */
980       bufsize += 1024;
981       buffer = realloc (buffer, bufsize);
982       if (!buffer) 
983         return gpg_error_from_errno (errno);
984     }
985
986   nread = _gpgme_io_read (gpg->colon.fd[0], buffer+readpos, bufsize-readpos);
987   if (nread == -1)
988     return gpg_error_from_errno (errno);
989
990   if (!nread)
991     {
992       gpg->colon.eof = 1;
993       assert (gpg->colon.fnc);
994       gpg->colon.fnc (gpg->colon.fnc_value, NULL);
995       return 0;
996     }
997
998   while (nread > 0)
999     {
1000       for (p = buffer + readpos; nread; nread--, p++)
1001         {
1002           if ( *p == '\n' )
1003             {
1004               /* (we require that the last line is terminated by a LF)
1005                  and we skip empty lines.  Note: we use UTF8 encoding
1006                  and escaping of special characters We require at
1007                  least one colon to cope with some other printed
1008                  information.  */
1009               *p = 0;
1010               if (*buffer && strchr (buffer, ':'))
1011                 {
1012                   assert (gpg->colon.fnc);
1013                   gpg->colon.fnc (gpg->colon.fnc_value, buffer);
1014                 }
1015             
1016               /* To reuse the buffer for the next line we have to
1017                  shift the remaining data to the buffer start and
1018                  restart the loop Hmmm: We can optimize this function
1019                  by looking forward in the buffer to see whether a
1020                  second complete line is available and in this case
1021                  avoid the memmove for this line.  */
1022               nread--; p++;
1023               if (nread)
1024                 memmove (buffer, p, nread);
1025               readpos = 0;
1026               break; /* The for loop.  */
1027             }
1028           else
1029             readpos++;
1030         }
1031     } 
1032
1033   /* Update the gpg object.  */
1034   gpg->colon.bufsize = bufsize;
1035   gpg->colon.buffer  = buffer;
1036   gpg->colon.readpos = readpos;
1037   return 0;
1038 }
1039
1040
1041 /* This colonline handler thing is not the clean way to do it.  It
1042    might be better to enhance the gpgme_data_t object to act as a wrapper
1043    for a callback.  Same goes for the status thing.  For now we use
1044    this thing here because it is easier to implement.  */
1045 static gpgme_error_t
1046 colon_line_handler (void *opaque, int fd)
1047 {
1048   engine_gpg_t gpg = opaque;
1049   gpgme_error_t rc = 0;
1050
1051   assert (fd == gpg->colon.fd[0]);
1052   rc = read_colon_line (gpg);
1053   if (rc)
1054     return rc;
1055   if (gpg->colon.eof)
1056     _gpgme_io_close (fd);
1057   return 0;
1058 }
1059
1060
1061 static gpgme_error_t
1062 start (engine_gpg_t gpg)
1063 {
1064   gpgme_error_t rc;
1065   int saved_errno;
1066   int i, n;
1067   int status;
1068   struct spawn_fd_item_s *fd_child_list, *fd_parent_list;
1069
1070   if (!gpg)
1071     return gpg_error (GPG_ERR_INV_VALUE);
1072
1073   if (!gpg->file_name && !_gpgme_get_gpg_path ())
1074     return gpg_error (GPG_ERR_INV_ENGINE);
1075
1076   rc = build_argv (gpg);
1077   if (rc)
1078     return rc;
1079
1080   n = 3; /* status_fd, colon_fd and end of list */
1081   for (i = 0; gpg->fd_data_map[i].data; i++) 
1082     n++;
1083   fd_child_list = calloc (n + n, sizeof *fd_child_list);
1084   if (!fd_child_list)
1085     return gpg_error_from_errno (errno);
1086   fd_parent_list = fd_child_list + n;
1087
1088   /* build the fd list for the child */
1089   n = 0;
1090   if (gpg->colon.fnc)
1091     {
1092       fd_child_list[n].fd = gpg->colon.fd[1]; 
1093       fd_child_list[n].dup_to = 1; /* dup to stdout */
1094       n++;
1095     }
1096   for (i = 0; gpg->fd_data_map[i].data; i++)
1097     {
1098       if (gpg->fd_data_map[i].dup_to != -1)
1099         {
1100           fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd;
1101           fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to;
1102           n++;
1103         }
1104     }
1105   fd_child_list[n].fd = -1;
1106   fd_child_list[n].dup_to = -1;
1107
1108   /* Build the fd list for the parent.  */
1109   n = 0;
1110   if (gpg->status.fd[1] != -1)
1111     {
1112       fd_parent_list[n].fd = gpg->status.fd[1];
1113       fd_parent_list[n].dup_to = -1;
1114       n++;
1115     }
1116   if (gpg->colon.fd[1] != -1)
1117     {
1118       fd_parent_list[n].fd = gpg->colon.fd[1];
1119       fd_parent_list[n].dup_to = -1;
1120       n++;
1121     }
1122   for (i = 0; gpg->fd_data_map[i].data; i++)
1123     {
1124       fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd;
1125       fd_parent_list[n].dup_to = -1;
1126       n++;
1127     }        
1128   fd_parent_list[n].fd = -1;
1129   fd_parent_list[n].dup_to = -1;
1130
1131   status = _gpgme_io_spawn (gpg->file_name ? gpg->file_name :
1132                             _gpgme_get_gpg_path (),
1133                             gpg->argv, fd_child_list, fd_parent_list);
1134   saved_errno = errno;
1135   free (fd_child_list);
1136   if (status == -1)
1137     return gpg_error_from_errno (saved_errno);
1138
1139   /*_gpgme_register_term_handler ( closure, closure_value, pid );*/
1140
1141   rc = add_io_cb (gpg, gpg->status.fd[0], 1, status_handler, gpg,
1142                   &gpg->status.tag);
1143   if (rc)
1144     /* FIXME: kill the child */
1145     return rc;
1146
1147   if (gpg->colon.fnc)
1148     {
1149       assert (gpg->colon.fd[0] != -1);
1150       rc = add_io_cb (gpg, gpg->colon.fd[0], 1, colon_line_handler, gpg,
1151                       &gpg->colon.tag);
1152       if (rc)
1153         /* FIXME: kill the child */
1154         return rc;
1155     }
1156
1157   for (i = 0; gpg->fd_data_map[i].data; i++)
1158     {
1159       if (gpg->cmd.used && i == gpg->cmd.idx)
1160         {
1161           /* Park the cmd fd.  */
1162           gpg->cmd.fd = gpg->fd_data_map[i].fd;
1163           gpg->fd_data_map[i].fd = -1;
1164         }
1165       else
1166         {
1167           rc = add_io_cb (gpg, gpg->fd_data_map[i].fd,
1168                           gpg->fd_data_map[i].inbound,
1169                           gpg->fd_data_map[i].inbound
1170                           ? _gpgme_data_inbound_handler
1171                           : _gpgme_data_outbound_handler,
1172                           gpg->fd_data_map[i].data, &gpg->fd_data_map[i].tag);
1173           
1174           if (rc)
1175             /* FIXME: kill the child */
1176             return rc;
1177         }
1178     }
1179
1180   (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_START, NULL);
1181   
1182   /* fixme: check what data we can release here */
1183   return 0;
1184 }
1185
1186
1187 static gpgme_error_t
1188 gpg_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1189 {
1190   engine_gpg_t gpg = engine;
1191   gpgme_error_t err;
1192
1193   err = add_arg (gpg, "--decrypt");
1194
1195   /* Tell the gpg object about the data.  */
1196   if (!err)
1197     err = add_arg (gpg, "--output");
1198   if (!err)
1199     err = add_arg (gpg, "-");
1200   if (!err)
1201     err = add_data (gpg, plain, 1, 1);
1202   if (!err)
1203     err = add_data (gpg, ciph, 0, 0);
1204
1205   if (!err)
1206     start (gpg);
1207   return err;
1208 }
1209
1210 static gpgme_error_t
1211 gpg_delete (void *engine, gpgme_key_t key, int allow_secret)
1212 {
1213   engine_gpg_t gpg = engine;
1214   gpgme_error_t err;
1215
1216   err = add_arg (gpg, allow_secret ? "--delete-secret-and-public-key"
1217                  : "--delete-key");
1218   if (!err)
1219     err = add_arg (gpg, "--");
1220   if (!err)
1221     {
1222       if (!key->subkeys || !key->subkeys->fpr)
1223         return gpg_error (GPG_ERR_INV_VALUE);
1224       else
1225         err = add_arg (gpg, key->subkeys->fpr);
1226     }
1227
1228   if (!err)
1229     start (gpg);
1230   return err;
1231 }
1232
1233
1234 static gpgme_error_t
1235 append_args_from_signers (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1236 {
1237   gpgme_error_t err = 0;
1238   int i;
1239   gpgme_key_t key;
1240
1241   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1242     {
1243       const char *s = key->subkeys ? key->subkeys->keyid : NULL;
1244       if (s)
1245         {
1246           if (!err)
1247             err = add_arg (gpg, "-u");
1248           if (!err)
1249             err = add_arg (gpg, s);
1250         }
1251       gpgme_key_unref (key);
1252       if (err) break;
1253     }
1254   return err;
1255 }
1256
1257
1258 static gpgme_error_t
1259 append_args_from_sig_notations (engine_gpg_t gpg, gpgme_ctx_t ctx /* FIXME */)
1260 {
1261   gpgme_error_t err = 0;
1262   gpgme_sig_notation_t notation;
1263
1264   notation = gpgme_sig_notation_get (ctx);
1265
1266   while (!err && notation)
1267     {
1268       if (notation->name
1269           && !(notation->flags & GPGME_SIG_NOTATION_HUMAN_READABLE))
1270         err = gpg_error (GPG_ERR_INV_VALUE);
1271       else if (notation->name)
1272         {
1273           char *arg;
1274
1275           /* Maximum space needed is one byte for the "critical" flag,
1276              the name, one byte for '=', the value, and a terminating
1277              '\0'.  */
1278
1279           arg = malloc (1 + notation->name_len + 1 + notation->value_len + 1);
1280           if (!arg)
1281             err = gpg_error_from_errno (errno);
1282
1283           if (!err)
1284             {
1285               char *argp = arg;
1286
1287               if (notation->critical)
1288                 *(argp++) = '!';
1289
1290               memcpy (argp, notation->name, notation->name_len);
1291               argp += notation->name_len;
1292
1293               *(argp++) = '=';
1294
1295               /* We know that notation->name is '\0' terminated.  */
1296               strcpy (argp, notation->value);
1297             }
1298
1299           if (!err)
1300             err = add_arg (gpg, "--sig-notation");
1301           if (!err)
1302             err = add_arg (gpg, arg);
1303
1304           if (arg)
1305             free (arg);
1306         }
1307       else
1308         {
1309           /* This is a policy URL.  */
1310
1311           char *value;
1312
1313           if (notation->critical)
1314             {
1315               value = malloc (1 + notation->value_len + 1);
1316               if (!value)
1317                 err = gpg_error_from_errno (errno);
1318               else
1319                 {
1320                   value[0] = '!';
1321                   /* We know that notation->value is '\0' terminated.  */
1322                   strcpy (&value[1], notation->value);
1323                 }
1324             }
1325           else
1326             value = notation->value;
1327
1328           if (!err)
1329             err = add_arg (gpg, "--sig-policy-url");
1330           if (!err)
1331             err = add_arg (gpg, value);
1332
1333           if (value != notation->value)
1334             free (value);
1335         }
1336
1337       notation = notation->next;
1338     }
1339   return err;
1340 }
1341
1342
1343 static gpgme_error_t
1344 gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
1345           gpgme_ctx_t ctx /* FIXME */)
1346 {
1347   engine_gpg_t gpg = engine;
1348   gpgme_error_t err;
1349
1350   err = add_arg (gpg, "--with-colons");
1351   if (!err)
1352     err = append_args_from_signers (gpg, ctx);
1353   if (!err)
1354   err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
1355   if (!err)
1356     err = add_data (gpg, out, 1, 1);
1357   if (!err)
1358     err = add_arg (gpg, "--");
1359   if (!err)
1360     {
1361       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1362       if (!s)
1363         err = gpg_error (GPG_ERR_INV_VALUE);
1364       else
1365         err = add_arg (gpg, s);
1366     }
1367   if (!err)
1368     err = start (gpg);
1369
1370   return err;
1371 }
1372
1373
1374 static gpgme_error_t
1375 append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
1376 {
1377   gpgme_error_t err = 0;
1378   int i = 0;
1379
1380   while (recp[i])
1381     {
1382       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1383         err = gpg_error (GPG_ERR_INV_VALUE);
1384       if (!err)
1385         err = add_arg (gpg, "-r");
1386       if (!err)
1387         err = add_arg (gpg, recp[i]->subkeys->fpr);
1388       if (err)
1389         break;
1390       i++;
1391     }    
1392   return err;
1393 }
1394
1395
1396 static gpgme_error_t
1397 gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1398              gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1399 {
1400   engine_gpg_t gpg = engine;
1401   gpgme_error_t err;
1402   int symmetric = !recp;
1403
1404   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1405
1406   if (!err && use_armor)
1407     err = add_arg (gpg, "--armor");
1408
1409   if (!symmetric)
1410     {
1411       /* If we know that all recipients are valid (full or ultimate trust)
1412          we can suppress further checks.  */
1413       if (!err && !symmetric && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1414         err = add_arg (gpg, "--always-trust");
1415
1416       if (!err)
1417         err = append_args_from_recipients (gpg, recp);
1418     }
1419
1420   /* Tell the gpg object about the data.  */
1421   if (!err)
1422     err = add_arg (gpg, "--output");
1423   if (!err)
1424     err = add_arg (gpg, "-");
1425   if (!err)
1426     err = add_data (gpg, ciph, 1, 1);
1427   if (gpgme_data_get_file_name (plain))
1428     {
1429       if (!err)
1430         err = add_arg (gpg, "--set-filename");
1431       if (!err)
1432         err = add_arg (gpg, gpgme_data_get_file_name (plain));
1433     }
1434   if (!err)
1435     err = add_arg (gpg, "--");
1436   if (!err)
1437     err = add_data (gpg, plain, 0, 0);
1438
1439   if (!err)
1440     err = start (gpg);
1441
1442   return err;
1443 }
1444
1445
1446 static gpgme_error_t
1447 gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
1448                   gpgme_encrypt_flags_t flags, gpgme_data_t plain,
1449                   gpgme_data_t ciph, int use_armor,
1450                   gpgme_ctx_t ctx /* FIXME */)
1451 {
1452   engine_gpg_t gpg = engine;
1453   gpgme_error_t err;
1454
1455   err = add_arg (gpg, "--encrypt");
1456   if (!err)
1457     err = add_arg (gpg, "--sign");
1458   if (!err && use_armor)
1459     err = add_arg (gpg, "--armor");
1460
1461   /* If we know that all recipients are valid (full or ultimate trust)
1462      we can suppress further checks.  */
1463   if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1464     err = add_arg (gpg, "--always-trust");
1465
1466   if (!err)
1467     err = append_args_from_recipients (gpg, recp);
1468
1469   if (!err)
1470     err = append_args_from_signers (gpg, ctx);
1471   if (!err)
1472     err = append_args_from_sig_notations (gpg, ctx);
1473
1474   /* Tell the gpg object about the data.  */
1475   if (!err)
1476     err = add_arg (gpg, "--output");
1477   if (!err)
1478     err = add_arg (gpg, "-");
1479   if (!err)
1480     err = add_data (gpg, ciph, 1, 1);
1481   if (gpgme_data_get_file_name (plain))
1482     {
1483       if (!err)
1484         err = add_arg (gpg, "--set-filename");
1485       if (!err)
1486         err = add_arg (gpg, gpgme_data_get_file_name (plain));
1487     }
1488   if (!err)
1489     err = add_arg (gpg, "--");
1490   if (!err)
1491     err = add_data (gpg, plain, 0, 0);
1492
1493   if (!err)
1494     err = start (gpg);
1495
1496   return err;
1497 }
1498
1499
1500 static gpgme_error_t
1501 gpg_export (void *engine, const char *pattern, unsigned int reserved,
1502             gpgme_data_t keydata, int use_armor)
1503 {
1504   engine_gpg_t gpg = engine;
1505   gpgme_error_t err;
1506
1507   if (reserved)
1508     return gpg_error (GPG_ERR_INV_VALUE);
1509
1510   err = add_arg (gpg, "--export");
1511   if (!err && use_armor)
1512     err = add_arg (gpg, "--armor");
1513   if (!err)
1514     err = add_data (gpg, keydata, 1, 1);
1515   if (!err)
1516     err = add_arg (gpg, "--");
1517
1518   if (!err && pattern && *pattern)
1519     err = add_arg (gpg, pattern);
1520
1521   if (!err)
1522     err = start (gpg);
1523
1524   return err;
1525 }
1526
1527
1528 static gpgme_error_t
1529 gpg_export_ext (void *engine, const char *pattern[], unsigned int reserved,
1530                 gpgme_data_t keydata, int use_armor)
1531 {
1532   engine_gpg_t gpg = engine;
1533   gpgme_error_t err;
1534
1535   if (reserved)
1536     return gpg_error (GPG_ERR_INV_VALUE);
1537
1538   err = add_arg (gpg, "--export");
1539   if (!err && use_armor)
1540     err = add_arg (gpg, "--armor");
1541   if (!err)
1542     err = add_data (gpg, keydata, 1, 1);
1543   if (!err)
1544     err = add_arg (gpg, "--");
1545
1546   if (pattern)
1547     {
1548       while (!err && *pattern && **pattern)
1549         err = add_arg (gpg, *(pattern++));
1550     }
1551
1552   if (!err)
1553     err = start (gpg);
1554
1555   return err;
1556 }
1557
1558
1559 static gpgme_error_t
1560 gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1561             gpgme_data_t pubkey, gpgme_data_t seckey)
1562 {
1563   engine_gpg_t gpg = engine;
1564   gpgme_error_t err;
1565
1566   if (!gpg)
1567     return gpg_error (GPG_ERR_INV_VALUE);
1568
1569   /* We need a special mechanism to get the fd of a pipe here, so that
1570      we can use this for the %pubring and %secring parameters.  We
1571      don't have this yet, so we implement only the adding to the
1572      standard keyrings.  */
1573   if (pubkey || seckey)
1574     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1575
1576   err = add_arg (gpg, "--gen-key");
1577   if (!err && use_armor)
1578     err = add_arg (gpg, "--armor");
1579   if (!err)
1580     err = add_data (gpg, help_data, 0, 0);
1581
1582   if (!err)
1583     err = start (gpg);
1584
1585   return err;
1586 }
1587
1588
1589 static gpgme_error_t
1590 gpg_import (void *engine, gpgme_data_t keydata)
1591 {
1592   engine_gpg_t gpg = engine;
1593   gpgme_error_t err;
1594
1595   err = add_arg (gpg, "--import");
1596   if (!err)
1597     err = add_data (gpg, keydata, 0, 0);
1598
1599   if (!err)
1600     err = start (gpg);
1601
1602   return err;
1603 }
1604
1605
1606 static gpgme_error_t
1607 gpg_keylist (void *engine, const char *pattern, int secret_only,
1608              gpgme_keylist_mode_t mode)
1609 {
1610   engine_gpg_t gpg = engine;
1611   gpgme_error_t err;
1612
1613   err = add_arg (gpg, "--with-colons");
1614   if (!err)
1615     err = add_arg (gpg, "--fixed-list-mode");
1616   if (!err)
1617     err = add_arg (gpg, "--with-fingerprint");
1618   if (!err)
1619     err = add_arg (gpg, "--with-fingerprint");
1620   if (!err && (mode & GPGME_KEYLIST_MODE_SIGS)
1621       && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
1622     {
1623       err = add_arg (gpg, "--list-options");
1624       if (!err)
1625         err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
1626     }
1627   if (!err)
1628     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1629                    : ((mode & GPGME_KEYLIST_MODE_SIGS)
1630                       ? "--check-sigs" : "--list-keys"));
1631   
1632   /* Tell the gpg object about the data.  */
1633   if (!err)
1634     err = add_arg (gpg, "--");
1635   if (!err && pattern && *pattern)
1636     err = add_arg (gpg, pattern);
1637
1638   if (!err)
1639     err = start (gpg);
1640
1641   return err;
1642 }
1643
1644
1645 static gpgme_error_t
1646 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
1647                  int reserved, gpgme_keylist_mode_t mode)
1648 {
1649   engine_gpg_t gpg = engine;
1650   gpgme_error_t err;
1651
1652   if (reserved)
1653     return gpg_error (GPG_ERR_INV_VALUE);
1654
1655   err = add_arg (gpg, "--with-colons");
1656   if (!err)
1657     err = add_arg (gpg, "--fixed-list-mode");
1658   if (!err)
1659     err = add_arg (gpg, "--with-fingerprint");
1660   if (!err)
1661     err = add_arg (gpg, "--with-fingerprint");
1662   if (!err && (mode & GPGME_KEYLIST_MODE_SIGS)
1663       && (mode & GPGME_KEYLIST_MODE_SIG_NOTATIONS))
1664     {
1665       err = add_arg (gpg, "--list-options");
1666       if (!err)
1667         err = add_arg (gpg, "show-sig-subpackets=\"20,26\"");
1668     }
1669   if (!err)
1670     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1671                    : ((mode & GPGME_KEYLIST_MODE_SIGS)
1672                       ? "--check-sigs" : "--list-keys"));
1673   if (!err)
1674     err = add_arg (gpg, "--");
1675
1676   if (pattern)
1677     {
1678       while (!err && *pattern && **pattern)
1679         err = add_arg (gpg, *(pattern++));
1680     }
1681
1682   if (!err)
1683     err = start (gpg);
1684
1685   return err;
1686 }
1687
1688
1689 static gpgme_error_t
1690 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1691           gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1692           int include_certs, gpgme_ctx_t ctx /* FIXME */)
1693 {
1694   engine_gpg_t gpg = engine;
1695   gpgme_error_t err;
1696
1697   if (mode == GPGME_SIG_MODE_CLEAR)
1698     err = add_arg (gpg, "--clearsign");
1699   else
1700     {
1701       err = add_arg (gpg, "--sign");
1702       if (!err && mode == GPGME_SIG_MODE_DETACH)
1703         err = add_arg (gpg, "--detach");
1704       if (!err && use_armor)
1705         err = add_arg (gpg, "--armor");
1706       if (!err && use_textmode)
1707         err = add_arg (gpg, "--textmode");
1708     }
1709
1710   if (!err)
1711     err = append_args_from_signers (gpg, ctx);
1712   if (!err)
1713     err = append_args_from_sig_notations (gpg, ctx);
1714
1715   if (gpgme_data_get_file_name (in))
1716     {
1717       if (!err)
1718         err = add_arg (gpg, "--set-filename");
1719       if (!err)
1720         err = add_arg (gpg, gpgme_data_get_file_name (in));
1721     }
1722
1723   /* Tell the gpg object about the data.  */
1724   if (!err)
1725     err = add_data (gpg, in, 0, 0);
1726   if (!err)
1727     err = add_data (gpg, out, 1, 1);
1728
1729   if (!err)
1730     start (gpg);
1731
1732   return err;
1733 }
1734
1735 static gpgme_error_t
1736 gpg_trustlist (void *engine, const char *pattern)
1737 {
1738   engine_gpg_t gpg = engine;
1739   gpgme_error_t err;
1740
1741   err = add_arg (gpg, "--with-colons");
1742   if (!err)
1743     err = add_arg (gpg, "--list-trust-path");
1744   
1745   /* Tell the gpg object about the data.  */
1746   if (!err)
1747     err = add_arg (gpg, "--");
1748   if (!err)
1749     err = add_arg (gpg, pattern);
1750
1751   if (!err)
1752     err = start (gpg);
1753
1754   return err;
1755 }
1756
1757
1758 static gpgme_error_t
1759 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1760             gpgme_data_t plaintext)
1761 {
1762   engine_gpg_t gpg = engine;
1763   gpgme_error_t err = 0;
1764
1765   if (plaintext)
1766     {
1767       /* Normal or cleartext signature.  */
1768
1769       err = add_arg (gpg, "--output");
1770       if (!err)
1771         err = add_arg (gpg, "-");
1772       if (!err)
1773         err = add_arg (gpg, "--");
1774       if (!err)
1775         err = add_data (gpg, sig, 0, 0);
1776       if (!err)
1777         err = add_data (gpg, plaintext, 1, 1);
1778     }
1779   else
1780     {
1781       err = add_arg (gpg, "--verify");
1782       if (!err)
1783         err = add_arg (gpg, "--");
1784       if (!err)
1785         err = add_data (gpg, sig, -1, 0);
1786       if (signed_text)
1787         {
1788           if (!err)
1789             err = add_arg (gpg, "-");
1790           if (!err)
1791             err = add_data (gpg, signed_text, 0, 0);
1792         }
1793     }
1794
1795   if (!err)
1796     err = start (gpg);
1797
1798   return err;
1799 }
1800
1801
1802 static void
1803 gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1804 {
1805   engine_gpg_t gpg = engine;
1806
1807   gpg->io_cbs = *io_cbs;
1808 }
1809
1810 \f
1811 struct engine_ops _gpgme_engine_ops_gpg =
1812   {
1813     /* Static functions.  */
1814     _gpgme_get_gpg_path,
1815     gpg_get_version,
1816     gpg_get_req_version,
1817     gpg_new,
1818
1819     /* Member functions.  */
1820     gpg_release,
1821     gpg_set_status_handler,
1822     gpg_set_command_handler,
1823     gpg_set_colon_line_handler,
1824     gpg_decrypt,
1825     gpg_delete,
1826     gpg_edit,
1827     gpg_encrypt,
1828     gpg_encrypt_sign,
1829     gpg_export,
1830     gpg_export_ext,
1831     gpg_genkey,
1832     gpg_import,
1833     gpg_keylist,
1834     gpg_keylist_ext,
1835     gpg_sign,
1836     gpg_trustlist,
1837     gpg_verify,
1838     gpg_set_io_cbs,
1839     gpg_io_event,
1840     gpg_cancel
1841   };