[asterisk-commits] mjordan: trunk r396028 - in /trunk: channels/ include/asterisk/ main/ res/ re...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Thu Aug 1 15:55:23 CDT 2013


Author: mjordan
Date: Thu Aug  1 15:55:17 2013
New Revision: 396028

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=396028
Log:
Support externally initiated parking requests; remove some dead code

This patch does the following:
 * It adds support for externally initiated parking requests. In particular,
   chan_skinny has a protocol level message that initiates a call park.
   This patch now supports that option, as well as the protocol specific
   mechanisms in chan_dahdi/sig_analog and chan_mgcp.
 * A parking bridge features virtual table has been added that provides
   access to the parking functionality that the Bridging API needs. This
   includes requests to park an entire 'call' (with little or no additional
   information, thank you chan_skinny), perform a blind transfer to a parking
   extension, determine if an extension is a parking extension, as well as the
   actual "do the parking" request from the Bridging API.
 * Refactoring in chan_mgcp, chan_skinny, and chan_dahdi to make use of the new
   functions
 * The removal of some - but not all - dead parking code from features.c

This also fixed blind transferring a multi-party bridge to a parking lot (which
was implemented, but had at least one code path where using the parking features
kK might not have worked)

Review: https://reviewboard.asterisk.org/r/2710

(closes issue ASTERISK-22134)
Reported by: Matt Jordan


Modified:
    trunk/channels/chan_dahdi.c
    trunk/channels/chan_iax2.c
    trunk/channels/chan_mgcp.c
    trunk/channels/chan_skinny.c
    trunk/channels/sig_analog.c
    trunk/include/asterisk/features.h
    trunk/include/asterisk/parking.h
    trunk/main/bridge.c
    trunk/main/bridge_channel.c
    trunk/main/features.c
    trunk/main/parking.c
    trunk/res/parking/parking_bridge_features.c
    trunk/res/res_parking.c

Modified: trunk/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_dahdi.c?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/channels/chan_dahdi.c (original)
+++ trunk/channels/chan_dahdi.c Thu Aug  1 15:55:17 2013
@@ -126,6 +126,7 @@
 #include "asterisk/features_config.h"
 #include "asterisk/bridge.h"
 #include "asterisk/stasis_channels.h"
+#include "asterisk/parking.h"
 #include "chan_dahdi.h"
 #include "dahdi/bridge_native_dahdi.h"
 
@@ -9230,6 +9231,10 @@
 	int idx;
 	struct ast_format tmpfmt;
 	RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, parking_provider,
+		ast_parking_get_bridge_features(),
+		ao2_cleanup);
+	int is_exten_parking;
 	const char *pickupexten;
 
 	ast_mutex_lock(&ss_thread_lock);
@@ -9560,11 +9565,13 @@
 				exten[len++]=res;
 				exten[len] = '\0';
 			}
