Revision
17319
Author
math.parent
Date
2010-04-16 08:03:37 -0500 (Fri, 16 Apr 2010)

Log Message

Skinny: Initial implementation of VersionReq

And reordering

Modified Paths

Diff

Modified: freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_protocol.c (17318 => 17319)


--- freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_protocol.c	2010-04-16 09:59:58 UTC (rev 17318)
+++ freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_protocol.c	2010-04-16 13:03:37 UTC (rev 17319)
@@ -1389,6 +1389,15 @@
 	return skinny_send_reply(listener, message);
 }
 
+switch_status_t send_version(listener_t *listener,
+	char *version)
+{
+	skinny_message_t *message;
+	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.version));
+	strncpy(message->data.version.version, version, 16);
+	return skinny_send_reply(listener, message);
+}
+
 switch_status_t send_register_reject(listener_t *listener,
     char *error)
 {
@@ -1579,25 +1588,18 @@
 	return skinny_send_reply(listener, message);
 }
 
-/* Message handling */
-switch_status_t skinny_handle_alarm(listener_t *listener, skinny_message_t *request)
+/*****************************************************************************/
+/* SKINNY MESSAGE HANDLERS */
+/*****************************************************************************/
+switch_status_t skinny_handle_keep_alive_message(listener_t *listener, skinny_message_t *request)
 {
-	switch_event_t *event = NULL;
+	skinny_message_t *message;
 
-	skinny_check_data_length(request, sizeof(request->data.alarm));
-
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
-		"Received alarm: Severity=%d, DisplayMessage=%s, Param1=%d, Param2=%d.\n",
-		request->data.alarm.alarm_severity, request->data.alarm.display_message,
-		request->data.alarm.alarm_param1, request->data.alarm.alarm_param2);
-	/* skinny::alarm event */
-	skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_ALARM);
-	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Severity", "%d", request->data.alarm.alarm_severity);
-	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-DisplayMessage", "%s", request->data.alarm.display_message);
-	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param1", "%d", request->data.alarm.alarm_param1);
-	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param2", "%d", request->data.alarm.alarm_param2);
-	switch_event_fire(&event);
-
+	message = switch_core_alloc(listener->pool, 12);
+	message->type = KEEP_ALIVE_ACK_MESSAGE;
+	message->length = 4;
+	keepalive_listener(listener, NULL);
+	skinny_send_reply(listener, message);
 	return SWITCH_STATUS_SUCCESS;
 }
 
@@ -1733,14 +1735,234 @@
 	return status;
 }
 
