<!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][16762] </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=16762">16762</a></dd>
<dt>Author</dt> <dd>sathieu</dd>
<dt>Date</dt> <dd>2010-02-24 05:59:49 -0600 (Wed, 24 Feb 2010)</dd>
</dl>

<h3>Log Message</h3>
<pre>Skinny: moving to SQL</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 (16761 => 16762)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_skinny/mod_skinny.c        2010-02-24 11:59:41 UTC (rev 16761)
+++ freeswitch/trunk/src/mod/endpoints/mod_skinny/mod_skinny.c        2010-02-24 11:59:49 UTC (rev 16762)
</span><span class="lines">@@ -111,14 +111,16 @@
</span><span class="cx"> static char lines_sql[] =
</span><span class="cx">         &quot;CREATE TABLE skinny_lines (\n&quot;
</span><span class="cx">         &quot;   device_name      VARCHAR(16),\n&quot;
</span><ins>+        &quot;   line_position    INTEGER,\n&quot;
</ins><span class="cx">         &quot;   line_name        VARCHAR(24),\n&quot;
</span><span class="cx">         &quot;   line_shortname   VARCHAR(40),\n&quot;
</span><span class="cx">         &quot;   line_displayname VARCHAR(44)\n&quot;
</span><span class="cx">         &quot;);\n&quot;;
</span><span class="cx"> 
</span><del>-static char speed_sql[] =
</del><ins>+static char speeddials_sql[] =
</ins><span class="cx">         &quot;CREATE TABLE skinny_speeddials (\n&quot;
</span><span class="cx">         &quot;   device_name       VARCHAR(16),\n&quot;
</span><ins>+        &quot;   speed_position    INTEGER,\n&quot;
</ins><span class="cx">         &quot;   speed_number      VARCHAR(24),\n&quot;
</span><span class="cx">         &quot;   speed_displayname VARCHAR(40)\n&quot;
</span><span class="cx">         &quot;);\n&quot;;
</span><span class="lines">@@ -268,45 +270,6 @@
</span><span class="cx"> /*****************************************************************************/
</span><span class="cx"> /* SKINNY TYPES */
</span><span class="cx"> /*****************************************************************************/
</span><del>-
-#define SKINNY_MAX_LINES 10
-struct skinny_line {
-        struct skinny_device_t *device;
-        char name[24];
-        char shortname[40];
-        char displayname[44];
-};
-typedef struct skinny_line skinny_line_t;
-
-#define SKINNY_MAX_SPEEDDIALS 20
-struct skinny_speeddial {
-        struct skinny_device_t *device;
-        char line[24];
-        char label[40];
-};
-typedef struct skinny_speeddial skinny_speeddial_t;
-
-struct skinny_device {
-        char deviceName[16];
-        uint32_t userId;
-        uint32_t instance;
-        struct in_addr ip;
-        uint32_t deviceType;
-        uint32_t maxStreams;
-
-        uint16_t port;
-
-        char *codec_string;
-        char *codec_order[SWITCH_MAX_CODECS];
-        int codec_order_last;
-
-        skinny_line_t line[SKINNY_MAX_LINES];
-        int line_last;
-        skinny_speeddial_t speeddial[SKINNY_MAX_SPEEDDIALS];
-        int speeddial_last;
-};
-typedef struct skinny_device skinny_device_t;
-
</del><span class="cx"> typedef switch_status_t (*skinny_command_t) (char **argv, int argc, switch_stream_handle_t *stream);
</span><span class="cx"> 
</span><span class="cx"> enum skinny_codecs {
</span><span class="lines">@@ -356,7 +319,7 @@
</span><span class="cx"> 
</span><span class="cx"> struct listener {
</span><span class="cx">         skinny_profile_t *profile;
</span><del>-        skinny_device_t *device; /* TODO -&gt; SQL */
</del><ins>+        char device_name[16];
</ins><span class="cx"> 
</span><span class="cx">         switch_socket_t *sock;
</span><span class="cx">         switch_memory_pool_t *pool;
</span><span class="lines">@@ -403,6 +366,34 @@
</span><span class="cx"> static switch_status_t keepalive_listener(listener_t *listener, void *pvt);
</span><span class="cx"> 
</span><span class="cx"> /*****************************************************************************/
</span><ins>+/* PROFILES FUNCTIONS */
+/*****************************************************************************/
+static switch_status_t dump_profile(const skinny_profile_t *profile, switch_stream_handle_t *stream)
+{
+        const char *line = &quot;=================================================================================================&quot;;
+        switch_assert(profile);
+        stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
+        stream-&gt;write_function(stream, &quot;Name             \t%s\n&quot;, profile-&gt;name);
+        stream-&gt;write_function(stream, &quot;Domain Name      \t%s\n&quot;, profile-&gt;domain);
+        stream-&gt;write_function(stream, &quot;IP               \t%s\n&quot;, profile-&gt;ip);
+        stream-&gt;write_function(stream, &quot;Port             \t%d\n&quot;, profile-&gt;port);
+        stream-&gt;write_function(stream, &quot;Dialplan         \t%s\n&quot;, profile-&gt;dialplan);
+        stream-&gt;write_function(stream, &quot;Keep-Alive       \t%d\n&quot;, profile-&gt;keep_alive);
+        stream-&gt;write_function(stream, &quot;Date-Format      \t%s\n&quot;, profile-&gt;date_format);
+        stream-&gt;write_function(stream, &quot;DBName           \t%s\n&quot;, profile-&gt;dbname ? profile-&gt;dbname : switch_str_nil(profile-&gt;odbc_dsn));
+        stream-&gt;write_function(stream, &quot;Listener-Threads \t%d\n&quot;, profile-&gt;listener_threads);
+        stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+
+static skinny_profile_t *get_profile(const char *profile_name)
+{
+        return (skinny_profile_t *) switch_core_hash_find(globals.profile_hash, profile_name);
+}
+
+/*****************************************************************************/
</ins><span class="cx"> /* SQL FUNCTIONS */
</span><span class="cx"> /*****************************************************************************/
</span><span class="cx"> static void skinny_execute_sql(skinny_profile_t *profile, char *sql, switch_mutex_t *mutex)
</span><span class="lines">@@ -427,6 +418,7 @@
</span><span class="cx">                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
</span><span class="cx">                         goto end;
</span><span class="cx">                 }
</span><ins>+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;SQL: %s\n&quot;, sql);
</ins><span class="cx">                 switch_core_db_persistant_execute(db, sql, 1);
</span><span class="cx">                 switch_core_db_close(db);
</span><span class="cx">         }
</span><span class="lines">@@ -456,6 +448,7 @@
</span><span class="cx">                         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, &quot;Error Opening DB %s\n&quot;, profile-&gt;dbname);
</span><span class="cx">                         goto end;
</span><span class="cx">                 }
</span><ins>+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;SQL: %s\n&quot;, sql);
</ins><span class="cx">                 switch_core_db_exec(db, sql, callback, pdata, &amp;errmsg);
</span><span class="cx"> 
</span><span class="cx">                 if (errmsg) {
</span><span class="lines">@@ -1018,23 +1011,46 @@
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static int skinny_device_event_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+        switch_event_t *event = (switch_event_t *) pArg;
+
+        char *device_name = argv[0];
+        char *user_id = argv[1];
+        char *instance = argv[2];
+        char *ip = argv[3];
+        char *device_type = argv[4];
+        char *max_streams = argv[5];
+        char *port = argv[6];
+        char *codec_string = argv[7];
+
+        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;Skinny-Device-Name&quot;, device_name);
+        switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-User-Id&quot;, &quot;%s&quot;, user_id);
+        switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-Instance&quot;, &quot;%s&quot;, instance);
+        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;Skinny-IP&quot;, ip);
+        switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-Device-Type&quot;, &quot;%s&quot;, device_type);
+        switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-Max-Streams&quot;, &quot;%s&quot;, max_streams);
+        switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-Port&quot;, &quot;%s&quot;, port);
+        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;Skinny-Codecs&quot;, codec_string);
+
+        return 0;
+}
+
</ins><span class="cx"> static switch_status_t skinny_device_event(listener_t *listener, switch_event_t **ev, switch_event_types_t event_id, const char *subclass_name)
</span><span class="cx"> {
</span><span class="cx">         switch_event_t *event = NULL;
</span><del>-        skinny_device_t *device;
</del><ins>+        char *sql;
+        skinny_profile_t *profile;
+        assert(listener-&gt;profile);
+        profile = listener-&gt;profile;
+
</ins><span class="cx">         switch_event_create_subclass(&amp;event, event_id, subclass_name);
</span><span class="cx">         switch_assert(event);
</span><del>-        if(listener-&gt;device) {
-                device = listener-&gt;device;
-                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;Skinny-Device-Name&quot;, switch_str_nil(device-&gt;deviceName));
-                switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-User-Id&quot;, &quot;%d&quot;, device-&gt;userId);
-                switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-Instance&quot;, &quot;%d&quot;, device-&gt;instance);
-                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;Skinny-IP&quot;, inet_ntoa(device-&gt;ip));
-                switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-Device-Type&quot;, &quot;%d&quot;, device-&gt;deviceType);
-                switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-Max-Streams&quot;, &quot;%d&quot;, device-&gt;maxStreams);
-                switch_event_add_header(       event, SWITCH_STACK_BOTTOM, &quot;Skinny-Port&quot;, &quot;%d&quot;, device-&gt;port);
-                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, &quot;Skinny-Codecs&quot;, device-&gt;codec_string);
</del><ins>+        if ((sql = switch_mprintf(&quot;select * from skinny_devices where device_name='%s'&quot;, listener-&gt;device_name))) {
+                skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, sql, skinny_device_event_callback, event);
+                switch_safe_free(sql);
</ins><span class="cx">         }
</span><ins>+
</ins><span class="cx">         *ev = event;
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="lines">@@ -1044,20 +1060,15 @@
</span><span class="cx"> {
</span><span class="cx">         switch_status_t status = SWITCH_STATUS_FALSE;
</span><span class="cx">         skinny_message_t *message;
</span><del>-        skinny_device_t *device;
</del><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><span class="cx">         switch_xml_t xroot, xdomain, xgroup, xuser, xskinny, xlines, xline, xspeeddials, xspeeddial;
</span><ins>+        char *sql;
</ins><span class="cx">         assert(listener-&gt;profile);
</span><span class="cx">         profile = listener-&gt;profile;
</span><span class="cx"> 
</span><del>-        skinny_execute_sql(profile, &quot;select * from skinny_devices&quot;, profile-&gt;listener_mutex);
-        skinny_execute_sql_callback(profile, profile-&gt;listener_mutex,
-                &quot;select * from skinny_devices&quot;, NULL, profile);
-
-
-        if(listener-&gt;device) {
</del><ins>+        if(!zstr(listener-&gt;device_name)) {
</ins><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
</span><span class="cx">                         &quot;A device is already registred on this listener.\n&quot;);
</span><span class="cx">                 message = switch_core_alloc(listener-&gt;pool, 12+sizeof(message-&gt;data.reg_rej));
</span><span class="lines">@@ -1067,65 +1078,87 @@
</span><span class="cx">                 skinny_send_reply(listener, message);
</span><span class="cx">                 return SWITCH_STATUS_FALSE;
</span><span class="cx">         }
</span><del>-        /* Initialize device */
-        device = switch_core_alloc(listener-&gt;pool, sizeof(skinny_device_t));
-        memcpy(device-&gt;deviceName, request-&gt;data.reg.deviceName, 16);
-        device-&gt;userId = request-&gt;data.reg.userId;
-        device-&gt;instance = request-&gt;data.reg.instance;
-        device-&gt;ip = request-&gt;data.reg.ip;
-        device-&gt;deviceType = request-&gt;data.reg.deviceType;
-        device-&gt;maxStreams = request-&gt;data.reg.maxStreams;
-        device-&gt;codec_string = realloc(device-&gt;codec_string, 1);
-        device-&gt;codec_string[0] = '\0';
-        device-&gt;line_last = 0;
</del><span class="cx"> 
</span><span class="cx">         /* Check directory */
</span><span class="cx">         skinny_device_event(listener, &amp;params, SWITCH_EVENT_REQUEST_PARAMS, SWITCH_EVENT_SUBCLASS_ANY);
</span><span class="cx">         switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, &quot;action&quot;, &quot;skinny-auth&quot;);
</span><span class="cx"> 
</span><del>-        if (switch_xml_locate_user(&quot;id&quot;, device-&gt;deviceName, profile-&gt;domain, &quot;&quot;, &amp;xroot, &amp;xdomain, &amp;xuser, &amp;xgroup, params) != SWITCH_STATUS_SUCCESS) {
</del><ins>+        if (switch_xml_locate_user(&quot;id&quot;, request-&gt;data.reg.deviceName, profile-&gt;domain, &quot;&quot;, &amp;xroot, &amp;xdomain, &amp;xuser, &amp;xgroup, params) != SWITCH_STATUS_SUCCESS) {
</ins><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, &quot;Can't find device [%s@%s]\n&quot;
</span><span class="cx">                                           &quot;You must define a domain called '%s' in your directory and add a user with id=\&quot;%s\&quot;.\n&quot;
</span><del>-                                          , device-&gt;deviceName, profile-&gt;domain, profile-&gt;domain, device-&gt;deviceName);
</del><ins>+                                          , request-&gt;data.reg.deviceName, profile-&gt;domain, profile-&gt;domain, request-&gt;data.reg.deviceName);
</ins><span class="cx">                 message = switch_core_alloc(listener-&gt;pool, 12+sizeof(message-&gt;data.reg_rej));
</span><span class="cx">                 message-&gt;type = REGISTER_REJ_MESSAGE;
</span><span class="cx">                 message-&gt;length = 4 + sizeof(message-&gt;data.reg_rej);
</span><span class="cx">                 strcpy(message-&gt;data.reg_rej.error, &quot;Device not found&quot;);
</span><span class="cx">                 skinny_send_reply(listener, message);
</span><del>-                return SWITCH_STATUS_FALSE;
</del><ins>+                status =  SWITCH_STATUS_FALSE;
</ins><span class="cx">                 goto end;
</span><span class="cx">         }
</span><ins>+
+        if ((sql = switch_mprintf(
+                        &quot;INSERT INTO skinny_devices &quot;
+                                &quot;(device_name, user_id, instance, ip, device_type, max_streams, codec_string) &quot;
+                                &quot;VALUES ('%s','%d','%d', '%s', '%d', '%d', '%s')&quot;,
+                        request-&gt;data.reg.deviceName,
+                        request-&gt;data.reg.userId,
+                        request-&gt;data.reg.instance,
+                        inet_ntoa(request-&gt;data.reg.ip),
+                        request-&gt;data.reg.deviceType,
+                        request-&gt;data.reg.maxStreams,
+                        &quot;&quot; /* codec_string */
+                        ))) {
+                skinny_execute_sql(profile, sql, profile-&gt;listener_mutex);
+                switch_safe_free(sql);
+        }
+
+
+        strcpy(listener-&gt;device_name, request-&gt;data.reg.deviceName);
+
</ins><span class="cx">         xskinny = switch_xml_child(xuser, &quot;skinny&quot;);
</span><span class="cx">         if (xskinny) {
</span><span class="cx">                 xlines = switch_xml_child(xskinny, &quot;lines&quot;);
</span><span class="cx">                 if (xlines) {
</span><span class="cx">                         for (xline = switch_xml_child(xlines, &quot;line&quot;); xline; xline = xline-&gt;next) {
</span><del>-                                //TODO const char *position = switch_xml_attr_soft(xline, &quot;position&quot;);
</del><ins>+                                const char *position = switch_xml_attr_soft(xline, &quot;position&quot;);
</ins><span class="cx">                                 const char *name = switch_xml_attr_soft(xline, &quot;name&quot;);
</span><span class="cx">                                 const char *shortname = switch_xml_attr_soft(xline, &quot;shortname&quot;);
</span><span class="cx">                                 const char *displayname = switch_xml_attr_soft(xline, &quot;displayname&quot;);
</span><del>-                                //TODO device-&gt;line[device-&gt;line_last].device = *device;
-                                strcpy(device-&gt;line[device-&gt;line_last].name, name);
-                                strcpy(device-&gt;line[device-&gt;line_last].shortname, shortname);
-                                strcpy(device-&gt;line[device-&gt;line_last].displayname, displayname);
-                                device-&gt;line_last++;
</del><ins>+                                if ((sql = switch_mprintf(
+                                                &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;,
+                                                request-&gt;data.reg.deviceName,
+                                                position,
+                                                name,
+                                                shortname,
+                                                displayname))) {
+                                        skinny_execute_sql(profile, sql, profile-&gt;listener_mutex);
+                                        switch_safe_free(sql);
+                                }
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">                 xspeeddials = switch_xml_child(xskinny, &quot;speed-dials&quot;);
</span><span class="cx">                 if (xspeeddials) {
</span><span class="cx">                         for (xspeeddial = switch_xml_child(xspeeddials, &quot;speed-dial&quot;); xspeeddial; xspeeddial = xspeeddial-&gt;next) {
</span><del>-                                //TODO const char *position = switch_xml_attr_soft(xspeeddial, &quot;position&quot;);
</del><ins>+                                const char *position = switch_xml_attr_soft(xspeeddial, &quot;position&quot;);
</ins><span class="cx">                                 const char *line = switch_xml_attr_soft(xspeeddial, &quot;line&quot;);
</span><span class="cx">                                 const char *label = switch_xml_attr_soft(xspeeddial, &quot;label&quot;);
</span><del>-                                //TODO device-&gt;speeddial[device-&gt;speeddial_last].device = *device;
-                                strcpy(device-&gt;speeddial[device-&gt;speeddial_last].line, line);
-                                strcpy(device-&gt;speeddial[device-&gt;speeddial_last].label, label);
-                                device-&gt;speeddial_last++;
</del><ins>+                                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);
+                                }
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        listener-&gt;device = device;
</del><span class="cx">         status = SWITCH_STATUS_SUCCESS;
</span><span class="cx"> 
</span><span class="cx">         /* Reply with RegisterAckMessage */
</span><span class="lines">@@ -1159,9 +1192,11 @@
</span><span class="cx"> 
</span><span class="cx"> static switch_status_t skinny_handle_capabilities_response(listener_t *listener, skinny_message_t *request)
</span><span class="cx"> {
</span><del>-        skinny_device_t *device = listener-&gt;device;
</del><span class="cx">         uint32_t i = 0;
</span><span class="cx">         uint32_t n = 0;
</span><ins>+        char *codec_order[SWITCH_MAX_CODECS];
+        char *codec_string;
+        
</ins><span class="cx">         size_t string_len, string_pos, pos;
</span><span class="cx"> 
</span><span class="cx">         n = request-&gt;data.cap_res.count;
</span><span class="lines">@@ -1171,60 +1206,91 @@
</span><span class="cx">         string_len = -1;
</span><span class="cx">         for (i = 0; i &lt; n; i++) {
</span><span class="cx">                 char *codec = skinny_codec2string(request-&gt;data.cap_res.caps[i].codec);
</span><del>-                device-&gt;codec_order[i] = codec;
</del><ins>+                codec_order[i] = codec;
</ins><span class="cx">                 string_len += strlen(codec)+1;
</span><span class="cx">         }
</span><span class="cx">         i = 0;
</span><span class="cx">         pos = 0;
</span><del>-        device-&gt;codec_string = realloc(device-&gt;codec_string, string_len+1);
</del><ins>+        codec_string = switch_core_alloc(listener-&gt;pool, string_len+1);
</ins><span class="cx">         for (string_pos = 0; string_pos &lt; string_len; string_pos++) {
</span><del>-                char *codec = device-&gt;codec_order[i];
</del><ins>+                char *codec = codec_order[i];
</ins><span class="cx">                 switch_assert(i &lt; n);
</span><span class="cx">                 if(pos == strlen(codec)) {
</span><del>-                        device-&gt;codec_string[string_pos] = ',';
</del><ins>+                        codec_string[string_pos] = ',';
</ins><span class="cx">                         i++;
</span><span class="cx">                         pos = 0;
</span><span class="cx">                 } else {
</span><del>-                        device-&gt;codec_string[string_pos] = codec[pos++];
</del><ins>+                        codec_string[string_pos] = codec[pos++];
</ins><span class="cx">                 }
</span><span class="cx">         }
</span><del>-        device-&gt;codec_string[string_len] = '\0';
-        device-&gt;codec_order_last = n;
</del><ins>+        codec_string[string_len] = '\0';
+        /* TODO SQL update */
</ins><span class="cx">         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
</span><del>-                &quot;Codecs %s supported.\n&quot;, device-&gt;codec_string);
</del><ins>+                &quot;Codecs %s supported.\n&quot;, codec_string);
</ins><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static switch_status_t skinny_handle_port_message(listener_t *listener, skinny_message_t *request)
</span><span class="cx"> {
</span><del>-        skinny_device_t *device = listener-&gt;device;
</del><ins>+        char *sql;
+        skinny_profile_t *profile;
</ins><span class="cx"> 
</span><del>-        device-&gt;port = request-&gt;data.as_uint16;
</del><ins>+        switch_assert(listener-&gt;profile);
+        switch_assert(listener-&gt;device_name);
+
+        profile = listener-&gt;profile;
+
+        if ((sql = switch_mprintf(
+                        &quot;update skinny_devices set port='%d' where device_name='%s'&quot;,
+                        request-&gt;data.as_uint16,
+                        listener-&gt;device_name
+                        ))) {
+                skinny_execute_sql(profile, sql, profile-&gt;listener_mutex);
+                switch_safe_free(sql);
+        }
</ins><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static int skinny_line_stat_request_callback(void *pArg, int argc, char **argv, char **columnNames)
+
+{
+        skinny_message_t *message = pArg;
+
+        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]);
+
+        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><del>-        skinny_device_t *device = listener-&gt;device;
</del><span class="cx">         skinny_message_t *message;
</span><del>-        uint32_t i = 0;
</del><ins>+        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;
+
+
</ins><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>-        i = request-&gt;data.line_req.number;
-        if(i &gt; 0 &amp;&amp; i &lt;= device-&gt;line_last) {
-                message-&gt;data.line_res.number = i;
-                strcpy(message-&gt;data.line_res.name, device-&gt;line[i-1].name);
-                strcpy(message-&gt;data.line_res.shortname, device-&gt;line[i-1].shortname);
-                strcpy(message-&gt;data.line_res.displayname, device-&gt;line[i-1].displayname);
-        } else {
-                message-&gt;data.line_res.number = i;
-                strcpy(message-&gt;data.line_res.name, &quot;&quot;);
-                strcpy(message-&gt;data.line_res.shortname, &quot;&quot;);
-                strcpy(message-&gt;data.line_res.displayname, &quot;&quot;);
</del><ins>+        message-&gt;data.line_res.number = request-&gt;data.line_req.number;
+
+        if ((sql = switch_mprintf(
+                        &quot;select * from skinny_lines where device_name='%s' and line_position='%d'&quot;,
+                        listener-&gt;device_name,
+                        request-&gt;data.line_req.number
+                        ))) {
+                skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, sql, skinny_line_stat_request_callback, message);
+                switch_safe_free(sql);
</ins><span class="cx">         }
</span><span class="cx">         skinny_send_reply(listener, message);
</span><ins>+
</ins><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1260,7 +1326,7 @@
</span><span class="cx"> {
</span><span class="cx">         switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,
</span><span class="cx">                 &quot;Received message (type=%x,length=%d).\n&quot;, request-&gt;type, request-&gt;length);
</span><del>-        if(!listener-&gt;device &amp;&amp; request-&gt;type != REGISTER_MESSAGE) {
</del><ins>+        if(zstr(listener-&gt;device_name) &amp;&amp; request-&gt;type != REGISTER_MESSAGE) {
</ins><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
</span><span class="cx">                         &quot;Device should send a register message first.\n&quot;);
</span><span class="cx">                 return SWITCH_STATUS_FALSE;
</span><span class="lines">@@ -1375,60 +1441,47 @@
</span><span class="cx">         /* TODO */
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static listener_t *find_listener(char *device_name)
</del><ins>+static int dump_device_callback(void *pArg, int argc, char **argv, char **columnNames)
</ins><span class="cx"> {
</span><del>-        switch_hash_index_t *hi;
-        void *val;
-        skinny_profile_t *profile;
-        listener_t *l, *r = NULL;
-        skinny_device_t *device;
-        
-        /* walk listeners */
-        for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) {
-                switch_hash_this(hi, NULL, NULL, &amp;val);
-                profile = (skinny_profile_t *) val;
</del><ins>+        switch_stream_handle_t *stream = (switch_stream_handle_t *) pArg;
</ins><span class="cx"> 
</span><del>-                switch_mutex_lock(profile-&gt;listener_mutex);
-                for (l = profile-&gt;listeners; l; l = l-&gt;next) {
-                        if (l-&gt;device) {
-                                device = l-&gt;device;
-                                if(!strcasecmp(device-&gt;deviceName,device_name)) {
-                                        if (switch_thread_rwlock_tryrdlock(l-&gt;rwlock) == SWITCH_STATUS_SUCCESS) {
-                                                r = l;
-                                        }
-                                        break;
-                                }
-                        }
-                }
-                switch_mutex_unlock(profile-&gt;listener_mutex);
-                if(r) {
-                        break;
-                }
-        }
-        return r;
</del><ins>+        char *device_name = argv[0];
+        char *user_id = argv[1];
+        char *instance = argv[2];
+        char *ip = argv[3];
+        char *device_type = argv[4];
+        char *max_streams = argv[5];
+        char *port = argv[6];
+        char *codec_string = argv[7];
+
+        const char *line = &quot;=================================================================================================&quot;;
+        stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
+        stream-&gt;write_function(stream, &quot;DeviceName    \t%s\n&quot;, switch_str_nil(device_name));
+        stream-&gt;write_function(stream, &quot;UserId        \t%s\n&quot;, user_id);
+        stream-&gt;write_function(stream, &quot;Instance      \t%s\n&quot;, instance);
+        stream-&gt;write_function(stream, &quot;IP            \t%s\n&quot;, ip);
+        stream-&gt;write_function(stream, &quot;DeviceType    \t%s\n&quot;, device_type);
+        stream-&gt;write_function(stream, &quot;MaxStreams    \t%s\n&quot;, max_streams);
+        stream-&gt;write_function(stream, &quot;Port          \t%s\n&quot;, port);
+        stream-&gt;write_function(stream, &quot;Codecs        \t%s\n&quot;, codec_string);
+        stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
+
+        return 0;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-static switch_status_t dump_listener(listener_t *listener, void *pvt)
</del><ins>+static switch_status_t dump_device(skinny_profile_t *profile, const char *device_name, switch_stream_handle_t *stream)
</ins><span class="cx"> {
</span><del>-        switch_stream_handle_t *stream = (switch_stream_handle_t *) pvt;
-        const char *line = &quot;=================================================================================================&quot;;
-        skinny_device_t *device;
-        if(listener-&gt;device) {
-                device = listener-&gt;device;
-                stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
-                stream-&gt;write_function(stream, &quot;DeviceName    \t%s\n&quot;, switch_str_nil(device-&gt;deviceName));
-                stream-&gt;write_function(stream, &quot;UserId        \t%d\n&quot;, device-&gt;userId);
-                stream-&gt;write_function(stream, &quot;Instance      \t%d\n&quot;, device-&gt;instance);
-                stream-&gt;write_function(stream, &quot;IP            \t%s\n&quot;, inet_ntoa(device-&gt;ip));
-                stream-&gt;write_function(stream, &quot;DeviceType    \t%d\n&quot;, device-&gt;deviceType);
-                stream-&gt;write_function(stream, &quot;MaxStreams    \t%d\n&quot;, device-&gt;maxStreams);
-                stream-&gt;write_function(stream, &quot;Port          \t%d\n&quot;, device-&gt;port);
-                stream-&gt;write_function(stream, &quot;Codecs        \t%s\n&quot;, device-&gt;codec_string);
-                stream-&gt;write_function(stream, &quot;%s\n&quot;, line);
</del><ins>+        char *sql;
+        if ((sql = switch_mprintf(&quot;select * from skinny_devices where device_name LIKE '%s'&quot;,
+                        device_name))) {
+                skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, sql, dump_device_callback, stream);
+                switch_safe_free(sql);
</ins><span class="cx">         }
</span><ins>+
</ins><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> static void close_socket(switch_socket_t **sock)
</span><span class="cx"> {
</span><span class="cx">         /* TODO
</span><span class="lines">@@ -1626,7 +1679,7 @@
</span><span class="cx">                 rv = switch_socket_listen(profile-&gt;sock, 5);
</span><span class="cx">                 if (rv)
</span><span class="cx">                         goto sock_fail;
</span><del>-                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, &quot;Socket up listening on %s:%u\n&quot;, profile-&gt;ip, profile-&gt;port);
</del><ins>+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, &quot;Socket up listening on %s:%u\n&quot;, profile-&gt;ip, profile-&gt;port);
</ins><span class="cx"> 
</span><span class="cx">                 break;
</span><span class="cx">           sock_fail:
</span><span class="lines">@@ -1669,7 +1722,7 @@
</span><span class="cx">                 listener-&gt;sock = inbound_socket;
</span><span class="cx">                 listener-&gt;pool = listener_pool;
</span><span class="cx">                 listener_pool = NULL;
</span><del>-                listener-&gt;device = NULL;
</del><ins>+                strcpy(listener-&gt;device_name, &quot;&quot;);
</ins><span class="cx">                 listener-&gt;profile = profile;
</span><span class="cx"> 
</span><span class="cx">                 switch_mutex_init(&amp;listener-&gt;flag_mutex, SWITCH_MUTEX_NESTED, listener-&gt;pool);
</span><span class="lines">@@ -1827,12 +1880,12 @@
</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);
</span><span class="cx">                                         switch_odbc_handle_exec(profile-&gt;master_odbc, lines_sql, NULL);
</span><del>-                                        switch_odbc_handle_exec(profile-&gt;master_odbc, speed_sql, NULL);
</del><ins>+                                        switch_odbc_handle_exec(profile-&gt;master_odbc, speeddials_sql, 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><span class="cx">                                                 switch_core_db_test_reactive(db, &quot;select * from skinny_lines&quot;, NULL, lines_sql);
</span><del>-                                                switch_core_db_test_reactive(db, &quot;select * from skinny_speeddials&quot;, NULL, speed_sql);
</del><ins>+                                                switch_core_db_test_reactive(db, &quot;select * from skinny_speeddials&quot;, NULL, speeddials_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">@@ -1853,23 +1906,27 @@
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static switch_status_t cmd_device(char **argv, int argc, switch_stream_handle_t *stream)
</del><ins>+static switch_status_t cmd_status_profile(const char *profile_name, switch_stream_handle_t *stream)
</ins><span class="cx"> {
</span><del>-        listener_t *listener;
-        if (argc != 1) {
-                stream-&gt;write_function(stream, &quot;Invalid Args!\n&quot;);
-                return SWITCH_STATUS_SUCCESS;
</del><ins>+        skinny_profile_t *profile;
+        if ((profile = get_profile(profile_name))) {
+                dump_profile(profile, stream);
+        } else {
+                stream-&gt;write_function(stream, &quot;Profile not found!\n&quot;);
</ins><span class="cx">         }
</span><del>-        
-        if (argv[0] &amp;&amp; !strcasecmp(argv[0], &quot;*&quot;)) {
-                walk_listeners(dump_listener, stream);
</del><ins>+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t cmd_status_profile_device(const char *profile_name, const char *device_name, switch_stream_handle_t *stream)
+{
+        skinny_profile_t *profile;
+        if ((profile = get_profile(profile_name))) {
+                dump_device(profile, device_name, stream);
</ins><span class="cx">         } else {
</span><del>-                listener=find_listener(argv[0]);
-                if(listener) {
-                        dump_listener(listener, stream);
-                }
</del><ins>+                stream-&gt;write_function(stream, &quot;Profile not found!\n&quot;);
</ins><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1879,12 +1936,11 @@
</span><span class="cx">         int argc = 0;
</span><span class="cx">         char *mycmd = NULL;
</span><span class="cx">         switch_status_t status = SWITCH_STATUS_SUCCESS;
</span><del>-        skinny_command_t func = NULL;
</del><span class="cx">         const char *usage_string = &quot;USAGE:\n&quot;
</span><span class="cx">                 &quot;--------------------------------------------------------------------------------\n&quot;
</span><span class="cx">                 &quot;skinny help\n&quot;
</span><del>-                &quot;skinny device *\n&quot;
-                &quot;skinny device &lt;device_name&gt;\n&quot;
</del><ins>+                &quot;skinny status profile &lt;profile_name&gt;\n&quot;
+                &quot;skinny status profile &lt;profile_name&gt; device &lt;device_name&gt;\n&quot;
</ins><span class="cx">                 &quot;--------------------------------------------------------------------------------\n&quot;;
</span><span class="cx">         if (session) {
</span><span class="cx">                 return SWITCH_STATUS_FALSE;
</span><span class="lines">@@ -1905,20 +1961,18 @@
</span><span class="cx">                 goto done;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (!strcasecmp(argv[0], &quot;device&quot;)) {
-                func = cmd_device;
</del><ins>+        if (argc == 3 &amp;&amp; !strcasecmp(argv[0], &quot;status&quot;) &amp;&amp; !strcasecmp(argv[1], &quot;profile&quot;)) {
+                status = cmd_status_profile(argv[2], stream);
+        } else if (argc == 5 &amp;&amp; !strcasecmp(argv[0], &quot;status&quot;) &amp;&amp; !strcasecmp(argv[1], &quot;profile&quot;) &amp;&amp; !strcasecmp(argv[3], &quot;device&quot;)) {
+                status = cmd_status_profile_device(argv[2], argv[4], stream);
</ins><span class="cx">         } else if (!strcasecmp(argv[0], &quot;help&quot;)) {
</span><span class="cx">                 stream-&gt;write_function(stream, &quot;%s&quot;, usage_string);
</span><span class="cx">                 goto done;
</span><del>-        }
-        
-        if (func) {
-                status = func(&amp;argv[1], argc - 1, stream);
</del><span class="cx">         } else {
</span><span class="cx">                 stream-&gt;write_function(stream, &quot;Unknown Command [%s]\n&quot;, argv[0]);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-  done:
</del><ins>+done:
</ins><span class="cx">         switch_safe_free(mycmd);
</span><span class="cx">         return status;
</span><span class="cx"> }
</span><span class="lines">@@ -1930,7 +1984,7 @@
</span><span class="cx">         }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-static switch_status_t skinny_list_devices(const char *line, const char *cursor, switch_console_callback_match_t **matches)
</del><ins>+static switch_status_t skinny_list_profiles(const char *line, const char *cursor, switch_console_callback_match_t **matches)
</ins><span class="cx"> {
</span><span class="cx">         switch_console_callback_match_t *my_matches = NULL;
</span><span class="cx">         switch_status_t status = SWITCH_STATUS_FALSE;
</span><span class="lines">@@ -1938,22 +1992,56 @@
</span><span class="cx">         void *val;
</span><span class="cx">         skinny_profile_t *profile;
</span><span class="cx">         
</span><del>-        listener_t *l;
-        skinny_device_t *device;
-
-        /* walk listeners */
</del><ins>+        /* walk profiles */
</ins><span class="cx">         for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) {
</span><span class="cx">                 switch_hash_this(hi, NULL, NULL, &amp;val);
</span><span class="cx">                 profile = (skinny_profile_t *) val;
</span><span class="cx"> 
</span><del>-                switch_mutex_lock(profile-&gt;listener_mutex);
-                for (l = profile-&gt;listeners; l; l = l-&gt;next) {
-                        if(l-&gt;device) {
-                                device = l-&gt;device;
-                                switch_console_push_match(&amp;my_matches, device-&gt;deviceName);
-                        }
</del><ins>+                switch_console_push_match(&amp;my_matches, profile-&gt;name);
+        }
+        
+        if (my_matches) {
+                *matches = my_matches;
+                status = SWITCH_STATUS_SUCCESS;
+        }
+        
+        return status;
+}
+
+static int skinny_list_devices_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+        switch_console_callback_match_t *my_matches = (switch_console_callback_match_t *) pArg;
+
+        char *device_name = argv[0];
+        switch_console_push_match(&amp;my_matches, device_name);
+        pArg = my_matches;
+        return 0;
+}
+
+static switch_status_t skinny_list_devices(const char *line, const char *cursor, switch_console_callback_match_t **matches)
+{
+        switch_console_callback_match_t *my_matches = NULL;
+        switch_status_t status = SWITCH_STATUS_FALSE;
+        skinny_profile_t *profile;
+        char *sql;
+
+        char *myline;
+        char *argv[1024] = { 0 };
+        int argc = 0;
+
+        if (!(myline = strdup(line))) {
+                status = SWITCH_STATUS_MEMERR;
+                return status;
+        }
+        if (!(argc = switch_separate_string(myline, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) || argc != 5) {
+                return status;
+        }
+
+        if((profile = get_profile(argv[3]))) {
+                if ((sql = switch_mprintf(&quot;select device_name from skinny_devices&quot;))) {
+                        skinny_execute_sql_callback(profile, profile-&gt;listener_mutex, sql, skinny_list_devices_callback, my_matches);
+                        switch_safe_free(sql);
</ins><span class="cx">                 }
</span><del>-                switch_mutex_unlock(profile-&gt;listener_mutex);
</del><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         if (my_matches) {
</span><span class="lines">@@ -2006,9 +2094,10 @@
</span><span class="cx"> 
</span><span class="cx">         SWITCH_ADD_API(api_interface, &quot;skinny&quot;, &quot;Skinny Controls&quot;, skinny_function, &quot;&lt;cmd&gt; &lt;args&gt;&quot;);
</span><span class="cx">         switch_console_set_complete(&quot;add skinny help&quot;);
</span><del>-        switch_console_set_complete(&quot;add skinny device *&quot;);
-        switch_console_set_complete(&quot;add skinny device ::skinny::list_devices&quot;);
</del><ins>+        switch_console_set_complete(&quot;add skinny status profile ::skinny::list_profiles&quot;);
+        switch_console_set_complete(&quot;add skinny status profile ::skinny::list_profiles device ::skinny::list_devices&quot;);
</ins><span class="cx"> 
</span><ins>+        switch_console_add_complete_func(&quot;::skinny::list_profiles&quot;, skinny_list_profiles);
</ins><span class="cx">         switch_console_add_complete_func(&quot;::skinny::list_devices&quot;, skinny_list_devices);
</span><span class="cx">         /* indicate that the module should continue to be loaded */
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span></span></pre></div>
<a id="freeswitchtrunksrcmodendpointsmod_skinnytestskinnypl"></a>
<div class="modfile"><h4>Modified: freeswitch/trunk/src/mod/endpoints/mod_skinny/test-skinny.pl (16761 => 16762)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/trunk/src/mod/endpoints/mod_skinny/test-skinny.pl        2010-02-24 11:59:41 UTC (rev 16761)
+++ freeswitch/trunk/src/mod/endpoints/mod_skinny/test-skinny.pl        2010-02-24 11:59:49 UTC (rev 16762)
</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; '127.0.0.1',
</del><ins>+                PeerAddr =&gt; '192.168.0.6',
</ins><span class="cx">                 PeerPort =&gt; 2000,
</span><span class="cx">                 );
</span><span class="cx"> }
</span><span class="lines">@@ -96,9 +96,9 @@
</span><span class="cx">         pack(&quot;V&quot;, 2
</span><span class="cx">         ));
</span><span class="cx"> 
</span><del>-
-skinny_sleep(3);
-skinny_send(0x0000, # keepalive
-        &quot;&quot;);
-skinny_recv(); # keepaliveack
-
</del><ins>+while(1) {
+        skinny_sleep(20);
+        skinny_send(0x0000, # keepalive
+                &quot;&quot;);
+        skinny_recv(); # keepaliveack
+}
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>

</body>
</html>