-			if (!ast_ignore_pattern(ast_channel_context(chan), exten))
+			if (!ast_ignore_pattern(ast_channel_context(chan), exten)) {
 				tone_zone_play_tone(p->subs[idx].dfd, -1);
-			else
+			} else {
 				tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
-			if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !ast_parking_ext_valid(exten, chan, ast_channel_context(chan))) {
+			}
+			is_exten_parking = (parking_provider ? parking_provider->parking_is_exten_park(ast_channel_context(chan), exten) : 0);
+			if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
 				if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
 					if (getforward) {
 						/* Record this as the forwarding extension */
@@ -9700,14 +9707,17 @@
 				getforward = 0;
 				memset(exten, 0, sizeof(exten));
 				len = 0;
-			} else if ((p->transfer || p->canpark) && ast_parking_ext_valid(exten, chan, ast_channel_context(chan)) &&
-						p->subs[SUB_THREEWAY].owner &&
-						ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
+			} else if ((p->transfer || p->canpark) && is_exten_parking &&
+						p->subs[SUB_THREEWAY].owner) {
+				RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
 				/* This is a three way call, the main call being a real channel,
 					and we're parking the first call. */
-				ast_masq_park_call_exten(ast_bridged_channel(p->subs[SUB_THREEWAY].owner),
-					chan, exten, ast_channel_context(chan), 0, NULL);
-				ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+				ast_channel_lock(chan);
+				bridge_channel = ast_channel_get_bridge_channel(chan);
+				ast_channel_unlock(chan);
+				if (bridge_channel && !parking_provider->parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+					ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+				}
 				break;
 			} else if (p->hidecallerid && !strcmp(exten, "*82")) {
 				ast_verb(3, "Enabling Caller*ID on %s\n", ast_channel_name(chan));

Modified: trunk/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_iax2.c?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/channels/chan_iax2.c (original)
+++ trunk/channels/chan_iax2.c Thu Aug  1 15:55:17 2013
@@ -9202,7 +9202,7 @@
 	memset(&ied1, 0, sizeof(ied1));
 	mm = ast_matchmore_extension(NULL, context, callednum, 1, callerid);
 	/* Must be started */
-	if (ast_parking_ext_valid(callednum, NULL, context) || ast_exists_extension(NULL, context, callednum, 1, callerid)) {
+	if (ast_exists_extension(NULL, context, callednum, 1, callerid)) {
 		dpstatus = IAX_DPSTATUS_EXISTS;
 	} else if (ast_canmatch_extension(NULL, context, callednum, 1, callerid)) {
 		dpstatus = IAX_DPSTATUS_CANEXIST;

Modified: trunk/channels/chan_mgcp.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_mgcp.c?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/channels/chan_mgcp.c (original)
+++ trunk/channels/chan_mgcp.c Thu Aug  1 15:55:17 2013
@@ -84,6 +84,7 @@
 #include "asterisk/stasis.h"
 #include "asterisk/bridge.h"
 #include "asterisk/features_config.h"
+#include "asterisk/parking.h"
 
 /*
  * Define to work around buggy dlink MGCP phone firmware which
@@ -2980,6 +2981,9 @@
 	int getforward = 0;
 	int loop_pause = 100;
 	RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, parking_provider,
+		ast_parking_get_bridge_features(),
+		ao2_cleanup);
 	const char *pickupexten;
 
 	len = strlen(p->dtmf_buf);
@@ -3148,13 +3152,17 @@
 			getforward = 0;
 			memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
 			len = 0;
-		} else if (ast_parking_ext_valid(p->dtmf_buf, chan, ast_channel_context(chan)) &&
-			sub->next->owner && ast_bridged_channel(sub->next->owner)) {
+		} else if (parking_provider && parking_provider->parking_is_exten_park(ast_channel_context(chan), p->dtmf_buf) &&
+			sub->next->owner) {
+			RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
 			/* This is a three way call, the main call being a real channel,
-			   and we're parking the first call. */
-			ast_masq_park_call_exten(ast_bridged_channel(sub->next->owner), chan,
-				p->dtmf_buf, ast_channel_context(chan), 0, NULL);
-			ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+				and we're parking the first call. */
+			ast_channel_lock(chan);
+			bridge_channel = ast_channel_get_bridge_channel(chan);
+			ast_channel_unlock(chan);
+			if (bridge_channel && !parking_provider->parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), p->dtmf_buf)) {
+				ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+			}
 			break;
 		} else if (!ast_strlen_zero(p->lastcallerid) && !strcmp(p->dtmf_buf, "*60")) {
 			ast_verb(3, "Blacklisting number %s\n", p->lastcallerid);

Modified: trunk/channels/chan_skinny.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/chan_skinny.c?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/channels/chan_skinny.c (original)
+++ trunk/channels/chan_skinny.c Thu Aug  1 15:55:17 2013
@@ -82,6 +82,7 @@
 #include "asterisk/linkedlists.h"
 #include "asterisk/stasis_endpoints.h"
 #include "asterisk/bridge.h"
+#include "asterisk/parking.h"
 
 /*** DOCUMENTATION
 	<manager name="SKINNYdevices" language="en_US">
@@ -6404,24 +6405,37 @@
 		break;
 	case STIMULUS_CALLPARK:
 		{
-		int extout;
+		char extout[AST_MAX_EXTENSION];
 		char message[32];
-
+		RAII_VAR(struct ast_parking_bridge_feature_fn_table *, parking_provider,
+			ast_parking_get_bridge_features(),
+			ao2_cleanup);
+		RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received STIMULUS_CALLPARK from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
 
-		if ((sub && sub->owner) && (ast_channel_state(sub->owner) ==  AST_STATE_UP)){
+		if (!parking_provider) {
+			transmit_displaynotify(d, "Call Park not available", 10);
+			break;
+		}
+
+		if ((sub && sub->owner) && (ast_channel_state(sub->owner) ==  AST_STATE_UP)) {
 			c = sub->owner;
-			if (ast_bridged_channel(c)) {
-				if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
-					snprintf(message, sizeof(message), "Call Parked at: %d", extout);
-					transmit_displaynotify(d, message, 10);
-				} else {
-					transmit_displaynotify(d, "Call Park failed", 10);
-				}
-			} else {
-				transmit_displaynotify(d, "Call Park not available", 10);
-			}
+			ast_channel_lock(c);
+			bridge_channel = ast_channel_get_bridge_channel(c);
+			ast_channel_unlock(c);
+
+			if (!bridge_channel) {
+				transmit_displaynotify(d, "Call Park failed", 10);
+				break;
+			}
+
+			if (!parking_provider->parking_park_call(bridge_channel, extout, sizeof(extout))) {
+				snprintf(message, sizeof(message), "Call Parked at: %s", extout);
+				transmit_displaynotify(d, message, 10);
+				break;
+			}
+			transmit_displaynotify(d, "Call Park failed", 10);
 		} else {
 			transmit_displaynotify(d, "Call Park not available", 10);
 		}
@@ -7141,24 +7155,37 @@
 		break;
 	case SOFTKEY_PARK:
 		{
-		int extout;
+		char extout[AST_MAX_EXTENSION];
 		char message[32];
-
+		RAII_VAR(struct ast_parking_bridge_feature_fn_table *, parking_provider,
+			ast_parking_get_bridge_features(),
+			ao2_cleanup);
+		RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);
 		SKINNY_DEBUG(DEBUG_PACKET, 3, "Received SOFTKEY_PARK from %s, inst %d, callref %d\n",
 			d->name, instance, callreference);
 
-		if ((sub && sub->owner) && (ast_channel_state(sub->owner) ==  AST_STATE_UP)){
+		if (!parking_provider) {
+			transmit_displaynotify(d, "Call Park not available", 10);
+			break;
+		}
+
+		if ((sub && sub->owner) && (ast_channel_state(sub->owner) ==  AST_STATE_UP)) {
 			c = sub->owner;
-			if (ast_bridged_channel(c)) {
-				if (!ast_masq_park_call(ast_bridged_channel(c), c, 0, &extout)) {
-					snprintf(message, sizeof(message), "Call Parked at: %d", extout);
-					transmit_displaynotify(d, message, 10);
-				} else {
-					transmit_displaynotify(d, "Call Park failed", 10);
-				}
-			} else {
-				transmit_displaynotify(d, "Call Park not available", 10);
-			}
+			ast_channel_lock(c);
+			bridge_channel = ast_channel_get_bridge_channel(c);
+			ast_channel_unlock(c);
+
+			if (!bridge_channel) {
+				transmit_displaynotify(d, "Call Park failed", 10);
+				break;
+			}
+
+			if (!parking_provider->parking_park_call(bridge_channel, extout, sizeof(extout))) {
+				snprintf(message, sizeof(message), "Call Parked at: %s", extout);
+				transmit_displaynotify(d, message, 10);
+				break;
+			}
+			transmit_displaynotify(d, "Call Park failed", 10);
 		} else {
 			transmit_displaynotify(d, "Call Park not available", 10);
 		}

Modified: trunk/channels/sig_analog.c
URL: http://svnview.digium.com/svn/asterisk/trunk/channels/sig_analog.c?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/channels/sig_analog.c (original)
+++ trunk/channels/sig_analog.c Thu Aug  1 15:55:17 2013
@@ -44,6 +44,7 @@
 #include "asterisk/causes.h"
 #include "asterisk/features_config.h"
 #include "asterisk/bridge.h"
+#include "asterisk/parking.h"
 
 #include "sig_analog.h"
 
@@ -1713,7 +1714,11 @@
 	int idx;
 	struct ast_callid *callid;
 	RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
+	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, parking_provider,
+		ast_parking_get_bridge_features(),
+		ao2_cleanup);
 	const char *pickupexten;
+	int is_exten_parking;
 
 	analog_increase_ss_count();
 
@@ -2094,7 +2099,8 @@
 			} else {
 				analog_play_tone(p, idx, ANALOG_TONE_DIALTONE);
 			}
-			if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !ast_parking_ext_valid(exten, chan, ast_channel_context(chan))) {
+			is_exten_parking = (parking_provider ? parking_provider->parking_is_exten_park(ast_channel_context(chan), exten) : 0);
+			if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) {
 				if (!res || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) {
 					if (getforward) {
 						/* Record this as the forwarding extension */
@@ -2238,15 +2244,18 @@
 				getforward = 0;
 				memset(exten, 0, sizeof(exten));
 				len = 0;
-			} else if ((p->transfer || p->canpark) && ast_parking_ext_valid(exten, chan, ast_channel_context(chan)) &&
-						p->subs[ANALOG_SUB_THREEWAY].owner &&
-						ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner)) {
+			} else if ((p->transfer || p->canpark) && is_exten_parking &&
+						p->subs[ANALOG_SUB_THREEWAY].owner) {
+				struct ast_bridge_channel *bridge_channel;
 				/* This is a three way call, the main call being a real channel,
 					and we're parking the first call. */
-				ast_masq_park_call_exten(
-					ast_bridged_channel(p->subs[ANALOG_SUB_THREEWAY].owner), chan, exten,
-					ast_channel_context(chan), 0, NULL);
-				ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+				ast_channel_lock(chan);
+				bridge_channel = ast_channel_get_bridge_channel(chan);
+				ast_channel_unlock(chan);
+				if (bridge_channel && !parking_provider->parking_blind_transfer_park(bridge_channel, ast_channel_context(chan), exten)) {
+					ast_verb(3, "Parking call to '%s'\n", ast_channel_name(chan));
+				}
+				ao2_ref(bridge_channel, -1);
 				break;
 			} else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {
 				ast_verb(3, "Blacklisting number %s\n", p->lastcid_num);

Modified: trunk/include/asterisk/features.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/features.h?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/include/asterisk/features.h (original)
+++ trunk/include/asterisk/features.h Thu Aug  1 15:55:17 2013
@@ -62,50 +62,6 @@
 	AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
 	AST_FEATURE_FLAG_BYBOTH	 =   (3 << 3),
 };