-switch_status_t skinny_headset_status_message(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_port_message(listener_t *listener, skinny_message_t *request)
 {
-	skinny_check_data_length(request, sizeof(request->data.headset_status));
+	char *sql;
+	skinny_profile_t *profile;
 
-	/* Nothing to do */
+	switch_assert(listener->profile);
+	switch_assert(listener->device_name);
+
+	profile = listener->profile;
+
+	skinny_check_data_length(request, sizeof(request->data.as_uint16));
+
+	if ((sql = switch_mprintf(
+			"UPDATE skinny_devices SET port=%d WHERE name='%s' and instance=%d",
+			request->data.port.port,
+			listener->device_name,
+			listener->device_instance
+			))) {
+		skinny_execute_sql(profile, sql, profile->sql_mutex);
+		switch_safe_free(sql);
+	}
 	return SWITCH_STATUS_SUCCESS;
 }
 
+switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny_message_t *request)
+{
+	uint32_t line_instance = 0;
+	switch_core_session_t *session;
+
+	skinny_check_data_length(request, sizeof(request->data.keypad_button));
+	
+	if(request->data.keypad_button.line_instance) {
+	    line_instance = request->data.keypad_button.line_instance;
+	} else {
+	    line_instance = 1;
+	}
+
+	session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.keypad_button.call_id);
+
+	if(session) {
+		switch_channel_t *channel = NULL;
+		private_t *tech_pvt = NULL;
+		char digit = '\0';
+
+		channel = switch_core_session_get_channel(session);
+		tech_pvt = switch_core_session_get_private(session);
+
+		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SEND DTMF ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button);
+
+		if (request->data.keypad_button.button == 14) {
+			digit = '*';
+		} else if (request->data.keypad_button.button == 15) {
+			digit = '#';
+		} else if (request->data.keypad_button.button >= 0 && request->data.keypad_button.button <= 9) {
+			digit = '0' + request->data.keypad_button.button;
+		} else {
+			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "UNKNOW DTMF RECEIVED ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button);
+		}
+
+		/* TODO check call_id and line */
+
+		if((skinny_line_get_state(listener, line_instance, tech_pvt->call_id) == SKINNY_OFF_HOOK)) {
+	
+		    skinny_session_process_dest(session, listener, line_instance, NULL, digit, 0);
+		} else {
+			if(digit != '\0') {
+				switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0)};
+				dtmf.digit = digit;
+				switch_channel_queue_dtmf(channel, &dtmf);
+			}
+		}
+	}
+
+	if(session) {
+		switch_core_session_rwunlock(session);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request)
+{
+	switch_status_t status = SWITCH_STATUS_SUCCESS;
+	struct speed_dial_stat_res_message *button = NULL;
+	uint32_t line_instance = 0;
+	uint32_t call_id = 0;
+	switch_core_session_t *session = NULL;
+
+	skinny_check_data_length(request, sizeof(request->data.stimulus)-sizeof(request->data.stimulus.call_id));
+
+	if(skinny_check_data_length_soft(request, sizeof(request->data.stimulus))) {
+	    call_id = request->data.stimulus.call_id;
+	}
+
+	switch(request->data.stimulus.instance_type) {
+		case SKINNY_BUTTON_LAST_NUMBER_REDIAL:
+		    skinny_create_ingoing_session(listener, &line_instance, &session);
+			skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0);
+			break;
+		case SKINNY_BUTTON_SPEED_DIAL:
+			skinny_speed_dial_get(listener, request->data.stimulus.instance, &button);
+			if(strlen(button->line) > 0) {
+		        skinny_create_ingoing_session(listener, &line_instance, &session);
+			    skinny_session_process_dest(session, listener, line_instance, button->line, '\0', 0);
+			}
+			break;
+		case SKINNY_BUTTON_HOLD:
+			session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id);
+
+			if(session) {
+				status = skinny_session_hold_line(session, listener, line_instance);
+			}
+			break;
+		case SKINNY_BUTTON_VOICEMAIL:
+		    skinny_create_ingoing_session(listener, &line_instance, &session);
+			skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0);
+			break;
+		default:
+			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown Stimulus Type Received [%d]\n", request->data.stimulus.instance_type);
+	}
+
+	if(session) {
+		switch_core_session_rwunlock(session);
+	}
+
+	return status;
+}
+
+switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_message_t *request)
+{
+	uint32_t line_instance;
+	switch_core_session_t *session = NULL;
+	private_t *tech_pvt = NULL;
+
+	skinny_check_data_length(request, sizeof(request->data.off_hook));
+
+	if(request->data.off_hook.line_instance > 0) {
+		line_instance = request->data.off_hook.line_instance;
+	} else {
+		line_instance = 1;
+	}
+
+	session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.off_hook.call_id);
+
+	if(session) { /*answering a call */
+		skinny_session_answer(session, listener, line_instance);
+	} else { /* start a new call */
+		skinny_create_ingoing_session(listener, &line_instance, &session);
+	    tech_pvt = switch_core_session_get_private(session);
+	    assert(tech_pvt != NULL);
+
+	    skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0);
+	}
+
+	if(session) {
+		switch_core_session_rwunlock(session);
+	}
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t skinny_handle_on_hook_message(listener_t *listener, skinny_message_t *request)
+{
+	switch_status_t status = SWITCH_STATUS_SUCCESS;
+	switch_core_session_t *session = NULL;
+	uint32_t line_instance = 0;
+
+	skinny_check_data_length(request, sizeof(request->data.on_hook));
+
+	line_instance = request->data.on_hook.line_instance;
+	
+	session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.on_hook.call_id);
+
+	if(session) {
+		switch_channel_t *channel = NULL;
+
+		channel = switch_core_session_get_channel(session);
+
+		switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
+	}
+
+	if(session) {
+		switch_core_session_rwunlock(session);
+	}
+
+	return status;
+}
+
+switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skinny_message_t *request)
+{
+	skinny_message_t *message;
+	struct speed_dial_stat_res_message *button = NULL;
+
+	skinny_check_data_length(request, sizeof(request->data.speed_dial_req));
+
+	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.speed_dial_res));
+	message->type = SPEED_DIAL_STAT_RES_MESSAGE;
+	message->length = 4 + sizeof(message->data.speed_dial_res);
+
+	skinny_speed_dial_get(listener, request->data.speed_dial_req.number, &button);
+
+	memcpy(&message->data.speed_dial_res, button, sizeof(struct speed_dial_stat_res_message));
+
+	skinny_send_reply(listener, message);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t skinny_handle_line_stat_request(listener_t *listener, skinny_message_t *request)
+{
+	skinny_message_t *message;
+	struct line_stat_res_message *button = NULL;
+
+	skinny_check_data_length(request, sizeof(request->data.line_req));
+
+	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.line_res));
+	message->type = LINE_STAT_RES_MESSAGE;
+	message->length = 4 + sizeof(message->data.line_res);
+
+	skinny_line_get(listener, request->data.line_req.number, &button);
+
+	memcpy(&message->data.line_res, button, sizeof(struct line_stat_res_message));
+
+	skinny_send_reply(listener, message);
+
+	return SWITCH_STATUS_SUCCESS;
+}
+
 int skinny_config_stat_res_callback(void *pArg, int argc, char **argv, char **columnNames)
 {
 	skinny_message_t *message = pArg;
@@ -1798,90 +2020,11 @@
 	return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_time_date_request(listener_t *listener, skinny_message_t *request)
 {
-	char *sql;
-	skinny_profile_t *profile;
-
-	uint32_t i = 0;
-	uint32_t n = 0;
-	char *codec_order[SWITCH_MAX_CODECS];
-	char *codec_string;
-
-	size_t string_len, string_pos, pos;
-
-	switch_assert(listener->profile);
-	switch_assert(listener->device_name);
-
-	profile = listener->profile;
-
-	skinny_check_data_length(request, sizeof(request->data.cap_res.count));
-
-	n = request->data.cap_res.count;
-	if (n > SWITCH_MAX_CODECS) {
-		n = SWITCH_MAX_CODECS;
-	}
-	string_len = -1;
-
-	skinny_check_data_length(request, sizeof(request->data.cap_res.count) + n * sizeof(request->data.cap_res.caps[0]));
-
-	for (i = 0; i < n; i++) {
-		char *codec = skinny_codec2string(request->data.cap_res.caps[i].codec);
-		codec_order[i] = codec;
-		string_len += strlen(codec)+1;
-	}
-	i = 0;
-	pos = 0;
-	codec_string = switch_core_alloc(listener->pool, string_len+1);
-	for (string_pos = 0; string_pos < string_len; string_pos++) {
-		char *codec = codec_order[i];
-		switch_assert(i < n);
-		if(pos == strlen(codec)) {
-			codec_string[string_pos] = ',';
-			i++;
-			pos = 0;
-		} else {
-			codec_string[string_pos] = codec[pos++];
-		}
-	}
-	codec_string[string_len] = '\0';
-	if ((sql = switch_mprintf(
-			"UPDATE skinny_devices SET codec_string='%s' WHERE name='%s'",
-			codec_string,
-			listener->device_name
-			))) {
-		skinny_execute_sql(profile, sql, profile->sql_mutex);
-		switch_safe_free(sql);
-	}
-	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
-		"Codecs %s supported.\n", codec_string);
-	return SWITCH_STATUS_SUCCESS;
+	return send_define_current_time_date(listener);
 }
 
