Remove dead code from features.c; refactor pickup code into pickup.c

This patch does the following:
 * It moves the pickup code out of features.c and into pickup.c
 * It removes the vast majority of dead code out of features.c. In particular,
   this includes the parking code.

(issue ASTERISK-22134)



git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@396060 65c4cc65-6c06-0410-ace0-fbb531ad65f3
changes/78/78/1
Matthew Jordan 12 years ago
parent 63a229e369
commit 38236e54a8

@ -311,6 +311,15 @@ AMI (Asterisk Manager Interface)
account. When set in the general context, it will act as the default
setting for defined accounts.
* The 'BridgeAction' event was removed. It technically added no value, as the
Bridge Action already receives confirmation of the bridge through a
successful completion Event.
* The 'BridgeExec' events were removed. These events duplicated the events that
occur in the Briding API, and are conveyed now through BridgeCreate,
BridgeEnter, and BridgeLeave events.
AGI (Asterisk Gateway Interface)
------------------
* The manager event AGIExec has been split into AGIExecStart and AGIExecEnd.

@ -185,6 +185,10 @@ Features:
- Executing a dynamic feature on the bridge peer in a multi-party bridge will
execute it on all peers of the activating channel.
- There is no longer an explicit 'features reload' CLI command. Features can still be
reloaded using 'module reload features'.
Parking:
- The arguments for the Park, ParkedCall, and ParkAndAnnounce applications have
been modified significantly. See the application documents for specific details.

