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