Beispiel #1
0
static int srv_query_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
	struct ast_datastore *datastore;

	if (!chan) {
		ast_log(LOG_WARNING, "%s cannot be used without a channel\n", cmd);
		return -1;
	}

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "%s requires a service as an argument\n", cmd);
		return -1;
	}
	
	/* If they already called SRVQUERY for this service once,
	 * we need to kill the old datastore.
	 */
	ast_channel_lock(chan);
	datastore = ast_channel_datastore_find(chan, &srv_result_datastore_info, data);
	ast_channel_unlock(chan);

	if (datastore) {
		ast_channel_datastore_remove(chan, datastore);
		ast_datastore_free(datastore);
	}
	
	if (!srv_datastore_setup(data, chan)) {
		return -1;
	}

	ast_copy_string(buf, data, len);

	return 0;
}
Beispiel #2
0
/*! \internal \brief Disable talk detection on the channel */
static int remove_talk_detect(struct ast_channel *chan)
{
	struct ast_datastore *datastore = NULL;
	struct talk_detect_params *td_params;
	SCOPED_CHANNELLOCK(chan_lock, chan);

	datastore = ast_channel_datastore_find(chan, &talk_detect_datastore, NULL);
	if (!datastore) {
		ast_log(AST_LOG_WARNING, "Cannot remove TALK_DETECT from %s: TALK_DETECT not currently enabled\n",
		        ast_channel_name(chan));
		return -1;
	}
	td_params = datastore->data;

	if (ast_audiohook_remove(chan, &td_params->audiohook)) {
		ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT audiohook from channel %s\n",
		        ast_channel_name(chan));
		return -1;
	}

	if (ast_channel_datastore_remove(chan, datastore)) {
		ast_log(AST_LOG_WARNING, "Failed to remove TALK_DETECT datastore from channel %s\n",
		        ast_channel_name(chan));
		return -1;
	}
	ast_datastore_free(datastore);

	return 0;
}
Beispiel #3
0
/*!
 * \internal
 * \brief Set the features datastore if it doesn't exist.
 *
 * \param chan Channel to add features datastore
 * \param my_features The channel's feature flags
 * \param peer_features The channel's bridge peer feature flags
 *
 * \retval TRUE if features datastore already existed.
 */
static int add_features_datastore(struct ast_channel *chan, const struct ast_flags *my_features, const struct ast_flags *peer_features)
{
	struct ast_datastore *datastore;
	struct ast_dial_features *dialfeatures;

	ast_channel_lock(chan);
	datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL);
	ast_channel_unlock(chan);
	if (datastore) {
		/* Already exists. */
		return 1;
	}

	/* Create a new datastore with specified feature flags. */
	datastore = ast_datastore_alloc(&dial_features_info, NULL);
	if (!datastore) {
		ast_log(LOG_WARNING, "Unable to create channel features datastore.\n");
		return 0;
	}
	dialfeatures = ast_calloc(1, sizeof(*dialfeatures));
	if (!dialfeatures) {
		ast_log(LOG_WARNING, "Unable to allocate memory for feature flags.\n");
		ast_datastore_free(datastore);
		return 0;
	}
	ast_copy_flags(&dialfeatures->my_features, my_features, AST_FLAGS_ALL);
	ast_copy_flags(&dialfeatures->peer_features, peer_features, AST_FLAGS_ALL);
	datastore->inheritance = DATASTORE_INHERIT_FOREVER;
	datastore->data = dialfeatures;
	ast_channel_lock(chan);
	ast_channel_datastore_add(chan, datastore);
	ast_channel_unlock(chan);
	return 0;
}
Beispiel #4
0
/*!
 * \brief Set a dial timeout interval hook on the channel.
 *
 * The absolute time that the timeout should occur is stored on
 * a datastore on the channel. This time is converted into a relative
 * number of milliseconds in the future. Then an interval hook is set
 * to trigger in that number of milliseconds.
 *
 * \pre chan is locked
 *
 * \param chan The channel on which to set the interval hook
 */
static void set_interval_hook(struct ast_channel *chan)
{
	struct ast_datastore *datastore;
	struct timeval *hangup_time;
	int64_t ms;
	struct ast_bridge_channel *bridge_channel;

	datastore = ast_channel_datastore_find(chan, &timeout_datastore, NULL);
	if (!datastore) {
		return;
	}

	hangup_time = datastore->data;

	ms = ast_tvdiff_ms(*hangup_time, ast_tvnow());
	bridge_channel = ast_channel_get_bridge_channel(chan);
	if (!bridge_channel) {
		return;
	}

	if (ast_bridge_interval_hook(bridge_channel->features, 0, ms > 0 ? ms : 1,
			bridge_timeout, NULL, NULL, 0)) {
		return;
	}

	ast_queue_frame(bridge_channel->chan, &ast_null_frame);
}
Beispiel #5
0
/*! \brief SpeechDestroy() Dialplan Application */
static int speech_destroy(struct ast_channel *chan, void *data)
{
	int res = 0;
        struct ast_module_user *u = NULL;
	struct ast_speech *speech = find_speech(chan);
	struct ast_datastore *datastore = NULL;

	u = ast_module_user_add(chan);

	if (speech == NULL) {
		ast_module_user_remove(u);
		return -1;
	}

	/* Destroy speech structure */
	ast_speech_destroy(speech);

	datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
	if (datastore != NULL) {
		ast_channel_datastore_remove(chan, datastore);
	}

	ast_module_user_remove(u);

	return res;
}
Beispiel #6
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;
}
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;
}
Beispiel #8
0
static struct chanspy_ds *chanspy_ds_free(struct chanspy_ds *chanspy_ds)
{
	struct ast_channel *chan;

	if (!chanspy_ds) {
		return NULL;
	}

	ast_mutex_lock(&chanspy_ds->lock);
	while ((chan = chanspy_ds->chan)) {
		struct ast_datastore *datastore;

		if (ast_channel_trylock(chan)) {
			DEADLOCK_AVOIDANCE(&chanspy_ds->lock);
			continue;
		}
		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);
		break;
	}
	ast_mutex_unlock(&chanspy_ds->lock);

	return NULL;
}
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;
}
Beispiel #10
0
static int speex_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
{
	struct ast_datastore *datastore = NULL;
	struct speex_direction_info *sdi = NULL;
	struct speex_info *si = NULL;
	char source[80];

	/* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || frame->frametype != AST_FRAME_VOICE) {
		return -1;
	}

	/* We are called with chan already locked */
	if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
		return -1;
	}

	si = datastore->data;

	sdi = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? si->rx : si->tx;

	if (!sdi) {
		return -1;
	}

	if ((sdi->samples != frame->samples) || (ast_format_rate(&frame->subclass.format) != si->lastrate)) {
		si->lastrate = ast_format_rate(&frame->subclass.format);
		if (sdi->state) {
			speex_preprocess_state_destroy(sdi->state);
		}

		if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), si->lastrate))) {
			return -1;
		}

		speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC, &sdi->agc);

		if (sdi->agc) {
			speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &sdi->agclevel);
		}

		speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_DENOISE, &sdi->denoise);
	}

	speex_preprocess(sdi->state, frame->data.ptr, NULL);
	snprintf(source, sizeof(source), "%s/speex", frame->src);
	if (frame->mallocd & AST_MALLOCD_SRC) {
		ast_free((char *) frame->src);
	}
	frame->src = ast_strdup(source);
	frame->mallocd |= AST_MALLOCD_SRC;

	return 0;
}
Beispiel #11
0
/*! \brief Helper function used to find the speech structure attached to a channel */
static struct ast_speech *find_speech(struct ast_channel *chan)
{
	struct ast_speech *speech = NULL;
	struct ast_datastore *datastore = NULL;
	
	datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
	if (datastore == NULL) {
		return NULL;
	}
	speech = datastore->data;

