diff --git a/main/manager.c b/main/manager.c index f0650457d9..332d2c591d 100644 --- a/main/manager.c +++ b/main/manager.c @@ -69,6 +69,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/threadstorage.h" #include "asterisk/linkedlists.h" #include "asterisk/term.h" +#include "asterisk/astobj2.h" /*! * Linked list of events. @@ -2935,6 +2936,47 @@ static void xml_copy_escape(struct ast_str **out, const char *src, int mode) } } +struct variable_count { + char *varname; + int count; +}; + +static int compress_char(char c) +{ + c &= 0x7f; + if (c < 32) + return 0; + else if (c >= 'a' && c <= 'z') + return c - 64; + else if (c > 'z') + return '_'; + else + return c - 32; +} + +static int variable_count_hash_fn(const void *vvc, const int flags) +{ + const struct variable_count *vc = vvc; + int res = 0, i; + for (i = 0; i < 5; i++) { + if (vc->varname[i] == '\0') + break; + res += compress_char(vc->varname[i]) << (i * 6); + } + return res; +} + +static int variable_count_cmp_fn(void *obj, void *vstr, int flags) +{ + /* Due to the simplicity of struct variable_count, it makes no difference + * if you pass in objects or strings, the same operation applies. This is + * due to the fact that the hash occurs on the first element, which means + * the address of both the struct and the string are exactly the same. */ + struct variable_count *vc = obj; + char *str = vstr; + return !strcmp(vc->varname, str) ? CMP_MATCH : 0; +} + /*! \brief Convert the input into XML or HTML. * The input is supposed to be a sequence of lines of the form * Name: value @@ -2972,6 +3014,8 @@ static void xml_translate(struct ast_str **out, char *in, struct ast_variable *v int in_data = 0; /* parsing data */ int inobj = 0; int xml = (format == FORMAT_XML); + struct variable_count *vc = NULL; + struct ao2_container *vco = NULL; for (v = vars; v; v = v->next) { if (!dest && !strcasecmp(v->name, "ajaxdest")) @@ -2983,36 +3027,14 @@ static void xml_translate(struct ast_str **out, char *in, struct ast_variable *v dest = "unknown"; if (!objtype) objtype = "generic"; -#if 0 - /* determine how large is the response. - * This is a heuristic - counting colons (for headers), - * newlines (for extra arguments), and escaped chars. - * XXX needs to be checked carefully for overflows. - * Even better, use some code that allows extensible strings. - */ - for (x = 0; in[x]; x++) { - if (in[x] == ':') - colons++; - else if (in[x] == '\n') - breaks++; - else if (strchr("&\"<>", in[x])) - escaped++; - } - len = (size_t) (1 + strlen(in) + colons * 5 + breaks * (40 + strlen(dest) + strlen(objtype)) + escaped * 10); /* foo="bar", "\n", inobj, in_data, val); + ast_debug(5, "inobj %d in_data %d line <%s>\n", inobj, in_data, val); if (ast_strlen_zero(val)) { if (in_data) { /* close data */ ast_str_append(out, 0, xml ? "'" : "\n"); @@ -3021,8 +3043,11 @@ static void xml_translate(struct ast_str **out, char *in, struct ast_variable *v ast_str_append(out, 0, xml ? " />\n" : "
\r\n"); inobj = 0; + ao2_ref(vco, -1); + vco = NULL; continue; } + /* we expect Name: value lines */ if (in_data) { var = NULL; @@ -3036,16 +3061,33 @@ static void xml_translate(struct ast_str **out, char *in, struct ast_variable *v var = "Opaque-data"; } } + if (!inobj) { if (xml) ast_str_append(out, 0, "<%s", dest, objtype); else ast_str_append(out, 0, "\n"); + vco = ao2_container_alloc(37, variable_count_hash_fn, variable_count_cmp_fn); inobj = 1; } + if (!in_data) { /* build appropriate line start */ ast_str_append(out, 0, xml ? " " : ""); + if ((vc = ao2_find(vco, var, 0))) + vc->count++; + else { + /* Create a new entry for this one */ + vc = ao2_alloc(sizeof(*vc), NULL); + vc->varname = var; + vc->count = 1; + /* Increment refcount, because we're going to deref once later */ + ao2_ref(vc, 1); + ao2_link(vco, vc); + } xml_copy_escape(out, var, xml ? 1 | 2 : 0); + if (vc->count > 1) + ast_str_append(out, 0, "-%d", vc->count); + ao2_ref(vc, -1); ast_str_append(out, 0, xml ? "='" : ""); if (!strcmp(var, "Opaque-data")) in_data = 1; @@ -3056,9 +3098,11 @@ static void xml_translate(struct ast_str **out, char *in, struct ast_variable *v else ast_str_append(out, 0, xml ? "\n" : "
\n"); } - if (inobj) + if (inobj) { ast_str_append(out, 0, xml ? " />
\n" : "
\r\n"); + ao2_ref(vco, -1); + } } static struct ast_str *generic_http_callback(enum output_format format,