diff --git a/CHANGES b/CHANGES index e6da22224e3228ff13d0c4c4deecee68b5585d5c..3223822ba6b0bddb9aadf8124298838c796c86e8 100644 --- a/CHANGES +++ b/CHANGES @@ -136,6 +136,10 @@ Core feature on the bridge peer in a multi-party bridge will execute it on all peers of the activating channel. + * A channel variable ATTENDEDTRANSFER is now set which indicates which channel + was responsible for an attended transfer in a similar fashion to + BLINDTRANSFER. + AMI (Asterisk Manager Interface) ------------------ * The SIPshowpeer action will now include a 'SubscribeContext' field for a peer @@ -176,12 +180,24 @@ AMI (Asterisk Manager Interface) * The AMI events 'ParkedCall', 'ParkedCallTimeOut', 'ParkedCallGiveUp', and 'UnParkedCall' have changed significantly in the new res_parking module. - First, channel snapshot data is included for both the parker and the parkee - in lieu of the "From" and "Channel" fields. They follow standard channel - snapshot format but each field is suffixed with 'Parker' or 'Parkee' - depending on which side it applies to. The 'Exten' field is replaced with - 'ParkingSpace' since the registration of extensions as for parking spaces - is no longer mandatory. + + The 'Channel' and 'From' headers are gone. For the channel that was parked + or is coming out of parking, a 'Parkee' channel snapshot is issued and it + has a number of fields associated with it. The old 'Channel' header relayed + the same data as the new 'ParkeeChannel' header. + + The 'From' field was ambiguous and changed meaning depending on the event. + for most of these, it was the name of the channel that parked the call + (the 'Parker'). There is no longer a header that provides this channel name, + however the 'ParkerDialString' will contain a dialstring to redial the + device that parked the call. + + On UnParkedCall events, the 'From' header would instead represent the + channel responsible for retrieving the parkee. It receives a channel + snapshot labeled 'Retriever'. The 'from' field is is replaced with + 'RetrieverChannel'. + + Lastly, the 'Exten' field has been replaced with 'ParkingSpace'. * The AMI event 'Parkinglot' (response to 'Parkinglots' command) in a similar fashion has changed the field names 'StartExten' and 'StopExten' to diff --git a/UPGRADE.txt b/UPGRADE.txt index 7a5261b94d7da4c2f4fbb45f38617b13f99e296d..bcb2de4db1efecb61937d5ffdda67ae1129170e1 100644 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -75,6 +75,22 @@ AMI: - Channels no longer swap Uniqueid's as a result of the masquerade. - Instead of a shell game of renames, there's now a single rename, appending <ZOMBIE> to the name of the original channel. + - The AMI events 'ParkedCall', 'ParkedCallTimeOut', 'ParkedCallGiveUp', and + 'UnParkedCall' have changed significantly in the new res_parking module. + - The 'Channel' and 'From' headers are gone. For the channel that was parked + or is coming out of parking, a 'Parkee' channel snapshot is issued and it + has a number of fields associated with it. The old 'Channel' header relayed + the same data as the new 'ParkeeChannel' header. + - The 'From' field was ambiguous and changed meaning depending on the event. + for most of these, it was the name of the channel that parked the call + (the 'Parker'). There is no longer a header that provides this channel name, + however the 'ParkerDialString' will contain a dialstring to redial the + device that parked the call. + - On UnParkedCall events, the 'From' header would instead represent the + channel responsible for retrieving the parkee. It receives a channel + snapshot labeled 'Retriever'. The 'from' field is is replaced with + 'RetrieverChannel'. + - Lastly, the 'Exten' field has been replaced with 'ParkingSpace'. CEL: - The Uniqueid field for a channel is now a stable identifier, and will not diff --git a/bridges/bridge_builtin_features.c b/bridges/bridge_builtin_features.c index b53e0db5c56adc267f77a5151ad2eb2a321424b0..f0c4c24379bcc2cb9e374fcc353f1cdf8886a283 100644 --- a/bridges/bridge_builtin_features.c +++ b/bridges/bridge_builtin_features.c @@ -140,6 +140,9 @@ static struct ast_channel *dial_transfer(struct ast_channel *caller, const char /* Who is transferring the call. */ pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", ast_channel_name(caller)); + /* To work as an analog to BLINDTRANSFER */ + pbx_builtin_setvar_helper(chan, "ATTENDEDTRANSFER", ast_channel_name(caller)); + /* Before we actually dial out let's inherit appropriate information. */ copy_caller_data(chan, caller); diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index d61494141d549c39a70722b798a77f153d2bd42a..2e74684183c9a8ec9b10d21ca6f54b6334541a42 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -4375,5 +4375,13 @@ int ast_channel_forward_endpoint(struct ast_channel *chan, struct ast_endpoint * */ const char *ast_channel_oldest_linkedid(const char *a, const char *b); +/*! + * \brief Removes the trailing identifiers from a channel name string + * \since 12.0.0 + * + * \param channel_name string that you wish to turn into a dial string. + * This string will be edited in place. + */ +void ast_channel_name_to_dial_string(char *channel_name); #endif /* _ASTERISK_CHANNEL_H */ diff --git a/include/asterisk/parking.h b/include/asterisk/parking.h index c4019d9cb63fbe4da8d1063ecbfbcf4efcfeaec4..dd8a67bf28789a044c58134510bd4d92675ec770 100644 --- a/include/asterisk/parking.h +++ b/include/asterisk/parking.h @@ -45,14 +45,14 @@ enum ast_parked_call_event_type { */ struct ast_parked_call_payload { struct ast_channel_snapshot *parkee; /*!< Snapshot of the channel that is parked */ - struct ast_channel_snapshot *parker; /*!< Snapshot of the channel that parked the call */ - struct ast_channel_snapshot *retriever; /*!< Snapshot of the channel that retrieved the call */ + struct ast_channel_snapshot *retriever; /*!< Snapshot of the channel that retrieved the call (may be NULL) */ enum ast_parked_call_event_type event_type; /*!< Reason for issuing the parked call message */ long unsigned int timeout; /*!< Time remaining before the call times out (seconds ) */ long unsigned int duration; /*!< How long the parkee has been parked (seconds) */ unsigned int parkingspace; /*!< Which Parking Space the parkee occupies */ AST_DECLARE_STRING_FIELDS( AST_STRING_FIELD(parkinglot); /*!< Name of the parking lot used to park the parkee */ + AST_STRING_FIELD(parker_dial_string); /*!< The device string used for call control on parking timeout */ ); }; @@ -64,7 +64,7 @@ struct ast_exten; * * \param event_type What kind of parked call event is happening * \param parkee_snapshot channel snapshot of the parkee - * \param parker_snapshot channel snapshot of the parker + * \param parker_dial_string dialstring used when the call times out * \param retriever_snapshot channel snapshot of the retriever (NULL allowed) * \param parkinglot name of the parking lot where the parked call is parked * \param parkingspace what numerical parking space the parked call is parked in @@ -75,7 +75,7 @@ struct ast_exten; * \retval reference to a newly created parked call payload */ struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type, - struct ast_channel_snapshot *parkee_snapshot, struct ast_channel_snapshot *parker_snapshot, + struct ast_channel_snapshot *parkee_snapshot, const char *parker_dial_string, struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot, unsigned int parkingspace, unsigned long int timeout, unsigned long int duration); diff --git a/main/bridging.c b/main/bridging.c index 110f5255b1a21b21ed515d7b266f593c2b6beb1f..348ce48e82d91540a9bcfda9c1dba69628c5b79f 100644 --- a/main/bridging.c +++ b/main/bridging.c @@ -719,8 +719,9 @@ static int bridge_channel_push(struct ast_bridge_channel *bridge_channel) bridge_channel_pull(swap); } - /* Clear any BLINDTRANSFER since the transfer has completed. */ + /* Clear any BLINDTRANSFER and ATTENDEDTRANSFER since the transfer has completed. */ pbx_builtin_setvar_helper(bridge_channel->chan, "BLINDTRANSFER", NULL); + pbx_builtin_setvar_helper(bridge_channel->chan, "ATTENDEDTRANSFER", NULL); bridge->reconfigured = 1; return 0; diff --git a/main/cel.c b/main/cel.c index 30838f369e727e937671e0a26d46e5e46ee414bf..bc1182aa747c5aa89a4183addab51c7670680d3c 100644 --- a/main/cel.c +++ b/main/cel.c @@ -1333,7 +1333,7 @@ static void cel_parking_cb( case PARKED_CALL: report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_START, NULL, parked_payload->parkinglot, - S_COR(parked_payload->parker, parked_payload->parker->name, NULL)); + parked_payload->parker_dial_string); break; case PARKED_CALL_TIMEOUT: report_event_snapshot(parked_payload->parkee, AST_CEL_PARK_END, NULL, "ParkedCallTimeOut", NULL); diff --git a/main/channel.c b/main/channel.c index 3bc5c0a75c9e02f4de1086f90ed0e164b8494d07..ce11e50b75b8c3453ac493999fb59bb234b9798c 100644 --- a/main/channel.c +++ b/main/channel.c @@ -6565,6 +6565,17 @@ const char *ast_channel_oldest_linkedid(const char *a, const char *b) } } +void ast_channel_name_to_dial_string(char *channel_name) +{ + char *dash; + + /* Truncate after the dash */ + dash = strrchr(channel_name, '-'); + if (dash) { + *dash = '\0'; + } +} + /*! * \internal * \brief Transfer COLP between target and transferee channels. diff --git a/main/features.c b/main/features.c index 577a1765502f9a14a504b94a7fb4050e43a83b53..9128551d88fab020aa9a2aecb2399aa00cbbda93 100644 --- a/main/features.c +++ b/main/features.c @@ -282,46 +282,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") <para>Bridge together two channels already in the PBX.</para> </description> </manager> - <managerEvent language="en_US" name="ParkedCallTimeOut"> - <managerEventInstance class="EVENT_FLAG_CALL"> - <synopsis>Raised when a parked call times out.</synopsis> - <syntax> - <parameter name="Exten"> - <para>The parking lot extension.</para> - </parameter> - <parameter name="Channel"/> - <parameter name="Parkinglot"> - <para>The name of the parking lot.</para> - </parameter> - <parameter name="CallerIDNum"/> - <parameter name="CallerIDName"/> - <parameter name="ConnectedLineNum"/> - <parameter name="ConnectedLineName"/> - <parameter name="UniqueID"/> - </syntax> - <see-also> - <ref type="managerEvent">ParkedCall</ref> - </see-also> - </managerEventInstance> - </managerEvent> - <managerEvent language="en_US" name="ParkedCallGiveUp"> - <managerEventInstance class="EVENT_FLAG_CALL"> - <synopsis>Raised when a parked call hangs up while in the parking lot.</synopsis> - <syntax> - <xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCallTimeOut']/managerEventInstance/syntax/parameter[@name='Exten'])" /> - <parameter name="Channel"/> - <xi:include xpointer="xpointer(/docs/managerEvent[@name='ParkedCallTimeOut']/managerEventInstance/syntax/parameter[@name='Parkinglot'])" /> - <parameter name="CallerIDNum"/> - <parameter name="CallerIDName"/> - <parameter name="ConnectedLineNum"/> - <parameter name="ConnectedLineName"/> - <parameter name="UniqueID"/> - </syntax> - <see-also> - <ref type="managerEvent">ParkedCall</ref> - </see-also> - </managerEventInstance> - </managerEvent> <managerEvent language="en_US" name="Pickup"> <managerEventInstance class="EVENT_FLAG_CALL"> <synopsis>Raised when a call pickup occurs.</synopsis> diff --git a/main/parking.c b/main/parking.c index a3da860b73d7bcef40023cc99c0e5b14270a7569..02695cd01ceac3fcf3546f2a284382d3e4d1906f 100644 --- a/main/parking.c +++ b/main/parking.c @@ -79,13 +79,12 @@ static void parked_call_payload_destructor(void *obj) struct ast_parked_call_payload *park_obj = obj; ao2_cleanup(park_obj->parkee); - ao2_cleanup(park_obj->parker); ao2_cleanup(park_obj->retriever); ast_string_field_free_memory(park_obj); } struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_call_event_type event_type, - struct ast_channel_snapshot *parkee_snapshot, struct ast_channel_snapshot *parker_snapshot, + struct ast_channel_snapshot *parkee_snapshot, const char *parker_dial_string, struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot, unsigned int parkingspace, unsigned long int timeout, unsigned long int duration) @@ -106,11 +105,6 @@ struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_c ao2_ref(parkee_snapshot, +1); payload->parkee = parkee_snapshot; - if (parker_snapshot) { - ao2_ref(parker_snapshot, +1); - payload->parker = parker_snapshot; - } - if (retriever_snapshot) { ao2_ref(retriever_snapshot, +1); payload->retriever = retriever_snapshot; @@ -120,6 +114,10 @@ struct ast_parked_call_payload *ast_parked_call_payload_create(enum ast_parked_c ast_string_field_set(payload, parkinglot, parkinglot); } + if (parker_dial_string) { + ast_string_field_set(payload, parker_dial_string, parker_dial_string); + } + payload->parkingspace = parkingspace; payload->timeout = timeout; payload->duration = duration; diff --git a/res/parking/parking_applications.c b/res/parking/parking_applications.c index eceeaca18a450406cc5043025eda8e862cde5882..f7e27976610e53a6f697679d8b731c033587d337 100644 --- a/res/parking/parking_applications.c +++ b/res/parking/parking_applications.c @@ -284,14 +284,24 @@ static int park_app_parse_data(const char *data, int *disable_announce, int *use return 0; } -static void park_common_datastore_destroy(void *data) +void park_common_datastore_free(struct park_common_datastore *datastore) { - struct park_common_datastore *datastore = data; + if (!datastore) { + return; + } + ast_free(datastore->parker_uuid); + ast_free(datastore->parker_dial_string); ast_free(datastore->comeback_override); ast_free(datastore); } +static void park_common_datastore_destroy(void *data) +{ + struct park_common_datastore *datastore = data; + park_common_datastore_free(datastore); +} + static const struct ast_datastore_info park_common_info = { .type = "park entry data", .destroy = park_common_datastore_destroy, @@ -314,6 +324,9 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p { struct ast_datastore *datastore = NULL; struct park_common_datastore *park_datastore; + const char *attended_transfer; + const char *blind_transfer; + char *parker_dial_string = NULL; wipe_park_common_datastore(parkee); @@ -326,7 +339,27 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p return -1; } - park_datastore->parker_uuid = ast_strdup(parker_uuid); + if (parker_uuid) { + park_datastore->parker_uuid = ast_strdup(parker_uuid); + } + + ast_channel_lock(parkee); + + attended_transfer = pbx_builtin_getvar_helper(parkee, "ATTENDEDTRANSFER"); + blind_transfer = pbx_builtin_getvar_helper(parkee, "BLINDTRANSFER"); + + if (attended_transfer || blind_transfer) { + parker_dial_string = ast_strdupa(S_OR(attended_transfer, blind_transfer)); + } + + ast_channel_unlock(parkee); + + if (!ast_strlen_zero(parker_dial_string)) { + ast_channel_name_to_dial_string(parker_dial_string); + ast_verb(5, "Setting dial string to %s from %s value", parker_dial_string, attended_transfer ? "ATTENDEDTRANSFER" : "BLINDTRANSFER"); + park_datastore->parker_dial_string = ast_strdup(parker_dial_string); + } + park_datastore->randomize = randomize; park_datastore->time_limit = time_limit; park_datastore->silence_announce = silence_announce; @@ -344,16 +377,15 @@ static int setup_park_common_datastore(struct ast_channel *parkee, const char *p return 0; } -void get_park_common_datastore_data(struct ast_channel *parkee, char **parker_uuid, char **comeback_override, - int *randomize, int *time_limit, int *silence_announce) +struct park_common_datastore *get_park_common_datastore_copy(struct ast_channel *parkee) { struct ast_datastore *datastore; struct park_common_datastore *data; + struct park_common_datastore *data_copy; - ast_channel_lock(parkee); + SCOPED_CHANNELLOCK(lock, parkee); if (!(datastore = ast_channel_datastore_find(parkee, &park_common_info, NULL))) { - ast_channel_unlock(parkee); - return; + return NULL; } data = datastore->data; @@ -363,16 +395,37 @@ void get_park_common_datastore_data(struct ast_channel *parkee, char **parker_uu ast_assert(0); } - *parker_uuid = ast_strdup(data->parker_uuid); - *randomize = data->randomize; - *time_limit = data->time_limit; - *silence_announce = data->silence_announce; + data_copy = ast_calloc(1, sizeof(*data_copy)); + if (!data_copy) { + return NULL; + } + + if (!(data_copy->parker_uuid = ast_strdup(data->parker_uuid))) { + park_common_datastore_free(data_copy); + return NULL; + } + + data_copy->randomize = data->randomize; + data_copy->time_limit = data->time_limit; + data_copy->silence_announce = data->silence_announce; if (data->comeback_override) { - *comeback_override = ast_strdup(data->comeback_override); + data_copy->comeback_override = ast_strdup(data->comeback_override); + if (!data_copy->comeback_override) { + park_common_datastore_free(data_copy); + return NULL; + } } - ast_channel_unlock(parkee); + if (data->parker_dial_string) { + data_copy->parker_dial_string = ast_strdup(data->parker_dial_string); + if (!data_copy->parker_dial_string) { + park_common_datastore_free(data_copy); + return NULL; + } + } + + return data_copy; } struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_channel *parker, @@ -382,6 +435,10 @@ struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_chan struct ast_bridge *parking_bridge; RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup); + if (!parker) { + parker = parkee; + } + /* If the name of the parking lot isn't specified in the arguments, find it based on the channel. */ if (ast_strlen_zero(lot_name)) { ast_channel_lock(parker); @@ -433,18 +490,6 @@ struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast } -/* XXX BUGBUG - determining the parker when transferred to deep park priority - * Currently all parking by the park application is treated as calls parking themselves. - * However, it's possible for calls to be transferred here when the Park application is - * set after the first priority of an extension. In that case, there used to be a variable - * (BLINDTRANSFER) set indicating which channel placed that call here. - * - * If BLINDTRANSFER is set, this channel name will need to be referenced in Park events - * generated by stasis. Ideally we would get a whole channel snapshot and use that for the - * parker, but that would likely require applying the channel snapshot to a channel datastore - * on all transfers. Alternatively just the name of the parking channel could be applied along - * with an indication that it's dead. - */ int park_app_exec(struct ast_channel *chan, const char *data) { RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup); @@ -452,7 +497,7 @@ int park_app_exec(struct ast_channel *chan, const char *data) struct ast_bridge_features chan_features; int res; int silence_announcements = 0; - const char *blind_transfer; + const char *transferer; /* Answer the channel if needed */ if (ast_channel_state(chan) != AST_STATE_UP) { @@ -460,14 +505,15 @@ int park_app_exec(struct ast_channel *chan, const char *data) } ast_channel_lock(chan); - if ((blind_transfer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"))) { - blind_transfer = ast_strdupa(blind_transfer); + if (!(transferer = pbx_builtin_getvar_helper(chan, "ATTENDEDTRANSFER"))) { + transferer = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"); } + transferer = ast_strdupa(S_OR(transferer, "")); ast_channel_unlock(chan); /* Handle the common parking setup stuff */ - if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) { - if (!silence_announcements && !blind_transfer) { + if (!(parking_bridge = park_application_setup(chan, NULL, data, &silence_announcements))) { + if (!silence_announcements && !transferer) { ast_stream_and_wait(chan, "pbx-parkingfailed", ""); } return 0; @@ -767,7 +813,7 @@ int park_and_announce_app_exec(struct ast_channel *chan, const char *data) } /* Handle the common parking setup stuff */ - if (!(parking_bridge = park_application_setup(chan, chan, data, &silence_announcements))) { + if (!(parking_bridge = park_application_setup(chan, NULL, data, &silence_announcements))) { return 0; } diff --git a/res/parking/parking_bridge.c b/res/parking/parking_bridge.c index 60d05ed59d93c8d081d89735ecbb85618edcbcb6..d0566a8984ba12d67c2f62ff579ac5ba498dc90f 100644 --- a/res/parking/parking_bridge.c +++ b/res/parking/parking_bridge.c @@ -66,8 +66,23 @@ static void destroy_parked_user(void *obj) struct parked_user *pu = obj; ao2_cleanup(pu->lot); - ao2_cleanup(pu->parker); ao2_cleanup(pu->retriever); + ast_free(pu->parker_dial_string); +} + +/* Only call this on a parked user that hasn't had its parker_dial_string set already */ +static int parked_user_set_parker_dial_string(struct parked_user *pu, struct ast_channel *parker) +{ + char *dial_string = ast_strdupa(ast_channel_name(parker)); + + ast_channel_name_to_dial_string(dial_string); + pu->parker_dial_string = ast_strdup(dial_string); + + if (!pu->parker_dial_string) { + return -1; + } + + return 0; } /*! @@ -78,6 +93,7 @@ static void destroy_parked_user(void *obj) * \param lot The parking lot we are assigning the user to * \param parkee The channel being parked * \param parker The channel performing the park operation (may be the same channel) + * \param parker_dial_string Takes priority over parker for setting the parker dial string if included * \param use_random_space if true, prioritize using a random parking space instead * of ${PARKINGEXTEN} and/or automatic assignment from the parking lot * \param time_limit If using a custom timeout, this should be supplied so that the @@ -89,7 +105,7 @@ static void destroy_parked_user(void *obj) * * \note ao2_cleanup this reference when you are done using it or you'll cause leaks. */ -static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, struct ast_channel *parker, int use_random_space, int time_limit) +static struct parked_user *generate_parked_user(struct parking_lot *lot, struct ast_channel *chan, struct ast_channel *parker, const char *parker_dial_string, int use_random_space, int time_limit) { struct parked_user *new_parked_user; int preferred_space = -1; /* Initialize to use parking lot defaults */ @@ -106,10 +122,6 @@ static struct parked_user *generate_parked_user(struct parking_lot *lot, struct return NULL; } - ast_channel_lock(chan); - ast_copy_string(new_parked_user->blindtransfer, S_OR(pbx_builtin_getvar_helper(chan, "BLINDTRANSFER"), ""), AST_CHANNEL_NAME); - ast_channel_unlock(chan); - if (use_random_space) { preferred_space = ast_random() % (lot->cfg->parking_stop - lot->cfg->parking_start + 1); preferred_space += lot->cfg->parking_start; @@ -150,8 +162,18 @@ static struct parked_user *generate_parked_user(struct parking_lot *lot, struct new_parked_user->start = ast_tvnow(); new_parked_user->time_limit = (time_limit >= 0) ? time_limit : lot->cfg->parkingtime; - new_parked_user->parker = ast_channel_snapshot_create(parker); - if (!new_parked_user->parker) { + + if (parker_dial_string) { + new_parked_user->parker_dial_string = ast_strdup(parker_dial_string); + } else { + if (parked_user_set_parker_dial_string(new_parked_user, parker)) { + ao2_ref(new_parked_user, -1); + ao2_unlock(lot); + return NULL; + } + } + + if (!new_parked_user->parker_dial_string) { ao2_ref(new_parked_user, -1); ao2_unlock(lot); return NULL; @@ -183,13 +205,9 @@ static struct parked_user *generate_parked_user(struct parking_lot *lot, struct static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridge_channel *bridge_channel, struct ast_bridge_channel *swap) { struct parked_user *pu; - int randomize = 0; - int time_limit = -1; - int silence = 0; const char *blind_transfer; - RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup); - RAII_VAR(char *, parker_uuid, NULL, ast_free); - RAII_VAR(char *, comeback_override, NULL, ast_free); + RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup); /* XXX replace with ast_channel_cleanup when available */ + RAII_VAR(struct park_common_datastore *, park_datastore, NULL, park_common_datastore_free); ast_bridge_base_v_table.push(&self->base, bridge_channel, swap); @@ -231,11 +249,14 @@ static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridg return 0; } - get_park_common_datastore_data(bridge_channel->chan, &parker_uuid, &comeback_override, &randomize, &time_limit, &silence); - parker = ast_channel_get_by_name(parker_uuid); + if (!(park_datastore = get_park_common_datastore_copy(bridge_channel->chan))) { + /* There was either a failure to apply the datastore when performing park common setup or else we had alloc failures while cloning. Abort. */ + return -1; + } + parker = ast_channel_get_by_name(park_datastore->parker_uuid); /* If the parker and the parkee are the same channel pointer, then the channel entered using - * the park application. It's possible the the blindtransfer channel is still alive (particularly + * the park application. It's possible that the channel that transferred it is still alive (particularly * when a multichannel bridge is parked), so try to get the real parker if possible. */ ast_channel_lock(bridge_channel->chan); blind_transfer = S_OR(pbx_builtin_getvar_helper(bridge_channel->chan, "BLINDTRANSFER"), @@ -253,19 +274,17 @@ static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridg } } - if (!parker) { - return -1; - } + pu = generate_parked_user(self->lot, bridge_channel->chan, parker, + park_datastore->parker_dial_string, park_datastore->randomize, park_datastore->time_limit); - pu = generate_parked_user(self->lot, bridge_channel->chan, parker, randomize, time_limit); if (!pu) { publish_parked_call_failure(bridge_channel->chan); return -1; } /* If a comeback_override was provided, set it for the parked user's comeback string. */ - if (comeback_override) { - strncpy(pu->comeback, comeback_override, sizeof(pu->comeback)); + if (park_datastore->comeback_override) { + strncpy(pu->comeback, park_datastore->comeback_override, sizeof(pu->comeback)); pu->comeback[sizeof(pu->comeback) - 1] = '\0'; } @@ -273,7 +292,7 @@ static int bridge_parking_push(struct ast_bridge_parking *self, struct ast_bridg publish_parked_call(pu, PARKED_CALL); /* If the parkee and the parker are the same and silence_announce isn't set, play the announcement to the parkee */ - if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !silence) { + if (!strcmp(blind_transfer, ast_channel_name(bridge_channel->chan)) && !park_datastore->silence_announce) { char saynum_buf[16]; snprintf(saynum_buf, sizeof(saynum_buf), "%u %u", 0, pu->parking_space); ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL); diff --git a/res/parking/parking_bridge_features.c b/res/parking/parking_bridge_features.c index f0cf0ae448055f5cc15872cfb4b61b2280cc9ed3..aee4edbab2dce06d5f046af1a4f864ea04922b31 100644 --- a/res/parking/parking_bridge_features.c +++ b/res/parking/parking_bridge_features.c @@ -367,23 +367,6 @@ static void parking_duration_cb_destroyer(void *hook_pvt) ao2_ref(user, -1); } -/*! - * \brief Removes the identification information from a channel name string - * \since 12.0 - * - * \param channel name string that you wish to turn into a dial string. This will be edited in place. - */ -static void channel_name_to_dial_string(char *peername) -{ - char *dash; - - /* Truncate after the dash */ - dash = strrchr(peername, '-'); - if (dash) { - *dash = '\0'; - } -} - /*! \internal * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout. * @@ -396,8 +379,8 @@ static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridg struct parked_user *user = hook_pvt; struct ast_channel *chan = user->chan; struct ast_context *park_dial_context; - char *peername; - char *peername_flat; + const char *dial_string; + char *dial_string_flat; char parking_space[AST_MAX_EXTENSION]; char returnexten[AST_MAX_EXTENSION]; @@ -426,14 +409,12 @@ static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridg pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */ pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name); - peername = ast_strdupa(S_OR(user->blindtransfer, user->parker->name)); - channel_name_to_dial_string(peername); - - peername_flat = ast_strdupa(user->parker->name); - flatten_peername(peername_flat); + dial_string = user->parker_dial_string; + dial_string_flat = ast_strdupa(dial_string); + flatten_dial_string(dial_string_flat); - pbx_builtin_setvar_helper(chan, "PARKER", peername); - pbx_builtin_setvar_helper(chan, "PARKER_FLAT", peername_flat); + pbx_builtin_setvar_helper(chan, "PARKER", dial_string); + pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat); /* Dialplan generation for park-dial extensions */ @@ -462,26 +443,26 @@ static int parking_duration_callback(struct ast_bridge *bridge, struct ast_bridg ast_assert(0); } - snprintf(returnexten, sizeof(returnexten), "%s,%u", peername, + snprintf(returnexten, sizeof(returnexten), "%s,%u", dial_string, user->lot->cfg->comebackdialtime); duplicate_returnexten = ast_strdup(returnexten); if (!duplicate_returnexten) { ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n", - peername_flat, PARK_DIAL_CONTEXT, returnexten); + dial_string_flat, PARK_DIAL_CONTEXT, returnexten); } /* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */ - if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, peername_flat, 1, NULL, NULL, E_MATCH)) && + if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) && (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) { ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n", - peername_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten)); - } else if (ast_add_extension2_nolock(park_dial_context, 1, peername_flat, 1, NULL, NULL, + dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten)); + } else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL, "Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR)) { ast_free(duplicate_returnexten); ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n", - peername_flat, PARK_DIAL_CONTEXT, returnexten); + dial_string_flat, PARK_DIAL_CONTEXT, returnexten); } if (ast_unlock_context(park_dial_context)) { diff --git a/res/parking/parking_controller.c b/res/parking/parking_controller.c index 2764f50d4ffa236d9ba4afc9d52a3664bb048a04..aa2baf5ccee453bf9dbc1276a2e8d0ceb2c00cd9 100644 --- a/res/parking/parking_controller.c +++ b/res/parking/parking_controller.c @@ -220,22 +220,14 @@ void parked_call_retrieve_enable_features(struct ast_channel *chan, struct parki return; } -void flatten_peername(char *peername) +void flatten_dial_string(char *dialstring) { int i; - char *dash; - /* Truncate after the dash */ - dash = strrchr(peername, '-'); - if (dash) { - *dash = '\0'; - } - - /* Replace slashes with underscores since slashes are reserved characters for extension matching */ - for (i = 0; peername[i]; i++) { - if (peername[i] == '/') { + for (i = 0; dialstring[i]; i++) { + if (dialstring[i] == '/') { /* The underscore is the flattest character of all. */ - peername[i] = '_'; + dialstring[i] = '_'; } } } @@ -243,39 +235,37 @@ void flatten_peername(char *peername) int comeback_goto(struct parked_user *pu, struct parking_lot *lot) { struct ast_channel *chan = pu->chan; - char *peername; - - peername = ast_strdupa(S_OR(pu->blindtransfer, pu->parker->name)); + char *peername_flat = ast_strdupa(pu->parker_dial_string); /* Flatten the peername so that it can be used for performing the timeout PBX operations */ - flatten_peername(peername); + flatten_dial_string(peername_flat); if (lot->cfg->comebacktoorigin) { - if (ast_exists_extension(chan, PARK_DIAL_CONTEXT, peername, 1, NULL)) { - ast_async_goto(chan, PARK_DIAL_CONTEXT, peername, 1); + if (ast_exists_extension(chan, PARK_DIAL_CONTEXT, peername_flat, 1, NULL)) { + ast_async_goto(chan, PARK_DIAL_CONTEXT, peername_flat, 1); return 0; } else { ast_log(LOG_ERROR, "Can not start %s at %s,%s,1 because extension does not exist. Terminating call.\n", - ast_channel_name(chan), PARK_DIAL_CONTEXT, peername); + ast_channel_name(chan), PARK_DIAL_CONTEXT, peername_flat); return -1; } } - if (ast_exists_extension(chan, lot->cfg->comebackcontext, peername, 1, NULL)) { - ast_async_goto(chan, lot->cfg->comebackcontext, peername, 1); + if (ast_exists_extension(chan, lot->cfg->comebackcontext, peername_flat, 1, NULL)) { + ast_async_goto(chan, lot->cfg->comebackcontext, peername_flat, 1); return 0; } if (ast_exists_extension(chan, lot->cfg->comebackcontext, "s", 1, NULL)) { ast_verb(2, "Could not start %s at %s,%s,1. Using 's@%s' instead.\n", ast_channel_name(chan), - lot->cfg->comebackcontext, peername, lot->cfg->comebackcontext); + lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext); ast_async_goto(chan, lot->cfg->comebackcontext, "s", 1); return 0; } ast_verb(2, "Can not start %s at %s,%s,1 and exten 's@%s' does not exist. Using 's@default'\n", ast_channel_name(chan), - lot->cfg->comebackcontext, peername, lot->cfg->comebackcontext); + lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext); ast_async_goto(chan, "default", "s", 1); return 0; diff --git a/res/parking/parking_manager.c b/res/parking/parking_manager.c index 5a2b3f6fdf3930558e0209e84473bb75170d45ab..b26f90e359dfc271cecba3393780acf8f5a4b433 100644 --- a/res/parking/parking_manager.c +++ b/res/parking/parking_manager.c @@ -134,43 +134,8 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") </parameter> <parameter name="ParkeeUniqueid"> </parameter> - <parameter name="ParkerChannel"> - </parameter> - <parameter name="ParkerChannelState"> - <para>A numeric code for the channel's current state, related to ChannelStateDesc</para> - </parameter> - <parameter name="ParkerChannelStateDesc"> - <enumlist> - <enum name="Down"/> - <enum name="Rsrvd"/> - <enum name="OffHook"/> - <enum name="Dialing"/> - <enum name="Ring"/> - <enum name="Ringing"/> - <enum name="Up"/> - <enum name="Busy"/> - <enum name="Dialing Offhook"/> - <enum name="Pre-ring"/> - <enum name="Unknown"/> - </enumlist> - </parameter> - <parameter name="ParkerCallerIDNum"> - </parameter> - <parameter name="ParkerCallerIDName"> - </parameter> - <parameter name="ParkerConnectedLineNum"> - </parameter> - <parameter name="ParkerConnectedLineName"> - </parameter> - <parameter name="ParkerAccountCode"> - </parameter> - <parameter name="ParkerContext"> - </parameter> - <parameter name="ParkerExten"> - </parameter> - <parameter name="ParkerPriority"> - </parameter> - <parameter name="ParkerUniqueid"> + <parameter name="ParkerDialString"> + <para>Dial String that can be used to call back the parker on ParkingTimeout.</para> </parameter> <parameter name="Parkinglot"> <para>Name of the parking lot that the parkee is parked in</para> @@ -276,10 +241,6 @@ static struct ast_parked_call_payload *parked_call_payload_from_parked_user(stru struct timeval now = ast_tvnow(); const char *lot_name = pu->lot->name; - if (!pu->parker) { - return NULL; - } - parkee_snapshot = ast_channel_snapshot_create(pu->chan); if (!parkee_snapshot) { @@ -289,7 +250,7 @@ static struct ast_parked_call_payload *parked_call_payload_from_parked_user(stru timeout = pu->start.tv_sec + (long) pu->time_limit - now.tv_sec; duration = now.tv_sec - pu->start.tv_sec; - return ast_parked_call_payload_create(event_type, parkee_snapshot, pu->parker, pu->retriever, lot_name, pu->parking_space, timeout, duration); + return ast_parked_call_payload_create(event_type, parkee_snapshot, pu->parker_dial_string, pu->retriever, lot_name, pu->parking_space, timeout, duration); } @@ -298,7 +259,6 @@ static struct ast_str *manager_build_parked_call_string(const struct ast_parked_ { struct ast_str *out = ast_str_create(1024); RAII_VAR(struct ast_str *, parkee_string, NULL, ast_free); - RAII_VAR(struct ast_str *, parker_string, NULL, ast_free); RAII_VAR(struct ast_str *, retriever_string, NULL, ast_free); if (!out) { @@ -307,26 +267,22 @@ static struct ast_str *manager_build_parked_call_string(const struct ast_parked_ parkee_string = ast_manager_build_channel_state_string_prefix(payload->parkee, "Parkee"); - if (payload->parker) { - parker_string = ast_manager_build_channel_state_string_prefix(payload->parker, "Parker"); - } - if (payload->retriever) { retriever_string = ast_manager_build_channel_state_string_prefix(payload->retriever, "Retriever"); } ast_str_set(&out, 0, "%s" /* parkee channel state */ - "%s" /* parker channel state */ "%s" /* retriever channel state (when available) */ + "ParkerDialString: %s\r\n" "Parkinglot: %s\r\n" "ParkingSpace: %u\r\n" "ParkingTimeout: %lu\r\n" "ParkingDuration: %lu\r\n", ast_str_buffer(parkee_string), - parker_string ? ast_str_buffer(parker_string) : "", retriever_string ? ast_str_buffer(retriever_string) : "", + payload->parker_dial_string, payload->parkinglot, payload->parkingspace, payload->timeout, diff --git a/res/parking/parking_ui.c b/res/parking/parking_ui.c index f3eeafa4c6cfcb3770f25bdb895ea5b6854dd5c1..2f54e8637e0fff6423587882b47012918de34a7b 100644 --- a/res/parking/parking_ui.c +++ b/res/parking/parking_ui.c @@ -40,9 +40,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static void display_parked_call(struct parked_user *user, int fd) { - ast_cli(fd, " Space: %d\n", user->parking_space); - ast_cli(fd, " Channel: %s\n", ast_channel_name(user->chan)); - ast_cli(fd, " Parker: %s\n", user->parker ? user->parker->name : "<unknown>"); + ast_cli(fd, " Space : %d\n", user->parking_space); + ast_cli(fd, " Channel : %s\n", ast_channel_name(user->chan)); + ast_cli(fd, " Parker Dial String : %s\n", user->parker_dial_string); ast_cli(fd, "\n"); } diff --git a/res/parking/res_parking.h b/res/parking/res_parking.h index 2955f87e1d88deafcdc67675f823ae6ae8f43167..b128ee3358cd4184dfef15d276e2f160d855a8b0 100644 --- a/res/parking/res_parking.h +++ b/res/parking/res_parking.h @@ -100,12 +100,11 @@ struct parking_lot { struct parked_user { struct ast_channel *chan; /*!< Parked channel */ - struct ast_channel_snapshot *parker; /*!< Snapshot of the channel that parked the call at the time of parking */ struct ast_channel_snapshot *retriever; /*!< Snapshot of the channel that retrieves a parked call */ struct timeval start; /*!< When the call was parked */ int parking_space; /*!< Which parking space is used */ char comeback[AST_MAX_CONTEXT]; /*!< Where to go on parking timeout */ - char blindtransfer[AST_CHANNEL_NAME]; /*!< What the BLINDTRANSFER variable was at the time of entry */ + char *parker_dial_string; /*!< dialstring to call back with comebacktoorigin. Used timeout extension generation and call control */ unsigned int time_limit; /*!< How long this specific channel may remain in the parking lot before timing out */ struct parking_lot *lot; /*!< Which parking lot the user is parked to */ enum park_call_resolution resolution; /*!< How did the parking session end? If the call is in a bridge, lock parked_user before checking/setting */ @@ -285,11 +284,11 @@ const char *find_channel_parking_lot_name(struct ast_channel *chan); /*! * \since 12.0.0 - * \brief Flattens a peer name so that it can be written to/found from PBX extensions + * \brief Flattens a dial string so that it can be written to/found from PBX extensions * - * \param peername unflattened peer name. This will be flattened in place, so expect it to change. + * \param peername unflattened dial string. This will be flattened in place. */ -void flatten_peername(char *peername); +void flatten_dial_string(char *dialstring); /*! * \since 12.0.0 @@ -370,7 +369,7 @@ struct ast_bridge *park_common_setup(struct ast_channel *parkee, struct ast_chan * channel. * * \param parkee The channel being preparred for parking - * \param parker The channel initiating the park; may be the parkee as well + * \param parker The channel initiating the park; may be the parkee as well. May be NULL. * \param app_data arguments supplied to the Park application. May be NULL. * \param silence_announcements optional pointer to an integer where we want to store the silence option flag * this value should be initialized to 0 prior to calling park_common_setup. @@ -385,6 +384,7 @@ struct ast_bridge *park_application_setup(struct ast_channel *parkee, struct ast struct park_common_datastore { char *parker_uuid; /*!< Unique ID of the channel parking the call. */ + char *parker_dial_string; /*!< Dial string that we would attempt to call when timing out when comebacktoorigin=yes */ char *comeback_override; /*!< Optional goto string for where to send the call after we are done */ int randomize; /*!< Pick a parking space to enter on at random */ int time_limit; /*!< time limit override. -1 values don't override, 0 for unlimited time, >0 for custom time limit in seconds */ @@ -393,19 +393,22 @@ struct park_common_datastore { /*! * \since 12.0.0 - * \brief Function that pulls data from the park common datastore on a channel in order to apply it to - * the parked user struct upon bridging. + * \brief Get a copy of the park_common_datastore from a channel that is being parked * * \param parkee The channel entering parking with the datastore we are checking - * \param parker_uuid pointer to a string pointer for placing the name of the channel that parked parkee - * \param comeback_override pointer to a string pointer for placing the comeback_override option - * \param randomize integer pointer to an integer for placing the randomize option - * \param time_limit integer pointer to an integer for placing the time limit option - * \param silence_announce pointer to an integer for placing the silence_announcements option - */ -void get_park_common_datastore_data(struct ast_channel *parkee, - char **parker_uuid, char **comeback_override, - int *randomize, int *time_limit, int *silence_announce); + * + * \retval Pointer to a copy of the park common datastore for parkee if it could be cloned. This needs to be free'd with park_common_datastore free. + * \retval NULL if the park_common_datastore could not be copied off of the channel. + */ +struct park_common_datastore *get_park_common_datastore_copy(struct ast_channel *parkee); + +/*! + * \since 12.0.0 + * \brief Free a park common datastore struct + * + * \param datastore The park_common_datastore being free'd. (NULL tolerant) + */ +void park_common_datastore_free(struct park_common_datastore *datastore); /*! * \since 12.0.0