-switch_status_t skinny_handle_port_message(listener_t *listener, skinny_message_t *request)
-{
-	char *sql;
-	skinny_profile_t *profile;
-
-	switch_assert(listener->profile);
-	switch_assert(listener->device_name);
-
-	profile = listener->profile;
-
-	skinny_check_data_length(request, sizeof(request->data.as_uint16));
-
-	if ((sql = switch_mprintf(
-			"UPDATE skinny_devices SET port=%d WHERE name='%s' and instance=%d",
-			request->data.port.port,
-			listener->device_name,
-			listener->device_instance
-			))) {
-		skinny_execute_sql(profile, sql, profile->sql_mutex);
-		switch_safe_free(sql);
-	}
-	return SWITCH_STATUS_SUCCESS;
-}
-
 struct button_template_helper {
 	skinny_message_t *message;
 	int count[SKINNY_BUTTON_UNDEFINED+1];
@@ -1968,38 +2111,187 @@
 		}
 	}
 
-	skinny_send_reply(listener, message);
+	
 
+	return skinny_send_reply(listener, message);;
+}
+
+switch_status_t skinny_handle_version_request(listener_t *listener, skinny_message_t *request)
+{
+	/* TODO */
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+		"VersionReqMessage not implemented yet.\n");
 	return SWITCH_STATUS_SUCCESS;
+	/* return send_version(listener, ""); */
 }
 
-switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny_message_t *request)
 {
-	skinny_message_t *message;
+	char *sql;
 	skinny_profile_t *profile;
 
+	uint32_t i = 0;
+	uint32_t n = 0;
+	char *codec_order[SWITCH_MAX_CODECS];
+	char *codec_string;
+
+	size_t string_len, string_pos, pos;
+
 	switch_assert(listener->profile);
 	switch_assert(listener->device_name);
 
 	profile = listener->profile;
 
-	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_template));
-	message->type = SOFT_KEY_TEMPLATE_RES_MESSAGE;
-	message->length = 4 + sizeof(message->data.soft_key_template);
+	skinny_check_data_length(request, sizeof(request->data.cap_res.count));
 
-	message->data.soft_key_template.soft_key_offset = 0;
-	message->data.soft_key_template.soft_key_count = 21;
-	message->data.soft_key_template.total_soft_key_count = 21;
+	n = request->data.cap_res.count;
+	if (n > SWITCH_MAX_CODECS) {
+		n = SWITCH_MAX_CODECS;
+	}
+	string_len = -1;
 
-	memcpy(message->data.soft_key_template.soft_key,
-		soft_key_template_default,
-		sizeof(soft_key_template_default));
+	skinny_check_data_length(request, sizeof(request->data.cap_res.count) + n * sizeof(request->data.cap_res.caps[0]));
 
-	skinny_send_reply(listener, message);
+	for (i = 0; i < n; i++) {
+		char *codec = skinny_codec2string(request->data.cap_res.caps[i].codec);
+		codec_order[i] = codec;
+		string_len += strlen(codec)+1;
+	}
+	i = 0;
+	pos = 0;
+	codec_string = switch_core_alloc(listener->pool, string_len+1);
+	for (string_pos = 0; string_pos < string_len; string_pos++) {
+		char *codec = codec_order[i];
+		switch_assert(i < n);
+		if(pos == strlen(codec)) {
+			codec_string[string_pos] = ',';
+			i++;
+			pos = 0;
+		} else {
+			codec_string[string_pos] = codec[pos++];
+		}
+	}
+	codec_string[string_len] = '\0';
+	if ((sql = switch_mprintf(
+			"UPDATE skinny_devices SET codec_string='%s' WHERE name='%s'",
+			codec_string,
+			listener->device_name
+			))) {
+		skinny_execute_sql(profile, sql, profile->sql_mutex);
+		switch_safe_free(sql);
+	}
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+		"Codecs %s supported.\n", codec_string);
+	return SWITCH_STATUS_SUCCESS;
+}
 
