Exemple #1
0
static int create_test_dialplan(void)
{
	int res = 0;

	test_message_context = ast_context_find_or_create(NULL, NULL, TEST_CONTEXT, AST_MODULE);
	if (!test_message_context) {
		return -1;
	}

	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 1, NULL, NULL,
	                         "UserEvent", "TestMessageUnitTest,Verify:To,Value:${MESSAGE(to)}",
	                         NULL, AST_MODULE);
	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 2, NULL, NULL,
	                         "UserEvent", "TestMessageUnitTest,Verify:From,Value:${MESSAGE(from)}",
	                         NULL, AST_MODULE);
	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 3, NULL, NULL,
	                         "UserEvent", "TestMessageUnitTest,Verify:Body,Value:${MESSAGE(body)}",
	                         NULL, AST_MODULE);
	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 4, NULL, NULL,
	                         "UserEvent", "TestMessageUnitTest,Verify:Custom,Value:${MESSAGE_DATA(custom_data)}",
	                         NULL, AST_MODULE);
	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 5, NULL, NULL,
	                         "Set", "MESSAGE_DATA(custom_data)=${MESSAGE_DATA(custom_data)}",
	                         NULL, AST_MODULE);
	res |= ast_add_extension(TEST_CONTEXT, 0, TEST_EXTENSION, 6, NULL, NULL,
	                         "MessageSend", "testmsg:${MESSAGE(from)},testmsg:${MESSAGE(to)}",
	                         NULL, AST_MODULE);

	ast_manager_register_hook(&user_event_hook);

	return res;
}
Exemple #2
0
/*!
 * \brief Register dialplan switches for our pbx_lua contexs.
 *
 * In the event of an error, an error string will be pushed onto the lua stack.
 *
 * \retval 0 success
 * \retval 1 failure
 */
static int lua_register_switches(lua_State *L)
{
	int extensions;
	struct ast_context *con = NULL;

	/* create the hash table for our contexts */
	/* XXX do we ever need to destroy this? pbx_config does not */
	if (!local_table)
		local_table = ast_hashtab_create(17, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);

	/* load the 'extensions' table */
	lua_getglobal(L, "extensions");
	extensions = lua_gettop(L);
	if (lua_isnil(L, -1)) {
		lua_pop(L, 1);
		lua_pushstring(L, "Unable to find 'extensions' table in extensions.lua\n");
		return 1;
	}

	/* iterate through the extensions table and register a context and
	 * dialplan switch for each lua context
	 */
	for (lua_pushnil(L); lua_next(L, extensions); lua_pop(L, 1)) {
		int context = lua_gettop(L);
		int context_name = context - 1;
		const char *context_str = lua_tostring(L, context_name);

		/* find or create this context */
		con = ast_context_find_or_create(&local_contexts, local_table, context_str, registrar);
		if (!con) {
			/* remove extensions table and context key and value */
			lua_pop(L, 3);
			lua_pushstring(L, "Failed to find or create context\n");
			return 1;
		}

		/* register the switch */
		if (ast_context_add_switch2(con, "Lua", "", 0, registrar)) {
			/* remove extensions table and context key and value */
			lua_pop(L, 3);
			lua_pushstring(L, "Unable to create switch for context\n");
			return 1;
		}
	}
	
	/* remove the extensions table */
	lua_pop(L, 1);
	return 0;
}
Exemple #3
0
struct stasis_app *app_create(const char *name, stasis_app_cb handler, void *data, enum stasis_app_subscription_model subscription_model)
{
	RAII_VAR(struct stasis_app *, app, NULL, ao2_cleanup);
	size_t size;
	int res = 0;
	size_t context_size = strlen("stasis-") + strlen(name) + 1;
	char context_name[context_size];

	ast_assert(name != NULL);
	ast_assert(handler != NULL);

	ast_verb(1, "Creating Stasis app '%s'\n", name);

	size = sizeof(*app) + strlen(name) + 1;
	app = ao2_alloc_options(size, app_dtor, AO2_ALLOC_OPT_LOCK_MUTEX);
	if (!app) {
		return NULL;
	}
	app->subscription_model = subscription_model;