-
-/*!
- * \brief Park a call via a masqueraded channel
- *
- * \param park_me Channel to be parked.
- * \param parker Channel parking the call.
- * \param timeout is a timeout in milliseconds
- * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
- *
- * \details
- * Masquerade the park_me channel into a new, empty channel which is then parked.
- *
- * \note Use ast_masq_park_call_exten() instead.
- *
- * \retval 0 on success.
- * \retval -1 on failure.
- */
-int ast_masq_park_call(struct ast_channel *park_me, struct ast_channel *parker, int timeout, int *extout);
-
-/*!
- * \brief Park a call via a masqueraded channel
- * \since 1.8.9
- *
- * \param park_me Channel to be parked.
- * \param parker Channel parking the call.
- * \param park_exten Parking lot access extension
- * \param park_context Parking lot context
- * \param timeout is a timeout in milliseconds
- * \param extout is a parameter to an int that will hold the parked location, or NULL if you want.
- *
- * \details
- * Masquerade the park_me channel into a new, empty channel which is then parked.
- *
- * \retval 0 on success.
- * \retval -1 on failure.
- */
-int ast_masq_park_call_exten(struct ast_channel *park_me, struct ast_channel *parker, const char *park_exten, const char *park_context, int timeout, int *extout);
-
-/*!
- * \brief Determine if parking extension exists in a given context
- * \retval 0 if extension does not exist
- * \retval 1 if extension does exist
-*/
-int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context);
 
 /*! \brief Bridge a call, optionally allowing redirection */
 int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer,struct ast_bridge_config *config);