+switch_status_t skinny_handle_alarm(listener_t *listener, skinny_message_t *request)
+{
+	switch_event_t *event = NULL;
+
+	skinny_check_data_length(request, sizeof(request->data.alarm));
+
+	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
+		"Received alarm: Severity=%d, DisplayMessage=%s, Param1=%d, Param2=%d.\n",
+		request->data.alarm.alarm_severity, request->data.alarm.display_message,
+		request->data.alarm.alarm_param1, request->data.alarm.alarm_param2);
+	/* skinny::alarm event */
+	skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_ALARM);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Severity", "%d", request->data.alarm.alarm_severity);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-DisplayMessage", "%s", request->data.alarm.display_message);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param1", "%d", request->data.alarm.alarm_param1);
+	switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Skinny-Alarm-Param2", "%d", request->data.alarm.alarm_param2);
+	switch_event_fire(&event);
+
 	return SWITCH_STATUS_SUCCESS;
 }
 
+switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *listener, skinny_message_t *request)
+{
+	switch_status_t status = SWITCH_STATUS_SUCCESS;
+	uint32_t line_instance = 0;
+	switch_core_session_t *session;
+
+	skinny_check_data_length(request, sizeof(request->data.open_receive_channel_ack));
+
+	session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.open_receive_channel_ack.pass_thru_party_id);
+
+	if(session) {
+		const char *err = NULL;
+		private_t *tech_pvt = NULL;
+		switch_channel_t *channel = NULL;
+		struct in_addr addr;
+
+		tech_pvt = switch_core_session_get_private(session);
+		channel = switch_core_session_get_channel(session);
+
+		/* Codec */
+		tech_pvt->iananame = "PCMU"; /* TODO */
+		tech_pvt->codec_ms = 10; /* TODO */
+		tech_pvt->rm_rate = 8000; /* TODO */
+		tech_pvt->rm_fmtp = NULL; /* TODO */
+		tech_pvt->agreed_pt = (switch_payload_t) 0; /* TODO */
+		tech_pvt->rm_encoding = switch_core_strdup(switch_core_session_get_pool(session), "");
+		skinny_tech_set_codec(tech_pvt, 0);
+		if ((status = skinny_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
+			goto end;
+		}
+
+		/* Request a local port from the core's allocator */
+		if (!(tech_pvt->local_sdp_audio_port = switch_rtp_request_port(listener->profile->ip))) {
+			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_CRIT, "No RTP ports available!\n");
+			return SWITCH_STATUS_FALSE;
+		}
+		tech_pvt->local_sdp_audio_ip = switch_core_strdup(switch_core_session_get_pool(session), listener->profile->ip);
+
+		tech_pvt->remote_sdp_audio_ip = inet_ntoa(request->data.open_receive_channel_ack.ip);
+		tech_pvt->remote_sdp_audio_port = request->data.open_receive_channel_ack.port;
+
+		tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
+											   tech_pvt->local_sdp_audio_port,
+											   tech_pvt->remote_sdp_audio_ip,
+											   tech_pvt->remote_sdp_audio_port,
+											   tech_pvt->agreed_pt,
+											   tech_pvt->read_impl.samples_per_packet,
+											   tech_pvt->codec_ms * 1000,
+											   (switch_rtp_flag_t) 0, "soft", &err,
+											   switch_core_session_get_pool(session));
+		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
+						  "AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
+						  switch_channel_get_name(channel),
+						  tech_pvt->local_sdp_audio_ip,
+						  tech_pvt->local_sdp_audio_port,
+						  tech_pvt->remote_sdp_audio_ip,
+						  tech_pvt->remote_sdp_audio_port,
+						  tech_pvt->agreed_pt,
+						  tech_pvt->read_impl.microseconds_per_packet / 1000,
+						  switch_rtp_ready(tech_pvt->rtp_session) ? "SUCCESS" : err);
+		inet_aton(tech_pvt->local_sdp_audio_ip, &addr);
+		send_start_media_transmission(listener,
+			tech_pvt->call_id, /* uint32_t conference_id, */
+			tech_pvt->party_id, /* uint32_t pass_thru_party_id, */
+			addr.s_addr, /* uint32_t remote_ip, */
+			tech_pvt->local_sdp_audio_port, /* uint32_t remote_port, */
+			20, /* uint32_t ms_per_packet, */
+			SKINNY_CODEC_ULAW_64K, /* uint32_t payload_capacity, */
+			184, /* uint32_t precedence, */
+			0, /* uint32_t silence_suppression, */
+			0, /* uint16_t max_frames_per_packet, */
+			0 /* uint32_t g723_bitrate */
+			);
+
+		if (switch_channel_get_state(channel) == CS_NEW) {
+			switch_channel_set_state(channel, CS_INIT);
+		}
+		switch_channel_mark_answered(channel);
+	}
+end:
+	if(session) {
+		switch_core_session_rwunlock(session);
+	}
+	return status;
+}
+
 switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_message_t *request)
 {
 	skinny_message_t *message;
@@ -2052,111 +2344,6 @@
 	return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_line_stat_request(listener_t *listener, skinny_message_t *request)
-{
-	skinny_message_t *message;
-	struct line_stat_res_message *button = NULL;
-
-	skinny_check_data_length(request, sizeof(request->data.line_req));
-
-	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.line_res));
-	message->type = LINE_STAT_RES_MESSAGE;
-	message->length = 4 + sizeof(message->data.line_res);
-
-	skinny_line_get(listener, request->data.line_req.number, &button);
-
-	memcpy(&message->data.line_res, button, sizeof(struct line_stat_res_message));
-
-	skinny_send_reply(listener, message);
-
-	return SWITCH_STATUS_SUCCESS;
-}
-
-switch_status_t skinny_handle_speed_dial_stat_request(listener_t *listener, skinny_message_t *request)
-{
-	skinny_message_t *message;
-	struct speed_dial_stat_res_message *button = NULL;
-
-	skinny_check_data_length(request, sizeof(request->data.speed_dial_req));
-
-	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.speed_dial_res));
-	message->type = SPEED_DIAL_STAT_RES_MESSAGE;
-	message->length = 4 + sizeof(message->data.speed_dial_res);
-
-	skinny_speed_dial_get(listener, request->data.speed_dial_req.number, &button);
-
-	memcpy(&message->data.speed_dial_res, button, sizeof(struct speed_dial_stat_res_message));
-
-	skinny_send_reply(listener, message);
-
-	return SWITCH_STATUS_SUCCESS;
-}
-
-switch_status_t skinny_handle_service_url_stat_request(listener_t *listener, skinny_message_t *request)
-{
-	skinny_message_t *message;
-	struct service_url_stat_res_message *button = NULL;
-
-	skinny_check_data_length(request, sizeof(request->data.service_url_req));
-
-	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.service_url_res));
-	message->type = SERVICE_URL_STAT_RES_MESSAGE;
-	message->length = 4 + sizeof(message->data.service_url_res);
-
-	skinny_service_url_get(listener, request->data.service_url_req.service_url_index, &button);
-
-	memcpy(&message->data.service_url_res, button, sizeof(struct service_url_stat_res_message));
-
-	skinny_send_reply(listener, message);
-
-	return SWITCH_STATUS_SUCCESS;
-}
-
-switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_message_t *request)
-{
-	skinny_message_t *message;
-	struct feature_stat_res_message *button = NULL;
-
-	skinny_check_data_length(request, sizeof(request->data.feature_req));
-
-	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.feature_res));
-	message->type = FEATURE_STAT_RES_MESSAGE;
-	message->length = 4 + sizeof(message->data.feature_res);
-
-	skinny_feature_get(listener, request->data.feature_req.feature_index, &button);
-
-	memcpy(&message->data.feature_res, button, sizeof(struct feature_stat_res_message));
-
-	skinny_send_reply(listener, message);
-
-	return SWITCH_STATUS_SUCCESS;
-}
-
-switch_status_t skinny_handle_register_available_lines_message(listener_t *listener, skinny_message_t *request)
-{
-	skinny_check_data_length(request, sizeof(request->data.reg_lines));
-
-	/* Do nothing */
-	return SWITCH_STATUS_SUCCESS;
-}
-
-switch_status_t skinny_handle_time_date_request(listener_t *listener, skinny_message_t *request)
-{
-	return send_define_current_time_date(listener);
-}
-
-switch_status_t skinny_handle_keep_alive_message(listener_t *listener, skinny_message_t *request)
-{
-	skinny_message_t *message;
-
-	message = switch_core_alloc(listener->pool, 12);
-	message->type = KEEP_ALIVE_ACK_MESSAGE;
-	message->length = 4;
-	keepalive_listener(listener, NULL);
-	skinny_send_reply(listener, message);
-	return SWITCH_STATUS_SUCCESS;
-}
-
 switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinny_message_t *request)
 {
 	switch_status_t status = SWITCH_STATUS_SUCCESS;
@@ -2240,274 +2427,107 @@
 	return status;
 }
 
