python: Implement data callbacks.
[gpgme.git] / src / engine-gpgsm.c
1 /* engine-gpgsm.c - GpgSM engine.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009,
4                  2010 g10 Code GmbH
5
6    This file is part of GPGME.
7
8    GPGME is free software; you can redistribute it and/or modify it
9    under the terms of the GNU Lesser General Public License as
10    published by the Free Software Foundation; either version 2.1 of
11    the License, or (at your option) any later version.
12
13    GPGME is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    Lesser General Public License for more details.
17
18    You should have received a copy of the GNU Lesser General Public
19    License along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21    02111-1307, USA.  */
22
23 #if HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdlib.h>
28 #include <string.h>
29 #ifdef HAVE_SYS_TYPES_H
30 # include <sys/types.h>
31 #endif
32 #include <assert.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #ifdef HAVE_LOCALE_H
37 #include <locale.h>
38 #endif
39 #include <fcntl.h> /* FIXME */
40 #include <errno.h>
41
42 #include "gpgme.h"
43 #include "util.h"
44 #include "ops.h"
45 #include "wait.h"
46 #include "priv-io.h"
47 #include "sema.h"
48 #include "data.h"
49
50 #include "assuan.h"
51 #include "debug.h"
52
53 #include "engine-backend.h"
54
55 \f
56 typedef struct
57 {
58   int fd;       /* FD we talk about.  */
59   int server_fd;/* Server FD for this connection.  */
60   int dir;      /* Inbound/Outbound, maybe given implicit?  */
61   void *data;   /* Handler-specific data.  */
62   void *tag;    /* ID from the user for gpgme_remove_io_callback.  */
63   char server_fd_str[15]; /* Same as SERVER_FD but as a string.  We
64                              need this because _gpgme_io_fd2str can't
65                              be used on a closed descriptor.  */
66 } iocb_data_t;
67
68
69 struct engine_gpgsm
70 {
71   assuan_context_t assuan_ctx;
72
73   int lc_ctype_set;
74   int lc_messages_set;
75
76   iocb_data_t status_cb;
77
78   /* Input, output etc are from the servers perspective.  */
79   iocb_data_t input_cb;
80   gpgme_data_t input_helper_data;  /* Input helper data object.  */
81   void *input_helper_memory;       /* Input helper memory block.  */
82
83   iocb_data_t output_cb;
84
85   iocb_data_t message_cb;
86
87   struct
88   {
89     engine_status_handler_t fnc;
90     void *fnc_value;
91     gpgme_status_cb_t mon_cb;
92     void *mon_cb_value;
93   } status;
94
95   struct
96   {
97     engine_colon_line_handler_t fnc;
98     void *fnc_value;
99     struct
100     {
101       char *line;
102       int linesize;
103       int linelen;
104     } attic;
105     int any; /* any data line seen */
106   } colon;
107
108   gpgme_data_t inline_data;  /* Used to collect D lines.  */
109
110   struct gpgme_io_cbs io_cbs;
111 };
112
113 typedef struct engine_gpgsm *engine_gpgsm_t;
114
115
116 static void gpgsm_io_event (void *engine,
117                             gpgme_event_io_t type, void *type_data);
118
119
120 \f
121 static char *
122 gpgsm_get_version (const char *file_name)
123 {
124   return _gpgme_get_program_version (file_name ? file_name
125                                      : _gpgme_get_default_gpgsm_name ());
126 }
127
128
129 static const char *
130 gpgsm_get_req_version (void)
131 {
132   return "2.0.4";
133 }
134
135 \f
136 static void
137 close_notify_handler (int fd, void *opaque)
138 {
139   engine_gpgsm_t gpgsm = opaque;
140
141   assert (fd != -1);
142   if (gpgsm->status_cb.fd == fd)
143     {
144       if (gpgsm->status_cb.tag)
145         (*gpgsm->io_cbs.remove) (gpgsm->status_cb.tag);
146       gpgsm->status_cb.fd = -1;
147       gpgsm->status_cb.tag = NULL;
148     }
149   else if (gpgsm->input_cb.fd == fd)
150     {
151       if (gpgsm->input_cb.tag)
152         (*gpgsm->io_cbs.remove) (gpgsm->input_cb.tag);
153       gpgsm->input_cb.fd = -1;
154       gpgsm->input_cb.tag = NULL;
155       if (gpgsm->input_helper_data)
156         {
157           gpgme_data_release (gpgsm->input_helper_data);
158           gpgsm->input_helper_data = NULL;
159         }
160       if (gpgsm->input_helper_memory)
161         {
162           free (gpgsm->input_helper_memory);
163           gpgsm->input_helper_memory = NULL;
164         }
165     }
166   else if (gpgsm->output_cb.fd == fd)
167     {
168       if (gpgsm->output_cb.tag)
169         (*gpgsm->io_cbs.remove) (gpgsm->output_cb.tag);
170       gpgsm->output_cb.fd = -1;
171       gpgsm->output_cb.tag = NULL;
172     }
173   else if (gpgsm->message_cb.fd == fd)
174     {
175       if (gpgsm->message_cb.tag)
176         (*gpgsm->io_cbs.remove) (gpgsm->message_cb.tag);
177       gpgsm->message_cb.fd = -1;
178       gpgsm->message_cb.tag = NULL;
179     }
180 }
181
182
183 /* This is the default inquiry callback.  We use it to handle the
184    Pinentry notifications.  */
185 static gpgme_error_t
186 default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
187 {
188   if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
189     {
190       _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
191     }
192
193   return 0;
194 }
195
196
197 static gpgme_error_t
198 gpgsm_cancel (void *engine)
199 {
200   engine_gpgsm_t gpgsm = engine;
201
202   if (!gpgsm)
203     return gpg_error (GPG_ERR_INV_VALUE);
204
205   if (gpgsm->status_cb.fd != -1)
206     _gpgme_io_close (gpgsm->status_cb.fd);
207   if (gpgsm->input_cb.fd != -1)
208     _gpgme_io_close (gpgsm->input_cb.fd);
209   if (gpgsm->output_cb.fd != -1)
210     _gpgme_io_close (gpgsm->output_cb.fd);
211   if (gpgsm->message_cb.fd != -1)
212     _gpgme_io_close (gpgsm->message_cb.fd);
213
214   if (gpgsm->assuan_ctx)
215     {
216       assuan_release (gpgsm->assuan_ctx);
217       gpgsm->assuan_ctx = NULL;
218     }
219
220   return 0;
221 }
222
223
224 static void
225 gpgsm_release (void *engine)
226 {
227   engine_gpgsm_t gpgsm = engine;
228
229   if (!gpgsm)
230     return;
231
232   gpgsm_cancel (engine);
233
234   free (gpgsm->colon.attic.line);
235   free (gpgsm);
236 }
237
238
239 static gpgme_error_t
240 gpgsm_new (void **engine, const char *file_name, const char *home_dir)
241 {
242   gpgme_error_t err = 0;
243   engine_gpgsm_t gpgsm;
244   const char *pgmname;
245   const char *argv[5];
246   int argc;
247 #if !USE_DESCRIPTOR_PASSING
248   int fds[2];
249   int child_fds[4];
250 #endif
251   char *dft_display = NULL;
252   char dft_ttyname[64];
253   char *dft_ttytype = NULL;
254   char *optstr;
255
256   gpgsm = calloc (1, sizeof *gpgsm);
257   if (!gpgsm)
258     return gpg_error_from_syserror ();
259
260   gpgsm->status_cb.fd = -1;
261   gpgsm->status_cb.dir = 1;
262   gpgsm->status_cb.tag = 0;
263   gpgsm->status_cb.data = gpgsm;
264
265   gpgsm->input_cb.fd = -1;
266   gpgsm->input_cb.dir = 0;
267   gpgsm->input_cb.tag = 0;
268   gpgsm->input_cb.server_fd = -1;
269   *gpgsm->input_cb.server_fd_str = 0;
270   gpgsm->output_cb.fd = -1;
271   gpgsm->output_cb.dir = 1;
272   gpgsm->output_cb.tag = 0;
273   gpgsm->output_cb.server_fd = -1;
274   *gpgsm->output_cb.server_fd_str = 0;
275   gpgsm->message_cb.fd = -1;
276   gpgsm->message_cb.dir = 0;
277   gpgsm->message_cb.tag = 0;
278   gpgsm->message_cb.server_fd = -1;
279   *gpgsm->message_cb.server_fd_str = 0;
280
281   gpgsm->status.fnc = 0;
282   gpgsm->colon.fnc = 0;
283   gpgsm->colon.attic.line = 0;
284   gpgsm->colon.attic.linesize = 0;
285   gpgsm->colon.attic.linelen = 0;
286   gpgsm->colon.any = 0;
287
288   gpgsm->inline_data = NULL;
289
290   gpgsm->io_cbs.add = NULL;
291   gpgsm->io_cbs.add_priv = NULL;
292   gpgsm->io_cbs.remove = NULL;
293   gpgsm->io_cbs.event = NULL;
294   gpgsm->io_cbs.event_priv = NULL;
295
296 #if !USE_DESCRIPTOR_PASSING
297   if (_gpgme_io_pipe (fds, 0) < 0)
298     {
299       err = gpg_error_from_syserror ();
300       goto leave;
301     }
302   gpgsm->input_cb.fd = fds[1];
303   gpgsm->input_cb.server_fd = fds[0];
304
305   if (_gpgme_io_pipe (fds, 1) < 0)
306     {
307       err = gpg_error_from_syserror ();
308       goto leave;
309     }
310   gpgsm->output_cb.fd = fds[0];
311   gpgsm->output_cb.server_fd = fds[1];
312
313   if (_gpgme_io_pipe (fds, 0) < 0)
314     {
315       err = gpg_error_from_syserror ();
316       goto leave;
317     }
318   gpgsm->message_cb.fd = fds[1];
319   gpgsm->message_cb.server_fd = fds[0];
320
321   child_fds[0] = gpgsm->input_cb.server_fd;
322   child_fds[1] = gpgsm->output_cb.server_fd;
323   child_fds[2] = gpgsm->message_cb.server_fd;
324   child_fds[3] = -1;
325 #endif
326
327   pgmname = file_name ? file_name : _gpgme_get_default_gpgsm_name ();
328
329   argc = 0;
330   argv[argc++] = _gpgme_get_basename (pgmname);
331   if (home_dir)
332     {
333       argv[argc++] = "--homedir";
334       argv[argc++] = home_dir;
335     }
336   argv[argc++] = "--server";
337   argv[argc++] = NULL;
338
339   err = assuan_new_ext (&gpgsm->assuan_ctx, GPG_ERR_SOURCE_GPGME,
340                         &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
341                         NULL);
342   if (err)
343     goto leave;
344   assuan_ctx_set_system_hooks (gpgsm->assuan_ctx, &_gpgme_assuan_system_hooks);
345
346 #if USE_DESCRIPTOR_PASSING
347   err = assuan_pipe_connect (gpgsm->assuan_ctx, pgmname, argv,
348                              NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING);
349 #else
350   {
351     assuan_fd_t achild_fds[4];
352     int i;
353
354     /* For now... */
355     for (i = 0; i < 4; i++)
356       achild_fds[i] = (assuan_fd_t) child_fds[i];
357
358     err = assuan_pipe_connect (gpgsm->assuan_ctx, pgmname, argv,
359                                achild_fds, NULL, NULL, 0);
360
361     /* For now... */
362     for (i = 0; i < 4; i++)
363       child_fds[i] = (int) achild_fds[i];
364   }
365
366   /* On Windows, handles are inserted in the spawned process with
367      DuplicateHandle, and child_fds contains the server-local names
368      for the inserted handles when assuan_pipe_connect returns.  */
369   if (!err)
370     {
371       /* Note: We don't use _gpgme_io_fd2str here.  On W32 the
372          returned handles are real W32 system handles, not whatever
373          GPGME uses internally (which may be a system handle, a C
374          library handle or a GLib/Qt channel.  Confusing, yes, but
375          remember these are server-local names, so they are not part
376          of GPGME at all.  */
377       snprintf (gpgsm->input_cb.server_fd_str,
378                 sizeof gpgsm->input_cb.server_fd_str, "%d", child_fds[0]);
379       snprintf (gpgsm->output_cb.server_fd_str,
380                 sizeof gpgsm->output_cb.server_fd_str, "%d", child_fds[1]);
381       snprintf (gpgsm->message_cb.server_fd_str,
382                 sizeof gpgsm->message_cb.server_fd_str, "%d", child_fds[2]);
383     }
384 #endif
385   if (err)
386     goto leave;
387
388   err = _gpgme_getenv ("DISPLAY", &dft_display);
389   if (err)
390     goto leave;
391   if (dft_display)
392     {
393       if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
394         {
395           free (dft_display);
396           err = gpg_error_from_syserror ();
397           goto leave;
398         }
399       free (dft_display);
400
401       err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
402                              NULL, NULL, NULL);
403       free (optstr);
404       if (err)
405         goto leave;
406     }
407
408   if (isatty (1))
409     {
410       int rc;
411
412       rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
413
414       /* Even though isatty() returns 1, ttyname_r() may fail in many
415          ways, e.g., when /dev/pts is not accessible under chroot.  */
416       if (!rc)
417         {
418           if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
419             {
420               err = gpg_error_from_syserror ();
421               goto leave;
422             }
423           err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
424                                  NULL, NULL, NULL);
425           free (optstr);
426           if (err)
427             goto leave;
428
429           err = _gpgme_getenv ("TERM", &dft_ttytype);
430           if (err)
431             goto leave;
432           if (dft_ttytype)
433             {
434               if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
435                 {
436                   free (dft_ttytype);
437                   err = gpg_error_from_syserror ();
438                   goto leave;
439                 }
440               free (dft_ttytype);
441
442               err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
443                                      NULL, NULL, NULL, NULL);
444               free (optstr);
445               if (err)
446                 goto leave;
447             }
448         }
449     }
450
451   /* Ask gpgsm to enable the audit log support.  */
452   if (!err)
453     {
454       err = assuan_transact (gpgsm->assuan_ctx, "OPTION enable-audit-log=1",
455                              NULL, NULL, NULL, NULL, NULL, NULL);
456       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
457         err = 0; /* This is an optional feature of gpgsm.  */
458     }
459
460
461 #ifdef HAVE_W32_SYSTEM
462   /* Under Windows we need to use AllowSetForegroundWindow.  Tell
463      gpgsm to tell us when it needs it.  */
464   if (!err)
465     {
466       err = assuan_transact (gpgsm->assuan_ctx, "OPTION allow-pinentry-notify",
467                              NULL, NULL, NULL, NULL, NULL, NULL);
468       if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
469         err = 0; /* This is a new feature of gpgsm.  */
470     }
471 #endif /*HAVE_W32_SYSTEM*/
472
473 #if !USE_DESCRIPTOR_PASSING
474   if (!err
475       && (_gpgme_io_set_close_notify (gpgsm->input_cb.fd,
476                                       close_notify_handler, gpgsm)
477           || _gpgme_io_set_close_notify (gpgsm->output_cb.fd,
478                                          close_notify_handler, gpgsm)
479           || _gpgme_io_set_close_notify (gpgsm->message_cb.fd,
480                                          close_notify_handler, gpgsm)))
481     {
482       err = gpg_error (GPG_ERR_GENERAL);
483       goto leave;
484     }
485 #endif
486
487  leave:
488   /* Close the server ends of the pipes (because of this, we must use
489      the stored server_fd_str in the function start).  Our ends are
490      closed in gpgsm_release().  */
491 #if !USE_DESCRIPTOR_PASSING
492   if (gpgsm->input_cb.server_fd != -1)
493     _gpgme_io_close (gpgsm->input_cb.server_fd);
494   if (gpgsm->output_cb.server_fd != -1)
495     _gpgme_io_close (gpgsm->output_cb.server_fd);
496   if (gpgsm->message_cb.server_fd != -1)
497     _gpgme_io_close (gpgsm->message_cb.server_fd);
498 #endif
499
500   if (err)
501     gpgsm_release (gpgsm);
502   else
503     *engine = gpgsm;
504
505   return err;
506 }
507
508
509 static gpgme_error_t
510 gpgsm_set_locale (void *engine, int category, const char *value)
511 {
512   engine_gpgsm_t gpgsm = engine;
513   gpgme_error_t err;
514   char *optstr;
515   char *catstr;
516
517   /* FIXME: If value is NULL, we need to reset the option to default.
518      But we can't do this.  So we error out here.  GPGSM needs support
519      for this.  */
520   if (0)
521     ;
522 #ifdef LC_CTYPE
523   else if (category == LC_CTYPE)
524     {
525       catstr = "lc-ctype";
526       if (!value && gpgsm->lc_ctype_set)
527         return gpg_error (GPG_ERR_INV_VALUE);
528       if (value)
529         gpgsm->lc_ctype_set = 1;
530     }
531 #endif
532 #ifdef LC_MESSAGES
533   else if (category == LC_MESSAGES)
534     {
535       catstr = "lc-messages";
536       if (!value && gpgsm->lc_messages_set)
537         return gpg_error (GPG_ERR_INV_VALUE);
538       if (value)
539         gpgsm->lc_messages_set = 1;
540     }
541 #endif /* LC_MESSAGES */
542   else
543     return gpg_error (GPG_ERR_INV_VALUE);
544
545   /* FIXME: Reset value to default.  */
546   if (!value)
547     return 0;
548
549   if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
550     err = gpg_error_from_syserror ();
551   else
552     {
553       err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
554                              NULL, NULL, NULL, NULL);
555       free (optstr);
556     }
557
558   return err;
559 }
560
561
562 static gpgme_error_t
563 gpgsm_assuan_simple_command (engine_gpgsm_t gpgsm, char *cmd,
564                              engine_status_handler_t status_fnc,
565                              void *status_fnc_value)
566 {
567   assuan_context_t ctx = gpgsm->assuan_ctx;
568   gpg_error_t err, cb_err;
569   char *line;
570   size_t linelen;
571
572   err = assuan_write_line (ctx, cmd);
573   if (err)
574     return err;
575
576   cb_err = 0;
577   do
578     {
579       err = assuan_read_line (ctx, &line, &linelen);
580       if (err)
581         return err;
582
583       if (*line == '#' || !linelen)
584         continue;
585
586       if (linelen >= 2
587           && line[0] == 'O' && line[1] == 'K'
588           && (line[2] == '\0' || line[2] == ' '))
589         return cb_err;
590       else if (linelen >= 4
591           && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
592           && line[3] == ' ')
593         {
594           /* We prefer a callback generated error because that one is
595              more related to gpgme and thus probably more important
596              than the error returned by the engine.  */
597           err = cb_err? cb_err : atoi (&line[4]);
598         }
599       else if (linelen >= 2
600                && line[0] == 'S' && line[1] == ' ')
601         {
602           /* After an error from a status callback we skip all further
603              status lines.  */
604           if (!cb_err)
605             {
606               char *rest;
607               gpgme_status_code_t r;
608
609               rest = strchr (line + 2, ' ');
610               if (!rest)
611                 rest = line + linelen; /* set to an empty string */
612               else
613                 *(rest++) = 0;
614
615               r = _gpgme_parse_status (line + 2);
616               if (gpgsm->status.mon_cb && r != GPGME_STATUS_PROGRESS)
617                 {
618                   /* Note that we call the monitor even if we do
619                    * not know the status code (r < 0).  */
620                   cb_err = gpgsm->status.mon_cb (gpgsm->status.mon_cb_value,
621                                                  line + 2, rest);
622                 }
623
624               if (r >= 0 && status_fnc && !cb_err)
625                 cb_err = status_fnc (status_fnc_value, r, rest);
626             }
627         }
628       else
629         {
630           /* Invalid line or INQUIRY.  We can't do anything else than
631              to stop.  As with ERR we prefer a status callback
632              generated error code, though.  */
633           err = cb_err ? cb_err : gpg_error (GPG_ERR_GENERAL);
634         }
635     }
636   while (!err);
637
638   return err;
639 }
640
641
642 typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
643
644 static void
645 gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
646 {
647 #if !USE_DESCRIPTOR_PASSING
648   switch (fd_type)
649     {
650     case INPUT_FD:
651       _gpgme_io_close (gpgsm->input_cb.fd);
652       break;
653     case OUTPUT_FD:
654       _gpgme_io_close (gpgsm->output_cb.fd);
655       break;
656     case MESSAGE_FD:
657       _gpgme_io_close (gpgsm->message_cb.fd);
658       break;
659     }
660 #endif
661 }
662
663 #define COMMANDLINELEN 40
664 static gpgme_error_t
665 gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
666 {
667   gpg_error_t err = 0;
668   char line[COMMANDLINELEN];
669   char *which;
670   iocb_data_t *iocb_data;
671 #if USE_DESCRIPTOR_PASSING
672   int dir;
673 #endif
674
675   switch (fd_type)
676     {
677     case INPUT_FD:
678       which = "INPUT";
679       iocb_data = &gpgsm->input_cb;
680       break;
681
682     case OUTPUT_FD:
683       which = "OUTPUT";
684       iocb_data = &gpgsm->output_cb;
685       break;
686
687     case MESSAGE_FD:
688       which = "MESSAGE";
689       iocb_data = &gpgsm->message_cb;
690       break;
691
692     default:
693       return gpg_error (GPG_ERR_INV_VALUE);
694     }
695
696 #if USE_DESCRIPTOR_PASSING
697   dir = iocb_data->dir;
698   /* We try to short-cut the communication by giving GPGSM direct
699      access to the file descriptor, rather than using a pipe.  */
700   iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
701   if (iocb_data->server_fd < 0)
702     {
703       int fds[2];
704
705       if (_gpgme_io_pipe (fds, dir) < 0)
706         return gpg_error_from_syserror ();
707
708       iocb_data->fd = dir ? fds[0] : fds[1];
709       iocb_data->server_fd = dir ? fds[1] : fds[0];
710
711       if (_gpgme_io_set_close_notify (iocb_data->fd,
712                                       close_notify_handler, gpgsm))
713         {
714           err = gpg_error (GPG_ERR_GENERAL);
715           goto leave_set_fd;
716         }
717     }
718
719   err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
720   if (err)
721     goto leave_set_fd;
722
723   _gpgme_io_close (iocb_data->server_fd);
724   iocb_data->server_fd = -1;
725
726   if (opt)
727     snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
728   else
729     snprintf (line, COMMANDLINELEN, "%s FD", which);
730 #else
731   if (opt)
732     snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
733               which, iocb_data->server_fd_str, opt);
734   else
735     snprintf (line, COMMANDLINELEN, "%s FD=%s",
736               which, iocb_data->server_fd_str);
737 #endif
738
739   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
740
741 #if USE_DESCRIPTOR_PASSING
742  leave_set_fd:
743   if (err)
744     {
745       _gpgme_io_close (iocb_data->fd);
746       iocb_data->fd = -1;
747       if (iocb_data->server_fd != -1)
748         {
749           _gpgme_io_close (iocb_data->server_fd);
750           iocb_data->server_fd = -1;
751         }
752     }
753 #endif
754
755   return err;
756 }
757
758
759 static const char *
760 map_data_enc (gpgme_data_t d)
761 {
762   switch (gpgme_data_get_encoding (d))
763     {
764     case GPGME_DATA_ENCODING_NONE:
765       break;
766     case GPGME_DATA_ENCODING_BINARY:
767       return "--binary";
768     case GPGME_DATA_ENCODING_BASE64:
769       return "--base64";
770     case GPGME_DATA_ENCODING_ARMOR:
771       return "--armor";
772     default:
773       break;
774     }
775   return NULL;
776 }
777
778
779 static gpgme_error_t
780 status_handler (void *opaque, int fd)
781 {
782   struct io_cb_data *data = (struct io_cb_data *) opaque;
783   engine_gpgsm_t gpgsm = (engine_gpgsm_t) data->handler_value;
784   gpgme_error_t err = 0;
785   char *line;
786   size_t linelen;
787
788   do
789     {
790       err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
791       if (err)
792         {
793           /* Try our best to terminate the connection friendly.  */
794           /*      assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
795           TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
796                   "fd 0x%x: error from assuan (%d) getting status line : %s",
797                   fd, err, gpg_strerror (err));
798         }
799       else if (linelen >= 3
800                && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
801                && (line[3] == '\0' || line[3] == ' '))
802         {
803           if (line[3] == ' ')
804             err = atoi (&line[4]);
805           if (! err)
806             err = gpg_error (GPG_ERR_GENERAL);
807           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
808                   "fd 0x%x: ERR line - mapped to: %s",
809                   fd, err ? gpg_strerror (err) : "ok");
810           /* Try our best to terminate the connection friendly.  */
811           /*      assuan_write_line (gpgsm->assuan_ctx, "BYE"); */
812         }
813       else if (linelen >= 2
814                && line[0] == 'O' && line[1] == 'K'
815                && (line[2] == '\0' || line[2] == ' '))
816         {
817           if (gpgsm->status.fnc)
818             err = gpgsm->status.fnc (gpgsm->status.fnc_value,
819                                      GPGME_STATUS_EOF, "");
820
821           if (!err && gpgsm->colon.fnc && gpgsm->colon.any)
822             {
823               /* We must tell a colon function about the EOF. We do
824                  this only when we have seen any data lines.  Note
825                  that this inlined use of colon data lines will
826                  eventually be changed into using a regular data
827                  channel. */
828               gpgsm->colon.any = 0;
829               err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
830             }
831           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
832                   "fd 0x%x: OK line - final status: %s",
833                   fd, err ? gpg_strerror (err) : "ok");
834           _gpgme_io_close (gpgsm->status_cb.fd);
835           return err;
836         }
837       else if (linelen > 2
838                && line[0] == 'D' && line[1] == ' '
839                && gpgsm->colon.fnc)
840         {
841           /* We are using the colon handler even for plain inline data
842              - strange name for that function but for historic reasons
843              we keep it.  */
844           /* FIXME We can't use this for binary data because we
845              assume this is a string.  For the current usage of colon
846              output it is correct.  */
847           char *src = line + 2;
848           char *end = line + linelen;
849           char *dst;
850           char **aline = &gpgsm->colon.attic.line;
851           int *alinelen = &gpgsm->colon.attic.linelen;
852
853           if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
854             {
855               char *newline = realloc (*aline, *alinelen + linelen + 1);
856               if (!newline)
857                 err = gpg_error_from_syserror ();
858               else
859                 {
860                   *aline = newline;
861                   gpgsm->colon.attic.linesize = *alinelen + linelen + 1;
862                 }
863             }
864           if (!err)
865             {
866               dst = *aline + *alinelen;
867
868               while (!err && src < end)
869                 {
870                   if (*src == '%' && src + 2 < end)
871                     {
872                       /* Handle escaped characters.  */
873                       ++src;
874                       *dst = _gpgme_hextobyte (src);
875                       (*alinelen)++;
876                       src += 2;
877                     }
878                   else
879                     {
880                       *dst = *src++;
881                       (*alinelen)++;
882                     }
883
884                   if (*dst == '\n')
885                     {
886                       /* Terminate the pending line, pass it to the colon
887                          handler and reset it.  */
888
889                       gpgsm->colon.any = 1;
890                       if (*alinelen > 1 && *(dst - 1) == '\r')
891                         dst--;
892                       *dst = '\0';
893
894                       /* FIXME How should we handle the return code?  */
895                       err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
896                       if (!err)
897                         {
898                           dst = *aline;
899                           *alinelen = 0;
900                         }
901                     }
902                   else
903                     dst++;
904                 }
905             }
906           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
907                   "fd 0x%x: D line; final status: %s",
908                   fd, err? gpg_strerror (err):"ok");
909         }
910       else if (linelen > 2
911                && line[0] == 'D' && line[1] == ' '
912                && gpgsm->inline_data)
913         {
914           char *src = line + 2;
915           char *end = line + linelen;
916           char *dst = src;
917           gpgme_ssize_t nwritten;
918
919           linelen = 0;
920           while (src < end)
921             {
922               if (*src == '%' && src + 2 < end)
923                 {
924                   /* Handle escaped characters.  */
925                   ++src;
926                   *dst++ = _gpgme_hextobyte (src);
927                   src += 2;
928                 }
929               else
930                 *dst++ = *src++;
931
932               linelen++;
933             }
934
935           src = line + 2;
936           while (linelen > 0)
937             {
938               nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
939               if (!nwritten || (nwritten < 0 && errno != EINTR)
940                   || nwritten > linelen)
941                 {
942                   err = gpg_error_from_syserror ();
943                   break;
944                 }
945               src += nwritten;
946               linelen -= nwritten;
947             }
948
949           TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
950                   "fd 0x%x: D inlinedata; final status: %s",
951                   fd, err? gpg_strerror (err):"ok");
952         }
953       else if (linelen > 2
954                && line[0] == 'S' && line[1] == ' ')
955         {
956           char *rest;
957           gpgme_status_code_t r;
958
959           rest = strchr (line + 2, ' ');
960           if (!rest)
961             rest = line + linelen; /* set to an empty string */
962           else
963             *(rest++) = 0;
964
965           r = _gpgme_parse_status (line + 2);
966
967           if (r >= 0)
968             {
969               if (gpgsm->status.fnc)
970                 err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
971             }
972           else
973             fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
974           TRACE3 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
975                   "fd 0x%x: S line (%s) - final status: %s",
976                   fd, line+2, err? gpg_strerror (err):"ok");
977         }
978       else if (linelen >= 7
979                && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
980                && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
981                && line[6] == 'E'
982                && (line[7] == '\0' || line[7] == ' '))
983         {
984           char *keyword = line+7;
985
986           while (*keyword == ' ')
987             keyword++;;
988           default_inq_cb (gpgsm, keyword);
989           assuan_write_line (gpgsm->assuan_ctx, "END");
990         }
991
992     }
993   while (!err && assuan_pending_line (gpgsm->assuan_ctx));
994
995   return err;
996 }
997
998
999 static gpgme_error_t
1000 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
1001 {
1002   gpgme_error_t err;
1003
1004   TRACE_BEG2 (DEBUG_ENGINE, "engine-gpgsm:add_io_cb", gpgsm,
1005               "fd %d, dir %d", iocbd->fd, iocbd->dir);
1006   err = (*gpgsm->io_cbs.add) (gpgsm->io_cbs.add_priv,
1007                               iocbd->fd, iocbd->dir,
1008                               handler, iocbd->data, &iocbd->tag);
1009   if (err)
1010     return TRACE_ERR (err);
1011   if (!iocbd->dir)
1012     /* FIXME Kludge around poll() problem.  */
1013     err = _gpgme_io_set_nonblocking (iocbd->fd);
1014   return TRACE_ERR (err);
1015 }
1016
1017
1018 static gpgme_error_t
1019 start (engine_gpgsm_t gpgsm, const char *command)
1020 {
1021   gpgme_error_t err;
1022   assuan_fd_t afdlist[5];
1023   int fdlist[5];
1024   int nfds;
1025   int i;
1026
1027   /* We need to know the fd used by assuan for reads.  We do this by
1028      using the assumption that the first returned fd from
1029      assuan_get_active_fds() is always this one.  */
1030   nfds = assuan_get_active_fds (gpgsm->assuan_ctx, 0 /* read fds */,
1031                                 afdlist, DIM (afdlist));
1032   if (nfds < 1)
1033     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1034   /* For now... */
1035   for (i = 0; i < nfds; i++)
1036     fdlist[i] = (int) afdlist[i];
1037
1038   /* We "duplicate" the file descriptor, so we can close it here (we
1039      can't close fdlist[0], as that is closed by libassuan, and
1040      closing it here might cause libassuan to close some unrelated FD
1041      later).  Alternatively, we could special case status_fd and
1042      register/unregister it manually as needed, but this increases
1043      code duplication and is more complicated as we can not use the
1044      close notifications etc.  A third alternative would be to let
1045      Assuan know that we closed the FD, but that complicates the
1046      Assuan interface.  */
1047
1048   gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1049   if (gpgsm->status_cb.fd < 0)
1050     return gpg_error_from_syserror ();
1051
1052   if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1053                                   close_notify_handler, gpgsm))
1054     {
1055       _gpgme_io_close (gpgsm->status_cb.fd);
1056       gpgsm->status_cb.fd = -1;
1057       return gpg_error (GPG_ERR_GENERAL);
1058     }
1059
1060   err = add_io_cb (gpgsm, &gpgsm->status_cb, status_handler);
1061   if (!err && gpgsm->input_cb.fd != -1)
1062     err = add_io_cb (gpgsm, &gpgsm->input_cb, _gpgme_data_outbound_handler);
1063   if (!err && gpgsm->output_cb.fd != -1)
1064     err = add_io_cb (gpgsm, &gpgsm->output_cb, _gpgme_data_inbound_handler);
1065   if (!err && gpgsm->message_cb.fd != -1)
1066     err = add_io_cb (gpgsm, &gpgsm->message_cb, _gpgme_data_outbound_handler);
1067
1068   if (!err)
1069     err = assuan_write_line (gpgsm->assuan_ctx, command);
1070
1071   if (!err)
1072     gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1073
1074   return err;
1075 }
1076
1077
1078 #if USE_DESCRIPTOR_PASSING
1079 static gpgme_error_t
1080 gpgsm_reset (void *engine)
1081 {
1082   engine_gpgsm_t gpgsm = engine;
1083
1084   /* IF we have an active connection we must send a reset because we
1085      need to reset the list of signers.  Note that RESET does not
1086      reset OPTION commands. */
1087   return (gpgsm->assuan_ctx
1088           ? gpgsm_assuan_simple_command (gpgsm, "RESET", NULL, NULL)
1089           : 0);
1090 }
1091 #endif
1092
1093
1094
1095 static gpgme_error_t
1096 gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1097 {
1098   engine_gpgsm_t gpgsm = engine;
1099   gpgme_error_t err;
1100
1101   if (!gpgsm)
1102     return gpg_error (GPG_ERR_INV_VALUE);
1103
1104   gpgsm->input_cb.data = ciph;
1105   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1106   if (err)
1107     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1108   gpgsm->output_cb.data = plain;
1109   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1110   if (err)
1111     return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1112   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1113   gpgsm->inline_data = NULL;
1114
1115   err = start (engine, "DECRYPT");
1116   return err;
1117 }
1118
1119
1120 static gpgme_error_t
1121 gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
1122 {
1123   engine_gpgsm_t gpgsm = engine;
1124   gpgme_error_t err;
1125   char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1126   char *linep = fpr;
1127   char *line;
1128   int length = 8;       /* "DELKEYS " */
1129
1130   if (!fpr)
1131     return gpg_error (GPG_ERR_INV_VALUE);
1132
1133   while (*linep)
1134     {
1135       length++;
1136       if (*linep == '%' || *linep == ' ' || *linep == '+')
1137         length += 2;
1138       linep++;
1139     }
1140   length++;
1141
1142   line = malloc (length);
1143   if (!line)
1144     return gpg_error_from_syserror ();
1145
1146   strcpy (line, "DELKEYS ");
1147   linep = &line[8];
1148
1149   while (*fpr)
1150     {
1151       switch (*fpr)
1152         {
1153         case '%':
1154           *(linep++) = '%';
1155           *(linep++) = '2';
1156           *(linep++) = '5';
1157           break;
1158         case ' ':
1159           *(linep++) = '%';
1160           *(linep++) = '2';
1161           *(linep++) = '0';
1162           break;
1163         case '+':
1164           *(linep++) = '%';
1165           *(linep++) = '2';
1166           *(linep++) = 'B';
1167           break;
1168         default:
1169           *(linep++) = *fpr;
1170           break;
1171         }
1172       fpr++;
1173     }
1174   *linep = '\0';
1175
1176   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1177   gpgsm_clear_fd (gpgsm, INPUT_FD);
1178   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1179   gpgsm->inline_data = NULL;
1180
1181   err = start (gpgsm, line);
1182   free (line);
1183
1184   return err;
1185 }
1186
1187
1188 static gpgme_error_t
1189 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1190 {
1191   gpgme_error_t err = 0;
1192   char *line;
1193   int linelen;
1194   int invalid_recipients = 0;
1195   int i;
1196
1197   linelen = 10 + 40 + 1;        /* "RECIPIENT " + guess + '\0'.  */
1198   line = malloc (10 + 40 + 1);
1199   if (!line)
1200     return gpg_error_from_syserror ();
1201   strcpy (line, "RECIPIENT ");
1202   for (i =0; !err && recp[i]; i++)
1203     {
1204       char *fpr;
1205       int newlen;
1206
1207       if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1208         {
1209           invalid_recipients++;
1210           continue;
1211         }
1212       fpr = recp[i]->subkeys->fpr;
1213
1214       newlen = 11 + strlen (fpr);
1215       if (linelen < newlen)
1216         {
1217           char *newline = realloc (line, newlen);
1218           if (! newline)
1219             {
1220               int saved_err = gpg_error_from_syserror ();
1221               free (line);
1222               return saved_err;
1223             }
1224           line = newline;
1225           linelen = newlen;
1226         }
1227       strcpy (&line[10], fpr);
1228
1229       err = gpgsm_assuan_simple_command (gpgsm, line, gpgsm->status.fnc,
1230                                          gpgsm->status.fnc_value);
1231       /* FIXME: This requires more work.  */
1232       if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1233         invalid_recipients++;
1234       else if (err)
1235         {
1236           free (line);
1237           return err;
1238         }
1239     }
1240   free (line);
1241   return gpg_error (invalid_recipients
1242                     ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1243 }
1244
1245
1246 static gpgme_error_t
1247 gpgsm_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1248                gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1249 {
1250   engine_gpgsm_t gpgsm = engine;
1251   gpgme_error_t err;
1252
1253   if (!gpgsm)
1254     return gpg_error (GPG_ERR_INV_VALUE);
1255   if (!recp)
1256     return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1257
1258   if (flags & GPGME_ENCRYPT_NO_ENCRYPT_TO)
1259     {
1260       err = gpgsm_assuan_simple_command (gpgsm,
1261                                          "OPTION no-encrypt-to", NULL, NULL);
1262       if (err)
1263         return err;
1264     }
1265
1266   gpgsm->input_cb.data = plain;
1267   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1268   if (err)
1269     return err;
1270   gpgsm->output_cb.data = ciph;
1271   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1272                       : map_data_enc (gpgsm->output_cb.data));
1273   if (err)
1274     return err;
1275   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1276   gpgsm->inline_data = NULL;
1277
1278   err = set_recipients (gpgsm, recp);
1279
1280   if (!err)
1281     err = start (gpgsm, "ENCRYPT");
1282
1283   return err;
1284 }
1285
1286
1287 static gpgme_error_t
1288 gpgsm_export (void *engine, const char *pattern, gpgme_export_mode_t mode,
1289               gpgme_data_t keydata, int use_armor)
1290 {
1291   engine_gpgsm_t gpgsm = engine;
1292   gpgme_error_t err = 0;
1293   char *cmd;
1294
1295   if (!gpgsm)
1296     return gpg_error (GPG_ERR_INV_VALUE);
1297
1298   if (!pattern)
1299     pattern = "";
1300
1301   cmd = malloc (7 + 9 + 9 + strlen (pattern) + 1);
1302   if (!cmd)
1303     return gpg_error_from_syserror ();
1304
1305   strcpy (cmd, "EXPORT ");
1306   if ((mode & GPGME_EXPORT_MODE_SECRET))
1307     {
1308       strcat (cmd, "--secret ");
1309       if ((mode & GPGME_EXPORT_MODE_RAW))
1310         strcat (cmd, "--raw ");
1311       else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1312         strcat (cmd, "--pkcs12 ");
1313     }
1314   strcat (cmd, pattern);
1315
1316   gpgsm->output_cb.data = keydata;
1317   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1318                       : map_data_enc (gpgsm->output_cb.data));
1319   if (err)
1320     return err;
1321   gpgsm_clear_fd (gpgsm, INPUT_FD);
1322   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1323   gpgsm->inline_data = NULL;
1324
1325   err = start (gpgsm, cmd);
1326   free (cmd);
1327   return err;
1328 }
1329
1330
1331 static gpgme_error_t
1332 gpgsm_export_ext (void *engine, const char *pattern[], gpgme_export_mode_t mode,
1333                   gpgme_data_t keydata, int use_armor)
1334 {
1335   engine_gpgsm_t gpgsm = engine;
1336   gpgme_error_t err = 0;
1337   char *line;
1338   /* Length is "EXPORT " + "--secret " + "--pkcs12 " + p + '\0'.  */
1339   int length = 7 + 9 + 9 + 1;
1340   char *linep;
1341
1342   if (!gpgsm)
1343     return gpg_error (GPG_ERR_INV_VALUE);
1344
1345   if (pattern && *pattern)
1346     {
1347       const char **pat = pattern;
1348
1349       while (*pat)
1350         {
1351           const char *patlet = *pat;
1352
1353           while (*patlet)
1354             {
1355               length++;
1356               if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1357                 length += 2;
1358               patlet++;
1359             }
1360           pat++;
1361           length++;
1362         }
1363     }
1364   line = malloc (length);
1365   if (!line)
1366     return gpg_error_from_syserror ();
1367
1368   strcpy (line, "EXPORT ");
1369   if ((mode & GPGME_EXPORT_MODE_SECRET))
1370     {
1371       strcat (line, "--secret ");
1372       if ((mode & GPGME_EXPORT_MODE_RAW))
1373         strcat (line, "--raw ");
1374       else if ((mode & GPGME_EXPORT_MODE_PKCS12))
1375         strcat (line, "--pkcs12 ");
1376     }
1377   linep = &line[strlen (line)];
1378
1379   if (pattern && *pattern)
1380     {
1381       while (*pattern)
1382         {
1383           const char *patlet = *pattern;
1384
1385           while (*patlet)
1386             {
1387               switch (*patlet)
1388                 {
1389                 case '%':
1390                   *(linep++) = '%';
1391                   *(linep++) = '2';
1392                   *(linep++) = '5';
1393                   break;
1394                 case ' ':
1395                   *(linep++) = '%';
1396                   *(linep++) = '2';
1397                   *(linep++) = '0';
1398                   break;
1399                 case '+':
1400                   *(linep++) = '%';
1401                   *(linep++) = '2';
1402                   *(linep++) = 'B';
1403                   break;
1404                 default:
1405                   *(linep++) = *patlet;
1406                   break;
1407                 }
1408               patlet++;
1409             }
1410           pattern++;
1411           if (*pattern)
1412             *linep++ = ' ';
1413         }
1414     }
1415   *linep = '\0';
1416
1417   gpgsm->output_cb.data = keydata;
1418   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1419                       : map_data_enc (gpgsm->output_cb.data));
1420   if (err)
1421     return err;
1422   gpgsm_clear_fd (gpgsm, INPUT_FD);
1423   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1424   gpgsm->inline_data = NULL;
1425
1426   err = start (gpgsm, line);
1427   free (line);
1428   return err;
1429 }
1430
1431
1432 static gpgme_error_t
1433 gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1434               gpgme_data_t pubkey, gpgme_data_t seckey)
1435 {
1436   engine_gpgsm_t gpgsm = engine;
1437   gpgme_error_t err;
1438
1439   if (!gpgsm || !pubkey || seckey)
1440     return gpg_error (GPG_ERR_INV_VALUE);
1441
1442   gpgsm->input_cb.data = help_data;
1443   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1444   if (err)
1445     return err;
1446   gpgsm->output_cb.data = pubkey;
1447   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1448                       : map_data_enc (gpgsm->output_cb.data));
1449   if (err)
1450     return err;
1451   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1452   gpgsm->inline_data = NULL;
1453
1454   err = start (gpgsm, "GENKEY");
1455   return err;
1456 }
1457
1458
1459 static gpgme_error_t
1460 gpgsm_import (void *engine, gpgme_data_t keydata, gpgme_key_t *keyarray)
1461 {
1462   engine_gpgsm_t gpgsm = engine;
1463   gpgme_error_t err;
1464   gpgme_data_encoding_t dataenc;
1465   int idx;
1466
1467   if (!gpgsm)
1468     return gpg_error (GPG_ERR_INV_VALUE);
1469
1470   if (keydata && keyarray)
1471     return gpg_error (GPG_ERR_INV_VALUE); /* Only one is allowed.  */
1472
1473   dataenc = gpgme_data_get_encoding (keydata);
1474
1475   if (keyarray)
1476     {
1477       size_t buflen;
1478       char *buffer, *p;
1479
1480       /* Fist check whether the engine already features the
1481          --re-import option.  */
1482       err = gpgsm_assuan_simple_command
1483         (gpgsm, "GETINFO cmd_has_option IMPORT re-import", NULL, NULL);
1484       if (err)
1485         return gpg_error (GPG_ERR_NOT_SUPPORTED);
1486
1487       /* Create an internal data object with a list of all
1488          fingerprints.  The data object and its memory (to avoid an
1489          extra copy by gpgme_data_new_from_mem) are stored in two
1490          variables which are released by the close_notify_handler.  */
1491       for (idx=0, buflen=0; keyarray[idx]; idx++)
1492         {
1493           if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1494               && keyarray[idx]->subkeys
1495               && keyarray[idx]->subkeys->fpr
1496               && *keyarray[idx]->subkeys->fpr)
1497             buflen += strlen (keyarray[idx]->subkeys->fpr) + 1;
1498         }
1499       /* Allocate a bufer with extra space for the trailing Nul
1500          introduced by the use of stpcpy.  */
1501       buffer = malloc (buflen+1);
1502       if (!buffer)
1503         return gpg_error_from_syserror ();
1504       for (idx=0, p = buffer; keyarray[idx]; idx++)
1505         {
1506           if (keyarray[idx]->protocol == GPGME_PROTOCOL_CMS
1507               && keyarray[idx]->subkeys
1508               && keyarray[idx]->subkeys->fpr
1509               && *keyarray[idx]->subkeys->fpr)
1510             p = stpcpy (stpcpy (p, keyarray[idx]->subkeys->fpr), "\n");
1511         }
1512
1513       err = gpgme_data_new_from_mem (&gpgsm->input_helper_data,
1514                                      buffer, buflen, 0);
1515       if (err)
1516         {
1517           free (buffer);
1518           return err;
1519         }
1520       gpgsm->input_helper_memory = buffer;
1521
1522       gpgsm->input_cb.data = gpgsm->input_helper_data;
1523       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1524       if (err)
1525         {
1526           gpgme_data_release (gpgsm->input_helper_data);
1527           gpgsm->input_helper_data = NULL;
1528           free (gpgsm->input_helper_memory);
1529           gpgsm->input_helper_memory = NULL;
1530           return err;
1531         }
1532       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1533       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1534       gpgsm->inline_data = NULL;
1535
1536       return start (gpgsm, "IMPORT --re-import");
1537     }
1538   else if (dataenc == GPGME_DATA_ENCODING_URL
1539            || dataenc == GPGME_DATA_ENCODING_URL0
1540            || dataenc == GPGME_DATA_ENCODING_URLESC)
1541     {
1542       return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1543     }
1544   else
1545     {
1546       gpgsm->input_cb.data = keydata;
1547       err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1548       if (err)
1549         return err;
1550       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1551       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1552       gpgsm->inline_data = NULL;
1553
1554       return start (gpgsm, "IMPORT");
1555     }
1556 }
1557
1558
1559 static gpgme_error_t
1560 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1561                gpgme_keylist_mode_t mode, int engine_flags)
1562 {
1563   engine_gpgsm_t gpgsm = engine;
1564   char *line;
1565   gpgme_error_t err;
1566   int list_mode = 0;
1567
1568   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1569     list_mode |= 1;
1570   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1571     list_mode |= 2;
1572
1573   if (!pattern)
1574     pattern = "";
1575
1576   /* Hack to make sure that the agent is started.  Only if the agent
1577      has been started an application may connect to the agent via
1578      GPGME_PROTOCOL_ASSUAN - for example to look for smartcards.  We
1579      do this only if a secret key listing has been requested.  In
1580      general this is not needed because a secret key listing starts
1581      the agent.  However on a fresh installation no public keys are
1582      available and thus there is no need for gpgsm to ask the agent
1583      whether a secret key exists for the public key.  */
1584   if (secret_only || (mode & GPGME_KEYLIST_MODE_WITH_SECRET))
1585     gpgsm_assuan_simple_command (gpgsm, "GETINFO agent-check", NULL, NULL);
1586
1587   /* Always send list-mode option because RESET does not reset it.  */
1588   if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1589     return gpg_error_from_syserror ();
1590   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1591   free (line);
1592   if (err)
1593     return err;
1594
1595
1596   /* Always send key validation because RESET does not reset it.  */
1597
1598   /* Use the validation mode if requested.  We don't check for an error
1599      yet because this is a pretty fresh gpgsm features. */
1600   gpgsm_assuan_simple_command (gpgsm,
1601                                (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1602                                "OPTION with-validation=1":
1603                                "OPTION with-validation=0" ,
1604                                NULL, NULL);
1605   /* Include the ephemeral keys if requested.  We don't check for an error
1606      yet because this is a pretty fresh gpgsm features. */
1607   gpgsm_assuan_simple_command (gpgsm,
1608                                (mode & GPGME_KEYLIST_MODE_EPHEMERAL)?
1609                                "OPTION with-ephemeral-keys=1":
1610                                "OPTION with-ephemeral-keys=0" ,
1611                                NULL, NULL);
1612   gpgsm_assuan_simple_command (gpgsm,
1613                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1614                                "OPTION with-secret=1":
1615                                "OPTION with-secret=0" ,
1616                                NULL, NULL);
1617   gpgsm_assuan_simple_command (gpgsm,
1618                                (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1619                                "OPTION offline=1":
1620                                "OPTION offline=0" ,
1621                                NULL, NULL);
1622
1623
1624   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1625   line = malloc (15 + strlen (pattern) + 1);
1626   if (!line)
1627     return gpg_error_from_syserror ();
1628   if (secret_only)
1629     {
1630       strcpy (line, "LISTSECRETKEYS ");
1631       strcpy (&line[15], pattern);
1632     }
1633   else
1634     {
1635       strcpy (line, "LISTKEYS ");
1636       strcpy (&line[9], pattern);
1637     }
1638
1639   gpgsm_clear_fd (gpgsm, INPUT_FD);
1640   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1641   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1642   gpgsm->inline_data = NULL;
1643
1644   err = start (gpgsm, line);
1645   free (line);
1646   return err;
1647 }
1648
1649
1650 static gpgme_error_t
1651 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1652                    int reserved, gpgme_keylist_mode_t mode, int engine_flags)
1653 {
1654   engine_gpgsm_t gpgsm = engine;
1655   char *line;
1656   gpgme_error_t err;
1657   /* Length is "LISTSECRETKEYS " + p + '\0'.  */
1658   int length = 15 + 1;
1659   char *linep;
1660   int any_pattern = 0;
1661   int list_mode = 0;
1662
1663   if (reserved)
1664     return gpg_error (GPG_ERR_INV_VALUE);
1665
1666   if (mode & GPGME_KEYLIST_MODE_LOCAL)
1667     list_mode |= 1;
1668   if (mode & GPGME_KEYLIST_MODE_EXTERN)
1669     list_mode |= 2;
1670
1671   /* Always send list-mode option because RESET does not reset it.  */
1672   if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1673     return gpg_error_from_syserror ();
1674   err = gpgsm_assuan_simple_command (gpgsm, line, NULL, NULL);
1675   free (line);
1676   if (err)
1677     return err;
1678
1679   /* Always send key validation because RESET does not reset it.  */
1680   /* Use the validation mode if required.  We don't check for an error
1681      yet because this is a pretty fresh gpgsm features. */
1682   gpgsm_assuan_simple_command (gpgsm,
1683                                (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1684                                "OPTION with-validation=1":
1685                                "OPTION with-validation=0" ,
1686                                NULL, NULL);
1687   gpgsm_assuan_simple_command (gpgsm,
1688                                (mode & GPGME_KEYLIST_MODE_WITH_SECRET)?
1689                                "OPTION with-secret=1":
1690                                "OPTION with-secret=0" ,
1691                                NULL, NULL);
1692   gpgsm_assuan_simple_command (gpgsm,
1693                                (engine_flags & GPGME_ENGINE_FLAG_OFFLINE)?
1694                                "OPTION offline=1":
1695                                "OPTION offline=0" ,
1696                                NULL, NULL);
1697
1698   if (pattern && *pattern)
1699     {
1700       const char **pat = pattern;
1701
1702       while (*pat)
1703         {
1704           const char *patlet = *pat;
1705
1706           while (*patlet)
1707             {
1708               length++;
1709               if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1710                 length += 2;
1711               patlet++;
1712             }
1713           pat++;
1714           length++;
1715         }
1716     }
1717   line = malloc (length);
1718   if (!line)
1719     return gpg_error_from_syserror ();
1720   if (secret_only)
1721     {
1722       strcpy (line, "LISTSECRETKEYS ");
1723       linep = &line[15];
1724     }
1725   else
1726     {
1727       strcpy (line, "LISTKEYS ");
1728       linep = &line[9];
1729     }
1730
1731   if (pattern && *pattern)
1732     {
1733       while (*pattern)
1734         {
1735           const char *patlet = *pattern;
1736
1737           while (*patlet)
1738             {
1739               switch (*patlet)
1740                 {
1741                 case '%':
1742                   *(linep++) = '%';
1743                   *(linep++) = '2';
1744                   *(linep++) = '5';
1745                   break;
1746                 case ' ':
1747                   *(linep++) = '%';
1748                   *(linep++) = '2';
1749                   *(linep++) = '0';
1750                   break;
1751                 case '+':
1752                   *(linep++) = '%';
1753                   *(linep++) = '2';
1754                   *(linep++) = 'B';
1755                   break;
1756                 default:
1757                   *(linep++) = *patlet;
1758                   break;
1759                 }
1760               patlet++;
1761             }
1762           any_pattern = 1;
1763           *linep++ = ' ';
1764           pattern++;
1765         }
1766     }
1767   if (any_pattern)
1768     linep--;
1769   *linep = '\0';
1770
1771   gpgsm_clear_fd (gpgsm, INPUT_FD);
1772   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1773   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1774   gpgsm->inline_data = NULL;
1775
1776   err = start (gpgsm, line);
1777   free (line);
1778   return err;
1779 }
1780
1781
1782 static gpgme_error_t
1783 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1784             gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1785             int include_certs, gpgme_ctx_t ctx /* FIXME */)
1786 {
1787   engine_gpgsm_t gpgsm = engine;
1788   gpgme_error_t err;
1789   char *assuan_cmd;
1790   int i;
1791   gpgme_key_t key;
1792
1793   if (!gpgsm)
1794     return gpg_error (GPG_ERR_INV_VALUE);
1795
1796   /* FIXME: This does not work as RESET does not reset it so we can't
1797      revert back to default.  */
1798   if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1799     {
1800       /* FIXME: Make sure that if we run multiple operations, that we
1801          can reset any previously set value in case the default is
1802          requested.  */
1803
1804       if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
1805         return gpg_error_from_syserror ();
1806       err = gpgsm_assuan_simple_command (gpgsm, assuan_cmd, NULL, NULL);
1807       free (assuan_cmd);
1808       if (err)
1809         return err;
1810     }
1811
1812   for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1813     {
1814       const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1815       if (s && strlen (s) < 80)
1816         {
1817           char buf[100];
1818
1819           strcpy (stpcpy (buf, "SIGNER "), s);
1820           err = gpgsm_assuan_simple_command (gpgsm, buf,
1821                                              gpgsm->status.fnc,
1822                                              gpgsm->status.fnc_value);
1823         }
1824       else
1825         err = gpg_error (GPG_ERR_INV_VALUE);
1826       gpgme_key_unref (key);
1827       if (err)
1828         return err;
1829     }
1830
1831   gpgsm->input_cb.data = in;
1832   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1833   if (err)
1834     return err;
1835   gpgsm->output_cb.data = out;
1836   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1837                       : map_data_enc (gpgsm->output_cb.data));
1838   if (err)
1839     return err;
1840   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1841   gpgsm->inline_data = NULL;
1842
1843   err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1844                ? "SIGN --detached" : "SIGN");
1845   return err;
1846 }
1847
1848
1849 static gpgme_error_t
1850 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1851               gpgme_data_t plaintext)
1852 {
1853   engine_gpgsm_t gpgsm = engine;
1854   gpgme_error_t err;
1855
1856   if (!gpgsm)
1857     return gpg_error (GPG_ERR_INV_VALUE);
1858
1859   gpgsm->input_cb.data = sig;
1860   err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1861   if (err)
1862     return err;
1863   if (plaintext)
1864     {
1865       /* Normal or cleartext signature.  */
1866       gpgsm->output_cb.data = plaintext;
1867       err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1868       gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1869     }
1870   else
1871     {
1872       /* Detached signature.  */
1873       gpgsm->message_cb.data = signed_text;
1874       err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1875       gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1876     }
1877   gpgsm->inline_data = NULL;
1878
1879   if (!err)
1880     err = start (gpgsm, "VERIFY");
1881
1882   return err;
1883 }
1884
1885
1886 /* Send the GETAUDITLOG command.  The result is saved to a gpgme data
1887    object.  */
1888 static gpgme_error_t
1889 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1890 {
1891   engine_gpgsm_t gpgsm = engine;
1892   gpgme_error_t err = 0;
1893
1894   if (!gpgsm || !output)
1895     return gpg_error (GPG_ERR_INV_VALUE);
1896
1897 #if USE_DESCRIPTOR_PASSING
1898   gpgsm->output_cb.data = output;
1899   err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1900   if (err)
1901     return err;
1902
1903   gpgsm_clear_fd (gpgsm, INPUT_FD);
1904   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1905   gpgsm->inline_data = NULL;
1906 # define CMD  "GETAUDITLOG"
1907 #else
1908   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1909   gpgsm_clear_fd (gpgsm, INPUT_FD);
1910   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1911   gpgsm->inline_data = output;
1912 # define CMD  "GETAUDITLOG --data"
1913 #endif
1914
1915   err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1916
1917   return err;
1918 }
1919
1920
1921 /* This sets a status callback for monitoring status lines before they
1922  * are passed to a caller set handler.  */
1923 static void
1924 gpgsm_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
1925 {
1926   engine_gpgsm_t gpgsm = engine;
1927
1928   gpgsm->status.mon_cb = cb;
1929   gpgsm->status.mon_cb_value = cb_value;
1930 }
1931
1932
1933 static void
1934 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
1935                           void *fnc_value)
1936 {
1937   engine_gpgsm_t gpgsm = engine;
1938
1939   gpgsm->status.fnc = fnc;
1940   gpgsm->status.fnc_value = fnc_value;
1941 }
1942
1943
1944 static gpgme_error_t
1945 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
1946                               void *fnc_value)
1947 {
1948   engine_gpgsm_t gpgsm = engine;
1949
1950   gpgsm->colon.fnc = fnc;
1951   gpgsm->colon.fnc_value = fnc_value;
1952   gpgsm->colon.any = 0;
1953   return 0;
1954 }
1955
1956
1957 static void
1958 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1959 {
1960   engine_gpgsm_t gpgsm = engine;
1961   gpgsm->io_cbs = *io_cbs;
1962 }
1963
1964
1965 static void
1966 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
1967 {
1968   engine_gpgsm_t gpgsm = engine;
1969
1970   TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
1971           "event %p, type %d, type_data %p",
1972           gpgsm->io_cbs.event, type, type_data);
1973   if (gpgsm->io_cbs.event)
1974     (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
1975 }
1976
1977
1978 static gpgme_error_t
1979 gpgsm_passwd (void *engine, gpgme_key_t key, unsigned int flags)
1980 {
1981   engine_gpgsm_t gpgsm = engine;
1982   gpgme_error_t err;
1983   char *line;
1984
1985   if (!key || !key->subkeys || !key->subkeys->fpr)
1986     return gpg_error (GPG_ERR_INV_CERT_OBJ);
1987
1988   if (asprintf (&line, "PASSWD -- %s", key->subkeys->fpr) < 0)
1989     return gpg_error_from_syserror ();
1990
1991   gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1992   gpgsm_clear_fd (gpgsm, INPUT_FD);
1993   gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1994   gpgsm->inline_data = NULL;
1995
1996   err = start (gpgsm, line);
1997   free (line);
1998
1999   return err;
2000 }
2001
2002
2003
2004 struct engine_ops _gpgme_engine_ops_gpgsm =
2005   {
2006     /* Static functions.  */
2007     _gpgme_get_default_gpgsm_name,
2008     NULL,
2009     gpgsm_get_version,
2010     gpgsm_get_req_version,
2011     gpgsm_new,
2012
2013     /* Member functions.  */
2014     gpgsm_release,
2015 #if USE_DESCRIPTOR_PASSING
2016     gpgsm_reset,
2017 #else
2018     NULL,                       /* reset */
2019 #endif
2020     gpgsm_set_status_cb,
2021     gpgsm_set_status_handler,
2022     NULL,               /* set_command_handler */
2023     gpgsm_set_colon_line_handler,
2024     gpgsm_set_locale,
2025     NULL,               /* set_protocol */
2026     gpgsm_decrypt,
2027     gpgsm_decrypt,
2028     gpgsm_delete,       /* decrypt_verify */
2029     NULL,               /* edit */
2030     gpgsm_encrypt,
2031     NULL,               /* encrypt_sign */
2032     gpgsm_export,
2033     gpgsm_export_ext,
2034     gpgsm_genkey,
2035     gpgsm_import,
2036     gpgsm_keylist,
2037     gpgsm_keylist_ext,
2038     gpgsm_sign,
2039     NULL,               /* trustlist */
2040     gpgsm_verify,
2041     gpgsm_getauditlog,
2042     NULL,               /* opassuan_transact */
2043     NULL,               /* conf_load */
2044     NULL,               /* conf_save */
2045     gpgsm_set_io_cbs,
2046     gpgsm_io_event,
2047     gpgsm_cancel,
2048     NULL,               /* cancel_op */
2049     gpgsm_passwd,
2050     NULL,               /* set_pinentry_mode */
2051     NULL                /* opspawn */
2052   };