[svn-commits] mmichelson: branch mmichelson/pubsub_bodies r405987 - in /team/mmichelson/pub...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Jan 20 17:58:17 CST 2014


Author: mmichelson
Date: Mon Jan 20 17:58:12 2014
New Revision: 405987

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=405987
Log:
Get rid of res_pjsip_exten_state.h.

Since exten state providers were replaced with body
generators, the methods and structures previously
provided in this header are no longer required.


Removed:
    team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_exten_state.h
Modified:
    team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h
    team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c
    team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c
    team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c
    team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c

Modified: team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h (original)
+++ team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h Mon Jan 20 17:58:12 2014
@@ -16,6 +16,11 @@
  * at the top of the source tree.
  */
 
+#ifndef _RES_PJSIP_BODY_GENERATOR_TYPES_H
+#define _RES_PJSIP_BODY_GENERATOR_TYPES_H
+
+#include "asterisk/pbx.h"
+
 /*!
  * \brief structure used for presence XML bodies
  *
@@ -24,13 +29,19 @@
  * \li application/xpidf+xml
  * \li application/cpim-pidf+xml
  */
-struct exten_state_body_generator_data {
-	/*! Extension state data. See res_pjsip_exten_state.h */
-	struct ast_sip_exten_state_data *exten_data;
+struct ast_sip_exten_state_data {
+	/*! The extension of the current state change */
+	const char *exten;
+	/*! The extension state of the change */
+	enum ast_extension_states exten_state;
+	/*! The presence state of the change */
+	enum ast_presence_state presence_state;
+	/*! Current device state information */
+	struct ao2_container *device_state_info;
 	/*! Local dialog URI */
-	const char *local;
+	char local[PJSIP_MAX_URL_SIZE];
 	/*! Remote dialog URI */
-	const char *remote;
+	char remote[PJSIP_MAX_URL_SIZE];
 	/*! Allocation pool */
 	pj_pool_t *pool;
 };
@@ -46,3 +57,5 @@
 	/*! Number of new messages */
 	int new_msgs;
 };
+
+#endif /* _RES_PJSIP_BODY_GENERATOR_TYPES_H */

Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c Mon Jan 20 17:58:12 2014
@@ -31,7 +31,6 @@
 
 #include "asterisk/res_pjsip.h"
 #include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_exten_state.h"
 #include "asterisk/res_pjsip_body_generator_types.h"
 #include "asterisk/module.h"
 #include "asterisk/logger.h"
@@ -41,43 +40,6 @@
 
 #define BODY_SIZE 1024
 #define EVENT_TYPE_SIZE 50
