--- asterisk-1.6.2.7/main/manager.c	2010-01-28 17:56:59.000000000 -0500
+++ asterisk-1.6.2.7.modified/main/manager.c	2010-05-09 19:26:09.849004910 -0500
@@ -3484,12 +3484,14 @@
 	FORMAT_RAW,
 	FORMAT_HTML,
 	FORMAT_XML,
+	FORMAT_JSON,
 };
 
 static char *contenttype[] = {
-	[FORMAT_RAW] = "plain",
-	[FORMAT_HTML] = "html",
-	[FORMAT_XML] =  "xml",
+	[FORMAT_RAW] = "text/plain",
+	[FORMAT_HTML] = "text/html",
+	[FORMAT_XML] =  "text/xml",
+	[FORMAT_JSON] = "application/json",
 };
 
 /*!
@@ -3709,7 +3711,10 @@
 	const char *objtype = NULL;
 	int in_data = 0;	/* parsing data */
 	int inobj = 0;
+	int is_first = 1;
+	int html = (format == FORMAT_HTML);
 	int xml = (format == FORMAT_XML);
+	int json = (format == FORMAT_JSON);
 	struct variable_count *vc = NULL;
 	struct ao2_container *vco = NULL;
 
@@ -3733,12 +3738,21 @@
 		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");
