Пример #1
0
static int mute_channel(struct ast_channel *chan, const char *direction, int mute)
{
	unsigned int mute_direction = 0;
	enum ast_frame_type frametype = AST_FRAME_VOICE;
	int ret = 0;

	if (!strcmp(direction, "in")) {
		mute_direction = AST_MUTE_DIRECTION_READ;
	} else if (!strcmp(direction, "out")) {
		mute_direction = AST_MUTE_DIRECTION_WRITE;
	} else if (!strcmp(direction, "all")) {
		mute_direction = AST_MUTE_DIRECTION_READ | AST_MUTE_DIRECTION_WRITE;
	} else {
		return -1;
	}

	ast_channel_lock(chan);

	if (mute) {
		ret = ast_channel_suppress(chan, mute_direction, frametype);
	} else {
		ret = ast_channel_unsuppress(chan, mute_direction, frametype);
	}

	ast_channel_unlock(chan);

	return ret;
}
Пример #2
0
int control_prestart_dispatch_all(struct stasis_app_control *control,
	struct ast_channel *chan)
{
	struct ao2_container *command_queue;
	int count = 0;
	struct ao2_iterator iter;
	struct stasis_app_command *command;

	ast_channel_lock(chan);
	command_queue = command_prestart_get_container(chan);
	ast_channel_unlock(chan);
	if (!command_queue) {
		return 0;
	}

	iter = ao2_iterator_init(command_queue, AO2_ITERATOR_UNLINK);

	while ((command = ao2_iterator_next(&iter))) {
		command_invoke(command, control, chan);
		ao2_cleanup(command);
		++count;
	}

	ao2_iterator_destroy(&iter);
	ao2_cleanup(command_queue);
	return count;
}
Пример #3
0
/*!
 * \brief Dial timeout
 *
 * This is a bridge interval hook callback. The interval hook triggering
 * means that the dial timeout has been reached. If the channel has not
 * been answered by the time this callback is called, then the channel
 * is hung up
 *
 * \param bridge_channel Bridge channel on which interval hook has been called
 * \param ignore Ignored
 * \return -1 (i.e. remove the interval hook)
 */
static int bridge_timeout(struct ast_bridge_channel *bridge_channel, void *ignore)
{
	struct ast_datastore *datastore;
	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);

	control = stasis_app_control_find_by_channel(bridge_channel->chan);

	ast_channel_lock(bridge_channel->chan);
	if (ast_channel_state(bridge_channel->chan) != AST_STATE_UP) {
		/* Don't bother removing the datastore because it will happen when the channel is hung up */
		ast_channel_unlock(bridge_channel->chan);
		stasis_app_send_command_async(control, hangup_channel, NULL, NULL);
		return -1;
	}

	datastore = ast_channel_datastore_find(bridge_channel->chan, &timeout_datastore, NULL);
	if (!datastore) {
		ast_channel_unlock(bridge_channel->chan);
		return -1;
	}
	ast_channel_datastore_remove(bridge_channel->chan, datastore);
	ast_channel_unlock(bridge_channel->chan);
	ast_datastore_free(datastore);

	return -1;
}
/*!
 * \internal
 * \since 12.0.0
 * \brief Park a call
 *
 * \param parker The bridge_channel parking the call
 * \param exten Optional. The extension where the call was parked.
 * \param length Optional. If \c exten is specified, the length of the buffer.
 *
 * \note This will determine the context and extension to park the channel based on
 * the configuration of the \ref ast_channel associated with \ref parker. It will then
 * park either the channel or the entire bridge.
 *
 * \retval 0 on success
 * \retval -1 on error
 */
