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