Implement boolean (yes/no or OK/Cancel, ...) input.

Implement UI controls.  Current controls are the possibility to output
the OpenSSL error stack on the same channel from within UI_process()
and to check if the same user interface can be redone without being
rebuilt (this is often more a question of philosophy than
technicalities).
This commit is contained in:
Richard Levitte 2001-06-23 16:22:48 +00:00
parent 8ada6e7705
commit 2d2ed9dffd
3 changed files with 397 additions and 52 deletions

View file

@ -91,8 +91,10 @@ UI *UI_new_method(const UI_METHOD *method);
void UI_free(UI *ui);
/* The following functions are used to add strings to be printed and prompt
strings to prompt for data. The names are UI_{add,dup}_<function>_string,
with the following meanings:
strings to prompt for data. The names are UI_{add,dup}_<function>_string
and UI_{add,dup}_input_boolean.
UI_{add,dup}_<function>_string have the following meanings:
add add a text or prompt string. The pointers given to these
functions are used verbatim, no copying is done.
dup make a copy of the text or prompt string, then add the copy
@ -108,12 +110,26 @@ void UI_free(UI *ui);
Honestly, there's currently no difference between info and error for the
moment.
All of the functions in this group take a UI and a string. The input and
verify addition functions also take a flag argument, a buffer for the result
to end up with, a minimum input size and a maximum input size (the result
buffer MUST be large enough to be able to contain the maximum number of
characters). Additionally, the verify addition functions takes another
buffer to compare the result against.
UI_{add,dup}_input_boolean have the same semantics for "add" and "dup",
and are typically used when one wants to prompt for a yes/no response.
All of the functions in this group take a UI and a prompt string.
The string input and verify addition functions also take a flag argument,
a buffer for the result to end up with, a minimum input size and a maximum
input size (the result buffer MUST be large enough to be able to contain
the maximum number of characters). Additionally, the verify addition
functions takes another buffer to compare the result against.
The boolean input functions take an action description string (which should
be safe to ignore if the expected user action is obvious, for example with
a dialog box with an OK button and a Cancel button), a string of acceptable
characters to mean OK and to mean Cancel. The two last strings are checked
to make sure they don't have common characters. Additionally, the same
flag argument as for the string input is taken, as well as a result buffer.
The result buffer is required to be at least one byte long. Depending on
the answer, the first character from the OK or the Cancel character strings
will be stored in the first byte of the result buffer. No NUL will be
added, so the result is *not* a string.
On success, the all return an index of the added information. That index
is usefull when retrieving results with UI_get0_result(). */
@ -125,6 +141,12 @@ int UI_add_verify_string(UI *ui, const char *prompt, int flags,
char *result_buf, int minsize, int maxsize, const char *test_buf);
int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
char *result_buf, int minsize, int maxsize, const char *test_buf);
int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
const char *ok_chars, const char *cancel_chars,
int flags, char *result_buf);
int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
const char *ok_chars, const char *cancel_chars,
int flags, char *result_buf);
int UI_add_info_string(UI *ui, const char *text);
int UI_dup_info_string(UI *ui, const char *text);
int UI_add_error_string(UI *ui, const char *text);
@ -192,6 +214,22 @@ const char *UI_get0_result(UI *ui, int i);
/* When all strings have been added, process the whole thing. */
int UI_process(UI *ui);
/* Give a user interface parametrised control commands. This can be used to
send down an integer, a data pointer or a function pointer, as well as
be used to get information from a UI. */
int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f)());
/* The commands */
/* Use UI_CONTROL_PRINT_ERRORS with the value 1 to have UI_process print the
OpenSSL error stack before printing any info or added error messages and
before any prompting. */
#define UI_CTRL_PRINT_ERRORS 1
/* Check if a UI_process() is possible to do again with the same instance of
a user interface. This makes UI_ctrl() return 1 if it is redoable, and 0
if not. */
#define UI_CTRL_IS_REDOABLE 2
/* Some methods may use extra data */
#define UI_set_app_data(s,arg) UI_set_ex_data(s,0,arg)
#define UI_get_app_data(s) UI_get_ex_data(s,0)
@ -265,6 +303,7 @@ enum UI_string_types
UIT_NONE=0,
UIT_PROMPT, /* Prompt for a string */
UIT_VERIFY, /* Prompt for a string and verify */
UIT_BOOLEAN, /* Prompt for a yes/no response */
UIT_INFO, /* Send info to the user */
UIT_ERROR /* Send an error message to the user */
};
@ -292,6 +331,8 @@ enum UI_string_types UI_get_string_type(UI_STRING *uis);
int UI_get_input_flags(UI_STRING *uis);
/* Return the actual string to output (the prompt, info or error) */
const char *UI_get0_output_string(UI_STRING *uis);
/* Return the optional action string to output (the boolean promtp instruction) */
const char *UI_get0_action_string(UI_STRING *uis);
/* Return the result of a prompt */
const char *UI_get0_result_string(UI_STRING *uis);
/* Return the string to test the result against. Only useful with verifies. */
@ -301,7 +342,7 @@ int UI_get_result_minsize(UI_STRING *uis);
/* Return the required maximum size of the result */
int UI_get_result_maxsize(UI_STRING *uis);
/* Set the result of a UI_STRING. */
int UI_set_result(UI_STRING *uis, const char *result);
int UI_set_result(UI *ui, UI_STRING *uis, const char *result);
/* BEGIN ERROR CODES */
@ -313,9 +354,13 @@ void ERR_load_UI_strings(void);
/* Error codes for the UI functions. */
/* Function codes. */
#define UI_F_GENERAL_ALLOCATE_BOOLEAN 108
#define UI_F_GENERAL_ALLOCATE_PROMPT 109
#define UI_F_GENERAL_ALLOCATE_STRING 100
#define UI_F_UI_CTRL 111
#define UI_F_UI_DUP_ERROR_STRING 101
#define UI_F_UI_DUP_INFO_STRING 102
#define UI_F_UI_DUP_INPUT_BOOLEAN 110
#define UI_F_UI_DUP_INPUT_STRING 103
#define UI_F_UI_DUP_VERIFY_STRING 106
#define UI_F_UI_GET0_RESULT 107
@ -323,10 +368,13 @@ void ERR_load_UI_strings(void);
#define UI_F_UI_SET_RESULT 105
/* Reason codes. */
#define UI_R_COMMON_OK_AND_CANCEL_CHARACTERS 104
#define UI_R_INDEX_TOO_LARGE 102
#define UI_R_INDEX_TOO_SMALL 103
#define UI_R_NO_RESULT_BUFFER 105
#define UI_R_RESULT_TOO_LARGE 100
#define UI_R_RESULT_TOO_SMALL 101
#define UI_R_UNKNOWN_CONTROL_COMMAND 106
#ifdef __cplusplus
}

