mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-14 16:33:34 +00:00
res_parking: Dynamic Parking Lots
(closes issue ASTERISK-21644) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2615/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393197 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
16
CHANGES
16
CHANGES
@@ -342,6 +342,22 @@ Parking
|
|||||||
by default. Instead, it will follow the timeout rules of the parking lot. The
|
by default. Instead, it will follow the timeout rules of the parking lot. The
|
||||||
old behavior can be reproduced by using the 'c' option.
|
old behavior can be reproduced by using the 'c' option.
|
||||||
|
|
||||||
|
* Dynamic parking lots will now fail to be created if the parking lot specified
|
||||||
|
by PARKINGDYNAMIC does not exist.
|
||||||
|
|
||||||
|
* Dynamic parking lots will also fail to be created now if they require exclusive
|
||||||
|
park and parkedcall extensions which overlap with other parking lots.
|
||||||
|
|
||||||
|
* Dynamic parking lots will be cleared on reload for dynamic parking lots that
|
||||||
|
currently contain no calls. Dynamic parking lots containing parked calls will
|
||||||
|
persist through the reloads without alteration.
|
||||||
|
|
||||||
|
* If parkext_exclusive is set for a parking lot and that extension is already in
|
||||||
|
use when that parking lot tries to register it, this is now considered a parking
|
||||||
|
system configuration error. Configurations which do this will be rejected.
|
||||||
|
Dynamic parking lots which try to register extensions that already exist will
|
||||||
|
also be rejected.
|
||||||
|
|
||||||
* Added a channel variable PARKER_FLAT which stores the name of the extension
|
* Added a channel variable PARKER_FLAT which stores the name of the extension
|
||||||
that would be used to come back to if comebacktoorigin was set to use. This can
|
that would be used to come back to if comebacktoorigin was set to use. This can
|
||||||
be useful when comebacktoorigin is off if you still want to use the extensions
|
be useful when comebacktoorigin is off if you still want to use the extensions
|
||||||
|
@@ -390,6 +390,9 @@ struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_chan
|
|||||||
}
|
}
|
||||||
|
|
||||||
lot = parking_lot_find_by_name(lot_name);
|
lot = parking_lot_find_by_name(lot_name);
|
||||||
|
if (!lot) {
|
||||||
|
lot = parking_create_dynamic_lot(lot_name, parkee);
|
||||||
|
}
|
||||||
|
|
||||||
if (!lot) {
|
if (!lot) {
|
||||||
ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", lot_name);
|
ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", lot_name);
|
||||||
@@ -451,6 +454,11 @@ int park_app_exec(struct ast_channel *chan, const char *data)
|
|||||||
int silence_announcements = 0;
|
int silence_announcements = 0;
|
||||||
const char *blind_transfer;
|
const char *blind_transfer;
|
||||||
|
|
||||||
|
/* Answer the channel if needed */
|
||||||
|
if (ast_channel_state(chan) != AST_STATE_UP) {
|
||||||
|
ast_answer(chan);
|
||||||
|
}
|
||||||
|
|
||||||
ast_channel_lock(chan);
|
ast_channel_lock(chan);
|
||||||
if ((blind_transfer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"))) {
|
if ((blind_transfer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"))) {
|
||||||
blind_transfer = ast_strdupa(blind_transfer);
|
blind_transfer = ast_strdupa(blind_transfer);
|
||||||
|
@@ -66,6 +66,7 @@ static void display_parking_lot(struct parking_lot *lot, int fd)
|
|||||||
ast_cli(fd, "Comeback Dial Time : %u sec\n", lot->cfg->comebackdialtime);
|
ast_cli(fd, "Comeback Dial Time : %u sec\n", lot->cfg->comebackdialtime);
|
||||||
ast_cli(fd, "MusicOnHold Class : %s\n", lot->cfg->mohclass);
|
ast_cli(fd, "MusicOnHold Class : %s\n", lot->cfg->mohclass);
|
||||||
ast_cli(fd, "Enabled : %s\n", (lot->mode == PARKINGLOT_DISABLED) ? "no" : "yes");
|
ast_cli(fd, "Enabled : %s\n", (lot->mode == PARKINGLOT_DISABLED) ? "no" : "yes");
|
||||||
|
ast_cli(fd, "Dynamic : %s\n", (lot->mode == PARKINGLOT_DYNAMIC) ? "yes" : "no");
|
||||||
ast_cli(fd, "\n");
|
ast_cli(fd, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,6 +103,14 @@ static void cli_display_parking_lot(int fd, const char *name)
|
|||||||
ast_cli(fd, "\n");
|
ast_cli(fd, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cli_display_parking_global(int fd)
|
||||||
|
{
|
||||||
|
ast_cli(fd, "Parking General Options\n"
|
||||||
|
"-----------------------\n");
|
||||||
|
ast_cli(fd, "Dynamic Parking : %s\n", parking_dynamic_lots_enabled() ? "yes" : "no");
|
||||||
|
ast_cli(fd, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
static void cli_display_parking_lot_list(int fd)
|
static void cli_display_parking_lot_list(int fd)
|
||||||
{
|
{
|
||||||
struct ao2_container *lot_container;
|
struct ao2_container *lot_container;
|
||||||
@@ -172,6 +181,7 @@ static char *handle_show_parking_lot_cmd(struct ast_cli_entry *e, int cmd, struc
|
|||||||
ast_cli(a->fd, "\n");
|
ast_cli(a->fd, "\n");
|
||||||
|
|
||||||
if (a->argc == 2) {
|
if (a->argc == 2) {
|
||||||
|
cli_display_parking_global(a->fd);
|
||||||
cli_display_parking_lot_list(a->fd);
|
cli_display_parking_lot_list(a->fd);
|
||||||
return CLI_SUCCESS;
|
return CLI_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@@ -118,6 +118,7 @@ struct parked_user {
|
|||||||
* struct based on a parking lot configuration and return a reference to the new one.
|
* struct based on a parking lot configuration and return a reference to the new one.
|
||||||
*
|
*
|
||||||
* \param cfg The configuration being used as a reference to build the parking lot from.
|
* \param cfg The configuration being used as a reference to build the parking lot from.
|
||||||
|
* \param dynamic non-zero if creating a dynamic parking lot with this. Don't replace existing parking lots. Ever.
|
||||||
*
|
*
|
||||||
* \retval A reference to the new parking lot
|
* \retval A reference to the new parking lot
|
||||||
* \retval NULL if it was not found and could not be be allocated
|
* \retval NULL if it was not found and could not be be allocated
|
||||||
@@ -125,7 +126,7 @@ struct parked_user {
|
|||||||
* \note The parking lot will need to be unreffed if it ever falls out of scope
|
* \note The parking lot will need to be unreffed if it ever falls out of scope
|
||||||
* \note The parking lot will automatically be added to the parking lot container if needed as part of this process
|
* \note The parking lot will automatically be added to the parking lot container if needed as part of this process
|
||||||
*/
|
*/
|
||||||
struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *cfg);
|
struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *cfg, int dynamic);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \since 12.0.0
|
* \since 12.0.0
|
||||||
@@ -133,10 +134,13 @@ struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *cfg);
|
|||||||
*
|
*
|
||||||
* \param lot Which parking lot is being checked for elimination
|
* \param lot Which parking lot is being checked for elimination
|
||||||
*
|
*
|
||||||
|
* \retval 0 if the parking lot was removed
|
||||||
|
* \retval -1 if the parking lot wasn't removed.
|
||||||
|
*
|
||||||
* \note This should generally be called when something is happening that could cause a parking lot to die such as a call being unparked or
|
* \note This should generally be called when something is happening that could cause a parking lot to die such as a call being unparked or
|
||||||
* a parking lot no longer existing in configurations.
|
* a parking lot no longer existing in configurations.
|
||||||
*/
|
*/
|
||||||
void parking_lot_remove_if_unused(struct parking_lot *lot);
|
int parking_lot_remove_if_unused(struct parking_lot *lot);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \since 12.0.0
|
* \since 12.0.0
|
||||||
@@ -251,6 +255,21 @@ struct ao2_container *get_parking_lot_container(void);
|
|||||||
*/
|
*/
|
||||||
struct parking_lot *parking_lot_find_by_name(const char *lot_name);
|
struct parking_lot *parking_lot_find_by_name(const char *lot_name);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \since 12.0.0
|
||||||
|
* \brief Create a dynamic parking lot
|
||||||
|
*
|
||||||
|
* \param name Dynamic parking lot name to create
|
||||||
|
* \param chan Channel parkee to get dynamic parking lot parameters from
|
||||||
|
*
|
||||||
|
* \retval dynamically created parking lot on success
|
||||||
|
* \retval NULL on error
|
||||||
|
*
|
||||||
|
* \note This should be called only after verifying that the named parking lot doesn't already exist in a non-dynamic way.
|
||||||
|
* The parking lots container should be locked before verifying and remain locked until after this function is called.
|
||||||
|
*/
|
||||||
|
struct parking_lot *parking_create_dynamic_lot(const char *name, struct ast_channel *chan);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \since 12.0.0
|
* \since 12.0.0
|
||||||
* \brief Find parking lot name from channel
|
* \brief Find parking lot name from channel
|
||||||
@@ -398,6 +417,15 @@ void get_park_common_datastore_data(struct ast_channel *parkee,
|
|||||||
*/
|
*/
|
||||||
void parking_notify_metermaids(int exten, const char *context, enum ast_device_state state);
|
void parking_notify_metermaids(int exten, const char *context, enum ast_device_state state);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \since 12.0.0
|
||||||
|
* \brief Check global configuration to see if dynamic parking is enabled
|
||||||
|
*
|
||||||
|
* \retval 1 if dynamic parking is enabled
|
||||||
|
* \retval 0 if dynamic parking is disabled
|
||||||
|
*/
|
||||||
|
int parking_dynamic_lots_enabled(void);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \since 12.0.0
|
* \since 12.0.0
|
||||||
* \brief Execution function for the parking application
|
* \brief Execution function for the parking application
|
||||||
|
@@ -231,7 +231,6 @@ static int config_parking_preapply(void);
|
|||||||
static void link_configured_disable_marked_lots(void);
|
static void link_configured_disable_marked_lots(void);
|
||||||
|
|
||||||
struct parking_global_config {
|
struct parking_global_config {
|
||||||
/* TODO Implement dynamic parking lots. Entirely. */
|
|
||||||
int parkeddynamic;
|
int parkeddynamic;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -353,23 +352,30 @@ static void *parking_config_alloc(void)
|
|||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void parking_lot_remove_if_unused(struct parking_lot *lot)
|
int parking_lot_remove_if_unused(struct parking_lot *lot)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (lot->mode != PARKINGLOT_DISABLED) {
|
if (lot->mode != PARKINGLOT_DISABLED) {
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!ao2_container_count(lot->parked_users)) {
|
if (!ao2_container_count(lot->parked_users)) {
|
||||||
ao2_unlink(parking_lot_container, lot);
|
ao2_unlink(parking_lot_container, lot);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void parking_lot_disable(struct parking_lot *lot)
|
static void parking_lot_disable(struct parking_lot *lot)
|
||||||
{
|
{
|
||||||
|
/* If a dynamic lot wasn't removed, we need to restore it to full functionality afterwards. */
|
||||||
|
int was_dynamic = (lot->mode == PARKINGLOT_DYNAMIC);
|
||||||
|
|
||||||
lot->mode = PARKINGLOT_DISABLED;
|
lot->mode = PARKINGLOT_DISABLED;
|
||||||
parking_lot_remove_if_unused(lot);
|
if (parking_lot_remove_if_unused(lot) && was_dynamic) {
|
||||||
|
lot->mode = PARKINGLOT_DYNAMIC;
|
||||||
|
lot->disable_mark = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Destroy a parking lot cfg object */
|
/*! \brief Destroy a parking lot cfg object */
|
||||||
@@ -703,17 +709,20 @@ int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
|
|||||||
struct ast_exten *existing_exten;
|
struct ast_exten *existing_exten;
|
||||||
struct ast_context *lot_context;
|
struct ast_context *lot_context;
|
||||||
struct pbx_find_info find_info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
|
struct pbx_find_info find_info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
|
||||||
const char *registrar_pointer;
|
const char *parkext_registrar_pointer; /* Used for park extension */
|
||||||
|
const char *parkedcall_registrar_pointer; /* Used for parkedcall extensions/hints */
|
||||||
|
|
||||||
if (ast_strlen_zero(lot_cfg->parkext)) {
|
if (ast_strlen_zero(lot_cfg->parkext)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ast_string_field_build(lot_cfg, registrar, "%s/%s", BASE_REGISTRAR, lot_cfg->name);
|
||||||
|
parkedcall_registrar_pointer = lot_cfg->registrar;
|
||||||
|
|
||||||
if (lot_cfg->parkext_exclusive) {
|
if (lot_cfg->parkext_exclusive) {
|
||||||
ast_string_field_build(lot_cfg, registrar, "%s/%s", BASE_REGISTRAR, lot_cfg->name);
|
parkext_registrar_pointer = lot_cfg->registrar;
|
||||||
registrar_pointer = lot_cfg->registrar;
|
|
||||||
} else {
|
} else {
|
||||||
registrar_pointer = BASE_REGISTRAR;
|
parkext_registrar_pointer = BASE_REGISTRAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We need the contexts list locked to safely be able to both read and lock the specific context within */
|
/* We need the contexts list locked to safely be able to both read and lock the specific context within */
|
||||||
@@ -722,7 +731,7 @@ int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(lot_context = ast_context_find_or_create(NULL, NULL, lot_cfg->parking_con, registrar_pointer))) {
|
if (!(lot_context = ast_context_find_or_create(NULL, NULL, lot_cfg->parking_con, parkext_registrar_pointer))) {
|
||||||
ast_log(LOG_ERROR, "Parking lot '%s' -- Needs a context '%s' which does not exist and Asterisk was unable to create\n",
|
ast_log(LOG_ERROR, "Parking lot '%s' -- Needs a context '%s' which does not exist and Asterisk was unable to create\n",
|
||||||
lot_cfg->name, lot_cfg->parking_con);
|
lot_cfg->name, lot_cfg->parking_con);
|
||||||
if (ast_unlock_contexts()) {
|
if (ast_unlock_contexts()) {
|
||||||
@@ -750,7 +759,7 @@ int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else if (parking_add_extension(lot_context, 0, lot_cfg->parkext, 1, PARK_APPLICATION,
|
} else if (parking_add_extension(lot_context, 0, lot_cfg->parkext, 1, PARK_APPLICATION,
|
||||||
lot_cfg->parkext_exclusive ? lot_cfg->name : "", registrar_pointer)) {
|
lot_cfg->parkext_exclusive ? lot_cfg->name : "", parkext_registrar_pointer)) {
|
||||||
ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
|
ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
|
||||||
lot_cfg->name, PARK_APPLICATION, lot_cfg->parkext, lot_cfg->parking_con);
|
lot_cfg->name, PARK_APPLICATION, lot_cfg->parkext, lot_cfg->parking_con);
|
||||||
ast_unlock_context(lot_context);
|
ast_unlock_context(lot_context);
|
||||||
@@ -779,7 +788,7 @@ int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
|
|||||||
|
|
||||||
ast_str_set(&arguments_string, 0, "%s,%s", lot_cfg->name, space);
|
ast_str_set(&arguments_string, 0, "%s,%s", lot_cfg->name, space);
|
||||||
if (parking_add_extension(lot_context, 0, space, 1, PARKED_CALL_APPLICATION,
|
if (parking_add_extension(lot_context, 0, space, 1, PARKED_CALL_APPLICATION,
|
||||||
ast_str_buffer(arguments_string), registrar_pointer)) {
|
ast_str_buffer(arguments_string), parkedcall_registrar_pointer)) {
|
||||||
ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
|
ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
|
||||||
lot_cfg->name, PARKED_CALL_APPLICATION, space, lot_cfg->parking_con);
|
lot_cfg->name, PARKED_CALL_APPLICATION, space, lot_cfg->parking_con);
|
||||||
ast_unlock_context(lot_context);
|
ast_unlock_context(lot_context);
|
||||||
@@ -800,7 +809,7 @@ int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parking_add_extension(lot_context, 0, space, PRIORITY_HINT, hint_device, "", registrar_pointer)) {
|
if (parking_add_extension(lot_context, 0, space, PRIORITY_HINT, hint_device, "", parkedcall_registrar_pointer)) {
|
||||||
ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add hint '%s@%s' to the PBX.\n",
|
ast_log(LOG_ERROR, "Parking lot '%s' -- Failed to add hint '%s@%s' to the PBX.\n",
|
||||||
lot_cfg->name, space, lot_cfg->parking_con);
|
lot_cfg->name, space, lot_cfg->parking_con);
|
||||||
ast_unlock_context(lot_context);
|
ast_unlock_context(lot_context);
|
||||||
@@ -816,7 +825,7 @@ int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *lot_cfg)
|
struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *lot_cfg, int dynamic)
|
||||||
{
|
{
|
||||||
struct parking_lot *lot;
|
struct parking_lot *lot;
|
||||||
struct parking_lot_cfg *replaced_cfg = NULL;
|
struct parking_lot_cfg *replaced_cfg = NULL;
|
||||||
@@ -833,6 +842,12 @@ struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *lot_cfg)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
found = 1;
|
found = 1;
|
||||||
|
|
||||||
|
if (dynamic) {
|
||||||
|
ast_log(LOG_ERROR, "Tried to create dynamic parking lot with name '%s' but a lot with that name already exists.\n", lot_cfg->name);
|
||||||
|
ao2_cleanup(lot);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the configuration reference. Unref the one currently in the lot if it's there. */
|
/* Set the configuration reference. Unref the one currently in the lot if it's there. */
|
||||||
@@ -847,7 +862,7 @@ struct parking_lot *parking_lot_build_or_update(struct parking_lot_cfg *lot_cfg)
|
|||||||
|
|
||||||
/* Set the operating mode to normal since the parking lot has a configuration. */
|
/* Set the operating mode to normal since the parking lot has a configuration. */
|
||||||
lot->disable_mark = 0;
|
lot->disable_mark = 0;
|
||||||
lot->mode = PARKINGLOT_NORMAL;
|
lot->mode = dynamic ? PARKINGLOT_DYNAMIC : PARKINGLOT_NORMAL;
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
/* Link after configuration is set since a lot without configuration will cause all kinds of trouble. */
|
/* Link after configuration is set since a lot without configuration will cause all kinds of trouble. */
|
||||||
@@ -865,12 +880,143 @@ static void generate_or_link_lots_to_configs(void)
|
|||||||
|
|
||||||
for (iter = ao2_iterator_init(cfg->parking_lots, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
|
for (iter = ao2_iterator_init(cfg->parking_lots, 0); (lot_cfg = ao2_iterator_next(&iter)); ao2_ref(lot_cfg, -1)) {
|
||||||
RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
|
RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
|
||||||
lot = parking_lot_build_or_update(lot_cfg);
|
lot = parking_lot_build_or_update(lot_cfg, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ao2_iterator_destroy(&iter);
|
ao2_iterator_destroy(&iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int parking_dynamic_lots_enabled(void)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct parking_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
|
||||||
|
|
||||||
|
if (!cfg) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cfg->global->parkeddynamic;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct parking_lot_cfg *clone_parkinglot_cfg(struct parking_lot_cfg *source, const char *name)
|
||||||
|
{
|
||||||
|
struct parking_lot_cfg *cfg = parking_lot_cfg_alloc(name);
|
||||||
|
|
||||||
|
if (!cfg) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_string_fields_copy(cfg, source);
|
||||||
|
|
||||||
|
/* Needs to be reset after being copied */
|
||||||
|
ast_string_field_set(cfg, name, name);
|
||||||
|
|
||||||
|
/* Stuff that should be cloned that isn't hit by string field copy */
|
||||||
|
cfg->parking_start = source->parking_start;
|
||||||
|
cfg->parking_stop = source->parking_stop;
|
||||||
|
cfg->parkingtime = source->parkingtime;
|
||||||
|
cfg->comebackdialtime = source->comebackdialtime;
|
||||||
|
cfg->parkfindnext = source->parkfindnext;
|
||||||
|
cfg->parkext_exclusive = source->parkext_exclusive;
|
||||||
|
cfg->parkaddhints = source->parkaddhints;
|
||||||
|
cfg->comebacktoorigin = source->comebacktoorigin;
|
||||||
|
cfg->parkedplay = source->parkedplay;
|
||||||
|
cfg->parkedcalltransfers = source->parkedcalltransfers;
|
||||||
|
cfg->parkedcallreparking = source->parkedcallreparking;
|
||||||
|
cfg->parkedcallhangup = source->parkedcallhangup;
|
||||||
|
cfg->parkedcallrecording = source->parkedcallrecording;
|
||||||
|
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct parking_lot *parking_create_dynamic_lot(const char *name, struct ast_channel *chan)
|
||||||
|
{
|
||||||
|
RAII_VAR(struct parking_lot_cfg *, cfg, NULL, ao2_cleanup);
|
||||||
|
RAII_VAR(struct parking_lot *, template_lot, NULL, ao2_cleanup);
|
||||||
|
|
||||||
|
struct parking_lot *lot;
|
||||||
|
const char *dyn_context;
|
||||||
|
const char *dyn_exten;
|
||||||
|
const char *dyn_range;
|
||||||
|
const char *template_name;
|
||||||
|
const char *chan_template_name;
|
||||||
|
int dyn_start;
|
||||||
|
int dyn_end;
|
||||||
|
|
||||||
|
if (!parking_dynamic_lots_enabled()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_channel_lock(chan);
|
||||||
|
chan_template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
|
||||||
|
dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
|
||||||
|
dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), ""));
|
||||||
|
dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
|
||||||
|
ast_channel_unlock(chan);
|
||||||
|
|
||||||
|
template_name = S_OR(chan_template_name, DEFAULT_PARKING_LOT);
|
||||||
|
|
||||||
|
template_lot = parking_lot_find_by_name(template_name);
|
||||||
|
if (!template_lot) {
|
||||||
|
ast_log(LOG_ERROR, "Lot %s does not exist. Can not use it as a dynamic parking lot template.\n",
|
||||||
|
template_name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg = clone_parkinglot_cfg(template_lot->cfg, name);
|
||||||
|
|
||||||
|
if (!cfg) {
|
||||||
|
ast_log(LOG_ERROR, "Failed to allocate dynamic parking lot configuration.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ast_strlen_zero(dyn_exten)) {
|
||||||
|
ast_string_field_set(cfg, parkext, dyn_exten);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ast_strlen_zero(dyn_context)) {
|
||||||
|
ast_string_field_set(cfg, parking_con, dyn_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ast_strlen_zero(dyn_range)) {
|
||||||
|
if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
|
||||||
|
ast_log(LOG_ERROR,
|
||||||
|
"Invalid parking range %s specified in PARKINGDYNPOS: could not parse minimum/maximum parking space range\n", dyn_range);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (dyn_end < dyn_start || dyn_start < 0) {
|
||||||
|
ast_log(LOG_ERROR,
|
||||||
|
"Invalid parking range %s specified for PARKINGDYNPOS: end parking space must be greater than starting parking space.\n", dyn_range);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg->parking_start = dyn_start;
|
||||||
|
cfg->parking_stop = dyn_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parking_lot_cfg_create_extensions(cfg)) {
|
||||||
|
ast_log(LOG_ERROR, "Extensions for dynamic parking lot '%s' could not be registered. Dynamic lot creation failed.\n", name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ao2_lock(parking_lot_container);
|
||||||
|
|
||||||
|
if ((lot = parking_lot_find_by_name(name))) {
|
||||||
|
ao2_unlock(parking_lot_container);
|
||||||
|
ast_log(LOG_ERROR, "Started creating dynamic parking lot '%s', but a parking lot with that name already exists.\n", name);
|
||||||
|
ao2_ref(lot, -1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lot = parking_lot_build_or_update(cfg, 1);
|
||||||
|
ao2_unlock(parking_lot_container);
|
||||||
|
|
||||||
|
if (!lot) {
|
||||||
|
ast_log(LOG_NOTICE, "Failed to build dynamic parking lot '%s'\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return lot;
|
||||||
|
}
|
||||||
|
|
||||||
/* Preapply */
|
/* Preapply */
|
||||||
|
|
||||||
static int verify_default_parking_lot(void)
|
static int verify_default_parking_lot(void)
|
||||||
@@ -951,11 +1097,6 @@ static void mark_lots_as_disabled(void)
|
|||||||
struct parking_lot *lot;
|
struct parking_lot *lot;
|
||||||
|
|
||||||
for (iter = ao2_iterator_init(parking_lot_container, 0); (lot = ao2_iterator_next(&iter)); ao2_ref(lot, -1)) {
|
for (iter = ao2_iterator_init(parking_lot_container, 0); (lot = ao2_iterator_next(&iter)); ao2_ref(lot, -1)) {
|
||||||
/* We aren't concerned with dynamic lots */
|
|
||||||
if (lot->mode == PARKINGLOT_DYNAMIC) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lot->disable_mark = 1;
|
lot->disable_mark = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1003,7 +1144,7 @@ static int load_module(void)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
parking_lot_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_RWLOCK,
|
parking_lot_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_MUTEX,
|
||||||
AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
|
AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT,
|
||||||
parking_lot_sort_fn,
|
parking_lot_sort_fn,
|
||||||
NULL);
|
NULL);
|
||||||
@@ -1013,6 +1154,7 @@ static int load_module(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Global options */
|
/* Global options */
|
||||||
|
aco_option_register(&cfg_info, "parkeddynamic", ACO_EXACT, global_options, "no", OPT_BOOL_T, 1, FLDSET(struct parking_global_config, parkeddynamic));
|
||||||
|
|
||||||
/* Register the per parking lot options. */
|
/* Register the per parking lot options. */
|
||||||
aco_option_register(&cfg_info, "parkext", ACO_EXACT, parking_lot_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, parkext));
|
aco_option_register(&cfg_info, "parkext", ACO_EXACT, parking_lot_types, "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct parking_lot_cfg, parkext));
|
||||||
|
Reference in New Issue
Block a user