diff --git a/assuan/ChangeLog b/assuan/ChangeLog index 3c3fdcd23..d12aceef3 100644 --- a/assuan/ChangeLog +++ b/assuan/ChangeLog @@ -1,3 +1,13 @@ +2002-01-20 Werner Koch + + * assuan.h: Added Invalid Option error code. + + * assuan-handler.c (std_handler_option): New. + (std_cmd_tbl): Add OPTION as standard command. + (assuan_register_option_handler): New. + (dispatch_command): Use case insensitive matching as a fallback. + (my_strcasecmp): New. + 2002-01-19 Werner Koch * assuan-buffer.c (_assuan_read_line): Add output logging. diff --git a/assuan/assuan-defs.h b/assuan/assuan-defs.h index d19e6b9cc..c14b40991 100644 --- a/assuan/assuan-defs.h +++ b/assuan/assuan-defs.h @@ -87,6 +87,7 @@ struct assuan_context_s { void (*bye_notify_fnc)(ASSUAN_CONTEXT); void (*reset_notify_fnc)(ASSUAN_CONTEXT); void (*cancel_notify_fnc)(ASSUAN_CONTEXT); + int (*option_handler_fnc)(ASSUAN_CONTEXT,const char*, const char*); void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *); void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *); diff --git a/assuan/assuan-handler.c b/assuan/assuan-handler.c index db9749e50..1c8aded7b 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 } }; @@ -262,6 +312,17 @@ assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT)) return 0; } +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; diff --git a/assuan/assuan.h b/assuan/assuan.h index 3382283cc..31d6fbd32 100644 --- a/assuan/assuan.h +++ b/assuan/assuan.h @@ -72,6 +72,7 @@ typedef enum { ASSUAN_Too_Much_Data = 119, ASSUAN_Inquire_Unknown = 120, ASSUAN_Inquire_Error = 121, + ASSUAN_Invalid_Option = 122, ASSUAN_Bad_Certificate = 201, ASSUAN_Bad_Certificate_Path = 202, @@ -97,6 +98,7 @@ typedef enum { ASSUAN_CMD_BYE, ASSUAN_CMD_AUTH, ASSUAN_CMD_RESET, + ASSUAN_CMD_OPTION, ASSUAN_CMD_DATA, ASSUAN_CMD_END, ASSUAN_CMD_INPUT, @@ -124,6 +126,11 @@ int assuan_register_input_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT, const char *)); int assuan_register_output_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT, const char *)); + +int assuan_register_option_handler (ASSUAN_CONTEXT ctx, + int (*fnc)(ASSUAN_CONTEXT, + const char*, const char*)); + int assuan_process (ASSUAN_CONTEXT ctx); int assuan_process_next (ASSUAN_CONTEXT ctx); int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,