summaryrefslogtreecommitdiff
path: root/misc/freeswitch/scripts/common
diff options
context:
space:
mode:
Diffstat (limited to 'misc/freeswitch/scripts/common')
-rw-r--r--misc/freeswitch/scripts/common/array.lua97
-rw-r--r--misc/freeswitch/scripts/common/conference.lua364
-rw-r--r--misc/freeswitch/scripts/common/database.lua23
-rw-r--r--misc/freeswitch/scripts/common/gateway.lua79
-rw-r--r--misc/freeswitch/scripts/common/intruder.lua43
-rw-r--r--misc/freeswitch/scripts/common/log.lua25
-rw-r--r--misc/freeswitch/scripts/common/object.lua12
-rw-r--r--misc/freeswitch/scripts/common/perimeter.lua44
-rw-r--r--misc/freeswitch/scripts/common/sip_account.lua6
-rw-r--r--misc/freeswitch/scripts/common/str.lua51
10 files changed, 507 insertions, 237 deletions
diff --git a/misc/freeswitch/scripts/common/array.lua b/misc/freeswitch/scripts/common/array.lua
new file mode 100644
index 0000000..b1b7a71
--- /dev/null
+++ b/misc/freeswitch/scripts/common/array.lua
@@ -0,0 +1,97 @@
+-- Gemeinschaft 5 module: array functions
+-- (c) AMOOMA GmbH 2013
+--
+
+module(...,package.seeall)
+
+function try(array, arguments)
+ if type(arguments) ~= 'string' or type(array) ~= 'table' then
+ return nil;
+ end
+
+ local result = array;
+
+ arguments:gsub('([^%.]+)', function(entry)
+ local success, result = pcall(function() result = (result[tonumber(entry) or entry]); end);
+ end);
+
+ 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
+
+
+function expand_variable(variable_path, variable_sets)
+ for index=1, #variable_sets do
+ local result = try(variable_sets[index], variable_path);
+ if result then
+ return result;
+ end
+ end
+end
+
+-- replace variables in a string by array values
+function expand_variables(line, ...)
+ local variable_sets = {...};
+ return (line:gsub('{([%a%d%._]+)}', function(captured)
+ return expand_variable(captured, variable_sets);
+ end))
+end
+
+
+-- concatenate array values
+function to_s(array, separator, prefix, suffix)
+ require 'common.str';
+
+ local buffer = '';
+ for key, value in pairs(array) do
+ buffer = common.str.append(buffer, value, separator, prefix, suffix);
+ end
+
+ return buffer;
+end
+
+-- concatenate array keys
+function keys_to_s(array, separator, prefix, suffix)
+ require 'common.str';
+
+ local buffer = '';
+ for key, value in pairs(array) do
+ buffer = common.str.append(buffer, key, separator, prefix, suffix);
+ end
+
+ return buffer;
+end
+
+-- convert to JSON
+function to_json(array)
+ require 'common.str';
+ local buffer = '{';
+ for key, value in pairs(array) do
+ if type(value) == 'table' then
+ buffer = buffer .. '"' .. key .. '":' .. to_json(value) .. ',';
+ else
+ buffer = buffer .. '"' .. key .. '":' .. common.str.to_json(value) .. ',';
+ end
+ end
+ if buffer:sub(-1) == ',' then
+ buffer = buffer:sub(1, -2);
+ end
+ buffer = buffer .. '}';
+ return buffer;
+end
diff --git a/misc/freeswitch/scripts/common/conference.lua b/misc/freeswitch/scripts/common/conference.lua
index b56cba9..5694f62 100644
--- a/misc/freeswitch/scripts/common/conference.lua
+++ b/misc/freeswitch/scripts/common/conference.lua
@@ -1,19 +1,11 @@
-- Gemeinschaft 5 module: conference class
--- (c) AMOOMA GmbH 2012-2013
+-- (c) AMOOMA GmbH 2013
--
module(...,package.seeall)
Conference = {}
-MEMBERS_MAX = 100;
-PIN_LENGTH_MAX = 10;
-PIN_LENGTH_MIN = 2;
-PIN_TIMEOUT = 4000;
-ANNOUNCEMENT_MAX_LEN = 10
-ANNOUNCEMENT_SILENCE_THRESHOLD = 500
-ANNOUNCEMENT_SILENCE_LEN = 3
-
-- create conference object
function Conference.new(self, arg)
arg = arg or {}
@@ -24,215 +16,271 @@ function Conference.new(self, arg)
self.log = arg.log;
self.database = arg.database;
self.record = arg.record;
- self.max_members = 0;
return object;
end
--- find conference by id
+
+function Conference.settings_get(self)
+ require 'common.array';
+ require 'common.configuration_table';
+
+ local configuration = common.configuration_table.get(self.database, 'conferences');
+ if not configuration then
+ return nil;
+ end
+
+ local parameters = configuration.parameters or {};
+ local settings = configuration.settings or {};
+ local sounds = configuration.sounds or {};
+
+ settings.members_max = settings.members_max or tonumber(parameters['max-members']) or 100;
+ settings.pin_length_max = tonumber(settings.pin_length_max) or 10;
+ settings.pin_length_min = tonumber(settings.pin_length_min) or 2;
+ settings.pin_timeout = tonumber(settings.pin_timeout) or 4000;
+ settings.announcement_max_length = tonumber(settings.announcement_max_length) or 10;
+ settings.announcement_silence_threshold = tonumber(settings.announcement_silence_threshold) or 500;
+ settings.announcement_silence_length = tonumber(settings.announcement_silence_length) or 3;
+ settings.flags = settings.flags or { waste = true };
+ sounds.pin = sounds.pin or 'conference/conf-pin.wav';
+ sounds.has_joined = sounds.has_joined or 'conference/conf-has_joined.wav';
+ sounds.has_left = sounds.has_left or 'conference/conf-has_left.wav';
+ sounds.alone = sounds.has_alone or 'conference/conf-alone.wav';
+
+ settings.key_enter = parameters.key_enter or '#';
+ settings.spool_dir = settings.spool_dir or '/var/spool/freeswitch';
+ return settings, sounds;
+end
+
+
function Conference.find_by_id(self, id)
- local sql_query = 'SELECT * FROM `conferences` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1';
+ local sql_query = 'SELECT *, (NOW() >= `start` AND NOW() <= `end`) AS `open_now` FROM `conferences` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1';
local conference = nil;
self.database:query(sql_query, function(conference_entry)
conference = Conference:new(self);
conference.record = conference_entry;
conference.id = tonumber(conference_entry.id);
+ conference.identifier = 'conference' .. conference.id;
conference.uuid = conference_entry.uuid;
- conference.max_members = tonumber(conference.record.max_members) or MEMBERS_MAX;
- end)
+ conference.pin = conference_entry.pin;
+ conference.open_for_public = common.str.to_b(conference_entry.open_for_anybody);
+ conference.announce_entering = common.str.to_b(conference_entry.announce_new_member_by_name);
+ conference.announce_leaving = common.str.to_b(conference_entry.announce_left_member_by_name);
+ if not common.str.blank(conference_entry.open_now) then
+ conference.open_now = common.str.to_b(conference_entry.open_now);
+ end
+ conference.settings, conference.sounds = self:settings_get();
+ if conference.settings then
+ conference.settings.members_max = tonumber(conference.record.max_members) or conference.settings.members_max;
+ else
+ conference.log:error('CONFERENCE - no basic configuration');
+ end
+ end)
+
return conference;
end
--- find invitee by phone numbers
+
function Conference.find_invitee_by_numbers(self, phone_numbers)
if not self.record then
- return false
+ return false;
end
- local sql_query = string.format(
- "SELECT `conference_invitees`.`pin` AS `pin`, `conference_invitees`.`speaker` AS `speaker`, `conference_invitees`.`moderator` AS `moderator` " ..
- "FROM `conference_invitees` JOIN `phone_numbers` ON `phone_numbers`.`phone_numberable_id` = `conference_invitees`.`id` " ..
- "WHERE `phone_numbers`.`phone_numberable_type` = 'ConferenceInvitee' AND `conference_invitees`.`conference_id` = %d " ..
- "AND `phone_numbers`.`number` IN ('%s') LIMIT 1", self.record.id, table.concat(phone_numbers, "','"));
+ local sql_query = 'SELECT `a`.* \
+ FROM `conference_invitees` `a` \
+ JOIN `phone_numbers` `b` ON `b`.`phone_numberable_id` = `a`.`id` \
+ WHERE `b`.`phone_numberable_type` = "ConferenceInvitee" \
+ AND `a`.`conference_id` = ' .. self.id .. ' \
+ AND `b`.`number` IN ("' .. table.concat(phone_numbers, "','") .. '") \
+ LIMIT 1';
local invitee = nil;
- self.database:query(sql_query, function(conference_entry)
- invitee = conference_entry;
+ self.database:query(sql_query, function(invitee_entry)
+ invitee = invitee_entry;
end)
- return invitee;
+ return invitee;
end
-function Conference.count(self)
- return tonumber(self.caller:result('conference ' .. self.record.id .. ' list count')) or 0;
+
+function Conference.members_count(self)
+ return tonumber(self.caller:result('conference ' .. self.identifier .. ' list count')) or 0;
end
--- Try to enter a conference
-function Conference.enter(self, caller, domain)
- local cause = "NORMAL_CLEARING";
- local pin = nil;
- local flags = {'waste'};
- self.caller = caller;
+function Conference.check_pin(self, pin)
+ local digits = '';
+ for i = 1, 3 do
+ if digits == pin then
+ self.caller:send_display('PIN: OK');
+ break
+ elseif digits ~= "" then
+ self.caller:send_display('PIN: wrong');
+ self.caller.session:sayPhrase('conference_bad_pin');
+ end
+ self.caller:send_display('Enter PIN');
+ digits = self.caller.session:read(self.settings.pin_length_min, self.settings.pin_length_max, self.sounds.pin, self.settings.pin_timeout, self.settings.key_enter);
+ end
- require "common.phone_number"
- local phone_number_class = common.phone_number.PhoneNumber:new{log = self.log, database = self.database}
- local phone_numbers = phone_number_class:list_by_owner(self.record.id, "Conference");
+ if digits ~= pin then
+ return false
+ end
- -- Set conference presence
- require "dialplan.presence"
- local presence = dialplan.presence.Presence:new();
- presence:init{ log = log, accounts = phone_numbers, domain = domain, uuid = "conference_" .. self.record.id };
+ return true;
+end
- local conference_count = self:count();
- -- Check if conference is full
- if conference_count >= self.max_members then
- presence:early();
- self.log:debug(string.format("full conference %s (\"%s\"), members: %d, members allowed: %d", self.record.id, self.record.name, conference_count, self.max_members));
+function Conference.check_ownership(self, check_caller)
+ local owner = nil;
- if (tonumber(self.record.conferenceable_id) == caller.account_owner_id)
- and (self.record.conferenceable_type == caller.account_owner_type) then
- self.log:debug("Allow owner of this conterence to enter a full conference");
- else
- cause = "CALL_REJECTED";
- caller:hangup(cause);
- return cause;
- end;
- end
-
- require 'common.str'
- -- Check if conference is within time frame
- if not common.str.blank(self.record.start) and not common.str.blank(self.record['end']) then
- local d = {}
- _,_,d.year,d.month,d.day,d.hour,d.min,d.sec=string.find(self.record.start, "(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)");
-
- local conference_start = os.time(d);
- _,_,d.year,d.month,d.day,d.hour,d.min,d.sec=string.find(self.record['end'], "(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)");
- local conference_end = os.time(d);
- local now = os.time(os.date("!*t", os.time()));
-
- log:debug("conference - open: " .. os.date("%c",conference_start) .. " by " .. os.date("%c",conference_end) .. ", now: " .. os.date("%c",now));
-
- if now < conference_start or now > conference_end then
- cause = "CALL_REJECTED";
- caller:hangup(cause);
- return cause;
- end
+ if check_caller then
+ owner = common.array.try(self.caller, 'account.owner');
+ else
+ owner = common.array.try(self.caller, 'auth_account.owner');
+ end
+ if not owner then
+ return false;
end
- -- Owner ist always moderator
- if (tonumber(self.record.conferenceable_id) == caller.account_owner_id) and (self.record.conferenceable_type == caller.account_owner_type) then
- table.insert(flags, 'moderator');
- log:debug("is owner - conference: " .. self.record.id .. ", owner: " .. caller.account_owner_type .. ":" .. caller.account_owner_id);
- else
- local invitee = self:find_invitee_by_numbers(caller.caller_phone_numbers);
+ if tonumber(self.record.conferenceable_id) == owner.id and self.record.conferenceable_type:lower() == owner.class then
+ return true;
+ end
+end
- if not common.str.to_b(self.record.open_for_anybody) and not invitee then
- log:debug(string.format("conference %s (\"%s\"), caller %s not allowed to enter this conference", self.record.id, self.record.name, caller.caller_phone_number));
- cause = "CALL_REJECTED";
- caller:hangup(cause);
- return cause;
- end
- if invitee then
- log:debug("conference " .. self.record.id .. " member invited - speaker: " .. invitee.speaker .. ", moderator: " .. invitee.moderator);
- if common.str.to_b(invitee.moderator) then
- table.insert(flags, 'moderator');
- end
- if not common.str.to_b(invitee.speaker) then
- table.insert(flags, 'mute');
- end
- pin = invitee.pin;
- else
- log:debug("conference " .. self.record.id .. " caller not invited");
- end
+function Conference.account_name_file(self)
+ if not self.caller.account or tostring(self.caller.account.class):lower() ~= 'sipaccount' then
+ return;
end
- if not pin and self.record.pin then
- pin = self.record.pin
+ require 'dialplan.voicemail'
+ local voicemail_account = dialplan.voicemail.Voicemail:new{ log = self.log, database = self.database }:find_by_sip_account_id(self.caller.account.id);
+ if voicemail_account and not common.str.blank(voicemail_account.record.name_path) then
+ self.log:debug('CONFERENCE ', self.id, ' - caller_name_file: ', voicemail_account.record.name_path);
+ return voicemail_account.record.name_path;
end
+end
- caller:answer();
- caller:sleep(1000);
- caller.session:sayPhrase('conference_welcome');
- if not common.str.blank(pin) then
- local digits = "";
- for i = 1, 3, 1 do
- if digits == pin then
- break
- elseif digits ~= "" then
- caller.session:sayPhrase('conference_bad_pin');
- end
- digits = caller.session:read(PIN_LENGTH_MIN, PIN_LENGTH_MAX, 'conference/conf-pin.wav', PIN_TIMEOUT, '#');
+function Conference.record_name(self)
+ self.caller:send_display('Record name');
+ local name_file = self.settings.spool_dir .. '/conference_caller_name_' .. self.caller.uuid .. '.wav';
+ self.caller.session:sayPhrase('conference_record_name');
+ self.caller.session:recordFile(name_file, self.settings.announcement_max_length, self.settings.announcement_silence_threshold, self.settings.announcement_max_length);
+ self.caller:send_display('Playback name');
+ self.caller:playback(name_file);
+
+ return name_file;
+end
+
+
+function Conference.playback(self, ...)
+ local sound_files = {...};
+ for index=1, #sound_files do
+ self.caller:execute('set',"result=${conference(" .. self.identifier .. " play ".. tostring(sound_files[index]) .. ")}");
+ end
+end
+
+function Conference.phrase(self, phrase, file_name)
+ self.caller:execute('set',"result=${conference(" .. self.identifier .. " phrase ".. phrase .. ':' .. file_name .. ")}");
+end
+
+function Conference.enter(self, caller, domain)
+ self.caller = caller;
+ local members = self:members_count();
+
+ self.log:info('CONFERENCE ', self.id, ' - open_for_public: ', self.open_for_public, ', open_now: ', self.open_now, ', members: ', members, ', members_max: ', self.settings.members_max);
+
+ if self.open_now == false then
+ self.log:notice('CONFERENCE ', self.id, ' - currently closed, start: ', self.record.start, ', end: ', self.record['end']);
+ return { continue = false, code = 493, phrase = 'Conference closed' };
+ end
+
+ if members >= self.settings.members_max then
+ self.log:notice('CONFERENCE ', self.id, ' - full, members: ', members, ', members_max: ', self.settings.members_max);
+ return { continue = false, code = 493, phrase = 'Conference closed' };
+ end
+
+ local invitee = self:find_invitee_by_numbers(caller.caller_phone_numbers);
+ if invitee then
+ if common.str.to_b(invitee.speaker) then
+ self.settings.flags.mute = nil;
+ end
+ if common.str.to_b(invitee.moderator) then
+ self.settings.flags.moderator = true;
end
- if digits ~= pin then
- caller.session:sayPhrase('conference_goodbye');
- return "CALL_REJECTED";
+ self.log:info('CONFERENCE ', self.id, ' - invitee=', invitee.id, '/', invitee.uuid, ', speaker: ', not self.settings.flags.mute, ', moderator: ', self.settings.flags.moderator);
+ self.pin = invitee.pin;
+ elseif self:check_ownership() then
+ self.pin = nil;
+ local caller_owner = false;
+ if self:check_ownership(true) then
+ self.settings.flags.moderator = true;
+ self.settings.flags.dtmf = true;
+ caller_owner = true;
end
+ self.log:info('CONFERENCE ', self.id, ' - owner authenticated: ', self.caller.auth_account.owner.class,'=', self.caller.auth_account.owner.id, '/', self.caller.auth_account.owner.uuid, ', owner: ', caller_owner, ', speaker: ', not self.settings.flags.mute, ', moderator: ', self.settings.flags.moderator);
+ elseif not self.open_for_public then
+ self.log:notice('CONFERENCE ', self.id, ' - not open for public');
+ return { continue = false, code = 493, phrase = 'Conference closed' };
end
- self.log:debug(string.format("entering conference %s - name: \"%s\", flags: %s, members: %d, max. members: %d",
- self.record.id, self.record.name, table.concat(flags, ','), conference_count, self.max_members));
-
- -- Members count will be incremented in a few milliseconds, set presence
- if (conference_count + 1) >= self.max_members then
- presence:early();
- else
- presence:confirmed();
+ caller:answer();
+ if not common.str.blank(self.pin) and not self:check_pin(self.pin) then
+ self.log:notice('CONFERENCE ', self.id, ' - PIN wrong');
+ caller.session:sayPhrase('conference_goodbye');
+ return { continue = false, code = 493, phrase = 'Not authorized' };
end
- -- Enter the conference
+ self.caller:send_display(tostring(self.record.name) .. ', members: ' .. tostring(members));
+ caller:sleep(1000);
+ caller.session:sayPhrase('conference_welcome');
+
+
local name_file = nil;
+ local name_file_delete = nil;
- -- Record caller's name
- if common.str.to_b(self.record.announce_new_member_by_name) or common.str.to_b(self.record.announce_left_member_by_name) then
- local uid = session:get_uuid();
- name_file = "/var/spool/freeswitch/conference_caller_name_" .. uid .. ".wav";
- caller.session:sayPhrase('conference_record_name');
- session:recordFile(name_file, ANNOUNCEMENT_MAX_LEN, ANNOUNCEMENT_SILENCE_THRESHOLD, ANNOUNCEMENT_SILENCE_LEN);
- caller.session:streamFile(name_file);
+ if self.announce_entering or self.announce_leaving then
+ name_file = self:account_name_file();
+ if not name_file then
+ name_file = self:record_name(caller);
+ name_file_delete = true;
+ end
end
- -- Play entering caller's name if recorded
- if name_file and (self:count() > 0) and common.str.to_b(self.record.announce_new_member_by_name) then
- caller.session:execute('set',"result=${conference(" .. self.record.id .. " play ".. name_file .. ")}");
- caller.session:execute('set',"result=${conference(" .. self.record.id .. " play conference/conf-has_joined.wav)}");
- else
- -- Ensure a surplus "#" digit is not passed to the conference
- caller.session:read(1, 1, '', 1000, "#");
+ members = self:members_count();
+ if self.announce_entering and name_file then
+ if members > 0 then
+ self:playback(name_file, self.sounds.has_joined);
+ end
end
- local result = caller.session:execute('conference', self.record.id .. "@profile_" .. self.record.id .. "++flags{" .. table.concat(flags, '|') .. "}");
- self.log:debug('exited conference - result: ' .. tostring(result));
+ if members == 0 then
+ caller.session:sayPhrase('conference_alone');
+ end
+
+ self.caller:send_display(tostring(self.record.name));
+ local result = caller:execute('conference', self.identifier .. "@profile_" .. self.identifier .. "++flags{" .. common.array.keys_to_s(self.settings.flags, '|') .. "}");
+
+ self.caller:send_display('Goodbye');
caller.session:sayPhrase('conference_goodbye');
- -- Play leaving caller's name if recorded
if name_file then
- if (self:count() > 0) and common.str.to_b(self.record.announce_left_member_by_name) then
- if (self:count() == 1) then
- caller.session:sleep(3000);
+ if self.announce_leaving then
+ members = self:members_count();
+ if members > 0 then
+ self:playback(name_file, self.sounds.has_left);
+ if members == 1 then
+ self:playback(self.sounds.alone);
+ end
end
- caller.session:execute('set',"result=${conference(" .. self.record.id .. " play ".. name_file .. ")}");
- caller.session:execute('set',"result=${conference(" .. self.record.id .. " play conference/conf-has_left.wav)}");
end
- os.remove(name_file);
- end
-
- -- Set presence according to member count
- conference_count = self:count();
- if conference_count >= self.max_members then
- presence:early();
- elseif conference_count > 0 then
- presence:confirmed();
- else
- presence:terminated();
+ if name_file_delete then
+ os.remove(name_file);
+ end
end
- cause = "NORMAL_CLEARING";
- caller.session:hangup(cause);
- return cause;
+ return { continue = false, code = 200, phrase = 'OK' }
end
diff --git a/misc/freeswitch/scripts/common/database.lua b/misc/freeswitch/scripts/common/database.lua
index 8aed1ac..be32ad7 100644
--- a/misc/freeswitch/scripts/common/database.lua
+++ b/misc/freeswitch/scripts/common/database.lua
@@ -67,6 +67,29 @@ function Database.query_return_value(self, sql_query)
end
+function Database.query_return_first(self, sql_query)
+ local result = nil;
+
+ self.conn:query(sql_query, function(row)
+ result = row;
+ return result;
+ end);
+
+ return result;
+end
+
+
+function Database.query_return_all(self, sql_query)
+ local result = {};
+
+ self.conn:query(sql_query, function(row)
+ table.insert(result, row);
+ end);
+
+ return result;
+end
+
+
function Database.last_insert_id(self)
return self:query_return_value('SELECT LAST_INSERT_ID()');
end
diff --git a/misc/freeswitch/scripts/common/gateway.lua b/misc/freeswitch/scripts/common/gateway.lua
index c1b50a7..ac38326 100644
--- a/misc/freeswitch/scripts/common/gateway.lua
+++ b/misc/freeswitch/scripts/common/gateway.lua
@@ -34,7 +34,11 @@ end
function Gateway.find_by_id(self, id)
- local sql_query = 'SELECT * FROM `gateways` WHERE `id`= ' .. tonumber(id) .. ' LIMIT 1';
+ local sql_query = 'SELECT `a`.*, `c`.`sip_host` AS `domain`, `c`.`contact` AS `contact_full`, `c`.`network_ip`, `c`.`network_port` \
+ FROM `gateways` `a` \
+ LEFT JOIN `gateway_settings` `b` ON `a`.`id` = `b`.`gateway_id` AND `b`.`name` = "inbound_username" \
+ LEFT JOIN `sip_registrations` `c` ON `b`.`value` = `c`.`sip_user` \
+ WHERE `a`.`id`= ' .. tonumber(id) .. ' LIMIT 1';
local gateway = nil;
self.database:query(sql_query, function(entry)
@@ -46,6 +50,9 @@ function Gateway.find_by_id(self, id)
gateway.technology = entry.technology;
gateway.outbound = common.str.to_b(entry.outbound);
gateway.inbound = common.str.to_b(entry.inbound);
+ gateway.domain = entry.domain;
+ gateway.network_ip = entry.network_ip;
+ gateway.network_port = tonumber(entry.network_port) or 5060;
end)
if gateway then
@@ -59,7 +66,45 @@ end
function Gateway.find_by_name(self, name)
local gateway_name = name:gsub('([^%a%d%._%+])', '');
- local sql_query = 'SELECT * FROM `gateways` WHERE `name`= "' .. gateway_name .. '" LIMIT 1';
+ local sql_query = 'SELECT `a`.*, `c`.`sip_host` `domain`, `c`.`contact` AS `contact_full`, `c`.`network_ip`, `c`.`network_port`\
+ FROM `gateways` `a` \
+ LEFT JOIN `gateway_settings` `b` ON `a`.`id` = `b`.`gateway_id` AND `b`.`name` = "inbound_username" \
+ LEFT JOIN `sip_registrations` `c` ON `b`.`value` = `c`.`sip_user` \
+ WHERE `a`.`name`= ' .. self.database:escape(gateway_name, '"') .. ' LIMIT 1';
+
+ local gateway = nil;
+ self.database:query(sql_query, function(entry)
+ require 'common.str';
+ gateway = Gateway:new(self);
+ gateway.record = entry;
+ gateway.id = tonumber(entry.id);
+ gateway.name = entry.name;
+ gateway.technology = entry.technology;
+ gateway.outbound = common.str.to_b(entry.outbound);
+ gateway.inbound = common.str.to_b(entry.inbound);
+ gateway.domain = entry.domain;
+ gateway.network_ip = entry.network_ip;
+ gateway.network_port = tonumber(entry.network_port) or 5060;
+ end)
+
+ if gateway then
+ gateway.settings = self:config_table_get('gateway_settings', gateway.id);
+ end
+
+ return gateway;
+end
+
+
+function Gateway.find_by_auth_name(self, name)
+ local auth_name = name:gsub('([^%a%d%._%+])', '');
+
+ local sql_query = 'SELECT `c`.*, `a`.`value` `password`, `b`.`value` `username` \
+ FROM `gateway_settings` `a` \
+ INNER JOIN `gateway_settings` `b` \
+ ON (`a`.`gateway_id` = `b`.`gateway_id` AND `a`.`name` = "inbound_password" AND `b`.`name` = "inbound_username" AND `b`.`value` = ' .. self.database:escape(auth_name, '"') .. ') \
+ LEFT JOIN `gateways` `c` \
+ ON (`a`.`gateway_id` = `c`.`id`) \
+ WHERE `c`.`inbound` IS TRUE OR `c`.`outbound` IS TRUE LIMIT 1';
local gateway = nil;
self.database:query(sql_query, function(entry)
@@ -82,14 +127,26 @@ end
function Gateway.call_url(self, destination_number)
- if self.technology == 'sip' then
- return 'sofia/gateway/' .. self.GATEWAY_PREFIX .. self.id .. '/' .. tostring(destination_number);
- elseif self.technology == 'xmpp' then
- local destination_str = tostring(destination_number);
- if self.settings.destination_domain then
- destination_str = destination_str .. '@' .. self.settings.destination_domain;
+ require 'common.str';
+
+ if common.str.blank(self.settings.dial_string) then
+ if self.technology == 'sip' then
+ if self.settings.inbound_username and self.settings.inbound_password and not common.str.blank(self.record.domain) then
+ return 'sofia/' .. (self.settings.profile or 'gemeinschaft') .. '/' .. self.settings.inbound_username .. '%' .. self.record.domain;
+ else
+ return 'sofia/gateway/' .. self.GATEWAY_PREFIX .. self.id .. '/' .. tostring(destination_number);
+ end
+
+ elseif self.technology == 'xmpp' then
+ local destination_str = tostring(destination_number);
+ if self.settings.destination_domain then
+ destination_str = destination_str .. '@' .. self.settings.destination_domain;
+ end
+ return 'dingaling/' .. self.GATEWAY_PREFIX .. self.id .. '/' .. destination_str;
end
- return 'dingaling/' .. self.GATEWAY_PREFIX .. self.id .. '/' .. destination_str;
+ else
+ require 'common.array';
+ return tostring(common.array.expand_variables(self.settings.dial_string, self, { destination_number = destination_number }));
end
return '';
@@ -174,9 +231,7 @@ function Gateway.parameters_build(self, gateway_id, technology)
parameters.register = common.str.to_b(settings.register);
end
- if common.str.blank(settings.password) then
- parameters.password = 'gateway' .. gateway_id;
- else
+ if not common.str.blank(settings.password) then
parameters.password = settings.password;
end
diff --git a/misc/freeswitch/scripts/common/intruder.lua b/misc/freeswitch/scripts/common/intruder.lua
index 083ec37..7d12155 100644
--- a/misc/freeswitch/scripts/common/intruder.lua
+++ b/misc/freeswitch/scripts/common/intruder.lua
@@ -49,3 +49,46 @@ function Intruder.update_blacklist(self, event)
self.database:insert_or_update('intruders', intruder_record, { created_at = false, comment = false });
end
+
+
+function Intruder.sources_list(self, key)
+ local sql_query = nil;
+
+ if key then
+ sql_query = 'SELECT * FROM `intruders` WHERE `key` = ' .. self.database:escape(key, '"') .. ' LIMIT 1';
+ else
+ sql_query = 'SELECT * FROM `intruders`';
+ end
+
+ local sources = {};
+ local sources_count = 0;
+ local blacklist_count = 0;
+ local whitelist_count = 0;
+
+ self.database:query(sql_query, function(record)
+ sources[record.key] = {
+ ignore = (record.list_type == 'whitelist'),
+ contact_first = 0,
+ contact_last = 0,
+ contact_count = tonumber(record.contact_count) or 0,
+ span_contact_count = 0,
+ span_start = 0,
+ points = tonumber(record.points) or 0,
+ banned = tonumber(record.bans) or 0,
+ };
+ sources_count = sources_count + 1;
+ if record.list_type == 'whitelist' then
+ whitelist_count = whitelist_count + 1;
+ elseif record.list_type == 'blacklist' then
+ blacklist_count = blacklist_count + 1;
+ end
+ end);
+
+ self.log:info('[intruder] INTRUDER_LIST - entries loaded: ', sources_count, ', blacklist: ', blacklist_count, ', whitelist: ', whitelist_count);
+
+ if key then
+ return sources[key];
+ end
+
+ return sources;
+end
diff --git a/misc/freeswitch/scripts/common/log.lua b/misc/freeswitch/scripts/common/log.lua
index b7c8d09..b9893ac 100644
--- a/misc/freeswitch/scripts/common/log.lua
+++ b/misc/freeswitch/scripts/common/log.lua
@@ -12,6 +12,8 @@ function Log.new(self, arg)
object = arg.object or {}
setmetatable(object, self);
self.__index = self;
+ self.disabled = arg.disabled or false;
+ self.buffer = arg.buffer;
self.prefix = arg.prefix or '### ';
self.level_console = arg.level_console or 0;
@@ -22,18 +24,31 @@ function Log.new(self, arg)
self.level_notice = arg.level_notice or 5;
self.level_info = arg.level_info or 6;
self.level_debug = arg.level_debug or 7;
+ self.level_devel = arg.level_devel or 4;
return object;
end
function Log.message(self, log_level, message_arguments )
+ if self.disabled then
+ return
+ end
local message = tostring(self.prefix);
for index, value in pairs(message_arguments) do
if type(index) == 'number' then
- message = message .. tostring(value);
+ if type(value) == 'table' then
+ require 'common.array';
+ message = message .. common.array.to_json(value);
+ else
+ message = message .. tostring(value);
+ end
end
end
- freeswitch.consoleLog(log_level, message .. '\n');
+ if self.buffer then
+ table.insert(self.buffer, message);
+ elseif freeswitch then
+ freeswitch.consoleLog(log_level, message .. '\n');
+ end
end
function Log.console(self, ...)
@@ -67,3 +82,9 @@ end
function Log.debug(self, ...)
self:message(self.level_debug, {...});
end
+
+function Log.devel(self, ...)
+ local arguments = {...};
+ table.insert(arguments, 1, '**');
+ self:message(self.level_devel, arguments);
+end
diff --git a/misc/freeswitch/scripts/common/object.lua b/misc/freeswitch/scripts/common/object.lua
index 8c195e5..68e1361 100644
--- a/misc/freeswitch/scripts/common/object.lua
+++ b/misc/freeswitch/scripts/common/object.lua
@@ -95,6 +95,18 @@ function Object.find(self, attributes)
if object then
object.owner = self:find{class = object.record.fax_accountable_type, id = tonumber(object.record.fax_accountable_id)};
end
+ elseif class == 'conference' then
+ require 'common.conference';
+
+ if tonumber(attributes.id) then
+ object = common.conference.Conference:new{ log = self.log, database = self.database }:find_by_id(attributes.id);
+ elseif not common.str.blank(attributes.uuid) then
+ object = common.conference.Conference:new{ log = self.log, database = self.database }:find_by_uuid(attributes.uuid);
+ end
+
+ if object then
+ object.owner = self:find{class = object.record.conferenceable_type, id = tonumber(object.record.conferenceable_id)};
+ end
end
if object then
diff --git a/misc/freeswitch/scripts/common/perimeter.lua b/misc/freeswitch/scripts/common/perimeter.lua
index 0815d33..d3b601c 100644
--- a/misc/freeswitch/scripts/common/perimeter.lua
+++ b/misc/freeswitch/scripts/common/perimeter.lua
@@ -9,6 +9,9 @@ Perimeter = {}
function Perimeter.new(self, arg)
+ require 'common.str';
+ require 'common.array';
+
arg = arg or {}
object = arg.object or {}
setmetatable(object, self);
@@ -94,12 +97,24 @@ end
function Perimeter.check(self, event)
- if not event or not event.key then
- self.log:warning('[perimeter] PERIMETER_CHECK - no event/key');
+ if not type(event) == 'list' then
+ self.log:warning('[perimeter] PERIMETER_CHECK - no event data');
+ return;
+ end
+ if not event.key then
+ self.log:warning('[perimeter] PERIMETER_CHECK - no key');
+ for key, value in pairs(event) do
+ self.log:debug('[perimeter] PERIMETER_CHECK event_data - "', key, '" = "', value, '"');
+ end
return;
end
- event.record = self:record_load(event);
+ event.record = self:record_load(event);
+
+ if event.record.ignore then
+ return
+ end
+
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
@@ -191,7 +206,7 @@ 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);
+ pattern = common.array.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);
@@ -213,29 +228,36 @@ function Perimeter.append_blacklist_file(self, event)
event.date = self:format_date(event.timestamp);
if self.blacklist_file_comment then
- blacklist:write(self:expand_variables(self.blacklist_file_comment, event), '\n');
+ blacklist:write(common.array.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:write(common.array.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);
+ local command = common.array.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))
+function Perimeter.action_db_rescan(self, record)
+ require 'common.intruder';
+
+ if common.str.blank(record.key) then
+ self.log:info('[perimeter] PERIMETER rescan entire sources database');
+ self.sources = common.intruder.Intruder:new{ log = self.log, database = self.database }:sources_list();
+ else
+ self.log:info('[perimeter] PERIMETER rescan sources database - key: ', record.key);
+ self.sources[record.key] = common.intruder.Intruder:new{ log = self.log, database = self.database }:sources_list(record.key);
+ end
end
diff --git a/misc/freeswitch/scripts/common/sip_account.lua b/misc/freeswitch/scripts/common/sip_account.lua
index 6cc7d25..e7ee0d7 100644
--- a/misc/freeswitch/scripts/common/sip_account.lua
+++ b/misc/freeswitch/scripts/common/sip_account.lua
@@ -130,9 +130,9 @@ end
function SipAccount.call_state(self)
- local sql_query = 'SELECT `callstate` FROM `detailed_calls` \
- WHERE `presence_id` LIKE "' .. self.record.auth_name .. '@%" \
- OR `b_presence_id` LIKE "' .. self.record.auth_name .. '@%" \
+ local sql_query = 'SELECT `callstate` FROM `calls_active` \
+ WHERE `sip_account_id` = ' .. self.id .. ' \
+ OR `b_sip_account_id` = ' .. self.id .. ' \
LIMIT 1';
return self.database:query_return_value(sql_query);
diff --git a/misc/freeswitch/scripts/common/str.lua b/misc/freeswitch/scripts/common/str.lua
index 541199f..3fd8fde 100644
--- a/misc/freeswitch/scripts/common/str.lua
+++ b/misc/freeswitch/scripts/common/str.lua
@@ -4,37 +4,6 @@
module(...,package.seeall)
-function try(array, arguments)
- if type(arguments) ~= 'string' or type(array) ~= 'table' then
- return nil;
- end
-
- local result = array;
-
- arguments:gsub('([^%.]+)', function(entry)
- local success, result = pcall(function() result = (result[tonumber(entry) or entry]); end);
- end);
-
- 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%.%+%-]', '');
@@ -160,23 +129,3 @@ function append(buffer, value, separator, prefix, suffix)
return buffer;
end
-
--- concatenate array values to string
-function concat(array, separator, prefix, suffix)
- local buffer = '';
- for key, value in pairs(array) do
- buffer = append(buffer, value, separator, prefix, suffix);
- end
-
- return buffer;
-end
-
--- concatenate array keys to string
-function concat_keys(array, separator, prefix, suffix)
- local buffer = '';
- for key, value in pairs(array) do
- buffer = append(buffer, key, separator, prefix, suffix);
- end
-
- return buffer;
-end