summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2001-11-19 16:15:43 +0000
committerWerner Koch <wk@gnupg.org>2001-11-19 16:15:43 +0000
commit8837bf960bd112a0de63fa69084312914a8c2140 (patch)
treeb6212fa8a082410eba5128776226687d1a60fd65
parente91d7477572cb1d5f8c5eb8c44870335e9230098 (diff)
downloadlibassuan-8837bf960bd112a0de63fa69084312914a8c2140.tar.gz
Added code for data lines. For ease of implementation we need glibc
(custom streams).
-rw-r--r--src/assuan-buffer.c96
-rw-r--r--src/assuan-defs.h9
-rw-r--r--src/assuan-handler.c65
-rw-r--r--src/assuan.h1
4 files changed, 155 insertions, 16 deletions
diff --git a/src/assuan-buffer.c b/src/assuan-buffer.c
index 73786b6..912272f 100644
--- a/src/assuan-buffer.c
+++ b/src/assuan-buffer.c
@@ -149,3 +149,99 @@ _assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
return rc;
}
+
+
+/* Write out the data in buffer as datalines with line wrapping and
+ percent escaping. This fucntion is used for GNU's custom streams */
+int
+_assuan_cookie_write_data (void *cookie, const char *buffer, size_t size)
+{
+ ASSUAN_CONTEXT ctx = cookie;
+ char *line;
+ size_t linelen;
+
+ if (ctx->outbound.data.error)
+ return 0;
+
+ line = ctx->outbound.data.line;
+ linelen = ctx->outbound.data.linelen;
+ line += linelen;
+ while (size)
+ {
+ /* insert data line header */
+ if (!linelen)
+ {
+ *line++ = 'D';
+ *line++ = ' ';
+ linelen += 2;
+ }
+
+ /* copy data, keep some space for the CRLF and to escape one character */
+ while (size && linelen < LINELENGTH-2-2)
+ {
+ if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
+ {
+ sprintf (line, "%%%02X", *(unsigned char*)buffer);
+ line += 3;
+ linelen += 3;
+ buffer++;
+ }
+ else
+ {
+ *line++ = *buffer++;
+ linelen++;
+ }
+ size--;
+ }
+
+ if (linelen >= LINELENGTH-2-2)
+ {
+ *line++ = '\n';
+ linelen++;
+ if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
+ {
+ ctx->outbound.data.error = ASSUAN_Write_Error;
+ return 0;
+ }
+ line = ctx->outbound.data.line;
+ linelen = 0;
+ }
+ }
+
+ ctx->outbound.data.linelen = linelen;
+ return 0;
+}
+
+
+/* Write out any buffered data
+ This fucntion is used for GNU's custom streams */
+int
+_assuan_cookie_write_flush (void *cookie)
+{
+ ASSUAN_CONTEXT ctx = cookie;
+ char *line;
+ size_t linelen;
+
+ if (ctx->outbound.data.error)
+ return 0;
+
+ line = ctx->outbound.data.line;
+ linelen = ctx->outbound.data.linelen;
+ line += linelen;
+ if (linelen)
+ {
+ *line++ = '\n';
+ linelen++;
+ if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
+ {
+ ctx->outbound.data.error = ASSUAN_Write_Error;
+ return 0;
+ }
+ ctx->outbound.data.linelen = 0;
+ }
+ return 0;
+}
+
+
+
+
diff --git a/src/assuan-defs.h b/src/assuan-defs.h
index 96e8a4a..8723fd3 100644
--- a/src/assuan-defs.h
+++ b/src/assuan-defs.h
@@ -49,6 +49,12 @@ struct assuan_context_s {
struct {
int fd;
+ struct {
+ FILE *fp;
+ char line[LINELENGTH];
+ int linelen;
+ int error;
+ } data;
} outbound;
int pipe_mode; /* We are in pipe mode, i.e. we can handle just one
@@ -74,6 +80,9 @@ int _assuan_register_std_commands (ASSUAN_CONTEXT ctx);
/*-- assuan-buffer.c --*/
int _assuan_write_line (ASSUAN_CONTEXT ctx, const char *line);
int _assuan_read_line (ASSUAN_CONTEXT ctx);
+int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
+int _assuan_cookie_write_flush (void *cookie);
+
diff --git a/src/assuan-handler.c b/src/assuan-handler.c
index 90f170a..472206b 100644
--- a/src/assuan-handler.c
+++ b/src/assuan-handler.c
@@ -192,11 +192,11 @@ assuan_register_command (ASSUAN_CONTEXT ctx,
if (!cmd_name)
return ASSUAN_Invalid_Value;
- fprintf (stderr, "DBG-assuan: registering %d as `%s'\n", cmd_id, cmd_name);
+/* fprintf (stderr, "DBG-assuan: registering %d as `%s'\n", cmd_id, cmd_name); */
if (!ctx->cmdtbl)
{
- ctx->cmdtbl_size = 10;
+ ctx->cmdtbl_size = 50;
ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
if (!ctx->cmdtbl)
return ASSUAN_Out_Of_Core;
@@ -206,13 +206,11 @@ assuan_register_command (ASSUAN_CONTEXT ctx,
{
struct cmdtbl_s *x;
- fprintf (stderr, "DBG-assuan: enlarging cmdtbl\n");
-
x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
if (!x)
return ASSUAN_Out_Of_Core;
ctx->cmdtbl = x;
- ctx->cmdtbl_size += 10;
+ ctx->cmdtbl_size += 50;
}
ctx->cmdtbl[ctx->cmdtbl_used].name = cmd_name;
@@ -285,7 +283,7 @@ dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
line += shift;
linelen -= shift;
- fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line);
+/* fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
return ctx->cmdtbl[i].handler (ctx, line);
}
@@ -316,15 +314,28 @@ assuan_process (ASSUAN_CONTEXT ctx)
if (rc)
return rc;
- fprintf (stderr, "DBG-assuan: got %d bytes `%s'\n",
- ctx->inbound.linelen, ctx->inbound.line);
+/* fprintf (stderr, "DBG-assuan: got %d bytes `%s'\n", */
+/* ctx->inbound.linelen, ctx->inbound.line); */
}
while ( *ctx->inbound.line == '#' || !ctx->inbound.linelen);
-
- /* dispatch comamnd and return reply */
+
+ ctx->outbound.data.error = 0;
+ ctx->outbound.data.linelen = 0;
+ /* dispatch command and return reply */
rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
+ /* check from data write errors */
+ if (ctx->outbound.data.fp)
+ { /* Flush the data lines */
+ fclose (ctx->outbound.data.fp);
+ ctx->outbound.data.fp = NULL;
+ if (!rc && ctx->outbound.data.error)
+ rc = ctx->outbound.data.error;
+ }
+ /* Error handling */
if (!rc)
- rc = _assuan_write_line (ctx, "OK");
+ {
+ rc = _assuan_write_line (ctx, "OK");
+ }
else if (rc == -1)
{ /* No error checking because the peer may have already disconnect */
_assuan_write_line (ctx, "OK Bye, bye - hope to meet you again");
@@ -354,6 +365,33 @@ assuan_process (ASSUAN_CONTEXT ctx)
}
+/* Return a FP to be used for data output. The FILE pointer is valid
+ until the end of a handler. So a close is not needed. Assuan does
+ all the buffering needed to insert the status line as well as the
+ required line wappping and quoting for data lines.
+
+ We use GNU's custom streams here. There should be an alternative
+ implementaion for systems w/o a glibc, a simple implementation
+ could use a child process */
+FILE *
+assuan_get_data_fp (ASSUAN_CONTEXT ctx)
+{
+ cookie_io_functions_t cookie_fnc;
+
+ if (ctx->outbound.data.fp)
+ return ctx->outbound.data.fp;
+
+ cookie_fnc.read = NULL;
+ cookie_fnc.write = _assuan_cookie_write_data;
+ cookie_fnc.seek = NULL;
+ cookie_fnc.close = _assuan_cookie_write_flush;
+
+ ctx->outbound.data.fp = fopencookie (ctx, "wb", cookie_fnc);
+ ctx->outbound.data.error = 0;
+ return ctx->outbound.data.fp;
+}
+
+
void
assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
{
@@ -391,8 +429,3 @@ assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
xfree (helpbuf);
}
}
-
-
-
-
-
diff --git a/src/assuan.h b/src/assuan.h
index 02a8fda..e6b33c7 100644
--- a/src/assuan.h
+++ b/src/assuan.h
@@ -80,6 +80,7 @@ int assuan_register_command (ASSUAN_CONTEXT ctx,
int cmd_id, const char *cmd_string,
int (*handler)(ASSUAN_CONTEXT, char *));
int assuan_process (ASSUAN_CONTEXT ctx);
+FILE *assuan_get_data_fp (ASSUAN_CONTEXT ctx);
void assuan_write_status (ASSUAN_CONTEXT ctx,
const char *keyword, const char *text);