1/* crypto/ui/ui_lib.c -*- mode:C; c-file-style: "eay" -*- */
2/* Written by Richard Levitte (richard@levitte.org) for the OpenSSL
3 * project 2001.
4 */
5/* ====================================================================
6 * Copyright (c) 2001 The OpenSSL Project.  All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in
17 *    the documentation and/or other materials provided with the
18 *    distribution.
19 *
20 * 3. All advertising materials mentioning features or use of this
21 *    software must display the following acknowledgment:
22 *    "This product includes software developed by the OpenSSL Project
23 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
24 *
25 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26 *    endorse or promote products derived from this software without
27 *    prior written permission. For written permission, please contact
28 *    openssl-core@openssl.org.
29 *
30 * 5. Products derived from this software may not be called "OpenSSL"
31 *    nor may "OpenSSL" appear in their names without prior written
32 *    permission of the OpenSSL Project.
33 *
34 * 6. Redistributions of any form whatsoever must retain the following
35 *    acknowledgment:
36 *    "This product includes software developed by the OpenSSL Project
37 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
38 *
39 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50 * OF THE POSSIBILITY OF SUCH DAMAGE.
51 * ====================================================================
52 *
53 * This product includes cryptographic software written by Eric Young
54 * (eay@cryptsoft.com).  This product includes software written by Tim
55 * Hudson (tjh@cryptsoft.com).
56 *
57 */
58
59#include <string.h>
60#include "cryptlib.h"
61#include <openssl/e_os2.h>
62#include <openssl/buffer.h>
63#include <openssl/ui.h>
64#include <openssl/err.h>
65#include "ui_locl.h"
66
67IMPLEMENT_STACK_OF(UI_STRING_ST)
68
69static const UI_METHOD *default_UI_meth=NULL;
70
71UI *UI_new(void)
72	{
73	return(UI_new_method(NULL));
74	}
75
76UI *UI_new_method(const UI_METHOD *method)
77	{
78	UI *ret;
79
80	ret=(UI *)OPENSSL_malloc(sizeof(UI));
81	if (ret == NULL)
82		{
83		UIerr(UI_F_UI_NEW_METHOD,ERR_R_MALLOC_FAILURE);
84		return NULL;
85		}
86	if (method == NULL)
87		ret->meth=UI_get_default_method();
88	else
89		ret->meth=method;
90
91	ret->strings=NULL;
92	ret->user_data=NULL;
93	CRYPTO_new_ex_data(CRYPTO_EX_INDEX_UI, ret, &ret->ex_data);
94	return ret;
95	}
96
97static void free_string(UI_STRING *uis)
98	{
99	if (uis->flags & OUT_STRING_FREEABLE)
100		{
101		OPENSSL_free((char *)uis->out_string);
102		switch(uis->type)
103			{
104		case UIT_BOOLEAN:
105			OPENSSL_free((char *)uis->_.boolean_data.action_desc);
106			OPENSSL_free((char *)uis->_.boolean_data.ok_chars);
107			OPENSSL_free((char *)uis->_.boolean_data.cancel_chars);
108			break;
109		default:
110			break;
111			}
112		}
113	OPENSSL_free(uis);
114	}
115
116void UI_free(UI *ui)
117	{
118	if (ui == NULL)
119		return;
120	sk_UI_STRING_pop_free(ui->strings,free_string);
121	CRYPTO_free_ex_data(CRYPTO_EX_INDEX_UI, ui, &ui->ex_data);
122	OPENSSL_free(ui);
123	}
124
125static int allocate_string_stack(UI *ui)
126	{
127	if (ui->strings == NULL)
128		{
129		ui->strings=sk_UI_STRING_new_null();
130		if (ui->strings == NULL)
131			{
132			return -1;
133			}
134		}
135	return 0;
136	}
137
138static UI_STRING *general_allocate_prompt(UI *ui, const char *prompt,
139	int prompt_freeable, enum UI_string_types type, int input_flags,
140	char *result_buf)
141	{
142	UI_STRING *ret = NULL;
143
144	if (prompt == NULL)
145		{
146		UIerr(UI_F_GENERAL_ALLOCATE_PROMPT,ERR_R_PASSED_NULL_PARAMETER);
147		}
148	else if ((type == UIT_PROMPT || type == UIT_VERIFY
149			 || type == UIT_BOOLEAN) && result_buf == NULL)
150		{
151		UIerr(UI_F_GENERAL_ALLOCATE_PROMPT,UI_R_NO_RESULT_BUFFER);
152		}
153	else if ((ret = (UI_STRING *)OPENSSL_malloc(sizeof(UI_STRING))))
154		{
155		ret->out_string=prompt;
156		ret->flags=prompt_freeable ? OUT_STRING_FREEABLE : 0;
157		ret->input_flags=input_flags;
158		ret->type=type;
159		ret->result_buf=result_buf;
160		}
161	return ret;
162	}
163
164static int general_allocate_string(UI *ui, const char *prompt,
165	int prompt_freeable, enum UI_string_types type, int input_flags,
166	char *result_buf, int minsize, int maxsize, const char *test_buf)
167	{
168	int ret = -1;
169	UI_STRING *s = general_allocate_prompt(ui, prompt, prompt_freeable,
170		type, input_flags, result_buf);
171
172	if (s)
173		{
174		if (allocate_string_stack(ui) >= 0)
175			{
176			s->_.string_data.result_minsize=minsize;
177			s->_.string_data.result_maxsize=maxsize;
178			s->_.string_data.test_buf=test_buf;
179			ret=sk_UI_STRING_push(ui->strings, s);
180			/* sk_push() returns 0 on error.  Let's addapt that */
181			if (ret <= 0) ret--;
182			}
183		else
184			free_string(s);
185		}
186	return ret;
187	}
188
189static int general_allocate_boolean(UI *ui,
190	const char *prompt, const char *action_desc,
191	const char *ok_chars, const char *cancel_chars,
192	int prompt_freeable, enum UI_string_types type, int input_flags,
193	char *result_buf)
194	{
195	int ret = -1;
196	UI_STRING *s;
197	const char *p;
198
199	if (ok_chars == NULL)
200		{
201		UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,ERR_R_PASSED_NULL_PARAMETER);
202		}
203	else if (cancel_chars == NULL)
204		{
205		UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,ERR_R_PASSED_NULL_PARAMETER);
206		}
207	else
208		{
209		for(p = ok_chars; *p; p++)
210			{
211			if (strchr(cancel_chars, *p))
212				{
213				UIerr(UI_F_GENERAL_ALLOCATE_BOOLEAN,
214					UI_R_COMMON_OK_AND_CANCEL_CHARACTERS);
215				}
216			}
217
218		s = general_allocate_prompt(ui, prompt, prompt_freeable,
219			type, input_flags, result_buf);
220
221		if (s)
222			{
223			if (allocate_string_stack(ui) >= 0)
224				{
225				s->_.boolean_data.action_desc = action_desc;
226				s->_.boolean_data.ok_chars = ok_chars;
227				s->_.boolean_data.cancel_chars = cancel_chars;
228				ret=sk_UI_STRING_push(ui->strings, s);
229				/* sk_push() returns 0 on error.
230				   Let's addapt that */
231				if (ret <= 0) ret--;
232				}
233			else
234				free_string(s);
235			}
236		}
237	return ret;
238	}
239
240/* Returns the index to the place in the stack or -1 for error.  Uses a
241   direct reference to the prompt.  */
242int UI_add_input_string(UI *ui, const char *prompt, int flags,
243	char *result_buf, int minsize, int maxsize)
244	{
245	return general_allocate_string(ui, prompt, 0,
246		UIT_PROMPT, flags, result_buf, minsize, maxsize, NULL);
247	}
248
249/* Same as UI_add_input_string(), excepts it takes a copy of the prompt */
250int UI_dup_input_string(UI *ui, const char *prompt, int flags,
251	char *result_buf, int minsize, int maxsize)
252	{
253	char *prompt_copy=NULL;
254
255	if (prompt)
256		{
257		prompt_copy=BUF_strdup(prompt);
258		if (prompt_copy == NULL)
259			{
260			UIerr(UI_F_UI_DUP_INPUT_STRING,ERR_R_MALLOC_FAILURE);
261			return 0;
262			}
263		}
264
265	return general_allocate_string(ui, prompt_copy, 1,
266		UIT_PROMPT, flags, result_buf, minsize, maxsize, NULL);
267	}
268
269int UI_add_verify_string(UI *ui, const char *prompt, int flags,
270	char *result_buf, int minsize, int maxsize, const char *test_buf)
271	{
272	return general_allocate_string(ui, prompt, 0,
273		UIT_VERIFY, flags, result_buf, minsize, maxsize, test_buf);
274	}
275
276int UI_dup_verify_string(UI *ui, const char *prompt, int flags,
277	char *result_buf, int minsize, int maxsize, const char *test_buf)
278	{
279	char *prompt_copy=NULL;
280
281	if (prompt)
282		{
283		prompt_copy=BUF_strdup(prompt);
284		if (prompt_copy == NULL)
285			{
286			UIerr(UI_F_UI_DUP_VERIFY_STRING,ERR_R_MALLOC_FAILURE);
287			return -1;
288			}
289		}
290
291	return general_allocate_string(ui, prompt_copy, 1,
292		UIT_VERIFY, flags, result_buf, minsize, maxsize, test_buf);
293	}
294
295int UI_add_input_boolean(UI *ui, const char *prompt, const char *action_desc,
296	const char *ok_chars, const char *cancel_chars,
297	int flags, char *result_buf)
298	{
299	return general_allocate_boolean(ui, prompt, action_desc,
300		ok_chars, cancel_chars, 0, UIT_BOOLEAN, flags, result_buf);
301	}
302
303int UI_dup_input_boolean(UI *ui, const char *prompt, const char *action_desc,
304	const char *ok_chars, const char *cancel_chars,
305	int flags, char *result_buf)
306	{
307	char *prompt_copy = NULL;
308	char *action_desc_copy = NULL;
309	char *ok_chars_copy = NULL;
310	char *cancel_chars_copy = NULL;
311
312	if (prompt)
313		{
314		prompt_copy=BUF_strdup(prompt);
315		if (prompt_copy == NULL)
316			{
317			UIerr(UI_F_UI_DUP_INPUT_BOOLEAN,ERR_R_MALLOC_FAILURE);
318			goto err;
319			}
320		}
321
322	if (action_desc)
323		{
324		action_desc_copy=BUF_strdup(action_desc);
325		if (action_desc_copy == NULL)
326			{
327			UIerr(UI_F_UI_DUP_INPUT_BOOLEAN,ERR_R_MALLOC_FAILURE);
328			goto err;
329			}
330		}
331
332	if (ok_chars)
333		{
334		ok_chars_copy=BUF_strdup(ok_chars);
335		if (ok_chars_copy == NULL)
336			{
337			UIerr(UI_F_UI_DUP_INPUT_BOOLEAN,ERR_R_MALLOC_FAILURE);
338			goto err;
339			}
340		}
341
342	if (cancel_chars)
343		{
344		cancel_chars_copy=BUF_strdup(cancel_chars);
345		if (cancel_chars_copy == NULL)
346			{
347			UIerr(UI_F_UI_DUP_INPUT_BOOLEAN,ERR_R_MALLOC_FAILURE);
348			goto err;
349			}
350		}
351
352	return general_allocate_boolean(ui, prompt_copy, action_desc_copy,
353		ok_chars_copy, cancel_chars_copy, 1, UIT_BOOLEAN, flags,
354		result_buf);
355 err:
356	if (prompt_copy) OPENSSL_free(prompt_copy);
357	if (action_desc_copy) OPENSSL_free(action_desc_copy);
358	if (ok_chars_copy) OPENSSL_free(ok_chars_copy);
359	if (cancel_chars_copy) OPENSSL_free(cancel_chars_copy);
360	return -1;
361	}
362
363int UI_add_info_string(UI *ui, const char *text)
364	{
365	return general_allocate_string(ui, text, 0, UIT_INFO, 0, NULL, 0, 0,
366		NULL);
367	}
368
369int UI_dup_info_string(UI *ui, const char *text)
370	{
371	char *text_copy=NULL;
372
373	if (text)
374		{
375		text_copy=BUF_strdup(text);
376		if (text_copy == NULL)
377			{
378			UIerr(UI_F_UI_DUP_INFO_STRING,ERR_R_MALLOC_FAILURE);
379			return -1;
380			}
381		}
382
383	return general_allocate_string(ui, text_copy, 1, UIT_INFO, 0, NULL,
384		0, 0, NULL);
385	}
386
387int UI_add_error_string(UI *ui, const char *text)
388	{
389	return general_allocate_string(ui, text, 0, UIT_ERROR, 0, NULL, 0, 0,
390		NULL);
391	}
392
393int UI_dup_error_string(UI *ui, const char *text)
394	{
395	char *text_copy=NULL;
396
397	if (text)
398		{
399		text_copy=BUF_strdup(text);
400		if (text_copy == NULL)
401			{
402			UIerr(UI_F_UI_DUP_ERROR_STRING,ERR_R_MALLOC_FAILURE);
403			return -1;
404			}
405		}
406	return general_allocate_string(ui, text_copy, 1, UIT_ERROR, 0, NULL,
407		0, 0, NULL);
408	}
409
410char *UI_construct_prompt(UI *ui, const char *object_desc,
411	const char *object_name)
412	{
413	char *prompt = NULL;
414
415	if (ui->meth->ui_construct_prompt)
416		prompt = ui->meth->ui_construct_prompt(ui,
417			object_desc, object_name);
418	else
419		{
420		char prompt1[] = "Enter ";
421		char prompt2[] = " for ";
422		char prompt3[] = ":";
423		int len = 0;
424
425		if (object_desc == NULL)
426			return NULL;
427		len = sizeof(prompt1) - 1 + strlen(object_desc);
428		if (object_name)
429			len += sizeof(prompt2) - 1 + strlen(object_name);
430		len += sizeof(prompt3) - 1;
431
432		prompt = (char *)OPENSSL_malloc(len + 1);
433		BUF_strlcpy(prompt, prompt1, len + 1);
434		BUF_strlcat(prompt, object_desc, len + 1);
435		if (object_name)
436			{
437			BUF_strlcat(prompt, prompt2, len + 1);
438			BUF_strlcat(prompt, object_name, len + 1);
439			}
440		BUF_strlcat(prompt, prompt3, len + 1);
441		}
442	return prompt;
443	}
444
445void *UI_add_user_data(UI *ui, void *user_data)
446	{
447	void *old_data = ui->user_data;
448	ui->user_data = user_data;
449	return old_data;
450	}
451
452void *UI_get0_user_data(UI *ui)
453	{
454	return ui->user_data;
455	}
456
457const char *UI_get0_result(UI *ui, int i)
458	{
459	if (i < 0)
460		{
461		UIerr(UI_F_UI_GET0_RESULT,UI_R_INDEX_TOO_SMALL);
462		return NULL;
463		}
464	if (i >= sk_UI_STRING_num(ui->strings))
465		{
466		UIerr(UI_F_UI_GET0_RESULT,UI_R_INDEX_TOO_LARGE);
467		return NULL;
468		}
469	return UI_get0_result_string(sk_UI_STRING_value(ui->strings, i));
470	}
471
472static int print_error(const char *str, size_t len, UI *ui)
473	{
474	UI_STRING uis;
475
476	memset(&uis, 0, sizeof(uis));
477	uis.type = UIT_ERROR;
478	uis.out_string = str;
479
480	if (ui->meth->ui_write_string
481		&& !ui->meth->ui_write_string(ui, &uis))
482		return -1;
483	return 0;
484	}
485
486int UI_process(UI *ui)
487	{
488	int i, ok=0;
489
490	if (ui->meth->ui_open_session && !ui->meth->ui_open_session(ui))
491		return -1;
492
493	if (ui->flags & UI_FLAG_PRINT_ERRORS)
494		ERR_print_errors_cb(
495			(int (*)(const char *, size_t, void *))print_error,
496			(void *)ui);
497
498	for(i=0; i<sk_UI_STRING_num(ui->strings); i++)
499		{
500		if (ui->meth->ui_write_string
501			&& !ui->meth->ui_write_string(ui,
502				sk_UI_STRING_value(ui->strings, i)))
503			{
504			ok=-1;
505			goto err;
506			}
507		}
508
509	if (ui->meth->ui_flush)
510		switch(ui->meth->ui_flush(ui))
511			{
512		case -1: /* Interrupt/Cancel/something... */
513			ok = -2;
514			goto err;
515		case 0: /* Errors */
516			ok = -1;
517			goto err;
518		default: /* Success */
519			ok = 0;
520			break;
521			}
522
523	for(i=0; i<sk_UI_STRING_num(ui->strings); i++)
524		{
525		if (ui->meth->ui_read_string)
526			{
527			switch(ui->meth->ui_read_string(ui,
528				sk_UI_STRING_value(ui->strings, i)))
529				{
530			case -1: /* Interrupt/Cancel/something... */
531				ok = -2;
532				goto err;
533			case 0: /* Errors */
534				ok = -1;
535				goto err;
536			default: /* Success */
537				ok = 0;
538				break;
539				}
540			}
541		}
542 err:
543	if (ui->meth->ui_close_session && !ui->meth->ui_close_session(ui))
544		return -1;
545	return ok;
546	}
547
548int UI_ctrl(UI *ui, int cmd, long i, void *p, void (*f)(void))
549	{
550	if (ui == NULL)
551		{
552		UIerr(UI_F_UI_CTRL,ERR_R_PASSED_NULL_PARAMETER);
553		return -1;
554		}
555	switch(cmd)
556		{
557	case UI_CTRL_PRINT_ERRORS:
558		{
559		int save_flag = !!(ui->flags & UI_FLAG_PRINT_ERRORS);
560		if (i)
561			ui->flags |= UI_FLAG_PRINT_ERRORS;
562		else
563			ui->flags &= ~UI_FLAG_PRINT_ERRORS;
564		return save_flag;
565		}
566	case UI_CTRL_IS_REDOABLE:
567		return !!(ui->flags & UI_FLAG_REDOABLE);
568	default:
569		break;
570		}
571	UIerr(UI_F_UI_CTRL,UI_R_UNKNOWN_CONTROL_COMMAND);
572	return -1;
573	}
574
575int UI_get_ex_new_index(long argl, void *argp, CRYPTO_EX_new *new_func,
576	     CRYPTO_EX_dup *dup_func, CRYPTO_EX_free *free_func)
577        {
578	return CRYPTO_get_ex_new_index(CRYPTO_EX_INDEX_UI, argl, argp,
579				new_func, dup_func, free_func);
580        }
581
582int UI_set_ex_data(UI *r, int idx, void *arg)
583	{
584	return(CRYPTO_set_ex_data(&r->ex_data,idx,arg));
585	}
586
587void *UI_get_ex_data(UI *r, int idx)
588	{
589	return(CRYPTO_get_ex_data(&r->ex_data,idx));
590	}
591
592void UI_set_default_method(const UI_METHOD *meth)
593	{
594	default_UI_meth=meth;
595	}
596
597const UI_METHOD *UI_get_default_method(void)
598	{
599	if (default_UI_meth == NULL)
600		{
601		default_UI_meth=UI_OpenSSL();
602		}
603	return default_UI_meth;
604	}
605
606const UI_METHOD *UI_get_method(UI *ui)
607	{
608	return ui->meth;
609	}
610
611const UI_METHOD *UI_set_method(UI *ui, const UI_METHOD *meth)
612	{
613	ui->meth=meth;
614	return ui->meth;
615	}
616
617
618UI_METHOD *UI_create_method(char *name)
619	{
620	UI_METHOD *ui_method = (UI_METHOD *)OPENSSL_malloc(sizeof(UI_METHOD));
621
622	if (ui_method)
623		{
624		memset(ui_method, 0, sizeof(*ui_method));
625		ui_method->name = BUF_strdup(name);
626		}
627	return ui_method;
628	}
629
630/* BIG FSCKING WARNING!!!!  If you use this on a statically allocated method
631   (that is, it hasn't been allocated using UI_create_method(), you deserve
632   anything Murphy can throw at you and more!  You have been warned. */
633void UI_destroy_method(UI_METHOD *ui_method)
634	{
635	OPENSSL_free(ui_method->name);
636	ui_method->name = NULL;
637	OPENSSL_free(ui_method);
638	}
639
640int UI_method_set_opener(UI_METHOD *method, int (*opener)(UI *ui))
641	{
642	if (method)
643		{
644		method->ui_open_session = opener;
645		return 0;
646		}
647	else
648		return -1;
649	}
650
651int UI_method_set_writer(UI_METHOD *method, int (*writer)(UI *ui, UI_STRING *uis))
652	{
653	if (method)
654		{
655		method->ui_write_string = writer;
656		return 0;
657		}
658	else
659		return -1;
660	}
661
662int UI_method_set_flusher(UI_METHOD *method, int (*flusher)(UI *ui))
663	{
664	if (method)
665		{
666		method->ui_flush = flusher;
667		return 0;
668		}
669	else
670		return -1;
671	}
672
673int UI_method_set_reader(UI_METHOD *method, int (*reader)(UI *ui, UI_STRING *uis))
674	{
675	if (method)
676		{
677		method->ui_read_string = reader;
678		return 0;
679		}
680	else
681		return -1;
682	}
683
684int UI_method_set_closer(UI_METHOD *method, int (*closer)(UI *ui))
685	{
686	if (method)
687		{
688		method->ui_close_session = closer;
689		return 0;
690		}
691	else
692		return -1;
693	}
694
695int (*UI_method_get_opener(UI_METHOD *method))(UI*)
696	{
697	if (method)
698		return method->ui_open_session;
699	else
700		return NULL;
701	}
702
703int (*UI_method_get_writer(UI_METHOD *method))(UI*,UI_STRING*)
704	{
705	if (method)
706		return method->ui_write_string;
707	else
708		return NULL;
709	}
710
711int (*UI_method_get_flusher(UI_METHOD *method))(UI*)
712	{
713	if (method)
714		return method->ui_flush;
715	else
716		return NULL;
717	}
718
719int (*UI_method_get_reader(UI_METHOD *method))(UI*,UI_STRING*)
720	{
721	if (method)
722		return method->ui_read_string;
723	else
724		return NULL;
725	}
726
727int (*UI_method_get_closer(UI_METHOD *method))(UI*)
728	{
729	if (method)
730		return method->ui_close_session;
731	else
732		return NULL;
733	}
734
735enum UI_string_types UI_get_string_type(UI_STRING *uis)
736	{
737	if (!uis)
738		return UIT_NONE;
739	return uis->type;
740	}
741
742int UI_get_input_flags(UI_STRING *uis)
743	{
744	if (!uis)
745		return 0;
746	return uis->input_flags;
747	}
748
749const char *UI_get0_output_string(UI_STRING *uis)
750	{
751	if (!uis)
752		return NULL;
753	return uis->out_string;
754	}
755
756const char *UI_get0_action_string(UI_STRING *uis)
757	{
758	if (!uis)
759		return NULL;
760	switch(uis->type)
761		{
762	case UIT_PROMPT:
763	case UIT_BOOLEAN:
764		return uis->_.boolean_data.action_desc;
765	default:
766		return NULL;
767		}
768	}
769
770const char *UI_get0_result_string(UI_STRING *uis)
771	{
772	if (!uis)
773		return NULL;
774	switch(uis->type)
775		{
776	case UIT_PROMPT:
777	case UIT_VERIFY:
778		return uis->result_buf;
779	default:
780		return NULL;
781		}
782	}
783
784const char *UI_get0_test_string(UI_STRING *uis)
785	{
786	if (!uis)
787		return NULL;
788	switch(uis->type)
789		{
790	case UIT_VERIFY:
791		return uis->_.string_data.test_buf;
792	default:
793		return NULL;
794		}
795	}
796
797int UI_get_result_minsize(UI_STRING *uis)
798	{
799	if (!uis)
800		return -1;
801	switch(uis->type)
802		{
803	case UIT_PROMPT:
804	case UIT_VERIFY:
805		return uis->_.string_data.result_minsize;
806	default:
807		return -1;
808		}
809	}
810
811int UI_get_result_maxsize(UI_STRING *uis)
812	{
813	if (!uis)
814		return -1;
815	switch(uis->type)
816		{
817	case UIT_PROMPT:
818	case UIT_VERIFY:
819		return uis->_.string_data.result_maxsize;
820	default:
821		return -1;
822		}
823	}
824
825int UI_set_result(UI *ui, UI_STRING *uis, const char *result)
826	{
827	int l = strlen(result);
828
829	ui->flags &= ~UI_FLAG_REDOABLE;
830
831	if (!uis)
832		return -1;
833	switch (uis->type)
834		{
835	case UIT_PROMPT:
836	case UIT_VERIFY:
837		{
838		char number1[DECIMAL_SIZE(uis->_.string_data.result_minsize)+1];
839		char number2[DECIMAL_SIZE(uis->_.string_data.result_maxsize)+1];
840
841		BIO_snprintf(number1, sizeof(number1), "%d",
842			uis->_.string_data.result_minsize);
843		BIO_snprintf(number2, sizeof(number2), "%d",
844			uis->_.string_data.result_maxsize);
845
846		if (l < uis->_.string_data.result_minsize)
847			{
848			ui->flags |= UI_FLAG_REDOABLE;
849			UIerr(UI_F_UI_SET_RESULT,UI_R_RESULT_TOO_SMALL);
850			ERR_add_error_data(5,"You must type in ",
851				number1," to ",number2," characters");
852			return -1;
853			}
854		if (l > uis->_.string_data.result_maxsize)
855			{
856			ui->flags |= UI_FLAG_REDOABLE;
857			UIerr(UI_F_UI_SET_RESULT,UI_R_RESULT_TOO_LARGE);
858			ERR_add_error_data(5,"You must type in ",
859				number1," to ",number2," characters");
860			return -1;
861			}
862		}
863
864		if (!uis->result_buf)
865			{
866			UIerr(UI_F_UI_SET_RESULT,UI_R_NO_RESULT_BUFFER);
867			return -1;
868			}
869
870		BUF_strlcpy(uis->result_buf, result,
871			    uis->_.string_data.result_maxsize + 1);
872		break;
873	case UIT_BOOLEAN:
874		{
875		const char *p;
876
877		if (!uis->result_buf)
878			{
879			UIerr(UI_F_UI_SET_RESULT,UI_R_NO_RESULT_BUFFER);
880			return -1;
881			}
882
883		uis->result_buf[0] = '\0';
884		for(p = result; *p; p++)
885			{
886			if (strchr(uis->_.boolean_data.ok_chars, *p))
887				{
888				uis->result_buf[0] =
889					uis->_.boolean_data.ok_chars[0];
890				break;
891				}
892			if (strchr(uis->_.boolean_data.cancel_chars, *p))
893				{
894				uis->result_buf[0] =
895					uis->_.boolean_data.cancel_chars[0];
896				break;
897				}
898			}
899	default:
900		break;
901		}
902		}
903	return 0;
904	}
905