summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorScott Griepentrog <sgriepentrog@digium.com>2014-03-07 15:47:55 +0000
committerScott Griepentrog <sgriepentrog@digium.com>2014-03-07 15:47:55 +0000
commit80ef9a21b9d91ff0bafc304923bc29effa230b00 (patch)
treea67db39a4c17a4b01a87201ef37ffdc43189c119 /res
parentd3ac8b8a0e70049af7b5552c4dfd8adc2cc5df11 (diff)
uniqueid: channel linkedid, ami, ari object creation with id's
Much needed was a way to assign id to objects on creation, and much change was necessary to accomplish it. Channel uniqueids and linkedids are split into separate string and creation time components without breaking linkedid propgation. This allowed the uniqueid to be specified by the user interface - and those values are now carried through to channel creation, adding the assignedids value to every function in the chain including the channel drivers. For local channels, the second channel can be specified or left to default to a ;2 suffix of first. In ARI, bridge, playback, and snoop objects can also be created with a specified uniqueid. Along the way, the args order to allocating channels was fixed in chan_mgcp and chan_gtalk, and linkedid is no longer lost as masquerade occurs. (closes issue ASTERISK-23120) Review: https://reviewboard.asterisk.org/r/3191/ ........ Merged revisions 410157 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410158 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res')
-rw-r--r--res/ari/resource_bridges.c52
-rw-r--r--res/ari/resource_bridges.h32
-rw-r--r--res/ari/resource_channels.c254
-rw-r--r--res/ari/resource_channels.h126
-rw-r--r--res/parking/parking_applications.c2
-rw-r--r--res/parking/parking_bridge.c2
-rw-r--r--res/parking/parking_bridge_features.c2
-rw-r--r--res/parking/parking_tests.c2
-rw-r--r--res/res_ari_bridges.c111
-rw-r--r--res/res_ari_channels.c451
-rw-r--r--res/res_calendar.c5
-rw-r--r--res/res_calendar_caldav.c1
-rw-r--r--res/res_calendar_ews.c1
-rw-r--r--res/res_calendar_exchange.c1
-rw-r--r--res/res_calendar_icalendar.c1
-rw-r--r--res/res_clioriginate.c4
-rw-r--r--res/res_stasis.c6
-rw-r--r--res/res_stasis_playback.c16
-rw-r--r--res/res_stasis_snoop.c5
-rw-r--r--res/stasis/control.c2
20 files changed, 992 insertions, 84 deletions
diff --git a/res/ari/resource_bridges.c b/res/ari/resource_bridges.c
index a8f2c3c04..418b7c8cb 100644
--- a/res/ari/resource_bridges.c
+++ b/res/ari/resource_bridges.c
@@ -314,7 +314,7 @@ static struct ast_channel *prepare_bridge_media_channel(const char *type)
return NULL;
}
- return ast_request(type, cap, NULL, "ARI", NULL);
+ return ast_request(type, cap, NULL, NULL, "ARI", NULL);
}
void ast_ari_bridges_play(struct ast_variable *headers,
@@ -370,7 +370,7 @@ void ast_ari_bridges_play(struct ast_variable *headers,
playback = stasis_app_control_play_uri(control, args->media, language,
args->bridge_id, STASIS_PLAYBACK_TARGET_BRIDGE, args->skipms,
- args->offsetms);
+ args->offsetms, NULL);
if (!playback) {
ast_ari_response_alloc_failed(response);
@@ -697,7 +697,7 @@ void ast_ari_bridges_create(struct ast_variable *headers,
struct ast_ari_bridges_create_args *args,
struct ast_ari_response *response)
{
- RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type, args->name), ao2_cleanup);
+ RAII_VAR(struct ast_bridge *, bridge, stasis_app_bridge_create(args->type, args->name, args->bridge_id), ao2_cleanup);
RAII_VAR(struct ast_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
if (!bridge) {
@@ -718,3 +718,49 @@ void ast_ari_bridges_create(struct ast_variable *headers,
ast_ari_response_ok(response,
ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
}
+
+void ast_ari_bridges_create_or_update_with_id(struct ast_variable *headers,
+ struct ast_ari_bridges_create_or_update_with_id_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_bridge_snapshot *, snapshot, NULL, ao2_cleanup);
+
+ if (bridge) {
+ /* update */
+ if (strcmp(args->name, bridge->name)) {
+ ast_ari_response_error(
+ response, 500, "Internal Error",
+ "Changing bridge name is not implemented");
+ return;
+ }
+ if (!ast_strlen_zero(args->type)) {
+ ast_ari_response_error(
+ response, 500, "Internal Error",
+ "Changing bridge type is not implemented");
+ return;
+ }
+ ast_ari_response_ok(response,
+ ast_bridge_snapshot_to_json(snapshot, stasis_app_get_sanitizer()));
+ return;
+ }
+
+ bridge = stasis_app_bridge_create(args->type, args->name, args->bridge_id);
+ 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, stasis_app_get_sanitizer()));
+}
diff --git a/res/ari/resource_bridges.h b/res/ari/resource_bridges.h
index 38ccb294b..1b8782310 100644
--- a/res/ari/resource_bridges.h
+++ b/res/ari/resource_bridges.h
@@ -54,6 +54,8 @@ void ast_ari_bridges_list(struct ast_variable *headers, struct ast_ari_bridges_l
struct ast_ari_bridges_create_args {
/*! \brief Type of bridge to create. */
const char *type;
+ /*! \brief Unique ID to give to the bridge being created. */
+ const char *bridge_id;
/*! \brief Name to give to the bridge being created. */
const char *name;
};
@@ -78,6 +80,36 @@ int ast_ari_bridges_create_parse_body(
* \param[out] response HTTP response
*/
void ast_ari_bridges_create(struct ast_variable *headers, struct ast_ari_bridges_create_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_bridges_create_or_update_with_id() */
+struct ast_ari_bridges_create_or_update_with_id_args {
+ /*! \brief Set the type of bridge. */
+ const char *type;
+ /*! \brief Unique ID to give to the bridge being created. */
+ const char *bridge_id;
+ /*! \brief Set the name of the bridge. */
+ const char *name;
+};
+/*!
+ * \brief Body parsing function for /bridges/{bridgeId}.
+ * \param body The JSON body from which to parse parameters.
+ * \param[out] args The args structure to parse into.
+ * \retval zero on success
+ * \retval non-zero on failure
+ */
+int ast_ari_bridges_create_or_update_with_id_parse_body(
+ struct ast_json *body,
+ struct ast_ari_bridges_create_or_update_with_id_args *args);
+
+/*!
+ * \brief Create a new bridge or updates an existing one.
+ *
+ * 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_bridges_create_or_update_with_id(struct ast_variable *headers, struct ast_ari_bridges_create_or_update_with_id_args *args, struct ast_ari_response *response);
/*! \brief Argument struct for ast_ari_bridges_get() */
struct ast_ari_bridges_get_args {
/*! \brief Bridge's id */
diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c
index 35520702a..2d074a16a 100644
--- a/res/ari/resource_channels.c
+++ b/res/ari/resource_channels.c
@@ -354,8 +354,13 @@ void ast_ari_channels_stop_silence(struct ast_variable *headers,
ast_ari_response_no_content(response);
}
-void ast_ari_channels_play(struct ast_variable *headers,
- struct ast_ari_channels_play_args *args,
+static void ari_channels_handle_play(
+ const char *args_channel_id,
+ const char *args_media,
+ const char *args_lang,
+ int args_offsetms,
+ int args_skipms,
+ const char *args_playback_id,
struct ast_ari_response *response)
{
RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
@@ -367,7 +372,7 @@ void ast_ari_channels_play(struct ast_variable *headers,
ast_assert(response != NULL);
- control = find_control(response, args->channel_id);
+ control = find_control(response, args_channel_id);
if (control == NULL) {
/* Response filled in by find_control */
return;
@@ -381,24 +386,24 @@ void ast_ari_channels_play(struct ast_variable *headers,
return;
}
- if (args->skipms < 0) {
+ if (args_skipms < 0) {
ast_ari_response_error(
response, 400, "Bad Request",
"skipms cannot be negative");
return;
}
- if (args->offsetms < 0) {
+ if (args_offsetms < 0) {
ast_ari_response_error(
response, 400, "Bad Request",
"offsetms cannot be negative");
return;
}
- language = S_OR(args->lang, snapshot->language);
+ 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);
+ playback = stasis_app_control_play_uri(control, args_media, language,
+ args_channel_id, STASIS_PLAYBACK_TARGET_CHANNEL, args_skipms, args_offsetms, args_playback_id);
if (!playback) {
ast_ari_response_error(
response, 500, "Internal Server Error",
@@ -426,6 +431,34 @@ void ast_ari_channels_play(struct ast_variable *headers,
ast_ari_response_created(response, playback_url, json);
}
+void ast_ari_channels_play(struct ast_variable *headers,
+ struct ast_ari_channels_play_args *args,
+ struct ast_ari_response *response)
+{
+ ari_channels_handle_play(
+ args->channel_id,
+ args->media,
+ args->lang,
+ args->offsetms,
+ args->skipms,
+ args->playback_id,
+ response);
+}
+
+void ast_ari_channels_play_with_id(struct ast_variable *headers,
+ struct ast_ari_channels_play_with_id_args *args,
+ struct ast_ari_response *response)
+{
+ ari_channels_handle_play(
+ args->channel_id,
+ args->media,
+ args->lang,
+ args->offsetms,
+ args->skipms,
+ args->playback_id,
+ response);
+}
+
void ast_ari_channels_record(struct ast_variable *headers,
struct ast_ari_channels_record_args *args,
struct ast_ari_response *response)
@@ -583,7 +616,7 @@ void ast_ari_channels_get(struct ast_variable *headers,
}
msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
- args->channel_id);
+ args->channel_id);
if (!msg) {
ast_ari_response_error(
response, 404, "Not Found",
@@ -698,8 +731,8 @@ static int json_to_ast_variables(struct ast_json *json_variables, struct ast_var
struct ast_variable *new_var;
new_var = ast_variable_new(ast_json_object_iter_key(it_json_var),
- ast_json_string_get(ast_json_object_iter_value(it_json_var)),
- "");
+ ast_json_string_get(ast_json_object_iter_value(it_json_var)),
+ "");
if (!new_var) {
ast_variables_destroy(*variables);
*variables = NULL;
@@ -718,8 +751,17 @@ static int json_to_ast_variables(struct ast_json *json_variables, struct ast_var
return 0;
}
-void ast_ari_channels_originate(struct ast_variable *headers,
- struct ast_ari_channels_originate_args *args,
+static void ari_channels_handle_originate_with_id(const char *args_endpoint,
+ const char *args_extension,
+ const char *args_context,
+ long args_priority,
+ const char *args_app,
+ const char *args_app_args,
+ const char *args_caller_id,
+ int args_timeout,
+ struct ast_variable *variables,
+ const char *args_channel_id,
+ const char *args_other_channel_id,
struct ast_ari_response *response)
{
char *dialtech;
@@ -731,10 +773,15 @@ void ast_ari_channels_originate(struct ast_variable *headers,
RAII_VAR(struct ast_format_cap *, cap,
ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_NOLOCK), ast_format_cap_destroy);
struct ast_format tmp_fmt;
- RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
char *stuff;
struct ast_channel *chan;
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+ struct ast_assigned_ids assignedids = {args_channel_id, args_other_channel_id};
+
+ if (strlen(assignedids.uniqueid) >= AST_MAX_UNIQUEID ||
+ strlen(assignedids.uniqueid2) >= AST_MAX_UNIQUEID) {
+ ast_log(LOG_WARNING, "Uniqueid length exceeds maximum of %d\n", AST_MAX_UNIQUEID);
+ }
if (!cap) {
ast_ari_response_alloc_failed(response);
@@ -742,28 +789,13 @@ void ast_ari_channels_originate(struct ast_variable *headers,
}
ast_format_cap_add(cap, ast_format_set(&tmp_fmt, AST_FORMAT_SLINEAR, 0));
- /* Parse any query parameters out of the body parameter */
- if (args->variables) {
- struct ast_json *json_variables;
-
- ast_ari_channels_originate_parse_body(args->variables, args);
- json_variables = ast_json_object_get(args->variables, "variables");
- if (json_variables) {
- if (json_to_ast_variables(json_variables, &variables)) {
- ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
- ast_ari_response_alloc_failed(response);
- return;
- }
- }
- }
-
- if (ast_strlen_zero(args->endpoint)) {
+ if (ast_strlen_zero(args_endpoint)) {
ast_ari_response_error(response, 400, "Bad Request",
"Endpoint must be specified");
return;
}
- dialtech = ast_strdupa(args->endpoint);
+ dialtech = ast_strdupa(args_endpoint);
if ((stuff = strchr(dialtech, '/'))) {
*stuff++ = '\0';
ast_copy_string(dialdevice, stuff, sizeof(dialdevice));
@@ -775,14 +807,14 @@ void ast_ari_channels_originate(struct ast_variable *headers,
return;
}
- if (args->timeout > 0) {
- timeout = args->timeout * 1000;
- } else if (args->timeout == -1) {
+ 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);
+ 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)) {
@@ -790,7 +822,7 @@ void ast_ari_channels_originate(struct ast_variable *headers,
}
}
- if (!ast_strlen_zero(args->app)) {
+ if (!ast_strlen_zero(args_app)) {
const char *app = "Stasis";
RAII_VAR(struct ast_str *, appdata, ast_str_create(64), ast_free);
@@ -800,19 +832,19 @@ void ast_ari_channels_originate(struct ast_variable *headers,
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);
+ 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, cap, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, variables, NULL, &chan)) {
+ if (ast_pbx_outgoing_app(dialtech, cap, dialdevice, timeout, app, ast_str_buffer(appdata), NULL, 0, cid_num, cid_name, variables, NULL, &chan, &assignedids)) {
ast_ari_response_alloc_failed(response);
return;
}
- } else if (!ast_strlen_zero(args->extension)) {
+ } else if (!ast_strlen_zero(args_extension)) {
/* originate a channel, sending it to an extension */
- if (ast_pbx_outgoing_exten(dialtech, cap, dialdevice, timeout, S_OR(args->context, "default"), args->extension, args->priority ? args->priority : 1, NULL, 0, cid_num, cid_name, variables, NULL, &chan, 0)) {
+ if (ast_pbx_outgoing_exten(dialtech, cap, dialdevice, timeout, S_OR(args_context, "default"), args_extension, args_priority ? args_priority : 1, NULL, 0, cid_num, cid_name, variables, NULL, &chan, 0, &assignedids)) {
ast_ari_response_alloc_failed(response);
return;
}
@@ -825,19 +857,91 @@ void ast_ari_channels_originate(struct ast_variable *headers,
snapshot = ast_channel_snapshot_create(chan);
ast_channel_unlock(chan);
- if (!ast_strlen_zero(args->app)) {
+ if (!ast_strlen_zero(args_app)) {
/* channel: + channel ID + null terminator */
char uri[9 + strlen(ast_channel_uniqueid(chan))];
const char *uris[1] = { uri, };
sprintf(uri, "channel:%s", ast_channel_uniqueid(chan));
- stasis_app_subscribe(args->app, uris, 1, NULL);
+ stasis_app_subscribe(args_app, uris, 1, NULL);
}
ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
ast_channel_unref(chan);
}
+void ast_ari_channels_originate_with_id(struct ast_variable *headers,
+ struct ast_ari_channels_originate_with_id_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
+
+ /* Parse any query parameters out of the body parameter */
+ if (args->variables) {
+ struct ast_json *json_variables;
+
+ ast_ari_channels_originate_with_id_parse_body(args->variables, args);
+ json_variables = ast_json_object_get(args->variables, "variables");
+ if (json_variables) {
+ if (json_to_ast_variables(json_variables, &variables)) {
+ ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+ }
+ }
+
+ ari_channels_handle_originate_with_id(
+ args->endpoint,
+ args->extension,
+ args->context,
+ args->priority,
+ args->app,
+ args->app_args,
+ args->caller_id,
+ args->timeout,
+ variables,
+ args->channel_id,
+ args->other_channel_id,
+ response);
+}
+
+void ast_ari_channels_originate(struct ast_variable *headers,
+ struct ast_ari_channels_originate_args *args,
+ struct ast_ari_response *response)
+{
+ RAII_VAR(struct ast_variable *, variables, NULL, ast_variables_destroy);
+
+ /* Parse any query parameters out of the body parameter */
+ if (args->variables) {
+ struct ast_json *json_variables;
+
+ ast_ari_channels_originate_parse_body(args->variables, args);
+ json_variables = ast_json_object_get(args->variables, "variables");
+ if (json_variables) {
+ if (json_to_ast_variables(json_variables, &variables)) {
+ ast_log(AST_LOG_ERROR, "Unable to convert 'variables' in JSON body to channel variables\n");
+ ast_ari_response_alloc_failed(response);
+ return;
+ }
+ }
+ }
+
+ ari_channels_handle_originate_with_id(
+ args->endpoint,
+ args->extension,
+ args->context,
+ args->priority,
+ args->app,
+ args->app_args,
+ args->caller_id,
+ args->timeout,
+ variables,
+ args->channel_id,
+ args->other_channel_id,
+ response);
+}
+
void ast_ari_channels_get_channel_var(struct ast_variable *headers,
struct ast_ari_channels_get_channel_var_args *args,
struct ast_ari_response *response)
@@ -902,7 +1006,14 @@ void ast_ari_channels_set_channel_var(struct ast_variable *headers,
ast_ari_response_no_content(response);
}
-void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari_channels_snoop_channel_args *args, struct ast_ari_response *response)
+static void ari_channels_handle_snoop_channel(
+ const char *args_channel_id,
+ const char *args_spy,
+ const char *args_whisper,
+ const char *args_app,
+ const char *args_app_args,
+ const char *args_snoop_id,
+ struct ast_ari_response *response)
{
enum stasis_app_snoop_direction spy, whisper;
RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_cleanup);
@@ -911,13 +1022,13 @@ void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari
ast_assert(response != NULL);
- if (ast_strlen_zero(args->spy) || !strcmp(args->spy, "none")) {
+ if (ast_strlen_zero(args_spy) || !strcmp(args_spy, "none")) {
spy = STASIS_SNOOP_DIRECTION_NONE;
- } else if (!strcmp(args->spy, "both")) {
+ } else if (!strcmp(args_spy, "both")) {
spy = STASIS_SNOOP_DIRECTION_BOTH;
- } else if (!strcmp(args->spy, "out")) {
+ } else if (!strcmp(args_spy, "out")) {
spy = STASIS_SNOOP_DIRECTION_OUT;
- } else if (!strcmp(args->spy, "in")) {
+ } else if (!strcmp(args_spy, "in")) {
spy = STASIS_SNOOP_DIRECTION_IN;
} else {
ast_ari_response_error(
@@ -926,13 +1037,13 @@ void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari
return;
}
- if (ast_strlen_zero(args->whisper) || !strcmp(args->whisper, "none")) {
+ if (ast_strlen_zero(args_whisper) || !strcmp(args_whisper, "none")) {
whisper = STASIS_SNOOP_DIRECTION_NONE;
- } else if (!strcmp(args->whisper, "both")) {
+ } else if (!strcmp(args_whisper, "both")) {
whisper = STASIS_SNOOP_DIRECTION_BOTH;
- } else if (!strcmp(args->whisper, "out")) {
+ } else if (!strcmp(args_whisper, "out")) {
whisper = STASIS_SNOOP_DIRECTION_OUT;
- } else if (!strcmp(args->whisper, "in")) {
+ } else if (!strcmp(args_whisper, "in")) {
whisper = STASIS_SNOOP_DIRECTION_IN;
} else {
ast_ari_response_error(
@@ -946,14 +1057,14 @@ void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari
response, 400, "Bad Request",
"Direction must be specified for at least spy or whisper");
return;
- } else if (ast_strlen_zero(args->app)) {
+ } else if (ast_strlen_zero(args_app)) {
ast_ari_response_error(
response, 400, "Bad Request",
"Application name is required");
return;
}
- chan = ast_channel_get_by_name(args->channel_id);
+ chan = ast_channel_get_by_name(args_channel_id);
if (chan == NULL) {
ast_ari_response_error(
response, 404, "Channel Not Found",
@@ -961,7 +1072,8 @@ void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari
return;
}
- snoop = stasis_app_control_snoop(chan, spy, whisper, args->app, args->app_args);
+ snoop = stasis_app_control_snoop(chan, spy, whisper, args_app, args_app_args,
+ args_snoop_id);
if (snoop == NULL) {
ast_ari_response_error(
response, 500, "Internal error",
@@ -972,3 +1084,31 @@ void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari
snapshot = ast_channel_snapshot_create(snoop);
ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
}
+
+void ast_ari_channels_snoop_channel(struct ast_variable *headers,
+ struct ast_ari_channels_snoop_channel_args *args,
+ struct ast_ari_response *response)
+{
+ ari_channels_handle_snoop_channel(
+ args->channel_id,
+ args->spy,
+ args->whisper,
+ args->app,
+ args->app_args,
+ args->snoop_id,
+ response);
+}
+
+void ast_ari_channels_snoop_channel_with_id(struct ast_variable *headers,
+ struct ast_ari_channels_snoop_channel_with_id_args *args,
+ struct ast_ari_response *response)
+{
+ ari_channels_handle_snoop_channel(
+ args->channel_id,
+ args->spy,
+ args->whisper,
+ args->app,
+ args->app_args,
+ args->snoop_id,
+ response);
+}
diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h
index 7f740a67c..cf48cee75 100644
--- a/res/ari/resource_channels.h
+++ b/res/ari/resource_channels.h
@@ -70,6 +70,10 @@ struct ast_ari_channels_originate_args {
int timeout;
/*! \brief The 'variables' key in the body object holds variable key/value pairs to set on the channel on creation. Other keys in the body object are interpreted as query parameters. Ex. { 'endpoint': 'SIP/Alice', 'variables': { 'CALLERID(name)': 'Alice' } } */
struct ast_json *variables;
+ /*! \brief The unique id to assign the channel on creation. */
+ const char *channel_id;
+ /*! \brief The unique id to assign the second channel when using local channels. */
+ const char *other_channel_id;
};
/*!
* \brief Body parsing function for /channels.
@@ -105,6 +109,52 @@ struct ast_ari_channels_get_args {
* \param[out] response HTTP response
*/
void ast_ari_channels_get(struct ast_variable *headers, struct ast_ari_channels_get_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_channels_originate_with_id() */
+struct ast_ari_channels_originate_with_id_args {
+ /*! \brief The unique id to assign the channel on creation. */
+ const char *channel_id;
+ /*! \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 that is subscribed to the originated channel, and passed 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 The 'variables' key in the body object holds variable key/value pairs to set on the channel on creation. Other keys in the body object are interpreted as query parameters. Ex. { 'endpoint': 'SIP/Alice', 'variables': { 'CALLERID(name)': 'Alice' } } */
+ struct ast_json *variables;
+ /*! \brief The unique id to assign the second channel when using local channels. */
+ const char *other_channel_id;
+};
+/*!
+ * \brief Body parsing function for /channels/{channelId}.
+ * \param body The JSON body from which to parse parameters.
+ * \param[out] args The args structure to parse into.
+ * \retval zero on success
+ * \retval non-zero on failure
+ */
+int ast_ari_channels_originate_with_id_parse_body(
+ struct ast_json *body,
+ struct ast_ari_channels_originate_with_id_args *args);
+
+/*!
+ * \brief Create a new channel (originate with id).
+ *
+ * The new channel is created immediately and a snapshot of it returned. If a Stasis application is provided it will be automatically subscribed to the originated channel for further events and updates.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_channels_originate_with_id(struct ast_variable *headers, struct ast_ari_channels_originate_with_id_args *args, struct ast_ari_response *response);
/*! \brief Argument struct for ast_ari_channels_hangup() */
struct ast_ari_channels_hangup_args {
/*! \brief Channel's id */
@@ -393,6 +443,8 @@ struct ast_ari_channels_play_args {
int offsetms;
/*! \brief Number of milliseconds to skip for forward/reverse operations. */
int skipms;
+ /*! \brief Playback ID. */
+ const char *playback_id;
};
/*!
* \brief Body parsing function for /channels/{channelId}/play.
@@ -415,6 +467,42 @@ int ast_ari_channels_play_parse_body(
* \param[out] response HTTP response
*/
void ast_ari_channels_play(struct ast_variable *headers, struct ast_ari_channels_play_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_channels_play_with_id() */
+struct ast_ari_channels_play_with_id_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief Playback ID. */
+ const char *playback_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 Body parsing function for /channels/{channelId}/play/{playbackId}.
+ * \param body The JSON body from which to parse parameters.
+ * \param[out] args The args structure to parse into.
+ * \retval zero on success
+ * \retval non-zero on failure
+ */
+int ast_ari_channels_play_with_id_parse_body(
+ struct ast_json *body,
+ struct ast_ari_channels_play_with_id_args *args);
+
+/*!
+ * \brief Start playback of media and specify the playbackId.
+ *
+ * The media URI may be any of a number of URI's. Currently sound: and recording: URI's are supported. 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_channels_play_with_id(struct ast_variable *headers, struct ast_ari_channels_play_with_id_args *args, struct ast_ari_response *response);
/*! \brief Argument struct for ast_ari_channels_record() */
struct ast_ari_channels_record_args {
/*! \brief Channel's id */
@@ -521,6 +609,8 @@ struct ast_ari_channels_snoop_channel_args {
const char *app;
/*! \brief The application arguments to pass to the Stasis application */
const char *app_args;
+ /*! \brief Unique ID to assign to snooping channel */
+ const char *snoop_id;
};
/*!
* \brief Body parsing function for /channels/{channelId}/snoop.
@@ -543,5 +633,41 @@ int ast_ari_channels_snoop_channel_parse_body(
* \param[out] response HTTP response
*/
void ast_ari_channels_snoop_channel(struct ast_variable *headers, struct ast_ari_channels_snoop_channel_args *args, struct ast_ari_response *response);
+/*! \brief Argument struct for ast_ari_channels_snoop_channel_with_id() */
+struct ast_ari_channels_snoop_channel_with_id_args {
+ /*! \brief Channel's id */
+ const char *channel_id;
+ /*! \brief Unique ID to assign to snooping channel */
+ const char *snoop_id;
+ /*! \brief Direction of audio to spy on */
+ const char *spy;
+ /*! \brief Direction of audio to whisper into */
+ const char *whisper;
+ /*! \brief Application the snooping channel is placed into */
+ const char *app;
+ /*! \brief The application arguments to pass to the Stasis application */
+ const char *app_args;
+};
+/*!
+ * \brief Body parsing function for /channels/{channelId}/snoop/{snoopId}.
+ * \param body The JSON body from which to parse parameters.
+ * \param[out] args The args structure to parse into.
+ * \retval zero on success
+ * \retval non-zero on failure
+ */
+int ast_ari_channels_snoop_channel_with_id_parse_body(
+ struct ast_json *body,
+ struct ast_ari_channels_snoop_channel_with_id_args *args);
+
+/*!
+ * \brief Start snooping.
+ *
+ * Snoop (spy/whisper) on a specific channel.
+ *
+ * \param headers HTTP headers
+ * \param args Swagger parameters
+ * \param[out] response HTTP response
+ */
+void ast_ari_channels_snoop_channel_with_id(struct ast_variable *headers, struct ast_ari_channels_snoop_channel_with_id_args *args, struct ast_ari_response *response);
#endif /* _ASTERISK_RESOURCE_CHANNELS_H */
diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c
index 2d481e421..85075bc5a 100644
--- a/res/parking/parking_applications.c
+++ b/res/parking/parking_applications.c
@@ -704,7 +704,7 @@ static void announce_to_dial(char *dial_string, char *announce_string, int parki
snprintf(buf, sizeof(buf), "%d", parkingspace);
oh.vars = ast_variable_new("_PARKEDAT", buf, "");
- dchan = __ast_request_and_dial(dial_tech, cap_slin, NULL, dial_string, 30000,
+ dchan = __ast_request_and_dial(dial_tech, cap_slin, NULL, NULL, dial_string, 30000,
&outstate,
parkee_snapshot->caller_number,
parkee_snapshot->caller_name,
diff --git a/res/parking/parking_bridge.c b/res/parking/parking_bridge.c
index bb9dbf30d..448d4ed5d 100644
--- a/res/parking/parking_bridge.c
+++ b/res/parking/parking_bridge.c
@@ -456,7 +456,7 @@ struct ast_bridge *bridge_parking_new(struct parking_lot *bridge_lot)
bridge = bridge_alloc(sizeof(struct ast_bridge_parking), &ast_bridge_parking_v_table);
bridge = bridge_base_init(bridge, AST_BRIDGE_CAPABILITY_HOLDING,
AST_BRIDGE_FLAG_MERGE_INHIBIT_TO | AST_BRIDGE_FLAG_MERGE_INHIBIT_FROM
- | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM, "Parking", bridge_lot->name);
+ | AST_BRIDGE_FLAG_SWAP_INHIBIT_FROM, "Parking", bridge_lot->name, NULL);
bridge = ast_bridge_parking_init(bridge, bridge_lot);
bridge = bridge_register(bridge);
return bridge;
diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c
index bf211a2bd..e9f814151 100644
--- a/res/parking/parking_bridge_features.c
+++ b/res/parking/parking_bridge_features.c
@@ -200,7 +200,7 @@ static struct ast_channel *park_local_transfer(struct ast_channel *parker, const
snprintf(destination, sizeof(destination), "%s@%s", exten, context);
/* Now we request that chan_local prepare to call the destination */
- parkee = ast_request("Local", ast_channel_nativeformats(parker), parker, destination,
+ parkee = ast_request("Local", ast_channel_nativeformats(parker), NULL, parker, destination,
&cause);
if (!parkee) {
return NULL;
diff --git a/res/parking/parking_tests.c b/res/parking/parking_tests.c
index f6767769a..ea7fd31d1 100644
--- a/res/parking/parking_tests.c
+++ b/res/parking/parking_tests.c
@@ -54,7 +54,7 @@ static const struct ast_party_caller alice_callerid = {
static struct ast_channel *create_alice_channel(void)
{
struct ast_channel *alice = ast_channel_alloc(0, AST_STATE_DOWN,
- "100", "Alice", "100", "100", "default", NULL, 0,
+ "100", "Alice", "100", "100", "default", NULL, NULL, 0,
CHANNEL_TECH_NAME "/Alice");
if (!alice) {
diff --git a/res/res_ari_bridges.c b/res/res_ari_bridges.c
index e1c9fe672..890a2ace5 100644
--- a/res/res_ari_bridges.c
+++ b/res/res_ari_bridges.c
@@ -112,6 +112,10 @@ int ast_ari_bridges_create_parse_body(
if (field) {
args->type = ast_json_string_get(field);
}
+ field = ast_json_object_get(body, "bridgeId");
+ if (field) {
+ args->bridge_id = ast_json_string_get(field);
+ }
field = ast_json_object_get(body, "name");
if (field) {
args->name = ast_json_string_get(field);
@@ -143,6 +147,9 @@ static void ast_ari_bridges_create_cb(
if (strcmp(i->name, "type") == 0) {
args.type = (i->value);
} else
+ if (strcmp(i->name, "bridgeId") == 0) {
+ args.bridge_id = (i->value);
+ } else
if (strcmp(i->name, "name") == 0) {
args.name = (i->value);
} else
@@ -199,6 +206,109 @@ static void ast_ari_bridges_create_cb(
fin: __attribute__((unused))
return;
}
+int ast_ari_bridges_create_or_update_with_id_parse_body(
+ struct ast_json *body,
+ struct ast_ari_bridges_create_or_update_with_id_args *args)
+{
+ struct ast_json *field;
+ /* Parse query parameters out of it */
+ field = ast_json_object_get(body, "type");
+ if (field) {
+ args->type = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "name");
+ if (field) {
+ args->name = ast_json_string_get(field);
+ }
+ return 0;
+}
+
+/*!
+ * \brief Parameter parsing callback for /bridges/{bridgeId}.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_bridges_create_or_update_with_id_cb(
+ struct ast_tcptls_session_instance *ser,
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct ast_ari_response *response)
+{
+ struct ast_ari_bridges_create_or_update_with_id_args args = {};
+ struct ast_variable *i;
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
+ for (i = get_params; i; i = i->next) {
+ if (strcmp(i->name, "type") == 0) {
+ args.type = (i->value);
+ } else
+ if (strcmp(i->name, "name") == 0) {
+ args.name = (i->value);
+ } else
+ {}
+ }
+ for (i = path_vars; i; i = i->next) {
+ if (strcmp(i->name, "bridgeId") == 0) {
+ args.bridge_id = (i->value);
+ } else
+ {}
+ }
+ /* Look for a JSON request entity */
+ body = ast_http_get_json(ser, headers);
+ if (!body) {
+ switch (errno) {
+ case EFBIG:
+ ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
+ goto fin;
+ case ENOMEM:
+ ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
+ goto fin;
+ case EIO:
+ ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
+ goto fin;
+ }
+ }
+ if (ast_ari_bridges_create_or_update_with_id_parse_body(body, &args)) {
+ ast_ari_response_alloc_failed(response);
+ goto fin;
+ }
+ ast_ari_bridges_create_or_update_with_id(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 0: /* Implementation is still a stub, or the code wasn't set */
+ is_valid = response->message == NULL;
+ break;
+ case 500: /* Internal Server Error */
+ case 501: /* Not Implemented */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ast_ari_validate_bridge(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /bridges/{bridgeId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /bridges/{bridgeId}\n");
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+ return;
+}
/*!
* \brief Parameter parsing callback for /bridges/{bridgeId}.
* \param get_params GET parameters in the HTTP request.
@@ -1129,6 +1239,7 @@ static struct stasis_rest_handlers bridges_bridgeId = {
.path_segment = "bridgeId",
.is_wildcard = 1,
.callbacks = {
+ [AST_HTTP_POST] = ast_ari_bridges_create_or_update_with_id_cb,
[AST_HTTP_GET] = ast_ari_bridges_get_cb,
[AST_HTTP_DELETE] = ast_ari_bridges_destroy_cb,
},
diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c
index 12ef16843..ac159bfec 100644
--- a/res/res_ari_channels.c
+++ b/res/res_ari_channels.c
@@ -140,6 +140,14 @@ int ast_ari_channels_originate_parse_body(
if (field) {
args->timeout = ast_json_integer_get(field);
}
+ field = ast_json_object_get(body, "channelId");
+ if (field) {
+ args->channel_id = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "otherChannelId");
+ if (field) {
+ args->other_channel_id = ast_json_string_get(field);
+ }
return 0;
}
@@ -188,6 +196,12 @@ static void ast_ari_channels_originate_cb(
if (strcmp(i->name, "timeout") == 0) {
args.timeout = atoi(i->value);
} else
+ if (strcmp(i->name, "channelId") == 0) {
+ args.channel_id = (i->value);
+ } else
+ if (strcmp(i->name, "otherChannelId") == 0) {
+ args.other_channel_id = (i->value);
+ } else
{}
}
/* Look for a JSON request entity */
@@ -298,6 +312,156 @@ static void ast_ari_channels_get_cb(
fin: __attribute__((unused))
return;
}
+int ast_ari_channels_originate_with_id_parse_body(
+ struct ast_json *body,
+ struct ast_ari_channels_originate_with_id_args *args)
+{
+ struct ast_json *field;
+ /* Parse query parameters out of it */
+ field = ast_json_object_get(body, "endpoint");
+ if (field) {
+ args->endpoint = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "extension");
+ if (field) {
+ args->extension = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "context");
+ if (field) {
+ args->context = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "priority");
+ if (field) {
+ args->priority = ast_json_integer_get(field);
+ }
+ field = ast_json_object_get(body, "app");
+ if (field) {
+ args->app = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "appArgs");
+ if (field) {
+ args->app_args = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "callerId");
+ if (field) {
+ args->caller_id = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "timeout");
+ if (field) {
+ args->timeout = ast_json_integer_get(field);
+ }
+ field = ast_json_object_get(body, "otherChannelId");
+ if (field) {
+ args->other_channel_id = ast_json_string_get(field);
+ }
+ return 0;
+}
+
+/*!
+ * \brief Parameter parsing callback for /channels/{channelId}.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_channels_originate_with_id_cb(
+ struct ast_tcptls_session_instance *ser,
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct ast_ari_response *response)
+{
+ struct ast_ari_channels_originate_with_id_args args = {};
+ struct ast_variable *i;
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
+ for (i = get_params; i; i = i->next) {
+ if (strcmp(i->name, "endpoint") == 0) {
+ args.endpoint = (i->value);
+ } else
+ if (strcmp(i->name, "extension") == 0) {
+ args.extension = (i->value);
+ } else
+ if (strcmp(i->name, "context") == 0) {
+ args.context = (i->value);
+ } else
+ if (strcmp(i->name, "priority") == 0) {
+ args.priority = atol(i->value);
+ } else
+ if (strcmp(i->name, "app") == 0) {
+ args.app = (i->value);
+ } else
+ if (strcmp(i->name, "appArgs") == 0) {
+ args.app_args = (i->value);
+ } else
+ if (strcmp(i->name, "callerId") == 0) {
+ args.caller_id = (i->value);
+ } else
+ if (strcmp(i->name, "timeout") == 0) {
+ args.timeout = atoi(i->value);
+ } else
+ if (strcmp(i->name, "otherChannelId") == 0) {
+ args.other_channel_id = (i->value);
+ } else
+ {}
+ }
+ for (i = path_vars; i; i = i->next) {
+ if (strcmp(i->name, "channelId") == 0) {
+ args.channel_id = (i->value);
+ } else
+ {}
+ }
+ /* Look for a JSON request entity */
+ body = ast_http_get_json(ser, headers);
+ if (!body) {
+ switch (errno) {
+ case EFBIG:
+ ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
+ goto fin;
+ case ENOMEM:
+ ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
+ goto fin;
+ case EIO:
+ ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
+ goto fin;
+ }
+ }
+ args.variables = ast_json_ref(body);
+ ast_ari_channels_originate_with_id(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 0: /* Implementation is still a stub, or the code wasn't set */
+ is_valid = response->message == NULL;
+ break;
+ case 500: /* Internal Server Error */
+ case 501: /* Not Implemented */
+ case 400: /* Invalid parameters for originating a channel. */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ast_ari_validate_channel(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}\n");
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+ return;
+}
int ast_ari_channels_hangup_parse_body(
struct ast_json *body,
struct ast_ari_channels_hangup_args *args)
@@ -1431,6 +1595,10 @@ int ast_ari_channels_play_parse_body(
if (field) {
args->skipms = ast_json_integer_get(field);
}
+ field = ast_json_object_get(body, "playbackId");
+ if (field) {
+ args->playback_id = ast_json_string_get(field);
+ }
return 0;
}
@@ -1467,6 +1635,9 @@ static void ast_ari_channels_play_cb(
if (strcmp(i->name, "skipms") == 0) {
args.skipms = atoi(i->value);
} else
+ if (strcmp(i->name, "playbackId") == 0) {
+ args.playback_id = (i->value);
+ } else
{}
}
for (i = path_vars; i; i = i->next) {
@@ -1528,6 +1699,128 @@ static void ast_ari_channels_play_cb(
fin: __attribute__((unused))
return;
}
+int ast_ari_channels_play_with_id_parse_body(
+ struct ast_json *body,
+ struct ast_ari_channels_play_with_id_args *args)
+{
+ struct ast_json *field;
+ /* Parse query parameters out of it */
+ field = ast_json_object_get(body, "media");
+ if (field) {
+ args->media = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "lang");
+ if (field) {
+ args->lang = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "offsetms");
+ if (field) {
+ args->offsetms = ast_json_integer_get(field);
+ }
+ field = ast_json_object_get(body, "skipms");
+ if (field) {
+ args->skipms = ast_json_integer_get(field);
+ }
+ return 0;
+}
+
+/*!
+ * \brief Parameter parsing callback for /channels/{channelId}/play/{playbackId}.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_channels_play_with_id_cb(
+ struct ast_tcptls_session_instance *ser,
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct ast_ari_response *response)
+{
+ struct ast_ari_channels_play_with_id_args args = {};
+ struct ast_variable *i;
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
+ for (i = get_params; i; i = i->next) {
+ if (strcmp(i->name, "media") == 0) {
+ args.media = (i->value);
+ } else
+ if (strcmp(i->name, "lang") == 0) {
+ args.lang = (i->value);
+ } else
+ if (strcmp(i->name, "offsetms") == 0) {
+ args.offsetms = atoi(i->value);
+ } else
+ if (strcmp(i->name, "skipms") == 0) {
+ args.skipms = atoi(i->value);
+ } else
+ {}
+ }
+ for (i = path_vars; i; i = i->next) {
+ if (strcmp(i->name, "channelId") == 0) {
+ args.channel_id = (i->value);
+ } else
+ if (strcmp(i->name, "playbackId") == 0) {
+ args.playback_id = (i->value);
+ } else
+ {}
+ }
+ /* Look for a JSON request entity */
+ body = ast_http_get_json(ser, headers);
+ if (!body) {
+ switch (errno) {
+ case EFBIG:
+ ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
+ goto fin;
+ case ENOMEM:
+ ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
+ goto fin;
+ case EIO:
+ ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
+ goto fin;
+ }
+ }
+ if (ast_ari_channels_play_with_id_parse_body(body, &args)) {
+ ast_ari_response_alloc_failed(response);
+ goto fin;
+ }
+ ast_ari_channels_play_with_id(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 0: /* Implementation is still a stub, or the code wasn't set */
+ is_valid = response->message == NULL;
+ break;
+ case 500: /* Internal Server Error */
+ case 501: /* Not Implemented */
+ case 404: /* Channel not found */
+ case 409: /* Channel not in a Stasis application */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ast_ari_validate_playback(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/play/{playbackId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/play/{playbackId}\n");
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+ return;
+}
int ast_ari_channels_record_parse_body(
struct ast_json *body,
struct ast_ari_channels_record_args *args)
@@ -1897,6 +2190,10 @@ int ast_ari_channels_snoop_channel_parse_body(
if (field) {
args->app_args = ast_json_string_get(field);
}
+ field = ast_json_object_get(body, "snoopId");
+ if (field) {
+ args->snoop_id = ast_json_string_get(field);
+ }
return 0;
}
@@ -1933,6 +2230,9 @@ static void ast_ari_channels_snoop_channel_cb(
if (strcmp(i->name, "appArgs") == 0) {
args.app_args = (i->value);
} else
+ if (strcmp(i->name, "snoopId") == 0) {
+ args.snoop_id = (i->value);
+ } else
{}
}
for (i = path_vars; i; i = i->next) {
@@ -1994,6 +2294,128 @@ static void ast_ari_channels_snoop_channel_cb(
fin: __attribute__((unused))
return;
}
+int ast_ari_channels_snoop_channel_with_id_parse_body(
+ struct ast_json *body,
+ struct ast_ari_channels_snoop_channel_with_id_args *args)
+{
+ struct ast_json *field;
+ /* Parse query parameters out of it */
+ field = ast_json_object_get(body, "spy");
+ if (field) {
+ args->spy = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "whisper");
+ if (field) {
+ args->whisper = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "app");
+ if (field) {
+ args->app = ast_json_string_get(field);
+ }
+ field = ast_json_object_get(body, "appArgs");
+ if (field) {
+ args->app_args = ast_json_string_get(field);
+ }
+ return 0;
+}
+
+/*!
+ * \brief Parameter parsing callback for /channels/{channelId}/snoop/{snoopId}.
+ * \param get_params GET parameters in the HTTP request.
+ * \param path_vars Path variables extracted from the request.
+ * \param headers HTTP headers.
+ * \param[out] response Response to the HTTP request.
+ */
+static void ast_ari_channels_snoop_channel_with_id_cb(
+ struct ast_tcptls_session_instance *ser,
+ struct ast_variable *get_params, struct ast_variable *path_vars,
+ struct ast_variable *headers, struct ast_ari_response *response)
+{
+ struct ast_ari_channels_snoop_channel_with_id_args args = {};
+ struct ast_variable *i;
+ RAII_VAR(struct ast_json *, body, NULL, ast_json_unref);
+#if defined(AST_DEVMODE)
+ int is_valid;
+ int code;
+#endif /* AST_DEVMODE */
+
+ for (i = get_params; i; i = i->next) {
+ if (strcmp(i->name, "spy") == 0) {
+ args.spy = (i->value);
+ } else
+ if (strcmp(i->name, "whisper") == 0) {
+ args.whisper = (i->value);
+ } else
+ if (strcmp(i->name, "app") == 0) {
+ args.app = (i->value);
+ } else
+ if (strcmp(i->name, "appArgs") == 0) {
+ args.app_args = (i->value);
+ } else
+ {}
+ }
+ for (i = path_vars; i; i = i->next) {
+ if (strcmp(i->name, "channelId") == 0) {
+ args.channel_id = (i->value);
+ } else
+ if (strcmp(i->name, "snoopId") == 0) {
+ args.snoop_id = (i->value);
+ } else
+ {}
+ }
+ /* Look for a JSON request entity */
+ body = ast_http_get_json(ser, headers);
+ if (!body) {
+ switch (errno) {
+ case EFBIG:
+ ast_ari_response_error(response, 413, "Request Entity Too Large", "Request body too large");
+ goto fin;
+ case ENOMEM:
+ ast_ari_response_error(response, 500, "Internal Server Error", "Error processing request");
+ goto fin;
+ case EIO:
+ ast_ari_response_error(response, 400, "Bad Request", "Error parsing request body");
+ goto fin;
+ }
+ }
+ if (ast_ari_channels_snoop_channel_with_id_parse_body(body, &args)) {
+ ast_ari_response_alloc_failed(response);
+ goto fin;
+ }
+ ast_ari_channels_snoop_channel_with_id(headers, &args, response);
+#if defined(AST_DEVMODE)
+ code = response->response_code;
+
+ switch (code) {
+ case 0: /* Implementation is still a stub, or the code wasn't set */
+ is_valid = response->message == NULL;
+ break;
+ case 500: /* Internal Server Error */
+ case 501: /* Not Implemented */
+ case 400: /* Invalid parameters */
+ case 404: /* Channel not found */
+ is_valid = 1;
+ break;
+ default:
+ if (200 <= code && code <= 299) {
+ is_valid = ast_ari_validate_channel(
+ response->message);
+ } else {
+ ast_log(LOG_ERROR, "Invalid error response %d for /channels/{channelId}/snoop/{snoopId}\n", code);
+ is_valid = 0;
+ }
+ }
+
+ if (!is_valid) {
+ ast_log(LOG_ERROR, "Response validation failed for /channels/{channelId}/snoop/{snoopId}\n");
+ ast_ari_response_error(response, 500,
+ "Internal Server Error", "Response validation failed");
+ }
+#endif /* AST_DEVMODE */
+
+fin: __attribute__((unused))
+ return;
+}
/*! \brief REST handler for /api-docs/channels.{format} */
static struct stasis_rest_handlers channels_channelId_continue = {
@@ -2073,13 +2495,23 @@ static struct stasis_rest_handlers channels_channelId_silence = {
.children = { }
};
/*! \brief REST handler for /api-docs/channels.{format} */
+static struct stasis_rest_handlers channels_channelId_play_playbackId = {
+ .path_segment = "playbackId",
+ .is_wildcard = 1,
+ .callbacks = {
+ [AST_HTTP_POST] = ast_ari_channels_play_with_id_cb,
+ },
+ .num_children = 0,
+ .children = { }
+};
+/*! \brief REST handler for /api-docs/channels.{format} */
static struct stasis_rest_handlers channels_channelId_play = {
.path_segment = "play",
.callbacks = {
[AST_HTTP_POST] = ast_ari_channels_play_cb,
},
- .num_children = 0,
- .children = { }
+ .num_children = 1,
+ .children = { &channels_channelId_play_playbackId, }
};
/*! \brief REST handler for /api-docs/channels.{format} */
static struct stasis_rest_handlers channels_channelId_record = {
@@ -2101,13 +2533,23 @@ static struct stasis_rest_handlers channels_channelId_variable = {
.children = { }
};
/*! \brief REST handler for /api-docs/channels.{format} */
+static struct stasis_rest_handlers channels_channelId_snoop_snoopId = {
+ .path_segment = "snoopId",
+ .is_wildcard = 1,
+ .callbacks = {
+ [AST_HTTP_POST] = ast_ari_channels_snoop_channel_with_id_cb,
+ },
+ .num_children = 0,
+ .children = { }
+};
+/*! \brief REST handler for /api-docs/channels.{format} */
static struct stasis_rest_handlers channels_channelId_snoop = {
.path_segment = "snoop",
.callbacks = {
[AST_HTTP_POST] = ast_ari_channels_snoop_channel_cb,
},
- .num_children = 0,
- .children = { }
+ .num_children = 1,
+ .children = { &channels_channelId_snoop_snoopId, }
};
/*! \brief REST handler for /api-docs/channels.{format} */
static struct stasis_rest_handlers channels_channelId = {
@@ -2115,6 +2557,7 @@ static struct stasis_rest_handlers channels_channelId = {
.is_wildcard = 1,
.callbacks = {
[AST_HTTP_GET] = ast_ari_channels_get_cb,
+ [AST_HTTP_POST] = ast_ari_channels_originate_with_id_cb,
[AST_HTTP_DELETE] = ast_ari_channels_hangup_cb,
},
.num_children = 12,
diff --git a/res/res_calendar.c b/res/res_calendar.c
index c36e5cf0a..f279e73a0 100644
--- a/res/res_calendar.c
+++ b/res/res_calendar.c
@@ -41,6 +41,7 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/_private.h"
+#include "asterisk/channel.h"
#include "asterisk/calendar.h"
#include "asterisk/utils.h"
#include "asterisk/astobj2.h"
@@ -745,7 +746,7 @@ static void *do_notify(void *data)
goto notify_cleanup;
}
- if (ast_dial_append(dial, tech, dest) < 0) {
+ if (ast_dial_append(dial, tech, dest, NULL) < 0) {
ast_log(LOG_ERROR, "Could not append channel\n");
goto notify_cleanup;
}
@@ -753,7 +754,7 @@ static void *do_notify(void *data)
ast_dial_set_global_timeout(dial, event->owner->notify_waittime);
generate_random_string(buf, sizeof(buf));
- if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, 0, 0, "Calendar/%s-%s", event->owner->name, buf))) {
+ if (!(chan = ast_channel_alloc(1, AST_STATE_DOWN, 0, 0, 0, 0, 0, NULL, NULL, 0, "Calendar/%s-%s", event->owner->name, buf))) {
ast_log(LOG_ERROR, "Could not allocate notification channel\n");
goto notify_cleanup;
}
diff --git a/res/res_calendar_caldav.c b/res/res_calendar_caldav.c
index b1dd628a8..0bf3e63cc 100644
--- a/res/res_calendar_caldav.c
+++ b/res/res_calendar_caldav.c
@@ -41,6 +41,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <libxml/parser.h>
#include "asterisk/module.h"
+#include "asterisk/channel.h"
#include "asterisk/calendar.h"
#include "asterisk/lock.h"
#include "asterisk/config.h"
diff --git a/res/res_calendar_ews.c b/res/res_calendar_ews.c
index 3cf0d745e..c6d827fe8 100644
--- a/res/res_calendar_ews.c
+++ b/res/res_calendar_ews.c
@@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <ne_redirect.h>
#include "asterisk/module.h"
+#include "asterisk/channel.h"
#include "asterisk/calendar.h"
#include "asterisk/lock.h"
#include "asterisk/config.h"
diff --git a/res/res_calendar_exchange.c b/res/res_calendar_exchange.c
index acfdcee7c..3f902a3dc 100644
--- a/res/res_calendar_exchange.c
+++ b/res/res_calendar_exchange.c
@@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <iksemel.h>
#include "asterisk/module.h"
+#include "asterisk/channel.h"
#include "asterisk/calendar.h"
#include "asterisk/lock.h"
#include "asterisk/config.h"
diff --git a/res/res_calendar_icalendar.c b/res/res_calendar_icalendar.c
index 3aea7a463..84b4e6845 100644
--- a/res/res_calendar_icalendar.c
+++ b/res/res_calendar_icalendar.c
@@ -38,6 +38,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include <ne_redirect.h>
#include "asterisk/module.h"
+#include "asterisk/channel.h"
#include "asterisk/calendar.h"
#include "asterisk/lock.h"
#include "asterisk/config.h"
diff --git a/res/res_clioriginate.c b/res/res_clioriginate.c
index 0d639c77d..cd8b5dde1 100644
--- a/res/res_clioriginate.c
+++ b/res/res_clioriginate.c
@@ -74,7 +74,7 @@ static char *orig_app(int fd, const char *chan, const char *app, const char *app
return CLI_FAILURE;
}
ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
- ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL);
+ ast_pbx_outgoing_app(chantech, cap, chandata, TIMEOUT * 1000, app, appdata, &reason, 0, NULL, NULL, NULL, NULL, NULL, NULL);
cap = ast_format_cap_destroy(cap);
return CLI_SUCCESS;
@@ -119,7 +119,7 @@ static char *orig_exten(int fd, const char *chan, const char *data)
return CLI_FAILURE;
}
ast_format_cap_add(cap, ast_format_set(&tmpfmt, AST_FORMAT_SLINEAR, 0));
- ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL, 0);
+ ast_pbx_outgoing_exten(chantech, cap, chandata, TIMEOUT * 1000, context, exten, 1, &reason, 0, NULL, NULL, NULL, NULL, NULL, 0, NULL);
cap = ast_format_cap_destroy(cap);
return CLI_SUCCESS;
diff --git a/res/res_stasis.c b/res/res_stasis.c
index f6fc0ac6e..3a9297139 100644
--- a/res/res_stasis.c
+++ b/res/res_stasis.c
@@ -441,7 +441,7 @@ static struct ast_channel *prepare_bridge_moh_channel(void)
ast_format_cap_add(cap, ast_format_set(&format, AST_FORMAT_SLINEAR, 0));
- return ast_request("Announcer", cap, NULL, "ARI_MOH", NULL);
+ return ast_request("Announcer", cap, NULL, NULL, "ARI_MOH", NULL);
}
/*! Provides the moh channel with a thread so it can actually play its music */
@@ -585,7 +585,7 @@ static void control_unlink(struct stasis_app_control *control)
ao2_cleanup(control);
}
-struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name)
+struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name, const char *id)
{
struct ast_bridge *bridge;
int capabilities;
@@ -604,7 +604,7 @@ struct ast_bridge *stasis_app_bridge_create(const char *type, const char *name)
return NULL;
}
- bridge = ast_bridge_base_new(capabilities, flags, "Stasis", name);
+ bridge = ast_bridge_base_new(capabilities, flags, "Stasis", name, id);
if (bridge) {
if (!ao2_link(app_bridges, bridge)) {
ast_bridge_destroy(bridge, 0);
diff --git a/res/res_stasis_playback.c b/res/res_stasis_playback.c
index c08c2fa40..ee4a20bcc 100644
--- a/res/res_stasis_playback.c
+++ b/res/res_stasis_playback.c
@@ -125,10 +125,10 @@ static void playback_dtor(void *obj)
}
static struct stasis_app_playback *playback_create(
- struct stasis_app_control *control)
+ struct stasis_app_control *control, const char *id)
{
RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
- char id[AST_UUID_STR_LEN];
+ char uuid[AST_UUID_STR_LEN];
int res;
if (!control) {
@@ -147,8 +147,12 @@ static struct stasis_app_playback *playback_create(
return NULL;
}
- ast_uuid_generate_str(id, sizeof(id));
- ast_string_field_set(playback, id, id);
+ if (!ast_strlen_zero(id)) {
+ ast_string_field_set(playback, id, id);
+ } else {
+ ast_uuid_generate_str(uuid, sizeof(uuid));
+ ast_string_field_set(playback, id, uuid);
+ }
playback->control = control;
@@ -462,7 +466,7 @@ struct stasis_app_playback *stasis_app_control_play_uri(
struct stasis_app_control *control, const char *uri,
const char *language, const char *target_id,
enum stasis_app_playback_target_type target_type,
- int skipms, long offsetms)
+ int skipms, long offsetms, const char *id)
{
RAII_VAR(struct stasis_app_playback *, playback, NULL, ao2_cleanup);
@@ -473,7 +477,7 @@ struct stasis_app_playback *stasis_app_control_play_uri(
ast_debug(3, "%s: Sending play(%s) command\n",
stasis_app_control_get_channel_id(control), uri);
- playback = playback_create(control);
+ playback = playback_create(control, id);
if (skipms == 0) {
skipms = PLAYBACK_DEFAULT_SKIPMS;
diff --git a/res/res_stasis_snoop.c b/res/res_stasis_snoop.c
index 65186d14e..eaa21603a 100644
--- a/res/res_stasis_snoop.c
+++ b/res/res_stasis_snoop.c
@@ -286,10 +286,11 @@ static void snoop_determine_format(struct ast_channel *chan, struct stasis_app_s
struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan,
enum stasis_app_snoop_direction spy, enum stasis_app_snoop_direction whisper,
- const char *app, const char *app_args)
+ const char *app, const char *app_args, const char *snoop_id)
{
RAII_VAR(struct stasis_app_snoop *, snoop, NULL, ao2_cleanup);
pthread_t thread;
+ struct ast_assigned_ids assignedids = {snoop_id, NULL};
if (spy == STASIS_SNOOP_DIRECTION_NONE &&
whisper == STASIS_SNOOP_DIRECTION_NONE) {
@@ -323,7 +324,7 @@ struct ast_channel *stasis_app_control_snoop(struct ast_channel *chan,
snoop_determine_format(chan, snoop);
/* Allocate a Snoop channel and set up various parameters */
- snoop->chan = ast_channel_alloc(1, AST_STATE_UP, "", "", "", "", "", "", 0, "Snoop/%s-%08x", ast_channel_uniqueid(chan),
+ snoop->chan = ast_channel_alloc(1, AST_STATE_UP, "", "", "", "", "", &assignedids, NULL, 0, "Snoop/%s-%08x", ast_channel_uniqueid(chan),
ast_atomic_fetchadd_int((int *)&chan_idx, +1));
if (!snoop->chan) {
return NULL;
diff --git a/res/stasis/control.c b/res/stasis/control.c
index 6b092918e..d813a2443 100644
--- a/res/stasis/control.c
+++ b/res/stasis/control.c
@@ -293,7 +293,7 @@ static int app_control_dial(struct stasis_app_control *control,
return -1;
}
- if (ast_dial_append(dial, tech, resource) < 0) {
+ if (ast_dial_append(dial, tech, resource, NULL) < 0) {
ast_log(LOG_ERROR, "Failed to add %s/%s to dialing structure.\n", tech, resource);
return -1;
}