	app->forwards = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_MUTEX,
		AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT,
		forwards_sort, NULL);
	if (!app->forwards) {
		return NULL;
	}

	app->topic = stasis_topic_create(name);
	if (!app->topic) {
		return NULL;
	}

	app->bridge_router = stasis_message_router_create(ast_bridge_topic_all());
	if (!app->bridge_router) {
		return NULL;
	}

	res |= stasis_message_router_add(app->bridge_router,
		ast_bridge_merge_message_type(), bridge_merge_handler, app);

	res |= stasis_message_router_add(app->bridge_router,
		ast_blind_transfer_type(), bridge_blind_transfer_handler, app);

	res |= stasis_message_router_add(app->bridge_router,
		ast_attended_transfer_type(), bridge_attended_transfer_handler, app);

	res |= stasis_message_router_add(app->bridge_router,
		stasis_subscription_change_type(), bridge_subscription_change_handler, app);

	if (res != 0) {
		return NULL;
	}
	/* Bridge router holds a reference */
	ao2_ref(app, +1);

	app->router = stasis_message_router_create(app->topic);
	if (!app->router) {
		return NULL;
	}

	res |= stasis_message_router_add(app->router,
		ast_bridge_snapshot_type(), sub_bridge_update_handler, app);

	res |= stasis_message_router_add(app->router,
		ast_channel_snapshot_type(), sub_channel_update_handler, app);

	res |= stasis_message_router_add_cache_update(app->router,
		ast_endpoint_snapshot_type(), sub_endpoint_update_handler, app);

	res |= stasis_message_router_add(app->router,
		stasis_subscription_change_type(), sub_subscription_change_handler, app);

	stasis_message_router_set_formatters_default(app->router,
		sub_default_handler, app, STASIS_SUBSCRIPTION_FORMATTER_JSON);

	if (res != 0) {
		return NULL;
	}
	/* Router holds a reference */
	ao2_ref(app, +1);

	strncpy(app->name, name, size - sizeof(*app));
	app->handler = handler;
	app->data = ao2_bump(data);

	/* Create a context, a match-all extension, and a 'h' extension for this application. Note that
	 * this should only be done if a context does not already exist. */
	strcpy(context_name, "stasis-");
	strcat(context_name, name);
	if (!ast_context_find(context_name)) {
		if (!ast_context_find_or_create(NULL, NULL, context_name, "res_stasis")) {
			ast_log(LOG_WARNING, "Could not create context '%s' for Stasis application '%s'\n", context_name, name);
		} else {
			ast_add_extension(context_name, 0, "_.", 1, NULL, NULL, "Stasis", ast_strdup(name), ast_free_ptr, "res_stasis");
			ast_add_extension(context_name, 0, "h", 1, NULL, NULL, "NoOp", NULL, NULL, "res_stasis");
		}
	} else {
		ast_log(LOG_WARNING, "Not creating context '%s' for Stasis application '%s' because it already exists\n",
			context_name, name);
	}

	ao2_ref(app, +1);
	return app;
}
Exemple #4
0
/*!
 * \brief Register dialplan hints for our pbx_lua contexs.
 *
 * In the event of an error, an error string will be pushed onto the lua stack.
 *
 * \retval 0 success
 * \retval 1 failure
 */
static int lua_register_hints(lua_State *L)
{
	int hints;
	struct ast_context *con = NULL;

	/* create the hash table for our contexts */
	/* XXX do we ever need to destroy this? pbx_config does not */
	if (!local_table)
		local_table = ast_hashtab_create(17, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);

	/* load the 'hints' table */
	lua_getglobal(L, "hints");
	hints = lua_gettop(L);
	if (lua_isnil(L, -1)) {
		/* hints table not found, move along */
		lua_pop(L, 1);
		return 0;
	}

	/* iterate through the hints table and register each context and
	 * the hints that go along with it
	 */
	for (lua_pushnil(L); lua_next(L, hints); lua_pop(L, 1)) {
		int context = lua_gettop(L);
		int context_name = context - 1;
		const char *context_str = lua_tostring(L, context_name);

		/* find or create this context */
		con = ast_context_find_or_create(&local_contexts, local_table, context_str, registrar);
		if (!con) {
			/* remove hints table and context key and value */
			lua_pop(L, 3);
			lua_pushstring(L, "Failed to find or create context\n");
			return 1;
		}

		/* register each hint */
		for (lua_pushnil(L); lua_next(L, context); lua_pop(L, 1)) {
			const char *hint_value = lua_tostring(L, -1);
			const char *hint_name;

			/* the hint value is not a string, ignore it */
			if (!hint_value) {
				continue;
			}

			/* copy the name then convert it to a string */
			lua_pushvalue(L, -2);
			if (!(hint_name = lua_tostring(L, -1))) {
				/* ignore non-string value */
				lua_pop(L, 1);
				continue;
			}

			if (ast_add_extension2(con, 0, hint_name, PRIORITY_HINT, NULL, NULL, hint_value, NULL, NULL, registrar)) {
				/* remove hints table, hint name, hint value,
				 * key copy, context name, and contex table */
				lua_pop(L, 6);
				lua_pushstring(L, "Error creating hint\n");
				return 1;
			}

			/* pop the name copy */
			lua_pop(L, 1);
		}
	}

	/* remove the hints table */
	lua_pop(L, 1);

	return 0;
}
/*! \internal
 * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
 *
 * \param bridge_channel bridge channel this interval hook is being executed on
 * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
 */
