1 /* engine-gpgsm.c - GpgSM engine.
2 Copyright (C) 2000 Werner Koch (dd9jn)
3 Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007 g10 Code GmbH
5 This file is part of GPGME.
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.
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.
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
28 #include <sys/types.h>
32 #include <fcntl.h> /* FIXME */
43 #include "status-table.h"
46 #include "engine-backend.h"
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. */
64 assuan_context_t assuan_ctx;
69 iocb_data_t status_cb;
71 /* Input, output etc are from the servers perspective. */
74 iocb_data_t output_cb;
76 iocb_data_t message_cb;
80 engine_status_handler_t fnc;
86 engine_colon_line_handler_t fnc;
94 int any; /* any data line seen */
97 gpgme_data_t inline_data; /* Used to collect D lines. */
99 struct gpgme_io_cbs io_cbs;
102 typedef struct engine_gpgsm *engine_gpgsm_t;
105 static void gpgsm_io_event (void *engine,
106 gpgme_event_io_t type, void *type_data);
111 gpgsm_get_version (const char *file_name)
113 return _gpgme_get_program_version (file_name ? file_name
114 : _gpgme_get_gpgsm_path ());
119 gpgsm_get_req_version (void)
121 return NEED_GPGSM_VERSION;
126 close_notify_handler (int fd, void *opaque)
128 engine_gpgsm_t gpgsm = opaque;
131 if (gpgsm->status_cb.fd == fd)
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;
138 else if (gpgsm->input_cb.fd == fd)
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;
145 else if (gpgsm->output_cb.fd == fd)
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;
152 else if (gpgsm->message_cb.fd == fd)
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;
163 map_assuan_error (gpg_error_t err)
169 return gpg_error (GPG_ERR_INV_ENGINE);
171 /* New code will use gpg_error_t values. */
172 if (gpg_err_source (err))
173 return (gpgme_error_t) err;
175 /* Legacy code will use old values. */
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);
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);
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);
218 case ASSUAN_Invalid_Response:
219 return gpg_error (GPG_ERR_INV_RESPONSE);
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);
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);
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);
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);
283 return gpg_error (GPG_ERR_GENERAL);
288 /* This is the default inquiry callback. We use it to handle the
289 Pinentry notifications. */
291 default_inq_cb (engine_gpgsm_t gpgsm, const char *line)
293 if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
295 _gpgme_allow_set_foregound_window ((pid_t)strtoul (line+17, NULL, 10));
303 gpgsm_cancel (void *engine)
305 engine_gpgsm_t gpgsm = engine;
308 return gpg_error (GPG_ERR_INV_VALUE);
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);
319 if (gpgsm->assuan_ctx)
321 assuan_disconnect (gpgsm->assuan_ctx);
322 gpgsm->assuan_ctx = NULL;
330 gpgsm_release (void *engine)
332 engine_gpgsm_t gpgsm = engine;
337 gpgsm_cancel (engine);
339 free (gpgsm->colon.attic.line);
345 gpgsm_new (void **engine, const char *file_name, const char *home_dir)
347 gpgme_error_t err = 0;
348 engine_gpgsm_t gpgsm;
351 #if !USE_DESCRIPTOR_PASSING
355 char *dft_display = NULL;
356 char dft_ttyname[64];
357 char *dft_ttytype = NULL;
360 gpgsm = calloc (1, sizeof *gpgsm);
362 return gpg_error_from_errno (errno);
364 gpgsm->status_cb.fd = -1;
365 gpgsm->status_cb.dir = 1;
366 gpgsm->status_cb.tag = 0;
367 gpgsm->status_cb.data = gpgsm;
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;
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;
392 gpgsm->inline_data = NULL;
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;
400 #if !USE_DESCRIPTOR_PASSING
401 if (_gpgme_io_pipe (fds, 0) < 0)
403 err = gpg_error_from_errno (errno);
406 gpgsm->input_cb.fd = fds[1];
407 gpgsm->input_cb.server_fd = fds[0];
409 if (_gpgme_io_pipe (fds, 1) < 0)
411 err = gpg_error_from_errno (errno);
414 gpgsm->output_cb.fd = fds[0];
415 gpgsm->output_cb.server_fd = fds[1];
417 if (_gpgme_io_pipe (fds, 0) < 0)
419 err = gpg_error_from_errno (errno);
422 gpgsm->message_cb.fd = fds[1];
423 gpgsm->message_cb.server_fd = fds[0];
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;
432 argv[argc++] = "gpgsm";
435 argv[argc++] = "--homedir";
436 argv[argc++] = home_dir;
438 argv[argc++] = "--server";
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);
446 err = assuan_pipe_connect
447 (&gpgsm->assuan_ctx, file_name ? file_name : _gpgme_get_gpgsm_path (),
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. */
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
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]);
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;
478 err = _gpgme_getenv ("DISPLAY", &dft_display);
483 if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
486 err = gpg_error_from_errno (errno);
491 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
496 err = map_assuan_error (err);
505 rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
508 err = gpg_error_from_errno (rc);
513 if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
515 err = gpg_error_from_errno (errno);
518 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL, NULL,
523 err = map_assuan_error (err);
527 err = _gpgme_getenv ("TERM", &dft_ttytype);
532 if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
535 err = gpg_error_from_errno (errno);
540 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
541 NULL, NULL, NULL, NULL);
545 err = map_assuan_error (err);
552 /* Ask gpgsm to enable the audit log support. */
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. */
562 #ifdef HAVE_W32_SYSTEM
563 /* Under Windows we need to use AllowSetForegroundWindow. Tell
564 gpgsm to tell us when it needs it. */
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. */
572 #endif /*HAVE_W32_SYSTEM*/
574 #if !USE_DESCRIPTOR_PASSING
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)))
583 err = gpg_error (GPG_ERR_GENERAL);
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);
602 gpgsm_release (gpgsm);
611 gpgsm_set_locale (void *engine, int category, const char *value)
613 engine_gpgsm_t gpgsm = engine;
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
621 if (category == LC_CTYPE)
624 if (!value && gpgsm->lc_ctype_set)
625 return gpg_error (GPG_ERR_INV_VALUE);
627 gpgsm->lc_ctype_set = 1;
630 else if (category == LC_MESSAGES)
632 catstr = "lc-messages";
633 if (!value && gpgsm->lc_messages_set)
634 return gpg_error (GPG_ERR_INV_VALUE);
636 gpgsm->lc_messages_set = 1;
638 #endif /* LC_MESSAGES */
640 return gpg_error (GPG_ERR_INV_VALUE);
642 /* FIXME: Reset value to default. */
646 if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
647 err = gpg_error_from_errno (errno);
650 err = assuan_transact (gpgsm->assuan_ctx, optstr, NULL, NULL,
651 NULL, NULL, NULL, NULL);
654 err = map_assuan_error (err);
661 /* Forward declaration. */
662 static gpgme_status_code_t parse_status (const char *name);
665 gpgsm_assuan_simple_command (assuan_context_t ctx, char *cmd,
666 engine_status_handler_t status_fnc,
667 void *status_fnc_value)
673 err = assuan_write_line (ctx, cmd);
675 return map_assuan_error (err);
679 err = assuan_read_line (ctx, &line, &linelen);
681 return map_assuan_error (err);
683 if (*line == '#' || !linelen)
687 && line[0] == 'O' && line[1] == 'K'
688 && (line[2] == '\0' || line[2] == ' '))
690 else if (linelen >= 4
691 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
693 err = map_assuan_error (atoi (&line[4]));
694 else if (linelen >= 2
695 && line[0] == 'S' && line[1] == ' ')
698 gpgme_status_code_t r;
700 rest = strchr (line + 2, ' ');
702 rest = line + linelen; /* set to an empty string */
706 r = parse_status (line + 2);
708 if (r >= 0 && status_fnc)
709 err = status_fnc (status_fnc_value, r, rest);
711 err = gpg_error (GPG_ERR_GENERAL);
714 err = gpg_error (GPG_ERR_GENERAL);
722 typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
725 gpgsm_clear_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type)
727 #if !USE_DESCRIPTOR_PASSING
731 _gpgme_io_close (gpgsm->input_cb.fd);
734 _gpgme_io_close (gpgsm->output_cb.fd);
737 _gpgme_io_close (gpgsm->message_cb.fd);
743 #define COMMANDLINELEN 40
745 gpgsm_set_fd (engine_gpgsm_t gpgsm, fd_type_t fd_type, const char *opt)
748 char line[COMMANDLINELEN];
750 iocb_data_t *iocb_data;
757 iocb_data = &gpgsm->input_cb;
762 iocb_data = &gpgsm->output_cb;
767 iocb_data = &gpgsm->message_cb;
771 return gpg_error (GPG_ERR_INV_VALUE);
774 dir = iocb_data->dir;
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)
784 if (_gpgme_io_pipe (fds, 0) < 0)
785 return gpg_error_from_errno (errno);
787 iocb_data->fd = dir ? fds[0] : fds[1];
788 iocb_data->server_fd = dir ? fds[1] : fds[0];
790 if (_gpgme_io_set_close_notify (iocb_data->fd,
791 close_notify_handler, gpgsm))
793 err = gpg_error (GPG_ERR_GENERAL);
798 err = assuan_sendfd (gpgsm->assuan_ctx, iocb_data->server_fd);
802 _gpgme_io_close (iocb_data->server_fd);
803 iocb_data->server_fd = -1;
806 snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
808 snprintf (line, COMMANDLINELEN, "%s FD", which);
811 snprintf (line, COMMANDLINELEN, "%s FD=%s %s",
812 which, iocb_data->server_fd_str, opt);
814 snprintf (line, COMMANDLINELEN, "%s FD=%s",
815 which, iocb_data->server_fd_str);
818 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
820 #if USE_DESCRIPTOR_PASSING
824 _gpgme_io_close (iocb_data->fd);
826 if (iocb_data->server_fd != -1)
828 _gpgme_io_close (iocb_data->server_fd);
829 iocb_data->server_fd = -1;
839 map_data_enc (gpgme_data_t d)
841 switch (gpgme_data_get_encoding (d))
843 case GPGME_DATA_ENCODING_NONE:
845 case GPGME_DATA_ENCODING_BINARY:
847 case GPGME_DATA_ENCODING_BASE64:
849 case GPGME_DATA_ENCODING_ARMOR:
859 status_cmp (const void *ap, const void *bp)
861 const struct status_table_s *a = ap;
862 const struct status_table_s *b = bp;
864 return strcmp (a->name, b->name);
868 static gpgme_status_code_t
869 parse_status (const char *name)
871 struct status_table_s t, *r;
873 r = bsearch (&t, status_table, DIM(status_table) - 1,
874 sizeof t, status_cmp);
875 return r ? r->code : -1;
880 status_handler (void *opaque, int fd)
882 gpg_error_t assuan_err;
883 gpgme_error_t err = 0;
884 engine_gpgsm_t gpgsm = opaque;
890 assuan_err = assuan_read_line (gpgsm->assuan_ctx, &line, &linelen);
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));
900 else if (linelen >= 3
901 && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
902 && (line[3] == '\0' || line[3] == ' '))
905 err = map_assuan_error (atoi (&line[4]));
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"); */
914 else if (linelen >= 2
915 && line[0] == 'O' && line[1] == 'K'
916 && (line[2] == '\0' || line[2] == ' '))
918 if (gpgsm->status.fnc)
919 err = gpgsm->status.fnc (gpgsm->status.fnc_value,
920 GPGME_STATUS_EOF, "");
922 if (!err && gpgsm->colon.fnc && gpgsm->colon.any )
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
929 gpgsm->colon.any = 0;
930 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, NULL);
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);
939 && line[0] == 'D' && line[1] == ' '
942 /* We are using the colon handler even for plain inline data
943 - strange name for that function but for historic reasons
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;
951 char **aline = &gpgsm->colon.attic.line;
952 int *alinelen = &gpgsm->colon.attic.linelen;
954 if (gpgsm->colon.attic.linesize < *alinelen + linelen + 1)
956 char *newline = realloc (*aline, *alinelen + linelen + 1);
958 err = gpg_error_from_errno (errno);
962 gpgsm->colon.attic.linesize += linelen + 1;
967 dst = *aline + *alinelen;
969 while (!err && src < end)
971 if (*src == '%' && src + 2 < end)
973 /* Handle escaped characters. */
975 *dst = _gpgme_hextobyte (src);
987 /* Terminate the pending line, pass it to the colon
988 handler and reset it. */
990 gpgsm->colon.any = 1;
991 if (*alinelen > 1 && *(dst - 1) == '\r')
995 /* FIXME How should we handle the return code? */
996 err = gpgsm->colon.fnc (gpgsm->colon.fnc_value, *aline);
1007 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
1008 "fd 0x%x: D line; final status: %s",
1009 fd, err? gpg_strerror (err):"ok");
1011 else if (linelen > 2
1012 && line[0] == 'D' && line[1] == ' '
1013 && gpgsm->inline_data)
1015 char *src = line + 2;
1016 char *end = line + linelen;
1023 if (*src == '%' && src + 2 < end)
1025 /* Handle escaped characters. */
1027 *dst++ = _gpgme_hextobyte (src);
1039 nwritten = gpgme_data_write (gpgsm->inline_data, src, linelen);
1040 if (!nwritten || (nwritten < 0 && errno != EINTR)
1041 || nwritten > linelen)
1043 err = gpg_error_from_errno (errno);
1047 linelen -= nwritten;
1050 TRACE2 (DEBUG_CTX, "gpgme:status_handler", gpgsm,
1051 "fd 0x%x: D inlinedata; final status: %s",
1052 fd, err? gpg_strerror (err):"ok");
1054 else if (linelen > 2
1055 && line[0] == 'S' && line[1] == ' ')
1058 gpgme_status_code_t r;
1060 rest = strchr (line + 2, ' ');
1062 rest = line + linelen; /* set to an empty string */
1066 r = parse_status (line + 2);
1070 if (gpgsm->status.fnc)
1071 err = gpgsm->status.fnc (gpgsm->status.fnc_value, r, rest);
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");
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'
1083 && (line[7] == '\0' || line[7] == ' '))
1085 char *keyword = line+7;
1087 while (*keyword == ' ')
1089 default_inq_cb (gpgsm, keyword);
1090 assuan_write_line (gpgsm->assuan_ctx, "END");
1094 while (!err && assuan_pending_line (gpgsm->assuan_ctx));
1100 static gpgme_error_t
1101 add_io_cb (engine_gpgsm_t gpgsm, iocb_data_t *iocbd, gpgme_io_cb_t handler)
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);
1111 return TRACE_ERR (err);
1113 /* FIXME Kludge around poll() problem. */
1114 err = _gpgme_io_set_nonblocking (iocbd->fd);
1115 return TRACE_ERR (err);
1119 static gpgme_error_t
1120 start (engine_gpgsm_t gpgsm, const char *command)
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));
1132 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
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. */
1144 gpgsm->status_cb.fd = _gpgme_io_dup (fdlist[0]);
1145 if (gpgsm->status_cb.fd < 0)
1146 return gpg_error_from_syserror ();
1148 if (_gpgme_io_set_close_notify (gpgsm->status_cb.fd,
1149 close_notify_handler, gpgsm))
1151 _gpgme_io_close (gpgsm->status_cb.fd);
1152 gpgsm->status_cb.fd = -1;
1153 return gpg_error (GPG_ERR_GENERAL);
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);
1165 err = map_assuan_error (assuan_write_line (gpgsm->assuan_ctx, command));
1168 gpgsm_io_event (gpgsm, GPGME_EVENT_START, NULL);
1174 #if USE_DESCRIPTOR_PASSING
1175 static gpgme_error_t
1176 gpgsm_reset (void *engine)
1178 engine_gpgsm_t gpgsm = engine;
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);
1187 static gpgme_error_t
1188 gpgsm_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
1190 engine_gpgsm_t gpgsm = engine;
1194 return gpg_error (GPG_ERR_INV_VALUE);
1196 gpgsm->input_cb.data = ciph;
1197 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1199 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1200 gpgsm->output_cb.data = plain;
1201 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1203 return gpg_error (GPG_ERR_GENERAL); /* FIXME */
1204 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1205 gpgsm->inline_data = NULL;
1207 err = start (engine, "DECRYPT");
1212 static gpgme_error_t
1213 gpgsm_delete (void *engine, gpgme_key_t key, int allow_secret)
1215 engine_gpgsm_t gpgsm = engine;
1217 char *fpr = key->subkeys ? key->subkeys->fpr : NULL;
1220 int length = 8; /* "DELKEYS " */
1223 return gpg_error (GPG_ERR_INV_VALUE);
1228 if (*linep == '%' || *linep == ' ' || *linep == '+')
1234 line = malloc (length);
1236 return gpg_error_from_errno (errno);
1238 strcpy (line, "DELKEYS ");
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;
1273 err = start (gpgsm, line);
1280 static gpgme_error_t
1281 set_recipients (engine_gpgsm_t gpgsm, gpgme_key_t recp[])
1283 gpgme_error_t err = 0;
1284 assuan_context_t ctx = gpgsm->assuan_ctx;
1287 int invalid_recipients = 0;
1290 linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */
1291 line = malloc (10 + 40 + 1);
1293 return gpg_error_from_errno (errno);
1294 strcpy (line, "RECIPIENT ");
1295 while (!err && recp[i])
1300 if (!recp[i]->subkeys || !recp[i]->subkeys->fpr)
1302 invalid_recipients++;
1305 fpr = recp[i]->subkeys->fpr;
1307 newlen = 11 + strlen (fpr);
1308 if (linelen < newlen)
1310 char *newline = realloc (line, newlen);
1313 int saved_errno = errno;
1315 return gpg_error_from_errno (saved_errno);
1320 strcpy (&line[10], fpr);
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++;
1335 return gpg_error (invalid_recipients
1336 ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
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)
1344 engine_gpgsm_t gpgsm = engine;
1348 return gpg_error (GPG_ERR_INV_VALUE);
1350 return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
1352 gpgsm->input_cb.data = plain;
1353 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1356 gpgsm->output_cb.data = ciph;
1357 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1358 : map_data_enc (gpgsm->output_cb.data));
1361 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1362 gpgsm->inline_data = NULL;
1364 err = set_recipients (gpgsm, recp);
1367 err = start (gpgsm, "ENCRYPT");
1373 static gpgme_error_t
1374 gpgsm_export (void *engine, const char *pattern, unsigned int reserved,
1375 gpgme_data_t keydata, int use_armor)
1377 engine_gpgsm_t gpgsm = engine;
1378 gpgme_error_t err = 0;
1381 if (!gpgsm || reserved)
1382 return gpg_error (GPG_ERR_INV_VALUE);
1387 cmd = malloc (7 + strlen (pattern) + 1);
1389 return gpg_error_from_errno (errno);
1390 strcpy (cmd, "EXPORT ");
1391 strcpy (&cmd[7], pattern);
1393 gpgsm->output_cb.data = keydata;
1394 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1395 : map_data_enc (gpgsm->output_cb.data));
1398 gpgsm_clear_fd (gpgsm, INPUT_FD);
1399 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1400 gpgsm->inline_data = NULL;
1402 err = start (gpgsm, cmd);
1408 static gpgme_error_t
1409 gpgsm_export_ext (void *engine, const char *pattern[], unsigned int reserved,
1410 gpgme_data_t keydata, int use_armor)
1412 engine_gpgsm_t gpgsm = engine;
1413 gpgme_error_t err = 0;
1415 /* Length is "EXPORT " + p + '\0'. */
1419 if (!gpgsm || reserved)
1420 return gpg_error (GPG_ERR_INV_VALUE);
1422 if (pattern && *pattern)
1424 const char **pat = pattern;
1428 const char *patlet = *pat;
1433 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1441 line = malloc (length);
1443 return gpg_error_from_errno (errno);
1445 strcpy (line, "EXPORT ");
1448 if (pattern && *pattern)
1452 const char *patlet = *pattern;
1474 *(linep++) = *patlet;
1486 gpgsm->output_cb.data = keydata;
1487 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1488 : map_data_enc (gpgsm->output_cb.data));
1491 gpgsm_clear_fd (gpgsm, INPUT_FD);
1492 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1493 gpgsm->inline_data = NULL;
1495 err = start (gpgsm, line);
1501 static gpgme_error_t
1502 gpgsm_genkey (void *engine, gpgme_data_t help_data, int use_armor,
1503 gpgme_data_t pubkey, gpgme_data_t seckey)
1505 engine_gpgsm_t gpgsm = engine;
1508 if (!gpgsm || !pubkey || seckey)
1509 return gpg_error (GPG_ERR_INV_VALUE);
1511 gpgsm->input_cb.data = help_data;
1512 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1515 gpgsm->output_cb.data = pubkey;
1516 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1517 : map_data_enc (gpgsm->output_cb.data));
1520 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1521 gpgsm->inline_data = NULL;
1523 err = start (gpgsm, "GENKEY");
1528 static gpgme_error_t
1529 gpgsm_import (void *engine, gpgme_data_t keydata)
1531 engine_gpgsm_t gpgsm = engine;
1535 return gpg_error (GPG_ERR_INV_VALUE);
1537 gpgsm->input_cb.data = keydata;
1538 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1541 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1542 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1543 gpgsm->inline_data = NULL;
1545 err = start (gpgsm, "IMPORT");
1550 static gpgme_error_t
1551 gpgsm_keylist (void *engine, const char *pattern, int secret_only,
1552 gpgme_keylist_mode_t mode)
1554 engine_gpgsm_t gpgsm = engine;
1559 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1561 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1567 /* Always send list-mode option because RESET does not reset it. */
1568 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1569 return gpg_error_from_errno (errno);
1570 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1576 /* Always send key validation because RESET does not reset it. */
1578 /* Use the validation mode if required. We don't check for an error
1579 yet because this is a pretty fresh gpgsm features. */
1580 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1581 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1582 "OPTION with-validation=1":
1583 "OPTION with-validation=0" ,
1587 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1588 line = malloc (15 + strlen (pattern) + 1);
1590 return gpg_error_from_errno (errno);
1593 strcpy (line, "LISTSECRETKEYS ");
1594 strcpy (&line[15], pattern);
1598 strcpy (line, "LISTKEYS ");
1599 strcpy (&line[9], pattern);
1602 gpgsm_clear_fd (gpgsm, INPUT_FD);
1603 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1604 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1605 gpgsm->inline_data = NULL;
1607 err = start (gpgsm, line);
1613 static gpgme_error_t
1614 gpgsm_keylist_ext (void *engine, const char *pattern[], int secret_only,
1615 int reserved, gpgme_keylist_mode_t mode)
1617 engine_gpgsm_t gpgsm = engine;
1620 /* Length is "LISTSECRETKEYS " + p + '\0'. */
1621 int length = 15 + 1;
1623 int any_pattern = 0;
1627 return gpg_error (GPG_ERR_INV_VALUE);
1629 if (mode & GPGME_KEYLIST_MODE_LOCAL)
1631 if (mode & GPGME_KEYLIST_MODE_EXTERN)
1634 /* Always send list-mode option because RESET does not reset it. */
1635 if (asprintf (&line, "OPTION list-mode=%d", (list_mode & 3)) < 0)
1636 return gpg_error_from_errno (errno);
1637 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, line, NULL, NULL);
1642 /* Always send key validation because RESET does not reset it. */
1643 /* Use the validation mode if required. We don't check for an error
1644 yet because this is a pretty fresh gpgsm features. */
1645 gpgsm_assuan_simple_command (gpgsm->assuan_ctx,
1646 (mode & GPGME_KEYLIST_MODE_VALIDATE)?
1647 "OPTION with-validation=1":
1648 "OPTION with-validation=0" ,
1652 if (pattern && *pattern)
1654 const char **pat = pattern;
1658 const char *patlet = *pat;
1663 if (*patlet == '%' || *patlet == ' ' || *patlet == '+')
1671 line = malloc (length);
1673 return gpg_error_from_errno (errno);
1676 strcpy (line, "LISTSECRETKEYS ");
1681 strcpy (line, "LISTKEYS ");
1685 if (pattern && *pattern)
1689 const char *patlet = *pattern;
1711 *(linep++) = *patlet;
1725 gpgsm_clear_fd (gpgsm, INPUT_FD);
1726 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1727 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1728 gpgsm->inline_data = NULL;
1730 err = start (gpgsm, line);
1736 static gpgme_error_t
1737 gpgsm_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1738 gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1739 int include_certs, gpgme_ctx_t ctx /* FIXME */)
1741 engine_gpgsm_t gpgsm = engine;
1748 return gpg_error (GPG_ERR_INV_VALUE);
1750 /* FIXME: This does not work as RESET does not reset it so we can't
1751 revert back to default. */
1752 if (include_certs != GPGME_INCLUDE_CERTS_DEFAULT)
1754 /* FIXME: Make sure that if we run multiple operations, that we
1755 can reset any previously set value in case the default is
1758 if (asprintf (&assuan_cmd, "OPTION include-certs %i", include_certs) < 0)
1759 return gpg_error_from_errno (errno);
1760 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, assuan_cmd,
1767 for (i = 0; (key = gpgme_signers_enum (ctx, i)); i++)
1769 const char *s = key->subkeys ? key->subkeys->fpr : NULL;
1770 if (s && strlen (s) < 80)
1774 strcpy (stpcpy (buf, "SIGNER "), s);
1775 err = gpgsm_assuan_simple_command (gpgsm->assuan_ctx, buf,
1779 err = gpg_error (GPG_ERR_INV_VALUE);
1780 gpgme_key_unref (key);
1785 gpgsm->input_cb.data = in;
1786 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1789 gpgsm->output_cb.data = out;
1790 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, use_armor ? "--armor"
1791 : map_data_enc (gpgsm->output_cb.data));
1794 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1795 gpgsm->inline_data = NULL;
1797 err = start (gpgsm, mode == GPGME_SIG_MODE_DETACH
1798 ? "SIGN --detached" : "SIGN");
1803 static gpgme_error_t
1804 gpgsm_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1805 gpgme_data_t plaintext)
1807 engine_gpgsm_t gpgsm = engine;
1811 return gpg_error (GPG_ERR_INV_VALUE);
1813 gpgsm->input_cb.data = sig;
1814 err = gpgsm_set_fd (gpgsm, INPUT_FD, map_data_enc (gpgsm->input_cb.data));
1819 /* Normal or cleartext signature. */
1820 gpgsm->output_cb.data = plaintext;
1821 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1822 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1826 /* Detached signature. */
1827 gpgsm->message_cb.data = signed_text;
1828 err = gpgsm_set_fd (gpgsm, MESSAGE_FD, 0);
1829 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1831 gpgsm->inline_data = NULL;
1834 err = start (gpgsm, "VERIFY");
1840 /* Send the GETAUDITLOG command. The result is saved to a gpgme data
1842 static gpgme_error_t
1843 gpgsm_getauditlog (void *engine, gpgme_data_t output, unsigned int flags)
1845 engine_gpgsm_t gpgsm = engine;
1846 gpgme_error_t err = 0;
1848 if (!gpgsm || !output)
1849 return gpg_error (GPG_ERR_INV_VALUE);
1851 #if USE_DESCRIPTOR_PASSING
1852 gpgsm->output_cb.data = output;
1853 err = gpgsm_set_fd (gpgsm, OUTPUT_FD, 0);
1857 gpgsm_clear_fd (gpgsm, INPUT_FD);
1858 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1859 gpgsm->inline_data = NULL;
1860 # define CMD "GETAUDITLOG"
1862 gpgsm_clear_fd (gpgsm, OUTPUT_FD);
1863 gpgsm_clear_fd (gpgsm, INPUT_FD);
1864 gpgsm_clear_fd (gpgsm, MESSAGE_FD);
1865 gpgsm->inline_data = output;
1866 # define CMD "GETAUDITLOG --data"
1869 err = start (gpgsm, (flags & GPGME_AUDITLOG_HTML)? CMD " --html" : CMD);
1877 gpgsm_set_status_handler (void *engine, engine_status_handler_t fnc,
1880 engine_gpgsm_t gpgsm = engine;
1882 gpgsm->status.fnc = fnc;
1883 gpgsm->status.fnc_value = fnc_value;
1887 static gpgme_error_t
1888 gpgsm_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
1891 engine_gpgsm_t gpgsm = engine;
1893 gpgsm->colon.fnc = fnc;
1894 gpgsm->colon.fnc_value = fnc_value;
1895 gpgsm->colon.any = 0;
1901 gpgsm_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1903 engine_gpgsm_t gpgsm = engine;
1904 gpgsm->io_cbs = *io_cbs;
1909 gpgsm_io_event (void *engine, gpgme_event_io_t type, void *type_data)
1911 engine_gpgsm_t gpgsm = engine;
1913 TRACE3 (DEBUG_ENGINE, "gpgme:gpgsm_io_event", gpgsm,
1914 "event %p, type %d, type_data %p",
1915 gpgsm->io_cbs.event, type, type_data);
1916 if (gpgsm->io_cbs.event)
1917 (*gpgsm->io_cbs.event) (gpgsm->io_cbs.event_priv, type, type_data);
1921 struct engine_ops _gpgme_engine_ops_gpgsm =
1923 /* Static functions. */
1924 _gpgme_get_gpgsm_path,
1926 gpgsm_get_req_version,
1929 /* Member functions. */
1931 #if USE_DESCRIPTOR_PASSING
1936 gpgsm_set_status_handler,
1937 NULL, /* set_command_handler */
1938 gpgsm_set_colon_line_handler,
1944 NULL, /* encrypt_sign */
1952 NULL, /* trustlist */
1955 NULL, /* conf_load */
1956 NULL, /* conf_save */