@ -43,7 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/app.h"
#include "asterisk/features.h"
#include "asterisk/pickup.h"
#include "asterisk/manager.h"
#include "asterisk/callerid.h"
@ -305,7 +305,7 @@ static int pickup_exec(struct ast_channel *chan, const char *data)
return 0;
}
/* Find channel for pick up specified by partial channel name */
/* Find channel for pick up specified by partial channel name */
static int find_by_part(void *obj, void *arg, void *data, int flags)
{
struct ast_channel *target = obj;/*!< Potential pickup target */
@ -323,7 +323,7 @@ static int find_by_part(void *obj, void *arg, void *data, int flags)
return 0;
}
/* Attempt to pick up specified by partial channel name */
/* Attempt to pick up specified by partial channel name */
static int pickup_by_part(struct ast_channel *chan, const char *part)
{
struct ast_channel *target;/*!< Potential pickup target */

@ -85,7 +85,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/abstract_jb.h"
#include "asterisk/jabber.h"
#include "asterisk/jingle.h"
#include "asterisk/features.h"
#include "asterisk/parking.h"
#include "asterisk/stasis_channels.h"
#define GOOGLE_CONFIG "gtalk.conf"
@ -2319,8 +2319,8 @@ static int gtalk_load_config(void)
* Module loading including tests for configuration or dependencies.
* This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
* or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
* tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
* configuration file or other non-critical problem return
* tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
* configuration file or other non-critical problem return
* AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
*/
static int load_module(void)

@ -259,7 +259,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/cli.h"
#include "asterisk/musiconhold.h"
#include "asterisk/dsp.h"
#include "asterisk/features.h"
#include "asterisk/pickup.h"
#include "asterisk/parking.h"
#include "asterisk/srv.h"
#include "asterisk/astdb.h"
#include "asterisk/causes.h"

@ -68,7 +68,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/manager.h"
#include "asterisk/say.h"
#include "asterisk/astdb.h"
#include "asterisk/features.h"
#include "asterisk/pickup.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/utils.h"

@ -73,7 +73,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/musiconhold.h"
#include "asterisk/causes.h"
#include "asterisk/indications.h"
#include "asterisk/features.h"
#include "asterisk/pickup.h"
#include "asterisk/astobj2.h"
#include "asterisk/astdb.h"
#include "asterisk/features_config.h"

@ -8,7 +8,7 @@
*
* \brief
* Prototypes for public functions only of internal interest,
*
*
*/
@ -25,7 +25,7 @@ int astdb_init(void); /*!< Provided by db.c */
void ast_channels_init(void); /*!< Provided by channel.c */
void ast_builtins_init(void); /*!< Provided by cli.c */
int ast_cli_perms_init(int reload); /*!< Provided by cli.c */
int dnsmgr_init(void); /*!< Provided by dnsmgr.c */
int dnsmgr_init(void); /*!< Provided by dnsmgr.c */
void dnsmgr_start_refresh(void); /*!< Provided by dnsmgr.c */
int dnsmgr_reload(void); /*!< Provided by dnsmgr.c */
void threadstorage_init(void); /*!< Provided by threadstorage.c */
@ -109,9 +109,9 @@ enum ast_module_reload_result ast_module_reload(const char *name);
*/
void ast_process_pending_reloads(void);
/*! \brief Load XML documentation. Provided by xmldoc.c
/*! \brief Load XML documentation. Provided by xmldoc.c
* \retval 1 on error.
* \retval 0 on success.
* \retval 0 on success.
*/
int ast_xmldoc_load_documentation(void);

@ -28,30 +28,6 @@
#include "asterisk/linkedlists.h"
#include "asterisk/bridge.h"
#define FEATURE_MAX_LEN 11
#define FEATURE_APP_LEN 64
#define FEATURE_APP_ARGS_LEN 256
#define FEATURE_SNAME_LEN 32
#define FEATURE_EXTEN_LEN 32
#define FEATURE_MOH_LEN 80 /* same as MAX_MUSICCLASS from channel.h */
#define DEFAULT_PARKINGLOT "default" /*!< Default parking lot */
#define AST_FEATURE_RETURN_HANGUP -1
#define AST_FEATURE_RETURN_SUCCESSBREAK 0
#define AST_FEATURE_RETURN_PBX_KEEPALIVE AST_PBX_KEEPALIVE
#define AST_FEATURE_RETURN_NO_HANGUP_PEER AST_PBX_NO_HANGUP_PEER
#define AST_FEATURE_RETURN_PASSDIGITS 21
#define AST_FEATURE_RETURN_STOREDIGITS 22
#define AST_FEATURE_RETURN_SUCCESS 23
#define AST_FEATURE_RETURN_KEEPTRYING 24
#define AST_FEATURE_RETURN_PARKFAILED 25
#define FEATURE_SENSE_CHAN (1 << 0)
#define FEATURE_SENSE_PEER (1 << 1)
typedef int (*ast_feature_operation)(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, const char *code, int sense, void *data);
/*! \brief main call feature structure */
enum {
@ -93,54 +69,7 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer,struct as
int ast_bridge_add_channel(struct ast_bridge *bridge, struct ast_channel *chan,
struct ast_bridge_features *features, int play_tone, const char *xfersound);
/*!
* \brief Test if a channel can be picked up.
*
* \param chan Channel to test if can be picked up.
*
* \note This function assumes that chan is locked.
*
* \return TRUE if channel can be picked up.
*/
int ast_can_pickup(struct ast_channel *chan);
/*!
* \brief Find a pickup channel target by group.
*
* \param chan channel that initiated pickup.
*
* \retval target on success. The returned channel is locked and reffed.
* \retval NULL on error.
*/
struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan);
/*! \brief Pickup a call */
int ast_pickup_call(struct ast_channel *chan);
/*!
* \brief Pickup a call target.
*
* \param chan channel that initiated pickup.
* \param target channel to be picked up.
*
* \note This function assumes that target is locked.
*
* \retval 0 on success.
* \retval -1 on failure.
*/
int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target);
/*!
* \brief accessor for call pickup message type
* \since 12.0.0
*
* \retval pointer to the stasis message type
* \retval NULL if not initialized
*/
struct stasis_message_type *ast_call_pickup_type(void);
/*! \brief Reload call features from features.conf */
int ast_features_reload(void);
/*!
* \brief parse L option and read associated channel variables to set warning, warning frequency, and timelimit

@ -30,6 +30,11 @@
*/
#define PARK_APPLICATION "Park"
/*!
* \brief The default parking lot
*/
#define DEFAULT_PARKINGLOT "default"
/*!
* \brief Defines the type of parked call message being published
* \since 12

@ -0,0 +1,91 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2013, Digium, Inc.
*
* Matt Jordan <mjordan@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*!
* \file
* \brief Call Pickup API
*
* Includes code and algorithms from the Zapata library.
*
*/
#ifndef _AST_FEATURES_H
#define _AST_FEATURES_H
/*!
* \brief Test if a channel can be picked up.
*
* \param chan Channel to test if can be picked up.
*
* \note This function assumes that chan is locked.
*
* \return TRUE if channel can be picked up.
*/
int ast_can_pickup(struct ast_channel *chan);
/*!
* \brief Find a pickup channel target by group.
*
* \param chan channel that initiated pickup.
*
* \retval target on success. The returned channel is locked and reffed.
* \retval NULL on error.
*/
struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan);
/*!
* \brief Pickup a call
*
* \param chan The channel that initiated the pickup
*
* \retval 0 on success
* \retval -1 on failure
*/
int ast_pickup_call(struct ast_channel *chan);
/*!
* \brief Pickup a call target.
*
* \param chan channel that initiated pickup.
* \param target channel to be picked up.
*
* \note This function assumes that target is locked.
*
* \retval 0 on success.
* \retval -1 on failure.
*/
int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target);
/*!
* \brief accessor for call pickup message type
* \since 12.0.0
*
* \retval pointer to the stasis message type
* \retval NULL if not initialized
*/
struct stasis_message_type *ast_call_pickup_type(void);
/*!
* \brief Initialize pickup
*
* \retval 0 on success
* \retval non-zero on failure
*/
int ast_pickup_init(void);
#endif /* _AST_FEATURES_H */

