summaryrefslogtreecommitdiff
path: root/misc
diff options
context:
space:
mode:
Diffstat (limited to 'misc')
-rw-r--r--misc/freeswitch/conf/freeswitch.xml466
-rw-r--r--misc/freeswitch/scripts/common/database.lua40
-rw-r--r--misc/freeswitch/scripts/common/fapi.lua5
-rw-r--r--misc/freeswitch/scripts/common/intruder.lua51
-rw-r--r--misc/freeswitch/scripts/common/perimeter.lua241
-rw-r--r--misc/freeswitch/scripts/common/sip_account.lua8
-rw-r--r--misc/freeswitch/scripts/common/str.lua17
-rw-r--r--misc/freeswitch/scripts/configuration.lua18
-rw-r--r--misc/freeswitch/scripts/dialplan/acd.lua2
-rw-r--r--misc/freeswitch/scripts/dialplan/dialplan.lua18
-rw-r--r--misc/freeswitch/scripts/dialplan/dtmf.lua69
-rw-r--r--misc/freeswitch/scripts/dialplan/functions.lua20
-rw-r--r--misc/freeswitch/scripts/dialplan/hunt_group.lua13
-rw-r--r--misc/freeswitch/scripts/dialplan/router.lua12
-rw-r--r--misc/freeswitch/scripts/dialplan/sip_call.lua71
-rw-r--r--misc/freeswitch/scripts/dialplan_default.lua37
-rw-r--r--misc/freeswitch/scripts/event/dump_variables.lua52
-rw-r--r--misc/freeswitch/scripts/event/event.lua33
-rw-r--r--misc/freeswitch/scripts/event/perimeter.lua107
-rw-r--r--misc/freeswitch/scripts/event/perimeter_defense.lua114
-rw-r--r--misc/freeswitch/scripts/event_manager.lua21
-rw-r--r--misc/freeswitch/scripts/fax_daemon.lua43
-rw-r--r--misc/freeswitch/scripts/http_request.lua2
-rw-r--r--misc/freeswitch/scripts/phones/phone.lua5
-rw-r--r--misc/freeswitch/scripts/send_fax.lua14
25 files changed, 1276 insertions, 203 deletions
diff --git a/misc/freeswitch/conf/freeswitch.xml b/misc/freeswitch/conf/freeswitch.xml
index fd6ab67..a5fe873 100644
--- a/misc/freeswitch/conf/freeswitch.xml
+++ b/misc/freeswitch/conf/freeswitch.xml
@@ -466,6 +466,470 @@
</macros>
</phrases>
</language>
+ <language name="de" say-module="de" sound-prefix="/opt/freeswitch/sounds/de/de/callie">
+ <phrases>
+ <macros>
+ <macro name="voicemail_hello">
+ <input pattern="(.*)">
+ <match>
+ <action function="play-file" data="voicemail/vm-hello.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_enter_id">
+ <input pattern="(.*)">
+ <match>
+ <action function="play-file" data="voicemail/vm-enter_id.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_enter_pass">
+ <input pattern="(.*)">
+ <match>
+ <action function="play-file" data="voicemail/vm-enter_pass.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_fail_auth">
+ <input pattern="(.*)">
+ <match>
+ <action function="play-file" data="voicemail/vm-fail_auth.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_goodbye">
+ <input pattern="(.*)">
+ <match>
+ <action function="play-file" data="voicemail/vm-goodbye.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_abort">
+ <input pattern="(.*)">
+ <match>
+ <action function="play-file" data="voicemail/vm-abort.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_message_count">
+ <input pattern="^(1):(.*)$" break_on_match="true">
+ <match>
+ <action function="play-file" data="voicemail/vm-you_have.wav"/>
+ <action function="say" data="$1" method="pronounced" type="items"/>
+ <action function="play-file" data="voicemail/vm-$2.wav"/>
+ <action function="play-file" data="voicemail/vm-message.wav"/>
+ </match>
+ </input>
+ <input pattern="^(\d+):(.*)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-you_have.wav"/>
+ <action function="say" data="$1" method="pronounced" type="items"/>
+ <action function="play-file" data="voicemail/vm-$2.wav"/>
+ <action function="play-file" data="voicemail/vm-messages.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_menu">
+ <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="play-file" data="voicemail/vm-listen_new.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ <action function="execute" data="sleep(100)"/>
+ <action function="play-file" data="voicemail/vm-listen_saved.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+ <action function="execute" data="sleep(100)"/>
+ <action function="play-file" data="voicemail/vm-advanced.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+ <action function="execute" data="sleep(100)"/>
+ <action function="play-file" data="voicemail/vm-to_exit.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$4" method="pronounced" type="name_phonetic"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_config_menu">
+ <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="play-file" data="voicemail/vm-to_record_greeting.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ <action function="execute" data="sleep(100)"/>
+ <action function="play-file" data="voicemail/vm-choose_greeting.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+ <action function="execute" data="sleep(100)"/>
+ <action function="play-file" data="voicemail/vm-record_name2.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+ <action function="execute" data="sleep(100)"/>
+ <action function="play-file" data="voicemail/vm-change_password.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$4" method="pronounced" type="name_spelled"/>
+ <action function="execute" data="sleep(100)"/>
+ <action function="play-file" data="voicemail/vm-main_menu.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$5" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_record_name">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-record_name1.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_record_file_check">
+ <input pattern="^([0-9#*]):([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-listen_to_recording.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-save_recording.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-rerecord.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_record_urgent_check">
+ <input pattern="^([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="play-file" data="voicemail/vm-mark-urgent.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-continue.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_forward_prepend">
+ <input pattern="^([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="play-file" data="voicemail/vm-forward_add_intro.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-send_message_now.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_forward_message_enter_extension">
+ <input pattern="^([0-9#*])$">
+ <match>
+ <action function="play-file" data="voicemail/vm-forward_enter_ext.wav"/>
+ <action function="play-file" data="voicemail/vm-followed_by.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_invalid_extension">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-that_was_an_invalid_ext.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_listen_file_check">
+ <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):(.*)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-listen_to_recording.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-save_recording.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-delete_recording.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-forward_to_email.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$4" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-return_call.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$5" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-to_forward.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$6" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ <input pattern="^([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*]):([0-9#*])$">
+ <match>
+ <action function="play-file" data="voicemail/vm-listen_to_recording.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-save_recording.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-delete_recording.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$3" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-return_call.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$5" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-to_forward.wav"/>
+ <action function="play-file" data="voicemail/vm-press.wav"/>
+ <action function="say" data="$6" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_choose_greeting">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-choose_greeting_choose.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_choose_greeting_fail">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-choose_greeting_fail.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_record_greeting">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-record_greeting.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_record_message">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-record_message.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_greeting_selected">
+ <input pattern="^(\d+)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-greeting.wav"/>
+ <action function="say" data="$1" method="pronounced" type="items"/>
+ <action function="play-file" data="voicemail/vm-selected.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_play_greeting">
+ <input pattern="^(\d+)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-person.wav"/>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ <action function="play-file" data="voicemail/vm-not_available.wav"/>
+ </match>
+ </input>
+ <input pattern="^name:(.+)$">
+ <match>
+ <action function="play-file" data="$1"/>
+ <action function="play-file" data="voicemail/vm-not_available.wav"/>
+ </match>
+ </input>
+ <input pattern="^greeting:(.+)$">
+ <match>
+ <action function="play-file" data="$1"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_say_number">
+ <input pattern="^(\d+)$">
+ <match>
+ <action function="say" data="$1" method="pronounced" type="items"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_say_message_number">
+ <input pattern="^([a-z]+):(\d+)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-$1.wav"/>
+ <action function="play-file" data="voicemail/vm-message_number.wav"/>
+ <action function="say" data="$2" method="pronounced" type="items"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_say_phone_number">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_say_name">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="say" data="$1" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_ack">
+ <input pattern="^(too-small)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-too-small.wav"/>
+ </match>
+ </input>
+ <input pattern="^(deleted)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-message.wav"/>
+ <action function="play-file" data="voicemail/vm-$1.wav"/>
+ </match>
+ </input>
+ <input pattern="^(saved)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-message.wav"/>
+ <action function="play-file" data="voicemail/vm-saved2.wav"/>
+ </match>
+ </input>
+ <input pattern="^(emailed)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-message.wav"/>
+ <action function="play-file" data="voicemail/vm-$1.wav"/>
+ </match>
+ </input>
+ <input pattern="^(marked-urgent)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-message.wav"/>
+ <action function="play-file" data="voicemail/vm-$1.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_say_date">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="say" data="$1" method="pronounced" type="current_date_time"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="voicemail_disk_quota_exceeded">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="voicemail/vm-mailbox_full.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="valet_announce_ext">
+ <input pattern="^([^\:]+):(.*)$">
+ <match>
+ <action function="say" data="$2" method="pronounced" type="name_spelled"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="valet_lot_full">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="tone_stream://%(275,10,600);%(275,100,300)"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="valet_lot_empty">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="tone_stream://%(275,10,600);%(275,100,300)"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="logged_in">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="ivr/ivr-you_are_now_logged_in.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="logged_out">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="ivr/ivr-you_are_now_logged_out.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="acd_announce_position_enter">
+ <input pattern="^([0-9]+)$">
+ <match>
+ <action function="play-file" data="ivr/ivr-you_are_number.wav"/>
+ <action function="say" data="$1" method="pronounced" type="number"/>
+ <action function="play-file" data="ivr/ivr-in_line.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="acd_announce_position_change">
+ <input pattern="^1$">
+ <match>
+ <action function="play-file" data="ivr/ivr-you_are_number.wav"/>
+ <action function="say" data="1" method="pronounced" type="number"/>
+ <action function="play-file" data="ivr/ivr-in_line.wav"/>
+ <action function="break"/>
+ </match>
+ </input>
+ <input pattern="^([0-9]+)$">
+ <match>
+ <action function="play-file" data="ivr/ivr-you_are_number.wav"/>
+ <action function="say" data="$1" method="pronounced" type="number"/>
+ <action function="play-file" data="ivr/ivr-in_line.wav"/>
+ <action function="play-file" data="ivr/ivr-thank_you_for_holding.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="acd_announce_position_periodic">
+ <input pattern="^1$">
+ <match>
+ <action function="play-file" data="ivr/ivr-you_are_number.wav"/>
+ <action function="say" data="1" method="pronounced" type="number"/>
+ <action function="play-file" data="ivr/ivr-in_line.wav"/>
+ <action function="break"/>
+ </match>
+ </input>
+ <input pattern="^([0-9]+)$">
+ <match>
+ <action function="play-file" data="ivr/ivr-you_are_number.wav"/>
+ <action function="say" data="$1" method="pronounced" type="number"/>
+ <action function="play-file" data="ivr/ivr-in_line.wav"/>
+ <action function="play-file" data="ivr/ivr-thank_you_for_holding.wav"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="acd_announce_call_agents">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="$1"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="acd_greeting">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="$1"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="acd_goodbye">
+ <input pattern="^(.*)$">
+ <match>
+ <action function="play-file" data="$1"/>
+ </match>
+ </input>
+ </macro>
+ <macro name="acd_agent_status">
+ <input pattern="^active$">
+ <match>
+ <action function="play-file" data="ivr/ivr-you_are_now_logged_in.wav"/>
+ </match>
+ </input>
+ <input pattern="^inactive$">
+ <match>
+ <action function="play-file" data="ivr/ivr-you_are_now_logged_out.wav"/>
+ </match>
+ </input>
+ </macro>
+ </macros>
+ </phrases>
+ </language>
</section>
<section name="configuration" description="Gemeinschaft5 FreeSwitch configuration">
<configuration name="acl.conf" description="Network Lists">
@@ -632,6 +1096,7 @@
<load module="mod_local_stream"/>
<load module="mod_tone_stream"/>
<load module="mod_say_en"/>
+ <load module="mod_say_de"/>
<load module="mod_spandsp"/>
<load module="mod_snmp"/>
<load module="mod_dingaling"/>
@@ -639,6 +1104,7 @@
</configuration>
<configuration name="lua.conf" description="LUA Configuration">
<settings>
+ <param name="module-directory" value="/usr/lib/i386-linux-gnu/lua/5.1/?.so;"/>
<param name="script-directory" value="/usr/share/freeswitch/scripts/?.lua;/usr/share/lua/5.1/?.lua;"/>
<param name="xml-handler-script" value="configuration.lua"/>
<param name="xml-handler-bindings" value="directory|configuration"/>
diff --git a/misc/freeswitch/scripts/common/database.lua b/misc/freeswitch/scripts/common/database.lua
index 1f39135..345f69d 100644
--- a/misc/freeswitch/scripts/common/database.lua
+++ b/misc/freeswitch/scripts/common/database.lua
@@ -16,6 +16,7 @@ function Database.new(self, arg)
self.class = 'database';
self.log = arg.log;
self.conn = nil;
+ self.ignore_on_update = arg.ignore_on_update or {};
return object;
end
@@ -71,6 +72,45 @@ function Database.last_insert_id(self)
end
+function Database.insert_or_update(self, db_table, record, use_on_update)
+ ignore_on_update = ignore_on_update or self.ignore_on_update;
+ local record_sql_create = {};
+ local record_sql_update = {};
+
+ for key, value in pairs(record) do
+ if ignore_on_update[key] ~= false then
+ table.insert(record_sql_update, self:key_value(key, value));
+ end
+ table.insert(record_sql_create, self:key_value(key, value));
+ end
+
+ local sql_query = 'INSERT INTO `' .. db_table .. '` SET ' .. table.concat(record_sql_create, ', ') .. ' ON DUPLICATE KEY UPDATE ' .. table.concat(record_sql_update, ', ');
+
+ return self:query(sql_query);
+end
+
+
+function Database.key_value(self, key, value)
+ return self:escape(key, '`') .. ' = ' .. self:escape(value, '"');
+end
+
+
+function Database.escape(self, value, str_quotes)
+ str_quotes = str_quotes or '';
+ if type(value) == 'boolean' then
+ return tostring(value):upper();
+ elseif type(value) == 'number' then
+ return tostring(value);
+ elseif type(value) == 'string' then
+ return str_quotes .. value:gsub('"', '\\"'):gsub("'", "\\'") .. str_quotes;
+ elseif type(value) == 'table' and value.raw then
+ return tostring(value[1]);
+ else
+ return 'NULL';
+ end
+end
+
+
function Database.release(self)
if self.conn then
self.conn:release();
diff --git a/misc/freeswitch/scripts/common/fapi.lua b/misc/freeswitch/scripts/common/fapi.lua
index 5b96633..b749a69 100644
--- a/misc/freeswitch/scripts/common/fapi.lua
+++ b/misc/freeswitch/scripts/common/fapi.lua
@@ -32,8 +32,10 @@ function FApi.return_result(self, result, positive, negative, unspecified)
return negative;
elseif result:match('^+OK') then
return positive;
- else
+ elseif type(unspecified) ~= 'nil' then
return unspecified;
+ else
+ return result;
end
end
@@ -75,6 +77,7 @@ function FApi.create_uuid(self, uuid)
end
function FApi.execute(self, function_name, function_parameters)
+ function_parameters = function_parameters or '';
local result = self.fs_api:execute(function_name, function_parameters);
return self:return_result(result, true);
end
diff --git a/misc/freeswitch/scripts/common/intruder.lua b/misc/freeswitch/scripts/common/intruder.lua
new file mode 100644
index 0000000..083ec37
--- /dev/null
+++ b/misc/freeswitch/scripts/common/intruder.lua
@@ -0,0 +1,51 @@
+-- Gemeinschaft 5 module: intruder class
+-- (c) AMOOMA GmbH 2013
+--
+
+module(...,package.seeall)
+
+
+Intruder = {}
+
+
+function Intruder.new(self, arg)
+ arg = arg or {}
+ object = arg.object or {}
+ setmetatable(object, self);
+ self.__index = self;
+ self.log = arg.log;
+ self.class = 'intruder'
+ self.database = arg.database;
+
+ return object;
+end
+
+
+function Intruder.update_blacklist(self, event)
+ local intruder_record = {
+ list_type = 'blacklist',
+ key = event.key,
+ points = event.points,
+ bans = event.record.banned,
+ contact_ip = event.received_ip,
+ contact_port = event.received_port,
+ contact_count = event.record.contact_count + 1,
+ contact_last = { 'FROM_UNIXTIME(' .. tostring(math.floor(event.timestamp/1000000)) .. ')', raw = true },
+ contacts_per_second = event.contacts_per_second,
+ contacts_per_second_max = event.contacts_per_second_max,
+ user_agent = event.user_agent,
+ to_user = event.to_user,
+ comment = 'Permimeter',
+ created_at = {'NOW()', raw = true },
+ updated_at = {'NOW()', raw = true },
+ };
+
+ if tonumber(event.ban_time) then
+ intruder_record.ban_last = { 'FROM_UNIXTIME(' .. event.ban_time .. ')', raw = true };
+ end
+ if tonumber(event.ban_end) then
+ intruder_record.ban_end = { 'FROM_UNIXTIME(' .. event.ban_end .. ')', raw = true };
+ end
+
+ self.database:insert_or_update('intruders', intruder_record, { created_at = false, comment = false });
+end
diff --git a/misc/freeswitch/scripts/common/perimeter.lua b/misc/freeswitch/scripts/common/perimeter.lua
new file mode 100644
index 0000000..0815d33
--- /dev/null
+++ b/misc/freeswitch/scripts/common/perimeter.lua
@@ -0,0 +1,241 @@
+-- Gemeinschaft 5 module: perimeter class
+-- (c) AMOOMA GmbH 2013
+--
+
+module(...,package.seeall)
+
+
+Perimeter = {}
+
+
+function Perimeter.new(self, arg)
+ arg = arg or {}
+ object = arg.object or {}
+ setmetatable(object, self);
+ self.__index = self;
+ self.log = arg.log;
+ self.class = 'perimeter'
+ self.database = arg.database;
+ self.domain = arg.domain;
+ self.sources = {};
+
+ self.checks_available = {
+ check_frequency = self.check_frequency,
+ check_username_scan = self.check_username_scan,
+ check_bad_headers = self.check_bad_headers,
+ };
+
+ return object;
+end
+
+
+function Perimeter.setup(self, event)
+ require 'common.configuration_table';
+ local config = common.configuration_table.get(self.database, 'perimeter');
+
+ self.contact_count_threshold = 10;
+ self.contact_span_threshold = 2;
+ self.name_changes_threshold = 2;
+ self.blacklist_file = '/var/opt/gemeinschaft/firewall/blacklist';
+ self.blacklist_file_comment = '# PERIMETER_BAN - points: {points}, generated: {date}';
+ self.blacklist_file_entry = '{received_ip} udp 5060';
+ self.ban_command = 'sudo /sbin/service shorewall refresh';
+ self.ban_threshold = 20;
+ self.ban_tries = 1;
+ self.checks = { register = {}, call = {} };
+ self.bad_headers = { register = {}, call = {} };
+
+ if config and config.general then
+ for key, value in pairs(config.general) do
+ self[key] = value;
+ end
+ end
+
+ self.checks.register = config.checks_register or {};
+ self.checks.call = config.checks_call or {};
+ self.bad_headers.register = config.bad_headers_register;
+ self.bad_headers.call = config.bad_headers_call;
+
+ self.log:info('[perimeter] PERIMETER - setup perimeter defense');
+end
+
+
+function Perimeter.record_load(self, event)
+ if not self.sources[event.key] then
+ self.sources[event.key] = {
+ contact_first = event.timestamp,
+ contact_last = event.timestamp,
+ contact_count = 0,
+ span_contact_count = 0,
+ span_start = event.timestamp,
+ points = 0,
+ banned = 0,
+ };
+ end
+
+ return self.sources[event.key];
+end
+
+
+function Perimeter.format_date(self, value)
+ local epoch = tonumber(tostring(value/1000000):match('^(%d-)%.'));
+ return os.date('%Y-%m-%d %X', tonumber(epoch)) .. '.' .. (value-(epoch*1000000));
+end
+
+
+function Perimeter.record_update(self, event)
+ event.record.contact_last = event.timestamp;
+ event.record.contact_count = event.record.contact_count + 1;
+ event.record.points = event.points or event.record.points;
+ event.record.span_start = event.span_start or event.record.span_start;
+ event.record.span_contact_count = (event.span_contact_count or event.record.span_contact_count) + 1;
+ event.record.users = event.users or event.record.users;
+end
+
+
+function Perimeter.check(self, event)
+ if not event or not event.key then
+ self.log:warning('[perimeter] PERIMETER_CHECK - no event/key');
+ return;
+ end
+
+ event.record = self:record_load(event);
+ if event.record.banned <= self.ban_tries then
+ for check_name, check_points in pairs(self.checks[event.action]) do
+ if self.checks_available[check_name] then
+ local result = self.checks_available[check_name](self, event);
+ if tonumber(result) then
+ event.points = (event.points or event.record.points) + result * check_points;
+ end
+ end
+ end
+ end
+
+ if tonumber(event.points) and event.points < 0 then
+ event.points = 0;
+ end
+
+ if event.points then
+ self.log:info('[', event.key, '/', event.sequence, '] PERIMETER suspicion rising - points: ', event.points,', ', event.action, '=', event.class, ', from: ', event.from_user, '@', event.from_host, ', to: ', event.to_user, '@', event.to_host, ', user_agent: ', event.user_agent);
+ end
+
+ if (event.points or event.record.points) > self.ban_threshold and event.record.banned <= self.ban_tries then
+ if event.record.banned > 0 and event.record.banned == self.ban_tries then
+ self.log:warning('[', event.key, '/', event.sequence, '] PERIMETER_BAN_FUTILE - points: ', event.points,', event: ', event.class, ', from: ', event.from_user, '@', event.from_host, ', to: ', event.to_user, '@', event.to_host);
+ else
+ self.log:notice('[', event.key, '/', event.sequence, '] PERIMETER_BAN - threshold reached: ', event.points,', event: ', event.class, ', from: ', event.from_user, '@', event.from_host, ', to: ', event.to_user, '@', event.to_host);
+ if event.record.banned == 0 then
+ self:append_blacklist_file(event);
+ end
+ self:execute_ban(event);
+ event.ban_time = os.time();
+ end
+
+ event.record.banned = event.record.banned + 1;
+ event.span_start = event.timestamp;
+ event.span_contact_count = 0;
+ event.points = 0;
+ end
+
+ if event.points then
+ self:update_intruder(event);
+ end
+
+ self:record_update(event);
+end
+
+
+function Perimeter.check_frequency(self, event)
+ if event.record.span_contact_count >= self.contact_count_threshold then
+ self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_FREQUENCY_CHECK - contacts: ', event.record.span_contact_count, ' in < ', (event.timestamp - event.record.span_start)/1000000, ' sec, threshold: ', self.contact_count_threshold, ' in ', self.contact_span_threshold, ' sec');
+ event.span_contact_count = 0;
+ event.span_start = event.timestamp;
+ event.contacts_per_second = event.record.span_contact_count / ((event.timestamp - event.record.span_start)/1000000)
+ return 1;
+ elseif (event.timestamp - event.record.span_start) > (self.contact_span_threshold * 1000000) then
+ event.span_contact_count = 0;
+ event.span_start = event.timestamp;
+ end
+end
+
+
+function Perimeter.check_username_scan(self, event)
+ if not event.to_user then
+ return;
+ end
+
+ if not event.record.users or tostring(event.auth_result) == 'SUCCESS' or tostring(event.auth_result) == 'RENEWED' then
+ event.users = { event.to_user };
+ return;
+ end
+
+ if #event.record.users >= self.name_changes_threshold then
+ self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_USER_SCAN - user names: ', #event.record.users, ', threshold: ', self.name_changes_threshold);
+ event.users = {};
+ return 1;
+ else
+ for index=1, #event.record.users do
+ if event.record.users[index] == tostring(event.to_user) then
+ return
+ end
+ end
+
+ if not event.users then
+ event.users = event.record.users or {};
+ end
+ table.insert(event.users, tostring(event.to_user));
+ end
+end
+
+
+function Perimeter.check_bad_headers(self, event)
+ local points = nil;
+ for name, pattern in pairs(self.bad_headers[event.action]) do
+ pattern = self:expand_variables(pattern, event);
+ local success, result = pcall(string.find, event[name], pattern);
+ if success and result then
+ self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_BAD_HEADERS - ', name, '=', event[name], ' ~= ', pattern);
+ points = (points or 0) + 1;
+ end
+ end
+
+ return points;
+end
+
+
+function Perimeter.append_blacklist_file(self, event)
+ local blacklist = io.open(self.blacklist_file, 'a');
+ if not blacklist then
+ self.log:error('[', event.key, '/', event.sequence, '] PERIMETER_APPEND_BLACKLIST - could not open file: ', self.blacklist_file);
+ return false;
+ end
+
+ event.date = self:format_date(event.timestamp);
+
+ if self.blacklist_file_comment then
+ blacklist:write(self:expand_variables(self.blacklist_file_comment, event), '\n');
+ end
+
+ self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_APPEND_BLACKLIST - file: ', self.blacklist_file);
+ blacklist:write(self:expand_variables(self.blacklist_file_entry, event), '\n');
+ blacklist:close();
+end
+
+
+function Perimeter.execute_ban(self, event)
+ local command = self:expand_variables(self.ban_command, event);
+ self.log:debug('[', event.key, '/', event.sequence, '] PERIMETER_EXECUTE_BAN - command: ', command);
+ local result = os.execute(command);
+end
+
+function Perimeter.update_intruder(self, event)
+ require 'common.intruder';
+ local result = common.intruder.Intruder:new{ log = self.log, database = self.database }:update_blacklist(event);
+end
+
+
+function Perimeter.expand_variables(self, line, variables)
+ return (line:gsub('{([%a%d%._]+)}', function(captured)
+ return variables[captured] or '';
+ end))
+end
diff --git a/misc/freeswitch/scripts/common/sip_account.lua b/misc/freeswitch/scripts/common/sip_account.lua
index 8dd432b..d023f20 100644
--- a/misc/freeswitch/scripts/common/sip_account.lua
+++ b/misc/freeswitch/scripts/common/sip_account.lua
@@ -38,8 +38,12 @@ function SipAccount.find_by_sql(self, where)
`a`.`sip_accountable_id`, \
`a`.`hotdeskable`, \
`a`.`gs_node_id`, \
- `b`.`host` \
- FROM `sip_accounts` `a` JOIN `sip_domains` `b` ON `a`.`sip_domain_id` = `b`.`id` \
+ `b`.`host`, \
+ `c`.`sip_host`, \
+ `c`.`profile_name` \
+ FROM `sip_accounts` `a` \
+ JOIN `sip_domains` `b` ON `a`.`sip_domain_id` = `b`.`id` \
+ LEFT JOIN `sip_registrations` `c` ON `a`.`auth_name` = `c`.`sip_user` \
WHERE ' .. where .. ' LIMIT 1';
local sip_account = nil;
diff --git a/misc/freeswitch/scripts/common/str.lua b/misc/freeswitch/scripts/common/str.lua
index 793c191..72ff388 100644
--- a/misc/freeswitch/scripts/common/str.lua
+++ b/misc/freeswitch/scripts/common/str.lua
@@ -18,6 +18,23 @@ function try(array, arguments)
return result;
end
+
+function set(array, arguments, value)
+ local nop, arguments_count = arguments:gsub('%.', '');
+ local structure = array;
+ arguments:gsub('([^%.]+)', function(entry)
+ if arguments_count <= 0 then
+ structure[entry] = value;
+ elseif type(structure[entry]) == 'table' then
+ structure = structure[entry];
+ else
+ structure[entry] = {};
+ structure = structure[entry];
+ end
+ arguments_count = arguments_count - 1;
+ end);
+end
+
-- to number
function to_n(value)
value = tostring(value):gsub('[^%d%.%+%-]', '');
diff --git a/misc/freeswitch/scripts/configuration.lua b/misc/freeswitch/scripts/configuration.lua
index 062cf5d..75d0df3 100644
--- a/misc/freeswitch/scripts/configuration.lua
+++ b/misc/freeswitch/scripts/configuration.lua
@@ -63,7 +63,12 @@ function profile(database, sofia_ini, profile_name, index, domains, node_id)
require 'configuration.simple_xml'
local xml = configuration.simple_xml.SimpleXml:new();
- local parameters = sofia_ini['profile:' .. profile_name];
+ local profile_template = sofia_ini['profile'] or {};
+ local parameters = sofia_ini['profile:' .. profile_name] or {};
+
+ for key, value in pairs(profile_template) do
+ parameters[key] = parameters[key] or value;
+ end
if not parameters then
log:error('SOFIA_PROFILE ', index,' - name: ', profile_name, ' - no parameters');
@@ -134,9 +139,16 @@ function conf_sofia(database)
require 'configuration.sip'
local domains = configuration.sip.Sip:new{ log = log, database = database}:domains();
- sofia_profiles_xml = '';
+ local sofia_profiles = {};
for profile_name, index in pairs(sofia_ini.profiles) do
if tonumber(index) and tonumber(index) > 0 then
+ sofia_profiles[index] = profile_name;
+ end
+ end
+
+ local sofia_profiles_xml = '';
+ for index, profile_name in ipairs(sofia_profiles) do
+ if tonumber(index) and tonumber(index) > 0 then
sofia_profiles_xml = sofia_profiles_xml .. profile(database, sofia_ini, profile_name, tonumber(index), domains, local_node_id);
end
end
@@ -403,7 +415,7 @@ function directory_sip_account(database)
end
else
require 'common.sip_account'
- local sip_account = common.sip_account.SipAccount:new{ log = log, database = database}:find_by_auth_name(auth_name, domain);
+ local sip_account = common.sip_account.SipAccount:new{ log = log, database = database}:find_by_auth_name(auth_name);
require 'common.configuration_table'
local user_parameters = common.configuration_table.get(database, 'sip_accounts', 'parameters');
diff --git a/misc/freeswitch/scripts/dialplan/acd.lua b/misc/freeswitch/scripts/dialplan/acd.lua
index f4b298e..5ed8979 100644
--- a/misc/freeswitch/scripts/dialplan/acd.lua
+++ b/misc/freeswitch/scripts/dialplan/acd.lua
@@ -194,7 +194,7 @@ function AutomaticCallDistributor.agents_available(self, strategy)
local accounts = {}
self.database:query(sql_query, function(entry)
- if not entry.callstate then
+ if common.str.blank(entry.callstate) then
table.insert(accounts, entry);
end
end);
diff --git a/misc/freeswitch/scripts/dialplan/dialplan.lua b/misc/freeswitch/scripts/dialplan/dialplan.lua
index ff4adc6..72503e5 100644
--- a/misc/freeswitch/scripts/dialplan/dialplan.lua
+++ b/misc/freeswitch/scripts/dialplan/dialplan.lua
@@ -350,10 +350,10 @@ function Dialplan.set_caller_picture(self, entry_id, entry_type, image)
require 'dialplan.user'
local user = dialplan.user.User:new{ log = self.log, database = self.database }:find_by_id(entry_id);
if user then
- self.caller:set_variable('sip_h_Call-Info', '<' .. self.user_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(user.record.image) .. '>;purpose=icon');
+ self.caller:export_variable('sip_h_Call-Info', '<' .. self.user_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(user.record.image) .. '>;purpose=icon');
end
elseif entry_type == 'phonebookentry' and image then
- self.caller:set_variable('sip_h_Call-Info', '<' .. self.phone_book_entry_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(image) .. '>;purpose=icon');
+ self.caller:export_variable('sip_h_Call-Info', '<' .. self.phone_book_entry_image_url .. '/' .. tonumber(entry_id) .. '/snom_caller_picture_' .. tostring(image) .. '>;purpose=icon');
end
end
@@ -445,6 +445,8 @@ function Dialplan.dial(self, destination)
send_ringing = ( self.send_ringing_to_gateways and self.caller.from_gateway ),
bypass_media_network = self.config.parameters.bypass_media_network,
update_callee_display = self.config.parameters.update_callee_display,
+ detect_dtmf_after_bridge_caller = self.detect_dtmf_after_bridge_caller,
+ detect_dtmf_after_bridge_callee = self.detect_dtmf_after_bridge_callee,
}
);
end
@@ -759,7 +761,7 @@ function Dialplan.switch(self, destination)
elseif not common.str.blank(destination.number) then
local result = { continue = false, code = 404, phrase = 'No route' }
- local clip_no_screening = common.str.try(caller, 'account.record.clip_no_screening');
+ local clip_no_screening = common.str.try(self.caller, 'account.record.clip_no_screening');
self.caller.caller_id_numbers = {}
if not common.str.blank(clip_no_screening) then
for index, number in ipairs(common.str.strip_to_a(clip_no_screening, ',')) do
@@ -814,11 +816,13 @@ function Dialplan.switch(self, destination)
self.caller:set_callee_id(destination.callee_id_number, destination.callee_id_name);
for index, route in ipairs(routes) do
- if route.endpoint_type == 'hangup' then
- return { continue = false, code = route.endpoint, phrase = route.phrase, cause = route.value }
+ if route.type == 'hangup' then
+ self.log:notice('SWITCH_HANGUP - code: ', route.code, ', phrase: ', route.phrase, ', cause: ', route.cause);
+ return { continue = false, code = route.code or '404', phrase = route.phrase, cause = route.cause }
end
- if route.endpoint_type == 'forward' then
- return { continue = true, call_forwarding = { number = route.value, service = 'route', type = 'phonenumber' }}
+ if route.type == 'forward' then
+ self.log:notice('SWITCH_CALL_FORWARDING - number: ', route.number);
+ return { continue = true, call_forwarding = { number = route.number, service = 'route', type = 'phonenumber' }}
end
for key, value in pairs(route) do
diff --git a/misc/freeswitch/scripts/dialplan/dtmf.lua b/misc/freeswitch/scripts/dialplan/dtmf.lua
new file mode 100644
index 0000000..4dbd35f
--- /dev/null
+++ b/misc/freeswitch/scripts/dialplan/dtmf.lua
@@ -0,0 +1,69 @@
+-- Gemeinschaft 5 module: dtmf class
+-- (c) AMOOMA GmbH 2013
+--
+
+module(...,package.seeall)
+
+Dtmf = {}
+
+-- create dtmf object
+function Dtmf.new(self, arg)
+ arg = arg or {}
+ object = arg.object or {}
+ setmetatable(object, self);
+ self.__index = self;
+ self.class = 'Dtmf';
+ self.log = arg.log;
+ self.bleg = arg.bleg
+ self.digit_timeout = arg.digit_timeout or 5;
+ self.router = arg.router;
+
+ return object;
+end
+
+
+function Dtmf.detect(self, caller, sequence, digit, duration, calee)
+ local timestamp = os.time();
+ if timestamp - sequence.updated > self.digit_timeout then
+ sequence.digits = digit;
+ else
+ sequence.digits = sequence.digits .. digit;
+ end
+
+ caller.dtmf_digits = sequence.digits;
+
+ if calee then
+ self.log:debug('DTMF_RECEIVER callee - digit: [', digit, '][', duration, '], sequence: ', sequence.digits);
+ else
+ self.log:debug('DTMF_RECEIVER caller - digit: [', digit, '][', duration, '], sequence: ', sequence.digits);
+ end
+
+ local route = self.router:route_run('dtmf', true);
+ sequence.updated = timestamp;
+
+ if not route then
+ return;
+ end
+
+ if route.type == 'dialplanfunction' or route.type == 'phonenumber' or route.type == 'unknown' then
+ self:transfer(caller, route.destination_number, calee)
+ else
+ self.log:notice('DTMF_RECEIVER - unhandled destination: ', route.type, '=', route.id);
+ end
+end
+
+
+function Dtmf.transfer(self, caller, destination, calee)
+ require 'common.fapi'
+ local fapi = common.fapi.FApi:new{ log = log };
+ local callee_uuid = caller:to_s('bridge_to');
+
+ self.log:notice('DTMF_RECEIVER_TRANSFER - destination: ', destination, ', uuid: ', caller.uuid, ', callee_uuid: ', callee_uuid, ', callee_initiated: ', calee);
+ if calee then
+ caller:execute('transfer', destination);
+ fapi:execute('uuid_kill', callee_uuid);
+ else
+ fapi:execute('uuid_transfer', callee_uuid .. ' ' .. destination);
+ caller.session:hangup();
+ end
+end
diff --git a/misc/freeswitch/scripts/dialplan/functions.lua b/misc/freeswitch/scripts/dialplan/functions.lua
index 2ca51c8..4430be1 100644
--- a/misc/freeswitch/scripts/dialplan/functions.lua
+++ b/misc/freeswitch/scripts/dialplan/functions.lua
@@ -111,6 +111,8 @@ function Functions.dialplan_function(self, caller, dialed_number)
result = "+" .. tostring(parameters[3]);
elseif fid == "hangup" then
result = self:hangup(caller, parameters[3], parameters[4]);
+ elseif fid == "park" then
+ result = self:park(caller, parameters[3]);
end
return result;
@@ -264,7 +266,7 @@ function Functions.account_node_change(self, caller)
-- resync caller phones
for index, phone_caller in ipairs(caller_phones) do
- local result = phone_caller:resync{ auth_name = caller_sip_account.auth_name, domain = caller.domain };
+ local result = phone_caller:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host };
self.log:info('NODE_CHANGE - resync phone - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result);
end
@@ -302,6 +304,7 @@ function Functions.user_login(self, caller, number, pin)
if not caller_phone then
self.log:notice('LOGIN - caller phone not found or not hot-deskable');
+ local result = phone_class:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host };
return { continue = false, code = 403, phrase = 'Phone not hot-deskable', no_cdr = true }
end
@@ -374,13 +377,13 @@ function Functions.user_login(self, caller, number, pin)
-- resync destination phones
for index, phone_destination in ipairs(destination_phones) do
- local result = phone_destination:resync{ auth_name = destination_sip_account.auth_name, domain = caller.domain_local };
+ local result = phone_destination:resync{ auth_name = destination_sip_account.record.auth_name, domain = destination_sip_account.record.host };
self.log:info('LOGIN - resync destination phone - mac: ', phone_destination.record.mac_address, ', ip_address: ', phone_destination.record.ip_address, ', result: ', result);
end
-- resync caller phones
for index, phone_caller in ipairs(caller_phones) do
- local result = phone_caller:resync{ auth_name = caller_sip_account.auth_name, domain = caller.domain };
+ local result = phone_caller:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host };
self.log:info('LOGIN - resync caller phone - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result);
end
@@ -409,8 +412,9 @@ function Functions.user_logout(self, caller)
local caller_phones = phone_class:find_all_hot_deskable_by_account(caller_sip_account.id);
- if caller_phones == 0 then
+ if #caller_phones == 0 then
self.log:notice('LOGOUT - caller phones not found or not hot-deskable');
+ local result = phone_class:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host };
return { continue = false, code = 403, phrase = 'Phone not hot-deskable', no_cdr = true }
end
@@ -426,7 +430,7 @@ function Functions.user_logout(self, caller)
-- resync caller phones
for index, phone_caller in ipairs(caller_phones) do
- local result = phone_caller:resync{ auth_name = caller_sip_account.auth_name, domain = caller.domain };
+ local result = phone_caller:resync{ auth_name = caller_sip_account.record.auth_name, domain = caller_sip_account.record.host };
self.log:info('LOGIN - resync caller phone - mac: ', phone_caller.record.mac_address, ', ip_address: ', phone_caller.record.ip_address, ', result: ', result);
end
@@ -909,3 +913,9 @@ function Functions.hangup(self, caller, code, phrase)
self.log:info("FUNCTION_HANGUP code: ", code, ', phrase: ', phrase);
return { continue = false, code = code, phrase = phrase:gsub('_', ' '), no_cdr = true }
end
+
+function Functions.park(self, caller, lot)
+ self.log:info("FUNCTION_PARK lot: ", lot);
+ caller:execute("valet_park", 'valet_lot ' .. lot);
+ return { continue = false, code = 200, phrase = 'OK', no_cdr = true }
+end
diff --git a/misc/freeswitch/scripts/dialplan/hunt_group.lua b/misc/freeswitch/scripts/dialplan/hunt_group.lua
index 2c73bf8..fa3c05b 100644
--- a/misc/freeswitch/scripts/dialplan/hunt_group.lua
+++ b/misc/freeswitch/scripts/dialplan/hunt_group.lua
@@ -98,6 +98,18 @@ function HuntGroup.run(self, dialplan_object, caller, destination)
self.log:info('HUNTGROUP ', self.record.id, ' - name: ', self.record.name, ', strategy: ', self.record.strategy,', members: ', #hunt_group_members);
+ local clip_no_screening = common.str.try(caller, 'account.record.clip_no_screening');
+ caller.caller_id_numbers = {}
+ if not common.str.blank(clip_no_screening) then
+ for index, number in ipairs(common.str.strip_to_a(clip_no_screening, ',')) do
+ table.insert(caller.caller_id_numbers, number);
+ end
+ end
+ for index, number in ipairs(caller.caller_phone_numbers) do
+ table.insert(caller.caller_id_numbers, number);
+ end
+ self.log:info('CALLER_ID_NUMBERS - clir: ', caller.clir, ', numbers: ', table.concat(caller.caller_id_numbers, ','));
+
local save_destination = caller.destination;
local destinations = {}
@@ -172,6 +184,7 @@ function HuntGroup.run(self, dialplan_object, caller, destination)
self.log:info('HUNTGROUP ', self.record.id, ' - all members busy');
run_queue = false;
end
+ caller:sleep(500);
end
else
if forwarding_destination then
diff --git a/misc/freeswitch/scripts/dialplan/router.lua b/misc/freeswitch/scripts/dialplan/router.lua
index cdcb58b..bda80a7 100644
--- a/misc/freeswitch/scripts/dialplan/router.lua
+++ b/misc/freeswitch/scripts/dialplan/router.lua
@@ -18,11 +18,16 @@ function Router.new(self, arg)
self.routes = arg.routes or {};
self.caller = arg.caller;
self.variables = arg.variables or {};
+ self.routing_tables = {};
return object;
end
-function Router.read_table(self, table_name)
+function Router.read_table(self, table_name, force_reload)
+ if not force_reload and self.routing_tables[table_name] then
+ return self.routing_tables[table_name];
+ end
+
local routing_table = {};
local sql_query = 'SELECT * \
@@ -48,6 +53,8 @@ function Router.read_table(self, table_name)
});
end);
+ self.routing_tables[table_name] = routing_table;
+
return routing_table;
end
@@ -143,7 +150,7 @@ function Router.route_match(self, route)
if not common.str.blank(element.var_out) then
local command, variable_name = common.str.partition(element.var_out, ':');
if not command or not variable_name or command == 'var' then
- destination[element.var_out] = replacement;
+ common.str.set(destination, element.var_out, replacement);
elseif command == 'chv' then
destination.channel_variables[variable_name] = replacement;
elseif command == 'hdr' then
@@ -159,6 +166,7 @@ function Router.route_match(self, route)
end
if route_matches then
+ destination.number = destination.number or destination.destination_number;
return destination;
end;
diff --git a/misc/freeswitch/scripts/dialplan/sip_call.lua b/misc/freeswitch/scripts/dialplan/sip_call.lua
index d1557e9..b56f1b2 100644
--- a/misc/freeswitch/scripts/dialplan/sip_call.lua
+++ b/misc/freeswitch/scripts/dialplan/sip_call.lua
@@ -95,39 +95,50 @@ function SipCall.fork(self, destinations, arg )
table.insert(origination_variables, 'ignore_display_updates=true');
end
- if not destination.node_local then
+ if not destination.node_local or destination.type == 'node' then
require 'common.node'
- local node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.node_id);
- if node then
- table.insert(origination_variables, 'sip_h_X-GS_node_id=' .. self.caller.local_node_id);
- table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/gateway/' .. node.record.name .. '/' .. destination.number);
+ local node = nil;
+
+ if not destination.node_local then
+ node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.node_id);
+ else
+ node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.id);
end
- elseif destination.type == 'node' then
- local node = common.node.Node:new{ log = self.log, database = self.database }:find_by_id(destination.id);
if node then
table.insert(origination_variables, 'sip_h_X-GS_node_id=' .. self.caller.local_node_id);
+ table.insert(origination_variables, 'sip_h_X-GS_account_uuid=' .. tostring(self.caller.account_uuid));
+ table.insert(origination_variables, 'sip_h_X-GS_account_type=' .. tostring(self.caller.account_type));
+ table.insert(origination_variables, 'sip_h_X-GS_auth_account_type=' .. tostring(self.caller.auth_account_type));
+ table.insert(origination_variables, 'sip_h_X-GS_auth_account_uuid=' .. tostring(self.caller.auth_account_uuid));
+ table.insert(origination_variables, 'sip_h_X-GS_loop_count=' .. tostring(self.caller.loop_count));
table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/gateway/' .. node.record.name .. '/' .. destination.number);
end
elseif destination.type == 'sipaccount' then
local callee_id_params = '';
local sip_account = sip_account_class:find_by_id(destination.id);
- local call_waiting = self:call_waiting_busy(sip_account);
- if not call_waiting then
- destinations[index].numbers = sip_account:phone_numbers();
+ if not sip_account then
+ self.log:notice('FORK - sip_account not found - sip_account=', destination.id);
+ elseif common.str.blank(sip_account.record.profile_name) or common.str.blank(sip_account.record.sip_host) then
+ call_result = { code = 480, phrase = 'User offline', disposition = 'USER_NOT_REGISTERED' };
+ else
+ local call_waiting = self:call_waiting_busy(sip_account);
+ if not call_waiting then
+ destinations[index].numbers = sip_account:phone_numbers();
- if not arg.callee_id_name then
- table.insert(origination_variables, "effective_callee_id_name='" .. sip_account.record.caller_name .. "'");
- end
- if not arg.callee_id_number then
- table.insert(origination_variables, "effective_callee_id_number='" .. destination.number .. "'");
- end
- if destination.alert_info then
- table.insert(origination_variables, "alert_info='" .. destination.alert_info .. "'");
+ if not arg.callee_id_name then
+ table.insert(origination_variables, "effective_callee_id_name='" .. sip_account.record.caller_name .. "'");
+ end
+ if not arg.callee_id_number then
+ table.insert(origination_variables, "effective_callee_id_number='" .. destination.number .. "'");
+ end
+ if destination.alert_info then
+ table.insert(origination_variables, "alert_info='" .. destination.alert_info .. "'");
+ end
+ table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/' .. sip_account.record.profile_name .. '/' .. sip_account.record.auth_name .. '%' .. sip_account.record.sip_host);
+ else
+ some_destinations_busy = true;
+ call_result = { code = 486, phrase = 'User busy', disposition = 'USER_BUSY' };
end
- table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']user/' .. sip_account.record.auth_name);
- else
- some_destinations_busy = true;
- call_result = { code = 486, phrase = 'User busy', disposition = 'USER_BUSY' };
end
elseif destination.type == 'gateway' then
require 'common.gateway'
@@ -169,11 +180,6 @@ function SipCall.fork(self, destinations, arg )
end
self.caller:set_callee_id(arg.callee_id_number, arg.callee_id_name);
- self.caller:set_header('X-GS_account_uuid', self.caller.account_uuid);
- self.caller:set_header('X-GS_account_type', self.caller.account_type);
- self.caller:set_header('X-GS_auth_account_type', self.caller.auth_account_type);
- self.caller:set_header('X-GS_auth_account_uuid', self.caller.auth_account_uuid);
- self.caller:set_header('X-GS_loop_count', self.caller.loop_count);
self.caller:set_variable('call_timeout', arg.timeout );
self.log:info('FORK DIAL - destinations: ', #dial_strings, ', timeout: ', arg.timeout);
@@ -195,6 +201,12 @@ function SipCall.fork(self, destinations, arg )
fork_index = tonumber(session_callee:getVariable('gs_fork_index')) or 0;
local destination = destinations[fork_index];
+ if arg.detect_dtmf_after_bridge_caller then
+ session:execute('start_dtmf');
+ end
+ if arg.detect_dtmf_after_bridge_callee then
+ session_callee:execute('start_dtmf');
+ end
if arg.bypass_media_network then
local callee_uuid = session_callee:get_uuid();
@@ -226,10 +238,15 @@ function SipCall.fork(self, destinations, arg )
self.caller:set_variable('gs_destination_id', destination.id);
self.caller:set_variable('gs_destination_uuid', destination.uuid);
+ if arg.detect_dtmf_after_bridge_callee then
+ session_callee:setInputCallback('input_call_back_callee', 'session_callee');
+ end
+
self.log:info('FORK ', fork_index,
' BRIDGE - destination: ', destination.type, '=', destination.id, '/', destination.uuid,'@', destination.node_id,
', number: ', destination.number,
', dial_time: ', os.time() - start_time);
+
freeswitch.bridge(self.caller.session, session_callee);
self:wait_hangup(self.caller.session, session_callee);
end
diff --git a/misc/freeswitch/scripts/dialplan_default.lua b/misc/freeswitch/scripts/dialplan_default.lua
index 7caff57..8fb9057 100644
--- a/misc/freeswitch/scripts/dialplan_default.lua
+++ b/misc/freeswitch/scripts/dialplan_default.lua
@@ -8,13 +8,28 @@ function hangup_hook_caller(s, status, arg)
if tostring(status) == 'transfer' then
if start_caller and start_caller.destination then
log:info('CALL_TRANSFERRED - destination was: ', start_caller.destination.type, '=', start_caller.destination.id,', number: ' .. tostring(start_caller.destination.number) .. ', to: ' .. start_caller:to_s('sip_refer_to'));
- start_caller.auth_account = start_dialplan:object_find(start_caller.destination.type, start_caller.destination.id);
+ start_caller.auth_account = start_caller.dialplan:object_find(start_caller.destination.type, start_caller.destination.id);
start_caller.forwarding_number = start_caller.destination.number;
start_caller.forwarding_service = 'transfer';
end
end
end
+function input_call_back_caller(s, object_type, object_data, arg)
+ if object_type == 'dtmf' then
+ require 'dialplan.dtmf'
+ local dtmf = dialplan.dtmf.Dtmf:new{ log = log, router = dtmf_router }:detect(start_caller, start_caller.dtmf, object_data.digit, object_data.duration);
+ end
+end
+
+function input_call_back_callee(s, object_type, object_data, arg)
+ if object_type == 'dtmf' then
+ require 'dialplan.dtmf'
+ local dtmf = dialplan.dtmf.Dtmf:new{ log = log, router = dtmf_router }:detect(start_caller, start_caller.dtmf_callee, object_data.digit, object_data.duration, true);
+ end
+end
+
+
-- initialize logging
require 'common.log'
log = common.log.Log:new{ prefix = '### [' .. session:get_uuid() .. '] ' };
@@ -36,8 +51,17 @@ require 'dialplan.dialplan'
local start_dialplan = dialplan.dialplan.Dialplan:new{ log = log, caller = start_caller, database = database };
start_dialplan:configuration_read();
+start_caller.dialplan = start_dialplan;
start_caller.local_node_id = start_dialplan.node_id;
start_caller:init_channel_variables();
+start_caller.dtmf = {
+ updated = os.time(),
+ digits = '';
+};
+start_caller.dtmf_callee = {
+ updated = os.time(),
+ digits = '';
+};
if start_dialplan.config.parameters.dump_variables then
start_caller:execute('info', 'notice');
@@ -72,6 +96,17 @@ if start_caller.from_node then
else
start_destination = { type = 'unknown' }
start_caller.session:setHangupHook('hangup_hook_caller', 'destination_number');
+
+ require 'dialplan.router'
+ dtmf_router = dialplan.router.Router:new{ log = log, database = database, caller = start_caller, variables = start_caller };
+ start_dialplan.dtmf_detection = #dtmf_router:read_table('dtmf') > 0;
+
+ if start_dialplan.dtmf_detection then
+ start_dialplan.detect_dtmf_after_bridge_caller = true;
+ start_dialplan.detect_dtmf_after_bridge_callee = true;
+ start_caller.session:setInputCallback('input_call_back_caller', 'start_dialplan');
+ end
+
start_dialplan:run(start_destination);
end
diff --git a/misc/freeswitch/scripts/event/dump_variables.lua b/misc/freeswitch/scripts/event/dump_variables.lua
new file mode 100644
index 0000000..96eb8f7
--- /dev/null
+++ b/misc/freeswitch/scripts/event/dump_variables.lua
@@ -0,0 +1,52 @@
+-- Gemeinschaft 5 module: dump_variables event handler class
+-- (c) AMOOMA GmbH 2012-2013
+--
+
+module(...,package.seeall)
+
+
+function handler_class()
+ return DumpVariables
+end
+
+
+DumpVariables = {}
+
+
+function DumpVariables.new(self, arg)
+ arg = arg or {}
+ object = arg.object or {}
+ setmetatable(object, self);
+ self.__index = self;
+ self.log = arg.log;
+ self.class = 'DumpVariables'
+ self.dump_file = arg.file or '/var/log/freeswitch/variables';
+
+ return object;
+end
+
+
+function DumpVariables.event_handlers(self)
+ return { CHANNEL_CREATE = { [true] = self.channel_data } }
+end
+
+
+function DumpVariables.channel_data(self, event)
+ local sequence = event:getHeader('Event-Sequence');
+ local direction = event:getHeader('Call-Direction');
+
+ if not direction or direction ~= 'inbound' then
+ return;
+ end
+
+ local file = io.open(self.dump_file, 'w');
+ if not file then
+ self.log:error('[', event.sequence, '] DUMP_VARIABLES - could not open file for writing: ', self.dump_file);
+ return;
+ end
+
+ self.log:debug('[', event.sequence, '] DUMP_VARIABLES - dumping channel data to: ', self.dump_file);
+
+ file:write(event:serialize(), '\n');
+ file:close();
+end
diff --git a/misc/freeswitch/scripts/event/event.lua b/misc/freeswitch/scripts/event/event.lua
index 08d8bfe..652fc48 100644
--- a/misc/freeswitch/scripts/event/event.lua
+++ b/misc/freeswitch/scripts/event/event.lua
@@ -16,29 +16,40 @@ function EventManager.new(self, arg)
self.class = 'eventmanager'
self.database = arg.database;
self.domain = arg.domain;
+ self.consumer = arg.consumer;
return object;
end
function EventManager.register(self)
- self.consumer = freeswitch.EventConsumer('all');
+ if not self.consumer then
+ self.consumer = freeswitch.EventConsumer('all');
+ end
return (self.consumer ~= nil);
end
-function EventManager.load_event_modules(self)
- require 'common.configuration_table'
- self.config = common.configuration_table.get(self.database, 'events');
+function EventManager.load_event_modules(self, modules)
+ local event_modules = {};
+
+ for module_name, index in pairs(modules) do
+ if tonumber(index) and index > 0 then
+ event_modules[index] = module_name;
+ self.log:debug('[event] EVENT_MANAGER - enabled handler module: ', module_name);
+ else
+ self.log:debug('[event] EVENT_MANAGER - disabled handler module: ', module_name);
+ end
+ end
- return self.config.modules;
+ return event_modules;
end
function EventManager.load_event_handlers(self, event_modules)
event_handlers = {}
-
- for event_module_name, index in pairs(event_modules) do
+ for index, event_module_name in ipairs(event_modules) do
+ package.loaded['event.' .. event_module_name] = nil;
event_module = require('event.' .. event_module_name);
if event_module then
self.log:info('[event] EVENT_MANAGER - loading handler module: ', event_module_name);
@@ -71,8 +82,12 @@ end
function EventManager.run(self)
+ require 'common.configuration_table'
+ self.config = common.configuration_table.get(self.database, 'events');
+
+ local event_modules = self:load_event_modules(self.config.modules);
+ self.log:info('[event] EVENT_MANAGER_START - handler modules: ', #event_modules);
- local event_modules = self:load_event_modules();
local event_handlers = self:load_event_handlers(event_modules);
if not event_handlers then
@@ -104,4 +119,6 @@ function EventManager.run(self)
end
end
end
+
+ self.log:info('[event] EVENT_MANAGER_EXIT - action: ', freeswitch.getGlobalVariable('gs_event_manager'));
end
diff --git a/misc/freeswitch/scripts/event/perimeter.lua b/misc/freeswitch/scripts/event/perimeter.lua
deleted file mode 100644
index 5bbb032..0000000
--- a/misc/freeswitch/scripts/event/perimeter.lua
+++ /dev/null
@@ -1,107 +0,0 @@
--- Gemeinschaft 5 module: cdr event handler class
--- (c) AMOOMA GmbH 2012-2013
---
-
-module(...,package.seeall)
-
-
-function handler_class()
- return Perimeter
-end
-
-
-
-Perimeter = {}
-
-MALICIOUS_CONTACT_COUNT = 20;
-MALICIOUS_CONTACT_TIME_SPAN = 2;
-BAN_FUTILE = 2;
-
-function Perimeter.new(self, arg)
- arg = arg or {}
- object = arg.object or {}
- setmetatable(object, self);
- self.__index = self;
- self.log = arg.log;
- self.class = 'cdrsave'
- self.database = arg.database;
- self.domain = arg.domain;
-
- self.ip_address_table = {}
- self:init();
-
- return object;
-end
-
-
-function Perimeter.event_handlers(self)
- return { CUSTOM = { ['sofia::pre_register'] = self.sofia_pre_register } }
-end
-
-
-function Perimeter.init(self)
- require 'common.configuration_table';
- local config = common.configuration_table.get(self.database, 'perimeter');
- if config and config.general then
- self.malicious_contact_count = tonumber(config.general.malicious_contact_count) or MALICIOUS_CONTACT_COUNT;
- self.malicious_contact_time_span = tonumber(config.general.malicious_contact_time_span) or MALICIOUS_CONTACT_TIME_SPAN;
- self.ban_futile = tonumber(config.general.ban_futile) or BAN_FUTILE;
- self.execute = config.general.execute;
- end
-
- self.log:info('[perimeter] PERIMETER - setup perimeter defense - config: ', self.malicious_contact_count, '/', self.malicious_contact_time_span, ', execute: ', self.execute);
-end
-
-
-function Perimeter.sofia_pre_register(self, event)
- local ip_address = event:getHeader('network-ip');
- self:check_ip(ip_address);
-end
-
-
-function Perimeter.check_ip(self, ip_address)
- local event_time = os.time();
-
- if not self.ip_address_table[ip_address] then
- self.ip_address_table[ip_address] = { last_contact = event_time, contact_count = 0, start_stamp = event_time, banned = 0 }
- end
-
- local ip_record = self.ip_address_table[ip_address];
- ip_record.last_contact = event_time;
- ip_record.contact_count = ip_record.contact_count + 1;
-
- if ip_record.contact_count > MALICIOUS_CONTACT_COUNT then
- if (event_time - ip_record.start_stamp) <= MALICIOUS_CONTACT_TIME_SPAN then
- self.log:warning('[', ip_address, '] PERIMETER - too many registration attempts');
- ip_record.start_stamp = event_time;
- ip_record.contact_count = 0;
- if ip_record.banned < BAN_FUTILE then
- ip_record.banned = ip_record.banned + 1;
- self:ban_ip(ip_address);
- else
- self.log:error('[', ip_address, '] PERIMETER - ban futile');
- end
- end
- end
-end
-
-
-function Perimeter.ban_ip(self, ip_address)
- self.ip_address = ip_address;
-
- if self.execute then
- local command = self:expand_variables(self.execute);
- self.log:debug('[', ip_address, '] PERIMETER - execute: ', command);
- local result = os.execute(command);
- if tostring(result) == '0' then
- self.log:warning('[', ip_address, '] PERIMETER - IP banned');
- end
- end
-end
-
-
-function Perimeter.expand_variables(self, line)
- return (line:gsub('{([%a%d_-]+)}', function(captured)
- return self[captured];
- end))
-end
diff --git a/misc/freeswitch/scripts/event/perimeter_defense.lua b/misc/freeswitch/scripts/event/perimeter_defense.lua
new file mode 100644
index 0000000..acdfa8d
--- /dev/null
+++ b/misc/freeswitch/scripts/event/perimeter_defense.lua
@@ -0,0 +1,114 @@
+-- Gemeinschaft 5 module: perimeter defense event handler class
+-- (c) AMOOMA GmbH 2013
+--
+
+module(...,package.seeall)
+
+function handler_class()
+ return PerimeterDefense
+end
+
+PerimeterDefense = {}
+
+function PerimeterDefense.new(self, arg)
+ arg = arg or {}
+ object = arg.object or {}
+ setmetatable(object, self);
+ self.__index = self;
+ self.log = arg.log;
+ self.class = 'perimeterdefense'
+ self.database = arg.database;
+ self.domain = arg.domain;
+
+ require 'common.perimeter';
+ self.perimeter = common.perimeter.Perimeter:new(arg);
+ self.perimeter:setup();
+
+ return object;
+end
+
+
+function PerimeterDefense.event_handlers(self)
+ return {
+ CUSTOM = {
+ ['sofia::pre_register'] = self.sofia_pre_register,
+ ['sofia::register_attempt'] = self.sofia_register_attempt,
+ ['sofia::register_failure'] = self.sofia_register_failure,
+ },
+ CHANNEL_HANGUP = { [true] = self.channel_hangup },
+ };
+end
+
+
+function PerimeterDefense.to_register_record(self, event, class)
+ return {
+ action = 'register',
+ class = class,
+ key = event:getHeader('network-ip'),
+ sequence = tonumber(event:getHeader('Event-Sequence')),
+ timestamp = tonumber(event:getHeader('Event-Date-Timestamp')),
+ received_ip = event:getHeader('network-ip'),
+ received_port = event:getHeader('network-port'),
+ from_user = event:getHeader('from-user'),
+ from_host = event:getHeader('from-host'),
+ to_user = event:getHeader('to-user'),
+ to_host = event:getHeader('to-host'),
+ user_agent = event:getHeader('user-agent'),
+ username = event:getHeader('username'),
+ realm = event:getHeader('realm'),
+ auth_result = event:getHeader('auth-result'),
+ contact = event:getHeader('contact'),
+ };
+end
+
+
+function PerimeterDefense.to_call_record(self, event, class)
+ return {
+ action = 'call',
+ class = class,
+ key = event:getHeader('Caller-Network-Addr'),
+ sequence = tonumber(event:getHeader('Event-Sequence')),
+ timestamp = tonumber(event:getHeader('Event-Date-Timestamp')),
+ received_ip = event:getHeader('Caller-Network-Addr'),
+ received_port = event:getHeader('variable_sip_network_port'),
+ hangup_cause = event:getHeader('Hangup-Cause'),
+ endpoint_disposition = event:getHeader('variable_endpoint_disposition'),
+ direction = event:getHeader('Call-Direction'),
+ destination_number = event:getHeader('Caller-Destination-Number');
+ caller_id_name = event:getHeader('Caller-Caller-ID-Name');
+ caller_id_number = event:getHeader('Caller-Caller-ID-Number');
+ from_user = event:getHeader('variable_sip_from_user'),
+ from_host = event:getHeader('variable_sip_from_host'),
+ to_user = event:getHeader('variable_sip_to_user'),
+ to_host = event:getHeader('variable_sip_to_host'),
+ req_user = event:getHeader('variable_sip_req_user'),
+ req_host = event:getHeader('variable_sip_req_host'),
+ user_agent = event:getHeader('variable_sip_user_agent'),
+ username = event:getHeader('Caller-Username'),
+ contact = event:getHeader('variable_sip_contact_uri'),
+ };
+end
+
+
+function PerimeterDefense.sofia_pre_register(self, event)
+ local record = self:to_register_record(event, 'pre_register');
+ self.perimeter:check(record);
+end
+
+
+function PerimeterDefense.sofia_register_attempt(self, event)
+ local record = self:to_register_record(event, 'register_attempt');
+ self.perimeter:check(record);
+end
+
+
+function PerimeterDefense.sofia_register_failure(self, event)
+ local record = self:to_register_record(event, 'register_failure');
+ self.perimeter:check(record);
+end
+
+
+function PerimeterDefense.channel_hangup(self, event)
+ local record = self:to_call_record(event, 'channel_hangup');
+ self.perimeter:check(record);
+end
diff --git a/misc/freeswitch/scripts/event_manager.lua b/misc/freeswitch/scripts/event_manager.lua
index 1e61baf..3991f8f 100644
--- a/misc/freeswitch/scripts/event_manager.lua
+++ b/misc/freeswitch/scripts/event_manager.lua
@@ -7,12 +7,12 @@ require "common.log"
local log = common.log.Log:new()
log.prefix = "#E# "
-log:info('[event] EVENT_MANAGER start');
+log:info('[event] EVENT_MANAGER_LOADER start');
require 'common.database'
local database = common.database.Database:new{ log = log }:connect();
if not database:connected() then
- log:error('[event] EVENT_MANAGER - cannot connect to Gemeinschaft database');
+ log:error('[event] EVENT_MANAGER_LOADER - cannot connect to Gemeinschaft database');
return;
end
@@ -23,16 +23,23 @@ local domain = '127.0.0.1';
if domains[1] then
domain = domains[1]['host'];
else
- log:error('[event] EVENT_MANAGER - No SIP domains found!');
+ log:error('[event] EVENT_MANAGER_LOADER - No SIP domains found!');
end
-require 'event.event'
-local event_manager = event.event.EventManager:new{ log = log, database = database, domain = domain }
-event_manager:run();
+local event_consumer = nil;
+freeswitch.setGlobalVariable('gs_event_manager', 'true');
+while freeswitch.getGlobalVariable('gs_event_manager') ~= 'false' do
+ package.loaded['event.event'] = nil;
+ local manager_class = require('event.event');
+ local event_manager = manager_class.EventManager:new{ log = log, database = database, domain = domain, consumer = event_consumer };
+ freeswitch.setGlobalVariable('gs_event_manager', 'true');
+ event_manager:run();
+ event_consumer = event_manager.consumer;
+end
-- ensure database handle is released on exit
if database then
database:release();
end
-log:info('[event] EVENT_MANAGER exit');
+log:info('[event] EVENT_MANAGER_LOADER exit');
diff --git a/misc/freeswitch/scripts/fax_daemon.lua b/misc/freeswitch/scripts/fax_daemon.lua
index 94d343a..0784890 100644
--- a/misc/freeswitch/scripts/fax_daemon.lua
+++ b/misc/freeswitch/scripts/fax_daemon.lua
@@ -5,38 +5,37 @@
local MAIN_LOOP_SLEEP_TIME = 30;
-- Set logger
-require "common.log"
+require 'common.log'
local log = common.log.Log:new()
-log.prefix = "### [faxdaemon] "
+log.prefix = '#F# [faxdaemon] '
-log:debug('Starting fax daemon');
+log:info('FAX_DAEMON start');
-local database = nil;
-local api = freeswitch.API();
+require 'common.database'
+local database = common.database.Database:new{ log = log }:connect();
+if not database:connected() then
+ log:error('FAX_DAEMON - cannot connect to Gemeinschaft database');
+ return;
+end
+local api = freeswitch.API();
+require 'dialplan.fax'
freeswitch.setGlobalVariable('gs_fax_daemon', 'true');
+
while freeswitch.getGlobalVariable("gs_fax_daemon") == 'true' do
- require 'common.database'
- local database = common.database.Database:new{ log = log }:connect();
-
- if not database:connected() then
- log:error("connection to Gemeinschaft database lost - retry in " .. MAIN_LOOP_SLEEP_TIME .. " seconds")
- else
- require 'dialplan.fax'
- local fax_documents = dialplan.fax.Fax:new{log=log, database=database}:queued_for_sending();
-
- for key, fax_document in pairs(fax_documents) do
- if table.getn(fax_document.destination_numbers) > 0 and tonumber(fax_document.retry_counter) > 0 then
- log:debug('FAX_DAEMON_LOOP - fax_document=', fax_document.id, '/', fax_document.uuid, ', number: ' .. fax_document.destination_numbers[1]);
- local result = api:executeString('luarun send_fax.lua ' .. fax_document.id);
- end
+ local fax_documents = dialplan.fax.Fax:new{log=log, database=database}:queued_for_sending();
+
+ for key, fax_document in pairs(fax_documents) do
+ if table.getn(fax_document.destination_numbers) > 0 and tonumber(fax_document.retry_counter) > 0 then
+ log:debug('FAX_DAEMON_LOOP - fax_document=', fax_document.id, '/', fax_document.uuid, ', number: ' .. fax_document.destination_numbers[1]);
+ local result = api:executeString('luarun send_fax.lua ' .. fax_document.id);
end
end
- database:release();
-
+
if freeswitch.getGlobalVariable("gs_fax_daemon") == 'true' then
freeswitch.msleep(MAIN_LOOP_SLEEP_TIME * 1000);
end
end
-log:debug('Exiting fax daemon');
+database:release();
+log:info('FAX_DAEMON exit');
diff --git a/misc/freeswitch/scripts/http_request.lua b/misc/freeswitch/scripts/http_request.lua
index 1d6f791..a74b4d8 100644
--- a/misc/freeswitch/scripts/http_request.lua
+++ b/misc/freeswitch/scripts/http_request.lua
@@ -29,7 +29,7 @@ end
local success, result, response_headers = http.request{url = url, headers = headers };
-if success then
+if success and tostring(result) == '200' then
log:debug('HTTP_REQUEST - url: ', url, ', auth: ', tostring(headers.Authorization ~= nil), ', result: ', result);
else
log:notice('HTTP_REQUEST - url: ', url, ', auth: ', tostring(headers.Authorization ~= nil), ', result: ', result);
diff --git a/misc/freeswitch/scripts/phones/phone.lua b/misc/freeswitch/scripts/phones/phone.lua
index 6da20f0..57997ba 100644
--- a/misc/freeswitch/scripts/phones/phone.lua
+++ b/misc/freeswitch/scripts/phones/phone.lua
@@ -115,8 +115,9 @@ end
function Phone.resync(self, arg)
if not self.model then
- self.log:notice('PHONE_RESYNC - unsupported phone model');
- return false;
+ self.log:notice('PHONE_RESYNC phone model not found - trying Snom resync');
+ require 'phones.snom'
+ return phones.snom.Snom:new{ log = self.log }:resync(arg);
end
arg.ip_address = arg.ip_address or self.record.ip_address;
diff --git a/misc/freeswitch/scripts/send_fax.lua b/misc/freeswitch/scripts/send_fax.lua
index 9b6ffce..4898cb8 100644
--- a/misc/freeswitch/scripts/send_fax.lua
+++ b/misc/freeswitch/scripts/send_fax.lua
@@ -6,9 +6,9 @@ local FAX_FILE_PATH = "/opt/GS5/public/uploads/fax_document/tiff/";
local FAX_ANSWERING_TIMEOUT = 20;
-- Set logger
-require "common.log"
+require 'common.log'
local log = common.log.Log:new()
-log.prefix = "### [sendfax] "
+log.prefix = '#F# [sendfax] '
local document_id = argv[1];
@@ -16,12 +16,12 @@ require 'common.database'
local database = common.database.Database:new{ log = log }:connect();
if not database:connected() then
- log:error('cannot connect to Gemeinschaft database');
+ log:error('FAX_SEND - cannot connect to Gemeinschaft database');
return
end
if not tonumber(document_id) then
- log:error('document id not specified');
+ log:error('FAX_SEND - document id not specified');
return
end
@@ -32,7 +32,7 @@ local fax_class = dialplan.fax.Fax:new(defaults);
local fax_document = fax_class:find_document_by_id(document_id);
if not fax_document then
- log:error('document ' .. document_id .. ' not found');
+ log:error('FAX_SEND - document ' .. document_id .. ' not found');
return
end
@@ -45,14 +45,14 @@ end
local fax_account = fax_class:find_by_id(fax_document.fax_account_id);
if not fax_account then
- log:error('fax account ' .. fax_document.fax_account_id .. ' not found');
+ log:error('FAX_SEND - fax account ' .. fax_document.fax_account_id .. ' not found');
return
end
local destination_number = fax_class:destination_number(document_id);
if not destination_number or tostring(destination_number) == '' then
- log:error('destination number not found');
+ log:error('FAX_SEND - destination number not found');
return
end