diff options
Diffstat (limited to 'gpgme/rungpg.c')
| -rw-r--r-- | gpgme/rungpg.c | 171 | 
1 files changed, 169 insertions, 2 deletions
| diff --git a/gpgme/rungpg.c b/gpgme/rungpg.c index ac6ba114..29263293 100644 --- a/gpgme/rungpg.c +++ b/gpgme/rungpg.c @@ -73,6 +73,17 @@ struct gpg_object_s {          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; +    } colon; +      char **argv;        struct fd_data_map_s *fd_data_map; @@ -86,12 +97,16 @@ struct gpg_object_s {  static void kill_gpg ( 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_status_handler ( void *opaque, pid_t pid, int fd ); +  static int gpg_inbound_handler ( void *opaque, pid_t pid, int fd );  static int gpg_outbound_handler ( void *opaque, pid_t pid, int fd ); +static int gpg_status_handler ( void *opaque, pid_t pid, int fd );  static GpgmeError read_status ( GpgObject gpg ); +static int gpg_colon_line_handler ( void *opaque, pid_t pid, int fd ); +static GpgmeError read_colon_line ( GpgObject gpg ); +  GpgmeError @@ -109,6 +124,8 @@ _gpgme_gpg_new_object ( GpgObject *r_gpg )      gpg->status.fd[0] = -1;      gpg->status.fd[1] = -1; +    gpg->colon.fd[0] = -1; +    gpg->colon.fd[1] = -1;      /* allocate the read buffer for the status pipe */      gpg->status.bufsize = 1024; @@ -150,12 +167,17 @@ _gpgme_gpg_release_object ( GpgObject gpg )      if ( !gpg )          return;      xfree (gpg->status.buffer); +    xfree (gpg->colon.buffer);      if ( gpg->argv )          free_argv (gpg->argv);      if (gpg->status.fd[0] != -1 )          close (gpg->status.fd[0]);      if (gpg->status.fd[1] != -1 )          close (gpg->status.fd[1]); +    if (gpg->colon.fd[0] != -1 ) +        close (gpg->colon.fd[0]); +    if (gpg->colon.fd[1] != -1 ) +        close (gpg->colon.fd[1]);      free_fd_data_map (gpg->fd_data_map);      kill_gpg (gpg); /* fixme: should be done asyncronously */      xfree (gpg); @@ -232,6 +254,30 @@ _gpgme_gpg_set_status_handler ( GpgObject gpg,      gpg->status.fnc_value = fnc_value;  } +/* Kludge to process --with-colon output */ +GpgmeError +_gpgme_gpg_set_colon_line_handler ( GpgObject gpg, +                                    GpgColonLineHandler fnc, void *fnc_value )  +{ +    assert (gpg); + +    gpg->colon.bufsize = 1024; +    gpg->colon.readpos = 0; +    gpg->colon.buffer = xtrymalloc (gpg->colon.bufsize); +    if (!gpg->colon.buffer) { +        return mk_error (Out_Of_Core); +    } +    if (pipe (gpg->colon.fd) == -1) { +        xfree (gpg->colon.buffer); gpg->colon.buffer = NULL; +        return mk_error (Pipe_Error); +    } +    gpg->colon.eof = 0; +    gpg->colon.fnc = fnc; +    gpg->colon.fnc_value = fnc_value; +    return 0; +} + +  static void  free_argv ( char **argv )  { @@ -431,6 +477,17 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )          int duped_stderr = 0;          close (gpg->status.fd[0]); + +        if (gpg->colon.fnc) { +            /* dup it to stdout */ +            if ( dup2 ( gpg->colon.fd[1], 1 ) == -1 ) { +                fprintf (stderr,"dup2(colon, 1) failed: %s\n", +                         strerror (errno) ); +                _exit (8); +            } +            close (gpg->colon.fd[0]); +            close (gpg->colon.fd[1]); +        }          for (i=0; gpg->fd_data_map[i].data; i++ ) {              close (gpg->fd_data_map[i].fd); @@ -485,14 +542,29 @@ _gpgme_gpg_spawn( GpgObject gpg, void *opaque )      /*_gpgme_register_term_handler ( closure, closure_value, pid );*/ -    if ( gpg->status.fd[1] != -1 ) +    if ( gpg->status.fd[1] != -1 ) {          close (gpg->status.fd[1]); +        gpg->status.fd[1] = -1; +    }      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);      } + +    if ( gpg->colon.fd[1] != -1 ) { +        close (gpg->colon.fd[1]); +        gpg->colon.fd[1] = -1; +        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); +             +        } +    } +      for (i=0; gpg->fd_data_map[i].data; i++ ) {          close (gpg->fd_data_map[i].peer_fd);          gpg->fd_data_map[i].peer_fd = -1; @@ -724,3 +796,98 @@ read_status ( GpgObject gpg )  } +/* + * This colonline handler thing is not the clean way to do it. + * It might be better to enhance the GpgmeData object to act as + * 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, pid_t pid, int fd ) +{ +    GpgObject gpg = opaque; +    GpgmeError rc = 0; + +    assert ( fd == gpg->colon.fd[0] ); +    rc = read_colon_line ( gpg ); +    if ( rc ) { +        fprintf (stderr, "gpg_colon_line_handler: " +                 "read problem %d\n - stop", rc); +        return 1; +    } + +    return gpg->status.eof; +} + +static GpgmeError +read_colon_line ( GpgObject gpg ) +{ +    char *p; +    int nread; +    size_t bufsize = gpg->colon.bufsize;  +    char *buffer = gpg->colon.buffer; +    size_t readpos = gpg->colon.readpos;  + +    assert (buffer); +    if (bufsize - readpos < 256) {  +        /* need more room for the read */ +        bufsize += 1024; +        buffer = xtryrealloc (buffer, bufsize); +        if ( !buffer )  +            return mk_error (Out_Of_Core); +    } +     + +    do {  +        nread = read ( gpg->colon.fd[0], buffer+readpos, bufsize-readpos ); +    } while (nread == -1 && errno == EINTR); + +    if (nread == -1) +        return mk_error(Read_Error); + +    if (!nread) { +        gpg->colon.eof = 1; +        assert (gpg->colon.fnc); +        gpg->colon.fnc ( gpg->colon.fnc_value, NULL ); +        return 0; +    } + +    while (nread > 0) { +        for (p = buffer + readpos; nread; nread--, p++) { +            if ( *p == '\n' ) { +                /* (we require that the last line is terminated by a +                 * LF) and we skip empty lines.  Note: we use UTF8 +                 * encoding and escaping of special characters +                 * We require at least one colon to cope with +                 * some other printed information. +                 */ +                *p = 0; +                if ( *buffer && strchr (buffer, ':') ) { +                    assert (gpg->colon.fnc); +                    gpg->colon.fnc ( gpg->colon.fnc_value, buffer ); +                } +             +                /* To reuse the buffer for the next line we have to +                 * shift the remaining data to the buffer start and +                 * restart the loop Hmmm: We can optimize this +                 * function by looking forward in the buffer to see +                 * whether a second complete line is available and in +                 * this case avoid the memmove for this line.  */ +                nread--; p++; +                if (nread) +                    memmove (buffer, p, nread); +                readpos = 0; +                break; /* the for loop */ +            } +            else +                readpos++; +        } +    }  +     +    /* Update the gpg object.  */ +    gpg->colon.bufsize = bufsize; +    gpg->colon.buffer  = buffer; +    gpg->colon.readpos = readpos; +    return 0; +} + | 
