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