[svn-commits] mmichelson: branch group/CCSS r224441 - in /team/group/CCSS: include/asterisk...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Sun Oct 18 16:23:35 CDT 2009


Author: mmichelson
Date: Sun Oct 18 16:23:32 2009
New Revision: 224441

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=224441
Log:
Make the cc_interface, cc_interface_tree, and cc_tree_item
private to ccss.c


Modified:
    team/group/CCSS/include/asterisk/ccss.h
    team/group/CCSS/main/ccss.c

Modified: team/group/CCSS/include/asterisk/ccss.h
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/include/asterisk/ccss.h?view=diff&rev=224441&r1=224440&r2=224441
==============================================================================
--- team/group/CCSS/include/asterisk/ccss.h (original)
+++ team/group/CCSS/include/asterisk/ccss.h Sun Oct 18 16:23:32 2009
@@ -500,54 +500,6 @@
 	char name[1];
 };
 
-/*!
- * \brief An item in a CC interface tree.
- *
- * These are the individual items in an interface tree.
- * The key difference between this structure and the ast_cc_interface
- * is that this structure contains data which is intrinsic to the item's
- * placement in the tree, such as who its parent is.
- */
-struct ast_cc_tree_item {
-	/* Information regarding the interface.
-	 */
-	struct ast_cc_interface *interface;
-	/* Every interface has an id associated with it. Think of
-	 * it like a "primary key"
-	 */
-	unsigned int id;
-	/* Who is this interface's parent interface? The "root" of
-	 * the tree will have 0 for this. Everyone else will have at
-	 * least 1 as their parent_id.
-	 */
-	unsigned int parent_id;
-	/* What service was offered by the endpoint. Note that
-	 * this field is completely irrelevant for ast_cc_tree_items
-	 * representing dialplan extensions. 
-	 */
-	enum ast_cc_service_type service_offered;
-	/*!
-	 * Name that should be used to recall specified interface
-	 *
-	 * When issuing a CC recall, some technologies will require
-	 * that a name other than the device name is dialed. For instance,
-	 * with SIP, a specific URI will be used which chan_sip will be able
-	 * to recognize as being a CC recall. Similarly, ISDN will need a specific
-	 * dial string to know that the call is a recall.
-	 */
-	char *dialable_name;
-	AST_LIST_ENTRY(ast_cc_tree_item) next;
-};
-
-/*!
- * \brief The "tree" of interfaces that is dialed.
- *
- * It is reference counted since several threads may need
- * to use it, and it may last beyond the lifetime of a single
- * thread.
- */
-AST_LIST_HEAD(ast_cc_interface_tree, ast_cc_tree_item);
-
 /* END TREE STRUCTURES AND API FOR APP_DIAL'S USE */
 
 /*!

Modified: team/group/CCSS/main/ccss.c
URL: http://svnview.digium.com/svn/asterisk/team/group/CCSS/main/ccss.c?view=diff&rev=224441&r1=224440&r2=224441
==============================================================================
--- team/group/CCSS/main/ccss.c (original)
+++ team/group/CCSS/main/ccss.c Sun Oct 18 16:23:32 2009
@@ -617,221 +617,6 @@
 
 #define cc_ref(obj, debug) ({ao2_t_ref((obj), +1, (debug)); (obj);})
 #define cc_unref(obj, debug) ({ao2_t_ref((obj), -1, (debug)); NULL;})
-
-/* Generic agent callbacks */
-static int cc_generic_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan);
-static int cc_generic_agent_start_offer_timer(struct ast_cc_agent *agent);
-static int cc_generic_agent_stop_offer_timer(struct ast_cc_agent *agent);
-static void cc_generic_agent_ack(struct ast_cc_agent *agent);
-static enum ast_device_state cc_generic_agent_status_request(struct ast_cc_agent *agent);
-static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent);
-static int cc_generic_agent_stop_monitoring(struct ast_cc_agent *agent);
-static int cc_generic_agent_recall(struct ast_cc_agent *agent);
-static void cc_generic_agent_destructor(struct ast_cc_agent *agent);
-
-static struct ast_cc_agent_callbacks generic_agent_callbacks = {
-	.type = "generic",
-	.init = cc_generic_agent_init,
-	.start_offer_timer = cc_generic_agent_start_offer_timer,
-	.stop_offer_timer = cc_generic_agent_stop_offer_timer,
-	.ack = cc_generic_agent_ack,
-	.status_request = cc_generic_agent_status_request,
-	.start_monitoring = cc_generic_agent_start_monitoring,
-	.stop_monitoring = cc_generic_agent_stop_monitoring,
-	.recall = cc_generic_agent_recall,
-	.destructor = cc_generic_agent_destructor,
-};
-
-struct cc_generic_agent_pvt {
-	/*!
-	 * Subscription to device state
-	 *
-	 * Used in the CC_CALLER_BUSY state. The
-	 * generic agent will subscribe to the
-	 * device state of the caller in order to
-	 * determine when we may move on
-	 */
-	struct ast_event_sub *sub;
-	/*!
-	 * Scheduler id of offer timer.
-	 */
-	int offer_timer_id;
-};
-
-static int cc_generic_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
-{
-	struct cc_generic_agent_pvt *generic_pvt = ast_calloc(1, sizeof(*generic_pvt));
-
-	if (!generic_pvt) {
-		return -1;
-	}
-
-	generic_pvt->offer_timer_id = -1;
-	agent->private_data = generic_pvt;
-	ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
-	return 0;
-}
-
-static int offer_timer_expire(const void *data)
-{
-	const struct ast_cc_agent *agent = data;
-	struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
-	ast_log(LOG_NOTICE, "Queuing change request because offer timer has expired.\n");
-	agent_pvt->offer_timer_id = -1;
-	ast_cc_request_state_change(CC_FAILED, agent->core_id, "Generic agent offer timer expired");
-	return 0;
-}
-
-static int cc_generic_agent_start_offer_timer(struct ast_cc_agent *agent)
-{
-	int when;
-	int sched_id;
-	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
-
-	ast_assert(cc_sched_thread != NULL);
-	ast_assert(agent->cc_params != NULL);
-
-	when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
-	ast_log(LOG_NOTICE, "About to schedule timer expiration for %d ms\n", when);
-	if ((sched_id = ast_sched_thread_add(cc_sched_thread, when, offer_timer_expire, agent)) == -1) {
-		return -1;
-	}
-	generic_pvt->offer_timer_id = sched_id;
-	return 0;
-}
-
-static int cc_generic_agent_stop_offer_timer(struct ast_cc_agent *agent)
-{
-	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
-
-	if (generic_pvt->offer_timer_id != -1) {
-		ast_sched_thread_del(cc_sched_thread, generic_pvt->offer_timer_id);
-		generic_pvt->offer_timer_id = -1;
-	}
-	return 0;
-}
-
-static void cc_generic_agent_ack(struct ast_cc_agent *agent)
-{
-	/* The generic agent doesn't have to do anything special to
-	 * acknowledge a CC request. Just return.
-	 */
-	return;
-}
-
-static enum ast_device_state cc_generic_agent_status_request(struct ast_cc_agent *agent)
-{
-	return ast_device_state(agent->interface);
-}
-
-static void generic_devstate_cb(const struct ast_event *event, void *userdata)
-{
-	struct ast_cc_agent *agent = userdata;
-	struct ast_str *str = ast_str_alloca(128);
-	ast_str_set(&str, 0, "%s is no longer busy\n", agent->interface);
-	ast_cc_request_state_change(CC_ACTIVE, agent->core_id, ast_str_buffer(str));
-}
-
-static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent)
-{
-	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
-	struct ast_str *str = ast_str_alloca(128);
-
-	ast_assert(generic_pvt->sub == NULL);
-	ast_str_set(&str, 0, "Starting to monitor %s device state since it is busy\n", agent->interface);
-
-	if (!(generic_pvt->sub = ast_event_subscribe(
-			AST_EVENT_DEVICE_STATE, generic_devstate_cb, ast_str_buffer(str), agent, 
-			AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, agent->interface,
-			AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, AST_DEVICE_NOT_INUSE,
-			AST_EVENT_IE_END))) {
-		return -1;
-	}
-	return 0;
-}
-
-static int cc_generic_agent_stop_monitoring(struct ast_cc_agent *agent)
-{
-	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
-	
-	ast_assert(generic_pvt->sub != NULL);
-
-	generic_pvt->sub = ast_event_unsubscribe(generic_pvt->sub);
-	return 0;
-}
-
-static void *generic_recall(void *data)
-{
-	struct ast_cc_agent *agent = data;
-	char *interface = ast_strdupa(agent->interface);
-	char *tech;
-	char *target;
-	int reason;
-	struct ast_channel *chan;
-	struct ast_cc_tree_item *tree_item = AST_LIST_FIRST(agent->interface_tree);
-	char *full_extension = ast_strdupa(tree_item->interface->name);
-	char *context;
-	char *exten;
-	const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
-	tech = interface;
-	if ((target = strchr(interface, '/'))) {
-		*target++ = '\0';
-	}
-	if (!(chan = ast_request_and_dial(tech, AST_FORMAT_SLINEAR, NULL, target, 20000, &reason, NULL, NULL))) {
-		/* Hmm, no channel. Sucks for you, bud.
-		 */
-		ast_log(LOG_NOTICE, "Failed to call back %s for reason %d\n", agent->interface, reason);
-		ast_cc_request_state_change(CC_FAILED, agent->core_id, "Failed to call back interface\n");
-		return NULL;
-	}
-	if (!ast_strlen_zero(callback_macro)) {
-		ast_log(LOG_NOTICE, "There's a callback macro configured\n");
-		if (ast_app_run_macro(NULL, chan, callback_macro, NULL)) {
-			ast_cc_request_state_change(CC_FAILED, agent->core_id, "Callback macro failed. Maybe a hangup?");
-			ast_hangup(chan);
-			return NULL;
-		}
-	}
-	/* We have a channel. It's time now to set up the datastore of recalled CC interfaces.
-	 * This will be a common task for all recall functions. If it were possible, I'd have
-	 * the core do it automatically, but alas I cannot. Instead, I will provide a public
-	 * function to do so.
-	 */
-	ast_setup_cc_recall_datastore(chan, agent);
-	ast_set_cc_interfaces_chanvar(chan, full_extension);
-	/* Now we can bust apart the outbound name so that the PBX will run. */
-	exten = full_extension;
-	if ((context = strchr(full_extension, '@'))) {
-		*context++ = '\0';
-	}
-	ast_copy_string(chan->exten, exten, sizeof(chan->exten));
-	ast_copy_string(chan->context, context, sizeof(chan->context));
-	chan->priority = 1;
-	ast_pbx_start(chan);
-	return NULL;
-}
-
-static int cc_generic_agent_recall(struct ast_cc_agent *agent)
-{
-	pthread_t clotho;
-	ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
-	return 0;
-}
-
-static void cc_generic_agent_destructor(struct ast_cc_agent *agent)
-{
-	struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
-	if (!agent_pvt) {
-		return;
-	}
-	
-	if (agent_pvt->sub) {
-		agent_pvt->sub = ast_event_unsubscribe(agent_pvt->sub);
-	}
-
-	ast_free(agent_pvt);
-}
-
 static void destroy_link(struct ast_cc_monitor_link *link)
 {
 	ast_log(LOG_NOTICE, "Destroying link with parent %s and child %s\n",
@@ -1255,14 +1040,54 @@
 	ast_free(gen_mon_pvt);
 	return;
 }
-#if 0
-static int print_debug(void *obj, void *args, int flags)
-{
-	struct ast_cc_monitor *monitor = obj;
-	ast_log(LOG_NOTICE, "%s is in the container\n", monitor->interface->name);
-	return 0;
-}
-#endif
+
+/*!
+ * \brief An item in a CC interface tree.
+ *
+ * These are the individual items in an interface tree.
+ * The key difference between this structure and the ast_cc_interface
+ * is that this structure contains data which is intrinsic to the item's
+ * placement in the tree, such as who its parent is.
+ */
+struct cc_tree_item {
+	/* Information regarding the interface.
+	 */
+	struct ast_cc_interface *interface;
+	/* Every interface has an id associated with it. Think of
+	 * it like a "primary key"
+	 */
+	unsigned int id;
+	/* Who is this interface's parent interface? The "root" of
+	 * the tree will have 0 for this. Everyone else will have at
+	 * least 1 as their parent_id.
+	 */
+	unsigned int parent_id;
+	/* What service was offered by the endpoint. Note that
+	 * this field is completely irrelevant for cc_tree_items
+	 * representing dialplan extensions. 
+	 */
+	enum ast_cc_service_type service_offered;
+	/*!
+	 * Name that should be used to recall specified interface
+	 *
+	 * When issuing a CC recall, some technologies will require
+	 * that a name other than the device name is dialed. For instance,
+	 * with SIP, a specific URI will be used which chan_sip will be able
+	 * to recognize as being a CC recall. Similarly, ISDN will need a specific
+	 * dial string to know that the call is a recall.
+	 */
+	char *dialable_name;
+	AST_LIST_ENTRY(cc_tree_item) next;
+};
+
+/*!
+ * \brief The "tree" of interfaces that is dialed.
+ *
+ * It is reference counted since several threads may need
+ * to use it, and it may last beyond the lifetime of a single
+ * thread.
+ */
+AST_LIST_HEAD(ast_cc_interface_tree, cc_tree_item);
 
 static void cc_interface_destroy(void *data)
 {
@@ -1271,7 +1096,7 @@
 	ast_cc_config_params_destroy(interface->config_params);
 }
 
-static void cc_tree_item_destroy(struct ast_cc_tree_item *tree_item)
+static void cc_tree_item_destroy(struct cc_tree_item *tree_item)
 {
 	cc_unref(tree_item->interface, "Unreffing tree's reference to interface");
 	ast_free(tree_item->dialable_name);
@@ -1281,7 +1106,7 @@
 static void cc_interface_tree_destroy(void *data)
 {
 	struct ast_cc_interface_tree *cc_interface_tree = data;
-	struct ast_cc_tree_item *tree_item;
+	struct cc_tree_item *tree_item;
 	while ((tree_item = AST_LIST_REMOVE_HEAD(cc_interface_tree, next))) {
 		cc_tree_item_destroy(tree_item);
 	}
@@ -1306,12 +1131,12 @@
 	 * This value serves a dual-purpose. When dial starts, if the
 	 * dialed_cc_interfaces datastore currently exists on the calling
 	 * channel, then the dial_parent_id will serve as a means of
-	 * letting the new extension ast_cc_tree_item we create know
+	 * letting the new extension cc_tree_item we create know
 	 * who his parent is. This value will be the extension
-	 * ast_cc_tree_item that dialed the local channel that resulted
+	 * cc_tree_item that dialed the local channel that resulted
 	 * in the new Dial app being called.
 	 *
-	 * In addition, once an extension ast_cc_tree_item is created,
+	 * In addition, once an extension cc_tree_item is created,
 	 * the dial_parent_id will be changed to the id of that newly
 	 * created interface. This way, device interfaces created from
 	 * receiving AST_CONTROL_CC frames can use this field to determine
@@ -1456,19 +1281,19 @@
  *
  * When app_dial starts, this function is called in order to set up the
  * information about the extension in which this Dial is occurring. Any
- * devices dialed will have this particular ast_cc_tree_item as a parent.
+ * devices dialed will have this particular cc_tree_item as a parent.
  *
  * \param exten Extension from which Dial is occurring
  * \param context Context to which exten belongs
  * \param parent_id What should we set the parent_id of this interface to?
  * \retval NULL Memory allocation failure
- * \retval non-NULL The newly-created ast_cc_tree_item for the extension
+ * \retval non-NULL The newly-created cc_tree_item for the extension
  */
-static struct ast_cc_tree_item *cc_extension_tree_item_init(const char * const exten, const char * const context, const unsigned int parent_id)
+static struct cc_tree_item *cc_extension_tree_item_init(const char * const exten, const char * const context, const unsigned int parent_id)
 {
 	struct ast_str *str = ast_str_alloca(2 * AST_MAX_EXTENSION);
 	struct ast_cc_interface *cc_interface;
-	struct ast_cc_tree_item *tree_item;
+	struct cc_tree_item *tree_item;
 
 	ast_str_set(&str, 0, "%s@%s", exten, context);
 
@@ -1508,7 +1333,7 @@
  */
 static int cc_interfaces_datastore_init(struct ast_channel *chan) {
 	struct dialed_cc_interfaces *interfaces;
-	struct ast_cc_tree_item *tree_item;
+	struct cc_tree_item *tree_item;
 	struct ast_datastore *dial_cc_datastore;
 
 	/*XXX This may be a bit controversial. In an attempt to not allocate
@@ -1559,7 +1384,7 @@
 }
 
 /*!
- * \brief Allocate and intitialize a device ast_cc_tree_item
+ * \brief Allocate and intitialize a device cc_tree_item
  *
  * For all intents and purposes, this is the same as
  * cc_extension_tree_item_init, except that there is only
@@ -1581,10 +1406,10 @@
  * \retval NULL Memory allocation failure
  * \retval non-NULL The new ast_cc_interface created.
  */
-static struct ast_cc_tree_item *cc_device_tree_item_init(const char * const name, const int parent_id, const struct ast_control_cc_payload *cc_data)
+static struct cc_tree_item *cc_device_tree_item_init(const char * const name, const int parent_id, const struct ast_control_cc_payload *cc_data)
 {
 	struct ast_cc_interface *cc_interface;
-	struct ast_cc_tree_item *tree_item;
+	struct cc_tree_item *tree_item;
 	size_t name_len = strlen(name);
 
 	if (!(cc_interface = ao2_alloc(sizeof(*cc_interface) + name_len, cc_interface_destroy))) {
@@ -1621,7 +1446,7 @@
  * from an outbound channel.
  *
  * This function will call cc_device_tree_item_init to
- * create the new ast_cc_tree_item for the device from which
+ * create the new cc_tree_item for the device from which
  * we read the frame. In addition, the new device will be added
  * to the interface tree on the dialed_cc_interfaces datastore
  * on the inbound channel.
@@ -1639,7 +1464,7 @@
 {
 	char device_name[AST_CHANNEL_NAME];
 	char *dash;
-	struct ast_cc_tree_item *tree_item;
+	struct cc_tree_item *tree_item;
 	struct ast_datastore *cc_datastore;
 	struct dialed_cc_interfaces *cc_interfaces;
 	struct ast_control_cc_payload *cc_data = frame_data;
@@ -1749,7 +1574,7 @@
 
 	struct ast_datastore *cc_interfaces_datastore;
 	struct dialed_cc_interfaces *interfaces;
-	struct ast_cc_tree_item *tree_item;
+	struct cc_tree_item *tree_item;
 	ast_channel_lock(chan);
 
 	if (ast_get_cc_agent_policy(ast_channel_get_cc_config_params(chan)) == AST_CC_AGENT_NEVER) {
@@ -1881,6 +1706,221 @@
 	ast_cc_config_params_destroy(agent->cc_params);
 	ast_free(agent);
 }
+
+/* Generic agent callbacks */
+static int cc_generic_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan);
+static int cc_generic_agent_start_offer_timer(struct ast_cc_agent *agent);
+static int cc_generic_agent_stop_offer_timer(struct ast_cc_agent *agent);
+static void cc_generic_agent_ack(struct ast_cc_agent *agent);
+static enum ast_device_state cc_generic_agent_status_request(struct ast_cc_agent *agent);
+static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent);
+static int cc_generic_agent_stop_monitoring(struct ast_cc_agent *agent);
+static int cc_generic_agent_recall(struct ast_cc_agent *agent);
+static void cc_generic_agent_destructor(struct ast_cc_agent *agent);
+
+static struct ast_cc_agent_callbacks generic_agent_callbacks = {
+	.type = "generic",
+	.init = cc_generic_agent_init,
+	.start_offer_timer = cc_generic_agent_start_offer_timer,
+	.stop_offer_timer = cc_generic_agent_stop_offer_timer,
+	.ack = cc_generic_agent_ack,
+	.status_request = cc_generic_agent_status_request,
+	.start_monitoring = cc_generic_agent_start_monitoring,
+	.stop_monitoring = cc_generic_agent_stop_monitoring,
+	.recall = cc_generic_agent_recall,
+	.destructor = cc_generic_agent_destructor,
+};
+
+struct cc_generic_agent_pvt {
+	/*!
+	 * Subscription to device state
+	 *
+	 * Used in the CC_CALLER_BUSY state. The
+	 * generic agent will subscribe to the
+	 * device state of the caller in order to
+	 * determine when we may move on
+	 */
+	struct ast_event_sub *sub;
+	/*!
+	 * Scheduler id of offer timer.
+	 */
+	int offer_timer_id;
+};
+
+static int cc_generic_agent_init(struct ast_cc_agent *agent, struct ast_channel *chan)
+{
+	struct cc_generic_agent_pvt *generic_pvt = ast_calloc(1, sizeof(*generic_pvt));
+
+	if (!generic_pvt) {
+		return -1;
+	}
+
+	generic_pvt->offer_timer_id = -1;
+	agent->private_data = generic_pvt;
+	ast_set_flag(agent, AST_CC_AGENT_SKIP_OFFER);
+	return 0;
+}
+
+static int offer_timer_expire(const void *data)
+{
+	const struct ast_cc_agent *agent = data;
+	struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
+	ast_log(LOG_NOTICE, "Queuing change request because offer timer has expired.\n");
+	agent_pvt->offer_timer_id = -1;
+	ast_cc_request_state_change(CC_FAILED, agent->core_id, "Generic agent offer timer expired");
+	return 0;
+}
+
+static int cc_generic_agent_start_offer_timer(struct ast_cc_agent *agent)
+{
+	int when;
+	int sched_id;
+	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
+
+	ast_assert(cc_sched_thread != NULL);
+	ast_assert(agent->cc_params != NULL);
+
+	when = ast_get_cc_offer_timer(agent->cc_params) * 1000;
+	ast_log(LOG_NOTICE, "About to schedule timer expiration for %d ms\n", when);
+	if ((sched_id = ast_sched_thread_add(cc_sched_thread, when, offer_timer_expire, agent)) == -1) {
+		return -1;
+	}
+	generic_pvt->offer_timer_id = sched_id;
+	return 0;
+}
+
+static int cc_generic_agent_stop_offer_timer(struct ast_cc_agent *agent)
+{
+	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
+
+	if (generic_pvt->offer_timer_id != -1) {
+		ast_sched_thread_del(cc_sched_thread, generic_pvt->offer_timer_id);
+		generic_pvt->offer_timer_id = -1;
+	}
+	return 0;
+}
+
+static void cc_generic_agent_ack(struct ast_cc_agent *agent)
+{
+	/* The generic agent doesn't have to do anything special to
+	 * acknowledge a CC request. Just return.
+	 */
+	return;
+}
+
+static enum ast_device_state cc_generic_agent_status_request(struct ast_cc_agent *agent)
+{
+	return ast_device_state(agent->interface);
+}
+
+static void generic_devstate_cb(const struct ast_event *event, void *userdata)
+{
+	struct ast_cc_agent *agent = userdata;
+	struct ast_str *str = ast_str_alloca(128);
+	ast_str_set(&str, 0, "%s is no longer busy\n", agent->interface);
+	ast_cc_request_state_change(CC_ACTIVE, agent->core_id, ast_str_buffer(str));
+}
+
+static int cc_generic_agent_start_monitoring(struct ast_cc_agent *agent)
+{
+	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
+	struct ast_str *str = ast_str_alloca(128);
+
+	ast_assert(generic_pvt->sub == NULL);
+	ast_str_set(&str, 0, "Starting to monitor %s device state since it is busy\n", agent->interface);
+
+	if (!(generic_pvt->sub = ast_event_subscribe(
+			AST_EVENT_DEVICE_STATE, generic_devstate_cb, ast_str_buffer(str), agent, 
+			AST_EVENT_IE_DEVICE, AST_EVENT_IE_PLTYPE_STR, agent->interface,
+			AST_EVENT_IE_STATE, AST_EVENT_IE_PLTYPE_UINT, AST_DEVICE_NOT_INUSE,
+			AST_EVENT_IE_END))) {
+		return -1;
+	}
+	return 0;
+}
+
+static int cc_generic_agent_stop_monitoring(struct ast_cc_agent *agent)
+{
+	struct cc_generic_agent_pvt *generic_pvt = agent->private_data;
+	
+	ast_assert(generic_pvt->sub != NULL);
+
+	generic_pvt->sub = ast_event_unsubscribe(generic_pvt->sub);
+	return 0;
+}
+
+static void *generic_recall(void *data)
+{
+	struct ast_cc_agent *agent = data;
+	char *interface = ast_strdupa(agent->interface);
+	char *tech;
+	char *target;
+	int reason;
+	struct ast_channel *chan;
+	struct cc_tree_item *tree_item = AST_LIST_FIRST(agent->interface_tree);
+	char *full_extension = ast_strdupa(tree_item->interface->name);
+	char *context;
+	char *exten;
+	const char *callback_macro = ast_get_cc_callback_macro(agent->cc_params);
+	tech = interface;
+	if ((target = strchr(interface, '/'))) {
+		*target++ = '\0';
+	}
+	if (!(chan = ast_request_and_dial(tech, AST_FORMAT_SLINEAR, NULL, target, 20000, &reason, NULL, NULL))) {
+		/* Hmm, no channel. Sucks for you, bud.
+		 */
+		ast_log(LOG_NOTICE, "Failed to call back %s for reason %d\n", agent->interface, reason);
+		ast_cc_request_state_change(CC_FAILED, agent->core_id, "Failed to call back interface\n");
+		return NULL;
+	}
+	if (!ast_strlen_zero(callback_macro)) {
+		ast_log(LOG_NOTICE, "There's a callback macro configured\n");
+		if (ast_app_run_macro(NULL, chan, callback_macro, NULL)) {
+			ast_cc_request_state_change(CC_FAILED, agent->core_id, "Callback macro failed. Maybe a hangup?");
+			ast_hangup(chan);
+			return NULL;
+		}
+	}
+	/* We have a channel. It's time now to set up the datastore of recalled CC interfaces.
+	 * This will be a common task for all recall functions. If it were possible, I'd have
+	 * the core do it automatically, but alas I cannot. Instead, I will provide a public
+	 * function to do so.
+	 */
+	ast_setup_cc_recall_datastore(chan, agent);
+	ast_set_cc_interfaces_chanvar(chan, full_extension);
+	/* Now we can bust apart the outbound name so that the PBX will run. */
+	exten = full_extension;
+	if ((context = strchr(full_extension, '@'))) {
+		*context++ = '\0';
+	}
+	ast_copy_string(chan->exten, exten, sizeof(chan->exten));
+	ast_copy_string(chan->context, context, sizeof(chan->context));
+	chan->priority = 1;
+	ast_pbx_start(chan);
+	return NULL;
+}
+
+static int cc_generic_agent_recall(struct ast_cc_agent *agent)
+{
+	pthread_t clotho;
+	ast_pthread_create_detached_background(&clotho, NULL, generic_recall, agent);
+	return 0;
+}
+
+static void cc_generic_agent_destructor(struct ast_cc_agent *agent)
+{
+	struct cc_generic_agent_pvt *agent_pvt = agent->private_data;
+	if (!agent_pvt) {
+		return;
+	}
+	
+	if (agent_pvt->sub) {
+		agent_pvt->sub = ast_event_unsubscribe(agent_pvt->sub);
+	}
+
+	ast_free(agent_pvt);
+}
+
 
 static void cc_core_instance_destructor(void *data)
 {
@@ -2009,7 +2049,7 @@
 	return ao2_t_find(cc_monitors, &finder, OBJ_POINTER, "Trying to find specific monitor");
 }
 
-static struct ast_cc_monitor *find_or_create_monitor(struct ast_cc_monitor *parent, struct ast_cc_tree_item *tree_item, const int core_id)
+static struct ast_cc_monitor *find_or_create_monitor(struct ast_cc_monitor *parent, struct cc_tree_item *tree_item, const int core_id)
 {
 	struct ast_cc_monitor *new_monitor;
 	struct ast_cc_monitor_link *new_link;
@@ -2039,9 +2079,9 @@
 	return new_monitor;
 }
 
-static void interface_tree_to_monitor(struct ast_cc_tree_item *current_place, struct ast_cc_monitor *parent, const int core_id)
-{
-	struct ast_cc_tree_item *tree_item = current_place;
+static void interface_tree_to_monitor(struct cc_tree_item *current_place, struct ast_cc_monitor *parent, const int core_id)
+{
+	struct cc_tree_item *tree_item = current_place;
 	struct ast_cc_monitor *monitor = find_or_create_monitor(parent, current_place, core_id);
 
 	if (!monitor) {
@@ -2520,7 +2560,7 @@
 {
 	struct ast_datastore *recall_datastore;
 	struct ast_cc_interface_tree *interface_tree;
-	struct ast_cc_tree_item *tree_item_iter;
+	struct cc_tree_item *tree_item_iter;
 	struct cc_recall_ds_data *recall_data;
 	unsigned int exten_id = 0;
 	struct ast_str *var_value = ast_str_create(64);




More information about the svn-commits mailing list