[asterisk-commits] gtjoseph: branch 12 r427275 - in /branches/12: include/asterisk/ main/ pbx/ t...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Nov 4 18:11:51 CST 2014


Author: gtjoseph
Date: Tue Nov  4 18:11:45 2014
New Revision: 427275

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=427275
Log:
config: Make text_file_save and 'dialplan save' escape semicolons in values.

When a config file is read, an unescaped semicolon signals comments which are
stripped from the value before it's stored.  Escaped semicolons are then
unescaped and become part of the value.  Both of these behaviors are normal
and expected.  When the config is serialized either by 'dialplan save' or
AMI/UpdateConfig however, the now unescaped semicolons are written as-is.
If you actually reload the file just saved, the unescaped semicolons are
now treated as start of comments.

Since true comments are stripped on read, any semicolons in
ast_variable.value must have been escaped originally.  This patch
re-escapes semicolons in ast_variable.values before they're written to
file either by 'dialplan save' or config/ast_config_text_file_save which
is called by AMI/UpdateConfig. I also fixed a few pre-existing formatting
issues nearby in pbx_config.c

Tested-by: George Joseph
ASTERISK-20127 #close

Review: https://reviewboard.asterisk.org/r/4132/


Modified:
    branches/12/include/asterisk/utils.h
    branches/12/main/config.c
    branches/12/main/utils.c
    branches/12/pbx/pbx_config.c
    branches/12/tests/test_strings.c

Modified: branches/12/include/asterisk/utils.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/utils.h?view=diff&rev=427275&r1=427274&r2=427275
==============================================================================
--- branches/12/include/asterisk/utils.h (original)
+++ branches/12/include/asterisk/utils.h Tue Nov  4 18:11:45 2014
@@ -317,6 +317,16 @@
  * \return a pointer to the escaped string
  */
 char *ast_escape_quoted(const char *string, char *outbuf, int buflen);
+
+/*!
+ * \brief Escape semicolons found in a string.
+ *
+ * \param string string to be escaped
+ * \param outbuf resulting escaped string
+ * \param buflen size of output buffer
+ * \return a pointer to the escaped string
+ */
+char *ast_escape_semicolons(const char *string, char *outbuf, int buflen);
 
 /*!
  * \brief Unescape quotes in a string

Modified: branches/12/main/config.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/config.c?view=diff&rev=427275&r1=427274&r2=427275
==============================================================================
--- branches/12/main/config.c (original)
+++ branches/12/main/config.c Tue Nov  4 18:11:45 2014
@@ -2496,6 +2496,7 @@
 			while (var) {
 				struct ast_category_template_instance *x;
 				int found = 0;
+
 				AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
 					struct ast_variable *v;
 					for (v = x->inst->root; v; v = v->next) {
@@ -2541,10 +2542,22 @@
 					if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
 						fprintf(f,"%s", cmt->cmt);
 				}
-				if (var->sameline)
-					fprintf(f, "%s %s %s  %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
-				else
-					fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
+
+				{ /* Block for 'escaped' scope */
+					int escaped_len = 2 * strlen(var->value) + 1;
+					char escaped[escaped_len];
+
+					ast_escape_semicolons(var->value, escaped, escaped_len);
+
+					if (var->sameline) {
+						fprintf(f, "%s %s %s  %s", var->name, (var->object ? "=>" : "="),
+							escaped, var->sameline->cmt);
+					} else {
+						fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="),
+							escaped);
+					}
+				}
+
 				for (cmt = var->trailing; cmt; cmt=cmt->next) {
 					if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
 						fprintf(f,"%s", cmt->cmt);

Modified: branches/12/main/utils.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/utils.c?view=diff&rev=427275&r1=427274&r2=427275
==============================================================================
--- branches/12/main/utils.c (original)
+++ branches/12/main/utils.c Tue Nov  4 18:11:45 2014
@@ -470,6 +470,37 @@
 				break;
 			}
 			out += sprintf(out, "\\%c", (unsigned char) *ptr);
+		} else {
+			*out = *ptr;
+			out++;
+		}
+		ptr++;
+	}
+
+	if (buflen) {
+		*out = '\0';
+	}
+
+	return outbuf;
+}
+
+char *ast_escape_semicolons(const char *string, char *outbuf, int buflen)
+{
+	const char *ptr = string;
+	char *out = outbuf;
+
+	if (string == NULL || outbuf == NULL) {
+		ast_assert(string != NULL && outbuf != NULL);
+		return NULL;
+	}
+
+	while (*ptr && out - outbuf < buflen - 1) {
+		if (*ptr == ';') {
+			if (out - outbuf >= buflen - 2) {
+				break;
+			}
+			strcpy(out, "\\;");
+			out += 2;
 		} else {
 			*out = *ptr;
 			out++;

Modified: branches/12/pbx/pbx_config.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/pbx/pbx_config.c?view=diff&rev=427275&r1=427274&r2=427275
==============================================================================
--- branches/12/pbx/pbx_config.c (original)
+++ branches/12/pbx/pbx_config.c Tue Nov  4 18:11:45 2014
@@ -789,7 +789,11 @@
 	if ((v = ast_variable_browse(cfg, "globals"))) {
 		fprintf(output, "[globals]\n");
 		while(v) {
-			fprintf(output, "%s => %s\n", v->name, v->value);
+			int escaped_len = 2 * strlen(v->value) + 1;
+			char escaped[escaped_len];
+
+			ast_escape_semicolons(v->value, escaped, escaped_len);
+			fprintf(output, "%s => %s\n", v->name, escaped);
 			v = v->next;
 		}
 		fprintf(output, "\n");
@@ -850,20 +854,33 @@
 					const char *sep, *cid;
 					const char *el = ast_get_extension_label(p);
 					char label[128] = "";
- 
+					char *appdata = ast_get_extension_app_data(p);
+					char *escaped;
+
 					if (ast_get_extension_matchcid(p)) {
 						sep = "/";
 						cid = ast_get_extension_cidmatch(p);
-					} else
+					} else {
 						sep = cid = "";
-				
-					if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2)))
+					}
+
+					if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2))) {
 						incomplete = 1;	/* error encountered or label > 125 chars */
-					
+					}
+
+					if (!ast_strlen_zero(appdata)) {
+						int escaped_len = 2 * strlen(appdata) + 1;
+						char escaped[escaped_len];
+
+						ast_escape_semicolons(appdata, escaped, escaped_len);
+					} else {
+						escaped = "";
+					}
+
 					fprintf(output, "exten => %s%s%s,%d%s,%s(%s)\n",
 					    ast_get_extension_name(p), (ast_strlen_zero(sep) ? "" : sep), (ast_strlen_zero(cid) ? "" : cid),
 					    ast_get_extension_priority(p), label,
-					    ast_get_extension_app(p), (ast_strlen_zero(ast_get_extension_app_data(p)) ? "" : (const char *)ast_get_extension_app_data(p)));
+					    ast_get_extension_app(p), escaped);
 				}
 			}
 		}