static int parking_park_call(struct ast_bridge_channel *parker, char *exten, size_t length)
{
	RAII_VAR(struct parking_lot *, lot, NULL, ao2_cleanup);
	const char *lot_name = NULL;

	ast_channel_lock(parker->chan);
	lot_name = find_channel_parking_lot_name(parker->chan);
	if (!ast_strlen_zero(lot_name)) {
		lot_name = ast_strdupa(lot_name);
	}
	ast_channel_unlock(parker->chan);

	if (ast_strlen_zero(lot_name)) {
		return -1;
	}

	lot = parking_lot_find_by_name(lot_name);
	if (!lot) {
		ast_log(AST_LOG_WARNING, "Cannot Park %s: lot %s unknown\n",
			ast_channel_name(parker->chan), lot_name);
		return -1;
	}

	if (exten) {
		ast_copy_string(exten, lot->cfg->parkext, length);
	}
	return parking_blind_transfer_park(parker, lot->cfg->parking_con, lot->cfg->parkext, NULL, NULL);
}
Пример #5
0
static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
{
	if (!chanspy_ds)
		return NULL;

	ast_mutex_lock(&chanspy_ds->lock);
	if (chanspy_ds->chan) {
		struct ast_datastore *datastore;
		struct ast_channel *chan;

		chan = chanspy_ds->chan;

		ast_channel_lock(chan);
		if ((datastore = ast_channel_datastore_find(chan, &chanspy_ds_info, chanspy_ds->unique_id))) {
			ast_channel_datastore_remove(chan, datastore);
			/* chanspy_ds->chan is NULL after this call */
			chanspy_ds_destroy(datastore->data);
			datastore->data = NULL;
			ast_channel_datastore_free(datastore);
		}
		ast_channel_unlock(chan);
	}
	ast_mutex_unlock(&chanspy_ds->lock);

	return NULL;
}
Пример #6
0
static int sendtext_exec(struct ast_channel *chan, const char *data)
{
	char *status = "UNSUPPORTED";
	struct ast_str *str;

	/* NOT ast_strlen_zero, because some protocols (e.g. SIP) MUST be able to
	 * send a zero-length message. */
	if (!data) {
		ast_log(LOG_WARNING, "SendText requires an argument (text)\n");
		return -1;
	}

	if (!(str = ast_str_alloca(strlen(data) + 1))) {
		return -1;
	}

	ast_str_get_encoded_str(&str, -1, data);

	ast_channel_lock(chan);
	if (!ast_channel_tech(chan)->send_text) {
		ast_channel_unlock(chan);
		/* Does not support transport */
		pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status);
		return 0;
	}
	status = "FAILURE";
	if (!ast_sendtext(chan, ast_str_buffer(str))) {
		status = "SUCCESS";
	}
	ast_channel_unlock(chan);
	pbx_builtin_setvar_helper(chan, "SENDTEXTSTATUS", status);
	return 0;
}
Пример #7
0
/*! \brief SpeechCreate() Dialplan Application */
static int speech_create(struct ast_channel *chan, const char *data)
{
	struct ast_speech *speech = NULL;
	struct ast_datastore *datastore = NULL;

	/* Request a speech object */
	speech = ast_speech_new(data, ast_channel_nativeformats(chan));
	if (speech == NULL) {
		/* Not available */
		pbx_builtin_setvar_helper(chan, "ERROR", "1");
		return 0;
	}

	datastore = ast_datastore_alloc(&speech_datastore, NULL);
	if (datastore == NULL) {
		ast_speech_destroy(speech);
		pbx_builtin_setvar_helper(chan, "ERROR", "1");
		return 0;
	}
	pbx_builtin_setvar_helper(chan, "ERROR", NULL);
	datastore->data = speech;
	ast_channel_lock(chan);
	ast_channel_datastore_add(chan, datastore);
	ast_channel_unlock(chan);

	return 0;
}
Пример #8
0
/* Called with ast locked */
static int local_queryoption(struct ast_channel *ast, int option, void *data, int *datalen)
{
	struct local_pvt *p;
	struct ast_channel *bridged = NULL;
	struct ast_channel *tmp = NULL;
	int res = 0;

	if (option != AST_OPTION_T38_STATE) {
		/* AST_OPTION_T38_STATE is the only supported option at this time */
		return -1;
	}

	/* for some reason the channel is not locked in channel.c when this function is called */
	if (!(p = ast_channel_tech_pvt(ast))) {
		return -1;
	}

	ao2_lock(p);
	if (!(tmp = IS_OUTBOUND(ast, p) ? p->owner : p->chan)) {
		ao2_unlock(p);
		return -1;
	}
	ast_channel_ref(tmp);
	ao2_unlock(p);
	ast_channel_unlock(ast); /* Held when called, unlock before locking another channel */

	ast_channel_lock(tmp);
	if (!(bridged = ast_bridged_channel(tmp))) {
		res = -1;
		ast_channel_unlock(tmp);
		goto query_cleanup;
	}
	ast_channel_ref(bridged);
	ast_channel_unlock(tmp);

query_cleanup:
	if (bridged) {
		res = ast_channel_queryoption(bridged, option, data, datalen, 0);
		bridged = ast_channel_unref(bridged);
	}
	if (tmp) {
		tmp = ast_channel_unref(tmp);
	}
	ast_channel_lock(ast); /* Lock back before we leave */

	return res;
}
Пример #9
0
static void bridge_stasis_queue_join_action(struct ast_bridge *self,
	struct ast_bridge_channel *bridge_channel)
{
	ast_channel_lock(bridge_channel->chan);
	command_prestart_queue_command(bridge_channel->chan, add_channel_to_bridge,
		ao2_bump(self), __ao2_cleanup);
	ast_channel_unlock(bridge_channel->chan);
}
Пример #10
0
struct ast_channel *ast_pickup_find_by_group(struct ast_channel *chan)
{
	struct ao2_container *candidates;/*!< Candidate channels found to pickup. */
	struct ast_channel *target;/*!< Potential pickup target */

