Exemplo n.º 1
0
static struct mwi_subscription *mwi_subscribe_single(
	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub, const char *name)
{
	RAII_VAR(struct ast_sip_aor *, aor,
		 ast_sip_location_retrieve_aor(name), ao2_cleanup);
	struct mwi_subscription *sub;

	if (!aor) {
		/*! I suppose it's possible for the AOR to disappear on us
		 * between accepting the subscription and sending the first
		 * NOTIFY...
		 */
		ast_log(LOG_WARNING, "Unable to locate aor %s. MWI "
			"subscription failed.\n", name);
		return NULL;
	}

	if (!(sub = mwi_create_subscription(endpoint, sip_sub))) {
		return NULL;
	}

	mwi_on_aor(aor, sub, 0);
	return sub;
}
Exemplo n.º 2
0
static void send_mwi_notify(struct mwi_subscription *sub)
{
	struct ast_sip_message_accumulator counter = {
		.old_msgs = 0,
		.new_msgs = 0,
	};
	struct ast_sip_body_data data = {
		.body_type = AST_SIP_MESSAGE_ACCUMULATOR,
		.body_data = &counter,
	};

	ao2_callback(sub->stasis_subs, OBJ_NODATA, get_message_count, &counter);

	if (sub->is_solicited) {
		ast_sip_subscription_notify(sub->sip_sub, &data, 0);
		return;
	}

	send_unsolicited_mwi_notify(sub, &counter);
}

static int unsubscribe_stasis(void *obj, void *arg, int flags)
{
	struct mwi_stasis_subscription *mwi_stasis = obj;
	if (mwi_stasis->stasis_sub) {
		ast_debug(3, "Removing stasis subscription to mailbox %s\n", mwi_stasis->mailbox);
		mwi_stasis->stasis_sub = stasis_unsubscribe_and_join(mwi_stasis->stasis_sub);
	}
	return CMP_MATCH;
}

static void mwi_subscription_shutdown(struct ast_sip_subscription *sub)
{
	struct mwi_subscription *mwi_sub;
	struct ast_datastore *mwi_datastore;

	mwi_datastore = ast_sip_subscription_get_datastore(sub, MWI_DATASTORE);
	if (!mwi_datastore) {
		return;
	}

	mwi_sub = mwi_datastore->data;
	ao2_callback(mwi_sub->stasis_subs, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, unsubscribe_stasis, NULL);
	ast_sip_subscription_remove_datastore(sub, MWI_DATASTORE);

	ao2_ref(mwi_datastore, -1);
}

static void mwi_ds_destroy(void *data)
{
	struct mwi_subscription *sub = data;

	ao2_ref(sub, -1);
}

static struct ast_datastore_info mwi_ds_info = {
	.destroy = mwi_ds_destroy,
};

static int add_mwi_datastore(struct mwi_subscription *sub)
{
	struct ast_datastore *mwi_datastore;
	int res;

	mwi_datastore = ast_sip_subscription_alloc_datastore(&mwi_ds_info, MWI_DATASTORE);
	if (!mwi_datastore) {
		return -1;
	}
	ao2_ref(sub, +1);
	mwi_datastore->data = sub;

	/*
	 * NOTE:  Adding the datastore to the subscription creates a ref loop
	 * that must be manually broken.
	 */
	res = ast_sip_subscription_add_datastore(sub->sip_sub, mwi_datastore);
	ao2_ref(mwi_datastore, -1);
	return res;
}

/*!
 * \brief Determines if an endpoint is receiving unsolicited MWI for a particular mailbox.
 *
 * \param endpoint The endpoint to check
 * \param mailbox The candidate mailbox
 * \retval 0 The endpoint does not receive unsolicited MWI for this mailbox
 * \retval 1 The endpoint receives unsolicited MWI for this mailbox
 */
static int endpoint_receives_unsolicited_mwi_for_mailbox(struct ast_sip_endpoint *endpoint,
		const char *mailbox)
{
	struct ao2_iterator *mwi_subs;
	struct mwi_subscription *mwi_sub;
	const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
	int ret = 0;

	mwi_subs = ao2_find(unsolicited_mwi, endpoint_id, OBJ_SEARCH_KEY | OBJ_MULTIPLE);

	if (!mwi_subs) {
		return 0;
	}

	for (; (mwi_sub = ao2_iterator_next(mwi_subs)) && !ret; ao2_cleanup(mwi_sub)) {
		struct mwi_stasis_subscription *mwi_stasis;

		mwi_stasis = ao2_find(mwi_sub->stasis_subs, mailbox, OBJ_SEARCH_KEY);
		if (mwi_stasis) {
			ret = 1;
			ao2_cleanup(mwi_stasis);
		}
	}

	ao2_iterator_destroy(mwi_subs);
	return ret;
}

