<!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][16915] </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=16915">16915</a></dd>
<dt>Author</dt> <dd>rupa</dd>
<dt>Date</dt> <dd>2010-03-05 10:51:03 -0600 (Fri, 05 Mar 2010)</dd>
</dl>
<h3>Log Message</h3>
<pre>mod_limit -> switch_limit*,mod_hash,mod_db
branch: rupa_limit</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#freeswitchbranchesrupa_limitMakefileam">freeswitch/branches/rupa_limit/Makefile.am</a></li>
<li><a href="#freeswitchbranchesrupa_limitbuildmodulesconfin">freeswitch/branches/rupa_limit/build/modules.conf.in</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcincludeswitchh">freeswitch/branches/rupa_limit/src/include/switch.h</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcincludeswitch_loadable_moduleh">freeswitch/branches/rupa_limit/src/include/switch_loadable_module.h</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcincludeswitch_module_interfacesh">freeswitch/branches/rupa_limit/src/include/switch_module_interfaces.h</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcincludeswitch_typesh">freeswitch/branches/rupa_limit/src/include/switch_types.h</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_commandsmod_commandsc">freeswitch/branches/rupa_limit/src/mod/applications/mod_commands/mod_commands.c</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_dptoolsmod_dptoolsc">freeswitch/branches/rupa_limit/src/mod/applications/mod_dptools/mod_dptools.c</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcswitch_corec">freeswitch/branches/rupa_limit/src/switch_core.c</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcswitch_loadable_modulec">freeswitch/branches/rupa_limit/src/switch_loadable_module.c</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li>freeswitch/branches/rupa_limit/src/mod/applications/mod_db/</li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbMakefile">freeswitch/branches/rupa_limit/src/mod/applications/mod_db/Makefile</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbmod_db2008vcproj">freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.2008.vcproj</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbmod_dbc">freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.c</a></li>
<li>freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/</li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashMakefile">freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/Makefile</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashmod_hash2008vcproj">freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.2008.vcproj</a></li>
<li><a href="#freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashmod_hashc">freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.c</a></li>
</ul>
<h3>Removed Paths</h3>
<ul>
<li>freeswitch/branches/rupa_limit/src/mod/applications/mod_limit/</li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchbranchesrupa_limitMakefileam"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/Makefile.am (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/Makefile.am        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/Makefile.am        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -171,6 +171,7 @@
</span><span class="cx">         libs/libteletone/src/libteletone_detect.h \
</span><span class="cx">         libs/libteletone/src/libteletone_generate.h \
</span><span class="cx">         libs/libteletone/src/libteletone.h \
</span><ins>+        src/include/switch_limit.h \
</ins><span class="cx">         src/include/switch_odbc.h
</span><span class="cx">
</span><span class="cx"> nodist_libfreeswitch_la_SOURCES = \
</span><span class="lines">@@ -225,6 +226,7 @@
</span><span class="cx">         src/switch_config.c \
</span><span class="cx">         src/switch_time.c \
</span><span class="cx">         src/switch_odbc.c \
</span><ins>+        src/switch_limit.c \
</ins><span class="cx">         src/g711.c \
</span><span class="cx">         src/switch_pcm.c \
</span><span class="cx">         libs/stfu/stfu.c \
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitbuildmodulesconfin"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/build/modules.conf.in (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/build/modules.conf.in        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/build/modules.conf.in        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -9,10 +9,11 @@
</span><span class="cx"> applications/mod_fifo
</span><span class="cx"> #applications/mod_fax
</span><span class="cx"> #applications/mod_curl
</span><ins>+applications/mod_db
+applications/mod_hash
</ins><span class="cx"> applications/mod_voicemail
</span><span class="cx"> #applications/mod_directory
</span><span class="cx"> #applications/mod_lcr
</span><del>-applications/mod_limit
</del><span class="cx"> applications/mod_expr
</span><span class="cx"> applications/mod_esf
</span><span class="cx"> #applications/mod_easyroute
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcincludeswitchh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/include/switch.h (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/include/switch.h        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/include/switch.h        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -131,6 +131,7 @@
</span><span class="cx"> #include "switch_config.h"
</span><span class="cx"> #include "switch_nat.h"
</span><span class="cx"> #include "switch_odbc.h"
</span><ins>+#include "switch_limit.h"
</ins><span class="cx">
</span><span class="cx"> #include <libteletone.h>
</span><span class="cx">
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcincludeswitch_loadable_moduleh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/include/switch_loadable_module.h (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/include/switch_loadable_module.h        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/include/switch_loadable_module.h        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -81,6 +81,8 @@
</span><span class="cx">         switch_asr_interface_t *asr_interface;
</span><span class="cx">         /*! the table of management interfaces the module has implmented */
</span><span class="cx">         switch_management_interface_t *management_interface;
</span><ins>+        /*! the table of limit interfaces the module has implmented */
+        switch_limit_interface_t *limit_interface;
</ins><span class="cx">         switch_thread_rwlock_t *rwlock;
</span><span class="cx">         int refs;
</span><span class="cx">         switch_memory_pool_t *pool;
</span><span class="lines">@@ -205,6 +207,13 @@
</span><span class="cx"> SWITCH_DECLARE(switch_management_interface_t *) switch_loadable_module_get_management_interface(const char *relative_oid);
</span><span class="cx">
</span><span class="cx"> /*!
</span><ins>+ \brief Retrieve the limit interface by it's registered name
+ \param name the name of the limit interface
+ \return the desired limit interface
+ */
+SWITCH_DECLARE(switch_limit_interface_t *) switch_loadable_module_get_limit_interface(const char *name);
+
+/*!
</ins><span class="cx"> \brief Retrieve the list of loaded codecs into an array
</span><span class="cx"> \param array the array to populate
</span><span class="cx"> \param arraylen the max size in elements of the array
</span><span class="lines">@@ -315,6 +324,18 @@
</span><span class="cx">         break; \
</span><span class="cx">         }
</span><span class="cx">
</span><ins>+#define SWITCH_ADD_LIMIT(limit_int, int_name, incrptr, releaseptr, usageptr, resetptr, statusptr) \
+        for (;;) { \
+        limit_int = (switch_limit_interface_t *)switch_loadable_module_create_interface(*module_interface, SWITCH_LIMIT_INTERFACE); \
+        limit_int->incr = incrptr; \
+        limit_int->release = releaseptr; \
+        limit_int->usage = usageptr; \
+        limit_int->reset = resetptr; \
+        limit_int->status = statusptr; \
+        limit_int->interface_name = int_name; \
+        break; \
+        }
+
</ins><span class="cx"> SWITCH_DECLARE(uint32_t) switch_core_codec_next_id(void);
</span><span class="cx">
</span><span class="cx"> #define SWITCH_ADD_CODEC(codec_int, int_name) \
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcincludeswitch_module_interfacesh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/include/switch_module_interfaces.h (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/include/switch_module_interfaces.h        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/include/switch_module_interfaces.h        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -512,6 +512,28 @@
</span><span class="cx">         struct switch_management_interface *next;
</span><span class="cx"> };
</span><span class="cx">
</span><ins>+/*! \brief Abstract interface to a limit module */
+struct switch_limit_interface {
+        /*! name of the interface */
+        const char *interface_name;
+        /*! increment */
+        switch_status_t (*incr) (switch_core_session_t *session, const char *realm, const char *resource, const int max, const int interval);
+        /*! release */
+        switch_status_t (*release) (switch_core_session_t *session, const char *realm, const char *resource);
+        /*! usage for resource */
+        int (*usage) (const char *realm, const char *resource);
+        /*! reset counters */
+        switch_status_t (*reset) (void);
+        /*! freform status */
+        char * (*status) (void);
+        /* internal */
+        switch_thread_rwlock_t *rwlock;
+        int refs;
+        switch_mutex_t *reflock;
+        switch_loadable_module_interface_t *parent;
+        struct switch_limit_interface *next;
+};
+
</ins><span class="cx"> /*! \brief Abstract interface to a directory module */
</span><span class="cx"> struct switch_directory_interface {
</span><span class="cx">         /*! the name of the interface */
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcincludeswitch_typesh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/include/switch_types.h (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/include/switch_types.h        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/include/switch_types.h        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -264,7 +264,8 @@
</span><span class="cx">         SWITCH_CHAT_INTERFACE,
</span><span class="cx">         SWITCH_SAY_INTERFACE,
</span><span class="cx">         SWITCH_ASR_INTERFACE,
</span><del>-        SWITCH_MANAGEMENT_INTERFACE
</del><ins>+        SWITCH_MANAGEMENT_INTERFACE,
+        SWITCH_LIMIT_INTERFACE
</ins><span class="cx"> } switch_module_interface_name_t;
</span><span class="cx">
</span><span class="cx"> typedef enum {
</span><span class="lines">@@ -1503,6 +1504,7 @@
</span><span class="cx"> typedef struct switch_management_interface switch_management_interface_t;
</span><span class="cx"> typedef struct switch_core_port_allocator switch_core_port_allocator_t;
</span><span class="cx"> typedef struct switch_media_bug switch_media_bug_t;
</span><ins>+typedef struct switch_limit_interface switch_limit_interface_t;
</ins><span class="cx">
</span><span class="cx"> struct switch_console_callback_match_node {
</span><span class="cx">         char *val;
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_commandsmod_commandsc"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/mod/applications/mod_commands/mod_commands.c (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_commands/mod_commands.c        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_commands/mod_commands.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -3201,7 +3201,7 @@
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-#define SHOW_SYNTAX "codec|endpoint|application|api|dialplan|file|timer|calls [count]|channels [count|like <match string>]|distinct_channels|aliases|complete|chat|management|modules|nat_map|say|interfaces|interface_types|tasks"
</del><ins>+#define SHOW_SYNTAX "codec|endpoint|application|api|dialplan|file|timer|calls [count]|channels [count|like <match string>]|distinct_channels|aliases|complete|chat|management|modules|nat_map|say|interfaces|interface_types|tasks|limits"
</ins><span class="cx"> SWITCH_STANDARD_API(show_function)
</span><span class="cx"> {
</span><span class="cx">         char sql[1024];
</span><span class="lines">@@ -3259,6 +3259,7 @@
</span><span class="cx">                          !strncasecmp(command, "file", 4) ||
</span><span class="cx">                          !strncasecmp(command, "timer", 5) ||
</span><span class="cx">                          !strncasecmp(command, "chat", 4) ||
</span><ins>+                         !strncasecmp(command, "limit", 5) ||
</ins><span class="cx">                          !strncasecmp(command, "say", 3) || !strncasecmp(command, "management", 10) || !strncasecmp(command, "endpoint", 8)) {
</span><span class="cx">                 if (end_of(command) == 's') {
</span><span class="cx">                         end_of(command) = '\0';
</span><span class="lines">@@ -4048,6 +4049,95 @@
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+/* LIMIT Stuff */
+#define LIMIT_USAGE_USAGE "<backend> <realm> <id>"
+SWITCH_STANDARD_API(limit_usage_function)
+{
+        int argc = 0;
+        char *argv[5] = { 0 };
+        char *mydata = NULL;
+        uint32_t count = 0;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 3) {
+                stream->write_function(stream, "USAGE: limit_usage %s\n", LIMIT_USAGE_USAGE);
+                goto end;
+        }
+        
+        count = switch_limit_usage(argv[0], argv[1], argv[2]);
+
+        stream->write_function(stream, "%d", count);
+
+end:
+        switch_safe_free(mydata);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+#define LIMIT_STATUS_USAGE "<backend>"
+SWITCH_STANDARD_API(limit_status_function)
+{
+        int argc = 0;
+        char *argv[2] = { 0 };
+        char *mydata = NULL;
+        char *ret = NULL;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 1) {
+                stream->write_function(stream, "USAGE: limit_status %s\n", LIMIT_STATUS_USAGE);
+                goto end;
+        }
+        
+        ret = switch_limit_status(argv[0]);
+
+        stream->write_function(stream, "%s", ret);
+
+end:
+        switch_safe_free(mydata);
+        switch_safe_free(ret);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+#define LIMIT_RESET_USAGE "<backend>"
+SWITCH_STANDARD_API(limit_reset_function)
+{
+        int argc = 0;
+        char *argv[2] = { 0 };
+        char *mydata = NULL;
+        switch_status_t ret = SWITCH_STATUS_SUCCESS;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 1) {
+                stream->write_function(stream, "USAGE: limit_reset %s\n", LIMIT_RESET_USAGE);
+                goto end;
+        }
+        
+        ret = switch_limit_reset(argv[0]);
+
+        stream->write_function(stream, "%s", (ret == SWITCH_STATUS_SUCCESS) ? "+OK" : "-ERR");
+
+end:
+        switch_safe_free(mydata);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
</ins><span class="cx"> SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_commands_shutdown)
</span><span class="cx"> {
</span><span class="cx">         int x;
</span><span class="lines">@@ -4108,6 +4198,9 @@
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, "hupall", "hupall", hupall_api_function, "<cause> [<var> <value>]");
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, "in_group", "determine if a user is in a group", in_group_function, "<user>[@<domain>] <group_name>");
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, "is_lan_addr", "see if an ip is a lan addr", lan_addr_function, "<ip>");
</span><ins>+        SWITCH_ADD_API(commands_api_interface, "limit_usage", "Gets the usage count of a limited resource", limit_usage_function, "<backend> <realm> <id>");
+        SWITCH_ADD_API(commands_api_interface, "limit_status", "Gets the status of a limit backend", limit_status_function, "<backend>");
+        SWITCH_ADD_API(commands_api_interface, "limit_reset", "Reset the counters of a limit backend", limit_reset_function, "<backend>");
</ins><span class="cx">         SWITCH_ADD_API(commands_api_interface, "load", "Load Module", load_function, LOAD_SYNTAX);
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, "md5", "md5", md5_function, "<data>");
</span><span class="cx">         SWITCH_ADD_API(commands_api_interface, "module_exists", "check if module exists", module_exists_function, "<module>");
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbMakefile"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_db/Makefile (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_db/Makefile         (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_db/Makefile        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+BASE=../../../..
+include $(BASE)/build/modmake.rules
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbmod_db2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.2008.vcproj (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.2008.vcproj         (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.2008.vcproj        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,283 @@
</span><ins>+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+        ProjectType="Visual C++"
+        Version="9.00"
+        Name="mod_db"
+        ProjectGUID="{F6A33240-8F29-48BD-98F0-826995911799}"
+        RootNamespace="mod_db"
+        Keyword="Win32Proj"
+        TargetFrameworkVersion="131072"
+        >
+        <Platforms>
+                <Platform
+                        Name="Win32"
+                />
+                <Platform
+                        Name="x64"
+                />
+        </Platforms>
+        <ToolFiles>
+        </ToolFiles>
+        <Configurations>
+                <Configuration
+                        Name="Debug|Win32"
+                        ConfigurationType="2"
+                        InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
+                        CharacterSet="2"
+                        >
+                        <Tool
+                                Name="VCPreBuildEventTool"
+                        />
+                        <Tool
+                                Name="VCCustomBuildTool"
+                        />
+                        <Tool
+                                Name="VCXMLDataGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCWebServiceProxyGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCMIDLTool"
+                        />
+                        <Tool
+                                Name="VCCLCompilerTool"
+                                UsePrecompiledHeader="0"
+                        />
+                        <Tool
+                                Name="VCManagedResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCPreLinkEventTool"
+                        />
+                        <Tool
+                                Name="VCLinkerTool"
+                                RandomizedBaseAddress="1"
+                                DataExecutionPrevention="0"
+                        />
+                        <Tool
+                                Name="VCALinkTool"
+                        />
+                        <Tool
+                                Name="VCManifestTool"
+                        />
+                        <Tool
+                                Name="VCXDCMakeTool"
+                        />
+                        <Tool
+                                Name="VCBscMakeTool"
+                        />
+                        <Tool
+                                Name="VCFxCopTool"
+                        />
+                        <Tool
+                                Name="VCAppVerifierTool"
+                        />
+                        <Tool
+                                Name="VCPostBuildEventTool"
+                        />
+                </Configuration>
+                <Configuration
+                        Name="Debug|x64"
+                        ConfigurationType="2"
+                        InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
+                        CharacterSet="2"
+                        >
+                        <Tool
+                                Name="VCPreBuildEventTool"
+                        />
+                        <Tool
+                                Name="VCCustomBuildTool"
+                        />
+                        <Tool
+                                Name="VCXMLDataGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCWebServiceProxyGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCMIDLTool"
+                                TargetEnvironment="3"
+                        />
+                        <Tool
+                                Name="VCCLCompilerTool"
+                                UsePrecompiledHeader="0"
+                        />
+                        <Tool
+                                Name="VCManagedResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCPreLinkEventTool"
+                        />
+                        <Tool
+                                Name="VCLinkerTool"
+                                OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
+                                RandomizedBaseAddress="1"
+                                DataExecutionPrevention="0"
+                                TargetMachine="17"
+                        />
+                        <Tool
+                                Name="VCALinkTool"
+                        />
+                        <Tool
+                                Name="VCManifestTool"
+                        />
+                        <Tool
+                                Name="VCXDCMakeTool"
+                        />
+                        <Tool
+                                Name="VCBscMakeTool"
+                        />
+                        <Tool
+                                Name="VCFxCopTool"
+                        />
+                        <Tool
+                                Name="VCAppVerifierTool"
+                        />
+                        <Tool
+                                Name="VCPostBuildEventTool"
+                        />
+                </Configuration>
+                <Configuration
+                        Name="Release|Win32"
+                        ConfigurationType="2"
+                        InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
+                        CharacterSet="2"
+                        >
+                        <Tool
+                                Name="VCPreBuildEventTool"
+                        />
+                        <Tool
+                                Name="VCCustomBuildTool"
+                        />
+                        <Tool
+                                Name="VCXMLDataGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCWebServiceProxyGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCMIDLTool"
+                        />
+                        <Tool
+                                Name="VCCLCompilerTool"
+                                UsePrecompiledHeader="0"
+                        />
+                        <Tool
+                                Name="VCManagedResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCPreLinkEventTool"
+                        />
+                        <Tool
+                                Name="VCLinkerTool"
+                                RandomizedBaseAddress="1"
+                                DataExecutionPrevention="0"
+                        />
+                        <Tool
+                                Name="VCALinkTool"
+                        />
+                        <Tool
+                                Name="VCManifestTool"
+                        />
+                        <Tool
+                                Name="VCXDCMakeTool"
+                        />
+                        <Tool
+                                Name="VCBscMakeTool"
+                        />
+                        <Tool
+                                Name="VCFxCopTool"
+                        />
+                        <Tool
+                                Name="VCAppVerifierTool"
+                        />
+                        <Tool
+                                Name="VCPostBuildEventTool"
+                        />
+                </Configuration>
+                <Configuration
+                        Name="Release|x64"
+                        ConfigurationType="2"
+                        InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
+                        CharacterSet="2"
+                        >
+                        <Tool
+                                Name="VCPreBuildEventTool"
+                        />
+                        <Tool
+                                Name="VCCustomBuildTool"
+                        />
+                        <Tool
+                                Name="VCXMLDataGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCWebServiceProxyGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCMIDLTool"
+                                TargetEnvironment="3"
+                        />
+                        <Tool
+                                Name="VCCLCompilerTool"
+                                UsePrecompiledHeader="0"
+                        />
+                        <Tool
+                                Name="VCManagedResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCPreLinkEventTool"
+                        />
+                        <Tool
+                                Name="VCLinkerTool"
+                                OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
+                                RandomizedBaseAddress="1"
+                                DataExecutionPrevention="0"
+                                TargetMachine="17"
+                        />
+                        <Tool
+                                Name="VCALinkTool"
+                        />
+                        <Tool
+                                Name="VCManifestTool"
+                        />
+                        <Tool
+                                Name="VCXDCMakeTool"
+                        />
+                        <Tool
+                                Name="VCBscMakeTool"
+                        />
+                        <Tool
+                                Name="VCFxCopTool"
+                        />
+                        <Tool
+                                Name="VCAppVerifierTool"
+                        />
+                        <Tool
+                                Name="VCPostBuildEventTool"
+                        />
+                </Configuration>
+        </Configurations>
+        <References>
+        </References>
+        <Files>
+                <File
+                        RelativePath=".\mod_db.c"
+                        >
+                </File>
+        </Files>
+        <Globals>
+        </Globals>
+</VisualStudioProject>
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_dbmod_dbc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.c (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.c         (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_db/mod_db.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,657 @@
</span><ins>+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2010, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Ken Rice <krice at suspicious dot org
+ * Mathieu Rene <mathieu.rene@gmail.com>
+ * Bret McDanel <trixter AT 0xdecafbad.com>
+ * Rupa Schomaker <rupa@rupa.com>
+ *
+ * mod_db.c -- Implements simple db API, group support, and limit db backend
+ *
+ */
+
+#include <switch.h>
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_db_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_db_shutdown);
+SWITCH_MODULE_DEFINITION(mod_db, mod_db_load, mod_db_shutdown, NULL);
+
+static struct {
+        switch_memory_pool_t *pool;
+        char hostname[256];
+        char *dbname;
+        char *odbc_dsn;
+        char *odbc_user;
+        char *odbc_pass;
+        switch_mutex_t *mutex;
+        switch_mutex_t *db_hash_mutex;
+        switch_hash_t *db_hash;
+} globals;
+
+typedef struct {
+        uint32_t total_usage;
+        uint32_t rate_usage;
+        time_t last_check;
+} limit_hash_item_t;
+
+struct callback {
+        char *buf;
+        size_t len;
+        int matches;
+};
+
+typedef struct callback callback_t;
+
+static int sql2str_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+        callback_t *cbt = (callback_t *) pArg;
+
+        switch_copy_string(cbt->buf, argv[0], cbt->len);
+        cbt->matches++;
+        return 0;
+}
+
+static char limit_sql[] =
+        "CREATE TABLE limit_data (\n"
+        " hostname VARCHAR(255),\n" " realm VARCHAR(255),\n" " id VARCHAR(255),\n" " uuid VARCHAR(255)\n" ");\n";
+
+static char db_sql[] =
+        "CREATE TABLE db_data (\n"
+        " hostname VARCHAR(255),\n" " realm VARCHAR(255),\n" " data_key VARCHAR(255),\n" " data VARCHAR(255)\n" ");\n";
+
+static char group_sql[] =
+        "CREATE TABLE group_data (\n" " hostname VARCHAR(255),\n" " groupname VARCHAR(255),\n" " url VARCHAR(255)\n" ");\n";
+
+
+switch_cache_db_handle_t *limit_get_db_handle(void)
+{
+        switch_cache_db_connection_options_t options = { {0} };
+        switch_cache_db_handle_t *dbh = NULL;
+
+        if (!zstr(globals.odbc_dsn)) {
+                options.odbc_options.dsn = globals.odbc_dsn;
+                options.odbc_options.user = globals.odbc_user;
+                options.odbc_options.pass = globals.odbc_pass;
+
+                if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_ODBC, &options) != SWITCH_STATUS_SUCCESS)
+                        dbh = NULL;
+                return dbh;
+        } else {
+                options.core_db_options.db_path = globals.dbname;
+                if (switch_cache_db_get_db_handle(&dbh, SCDB_TYPE_CORE_DB, &options) != SWITCH_STATUS_SUCCESS)
+                        dbh = NULL;
+                return dbh;
+        }
+}
+
+
+static switch_status_t limit_execute_sql(char *sql)
+{
+        switch_cache_db_handle_t *dbh = NULL;
+        switch_status_t status = SWITCH_STATUS_FALSE;
+
+        if (!(dbh = limit_get_db_handle())) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
+                goto end;
+        }
+
+        status = switch_cache_db_execute_sql(dbh, sql, NULL);
+
+ end:
+
+        switch_cache_db_release_db_handle(&dbh);
+
+        return status;
+}
+
+
+static switch_bool_t limit_execute_sql_callback(char *sql, switch_core_db_callback_func_t callback, void *pdata)
+{
+        switch_bool_t ret = SWITCH_FALSE;
+        char *errmsg = NULL;
+        switch_cache_db_handle_t *dbh = NULL;
+
+        if (!(dbh = limit_get_db_handle())) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
+                goto end;
+        }
+
+        switch_cache_db_execute_sql_callback(dbh, sql, callback, pdata, &errmsg);
+
+        if (errmsg) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg);
+                free(errmsg);
+        }
+
+ end:
+
+        switch_cache_db_release_db_handle(&dbh);
+
+        return ret;
+}
+
+static char * limit_execute_sql2str(char *sql, char *str, size_t len)
+{
+        callback_t cbt = { 0 };
+
+        cbt.buf = str;
+        cbt.len = len;
+
+        limit_execute_sql_callback(sql, sql2str_callback, &cbt);
+        
+        return cbt.buf;
+}
+
+/* \brief Enforces limit restrictions
+ * \param session current session
+ * \param realm limit realm
+ * \param id limit id
+ * \param max maximum count
+ * \return SWITCH_STATUS_SUCCESS if the access is allowed
+ */
+SWITCH_LIMIT_INCR(limit_incr_sql)
+{
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+        int got = 0;
+        char *sql = NULL;
+        char gotstr[128];
+        switch_status_t status = SWITCH_STATUS_SUCCESS;
+
+        // check max! WTF
+        
+        switch_mutex_lock(globals.mutex);
+
+        switch_channel_set_variable(channel, "limit_realm", realm);
+        switch_channel_set_variable(channel, "limit_id", resource);
+        switch_channel_set_variable(channel, "limit_max", switch_core_session_sprintf(session, "%d", max));
+
+        sql = switch_mprintf("select count(hostname) from limit_data where realm='%q' and id='%q';", realm, resource);
+        limit_execute_sql2str(sql, gotstr, 128);
+        switch_safe_free(sql);
+        got = atoi(gotstr);
+
+        if (max < 0) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s_%s is now %d\n", realm, resource, got + 1);
+        } else {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s_%s is now %d/%d\n", realm, resource, got + 1, max);
+        }
+
+        if (max >= 0 && got + 1 > max) {
+                status = SWITCH_STATUS_GENERR;
+                goto done;
+        }
+
+        sql =
+                switch_mprintf("insert into limit_data (hostname, realm, id, uuid) values('%q','%q','%q','%q');", globals.hostname, realm, resource,
+                                         switch_core_session_get_uuid(session));
+        limit_execute_sql(sql);
+        switch_safe_free(sql);
+
+        {
+                const char *susage = switch_core_session_sprintf(session, "%d", ++got);
+
+                switch_channel_set_variable(channel, "limit_usage", susage);
+                switch_channel_set_variable(channel, switch_core_session_sprintf(session, "limit_usage_%s_%s", realm, resource), susage);
+        }
+        switch_limit_fire_event("sql", realm, resource, got, 0, max, 0);
+
+ done:
+        switch_mutex_unlock(globals.mutex);
+        return status;
+}
+
+SWITCH_LIMIT_RELEASE(limit_release_sql)
+{
+        char *sql = NULL;
+
+        if (realm == NULL && resource == NULL) {
+                sql = switch_mprintf("delete from limit_data where uuid='%q'", switch_core_session_get_uuid(session));
+        } else {
+                sql = switch_mprintf("delete from limit_data where uuid='%q' and realm='%q' and id = '%q'", switch_core_session_get_uuid(session), realm, resource);
+        }
+        limit_execute_sql(sql);
+        switch_safe_free(sql);
+        
+        return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_LIMIT_USAGE(limit_usage_sql)
+{
+        char usagestr[128] = "";
+        int usage = 0;
+        char *sql = NULL;
+        
+        sql = switch_mprintf("select count(hostname) from limit_data where realm='%q' and id='%q'", realm, resource);
+        limit_execute_sql2str(sql, usagestr, sizeof(usagestr));
+        switch_safe_free(sql);
+        usage = atoi(usagestr);
+        
+        return usage;
+}
+
+SWITCH_LIMIT_RESET(limit_reset_sql)
+{
+        char *sql = NULL;
+        sql = switch_mprintf("delete from limit_data where hostname='%q';", globals.hostname);
+        limit_execute_sql(sql);
+        switch_safe_free(sql);
+        
+        return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_LIMIT_STATUS(limit_status_sql)
+{
+        char count[128] = "";
+        char *ret = NULL;
+        char *sql = NULL;
+        
+        sql = switch_mprintf("select count(hostname) from limit_data where hostname='%q'", globals.hostname);
+        limit_execute_sql2str(sql, count, sizeof(count));
+        switch_safe_free(sql);
+        ret = switch_mprintf("Tracking %s resources for hostname %s.", count, globals.hostname);
+        return ret;
+}
+
+/* INIT / Config */
+
+static switch_xml_config_string_options_t limit_config_dsn = { NULL, 0, "[^:]+:[^:]+:.+" };
+
+static switch_xml_config_item_t config_settings[] = {
+        SWITCH_CONFIG_ITEM("odbc-dsn", SWITCH_CONFIG_STRING, 0, &globals.odbc_dsn, NULL, &limit_config_dsn,
+                                         "dsn:username:password", "If set, the ODBC DSN used by the limit and db applications"),
+        SWITCH_CONFIG_ITEM_END()
+};
+
+static switch_status_t do_config()
+{
+        switch_cache_db_handle_t *dbh = NULL;
+        switch_status_t status = SWITCH_STATUS_SUCCESS;
+        char *sql = NULL;
+
+        limit_config_dsn.pool = globals.pool;
+
+        if (switch_xml_config_parse_module_settings("db.conf", SWITCH_FALSE, config_settings) != SWITCH_STATUS_SUCCESS) {
+                return SWITCH_STATUS_TERM;
+        }
+
+        if (globals.odbc_dsn) {
+                if ((globals.odbc_user = strchr(globals.odbc_dsn, ':'))) {
+                        *globals.odbc_user++ = '\0';
+                        if ((globals.odbc_pass = strchr(globals.odbc_user, ':'))) {
+                                *globals.odbc_pass++ = '\0';
+                        }
+                }
+
+                if (!(dbh = limit_get_db_handle())) {
+                        globals.odbc_dsn = globals.odbc_user = globals.odbc_pass;
+                }
+        }
+
+
+        if (zstr(globals.odbc_dsn)) {
+                globals.dbname = "call_limit";
+                dbh = limit_get_db_handle();
+        }
+
+
+        if (dbh) {
+                int x = 0;
+                char *indexes[] = {
+                        "create index ld_hostname on limit_data (hostname)",
+                        "create index ld_uuid on limit_data (uuid)",
+                        "create index ld_realm on limit_data (realm)",
+                        "create index ld_id on limit_data (id)",
+                        "create index dd_realm on db_data (realm)",
+                        "create index dd_data_key on db_data (data_key)",
+                        "create index gd_groupname on group_data (groupname)",
+                        "create index gd_url on group_data (url)",
+                        NULL
+                };
+
+
+
+                switch_cache_db_test_reactive(dbh, "select * from limit_data", NULL, limit_sql);
+                switch_cache_db_test_reactive(dbh, "select * from db_data", NULL, db_sql);
+                switch_cache_db_test_reactive(dbh, "select * from group_data", NULL, group_sql);
+
+                for (x = 0; indexes[x]; x++) {
+                        switch_cache_db_execute_sql(dbh, indexes[x], NULL);
+                }
+
+                switch_cache_db_release_db_handle(&dbh);
+
+                sql = switch_mprintf("delete from limit_data where hostname='%q';", globals.hostname);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+        }
+
+        return status;
+}
+
+/* APP/API STUFF */
+
+/* CORE DB STUFF */
+
+SWITCH_STANDARD_API(db_api_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *sql;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 1 || !argv[0]) {
+                goto error;
+        }
+
+        if (!strcasecmp(argv[0], "insert")) {
+                if (argc < 4) {
+                        goto error;
+                }
+                sql = switch_mprintf("delete from db_data where realm='%q' and data_key='%q'", argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                sql =
+                        switch_mprintf("insert into db_data (hostname, realm, data_key, data) values('%q','%q','%q','%q');", globals.hostname, argv[1], argv[2],
+                                                 argv[3]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                stream->write_function(stream, "+OK");
+                goto done;
+        } else if (!strcasecmp(argv[0], "delete")) {
+                if (argc < 2) {
+                        goto error;
+                }
+                sql = switch_mprintf("delete from db_data where realm='%q' and data_key='%q'", argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                stream->write_function(stream, "+OK");
+                goto done;
+        } else if (!strcasecmp(argv[0], "select")) {
+                char buf[256] = "";
+                if (argc < 3) {
+                        goto error;
+                }
+                sql = switch_mprintf("select data from db_data where realm='%q' and data_key='%q'", argv[1], argv[2]);
+                limit_execute_sql2str(sql, buf, sizeof(buf));
+                switch_safe_free(sql);
+                stream->write_function(stream, "%s", buf);
+                goto done;
+        }
+
+ error:
+        stream->write_function(stream, "!err!");
+
+ done:
+
+        switch_safe_free(mydata);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+#define DB_USAGE "[insert|delete]/<realm>/<key>/<val>"
+#define DB_DESC "save data"
+
+SWITCH_STANDARD_APP(db_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *sql = NULL;
+
+        if (!zstr(data)) {
+                mydata = switch_core_session_strdup(session, data);
+                argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 3 || !argv[0]) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "USAGE: db %s\n", DB_USAGE);
+                return;
+        }
+
+        if (!strcasecmp(argv[0], "insert")) {
+                if (argc < 4) {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "USAGE: db %s\n", DB_USAGE);
+                        return;
+                }
+                sql = switch_mprintf("delete from db_data where realm='%q' and data_key='%q'", argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+
+                sql =
+                        switch_mprintf("insert into db_data (hostname, realm, data_key, data) values('%q','%q','%q','%q');", globals.hostname, argv[1], argv[2],
+                                                 argv[3]);
+        } else if (!strcasecmp(argv[0], "delete")) {
+                sql = switch_mprintf("delete from db_data where realm='%q' and data_key='%q'", argv[1], argv[2]);
+        } else {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "USAGE: db %s\n", DB_USAGE);
+                return;
+        }
+
+        if (sql) {
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+        }
+}
+
+/* GROUP STUFF */
+
+static int group_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+        callback_t *cbt = (callback_t *) pArg;
+        switch_snprintf(cbt->buf + strlen(cbt->buf), cbt->len - strlen(cbt->buf), "%s%c", argv[0], *argv[1]);
+        cbt->matches++;
+        return 0;
+}
+
+SWITCH_STANDARD_API(group_api_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *sql;
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 2 || !argv[0]) {
+                goto error;
+        }
+
+        if (!strcasecmp(argv[0], "insert")) {
+                if (argc < 3) {
+                        goto error;
+                }
+                sql = switch_mprintf("delete from group_data where groupname='%q' and url='%q';", argv[1], argv[2]);
+                switch_assert(sql);
+
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                sql = switch_mprintf("insert into group_data (hostname, groupname, url) values('%q','%q','%q');", globals.hostname, argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                stream->write_function(stream, "+OK");
+                goto done;
+        } else if (!strcasecmp(argv[0], "delete")) {
+                if (argc < 3) {
+                        goto error;
+                }
+                if (!strcmp(argv[2], "*")) {
+                        sql = switch_mprintf("delete from group_data where groupname='%q';", argv[1]);
+                } else {
+                        sql = switch_mprintf("delete from group_data where groupname='%q' and url='%q';", argv[1], argv[2]);
+                }
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+                stream->write_function(stream, "+OK");
+                goto done;
+        } else if (!strcasecmp(argv[0], "call")) {
+                char buf[4096] = "";
+                char *how = ",";
+                callback_t cbt = { 0 };
+                cbt.buf = buf;
+                cbt.len = sizeof(buf);
+
+                if (argc > 2) {
+                        if (!strcasecmp(argv[2], "order")) {
+                                how = "|";
+                        }
+                }
+
+                sql = switch_mprintf("select url,'%q' from group_data where groupname='%q'", how, argv[1]);
+                switch_assert(sql);
+
+                limit_execute_sql_callback(sql, group_callback, &cbt);
+                switch_safe_free(sql);
+
+                *(buf + (strlen(buf) - 1)) = '\0';
+                stream->write_function(stream, "%s", buf);
+
+                goto done;
+        }
+
+ error:
+        stream->write_function(stream, "!err!");
+
+ done:
+
+        switch_safe_free(mydata);
+        return SWITCH_STATUS_SUCCESS;
+}
+
+#define GROUP_USAGE "[insert|delete]:<group name>:<val>"
+#define GROUP_DESC "save data"
+
+SWITCH_STANDARD_APP(group_function)
+{
+        int argc = 0;
+        char *argv[3] = { 0 };
+        char *mydata = NULL;
+        char *sql;
+
+        if (!zstr(data)) {
+                mydata = switch_core_session_strdup(session, data);
+                argc = switch_separate_string(mydata, ':', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 3 || !argv[0]) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "USAGE: group %s\n", DB_USAGE);
+                return;
+        }
+
+        if (!strcasecmp(argv[0], "insert")) {
+                sql = switch_mprintf("insert into group_data (hostname, groupname, url) values('%q','%q','%q');", globals.hostname, argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+        } else if (!strcasecmp(argv[0], "delete")) {
+                sql = switch_mprintf("delete from group_data where groupname='%q' and url='%q';", argv[1], argv[2]);
+                switch_assert(sql);
+                limit_execute_sql(sql);
+                switch_safe_free(sql);
+        }
+}
+
+/* INIT/DEINIT STUFF */
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_db_load)
+{
+        switch_status_t status;
+        switch_application_interface_t *app_interface;
+        switch_api_interface_t *commands_api_interface;
+        switch_limit_interface_t *limit_interface;
+
+        memset(&globals, 0, sizeof(&globals));
+        gethostname(globals.hostname, sizeof(globals.hostname));
+        globals.pool = pool;
+
+
+        if ((status = do_config() != SWITCH_STATUS_SUCCESS)) {
+                return status;
+        }
+
+        switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_mutex_init(&globals.db_hash_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_core_hash_init(&globals.db_hash, pool);
+
+        /* connect my internal structure to the blank pointer passed to me */
+        *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+        /* register limit interfaces */
+        SWITCH_ADD_LIMIT(limit_interface, "sql", limit_incr_sql, limit_release_sql, limit_usage_sql, limit_reset_sql, limit_status_sql);
+
+        SWITCH_ADD_APP(app_interface, "db", "Insert to the db", DB_DESC, db_function, DB_USAGE, SAF_SUPPORT_NOMEDIA);
+        SWITCH_ADD_APP(app_interface, "group", "Manage a group", GROUP_DESC, group_function, GROUP_USAGE, SAF_SUPPORT_NOMEDIA);
+        SWITCH_ADD_API(commands_api_interface, "db", "db get/set", db_api_function, "[insert|delete|select]/<realm>/<key>/<value>");
+        switch_console_set_complete("add db insert");
+        switch_console_set_complete("add db delete");
+        switch_console_set_complete("add db select");
+        SWITCH_ADD_API(commands_api_interface, "group", "group [insert|delete|call]", group_api_function, "[insert|delete|call]:<group name>:<url>");
+        switch_console_set_complete("add group insert");
+        switch_console_set_complete("add group delete");
+        switch_console_set_complete("add group call");
+
+        /* indicate that the module should continue to be loaded */
+        return SWITCH_STATUS_SUCCESS;
+        
+}
+
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_db_shutdown)
+{
+
+        switch_xml_config_cleanup(config_settings);
+
+        switch_mutex_destroy(globals.mutex);
+        switch_mutex_destroy(globals.db_hash_mutex);
+
+        switch_core_hash_destroy(&globals.db_hash);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_dptoolsmod_dptoolsc"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/mod/applications/mod_dptools/mod_dptools.c (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_dptools/mod_dptools.c        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_dptools/mod_dptools.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -2977,6 +2977,140 @@
</span><span class="cx">         }
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+/* LIMIT STUFF */
+#define LIMIT_USAGE "<backend> <realm> <id> [<max>[/interval]] [number [dialplan [context]]]"
+#define LIMIT_DESC "limit access to a resource and transfer to an extension if the limit is exceeded"
+SWITCH_STANDARD_APP(limit_function)
+{
+        int argc = 0;
+        char *argv[7] = { 0 };
+        char *mydata = NULL;
+        char *backend = NULL;
+        char *realm = NULL;
+        char *id = NULL;
+        char *xfer_exten = NULL;
+        int max = -1;
+        int interval = 0;
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+
+        /* Parse application data */
+        if (!zstr(data)) {
+                mydata = switch_core_session_strdup(session, data);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 3) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "USAGE: limit %s\n", LIMIT_USAGE);
+                return;
+        }
+
+        backend = argv[0];
+        realm = argv[1];
+        id = argv[2];
+
+        /* If max is omitted or negative, only act as a counter and skip maximum checks */
+        if (argc > 3) {
+                if (argv[3][0] == '-') {
+                        max = -1;
+                } else {
+                        char *szinterval = NULL;
+                        if ((szinterval = strchr(argv[2], '/'))) {
+                                *szinterval++ = '\0';
+                                interval = atoi(szinterval);
+                        }
+
+                        max = atoi(argv[3]);
+
+                        if (max < 0) {
+                                max = 0;
+                        }
+                }
+        }
+
+        if (argc > 4) {
+                xfer_exten = argv[4];
+        } else {
+                xfer_exten = LIMIT_DEF_XFER_EXTEN;
+        }
+
+        if (switch_limit_incr(backend, session, realm, id, max, interval) != SWITCH_STATUS_SUCCESS) {
+                /* Limit exceeded */
+                if (*xfer_exten == '!') {
+                        switch_channel_hangup(channel, switch_channel_str2cause(xfer_exten + 1));
+                } else {
+                        switch_ivr_session_transfer(session, xfer_exten, argv[5], argv[6]);
+                }
+        }
+}
+
+
+#define LIMITEXECUTE_USAGE "<backend> <realm> <id> [<max>[/interval]] [application] [application arguments]"
+#define LIMITEXECUTE_DESC "limit access to a resource. the specified application will only be executed if the resource is available"
+SWITCH_STANDARD_APP(limit_execute_function)
+{
+        int argc = 0;
+        char *argv[6] = { 0 };
+        char *mydata = NULL;
+        char *backend = NULL;
+        char *realm = NULL;
+        char *id = NULL;
+        char *app = NULL;
+        char *app_arg = NULL;
+        int max = -1;
+        int interval = 0;
+
+        /* Parse application data */
+        if (!zstr(data)) {
+                mydata = switch_core_session_strdup(session, data);
+                argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 6) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "USAGE: limit_execute %s\n", LIMITEXECUTE_USAGE);
+                return;
+        }
+
+        backend = argv[0];
+        realm = argv[1];
+        id = argv[2];
+
+        /* Accept '-' as unlimited (act as counter) */
+        if (argv[3][0] == '-') {
+                max = -1;
+        } else {
+                char *szinterval = NULL;
+
+                if ((szinterval = strchr(argv[3], '/'))) {
+                        *szinterval++ = '\0';
+                        interval = atoi(szinterval);
+                }
+
+                max = atoi(argv[3]);
+
+                if (max < 0) {
+                        max = 0;
+                }
+        }
+
+        app = argv[4];
+        app_arg = argv[5];
+
+        if (zstr(app)) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Missing application\n");
+                return;
+        }
+
+        if (switch_limit_incr(backend, session, realm, id, max, interval) == SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Executing\n");
+                switch_core_session_execute_application(session, app, app_arg);
+                /* Only release the resource if we are still in CS_EXECUTE */
+                if (switch_channel_get_state(switch_core_session_get_channel(session)) == CS_EXECUTE) {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "immediately releasing\n");
+                        switch_limit_release(backend, session, realm, id);                        
+                }
+        }
+}
+
</ins><span class="cx"> #define SPEAK_DESC "Speak text to a channel via the tts interface"
</span><span class="cx"> #define DISPLACE_DESC "Displace audio from a file to the channels input"
</span><span class="cx"> #define SESS_REC_DESC "Starts a background recording of the entire session"
</span><span class="lines">@@ -3144,6 +3278,8 @@
</span><span class="cx">                                  SAF_NONE);
</span><span class="cx">         SWITCH_ADD_APP(app_interface, "session_loglevel", "session_loglevel", "session_loglevel", session_loglevel_function, SESSION_LOGLEVEL_SYNTAX,
</span><span class="cx">                                  SAF_SUPPORT_NOMEDIA);
</span><ins>+        SWITCH_ADD_APP(app_interface, "limit", "Limit", LIMIT_DESC, limit_function, LIMIT_USAGE, SAF_SUPPORT_NOMEDIA);
+        SWITCH_ADD_APP(app_interface, "limit_execute", "Limit", LIMITEXECUTE_USAGE, limit_execute_function, LIMITEXECUTE_USAGE, SAF_SUPPORT_NOMEDIA);
</ins><span class="cx">
</span><span class="cx">         SWITCH_ADD_DIALPLAN(dp_interface, "inline", inline_dialplan_hunt);
</span><span class="cx">
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashMakefile"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/Makefile (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/Makefile         (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/Makefile        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+BASE=../../../..
+include $(BASE)/build/modmake.rules
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashmod_hash2008vcproj"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.2008.vcproj (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.2008.vcproj         (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.2008.vcproj        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,283 @@
</span><ins>+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+        ProjectType="Visual C++"
+        Version="9.00"
+        Name="mod_hash"
+        ProjectGUID="{F6A33240-8F29-48BD-98F0-826995911799}"
+        RootNamespace="mod_hash"
+        Keyword="Win32Proj"
+        TargetFrameworkVersion="131072"
+        >
+        <Platforms>
+                <Platform
+                        Name="Win32"
+                />
+                <Platform
+                        Name="x64"
+                />
+        </Platforms>
+        <ToolFiles>
+        </ToolFiles>
+        <Configurations>
+                <Configuration
+                        Name="Debug|Win32"
+                        ConfigurationType="2"
+                        InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
+                        CharacterSet="2"
+                        >
+                        <Tool
+                                Name="VCPreBuildEventTool"
+                        />
+                        <Tool
+                                Name="VCCustomBuildTool"
+                        />
+                        <Tool
+                                Name="VCXMLDataGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCWebServiceProxyGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCMIDLTool"
+                        />
+                        <Tool
+                                Name="VCCLCompilerTool"
+                                UsePrecompiledHeader="0"
+                        />
+                        <Tool
+                                Name="VCManagedResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCPreLinkEventTool"
+                        />
+                        <Tool
+                                Name="VCLinkerTool"
+                                RandomizedBaseAddress="1"
+                                DataExecutionPrevention="0"
+                        />
+                        <Tool
+                                Name="VCALinkTool"
+                        />
+                        <Tool
+                                Name="VCManifestTool"
+                        />
+                        <Tool
+                                Name="VCXDCMakeTool"
+                        />
+                        <Tool
+                                Name="VCBscMakeTool"
+                        />
+                        <Tool
+                                Name="VCFxCopTool"
+                        />
+                        <Tool
+                                Name="VCAppVerifierTool"
+                        />
+                        <Tool
+                                Name="VCPostBuildEventTool"
+                        />
+                </Configuration>
+                <Configuration
+                        Name="Debug|x64"
+                        ConfigurationType="2"
+                        InheritedPropertySheets="..\..\..\..\w32\module_debug.vsprops"
+                        CharacterSet="2"
+                        >
+                        <Tool
+                                Name="VCPreBuildEventTool"
+                        />
+                        <Tool
+                                Name="VCCustomBuildTool"
+                        />
+                        <Tool
+                                Name="VCXMLDataGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCWebServiceProxyGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCMIDLTool"
+                                TargetEnvironment="3"
+                        />
+                        <Tool
+                                Name="VCCLCompilerTool"
+                                UsePrecompiledHeader="0"
+                        />
+                        <Tool
+                                Name="VCManagedResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCPreLinkEventTool"
+                        />
+                        <Tool
+                                Name="VCLinkerTool"
+                                OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
+                                RandomizedBaseAddress="1"
+                                DataExecutionPrevention="0"
+                                TargetMachine="17"
+                        />
+                        <Tool
+                                Name="VCALinkTool"
+                        />
+                        <Tool
+                                Name="VCManifestTool"
+                        />
+                        <Tool
+                                Name="VCXDCMakeTool"
+                        />
+                        <Tool
+                                Name="VCBscMakeTool"
+                        />
+                        <Tool
+                                Name="VCFxCopTool"
+                        />
+                        <Tool
+                                Name="VCAppVerifierTool"
+                        />
+                        <Tool
+                                Name="VCPostBuildEventTool"
+                        />
+                </Configuration>
+                <Configuration
+                        Name="Release|Win32"
+                        ConfigurationType="2"
+                        InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
+                        CharacterSet="2"
+                        >
+                        <Tool
+                                Name="VCPreBuildEventTool"
+                        />
+                        <Tool
+                                Name="VCCustomBuildTool"
+                        />
+                        <Tool
+                                Name="VCXMLDataGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCWebServiceProxyGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCMIDLTool"
+                        />
+                        <Tool
+                                Name="VCCLCompilerTool"
+                                UsePrecompiledHeader="0"
+                        />
+                        <Tool
+                                Name="VCManagedResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCPreLinkEventTool"
+                        />
+                        <Tool
+                                Name="VCLinkerTool"
+                                RandomizedBaseAddress="1"
+                                DataExecutionPrevention="0"
+                        />
+                        <Tool
+                                Name="VCALinkTool"
+                        />
+                        <Tool
+                                Name="VCManifestTool"
+                        />
+                        <Tool
+                                Name="VCXDCMakeTool"
+                        />
+                        <Tool
+                                Name="VCBscMakeTool"
+                        />
+                        <Tool
+                                Name="VCFxCopTool"
+                        />
+                        <Tool
+                                Name="VCAppVerifierTool"
+                        />
+                        <Tool
+                                Name="VCPostBuildEventTool"
+                        />
+                </Configuration>
+                <Configuration
+                        Name="Release|x64"
+                        ConfigurationType="2"
+                        InheritedPropertySheets="..\..\..\..\w32\module_release.vsprops"
+                        CharacterSet="2"
+                        >
+                        <Tool
+                                Name="VCPreBuildEventTool"
+                        />
+                        <Tool
+                                Name="VCCustomBuildTool"
+                        />
+                        <Tool
+                                Name="VCXMLDataGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCWebServiceProxyGeneratorTool"
+                        />
+                        <Tool
+                                Name="VCMIDLTool"
+                                TargetEnvironment="3"
+                        />
+                        <Tool
+                                Name="VCCLCompilerTool"
+                                UsePrecompiledHeader="0"
+                        />
+                        <Tool
+                                Name="VCManagedResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCResourceCompilerTool"
+                        />
+                        <Tool
+                                Name="VCPreLinkEventTool"
+                        />
+                        <Tool
+                                Name="VCLinkerTool"
+                                OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
+                                RandomizedBaseAddress="1"
+                                DataExecutionPrevention="0"
+                                TargetMachine="17"
+                        />
+                        <Tool
+                                Name="VCALinkTool"
+                        />
+                        <Tool
+                                Name="VCManifestTool"
+                        />
+                        <Tool
+                                Name="VCXDCMakeTool"
+                        />
+                        <Tool
+                                Name="VCBscMakeTool"
+                        />
+                        <Tool
+                                Name="VCFxCopTool"
+                        />
+                        <Tool
+                                Name="VCAppVerifierTool"
+                        />
+                        <Tool
+                                Name="VCPostBuildEventTool"
+                        />
+                </Configuration>
+        </Configurations>
+        <References>
+        </References>
+        <Files>
+                <File
+                        RelativePath=".\mod_hash.c"
+                        >
+                </File>
+        </Files>
+        <Globals>
+        </Globals>
+</VisualStudioProject>
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcmodapplicationsmod_hashmod_hashc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.c (0 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.c         (rev 0)
+++ freeswitch/branches/rupa_limit/src/mod/applications/mod_hash/mod_hash.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -0,0 +1,457 @@
</span><ins>+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2010, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Ken Rice <krice at suspicious dot org
+ * Mathieu Rene <mathieu.rene@gmail.com>
+ * Bret McDanel <trixter AT 0xdecafbad.com>
+ * Rupa Schomaker <rupa@rupa.com>
+ *
+ * mod_hash.c -- Hash api, hash backend for limit
+ *
+ */
+
+#include <switch.h>
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown);
+SWITCH_MODULE_DEFINITION(mod_hash, mod_hash_load, mod_hash_shutdown, NULL);
+
+/* CORE STUFF */
+static struct {
+        switch_memory_pool_t *pool;
+        switch_mutex_t *mutex;
+        switch_mutex_t *limit_hash_mutex;
+        switch_hash_t *limit_hash;
+        switch_mutex_t *db_hash_mutex;
+        switch_hash_t *db_hash;
+} globals;
+
+typedef struct {
+        uint32_t total_usage;
+        uint32_t rate_usage;
+        time_t last_check;
+} limit_hash_item_t;
+
+struct callback {
+        char *buf;
+        size_t len;
+        int matches;
+};
+
+typedef struct callback callback_t;
+
+/* HASH STUFF */
+typedef struct {
+        switch_hash_t *hash;
+} limit_hash_private_t;
+
+/* \brief Enforces limit_hash restrictions
+ * \param session current session
+ * \param realm limit realm
+ * \param id limit id
+ * \param max maximum count
+ * \param interval interval for rate limiting
+ * \return SWITCH_TRUE if the access is allowed, SWITCH_FALSE if it isnt
+ */
+SWITCH_LIMIT_INCR(limit_incr_hash)
+{
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+        char *hashkey = NULL;
+        switch_bool_t status = SWITCH_STATUS_SUCCESS;
+        limit_hash_item_t *item = NULL;
+        time_t now = switch_epoch_time_now(NULL);
+        limit_hash_private_t *pvt = NULL;
+        uint8_t increment = 1;
+
+        hashkey = switch_core_session_sprintf(session, "%s_%s", realm, resource);
+
+        switch_mutex_lock(globals.limit_hash_mutex);
+        /* Check if that realm+resource has ever been checked */
+        if (!(item = (limit_hash_item_t *) switch_core_hash_find(globals.limit_hash, hashkey))) {
+                /* No, create an empty structure and add it, then continue like as if it existed */
+                item = (limit_hash_item_t *) malloc(sizeof(limit_hash_item_t));
+                switch_assert(item);
+                memset(item, 0, sizeof(limit_hash_item_t));
+                switch_core_hash_insert(globals.limit_hash, hashkey, item);
+        }
+
+        /* Did we already run on this channel before? */
+        if ((pvt = switch_channel_get_private(channel, "limit_hash"))) {
+                /* Yes, but check if we did that realm+resource
+                 If we didnt, allow incrementing the counter.
+                 If we did, dont touch it but do the validation anyways
+                 */
+                increment = !switch_core_hash_find(pvt->hash, hashkey);
+        } else {
+                /* This is the first limit check on this channel, create a hashtable, set our prviate data and add a state handler */
+                pvt = (limit_hash_private_t *) switch_core_session_alloc(session, sizeof(limit_hash_private_t));
+                memset(pvt, 0, sizeof(limit_hash_private_t));
+                switch_core_hash_init(&pvt->hash, switch_core_session_get_pool(session));
+                switch_channel_set_private(channel, "limit_hash", pvt);
+        }
+
+        if (interval > 0) {
+                if (item->last_check <= (now - interval)) {
+                        item->rate_usage = 1;
+                        item->last_check = now;
+                } else {
+                        /* Always increment rate when its checked as it doesnt depend on the channel */
+                        item->rate_usage++;
+
+                        if ((max >= 0) && (item->rate_usage > (uint32_t) max)) {
+                                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s exceeds maximum rate of %d/%ds, now at %d\n",
+                                                                 hashkey, max, interval, item->rate_usage);
+                                status = SWITCH_STATUS_GENERR;
+                                goto end;
+                        }
+                }
+        } else if ((max >= 0) && (item->total_usage + increment > (uint32_t) max)) {
+                switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s is already at max value (%d)\n", hashkey, item->total_usage);
+                status = SWITCH_STATUS_GENERR;
+                goto end;
+        }
+
+        if (increment) {
+                item->total_usage++;
+
+                switch_core_hash_insert(pvt->hash, hashkey, item);
+
+                if (max == -1) {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s is now %d\n", hashkey, item->total_usage);
+                } else if (interval == 0) {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s is now %d/%d\n", hashkey, item->total_usage, max);
+                } else {
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s is now %d/%d for the last %d seconds\n", hashkey,
+                                                         item->rate_usage, max, interval);
+                }
+
+                switch_limit_fire_event("hash", realm, resource, item->total_usage, item->rate_usage, max, max >= 0 ? (uint32_t) max : 0);
+        }
+
+        /* Save current usage & rate into channel variables so it can be used later in the dialplan, or added to CDR records */
+        {
+                const char *susage = switch_core_session_sprintf(session, "%d", item->total_usage);
+                const char *srate = switch_core_session_sprintf(session, "%d", item->rate_usage);
+
+                switch_channel_set_variable(channel, "limit_usage", susage);
+                switch_channel_set_variable(channel, switch_core_session_sprintf(session, "limit_usage_%s", hashkey), susage);
+
+                switch_channel_set_variable(channel, "limit_rate", srate);
+                switch_channel_set_variable(channel, switch_core_session_sprintf(session, "limit_rate_%s", hashkey), srate);
+        }
+
+ end:
+        switch_mutex_unlock(globals.limit_hash_mutex);
+        return status;
+}
+
+/* !\brief Releases usage of a limit_hash-controlled ressource */
+SWITCH_LIMIT_RELEASE(limit_release_hash)
+{
+        switch_channel_t *channel = switch_core_session_get_channel(session);
+        limit_hash_private_t *pvt = switch_channel_get_private(channel, "limit_hash");
+        limit_hash_item_t *item = NULL;
+        switch_hash_index_t *hi;
+        char *hashkey = NULL;
+
+        if (!pvt || !pvt->hash) {
+                return SWITCH_STATUS_SUCCESS;
+        }
+
+        switch_mutex_lock(globals.limit_hash_mutex);
+
+        /* clear for uuid */
+        if (realm == NULL && resource == NULL) {
+                /* Loop through the channel's hashtable which contains mapping to all the limit_hash_item_t referenced by that channel */
+                while ((hi = switch_hash_first(NULL, pvt->hash))) {
+                        void *val = NULL;
+                        const void *key;
+                        switch_ssize_t keylen;
+                        limit_hash_item_t *item = NULL;
+
+                        switch_hash_this(hi, &key, &keylen, &val);
+
+                        item = (limit_hash_item_t *) val;
+                        item->total_usage--;
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s is now %d\n", (const char *) key, item->total_usage);
+
+                        if (item->total_usage == 0) {
+                                /* Noone is using this item anymore */
+                                switch_core_hash_delete(globals.limit_hash, (const char *) key);
+                                free(item);
+                        }
+
+                        switch_core_hash_delete(pvt->hash, (const char *) key);
+                }
+        } else {
+                hashkey = switch_core_session_sprintf(session, "%s_%s", realm, resource);
+
+                if ((item = (limit_hash_item_t *) switch_core_hash_find(pvt->hash, hashkey))) {
+                        item->total_usage--;
+                        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Usage for %s is now %d\n", (const char *) hashkey, item->total_usage);
+
+                        switch_core_hash_delete(pvt->hash, hashkey);
+
+                        if (item->total_usage == 0) {
+                                /* Noone is using this item anymore */
+                                switch_core_hash_delete(globals.limit_hash, (const char *) hashkey);
+                                free(item);
+                        }
+                }
+        }
+
+        switch_mutex_unlock(globals.limit_hash_mutex);
+        
+        return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_LIMIT_USAGE(limit_usage_hash)
+{
+        char *hash_key = NULL;
+        limit_hash_item_t *item = NULL;
+        int count = 0;
+
+        switch_mutex_lock(globals.limit_hash_mutex);
+
+        hash_key = switch_mprintf("%s_%s", realm, resource);
+
+        if ((item = switch_core_hash_find(globals.limit_hash, hash_key))) {
+                count = item->total_usage;
+        }
+
+         switch_safe_free(hash_key);
+        switch_mutex_unlock(globals.limit_hash_mutex);
+
+        return count;
+}
+
+SWITCH_LIMIT_RESET(limit_reset_hash)
+{
+        return SWITCH_STATUS_GENERR;
+}
+
+SWITCH_LIMIT_STATUS(limit_status_hash)
+{
+        switch_hash_index_t *hi = NULL;
+        int count = 0;
+        char *ret = NULL;
+        
+        switch_mutex_lock(globals.limit_hash_mutex);
+        
+        while ((hi = switch_hash_first(NULL, globals.limit_hash))) {
+                count++;
+        }
+        switch_mutex_unlock(globals.limit_hash_mutex);
+        
+        ret = switch_mprintf("There are %d elements being tracked.", count);
+        return ret;
+}
+
+/* APP/API STUFF */
+
+/* CORE HASH STUFF */
+
+#define HASH_USAGE "[insert|delete]/<realm>/<key>/<val>"
+#define HASH_DESC "save data"
+
+SWITCH_STANDARD_APP(hash_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *hash_key = NULL;
+        char *value = NULL;
+
+        switch_mutex_lock(globals.db_hash_mutex);
+
+        if (!zstr(data)) {
+                mydata = strdup(data);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 3 || !argv[0]) {
+                goto usage;
+        }
+
+        hash_key = switch_mprintf("%s_%s", argv[1], argv[2]);
+
+        if (!strcasecmp(argv[0], "insert")) {
+                if (argc < 4) {
+                        goto usage;
+                }
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        free(value);
+                        switch_core_hash_delete(globals.db_hash, hash_key);
+                }
+                value = strdup(argv[3]);
+                switch_assert(value);
+                switch_core_hash_insert(globals.db_hash, hash_key, value);
+        } else if (!strcasecmp(argv[0], "delete")) {
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        switch_safe_free(value);
+                        switch_core_hash_delete(globals.db_hash, hash_key);
+                }
+        } else {
+                goto usage;
+        }
+
+        goto done;
+
+ usage:
+        switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "USAGE: hash %s\n", HASH_USAGE);
+
+ done:
+        switch_mutex_unlock(globals.db_hash_mutex);
+        switch_safe_free(mydata);
+        switch_safe_free(hash_key);
+}
+
+#define HASH_API_USAGE "insert|select|delete/realm/key[/value]"
+SWITCH_STANDARD_API(hash_api_function)
+{
+        int argc = 0;
+        char *argv[4] = { 0 };
+        char *mydata = NULL;
+        char *value = NULL;
+        char *hash_key = NULL;
+
+        switch_mutex_lock(globals.db_hash_mutex);
+
+        if (!zstr(cmd)) {
+                mydata = strdup(cmd);
+                switch_assert(mydata);
+                argc = switch_separate_string(mydata, '/', argv, (sizeof(argv) / sizeof(argv[0])));
+        }
+
+        if (argc < 3 || !argv[0]) {
+                goto usage;
+        }
+
+        hash_key = switch_mprintf("%s_%s", argv[1], argv[2]);
+
+        if (!strcasecmp(argv[0], "insert")) {
+                if (argc < 4) {
+                        goto usage;
+                }
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        switch_safe_free(value);
+                        switch_core_hash_delete(globals.db_hash, hash_key);
+                }
+                value = strdup(argv[3]);
+                switch_assert(value);
+                switch_core_hash_insert(globals.db_hash, hash_key, value);
+                stream->write_function(stream, "+OK\n");
+        } else if (!strcasecmp(argv[0], "delete")) {
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        switch_safe_free(value);
+                        switch_core_hash_delete(globals.db_hash, hash_key);
+                        stream->write_function(stream, "+OK\n");
+                } else {
+                        stream->write_function(stream, "-ERR Not found\n");
+                }
+        } else if (!strcasecmp(argv[0], "select")) {
+                if ((value = switch_core_hash_find(globals.db_hash, hash_key))) {
+                        stream->write_function(stream, "%s", value);
+                }
+        } else {
+                goto usage;
+        }
+
+        goto done;
+
+ usage:
+        stream->write_function(stream, "-ERR Usage: hash %s\n", HASH_API_USAGE);
+
+ done:
+        switch_mutex_unlock(globals.db_hash_mutex);
+        switch_safe_free(mydata);
+        switch_safe_free(hash_key);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+/* INIT/DEINIT STUFF */
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_hash_load)
+{
+        switch_application_interface_t *app_interface;
+        switch_api_interface_t *commands_api_interface;
+        switch_limit_interface_t *limit_interface;
+
+        memset(&globals, 0, sizeof(&globals));
+        globals.pool = pool;
+
+        if (switch_event_reserve_subclass(LIMIT_EVENT_USAGE) != SWITCH_STATUS_SUCCESS) {
+                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldnt register event subclass \"%s\"", LIMIT_EVENT_USAGE);
+                return SWITCH_STATUS_FALSE;
+        }
+
+        switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_mutex_init(&globals.limit_hash_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_mutex_init(&globals.db_hash_mutex, SWITCH_MUTEX_NESTED, globals.pool);
+        switch_core_hash_init(&globals.limit_hash, pool);
+        switch_core_hash_init(&globals.db_hash, pool);
+
+        /* connect my internal structure to the blank pointer passed to me */
+        *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+        /* register limit interfaces */
+        SWITCH_ADD_LIMIT(limit_interface, "hash", limit_incr_hash, limit_release_hash, limit_usage_hash, limit_reset_hash, limit_status_hash);
+
+        SWITCH_ADD_APP(app_interface, "hash", "Insert into the hashtable", HASH_DESC, hash_function, HASH_USAGE, SAF_SUPPORT_NOMEDIA)
+        SWITCH_ADD_API(commands_api_interface, "hash", "hash get/set", hash_api_function, "[insert|delete|select]/<realm>/<key>/<value>");
+        switch_console_set_complete("add hash insert");
+        switch_console_set_complete("add hash delete");
+        switch_console_set_complete("add hash select");
+
+        /* indicate that the module should continue to be loaded */
+        return SWITCH_STATUS_SUCCESS;
+        
+}
+
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_hash_shutdown)
+{
+
+        switch_mutex_destroy(globals.mutex);
+        switch_mutex_destroy(globals.limit_hash_mutex);
+
+        switch_core_hash_destroy(&globals.limit_hash);
+
+        return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
</ins></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcswitch_corec"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/switch_core.c (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/switch_core.c        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/switch_core.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -1290,7 +1290,6 @@
</span><span class="cx">         runtime.timer_affinity = -1;
</span><span class="cx">         switch_load_core_config("switch.conf");
</span><span class="cx">
</span><del>-
</del><span class="cx">         switch_core_state_machine_init(runtime.memory_pool);
</span><span class="cx">
</span><span class="cx">         if (switch_core_sqldb_start(runtime.memory_pool, switch_test_flag((&runtime), SCF_USE_SQL) ? SWITCH_TRUE : SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
</span><span class="lines">@@ -1301,6 +1300,8 @@
</span><span class="cx">
</span><span class="cx">         switch_rtp_init(runtime.memory_pool);
</span><span class="cx">
</span><ins>+        switch_nat_init(runtime.memory_pool);
+
</ins><span class="cx">         runtime.running = 1;
</span><span class="cx">         runtime.initiated = switch_time_now();
</span><span class="cx">         
</span></span></pre></div>
<a id="freeswitchbranchesrupa_limitsrcswitch_loadable_modulec"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/rupa_limit/src/switch_loadable_module.c (16914 => 16915)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/rupa_limit/src/switch_loadable_module.c        2010-03-05 14:54:56 UTC (rev 16914)
+++ freeswitch/branches/rupa_limit/src/switch_loadable_module.c        2010-03-05 16:51:03 UTC (rev 16915)
</span><span class="lines">@@ -71,6 +71,7 @@
</span><span class="cx">         switch_hash_t *chat_hash;
</span><span class="cx">         switch_hash_t *say_hash;
</span><span class="cx">         switch_hash_t *management_hash;
</span><ins>+        switch_hash_t *limit_hash;
</ins><span class="cx">         switch_mutex_t *mutex;
</span><span class="cx">         switch_memory_pool_t *pool;
</span><span class="cx"> };
</span><span class="lines">@@ -433,7 +434,33 @@
</span><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">         }
</span><ins>+        if (new_module->module_interface->limit_interface) {
+                const switch_limit_interface_t *ptr;
</ins><span class="cx">
</span><ins>+                for (ptr = new_module->module_interface->limit_interface; ptr; ptr = ptr->next) {
+                        if (!ptr->interface_name) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to load limit interface from %s due to no interface name.\n", key);
+                        } else {
+                                if (switch_core_hash_find(loadable_modules.limit_hash, ptr->interface_name)) {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
+                                                                         "Failed to load limit interface %s. Name %s already exists\n", key, ptr->interface_name);
+                                } else {
+                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
+                                                                         "Adding Limit interface '%s'\n", ptr->interface_name);
+                                        switch_core_hash_insert(loadable_modules.limit_hash, ptr->interface_name, (const void *) ptr);
+                                        if (switch_event_create(&event, SWITCH_EVENT_MODULE_LOAD) == SWITCH_STATUS_SUCCESS) {
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "limit");
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "key", new_module->key);
+                                                switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "filename", new_module->filename);
+                                                switch_event_fire(&event);
+                                        }
+                                }
+
+                        }
+                }
+        }
+
</ins><span class="cx">         switch_mutex_unlock(loadable_modules.mutex);
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx">
</span><span class="lines">@@ -768,6 +795,23 @@
</span><span class="cx">                 }
</span><span class="cx">         }
</span><span class="cx">
</span><ins>+        if (old_module->module_interface->limit_interface) {
+                const switch_limit_interface_t *ptr;
+
+                for (ptr = old_module->module_interface->limit_interface; ptr; ptr = ptr->next) {
+                        if (ptr->interface_name) {
+                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
+                                                                 "Deleting Limit interface '%s'\n", ptr->interface_name);
+                                switch_core_hash_delete(loadable_modules.limit_hash, ptr->interface_name);
+                                if (switch_event_create(&event, SWITCH_EVENT_MODULE_UNLOAD) == SWITCH_STATUS_SUCCESS) {
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "type", "limit");
+                                        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "name", ptr->interface_name);
+                                        switch_event_fire(&event);
+                                }
+                        }
+                }
+        }
+
</ins><span class="cx">         switch_mutex_unlock(loadable_modules.mutex);
</span><span class="cx">
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="lines">@@ -1164,6 +1208,7 @@
</span><span class="cx">         switch_core_hash_init_nocase(&loadable_modules.chat_hash, loadable_modules.pool);
</span><span class="cx">         switch_core_hash_init_nocase(&loadable_modules.say_hash, loadable_modules.pool);
</span><span class="cx">         switch_core_hash_init_nocase(&loadable_modules.management_hash, loadable_modules.pool);
</span><ins>+        switch_core_hash_init_nocase(&loadable_modules.limit_hash, loadable_modules.pool);
</ins><span class="cx">         switch_core_hash_init_nocase(&loadable_modules.dialplan_hash, loadable_modules.pool);
</span><span class="cx">         switch_mutex_init(&loadable_modules.mutex, SWITCH_MUTEX_NESTED, loadable_modules.pool);
</span><span class="cx">
</span><span class="lines">@@ -1347,6 +1392,7 @@
</span><span class="cx">         switch_core_hash_destroy(&loadable_modules.chat_hash);
</span><span class="cx">         switch_core_hash_destroy(&loadable_modules.say_hash);
</span><span class="cx">         switch_core_hash_destroy(&loadable_modules.management_hash);
</span><ins>+        switch_core_hash_destroy(&loadable_modules.limit_hash);
</ins><span class="cx">         switch_core_hash_destroy(&loadable_modules.dialplan_hash);
</span><span class="cx">
</span><span class="cx"> }
</span><span class="lines">@@ -1403,17 +1449,18 @@
</span><span class="cx">         }
</span><span class="cx">
</span><span class="cx"> HASH_FUNC(dialplan)
</span><del>-        HASH_FUNC(timer)
-        HASH_FUNC(application)
-        HASH_FUNC(api)
-        HASH_FUNC(file)
-        HASH_FUNC(speech)
-        HASH_FUNC(asr)
-        HASH_FUNC(directory)
-        HASH_FUNC(chat)
</del><ins>+HASH_FUNC(timer)
+HASH_FUNC(application)
+HASH_FUNC(api)
+HASH_FUNC(file)
+HASH_FUNC(speech)
+HASH_FUNC(asr)
+HASH_FUNC(directory)
+HASH_FUNC(chat)
+HASH_FUNC(limit)
</ins><span class="cx">
</span><span class="cx">
</span><del>-        SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(const char *name)
</del><ins>+SWITCH_DECLARE(switch_say_interface_t *) switch_loadable_module_get_say_interface(const char *name)
</ins><span class="cx"> {
</span><span class="cx">         return switch_core_hash_find_locked(loadable_modules.say_hash, name, loadable_modules.mutex);
</span><span class="cx"> }
</span><span class="lines">@@ -1683,6 +1730,9 @@
</span><span class="cx">         case SWITCH_MANAGEMENT_INTERFACE:
</span><span class="cx">                 ALLOC_INTERFACE(management)
</span><span class="cx">
</span><ins>+        case SWITCH_LIMIT_INTERFACE:
+                ALLOC_INTERFACE(limit)
+
</ins><span class="cx">         default:
</span><span class="cx">                 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid Module Type!\n");
</span><span class="cx">                 return NULL;
</span></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>
</body>
</html>