+				if (html)
+					ast_str_append(out, 0, "</td></tr>\r\n");
+				else if (xml)
+					ast_str_append(out, 0, "'");
+				else if (json)
+					ast_str_append(out, 0, "\"");
 				in_data = 0;
 			}
 			if (inobj) {
-				ast_str_append(out, 0, xml ? " /></response>\n" :
-					"<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+				if (html)
+					ast_str_append(out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+				else if (xml)
+					ast_str_append(out, 0, " /></response>\n");
+				else if (json)
+					ast_str_append(out, 0, "}");
 				inobj = 0;
 				ao2_ref(vco, -1);
 				vco = NULL;
@@ -3761,16 +3775,26 @@
 		}
 
 		if (!inobj) {
-			if (xml)
+			if (html)
+				ast_str_append(out, 0, "<body>\r\n");
+			else if (xml)
 				ast_str_append(out, 0, "<response type='object' id='%s'><%s", dest, objtype);
-			else
-				ast_str_append(out, 0, "<body>\n");
+			else if (json) {
+				if (!is_first)
+					ast_str_append(out, 0, ",");
+				ast_str_append(out, 0, "{\"id\":\"%s\",\"type\":\"%s\"", dest, objtype);
+			}
 			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 (html)
+				ast_str_append(out, 0, "<tr><td>");
+			else if (xml)
+				ast_str_append(out, 0, " ");
+			else if (json)
+				ast_str_append(out, 0, ",\"");
 			if ((vc = ao2_find(vco, var, 0)))
 				vc->count++;
 			else {
@@ -3780,23 +3804,47 @@
 				vc->count = 1;
 				ao2_link(vco, vc);
 			}
-			xml_copy_escape(out, var, xml ? 1 | 2 : 0);
+			xml_copy_escape(out, var, xml || json ? 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 (html)
+				ast_str_append(out, 0, "</td><td>");
+			else if (xml)
+				ast_str_append(out, 0, "='");
+			else if (json)
+				ast_str_append(out, 0, "\":\"");
 			if (!strcmp(var, "Opaque-data"))
 				in_data = 1;
 		}
-		xml_copy_escape(out, val, 0);	/* data field */
-		if (!in_data)
-			ast_str_append(out, 0, xml ? "'" : "</td></tr>\n");
+		/* data field */
+		if (json)
+			ast_str_append(out, 0, "%s", val);
 		else
-			ast_str_append(out, 0, xml ? "\n" : "<br>\n");
+			xml_copy_escape(out, val, 0);
+		if (is_first)
+			is_first = 0;
+		if (!in_data) {
+			if (html)
+				ast_str_append(out, 0, "</td></tr>\n");
+			else if (xml)
+				ast_str_append(out, 0, "'");
+			else if (json)
+				ast_str_append(out, 0, "\"");
+		} else {
+			if (html)
+				ast_str_append(out, 0, "<br>\n");
+			else if (xml)
+				ast_str_append(out, 0, "\n");
+		}
 	}
 	if (inobj) {
-		ast_str_append(out, 0, xml ? " /></response>\n" :
-			"<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+		if (html)
+			ast_str_append(out, 0, "<tr><td colspan=\"2\"><hr></td></tr>\r\n");
+		else if (xml)
+			ast_str_append(out, 0, " /></response>\n");
+		else if (json)
+			ast_str_append(out, 0, "}");
 		ao2_ref(vco, -1);
 	}
 }
@@ -3890,7 +3938,7 @@
 	}
 
 	ast_str_append(&out, 0,
-		       "Content-type: text/%s\r\n"
+		       "Content-type: %s\r\n"
 		       "Cache-Control: no-cache;\r\n"
 		       "Set-Cookie: mansession_id=\"%08x\"; Version=\"1\"; Max-Age=%d\r\n"
 		       "Pragma: SuppressEvents\r\n"
@@ -3900,6 +3948,8 @@
 
 	if (format == FORMAT_XML) {
 		ast_str_append(&out, 0, "<ajax-response>\n");
+	} else if (format == FORMAT_JSON) {
+		ast_str_append(&out, 0, "[");
 	} else if (format == FORMAT_HTML) {
 		/*
 		 * When handling AMI-over-HTTP in HTML format, we provide a simple form for
@@ -3937,13 +3987,13 @@
 
 		if ((l = ftell(s.f))) {
 			if ((buf = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_SHARED, s.fd, 0))) {
-				if (format == FORMAT_XML || format == FORMAT_HTML)
+				if (format == FORMAT_XML || format == FORMAT_HTML || format == FORMAT_JSON)
 					xml_translate(&out, buf, params, format);
 				else
 					ast_str_append(&out, 0, "%s", buf);
 				munmap(buf, l);
 			}
-		} else if (format == FORMAT_XML || format == FORMAT_HTML) {
+		} else if (format == FORMAT_XML || format == FORMAT_HTML || format == FORMAT_JSON) {
 			xml_translate(&out, "", params, format);
 		}
 		fclose(s.f);
@@ -3953,6 +4003,8 @@
 
 	if (format == FORMAT_XML) {
 		ast_str_append(&out, 0, "</ajax-response>\n");
+	} else if (format == FORMAT_JSON) {
+		ast_str_append(&out, 0, "]\n");
 	} else if (format == FORMAT_HTML)
 		ast_str_append(&out, 0, "</table></body>\r\n");
 
@@ -3992,6 +4044,11 @@
 	return generic_http_callback(FORMAT_XML, &ser->remote_address, uri, method, params, status, title, contentlength);
 }
 
+static struct ast_str *mjson_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
+{
+	return generic_http_callback(FORMAT_JSON, &ser->remote_address, uri, method, params, status, title, contentlength);
+}
+
 static struct ast_str *rawman_http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *params, struct ast_variable *headers, int *status, char **title, int *contentlength)
 {
 	return generic_http_callback(FORMAT_RAW, &ser->remote_address, uri, method, params, status, title, contentlength);
@@ -4024,6 +4081,15 @@
 	.key = __FILE__,
 };
 
+struct ast_http_uri managerjsonuri = {
+	.description = "JSON Manager Event Interface",
+	.uri = "mjson",
+	.callback = mjson_http_callback,
+	.supports_get = 1,
+	.data = NULL,
+	.key = __FILE__,
+};
+
 static int registered = 0;
 static int webregged = 0;
 
@@ -4351,6 +4417,7 @@
 			ast_http_uri_link(&rawmanuri);
 			ast_http_uri_link(&manageruri);
 			ast_http_uri_link(&managerxmluri);
+			ast_http_uri_link(&managerjsonuri);
 			webregged = 1;
 		}
 	} else {
@@ -4358,6 +4425,7 @@
 			ast_http_uri_unlink(&rawmanuri);
 			ast_http_uri_unlink(&manageruri);
 			ast_http_uri_unlink(&managerxmluri);
+			ast_http_uri_unlink(&managerjsonuri);
 			webregged = 0;
 		}
 	}