/*!
 * \brief Determine if an endpoint is a candidate to be able to subscribe for MWI
 *
 * Currently, this just makes sure that the endpoint is not already receiving unsolicted
 * MWI for any of an AOR's configured mailboxes.
 *
 * \param obj The AOR to which the endpoint is subscribing.
 * \param arg The endpoint that is attempting to subscribe.
 * \param flags Unused.
 * \retval 0 Endpoint is a candidate to subscribe to MWI on the AOR.
 * \retval -1 The endpoint cannot subscribe to MWI on the AOR.
 */
static int mwi_validate_for_aor(void *obj, void *arg, int flags)
{
	struct ast_sip_aor *aor = obj;
	struct ast_sip_endpoint *endpoint = arg;
	char *mailboxes;
	char *mailbox;

	if (ast_strlen_zero(aor->mailboxes)) {
		return 0;
	}

	mailboxes = ast_strdupa(aor->mailboxes);
	while ((mailbox = strsep(&mailboxes, ","))) {
		if (endpoint_receives_unsolicited_mwi_for_mailbox(endpoint, mailbox)) {
			ast_log(LOG_NOTICE, "Endpoint '%s' already configured for unsolicited MWI for mailbox '%s'. "
					"Denying MWI subscription to %s\n", ast_sorcery_object_get_id(endpoint), mailbox,
					ast_sorcery_object_get_id(aor));
			return -1;
		}
	}

	return 0;
}

static int mwi_on_aor(void *obj, void *arg, int flags)
{
	struct ast_sip_aor *aor = obj;
	struct mwi_subscription *sub = arg;
	char *mailboxes;
	char *mailbox;

	if (ast_strlen_zero(aor->mailboxes)) {
		return 0;
	}

	mailboxes = ast_strdupa(aor->mailboxes);
	while ((mailbox = strsep(&mailboxes, ","))) {
		struct mwi_stasis_subscription *mwi_stasis_sub;

		mwi_stasis_sub = mwi_stasis_subscription_alloc(mailbox, sub);
		if (!mwi_stasis_sub) {
			continue;
		}

		ao2_link(sub->stasis_subs, mwi_stasis_sub);
		ao2_ref(mwi_stasis_sub, -1);
	}

	return 0;
}

static struct mwi_subscription *mwi_create_subscription(
	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub)
{
	struct mwi_subscription *sub = mwi_subscription_alloc(endpoint, 1, sip_sub);

	if (!sub) {
		return NULL;
	}

	if (add_mwi_datastore(sub)) {
		ast_log(LOG_WARNING, "Unable to add datastore for MWI subscription to %s\n",
			sub->id);
		ao2_ref(sub, -1);
		return NULL;
	}

	return sub;
}

static struct mwi_subscription *mwi_subscribe_single(
	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub, const char *name)
{
	struct ast_sip_aor *aor;
	struct mwi_subscription *sub;

	aor = ast_sip_location_retrieve_aor(name);
	if (!aor) {
		/*! I suppose it's possible for the AOR to disappear on us
		 * between accepting the subscription and sending the first
		 * NOTIFY...
		 */
		ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n",
			name);
		return NULL;
	}

	sub = mwi_create_subscription(endpoint, sip_sub);
	if (sub) {
		mwi_on_aor(aor, sub, 0);
	}

	ao2_ref(aor, -1);
	return sub;
}

static struct mwi_subscription *mwi_subscribe_all(
	struct ast_sip_endpoint *endpoint, struct ast_sip_subscription *sip_sub)
{
	struct mwi_subscription *sub;

	sub = mwi_create_subscription(endpoint, sip_sub);
	if (!sub) {
		return NULL;
	}

	ast_sip_for_each_aor(endpoint->aors, mwi_on_aor, sub);
	return sub;
}

static int mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
		const char *resource)
{
	RAII_VAR(struct ast_sip_aor *, aor, NULL, ao2_cleanup);

	if (ast_strlen_zero(resource)) {
		if (ast_sip_for_each_aor(endpoint->aors, mwi_validate_for_aor, endpoint)) {
			return 500;
		}
		return 200;
	}

	aor = ast_sip_location_retrieve_aor(resource);
	if (!aor) {
		ast_log(LOG_WARNING, "Unable to locate aor %s. MWI subscription failed.\n",
			resource);
		return 404;
	}

	if (ast_strlen_zero(aor->mailboxes)) {
		ast_log(LOG_NOTICE, "AOR %s has no configured mailboxes. MWI subscription failed.\n",
			resource);
		return 404;
	}

	if (mwi_validate_for_aor(aor, endpoint, 0)) {
		return 500;
	}

	return 200;
}