Modified: trunk/include/asterisk/parking.h
URL: http://svnview.digium.com/svn/asterisk/trunk/include/asterisk/parking.h?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/include/asterisk/parking.h (original)
+++ trunk/include/asterisk/parking.h Thu Aug  1 15:55:17 2013
@@ -25,6 +25,9 @@
 
 #include "asterisk/stringfields.h"
 
+/*!
+ * \brief The default parking application that Asterisk expects.
+ */
 #define PARK_APPLICATION "Park"
 
 /*!
@@ -79,6 +82,10 @@
 		struct ast_channel_snapshot *retriever_snapshot, const char *parkinglot,
 		unsigned int parkingspace, unsigned long int timeout, unsigned long int duration);
 
+/*! \addtogroup StasisTopicsAndMessages
+ * @{
+ */
+
 /*!
  * \brief accessor for the parking stasis topic
  * \since 12
@@ -97,75 +104,110 @@
  */
 struct stasis_message_type *ast_parked_call_type(void);
 
-/*!
- * \brief invoke an installable park callback to asynchronously park a bridge_channel in a bridge
- * \since 12
- *
- * \param bridge_channel the bridge channel that initiated parking
- * \parkee_uuid channel id of the channel being parked
- * \parker_uuid channel id of the channel that initiated parking
- * \param app_data string of application data that might be applied to parking
- */
-void ast_bridge_channel_park(struct ast_bridge_channel *bridge_channel,
-	const char *parkee_uuid,
-	const char *parker_uuid,
-	const char *app_data);
-
-typedef int (*ast_park_blind_xfer_fn)(struct ast_bridge_channel *parker, struct ast_exten *park_exten);
-
-/*!
- * \brief install a callback for handling blind transfers to a parking extension
- * \since 12
- *
- * \param parking_func Function to use for transfers to 'Park' applications
- */
-void ast_install_park_blind_xfer_func(ast_park_blind_xfer_fn park_blind_xfer_func);
-
-/*!
- * \brief uninstall a callback for handling blind transfers to a parking extension
- * \since 12
- */
-void ast_uninstall_park_blind_xfer_func(void);
-
-/*!
- * \brief use the installed park blind xfer func
- * \since 12
- *
- * \param parker Bridge channel initiating the park
- * \param park_exten Exten to blind transfer part to.
+/*! @} */
+
+#define PARKING_MODULE_VERSION 1
+
+/*!
+ * \brief A function table providing parking functionality to the \ref AstBridging
+ * Bridging API and other consumers
+ */
+struct ast_parking_bridge_feature_fn_table {
+
+	/*!
+	 * \brief The version of this function table. If the ABI for this table
+	 * changes, the module version (/ref PARKING_MODULE_VERSION) should be
+	 * incremented.
+	 */
+	unsigned int module_version;
+
+	/*!
+	 * \brief The name of the module that provides this parking functionality
+	 */
+	const char *module_name;
+
+	/*!
+	 * \brief Determine if the context/exten is a "parking" extension
+	 *
+	 * \retval 0 if the extension is not a parking extension
+	 * \retval 1 if the extension is a parking extension
+	 */
+	int (* parking_is_exten_park)(const char *context, const char *exten);
+
+	/*!
+	 * \brief Park the bridge and/or callers that this channel is in
+	 *
+	 * \param parker The bridge_channel parking the bridge
+	 * \param exten Optional. The extension the channel or bridge was parked at if the
+	 * call succeeds.
+	 * \param length Optional. If \c exten is specified, the size of the buffer.
+	 *
+	 * \note This is safe to be called outside of the \ref AstBridging Bridging API.
+	 *
+	 * \retval 0 on success
+	 * \retval non-zero on error
+	 */
+	int (* parking_park_call)(struct ast_bridge_channel *parker, char *exten, size_t length);
+
+	/*!
+	 * \brief Perform a blind transfer to a parking extension.
+	 *
+	 * \param parker The \ref bridge_channel object that is initiating the parking
+	 * \param context The context to blind transfer to
+	 * \param exten The extension to blind transfer to
+	 *
+	 * \note If the bridge \ref parker is in has more than one other occupant, the entire
+	 * bridge will be parked using a Local channel
+	 *
+	 * \note This is safe to be called outside of the \ref AstBridging Bridging API.
+	 *
+	 * \retval 0 on success
+	 * \retval non-zero on error
+	 */
+	int (* parking_blind_transfer_park)(struct ast_bridge_channel *parker, const char *context, const char *exten);
+
+	/*!
+	 * \brief Perform a direct park on a channel in a bridge.
+	 *
+	 * \param parkee The channel in the bridge to be parked.
+	 * \param parkee_uuid The UUID of the channel being packed.
+	 * \param parker_uuid The UUID of the channel performing the park.
+	 * \param app_data Data to pass to the Park application
+	 *
+	 * \note This must be called within the context of the \ref AstBridging Bridging API.
+	 * External entities should not call this method directly, but should instead use
+	 * the direct call parking method or the blind transfer method.
+	 *
+	 * \retval 0 on success
+	 * \retval non-zero on error
+	 */
+	int (* parking_park_bridge_channel)(struct ast_bridge_channel *parkee, const char *parkee_uuid, const char *parker_uuid, const char *app_data);
+};
+
+/*!
+ * \brief Obtain the current parking provider
+ *
+ * \retval NULL if no provider exists
+ * \retval an ao2 ref counted object of the existing provider's function table
+ */
+struct ast_parking_bridge_feature_fn_table *ast_parking_get_bridge_features(void);
+
+/*!
+ * \brief Register a parking provider
+ *
+ * \param fn_table The \ref ast_parking_bridge_feature_fn_table to register
  *
  * \retval 0 on success
- * \retval -1 on failure
- */
-int ast_park_blind_xfer(struct ast_bridge_channel *parker, struct ast_exten *park_exten);
-
-typedef void (*ast_bridge_channel_park_fn)(struct ast_bridge_channel *parkee, const char *parkee_uuid,
-	const char *parker_uuid, const char *app_data);
-
-/*!
- * \brief Install a function for ast_bridge_channel_park
- * \since 12
- *
- * \param bridge_channel_park_func function callback to use for ast_bridge_channel_park
- */
-void ast_install_bridge_channel_park_func(ast_bridge_channel_park_fn bridge_channel_park_func);
-
-/*!
- * \brief Uninstall the ast_bridge_channel_park function callback
- * \since 12
- */
-void ast_uninstall_bridge_channel_park_func(void);
-
-
-/*!
- * \brief Determines whether a certain extension is a park application extension or not.
- * \since 12
- *
- * \param exten_str string representation of the extension sought
- * \param chan channel the extension is sought for
- * \param context context the extension is sought from
- *
- * \retval pointer to the extension if the extension is a park extension
- * \retval NULL if the extension was not a park extension
- */
-struct ast_exten *ast_get_parking_exten(const char *exten_str, struct ast_channel *chan, const char *context);
+ * \retval -1 on error
+ */
+int ast_parking_register_bridge_features(struct ast_parking_bridge_feature_fn_table *fn_table);
+
+/*!
+ * \brief Unregister the current parking provider
+ *
+ * \param The module name of the provider to unregister
+ *
+ * \retval 0 if the parking provider \c module_name was unregsistered
+ * \retval -1 on error
+ */
+int ast_parking_unregister_bridge_features(const char *module_name);

