Blame src/engine-uiserver.c

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