Esempio n. 1
0
/*!
 * \internal
 * \brief Queue a connected line update on a session's channel.
 * \param session The session whose channel should have the connected line update queued upon.
 * \param id The identification information to place in the connected line update
 */
static void queue_connected_line_update(struct ast_sip_session *session, const struct ast_party_id *id)
{
	struct ast_party_connected_line connected;
	struct ast_set_party_connected_line update_connected;

	ast_party_connected_line_init(&connected);
	ast_party_id_copy(&connected.id, id);

	memset(&update_connected, 0, sizeof(update_connected));
	update_connected.id.number = 1;
	update_connected.id.name = 1;

	ast_set_party_id_all(&update_connected.priv);
	connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
	ast_party_id_copy(&session->id, &connected.id);
	ast_channel_queue_connected_line_update(session->channel, &connected, &update_connected);

	ast_party_connected_line_free(&connected);
}
/*!
 * \internal
 * \brief Queue a connected line update on a session's channel.
 * \param session The session whose channel should have the connected line update queued upon.
 * \param id The identification information to place in the connected line update
 */
static void queue_connected_line_update(struct ast_sip_session *session, const struct ast_party_id *id)
{
	struct ast_party_connected_line connected;
	struct ast_party_caller caller;

	/* Fill connected line information */
	ast_party_connected_line_init(&connected);
	connected.id = *id;
	connected.id.tag = session->endpoint->id.self.tag;
	connected.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;

	/* Save to channel driver copy */
	ast_party_id_copy(&session->id, &connected.id);

	/* Update our channel CALLERID() */
	ast_party_caller_init(&caller);
	caller.id = connected.id;
	caller.ani = connected.id;
	caller.ani2 = ast_channel_caller(session->channel)->ani2;
	ast_channel_set_caller_event(session->channel, &caller, NULL);

	/* Tell peer about the new connected line information. */
	ast_channel_queue_connected_line_update(session->channel, &connected, NULL);
}
Esempio n. 3
0
int ast_do_pickup(struct ast_channel *chan, struct ast_channel *target)
{
	struct ast_party_connected_line connected_caller;
	struct ast_datastore *ds_pickup;
	const char *chan_name;/*!< A masquerade changes channel names. */
	const char *target_name;/*!< A masquerade changes channel names. */
	int res = -1;

	RAII_VAR(struct ast_channel_snapshot *, chan_snapshot, NULL, ao2_cleanup);
	RAII_VAR(struct ast_channel_snapshot *, target_snapshot, NULL, ao2_cleanup);

	target_name = ast_strdupa(ast_channel_name(target));
	ast_debug(1, "Call pickup on '%s' by '%s'\n", target_name, ast_channel_name(chan));

	/* Mark the target to block any call pickup race. */
	ds_pickup = ast_datastore_alloc(&pickup_active, NULL);
	if (!ds_pickup) {
		ast_log(LOG_WARNING,
			"Unable to create channel datastore on '%s' for call pickup\n", target_name);
		return -1;
	}
	ast_channel_datastore_add(target, ds_pickup);

	ast_party_connected_line_init(&connected_caller);
	ast_party_connected_line_copy(&connected_caller, ast_channel_connected(target));
	ast_channel_unlock(target);/* The pickup race is avoided so we do not need the lock anymore. */
	/* Reset any earlier private connected id representation */
	ast_party_id_reset(&connected_caller.priv);

	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
	if (ast_channel_connected_line_sub(NULL, chan, &connected_caller, 0) &&
		ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
		ast_channel_update_connected_line(chan, &connected_caller, NULL);
	}
	ast_party_connected_line_free(&connected_caller);

	ast_channel_lock(chan);
	chan_name = ast_strdupa(ast_channel_name(chan));
	ast_connected_line_copy_from_caller(&connected_caller, ast_channel_caller(chan));
	ast_channel_unlock(chan);
	connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;

	if (ast_answer(chan)) {
		ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan_name);
		goto pickup_failed;
	}

	if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
		ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan_name);
		goto pickup_failed;
	}

	ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);

	/* setting the HANGUPCAUSE so the ringing channel knows this call was not a missed call */
	ast_channel_hangupcause_set(chan, AST_CAUSE_ANSWERED_ELSEWHERE);

	ast_channel_lock(chan);
	chan_snapshot = ast_channel_snapshot_create(chan);
	ast_channel_unlock(chan);
	if (!chan_snapshot) {
		goto pickup_failed;
	}

	target_snapshot = ast_channel_snapshot_get_latest(ast_channel_uniqueid(target));
	if (!target_snapshot) {
		goto pickup_failed;
	}

	if (ast_channel_move(target, chan)) {
		ast_log(LOG_WARNING, "Unable to complete call pickup of '%s' with '%s'\n",
			chan_name, target_name);
		goto pickup_failed;
	}

	/* target points to the channel that did the pickup at this point, so use that channel's topic instead of chan */
	send_call_pickup_stasis_message(target, chan_snapshot, target_snapshot);

	res = 0;

pickup_failed:
	ast_channel_lock(target);
	if (!ast_channel_datastore_remove(target, ds_pickup)) {
		ast_datastore_free(ds_pickup);
	}
	ast_party_connected_line_free(&connected_caller);

	return res;
}