Modified: trunk/main/bridge.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridge.c?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/main/bridge.c (original)
+++ trunk/main/bridge.c Thu Aug  1 15:55:17 2013
@@ -3781,32 +3781,31 @@
 	return transferee;
 }
 
-enum try_parking_result {
-	PARKING_SUCCESS,
-	PARKING_FAILURE,
-	PARKING_NOT_APPLICABLE,
-};
-
-static enum try_parking_result try_parking(struct ast_channel *transferer, const char *exten, const char *context)
+static enum ast_transfer_result try_parking(struct ast_channel *transferer, const char *context, const char *exten)
 {
 	RAII_VAR(struct ast_bridge_channel *, transferer_bridge_channel, NULL, ao2_cleanup);
-	struct ast_exten *parking_exten;
+	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, parking_provider,
+		ast_parking_get_bridge_features(),
+		ao2_cleanup);
+
+	if (!parking_provider) {
+		return AST_BRIDGE_TRANSFER_FAIL;
+	}
 
 	ast_channel_lock(transferer);
 	transferer_bridge_channel = ast_channel_get_bridge_channel(transferer);
 	ast_channel_unlock(transferer);
 
 	if (!transferer_bridge_channel) {
-		return PARKING_FAILURE;
-	}
-
-	parking_exten = ast_get_parking_exten(exten, NULL, context);
-	if (parking_exten) {
-		return ast_park_blind_xfer(transferer_bridge_channel, parking_exten) == 0 ?
-			PARKING_SUCCESS : PARKING_FAILURE;
-	}
-
-	return PARKING_NOT_APPLICABLE;
+		return AST_BRIDGE_TRANSFER_FAIL;
+	}
+
+	if (parking_provider->parking_blind_transfer_park(transferer_bridge_channel,
+		context, exten)) {
+		return AST_BRIDGE_TRANSFER_FAIL;
+	}
+
+	return AST_BRIDGE_TRANSFER_SUCCESS;
 }
 
 /*!
@@ -3883,7 +3882,6 @@
 	RAII_VAR(struct ast_channel *, transferee, NULL, ast_channel_cleanup);
 	int do_bridge_transfer;
 	int transfer_prohibited;
-	enum try_parking_result parking_result;
 	enum ast_transfer_result transfer_result;
 
 	bridge = acquire_bridge(transferer);
@@ -3902,17 +3900,9 @@
 	/* Take off hold if they are on hold. */
 	ast_bridge_channel_write_unhold(bridge_channel);
 
