diff options
Diffstat (limited to '')
-rw-r--r-- | assuan/assuan-handler.c | 129 |
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) { |