summaryrefslogtreecommitdiff
path: root/res/ari
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2014-12-09 15:44:05 +0000
committerJoshua Colp <jcolp@digium.com>2014-12-09 15:44:05 +0000
commit74b032bb0341a260c8147b86b00901284e4f5e56 (patch)
tree420a9351da78d79af75743939c443bac889a3da7 /res/ari
parent64581d894d570a3cfa5ae8b947f326e6fcaa9ef3 (diff)
ari: Add support for specifying an originator channel when originating.
If an originator channel is specified when originating a channel the linked ID of it will be applied to the newly originated outgoing channel. This allows an association to be made between the two so it is known that the originator has dialed the originated channel. ASTERISK-24552 #close Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/4243/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/13@429153 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/ari')
-rw-r--r--res/ari/resource_channels.c214
-rw-r--r--res/ari/resource_channels.h4
2 files changed, 195 insertions, 23 deletions
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}.