@ -202,6 +202,7 @@ int daemon(int, int); /* defined in libresolv of all places */
#include "asterisk/cli.h"
#include "asterisk/channel.h"
#include "asterisk/translate.h"
#include "asterisk/pickup.h"
#include "asterisk/features.h"
#include "asterisk/acl.h"
#include "asterisk/ulaw.h"
@ -4298,6 +4299,11 @@ int main(int argc, char *argv[])
exit(1);
}
if (ast_pickup_init()) {
printf("%s", term_quit());
exit(1);
}
if (ast_bridging_init()) {
printf("%s", term_quit());
exit(1);

@ -40,6 +40,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/bridge.h"
#include "asterisk/bridge_internal.h"
#include "asterisk/bridge_channel_internal.h"
#include "asterisk/bridge_features.h"
#include "asterisk/bridge_basic.h"
#include "asterisk/bridge_technology.h"
#include "asterisk/bridge_channel.h"

@ -916,17 +916,14 @@ static int snapshot_cep_changed(struct ast_channel_snapshot *old_snapshot,
return 0;
}
if (strcmp(new_snapshot->context, old_snapshot->context)
|| strcmp(new_snapshot->exten, old_snapshot->exten)
|| new_snapshot->priority != old_snapshot->priority) {
return 1;
}
/* When Party A is originated to an application and the application exits, the stack
* will attempt to clear the application and restore the dummy originate application
* of "AppDialX". Ignore application changes to AppDialX as a result.
*/
if (strcmp(new_snapshot->appl, old_snapshot->appl) && strncasecmp(new_snapshot->appl, "appdial", 7)) {
if (strcmp(new_snapshot->appl, old_snapshot->appl) && strncasecmp(new_snapshot->appl, "appdial", 7)
&& (strcmp(new_snapshot->context, old_snapshot->context)
|| strcmp(new_snapshot->exten, old_snapshot->exten)
|| new_snapshot->priority != old_snapshot->priority)) {
return 1;
}

@ -61,7 +61,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/stasis_bridges.h"
#include "asterisk/bridge.h"
#include "asterisk/parking.h"
#include "asterisk/features.h"
#include "asterisk/pickup.h"
#include "asterisk/core_local.h"
/*** DOCUMENTATION

File diff suppressed because it is too large Load Diff

@ -4651,18 +4651,6 @@ static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
COLORIZE(COLOR_BRMAGENTA, 0, passdata),
"in new stack");
}
snapshot = ast_channel_snapshot_create(c);
if (snapshot) {
/* pbx_exec sets application name and data, but we don't want to log
* every exec. Just update the snapshot here instead.
*/
ast_string_field_set(snapshot, appl, app->name);
ast_string_field_set(snapshot, data, passdata);
msg = stasis_message_create(ast_channel_snapshot_type(), snapshot);
if (msg) {
stasis_publish(ast_channel_topic(c), msg);
}
}
return pbx_exec(c, app, passdata); /* 0 on success, -1 on failure */
}
} else if (q.swo) { /* not found here, but in another switch */

@ -0,0 +1,423 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 1999 - 2013, Digium, Inc.
* Copyright (C) 2012, Russell Bryant
*
* Matt Jordan <mjordan@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Routines implementing call pickup
*
* \author Matt Jordan <mjordan@digium.com>
*/
/*!
* \li Call pickup uses the configuration file \ref features.conf
* \addtogroup configuration_file Configuration Files
*/
/*** MODULEINFO
<support_level>core</support_level>
***/
/*** DOCUMENTATION
<managerEvent language="en_US" name="Pickup">
<managerEventInstance class="EVENT_FLAG_CALL">
<synopsis>Raised when a call pickup occurs.</synopsis>
<syntax>
<xi:include xpointer="xpointer(/docs/managerEvent[@name='Newchannel']/managerEventInstance/syntax/parameter)" />
<parameter name="TargetChannel"/>
<parameter name="TargetChannelState"><para>A numeric code for the channel's current state, related to TargetChannelStateDesc</para></parameter>
<parameter name="TargetChannelStateDesc">
<enumlist>
<enum name="Down"/>
<enum name="Rsrvd"/>
<enum name="OffHook"/>
<enum name="Dialing"/>
<enum name="Ring"/>
<enum name="Ringing"/>
<enum name="Up"/>
<enum name="Busy"/>
<enum name="Dialing Offhook"/>
<enum name="Pre-ring"/>
<enum name="Unknown"/>
</enumlist>
</parameter>
<parameter name="TargetCallerIDNum"/>
<parameter name="TargetCallerIDName"/>
<parameter name="TargetConnectedLineNum"/>
<parameter name="TargetConnectedLineName"/>
<parameter name="TargetAccountCode"/>
<parameter name="TargetContext"/>
<parameter name="TargetExten"/>
<parameter name="TargetPriority"/>
<parameter name="TargetUniqueid"/>
</syntax>
</managerEventInstance>
</managerEvent>
***/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/pickup.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/callerid.h"
#include "asterisk/causes.h"
#include "asterisk/stasis.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/features_config.h"
static struct ast_manager_event_blob *call_pickup_to_ami(struct stasis_message *message);
STASIS_MESSAGE_TYPE_DEFN(
ast_call_pickup_type,
.to_ami = call_pickup_to_ami);
/*!
* The presence of this datastore on the channel indicates that
* someone is attemting to pickup or has picked up the channel.
* The purpose is to prevent a race between two channels
* attempting to pickup the same channel.
*/
static const struct ast_datastore_info pickup_active = {
.type = "pickup-active",
};
int ast_can_pickup(struct ast_channel *chan)
{
if (!ast_channel_pbx(chan) && !ast_channel_masq(chan) && !ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
&& (ast_channel_state(chan) == AST_STATE_RINGING
|| ast_channel_state(chan) == AST_STATE_RING
/*
* Check the down state as well because some SIP devices do not
* give 180 ringing when they can just give 183 session progress
* instead. Issue 14005. (Some ISDN switches as well for that
* matter.)
*/
|| ast_channel_state(chan) == AST_STATE_DOWN)
&& !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
return 1;
}
return 0;
}
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
{
struct ast_channel *target = obj; /*!< Potential pickup target */
struct ast_channel *chan = arg; /*!< Channel wanting to pickup call */
if (chan == target) {
return 0;
}
ast_channel_lock(target);
if (ast_can_pickup(target)) {
/* Lock both channels. */
while (ast_channel_trylock(chan)) {
ast_channel_unlock(target);
sched_yield();
ast_channel_lock(target);
}
/*
* Both callgroup and namedcallgroup pickup variants are
* matched independently. Checking for named group match is
* done last since it's a more expensive operation.
*/
if ((ast_channel_pickupgroup(chan) & ast_channel_callgroup(target))
|| (ast_namedgroups_intersect(ast_channel_named_pickupgroups(chan),
ast_channel_named_callgroups(target)))) {
struct ao2_container *candidates = data;/*!< Candidate channels found. */
/* This is a candidate to pickup */
ao2_link(candidates, target);
}
ast_channel_unlock(chan);
}
ast_channel_unlock(target);
return 0;
}
struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan)
{
struct ao2_container *candidates;/*!< Candidate channels found to pickup. */
struct ast_channel *target;/*!< Potential pickup target */
candidates = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
if (!candidates) {
return NULL;
}
/* Find all candidate targets by group. */
ast_channel_callback(find_channel_by_group, chan, candidates, 0);
/* Find the oldest pickup target candidate */
target = NULL;
for (;;) {
struct ast_channel *candidate;/*!< Potential new older target */
struct ao2_iterator iter;
iter = ao2_iterator_init(candidates, 0);
while ((candidate = ao2_iterator_next(&iter))) {
if (!target) {
/* First target. */
target = candidate;
continue;
}
if (ast_tvcmp(ast_channel_creationtime(candidate), ast_channel_creationtime(target)) < 0) {
/* We have a new target. */
ast_channel_unref(target);
target = candidate;
continue;
}
ast_channel_unref(candidate);
}
ao2_iterator_destroy(&iter);
if (!target) {
/* No candidates found. */
break;
}
/* The found channel must be locked and ref'd. */
ast_channel_lock(target);
/* Recheck pickup ability */
if (ast_can_pickup(target)) {
/* This is the channel to pickup. */
break;
}
/* Someone else picked it up or the call went away. */
ast_channel_unlock(target);
ao2_unlink(candidates, target);
target = ast_channel_unref(target);
}
ao2_ref(candidates, -1);
return target;
}
/*!
* \brief Pickup a call
* \param chan channel that initiated pickup.
*
* Walk list of channels, checking it is not itself, channel is pbx one,
* check that the callgroup for both channels are the same and the channel is ringing.
* Answer calling channel, flag channel as answered on queue, masq channels together.
*/
int ast_pickup_call(struct ast_channel *chan)
{
struct ast_channel *target;/*!< Potential pickup target */
int res = -1;
RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
const char *pickup_sound;
const char *fail_sound;
ast_debug(1, "Pickup attempt by %s\n", ast_channel_name(chan));
ast_channel_lock(chan);
pickup_cfg = ast_get_chan_features_pickup_config(chan);
if (!pickup_cfg) {
ast_log(LOG_ERROR, "Unable to retrieve pickup configuration. Unable to play pickup sounds\n");
}
pickup_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupsound : "");
fail_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupfailsound : "");
ast_channel_unlock(chan);
/* The found channel is already locked. */
target = ast_pickup_find_by_group(chan);
if (target) {
ast_log(LOG_NOTICE, "Pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan));
res = ast_do_pickup(chan, target);
ast_channel_unlock(target);
if (!res) {
if (!ast_strlen_zero(pickup_sound)) {
pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickup_sound);
}
} else {
ast_log(LOG_WARNING, "Pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan));
}
target = ast_channel_unref(target);
}
if (res < 0) {
ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan));
if (!ast_strlen_zero(fail_sound)) {
ast_answer(chan);
ast_stream_and_wait(chan, fail_sound, "");
}
}
return res;
}
static struct ast_manager_event_blob *call_pickup_to_ami(struct stasis_message *message)
{
struct ast_multi_channel_blob *contents = stasis_message_data(message);
struct ast_channel_snapshot *chan;
struct ast_channel_snapshot *target;
struct ast_manager_event_blob *res;
RAII_VAR(struct ast_str *, channel_str, NULL, ast_free);
RAII_VAR(struct ast_str *, target_str, NULL, ast_free);
chan = ast_multi_channel_blob_get_channel(contents, "channel");
target = ast_multi_channel_blob_get_channel(contents, "target");
ast_assert(chan != NULL && target != NULL);
if (!(channel_str = ast_manager_build_channel_state_string(chan))) {
return NULL;
}
if (!(target_str = ast_manager_build_channel_state_string_prefix(target, "Target"))) {
return NULL;
}
res = ast_manager_event_blob_create(EVENT_FLAG_CALL, "Pickup",
"%s"
"%s",
ast_str_buffer(channel_str),
ast_str_buffer(target_str));
return res;
}
static int send_call_pickup_stasis_message(struct ast_channel *picking_up, struct ast_channel_snapshot *chan, struct ast_channel_snapshot *target)
{
RAII_VAR(struct ast_multi_channel_blob *, pickup_payload, NULL, ao2_cleanup);
RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
if (!(pickup_payload = ast_multi_channel_blob_create(ast_json_null()))) {
return -1;
}
ast_multi_channel_blob_add_channel(pickup_payload, "channel", chan);
ast_multi_channel_blob_add_channel(pickup_payload, "target", target);
if (!(msg = stasis_message_create(ast_call_pickup_type(), pickup_payload))) {
return -1;
}
stasis_publish(ast_channel_topic(picking_up), msg);
return 0;
}
int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
{
struct ast_party_connected_line connected_caller;
struct ast_datastore *ds_pickup;
const char *chan_name;/*!< A masquerade changes channel names. */
const char *target_name;/*!< A masquerade changes channel names. */
int res = -1;
RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup);
RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup);
target_name = ast_strdupa(ast_channel_name(target));
ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));
/* Mark the target to block any call pickup race. */
ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
if (!ds_pickup) {
ast_log(LOG_WARNING,
"Unable to create channel datastore on '%s' for call pickup\n", target_name);
return -1;
}
ast_channel_datastore_add(target, ds_pickup);
ast_party_connected_line_init(&connected_caller);
ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target));
ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
/* Reset any earlier private connected id representation */
ast_party_id_reset(&connected_caller.priv);
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) &&
ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
ast_channel_update_connected_line(chan, &connected_caller, NULL);
}
ast_party_connected_line_free(&connected_caller);
ast_channel_lock(chan);
chan_name = ast_strdupa(ast_channel_name(chan));
ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan));
ast_channel_unlock(chan);
connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
if (ast_answer(chan)) {
ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
goto pickup_failed;
}
if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
goto pickup_failed;
}
ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
/* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);
if (!(chan_snapshot = ast_channel_snapshot_create(chan))) {
goto pickup_failed;
}
if (!(target_snapshot = ast_channel_snapshot_create(target))) {
goto pickup_failed;
}
if (ast_channel_move(target, chan)) {
ast_log(LOG_WARNING, "Unable to complete call pickup of '%s' with '%s'\n",
chan_name, target_name);
goto pickup_failed;
}
/* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */
send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot);
res = 0;
pickup_failed:
ast_channel_lock(target);
if (!ast_channel_datastore_remove(target, ds_pickup)) {
ast_datastore_free(ds_pickup);
}
ast_party_connected_line_free(&connected_caller);
return res;
}
/*! \internal \brief Clean up resources on Asterisk shutdown */
static void pickup_shutdown(void)
{
STASIS_MESSAGE_TYPE_CLEANUP(ast_call_pickup_type);
}
int ast_pickup_init(void)
{
STASIS_MESSAGE_TYPE_INIT(ast_call_pickup_type);
ast_register_atexit(pickup_shutdown);
return 0;
}

