Line data Source code
1 : /* engine-uiserver.c - Uiserver engine.
2 : Copyright (C) 2000 Werner Koch (dd9jn)
3 : Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH
4 :
5 : This file is part of GPGME.
6 :
7 : GPGME is free software; you can redistribute it and/or modify it
8 : under the terms of the GNU Lesser General Public License as
9 : published by the Free Software Foundation; either version 2.1 of
10 : the License, or (at your option) any later version.
11 :
12 : GPGME is distributed in the hope that it will be useful, but
13 : WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : Lesser General Public License for more details.
16 :
17 : You should have received a copy of the GNU Lesser General Public
18 : License along with this program; if not, write to the Free Software
19 : Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 : 02111-1307, USA. */
21 :
22 : /* Peculiar: Use special keys from email address for recipient and
23 : signer (==sender). Use no data objects with encryption for
24 : prep_encrypt. */
25 :
26 : #if HAVE_CONFIG_H
27 : #include <config.h>
28 : #endif
29 :
30 : #include <stdlib.h>
31 : #include <string.h>
32 : #ifdef HAVE_SYS_TYPES_H
33 : # include <sys/types.h>
34 : #endif
35 : #include <assert.h>
36 : #ifdef HAVE_UNISTD_H
37 : # include <unistd.h>
38 : #endif
39 : #include <locale.h>
40 : #include <fcntl.h> /* FIXME */
41 : #include <errno.h>
42 :
43 : #include "gpgme.h"
44 : #include "util.h"
45 : #include "ops.h"
46 : #include "wait.h"
47 : #include "priv-io.h"
48 : #include "sema.h"
49 : #include "data.h"
50 :
51 : #include "assuan.h"
52 : #include "debug.h"
53 :
54 : #include "engine-backend.h"
55 :
56 :
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_uiserver
71 : {
72 : assuan_context_t assuan_ctx;
73 :
74 : int lc_ctype_set;
75 : int lc_messages_set;
76 : gpgme_protocol_t protocol;
77 :
78 : iocb_data_t status_cb;
79 :
80 : /* Input, output etc are from the servers perspective. */
81 : iocb_data_t input_cb;
82 : gpgme_data_t input_helper_data; /* Input helper data object. */
83 : void *input_helper_memory; /* Input helper memory block. */
84 :
85 : iocb_data_t output_cb;
86 :
87 : iocb_data_t message_cb;
88 :
89 : struct
90 : {
91 : engine_status_handler_t fnc;
92 : void *fnc_value;
93 : gpgme_status_cb_t mon_cb;
94 : void *mon_cb_value;
95 : } status;
96 :
97 : struct
98 : {
99 : engine_colon_line_handler_t fnc;
100 : void *fnc_value;
101 : struct
102 : {
103 : char *line;
104 : int linesize;
105 : int linelen;
106 : } attic;
107 : int any; /* any data line seen */
108 : } colon;
109 :
110 : gpgme_data_t inline_data; /* Used to collect D lines. */
111 :
112 : struct gpgme_io_cbs io_cbs;
113 : };
114 :
115 : typedef struct engine_uiserver *engine_uiserver_t;
116 :
117 :
118 : static void uiserver_io_event (void *engine,
119 : gpgme_event_io_t type, void *type_data);
120 :
121 :
122 :
123 : static char *
124 56 : uiserver_get_version (const char *file_name)
125 : {
126 : (void)file_name;
127 56 : return NULL;
128 : }
129 :
130 :
131 : static const char *
132 56 : uiserver_get_req_version (void)
133 : {
134 56 : return NULL;
135 : }
136 :
137 :
138 : static void
139 0 : close_notify_handler (int fd, void *opaque)
140 : {
141 0 : engine_uiserver_t uiserver = opaque;
142 :
143 0 : assert (fd != -1);
144 0 : if (uiserver->status_cb.fd == fd)
145 : {
146 0 : if (uiserver->status_cb.tag)
147 0 : (*uiserver->io_cbs.remove) (uiserver->status_cb.tag);
148 0 : uiserver->status_cb.fd = -1;
149 0 : uiserver->status_cb.tag = NULL;
150 : }
151 0 : else if (uiserver->input_cb.fd == fd)
152 : {
153 0 : if (uiserver->input_cb.tag)
154 0 : (*uiserver->io_cbs.remove) (uiserver->input_cb.tag);
155 0 : uiserver->input_cb.fd = -1;
156 0 : uiserver->input_cb.tag = NULL;
157 0 : if (uiserver->input_helper_data)
158 : {
159 0 : gpgme_data_release (uiserver->input_helper_data);
160 0 : uiserver->input_helper_data = NULL;
161 : }
162 0 : if (uiserver->input_helper_memory)
163 : {
164 0 : free (uiserver->input_helper_memory);
165 0 : uiserver->input_helper_memory = NULL;
166 : }
167 : }
168 0 : else if (uiserver->output_cb.fd == fd)
169 : {
170 0 : if (uiserver->output_cb.tag)
171 0 : (*uiserver->io_cbs.remove) (uiserver->output_cb.tag);
172 0 : uiserver->output_cb.fd = -1;
173 0 : uiserver->output_cb.tag = NULL;
174 : }
175 0 : else if (uiserver->message_cb.fd == fd)
176 : {
177 0 : if (uiserver->message_cb.tag)
178 0 : (*uiserver->io_cbs.remove) (uiserver->message_cb.tag);
179 0 : uiserver->message_cb.fd = -1;
180 0 : uiserver->message_cb.tag = NULL;
181 : }
182 0 : }
183 :
184 :
185 : /* This is the default inquiry callback. We use it to handle the
186 : Pinentry notifications. */
187 : static gpgme_error_t
188 0 : default_inq_cb (engine_uiserver_t uiserver, const char *line)
189 : {
190 0 : if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
191 : {
192 0 : _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
193 : }
194 :
195 0 : return 0;
196 : }
197 :
198 :
199 : static gpgme_error_t
200 0 : uiserver_cancel (void *engine)
201 : {
202 0 : engine_uiserver_t uiserver = engine;
203 :
204 0 : if (!uiserver)
205 0 : return gpg_error (GPG_ERR_INV_VALUE);
206 :
207 0 : if (uiserver->status_cb.fd != -1)
208 0 : _gpgme_io_close (uiserver->status_cb.fd);
209 0 : if (uiserver->input_cb.fd != -1)
210 0 : _gpgme_io_close (uiserver->input_cb.fd);
211 0 : if (uiserver->output_cb.fd != -1)
212 0 : _gpgme_io_close (uiserver->output_cb.fd);
213 0 : if (uiserver->message_cb.fd != -1)
214 0 : _gpgme_io_close (uiserver->message_cb.fd);
215 :
216 0 : if (uiserver->assuan_ctx)
217 : {
218 0 : assuan_release (uiserver->assuan_ctx);
219 0 : uiserver->assuan_ctx = NULL;
220 : }
221 :
222 0 : return 0;
223 : }
224 :
225 :
226 : static void
227 0 : uiserver_release (void *engine)
228 : {
229 0 : engine_uiserver_t uiserver = engine;
230 :
231 0 : if (!uiserver)
232 0 : return;
233 :
234 0 : uiserver_cancel (engine);
235 :
236 0 : free (uiserver->colon.attic.line);
237 0 : free (uiserver);
238 : }
239 :
240 :
241 : static gpgme_error_t
242 0 : uiserver_new (void **engine, const char *file_name, const char *home_dir,
243 : const char *version)
244 : {
245 0 : gpgme_error_t err = 0;
246 : engine_uiserver_t uiserver;
247 0 : char *dft_display = NULL;
248 : char dft_ttyname[64];
249 0 : char *dft_ttytype = NULL;
250 : char *optstr;
251 :
252 : (void)version; /* Not yet used. */
253 :
254 0 : uiserver = calloc (1, sizeof *uiserver);
255 0 : if (!uiserver)
256 0 : return gpg_error_from_syserror ();
257 :
258 0 : uiserver->protocol = GPGME_PROTOCOL_DEFAULT;
259 0 : uiserver->status_cb.fd = -1;
260 0 : uiserver->status_cb.dir = 1;
261 0 : uiserver->status_cb.tag = 0;
262 0 : uiserver->status_cb.data = uiserver;
263 :
264 0 : uiserver->input_cb.fd = -1;
265 0 : uiserver->input_cb.dir = 0;
266 0 : uiserver->input_cb.tag = 0;
267 0 : uiserver->input_cb.server_fd = -1;
268 0 : *uiserver->input_cb.server_fd_str = 0;
269 0 : uiserver->output_cb.fd = -1;
270 0 : uiserver->output_cb.dir = 1;
271 0 : uiserver->output_cb.tag = 0;
272 0 : uiserver->output_cb.server_fd = -1;
273 0 : *uiserver->output_cb.server_fd_str = 0;
274 0 : uiserver->message_cb.fd = -1;
275 0 : uiserver->message_cb.dir = 0;
276 0 : uiserver->message_cb.tag = 0;
277 0 : uiserver->message_cb.server_fd = -1;
278 0 : *uiserver->message_cb.server_fd_str = 0;
279 :
280 0 : uiserver->status.fnc = 0;
281 0 : uiserver->colon.fnc = 0;
282 0 : uiserver->colon.attic.line = 0;
283 0 : uiserver->colon.attic.linesize = 0;
284 0 : uiserver->colon.attic.linelen = 0;
285 0 : uiserver->colon.any = 0;
286 :
287 0 : uiserver->inline_data = NULL;
288 :
289 0 : uiserver->io_cbs.add = NULL;
290 0 : uiserver->io_cbs.add_priv = NULL;
291 0 : uiserver->io_cbs.remove = NULL;
292 0 : uiserver->io_cbs.event = NULL;
293 0 : uiserver->io_cbs.event_priv = NULL;
294 :
295 0 : err = assuan_new_ext (&uiserver->assuan_ctx, GPG_ERR_SOURCE_GPGME,
296 : &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
297 : NULL);
298 0 : if (err)
299 0 : goto leave;
300 0 : assuan_ctx_set_system_hooks (uiserver->assuan_ctx,
301 : &_gpgme_assuan_system_hooks);
302 :
303 0 : err = assuan_socket_connect (uiserver->assuan_ctx,
304 : file_name ?
305 : file_name : _gpgme_get_default_uisrv_socket (),
306 : 0, ASSUAN_SOCKET_SERVER_FDPASSING);
307 0 : if (err)
308 0 : goto leave;
309 :
310 0 : err = _gpgme_getenv ("DISPLAY", &dft_display);
311 0 : if (err)
312 0 : goto leave;
313 0 : if (dft_display)
314 : {
315 0 : if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
316 : {
317 0 : err = gpg_error_from_syserror ();
318 0 : free (dft_display);
319 0 : goto leave;
320 : }
321 0 : free (dft_display);
322 :
323 0 : err = assuan_transact (uiserver->assuan_ctx, optstr, NULL, NULL, NULL,
324 : NULL, NULL, NULL);
325 0 : free (optstr);
326 0 : if (err)
327 0 : goto leave;
328 : }
329 :
330 0 : if (isatty (1))
331 : {
332 : int rc;
333 :
334 0 : rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
335 :
336 : /* Even though isatty() returns 1, ttyname_r() may fail in many
337 : ways, e.g., when /dev/pts is not accessible under chroot. */
338 0 : if (!rc)
339 : {
340 0 : if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
341 : {
342 0 : err = gpg_error_from_syserror ();
343 0 : goto leave;
344 : }
345 0 : err = assuan_transact (uiserver->assuan_ctx, optstr, NULL, NULL, NULL,
346 : NULL, NULL, NULL);
347 0 : free (optstr);
348 0 : if (err)
349 0 : goto leave;
350 :
351 0 : err = _gpgme_getenv ("TERM", &dft_ttytype);
352 0 : if (err)
353 0 : goto leave;
354 0 : if (dft_ttytype)
355 : {
356 0 : if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0)
357 : {
358 0 : err = gpg_error_from_syserror ();
359 0 : free (dft_ttytype);
360 0 : goto leave;
361 : }
362 0 : free (dft_ttytype);
363 :
364 0 : err = assuan_transact (uiserver->assuan_ctx, optstr, NULL, NULL,
365 : NULL, NULL, NULL, NULL);
366 0 : free (optstr);
367 0 : if (err)
368 0 : goto leave;
369 : }
370 : }
371 : }
372 :
373 : #ifdef HAVE_W32_SYSTEM
374 : /* Under Windows we need to use AllowSetForegroundWindow. Tell
375 : uiserver to tell us when it needs it. */
376 : if (!err)
377 : {
378 : err = assuan_transact (uiserver->assuan_ctx, "OPTION allow-pinentry-notify",
379 : NULL, NULL, NULL, NULL, NULL, NULL);
380 : if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
381 : err = 0; /* This is a new feature of uiserver. */
382 : }
383 : #endif /*HAVE_W32_SYSTEM*/
384 :
385 : leave:
386 0 : if (err)
387 0 : uiserver_release (uiserver);
388 : else
389 0 : *engine = uiserver;
390 :
391 0 : return err;
392 : }
393 :
394 :
395 : static gpgme_error_t
396 0 : uiserver_set_locale (void *engine, int category, const char *value)
397 : {
398 0 : engine_uiserver_t uiserver = engine;
399 : gpgme_error_t err;
400 : char *optstr;
401 : char *catstr;
402 :
403 : /* FIXME: If value is NULL, we need to reset the option to default.
404 : But we can't do this. So we error out here. UISERVER needs support
405 : for this. */
406 0 : if (category == LC_CTYPE)
407 : {
408 0 : catstr = "lc-ctype";
409 0 : if (!value && uiserver->lc_ctype_set)
410 0 : return gpg_error (GPG_ERR_INV_VALUE);
411 0 : if (value)
412 0 : uiserver->lc_ctype_set = 1;
413 : }
414 : #ifdef LC_MESSAGES
415 0 : else if (category == LC_MESSAGES)
416 : {
417 0 : catstr = "lc-messages";
418 0 : if (!value && uiserver->lc_messages_set)
419 0 : return gpg_error (GPG_ERR_INV_VALUE);
420 0 : if (value)
421 0 : uiserver->lc_messages_set = 1;
422 : }
423 : #endif /* LC_MESSAGES */
424 : else
425 0 : return gpg_error (GPG_ERR_INV_VALUE);
426 :
427 : /* FIXME: Reset value to default. */
428 0 : if (!value)
429 0 : return 0;
430 :
431 0 : if (asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
432 0 : err = gpg_error_from_syserror ();
433 : else
434 : {
435 0 : err = assuan_transact (uiserver->assuan_ctx, optstr, NULL, NULL,
436 : NULL, NULL, NULL, NULL);
437 0 : free (optstr);
438 : }
439 :
440 0 : return err;
441 : }
442 :
443 :
444 : static gpgme_error_t
445 0 : uiserver_set_protocol (void *engine, gpgme_protocol_t protocol)
446 : {
447 0 : engine_uiserver_t uiserver = engine;
448 :
449 0 : if (protocol != GPGME_PROTOCOL_OpenPGP
450 0 : && protocol != GPGME_PROTOCOL_CMS
451 0 : && protocol != GPGME_PROTOCOL_DEFAULT)
452 0 : return gpg_error (GPG_ERR_INV_VALUE);
453 :
454 0 : uiserver->protocol = protocol;
455 0 : return 0;
456 : }
457 :
458 :
459 : static gpgme_error_t
460 0 : uiserver_assuan_simple_command (engine_uiserver_t uiserver, char *cmd,
461 : engine_status_handler_t status_fnc,
462 : void *status_fnc_value)
463 : {
464 0 : assuan_context_t ctx = uiserver->assuan_ctx;
465 : gpg_error_t err;
466 : char *line;
467 : size_t linelen;
468 :
469 0 : err = assuan_write_line (ctx, cmd);
470 0 : if (err)
471 0 : return err;
472 :
473 : do
474 : {
475 0 : err = assuan_read_line (ctx, &line, &linelen);
476 0 : if (err)
477 0 : return err;
478 :
479 0 : if (*line == '#' || !linelen)
480 0 : continue;
481 :
482 0 : if (linelen >= 2
483 0 : && line[0] == 'O' && line[1] == 'K'
484 0 : && (line[2] == '\0' || line[2] == ' '))
485 0 : return 0;
486 0 : else if (linelen >= 4
487 0 : && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
488 0 : && line[3] == ' ')
489 0 : err = atoi (&line[4]);
490 0 : else if (linelen >= 2
491 0 : && line[0] == 'S' && line[1] == ' ')
492 0 : {
493 : char *rest;
494 : gpgme_status_code_t r;
495 :
496 0 : rest = strchr (line + 2, ' ');
497 0 : if (!rest)
498 0 : rest = line + linelen; /* set to an empty string */
499 : else
500 0 : *(rest++) = 0;
501 :
502 0 : r = _gpgme_parse_status (line + 2);
503 0 : if (uiserver->status.mon_cb && r != GPGME_STATUS_PROGRESS)
504 : {
505 : /* Note that we call the monitor even if we do
506 : * not know the status code (r < 0). */
507 0 : err = uiserver->status.mon_cb (uiserver->status.mon_cb_value,
508 0 : line + 2, rest);
509 : }
510 :
511 0 : if (err)
512 : ;
513 0 : else if (r >= 0 && status_fnc)
514 0 : err = status_fnc (status_fnc_value, r, rest);
515 : else
516 0 : err = gpg_error (GPG_ERR_GENERAL);
517 : }
518 : else
519 0 : err = gpg_error (GPG_ERR_GENERAL);
520 : }
521 0 : while (!err);
522 :
523 0 : return err;
524 : }
525 :
526 :
527 : typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
528 :
529 : #define COMMANDLINELEN 40
530 : static gpgme_error_t
531 0 : uiserver_set_fd (engine_uiserver_t uiserver, fd_type_t fd_type, const char *opt)
532 : {
533 0 : gpg_error_t err = 0;
534 : char line[COMMANDLINELEN];
535 : char *which;
536 : iocb_data_t *iocb_data;
537 : int dir;
538 :
539 0 : switch (fd_type)
540 : {
541 : case INPUT_FD:
542 0 : which = "INPUT";
543 0 : iocb_data = &uiserver->input_cb;
544 0 : break;
545 :
546 : case OUTPUT_FD:
547 0 : which = "OUTPUT";
548 0 : iocb_data = &uiserver->output_cb;
549 0 : break;
550 :
551 : case MESSAGE_FD:
552 0 : which = "MESSAGE";
553 0 : iocb_data = &uiserver->message_cb;
554 0 : break;
555 :
556 : default:
557 0 : return gpg_error (GPG_ERR_INV_VALUE);
558 : }
559 :
560 0 : dir = iocb_data->dir;
561 :
562 : /* We try to short-cut the communication by giving UISERVER direct
563 : access to the file descriptor, rather than using a pipe. */
564 0 : iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
565 0 : if (iocb_data->server_fd < 0)
566 : {
567 : int fds[2];
568 :
569 0 : if (_gpgme_io_pipe (fds, 0) < 0)
570 0 : return gpg_error_from_syserror ();
571 :
572 0 : iocb_data->fd = dir ? fds[0] : fds[1];
573 0 : iocb_data->server_fd = dir ? fds[1] : fds[0];
574 :
575 0 : if (_gpgme_io_set_close_notify (iocb_data->fd,
576 : close_notify_handler, uiserver))
577 : {
578 0 : err = gpg_error (GPG_ERR_GENERAL);
579 0 : goto leave_set_fd;
580 : }
581 : }
582 :
583 0 : err = assuan_sendfd (uiserver->assuan_ctx, iocb_data->server_fd);
584 0 : if (err)
585 0 : goto leave_set_fd;
586 :
587 0 : _gpgme_io_close (iocb_data->server_fd);
588 0 : iocb_data->server_fd = -1;
589 :
590 0 : if (opt)
591 0 : snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
592 : else
593 0 : snprintf (line, COMMANDLINELEN, "%s FD", which);
594 :
595 0 : err = uiserver_assuan_simple_command (uiserver, line, NULL, NULL);
596 :
597 : leave_set_fd:
598 0 : if (err)
599 : {
600 0 : _gpgme_io_close (iocb_data->fd);
601 0 : iocb_data->fd = -1;
602 0 : if (iocb_data->server_fd != -1)
603 : {
604 0 : _gpgme_io_close (iocb_data->server_fd);
605 0 : iocb_data->server_fd = -1;
606 : }
607 : }
608 :
609 0 : return err;
610 : }
611 :
612 :
613 : static const char *
614 0 : map_data_enc (gpgme_data_t d)
615 : {
616 0 : switch (gpgme_data_get_encoding (d))
617 : {
618 : case GPGME_DATA_ENCODING_NONE:
619 0 : break;
620 : case GPGME_DATA_ENCODING_BINARY:
621 0 : return "--binary";
622 : case GPGME_DATA_ENCODING_BASE64:
623 0 : return "--base64";
624 : case GPGME_DATA_ENCODING_ARMOR:
625 0 : return "--armor";
626 : default:
627 0 : break;
628 : }
629 0 : return NULL;
630 : }
631 :
632 :
633 : static gpgme_error_t
634 0 : status_handler (void *opaque, int fd)
635 : {
636 0 : struct io_cb_data *data = (struct io_cb_data *) opaque;
637 0 : engine_uiserver_t uiserver = (engine_uiserver_t) data->handler_value;
638 0 : gpgme_error_t err = 0;
639 : char *line;
640 : size_t linelen;
641 :
642 : do
643 : {
644 0 : err = assuan_read_line (uiserver->assuan_ctx, &line, &linelen);
645 0 : if (err)
646 : {
647 : /* Try our best to terminate the connection friendly. */
648 : /* assuan_write_line (uiserver->assuan_ctx, "BYE"); */
649 0 : TRACE3 (DEBUG_CTX, "gpgme:status_handler", uiserver,
650 : "fd 0x%x: error from assuan (%d) getting status line : %s",
651 : fd, err, gpg_strerror (err));
652 : }
653 0 : else if (linelen >= 3
654 0 : && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
655 0 : && (line[3] == '\0' || line[3] == ' '))
656 : {
657 0 : if (line[3] == ' ')
658 0 : err = atoi (&line[4]);
659 0 : if (! err)
660 0 : err = gpg_error (GPG_ERR_GENERAL);
661 0 : TRACE2 (DEBUG_CTX, "gpgme:status_handler", uiserver,
662 : "fd 0x%x: ERR line - mapped to: %s",
663 : fd, err ? gpg_strerror (err) : "ok");
664 : /* Try our best to terminate the connection friendly. */
665 : /* assuan_write_line (uiserver->assuan_ctx, "BYE"); */
666 : }
667 0 : else if (linelen >= 2
668 0 : && line[0] == 'O' && line[1] == 'K'
669 0 : && (line[2] == '\0' || line[2] == ' '))
670 : {
671 0 : if (uiserver->status.fnc)
672 0 : err = uiserver->status.fnc (uiserver->status.fnc_value,
673 : GPGME_STATUS_EOF, "");
674 :
675 0 : if (!err && uiserver->colon.fnc && uiserver->colon.any)
676 : {
677 : /* We must tell a colon function about the EOF. We do
678 : this only when we have seen any data lines. Note
679 : that this inlined use of colon data lines will
680 : eventually be changed into using a regular data
681 : channel. */
682 0 : uiserver->colon.any = 0;
683 0 : err = uiserver->colon.fnc (uiserver->colon.fnc_value, NULL);
684 : }
685 0 : TRACE2 (DEBUG_CTX, "gpgme:status_handler", uiserver,
686 : "fd 0x%x: OK line - final status: %s",
687 : fd, err ? gpg_strerror (err) : "ok");
688 0 : _gpgme_io_close (uiserver->status_cb.fd);
689 0 : return err;
690 : }
691 0 : else if (linelen > 2
692 0 : && line[0] == 'D' && line[1] == ' '
693 0 : && uiserver->colon.fnc)
694 0 : {
695 : /* We are using the colon handler even for plain inline data
696 : - strange name for that function but for historic reasons
697 : we keep it. */
698 : /* FIXME We can't use this for binary data because we
699 : assume this is a string. For the current usage of colon
700 : output it is correct. */
701 0 : char *src = line + 2;
702 0 : char *end = line + linelen;
703 : char *dst;
704 0 : char **aline = &uiserver->colon.attic.line;
705 0 : int *alinelen = &uiserver->colon.attic.linelen;
706 :
707 0 : if (uiserver->colon.attic.linesize < *alinelen + linelen + 1)
708 : {
709 0 : char *newline = realloc (*aline, *alinelen + linelen + 1);
710 0 : if (!newline)
711 0 : err = gpg_error_from_syserror ();
712 : else
713 : {
714 0 : *aline = newline;
715 0 : uiserver->colon.attic.linesize = *alinelen + linelen + 1;
716 : }
717 : }
718 0 : if (!err)
719 : {
720 0 : dst = *aline + *alinelen;
721 :
722 0 : while (!err && src < end)
723 : {
724 0 : if (*src == '%' && src + 2 < end)
725 : {
726 : /* Handle escaped characters. */
727 0 : ++src;
728 0 : *dst = _gpgme_hextobyte (src);
729 0 : (*alinelen)++;
730 0 : src += 2;
731 : }
732 : else
733 : {
734 0 : *dst = *src++;
735 0 : (*alinelen)++;
736 : }
737 :
738 0 : if (*dst == '\n')
739 : {
740 : /* Terminate the pending line, pass it to the colon
741 : handler and reset it. */
742 :
743 0 : uiserver->colon.any = 1;
744 0 : if (*alinelen > 1 && *(dst - 1) == '\r')
745 0 : dst--;
746 0 : *dst = '\0';
747 :
748 : /* FIXME How should we handle the return code? */
749 0 : err = uiserver->colon.fnc (uiserver->colon.fnc_value, *aline);
750 0 : if (!err)
751 : {
752 0 : dst = *aline;
753 0 : *alinelen = 0;
754 : }
755 : }
756 : else
757 0 : dst++;
758 : }
759 : }
760 0 : TRACE2 (DEBUG_CTX, "gpgme:status_handler", uiserver,
761 : "fd 0x%x: D line; final status: %s",
762 : fd, err? gpg_strerror (err):"ok");
763 : }
764 0 : else if (linelen > 2
765 0 : && line[0] == 'D' && line[1] == ' '
766 0 : && uiserver->inline_data)
767 0 : {
768 0 : char *src = line + 2;
769 0 : char *end = line + linelen;
770 0 : char *dst = src;
771 : gpgme_ssize_t nwritten;
772 :
773 0 : linelen = 0;
774 0 : while (src < end)
775 : {
776 0 : if (*src == '%' && src + 2 < end)
777 : {
778 : /* Handle escaped characters. */
779 0 : ++src;
780 0 : *dst++ = _gpgme_hextobyte (src);
781 0 : src += 2;
782 : }
783 : else
784 0 : *dst++ = *src++;
785 :
786 0 : linelen++;
787 : }
788 :
789 0 : src = line + 2;
790 0 : while (linelen > 0)
791 : {
792 0 : nwritten = gpgme_data_write (uiserver->inline_data, src, linelen);
793 0 : if (!nwritten || (nwritten < 0 && errno != EINTR)
794 0 : || nwritten > linelen)
795 : {
796 0 : err = gpg_error_from_syserror ();
797 0 : break;
798 : }
799 0 : src += nwritten;
800 0 : linelen -= nwritten;
801 : }
802 :
803 0 : TRACE2 (DEBUG_CTX, "gpgme:status_handler", uiserver,
804 : "fd 0x%x: D inlinedata; final status: %s",
805 : fd, err? gpg_strerror (err):"ok");
806 : }
807 0 : else if (linelen > 2
808 0 : && line[0] == 'S' && line[1] == ' ')
809 0 : {
810 : char *rest;
811 : gpgme_status_code_t r;
812 :
813 0 : rest = strchr (line + 2, ' ');
814 0 : if (!rest)
815 0 : rest = line + linelen; /* set to an empty string */
816 : else
817 0 : *(rest++) = 0;
818 :
819 0 : r = _gpgme_parse_status (line + 2);
820 :
821 : if (r >= 0)
822 : {
823 0 : if (uiserver->status.fnc)
824 0 : err = uiserver->status.fnc (uiserver->status.fnc_value, r, rest);
825 : }
826 : else
827 : fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
828 0 : TRACE3 (DEBUG_CTX, "gpgme:status_handler", uiserver,
829 : "fd 0x%x: S line (%s) - final status: %s",
830 : fd, line+2, err? gpg_strerror (err):"ok");
831 : }
832 0 : else if (linelen >= 7
833 0 : && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
834 0 : && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
835 0 : && line[6] == 'E'
836 0 : && (line[7] == '\0' || line[7] == ' '))
837 : {
838 0 : char *keyword = line+7;
839 :
840 0 : while (*keyword == ' ')
841 0 : keyword++;;
842 0 : default_inq_cb (uiserver, keyword);
843 0 : assuan_write_line (uiserver->assuan_ctx, "END");
844 : }
845 :
846 : }
847 0 : while (!err && assuan_pending_line (uiserver->assuan_ctx));
848 :
849 0 : return err;
850 : }
851 :
852 :
853 : static gpgme_error_t
854 0 : add_io_cb (engine_uiserver_t uiserver, iocb_data_t *iocbd, gpgme_io_cb_t handler)
855 : {
856 : gpgme_error_t err;
857 :
858 0 : TRACE_BEG2 (DEBUG_ENGINE, "engine-uiserver:add_io_cb", uiserver,
859 : "fd %d, dir %d", iocbd->fd, iocbd->dir);
860 0 : err = (*uiserver->io_cbs.add) (uiserver->io_cbs.add_priv,
861 : iocbd->fd, iocbd->dir,
862 : handler, iocbd->data, &iocbd->tag);
863 0 : if (err)
864 0 : return TRACE_ERR (err);
865 0 : if (!iocbd->dir)
866 : /* FIXME Kludge around poll() problem. */
867 0 : err = _gpgme_io_set_nonblocking (iocbd->fd);
868 0 : return TRACE_ERR (err);
869 : }
870 :
871 :
872 : static gpgme_error_t
873 0 : start (engine_uiserver_t uiserver, const char *command)
874 : {
875 : gpgme_error_t err;
876 : int fdlist[5];
877 : int nfds;
878 :
879 : /* We need to know the fd used by assuan for reads. We do this by
880 : using the assumption that the first returned fd from
881 : assuan_get_active_fds() is always this one. */
882 0 : nfds = assuan_get_active_fds (uiserver->assuan_ctx, 0 /* read fds */,
883 : fdlist, DIM (fdlist));
884 0 : if (nfds < 1)
885 0 : return gpg_error (GPG_ERR_GENERAL); /* FIXME */
886 :
887 : /* We "duplicate" the file descriptor, so we can close it here (we
888 : can't close fdlist[0], as that is closed by libassuan, and
889 : closing it here might cause libassuan to close some unrelated FD
890 : later). Alternatively, we could special case status_fd and
891 : register/unregister it manually as needed, but this increases
892 : code duplication and is more complicated as we can not use the
893 : close notifications etc. A third alternative would be to let
894 : Assuan know that we closed the FD, but that complicates the
895 : Assuan interface. */
896 :
897 0 : uiserver->status_cb.fd = _gpgme_io_dup (fdlist[0]);
898 0 : if (uiserver->status_cb.fd < 0)
899 0 : return gpg_error_from_syserror ();
900 :
901 0 : if (_gpgme_io_set_close_notify (uiserver->status_cb.fd,
902 : close_notify_handler, uiserver))
903 : {
904 0 : _gpgme_io_close (uiserver->status_cb.fd);
905 0 : uiserver->status_cb.fd = -1;
906 0 : return gpg_error (GPG_ERR_GENERAL);
907 : }
908 :
909 0 : err = add_io_cb (uiserver, &uiserver->status_cb, status_handler);
910 0 : if (!err && uiserver->input_cb.fd != -1)
911 0 : err = add_io_cb (uiserver, &uiserver->input_cb, _gpgme_data_outbound_handler);
912 0 : if (!err && uiserver->output_cb.fd != -1)
913 0 : err = add_io_cb (uiserver, &uiserver->output_cb, _gpgme_data_inbound_handler);
914 0 : if (!err && uiserver->message_cb.fd != -1)
915 0 : err = add_io_cb (uiserver, &uiserver->message_cb, _gpgme_data_outbound_handler);
916 :
917 0 : if (!err)
918 0 : err = assuan_write_line (uiserver->assuan_ctx, command);
919 :
920 0 : if (!err)
921 0 : uiserver_io_event (uiserver, GPGME_EVENT_START, NULL);
922 :
923 0 : return err;
924 : }
925 :
926 :
927 : static gpgme_error_t
928 0 : uiserver_reset (void *engine)
929 : {
930 0 : engine_uiserver_t uiserver = engine;
931 :
932 : /* We must send a reset because we need to reset the list of
933 : signers. Note that RESET does not reset OPTION commands. */
934 0 : return uiserver_assuan_simple_command (uiserver, "RESET", NULL, NULL);
935 : }
936 :
937 :
938 : static gpgme_error_t
939 0 : _uiserver_decrypt (void *engine, int verify,
940 : gpgme_data_t ciph, gpgme_data_t plain)
941 : {
942 0 : engine_uiserver_t uiserver = engine;
943 : gpgme_error_t err;
944 : const char *protocol;
945 : char *cmd;
946 :
947 0 : if (!uiserver)
948 0 : return gpg_error (GPG_ERR_INV_VALUE);
949 0 : if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
950 0 : protocol = "";
951 0 : else if (uiserver->protocol == GPGME_PROTOCOL_OpenPGP)
952 0 : protocol = " --protocol=OpenPGP";
953 0 : else if (uiserver->protocol == GPGME_PROTOCOL_CMS)
954 0 : protocol = " --protocol=CMS";
955 : else
956 0 : return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
957 :
958 0 : if (asprintf (&cmd, "DECRYPT%s%s", protocol,
959 : verify ? "" : " --no-verify") < 0)
960 0 : return gpg_error_from_syserror ();
961 :
962 0 : uiserver->input_cb.data = ciph;
963 0 : err = uiserver_set_fd (uiserver, INPUT_FD,
964 0 : map_data_enc (uiserver->input_cb.data));
965 0 : if (err)
966 : {
967 0 : free (cmd);
968 0 : return gpg_error (GPG_ERR_GENERAL); /* FIXME */
969 : }
970 0 : uiserver->output_cb.data = plain;
971 0 : err = uiserver_set_fd (uiserver, OUTPUT_FD, 0);
972 0 : if (err)
973 : {
974 0 : free (cmd);
975 0 : return gpg_error (GPG_ERR_GENERAL); /* FIXME */
976 : }
977 0 : uiserver->inline_data = NULL;
978 :
979 0 : err = start (engine, cmd);
980 0 : free (cmd);
981 0 : return err;
982 : }
983 :
984 :
985 : static gpgme_error_t
986 0 : uiserver_decrypt (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
987 : {
988 0 : return _uiserver_decrypt (engine, 0, ciph, plain);
989 : }
990 :
991 :
992 : static gpgme_error_t
993 0 : uiserver_decrypt_verify (void *engine, gpgme_data_t ciph, gpgme_data_t plain)
994 : {
995 0 : return _uiserver_decrypt (engine, 1, ciph, plain);
996 : }
997 :
998 :
999 : static gpgme_error_t
1000 0 : set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[])
1001 : {
1002 0 : gpgme_error_t err = 0;
1003 : char *line;
1004 : int linelen;
1005 0 : int invalid_recipients = 0;
1006 : int i;
1007 :
1008 0 : linelen = 10 + 40 + 1; /* "RECIPIENT " + guess + '\0'. */
1009 0 : line = malloc (10 + 40 + 1);
1010 0 : if (!line)
1011 0 : return gpg_error_from_syserror ();
1012 0 : strcpy (line, "RECIPIENT ");
1013 0 : for (i=0; !err && recp[i]; i++)
1014 : {
1015 : char *uid;
1016 : int newlen;
1017 :
1018 : /* We use only the first user ID of the key. */
1019 0 : if (!recp[i]->uids || !(uid=recp[i]->uids->uid) || !*uid)
1020 : {
1021 0 : invalid_recipients++;
1022 0 : continue;
1023 : }
1024 :
1025 0 : newlen = 11 + strlen (uid);
1026 0 : if (linelen < newlen)
1027 : {
1028 0 : char *newline = realloc (line, newlen);
1029 0 : if (! newline)
1030 : {
1031 0 : int saved_err = gpg_error_from_syserror ();
1032 0 : free (line);
1033 0 : return saved_err;
1034 : }
1035 0 : line = newline;
1036 0 : linelen = newlen;
1037 : }
1038 : /* FIXME: need to do proper escaping */
1039 0 : strcpy (&line[10], uid);
1040 :
1041 0 : err = uiserver_assuan_simple_command (uiserver, line,
1042 : uiserver->status.fnc,
1043 : uiserver->status.fnc_value);
1044 : /* FIXME: This might requires more work. */
1045 0 : if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
1046 0 : invalid_recipients++;
1047 0 : else if (err)
1048 : {
1049 0 : free (line);
1050 0 : return err;
1051 : }
1052 : }
1053 0 : free (line);
1054 0 : return gpg_error (invalid_recipients
1055 : ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
1056 : }
1057 :
1058 :
1059 : static gpgme_error_t
1060 0 : uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
1061 : gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
1062 : {
1063 0 : engine_uiserver_t uiserver = engine;
1064 : gpgme_error_t err;
1065 : const char *protocol;
1066 : char *cmd;
1067 :
1068 0 : if (!uiserver)
1069 0 : return gpg_error (GPG_ERR_INV_VALUE);
1070 0 : if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
1071 0 : protocol = "";
1072 0 : else if (uiserver->protocol == GPGME_PROTOCOL_OpenPGP)
1073 0 : protocol = " --protocol=OpenPGP";
1074 0 : else if (uiserver->protocol == GPGME_PROTOCOL_CMS)
1075 0 : protocol = " --protocol=CMS";
1076 : else
1077 0 : return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
1078 :
1079 0 : if (flags & GPGME_ENCRYPT_PREPARE)
1080 : {
1081 0 : if (!recp || plain || ciph)
1082 0 : return gpg_error (GPG_ERR_INV_VALUE);
1083 :
1084 0 : if (asprintf (&cmd, "PREP_ENCRYPT%s%s", protocol,
1085 0 : (flags & GPGME_ENCRYPT_EXPECT_SIGN)
1086 : ? " --expect-sign" : "") < 0)
1087 0 : return gpg_error_from_syserror ();
1088 : }
1089 : else
1090 : {
1091 0 : if (!plain || !ciph)
1092 0 : return gpg_error (GPG_ERR_INV_VALUE);
1093 :
1094 0 : if (asprintf (&cmd, "ENCRYPT%s", protocol) < 0)
1095 0 : return gpg_error_from_syserror ();
1096 : }
1097 :
1098 0 : if (plain)
1099 : {
1100 0 : uiserver->input_cb.data = plain;
1101 0 : err = uiserver_set_fd (uiserver, INPUT_FD,
1102 0 : map_data_enc (uiserver->input_cb.data));
1103 0 : if (err)
1104 : {
1105 0 : free (cmd);
1106 0 : return err;
1107 : }
1108 : }
1109 :
1110 0 : if (ciph)
1111 : {
1112 0 : uiserver->output_cb.data = ciph;
1113 0 : err = uiserver_set_fd (uiserver, OUTPUT_FD, use_armor ? "--armor"
1114 0 : : map_data_enc (uiserver->output_cb.data));
1115 0 : if (err)
1116 : {
1117 0 : free (cmd);
1118 0 : return err;
1119 : }
1120 : }
1121 :
1122 0 : uiserver->inline_data = NULL;
1123 :
1124 0 : if (recp)
1125 : {
1126 0 : err = set_recipients (uiserver, recp);
1127 0 : if (err)
1128 : {
1129 0 : free (cmd);
1130 0 : return err;
1131 : }
1132 : }
1133 :
1134 0 : err = start (uiserver, cmd);
1135 0 : free (cmd);
1136 0 : return err;
1137 : }
1138 :
1139 :
1140 : static gpgme_error_t
1141 0 : uiserver_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
1142 : gpgme_sig_mode_t mode, int use_armor, int use_textmode,
1143 : int include_certs, gpgme_ctx_t ctx /* FIXME */)
1144 : {
1145 0 : engine_uiserver_t uiserver = engine;
1146 0 : gpgme_error_t err = 0;
1147 : const char *protocol;
1148 : char *cmd;
1149 : gpgme_key_t key;
1150 :
1151 0 : if (!uiserver || !in || !out)
1152 0 : return gpg_error (GPG_ERR_INV_VALUE);
1153 0 : if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
1154 0 : protocol = "";
1155 0 : else if (uiserver->protocol == GPGME_PROTOCOL_OpenPGP)
1156 0 : protocol = " --protocol=OpenPGP";
1157 0 : else if (uiserver->protocol == GPGME_PROTOCOL_CMS)
1158 0 : protocol = " --protocol=CMS";
1159 : else
1160 0 : return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
1161 :
1162 0 : if (asprintf (&cmd, "SIGN%s%s", protocol,
1163 : (mode == GPGME_SIG_MODE_DETACH) ? " --detached" : "") < 0)
1164 0 : return gpg_error_from_syserror ();
1165 :
1166 0 : key = gpgme_signers_enum (ctx, 0);
1167 0 : if (key)
1168 : {
1169 0 : const char *s = NULL;
1170 :
1171 0 : if (key && key->uids)
1172 0 : s = key->uids->email;
1173 :
1174 0 : if (s && strlen (s) < 80)
1175 0 : {
1176 : char buf[100];
1177 :
1178 0 : strcpy (stpcpy (buf, "SENDER --info "), s);
1179 0 : err = uiserver_assuan_simple_command (uiserver, buf,
1180 : uiserver->status.fnc,
1181 : uiserver->status.fnc_value);
1182 : }
1183 : else
1184 0 : err = gpg_error (GPG_ERR_INV_VALUE);
1185 0 : gpgme_key_unref (key);
1186 0 : if (err)
1187 : {
1188 0 : free (cmd);
1189 0 : return err;
1190 : }
1191 : }
1192 :
1193 0 : uiserver->input_cb.data = in;
1194 0 : err = uiserver_set_fd (uiserver, INPUT_FD,
1195 0 : map_data_enc (uiserver->input_cb.data));
1196 0 : if (err)
1197 : {
1198 0 : free (cmd);
1199 0 : return err;
1200 : }
1201 0 : uiserver->output_cb.data = out;
1202 0 : err = uiserver_set_fd (uiserver, OUTPUT_FD, use_armor ? "--armor"
1203 0 : : map_data_enc (uiserver->output_cb.data));
1204 0 : if (err)
1205 : {
1206 0 : free (cmd);
1207 0 : return err;
1208 : }
1209 0 : uiserver->inline_data = NULL;
1210 :
1211 0 : err = start (uiserver, cmd);
1212 0 : free (cmd);
1213 0 : return err;
1214 : }
1215 :
1216 :
1217 : /* FIXME: Missing a way to specify --silent. */
1218 : static gpgme_error_t
1219 0 : uiserver_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
1220 : gpgme_data_t plaintext)
1221 : {
1222 0 : engine_uiserver_t uiserver = engine;
1223 : gpgme_error_t err;
1224 : const char *protocol;
1225 : char *cmd;
1226 :
1227 0 : if (!uiserver)
1228 0 : return gpg_error (GPG_ERR_INV_VALUE);
1229 0 : if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
1230 0 : protocol = "";
1231 0 : else if (uiserver->protocol == GPGME_PROTOCOL_OpenPGP)
1232 0 : protocol = " --protocol=OpenPGP";
1233 0 : else if (uiserver->protocol == GPGME_PROTOCOL_CMS)
1234 0 : protocol = " --protocol=CMS";
1235 : else
1236 0 : return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
1237 :
1238 0 : if (asprintf (&cmd, "VERIFY%s", protocol) < 0)
1239 0 : return gpg_error_from_syserror ();
1240 :
1241 0 : uiserver->input_cb.data = sig;
1242 0 : err = uiserver_set_fd (uiserver, INPUT_FD,
1243 0 : map_data_enc (uiserver->input_cb.data));
1244 0 : if (err)
1245 : {
1246 0 : free (cmd);
1247 0 : return err;
1248 : }
1249 0 : if (plaintext)
1250 : {
1251 : /* Normal or cleartext signature. */
1252 0 : uiserver->output_cb.data = plaintext;
1253 0 : err = uiserver_set_fd (uiserver, OUTPUT_FD, 0);
1254 : }
1255 : else
1256 : {
1257 : /* Detached signature. */
1258 0 : uiserver->message_cb.data = signed_text;
1259 0 : err = uiserver_set_fd (uiserver, MESSAGE_FD, 0);
1260 : }
1261 0 : uiserver->inline_data = NULL;
1262 :
1263 0 : if (!err)
1264 0 : err = start (uiserver, cmd);
1265 :
1266 0 : free (cmd);
1267 0 : return err;
1268 : }
1269 :
1270 :
1271 : /* This sets a status callback for monitoring status lines before they
1272 : * are passed to a caller set handler. */
1273 : static void
1274 0 : uiserver_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
1275 : {
1276 0 : engine_uiserver_t uiserver = engine;
1277 :
1278 0 : uiserver->status.mon_cb = cb;
1279 0 : uiserver->status.mon_cb_value = cb_value;
1280 0 : }
1281 :
1282 :
1283 : static void
1284 0 : uiserver_set_status_handler (void *engine, engine_status_handler_t fnc,
1285 : void *fnc_value)
1286 : {
1287 0 : engine_uiserver_t uiserver = engine;
1288 :
1289 0 : uiserver->status.fnc = fnc;
1290 0 : uiserver->status.fnc_value = fnc_value;
1291 0 : }
1292 :
1293 :
1294 : static gpgme_error_t
1295 0 : uiserver_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
1296 : void *fnc_value)
1297 : {
1298 0 : engine_uiserver_t uiserver = engine;
1299 :
1300 0 : uiserver->colon.fnc = fnc;
1301 0 : uiserver->colon.fnc_value = fnc_value;
1302 0 : uiserver->colon.any = 0;
1303 0 : return 0;
1304 : }
1305 :
1306 :
1307 : static void
1308 0 : uiserver_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
1309 : {
1310 0 : engine_uiserver_t uiserver = engine;
1311 0 : uiserver->io_cbs = *io_cbs;
1312 0 : }
1313 :
1314 :
1315 : static void
1316 0 : uiserver_io_event (void *engine, gpgme_event_io_t type, void *type_data)
1317 : {
1318 0 : engine_uiserver_t uiserver = engine;
1319 :
1320 0 : TRACE3 (DEBUG_ENGINE, "gpgme:uiserver_io_event", uiserver,
1321 : "event %p, type %d, type_data %p",
1322 : uiserver->io_cbs.event, type, type_data);
1323 0 : if (uiserver->io_cbs.event)
1324 0 : (*uiserver->io_cbs.event) (uiserver->io_cbs.event_priv, type, type_data);
1325 0 : }
1326 :
1327 :
1328 : struct engine_ops _gpgme_engine_ops_uiserver =
1329 : {
1330 : /* Static functions. */
1331 : _gpgme_get_default_uisrv_socket,
1332 : NULL,
1333 : uiserver_get_version,
1334 : uiserver_get_req_version,
1335 : uiserver_new,
1336 :
1337 : /* Member functions. */
1338 : uiserver_release,
1339 : uiserver_reset,
1340 : uiserver_set_status_cb,
1341 : uiserver_set_status_handler,
1342 : NULL, /* set_command_handler */
1343 : uiserver_set_colon_line_handler,
1344 : uiserver_set_locale,
1345 : uiserver_set_protocol,
1346 : uiserver_decrypt,
1347 : uiserver_decrypt_verify,
1348 : NULL, /* delete */
1349 : NULL, /* edit */
1350 : uiserver_encrypt,
1351 : NULL, /* encrypt_sign */
1352 : NULL, /* export */
1353 : NULL, /* export_ext */
1354 : NULL, /* genkey */
1355 : NULL, /* import */
1356 : NULL, /* keylist */
1357 : NULL, /* keylist_ext */
1358 : uiserver_sign,
1359 : NULL, /* trustlist */
1360 : uiserver_verify,
1361 : NULL, /* getauditlog */
1362 : NULL, /* opassuan_transact */
1363 : NULL, /* conf_load */
1364 : NULL, /* conf_save */
1365 : uiserver_set_io_cbs,
1366 : uiserver_io_event,
1367 : uiserver_cancel,
1368 : NULL, /* cancel_op */
1369 : NULL, /* passwd */
1370 : NULL, /* set_pinentry_mode */
1371 : NULL /* opspawn */
1372 : };
|