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