	return speech;
}
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);
}
/*! \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,
		.consume_cb = t38_consume,
		.chan_fixup_cb = t38_masq,
		.chan_breakdown_cb = t38_masq,
	};

	/* If the channel's already gone, bail */
	if (!session->channel) {
		return;
	}

	/* 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);
}
Beispiel #14
0
/*! \internal \brief Enable talk detection on the channel */
static int set_talk_detect(struct ast_channel *chan, int dsp_silence_threshold, int dsp_talking_threshold)
{
	struct ast_datastore *datastore = NULL;
	struct talk_detect_params *td_params;
	SCOPED_CHANNELLOCK(chan_lock, chan);

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

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

		ast_audiohook_init(&td_params->audiohook,
		                   AST_AUDIOHOOK_TYPE_MANIPULATE,
		                   "TALK_DETECT",
		                   AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
		td_params->audiohook.manipulate_callback = talk_detect_audiohook_cb;
		ast_set_flag(&td_params->audiohook, AST_AUDIOHOOK_TRIGGER_READ);

		td_params->dsp = ast_dsp_new_with_rate(ast_format_get_sample_rate(ast_channel_rawreadformat(chan)));
		if (!td_params->dsp) {
			ast_datastore_free(datastore);
			ast_free(td_params);
			return -1;
		}
		datastore->data = td_params;

		ast_channel_datastore_add(chan, datastore);
		ast_audiohook_attach(chan, &td_params->audiohook);
	} else {
		/* Talk detection already enabled; update existing settings */
		td_params = datastore->data;
	}

	td_params->dsp_talking_threshold = dsp_talking_threshold;
	td_params->dsp_silence_threshold = dsp_silence_threshold;

	ast_dsp_set_threshold(td_params->dsp, td_params->dsp_talking_threshold);

	return 0;
}
Beispiel #15
0
int ast_can_pickup(struct ast_channel *chan)
{
	if (!ast_channel_pbx(chan) && !ast_channel_masq(chan) && !ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)
		&& (ast_channel_state(chan) == AST_STATE_RINGING
			|| ast_channel_state(chan) == AST_STATE_RING
			/*
			 * Check the down state as well because some SIP devices do not
			 * give 180 ringing when they can just give 183 session progress
			 * instead.  Issue 14005.  (Some ISDN switches as well for that
			 * matter.)
			 */
			|| ast_channel_state(chan) == AST_STATE_DOWN)
		&& !ast_channel_datastore_find(chan, &pickup_active, NULL)) {
		return 1;
	}
	return 0;
}
Beispiel #16
0
static int volume_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
{
	struct ast_datastore *datastore = NULL;
	struct volume_information *vi = NULL;
	int *gain = NULL;

	/* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE)
		return 0;

	/* Grab datastore which contains our gain information */
	if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL)))
		return 0;

	vi = datastore->data;

	/* If this is DTMF then allow them to increase/decrease the gains */
	if (ast_test_flag(vi, VOLUMEFLAG_CHANGE)) {
		if (frame->frametype == AST_FRAME_DTMF) {
			/* Only use DTMF coming from the source... not going to it */
			if (direction != AST_AUDIOHOOK_DIRECTION_READ)
				return 0; 
			if (frame->subclass.integer == '*') {
				vi->tx_gain += 1;
				vi->rx_gain += 1;
			} else if (frame->subclass.integer == '#') {
				vi->tx_gain -= 1;
				vi->rx_gain -= 1;
			}
		}
	}

	
	if (frame->frametype == AST_FRAME_VOICE) {
		/* Based on direction of frame grab the gain, and confirm it is applicable */
		if (!(gain = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? &vi->rx_gain : &vi->tx_gain) || !*gain)
			return 0;
		/* Apply gain to frame... easy as pi */
		ast_frame_adjust_volume(frame, *gain);
	}

	return 0;
}
/*! \brief Mute dialplan function */
static int func_mute_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
	struct ast_datastore *datastore = NULL;
	struct mute_information *mute = NULL;
	int is_new = 0;

	if (!chan) {
		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
		return -1;
	}

	ast_channel_lock(chan);
	if (!(datastore = ast_channel_datastore_find(chan, &mute_datastore, NULL))) {
		if (!(datastore = initialize_mutehook(chan))) {
			ast_channel_unlock(chan);
			return 0;
		}
		is_new = 1;
	}

	mute = datastore->data;

	if (!strcasecmp(data, "out")) {
		mute->mute_write = ast_true(value);
		ast_debug(1, "%s channel - outbound \n", ast_true(value) ? "Muting" : "Unmuting");
	} else if (!strcasecmp(data, "in")) {
		mute->mute_read = ast_true(value);
		ast_debug(1, "%s channel - inbound  \n", ast_true(value) ? "Muting" : "Unmuting");
	} else if (!strcasecmp(data,"all")) {
		mute->mute_write = mute->mute_read = ast_true(value);
	}

	if (is_new) {
		if (mute_add_audiohook(chan, mute, datastore)) {
			/* Can't add audiohook - already printed error message */
			ast_datastore_free(datastore);
			ast_free(mute);
		}
	}
	ast_channel_unlock(chan);

	return 0;
}
/*!
 * \internal
 * \brief Destroy the speech datastore on the given channel.
 *
 * \param chan Channel to destroy speech datastore.
 *
 * \retval 0 on success.
 * \retval -1 not found.
 */
