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
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(). */
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);
/* 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)
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 */
};
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. */
/* 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 */
/* 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
#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
}
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);
}
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)
+ {
+ 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);
+ }
+ 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)
{
- UIerr(UI_F_GENERAL_ALLOCATE_STRING,ERR_R_PASSED_NULL_PARAMETER);
+ UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,ERR_R_PASSED_NULL_PARAMETER);
}
- else if (allocate_string_stack(ui) >= 0)
+ else if (cancel_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
+ {
+ 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;
}
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,
}
}
- 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)
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;
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
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)
{
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)
{
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];
- if (!uis->result_buf)
- {
- uis->result_buf = OPENSSL_malloc(uis->result_maxsize+1);
+ 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)
+ if (!uis->result_buf)
+ {
+ UIerr(UI_F_UI_SET_RESULT,UI_R_NO_RESULT_BUFFER);
+ return -1;
+ }
+
+ 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;
}