Restore Dial, Queue, and FollowMe 'I' option support.
[asterisk/asterisk.git] / res / parking / parking_bridge_features.c
index 06987dc..0e5e05d 100644 (file)
@@ -40,6 +40,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/say.h"
 #include "asterisk/datastore.h"
 #include "asterisk/stasis.h"
 #include "asterisk/say.h"
 #include "asterisk/datastore.h"
 #include "asterisk/stasis.h"
+#include "asterisk/module.h"
+#include "asterisk/core_local.h"
+#include "asterisk/causes.h"
 
 struct parked_subscription_datastore {
        struct stasis_subscription *parked_subscription;
 
 struct parked_subscription_datastore {
        struct stasis_subscription *parked_subscription;
@@ -188,15 +191,11 @@ static int create_parked_subscription(struct ast_channel *chan, const char *park
  */
 static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *context, const char *exten)
 {
  */
 static struct ast_channel *park_local_transfer(struct ast_channel *parker, const char *context, const char *exten)
 {
-       RAII_VAR(struct ast_channel *, parkee_side_2, NULL, ao2_cleanup);
        char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
        struct ast_channel *parkee;
        char destination[AST_MAX_EXTENSION + AST_MAX_CONTEXT + 1];
        struct ast_channel *parkee;
+       struct ast_channel *parkee_side_2;
        int cause;
 
        int cause;
 
-       /* Used for side_2 hack */
-       char *parkee_name;
-       char *semi_pos;
-
        /* Fill the variable with the extension and context we want to call */
        snprintf(destination, sizeof(destination), "%s@%s", exten, context);
 
        /* Fill the variable with the extension and context we want to call */
        snprintf(destination, sizeof(destination), "%s@%s", exten, context);
 
@@ -212,27 +211,19 @@ static struct ast_channel *park_local_transfer(struct ast_channel *parker, const
        ast_connected_line_copy_from_caller(ast_channel_connected(parkee), ast_channel_caller(parker));
        ast_channel_inherit_variables(parker, parkee);
        ast_channel_datastore_inherit(parker, parkee);
        ast_connected_line_copy_from_caller(ast_channel_connected(parkee), ast_channel_caller(parker));
        ast_channel_inherit_variables(parker, parkee);
        ast_channel_datastore_inherit(parker, parkee);
-       ast_channel_unlock(parkee);
        ast_channel_unlock(parker);
 
        ast_channel_unlock(parker);
 
-       /* BUGBUG Use Richard's unreal channel stuff here instead of this hack */
-       parkee_name = ast_strdupa(ast_channel_name(parkee));
-
-       semi_pos = strrchr(parkee_name, ';');
-       if (!semi_pos) {
-               /* There should always be a semicolon present in the string if is used since it's a local channel. */
-               ast_assert(0);
-               return NULL;
-       }
-
-       parkee_name[(semi_pos - parkee_name) + 1] = '2';
-       parkee_side_2 = ast_channel_get_by_name(parkee_name);
+       parkee_side_2 = ast_local_get_peer(parkee);
+       ast_assert(parkee_side_2 != NULL);
+       ast_channel_unlock(parkee);
 
        /* We need to have the parker subscribe to the new local channel before hand. */
        create_parked_subscription(parker, ast_channel_uniqueid(parkee_side_2));
 
        pbx_builtin_setvar_helper(parkee_side_2, "BLINDTRANSFER", ast_channel_name(parker));
 
 
        /* We need to have the parker subscribe to the new local channel before hand. */
        create_parked_subscription(parker, ast_channel_uniqueid(parkee_side_2));
 
        pbx_builtin_setvar_helper(parkee_side_2, "BLINDTRANSFER", ast_channel_name(parker));
 
+       ast_channel_unref(parkee_side_2);
+
        /* Since the above worked fine now we actually call it and return the channel */
        if (ast_call(parkee, destination, 0)) {
                ast_hangup(parkee);
        /* Since the above worked fine now we actually call it and return the channel */
        if (ast_call(parkee, destination, 0)) {
                ast_hangup(parkee);
@@ -242,7 +233,10 @@ static struct ast_channel *park_local_transfer(struct ast_channel *parker, const
        return parkee;
 }
 
        return parkee;
 }
 
-/*! \internal \brief Determine if an extension is a parking extension */
+/*!
+ * \internal
+ * \brief Determine if an extension is a parking extension
+ */
 static int parking_is_exten_park(const char *context, const char *exten)
 {
        struct ast_exten *exten_obj;
 static int parking_is_exten_park(const char *context, const char *exten)
 {
        struct ast_exten *exten_obj;
@@ -322,7 +316,8 @@ static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel
                        return -1;
                }
 
                        return -1;
                }
 
-               if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL, 1)) {
+               if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL,
+                       AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
                        ast_hangup(transfer_chan);
                        return -1;
                }
                        ast_hangup(transfer_chan);
                        return -1;
                }
@@ -452,6 +447,8 @@ static int parking_park_call(struct ast_bridge_channel *parker, char *exten, siz
 
 static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
 
 static int feature_park_call(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
 {
+       SCOPED_MODULE_USE(parking_get_module_info()->self);
+
        return parking_park_call(bridge_channel, NULL, 0);
 }
 
        return parking_park_call(bridge_channel, NULL, 0);
 }
 
@@ -488,7 +485,8 @@ static int parking_duration_callback(struct ast_bridge_channel *bridge_channel,
        user->resolution = PARK_TIMEOUT;
        ao2_unlock(user);
 
        user->resolution = PARK_TIMEOUT;
        ao2_unlock(user);
 
-       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+       ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
+               AST_CAUSE_NORMAL_CLEARING);
 
        /* Set parking timeout channel variables */
        snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
 
        /* Set parking timeout channel variables */
        snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
@@ -576,14 +574,17 @@ void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *pa
        if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
                /* If say_parking_space is called with a non-numeric string, we have a problem. */
                ast_assert(0);
        if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
                /* If say_parking_space is called with a non-numeric string, we have a problem. */
                ast_assert(0);
-               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+               ast_bridge_channel_leave_bridge(bridge_channel,
+                       BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
                return;
        }
 
                return;
        }
 
-       ast_say_digits(bridge_channel->chan, numeric_value, "", ast_channel_language(bridge_channel->chan));
+       ast_say_digits(bridge_channel->chan, numeric_value, "",
+               ast_channel_language(bridge_channel->chan));
 
        if (hangup_after) {
 
        if (hangup_after) {
-               ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE);
+               ast_bridge_channel_leave_bridge(bridge_channel,
+                       BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
        }
 }
 
        }
 }
 
@@ -607,9 +608,9 @@ void parking_set_duration(struct ast_bridge_features *features, struct parked_us
        /* The interval hook is going to need a reference to the parked_user */
        ao2_ref(user, +1);
 
        /* The interval hook is going to need a reference to the parked_user */
        ao2_ref(user, +1);
 
-       if (ast_bridge_interval_hook(features, time_limit,
+       if (ast_bridge_interval_hook(features, 0, time_limit,
                parking_duration_callback, user, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
                parking_duration_callback, user, __ao2_cleanup, AST_BRIDGE_HOOK_REMOVE_ON_PULL)) {
-               ast_log(LOG_ERROR, "Failed to apply duration limits to the parking call.\n");
+               ast_log(LOG_ERROR, "Failed to apply duration limit to the parked call.\n");
                ao2_ref(user, -1);
        }
 }
                ao2_ref(user, -1);
        }
 }
@@ -631,10 +632,15 @@ void unload_parking_bridge_features(void)
 
 int load_parking_bridge_features(void)
 {
 
 int load_parking_bridge_features(void)
 {
+       parking_provider.module_info = parking_get_module_info();
+
        if (ast_parking_register_bridge_features(&parking_provider)) {
                return -1;
        }
 
        if (ast_parking_register_bridge_features(&parking_provider)) {
                return -1;
        }
 
-       ast_bridge_features_register(AST_BRIDGE_BUILTIN_PARKCALL, feature_park_call, NULL);
+       if (ast_bridge_features_register(AST_BRIDGE_BUILTIN_PARKCALL, feature_park_call, NULL)) {
+               return -1;
+       }
+
        return 0;
 }
        return 0;
 }