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