#include "asterisk/threadstorage.h"
#include "asterisk/linkedlists.h"
#include "asterisk/term.h"
+#include "asterisk/astobj2.h"
/*!
* Linked list of events.
}
}
+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
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"))
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", "<response type=\"object\" id=\"dest\"", "&" */
- out = ast_malloc(len);
- if (!out)
- return NULL;
- tmp = out;
- *tmp = '\0';
-#endif
+
/* we want to stop when we find an empty line */
while (in && *in) {
val = strsep(&in, "\r\n"); /* mark start and end of line */
if (in && *in == '\n') /* remove trailing \n if any */
in++;
ast_trim_blanks(val);
- if (0)
- ast_verbose("inobj %d in_data %d line <%s>\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 ? "'" : "</td></tr>\n");
ast_str_append(out, 0, xml ? " /></response>\n" :
"<tr><td colspan=\"2\"><hr></td></tr>\r\n");
inobj = 0;
+ ao2_ref(vco, -1);
+ vco = NULL;
continue;
}
+
/* we expect Name: value lines */
if (in_data) {
var = NULL;
var = "Opaque-data";
}
}
+
if (!inobj) {
if (xml)
ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
else
ast_str_append(out, 0, "<body>\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 ? " " : "<tr><td>");
+ 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 ? "='" : "</td><td>");
if (!strcmp(var, "Opaque-data"))
in_data = 1;
else
ast_str_append(out, 0, xml ? "\n" : "<br>\n");
}
- if (inobj)
+ if (inobj) {
ast_str_append(out, 0, xml ? " /></response>\n" :
"<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+ ao2_ref(vco, -1);
+ }
}
static struct ast_str *generic_http_callback(enum output_format format,