aboutsummaryrefslogtreecommitdiffstats
path: root/assuan/assuan-handler.c
diff options
context:
space:
mode:
authorMarcus Brinkmann <[email protected]>2009-03-06 22:29:49 +0000
committerMarcus Brinkmann <[email protected]>2009-03-06 22:29:49 +0000
commit9ace1d56423f849b23fecdb77dd7ad6854975460 (patch)
tree212cfbddf9a9a640d597f2b39c993b166852e811 /assuan/assuan-handler.c
parentChnaged the op-assuan interface. (diff)
downloadgpgme-9ace1d56423f849b23fecdb77dd7ad6854975460.tar.gz
gpgme-9ace1d56423f849b23fecdb77dd7ad6854975460.zip
assuan/
2009-03-06 Marcus Brinkmann <[email protected]> * assuan/: Update to libassuan SVN 2009-03-06. src/ 2009-03-06 Marcus Brinkmann <[email protected]> * version.c (do_subsystem_inits): Do not set assuan log level. * debug.c (debug_init): Likewise.
Diffstat (limited to 'assuan/assuan-handler.c')
-rw-r--r--assuan/assuan-handler.c290
1 files changed, 206 insertions, 84 deletions
diff --git a/assuan/assuan-handler.c b/assuan/assuan-handler.c
index d1b29cff..b940bfd4 100644
--- a/assuan/assuan-handler.c
+++ b/assuan/assuan-handler.c
@@ -1,5 +1,5 @@
/* assuan-handler.c - dispatch commands
- * Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2007 Free Software Foundation, Inc.
*
* This file is part of Assuan.
*
@@ -14,9 +14,7 @@
* 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, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
@@ -35,18 +33,21 @@
static int my_strcasecmp (const char *a, const char *b);
+#define PROCESS_DONE(ctx, rc) \
+ ((ctx)->in_process_next ? assuan_process_done ((ctx), (rc)) : (rc))
static int
dummy_handler (assuan_context_t ctx, char *line)
{
- return set_error (ctx, Server_Fault, "no handler registered");
+ return
+ PROCESS_DONE (ctx, set_error (ctx, Server_Fault, "no handler registered"));
}
static int
std_handler_nop (assuan_context_t ctx, char *line)
{
- return 0; /* okay */
+ return PROCESS_DONE (ctx, 0); /* okay */
}
static int
@@ -54,7 +55,7 @@ std_handler_cancel (assuan_context_t ctx, char *line)
{
if (ctx->cancel_notify_fnc)
ctx->cancel_notify_fnc (ctx);
- return set_error (ctx, Not_Implemented, NULL);
+ return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL));
}
static int
@@ -65,9 +66,12 @@ std_handler_option (assuan_context_t ctx, char *line)
for (key=line; spacep (key); key++)
;
if (!*key)
- return set_error (ctx, Syntax_Error, "argument required");
+ return
+ PROCESS_DONE (ctx, set_error (ctx, Syntax_Error, "argument required"));
if (*key == '=')
- return set_error (ctx, Syntax_Error, "no option name given");
+ return
+ PROCESS_DONE (ctx, set_error (ctx, Syntax_Error,
+ "no option name given"));
for (value=key; *value && !spacep (value) && *value != '='; value++)
;
if (*value)
@@ -82,7 +86,9 @@ std_handler_option (assuan_context_t ctx, char *line)
for (; spacep (value); value++)
;
if (!*value)
- return set_error (ctx, Syntax_Error, "option argument expected");
+ return
+ PROCESS_DONE (ctx, set_error (ctx, Syntax_Error,
+ "option argument expected"));
}
if (*value)
{
@@ -96,12 +102,13 @@ std_handler_option (assuan_context_t ctx, char *line)
if (*key == '-' && key[1] == '-' && key[2])
key += 2; /* the double dashes are optional */
if (*key == '-')
- return set_error (ctx, Syntax_Error,
- "option should not begin with one dash");
+ return PROCESS_DONE (ctx,
+ set_error (ctx, Syntax_Error,
+ "option should not begin with one dash"));
if (ctx->option_handler_fnc)
- return ctx->option_handler_fnc (ctx, key, value);
- return 0;
+ return PROCESS_DONE (ctx, ctx->option_handler_fnc (ctx, key, value));
+ return PROCESS_DONE (ctx, 0);
}
static int
@@ -111,13 +118,13 @@ std_handler_bye (assuan_context_t ctx, char *line)
ctx->bye_notify_fnc (ctx);
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
- return -1; /* pretty simple :-) */
+ return PROCESS_DONE (ctx, _assuan_error (-1)); /* pretty simple :-) */
}
static int
std_handler_auth (assuan_context_t ctx, char *line)
{
- return set_error (ctx, Not_Implemented, NULL);
+ return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL));
}
static int
@@ -128,17 +135,35 @@ std_handler_reset (assuan_context_t ctx, char *line)
assuan_close_input_fd (ctx);
assuan_close_output_fd (ctx);
_assuan_uds_close_fds (ctx);
- return 0;
+ return PROCESS_DONE (ctx, 0);
}
static int
+std_handler_help (assuan_context_t ctx, char *line)
+{
+ unsigned int i;
+ char buf[ASSUAN_LINELENGTH];
+
+ for (i = 0; i < ctx->cmdtbl_used; i++)
+ {
+ snprintf (buf, sizeof (buf), "# %s", ctx->cmdtbl[i].name);
+ buf[ASSUAN_LINELENGTH - 1] = '\0';
+ assuan_write_line (ctx, buf);
+ }
+
+ return PROCESS_DONE (ctx, 0);
+}
+
+
+static int
std_handler_end (assuan_context_t ctx, char *line)
{
- return set_error (ctx, Not_Implemented, NULL);
+ return PROCESS_DONE (ctx, set_error (ctx, Not_Implemented, NULL));
}
+
assuan_error_t
-assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd)
+assuan_command_parse_fd (assuan_context_t ctx, char *line, assuan_fd_t *rfd)
{
char *endp;
@@ -151,7 +176,13 @@ assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd)
line ++;
if (!digitp (*line))
return set_error (ctx, Syntax_Error, "number required");
+#ifdef HAVE_W32_SYSTEM
+ /* Fixme: For a W32/64bit system we will need to change the cast
+ and the conversion fucntion. */
+ *rfd = (void*)strtoul (line, &endp, 10);
+#else
*rfd = strtoul (line, &endp, 10);
+#endif
/* Remove that argument so that a notify handler won't see it. */
memset (line, ' ', endp? (endp-line):strlen(line));
@@ -166,34 +197,37 @@ assuan_command_parse_fd (assuan_context_t ctx, char *line, int *rfd)
return assuan_receivefd (ctx, rfd);
}
+
/* Format is INPUT FD=<n> */
static int
std_handler_input (assuan_context_t ctx, char *line)
{
- int rc, fd;
+ int rc;
+ assuan_fd_t fd;
rc = assuan_command_parse_fd (ctx, line, &fd);
if (rc)
- return rc;
+ return PROCESS_DONE (ctx, rc);
ctx->input_fd = fd;
if (ctx->input_notify_fnc)
ctx->input_notify_fnc (ctx, line);
- return 0;
+ return PROCESS_DONE (ctx, 0);
}
/* Format is OUTPUT FD=<n> */
static int
std_handler_output (assuan_context_t ctx, char *line)
{
- int rc, fd;
+ int rc;
+ assuan_fd_t fd;
rc = assuan_command_parse_fd (ctx, line, &fd);
if (rc)
- return rc;
+ return PROCESS_DONE (ctx, rc);
ctx->output_fd = fd;
if (ctx->output_notify_fnc)
ctx->output_notify_fnc (ctx, line);
- return 0;
+ return PROCESS_DONE (ctx, 0);
}
@@ -215,11 +249,12 @@ static struct {
{ "AUTH", std_handler_auth, 1 },
{ "RESET", std_handler_reset, 1 },
{ "END", std_handler_end, 1 },
+ { "HELP", std_handler_help, 1 },
- { "INPUT", std_handler_input },
- { "OUTPUT", std_handler_output },
+ { "INPUT", std_handler_input, 0 },
+ { "OUTPUT", std_handler_output, 0 },
{ "OPTION", std_handler_option, 1 },
- { NULL }
+ { NULL, NULL, 0 }
};
@@ -406,9 +441,10 @@ my_strcasecmp (const char *a, const char *b)
return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
}
+
/* Parse the line, break out the command, find it in the command
table, remove leading and white spaces from the arguments, call the
- handler with the argument line and return the error */
+ handler with the argument line and return the error. */
static int
dispatch_command (assuan_context_t ctx, char *line, int linelen)
{
@@ -416,13 +452,21 @@ dispatch_command (assuan_context_t ctx, char *line, int linelen)
const char *s;
int shift, i;
+ /* Note that as this function is invoked by assuan_process_next as
+ well, we need to hide non-critical errors with PROCESS_DONE. */
+
if (*line == 'D' && line[1] == ' ') /* divert to special handler */
- return handle_data_line (ctx, line+2, linelen-2);
+ /* FIXME: Depending on the final implementation of
+ handle_data_line, this may be wrong here. For example, if a
+ user callback is invoked, and that callback is responsible for
+ calling assuan_process_done, then this is wrong. */
+ return PROCESS_DONE (ctx, handle_data_line (ctx, line+2, linelen-2));
for (p=line; *p && *p != ' ' && *p != '\t'; p++)
;
if (p==line)
- return set_error (ctx, Syntax_Error, "leading white-space");
+ return PROCESS_DONE
+ (ctx, set_error (ctx, Syntax_Error, "leading white-space"));
if (*p)
{ /* Skip over leading WS after the keyword */
*p++ = 0;
@@ -445,7 +489,7 @@ dispatch_command (assuan_context_t ctx, char *line, int linelen)
}
}
if (!s)
- return set_error (ctx, Unknown_Command, NULL);
+ return PROCESS_DONE (ctx, set_error (ctx, Unknown_Command, NULL));
line += shift;
linelen -= shift;
@@ -453,42 +497,34 @@ dispatch_command (assuan_context_t ctx, char *line, int linelen)
return ctx->cmdtbl[i].handler (ctx, line);
}
-
-
-static int
-process_request (assuan_context_t ctx)
+/* Call this to acknowledge the current command. */
+int
+assuan_process_done (assuan_context_t ctx, int rc)
{
- int rc;
-
- if (ctx->in_inquire)
- return _assuan_error (ASSUAN_Nested_Commands);
+ if (!ctx->in_command)
+ return _assuan_error (ASSUAN_General_Error);
- rc = _assuan_read_line (ctx);
- if (rc)
- return rc;
- if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
- return 0; /* comment line - ignore */
+ ctx->in_command = 0;
- 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 */
+ /* Check for data write errors. */
if (ctx->outbound.data.fp)
- { /* Flush the data lines */
+ {
+ /* 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;
+ rc = ctx->outbound.data.error;
}
- else /* flush any data send w/o using the data fp */
+ else
{
+ /* Flush any data send without using the data FP. */
assuan_send_data (ctx, NULL, 0);
if (!rc && ctx->outbound.data.error)
- rc = ctx->outbound.data.error;
+ rc = ctx->outbound.data.error;
}
- /* Error handling */
+
+ /* Error handling. */
if (!rc)
{
rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
@@ -501,26 +537,26 @@ process_request (assuan_context_t ctx)
else
{
char errline[300];
-
+
if (rc < 100)
sprintf (errline, "ERR %d server fault (%.50s)",
_assuan_error (ASSUAN_Server_Fault), assuan_strerror (rc));
else
{
const char *text = ctx->err_no == rc? ctx->err_str:NULL;
-
+
#if defined(HAVE_W32_SYSTEM)
unsigned int source, code;
char ebuf[50];
const char *esrc;
-
+
source = ((rc >> 24) & 0xff);
code = (rc & 0x00ffffff);
if (source
&& !_assuan_gpg_strerror_r (rc, ebuf, sizeof ebuf)
&& (esrc=_assuan_gpg_strsource (rc)))
{
- /* Assume this is an libgpg-error. */
+ /* Assume this is an libgpg-error. */
sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
rc, ebuf, esrc,
text? " - ":"", text?text:"");
@@ -554,7 +590,7 @@ process_request (assuan_context_t ctx)
{
/* Assume this is an libgpg-error. */
char ebuf[50];
-
+
gpg_strerror_r (rc, ebuf, sizeof ebuf );
sprintf (errline, "ERR %d %.50s <%.30s>%s%.100s",
rc,
@@ -569,19 +605,123 @@ process_request (assuan_context_t ctx)
}
rc = assuan_write_line (ctx, errline);
}
-
+
if (ctx->post_cmd_notify_fnc)
ctx->post_cmd_notify_fnc (ctx, rc);
-
+
ctx->confidential = 0;
if (ctx->okay_line)
{
xfree (ctx->okay_line);
ctx->okay_line = NULL;
}
+
+ return rc;
+}
+
+
+static int
+process_next (assuan_context_t ctx)
+{
+ int rc;
+
+ /* What the next thing to do is depends on the current state.
+ However, we will always first read the next line. The client is
+ required to write full lines without blocking long after starting
+ a partial line. */
+ rc = _assuan_read_line (ctx);
+ if (_assuan_error_is_eagain (rc))
+ return 0;
+ if (rc)
+ return rc;
+ if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
+ /* Comment lines are ignored. */
+ return 0;
+
+ /* Now we have a line that really means something. It could be one
+ of the following things: First, if we are not in a command
+ already, it is the next command to dispatch. Second, if we are
+ in a command, it can only be the response to an INQUIRE
+ reply. */
+
+ if (!ctx->in_command)
+ {
+ ctx->in_command = 1;
+
+ ctx->outbound.data.error = 0;
+ ctx->outbound.data.linelen = 0;
+ /* Dispatch command and return reply. */
+ ctx->in_process_next = 1;
+ rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
+ ctx->in_process_next = 0;
+ }
+ else if (ctx->in_inquire)
+ {
+ /* FIXME: Pick up the continuation. */
+ rc = _assuan_inquire_ext_cb (ctx);
+ }
+ else
+ {
+ /* Should not happen. The client is sending data while we are
+ in a command and not waiting for an inquire. We log an error
+ and discard it. */
+ _assuan_log_printf ("unexpected client data\n");
+ rc = 0;
+ }
+
return rc;
}
+
+/* This function should be invoked when the assuan connected FD is
+ ready for reading. If the equivalent to EWOULDBLOCK is returned
+ (this should be done by the command handler), assuan_process_next
+ should be invoked the next time the connected FD is readable.
+ Eventually, the caller will finish by invoking
+ assuan_process_done. */
+int
+assuan_process_next (assuan_context_t ctx)
+{
+ int rc;
+
+ do
+ {
+ rc = process_next (ctx);
+ }
+ while (!rc && assuan_pending_line (ctx));
+
+ return rc;
+}
+
+
+
+static int
+process_request (assuan_context_t ctx)
+{
+ int rc;
+
+ if (ctx->in_inquire)
+ return _assuan_error (ASSUAN_Nested_Commands);
+
+ do
+ {
+ rc = _assuan_read_line (ctx);
+ }
+ while (_assuan_error_is_eagain (rc));
+ if (rc)
+ return rc;
+ if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
+ return 0; /* comment line - ignore */
+
+ ctx->in_command = 1;
+ 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);
+
+ return assuan_process_done (ctx, rc);
+}
+
/**
* assuan_process:
* @ctx: assuan context
@@ -610,24 +750,6 @@ assuan_process (assuan_context_t ctx)
/**
- * assuan_process_next:
- * @ctx: Assuan context
- *
- * Same as assuan_process() but the user has to provide the outer
- * loop. He should loop as long as the return code is zero and stop
- * otherwise; -1 is regular end.
- *
- * See also: assuan_get_active_fds()
- * Return value: -1 for end of server, 0 on success or an error code
- **/
-int
-assuan_process_next (assuan_context_t ctx)
-{
- return process_request (ctx);
-}
-
-
-/**
* assuan_get_active_fds:
* @ctx: Assuan context
* @what: 0 for read fds, 1 for write fds
@@ -646,7 +768,7 @@ assuan_process_next (assuan_context_t ctx)
**/
int
assuan_get_active_fds (assuan_context_t ctx, int what,
- int *fdarray, int fdarraysize)
+ assuan_fd_t *fdarray, int fdarraysize)
{
int n = 0;
@@ -655,16 +777,16 @@ assuan_get_active_fds (assuan_context_t ctx, int what,
if (!what)
{
- if (ctx->inbound.fd != -1)
+ if (ctx->inbound.fd != ASSUAN_INVALID_FD)
fdarray[n++] = ctx->inbound.fd;
}
else
{
- if (ctx->outbound.fd != -1)
+ if (ctx->outbound.fd != ASSUAN_INVALID_FD)
fdarray[n++] = ctx->outbound.fd;
if (ctx->outbound.data.fp)
#ifdef HAVE_W32_SYSTEM
- fdarray[n++] = _get_osfhandle (fileno (ctx->outbound.data.fp));
+ fdarray[n++] = (void*)_get_osfhandle (fileno (ctx->outbound.data.fp));
#else
fdarray[n++] = fileno (ctx->outbound.data.fp);
#endif