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