-	parking_result = try_parking(transferer, exten, context);
-	switch (parking_result) {
-	case PARKING_SUCCESS:
-		transfer_result = AST_BRIDGE_TRANSFER_SUCCESS;
+	transfer_result = try_parking(transferer, context, exten);
+	if (transfer_result == AST_BRIDGE_TRANSFER_SUCCESS) {
 		goto publish;
-	case PARKING_FAILURE:
-		transfer_result = AST_BRIDGE_TRANSFER_FAIL;
-		goto publish;
-	case PARKING_NOT_APPLICABLE:
-	default:
-		break;
 	}
 
 	{

Modified: trunk/main/bridge_channel.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/bridge_channel.c?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/main/bridge_channel.c (original)
+++ trunk/main/bridge_channel.c Thu Aug  1 15:55:17 2013
@@ -757,9 +757,22 @@
  */
 static void bridge_channel_park(struct ast_bridge_channel *bridge_channel, struct bridge_park *payload)
 {
-	ast_bridge_channel_park(bridge_channel, payload->parkee_uuid,
+	RAII_VAR(struct ast_parking_bridge_feature_fn_table *, parking_provider,
+		ast_parking_get_bridge_features(),
+		ao2_cleanup);
+
+	if (!parking_provider) {
+		ast_log(AST_LOG_WARNING, "Unable to park %s: No parking provider loaded!\n",
+			ast_channel_name(bridge_channel->chan));
+		return;
+	}
+
+	if (parking_provider->parking_park_bridge_channel(bridge_channel, payload->parkee_uuid,
 		&payload->parkee_uuid[payload->parker_uuid_offset],
-		payload->app_data_offset ? &payload->parkee_uuid[payload->app_data_offset] : NULL);
+		payload->app_data_offset ? &payload->parkee_uuid[payload->app_data_offset] : NULL)) {
+		ast_log(AST_LOG_WARNING, "Error occurred while parking %s\n",
+			ast_channel_name(bridge_channel->chan));
+	}
 }
 
 /*!

Modified: trunk/main/features.c
URL: http://svnview.digium.com/svn/asterisk/trunk/main/features.c?view=diff&rev=396028&r1=396027&r2=396028
==============================================================================
--- trunk/main/features.c (original)
+++ trunk/main/features.c Thu Aug  1 15:55:17 2013
@@ -470,19 +470,10 @@
 /*! \brief The configured parking lots container. Always at least one  - the default parking lot */
 static struct ao2_container *parkinglots;
 
-/*!
- * \brief Default parking lot.
- * \note Holds a parkinglot reference.
- * \note Will not be NULL while running.
- */
-static struct ast_parkinglot *default_parkinglot;
-
 /*! Force a config reload to reload regardless of config file timestamp. */
 #ifdef TEST_FRAMEWORK
 static int force_reload_load;
 #endif
-
-static int parkeddynamic = 0;                              /*!< Enable creation of parkinglots dynamically */
 
 /*!
  * \brief Context for parking dialback to parker.
@@ -496,8 +487,6 @@
 
 /*! Ensure that features.conf reloads on one thread at a time. */
 AST_MUTEX_DEFINE_STATIC(features_reload_lock);
-
-static int adsipark;
 
 static char *registrar = "features";		   /*!< Registrar for operations */
 
@@ -511,9 +500,6 @@
 	AST_APP_ARG(pl_name);		/*!< Parking lot name to use if present. */
 	AST_APP_ARG(dummy);			/*!< Place to put any remaining args string. */
 	);
-
-/* module and CLI command definitions */
-static const char *parkcall = "Park";
 
 static pthread_t parking_thread;
 struct ast_dial_features {
@@ -670,50 +656,7 @@
 }
 
 /* Forward declarations */
-static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
 static void parkinglot_unref(struct ast_parkinglot *parkinglot);
-static struct ast_parkinglot *find_parkinglot(const char *name);
-static struct ast_parkinglot *create_parkinglot(const char *name);
-static struct ast_parkinglot *copy_parkinglot(const char *name, const struct ast_parkinglot *parkinglot);
-static int parkinglot_activate(struct ast_parkinglot *parkinglot);
-static int play_message_on_chan(struct ast_channel *play_to, struct ast_channel *other, const char *msg, const char *audiofile);
-
-/*!
- * \internal
- * \brief Get the parking extension if it exists.
- *
- * \param exten_str Parking extension to see if exists.
- * \param chan Channel to autoservice while looking for exten.  (Could be NULL)
- * \param context Parking context to look in for exten.
- *
- * \retval exten on success.
- * \retval NULL on error or exten does not exist.
- */
-static struct ast_exten *get_parking_exten(const char *exten_str, struct ast_channel *chan, const char *context)
-{
-	struct ast_exten *exten;
-	struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
-	const char *app_at_exten;
-
-	ast_debug(4, "Checking if %s@%s is a parking exten\n", exten_str, context);
-	exten = pbx_find_extension(chan, NULL, &q, context, exten_str, 1, NULL, NULL,
-		E_MATCH);
-	if (!exten) {
-		return NULL;
-	}
-
-	app_at_exten = ast_get_extension_app(exten);
-	if (!app_at_exten || strcasecmp(parkcall, app_at_exten)) {
-		return NULL;
-	}
-
-	return exten;
-}
-
-int ast_parking_ext_valid(const char *exten_str, struct ast_channel *chan, const char *context)
-{
-	return get_parking_exten(exten_str, chan, context) ? 1 : 0;
-}
 
 struct ast_bridge_thread_obj
 {
@@ -754,46 +697,6 @@
 	.type = "Channel appdata datastore",
 	.destroy = ast_free_ptr,
 };
-
-/*!
- * \brief Announce call parking by ADSI
- * \param chan .
- * \param parkingexten .
- * Create message to show for ADSI, display message.
- * \retval 0 on success.
- * \retval -1 on failure.
- */
-static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
-{
-	int res;
-	int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
-	char tmp[256];
-	char *message[5] = {NULL, NULL, NULL, NULL, NULL};
-
-	snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
-	message[0] = tmp;
-	res = ast_adsi_load_session(chan, NULL, 0, 1);
-	if (res == -1)
-		return res;
-	return ast_adsi_print(chan, message, justify, 1);
-}
-
-/*!
- * \brief Find parking lot name from channel
- * \note Channel needs to be locked while the returned string is in use.
- */
-static const char *findparkinglotname(struct ast_channel *chan)
-{
-	const char *name;
-
-	/* The channel variable overrides everything */
-	name = pbx_builtin_getvar_helper(chan, "PARKINGLOT");
-	if (!name && !ast_strlen_zero(ast_channel_parkinglot(chan))) {
-		/* Use the channel's parking lot. */
-		name = ast_channel_parkinglot(chan);
-	}
-	return name;
-}
 
 /*! \brief Notify metermaids that we've changed an extension */
 static void notify_metermaids(const char *exten, char *context, enum ast_device_state state)
@@ -854,705 +757,6 @@
 	/*! \brief Parkinglot to be parked in */
 	struct ast_parkinglot *parkinglot;
 };