	candidates = ao2_container_alloc_options(AO2_ALLOC_OPT_LOCK_NOLOCK, 1, NULL, NULL);
	if (!candidates) {
		return NULL;
	}

	/* Find all candidate targets by group. */
	ast_channel_callback(find_channel_by_group, chan, candidates, 0);

	/* Find the oldest pickup target candidate */
	target = NULL;
	for (;;) {
		struct ast_channel *candidate;/*!< Potential new older target */
		struct ao2_iterator iter;

		iter = ao2_iterator_init(candidates, 0);
		while ((candidate = ao2_iterator_next(&iter))) {
			if (!target) {
				/* First target. */
				target = candidate;
				continue;
			}
			if (ast_tvcmp(ast_channel_creationtime(candidate), ast_channel_creationtime(target)) < 0) {
				/* We have a new target. */
				ast_channel_unref(target);
				target = candidate;
				continue;
			}
			ast_channel_unref(candidate);
		}
		ao2_iterator_destroy(&iter);
		if (!target) {
			/* No candidates found. */
			break;
		}

		/* The found channel must be locked and ref'd. */
		ast_channel_lock(target);

		/* Recheck pickup ability */
		if (ast_can_pickup(target)) {
			/* This is the channel to pickup. */
			break;
		}

		/* Someone else picked it up or the call went away. */
		ast_channel_unlock(target);
		ao2_unlink(candidates, target);
		target = ast_channel_unref(target);
	}
	ao2_ref(candidates, -1);

	return target;
}
Пример #11
0
/*! \brief Helper function which adds frame hook to bridge channel */
static int native_rtp_bridge_framehook_attach(struct ast_bridge_channel *bridge_channel)
{
	struct native_rtp_bridge_data *data = ao2_alloc(sizeof(*data), NULL);
	static struct ast_framehook_interface hook = {
		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
		.event_cb = native_rtp_framehook,
		.destroy_cb = __ao2_cleanup,
		.consume_cb = native_rtp_framehook_consume,
		.disable_inheritance = 1,
	};

	if (!data) {
		return -1;
	}

	ast_channel_lock(bridge_channel->chan);
	hook.data = ao2_bump(data);
	data->id = ast_framehook_attach(bridge_channel->chan, &hook);
	ast_channel_unlock(bridge_channel->chan);
	if (data->id < 0) {
		/* We need to drop both the reference we hold, and the one the framehook would hold */
		ao2_ref(data, -2);
		return -1;
	}

	bridge_channel->tech_pvt = data;

	return 0;
}

