Blame src/engine-uiserver.c

Packit Service 672cf4
/* engine-uiserver.c - Uiserver engine.
Packit Service 6c01f9
   Copyright (C) 2000 Werner Koch (dd9jn)
Packit Service 6c01f9
   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007, 2009 g10 Code GmbH
Packit Service 6c01f9
Packit Service 6c01f9
   This file is part of GPGME.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is free software; you can redistribute it and/or modify it
Packit Service 6c01f9
   under the terms of the GNU Lesser General Public License as
Packit Service 6c01f9
   published by the Free Software Foundation; either version 2.1 of
Packit Service 6c01f9
   the License, or (at your option) any later version.
Packit Service 6c01f9
Packit Service 6c01f9
   GPGME is distributed in the hope that it will be useful, but
Packit Service 6c01f9
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 6c01f9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 6c01f9
   Lesser General Public License for more details.
Packit Service 6c01f9
Packit Service 6c01f9
   You should have received a copy of the GNU Lesser General Public
Packit Service 6c01f9
   License along with this program; if not, write to the Free Software
Packit Service 6c01f9
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
Packit Service 6c01f9
   02111-1307, USA.  */
Packit Service 672cf4
Packit Service 672cf4
/* Peculiar: Use special keys from email address for recipient and
Packit Service 672cf4
   signer (==sender).  Use no data objects with encryption for
Packit Service 672cf4
   prep_encrypt.  */
