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