/*! \brief Helper function which removes frame hook from bridge channel */
static void native_rtp_bridge_framehook_detach(struct ast_bridge_channel *bridge_channel)
{
	RAII_VAR(struct native_rtp_bridge_data *, data, bridge_channel->tech_pvt, ao2_cleanup);

	if (!data) {
		return;
	}

	ast_channel_lock(bridge_channel->chan);
	ast_framehook_detach(bridge_channel->chan, data->id);
	data->detached = 1;
	ast_channel_unlock(bridge_channel->chan);
	bridge_channel->tech_pvt = NULL;
}
Пример #12
0
static int frame_trace_helper(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
	struct frame_trace_data *framedata;
	struct ast_datastore *datastore = NULL;
	struct ast_framehook_interface interface = {
		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
		.event_cb = hook_event_cb,
		.destroy_cb = hook_destroy_cb,
	};
	int i = 0;

	if (!(framedata = ast_calloc(1, sizeof(*framedata)))) {
		return 0;
	}

	interface.data = framedata;

	if (!strcasecmp(data, "black")) {
		framedata->list_type = 1;
	}
	for (i = 0; i < ARRAY_LEN(frametype2str); i++) {
		if (strcasestr(value, frametype2str[i].str)) {
			framedata->values[i] = 1;
		}
	}

	ast_channel_lock(chan);
	i = ast_framehook_attach(chan, &interface);
	if (i >= 0) {
		int *id;
		if ((datastore = ast_channel_datastore_find(chan, &frame_trace_datastore, NULL))) {
			id = datastore->data;
			ast_framehook_detach(chan, *id);
			ast_channel_datastore_remove(chan, datastore);
		}

		if (!(datastore = ast_datastore_alloc(&frame_trace_datastore, NULL))) {
			ast_framehook_detach(chan, i);
			ast_channel_unlock(chan);
			return 0;
		}

		if (!(id = ast_calloc(1, sizeof(int)))) {
			ast_datastore_free(datastore);
			ast_framehook_detach(chan, i);
			ast_channel_unlock(chan);
			return 0;
		}

		*id = i; /* Store off the id. The channel is still locked so it is safe to access this ptr. */
		datastore->data = id;
		ast_channel_datastore_add(chan, datastore);
	}
	ast_channel_unlock(chan);

	return 0;
}
Пример #13
0
/*! \brief Function called to attach T.38 framehook to channel when appropriate */
static void t38_attach_framehook(struct ast_sip_session *session)
{
	int framehook_id;
	struct ast_datastore *datastore = NULL;
	static struct ast_framehook_interface hook = {
		.version = AST_FRAMEHOOK_INTERFACE_VERSION,
		.event_cb = t38_framehook,
		.chan_fixup_cb = t38_masq,
		.chan_breakdown_cb = t38_masq,
	};

	/* Only attach the framehook if t38 is enabled for the endpoint */
	if (!session->endpoint->media.t38.enabled) {
		return;
	}

	/* Skip attaching the framehook if the T.38 datastore already exists for the channel */
	ast_channel_lock(session->channel);
	if ((datastore = ast_channel_datastore_find(session->channel, &t38_framehook_datastore, NULL))) {
		ast_channel_unlock(session->channel);
		return;
	}
	ast_channel_unlock(session->channel);

	framehook_id = ast_framehook_attach(session->channel, &hook);
	if (framehook_id < 0) {
		ast_log(LOG_WARNING, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n",
			ast_channel_name(session->channel));
		return;
	}

	ast_channel_lock(session->channel);
	datastore = ast_datastore_alloc(&t38_framehook_datastore, NULL);
	if (!datastore) {
		ast_log(LOG_ERROR, "Could not attach T.38 Frame hook to channel, T.38 will be unavailable on '%s'\n",
			ast_channel_name(session->channel));
		ast_framehook_detach(session->channel, framehook_id);
		ast_channel_unlock(session->channel);
		return;
	}

	ast_channel_datastore_add(session->channel, datastore);
	ast_channel_unlock(session->channel);
}
Пример #14
0
static void bridge_after_cb(struct ast_channel *chan, void *data)
{
	struct stasis_app_control *control = data;
	SCOPED_AO2LOCK(lock, control);
	struct ast_bridge_channel *bridge_channel;

	ast_debug(3, "%s, %s: Channel leaving bridge\n",
		ast_channel_uniqueid(chan), control->bridge->uniqueid);

	ast_assert(chan == control->channel);

	/* Restore the channel's PBX */
	ast_channel_pbx_set(control->channel, control->pbx);
	control->pbx = NULL;

	app_unsubscribe_bridge(control->app, control->bridge);

	/* No longer in the bridge */
	control->bridge = NULL;

	/* Get the bridge channel so we don't depart from the wrong bridge */
	ast_channel_lock(chan);
	bridge_channel = ast_channel_get_bridge_channel(chan);
	ast_channel_unlock(chan);

	/* Depart this channel from the bridge using the command queue if possible */
	stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup);
	if (stasis_app_channel_is_stasis_end_published(chan)) {
		/* The channel has had a StasisEnd published on it, but until now had remained in
		 * the bridging system. This means that the channel moved from a Stasis bridge to a
		 * non-Stasis bridge and is now exiting the bridging system. Because of this, the
		 * channel needs to exit the Stasis application and go to wherever the non-Stasis
		 * bridge has directed it to go. If the non-Stasis bridge has not set up an after
		 * bridge destination, then the channel should be hung up.
		 */
		int hangup_flag;

		hangup_flag = ast_bridge_setup_after_goto(chan) ? AST_SOFTHANGUP_DEV : AST_SOFTHANGUP_ASYNCGOTO;
		ast_channel_lock(chan);
		ast_softhangup_nolock(chan, hangup_flag);
		ast_channel_unlock(chan);
	}
}
Пример #15
0
static int manager_park(struct mansession *s, const struct message *m)
{
	const char *channel = astman_get_header(m, "Channel");
	const char *timeout_channel = S_OR(astman_get_header(m, "TimeoutChannel"), astman_get_header(m, "Channel2"));
	const char *timeout = astman_get_header(m, "Timeout");
	const char *parkinglot = astman_get_header(m, "Parkinglot");
	char buf[BUFSIZ];
	int timeout_override = -1;

	RAII_VAR(struct ast_channel *, chan, NULL, ao2_cleanup);
	RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup);

	if (ast_strlen_zero(channel)) {
		astman_send_error(s, m, "Channel not specified");
		return 0;
	}

	if (!ast_strlen_zero(timeout)) {
		if (sscanf(timeout, "%30d", &timeout_override) != 1 || timeout < 0) {
			astman_send_error(s, m, "Invalid Timeout value.");
			return 0;
		}

		if (timeout_override > 0) {
			/* If greater than zero, convert to seconds for internal use. Must be >= 1 second. */
			timeout_override = MAX(1, timeout_override / 1000);
		}
	}

	if (!(chan = ast_channel_get_by_name(channel))) {
		snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
		astman_send_error(s, m, buf);
		return 0;
	}

	ast_channel_lock(chan);
	if (!ast_strlen_zero(timeout_channel)) {
		pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", timeout_channel);
	}
	ast_channel_unlock(chan);

	if (!(parking_bridge = park_common_setup(chan, chan, parkinglot, NULL, 0, 0, timeout_override, 0))) {
		astman_send_error(s, m, "Park action failed\n");
		return 0;
	}

	if (ast_bridge_add_channel(parking_bridge, chan, NULL, 0, NULL)) {
		astman_send_error(s, m, "Park action failed\n");
		return 0;
	}

	astman_send_ack(s, m, "Park successful\n");
	return 0;
}
Пример #16
0
/*!
 * \internal
 * \brief CLI output the channel hangup handlers.
 * \since 11.0
 *
 * \param fd CLI file descriptor to use.
 * \param chan Channel to show hangup handlers.
 *
 * \return Nothing
 */
