diff options
Diffstat (limited to 'misc/freeswitch/scripts/dialplan')
-rw-r--r-- | misc/freeswitch/scripts/dialplan/acd.lua | 2 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/cdr.lua | 2 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/dialplan.lua | 228 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/fax.lua | 2 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/functions.lua | 74 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/geo_number.lua | 2 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/hunt_group.lua | 39 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/phone_book.lua | 2 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/presence.lua | 2 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/route.lua | 265 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/router.lua | 187 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/session.lua | 6 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/sip_call.lua | 18 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/tenant.lua | 2 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/user.lua | 4 | ||||
-rw-r--r-- | misc/freeswitch/scripts/dialplan/voicemail.lua | 4 |
16 files changed, 445 insertions, 394 deletions
diff --git a/misc/freeswitch/scripts/dialplan/acd.lua b/misc/freeswitch/scripts/dialplan/acd.lua index 563d836..f4b298e 100644 --- a/misc/freeswitch/scripts/dialplan/acd.lua +++ b/misc/freeswitch/scripts/dialplan/acd.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: acd class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) diff --git a/misc/freeswitch/scripts/dialplan/cdr.lua b/misc/freeswitch/scripts/dialplan/cdr.lua index 55a7889..d0fdede 100644 --- a/misc/freeswitch/scripts/dialplan/cdr.lua +++ b/misc/freeswitch/scripts/dialplan/cdr.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: cdr class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) diff --git a/misc/freeswitch/scripts/dialplan/dialplan.lua b/misc/freeswitch/scripts/dialplan/dialplan.lua index 391f5bf..b92dc70 100644 --- a/misc/freeswitch/scripts/dialplan/dialplan.lua +++ b/misc/freeswitch/scripts/dialplan/dialplan.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: dialplan class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) @@ -7,7 +7,6 @@ module(...,package.seeall) Dialplan = {} -- local constants -local CONFIG_FILE_NAME = '/opt/freeswitch/scripts/ini/dialplan.ini'; local DIAL_TIMEOUT = 120; local MAX_LOOPS = 20; local DIALPLAN_FUNCTION_PATTERN = '^f[_%-].*'; @@ -74,22 +73,22 @@ function Dialplan.domain_get(self, domain) end -function Dialplan.configuration_read(self, file_name) +function Dialplan.configuration_read(self) require 'common.str' - require 'common.configuration_file' + require 'common.configuration_table' -- dialplan configuration - self.config = common.configuration_file.get(file_name or CONFIG_FILE_NAME); + self.config = common.configuration_table.get(self.database, 'dialplan'); self.node_id = common.str.to_i(self.config.parameters.node_id); self.domain = self:domain_get(self.config.parameters.domain); self.dial_timeout = tonumber(self.config.parameters.dial_timeout) or DIAL_TIMEOUT; self.max_loops = tonumber(self.config.parameters.max_loops) or MAX_LOOPS; self.user_image_url = common.str.to_s(self.config.parameters.user_image_url); self.phone_book_entry_image_url = common.str.to_s(self.config.parameters.phone_book_entry_image_url); - self.phonebook_number_lookup = common.str.to_b(self.config.parameters.phonebook_number_lookup); - self.geo_number_lookup = common.str.to_b(self.config.parameters.geo_number_lookup); + self.phonebook_number_lookup = self.config.parameters.phonebook_number_lookup; + self.geo_number_lookup = self.config.parameters.geo_number_lookup; self.default_language = self.config.parameters.default_language or 'en'; - self.send_ringing_to_gateways = common.str.to_b(self.config.parameters.send_ringing_to_gateways); + self.send_ringing_to_gateways = self.config.parameters.send_ringing_to_gateways; if tonumber(self.config.parameters.default_ringtone) then self.default_ringtone = 'http://amooma.de;info=Ringer' .. self.config.parameters.default_ringtone .. ';x-line-id=0'; @@ -113,57 +112,34 @@ function Dialplan.hangup(self, code, phrase, cause) end -function Dialplan.check_auth(self) - local authenticated = false; - - require 'common.str' - if self.caller.from_node then - self.log:info('AUTH_FIRST_STAGE - node authenticated - node_id: ', self.caller.node_id); - authenticated = true; - elseif not common.str.blank(self.caller.auth_account_type) then - self.log:info('AUTH_FIRST_STAGE - sipaccount autheticated by name/password: ', self.caller.auth_account_type, '=', self.caller.account_id, '/', self.caller.account_uuid); - authenticated = true; - elseif self.caller.from_gateway then - self.log:info('AUTH_FIRST_STAGE - gateway autheticated by name/password: gateway=', self.caller.gateway_id, ', name: ', self.caller.gateway_name); - authenticated = true; - else - local gateways = common.configuration_file.get('/opt/freeswitch/scripts/ini/gateways.ini', false); - if not gateways then - return false; - end - for gateway, gateway_parameters in pairs(gateways) do - if common.str.to_s(gateway_parameters.proxy) == self.caller.sip_contact_host then - self.caller.gateway_name = gateway; - self.caller.from_gateway = true; - self.log:info('AUTH_FIRST_STAGE - gateway autheticated by ip: gateway=', self.caller.gateway_id, ', name: ', self.caller.gateway_name, ', ip: ', self.caller.sip_contact_host); - authenticated = true; - end - end - end - - return authenticated; -end - - -function Dialplan.check_auth_node(self) +function Dialplan.auth_node(self) require 'common.node' local node = common.node.Node:new{ log = self.log, database = self.database }:find_by_address(self.caller.sip_contact_host); - return (node ~= nil); + if node then + self.log:info('AUTH_NODE - node_id: ', self.caller.node_id, ', contact address:', self.caller.sip_contact_host); + return true; + end end -function Dialplan.check_auth_ip(self) - self.log:info('AUTH - node: ', self.caller.from_node, ', auth_account: ', self.caller.auth_account_type, ', gateway: ', self.caller.from_gateway); +function Dialplan.auth_sip_account(self) require 'common.str' - if self.caller.from_node then + 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; - elseif not common.str.blank(self.caller.auth_account_type) then - return true; - elseif self.caller.from_gateway then - return true; - else - return nil; + end +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('sip', self.caller); + + 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); + return gateway_class:find_by_id(gateway.id); end end @@ -258,19 +234,21 @@ end function Dialplan.retrieve_caller_data(self) - self.caller.caller_phone_numbers_hash = {} - require 'common.str' - local dialed_sip_user = self.caller:to_s('dialed_user'); + self.caller.caller_phone_numbers_hash = {} -- TODO: Set auth_account on transfer initiated by calling party - if not common.str.blank(dialed_sip_user) then - self.caller.auth_account = self:object_find('sipaccount', self.caller:to_s('dialed_domain'), dialed_sip_user); - self.caller:set_auth_account(self.caller.auth_account); + if not common.str.blank(self.caller.dialed_sip_user) then + self.caller.auth_account = self:object_find('sipaccount', self.caller.dialed_domain, dialed_sip_user); + if self.caller.set_auth_account then + self.caller:set_auth_account(self.caller.auth_account); + end 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(self.caller.auth_account_type, self.caller.auth_account_uuid); - self.caller:set_auth_account(self.caller.auth_account); + if self.caller.set_auth_account then + self.caller:set_auth_account(self.caller.auth_account); + end end if self.caller.auth_account then @@ -299,7 +277,7 @@ function Dialplan.retrieve_caller_data(self) self.log:error('CALLER_DATA - caller owner not found'); end - if not self.caller.clir then + if not self.caller.clir and self.caller.set_caller_id then self.caller:set_caller_id(self.caller.caller_phone_numbers[1], self.caller.account.record.caller_name or self.caller.account.record.name); end else @@ -366,12 +344,6 @@ function Dialplan.destination_new(self, arg) end -function Dialplan.routes_get(self, destination) - require 'dialplan.route' - return dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = self.routes }:outbound(self.caller, destination.number); -end - - function Dialplan.set_caller_picture(self, entry_id, entry_type, image) entry_type = entry_type:lower(); if entry_type == 'user' then @@ -466,16 +438,13 @@ function Dialplan.dial(self, destination) end end - if common.str.to_b(self.config.parameters.bypass_media) then - self.caller:set_variable('bypass_media', true); - end - require 'dialplan.sip_call' return dialplan.sip_call.SipCall:new{ log = self.log, database = self.database, caller = self.caller }:fork( destinations, { timeout = self.dial_timeout_active, 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, } ); end @@ -655,9 +624,11 @@ function Dialplan.callthrough(self, destination) return { continue = false, code = 404, phrase = 'No destination' } end - local route = dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = self.routes }:prerouting(self.caller, destination_number); - if route and route.value then - destination_number = route.value; + require 'dialplan.router' + local route = dialplan.router.Router:new{ log = self.log, database = self.database, caller = self.caller, variables = self.caller }:route_run('prerouting', true); + + if route and route.destination_number then + destination_number = route.destination_number; end if not callthrough:whitelist(destination_number) then @@ -786,16 +757,30 @@ function Dialplan.switch(self, destination) return self:dialplanfunction(destination); elseif not common.str.blank(destination.number) then local result = { continue = false, code = 404, phrase = 'No route' } - local routes = self:routes_get(destination); + + local clip_no_screening = common.str.try(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 + table.insert(self.caller.caller_id_numbers, number); + end + end + 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, ',')); + + destination.callee_id_number = destination.number; + destination.callee_id_name = nil; + + require 'dialplan.router' + local routes = dialplan.router.Router:new{ log = self.log, database = self.database, caller = self.caller, variables = self.caller }:route_run('outbound'); if not routes or #routes == 0 then self.log:notice('SWITCH - no route - number: ', destination.number); return { continue = false, code = 404, phrase = 'No route' } end - destination.callee_id_number = destination.number; - destination.callee_id_name = nil; - if self.phonebook_number_lookup then require 'common.str' local user_id = common.str.try(self.caller, 'account.owner.id'); @@ -828,26 +813,26 @@ 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.class == 'hangup' then + if route.endpoint_type == 'hangup' then return { continue = false, code = route.endpoint, phrase = route.phrase, cause = route.value } end - if route.class == 'forward' then + if route.endpoint_type == 'forward' then return { continue = true, call_forwarding = { number = route.value, service = 'route', type = 'phonenumber' }} end - destination.gateway = route.endpoint; - destination.type = route.class; - destination.number = route.value; - destination.caller_id_number = route.caller_id_number; - destination.caller_id_name = route.caller_id_name; + + for key, value in pairs(route) do + destination[key] = value; + end + result = self:dial(destination); if result.continue == false then break; end - if common.str.to_b(self.routes.failover[tostring(result.code)]) == true then + if common.str.to_b(self.route_failover[tostring(result.code)]) == true then self.log:info('SWITCH - failover - code: ', result.code); - elseif common.str.to_b(self.routes.failover[tostring(result.cause)]) == true then + elseif common.str.to_b(self.route_failover[tostring(result.cause)]) == true then self.log:info('SWITCH - failover - cause: ', result.cause); else self.log:info('SWITCH - no failover - cause: ', result.cause, ', code: ', result.code); @@ -864,10 +849,11 @@ end function Dialplan.run(self, destination) + require 'common.str'; + require 'dialplan.router'; + self.caller:set_variable('hangup_after_bridge', false); - self.caller:set_variable('ringback', self.config.parameters.ringback); self.caller:set_variable('bridge_early_media', 'true'); - self.caller:set_variable('send_silence_when_idle', 0); self.caller:set_variable('default_language', self.default_language); self.caller:set_variable('gs_save_cdr', true); self.caller:set_variable('gs_call_service', 'dial'); @@ -875,30 +861,69 @@ function Dialplan.run(self, destination) self.caller.date = os.date('%y%m%d%w'); self.caller.time = os.date('%H%M%S'); - self.routes = common.configuration_file.get('/opt/freeswitch/scripts/ini/routes.ini'); + if type(self.config.variables) == 'table' then + for key, value in pairs(self.config.variables) do + self.caller:set_variable(key, value); + end + end + self.caller.domain_local = self.domain; self:retrieve_caller_data(); + self.route_failover = common.configuration_table.get(self.database, 'call_route', 'failover'); if not destination or destination.type == 'unknown' then - require 'dialplan.route' local route = nil; + if self.caller.gateway then + if not common.str.blank(self.caller.gateway.settings.number_source) then + self.log:debug('INBOUND_NUMBER: number_source: ', self.caller.gateway.settings.number_source, ', number: ', self.caller:to_s(self.caller.gateway.settings.number_source)); + self.caller.destination_number = self.caller:to_s(self.caller.gateway.settings.number_source); + end - if self.caller.from_gateway then - local route_object = dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = self.routes }; - route = route_object:inbound(self.caller, self.caller.destination_number); - local inbound_caller_id_number = route_object:inbound_cid_number(self.caller, self.caller.gateway_name, 'gateway'); - route_object.expandable.caller_id_number = inbound_caller_id_number; - local inbound_caller_id_name = route_object:inbound_cid_name(self.caller, self.caller.gateway_name, 'gateway'); - self.log:info('INBOUND_CALLER_ID_REWRITE - number: ', inbound_caller_id_number, ', name: ', inbound_caller_id_name); - self.caller.caller_id_number = inbound_caller_id_number or self.caller.caller_id_number; - self.caller.caller_id_name = inbound_caller_id_name or self.caller.caller_id_name; - self.caller.caller_phone_numbers[1] = self.caller.caller_id_number; + route = dialplan.router.Router:new{ log = self.log, database = self.database, caller = self.caller, variables = self.caller }:route_run('inbound', true); + if route then + local ignore_keys = { + id = true, + gateway = true, + ['type'] = true, + channel_variables = true, + }; + + for key, value in pairs(route) do + if not ignore_keys[key] then + self.caller[key] = value; + end + end + + self.caller.caller_phone_numbers[1] = self.caller.caller_id_number; + else + self.log:notice('INBOUND - no route'); + end else - route = dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = self.routes }:prerouting(self.caller, self.caller.destination_number); + route = dialplan.router.Router:new{ log = self.log, database = self.database, caller = self.caller, variables = self.caller }:route_run('prerouting', true); + if route then + local ignore_keys = { + id = true, + gateway = true, + ['type'] = true, + channel_variables = true, + }; + + for key, value in pairs(route) do + if not ignore_keys[key] then + self.caller[key] = value; + end + end + end end if route then - destination = self:destination_new{ number = route.value } + if type(route.channel_variables) == 'table' then + for key, value in pairs(route.channel_variables) do + self.caller:set_variable(key, value); + end + end + + destination = self:destination_new{ ['type'] = route.type, id = route.id, number = route.destination_number } self.caller.destination_number = destination.number; self.caller.destination = destination; elseif not destination or destination.type == 'unknown' then @@ -979,6 +1004,7 @@ function Dialplan.run(self, destination) self.log:info('LOOP ', loop, ' NEW_DESTINATION_NUMBER - number: ', result.number ); destination = self:destination_new{ number = result.number } self.caller.destination = destination; + self.caller.destination_number = destination.number; end end diff --git a/misc/freeswitch/scripts/dialplan/fax.lua b/misc/freeswitch/scripts/dialplan/fax.lua index 2a40620..aa29ff6 100644 --- a/misc/freeswitch/scripts/dialplan/fax.lua +++ b/misc/freeswitch/scripts/dialplan/fax.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: fax class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) diff --git a/misc/freeswitch/scripts/dialplan/functions.lua b/misc/freeswitch/scripts/dialplan/functions.lua index 9a89857..2ca51c8 100644 --- a/misc/freeswitch/scripts/dialplan/functions.lua +++ b/misc/freeswitch/scripts/dialplan/functions.lua @@ -51,10 +51,16 @@ function Functions.dialplan_function(self, caller, dialed_number) result = self:user_auto_logout(caller, true); elseif fid == "loaoff" then result = self:user_auto_logout(caller, false); + elseif fid == "redial" then + result = self:redial(caller); elseif fid == "dcliroff" then result = self:dial_clir_off(caller, parameters[3]); elseif fid == "dcliron" then result = self:dial_clir_on(caller, parameters[3]); + elseif fid == "cliron" then + result = self:clir_on(caller); + elseif fid == "cliroff" then + result = self:clir_off(caller); elseif fid == "clipon" then result = self:clip_on(caller); elseif fid == "clipoff" then @@ -503,6 +509,30 @@ function Functions.user_auto_logout(self, caller, auto_logout) caller:sleep(1000); end +function Functions.redial(self, caller) + -- Ensure a valid sip account + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + local sql_query = 'SELECT `destination_number` \ + FROM `call_histories` \ + WHERE `entry_type` = "dialed" \ + AND `call_historyable_type` = "SipAccount" \ + AND `call_historyable_id` = ' .. caller_sip_account.record.id .. ' \ + ORDER BY `start_stamp` DESC LIMIT 1'; + + local phone_number = self.database:query_return_value(sql_query); + + common_str = require 'common.str'; + if common_str.blank(phone_number) then + return { continue = false, code = 404, phrase = 'No phone number saved', no_cdr = true } + end + + return { continue = true, number = phone_number } +end + function Functions.dial_clir_off(self, caller, phone_number) -- Ensure a valid sip account local caller_sip_account = self:ensure_caller_sip_account(caller); @@ -565,6 +595,48 @@ function Functions.callwaiting_off(self, caller) return { continue = false, code = 200, phrase = 'OK', no_cdr = true } end +function Functions.clir_on(self, caller) + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + local sql_query = 'UPDATE `sip_accounts` SET `clir` = TRUE WHERE `id` = ' .. caller_sip_account.record.id; + + if not self.database:query(sql_query) then + self.log:notice("CLIR could not be set"); + return { continue = false, code = 500, phrase = 'CLIR could not be set', no_cdr = true } + + end + + caller:answer(); + caller:send_display('CLIR on'); + caller:sleep(1000); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + +function Functions.clir_off(self, caller) + -- Find caller's SipAccount + local caller_sip_account = self:ensure_caller_sip_account(caller); + if not caller_sip_account then + return { continue = false, code = 403, phrase = 'Incompatible caller', no_cdr = true } + end + + local sql_query = 'UPDATE `sip_accounts` SET `clir` = FALSE WHERE `id` = ' .. caller_sip_account.record.id; + + if not self.database:query(sql_query) then + self.log:notice("CLIR could not be set"); + return { continue = false, code = 500, phrase = 'CLIR could not be set', no_cdr = true } + + end + + caller:answer(); + caller:send_display('CLIR off'); + caller:sleep(1000); + return { continue = false, code = 200, phrase = 'OK', no_cdr = true } +end + function Functions.clip_on(self, caller) -- Find caller's SipAccount local caller_sip_account = self:ensure_caller_sip_account(caller); @@ -586,6 +658,7 @@ function Functions.clip_on(self, caller) return { continue = false, code = 200, phrase = 'OK', no_cdr = true } end + function Functions.clip_off(self, caller) -- Find caller's SipAccount local caller_sip_account = self:ensure_caller_sip_account(caller); @@ -607,7 +680,6 @@ function Functions.clip_off(self, caller) return { continue = false, code = 200, phrase = 'OK', no_cdr = true } end - function Functions.call_forwarding_off(self, caller, call_forwarding_service, delete) local defaults = {log = self.log, database = self.database, domain = caller.domain} diff --git a/misc/freeswitch/scripts/dialplan/geo_number.lua b/misc/freeswitch/scripts/dialplan/geo_number.lua index 06bfd62..76cc01b 100644 --- a/misc/freeswitch/scripts/dialplan/geo_number.lua +++ b/misc/freeswitch/scripts/dialplan/geo_number.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: geonumber class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) diff --git a/misc/freeswitch/scripts/dialplan/hunt_group.lua b/misc/freeswitch/scripts/dialplan/hunt_group.lua index 87f86f1..2c73bf8 100644 --- a/misc/freeswitch/scripts/dialplan/hunt_group.lua +++ b/misc/freeswitch/scripts/dialplan/hunt_group.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: hunt group class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) @@ -98,21 +98,33 @@ 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 save_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 - require 'dialplan.route' - local routes = dialplan.route.Route:new{ log = self.log, database = self.database, routing_table = dialplan_object.routes }:outbound(caller, destination.number); - if routes and #routes > 0 then - destination.callee_id_number = destination.number; - destination.callee_id_name = nil; - local route = routes[1]; - destination.gateway = route.endpoint; - destination.type = route.class; - destination.number = route.value; - destination.caller_id_number = route.caller_id_number; - destination.caller_id_name = route.caller_id_name; + + caller.destination_number = destination.number; + + require 'dialplan.router' + local route = dialplan.router.Router:new{ log = self.log, database = self.database, caller = caller, variables = caller }:route_run('outbound', true); + + if route then + destination = dialplan_object:destination_new{ ['type'] = route.type, id = route.id, number = route.destination_number } + + local ignore_keys = { + id = true, + ['type'] = true, + channel_variables = true, + }; + + for key, value in pairs(route) do + if not ignore_keys[key] then + destination[key] = value; + end + end + table.insert(destinations, destination); end else @@ -120,6 +132,9 @@ function HuntGroup.run(self, dialplan_object, caller, destination) end end + caller.destination = save_destination; + caller.destination_number = save_destination.number; + local forwarding_destination = nil; if caller.forwarding_service == 'assistant' and caller.auth_account then forwarding_destination = dialplan_object:destination_new{ type = caller.auth_account.class, id = caller.auth_account.id, number = forwarding_number } diff --git a/misc/freeswitch/scripts/dialplan/phone_book.lua b/misc/freeswitch/scripts/dialplan/phone_book.lua index 089f115..6653789 100644 --- a/misc/freeswitch/scripts/dialplan/phone_book.lua +++ b/misc/freeswitch/scripts/dialplan/phone_book.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: phone book class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) diff --git a/misc/freeswitch/scripts/dialplan/presence.lua b/misc/freeswitch/scripts/dialplan/presence.lua index 234b908..0f63ce9 100644 --- a/misc/freeswitch/scripts/dialplan/presence.lua +++ b/misc/freeswitch/scripts/dialplan/presence.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: presence class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) diff --git a/misc/freeswitch/scripts/dialplan/route.lua b/misc/freeswitch/scripts/dialplan/route.lua deleted file mode 100644 index 2243cbe..0000000 --- a/misc/freeswitch/scripts/dialplan/route.lua +++ /dev/null @@ -1,265 +0,0 @@ --- Gemeinschaft 5 module: routing class --- (c) AMOOMA GmbH 2012 --- - -module(...,package.seeall) - -Route = {} - --- create route object -function Route.new(self, arg) - arg = arg or {} - object = arg.object or {} - setmetatable(object, self); - self.__index = self; - self.log = arg.log; - self.database = arg.database; - self.routing_table = arg.routing_table; - self.expandable = arg.expandable or {}; - return object; -end - --- find matching routes -function Route.prerouting(self, caller, number) - require 'common.routing_tables' - - for index, routing_entry in pairs(self.routing_table.prerouting) do - local route = common.routing_tables.match_route(routing_entry, number); - if route.error then - self.log:error('PREROUTE - error: ', route.error); - elseif route.value then - self.log:info('ROUTE_PREROUTING - called number: ', number, ', value: ', route.value, ', pattern: ', route.pattern); - return route; - end - end -end - --- find matching routes -function Route.outbound(self, caller, number) - local routes = {}; - require 'common.routing_tables' - require 'common.str' - - local ignore_arguments = { - class=true, - endpoint=true, - pattern=true, - value=true, - group=true, - phrase=true, - } - - local clip_no_screening = common.str.try(caller, 'account.record.clip_no_screening'); - local 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_id_numbers, number); - end - end - for index, number in ipairs(caller.caller_phone_numbers) do - table.insert(caller_id_numbers, number); - end - self.log:info('CALLER_ID_NUMBER - caller_id_numbers: ', table.concat(caller_id_numbers, ',')); - - for index, routing_entry in pairs(self.routing_table.outbound) do - local route = common.routing_tables.match_route(routing_entry, number); - if route.error then - self.log:error('ROUTE_OUTBOUND - error: ', route.error); - elseif route.value then - local valid_route = true; - - for argument, value in pairs(route) do - if not ignore_arguments[argument] then - local table_value = common.str.downcase(tostring(common.str.try(caller, argument))); - value = common.str.downcase(tostring(value)); - if table_value:match(value) then - self.log:info('ROUTE_OUTBOUND_POSITIVE - ', argument, '=', value, ' ~ ', table_value, ', pattern: ', route.pattern); - else - self.log:info('ROUTE_OUTBOUND_NEGATIVE - ', argument, '=', value, ' !~ ', table_value, ', pattern: ', route.pattern); - valid_route = false; - end - end - end - - if route.group then - if common.str.try(caller.auth_account, 'owner.groups.' .. tostring(route.group)) then - self.log:info('ROUTE_OUTBOUND_POSITIVE - group=', route.group, ', pattern: ', route.pattern); - else - self.log:info('ROUTE_OUTBOUND_NEGATIVE - group=', route.group, ', pattern: ', route.pattern); - valid_route = false; - end - end - - if route.cidn then - if caller.caller_id_number:match(route.cidn) then - self.log:info('ROUTE_OUTBOUND_POSITIVE - cidn=', route.cidn, ' ~ ', caller.caller_id_number,', pattern: ', route.pattern); - else - self.log:info('ROUTE_OUTBOUND_NEGATIVE - cidn=', route.cidn, ' !~ ', caller.caller_id_number, ', pattern: ', route.pattern); - valid_route = false; - end - end - - if valid_route then - if route.class ~= 'hangup' then - route.caller_id_number = self:outbound_cid_number(caller, caller_id_numbers, route.endpoint, route.class); - self.expandable.caller_id_number = route.caller_id_number; - route.caller_id_name = self:outbound_cid_name(caller, route.endpoint, route.class); - end - table.insert(routes, route); - self.log:info('ROUTE_OUTBOUND ', #routes,' - ', route.class, '=', route.endpoint, ', value: ', route.value, ', caller_id_number: ', route.caller_id_number, ', caller_id_name: ', route.caller_id_name); - end - end - end - - return routes; -end - - -function Route.inbound(self, caller, number) - require 'common.routing_tables' - - local ignore_arguments = { - class=true, - endpoint=true, - pattern=true, - value=true, - group=true, - phrase=true, - } - - for index, routing_entry in pairs(self.routing_table.inbound) do - local route = common.routing_tables.match_route(routing_entry, number); - if route.error then - self.log:error('ROUTE_INBOUND - error: ', route.error); - elseif route.value then - local valid_route = true; - - for argument, value in pairs(route) do - if not ignore_arguments[argument] then - local table_value = common.str.downcase(tostring(common.str.try(caller, argument))); - value = common.str.downcase(tostring(value)); - if table_value:match(value) then - self.log:info('ROUTE_INBOUND_POSITIVE - ', argument, '=', value, ' ~ ', table_value, ', pattern: ', route.pattern); - else - self.log:info('ROUTE_INBOUND_NEGATIVE - ', argument, '=', value, ' !~ ', table_value, ', pattern: ', route.pattern); - valid_route = false; - end - end - end - - if route.class and route.endpoint then - if route.class == 'gateway' and caller.gateway_name:match(route.endpoint) then - self.log:info('ROUTE_INBOUND_POSITIVE - ', route.class, '=', route.endpoint, ' ~ ', caller.gateway_name, ', pattern: ', route.pattern); - else - self.log:info('ROUTE_INBOUND_NEGATIVE - ', route.class, '=', route.endpoint, ' !~ ', caller.gateway_name, ', pattern: ', route.pattern); - valid_route = false; - end - end - - if valid_route then - self.log:info('ROUTE_INBOUND - called number: ', number, ', value: ', route.value, ', pattern: ', route.pattern); - return route; - end - end - end -end - --- find caller id -function Route.caller_id(self, caller, cid_entry, search_str, endpoint, class) - local ignore_arguments = { - class=true, - endpoint=true, - pattern=true, - value=true, - group=true, - phrase=true, - } - - local route = common.routing_tables.match_route(cid_entry, search_str, self.expandable); - if route.error then - self.log:error('CALLER_ID - error: ', route.error); - elseif route.value then - local valid_route = true; - - for argument, value in pairs(route) do - if not ignore_arguments[argument] then - local table_value = common.str.downcase(tostring(common.str.try(caller, argument))); - value = common.str.downcase(tostring(value)); - if table_value:match(value) then - self.log:debug('CALLER_ID_POSITIVE - ', argument, '=', value, ' ~ ', table_value, ', pattern: ', route.pattern); - else - self.log:debug('CALLER_ID_NEGATIVE - ', argument, '=', value, ' !~ ', table_value, ', pattern: ', route.pattern); - valid_route = false; - end - end - end - - if route.group then - if common.str.try(caller.auth_account, 'owner.groups.' .. tostring(route.group)) then - self.log:debug('CALLER_ID_POSITIVE - group=', route.group, ', pattern: ', route.pattern); - else - self.log:debug('CALLER_ID_NEGATIVE - group=', route.group, ', pattern: ', route.pattern); - valid_route = false; - end - end - - endpoint = tostring(endpoint); - if route.class and route.endpoint then - if route.class == 'gateway' and endpoint:match(route.endpoint) then - self.log:debug('CALLER_ID_POSITIVE - ', route.class, '=', route.endpoint, ' ~ ', endpoint, ', pattern: ', route.pattern); - else - self.log:debug('CALLER_ID_NEGATIVE - ', route.class, '=', route.endpoint, ' !~ ', endpoint, ', pattern: ', route.pattern); - valid_route = false; - end - end - - if valid_route then - self.log:debug('CALLER_ID ', route.class, '=', route.endpoint, ', value: ', route.value); - return route.value; - end - end - - return nil; -end - --- find matching caller id number -function Route.outbound_cid_number(self, caller, caller_id_numbers, endpoint, class) - for route_index, cid_entry in pairs(self.routing_table.outbound_cid_number) do - for index, number in ipairs(caller_id_numbers) do - local route = self:caller_id(caller, cid_entry, number, endpoint, class); - if route then - return route; - end - end - end -end - --- find matching caller id name -function Route.outbound_cid_name(self, caller, endpoint, class) - for route_index, cid_entry in pairs(self.routing_table.outbound_cid_name) do - local route = self:caller_id(caller, cid_entry, caller.caller_id_name, endpoint, class); - if route then - return route; - end - end -end - --- find matching caller id number -function Route.inbound_cid_number(self, caller, endpoint, class) - for route_index, cid_entry in pairs(self.routing_table.inbound_cid_number) do - local route = self:caller_id(caller, cid_entry, caller.caller_id_number, endpoint, class); - if route then - return route; - end - end -end - --- find matching caller id name -function Route.inbound_cid_name(self, caller, endpoint, class) - for route_index, cid_entry in pairs(self.routing_table.inbound_cid_name) do - local route = self:caller_id(caller, cid_entry, caller.caller_id_name, endpoint, class); - if route then - return route; - end - end -end diff --git a/misc/freeswitch/scripts/dialplan/router.lua b/misc/freeswitch/scripts/dialplan/router.lua new file mode 100644 index 0000000..7e64d7b --- /dev/null +++ b/misc/freeswitch/scripts/dialplan/router.lua @@ -0,0 +1,187 @@ +-- Gemeinschaft 5 module: call router class +-- (c) AMOOMA GmbH 2013 +-- + +module(...,package.seeall) + +Router = {} + +-- create route object +function Router.new(self, arg) + arg = arg or {} + object = arg.object or {} + setmetatable(object, self); + self.__index = self; + self.class = 'router'; + self.log = arg.log; + self.database = arg.database; + self.routes = arg.routes or {}; + self.caller = arg.caller; + self.variables = arg.variables or {}; + return object; +end + + +function Router.read_table(self, table_name) + local routing_table = {}; + + local sql_query = 'SELECT * \ + FROM `call_routes` `a` \ + JOIN `route_elements` `b` ON `a`.`id` = `b`.`call_route_id`\ + WHERE `a`.`routing_table` = "' .. table_name .. '" \ + ORDER BY `a`.`position`, `b`.`position`'; + + local last_id = 0; + self.database:query(sql_query, function(route) + if last_id ~= tonumber(route.call_route_id) then + last_id = tonumber(route.call_route_id); + table.insert(routing_table, {id = route.call_route_id, name = route.name, endpoint_type = route.endpoint_type , endpoint_id = route.endpoint_id, elements = {} }); + end + + table.insert(routing_table[#routing_table].elements, { + var_in = route.var_in, + var_out = route.var_out, + pattern = route.pattern, + replacement = route.replacement, + action = route.action, + mandatory = common.str.to_b(route.mandatory), + }); + end); + + return routing_table; +end + + +function Router.expand_variables(self, line, variables) + return (line:gsub('{([%a%d%._]+)}', function(captured) + return common.str.try(variables, captured) or ''; + end)) +end + + +function Router.element_match(self, pattern, search_string, replacement) + 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); + elseif result then + return true, search_string:gsub(pattern, self:expand_variables(replacement, self.variables)); + end + + return false; +end + + +function Router.element_match_group(self, pattern, groups, replacement, use_key) + if type(groups) ~= 'table' then + return false; + end + + for key, value in pairs(groups) do + if use_key then + value = key; + end + result, replaced_value = self:element_match(pattern, tostring(value), replacement); + if result then + return true, replaced_value; + end + end +end + + +function Router.route_match(self, route) + local destination = { + gateway = 'gateway' .. route.endpoint_id, + ['type'] = route.endpoint_type, + id = route.endpoint_id, + channel_variables = {} + }; + + local route_matches = false; + + for index=1, #route.elements do + local result = false; + local replacement = nil; + + local element = route.elements[index]; + + 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, self.variables); + else + local command, variable_name = common.str.partition(element.var_in, ':'); + + if not command or not variable_name or command == 'var' then + local search_string = tostring(common.str.try(self.caller, element.var_in)) + result, replacement = self:element_match(tostring(element.pattern), tostring(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'); + 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)); + elseif command == 'hdr' then + local search_string = self.caller:to_s('sip_h_' .. variable_name); + result, replacement = self:element_match(tostring(element.pattern), search_string, tostring(element.replacement)); + end + end + + if element.action == 'not_match' then + result = not result; + end + + if not result then + if element.mandatory then + return false; + end + else + 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; + elseif command == 'chv' then + destination.channel_variables[variable_name] = replacement; + elseif command == 'hdr' then + destination.channel_variables['sip_h_' .. variable_name] = replacement; + end + end + + if element.action == 'match' or element.action == 'not_match' then + route_matches = true; + end + end + end + end + + if route_matches then + return destination; + end; + + return nil; +end + + +function Router.route_run(self, table_name, find_first) + local routing_table = self:read_table(table_name); + local routes = {}; + + if type(routing_table) == 'table' then + for index=1, #routing_table do + local route = self:route_match(routing_table[index]); + if route then + table.insert(routes, route); + self.log:info('ROUTE ', #routes,' - ', table_name,'=', routing_table[index].id, '/', routing_table[index].name, ', destination: ', route.type, '=', route.id, ', destination_number: ', route.destination_number); + if find_first then + return route; + end + else + self.log:debug('ROUTE_NO_MATCH - ', table_name, '=', routing_table[index].id, '/', routing_table[index].name); + end + end + end + + if not find_first then + return routes; + end +end diff --git a/misc/freeswitch/scripts/dialplan/session.lua b/misc/freeswitch/scripts/dialplan/session.lua index 7174b24..7de85ca 100644 --- a/misc/freeswitch/scripts/dialplan/session.lua +++ b/misc/freeswitch/scripts/dialplan/session.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: caller session class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) @@ -43,9 +43,13 @@ function Session.init_channel_variables(self) self.from_gateway = true; end + self.dialed_sip_user = self:to_s('dialed_user'); + self.dialed_domain = self:to_s('dialed_domain'); + self.account_uuid = self:to_s('gs_account_uuid'); self.account_type = self:to_s('gs_account_type'); self.sip_contact_host = self:to_s('sip_contact_host'); + self.sip_network_ip = self:to_s('sip_network_ip'); self.clir = self:to_b('gs_clir'); self.call_timeout = self:to_i('gs_call_timeout'); self.auth_account_type = self:to_s('gs_auth_account_type'); diff --git a/misc/freeswitch/scripts/dialplan/sip_call.lua b/misc/freeswitch/scripts/dialplan/sip_call.lua index 57f92c6..3f56753 100644 --- a/misc/freeswitch/scripts/dialplan/sip_call.lua +++ b/misc/freeswitch/scripts/dialplan/sip_call.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: sip call class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall); @@ -79,6 +79,8 @@ function SipCall.fork(self, destinations, arg ) local dial_strings = {} require 'common.sip_account' + require 'common.str' + local sip_account_class = common.sip_account.SipAccount:new{ log = self.log, database = self.database }; local call_result = { code = 404, phrase = 'No destination' }; @@ -87,7 +89,12 @@ function SipCall.fork(self, destinations, arg ) for index, destination in ipairs(destinations) do local origination_variables = { 'gs_fork_index=' .. index } - self.log:info('FORK ', index, '/', #destinations, ' - ', destination.type, '=', destination.id, '/', destination.gateway or destination.uuid, '@', destination.node_id, ', number: ', destination.number); + self.log:info('FORK ', index, '/', #destinations, ' - ', destination.type, '=', destination.id, '/', destination.gateway or destination.uuid, '@', destination.node_id, ', number: ', destination.number, ', caller_id: "', destination.caller_id_name, '" <', destination.caller_id_number, '>'); + + if not common.str.to_b(arg.update_callee_display) then + table.insert(origination_variables, 'ignore_display_updates=true'); + end + if not destination.node_local or destination.type == 'node' then require 'common.node' local node = nil; @@ -128,7 +135,12 @@ function SipCall.fork(self, destinations, arg ) if destination.caller_id_name then table.insert(origination_variables, "origination_caller_id_name='" .. destination.caller_id_name .. "'"); end - table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/gateway/' .. destination.gateway .. '/' .. destination.number); + if destination.channel_variables then + for key, value in pairs(destination.channel_variables) do + table.insert(origination_variables, tostring(key) .. "='" .. tostring(value) .. "'"); + end + end + table.insert(dial_strings, '[' .. table.concat(origination_variables , ',') .. ']sofia/gateway/' .. tostring(destination.gateway) .. '/' .. tostring(destination.number)); elseif destination.type == 'dial' then if destination.caller_id_number then table.insert(origination_variables, "origination_caller_id_number='" .. destination.caller_id_number .. "'"); diff --git a/misc/freeswitch/scripts/dialplan/tenant.lua b/misc/freeswitch/scripts/dialplan/tenant.lua index 8d6436c..904609e 100644 --- a/misc/freeswitch/scripts/dialplan/tenant.lua +++ b/misc/freeswitch/scripts/dialplan/tenant.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: user class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) diff --git a/misc/freeswitch/scripts/dialplan/user.lua b/misc/freeswitch/scripts/dialplan/user.lua index 3b483c8..b536600 100644 --- a/misc/freeswitch/scripts/dialplan/user.lua +++ b/misc/freeswitch/scripts/dialplan/user.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: user class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) @@ -62,7 +62,7 @@ function User.list_groups(self, id) local groups = {}; self.database:query(sql_query, function(entry) - groups[common.str.downcase(entry.name)] = true; + table.insert(groups, common.str.downcase(entry.name)); end); return groups; diff --git a/misc/freeswitch/scripts/dialplan/voicemail.lua b/misc/freeswitch/scripts/dialplan/voicemail.lua index b9dab79..5d79ba3 100644 --- a/misc/freeswitch/scripts/dialplan/voicemail.lua +++ b/misc/freeswitch/scripts/dialplan/voicemail.lua @@ -1,5 +1,5 @@ -- Gemeinschaft 5 module: voicemail class --- (c) AMOOMA GmbH 2012 +-- (c) AMOOMA GmbH 2012-2013 -- module(...,package.seeall) @@ -128,7 +128,7 @@ end function Voicemail.send_notify(self, caller) self.log:debug('VOICEMAIL_NOTIFY - account: ' .. self.record.auth_name .. ", id: " .. tostring(caller.uuid)); - local file = io.popen("/opt/GS5/script/voicemail_new.sh '" .. tostring(self.record.auth_name) .. "' '" .. tostring(caller.uuid) .. "' 2>&1"); + local file = io.popen("/opt/GS5/script/voicemail_new '" .. tostring(self.record.auth_name) .. "' '" .. tostring(caller.uuid) .. "' 2>&1"); self.log:debug('VOICEMAIL_NOTIFY - result: ' .. tostring(file:read("*a"))); file:close(); |