@ -37,7 +37,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/module.h"
#include "asterisk/app.h"
#include "asterisk/say.h"
#include "asterisk/features.h"
#include "asterisk/bridge_basic.h"
/*** DOCUMENTATION

@ -578,5 +578,6 @@ void unload_parking_manager(void)
{
ast_manager_unregister("Parkinglots");
ast_manager_unregister("ParkedCalls");
ast_manager_unregister("Park");
parking_manager_disable_stasis();
}

@ -1227,6 +1227,9 @@ static int reload_module(void)
static int unload_module(void)
{
/*ast_parking_unregister_bridge_features(parking_provider.module_name);*/
/* XXX Parking is currently not unloadable due to the fact that it loads features which could cause
* significant problems if they disappeared while a channel still had access to them.
*/

@ -34,7 +34,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/dial.h"
#include "asterisk/bridge.h"
#include "asterisk/bridge_basic.h"
#include "asterisk/bridge_features.h"
#include "asterisk/frame.h"
#include "asterisk/pbx.h"
#include "asterisk/musiconhold.h"

@ -43,7 +43,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/causes.h"
#include "asterisk/time.h"
#include "asterisk/bridge.h"
#include "asterisk/bridge_basic.h"
#include "asterisk/bridge_features.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_bridges.h"

@ -44,7 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/causes.h"
#include "asterisk/time.h"
#include "asterisk/bridge.h"
#include "asterisk/bridge_basic.h"
#include "asterisk/bridge_features.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_bridges.h"
#include "asterisk/json.h"

Loading…
Cancel
Save