static void ast_pbx_hangup_handler_show(int fd, struct ast_channel *chan)
{
	struct ast_hangup_handler_list *handlers;
	struct ast_hangup_handler *h_handler;
	int first = 1;

	ast_channel_lock(chan);
	handlers = ast_channel_hangup_handlers(chan);
	AST_LIST_TRAVERSE(handlers, h_handler, node) {
		ast_cli(fd, HANDLER_FORMAT, first ? ast_channel_name(chan) : "", h_handler->args);
		first = 0;
	}
Пример #17
0
static int linkedid_match(void *obj, void *arg, void *data, int flags)
{
	struct ast_channel *c = obj;
	struct channel_find_data *find_dat = data;
	int res;

	ast_channel_lock(c);
	res = (c != find_dat->chan && c->linkedid && !strcmp(find_dat->linkedid, c->linkedid));
	ast_channel_unlock(c);

	return res ? CMP_MATCH | CMP_STOP : 0;
}
Пример #18
0
static void parker_parked_call_message_response(struct ast_parked_call_payload *message, struct parked_subscription_data *data,
	struct stasis_subscription *sub)
{
	const char *parkee_to_act_on = data->parkee_uuid;
	char saynum_buf[16];
	struct ast_channel_snapshot *parkee_snapshot = message->parkee;
	RAII_VAR(struct ast_channel *, parker, NULL, ast_channel_cleanup);
	RAII_VAR(struct ast_bridge_channel *, bridge_channel, NULL, ao2_cleanup);

	if (strcmp(parkee_to_act_on, parkee_snapshot->uniqueid)) {
		return;
	}

	if (message->event_type != PARKED_CALL && message->event_type != PARKED_CALL_FAILED) {
		/* We only care about these two event types */
		return;
	}

	parker = ast_channel_get_by_name(data->parker_uuid);
	if (!parker) {
		return;
	}

	ast_channel_lock(parker);
	bridge_channel = ast_channel_get_bridge_channel(parker);
	ast_channel_unlock(parker);
	if (!bridge_channel) {
		return;
	}

	/* This subscription callback will block for the duration of the announcement if
	 * parked_subscription_data is tracking a transfer_channel_data struct. */
	if (message->event_type == PARKED_CALL) {
		/* queue the saynum on the bridge channel and hangup */
		snprintf(saynum_buf, sizeof(saynum_buf), "%d %u", data->hangup_after, message->parkingspace);
		if (!data->transfer_data) {
			ast_bridge_channel_queue_playfile(bridge_channel, say_parking_space, saynum_buf, NULL);
		} else {
			ast_bridge_channel_queue_playfile_sync(bridge_channel, say_parking_space, saynum_buf, NULL);
			data->transfer_data->completed = 1;
		}
		wipe_subscription_datastore(parker);
	} else if (message->event_type == PARKED_CALL_FAILED) {
		if (!data->transfer_data) {
			ast_bridge_channel_queue_playfile(bridge_channel, NULL, "pbx-parkingfailed", NULL);
		} else {
			ast_bridge_channel_queue_playfile_sync(bridge_channel, NULL, "pbx-parkingfailed", NULL);
			data->transfer_data->completed = 1;
		}
		wipe_subscription_datastore(parker);
	}
}
Пример #19
0
static int func_channels_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t maxlen)
{
	struct ast_channel *c = NULL;
	regex_t re;
	int res;
	size_t buflen = 0;
	struct ast_channel_iterator *iter;

	buf[0] = '\0';

	if (!ast_strlen_zero(data)) {
		if ((res = regcomp(&re, data, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
			regerror(res, &re, buf, maxlen);
			ast_log(LOG_WARNING, "Error compiling regular expression for %s(%s): %s\n", function, data, buf);
			return -1;
		}
	}

	if (!(iter = ast_channel_iterator_all_new())) {
		if (!ast_strlen_zero(data)) {
			regfree(&re);
		}
		return -1;
	}

	while ((c = ast_channel_iterator_next(iter))) {
		ast_channel_lock(c);
		if (ast_strlen_zero(data) || regexec(&re, ast_channel_name(c), 0, NULL, 0) == 0) {
			size_t namelen = strlen(ast_channel_name(c));
			if (buflen + namelen + (ast_strlen_zero(buf) ? 0 : 1) + 1 < maxlen) {
				if (!ast_strlen_zero(buf)) {
					strcat(buf, " ");
					buflen++;
				}
				strcat(buf, ast_channel_name(c));
				buflen += namelen;
			} else {
				ast_log(LOG_WARNING, "Number of channels exceeds the available buffer space.  Output will be truncated!\n");
			}
		}
		ast_channel_unlock(c);
		c = ast_channel_unref(c);
	}

	ast_channel_iterator_destroy(iter);

	if (!ast_strlen_zero(data)) {
		regfree(&re);
	}

	return 0;
}
Пример #20
0
static void wipe_subscription_datastore(struct ast_channel *chan)
{
	struct ast_datastore *datastore;

	ast_channel_lock(chan);

	datastore = ast_channel_datastore_find(chan, &parked_subscription_info, NULL);
	if (datastore) {
		ast_channel_datastore_remove(chan, datastore);
		ast_datastore_free(datastore);
	}
	ast_channel_unlock(chan);
}
Пример #21
0
static struct ast_parked_call_payload *parked_call_payload_from_failure(struct ast_channel *chan)
{
	RAII_VAR(struct ast_channel_snapshot *, parkee_snapshot, NULL, ao2_cleanup);

	ast_channel_lock(chan);
	parkee_snapshot = ast_channel_snapshot_create(chan);
	ast_channel_unlock(chan);
	if (!parkee_snapshot) {
		return NULL;
	}

	return ast_parked_call_payload_create(PARKED_CALL_FAILED, parkee_snapshot, NULL, NULL, NULL, 0, 0, 0);
}
Пример #22
0
static int create_parked_subscription_full(struct ast_channel *chan, const char *parkee_uuid, int hangup_after,
	struct transfer_channel_data *parked_channel_data)
{
	struct ast_datastore *datastore;
	struct parked_subscription_datastore *parked_datastore;
	struct parked_subscription_data *subscription_data;

	char *parker_uuid = ast_strdupa(ast_channel_uniqueid(chan));
	size_t parker_uuid_size = strlen(parker_uuid) + 1;

	/* If there is already a subscription, get rid of it. */
	wipe_subscription_datastore(chan);

	if (!(datastore = ast_datastore_alloc(&parked_subscription_info, NULL))) {
		return -1;
	}

	if (!(parked_datastore = ast_calloc(1, sizeof(*parked_datastore)))) {
		ast_datastore_free(datastore);
		return -1;
	}

	if (!(subscription_data = ast_calloc(1, sizeof(*subscription_data) + parker_uuid_size +
			strlen(parkee_uuid) + 1))) {
		ast_datastore_free(datastore);
		ast_free(parked_datastore);
		return -1;
	}

	if (parked_channel_data) {
		subscription_data->transfer_data = parked_channel_data;
		ao2_ref(parked_channel_data, +1);
	}

	subscription_data->hangup_after = hangup_after;
	subscription_data->parkee_uuid = subscription_data->parker_uuid + parker_uuid_size;
	strcpy(subscription_data->parkee_uuid, parkee_uuid);
	strcpy(subscription_data->parker_uuid, parker_uuid);

	if (!(parked_datastore->parked_subscription = stasis_subscribe_pool(ast_parking_topic(), parker_update_cb, subscription_data))) {
		return -1;
	}

	datastore->data = parked_datastore;

	ast_channel_lock(chan);
	ast_channel_datastore_add(chan, datastore);
	ast_channel_unlock(chan);

	return 0;
}
Пример #23
0
/*!
 * \ingroup applications
 */
int indicate_congestion(struct ast_channel *chan, const char *data)
{
	ast_indicate(chan, AST_CONTROL_CONGESTION);
	/* Don't change state of an UP channel, just indicate
	   congestion in audio */
	ast_channel_lock(chan);
	if (ast_channel_state(chan) != AST_STATE_UP) {
		ast_channel_hangupcause_set(chan, AST_CAUSE_CONGESTION);
		ast_setstate(chan, AST_STATE_BUSY);
	}
	ast_channel_unlock(chan);
	wait_for_hangup(chan, data);
	return -1;
}
Пример #24
0
static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
{
	struct ast_channel *target = obj;/*!< Potential pickup target */
	struct pickup_by_name_args *args = data;

	ast_channel_lock(target);
	if (!strncasecmp(ast_channel_name(target), args->name, args->len) && ast_can_pickup(target)) {
		/* Return with the channel still locked on purpose */
		return CMP_MATCH | CMP_STOP;
	}
	ast_channel_unlock(target);

	return 0;
}
Пример #25
0
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
{
	struct ast_channel *target = obj; /*!< Potential pickup target */
	struct ast_channel *chan = arg;   /*!< Channel wanting to pickup call */

	if (chan == target) {
		return 0;
	}

	ast_channel_lock(target);
	if (ast_can_pickup(target)) {
		/* Lock both channels. */
		while (ast_channel_trylock(chan)) {
			ast_channel_unlock(target);
			sched_yield();
			ast_channel_lock(target);
		}

		/*
		 * Both callgroup and namedcallgroup pickup variants are
		 * matched independently.  Checking for named group match is
		 * done last since it's a more expensive operation.
		 */
		if ((ast_channel_pickupgroup(chan) & ast_channel_callgroup(target))
			|| (ast_namedgroups_intersect(ast_channel_named_pickupgroups(chan),
				ast_channel_named_callgroups(target)))) {
			struct ao2_container *candidates = data;/*!< Candidate channels found. */

			/* This is a candidate to pickup */
			ao2_link(candidates, target);
		}
		ast_channel_unlock(chan);
	}
	ast_channel_unlock(target);

	return 0;
}
Пример #26
0
static int func_channel_read(struct ast_channel *chan, const char *function,
			     char *data, char *buf, size_t len)
{
	int ret = 0;

	if (!strcasecmp(data, "audionativeformat"))
		/* use the _multiple version when chan->nativeformats holds multiple formats */
		/* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_AUDIO_MASK); */
		ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_AUDIO_MASK), len);
	else if (!strcasecmp(data, "videonativeformat"))
		/* use the _multiple version when chan->nativeformats holds multiple formats */
		/* ast_getformatname_multiple(buf, len, chan->nativeformats & AST_FORMAT_VIDEO_MASK); */
		ast_copy_string(buf, ast_getformatname(chan->nativeformats & AST_FORMAT_VIDEO_MASK), len);
	else if (!strcasecmp(data, "audioreadformat"))
		ast_copy_string(buf, ast_getformatname(chan->readformat), len);
	else if (!strcasecmp(data, "audiowriteformat"))
		ast_copy_string(buf, ast_getformatname(chan->writeformat), len);
#ifdef CHANNEL_TRACE
	else if (!strcasecmp(data, "trace")) {
		ast_channel_lock(chan);
		ast_copy_string(buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len);
		ast_channel_unlock(chan);
	}
#endif
	else if (!strcasecmp(data, "tonezone") && chan->zone)
		locked_copy_string(chan, buf, chan->zone->country, len);
	else if (!strcasecmp(data, "language"))
		locked_copy_string(chan, buf, chan->language, len);
	else if (!strcasecmp(data, "musicclass"))
		locked_copy_string(chan, buf, chan->musicclass, len);
	else if (!strcasecmp(data, "parkinglot"))
		locked_copy_string(chan, buf, chan->parkinglot, len);
	else if (!strcasecmp(data, "state"))
		locked_copy_string(chan, buf, ast_state2str(chan->_state), len);
	else if (!strcasecmp(data, "channeltype"))
		locked_copy_string(chan, buf, chan->tech->type, len);
	else if (!strcasecmp(data, "transfercapability"))
		locked_copy_string(chan, buf, transfercapability_table[chan->transfercapability & 0x1f], len);
	else if (!strcasecmp(data, "callgroup")) {
		char groupbuf[256];
		locked_copy_string(chan, buf,  ast_print_group(groupbuf, sizeof(groupbuf), chan->callgroup), len);
	} else if (!chan->tech->func_channel_read
		 || chan->tech->func_channel_read(chan, function, data, buf, len)) {
		ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
		ret = -1;
	}

	return ret;
}
Пример #27
0
/*!
 * \brief after bridge callback for the dial bridge
 *
 * The only purpose of this callback is to ensure that the control structure's
 * bridge pointer is NULLed
 */
