diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index 2770233332..cbc23fac1b 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -30,10 +30,12 @@ #include "asterisk/astobj2.h" #include "asterisk/logger.h" #include "asterisk/pbx.h" +#include "asterisk/app.h" #include "asterisk/bridge.h" #include "asterisk/bridge_internal.h" #include "asterisk/bridge_channel.h" #include "asterisk/bridge_features.h" +#include "asterisk/conversions.h" #include "asterisk/features.h" #include "asterisk/say.h" #include "asterisk/datastore.h" @@ -42,6 +44,24 @@ #include "asterisk/core_local.h" #include "asterisk/causes.h" +/*** DOCUMENTATION + <function name="PARK_GET_CHANNEL" language="en_US"> + <synopsis> + Get the channel name of an occupied parking space in a parking lot. + </synopsis> + <syntax> + <parameter name="parking_space" required="true"> + </parameter> + <parameter name="parking_lot" required="true"> + </parameter> + </syntax> + <description> + <para>This function returns the channel of the specified parking space + if the parking lot space is occupied.</para> + </description> + </function> +***/ + struct parked_subscription_datastore { struct stasis_subscription *parked_subscription; }; @@ -704,6 +724,60 @@ void parking_set_duration(struct ast_bridge_features *features, struct parked_us } } +/*! \brief Dial plan function to get the parking lot channel of an occupied parking lot */ +static int func_get_parkingslot_channel(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len) +{ + RAII_VAR(struct parked_user *, pu, NULL, ao2_cleanup); + RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup); + unsigned int space = 0; + const char *content = NULL; + + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(parking_space); + AST_APP_ARG(parking_lot); + AST_APP_ARG(other); + ); + + /* Parse the arguments. */ + AST_STANDARD_APP_ARGS(args, data); + + if (args.argc < 2) { + /* Didn't receive enough arguments to do anything */ + ast_log(LOG_ERROR, "Usage: %s(<parking_space>,<parking_lot>)\n", + function); + return -1; + } + + lot = parking_lot_find_by_name(args.parking_lot); + if (!lot) { + ast_log(LOG_ERROR, "Could not find parking lot: '%s'\n", args.parking_lot); + return -1; + } + + if (!ast_strlen_zero(args.parking_space)) { + if (ast_str_to_uint(args.parking_space, &space) != 0) { + ast_log(LOG_ERROR, "value '%s' for parking_space argument is invalid. Must be an integer greater than 0.\n", + args.parking_space); + return -1; + } + } + + pu = parking_lot_inspect_parked_user(lot, space); + if (!pu) { + return -1; + } + + content = ast_channel_name(pu->chan); + ast_copy_string(buf, content, len); + + return 0; +} + +static struct ast_custom_function getparkingslotchannel_function = { + .name = "PARK_GET_CHANNEL", + .read = func_get_parkingslot_channel, +}; + struct ast_parking_bridge_feature_fn_table parking_provider = { .module_version = PARKING_MODULE_VERSION, .module_name = __FILE__, @@ -717,12 +791,15 @@ void unload_parking_bridge_features(void) { ast_bridge_features_unregister(AST_BRIDGE_BUILTIN_PARKCALL); ast_parking_unregister_bridge_features(parking_provider.module_name); + ast_custom_function_unregister(&getparkingslotchannel_function); } int load_parking_bridge_features(void) { parking_provider.module = AST_MODULE_SELF; + ast_custom_function_register(&getparkingslotchannel_function); + if (ast_parking_register_bridge_features(&parking_provider)) { return -1; } diff --git a/res/parking/parking_controller.c b/res/parking/parking_controller.c index 9e9e540cd8..365acddb7f 100644 --- a/res/parking/parking_controller.c +++ b/res/parking/parking_controller.c @@ -163,6 +163,23 @@ static int retrieve_parked_user_targeted(void *obj, void *arg, int flags) return 0; } +struct parked_user *parking_lot_inspect_parked_user(struct parking_lot *lot, int target) +{ + struct parked_user *user; + + if (target < 0) { + user = ao2_callback(lot->parked_users, 0, NULL, NULL); + } else { + user = ao2_callback(lot->parked_users, 0, retrieve_parked_user_targeted, &target); + } + + if (!user) { + return NULL; + } + + return user; +} + struct parked_user *parking_lot_retrieve_parked_user(struct parking_lot *lot, int target) { RAII_VAR(struct parked_user *, user, NULL, ao2_cleanup); diff --git a/res/parking/res_parking.h b/res/parking/res_parking.h index 3c34e5c92e..79fb97f34b 100644 --- a/res/parking/res_parking.h +++ b/res/parking/res_parking.h @@ -195,6 +195,19 @@ struct ast_bridge *parking_lot_get_bridge(struct parking_lot *lot); */ int parking_lot_get_space(struct parking_lot *lot, int target_override); +/*! + * \brief Determine if there is a parked user in a parking space and return it if there is. + * + * \param lot Parking lot being pulled from + * \param target If < 0 search for the first occupied space in the parking lot + * If >= 0 Only pull from the indicated target + * + * \retval NULL if no parked user could be pulled from the requested parking lot at the requested parking space + * \retval reference to the requested parked user + * + */ +struct parked_user *parking_lot_inspect_parked_user(struct parking_lot *lot, int target); + /*! * \since 12.0.0 * \brief Determine if there is a parked user in a parking space and pull it from the parking lot if there is.