-
-/*!
- * \internal
- * \brief Create a dynamic parking lot.
- *
- * \param name Dynamic parking lot name to create.
- * \param chan Channel to get dynamic parking lot parameters.
- *
- * \retval parkinglot on success.
- * \retval NULL on error.
- */
-static struct ast_parkinglot *create_dynamic_parkinglot(const char *name, struct ast_channel *chan)
-{
-	const char *dyn_context;
-	const char *dyn_exten;
-	const char *dyn_range;
-	const char *template_name;
-	struct ast_parkinglot *template_parkinglot = NULL;
-	struct ast_parkinglot *parkinglot;
-	int dyn_start;
-	int dyn_end;
-
-	ast_channel_lock(chan);
-	template_name = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNAMIC"), ""));
-	dyn_context = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNCONTEXT"), ""));
-	dyn_exten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNEXTEN"), ""));
-	dyn_range = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGDYNPOS"), ""));
-	ast_channel_unlock(chan);
-
-	if (!ast_strlen_zero(template_name)) {
-		template_parkinglot = find_parkinglot(template_name);
-		if (!template_parkinglot) {
-			ast_debug(1, "PARKINGDYNAMIC lot %s does not exist.\n",
-				template_name);
-		} else if (template_parkinglot->cfg.is_invalid) {
-			ast_debug(1, "PARKINGDYNAMIC lot %s has invalid config.\n",
-				template_name);
-			parkinglot_unref(template_parkinglot);
-			template_parkinglot = NULL;
-		}
-	}
-	if (!template_parkinglot) {
-		template_parkinglot = parkinglot_addref(default_parkinglot);
-		ast_debug(1, "Using default parking lot for template\n");
-	}
-
-	parkinglot = copy_parkinglot(name, template_parkinglot);
-	if (!parkinglot) {
-		ast_log(LOG_ERROR, "Could not build dynamic parking lot!\n");
-	} else {
-		/* Configure the dynamic parking lot. */
-		if (!ast_strlen_zero(dyn_context)) {
-			ast_copy_string(parkinglot->cfg.parking_con, dyn_context,
-				sizeof(parkinglot->cfg.parking_con));
-		}
-		if (!ast_strlen_zero(dyn_exten)) {
-			ast_copy_string(parkinglot->cfg.parkext, dyn_exten,
-				sizeof(parkinglot->cfg.parkext));
-		}
-		if (!ast_strlen_zero(dyn_range)) {
-			if (sscanf(dyn_range, "%30d-%30d", &dyn_start, &dyn_end) != 2) {
-				ast_log(LOG_WARNING,
-					"Format for parking positions is a-b, where a and b are numbers\n");
-			} else if (dyn_end < dyn_start || dyn_start <= 0 || dyn_end <= 0) {
-				ast_log(LOG_WARNING,
-					"Format for parking positions is a-b, where a <= b\n");
-			} else {
-				parkinglot->cfg.parking_start = dyn_start;
-				parkinglot->cfg.parking_stop = dyn_end;
-			}
-		}
-
-		/*
-		 * Sanity check for dynamic parking lot configuration.
-		 *
-		 * XXX It may be desirable to instead check if the dynamic
-		 * parking lot overlaps any existing lots like what is done for
-		 * a reload.
-		 */
-		if (!strcmp(parkinglot->cfg.parking_con, template_parkinglot->cfg.parking_con)) {
-			if (!strcmp(parkinglot->cfg.parkext, template_parkinglot->cfg.parkext)
-				&& parkinglot->cfg.parkext_exclusive) {
-				ast_log(LOG_WARNING,
-					"Parking lot '%s' conflicts with template parking lot '%s'!\n"
-					"Change either PARKINGDYNCONTEXT or PARKINGDYNEXTEN.\n",
-					parkinglot->name, template_parkinglot->name);
-			}
-			if ((template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_start
-					&& parkinglot->cfg.parking_start <= template_parkinglot->cfg.parking_stop)
-				|| (template_parkinglot->cfg.parking_start <= parkinglot->cfg.parking_stop
-					&& parkinglot->cfg.parking_stop <= template_parkinglot->cfg.parking_stop)
-				|| (parkinglot->cfg.parking_start < template_parkinglot->cfg.parking_start
-					&& template_parkinglot->cfg.parking_stop < parkinglot->cfg.parking_stop)) {
-				ast_log(LOG_WARNING,
-					"Parking lot '%s' parking spaces overlap template parking lot '%s'!\n"
-					"Change PARKINGDYNPOS.\n",
-					parkinglot->name, template_parkinglot->name);
-			}
-		}
-
-		parkinglot_activate(parkinglot);
-		ao2_link(parkinglots, parkinglot);
-	}
-	parkinglot_unref(template_parkinglot);
-
-	return parkinglot;
-}
-
-/*!
- * \internal
- * \brief Abort parking a call that has not completed parking yet.
- *
- * \param pu Parked user item to clean up.
- *
- * \note The parking lot parkings list is locked on entry.
- *
- * \return Nothing
- */
-static void park_space_abort(struct parkeduser *pu)
-{
-	struct ast_parkinglot *parkinglot;
-
-	parkinglot = pu->parkinglot;
-
-	/* Put back the parking space just allocated. */
-	--parkinglot->next_parking_space;
-
-	AST_LIST_REMOVE(&parkinglot->parkings, pu, list);
-
-	AST_LIST_UNLOCK(&parkinglot->parkings);
-	parkinglot_unref(parkinglot);
-	ast_free(pu);
-}
-
-/*!
- * \internal
- * \brief Reserve a parking space in a parking lot for a call being parked.
- *
- * \param park_me Channel being parked.
- * \param parker Channel parking the call.
- * \param args Optional additional parking options when parking a call.
- *
- * \return Parked call descriptor or NULL if failed.
- * \note The parking lot list is locked if successful.
- */
-static struct parkeduser *park_space_reserve(struct ast_channel *park_me, struct ast_channel *parker, struct ast_park_call_args *args)
-{
-	struct parkeduser *pu;
-	int i;
-	int parking_space = -1;
-	const char *parkinglotname;
-	const char *parkingexten;
-	struct parkeduser *cur;
-	struct ast_parkinglot *parkinglot = NULL;
-
-	if (args->parkinglot) {
-		parkinglot = parkinglot_addref(args->parkinglot);
-		parkinglotname = parkinglot->name;
-	} else {
-		if (parker) {
-			parkinglotname = findparkinglotname(parker);
-		} else { /* parker was NULL, check park_me (ParkAndAnnounce / res_agi) */
-			parkinglotname = findparkinglotname(park_me);
-		}
-		if (!ast_strlen_zero(parkinglotname)) {
-			parkinglot = find_parkinglot(parkinglotname);
-		} else {
-			/* Parking lot is not specified, so use the default parking lot. */
-			ast_debug(4, "This could be an indication channel driver needs updating, using default lot.\n");
-			parkinglot = parkinglot_addref(default_parkinglot);
-		}
-	}
-
-	/* Dynamically create parkinglot */
-	if (!parkinglot && parkeddynamic && !ast_strlen_zero(parkinglotname)) {
-		parkinglot = create_dynamic_parkinglot(parkinglotname, park_me);
-	}
-
-	if (!parkinglot) {
-		ast_log(LOG_WARNING, "Parking lot not available to park %s.\n", ast_channel_name(park_me));
-		return NULL;
-	}
-
-	ast_debug(1, "Parking lot: %s\n", parkinglot->name);
-	if (parkinglot->disabled || parkinglot->cfg.is_invalid) {
-		ast_log(LOG_WARNING, "Parking lot %s is not in a useable state.\n",
-			parkinglot->name);
-		parkinglot_unref(parkinglot);
-		return NULL;
-	}
-
-	/* Allocate memory for parking data */
-	if (!(pu = ast_calloc(1, sizeof(*pu)))) {
-		parkinglot_unref(parkinglot);
-		return NULL;
-	}
-
-	/* Lock parking list */
-	AST_LIST_LOCK(&parkinglot->parkings);
-
-	/* Check for channel variable PARKINGEXTEN */
-	parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(park_me, "PARKINGEXTEN"), ""));
-	if (!ast_strlen_zero(parkingexten)) {
-		/*!
-		 * \note The API forces us to specify a numeric parking slot, even
-		 * though the architecture would tend to support non-numeric extensions

[... 1559 lines stripped ...]



More information about the asterisk-commits mailing list