-
-AST_RWLIST_HEAD_STATIC(providers, ast_sip_exten_state_provider);
-
-/*!
- * \internal
- * \brief Find a provider based on the given accept body type.
- */
-static struct ast_sip_exten_state_provider *provider_by_type(const char *type)
-{
-	struct ast_sip_exten_state_provider *i;
-	SCOPED_LOCK(lock, &providers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
-	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&providers, i, next) {
-		if (!strcmp(i->body_type, type)) {
-			return i;
-		}
-	}
-	AST_RWLIST_TRAVERSE_SAFE_END;
-	return NULL;
-}
-
-/*!
- * \internal
- * \brief Find a provider based on the given accept body types.
- */
-static struct ast_sip_exten_state_provider *provider_by_types(const char *event_name,
-							      char **types, int count)
-{
-	int i;
-	struct ast_sip_exten_state_provider *res;
-	for (i = 0; i < count; ++i) {
-		if ((res = provider_by_type(types[i])) &&
-		    !strcmp(event_name, res->event_name)) {
-			return res;
-		}
-	}
-	return NULL;
-}
 
 /*!
  * \brief A subscription for extension state
@@ -105,454 +67,18 @@
 	enum ast_extension_states last_exten_state;
 };
 
-static void exten_state_subscription_destructor(void *obj)
-{
-	struct exten_state_subscription *sub = obj;
-	int i;
-
-	for (i = 0; i < sub->body_types_count; ++i) {
-		ast_free(sub->body_types[i]);
-	}
-
-	ast_free(sub->body_types);
-	ao2_cleanup(sub->sip_sub);
-}
-
-/*!
- * \internal
- * \brief Copies the body types the message wishes to subscribe to.
- */
-static void copy_body_types(pjsip_rx_data *rdata,
-			    struct exten_state_subscription *exten_state_sub)
-{
-	int i;
-	pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)
-		pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
-
-	exten_state_sub->body_types_count = hdr->count;
-	exten_state_sub->body_types = ast_malloc(hdr->count * sizeof(char*));
-
-	for (i = 0; i < hdr->count; ++i) {
-		exten_state_sub->body_types[i] =
-			ast_malloc(hdr->values[i].slen * sizeof(char*) + 1);
-
-		ast_copy_string(exten_state_sub->body_types[i],
-				pj_strbuf(&hdr->values[i]), hdr->values[i].slen + 1);
-	}
-}
-
-/*!
- * \internal
- * \brief Initialize the last extension state to something outside
- * its usual states.
- */
-#define INITIAL_LAST_EXTEN_STATE -3
-
-/*!
- * \internal
- * \brief Allocates an exten_state_subscription object.
- *
- * Creates the underlying SIP subscription for the given request. First makes
- * sure that there are registered handler and provider objects available.
- */
-static struct exten_state_subscription *exten_state_subscription_alloc(
-	struct ast_sip_endpoint *endpoint, enum ast_sip_subscription_role role, pjsip_rx_data *rdata)
-{
-	static const pj_str_t event_name = { "Event", 5 };
-	pjsip_event_hdr *hdr = (pjsip_event_hdr*)pjsip_msg_find_hdr_by_name(
-		rdata->msg_info.msg, &event_name, NULL);
-
-	struct ast_sip_exten_state_provider *provider;
-	RAII_VAR(struct exten_state_subscription *, exten_state_sub,
-		 ao2_alloc(sizeof(*exten_state_sub), exten_state_subscription_destructor), ao2_cleanup);
-
-	if (!exten_state_sub) {
-		return NULL;
-	}
-
-	ast_copy_pj_str(exten_state_sub->event_name, &hdr->event_type,
-			sizeof(exten_state_sub->event_name));
-
-	copy_body_types(rdata, exten_state_sub);
-	if (!(provider = provider_by_types(exten_state_sub->event_name,
-					   exten_state_sub->body_types,
-					   exten_state_sub->body_types_count))) {
-		ast_log(LOG_WARNING, "Unable to locate subscription handler\n");
-		return NULL;
-	}
-
-	if (!(exten_state_sub->sip_sub = ast_sip_create_subscription(
-		      provider->handler, role, endpoint, rdata))) {
-		ast_log(LOG_WARNING, "Unable to create SIP subscription for endpoint %s\n",
-			ast_sorcery_object_get_id(endpoint));
-		return NULL;
-	}
-
-	exten_state_sub->last_exten_state = INITIAL_LAST_EXTEN_STATE;
-
-	ao2_ref(exten_state_sub, +1);
-	return exten_state_sub;
-}
-
-static int exten_state_body_generator_data_init(struct ast_sip_exten_state_data *exten_data,
-		const char *local, const char *remote,
-		struct exten_state_body_generator_data *gen_data)
-{
-	gen_data->pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
-			"pidf", 1024, 1024);
-
-	if (!gen_data->pool) {
-		return -1;
-	}
-
-	gen_data->local = local;
-	gen_data->remote = remote;
-	gen_data->exten_data = exten_data;
-
-	return 0;
-}
-
-static void exten_state_body_generator_data_release(struct exten_state_body_generator_data *gen_data)
-{
-	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), gen_data->pool);
-}
-
-/*!
- * \internal
- * \brief Create and send a NOTIFY request to the subscriber.
- */
-static void create_send_notify(struct exten_state_subscription *exten_state_sub, const char *reason,
-			       pjsip_evsub_state evsub_state, struct ast_sip_exten_state_data *exten_state_data)
-{
-	RAII_VAR(struct ast_str *, body_text, ast_str_create(BODY_SIZE), ast_free_ptr);
-	pj_str_t reason_str;
-	const pj_str_t *reason_str_ptr = NULL;
-	pjsip_tx_data *tdata;
-	pjsip_dialog *dlg;
-	char local[PJSIP_MAX_URL_SIZE], remote[PJSIP_MAX_URL_SIZE];
-	struct ast_sip_body body;
-	struct exten_state_body_generator_data gen_data;
-
-	body.type = ast_sip_subscription_get_body_type(exten_state_sub->sip_sub);
-	body.subtype = ast_sip_subscription_get_body_subtype(exten_state_sub->sip_sub);
-
-	dlg = ast_sip_subscription_get_dlg(exten_state_sub->sip_sub);
-	ast_copy_pj_str(local, &dlg->local.info_str, sizeof(local));
-	ast_copy_pj_str(remote, &dlg->remote.info_str, sizeof(remote));
-
-	if (exten_state_body_generator_data_init(exten_state_data, local, remote, &gen_data)) {
-		ast_log(LOG_ERROR, "Unable to allocate resources for sending presence NOTIFY request\n");
-		return;
-	}
-
-	if (ast_sip_pubsub_generate_body_content(body.type, body.subtype,
-				&gen_data, &body_text)) {
-		ast_log(LOG_ERROR, "Unable to create body on NOTIFY request\n");
-		goto end;
-	}
-
-	body.body_text = ast_str_buffer(body_text);
-
-	if (reason) {
-		pj_cstr(&reason_str, reason);
-		reason_str_ptr = &reason_str;
-	}
-
-	if (pjsip_evsub_notify(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub),
-			      evsub_state, NULL, reason_str_ptr, &tdata) != PJ_SUCCESS) {
-		ast_log(LOG_WARNING, "Unable to create NOTIFY request\n");
-		goto end;
-	}
-
-	if (ast_sip_add_body(tdata, &body)) {
-		ast_log(LOG_WARNING, "Unable to add body to NOTIFY request\n");
-		pjsip_tx_data_dec_ref(tdata);
-		goto end;
-	}
-
-	if (ast_sip_subscription_send_request(exten_state_sub->sip_sub, tdata) != PJ_SUCCESS) {
-		ast_log(LOG_WARNING, "Unable to send NOTIFY request\n");
-	}
-
-end:
-	exten_state_body_generator_data_release(&gen_data);
-}
-
-/*!
- * \internal
- * \brief Get device state information and send notification to the subscriber.
- */
-static void send_notify(struct exten_state_subscription *exten_state_sub, const char *reason,
-	pjsip_evsub_state evsub_state)
-{
-	RAII_VAR(struct ao2_container*, info, NULL, ao2_cleanup);
-	char *subtype = NULL, *message = NULL;
-
-	struct ast_sip_exten_state_data exten_state_data = {
-		.exten = exten_state_sub->exten,
-		.presence_state = ast_hint_presence_state(NULL, exten_state_sub->context,
-							  exten_state_sub->exten, &subtype, &message),
-	};
-
-	if ((exten_state_data.exten_state = ast_extension_state_extended(
-		     NULL, exten_state_sub->context, exten_state_sub->exten, &info)) < 0) {
-
-		ast_log(LOG_WARNING, "Unable to get device hint/info for extension %s\n",
-			exten_state_sub->exten);
-		return;
-	}
-
-	exten_state_data.device_state_info = info;
-	create_send_notify(exten_state_sub, reason, evsub_state, &exten_state_data);
-}
-
-struct notify_task_data {
-	struct ast_sip_exten_state_data exten_state_data;
-	struct exten_state_subscription *exten_state_sub;
-	pjsip_evsub_state evsub_state;
-};
-
-static void notify_task_data_destructor(void *obj)
-{
-	struct notify_task_data *task_data = obj;
-
-	ao2_ref(task_data->exten_state_sub, -1);
-	ao2_cleanup(task_data->exten_state_data.device_state_info);
-}
-
-static struct notify_task_data *alloc_notify_task_data(char *exten, struct exten_state_subscription *exten_state_sub,
-						       struct ast_state_cb_info *info)
-{
-	struct notify_task_data *task_data =
-		ao2_alloc(sizeof(*task_data), notify_task_data_destructor);
-
-	if (!task_data) {
-		ast_log(LOG_WARNING, "Unable to create notify task data\n");
-		return NULL;
-	}
-
-	task_data->evsub_state = PJSIP_EVSUB_STATE_ACTIVE;
-	task_data->exten_state_sub = exten_state_sub;
-	task_data->exten_state_sub->last_exten_state = info->exten_state;
-	ao2_ref(task_data->exten_state_sub, +1);
-
-	task_data->exten_state_data.exten = exten_state_sub->exten;
-	task_data->exten_state_data.exten_state = info->exten_state;
-	task_data->exten_state_data.presence_state = info->presence_state;
-	task_data->exten_state_data.device_state_info = info->device_state_info;
-
-	if (task_data->exten_state_data.device_state_info) {
-		ao2_ref(task_data->exten_state_data.device_state_info, +1);
-	}
-
-	if ((info->exten_state == AST_EXTENSION_DEACTIVATED) ||
-	    (info->exten_state == AST_EXTENSION_REMOVED)) {
-		task_data->evsub_state = PJSIP_EVSUB_STATE_TERMINATED;
-		ast_log(LOG_WARNING, "Watcher for hint %s %s\n", exten, info->exten_state
-			 == AST_EXTENSION_REMOVED ? "removed" : "deactivated");
-	}
-
-	return task_data;
-}
-
-static int notify_task(void *obj)
-{
-	RAII_VAR(struct notify_task_data *, task_data, obj, ao2_cleanup);
-
-	create_send_notify(task_data->exten_state_sub, task_data->evsub_state ==
-			   PJSIP_EVSUB_STATE_TERMINATED ? "noresource" : NULL,
-			   task_data->evsub_state, &task_data->exten_state_data);
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Callback for exten/device state changes.
- *
- * Upon state change, send the appropriate notification to the subscriber.
- */
-static int state_changed(char *context, char *exten,
-			 struct ast_state_cb_info *info, void *data)
-{
-	struct notify_task_data *task_data;
-	struct exten_state_subscription *exten_state_sub = data;
-
-	if (exten_state_sub->last_exten_state == info->exten_state) {
-		return 0;
-	}
-
-	if (!(task_data = alloc_notify_task_data(exten, exten_state_sub, info))) {
-		return -1;
-	}
-
-	/* safe to push this async since we copy the data from info and
-	   add a ref for the device state info */
-	if (ast_sip_push_task(ast_sip_subscription_get_serializer(task_data->exten_state_sub->sip_sub),
-			      notify_task, task_data)) {
-		ao2_cleanup(task_data);
-		return -1;
-	}
-	return 0;
-}
-
-static void state_changed_destroy(int id, void *data)
-{
-	struct exten_state_subscription *exten_state_sub = data;
-	ao2_cleanup(exten_state_sub);
-}
-
-static struct ast_datastore_info ds_info = { };
-static const char ds_name[] = "exten state datastore";
-
-/*!
- * \internal
- * \brief Add a datastore for exten exten_state_subscription.
- *
- * Adds the exten_state_subscription wrapper object to a datastore so it can be retrieved
- * later based upon its association with the ast_sip_subscription.
- */
-static int add_datastore(struct exten_state_subscription *exten_state_sub)
-{
-	RAII_VAR(struct ast_datastore *, datastore,
-		 ast_sip_subscription_alloc_datastore(&ds_info, ds_name), ao2_cleanup);
-
-	if (!datastore) {
-		return -1;
-	}
-
-	datastore->data = exten_state_sub;
-	ast_sip_subscription_add_datastore(exten_state_sub->sip_sub, datastore);
-	ao2_ref(exten_state_sub, +1);
-	return 0;
-}
-
-/*!
- * \internal
- * \brief Get the exten_state_subscription object associated with the given
- * ast_sip_subscription in the datastore.
- */
-static struct exten_state_subscription *get_exten_state_sub(
-	struct ast_sip_subscription *sub)
-{
-	RAII_VAR(struct ast_datastore *, datastore,
-		 ast_sip_subscription_get_datastore(sub, ds_name), ao2_cleanup);
-
-	return datastore ? datastore->data : NULL;
-}
-
-static void subscription_shutdown(struct ast_sip_subscription *sub)
-{
-	struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
-
-	if (!exten_state_sub) {
-		return;
-	}
-
-	ast_extension_state_del(exten_state_sub->id, state_changed);
-	ast_sip_subscription_remove_datastore(exten_state_sub->sip_sub, ds_name);
-	/* remove data store reference */
-	ao2_cleanup(exten_state_sub);
-}
-
+#define DEFAULT_PRESENCE_BODY "application/pidf+xml"
+
+static void subscription_shutdown(struct ast_sip_subscription *sub);
 static struct ast_sip_subscription *new_subscribe(struct ast_sip_endpoint *endpoint,
-						  pjsip_rx_data *rdata)
-{
-	pjsip_uri *uri = rdata->msg_info.msg->line.req.uri;
-	pjsip_sip_uri *sip_uri = pjsip_uri_get_uri(uri);
-	RAII_VAR(struct exten_state_subscription *, exten_state_sub, NULL, ao2_cleanup);
-
-	if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
-		ast_log(LOG_WARNING, "Attempt to SUBSCRIBE to a non-SIP URI\n");
-		return NULL;
-	}
-
-	if (!(exten_state_sub = exten_state_subscription_alloc(endpoint, AST_SIP_NOTIFIER, rdata))) {
-		return NULL;
-	}
-
-	ast_copy_string(exten_state_sub->context, endpoint->context, sizeof(exten_state_sub->context));
-	ast_copy_pj_str(exten_state_sub->exten, &sip_uri->user, sizeof(exten_state_sub->exten));
-
-	if ((exten_state_sub->id = ast_extension_state_add_destroy_extended(
-		     exten_state_sub->context, exten_state_sub->exten,
-		     state_changed, state_changed_destroy, exten_state_sub)) < 0) {
-		ast_log(LOG_WARNING, "Unable to subscribe endpoint '%s' to extension '%s@%s'\n",
-			ast_sorcery_object_get_id(endpoint), exten_state_sub->exten,
-			exten_state_sub->context);
-		pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
-		return NULL;
-	}
-
-	/* bump the ref since ast_extension_state_add holds a reference */
-	ao2_ref(exten_state_sub, +1);
-
-	if (add_datastore(exten_state_sub)) {
-		ast_log(LOG_WARNING, "Unable to add to subscription datastore.\n");
-		pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
-		return NULL;
-	}
-
-	if (pjsip_evsub_accept(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub),
-			       rdata, 200, NULL) != PJ_SUCCESS) {
-		ast_log(LOG_WARNING, "Unable to accept the incoming extension state subscription.\n");
-		pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
-		return NULL;
-	}
-
-	send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_ACTIVE);
-	return exten_state_sub->sip_sub;
-}
-
+						  pjsip_rx_data *rdata);
 static void resubscribe(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
-			struct ast_sip_subscription_response_data *response_data)
-{
-	struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
-
-	if (!exten_state_sub) {
-		return;
-	}
-
-	send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_ACTIVE);
-}
-
-static void subscription_timeout(struct ast_sip_subscription *sub)
-{
-	struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
-
-	if (!exten_state_sub) {
-		return;
-	}
-
-	ast_verbose(VERBOSE_PREFIX_3 "Subscription has timed out.\n");
-	send_notify(exten_state_sub, "timeout", PJSIP_EVSUB_STATE_TERMINATED);
-}
-
+			struct ast_sip_subscription_response_data *response_data);
+static void subscription_timeout(struct ast_sip_subscription *sub);
 static void subscription_terminated(struct ast_sip_subscription *sub,
-				    pjsip_rx_data *rdata)
-{
-	struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
-
-	if (!exten_state_sub) {
-		return;
-	}
-
-	ast_verbose(VERBOSE_PREFIX_3 "Subscription has been terminated.\n");
-	send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_TERMINATED);
-}
-
+				    pjsip_rx_data *rdata);
 static void to_ami(struct ast_sip_subscription *sub,
-		   struct ast_str **buf)
-{
-	struct exten_state_subscription *exten_state_sub =
-		get_exten_state_sub(sub);
-
-	ast_str_append(buf, 0, "SubscriptionType: extension_state\r\n"
-		       "Extension: %s\r\nExtensionStates: %s\r\n",
-		       exten_state_sub->exten, ast_extension_state2str(
-			       exten_state_sub->last_exten_state));
-}
-
-#define DEFAULT_PRESENCE_BODY "application/pidf+xml"
+		   struct ast_str **buf);
 
 struct ast_sip_subscription_handler presence_handler = {
 	.event_name = "presence",
@@ -566,6 +92,417 @@
 	.to_ami = to_ami,
 };
 
