From ff1ba2fdc758f330d279df78bcee582935615201 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Mon, 19 Nov 2001 16:15:43 +0000 Subject: [PATCH] Added code for data lines. For ease of implementation we need glibc (custom streams). --- assuan/assuan-buffer.c | 96 +++++++++++++++++++++++++++++++++++++++++ assuan/assuan-defs.h | 9 ++++ assuan/assuan-handler.c | 65 +++++++++++++++++++++------- assuan/assuan.h | 1 + 4 files changed, 155 insertions(+), 16 deletions(-) diff --git a/assuan/assuan-buffer.c b/assuan/assuan-buffer.c index 73786b631..912272f18 100644 --- a/assuan/assuan-buffer.c +++ b/assuan/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/assuan/assuan-defs.h b/assuan/assuan-defs.h index 96e8a4a26..8723fd315 100644 --- a/assuan/assuan-defs.h +++ b/assuan/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/assuan/assuan-handler.c b/assuan/assuan-handler.c index 90f170aea..472206b05 100644 --- a/assuan/assuan-handler.c +++ b/assuan/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/assuan/assuan.h b/assuan/assuan.h index 02a8fdacd..e6b33c703 100644 --- a/assuan/assuan.h +++ b/assuan/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);