static int speech_datastore_destroy(struct ast_channel *chan)
{
	struct ast_datastore *datastore;
	int res;

	ast_channel_lock(chan);
	datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
	if (datastore) {
		ast_channel_datastore_remove(chan, datastore);
	}
	ast_channel_unlock(chan);
	if (datastore) {
		ast_datastore_free(datastore);
		res = 0;
	} else {
		res = -1;
	}
	return res;
}
/*! \brief The callback from the audiohook subsystem. We basically get a frame to have fun with */
static int mute_callback(struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
{
	struct ast_datastore *datastore = NULL;
	struct mute_information *mute = NULL;


	/* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
	if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE) {
		return 0;
	}

	ast_channel_lock(chan);
	/* Grab datastore which contains our mute information */
	if (!(datastore = ast_channel_datastore_find(chan, &mute_datastore, NULL))) {
		ast_channel_unlock(chan);
		ast_debug(2, "Can't find any datastore to use. Bad. \n");
		return 0;
	}

	mute = datastore->data;


	/* If this is audio then allow them to increase/decrease the gains */
	if (frame->frametype == AST_FRAME_VOICE) {
		ast_debug(2, "Audio frame - direction %s  mute READ %s WRITE %s\n", direction == AST_AUDIOHOOK_DIRECTION_READ ? "read" : "write", mute->mute_read ? "on" : "off", mute->mute_write ? "on" : "off");

		/* Based on direction of frame grab the gain, and confirm it is applicable */
		if ((direction == AST_AUDIOHOOK_DIRECTION_READ && mute->mute_read) || (direction == AST_AUDIOHOOK_DIRECTION_WRITE && mute->mute_write)) {
			/* Ok, we just want to reset all audio in this frame. Keep NOTHING, thanks. */
			ast_frame_clear(frame);
		}
	}
	ast_channel_unlock(chan);

	return 0;
}
Beispiel #20
0
static int volume_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
	struct ast_datastore *datastore = NULL;
	struct volume_information *vi = NULL;
	int is_new = 0;

	if (!(datastore = ast_channel_datastore_find(chan, &volume_datastore, NULL))) {
		/* Allocate a new datastore to hold the reference to this volume and audiohook information */
		if (!(datastore = ast_datastore_alloc(&volume_datastore, NULL)))
			return 0;
		if (!(vi = ast_calloc(1, sizeof(*vi)))) {
			ast_datastore_free(datastore);
			return 0;
		}
		ast_audiohook_init(&vi->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "Volume");
		vi->audiohook.manipulate_callback = volume_callback;
		ast_set_flag(&vi->audiohook, AST_AUDIOHOOK_WANTS_DTMF);
		is_new = 1;
	} else {
		vi = datastore->data;
	}

	/* Adjust gain on volume information structure */
	if (!strcasecmp(data, "tx"))
		vi->tx_gain = atoi(value);
	else if (!strcasecmp(data, "rx"))
		vi->rx_gain = atoi(value);

	if (is_new) {
		datastore->data = vi;
		ast_channel_datastore_add(chan, datastore);
		ast_audiohook_attach(chan, &vi->audiohook);
	}

	return 0;
}
Beispiel #21
0
static int speex_read(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
{
	struct ast_datastore *datastore = NULL;
	struct speex_info *si = NULL;
	struct speex_direction_info *sdi = NULL;

	if (!chan) {
		ast_log(LOG_ERROR, "%s cannot be used without a channel!\n", cmd);
		return -1;
	}

	ast_channel_lock(chan);
	if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
		ast_channel_unlock(chan);
		return -1;
	}
	ast_channel_unlock(chan);

	si = datastore->data;

	if (!strcasecmp(data, "tx"))
		sdi = si->tx;
	else if (!strcasecmp(data, "rx"))
		sdi = si->rx;
	else {
		ast_log(LOG_ERROR, "%s(%s) must either \"tx\" or \"rx\"\n", cmd, data);
		return -1;
	}

	if (!strcasecmp(cmd, "agc"))
		snprintf(buf, len, "%.01f", sdi ? sdi->agclevel : 0.0);
	else
		snprintf(buf, len, "%d", sdi ? sdi->denoise : 0);

	return 0;
}
Beispiel #22
0
static int func_channel_read(struct ast_channel *chan, const char *function,
			     char *data, char *buf, size_t len)
{
	int ret = 0;
	struct ast_format_cap *tmpcap;

	if (!chan) {
		ast_log(LOG_WARNING, "No channel was provided to %s function.\n", function);
		return -1;
	}

	if (!strcasecmp(data, "audionativeformat")) {
		tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
		if (tmpcap) {
			struct ast_str *codec_buf = ast_str_alloca(128);

			ast_channel_lock(chan);
			ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_AUDIO);
			ast_channel_unlock(chan);
			ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len);
			ao2_ref(tmpcap, -1);
		}
	} else if (!strcasecmp(data, "videonativeformat")) {
		tmpcap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
		if (tmpcap) {
			struct ast_str *codec_buf = ast_str_alloca(128);

			ast_channel_lock(chan);
			ast_format_cap_append_from_cap(tmpcap, ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO);
			ast_channel_unlock(chan);
			ast_copy_string(buf, ast_format_cap_get_names(tmpcap, &codec_buf), len);
			ao2_ref(tmpcap, -1);
		}
	} else if (!strcasecmp(data, "audioreadformat")) {
		locked_copy_string(chan, buf, ast_format_get_name(ast_channel_readformat(chan)), len);
	} else if (!strcasecmp(data, "audiowriteformat")) {
		locked_copy_string(chan, buf, ast_format_get_name(ast_channel_writeformat(chan)), len);
#ifdef CHANNEL_TRACE
	} else if (!strcasecmp(data, "trace")) {
		locked_copy_string(chan, buf, ast_channel_trace_is_enabled(chan) ? "1" : "0", len);
#endif
	} else if (!strcasecmp(data, "tonezone") && ast_channel_zone(chan)) {
		locked_copy_string(chan, buf, ast_channel_zone(chan)->country, len);
	} else if (!strcasecmp(data, "dtmf_features")) {
		if (ast_bridge_features_ds_get_string(chan, buf, len)) {
			buf[0] = '\0';
		}
	} else if (!strcasecmp(data, "language"))
		locked_copy_string(chan, buf, ast_channel_language(chan), len);
	else if (!strcasecmp(data, "musicclass"))
		locked_copy_string(chan, buf, ast_channel_musicclass(chan), len);
	else if (!strcasecmp(data, "name")) {
		locked_copy_string(chan, buf, ast_channel_name(chan), len);
	} else if (!strcasecmp(data, "parkinglot"))
		locked_copy_string(chan, buf, ast_channel_parkinglot(chan), len);
	else if (!strcasecmp(data, "state"))
		locked_copy_string(chan, buf, ast_state2str(ast_channel_state(chan)), len);
	else if (!strcasecmp(data, "onhold")) {
		locked_copy_string(chan, buf,
			ast_channel_hold_state(chan) == AST_CONTROL_HOLD ? "1" : "0", len);
	} else if (!strcasecmp(data, "channeltype"))
		locked_copy_string(chan, buf, ast_channel_tech(chan)->type, len);
	else if (!strcasecmp(data, "accountcode"))
		locked_copy_string(chan, buf, ast_channel_accountcode(chan), len);
	else if (!strcasecmp(data, "checkhangup")) {
		locked_copy_string(chan, buf, ast_check_hangup(chan) ? "1" : "0", len);
	} else if (!strcasecmp(data, "peeraccount"))
		locked_copy_string(chan, buf, ast_channel_peeraccount(chan), len);
	else if (!strcasecmp(data, "hangupsource"))
		locked_copy_string(chan, buf, ast_channel_hangupsource(chan), len);
	else if (!strcasecmp(data, "appname") && ast_channel_appl(chan))
		locked_copy_string(chan, buf, ast_channel_appl(chan), len);
	else if (!strcasecmp(data, "appdata") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_data(chan), len);
	else if (!strcasecmp(data, "exten") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_exten(chan), len);
	else if (!strcasecmp(data, "context") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_context(chan), len);
	else if (!strcasecmp(data, "userfield") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_userfield(chan), len);
	else if (!strcasecmp(data, "channame") && ast_channel_data(chan))
		locked_copy_string(chan, buf, ast_channel_name(chan), len);
	else if (!strcasecmp(data, "linkedid")) {
		ast_channel_lock(chan);
		if (ast_strlen_zero(ast_channel_linkedid(chan))) {
			/* fall back on the channel's uniqueid if linkedid is unset */
			ast_copy_string(buf, ast_channel_uniqueid(chan), len);
		}
		else {
			ast_copy_string(buf, ast_channel_linkedid(chan), len);
		}
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "peer")) {
		struct ast_channel *peer;

		peer = ast_channel_bridge_peer(chan);
		if (peer) {
			/* Only real channels could have a bridge peer this way. */
			ast_channel_lock(peer);
			ast_copy_string(buf, ast_channel_name(peer), len);
			ast_channel_unlock(peer);
			ast_channel_unref(peer);
		} else {
			buf[0] = '\0';
			ast_channel_lock(chan);
			if (!ast_channel_tech(chan)) {
				const char *pname;

				/*
				 * A dummy channel can still pass along bridged peer info
				 * via the BRIDGEPEER variable.
				 *
				 * A horrible kludge, but... how else?
				 */
				pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER");
				if (!ast_strlen_zero(pname)) {
					ast_copy_string(buf, pname, len);
				}
			}
			ast_channel_unlock(chan);
		}
	} else if (!strcasecmp(data, "uniqueid")) {
		locked_copy_string(chan, buf, ast_channel_uniqueid(chan), len);
	} else if (!strcasecmp(data, "transfercapability")) {
		locked_copy_string(chan, buf, transfercapability_table[ast_channel_transfercapability(chan) & 0x1f], len);
	} else if (!strcasecmp(data, "callgroup")) {
		char groupbuf[256];

		locked_copy_string(chan, buf,  ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_callgroup(chan)), len);
	} else if (!strcasecmp(data, "pickupgroup")) {
		char groupbuf[256];

		locked_copy_string(chan, buf,  ast_print_group(groupbuf, sizeof(groupbuf), ast_channel_pickupgroup(chan)), len);
	} else if (!strcasecmp(data, "namedcallgroup")) {
		struct ast_str *tmp_str = ast_str_alloca(1024);

		locked_copy_string(chan, buf,  ast_print_namedgroups(&tmp_str, ast_channel_named_callgroups(chan)), len);
	} else if (!strcasecmp(data, "namedpickupgroup")) {
		struct ast_str *tmp_str = ast_str_alloca(1024);

		locked_copy_string(chan, buf,  ast_print_namedgroups(&tmp_str, ast_channel_named_pickupgroups(chan)), len);
	} else if (!strcasecmp(data, "after_bridge_goto")) {
		ast_bridge_read_after_goto(chan, buf, len);
	} else if (!strcasecmp(data, "amaflags")) {
		ast_channel_lock(chan);
		snprintf(buf, len, "%u", ast_channel_amaflags(chan));
		ast_channel_unlock(chan);
	} else if (!strncasecmp(data, "secure_bridge_", 14)) {
		struct ast_datastore *ds;

		buf[0] = '\0';
		ast_channel_lock(chan);
		if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
			struct ast_secure_call_store *encrypt = ds->data;

			if (!strcasecmp(data, "secure_bridge_signaling")) {
				snprintf(buf, len, "%s", encrypt->signaling ? "1" : "");
			} else if (!strcasecmp(data, "secure_bridge_media")) {
				snprintf(buf, len, "%s", encrypt->media ? "1" : "");
			}
		}
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "max_forwards")) {
		ast_channel_lock(chan);
		snprintf(buf, len, "%d", ast_max_forwards_get(chan));
		ast_channel_unlock(chan);
	} else if (!ast_channel_tech(chan) || !ast_channel_tech(chan)->func_channel_read || ast_channel_tech(chan)->func_channel_read(chan, function, data, buf, len)) {
		ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n", data);
		ret = -1;
	}

	return ret;
}
static int manager_mutestream(struct mansession *s, const struct message *m)
{
	const char *channel = astman_get_header(m, "Channel");
	const char *id = astman_get_header(m,"ActionID");
	const char *state = astman_get_header(m,"State");
	const char *direction = astman_get_header(m,"Direction");
	char id_text[256];
	struct ast_channel *c = NULL;
	struct ast_datastore *datastore = NULL;
	struct mute_information *mute = NULL;
	int is_new = 0;
	int turnon;

	if (ast_strlen_zero(channel)) {
		astman_send_error(s, m, "Channel not specified");
		return 0;
	}
	if (ast_strlen_zero(state)) {
		astman_send_error(s, m, "State not specified");
		return 0;
	}
	if (ast_strlen_zero(direction)) {
		astman_send_error(s, m, "Direction not specified");
		return 0;
	}
	/* Ok, we have everything */

	c = ast_channel_get_by_name(channel);
	if (!c) {
		astman_send_error(s, m, "No such channel");
		return 0;
	}

	ast_channel_lock(c);

	if (!(datastore = ast_channel_datastore_find(c, &mute_datastore, NULL))) {
		if (!(datastore = initialize_mutehook(c))) {
			ast_channel_unlock(c);
			ast_channel_unref(c);
			astman_send_error(s, m, "Memory allocation failure");
			return 0;
		}
		is_new = 1;
	}
	mute = datastore->data;

	turnon = ast_true(state);
	if (!strcasecmp(direction, "in")) {
		mute->mute_read = turnon;
	} else if (!strcasecmp(direction, "out")) {
		mute->mute_write = turnon;
	} else if (!strcasecmp(direction, "all")) {
		mute->mute_read = mute->mute_write = turnon;
	}

	if (is_new) {
		if (mute_add_audiohook(c, mute, datastore)) {
			/* Can't add audiohook */
			ast_datastore_free(datastore);
			ast_free(mute);
			ast_channel_unlock(c);
			ast_channel_unref(c);
			astman_send_error(s, m, "Couldn't add mute audiohook");
			return 0;
		}
	}
	ast_channel_unlock(c);
	ast_channel_unref(c);

	if (!ast_strlen_zero(id)) {
		snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
	} else {
		id_text[0] = '\0';
	}
	astman_append(s, "Response: Success\r\n"
		"%s"
		"\r\n", id_text);
	return 0;
}
Beispiel #24
0
static int speex_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
	struct ast_datastore *datastore = NULL;
	struct speex_info *si = NULL;
	struct speex_direction_info **sdi = NULL;
	int is_new = 0;

	ast_channel_lock(chan);
	if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
		ast_channel_unlock(chan);

		if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) {
			return 0;
		}

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

		ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
		si->audiohook.manipulate_callback = speex_callback;
		si->lastrate = 8000;
		is_new = 1;
	} else {
		ast_channel_unlock(chan);
		si = datastore->data;
	}

	if (!strcasecmp(data, "rx")) {
		sdi = &si->rx;
	} else if (!strcasecmp(data, "tx")) {
		sdi = &si->tx;
	} else {
		ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);

		if (is_new) {
			ast_datastore_free(datastore);
			return -1;
		}
	}

	if (!*sdi) {
		if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) {
			return 0;
		}
		/* Right now, the audiohooks API will _only_ provide us 8 kHz slinear
		 * audio.  When it supports 16 kHz (or any other sample rates, we will
		 * have to take that into account here. */
		(*sdi)->samples = -1;
	}

	if (!strcasecmp(cmd, "agc")) {
		if (!sscanf(value, "%30f", &(*sdi)->agclevel))
			(*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0;
	
		if ((*sdi)->agclevel > 32768.0) {
			ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n", 
					((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel);
			(*sdi)->agclevel = 32768.0;
		}
	
		(*sdi)->agc = !!((*sdi)->agclevel);

		if ((*sdi)->state) {
			speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc);
			if ((*sdi)->agc) {
				speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel);
			}
		}
	} else if (!strcasecmp(cmd, "denoise")) {
		(*sdi)->denoise = (ast_true(value) != 0);

		if ((*sdi)->state) {
			speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise);
		}
	}

	if (!(*sdi)->agc && !(*sdi)->denoise) {
		if ((*sdi)->state)
			speex_preprocess_state_destroy((*sdi)->state);

		ast_free(*sdi);
		*sdi = NULL;
	}

	if (!si->rx && !si->tx) {
		if (is_new) {
			is_new = 0;
		} else {
			ast_channel_lock(chan);
			ast_channel_datastore_remove(chan, datastore);
			ast_channel_unlock(chan);
			ast_audiohook_remove(chan, &si->audiohook);
			ast_audiohook_detach(&si->audiohook);
		}
		
		ast_datastore_free(datastore);
	}

	if (is_new) { 
		datastore->data = si;
		ast_channel_lock(chan);
		ast_channel_datastore_add(chan, datastore);
		ast_channel_unlock(chan);
		ast_audiohook_attach(chan, &si->audiohook);
	}

	return 0;
}
Beispiel #25
0
static int func_channel_read(struct ast_channel *chan, const char *function,
                             char *data, char *buf, size_t len)
{
    int ret = 0;
    char tmp[512];
    struct ast_format_cap *tmpcap;

    if (!strcasecmp(data, "audionativeformat")) {
        if ((tmpcap = ast_format_cap_get_type(chan->nativeformats, AST_FORMAT_TYPE_AUDIO))) {
            ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len);
            tmpcap = ast_format_cap_destroy(tmpcap);
        }
    } else if (!strcasecmp(data, "videonativeformat")) {
        if ((tmpcap = ast_format_cap_get_type(chan->nativeformats, AST_FORMAT_TYPE_VIDEO))) {
            ast_copy_string(buf, ast_getformatname_multiple(tmp, sizeof(tmp), tmpcap), len);
            tmpcap = ast_format_cap_destroy(tmpcap);
        }
    } 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, "name")) {
        locked_copy_string(chan, buf, chan->name, 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, "accountcode"))
        locked_copy_string(chan, buf, chan->accountcode, len);
    else if (!strcasecmp(data, "checkhangup")) {
        ast_channel_lock(chan);
        ast_copy_string(buf, ast_check_hangup(chan) ? "1" : "0", len);
        ast_channel_unlock(chan);
    } else if (!strcasecmp(data, "peeraccount"))
        locked_copy_string(chan, buf, chan->peeraccount, len);
    else if (!strcasecmp(data, "hangupsource"))
        locked_copy_string(chan, buf, chan->hangupsource, len);
    else if (!strcasecmp(data, "appname") && chan->appl)
        locked_copy_string(chan, buf, chan->appl, len);
    else if (!strcasecmp(data, "appdata") && chan->data)
        locked_copy_string(chan, buf, chan->data, len);
    else if (!strcasecmp(data, "exten") && chan->data)
        locked_copy_string(chan, buf, chan->exten, len);
    else if (!strcasecmp(data, "context") && chan->data)
        locked_copy_string(chan, buf, chan->context, len);
    else if (!strcasecmp(data, "userfield") && chan->data)
        locked_copy_string(chan, buf, chan->userfield, len);
    else if (!strcasecmp(data, "channame") && chan->data)
        locked_copy_string(chan, buf, chan->name, len);
    else if (!strcasecmp(data, "linkedid")) {
        ast_channel_lock(chan);
        if (ast_strlen_zero(chan->linkedid)) {
            /* fall back on the channel's uniqueid if linkedid is unset */
            ast_copy_string(buf, chan->uniqueid, len);
        }
        else {
            ast_copy_string(buf, chan->linkedid, len);
        }
        ast_channel_unlock(chan);
    } else if (!strcasecmp(data, "peer")) {
        struct ast_channel *p;
        ast_channel_lock(chan);
        p = ast_bridged_channel(chan);
        if (p || chan->tech || chan->cdr) /* dummy channel? if so, we hid the peer name in the language */
            ast_copy_string(buf, (p ? p->name : ""), len);
        else {
            /* a dummy channel can still pass along bridged peer info via
                           the BRIDGEPEER variable */
            const char *pname = pbx_builtin_getvar_helper(chan, "BRIDGEPEER");
            if (!ast_strlen_zero(pname))
                ast_copy_string(buf, pname, len); /* a horrible kludge, but... how else? */
            else
                buf[0] = 0;
        }
        ast_channel_unlock(chan);
    } else if (!strcasecmp(data, "uniqueid")) {
        locked_copy_string(chan, buf, chan->uniqueid, 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 (!strcasecmp(data, "pickupgroup")) {
        char groupbuf[256];
        locked_copy_string(chan, buf,  ast_print_group(groupbuf, sizeof(groupbuf), chan->pickupgroup), len);
    } else if (!strcasecmp(data, "amaflags")) {
        char amabuf[256];
        snprintf(amabuf,sizeof(amabuf), "%d", chan->amaflags);
        locked_copy_string(chan, buf, amabuf, len);
    } else if (!strncasecmp(data, "secure_bridge_", 14)) {
        struct ast_datastore *ds;
        ast_channel_lock(chan);
        if ((ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
            struct ast_secure_call_store *encrypt = ds->data;
            if (!strcasecmp(data, "secure_bridge_signaling")) {
                snprintf(buf, len, "%s", encrypt->signaling ? "1" : "");
            } else if (!strcasecmp(data, "secure_bridge_media")) {
                snprintf(buf, len, "%s", encrypt->media ? "1" : "");
            }
        }
        ast_channel_unlock(chan);
    } else if (!chan->tech || !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;
}
Beispiel #26
0
static int func_channel_write_real(struct ast_channel *chan, const char *function,
                                   char *data, const char *value)
{
    int ret = 0;
    signed char gainset;

    if (!strcasecmp(data, "language"))
        locked_string_field_set(chan, language, value);
    else if (!strcasecmp(data, "parkinglot"))
        locked_string_field_set(chan, parkinglot, value);
    else if (!strcasecmp(data, "musicclass"))
        locked_string_field_set(chan, musicclass, value);
    else if (!strcasecmp(data, "accountcode"))
        locked_string_field_set(chan, accountcode, value);
    else if (!strcasecmp(data, "userfield"))
        locked_string_field_set(chan, userfield, value);
    else if (!strcasecmp(data, "amaflags")) {
        ast_channel_lock(chan);
        if(isdigit(*value)) {
            sscanf(value, "%30d", &chan->amaflags);
        } else if (!strcasecmp(value,"OMIT")) {
            chan->amaflags = 1;
        } else if (!strcasecmp(value,"BILLING")) {
            chan->amaflags = 2;
        } else if (!strcasecmp(value,"DOCUMENTATION")) {
            chan->amaflags = 3;
        }
        ast_channel_unlock(chan);
    } else if (!strcasecmp(data, "peeraccount"))
        locked_string_field_set(chan, peeraccount, value);
    else if (!strcasecmp(data, "hangupsource"))
        /* XXX - should we be forcing this here? */
        ast_set_hangupsource(chan, value, 0);
#ifdef CHANNEL_TRACE
    else if (!strcasecmp(data, "trace")) {
        ast_channel_lock(chan);
        if (ast_true(value))
            ret = ast_channel_trace_enable(chan);
        else if (ast_false(value))
            ret = ast_channel_trace_disable(chan);
        else {
            ret = -1;
            ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace).");
        }
        ast_channel_unlock(chan);
    }
#endif
    else if (!strcasecmp(data, "tonezone")) {
        struct ast_tone_zone *new_zone;
        if (!(new_zone = ast_get_indication_zone(value))) {
            ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
            ret = -1;
        } else {
            ast_channel_lock(chan);
            if (chan->zone) {
                chan->zone = ast_tone_zone_unref(chan->zone);
            }
            chan->zone = ast_tone_zone_ref(new_zone);
            ast_channel_unlock(chan);
            new_zone = ast_tone_zone_unref(new_zone);
        }
    } else if (!strcasecmp(data, "callgroup")) {
        chan->callgroup = ast_get_group(value);
    } else if (!strcasecmp(data, "pickupgroup")) {
        chan->pickupgroup = ast_get_group(value);
    } else if (!strcasecmp(data, "txgain")) {
        sscanf(value, "%4hhd", &gainset);
        ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0);
    } else if (!strcasecmp(data, "rxgain")) {
        sscanf(value, "%4hhd", &gainset);
        ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0);
    } else if (!strcasecmp(data, "transfercapability")) {
        unsigned short i;
        for (i = 0; i < 0x20; i++) {
            if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) {
                chan->transfercapability = i;
                break;
            }
        }
    } else if (!strncasecmp(data, "secure_bridge_", 14)) {
        struct ast_datastore *ds;
        struct ast_secure_call_store *store;

        if (!chan || !value) {
            return -1;
        }

        ast_channel_lock(chan);
        if (!(ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
            if (!(ds = ast_datastore_alloc(&secure_call_info, NULL))) {
                ast_channel_unlock(chan);
                return -1;
            }
            if (!(store = ast_calloc(1, sizeof(*store)))) {
                ast_channel_unlock(chan);
                ast_free(ds);
                return -1;
            }
            ds->data = store;
            ast_channel_datastore_add(chan, ds);
        } else {
            store = ds->data;
        }
        ast_channel_unlock(chan);

        if (!strcasecmp(data, "secure_bridge_signaling")) {
            store->signaling = ast_true(value) ? 1 : 0;
        } else if (!strcasecmp(data, "secure_bridge_media")) {
            store->media = ast_true(value) ? 1 : 0;
        }
    } else if (!chan->tech->func_channel_write
               || chan->tech->func_channel_write(chan, function, data, value)) {
        ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
                data);
        ret = -1;
    }

    return ret;
}
Beispiel #27
0
static int func_channel_write_real(struct ast_channel *chan, const char *function,
			      char *data, const char *value)
{
	int ret = 0;
	signed char gainset;

	if (!strcasecmp(data, "language"))
		locked_string_field_set(chan, language, value);
	else if (!strcasecmp(data, "parkinglot"))
		locked_string_field_set(chan, parkinglot, value);
	else if (!strcasecmp(data, "musicclass"))
		locked_string_field_set(chan, musicclass, value);
	else if (!strcasecmp(data, "accountcode"))
		locked_string_field_set(chan, accountcode, value);
	else if (!strcasecmp(data, "userfield"))
		locked_string_field_set(chan, userfield, value);
	else if (!strcasecmp(data, "after_bridge_goto")) {
		if (ast_strlen_zero(value)) {
			ast_bridge_discard_after_goto(chan);
		} else {
			ast_bridge_set_after_go_on(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), value);
		}
	} else if (!strcasecmp(data, "amaflags")) {
		ast_channel_lock(chan);
		if (isdigit(*value)) {
			int amaflags;
			sscanf(value, "%30d", &amaflags);
			ast_channel_amaflags_set(chan, amaflags);
		} else if (!strcasecmp(value,"OMIT")){
			ast_channel_amaflags_set(chan, 1);
		} else if (!strcasecmp(value,"BILLING")){
			ast_channel_amaflags_set(chan, 2);
		} else if (!strcasecmp(value,"DOCUMENTATION")){
			ast_channel_amaflags_set(chan, 3);
		}
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "peeraccount"))
		locked_string_field_set(chan, peeraccount, value);
	else if (!strcasecmp(data, "hangupsource"))
		/* XXX - should we be forcing this here? */
		ast_set_hangupsource(chan, value, 0);
