forked from Mirrors/freeswitch
add pickup endpoint and app to dptools add pickup/keyname to forked dial, then route a call to call app pickup(keyname) to have your channel return from originate. sub to pickup+keyname or presence map the pickup proto to use on blf
This commit is contained in:
parent
5c66ab4793
commit
64d4d9ea57
@ -1211,6 +1211,7 @@ typedef enum {
|
||||
CF_SERVICE_VIDEO,
|
||||
CF_ZRTP_HASH,
|
||||
CF_ZRTP_PASS,
|
||||
CF_CHANNEL_SWAP,
|
||||
/* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */
|
||||
/* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */
|
||||
CF_FLAG_MAX
|
||||
|
@ -38,7 +38,8 @@
|
||||
#include <switch.h>
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load);
|
||||
SWITCH_MODULE_DEFINITION(mod_dptools, mod_dptools_load, NULL, NULL);
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_dptools_shutdown);
|
||||
SWITCH_MODULE_DEFINITION(mod_dptools, mod_dptools_load, mod_dptools_shutdown, NULL);
|
||||
|
||||
SWITCH_STANDARD_DIALPLAN(inline_dialplan_hunt)
|
||||
{
|
||||
@ -3094,6 +3095,484 @@ SWITCH_STANDARD_APP(audio_bridge_function)
|
||||
}
|
||||
}
|
||||
|
||||
static struct {
|
||||
switch_memory_pool_t *pool;
|
||||
switch_hash_t *pickup_hash;
|
||||
switch_mutex_t *pickup_mutex;
|
||||
} globals;
|
||||
|
||||
/* pickup channel */
|
||||
|
||||
|
||||
|
||||
typedef struct pickup_node_s {
|
||||
char *key;
|
||||
char *uuid;
|
||||
struct pickup_node_s *next;
|
||||
} pickup_node_t;
|
||||
|
||||
|
||||
#define PICKUP_PROTO "pickup"
|
||||
static int EC = 0;
|
||||
|
||||
static int pickup_count(const char *key_name)
|
||||
{
|
||||
int count = 0;
|
||||
pickup_node_t *head, *np;
|
||||
|
||||
switch_mutex_lock(globals.pickup_mutex);
|
||||
if ((head = switch_core_hash_find(globals.pickup_hash, key_name))) {
|
||||
for (np = head; np; np = np->next) count++;
|
||||
}
|
||||
switch_mutex_unlock(globals.pickup_mutex);
|
||||
|
||||
return count;
|
||||
|
||||
}
|
||||
|
||||
static void pickup_send_presence(const char *key_name)
|
||||
{
|
||||
|
||||
char *domain_name, *dup_key_name = NULL, *dup_domain_name = NULL, *dup_id = NULL;
|
||||
switch_event_t *event;
|
||||
int count;
|
||||
|
||||
|
||||
dup_key_name = strdup(key_name);
|
||||
key_name = dup_key_name;
|
||||
|
||||
if ((domain_name = strchr(dup_key_name, '@'))) {
|
||||
*domain_name++ = '\0';
|
||||
}
|
||||
|
||||
if (zstr(domain_name)) {
|
||||
dup_domain_name = switch_core_get_variable_dup("domain");
|
||||
domain_name = dup_domain_name;
|
||||
}
|
||||
|
||||
if (zstr(domain_name)) {
|
||||
domain_name = "cluecon.com";
|
||||
}
|
||||
|
||||
dup_id = switch_mprintf("%s@%s", key_name, domain_name);
|
||||
|
||||
count = pickup_count(dup_id);
|
||||
|
||||
if (count > 0) {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", PICKUP_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", dup_id);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", dup_id);
|
||||
|
||||
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "force-status", "Active (%d call%s)", count, count == 1 ? "" : "s");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "active");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", key_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
} else {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", PICKUP_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", dup_id);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "from", dup_id);
|
||||
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Idle");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", dup_id);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
switch_safe_free(dup_domain_name);
|
||||
switch_safe_free(dup_key_name);
|
||||
switch_safe_free(dup_id);
|
||||
|
||||
}
|
||||
|
||||
static void pickup_pres_event_handler(switch_event_t *event)
|
||||
{
|
||||
char *to = switch_event_get_header(event, "to");
|
||||
char *dup_to = NULL, *key_name, *dup_key_name = NULL, *domain_name, *dup_domain_name = NULL;
|
||||
int count = 0;
|
||||
|
||||
if (!to || strncasecmp(to, "pickup+", 7) || !strchr(to, '@')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(dup_to = strdup(to))) {
|
||||
return;
|
||||
}
|
||||
|
||||
key_name = dup_to + 7;
|
||||
|
||||
if ((domain_name = strchr(key_name, '@'))) {
|
||||
*domain_name++ = '\0';
|
||||
} else {
|
||||
dup_domain_name = switch_core_get_variable_dup("domain");
|
||||
domain_name = dup_domain_name;
|
||||
}
|
||||
|
||||
if (zstr(domain_name)) {
|
||||
switch_safe_free(dup_to);
|
||||
return;
|
||||
}
|
||||
|
||||
dup_key_name = switch_mprintf("%q@%q", key_name, domain_name);
|
||||
count = pickup_count(dup_key_name);
|
||||
|
||||
switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN);
|
||||
|
||||
if (count) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", PICKUP_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", key_name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", key_name, domain_name);
|
||||
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "force-status", "Active (%d call%s)", count, count == 1 ? "" : "s");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "active");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", key_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
} else {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", PICKUP_PROTO);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", key_name);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", key_name, domain_name);
|
||||
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Idle");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", key_name);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated");
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound");
|
||||
|
||||
}
|
||||
|
||||
switch_event_fire(&event);
|
||||
switch_safe_free(dup_to);
|
||||
switch_safe_free(dup_key_name);
|
||||
switch_safe_free(dup_domain_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void pickup_add_session(switch_core_session_t *session, const char *key)
|
||||
{
|
||||
pickup_node_t *head, *node, *np;
|
||||
char *dup_key = NULL;
|
||||
|
||||
if (!strchr(key, '@')) {
|
||||
dup_key = switch_mprintf("%s@%s", key, switch_core_get_variable("domain"));
|
||||
key = dup_key;
|
||||
}
|
||||
|
||||
node = malloc(sizeof(*node));
|
||||
node->key = strdup(key);
|
||||
node->uuid = strdup(switch_core_session_get_uuid(session));
|
||||
node->next = NULL;
|
||||
|
||||
switch_mutex_lock(globals.pickup_mutex);
|
||||
head = switch_core_hash_find(globals.pickup_hash, key);
|
||||
|
||||
if (head) {
|
||||
for (np = head; np && np->next; np = np->next);
|
||||
np->next = node;
|
||||
} else {
|
||||
head = node;
|
||||
switch_core_hash_insert(globals.pickup_hash, key, head);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(globals.pickup_mutex);
|
||||
|
||||
pickup_send_presence(key);
|
||||
|
||||
switch_safe_free(dup_key);
|
||||
}
|
||||
|
||||
static char *pickup_pop_uuid(const char *key, const char *uuid)
|
||||
{
|
||||
pickup_node_t *node = NULL, *head;
|
||||
char *r = NULL;
|
||||
char *dup_key = NULL;
|
||||
|
||||
if (!strchr(key, '@')) {
|
||||
dup_key = switch_mprintf("%s@%s", key, switch_core_get_variable("domain"));
|
||||
key = dup_key;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.pickup_mutex);
|
||||
|
||||
if ((head = switch_core_hash_find(globals.pickup_hash, key))) {
|
||||
|
||||
switch_core_hash_delete(globals.pickup_hash, key);
|
||||
|
||||
if (uuid) {
|
||||
pickup_node_t *np, *lp = NULL;
|
||||
|
||||
for(np = head; np; np = np->next) {
|
||||
if (!strcmp(np->uuid, uuid)) {
|
||||
if (lp) {
|
||||
lp->next = np->next;
|
||||
} else {
|
||||
head = np->next;
|
||||
}
|
||||
|
||||
node = np;
|
||||
break;
|
||||
}
|
||||
|
||||
lp = np;
|
||||
}
|
||||
|
||||
} else {
|
||||
node = head;
|
||||
head = head->next;
|
||||
}
|
||||
|
||||
|
||||
if (head) {
|
||||
switch_core_hash_insert(globals.pickup_hash, key, head);
|
||||
}
|
||||
}
|
||||
|
||||
if (node) {
|
||||
r = node->uuid;
|
||||
free(node->key);
|
||||
free(node);
|
||||
}
|
||||
|
||||
switch_mutex_unlock(globals.pickup_mutex);
|
||||
|
||||
if (r) pickup_send_presence(key);
|
||||
|
||||
switch_safe_free(dup_key);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
typedef struct pickup_pvt_s {
|
||||
char *key;
|
||||
switch_event_t *vars;
|
||||
} pickup_pvt_t;
|
||||
|
||||
switch_endpoint_interface_t *pickup_endpoint_interface;
|
||||
static switch_call_cause_t pickup_outgoing_channel(switch_core_session_t *session,
|
||||
switch_event_t *var_event,
|
||||
switch_caller_profile_t *outbound_profile,
|
||||
switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
|
||||
switch_call_cause_t *cancel_cause);
|
||||
switch_io_routines_t pickup_io_routines = {
|
||||
/*.outgoing_channel */ pickup_outgoing_channel
|
||||
};
|
||||
|
||||
static switch_status_t pickup_event_handler(switch_core_session_t *session)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_channel_state_t state = switch_channel_get_running_state(channel);
|
||||
pickup_pvt_t *tech_pvt = switch_core_session_get_private(session);
|
||||
|
||||
switch(state) {
|
||||
case CS_DESTROY:
|
||||
if (tech_pvt->vars) {
|
||||
switch_event_destroy(&tech_pvt->vars);
|
||||
}
|
||||
break;
|
||||
case CS_REPORTING:
|
||||
return SWITCH_STATUS_FALSE;
|
||||
case CS_HANGUP:
|
||||
{
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_CHANNEL_SWAP)) {
|
||||
const char *key = switch_channel_get_variable(channel, "channel_swap_uuid");
|
||||
switch_core_session_t *swap_session;
|
||||
|
||||
if ((swap_session = switch_core_session_locate(key))) {
|
||||
switch_channel_t *swap_channel = switch_core_session_get_channel(swap_session);
|
||||
switch_channel_hangup(swap_channel, SWITCH_CAUSE_PICKED_OFF);
|
||||
switch_core_session_rwunlock(swap_session);
|
||||
}
|
||||
switch_channel_clear_flag(channel, CF_CHANNEL_SWAP);
|
||||
}
|
||||
|
||||
pickup_pop_uuid(tech_pvt->key, switch_core_session_get_uuid(session));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_state_handler_table_t pickup_event_handlers = {
|
||||
/*.on_init */ pickup_event_handler,
|
||||
/*.on_routing */ pickup_event_handler,
|
||||
/*.on_execute */ pickup_event_handler,
|
||||
/*.on_hangup */ pickup_event_handler,
|
||||
/*.on_exchange_media */ pickup_event_handler,
|
||||
/*.on_soft_execute */ pickup_event_handler,
|
||||
/*.on_consume_media */ pickup_event_handler,
|
||||
/*.on_hibernate */ pickup_event_handler,
|
||||
/*.on_reset */ pickup_event_handler,
|
||||
/*.on_park */ pickup_event_handler,
|
||||
/*.on_reporting */ pickup_event_handler,
|
||||
/*.on_destroy */ pickup_event_handler
|
||||
};
|
||||
|
||||
static switch_call_cause_t pickup_outgoing_channel(switch_core_session_t *session,
|
||||
switch_event_t *var_event,
|
||||
switch_caller_profile_t *outbound_profile,
|
||||
switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags,
|
||||
switch_call_cause_t *cancel_cause)
|
||||
{
|
||||
char *pickup;
|
||||
switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
|
||||
switch_core_session_t *nsession;
|
||||
switch_channel_t *nchannel;
|
||||
char *name;
|
||||
pickup_pvt_t *tech_pvt;
|
||||
switch_caller_profile_t *caller_profile;
|
||||
|
||||
if (zstr(outbound_profile->destination_number)) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
pickup = outbound_profile->destination_number;
|
||||
|
||||
|
||||
if (!(nsession = switch_core_session_request(pickup_endpoint_interface, SWITCH_CALL_DIRECTION_OUTBOUND, flags, pool))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
tech_pvt = switch_core_session_alloc(nsession, sizeof(*tech_pvt));
|
||||
tech_pvt->key = switch_core_session_strdup(nsession, pickup);
|
||||
switch_event_dup(&tech_pvt->vars, var_event);
|
||||
|
||||
switch_core_session_set_private(nsession, tech_pvt);
|
||||
|
||||
nchannel = switch_core_session_get_channel(nsession);
|
||||
caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
|
||||
switch_channel_set_caller_profile(nchannel, caller_profile);
|
||||
|
||||
switch_channel_set_state(nchannel, CS_ROUTING);
|
||||
|
||||
|
||||
|
||||
*new_session = nsession;
|
||||
cause = SWITCH_CAUSE_SUCCESS;
|
||||
name = switch_core_session_sprintf(nsession, "pickup/%s", pickup);
|
||||
switch_channel_set_name(nchannel, name);
|
||||
switch_channel_set_variable(nchannel, "process_cdr", "false");
|
||||
pickup_add_session(nsession, pickup);
|
||||
|
||||
goto done;
|
||||
|
||||
error:
|
||||
|
||||
if (nsession) {
|
||||
switch_core_session_destroy(&nsession);
|
||||
}
|
||||
|
||||
if (pool) {
|
||||
*pool = NULL;
|
||||
}
|
||||
|
||||
done:
|
||||
|
||||
|
||||
return cause;
|
||||
}
|
||||
|
||||
#define PICKUP_SYNTAX "[<key>]"
|
||||
SWITCH_STANDARD_APP(pickup_function)
|
||||
{
|
||||
char *uuid = NULL;
|
||||
switch_core_session_t *pickup_session;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (zstr(data)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing data. Usage: pickup %s\n", PICKUP_SYNTAX);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((uuid = pickup_pop_uuid((char *)data, NULL))) {
|
||||
if ((pickup_session = switch_core_session_locate(uuid))) {
|
||||
switch_channel_t *pickup_channel = switch_core_session_get_channel(pickup_session);
|
||||
switch_caller_profile_t *pickup_caller_profile = switch_channel_get_caller_profile(pickup_channel),
|
||||
*caller_profile = switch_channel_get_caller_profile(channel);
|
||||
const char *name, *num;
|
||||
switch_event_t *event;
|
||||
switch_event_header_t *hp;
|
||||
pickup_pvt_t *tech_pvt = switch_core_session_get_private(pickup_session);
|
||||
|
||||
for(hp = tech_pvt->vars->headers; hp; hp = hp->next) {
|
||||
switch_channel_set_variable(channel, hp->name, hp->value);
|
||||
}
|
||||
|
||||
|
||||
switch_channel_set_flag(pickup_channel, CF_CHANNEL_SWAP);
|
||||
switch_channel_set_variable(pickup_channel, "channel_swap_uuid", switch_core_session_get_uuid(session));
|
||||
|
||||
name = caller_profile->caller_id_name;
|
||||
num = caller_profile->caller_id_number;
|
||||
|
||||
caller_profile->caller_id_name = switch_core_strdup(caller_profile->pool, pickup_caller_profile->caller_id_name);
|
||||
caller_profile->caller_id_number = switch_core_strdup(caller_profile->pool, pickup_caller_profile->caller_id_number);
|
||||
|
||||
caller_profile->callee_id_name = name;
|
||||
caller_profile->callee_id_number = num;
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_CALL_UPDATE) == SWITCH_STATUS_SUCCESS) {
|
||||
const char *uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Direction", "RECV");
|
||||
|
||||
if (!uuid) {
|
||||
uuid = switch_channel_get_variable(channel, "originate_signal_bond");
|
||||
}
|
||||
|
||||
|
||||
if (uuid) {
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Bridged-To", uuid);
|
||||
}
|
||||
switch_channel_event_set_data(channel, event);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
|
||||
switch_channel_set_state(channel, CS_HIBERNATE);
|
||||
|
||||
switch_channel_mark_answered(pickup_channel);
|
||||
switch_core_session_rwunlock(pickup_session);
|
||||
}
|
||||
free(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* fake chan_error */
|
||||
switch_endpoint_interface_t *error_endpoint_interface;
|
||||
static switch_call_cause_t error_outgoing_channel(switch_core_session_t *session,
|
||||
@ -3985,6 +4464,14 @@ static char *file_string_supported_formats[SWITCH_MAX_CODECS] = { 0 };
|
||||
#define LOG_LONG_DESC "Logs a channel variable for the channel calling the application."
|
||||
#define TRANSFER_LONG_DESC "Immediately transfer the calling channel to a new extension"
|
||||
#define SLEEP_LONG_DESC "Pause the channel for a given number of milliseconds, consuming the audio for that period of time."
|
||||
|
||||
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_dptools_shutdown)
|
||||
{
|
||||
switch_event_unbind_callback(pickup_pres_event_handler);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
{
|
||||
switch_api_interface_t *api_interface;
|
||||
@ -3993,9 +4480,16 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
switch_chat_interface_t *chat_interface;
|
||||
switch_file_interface_t *file_interface;
|
||||
|
||||
globals.pool = pool;
|
||||
switch_core_hash_init(&globals.pickup_hash, NULL);
|
||||
switch_mutex_init(&globals.pickup_mutex, SWITCH_MUTEX_NESTED, globals.pool);
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
||||
switch_event_bind(modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, pickup_pres_event_handler, NULL);
|
||||
|
||||
|
||||
file_string_supported_formats[0] = "file_string";
|
||||
|
||||
file_interface = (switch_file_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
|
||||
@ -4019,6 +4513,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
user_endpoint_interface->interface_name = "user";
|
||||
user_endpoint_interface->io_routines = &user_io_routines;
|
||||
|
||||
pickup_endpoint_interface = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE);
|
||||
pickup_endpoint_interface->interface_name = "pickup";
|
||||
pickup_endpoint_interface->io_routines = &pickup_io_routines;
|
||||
pickup_endpoint_interface->state_handler = &pickup_event_handlers;
|
||||
|
||||
SWITCH_ADD_CHAT(chat_interface, "event", event_chat_send);
|
||||
SWITCH_ADD_CHAT(chat_interface, "api", api_chat_send);
|
||||
|
||||
@ -4193,6 +4692,9 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
|
||||
SWITCH_ADD_APP(app_interface, "limit_execute", "Limit", LIMITEXECUTE_DESC, limit_execute_function, LIMITEXECUTE_USAGE, SAF_SUPPORT_NOMEDIA);
|
||||
SWITCH_ADD_APP(app_interface, "limit_hash_execute", "Limit", LIMITHASHEXECUTE_DESC, limit_hash_execute_function, LIMITHASHEXECUTE_USAGE, SAF_SUPPORT_NOMEDIA);
|
||||
|
||||
SWITCH_ADD_APP(app_interface, "pickup", "Pickup", "Pickup a call", pickup_function, PICKUP_SYNTAX, SAF_SUPPORT_NOMEDIA);
|
||||
|
||||
|
||||
SWITCH_ADD_DIALPLAN(dp_interface, "inline", inline_dialplan_hunt);
|
||||
|
||||
/* indicate that the module should continue to be loaded */
|
||||
|
@ -1761,6 +1761,20 @@ static int sofia_dialog_probe_callback(void *pArg, int argc, char **argv, char *
|
||||
remote_user = to_user;
|
||||
remote_host = local_host;
|
||||
}
|
||||
else if (proto && !strcasecmp(proto, "pickup")) {
|
||||
local_user = to_user;
|
||||
local_user_param = switch_mprintf(";proto=%s", proto);
|
||||
event_status = "hold";
|
||||
if (skip_proto) {
|
||||
buf_to_free = switch_mprintf("sip:%s", to_user);
|
||||
} else {
|
||||
buf_to_free = switch_mprintf("sip:pickup+%s", to_user);
|
||||
}
|
||||
remote_uri = buf_to_free;
|
||||
strcpy(remote_display_buf, "pickup");
|
||||
remote_user = to_user;
|
||||
remote_host = local_host;
|
||||
}
|
||||
else if (proto && !strcasecmp(proto, "conf")) {
|
||||
local_user = to_user;
|
||||
local_user_param = switch_mprintf(";proto=%s", proto);
|
||||
@ -2626,6 +2640,18 @@ static int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char *
|
||||
stream.write_function(&stream, "<target uri=\"sip:park+%s\"/>\n", uuid);
|
||||
}
|
||||
stream.write_function(&stream, "</remote>\n");
|
||||
} else if (!strcasecmp(proto, "pickup")) {
|
||||
stream.write_function(&stream, "<local>\n<identity display=\"pickup\">sip:%s@%s;proto=pickup</identity>\n",
|
||||
!zstr(clean_to_user) ? clean_to_user : "unknown", host);
|
||||
stream.write_function(&stream, "<target uri=\"sip:%s@%s;proto=pickup\">\n", !zstr(clean_to_user) ? clean_to_user : "unknown", host);
|
||||
stream.write_function(&stream, "<param pname=\"+sip.rendering\" pvalue=\"no\"/>\n</target>\n</local>\n");
|
||||
stream.write_function(&stream, "<remote>\n<identity display=\"pickup\">sip:%s</identity>\n", uuid);
|
||||
if (skip_proto) {
|
||||
stream.write_function(&stream, "<target uri=\"sip:%s\"/>\n", uuid);
|
||||
} else {
|
||||
stream.write_function(&stream, "<target uri=\"sip:pickup+%s\"/>\n", uuid);
|
||||
}
|
||||
stream.write_function(&stream, "</remote>\n");
|
||||
} else if (!strcasecmp(proto, "conf")) {
|
||||
stream.write_function(&stream, "<local>\n<identity display=\"conference\">sip:%s@%s;proto=conference</identity>\n",
|
||||
!zstr(clean_to_user) ? clean_to_user : "unknown", host);
|
||||
|
@ -3541,6 +3541,25 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess
|
||||
if (*bleg) {
|
||||
switch_channel_t *bchan = switch_core_session_get_channel(*bleg);
|
||||
|
||||
|
||||
if (switch_channel_test_flag(bchan, CF_CHANNEL_SWAP)) {
|
||||
const char *key = switch_channel_get_variable(bchan, "channel_swap_uuid");
|
||||
switch_core_session_t *swap_session, *old_session;
|
||||
|
||||
if ((swap_session = switch_core_session_locate(key))) {
|
||||
switch_channel_clear_flag(bchan, CF_CHANNEL_SWAP);
|
||||
switch_channel_hangup(bchan, SWITCH_CAUSE_PICKED_OFF);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(bchan), SWITCH_LOG_DEBUG, "Swapping %s for %s\n",
|
||||
switch_core_session_get_name(swap_session), switch_channel_get_name(bchan));
|
||||
|
||||
old_session = *bleg;
|
||||
*bleg = swap_session;
|
||||
bchan = switch_core_session_get_channel(*bleg);
|
||||
switch_channel_answer(bchan);
|
||||
switch_core_session_rwunlock(old_session);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (session && caller_channel) {
|
||||
|
Loading…
Reference in New Issue
Block a user