237 #define PARK_AND_ANNOUNCE_APPLICATION "ParkAndAnnounce"
249 MUXFLAG_RINGING = (1 << 0),
250 MUXFLAG_RANDOMIZE = (1 << 1),
251 MUXFLAG_NOANNOUNCE = (1 << 2),
252 MUXFLAG_COMEBACK_OVERRIDE = (1 << 3),
253 MUXFLAG_TIMEOUT_OVERRIDE = (1 << 4),
254 MUXFLAG_MUSICONHOLD = (1 << 5),
266 static int apply_option_timeout (
int *var,
char *timeout_arg)
268 if (ast_strlen_zero(timeout_arg)) {
269 ast_log(LOG_ERROR,
"No duration value provided for the timeout ('t') option.\n");
273 if (sscanf(timeout_arg,
"%d", var) != 1 || *var < 0) {
274 ast_log(LOG_ERROR,
"Duration value provided for timeout ('t') option must be 0 or greater.\n");
281 static int park_app_parse_data(
const char *data,
int *disable_announce,
int *use_ringing,
int *randomize,
int *time_limit,
282 char **comeback_override,
char **lot_name,
char **musicclass)
297 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
299 if (ast_test_flag(&flags, MUXFLAG_TIMEOUT_OVERRIDE)) {
300 if (apply_option_timeout(time_limit, opts[OPT_ARG_TIMEOUT])) {
305 if (ast_test_flag(&flags, MUXFLAG_COMEBACK_OVERRIDE)) {
306 *comeback_override =
ast_strdup(opts[OPT_ARG_COMEBACK]);
309 if (ast_test_flag(&flags, MUXFLAG_NOANNOUNCE)) {
310 if (disable_announce) {
311 *disable_announce = 1;
315 if (ast_test_flag(&flags, MUXFLAG_MUSICONHOLD)) {
316 *musicclass =
ast_strdup(opts[OPT_ARG_MUSICONHOLD]);
319 if (ast_test_flag(&flags, MUXFLAG_RINGING)) {
323 if (ast_test_flag(&flags, MUXFLAG_RANDOMIZE)) {
328 if (!ast_strlen_zero(args.lot_name)) {
347 static void park_common_datastore_destroy(
void *data)
354 .
type =
"park entry data",
355 .destroy = park_common_datastore_destroy,
358 static void wipe_park_common_datastore(
struct ast_channel *chan)
362 ast_channel_lock(chan);
368 ast_channel_unlock(chan);
371 static int setup_park_common_datastore(
struct ast_channel *parkee,
const char *parker_uuid,
const char *comeback_override,
int randomize,
int time_limit,
int silence_announce)
375 const char *attended_transfer;
376 const char *blind_transfer;
379 wipe_park_common_datastore(parkee);
381 if (!(datastore = ast_datastore_alloc(&park_common_info, NULL))) {
385 if (!(park_datastore =
ast_calloc(1,
sizeof(*park_datastore)))) {
389 datastore->
data = park_datastore;
397 ast_channel_lock(parkee);
400 if (!ast_strlen_zero(attended_transfer)) {
401 parker_dial_string =
ast_strdupa(attended_transfer);
402 }
else if (!ast_strlen_zero(blind_transfer)) {
405 attended_transfer = NULL;
407 ast_channel_unlock(parkee);
409 if (!ast_strlen_zero(parker_dial_string)) {
411 ast_verb(4,
"Setting Parker dial string to %s from %s value\n",
413 attended_transfer ?
"ATTENDEDTRANSFER" :
"BLINDTRANSFER");
425 if (comeback_override) {
434 ast_channel_lock(parkee);
436 ast_channel_unlock(parkee);
453 data = datastore->
data;
456 ast_assert(data != NULL);
458 data_copy =
ast_calloc(1,
sizeof(*data_copy));
493 const char *lot_name,
const char *comeback_override,
const char *musicclass,
494 int use_ringing,
int randomize,
int time_limit,
int silence_announcements)
504 if (ast_strlen_zero(lot_name)) {
505 ast_channel_lock(parker);
507 ast_channel_unlock(parker);
515 ast_log(LOG_ERROR,
"Could not find parking lot: '%s'\n", lot_name);
523 if (!parking_bridge) {
530 if (!ast_strlen_zero(musicclass)) {
533 setup_park_common_datastore(parkee, ast_channel_uniqueid(parker), comeback_override, randomize, time_limit,
534 silence_announcements);
535 return parking_bridge;
539 const char *lot_name,
const char *comeback_override,
540 int use_ringing,
int randomize,
int time_limit,
int silence_announcements)
542 return park_common_setup2(parkee, parker, lot_name, comeback_override, NULL, use_ringing, randomize, time_limit, silence_announcements);
546 int *silence_announcements)
552 RAII_VAR(
char *, comeback_override, NULL, ast_free);
553 RAII_VAR(
char *, lot_name_app_arg, NULL, ast_free);
554 RAII_VAR(
char *, musicclass, NULL, ast_free);
557 park_app_parse_data(app_data, silence_announcements, &use_ringing, &randomize, &time_limit, &comeback_override, &lot_name_app_arg, &musicclass);
560 return park_common_setup2(parkee, parker, lot_name_app_arg, comeback_override, musicclass, use_ringing,
561 randomize, time_limit, silence_announcements ? *silence_announcements : 0);
565 static int park_app_exec(
struct ast_channel *chan,
const char *data)
571 int silence_announcements = 0;
579 ast_channel_lock(chan);
581 ast_channel_unlock(chan);
585 if (!silence_announcements && !blind_transfer) {
595 if (res ||
ast_bridge_join(parking_bridge, chan, NULL, &chan_features, NULL, 0)) {
596 if (!silence_announcements && !blind_transfer) {
611 ast_channel_lock(chan);
615 ast_channel_unlock(chan);
624 static int parked_call_app_exec(
struct ast_channel *chan,
const char *data)
630 int target_space = -1;
633 const char *lot_name;
649 lot_name = args.lot_name;
652 if (ast_strlen_zero(lot_name)) {
653 ast_channel_lock(chan);
655 ast_channel_unlock(chan);
660 ast_log(LOG_ERROR,
"Could not find the requested parking lot\n");
665 if (!ast_strlen_zero(args.parking_space)) {
666 if (sscanf(args.parking_space,
"%d", &target_space) != 1 || target_space < 0) {
668 ast_log(LOG_ERROR,
"value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n", args.parking_space);
681 ast_assert(pu->retriever == NULL);
686 if (!retrieval_bridge) {
691 if (
ast_bridge_move(retrieval_bridge, lot->parking_bridge, pu->chan, NULL, 0)) {
708 if (lot->cfg->parkedplay & AST_FEATURE_FLAG_BYCALLER) {
727 char *announce_string;
730 static void park_announce_subscription_data_destroy(
void *data)
733 ast_free(pa_data->parkee_uuid);
734 ast_free(pa_data->dial_string);
735 ast_free(pa_data->announce_string);
740 const char *dial_string,
741 const char *announce_string)
745 if (!(pa_data =
ast_calloc(1,
sizeof(*pa_data)))) {
749 if (!(pa_data->parkee_uuid =
ast_strdup(parkee_uuid))
750 || !(pa_data->dial_string =
ast_strdup(dial_string))
751 || !(pa_data->announce_string =
ast_strdup(announce_string))) {
752 park_announce_subscription_data_destroy(pa_data);
765 static void inherit_channel_vars_from_id(
struct outgoing_helper *oh,
const char *channel_id)
779 ast_channel_lock(chan);
782 varname = ast_var_full_name(current);
788 if (varname[0] ==
'_') {
790 if (varname[1] ==
'_') {
797 newvar = ast_variable_new(&varname[1], ast_var_value(current),
"");
800 newvar = ast_variable_new(varname, ast_var_value(current),
"");
806 ast_debug(1,
"Inheriting variable %s from %s.\n",
807 newvar->
name, ast_channel_name(chan));
809 newvar->
next = oh->vars;
815 ast_channel_unlock(chan);
819 static void announce_to_dial(
char *dial_string,
char *announce_string,
int parkingspace,
struct ast_channel_snapshot *parkee_snapshot)
829 dial_tech = strsep(&dial_string,
"/");
830 ast_verb(3,
"Dial Tech,String: (%s,%s)\n", dial_tech, dial_string);
833 ast_log(LOG_WARNING,
"PARK: Failed to announce park.\n");
834 goto announce_cleanup;
838 snprintf(buf,
sizeof(buf),
"%d", parkingspace);
839 oh.vars = ast_variable_new(
"_PARKEDAT", buf,
"");
841 inherit_channel_vars_from_id(&oh, parkee_snapshot->
base->
uniqueid);
851 ast_log(LOG_WARNING,
"PARK: Unable to allocate announce channel.\n");
852 goto announce_cleanup;
855 ast_verb(4,
"Announce Template: %s\n", announce_string);
857 for (cur_announce = strsep(&announce_string,
":"); cur_announce; cur_announce = strsep(&announce_string,
":")) {
858 ast_verb(4,
"Announce:%s\n", cur_announce);
859 if (!strcmp(cur_announce,
"PARKED")) {
860 ast_say_digits(dchan, parkingspace,
"", ast_channel_language(dchan));
862 int dres =
ast_streamfile(dchan, cur_announce, ast_channel_language(dchan));
866 ast_log(LOG_WARNING,
"ast_streamfile of %s failed on %s\n", cur_announce, ast_channel_name(dchan));
875 ao2_cleanup(cap_slin);
881 char *dial_string = pa_data->dial_string;
886 park_announce_subscription_data_destroy(data);
904 if (!ast_strlen_zero(dial_string)) {
905 announce_to_dial(dial_string, pa_data->announce_string, payload->
parkingspace, payload->
parkee);
911 static int park_and_announce_app_exec(
struct ast_channel *chan,
const char *data)
916 int silence_announcements = 1;
931 if (ast_strlen_zero(data)) {
932 ast_log(LOG_ERROR,
"ParkAndAnnounce has required arguments. No arguments were provided.\n");
939 if (ast_strlen_zero(args.announce_template)) {
941 ast_log(LOG_ERROR,
"ParkAndAnnounce requires the announce_template argument.\n");
945 if (ast_strlen_zero(args.dial)) {
947 ast_log(LOG_ERROR,
"ParkAndAnnounce requires the dial argument.\n");
951 if (!strchr(args.dial,
'/')) {
952 ast_log(LOG_ERROR,
"ParkAndAnnounce dial string '%s' is improperly formed.\n", args.dial);
969 pa_data = park_announce_subscription_data_create(ast_channel_uniqueid(chan), args.dial, args.announce_template);
974 if (!(parking_subscription = stasis_subscribe_pool(
ast_parking_topic(), park_announce_update_cb, pa_data))) {
976 park_announce_subscription_data_destroy(pa_data);
997 ast_channel_lock(chan);
1001 ast_channel_unlock(chan);
struct ast_variable * next
Main Channel structure associated with a channel.
void ast_bridge_features_cleanup(struct ast_bridge_features *features)
Clean up the contents of a bridge features structure.
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
struct ast_channel_snapshot_base * base
Asterisk main include file. File version handling, generic pbx functions.
struct parking_lot * parking_create_dynamic_lot(const char *name, struct ast_channel *chan)
Create a dynamic parking lot.
void park_common_datastore_free(struct park_common_datastore *datastore)
Free a park common datastore struct.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
const ast_string_field name
Structure that contains features information.
void unload_parking_applications(void)
Unregister parking applications.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
struct stasis_message_type * ast_parked_call_type(void)
accessor for the parked call stasis message type
int ast_bridge_features_init(struct ast_bridge_features *features)
Initialize bridge features structure.
Structure for variables, used for configurations and for channel variables.
Structure representing a snapshot of channel state.
void parked_call_retrieve_enable_features(struct ast_channel *chan, struct parking_lot *lot, int recipient_mode)
Apply features based on the parking lot feature options.
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.
ast_channel_state
ast_channel states
int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
says digits
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
const ast_string_field uniqueid
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.
int ast_unregister_application(const char *app)
Unregister an application.
enum ast_parked_call_event_type event_type
struct parked_user * parking_lot_retrieve_parked_user(struct parking_lot *lot, int target)
Determine if there is a parked user in a parking space and pull it from the parking lot if there is...
struct ast_channel_snapshot * ast_channel_snapshot_create(struct ast_channel *chan)
Generate a snapshot of the channel state. This is an ao2 object, so ao2_cleanup() to deallocate...
int ast_datastore_free(struct ast_datastore *datastore)
Free a data store object.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
void publish_parked_call_failure(struct ast_channel *parkee)
Publish a stasis parked call message for the channel indicating failure to park.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
int ast_channel_set_bridge_role_option(struct ast_channel *channel, const char *role_name, const char *option, const char *value)
Set a role option on a channel.
Configuration File Parser.
int parking_channel_set_roles(struct ast_channel *chan, struct parking_lot *lot, int force_ringing)
Set necessary bridge roles on a channel that is about to enter a parking lot.
#define SCOPED_CHANNELLOCK(varname, chan)
scoped lock specialization for channels.
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...
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_channel_cleanup(c)
Cleanup a channel reference.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
struct ast_channel_snapshot_caller * caller
int load_parking_applications(void)
Register parking applications.
Configuration option-handling.
Structure that contains information about a bridge.
void ast_channel_name_to_dial_string(char *channel_name)
Removes the trailing identifiers from a channel name string.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
unsigned int parkingspace
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
#define PARK_APPLICATION
The default parking application that Asterisk expects.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
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_calloc(num, len)
A wrapper for calloc()
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
struct ast_channel * __ast_request_and_dial(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *addr, int timeout, int *reason, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
Request a channel of a given type, with data as optional information used by the low level module and...
Basic bridge subclass API.
Structure used to handle boolean flags.
int ast_bridge_join(struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap, struct ast_bridge_features *features, struct ast_bridge_tech_optimizations *tech_args, enum ast_bridge_join_flags flags)
Join a channel to a bridge (blocking)
struct ast_bridge * ast_bridge_basic_new(void)
Create a new basic class bridge.
struct stasis_topic * ast_parking_topic(void)
accessor for the parking stasis topic
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.
struct park_common_datastore * get_park_common_datastore_copy(struct ast_channel *parkee)
Get a copy of the park_common_datastore from a channel that is being parked.
const ast_string_field number
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
int ast_answer(struct ast_channel *chan)
Answer a channel.
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.
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.
char * parker_dial_string
const char * find_channel_parking_lot_name(struct ast_channel *chan)
Find parking lot name from channel.
Call Parking and Pickup API Includes code and algorithms from the Zapata library. ...
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
struct ast_bridge * parking_lot_get_bridge(struct parking_lot *lot)
Get a reference to a parking lot's bridge. If it doesn't exist, create it and get a reference...
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.
static struct stasis_forward * parking_subscription
Our subscription for parking.
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#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...
int ast_channel_datastore_remove(struct ast_channel *chan, struct ast_datastore *datastore)
Remove a datastore from a channel.
int ast_stopstream(struct ast_channel *c)
Stops a stream.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
struct ast_bridge * park_common_setup(struct ast_channel *parkee, struct ast_channel *parker, const char *lot_name, const char *comeback_override, int use_ringing, int randomize, int time_limit, int silence_announcements)
Setup a parked call on a parking bridge without needing to parse appdata.
#define AST_APP_ARG(name)
Define an application argument.