Packit Service 672cf4
Packit Service 672cf4
#if HAVE_CONFIG_H
Packit Service 672cf4
#include <config.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
Packit Service 672cf4
#include <stdlib.h>
Packit Service 672cf4
#include <string.h>
Packit Service 672cf4
#ifdef HAVE_SYS_TYPES_H
Packit Service 672cf4
# include <sys/types.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <assert.h>
Packit Service 672cf4
#ifdef HAVE_UNISTD_H
Packit Service 672cf4
# include <unistd.h>
Packit Service 672cf4
#endif
Packit Service 672cf4
#include <locale.h>
Packit Service 672cf4
#include <fcntl.h> /* FIXME */
Packit Service 672cf4
#include <errno.h>
Packit Service 672cf4
Packit Service 672cf4
#include "gpgme.h"
Packit Service 672cf4
#include "util.h"
Packit Service 672cf4
#include "ops.h"
Packit Service 672cf4
#include "wait.h"
Packit Service 672cf4
#include "priv-io.h"
Packit Service 672cf4
#include "sema.h"
Packit Service 672cf4
#include "data.h"
Packit Service 672cf4
Packit Service 672cf4
#include "assuan.h"
Packit Service 672cf4
#include "debug.h"
Packit Service 672cf4
Packit Service 672cf4
#include "engine-backend.h"
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
typedef struct
Packit Service 672cf4
{
Packit Service 672cf4
  int fd;	/* FD we talk about.  */
Packit Service 672cf4
  int server_fd;/* Server FD for this connection.  */
Packit Service 672cf4
  int dir;	/* Inbound/Outbound, maybe given implicit?  */
Packit Service 672cf4
  void *data;	/* Handler-specific data.  */
Packit Service 672cf4
  void *tag;	/* ID from the user for gpgme_remove_io_callback.  */
Packit Service 672cf4
  char server_fd_str[15]; /* Same as SERVER_FD but as a string.  We
Packit Service 672cf4
                             need this because _gpgme_io_fd2str can't
Packit Service 672cf4
                             be used on a closed descriptor.  */
Packit Service 672cf4
} iocb_data_t;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
struct engine_uiserver
Packit Service 672cf4
{
Packit Service 672cf4
  assuan_context_t assuan_ctx;
Packit Service 672cf4
Packit Service 672cf4
  int lc_ctype_set;
Packit Service 672cf4
  int lc_messages_set;
Packit Service 672cf4
  gpgme_protocol_t protocol;
Packit Service 672cf4
Packit Service 672cf4
  iocb_data_t status_cb;
Packit Service 672cf4
Packit Service 672cf4
  /* Input, output etc are from the servers perspective.  */
Packit Service 672cf4
  iocb_data_t input_cb;
Packit Service 672cf4
  gpgme_data_t input_helper_data;  /* Input helper data object.  */
Packit Service 672cf4
  void *input_helper_memory;       /* Input helper memory block.  */
Packit Service 672cf4
Packit Service 672cf4
  iocb_data_t output_cb;
Packit Service 672cf4
Packit Service 672cf4
  iocb_data_t message_cb;
Packit Service 672cf4
Packit Service 672cf4
  struct
Packit Service 672cf4
  {
Packit Service 672cf4
    engine_status_handler_t fnc;
Packit Service 672cf4
    void *fnc_value;
Packit Service 672cf4
    gpgme_status_cb_t mon_cb;
Packit Service 672cf4
    void *mon_cb_value;
Packit Service 672cf4
  } status;
Packit Service 672cf4
Packit Service 672cf4
  struct
Packit Service 672cf4
  {
Packit Service 672cf4
    engine_colon_line_handler_t fnc;
Packit Service 672cf4
    void *fnc_value;
Packit Service 672cf4
    struct
Packit Service 672cf4
    {
Packit Service 672cf4
      char *line;
Packit Service 672cf4
      int linesize;
Packit Service 672cf4
      int linelen;
Packit Service 672cf4
    } attic;
Packit Service 672cf4
    int any; /* any data line seen */
Packit Service 672cf4
  } colon;
Packit Service 672cf4
Packit Service 672cf4
  gpgme_data_t inline_data;  /* Used to collect D lines.  */
Packit Service 672cf4
Packit Service 672cf4
  struct gpgme_io_cbs io_cbs;
Packit Service 672cf4
};
Packit Service 672cf4
Packit Service 672cf4
typedef struct engine_uiserver *engine_uiserver_t;
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void uiserver_io_event (void *engine,
Packit Service 672cf4
                            gpgme_event_io_t type, void *type_data);
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
static char *
Packit Service 672cf4
uiserver_get_version (const char *file_name)
Packit Service 672cf4
{
Packit Service 672cf4
  (void)file_name;
Packit Service 672cf4
  return NULL;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static const char *
Packit Service 672cf4
uiserver_get_req_version (void)
Packit Service 672cf4
{
Packit Service 672cf4
  return NULL;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4

Packit Service 672cf4
static void
Packit Service 672cf4
close_notify_handler (int fd, void *opaque)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = opaque;
Packit Service 672cf4
Packit Service 672cf4
  assert (fd != -1);
Packit Service 672cf4
  if (uiserver->status_cb.fd == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (uiserver->status_cb.tag)
Packit Service 672cf4
	(*uiserver->io_cbs.remove) (uiserver->status_cb.tag);
Packit Service 672cf4
      uiserver->status_cb.fd = -1;
Packit Service 672cf4
      uiserver->status_cb.tag = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (uiserver->input_cb.fd == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (uiserver->input_cb.tag)
Packit Service 672cf4
	(*uiserver->io_cbs.remove) (uiserver->input_cb.tag);
Packit Service 672cf4
      uiserver->input_cb.fd = -1;
Packit Service 672cf4
      uiserver->input_cb.tag = NULL;
Packit Service 672cf4
      if (uiserver->input_helper_data)
Packit Service 672cf4
        {
Packit Service 672cf4
          gpgme_data_release (uiserver->input_helper_data);
Packit Service 672cf4
          uiserver->input_helper_data = NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
      if (uiserver->input_helper_memory)
Packit Service 672cf4
        {
Packit Service 672cf4
          free (uiserver->input_helper_memory);
Packit Service 672cf4
          uiserver->input_helper_memory = NULL;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (uiserver->output_cb.fd == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (uiserver->output_cb.tag)
Packit Service 672cf4
	(*uiserver->io_cbs.remove) (uiserver->output_cb.tag);
Packit Service 672cf4
      uiserver->output_cb.fd = -1;
Packit Service 672cf4
      uiserver->output_cb.tag = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
  else if (uiserver->message_cb.fd == fd)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (uiserver->message_cb.tag)
Packit Service 672cf4
	(*uiserver->io_cbs.remove) (uiserver->message_cb.tag);
Packit Service 672cf4
      uiserver->message_cb.fd = -1;
Packit Service 672cf4
      uiserver->message_cb.tag = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* This is the default inquiry callback.  We use it to handle the
Packit Service 672cf4
   Pinentry notifications.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
default_inq_cb (engine_uiserver_t uiserver, const char *line)
Packit Service 672cf4
{
Packit Service 672cf4
  (void)uiserver;
Packit Service 672cf4
Packit Service 672cf4
  if (!strncmp (line, "PINENTRY_LAUNCHED", 17) && (line[17]==' '||!line[17]))
Packit Service 672cf4
    {
Packit Service 672cf4
      _gpgme_allow_set_foreground_window ((pid_t)strtoul (line+17, NULL, 10));
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_cancel (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (!uiserver)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  if (uiserver->status_cb.fd != -1)
Packit Service 672cf4
    _gpgme_io_close (uiserver->status_cb.fd);
Packit Service 672cf4
  if (uiserver->input_cb.fd != -1)
Packit Service 672cf4
    _gpgme_io_close (uiserver->input_cb.fd);
Packit Service 672cf4
  if (uiserver->output_cb.fd != -1)
Packit Service 672cf4
    _gpgme_io_close (uiserver->output_cb.fd);
Packit Service 672cf4
  if (uiserver->message_cb.fd != -1)
Packit Service 672cf4
    _gpgme_io_close (uiserver->message_cb.fd);
Packit Service 672cf4
Packit Service 672cf4
  if (uiserver->assuan_ctx)
Packit Service 672cf4
    {
Packit Service 672cf4
      assuan_release (uiserver->assuan_ctx);
Packit Service 672cf4
      uiserver->assuan_ctx = NULL;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
uiserver_release (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (!uiserver)
Packit Service 672cf4
    return;
Packit Service 672cf4
Packit Service 672cf4
  uiserver_cancel (engine);
Packit Service 672cf4
Packit Service 672cf4
  free (uiserver->colon.attic.line);
Packit Service 672cf4
  free (uiserver);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_new (void **engine, const char *file_name, const char *home_dir,
Packit Service 672cf4
              const char *version)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  engine_uiserver_t uiserver;
Packit Service 672cf4
  char *dft_display = NULL;
Packit Service 672cf4
  char dft_ttyname[64];
Packit Service 672cf4
  char *env_tty = NULL;
Packit Service 672cf4
  char *dft_ttytype = NULL;
Packit Service 672cf4
  char *optstr;
Packit Service 672cf4
Packit Service 672cf4
  (void)home_dir;
Packit Service 672cf4
  (void)version; /* Not yet used.  */
Packit Service 672cf4
Packit Service 672cf4
  uiserver = calloc (1, sizeof *uiserver);
Packit Service 672cf4
  if (!uiserver)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  uiserver->protocol = GPGME_PROTOCOL_DEFAULT;
Packit Service 672cf4
  uiserver->status_cb.fd = -1;
Packit Service 672cf4
  uiserver->status_cb.dir = 1;
Packit Service 672cf4
  uiserver->status_cb.tag = 0;
Packit Service 672cf4
  uiserver->status_cb.data = uiserver;
Packit Service 672cf4
Packit Service 672cf4
  uiserver->input_cb.fd = -1;
Packit Service 672cf4
  uiserver->input_cb.dir = 0;
Packit Service 672cf4
  uiserver->input_cb.tag = 0;
Packit Service 672cf4
  uiserver->input_cb.server_fd = -1;
Packit Service 672cf4
  *uiserver->input_cb.server_fd_str = 0;
Packit Service 672cf4
  uiserver->output_cb.fd = -1;
Packit Service 672cf4
  uiserver->output_cb.dir = 1;
Packit Service 672cf4
  uiserver->output_cb.tag = 0;
Packit Service 672cf4
  uiserver->output_cb.server_fd = -1;
Packit Service 672cf4
  *uiserver->output_cb.server_fd_str = 0;
Packit Service 672cf4
  uiserver->message_cb.fd = -1;
Packit Service 672cf4
  uiserver->message_cb.dir = 0;
Packit Service 672cf4
  uiserver->message_cb.tag = 0;
Packit Service 672cf4
  uiserver->message_cb.server_fd = -1;
Packit Service 672cf4
  *uiserver->message_cb.server_fd_str = 0;
Packit Service 672cf4
Packit Service 672cf4
  uiserver->status.fnc = 0;
Packit Service 672cf4
  uiserver->colon.fnc = 0;
Packit Service 672cf4
  uiserver->colon.attic.line = 0;
Packit Service 672cf4
  uiserver->colon.attic.linesize = 0;
Packit Service 672cf4
  uiserver->colon.attic.linelen = 0;
Packit Service 672cf4
  uiserver->colon.any = 0;
Packit Service 672cf4
Packit Service 672cf4
  uiserver->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  uiserver->io_cbs.add = NULL;
Packit Service 672cf4
  uiserver->io_cbs.add_priv = NULL;
Packit Service 672cf4
  uiserver->io_cbs.remove = NULL;
Packit Service 672cf4
  uiserver->io_cbs.event = NULL;
Packit Service 672cf4
  uiserver->io_cbs.event_priv = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = assuan_new_ext (&uiserver->assuan_ctx, GPG_ERR_SOURCE_GPGME,
Packit Service 672cf4
			&_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb,
Packit Service 672cf4
			NULL);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
  assuan_ctx_set_system_hooks (uiserver->assuan_ctx,
Packit Service 672cf4
			       &_gpgme_assuan_system_hooks);
Packit Service 672cf4
Packit Service 672cf4
  err = assuan_socket_connect (uiserver->assuan_ctx,
Packit Service 672cf4
			       file_name ?
Packit Service 672cf4
			       file_name : _gpgme_get_default_uisrv_socket (),
Packit Service 672cf4
			       0, ASSUAN_SOCKET_SERVER_FDPASSING);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_getenv ("DISPLAY", &dft_display);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave;
Packit Service 672cf4
  if (dft_display)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (gpgrt_asprintf (&optstr, "OPTION display=%s", dft_display) < 0)
Packit Service 672cf4
        {
Packit Service 672cf4
	  err = gpg_error_from_syserror ();
Packit Service 672cf4
	  free (dft_display);
Packit Service 672cf4
	  goto leave;
Packit Service 672cf4
	}
Packit Service 672cf4
      free (dft_display);
Packit Service 672cf4
Packit Service 672cf4
      err = assuan_transact (uiserver->assuan_ctx, optstr, NULL, NULL, NULL,
Packit Service 672cf4
			     NULL, NULL, NULL);
Packit Service 672cf4
      gpgrt_free (optstr);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	goto leave;
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  err = _gpgme_getenv ("GPG_TTY", &env_tty);
Packit Service 672cf4
  if (isatty (1) || env_tty || err)
Packit Service 672cf4
    {
Packit Service 672cf4
      int rc = 0;
Packit Service 672cf4
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        goto leave;
Packit Service 672cf4
      else if (env_tty)
Packit Service 672cf4
        {
Packit Service 672cf4
          snprintf (dft_ttyname, sizeof (dft_ttyname), "%s", env_tty);
Packit Service 672cf4
          free (env_tty);
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
        rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname));
Packit Service 672cf4
Packit Service 672cf4
      /* Even though isatty() returns 1, ttyname_r() may fail in many
Packit Service 672cf4
	 ways, e.g., when /dev/pts is not accessible under chroot.  */
Packit Service 672cf4
      if (!rc)
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (gpgrt_asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      err = gpg_error_from_syserror ();
Packit Service 672cf4
	      goto leave;
Packit Service 672cf4
	    }
Packit Service 672cf4
	  err = assuan_transact (uiserver->assuan_ctx, optstr, NULL, NULL, NULL,
Packit Service 672cf4
				 NULL, NULL, NULL);
Packit Service 672cf4
	  gpgrt_free (optstr);
Packit Service 672cf4
	  if (err)
Packit Service 672cf4
	    goto leave;
Packit Service 672cf4
Packit Service 672cf4
	  err = _gpgme_getenv ("TERM", &dft_ttytype);
Packit Service 672cf4
	  if (err)
Packit Service 672cf4
	    goto leave;
Packit Service 672cf4
	  if (dft_ttytype)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      if (gpgrt_asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype)< 0)
Packit Service 672cf4
		{
Packit Service 672cf4
		  err = gpg_error_from_syserror ();
Packit Service 672cf4
		  free (dft_ttytype);
Packit Service 672cf4
		  goto leave;
Packit Service 672cf4
		}
Packit Service 672cf4
	      free (dft_ttytype);
Packit Service 672cf4
Packit Service 672cf4
	      err = assuan_transact (uiserver->assuan_ctx, optstr, NULL, NULL,
Packit Service 672cf4
				     NULL, NULL, NULL, NULL);
Packit Service 672cf4
	      gpgrt_free (optstr);
Packit Service 672cf4
	      if (err)
Packit Service 672cf4
		goto leave;
Packit Service 672cf4
	    }
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
#ifdef HAVE_W32_SYSTEM
Packit Service 672cf4
  /* Under Windows we need to use AllowSetForegroundWindow.  Tell
Packit Service 672cf4
     uiserver to tell us when it needs it.  */
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    {
Packit Service 672cf4
      err = assuan_transact (uiserver->assuan_ctx, "OPTION allow-pinentry-notify",
Packit Service 672cf4
                             NULL, NULL, NULL, NULL, NULL, NULL);
Packit Service 672cf4
      if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION)
Packit Service 672cf4
        err = 0; /* This is a new feature of uiserver.  */
Packit Service 672cf4
    }
Packit Service 672cf4
#endif /*HAVE_W32_SYSTEM*/
Packit Service 672cf4
Packit Service 672cf4
 leave:
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    uiserver_release (uiserver);
Packit Service 672cf4
  else
Packit Service 672cf4
    *engine = uiserver;
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_set_locale (void *engine, int category, const char *value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  char *optstr;
Packit Service 672cf4
  const char *catstr;
Packit Service 672cf4
Packit Service 672cf4
  /* FIXME: If value is NULL, we need to reset the option to default.
Packit Service 672cf4
     But we can't do this.  So we error out here.  UISERVER needs support
Packit Service 672cf4
     for this.  */
Packit Service 672cf4
  if (category == LC_CTYPE)
Packit Service 672cf4
    {
Packit Service 672cf4
      catstr = "lc-ctype";
Packit Service 672cf4
      if (!value && uiserver->lc_ctype_set)
Packit Service 672cf4
	return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      if (value)
Packit Service 672cf4
	uiserver->lc_ctype_set = 1;
Packit Service 672cf4
    }
Packit Service 672cf4
#ifdef LC_MESSAGES
Packit Service 672cf4
  else if (category == LC_MESSAGES)
Packit Service 672cf4
    {
Packit Service 672cf4
      catstr = "lc-messages";
Packit Service 672cf4
      if (!value && uiserver->lc_messages_set)
Packit Service 672cf4
	return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      if (value)
Packit Service 672cf4
	uiserver->lc_messages_set = 1;
Packit Service 672cf4
    }
Packit Service 672cf4
#endif /* LC_MESSAGES */
Packit Service 672cf4
  else
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  /* FIXME: Reset value to default.  */
Packit Service 672cf4
  if (!value)
Packit Service 672cf4
    return 0;
Packit Service 672cf4
Packit Service 672cf4
  if (gpgrt_asprintf (&optstr, "OPTION %s=%s", catstr, value) < 0)
Packit Service 672cf4
    err = gpg_error_from_syserror ();
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      err = assuan_transact (uiserver->assuan_ctx, optstr, NULL, NULL,
Packit Service 672cf4
			     NULL, NULL, NULL, NULL);
Packit Service 672cf4
      gpgrt_free (optstr);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_set_protocol (void *engine, gpgme_protocol_t protocol)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
Packit Service 672cf4
  if (protocol != GPGME_PROTOCOL_OpenPGP
Packit Service 672cf4
      && protocol != GPGME_PROTOCOL_CMS
Packit Service 672cf4
      && protocol != GPGME_PROTOCOL_DEFAULT)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
  uiserver->protocol = protocol;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_assuan_simple_command (engine_uiserver_t uiserver, const char *cmd,
Packit Service 672cf4
                                engine_status_handler_t status_fnc,
Packit Service 672cf4
                                void *status_fnc_value)
Packit Service 672cf4
{
Packit Service 672cf4
  assuan_context_t ctx = uiserver->assuan_ctx;
Packit Service 672cf4
  gpg_error_t err;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  size_t linelen;
Packit Service 672cf4
Packit Service 672cf4
  err = assuan_write_line (ctx, cmd);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return err;
Packit Service 672cf4
Packit Service 672cf4
  do
Packit Service 672cf4
    {
Packit Service 672cf4
      err = assuan_read_line (ctx, &line, &linelen);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	return err;
Packit Service 672cf4
Packit Service 672cf4
      if (*line == '#' || !linelen)
Packit Service 672cf4
	continue;
Packit Service 672cf4
Packit Service 672cf4
      if (linelen >= 2
Packit Service 672cf4
	  && line[0] == 'O' && line[1] == 'K'
Packit Service 672cf4
	  && (line[2] == '\0' || line[2] == ' '))
Packit Service 672cf4
	return 0;
Packit Service 672cf4
      else if (linelen >= 4
Packit Service 672cf4
	  && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
Packit Service 672cf4
	  && line[3] == ' ')
Packit Service 672cf4
	err = atoi (&line[4]);
Packit Service 672cf4
      else if (linelen >= 2
Packit Service 672cf4
	       && line[0] == 'S' && line[1] == ' ')
Packit Service 672cf4
	{
Packit Service 672cf4
	  char *rest;
Packit Service 672cf4
	  gpgme_status_code_t r;
Packit Service 672cf4
Packit Service 672cf4
	  rest = strchr (line + 2, ' ');
Packit Service 672cf4
	  if (!rest)
Packit Service 672cf4
	    rest = line + linelen; /* set to an empty string */
Packit Service 672cf4
	  else
Packit Service 672cf4
	    *(rest++) = 0;
Packit Service 672cf4
Packit Service 672cf4
	  r = _gpgme_parse_status (line + 2);
Packit Service 672cf4
          if (uiserver->status.mon_cb && r != GPGME_STATUS_PROGRESS)
Packit Service 672cf4
            {
Packit Service 672cf4
              /* Note that we call the monitor even if we do
Packit Service 672cf4
               * not know the status code (r < 0).  */
Packit Service 672cf4
              err = uiserver->status.mon_cb (uiserver->status.mon_cb_value,
Packit Service 672cf4
                                             line + 2, rest);
Packit Service 672cf4
            }
Packit Service 672cf4
Packit Service 672cf4
          if (err)
Packit Service 672cf4
            ;
Packit Service 672cf4
	  else if (r >= 0 && status_fnc)
Packit Service 672cf4
	    err = status_fnc (status_fnc_value, r, rest);
Packit Service 672cf4
	  else
Packit Service 672cf4
	    err = gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
	}
Packit Service 672cf4
      else
Packit Service 672cf4
	err = gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
    }
Packit Service 672cf4
  while (!err);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
typedef enum { INPUT_FD, OUTPUT_FD, MESSAGE_FD } fd_type_t;
Packit Service 672cf4
Packit Service 672cf4
#define COMMANDLINELEN 40
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_set_fd (engine_uiserver_t uiserver, fd_type_t fd_type, const char *opt)
Packit Service 672cf4
{
Packit Service 672cf4
  gpg_error_t err = 0;
Packit Service 672cf4
  char line[COMMANDLINELEN];
Packit Service 672cf4
  const char *which;
Packit Service 672cf4
  iocb_data_t *iocb_data;
Packit Service 672cf4
  int dir;
Packit Service 672cf4
Packit Service 672cf4
  switch (fd_type)
Packit Service 672cf4
    {
Packit Service 672cf4
    case INPUT_FD:
Packit Service 672cf4
      which = "INPUT";
Packit Service 672cf4
      iocb_data = &uiserver->input_cb;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case OUTPUT_FD:
Packit Service 672cf4
      which = "OUTPUT";
Packit Service 672cf4
      iocb_data = &uiserver->output_cb;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    case MESSAGE_FD:
Packit Service 672cf4
      which = "MESSAGE";
Packit Service 672cf4
      iocb_data = &uiserver->message_cb;
Packit Service 672cf4
      break;
Packit Service 672cf4
Packit Service 672cf4
    default:
Packit Service 672cf4
      return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  dir = iocb_data->dir;
Packit Service 672cf4
Packit Service 672cf4
  /* We try to short-cut the communication by giving UISERVER direct
Packit Service 672cf4
     access to the file descriptor, rather than using a pipe.  */
Packit Service 672cf4
  iocb_data->server_fd = _gpgme_data_get_fd (iocb_data->data);
Packit Service 672cf4
  if (iocb_data->server_fd < 0)
Packit Service 672cf4
    {
Packit Service 672cf4
      int fds[2];
Packit Service 672cf4
Packit Service 672cf4
      if (_gpgme_io_pipe (fds, 0) < 0)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
      iocb_data->fd = dir ? fds[0] : fds[1];
Packit Service 672cf4
      iocb_data->server_fd = dir ? fds[1] : fds[0];
Packit Service 672cf4
Packit Service 672cf4
      if (_gpgme_io_set_close_notify (iocb_data->fd,
Packit Service 672cf4
				      close_notify_handler, uiserver))
Packit Service 672cf4
	{
Packit Service 672cf4
	  err = gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
	  goto leave_set_fd;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  err = assuan_sendfd (uiserver->assuan_ctx, iocb_data->server_fd);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    goto leave_set_fd;
Packit Service 672cf4
Packit Service 672cf4
  _gpgme_io_close (iocb_data->server_fd);
Packit Service 672cf4
  iocb_data->server_fd = -1;
Packit Service 672cf4
Packit Service 672cf4
  if (opt)
Packit Service 672cf4
    snprintf (line, COMMANDLINELEN, "%s FD %s", which, opt);
Packit Service 672cf4
  else
Packit Service 672cf4
    snprintf (line, COMMANDLINELEN, "%s FD", which);
Packit Service 672cf4
Packit Service 672cf4
  err = uiserver_assuan_simple_command (uiserver, line, NULL, NULL);
Packit Service 672cf4
Packit Service 672cf4
 leave_set_fd:
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    {
Packit Service 672cf4
      _gpgme_io_close (iocb_data->fd);
Packit Service 672cf4
      iocb_data->fd = -1;
Packit Service 672cf4
      if (iocb_data->server_fd != -1)
Packit Service 672cf4
        {
Packit Service 672cf4
          _gpgme_io_close (iocb_data->server_fd);
Packit Service 672cf4
          iocb_data->server_fd = -1;
Packit Service 672cf4
        }
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static const char *
Packit Service 672cf4
map_data_enc (gpgme_data_t d)
Packit Service 672cf4
{
Packit Service 672cf4
  switch (gpgme_data_get_encoding (d))
Packit Service 672cf4
    {
Packit Service 672cf4
    case GPGME_DATA_ENCODING_NONE:
Packit Service 672cf4
      break;
Packit Service 672cf4
    case GPGME_DATA_ENCODING_BINARY:
Packit Service 672cf4
      return "--binary";
Packit Service 672cf4
    case GPGME_DATA_ENCODING_BASE64:
Packit Service 672cf4
      return "--base64";
Packit Service 672cf4
    case GPGME_DATA_ENCODING_ARMOR:
Packit Service 672cf4
      return "--armor";
Packit Service 672cf4
    default:
Packit Service 672cf4
      break;
Packit Service 672cf4
    }
Packit Service 672cf4
  return NULL;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
status_handler (void *opaque, int fd)
Packit Service 672cf4
{
Packit Service 672cf4
  struct io_cb_data *data = (struct io_cb_data *) opaque;
Packit Service 672cf4
  engine_uiserver_t uiserver = (engine_uiserver_t) data->handler_value;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  size_t linelen;
Packit Service 672cf4
Packit Service 672cf4
  do
Packit Service 672cf4
    {
Packit Service 672cf4
      err = assuan_read_line (uiserver->assuan_ctx, &line, &linelen);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	{
Packit Service 672cf4
	  /* Try our best to terminate the connection friendly.  */
Packit Service 672cf4
	  /*	  assuan_write_line (uiserver->assuan_ctx, "BYE"); */
Packit Service 6c01f9
          TRACE3 (DEBUG_CTX, "gpgme:status_handler", uiserver,
Packit Service 672cf4
		  "fd 0x%x: error from assuan (%d) getting status line : %s",
Packit Service 672cf4
                  fd, err, gpg_strerror (err));
Packit Service 672cf4
	}
Packit Service 672cf4
      else if (linelen >= 3
Packit Service 672cf4
	       && line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
Packit Service 672cf4
	       && (line[3] == '\0' || line[3] == ' '))
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (line[3] == ' ')
Packit Service 672cf4
	    err = atoi (&line[4]);
Packit Service 672cf4
	  if (! err)
Packit Service 672cf4
	    err = gpg_error (GPG_ERR_GENERAL);
Packit Service 6c01f9
          TRACE2 (DEBUG_CTX, "gpgme:status_handler", uiserver,
Packit Service 672cf4
		  "fd 0x%x: ERR line - mapped to: %s",
Packit Service 672cf4
                  fd, err ? gpg_strerror (err) : "ok");
Packit Service 672cf4
	  /* Try our best to terminate the connection friendly.  */
Packit Service 672cf4
	  /*	  assuan_write_line (uiserver->assuan_ctx, "BYE"); */
Packit Service 672cf4
	}
Packit Service 672cf4
      else if (linelen >= 2
Packit Service 672cf4
	       && line[0] == 'O' && line[1] == 'K'
Packit Service 672cf4
	       && (line[2] == '\0' || line[2] == ' '))
Packit Service 672cf4
	{
Packit Service 672cf4
	  if (uiserver->status.fnc)
Packit Service 672cf4
            {
Packit Service 672cf4
              char emptystring[1] = {0};
Packit Service 672cf4
              err = uiserver->status.fnc (uiserver->status.fnc_value,
Packit Service 672cf4
                                          GPGME_STATUS_EOF, emptystring);
Packit Service 672cf4
              if (gpg_err_code (err) == GPG_ERR_FALSE)
Packit Service 672cf4
                err = 0; /* Drop special error code.  */
Packit Service 672cf4
            }
Packit Service 672cf4
Packit Service 672cf4
	  if (!err && uiserver->colon.fnc && uiserver->colon.any)
Packit Service 672cf4
            {
Packit Service 672cf4
              /* We must tell a colon function about the EOF. We do
Packit Service 672cf4
                 this only when we have seen any data lines.  Note
Packit Service 672cf4
                 that this inlined use of colon data lines will
Packit Service 672cf4
                 eventually be changed into using a regular data
Packit Service 672cf4
                 channel. */
Packit Service 672cf4
              uiserver->colon.any = 0;
Packit Service 672cf4
              err = uiserver->colon.fnc (uiserver->colon.fnc_value, NULL);
Packit Service 672cf4
            }
Packit Service 6c01f9
          TRACE2 (DEBUG_CTX, "gpgme:status_handler", uiserver,
Packit Service 672cf4
		  "fd 0x%x: OK line - final status: %s",
Packit Service 672cf4
                  fd, err ? gpg_strerror (err) : "ok");
Packit Service 672cf4
	  _gpgme_io_close (uiserver->status_cb.fd);
Packit Service 672cf4
	  return err;
Packit Service 672cf4
	}
Packit Service 672cf4
      else if (linelen > 2
Packit Service 672cf4
	       && line[0] == 'D' && line[1] == ' '
Packit Service 672cf4
	       && uiserver->colon.fnc)
Packit Service 672cf4
        {
Packit Service 672cf4
	  /* We are using the colon handler even for plain inline data
Packit Service 672cf4
             - strange name for that function but for historic reasons
Packit Service 672cf4
             we keep it.  */
Packit Service 672cf4
          /* FIXME We can't use this for binary data because we
Packit Service 672cf4
             assume this is a string.  For the current usage of colon
Packit Service 672cf4
             output it is correct.  */
Packit Service 672cf4
          char *src = line + 2;
Packit Service 672cf4
	  char *end = line + linelen;
Packit Service 672cf4
	  char *dst;
Packit Service 672cf4
          char **aline = &uiserver->colon.attic.line;
Packit Service 672cf4
	  int *alinelen = &uiserver->colon.attic.linelen;
Packit Service 672cf4
Packit Service 672cf4
	  if (uiserver->colon.attic.linesize < *alinelen + linelen + 1)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      char *newline = realloc (*aline, *alinelen + linelen + 1);
Packit Service 672cf4
	      if (!newline)
Packit Service 672cf4
		err = gpg_error_from_syserror ();
Packit Service 672cf4
	      else
Packit Service 672cf4
		{
Packit Service 672cf4
		  *aline = newline;
Packit Service 672cf4
		  uiserver->colon.attic.linesize = *alinelen + linelen + 1;
Packit Service 672cf4
		}
Packit Service 672cf4
	    }
Packit Service 672cf4
	  if (!err)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      dst = *aline + *alinelen;
Packit Service 672cf4
Packit Service 672cf4
	      while (!err && src < end)
Packit Service 672cf4
		{
Packit Service 672cf4
		  if (*src == '%' && src + 2 < end)
Packit Service 672cf4
		    {
Packit Service 672cf4
		      /* Handle escaped characters.  */
Packit Service 672cf4
		      ++src;
Packit Service 672cf4
		      *dst = _gpgme_hextobyte (src);
Packit Service 672cf4
		      (*alinelen)++;
Packit Service 672cf4
		      src += 2;
Packit Service 672cf4
		    }
Packit Service 672cf4
		  else
Packit Service 672cf4
		    {
Packit Service 672cf4
		      *dst = *src++;
Packit Service 672cf4
		      (*alinelen)++;
Packit Service 672cf4
		    }
Packit Service 672cf4
Packit Service 672cf4
		  if (*dst == '\n')
Packit Service 672cf4
		    {
Packit Service 672cf4
		      /* Terminate the pending line, pass it to the colon
Packit Service 672cf4
			 handler and reset it.  */
Packit Service 672cf4
Packit Service 672cf4
		      uiserver->colon.any = 1;
Packit Service 672cf4
		      if (*alinelen > 1 && *(dst - 1) == '\r')
Packit Service 672cf4
			dst--;
Packit Service 672cf4
		      *dst = '\0';
Packit Service 672cf4
Packit Service 672cf4
		      /* FIXME How should we handle the return code?  */
Packit Service 672cf4
		      err = uiserver->colon.fnc (uiserver->colon.fnc_value, *aline);
Packit Service 672cf4
		      if (!err)
Packit Service 672cf4
			{
Packit Service 672cf4
			  dst = *aline;
Packit Service 672cf4
			  *alinelen = 0;
Packit Service 672cf4
			}
Packit Service 672cf4
		    }
Packit Service 672cf4
		  else
Packit Service 672cf4
		    dst++;
Packit Service 672cf4
		}
Packit Service 672cf4
	    }
Packit Service 6c01f9
          TRACE2 (DEBUG_CTX, "gpgme:status_handler", uiserver,
Packit Service 672cf4
		  "fd 0x%x: D line; final status: %s",
Packit Service 672cf4
                  fd, err? gpg_strerror (err):"ok");
Packit Service 672cf4
        }
Packit Service 672cf4
      else if (linelen > 2
Packit Service 672cf4
	       && line[0] == 'D' && line[1] == ' '
Packit Service 672cf4
	       && uiserver->inline_data)
Packit Service 672cf4
        {
Packit Service 672cf4
          char *src = line + 2;
Packit Service 672cf4
	  char *end = line + linelen;
Packit Service 672cf4
	  char *dst = src;
Packit Service 672cf4
          gpgme_ssize_t nwritten;
Packit Service 672cf4
Packit Service 672cf4
          linelen = 0;
Packit Service 672cf4
          while (src < end)
Packit Service 672cf4
            {
Packit Service 672cf4
              if (*src == '%' && src + 2 < end)
Packit Service 672cf4
                {
Packit Service 672cf4
                  /* Handle escaped characters.  */
Packit Service 672cf4
                  ++src;
Packit Service 672cf4
                  *dst++ = _gpgme_hextobyte (src);
Packit Service 672cf4
                  src += 2;
Packit Service 672cf4
                }
Packit Service 672cf4
              else
Packit Service 672cf4
                *dst++ = *src++;
Packit Service 672cf4
Packit Service 672cf4
              linelen++;
Packit Service 672cf4
            }
Packit Service 672cf4
Packit Service 672cf4
          src = line + 2;
Packit Service 672cf4
          while (linelen > 0)
Packit Service 672cf4
            {
Packit Service 672cf4
              nwritten = gpgme_data_write (uiserver->inline_data, src, linelen);
Packit Service 672cf4
              if (!nwritten || (nwritten < 0 && errno != EINTR)
Packit Service 672cf4
                  || nwritten > linelen)
Packit Service 672cf4
                {
Packit Service 672cf4
                  err = gpg_error_from_syserror ();
Packit Service 672cf4
                  break;
Packit Service 672cf4
                }
Packit Service 672cf4
              src += nwritten;
Packit Service 672cf4
              linelen -= nwritten;
Packit Service 672cf4
            }
Packit Service 672cf4
Packit Service 6c01f9
          TRACE2 (DEBUG_CTX, "gpgme:status_handler", uiserver,
Packit Service 672cf4
		  "fd 0x%x: D inlinedata; final status: %s",
Packit Service 672cf4
                  fd, err? gpg_strerror (err):"ok");
Packit Service 672cf4
        }
Packit Service 672cf4
      else if (linelen > 2
Packit Service 672cf4
	       && line[0] == 'S' && line[1] == ' ')
Packit Service 672cf4
	{
Packit Service 672cf4
	  char *rest;
Packit Service 672cf4
	  gpgme_status_code_t r;
Packit Service 672cf4
Packit Service 672cf4
	  rest = strchr (line + 2, ' ');
Packit Service 672cf4
	  if (!rest)
Packit Service 672cf4
	    rest = line + linelen; /* set to an empty string */
Packit Service 672cf4
	  else
Packit Service 672cf4
	    *(rest++) = 0;
Packit Service 672cf4
Packit Service 672cf4
	  r = _gpgme_parse_status (line + 2);
Packit Service 672cf4
Packit Service 672cf4
	  if (r >= 0)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      if (uiserver->status.fnc)
Packit Service 672cf4
                {
Packit Service 672cf4
                  err = uiserver->status.fnc (uiserver->status.fnc_value,
Packit Service 672cf4
                                              r, rest);
Packit Service 672cf4
                  if (gpg_err_code (err) == GPG_ERR_FALSE)
Packit Service 672cf4
                    err = 0; /* Drop special error code.  */
Packit Service 672cf4
                }
Packit Service 672cf4
	    }
Packit Service 672cf4
	  else
Packit Service 672cf4
	    fprintf (stderr, "[UNKNOWN STATUS]%s %s", line + 2, rest);
Packit Service 6c01f9
          TRACE3 (DEBUG_CTX, "gpgme:status_handler", uiserver,
Packit Service 672cf4
		  "fd 0x%x: S line (%s) - final status: %s",
Packit Service 672cf4
                  fd, line+2, err? gpg_strerror (err):"ok");
Packit Service 672cf4
	}
Packit Service 672cf4
      else if (linelen >= 7
Packit Service 672cf4
               && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
Packit Service 672cf4
               && line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
Packit Service 672cf4
               && line[6] == 'E'
Packit Service 672cf4
               && (line[7] == '\0' || line[7] == ' '))
Packit Service 672cf4
        {
Packit Service 672cf4
          char *keyword = line+7;
Packit Service 672cf4
Packit Service 672cf4
          while (*keyword == ' ')
Packit Service 672cf4
            keyword++;;
Packit Service 672cf4
          default_inq_cb (uiserver, keyword);
Packit Service 672cf4
          assuan_write_line (uiserver->assuan_ctx, "END");
Packit Service 672cf4
        }
Packit Service 672cf4
Packit Service 672cf4
    }
Packit Service 672cf4
  while (!err && assuan_pending_line (uiserver->assuan_ctx));
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
add_io_cb (engine_uiserver_t uiserver, iocb_data_t *iocbd, gpgme_io_cb_t handler)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
Packit Service 6c01f9
  TRACE_BEG2 (DEBUG_ENGINE, "engine-uiserver:add_io_cb", uiserver,
Packit Service 6c01f9
              "fd %d, dir %d", iocbd->fd, iocbd->dir);
Packit Service 672cf4
  err = (*uiserver->io_cbs.add) (uiserver->io_cbs.add_priv,
Packit Service 672cf4
			      iocbd->fd, iocbd->dir,
Packit Service 672cf4
			      handler, iocbd->data, &iocbd->tag);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    return TRACE_ERR (err);
Packit Service 672cf4
  if (!iocbd->dir)
Packit Service 672cf4
    /* FIXME Kludge around poll() problem.  */
Packit Service 672cf4
    err = _gpgme_io_set_nonblocking (iocbd->fd);
Packit Service 672cf4
  return TRACE_ERR (err);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
start (engine_uiserver_t uiserver, const char *command)
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  int fdlist[5];
Packit Service 672cf4
  int nfds;
Packit Service 672cf4
Packit Service 672cf4
  /* We need to know the fd used by assuan for reads.  We do this by
Packit Service 672cf4
     using the assumption that the first returned fd from
Packit Service 672cf4
     assuan_get_active_fds() is always this one.  */
Packit Service 672cf4
  nfds = assuan_get_active_fds (uiserver->assuan_ctx, 0 /* read fds */,
Packit Service 672cf4
                                fdlist, DIM (fdlist));
Packit Service 672cf4
  if (nfds < 1)
Packit Service 672cf4
    return gpg_error (GPG_ERR_GENERAL);	/* FIXME */
Packit Service 672cf4
Packit Service 672cf4
  /* We "duplicate" the file descriptor, so we can close it here (we
Packit Service 672cf4
     can't close fdlist[0], as that is closed by libassuan, and
Packit Service 672cf4
     closing it here might cause libassuan to close some unrelated FD
Packit Service 672cf4
     later).  Alternatively, we could special case status_fd and
Packit Service 672cf4
     register/unregister it manually as needed, but this increases
Packit Service 672cf4
     code duplication and is more complicated as we can not use the
Packit Service 672cf4
     close notifications etc.  A third alternative would be to let
Packit Service 672cf4
     Assuan know that we closed the FD, but that complicates the
Packit Service 672cf4
     Assuan interface.  */
Packit Service 672cf4
Packit Service 672cf4
  uiserver->status_cb.fd = _gpgme_io_dup (fdlist[0]);
Packit Service 672cf4
  if (uiserver->status_cb.fd < 0)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  if (_gpgme_io_set_close_notify (uiserver->status_cb.fd,
Packit Service 672cf4
				  close_notify_handler, uiserver))
Packit Service 672cf4
    {
Packit Service 672cf4
      _gpgme_io_close (uiserver->status_cb.fd);
Packit Service 672cf4
      uiserver->status_cb.fd = -1;
Packit Service 672cf4
      return gpg_error (GPG_ERR_GENERAL);
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  err = add_io_cb (uiserver, &uiserver->status_cb, status_handler);
Packit Service 672cf4
  if (!err && uiserver->input_cb.fd != -1)
Packit Service 672cf4
    err = add_io_cb (uiserver, &uiserver->input_cb, _gpgme_data_outbound_handler);
Packit Service 672cf4
  if (!err && uiserver->output_cb.fd != -1)
Packit Service 672cf4
    err = add_io_cb (uiserver, &uiserver->output_cb, _gpgme_data_inbound_handler);
Packit Service 672cf4
  if (!err && uiserver->message_cb.fd != -1)
Packit Service 672cf4
    err = add_io_cb (uiserver, &uiserver->message_cb, _gpgme_data_outbound_handler);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = assuan_write_line (uiserver->assuan_ctx, command);
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    uiserver_io_event (uiserver, GPGME_EVENT_START, NULL);
Packit Service 672cf4
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_reset (void *engine)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
Packit Service 672cf4
  /* We must send a reset because we need to reset the list of
Packit Service 672cf4
     signers.  Note that RESET does not reset OPTION commands. */
Packit Service 672cf4
  return uiserver_assuan_simple_command (uiserver, "RESET", NULL, NULL);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_decrypt (void *engine,
Packit Service 672cf4
                  gpgme_decrypt_flags_t flags,
Packit Service 672cf4
                  gpgme_data_t ciph, gpgme_data_t plain,
Packit Service 672cf4
                  int export_session_key, const char *override_session_key,
Packit Service 672cf4
                  int auto_key_retrieve)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  const char *protocol;
Packit Service 672cf4
  char *cmd;
Packit Service 672cf4
  int verify = !!(flags & GPGME_DECRYPT_VERIFY);
Packit Service 672cf4
Packit Service 672cf4
  (void)override_session_key; /* Fixme: We need to see now to add this
Packit Service 672cf4
                               * to the UI server protocol  */
Packit Service 672cf4
  (void)auto_key_retrieve;    /* Not yet supported.  */
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
  if (!uiserver)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
  if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
Packit Service 672cf4
    protocol = "";
Packit Service 672cf4
  else if (uiserver->protocol == GPGME_PROTOCOL_OpenPGP)
Packit Service 672cf4
    protocol = " --protocol=OpenPGP";
Packit Service 672cf4
  else if (uiserver->protocol == GPGME_PROTOCOL_CMS)
Packit Service 672cf4
    protocol = " --protocol=CMS";
Packit Service 672cf4
  else
Packit Service 672cf4
    return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
Packit Service 672cf4
Packit Service 672cf4
  if (gpgrt_asprintf (&cmd, "DECRYPT%s%s%s", protocol,
Packit Service 672cf4
		verify ? "" : " --no-verify",
Packit Service 672cf4
                export_session_key ? " --export-session-key" : "") < 0)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  uiserver->input_cb.data = ciph;
Packit Service 672cf4
  err = uiserver_set_fd (uiserver, INPUT_FD,
Packit Service 672cf4
			 map_data_enc (uiserver->input_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgrt_free (cmd);
Packit Service 672cf4
      return gpg_error (GPG_ERR_GENERAL);	/* FIXME */
Packit Service 672cf4
    }
Packit Service 672cf4
  uiserver->output_cb.data = plain;
Packit Service 672cf4
  err = uiserver_set_fd (uiserver, OUTPUT_FD, 0);
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgrt_free (cmd);
Packit Service 672cf4
      return gpg_error (GPG_ERR_GENERAL);	/* FIXME */
Packit Service 672cf4
    }
Packit Service 672cf4
  uiserver->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (engine, cmd);
Packit Service 672cf4
  gpgrt_free (cmd);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
set_recipients (engine_uiserver_t uiserver, gpgme_key_t recp[])
Packit Service 672cf4
{
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  char *line;
Packit Service 672cf4
  int linelen;
Packit Service 672cf4
  int invalid_recipients = 0;
Packit Service 672cf4
  int i;
Packit Service 672cf4
Packit Service 672cf4
  linelen = 10 + 40 + 1;	/* "RECIPIENT " + guess + '\0'.  */
Packit Service 672cf4
  line = malloc (10 + 40 + 1);
Packit Service 672cf4
  if (!line)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
  strcpy (line, "RECIPIENT ");
Packit Service 672cf4
  for (i=0; !err && recp[i]; i++)
Packit Service 672cf4
    {
Packit Service 672cf4
      char *uid;
Packit Service 672cf4
      int newlen;
Packit Service 672cf4
Packit Service 672cf4
      /* We use only the first user ID of the key.  */
Packit Service 672cf4
      if (!recp[i]->uids || !(uid=recp[i]->uids->uid) || !*uid)
Packit Service 672cf4
	{
Packit Service 672cf4
	  invalid_recipients++;
Packit Service 672cf4
	  continue;
Packit Service 672cf4
	}
Packit Service 672cf4
Packit Service 672cf4
      newlen = 11 + strlen (uid);
Packit Service 672cf4
      if (linelen < newlen)
Packit Service 672cf4
	{
Packit Service 672cf4
	  char *newline = realloc (line, newlen);
Packit Service 672cf4
	  if (! newline)
Packit Service 672cf4
	    {
Packit Service 672cf4
	      int saved_err = gpg_error_from_syserror ();
Packit Service 672cf4
	      free (line);
Packit Service 672cf4
	      return saved_err;
Packit Service 672cf4
	    }
Packit Service 672cf4
	  line = newline;
Packit Service 672cf4
	  linelen = newlen;
Packit Service 672cf4
	}
Packit Service 672cf4
      /* FIXME: need to do proper escaping  */
Packit Service 672cf4
      strcpy (&line[10], uid);
Packit Service 672cf4
Packit Service 672cf4
      err = uiserver_assuan_simple_command (uiserver, line,
Packit Service 672cf4
                                            uiserver->status.fnc,
Packit Service 672cf4
                                            uiserver->status.fnc_value);
Packit Service 672cf4
      /* FIXME: This might requires more work.  */
Packit Service 672cf4
      if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY)
Packit Service 672cf4
	invalid_recipients++;
Packit Service 672cf4
      else if (err)
Packit Service 672cf4
	{
Packit Service 672cf4
	  free (line);
Packit Service 672cf4
	  return err;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
  free (line);
Packit Service 672cf4
  return gpg_error (invalid_recipients
Packit Service 672cf4
		    ? GPG_ERR_UNUSABLE_PUBKEY : GPG_ERR_NO_ERROR);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 6c01f9
uiserver_encrypt (void *engine, gpgme_key_t recp[], gpgme_encrypt_flags_t flags,
Packit Service 672cf4
		  gpgme_data_t plain, gpgme_data_t ciph, int use_armor)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  const char *protocol;
Packit Service 672cf4
  char *cmd;
Packit Service 672cf4
Packit Service 672cf4
  if (!uiserver)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
  if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
Packit Service 672cf4
    protocol = "";
Packit Service 672cf4
  else if (uiserver->protocol == GPGME_PROTOCOL_OpenPGP)
Packit Service 672cf4
    protocol = " --protocol=OpenPGP";
Packit Service 672cf4
  else if (uiserver->protocol == GPGME_PROTOCOL_CMS)
Packit Service 672cf4
    protocol = " --protocol=CMS";
Packit Service 672cf4
  else
Packit Service 672cf4
    return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
Packit Service 672cf4
Packit Service 672cf4
  if (flags & GPGME_ENCRYPT_PREPARE)
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!recp || plain || ciph)
Packit Service 672cf4
	return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
      if (gpgrt_asprintf (&cmd, "PREP_ENCRYPT%s%s", protocol,
Packit Service 672cf4
		    (flags & GPGME_ENCRYPT_EXPECT_SIGN)
Packit Service 672cf4
		    ? " --expect-sign" : "") < 0)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      if (!plain || !ciph)
Packit Service 672cf4
	return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
Packit Service 672cf4
      if (gpgrt_asprintf (&cmd, "ENCRYPT%s", protocol) < 0)
Packit Service 672cf4
	return gpg_error_from_syserror ();
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (plain)
Packit Service 672cf4
    {
Packit Service 672cf4
      uiserver->input_cb.data = plain;
Packit Service 672cf4
      err = uiserver_set_fd (uiserver, INPUT_FD,
Packit Service 672cf4
			     map_data_enc (uiserver->input_cb.data));
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	{
Packit Service 672cf4
	  gpgrt_free (cmd);
Packit Service 672cf4
	  return err;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  if (ciph)
Packit Service 672cf4
    {
Packit Service 672cf4
      uiserver->output_cb.data = ciph;
Packit Service 672cf4
      err = uiserver_set_fd (uiserver, OUTPUT_FD, use_armor ? "--armor"
Packit Service 672cf4
			     : map_data_enc (uiserver->output_cb.data));
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	{
Packit Service 672cf4
	  gpgrt_free (cmd);
Packit Service 672cf4
	  return err;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  uiserver->inline_data = NULL;
Packit Service 672cf4
Packit Service 6c01f9
  if (recp)
Packit Service 672cf4
    {
Packit Service 6c01f9
      err = set_recipients (uiserver, recp);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
	{
Packit Service 672cf4
	  gpgrt_free (cmd);
Packit Service 672cf4
	  return err;
Packit Service 672cf4
	}
Packit Service 672cf4
    }
Packit Service 672cf4
Packit Service 672cf4
  err = start (uiserver, cmd);
Packit Service 672cf4
  gpgrt_free (cmd);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_sign (void *engine, gpgme_data_t in, gpgme_data_t out,
Packit Service 672cf4
	       gpgme_sig_mode_t mode, int use_armor, int use_textmode,
Packit Service 672cf4
	       int include_certs, gpgme_ctx_t ctx /* FIXME */)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
  gpgme_error_t err = 0;
Packit Service 672cf4
  const char *protocol;
Packit Service 672cf4
  char *cmd;
Packit Service 672cf4
  gpgme_key_t key;
Packit Service 672cf4
Packit Service 672cf4
  (void)use_textmode;
Packit Service 672cf4
  (void)include_certs;
Packit Service 672cf4
Packit Service 672cf4
  if (!uiserver || !in || !out)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
  if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
Packit Service 672cf4
    protocol = "";
Packit Service 672cf4
  else if (uiserver->protocol == GPGME_PROTOCOL_OpenPGP)
Packit Service 672cf4
    protocol = " --protocol=OpenPGP";
Packit Service 672cf4
  else if (uiserver->protocol == GPGME_PROTOCOL_CMS)
Packit Service 672cf4
    protocol = " --protocol=CMS";
Packit Service 672cf4
  else
Packit Service 672cf4
    return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
Packit Service 672cf4
Packit Service 672cf4
  if (gpgrt_asprintf (&cmd, "SIGN%s%s", protocol,
Packit Service 672cf4
		(mode == GPGME_SIG_MODE_DETACH) ? " --detached" : "") < 0)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  key = gpgme_signers_enum (ctx, 0);
Packit Service 672cf4
  if (key)
Packit Service 672cf4
    {
Packit Service 672cf4
      const char *s = NULL;
Packit Service 672cf4
Packit Service 672cf4
      if (key && key->uids)
Packit Service 672cf4
        s = key->uids->email;
Packit Service 672cf4
Packit Service 672cf4
      if (s && strlen (s) < 80)
Packit Service 672cf4
        {
Packit Service 672cf4
          char buf[100];
Packit Service 672cf4
Packit Service 672cf4
          strcpy (stpcpy (buf, "SENDER --info "), s);
Packit Service 672cf4
          err = uiserver_assuan_simple_command (uiserver, buf,
Packit Service 672cf4
                                                uiserver->status.fnc,
Packit Service 672cf4
                                                uiserver->status.fnc_value);
Packit Service 672cf4
        }
Packit Service 672cf4
      else
Packit Service 672cf4
        err = gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
      gpgme_key_unref (key);
Packit Service 672cf4
      if (err)
Packit Service 672cf4
        {
Packit Service 672cf4
          gpgrt_free (cmd);
Packit Service 672cf4
          return err;
Packit Service 672cf4
        }
Packit Service 672cf4
  }
Packit Service 672cf4
Packit Service 672cf4
  uiserver->input_cb.data = in;
Packit Service 672cf4
  err = uiserver_set_fd (uiserver, INPUT_FD,
Packit Service 672cf4
			 map_data_enc (uiserver->input_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgrt_free (cmd);
Packit Service 672cf4
      return err;
Packit Service 672cf4
    }
Packit Service 672cf4
  uiserver->output_cb.data = out;
Packit Service 672cf4
  err = uiserver_set_fd (uiserver, OUTPUT_FD, use_armor ? "--armor"
Packit Service 672cf4
			 : map_data_enc (uiserver->output_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgrt_free (cmd);
Packit Service 672cf4
      return err;
Packit Service 672cf4
    }
Packit Service 672cf4
  uiserver->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  err = start (uiserver, cmd);
Packit Service 672cf4
  gpgrt_free (cmd);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* FIXME: Missing a way to specify --silent.  */
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_verify (void *engine, gpgme_data_t sig, gpgme_data_t signed_text,
Packit Service 672cf4
                 gpgme_data_t plaintext, gpgme_ctx_t ctx)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
  gpgme_error_t err;
Packit Service 672cf4
  const char *protocol;
Packit Service 672cf4
  char *cmd;
Packit Service 672cf4
Packit Service 672cf4
  (void)ctx; /* FIXME: We should to add a --sender option to the
Packit Service 672cf4
              * UISever protocol.  */
Packit Service 672cf4
Packit Service 672cf4
  if (!uiserver)
Packit Service 672cf4
    return gpg_error (GPG_ERR_INV_VALUE);
Packit Service 672cf4
  if (uiserver->protocol == GPGME_PROTOCOL_DEFAULT)
Packit Service 672cf4
    protocol = "";
Packit Service 672cf4
  else if (uiserver->protocol == GPGME_PROTOCOL_OpenPGP)
Packit Service 672cf4
    protocol = " --protocol=OpenPGP";
Packit Service 672cf4
  else if (uiserver->protocol == GPGME_PROTOCOL_CMS)
Packit Service 672cf4
    protocol = " --protocol=CMS";
Packit Service 672cf4
  else
Packit Service 672cf4
    return gpgme_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
Packit Service 672cf4
Packit Service 672cf4
  if (gpgrt_asprintf (&cmd, "VERIFY%s", protocol) < 0)
Packit Service 672cf4
    return gpg_error_from_syserror ();
Packit Service 672cf4
Packit Service 672cf4
  uiserver->input_cb.data = sig;
Packit Service 672cf4
  err = uiserver_set_fd (uiserver, INPUT_FD,
Packit Service 672cf4
			 map_data_enc (uiserver->input_cb.data));
Packit Service 672cf4
  if (err)
Packit Service 672cf4
    {
Packit Service 672cf4
      gpgrt_free (cmd);
Packit Service 672cf4
      return err;
Packit Service 672cf4
    }
Packit Service 672cf4
  if (plaintext)
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Normal or cleartext signature.  */
Packit Service 672cf4
      uiserver->output_cb.data = plaintext;
Packit Service 672cf4
      err = uiserver_set_fd (uiserver, OUTPUT_FD, 0);
Packit Service 672cf4
    }
Packit Service 672cf4
  else
Packit Service 672cf4
    {
Packit Service 672cf4
      /* Detached signature.  */
Packit Service 672cf4
      uiserver->message_cb.data = signed_text;
Packit Service 672cf4
      err = uiserver_set_fd (uiserver, MESSAGE_FD, 0);
Packit Service 672cf4
    }
Packit Service 672cf4
  uiserver->inline_data = NULL;
Packit Service 672cf4
Packit Service 672cf4
  if (!err)
Packit Service 672cf4
    err = start (uiserver, cmd);
Packit Service 672cf4
Packit Service 672cf4
  gpgrt_free (cmd);
Packit Service 672cf4
  return err;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
/* This sets a status callback for monitoring status lines before they
Packit Service 672cf4
 * are passed to a caller set handler.  */
Packit Service 672cf4
static void
Packit Service 672cf4
uiserver_set_status_cb (void *engine, gpgme_status_cb_t cb, void *cb_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
Packit Service 672cf4
  uiserver->status.mon_cb = cb;
Packit Service 672cf4
  uiserver->status.mon_cb_value = cb_value;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
uiserver_set_status_handler (void *engine, engine_status_handler_t fnc,
Packit Service 672cf4
			  void *fnc_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
Packit Service 672cf4
  uiserver->status.fnc = fnc;
Packit Service 672cf4
  uiserver->status.fnc_value = fnc_value;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static gpgme_error_t
Packit Service 672cf4
uiserver_set_colon_line_handler (void *engine, engine_colon_line_handler_t fnc,
Packit Service 672cf4
			      void *fnc_value)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
Packit Service 672cf4
  uiserver->colon.fnc = fnc;
Packit Service 672cf4
  uiserver->colon.fnc_value = fnc_value;
Packit Service 672cf4
  uiserver->colon.any = 0;
Packit Service 672cf4
  return 0;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
uiserver_set_io_cbs (void *engine, gpgme_io_cbs_t io_cbs)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
  uiserver->io_cbs = *io_cbs;
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
static void
Packit Service 672cf4
uiserver_io_event (void *engine, gpgme_event_io_t type, void *type_data)
Packit Service 672cf4
{
Packit Service 672cf4
  engine_uiserver_t uiserver = engine;
Packit Service 672cf4
Packit Service 6c01f9
  TRACE3 (DEBUG_ENGINE, "gpgme:uiserver_io_event", uiserver,
Packit Service 672cf4
          "event %p, type %d, type_data %p",
Packit Service 672cf4
          uiserver->io_cbs.event, type, type_data);
Packit Service 672cf4
  if (uiserver->io_cbs.event)
Packit Service 672cf4
    (*uiserver->io_cbs.event) (uiserver->io_cbs.event_priv, type, type_data);
Packit Service 672cf4
}
Packit Service 672cf4
Packit Service 672cf4
Packit Service 672cf4
struct engine_ops _gpgme_engine_ops_uiserver =
Packit Service 672cf4
  {
Packit Service 672cf4
    /* Static functions.  */
Packit Service 672cf4
    _gpgme_get_default_uisrv_socket,
Packit Service 672cf4
    NULL,
Packit Service 672cf4
    uiserver_get_version,
Packit Service 672cf4
    uiserver_get_req_version,
Packit Service 672cf4
    uiserver_new,
Packit Service 672cf4
Packit Service 672cf4
    /* Member functions.  */
Packit Service 672cf4
    uiserver_release,
Packit Service 672cf4
    uiserver_reset,
Packit Service 672cf4
    uiserver_set_status_cb,
Packit Service 672cf4
    uiserver_set_status_handler,
Packit Service 672cf4
    NULL,		/* set_command_handler */
Packit Service 672cf4
    uiserver_set_colon_line_handler,
Packit Service 672cf4
    uiserver_set_locale,
Packit Service 672cf4
    uiserver_set_protocol,
Packit Service 672cf4
    uiserver_decrypt,
Packit Service 672cf4
    NULL,		/* delete */
Packit Service 672cf4
    NULL,		/* edit */
Packit Service 672cf4
    uiserver_encrypt,
Packit Service 672cf4
    NULL,		/* encrypt_sign */
Packit Service 672cf4
    NULL,		/* export */
Packit Service 672cf4
    NULL,		/* export_ext */
Packit Service 672cf4
    NULL,		/* genkey */
Packit Service 672cf4
    NULL,		/* import */
Packit Service 672cf4
    NULL,		/* keylist */
Packit Service 672cf4
    NULL,		/* keylist_ext */
Packit Service 672cf4
    NULL,               /* keylist_data */
Packit Service 672cf4
    NULL,               /* keysign */
Packit Service 672cf4
    NULL,               /* tofu_policy */
Packit Service 672cf4
    uiserver_sign,
Packit Service 672cf4
    NULL,		/* trustlist */
Packit Service 672cf4
    uiserver_verify,
Packit Service 672cf4
    NULL,		/* getauditlog */
Packit Service 672cf4
    NULL,               /* opassuan_transact */
Packit Service 672cf4
    NULL,		/* conf_load */
Packit Service 672cf4
    NULL,		/* conf_save */
Packit Service 672cf4
    NULL,		/* conf_dir */
Packit Service 672cf4
    NULL,               /* query_swdb */
Packit Service 672cf4
    uiserver_set_io_cbs,
Packit Service 672cf4
    uiserver_io_event,
Packit Service 672cf4
    uiserver_cancel,
Packit Service 672cf4
    NULL,		/* cancel_op */
Packit Service 672cf4
    NULL,               /* passwd */
Packit Service 672cf4
    NULL,               /* set_pinentry_mode */
Packit Service 672cf4
    NULL                /* opspawn */
Packit Service 672cf4
  };