-switch_status_t skinny_handle_off_hook_message(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_unregister(listener_t *listener, skinny_message_t *request)
 {
-	uint32_t line_instance;
-	switch_core_session_t *session = NULL;
-	private_t *tech_pvt = NULL;
+	switch_event_t *event = NULL;
+	skinny_message_t *message;
 
-	skinny_check_data_length(request, sizeof(request->data.off_hook));
+	/* skinny::unregister event */
+	skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_UNREGISTER);
+	switch_event_fire(&event);
 
-	if(request->data.off_hook.line_instance > 0) {
-		line_instance = request->data.off_hook.line_instance;
-	} else {
-		line_instance = 1;
-	}
+	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.unregister_ack));
+	message->type = UNREGISTER_ACK_MESSAGE;
+	message->length = 4 + sizeof(message->data.unregister_ack);
+	message->data.unregister_ack.unregister_status = 0; /* OK */
+	skinny_send_reply(listener, message);
 
-	session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.off_hook.call_id);
+	/* Close socket */
+	switch_clear_flag_locked(listener, LFLAG_RUNNING);
 
-	if(session) { /*answering a call */
-		skinny_session_answer(session, listener, line_instance);
-	} else { /* start a new call */
-		skinny_create_ingoing_session(listener, &line_instance, &session);
-	    tech_pvt = switch_core_session_get_private(session);
-	    assert(tech_pvt != NULL);
-
-	    skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0);
-	}
-
-	if(session) {
-		switch_core_session_rwunlock(session);
-	}
-
 	return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, skinny_message_t *request)
 {
-	switch_status_t status = SWITCH_STATUS_SUCCESS;
-	struct speed_dial_stat_res_message *button = NULL;
-	uint32_t line_instance = 0;
-	uint32_t call_id = 0;
-	switch_core_session_t *session = NULL;
+	skinny_message_t *message;
+	skinny_profile_t *profile;
 
-	skinny_check_data_length(request, sizeof(request->data.stimulus)-sizeof(request->data.stimulus.call_id));
+	switch_assert(listener->profile);
+	switch_assert(listener->device_name);
 
-	if(skinny_check_data_length_soft(request, sizeof(request->data.stimulus))) {
-	    call_id = request->data.stimulus.call_id;
-	}
+	profile = listener->profile;
 
-	switch(request->data.stimulus.instance_type) {
-		case SKINNY_BUTTON_LAST_NUMBER_REDIAL:
-		    skinny_create_ingoing_session(listener, &line_instance, &session);
-			skinny_session_process_dest(session, listener, line_instance, "redial", '\0', 0);
-			break;
-		case SKINNY_BUTTON_SPEED_DIAL:
-			skinny_speed_dial_get(listener, request->data.stimulus.instance, &button);
-			if(strlen(button->line) > 0) {
-		        skinny_create_ingoing_session(listener, &line_instance, &session);
-			    skinny_session_process_dest(session, listener, line_instance, button->line, '\0', 0);
-			}
-			break;
-		case SKINNY_BUTTON_HOLD:
-			session = skinny_profile_find_session(listener->profile, listener, &line_instance, call_id);
+	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.soft_key_template));
+	message->type = SOFT_KEY_TEMPLATE_RES_MESSAGE;
+	message->length = 4 + sizeof(message->data.soft_key_template);
 
