summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES11
-rw-r--r--res/ari/resource_channels.c214
-rw-r--r--res/ari/resource_channels.h4
-rw-r--r--res/res_ari_channels.c14
-rw-r--r--rest-api/api-docs/channels.json16
5 files changed, 236 insertions, 23 deletions
diff --git a/CHANGES b/CHANGES
index a883f5156..b4f798f40 100644
--- a/CHANGES
+++ b/CHANGES
@@ -76,6 +76,17 @@ res_musiconhold
application (e.g. Queue or Dial) specified music.
------------------------------------------------------------------------------
+--- Functionality changes from Asterisk 13.1.0 to Asterisk 13.2.0 ------------
+------------------------------------------------------------------------------
+
+ARI
+------------------
+ * The Originate operation now takes in an originator channel. The linked ID of
+ this originator channel is applied to the newly originated outgoing channel.
+ If using CEL this allows an association to be established between the two so
+ it can be recognized that the originator is dialing the originated channel.
+
+------------------------------------------------------------------------------
--- Functionality changes from Asterisk 13.0.0 to Asterisk 13.1.0 ------------
------------------------------------------------------------------------------
diff --git a/res/ari/resource_channels.c b/res/ari/resource_channels.c
index 112607db6..e3ef9eb16 100644
--- a/res/ari/resource_channels.c
+++ b/res/ari/resource_channels.c
@@ -44,6 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/causes.h"
#include "asterisk/format_cache.h"
#include "asterisk/core_local.h"
+#include "asterisk/dial.h"
#include "resource_channels.h"
#include <limits.h>
@@ -723,6 +724,69 @@ void ast_ari_channels_list(struct ast_variable *headers,
ast_ari_response_ok(response, ast_json_ref(json));
}
+/*! \brief Structure used for origination */
+struct ari_origination {
+ /*! \brief Dialplan context */
+ char context[AST_MAX_CONTEXT];
+ /*! \brief Dialplan extension */
+ char exten[AST_MAX_EXTENSION];
+ /*! \brief Dialplan priority */
+ int priority;
+ /*! \brief Application data to pass to Stasis application */
+ char appdata[0];
+};
+
+/*! \brief Thread which dials and executes upon answer */
+static void *ari_originate_dial(void *data)
+{
+ struct ast_dial *dial = data;
+ struct ari_origination *origination = ast_dial_get_user_data(dial);
+ enum ast_dial_result res;
+
+ res = ast_dial_run(dial, NULL, 0);
+ if (res != AST_DIAL_RESULT_ANSWERED) {
+ goto end;
+ }
+
+ if (!ast_strlen_zero(origination->appdata)) {
+ struct ast_app *app = pbx_findapp("Stasis");
+
+ if (app) {
+ ast_verb(4, "Launching Stasis(%s) on %s\n", origination->appdata,
+ ast_channel_name(ast_dial_answered(dial)));
+ pbx_exec(ast_dial_answered(dial), app, origination->appdata);
+ } else {
+ ast_log(LOG_WARNING, "No such application 'Stasis'\n");
+ }
+ } else {
+ struct ast_channel *answered = ast_dial_answered(dial);
+
+ if (!ast_strlen_zero(origination->context)) {
+ ast_channel_context_set(answered, origination->context);
+ }
+
+ if (!ast_strlen_zero(origination->exten)) {
+ ast_channel_exten_set(answered, origination->exten);
+ }
+
+ if (origination->priority > 0) {
+ ast_channel_priority_set(answered, origination->priority);
+ }
+
+ if (ast_pbx_run(answered)) {
+ ast_log(LOG_ERROR, "Failed to start PBX on %s\n", ast_channel_name(answered));
+ } else {
+ /* PBX will have taken care of hanging up, so we steal the answered channel so dial doesn't do it */
+ ast_dial_answered_steal(dial);
+ }
+ }
+
+end:
+ ast_dial_destroy(dial);
+ ast_free(origination);
+ return NULL;
+}
+
static void ari_channels_handle_originate_with_id(const char *args_endpoint,
const char *args_extension,
const char *args_context,
@@ -734,23 +798,27 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
struct ast_variable *variables,
const char *args_channel_id,
const char *args_other_channel_id,
+ const char *args_originator,
struct ast_ari_response *response)
{
char *dialtech;
char dialdevice[AST_CHANNEL_NAME];
+ struct ast_dial *dial;
char *caller_id = NULL;
char *cid_num = NULL;
char *cid_name = NULL;
- int timeout = 30000;
RAII_VAR(struct ast_format_cap *, cap,
ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT), ao2_cleanup);
char *stuff;
+ struct ast_channel *other = NULL;
struct ast_channel *chan;
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
struct ast_assigned_ids assignedids = {
.uniqueid = args_channel_id,
.uniqueid2 = args_other_channel_id,
};
+ struct ari_origination *origination;
+ pthread_t thread;
if (!cap) {
ast_ari_response_alloc_failed(response);
@@ -783,24 +851,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
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) {
@@ -813,23 +864,125 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
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, &assignedids)) {
+ origination = ast_calloc(1, sizeof(*origination) + ast_str_size(appdata) + 1);
+ if (!origination) {
ast_ari_response_alloc_failed(response);
return;
}
+
+ strcpy(origination->appdata, ast_str_buffer(appdata));
} 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, &assignedids)) {
+ origination = ast_calloc(1, sizeof(*origination) + 1);
+ if (!origination) {
ast_ari_response_alloc_failed(response);
return;
}
+
+ ast_copy_string(origination->context, S_OR(args_context, "default"), sizeof(origination->context));
+ ast_copy_string(origination->exten, args_extension, sizeof(origination->exten));
+ origination->priority = args_priority ? args_priority : 1;
+ origination->appdata[0] = '\0';
} else {
ast_ari_response_error(response, 400, "Bad Request",
"Application or extension must be specified");
return;
}
+ dial = ast_dial_create();
+ if (!dial) {
+ ast_ari_response_alloc_failed(response);
+ ast_free(origination);
+ return;
+ }
+ ast_dial_set_user_data(dial, origination);
+
+ if (ast_dial_append(dial, dialtech, dialdevice, &assignedids)) {
+ ast_ari_response_alloc_failed(response);
+ ast_dial_destroy(dial);
+ ast_free(origination);
+ return;
+ }
+
+ if (args_timeout > 0) {
+ ast_dial_set_global_timeout(dial, args_timeout * 1000);
+ } else if (args_timeout == -1) {
+ ast_dial_set_global_timeout(dial, -1);
+ } else {
+ ast_dial_set_global_timeout(dial, 30000);
+ }
+
+ 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_originator)) {
+ other = ast_channel_get_by_name(args_originator);
+ if (!other) {
+ ast_ari_response_error(
+ response, 400, "Bad Request",
+ "Provided originator channel was not found");
+ ast_dial_destroy(dial);
+ ast_free(origination);
+ return;
+ }
+ }
+
+ if (ast_dial_prerun(dial, other, cap)) {
+ ast_ari_response_alloc_failed(response);
+ ast_dial_destroy(dial);
+ ast_free(origination);
+ ast_channel_cleanup(other);
+ return;
+ }
+
+ ast_channel_cleanup(other);
+
+ chan = ast_dial_get_channel(dial, 0);
+ if (!chan) {
+ ast_ari_response_alloc_failed(response);
+ ast_dial_destroy(dial);
+ ast_free(origination);
+ return;
+ }
+
+ if (!ast_strlen_zero(cid_num) || !ast_strlen_zero(cid_name)) {
+ struct ast_party_connected_line connected;
+
+ /*
+ * It seems strange to set the CallerID on an outgoing call leg
+ * to whom we are calling, but this function's callers are doing
+ * various Originate methods. This call leg goes to the local
+ * user. Once the called party answers, the dialplan needs to
+ * be able to access the CallerID from the CALLERID function as
+ * if the called party had placed this call.
+ */
+ ast_set_callerid(chan, cid_num, cid_name, cid_num);
+
+ ast_party_connected_line_set_init(&connected, ast_channel_connected(chan));
+ if (!ast_strlen_zero(cid_num)) {
+ connected.id.number.valid = 1;
+ connected.id.number.str = (char *) cid_num;
+ connected.id.number.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+ }
+ if (!ast_strlen_zero(cid_name)) {
+ connected.id.name.valid = 1;
+ connected.id.name.str = (char *) cid_name;
+ connected.id.name.presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED;
+ }
+ ast_channel_set_connected_line(chan, &connected, NULL);
+ }
+
+ ast_channel_lock(chan);
+ if (variables) {
+ ast_set_variables(chan, variables);
+ }
+ ast_set_flag(ast_channel_flags(chan), AST_FLAG_ORIGINATED);
+
if (!ast_strlen_zero(args_app)) {
struct ast_channel *local_peer;
@@ -846,8 +999,21 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(chan));
ast_channel_unlock(chan);
- ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
+ /* Before starting the async dial bump the ref in case the dial quickly goes away and takes
+ * the reference with it
+ */
+ ast_channel_ref(chan);
+
+ if (ast_pthread_create_detached(&thread, NULL, ari_originate_dial, dial)) {
+ ast_ari_response_alloc_failed(response);
+ ast_dial_destroy(dial);
+ ast_free(origination);
+ } else {
+ ast_ari_response_ok(response, ast_channel_snapshot_to_json(snapshot, NULL));
+ }
+
ast_channel_unref(chan);
+ return;
}
void ast_ari_channels_originate_with_id(struct ast_variable *headers,
@@ -883,6 +1049,7 @@ void ast_ari_channels_originate_with_id(struct ast_variable *headers,
variables,
args->channel_id,
args->other_channel_id,
+ args->originator,
response);
}
@@ -919,6 +1086,7 @@ void ast_ari_channels_originate(struct ast_variable *headers,
variables,
args->channel_id,
args->other_channel_id,
+ args->originator,
response);
}
diff --git a/res/ari/resource_channels.h b/res/ari/resource_channels.h
index 104e1bdb3..627f9c97a 100644
--- a/res/ari/resource_channels.h
+++ b/res/ari/resource_channels.h
@@ -74,6 +74,8 @@ struct ast_ari_channels_originate_args {
const char *channel_id;
/*! The unique id to assign the second channel when using local channels. */
const char *other_channel_id;
+ /*! The unique id of the channel which is originating this one. */
+ const char *originator;
};
/*!
* \brief Body parsing function for /channels.
@@ -133,6 +135,8 @@ struct ast_ari_channels_originate_with_id_args {
struct ast_json *variables;
/*! The unique id to assign the second channel when using local channels. */
const char *other_channel_id;
+ /*! The unique id of the channel which is originating this one. */
+ const char *originator;
};
/*!
* \brief Body parsing function for /channels/{channelId}.
diff --git a/res/res_ari_channels.c b/res/res_ari_channels.c
index 08edc64dc..8cc25f1d8 100644
--- a/res/res_ari_channels.c
+++ b/res/res_ari_channels.c
@@ -148,6 +148,10 @@ int ast_ari_channels_originate_parse_body(
if (field) {
args->other_channel_id = ast_json_string_get(field);
}
+ field = ast_json_object_get(body, "originator");
+ if (field) {
+ args->originator = ast_json_string_get(field);
+ }
return 0;
}
@@ -202,6 +206,9 @@ static void ast_ari_channels_originate_cb(
if (strcmp(i->name, "otherChannelId") == 0) {
args.other_channel_id = (i->value);
} else
+ if (strcmp(i->name, "originator") == 0) {
+ args.originator = (i->value);
+ } else
{}
}
/* Look for a JSON request entity */
@@ -354,6 +361,10 @@ int ast_ari_channels_originate_with_id_parse_body(
if (field) {
args->other_channel_id = ast_json_string_get(field);
}
+ field = ast_json_object_get(body, "originator");
+ if (field) {
+ args->originator = ast_json_string_get(field);
+ }
return 0;
}
@@ -405,6 +416,9 @@ static void ast_ari_channels_originate_with_id_cb(
if (strcmp(i->name, "otherChannelId") == 0) {
args.other_channel_id = (i->value);
} else
+ if (strcmp(i->name, "originator") == 0) {
+ args.originator = (i->value);
+ } else
{}
}
for (i = path_vars; i; i = i->next) {
diff --git a/rest-api/api-docs/channels.json b/rest-api/api-docs/channels.json
index 67634740a..f9c8d8647 100644
--- a/rest-api/api-docs/channels.json
+++ b/rest-api/api-docs/channels.json
@@ -112,6 +112,14 @@
"required": false,
"allowMultiple": false,
"dataType": "string"
+ },
+ {
+ "name": "originator",
+ "description": "The unique id of the channel which is originating this one.",
+ "paramType": "query",
+ "required": false,
+ "allowMultiple": false,
+ "dataType": "string"
}
],
"errorResponses": [
@@ -244,6 +252,14 @@
"required": false,
"allowMultiple": false,
"dataType": "string"
+ },
+ {
+ "name": "originator",
+ "description": "The unique id of the channel which is originating this one.",
+ "paramType": "query",
+ "required": false,
+ "allowMultiple": false,
+ "dataType": "string"
}
],
"errorResponses": [