diff options
Diffstat (limited to 'gpgme/rungpg.c')
| -rw-r--r-- | gpgme/rungpg.c | 1080 | 
1 files changed, 607 insertions, 473 deletions
| diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index 1d6aa2b1..318e99d8 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -54,113 +54,166 @@ struct arg_and_data_s {      char arg[1];     /* .. this is used */  }; -struct fd_data_map_s { -    GpgmeData data; -    int inbound;  /* true if this is used for reading from gpg */ -    int dup_to; -    int fd;       /* the fd to use */ -    int peer_fd;  /* the outher side of the pipe */ +struct fd_data_map_s +{ +  GpgmeData data; +  int inbound;  /* true if this is used for reading from gpg */ +  int dup_to; +  int fd;       /* the fd to use */ +  int peer_fd;  /* the outher side of the pipe */ +  void *tag;  }; -struct gpg_object_s { -    struct arg_and_data_s *arglist; -    struct arg_and_data_s **argtail; -    int arg_error;   - -    struct { -        int fd[2];   -        size_t bufsize; -        char *buffer; -        size_t readpos; -        int eof; -        GpgStatusHandler fnc; -        void *fnc_value; -    } status; - -    /* This is a kludge - see the comment at gpg_colon_line_handler */ -    struct { -        int fd[2];   -        size_t bufsize; -        char *buffer; -        size_t readpos; -        int eof; -        GpgColonLineHandler fnc;  /* this indicate use of this structrue */ -        void *fnc_value; -        int simple; -    } colon; - -    char **argv;   -    struct fd_data_map_s *fd_data_map; - -    int pid; /* we can't use pid_t because we don't use it in Windoze */ - -    int running; -     -    /* stuff needed for pipemode */ -    struct { -        int used; -        int active; -        GpgmeData sig; -        GpgmeData text; -        int stream_started; -    } pm; - -    /* stuff needed for interactive (command) mode */ -    struct { -        int used; -        int fd; -        GpgmeData cb_data;   /* hack to get init the above fd later */ -        GpgStatusCode code;  /* last code */ -        char *keyword;       /* what has been requested (malloced) */ -        GpgCommandHandler fnc;  -        void *fnc_value; -    } cmd; +struct gpg_object_s +{ +  struct arg_and_data_s *arglist; +  struct arg_and_data_s **argtail; +  int arg_error;   + +  struct +  { +    int fd[2];   +    size_t bufsize; +    char *buffer; +    size_t readpos; +    int eof; +    GpgStatusHandler fnc; +    void *fnc_value; +    void *tag; +  } status; + +  /* This is a kludge - see the comment at gpg_colon_line_handler */ +  struct +  { +    int fd[2];   +    size_t bufsize; +    char *buffer; +    size_t readpos; +    int eof; +    GpgColonLineHandler fnc;  /* this indicate use of this structrue */ +    void *fnc_value; +    void *tag; +    int simple; +  } colon; + +  char **argv;   +  struct fd_data_map_s *fd_data_map; + +  int pid; /* we can't use pid_t because we don't use it in Windoze */ + +  /* stuff needed for pipemode */ +  struct +  { +    int used; +    int active; +    GpgmeData sig; +    GpgmeData text; +    int stream_started; +  } pm; + +  /* stuff needed for interactive (command) mode */ +  struct +  { +    int used; +    int fd; +    int idx;		/* Index in fd_data_map */ +    GpgmeData cb_data;   /* hack to get init the above idx later */ +    GpgStatusCode code;  /* last code */ +    char *keyword;       /* what has been requested (malloced) */ +    GpgCommandHandler fnc;  +    void *fnc_value; +  } cmd; + +  struct GpgmeIOCbs io_cbs;  }; -static void free_argv ( char **argv ); -static void free_fd_data_map ( struct fd_data_map_s *fd_data_map ); - -static int gpg_status_handler ( void *opaque, int pid, int fd ); -static GpgmeError read_status ( GpgObject gpg ); +static void free_argv (char **argv); +static void free_fd_data_map (struct fd_data_map_s *fd_data_map); -static int gpg_colon_line_handler ( void *opaque, int pid, int fd ); -static GpgmeError read_colon_line ( GpgObject gpg ); +static void gpg_status_handler (void *opaque, int fd); +static GpgmeError read_status (GpgObject gpg); -static int pipemode_cb ( void *opaque, -                         char *buffer, size_t length, size_t *nread ); -static int command_cb ( void *opaque, -                        char *buffer, size_t length, size_t *nread ); +static void gpg_colon_line_handler (void *opaque, int fd); +static GpgmeError read_colon_line (GpgObject gpg); +static int pipemode_cb (void *opaque, char *buffer, size_t length, +			size_t *nread); +static int command_cb (void *opaque, char *buffer, size_t length, +		       size_t *nread);  static void -close_notify_handler ( int fd, void *opaque ) +close_notify_handler (int fd, void *opaque)  { -    GpgObject gpg = opaque; +  GpgObject gpg = opaque; +  int possibly_done = 0; +  int not_done = 0; +  assert (fd != -1); -    assert (fd != -1); -    if (gpg->status.fd[0] == fd ) -        gpg->status.fd[0] = -1; -    else if (gpg->status.fd[1] == fd ) -        gpg->status.fd[1] = -1; -    else if (gpg->colon.fd[0] == fd ) -        gpg->colon.fd[0] = -1; -    else if (gpg->colon.fd[1] == fd ) -        gpg->colon.fd[1] = -1; -    else if (gpg->fd_data_map) { -        int i; - -        for (i=0; gpg->fd_data_map[i].data; i++ ) { -            if ( gpg->fd_data_map[i].fd == fd ) { -                gpg->fd_data_map[i].fd = -1; -                break; +  if (gpg->status.fd[0] == fd) +    { +      if (gpg->status.tag) +	{ +	  (*gpg->io_cbs.remove) (gpg->status.tag); +	  possibly_done = 1; +	} +      gpg->status.fd[0] = -1; +    } +  else if (gpg->status.fd[1] == fd) +    gpg->status.fd[1] = -1; +  else if (gpg->colon.fd[0] == fd) +    { +      if (gpg->colon.tag) +	{ +	  (*gpg->io_cbs.remove) (gpg->colon.tag); +	  possibly_done = 1; +	} +      gpg->colon.fd[0] = -1; +    } +  else if (gpg->colon.fd[1] == fd) +    gpg->colon.fd[1] = -1; +  else if (gpg->fd_data_map) +    { +      int i; + +      for (i = 0; gpg->fd_data_map[i].data; i++) +	{ +	  if (gpg->fd_data_map[i].fd == fd) +	    { +	      if (gpg->fd_data_map[i].tag) +		{ +		  (*gpg->io_cbs.remove) (gpg->fd_data_map[i].tag); +		  possibly_done = 1; +		} +	      gpg->fd_data_map[i].fd = -1; +	      break;              } -            if ( gpg->fd_data_map[i].peer_fd == fd ) { -                gpg->fd_data_map[i].peer_fd = -1; -                break; +	  if (gpg->fd_data_map[i].peer_fd == fd) +	    { +	      gpg->fd_data_map[i].peer_fd = -1; +	      break;              }          }      } +  if (!possibly_done) +    not_done = 1; +  else if (gpg->status.fd[0] != -1) +    not_done = 1; +  else if (gpg->colon.fd[0] != -1) +    not_done = 1; +  else if (gpg->fd_data_map) +    { +      int i; + +      for (i = 0; gpg->fd_data_map[i].data; i++) +	if (gpg->fd_data_map[i].fd != -1) +	  { +	    not_done = 1; +	    break; +	  } +    } +  if (!not_done && gpg->io_cbs.event) +    (*gpg->io_cbs.event) (gpg->io_cbs.event_priv, GPGME_EVENT_DONE, NULL);  }  const char * @@ -185,65 +238,70 @@ _gpgme_gpg_check_version (void)  }  GpgmeError -_gpgme_gpg_new ( GpgObject *r_gpg ) +_gpgme_gpg_new (GpgObject *r_gpg)  { -    GpgObject gpg; -    int rc = 0; - -    gpg = xtrycalloc ( 1, sizeof *gpg ); -    if ( !gpg ) { -        rc = mk_error (Out_Of_Core); -        goto leave; -    } -    gpg->argtail = &gpg->arglist; +  GpgObject gpg; +  int rc = 0; -    gpg->status.fd[0] = -1; -    gpg->status.fd[1] = -1; -    gpg->colon.fd[0] = -1; -    gpg->colon.fd[1] = -1; -    gpg->cmd.fd = -1; - -    gpg->pid = -1; - -    /* allocate the read buffer for the status pipe */ -    gpg->status.bufsize = 1024; -    gpg->status.readpos = 0; -    gpg->status.buffer = xtrymalloc (gpg->status.bufsize); -    if (!gpg->status.buffer) { -        rc = mk_error (Out_Of_Core); -        goto leave; +  gpg = xtrycalloc (1, sizeof *gpg); +  if (!gpg) +    { +      rc = mk_error (Out_Of_Core); +      goto leave;      } -    /* In any case we need a status pipe - create it right here  and -     * don't handle it with our generic GpgmeData mechanism */ -    if (_gpgme_io_pipe (gpg->status.fd, 1) == -1) { -        rc = mk_error (Pipe_Error); -        goto leave; +  gpg->argtail = &gpg->arglist; + +  gpg->status.fd[0] = -1; +  gpg->status.fd[1] = -1; +  gpg->colon.fd[0] = -1; +  gpg->colon.fd[1] = -1; +  gpg->cmd.fd = -1; +  gpg->cmd.idx = -1; + +  gpg->pid = -1; + +  /* Allocate the read buffer for the status pipe.  */ +  gpg->status.bufsize = 1024; +  gpg->status.readpos = 0; +  gpg->status.buffer = xtrymalloc (gpg->status.bufsize); +  if (!gpg->status.buffer) +    { +      rc = mk_error (Out_Of_Core); +      goto leave;      } -    if ( _gpgme_io_set_close_notify (gpg->status.fd[0], -                                     close_notify_handler, gpg) -         || _gpgme_io_set_close_notify (gpg->status.fd[1], -                                        close_notify_handler, gpg) ) { -        rc = mk_error (General_Error); -        goto leave; +  /* In any case we need a status pipe - create it right here and +     don't handle it with our generic GpgmeData mechanism.  */ +  if (_gpgme_io_pipe (gpg->status.fd, 1) == -1) +    { +      rc = mk_error (Pipe_Error); +      goto leave;      } -    gpg->status.eof = 0; -    _gpgme_gpg_add_arg ( gpg, "--status-fd" ); +  if (_gpgme_io_set_close_notify (gpg->status.fd[0], +				  close_notify_handler, gpg) +      || _gpgme_io_set_close_notify (gpg->status.fd[1], +				     close_notify_handler, gpg))      { -        char buf[25]; -        sprintf ( buf, "%d", gpg->status.fd[1]); -        _gpgme_gpg_add_arg ( gpg, buf ); +      rc = mk_error (General_Error); +      goto leave;      } -    _gpgme_gpg_add_arg ( gpg, "--no-tty" ); - +  gpg->status.eof = 0; +  _gpgme_gpg_add_arg (gpg, "--status-fd"); +  { +    char buf[25]; +    sprintf (buf, "%d", gpg->status.fd[1]); +    _gpgme_gpg_add_arg (gpg, buf); +  } +  _gpgme_gpg_add_arg (gpg, "--no-tty");   leave: -    if (rc) { -        _gpgme_gpg_release (gpg); -        *r_gpg = NULL; +  if (rc) +    { +      _gpgme_gpg_release (gpg); +      *r_gpg = NULL;      } -    else -        *r_gpg = gpg; -    return rc; +  else +    *r_gpg = gpg; +  return rc;  } @@ -268,8 +326,6 @@ _gpgme_gpg_release (GpgObject gpg)    gpgme_data_release (gpg->cmd.cb_data);    xfree (gpg->cmd.keyword); -  if (gpg->pid != -1)  -    _gpgme_remove_proc_from_wait_queue (gpg->pid);    if (gpg->status.fd[0] != -1)      _gpgme_io_close (gpg->status.fd[0]);    if (gpg->status.fd[1] != -1) @@ -279,7 +335,9 @@ _gpgme_gpg_release (GpgObject gpg)    if (gpg->colon.fd[1] != -1)      _gpgme_io_close (gpg->colon.fd[1]);    free_fd_data_map (gpg->fd_data_map); -  if (gpg->running) +  if (gpg->cmd.fd != -1) +    _gpgme_io_close (gpg->cmd.fd); +  if (gpg->pid != -1)      _gpgme_engine_add_child_to_reap_list (gpg, sizeof *gpg, gpg->pid);    else      xfree (gpg); @@ -512,341 +570,387 @@ free_fd_data_map ( struct fd_data_map_s *fd_data_map )  static GpgmeError -build_argv ( GpgObject gpg ) +build_argv (GpgObject gpg)  { -    struct arg_and_data_s *a; -    struct fd_data_map_s *fd_data_map; -    size_t datac=0, argc=0;   -    char **argv; -    int need_special = 0; -    int use_agent = !!getenv ("GPG_AGENT_INFO"); +  struct arg_and_data_s *a; +  struct fd_data_map_s *fd_data_map; +  size_t datac=0, argc=0;   +  char **argv; +  int need_special = 0; +  int use_agent = !!getenv ("GPG_AGENT_INFO"); -    if ( gpg->argv ) { -        free_argv ( gpg->argv ); -        gpg->argv = NULL; +  if (gpg->argv) +    { +      free_argv (gpg->argv); +      gpg->argv = NULL;      } -    if (gpg->fd_data_map) { -        free_fd_data_map (gpg->fd_data_map); -        gpg->fd_data_map = NULL; +  if (gpg->fd_data_map) +    { +      free_fd_data_map (gpg->fd_data_map); +      gpg->fd_data_map = NULL;      } -    argc++; /* for argv[0] */ -    for ( a=gpg->arglist; a; a = a->next ) { -        argc++; -        if (a->data) { -            /*fprintf (stderr, "build_argv: data\n" );*/ -            datac++; -            if ( a->dup_to == -1 && !a->print_fd ) -                need_special = 1; +  argc++;	/* For argv[0].  */ +  for (a = gpg->arglist; a; a = a->next) +    { +      argc++; +      if (a->data) +	{ +	  /*fprintf (stderr, "build_argv: data\n" );*/ +	  datac++; +	  if (a->dup_to == -1 && !a->print_fd) +	    need_special = 1;          } -        else { -            /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/ +      else +	{ +	  /*   fprintf (stderr, "build_argv: arg=`%s'\n", a->arg );*/          }      } -    if ( need_special ) -        argc++; -    if (use_agent) -        argc++; -    if (!gpg->cmd.used) -        argc++; -    argc += 2; /* --comment */ - -    argv = xtrycalloc ( argc+1, sizeof *argv ); -    if (!argv) -        return mk_error (Out_Of_Core); -    fd_data_map = xtrycalloc ( datac+1, sizeof *fd_data_map ); -    if (!fd_data_map) { -        free_argv (argv); -        return mk_error (Out_Of_Core); +  if (need_special) +    argc++; +  if (use_agent) +    argc++; +  if (!gpg->cmd.used) +    argc++; +  argc += 2; /* --comment */ + +  argv = xtrycalloc (argc + 1, sizeof *argv); +  if (!argv) +    return mk_error (Out_Of_Core); +  fd_data_map = xtrycalloc (datac + 1, sizeof *fd_data_map); +  if (!fd_data_map) +    { +      free_argv (argv); +      return mk_error (Out_Of_Core);      } -    argc = datac = 0; -    argv[argc] = xtrystrdup ( "gpg" ); /* argv[0] */ -    if (!argv[argc]) { -        xfree (fd_data_map); -        free_argv (argv); -        return mk_error (Out_Of_Core); +  argc = datac = 0; +  argv[argc] = xtrystrdup ("gpg"); /* argv[0] */ +  if (!argv[argc]) +    { +      xfree (fd_data_map); +      free_argv (argv); +      return mk_error (Out_Of_Core);      } -    argc++; -    if ( need_special ) { -        argv[argc] = xtrystrdup ( "--enable-special-filenames" ); -        if (!argv[argc]) { -            xfree (fd_data_map); -            free_argv (argv); -            return mk_error (Out_Of_Core); +  argc++; +  if (need_special) +    { +      argv[argc] = xtrystrdup ("--enable-special-filenames"); +      if (!argv[argc]) +	{ +	  xfree (fd_data_map); +	  free_argv (argv); +	  return mk_error (Out_Of_Core);          } -        argc++; +      argc++;      } -    if ( use_agent ) { -        argv[argc] = xtrystrdup ( "--use-agent" ); -        if (!argv[argc]) { -            xfree (fd_data_map); -            free_argv (argv); -            return mk_error (Out_Of_Core); +  if (use_agent) +    { +      argv[argc] = xtrystrdup ("--use-agent"); +      if (!argv[argc]) +	{ +	  xfree (fd_data_map); +	  free_argv (argv); +	  return mk_error (Out_Of_Core);          } -        argc++; +      argc++;      } -    if ( !gpg->cmd.used ) { -        argv[argc] = xtrystrdup ( "--batch" ); -        if (!argv[argc]) { -            xfree (fd_data_map); -            free_argv (argv); -            return mk_error (Out_Of_Core); +  if (!gpg->cmd.used) +    { +      argv[argc] = xtrystrdup ("--batch"); +      if (!argv[argc]) +	{ +	  xfree (fd_data_map); +	  free_argv (argv); +	  return mk_error (Out_Of_Core);          } -        argc++; +      argc++;      } -    argv[argc] = xtrystrdup ( "--comment" ); -    if (!argv[argc]) { -        xfree (fd_data_map); -        free_argv (argv); -        return mk_error (Out_Of_Core); +  argv[argc] = xtrystrdup ("--comment"); +  if (!argv[argc]) +    { +      xfree (fd_data_map); +      free_argv (argv); +      return mk_error (Out_Of_Core);      } -    argc++; -    argv[argc] = xtrystrdup ( "" ); -    if (!argv[argc]) { -        xfree (fd_data_map); -        free_argv (argv); -        return mk_error (Out_Of_Core); +  argc++; +  argv[argc] = xtrystrdup (""); +  if (!argv[argc]) +    { +      xfree (fd_data_map); +      free_argv (argv); +      return mk_error (Out_Of_Core);      } -    argc++; -    for ( a=gpg->arglist; a; a = a->next ) { -        if ( a->data ) { -            switch ( _gpgme_data_get_mode (a->data) ) { -              case GPGME_DATA_MODE_NONE: -              case GPGME_DATA_MODE_INOUT: -                xfree (fd_data_map); -                free_argv (argv); -                return mk_error (Invalid_Mode); -              case GPGME_DATA_MODE_IN: -                /* create a pipe to read from gpg */ -                fd_data_map[datac].inbound = 1; -                break; -              case GPGME_DATA_MODE_OUT: -                /* create a pipe to pass it down to gpg */ -                fd_data_map[datac].inbound = 0; -                break; +  argc++; +  for (a = gpg->arglist; a; a = a->next) +    { +      if (a->data) +	{ +	  switch (_gpgme_data_get_mode (a->data)) +	    { +	    case GPGME_DATA_MODE_NONE: +	    case GPGME_DATA_MODE_INOUT: +	      xfree (fd_data_map); +	      free_argv (argv); +	      return mk_error (Invalid_Mode); +	    case GPGME_DATA_MODE_IN: +	      /* Create a pipe to read from gpg.  */ +	      fd_data_map[datac].inbound = 1; +	      break; +	    case GPGME_DATA_MODE_OUT: +	      /* Create a pipe to pass it down to gpg.  */ +	      fd_data_map[datac].inbound = 0; +	      break;              } -            switch ( gpgme_data_get_type (a->data) ) { -              case GPGME_DATA_TYPE_NONE: -                if ( fd_data_map[datac].inbound ) -                    break;  /* allowed */ -                xfree (fd_data_map); -                free_argv (argv); -                return mk_error (Invalid_Type); -              case GPGME_DATA_TYPE_MEM: -              case GPGME_DATA_TYPE_CB: -                break; -              case GPGME_DATA_TYPE_FD: -              case GPGME_DATA_TYPE_FILE: -                xfree (fd_data_map); -                free_argv (argv); -                return mk_error (Not_Implemented); +	  switch (gpgme_data_get_type (a->data)) +	    { +	    case GPGME_DATA_TYPE_NONE: +	      if (fd_data_map[datac].inbound) +		break;  /* Allowed.  */ +	      xfree (fd_data_map); +	      free_argv (argv); +	      return mk_error (Invalid_Type); +	    case GPGME_DATA_TYPE_MEM: +	    case GPGME_DATA_TYPE_CB: +	      break; +	    case GPGME_DATA_TYPE_FD: +	    case GPGME_DATA_TYPE_FILE: +	      xfree (fd_data_map); +	      free_argv (argv); +	      return mk_error (Not_Implemented);              } -            /* create a pipe */ -            {    -                int fds[2]; -                 -                if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound?1:0 ) -                    == -1) { -                    xfree (fd_data_map); -                    free_argv (argv); -                    return mk_error (Pipe_Error); -                } -                if ( _gpgme_io_set_close_notify (fds[0], -                                                 close_notify_handler, gpg) -                     || _gpgme_io_set_close_notify (fds[1], -                                                    close_notify_handler, -                                                    gpg)) { -                    return mk_error (General_Error); -                } -                /* if the data_type is FD, we have to do a dup2 here */ -                if (fd_data_map[datac].inbound) { -                    fd_data_map[datac].fd       = fds[0]; -                    fd_data_map[datac].peer_fd  = fds[1]; -                } -                else { -                    fd_data_map[datac].fd       = fds[1]; -                    fd_data_map[datac].peer_fd  = fds[0]; -                } -            } - -            /* Hack to get hands on the fd later */ -            if ( gpg->cmd.used && gpg->cmd.cb_data == a->data ) { -                assert (gpg->cmd.fd == -1); -                gpg->cmd.fd = fd_data_map[datac].fd; -            } +	  /* Create a pipe.  */ +	  {    +	    int fds[2]; +	     +	    if (_gpgme_io_pipe (fds, fd_data_map[datac].inbound ? 1 : 0) +		== -1) +	      { +		xfree (fd_data_map); +		free_argv (argv); +		return mk_error (Pipe_Error); +	      } +	    if (_gpgme_io_set_close_notify (fds[0], +					    close_notify_handler, gpg) +		|| _gpgme_io_set_close_notify (fds[1], +					       close_notify_handler, +					       gpg)) +	      { +		return mk_error (General_Error); +	      } +	    /* If the data_type is FD, we have to do a dup2 here.  */ +	    if (fd_data_map[datac].inbound) +	      { +		fd_data_map[datac].fd       = fds[0]; +		fd_data_map[datac].peer_fd  = fds[1]; +	      } +	    else +	      { +		fd_data_map[datac].fd       = fds[1]; +		fd_data_map[datac].peer_fd  = fds[0]; +	      } +	  } + +	  /* Hack to get hands on the fd later.  */ +	  if (gpg->cmd.used && gpg->cmd.cb_data == a->data) +	    { +	      assert (gpg->cmd.idx == -1); +	      gpg->cmd.idx = datac; +	    } -            fd_data_map[datac].data = a->data; -            fd_data_map[datac].dup_to = a->dup_to; -            if ( a->dup_to == -1 ) { -                argv[argc] = xtrymalloc ( 25 ); -                if (!argv[argc]) { -                    xfree (fd_data_map); -                    free_argv (argv); -                    return mk_error (Out_Of_Core); +	  fd_data_map[datac].data = a->data; +	  fd_data_map[datac].dup_to = a->dup_to; +	  if (a->dup_to == -1) +	    { +	      argv[argc] = xtrymalloc (25); +	      if (!argv[argc]) +		{ +		  xfree (fd_data_map); +		  free_argv (argv); +		  return mk_error (Out_Of_Core);                  } -                sprintf ( argv[argc],  -                          a->print_fd? "%d" : "-&%d", -                          fd_data_map[datac].peer_fd ); -                argc++; +	      sprintf (argv[argc],  +		       a->print_fd ? "%d" : "-&%d", +		       fd_data_map[datac].peer_fd); +	      argc++;              } -            datac++; +	  datac++;          } -        else { -            argv[argc] = xtrystrdup ( a->arg ); -            if (!argv[argc]) { -                xfree (fd_data_map); -                free_argv (argv); -                return mk_error (Out_Of_Core); +      else +	{ +	  argv[argc] = xtrystrdup (a->arg); +	  if (!argv[argc]) +	    { +	      xfree (fd_data_map); +	      free_argv (argv); +	      return mk_error (Out_Of_Core);              }              argc++;          }      } -    gpg->argv = argv; -    gpg->fd_data_map = fd_data_map; -    return 0; +  gpg->argv = argv; +  gpg->fd_data_map = fd_data_map; +  return 0; +} + +static GpgmeError +_gpgme_gpg_add_io_cb (GpgObject gpg, int fd, int dir, +		      GpgmeIOCb handler, void *data, void **tag) +{ +  GpgmeError err = 0; + +  *tag = (*gpg->io_cbs.add) (gpg->io_cbs.add_priv, fd, dir, handler, data); +  if (!tag) +    err = mk_error (General_Error); +  if (!err && !dir) +    /* FIXME Kludge around poll() problem.  */ +    err = _gpgme_io_set_nonblocking (fd); +  return err;  }  GpgmeError -_gpgme_gpg_spawn( GpgObject gpg, void *opaque ) +_gpgme_gpg_spawn (GpgObject gpg, void *opaque)  { -    int rc; -    int i, n; -    int pid; -    struct spawn_fd_item_s *fd_child_list, *fd_parent_list; +  GpgmeError rc; +  int i, n; +  int pid; +  struct spawn_fd_item_s *fd_child_list, *fd_parent_list; -    if (!gpg) -      return mk_error (Invalid_Value); +  if (!gpg) +    return mk_error (Invalid_Value); -    if (! _gpgme_get_gpg_path ()) -      return mk_error (Invalid_Engine); +  if (! _gpgme_get_gpg_path ()) +    return mk_error (Invalid_Engine); -    /* Kludge, so that we don't need to check the return code of -     * all the gpgme_gpg_add_arg().  we bail out here instead */ -    if ( gpg->arg_error ) -        return mk_error (Out_Of_Core); +  /* Kludge, so that we don't need to check the return code of all the +     gpgme_gpg_add_arg().  we bail out here instead */ +  if (gpg->arg_error) +    return mk_error (Out_Of_Core); -    if (gpg->pm.active) -        return 0; +  if (gpg->pm.active) +    return 0; -    rc = build_argv ( gpg ); -    if ( rc ) -        return rc; +  rc = build_argv (gpg); +  if (rc) +    return rc; -    n = 3; /* status_fd, colon_fd and end of list */ -    for (i=0; gpg->fd_data_map[i].data; i++ )  -        n++; -    fd_child_list = xtrycalloc ( n+n, sizeof *fd_child_list ); -    if (!fd_child_list) -        return mk_error (Out_Of_Core); -    fd_parent_list = fd_child_list + n; - -    /* build the fd list for the child */ -    n=0; -    if ( gpg->colon.fnc ) { -        fd_child_list[n].fd = gpg->colon.fd[1];  -        fd_child_list[n].dup_to = 1; /* dup to stdout */ -        n++; +  n = 3; /* status_fd, colon_fd and end of list */ +  for (i = 0; gpg->fd_data_map[i].data; i++)  +    n++; +  fd_child_list = xtrycalloc (n + n, sizeof *fd_child_list); +  if (!fd_child_list) +    return mk_error (Out_Of_Core); +  fd_parent_list = fd_child_list + n; + +  /* build the fd list for the child */ +  n = 0; +  if (gpg->colon.fnc) +    { +      fd_child_list[n].fd = gpg->colon.fd[1];  +      fd_child_list[n].dup_to = 1; /* dup to stdout */ +      n++;      } -    for (i=0; gpg->fd_data_map[i].data; i++ ) { -        if (gpg->fd_data_map[i].dup_to != -1) { -            fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd; -            fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to; -            n++; +  for (i = 0; gpg->fd_data_map[i].data; i++) +    { +      if (gpg->fd_data_map[i].dup_to != -1) +	{ +	  fd_child_list[n].fd = gpg->fd_data_map[i].peer_fd; +	  fd_child_list[n].dup_to = gpg->fd_data_map[i].dup_to; +	  n++;          }      } -    fd_child_list[n].fd = -1; -    fd_child_list[n].dup_to = -1; - -    /* build the fd list for the parent */ -    n=0; -    if ( gpg->status.fd[1] != -1 ) { -        fd_parent_list[n].fd = gpg->status.fd[1]; -        fd_parent_list[n].dup_to = -1; -        n++; -        gpg->status.fd[1] = -1; +  fd_child_list[n].fd = -1; +  fd_child_list[n].dup_to = -1; + +  /* Build the fd list for the parent.  */ +  n = 0; +  if (gpg->status.fd[1] != -1) +    { +      fd_parent_list[n].fd = gpg->status.fd[1]; +      fd_parent_list[n].dup_to = -1; +      n++; +      gpg->status.fd[1] = -1;      } -    if ( gpg->colon.fd[1] != -1 ) { -        fd_parent_list[n].fd = gpg->colon.fd[1]; -        fd_parent_list[n].dup_to = -1; -        n++; -        gpg->colon.fd[1] = -1; +  if (gpg->colon.fd[1] != -1) +    { +      fd_parent_list[n].fd = gpg->colon.fd[1]; +      fd_parent_list[n].dup_to = -1; +      n++; +      gpg->colon.fd[1] = -1;      } -    for (i=0; gpg->fd_data_map[i].data; i++ ) { -        fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd; -        fd_parent_list[n].dup_to = -1; -        n++; -        gpg->fd_data_map[i].peer_fd = -1; +  for (i = 0; gpg->fd_data_map[i].data; i++) +    { +      fd_parent_list[n].fd = gpg->fd_data_map[i].peer_fd; +      fd_parent_list[n].dup_to = -1; +      n++; +      gpg->fd_data_map[i].peer_fd = -1;      }         -    fd_parent_list[n].fd = -1; -    fd_parent_list[n].dup_to = -1; - +  fd_parent_list[n].fd = -1; +  fd_parent_list[n].dup_to = -1; -    pid = _gpgme_io_spawn (_gpgme_get_gpg_path (), -                           gpg->argv, fd_child_list, fd_parent_list); -    xfree (fd_child_list); -    if (pid == -1) { -        return mk_error (Exec_Error); -    } +  pid = _gpgme_io_spawn (_gpgme_get_gpg_path (), +			 gpg->argv, fd_child_list, fd_parent_list); +  xfree (fd_child_list); +  if (pid == -1) +    return mk_error (Exec_Error); -    gpg->pid = pid; -    if (gpg->pm.used) -        gpg->pm.active = 1; +  gpg->pid = pid; +  if (gpg->pm.used) +    gpg->pm.active = 1; -    /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ - -    if ( _gpgme_register_pipe_handler ( opaque, gpg_status_handler, -                                        gpg, pid, gpg->status.fd[0], 1 ) ) { -        /* FIXME: kill the child */ -        return mk_error (General_Error); +  /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ -    } +  rc = _gpgme_gpg_add_io_cb (gpg, gpg->status.fd[0], 1, +			     gpg_status_handler, gpg, &gpg->status.tag); +  if (rc) +    /* FIXME: kill the child */ +    return rc; -    if ( gpg->colon.fnc ) { -        assert ( gpg->colon.fd[0] != -1 ); -        if ( _gpgme_register_pipe_handler ( opaque, gpg_colon_line_handler, -                                            gpg, pid, gpg->colon.fd[0], 1 ) ) { -            /* FIXME: kill the child */ -            return mk_error (General_Error); -             -        } +  if (gpg->colon.fnc) +    { +      assert (gpg->colon.fd[0] != -1); +      rc = _gpgme_gpg_add_io_cb (gpg, gpg->colon.fd[0], 1, +				 gpg_colon_line_handler, gpg, +				 &gpg->colon.tag); +      if (rc) +	/* FIXME: kill the child */ +	return rc;      } -    for (i=0; gpg->fd_data_map[i].data; i++ ) { -        /* Due to problems with select and write we set outbound pipes -         * to non-blocking */ -        if (!gpg->fd_data_map[i].inbound) { -            _gpgme_io_set_nonblocking (gpg->fd_data_map[i].fd); -        } - -        if ( _gpgme_register_pipe_handler ( -                 opaque,  -                 gpg->fd_data_map[i].inbound? -		 _gpgme_data_inbound_handler:_gpgme_data_outbound_handler, -                 gpg->fd_data_map[i].data, -                 pid, gpg->fd_data_map[i].fd, -                 gpg->fd_data_map[i].inbound ) -           ) { -            /* FIXME: kill the child */ -            return mk_error (General_Error); -        } +  for (i = 0; gpg->fd_data_map[i].data; i++) +    { +      if (gpg->cmd.used && i == gpg->cmd.idx) +	{ +	  /* Park the cmd fd.  */ +	  gpg->cmd.fd = gpg->fd_data_map[i].fd; +	  gpg->fd_data_map[i].fd = -1; +	} +      else +	{ +	  rc = _gpgme_gpg_add_io_cb (gpg, gpg->fd_data_map[i].fd, +				     gpg->fd_data_map[i].inbound, +				     gpg->fd_data_map[i].inbound +				     ? _gpgme_data_inbound_handler +				     : _gpgme_data_outbound_handler, +				     gpg->fd_data_map[i].data, +				     &gpg->fd_data_map[i].tag); +	   +	  if (rc) +	    /* FIXME: kill the child */ +	    return rc; +	}      } - -    if ( gpg->cmd.used ) -        _gpgme_freeze_fd ( gpg->cmd.fd ); - -    /* fixme: check what data we can release here */ -     -    gpg->running = 1; -    return 0; +   +  /* fixme: check what data we can release here */ +  return 0;  } -static int -gpg_status_handler (void *opaque, int pid, int fd) +static void +gpg_status_handler (void *opaque, int fd)  {    GpgObject gpg = opaque;    int err; @@ -860,9 +964,11 @@ gpg_status_handler (void *opaque, int pid, int fd)        GpgmeCtx ctx = (GpgmeCtx) gpg->status.fnc_value;        ctx->error = err;        DEBUG1 ("gpg_handler: read_status problem %d\n - stop", err); -      return 1; +      _gpgme_io_close (fd); +      return;      } -  return gpg->status.eof; +  if (gpg->status.eof) +    _gpgme_io_close (fd);  } @@ -951,7 +1057,14 @@ read_status ( GpgObject gpg )                               * handler does its action */                              if ( nread > 1 )                                  DEBUG0 ("ERROR, unexpected data in read_status"); -                            _gpgme_thaw_fd (gpg->cmd.fd); + +			    _gpgme_gpg_add_io_cb +			      (gpg, gpg->cmd.fd, +			       0, _gpgme_data_outbound_handler, +			       gpg->fd_data_map[gpg->cmd.idx].data, +			       &gpg->fd_data_map[gpg->cmd.idx].tag); +			    gpg->fd_data_map[gpg->cmd.idx].fd = gpg->cmd.fd; +			    gpg->cmd.fd = -1;                          }                          else if ( gpg->status.fnc ) {                              gpg->status.fnc ( gpg->status.fnc_value,  @@ -959,8 +1072,13 @@ read_status ( GpgObject gpg )                          }                          if ( r->code == STATUS_END_STREAM ) { -                            if ( gpg->cmd.used ) -                                _gpgme_freeze_fd ( gpg->cmd.fd ); +			  if (gpg->cmd.used) +			    { +			      (*gpg->io_cbs.remove) +				(gpg->fd_data_map[gpg->cmd.idx].tag); +			      gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd; +			      gpg->fd_data_map[gpg->cmd.idx].fd = -1; +			    }                          }                      }                  } @@ -995,21 +1113,23 @@ read_status ( GpgObject gpg )   * a wrapper for a callback.  Same goes for the status thing.   * For now we use this thing here becuase it is easier to implement.   */ -static int -gpg_colon_line_handler ( void *opaque, int pid, int fd ) +static void +gpg_colon_line_handler (void *opaque, int fd)  { -    GpgObject gpg = opaque; -    GpgmeError rc = 0; - -    assert ( fd == gpg->colon.fd[0] ); -    rc = read_colon_line ( gpg ); -    if ( rc ) { -        DEBUG1 ("gpg_colon_line_handler: " -                 "read problem %d\n - stop", rc); -        return 1; -    } +  GpgObject gpg = opaque; +  GpgmeError rc = 0; -    return gpg->colon.eof; +  assert (fd == gpg->colon.fd[0]); +  rc = read_colon_line (gpg); +  if (rc) +    { +      DEBUG1 ("gpg_colon_line_handler: " +	      "read problem %d\n - stop", rc); +      _gpgme_io_close (fd); +      return; +    } +  if (gpg->colon.eof) +    _gpgme_io_close (fd);  }  static GpgmeError @@ -1167,52 +1287,59 @@ pipemode_cb ( void *opaque, char *buffer, size_t length, size_t *nread )   */  static int -command_cb ( void *opaque, char *buffer, size_t length, size_t *nread ) +command_cb (void *opaque, char *buffer, size_t length, size_t *nread)  { -    GpgObject gpg = opaque; -    const char *value; -    int value_len; - -    DEBUG0 ("command_cb: enter\n"); -    assert (gpg->cmd.used); -    if ( !buffer || !length || !nread ) -        return 0; /* those values are reserved for extensions */ -    *nread =0; -    if ( !gpg->cmd.code ) { -        DEBUG0 ("command_cb: no code\n"); -        return -1; +  GpgObject gpg = opaque; +  const char *value; +  int value_len; + +  DEBUG0 ("command_cb: enter\n"); +  assert (gpg->cmd.used); +  if (!buffer || !length || !nread) +    return 0; /* These values are reserved for extensions.  */ +  *nread = 0; +  if (!gpg->cmd.code) +    { +      DEBUG0 ("command_cb: no code\n"); +      return -1;      } -    if ( !gpg->cmd.fnc ) { -        DEBUG0 ("command_cb: no user cb\n"); -        return -1; +  if (!gpg->cmd.fnc) +    { +      DEBUG0 ("command_cb: no user cb\n"); +      return -1;      } -    value = gpg->cmd.fnc ( gpg->cmd.fnc_value,  -                           gpg->cmd.code, gpg->cmd.keyword ); -    if ( !value ) { -        DEBUG0 ("command_cb: no data from user cb\n"); -        gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); -        return -1; +  value = gpg->cmd.fnc (gpg->cmd.fnc_value,  +			gpg->cmd.code, gpg->cmd.keyword); +  if (!value) +    { +      DEBUG0 ("command_cb: no data from user cb\n"); +      gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value); +      return -1;      } -    value_len = strlen (value); -    if ( value_len+1 > length ) { -        DEBUG0 ("command_cb: too much data from user cb\n"); -        gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); -        return -1; +  value_len = strlen (value); +  if (value_len + 1 > length) +    { +      DEBUG0 ("command_cb: too much data from user cb\n"); +      gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value); +      return -1;      } -    memcpy ( buffer, value, value_len ); -    if ( !value_len || (value_len && value[value_len-1] != '\n') )  -        buffer[value_len++] = '\n'; -    *nread = value_len; +  memcpy (buffer, value, value_len); +  if (!value_len || (value_len && value[value_len-1] != '\n'))  +    buffer[value_len++] = '\n'; +  *nread = value_len; -    gpg->cmd.fnc ( gpg->cmd.fnc_value, 0, value); -    gpg->cmd.code = 0; -    /* and sleep again until read_status will wake us up again */ -    _gpgme_freeze_fd ( gpg->cmd.fd ); -    return 0; +  gpg->cmd.fnc (gpg->cmd.fnc_value, 0, value); +  gpg->cmd.code = 0; +  /* And sleep again until read_status will wake us up again.  */ +  (*gpg->io_cbs.remove) (gpg->fd_data_map[gpg->cmd.idx].tag); +  gpg->cmd.fd = gpg->fd_data_map[gpg->cmd.idx].fd; +  gpg->fd_data_map[gpg->cmd.idx].fd = -1; + +  return 0;  }  GpgmeError @@ -1603,3 +1730,10 @@ _gpgme_gpg_op_verify (GpgObject gpg, GpgmeData sig, GpgmeData text)      }    return err;  } + + +void +_gpgme_gpg_set_io_cbs (GpgObject gpg, struct GpgmeIOCbs *io_cbs) +{ +  gpg->io_cbs = *io_cbs; +} | 
