res_parking: Replace Parker snapshots with ParkerDialString
authorJonathan Rose <jrose@digium.com>
Thu, 4 Jul 2013 18:46:56 +0000 (18:46 +0000)
committerJonathan Rose <jrose@digium.com>
Thu, 4 Jul 2013 18:46:56 +0000 (18:46 +0000)
This process also involved a large amount of rework regarding how to redial
the Parker when a channel leaves a parking lot due to timeout. An attended
transfer channel variable has been added to attended transfers to extensions
that will eventually park (but haven't at the time of transfer) as well.
This resolves one of the two BUGBUG comments remaining in res_parking.

(issues ASTERISK-21877)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2638/

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393704 65c4cc65-6c06-0410-ace0-fbb531ad65f3

17 files changed:
CHANGES
UPGRADE.txt
bridges/bridge_builtin_features.c
include/asterisk/channel.h
include/asterisk/parking.h
main/bridging.c
main/cel.c
main/channel.c
main/features.c
main/parking.c
res/parking/parking_applications.c
res/parking/parking_bridge.c
res/parking/parking_bridge_features.c
res/parking/parking_controller.c
res/parking/parking_manager.c
res/parking/parking_ui.c
res/parking/res_parking.h

diff --git a/CHANGES b/CHANGES
index e6da222..3223822 100644 (file)
--- 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
index 7a5261b..bcb2de4 100644 (file)
@@ -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
index b53e0db..f0c4c24 100644 (file)
@@ -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);
 
index d614941..2e74684 100644 (file)
@@ -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 */
index c4019d9..dd8a67b 100644 (file)
@@ -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);
 
index 110f525..348ce48 100644 (file)
@@ -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;
index 30838f3..bc1182a 100644 (file)
@@ -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);
index 3bc5c0a..ce11e50 100644 (file)
@@ -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.
index 577a176..9128551 100644 (file)
@@ -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>
index a3da860..02695cd 100644 (file)
@@ -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;
index eceeaca..f7e2797 100644 (file)
@@ -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;
        }
 
index 60d05ed..d0566a8 100644 (file)
@@ -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);
index f0cf0ae..aee4edb 100644 (file)
@@ -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)) {
index 2764f50..aa2baf5 100644 (file)
@@ -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;
index 5a2b3f6..b26f90e 100644 (file)
@@ -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,
index f3eeafa..2f54e86 100644 (file)
@@ -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");
 }
 
index 2955f87..b128ee3 100644 (file)
@@ -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