<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][16769] </title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=16769">16769</a></dd>
<dt>Author</dt> <dd>sathieu</dd>
<dt>Date</dt> <dd>2010-02-24 06:00:45 -0600 (Wed, 24 Feb 2010)</dd>
</dl>

<h3>Log Message</h3>
<pre>Skinny: Milestone 4: Button template, Soft-key template and Soft-key sets

- buttons are now stored in the same table
- answer ButtonTemplateReqMessage with ButtonTemplateMessage: DONE
- answer SoftKeyTemplateReqMessage with SoftKeyTemplateResMessage: WIP (currently empty response)
- answer SoftKeySetReqMessage with SoftKeySetResMessage: WIP (currently empty response)</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#freeswitchtrunksrcmodendpointsmod_skinnymod_skinnyc">freeswitch/trunk/src/mod/endpoints/mod_skinny/mod_skinny.c</a></li>
<li><a href="#freeswitchtrunksrcmodendpointsmod_skinnytestskinnypl">freeswitch/trunk/src/mod/endpoints/mod_skinny/test-skinny.pl</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchtrunksrcmodendpointsmod_skinnymod_skinnyc"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_skinny/mod_skinny.c (16768 => 16769)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_skinny/mod_skinny.c        2010-02-24 12:00:35 UTC (rev 16768)
+++ freeswitch/trunk/src/mod/endpoints/mod_skinny/mod_skinny.c        2010-02-24 12:00:45 UTC (rev 16769)
</span><span class="lines">@@ -103,33 +103,26 @@
</span><span class="cx"> /*****************************************************************************/
</span><span class="cx"> static char devices_sql[] =
</span><span class="cx">         &quot;CREATE TABLE skinny_devices (\n&quot;
</span><del>-        &quot;   device_name      VARCHAR(16),\n&quot;
</del><ins>+        &quot;   name           VARCHAR(16),\n&quot;
</ins><span class="cx">         &quot;   user_id          INTEGER,\n&quot;
</span><span class="cx">         &quot;   instance         INTEGER,\n&quot;
</span><span class="cx">         &quot;   ip               VARCHAR(255),\n&quot;
</span><del>-        &quot;   device_type      INTEGER,\n&quot;
</del><ins>+        &quot;   type             INTEGER,\n&quot;
</ins><span class="cx">         &quot;   max_streams      INTEGER,\n&quot;
</span><span class="cx">         &quot;   port             INTEGER,\n&quot;
</span><span class="cx">         &quot;   codec_string     VARCHAR(255)\n&quot;
</span><span class="cx">         &quot;);\n&quot;;
</span><span class="cx"> 
</span><del>-static char lines_sql[] =
-        &quot;CREATE TABLE skinny_lines (\n&quot;
</del><ins>+static char buttons_sql[] =
+        &quot;CREATE TABLE skinny_buttons (\n&quot;
</ins><span class="cx">         &quot;   device_name      VARCHAR(16),\n&quot;
</span><del>-        &quot;   line_position    INTEGER,\n&quot;
-        &quot;   line_name        VARCHAR(24),\n&quot;
-        &quot;   line_shortname   VARCHAR(40),\n&quot;
-        &quot;   line_displayname VARCHAR(44)\n&quot;
</del><ins>+        &quot;   position         INTEGER,\n&quot;
+        &quot;   type             VARCHAR(10),\n&quot;
+        &quot;   label            VARCHAR(40),\n&quot;
+        &quot;   value            VARCHAR(24),\n&quot;
+        &quot;   settings         VARCHAR(44)\n&quot;
</ins><span class="cx">         &quot;);\n&quot;;
</span><span class="cx"> 
</span><del>-static char speeddials_sql[] =
-        &quot;CREATE TABLE skinny_speeddials (\n&quot;
-        &quot;   device_name       VARCHAR(16),\n&quot;
-        &quot;   speed_position    INTEGER,\n&quot;
-        &quot;   speed_number      VARCHAR(24),\n&quot;
-        &quot;   speed_displayname VARCHAR(40)\n&quot;
-        &quot;);\n&quot;;
-
</del><span class="cx"> /*****************************************************************************/
</span><span class="cx"> /* CHANNEL TYPES */
</span><span class="cx"> /*****************************************************************************/
</span><span class="lines">@@ -201,6 +194,9 @@
</span><span class="cx">         char reserved[10];
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+/* ButtonTemplateReqMessage */
+#define BUTTON_TEMPLATE_REQ_MESSAGE 0x000E
+
</ins><span class="cx"> #define CAPABILITIES_RES_MESSAGE 0x0010
</span><span class="cx"> struct capabilities_res_message {
</span><span class="cx">         uint32_t count;
</span><span class="lines">@@ -216,9 +212,15 @@
</span><span class="cx">         uint32_t alarm_param2;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+/* SoftKeySetReqMessage */
+#define SOFT_KEY_SET_REQ_MESSAGE 0x0025
+
</ins><span class="cx"> /* UnregisterMessage */
</span><span class="cx"> #define UNREGISTER_MESSAGE 0x0027
</span><span class="cx"> 
</span><ins>+/* SoftKeyTemplateReqMessage */
+#define SOFT_KEY_TEMPLATE_REQ_MESSAGE 0x0028
+
</ins><span class="cx"> /* RegisterAvailableLinesMessage */
</span><span class="cx"> #define REGISTER_AVAILABLE_LINES_MESSAGE 0x002D
</span><span class="cx"> struct register_available_lines_message {
</span><span class="lines">@@ -244,6 +246,20 @@
</span><span class="cx">         char displayname[44];
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+/* ButtonTemplateMessage */
+#define BUTTON_TEMPLATE_RES_MESSAGE 0x0097
+struct button_definition {
+        uint8_t instance_number;
+        uint8_t button_definition;
+};
+
+struct button_template_message {
+        uint32_t button_offset;
+        uint32_t button_count;
+        uint32_t total_button_count;
+        struct button_definition btn[42];
+};
+
</ins><span class="cx"> /* CapabilitiesReqMessage */
</span><span class="cx"> #define CAPABILITIES_REQ_MESSAGE 0x009B
</span><span class="cx"> 
</span><span class="lines">@@ -256,6 +272,36 @@
</span><span class="cx"> /* KeepAliveAckMessage */
</span><span class="cx"> #define KEEP_ALIVE_ACK_MESSAGE 0x0100
</span><span class="cx"> 
</span><ins>+/* SoftKeyTemplateResMessage */
+#define SOFT_KEY_TEMPLATE_RES_MESSAGE 0x0108
+
+struct soft_key_template_definition {
+        char soft_key_label[16];
+        uint32_t soft_key_event;
+};
+
+struct soft_key_template_res_message {
+        uint32_t soft_key_offset;
+        uint32_t soft_key_count;
+        uint32_t total_soft_key_count;
+        struct soft_key_template_definition soft_key[32];
+};
+
+/* SoftKeySetResMessage */
+#define SOFT_KEY_SET_RES_MESSAGE 0x0109
+struct soft_key_set_definition {
+        uint8_t soft_key_template_index[16];
+        uint16_t soft_key_info_index[16];
+};
+
+struct soft_key_set_res_message {
+        uint32_t soft_key_set_offset;
+        uint32_t soft_key_set_count;
+        uint32_t total_soft_key_set_count;
+        struct soft_key_set_definition soft_key_set[16];
+        uint32_t res;
+};
+
</ins><span class="cx"> /* Message */
</span><span class="cx"> #define SKINNY_MESSAGE_FIELD_SIZE 4 /* 4-bytes field */
</span><span class="cx"> #define SKINNY_MESSAGE_HEADERSIZE 12 /* three 4-bytes fields */
</span><span class="lines">@@ -269,7 +315,10 @@
</span><span class="cx">         struct capabilities_res_message cap_res;
</span><span class="cx">         struct alarm_message alarm;
</span><span class="cx">         struct line_stat_res_message line_res;
</span><ins>+        struct button_template_message button_template;
</ins><span class="cx">         struct register_rej_message reg_rej;
</span><ins>+        struct soft_key_template_res_message soft_key_template;
+        struct soft_key_set_res_message soft_key_set;
</ins><span class="cx">         
</span><span class="cx">         uint16_t as_uint16;
</span><span class="cx">         char as_char;
</span><span class="lines">@@ -1131,7 +1180,7 @@
</span><span class="cx"> 
</span><span class="cx">         switch_event_create_subclass(&amp;event, event_id, subclass_name);
</span><span class="cx">         switch_assert(event);
</span><del>-        if ((sql = switch_mprintf(&quot;SELECT * FROM skinny_devices WHERE device_name='%s'&quot;, listener-&gt;device_name))) {
</del><ins>+        if ((sql = switch_mprintf(&quot;SELECT * FROM skinny_devices WHERE name='%s'&quot;, listener-&gt;device_name))) {
</ins><span class="cx">                 skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, sql, skinny_device_event_callback, event);
</span><span class="cx">                 switch_safe_free(sql);
</span><span class="cx">         }
</span><span class="lines">@@ -1159,7 +1208,7 @@
</span><span class="cx">         skinny_profile_t *profile;
</span><span class="cx">         switch_event_t *event = NULL;
</span><span class="cx">         switch_event_t *params = NULL;
</span><del>-        switch_xml_t xroot, xdomain, xgroup, xuser, xskinny, xlines, xline, xspeeddials, xspeeddial;
</del><ins>+        switch_xml_t xroot, xdomain, xgroup, xuser, xskinny, xbuttons, xbutton;
</ins><span class="cx">         char *sql;
</span><span class="cx">         assert(listener-&gt;profile);
</span><span class="cx">         profile = listener-&gt;profile;
</span><span class="lines">@@ -1196,7 +1245,7 @@
</span><span class="cx"> 
</span><span class="cx">         if ((sql = switch_mprintf(
</span><span class="cx">                         &quot;INSERT INTO skinny_devices &quot;
</span><del>-                                &quot;(device_name, user_id, instance, ip, device_type, max_streams, codec_string) &quot;
</del><ins>+                                &quot;(name, user_id, instance, ip, type, max_streams, codec_string) &quot;
</ins><span class="cx">                                 &quot;VALUES ('%s','%d','%d', '%s', '%d', '%d', '%s')&quot;,
</span><span class="cx">                         request-&gt;data.reg.deviceName,
</span><span class="cx">                         request-&gt;data.reg.userId,
</span><span class="lines">@@ -1215,46 +1264,29 @@
</span><span class="cx"> 
</span><span class="cx">         xskinny = switch_xml_child(xuser, &quot;skinny&quot;);
</span><span class="cx">         if (xskinny) {
</span><del>-                xlines = switch_xml_child(xskinny, &quot;lines&quot;);
-                if (xlines) {
-                        for (xline = switch_xml_child(xlines, &quot;line&quot;); xline; xline = xline-&gt;next) {
-                                const char *position = switch_xml_attr_soft(xline, &quot;position&quot;);
-                                const char *name = switch_xml_attr_soft(xline, &quot;name&quot;);
-                                const char *shortname = switch_xml_attr_soft(xline, &quot;shortname&quot;);
-                                const char *displayname = switch_xml_attr_soft(xline, &quot;displayname&quot;);
</del><ins>+                xbuttons = switch_xml_child(xskinny, &quot;buttons&quot;);
+                if (xbuttons) {
+                        for (xbutton = switch_xml_child(xbuttons, &quot;button&quot;); xbutton; xbutton = xbutton-&gt;next) {
+                                const char *position = switch_xml_attr_soft(xbutton, &quot;position&quot;);
+                                const char *type = switch_xml_attr_soft(xbutton, &quot;type&quot;);
+                                const char *label = switch_xml_attr_soft(xbutton, &quot;label&quot;);
+                                const char *value = switch_xml_attr_soft(xbutton, &quot;value&quot;);
+                                const char *settings = switch_xml_attr_soft(xbutton, &quot;settings&quot;);
</ins><span class="cx">                                 if ((sql = switch_mprintf(
</span><del>-                                                &quot;INSERT INTO skinny_lines &quot;
-                                                        &quot;(device_name, line_position, line_name, line_shortname, line_displayname) &quot;
-                                                        &quot;VALUES('%s', '%s', '%s', '%s', '%s')&quot;,
</del><ins>+                                                &quot;INSERT INTO skinny_buttons &quot;
+                                                        &quot;(device_name, position, type, label, value, settings) &quot;
+                                                        &quot;VALUES('%s', '%s', '%s', '%s', '%s', '%s')&quot;,
</ins><span class="cx">                                                 request-&gt;data.reg.deviceName,
</span><span class="cx">                                                 position,
</span><del>-                                                name,
-                                                shortname,
-                                                displayname))) {
</del><ins>+                                                type,
+                                                label,
+                                                value,
+                                                settings))) {
</ins><span class="cx">                                         skinny_execute_sql(profile, sql, profile-&gt;listener_mutex);
</span><span class="cx">                                         switch_safe_free(sql);
</span><span class="cx">                                 }
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><del>-                xspeeddials = switch_xml_child(xskinny, &quot;speed-dials&quot;);
-                if (xspeeddials) {
-                        for (xspeeddial = switch_xml_child(xspeeddials, &quot;speed-dial&quot;); xspeeddial; xspeeddial = xspeeddial-&gt;next) {
-                                const char *position = switch_xml_attr_soft(xspeeddial, &quot;position&quot;);
-                                const char *line = switch_xml_attr_soft(xspeeddial, &quot;line&quot;);
-                                const char *label = switch_xml_attr_soft(xspeeddial, &quot;label&quot;);
-                                if ((sql = switch_mprintf(
-                                                &quot;INSERT INTO skinny_speeddials &quot;
-                                                        &quot;(device_name, speed_position, speed_line, speed_label) &quot;
-                                                        &quot;VALUES('%s', '%s', '%s', '%s')&quot;,
-                                                request-&gt;data.reg.deviceName,
-                                                position,
-                                                line,
-                                                label))) {
-                                        skinny_execute_sql(profile, sql, profile-&gt;listener_mutex);
-                                        switch_safe_free(sql);
-                                }
-                        }
-                }
</del><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         status = SWITCH_STATUS_SUCCESS;
</span><span class="lines">@@ -1336,7 +1368,7 @@
</span><span class="cx">         }
</span><span class="cx">         codec_string[string_len] = '\0';
</span><span class="cx">         if ((sql = switch_mprintf(
</span><del>-                        &quot;UPDATE skinny_devices SET codec_string='%s' WHERE device_name='%s'&quot;,
</del><ins>+                        &quot;UPDATE skinny_devices SET codec_string='%s' WHERE name='%s'&quot;,
</ins><span class="cx">                         codec_string,
</span><span class="cx">                         listener-&gt;device_name
</span><span class="cx">                         ))) {
</span><span class="lines">@@ -1361,7 +1393,7 @@
</span><span class="cx">         skinny_check_data_length(request, sizeof(request-&gt;data.as_uint16));
</span><span class="cx"> 
</span><span class="cx">         if ((sql = switch_mprintf(
</span><del>-                        &quot;UPDATE skinny_devices SET port='%d' WHERE device_name='%s'&quot;,
</del><ins>+                        &quot;UPDATE skinny_devices SET port='%d' WHERE name='%s'&quot;,
</ins><span class="cx">                         request-&gt;data.as_uint16,
</span><span class="cx">                         listener-&gt;device_name
</span><span class="cx">                         ))) {
</span><span class="lines">@@ -1371,19 +1403,146 @@
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static int skinny_line_stat_request_callback(void *pArg, int argc, char **argv, char **columnNames)
</del><ins>+struct button_template_helper {
+        skinny_message_t *message;
+        int count[0xff+1];
+};
</ins><span class="cx"> 
</span><ins>+static int skinny_handle_button_template_request_callback(void *pArg, int argc, char **argv, char **columnNames)
</ins><span class="cx"> {
</span><del>-        skinny_message_t *message = pArg;
</del><ins>+        struct button_template_helper *helper = pArg;
+        skinny_message_t *message = helper-&gt;message;
+        char *device_name = argv[0];
+        int position = atoi(argv[1]);
+        char *type = argv[2];
+        int i;
+        
+        /* fill buttons between previous one and current one */
+        for(i = message-&gt;data.button_template.button_count; i+1 &lt; position; i++) {
+                message-&gt;data.button_template.btn[i].instance_number = ++helper-&gt;count[0xff];
+                message-&gt;data.button_template.btn[i].button_definition = 0xff; /* None */
+                message-&gt;data.button_template.button_count++;
+                message-&gt;data.button_template.total_button_count++;
+        }
</ins><span class="cx"> 
</span><del>-        strcpy(message-&gt;data.line_res.name, argv[2]);
-        strcpy(message-&gt;data.line_res.shortname,  argv[3]);
-        strcpy(message-&gt;data.line_res.displayname,  argv[4]);
</del><span class="cx"> 
</span><ins>+        if (!strcasecmp(type, &quot;line&quot;)) {
+                message-&gt;data.button_template.btn[i].instance_number = ++helper-&gt;count[0x09];
+                message-&gt;data.button_template.btn[position-1].button_definition = 0x09; /* Line */
+        } else if (!strcasecmp(type, &quot;speed-dial&quot;)) {
+                message-&gt;data.button_template.btn[i].instance_number = ++helper-&gt;count[0x02];
+                message-&gt;data.button_template.btn[position-1].button_definition = 0x02; /* speeddial */
+        } else {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
+                        &quot;Unknown button type %s for device %s.\n&quot;, type, device_name);
+        }
+        message-&gt;data.button_template.button_count++;
+        message-&gt;data.button_template.total_button_count++;
+
</ins><span class="cx">         return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static switch_status_t skinny_handle_button_template_request(listener_t *listener, skinny_message_t *request)
+{
+        skinny_message_t *message;
+        struct button_template_helper helper = {0};
+        skinny_profile_t *profile;
+        char *sql;
</ins><span class="cx"> 
</span><ins>+        switch_assert(listener-&gt;profile);
+        switch_assert(listener-&gt;device_name);
+
+        profile = listener-&gt;profile;
+
+        message = switch_core_alloc(listener-&gt;pool, 12+sizeof(message-&gt;data.button_template));
+        message-&gt;type = BUTTON_TEMPLATE_RES_MESSAGE;
+        message-&gt;length = 4 + sizeof(message-&gt;data.button_template);
+
+        message-&gt;data.button_template.button_offset = 0;
+        message-&gt;data.button_template.button_count = 0;
+        message-&gt;data.button_template.total_button_count = 0;
+        
+        helper.message = message;
+        /* Add buttons */
+        if ((sql = switch_mprintf(
+                        &quot;SELECT device_name, position, type &quot;
+                                &quot;FROM skinny_buttons WHERE device_name='%s' ORDER BY position&quot;,
+                        listener-&gt;device_name
+                        ))) {
+                skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, sql, skinny_handle_button_template_request_callback, &amp;helper);
+                switch_safe_free(sql);
+        }
+        
+        skinny_send_reply(listener, message);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t skinny_handle_soft_key_template_request(listener_t *listener, skinny_message_t *request)
+{
+        skinny_message_t *message;
+        skinny_profile_t *profile;
+
+        switch_assert(listener-&gt;profile);
+        switch_assert(listener-&gt;device_name);
+
+        profile = listener-&gt;profile;
+
+        message = switch_core_alloc(listener-&gt;pool, 12+sizeof(message-&gt;data.soft_key_template));
+        message-&gt;type = SOFT_KEY_TEMPLATE_RES_MESSAGE;
+        message-&gt;length = 4 + sizeof(message-&gt;data.soft_key_template);
+
+        message-&gt;data.soft_key_template.soft_key_offset = 0;
+        message-&gt;data.soft_key_template.soft_key_count = 21;
+        message-&gt;data.soft_key_template.total_soft_key_count = 21;
+        
+        /* TODO fill the template */
+        strcpy(message-&gt;data.soft_key_template.soft_key[0].soft_key_label, &quot;\200\001&quot;);
+        message-&gt;data.soft_key_template.soft_key[0].soft_key_event = 1; /* Redial */
+        
+        skinny_send_reply(listener, message);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t skinny_handle_soft_key_set_request(listener_t *listener, skinny_message_t *request)
+{
+        skinny_message_t *message;
+        skinny_profile_t *profile;
+
+        switch_assert(listener-&gt;profile);
+        switch_assert(listener-&gt;device_name);
+
+        profile = listener-&gt;profile;
+
+        message = switch_core_alloc(listener-&gt;pool, 12+sizeof(message-&gt;data.soft_key_set));
+        message-&gt;type = SOFT_KEY_SET_RES_MESSAGE;
+        message-&gt;length = 4 + sizeof(message-&gt;data.soft_key_set);
+
+        message-&gt;data.soft_key_set.soft_key_set_offset = 0;
+        message-&gt;data.soft_key_set.soft_key_set_count = 11;
+        message-&gt;data.soft_key_set.total_soft_key_set_count = 11;
+        
+        /* TODO fill the set */
+        
+        skinny_send_reply(listener, message);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static int skinny_line_stat_request_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+        skinny_message_t *message = pArg;
+
+        message-&gt;data.line_res.number++;
+        if (message-&gt;data.line_res.number == atoi(argv[0])) { /* wanted_position */
+                strcpy(message-&gt;data.line_res.name, argv[3]); /* value */
+                strcpy(message-&gt;data.line_res.shortname,  argv[2]); /* label */
+                strcpy(message-&gt;data.line_res.displayname,  argv[4]); /* settings */
+        }
+        return 0;
+}
+
</ins><span class="cx"> static switch_status_t skinny_handle_line_stat_request(listener_t *listener, skinny_message_t *request)
</span><span class="cx"> {
</span><span class="cx">         skinny_message_t *message;
</span><span class="lines">@@ -1400,16 +1559,19 @@
</span><span class="cx">         message = switch_core_alloc(listener-&gt;pool, 12+sizeof(message-&gt;data.line_res));
</span><span class="cx">         message-&gt;type = LINE_STAT_RES_MESSAGE;
</span><span class="cx">         message-&gt;length = 4 + sizeof(message-&gt;data.line_res);
</span><del>-        message-&gt;data.line_res.number = request-&gt;data.line_req.number;
</del><ins>+        message-&gt;data.line_res.number = 0;
</ins><span class="cx"> 
</span><span class="cx">         if ((sql = switch_mprintf(
</span><del>-                        &quot;SELECT * FROM skinny_lines WHERE device_name='%s' AND line_position='%d'&quot;,
-                        listener-&gt;device_name,
-                        request-&gt;data.line_req.number
</del><ins>+                        &quot;SELECT '%d' AS wanted_position, position, label, value, settings &quot;
+                                &quot;FROM skinny_buttons WHERE device_name='%s' AND type='line' &quot;
+                                &quot;ORDER BY position&quot;,
+                        request-&gt;data.line_req.number,
+                        listener-&gt;device_name
</ins><span class="cx">                         ))) {
</span><span class="cx">                 skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, sql, skinny_line_stat_request_callback, message);
</span><span class="cx">                 switch_safe_free(sql);
</span><span class="cx">         }
</span><ins>+        message-&gt;data.line_res.number = request-&gt;data.line_req.number;
</ins><span class="cx">         skinny_send_reply(listener, message);
</span><span class="cx"> 
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="lines">@@ -1463,6 +1625,12 @@
</span><span class="cx">                         return skinny_handle_capabilities_response(listener, request);
</span><span class="cx">                 case PORT_MESSAGE:
</span><span class="cx">                         return skinny_handle_port_message(listener, request);
</span><ins>+                case BUTTON_TEMPLATE_REQ_MESSAGE:
+                        return skinny_handle_button_template_request(listener, request);
+                case SOFT_KEY_TEMPLATE_REQ_MESSAGE:
+                        return skinny_handle_soft_key_template_request(listener, request);
+                case SOFT_KEY_SET_REQ_MESSAGE:
+                        return skinny_handle_soft_key_set_request(listener, request);
</ins><span class="cx">                 case LINE_STAT_REQ_MESSAGE:
</span><span class="cx">                         return skinny_handle_line_stat_request(listener, request);
</span><span class="cx">                 case REGISTER_AVAILABLE_LINES_MESSAGE:
</span><span class="lines">@@ -1567,22 +1735,22 @@
</span><span class="cx"> {
</span><span class="cx">         switch_stream_handle_t *stream = (switch_stream_handle_t *) pArg;
</span><span class="cx"> 
</span><del>-        char *device_name = argv[0];
</del><ins>+        char *name = argv[0];
</ins><span class="cx">         char *user_id = argv[1];
</span><span class="cx">         char *instance = argv[2];
</span><span class="cx">         char *ip = argv[3];
</span><del>-        char *device_type = argv[4];
</del><ins>+        char *type = argv[4];
</ins><span class="cx">         char *max_streams = argv[5];
</span><span class="cx">         char *port = argv[6];
</span><span class="cx">         char *codec_string = argv[7];
</span><span class="cx"> 
</span><span class="cx">         const char *line = &quot;=================================================================================================&quot;;
</span><span class="cx">         stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
</span><del>-        stream-&gt;write_function(stream, &quot;DeviceName    \t%s\n&quot;, switch_str_nil(device_name));
</del><ins>+        stream-&gt;write_function(stream, &quot;DeviceName    \t%s\n&quot;, switch_str_nil(name));
</ins><span class="cx">         stream-&gt;write_function(stream, &quot;UserId        \t%s\n&quot;, user_id);
</span><span class="cx">         stream-&gt;write_function(stream, &quot;Instance      \t%s\n&quot;, instance);
</span><span class="cx">         stream-&gt;write_function(stream, &quot;IP            \t%s\n&quot;, ip);
</span><del>-        stream-&gt;write_function(stream, &quot;DeviceType    \t%s\n&quot;, device_type);
</del><ins>+        stream-&gt;write_function(stream, &quot;DeviceType    \t%s\n&quot;, type);
</ins><span class="cx">         stream-&gt;write_function(stream, &quot;MaxStreams    \t%s\n&quot;, max_streams);
</span><span class="cx">         stream-&gt;write_function(stream, &quot;Port          \t%s\n&quot;, port);
</span><span class="cx">         stream-&gt;write_function(stream, &quot;Codecs        \t%s\n&quot;, codec_string);
</span><span class="lines">@@ -1594,7 +1762,7 @@
</span><span class="cx"> static switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream)
</span><span class="cx"> {
</span><span class="cx">         char *sql;
</span><del>-        if ((sql = switch_mprintf(&quot;SELECT * FROM skinny_devices WHERE device_name LIKE '%s'&quot;,
</del><ins>+        if ((sql = switch_mprintf(&quot;SELECT * FROM skinny_devices WHERE name LIKE '%s'&quot;,
</ins><span class="cx">                         device_name))) {
</span><span class="cx">                 skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, sql, dump_device_callback, stream);
</span><span class="cx">                 switch_safe_free(sql);
</span><span class="lines">@@ -1992,13 +2160,11 @@
</span><span class="cx"> 
</span><span class="cx">                                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;Connected ODBC DSN: %s\n&quot;, profile-&gt;odbc_dsn);
</span><span class="cx">                                         switch_odbc_handle_exec(profile-&gt;master_odbc, devices_sql, NULL, NULL);
</span><del>-                                        switch_odbc_handle_exec(profile-&gt;master_odbc, lines_sql, NULL, NULL);
-                                        switch_odbc_handle_exec(profile-&gt;master_odbc, speeddials_sql, NULL, NULL);
</del><ins>+                                        switch_odbc_handle_exec(profile-&gt;master_odbc, buttons_sql, NULL, NULL);
</ins><span class="cx">                                 } else {
</span><span class="cx">                                         if ((db = switch_core_db_open_file(profile-&gt;dbname))) {
</span><span class="cx">                                                 switch_core_db_test_reactive(db, &quot;SELECT * FROM skinny_devices&quot;, NULL, devices_sql);
</span><del>-                                                switch_core_db_test_reactive(db, &quot;SELECT * FROM skinny_lines&quot;, NULL, lines_sql);
-                                                switch_core_db_test_reactive(db, &quot;SELECT * FROM skinny_speeddials&quot;, NULL, speeddials_sql);
</del><ins>+                                                switch_core_db_test_reactive(db, &quot;SELECT * FROM skinny_buttons&quot;, NULL, buttons_sql);
</ins><span class="cx">                                         } else {
</span><span class="cx">                                                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, &quot;Cannot Open SQL Database!\n&quot;);
</span><span class="cx">                                                 continue;
</span><span class="lines">@@ -2007,8 +2173,7 @@
</span><span class="cx">                                 }
</span><span class="cx">                                 
</span><span class="cx">                                 skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, &quot;DELETE FROM skinny_devices&quot;, NULL, NULL);
</span><del>-                                skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, &quot;DELETE FROM skinny_lines&quot;, NULL, NULL);
-                                skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, &quot;DELETE FROM skinny_speeddials&quot;, NULL, NULL);
</del><ins>+                                skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, &quot;DELETE FROM skinny_buttons&quot;, NULL, NULL);
</ins><span class="cx"> 
</span><span class="cx">                                 switch_core_hash_insert(globals.profile_hash, profile-&gt;name, profile);
</span><span class="cx">                                 profile = NULL;
</span><span class="lines">@@ -2158,7 +2323,7 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if((profile = skinny_find_profile(argv[3]))) {
</span><del>-                if ((sql = switch_mprintf(&quot;SELECT device_name FROM skinny_devices&quot;))) {
</del><ins>+                if ((sql = switch_mprintf(&quot;SELECT name FROM skinny_devices&quot;))) {
</ins><span class="cx">                         skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, sql, skinny_list_devices_callback, &amp;h);
</span><span class="cx">                         switch_safe_free(sql);
</span><span class="cx">                 }
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_skinnytestskinnypl"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_skinny/test-skinny.pl (16768 => 16769)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_skinny/test-skinny.pl        2010-02-24 12:00:35 UTC (rev 16768)
+++ freeswitch/trunk/src/mod/endpoints/mod_skinny/test-skinny.pl        2010-02-24 12:00:45 UTC (rev 16769)
</span><span class="lines">@@ -11,7 +11,7 @@
</span><span class="cx"> sub skinny_connect
</span><span class="cx"> {
</span><span class="cx">         $socket = IO::Socket::INET-&gt;new(
</span><del>-                PeerAddr =&gt; '192.168.0.6',
</del><ins>+                PeerAddr =&gt; '127.0.0.1',
</ins><span class="cx">                 PeerPort =&gt; 2000,
</span><span class="cx">                 );
</span><span class="cx"> }
</span><span class="lines">@@ -62,10 +62,13 @@
</span><span class="cx">         printf &quot;.\n&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# =============================================================================
+# 
+# =============================================================================
</ins><span class="cx"> skinny_connect();
</span><span class="cx"> 
</span><del>-#
-skinny_send(0x0001, # register
</del><ins>+# =============================================================================
+skinny_send(0x0001, # Register
</ins><span class="cx">         pack(&quot;a16VVVVV&quot;,
</span><span class="cx">                 &quot;SEP001120AABBCC&quot;,
</span><span class="cx">                 0, # userId;
</span><span class="lines">@@ -74,25 +77,42 @@
</span><span class="cx">                 7, # deviceType;
</span><span class="cx">                 0, # maxStreams;
</span><span class="cx">         ));
</span><del>-skinny_recv(); # registerack
</del><ins>+skinny_recv(); # RegisterAck
</ins><span class="cx"> 
</span><del>-skinny_send(0x0002, # port
</del><ins>+skinny_send(0x0002, # Port
</ins><span class="cx">         pack(&quot;n&quot;, 2000
</span><span class="cx">         ));
</span><span class="cx"> 
</span><del>-skinny_recv(); # capreq
-skinny_send(0x0010, # capres
</del><ins>+skinny_send(0x002b, # HeadSetStatus
+        pack(&quot;V&quot;,
+                2, # Off
+        ));
+
+skinny_recv(); # CapabilitiesReq
+skinny_send(0x0010, # CapabilitiesRes
</ins><span class="cx">         pack(&quot;V&quot;.&quot;Vva10&quot;.&quot;Vva10&quot;,
</span><span class="cx">                 2, # count
</span><span class="cx">                 2, 8, &quot;&quot;, # codec, frames, res
</span><span class="cx">                 4, 16, &quot;&quot;, # codec, frames, res
</span><span class="cx">         ));
</span><span class="cx"> 
</span><del>-skinny_send(0x000B, # linestatreq
</del><ins>+skinny_send(0x000e, # ButtonTemplateReqMessage
+        &quot;&quot;);
+skinny_recv(); # ButtonTemplateMessage
+
+skinny_send(0x0028, # SoftKeyTemplateReq
+        &quot;&quot;);
+skinny_recv(); # SoftKeyTemplateRes
+
+skinny_send(0x0025, # SoftKeySetReq
+        &quot;&quot;);
+skinny_recv(); # SoftKeySetRes
+
+skinny_send(0x000B, # LineStatReq
</ins><span class="cx">         pack(&quot;V&quot;, 1));
</span><del>-skinny_recv(); # linestatres
</del><ins>+skinny_recv(); # LineStat
</ins><span class="cx"> 
</span><del>-skinny_send(0x002D, # registeravlines
</del><ins>+skinny_send(0x002D, # RegisterAvailableLines
</ins><span class="cx">         pack(&quot;V&quot;, 2
</span><span class="cx">         ));
</span><span class="cx"> 
</span></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>

</body>
</html>