View file

@ -98,7 +98,19 @@ UI *UI_new_method(const UI_METHOD *method)
static void free_string(UI_STRING *uis)
{
if (uis->flags & OUT_STRING_FREEABLE)
{
OPENSSL_free((char *)uis->out_string);
switch(uis->type)
{
case UIT_BOOLEAN:
OPENSSL_free((char *)uis->_.boolean_data.action_desc);
OPENSSL_free((char *)uis->_.boolean_data.ok_chars);
OPENSSL_free((char *)uis->_.boolean_data.cancel_chars);
break;
default:
break;
}
}
OPENSSL_free(uis);
}
@ -123,28 +135,98 @@ static int allocate_string_stack(UI *ui)
return 0;
}
static UI_STRING *general_allocate_prompt(UI *ui, const char *prompt,
int prompt_freeable, enum UI_string_types type, int input_flags,
char *result_buf)
{
UI_STRING *ret = NULL;
if (prompt == NULL)
{
UIerr(UI_F_GENERAL_ALLOCATE_PROMPT,ERR_R_PASSED_NULL_PARAMETER);
}
else if (result_buf == NULL)
{
UIerr(UI_F_GENERAL_ALLOCATE_PROMPT,UI_R_NO_RESULT_BUFFER);
}
else if ((ret = (UI_STRING *)OPENSSL_malloc(sizeof(UI_STRING))))
{
ret->out_string=prompt;
ret->flags=prompt_freeable ? OUT_STRING_FREEABLE : 0;
ret->input_flags=input_flags;
ret->type=type;
ret->result_buf=result_buf;
}
return ret;
}
static int general_allocate_string(UI *ui, const char *prompt,
int prompt_freeable, enum UI_string_types type, int input_flags,
char *result_buf, int minsize, int maxsize, const char *test_buf)
{
int ret=-1;
int ret = -1;
UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable,
type, input_flags, result_buf);
if (prompt == NULL)
if (s)
{
UIerr(UI_F_GENERAL_ALLOCATE_STRING,ERR_R_PASSED_NULL_PARAMETER);
if (allocate_string_stack(ui) >= 0)
{
s->_.string_data.result_minsize=minsize;
s->_.string_data.result_maxsize=maxsize;
s->_.string_data.test_buf=test_buf;
ret=sk_UI_STRING_push(ui->strings, s);
}
else
free_string(s);
}
else if (allocate_string_stack(ui) >= 0)
return ret;
}
static int general_allocate_boolean(UI *ui,
const char *prompt, const char *action_desc,
const char *ok_chars, const char *cancel_chars,
int prompt_freeable, enum UI_string_types type, int input_flags,
char *result_buf)
{
int ret = -1;
UI_STRING *s;
const char *p;
if (ok_chars == NULL)
{
UI_STRING *s=(UI_STRING *)OPENSSL_malloc(sizeof(UI_STRING));
s->out_string=prompt;
s->flags=prompt_freeable ? OUT_STRING_FREEABLE : 0;
s->input_flags=input_flags;
s->type=type;
s->result_buf=result_buf;
s->result_minsize=minsize;
s->result_maxsize=maxsize;
s->test_buf=test_buf;
ret=sk_UI_STRING_push(ui->strings, s);
UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,ERR_R_PASSED_NULL_PARAMETER);
}
else if (cancel_chars == NULL)
{
UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,ERR_R_PASSED_NULL_PARAMETER);
}
else
{
for(p = ok_chars; *p; p++)
{
if (strchr(cancel_chars, *p))
{
UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,
UI_R_COMMON_OK_AND_CANCEL_CHARACTERS);
}
}
s = general_allocate_prompt(ui, prompt, prompt_freeable,
type, input_flags, result_buf);
if (s)
{
if (allocate_string_stack(ui) >= 0)
{
s->_.boolean_data.action_desc = action_desc;
s->_.boolean_data.ok_chars = ok_chars;
s->_.boolean_data.cancel_chars = cancel_chars;
ret=sk_UI_STRING_push(ui->strings, s);
}
else
free_string(s);
}
}
return ret;
}
@ -204,6 +286,74 @@ int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
UIT_VERIFY, flags, result_buf, minsize, maxsize, test_buf);
}
int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
const char *ok_chars, const char *cancel_chars,
int flags, char *result_buf)
{
return general_allocate_boolean(ui, prompt, action_desc,
ok_chars, cancel_chars, 0, UIT_BOOLEAN, flags, result_buf);
}
int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
const char *ok_chars, const char *cancel_chars,
int flags, char *result_buf)
{
char *prompt_copy = NULL;
char *action_desc_copy = NULL;
char *ok_chars_copy = NULL;
char *cancel_chars_copy = NULL;
if (prompt)
{
prompt_copy=BUF_strdup(prompt);
if (prompt_copy == NULL)
{
UIerr(UI_F_UI_DUP_INPUT_BOOLEAN,ERR_R_MALLOC_FAILURE);
goto err;
}
}
if (action_desc)
{
action_desc_copy=BUF_strdup(action_desc);
if (action_desc_copy == NULL)
{
UIerr(UI_F_UI_DUP_INPUT_BOOLEAN,ERR_R_MALLOC_FAILURE);
goto err;
}
}
if (ok_chars)
{
ok_chars_copy=BUF_strdup(ok_chars);
if (ok_chars_copy == NULL)
{
UIerr(UI_F_UI_DUP_INPUT_BOOLEAN,ERR_R_MALLOC_FAILURE);
goto err;
}
}
if (cancel_chars)
{
cancel_chars_copy=BUF_strdup(cancel_chars);
if (cancel_chars_copy == NULL)
{
UIerr(UI_F_UI_DUP_INPUT_BOOLEAN,ERR_R_MALLOC_FAILURE);
goto err;
}
}
return general_allocate_boolean(ui, prompt_copy, action_desc_copy,
ok_chars_copy, cancel_chars_copy, 1, UIT_BOOLEAN, flags,
result_buf);
err:
if (prompt_copy) OPENSSL_free(prompt_copy);
if (action_desc_copy) OPENSSL_free(action_desc_copy);
if (ok_chars_copy) OPENSSL_free(ok_chars_copy);
if (cancel_chars_copy) OPENSSL_free(cancel_chars_copy);
return -1;
}
int UI_add_info_string(UI *ui, const char *text)
{
return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
@ -224,8 +374,8 @@ int UI_dup_info_string(UI *ui, const char *text)
}
}
return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL, 0, 0,
NULL);
return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
0, 0, NULL);
}
int UI_add_error_string(UI *ui, const char *text)
@ -313,6 +463,20 @@ const char *UI_get0_result(UI *ui, int i)
return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
}
static int print_error(const char *str, size_t len, UI *ui)
{
UI_STRING uis;
memset(&uis, 0, sizeof(uis));
uis.type = UIT_ERROR;
uis.out_string = str;
if (ui->meth->ui_write_string
&& !ui->meth->ui_write_string(ui, &uis))
return -1;
return 0;
}
int UI_process(UI *ui)
{
int i, ok=0;
@ -320,6 +484,11 @@ int UI_process(UI *ui)
if (ui->meth->ui_open_session && !ui->meth->ui_open_session(ui))
return -1;
if (ui->flags & UI_FLAG_PRINT_ERRORS)
ERR_print_errors_cb(
(int (*)(const char *, size_t, void *))print_error,
(void *)ui);
for(i=0; i<sk_UI_STRING_num(ui->strings); i++)
{
if (ui->meth->ui_write_string
@ -370,6 +539,33 @@ int UI_process(UI *ui)
return ok;
}
int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f)())
{
if (ui == NULL)
{
UIerr(UI_F_UI_CTRL,ERR_R_PASSED_NULL_PARAMETER);
return -1;
}
switch(cmd)
{
case UI_CTRL_PRINT_ERRORS:
{
int save_flag = !!(ui->flags & UI_FLAG_PRINT_ERRORS);
if (i)
ui->flags |= UI_FLAG_PRINT_ERRORS;
else
ui->flags &= ~UI_FLAG_PRINT_ERRORS;
return save_flag;
}
case UI_CTRL_IS_REDOABLE:
return !!(ui->flags & UI_FLAG_REDOABLE);
default:
break;
}
UIerr(UI_F_UI_CTRL,UI_R_UNKNOWN_CONTROL_COMMAND);
return -1;
}
int UI_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
{
@ -542,6 +738,20 @@ const char *UI_get0_output_string(UI_STRING *uis)
return uis->out_string;
}
const char *UI_get0_action_string(UI_STRING *uis)
{
if (!uis)
return NULL;
switch(uis->type)
{
case UIT_PROMPT:
case UIT_BOOLEAN:
return uis->_.boolean_data.action_desc;
default:
return NULL;
}
}
const char *UI_get0_result_string(UI_STRING *uis)
{
if (!uis)
@ -560,51 +770,119 @@ const char *UI_get0_test_string(UI_STRING *uis)
{
if (!uis)
return NULL;
return uis->test_buf;
switch(uis->type)
{
case UIT_VERIFY:
return uis->_.string_data.test_buf;
default:
return NULL;
}
}
int UI_get_result_minsize(UI_STRING *uis)
{
if (!uis)
return -1;
return uis->result_minsize;
switch(uis->type)
{
case UIT_PROMPT:
case UIT_VERIFY:
return uis->_.string_data.result_minsize;
default:
return -1;
}
}
int UI_get_result_maxsize(UI_STRING *uis)
{
if (!uis)
return -1;
return uis->result_maxsize;
switch(uis->type)
{
case UIT_PROMPT:
case UIT_VERIFY:
return uis->_.string_data.result_maxsize;
default:
return -1;
}
}
int UI_set_result(UI_STRING *uis, const char *result)
int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
{
int l = strlen(result);
ui->flags &= ~UI_FLAG_REDOABLE;
if (!uis)
return -1;
if (l < uis->result_minsize)
switch (uis->type)
{
UIerr(UI_F_UI_SET_RESULT,UI_R_RESULT_TOO_SMALL);
return -1;
}
if (l > uis->result_maxsize)
case UIT_PROMPT:
case UIT_VERIFY:
{
UIerr(UI_F_UI_SET_RESULT,UI_R_RESULT_TOO_LARGE);
return -1;
char number1[20];
char number2[20];
BIO_snprintf(number1, sizeof(number1), "%d",
uis->_.string_data.result_minsize);
BIO_snprintf(number2, sizeof(number2), "%d",
uis->_.string_data.result_maxsize);
if (l < uis->_.string_data.result_minsize)
{
ui->flags |= UI_FLAG_REDOABLE;
UIerr(UI_F_UI_SET_RESULT,UI_R_RESULT_TOO_SMALL);
ERR_add_error_data(5,"You must type in ",
number1," to ",number2," characters");
return -1;
}
if (l > uis->_.string_data.result_maxsize)
{
ui->flags |= UI_FLAG_REDOABLE;
UIerr(UI_F_UI_SET_RESULT,UI_R_RESULT_TOO_LARGE);
ERR_add_error_data(5,"You must type in ",
number1," to ",number2," characters");
return -1;
}
}
if (!uis->result_buf)
{
uis->result_buf = OPENSSL_malloc(uis->result_maxsize+1);
}
if (!uis->result_buf)
{
UIerr(UI_F_UI_SET_RESULT,UI_R_NO_RESULT_BUFFER);
return -1;
}
if (!uis->result_buf)
strcpy(uis->result_buf, result);
break;
case UIT_BOOLEAN:
{
UIerr(UI_F_UI_NEW_METHOD,ERR_R_MALLOC_FAILURE);
return -1;
}
const char *p;
strcpy(uis->result_buf, result);
if (!uis->result_buf)
{
UIerr(UI_F_UI_SET_RESULT,UI_R_NO_RESULT_BUFFER);
return -1;
}
uis->result_buf[0] = '\0';
for(p = result; *p; p++)
{
if (strchr(uis->_.boolean_data.ok_chars, *p))
{
uis->result_buf[0] =
uis->_.boolean_data.ok_chars[0];
break;
}
if (strchr(uis->_.boolean_data.cancel_chars, *p))
{
uis->result_buf[0] =
uis->_.boolean_data.cancel_chars[0];
break;
}
}
default:
break;
}
}
return 0;
}