-			if(session) {
-				status = skinny_session_hold_line(session, listener, line_instance);
-			}
-			break;
-		case SKINNY_BUTTON_VOICEMAIL:
-		    skinny_create_ingoing_session(listener, &line_instance, &session);
-			skinny_session_process_dest(session, listener, line_instance, "vmain", '\0', 0);
-			break;
-		default:
-			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unknown Stimulus Type Received [%d]\n", request->data.stimulus.instance_type);
-	}
+	message->data.soft_key_template.soft_key_offset = 0;
+	message->data.soft_key_template.soft_key_count = 21;
+	message->data.soft_key_template.total_soft_key_count = 21;
 
-	if(session) {
-		switch_core_session_rwunlock(session);
-	}
+	memcpy(message->data.soft_key_template.soft_key,
+		soft_key_template_default,
+		sizeof(soft_key_template_default));
 
-	return status;
+	skinny_send_reply(listener, message);
+
+	return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_headset_status_message(listener_t *listener, skinny_message_t *request)
 {
-	switch_status_t status = SWITCH_STATUS_SUCCESS;
-	uint32_t line_instance = 0;
-	switch_core_session_t *session;
+	skinny_check_data_length(request, sizeof(request->data.headset_status));
 
-	skinny_check_data_length(request, sizeof(request->data.open_receive_channel_ack));
+	/* Nothing to do */
+	return SWITCH_STATUS_SUCCESS;
+}
 