+static void exten_state_subscription_destructor(void *obj)
+{
+	struct exten_state_subscription *sub = obj;
+	int i;
+
+	for (i = 0; i < sub->body_types_count; ++i) {
+		ast_free(sub->body_types[i]);
+	}
+
+	ast_free(sub->body_types);
+	ao2_cleanup(sub->sip_sub);
+}
+
+/*!
+ * \internal
+ * \brief Copies the body types the message wishes to subscribe to.
+ */
+static void copy_body_types(pjsip_rx_data *rdata,
+			    struct exten_state_subscription *exten_state_sub)
+{
+	int i;
+	pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)
+		pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
+
+	exten_state_sub->body_types_count = hdr->count;
+	exten_state_sub->body_types = ast_malloc(hdr->count * sizeof(char*));
+
+	for (i = 0; i < hdr->count; ++i) {
+		exten_state_sub->body_types[i] =
+			ast_malloc(hdr->values[i].slen * sizeof(char*) + 1);
+
+		ast_copy_string(exten_state_sub->body_types[i],
+				pj_strbuf(&hdr->values[i]), hdr->values[i].slen + 1);
+	}
+}
+
+/*!
+ * \internal
+ * \brief Initialize the last extension state to something outside
+ * its usual states.
+ */
+#define INITIAL_LAST_EXTEN_STATE -3
+
+/*!
+ * \internal
+ * \brief Allocates an exten_state_subscription object.
+ *
+ * Creates the underlying SIP subscription for the given request. First makes
+ * sure that there are registered handler and provider objects available.
+ */
+static struct exten_state_subscription *exten_state_subscription_alloc(
+	struct ast_sip_endpoint *endpoint, enum ast_sip_subscription_role role, pjsip_rx_data *rdata)
+{
+	static const pj_str_t event_name = { "Event", 5 };
+	pjsip_event_hdr *hdr = (pjsip_event_hdr*)pjsip_msg_find_hdr_by_name(
+		rdata->msg_info.msg, &event_name, NULL);
+	RAII_VAR(struct exten_state_subscription *, exten_state_sub,
+		 ao2_alloc(sizeof(*exten_state_sub), exten_state_subscription_destructor), ao2_cleanup);
+
+	if (!exten_state_sub) {
+		return NULL;
+	}
+
+	ast_copy_pj_str(exten_state_sub->event_name, &hdr->event_type,
+			sizeof(exten_state_sub->event_name));
+
+	copy_body_types(rdata, exten_state_sub);
+
+	if (!(exten_state_sub->sip_sub = ast_sip_create_subscription(
+		      &presence_handler, role, endpoint, rdata))) {
+		ast_log(LOG_WARNING, "Unable to create SIP subscription for endpoint %s\n",
+			ast_sorcery_object_get_id(endpoint));
+		return NULL;
+	}
+
+	exten_state_sub->last_exten_state = INITIAL_LAST_EXTEN_STATE;
+
+	ao2_ref(exten_state_sub, +1);
+	return exten_state_sub;
+}
+
+/*!
+ * \internal
+ * \brief Create and send a NOTIFY request to the subscriber.
+ */
+static void create_send_notify(struct exten_state_subscription *exten_state_sub, const char *reason,
+			       pjsip_evsub_state evsub_state, struct ast_sip_exten_state_data *exten_state_data)
+{
+	RAII_VAR(struct ast_str *, body_text, ast_str_create(BODY_SIZE), ast_free_ptr);
+	pj_str_t reason_str;
+	const pj_str_t *reason_str_ptr = NULL;
+	pjsip_tx_data *tdata;
+	struct ast_sip_body body;
+
+	body.type = ast_sip_subscription_get_body_type(exten_state_sub->sip_sub);
+	body.subtype = ast_sip_subscription_get_body_subtype(exten_state_sub->sip_sub);
+
+	if (ast_sip_pubsub_generate_body_content(body.type, body.subtype,
+				exten_state_data, &body_text)) {
+		ast_log(LOG_ERROR, "Unable to create body on NOTIFY request\n");
+		return;
+	}
+
+	body.body_text = ast_str_buffer(body_text);
+
+	if (reason) {
+		pj_cstr(&reason_str, reason);
+		reason_str_ptr = &reason_str;
+	}
+
+	if (pjsip_evsub_notify(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub),
+			      evsub_state, NULL, reason_str_ptr, &tdata) != PJ_SUCCESS) {
+		ast_log(LOG_WARNING, "Unable to create NOTIFY request\n");
+		return;
+	}
+
+	if (ast_sip_add_body(tdata, &body)) {
+		ast_log(LOG_WARNING, "Unable to add body to NOTIFY request\n");
+		pjsip_tx_data_dec_ref(tdata);
+		return;
+	}
+
+	if (ast_sip_subscription_send_request(exten_state_sub->sip_sub, tdata) != PJ_SUCCESS) {
+		ast_log(LOG_WARNING, "Unable to send NOTIFY request\n");
+	}
+}
+
+/*!
+ * \internal
+ * \brief Get device state information and send notification to the subscriber.
+ */
+static void send_notify(struct exten_state_subscription *exten_state_sub, const char *reason,
+	pjsip_evsub_state evsub_state)
+{
+	RAII_VAR(struct ao2_container*, info, NULL, ao2_cleanup);
+	char *subtype = NULL, *message = NULL;
+	pjsip_dialog *dlg;
+	struct ast_sip_exten_state_data exten_state_data = {
+		.exten = exten_state_sub->exten,
+		.presence_state = ast_hint_presence_state(NULL, exten_state_sub->context,
+							  exten_state_sub->exten, &subtype, &message),
+	};
+
+	dlg = ast_sip_subscription_get_dlg(exten_state_sub->sip_sub);
+	ast_copy_pj_str(exten_state_data.local, &dlg->local.info_str,
+			sizeof(exten_state_data.local));
+	ast_copy_pj_str(exten_state_data.remote, &dlg->remote.info_str,
+			sizeof(exten_state_data.remote));
+
+	if ((exten_state_data.exten_state = ast_extension_state_extended(
+		     NULL, exten_state_sub->context, exten_state_sub->exten, &info)) < 0) {
+
+		ast_log(LOG_WARNING, "Unable to get device hint/info for extension %s\n",
+			exten_state_sub->exten);
+		return;
+	}
+
+	exten_state_data.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
+			"exten_state", 1024, 1024);
+
+	exten_state_data.device_state_info = info;
+	create_send_notify(exten_state_sub, reason, evsub_state, &exten_state_data);
+	pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), exten_state_data.pool);
+}
+
+struct notify_task_data {
+	struct ast_sip_exten_state_data exten_state_data;
+	struct exten_state_subscription *exten_state_sub;
+	pjsip_evsub_state evsub_state;
+};
+
+static void notify_task_data_destructor(void *obj)
+{
+	struct notify_task_data *task_data = obj;
+
+	ao2_ref(task_data->exten_state_sub, -1);
+	ao2_cleanup(task_data->exten_state_data.device_state_info);
+}
+
+static struct notify_task_data *alloc_notify_task_data(char *exten, struct exten_state_subscription *exten_state_sub,
+						       struct ast_state_cb_info *info)
+{
+	struct notify_task_data *task_data =
+		ao2_alloc(sizeof(*task_data), notify_task_data_destructor);
+
+	if (!task_data) {
+		ast_log(LOG_WARNING, "Unable to create notify task data\n");
+		return NULL;
+	}
+
+	task_data->evsub_state = PJSIP_EVSUB_STATE_ACTIVE;
+	task_data->exten_state_sub = exten_state_sub;
+	task_data->exten_state_sub->last_exten_state = info->exten_state;
+	ao2_ref(task_data->exten_state_sub, +1);
+
+	task_data->exten_state_data.exten = exten_state_sub->exten;
+	task_data->exten_state_data.exten_state = info->exten_state;
+	task_data->exten_state_data.presence_state = info->presence_state;
+	task_data->exten_state_data.device_state_info = info->device_state_info;
+
+	if (task_data->exten_state_data.device_state_info) {
+		ao2_ref(task_data->exten_state_data.device_state_info, +1);
+	}
+
+	if ((info->exten_state == AST_EXTENSION_DEACTIVATED) ||
+	    (info->exten_state == AST_EXTENSION_REMOVED)) {
+		task_data->evsub_state = PJSIP_EVSUB_STATE_TERMINATED;
+		ast_log(LOG_WARNING, "Watcher for hint %s %s\n", exten, info->exten_state
+			 == AST_EXTENSION_REMOVED ? "removed" : "deactivated");
+	}
+
+	return task_data;
+}
+
+static int notify_task(void *obj)
+{
+	RAII_VAR(struct notify_task_data *, task_data, obj, ao2_cleanup);
+
+	create_send_notify(task_data->exten_state_sub, task_data->evsub_state ==
+			   PJSIP_EVSUB_STATE_TERMINATED ? "noresource" : NULL,
+			   task_data->evsub_state, &task_data->exten_state_data);
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Callback for exten/device state changes.
+ *
+ * Upon state change, send the appropriate notification to the subscriber.
+ */
+static int state_changed(char *context, char *exten,
+			 struct ast_state_cb_info *info, void *data)
+{
+	struct notify_task_data *task_data;
+	struct exten_state_subscription *exten_state_sub = data;
+
+	if (exten_state_sub->last_exten_state == info->exten_state) {
+		return 0;
+	}
+
+	if (!(task_data = alloc_notify_task_data(exten, exten_state_sub, info))) {
+		return -1;
+	}
+
+	/* safe to push this async since we copy the data from info and
+	   add a ref for the device state info */
+	if (ast_sip_push_task(ast_sip_subscription_get_serializer(task_data->exten_state_sub->sip_sub),
+			      notify_task, task_data)) {
+		ao2_cleanup(task_data);
+		return -1;
+	}
+	return 0;
+}
+
+static void state_changed_destroy(int id, void *data)
+{
+	struct exten_state_subscription *exten_state_sub = data;
+	ao2_cleanup(exten_state_sub);
+}
+
+static struct ast_datastore_info ds_info = { };
+static const char ds_name[] = "exten state datastore";
+
+/*!
+ * \internal
+ * \brief Add a datastore for exten exten_state_subscription.
+ *
+ * Adds the exten_state_subscription wrapper object to a datastore so it can be retrieved
+ * later based upon its association with the ast_sip_subscription.
+ */
+static int add_datastore(struct exten_state_subscription *exten_state_sub)
+{
+	RAII_VAR(struct ast_datastore *, datastore,
+		 ast_sip_subscription_alloc_datastore(&ds_info, ds_name), ao2_cleanup);
+
+	if (!datastore) {
+		return -1;
+	}
+
+	datastore->data = exten_state_sub;
+	ast_sip_subscription_add_datastore(exten_state_sub->sip_sub, datastore);
+	ao2_ref(exten_state_sub, +1);
+	return 0;
+}
+
+/*!
+ * \internal
+ * \brief Get the exten_state_subscription object associated with the given
+ * ast_sip_subscription in the datastore.
+ */
+static struct exten_state_subscription *get_exten_state_sub(
+	struct ast_sip_subscription *sub)
+{
+	RAII_VAR(struct ast_datastore *, datastore,
+		 ast_sip_subscription_get_datastore(sub, ds_name), ao2_cleanup);
+
+	return datastore ? datastore->data : NULL;
+}
+
+static void subscription_shutdown(struct ast_sip_subscription *sub)
+{
+	struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
+
+	if (!exten_state_sub) {
+		return;
+	}
+
+	ast_extension_state_del(exten_state_sub->id, state_changed);
+	ast_sip_subscription_remove_datastore(exten_state_sub->sip_sub, ds_name);
+	/* remove data store reference */
+	ao2_cleanup(exten_state_sub);
+}
+
+static struct ast_sip_subscription *new_subscribe(struct ast_sip_endpoint *endpoint,
+						  pjsip_rx_data *rdata)
+{
+	pjsip_uri *uri = rdata->msg_info.msg->line.req.uri;
+	pjsip_sip_uri *sip_uri = pjsip_uri_get_uri(uri);
+	RAII_VAR(struct exten_state_subscription *, exten_state_sub, NULL, ao2_cleanup);
+
+	if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
+		ast_log(LOG_WARNING, "Attempt to SUBSCRIBE to a non-SIP URI\n");
+		return NULL;
+	}
+
+	if (!(exten_state_sub = exten_state_subscription_alloc(endpoint, AST_SIP_NOTIFIER, rdata))) {
+		return NULL;
+	}
+
+	ast_copy_string(exten_state_sub->context, endpoint->context, sizeof(exten_state_sub->context));
+	ast_copy_pj_str(exten_state_sub->exten, &sip_uri->user, sizeof(exten_state_sub->exten));
+
+	if ((exten_state_sub->id = ast_extension_state_add_destroy_extended(
+		     exten_state_sub->context, exten_state_sub->exten,
+		     state_changed, state_changed_destroy, exten_state_sub)) < 0) {
+		ast_log(LOG_WARNING, "Unable to subscribe endpoint '%s' to extension '%s@%s'\n",
+			ast_sorcery_object_get_id(endpoint), exten_state_sub->exten,
+			exten_state_sub->context);
+		pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
+		return NULL;
+	}
+
+	/* bump the ref since ast_extension_state_add holds a reference */
+	ao2_ref(exten_state_sub, +1);
+
+	if (add_datastore(exten_state_sub)) {
+		ast_log(LOG_WARNING, "Unable to add to subscription datastore.\n");
+		pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
+		return NULL;
+	}
+
+	if (pjsip_evsub_accept(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub),
+			       rdata, 200, NULL) != PJ_SUCCESS) {
+		ast_log(LOG_WARNING, "Unable to accept the incoming extension state subscription.\n");
+		pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
+		return NULL;
+	}
+
+	send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_ACTIVE);
+	return exten_state_sub->sip_sub;
+}
+
+static void resubscribe(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
+			struct ast_sip_subscription_response_data *response_data)
+{
+	struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
+
+	if (!exten_state_sub) {
+		return;
+	}
+
+	send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_ACTIVE);
+}
+
+static void subscription_timeout(struct ast_sip_subscription *sub)
+{
+	struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
+
+	if (!exten_state_sub) {
+		return;
+	}
+
+	ast_verbose(VERBOSE_PREFIX_3 "Subscription has timed out.\n");
+	send_notify(exten_state_sub, "timeout", PJSIP_EVSUB_STATE_TERMINATED);
+}
+
+static void subscription_terminated(struct ast_sip_subscription *sub,
+				    pjsip_rx_data *rdata)
+{
+	struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
+
+	if (!exten_state_sub) {
+		return;
+	}
+
+	ast_verbose(VERBOSE_PREFIX_3 "Subscription has been terminated.\n");
+	send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_TERMINATED);
+}
+
+static void to_ami(struct ast_sip_subscription *sub,
+		   struct ast_str **buf)
+{
+	struct exten_state_subscription *exten_state_sub =
+		get_exten_state_sub(sub);
+
+	ast_str_append(buf, 0, "SubscriptionType: extension_state\r\n"
+		       "Extension: %s\r\nExtensionStates: %s\r\n",
+		       exten_state_sub->exten, ast_extension_state2str(
+			       exten_state_sub->last_exten_state));
+}
+
 static int load_module(void)
 {
 	if (ast_sip_register_subscription_handler(&presence_handler)) {

Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c Mon Jan 20 17:58:12 2014
@@ -32,7 +32,6 @@
 
 #include "asterisk/module.h"
 #include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_exten_state.h"
 #include "asterisk/res_pjsip_pubsub.h"
 #include "asterisk/res_pjsip_xml.h"
 #include "asterisk/res_pjsip_body_generator_types.h"

Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c Mon Jan 20 17:58:12 2014
@@ -31,7 +31,6 @@
 
 #include "asterisk/module.h"
 #include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_exten_state.h"
 #include "asterisk/res_pjsip_pubsub.h"
 #include "asterisk/res_pjsip_xml.h"
 #include "asterisk/res_pjsip_body_generator_types.h"
@@ -111,11 +110,11 @@
 
 static void *pidf_allocate_body(void *data)
 {
-	struct exten_state_body_generator_data *gen_data = data;
+	struct ast_sip_exten_state_data *state_data = data;
 	pjpidf_pres *pres;
 	pj_str_t entity;
 
-	pres = pjpidf_create(gen_data->pool, pj_cstr(&entity, gen_data->local));
+	pres = pjpidf_create(state_data->pool, pj_cstr(&entity, state_data->local));
 
 	return pres;
 }
@@ -128,27 +127,27 @@
 	int local_state;
 	char sanitized[PJSIP_MAX_URL_SIZE];
 	pjpidf_pres *pres = body;
-	struct exten_state_body_generator_data *gen_data = data;
-
-	exten_state_to_str(gen_data->exten_data->exten_state, &statestring, &pidfstate,
+	struct ast_sip_exten_state_data *state_data = data;
+
+	exten_state_to_str(state_data->exten_state, &statestring, &pidfstate,
 			   &pidfnote, &local_state);
 
-	add_non_standard(gen_data->pool, pres, pidfstate);
-
-	if (!pjpidf_pres_add_note(gen_data->pool, pres, pj_cstr(&note, pidfnote))) {
+	add_non_standard(state_data->pool, pres, pidfstate);
+
+	if (!pjpidf_pres_add_note(state_data->pool, pres, pj_cstr(&note, pidfnote))) {
 		ast_log(LOG_WARNING, "Unable to add note to PIDF presence\n");
 		return -1;
 	}
 
-	if (!(tuple = pjpidf_pres_add_tuple(gen_data->pool, pres,
-					pj_cstr(&id, gen_data->exten_data->exten)))) {
+	if (!(tuple = pjpidf_pres_add_tuple(state_data->pool, pres,
+					pj_cstr(&id, state_data->exten)))) {
 		ast_log(LOG_WARNING, "Unable to create PIDF tuple\n");
 		return -1;
 	}
 
-	sanitize_xml(gen_data->remote, sanitized, sizeof(sanitized));
-	pjpidf_tuple_set_contact(gen_data->pool, tuple, pj_cstr(&contact, sanitized));
-	pjpidf_tuple_set_contact_prio(gen_data->pool, tuple, pj_cstr(&priority, "1"));
+	sanitize_xml(state_data->remote, sanitized, sizeof(sanitized));
+	pjpidf_tuple_set_contact(state_data->pool, tuple, pj_cstr(&contact, sanitized));
+	pjpidf_tuple_set_contact_prio(state_data->pool, tuple, pj_cstr(&priority, "1"));
 	pjpidf_status_set_basic_open(pjpidf_tuple_get_status(tuple),
 				     (pidfstate[0] == 'b') || (local_state != NOTIFY_CLOSED));
 

Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c Mon Jan 20 17:58:12 2014
@@ -32,54 +32,53 @@
 
 #include "asterisk/module.h"
 #include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_exten_state.h"
 #include "asterisk/res_pjsip_pubsub.h"
 #include "asterisk/res_pjsip_xml.h"
 #include "asterisk/res_pjsip_body_generator_types.h"
 
 static void *xpidf_allocate_body(void *data)
 {
-	struct exten_state_body_generator_data *gen_data = data;
+	struct ast_sip_exten_state_data *state_data = data;
 	pjxpidf_pres *pres;
 	pj_str_t name;
 
-	pres = pjxpidf_create(gen_data->pool, pj_cstr(&name, gen_data->local));
+	pres = pjxpidf_create(state_data->pool, pj_cstr(&name, state_data->local));
 	return pres;
 }
 
 static int xpidf_generate_body_content(void *body, void *data)
 {
 	pjxpidf_pres *pres = body;
-	struct exten_state_body_generator_data *gen_data = data;
+	struct ast_sip_exten_state_data *state_data = data;
 	static pj_str_t STR_ADDR_PARAM = { ";user=ip", 8 };
 	char *statestring = NULL, *pidfstate = NULL, *pidfnote = NULL;
 	pj_xml_attr *attr;
 	int local_state;
 	pj_str_t name, uri;
 
-	exten_state_to_str(gen_data->exten_data->exten_state, &statestring, &pidfstate,
+	exten_state_to_str(state_data->exten_state, &statestring, &pidfstate,
 			   &pidfnote, &local_state);
 
-	attr = find_node_attr(gen_data->pool, pres, "atom", "id");
-	pj_strdup2(gen_data->pool, &attr->value, gen_data->exten_data->exten);
+	attr = find_node_attr(state_data->pool, pres, "atom", "id");
+	pj_strdup2(state_data->pool, &attr->value, state_data->exten);
 
-	attr = find_node_attr(gen_data->pool, pres, "address", "uri");
+	attr = find_node_attr(state_data->pool, pres, "address", "uri");
 
-	uri.ptr = (char*) pj_pool_alloc(gen_data->pool, strlen(gen_data->remote) + STR_ADDR_PARAM.slen);
-	pj_strcpy2( &uri, gen_data->remote);
+	uri.ptr = (char*) pj_pool_alloc(state_data->pool, strlen(state_data->remote) + STR_ADDR_PARAM.slen);
+	pj_strcpy2( &uri, state_data->remote);
 	pj_strcat( &uri, &STR_ADDR_PARAM);
-	pj_strdup(gen_data->pool, &attr->value, &uri);
+	pj_strdup(state_data->pool, &attr->value, &uri);
 
-	create_attr(gen_data->pool, pj_xml_find_node(pres, pj_cstr(&name, "address")),
+	create_attr(state_data->pool, pj_xml_find_node(pres, pj_cstr(&name, "address")),
 		    "priority", "0.80000");
 
-	attr = find_node_attr(gen_data->pool, pres, "status", "status");
-	pj_strdup2(gen_data->pool, &attr->value,
+	attr = find_node_attr(state_data->pool, pres, "status", "status");
+	pj_strdup2(state_data->pool, &attr->value,
 		   (local_state ==  NOTIFY_OPEN) ? "open" :
 		   (local_state == NOTIFY_INUSE) ? "inuse" : "closed");
 
-	attr = find_node_attr(gen_data->pool, pres, "msnsubstatus", "substatus");
-	pj_strdup2(gen_data->pool, &attr->value,
+	attr = find_node_attr(state_data->pool, pres, "msnsubstatus", "substatus");
+	pj_strdup2(state_data->pool, &attr->value,
 		   (local_state == NOTIFY_OPEN) ? "online" :
 		   (local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
 




More information about the svn-commits mailing list