]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Skinny: Initial implementation of VersionReq
authorMathieu Parent <math.parent@gmail.com>
Fri, 16 Apr 2010 13:03:37 +0000 (15:03 +0200)
committerMathieu Parent <math.parent@gmail.com>
Fri, 16 Apr 2010 13:03:37 +0000 (15:03 +0200)
And reordering

src/mod/endpoints/mod_skinny/skinny_protocol.c
src/mod/endpoints/mod_skinny/skinny_protocol.h
src/mod/endpoints/mod_skinny/skinny_tables.c
src/mod/endpoints/mod_skinny/skinny_tables.h

index c6daed417f982f87c06aa16343ecee9c064d36b6..975007279c615b71b52a3f0e5e4aa2658f57a986 100644 (file)
@@ -1389,6 +1389,15 @@ switch_status_t send_capabilities_req(listener_t *listener)
        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 @@ switch_status_t send_reset(listener_t *listener, uint32_t reset_type)
        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_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);
+       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;
 }
 
@@ -1733,11 +1735,231 @@ end:
        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;
+
+       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);
 
-       /* Nothing to do */
        return SWITCH_STATUS_SUCCESS;
 }
 
@@ -1798,88 +2020,9 @@ switch_status_t skinny_handle_config_stat_request(listener_t *listener, skinny_m
        return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_capabilities_response(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;
-}
-
-switch_status_t skinny_handle_port_message(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;
-
-       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;
+       return send_define_current_time_date(listener);
 }
 
 struct button_template_helper {
@@ -1968,38 +2111,187 @@ switch_status_t skinny_handle_button_template_request(listener_t *listener, skin
                }
        }
 
-       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,112 +2344,7 @@ switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_
        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 skinny_handle_soft_key_event_message(listener_t *listener, skinny_message_t *request)
 {
        switch_status_t status = SWITCH_STATUS_SUCCESS;
        uint32_t line_instance = 0;
@@ -2240,273 +2427,106 @@ switch_status_t skinny_handle_soft_key_event_message(listener_t *listener, skinn
        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;
-
-       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);
+       switch_event_t *event = NULL;
+       skinny_message_t *message;
 
-       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::unregister event */
+       skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_UNREGISTER);
+       switch_event_fire(&event);
 
-           skinny_session_process_dest(session, listener, line_instance, NULL, '\0', 0);
-       }
+       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);
 
-       if(session) {
-               switch_core_session_rwunlock(session);
-       }
+       /* Close socket */
+       switch_clear_flag_locked(listener, LFLAG_RUNNING);
 
        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.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 */
-                       );
+       skinny_check_data_length(request, sizeof(request->data.headset_status));
 
-               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;
+       /* Nothing to do */
+       return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_register_available_lines_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);
-       }
+       skinny_check_data_length(request, sizeof(request->data.reg_lines));
 
+       /* Do nothing */
        return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_on_hook_message(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_service_url_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_check_data_length(request, sizeof(request->data.on_hook));
+       skinny_message_t *message;
+       struct service_url_stat_res_message *button = NULL;
 
-       line_instance = request->data.on_hook.line_instance;
-       
-       session = skinny_profile_find_session(listener->profile, listener, &line_instance, request->data.on_hook.call_id);
+       skinny_check_data_length(request, sizeof(request->data.service_url_req));
 
-       if(session) {
-               switch_channel_t *channel = NULL;
+       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);
 
-               channel = switch_core_session_get_channel(session);
+       skinny_service_url_get(listener, request->data.service_url_req.service_url_index, &button);
 
-               switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING);
-       }
+       memcpy(&message->data.service_url_res, button, sizeof(struct service_url_stat_res_message));
 
-       if(session) {
-               switch_core_session_rwunlock(session);
-       }
+       skinny_send_reply(listener, message);
 
-       return status;
+       return SWITCH_STATUS_SUCCESS;
 }
 
-switch_status_t skinny_handle_unregister(listener_t *listener, skinny_message_t *request)
+switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_message_t *request)
 {
-       switch_event_t *event = NULL;
        skinny_message_t *message;
+       struct feature_stat_res_message *button = NULL;
 
-       /* skinny::unregister event */
-       skinny_device_event(listener, &event, SWITCH_EVENT_CUSTOM, SKINNY_EVENT_UNREGISTER);
-       switch_event_fire(&event);
+       skinny_check_data_length(request, sizeof(request->data.feature_req));
 
-       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);
+       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);
 
-       /* Close socket */
-       switch_clear_flag_locked(listener, LFLAG_RUNNING);
+       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;
 }
@@ -2545,6 +2565,8 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re
                        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:
index 994462684fd032438cf0f3e160dbf8371b75fb55..aeaa42f09e144f6649cb65ad1f66d308fecbe1db 100644 (file)
@@ -114,6 +114,9 @@ struct line_stat_req_message {
 /* 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_template_message {
     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 @@ union skinny_data {
     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 @@ switch_status_t send_define_time_date(listener_t *listener,
        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,
index a9bf84431ff3f54ebd01f3b52522f9057d516579..42e8bb96b3c95637d1691239ec5d7ff516c549e8 100644 (file)
@@ -47,6 +47,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = {
     {"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 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = {
     {"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},
index f3755b5c2ff89f93ed1aa0c172f1e6cb322f082a..90bc45ef91b62cea22455638e5c3489afb8d9066 100644 (file)
@@ -84,7 +84,7 @@ uint32_t func(const char *str)\
     }
 
 
-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)