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