static void dial_bridge_after_cb(struct ast_channel *chan, void *data)
{
	struct stasis_app_control *control = data;
	struct ast_bridge_channel *bridge_channel;

	ast_channel_lock(chan);
	bridge_channel = ast_channel_get_bridge_channel(chan);
	ast_channel_unlock(chan);

	ast_debug(3, "Channel: <%s>  Reason: %d\n", ast_channel_name(control->channel), ast_channel_hangupcause(chan));

	stasis_app_send_command_async(control, bridge_channel_depart, bridge_channel, __ao2_cleanup);

	control->bridge = NULL;
}
Пример #28
0
int ast_pbx_hangup_handler_run(struct ast_channel *chan)
{
	struct ast_hangup_handler_list *handlers;
	struct ast_hangup_handler *h_handler;

	ast_channel_lock(chan);
	handlers = ast_channel_hangup_handlers(chan);
	if (AST_LIST_EMPTY(handlers)) {
		ast_channel_unlock(chan);
		return 0;
	}

	/*
	 * Make sure that the channel is marked as hungup since we are
	 * going to run the hangup handlers on it.
	 */
	ast_softhangup_nolock(chan, AST_SOFTHANGUP_HANGUP_EXEC);

	for (;;) {
		handlers = ast_channel_hangup_handlers(chan);
		h_handler = AST_LIST_REMOVE_HEAD(handlers, node);
		if (!h_handler) {
			break;
		}

		publish_hangup_handler_message("run", chan, h_handler->args);
		ast_channel_unlock(chan);

		ast_app_exec_sub(NULL, chan, h_handler->args, 1);
		ast_free(h_handler);

		ast_channel_lock(chan);
	}
	ast_channel_unlock(chan);
	return 1;
}
Пример #29
0
void ast_pbx_hangup_handler_destroy(struct ast_channel *chan)
{
	struct ast_hangup_handler_list *handlers;
	struct ast_hangup_handler *h_handler;

	ast_channel_lock(chan);

	/* Get rid of each of the hangup handlers on the channel */
	handlers = ast_channel_hangup_handlers(chan);
	while ((h_handler = AST_LIST_REMOVE_HEAD(handlers, node))) {
		ast_free(h_handler);
	}

	ast_channel_unlock(chan);
}
static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
{
	struct ast_channel *target = obj;/*!< Potential pickup target */
	struct ast_channel *chan = data;/*!< Channel wanting to pickup call */

	ast_channel_lock(target);
	if (chan != target && (chan->pickupgroup & target->callgroup)
		&& ast_can_pickup(target)) {
		/* Return with the channel still locked on purpose */
		return CMP_MATCH | CMP_STOP;
	}
	ast_channel_unlock(target);

	return 0;
}