summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--src/ChangeLog23
-rw-r--r--src/Makefile.am1
-rw-r--r--src/assuan-client.c233
-rw-r--r--src/assuan-defs.h4
-rw-r--r--src/assuan-pipe-connect.c7
-rw-r--r--src/assuan-socket-connect.c7
-rw-r--r--src/assuan.h20
-rw-r--r--src/client.c247
-rw-r--r--src/libassuan.def2
-rw-r--r--src/libassuan.vers2
11 files changed, 306 insertions, 242 deletions
diff --git a/NEWS b/NEWS
index f16d56c..8d29117 100644
--- a/NEWS
+++ b/NEWS
@@ -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;