2005-09-12 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     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 gpg_edit (void *engine, int type, gpgme_key_t key, gpgme_data_t out,
1260           gpgme_ctx_t ctx /* FIXME */)
1261 {
1262   engine_gpg_t gpg = engine;
1263   gpgme_error_t err;
1264
1265   err = add_arg (gpg, "--with-colons");
1266   if (!err)
1267     err = append_args_from_signers (gpg, ctx);
1268   if (!err)
1269   err = add_arg (gpg, type == 0 ? "--edit-key" : "--card-edit");
1270   if (!err)
1271     err = add_data (gpg, out, 1, 1);
1272   if (!err)
1273     err = add_arg (gpg, "--");
1274   if (!err)
1275     {
1276       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1277       if (!s)
1278         err = gpg_error (GPG_ERR_INV_VALUE);
1279       else
1280         err = add_arg (gpg, s);
1281     }
1282   if (!err)
1283     err = start (gpg);
1284
1285   return err;
1286 }
1287
1288
1289 static gpgme_error_t
1290 append_args_from_recipients (engine_gpg_t gpg, gpgme_key_t recp[])
1291 {
1292   gpgme_error_t err = 0;
1293   int i = 0;
1294
1295   while (recp[i])
1296     {
1297       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1298         err = gpg_error (GPG_ERR_INV_VALUE);
1299       if (!err)
1300         err = add_arg (gpg, "-r");
1301       if (!err)
1302         err = add_arg (gpg, recp[i]->subkeys->fpr);
1303       if (err)
1304         break;
1305       i++;
1306     }    
1307   return err;
1308 }
1309
1310
1311 static gpgme_error_t
1312 gpg_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1313              gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1314 {
1315   engine_gpg_t gpg = engine;
1316   gpgme_error_t err;
1317   int symmetric = !recp;
1318
1319   err = add_arg (gpg, symmetric ? "--symmetric" : "--encrypt");
1320
1321   if (!err && use_armor)
1322     err = add_arg (gpg, "--armor");
1323
1324   if (!symmetric)
1325     {
1326       /* If we know that all recipients are valid (full or ultimate trust)
1327          we can suppress further checks.  */
1328       if (!err && !symmetric && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1329         err = add_arg (gpg, "--always-trust");
1330
1331       if (!err)
1332         err = append_args_from_recipients (gpg, recp);
1333     }
1334
1335   /* Tell the gpg object about the data.  */
1336   if (!err)
1337     err = add_arg (gpg, "--output");
1338   if (!err)
1339     err = add_arg (gpg, "-");
1340   if (!err)
1341     err = add_data (gpg, ciph, 1, 1);
1342   if (!err)
1343     err = add_arg (gpg, "--");
1344   if (!err)
1345     err = add_data (gpg, plain, 0, 0);
1346
1347   if (!err)
1348     err = start (gpg);
1349
1350   return err;
1351 }
1352
1353
1354 static gpgme_error_t
1355 gpg_encrypt_sign (void *engine, gpgme_key_t recp[],
1356                   gpgme_encrypt_flags_t flags, gpgme_data_t plain,
1357                   gpgme_data_t ciph, int use_armor,
1358                   gpgme_ctx_t ctx /* FIXME */)
1359 {
1360   engine_gpg_t gpg = engine;
1361   gpgme_error_t err;
1362
1363   err = add_arg (gpg, "--encrypt");
1364   if (!err)
1365     err = add_arg (gpg, "--sign");
1366   if (!err && use_armor)
1367     err = add_arg (gpg, "--armor");
1368
1369   /* If we know that all recipients are valid (full or ultimate trust)
1370      we can suppress further checks.  */
1371   if (!err && (flags & GPGME_ENCRYPT_ALWAYS_TRUST))
1372     err = add_arg (gpg, "--always-trust");
1373
1374   if (!err)
1375     err = append_args_from_recipients (gpg, recp);
1376
1377   if (!err)
1378     err = append_args_from_signers (gpg, ctx);
1379
1380   /* Tell the gpg object about the data.  */
1381   if (!err)
1382     err = add_arg (gpg, "--output");
1383   if (!err)
1384     err = add_arg (gpg, "-");
1385   if (!err)
1386     err = add_data (gpg, ciph, 1, 1);
1387   if (!err)
1388     err = add_arg (gpg, "--");
1389   if (!err)
1390     err = add_data (gpg, plain, 0, 0);
1391
1392   if (!err)
1393     err = start (gpg);
1394
1395   return err;
1396 }
1397
1398
1399 static gpgme_error_t
1400 gpg_export (void *engine, const char *pattern, unsigned int reserved,
1401             gpgme_data_t keydata, int use_armor)
1402 {
1403   engine_gpg_t gpg = engine;
1404   gpgme_error_t err;
1405
1406   if (reserved)
1407     return gpg_error (GPG_ERR_INV_VALUE);
1408
1409   err = add_arg (gpg, "--export");
1410   if (!err && use_armor)
1411     err = add_arg (gpg, "--armor");
1412   if (!err)
1413     err = add_data (gpg, keydata, 1, 1);
1414   if (!err)
1415     err = add_arg (gpg, "--");
1416
1417   if (!err && pattern && *pattern)
1418     err = add_arg (gpg, pattern);
1419
1420   if (!err)
1421     err = start (gpg);
1422
1423   return err;
1424 }
1425
1426
1427 static gpgme_error_t
1428 gpg_export_ext (void *engine, const char *pattern[], unsigned int reserved,
1429                 gpgme_data_t keydata, int use_armor)
1430 {
1431   engine_gpg_t gpg = engine;
1432   gpgme_error_t err;
1433
1434   if (reserved)
1435     return gpg_error (GPG_ERR_INV_VALUE);
1436
1437   err = add_arg (gpg, "--export");
1438   if (!err && use_armor)
1439     err = add_arg (gpg, "--armor");
1440   if (!err)
1441     err = add_data (gpg, keydata, 1, 1);
1442   if (!err)
1443     err = add_arg (gpg, "--");
1444
1445   if (pattern)
1446     {
1447       while (!err && *pattern && **pattern)
1448         err = add_arg (gpg, *(pattern++));
1449     }
1450
1451   if (!err)
1452     err = start (gpg);
1453
1454   return err;
1455 }
1456
1457
1458 static gpgme_error_t
1459 gpg_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1460             gpgme_data_t pubkey, gpgme_data_t seckey)
1461 {
1462   engine_gpg_t gpg = engine;
1463   gpgme_error_t err;
1464
1465   if (!gpg)
1466     return gpg_error (GPG_ERR_INV_VALUE);
1467
1468   /* We need a special mechanism to get the fd of a pipe here, so that
1469      we can use this for the %pubring and %secring parameters.  We
1470      don't have this yet, so we implement only the adding to the
1471      standard keyrings.  */
1472   if (pubkey || seckey)
1473     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1474
1475   err = add_arg (gpg, "--gen-key");
1476   if (!err && use_armor)
1477     err = add_arg (gpg, "--armor");
1478   if (!err)
1479     err = add_data (gpg, help_data, 0, 0);
1480
1481   if (!err)
1482     err = start (gpg);
1483
1484   return err;
1485 }
1486
1487
1488 static gpgme_error_t
1489 gpg_import (void *engine, gpgme_data_t keydata)
1490 {
1491   engine_gpg_t gpg = engine;
1492   gpgme_error_t err;
1493
1494   err = add_arg (gpg, "--import");
1495   if (!err)
1496     err = add_data (gpg, keydata, 0, 0);
1497
1498   if (!err)
1499     err = start (gpg);
1500
1501   return err;
1502 }
1503
1504
1505 static gpgme_error_t
1506 gpg_keylist (void *engine, const char *pattern, int secret_only,
1507              gpgme_keylist_mode_t mode)
1508 {
1509   engine_gpg_t gpg = engine;
1510   gpgme_error_t err;
1511
1512   err = add_arg (gpg, "--with-colons");
1513   if (!err)
1514     err = add_arg (gpg, "--fixed-list-mode");
1515   if (!err)
1516     err = add_arg (gpg, "--with-fingerprint");
1517   if (!err)
1518     err = add_arg (gpg, "--with-fingerprint");
1519   if (!err)
1520     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1521                    : ((mode & GPGME_KEYLIST_MODE_SIGS)
1522                       ? "--check-sigs" : "--list-keys"));
1523   
1524   /* Tell the gpg object about the data.  */
1525   if (!err)
1526     err = add_arg (gpg, "--");
1527   if (!err && pattern && *pattern)
1528     err = add_arg (gpg, pattern);
1529
1530   if (!err)
1531     err = start (gpg);
1532
1533   return err;
1534 }
1535
1536
1537 static gpgme_error_t
1538 gpg_keylist_ext (void *engine, const char *pattern[], int secret_only,
1539                  int reserved, gpgme_keylist_mode_t mode)
1540 {
1541   engine_gpg_t gpg = engine;
1542   gpgme_error_t err;
1543
1544   if (reserved)
1545     return gpg_error (GPG_ERR_INV_VALUE);
1546
1547   err = add_arg (gpg, "--with-colons");
1548   if (!err)
1549     err = add_arg (gpg, "--fixed-list-mode");
1550   if (!err)
1551     err = add_arg (gpg, "--with-fingerprint");
1552   if (!err)
1553     err = add_arg (gpg, "--with-fingerprint");
1554   if (!err)
1555     err = add_arg (gpg, secret_only ? "--list-secret-keys"
1556                    : ((mode & GPGME_KEYLIST_MODE_SIGS)
1557                       ? "--check-sigs" : "--list-keys"));
1558   if (!err)
1559     err = add_arg (gpg, "--");
1560
1561   if (pattern)
1562     {
1563       while (!err && *pattern && **pattern)
1564         err = add_arg (gpg, *(pattern++));
1565     }
1566
1567   if (!err)
1568     err = start (gpg);
1569
1570   return err;
1571 }
1572
1573
1574 static gpgme_error_t
1575 gpg_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1576           gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1577           int include_certs, gpgme_ctx_t ctx /* FIXME */)
1578 {
1579   engine_gpg_t gpg = engine;
1580   gpgme_error_t err;
1581
1582   if (mode == GPGME_SIG_MODE_CLEAR)
1583     err = add_arg (gpg, "--clearsign");
1584   else
1585     {
1586       err = add_arg (gpg, "--sign");
1587       if (!err && mode == GPGME_SIG_MODE_DETACH)
1588         err = add_arg (gpg, "--detach");
1589       if (!err && use_armor)
1590         err = add_arg (gpg, "--armor");
1591       if (!err && use_textmode)
1592         err = add_arg (gpg, "--textmode");
1593     }
1594
1595   if (!err)
1596     err = append_args_from_signers (gpg, ctx);
1597
1598   /* Tell the gpg object about the data.  */
1599   if (!err)
1600     err = add_data (gpg, in, 0, 0);
1601   if (!err)
1602     err = add_data (gpg, out, 1, 1);
1603
1604   if (!err)
1605     start (gpg);
1606
1607   return err;
1608 }
1609
1610 static gpgme_error_t
1611 gpg_trustlist (void *engine, const char *pattern)
1612 {
1613   engine_gpg_t gpg = engine;
1614   gpgme_error_t err;
1615
1616   err = add_arg (gpg, "--with-colons");
1617   if (!err)
1618     err = add_arg (gpg, "--list-trust-path");
1619   
1620   /* Tell the gpg object about the data.  */
1621   if (!err)
1622     err = add_arg (gpg, "--");
1623   if (!err)
1624     err = add_arg (gpg, pattern);
1625
1626   if (!err)
1627     err = start (gpg);
1628
1629   return err;
1630 }
1631
1632
1633 static gpgme_error_t
1634 gpg_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1635             gpgme_data_t plaintext)
1636 {
1637   engine_gpg_t gpg = engine;
1638   gpgme_error_t err = 0;
1639
1640   if (plaintext)
1641     {
1642       /* Normal or cleartext signature.  */
1643
1644       err = add_arg (gpg, "--output");
1645       if (!err)
1646         err = add_arg (gpg, "-");
1647       if (!err)
1648         err = add_arg (gpg, "--");
1649       if (!err)
1650         err = add_data (gpg, sig, 0, 0);
1651       if (!err)
1652         err = add_data (gpg, plaintext, 1, 1);
1653     }
1654   else
1655     {
1656       err = add_arg (gpg, "--verify");
1657       if (!err)
1658         err = add_arg (gpg, "--");
1659       if (!err)
1660         err = add_data (gpg, sig, -1, 0);
1661       if (signed_text)
1662         {
1663           if (!err)
1664             err = add_arg (gpg, "-");
1665           if (!err)
1666             err = add_data (gpg, signed_text, 0, 0);
1667         }
1668     }
1669
1670   if (!err)
1671     err = start (gpg);
1672
1673   return err;
1674 }
1675
1676
1677 static void
1678 gpg_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1679 {
1680   engine_gpg_t gpg = engine;
1681
1682   gpg->io_cbs = *io_cbs;
1683 }
1684
1685 \f
1686 struct engine_ops _gpgme_engine_ops_gpg =
1687   {
1688     /* Static functions.  */
1689     _gpgme_get_gpg_path,
1690     gpg_get_version,
1691     gpg_get_req_version,
1692     gpg_new,
1693
1694     /* Member functions.  */
1695     gpg_release,
1696     gpg_set_status_handler,
1697     gpg_set_command_handler,
1698     gpg_set_colon_line_handler,
1699     gpg_decrypt,
1700     gpg_delete,
1701     gpg_edit,
1702     gpg_encrypt,
1703     gpg_encrypt_sign,
1704     gpg_export,
1705     gpg_export_ext,
1706     gpg_genkey,
1707     gpg_import,
1708     gpg_keylist,
1709     gpg_keylist_ext,
1710     gpg_sign,
1711     gpg_trustlist,
1712     gpg_verify,
1713     gpg_set_io_cbs,
1714     gpg_io_event,
1715     gpg_cancel
1716   };