diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | src/ChangeLog | 23 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/assuan-client.c | 233 | ||||
-rw-r--r-- | src/assuan-defs.h | 4 | ||||
-rw-r--r-- | src/assuan-pipe-connect.c | 7 | ||||
-rw-r--r-- | src/assuan-socket-connect.c | 7 | ||||
-rw-r--r-- | src/assuan.h | 20 | ||||
-rw-r--r-- | src/client.c | 247 | ||||
-rw-r--r-- | src/libassuan.def | 2 | ||||
-rw-r--r-- | src/libassuan.vers | 2 |
11 files changed, 306 insertions, 242 deletions
@@ -88,6 +88,8 @@ ASSUAN_SOCKET_SERVER_ACCEPTED NEW ASSUAN_SOCKET_CONNECT_FDPASSING NEW assuan_peercred_t NEW assuan_get_peercred CHANGED: Return assuan_peercred_t. +assuan_client_read_response NEW +assuan_client_parse_response NEW ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/ChangeLog b/src/ChangeLog index b63315d..45a849b 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,26 @@ +2009-12-02 Marcus Brinkmann <marcus@g10code.de> + + * Makefile.am (common_sources): Remove assuan-client.c. + * assuan-client.c: File removed. + * assuan.h (ASSUAN_RESPONSE_ERROR, ASSUAN_RESPONSE_OK) + (ASSUAN_RESPONSE_STATUS, ASSUAN_RESPONSE_INQUIRE) + (ASSUAN_RESPONSE_STATUS): New macros. + (assuan_response_t): New type. + (assuan_client_read_response, assuan_client_parse_response): New + prototypes. + * libassuan.def, libassuan.vers: Add assuan_client_read_response, + assuan_client_parse_response. + * assuan-client.c (xtoi_1, xtoi_2, assuan_transact) + (_assuan_read_from_server): Moved to ... + * client.c: ... here, with updates to use new functions and types. + Include <stdlib.h>. + (assuan_client_read_response, assuan_client_parse_response): New + functions. + * assuan-defs.h (_assuan_read_from_server): Use assuan_response_t. + * assuan-pipe-connect.c (initial_handshake): Use assuan_response_t + and ASSUAN_RESPONSE_OK. + * assuan-socket-connect.c (assuan_socket_connect): Likewise. + 2009-12-01 Marcus Brinkmann <marcus@g10code.de> * assuan-pipe-server.c (assuan_init_pipe_server): Fix debug output. diff --git a/src/Makefile.am b/src/Makefile.am index b5b9f52..d2f1af0 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,7 +44,6 @@ common_sources = \ assuan-handler.c \ assuan-inquire.c \ assuan-listen.c \ - assuan-client.c \ assuan-pipe-server.c \ assuan-socket-server.c \ assuan-pipe-connect.c \ diff --git a/src/assuan-client.c b/src/assuan-client.c deleted file mode 100644 index 1f860b8..0000000 --- a/src/assuan-client.c +++ /dev/null @@ -1,233 +0,0 @@ -/* assuan-client.c - client functions - Copyright (C) 2001, 2002, 2005, 2009 Free Software Foundation, Inc. - - This file is part of Assuan. - - Assuan is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of - the License, or (at your option) any later version. - - Assuan is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <stdlib.h> -#include <stdio.h> -#include <errno.h> -#include <unistd.h> -#include <assert.h> - -#include "assuan-defs.h" - -#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ - *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) -#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) - - -gpg_error_t -_assuan_read_from_server (assuan_context_t ctx, int *okay, int *off) -{ - char *line; - int linelen; - gpg_error_t rc; - - *okay = 0; - *off = 0; - do - { - do - { - rc = _assuan_read_line (ctx); - } - while (_assuan_error_is_eagain (ctx, rc)); - if (rc) - return rc; - line = ctx->inbound.line; - linelen = ctx->inbound.linelen; - } - while (*line == '#' || !linelen); - - if (linelen >= 1 - && line[0] == 'D' && line[1] == ' ') - { - *okay = 2; /* data line */ - *off = 2; - } - else if (linelen >= 1 - && line[0] == 'S' - && (line[1] == '\0' || line[1] == ' ')) - { - *okay = 4; - *off = 1; - while (line[*off] == ' ') - ++*off; - } - else if (linelen >= 2 - && line[0] == 'O' && line[1] == 'K' - && (line[2] == '\0' || line[2] == ' ')) - { - *okay = 1; - *off = 2; - while (line[*off] == ' ') - ++*off; - } - else if (linelen >= 3 - && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' - && (line[3] == '\0' || line[3] == ' ')) - { - *okay = 0; - *off = 3; - while (line[*off] == ' ') - ++*off; - } - else if (linelen >= 7 - && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q' - && line[3] == 'U' && line[4] == 'I' && line[5] == 'R' - && line[6] == 'E' - && (line[7] == '\0' || line[7] == ' ')) - { - *okay = 3; - *off = 7; - while (line[*off] == ' ') - ++*off; - } - else if (linelen >= 3 - && line[0] == 'E' && line[1] == 'N' && line[2] == 'D' - && (line[3] == '\0' || line[3] == ' ')) - { - *okay = 5; /* end line */ - *off = 3; - } - else - rc = _assuan_error (ctx, GPG_ERR_ASS_INV_RESPONSE); - return rc; -} - - - -/** - * assuan_transact: - * @ctx: The Assuan context - * @command: Command line to be send to the server - * @data_cb: Callback function for data lines - * @data_cb_arg: first argument passed to @data_cb - * @inquire_cb: Callback function for a inquire response - * @inquire_cb_arg: first argument passed to @inquire_cb - * @status_cb: Callback function for a status response - * @status_cb_arg: first argument passed to @status_cb - * - * FIXME: Write documentation - * - * Return value: 0 on success or error code. The error code may be - * the one one returned by the server in error lines or from the - * callback functions. Take care: When a callback returns an error - * this function returns immediately with an error and thus the caller - * will altter return an Assuan error (write erro in most cases). - **/ -gpg_error_t -assuan_transact (assuan_context_t ctx, - const char *command, - gpg_error_t (*data_cb)(void *, const void *, size_t), - void *data_cb_arg, - gpg_error_t (*inquire_cb)(void*, const char *), - void *inquire_cb_arg, - gpg_error_t (*status_cb)(void*, const char *), - void *status_cb_arg) -{ - gpg_error_t rc; - int okay, off; - char *line; - int linelen; - - rc = assuan_write_line (ctx, command); - if (rc) - return rc; - - if (*command == '#' || !*command) - return 0; /* Don't expect a response for a comment line. */ - - again: - rc = _assuan_read_from_server (ctx, &okay, &off); - if (rc) - return rc; /* error reading from server */ - - line = ctx->inbound.line + off; - linelen = ctx->inbound.linelen - off; - - if (!okay) - rc = atoi (line); - else if (okay == 2) - { - if (!data_cb) - rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB); - else - { - char *s, *d; - - for (s=d=line; linelen; linelen--) - { - if (*s == '%' && linelen > 2) - { /* handle escaping */ - s++; - *d++ = xtoi_2 (s); - s += 2; - linelen -= 2; - } - else - *d++ = *s++; - } - *d = 0; /* add a hidden string terminator */ - rc = data_cb (data_cb_arg, line, d - line); - if (!rc) - goto again; - } - } - else if (okay == 3) - { - if (!inquire_cb) - { - assuan_write_line (ctx, "END"); /* get out of inquire mode */ - _assuan_read_from_server (ctx, &okay, &off); /* dummy read */ - rc = _assuan_error (ctx, GPG_ERR_ASS_NO_INQUIRE_CB); - } - else - { - rc = inquire_cb (inquire_cb_arg, line); - if (!rc) - rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */ - if (!rc) - goto again; - } - } - else if (okay == 4) - { - if (status_cb) - rc = status_cb (status_cb_arg, line); - if (!rc) - goto again; - } - else if (okay == 5) - { - if (!data_cb) - rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB); - else - { - rc = data_cb (data_cb_arg, NULL, 0); - if (!rc) - goto again; - } - } - - return rc; -} - diff --git a/src/assuan-defs.h b/src/assuan-defs.h index c3b53f0..06e0e8b 100644 --- a/src/assuan-defs.h +++ b/src/assuan-defs.h @@ -277,9 +277,9 @@ int _assuan_cookie_write_flush (void *cookie); gpg_error_t _assuan_write_line (assuan_context_t ctx, const char *prefix, const char *line, size_t len); -/*-- assuan-client.c --*/ +/*-- client.c --*/ gpg_error_t _assuan_read_from_server (assuan_context_t ctx, - int *okay, int *off); + assuan_response_t *okay, int *off); /*-- assuan-error.c --*/ diff --git a/src/assuan-pipe-connect.c b/src/assuan-pipe-connect.c index c1dfe94..4239459 100644 --- a/src/assuan-pipe-connect.c +++ b/src/assuan-pipe-connect.c @@ -88,14 +88,15 @@ fix_signals (void) static gpg_error_t initial_handshake (assuan_context_t ctx) { - int okay, off; + assuan_response_t response; + int off; gpg_error_t err; - err = _assuan_read_from_server (ctx, &okay, &off); + err = _assuan_read_from_server (ctx, &response, &off); if (err) TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx, "can't connect server: %s", gpg_strerror (err)); - else if (okay != 1) + else if (response != ASSUAN_RESPONSE_OK) { TRACE1 (ctx, ASSUAN_LOG_SYSIO, "initial_handshake", ctx, "can't connect server: `%s'", ctx->inbound.line); diff --git a/src/assuan-socket-connect.c b/src/assuan-socket-connect.c index 666f9ca..3b20f19 100644 --- a/src/assuan-socket-connect.c +++ b/src/assuan-socket-connect.c @@ -124,13 +124,14 @@ assuan_socket_connect (assuan_context_t ctx, const char *name, /* initial handshake */ { - int okay, off; + assuan_response_t response; + int off; - err = _assuan_read_from_server (ctx, &okay, &off); + err = _assuan_read_from_server (ctx, &response, &off); if (err) TRACE1 (ctx, ASSUAN_LOG_SYSIO, "assuan_socket_connect_ext", ctx, "can't connect to server: %s\n", gpg_strerror (err)); - else if (okay != 1) + else if (response != ASSUAN_RESPONSE_OK) { char *sname = _assuan_encode_c_string (ctx, ctx->inbound.line); if (sname) diff --git a/src/assuan.h b/src/assuan.h index bb5c60f..1fd7192 100644 --- a/src/assuan.h +++ b/src/assuan.h @@ -408,6 +408,26 @@ typedef struct _assuan_peercred *assuan_peercred_t; gpg_error_t assuan_get_peercred (assuan_context_t ctx, assuan_peercred_t *peercred); + + +/* Client interface. */ +#define ASSUAN_RESPONSE_ERROR 0 +#define ASSUAN_RESPONSE_OK 1 +#define ASSUAN_RESPONSE_DATA 2 +#define ASSUAN_RESPONSE_INQUIRE 3 +#define ASSUAN_RESPONSE_STATUS 4 +#define ASSUAN_RESPONSE_END 5 +typedef int assuan_response_t; + +/* This already de-escapes data lines. */ +gpg_error_t assuan_client_read_response (assuan_context_t ctx, + char **line, int *linelen); + +gpg_error_t assuan_client_parse_response (assuan_context_t ctx, + char *line, int linelen, + assuan_response_t *response, + int *off); + /*-- assuan-client.c --*/ gpg_error_t assuan_transact (assuan_context_t ctx, diff --git a/src/client.c b/src/client.c index 685a941..e74b73b 100644 --- a/src/client.c +++ b/src/client.c @@ -22,9 +22,16 @@ #include <config.h> #endif +#include <stdlib.h> + #include "assuan-defs.h" #include "debug.h" +#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \ + *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10)) +#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1)) + + void _assuan_client_finish (assuan_context_t ctx) { @@ -58,3 +65,243 @@ _assuan_client_release (assuan_context_t ctx) _assuan_client_finish (ctx); } + + +/* This function also does deescaping for data lines. */ +gpg_error_t +assuan_client_read_response (assuan_context_t ctx, + char **line_r, int *linelen_r) +{ + gpg_error_t rc; + char *line = NULL; + int linelen = 0; + + *line_r = NULL; + *linelen_r = 0; + + do + { + do + { + rc = _assuan_read_line (ctx); + } + while (_assuan_error_is_eagain (ctx, rc)); + if (rc) + return rc; + line = ctx->inbound.line; + linelen = ctx->inbound.linelen; + } + while (*line == '#' || !linelen); + + /* For data lines, we deescape immediately. The user will never + have to worry about it. */ + if (linelen >= 1 && line[0] == 'D' && line[1] == ' ') + { + char *s, *d; + for (s=d=line; linelen; linelen--) + { + if (*s == '%' && linelen > 2) + { /* handle escaping */ + s++; + *d++ = xtoi_2 (s); + s += 2; + linelen -= 2; + } + else + *d++ = *s++; + } + *d = 0; /* add a hidden string terminator */ + + ctx->inbound.linelen = linelen; + } + + *line_r = line; + *linelen_r = linelen; + + return 0; +} + + +gpg_error_t +assuan_client_parse_response (assuan_context_t ctx, char *line, int linelen, + assuan_response_t *response, int *off) +{ + *response = ASSUAN_RESPONSE_ERROR; + *off = 0; + + if (linelen >= 1 + && line[0] == 'D' && line[1] == ' ') + { + *response = ASSUAN_RESPONSE_DATA; /* data line */ + *off = 2; + } + else if (linelen >= 1 + && line[0] == 'S' + && (line[1] == '\0' || line[1] == ' ')) + { + *response = ASSUAN_RESPONSE_STATUS; + *off = 1; + while (line[*off] == ' ') + ++*off; + } + else if (linelen >= 2 + && line[0] == 'O' && line[1] == 'K' + && (line[2] == '\0' || line[2] == ' ')) + { + *response = ASSUAN_RESPONSE_OK; + *off = 2; + while (line[*off] == ' ') + ++*off; + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'R' && line[2] == 'R' + && (line[3] == '\0' || line[3] == ' ')) + { + *response = ASSUAN_RESPONSE_ERROR; + *off = 3; + while (line[*off] == ' ') + ++*off; + } + else if (linelen >= 7 + && line[0] == 'I' && line[1] == 'N' && line[2] == 'Q' + && line[3] == 'U' && line[4] == 'I' && line[5] == 'R' + && line[6] == 'E' + && (line[7] == '\0' || line[7] == ' ')) + { + *response = ASSUAN_RESPONSE_INQUIRE; + *off = 7; + while (line[*off] == ' ') + ++*off; + } + else if (linelen >= 3 + && line[0] == 'E' && line[1] == 'N' && line[2] == 'D' + && (line[3] == '\0' || line[3] == ' ')) + { + *response = ASSUAN_RESPONSE_END; + *off = 3; + } + else + return _assuan_error (ctx, GPG_ERR_ASS_INV_RESPONSE); + + return 0; +} + + +gpg_error_t +_assuan_read_from_server (assuan_context_t ctx, assuan_response_t *response, + int *off) +{ + gpg_error_t rc; + char *line; + int linelen; + + *response = ASSUAN_RESPONSE_ERROR; + *off = 0; + rc = assuan_client_read_response (ctx, &line, &linelen); + if (!rc) + rc = assuan_client_parse_response (ctx, line, linelen, response, off); + return rc; +} + + +/** + * assuan_transact: + * @ctx: The Assuan context + * @command: Command line to be send to the server + * @data_cb: Callback function for data lines + * @data_cb_arg: first argument passed to @data_cb + * @inquire_cb: Callback function for a inquire response + * @inquire_cb_arg: first argument passed to @inquire_cb + * @status_cb: Callback function for a status response + * @status_cb_arg: first argument passed to @status_cb + * + * FIXME: Write documentation + * + * Return value: 0 on success or error code. The error code may be + * the one one returned by the server in error lines or from the + * callback functions. Take care: When a callback returns an error + * this function returns immediately with an error and thus the caller + * will altter return an Assuan error (write erro in most cases). + **/ +gpg_error_t +assuan_transact (assuan_context_t ctx, + const char *command, + gpg_error_t (*data_cb)(void *, const void *, size_t), + void *data_cb_arg, + gpg_error_t (*inquire_cb)(void*, const char *), + void *inquire_cb_arg, + gpg_error_t (*status_cb)(void*, const char *), + void *status_cb_arg) +{ + gpg_error_t rc; + assuan_response_t response; + int off; + char *line; + int linelen; + + rc = assuan_write_line (ctx, command); + if (rc) + return rc; + + if (*command == '#' || !*command) + return 0; /* Don't expect a response for a comment line. */ + + again: + rc = _assuan_read_from_server (ctx, &response, &off); + if (rc) + return rc; /* error reading from server */ + + line = ctx->inbound.line + off; + linelen = ctx->inbound.linelen - off; + + if (response == ASSUAN_RESPONSE_ERROR) + rc = atoi (line); + else if (response == ASSUAN_RESPONSE_DATA) + { + if (!data_cb) + rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB); + else + { + rc = data_cb (data_cb_arg, line, linelen); + if (!rc) + goto again; + } + } + else if (response == ASSUAN_RESPONSE_INQUIRE) + { + if (!inquire_cb) + { + assuan_write_line (ctx, "END"); /* get out of inquire mode */ + _assuan_read_from_server (ctx, &response, &off); /* dummy read */ + rc = _assuan_error (ctx, GPG_ERR_ASS_NO_INQUIRE_CB); + } + else + { + rc = inquire_cb (inquire_cb_arg, line); + if (!rc) + rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */ + if (!rc) + goto again; + } + } + else if (response == ASSUAN_RESPONSE_STATUS) + { + if (status_cb) + rc = status_cb (status_cb_arg, line); + if (!rc) + goto again; + } + else if (response == ASSUAN_RESPONSE_END) + { + if (!data_cb) + rc = _assuan_error (ctx, GPG_ERR_ASS_NO_DATA_CB); + else + { + rc = data_cb (data_cb_arg, NULL, 0); + if (!rc) + goto again; + } + } + + return rc; +} diff --git a/src/libassuan.def b/src/libassuan.def index 7896acb..456bbbe 100644 --- a/src/libassuan.def +++ b/src/libassuan.def @@ -94,6 +94,8 @@ EXPORTS __assuan_spawn @73 __assuan_usleep @74 assuan_fdopen @75 + assuan_client_read_response @76 + assuan_client_parse_response @77 ; END diff --git a/src/libassuan.vers b/src/libassuan.vers index f7b8559..923db6a 100644 --- a/src/libassuan.vers +++ b/src/libassuan.vers @@ -24,6 +24,8 @@ LIBASSUAN_1.0 { global: assuan_accept; assuan_begin_confidential; + assuan_client_read_response; + assuan_client_parse_response; assuan_close_input_fd; assuan_close_output_fd; assuan_command_parse_fd; |