mirror of
https://github.com/fusionpbx/fusionpbx.git
synced 2026-01-07 04:03:49 +00:00
* Fix table name, variables and syntax Follow me Lua Correct the wrong table name on line 123. Correct the param on line 126 and correct the syntax on line 347. * Update index.lua Missing AND in where clause. * Change order of preference Caller ID Changed order of preference for Caller ID. If user exists should take preference over Follow Me override select caller ID. This is my preference and my opinion only. May not be the desired effect of others. Perhaps a select option to choose a preference like the following options: Set caller ID override all, Local user else Caller ID
458 lines
18 KiB
Lua
458 lines
18 KiB
Lua
-- FusionPBX
|
|
-- Version: MPL 1.1
|
|
|
|
-- The contents of this file are subject to the Mozilla Public License Version
|
|
-- 1.1 (the "License"); you may not use this file except in compliance with
|
|
-- the License. You may obtain a copy of the License at
|
|
-- http://www.mozilla.org/MPL/
|
|
|
|
-- Software distributed under the License is distributed on an "AS IS" basis,
|
|
-- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
-- for the specific language governing rights and limitations under the
|
|
-- License.
|
|
|
|
-- The Original Code is FusionPBX
|
|
|
|
-- The Initial Developer of the Original Code is
|
|
-- Mark J Crane <markjcrane@fusionpbx.com>
|
|
-- Portions created by the Initial Developer are Copyright (C) 2019
|
|
-- the Initial Developer. All Rights Reserved.
|
|
|
|
--includes
|
|
local Database = require "resources.functions.database";
|
|
local route_to_bridge = require "resources.functions.route_to_bridge"
|
|
require "resources.functions.trim";
|
|
|
|
--get the variables
|
|
if (session:ready()) then
|
|
domain_name = session:getVariable("domain_name");
|
|
domain_uuid = session:getVariable("domain_uuid");
|
|
destination_number = session:getVariable("destination_number");
|
|
caller_id_name = session:getVariable("caller_id_name");
|
|
caller_id_number = session:getVariable("caller_id_number");
|
|
outbound_caller_id_name = session:getVariable("outbound_caller_id_name");
|
|
outbound_caller_id_number = session:getVariable("outbound_caller_id_number");
|
|
call_direction = session:getVariable("call_direction");
|
|
original_destination_number = session:getVariable("destination_number");
|
|
end
|
|
|
|
--set caller id
|
|
if (effective_caller_id_name ~= nil) then
|
|
caller_id_name = effective_caller_id_name;
|
|
end
|
|
if (effective_caller_id_number ~= nil) then
|
|
caller_id_number = effective_caller_id_number;
|
|
end
|
|
|
|
--default to local if nil
|
|
if (call_direction == nil) then
|
|
call_direction = "local";
|
|
end
|
|
|
|
--set the strategy
|
|
follow_me_strategy = 'simultaneous'; --simultaneous, enterprise
|
|
|
|
--include json library
|
|
debug["sql"] = false;
|
|
local json
|
|
if (debug["sql"]) then
|
|
json = require "resources.functions.lunajson";
|
|
end
|
|
|
|
--prepare the api object
|
|
api = freeswitch.API();
|
|
|
|
--get the destination and follow the forward
|
|
function get_forward_all(count, destination_number, domain_name)
|
|
cmd = "user_exists id ".. destination_number .." "..domain_name;
|
|
--freeswitch.consoleLog("notice", "[follow me][call forward all] " .. cmd .. "\n");
|
|
user_exists = api:executeString(cmd);
|
|
if (user_exists == "true") then
|
|
---check to see if the new destination is forwarded
|
|
cmd = "user_data ".. destination_number .."@" ..domain_name.." var forward_all_enabled";
|
|
if (api:executeString(cmd) == "true") then
|
|
--get the toll_allow var
|
|
cmd = "user_data ".. destination_number .."@" ..domain_name.." var toll_allow";
|
|
toll_allow = api:executeString(cmd);
|
|
--freeswitch.consoleLog("notice", "[follow me][call forward all] " .. destination_number .. " toll_allow is ".. toll_allow .."\n");
|
|
|
|
--get the new destination
|
|
cmd = "user_data ".. destination_number .."@" ..domain_name.." var forward_all_destination";
|
|
destination_number = api:executeString(cmd);
|
|
--freeswitch.consoleLog("notice", "[follow me][call forward all] " .. count .. " " .. cmd .. " ".. destination_number .."\n");
|
|
count = count + 1;
|
|
if (count < 5) then
|
|
count, destination_number = get_forward_all(count, destination_number, domain_name);
|
|
end
|
|
end
|
|
end
|
|
return count, destination_number, toll_allow;
|
|
end
|
|
|
|
--connect to the database
|
|
local dbh = Database.new('system');
|
|
|
|
--get the forward busy
|
|
--cmd = "user_data ".. destination_number .."@"..domain_name.." var forward_busy_enabled=";
|
|
--forward_busy_enabled = trim(api:executeString(cmd));
|
|
--cmd = "user_data ".. destination_number .."@"..domain_name.." var forward_busy_destination=";
|
|
--forward_busy_destination = trim(api:executeString(cmd));
|
|
|
|
--select data from the database
|
|
local sql = "select follow_me_uuid, toll_allow ";
|
|
sql = sql .. "from v_extensions ";
|
|
sql = sql .. "where domain_uuid = :domain_uuid ";
|
|
sql = sql .. "and ( ";
|
|
sql = sql .. " extension = :destination_number ";
|
|
sql = sql .. " OR number_alias = :destination_number ";
|
|
sql = sql .. ") ";
|
|
local params = {domain_uuid = domain_uuid,destination_number = destination_number};
|
|
if (debug["sql"]) then
|
|
freeswitch.consoleLog("notice", "SQL:" .. sql .. "; params: " .. json.encode(params) .. "\n");
|
|
end
|
|
status = dbh:query(sql, params, function(row)
|
|
follow_me_uuid = row["follow_me_uuid"];
|
|
extension_toll_allow = row["toll_allow"];
|
|
end);
|
|
--dbh:query(sql, params, function(row);
|
|
|
|
--get the follow me data
|
|
if (follow_me_uuid ~= nil) then
|
|
local sql = "select cid_name_prefix, cid_number_prefix, ";
|
|
sql = sql .. "follow_me_enabled, follow_me_caller_id_uuid, follow_me_ignore_busy ";
|
|
sql = sql .. "from v_follow_me ";
|
|
sql = sql .. "where domain_uuid = :domain_uuid ";
|
|
sql = sql .. "and follow_me_uuid = :follow_me_uuid; ";
|
|
local params = {domain_uuid = domain_uuid,follow_me_uuid = follow_me_uuid};
|
|
if (debug["sql"]) then
|
|
freeswitch.consoleLog("notice", "SQL:" .. sql .. "; params: " .. json.encode(params) .. "\n");
|
|
end
|
|
status = dbh:query(sql, params, function(row)
|
|
caller_id_name_prefix = row["cid_name_prefix"];
|
|
caller_id_number_prefix = row["cid_number_prefix"];
|
|
follow_me_enabled = row["follow_me_enabled"];
|
|
follow_me_caller_id_uuid = row["follow_me_caller_id_uuid"];
|
|
follow_me_ignore_busy = row["follow_me_ignore_busy"];
|
|
end);
|
|
--dbh:query(sql, params, function(row);
|
|
end
|
|
|
|
--get the follow me destinations
|
|
if (follow_me_uuid ~= nil) then
|
|
sql = "select d.domain_uuid, d.domain_name, f.follow_me_destination as destination_number, ";
|
|
sql = sql .. "f.follow_me_delay as destination_delay, f.follow_me_timeout as destination_timeout, ";
|
|
sql = sql .. "f.follow_me_prompt as destination_prompt ";
|
|
sql = sql .. "from v_follow_me_destinations as f, v_domains as d ";
|
|
sql = sql .. "where f.follow_me_uuid = :follow_me_uuid ";
|
|
sql = sql .. "and f.domain_uuid = d.domain_uuid ";
|
|
sql = sql .. "order by f.follow_me_order; ";
|
|
local params = {follow_me_uuid = follow_me_uuid};
|
|
destinations = {};
|
|
destination_count = 0;
|
|
x = 1;
|
|
dbh:query(sql, params, function(row)
|
|
domain_uuid = row["domain_uuid"];
|
|
domain_name = row["domain_name"];
|
|
|
|
if (row.destination_prompt == "1" or row.destination_prompt == "2") then
|
|
prompt = "true";
|
|
end
|
|
|
|
--follow the forwards
|
|
count, destination_number, toll_allow = get_forward_all(0, row.destination_number, domain_name);
|
|
|
|
--update values
|
|
row['destination_number'] = destination_number
|
|
--row['toll_allow'] = toll_allow;
|
|
|
|
--check if the user exists
|
|
cmd = "user_exists id ".. destination_number .." "..domain_name;
|
|
user_exists = api:executeString(cmd);
|
|
|
|
--cmd = "user_exists id ".. destination_number .." "..domain_name;
|
|
if (user_exists == "true") then
|
|
--add user_exists true or false to the row array
|
|
row['user_exists'] = "true";
|
|
--handle do_not_disturb
|
|
cmd = "user_data ".. destination_number .."@" ..domain_name.." var do_not_disturb";
|
|
if (api:executeString(cmd) ~= "true") then
|
|
--add the row to the destinations array
|
|
destinations[x] = row;
|
|
end
|
|
else
|
|
--set the values
|
|
external = "true";
|
|
row['user_exists'] = "false";
|
|
--add the row to the destinations array
|
|
destinations[x] = row;
|
|
end
|
|
row['domain_name'] = domain_name;
|
|
destination_count = destination_count + 1;
|
|
x = x + 1;
|
|
end);
|
|
end
|
|
|
|
--get the dialplan data and save it to a table
|
|
if (external == "true") then
|
|
dialplans = route_to_bridge.preload_dialplan(
|
|
dbh, domain_uuid, {hostname = hostname, context = context}
|
|
)
|
|
end
|
|
|
|
--prepare the array of destinations
|
|
x = 1;
|
|
for key, row in pairs(destinations) do
|
|
--set the values from the database as variables
|
|
destination_number = row.destination_number;
|
|
|
|
--determine if the user is registered if not registered then lookup
|
|
if (user_exists == "true") then
|
|
cmd = "sofia_contact */".. destination_number .."@" ..domain_name;
|
|
if (api:executeString(cmd) == "error/user_not_registered") then
|
|
freeswitch.consoleLog("NOTICE", "[follow_me] "..cmd.."\n");
|
|
cmd = "user_data ".. destination_number .."@" ..domain_name.." var forward_user_not_registered_enabled";
|
|
freeswitch.consoleLog("NOTICE", "[follow_me] "..cmd.."\n");
|
|
if (api:executeString(cmd) == "true") then
|
|
--get the new destination number
|
|
cmd = "user_data ".. destination_number .."@" ..domain_name.." var forward_user_not_registered_destination";
|
|
freeswitch.consoleLog("NOTICE", "[follow_me] "..cmd.."\n");
|
|
not_registered_destination_number = api:executeString(cmd);
|
|
freeswitch.consoleLog("NOTICE", "[follow_me] "..not_registered_destination_number.."\n");
|
|
if (not_registered_destination_number ~= nil) then
|
|
destination_number = not_registered_destination_number;
|
|
destinations[key]['destination_number'] = destination_number;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--process the destinations
|
|
x = 1;
|
|
for key, row in pairs(destinations) do
|
|
freeswitch.consoleLog("NOTICE", "[follow me] destination_number: "..row.destination_number.."\n");
|
|
end
|
|
|
|
--process the destinations
|
|
x = 1;
|
|
for key, row in pairs(destinations) do
|
|
--set the values from the database as variables
|
|
domain_uuid = row.domain_uuid;
|
|
destination_number = row.destination_number;
|
|
destination_delay = row.destination_delay;
|
|
destination_timeout = row.destination_timeout;
|
|
destination_prompt = row.destination_prompt;
|
|
group_confirm_key = row.group_confirm_key;
|
|
group_confirm_file = row.group_confirm_file;
|
|
toll_allow = row.toll_allow;
|
|
user_exists = row.user_exists;
|
|
|
|
--follow the forwards
|
|
count, destination_number = get_forward_all(0, destination_number, domain_name);
|
|
|
|
--check if the user exists
|
|
cmd = "user_exists id ".. destination_number .." "..domain_name;
|
|
user_exists = api:executeString(cmd);
|
|
|
|
--set ringback
|
|
--follow_me_ringback = format_ringback(follow_me_ringback);
|
|
--session:setVariable("ringback", follow_me_ringback);
|
|
--session:setVariable("transfer_ringback", follow_me_ringback);
|
|
|
|
--set the timeout if there is only one destination
|
|
if (session:ready() and destination_count == 1) then
|
|
session:execute("set", "call_timeout="..row.destination_timeout);
|
|
end
|
|
|
|
--setup the delimiter
|
|
delimiter = ",";
|
|
if (follow_me_strategy == "simultaneous") then
|
|
delimiter = ",";
|
|
end
|
|
if (follow_me_strategy == "enterprise") then
|
|
delimiter = ":_:";
|
|
end
|
|
|
|
--leg delay settings
|
|
if (follow_me_strategy == "enterprise") then
|
|
timeout_name = "originate_timeout";
|
|
delay_name = "originate_delay_start";
|
|
destination_delay = destination_delay * 500;
|
|
else
|
|
timeout_name = "leg_timeout";
|
|
delay_name = "leg_delay_start";
|
|
end
|
|
|
|
--set confirm
|
|
if (session:ready() and follow_me_strategy == "simultaneous") then
|
|
session:execute("set", "group_confirm_key=exec");
|
|
session:execute("set", "group_confirm_file=lua ".. scripts_dir:gsub('\\','/') .."/confirm.lua");
|
|
end
|
|
|
|
--determine confirm prompt
|
|
if (destination_prompt == nil) then
|
|
group_confirm = "confirm=false,";
|
|
elseif (destination_prompt == "1") then
|
|
group_confirm = "group_confirm_key=exec,group_confirm_file=lua ".. scripts_dir:gsub('\\','/') .."/confirm.lua,confirm=true";
|
|
elseif (destination_prompt == "2") then
|
|
group_confirm = "group_confirm_key=exec,group_confirm_file=lua ".. scripts_dir:gsub('\\','/') .."/confirm.lua,confirm=true";
|
|
else
|
|
group_confirm = "confirm=false";
|
|
end
|
|
|
|
--process according to user_exists, sip_uri, external number
|
|
if (user_exists == "true") then
|
|
--get the extension_uuid
|
|
cmd = "user_data ".. destination_number .."@"..domain_name.." var extension_uuid";
|
|
extension_uuid = trim(api:executeString(cmd));
|
|
--send to user
|
|
local dial_string_to_user = "[sip_invite_domain="..domain_name..",call_direction="..call_direction..","..group_confirm..","..timeout_name.."="..destination_timeout..","..delay_name.."="..destination_delay..",dialed_extension=" .. row.destination_number .. ",extension_uuid="..extension_uuid .. "]user/" .. row.destination_number .. "@" .. domain_name;
|
|
dial_string = dial_string_to_user;
|
|
elseif (tonumber(destination_number) == nil) then
|
|
--sip uri
|
|
dial_string = "[sip_invite_domain="..domain_name..",call_direction="..call_direction..","..group_confirm..","..timeout_name.."="..destination_timeout..","..delay_name.."="..destination_delay.."]" .. row.destination_number;
|
|
else
|
|
--external number
|
|
route_bridge = 'loopback/'..destination_number;
|
|
if (extension_toll_allow ~= nil) then
|
|
toll_allow = extension_toll_allow:gsub(",", ":");
|
|
end
|
|
|
|
--set the toll allow to an empty string
|
|
if (toll_allow == nil) then
|
|
toll_allow = '';
|
|
end
|
|
|
|
--get the destination caller id name and number
|
|
if (follow_me_caller_id_uuid ~= nil) then
|
|
local sql = "select destination_uuid, destination_number, destination_description, destination_caller_id_name, destination_caller_id_number ";
|
|
sql = sql .. "from v_destinations ";
|
|
sql = sql .. "where domain_uuid = :domain_uuid ";
|
|
sql = sql .. "and destination_uuid = :destination_uuid ";
|
|
sql = sql .. "order by destination_number asc ";
|
|
local params = {domain_uuid = domain_uuid, destination_uuid = follow_me_caller_id_uuid};
|
|
if (debug["sql"]) then
|
|
freeswitch.consoleLog("notice", "SQL:" .. sql .. "; params: " .. json.encode(params) .. "\n");
|
|
end
|
|
status = dbh:query(sql, params, function(field)
|
|
caller_id_name = field["destination_caller_id_name"];
|
|
caller_id_number = field["destination_caller_id_number"];
|
|
end);
|
|
end
|
|
|
|
--check if the user exists
|
|
if tonumber(caller_id_number) ~= nil then
|
|
cmd = "user_exists id ".. caller_id_number .." "..domain_name;
|
|
caller_is_local = api:executeString(cmd);
|
|
end
|
|
|
|
--set the outbound caller id
|
|
if (session:ready() and caller_is_local) then
|
|
if (outbound_caller_id_name ~= nil) then
|
|
caller_id_name = outbound_caller_id_name;
|
|
end
|
|
if (outbound_caller_id_number ~= nil) then
|
|
caller_id_number = outbound_caller_id_number;
|
|
end
|
|
end
|
|
|
|
|
|
--set the caller id
|
|
caller_id = '';
|
|
if (caller_id_name ~= nil) then
|
|
caller_id = "origination_caller_id_name='"..caller_id_name.."'"
|
|
end
|
|
if (caller_id_number ~= nil) then
|
|
caller_id = caller_id .. ",origination_caller_id_number="..caller_id_number;
|
|
end
|
|
|
|
--set the destination dial string
|
|
dial_string = "[ignore_early_media=true,toll_allow=".. toll_allow ..",".. caller_id ..",sip_invite_domain="..domain_name..",call_direction="..call_direction..","..group_confirm..","..timeout_name.."="..destination_timeout..","..delay_name.."="..destination_delay.."]"..route_bridge
|
|
end
|
|
|
|
--add a delimiter between destinations
|
|
if (dial_string ~= nil) then
|
|
--freeswitch.consoleLog("notice", "[follow me] dial_string: " .. dial_string .. "\n");
|
|
if (x == 1) then
|
|
if (follow_me_strategy == "enterprise") then
|
|
app_data = dial_string;
|
|
else
|
|
app_data = "{ignore_early_media=true}"..dial_string;
|
|
end
|
|
else
|
|
if (app_data == nil) then
|
|
if (follow_me_strategy == "enterprise") then
|
|
app_data = dial_string;
|
|
else
|
|
app_data = "{ignore_early_media=true}"..dial_string;
|
|
end
|
|
else
|
|
app_data = app_data .. delimiter .. dial_string;
|
|
end
|
|
end
|
|
end
|
|
|
|
--increment the value of x
|
|
x = x + 1;
|
|
end
|
|
|
|
--set ring ready
|
|
if (session:ready()) then
|
|
session:execute("ring_ready", "");
|
|
end
|
|
|
|
--send to the console
|
|
freeswitch.consoleLog("notice", "[app:follow_me] " .. destination_number .. "\n");
|
|
|
|
--session execute
|
|
if (session:ready()) then
|
|
--set the variables
|
|
session:execute("set", "hangup_after_bridge=true");
|
|
session:execute("set", "continue_on_fail=true");
|
|
|
|
--execute the bridge
|
|
if (app_data ~= nil) then
|
|
if (follow_me_strategy == "enterprise") then
|
|
app_data = app_data:gsub("%[", "{");
|
|
app_data = app_data:gsub("%]", "}");
|
|
end
|
|
freeswitch.consoleLog("NOTICE", "[follow me] app_data: "..app_data.."\n");
|
|
session:execute("bridge", app_data);
|
|
end
|
|
|
|
--timeout destination
|
|
if (app_data ~= nil) then
|
|
if session:ready() and (
|
|
session:getVariable("originate_disposition") == "ALLOTTED_TIMEOUT"
|
|
or session:getVariable("originate_disposition") == "NO_ANSWER"
|
|
or session:getVariable("originate_disposition") == "NO_USER_RESPONSE"
|
|
or session:getVariable("originate_disposition") == "USER_NOT_REGISTERED"
|
|
or session:getVariable("originate_disposition") == "NORMAL_TEMPORARY_FAILURE"
|
|
or session:getVariable("originate_disposition") == "NO_ROUTE_DESTINATION"
|
|
or session:getVariable("originate_disposition") == "USER_BUSY"
|
|
or session:getVariable("originate_disposition") == "RECOVERY_ON_TIMER_EXPIRE"
|
|
or session:getVariable("originate_disposition") == "failure"
|
|
) then
|
|
--get the forward no answer
|
|
cmd = "user_data ".. original_destination_number .."@"..domain_name.." var forward_no_answer_enabled";
|
|
forward_no_answer_enabled = trim(api:executeString(cmd));
|
|
|
|
cmd = "user_data ".. original_destination_number .."@"..domain_name.." var forward_no_answer_destination";
|
|
forward_no_answer_destination = trim(api:executeString(cmd));
|
|
|
|
cmd = "user_data ".. original_destination_number .."@"..domain_name.." var user_context";
|
|
user_context = trim(api:executeString(cmd));
|
|
|
|
--execute the time out action
|
|
if (forward_no_answer_enabled == 'true') then
|
|
session:transfer(forward_no_answer_destination, 'XML', user_context);
|
|
else
|
|
session:transfer('*99' .. original_destination_number, 'XML', user_context);
|
|
end
|
|
|
|
--check and report missed call
|
|
--missed();
|
|
end
|
|
end
|
|
end
|