72 unsigned int hangup_after:1;
76 static void parked_subscription_datastore_destroy(
void *data)
81 subscription_datastore->parked_subscription = NULL;
83 ast_free(subscription_datastore);
87 .
type =
"park subscription",
88 .destroy = parked_subscription_datastore_destroy,
91 static void wipe_subscription_datastore(
struct ast_channel *chan)
95 ast_channel_lock(chan);
102 ast_channel_unlock(chan);
108 const char *parkee_to_act_on = data->parkee_uuid;
114 if (strcmp(parkee_to_act_on, parkee_snapshot->
base->
uniqueid)) {
128 ast_channel_lock(parker);
130 ast_channel_unlock(parker);
131 if (!bridge_channel) {
139 snprintf(saynum_buf,
sizeof(saynum_buf),
"%d %u", data->hangup_after, message->
parkingspace);
140 if (!data->transfer_data) {
146 wipe_subscription_datastore(parker);
147 }
else if (message->
event_type == PARKED_CALL_FAILED) {
148 if (!data->transfer_data) {
154 wipe_subscription_datastore(parker);
162 ao2_cleanup(ps_data->transfer_data);
163 ps_data->transfer_data = NULL;
170 parker_parked_call_message_response(parked_call_message, data, sub);
174 static int create_parked_subscription_full(
struct ast_channel *chan,
const char *parkee_uuid,
int hangup_after,
181 char *parker_uuid =
ast_strdupa(ast_channel_uniqueid(chan));
182 size_t parker_uuid_size;
183 size_t parkee_uuid_size;
186 wipe_subscription_datastore(chan);
188 if (!(datastore = ast_datastore_alloc(&parked_subscription_info, NULL))) {
192 if (!(parked_datastore =
ast_calloc(1,
sizeof(*parked_datastore)))) {
197 parker_uuid_size = strlen(parker_uuid) + 1;
198 parkee_uuid_size = strlen(parkee_uuid) + 1;
200 if (!(subscription_data =
ast_calloc(1,
sizeof(*subscription_data) + parker_uuid_size +
201 parkee_uuid_size))) {
203 ast_free(parked_datastore);
207 if (parked_channel_data) {
208 subscription_data->transfer_data = parked_channel_data;
209 ao2_ref(parked_channel_data, +1);
212 subscription_data->hangup_after = hangup_after;
213 subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size;
214 ast_copy_string(subscription_data->parkee_uuid, parkee_uuid, parkee_uuid_size);
215 ast_copy_string(subscription_data->parker_uuid, parker_uuid, parker_uuid_size);
217 if (!(parked_datastore->parked_subscription = stasis_subscribe_pool(
ast_parking_topic(), parker_update_cb, subscription_data))) {
224 datastore->
data = parked_datastore;
226 ast_channel_lock(chan);
228 ast_channel_unlock(chan);
235 return create_parked_subscription_full(chan, parkee_uuid, hangup_after, NULL);
252 snprintf(destination,
sizeof(destination),
"%s@%s", exten, context);
255 parkee =
ast_request(
"Local", ast_channel_nativeformats(parker), NULL, parker, destination,
264 ast_channel_parkinglot_set(parkee, ast_channel_parkinglot(parker));
269 ast_channel_unlock(parker);
272 ast_assert(parkee_side_2 != NULL);
273 ast_channel_unlock(parkee);
276 if (create_parked_subscription_full(parker, ast_channel_uniqueid(parkee_side_2), 1, parked_channel_data)) {
285 if (
ast_call(parkee, destination, 0)) {
297 static int parking_is_exten_park(
const char *context,
const char *exten)
301 const char *app_at_exten;
303 ast_debug(4,
"Checking if %s@%s is a parking exten\n", exten, context);
304 exten_obj = pbx_find_extension(NULL, NULL, &info, context, exten, 1, NULL, NULL, E_MATCH);
309 app_at_exten = ast_get_extension_app(exten_obj);
347 if (ast_strlen_zero(context) || ast_strlen_zero(exten)) {
355 if (!parking_is_exten_park(context, exten)) {
361 if (peer_count == 2) {
364 other_chan = other->chan;
369 if (peer_count < 2) {
377 if (peer_count > 2) {
380 transfer_chan = park_local_transfer(bridge_channel->
chan, context, exten, parked_channel_data);
381 if (!transfer_chan) {
386 if (parked_channel_cb) {
403 if (create_parked_subscription_full(bridge_channel->
chan, ast_channel_uniqueid(other->chan), 1, parked_channel_data)) {
407 if (parked_channel_cb) {
411 e = pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH);
415 ast_channel_uniqueid(other_chan),
416 ast_channel_uniqueid(bridge_channel->
chan),
417 e ? ast_get_extension_app_data(e) : NULL);
434 static int parking_park_bridge_channel(
struct ast_bridge_channel *bridge_channel,
const char *uuid_parkee,
const char *uuid_parker,
const char *
app_data)
440 if (strcmp(ast_channel_uniqueid(bridge_channel->
chan), uuid_parkee)) {
448 ast_log(LOG_NOTICE,
"Channel with uuid %s left before we could start parking the call. Parking canceled.\n", uuid_parker);
461 ao2_lock(bridge_channel);
463 original_bridge = bridge_channel->
bridge;
464 if (!original_bridge) {
465 ao2_unlock(bridge_channel);
472 ao2_unlock(bridge_channel);
475 ast_log(LOG_ERROR,
"Failed to move %s into the parking bridge.\n",
476 ast_channel_name(bridge_channel->
chan));
499 static int parking_park_call(
struct ast_bridge_channel *parker,
char *exten,
size_t length)
502 const char *lot_name;
504 ast_channel_lock(parker->
chan);
506 ast_channel_unlock(parker->
chan);
513 ast_log(AST_LOG_WARNING,
"Cannot Park %s: lot %s unknown\n",
514 ast_channel_name(parker->
chan), lot_name);
521 return parking_blind_transfer_park(parker, lot->cfg->parking_con, lot->cfg->parkext, NULL, NULL);
524 static int feature_park_call(
struct ast_bridge_channel *bridge_channel,
void *hook_pvt)
528 parking_park_call(bridge_channel, NULL, 0);
573 static int parking_duration_callback(
struct ast_bridge_channel *bridge_channel,
void *hook_pvt)
578 const char *dial_string;
579 char *dial_string_flat;
583 char *duplicate_returnexten;
600 AST_CAUSE_NORMAL_CLEARING);
607 snprintf(parking_space,
sizeof(parking_space),
"%d", user->
parking_space);
608 ast_channel_lock(chan);
614 parking_timeout_set_caller_features(chan, user->
lot->
cfg);
616 ast_channel_unlock(chan);
621 ast_log(LOG_ERROR,
"Failed to lock the contexts list. Can't add the park-dial extension.\n");
626 ast_log(LOG_ERROR,
"Parking dial context '%s' does not exist and unable to create\n", PARK_DIAL_CONTEXT);
630 goto abandon_extension_creation;
634 ast_log(LOG_ERROR,
"failed to obtain write lock on context '%s'\n", PARK_DIAL_CONTEXT);
638 goto abandon_extension_creation;
645 snprintf(returnexten,
sizeof(returnexten),
"%s,%u", dial_string,
648 duplicate_returnexten =
ast_strdup(returnexten);
649 if (!duplicate_returnexten) {
650 ast_log(LOG_ERROR,
"Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
651 dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
655 if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) &&
656 (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
657 ast_debug(3,
"An extension for '%s@%s' was already registered by another registrar '%s'\n",
658 dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
660 "Dial", duplicate_returnexten,
ast_free_ptr, BASE_REGISTRAR, NULL, 0)) {
661 ast_log(LOG_ERROR,
"Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
662 dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
669 abandon_extension_creation:
672 if (!ast_strlen_zero(user->
comeback)) {
683 unsigned int numeric_value;
684 unsigned int hangup_after;
686 if (sscanf(payload,
"%u %u", &hangup_after, &numeric_value) != 2) {
695 ast_channel_language(bridge_channel->
chan));
705 unsigned int time_limit;
716 if (time_limit <= 0) {
725 ast_log(LOG_ERROR,
"Failed to apply duration limit to the parked call.\n");
735 unsigned int space = 0;
736 const char *content = NULL;
749 ast_log(LOG_ERROR,
"Usage: %s(<parking_space>,<parking_lot>)\n",
756 ast_log(LOG_ERROR,
"Could not find parking lot: '%s'\n", args.parking_lot);
760 if (!ast_strlen_zero(args.parking_space)) {
762 ast_log(LOG_ERROR,
"value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n",
773 content = ast_channel_name(pu->chan);
780 .
name =
"PARK_GET_CHANNEL",
786 .module_name = __FILE__,
802 parking_provider.
module = AST_MODULE_SELF;
int ast_unlock_context(struct ast_context *con)
Main Channel structure associated with a channel.
Local proxy channel special access.
struct ast_channel_snapshot_base * base
Asterisk main include file. File version handling, generic pbx functions.
ast_exten: An extension The dialplan is saved as a linked list with each context having it's own link...
struct parking_lot * parking_create_dynamic_lot(const char *name, struct ast_channel *chan)
Create a dynamic parking lot.
unsigned int comebackdialtime
int(* parking_is_exten_park)(const char *context, const char *exten)
Determine if the context/exten is a "parking" extension.
Structure that contains features information.
#define ast_channel_unref(c)
Decrease channel reference count.
struct ast_bridge_channel * ast_bridge_channel_peer(struct ast_bridge_channel *bridge_channel)
Get the peer bridge channel of a two party bridge.
char context[AST_MAX_CONTEXT]
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_message_type * ast_parked_call_type(void)
accessor for the parked call stasis message type
void __ao2_cleanup(void *obj)
int ast_call(struct ast_channel *chan, const char *addr, int timeout)
Make a call.
int ast_bridge_channel_write_park(struct ast_bridge_channel *bridge_channel, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
Have a bridge channel park a channel in the bridge.
Structure representing a snapshot of channel state.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Structure for a data store type.
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
const ast_string_field uniqueid
int ast_wrlock_contexts(void)
Write locks the context list.
void parking_set_duration(struct ast_bridge_features *features, struct parked_user *user)
Setup timeout interval feature on an ast_bridge_features for parking.
void flatten_dial_string(char *dialstring)
Flattens a dial string so that it can be written to/found from PBX extensions.
A parked call message payload.
#define ast_strdup(str)
A wrapper for strdup()
Structure for a data store object.
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
const char * module_name
The name of the module that provides this parking functionality.
enum ast_parked_call_event_type event_type
void ast_free_ptr(void *ptr)
free() wrapper
void unload_parking_bridge_features(void)
Unregister features registered by load_parking_bridge_features.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
struct ast_bridge * bridge
Bridge this channel is participating in.
struct ast_channel * ast_local_get_peer(struct ast_channel *ast)
Get the other local channel in the pair.
void publish_parked_call_failure(struct ast_channel *parkee)
Publish a stasis parked call message for the channel indicating failure to park.
struct ast_channel * ast_request(const char *type, struct ast_format_cap *request_cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int *cause)
Requests a channel.
struct parked_user * parking_lot_inspect_parked_user(struct parking_lot *lot, int target)
Determine if there is a parked user in a parking space and return it if there is. ...
int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature)
Unregister a handler for a built in feature.
Asterisk datastore objects.
A function table providing parking functionality to the Bridging API Bridging API and other consumers...
int ast_channel_datastore_inherit(struct ast_channel *from, struct ast_channel *to)
Inherit datastores from a parent to a child.
int ast_bridge_impart(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, enum ast_bridge_impart_flags flags) attribute_warn_unused_result
Impart a channel to a bridge (non-blocking)
struct ast_channel_snapshot * parkee
struct ast_bridge * park_application_setup(struct ast_channel *parkee, struct ast_channel *parker, const char *app_data, int *silence_announcements)
Function to prepare a channel for parking by determining which parking bridge should be used...
int load_parking_bridge_features(void)
Register bridge features for parking.
void ast_channel_stage_snapshot_done(struct ast_channel *chan)
Clear flag to indicate channel snapshot is being staged, and publish snapshot.
char * parker_dial_string
#define ast_strdupa(s)
duplicate a string in memory from the stack
Data structure associated with a custom dialplan function.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_MAX_EXTENSION
#define ast_channel_cleanup(c)
Cleanup a channel reference.
Conversion utility functions.
int ast_bridge_interval_hook(struct ast_bridge_features *features, enum ast_bridge_hook_timer_option flags, unsigned int interval, ast_bridge_hook_callback callback, void *hook_pvt, ast_bridge_hook_pvt_destructor destructor, enum ast_bridge_hook_remove_flags remove_flags)
Attach an interval hook to a bridge features structure.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_parking_register_bridge_features(struct ast_parking_bridge_feature_fn_table *fn_table)
Register a parking provider.
void ast_channel_req_accountcodes(struct ast_channel *chan, const struct ast_channel *requestor, enum ast_channel_requestor_relationship relationship)
Setup new channel accountcodes from the requestor channel after ast_request().
enum park_call_resolution resolution
Core PBX routines and definitions.
struct ast_module * module
The module info for the module registering this parking provider.
unsigned int module_version
The version of this function table. If the ABI for this table changes, the module version (/ref PARKI...
void ast_channel_stage_snapshot(struct ast_channel *chan)
Set flag to indicate channel snapshot is being staged.
Structure that contains information about a bridge.
int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
Set a channel's position in the PBX after timeout using the parking lot settings. ...
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
int ast_remaining_ms(struct timeval start, int max_ms)
Calculate remaining milliseconds given a starting timestamp and upper bound.
unsigned int parkingspace
int ast_unlock_contexts(void)
Unlocks contexts.
int(* parking_blind_transfer_park)(struct ast_bridge_channel *parker, const char *context, const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data)
Perform a blind transfer to a parking extension.
int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_bridge_hook_callback callback, const char *dtmf)
Register a handler for a built in feature.
static int func_get_parkingslot_channel(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Dial plan function to get the parking lot channel of an occupied parking lot.
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
custom callback function for ast_bridge_channel_queue_playfile which plays a parking space and option...
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
void ast_bridge_channel_leave_bridge(struct ast_bridge_channel *bridge_channel, enum bridge_channel_state new_state, int cause)
Set bridge channel state to leave bridge (if not leaving already).
#define PARK_APPLICATION
The default parking application that Asterisk expects.
int stasis_subscription_final_message(struct stasis_subscription *sub, struct stasis_message *msg)
Determine whether a message is the final message to be received on a subscription.
#define ast_bridge_unlock(bridge)
Unlock the bridge.
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
Inherits channel variable from parent to child channel.
#define ast_calloc(num, len)
A wrapper for calloc()
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
Support for logging to various files, console and syslog Configuration in file logger.conf.
void ast_bridge_set_transfer_variables(struct ast_channel *chan, const char *value, int is_attended)
Set the relevant transfer variables for a single channel.
const ast_string_field name
#define SCOPED_MODULE_USE(module)
int ast_str_to_uint(const char *str, unsigned int *res)
Convert the given string to an unsigned integer.
structure to hold users read from users.conf
struct ast_bridge_channel * ast_channel_get_bridge_channel(struct ast_channel *chan)
Get a reference to the channel's bridge pointer.
int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
#define ast_channel_lock_both(chan1, chan2)
Lock two channels.
struct stasis_topic * ast_parking_topic(void)
accessor for the parking stasis topic
struct ast_channel * chan
Structure that contains information regarding a channel in a bridge.
int ast_bridge_move(struct ast_bridge *dst_bridge, struct ast_bridge *src_bridge, struct ast_channel *chan, struct ast_channel *swap, int attempt_recovery)
Move a channel from one bridge to another.
#define ast_channel_ref(c)
Increase channel reference count.
void ast_bridge_channel_lock_bridge(struct ast_bridge_channel *bridge_channel)
Lock the bridge associated with the bridge channel.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
void ast_connected_line_copy_from_caller(struct ast_party_connected_line *dest, const struct ast_party_caller *src)
Copy the caller information to the connected line information.
int ast_bridge_channel_queue_playfile(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
Queue a bridge action play file frame onto the bridge channel.
AO2 object that wraps data for transfer_channel_cb.
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Internal Asterisk hangup causes.
void(* transfer_channel_cb)(struct ast_channel *chan, struct transfer_channel_data *user_data, enum ast_transfer_type transfer_type)
Callback function type called during blind transfers.
struct stasis_message_type * stasis_subscription_change_type(void)
Gets the message type for subscription change notices.
struct parking_lot * parking_lot_find_by_name(const char *lot_name)
Find a parking lot based on its name.
Call Parking Resource Internal API.
const char * find_channel_parking_lot_name(struct ast_channel *chan)
Find parking lot name from channel.
int ast_bridge_channel_queue_playfile_sync(struct ast_bridge_channel *bridge_channel, ast_bridge_custom_play_fn custom_play, const char *playfile, const char *moh_class)
Synchronously queue a bridge action play file frame onto the bridge channel.
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Say numbers and dates (maybe words one day too)
struct ast_channel * ast_channel_get_by_name(const char *name)
Find a channel by name.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
int(* parking_park_bridge_channel)(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data)
Perform a direct park on a channel in a bridge.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
ast_context: An extension context
struct ast_channel * chan
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
unsigned int num_channels
#define ast_custom_function_register(acf)
Register a custom function.
char exten[AST_MAX_EXTENSION]
int ast_add_extension2_nolock(struct ast_context *con, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar, const char *registrar_file, int registrar_line)
Same as ast_add_extension2, but assumes you have already locked context.
int(* parking_park_call)(struct ast_bridge_channel *parker, char *exten, size_t length)
Park the bridge and/or callers that this channel is in.
#define AST_APP_ARG(name)
Define an application argument.
int create_parked_subscription(struct ast_channel *chan, const char *parkee_uuid, int hangup_after)
Create a parking announcement subscription.
struct parking_lot_cfg * cfg
int ast_parking_unregister_bridge_features(const char *module_name)
Unregister the current parking provider.