summaryrefslogtreecommitdiff
path: root/res/ari
diff options
context:
space:
mode:
authorKinsey Moore <kmoore@digium.com>2013-07-27 23:11:02 +0000
committerKinsey Moore <kmoore@digium.com>2013-07-27 23:11:02 +0000
commitd8956f690e7fe2d3b7799c16d0d44bbcbe25d83f (patch)
tree437bcde14739627193195953a5f8742eaa216333 /res/ari
parentfc05248bd1158d587d2339c56ed27be57d333d86 (diff)
Rename everything Stasis-HTTP to ARI
This renames all files and API calls from several variants of Stasis-HTTP to ARI including: * Stasis-HTTP -> ARI * STASIS_HTTP -> ARI * stasis_http -> ari (ast_ari for global symbols, file names as well) * stasis http -> ARI Review: https://reviewboard.asterisk.org/r/2706/ (closes issue ASTERISK-22136) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@395603 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/ari')
-rw-r--r--res/ari/ari_model_validators.c2969
-rw-r--r--res/ari/ari_model_validators.h962
-rw-r--r--res/ari/ari_websockets.c165
-rw-r--r--res/ari/cli.c267
-rw-r--r--res/ari/config.c345
-rw-r--r--res/ari/internal.h143
-rw-r--r--res/ari/resource_asterisk.c80
-rw-r--r--res/ari/resource_asterisk.h84
-rw-r--r--res/ari/resource_bridges.c514
-rw-r--r--res/ari/resource_bridges.h179
-rw-r--r--res/ari/resource_channels.c693
-rw-r--r--res/ari/resource_channels.h330
-rw-r--r--res/ari/resource_endpoints.c157
-rw-r--r--res/ari/resource_endpoints.h82
-rw-r--r--res/ari/resource_events.c218
-rw-r--r--res/ari/resource_events.h56
-rw-r--r--res/ari/resource_playback.c137
-rw-r--r--res/ari/resource_playback.h84
-rw-r--r--res/ari/resource_recordings.c97
-rw-r--r--res/ari/resource_recordings.h186
-rw-r--r--res/ari/resource_sounds.c220
-rw-r--r--res/ari/resource_sounds.h69
22 files changed, 8037 insertions, 0 deletions
diff --git a/res/ari/ari_model_validators.c b/res/ari/ari_model_validators.c
new file mode 100644
index 000000000..1894ddb9a
--- /dev/null
+++ b/res/ari/ari_model_validators.c
@@ -0,0 +1,2969 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - Build validators for ARI model objects.
+ */
+
+ /*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_model_validators.h.mustache
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/logger.h"
+#include "asterisk/module.h"
+#include "ari_model_validators.h"
+
+int ast_ari_validate_asterisk_info(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ {
+ ast_log(LOG_ERROR,
+ "ARI AsteriskInfo has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_asterisk_info_fn(void)
+{
+ return ast_ari_validate_asterisk_info;
+}
+
+int ast_ari_validate_variable(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_value = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("value", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_value = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Variable field value failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Variable has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_value) {
+ ast_log(LOG_ERROR, "ARI Variable missing required field value\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_variable_fn(void)
+{
+ return ast_ari_validate_variable;
+}
+
+int ast_ari_validate_endpoint(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_channel_ids = 0;
+ int has_resource = 0;
+ int has_technology = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("channel_ids", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel_ids = 1;
+ prop_is_valid = ast_ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ast_ari_validate_string);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Endpoint field channel_ids failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("resource", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_resource = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Endpoint field resource failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Endpoint field state failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("technology", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_technology = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Endpoint field technology failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Endpoint has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_channel_ids) {
+ ast_log(LOG_ERROR, "ARI Endpoint missing required field channel_ids\n");
+ res = 0;
+ }
+
+ if (!has_resource) {
+ ast_log(LOG_ERROR, "ARI Endpoint missing required field resource\n");
+ res = 0;
+ }
+
+ if (!has_technology) {
+ ast_log(LOG_ERROR, "ARI Endpoint missing required field technology\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_endpoint_fn(void)
+{
+ return ast_ari_validate_endpoint;
+}
+
+int ast_ari_validate_caller_id(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_name = 0;
+ int has_number = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_name = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI CallerID field name failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("number", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_number = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI CallerID field number failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI CallerID has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_name) {
+ ast_log(LOG_ERROR, "ARI CallerID missing required field name\n");
+ res = 0;
+ }
+
+ if (!has_number) {
+ ast_log(LOG_ERROR, "ARI CallerID missing required field number\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_caller_id_fn(void)
+{
+ return ast_ari_validate_caller_id;
+}
+
+int ast_ari_validate_channel(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_accountcode = 0;
+ int has_caller = 0;
+ int has_connected = 0;
+ int has_creationtime = 0;
+ int has_dialplan = 0;
+ int has_id = 0;
+ int has_name = 0;
+ int has_state = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("accountcode", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_accountcode = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field accountcode failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("caller", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_caller = 1;
+ prop_is_valid = ast_ari_validate_caller_id(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field caller failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("connected", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_connected = 1;
+ prop_is_valid = ast_ari_validate_caller_id(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field connected failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("creationtime", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_creationtime = 1;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field creationtime failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("dialplan", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_dialplan = 1;
+ prop_is_valid = ast_ari_validate_dialplan_cep(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field dialplan failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field id failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_name = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field name failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_state = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Channel field state failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Channel has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_accountcode) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field accountcode\n");
+ res = 0;
+ }
+
+ if (!has_caller) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field caller\n");
+ res = 0;
+ }
+
+ if (!has_connected) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field connected\n");
+ res = 0;
+ }
+
+ if (!has_creationtime) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field creationtime\n");
+ res = 0;
+ }
+
+ if (!has_dialplan) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field dialplan\n");
+ res = 0;
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field id\n");
+ res = 0;
+ }
+
+ if (!has_name) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field name\n");
+ res = 0;
+ }
+
+ if (!has_state) {
+ ast_log(LOG_ERROR, "ARI Channel missing required field state\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_fn(void)
+{
+ return ast_ari_validate_channel;
+}
+
+int ast_ari_validate_dialed(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ {
+ ast_log(LOG_ERROR,
+ "ARI Dialed has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_dialed_fn(void)
+{
+ return ast_ari_validate_dialed;
+}
+
+int ast_ari_validate_dialplan_cep(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_context = 0;
+ int has_exten = 0;
+ int has_priority = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("context", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_context = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP field context failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("exten", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_exten = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP field exten failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("priority", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_priority = 1;
+ prop_is_valid = ast_ari_validate_long(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP field priority failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI DialplanCEP has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_context) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP missing required field context\n");
+ res = 0;
+ }
+
+ if (!has_exten) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP missing required field exten\n");
+ res = 0;
+ }
+
+ if (!has_priority) {
+ ast_log(LOG_ERROR, "ARI DialplanCEP missing required field priority\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_dialplan_cep_fn(void)
+{
+ return ast_ari_validate_dialplan_cep;
+}
+
+int ast_ari_validate_bridge(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_bridge_class = 0;
+ int has_bridge_type = 0;
+ int has_channels = 0;
+ int has_id = 0;
+ int has_technology = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("bridge_class", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge_class = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field bridge_class failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge_type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field bridge_type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channels", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channels = 1;
+ prop_is_valid = ast_ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ast_ari_validate_string);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field channels failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field id failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("technology", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_technology = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Bridge field technology failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Bridge has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_bridge_class) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field bridge_class\n");
+ res = 0;
+ }
+
+ if (!has_bridge_type) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field bridge_type\n");
+ res = 0;
+ }
+
+ if (!has_channels) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field channels\n");
+ res = 0;
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field id\n");
+ res = 0;
+ }
+
+ if (!has_technology) {
+ ast_log(LOG_ERROR, "ARI Bridge missing required field technology\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_bridge_fn(void)
+{
+ return ast_ari_validate_bridge;
+}
+
+int ast_ari_validate_live_recording(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_format = 0;
+ int has_name = 0;
+ int has_state = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("format", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_format = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI LiveRecording field format failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("name", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_name = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI LiveRecording field name failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_state = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI LiveRecording field state failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI LiveRecording has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_format) {
+ ast_log(LOG_ERROR, "ARI LiveRecording missing required field format\n");
+ res = 0;
+ }
+
+ if (!has_name) {
+ ast_log(LOG_ERROR, "ARI LiveRecording missing required field name\n");
+ res = 0;
+ }
+
+ if (!has_state) {
+ ast_log(LOG_ERROR, "ARI LiveRecording missing required field state\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_live_recording_fn(void)
+{
+ return ast_ari_validate_live_recording;
+}
+
+int ast_ari_validate_stored_recording(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_formats = 0;
+ int has_id = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("duration_seconds", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StoredRecording field duration_seconds failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("formats", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_formats = 1;
+ prop_is_valid = ast_ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ast_ari_validate_string);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StoredRecording field formats failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StoredRecording field id failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("time", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StoredRecording field time failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI StoredRecording has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_formats) {
+ ast_log(LOG_ERROR, "ARI StoredRecording missing required field formats\n");
+ res = 0;
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI StoredRecording missing required field id\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_stored_recording_fn(void)
+{
+ return ast_ari_validate_stored_recording;
+}
+
+int ast_ari_validate_format_lang_pair(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_format = 0;
+ int has_language = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("format", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_format = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI FormatLangPair field format failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("language", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_language = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI FormatLangPair field language failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI FormatLangPair has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_format) {
+ ast_log(LOG_ERROR, "ARI FormatLangPair missing required field format\n");
+ res = 0;
+ }
+
+ if (!has_language) {
+ ast_log(LOG_ERROR, "ARI FormatLangPair missing required field language\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_format_lang_pair_fn(void)
+{
+ return ast_ari_validate_format_lang_pair;
+}
+
+int ast_ari_validate_sound(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_formats = 0;
+ int has_id = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("formats", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_formats = 1;
+ prop_is_valid = ast_ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ast_ari_validate_format_lang_pair);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Sound field formats failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Sound field id failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("text", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Sound field text failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Sound has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_formats) {
+ ast_log(LOG_ERROR, "ARI Sound missing required field formats\n");
+ res = 0;
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI Sound missing required field id\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_sound_fn(void)
+{
+ return ast_ari_validate_sound;
+}
+
+int ast_ari_validate_playback(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_id = 0;
+ int has_media_uri = 0;
+ int has_state = 0;
+ int has_target_uri = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("id", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_id = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field id failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("language", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field language failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("media_uri", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_media_uri = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field media_uri failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("state", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_state = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field state failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("target_uri", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_target_uri = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Playback field target_uri failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Playback has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_id) {
+ ast_log(LOG_ERROR, "ARI Playback missing required field id\n");
+ res = 0;
+ }
+
+ if (!has_media_uri) {
+ ast_log(LOG_ERROR, "ARI Playback missing required field media_uri\n");
+ res = 0;
+ }
+
+ if (!has_state) {
+ ast_log(LOG_ERROR, "ARI Playback missing required field state\n");
+ res = 0;
+ }
+
+ if (!has_target_uri) {
+ ast_log(LOG_ERROR, "ARI Playback missing required field target_uri\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_playback_fn(void)
+{
+ return ast_ari_validate_playback;
+}
+
+int ast_ari_validate_application_replaced(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ApplicationReplaced has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ApplicationReplaced missing required field application\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_application_replaced_fn(void)
+{
+ return ast_ari_validate_application_replaced;
+}
+
+int ast_ari_validate_bridge_created(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_bridge = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ast_ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI BridgeCreated has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI BridgeCreated missing required field bridge\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_bridge_created_fn(void)
+{
+ return ast_ari_validate_bridge_created;
+}
+
+int ast_ari_validate_bridge_destroyed(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_bridge = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ast_ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI BridgeDestroyed has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI BridgeDestroyed missing required field bridge\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_bridge_destroyed_fn(void)
+{
+ return ast_ari_validate_bridge_destroyed;
+}
+
+int ast_ari_validate_bridge_merged(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_bridge = 0;
+ int has_bridge_from = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ast_ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge_from", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge_from = 1;
+ prop_is_valid = ast_ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged field bridge_from failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI BridgeMerged has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged missing required field bridge\n");
+ res = 0;
+ }
+
+ if (!has_bridge_from) {
+ ast_log(LOG_ERROR, "ARI BridgeMerged missing required field bridge_from\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_bridge_merged_fn(void)
+{
+ return ast_ari_validate_bridge_merged;
+}
+
+int ast_ari_validate_channel_caller_id(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_caller_presentation = 0;
+ int has_caller_presentation_txt = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("caller_presentation", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_caller_presentation = 1;
+ prop_is_valid = ast_ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field caller_presentation failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("caller_presentation_txt", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_caller_presentation_txt = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field caller_presentation_txt failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelCallerId has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_caller_presentation) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field caller_presentation\n");
+ res = 0;
+ }
+
+ if (!has_caller_presentation_txt) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field caller_presentation_txt\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelCallerId missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_caller_id_fn(void)
+{
+ return ast_ari_validate_channel_caller_id;
+}
+
+int ast_ari_validate_channel_created(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelCreated has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelCreated missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_created_fn(void)
+{
+ return ast_ari_validate_channel_created;
+}
+
+int ast_ari_validate_channel_destroyed(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_cause = 0;
+ int has_cause_txt = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_cause = 1;
+ prop_is_valid = ast_ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field cause failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("cause_txt", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_cause_txt = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field cause_txt failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelDestroyed has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_cause) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field cause\n");
+ res = 0;
+ }
+
+ if (!has_cause_txt) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field cause_txt\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelDestroyed missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_destroyed_fn(void)
+{
+ return ast_ari_validate_channel_destroyed;
+}
+
+int ast_ari_validate_channel_dialplan(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_channel = 0;
+ int has_dialplan_app = 0;
+ int has_dialplan_app_data = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("dialplan_app", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_dialplan_app = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field dialplan_app failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("dialplan_app_data", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_dialplan_app_data = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan field dialplan_app_data failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelDialplan has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field channel\n");
+ res = 0;
+ }
+
+ if (!has_dialplan_app) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field dialplan_app\n");
+ res = 0;
+ }
+
+ if (!has_dialplan_app_data) {
+ ast_log(LOG_ERROR, "ARI ChannelDialplan missing required field dialplan_app_data\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_dialplan_fn(void)
+{
+ return ast_ari_validate_channel_dialplan;
+}
+
+int ast_ari_validate_channel_dtmf_received(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_channel = 0;
+ int has_digit = 0;
+ int has_duration_ms = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("digit", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_digit = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field digit failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("duration_ms", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_duration_ms = 1;
+ prop_is_valid = ast_ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived field duration_ms failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelDtmfReceived has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field channel\n");
+ res = 0;
+ }
+
+ if (!has_digit) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field digit\n");
+ res = 0;
+ }
+
+ if (!has_duration_ms) {
+ ast_log(LOG_ERROR, "ARI ChannelDtmfReceived missing required field duration_ms\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_dtmf_received_fn(void)
+{
+ return ast_ari_validate_channel_dtmf_received;
+}
+
+int ast_ari_validate_channel_entered_bridge(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_bridge = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ast_ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelEnteredBridge has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI ChannelEnteredBridge missing required field bridge\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_entered_bridge_fn(void)
+{
+ return ast_ari_validate_channel_entered_bridge;
+}
+
+int ast_ari_validate_channel_hangup_request(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_int(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field cause failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("soft", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_boolean(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest field soft failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelHangupRequest has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelHangupRequest missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_hangup_request_fn(void)
+{
+ return ast_ari_validate_channel_hangup_request;
+}
+
+int ast_ari_validate_channel_left_bridge(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_bridge = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("bridge", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_bridge = 1;
+ prop_is_valid = ast_ari_validate_bridge(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge field bridge failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelLeftBridge has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_bridge) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field bridge\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelLeftBridge missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_left_bridge_fn(void)
+{
+ return ast_ari_validate_channel_left_bridge;
+}
+
+int ast_ari_validate_channel_state_change(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelStateChange has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelStateChange missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_state_change_fn(void)
+{
+ return ast_ari_validate_channel_state_change;
+}
+
+int ast_ari_validate_channel_userevent(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_channel = 0;
+ int has_eventname = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("eventname", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_eventname = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent field eventname failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelUserevent has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field channel\n");
+ res = 0;
+ }
+
+ if (!has_eventname) {
+ ast_log(LOG_ERROR, "ARI ChannelUserevent missing required field eventname\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_userevent_fn(void)
+{
+ return ast_ari_validate_channel_userevent;
+}
+
+int ast_ari_validate_channel_varset(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_value = 0;
+ int has_variable = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("value", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_value = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field value failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("variable", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_variable = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset field variable failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI ChannelVarset has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_value) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset missing required field value\n");
+ res = 0;
+ }
+
+ if (!has_variable) {
+ ast_log(LOG_ERROR, "ARI ChannelVarset missing required field variable\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_channel_varset_fn(void)
+{
+ return ast_ari_validate_channel_varset;
+}
+
+int ast_ari_validate_event(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ const char *discriminator;
+
+ discriminator = ast_json_string_get(ast_json_object_get(json, "type"));
+ if (!discriminator) {
+ ast_log(LOG_ERROR, "ARI Event missing required field type");
+ return 0;
+ }
+
+ if (strcmp("Event", discriminator) == 0) {
+ /* Self type; fall through */
+ } else
+ if (strcmp("ApplicationReplaced", discriminator) == 0) {
+ return ast_ari_validate_application_replaced(json);
+ } else
+ if (strcmp("BridgeCreated", discriminator) == 0) {
+ return ast_ari_validate_bridge_created(json);
+ } else
+ if (strcmp("BridgeDestroyed", discriminator) == 0) {
+ return ast_ari_validate_bridge_destroyed(json);
+ } else
+ if (strcmp("BridgeMerged", discriminator) == 0) {
+ return ast_ari_validate_bridge_merged(json);
+ } else
+ if (strcmp("ChannelCallerId", discriminator) == 0) {
+ return ast_ari_validate_channel_caller_id(json);
+ } else
+ if (strcmp("ChannelCreated", discriminator) == 0) {
+ return ast_ari_validate_channel_created(json);
+ } else
+ if (strcmp("ChannelDestroyed", discriminator) == 0) {
+ return ast_ari_validate_channel_destroyed(json);
+ } else
+ if (strcmp("ChannelDialplan", discriminator) == 0) {
+ return ast_ari_validate_channel_dialplan(json);
+ } else
+ if (strcmp("ChannelDtmfReceived", discriminator) == 0) {
+ return ast_ari_validate_channel_dtmf_received(json);
+ } else
+ if (strcmp("ChannelEnteredBridge", discriminator) == 0) {
+ return ast_ari_validate_channel_entered_bridge(json);
+ } else
+ if (strcmp("ChannelHangupRequest", discriminator) == 0) {
+ return ast_ari_validate_channel_hangup_request(json);
+ } else
+ if (strcmp("ChannelLeftBridge", discriminator) == 0) {
+ return ast_ari_validate_channel_left_bridge(json);
+ } else
+ if (strcmp("ChannelStateChange", discriminator) == 0) {
+ return ast_ari_validate_channel_state_change(json);
+ } else
+ if (strcmp("ChannelUserevent", discriminator) == 0) {
+ return ast_ari_validate_channel_userevent(json);
+ } else
+ if (strcmp("ChannelVarset", discriminator) == 0) {
+ return ast_ari_validate_channel_varset(json);
+ } else
+ if (strcmp("PlaybackFinished", discriminator) == 0) {
+ return ast_ari_validate_playback_finished(json);
+ } else
+ if (strcmp("PlaybackStarted", discriminator) == 0) {
+ return ast_ari_validate_playback_started(json);
+ } else
+ if (strcmp("StasisEnd", discriminator) == 0) {
+ return ast_ari_validate_stasis_end(json);
+ } else
+ if (strcmp("StasisStart", discriminator) == 0) {
+ return ast_ari_validate_stasis_start(json);
+ } else
+ {
+ ast_log(LOG_ERROR, "ARI Event has undocumented subtype %s\n",
+ discriminator);
+ res = 0;
+ }
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Event field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Event field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Event field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Event has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI Event missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI Event missing required field application\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_event_fn(void)
+{
+ return ast_ari_validate_event;
+}
+
+int ast_ari_validate_message(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ const char *discriminator;
+
+ discriminator = ast_json_string_get(ast_json_object_get(json, "type"));
+ if (!discriminator) {
+ ast_log(LOG_ERROR, "ARI Message missing required field type");
+ return 0;
+ }
+
+ if (strcmp("Message", discriminator) == 0) {
+ /* Self type; fall through */
+ } else
+ if (strcmp("ApplicationReplaced", discriminator) == 0) {
+ return ast_ari_validate_application_replaced(json);
+ } else
+ if (strcmp("BridgeCreated", discriminator) == 0) {
+ return ast_ari_validate_bridge_created(json);
+ } else
+ if (strcmp("BridgeDestroyed", discriminator) == 0) {
+ return ast_ari_validate_bridge_destroyed(json);
+ } else
+ if (strcmp("BridgeMerged", discriminator) == 0) {
+ return ast_ari_validate_bridge_merged(json);
+ } else
+ if (strcmp("ChannelCallerId", discriminator) == 0) {
+ return ast_ari_validate_channel_caller_id(json);
+ } else
+ if (strcmp("ChannelCreated", discriminator) == 0) {
+ return ast_ari_validate_channel_created(json);
+ } else
+ if (strcmp("ChannelDestroyed", discriminator) == 0) {
+ return ast_ari_validate_channel_destroyed(json);
+ } else
+ if (strcmp("ChannelDialplan", discriminator) == 0) {
+ return ast_ari_validate_channel_dialplan(json);
+ } else
+ if (strcmp("ChannelDtmfReceived", discriminator) == 0) {
+ return ast_ari_validate_channel_dtmf_received(json);
+ } else
+ if (strcmp("ChannelEnteredBridge", discriminator) == 0) {
+ return ast_ari_validate_channel_entered_bridge(json);
+ } else
+ if (strcmp("ChannelHangupRequest", discriminator) == 0) {
+ return ast_ari_validate_channel_hangup_request(json);
+ } else
+ if (strcmp("ChannelLeftBridge", discriminator) == 0) {
+ return ast_ari_validate_channel_left_bridge(json);
+ } else
+ if (strcmp("ChannelStateChange", discriminator) == 0) {
+ return ast_ari_validate_channel_state_change(json);
+ } else
+ if (strcmp("ChannelUserevent", discriminator) == 0) {
+ return ast_ari_validate_channel_userevent(json);
+ } else
+ if (strcmp("ChannelVarset", discriminator) == 0) {
+ return ast_ari_validate_channel_varset(json);
+ } else
+ if (strcmp("Event", discriminator) == 0) {
+ return ast_ari_validate_event(json);
+ } else
+ if (strcmp("MissingParams", discriminator) == 0) {
+ return ast_ari_validate_missing_params(json);
+ } else
+ if (strcmp("PlaybackFinished", discriminator) == 0) {
+ return ast_ari_validate_playback_finished(json);
+ } else
+ if (strcmp("PlaybackStarted", discriminator) == 0) {
+ return ast_ari_validate_playback_started(json);
+ } else
+ if (strcmp("StasisEnd", discriminator) == 0) {
+ return ast_ari_validate_stasis_end(json);
+ } else
+ if (strcmp("StasisStart", discriminator) == 0) {
+ return ast_ari_validate_stasis_start(json);
+ } else
+ {
+ ast_log(LOG_ERROR, "ARI Message has undocumented subtype %s\n",
+ discriminator);
+ res = 0;
+ }
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI Message field type failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI Message has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI Message missing required field type\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_message_fn(void)
+{
+ return ast_ari_validate_message;
+}
+
+int ast_ari_validate_missing_params(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_params = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI MissingParams field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("params", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_params = 1;
+ prop_is_valid = ast_ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ast_ari_validate_string);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI MissingParams field params failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI MissingParams has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI MissingParams missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_params) {
+ ast_log(LOG_ERROR, "ARI MissingParams missing required field params\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_missing_params_fn(void)
+{
+ return ast_ari_validate_missing_params;
+}
+
+int ast_ari_validate_playback_finished(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_playback = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("playback", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_playback = 1;
+ prop_is_valid = ast_ari_validate_playback(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished field playback failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI PlaybackFinished has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_playback) {
+ ast_log(LOG_ERROR, "ARI PlaybackFinished missing required field playback\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_playback_finished_fn(void)
+{
+ return ast_ari_validate_playback_finished;
+}
+
+int ast_ari_validate_playback_started(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_playback = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("playback", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_playback = 1;
+ prop_is_valid = ast_ari_validate_playback(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted field playback failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI PlaybackStarted has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_playback) {
+ ast_log(LOG_ERROR, "ARI PlaybackStarted missing required field playback\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_playback_started_fn(void)
+{
+ return ast_ari_validate_playback_started;
+}
+
+int ast_ari_validate_stasis_end(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisEnd field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisEnd field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisEnd field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisEnd field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI StasisEnd has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI StasisEnd missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI StasisEnd missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI StasisEnd missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_stasis_end_fn(void)
+{
+ return ast_ari_validate_stasis_end;
+}
+
+int ast_ari_validate_stasis_start(struct ast_json *json)
+{
+ int res = 1;
+ struct ast_json_iter *iter;
+ int has_type = 0;
+ int has_application = 0;
+ int has_args = 0;
+ int has_channel = 0;
+
+ for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
+ if (strcmp("type", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_type = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field type failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("application", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_application = 1;
+ prop_is_valid = ast_ari_validate_string(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field application failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("timestamp", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ prop_is_valid = ast_ari_validate_date(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field timestamp failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("args", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_args = 1;
+ prop_is_valid = ast_ari_validate_list(
+ ast_json_object_iter_value(iter),
+ ast_ari_validate_string);
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field args failed validation\n");
+ res = 0;
+ }
+ } else
+ if (strcmp("channel", ast_json_object_iter_key(iter)) == 0) {
+ int prop_is_valid;
+ has_channel = 1;
+ prop_is_valid = ast_ari_validate_channel(
+ ast_json_object_iter_value(iter));
+ if (!prop_is_valid) {
+ ast_log(LOG_ERROR, "ARI StasisStart field channel failed validation\n");
+ res = 0;
+ }
+ } else
+ {
+ ast_log(LOG_ERROR,
+ "ARI StasisStart has undocumented field %s\n",
+ ast_json_object_iter_key(iter));
+ res = 0;
+ }
+ }
+
+ if (!has_type) {
+ ast_log(LOG_ERROR, "ARI StasisStart missing required field type\n");
+ res = 0;
+ }
+
+ if (!has_application) {
+ ast_log(LOG_ERROR, "ARI StasisStart missing required field application\n");
+ res = 0;
+ }
+
+ if (!has_args) {
+ ast_log(LOG_ERROR, "ARI StasisStart missing required field args\n");
+ res = 0;
+ }
+
+ if (!has_channel) {
+ ast_log(LOG_ERROR, "ARI StasisStart missing required field channel\n");
+ res = 0;
+ }
+
+ return res;
+}
+
+ari_validator ast_ari_validate_stasis_start_fn(void)
+{
+ return ast_ari_validate_stasis_start;
+}
diff --git a/res/ari/ari_model_validators.h b/res/ari/ari_model_validators.h
new file mode 100644
index 000000000..c5e74d21a
--- /dev/null
+++ b/res/ari/ari_model_validators.h
@@ -0,0 +1,962 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - Build validators for ARI model objects.
+ *
+ * In addition to the normal validation functions one would normally expect,
+ * each validator has a ast_ari_validate_{id}_fn() companion function that returns
+ * the validator's function pointer.
+ *
+ * The reason for this seamingly useless indirection is the way function
+ * pointers interfere with module loading. Asterisk attempts to dlopen() each
+ * module using \c RTLD_LAZY in order to read some metadata from the module.
+ * Unfortunately, if you take the address of a function, the function has to be
+ * resolvable at load time, even if \c RTLD_LAZY is specified. By moving the
+ * function-address-taking into this module, we can once again be lazy.
+ */
+
+ /*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_model_validators.h.mustache
+ */
+
+#ifndef _ASTERISK_ARI_MODEL_H
+#define _ASTERISK_ARI_MODEL_H
+
+#include "asterisk/json.h"
+
+/*! @{ */
+
+/*!
+ * \brief Validator for native Swagger void.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_void(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger byte.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_byte(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger boolean.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_boolean(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger int.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_int(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger long.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_long(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger float.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_float(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger double.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_double(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger string.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_string(struct ast_json *json);
+
+/*!
+ * \brief Validator for native Swagger date.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_date(struct ast_json *json);
+
+/*!
+ * \brief Validator for a Swagger List[]/JSON array.
+ *
+ * \param json JSON object to validate.
+ * \param fn Validator to call on every element in the array.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_list(struct ast_json *json, int (*fn)(struct ast_json *));
+
+/*! @} */
+
+/*!
+ * \brief Function type for validator functions. Allows for
+ */
+typedef int (*ari_validator)(struct ast_json *json);
+
+/*!
+ * \brief Validator for AsteriskInfo.
+ *
+ * Asterisk system information
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_asterisk_info(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_asterisk_info().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_asterisk_info_fn(void);
+
+/*!
+ * \brief Validator for Variable.
+ *
+ * The value of a channel variable
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_variable(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_variable().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_variable_fn(void);
+
+/*!
+ * \brief Validator for Endpoint.
+ *
+ * An external device that may offer/accept calls to/from Asterisk.
+ *
+ * Unlike most resources, which have a single unique identifier, an endpoint is uniquely identified by the technology/resource pair.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_endpoint(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_endpoint().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_endpoint_fn(void);
+
+/*!
+ * \brief Validator for CallerID.
+ *
+ * Caller identification
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_caller_id(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_caller_id().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_caller_id_fn(void);
+
+/*!
+ * \brief Validator for Channel.
+ *
+ * A specific communication connection between Asterisk and an Endpoint.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_fn(void);
+
+/*!
+ * \brief Validator for Dialed.
+ *
+ * Dialed channel information.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_dialed(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_dialed().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_dialed_fn(void);
+
+/*!
+ * \brief Validator for DialplanCEP.
+ *
+ * Dialplan location (context/extension/priority)
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_dialplan_cep(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_dialplan_cep().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_dialplan_cep_fn(void);
+
+/*!
+ * \brief Validator for Bridge.
+ *
+ * The merging of media from one or more channels.
+ *
+ * Everyone on the bridge receives the same audio.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_bridge(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_bridge().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_bridge_fn(void);
+
+/*!
+ * \brief Validator for LiveRecording.
+ *
+ * A recording that is in progress
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_live_recording(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_live_recording().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_live_recording_fn(void);
+
+/*!
+ * \brief Validator for StoredRecording.
+ *
+ * A past recording that may be played back.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_stored_recording(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_stored_recording().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_stored_recording_fn(void);
+
+/*!
+ * \brief Validator for FormatLangPair.
+ *
+ * Identifies the format and language of a sound file
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_format_lang_pair(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_format_lang_pair().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_format_lang_pair_fn(void);
+
+/*!
+ * \brief Validator for Sound.
+ *
+ * A media file that may be played back.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_sound(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_sound().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_sound_fn(void);
+
+/*!
+ * \brief Validator for Playback.
+ *
+ * Object representing the playback of media to a channel
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_playback(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_playback().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_playback_fn(void);
+
+/*!
+ * \brief Validator for ApplicationReplaced.
+ *
+ * Notification that another WebSocket has taken over for an application.
+ *
+ * An application may only be subscribed to by a single WebSocket at a time. If multiple WebSockets attempt to subscribe to the same application, the newer WebSocket wins, and the older one receives this event.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_application_replaced(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_application_replaced().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_application_replaced_fn(void);
+
+/*!
+ * \brief Validator for BridgeCreated.
+ *
+ * Notification that a bridge has been created.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_bridge_created(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_bridge_created().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_bridge_created_fn(void);
+
+/*!
+ * \brief Validator for BridgeDestroyed.
+ *
+ * Notification that a bridge has been destroyed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_bridge_destroyed(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_bridge_destroyed().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_bridge_destroyed_fn(void);
+
+/*!
+ * \brief Validator for BridgeMerged.
+ *
+ * Notification that one bridge has merged into another.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_bridge_merged(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_bridge_merged().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_bridge_merged_fn(void);
+
+/*!
+ * \brief Validator for ChannelCallerId.
+ *
+ * Channel changed Caller ID.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_caller_id(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_caller_id().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_caller_id_fn(void);
+
+/*!
+ * \brief Validator for ChannelCreated.
+ *
+ * Notification that a channel has been created.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_created(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_created().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_created_fn(void);
+
+/*!
+ * \brief Validator for ChannelDestroyed.
+ *
+ * Notification that a channel has been destroyed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_destroyed(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_destroyed().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_destroyed_fn(void);
+
+/*!
+ * \brief Validator for ChannelDialplan.
+ *
+ * Channel changed location in the dialplan.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_dialplan(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_dialplan().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_dialplan_fn(void);
+
+/*!
+ * \brief Validator for ChannelDtmfReceived.
+ *
+ * DTMF received on a channel.
+ *
+ * This event is sent when the DTMF ends. There is no notification about the start of DTMF
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_dtmf_received(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_dtmf_received().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_dtmf_received_fn(void);
+
+/*!
+ * \brief Validator for ChannelEnteredBridge.
+ *
+ * Notification that a channel has entered a bridge.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_entered_bridge(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_entered_bridge().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_entered_bridge_fn(void);
+
+/*!
+ * \brief Validator for ChannelHangupRequest.
+ *
+ * A hangup was requested on the channel.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_hangup_request(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_hangup_request().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_hangup_request_fn(void);
+
+/*!
+ * \brief Validator for ChannelLeftBridge.
+ *
+ * Notification that a channel has left a bridge.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_left_bridge(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_left_bridge().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_left_bridge_fn(void);
+
+/*!
+ * \brief Validator for ChannelStateChange.
+ *
+ * Notification of a channel's state change.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_state_change(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_state_change().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_state_change_fn(void);
+
+/*!
+ * \brief Validator for ChannelUserevent.
+ *
+ * User-generated event with additional user-defined fields in the object.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_userevent(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_userevent().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_userevent_fn(void);
+
+/*!
+ * \brief Validator for ChannelVarset.
+ *
+ * Channel variable changed.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_channel_varset(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_channel_varset().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_channel_varset_fn(void);
+
+/*!
+ * \brief Validator for Event.
+ *
+ * Base type for asynchronous events from Asterisk.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_event(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_event().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_event_fn(void);
+
+/*!
+ * \brief Validator for Message.
+ *
+ * Base type for errors and events
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_message(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_message().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_message_fn(void);
+
+/*!
+ * \brief Validator for MissingParams.
+ *
+ * Error event sent when required params are missing.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_missing_params(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_missing_params().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_missing_params_fn(void);
+
+/*!
+ * \brief Validator for PlaybackFinished.
+ *
+ * Event showing the completion of a media playback operation.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_playback_finished(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_playback_finished().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_playback_finished_fn(void);
+
+/*!
+ * \brief Validator for PlaybackStarted.
+ *
+ * Event showing the start of a media playback operation.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_playback_started(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_playback_started().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_playback_started_fn(void);
+
+/*!
+ * \brief Validator for StasisEnd.
+ *
+ * Notification that a channel has left a Stasis appliction.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_stasis_end(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_stasis_end().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_stasis_end_fn(void);
+
+/*!
+ * \brief Validator for StasisStart.
+ *
+ * Notification that a channel has entered a Stasis appliction.
+ *
+ * \param json JSON object to validate.
+ * \returns True (non-zero) if valid.
+ * \returns False (zero) if invalid.
+ */
+int ast_ari_validate_stasis_start(struct ast_json *json);
+
+/*!
+ * \brief Function pointer to ast_ari_validate_stasis_start().
+ *
+ * See \ref ast_ari_model_validators.h for more details.
+ */
+ari_validator ast_ari_validate_stasis_start_fn(void);
+
+/*
+ * JSON models
+ *
+ * AsteriskInfo
+ * Variable
+ * - value: string (required)
+ * Endpoint
+ * - channel_ids: List[string] (required)
+ * - resource: string (required)
+ * - state: string
+ * - technology: string (required)
+ * CallerID
+ * - name: string (required)
+ * - number: string (required)
+ * Channel
+ * - accountcode: string (required)
+ * - caller: CallerID (required)
+ * - connected: CallerID (required)
+ * - creationtime: Date (required)
+ * - dialplan: DialplanCEP (required)
+ * - id: string (required)
+ * - name: string (required)
+ * - state: string (required)
+ * Dialed
+ * DialplanCEP
+ * - context: string (required)
+ * - exten: string (required)
+ * - priority: long (required)
+ * Bridge
+ * - bridge_class: string (required)
+ * - bridge_type: string (required)
+ * - channels: List[string] (required)
+ * - id: string (required)
+ * - technology: string (required)
+ * LiveRecording
+ * - format: string (required)
+ * - name: string (required)
+ * - state: string (required)
+ * StoredRecording
+ * - duration_seconds: int
+ * - formats: List[string] (required)
+ * - id: string (required)
+ * - time: Date
+ * FormatLangPair
+ * - format: string (required)
+ * - language: string (required)
+ * Sound
+ * - formats: List[FormatLangPair] (required)
+ * - id: string (required)
+ * - text: string
+ * Playback
+ * - id: string (required)
+ * - language: string
+ * - media_uri: string (required)
+ * - state: string (required)
+ * - target_uri: string (required)
+ * ApplicationReplaced
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * BridgeCreated
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - bridge: Bridge (required)
+ * BridgeDestroyed
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - bridge: Bridge (required)
+ * BridgeMerged
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - bridge: Bridge (required)
+ * - bridge_from: Bridge (required)
+ * ChannelCallerId
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - caller_presentation: int (required)
+ * - caller_presentation_txt: string (required)
+ * - channel: Channel (required)
+ * ChannelCreated
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - channel: Channel (required)
+ * ChannelDestroyed
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - cause: int (required)
+ * - cause_txt: string (required)
+ * - channel: Channel (required)
+ * ChannelDialplan
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - channel: Channel (required)
+ * - dialplan_app: string (required)
+ * - dialplan_app_data: string (required)
+ * ChannelDtmfReceived
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - channel: Channel (required)
+ * - digit: string (required)
+ * - duration_ms: int (required)
+ * ChannelEnteredBridge
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - bridge: Bridge (required)
+ * - channel: Channel
+ * ChannelHangupRequest
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - cause: int
+ * - channel: Channel (required)
+ * - soft: boolean
+ * ChannelLeftBridge
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - bridge: Bridge (required)
+ * - channel: Channel (required)
+ * ChannelStateChange
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - channel: Channel (required)
+ * ChannelUserevent
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - channel: Channel (required)
+ * - eventname: string (required)
+ * ChannelVarset
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - channel: Channel
+ * - value: string (required)
+ * - variable: string (required)
+ * Event
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * Message
+ * - type: string (required)
+ * MissingParams
+ * - type: string (required)
+ * - params: List[string] (required)
+ * PlaybackFinished
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - playback: Playback (required)
+ * PlaybackStarted
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - playback: Playback (required)
+ * StasisEnd
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - channel: Channel (required)
+ * StasisStart
+ * - type: string (required)
+ * - application: string (required)
+ * - timestamp: Date
+ * - args: List[string] (required)
+ * - channel: Channel (required)
+ */
+
+#endif /* _ASTERISK_ARI_MODEL_H */
diff --git a/res/ari/ari_websockets.c b/res/ari/ari_websockets.c
new file mode 100644
index 000000000..13650c293
--- /dev/null
+++ b/res/ari/ari_websockets.c
@@ -0,0 +1,165 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/astobj2.h"
+#include "asterisk/ari.h"
+
+/*! \file
+ *
+ * \brief WebSocket support for RESTful API's.
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+struct ast_ari_websocket_session {
+ struct ast_websocket *ws_session;
+ int (*validator)(struct ast_json *);
+};
+
+static void websocket_session_dtor(void *obj)
+{
+ struct ast_ari_websocket_session *session = obj;
+
+ ast_websocket_unref(session->ws_session);
+ session->ws_session = NULL;
+}
+
+/*!
+ * \brief Validator that always succeeds.
+ */
+static int null_validator(struct ast_json *json)
+{
+ return 1;
+}
+
+struct ast_ari_websocket_session *ast_ari_websocket_session_create(
+ struct ast_websocket *ws_session, int (*validator)(struct ast_json *))
+{
+ RAII_VAR(struct ast_ari_websocket_session *, session, NULL, ao2_cleanup);
+
+ if (ws_session == NULL) {
+ return NULL;
+ }
+
+ if (validator == NULL) {
+ validator = null_validator;
+ }
+
+ if (ast_websocket_set_nonblock(ws_session) != 0) {
+ ast_log(LOG_ERROR,
+ "ARI web socket failed to set nonblock; closing: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+
+ session = ao2_alloc(sizeof(*session), websocket_session_dtor);
+ if (!session) {
+ return NULL;
+ }
+
+ ao2_ref(ws_session, +1);
+ session->ws_session = ws_session;
+ session->validator = validator;
+
+ ao2_ref(session, +1);
+ return session;
+}
+
+struct ast_json *ast_ari_websocket_session_read(
+ struct ast_ari_websocket_session *session)
+{
+ RAII_VAR(struct ast_json *, message, NULL, ast_json_unref);
+
+ while (!message) {
+ int res;
+ char *payload;
+ uint64_t payload_len;
+ enum ast_websocket_opcode opcode;
+ int fragmented;
+
+ res = ast_wait_for_input(
+ ast_websocket_fd(session->ws_session), -1);
+
+ if (res <= 0) {
+ ast_log(LOG_WARNING, "WebSocket poll error: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+
+ res = ast_websocket_read(session->ws_session, &payload,
+ &payload_len, &opcode, &fragmented);
+
+ if (res != 0) {
+ ast_log(LOG_WARNING, "WebSocket read error: %s\n",
+ strerror(errno));
+ return NULL;
+ }
+
+ switch (opcode) {
+ case AST_WEBSOCKET_OPCODE_CLOSE:
+ ast_debug(1, "WebSocket closed by peer\n");
+ return NULL;
+ case AST_WEBSOCKET_OPCODE_TEXT:
+ message = ast_json_load_buf(payload, payload_len, NULL);
+ if (message == NULL) {
+ ast_log(LOG_WARNING,
+ "WebSocket input failed to parse\n");
+ }
+ break;
+ default:
+ /* Ignore all other message types */
+ break;
+ }
+ }
+
+ return ast_json_ref(message);
+}
+
+#define VALIDATION_FAILED \
+ "{" \
+ " \"error\": \"InvalidMessage\"," \
+ " \"message\": \"Message validation failed\"" \
+ "}"
+
+int ast_ari_websocket_session_write(struct ast_ari_websocket_session *session,
+ struct ast_json *message)
+{
+ RAII_VAR(char *, str, NULL, ast_free);
+
+#ifdef AST_DEVMODE
+ if (!session->validator(message)) {
+ ast_log(LOG_ERROR, "Outgoing message failed validation\n");
+ return ast_websocket_write(session->ws_session,
+ AST_WEBSOCKET_OPCODE_TEXT, VALIDATION_FAILED,
+ strlen(VALIDATION_FAILED));
+ }
+#endif
+
+ str = ast_json_dump_string_format(message, ast_ari_json_format());
+
+ if (str == NULL) {
+ ast_log(LOG_ERROR, "Failed to encode JSON object\n");
+ return -1;
+ }
+
+ return ast_websocket_write(session->ws_session,
+ AST_WEBSOCKET_OPCODE_TEXT, str, strlen(str));
+}
diff --git a/res/ari/cli.c b/res/ari/cli.c
new file mode 100644
index 000000000..819407997
--- /dev/null
+++ b/res/ari/cli.c
@@ -0,0 +1,267 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Command line for ARI.
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/astobj2.h"
+#include "asterisk/cli.h"
+#include "internal.h"
+
+static char *ari_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari show status";
+ e->usage =
+ "Usage: ari show status\n"
+ " Shows all ARI settings\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ default:
+ break;
+ }
+
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+
+ conf = ast_ari_config_get();
+
+ if (!conf) {
+ ast_cli(a->fd, "Error getting ARI configuration\n");
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, "ARI Status:\n");
+ ast_cli(a->fd, "Enabled: %s\n", AST_CLI_YESNO(conf->general->enabled));
+ ast_cli(a->fd, "Output format: ");
+ switch (conf->general->format) {
+ case AST_JSON_COMPACT:
+ ast_cli(a->fd, "compact");
+ break;
+ case AST_JSON_PRETTY:
+ ast_cli(a->fd, "pretty");
+ break;
+ }
+ ast_cli(a->fd, "\n");
+ ast_cli(a->fd, "Auth realm: %s\n", conf->general->auth_realm);
+ ast_cli(a->fd, "Allowed Origins: %s\n", conf->general->allowed_origins);
+ ast_cli(a->fd, "User count: %d\n", ao2_container_count(conf->users));
+ return CLI_SUCCESS;
+}
+
+static int show_users_cb(void *obj, void *arg, int flags)
+{
+ struct ast_ari_conf_user *user = obj;
+ struct ast_cli_args *a = arg;
+
+ ast_cli(a->fd, "%-4s %s\n",
+ AST_CLI_YESNO(user->read_only),
+ user->username);
+ return 0;
+}
+
+static char *ari_show_users(struct ast_cli_entry *e, int cmd,
+ struct ast_cli_args *a)
+{
+ RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari show users";
+ e->usage =
+ "Usage: ari show users\n"
+ " Shows all ARI users\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ default:
+ break;
+ }
+
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+
+ conf = ast_ari_config_get();
+ if (!conf) {
+ ast_cli(a->fd, "Error getting ARI configuration\n");
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, "r/o? Username\n");
+ ast_cli(a->fd, "---- --------\n");
+
+ ao2_callback(conf->users, OBJ_NODATA, show_users_cb, a);
+
+ return CLI_SUCCESS;
+}
+
+struct user_complete {
+ /*! Nth user to search for */
+ int state;
+ /*! Which user currently on */
+ int which;
+};
+
+static int complete_ari_user_search(void *obj, void *arg, void *data, int flags)
+{
+ struct user_complete *search = data;
+
+ if (++search->which > search->state) {
+ return CMP_MATCH;
+ }
+ return 0;
+}
+
+static char *complete_ari_user(struct ast_cli_args *a)
+{
+ RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
+
+ struct user_complete search = {
+ .state = a->n,
+ };
+
+ conf = ast_ari_config_get();
+ if (!conf) {
+ ast_cli(a->fd, "Error getting ARI configuration\n");
+ return CLI_FAILURE;
+ }
+
+ user = ao2_callback_data(conf->users,
+ ast_strlen_zero(a->word) ? 0 : OBJ_PARTIAL_KEY,
+ complete_ari_user_search, (char*)a->word, &search);
+
+ return user ? ast_strdup(user->username) : NULL;
+}
+
+static char *complete_ari_show_user(struct ast_cli_args *a)
+{
+ if (a->pos == 3) {
+ return complete_ari_user(a);
+ }
+
+ return NULL;
+}
+
+static char *ari_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari show user";
+ e->usage =
+ "Usage: ari show user <username>\n"
+ " Shows a specific ARI user\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_ari_show_user(a);
+ default:
+ break;
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ conf = ast_ari_config_get();
+
+ if (!conf) {
+ ast_cli(a->fd, "Error getting ARI configuration\n");
+ return CLI_FAILURE;
+ }
+
+ user = ao2_find(conf->users, a->argv[3], OBJ_KEY);
+ if (!user) {
+ ast_cli(a->fd, "User '%s' not found\n", a->argv[3]);
+ return CLI_SUCCESS;
+ }
+
+ ast_cli(a->fd, "Username: %s\n", user->username);
+ ast_cli(a->fd, "Read only?: %s\n", AST_CLI_YESNO(user->read_only));
+
+ return CLI_SUCCESS;
+}
+
+static char *ari_mkpasswd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ RAII_VAR(char *, crypted, NULL, ast_free);
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari mkpasswd";
+ e->usage =
+ "Usage: ari mkpasswd <password>\n"
+ " Encrypts a password for use in ari.conf\n"
+ " Be aware that the password will be shown in the\n"
+ " command line history. The mkpasswd shell command\n"
+ " may be preferable.\n"
+ ;
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ default:
+ break;
+ }
+
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+
+ crypted = ast_crypt_encrypt(a->argv[2]);
+ if (!crypted) {
+ ast_cli(a->fd, "Failed to encrypt password\n");
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd,
+ "; Copy the following two lines into ari.conf\n");
+ ast_cli(a->fd, "password_format = crypt\n");
+ ast_cli(a->fd, "password = %s\n", crypted);
+
+ return CLI_SUCCESS;
+}
+
+static struct ast_cli_entry cli_ari[] = {
+ AST_CLI_DEFINE(ari_show, "Show ARI settings"),
+ AST_CLI_DEFINE(ari_show_users, "List ARI users"),
+ AST_CLI_DEFINE(ari_show_user, "List single ARI user"),
+ AST_CLI_DEFINE(ari_mkpasswd, "Encrypts a password"),
+};
+
+int ast_ari_cli_register(void) {
+ return ast_cli_register_multiple(cli_ari, ARRAY_LEN(cli_ari));
+}
+
+void ast_ari_cli_unregister(void) {
+ ast_cli_unregister_multiple(cli_ari, ARRAY_LEN(cli_ari));
+}
diff --git a/res/ari/config.c b/res/ari/config.c
new file mode 100644
index 000000000..e25fa8ad1
--- /dev/null
+++ b/res/ari/config.c
@@ -0,0 +1,345 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Config framework stuffz for ARI.
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/config_options.h"
+#include "internal.h"
+
+/*! \brief Locking container for safe configuration access. */
+static AO2_GLOBAL_OBJ_STATIC(confs);
+
+/*! \brief Mapping of the ARI conf struct's globals to the
+ * general context in the config file. */
+static struct aco_type general_option = {
+ .type = ACO_GLOBAL,
+ .name = "general",
+ .item_offset = offsetof(struct ast_ari_conf, general),
+ .category = "^general$",
+ .category_match = ACO_WHITELIST,
+};
+
+static struct aco_type *general_options[] = ACO_TYPES(&general_option);
+
+/*! \brief Encoding format handler converts from boolean to enum. */
+static int encoding_format_handler(const struct aco_option *opt,
+ struct ast_variable *var, void *obj)
+{
+ struct ast_ari_conf_general *general = obj;
+
+ if (!strcasecmp(var->name, "pretty")) {
+ general->format = ast_true(var->value) ?
+ AST_JSON_PRETTY : AST_JSON_COMPACT;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*! \brief Parses the ast_ari_password_format enum from a config file */
+static int password_format_handler(const struct aco_option *opt,
+ struct ast_variable *var, void *obj)
+{
+ struct ast_ari_conf_user *user = obj;
+
+ if (strcasecmp(var->value, "plain") == 0) {
+ user->password_format = ARI_PASSWORD_FORMAT_PLAIN;
+ } else if (strcasecmp(var->value, "crypt") == 0) {
+ user->password_format = ARI_PASSWORD_FORMAT_CRYPT;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*! \brief Destructor for \ref ast_ari_conf_user */
+static void user_dtor(void *obj)
+{
+ struct ast_ari_conf_user *user = obj;
+ ast_debug(3, "Disposing of user %s\n", user->username);
+ ast_free(user->username);
+}
+
+/*! \brief Allocate an \ref ast_ari_conf_user for config parsing */
+static void *user_alloc(const char *cat)
+{
+ RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
+
+ if (!cat) {
+ return NULL;
+ }
+
+ ast_debug(3, "Allocating user %s\n", cat);
+
+ user = ao2_alloc_options(sizeof(*user), user_dtor,
+ AO2_ALLOC_OPT_LOCK_NOLOCK);
+ if (!user) {
+ return NULL;
+ }
+
+ user->username = ast_strdup(cat);
+ if (!user->username) {
+ return NULL;
+ }
+
+ ao2_ref(user, +1);
+ return user;
+}
+
+/*! \brief Sorting function for use with red/black tree */
+static int user_sort_cmp(const void *obj_left, const void *obj_right, int flags)
+{
+ const struct ast_ari_conf_user *user_left = obj_left;
+
+ if (flags & OBJ_PARTIAL_KEY) {
+ const char *key_right = obj_right;
+ return strncasecmp(user_left->username, key_right,
+ strlen(key_right));
+ } else if (flags & OBJ_KEY) {
+ const char *key_right = obj_right;
+ return strcasecmp(user_left->username, key_right);
+ } else {
+ const struct ast_ari_conf_user *user_right = obj_right;
+ const char *key_right = user_right->username;
+ return strcasecmp(user_left->username, key_right);
+ }
+}
+
+/*! \brief \ref aco_type item_find function */
+static void *user_find(struct ao2_container *tmp_container, const char *cat)
+{
+ if (!cat) {
+ return NULL;
+ }
+
+ return ao2_find(tmp_container, cat, OBJ_KEY);
+}
+
+static struct aco_type user_option = {
+ .type = ACO_ITEM,
+ .name = "user",
+ .category_match = ACO_BLACKLIST,
+ .category = "^general$",
+ .matchfield = "type",
+ .matchvalue = "user",
+ .item_alloc = user_alloc,
+ .item_find = user_find,
+ .item_offset = offsetof(struct ast_ari_conf, users),
+};
+
+static struct aco_type *user[] = ACO_TYPES(&user_option);
+
+/*! \brief \ref ast_ari_conf destructor. */
+static void conf_destructor(void *obj)
+{
+ struct ast_ari_conf *cfg = obj;
+
+ ast_string_field_free_memory(cfg->general);
+
+ ao2_cleanup(cfg->general);
+ ao2_cleanup(cfg->users);
+}
+
+/*! \brief Allocate an \ref ast_ari_conf for config parsing */
+static void *conf_alloc(void)
+{
+ RAII_VAR(struct ast_ari_conf *, cfg, NULL, ao2_cleanup);
+
+ cfg = ao2_alloc_options(sizeof(*cfg), conf_destructor,
+ AO2_ALLOC_OPT_LOCK_NOLOCK);
+ if (!cfg) {
+ return NULL;
+ }
+
+ cfg->general = ao2_alloc_options(sizeof(*cfg->general), NULL,
+ AO2_ALLOC_OPT_LOCK_NOLOCK);
+ if (!cfg->general) {
+ return NULL;
+ }
+ aco_set_defaults(&general_option, "general", cfg->general);
+
+ if (ast_string_field_init(cfg->general, 64)) {
+ return NULL;
+ }
+
+ cfg->users = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
+ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, user_sort_cmp, NULL);
+
+ ao2_ref(cfg, +1);
+ return cfg;
+}
+
+#define CONF_FILENAME "ari.conf"
+
+/*! \brief The conf file that's processed for the module. */
+static struct aco_file conf_file = {
+ /*! The config file name. */
+ .filename = CONF_FILENAME,
+ /*! The mapping object types to be processed. */
+ .types = ACO_TYPES(&general_option, &user_option),
+};
+
+CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,
+ .files = ACO_FILES(&conf_file));
+
+struct ast_ari_conf *ast_ari_config_get(void)
+{
+ struct ast_ari_conf *res = ao2_global_obj_ref(confs);
+ if (!res) {
+ ast_log(LOG_ERROR,
+ "Error obtaining config from " CONF_FILENAME "\n");
+ }
+ return res;
+}
+
+struct ast_ari_conf_user *ast_ari_config_validate_user(const char *username,
+ const char *password)
+{
+ RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_ari_conf_user *, user, NULL, ao2_cleanup);
+ int is_valid = 0;
+
+ conf = ast_ari_config_get();
+ if (!conf) {
+ return NULL;
+ }
+
+ user = ao2_find(conf->users, username, OBJ_KEY);
+ if (!user) {
+ return NULL;
+ }
+
+ if (ast_strlen_zero(user->password)) {
+ ast_log(LOG_WARNING,
+ "User '%s' missing password; authentication failed\n",
+ user->username);
+ return NULL;
+ }
+
+ switch (user->password_format) {
+ case ARI_PASSWORD_FORMAT_PLAIN:
+ is_valid = strcmp(password, user->password) == 0;
+ break;
+ case ARI_PASSWORD_FORMAT_CRYPT:
+ is_valid = ast_crypt_validate(password, user->password);
+ break;
+ }
+
+ if (!is_valid) {
+ return NULL;
+ }
+
+ ao2_ref(user, +1);
+ return user;
+}
+
+/*! \brief Callback to validate a user object */
+static int validate_user_cb(void *obj, void *arg, int flags)
+{
+ struct ast_ari_conf_user *user = obj;
+
+ if (ast_strlen_zero(user->password)) {
+ ast_log(LOG_WARNING, "User '%s' missing password\n",
+ user->username);
+ }
+
+ return 0;
+}
+
+/*! \brief Load (or reload) configuration. */
+static int process_config(int reload)
+{
+ RAII_VAR(struct ast_ari_conf *, conf, NULL, ao2_cleanup);
+
+ switch (aco_process_config(&cfg_info, reload)) {
+ case ACO_PROCESS_ERROR:
+ return -1;
+ case ACO_PROCESS_OK:
+ case ACO_PROCESS_UNCHANGED:
+ break;
+ }
+
+ conf = ast_ari_config_get();
+ if (!conf) {
+ ast_assert(0); /* We just configured; it should be there */
+ return -1;
+ }
+
+ if (ao2_container_count(conf->users) == 0) {
+ ast_log(LOG_ERROR, "No configured users for ARI\n");
+ }
+
+ ao2_callback(conf->users, OBJ_NODATA, validate_user_cb, NULL);
+
+ return 0;
+}
+
+int ast_ari_config_init(void)
+{
+ if (aco_info_init(&cfg_info)) {
+ aco_info_destroy(&cfg_info);
+ return -1;
+ }
+
+ aco_option_register(&cfg_info, "enabled", ACO_EXACT, general_options,
+ "yes", OPT_BOOL_T, 1,
+ FLDSET(struct ast_ari_conf_general, enabled));
+ aco_option_register_custom(&cfg_info, "pretty", ACO_EXACT,
+ general_options, "no", encoding_format_handler, 0);
+ aco_option_register(&cfg_info, "auth_realm", ACO_EXACT, general_options,
+ "Asterisk REST Interface", OPT_CHAR_ARRAY_T, 0,
+ FLDSET(struct ast_ari_conf_general, auth_realm),
+ ARI_AUTH_REALM_LEN);
+ aco_option_register(&cfg_info, "allowed_origins", ACO_EXACT, general_options,
+ "", OPT_STRINGFIELD_T, 0,
+ STRFLDSET(struct ast_ari_conf_general, allowed_origins));
+
+ aco_option_register(&cfg_info, "type", ACO_EXACT, user, NULL,
+ OPT_NOOP_T, 0, 0);
+ aco_option_register(&cfg_info, "read_only", ACO_EXACT, user,
+ "no", OPT_BOOL_T, 1,
+ FLDSET(struct ast_ari_conf_user, read_only));
+ aco_option_register(&cfg_info, "password", ACO_EXACT, user,
+ "", OPT_CHAR_ARRAY_T, 0,
+ FLDSET(struct ast_ari_conf_user, password), ARI_PASSWORD_LEN);
+ aco_option_register_custom(&cfg_info, "password_format", ACO_EXACT,
+ user, "plain", password_format_handler, 0);
+
+ return process_config(0);
+}
+
+int ast_ari_config_reload(void)
+{
+ return process_config(1);
+}
+
+void ast_ari_config_destroy(void)
+{
+ aco_info_destroy(&cfg_info);
+ ao2_global_obj_release(confs);
+}
diff --git a/res/ari/internal.h b/res/ari/internal.h
new file mode 100644
index 000000000..ffacd4939
--- /dev/null
+++ b/res/ari/internal.h
@@ -0,0 +1,143 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#ifndef ARI_INTERNAL_H_
+#define ARI_INTERNAL_H_
+
+/*! \file
+ *
+ * \brief Internal API's for res_ari.
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+#include "asterisk/json.h"
+
+/*! @{ */
+
+/*!
+ * \brief Register CLI commands for ARI.
+ *
+ * \return 0 on success.
+ * \return Non-zero on error.
+ */
+int ast_ari_cli_register(void);
+
+/*!
+ * \brief Unregister CLI commands for ARI.
+ */
+void ast_ari_cli_unregister(void);
+
+/*! @} */
+
+/*! @{ */
+
+struct ast_ari_conf_general;
+
+/*! \brief All configuration options for ARI. */
+struct ast_ari_conf {
+ /*! The general section configuration options. */
+ struct ast_ari_conf_general *general;
+ /*! Configured users */
+ struct ao2_container *users;
+};
+
+/*! Max length for auth_realm field */
+#define ARI_AUTH_REALM_LEN 80
+
+/*! \brief Global configuration options for ARI. */
+struct ast_ari_conf_general {
+ /*! Enabled by default, disabled if false. */
+ int enabled;
+ /*! Encoding format used during output (default compact). */
+ enum ast_json_encoding_format format;
+ /*! Authentication realm */
+ char auth_realm[ARI_AUTH_REALM_LEN];
+
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(allowed_origins);
+ );
+};
+
+/*! \brief Password format */
+enum ast_ari_password_format {
+ /*! \brief Plaintext password */
+ ARI_PASSWORD_FORMAT_PLAIN,
+ /*! crypt(3) password */
+ ARI_PASSWORD_FORMAT_CRYPT,
+};
+
+/*!
+ * \brief User's password mx length.
+ *
+ * If 256 seems like a lot, a crypt SHA-512 has over 106 characters.
+ */
+#define ARI_PASSWORD_LEN 256
+
+/*! \brief Per-user configuration options */
+struct ast_ari_conf_user {
+ /*! Username for authentication */
+ char *username;
+ /*! User's password. */
+ char password[ARI_PASSWORD_LEN];
+ /*! Format for the password field */
+ enum ast_ari_password_format password_format;
+ /*! If true, user cannot execute change operations */
+ int read_only;
+};
+
+/*!
+ * \brief Initialize the ARI configuration
+ */
+int ast_ari_config_init(void);
+
+/*!
+ * \brief Reload the ARI configuration
+ */
+int ast_ari_config_reload(void);
+
+/*!
+ * \brief Destroy the ARI configuration
+ */
+void ast_ari_config_destroy(void);
+
+/*!
+ * \brief Get the current ARI configuration.
+ *
+ * This is an immutable object, so don't modify it. It is AO2 managed, so
+ * ao2_cleanup() when you're done with it.
+ *
+ * \return ARI configuration object.
+ * \return \c NULL on error.
+ */
+struct ast_ari_conf *ast_ari_config_get(void);
+
+/*!
+ * \brief Validated a user's credentials.
+ *
+ * \param username Name of the user.
+ * \param password User's password.
+ * \return User object.
+ * \return \c NULL if username or password is invalid.
+ */
+struct ast_ari_conf_user *ast_ari_config_validate_user(const char *username,
+ const char *password);
+
+/*! @} */
+
+
+#endif /* ARI_INTERNAL_H_ */
diff --git a/res/ari/resource_asterisk.c b/res/ari/resource_asterisk.c
new file mode 100644
index 000000000..dac45714f
--- /dev/null
+++ b/res/ari/resource_asterisk.c
@@ -0,0 +1,80 @@
+/* -*- C -*-
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Implementation for ARI stubs.
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "resource_asterisk.h"
+#include "asterisk/pbx.h"
+
+void ast_ari_get_asterisk_info(struct ast_variable *headers, struct ast_get_asterisk_info_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ari_get_asterisk_info\n");
+}
+
+void ast_ari_get_global_var(struct ast_variable *headers, struct ast_get_global_var_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ RAII_VAR(struct ast_str *, tmp, ast_str_create(32), ast_free);
+
+ const char *value;
+
+ ast_assert(response != NULL);
+
+ if (!tmp) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ value = ast_str_retrieve_variable(&tmp, 0, NULL, NULL, args->variable);
+
+ if (!(json = ast_json_pack("{s: s}", "value", S_OR(value, "")))) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ ast_ari_response_ok(response, ast_json_ref(json));
+}
+
+void ast_ari_set_global_var(struct ast_variable *headers, struct ast_set_global_var_args *args, struct ast_ari_response *response)
+{
+ ast_assert(response != NULL);
+
+ if (ast_strlen_zero(args->variable)) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Variable name is required");
+ return;
+ }
+
+ pbx_builtin_setvar_helper(NULL, args->variable, args->value);
+
+ ast_ari_response_no_content(response);
+}
diff --git a/res/ari/resource_asterisk.h b/res/ari/resource_asterisk.h
new file mode 100644
index 000000000..69539525e
--- /dev/null
+++ b/res/ari/resource_asterisk.h
@@ -0,0 +1,84 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - declares stubs to be implemented in
+ * res/ari/resource_asterisk.c
+ *
+ * Asterisk resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_resource.h.mustache
+ */
+
+#ifndef _ASTERISK_RESOURCE_ASTERISK_H
+#define _ASTERISK_RESOURCE_ASTERISK_H
+
+#include "asterisk/ari.h"
+
+/*! \brief Argument struct for ast_ari_get_asterisk_info() */
+struct ast_get_asterisk_info_args {
+ /*! \brief Filter information returned */
+ const char *only;
+};
+/*!
+ * \brief Gets Asterisk system information.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_asterisk_info(struct ast_variable *headers, struct ast_get_asterisk_info_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_global_var() */
+struct ast_get_global_var_args {
+ /*! \brief The variable to get */
+ const char *variable;
+};
+/*!
+ * \brief Get the value of a global variable.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_global_var(struct ast_variable *headers, struct ast_get_global_var_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_set_global_var() */
+struct ast_set_global_var_args {
+ /*! \brief The variable to set */
+ const char *variable;
+ /*! \brief The value to set the variable to */
+ const char *value;
+};
+/*!
+ * \brief Set the value of a global variable.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_set_global_var(struct ast_variable *headers, struct ast_set_global_var_args *args, struct ast_ari_response *response);
+
+#endif /* _ASTERISK_RESOURCE_ASTERISK_H */
diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c
new file mode 100644
index 000000000..17a8bb132
--- /dev/null
+++ b/res/ari/resource_bridges.c
@@ -0,0 +1,514 @@
+/* -*- C -*-
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Implementation for ARI stubs.
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "resource_bridges.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_bridges.h"
+#include "asterisk/stasis_app.h"
+#include "asterisk/stasis_app_playback.h"
+#include "asterisk/stasis_app_recording.h"
+#include "asterisk/stasis_channels.h"
+#include "asterisk/core_unreal.h"
+#include "asterisk/channel.h"
+#include "asterisk/bridge.h"
+#include "asterisk/format_cap.h"
+#include "asterisk/file.h"
+
+/*!
+ * \brief Finds a bridge, filling the response with an error, if appropriate.
+ *
+ * \param[out] response Response to fill with an error if control is not found.
+ * \param bridge_id ID of the bridge to lookup.
+ *
+ * \return Bridget.
+ * \return \c NULL if bridge does not exist.
+ */
+static struct ast_bridge *find_bridge(
+ struct ast_ari_response *response,
+ const char *bridge_id)
+{
+ RAII_VAR(struct ast_bridge *, bridge, NULL, ao2_cleanup);
+
+ ast_assert(response != NULL);
+
+ bridge = stasis_app_bridge_find_by_id(bridge_id);
+ if (bridge == NULL) {
+ RAII_VAR(struct ast_bridge_snapshot *, snapshot,
+ ast_bridge_snapshot_get_latest(bridge_id), ao2_cleanup);
+ if (!snapshot) {
+ ast_ari_response_error(response, 404, "Not found",
+ "Bridge not found");
+ return NULL;
+ }
+
+ ast_ari_response_error(response, 409, "Conflict",
+ "Bridge not in Stasis application");
+ return NULL;
+ }
+
+ ao2_ref(bridge, +1);
+ return bridge;
+}
+
+/*!
+ * \brief Finds the control object for a channel, filling the response with an
+ * error, if appropriate.
+ * \param[out] response Response to fill with an error if control is not found.
+ * \param channel_id ID of the channel to lookup.
+ * \return Channel control object.
+ * \return \c NULL if control object does not exist.
+ */
+static struct stasis_app_control *find_channel_control(
+ struct ast_ari_response *response,
+ const char *channel_id)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+ ast_assert(response != NULL);
+
+ control = stasis_app_control_find_by_channel_id(channel_id);
+ if (control == NULL) {
+ ast_ari_response_error(response, 422, "Unprocessable Entity",
+ "Channel not in Stasis application");
+ return NULL;
+ }
+
+ ao2_ref(control, +1);
+ return control;
+}
+
+void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+ if (!bridge) {
+ return;
+ }
+
+ control = find_channel_control(response, args->channel);
+ if (!control) {
+ return;
+ }
+
+ stasis_app_control_add_channel_to_bridge(control, bridge);
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+ if (!bridge) {
+ return;
+ }
+
+ control = find_channel_control(response, args->channel);
+ if (!control) {
+ return;
+ }
+
+ /* BUGBUG this should make sure the bridge requested for removal is actually
+ * the bridge the channel is in. This will be possible once the bridge uniqueid
+ * is added to the channel snapshot. A 409 response should be issued if the bridge
+ * uniqueids don't match */
+ if (stasis_app_control_remove_channel_from_bridge(control, bridge)) {
+ ast_ari_response_error(response, 500, "Internal Error",
+ "Could not remove channel from bridge");
+ return;
+ }
+
+ ast_ari_response_no_content(response);
+}
+
+struct bridge_channel_control_thread_data {
+ struct ast_channel *bridge_channel;
+ struct stasis_app_control *control;
+};
+
+static void *bridge_channel_control_thread(void *data)
+{
+ struct bridge_channel_control_thread_data *thread_data = data;
+ struct ast_channel *bridge_channel = thread_data->bridge_channel;
+ struct stasis_app_control *control = thread_data->control;
+
+ RAII_VAR(struct ast_callid *, callid, ast_channel_callid(bridge_channel), ast_callid_cleanup);
+
+ if (callid) {
+ ast_callid_threadassoc_add(callid);
+ }
+
+ ast_free(thread_data);
+ thread_data = NULL;
+
+ stasis_app_control_execute_until_exhausted(bridge_channel, control);
+
+ ast_hangup(bridge_channel);
+ ao2_cleanup(control);
+ return NULL;
+}
+
+static struct ast_channel *prepare_bridge_media_channel(const char *type)
+{
+ RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
+ struct ast_format format;
+
+ cap = ast_format_cap_alloc_nolock();
+ if (!cap) {
+ return NULL;
+ }
+
+ ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
+
+ if (!cap) {
+ return NULL;
+ }
+
+ return ast_request(type, cap, NULL, "ARI", NULL);
+}
+
+void ast_ari_play_on_bridge(struct ast_variable *headers, struct ast_play_on_bridge_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
+ RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
+ RAII_VAR(char *, playback_url, NULL, ast_free);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+
+ struct bridge_channel_control_thread_data *thread_data;
+ const char *language;
+ pthread_t threadid;
+
+ ast_assert(response != NULL);
+
+ if (!bridge) {
+ return;
+ }
+
+ if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
+ ast_ari_response_error(
+ response, 500, "Internal Error", "Could not create playback channel");
+ return;
+ }
+ ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));
+
+ if (ast_unreal_channel_push_to_bridge(play_channel, bridge)) {
+ ast_ari_response_error(
+ response, 500, "Internal Error", "Failed to put playback channel into the bridge");
+ return;
+ }
+
+ control = stasis_app_control_create(play_channel);
+ if (control == NULL) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ snapshot = stasis_app_control_get_snapshot(control);
+ if (!snapshot) {
+ ast_ari_response_error(
+ response, 500, "Internal Error", "Failed to get control snapshot");
+ return;
+ }
+
+ language = S_OR(args->lang, snapshot->language);
+
+ playback = stasis_app_control_play_uri(control, args->media, language,
+ args->bridge_id, STASIS_PLAYBACK_TARGET_BRIDGE, args->skipms,
+ args->offsetms);
+
+ if (!playback) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ ast_asprintf(&playback_url, "/playback/%s",
+ stasis_app_playback_get_id(playback));
+
+ if (!playback_url) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ json = stasis_app_playback_to_json(playback);
+ if (!json) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ /* Give play_channel and control reference to the thread data */
+ thread_data = ast_calloc(1, sizeof(*thread_data));
+ if (!thread_data) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ thread_data->bridge_channel = play_channel;
+ thread_data->control = control;
+
+ if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
+ ast_ari_response_alloc_failed(response);
+ ast_free(thread_data);
+ return;
+ }
+
+ /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
+ play_channel = NULL;
+ control = NULL;
+
+ ast_ari_response_created(response, playback_url, json);
+}
+
+void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
+ RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
+ RAII_VAR(char *, recording_url, NULL, ast_free);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
+ RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
+
+ size_t uri_name_maxlen;
+ struct bridge_channel_control_thread_data *thread_data;
+ pthread_t threadid;
+
+ ast_assert(response != NULL);
+
+ if (bridge == NULL) {
+ return;
+ }
+
+ if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error", "Failed to create recording channel");
+ return;
+ }
+
+ if (ast_unreal_channel_push_to_bridge(record_channel, bridge)) {
+ ast_ari_response_error(
+ response, 500, "Internal Error", "Failed to put recording channel into the bridge");
+ return;
+ }
+
+ control = stasis_app_control_create(record_channel);
+ if (control == NULL) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ options = stasis_app_recording_options_create(args->name, args->format);
+ if (options == NULL) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ options->max_silence_seconds = args->max_silence_seconds;
+ options->max_duration_seconds = args->max_duration_seconds;
+ options->terminate_on =
+ stasis_app_recording_termination_parse(args->terminate_on);
+ options->if_exists =
+ stasis_app_recording_if_exists_parse(args->if_exists);
+ options->beep = args->beep;
+
+ recording = stasis_app_control_record(control, options);
+ if (recording == NULL) {
+ switch(errno) {
+ case EINVAL:
+ /* While the arguments are invalid, we should have
+ * caught them prior to calling record.
+ */
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Error parsing request");
+ break;
+ case EEXIST:
+ ast_ari_response_error(response, 409, "Conflict",
+ "Recording '%s' already in progress",
+ args->name);
+ break;
+ case ENOMEM:
+ ast_ari_response_alloc_failed(response);
+ break;
+ case EPERM:
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Recording name invalid");
+ break;
+ default:
+ ast_log(LOG_WARNING,
+ "Unrecognized recording error: %s\n",
+ strerror(errno));
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Internal Server Error");
+ break;
+ }
+ return;
+ }
+
+ uri_name_maxlen = strlen(args->name) * 3;
+ uri_encoded_name = ast_malloc(uri_name_maxlen);
+ if (!uri_encoded_name) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+ ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);
+
+ ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
+ if (!recording_url) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ json = stasis_app_recording_to_json(recording);
+ if (!json) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ thread_data = ast_calloc(1, sizeof(*thread_data));
+ if (!thread_data) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ thread_data->bridge_channel = record_channel;
+ thread_data->control = control;
+
+ if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
+ ast_ari_response_alloc_failed(response);
+ ast_free(thread_data);
+ return;
+ }
+
+ /* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
+ record_channel = NULL;
+ control = NULL;
+
+ ast_ari_response_created(response, recording_url, json);
+}
+
+void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_bridge_snapshot *, snapshot, ast_bridge_snapshot_get_latest(args->bridge_id), ao2_cleanup);
+ if (!snapshot) {
+ ast_ari_response_error(
+ response, 404, "Not Found",
+ "Bridge not found");
+ return;
+ }
+
+ ast_ari_response_ok(response,
+ ast_bridge_snapshot_to_json(snapshot));
+}
+
+void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
+ if (!bridge) {
+ return;
+ }
+
+ stasis_app_bridge_destroy(args->bridge_id);
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ struct ao2_iterator i;
+ void *obj;
+
+ caching_topic = ast_bridge_topic_all_cached();
+ if (!caching_topic) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Message bus not initialized");
+ return;
+ }
+ ao2_ref(caching_topic, +1);
+
+ snapshots = stasis_cache_dump(caching_topic, ast_bridge_snapshot_type());
+ if (!snapshots) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ json = ast_json_array_create();
+ if (!json) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ i = ao2_iterator_init(snapshots, 0);
+ while ((obj = ao2_iterator_next(&i))) {
+ RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
+ struct ast_bridge_snapshot *snapshot = stasis_message_data(msg);
+ if (ast_json_array_append(json, ast_bridge_snapshot_to_json(snapshot))) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+ }
+ ao2_iterator_destroy(&i);
+
+ ast_ari_response_ok(response, ast_json_ref(json));
+}
+
+void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type), ao2_cleanup);
+ RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
+
+ if (!bridge) {
+ ast_ari_response_error(
+ response, 500, "Internal Error",
+ "Unable to create bridge");
+ return;
+ }
+
+ snapshot = ast_bridge_snapshot_create(bridge);
+ if (!snapshot) {
+ ast_ari_response_error(
+ response, 500, "Internal Error",
+ "Unable to create snapshot for new bridge");
+ return;
+ }
+
+ ast_ari_response_ok(response,
+ ast_bridge_snapshot_to_json(snapshot));
+}
diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h
new file mode 100644
index 000000000..892a3f269
--- /dev/null
+++ b/res/ari/resource_bridges.h
@@ -0,0 +1,179 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - declares stubs to be implemented in
+ * res/ari/resource_bridges.c
+ *
+ * Bridge resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_resource.h.mustache
+ */
+
+#ifndef _ASTERISK_RESOURCE_BRIDGES_H
+#define _ASTERISK_RESOURCE_BRIDGES_H
+
+#include "asterisk/ari.h"
+
+/*! \brief Argument struct for ast_ari_get_bridges() */
+struct ast_get_bridges_args {
+};
+/*!
+ * \brief List active bridges.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_bridges(struct ast_variable *headers, struct ast_get_bridges_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_new_bridge() */
+struct ast_new_bridge_args {
+ /*! \brief Type of bridge to create. */
+ const char *type;
+};
+/*!
+ * \brief Create a new bridge.
+ *
+ * This bridge persists until it has been shut down, or Asterisk has been shut down.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_new_bridge(struct ast_variable *headers, struct ast_new_bridge_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_bridge() */
+struct ast_get_bridge_args {
+ /*! \brief Bridge's id */
+ const char *bridge_id;
+};
+/*!
+ * \brief Get bridge details.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_bridge(struct ast_variable *headers, struct ast_get_bridge_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_delete_bridge() */
+struct ast_delete_bridge_args {
+ /*! \brief Bridge's id */
+ const char *bridge_id;
+};
+/*!
+ * \brief Shut down a bridge.
+ *
+ * If any channels are in this bridge, they will be removed and resume whatever they were doing beforehand.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_delete_bridge(struct ast_variable *headers, struct ast_delete_bridge_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_add_channel_to_bridge() */
+struct ast_add_channel_to_bridge_args {
+ /*! \brief Bridge's id */
+ const char *bridge_id;
+ /*! \brief Channel's id */
+ const char *channel;
+};
+/*!
+ * \brief Add a channel to a bridge.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_add_channel_to_bridge(struct ast_variable *headers, struct ast_add_channel_to_bridge_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_remove_channel_from_bridge() */
+struct ast_remove_channel_from_bridge_args {
+ /*! \brief Bridge's id */
+ const char *bridge_id;
+ /*! \brief Channel's id */
+ const char *channel;
+};
+/*!
+ * \brief Remove a channel from a bridge.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_remove_channel_from_bridge(struct ast_variable *headers, struct ast_remove_channel_from_bridge_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_play_on_bridge() */
+struct ast_play_on_bridge_args {
+ /*! \brief Bridge's id */
+ const char *bridge_id;
+ /*! \brief Media's URI to play. */
+ const char *media;
+ /*! \brief For sounds, selects language for sound. */
+ const char *lang;
+ /*! \brief Number of media to skip before playing. */
+ int offsetms;
+ /*! \brief Number of milliseconds to skip for forward/reverse operations. */
+ int skipms;
+};
+/*!
+ * \brief Start playback of media on a bridge.
+ *
+ * The media URI may be any of a number of URI's. You may use http: and https: URI's, as well as sound: and recording: URI's. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_play_on_bridge(struct ast_variable *headers, struct ast_play_on_bridge_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_record_bridge() */
+struct ast_record_bridge_args {
+ /*! \brief Bridge's id */
+ const char *bridge_id;
+ /*! \brief Recording's filename */
+ const char *name;
+ /*! \brief Format to encode audio in */
+ const char *format;
+ /*! \brief Maximum duration of the recording, in seconds. 0 for no limit. */
+ int max_duration_seconds;
+ /*! \brief Maximum duration of silence, in seconds. 0 for no limit. */
+ int max_silence_seconds;
+ /*! \brief Action to take if a recording with the same name already exists. */
+ const char *if_exists;
+ /*! \brief Play beep when recording begins */
+ int beep;
+ /*! \brief DTMF input to terminate recording. */
+ const char *terminate_on;
+};
+/*!
+ * \brief Start a recording.
+ *
+ * This records the mixed audio from all channels participating in this bridge.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_record_bridge(struct ast_variable *headers, struct ast_record_bridge_args *args, struct ast_ari_response *response);
+
+#endif /* _ASTERISK_RESOURCE_BRIDGES_H */
diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c
new file mode 100644
index 000000000..7f3a91fba
--- /dev/null
+++ b/res/ari/resource_channels.c
@@ -0,0 +1,693 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Implementation for ARI stubs.
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*** MODULEINFO
+ <depend type="module">res_stasis_app_playback</depend>
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/file.h"
+#include "asterisk/pbx.h"
+#include "asterisk/dial.h"
+#include "asterisk/bridge.h"
+#include "asterisk/callerid.h"
+#include "asterisk/stasis_app.h"
+#include "asterisk/stasis_app_playback.h"
+#include "asterisk/stasis_app_recording.h"
+#include "asterisk/stasis_channels.h"
+#include "resource_channels.h"
+
+#include <limits.h>
+
+/*!
+ * \brief Finds the control object for a channel, filling the response with an
+ * error, if appropriate.
+ * \param[out] response Response to fill with an error if control is not found.
+ * \param channel_id ID of the channel to lookup.
+ * \return Channel control object.
+ * \return \c NULL if control object does not exist.
+ */
+static struct stasis_app_control *find_control(
+ struct ast_ari_response *response,
+ const char *channel_id)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+ ast_assert(response != NULL);
+
+ control = stasis_app_control_find_by_channel_id(channel_id);
+ if (control == NULL) {
+ /* Distinguish between 404 and 409 errors */
+ RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
+ chan = ast_channel_get_by_name(channel_id);
+ if (chan == NULL) {
+ ast_ari_response_error(response, 404, "Not Found",
+ "Channel not found");
+ return NULL;
+ }
+
+ ast_ari_response_error(response, 409, "Conflict",
+ "Channel not in Stasis application");
+ return NULL;
+ }
+
+ ao2_ref(control, +1);
+ return control;
+}
+
+void ast_ari_dial(struct ast_variable *headers, struct ast_dial_args *args, struct ast_ari_response *response)
+{
+ struct stasis_app_control *control;
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ return;
+ }
+
+ if (stasis_app_control_dial(control, args->endpoint, args->timeout)) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_continue_in_dialplan(
+ struct ast_variable *headers,
+ struct ast_continue_in_dialplan_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+ ast_assert(response != NULL);
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ return;
+ }
+
+ if (stasis_app_control_continue(control, args->context, args->extension, args->priority)) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_answer_channel(struct ast_variable *headers,
+ struct ast_answer_channel_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ return;
+ }
+
+ if (stasis_app_control_answer(control) != 0) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Failed to answer channel");
+ return;
+ }
+
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_mute_channel(struct ast_variable *headers, struct ast_mute_channel_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+ unsigned int direction = 0;
+ enum ast_frame_type frametype = AST_FRAME_VOICE;
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ return;
+ }
+
+ if (!strcmp(args->direction, "in")) {
+ direction = AST_MUTE_DIRECTION_READ;
+ } else if (!strcmp(args->direction, "out")) {
+ direction = AST_MUTE_DIRECTION_WRITE;
+ } else if (!strcmp(args->direction, "both")) {
+ direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
+ } else {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Invalid direction specified");
+ return;
+ }
+
+ stasis_app_control_mute(control, direction, frametype);
+
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_unmute_channel(struct ast_variable *headers, struct ast_unmute_channel_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+ unsigned int direction = 0;
+ enum ast_frame_type frametype = AST_FRAME_VOICE;
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ return;
+ }
+
+ if (!strcmp(args->direction, "in")) {
+ direction = AST_MUTE_DIRECTION_READ;
+ } else if (!strcmp(args->direction, "out")) {
+ direction = AST_MUTE_DIRECTION_WRITE;
+ } else if (!strcmp(args->direction, "both")) {
+ direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
+ } else {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Invalid direction specified");
+ return;
+ }
+
+ stasis_app_control_unmute(control, direction, frametype);
+
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_hold_channel(struct ast_variable *headers, struct ast_hold_channel_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ /* Response filled in by find_control */
+ return;
+ }
+
+ stasis_app_control_hold(control);
+
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_unhold_channel(struct ast_variable *headers, struct ast_unhold_channel_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ /* Response filled in by find_control */
+ return;
+ }
+
+ stasis_app_control_unhold(control);
+
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_moh_start_channel(struct ast_variable *headers, struct ast_moh_start_channel_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ /* Response filled in by find_control */
+ return;
+ }
+
+ stasis_app_control_moh_start(control, args->moh_class);
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_moh_stop_channel(struct ast_variable *headers, struct ast_moh_stop_channel_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ /* Response filled in by find_control */
+ return;
+ }
+
+ stasis_app_control_moh_stop(control);
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_play_on_channel(struct ast_variable *headers,
+ struct ast_play_on_channel_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
+ RAII_VAR(char *, playback_url, NULL, ast_free);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ const char *language;
+
+ ast_assert(response != NULL);
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ /* Response filled in by find_control */
+ return;
+ }
+
+ snapshot = stasis_app_control_get_snapshot(control);
+ if (!snapshot) {
+ ast_ari_response_error(
+ response, 404, "Not Found",
+ "Channel not found");
+ return;
+ }
+
+ if (args->skipms < 0) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "skipms cannot be negative");
+ return;
+ }
+
+ if (args->offsetms < 0) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "offsetms cannot be negative");
+ return;
+ }
+
+ language = S_OR(args->lang, snapshot->language);
+
+ playback = stasis_app_control_play_uri(control, args->media, language,
+ args->channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args->skipms, args->offsetms);
+ if (!playback) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Failed to queue media for playback");
+ return;
+ }
+
+ ast_asprintf(&playback_url, "/playback/%s",
+ stasis_app_playback_get_id(playback));
+ if (!playback_url) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Out of memory");
+ return;
+ }
+
+ json = stasis_app_playback_to_json(playback);
+ if (!json) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Out of memory");
+ return;
+ }
+
+ ast_ari_response_created(response, playback_url, json);
+}
+
+void ast_ari_record_channel(struct ast_variable *headers,
+ struct ast_record_channel_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
+ RAII_VAR(char *, recording_url, NULL, ast_free);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_app_recording_options *, options, NULL,
+ ao2_cleanup);
+ RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
+ size_t uri_name_maxlen;
+
+ ast_assert(response != NULL);
+
+ if (args->max_duration_seconds < 0) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "max_duration_seconds cannot be negative");
+ return;
+ }
+
+ if (args->max_silence_seconds < 0) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "max_silence_seconds cannot be negative");
+ return;
+ }
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ /* Response filled in by find_control */
+ return;
+ }
+
+ options = stasis_app_recording_options_create(args->name, args->format);
+ if (options == NULL) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Out of memory");
+ }
+ options->max_silence_seconds = args->max_silence_seconds;
+ options->max_duration_seconds = args->max_duration_seconds;
+ options->terminate_on =
+ stasis_app_recording_termination_parse(args->terminate_on);
+ options->if_exists =
+ stasis_app_recording_if_exists_parse(args->if_exists);
+ options->beep = args->beep;
+
+ if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "terminateOn invalid");
+ return;
+ }
+
+ if (options->if_exists == -1) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "ifExists invalid");
+ return;
+ }
+
+ recording = stasis_app_control_record(control, options);
+ if (recording == NULL) {
+ switch(errno) {
+ case EINVAL:
+ /* While the arguments are invalid, we should have
+ * caught them prior to calling record.
+ */
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Error parsing request");
+ break;
+ case EEXIST:
+ ast_ari_response_error(response, 409, "Conflict",
+ "Recording '%s' already in progress",
+ args->name);
+ break;
+ case ENOMEM:
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Out of memory");
+ break;
+ case EPERM:
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Recording name invalid");
+ break;
+ default:
+ ast_log(LOG_WARNING,
+ "Unrecognized recording error: %s\n",
+ strerror(errno));
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Internal Server Error");
+ break;
+ }
+ return;
+ }
+
+ uri_name_maxlen = strlen(args->name) * 3;
+ uri_encoded_name = ast_malloc(uri_name_maxlen);
+ if (!uri_encoded_name) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Out of memory");
+ return;
+ }
+ ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen,
+ ast_uri_http);
+
+ ast_asprintf(&recording_url, "/recordings/live/%s", uri_encoded_name);
+ if (!recording_url) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Out of memory");
+ return;
+ }
+
+ json = stasis_app_recording_to_json(recording);
+ if (!json) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Out of memory");
+ return;
+ }
+
+ ast_ari_response_created(response, recording_url, json);
+}
+
+void ast_ari_get_channel(struct ast_variable *headers,
+ struct ast_get_channel_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
+ struct stasis_caching_topic *caching_topic;
+ struct ast_channel_snapshot *snapshot;
+
+ caching_topic = ast_channel_topic_all_cached();
+ if (!caching_topic) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Message bus not initialized");
+ return;
+ }
+
+ msg = stasis_cache_get(caching_topic, ast_channel_snapshot_type(),
+ args->channel_id);
+ if (!msg) {
+ ast_ari_response_error(
+ response, 404, "Not Found",
+ "Channel not found");
+ return;
+ }
+
+ snapshot = stasis_message_data(msg);
+ ast_assert(snapshot != NULL);
+
+ ast_ari_response_ok(response,
+ ast_channel_snapshot_to_json(snapshot));
+}
+
+void ast_ari_delete_channel(struct ast_variable *headers,
+ struct ast_delete_channel_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
+
+ chan = ast_channel_get_by_name(args->channel_id);
+ if (chan == NULL) {
+ ast_ari_response_error(
+ response, 404, "Not Found",
+ "Channel not found");
+ return;
+ }
+
+ ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
+
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_get_channels(struct ast_variable *headers,
+ struct ast_get_channels_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ struct ao2_iterator i;
+ void *obj;
+
+ caching_topic = ast_channel_topic_all_cached();
+ if (!caching_topic) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Message bus not initialized");
+ return;
+ }
+ ao2_ref(caching_topic, +1);
+
+ snapshots = stasis_cache_dump(caching_topic, ast_channel_snapshot_type());
+ if (!snapshots) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ json = ast_json_array_create();
+ if (!json) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ i = ao2_iterator_init(snapshots, 0);
+ while ((obj = ao2_iterator_next(&i))) {
+ RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
+ struct ast_channel_snapshot *snapshot = stasis_message_data(msg);
+ int r = ast_json_array_append(
+ json, ast_channel_snapshot_to_json(snapshot));
+ if (r != 0) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+ }
+ ao2_iterator_destroy(&i);
+
+ ast_ari_response_ok(response, ast_json_ref(json));
+}
+
+void ast_ari_originate(struct ast_variable *headers,
+ struct ast_originate_args *args,
+ struct ast_ari_response *response)
+{
+ char *dialtech;
+ char dialdevice[AST_CHANNEL_NAME];
+ char *caller_id = NULL;
+ char *cid_num = NULL;
+ char *cid_name = NULL;
+ int timeout = 30000;
+
+ char *stuff;
+
+ if (ast_strlen_zero(args->endpoint)) {
+ ast_ari_response_error(response, 400, "Bad Request",
+ "Endpoint must be specified");
+ return;
+ }
+
+ dialtech = ast_strdupa(args->endpoint);
+ if ((stuff = strchr(dialtech, '/'))) {
+ *stuff++ = '\0';
+ ast_copy_string(dialdevice, stuff, sizeof(dialdevice));
+ }
+
+ if (ast_strlen_zero(dialtech) || ast_strlen_zero(dialdevice)) {
+ ast_ari_response_error(response, 400, "Bad Request",
+ "Invalid endpoint specified");
+ return;
+ }
+
+ if (args->timeout > 0) {
+ timeout = args->timeout * 1000;
+ } else if (args->timeout == -1) {
+ timeout = -1;
+ }
+
+ if (!ast_strlen_zero(args->caller_id)) {
+ caller_id = ast_strdupa(args->caller_id);
+ ast_callerid_parse(caller_id, &cid_name, &cid_num);
+
+ if (ast_is_shrinkable_phonenumber(cid_num)) {
+ ast_shrink_phone_number(cid_num);
+ }
+ }
+
+ if (!ast_strlen_zero(args->app)) {
+ const char *app = "Stasis";
+
+ RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free);
+
+ if (!appdata) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ ast_str_set(&appdata, 0, "%s", args->app);
+ if (!ast_strlen_zero(args->app_args)) {
+ ast_str_append(&appdata, 0, ",%s", args->app_args);
+ }
+
+ /* originate a channel, putting it into an application */
+ if (ast_pbx_outgoing_app(dialtech, NULL, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, NULL, NULL, NULL)) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+ } else if (!ast_strlen_zero(args->extension)) {
+ /* originate a channel, sending it to an extension */
+ if (ast_pbx_outgoing_exten(dialtech, NULL, dialdevice, timeout, S_OR(args->context, "default"), args->extension, args->priority ? args->priority : 1, NULL, 0, cid_num, cid_name, NULL, NULL, NULL, 0)) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+ } else {
+ ast_ari_response_error(response, 400, "Bad Request",
+ "Application or extension must be specified");
+ return;
+ }
+
+ ast_ari_response_no_content(response);
+}
+
+void ast_ari_get_channel_var(struct ast_variable *headers, struct ast_get_channel_var_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+ RAII_VAR(char *, value, NULL, ast_free);
+
+ ast_assert(response != NULL);
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ return;
+ }
+
+ value = stasis_app_control_get_channel_var(control, args->variable);
+
+ if (!(json = ast_json_pack("{s: s}", "value", S_OR(value, "")))) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ ast_ari_response_ok(response, ast_json_ref(json));
+}
+
+void ast_ari_set_channel_var(struct ast_variable *headers, struct ast_set_channel_var_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
+
+ ast_assert(response != NULL);
+
+ control = find_control(response, args->channel_id);
+ if (control == NULL) {
+ return;
+ }
+
+ if (ast_strlen_zero(args->variable)) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Variable name is required");
+ return;
+ }
+
+ if (stasis_app_control_set_channel_var(control, args->variable, args->value)) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Failed to execute function");
+ return;
+ }
+
+ ast_ari_response_no_content(response);
+}
+
diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h
new file mode 100644
index 000000000..953d58f4e
--- /dev/null
+++ b/res/ari/resource_channels.h
@@ -0,0 +1,330 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - declares stubs to be implemented in
+ * res/ari/resource_channels.c
+ *
+ * Channel resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_resource.h.mustache
+ */
+
+#ifndef _ASTERISK_RESOURCE_CHANNELS_H
+#define _ASTERISK_RESOURCE_CHANNELS_H
+
+#include "asterisk/ari.h"
+
+/*! \brief Argument struct for ast_ari_get_channels() */
+struct ast_get_channels_args {
+};
+/*!
+ * \brief List active channels.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_channels(struct ast_variable *headers, struct ast_get_channels_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_originate() */
+struct ast_originate_args {
+ /*! \brief Endpoint to call. */
+ const char *endpoint;
+ /*! \brief The extension to dial after the endpoint answers */
+ const char *extension;
+ /*! \brief The context to dial after the endpoint answers. If omitted, uses 'default' */
+ const char *context;
+ /*! \brief The priority to dial after the endpoint answers. If omitted, uses 1 */
+ long priority;
+ /*! \brief The application name to pass to the Stasis application. */
+ const char *app;
+ /*! \brief The application arguments to pass to the Stasis application. */
+ const char *app_args;
+ /*! \brief CallerID to use when dialing the endpoint or extension. */
+ const char *caller_id;
+ /*! \brief Timeout (in seconds) before giving up dialing, or -1 for no timeout. */
+ int timeout;
+};
+/*!
+ * \brief Create a new channel (originate).
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_originate(struct ast_variable *headers, struct ast_originate_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_channel() */
+struct ast_get_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+};
+/*!
+ * \brief Channel details.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_channel(struct ast_variable *headers, struct ast_get_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_delete_channel() */
+struct ast_delete_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+};
+/*!
+ * \brief Delete (i.e. hangup) a channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_delete_channel(struct ast_variable *headers, struct ast_delete_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_dial() */
+struct ast_dial_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief Endpoint to call. If not specified, dial is routed via dialplan */
+ const char *endpoint;
+ /*! \brief Extension to dial */
+ const char *extension;
+ /*! \brief When routing via dialplan, the context use. If omitted, uses 'default' */
+ const char *context;
+ /*! \brief Timeout (in seconds) before giving up dialing, or -1 for no timeout. */
+ int timeout;
+};
+/*!
+ * \brief Create a new channel (originate) and bridge to this channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_dial(struct ast_variable *headers, struct ast_dial_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_continue_in_dialplan() */
+struct ast_continue_in_dialplan_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief The context to continue to. */
+ const char *context;
+ /*! \brief The extension to continue to. */
+ const char *extension;
+ /*! \brief The priority to continue to. */
+ int priority;
+};
+/*!
+ * \brief Exit application; continue execution in the dialplan.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_continue_in_dialplan(struct ast_variable *headers, struct ast_continue_in_dialplan_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_answer_channel() */
+struct ast_answer_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+};
+/*!
+ * \brief Answer a channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_answer_channel(struct ast_variable *headers, struct ast_answer_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_mute_channel() */
+struct ast_mute_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief Direction in which to mute audio */
+ const char *direction;
+};
+/*!
+ * \brief Mute a channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_mute_channel(struct ast_variable *headers, struct ast_mute_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_unmute_channel() */
+struct ast_unmute_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief Direction in which to unmute audio */
+ const char *direction;
+};
+/*!
+ * \brief Unmute a channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_unmute_channel(struct ast_variable *headers, struct ast_unmute_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_hold_channel() */
+struct ast_hold_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+};
+/*!
+ * \brief Hold a channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_hold_channel(struct ast_variable *headers, struct ast_hold_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_unhold_channel() */
+struct ast_unhold_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+};
+/*!
+ * \brief Remove a channel from hold.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_unhold_channel(struct ast_variable *headers, struct ast_unhold_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_moh_start_channel() */
+struct ast_moh_start_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief Music on hold class to use */
+ const char *moh_class;
+};
+/*!
+ * \brief Play music on hold to a channel.
+ *
+ * Using media operations such as playOnChannel on a channel playing MOH in this manner will suspend MOH without resuming automatically. If continuing music on hold is desired, the stasis application must reinitiate music on hold.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_moh_start_channel(struct ast_variable *headers, struct ast_moh_start_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_moh_stop_channel() */
+struct ast_moh_stop_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+};
+/*!
+ * \brief Stop playing music on hold to a channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_moh_stop_channel(struct ast_variable *headers, struct ast_moh_stop_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_play_on_channel() */
+struct ast_play_on_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief Media's URI to play. */
+ const char *media;
+ /*! \brief For sounds, selects language for sound. */
+ const char *lang;
+ /*! \brief Number of media to skip before playing. */
+ int offsetms;
+ /*! \brief Number of milliseconds to skip for forward/reverse operations. */
+ int skipms;
+};
+/*!
+ * \brief Start playback of media.
+ *
+ * The media URI may be any of a number of URI's. You may use http: and https: URI's, as well as sound: and recording: URI's. This operation creates a playback resource that can be used to control the playback of media (pause, rewind, fast forward, etc.)
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_play_on_channel(struct ast_variable *headers, struct ast_play_on_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_record_channel() */
+struct ast_record_channel_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief Recording's filename */
+ const char *name;
+ /*! \brief Format to encode audio in */
+ const char *format;
+ /*! \brief Maximum duration of the recording, in seconds. 0 for no limit */
+ int max_duration_seconds;
+ /*! \brief Maximum duration of silence, in seconds. 0 for no limit */
+ int max_silence_seconds;
+ /*! \brief Action to take if a recording with the same name already exists. */
+ const char *if_exists;
+ /*! \brief Play beep when recording begins */
+ int beep;
+ /*! \brief DTMF input to terminate recording */
+ const char *terminate_on;
+};
+/*!
+ * \brief Start a recording.
+ *
+ * Record audio from a channel. Note that this will not capture audio sent to the channel. The bridge itself has a record feature if that's what you want.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_record_channel(struct ast_variable *headers, struct ast_record_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_channel_var() */
+struct ast_get_channel_var_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief The channel variable or function to get */
+ const char *variable;
+};
+/*!
+ * \brief Get the value of a channel variable or function.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_channel_var(struct ast_variable *headers, struct ast_get_channel_var_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_set_channel_var() */
+struct ast_set_channel_var_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief The channel variable or function to set */
+ const char *variable;
+ /*! \brief The value to set the variable to */
+ const char *value;
+};
+/*!
+ * \brief Set the value of a channel variable or function.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_set_channel_var(struct ast_variable *headers, struct ast_set_channel_var_args *args, struct ast_ari_response *response);
+
+#endif /* _ASTERISK_RESOURCE_CHANNELS_H */
diff --git a/res/ari/resource_endpoints.c b/res/ari/resource_endpoints.c
new file mode 100644
index 000000000..bb28df03c
--- /dev/null
+++ b/res/ari/resource_endpoints.c
@@ -0,0 +1,157 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief /api-docs/endpoints.{format} implementation- Endpoint resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "resource_endpoints.h"
+
+#include "asterisk/astobj2.h"
+#include "asterisk/stasis.h"
+#include "asterisk/stasis_endpoints.h"
+
+void ast_ari_get_endpoints(struct ast_variable *headers,
+ struct ast_get_endpoints_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ struct ao2_iterator i;
+ void *obj;
+
+ caching_topic = ast_endpoint_topic_all_cached();
+ if (!caching_topic) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Message bus not initialized");
+ return;
+ }
+ ao2_ref(caching_topic, +1);
+
+ snapshots = stasis_cache_dump(caching_topic, ast_endpoint_snapshot_type());
+ if (!snapshots) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ json = ast_json_array_create();
+ if (!json) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ i = ao2_iterator_init(snapshots, 0);
+ while ((obj = ao2_iterator_next(&i))) {
+ RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
+ struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
+ int r = ast_json_array_append(
+ json, ast_endpoint_snapshot_to_json(snapshot));
+ if (r != 0) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+ }
+ ao2_iterator_destroy(&i);
+
+ ast_ari_response_ok(response, ast_json_ref(json));
+}
+void ast_ari_get_endpoints_by_tech(struct ast_variable *headers,
+ struct ast_get_endpoints_by_tech_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_caching_topic *, caching_topic, NULL, ao2_cleanup);
+ RAII_VAR(struct ao2_container *, snapshots, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ struct ao2_iterator i;
+ void *obj;
+
+ /* TODO - if tech isn't a recognized type of endpoint, it should 404 */
+
+ caching_topic = ast_endpoint_topic_all_cached();
+ if (!caching_topic) {
+ ast_ari_response_error(
+ response, 500, "Internal Server Error",
+ "Message bus not initialized");
+ return;
+ }
+ ao2_ref(caching_topic, +1);
+
+ snapshots = stasis_cache_dump(caching_topic, ast_endpoint_snapshot_type());
+ if (!snapshots) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ json = ast_json_array_create();
+ if (!json) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ i = ao2_iterator_init(snapshots, 0);
+ while ((obj = ao2_iterator_next(&i))) {
+ RAII_VAR(struct stasis_message *, msg, obj, ao2_cleanup);
+ struct ast_endpoint_snapshot *snapshot = stasis_message_data(msg);
+ int r;
+
+ if (strcmp(args->tech, snapshot->tech) != 0) {
+ continue;
+ }
+
+ r = ast_json_array_append(
+ json, ast_endpoint_snapshot_to_json(snapshot));
+ if (r != 0) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+ }
+ ao2_iterator_destroy(&i);
+
+ ast_ari_response_ok(response, ast_json_ref(json));
+}
+void ast_ari_get_endpoint(struct ast_variable *headers,
+ struct ast_get_endpoint_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+ RAII_VAR(struct ast_endpoint_snapshot *, snapshot, NULL, ao2_cleanup);
+
+ snapshot = ast_endpoint_latest_snapshot(args->tech, args->resource, 0);
+ if (!snapshot) {
+ ast_ari_response_error(response, 404, "Not Found",
+ "Endpoint not found");
+ return;
+ }
+
+ json = ast_endpoint_snapshot_to_json(snapshot);
+ if (!json) {
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+
+ ast_ari_response_ok(response, ast_json_ref(json));
+}
diff --git a/res/ari/resource_endpoints.h b/res/ari/resource_endpoints.h
new file mode 100644
index 000000000..82c6afc0a
--- /dev/null
+++ b/res/ari/resource_endpoints.h
@@ -0,0 +1,82 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - declares stubs to be implemented in
+ * res/ari/resource_endpoints.c
+ *
+ * Endpoint resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_resource.h.mustache
+ */
+
+#ifndef _ASTERISK_RESOURCE_ENDPOINTS_H
+#define _ASTERISK_RESOURCE_ENDPOINTS_H
+
+#include "asterisk/ari.h"
+
+/*! \brief Argument struct for ast_ari_get_endpoints() */
+struct ast_get_endpoints_args {
+};
+/*!
+ * \brief List all endoints.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_endpoints(struct ast_variable *headers, struct ast_get_endpoints_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_endpoints_by_tech() */
+struct ast_get_endpoints_by_tech_args {
+ /*! \brief Technology of the endpoints (sip,iax2,...) */
+ const char *tech;
+};
+/*!
+ * \brief List available endoints for a given endpoint technology.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_endpoints_by_tech(struct ast_variable *headers, struct ast_get_endpoints_by_tech_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_endpoint() */
+struct ast_get_endpoint_args {
+ /*! \brief Technology of the endpoint */
+ const char *tech;
+ /*! \brief ID of the endpoint */
+ const char *resource;
+};
+/*!
+ * \brief Details for an endpoint.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_endpoint(struct ast_variable *headers, struct ast_get_endpoint_args *args, struct ast_ari_response *response);
+
+#endif /* _ASTERISK_RESOURCE_ENDPOINTS_H */
diff --git a/res/ari/resource_events.c b/res/ari/resource_events.c
new file mode 100644
index 000000000..e5490b546
--- /dev/null
+++ b/res/ari/resource_events.c
@@ -0,0 +1,218 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief /api-docs/events.{format} implementation- WebSocket resource
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/astobj2.h"
+#include "asterisk/stasis_app.h"
+#include "resource_events.h"
+
+/*! Number of buckets for the Stasis application hash table. Remember to keep it
+ * a prime number!
+ */
+#define APPS_NUM_BUCKETS 7
+
+/*! \brief A connection to the event WebSocket */
+struct event_session {
+ struct ast_ari_websocket_session *ws_session;
+ struct ao2_container *websocket_apps;
+};
+
+/*!
+ * \brief Explicitly shutdown a session.
+ *
+ * An explicit shutdown is necessary, since stasis-app has a reference to this
+ * session. We also need to be sure to null out the \c ws_session field, since
+ * the websocket is about to go away.
+ *
+ * \param session Session info struct.
+ */
+static void session_shutdown(struct event_session *session)
+{
+ struct ao2_iterator i;
+ char *app;
+ SCOPED_AO2LOCK(lock, session);
+
+ i = ao2_iterator_init(session->websocket_apps, 0);
+ while ((app = ao2_iterator_next(&i))) {
+ stasis_app_unregister(app);
+ ao2_cleanup(app);
+ }
+ ao2_iterator_destroy(&i);
+ ao2_cleanup(session->websocket_apps);
+
+ session->websocket_apps = NULL;
+ session->ws_session = NULL;
+}
+
+static void session_dtor(void *obj)
+{
+#ifdef AST_DEVMODE /* Avoid unused variable warning */
+ struct event_session *session = obj;
+#endif
+
+ /* session_shutdown should have been called before */
+ ast_assert(session->ws_session == NULL);
+ ast_assert(session->websocket_apps == NULL);
+}
+
+static void session_cleanup(struct event_session *session)
+{
+ session_shutdown(session);
+ ao2_cleanup(session);
+}
+
+static struct event_session *session_create(
+ struct ast_ari_websocket_session *ws_session)
+{
+ RAII_VAR(struct event_session *, session, NULL, ao2_cleanup);
+
+ session = ao2_alloc(sizeof(*session), session_dtor);
+
+ session->ws_session = ws_session;
+ session->websocket_apps =
+ ast_str_container_alloc(APPS_NUM_BUCKETS);
+
+ if (!session->websocket_apps) {
+ return NULL;
+ }
+
+ ao2_ref(session, +1);
+ return session;
+}
+
+/*!
+ * \brief Callback handler for Stasis application messages.
+ */
+static void app_handler(void *data, const char *app_name,
+ struct ast_json *message)
+{
+ struct event_session *session = data;
+ int res;
+ const char *msg_type = S_OR(
+ ast_json_string_get(ast_json_object_get(message, "type")),
+ "");
+ const char *msg_application = S_OR(
+ ast_json_string_get(ast_json_object_get(message, "application")),
+ "");
+
+ /* Determine if we've been replaced */
+ if (strcmp(msg_type, "ApplicationReplaced") == 0 &&
+ strcmp(msg_application, app_name) == 0) {
+ ao2_find(session->websocket_apps, msg_application,
+ OBJ_UNLINK | OBJ_NODATA);
+ }
+
+ res = ast_json_object_set(message, "application",
+ ast_json_string_create(app_name));
+ if(res != 0) {
+ return;
+ }
+
+ ao2_lock(session);
+ if (session->ws_session) {
+ ast_ari_websocket_session_write(session->ws_session, message);
+ }
+ ao2_unlock(session);
+}
+
+/*!
+ * \brief Register for all of the apps given.
+ * \param session Session info struct.
+ * \param app_list Comma seperated list of app names to register.
+ */
+static int session_register_apps(struct event_session *session,
+ const char *app_list)
+{
+ RAII_VAR(char *, to_free, NULL, ast_free);
+ char *apps, *app_name;
+ SCOPED_AO2LOCK(lock, session);
+
+ ast_assert(session->ws_session != NULL);
+ ast_assert(session->websocket_apps != NULL);
+
+ if (!app_list) {
+ return -1;
+ }
+
+ to_free = apps = ast_strdup(app_list);
+ if (!apps) {
+ ast_ari_websocket_session_write(session->ws_session, ast_ari_oom_json());
+ return -1;
+ }
+ while ((app_name = strsep(&apps, ","))) {
+ if (ast_str_container_add(session->websocket_apps, app_name)) {
+ ast_ari_websocket_session_write(session->ws_session, ast_ari_oom_json());
+ return -1;
+ }
+
+ stasis_app_register(app_name, app_handler, session);
+ }
+ return 0;
+}
+
+void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *ws_session,
+ struct ast_variable *headers,
+ struct ast_event_websocket_args *args)
+{
+ RAII_VAR(struct event_session *, session, NULL, session_cleanup);
+ struct ast_json *msg;
+ int res;
+
+ ast_debug(3, "/events WebSocket connection\n");
+
+ session = session_create(ws_session);
+ if (!session) {
+ ast_ari_websocket_session_write(ws_session, ast_ari_oom_json());
+ return;
+ }
+
+ if (!args->app) {
+ RAII_VAR(struct ast_json *, msg, NULL, ast_json_unref);
+
+ msg = ast_json_pack("{s: s, s: [s]}",
+ "type", "MissingParams",
+ "params", "app");
+ if (!msg) {
+ msg = ast_json_ref(ast_ari_oom_json());
+ }
+
+ ast_ari_websocket_session_write(session->ws_session, msg);
+ return;
+ }
+
+ res = session_register_apps(session, args->app);
+ if (res != 0) {
+ ast_ari_websocket_session_write(ws_session, ast_ari_oom_json());
+ return;
+ }
+
+ /* We don't process any input, but we'll consume it waiting for EOF */
+ while ((msg = ast_ari_websocket_session_read(ws_session))) {
+ ast_json_unref(msg);
+ }
+}
diff --git a/res/ari/resource_events.h b/res/ari/resource_events.h
new file mode 100644
index 000000000..554ed9a87
--- /dev/null
+++ b/res/ari/resource_events.h
@@ -0,0 +1,56 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - declares stubs to be implemented in
+ * res/ari/resource_events.c
+ *
+ * WebSocket resource
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_resource.h.mustache
+ */
+
+#ifndef _ASTERISK_RESOURCE_EVENTS_H
+#define _ASTERISK_RESOURCE_EVENTS_H
+
+#include "asterisk/ari.h"
+
+/*! \brief Argument struct for ast_ari_event_websocket() */
+struct ast_event_websocket_args {
+ /*! \brief Comma seperated list of applications to subscribe to. */
+ const char *app;
+};
+/*!
+ * \brief WebSocket connection for events.
+ *
+ * \param session ARI WebSocket.
+ * \param headers HTTP headers.
+ * \param args Swagger parameters.
+ */
+void ast_ari_websocket_event_websocket(struct ast_ari_websocket_session *session, struct ast_variable *headers, struct ast_event_websocket_args *args);
+
+#endif /* _ASTERISK_RESOURCE_EVENTS_H */
diff --git a/res/ari/resource_playback.c b/res/ari/resource_playback.c
new file mode 100644
index 000000000..64afe10c1
--- /dev/null
+++ b/res/ari/resource_playback.c
@@ -0,0 +1,137 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief /api-docs/playback.{format} implementation- Playback control resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/stasis_app_playback.h"
+#include "resource_playback.h"
+
+void ast_ari_get_playback(struct ast_variable *headers,
+ struct ast_get_playback_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+
+ playback = stasis_app_playback_find_by_id(args->playback_id);
+ if (playback == NULL) {
+ ast_ari_response_error(response, 404, "Not Found",
+ "Playback not found");
+ return;
+ }
+
+ json = stasis_app_playback_to_json(playback);
+ if (json == NULL) {
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Error building response");
+ return;
+ }
+
+ ast_ari_response_ok(response, ast_json_ref(json));
+}
+void ast_ari_stop_playback(struct ast_variable *headers,
+ struct ast_stop_playback_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
+ enum stasis_playback_oper_results res;
+
+ playback = stasis_app_playback_find_by_id(args->playback_id);
+ if (playback == NULL) {
+ ast_ari_response_error(response, 404, "Not Found",
+ "Playback not found");
+ return;
+ }
+
+ res = stasis_app_playback_operation(playback, STASIS_PLAYBACK_STOP);
+
+ switch (res) {
+ case STASIS_PLAYBACK_OPER_OK:
+ ast_ari_response_no_content(response);
+ return;
+ case STASIS_PLAYBACK_OPER_FAILED:
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Could not stop playback");
+ return;
+ case STASIS_PLAYBACK_OPER_NOT_PLAYING:
+ /* Stop operation should be valid even when not playing */
+ ast_assert(0);
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Could not stop playback");
+ return;
+ }
+}
+void ast_ari_control_playback(struct ast_variable *headers,
+ struct ast_control_playback_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
+ enum stasis_app_playback_media_operation oper;
+ enum stasis_playback_oper_results res;
+
+ if (strcmp(args->operation, "unpause") == 0) {
+ oper = STASIS_PLAYBACK_UNPAUSE;
+ } else if (strcmp(args->operation, "pause") == 0) {
+ oper = STASIS_PLAYBACK_PAUSE;
+ } else if (strcmp(args->operation, "restart") == 0) {
+ oper = STASIS_PLAYBACK_RESTART;
+ } else if (strcmp(args->operation, "reverse") == 0) {
+ oper = STASIS_PLAYBACK_REVERSE;
+ } else if (strcmp(args->operation, "forward") == 0) {
+ oper = STASIS_PLAYBACK_FORWARD;
+ } else {
+ ast_ari_response_error(response, 400,
+ "Bad Request", "Invalid operation %s",
+ args->operation);
+ return;
+
+ }
+
+ playback = stasis_app_playback_find_by_id(args->playback_id);
+ if (playback == NULL) {
+ ast_ari_response_error(response, 404, "Not Found",
+ "Playback not found");
+ return;
+ }
+
+ res = stasis_app_playback_operation(playback, oper);
+
+ switch (res) {
+ case STASIS_PLAYBACK_OPER_OK:
+ ast_ari_response_no_content(response);
+ return;
+ case STASIS_PLAYBACK_OPER_FAILED:
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Could not %s playback",
+ args->operation);
+ return;
+ case STASIS_PLAYBACK_OPER_NOT_PLAYING:
+ ast_ari_response_error(response, 409, "Conflict",
+ "Can only %s while media is playing", args->operation);
+ return;
+ }
+}
diff --git a/res/ari/resource_playback.h b/res/ari/resource_playback.h
new file mode 100644
index 000000000..c606a5caf
--- /dev/null
+++ b/res/ari/resource_playback.h
@@ -0,0 +1,84 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - declares stubs to be implemented in
+ * res/ari/resource_playback.c
+ *
+ * Playback control resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_resource.h.mustache
+ */
+
+#ifndef _ASTERISK_RESOURCE_PLAYBACK_H
+#define _ASTERISK_RESOURCE_PLAYBACK_H
+
+#include "asterisk/ari.h"
+
+/*! \brief Argument struct for ast_ari_get_playback() */
+struct ast_get_playback_args {
+ /*! \brief Playback's id */
+ const char *playback_id;
+};
+/*!
+ * \brief Get a playback's details.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_playback(struct ast_variable *headers, struct ast_get_playback_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_stop_playback() */
+struct ast_stop_playback_args {
+ /*! \brief Playback's id */
+ const char *playback_id;
+};
+/*!
+ * \brief Stop a playback.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_stop_playback(struct ast_variable *headers, struct ast_stop_playback_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_control_playback() */
+struct ast_control_playback_args {
+ /*! \brief Playback's id */
+ const char *playback_id;
+ /*! \brief Operation to perform on the playback. */
+ const char *operation;
+};
+/*!
+ * \brief Get a playback's details.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_control_playback(struct ast_variable *headers, struct ast_control_playback_args *args, struct ast_ari_response *response);
+
+#endif /* _ASTERISK_RESOURCE_PLAYBACK_H */
diff --git a/res/ari/resource_recordings.c b/res/ari/resource_recordings.c
new file mode 100644
index 000000000..46439ff0b
--- /dev/null
+++ b/res/ari/resource_recordings.c
@@ -0,0 +1,97 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief /api-docs/recordings.{format} implementation- Recording resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/stasis_app_recording.h"
+#include "resource_recordings.h"
+
+void ast_ari_get_stored_recordings(struct ast_variable *headers, struct ast_get_stored_recordings_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_get_stored_recordings\n");
+}
+void ast_ari_get_stored_recording(struct ast_variable *headers, struct ast_get_stored_recording_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_get_stored_recording\n");
+}
+void ast_ari_delete_stored_recording(struct ast_variable *headers, struct ast_delete_stored_recording_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_delete_stored_recording\n");
+}
+void ast_ari_get_live_recordings(struct ast_variable *headers, struct ast_get_live_recordings_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_get_live_recordings\n");
+}
+
+void ast_ari_get_live_recording(struct ast_variable *headers,
+ struct ast_get_live_recording_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
+ RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
+
+ recording = stasis_app_recording_find_by_name(args->recording_name);
+ if (recording == NULL) {
+ ast_ari_response_error(response, 404, "Not Found",
+ "Recording not found");
+ return;
+ }
+
+ json = stasis_app_recording_to_json(recording);
+ if (json == NULL) {
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Error building response");
+ return;
+ }
+
+ ast_ari_response_ok(response, ast_json_ref(json));
+}
+
+void ast_ari_cancel_recording(struct ast_variable *headers, struct ast_cancel_recording_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_cancel_recording\n");
+}
+void ast_ari_stop_recording(struct ast_variable *headers, struct ast_stop_recording_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_stop_recording\n");
+}
+void ast_ari_pause_recording(struct ast_variable *headers, struct ast_pause_recording_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_pause_recording\n");
+}
+void ast_ari_unpause_recording(struct ast_variable *headers, struct ast_unpause_recording_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_unpause_recording\n");
+}
+void ast_ari_mute_recording(struct ast_variable *headers, struct ast_mute_recording_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_mute_recording\n");
+}
+void ast_ari_unmute_recording(struct ast_variable *headers, struct ast_unmute_recording_args *args, struct ast_ari_response *response)
+{
+ ast_log(LOG_ERROR, "TODO: ast_ari_unmute_recording\n");
+}
diff --git a/res/ari/resource_recordings.h b/res/ari/resource_recordings.h
new file mode 100644
index 000000000..e3ee88be8
--- /dev/null
+++ b/res/ari/resource_recordings.h
@@ -0,0 +1,186 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - declares stubs to be implemented in
+ * res/ari/resource_recordings.c
+ *
+ * Recording resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_resource.h.mustache
+ */
+
+#ifndef _ASTERISK_RESOURCE_RECORDINGS_H
+#define _ASTERISK_RESOURCE_RECORDINGS_H
+
+#include "asterisk/ari.h"
+
+/*! \brief Argument struct for ast_ari_get_stored_recordings() */
+struct ast_get_stored_recordings_args {
+};
+/*!
+ * \brief List recordings that are complete.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_stored_recordings(struct ast_variable *headers, struct ast_get_stored_recordings_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_stored_recording() */
+struct ast_get_stored_recording_args {
+ /*! \brief The name of the recording */
+ const char *recording_name;
+};
+/*!
+ * \brief Get a stored recording's details.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_stored_recording(struct ast_variable *headers, struct ast_get_stored_recording_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_delete_stored_recording() */
+struct ast_delete_stored_recording_args {
+ /*! \brief The name of the recording */
+ const char *recording_name;
+};
+/*!
+ * \brief Delete a stored recording.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_delete_stored_recording(struct ast_variable *headers, struct ast_delete_stored_recording_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_live_recordings() */
+struct ast_get_live_recordings_args {
+};
+/*!
+ * \brief List libe recordings.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_live_recordings(struct ast_variable *headers, struct ast_get_live_recordings_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_live_recording() */
+struct ast_get_live_recording_args {
+ /*! \brief The name of the recording */
+ const char *recording_name;
+};
+/*!
+ * \brief List live recordings.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_live_recording(struct ast_variable *headers, struct ast_get_live_recording_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_cancel_recording() */
+struct ast_cancel_recording_args {
+ /*! \brief The name of the recording */
+ const char *recording_name;
+};
+/*!
+ * \brief Stop a live recording and discard it.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_cancel_recording(struct ast_variable *headers, struct ast_cancel_recording_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_stop_recording() */
+struct ast_stop_recording_args {
+ /*! \brief The name of the recording */
+ const char *recording_name;
+};
+/*!
+ * \brief Stop a live recording and store it.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_stop_recording(struct ast_variable *headers, struct ast_stop_recording_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_pause_recording() */
+struct ast_pause_recording_args {
+ /*! \brief The name of the recording */
+ const char *recording_name;
+};
+/*!
+ * \brief Pause a live recording.
+ *
+ * Pausing a recording suspends silence detection, which will be restarted when the recording is unpaused.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_pause_recording(struct ast_variable *headers, struct ast_pause_recording_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_unpause_recording() */
+struct ast_unpause_recording_args {
+ /*! \brief The name of the recording */
+ const char *recording_name;
+};
+/*!
+ * \brief Unpause a live recording.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_unpause_recording(struct ast_variable *headers, struct ast_unpause_recording_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_mute_recording() */
+struct ast_mute_recording_args {
+ /*! \brief The name of the recording */
+ const char *recording_name;
+};
+/*!
+ * \brief Mute a live recording.
+ *
+ * Muting a recording suspends silence detection, which will be restarted when the recording is unmuted.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_mute_recording(struct ast_variable *headers, struct ast_mute_recording_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_unmute_recording() */
+struct ast_unmute_recording_args {
+ /*! \brief The name of the recording */
+ const char *recording_name;
+};
+/*!
+ * \brief Unmute a live recording.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_unmute_recording(struct ast_variable *headers, struct ast_unmute_recording_args *args, struct ast_ari_response *response);
+
+#endif /* _ASTERISK_RESOURCE_RECORDINGS_H */
diff --git a/res/ari/resource_sounds.c b/res/ari/resource_sounds.c
new file mode 100644
index 000000000..f77c8a227
--- /dev/null
+++ b/res/ari/resource_sounds.c
@@ -0,0 +1,220 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief /api-docs/sounds.{format} implementation- Sound resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "resource_sounds.h"
+#include "asterisk/media_index.h"
+#include "asterisk/sounds_index.h"
+#include "asterisk/format.h"
+#include "asterisk/format_cap.h"
+#include "asterisk/json.h"
+
+/*! \brief arguments that are necessary for adding format/lang pairs */
+struct lang_format_info {
+ struct ast_json *format_list; /*!< The embedded array to which format/lang pairs should be added */
+ const char *filename; /*!< Name of the file for which to add format/lang pairs */
+ const char *format_filter; /*!< Format filter provided in the request */
+};
+
+/*! \brief Add format/lang pairs to the array embedded in the sound object */
+static int add_format_information_cb(void *obj, void *arg, int flags)
+{
+ char *language = obj;
+ struct lang_format_info *args = arg;
+ struct ast_format format;
+ RAII_VAR(struct ast_format_cap *, cap, NULL, ast_format_cap_destroy);
+ RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);
+
+ if (!sounds_index) {
+ return CMP_STOP;
+ }
+
+ cap = ast_media_get_format_cap(sounds_index, args->filename, language);
+ if (!cap) {
+ return CMP_STOP;
+ }
+
+ ast_format_cap_iter_start(cap);
+ while (!ast_format_cap_iter_next(cap, &format)) {
+ struct ast_json *lang_format_pair;
+ const char *format_name = ast_getformatname(&format);
+
+ if (!ast_strlen_zero(args->format_filter)
+ && strcmp(args->format_filter, format_name)) {
+ continue;
+ }
+
+ lang_format_pair = ast_json_pack("{s: s, s: s}",
+ "language", language,
+ "format", format_name);
+ if (!lang_format_pair) {
+ ast_format_cap_iter_end(cap);
+ return CMP_STOP;
+ }
+
+ ast_json_array_append(args->format_list, lang_format_pair);
+ }
+ ast_format_cap_iter_end(cap);
+ return 0;
+}
+
+/*! \brief Filter out all languages not matching the specified language */
+static int filter_langs_cb(void *obj, void *arg, int flags)
+{
+ char *lang_filter = arg;
+ char *lang = obj;
+ if (strcmp(lang, lang_filter)) {
+ return CMP_MATCH;
+ }
+ return 0;
+}
+
+/*! \brief Generate a Sound structure as documented in sounds.json for the specified filename */
+static struct ast_json *create_sound_blob(const char *filename, struct ast_get_sounds_args *args)
+{
+ RAII_VAR(struct ast_json *, sound, NULL, ast_json_unref);
+ RAII_VAR(struct ao2_container *, languages, NULL, ao2_cleanup);
+ const char *description;
+ struct ast_json *format_lang_list;
+ struct lang_format_info info;
+ RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);
+
+ if (!sounds_index) {
+ return NULL;
+ }
+
+ description = ast_media_get_description(sounds_index, filename, "en");
+ if (ast_strlen_zero(description)) {
+ sound = ast_json_pack("{s: s, s: []}",
+ "id", filename,
+ "formats");
+ } else {
+ sound = ast_json_pack("{s: s, s: s, s: []}",
+ "id", filename,
+ "text", description,
+ "formats");
+ }
+ if (!sound) {
+ return NULL;
+ }
+
+ format_lang_list = ast_json_object_get(sound, "formats");
+ if (!format_lang_list) {
+ return NULL;
+ }
+
+ languages = ast_media_get_variants(sounds_index, filename);
+ if (!languages || !ao2_container_count(languages)) {
+ return NULL;
+ }
+
+ /* filter requested languages */
+ if (args && !ast_strlen_zero(args->lang)) {
+ char *lang_filter = ast_strdupa(args->lang);
+ ao2_callback(languages, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, filter_langs_cb, lang_filter);
+ if (!languages || !ao2_container_count(languages)) {
+ return NULL;
+ }
+ }
+
+ info.filename = filename;
+ info.format_list = format_lang_list;
+ info.format_filter = NULL;
+ if (args) {
+ info.format_filter = args->format;
+ }
+ ao2_callback(languages, OBJ_NODATA, add_format_information_cb, &info);
+
+ /* no format/lang pairs for this sound so nothing to return */
+ if (!ast_json_array_size(format_lang_list)) {
+ return NULL;
+ }
+
+ return ast_json_ref(sound);
+}
+
+/*! \brief Generate a Sound structure and append it to the output blob */
+static int append_sound_cb(void *obj, void *arg, void *data, int flags)
+{
+ struct ast_json *sounds_array = arg;
+ char *filename = obj;
+ struct ast_get_sounds_args *args = data;
+ struct ast_json *sound_blob = create_sound_blob(filename, args);
+ if (!sound_blob) {
+ return 0;
+ }
+
+ ast_json_array_append(sounds_array, sound_blob);
+ return 0;
+}
+
+void ast_ari_get_sounds(struct ast_variable *headers, struct ast_get_sounds_args *args, struct ast_ari_response *response)
+{
+ RAII_VAR(struct ao2_container *, sound_files, NULL, ao2_cleanup);
+ struct ast_json *sounds_blob;
+ RAII_VAR(struct ast_media_index *, sounds_index, ast_sounds_get_index(), ao2_cleanup);
+
+ if (!sounds_index) {
+ ast_ari_response_error(response, 500, "Internal Error", "Sounds index not available");
+ return;
+ }
+
+ sound_files = ast_media_get_media(sounds_index);
+ if (!sound_files) {
+ ast_ari_response_error(response, 500, "Internal Error", "Allocation Error");
+ return;
+ }
+
+ sounds_blob = ast_json_array_create();
+ if (!sounds_blob) {
+ ast_ari_response_error(response, 500, "Internal Error", "Allocation Error");
+ return;
+ }
+
+ ao2_callback_data(sound_files, OBJ_NODATA, append_sound_cb, sounds_blob, args);
+
+ if (!ast_json_array_size(sounds_blob)) {
+ ast_ari_response_error(response, 404, "Not Found", "No sounds found that matched the query");
+ return;
+ }
+
+ ast_ari_response_ok(response, sounds_blob);
+}
+
+void ast_ari_get_stored_sound(struct ast_variable *headers, struct ast_get_stored_sound_args *args, struct ast_ari_response *response)
+{
+ struct ast_json *sound_blob;
+
+ sound_blob = create_sound_blob(args->sound_id, NULL);
+ if (!sound_blob) {
+ ast_ari_response_error(response, 404, "Not Found", "Sound not found");
+ return;
+ }
+
+ ast_ari_response_ok(response, sound_blob);
+}
diff --git a/res/ari/resource_sounds.h b/res/ari/resource_sounds.h
new file mode 100644
index 000000000..7cb22fb71
--- /dev/null
+++ b/res/ari/resource_sounds.h
@@ -0,0 +1,69 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2012 - 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Generated file - declares stubs to be implemented in
+ * res/ari/resource_sounds.c
+ *
+ * Sound resources
+ *
+ * \author David M. Lee, II <dlee@digium.com>
+ */
+
+/*
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * !!!!! DO NOT EDIT !!!!!
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * This file is generated by a mustache template. Please see the original
+ * template in rest-api-templates/ari_resource.h.mustache
+ */
+
+#ifndef _ASTERISK_RESOURCE_SOUNDS_H
+#define _ASTERISK_RESOURCE_SOUNDS_H
+
+#include "asterisk/ari.h"
+
+/*! \brief Argument struct for ast_ari_get_sounds() */
+struct ast_get_sounds_args {
+ const char *lang;
+ const char *format;
+};
+/*!
+ * \brief List all sounds.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_sounds(struct ast_variable *headers, struct ast_get_sounds_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_get_stored_sound() */
+struct ast_get_stored_sound_args {
+ /*! \brief Sound's id */
+ const char *sound_id;
+};
+/*!
+ * \brief Get a sound's details.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_get_stored_sound(struct ast_variable *headers, struct ast_get_stored_sound_args *args, struct ast_ari_response *response);
+
+#endif /* _ASTERISK_RESOURCE_SOUNDS_H */