Modified: branches/12/tests/test_strings.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/tests/test_strings.c?view=diff&rev=427275&r1=427274&r2=427275
==============================================================================
--- branches/12/tests/test_strings.c (original)
+++ branches/12/tests/test_strings.c Tue Nov  4 18:11:45 2014
@@ -387,6 +387,74 @@
 	return AST_TEST_PASS;
 }
 
+static int test_semi(char *string1, char *string2, int test_len)
+{
+	char *test2 = NULL;
+	if (test_len >= 0) {
+		test2 = ast_alloca(test_len);
+		*test2 = '\0';
+	}
+	ast_escape_semicolons(string1, test2, test_len);
+	if (test2 != NULL && strcmp(string2, test2) == 0) {
+		return 1;
+	} else {
+		return 0;
+	}
+}
+
+AST_TEST_DEFINE(escape_semicolons_test)
+{
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "escape_semicolons";
+		info->category = "/main/strings/";
+		info->summary = "Test ast_escape_semicolons";
+		info->description = "Test ast_escape_semicolons";
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+
+	ast_test_validate(test, test_semi("this is a ;test", "this is a \\;test", 18));
+	ast_test_validate(test, test_semi(";", "\\;", 3));
+
+	/* The following tests should return empty because there's not enough room to output
+	 * an escaped ; or even a single character.
+	 */
+	ast_test_validate(test, test_semi(";", "", 0));
+	ast_test_validate(test, test_semi(";", "", 1));
+	ast_test_validate(test, test_semi(";", "", 2));
+	ast_test_validate(test, test_semi("x", "", 0));
+	ast_test_validate(test, test_semi("x", "", 1));
+
+	/* At least some output should be produced now. */
+	ast_test_validate(test, test_semi("xx;xx", "x", 2));
+	ast_test_validate(test, test_semi("xx;xx", "xx", 3));
+
+	/* There's still not enough room to output \; so
+	 * don't even print the \
+	 */
+	ast_test_validate(test, test_semi("xx;xx", "xx", 4));
+
+	ast_test_validate(test, test_semi("xx;xx", "xx\\;", 5));
+	ast_test_validate(test, test_semi("xx;xx", "xx\\;x", 6));
+	ast_test_validate(test, test_semi("xx;xx", "xx\\;xx", 7));
+	ast_test_validate(test, test_semi("xx;xx", "xx\\;xx", 8));
+
+	/* Random stuff */
+	ast_test_validate(test, test_semi("xx;xx;this is a test", "xx\\;xx\\;this is a test", 32));
+	ast_test_validate(test, test_semi(";;;;;", "\\;\\;\\;\\;\\;", 32));
+	ast_test_validate(test, test_semi(";;;;;", "\\;\\;\\;\\;", 10));
+	ast_test_validate(test, test_semi(";;;;;", "\\;\\;\\;\\;\\;", 11));
+	ast_test_validate(test, test_semi(";;\\;;;", "\\;\\;\\\\;\\;\\;", 32));
+
+	ast_test_status_update(test, "This test should produce 2 'ast_escape_semicolons: FRACK!, Failed assertion' messages.\n");
+	ast_test_validate(test, !test_semi(NULL, "xx\\;xx", 8));
+	ast_test_validate(test, !test_semi("xx;xx", "xx\\;xx", -1));
+
+	return AST_TEST_PASS;
+}
 
 static int unload_module(void)
 {
@@ -394,6 +462,7 @@
 	AST_TEST_UNREGISTER(begins_with_test);
 	AST_TEST_UNREGISTER(ends_with_test);
 	AST_TEST_UNREGISTER(strsep_test);
+	AST_TEST_UNREGISTER(escape_semicolons_test);
 	return 0;
 }
 
@@ -403,6 +472,7 @@
 	AST_TEST_REGISTER(begins_with_test);
 	AST_TEST_REGISTER(ends_with_test);
 	AST_TEST_REGISTER(strsep_test);
+	AST_TEST_REGISTER(escape_semicolons_test);
 	return AST_MODULE_LOAD_SUCCESS;
 }
 




More information about the asterisk-commits mailing list