aboutsummaryrefslogtreecommitdiffstats
path: root/assuan/assuan-handler.c
diff options
context:
space:
mode:
Diffstat (limited to 'assuan/assuan-handler.c')
-rw-r--r--assuan/assuan-handler.c129
1 files changed, 125 insertions, 4 deletions
diff --git a/assuan/assuan-handler.c b/assuan/assuan-handler.c
index a82bd537..1c8aded7 100644
--- a/assuan/assuan-handler.c
+++ b/assuan/assuan-handler.c
@@ -25,6 +25,7 @@
#include "assuan-defs.h"
+#define spacep(p) (*(p) == ' ' || *(p) == '\t')
#define digitp(a) ((a) >= '0' && (a) <= '9')
@@ -48,6 +49,53 @@ std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
ctx->cancel_notify_fnc (ctx);
return set_error (ctx, Not_Implemented, NULL);
}
+
+static int
+std_handler_option (ASSUAN_CONTEXT ctx, char *line)
+{
+ char *key, *value, *p;
+
+ for (key=line; spacep (key); key++)
+ ;
+ if (!*key)
+ return set_error (ctx, Syntax_Error, "argument required");
+ if (*key == '=')
+ return set_error (ctx, Syntax_Error, "no option name given");
+ for (value=key; *value && !spacep (value) && *value != '='; value++)
+ ;
+ if (*value)
+ {
+ if (spacep (value))
+ *value++ = 0; /* terminate key */
+ for (; spacep (value); value++)
+ ;
+ if (*value == '=')
+ {
+ *value++ = 0; /* terminate key */
+ for (; spacep (value); value++)
+ ;
+ if (!*value)
+ return set_error (ctx, Syntax_Error, "option argument expected");
+ }
+ if (*value)
+ {
+ for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
+ ;
+ if (p > value)
+ *++p = 0; /* strip trailing spaces */
+ }
+ }
+
+ 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");
+
+ if (ctx->option_handler_fnc)
+ return ctx->option_handler_fnc (ctx, key, value);
+ return 0;
+}
static int
std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
@@ -147,6 +195,7 @@ static struct {
} std_cmd_table[] = {
{ "NOP", ASSUAN_CMD_NOP, std_handler_nop, 1 },
{ "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 },
+ { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
{ "BYE", ASSUAN_CMD_BYE, std_handler_bye, 1 },
{ "AUTH", ASSUAN_CMD_AUTH, std_handler_auth, 1 },
{ "RESET", ASSUAN_CMD_RESET, std_handler_reset, 1 },
@@ -154,6 +203,7 @@ static struct {
{ "INPUT", ASSUAN_CMD_INPUT, std_handler_input },
{ "OUTPUT", ASSUAN_CMD_OUTPUT, std_handler_output },
+ { "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
{ NULL }
};
@@ -263,6 +313,17 @@ assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
}
int
+assuan_register_option_handler (ASSUAN_CONTEXT ctx,
+ int (*fnc)(ASSUAN_CONTEXT,
+ const char*, const char*))
+{
+ if (!ctx)
+ return ASSUAN_Invalid_Value;
+ ctx->option_handler_fnc = fnc;
+ return 0;
+}
+
+int
assuan_register_input_notify (ASSUAN_CONTEXT ctx,
void (*fnc)(ASSUAN_CONTEXT, const char *))
{
@@ -312,6 +373,20 @@ handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen)
return set_error (ctx, Not_Implemented, NULL);
}
+/* like ascii_strcasecmp but assume that B is already uppercase */
+static int
+my_strcasecmp (const char *a, const char *b)
+{
+ if (a == b)
+ return 0;
+
+ for (; *a && *b; a++, b++)
+ {
+ if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
+ break;
+ }
+ 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, all the
@@ -339,8 +414,18 @@ dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
shift = p - line;
for (i=0; (s=ctx->cmdtbl[i].name); i++)
- if (!strcmp (line, s))
- break;
+ {
+ if (!strcmp (line, s))
+ break;
+ }
+ if (!s)
+ { /* and try case insensitive */
+ for (i=0; (s=ctx->cmdtbl[i].name); i++)
+ {
+ if (!my_strcasecmp (line, s))
+ break;
+ }
+ }
if (!s)
return set_error (ctx, Unknown_Command, NULL);
line += shift;
@@ -382,17 +467,18 @@ process_request (ASSUAN_CONTEXT ctx)
/* Error handling */
if (!rc)
{
- rc = assuan_write_line (ctx, "OK");
+ rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
}
else if (rc == -1)
{ /* No error checking because the peer may have already disconnect */
assuan_write_line (ctx, "OK closing connection");
+ ctx->finish_handler (ctx);
}
else
{
char errline[256];
- if (rc < 100)
+ if (rc < 100)
sprintf (errline, "ERR %d server fault (%.50s)",
ASSUAN_Server_Fault, assuan_strerror (rc));
else
@@ -405,6 +491,12 @@ process_request (ASSUAN_CONTEXT ctx)
rc = assuan_write_line (ctx, errline);
}
+ ctx->confidential = 0;
+ if (ctx->okay_line)
+ {
+ xfree (ctx->okay_line);
+ ctx->okay_line = NULL;
+ }
return rc;
}
@@ -522,6 +614,35 @@ assuan_get_data_fp (ASSUAN_CONTEXT ctx)
}
+/* Set the text used for the next OK reponse. This string is
+ automatically reset to NULL after the next command. */
+AssuanError
+assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line)
+{
+ if (!ctx)
+ return ASSUAN_Invalid_Value;
+ if (!line)
+ {
+ xfree (ctx->okay_line);
+ ctx->okay_line = NULL;
+ }
+ else
+ {
+ /* FIXME: we need to use gcry_is_secure() to test whether
+ we should allocate the entire line in secure memory */
+ char *buf = xtrymalloc (3+strlen(line)+1);
+ if (!buf)
+ return ASSUAN_Out_Of_Core;
+ strcpy (buf, "OK ");
+ strcpy (buf+3, line);
+ xfree (ctx->okay_line);
+ ctx->okay_line = buf;
+ }
+ return 0;
+}
+
+
+
void
assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
{