-	session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.open_receive_channel_ack.pass_thru_party_id);
+switch_status_t skinny_handle_register_available_lines_message(listener_t *listener, skinny_message_t *request)
+{
+	skinny_check_data_length(request, sizeof(request->data.reg_lines));
 
-	if(session) {
-		const char *err = NULL;
-		private_t *tech_pvt = NULL;
-		switch_channel_t *channel = NULL;
-		struct in_addr addr;
-
-		tech_pvt = switch_core_session_get_private(session);
-		channel = switch_core_session_get_channel(session);
-
-		/* Codec */
-		tech_pvt->iananame = "PCMU"; /* TODO */
-		tech_pvt->codec_ms = 10; /* TODO */
-		tech_pvt->rm_rate = 8000; /* TODO */
-		tech_pvt->rm_fmtp = NULL; /* TODO */
-		tech_pvt->agreed_pt = (switch_payload_t) 0; /* TODO */
-		tech_pvt->rm_encoding = switch_core_strdup(switch_core_session_get_pool(session), "");
-		skinny_tech_set_codec(tech_pvt, 0);
-		if ((status = skinny_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
-			goto end;
-		}
-
-		/* Request a local port from the core's allocator */
-		if (!(tech_pvt->local_sdp_audio_port = switch_rtp_request_port(listener->profile->ip))) {
-			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_CRIT, "No RTP ports available!\n");
-			return SWITCH_STATUS_FALSE;
-		}
-		tech_pvt->local_sdp_audio_ip = switch_core_strdup(switch_core_session_get_pool(session), listener->profile->ip);
-
-		tech_pvt->remote_sdp_audio_ip = inet_ntoa(request->data.open_receive_channel_ack.ip);
-		tech_pvt->remote_sdp_audio_port = request->data.open_receive_channel_ack.port;
-
-		tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
-											   tech_pvt->local_sdp_audio_port,
-											   tech_pvt->remote_sdp_audio_ip,
-											   tech_pvt->remote_sdp_audio_port,
-											   tech_pvt->agreed_pt,
-											   tech_pvt->read_impl.samples_per_packet,
-											   tech_pvt->codec_ms * 1000,
-											   (switch_rtp_flag_t) 0, "soft", &err,
-											   switch_core_session_get_pool(session));
-		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG,
-						  "AUDIO RTP [%s] %s:%d->%s:%d codec: %u ms: %d [%s]\n",
-						  switch_channel_get_name(channel),
-						  tech_pvt->local_sdp_audio_ip,
-						  tech_pvt->local_sdp_audio_port,
-						  tech_pvt->remote_sdp_audio_ip,
-						  tech_pvt->remote_sdp_audio_port,
-						  tech_pvt->agreed_pt,
-						  tech_pvt->read_impl.microseconds_per_packet / 1000,
-						  switch_rtp_ready(tech_pvt->rtp_session) ? "SUCCESS" : err);
-		inet_aton(tech_pvt->local_sdp_audio_ip, &addr);
-		send_start_media_transmission(listener,
-			tech_pvt->call_id, /* uint32_t conference_id, */
-			tech_pvt->party_id, /* uint32_t pass_thru_party_id, */
-			addr.s_addr, /* uint32_t remote_ip, */
-			tech_pvt->local_sdp_audio_port, /* uint32_t remote_port, */
-			20, /* uint32_t ms_per_packet, */
-			SKINNY_CODEC_ULAW_64K, /* uint32_t payload_capacity, */
-			184, /* uint32_t precedence, */
-			0, /* uint32_t silence_suppression, */
-			0, /* uint16_t max_frames_per_packet, */
-			0 /* uint32_t g723_bitrate */
-			);
-
-		if (switch_channel_get_state(channel) == CS_NEW) {
-			switch_channel_set_state(channel, CS_INIT);
-		}
-		switch_channel_mark_answered(channel);
-	}
-end:
-	if(session) {
-		switch_core_session_rwunlock(session);
-	}
-	return status;
+	/* Do nothing */
+	return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_service_url_stat_request(listener_t *listener, skinny_message_t *request)
 {
-	uint32_t line_instance = 0;
-	switch_core_session_t *session;
+	skinny_message_t *message;
+	struct service_url_stat_res_message *button = NULL;
 
-	skinny_check_data_length(request, sizeof(request->data.keypad_button));
-	
-	if(request->data.keypad_button.line_instance) {
-	    line_instance = request->data.keypad_button.line_instance;
-	} else {
-	    line_instance = 1;
-	}
+	skinny_check_data_length(request, sizeof(request->data.service_url_req));
 
-	session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.keypad_button.call_id);
+	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.service_url_res));
+	message->type = SERVICE_URL_STAT_RES_MESSAGE;
+	message->length = 4 + sizeof(message->data.service_url_res);
 
-	if(session) {
-		switch_channel_t *channel = NULL;
-		private_t *tech_pvt = NULL;
-		char digit = '\0';
+	skinny_service_url_get(listener, request->data.service_url_req.service_url_index, &button);
 
-		channel = switch_core_session_get_channel(session);
-		tech_pvt = switch_core_session_get_private(session);
+	memcpy(&message->data.service_url_res, button, sizeof(struct service_url_stat_res_message));
 
-		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SEND DTMF ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button);
+	skinny_send_reply(listener, message);
 
-		if (request->data.keypad_button.button == 14) {
-			digit = '*';
-		} else if (request->data.keypad_button.button == 15) {
-			digit = '#';
-		} else if (request->data.keypad_button.button >= 0 && request->data.keypad_button.button <= 9) {
-			digit = '0' + request->data.keypad_button.button;
-		} else {
-			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "UNKNOW DTMF RECEIVED ON CALL %d [%d]\n", tech_pvt->call_id, request->data.keypad_button.button);
-		}
-
-		/* TODO check call_id and line */
-
-		if((skinny_line_get_state(listener, line_instance, tech_pvt->call_id) == SKINNY_OFF_HOOK)) {
-	
-		    skinny_session_process_dest(session, listener, line_instance, NULL, digit, 0);
-		} else {
-			if(digit != '\0') {
-				switch_dtmf_t dtmf = { 0, switch_core_default_dtmf_duration(0)};
-				dtmf.digit = digit;
-				switch_channel_queue_dtmf(channel, &dtmf);
-			}
-		}
-	}
-
-	if(session) {
-		switch_core_session_rwunlock(session);
-	}
-
 	return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_on_hook_message(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_message_t *request)
 {
-	switch_status_t status = SWITCH_STATUS_SUCCESS;
-	switch_core_session_t *session = NULL;
-	uint32_t line_instance = 0;
+	skinny_message_t *message;
+	struct feature_stat_res_message *button = NULL;
 
-	skinny_check_data_length(request, sizeof(request->data.on_hook));
+	skinny_check_data_length(request, sizeof(request->data.feature_req));
 
-	line_instance = request->data.on_hook.line_instance;
-	
-	session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.on_hook.call_id);
+	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.feature_res));
+	message->type = FEATURE_STAT_RES_MESSAGE;
+	message->length = 4 + sizeof(message->data.feature_res);
 