View file

@ -96,21 +96,36 @@ struct ui_method_st
struct ui_string_st
{
const char *out_string; /* Input */
enum UI_string_types type; /* Input */
const char *out_string; /* Input */
int input_flags; /* Flags from the user */
/* The following parameters are completely irrelevant for UI_INFO,
and can therefore be set to 0 ro NULL */
/* The following parameters are completely irrelevant for UIT_INFO,
and can therefore be set to 0 or NULL */
char *result_buf; /* Input and Output: If not NULL, user-defined
with size in result_maxsize. Otherwise, it
may be allocated by the UI routine, meaning
result_minsize is going to be overwritten.*/
int result_minsize; /* Input: minimum required size of the result*/
int result_maxsize; /* Input: maximum permitted size of the
result */
union
{
struct
{
int result_minsize; /* Input: minimum required
size of the result.
*/
int result_maxsize; /* Input: maximum permitted
size of the result */
const char *test_buf; /* Input: test string to verify against */
const char *test_buf; /* Input: test string to verify
against */
} string_data;
struct
{
const char *action_desc; /* Input */
const char *ok_chars; /* Input */
const char *cancel_chars; /* Input */
} boolean_data;
} _;
#define OUT_STRING_FREEABLE 0x01
int flags; /* flags for internal use */
@ -124,6 +139,10 @@ struct ui_st
with different echoing status. */
void *user_data;
CRYPTO_EX_DATA ex_data;
#define UI_FLAG_REDOABLE 0x0001
#define UI_FLAG_PRINT_ERRORS 0x0100
int flags;
};
#endif