#ifdef CHANNEL_TRACE
	else if (!strcasecmp(data, "trace")) {
		ast_channel_lock(chan);
		if (ast_true(value))
			ret = ast_channel_trace_enable(chan);
		else if (ast_false(value))
			ret = ast_channel_trace_disable(chan);
		else {
			ret = -1;
			ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace).\n");
		}
		ast_channel_unlock(chan);
	}
#endif
	else if (!strcasecmp(data, "tonezone")) {
		struct ast_tone_zone *new_zone;
		if (!(new_zone = ast_get_indication_zone(value))) {
			ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
			ret = -1;
		} else {
			ast_channel_lock(chan);
			if (ast_channel_zone(chan)) {
				ast_channel_zone_set(chan, ast_tone_zone_unref(ast_channel_zone(chan)));
			}
			ast_channel_zone_set(chan, ast_tone_zone_ref(new_zone));
			ast_channel_unlock(chan);
			new_zone = ast_tone_zone_unref(new_zone);
		}
	} else if (!strcasecmp(data, "dtmf_features")) {
		ret = ast_bridge_features_ds_set_string(chan, value);
	} else if (!strcasecmp(data, "callgroup")) {
		ast_channel_lock(chan);
		ast_channel_callgroup_set(chan, ast_get_group(value));
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "pickupgroup")) {
		ast_channel_lock(chan);
		ast_channel_pickupgroup_set(chan, ast_get_group(value));
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "namedcallgroup")) {
		struct ast_namedgroups *groups = ast_get_namedgroups(value);

		ast_channel_lock(chan);
		ast_channel_named_callgroups_set(chan, groups);
		ast_channel_unlock(chan);
		ast_unref_namedgroups(groups);
	} else if (!strcasecmp(data, "namedpickupgroup")) {
		struct ast_namedgroups *groups = ast_get_namedgroups(value);

		ast_channel_lock(chan);
		ast_channel_named_pickupgroups_set(chan, groups);
		ast_channel_unlock(chan);
		ast_unref_namedgroups(groups);
	} else if (!strcasecmp(data, "txgain")) {
		sscanf(value, "%4hhd", &gainset);
		ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0);
	} else if (!strcasecmp(data, "rxgain")) {
		sscanf(value, "%4hhd", &gainset);
		ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0);
	} else if (!strcasecmp(data, "transfercapability")) {
		unsigned short i;

		ast_channel_lock(chan);
		for (i = 0; i < 0x20; i++) {
			if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) {
				ast_channel_transfercapability_set(chan, i);
				break;
			}
		}
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "hangup_handler_pop")) {
		/* Pop one hangup handler before pushing the new handler. */
		ast_pbx_hangup_handler_pop(chan);
		ast_pbx_hangup_handler_push(chan, value);
	} else if (!strcasecmp(data, "hangup_handler_push")) {
		ast_pbx_hangup_handler_push(chan, value);
	} else if (!strcasecmp(data, "hangup_handler_wipe")) {
		/* Pop all hangup handlers before pushing the new handler. */
		while (ast_pbx_hangup_handler_pop(chan)) {
		}
		ast_pbx_hangup_handler_push(chan, value);
	} else if (!strncasecmp(data, "secure_bridge_", 14)) {
		struct ast_datastore *ds;
		struct ast_secure_call_store *store;

		if (!chan || !value) {
			return -1;
		}

		ast_channel_lock(chan);
		if (!(ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
			if (!(ds = ast_datastore_alloc(&secure_call_info, NULL))) {
				ast_channel_unlock(chan);
				return -1;
			}
			if (!(store = ast_calloc(1, sizeof(*store)))) {
				ast_channel_unlock(chan);
				ast_free(ds);
				return -1;
			}
			ds->data = store;
			ast_channel_datastore_add(chan, ds);
		} else {
			store = ds->data;
		}

		if (!strcasecmp(data, "secure_bridge_signaling")) {
			store->signaling = ast_true(value) ? 1 : 0;
		} else if (!strcasecmp(data, "secure_bridge_media")) {
			store->media = ast_true(value) ? 1 : 0;
		}
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "max_forwards")) {
		int max_forwards;
		if (sscanf(value, "%d", &max_forwards) != 1) {
			ast_log(LOG_WARNING, "Unable to set max forwards to '%s'\n", value);
			ret = -1;
		} else {
			ast_channel_lock(chan);
			ret = ast_max_forwards_set(chan, max_forwards);
			ast_channel_unlock(chan);
		}
	} else if (!ast_channel_tech(chan)->func_channel_write
		 || ast_channel_tech(chan)->func_channel_write(chan, function, data, value)) {
		ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
				data);
		ret = -1;
	}

	return ret;
}
Beispiel #28
0
static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
{
	const char *s;
	char *tmp;
	char *cur, *rest;
	char *macro;
	char fullmacro[80];
	char varname[80];
	char runningapp[80], runningdata[1024];
	char *oldargs[MAX_ARGS + 1] = { NULL, };
	int argc, x;
	int res=0;
	char oldexten[256]="";
	int oldpriority, gosub_level = 0;
	char pc[80], depthc[12];
	char oldcontext[AST_MAX_CONTEXT] = "";
	const char *inhangupc;
	int offset, depth = 0, maxdepth = 7;
	int setmacrocontext=0;
	int autoloopflag, inhangup = 0;
	struct ast_str *tmp_subst = NULL;
  
	char *save_macro_exten;
	char *save_macro_context;
	char *save_macro_priority;
	char *save_macro_offset;
	struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
		return -1;
	}

	do {
		if (macro_store) {
			break;
		}
		if (!(macro_store = ast_datastore_alloc(&macro_ds_info, NULL))) {
			ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
			break;
		}
		/* Just the existence of this datastore is enough. */
		macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
		ast_channel_datastore_add(chan, macro_store);
	} while (0);

	/* does the user want a deeper rabbit hole? */
	ast_channel_lock(chan);
	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
		sscanf(s, "%30d", &maxdepth);
	}
	
	/* Count how many levels deep the rabbit hole goes */
	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH"))) {
		sscanf(s, "%30d", &depth);
	}
	
	/* Used for detecting whether to return when a Macro is called from another Macro after hangup */
	if (strcmp(ast_channel_exten(chan), "h") == 0)
		pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
	
	if ((inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP"))) {
		sscanf(inhangupc, "%30d", &inhangup);
	}
	ast_channel_unlock(chan);

	if (depth >= maxdepth) {
		ast_log(LOG_ERROR, "Macro():  possible infinite loop detected.  Returning early.\n");
		return 0;
	}
	snprintf(depthc, sizeof(depthc), "%d", depth + 1);

	tmp = ast_strdupa(data);
	rest = tmp;
	macro = strsep(&rest, ",");
	if (ast_strlen_zero(macro)) {
		ast_log(LOG_WARNING, "Invalid macro name specified\n");
		return 0;
	}

	snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
	if (!ast_exists_extension(chan, fullmacro, "s", 1,
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
		if (!ast_context_find(fullmacro)) 
			ast_log(LOG_WARNING, "No such context '%s' for macro '%s'. Was called by %s@%s\n", fullmacro, macro, ast_channel_exten(chan), ast_channel_context(chan));
		else
			ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
		return 0;
	}

	/* If we are to run the macro exclusively, take the mutex */
	if (exclusive) {
		ast_debug(1, "Locking macrolock for '%s'\n", fullmacro);
		ast_autoservice_start(chan);
		if (ast_context_lockmacro(fullmacro)) {
			ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
			ast_autoservice_stop(chan);
			return 0;
		}
		ast_autoservice_stop(chan);
	}

	if (!(tmp_subst = ast_str_create(16))) {
		return -1;
	}

	/* Save old info */
	oldpriority = ast_channel_priority(chan);
	ast_copy_string(oldexten, ast_channel_exten(chan), sizeof(oldexten));
	ast_copy_string(oldcontext, ast_channel_context(chan), sizeof(oldcontext));
	if (ast_strlen_zero(ast_channel_macrocontext(chan))) {
		ast_channel_macrocontext_set(chan, ast_channel_context(chan));
		ast_channel_macroexten_set(chan, ast_channel_exten(chan));
		ast_channel_macropriority_set(chan, ast_channel_priority(chan));
		setmacrocontext=1;
	}
	argc = 1;
	/* Save old macro variables */
	save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);

	save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);

	save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
	snprintf(pc, sizeof(pc), "%d", oldpriority);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
  
	save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);

	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

	/* Setup environment for new run */
	ast_channel_exten_set(chan, "s");
	ast_channel_context_set(chan, fullmacro);
	ast_channel_priority_set(chan, 1);

	ast_channel_lock(chan);
	while((cur = strsep(&rest, ",")) && (argc < MAX_ARGS)) {
		const char *argp;
  		/* Save copy of old arguments if we're overwriting some, otherwise
	   	let them pass through to the other macro */
  		snprintf(varname, sizeof(varname), "ARG%d", argc);
		if ((argp = pbx_builtin_getvar_helper(chan, varname))) {
			oldargs[argc] = ast_strdup(argp);
		}
		pbx_builtin_setvar_helper(chan, varname, cur);
		argc++;
	}
	ast_channel_unlock(chan);
	autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
	ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
	while (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
		struct ast_context *c;
		struct ast_exten *e;
		int foundx;
		runningapp[0] = '\0';
		runningdata[0] = '\0';

		/* What application will execute? */
		if (ast_rdlock_contexts()) {
			ast_log(LOG_WARNING, "Failed to lock contexts list\n");
		} else {
			for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
				if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
					if (ast_rdlock_context(c)) {
						ast_log(LOG_WARNING, "Unable to lock context?\n");
					} else {
						e = find_matching_priority(c, ast_channel_exten(chan), ast_channel_priority(chan),
							S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
						if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
							ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
							ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
						}
						ast_unlock_context(c);
					}
					break;
				}
			}
		}
		ast_unlock_contexts();

		/* Reset the macro depth, if it was changed in the last iteration */
		pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

		res = ast_spawn_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
			&foundx, 1);
		if (res) {
			/* Something bad happened, or a hangup has been requested. */
			if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
		    	(res == '*') || (res == '#')) {
				/* Just return result as to the previous application as if it had been dialed */
				ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
				break;
			}
			switch(res) {
			case MACRO_EXIT_RESULT:
				res = 0;
				goto out;
			default:
				ast_debug(2, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
				ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
				goto out;
			}
		}

		ast_debug(1, "Executed application: %s\n", runningapp);

		if (!strcasecmp(runningapp, "GOSUB")) {
			gosub_level++;
			ast_debug(1, "Incrementing gosub_level\n");
		} else if (!strcasecmp(runningapp, "GOSUBIF")) {
			char *cond, *app_arg;
			char *app2;
			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
			app2 = ast_str_buffer(tmp_subst);
			cond = strsep(&app2, "?");
			app_arg = strsep(&app2, ":");
			if (pbx_checkcondition(cond)) {
				if (!ast_strlen_zero(app_arg)) {
					gosub_level++;
					ast_debug(1, "Incrementing gosub_level\n");
				}
			} else {
				if (!ast_strlen_zero(app2)) {
					gosub_level++;
					ast_debug(1, "Incrementing gosub_level\n");
				}
			}
		} else if (!strcasecmp(runningapp, "RETURN")) {
			gosub_level--;
			ast_debug(1, "Decrementing gosub_level\n");
		} else if (!strcasecmp(runningapp, "STACKPOP")) {
			gosub_level--;
			ast_debug(1, "Decrementing gosub_level\n");
		} else if (!strncasecmp(runningapp, "EXEC", 4)) {
			/* Must evaluate args to find actual app */
			char *tmp2, *tmp3 = NULL;
			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
			tmp2 = ast_str_buffer(tmp_subst);
			if (!strcasecmp(runningapp, "EXECIF")) {
				if ((tmp3 = strchr(tmp2, '|'))) {
					*tmp3++ = '\0';
				}
				if (!pbx_checkcondition(tmp2)) {
					tmp3 = NULL;
				}
			} else {
				tmp3 = tmp2;
			}

			if (tmp3) {
				ast_debug(1, "Last app: %s\n", tmp3);
			}

			if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
				gosub_level++;
				ast_debug(1, "Incrementing gosub_level\n");
			} else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
				gosub_level--;
				ast_debug(1, "Decrementing gosub_level\n");
			} else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
				gosub_level--;
				ast_debug(1, "Decrementing gosub_level\n");
			}
		}

		if (gosub_level == 0 && strcasecmp(ast_channel_context(chan), fullmacro)) {
			ast_verb(2, "Channel '%s' jumping out of macro '%s'\n", ast_channel_name(chan), macro);
			break;
		}

		/* don't stop executing extensions when we're in "h" */
		if (ast_check_hangup(chan) && !inhangup) {
			ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n", ast_channel_exten(chan), ast_channel_macroexten(chan), ast_channel_priority(chan));
			goto out;
		}
		ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
  	}
	out:

	/* Don't let the channel change now. */
	ast_channel_lock(chan);

	/* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
	snprintf(depthc, sizeof(depthc), "%d", depth);
	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
	ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);

  	for (x = 1; x < argc; x++) {
  		/* Restore old arguments and delete ours */
		snprintf(varname, sizeof(varname), "ARG%d", x);
  		if (oldargs[x]) {
			pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
			ast_free(oldargs[x]);
		} else {
			pbx_builtin_setvar_helper(chan, varname, NULL);
		}
  	}

	/* Restore macro variables */
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
	if (save_macro_exten)
		ast_free(save_macro_exten);
	if (save_macro_context)
		ast_free(save_macro_context);
	if (save_macro_priority)
		ast_free(save_macro_priority);

	if (setmacrocontext) {
		ast_channel_macrocontext_set(chan, "");
		ast_channel_macroexten_set(chan, "");
		ast_channel_macropriority_set(chan, 0);
	}

	if (!strcasecmp(ast_channel_context(chan), fullmacro)) {
		const char *offsets;

  		/* If we're leaving the macro normally, restore original information */
		ast_channel_priority_set(chan, oldpriority);
		ast_channel_context_set(chan, oldcontext);
		ast_channel_exten_set(chan, oldexten);
		if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
			/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
			normally if there is any problem */
			if (sscanf(offsets, "%30d", &offset) == 1) {
				if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan),
					ast_channel_priority(chan) + offset + 1,
					S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
					ast_channel_priority_set(chan, ast_channel_priority(chan) + offset);
				}
			}
		}
	}

	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
	if (save_macro_offset)
		ast_free(save_macro_offset);

	/* Unlock the macro */
	if (exclusive) {
		ast_debug(1, "Unlocking macrolock for '%s'\n", fullmacro);
		if (ast_context_unlockmacro(fullmacro)) {
			ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
			res = 0;
		}
	}
	ast_channel_unlock(chan);
	ast_free(tmp_subst);

	return res;
}
Beispiel #29
0
/*! \brief SpeechBackground(Sound File|Timeout) Dialplan Application */
static int speech_background(struct ast_channel *chan, void *data)
{
        unsigned int timeout = 0;
        int res = 0, done = 0, argc = 0, started = 0, quieted = 0, max_dtmf_len = 0;
        struct ast_module_user *u = NULL;
        struct ast_speech *speech = find_speech(chan);
        struct ast_frame *f = NULL;
        int oldreadformat = AST_FORMAT_SLINEAR;
        char dtmf[AST_MAX_EXTENSION] = "";
        time_t start, current;
        struct ast_datastore *datastore = NULL;
        char *argv[2], *args = NULL, *filename_tmp = NULL, *filename = NULL, tmp[2] = "", dtmf_terminator = '#';
	const char *tmp2 = NULL;

        args = ast_strdupa(data);

        u = ast_module_user_add(chan);

        if (speech == NULL) {
                ast_module_user_remove(u);
                return -1;
        }

	/* If channel is not already answered, then answer it */
	if (chan->_state != AST_STATE_UP && ast_answer(chan)) {
		ast_module_user_remove(u);
		return -1;
	}

        /* Record old read format */
        oldreadformat = chan->readformat;

        /* Change read format to be signed linear */
        if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
                ast_module_user_remove(u);
                return -1;
        }

        /* Parse out options */
        argc = ast_app_separate_args(args, '|', argv, sizeof(argv) / sizeof(argv[0]));
        if (argc > 0) {
                /* Yay sound file */
                filename_tmp = ast_strdupa(argv[0]);
		if (!ast_strlen_zero(argv[1])) {
			if ((timeout = atoi(argv[1])) == 0)
				timeout = -1;
		} else
			timeout = 0;
        }

	/* See if the maximum DTMF length variable is set... we use a variable in case they want to carry it through their entire dialplan */
	if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_MAXLEN")) && !ast_strlen_zero(tmp2))
		max_dtmf_len = atoi(tmp2);

	/* See if a terminator is specified */
	if ((tmp2 = pbx_builtin_getvar_helper(chan, "SPEECH_DTMF_TERMINATOR"))) {
		if (ast_strlen_zero(tmp2))
			dtmf_terminator = '\0';
		else
			dtmf_terminator = tmp2[0];
	}

        /* Before we go into waiting for stuff... make sure the structure is ready, if not - start it again */
        if (speech->state == AST_SPEECH_STATE_NOT_READY || speech->state == AST_SPEECH_STATE_DONE) {
		ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
                ast_speech_start(speech);
        }

	/* Ensure no streams are currently running */
	ast_stopstream(chan);

        /* Okay it's streaming so go into a loop grabbing frames! */
        while (done == 0) {
		/* If the filename is null and stream is not running, start up a new sound file */
		if (!quieted && (chan->streamid == -1 && chan->timingfunc == NULL) && (filename = strsep(&filename_tmp, "&"))) {
			/* Discard old stream information */
			ast_stopstream(chan);
			/* Start new stream */
			speech_streamfile(chan, filename, chan->language);
		}

                /* Run scheduled stuff */
                ast_sched_runq(chan->sched);

                /* Yay scheduling */
                res = ast_sched_wait(chan->sched);
                if (res < 0) {
                        res = 1000;
                }

                /* If there is a frame waiting, get it - if not - oh well */
                if (ast_waitfor(chan, res) > 0) {
                        f = ast_read(chan);
                        if (f == NULL) {
                                /* The channel has hung up most likely */
                                done = 3;
                                break;
                        }
                }

		/* Do timeout check (shared between audio/dtmf) */
		if ((!quieted || strlen(dtmf)) && started == 1) {
			time(&current);
			if ((current-start) >= timeout) {
				done = 1;
				if (f)
					ast_frfree(f);
				break;
			}
		}

                /* Do checks on speech structure to see if it's changed */
                ast_mutex_lock(&speech->lock);
                if (ast_test_flag(speech, AST_SPEECH_QUIET)) {
			if (chan->stream)
				ast_stopstream(chan);
			ast_clear_flag(speech, AST_SPEECH_QUIET);
			quieted = 1;
                }
                /* Check state so we can see what to do */
                switch (speech->state) {
                case AST_SPEECH_STATE_READY:
                        /* If audio playback has stopped do a check for timeout purposes */
                        if (chan->streamid == -1 && chan->timingfunc == NULL)
                                ast_stopstream(chan);
                        if (!quieted && chan->stream == NULL && timeout && started == 0 && !filename_tmp) {
				if (timeout == -1) {
					done = 1;
					if (f)
						ast_frfree(f);
					break;
				}
				time(&start);
				started = 1;
                        }
                        /* Write audio frame out to speech engine if no DTMF has been received */
                        if (!strlen(dtmf) && f != NULL && f->frametype == AST_FRAME_VOICE) {
                                ast_speech_write(speech, f->data, f->datalen);
                        }
                        break;
                case AST_SPEECH_STATE_WAIT:
                        /* Cue up waiting sound if not already playing */
			if (!strlen(dtmf)) {
				if (chan->stream == NULL) {
					if (speech->processing_sound != NULL) {
						if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
							speech_streamfile(chan, speech->processing_sound, chan->language);
						}
					}
				} else if (chan->streamid == -1 && chan->timingfunc == NULL) {
					ast_stopstream(chan);
					if (speech->processing_sound != NULL) {
						if (strlen(speech->processing_sound) > 0 && strcasecmp(speech->processing_sound,"none")) {
							speech_streamfile(chan, speech->processing_sound, chan->language);
						}
					}
				}
			}
                        break;
                case AST_SPEECH_STATE_DONE:
			/* Now that we are done... let's switch back to not ready state */
			ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
			if (!strlen(dtmf)) {
				/* Copy to speech structure the results, if available */
				speech->results = ast_speech_results_get(speech);
				/* Break out of our background too */
				done = 1;
				/* Stop audio playback */
				if (chan->stream != NULL) {
					ast_stopstream(chan);
				}
			}
                        break;
                default:
                        break;
                }
                ast_mutex_unlock(&speech->lock);

                /* Deal with other frame types */
                if (f != NULL) {
                        /* Free the frame we received */
                        switch (f->frametype) {
                        case AST_FRAME_DTMF:
				if (dtmf_terminator != '\0' && f->subclass == dtmf_terminator) {
					done = 1;
				} else {
					if (chan->stream != NULL) {
						ast_stopstream(chan);
					}
					if (!started) {
						/* Change timeout to be 5 seconds for DTMF input */
						timeout = (chan->pbx && chan->pbx->dtimeout) ? chan->pbx->dtimeout : 5;
						started = 1;
					}
					time(&start);
					snprintf(tmp, sizeof(tmp), "%c", f->subclass);
					strncat(dtmf, tmp, sizeof(dtmf) - strlen(dtmf) - 1);
					/* If the maximum length of the DTMF has been reached, stop now */
					if (max_dtmf_len && strlen(dtmf) == max_dtmf_len)
						done = 1;
				}
                                break;
                        case AST_FRAME_CONTROL:
                                switch (f->subclass) {
                                case AST_CONTROL_HANGUP:
                                        /* Since they hung up we should destroy the speech structure */
                                        done = 3;
                                default:
                                        break;
                                }
                        default:
                                break;
                        }
                        ast_frfree(f);
                        f = NULL;
                }
        }

	if (strlen(dtmf)) {
		/* We sort of make a results entry */
		speech->results = ast_calloc(1, sizeof(*speech->results));
		if (speech->results != NULL) {
			ast_speech_dtmf(speech, dtmf);
			speech->results->score = 1000;
			speech->results->text = strdup(dtmf);
			speech->results->grammar = strdup("dtmf");
		}
		ast_speech_change_state(speech, AST_SPEECH_STATE_NOT_READY);
	}

        /* See if it was because they hung up */
        if (done == 3) {
                /* Destroy speech structure */
                ast_speech_destroy(speech);
                datastore = ast_channel_datastore_find(chan, &speech_datastore, NULL);
                if (datastore != NULL) {
                        ast_channel_datastore_remove(chan, datastore);
                }
        } else {
                /* Channel is okay so restore read format */
                ast_set_read_format(chan, oldreadformat);
        }

        ast_module_user_remove(u);

        return 0;
}
Beispiel #30
0
/*!
 * \brief Get the lua_State for this channel
 *
 * If no channel is passed then a new state is allocated.  States with no
 * channel assocatied with them should only be used for matching extensions.
 * If the channel does not yet have a lua state associated with it, one will be
 * created.
 *
 * \note If no channel was passed then the caller is expected to free the state
 * using lua_close().
 *
 * \return a lua_State
 */
static lua_State *lua_get_state(struct ast_channel *chan)
{
	struct ast_datastore *datastore = NULL;
	lua_State *L;

	if (!chan) {
		L = luaL_newstate();
		if (!L) {
			ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
			return NULL;
		}

		if (lua_load_extensions(L, NULL)) {
			const char *error = lua_tostring(L, -1);
			ast_log(LOG_ERROR, "Error loading extensions.lua: %s\n", error);
			lua_close(L);
			return NULL;
		}
		return L;
	} else {
		ast_channel_lock(chan);
		datastore = ast_channel_datastore_find(chan, &lua_datastore, NULL);
		ast_channel_unlock(chan);

		if (!datastore) {
			/* nothing found, allocate a new lua state */
			datastore = ast_datastore_alloc(&lua_datastore, NULL);
			if (!datastore) {
				ast_log(LOG_ERROR, "Error allocation channel datastore for lua_State\n");
				return NULL;
			}

			datastore->data = luaL_newstate();
			if (!datastore->data) {
				ast_datastore_free(datastore);
				ast_log(LOG_ERROR, "Error allocating lua_State, no memory\n");
				return NULL;
			}

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

			L = datastore->data;

			if (lua_load_extensions(L, chan)) {
				const char *error = lua_tostring(L, -1);
				ast_log(LOG_ERROR, "Error loading extensions.lua for %s: %s\n", ast_channel_name(chan), error);

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

				ast_datastore_free(datastore);
				return NULL;
			}
		}

		return datastore->data;
	}
}