Example #1
0
static u_char *ast_var_channels_table(struct variable *vp, oid *name, size_t *length,
									int exact, size_t *var_len, WriteMethod **write_method)
{
	static unsigned long long_ret;
	static u_char bits_ret[2];
	static char string_ret[256];
	struct ast_channel *chan, *bridge;
	struct timeval tval;
	u_char *ret = NULL;
	int i, bit;
	struct ast_str *out = ast_str_alloca(2048);
	struct ast_channel_iterator *iter;

	if (header_simple_table(vp, name, length, exact, var_len, write_method, ast_active_channels()))
		return NULL;

	i = name[*length - 1] - 1;

	if (!(iter = ast_channel_iterator_all_new())) {
		return NULL;
	}

	while ((chan = ast_channel_iterator_next(iter)) && i) {
		ast_channel_unref(chan);
		i--;
	}

	iter = ast_channel_iterator_destroy(iter);

	if (chan == NULL) {
		return NULL;
	}

	*var_len = sizeof(long_ret);

	ast_channel_lock(chan);

	switch (vp->magic) {
	case ASTCHANINDEX:
		long_ret = name[*length - 1];
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANNAME:
		if (!ast_strlen_zero(ast_channel_name(chan))) {
			ast_copy_string(string_ret, ast_channel_name(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANLANGUAGE:
		if (!ast_strlen_zero(ast_channel_language(chan))) {
			ast_copy_string(string_ret, ast_channel_language(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANTYPE:
		ast_copy_string(string_ret, ast_channel_tech(chan)->type, sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMUSICCLASS:
		if (!ast_strlen_zero(ast_channel_musicclass(chan))) {
			ast_copy_string(string_ret, ast_channel_musicclass(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANBRIDGE:
		if ((bridge = ast_bridged_channel(chan)) != NULL) {
			ast_copy_string(string_ret, ast_channel_name(bridge), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANMASQ:
		if (ast_channel_masq(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masq(chan)))) {
			ast_copy_string(string_ret, ast_channel_name(ast_channel_masq(chan)), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANMASQR:
		if (ast_channel_masqr(chan) && !ast_strlen_zero(ast_channel_name(ast_channel_masqr(chan)))) {
			ast_copy_string(string_ret, ast_channel_name(ast_channel_masqr(chan)), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANWHENHANGUP:
		if (!ast_tvzero(*ast_channel_whentohangup(chan))) {
			gettimeofday(&tval, NULL);
			long_ret = difftime(ast_channel_whentohangup(chan)->tv_sec, tval.tv_sec) * 100 - tval.tv_usec / 10000;
			ret= (u_char *)&long_ret;
		}
		break;
	case ASTCHANAPP:
		if (ast_channel_appl(chan)) {
			ast_copy_string(string_ret, ast_channel_appl(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANDATA:
		if (ast_channel_data(chan)) {
			ast_copy_string(string_ret, ast_channel_data(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCONTEXT:
		ast_copy_string(string_ret, ast_channel_context(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMACROCONTEXT:
		ast_copy_string(string_ret, ast_channel_macrocontext(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMACROEXTEN:
		ast_copy_string(string_ret, ast_channel_macroexten(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANMACROPRI:
		long_ret = ast_channel_macropriority(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANEXTEN:
		ast_copy_string(string_ret, ast_channel_exten(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANPRI:
		long_ret = ast_channel_priority(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANACCOUNTCODE:
		if (!ast_strlen_zero(ast_channel_accountcode(chan))) {
			ast_copy_string(string_ret, ast_channel_accountcode(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANFORWARDTO:
		if (!ast_strlen_zero(ast_channel_call_forward(chan))) {
			ast_copy_string(string_ret, ast_channel_call_forward(chan), sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANUNIQUEID:
		ast_copy_string(string_ret, ast_channel_uniqueid(chan), sizeof(string_ret));
		*var_len = strlen(string_ret);
		ret = (u_char *)string_ret;
		break;
	case ASTCHANCALLGROUP:
		long_ret = ast_channel_callgroup(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANPICKUPGROUP:
		long_ret = ast_channel_pickupgroup(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANSTATE:
		long_ret = ast_channel_state(chan) & 0xffff;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANMUTED:
		long_ret = ast_channel_state(chan) & AST_STATE_MUTE ? 1 : 2;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANRINGS:
		long_ret = ast_channel_rings(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDDNID:
		if (ast_channel_dialed(chan)->number.str) {
			ast_copy_string(string_ret, ast_channel_dialed(chan)->number.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDNUM:
		if (ast_channel_caller(chan)->id.number.valid && ast_channel_caller(chan)->id.number.str) {
			ast_copy_string(string_ret, ast_channel_caller(chan)->id.number.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDNAME:
		if (ast_channel_caller(chan)->id.name.valid && ast_channel_caller(chan)->id.name.str) {
			ast_copy_string(string_ret, ast_channel_caller(chan)->id.name.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDANI:
		if (ast_channel_caller(chan)->ani.number.valid && ast_channel_caller(chan)->ani.number.str) {
			ast_copy_string(string_ret, ast_channel_caller(chan)->ani.number.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDRDNIS:
		if (ast_channel_redirecting(chan)->from.number.valid && ast_channel_redirecting(chan)->from.number.str) {
			ast_copy_string(string_ret, ast_channel_redirecting(chan)->from.number.str, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANCIDPRES:
		long_ret = ast_party_id_presentation(&ast_channel_caller(chan)->id);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDANI2:
		long_ret = ast_channel_caller(chan)->ani2;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDTON:
		long_ret = ast_channel_caller(chan)->id.number.plan;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANCIDTNS:
		long_ret = ast_channel_dialed(chan)->transit_network_select;
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANAMAFLAGS:
		long_ret = ast_channel_amaflags(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANADSI:
		long_ret = ast_channel_adsicpe(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANTONEZONE:
		if (ast_channel_zone(chan)) {
			ast_copy_string(string_ret, ast_channel_zone(chan)->country, sizeof(string_ret));
			*var_len = strlen(string_ret);
			ret = (u_char *)string_ret;
		}
		break;
	case ASTCHANHANGUPCAUSE:
		long_ret = ast_channel_hangupcause(chan);
		ret = (u_char *)&long_ret;
		break;
	case ASTCHANVARIABLES:
		if (pbx_builtin_serialize_variables(chan, &out)) {
			*var_len = ast_str_strlen(out);
			ret = (u_char *)ast_str_buffer(out);
		}
		break;
	case ASTCHANFLAGS:
		bits_ret[0] = 0;
		for (bit = 0; bit < 8; bit++)
			bits_ret[0] |= ((ast_channel_flags(chan)->flags & (1 << bit)) >> bit) << (7 - bit);
		bits_ret[1] = 0;
		for (bit = 0; bit < 8; bit++)
			bits_ret[1] |= (((ast_channel_flags(chan)->flags >> 8) & (1 << bit)) >> bit) << (7 - bit);
		*var_len = 2;
		ret = bits_ret;
		break;
	case ASTCHANTRANSFERCAP:
		long_ret = ast_channel_transfercapability(chan);
		ret = (u_char *)&long_ret;
	default:
		break;
	}

	ast_channel_unlock(chan);
	chan = ast_channel_unref(chan);

	return ret;
}
Example #2
0
 */
static int oss_call(struct ast_channel *c, const char *dest, int timeout)
{
	struct chan_oss_pvt *o = ast_channel_tech_pvt(c);
	struct ast_frame f = { AST_FRAME_CONTROL, };
	AST_DECLARE_APP_ARGS(args,
		AST_APP_ARG(name);
		AST_APP_ARG(flags);
	);
	char *parse = ast_strdupa(dest);

	AST_NONSTANDARD_APP_ARGS(args, parse, '/');

	ast_verbose(" << Call to device '%s' dnid '%s' rdnis '%s' on console from '%s' <%s> >>\n",
		dest,
		S_OR(ast_channel_dialed(c)->number.str, ""),
		S_COR(ast_channel_redirecting(c)->from.number.valid, ast_channel_redirecting(c)->from.number.str, ""),
		S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, ""),
		S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, ""));
	if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "answer") == 0) {
		f.subclass.integer = AST_CONTROL_ANSWER;
		ast_queue_frame(c, &f);
	} else if (!ast_strlen_zero(args.flags) && strcasecmp(args.flags, "noanswer") == 0) {
		f.subclass.integer = AST_CONTROL_RINGING;
		ast_queue_frame(c, &f);
		ast_indicate(c, AST_CONTROL_RINGING);
	} else if (o->autoanswer) {
		ast_verbose(" << Auto-answered >> \n");
		f.subclass.integer = AST_CONTROL_ANSWER;
		ast_queue_frame(c, &f);
		o->hookstate = 1;
Example #3
0
static int serialize_showchan(struct ast_channel *c, char *buf, size_t size)
{
	long elapsed_seconds = 0;
	int hour = 0, min = 0, sec = 0;
	struct ast_str *format_buf = ast_str_alloca(64);
	char cgrp[256];
	char pgrp[256];
	struct ast_str *write_transpath = ast_str_alloca(256);
	struct ast_str *read_transpath = ast_str_alloca(256);
	struct ast_bridge *bridge;

	memset(buf, 0, size);
	if (!c)
		return 0;

	elapsed_seconds = ast_channel_get_duration(c);
	hour = elapsed_seconds / 3600;
	min = (elapsed_seconds % 3600) / 60;
	sec = elapsed_seconds % 60;

	ast_channel_lock(c);
	bridge = ast_channel_get_bridge(c);
	ast_channel_unlock(c);

	snprintf(buf,size,
		"Name=               %s\n"
		"Type=               %s\n"
		"UniqueID=           %s\n"
		"LinkedID=           %s\n"
		"CallerIDNum=        %s\n"
		"CallerIDName=       %s\n"
		"ConnectedLineIDNum= %s\n"
		"ConnectedLineIDName=%s\n"
		"DNIDDigits=         %s\n"
		"RDNIS=              %s\n"
		"Parkinglot=         %s\n"
		"Language=           %s\n"
		"State=              %s (%u)\n"
		"Rings=              %d\n"
		"NativeFormat=       %s\n"
		"WriteFormat=        %s\n"
		"ReadFormat=         %s\n"
		"RawWriteFormat=     %s\n"
		"RawReadFormat=      %s\n"
		"WriteTranscode=     %s %s\n"
		"ReadTranscode=      %s %s\n"
		"1stFileDescriptor=  %d\n"
		"Framesin=           %u %s\n"
		"Framesout=          %u %s\n"
		"TimetoHangup=       %ld\n"
		"ElapsedTime=        %dh%dm%ds\n"
		"BridgeID=           %s\n"
		"Context=            %s\n"
		"Extension=          %s\n"
		"Priority=           %d\n"
		"CallGroup=          %s\n"
		"PickupGroup=        %s\n"
		"Application=        %s\n"
		"Data=               %s\n"
		"Blocking_in=        %s\n",
		ast_channel_name(c),
		ast_channel_tech(c)->type,
		ast_channel_uniqueid(c),
		ast_channel_linkedid(c),
		S_COR(ast_channel_caller(c)->id.number.valid, ast_channel_caller(c)->id.number.str, "(N/A)"),
		S_COR(ast_channel_caller(c)->id.name.valid, ast_channel_caller(c)->id.name.str, "(N/A)"),
		S_COR(ast_channel_connected(c)->id.number.valid, ast_channel_connected(c)->id.number.str, "(N/A)"),
		S_COR(ast_channel_connected(c)->id.name.valid, ast_channel_connected(c)->id.name.str, "(N/A)"),
		S_OR(ast_channel_dialed(c)->number.str, "(N/A)"),
		S_COR(ast_channel_redirecting(c)->from.number.valid, ast_channel_redirecting(c)->from.number.str, "(N/A)"),
		ast_channel_parkinglot(c),
		ast_channel_language(c),
		ast_state2str(ast_channel_state(c)),
		ast_channel_state(c),
		ast_channel_rings(c),
		ast_format_cap_get_names(ast_channel_nativeformats(c), &format_buf),
		ast_format_get_name(ast_channel_writeformat(c)),
		ast_format_get_name(ast_channel_readformat(c)),
		ast_format_get_name(ast_channel_rawwriteformat(c)),
		ast_format_get_name(ast_channel_rawreadformat(c)),
		ast_channel_writetrans(c) ? "Yes" : "No",
		ast_translate_path_to_str(ast_channel_writetrans(c), &write_transpath),
		ast_channel_readtrans(c) ? "Yes" : "No",
		ast_translate_path_to_str(ast_channel_readtrans(c), &read_transpath),
		ast_channel_fd(c, 0),
		ast_channel_fin(c) & ~DEBUGCHAN_FLAG, (ast_channel_fin(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
		ast_channel_fout(c) & ~DEBUGCHAN_FLAG, (ast_channel_fout(c) & DEBUGCHAN_FLAG) ? " (DEBUGGED)" : "",
		(long)ast_channel_whentohangup(c)->tv_sec,
		hour,
		min,
		sec,
		bridge ? bridge->uniqueid : "(Not bridged)",
		ast_channel_context(c),
		ast_channel_exten(c),
		ast_channel_priority(c),
		ast_print_group(cgrp, sizeof(cgrp), ast_channel_callgroup(c)),
		ast_print_group(pgrp, sizeof(pgrp), ast_channel_pickupgroup(c)),
		ast_channel_appl(c) ? ast_channel_appl(c) : "(N/A)",
		ast_channel_data(c) ? S_OR(ast_channel_data(c), "(Empty)") : "(None)",
		(ast_test_flag(ast_channel_flags(c), AST_FLAG_BLOCKING) ? ast_channel_blockproc(c) : "(Not Blocking)"));

	ao2_cleanup(bridge);
	return 0;
}
/*!
 * \internal
 * \note This function assumes that we're only called from the "outbound" local channel side
 *
 * \note it is assummed p is locked and reffed before entering this function
 */
static void check_bridge(struct ast_channel *ast, struct local_pvt *p)
{
	struct ast_channel *owner;
	struct ast_channel *chan;
	struct ast_channel *bridged_chan;
	struct ast_frame *f;

	/* Do a few conditional checks early on just to see if this optimization is possible */
	if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
		|| !p->chan || !p->owner) {
		return;
	}

	/* Safely get the channel bridged to p->chan */
	chan = ast_channel_ref(p->chan);

	ao2_unlock(p); /* don't call bridged channel with the pvt locked */
	bridged_chan = ast_bridged_channel(chan);
	ao2_lock(p);

	chan = ast_channel_unref(chan);

	/* since we had to unlock p to get the bridged chan, validate our
	 * data once again and verify the bridged channel is what we expect
	 * it to be in order to perform this optimization */
	if (ast_test_flag(p, LOCAL_NO_OPTIMIZATION | LOCAL_ALREADY_MASQED)
		|| !p->chan || !p->owner
		|| (ast_channel_internal_bridged_channel(p->chan) != bridged_chan)) {
		return;
	}

	/* only do the masquerade if we are being called on the outbound channel,
	   if it has been bridged to another channel and if there are no pending
	   frames on the owner channel (because they would be transferred to the
	   outbound channel during the masquerade)
	*/
	if (!ast_channel_internal_bridged_channel(p->chan) /* Not ast_bridged_channel!  Only go one step! */
		|| !AST_LIST_EMPTY(ast_channel_readq(p->owner))
		|| ast != p->chan /* Sanity check (should always be false) */) {
		return;
	}

	/* Masquerade bridged channel into owner */
	/* Lock everything we need, one by one, and give up if
	   we can't get everything.  Remember, we'll get another
	   chance in just a little bit */
	if (ast_channel_trylock(ast_channel_internal_bridged_channel(p->chan))) {
		return;
	}
	if (ast_check_hangup(ast_channel_internal_bridged_channel(p->chan))
		|| ast_channel_trylock(p->owner)) {
		ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));
		return;
	}

	/*
	 * At this point we have 4 locks:
	 * p, p->chan (same as ast), p->chan->_bridge, p->owner
	 *
	 * Flush a voice or video frame on the outbound channel to make
	 * the queue empty faster so we can get optimized out.
	 */
	f = AST_LIST_FIRST(ast_channel_readq(p->chan));
	if (f && (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO)) {
		AST_LIST_REMOVE_HEAD(ast_channel_readq(p->chan), frame_list);
		ast_frfree(f);
		f = AST_LIST_FIRST(ast_channel_readq(p->chan));
	}

	if (f
		|| ast_check_hangup(p->owner)
		|| ast_channel_masquerade(p->owner, ast_channel_internal_bridged_channel(p->chan))) {
		ast_channel_unlock(p->owner);
		ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));
		return;
	}

	/* Masquerade got setup. */
	ast_debug(4, "Masquerading %s <- %s\n",
		ast_channel_name(p->owner),
		ast_channel_name(ast_channel_internal_bridged_channel(p->chan)));
	if (ast_channel_monitor(p->owner)
		&& !ast_channel_monitor(ast_channel_internal_bridged_channel(p->chan))) {
		struct ast_channel_monitor *tmp;

		/* If a local channel is being monitored, we don't want a masquerade
		 * to cause the monitor to go away. Since the masquerade swaps the monitors,
		 * pre-swapping the monitors before the masquerade will ensure that the monitor
		 * ends up where it is expected.
		 */
		tmp = ast_channel_monitor(p->owner);
		ast_channel_monitor_set(p->owner, ast_channel_monitor(ast_channel_internal_bridged_channel(p->chan)));
		ast_channel_monitor_set(ast_channel_internal_bridged_channel(p->chan), tmp);
	}
	if (ast_channel_audiohooks(p->chan)) {
		struct ast_audiohook_list *audiohooks_swapper;

		audiohooks_swapper = ast_channel_audiohooks(p->chan);
		ast_channel_audiohooks_set(p->chan, ast_channel_audiohooks(p->owner));
		ast_channel_audiohooks_set(p->owner, audiohooks_swapper);
	}

	/* If any Caller ID was set, preserve it after masquerade like above. We must check
	 * to see if Caller ID was set because otherwise we'll mistakingly copy info not
	 * set from the dialplan and will overwrite the real channel Caller ID. The reason
	 * for this whole preswapping action is because the Caller ID is set on the channel
	 * thread (which is the to be masqueraded away local channel) before both local
	 * channels are optimized away.
	 */
	if (ast_channel_caller(p->owner)->id.name.valid || ast_channel_caller(p->owner)->id.number.valid
		|| ast_channel_caller(p->owner)->id.subaddress.valid || ast_channel_caller(p->owner)->ani.name.valid
		|| ast_channel_caller(p->owner)->ani.number.valid || ast_channel_caller(p->owner)->ani.subaddress.valid) {
		SWAP(*ast_channel_caller(p->owner), *ast_channel_caller(ast_channel_internal_bridged_channel(p->chan)));
	}
	if (ast_channel_redirecting(p->owner)->from.name.valid || ast_channel_redirecting(p->owner)->from.number.valid
		|| ast_channel_redirecting(p->owner)->from.subaddress.valid || ast_channel_redirecting(p->owner)->to.name.valid
		|| ast_channel_redirecting(p->owner)->to.number.valid || ast_channel_redirecting(p->owner)->to.subaddress.valid) {
		SWAP(*ast_channel_redirecting(p->owner), *ast_channel_redirecting(ast_channel_internal_bridged_channel(p->chan)));
	}
	if (ast_channel_dialed(p->owner)->number.str || ast_channel_dialed(p->owner)->subaddress.valid) {
		SWAP(*ast_channel_dialed(p->owner), *ast_channel_dialed(ast_channel_internal_bridged_channel(p->chan)));
	}
	ast_app_group_update(p->chan, p->owner);
	ast_set_flag(p, LOCAL_ALREADY_MASQED);

	ast_channel_unlock(p->owner);
	ast_channel_unlock(ast_channel_internal_bridged_channel(p->chan));

	/* Do the masquerade now. */
	owner = ast_channel_ref(p->owner);
	ao2_unlock(p);
	ast_channel_unlock(ast);
	ast_do_masquerade(owner);
	ast_channel_unref(owner);
	ast_channel_lock(ast);
	ao2_lock(p);
}
/*! \brief Initiate new call, part of PBX interface
 *         dest is the dial string */
static int local_call(struct ast_channel *ast, const char *dest, int timeout)
{
	struct local_pvt *p = ast_channel_tech_pvt(ast);
	int pvt_locked = 0;

	struct ast_channel *owner = NULL;
	struct ast_channel *chan = NULL;
	int res;
	struct ast_var_t *varptr;
	struct ast_var_t *clone_var;
	char *reduced_dest = ast_strdupa(dest);
	char *slash;
	const char *exten;
	const char *context;

	if (!p) {
		return -1;
	}

	/* since we are letting go of channel locks that were locked coming into
	 * this function, then we need to give the tech pvt a ref */
	ao2_ref(p, 1);
	ast_channel_unlock(ast);

	awesome_locking(p, &chan, &owner);
	pvt_locked = 1;

	if (owner != ast) {
		res = -1;
		goto return_cleanup;
	}

	if (!owner || !chan) {
		res = -1;
		goto return_cleanup;
	}

	/*
	 * Note that cid_num and cid_name aren't passed in the ast_channel_alloc
	 * call, so it's done here instead.
	 *
	 * All these failure points just return -1. The individual strings will
	 * be cleared when we destroy the channel.
	 */
	ast_party_redirecting_copy(ast_channel_redirecting(chan), ast_channel_redirecting(owner));

	ast_party_dialed_copy(ast_channel_dialed(chan), ast_channel_dialed(owner));

	ast_connected_line_copy_to_caller(ast_channel_caller(chan), ast_channel_connected(owner));
	ast_connected_line_copy_from_caller(ast_channel_connected(chan), ast_channel_caller(owner));

	ast_channel_language_set(chan, ast_channel_language(owner));
	ast_channel_accountcode_set(chan, ast_channel_accountcode(owner));
	ast_channel_musicclass_set(chan, ast_channel_musicclass(owner));
	ast_cdr_update(chan);

	ast_channel_cc_params_init(chan, ast_channel_get_cc_config_params(owner));

	/* Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's set on the queue/dial call request in the dialplan */
	if (ast_channel_hangupcause(ast) == AST_CAUSE_ANSWERED_ELSEWHERE) {
		ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);
	}

	/* copy the channel variables from the incoming channel to the outgoing channel */
	/* Note that due to certain assumptions, they MUST be in the same order */
	AST_LIST_TRAVERSE(ast_channel_varshead(owner), varptr, entries) {
		clone_var = ast_var_assign(varptr->name, varptr->value);
		if (clone_var) {
			AST_LIST_INSERT_TAIL(ast_channel_varshead(chan), clone_var, entries);
		}
	}
Example #6
0
int ast_cel_report_event(struct ast_channel *chan, enum ast_cel_event_type event_type,
                         const char *userdefevname, const char *extra, struct ast_channel *peer2)
{
    struct timeval eventtime;
    struct ast_event *ev;
    const char *peername = "";
    struct ast_channel *peer;

    ast_channel_lock(chan);
    peer = ast_bridged_channel(chan);
    if (peer) {
        ast_channel_ref(peer);
    }
    ast_channel_unlock(chan);

    /* Make sure a reload is not occurring while we're checking to see if this
     * is an event that we care about.  We could lose an important event in this
     * process otherwise. */
    ast_mutex_lock(&reload_lock);

    if (!cel_enabled || !ast_cel_track_event(event_type)) {
        ast_mutex_unlock(&reload_lock);
        if (peer) {
            ast_channel_unref(peer);
        }
        return 0;
    }

    if (event_type == AST_CEL_APP_START || event_type == AST_CEL_APP_END) {
        char *app;
        if (!(app = ao2_find(appset, (char *) ast_channel_appl(chan), OBJ_POINTER))) {
            ast_mutex_unlock(&reload_lock);
            if (peer) {
                ast_channel_unref(peer);
            }
            return 0;
        }
        ao2_ref(app, -1);
    }

    ast_mutex_unlock(&reload_lock);

    if (peer) {
        ast_channel_lock(peer);
        peername = ast_strdupa(ast_channel_name(peer));
        ast_channel_unlock(peer);
    } else if (peer2) {
        ast_channel_lock(peer2);
        peername = ast_strdupa(ast_channel_name(peer2));
        ast_channel_unlock(peer2);
    }

    if (!userdefevname) {
        userdefevname = "";
    }

    if (!extra) {
        extra = "";
    }

    eventtime = ast_tvnow();

    ast_channel_lock(chan);

    ev = ast_event_new(AST_EVENT_CEL,
                       AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, event_type,
                       AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_sec,
                       AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, eventtime.tv_usec,
                       AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, userdefevname,
                       AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR,
                       S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""),
                       AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR,
                       S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
                       AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR,
                       S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""),
                       AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR,
                       S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""),
                       AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR,
                       S_OR(ast_channel_dialed(chan)->number.str, ""),
                       AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, ast_channel_exten(chan),
                       AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, ast_channel_context(chan),
                       AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, ast_channel_name(chan),
                       AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_appl(chan), ""),
                       AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, S_OR(ast_channel_data(chan), ""),
                       AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, ast_channel_amaflags(chan),
                       AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, ast_channel_accountcode(chan),
                       AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, ast_channel_peeraccount(chan),
                       AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, ast_channel_uniqueid(chan),
                       AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, ast_channel_linkedid(chan),
                       AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, ast_channel_userfield(chan),
                       AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, extra,
                       AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, peername,
                       AST_EVENT_IE_END);

    ast_channel_unlock(chan);

    if (peer) {
        peer = ast_channel_unref(peer);
    }

    if (ev && ast_event_queue(ev)) {
        ast_event_destroy(ev);
        return -1;
    }

    return 0;
}
Example #7
0
struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event)
{
    struct varshead *headp;
    struct ast_var_t *newvariable;
    const char *mixed_name;
    char timebuf[30];
    struct ast_channel *tchan;
    struct ast_cel_event_record record = {
        .version = AST_CEL_EVENT_RECORD_VERSION,
    };

    /* do not call ast_channel_alloc because this is not really a real channel */
    if (!(tchan = ast_dummy_channel_alloc())) {
        return NULL;
    }

    headp = ast_channel_varshead(tchan);

    /* first, get the variables from the event */
    if (ast_cel_fill_record(event, &record)) {
        ast_channel_unref(tchan);
        return NULL;
    }

    /* next, fill the channel with their data */
    mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
                 ? record.user_defined_name : record.event_name;
    if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
        AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    }

    if (ast_strlen_zero(cel_dateformat)) {
        snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
                 (long) record.event_time.tv_usec);
    } else {
        struct ast_tm tm;
        ast_localtime(&record.event_time, &tm, NULL);
        ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
    }

    if ((newvariable = ast_var_assign("eventtime", timebuf))) {
        AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    }

    if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
        AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    }
    if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
        AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    }
    if ((newvariable = ast_var_assign("eventextra", record.extra))) {
        AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    }

    ast_channel_caller(tchan)->id.name.valid = 1;
    ast_channel_caller(tchan)->id.name.str = ast_strdup(record.caller_id_name);
    ast_channel_caller(tchan)->id.number.valid = 1;
    ast_channel_caller(tchan)->id.number.str = ast_strdup(record.caller_id_num);
    ast_channel_caller(tchan)->ani.number.valid = 1;
    ast_channel_caller(tchan)->ani.number.str = ast_strdup(record.caller_id_ani);
    ast_channel_redirecting(tchan)->from.number.valid = 1;
    ast_channel_redirecting(tchan)->from.number.str = ast_strdup(record.caller_id_rdnis);
    ast_channel_dialed(tchan)->number.str = ast_strdup(record.caller_id_dnid);

    ast_channel_exten_set(tchan, record.extension);
    ast_channel_context_set(tchan, record.context);
    ast_channel_name_set(tchan, record.channel_name);
    ast_channel_uniqueid_set(tchan, record.unique_id);
    ast_channel_linkedid_set(tchan, record.linked_id);
    ast_channel_accountcode_set(tchan, record.account_code);
    ast_channel_peeraccount_set(tchan, record.peer_account);
    ast_channel_userfield_set(tchan, record.user_field);

    if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
        AST_LIST_INSERT_HEAD(headp, newvariable, entries);
    }

    ast_channel_appl_set(tchan, ast_strdup(record.application_name));
    ast_channel_data_set(tchan, ast_strdup(record.application_data));
    ast_channel_amaflags_set(tchan, record.amaflag);

    return tchan;
}
Example #8
0
struct ast_channel_snapshot *ast_channel_snapshot_create(struct ast_channel *chan)
{
	struct ast_channel_snapshot *snapshot;
	struct ast_bridge *bridge;
	char nativeformats[256];
	struct ast_str *write_transpath = ast_str_alloca(256);
	struct ast_str *read_transpath = ast_str_alloca(256);
	struct ast_party_id effective_connected_id;
	struct ast_callid *callid;

	/* no snapshots for dummy channels */
	if (!ast_channel_tech(chan)) {
		return NULL;
	}

	snapshot = ao2_alloc(sizeof(*snapshot), channel_snapshot_dtor);
	if (!snapshot || ast_string_field_init(snapshot, 1024)) {
		ao2_cleanup(snapshot);
		return NULL;
	}

	ast_string_field_set(snapshot, name, ast_channel_name(chan));
	ast_string_field_set(snapshot, type, ast_channel_tech(chan)->type);
	ast_string_field_set(snapshot, accountcode, ast_channel_accountcode(chan));
	ast_string_field_set(snapshot, peeraccount, ast_channel_peeraccount(chan));
	ast_string_field_set(snapshot, userfield, ast_channel_userfield(chan));
	ast_string_field_set(snapshot, uniqueid, ast_channel_uniqueid(chan));
	ast_string_field_set(snapshot, linkedid, ast_channel_linkedid(chan));
	ast_string_field_set(snapshot, hangupsource, ast_channel_hangupsource(chan));
	if (ast_channel_appl(chan)) {
		ast_string_field_set(snapshot, appl, ast_channel_appl(chan));
	}
	if (ast_channel_data(chan)) {
		ast_string_field_set(snapshot, data, ast_channel_data(chan));
	}
	ast_string_field_set(snapshot, context, ast_channel_context(chan));
	ast_string_field_set(snapshot, exten, ast_channel_exten(chan));

	ast_string_field_set(snapshot, caller_name,
		S_COR(ast_channel_caller(chan)->id.name.valid, ast_channel_caller(chan)->id.name.str, ""));
	ast_string_field_set(snapshot, caller_number,
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""));
	ast_string_field_set(snapshot, caller_dnid, S_OR(ast_channel_dialed(chan)->number.str, ""));
	ast_string_field_set(snapshot, caller_subaddr,
		S_COR(ast_channel_caller(chan)->id.subaddress.valid, ast_channel_caller(chan)->id.subaddress.str, ""));
	ast_string_field_set(snapshot, dialed_subaddr,
		S_COR(ast_channel_dialed(chan)->subaddress.valid, ast_channel_dialed(chan)->subaddress.str, ""));
	ast_string_field_set(snapshot, caller_ani,
		S_COR(ast_channel_caller(chan)->ani.number.valid, ast_channel_caller(chan)->ani.number.str, ""));
	ast_string_field_set(snapshot, caller_rdnis,
		S_COR(ast_channel_redirecting(chan)->from.number.valid, ast_channel_redirecting(chan)->from.number.str, ""));
	ast_string_field_set(snapshot, caller_dnid,
		S_OR(ast_channel_dialed(chan)->number.str, ""));

	ast_string_field_set(snapshot, connected_name,
		S_COR(ast_channel_connected(chan)->id.name.valid, ast_channel_connected(chan)->id.name.str, ""));
	ast_string_field_set(snapshot, connected_number,
		S_COR(ast_channel_connected(chan)->id.number.valid, ast_channel_connected(chan)->id.number.str, ""));
	ast_string_field_set(snapshot, language, ast_channel_language(chan));

	if ((bridge = ast_channel_get_bridge(chan))) {
		ast_string_field_set(snapshot, bridgeid, bridge->uniqueid);
		ao2_cleanup(bridge);
	}

	ast_string_field_set(snapshot, nativeformats, ast_getformatname_multiple(nativeformats, sizeof(nativeformats),
		ast_channel_nativeformats(chan)));
	ast_string_field_set(snapshot, readformat, ast_getformatname(ast_channel_readformat(chan)));
	ast_string_field_set(snapshot, writeformat, ast_getformatname(ast_channel_writeformat(chan)));
	ast_string_field_set(snapshot, writetrans, ast_translate_path_to_str(ast_channel_writetrans(chan), &write_transpath));
	ast_string_field_set(snapshot, readtrans, ast_translate_path_to_str(ast_channel_readtrans(chan), &read_transpath));

	effective_connected_id = ast_channel_connected_effective_id(chan);
	ast_string_field_set(snapshot, effective_name,
		S_COR(effective_connected_id.name.valid, effective_connected_id.name.str, ""));
	ast_string_field_set(snapshot, effective_number,
		S_COR(effective_connected_id.number.valid, effective_connected_id.number.str, ""));

	if ((callid = ast_channel_callid(chan))) {
		ast_callid_strnprint(snapshot->callid, sizeof(snapshot->callid), callid);
		ast_callid_unref(callid);
	}

	snapshot->creationtime = ast_channel_creationtime(chan);
	snapshot->hanguptime = *(ast_channel_whentohangup(chan));
	snapshot->state = ast_channel_state(chan);
	snapshot->priority = ast_channel_priority(chan);
	snapshot->amaflags = ast_channel_amaflags(chan);
	snapshot->hangupcause = ast_channel_hangupcause(chan);
	ast_copy_flags(&snapshot->flags, ast_channel_flags(chan), 0xFFFFFFFF);
	snapshot->caller_pres = ast_party_id_presentation(&ast_channel_caller(chan)->id);
	snapshot->callgroup = ast_channel_callgroup(chan);
	snapshot->pickupgroup = ast_channel_pickupgroup(chan);
	ast_set_flag(&snapshot->softhangup_flags, ast_channel_softhangup_internal_flag(chan));

	snapshot->manager_vars = ast_channel_get_manager_vars(chan);
	snapshot->channel_vars = ast_channel_get_vars(chan);
	snapshot->tech_properties = ast_channel_tech(chan)->properties;

	return snapshot;
}
Example #9
0
/*!
 * \internal
 * \brief Handle COLP and redirecting conditions.
 * \since 12.0.0
 *
 * \param p Unreal private structure.
 * \param ast Channel indicating the condition.
 * \param condition What is being indicated.
 *
 * \retval 0 on success.
 * \retval -1 on error.
 */
static int unreal_colp_redirect_indicate(struct ast_unreal_pvt *p, struct ast_channel *ast, int condition)
{
	struct ast_channel *my_chan;
	struct ast_channel *my_owner;
	struct ast_channel *this_channel;
	struct ast_channel *the_other_channel;
	int isoutbound;
	int res = 0;
	unsigned char frame_data[1024];
	struct ast_frame f = {
		.frametype = AST_FRAME_CONTROL,
		.subclass.integer = condition,
		.data.ptr = frame_data,
	};

	/*
	 * A connected line update frame may only contain a partial
	 * amount of data, such as just a source, or just a ton, and not
	 * the full amount of information.  However, the collected
	 * information is all stored in the outgoing channel's
	 * connectedline structure, so when receiving a connected line
	 * update on an outgoing unreal channel, we need to transmit the
	 * collected connected line information instead of whatever
	 * happens to be in this control frame.  The same applies for
	 * redirecting information, which is why it is handled here as
	 * well.
	 */
	ast_channel_unlock(ast);
	ast_unreal_lock_all(p, &my_chan, &my_owner);
	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
	if (isoutbound) {
		this_channel = p->chan;
		the_other_channel = p->owner;
	} else {
		this_channel = p->owner;
		the_other_channel = p->chan;
	}
	if (the_other_channel) {
		if (condition == AST_CONTROL_CONNECTED_LINE) {
			ast_connected_line_copy_to_caller(ast_channel_caller(the_other_channel),
				ast_channel_connected(this_channel));
			f.datalen = ast_connected_line_build_data(frame_data, sizeof(frame_data),
				ast_channel_connected(this_channel), NULL);
		} else {
			f.datalen = ast_redirecting_build_data(frame_data, sizeof(frame_data),
				ast_channel_redirecting(this_channel), NULL);
		}
	}
	if (my_chan) {
		ast_channel_unlock(my_chan);
		ast_channel_unref(my_chan);
	}
	if (my_owner) {
		ast_channel_unlock(my_owner);
		ast_channel_unref(my_owner);
	}
	if (the_other_channel) {
		res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
	}
	ao2_unlock(p);
	ast_channel_lock(ast);

	return res;
}

int ast_unreal_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
{
	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
	int res = 0;

	if (!p) {
		return -1;
	}

	ao2_ref(p, 1); /* ref for unreal_queue_frame */

	switch (condition) {
	case AST_CONTROL_CONNECTED_LINE:
	case AST_CONTROL_REDIRECTING:
		res = unreal_colp_redirect_indicate(p, ast, condition);
		break;
	case AST_CONTROL_HOLD:
		if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
			ast_moh_start(ast, data, NULL);
			break;
		}
		res = unreal_queue_indicate(p, ast, condition, data, datalen);
		break;
	case AST_CONTROL_UNHOLD:
		if (ast_test_flag(p, AST_UNREAL_MOH_INTERCEPT)) {
			ast_moh_stop(ast);
			break;
		}
		res = unreal_queue_indicate(p, ast, condition, data, datalen);
		break;
	default:
		res = unreal_queue_indicate(p, ast, condition, data, datalen);
		break;
	}

	ao2_ref(p, -1);
	return res;
}

int ast_unreal_digit_begin(struct ast_channel *ast, char digit)
{
	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
	int res = -1;
	struct ast_frame f = { AST_FRAME_DTMF_BEGIN, };
	int isoutbound;

	if (!p) {
		return -1;
	}

	ao2_ref(p, 1); /* ref for unreal_queue_frame */
	ao2_lock(p);
	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
	f.subclass.integer = digit;
	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
	ao2_unlock(p);
	ao2_ref(p, -1);

	return res;
}

int ast_unreal_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
{
	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
	int res = -1;
	struct ast_frame f = { AST_FRAME_DTMF_END, };
	int isoutbound;

	if (!p) {
		return -1;
	}

	ao2_ref(p, 1); /* ref for unreal_queue_frame */
	ao2_lock(p);
	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
	f.subclass.integer = digit;
	f.len = duration;
	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
	ao2_unlock(p);
	ao2_ref(p, -1);

	return res;
}

int ast_unreal_sendtext(struct ast_channel *ast, const char *text)
{
	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
	int res = -1;
	struct ast_frame f = { AST_FRAME_TEXT, };
	int isoutbound;

	if (!p) {
		return -1;
	}

	ao2_ref(p, 1); /* ref for unreal_queue_frame */
	ao2_lock(p);
	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
	f.data.ptr = (char *) text;
	f.datalen = strlen(text) + 1;
	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
	ao2_unlock(p);
	ao2_ref(p, -1);
	return res;
}

int ast_unreal_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
{
	struct ast_unreal_pvt *p = ast_channel_tech_pvt(ast);
	int res = -1;
	struct ast_frame f = { AST_FRAME_HTML, };
	int isoutbound;

	if (!p) {
		return -1;
	}

	ao2_ref(p, 1); /* ref for unreal_queue_frame */
	ao2_lock(p);
	isoutbound = AST_UNREAL_IS_OUTBOUND(ast, p);
	f.subclass.integer = subclass;
	f.data.ptr = (char *)data;
	f.datalen = datalen;
	res = unreal_queue_frame(p, isoutbound, &f, ast, 0);
	ao2_unlock(p);
	ao2_ref(p, -1);

	return res;
}

void ast_unreal_call_setup(struct ast_channel *semi1, struct ast_channel *semi2)
{
	struct ast_var_t *varptr;
	struct ast_var_t *clone_var;

	/*
	 * Note that cid_num and cid_name aren't passed in the
	 * ast_channel_alloc calls in ast_unreal_new_channels().  It's
	 * done here instead.
	 */
	ast_party_redirecting_copy(ast_channel_redirecting(semi2), ast_channel_redirecting(semi1));

	ast_party_dialed_copy(ast_channel_dialed(semi2), ast_channel_dialed(semi1));

	ast_connected_line_copy_to_caller(ast_channel_caller(semi2), ast_channel_connected(semi1));
	ast_connected_line_copy_from_caller(ast_channel_connected(semi2), ast_channel_caller(semi1));

	ast_channel_language_set(semi2, ast_channel_language(semi1));
	ast_channel_accountcode_set(semi2, ast_channel_accountcode(semi1));
	ast_channel_musicclass_set(semi2, ast_channel_musicclass(semi1));

	ast_channel_cc_params_init(semi2, ast_channel_get_cc_config_params(semi1));

	/*
	 * Make sure we inherit the AST_CAUSE_ANSWERED_ELSEWHERE if it's
	 * set on the queue/dial call request in the dialplan.
	 */
	if (ast_channel_hangupcause(semi1) == AST_CAUSE_ANSWERED_ELSEWHERE) {
		ast_channel_hangupcause_set(semi2, AST_CAUSE_ANSWERED_ELSEWHERE);
	}

	/*
	 * Copy the channel variables from the semi1 channel to the
	 * outgoing channel.
	 *
	 * Note that due to certain assumptions, they MUST be in the
	 * same order.
	 */
	AST_LIST_TRAVERSE(ast_channel_varshead(semi1), varptr, entries) {
		clone_var = ast_var_assign(varptr->name, varptr->value);
		if (clone_var) {
			AST_LIST_INSERT_TAIL(ast_channel_varshead(semi2), clone_var, entries);
		}
	}
	ast_channel_datastore_inherit(semi1, semi2);
}
Example #10
0
struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event *event)
{
	struct varshead *headp;
	struct ast_var_t *newvariable;
	const char *mixed_name;
	char timebuf[30];
	struct ast_channel *tchan;
	struct ast_cel_event_record record = {
		.version = AST_CEL_EVENT_RECORD_VERSION,
	};
	struct ast_datastore *datastore;
	char *app_data;

	/* do not call ast_channel_alloc because this is not really a real channel */
	if (!(tchan = ast_dummy_channel_alloc())) {
		return NULL;
	}

	headp = ast_channel_varshead(tchan);

	/* first, get the variables from the event */
	if (ast_cel_fill_record(event, &record)) {
		ast_channel_unref(tchan);
		return NULL;
	}

	/* next, fill the channel with their data */
	mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
		? record.user_defined_name : record.event_name;
	if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}

	if (ast_strlen_zero(cel_dateformat)) {
		snprintf(timebuf, sizeof(timebuf), "%ld.%06ld", (long) record.event_time.tv_sec,
				(long) record.event_time.tv_usec);
	} else {
		struct ast_tm tm;
		ast_localtime(&record.event_time, &tm, NULL);
		ast_strftime(timebuf, sizeof(timebuf), cel_dateformat, &tm);
	}

	if ((newvariable = ast_var_assign("eventtime", timebuf))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}

	if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}
	if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}
	if ((newvariable = ast_var_assign("eventextra", record.extra))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}

	ast_channel_caller(tchan)->id.name.valid = 1;
	ast_channel_caller(tchan)->id.name.str = ast_strdup(record.caller_id_name);
	ast_channel_caller(tchan)->id.number.valid = 1;
	ast_channel_caller(tchan)->id.number.str = ast_strdup(record.caller_id_num);
	ast_channel_caller(tchan)->ani.number.valid = 1;
	ast_channel_caller(tchan)->ani.number.str = ast_strdup(record.caller_id_ani);
	ast_channel_redirecting(tchan)->from.number.valid = 1;
	ast_channel_redirecting(tchan)->from.number.str = ast_strdup(record.caller_id_rdnis);
	ast_channel_dialed(tchan)->number.str = ast_strdup(record.caller_id_dnid);

	ast_channel_exten_set(tchan, record.extension);
	ast_channel_context_set(tchan, record.context);
	ast_channel_name_set(tchan, record.channel_name);
	ast_channel_uniqueid_set(tchan, record.unique_id);
	ast_channel_linkedid_set(tchan, record.linked_id);
	ast_channel_accountcode_set(tchan, record.account_code);
	ast_channel_peeraccount_set(tchan, record.peer_account);
	ast_channel_userfield_set(tchan, record.user_field);

	if ((newvariable = ast_var_assign("BRIDGEPEER", record.peer))) {
		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
	}

	ast_channel_amaflags_set(tchan, record.amaflag);

	/* We need to store an 'application name' and 'application
	 * data' on the channel for logging purposes, but the channel
	 * structure only provides a place to store pointers, and it
	 * expects these pointers to be pointing to data that does not
	 * need to be freed. This means that the channel's destructor
	 * does not attempt to free any storage that these pointers
	 * point to. However, we can't provide data in that form directly for
	 * these structure members. In order to ensure that these data
	 * elements have a lifetime that matches the channel's
	 * lifetime, we'll put them in a datastore attached to the
	 * channel, and set's the channel's pointers to point into the
	 * datastore.  The datastore will then be automatically destroyed
	 * when the channel is destroyed.
	 */

	if (!(datastore = ast_datastore_alloc(&fabricated_channel_datastore, NULL))) {
		ast_channel_unref(tchan);
		return NULL;
	}

	if (!(app_data = ast_malloc(strlen(record.application_name) + strlen(record.application_data) + 2))) {
		ast_datastore_free(datastore);
		ast_channel_unref(tchan);
		return NULL;
	}

	ast_channel_appl_set(tchan, strcpy(app_data, record.application_name));
	ast_channel_data_set(tchan, strcpy(app_data + strlen(record.application_name) + 1,
		record.application_data));

	datastore->data = app_data;
	ast_channel_datastore_add(tchan, datastore);

	return tchan;
}