Beispiel #1
0
SWITCH_DECLARE(const char *) CoreSession::getState()
{
	this_check(NULL);

	if (channel) {
		return switch_channel_state_name(switch_channel_get_state(channel));
	}

	return "ERROR";

}
Beispiel #2
0
static void check_presence(switch_core_session_t *session)
{
	switch_channel_state_t state = switch_channel_get_running_state(session->channel);

	if (state == CS_ROUTING || state == CS_HANGUP) {
		if (switch_channel_get_cause(session->channel) == SWITCH_CAUSE_LOSE_RACE) {
			switch_channel_presence(session->channel, "unknown", "cancelled", NULL);
			switch_channel_set_variable(session->channel, "presence_call_info", NULL);
		} else {
			switch_channel_presence(session->channel, "unknown", switch_channel_state_name(state), NULL);
		}
	}
}
Beispiel #3
0
static switch_status_t my_on_reporting(switch_core_session_t *session)
{
	switch_status_t status = SWITCH_STATUS_SUCCESS;
	switch_channel_t *channel = switch_core_session_get_channel(session);
	switch_event_header_t *hi;
	switch_caller_profile_t *caller_profile;
	switch_app_log_t *app_log;
	bson cdr;
	int is_b;
	char *tmp;

	if (globals.shutdown) {
		return SWITCH_STATUS_SUCCESS;
	}

	is_b = channel && switch_channel_get_originator_caller_profile(channel);
	if (!globals.log_b && is_b) {
		const char *force_cdr = switch_channel_get_variable(channel, SWITCH_FORCE_PROCESS_CDR_VARIABLE);
		if (!switch_true(force_cdr)) {
			return SWITCH_STATUS_SUCCESS;
		}
	}

	bson_init(&cdr);

	/* Channel data */
	bson_append_start_object(&cdr, "channel_data");
	bson_append_string(&cdr, "state", switch_channel_state_name(switch_channel_get_state(channel)));
	bson_append_string(&cdr, "direction", switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound");
	bson_append_int(&cdr, "state_number", switch_channel_get_state(channel));

	if ((tmp = switch_channel_get_flag_string(channel))) {
		bson_append_string(&cdr, "flags", tmp);
		free(tmp);
	}

	if ((tmp = switch_channel_get_cap_string(channel))) {
		bson_append_string(&cdr, "caps", tmp);
		free(tmp);
	}
	bson_append_finish_object(&cdr);				/* channel_data */


	/* Channel variables */
	bson_append_start_object(&cdr, "variables");

	if ((hi = switch_channel_variable_first(channel))) {
		for (; hi; hi = hi->next) {
			if (!zstr(hi->name) && !zstr(hi->value)) {
				bson_append_string(&cdr, hi->name, hi->value);
			}
		}
		switch_channel_variable_last(channel);
	}

	bson_append_finish_object(&cdr);				/* variables */


	/* App log */
	if ((app_log = switch_core_session_get_app_log(session))) {
		switch_app_log_t *ap;

		bson_append_start_object(&cdr, "app_log");
		for (ap = app_log; ap; ap = ap->next) {
			bson_append_start_object(&cdr, "application");
			bson_append_string(&cdr, "app_name", ap->app);
			bson_append_string(&cdr, "app_data", ap->arg);
			bson_append_long(&cdr, "app_stamp", ap->stamp);
			bson_append_finish_object(&cdr);		/* application */
		}

		bson_append_finish_object(&cdr);			/* app_log */
	}


	/* Callflow */
	caller_profile = switch_channel_get_caller_profile(channel);

	while (caller_profile) {
		bson_append_start_object(&cdr, "callflow");

		if (!zstr(caller_profile->dialplan)) {
			bson_append_string(&cdr, "dialplan", caller_profile->dialplan);
		}

		if (!zstr(caller_profile->profile_index)) {
			bson_append_string(&cdr, "profile_index", caller_profile->profile_index);
		}

		if (caller_profile->caller_extension) {
			switch_caller_application_t *ap;

			bson_append_start_object(&cdr, "extension");

			bson_append_string(&cdr, "name", caller_profile->caller_extension->extension_name);
			bson_append_string(&cdr, "number", caller_profile->caller_extension->extension_number);

			if (caller_profile->caller_extension->current_application) {
				bson_append_string(&cdr, "current_app", caller_profile->caller_extension->current_application->application_name);
			}

			for (ap = caller_profile->caller_extension->applications; ap; ap = ap->next) {
				bson_append_start_object(&cdr, "application");
				if (ap == caller_profile->caller_extension->current_application) {
					bson_append_bool(&cdr, "last_executed", 1);
				}
				bson_append_string(&cdr, "app_name", ap->application_name);
				bson_append_string(&cdr, "app_data", ap->application_data);
				bson_append_finish_object(&cdr);
			}

			if (caller_profile->caller_extension->children) {
				switch_caller_profile_t *cp = NULL;

				for (cp = caller_profile->caller_extension->children; cp; cp = cp->next) {

					if (!cp->caller_extension) {
						continue;
					}

					bson_append_start_object(&cdr, "sub_extensions");
					bson_append_start_object(&cdr, "extension");

					bson_append_string(&cdr, "name", cp->caller_extension->extension_name);
					bson_append_string(&cdr, "number", cp->caller_extension->extension_number);
					bson_append_string(&cdr, "dialplan", cp->dialplan);
					if (cp->caller_extension->current_application) {
						bson_append_string(&cdr, "current_app", cp->caller_extension->current_application->application_name);
					}

					for (ap = cp->caller_extension->applications; ap; ap = ap->next) {
						bson_append_start_object(&cdr, "application");
						if (ap == cp->caller_extension->current_application) {
							bson_append_bool(&cdr, "last_executed", 1);
						}
						bson_append_string(&cdr, "app_name", ap->application_name);
						bson_append_string(&cdr, "app_data", ap->application_data);
						bson_append_finish_object(&cdr);
					}

					bson_append_finish_object(&cdr);	/* extension */
					bson_append_finish_object(&cdr);	/* sub_extensions */
				}
			}

			bson_append_finish_object(&cdr);			/* extension */
		}

		bson_append_start_object(&cdr, "caller_profile");
		set_bson_profile_data(&cdr, caller_profile);

		if (caller_profile->origination_caller_profile) {
			switch_caller_profile_t *cp = NULL;

			bson_append_start_object(&cdr, "origination");
			for (cp = caller_profile->origination_caller_profile; cp; cp = cp->next) {
				bson_append_start_object(&cdr, "origination_caller_profile");
				set_bson_profile_data(&cdr, cp);
				bson_append_finish_object(&cdr);
			}
			bson_append_finish_object(&cdr);			/* origination */
		}

		if (caller_profile->originator_caller_profile) {
			switch_caller_profile_t *cp = NULL;

			bson_append_start_object(&cdr, "originator");
			for (cp = caller_profile->originator_caller_profile; cp; cp = cp->next) {
				bson_append_start_object(&cdr, "originator_caller_profile");
				set_bson_profile_data(&cdr, cp);
				bson_append_finish_object(&cdr);
			}
			bson_append_finish_object(&cdr);			/* originator */
		}

		if (caller_profile->originatee_caller_profile) {
			switch_caller_profile_t *cp = NULL;

			bson_append_start_object(&cdr, "originatee");
			for (cp = caller_profile->originatee_caller_profile; cp; cp = cp->next) {
				bson_append_start_object(&cdr, "originatee_caller_profile");
				set_bson_profile_data(&cdr, cp);
				bson_append_finish_object(&cdr);
			}
			bson_append_finish_object(&cdr);			/* originatee */
		}

		bson_append_finish_object(&cdr);				/* caller_profile */

		/* Timestamps */
		if (caller_profile->times) {
			bson_append_start_object(&cdr, "times");

			/* Insert timestamps as long ints (microseconds) to preserve accuracy */
			bson_append_long(&cdr, "created_time", caller_profile->times->created);
			bson_append_long(&cdr, "profile_created_time", caller_profile->times->profile_created);
			bson_append_long(&cdr, "progress_time", caller_profile->times->progress);
			bson_append_long(&cdr, "progress_media_time", caller_profile->times->progress_media);
			bson_append_long(&cdr, "answered_time", caller_profile->times->answered);
			bson_append_long(&cdr, "bridged_time", caller_profile->times->bridged);
			bson_append_long(&cdr, "last_hold_time", caller_profile->times->last_hold);
			bson_append_long(&cdr, "hold_accum_time", caller_profile->times->hold_accum);
			bson_append_long(&cdr, "hangup_time", caller_profile->times->hungup);
			bson_append_long(&cdr, "resurrect_time", caller_profile->times->resurrected);
			bson_append_long(&cdr, "transfer_time", caller_profile->times->transferred);
			bson_append_finish_object(&cdr);			/* times */
		}

		bson_append_finish_object(&cdr);				/* callflow */
		caller_profile = caller_profile->next;
	}

	bson_finish(&cdr);

	switch_mutex_lock(globals.mongo_mutex);

	if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) {
		if (globals.mongo_conn->err == MONGO_IO_ERROR) {
			mongo_error_t db_status;
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "MongoDB connection failed; attempting reconnect...\n");
			db_status = mongo_reconnect(globals.mongo_conn);

			if (db_status != MONGO_OK) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MongoDB reconnect failed with error code %d\n", db_status);
				status = SWITCH_STATUS_FALSE;
			} else {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MongoDB connection re-established.\n");
				if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) {
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mongo_insert: error code %d\n", globals.mongo_conn->err);
					status = SWITCH_STATUS_FALSE;
				}
			}

		} else {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mongo_insert: error code %d\n", globals.mongo_conn->err);
			status = SWITCH_STATUS_FALSE;
		}
	}

	switch_mutex_unlock(globals.mongo_mutex);
	bson_destroy(&cdr);

	return status;
}
Beispiel #4
0
SWITCH_DECLARE(void) switch_core_session_run(switch_core_session_t *session)
{
	switch_channel_state_t state = CS_NEW, midstate = CS_DESTROY, endstate;
	const switch_endpoint_interface_t *endpoint_interface;
	const switch_state_handler_table_t *driver_state_handler = NULL;
	const switch_state_handler_table_t *application_state_handler = NULL;
	int silly = 0;
	uint32_t new_loops = 500;

	/*
	   Life of the channel. you have channel and pool in your session
	   everywhere you go you use the session to malloc with
	   switch_core_session_alloc(session, <size>)

	   The endpoint module gets the first crack at implementing the state
	   if it wants to, it can cancel the default behavior by returning SWITCH_STATUS_FALSE

	   Next comes the channel's event handler table that can be set by an application
	   which also can veto the next behavior in line by returning SWITCH_STATUS_FALSE

	   Finally the default state behavior is called.


	 */
	switch_assert(session != NULL);

	switch_set_flag(session, SSF_THREAD_RUNNING);
	endpoint_interface = session->endpoint_interface;
	switch_assert(endpoint_interface != NULL);

	driver_state_handler = endpoint_interface->state_handler;
	switch_assert(driver_state_handler != NULL);

	switch_mutex_lock(session->mutex);

	while ((state = switch_channel_get_state(session->channel)) != CS_DESTROY) {

		if (switch_channel_test_flag(session->channel, CF_BLOCK_STATE)) {
			switch_channel_wait_for_flag(session->channel, CF_BLOCK_STATE, SWITCH_FALSE, 0, NULL);
			if ((state = switch_channel_get_state(session->channel)) == CS_DESTROY) {
				break;
			}
		}

		midstate = state;
		if (state != switch_channel_get_running_state(session->channel) || state >= CS_HANGUP) {
			int index = 0;
			int proceed = 1;
			int global_proceed = 1;
			int do_extra_handlers = 1;
			switch_io_event_hook_state_run_t *ptr;
			switch_status_t rstatus = SWITCH_STATUS_SUCCESS;

			switch_channel_set_running_state(session->channel, state);
			switch_channel_clear_flag(session->channel, CF_TRANSFER);
			switch_channel_clear_flag(session->channel, CF_REDIRECT);
			
			if (session->endpoint_interface->io_routines->state_run) {
				rstatus = session->endpoint_interface->io_routines->state_run(session);
			}
			
			if (rstatus == SWITCH_STATUS_SUCCESS) {
				for (ptr = session->event_hooks.state_run; ptr; ptr = ptr->next) {
					if ((rstatus = ptr->state_run(session)) != SWITCH_STATUS_SUCCESS) {
						break;
					}
				}
			}
			
			switch (state) {
			case CS_NEW:		/* Just created, Waiting for first instructions */
				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "(%s) State NEW\n", switch_channel_get_name(session->channel));
				break;
			case CS_DESTROY:
				goto done;
			case CS_REPORTING:	/* Call Detail */
				{
					switch_core_session_reporting_state(session);
					switch_channel_set_state(session->channel, CS_DESTROY);
				}
				goto done;
			case CS_HANGUP:	/* Deactivate and end the thread */
				{
					switch_core_session_hangup_state(session, SWITCH_TRUE);
					switch_channel_set_state(session->channel, CS_REPORTING);
				}

				break;
			case CS_INIT:		/* Basic setup tasks */
				{
					switch_event_t *event;

					STATE_MACRO(init, "INIT");
					
					if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_CREATE) == SWITCH_STATUS_SUCCESS) {
						switch_channel_event_set_data(session->channel, event);
						switch_event_fire(&event);
					}

					if (switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
						if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_ORIGINATE) == SWITCH_STATUS_SUCCESS) {
							switch_channel_event_set_data(session->channel, event);
							switch_event_fire(&event);
						}
					}
				}
				break;
			case CS_ROUTING:	/* Look for a dialplan and find something to do */
				STATE_MACRO(routing, "ROUTING");
				break;
			case CS_RESET:		/* Reset */
				STATE_MACRO(reset, "RESET");
				break;
				/* These other states are intended for prolonged durations so we do not signal lock for them */
			case CS_EXECUTE:	/* Execute an Operation */
				STATE_MACRO(execute, "EXECUTE");
				break;
			case CS_EXCHANGE_MEDIA:	/* loop all data back to source */
				STATE_MACRO(exchange_media, "EXCHANGE_MEDIA");
				break;
			case CS_SOFT_EXECUTE:	/* send/recieve data to/from another channel */
				STATE_MACRO(soft_execute, "SOFT_EXECUTE");
				break;
			case CS_PARK:		/* wait in limbo */
				STATE_MACRO(park, "PARK");
				break;
			case CS_CONSUME_MEDIA:	/* wait in limbo */
				STATE_MACRO(consume_media, "CONSUME_MEDIA");
				break;
			case CS_HIBERNATE:	/* sleep */
				STATE_MACRO(hibernate, "HIBERNATE");
				break;
			case CS_NONE:
				abort();
				break;
			}

			check_presence(session);

			if (midstate == CS_DESTROY) {
				break;
			}

		}

		endstate = switch_channel_get_state(session->channel);

		if (endstate == switch_channel_get_running_state(session->channel)) {
			if (endstate == CS_NEW) {
				switch_yield(20000);
				switch_ivr_parse_all_events(session);
				if (!--new_loops) {
					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s %s Abandoned\n",
									  session->uuid_str, switch_core_session_get_name(session));
					switch_channel_set_flag(session->channel, CF_NO_CDR);
					switch_channel_hangup(session->channel, SWITCH_CAUSE_WRONG_CALL_STATE);
				}
			} else {
				switch_ivr_parse_all_events(session);
				switch_ivr_parse_all_events(session);

				if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) {
					switch_channel_state_thread_lock(session->channel);
					switch_channel_set_flag(session->channel, CF_THREAD_SLEEPING);
					if (switch_channel_get_state(session->channel) == switch_channel_get_running_state(session->channel)) {
						switch_ivr_parse_all_events(session);
						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s session thread sleep state: %s!\n", 
										  switch_channel_get_name(session->channel),
										  switch_channel_state_name(switch_channel_get_running_state(session->channel)));
						switch_thread_cond_wait(session->cond, session->mutex);
						switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "%s session thread wake state: %s!\n", 
										  switch_channel_get_name(session->channel),
										  switch_channel_state_name(switch_channel_get_running_state(session->channel)));


					}
					switch_channel_clear_flag(session->channel, CF_THREAD_SLEEPING);
					switch_channel_state_thread_unlock(session->channel);
				}

				switch_ivr_parse_all_events(session);
				switch_ivr_parse_all_events(session);
			}
		}
	}
  done:
	switch_mutex_unlock(session->mutex);

	switch_clear_flag(session, SSF_THREAD_RUNNING);
}
static switch_status_t generate_json_cdr(switch_core_session_t *session, struct json_object **json_cdr)
{

	struct json_object *cdr = json_object_new_object();
	switch_channel_t *channel = switch_core_session_get_channel(session);
	switch_caller_profile_t *caller_profile;
	struct json_object *variables, *j_main_cp, *j_caller_profile, *j_caller_extension, *j_times, *time_tag,
		*j_application, *j_callflow, *j_inner_extension, *j_apps, *j_o, *j_channel_data, *j_field;
	switch_app_log_t *app_log;
	char tmp[512], *f;
	
	if (is_error(cdr)) {
		return SWITCH_STATUS_FALSE;
	}

	j_channel_data = json_object_new_object();
	if (is_error(j_channel_data)) {
		goto error;
	}
	json_object_object_add(cdr, "channel_data", j_channel_data);

	
	j_field = json_object_safe_new_string((char *) switch_channel_state_name(switch_channel_get_state(channel)));
	json_object_object_add(j_channel_data, "state", j_field);

	j_field = json_object_safe_new_string(switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound");

	json_object_object_add(j_channel_data, "direction", j_field);


	switch_snprintf(tmp, sizeof(tmp), "%d", switch_channel_get_state(channel));
	j_field = json_object_new_string((char *) tmp);
	json_object_object_add(j_channel_data, "state_number", j_field);
	

	if ((f = switch_channel_get_flag_string(channel))) {
		j_field = json_object_safe_new_string((char *) f);
		json_object_object_add(j_channel_data, "flags", j_field);
		free(f);
	}

	if ((f = switch_channel_get_cap_string(channel))) {
		j_field = json_object_safe_new_string((char *) f);
		json_object_object_add(j_channel_data, "caps", j_field);
		free(f);
	}


	variables = json_object_new_object();
	json_object_object_add(cdr, "variables", variables);

	if (is_error(variables)) {
		goto error;
	}

	set_json_chan_vars(variables, channel);


	if ((app_log = switch_core_session_get_app_log(session))) {
		switch_app_log_t *ap;

		j_apps = json_object_new_object();

		if (is_error(j_apps)) {
			goto error;
		}

		json_object_object_add(cdr, "app_log", j_apps);

		for (ap = app_log; ap; ap = ap->next) {
			j_application = json_object_new_object();

			if (is_error(j_application)) {
				goto error;
			}

			json_object_object_add(j_application, "app_name", json_object_safe_new_string(ap->app));
			json_object_object_add(j_application, "app_data", json_object_safe_new_string(ap->arg));

			json_object_object_add(j_apps, "application", j_application);
		}
	}


	caller_profile = switch_channel_get_caller_profile(channel);

	while (caller_profile) {

		j_callflow = json_object_new_object();

		if (is_error(j_callflow)) {
			goto error;
		}

		json_object_object_add(cdr, "callflow", j_callflow);

		if (!zstr(caller_profile->dialplan)) {
			json_object_object_add(j_callflow, "dialplan", json_object_safe_new_string((char *)caller_profile->dialplan));
		}

		if (!zstr(caller_profile->profile_index)) {
			json_object_object_add(j_callflow, "profile_index", json_object_safe_new_string((char *)caller_profile->profile_index));
		}

		if (caller_profile->caller_extension) {
			switch_caller_application_t *ap;

			j_caller_extension = json_object_new_object();

			if (is_error(j_caller_extension)) {
				goto error;
			}

			json_object_object_add(j_callflow, "extension", j_caller_extension);

			json_object_object_add(j_caller_extension, "name", json_object_safe_new_string(caller_profile->caller_extension->extension_name));
			json_object_object_add(j_caller_extension, "number", json_object_safe_new_string(caller_profile->caller_extension->extension_number));

			if (caller_profile->caller_extension->current_application) {
				json_object_object_add(j_caller_extension, "current_app", json_object_safe_new_string(caller_profile->caller_extension->current_application->application_name));
			}

			for (ap = caller_profile->caller_extension->applications; ap; ap = ap->next) {
				j_application = json_object_new_object();

				if (is_error(j_application)) {
					goto error;
				}


				json_object_object_add(j_caller_extension, "application", j_application);

				if (ap == caller_profile->caller_extension->current_application) {
					json_object_object_add(j_application, "last_executed", json_object_new_string("true"));
				}
				json_object_object_add(j_application, "app_name", json_object_safe_new_string(ap->application_name));
				json_object_object_add(j_application, "app_data", json_object_safe_new_string(switch_str_nil(ap->application_data)));
			}

			if (caller_profile->caller_extension->children) {
				switch_caller_profile_t *cp = NULL;
				for (cp = caller_profile->caller_extension->children; cp; cp = cp->next) {

					if (!cp->caller_extension) {
						continue;
					}

					j_inner_extension = json_object_new_object();
					if (is_error(j_inner_extension)) {
						goto error;
					}

					json_object_object_add(j_caller_extension, "sub_extensions", j_inner_extension);


					j_caller_extension = json_object_new_object();
					if (is_error(j_caller_extension)) {
						goto error;
					}

					json_object_object_add(j_inner_extension, "extension", j_caller_extension);

					json_object_object_add(j_caller_extension, "name", json_object_safe_new_string(cp->caller_extension->extension_name));
					json_object_object_add(j_caller_extension, "number", json_object_safe_new_string(cp->caller_extension->extension_number));

					json_object_object_add(j_caller_extension, "dialplan", json_object_safe_new_string((char *)cp->dialplan));

					if (cp->caller_extension->current_application) {
						json_object_object_add(j_caller_extension, "current_app", json_object_safe_new_string(cp->caller_extension->current_application->application_name));
					}

					for (ap = cp->caller_extension->applications; ap; ap = ap->next) {
						j_application = json_object_new_object();
						
						if (is_error(j_application)) {
							goto error;
						}
						json_object_object_add(j_caller_extension, "application", j_application);

						if (ap == cp->caller_extension->current_application) {
							json_object_object_add(j_application, "last_executed", json_object_new_string("true"));
						}
						json_object_object_add(j_application, "app_name", json_object_safe_new_string(ap->application_name));
						json_object_object_add(j_application, "app_data", json_object_safe_new_string(switch_str_nil(ap->application_data)));
					}
				}
			}
		}

		j_main_cp = json_object_new_object();
		if (is_error(j_main_cp)) {
			goto error;
		}

		json_object_object_add(j_callflow, "caller_profile", j_main_cp);

		set_json_profile_data(j_main_cp, caller_profile);

		if (caller_profile->originator_caller_profile) {
			switch_caller_profile_t *cp = NULL;

			j_o = json_object_new_object();
			if (is_error(j_o)) {
				goto error;
			}
			
			json_object_object_add(j_main_cp, "originator", j_o);

			for (cp = caller_profile->originator_caller_profile; cp; cp = cp->next) {
				j_caller_profile = json_object_new_object();
				if (is_error(j_caller_profile)) {
					goto error;
				}

				json_object_object_add(j_o, "originator_caller_profile", j_caller_profile);

				set_json_profile_data(j_caller_profile, cp);
			}
		}

		if (caller_profile->originatee_caller_profile) {
			switch_caller_profile_t *cp = NULL;

			j_o = json_object_new_object();
			if (is_error(j_o)) {
				goto error;
			}

			json_object_object_add(j_main_cp, "originatee", j_o);

			for (cp = caller_profile->originatee_caller_profile; cp; cp = cp->next) {

				j_caller_profile = json_object_new_object();
				if (is_error(j_caller_profile)) {
					goto error;
				}
				
				json_object_object_add(j_o, "originatee_caller_profile", j_caller_profile);
				set_json_profile_data(j_caller_profile, cp);
			}
		}

		if (caller_profile->times) {

			j_times = json_object_new_object();
			if (is_error(j_times)) {
				goto error;
			}

			json_object_object_add(j_callflow, "times", j_times);

			switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->created);
			time_tag = json_object_new_string(tmp);
			if (is_error(time_tag)) {
				goto error;
			}
			json_object_object_add(j_times, "created_time", time_tag);

			switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->profile_created);
			time_tag = json_object_new_string(tmp);
			if (is_error(time_tag)) {
				goto error;
			}
			json_object_object_add(j_times, "profile_created_time", time_tag);

			switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->progress);
			time_tag = json_object_new_string(tmp);
			if (is_error(time_tag)) {
				goto error;
			}
			json_object_object_add(j_times, "progress_time", time_tag);

			switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->progress_media);
			time_tag = json_object_new_string(tmp);
			if (is_error(time_tag)) {
				goto error;
			}
			json_object_object_add(j_times, "progress_media_time", time_tag);


			switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->answered);
			time_tag = json_object_new_string(tmp);
			if (is_error(time_tag)) {
				goto error;
			}
			json_object_object_add(j_times, "answered_time", time_tag);

			switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->hungup);
			time_tag = json_object_new_string(tmp);
			if (is_error(time_tag)) {
				goto error;
			}
			json_object_object_add(j_times, "hangup_time", time_tag);

			switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->resurrected);
			time_tag = json_object_new_string(tmp);
			if (is_error(time_tag)) {
				goto error;
			}
			json_object_object_add(j_times, "resurrect_time", time_tag);

			switch_snprintf(tmp, sizeof(tmp), "%" SWITCH_TIME_T_FMT, caller_profile->times->transferred);
			time_tag = json_object_new_string(tmp);
			if (is_error(time_tag)) {
				goto error;
			}
			json_object_object_add(j_times, "transfer_time", time_tag);

		}

		caller_profile = caller_profile->next;
	}

	*json_cdr = cdr;

	return SWITCH_STATUS_SUCCESS;
	
  error:

	if (cdr) {
		json_object_put(cdr);
	}

	return SWITCH_STATUS_FALSE;
}