-	if(session) {
-		switch_channel_t *channel = NULL;
+	skinny_feature_get(listener, request->data.feature_req.feature_index, &button);
 
-		channel = switch_core_session_get_channel(session);
+	memcpy(&message->data.feature_res, button, sizeof(struct feature_stat_res_message));
 
-		switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
-	}
-
-	if(session) {
-		switch_core_session_rwunlock(session);
-	}
-
-	return status;
-}
-
-switch_status_t skinny_handle_unregister(listener_t *listener, skinny_message_t *request)
-{
-	switch_event_t *event = NULL;
-	skinny_message_t *message;
-
-	/* skinny::unregister event */
-	skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_UNREGISTER);
-	switch_event_fire(&event);
-
-	message = switch_core_alloc(listener->pool, 12+sizeof(message->data.unregister_ack));
-	message->type = UNREGISTER_ACK_MESSAGE;
-	message->length = 4 + sizeof(message->data.unregister_ack);
-	message->data.unregister_ack.unregister_status = 0; /* OK */
 	skinny_send_reply(listener, message);
 
-	/* Close socket */
-	switch_clear_flag_locked(listener, LFLAG_RUNNING);
-
 	return SWITCH_STATUS_SUCCESS;
 }
 
@@ -2545,6 +2565,8 @@
 			return skinny_handle_time_date_request(listener, request);
 		case BUTTON_TEMPLATE_REQ_MESSAGE:
 			return skinny_handle_button_template_request(listener, request);
+		case VERSION_REQ_MESSAGE:
+			return skinny_handle_version_request(listener, request);
 		case CAPABILITIES_RES_MESSAGE:
 			return skinny_handle_capabilities_response(listener, request);
 		case ALARM_MESSAGE:

Modified: freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_protocol.h (17318 => 17319)


--- freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_protocol.h	2010-04-16 09:59:58 UTC (rev 17318)
+++ freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_protocol.h	2010-04-16 13:03:37 UTC (rev 17319)
@@ -114,6 +114,9 @@
 /* ButtonTemplateReqMessage */
 #define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
 
+/* VersionReqMessage */
+#define VERSION_REQ_MESSAGE 0x000F
+
 /* CapabilitiesResMessage */
 #define CAPABILITIES_RES_MESSAGE 0x0010
 struct station_capabilities {
@@ -343,6 +346,12 @@
     struct button_definition btn[SKINNY_MAX_BUTTON_COUNT];
 };
 
+/* VersionMessage */
+#define VERSION_MESSAGE 0x0098
+struct version_message {
+    char version[16];
+};
+
 /* CapabilitiesReqMessage */
 #define CAPABILITIES_REQ_MESSAGE 0x009B
 
@@ -535,6 +544,7 @@
     struct config_stat_res_message config_res;
     struct define_time_date_message define_time_date;
     struct button_template_message button_template;
+    struct version_message version;
     struct register_reject_message reg_rej;
     struct reset_message reset;
     struct open_receive_channel_message open_receive_channel;
@@ -724,6 +734,10 @@
 	uint32_t milliseconds,
 	uint32_t timestamp);
 switch_status_t send_define_current_time_date(listener_t *listener);
+switch_status_t send_version(listener_t *listener,
+    char *version);
+switch_status_t send_register_reject(listener_t *listener,
+    char *error);
 switch_status_t send_open_receive_channel(listener_t *listener,
     uint32_t conference_id,
     uint32_t pass_thru_party_id,

Modified: freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_tables.c (17318 => 17319)


--- freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_tables.c	2010-04-16 09:59:58 UTC (rev 17318)
+++ freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_tables.c	2010-04-16 13:03:37 UTC (rev 17319)
@@ -47,6 +47,7 @@
     {"ConfigStatReqMessage", CONFIG_STAT_REQ_MESSAGE},
     {"TimeDateReqMessage", TIME_DATE_REQ_MESSAGE},
     {"ButtonTemplateReqMessage", BUTTON_TEMPLATE_REQ_MESSAGE},
+    {"VersionReqMessage", VERSION_REQ_MESSAGE},
     {"CapabilitiesReqMessage", CAPABILITIES_RES_MESSAGE},
     {"AlarmMessage", ALARM_MESSAGE},
     {"OpenReceiveChannelAckMessage", OPEN_RECEIVE_CHANNEL_ACK_MESSAGE},
@@ -72,6 +73,7 @@
     {"ConfigStatResMessage", CONFIG_STAT_RES_MESSAGE},
     {"DefineTimeDateMessage", DEFINE_TIME_DATE_MESSAGE},
     {"ButtonTemplateResMessage", BUTTON_TEMPLATE_RES_MESSAGE},
+    {"VersionMessage", VERSION_MESSAGE},
     {"CapabilitiesReqMessage", CAPABILITIES_REQ_MESSAGE},
     {"RegisterRejectMessage", REGISTER_REJECT_MESSAGE},
     {"ResetMessage", RESET_MESSAGE},

Modified: freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_tables.h (17318 => 17319)


--- freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_tables.h	2010-04-16 09:59:58 UTC (rev 17318)
+++ freeswitch/trunk/src/mod/endpoints/mod_skinny/skinny_tables.h	2010-04-16 13:03:37 UTC (rev 17319)
@@ -84,7 +84,7 @@
     }
 
 
-struct skinny_table SKINNY_MESSAGE_TYPES[57];
+struct skinny_table SKINNY_MESSAGE_TYPES[59];
 const char *skinny_message_type2str(uint32_t id);
 uint32_t skinny_str2message_type(const char *str);
 #define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES)