summaryrefslogtreecommitdiff
path: root/subversion/libsvn_subr/cmdline.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_subr/cmdline.c')
-rw-r--r--subversion/libsvn_subr/cmdline.c435
1 files changed, 356 insertions, 79 deletions
diff --git a/subversion/libsvn_subr/cmdline.c b/subversion/libsvn_subr/cmdline.c
index 89d1ff3..9e97bf7 100644
--- a/subversion/libsvn_subr/cmdline.c
+++ b/subversion/libsvn_subr/cmdline.c
@@ -34,6 +34,7 @@
#else
#include <crtdbg.h>
#include <io.h>
+#include <conio.h>
#endif
#include <apr.h> /* for STDIN_FILENO */
@@ -62,17 +63,32 @@
#include "private/svn_cmdline_private.h"
#include "private/svn_utf_private.h"
+#include "private/svn_sorts_private.h"
#include "private/svn_string_private.h"
#include "svn_private_config.h"
#include "win32_crashrpt.h"
+#if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER < 1400)
+/* Before Visual Studio 2005, the C runtime didn't handle encodings for the
+ for the stdio output handling. */
+#define CMDLINE_USE_CUSTOM_ENCODING
+
/* The stdin encoding. If null, it's the same as the native encoding. */
static const char *input_encoding = NULL;
/* The stdout encoding. If null, it's the same as the native encoding. */
static const char *output_encoding = NULL;
+#elif defined(WIN32) && defined(_MSC_VER)
+/* For now limit this code to Visual C++, as the result is highly dependent
+ on the CRT implementation */
+#define USE_WIN32_CONSOLE_SHORTCUT
+
+/* When TRUE, stdout/stderr is directly connected to a console */
+static svn_boolean_t shortcut_stdout_to_console = FALSE;
+static svn_boolean_t shortcut_stderr_to_console = FALSE;
+#endif
int
@@ -114,7 +130,7 @@ svn_cmdline_init(const char *progname, FILE *error_stream)
#endif
#ifdef WIN32
-#if _MSC_VER < 1400
+#ifdef CMDLINE_USE_CUSTOM_ENCODING
/* Initialize the input and output encodings. */
{
static char input_encoding_buffer[16];
@@ -128,33 +144,35 @@ svn_cmdline_init(const char *progname, FILE *error_stream)
"CP%u", (unsigned) GetConsoleOutputCP());
output_encoding = output_encoding_buffer;
}
-#endif /* _MSC_VER < 1400 */
+#endif /* CMDLINE_USE_CUSTOM_ENCODING */
#ifdef SVN_USE_WIN32_CRASHHANDLER
- /* Attach (but don't load) the crash handler */
- SetUnhandledExceptionFilter(svn__unhandled_exception_filter);
+ if (!getenv("SVN_CMDLINE_DISABLE_CRASH_HANDLER"))
+ {
+ /* Attach (but don't load) the crash handler */
+ SetUnhandledExceptionFilter(svn__unhandled_exception_filter);
#if _MSC_VER >= 1400
- /* ### This should work for VC++ 2002 (=1300) and later */
- /* Show the abort message on STDERR instead of a dialog to allow
- scripts (e.g. our testsuite) to continue after an abort without
- user intervention. Allow overriding for easier debugging. */
- if (!getenv("SVN_CMDLINE_USE_DIALOG_FOR_ABORT"))
- {
- /* In release mode: Redirect abort() errors to stderr */
- _set_error_mode(_OUT_TO_STDERR);
-
- /* In _DEBUG mode: Redirect all debug output (E.g. assert() to stderr.
- (Ignored in release builds) */
- _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);
- _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
- _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR);
- _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
- }
+ /* ### This should work for VC++ 2002 (=1300) and later */
+ /* Show the abort message on STDERR instead of a dialog to allow
+ scripts (e.g. our testsuite) to continue after an abort without
+ user intervention. Allow overriding for easier debugging. */
+ if (!getenv("SVN_CMDLINE_USE_DIALOG_FOR_ABORT"))
+ {
+ /* In release mode: Redirect abort() errors to stderr */
+ _set_error_mode(_OUT_TO_STDERR);
+
+ /* In _DEBUG mode: Redirect all debug output (E.g. assert() to stderr.
+ (Ignored in release builds) */
+ _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
+ _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+ }
#endif /* _MSC_VER >= 1400 */
-
+ }
#endif /* SVN_USE_WIN32_CRASHHANDLER */
#endif /* WIN32 */
@@ -247,6 +265,31 @@ svn_cmdline_init(const char *progname, FILE *error_stream)
return EXIT_FAILURE;
}
+#ifdef USE_WIN32_CONSOLE_SHORTCUT
+ if (_isatty(STDOUT_FILENO))
+ {
+ DWORD ignored;
+ HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
+
+ /* stdout is a char device handle, but is it the console? */
+ if (GetConsoleMode(stdout_handle, &ignored))
+ shortcut_stdout_to_console = TRUE;
+
+ /* Don't close stdout_handle */
+ }
+ if (_isatty(STDERR_FILENO))
+ {
+ DWORD ignored;
+ HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
+
+ /* stderr is a char device handle, but is it the console? */
+ if (GetConsoleMode(stderr_handle, &ignored))
+ shortcut_stderr_to_console = TRUE;
+
+ /* Don't close stderr_handle */
+ }
+#endif
+
return EXIT_SUCCESS;
}
@@ -256,10 +299,12 @@ svn_cmdline_cstring_from_utf8(const char **dest,
const char *src,
apr_pool_t *pool)
{
- if (output_encoding == NULL)
- return svn_utf_cstring_from_utf8(dest, src, pool);
- else
+#ifdef CMDLINE_USE_CUSTOM_ENCODING
+ if (output_encoding != NULL)
return svn_utf_cstring_from_utf8_ex2(dest, src, output_encoding, pool);
+#endif
+
+ return svn_utf_cstring_from_utf8(dest, src, pool);
}
@@ -277,10 +322,12 @@ svn_cmdline_cstring_to_utf8(const char **dest,
const char *src,
apr_pool_t *pool)
{
- if (input_encoding == NULL)
- return svn_utf_cstring_to_utf8(dest, src, pool);
- else
+#ifdef CMDLINE_USE_CUSTOM_ENCODING
+ if (input_encoding != NULL)
return svn_utf_cstring_to_utf8_ex2(dest, src, input_encoding, pool);
+#endif
+
+ return svn_utf_cstring_to_utf8(dest, src, pool);
}
@@ -336,6 +383,45 @@ svn_cmdline_fputs(const char *string, FILE* stream, apr_pool_t *pool)
svn_error_t *err;
const char *out;
+#ifdef USE_WIN32_CONSOLE_SHORTCUT
+ /* For legacy reasons the Visual C++ runtime converts output to the console
+ from the native 'ansi' encoding, to unicode, then back to 'ansi' and then
+ onwards to the console which is implemented as unicode.
+
+ For operations like 'svn status -v' this may cause about 70% of the total
+ processing time, with absolutely no gain.
+
+ For this specific scenario this shortcut exists. It has the nice side
+ effect of allowing full unicode output to the console.
+
+ Note that this shortcut is not used when the output is redirected, as in
+ that case the data is put on the pipe/file after the first conversion to
+ ansi. In this case the most expensive conversion is already avoided.
+ */
+ if ((stream == stdout && shortcut_stdout_to_console)
+ || (stream == stderr && shortcut_stderr_to_console))
+ {
+ WCHAR *result;
+
+ if (string[0] == '\0')
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_cmdline_fflush(stream)); /* Flush existing output */
+
+ SVN_ERR(svn_utf__win32_utf8_to_utf16(&result, string, NULL, pool));
+
+ if (_cputws(result))
+ {
+ if (apr_get_os_error())
+ {
+ return svn_error_wrap_apr(apr_get_os_error(), _("Write error"));
+ }
+ }
+
+ return SVN_NO_ERROR;
+ }
+#endif
+
err = svn_cmdline_cstring_from_utf8(&out, string, pool);
if (err)
@@ -393,10 +479,12 @@ svn_cmdline_fflush(FILE *stream)
const char *svn_cmdline_output_encoding(apr_pool_t *pool)
{
+#ifdef CMDLINE_USE_CUSTOM_ENCODING
if (output_encoding)
return apr_pstrdup(pool, output_encoding);
- else
- return SVN_APR_LOCALE_CHARSET;
+#endif
+
+ return SVN_APR_LOCALE_CHARSET;
}
int
@@ -419,31 +507,51 @@ svn_cmdline_handle_exit_error(svn_error_t *err,
return EXIT_FAILURE;
}
+struct trust_server_cert_non_interactive_baton {
+ svn_boolean_t trust_server_cert_unknown_ca;
+ svn_boolean_t trust_server_cert_cn_mismatch;
+ svn_boolean_t trust_server_cert_expired;
+ svn_boolean_t trust_server_cert_not_yet_valid;
+ svn_boolean_t trust_server_cert_other_failure;
+};
+
/* This implements 'svn_auth_ssl_server_trust_prompt_func_t'.
Don't actually prompt. Instead, set *CRED_P to valid credentials
- iff FAILURES is empty or is exactly SVN_AUTH_SSL_UNKNOWNCA. If
- there are any other failure bits, then set *CRED_P to null (that
- is, reject the cert).
+ iff FAILURES is empty or may be accepted according to the flags
+ in BATON. If there are any other failure bits, then set *CRED_P
+ to null (that is, reject the cert).
Ignore MAY_SAVE; we don't save certs we never prompted for.
- Ignore BATON, REALM, and CERT_INFO,
+ Ignore REALM and CERT_INFO,
Ignore any further films by George Lucas. */
static svn_error_t *
-ssl_trust_unknown_server_cert
- (svn_auth_cred_ssl_server_trust_t **cred_p,
- void *baton,
- const char *realm,
- apr_uint32_t failures,
- const svn_auth_ssl_server_cert_info_t *cert_info,
- svn_boolean_t may_save,
- apr_pool_t *pool)
+trust_server_cert_non_interactive(svn_auth_cred_ssl_server_trust_t **cred_p,
+ void *baton,
+ const char *realm,
+ apr_uint32_t failures,
+ const svn_auth_ssl_server_cert_info_t
+ *cert_info,
+ svn_boolean_t may_save,
+ apr_pool_t *pool)
{
+ struct trust_server_cert_non_interactive_baton *b = baton;
+ apr_uint32_t non_ignored_failures;
*cred_p = NULL;
- if (failures == 0 || failures == SVN_AUTH_SSL_UNKNOWNCA)
+ /* Mask away bits we are instructed to ignore. */
+ non_ignored_failures = failures & ~(
+ (b->trust_server_cert_unknown_ca ? SVN_AUTH_SSL_UNKNOWNCA : 0)
+ | (b->trust_server_cert_cn_mismatch ? SVN_AUTH_SSL_CNMISMATCH : 0)
+ | (b->trust_server_cert_expired ? SVN_AUTH_SSL_EXPIRED : 0)
+ | (b->trust_server_cert_not_yet_valid ? SVN_AUTH_SSL_NOTYETVALID : 0)
+ | (b->trust_server_cert_other_failure ? SVN_AUTH_SSL_OTHER : 0)
+ );
+
+ /* If no failures remain, accept the certificate. */
+ if (non_ignored_failures == 0)
{
*cred_p = apr_pcalloc(pool, sizeof(**cred_p));
(*cred_p)->may_save = FALSE;
@@ -454,17 +562,22 @@ ssl_trust_unknown_server_cert
}
svn_error_t *
-svn_cmdline_create_auth_baton(svn_auth_baton_t **ab,
- svn_boolean_t non_interactive,
- const char *auth_username,
- const char *auth_password,
- const char *config_dir,
- svn_boolean_t no_auth_cache,
- svn_boolean_t trust_server_cert,
- svn_config_t *cfg,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *pool)
+svn_cmdline_create_auth_baton2(svn_auth_baton_t **ab,
+ svn_boolean_t non_interactive,
+ const char *auth_username,
+ const char *auth_password,
+ const char *config_dir,
+ svn_boolean_t no_auth_cache,
+ svn_boolean_t trust_server_cert_unknown_ca,
+ svn_boolean_t trust_server_cert_cn_mismatch,
+ svn_boolean_t trust_server_cert_expired,
+ svn_boolean_t trust_server_cert_not_yet_valid,
+ svn_boolean_t trust_server_cert_other_failure,
+ svn_config_t *cfg,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *pool)
+
{
svn_boolean_t store_password_val = TRUE;
svn_boolean_t store_auth_creds_val = TRUE;
@@ -505,24 +618,6 @@ svn_cmdline_create_auth_baton(svn_auth_baton_t **ab,
svn_auth_get_username_provider(&provider, pool);
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
- /* The windows ssl server certificate CRYPTOAPI provider. */
- SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
- "windows",
- "ssl_server_trust",
- pool));
-
- if (provider)
- APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
-
- /* The windows ssl authority certificate CRYPTOAPI provider. */
- SVN_ERR(svn_auth_get_platform_specific_provider(&provider,
- "windows",
- "ssl_server_authority",
- pool));
-
- if (provider)
- APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
-
svn_auth_get_ssl_server_trust_file_provider(&provider, pool);
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
svn_auth_get_ssl_client_cert_file_provider(&provider, pool);
@@ -583,11 +678,22 @@ svn_cmdline_create_auth_baton(svn_auth_baton_t **ab,
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
}
}
- else if (trust_server_cert)
+ else if (trust_server_cert_unknown_ca || trust_server_cert_cn_mismatch ||
+ trust_server_cert_expired || trust_server_cert_not_yet_valid ||
+ trust_server_cert_other_failure)
{
+ struct trust_server_cert_non_interactive_baton *b;
+
+ b = apr_palloc(pool, sizeof(*b));
+ b->trust_server_cert_unknown_ca = trust_server_cert_unknown_ca;
+ b->trust_server_cert_cn_mismatch = trust_server_cert_cn_mismatch;
+ b->trust_server_cert_expired = trust_server_cert_expired;
+ b->trust_server_cert_not_yet_valid = trust_server_cert_not_yet_valid;
+ b->trust_server_cert_other_failure = trust_server_cert_other_failure;
+
/* Remember, only register this provider if non_interactive. */
svn_auth_get_ssl_server_trust_prompt_provider
- (&provider, ssl_trust_unknown_server_cert, NULL, pool);
+ (&provider, trust_server_cert_non_interactive, b, pool);
APR_ARRAY_PUSH(providers, svn_auth_provider_object_t *) = provider;
}
@@ -689,12 +795,12 @@ svn_cmdline__print_xml_prop(svn_stringbuf_t **outstr,
outstr, pool, svn_xml_protect_pcdata,
inherited_prop ? "inherited_property" : "property",
"name", propname,
- "encoding", encoding, NULL);
+ "encoding", encoding, SVN_VA_NULL);
else
svn_xml_make_open_tag(
outstr, pool, svn_xml_protect_pcdata,
inherited_prop ? "inherited_property" : "property",
- "name", propname, NULL);
+ "name", propname, SVN_VA_NULL);
svn_stringbuf_appendcstr(*outstr, xml_safe);
@@ -705,9 +811,124 @@ svn_cmdline__print_xml_prop(svn_stringbuf_t **outstr,
return;
}
+/* Return the most similar string to NEEDLE in HAYSTACK, which contains
+ * HAYSTACK_LEN elements. Return NULL if no string is sufficiently similar.
+ */
+/* See svn_cl__similarity_check() for a more general solution. */
+static const char *
+most_similar(const char *needle_cstr,
+ const char **haystack,
+ apr_size_t haystack_len,
+ apr_pool_t *scratch_pool)
+{
+ const char *max_similar;
+ apr_size_t max_score = 0;
+ apr_size_t i;
+ svn_membuf_t membuf;
+ svn_string_t *needle_str = svn_string_create(needle_cstr, scratch_pool);
+
+ svn_membuf__create(&membuf, 64, scratch_pool);
+
+ for (i = 0; i < haystack_len; i++)
+ {
+ apr_size_t score;
+ svn_string_t *hay = svn_string_create(haystack[i], scratch_pool);
+
+ score = svn_string__similarity(needle_str, hay, &membuf, NULL);
+
+ /* If you update this factor, consider updating
+ * svn_cl__similarity_check(). */
+ if (score >= (2 * SVN_STRING__SIM_RANGE_MAX + 1) / 3
+ && score > max_score)
+ {
+ max_score = score;
+ max_similar = haystack[i];
+ }
+ }
+
+ if (max_score)
+ return max_similar;
+ else
+ return NULL;
+}
+
+/* Verify that NEEDLE is in HAYSTACK, which contains HAYSTACK_LEN elements. */
+static svn_error_t *
+string_in_array(const char *needle,
+ const char **haystack,
+ apr_size_t haystack_len,
+ apr_pool_t *scratch_pool)
+{
+ const char *next_of_kin;
+ apr_size_t i;
+ for (i = 0; i < haystack_len; i++)
+ {
+ if (!strcmp(needle, haystack[i]))
+ return SVN_NO_ERROR;
+ }
+
+ /* Error. */
+ next_of_kin = most_similar(needle, haystack, haystack_len, scratch_pool);
+ if (next_of_kin)
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Ignoring unknown value '%s'; "
+ "did you mean '%s'?"),
+ needle, next_of_kin);
+ else
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Ignoring unknown value '%s'"),
+ needle);
+}
+
+#include "config_keys.inc"
+
+/* Validate the FILE, SECTION, and OPTION components of CONFIG_OPTION are
+ * known. Warn to stderr if not. (An unknown value may be either a typo
+ * or added in a newer minor version of Subversion.) */
+static svn_error_t *
+validate_config_option(svn_cmdline__config_argument_t *config_option,
+ apr_pool_t *scratch_pool)
+{
+ svn_boolean_t arbitrary_keys = FALSE;
+
+ /* TODO: some day, we could also verify that OPTION is valid for SECTION;
+ i.e., forbid invalid combinations such as config:auth:diff-extensions. */
+
+#define ARRAYLEN(x) ( sizeof((x)) / sizeof((x)[0]) )
+
+ SVN_ERR(string_in_array(config_option->file, svn__valid_config_files,
+ ARRAYLEN(svn__valid_config_files),
+ scratch_pool));
+ SVN_ERR(string_in_array(config_option->section, svn__valid_config_sections,
+ ARRAYLEN(svn__valid_config_sections),
+ scratch_pool));
+
+ /* Don't validate option names for sections such as servers[group],
+ * config[tunnels], and config[auto-props] that permit arbitrary options. */
+ {
+ int i;
+
+ for (i = 0; i < ARRAYLEN(svn__empty_config_sections); i++)
+ {
+ if (!strcmp(config_option->section, svn__empty_config_sections[i]))
+ arbitrary_keys = TRUE;
+ }
+ }
+
+ if (! arbitrary_keys)
+ SVN_ERR(string_in_array(config_option->option, svn__valid_config_options,
+ ARRAYLEN(svn__valid_config_options),
+ scratch_pool));
+
+#undef ARRAYLEN
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_cmdline__parse_config_option(apr_array_header_t *config_options,
const char *opt_arg,
+ const char *prefix,
apr_pool_t *pool)
{
svn_cmdline__config_argument_t *config_option;
@@ -721,6 +942,8 @@ svn_cmdline__parse_config_option(apr_array_header_t *config_options,
if ((equals_sign = strchr(second_colon + 1, '=')) &&
(equals_sign != second_colon + 1))
{
+ svn_error_t *warning;
+
config_option = apr_pcalloc(pool, sizeof(*config_option));
config_option->file = apr_pstrndup(pool, opt_arg,
first_colon - opt_arg);
@@ -729,6 +952,13 @@ svn_cmdline__parse_config_option(apr_array_header_t *config_options,
config_option->option = apr_pstrndup(pool, second_colon + 1,
equals_sign - second_colon - 1);
+ warning = validate_config_option(config_option, pool);
+ if (warning)
+ {
+ svn_handle_warning2(stderr, warning, prefix);
+ svn_error_clear(warning);
+ }
+
if (! (strchr(config_option->option, ':')))
{
config_option->value = apr_pstrndup(pool, equals_sign + 1,
@@ -920,7 +1150,7 @@ svn_cmdline__print_xml_prop_hash(svn_stringbuf_t **outstr,
svn_xml_make_open_tag(
outstr, pool, svn_xml_self_closing,
inherited_props ? "inherited_property" : "property",
- "name", pname, NULL);
+ "name", pname, SVN_VA_NULL);
}
else
{
@@ -1275,7 +1505,7 @@ svn_cmdline__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
/* Translate back to UTF8/LF if desired. */
if (as_text)
{
- err = svn_subst_translate_string2(edited_contents, FALSE, FALSE,
+ err = svn_subst_translate_string2(edited_contents, NULL, NULL,
*edited_contents, encoding, FALSE,
pool, pool);
if (err)
@@ -1319,3 +1549,50 @@ svn_cmdline__edit_string_externally(svn_string_t **edited_contents /* UTF-8! */,
return svn_error_trace(err);
}
+
+svn_error_t *
+svn_cmdline__parse_trust_options(
+ svn_boolean_t *trust_server_cert_unknown_ca,
+ svn_boolean_t *trust_server_cert_cn_mismatch,
+ svn_boolean_t *trust_server_cert_expired,
+ svn_boolean_t *trust_server_cert_not_yet_valid,
+ svn_boolean_t *trust_server_cert_other_failure,
+ const char *opt_arg,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *failures;
+ int i;
+
+ *trust_server_cert_unknown_ca = FALSE;
+ *trust_server_cert_cn_mismatch = FALSE;
+ *trust_server_cert_expired = FALSE;
+ *trust_server_cert_not_yet_valid = FALSE;
+ *trust_server_cert_other_failure = FALSE;
+
+ failures = svn_cstring_split(opt_arg, ", \n\r\t\v", TRUE, scratch_pool);
+
+ for (i = 0; i < failures->nelts; i++)
+ {
+ const char *value = APR_ARRAY_IDX(failures, i, const char *);
+ if (!strcmp(value, "unknown-ca"))
+ *trust_server_cert_unknown_ca = TRUE;
+ else if (!strcmp(value, "cn-mismatch"))
+ *trust_server_cert_cn_mismatch = TRUE;
+ else if (!strcmp(value, "expired"))
+ *trust_server_cert_expired = TRUE;
+ else if (!strcmp(value, "not-yet-valid"))
+ *trust_server_cert_not_yet_valid = TRUE;
+ else if (!strcmp(value, "other"))
+ *trust_server_cert_other_failure = TRUE;
+ else
+ return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("Unknown value '%s' for %s.\n"
+ "Supported values: %s"),
+ value,
+ "--trust-server-cert-failures",
+ "unknown-ca, cn-mismatch, expired, "
+ "not-yet-valid, other");
+ }
+
+ return SVN_NO_ERROR;
+}