244 static int parking_lot_sort_fn(
const void *obj_left,
const void *obj_right,
int flags)
248 const char *right_key = obj_right;
254 right_key = right->
name;
257 cmp = strcmp(left->
name, right_key);
260 cmp = strncmp(left->
name, right_key, strlen(right_key));
273 static int config_parking_preapply(
void);
274 static void link_configured_disable_marked_lots(
void);
290 .category =
"general",
295 static struct aco_type parking_lot_type = {
297 .name =
"parking_lot",
299 .category =
"general",
307 struct aco_file parking_lot_conf = {
309 .types =
ACO_TYPES(&global_option, &parking_lot_type),
315 .files = ACO_FILES(&parking_lot_conf),
316 .pre_apply_config = config_parking_preapply,
317 .post_apply_config = link_configured_disable_marked_lots,
320 static int parking_lot_cfg_hash_fn(
const void *obj,
const int flags)
338 static int parking_lot_cfg_cmp_fn(
void *obj,
void *arg,
const int flags)
352 key_size = strlen(key);
353 return (!strncmp(entry1->
name, key, key_size)) ?
CMP_MATCH : 0;
366 ao2_cleanup(cfg->parking_lots);
367 ao2_cleanup(cfg->global);
386 parking_lot_cfg_hash_fn, NULL, parking_lot_cfg_cmp_fn);
387 if (!cfg->parking_lots) {
414 static void parking_lot_disable(
struct parking_lot *lot)
435 static int parked_user_cmp_fn(
void *obj,
void *arg,
int flags)
437 int *search_space = arg;
441 if (*search_space == object_space) {
447 static int parked_user_sort_fn(
const void *obj_left,
const void *obj_right,
int flags)
471 ao2_cleanup(lot_cfg);
480 #if defined(TEST_FRAMEWORK)
499 return ao2_find(container, name,
OBJ_KEY);
511 if (sscanf(var->
value,
"%30d-%30d", &low, &high) != 2) {
512 ast_log(LOG_WARNING,
"Format for parking positions is a-b, where a and b are numbers\n");
513 }
else if (high < low || low <= 0 || high <= 0) {
514 ast_log(LOG_WARNING,
"Format for parking positions is a-b, where a <= b\n");
530 if (!strcmp(var->
value,
"first")) {
532 }
else if (!strcmp(var->
value,
"next")) {
535 ast_log(LOG_WARNING,
"value '%s' is not valid for findslot option.\n", var->
value);
549 }
else if (!strcasecmp(var,
"both")) {
550 *param = AST_FEATURE_FLAG_BYBOTH;
551 }
else if (!strcasecmp(var,
"caller")) {
552 *param = AST_FEATURE_FLAG_BYCALLER;
553 }
else if (!strcasecmp(var,
"callee")) {
554 *param = AST_FEATURE_FLAG_BYCALLEE;
569 int *parameter = NULL;
575 case OPT_PARKEDTRANSFERS:
578 case OPT_PARKEDREPARKING:
581 case OPT_PARKEDHANGUP:
584 case OPT_PARKEDRECORDING:
589 ast_assert(parameter != NULL);
614 if (ast_strlen_zero(name)) {
616 name = ast_channel_parkinglot(chan);
617 if (ast_strlen_zero(name)) {
619 name = DEFAULT_PARKING_LOT;
626 static void parking_lot_destructor(
void *obj)
634 ao2_cleanup(lot->
cfg);
641 if (!(lot = ao2_alloc(
sizeof(*lot), parking_lot_destructor))) {
666 if (!ast_strlen_zero(lot_cfg->
registrar)) {
679 static void remove_all_configured_parking_lot_extensions(
void)
714 static int parking_add_extension(
struct ast_context *context,
int replace,
const char *
extension,
715 int priority,
const char *application,
const char *data,
const char *registrar)
719 if (!data_duplicate) {
724 application, data_duplicate,
ast_free_ptr, registrar, NULL, 0)) {
731 static int extension_is_compatible(
struct parking_lot_cfg *lot_cfg,
const char *app_type,
struct ast_exten *extension)
733 const char *extension_registrar = ast_get_extension_registrar(extension);
734 const char *extension_context = ast_get_context_name(ast_get_extension_context(extension));
735 const char *extension_name = ast_get_extension_name(extension);
736 const char *extension_application = ast_get_extension_app(extension);
738 ast_assert(extension_registrar && extension_context && extension_name && extension_application);
740 if (strcmp(extension_registrar, BASE_REGISTRAR)) {
741 ast_log(LOG_ERROR,
"Parking lot '%s' -- Needs an extension '%s@%s', but that extension is already owned by %s.\n",
742 lot_cfg->
name, extension_name, extension_context, extension_registrar);
746 if (strcmp(extension_application, app_type)) {
747 ast_log(LOG_ERROR,
"Parking lot '%s' -- Needs an extension '%s@%s' with a non-exclusive %s application, "
748 "but a/an %s application is already registered to that extension by %s.\n",
749 lot_cfg->
name, extension_name, extension_context, app_type,
750 extension_application, BASE_REGISTRAR);
754 ast_debug(3,
"Parking lot '%s' -- extension '%s@%s' with application %s is compatible.\n",
755 lot_cfg->
name, extension_name, extension_context, app_type);
765 const char *parkext_registrar_pointer;
766 const char *parkedcall_registrar_pointer;
768 if (ast_strlen_zero(lot_cfg->
parkext)) {
773 parkedcall_registrar_pointer = lot_cfg->
registrar;
776 parkext_registrar_pointer = lot_cfg->
registrar;
778 parkext_registrar_pointer = BASE_REGISTRAR;
785 ast_log(LOG_ERROR,
"Parking lot '%s' -- Needs a context '%s' which does not exist and Asterisk was unable to create\n",
799 if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->
parking_con, lot_cfg->
parkext, 1, NULL, NULL, E_MATCH))) {
806 ast_log(LOG_ERROR,
"Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
813 for (parkingspace = lot_cfg->
parking_start; parkingspace <= lot_cfg->parking_stop; parkingspace++) {
816 find_info.stacklen = 0;
818 snprintf(space,
sizeof(space),
"%d", parkingspace);
821 if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->
parking_con, space, 1, NULL, NULL, E_MATCH))) {
827 if (!arguments_string) {
833 if (parking_add_extension(lot_context, 0, space, 1, PARKED_CALL_APPLICATION,
834 ast_str_buffer(arguments_string), parkedcall_registrar_pointer)) {
835 ast_log(LOG_ERROR,
"Parking lot '%s' -- Failed to add %s extension '%s@%s' to the PBX.\n",
841 find_info.stacklen = 0;
846 snprintf(hint_device,
sizeof(hint_device),
"park:%s@%s", space, lot_cfg->
parking_con);
848 if ((existing_exten = pbx_find_extension(NULL, NULL, &find_info, lot_cfg->
parking_con, space,
PRIORITY_HINT, NULL, NULL, E_MATCH))) {
849 ast_log(LOG_ERROR,
"Parking lot '%s' -- Needs to add a hint '%s' at '%s@%s' but one already exists owned by %s\n",
850 lot_cfg->
name, hint_device, space, lot_cfg->
parking_con, ast_get_extension_registrar(existing_exten));
855 if (parking_add_extension(lot_context, 0, space,
PRIORITY_HINT, hint_device,
"", parkedcall_registrar_pointer)) {
856 ast_log(LOG_ERROR,
"Parking lot '%s' -- Failed to add hint '%s@%s' to the PBX.\n",
878 lot = alloc_new_parking_lot(lot_cfg);
888 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);
896 replaced_cfg = lot->
cfg;
902 ao2_cleanup(replaced_cfg);
910 ao2_link(parking_lot_container, lot);
916 static void generate_or_link_lots_to_configs(
void)
923 for (; (lot_cfg = ao2_iterator_next(&iter));
ao2_ref(lot_cfg, -1)) {
937 return cfg->global->parkeddynamic;
971 static struct parking_lot *create_dynamic_lot_full(
const char *name,
struct ast_channel *chan,
int forced)
977 const char *dyn_context;
978 const char *dyn_exten;
979 const char *dyn_range;
980 const char *template_name;
981 const char *chan_template_name;
989 ast_channel_lock(chan);
994 ast_channel_unlock(chan);
996 template_name =
S_OR(chan_template_name, DEFAULT_PARKING_LOT);
1000 ast_log(LOG_ERROR,
"Lot %s does not exist. Can not use it as a dynamic parking lot template.\n",
1005 cfg = clone_parkinglot_cfg(template_lot->cfg, name);
1008 ast_log(LOG_ERROR,
"Failed to allocate dynamic parking lot configuration.\n");
1012 if (!ast_strlen_zero(dyn_exten)) {
1016 if (!ast_strlen_zero(dyn_context)) {
1020 if (!ast_strlen_zero(dyn_range)) {
1021 if (sscanf(dyn_range,
"%30d-%30d", &dyn_start, &dyn_end) != 2) {
1023 "Invalid parking range %s specified in PARKINGDYNPOS: could not parse minimum/maximum parking space range\n", dyn_range);
1026 if (dyn_end < dyn_start || dyn_start < 0) {
1028 "Invalid parking range %s specified for PARKINGDYNPOS: end parking space must be greater than starting parking space.\n", dyn_range);
1037 ast_log(LOG_ERROR,
"Extensions for dynamic parking lot '%s' could not be registered. Dynamic lot creation failed.\n", name);
1041 ao2_lock(parking_lot_container);
1044 ao2_unlock(parking_lot_container);
1045 ast_log(LOG_ERROR,
"Started creating dynamic parking lot '%s', but a parking lot with that name already exists.\n", name);
1051 ao2_unlock(parking_lot_container);
1054 ast_log(LOG_NOTICE,
"Failed to build dynamic parking lot '%s'\n", name);
1061 return create_dynamic_lot_full(name, chan, 0);
1064 #if defined(TEST_FRAMEWORK)
1066 return create_dynamic_lot_full(name, chan, 1);
1072 static int verify_default_parking_lot(
void)
1081 lot_cfg = ao2_find(cfg->parking_lots, DEFAULT_PARKING_LOT,
OBJ_KEY);
1087 ast_log(AST_LOG_NOTICE,
"Adding %s profile to res_parking\n", DEFAULT_PARKING_LOT);
1090 ao2_link(cfg->parking_lots, lot_cfg);
1096 static void remove_pending_parking_lot_extensions(
struct parking_config *cfg_pending)
1101 for (iter =
ao2_iterator_init(cfg_pending->parking_lots, 0); (lot_cfg = ao2_iterator_next(&iter));
ao2_ref(lot_cfg, -1)) {
1111 static int configure_parking_extensions(
void)
1123 remove_all_configured_parking_lot_extensions();
1128 ao2_cleanup(lot_cfg);
1137 remove_pending_parking_lot_extensions(cfg);
1138 ast_log(LOG_ERROR,
"Extension registration failed. Previously configured lot extensions were removed and can not be safely restored.\n");
1144 static void mark_lots_as_disabled(
void)
1156 static int config_parking_preapply(
void)
1158 mark_lots_as_disabled();
1160 if (verify_default_parking_lot()) {
1164 if (configure_parking_extensions()) {
1171 static void disable_marked_lots(
void)
1178 parking_lot_disable(lot);
1185 static void link_configured_disable_marked_lots(
void)
1187 generate_or_link_lots_to_configs();
1188 disable_marked_lots();
1191 static int unload_module(
void)
1194 remove_all_configured_parking_lot_extensions();
1200 ao2_cleanup(parking_lot_container);
1201 parking_lot_container = NULL;
1208 static int load_module(
void)
1212 parking_lot_sort_fn,
1214 if (!parking_lot_container) {
1281 static int reload_module(
void)
1290 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"Call Parking Resource",
1291 .support_level = AST_MODULE_SUPPORT_CORE,
1292 .load = load_module,
1293 .unload = unload_module,
1294 .reload = reload_module,
int ast_unlock_context(struct ast_context *con)
Main Channel structure associated with a channel.
int load_parking_manager(void)
Register manager actions and setup subscriptions for stasis events.
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...
unsigned int comebackdialtime
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void parking_global_config_destructor(void *obj)
destructor for parking_global_config
struct parking_lot * parking_create_dynamic_lot(const char *name, struct ast_channel *chan)
Create a dynamic parking lot.
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
unsigned int aco_option_get_flags(const struct aco_option *option)
Read the flags of a config option - useful when using a custom callback for a config option...
void unload_parking_ui(void)
Unregister CLI commands.
void unload_parking_applications(void)
Unregister parking applications.
struct ast_bridge * parking_bridge
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
struct ao2_container * parked_users
int load_parking_tests(void)
Register parking unit tests.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Structure for variables, used for configurations and for channel variables.
int parking_lot_remove_if_unused(struct parking_lot *lot)
Remove a parking lot from the usable lists if it is no longer involved in any calls and no configurat...
void parking_lot_cfg_remove_extensions(struct parking_lot_cfg *lot_cfg)
Remove extensions belonging to a parking lot configuration.
int ast_bridge_destroy(struct ast_bridge *bridge, int cause)
Destroy a bridge.
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int ast_wrlock_contexts(void)
Write locks the context list.
static int parking_feature_flag_cfg(int *param, const char *var)
Maps string values for option_handler_parkedfeature to their ENUM values.
int load_parking_ui(void)
Register CLI commands.
#define ast_strdup(str)
A wrapper for strdup()
static void * named_item_find(struct ao2_container *container, const char *name)
find an item in a container by its name
The representation of a single configuration file to be processed.
void ast_free_ptr(void *ptr)
free() wrapper
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
void unload_parking_bridge_features(void)
Unregister features registered by load_parking_bridge_features.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static int option_handler_findslot(const struct aco_option *opt, struct ast_variable *var, void *obj)
Custom field handler for the findslot option.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
struct ao2_container * get_parking_lot_container(void)
Get a pointer to the parking lot container for purposes such as iteration.
void unload_parking_devstate(void)
Unregister Parking devstate handler.
Configuration File Parser.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
const ast_string_field name
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
const ast_string_field parking_con
int load_parking_bridge_features(void)
Register bridge features for parking.
void * aco_pending_config(struct aco_info *info)
Get pending config changes.
int parking_dynamic_lots_enabled(void)
Check global configuration to see if dynamic parking is enabled.
Type for default option handler for unsigned integers.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_strdupa(s)
duplicate a string in memory from the stack
unsigned int parkaddhints
struct parking_lot * parking_lot_find_by_name(const char *lot_name)
Find a parking lot based on its name.
static struct ao2_container * parking_lot_container
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_MAX_EXTENSION
const char * find_channel_parking_lot_name(struct ast_channel *chan)
Find parking lot name from channel.
structure to hold extensions
static int option_handler_parkedfeature(const struct aco_option *opt, struct ast_variable *var, void *obj)
Custom field handler for feature mapping on parked call pickup options.
struct ao2_container * container
#define ast_debug(level,...)
Log a DEBUG message.
Core PBX routines and definitions.
unsigned int comebacktoorigin
static void * parking_lot_cfg_alloc(const char *cat)
create a parking lot structure
static void parking_config_destructor(void *obj)
destructor for parking_config
Their was an error and no changes were applied.
int load_parking_applications(void)
Register parking applications.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
Configuration option-handling.
#define ast_string_fields_copy(copy, orig)
Copy all string fields from one instance to another of the same structure.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Support for dynamic strings.
const ast_string_field registrar
#define ao2_unlink(container, obj)
Remove an object from a container.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Type for default option handler for bools (ast_true/ast_false)
int ast_unlock_contexts(void)
Unlocks contexts.
void unload_parking_tests(void)
Unregister parking unit tests.
int ast_wrlock_context(struct ast_context *con)
Write locks a given context.
#define PARK_APPLICATION
The default parking application that Asterisk expects.
static int option_handler_parkpos(const struct aco_option *opt, struct ast_variable *var, void *obj)
Custom field handler for parking positions.
unsigned int parkfindnext
void unload_parking_manager(void)
Unregister manager actions and remove subscriptions for stasis events.
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Module has failed to load, may be in an inconsistent state.
const ast_string_field name
static void * parking_config_alloc(void)
allocator callback for parking_config. Notice it returns void * since it is only used by the backend ...
static struct aco_type global_option
An aco_type structure to link the "general" category to the skel_global_config type.
structure to hold users read from users.conf
#define ast_string_field_build(x, field, fmt, args...)
Set a field to a complex (built) value.
enum parking_lot_modes mode
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Standard Command Line Interface.
Type information about a category-level configurable object.
const ast_string_field parkext
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
struct parking_lot * parking_lot_build_or_update(struct parking_lot_cfg *lot_cfg, int dynamic)
If a parking lot exists in the parking lot list already, update its status to match the provided conf...
void ast_context_destroy(struct ast_context *con, const char *registrar)
Destroy a context (matches the specified context or ANY context if NULL)
Type for default option handler for stringfields.
int load_parking_devstate(void)
Register Parking devstate handler.
Reject objects with duplicate keys in container.
Call Parking Resource Internal API.
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.
#define AO2_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
#define ASTERISK_GPL_KEY
The text the key() function should return.
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.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define CONFIG_INFO_STANDARD(name, arr, alloc,...)
Declare an aco_info struct with default module and preload values.
ast_context: An extension context
int parking_lot_cfg_create_extensions(struct parking_lot_cfg *lot_cfg)
Add extensions for a parking lot configuration.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
unsigned int parkext_exclusive
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.
static void parking_lot_cfg_destructor(void *obj)
Destroy a parking lot cfg object.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
struct parking_lot_cfg * cfg
#define ao2_link(container, obj)
Add an object to a container.