summaryrefslogtreecommitdiff
path: root/misc/freeswitch/scripts/dialplan
diff options
context:
space:
mode:
Diffstat (limited to 'misc/freeswitch/scripts/dialplan')
-rw-r--r--misc/freeswitch/scripts/dialplan/callback.lua85
-rw-r--r--misc/freeswitch/scripts/dialplan/dialplan.lua102
-rw-r--r--misc/freeswitch/scripts/dialplan/fax.lua4
-rw-r--r--misc/freeswitch/scripts/dialplan/functions.lua52
-rw-r--r--misc/freeswitch/scripts/dialplan/hunt_group.lua27
-rw-r--r--misc/freeswitch/scripts/dialplan/ivr.lua119
-rw-r--r--misc/freeswitch/scripts/dialplan/router.lua52
-rw-r--r--misc/freeswitch/scripts/dialplan/session.lua18
-rw-r--r--misc/freeswitch/scripts/dialplan/sip_call.lua11
-rw-r--r--misc/freeswitch/scripts/dialplan/voicemail.lua9
10 files changed, 367 insertions, 112 deletions
diff --git a/misc/freeswitch/scripts/dialplan/callback.lua b/misc/freeswitch/scripts/dialplan/callback.lua
new file mode 100644
index 0000000..f6fd48e
--- /dev/null
+++ b/misc/freeswitch/scripts/dialplan/callback.lua
@@ -0,0 +1,85 @@
+-- Gemeinschaft 5 module: callback class
+-- (c) AMOOMA GmbH 2013
+--
+
+module(...,package.seeall)
+
+Callback = {}
+
+-- create callback callback ;)
+function Callback.new(self, arg)
+ arg = arg or {}
+ callback = arg.callback or {}
+ setmetatable(callback, self);
+ self.__index = self;
+ self.class = 'callback';
+ self.log = arg.log;
+ self.session = arg.session;
+ self.sessions = {};
+ local id = common.str.to_i(self.session);
+ self.sessions[id] = { id = id, session = self.session, dtmf = {} };
+ return callback;
+end
+
+
+function Callback.callback(self, class, identifier, callback_function, callback_instance, callback_session)
+ local id = common.str.to_i(callback_session or self.session);
+ local session_record = self.sessions[id];
+
+ if not session_record and callback_session then
+ self.sessions[id] = { id = id, session = callback_session, dtmf = {} };
+ session_record = self.sessions[id];
+ end
+
+ if not session_record then
+ return false;
+ end
+
+
+ _G['global_callback_record_' .. id] = session_record;
+
+ session_record.session:setInputCallback('global_callback_handler', 'global_callback_record_' .. id);
+ session_record[class][identifier] = { method = callback_function, instance = callback_instance };
+
+ return true;
+end
+
+
+function Callback.callback_unset(self, class, identifier, callback_session)
+ local session_record = self.sessions[tostring(callback_session or self.session)];
+ if not session_record then
+ return false;
+ end
+
+ -- session_record.session:unsetInputCallback();
+ session_record[class][identifier] = nil;
+
+ return true;
+end
+
+
+function Callback.run(self, arg)
+ local identifier = arg[2];
+ local data = arg[3];
+ local session_record = arg[4];
+ local callbacks = session_record[identifier];
+
+ local return_value = nil;
+ if callbacks then
+ for identifier, callback in pairs(callbacks) do
+ if callback.method then
+ local result = nil;
+ if callback.instance then
+ result = callback.method(callback.instance, data);
+ else
+ result = callback.method(data.digit, data);
+ end
+ if result == false then
+ return_value = 'break';
+ end
+ end
+ end
+ end
+
+ return return_value;
+end
diff --git a/misc/freeswitch/scripts/dialplan/dialplan.lua b/misc/freeswitch/scripts/dialplan/dialplan.lua
index ffad4da..5335328 100644
--- a/misc/freeswitch/scripts/dialplan/dialplan.lua
+++ b/misc/freeswitch/scripts/dialplan/dialplan.lua
@@ -22,6 +22,9 @@ local CALL_FORWARDING_SERVICES = {
-- create dialplan object
function Dialplan.new(self, arg)
+ require 'common.str';
+ require 'common.array';
+
arg = arg or {}
object = arg.object or {}
setmetatable(object, self);
@@ -35,7 +38,6 @@ end
function Dialplan.domain_get(self, domain)
- require 'common.str'
local global_domain = freeswitch.API():execute('global_getvar', 'domain');
if common.str.blank(global_domain) then
@@ -74,8 +76,7 @@ end
function Dialplan.configuration_read(self)
- require 'common.str'
- require 'common.configuration_table'
+ require 'common.configuration_table';
-- dialplan configuration
self.config = common.configuration_table.get(self.database, 'dialplan');
@@ -124,7 +125,6 @@ end
function Dialplan.auth_sip_account(self)
- require 'common.str'
if not common.str.blank(self.caller.auth_account_type) then
self.log:info('AUTH_SIP_ACCOUNT - ', self.caller.auth_account_type, '=', self.caller.account_id, '/', self.caller.account_uuid);
return true;
@@ -135,10 +135,22 @@ end
function Dialplan.auth_gateway(self)
require 'common.gateway'
local gateway_class = common.gateway.Gateway:new{ log = self.log, database = self.database};
- local gateway = gateway_class:authenticate(self.caller);
+
+ local gateway = false;
+
+ if self.caller:to_b('gs_from_gateway') then
+ gateway = {
+ name = self.caller:to_s('gs_gateway_name'),
+ id = self.caller:to_i('gs_gateway_id'),
+ }
+ log:info('AUTH_GATEWAY - authenticaded by password and username: ', self.caller:to_s('username'), ', gateway=', gateway.id, '|', gateway.name, ', ip: ', self.caller.sip_contact_host);
+ return gateway_class:find_by_id(gateway.id);
+ else
+ gateway = gateway_class:authenticate(self.caller);
+ end
if gateway then
- log:info('AUTH_GATEWAY - ', gateway.auth_source, ' ~ ', gateway.auth_pattern, ', gateway=', gateway.id, ', name: ', gateway.name, ', ip: ', self.caller.sip_contact_host);
+ log:info('AUTH_GATEWAY - ', gateway.auth_source, ' ~ ', gateway.auth_pattern, ', gateway=', gateway.id, '|', gateway.name, ', ip: ', self.caller.sip_contact_host);
return gateway_class:find_by_id(gateway.id);
end
end
@@ -151,20 +163,15 @@ end
function Dialplan.retrieve_caller_data(self)
- require 'common.str'
self.caller.caller_phone_numbers_hash = {};
- -- TODO: Set auth_account on transfer initiated by calling party
- if not common.str.blank(self.caller.dialed_sip_user) then
- self.caller.auth_account = self:object_find{class = 'sipaccount', domain = self.caller.dialed_domain, auth_account = self.caller.dialed_sip_user};
- if self.caller.set_auth_account then
- self.caller:set_auth_account(self.caller.auth_account);
- end
+ if not common.str.blank(self.caller.previous_destination_type) and not common.str.blank(self.caller.previous_destination_uuid) then
+ self.log:debug('CALLER_DATA - authenticate by previous destination: ', self.caller.previous_destination_type, '=', self.caller.previous_destination_id, '/', self.caller.previous_destination_uuid);
+ self.caller.auth_account = self:object_find{class = self.caller.previous_destination_type, uuid = self.caller.previous_destination_uuid};
elseif not common.str.blank(self.caller.auth_account_type) and not common.str.blank(self.caller.auth_account_uuid) then
self.caller.auth_account = self:object_find{class = self.caller.auth_account_type, uuid = self.caller.auth_account_uuid};
- if self.caller.set_auth_account then
- self.caller:set_auth_account(self.caller.auth_account);
- end
+ elseif not common.str.blank(self.caller.dialed_sip_user) then
+ self.caller.auth_account = self:object_find{class = 'sipaccount', domain = self.caller.dialed_domain, auth_account = self.caller.dialed_sip_user};
end
if self.caller.auth_account then
@@ -174,13 +181,19 @@ function Dialplan.retrieve_caller_data(self)
else
self.log:error('CALLER_DATA - auth owner not found');
end
+ if self.caller.set_auth_account then
+ self.caller:set_auth_account(self.caller.auth_account);
+ end
else
- self.log:info('CALLER_DATA - no data - unauthenticated call: ', self.caller.auth_account_type, '/', self.caller.auth_account_uuid);
+ self.log:info('CALLER_DATA - no data - unauthenticated call: ', self.caller.auth_account_type, '=', self.caller.auth_account_id, '/', self.caller.auth_account_uuid);
end
if not common.str.blank(self.caller.account_type) and not common.str.blank(self.caller.account_uuid) then
self.caller.account = self:object_find{class = self.caller.account_type, uuid = self.caller.account_uuid};
if self.caller.account then
+ self.caller.clir = common.str.to_b(common.array.try(self.caller, 'account.record.clir'));
+ self.caller.clip = common.str.to_b(common.array.try(self.caller, 'account.record.clip'));
+
require 'common.phone_number'
self.caller.caller_phone_numbers = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:list_by_owner(self.caller.account.id, self.caller.account.class);
for index, caller_number in ipairs(self.caller.caller_phone_numbers) do
@@ -207,8 +220,6 @@ end
function Dialplan.destination_new(self, arg)
- require 'common.str'
-
local destination = {
number = arg.number or '',
type = arg.type or 'unknown',
@@ -288,7 +299,6 @@ function Dialplan.dial(self, destination)
local user_id = nil;
local tenant_id = nil;
- require 'common.str'
destination.caller_id_number = destination.caller_id_number or self.caller.caller_phone_numbers[1];
if destination.node_local and destination.type == 'sipaccount' then
@@ -296,6 +306,7 @@ function Dialplan.dial(self, destination)
destination.account = self:object_find{class = destination.type, id = destination.id};
if destination.account then
+ destination.uuid = destination.account.uuid;
if destination.account.class == 'sipaccount' then
destination.callee_id_name = destination.account.record.caller_name;
self.caller:set_callee_id(destination.number, destination.account.record.caller_name);
@@ -306,7 +317,7 @@ function Dialplan.dial(self, destination)
self.log:debug('DESTINATION_GROUPS - pickup_groups: ', table.concat(group_names, ','));
for index=1, #group_ids do
table.insert(destination.pickup_groups, 'g' .. group_ids[index]);
- end
+ end
end
if destination.account and destination.account.owner then
@@ -317,12 +328,14 @@ function Dialplan.dial(self, destination)
elseif destination.account.owner.class == 'tenant' then
tenant_id = destination.account.owner.id;
end
+ self.caller:set_variable('gs_destination_owner_type', destination.account.owner.class);
+ self.caller:set_variable('gs_destination_owner_id', destination.account.owner.id);
+ self.caller:set_variable('gs_destination_owner_uuid', destination.account.owner.uuid);
end
end
if not self.caller.clir then
if user_id or tenant_id then
- require 'common.str'
if self.phonebook_number_lookup then
require 'dialplan.phone_book'
@@ -455,16 +468,14 @@ end
function Dialplan.conference(self, destination)
- -- call local conference
- require 'common.conference'
- conference = common.conference.Conference:new{ log = self.log, database = self.database }:find_by_id(destination.id);
+ require 'common.conference';
+ local conference = common.conference.Conference:new{ log = self.log, database = self.database }:find_by_id(destination.id);
if not conference then
return { continue = false, code = 404, phrase = 'Conference not found' }
end
- local cause = conference:enter(self.caller, self.domain);
- return { continue = false, cause = cause }
+ return conference:enter(self.caller, self.domain);
end
@@ -579,13 +590,16 @@ end
function Dialplan.voicemail(self, destination)
- if not self.caller.auth_account or self.caller.auth_account.class ~= 'sipaccount' then
- self.log:error('VOICEMAIL - incompatible destination');
- return { continue = false, code = 404, phrase = 'Mailbox not found' }
- end
-
require 'dialplan.voicemail'
- local voicemail_account = dialplan.voicemail.Voicemail:new{ log = self.log, database = self.database }:find_by_sip_account_id(self.caller.auth_account.id);
+
+ local voicemail_account = nil;
+
+ local sip_account_id
+ if not common.str.blank(destination.number) and false then
+ voicemail_account = dialplan.voicemail.Voicemail:new{ log = self.log, database = self.database }:find_by_number(destination.number);
+ elseif self.caller.auth_account and self.caller.auth_account.class == 'sipaccount' then
+ voicemail_account = dialplan.voicemail.Voicemail:new{ log = self.log, database = self.database }:find_by_sip_account_id(self.caller.auth_account.id);
+ end
if not voicemail_account then
self.log:error('VOICEMAIL - no mailbox');
@@ -609,7 +623,6 @@ end
function Dialplan.switch(self, destination)
- require 'common.str'
local result = nil;
self.dial_timeout_active = self.dial_timeout;
@@ -703,7 +716,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(self.caller, 'account.record.clip_no_screening');
+ local clip_no_screening = common.array.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
@@ -713,8 +726,8 @@ function Dialplan.switch(self, destination)
for index, number in ipairs(self.caller.caller_phone_numbers) do
table.insert(self.caller.caller_id_numbers, number);
end
- self.log:info('CALLER_ID_NUMBERS - clir: ', self.caller.clir, ', numbers: ', table.concat(self.caller.caller_id_numbers, ','));
+ self.log:info('SWITCH - clir: ', self.caller.clir, ', caller_id_numbers: ', table.concat(self.caller.caller_id_numbers, ','));
destination.callee_id_number = destination.number;
destination.callee_id_name = nil;
@@ -727,9 +740,8 @@ function Dialplan.switch(self, destination)
end
if self.phonebook_number_lookup then
- require 'common.str'
- local user_id = common.str.try(self.caller, 'account.owner.id');
- local tenant_id = common.str.try(self.caller, 'account.owner.record.current_tenant_id');
+ local user_id = common.array.try(self.caller, 'account.owner.id');
+ local tenant_id = common.array.try(self.caller, 'account.owner.record.current_tenant_id');
if user_id or tenant_id then
require 'dialplan.phone_book'
@@ -745,7 +757,6 @@ function Dialplan.switch(self, destination)
require 'dialplan.geo_number'
local geo_number = dialplan.geo_number.GeoNumber:new{ log = self.log, database = self.database }:find(destination.number);
if geo_number then
- require 'common.str'
self.log:info('GEO_NUMBER - found: ', geo_number.name, ', ', geo_number.country);
if geo_number.name then
destination.callee_id_name = common.str.to_ascii(geo_number.name) .. ', ' .. common.str.to_ascii(geo_number.country);
@@ -796,7 +807,6 @@ end
function Dialplan.run(self, destination)
- require 'common.str';
require 'dialplan.router';
self.caller:set_variable('hangup_after_bridge', false);
@@ -881,14 +891,21 @@ function Dialplan.run(self, destination)
end
self.caller:set_variable('default_language', self.caller.language);
- self.caller:set_variable('sound_prefix', common.str.try(self.config, 'sounds.' .. tostring(self.caller.language)));
+ self.caller:set_variable('sound_prefix', common.array.try(self.config, 'sounds.' .. tostring(self.caller.language)));
self.log:info('DIALPLAN start - caller_id: ',self.caller.caller_id_number, ' "', self.caller.caller_id_name, '" , number: ', destination.number, ', language: ', self.caller.language);
+
+ self.caller.static_caller_id_number = self.caller.caller_id_number;
+ self.caller.static_caller_id_name = self.caller.caller_id_name;
+
local result = { continue = false };
local loop = self.caller.loop_count;
while self.caller:ready() and loop < self.max_loops do
loop = loop + 1;
self.caller.loop_count = loop;
+
+ self.caller.caller_id_number = self.caller.static_caller_id_number;
+ self.caller.caller_id_name = self.caller.static_caller_id_name;
self.log:info('LOOP ', loop,
' - destination: ', destination.type, '=', destination.id, '/', destination.uuid,'@', destination.node_id,
@@ -900,6 +917,7 @@ function Dialplan.run(self, destination)
self.caller:set_variable('gs_destination_uuid', destination.uuid);
self.caller:set_variable('gs_destination_number', destination.number);
self.caller:set_variable('gs_destination_node_local', destination.node_local);
+ self.caller:set_variable('gs_destination_node_id, ', destination.node_id);
result = self:switch(destination);
result = result or { continue = false, code = 502, cause = 'DESTINATION_OUT_OF_ORDER', phrase = 'Destination out of order' }
diff --git a/misc/freeswitch/scripts/dialplan/fax.lua b/misc/freeswitch/scripts/dialplan/fax.lua
index 6dce0a9..dc52d16 100644
--- a/misc/freeswitch/scripts/dialplan/fax.lua
+++ b/misc/freeswitch/scripts/dialplan/fax.lua
@@ -231,8 +231,8 @@ function Fax.insert_document(self, record)
return self.database:query(sql_query);
end
-function Fax.trigger_notification(self, fax_document_id, uuid)
- local command = 'http_request.lua ' .. uuid .. ' http://127.0.0.1/trigger/fax?fax_account_id=' .. tostring(fax_document_id);
+function Fax.trigger_notification(self, fax_account_id, uuid)
+ local command = 'http_request.lua ' .. uuid .. ' http://127.0.0.1/trigger/fax?fax_account_id=' .. tostring(fax_account_id);
require 'common.fapi'
return common.fapi.FApi:new():execute('luarun', command);
diff --git a/misc/freeswitch/scripts/dialplan/functions.lua b/misc/freeswitch/scripts/dialplan/functions.lua
index 780e3be..a47d9d3 100644
--- a/misc/freeswitch/scripts/dialplan/functions.lua
+++ b/misc/freeswitch/scripts/dialplan/functions.lua
@@ -23,7 +23,6 @@ function Functions.ensure_caller_sip_account(self, caller)
end
function Functions.dialplan_function(self, caller, dialed_number)
- require 'common.str'
local parameters = common.str.to_a(dialed_number, '%-');
if not parameters[2] then
return { continue = false, code = 484, phrase = 'Malformed function parameters', no_cdr = true };
@@ -120,35 +119,32 @@ function Functions.dialplan_function(self, caller, dialed_number)
return result or { continue = false, code = 505, phrase = 'Error executing function', no_cdr = true };
end
--- Transfer all calls to a conference
+
function Functions.transfer_all(self, caller, destination_number)
- self.log:info('TRANSFER_ALL - caller: ', caller.account_type, '/', caller.account_uuid, ' number: ', destination_number);
-
local caller_sip_account = self:ensure_caller_sip_account(caller);
if not caller_sip_account then
self.log:error('TRANSFER_ALL - incompatible caller');
return { continue = false, code = 403, phrase = 'Incompatible caller' }
end
- -- Query call and channel table for channel IDs
- local sql_query = 'SELECT `b`.`name` AS `caller_chan_name`, `a`.`caller_uuid`, `a`.`callee_uuid` \
- FROM `calls` `a` JOIN `channels` `b` ON `a`.`caller_uuid` = `b`.`uuid` JOIN `channels` `c` \
- ON `a`.`callee_uuid` = `c`.`uuid` WHERE `b`.`name` LIKE ("%' .. caller_sip_account.record.auth_name .. '@%") \
- OR `c`.`name` LIKE ("%' .. caller_sip_account.record.auth_name .. '@%") LIMIT 100';
+ self.log:info('TRANSFER_ALL - initiator: ', caller.account.class, '=', caller.account.id, '/', caller.account.uuid, ', number: ', destination_number);
+ local sql_query = 'SELECT `uuid`, `b_uuid`, `callee_number`, `caller_id_number`, `sip_account_id`, `b_sip_account_id` \
+ FROM `calls_active` WHERE `sip_account_id` = '.. caller.account.id .. ' OR `b_sip_account_id` = '.. caller.account.id;
+ local index = 1;
self.database:query(sql_query, function(call_entry)
- local uid = nil
- if call_entry.caller_chan_name:find(caller_sip_account.record.auth_name .. "@") then
- uid = call_entry.callee_uuid;
- self.log:debug("Transfering callee channel with uid: " .. uid);
- else
- uid = call_entry.caller_uuid;
- self.log:debug("Transfering caller channel with uid: " .. uid);
+ if not common.str.blank(call_entry.uuid) and tostring(caller.account.id) ~= tostring(call_entry.sip_account_id) then
+ self.log:info('TRANSFER_ALEG ', index, ' - channel/', call_entry.uuid, '|', call_entry.caller_id_number);
+ freeswitch.API():execute("uuid_transfer", call_entry.uuid .. " " .. destination_number);
+ end
+ if not common.str.blank(call_entry.b_uuid) and tostring(caller.account.id) ~= tostring(call_entry.b_sip_account_id) then
+ self.log:info('TRANSFER_BLEG ', index, ' - channel/', call_entry.b_uuid, '|', call_entry.callee_number);
+ freeswitch.API():execute("uuid_transfer", call_entry.b_uuid .. " " .. destination_number);
end
- freeswitch.API():execute("uuid_transfer", uid .. " " .. destination_number);
+ index = index + 1;
end)
- return destination_number;
+ return { continue = true, number = destination_number }
end
@@ -165,19 +161,18 @@ function Functions.intercept_any_number(self, caller, destination_number)
local phone_numberable = common.object.Object:new{ log = self.log, database = self.database}:find{class = phone_number.record.phone_numberable_type, id = phone_number.record.phone_numberable_id};
if not phone_numberable then
- self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - numberable not found: ', dphone_number.record.phone_numberable_type, '=', phone_number.record.phone_numberable_id);
+ self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - numberable not found: ', phone_number.record.phone_numberable_type, '=', phone_number.record.phone_numberable_id);
return { continue = false, code = 404, phrase = 'Destination not found', no_cdr = true };
end
- require 'common.str';
require 'common.group';
local group_class = common.group.Group:new{ log = self.log, database = self.database };
- local group_ids = group_class:union(common.str.try(caller, 'auth_account.group_ids'), common.str.try(caller, 'auth_account.owner.group_ids'));
+ local group_ids = group_class:union(common.array.try(caller, 'auth_account.group_ids'), common.array.try(caller, 'auth_account.owner.group_ids'));
local target_groups, target_group_ids = group_class:permission_targets(group_ids, 'pickup');
- local destination_group_ids = group_class:union(common.str.try(phone_numberable, 'group_ids'), common.str.try(phone_numberable, 'owner.group_ids'));
+ local destination_group_ids = group_class:union(common.array.try(phone_numberable, 'group_ids'), common.array.try(phone_numberable, 'owner.group_ids'));
if #group_class:intersection(destination_group_ids, target_group_ids) == 0 then
- self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - Groups not found or insufficient permissions');
+ self.log:notice('FUNCTION_INTERCEPT_ANY_NUMBER - Groups not found or insufficient permissions, destination:', destination_group_ids, ', target: ', target_group_ids);
return { continue = false, code = 402, phrase = '"Insufficient permissions', no_cdr = true };
end
@@ -195,10 +190,9 @@ function Functions.group_pickup(self, caller, group_id)
return { continue = false, code = 505, phrase = 'Incompatible destination', no_cdr = true };
end
- require 'common.str';
require 'common.group';
local group_class = common.group.Group:new{ log = self.log, database = self.database };
- local group_ids = group_class:union(common.str.try(caller, 'auth_account.group_ids'), common.str.try(caller, 'auth_account.owner.group_ids'));
+ local group_ids = group_class:union(common.array.try(caller, 'auth_account.group_ids'), common.array.try(caller, 'auth_account.owner.group_ids'));
local target_group = group_class:is_target(group_id, 'pickup');
if not target_group then
@@ -250,8 +244,6 @@ end
function Functions.user_login(self, caller, number, pin)
- require 'common.str'
-
local PHONE_NUMBER_LEN_MIN = 4;
local PHONE_NUMBER_LEN_MAX = 12;
local PIN_LEN_MIN = 4;
@@ -367,7 +359,6 @@ end
function Functions.user_logout(self, caller)
- require 'common.str'
self.log:info('LOGOUT - caller: ', caller.account_type, '/', caller.account_uuid, ', caller_id: ', caller.caller_id_number);
-- find caller's sip account
@@ -845,8 +836,6 @@ end
function Functions.hangup(self, caller, code, phrase)
- require 'common.str'
-
if not tonumber(code) then
code = 403;
phrase = 'Forbidden';
@@ -885,8 +874,7 @@ function Functions.call_parking_inout_index(self, caller, stall_index)
return { continue = false, code = 404, phrase = 'No parkings stall specified', no_cdr = true }
end
- require 'common.str';
- local owner = common.str.try(caller, 'auth_account.owner');
+ local owner = common.array.try(caller, 'auth_account.owner');
if not owner then
self.log:notice('FUNCTION_CALL_PARKING_INOUT_INDEX - stall owner not specified');
diff --git a/misc/freeswitch/scripts/dialplan/hunt_group.lua b/misc/freeswitch/scripts/dialplan/hunt_group.lua
index fa3c05b..b1728c3 100644
--- a/misc/freeswitch/scripts/dialplan/hunt_group.lua
+++ b/misc/freeswitch/scripts/dialplan/hunt_group.lua
@@ -38,7 +38,7 @@ end
function HuntGroup.find_by_uuid(self, uuid)
- local sql_query = 'SELECT * FROM `hunt_groups` WHERE `id`= "'.. uuid .. '" LIMIT 1';
+ local sql_query = 'SELECT * FROM `hunt_groups` WHERE `uuid`= "'.. uuid .. '" LIMIT 1';
local hunt_group = nil;
self.database:query(sql_query, function(entry)
@@ -98,25 +98,26 @@ 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 phone_numbers = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:list_by_owner(self.id, self.class);
+ for index, number in ipairs(phone_numbers) do
+ table.insert(caller.caller_id_numbers, number);
+ end
+
+ self.log:debug('HUNTGROUP ', self.record.id, ' - auth: ', caller.auth_account.class, '=', caller.auth_account.id, '/', caller.auth_account.uuid, ', caller: ', caller.account.class, '=', caller.account.id, '/', caller.account.uuid);
+ self.log:info('HUNTGROUP ', self.record.id, ' - clir: ', caller.clir, ', caller_id_numbers: ', table.concat(caller.caller_id_numbers, ','));
+
+ local hunt_group_destination = caller.destination;
local destinations = {}
for index, hunt_group_member in ipairs(hunt_group_members) do
local destination = dialplan_object:destination_new{ number = hunt_group_member.number };
if destination.type == 'unknown' then
-
+ caller.destination = destination;
caller.destination_number = destination.number;
require 'dialplan.router'
@@ -144,8 +145,8 @@ function HuntGroup.run(self, dialplan_object, caller, destination)
end
end
- caller.destination = save_destination;
- caller.destination_number = save_destination.number;
+ caller.destination = hunt_group_destination;
+ caller.destination_number = hunt_group_destination.number;
local forwarding_destination = nil;
if caller.forwarding_service == 'assistant' and caller.auth_account then
@@ -165,7 +166,7 @@ function HuntGroup.run(self, dialplan_object, caller, destination)
table.insert(recursive_destinations, forwarding_destination);
end
require 'dialplan.sip_call'
- result = dialplan.sip_call.SipCall:new{ log = self.log, database = self.database, caller = caller }:fork( recursive_destinations, { callee_id_number = destination.number, timeout = member_timeout });
+ result = dialplan.sip_call.SipCall:new{ log = self.log, database = self.database, caller = caller }:fork( recursive_destinations, { callee_id_number = hunt_group_destination.number, timeout = member_timeout });
if result.disposition == 'SUCCESS' then
if result.fork_index then
result.destination = recursive_destinations[result.fork_index];
diff --git a/misc/freeswitch/scripts/dialplan/ivr.lua b/misc/freeswitch/scripts/dialplan/ivr.lua
new file mode 100644
index 0000000..f8b8a2d
--- /dev/null
+++ b/misc/freeswitch/scripts/dialplan/ivr.lua
@@ -0,0 +1,119 @@
+-- Gemeinschaft 5 module: ivr class
+-- (c) AMOOMA GmbH 2013
+--
+
+module(...,package.seeall)
+
+Ivr = {}
+
+-- create ivr ivr ;)
+function Ivr.new(self, arg)
+ arg = arg or {}
+ ivr = arg.ivr or {}
+ setmetatable(ivr, self);
+ self.__index = self;
+ self.class = 'ivr';
+ self.log = arg.log;
+ self.caller = arg.caller;
+ self.dtmf_threshold = arg.dtmf_threshold or 500;
+
+ return ivr;
+end
+
+
+function Ivr.ivr_phrase(self, phrase, keys, timeout, ivr_repeat)
+ ivr_repeat = ivr_repeat or 3;
+ timeout = timeout or 30;
+ self.digit = '';
+ self.exit = false;
+
+ self.break_keys = {};
+ for index=1, #keys do
+ self.break_keys[keys[index]] = true;
+ end
+
+ global_callback:callback('dtmf', 'ivr_ivr_phrase', self.ivr_phrase_dtmf, self);
+
+ for index=0, ivr_repeat do
+ self.caller.session:sayPhrase(phrase, table.concat(keys, ':'));
+ self.caller:sleep(timeout * 1000);
+ if self.exit then
+ break;
+ end
+ end
+
+ global_callback:callback_unset('dtmf', 'ivr_ivr_phrase');
+
+ return self.digit;
+end
+
+
+function Ivr.ivr_phrase_dtmf(self, dtmf)
+ if self.break_keys[dtmf.digit] then
+ self.digit = dtmf.digit;
+ self.exit = true;
+ return false;
+ end
+end
+
+
+function Ivr.read_phrase(self, phrase, phrase_data, max_keys, min_keys, timeout, enter_key)
+ self.max_keys = max_keys or 64;
+ self.min_keys = min_keys or 1;
+ self.enter_key = enter_key or '#';
+ self.digits = '';
+ self.exit = false;
+ timeout = timeout or 30;
+
+ global_callback:callback('dtmf', 'ivr_read_phrase', self.read_phrase_dtmf, self);
+ self.caller.session:sayPhrase(phrase, phrase_data or enter_key or '');
+ self.caller:sleep(timeout * 1000);
+ global_callback:callback_unset('dtmf', 'ivr_read_phrase');
+
+ return self.digits;
+end
+
+
+function Ivr.read_phrase_dtmf(self, dtmf)
+ if dtmf.duration < self.dtmf_threshold then
+ return nil;
+ end
+
+ if self.enter_key == dtmf.digit then
+ self.exit = true;
+ return false;
+ end
+
+ self.digits = self.digits .. dtmf.digit;
+end
+
+
+function Ivr.check_pin(self, phrase, pin, pin_timeout, pin_repeat, key_enter)
+ if not pin then
+ return nil;
+ end
+
+ pin_timeout = pin_timeout or 30;
+ pin_repeat = pin_repeat or 3;
+ key_enter = key_enter or '#';
+
+ local digits = '';
+ for i = 1, pin_repeat do
+ if digits == pin then
+ self.caller:send_display('PIN: OK');
+ break
+ elseif digits ~= "" then
+ self.caller:send_display('PIN: wrong');
+ end
+ self.caller:send_display('Enter PIN');
+ digits = ivr:read_phrase(phrase, nil, 0, pin:len() + 1, pin_timeout, key_enter);
+ end
+
+ if digits ~= pin then
+ self.caller:send_display('PIN: wrong');
+ return false
+ end
+ self.caller:send_display('PIN: OK');
+
+ return true;
+end
diff --git a/misc/freeswitch/scripts/dialplan/router.lua b/misc/freeswitch/scripts/dialplan/router.lua
index 8473c2b..322c748 100644
--- a/misc/freeswitch/scripts/dialplan/router.lua
+++ b/misc/freeswitch/scripts/dialplan/router.lua
@@ -9,6 +9,7 @@ Router = {}
-- create route object
function Router.new(self, arg)
require 'common.str';
+ require 'common.array';
arg = arg or {}
object = arg.object or {}
setmetatable(object, self);
@@ -19,6 +20,7 @@ function Router.new(self, arg)
self.routes = arg.routes or {};
self.caller = arg.caller;
self.variables = arg.variables or {};
+ self.log_details = arg.log_details;
self.routing_tables = {};
return object;
end
@@ -60,31 +62,37 @@ function Router.read_table(self, table_name, force_reload)
end
-function Router.expand_variables(self, line, variables, variables2)
- return (line:gsub('{([%a%d%._]+)}', function(captured)
- return common.str.try(variables, captured) or common.str.try(variables2, captured) or '';
- end))
-end
-
-
function Router.element_match(self, pattern, search_string, replacement, route_variables)
local success, result = pcall(string.find, search_string, pattern);
if not success then
- self.log:error('ELEMENT_MATCH - table error - pattern: ', pattern, ', search_string: ', search_string);
+ self.log:error('ELEMENT_ERROR - table error - pattern: ', pattern, ', search_string: ', search_string);
elseif result then
- return true, search_string:gsub(pattern, self:expand_variables(replacement, route_variables, self.variables));
+ local replace_by = common.array.expand_variables(replacement, route_variables, self.variables)
+ result = search_string:gsub(pattern, replace_by);
+ if self.log_details then
+ self.log:debug('ELEMENT_MATCH - ', search_string, ' ~= ', pattern, ' => ', replacement, ' => ', replace_by);
+ end
+ return true, result;
end
+ if self.log_details then
+ self.log:debug('ELEMENT_NO_MATCH - ', search_string, ' != ', pattern);
+ end
return false;
end
-function Router.element_match_group(self, pattern, groups, replacement, use_key, route_variables)
+function Router.element_match_group(self, pattern, groups, replacement, use_key, route_variables, variable_name)
if type(groups) ~= 'table' then
+ self.log:debug('ELEMENT_FIND_IN_ARRAY - no such array: ', variable_name, ', use_keys: ', tostring(use_key));
return false;
end
+ if self.log_details then
+ self.log:debug('ELEMENT_FIND_IN_ARRAY - array: ', variable_name, ', use_keys: ', tostring(use_key));
+ end
+
for key, value in pairs(groups) do
if use_key then
value = key;
@@ -102,8 +110,9 @@ function Router.route_match(self, route)
gateway = 'gateway' .. route.endpoint_id,
['type'] = route.endpoint_type,
id = route.endpoint_id,
- destination_number = common.str.try(self, 'caller.destination_number'),
+ destination_number = common.array.try(self, 'caller.destination_number'),
channel_variables = {},
+ route_id = route.id,
};
local route_matches = false;
@@ -114,22 +123,26 @@ function Router.route_match(self, route)
local element = route.elements[index];
+ if self.log_details then
+ self.log:debug('ROUTE_ELEMENT ', element.id, ' - var_in: ', element.var_in, ', var_out: ', element.var_out, ', action: ', element.action, ', mandatory: ', element.mandatory);
+ end
+
if element.action ~= 'none' then
if common.str.blank(element.var_in) or common.str.blank(element.pattern) and element.action == 'set' then
result = true;
- replacement = self:expand_variables(element.replacement, destination, self.variables);
+ replacement = common.array.expand_variables(element.replacement, destination, self.variables);
else
local command, variable_name = common.str.partition(element.var_in, ':');
if not command or not variable_name then
- local search_string = tostring(common.str.try(destination, element.var_in) or common.str.try(self.caller, element.var_in));
+ local search_string = tostring(common.array.try(destination, element.var_in) or common.array.try(self.caller, element.var_in));
result, replacement = self:element_match(tostring(element.pattern), search_string, tostring(element.replacement), destination);
elseif command == 'var' then
- local search_string = tostring(common.str.try(self.caller, element.var_in));
+ local search_string = tostring(common.array.try(self.caller, variable_name));
result, replacement = self:element_match(tostring(element.pattern), search_string, tostring(element.replacement));
elseif command == 'key' or command == 'val' then
- local groups = common.str.try(self.caller, variable_name);
- result, replacement = self:element_match_group(tostring(element.pattern), groups, tostring(element.replacement), command == 'key');
+ local groups = common.array.try(destination, variable_name) or common.array.try(self.caller, variable_name);
+ result, replacement = self:element_match_group(tostring(element.pattern), groups, tostring(element.replacement), command == 'key', destination, variable_name);
elseif command == 'chv' then
local search_string = self.caller:to_s(variable_name);
result, replacement = self:element_match(tostring(element.pattern), search_string, tostring(element.replacement));
@@ -151,7 +164,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
- common.str.set(destination, element.var_out, replacement);
+ common.array.set(destination, element.var_out, replacement);
elseif command == 'chv' then
destination.channel_variables[variable_name] = replacement;
elseif command == 'hdr' then
@@ -180,7 +193,10 @@ function Router.route_run(self, table_name, find_first)
local routes = {};
if type(routing_table) == 'table' then
- for index=1, #routing_table do
+ for index=1, #routing_table do
+ if self.log_details then
+ self.log:info('ROUTE_',table_name:upper(),' ', index,' - ', table_name,'=', routing_table[index].id, '/', routing_table[index].name);
+ end
local route = self:route_match(routing_table[index]);
if route then
table.insert(routes, route);
diff --git a/misc/freeswitch/scripts/dialplan/session.lua b/misc/freeswitch/scripts/dialplan/session.lua
index 7de85ca..9c43e74 100644
--- a/misc/freeswitch/scripts/dialplan/session.lua
+++ b/misc/freeswitch/scripts/dialplan/session.lua
@@ -58,6 +58,13 @@ function Session.init_channel_variables(self)
self.node_id = self:to_i('sip_h_X-GS_node_id');
self.loop_count = self:to_i('sip_h_X-GS_loop_count');
+ self.previous_destination_type = self:to_s('gs_destination_type');
+ self.previous_destination_id = self:to_i('gs_destination_id');
+ self.previous_destination_uuid = self:to_s('gs_destination_uuid');
+ self.previous_destination_owner_type = self:to_s('gs_destination_owner_type');
+ self.previous_destination_owner_id = self:to_i('gs_destination_owner_id');
+ self.previous_destination_owner_uuid = self:to_s('gs_destination_owner_uuid');
+
if self.node_id > 0 and self.node_id ~= self.local_node_id then
self.from_node = true;
else
@@ -166,6 +173,12 @@ function Session.answer(self)
return self.session:answer();
end
+-- Is answered?
+function Session.answered(self)
+ return self.session:answered();
+end
+
+
function Session.intercept(self, uid)
self.session:execute("intercept", uid);
end
@@ -226,3 +239,8 @@ function Session.expand_variables(self, line)
return self.session:getVariable(captured) or '';
end))
end
+
+
+function Session.playback(self, file)
+ self.session:streamFile(file);
+end
diff --git a/misc/freeswitch/scripts/dialplan/sip_call.lua b/misc/freeswitch/scripts/dialplan/sip_call.lua
index 5c98792..0cde601 100644
--- a/misc/freeswitch/scripts/dialplan/sip_call.lua
+++ b/misc/freeswitch/scripts/dialplan/sip_call.lua
@@ -135,6 +135,17 @@ function SipCall.fork(self, destinations, arg )
if destination.alert_info then
table.insert(origination_variables, "alert_info='" .. destination.alert_info .. "'");
end
+ if destination.account then
+ table.insert(origination_variables, "gs_account_type='" .. common.str.to_s(destination.account.class) .. "'");
+ table.insert(origination_variables, "gs_account_id='" .. common.str.to_i(destination.account.id) .. "'");
+ table.insert(origination_variables, "gs_account_uuid='" .. common.str.to_s(destination.account.uuid) .. "'");
+ end
+ if self.caller.auth_account then
+ table.insert(origination_variables, "gs_auth_account_type='" .. common.str.to_s(self.caller.auth_account.class) .. "'");
+ table.insert(origination_variables, "gs_auth_account_id='" .. common.str.to_i(self.caller.auth_account.id) .. "'");
+ table.insert(origination_variables, "gs_auth_account_uuid='" .. common.str.to_s(self.caller.auth_account.uuid) .. "'");
+ 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);
if destination.pickup_groups and #destination.pickup_groups > 0 then
for key=1, #destination.pickup_groups do
diff --git a/misc/freeswitch/scripts/dialplan/voicemail.lua b/misc/freeswitch/scripts/dialplan/voicemail.lua
index ae7d0a1..caeeb48 100644
--- a/misc/freeswitch/scripts/dialplan/voicemail.lua
+++ b/misc/freeswitch/scripts/dialplan/voicemail.lua
@@ -66,15 +66,14 @@ function Voicemail.find_by_name(self, account_name)
return voicemail_account
end
--- Find Voicemail account by name
+-- Find Voicemail account by number
function Voicemail.find_by_number(self, phone_number)
local sip_account = nil;
require "common.phone_number"
- local phone_number_class = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database };
- local destination_number_object = phone_number_class:find_by_number(phone_number);
- if destination_number_object and destination_number_object.record.phone_numberable_type == "SipAccount" then
- return Voicemail:find_by_sip_account_id(destination_number_object.record.phone_numberable_id);
+ local destination_number_object = common.phone_number.PhoneNumber:new{ log = self.log, database = self.database }:find_by_number(phone_number);
+ if destination_number_object and destination_number_object.record.phone_numberable_type:lower() == "sipaccount" then
+ return self:find_by_sip_account_id(destination_number_object.record.phone_numberable_id);
end
return false;