static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
	struct parked_user *user = hook_pvt;
	struct ast_channel *chan = user->chan;
	struct ast_context *park_dial_context;
	const char *dial_string;
	char *dial_string_flat;
	char parking_space[AST_MAX_EXTENSION];

	char returnexten[AST_MAX_EXTENSION];
	char *duplicate_returnexten;
	struct ast_exten *existing_exten;
	struct pbx_find_info pbx_finder = { .stacklen = 0 }; /* The rest is reset in pbx_find_extension */


	/* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
	   to deal with this, lock the parked user, check and set resolution. */
	ao2_lock(user);
	if (user->resolution != PARK_UNSET) {
		/* Abandon timeout since something else has resolved the parked user before we got to it. */
		ao2_unlock(user);
		return -1;
	}
	user->resolution = PARK_TIMEOUT;
	ao2_unlock(user);

	ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
		AST_CAUSE_NORMAL_CLEARING);

	dial_string = user->parker_dial_string;
	dial_string_flat = ast_strdupa(dial_string);
	flatten_dial_string(dial_string_flat);

	/* Set parking timeout channel variables */
	snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
	ast_channel_lock(chan);
	ast_channel_stage_snapshot(chan);
	pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
	pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */
	pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
	pbx_builtin_setvar_helper(chan, "PARKER", dial_string);
	pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat);
	parking_timeout_set_caller_features(chan, user->lot->cfg);
	ast_channel_stage_snapshot_done(chan);
	ast_channel_unlock(chan);

	/* Dialplan generation for park-dial extensions */

	if (ast_wrlock_contexts()) {
		ast_log(LOG_ERROR, "Failed to lock the contexts list. Can't add the park-dial extension.\n");
		return -1;
	}

	if (!(park_dial_context = ast_context_find_or_create(NULL, NULL, PARK_DIAL_CONTEXT, BASE_REGISTRAR))) {
		ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", PARK_DIAL_CONTEXT);
		if (ast_unlock_contexts()) {
			ast_assert(0);
		}
		goto abandon_extension_creation;
	}

	if (ast_wrlock_context(park_dial_context)) {
		ast_log(LOG_ERROR, "failed to obtain write lock on context '%s'\n", PARK_DIAL_CONTEXT);
		if (ast_unlock_contexts()) {
			ast_assert(0);
		}
		goto abandon_extension_creation;
	}

	if (ast_unlock_contexts()) {
		ast_assert(0);
	}

	snprintf(returnexten, sizeof(returnexten), "%s,%u", dial_string,
		user->lot->cfg->comebackdialtime);

	duplicate_returnexten = ast_strdup(returnexten);
	if (!duplicate_returnexten) {
		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
	}

	/* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */
	if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) &&
	    (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
		ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n",
			dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
	} else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL,
			"Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR)) {
			ast_free(duplicate_returnexten);
		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
	}

	if (ast_unlock_context(park_dial_context)) {
		ast_assert(0);
	}

abandon_extension_creation:

	/* async_goto the proper PBX destination - this should happen when we come out of the bridge */
	if (!ast_strlen_zero(user->comeback)) {
		ast_async_parseable_goto(chan, user->comeback);
	} else {
		comeback_goto(user, user->lot);
	}

	return -1;
}

void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
{
	unsigned int numeric_value;
	unsigned int hangup_after;

	if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
		/* If say_parking_space is called with a non-numeric string, we have a problem. */
		ast_assert(0);
		ast_bridge_channel_leave_bridge(bridge_channel,
			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
		return;
	}

	ast_say_digits(bridge_channel->chan, numeric_value, "",
		ast_channel_language(bridge_channel->chan));

	if (hangup_after) {
		ast_bridge_channel_leave_bridge(bridge_channel,
			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
	}
}