Move scripts to app/switch/resources/scripts
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
|
||||
--get the argv values
|
||||
script_name = argv[0];
|
||||
app_name = argv[1];
|
||||
|
||||
--example use command
|
||||
--luarun app.lua app_name 'a' 'b 123' 'c'
|
||||
|
||||
--for loop through arguments
|
||||
arguments = "";
|
||||
for key,value in pairs(argv) do
|
||||
if (key > 1) then
|
||||
arguments = arguments .. " '" .. value .. "'";
|
||||
--freeswitch.consoleLog("notice", "[app.lua] argv["..key.."]: "..argv[key].."\n");
|
||||
end
|
||||
end
|
||||
|
||||
--route the request to the application
|
||||
--freeswitch.consoleLog("notice", "["..app_name.."]".. scripts_dir .. "/app/" .. app_name .. "/index.lua\n");
|
||||
loadfile(scripts_dir .. "/app/" .. app_name .. "/index.lua")(argv);
|
||||
@@ -0,0 +1,272 @@
|
||||
|
||||
--set default variables
|
||||
max_digits = 15;
|
||||
digit_timeout = 5000;
|
||||
debug["sql"] = true;
|
||||
|
||||
--general functions
|
||||
require "resources.functions.trim";
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
local presence_in = require "resources.functions.presence_in"
|
||||
|
||||
--set the api
|
||||
api = freeswitch.API();
|
||||
|
||||
--get the argv values
|
||||
action = argv[2];
|
||||
|
||||
--get the session variables
|
||||
if (session:ready()) then
|
||||
session:answer();
|
||||
session:sleep('1000');
|
||||
end
|
||||
|
||||
--get the session variables
|
||||
if (session:ready()) then
|
||||
--general variables
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
domain_name = session:getVariable("domain_name");
|
||||
context = session:getVariable("context");
|
||||
uuid = session:get_uuid();
|
||||
agent_authorized = session:getVariable("agent_authorized");
|
||||
agent_action = session:getVariable("agent_action");
|
||||
agent_id = session:getVariable("agent_id");
|
||||
agent_name = session:getVariable("agent_name");
|
||||
agent_password = session:getVariable("agent_password");
|
||||
|
||||
--set the sounds path for the language, dialect and voice
|
||||
default_language = session:getVariable("default_language");
|
||||
default_dialect = session:getVariable("default_dialect");
|
||||
default_voice = session:getVariable("default_voice");
|
||||
if (not default_language) then default_language = 'en'; end
|
||||
if (not default_dialect) then default_dialect = 'us'; end
|
||||
if (not default_voice) then default_voice = 'callie'; end
|
||||
end
|
||||
|
||||
--set default as access denied
|
||||
if (agent_authorized == nil or agent_authorized ~= 'true') then
|
||||
agent_authorized = 'false';
|
||||
end
|
||||
|
||||
--define the sounds directory
|
||||
sounds_dir = session:getVariable("sounds_dir");
|
||||
sounds_dir = sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice;
|
||||
|
||||
--get the agent_id from the caller
|
||||
if (agent_id == nil and agent_name == nil) then
|
||||
min_digits = 2;
|
||||
max_digits = 20;
|
||||
max_tries = 3;
|
||||
agent_id = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_id:#", "", "\\d+");
|
||||
end
|
||||
|
||||
--get the pin number from the caller
|
||||
if (agent_password == nil and agent_authorized ~= 'true') then
|
||||
min_digits = 3;
|
||||
max_digits = 20;
|
||||
max_tries = 3;
|
||||
agent_password = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_pass:#", "", "\\d+");
|
||||
end
|
||||
|
||||
--get the agent password
|
||||
local params = {domain_uuid = domain_uuid, agent_id = agent_id, agent_name = agent_name}
|
||||
local sql = "SELECT * FROM v_call_center_agents ";
|
||||
sql = sql .. "WHERE domain_uuid = :domain_uuid ";
|
||||
if (agent_id ~= nil) then
|
||||
sql = sql .. "AND (agent_id = :agent_id or agent_name = :agent_id) ";
|
||||
else
|
||||
sql = sql .. "AND agent_name = :agent_name ";
|
||||
end
|
||||
if (agent_authorized ~= 'true') then
|
||||
sql = sql .. "AND agent_password = :agent_password ";
|
||||
params.agent_password = agent_password;
|
||||
end
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[user status] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
--set the variables
|
||||
agent_uuid = row.call_center_agent_uuid;
|
||||
agent_name = row.agent_name;
|
||||
agent_id = row.agent_id;
|
||||
user_uuid = row.user_uuid;
|
||||
--authorize the user
|
||||
agent_authorized = 'true';
|
||||
end);
|
||||
|
||||
--show the results
|
||||
if (agent_id) then
|
||||
freeswitch.consoleLog("notice", "[user status][login] agent id: " .. agent_id .. " authorized: " .. agent_authorized .. "\n");
|
||||
end
|
||||
if (agent_password and debug["password"]) then
|
||||
freeswitch.consoleLog("notice", "[user status][login] agent password: " .. agent_password .. "\n");
|
||||
end
|
||||
|
||||
--get the user_uuid
|
||||
if (agent_authorized == 'true') then
|
||||
|
||||
--get the agent status from mod_callcenter
|
||||
cmd = "callcenter_config agent get status "..agent_uuid.."";
|
||||
freeswitch.consoleLog("notice", "[user status][login] "..cmd.."\n");
|
||||
user_status = trim(api:executeString(cmd));
|
||||
|
||||
--get the user info
|
||||
if (agent_action == nil) then
|
||||
if (user_status == "Available") then
|
||||
action = "logout";
|
||||
status = 'Logged Out';
|
||||
else
|
||||
action = "login";
|
||||
status = 'Available';
|
||||
end
|
||||
elseif (agent_action == "break") then
|
||||
if (user_status == "On Break") then
|
||||
action = "login";
|
||||
status = 'Available';
|
||||
else
|
||||
action = "break";
|
||||
status = 'On Break';
|
||||
end
|
||||
elseif (agent_action == "login") then
|
||||
action = "login";
|
||||
status = 'Available';
|
||||
elseif (agent_action == "logout") then
|
||||
action = "logout";
|
||||
status = 'Logged Out';
|
||||
end
|
||||
|
||||
--send a login or logout to mod_callcenter
|
||||
cmd = "sched_api +5 none callcenter_config agent set status "..agent_uuid.." '"..status.."'";
|
||||
freeswitch.consoleLog("notice", "[user status][login] "..cmd.."\n");
|
||||
result = api:executeString(cmd);
|
||||
|
||||
--update the user status
|
||||
if (user_uuid ~= nil and user_uuid ~= '') then
|
||||
local sql = "SELECT user_status FROM v_users ";
|
||||
sql = sql .. "WHERE user_uuid = :user_uuid ";
|
||||
sql = sql .. "AND domain_uuid = :domain_uuid ";
|
||||
local params = {user_uuid = user_uuid, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[call_center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--set the user_status in the users table
|
||||
local sql = "UPDATE v_users SET ";
|
||||
sql = sql .. "user_status = :status ";
|
||||
sql = sql .. "WHERE user_uuid = :user_uuid ";
|
||||
local params = {status = status, user_uuid = user_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[call_center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
end);
|
||||
end
|
||||
|
||||
--set the presence to terminated - turn the lamp off:
|
||||
if (action == "logout" or action == "break") then
|
||||
event = freeswitch.Event("PRESENCE_IN");
|
||||
event:addHeader("proto", "agent");
|
||||
event:addHeader("event_type", "presence");
|
||||
event:addHeader("alt_event_type", "dialog");
|
||||
event:addHeader("Presence-Call-Direction", "outbound");
|
||||
event:addHeader("state", "Active (1 waiting)");
|
||||
event:addHeader("from", agent_name.."@"..domain_name);
|
||||
event:addHeader("login", agent_name.."@"..domain_name);
|
||||
event:addHeader("unique-id", uuid);
|
||||
event:addHeader("answer-state", "terminated");
|
||||
event:fire();
|
||||
|
||||
event = freeswitch.Event("PRESENCE_IN");
|
||||
event:addHeader("proto", "agent");
|
||||
event:addHeader("event_type", "presence");
|
||||
event:addHeader("alt_event_type", "dialog");
|
||||
event:addHeader("Presence-Call-Direction", "outbound");
|
||||
event:addHeader("state", "Active (1 waiting)");
|
||||
event:addHeader("from", agent_id.."@"..domain_name);
|
||||
event:addHeader("login", agent_id.."@"..domain_name);
|
||||
event:addHeader("unique-id", uuid);
|
||||
event:addHeader("answer-state", "terminated");
|
||||
event:fire();
|
||||
end
|
||||
|
||||
--set presence in - turn lamp on
|
||||
if (action == "login") then
|
||||
event = freeswitch.Event("PRESENCE_IN");
|
||||
event:addHeader("proto", "agent");
|
||||
event:addHeader("login", agent_name.."@"..domain_name);
|
||||
event:addHeader("from", agent_name.."@"..domain_name);
|
||||
event:addHeader("status", "Active (1 waiting)");
|
||||
event:addHeader("rpid", "unknown");
|
||||
event:addHeader("event_type", "presence");
|
||||
event:addHeader("alt_event_type", "dialog");
|
||||
event:addHeader("event_count", "1");
|
||||
event:addHeader("unique-id", uuid);
|
||||
event:addHeader("Presence-Call-Direction", "outbound");
|
||||
event:addHeader("answer-state", "confirmed");
|
||||
event:fire();
|
||||
|
||||
event = freeswitch.Event("PRESENCE_IN");
|
||||
event:addHeader("proto", "agent");
|
||||
event:addHeader("login", agent_id.."@"..domain_name);
|
||||
event:addHeader("from", agent_id.."@"..domain_name);
|
||||
event:addHeader("status", "Active (1 waiting)");
|
||||
event:addHeader("rpid", "unknown");
|
||||
event:addHeader("event_type", "presence");
|
||||
event:addHeader("alt_event_type", "dialog");
|
||||
event:addHeader("event_count", "1");
|
||||
event:addHeader("unique-id", uuid);
|
||||
event:addHeader("Presence-Call-Direction", "outbound");
|
||||
event:addHeader("answer-state", "confirmed");
|
||||
event:fire();
|
||||
end
|
||||
|
||||
if (action == "login") then
|
||||
blf_status = "false"
|
||||
end
|
||||
if string.find(agent_name, 'agent+', nil, true) ~= 1 then
|
||||
presence_in.turn_lamp( blf_status,
|
||||
'agent+'..agent_name.."@"..domain_name,
|
||||
uuid
|
||||
);
|
||||
end
|
||||
end
|
||||
|
||||
--unauthorized
|
||||
if (agent_authorized == 'false') then
|
||||
result = session:streamFile(sounds_dir.."/voicemail/vm-fail_auth.wav");
|
||||
status = "Invalid ID or Password";
|
||||
end
|
||||
|
||||
--set the status and presence
|
||||
if (session:ready()) then
|
||||
if (action == "login") then
|
||||
session:execute("playback", sounds_dir.."/ivr/ivr-you_are_now_logged_in.wav");
|
||||
end
|
||||
if (action == "logout") then
|
||||
session:execute("playback", sounds_dir.."/ivr/ivr-you_are_now_logged_out.wav");
|
||||
end
|
||||
if (action == "break") then
|
||||
session:execute("playback", sounds_dir.."/ivr/ivr-thank_you.wav");
|
||||
end
|
||||
end
|
||||
|
||||
--send the status to the display
|
||||
if (status ~= nil) then
|
||||
reply = api:executeString("uuid_display "..uuid.." '"..status.."'");
|
||||
end
|
||||
|
||||
--set the session sleep to give time to see the display
|
||||
if (session:ready()) then
|
||||
session:execute("sleep", "2000");
|
||||
end
|
||||
@@ -0,0 +1,19 @@
|
||||
--subscribe to the events
|
||||
events = freeswitch.EventConsumer("CUSTOM","avmd::beep");
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--get the events
|
||||
for event in (function() return events:pop(1) end) do
|
||||
--serialize the data for the console
|
||||
--freeswitch.consoleLog("notice","event:" .. event:serialize("xml") .. "\n");
|
||||
--freeswitch.consoleLog("notice","event:" .. event:serialize("json") .. "\n");
|
||||
|
||||
--get the uuid
|
||||
local uuid = event:getHeader("Unique-ID");
|
||||
freeswitch.consoleLog("[avmd] uuid: ", uuid .. "\n");
|
||||
|
||||
--end the call
|
||||
reply = api:executeString("uuid_kill "..uuid.." NORMAL_CLEARING");
|
||||
end
|
||||
@@ -0,0 +1,271 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2019
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
|
||||
--set the debug level
|
||||
debug["sql"] = false;
|
||||
|
||||
--includes
|
||||
local cache = require"resources.functions.cache";
|
||||
local log = require"resources.functions.log"["call_block"];
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson";
|
||||
end
|
||||
|
||||
--include functions
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.file_exists";
|
||||
|
||||
--get the variables
|
||||
if (session:ready()) then
|
||||
--session:setAutoHangup(false);
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
call_direction = session:getVariable("call_direction");
|
||||
caller_id_name = session:getVariable("caller_id_name");
|
||||
caller_id_number = session:getVariable("caller_id_number");
|
||||
destination_number = session:getVariable("destination_number");
|
||||
context = session:getVariable("context");
|
||||
call_block = session:getVariable("call_block");
|
||||
extension_uuid = session:getVariable("extension_uuid");
|
||||
hold_music = session:getVariable("hold_music");
|
||||
end
|
||||
|
||||
--set default variables
|
||||
api = freeswitch.API();
|
||||
|
||||
--set the dialplan cache key
|
||||
local call_block_cache_key = "call_block:" .. caller_id_number;
|
||||
|
||||
--get the cache
|
||||
cached_value, err = cache.get(call_block_cache_key);
|
||||
if (debug['cache']) then
|
||||
if cached_value then
|
||||
log.notice(call_block_cache_key.." source: cache");
|
||||
elseif err ~= 'NOT FOUND' then
|
||||
log.notice("error cache: " .. err);
|
||||
end
|
||||
end
|
||||
|
||||
--disable the cache
|
||||
cached_value = nil;
|
||||
|
||||
--domain_uuid is null then use a random uuid to prevent an error and allow domain_uuid is null SQL to still run
|
||||
if (domain_uuid == nil) then
|
||||
domain_uuid = '74040b66-ca70-4a80-84b5-8cb2139c07dd';
|
||||
end
|
||||
|
||||
--run call block one time
|
||||
if (call_block == nil and call_block ~= 'true') then
|
||||
|
||||
--set the cache
|
||||
if (not cached_value) then
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson";
|
||||
end
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--check to see if the call should be blocked
|
||||
sql = "select * from v_call_block\n";
|
||||
sql = sql .. "where (domain_uuid = :domain_uuid or domain_uuid is null) \n";
|
||||
sql = sql .. "and call_block_enabled = 'true' \n";
|
||||
sql = sql .. "and call_block_direction = :call_block_direction \n";
|
||||
sql = sql .. "and ( \n";
|
||||
sql = sql .. " (\n";
|
||||
sql = sql .. " call_block_name = :call_block_name \n";
|
||||
sql = sql .. " and ( \n";
|
||||
sql = sql .. " '+' || call_block_country_code || call_block_number = :call_block_number \n";
|
||||
sql = sql .. " or call_block_country_code || call_block_number = :call_block_number \n";
|
||||
sql = sql .. " or call_block_number = :call_block_number \n";
|
||||
sql = sql .. " ) \n";
|
||||
sql = sql .. " ) \n";
|
||||
sql = sql .. " or (\n";
|
||||
sql = sql .. " call_block_name is null \n";
|
||||
sql = sql .. " and ( \n";
|
||||
sql = sql .. " '+' || call_block_country_code || call_block_number = :call_block_number \n";
|
||||
sql = sql .. " or call_block_country_code || call_block_number = :call_block_number \n";
|
||||
sql = sql .. " or call_block_number = :call_block_number \n";
|
||||
sql = sql .. " ) \n";
|
||||
sql = sql .. " ) \n";
|
||||
sql = sql .. " or (call_block_name = :call_block_name and call_block_number is null) \n";
|
||||
sql = sql .. ") \n";
|
||||
if (extension_uuid == nil) then
|
||||
sql = sql .. "and extension_uuid is null ";
|
||||
else
|
||||
sql = sql .. "and (extension_uuid is null or extension_uuid = :extension_uuid) ";
|
||||
end
|
||||
if (extension_uuid ~= nil) then
|
||||
if (call_direction == 'inbound') then
|
||||
params = {domain_uuid = domain_uuid, call_block_direction = call_direction, call_block_name = caller_id_name, call_block_number = caller_id_number, extension_uuid = extension_uuid};
|
||||
end
|
||||
if (call_direction == 'outbound') then
|
||||
params = {domain_uuid = domain_uuid, call_block_direction = call_direction, call_block_name = caller_id_name, call_block_number = destination_number, extension_uuid = extension_uuid};
|
||||
end
|
||||
else
|
||||
if (call_direction == 'inbound') then
|
||||
params = {domain_uuid = domain_uuid, call_block_direction = call_direction, call_block_name = caller_id_name, call_block_number = caller_id_number};
|
||||
end
|
||||
if (call_direction == 'outbound') then
|
||||
params = {domain_uuid = domain_uuid, call_block_direction = call_direction, call_block_name = caller_id_name, call_block_number = destination_number};
|
||||
end
|
||||
end
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[dialplan] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
local found = false;
|
||||
dbh:query(sql, params, function(row)
|
||||
found = true;
|
||||
|
||||
--get the values from the database
|
||||
call_block_uuid = row.call_block_uuid;
|
||||
call_block_app = row.call_block_app;
|
||||
call_block_data = row.call_block_data;
|
||||
call_block_count = row.call_block_count;
|
||||
extension_uuid = row.extension_uuid;
|
||||
|
||||
--cached_value = domain_uuid..','..caller_id_number;
|
||||
end);
|
||||
|
||||
--set call block default to false
|
||||
call_block = false;
|
||||
if (call_block_app ~= nil) then
|
||||
call_block = true;
|
||||
if (session:ready()) then
|
||||
session:execute('set', 'call_block=true');
|
||||
end
|
||||
end
|
||||
|
||||
--call block action
|
||||
if (call_block_app ~= nil and call_block_app == 'busy') then
|
||||
if (session:ready()) then
|
||||
session:execute("respond", '486');
|
||||
session:execute('set', 'call_block_uuid='..call_block_uuid);
|
||||
session:execute('set', 'call_block_app=busy');
|
||||
freeswitch.consoleLog("notice", "[call_block] caller id number " .. caller_id_number .. " action: Busy\n");
|
||||
end
|
||||
end
|
||||
if (call_block_app ~= nil and call_block_app == 'hold') then
|
||||
if (session:ready()) then
|
||||
session:execute('set', 'call_block_uuid='..call_block_uuid);
|
||||
session:execute('set', 'call_block_app=hold');
|
||||
session:execute("playback", hold_music);
|
||||
freeswitch.consoleLog("notice", "[call_block] caller id number " .. caller_id_number .. " action: Hold\n");
|
||||
end
|
||||
end
|
||||
if (call_block_app ~= nil and call_block_app == 'reject') then
|
||||
if (session:ready()) then
|
||||
session:execute("respond", '600');
|
||||
session:execute('set', 'call_block_uuid='..call_block_uuid);
|
||||
session:execute('set', 'call_block_app=reject');
|
||||
freeswitch.consoleLog("notice", "[call_block] caller id number " .. caller_id_number .. " action: Reject\n");
|
||||
end
|
||||
end
|
||||
if (call_block_app ~= nil and call_block_data ~= nil) then
|
||||
if (call_block_app == 'extension') then
|
||||
if (session:ready()) then
|
||||
session:execute('set', 'call_block_uuid='..call_block_uuid);
|
||||
session:execute('set', 'call_block_app='..call_block_app);
|
||||
session:execute('set', 'call_block_data='..call_block_data);
|
||||
session:execute("transfer", call_block_data..' XML '.. context);
|
||||
freeswitch.consoleLog("notice", "[call_block] caller id number " .. caller_id_number .. " action: extension ".. call_block_data.."\n");
|
||||
end
|
||||
end
|
||||
if (call_block_app == 'ivr') then
|
||||
if (session:ready()) then
|
||||
session:execute('set', 'call_block_uuid='..call_block_uuid);
|
||||
session:execute('set', 'call_block_app='..call_block_app);
|
||||
session:execute('set', 'call_block_data='..call_block_data);
|
||||
session:execute("transfer", call_block_data..' XML '.. context);
|
||||
freeswitch.consoleLog("notice", "[call_block] caller id number " .. caller_id_number .. " action: extension ".. call_block_data.."\n");
|
||||
end
|
||||
end
|
||||
if (call_block_app == 'ring_group') then
|
||||
if (session:ready()) then
|
||||
session:execute('set', 'call_block_uuid='..call_block_uuid);
|
||||
session:execute('set', 'call_block_app='..call_block_app);
|
||||
session:execute('set', 'call_block_data='..call_block_data);
|
||||
session:execute("transfer", call_block_data..' XML '.. context);
|
||||
freeswitch.consoleLog("notice", "[call_block] caller id number " .. caller_id_number .. " action: extension ".. call_block_data.."\n");
|
||||
end
|
||||
end
|
||||
if (call_block_app == 'voicemail') then
|
||||
if (session:ready()) then
|
||||
session:execute('set', 'call_block_uuid='..call_block_uuid);
|
||||
session:execute('set', 'call_block_app='..call_block_app);
|
||||
session:execute('set', 'call_block_data='..call_block_data);
|
||||
session:execute("transfer", '*99'..call_block_data..' XML '.. context);
|
||||
freeswitch.consoleLog("notice", "[call_block] caller id number " .. caller_id_number .. " action: voicemail *99".. call_block_data.."\n");
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--update the call block count
|
||||
if (call_block) then
|
||||
sql = "update v_call_block ";
|
||||
sql = sql .. "set call_block_count = :call_block_count ";
|
||||
sql = sql .. "where call_block_uuid = :call_block_uuid ";
|
||||
local params = {call_block_uuid = call_block_uuid, call_block_count = #call_block_count + 1};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[dialplan] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
|
||||
--set the cache
|
||||
if (cached_value ~= nil) then
|
||||
local ok, err = cache.set(call_block_cache_key, cached_value, '3600');
|
||||
end
|
||||
if debug["cache"] then
|
||||
if ok then
|
||||
freeswitch.consoleLog("notice", "[call_block] " .. call_block_cache_key .. " stored in the cache\n");
|
||||
else
|
||||
freeswitch.consoleLog("warning", "[call_block] " .. call_block_cache_key .. " can not be stored in the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[call_block] " .. call_block_cache_key .. " source: database\n");
|
||||
end
|
||||
else
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[call_block] " .. call_block_cache_key .. " source: cache\n");
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,834 @@
|
||||
-- conference_center/index.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 - 2021 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED AS ''IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- Luis Daniel Lucio Quiroz <dlucio@okay.com.mx>
|
||||
|
||||
--set variables
|
||||
flags = "";
|
||||
max_tries = 3;
|
||||
digit_timeout = 5000;
|
||||
|
||||
--debug
|
||||
debug["sql"] = false;
|
||||
|
||||
--includes
|
||||
require "resources.functions.config";
|
||||
local Database = require "resources.functions.database";
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
dbh = Database.new('system');
|
||||
local settings = Settings.new(dbh, domain_name, domain_uuid);
|
||||
|
||||
--get the settings
|
||||
session_enabled = settings:get('conference_center', 'session_enabled', 'boolean');
|
||||
account_code_enabled = settings:get('conference_center', 'account_code_enabled', 'boolean');
|
||||
http_protocol = settings:get('domain', 'http_protocol', 'text') or "https";
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--general functions
|
||||
require "resources.functions.base64";
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.file_exists";
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.format_seconds";
|
||||
require "resources.functions.mkdir";
|
||||
|
||||
--get the session variables
|
||||
uuid = session:getVariable("uuid");
|
||||
|
||||
--answer the call
|
||||
session:answer();
|
||||
|
||||
--get record_ext
|
||||
record_ext = session:getVariable("record_ext");
|
||||
if (not record_ext) then
|
||||
record_ext = "wav";
|
||||
end
|
||||
|
||||
--define a function to send email
|
||||
function send_email(email, attachment, default_language, default_dialect)
|
||||
|
||||
--require the email address to send the email
|
||||
if (string.len(email) > 2) then
|
||||
|
||||
--format the message length and date
|
||||
--message_length_formatted = format_seconds(message_length);
|
||||
--if (debug["info"]) then
|
||||
-- freeswitch.consoleLog("notice", "[conference_center] message length: " .. message_length .. "\n");
|
||||
--end
|
||||
local conference_date_end = os.date("%A, %d %b %Y %I:%M %p");
|
||||
--os.time();
|
||||
|
||||
--prepare the files
|
||||
file_subject = scripts_dir.."/app/conference_center/resources/templates/"..default_language.."/"..default_dialect.."email_subject.tpl";
|
||||
file_body = scripts_dir.."/app/conference_center/resources/templates/"..default_language.."/"..default_dialect.."/email_body.tpl";
|
||||
if (not file_exists(file_subject)) then
|
||||
file_subject = scripts_dir.."/app/conference_center/resources/templates/en/us/email_subject.tpl";
|
||||
file_body = scripts_dir.."/app/conference_center/resources/templates/en/us/email_body.tpl";
|
||||
end
|
||||
|
||||
--get the moderator_pin
|
||||
local sql = "SELECT moderator_pin FROM v_conference_rooms WHERE conference_room_uuid = :conference_room_uuid";
|
||||
local params = {conference_room_uuid = conference_room_uuid}
|
||||
freeswitch.consoleLog("notice", "[voicemail] sql: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
dbh:query(sql, params, function(row)
|
||||
moderator_pin = string.lower(row["moderator_pin"]);
|
||||
end);
|
||||
|
||||
--get the link_address
|
||||
link_address = http_protocol.."://"..domain_name..project_path;
|
||||
|
||||
--prepare the headers
|
||||
headers = {}
|
||||
headers["X-FusionPBX-Domain-UUID"] = domain_uuid;
|
||||
headers["X-FusionPBX-Domain-Name"] = domain_name;
|
||||
headers["X-FusionPBX-Call-UUID"] = 'na';
|
||||
headers["X-FusionPBX-Email-Type"] = 'conference';
|
||||
|
||||
--remove quotes from caller id name and number
|
||||
caller_id_name = caller_id_name:gsub("'", "'");
|
||||
caller_id_name = caller_id_name:gsub([["]], """);
|
||||
caller_id_number = caller_id_number:gsub("'", "'");
|
||||
caller_id_number = caller_id_number:gsub([["]], """);
|
||||
|
||||
--prepare the subject
|
||||
local f = io.open(file_subject, "r");
|
||||
local subject = f:read("*all");
|
||||
f:close();
|
||||
subject = subject:gsub("${moderator_pin}", moderator_pin);
|
||||
subject = subject:gsub("${conference_date_end}", conference_date_end);
|
||||
--subject = subject:gsub("${conference_duration}", message_length_formatted);
|
||||
subject = subject:gsub("${domain_name}", domain_name);
|
||||
subject = subject:gsub("${link_address}", link_address);
|
||||
subject = trim(subject);
|
||||
subject = '=?utf-8?B?'..base64.enc(subject)..'?=';
|
||||
|
||||
--prepare the body
|
||||
local f = io.open(file_body, "r");
|
||||
local body = f:read("*all");
|
||||
f:close();
|
||||
body = body:gsub("${moderator_pin}", moderator_pin);
|
||||
body = body:gsub("${conference_date_end}", conference_date_end);
|
||||
body = body:gsub("${conference_uuid}", conference_session_uuid);
|
||||
--body = body:gsub("${conference_duration}", message_length_formatted);
|
||||
body = body:gsub("${domain_name}", domain_name);
|
||||
body = body:gsub("${link_address}", link_address);
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("%s+", "");
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("\n", "");
|
||||
body = body:gsub("\n", "");
|
||||
body = trim(body);
|
||||
|
||||
--send the email
|
||||
if (string.len(attachment) > 4) then
|
||||
send_mail(headers,
|
||||
email,
|
||||
email,
|
||||
{subject, body},
|
||||
attachment
|
||||
);
|
||||
else
|
||||
send_mail(headers,
|
||||
email,
|
||||
email,
|
||||
{subject, body}
|
||||
);
|
||||
end
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] cmd: " .. email .. " " .. subject .. " " .. body .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--define the session hangup
|
||||
function session_hangup_hook()
|
||||
|
||||
--get the session variables
|
||||
conference_session_detail_uuid = api:executeString("create_uuid");
|
||||
--conference_name = session:getVariable("conference_name");
|
||||
conference_session_uuid = session:getVariable("conference_uuid");
|
||||
--conference_recording = session:getVariable("conference_recording");
|
||||
conference_moderator = session:getVariable("conference_moderator");
|
||||
default_language = session:getVariable("default_language");
|
||||
default_dialect = session:getVariable("default_dialect");
|
||||
--recording = session:getVariable("recording");
|
||||
domain_name = session:getVariable("domain_name");
|
||||
|
||||
--set the end epoch
|
||||
end_epoch = os.time();
|
||||
|
||||
--connect to the database
|
||||
dbh = Database.new('system');
|
||||
|
||||
--get the conference sessions
|
||||
if (conference_session_uuid) then
|
||||
local sql = [[SELECT count(*) as num_rows
|
||||
FROM v_conference_sessions
|
||||
WHERE conference_session_uuid = :conference_session_uuid]];
|
||||
local params = {conference_session_uuid = conference_session_uuid};
|
||||
dbh:query(sql, params, function(row)
|
||||
num_rows = string.lower(row["num_rows"]);
|
||||
end);
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "; Rows: "..num_rows.."\n");
|
||||
end
|
||||
if (tonumber(num_rows) == 0) then
|
||||
local sql = {}
|
||||
table.insert(sql, "INSERT INTO v_conference_sessions ");
|
||||
table.insert(sql, "(");
|
||||
table.insert(sql, "conference_session_uuid, ");
|
||||
table.insert(sql, "domain_uuid, ");
|
||||
table.insert(sql, "meeting_uuid, ");
|
||||
--if (conference_recording) then
|
||||
-- table.insert(sql, "recording, ");
|
||||
--end
|
||||
--if (wait_mod) then
|
||||
-- table.insert(sql, "wait_mod, ");
|
||||
--end
|
||||
--table.insert(sql, "start_epoch, ");
|
||||
table.insert(sql, "profile ");
|
||||
table.insert(sql, ") ");
|
||||
table.insert(sql, "VALUES ");
|
||||
table.insert(sql, "( ");
|
||||
table.insert(sql, ":conference_session_uuid, ");
|
||||
table.insert(sql, ":domain_uuid, ");
|
||||
table.insert(sql, ":meeting_uuid, ");
|
||||
--if (conference_recording) then
|
||||
-- table.insert(sql, ":conference_recording, ");
|
||||
--end
|
||||
--if (wait_mod) then
|
||||
-- table.insert(sql, ":wait_mod, ");
|
||||
--end
|
||||
--table.insert(sql, ":start_epoch, ");
|
||||
table.insert(sql, ":profile ");
|
||||
table.insert(sql, ") ");
|
||||
|
||||
sql = table.concat(sql, "\n");
|
||||
|
||||
local params = {
|
||||
conference_session_uuid = conference_session_uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
meeting_uuid = conference_room_uuid;
|
||||
-- conference_recording = conference_recording;
|
||||
-- wait_mod = wait_mod;
|
||||
-- start_epoch = start_epoch;
|
||||
profile = profile;
|
||||
};
|
||||
|
||||
dbh:query(sql, params);
|
||||
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--add the conference sessions details
|
||||
if (conference_session_uuid) then
|
||||
local sql = {}
|
||||
table.insert(sql, "INSERT INTO v_conference_session_details ");
|
||||
table.insert(sql, "(");
|
||||
table.insert(sql, "conference_session_detail_uuid, ");
|
||||
table.insert(sql, "domain_uuid, ");
|
||||
table.insert(sql, "conference_session_uuid, ");
|
||||
table.insert(sql, "meeting_uuid, ");
|
||||
table.insert(sql, "username, ");
|
||||
table.insert(sql, "caller_id_name, ");
|
||||
table.insert(sql, "caller_id_number, ");
|
||||
table.insert(sql, "network_addr, ");
|
||||
table.insert(sql, "uuid, ");
|
||||
if (conference_moderator) then
|
||||
table.insert(sql, "moderator, ");
|
||||
end
|
||||
table.insert(sql, "start_epoch, ");
|
||||
table.insert(sql, "end_epoch ");
|
||||
table.insert(sql, ") ");
|
||||
table.insert(sql, "VALUES ");
|
||||
table.insert(sql, "( ");
|
||||
table.insert(sql, ":conference_session_detail_uuid, ");
|
||||
table.insert(sql, ":domain_uuid, ");
|
||||
table.insert(sql, ":conference_session_uuid, ");
|
||||
table.insert(sql, ":meeting_uuid, ");
|
||||
table.insert(sql, ":username, ");
|
||||
table.insert(sql, ":caller_id_name, ");
|
||||
table.insert(sql, ":caller_id_number, ");
|
||||
table.insert(sql, ":network_addr, ");
|
||||
table.insert(sql, ":uuid, ");
|
||||
if (conference_moderator) then
|
||||
table.insert(sql, ":conference_moderator, ");
|
||||
end
|
||||
table.insert(sql, ":start_epoch, ");
|
||||
table.insert(sql, ":end_epoch ");
|
||||
table.insert(sql, ") ");
|
||||
sql = table.concat(sql, "\n");
|
||||
local params = {
|
||||
conference_session_detail_uuid = conference_session_detail_uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
conference_session_uuid = conference_session_uuid;
|
||||
meeting_uuid = conference_room_uuid;
|
||||
username = username;
|
||||
caller_id_name = caller_id_name;
|
||||
caller_id_number = caller_id_number;
|
||||
network_addr = network_addr;
|
||||
uuid = uuid;
|
||||
conference_moderator = conference_moderator;
|
||||
start_epoch = start_epoch;
|
||||
end_epoch = end_epoch;
|
||||
};
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
|
||||
--if the conference is empty
|
||||
if (conference_session_uuid) then
|
||||
cmd = "conference "..conference_room_uuid.."@"..domain_name.." xml_list";
|
||||
result = trim(api:executeString(cmd));
|
||||
if (string.sub(result, -9) == "not found") then
|
||||
--get the conference start_epoch
|
||||
local sql = [[SELECT start_epoch
|
||||
FROM v_conference_session_details
|
||||
WHERE conference_session_uuid = :conference_session_uuid
|
||||
ORDER BY start_epoch ASC
|
||||
LIMIT 1]];
|
||||
local params = {conference_session_uuid = conference_session_uuid};
|
||||
dbh:query(sql, params, function(row)
|
||||
start_epoch = string.lower(row["start_epoch"]);
|
||||
end);
|
||||
--freeswitch.consoleLog("notice", "[conference center] <conference_start_epoch> sql: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
|
||||
--set the conference_recording
|
||||
conference_recording = recordings_dir.."/archive/"..os.date("%Y", start_epoch).."/"..os.date("%b", start_epoch).."/"..os.date("%d", start_epoch) .."/"..conference_session_uuid .. "." .. record_ext;
|
||||
freeswitch.consoleLog("notice", "[conference center] conference_recording: "..conference_recording.."\n");
|
||||
--conference has ended set the end_epoch
|
||||
local sql = {}
|
||||
table.insert(sql, "update v_conference_sessions set ");
|
||||
table.insert(sql, "recording = :conference_recording, ");
|
||||
table.insert(sql, "start_epoch = :start_epoch, ");
|
||||
table.insert(sql, "end_epoch = :end_epoch ");
|
||||
table.insert(sql, "where conference_session_uuid = :conference_session_uuid ");
|
||||
sql = table.concat(sql, "\n");
|
||||
local params = {
|
||||
conference_recording = conference_recording;
|
||||
start_epoch = start_epoch;
|
||||
end_epoch = end_epoch;
|
||||
conference_session_uuid = conference_session_uuid;
|
||||
};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
--convert the wav to an mp3
|
||||
if (record == "true") then
|
||||
--cmd = "sox "..conference_recording..".wav -r 16000 -c 1 "..conference_recording..".mp3";
|
||||
cmd = "/usr/bin/lame -b 32 --resample 8 -a "..conference_recording..".wav "..conference_recording..".mp3";
|
||||
freeswitch.consoleLog("notice", "[conference center] cmd: " .. cmd .. "\n");
|
||||
os.execute(cmd);
|
||||
--if (file_exists(conference_recording..".mp3")) then
|
||||
-- cmd = "rm "..conference_recording..".wav";
|
||||
-- os.execute(cmd);
|
||||
--end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
if (conference_session_uuid) then
|
||||
dbh:release();
|
||||
end
|
||||
end
|
||||
|
||||
--make sure the session is ready
|
||||
if (session:ready()) then
|
||||
|
||||
--answer the call
|
||||
session:preAnswer();
|
||||
|
||||
--set the session sleep
|
||||
session:sleep(1000);
|
||||
|
||||
--get session variables
|
||||
sounds_dir = session:getVariable("sounds_dir");
|
||||
hold_music = session:getVariable("hold_music");
|
||||
domain_name = session:getVariable("domain_name");
|
||||
pin_number = session:getVariable("pin_number");
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
destination_number = session:getVariable("destination_number");
|
||||
caller_id_number = session:getVariable("caller_id_number");
|
||||
--freeswitch.consoleLog("notice", "[conference center] destination_number: " .. destination_number .. "\n");
|
||||
--freeswitch.consoleLog("notice", "[conference center] caller_id_number: " .. caller_id_number .. "\n");
|
||||
|
||||
--add the domain name to the recordings directory
|
||||
recordings_dir = recordings_dir .. "/"..domain_name;
|
||||
|
||||
--set the sounds path for the language, dialect and voice
|
||||
default_language = session:getVariable("default_language");
|
||||
default_dialect = session:getVariable("default_dialect");
|
||||
default_voice = session:getVariable("default_voice");
|
||||
if (not default_language) then default_language = 'en'; end
|
||||
if (not default_dialect) then default_dialect = 'us'; end
|
||||
if (not default_voice) then default_voice = 'callie'; end
|
||||
|
||||
--get the domain_uuid
|
||||
if (domain_name ~= nil and domain_uuid == nil) then
|
||||
local sql = "SELECT domain_uuid FROM v_domains ";
|
||||
sql = sql .. "WHERE domain_name = :domain_name ";
|
||||
local params = {domain_name = domain_name};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(rows)
|
||||
domain_uuid = string.lower(rows["domain_uuid"]);
|
||||
end);
|
||||
end
|
||||
|
||||
--conference center details
|
||||
local sql = [[SELECT * FROM v_conference_centers
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND conference_center_extension = :destination_number]];
|
||||
local params = {domain_uuid = domain_uuid, destination_number = destination_number};
|
||||
dbh:query(sql, params, function(row)
|
||||
conference_center_uuid = string.lower(row["conference_center_uuid"]);
|
||||
conference_center_greeting = row["conference_center_greeting"];
|
||||
end);
|
||||
if (conference_center_greeting == '') then
|
||||
conference_center_greeting = sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/conference/conf-pin.wav";
|
||||
end
|
||||
|
||||
--connect to the switch database
|
||||
local dbh_switch = Database.new('switch')
|
||||
|
||||
--check if someone has already joined the conference
|
||||
local_hostname = trim(api:execute("switchname", ""));
|
||||
freeswitch.consoleLog("notice", "[conference center] local_hostname is " .. local_hostname .. "\n");
|
||||
sql = "SELECT hostname FROM channels WHERE application = 'conference' "
|
||||
.. "AND dest = :destination_number AND cid_num <> :caller_id_number LIMIT 1";
|
||||
params = {destination_number = destination_number, caller_id_number = caller_id_number};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh_switch:query(sql, params, function(rows)
|
||||
conference_hostname = rows["hostname"];
|
||||
end);
|
||||
|
||||
--close the database connection
|
||||
dbh_switch:release();
|
||||
|
||||
--if conference hosntame exist, then we bridge there
|
||||
if (conference_hostname ~= nil) then
|
||||
freeswitch.consoleLog("notice", "[conference center] conference_hostname is " .. conference_hostname .. "\n");
|
||||
if (conference_hostname ~= local_hostname) then
|
||||
session:execute("bridge","sofia/internal/" .. destination_number .. "@" .. domain_name .. ";fs_path=sip:" .. conference_hostname);
|
||||
end
|
||||
end
|
||||
|
||||
--call not bridged, so we answer
|
||||
session:answer();
|
||||
|
||||
--set the hangup hook function
|
||||
if (session_enabled == 'true') then
|
||||
freeswitch.consoleLog("notice", "[conference center] session_enabled: true\n");
|
||||
session:setHangupHook("session_hangup_hook");
|
||||
else
|
||||
freeswitch.consoleLog("notice", "[conference center] session_enabled: false\n");
|
||||
end
|
||||
|
||||
--sounds
|
||||
enter_sound = "tone_stream://v=-20;%(100,1000,100);v=-20;%(90,60,440);%(90,60,620)";
|
||||
exit_sound = "tone_stream://v=-20;%(90,60,620);/%(90,60,440)";
|
||||
|
||||
--get the variables
|
||||
username = session:getVariable("username");
|
||||
caller_id_name = session:getVariable("caller_id_name");
|
||||
caller_id_number = session:getVariable("caller_id_number");
|
||||
callee_id_name = session:getVariable("callee_id_name");
|
||||
callee_id_number = session:getVariable("callee_id_number");
|
||||
dialplan = session:getVariable("dialplan");
|
||||
network_addr = session:getVariable("network_addr");
|
||||
uuid = session:getVariable("uuid");
|
||||
--context = session:getVariable("context");
|
||||
chan_name = session:getVariable("chan_name");
|
||||
|
||||
--define the function get_pin_number
|
||||
function get_pin_number(domain_uuid, prompt_audio_file)
|
||||
--if the pin number is provided then require it
|
||||
if (not pin_number) then
|
||||
min_digits = 2;
|
||||
max_digits = 20;
|
||||
max_tries = 1;
|
||||
digit_timeout = 5000;
|
||||
pin_number = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", prompt_audio_file, "", "\\d+");
|
||||
--remove non numerics
|
||||
pin_number = pin_number:gsub("%p","")
|
||||
end
|
||||
--use the pin_number to find the conference room
|
||||
if (pin_number ~= "") then
|
||||
local sql = [[SELECT * FROM v_conference_rooms
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND (moderator_pin = :pin_number or participant_pin = :pin_number)
|
||||
AND enabled = 'true'
|
||||
AND (
|
||||
( start_datetime <> '' AND start_datetime is not null AND start_datetime <= :timestamp ) OR
|
||||
( start_datetime = '' OR start_datetime is null )
|
||||
)
|
||||
AND (
|
||||
( stop_datetime <> '' AND stop_datetime is not null AND stop_datetime > :timestamp ) OR
|
||||
( stop_datetime = '' OR stop_datetime is null )
|
||||
) ]];
|
||||
local params = {
|
||||
domain_uuid = domain_uuid;
|
||||
pin_number = pin_number;
|
||||
timestamp = os.date("%Y-%m-%d %X");
|
||||
};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
conference_room_uuid = string.lower(row["conference_room_uuid"]);
|
||||
end);
|
||||
end
|
||||
--if the conference room was not found then return nil
|
||||
if (conference_room_uuid == nil) then
|
||||
return nil;
|
||||
else
|
||||
return pin_number;
|
||||
end
|
||||
end
|
||||
|
||||
--get the pin
|
||||
pin_number = session:getVariable("pin_number");
|
||||
pin_number = get_pin_number(domain_uuid, conference_center_greeting);
|
||||
if (pin_number == nil) then
|
||||
pin_number = get_pin_number(domain_uuid, conference_center_greeting);
|
||||
end
|
||||
if (pin_number == nil) then
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/conference/conf-bad-pin.wav");
|
||||
pin_number = get_pin_number(domain_uuid, conference_center_greeting);
|
||||
end
|
||||
if (pin_number == nil) then
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/conference/conf-bad-pin.wav");
|
||||
pin_number = get_pin_number(domain_uuid, conference_center_greeting);
|
||||
end
|
||||
if (pin_number ~= nil) then
|
||||
local sql = [[SELECT * FROM v_conference_rooms
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND conference_center_uuid = :conference_center_uuid
|
||||
AND (moderator_pin = :pin_number or participant_pin = :pin_number)
|
||||
AND enabled = 'true'
|
||||
]];
|
||||
local params = {
|
||||
domain_uuid = domain_uuid;
|
||||
conference_center_uuid = conference_center_uuid;
|
||||
pin_number = pin_number;
|
||||
};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
conference_room_uuid = string.lower(row["conference_room_uuid"]);
|
||||
conference_room_name = string.lower(row["conference_room_name"]);
|
||||
--meeting_uuid = string.lower(row["meeting_uuid"]);
|
||||
record = string.lower(row["record"]);
|
||||
profile = string.lower(row["profile"]);
|
||||
max_members = row["max_members"];
|
||||
wait_mod = row["wait_mod"];
|
||||
moderator_endconf = row["moderator_endconf"];
|
||||
moderator_pin = row["moderator_pin"];
|
||||
participant_pin = row["participant_pin"];
|
||||
announce_name = row["announce_name"];
|
||||
announce_count = row["announce_count"];
|
||||
announce_recording = row["announce_recording"];
|
||||
mute = row["mute"];
|
||||
sounds = row["sounds"];
|
||||
created = row["created"];
|
||||
created_by = row["created_by"];
|
||||
enabled = row["enabled"];
|
||||
description = row["description"];
|
||||
return pin_number;
|
||||
end);
|
||||
freeswitch.consoleLog("INFO","conference_room_uuid: " .. conference_room_uuid .. "\n");
|
||||
end
|
||||
|
||||
--set the member type
|
||||
if (pin_number == moderator_pin) then
|
||||
member_type = "moderator";
|
||||
end
|
||||
if (pin_number == participant_pin) then
|
||||
member_type = "participant";
|
||||
end
|
||||
|
||||
--get the account code
|
||||
if (account_code_enabled == 'true' and member_type == 'moderator') then
|
||||
--request the account code
|
||||
min_digits = 2;
|
||||
max_digits = 20;
|
||||
account_code = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_id:#", "", "\\d+");
|
||||
--user_id = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-please_enter_extension_followed_by_pound.wav", "", "\\d+");
|
||||
|
||||
--update the account code
|
||||
local sql = {}
|
||||
table.insert(sql, "update v_conference_rooms ");
|
||||
table.insert(sql, "set account_code = :account_code ");
|
||||
table.insert(sql, "where conference_center_uuid = :conference_center_uuid ");
|
||||
sql = table.concat(sql, "\n");
|
||||
local params = {
|
||||
conference_center_uuid = conference_center_uuid;
|
||||
account_code = account_code;
|
||||
};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
|
||||
--set the conference_room_uuid
|
||||
if (conference_room_uuid) then
|
||||
session:setVariable("conference_room_uuid", conference_room_uuid);
|
||||
end
|
||||
|
||||
--set the conference_room_name
|
||||
if (conference_room_name) then
|
||||
session:setVariable("conference_room_name", conference_room_name);
|
||||
end
|
||||
|
||||
--set the meeting uuid
|
||||
if (meeting_uuid) then
|
||||
session:setVariable("meeting_uuid", meeting_uuid);
|
||||
end
|
||||
|
||||
--check if the conference exists
|
||||
if (conference_room_uuid and domain_name) then
|
||||
cmd = "conference "..conference_room_uuid.."@"..domain_name.." xml_list";
|
||||
result = trim(api:executeString(cmd));
|
||||
if (string.sub(result, -9) == "not found") then
|
||||
conference_exists = false;
|
||||
else
|
||||
conference_exists = true;
|
||||
end
|
||||
end
|
||||
|
||||
--check if the conference is locked
|
||||
if (string.find(result, [[locked="true"]]) == nil) then
|
||||
conference_locked = false;
|
||||
else
|
||||
conference_locked = true;
|
||||
end
|
||||
|
||||
--set a conference parameter
|
||||
if (max_members ~= nil) then
|
||||
if (tonumber(max_members) > 0) then
|
||||
--max members must be 2 or more
|
||||
session:execute("set","conference_max_members="..max_members);
|
||||
if (conference_exists) then
|
||||
cmd = "conference "..conference_room_uuid.."@"..domain_name.." get count";
|
||||
count = trim(api:executeString(cmd));
|
||||
if (count ~= nil) then
|
||||
if (tonumber(count) >= tonumber(max_members)) then
|
||||
session:execute("playback", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/conference/conf-locked.wav");
|
||||
session:hangup("CALL_REJECTED");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--announce the caller
|
||||
if (conference_locked) then
|
||||
announce = "false";
|
||||
end
|
||||
if (announce_name == "true") then
|
||||
--prompt for the name of the caller
|
||||
session:execute("playback", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-say_name.wav");
|
||||
session:execute("playback", "tone_stream://v=-7;%%(500,0,500.0)");
|
||||
--record the response
|
||||
max_len_seconds = 5;
|
||||
silence_threshold = "500";
|
||||
silence_secs = "3";
|
||||
session:recordFile(temp_dir:gsub("\\","/") .. "/conference-"..uuid..".wav", max_len_seconds, silence_threshold, silence_secs);
|
||||
end
|
||||
|
||||
--play a message that the conference is being a recorded
|
||||
--if (record == "true") then
|
||||
--session:execute("playback", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-recording_started.wav");
|
||||
--end
|
||||
|
||||
--wait for moderator
|
||||
if (wait_mod == "true") then
|
||||
if (conference_exists) then
|
||||
--continue
|
||||
else
|
||||
if (member_type == "participant") then
|
||||
profile = "wait-mod";
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--set the exit sound
|
||||
if (sounds == "true") then
|
||||
session:execute("set","conference_exit_sound="..exit_sound);
|
||||
else
|
||||
session:execute("set","conference_enter_sound=none");
|
||||
session:execute("set","conference_exit_sound=none");
|
||||
end
|
||||
|
||||
--set flags and moderator controls
|
||||
if (wait_mod == "true") then
|
||||
if (member_type == "participant") then
|
||||
flags = flags .. "wait-mod";
|
||||
end
|
||||
end
|
||||
if (mute == "true") then
|
||||
if (member_type == "participant") then
|
||||
flags = flags .. "|mute";
|
||||
end
|
||||
end
|
||||
|
||||
if (member_type == "moderator") then
|
||||
--set as the moderator
|
||||
flags = flags .. "|moderator";
|
||||
--when the moderator leaves end the conference
|
||||
if (moderator_endconf == "true") then
|
||||
flags = flags .. "|endconf";
|
||||
end
|
||||
end
|
||||
|
||||
--get the conference xml_list
|
||||
cmd = "conference "..conference_room_uuid.."@"..domain_name.." xml_list";
|
||||
freeswitch.consoleLog("INFO","" .. cmd .. "\n");
|
||||
result = trim(api:executeString(cmd));
|
||||
|
||||
--get the content to the <conference> tag
|
||||
result = string.match(result,[[<conference (.-)>]],1);
|
||||
|
||||
--get the uuid out of the xml tag contents
|
||||
if (result ~= nil) then
|
||||
conference_session_uuid = string.match(result,[[uuid="(.-)"]],1);
|
||||
end
|
||||
|
||||
--log entry
|
||||
if (conference_session_uuid ~= nil) then
|
||||
freeswitch.consoleLog("INFO","conference_session_uuid: " .. conference_session_uuid .. "\n");
|
||||
end
|
||||
|
||||
--set the start epoch
|
||||
start_epoch = os.time();
|
||||
|
||||
--set the recording variable
|
||||
if (conference_session_uuid ~= nil) then
|
||||
if (record == "true") then
|
||||
recordings_dir_2 = recordings_dir.."/archive/"..os.date("%Y", start_epoch).."/"..os.date("%b", start_epoch).."/"..os.date("%d", start_epoch);
|
||||
mkdir(recordings_dir_2);
|
||||
recording = recordings_dir_2.."/"..conference_session_uuid;
|
||||
session:execute("set","recording="..recording);
|
||||
session:execute("set","conference_session_uuid="..conference_session_uuid);
|
||||
end
|
||||
end
|
||||
|
||||
--record the conference
|
||||
if (announce_recording == "true") then
|
||||
if (record == "true") then
|
||||
--play a message that the conference is being a recorded
|
||||
session:execute("playback", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-recording_started.wav");
|
||||
--play a message that the conference is being a recorded
|
||||
--cmd = "conference "..meeting_uuid.."@"..domain_name.." play "..sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-recording_started.wav";
|
||||
--freeswitch.consoleLog("notice", "[conference center] ".. cmd .."\n");
|
||||
--response = api:executeString(cmd);
|
||||
end
|
||||
end
|
||||
|
||||
--announce the caller
|
||||
if (announce_name == "true") then
|
||||
--announce the caller - play the recording
|
||||
cmd = "conference "..conference_room_uuid.."@"..domain_name.." play " .. temp_dir:gsub("\\", "/") .. "/conference-"..uuid..".wav";
|
||||
--freeswitch.consoleLog("notice", "[conference center] ".. cmd .."\n");
|
||||
response = api:executeString(cmd);
|
||||
--play has entered the conference
|
||||
cmd = "conference "..conference_room_uuid.."@"..domain_name.." play "..sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/conference/conf-has_joined.wav";
|
||||
--freeswitch.consoleLog("notice", "[conference center] ".. cmd .."\n");
|
||||
response = api:executeString(cmd);
|
||||
else
|
||||
if (not conference_locked) then
|
||||
if (sounds == "true") then
|
||||
cmd = "conference "..conference_room_uuid.."@"..domain_name.." play "..enter_sound;
|
||||
response = api:executeString(cmd);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--get the conference member count
|
||||
cmd = "conference "..conference_room_uuid.."@"..domain_name.." list count";
|
||||
--freeswitch.consoleLog("notice", "[conference center] cmd: ".. cmd .."\n");
|
||||
member_count = api:executeString(cmd);
|
||||
if (string.sub(trim(member_count), -9) == "not found") then
|
||||
member_count = "0";
|
||||
end
|
||||
|
||||
--play member count
|
||||
if (announce_count == "true") then
|
||||
if (member_count == "1") then
|
||||
--there is one other member in this conference
|
||||
session:execute("playback", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/conference/conf-one_other_member_conference.wav");
|
||||
elseif (member_count == "0") then
|
||||
--conference profile defines the alone sound file
|
||||
else
|
||||
--say the count
|
||||
session:execute("say", default_language.." number pronounced "..member_count);
|
||||
--members in this conference
|
||||
session:execute("playback", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/conference/conf-members_in_conference.wav");
|
||||
end
|
||||
end
|
||||
--record the conference
|
||||
if (record == "true") then
|
||||
if (wait_mod == "true" and member_type ~= "moderator") then
|
||||
--don't start recording yet
|
||||
else
|
||||
cmd="sched_api +3 none lua "..scripts_dir.."/app/conference_center/resources/scripts/start_recording.lua "..conference_room_uuid.." "..domain_name.." "..record_ext;
|
||||
api:executeString(cmd);
|
||||
end
|
||||
end
|
||||
|
||||
--use default profile if not provided
|
||||
if (profile == null) then
|
||||
profile = 'default';
|
||||
end
|
||||
|
||||
--send the call to the conference
|
||||
cmd = conference_room_uuid.."@"..domain_name.."@"..profile.."+flags{".. flags .."}";
|
||||
freeswitch.consoleLog("INFO","[conference center] conference " .. cmd .. "\n");
|
||||
session:execute("conference", cmd);
|
||||
end
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
--get the argv values
|
||||
script_name = argv[0];
|
||||
|
||||
--options all, last, non_moderator, member_id
|
||||
data = argv[1];
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--get the session variables
|
||||
conference_name = session:getVariable("conference_name");
|
||||
|
||||
--send the conferenc mute command
|
||||
cmd = "conference " .. conference_name .. " mute " .. data;
|
||||
response = api:executeString(cmd);
|
||||
@@ -0,0 +1,15 @@
|
||||
--options are true and false and toggle
|
||||
data = argv[1];
|
||||
if (data == "toggle") then
|
||||
data = session:getVariable("hand_raised")
|
||||
if(data == "true")then
|
||||
session:setVariable("hand_raised","false")
|
||||
else
|
||||
session:setVariable("hand_raised","true")
|
||||
end
|
||||
elseif(data == "true")then
|
||||
session:setVariable("hand_raised","true")
|
||||
elseif(data == "false")then
|
||||
session:setVariable("hand_raised","false")
|
||||
end
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
--get the scripts directory and include the config.lua
|
||||
require "resources.functions.config";
|
||||
|
||||
--additional includes
|
||||
require "resources.functions.file_exists";
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.mkdir";
|
||||
|
||||
--get the argv values
|
||||
script_name = argv[0];
|
||||
|
||||
--options all, last, non_moderator, member_id
|
||||
meeting_uuid = argv[1];
|
||||
domain_name = argv[2];
|
||||
record_ext = argv[3];
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--check if the conference exists
|
||||
cmd = "conference "..meeting_uuid.."@"..domain_name.." xml_list";
|
||||
freeswitch.consoleLog("INFO","" .. cmd .. "\n");
|
||||
result = trim(api:executeString(cmd));
|
||||
if (string.sub(result, -9) == "not found") then
|
||||
conference_exists = false;
|
||||
else
|
||||
conference_exists = true;
|
||||
end
|
||||
|
||||
--start the recording
|
||||
if (conference_exists) then
|
||||
--get the conference session uuid
|
||||
result = string.match(result,[[<conference (.-)>]],1);
|
||||
conference_session_uuid = string.match(result,[[uuid="(.-)"]],1);
|
||||
freeswitch.consoleLog("INFO","[start-recording] conference_session_uuid: " .. conference_session_uuid .. "\n");
|
||||
|
||||
--get the current time
|
||||
start_epoch = os.time();
|
||||
|
||||
--add the domain name to the recordings directory
|
||||
recordings_dir = recordings_dir .. "/"..domain_name;
|
||||
recordings_dir = recordings_dir.."/archive/"..os.date("%Y", start_epoch).."/"..os.date("%b", start_epoch).."/"..os.date("%d", start_epoch);
|
||||
mkdir(recordings_dir);
|
||||
recording = recordings_dir.."/"..conference_session_uuid;
|
||||
|
||||
--send a command to record the conference
|
||||
if (not file_exists(recording.."."..record_ext)) then
|
||||
cmd = "conference "..meeting_uuid.."@"..domain_name.." record "..recording.."."..record_ext;
|
||||
freeswitch.consoleLog("notice", "[start-recording] cmd: " .. cmd .. "\n");
|
||||
response = api:executeString(cmd);
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
--get the argv values
|
||||
script_name = argv[0];
|
||||
|
||||
--options all, last, non_moderator, member_id
|
||||
data = argv[1];
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--get the session variables
|
||||
conference_name = session:getVariable("conference_name");
|
||||
|
||||
--send the conferenc mute command
|
||||
cmd = "conference " .. conference_name .. " unmute " .. data;
|
||||
response = api:executeString(cmd);
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
<font face="arial">
|
||||
<p>The conference moderator pin is ${moderator_pin} and it ended on ${conference_date_end}.</p>
|
||||
<p>You can download your conference recording by clicking <a href='${link_address}/app/conference_centers/conference_session_details.php?uuid=${conference_uuid}'>here</a>.</p>
|
||||
<hr noshade="noshade" size="1"/>
|
||||
Moderator PIN: ${moderator_pin}
|
||||
Ended: ${conference_date_end}<br/>
|
||||
</font>
|
||||
+1
@@ -0,0 +1 @@
|
||||
New recording available for conference ${moderator_pin} ${conference_date_end}.
|
||||
@@ -0,0 +1,107 @@
|
||||
-- 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) 2014
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
|
||||
--add functions
|
||||
require "resources.functions.file_exists";
|
||||
require "resources.functions.trim";
|
||||
|
||||
--set the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--windows (/ad show only directories)
|
||||
--dir "C:\program files\fusionpbx" /b
|
||||
--unix
|
||||
-- dir /usr/local/freeswitch/scripts -1
|
||||
|
||||
--set local variables
|
||||
uuid = session:getVariable("uuid");
|
||||
context = session:getVariable("context");
|
||||
destination_number = session:getVariable("destination_number");
|
||||
call_direction = session:getVariable("call_direction");
|
||||
domain_name = session:getVariable("domain_name");
|
||||
|
||||
--determine the call direction
|
||||
if (call_direction == nil) then
|
||||
--get the call directory
|
||||
if (context == "public") then
|
||||
call_direction = "inbound";
|
||||
else
|
||||
if (string.sub(context, 0, 9) == "outbound@") then
|
||||
call_direction = "outbound";
|
||||
else
|
||||
if (string.len(destination_number) > 6) then
|
||||
call_direction = "outbound";
|
||||
else
|
||||
call_direction = "local";
|
||||
end
|
||||
end
|
||||
end
|
||||
--set the call direction as a session variable
|
||||
session:setVariable("call_direction", call_direction);
|
||||
--freeswitch.consoleLog("notice", "[app:dialplan] set call_direction " .. call_direction .. "\n");
|
||||
end
|
||||
|
||||
--determine the directory to include
|
||||
if (context == "public") then
|
||||
dialplan_dir = "inbound";
|
||||
else
|
||||
if (string.sub(context, 0, 9) == "outbound@") then
|
||||
dialplan_dir = "outbound";
|
||||
else
|
||||
if (string.len(destination_number) > 6) then
|
||||
dialplan_dir = "outbound";
|
||||
else
|
||||
dialplan_dir = "local";
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--include before
|
||||
result = assert (api:executeString("dir " ..scripts_dir.."/app/dialplan/resources/before /b -1"));
|
||||
for file in result:lines() do
|
||||
if (string.sub(file, -4) == ".lua") then
|
||||
if file_exists(scripts_dir.."/app/dialplan/resources/before/"..file) then
|
||||
dofile(scripts_dir.."/app/dialplan/resources/before/"..file);
|
||||
end
|
||||
--freeswitch.consoleLog("notice", "[app:dialplan] lua: before/" .. file .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--include the dialplans
|
||||
result = assert (api:executeString("dir " ..scripts_dir.."/app/dialplan/resources/"..dialplan_dir.." /b -1"));
|
||||
for file in result:lines() do
|
||||
if (string.sub(file, -4) == ".lua") then
|
||||
if file_exists(scripts_dir.."/app/dialplan/resources/"..dialplan_dir.."/"..file) then
|
||||
dofile(scripts_dir.."/app/dialplan/resources/"..dialplan_dir.."/"..file);
|
||||
end
|
||||
--freeswitch.consoleLog("notice", "[app:dialplan] lua: "..dialplan_dir.."/" .. file .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--include after
|
||||
result = assert (api:executeString("dir " ..scripts_dir.."/app/dialplan/resources/after /b -1"));
|
||||
for file in result:lines() do
|
||||
if (string.sub(file, -4) == ".lua") then
|
||||
if file_exists(scripts_dir.."/app/dialplan/resources/after/"..file) then
|
||||
dofile(scripts_dir.."/app/dialplan/resources/after/"..file);
|
||||
end
|
||||
--freeswitch.consoleLog("notice", "[app:dialplan] lua: after/" .. file .. "\n");
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,87 @@
|
||||
--set the user_exists to true or false
|
||||
if (context ~= "public") then
|
||||
--set the default
|
||||
record_ext = "wav";
|
||||
|
||||
--get record_ext
|
||||
if (session:getVariable("record_ext")) then
|
||||
record_ext = session:getVariable("record_ext");
|
||||
end
|
||||
|
||||
--set the recording path
|
||||
path = recordings_dir
|
||||
if (domain_count > 1) then
|
||||
path = path.."/"..domain_name;
|
||||
end
|
||||
path = path.."/archive/"..(os.date("%Y")).."/"..(os.date("%b")).."/"..(os.date("%d"));
|
||||
|
||||
--add functions
|
||||
require "resources.functions.mkdir";
|
||||
|
||||
--make sure the recordings directory exists
|
||||
mkdir(path);
|
||||
|
||||
--check whether to record the to user
|
||||
if (user_exists == "true") then
|
||||
if (session:ready()) then
|
||||
--get user_variable -> record
|
||||
cmd = "user_data ".. destination_number .."@"..domain_name.." var user_record";
|
||||
user_record = trim(api:executeString(cmd));
|
||||
--freeswitch.consoleLog("notice", "[app:dialplan] " .. cmd .. "\n");
|
||||
|
||||
--set the record_session variable
|
||||
--uuid_record,<uuid> [start|stop|mask|unmask] <path> [<limit>],Record session audio,mod_commands
|
||||
if (user_record == "all") then
|
||||
record_session = true;
|
||||
end
|
||||
if (user_record == "inbound" and call_direction == "inbound") then
|
||||
record_session = true;
|
||||
end
|
||||
if (user_record == "outbound" and call_direction == "outbound") then
|
||||
record_session = true;
|
||||
end
|
||||
if (user_record == "local" and call_direction == "local") then
|
||||
record_session = true;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--check whether to record the from user
|
||||
if (not record_session) then
|
||||
--get the from user
|
||||
sip_from_user = session:getVariable("sip_from_user");
|
||||
sip_from_uri = session:getVariable("sip_from_uri");
|
||||
sip_from_host = session:getVariable("sip_from_host");
|
||||
|
||||
--get user exists true or false
|
||||
cmd = "user_exists id ".. sip_from_user .." "..sip_from_host;
|
||||
user_exists = trim(api:executeString(cmd));
|
||||
|
||||
--get user_variable -> record
|
||||
cmd = "user_data ".. sip_from_user .."@"..sip_from_host.." var user_record";
|
||||
freeswitch.consoleLog("notice", "[app:dialplan] " .. cmd .. "\n");
|
||||
user_record = trim(api:executeString(cmd));
|
||||
|
||||
--set the record_session variable
|
||||
--uuid_record,<uuid> [start|stop|mask|unmask] <path> [<limit>],Record session audio,mod_commands
|
||||
if (user_record == "all") then
|
||||
record_session = true;
|
||||
end
|
||||
if (user_record == "inbound" and call_direction == "inbound") then
|
||||
record_session = true;
|
||||
end
|
||||
if (user_record == "outbound" and call_direction == "outbound") then
|
||||
record_session = true;
|
||||
end
|
||||
if (user_record == "local" and call_direction == "local") then
|
||||
record_session = true;
|
||||
end
|
||||
end
|
||||
|
||||
--record the session
|
||||
if (record_session) then
|
||||
cmd = "uuid_record "..uuid.." start "..path.."/"..uuid.."."..record_ext;
|
||||
session:execute("set", "api_on_answer="..cmd);
|
||||
--freeswitch.consoleLog("notice", "[app:dialplan] "..cmd.."\n");
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
--set the user_exists to true or false
|
||||
if (context ~= "public") then
|
||||
if (user_exists == nil) then
|
||||
--get user exists true or false
|
||||
cmd = "user_exists id ".. destination_number .." "..domain_name;
|
||||
user_exists = trim(api:executeString(cmd));
|
||||
--freeswitch.consoleLog("notice", "[app:dialplan] "..cmd.." user_exists: "..user_exists.."\n");
|
||||
end
|
||||
end
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
-- 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) 2014-2019
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
|
||||
--set defaults
|
||||
expire = {}
|
||||
expire["get_domain"] = "3600";
|
||||
source = "";
|
||||
|
||||
--include cache library
|
||||
local cache = require "resources.functions.cache"
|
||||
|
||||
--get the variables
|
||||
local destination_number = session:getVariable("destination_number");
|
||||
|
||||
--remove the plus if it exists
|
||||
if (string.sub(destination_number, 0, 1) == "+") then
|
||||
destination_number = string.sub(destination_number, 2, (string.len(destination_number)));
|
||||
end
|
||||
|
||||
--connect to the database
|
||||
require "resources.functions.database_handle";
|
||||
dbh = database_handle('system');
|
||||
|
||||
--get the cache
|
||||
if (cache.support() and destination_number) then
|
||||
local key, err = "app:dialplan:inbound:get_domain:" .. destination_number;
|
||||
cache, err = cache.get(key);
|
||||
end
|
||||
|
||||
--get the ring group destinations
|
||||
if (cache == "-ERR NOT FOUND") then
|
||||
sql = "SELECT d.domain_uuid, d.domain_name, n.destination_number, n.destination_context "
|
||||
sql = sql .. "FROM v_destinations as n, v_domains as d "
|
||||
sql = sql .. "WHERE n.destination_number = '"..destination_number.."' "
|
||||
sql = sql .. "AND n.destination_type = 'inbound' "
|
||||
sql = sql .. "AND n.domain_uuid = d.domain_uuid "
|
||||
--freeswitch.consoleLog("notice", "SQL:" .. sql .. "\n");
|
||||
dbh:query(sql, function(row)
|
||||
--set the local variables
|
||||
domain_uuid = row.domain_uuid;
|
||||
domain_name = row.domain_name;
|
||||
--local destination_number = row.destination_number;
|
||||
--local destination_context = row.destination_context;
|
||||
|
||||
--set the cache
|
||||
domain = "domain_uuid=" .. domain_uuid .. "&domain_name=" .. domain_name;
|
||||
if cache.support() then
|
||||
local key = app:dialplan:inbound:get_domain:" .. destination_number .. " '"..domain.."' "..expire["get_domain"];
|
||||
if debug['cache'] then
|
||||
freeswitch.consoleLog("notice", "[dialplan][cache] set key: " .. key .. "\n")
|
||||
end
|
||||
local ok, err = cache.set(key, XML_STRING, expire["directory"])
|
||||
if debug["cache"] and not ok then
|
||||
freeswitch.consoleLog("warning", "[dialplan][cache] set key: " .. key .. " fail: " .. tostring(err) .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--set the source
|
||||
source = "database";
|
||||
|
||||
end);
|
||||
|
||||
else
|
||||
--add the function
|
||||
require "resources.functions.explode";
|
||||
|
||||
--parse the cache
|
||||
array = explode("&", cache);
|
||||
|
||||
--define the array/table and variables
|
||||
local var = {}
|
||||
local key = "";
|
||||
local value = "";
|
||||
|
||||
--parse the cache
|
||||
key_pairs = explode("&", cache);
|
||||
for k,v in pairs(key_pairs) do
|
||||
f = explode("=", v);
|
||||
key = f[1];
|
||||
value = f[2];
|
||||
var[key] = value;
|
||||
end
|
||||
|
||||
--set the variables
|
||||
domain_uuid = var["domain_uuid"];
|
||||
domain_name = var["domain_name"];
|
||||
|
||||
--set the source
|
||||
source = "cache";
|
||||
end
|
||||
|
||||
if (domain_name ~= nil) then
|
||||
--set the call direction as a session variable
|
||||
session:setVariable("domain_name", domain_name);
|
||||
session:setVariable("domain", domain_name);
|
||||
session:setVariable("domain_uuid", domain_uuid);
|
||||
--send information to the console
|
||||
freeswitch.consoleLog("notice", "[app:dialplan:inbound:get_domain] " .. cache .. " source: ".. source .."\n");
|
||||
end
|
||||
@@ -0,0 +1,137 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2010-2015
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- KonradSC <konrd@yahoo.com>
|
||||
--
|
||||
-- Instructions:
|
||||
-- Simply add an action to your emergency outbound route. Make sure
|
||||
-- the order is a lower number than your bridge statement.
|
||||
--
|
||||
-- Tag: action
|
||||
-- Type: lua
|
||||
-- Data: app.lua emergency_notify [to_email_address] [from_email_address]
|
||||
--
|
||||
|
||||
--debug
|
||||
debug["info"] = false;
|
||||
debug["sql"] = false;
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.base64";
|
||||
|
||||
--get arguments
|
||||
to_email = argv[2];
|
||||
from_email = argv[3];
|
||||
|
||||
--check the missed calls
|
||||
function send_mail()
|
||||
|
||||
--set the sounds path for the language, dialect and voice
|
||||
default_language = session:getVariable("default_language");
|
||||
default_dialect = session:getVariable("default_dialect");
|
||||
default_voice = session:getVariable("default_voice");
|
||||
if (not default_language) then default_language = 'en'; end
|
||||
if (not default_dialect) then default_dialect = 'us'; end
|
||||
if (not default_voice) then default_voice = 'callie'; end
|
||||
|
||||
--prepare the files
|
||||
file_subject = scripts_dir.."/app/emergency_notify/resources/templates/"..default_language.."/"..default_dialect.."/email_subject.tpl";
|
||||
file_body = scripts_dir.."/app/emergency_notify/resources/templates/"..default_language.."/"..default_dialect.."/email_body.tpl";
|
||||
if (not file_exists(file_subject)) then
|
||||
file_subject = scripts_dir.."/app/emergency_notify/resources/templates/en/us/email_subject.tpl";
|
||||
file_body = scripts_dir.."/app/emergency_notify/resources/templates/en/us/email_body.tpl";
|
||||
end
|
||||
|
||||
--prepare the headers
|
||||
local headers = {}
|
||||
headers["X-FusionPBX-Domain-UUID"] = domain_uuid;
|
||||
headers["X-FusionPBX-Domain-Name"] = domain_name;
|
||||
headers["X-FusionPBX-Call-UUID"] = uuid;
|
||||
headers["X-FusionPBX-Email-Type"] = 'emergency_call';
|
||||
|
||||
--remove quotes from caller id name and number
|
||||
caller_id_name = caller_id_name:gsub("'", "'");
|
||||
caller_id_name = caller_id_name:gsub([["]], """);
|
||||
caller_id_number = caller_id_number:gsub("'", "'");
|
||||
caller_id_number = caller_id_number:gsub([["]], """);
|
||||
|
||||
--prepare the subject
|
||||
local f = io.open(file_subject, "r");
|
||||
local subject = f:read("*all");
|
||||
f:close();
|
||||
subject = subject:gsub("${caller_id_name}", caller_id_name);
|
||||
subject = subject:gsub("${caller_id_number}", caller_id_number);
|
||||
subject = subject:gsub("${sip_to_user}", sip_to_user);
|
||||
subject = subject:gsub("${caller_destination}", caller_destination);
|
||||
subject = trim(subject);
|
||||
subject = '=?utf-8?B?'..base64.encode(subject)..'?=';
|
||||
|
||||
--prepare the body
|
||||
local f = io.open(file_body, "r");
|
||||
local body = f:read("*all");
|
||||
f:close();
|
||||
body = body:gsub("${caller_id_name}", caller_id_name);
|
||||
body = body:gsub("${caller_id_number}", caller_id_number);
|
||||
body = body:gsub("${sip_to_user}", sip_to_user);
|
||||
body = body:gsub("${caller_destination}", caller_destination);
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("%s+", "");
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("\n", "");
|
||||
body = body:gsub("\n", "");
|
||||
body = trim(body);
|
||||
|
||||
--send the email
|
||||
send_mail(headers,
|
||||
from_email,
|
||||
to_email,
|
||||
{subject, body}
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
--handle originate_disposition
|
||||
if (session ~= nil and session:ready()) then
|
||||
uuid = session:getVariable("uuid");
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
domain_name = session:getVariable("domain_name");
|
||||
context = session:getVariable("context");
|
||||
caller_id_name = session:getVariable("outbound_caller_id_name");
|
||||
caller_id_number = session:getVariable("caller_id_number");
|
||||
sip_to_user = session:getVariable("sip_to_user");
|
||||
caller_destination = session:getVariable("caller_destination");
|
||||
|
||||
|
||||
if (debug["info"] == true) then
|
||||
freeswitch.consoleLog("INFO", "[emergency_notify] caller_id_number: " .. tostring(caller_id_number) .. "\n");
|
||||
freeswitch.consoleLog("INFO", "[emergency_notify] caller_id_number: " .. tostring(caller_id_number) .. "\n");
|
||||
freeswitch.consoleLog("INFO", "[emergency_notify] caller_destination: " .. tostring(caller_destination) .. "\n");
|
||||
freeswitch.consoleLog("INFO", "[emergency_notify] to_email: " .. tostring(to_email) .. "\n");
|
||||
freeswitch.consoleLog("INFO", "[emergency_notify] from_email: " .. tostring(from_email) .. "\n");
|
||||
end
|
||||
|
||||
send_mail();
|
||||
|
||||
end
|
||||
+1
@@ -0,0 +1 @@
|
||||
${caller_id_name} <${caller_id_number}> made an emergency call to ${sip_to_user}
|
||||
+1
@@ -0,0 +1 @@
|
||||
${caller_id_name} <${caller_id_number}> Made An Emergency Call
|
||||
@@ -0,0 +1,192 @@
|
||||
--
|
||||
-- event_notify
|
||||
-- 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 - event_notify
|
||||
--
|
||||
-- The Initial Developer of the Original Code is
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- Copyright (C) 2013 - 2018
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- Errol Samuels <voiptology@gmail.com>
|
||||
|
||||
--define the explode function
|
||||
require "resources.functions.explode";
|
||||
|
||||
--usage
|
||||
--luarun app.lua event_notify internal reboot 1003@domain.fusionpbx.com yealink
|
||||
|
||||
--set the args as variables
|
||||
profile = argv[2];
|
||||
command = argv[3];
|
||||
user = argv[4];
|
||||
vendor = argv[5];
|
||||
|
||||
--log the args
|
||||
--freeswitch.consoleLog("notice", "[event_notify] profile "..profile.."\n");
|
||||
--freeswitch.consoleLog("notice", "[event_notify] command "..command.."\n");
|
||||
--freeswitch.consoleLog("notice", "[event_notify] user "..user.."\n");
|
||||
--freeswitch.consoleLog("notice", "[event_notify] vendor "..vendor.."\n");
|
||||
|
||||
--get the user and domain name from the user argv user@domain
|
||||
user_table = explode("@",user);
|
||||
user = user_table[1];
|
||||
domain = user_table[2];
|
||||
|
||||
--create the event notify object
|
||||
local event = freeswitch.Event('NOTIFY');
|
||||
|
||||
--add the headers
|
||||
event:addHeader('profile', profile);
|
||||
event:addHeader('user', user);
|
||||
event:addHeader('host', domain);
|
||||
event:addHeader('content-type', 'application/simple-message-summary');
|
||||
|
||||
--aastra
|
||||
if (vendor == "aastra") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
end
|
||||
|
||||
--cisco
|
||||
if (vendor == "cisco") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'check-sync');
|
||||
end
|
||||
end
|
||||
|
||||
--cisco-spa
|
||||
if (vendor == "cisco-spa") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'reboot=true');
|
||||
end
|
||||
end
|
||||
|
||||
--digium
|
||||
if (vendor == "digium") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'check-sync');
|
||||
end
|
||||
end
|
||||
|
||||
--fanvil
|
||||
if (vendor == "fanvil") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'resync');
|
||||
end
|
||||
end
|
||||
|
||||
--grandstream
|
||||
if (vendor == "grandstream") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'resync');
|
||||
end
|
||||
end
|
||||
|
||||
--htek
|
||||
if (vendor == "htek") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'resync');
|
||||
end
|
||||
end
|
||||
|
||||
--sangoma
|
||||
if (vendor == "sangoma") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'resync');
|
||||
end
|
||||
end
|
||||
|
||||
--linksys
|
||||
if (vendor == "linksys") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'reboot=true');
|
||||
end
|
||||
end
|
||||
|
||||
--panasonic
|
||||
if (vendor == "panasonic") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
end
|
||||
|
||||
--polycom
|
||||
if (vendor == "polycom") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'check-sync');
|
||||
end
|
||||
end
|
||||
|
||||
--snom
|
||||
if (vendor == "snom") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=false');
|
||||
end
|
||||
end
|
||||
|
||||
--yealink
|
||||
if (vendor == "yealink") then
|
||||
if (command == "reboot") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=true');
|
||||
end
|
||||
if (command == "check_sync") then
|
||||
event:addHeader('event-string', 'check-sync;reboot=false');
|
||||
end
|
||||
end
|
||||
|
||||
--send the event
|
||||
event:fire();
|
||||
|
||||
--log the event
|
||||
freeswitch.consoleLog("notice", "[event_notify] command "..command.." "..user.."@"..domain.." vendor "..tostring(vendor).."\n");
|
||||
@@ -0,0 +1,258 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2010-2018
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Salvatore Caruso <salvatore.caruso@nems.it>
|
||||
-- Riccardo Granchi <riccardo.granchi@nems.it>
|
||||
-- Luis Daniel Lucio Quiroz <dlucio@okay.com.mx>
|
||||
|
||||
--debug
|
||||
debug["info"] = false;
|
||||
debug["sql"] = false;
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.base64";
|
||||
|
||||
--load libraries
|
||||
require 'resources.functions.send_mail'
|
||||
|
||||
--check the missed calls
|
||||
function missed()
|
||||
if (missed_call_app ~= nil and missed_call_data ~= nil) then
|
||||
if (missed_call_app == "email") then
|
||||
--set the sounds path for the language, dialect and voice
|
||||
default_language = session:getVariable("default_language");
|
||||
default_dialect = session:getVariable("default_dialect");
|
||||
default_voice = session:getVariable("default_voice");
|
||||
if (not default_language) then default_language = 'en'; end
|
||||
if (not default_dialect) then default_dialect = 'us'; end
|
||||
if (not default_voice) then default_voice = 'callie'; end
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
local dbh = Database.new('system');
|
||||
|
||||
--get the templates
|
||||
local sql = "SELECT * FROM v_email_templates ";
|
||||
sql = sql .. "WHERE (domain_uuid = :domain_uuid or domain_uuid is null) ";
|
||||
sql = sql .. "AND template_language = :template_language ";
|
||||
sql = sql .. "AND template_category = 'missed' "
|
||||
sql = sql .. "AND template_enabled = 'true' "
|
||||
sql = sql .. "ORDER BY domain_uuid DESC "
|
||||
local params = {domain_uuid = domain_uuid, template_language = default_language.."-"..default_dialect};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
subject = row["template_subject"];
|
||||
body = row["template_body"];
|
||||
end);
|
||||
|
||||
--prepare the headers
|
||||
local headers = {}
|
||||
headers["X-FusionPBX-Domain-UUID"] = domain_uuid;
|
||||
headers["X-FusionPBX-Domain-Name"] = domain_name;
|
||||
headers["X-FusionPBX-Call-UUID"] = uuid;
|
||||
headers["X-FusionPBX-Email-Type"] = 'missed';
|
||||
|
||||
--remove quotes from caller id name and number
|
||||
caller_id_name = caller_id_name:gsub("'", "'");
|
||||
caller_id_name = caller_id_name:gsub([["]], """);
|
||||
caller_id_number = caller_id_number:gsub("'", "'");
|
||||
caller_id_number = caller_id_number:gsub([["]], """);
|
||||
|
||||
--prepare the subject
|
||||
subject = subject:gsub("${caller_id_name}", caller_id_name);
|
||||
subject = subject:gsub("${caller_id_number}", caller_id_number);
|
||||
subject = subject:gsub("${sip_to_user}", sip_to_user);
|
||||
subject = subject:gsub("${dialed_user}", dialed_user);
|
||||
subject = trim(subject);
|
||||
subject = '=?utf-8?B?'..base64.encode(subject)..'?=';
|
||||
|
||||
--prepare the body
|
||||
body = body:gsub("${caller_id_name}", caller_id_name);
|
||||
body = body:gsub("${caller_id_number}", caller_id_number);
|
||||
body = body:gsub("${sip_to_user}", sip_to_user);
|
||||
body = body:gsub("${dialed_user}", dialed_user);
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("%s+", "");
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("\n", "");
|
||||
body = body:gsub("\n", "");
|
||||
body = trim(body);
|
||||
|
||||
--send the email
|
||||
send_mail(headers,
|
||||
nil,
|
||||
missed_call_data,
|
||||
{subject, body}
|
||||
);
|
||||
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[missed call] " .. caller_id_number .. "->" .. sip_to_user .. "emailed to " .. missed_call_data .. "\n");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--handle originate_disposition
|
||||
if (session ~= nil and session:ready()) then
|
||||
uuid = session:getVariable("uuid");
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
domain_name = session:getVariable("domain_name");
|
||||
context = session:getVariable("context");
|
||||
originate_disposition = session:getVariable("originate_disposition");
|
||||
originate_causes = session:getVariable("originate_causes");
|
||||
hangup_on_subscriber_absent = session:getVariable("hangup_on_subscriber_absent");
|
||||
hangup_on_call_reject = session:getVariable("hangup_on_call_reject");
|
||||
caller_id_name = session:getVariable("caller_id_name");
|
||||
caller_id_number = session:getVariable("caller_id_number");
|
||||
call_direction = session:getVariable("call_direction");
|
||||
if (caller_direction == "local") then
|
||||
caller_id_name = session:getVariable("effective_caller_id_name");
|
||||
end
|
||||
sip_to_user = session:getVariable("sip_to_user");
|
||||
dialed_user = session:getVariable("dialed_user");
|
||||
missed_call_app = session:getVariable("missed_call_app");
|
||||
missed_call_data = session:getVariable("missed_call_data");
|
||||
sip_code = session:getVariable("last_bridge_proto_specific_hangup_cause");
|
||||
|
||||
if (debug["info"] == true) then
|
||||
freeswitch.consoleLog("INFO", "[failure_handler] originate_causes: " .. tostring(originate_causes) .. "\n");
|
||||
freeswitch.consoleLog("INFO", "[failure_handler] originate_disposition: " .. tostring(originate_disposition) .. "\n");
|
||||
freeswitch.consoleLog("INFO", "[failure_handler] hangup_on_subscriber_absent: " .. tostring(hangup_on_subscriber_absent) .. "\n");
|
||||
freeswitch.consoleLog("INFO", "[failure_handler] hangup_on_call_reject: " .. tostring(hangup_on_call_reject) .. "\n");
|
||||
freeswitch.consoleLog("INFO", "[failure_handler] sip_code: " .. tostring(sip_code) .. "\n");
|
||||
end
|
||||
|
||||
if (originate_causes ~= nil) then
|
||||
array = explode("|",originate_causes);
|
||||
if (string.find(array[1], "USER_BUSY")) or (sip_code == "sip:486") then
|
||||
originate_disposition = "USER_BUSY";
|
||||
session:setVariable("originate_disposition", originate_disposition);
|
||||
end
|
||||
end
|
||||
|
||||
if (originate_disposition ~= nil) then
|
||||
if (originate_disposition == 'USER_BUSY') then
|
||||
|
||||
--handle USER_BUSY
|
||||
dialed_extension = session:getVariable("dialed_extension");
|
||||
last_busy_dialed_extension = session:getVariable("last_busy_dialed_extension");
|
||||
if (debug["info"] ) then
|
||||
freeswitch.consoleLog("INFO", "[failure_handler] last_busy_dialed_extension: " .. tostring(last_busy_dialed_extension) .. "\n");
|
||||
end
|
||||
|
||||
--transfer to the forward busy destination
|
||||
if (dialed_extension ~= nil and dialed_extension ~= last_busy_dialed_extension) then
|
||||
forward_busy_enabled = session:getVariable("forward_busy_enabled");
|
||||
if (forward_busy_enabled == "true") then
|
||||
forward_busy_destination = session:getVariable("forward_busy_destination");
|
||||
if (forward_busy_destination ~= nil and string.len(forward_busy_destination) > 0) then
|
||||
--handle USER_BUSY - forwarding to number
|
||||
session:setVariable("last_busy_dialed_extension", dialed_extension);
|
||||
if (forward_busy_destination == nil) then
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] forwarding on busy to hangup\n");
|
||||
session:hangup("USER_BUSY");
|
||||
else
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] forwarding on busy to: " .. forward_busy_destination .. "\n");
|
||||
session:transfer(forward_busy_destination, "XML", context);
|
||||
end
|
||||
else
|
||||
--send missed call notification
|
||||
missed();
|
||||
|
||||
--handle USER_BUSY - hangup
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] forward on busy with empty destination: hangup(USER_BUSY)\n");
|
||||
session:hangup("USER_BUSY");
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif (originate_disposition == "NO_ANSWER") or (sip_code == "sip:480") then
|
||||
|
||||
--handle NO_ANSWER
|
||||
forward_no_answer_enabled = session:getVariable("forward_no_answer_enabled");
|
||||
if (forward_no_answer_enabled == "true") then
|
||||
forward_no_answer_destination = session:getVariable("forward_no_answer_destination");
|
||||
if (forward_no_answer_destination == nil) then
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] forwarding no answer to hangup\n");
|
||||
session:hangup("NO_ANSWER");
|
||||
else
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] forwarding no answer to: " .. forward_no_answer_destination .. "\n");
|
||||
session:transfer(forward_no_answer_destination, "XML", context);
|
||||
end
|
||||
else
|
||||
--send missed call notification
|
||||
missed();
|
||||
end
|
||||
if (debug["info"] ) then
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] - NO_ANSWER\n");
|
||||
end
|
||||
|
||||
elseif (originate_disposition == "USER_NOT_REGISTERED") then
|
||||
|
||||
--handle USER_NOT_REGISTERED
|
||||
forward_user_not_registered_enabled = session:getVariable("forward_user_not_registered_enabled");
|
||||
if (forward_user_not_registered_enabled == "true") then
|
||||
forward_user_not_registered_destination = session:getVariable("forward_user_not_registered_destination");
|
||||
if (forward_user_not_registered_destination == nil) then
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] forwarding user not registered to hangup\n");
|
||||
session:hangup("NO_ANSWER");
|
||||
else
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] forwarding user not registerd to: " .. forward_user_not_registered_destination .. "\n");
|
||||
session:transfer(forward_user_not_registered_destination, "XML", context);
|
||||
end
|
||||
else
|
||||
--send missed call notification
|
||||
missed();
|
||||
end
|
||||
|
||||
--send missed call notification
|
||||
--missed();
|
||||
|
||||
--handle USER_NOT_REGISTERED
|
||||
if (debug["info"] ) then
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] - USER_NOT_REGISTERED - Doing nothing\n");
|
||||
end
|
||||
|
||||
elseif (originate_disposition == "SUBSCRIBER_ABSENT" and hangup_on_subscriber_absent == "true") then
|
||||
--send missed call notification
|
||||
missed();
|
||||
|
||||
--handle SUBSCRIBER_ABSENT
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] - SUBSCRIBER_ABSENT - hangup(UNALLOCATED_NUMBER)\n");
|
||||
session:hangup("UNALLOCATED_NUMBER");
|
||||
|
||||
elseif (originate_disposition == "CALL_REJECTED" and hangup_on_call_reject =="true") then
|
||||
--send missed call notification
|
||||
missed();
|
||||
|
||||
--handle CALL_REJECT
|
||||
freeswitch.consoleLog("NOTICE", "[failure_handler] - CALL_REJECT - hangup()\n");
|
||||
session:hangup();
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
text = text or {};
|
||||
|
||||
text['message-send_success'] = {}
|
||||
text['message-send_success']['en-us'] = "We are happy to report the fax was sent successfully. It has been attached for your records."
|
||||
text['message-send_success']['ru-ru'] = "Мы рады сообщить, что факс был отправлен успешно. Он был прикреплен к вашим записям."
|
||||
|
||||
text['message-send_fail'] = {}
|
||||
text['message-send_fail']['en-us'] = "We are sorry the fax failed to go through. It has been attached. Please check the number, and if it was correct you might consider emailing it instead."
|
||||
text['message-send_fail']['ru-ru'] = "Нам жаль, что факс не прошел. Он был прикреплен. Пожалуйста, проверьте номер, и если он был правильным, вы можете отправить его с помощью электронной почты."
|
||||
|
||||
return text
|
||||
@@ -0,0 +1,42 @@
|
||||
local sleep_interval = 60;
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
|
||||
--general functions
|
||||
require "resources.functions.file_exists";
|
||||
require "resources.functions.mkdir";
|
||||
require "resources.functions.sleep";
|
||||
|
||||
local log = require "resources.functions.log".fax_queue_monitor
|
||||
local Next = require "app.fax.resources.scripts.queue.next"
|
||||
|
||||
mkdir(scripts_dir .. "/run");
|
||||
|
||||
--define the run file
|
||||
local run_file = scripts_dir .. "/run/fax_queue.tmp";
|
||||
|
||||
--used to stop the lua service
|
||||
local file = assert(io.open(run_file, "w"));
|
||||
file:write("remove this file to stop the script");
|
||||
file:close()
|
||||
|
||||
log.notice("Start")
|
||||
|
||||
while true do
|
||||
local ok, err = pcall(function()
|
||||
Next.poll_once()
|
||||
end)
|
||||
|
||||
if not ok then
|
||||
log.errf("fail poll queue: %s", tostring(err))
|
||||
end
|
||||
|
||||
if not file_exists(run_file) then
|
||||
break;
|
||||
end
|
||||
|
||||
sleep(sleep_interval * 1000)
|
||||
end
|
||||
|
||||
log.notice("Stop")
|
||||
@@ -0,0 +1 @@
|
||||
require "app.fax.resources.scripts.queue.next".poll_once()
|
||||
@@ -0,0 +1,446 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2015-2023
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Mark J. Crane
|
||||
|
||||
--set the debug options
|
||||
debug["sql"] = true;
|
||||
|
||||
--create the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--additional includes
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.count";
|
||||
require "resources.functions.send_mail";
|
||||
|
||||
--check if windows
|
||||
local IS_WINDOWS = (package.config:sub(1,1) == '\\')
|
||||
|
||||
--define function quote
|
||||
local function quote(s)
|
||||
local q = IS_WINDOWS and '"' or "'"
|
||||
if s:find('%s') or s:find(q, nil, true) then
|
||||
s = q .. s:gsub(q, q..q) .. q
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
--escape shell arguments to prevent command injection
|
||||
local function shell_esc(x)
|
||||
return (x:gsub('\\', '\\\\')
|
||||
:gsub('\'', '\\\''))
|
||||
end
|
||||
|
||||
--create the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--set channel variables to lua variables
|
||||
domain_uuid = env:getHeader("domain_uuid");
|
||||
domain_name = env:getHeader("domain_name");
|
||||
|
||||
--get the domain_uuid using the domain name required for multi-tenant
|
||||
if (domain_name ~= nil) then
|
||||
sql = "SELECT domain_uuid FROM v_domains ";
|
||||
sql = sql .. "WHERE domain_name = :domain_name ";
|
||||
dbh:query(sql, {domain_name = domain_name}, function(rows)
|
||||
domain_uuid = rows["domain_uuid"];
|
||||
end);
|
||||
end
|
||||
|
||||
--settings
|
||||
require "resources.functions.settings";
|
||||
settings = settings(domain_uuid);
|
||||
storage_type = "";
|
||||
storage_path = "";
|
||||
if (settings['fax'] ~= nil) then
|
||||
if (settings['fax']['storage_type'] ~= nil) then
|
||||
if (settings['fax']['storage_type']['text'] ~= nil) then
|
||||
storage_type = settings['fax']['storage_type']['text'];
|
||||
end
|
||||
end
|
||||
if (settings['fax']['storage_path'] ~= nil) then
|
||||
if (settings['fax']['storage_path']['text'] ~= nil) then
|
||||
storage_path = settings['fax']['storage_path']['text'];
|
||||
storage_path = storage_path:gsub("${domain_name}", domain_name);
|
||||
storage_path = storage_path:gsub("${voicemail_id}", voicemail_id);
|
||||
storage_path = storage_path:gsub("${voicemail_dir}", voicemail_dir);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--show all channel variables
|
||||
serialized = env:serialize()
|
||||
freeswitch.consoleLog("INFO","[fax]\n" .. serialized .. "\n")
|
||||
|
||||
--example channel variables relating to fax
|
||||
--variable_fax_success: 0
|
||||
--variable_fax_result_code: 49
|
||||
--variable_fax_result_text: The%20call%20dropped%20prematurely
|
||||
--variable_fax_ecm_used: off
|
||||
--variable_fax_local_station_id: SpanDSP%20Fax%20Ident
|
||||
--variable_fax_document_transferred_pages: 0
|
||||
--variable_fax_document_total_pages: 0
|
||||
--variable_fax_image_resolution: 0x0
|
||||
--variable_fax_image_size: 0
|
||||
--variable_fax_bad_rows: 0
|
||||
--variable_fax_transfer_rate: 14400
|
||||
|
||||
--set channel variables to lua variables
|
||||
uuid = env:getHeader("uuid");
|
||||
fax_uuid = env:getHeader("fax_uuid");
|
||||
fax_queue_uuid = env:getHeader("fax_queue_uuid");
|
||||
fax_success = env:getHeader("fax_success");
|
||||
fax_result_text = env:getHeader("fax_result_text");
|
||||
fax_local_station_id = env:getHeader("fax_local_station_id");
|
||||
fax_ecm_used = env:getHeader("fax_ecm_used");
|
||||
fax_uri = env:getHeader("fax_uri");
|
||||
fax_extension_number = env:getHeader("fax_extension_number");
|
||||
caller_id_name = env:getHeader("caller_id_name");
|
||||
caller_id_number = env:getHeader("caller_id_number");
|
||||
fax_bad_rows = env:getHeader("fax_bad_rows");
|
||||
fax_transfer_rate = env:getHeader("fax_transfer_rate");
|
||||
sip_to_user = env:getHeader("sip_to_user");
|
||||
bridge_hangup_cause = env:getHeader("bridge_hangup_cause");
|
||||
fax_result_code = env:getHeader("fax_result_code");
|
||||
fax_remote_station_id = env:getHeader("fax_remote_station_id");
|
||||
fax_document_total_pages = env:getHeader("fax_document_total_pages");
|
||||
hangup_cause_q850 = tonumber(env:getHeader("hangup_cause_q850"));
|
||||
fax_file = env:getHeader("fax_file");
|
||||
|
||||
--prevent nil errors
|
||||
if (fax_file == nil) then
|
||||
fax_file = env:getHeader("fax_filename");
|
||||
end
|
||||
if (fax_uri == nil) then
|
||||
fax_uri = "";
|
||||
end
|
||||
if (fax_remote_station_id == nil) then
|
||||
fax_remote_station_id = "";
|
||||
end
|
||||
if (caller_id_name == nil) then
|
||||
caller_id_name = env:getHeader("Caller-Caller-ID-Name");
|
||||
end
|
||||
if (caller_id_number == nil) then
|
||||
caller_id_number = env:getHeader("Caller-Caller-ID-Number");
|
||||
end
|
||||
if (document_root == nil) then
|
||||
document_root = '';
|
||||
end
|
||||
|
||||
--set default values
|
||||
if (not fax_success) then
|
||||
fax_success = "0";
|
||||
end
|
||||
if (hangup_cause_q850 == "17") then
|
||||
fax_success = "0";
|
||||
fax_result_text = "USER_BUSY";
|
||||
end
|
||||
if (not fax_result_text) then
|
||||
fax_result_text = "FS_NOT_SET";
|
||||
end
|
||||
|
||||
--get the fax settings from the database
|
||||
local sql = [[SELECT * FROM v_fax
|
||||
WHERE fax_uuid = :fax_uuid
|
||||
AND domain_uuid = :domain_uuid]];
|
||||
local params = {fax_uuid = fax_uuid, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[fax] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
dialplan_uuid = row["dialplan_uuid"];
|
||||
fax_extension = row["fax_extension"];
|
||||
fax_accountcode = row["accountcode"];
|
||||
fax_destination_number = row["fax_destination_number"];
|
||||
fax_name = row["fax_name"];
|
||||
fax_prefix = row["fax_prefix"];
|
||||
fax_email = row["fax_email"];
|
||||
fax_email_connection_type = row["fax_email_connection_type"];
|
||||
fax_email_connection_host = row["fax_email_connection_host"];
|
||||
fax_email_connection_port = row["fax_email_connection_port"];
|
||||
fax_email_connection_security = row["fax_email_connection_security"];
|
||||
fax_email_connection_validate = row["fax_email_connection_validate"];
|
||||
fax_email_connection_username = row["fax_email_connection_username"];
|
||||
fax_email_connection_password = row["fax_email_connection_password"];
|
||||
fax_email_connection_mailbox = row["fax_email_connection_mailbox"];
|
||||
fax_email_inbound_subject_tag = row["fax_email_inbound_subject_tag"];
|
||||
fax_email_outbound_subject_tag = row["fax_email_outbound_subject_tag"];
|
||||
fax_email_outbound_authorized_senders = row["fax_email_outbound_authorized_senders"];
|
||||
fax_caller_id_name = row["fax_caller_id_name"];
|
||||
fax_caller_id_number = row["fax_caller_id_number"];
|
||||
fax_forward_number = row["fax_forward_number"];
|
||||
fax_description = row["fax_description"];
|
||||
end);
|
||||
|
||||
--get the values from the fax file
|
||||
if (fax_file ~= nil) then
|
||||
array = explode("/", fax_file);
|
||||
fax_file_name = array[count(array)];
|
||||
end
|
||||
|
||||
--fax to email
|
||||
cmd = quote(shell_esc(php_dir).."/"..shell_esc(php_bin)).." "..quote(shell_esc(document_root).."/secure/fax_to_email.php").." ";
|
||||
cmd = cmd .. "email="..quote(shell_esc(fax_email)).." ";
|
||||
cmd = cmd .. "extension="..quote(shell_esc(fax_extension)).." ";
|
||||
cmd = cmd .. "name="..quote(shell_esc(fax_file)).." ";
|
||||
cmd = cmd .. "messages=" .. quote("result:"..shell_esc(fax_result_text).." sender:"..shell_esc(fax_remote_station_id).." pages:"..shell_esc(fax_document_total_pages)).." ";
|
||||
cmd = cmd .. "domain="..quote(shell_esc(domain_name)).." ";
|
||||
cmd = cmd .. "caller_id_name=" .. quote(shell_esc(caller_id_name) or '') .. " ";
|
||||
cmd = cmd .. "caller_id_number=" .. quote(shell_esc(caller_id_number) or '') .. " ";
|
||||
if #fax_forward_number > 0 then
|
||||
cmd = cmd .. "fax_relay=true ";
|
||||
else
|
||||
cmd = cmd .. "fax_relay=false ";
|
||||
end
|
||||
if #fax_prefix > 0 then
|
||||
cmd = cmd .. "fax_prefix=true ";
|
||||
else
|
||||
cmd = cmd .. "fax_prefix=false ";
|
||||
end
|
||||
freeswitch.consoleLog("notice", "[fax] command: " .. cmd .. "\n");
|
||||
os.execute(cmd);
|
||||
|
||||
--add to fax logs
|
||||
sql = "insert into v_fax_logs ";
|
||||
sql = sql .. "(";
|
||||
sql = sql .. "fax_log_uuid, ";
|
||||
sql = sql .. "domain_uuid, ";
|
||||
if (fax_uuid ~= nil) then
|
||||
sql = sql .. "fax_uuid, ";
|
||||
end
|
||||
sql = sql .. "fax_success, ";
|
||||
sql = sql .. "fax_result_code, ";
|
||||
sql = sql .. "fax_result_text, ";
|
||||
sql = sql .. "fax_file, ";
|
||||
if (fax_ecm_used ~= nil) then
|
||||
sql = sql .. "fax_ecm_used, ";
|
||||
end
|
||||
if (fax_local_station_id ~= nil) then
|
||||
sql = sql .. "fax_local_station_id, ";
|
||||
end
|
||||
sql = sql .. "fax_document_transferred_pages, ";
|
||||
sql = sql .. "fax_document_total_pages, ";
|
||||
if (fax_image_resolution ~= nil) then
|
||||
sql = sql .. "fax_image_resolution, ";
|
||||
end
|
||||
if (fax_image_size ~= nil) then
|
||||
sql = sql .. "fax_image_size, ";
|
||||
end
|
||||
if (fax_bad_rows ~= nil) then
|
||||
sql = sql .. "fax_bad_rows, ";
|
||||
end
|
||||
if (fax_transfer_rate ~= nil) then
|
||||
sql = sql .. "fax_transfer_rate, ";
|
||||
end
|
||||
if (fax_uri ~= nil) then
|
||||
sql = sql .. "fax_uri, ";
|
||||
end
|
||||
sql = sql .. "fax_date, ";
|
||||
sql = sql .. "fax_epoch ";
|
||||
sql = sql .. ") ";
|
||||
sql = sql .. "values ";
|
||||
sql = sql .. "(";
|
||||
sql = sql .. ":uuid, ";
|
||||
sql = sql .. ":domain_uuid, ";
|
||||
if (fax_uuid ~= nil) then
|
||||
sql = sql .. ":fax_uuid, ";
|
||||
end
|
||||
sql = sql .. ":fax_success, ";
|
||||
sql = sql .. ":fax_result_code, ";
|
||||
sql = sql .. ":fax_result_text, ";
|
||||
sql = sql .. ":fax_file, ";
|
||||
if (fax_ecm_used ~= nil) then
|
||||
sql = sql .. ":fax_ecm_used, ";
|
||||
end
|
||||
if (fax_local_station_id ~= nil) then
|
||||
sql = sql .. ":fax_local_station_id, ";
|
||||
end
|
||||
sql = sql .. ":fax_document_transferred_pages, ";
|
||||
sql = sql .. ":fax_document_total_pages, ";
|
||||
if (fax_image_resolution ~= nil) then
|
||||
sql = sql .. ":fax_image_resolution, ";
|
||||
end
|
||||
if (fax_image_size ~= nil) then
|
||||
sql = sql .. ":fax_image_size, ";
|
||||
end
|
||||
if (fax_bad_rows ~= nil) then
|
||||
sql = sql .. ":fax_bad_rows, ";
|
||||
end
|
||||
if (fax_transfer_rate ~= nil) then
|
||||
sql = sql .. ":fax_transfer_rate, ";
|
||||
end
|
||||
if (fax_uri ~= nil) then
|
||||
sql = sql .. ":fax_uri, ";
|
||||
end
|
||||
if (database["type"] == "sqlite") then
|
||||
sql = sql .. ":fax_date, ";
|
||||
else
|
||||
sql = sql .. "now(), ";
|
||||
end
|
||||
sql = sql .. ":fax_time ";
|
||||
sql = sql .. ")";
|
||||
|
||||
local params = {
|
||||
uuid = uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
fax_uuid = fax_uuid;
|
||||
fax_success = fax_success;
|
||||
fax_result_code = fax_result_code;
|
||||
fax_result_text = fax_result_text;
|
||||
fax_file = fax_file;
|
||||
fax_ecm_used = fax_ecm_used;
|
||||
fax_local_station_id = fax_local_station_id;
|
||||
fax_document_transferred_pages = fax_document_transferred_pages or '0';
|
||||
fax_document_total_pages = fax_document_total_pages or '0';
|
||||
fax_image_resolution = fax_image_resolution;
|
||||
fax_image_size = fax_image_size;
|
||||
fax_bad_rows = fax_bad_rows;
|
||||
fax_transfer_rate = fax_transfer_rate;
|
||||
fax_uri = fax_uri;
|
||||
fax_date = os.date("%Y-%m-%d %X");
|
||||
fax_time = os.time();
|
||||
};
|
||||
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[fax] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
dbh:query(sql, params);
|
||||
|
||||
--add the fax files
|
||||
if (fax_success ~= nil) then
|
||||
if (fax_success =="1") then
|
||||
if (storage_type == "base64") then
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--read file content as base64 string
|
||||
fax_base64 = assert(file.read_base64(fax_file));
|
||||
end
|
||||
|
||||
local sql = {}
|
||||
table.insert(sql, "insert into v_fax_files ");
|
||||
table.insert(sql, "(");
|
||||
table.insert(sql, "fax_file_uuid, ");
|
||||
table.insert(sql, "fax_uuid, ");
|
||||
table.insert(sql, "fax_mode, ");
|
||||
table.insert(sql, "fax_file_type, ");
|
||||
table.insert(sql, "fax_file_path, ");
|
||||
if (caller_id_name ~= nil) then
|
||||
table.insert(sql, "fax_caller_id_name, ");
|
||||
end
|
||||
if (caller_id_number ~= nil) then
|
||||
table.insert(sql, "fax_caller_id_number, ");
|
||||
end
|
||||
table.insert(sql, "fax_date, ");
|
||||
table.insert(sql, "fax_epoch, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(sql, "fax_base64, ");
|
||||
end
|
||||
table.insert(sql, "domain_uuid");
|
||||
table.insert(sql, ") ");
|
||||
table.insert(sql, "values ");
|
||||
table.insert(sql, "(");
|
||||
table.insert(sql, ":uuid, ");
|
||||
table.insert(sql, ":fax_uuid, ");
|
||||
table.insert(sql, "'rx', ");
|
||||
table.insert(sql, "'tif', ");
|
||||
table.insert(sql, ":fax_file, ");
|
||||
if (caller_id_name ~= nil) then
|
||||
table.insert(sql, ":caller_id_name, ");
|
||||
end
|
||||
if (caller_id_number ~= nil) then
|
||||
table.insert(sql, ":caller_id_number, ");
|
||||
end
|
||||
if (database["type"] == "sqlite") then
|
||||
table.insert(sql, ":fax_date, ");
|
||||
else
|
||||
table.insert(sql, "now(), ");
|
||||
end
|
||||
table.insert(sql, ":fax_time, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(sql, ":fax_base64, ");
|
||||
end
|
||||
table.insert(sql, ":domain_uuid");
|
||||
table.insert(sql, ")");
|
||||
sql = table.concat(sql, "\n");
|
||||
local params = {
|
||||
uuid = uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
fax_uuid = fax_uuid;
|
||||
fax_file = fax_file;
|
||||
caller_id_name = caller_id_name;
|
||||
caller_id_number = caller_id_number;
|
||||
fax_base64 = fax_base64;
|
||||
fax_date = os.date("%Y-%m-%d %X");
|
||||
fax_time = os.time();
|
||||
};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[fax] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
if (storage_type == "base64") then
|
||||
local dbh = Database.new('system', 'base64');
|
||||
dbh:query(sql, params);
|
||||
dbh:release();
|
||||
else
|
||||
result = dbh:query(sql, params);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--send the selected variables to the console
|
||||
if (fax_success ~= nil) then
|
||||
freeswitch.consoleLog("INFO","fax_success: '" .. fax_success .. "'\n");
|
||||
end
|
||||
freeswitch.consoleLog("INFO","domain_uuid: '" .. domain_uuid .. "'\n");
|
||||
freeswitch.consoleLog("INFO","domain_name: '" .. domain_name .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_uuid: '" .. fax_uuid .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_extension: '" .. fax_extension .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_result_text: '" .. fax_result_text .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_file: '" .. fax_file .. "'\n");
|
||||
freeswitch.consoleLog("INFO","uuid: '" .. uuid .. "'\n");
|
||||
--freeswitch.consoleLog("INFO","fax_ecm_used: '" .. fax_ecm_used .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_uri: '" .. fax_uri.. "'\n");
|
||||
if (caller_id_name ~= nil) then
|
||||
freeswitch.consoleLog("INFO","caller_id_name: " .. caller_id_name .. "\n");
|
||||
end
|
||||
if (caller_id_number ~= nil) then
|
||||
freeswitch.consoleLog("INFO","caller_id_number: " .. caller_id_number .. "\n");
|
||||
end
|
||||
freeswitch.consoleLog("INFO","fax_result_code: ".. fax_result_code .."\n");
|
||||
--freeswitch.consoleLog("INFO","mailfrom_address: ".. from_address .."\n");
|
||||
--freeswitch.consoleLog("INFO","mailto_address: ".. email_address .."\n");
|
||||
freeswitch.consoleLog("INFO","hangup_cause_q850: '" .. hangup_cause_q850 .. "'\n");
|
||||
@@ -0,0 +1,452 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2015-2023
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Mark J. Crane
|
||||
|
||||
--set the debug options
|
||||
debug["sql"] = true;
|
||||
|
||||
--create the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--additional includes
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.count";
|
||||
require "resources.functions.send_mail";
|
||||
|
||||
--check if windows
|
||||
local IS_WINDOWS = (package.config:sub(1,1) == '\\')
|
||||
|
||||
--define function quote
|
||||
local function quote(s)
|
||||
local q = IS_WINDOWS and '"' or "'"
|
||||
if s:find('%s') or s:find(q, nil, true) then
|
||||
s = q .. s:gsub(q, q..q) .. q
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
--escape shell arguments to prevent command injection
|
||||
local function shell_esc(x)
|
||||
return (x:gsub('\\', '\\\\')
|
||||
:gsub('\'', '\\\''))
|
||||
end
|
||||
|
||||
--set channel variables to lua variables
|
||||
domain_uuid = env:getHeader("domain_uuid");
|
||||
domain_name = env:getHeader("domain_name");
|
||||
|
||||
--get the domain_uuid using the domain name required for multi-tenant
|
||||
if (domain_name ~= nil) then
|
||||
sql = "SELECT domain_uuid FROM v_domains ";
|
||||
sql = sql .. "WHERE domain_name = :domain_name ";
|
||||
dbh:query(sql, {domain_name = domain_name}, function(rows)
|
||||
domain_uuid = rows["domain_uuid"];
|
||||
end);
|
||||
end
|
||||
|
||||
--settings
|
||||
require "resources.functions.settings";
|
||||
settings = settings(domain_uuid);
|
||||
storage_type = "";
|
||||
storage_path = "";
|
||||
if (settings['fax'] ~= nil) then
|
||||
if (settings['fax']['storage_type'] ~= nil) then
|
||||
if (settings['fax']['storage_type']['text'] ~= nil) then
|
||||
storage_type = settings['fax']['storage_type']['text'];
|
||||
end
|
||||
end
|
||||
if (settings['fax']['storage_path'] ~= nil) then
|
||||
if (settings['fax']['storage_path']['text'] ~= nil) then
|
||||
storage_path = settings['fax']['storage_path']['text'];
|
||||
storage_path = storage_path:gsub("${domain_name}", domain_name);
|
||||
storage_path = storage_path:gsub("${voicemail_id}", voicemail_id);
|
||||
storage_path = storage_path:gsub("${voicemail_dir}", voicemail_dir);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--show all channel variables
|
||||
serialized = env:serialize()
|
||||
freeswitch.consoleLog("INFO","[fax]\n" .. serialized .. "\n")
|
||||
|
||||
--example channel variables relating to fax
|
||||
--variable_fax_success: 0
|
||||
--variable_fax_result_code: 49
|
||||
--variable_fax_result_text: The%20call%20dropped%20prematurely
|
||||
--variable_fax_ecm_used: off
|
||||
--variable_fax_local_station_id: SpanDSP%20Fax%20Ident
|
||||
--variable_fax_document_transferred_pages: 0
|
||||
--variable_fax_document_total_pages: 0
|
||||
--variable_fax_image_resolution: 0x0
|
||||
--variable_fax_image_size: 0
|
||||
--variable_fax_bad_rows: 0
|
||||
--variable_fax_transfer_rate: 14400
|
||||
|
||||
--set channel variables to lua variables
|
||||
uuid = env:getHeader("uuid");
|
||||
fax_uuid = env:getHeader("fax_uuid");
|
||||
fax_queue_uuid = env:getHeader("fax_queue_uuid");
|
||||
fax_success = env:getHeader("fax_success");
|
||||
fax_result_text = env:getHeader("fax_result_text");
|
||||
fax_local_station_id = env:getHeader("fax_local_station_id");
|
||||
fax_image_resolution = env:getHeader("fax_image_resolution");
|
||||
fax_image_size = env:getHeader("fax_image_size");
|
||||
fax_ecm_used = env:getHeader("fax_ecm_used");
|
||||
fax_uri = env:getHeader("fax_uri");
|
||||
fax_extension_number = env:getHeader("fax_extension_number");
|
||||
caller_id_name = env:getHeader("caller_id_name");
|
||||
caller_id_number = env:getHeader("caller_id_number");
|
||||
fax_bad_rows = env:getHeader("fax_bad_rows");
|
||||
fax_transfer_rate = env:getHeader("fax_transfer_rate");
|
||||
sip_to_user = env:getHeader("sip_to_user");
|
||||
bridge_hangup_cause = env:getHeader("bridge_hangup_cause");
|
||||
fax_result_code = env:getHeader("fax_result_code");
|
||||
fax_remote_station_id = env:getHeader("fax_remote_station_id");
|
||||
fax_document_transferred_pages = env:getHeader("fax_document_transferred_pages");
|
||||
fax_document_total_pages = env:getHeader("fax_document_total_pages");
|
||||
hangup_cause_q850 = tonumber(env:getHeader("hangup_cause_q850"));
|
||||
fax_file = env:getHeader("fax_file");
|
||||
fax_duration = env:getHeader("billsec");
|
||||
|
||||
--prevent nil errors
|
||||
if (fax_file == nil) then
|
||||
fax_file = env:getHeader("fax_filename");
|
||||
end
|
||||
if (fax_uri == nil) then
|
||||
fax_uri = "";
|
||||
end
|
||||
if (fax_remote_station_id == nil) then
|
||||
fax_remote_station_id = "";
|
||||
end
|
||||
if (caller_id_name == nil) then
|
||||
caller_id_name = env:getHeader("Caller-Caller-ID-Name");
|
||||
end
|
||||
if (caller_id_number == nil) then
|
||||
caller_id_number = env:getHeader("Caller-Caller-ID-Number");
|
||||
end
|
||||
if (document_root == nil) then
|
||||
document_root = '';
|
||||
end
|
||||
|
||||
--set default values
|
||||
if (not fax_success) then
|
||||
fax_success = "0";
|
||||
end
|
||||
if (hangup_cause_q850 == "17") then
|
||||
fax_success = "0";
|
||||
fax_result_text = "USER_BUSY";
|
||||
end
|
||||
if (not fax_result_text) then
|
||||
fax_result_text = "FS_NOT_SET";
|
||||
end
|
||||
|
||||
--fax sent successfully
|
||||
if (fax_success == '1') then
|
||||
fax_status = 'sent';
|
||||
else
|
||||
fax_status = 'trying';
|
||||
end
|
||||
|
||||
--fax busy
|
||||
if (fax_result_code == "2" or fax_result_code == "3" or hangup_cause_q850 == 17) then
|
||||
--do nothing. don't want to increment
|
||||
freeswitch.consoleLog("INFO","[FAX] Last Fax was probably Busy, don't increment retry_attempts. \n");
|
||||
fax_status = 'busy';
|
||||
end
|
||||
|
||||
--get the fax settings from the database
|
||||
local sql = [[SELECT * FROM v_fax
|
||||
WHERE fax_uuid = :fax_uuid
|
||||
AND domain_uuid = :domain_uuid]];
|
||||
local params = {fax_uuid = fax_uuid, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[fax] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
dialplan_uuid = row["dialplan_uuid"];
|
||||
fax_extension = row["fax_extension"];
|
||||
fax_accountcode = row["accountcode"];
|
||||
fax_destination_number = row["fax_destination_number"];
|
||||
fax_name = row["fax_name"];
|
||||
fax_prefix = row["fax_prefix"];
|
||||
fax_email = row["fax_email"];
|
||||
fax_email_connection_type = row["fax_email_connection_type"];
|
||||
fax_email_connection_host = row["fax_email_connection_host"];
|
||||
fax_email_connection_port = row["fax_email_connection_port"];
|
||||
fax_email_connection_security = row["fax_email_connection_security"];
|
||||
fax_email_connection_validate = row["fax_email_connection_validate"];
|
||||
fax_email_connection_username = row["fax_email_connection_username"];
|
||||
fax_email_connection_password = row["fax_email_connection_password"];
|
||||
fax_email_connection_mailbox = row["fax_email_connection_mailbox"];
|
||||
fax_email_inbound_subject_tag = row["fax_email_inbound_subject_tag"];
|
||||
fax_email_outbound_subject_tag = row["fax_email_outbound_subject_tag"];
|
||||
fax_email_outbound_authorized_senders = row["fax_email_outbound_authorized_senders"];
|
||||
fax_caller_id_name = row["fax_caller_id_name"];
|
||||
fax_caller_id_number = row["fax_caller_id_number"];
|
||||
fax_forward_number = row["fax_forward_number"];
|
||||
fax_description = row["fax_description"];
|
||||
end);
|
||||
|
||||
--get the values from the fax file
|
||||
if (fax_file ~= nil) then
|
||||
array = explode("/", fax_file);
|
||||
fax_file_name = array[count(array)];
|
||||
end
|
||||
|
||||
--add to fax logs
|
||||
sql = "insert into v_fax_logs ";
|
||||
sql = sql .. "(";
|
||||
sql = sql .. "fax_log_uuid, ";
|
||||
sql = sql .. "domain_uuid, ";
|
||||
if (fax_uuid ~= nil) then
|
||||
sql = sql .. "fax_uuid, ";
|
||||
end
|
||||
sql = sql .. "fax_success, ";
|
||||
sql = sql .. "fax_result_code, ";
|
||||
sql = sql .. "fax_result_text, ";
|
||||
sql = sql .. "fax_file, ";
|
||||
if (fax_ecm_used ~= nil) then
|
||||
sql = sql .. "fax_ecm_used, ";
|
||||
end
|
||||
if (fax_local_station_id ~= nil) then
|
||||
sql = sql .. "fax_local_station_id, ";
|
||||
end
|
||||
sql = sql .. "fax_document_transferred_pages, ";
|
||||
sql = sql .. "fax_document_total_pages, ";
|
||||
if (fax_image_resolution ~= nil) then
|
||||
sql = sql .. "fax_image_resolution, ";
|
||||
end
|
||||
if (fax_image_size ~= nil) then
|
||||
sql = sql .. "fax_image_size, ";
|
||||
end
|
||||
if (fax_bad_rows ~= nil) then
|
||||
sql = sql .. "fax_bad_rows, ";
|
||||
end
|
||||
if (fax_transfer_rate ~= nil) then
|
||||
sql = sql .. "fax_transfer_rate, ";
|
||||
end
|
||||
if (fax_uri ~= nil) then
|
||||
sql = sql .. "fax_uri, ";
|
||||
end
|
||||
if (fax_duration ~= nil) then
|
||||
sql = sql .. "fax_duration, ";
|
||||
end
|
||||
sql = sql .. "fax_date, ";
|
||||
sql = sql .. "fax_epoch ";
|
||||
sql = sql .. ") ";
|
||||
sql = sql .. "values ";
|
||||
sql = sql .. "(";
|
||||
sql = sql .. ":uuid, ";
|
||||
sql = sql .. ":domain_uuid, ";
|
||||
if (fax_uuid ~= nil) then
|
||||
sql = sql .. ":fax_uuid, ";
|
||||
end
|
||||
sql = sql .. ":fax_success, ";
|
||||
sql = sql .. ":fax_result_code, ";
|
||||
sql = sql .. ":fax_result_text, ";
|
||||
sql = sql .. ":fax_file, ";
|
||||
if (fax_ecm_used ~= nil) then
|
||||
sql = sql .. ":fax_ecm_used, ";
|
||||
end
|
||||
if (fax_local_station_id ~= nil) then
|
||||
sql = sql .. ":fax_local_station_id, ";
|
||||
end
|
||||
sql = sql .. ":fax_document_transferred_pages, ";
|
||||
sql = sql .. ":fax_document_total_pages, ";
|
||||
if (fax_image_resolution ~= nil) then
|
||||
sql = sql .. ":fax_image_resolution, ";
|
||||
end
|
||||
if (fax_image_size ~= nil) then
|
||||
sql = sql .. ":fax_image_size, ";
|
||||
end
|
||||
if (fax_bad_rows ~= nil) then
|
||||
sql = sql .. ":fax_bad_rows, ";
|
||||
end
|
||||
if (fax_transfer_rate ~= nil) then
|
||||
sql = sql .. ":fax_transfer_rate, ";
|
||||
end
|
||||
if (fax_uri ~= nil) then
|
||||
sql = sql .. ":fax_uri, ";
|
||||
end
|
||||
if (fax_duration ~= nil) then
|
||||
sql = sql .. ":fax_duration, ";
|
||||
end
|
||||
if (database["type"] == "sqlite") then
|
||||
sql = sql .. ":fax_date, ";
|
||||
else
|
||||
sql = sql .. "now(), ";
|
||||
end
|
||||
sql = sql .. ":fax_time ";
|
||||
sql = sql .. ")";
|
||||
local params = {
|
||||
uuid = uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
fax_uuid = fax_uuid;
|
||||
fax_success = fax_success;
|
||||
fax_result_code = fax_result_code;
|
||||
fax_result_text = fax_result_text;
|
||||
fax_file = fax_file;
|
||||
fax_ecm_used = fax_ecm_used;
|
||||
fax_local_station_id = fax_local_station_id;
|
||||
fax_document_transferred_pages = fax_document_transferred_pages or '0';
|
||||
fax_document_total_pages = fax_document_total_pages or '0';
|
||||
fax_image_resolution = fax_image_resolution;
|
||||
fax_image_size = fax_image_size;
|
||||
fax_bad_rows = fax_bad_rows;
|
||||
fax_transfer_rate = fax_transfer_rate;
|
||||
fax_uri = fax_uri;
|
||||
fax_duration = fax_duration;
|
||||
fax_date = os.date("%Y-%m-%d %X");
|
||||
fax_time = os.time();
|
||||
};
|
||||
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[fax] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
--update the email queue status
|
||||
sql = "update v_fax_queue ";
|
||||
sql = sql .. "set fax_status = :fax_status, fax_log_uuid = :fax_log_uuid ";
|
||||
sql = sql .. "where fax_queue_uuid = :fax_queue_uuid ";
|
||||
local params = {fax_queue_uuid = fax_queue_uuid, fax_status = fax_status, fax_log_uuid = uuid}
|
||||
dbh:query(sql, params);
|
||||
|
||||
--prepare base64
|
||||
if (storage_type == "base64") then
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--read file content as base64 string
|
||||
fax_base64 = assert(file.read_base64(fax_file));
|
||||
end
|
||||
|
||||
--add the fax files
|
||||
local sql = {}
|
||||
table.insert(sql, "insert into v_fax_files ");
|
||||
table.insert(sql, "(");
|
||||
table.insert(sql, "fax_file_uuid, ");
|
||||
table.insert(sql, "fax_uuid, ");
|
||||
table.insert(sql, "fax_mode, ");
|
||||
table.insert(sql, "fax_file_type, ");
|
||||
table.insert(sql, "fax_file_path, ");
|
||||
if (caller_id_name ~= nil) then
|
||||
table.insert(sql, "fax_caller_id_name, ");
|
||||
end
|
||||
if (caller_id_number ~= nil) then
|
||||
table.insert(sql, "fax_caller_id_number, ");
|
||||
end
|
||||
table.insert(sql, "fax_destination, ");
|
||||
table.insert(sql, "fax_date, ");
|
||||
table.insert(sql, "fax_epoch, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(sql, "fax_base64, ");
|
||||
end
|
||||
table.insert(sql, "domain_uuid");
|
||||
table.insert(sql, ") ");
|
||||
table.insert(sql, "values ");
|
||||
table.insert(sql, "(");
|
||||
table.insert(sql, ":uuid, ");
|
||||
table.insert(sql, ":fax_uuid, ");
|
||||
table.insert(sql, "'tx', ");
|
||||
table.insert(sql, "'tif', ");
|
||||
table.insert(sql, ":fax_file, ");
|
||||
if (caller_id_name ~= nil) then
|
||||
table.insert(sql, ":caller_id_name, ");
|
||||
end
|
||||
if (caller_id_number ~= nil) then
|
||||
table.insert(sql, ":caller_id_number, ");
|
||||
end
|
||||
table.insert(sql, ":fax_destination, ");
|
||||
if (database["type"] == "sqlite") then
|
||||
table.insert(sql, ":fax_date, ");
|
||||
else
|
||||
table.insert(sql, "now(), ");
|
||||
end
|
||||
table.insert(sql, ":fax_time, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(sql, ":fax_base64, ");
|
||||
end
|
||||
table.insert(sql, ":domain_uuid");
|
||||
table.insert(sql, ")");
|
||||
sql = table.concat(sql, "\n");
|
||||
local params = {
|
||||
uuid = uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
fax_uuid = fax_uuid;
|
||||
fax_file = fax_file;
|
||||
caller_id_name = fax_caller_id_name;
|
||||
caller_id_number = fax_caller_id_number;
|
||||
fax_destination = sip_to_user;
|
||||
fax_base64 = fax_base64;
|
||||
fax_date = os.date("%Y-%m-%d %X");
|
||||
fax_time = os.time();
|
||||
};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[fax] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
if (storage_type == "base64") then
|
||||
local dbh = Database.new('system', 'base64');
|
||||
dbh:query(sql, params);
|
||||
dbh:release();
|
||||
else
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
|
||||
--send the selected variables to the console
|
||||
if (fax_success ~= nil) then
|
||||
freeswitch.consoleLog("INFO","fax_success: '" .. fax_success .. "'\n");
|
||||
end
|
||||
freeswitch.consoleLog("INFO","domain_uuid: '" .. domain_uuid .. "'\n");
|
||||
freeswitch.consoleLog("INFO","domain_name: '" .. domain_name .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_uuid: '" .. fax_uuid .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_extension: '" .. fax_extension .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_result_text: '" .. fax_result_text .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_file: '" .. fax_file .. "'\n");
|
||||
freeswitch.consoleLog("INFO","uuid: '" .. uuid .. "'\n");
|
||||
--freeswitch.consoleLog("INFO","fax_ecm_used: '" .. fax_ecm_used .. "'\n");
|
||||
freeswitch.consoleLog("INFO","fax_uri: '" .. fax_uri.. "'\n");
|
||||
if (caller_id_name ~= nil) then
|
||||
freeswitch.consoleLog("INFO","caller_id_name: " .. fax_caller_id_name .. "\n");
|
||||
end
|
||||
if (caller_id_number ~= nil) then
|
||||
freeswitch.consoleLog("INFO","caller_id_number: " .. fax_caller_id_number .. "\n");
|
||||
end
|
||||
freeswitch.consoleLog("INFO","fax_destination: " .. sip_to_user .. "\n");
|
||||
freeswitch.consoleLog("INFO","fax_result_code: ".. fax_result_code .."\n");
|
||||
--freeswitch.consoleLog("INFO","mailfrom_address: ".. from_address .."\n");
|
||||
--freeswitch.consoleLog("INFO","mailto_address: ".. email_address .."\n");
|
||||
freeswitch.consoleLog("INFO","hangup_cause_q850: '" .. hangup_cause_q850 .. "'\n");
|
||||
@@ -0,0 +1,51 @@
|
||||
<html>
|
||||
<table width="400" border="0" cellspacing="0" cellpadding="0" align="center"
|
||||
style="border: 1px solid #cbcfd5;-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px; border-radius: 4px;">
|
||||
<tr>
|
||||
<td valign="middle" align="center" bgcolor="#ff7174" style="background-color: #ff7174;
|
||||
color: #000; font-family: Arial; font-size: 14px; padding: 7px;-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px; border-radius: 4px;">
|
||||
<strong>Send fax fail</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="padding: 15px;">
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>To</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${destination_number}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Pages</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${document_transferred_pages}/${document_total_pages}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Message</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${message}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Error</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${hangup_cause}/${fax_result_code}/${fax_result_text}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</html>
|
||||
+1
@@ -0,0 +1 @@
|
||||
Fax to: ${destination_number} FAILED
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
<html>
|
||||
<table width="400" border="0" cellspacing="0" cellpadding="0" align="center"
|
||||
style="border: 1px solid #cbcfd5;-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px; border-radius: 4px;">
|
||||
<tr>
|
||||
<td valign="middle" align="center" bgcolor="#e5e9f0" style="background-color: #e5e9f0;
|
||||
color: #000; font-family: Arial; font-size: 14px; padding: 7px;-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px; border-radius: 4px;">
|
||||
<strong>Send fax successfully</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="padding: 15px;">
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>To</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${destination_number}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Pages</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${document_transferred_pages}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Message</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${message}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Options</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${fax_options}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</html>
|
||||
+1
@@ -0,0 +1 @@
|
||||
Fax to: ${destination_number} sent
|
||||
@@ -0,0 +1,359 @@
|
||||
--
|
||||
-- event_notify
|
||||
-- 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 - event_notify
|
||||
--
|
||||
-- The Initial Developer of the Original Code is
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- Copyright (C) 2013 - 2021
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- KonradSC <konrd@yahoo.com>
|
||||
|
||||
-- Start the script
|
||||
-- /etc/freeswitch/autoload_configs/lua.conf.xml
|
||||
-- <!-- Subscribe to events -->
|
||||
-- <hook event="PHONE_FEATURE_SUBSCRIBE" subclass="" script="app.lua feature_event"/>
|
||||
|
||||
--Enable Feature Sync
|
||||
-- Default Settings:
|
||||
-- Device -> feature_sync = true
|
||||
|
||||
--Yealink
|
||||
-- Web Interface -> Features -> General Information -> Feature Key Synchronization set to Enabled
|
||||
-- Config Files -> bw.feature_key_sync = 1
|
||||
--Polycom
|
||||
-- reg.{$row.line_number}.serverFeatureControl.cf="1"
|
||||
-- reg.{$row.line_number}.serverFeatureControl.dnd="1"
|
||||
-- Cisco SPA
|
||||
-- <Feature_Key_Sync_1_ group="Ext_1/Call_Feature_Settings">Yes</Feature_Key_Sync_1_>
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--define the functions
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.explode";
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
local cache = require "resources.functions.cache"
|
||||
local notify = require "app.feature_event.resources.functions.feature_event_notify"
|
||||
dbh = Database.new('system');
|
||||
local settings = Settings.new(dbh, domain_name, domain_uuid);
|
||||
|
||||
--set debug
|
||||
debug["sql"] = false;
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--get the events
|
||||
--serialize the data for the console
|
||||
--freeswitch.consoleLog("notice","[events] " .. event:serialize("xml") .. "\n");
|
||||
--freeswitch.consoleLog("notice","[evnts] " .. event:serialize("json") .. "\n");
|
||||
|
||||
--get the event variables
|
||||
user = event:getHeader("user");
|
||||
host = event:getHeader("host");
|
||||
domain_name = event:getHeader("host");
|
||||
contact = event:getHeader("contact");
|
||||
feature_action = event:getHeader("Feature-Action");
|
||||
feature_enabled = event:getHeader("Feature-Enabled");
|
||||
action_name = event:getHeader("Action-Name");
|
||||
action_value = event:getHeader("Action-Value")
|
||||
ring_count = event:getHeader("ringCount")
|
||||
|
||||
--send to the log
|
||||
-- freeswitch.consoleLog("notice","[events] user: " .. user .. "\n");
|
||||
-- freeswitch.consoleLog("notice","[events] host: " .. host .. "\n");
|
||||
-- if (feature_action ~= nil) then freeswitch.consoleLog("notice","[events] feature_action: " .. feature_action .. "\n"); end
|
||||
-- if (feature_enabled ~= nil) then freeswitch.consoleLog("notice","[events] feature_enabled: " .. feature_enabled .. "\n"); end
|
||||
-- if (action_name ~= nil) then freeswitch.consoleLog("notice","[events] action_name: " .. action_name .. "\n"); end
|
||||
-- if (action_value ~= nil) then freeswitch.consoleLog("notice","[events] action_value: " .. action_value .. "\n"); end
|
||||
|
||||
--get the domain uuid from the host
|
||||
local sql = "select * from v_domains ";
|
||||
sql = sql .. "where domain_name = :domain_name ";
|
||||
local params = {domain_name = domain_name};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
domain_uuid = row.domain_uuid;
|
||||
end);
|
||||
|
||||
--get extension information
|
||||
if (user ~= nil and domain_name ~= nil) then
|
||||
do_not_disturb, forward_all_enabled, forward_all_destination, forward_busy_enabled, forward_busy_destination, forward_no_answer_enabled, forward_no_answer_destination, call_timeout = notify.get_db_values(user, domain_name)
|
||||
end
|
||||
|
||||
--get sip profile
|
||||
if (user ~= nil and host ~= nil) then
|
||||
sip_profiles = notify.get_profiles(user, host);
|
||||
end
|
||||
|
||||
--DND
|
||||
if (sip_profiles ~= nil) then
|
||||
--DND enabled
|
||||
if (feature_action == "SetDoNotDisturb") then
|
||||
--set dnd
|
||||
if(feature_enabled == "true") then
|
||||
do_not_disturb = "true";
|
||||
else
|
||||
do_not_disturb = "false";
|
||||
end
|
||||
|
||||
--update the extension
|
||||
sql = "update v_extensions set ";
|
||||
sql = sql .. "do_not_disturb = :do_not_disturb ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and extension_uuid = :extension_uuid ";
|
||||
local params = {domain_uuid = domain_uuid, extension_uuid = extension_uuid, do_not_disturb = do_not_disturb};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
--send notify to the phone
|
||||
notify.dnd(user, host, sip_profiles, do_not_disturb);
|
||||
end
|
||||
|
||||
--Call Forward
|
||||
|
||||
--Call Forward All enabled
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "true" and action_name == "forward_immediate") then
|
||||
--set a variable
|
||||
forward_all_destination = action_value;
|
||||
forward_all_enabled = "true";
|
||||
forward_immediate_destination = action_value;
|
||||
forward_immediate_enabled = "true";
|
||||
|
||||
if feature_enabled == "true" then
|
||||
local destination_extension, destination_number_alias
|
||||
|
||||
--used for number_alias to get the correct user
|
||||
local sql = "select extension, number_alias from v_extensions ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and number_alias = :number_alias ";
|
||||
local params = {domain_uuid = domain_uuid; number_alias = forward_all_destination}
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
destination_user = row.extension;
|
||||
destination_extension = row.extension;
|
||||
destination_number_alias = row.number_alias or '';
|
||||
end);
|
||||
|
||||
if (destination_user ~= nil) then
|
||||
cmd = "user_exists id ".. destination_user .." "..domain_name;
|
||||
else
|
||||
cmd = "user_exists id ".. forward_all_destination .." "..domain_name;
|
||||
end
|
||||
local user_exists = trim(api:executeString(cmd));
|
||||
end
|
||||
|
||||
--update the extension
|
||||
sql = "update v_extensions set ";
|
||||
sql = sql .. "do_not_disturb = 'false', ";
|
||||
sql = sql .. "forward_all_enabled = 'true', ";
|
||||
sql = sql .. "forward_all_destination = :forward_all_destination ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and extension_uuid = :extension_uuid ";
|
||||
local params = {domain_uuid = domain_uuid, extension_uuid = extension_uuid, forward_all_destination = forward_all_destination};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
--send notify to the phone
|
||||
notify.forward_immediate(user, host, sip_profiles, forward_immediate_enabled, forward_immediate_destination);
|
||||
end
|
||||
|
||||
--Call Forward All disable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "false" and action_name == "forward_immediate") then
|
||||
--set a variable
|
||||
forward_all_destination = action_value;
|
||||
forward_all_enabled = "false";
|
||||
forward_immediate_enabled = "false";
|
||||
forward_immediate_destination = action_value;
|
||||
|
||||
--update the extension
|
||||
sql = "update v_extensions set ";
|
||||
sql = sql .. "do_not_disturb = 'false', ";
|
||||
sql = sql .. "forward_all_enabled = 'false', ";
|
||||
if (forward_all_destination ~= nil) then
|
||||
sql = sql .. "forward_all_destination = :forward_all_destination ";
|
||||
else
|
||||
sql = sql .. "forward_all_destination = null ";
|
||||
end
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and extension_uuid = :extension_uuid ";
|
||||
local params = {domain_uuid = domain_uuid, extension_uuid = extension_uuid, forward_all_destination = forward_all_destination};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
--send notify to the phone
|
||||
if (forward_immediate_destination == nil) then
|
||||
forward_immediate_destination = " ";
|
||||
end
|
||||
notify.forward_immediate(user, host, sip_profiles, forward_immediate_enabled, forward_immediate_destination);
|
||||
end
|
||||
|
||||
--Call Forward BUSY enable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "true" and action_name == "forward_busy") then
|
||||
--set a variable
|
||||
forward_busy_destination = action_value;
|
||||
forward_busy_enabled = "true";
|
||||
|
||||
--update the extension
|
||||
sql = "update v_extensions set ";
|
||||
sql = sql .. "do_not_disturb = 'false', ";
|
||||
sql = sql .. "forward_busy_enabled = 'true', ";
|
||||
sql = sql .. "forward_busy_destination = :forward_busy_destination ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and extension_uuid = :extension_uuid ";
|
||||
local params = {domain_uuid = domain_uuid, extension_uuid = extension_uuid, forward_busy_destination = forward_busy_destination};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
--send notify to the phone
|
||||
notify.forward_busy(user, host, sip_profiles, forward_busy_enabled, forward_busy_destination);
|
||||
end
|
||||
|
||||
--Call Forward BUSY disable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "false" and action_name == "forward_busy") then
|
||||
--set a variable
|
||||
forward_busy_destination = action_value;
|
||||
forward_busy_enabled = "false";
|
||||
|
||||
--update the extension
|
||||
sql = "update v_extensions set ";
|
||||
sql = sql .. "do_not_disturb = 'false', ";
|
||||
sql = sql .. "forward_busy_enabled = 'false', ";
|
||||
if (forward_busy_destination ~= nil) then
|
||||
sql = sql .. "forward_busy_destination = :forward_busy_destination ";
|
||||
else
|
||||
sql = sql .. "forward_busy_destination = null ";
|
||||
end
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and extension_uuid = :extension_uuid ";
|
||||
local params = {domain_uuid = domain_uuid, extension_uuid = extension_uuid, forward_busy_destination = forward_busy_destination};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
--send notify to the phone
|
||||
notify.forward_busy(user, host, sip_profiles, forward_busy_enabled, forward_busy_destination);
|
||||
end
|
||||
|
||||
--Call Forward NO ANSWER enable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "true" and action_name == "forward_no_answer") then
|
||||
--set a variable
|
||||
forward_no_answer_destination = action_value;
|
||||
forward_no_answer_enabled = "true";
|
||||
call_timeout = ring_count * 6;
|
||||
|
||||
--update the extension
|
||||
sql = "update v_extensions set ";
|
||||
sql = sql .. "do_not_disturb = 'false', ";
|
||||
sql = sql .. "call_timeout = :call_timeout, ";
|
||||
sql = sql .. "forward_no_answer_enabled = 'true', ";
|
||||
sql = sql .. "forward_no_answer_destination = :forward_no_answer_destination ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and extension_uuid = :extension_uuid ";
|
||||
local params = {domain_uuid = domain_uuid, extension_uuid = extension_uuid, forward_no_answer_destination = forward_no_answer_destination, call_timeout = call_timeout};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
--send notify to the phone
|
||||
notify.forward_no_answer(user, host, sip_profiles, forward_no_answer_enabled, forward_no_answer_destination, ring_count);
|
||||
end
|
||||
|
||||
--Call Forward NO ANSWER disable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "false" and action_name == "forward_no_answer") then
|
||||
--set a variable
|
||||
forward_no_answer_destination = action_value;
|
||||
forward_no_answer_enabled = "false";
|
||||
|
||||
--update the extension
|
||||
sql = "update v_extensions set ";
|
||||
sql = sql .. "do_not_disturb = 'false', ";
|
||||
sql = sql .. "forward_no_answer_enabled = 'false', ";
|
||||
if (forward_no_answer_destination ~= nil) then
|
||||
sql = sql .. "forward_no_answer_destination = :forward_no_answer_destination ";
|
||||
else
|
||||
sql = sql .. "forward_no_answer_destination = null ";
|
||||
end
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and extension_uuid = :extension_uuid ";
|
||||
local params = {domain_uuid = domain_uuid, extension_uuid = extension_uuid, forward_no_answer_destination = forward_no_answer_destination, call_timeout = call_timeout};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
--send notify to the phone
|
||||
notify.forward_no_answer(user, host, sip_profiles, forward_no_answer_enabled, forward_no_answer_destination, ring_count);
|
||||
end
|
||||
|
||||
--No feature event (phone boots): Send all values
|
||||
if (feature_enabled == nil) then
|
||||
--Do Not Disturb
|
||||
--notify.dnd(user, host, sip_profiles, do_not_disturb);
|
||||
|
||||
--Forward all
|
||||
forward_immediate_enabled = forward_all_enabled;
|
||||
forward_immediate_destination = forward_all_destination;
|
||||
--notify.forward_immediate(user, host, sip_profiles, forward_immediate_enabled, forward_immediate_destination);
|
||||
|
||||
--Forward busy
|
||||
--notify.forward_busy(user, host, sip_profiles, forward_busy_enabled, forward_busy_destination);
|
||||
|
||||
--Forward No Answer
|
||||
ring_count = math.ceil (call_timeout / 6);
|
||||
--notify.forward_no_answer(user, host, sip_profiles, forward_no_answer_enabled, forward_no_answer_destination, ring_count);
|
||||
notify.init(user,
|
||||
host,
|
||||
sip_profiles,
|
||||
forward_immediate_enabled,
|
||||
forward_immediate_destination,
|
||||
forward_busy_enabled,
|
||||
forward_busy_destination,
|
||||
forward_no_answer_enabled,
|
||||
forward_no_answer_destination,
|
||||
ring_count,
|
||||
do_not_disturb);
|
||||
end
|
||||
|
||||
-- feature_event_notify.init(user, host, sip_profiles, forward_immediate_enabled, forward_immediate_destination, forward_busy_enabled, forward_busy_destination, forward_no_answer_enabled, forward_no_answer_destination, ring_count, do_not_disturb)
|
||||
end
|
||||
--clear the cache
|
||||
if (feature_enabled ~= nil) then
|
||||
cache.del("directory:"..user.."@"..host)
|
||||
end
|
||||
+176
@@ -0,0 +1,176 @@
|
||||
local feature_event_notify = {}
|
||||
|
||||
function feature_event_notify.get_db_values(user, domain_name)
|
||||
--get the domain uuid from the host
|
||||
local Database = require "resources.functions.database";
|
||||
local dbh = Database.new('system');
|
||||
|
||||
local sql = "select * from v_domains ";
|
||||
sql = sql .. "where domain_name = :domain_name ";
|
||||
local params = {domain_name = domain_name};
|
||||
-- if (debug["sql"]) then
|
||||
-- freeswitch.consoleLog("notice", "[feature_event] " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
-- end
|
||||
dbh:query(sql, params, function(row)
|
||||
domain_uuid = row.domain_uuid;
|
||||
end);
|
||||
|
||||
--get extension information
|
||||
local sql = "select * from v_extensions ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and (extension = :extension or number_alias = :extension) ";
|
||||
local params = {domain_uuid = domain_uuid, extension = user};
|
||||
-- if (debug["sql"]) then
|
||||
-- freeswitch.consoleLog("notice", "[feature_event] " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
-- end
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
extension_uuid = row.extension_uuid;
|
||||
extension = row.extension;
|
||||
number_alias = row.number_alias or '';
|
||||
accountcode = row.accountcode;
|
||||
follow_me_uuid = row.follow_me_uuid;
|
||||
do_not_disturb = row.do_not_disturb;
|
||||
forward_all_enabled = row.forward_all_enabled;
|
||||
forward_all_destination = row.forward_all_destination;
|
||||
forward_busy_enabled = row.forward_busy_enabled;
|
||||
forward_busy_destination = row.forward_busy_destination;
|
||||
forward_no_answer_enabled = row.forward_no_answer_enabled;
|
||||
forward_no_answer_destination = row.forward_no_answer_destination;
|
||||
forward_user_not_registered_enabled = row.forward_user_not_registered_enabled;
|
||||
forward_user_not_registered_destination = row.forward_user_not_registered_destination;
|
||||
toll_allow = row.toll_allow
|
||||
call_timeout = row.call_timeout
|
||||
--freeswitch.consoleLog("NOTICE", "[feature_event] extension "..row.extension.."\n");
|
||||
--freeswitch.consoleLog("NOTICE", "[feature_event] accountcode "..row.accountcode.."\n");
|
||||
end);
|
||||
|
||||
--set some defaults if values in database are NULL
|
||||
if (forward_all_enabled == "") then forward_all_enabled = "false"; end
|
||||
--if (forward_all_destination == "") then forward_all_destination = nil; end
|
||||
if (forward_busy_enabled == "") then forward_busy_enabled = "false"; end
|
||||
if (forward_no_answer_enabled == "") then forward_no_answer_enabled = "false"; end
|
||||
if (do_not_disturb == "") then do_not_disturb = "false"; end
|
||||
if (call_timeout == "") then call_timeout = "30"; end
|
||||
|
||||
return do_not_disturb, forward_all_enabled, forward_all_destination, forward_busy_enabled, forward_busy_destination, forward_no_answer_enabled, forward_no_answer_destination, call_timeout
|
||||
end
|
||||
|
||||
---@return table, nil
|
||||
function feature_event_notify.get_profiles(user, domain)
|
||||
--includes
|
||||
require "resources.functions.trim"
|
||||
|
||||
local account = user.."@"..domain
|
||||
--create the api object
|
||||
api = freeswitch.API();
|
||||
local sofia_contact = trim(api:executeString("sofia_contact */"..account));
|
||||
--get all profiles for the user account
|
||||
local profile_iterator = string.gmatch(sofia_contact, "sofia/([^,]+)/[^,]+");
|
||||
|
||||
--remove any duplicates and check if we have any profiles
|
||||
local unique_profiles = {}
|
||||
local has_profile = false
|
||||
for profile in profile_iterator do
|
||||
has_profile = true
|
||||
unique_profiles[profile] = 1
|
||||
end
|
||||
|
||||
-- return nil if we have no profiles
|
||||
if not has_profile then return nil end
|
||||
|
||||
return unique_profiles
|
||||
end
|
||||
|
||||
|
||||
function feature_event_notify.dnd(user, host, sip_profiles, do_not_disturb)
|
||||
--set the event and send it to each profile
|
||||
for sip_profile, _ in pairs(sip_profiles) do
|
||||
local event = freeswitch.Event("SWITCH_EVENT_PHONE_FEATURE")
|
||||
event:addHeader("profile", sip_profile)
|
||||
event:addHeader("user", user)
|
||||
event:addHeader("host", host)
|
||||
event:addHeader("device", "")
|
||||
event:addHeader("Feature-Event", "DoNotDisturbEvent")
|
||||
event:addHeader("doNotDisturbOn", do_not_disturb)
|
||||
--freeswitch.consoleLog("notice","[events] " .. event:serialize("xml") .. "\n");
|
||||
freeswitch.msleep(300);
|
||||
event:fire()
|
||||
end
|
||||
end
|
||||
|
||||
function feature_event_notify.forward_immediate(user, host, sip_profiles, forward_immediate_enabled, forward_immediate_destination)
|
||||
--set the event and send it to each profile
|
||||
for sip_profile, _ in pairs(sip_profiles) do
|
||||
local event = freeswitch.Event("SWITCH_EVENT_PHONE_FEATURE")
|
||||
event:addHeader("profile", sip_profile)
|
||||
event:addHeader("user", user)
|
||||
event:addHeader("host", host)
|
||||
event:addHeader("device", "")
|
||||
event:addHeader("Feature-Event", "ForwardingEvent")
|
||||
event:addHeader("forward_immediate_enabled", forward_immediate_enabled)
|
||||
event:addHeader("forward_immediate", forward_immediate_destination);
|
||||
freeswitch.consoleLog("notice","[events] " .. event:serialize("xml") .. "\n");
|
||||
freeswitch.msleep(300);
|
||||
event:fire()
|
||||
end
|
||||
end
|
||||
|
||||
function feature_event_notify.forward_busy(user, host, sip_profiles, forward_busy_enabled, forward_busy_destination)
|
||||
--set the event and send it to each profile
|
||||
for sip_profile, _ in pairs(sip_profiles) do
|
||||
local event = freeswitch.Event("SWITCH_EVENT_PHONE_FEATURE")
|
||||
event:addHeader("profile", sip_profile)
|
||||
event:addHeader("user", user)
|
||||
event:addHeader("host", host)
|
||||
event:addHeader("device", "")
|
||||
event:addHeader("Feature-Event", "ForwardingEvent")
|
||||
event:addHeader("forward_busy", forward_busy_destination)
|
||||
event:addHeader("forward_busy_enabled", forward_busy_enabled)
|
||||
freeswitch.msleep(300);
|
||||
event:fire()
|
||||
end
|
||||
end
|
||||
|
||||
function feature_event_notify.forward_no_answer(user, host, sip_profiles, forward_no_answer_enabled, forward_no_answer_destination, ring_count)
|
||||
--set the event and send it to each profile
|
||||
for sip_profile, _ in pairs(sip_profiles) do
|
||||
local event = freeswitch.Event("SWITCH_EVENT_PHONE_FEATURE")
|
||||
event:addHeader("profile", sip_profile)
|
||||
event:addHeader("user", user)
|
||||
event:addHeader("host", host)
|
||||
event:addHeader("device", "")
|
||||
event:addHeader("Feature-Event", "ForwardingEvent")
|
||||
event:addHeader("forward_no_answer", forward_no_answer_destination)
|
||||
event:addHeader("forward_no_answer_enabled", forward_no_answer_enabled)
|
||||
event:addHeader("ringCount", ring_count)
|
||||
freeswitch.msleep(300);
|
||||
event:fire()
|
||||
end
|
||||
end
|
||||
|
||||
function feature_event_notify.init(user, host, sip_profiles, forward_immediate_enabled, forward_immediate_destination, forward_busy_enabled, forward_busy_destination, forward_no_answer_enabled, forward_no_answer_destination, ring_count, do_not_disturb)
|
||||
--set the event and send it to each profile
|
||||
for sip_profile, _ in pairs(sip_profiles) do
|
||||
local event = freeswitch.Event("SWITCH_EVENT_PHONE_FEATURE")
|
||||
event:addHeader("profile", sip_profile)
|
||||
event:addHeader("user", user)
|
||||
event:addHeader("host", host)
|
||||
event:addHeader("device", "")
|
||||
event:addHeader("Feature-Event", "init")
|
||||
event:addHeader("forward_immediate_enabled", forward_immediate_enabled)
|
||||
event:addHeader("forward_immediate", forward_immediate_destination);
|
||||
event:addHeader("forward_busy", forward_busy_destination)
|
||||
event:addHeader("forward_busy_enabled", forward_busy_enabled)
|
||||
event:addHeader("Feature-Event", "ForwardingEvent")
|
||||
event:addHeader("forward_no_answer", forward_no_answer_destination)
|
||||
event:addHeader("forward_no_answer_enabled", forward_no_answer_enabled)
|
||||
event:addHeader("ringCount", ring_count)
|
||||
event:addHeader("Feature-Event", "DoNotDisturbEvent")
|
||||
event:addHeader("doNotDisturbOn", do_not_disturb)
|
||||
freeswitch.msleep(300);
|
||||
event:fire()
|
||||
end
|
||||
end
|
||||
|
||||
return feature_event_notify
|
||||
@@ -0,0 +1,567 @@
|
||||
-- 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 - 2020
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
|
||||
--includes
|
||||
local Database = require "resources.functions.database";
|
||||
local route_to_bridge = require "resources.functions.route_to_bridge"
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
require "resources.functions.trim";
|
||||
require 'resources.functions.send_mail';
|
||||
|
||||
--get the variables
|
||||
if (session:ready()) then
|
||||
domain_name = session:getVariable("domain_name");
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
uuid = session:getVariable("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");
|
||||
missed_call_app = session:getVariable("missed_call_app");
|
||||
missed_call_data = session:getVariable("missed_call_data");
|
||||
sip_to_user = session:getVariable("sip_to_user");
|
||||
dialed_user = session:getVariable("dialed_user") or '';
|
||||
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
|
||||
|
||||
--connect to the database
|
||||
local dbh = Database.new('system');
|
||||
|
||||
--set the strategy
|
||||
local settings = Settings.new(dbh, domain_name, domain_uuid);
|
||||
local follow_me_strategy = settings:get('follow_me', 'strategy', 'text') or 'enterprise'; --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();
|
||||
|
||||
--check the missed calls
|
||||
function missed()
|
||||
if (missed_call_app ~= nil and missed_call_data ~= nil) then
|
||||
if (missed_call_app == "email") then
|
||||
--set the sounds path for the language, dialect and voice
|
||||
default_language = session:getVariable("default_language");
|
||||
default_dialect = session:getVariable("default_dialect");
|
||||
default_voice = session:getVariable("default_voice");
|
||||
if (not default_language) then default_language = 'en'; end
|
||||
if (not default_dialect) then default_dialect = 'us'; end
|
||||
if (not default_voice) then default_voice = 'callie'; end
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
local dbh = Database.new('system');
|
||||
|
||||
--get the templates
|
||||
local sql = "SELECT * FROM v_email_templates ";
|
||||
sql = sql .. "WHERE (domain_uuid = :domain_uuid or domain_uuid is null) ";
|
||||
sql = sql .. "AND template_language = :template_language ";
|
||||
sql = sql .. "AND template_category = 'missed' "
|
||||
sql = sql .. "AND template_enabled = 'true' "
|
||||
sql = sql .. "ORDER BY domain_uuid DESC "
|
||||
local params = {domain_uuid = domain_uuid, template_language = default_language.."-"..default_dialect};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
subject = row["template_subject"];
|
||||
body = row["template_body"];
|
||||
end);
|
||||
|
||||
--prepare the headers
|
||||
local headers = {}
|
||||
headers["X-FusionPBX-Domain-UUID"] = domain_uuid;
|
||||
headers["X-FusionPBX-Domain-Name"] = domain_name;
|
||||
headers["X-FusionPBX-Call-UUID"] = uuid;
|
||||
headers["X-FusionPBX-Email-Type"] = 'missed';
|
||||
|
||||
--prepare the subject
|
||||
subject = subject:gsub("${caller_id_name}", caller_id_name);
|
||||
subject = subject:gsub("${caller_id_number}", caller_id_number);
|
||||
subject = subject:gsub("${sip_to_user}", sip_to_user);
|
||||
subject = subject:gsub("${dialed_user}", dialed_user);
|
||||
subject = trim(subject);
|
||||
subject = '=?utf-8?B?'..base64.encode(subject)..'?=';
|
||||
|
||||
--prepare the body
|
||||
body = body:gsub("${caller_id_name}", caller_id_name);
|
||||
body = body:gsub("${caller_id_number}", caller_id_number);
|
||||
body = body:gsub("${sip_to_user}", sip_to_user);
|
||||
body = body:gsub("${dialed_user}", dialed_user);
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("%s+", "");
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("\n", "");
|
||||
body = body:gsub("\n", "");
|
||||
body = body:gsub("'", "'");
|
||||
body = body:gsub([["]], """);
|
||||
body = trim(body);
|
||||
|
||||
--send the emails
|
||||
send_mail(headers,
|
||||
missed_call_data,
|
||||
{subject, body}
|
||||
);
|
||||
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[missed call] " .. caller_id_number .. "->" .. sip_to_user .. "emailed to " .. missed_call_data .. "\n");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--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 extensions accountcode
|
||||
cmd = "user_data ".. destination_number .."@" ..domain_name.." var accountcode";
|
||||
accountcode = api:executeString(cmd);
|
||||
|
||||
--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, toll_allow, accountcode = get_forward_all(count, destination_number, domain_name);
|
||||
end
|
||||
end
|
||||
end
|
||||
return count, destination_number, toll_allow, accountcode;
|
||||
end
|
||||
|
||||
--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));
|
||||
|
||||
--get the domain_uuid
|
||||
if (domain_uuid == nil) then
|
||||
if (domain_name ~= nil) then
|
||||
local sql = "SELECT domain_uuid FROM v_domains "
|
||||
.. "WHERE domain_name = :domain_name ";
|
||||
local params = {domain_name = domain_name};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(rows)
|
||||
domain_uuid = rows["domain_uuid"];
|
||||
end);
|
||||
end
|
||||
end
|
||||
|
||||
--select data from the database
|
||||
local sql = "select follow_me_uuid, toll_allow, accountcode ";
|
||||
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"];
|
||||
accountcode = row["accountcode"];
|
||||
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_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_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 * 1000 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, accountcode = 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";
|
||||
if (accountcode ~= nil) then
|
||||
row['accountcode'] = accountcode;
|
||||
else
|
||||
row['accountcode'] = domain_name;
|
||||
end
|
||||
--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;
|
||||
accountcode = row.accountcode;
|
||||
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));
|
||||
|
||||
local record_session = "";
|
||||
--if session is already recording then skip
|
||||
if (session:getVariable("record_session") ~= "true") then
|
||||
local cmd = "user_data "..destination_number.."@"..domain_name.." var user_record";
|
||||
local user_record = api:executeString(cmd);
|
||||
if (user_record == "all" or user_record == call_direction) then
|
||||
local recordings_dir = session:getVariable("recordings_dir");
|
||||
local record_ext = session:getVariable("record_ext") or "wav";
|
||||
local record_name = uuid.."."..record_ext;
|
||||
local record_path = recordings_dir .. "/" .. domain_name .. "/archive/" .. os.date("%Y/%b/%d");
|
||||
record_session = ",api_on_answer='uuid_record "..uuid.." start ".. record_path .. "/" .. record_name .. "',record_path='".. record_path .."',record_name="..record_name;
|
||||
end
|
||||
end
|
||||
|
||||
--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..record_session.."]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
|
||||
|
||||
--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
|
||||
ignore_outbound_caller_id = session:getVariable("follow_me_ignore_outbound_caller_id");
|
||||
if (session:ready() and caller_is_local and ignore_outbound_caller_id ~= "true") 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
|
||||
-- have to double destination_delay here due a FS bug requiring a 50% delay value for internal extensions, but not external calls.
|
||||
--destination_delay = destination_delay * 2;
|
||||
dial_string = "[toll_allow=".. toll_allow ..",accountcode="..accountcode..",".. caller_id ..",sip_invite_domain="..domain_name..",domain_uuid="..domain_uuid..",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: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
|
||||
if session:ready() 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
|
||||
end
|
||||
|
||||
--check and report missed call
|
||||
missed();
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,164 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2015 - 2018
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
|
||||
--set the debug options
|
||||
debug["params"] = false;
|
||||
debug["info"] = false;
|
||||
debug["sql"] = false;
|
||||
|
||||
--general functions
|
||||
require "resources.functions.config";
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.base64";
|
||||
require "resources.functions.file_exists";
|
||||
|
||||
--load libraries
|
||||
require 'resources.functions.send_mail'
|
||||
|
||||
--create the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--check the missed calls
|
||||
function missed()
|
||||
if (missed_call_app ~= nil and missed_call_data ~= nil) then
|
||||
if (missed_call_app == "email") then
|
||||
--set the sounds path for the language, dialect and voice
|
||||
default_language = env:getHeader("default_language");
|
||||
default_dialect = env:getHeader("default_dialect");
|
||||
default_voice = env:getHeader("default_voice");
|
||||
if (not default_language) then default_language = 'en'; end
|
||||
if (not default_dialect) then default_dialect = 'us'; end
|
||||
if (not default_voice) then default_voice = 'callie'; end
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
local dbh = Database.new('system');
|
||||
|
||||
--prepare to get the settings
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
local settings = Settings.new(dbh, domain_name, domain_uuid)
|
||||
local from_address = settings:get('email', 'smtp_from', 'text');
|
||||
|
||||
--get the templates
|
||||
local sql = "SELECT * FROM v_email_templates ";
|
||||
sql = sql .. "WHERE (domain_uuid = :domain_uuid or domain_uuid is null) ";
|
||||
sql = sql .. "AND template_language = :template_language ";
|
||||
sql = sql .. "AND template_category = 'missed' "
|
||||
sql = sql .. "AND template_enabled = 'true' "
|
||||
sql = sql .. "ORDER BY domain_uuid DESC "
|
||||
local params = {domain_uuid = domain_uuid, template_language = default_language.."-"..default_dialect};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
subject = row["template_subject"];
|
||||
body = row["template_body"];
|
||||
end);
|
||||
|
||||
--prepare the headers
|
||||
local headers = {}
|
||||
headers["X-FusionPBX-Domain-UUID"] = domain_uuid;
|
||||
headers["X-FusionPBX-Domain-Name"] = domain_name;
|
||||
headers["X-FusionPBX-Call-UUID"] = uuid;
|
||||
headers["X-FusionPBX-Email-Type"] = 'missed';
|
||||
|
||||
--remove quotes from caller id name and number
|
||||
caller_id_name = caller_id_name:gsub("'", "'");
|
||||
caller_id_name = caller_id_name:gsub([["]], """);
|
||||
caller_id_number = caller_id_number:gsub("'", "'");
|
||||
caller_id_number = caller_id_number:gsub([["]], """);
|
||||
|
||||
--prepare the subject
|
||||
subject = subject:gsub("${caller_id_name}", caller_id_name);
|
||||
subject = subject:gsub("${caller_id_number}", caller_id_number);
|
||||
subject = subject:gsub("${sip_to_user}", sip_to_user);
|
||||
subject = subject:gsub("${dialed_user}", dialed_user);
|
||||
subject = trim(subject);
|
||||
subject = '=?utf-8?B?'..base64.encode(subject)..'?=';
|
||||
|
||||
--prepare the body
|
||||
body = body:gsub("${caller_id_name}", caller_id_name);
|
||||
body = body:gsub("${caller_id_number}", caller_id_number);
|
||||
body = body:gsub("${sip_to_user}", sip_to_user);
|
||||
body = body:gsub("${dialed_user}", dialed_user);
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("%s+", "");
|
||||
body = body:gsub(" ", " ");
|
||||
body = body:gsub("\n", "");
|
||||
body = body:gsub("\n", "");
|
||||
body = trim(body);
|
||||
|
||||
--send the emails
|
||||
send_mail(headers,
|
||||
from_address,
|
||||
missed_call_data,
|
||||
{subject, body}
|
||||
);
|
||||
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[missed call] " .. caller_id_name .. " " .. caller_id_number .. " " .. sip_to_user .. "emailed to " .. missed_call_data .. "\n");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- show all channel variables
|
||||
--serialized = env:serialize()
|
||||
--freeswitch.consoleLog("INFO","[hangup]\n" .. serialized .. "\n")
|
||||
|
||||
-- set channel variables to lua variables
|
||||
originate_disposition = env:getHeader("originate_disposition");
|
||||
originate_causes = env:getHeader("originate_causes");
|
||||
uuid = env:getHeader("uuid");
|
||||
domain_uuid = env:getHeader("domain_uuid");
|
||||
domain_name = env:getHeader("domain_name");
|
||||
sip_to_user = env:getHeader("sip_to_user");
|
||||
dialed_user = env:getHeader("dialed_user");
|
||||
missed_call_app = env:getHeader("missed_call_app");
|
||||
missed_call_data = env:getHeader("missed_call_data");
|
||||
call_direction = env:getHeader("call_direction");
|
||||
|
||||
-- get the Caller ID
|
||||
caller_id_name = env:getHeader("caller_id_name");
|
||||
caller_id_number = env:getHeader("caller_id_number");
|
||||
if (caller_id_name == nil) then
|
||||
caller_id_name = env:getHeader("Caller-Caller-ID-Name");
|
||||
end
|
||||
if (caller_id_number == nil) then
|
||||
caller_id_number = env:getHeader("Caller-Caller-ID-Number");
|
||||
end
|
||||
if (call_direction == "local") then
|
||||
caller_id_name = env:getHeader("effective_caller_id_name");
|
||||
end
|
||||
|
||||
--show the logs
|
||||
if (debug["info"] == true) then
|
||||
freeswitch.consoleLog("INFO", "[hangup] originate_causes: " .. tostring(originate_causes) .. "\n");
|
||||
freeswitch.consoleLog("INFO", "[hangup] originate_disposition: " .. tostring(originate_disposition) .. "\n");
|
||||
end
|
||||
|
||||
--handle originate disposition
|
||||
if (originate_disposition ~= nil) then
|
||||
if (originate_disposition == "ORIGINATOR_CANCEL") then
|
||||
missed();
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,140 @@
|
||||
-- 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) 2014-2020
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
|
||||
|
||||
--set defaults
|
||||
expire = {}
|
||||
expire["is_local"] = "3600";
|
||||
|
||||
--get the variables
|
||||
domain_name = session:getVariable("domain_name");
|
||||
destination_number = session:getVariable("destination_number");
|
||||
outbound_caller_id_name = session:getVariable("outbound_caller_id_name");
|
||||
outbound_caller_id_number = session:getVariable("outbound_caller_id_number");
|
||||
|
||||
--includes
|
||||
local cache = require "resources.functions.cache"
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--define the trim function
|
||||
require "resources.functions.trim";
|
||||
|
||||
--set the cache key
|
||||
key = "app:dialplan:outbound:is_local:" .. destination_number .. "@" .. domain_name;
|
||||
|
||||
--get the destination number
|
||||
value, err = cache.get(key);
|
||||
if (err == 'NOT FOUND') then
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
local dbh = Database.new('system');
|
||||
|
||||
--select data from the database
|
||||
local sql = "SELECT destination_number, destination_context ";
|
||||
sql = sql .. "FROM v_destinations ";
|
||||
sql = sql .. "WHERE ( ";
|
||||
sql = sql .. " destination_prefix || destination_area_code || destination_number = :destination_number ";
|
||||
sql = sql .. " OR destination_trunk_prefix || destination_area_code || destination_number = :destination_number ";
|
||||
sql = sql .. " OR destination_prefix || destination_number = :destination_number ";
|
||||
sql = sql .. " OR '+' || destination_prefix || destination_number = :destination_number ";
|
||||
sql = sql .. " OR '+' || destination_prefix || destination_area_code || destination_number = :destination_number ";
|
||||
sql = sql .. " OR destination_area_code || destination_number = :destination_number ";
|
||||
sql = sql .. " OR destination_number = :destination_number ";
|
||||
sql = sql .. ") ";
|
||||
sql = sql .. "AND destination_type = 'inbound' ";
|
||||
sql = sql .. "AND destination_enabled = 'true' ";
|
||||
local params = {destination_number = destination_number};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "SQL:" .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
|
||||
--set the local variables
|
||||
destination_context = row.destination_context;
|
||||
|
||||
--set the cache
|
||||
if (destination_number == row.destination_number) then
|
||||
key = "app:dialplan:outbound:is_local:" .. destination_number .. "@" .. domain_name;
|
||||
value = "destination_number=" .. row.destination_number .. "&destination_context=" .. destination_context;
|
||||
ok, err = cache.set(key, value, expire["is_local"]);
|
||||
else
|
||||
key = "app:dialplan:outbound:is_local:" .. destination_number .. "@" .. domain_name;
|
||||
value = "destination_number=" .. row.destination_number .. "&destination_context=" .. destination_context;
|
||||
ok, err = cache.set(key, value, expire["is_local"]);
|
||||
end
|
||||
|
||||
--log the result
|
||||
freeswitch.consoleLog("notice", "[app:dialplan:outbound:is_local] " .. row.destination_number .. " XML " .. destination_context .. " source: database\n");
|
||||
|
||||
--set the outbound caller id
|
||||
if (outbound_caller_id_name ~= nil) then
|
||||
session:execute("set", "caller_id_name="..outbound_caller_id_name);
|
||||
session:execute("set", "effective_caller_id_name="..outbound_caller_id_name);
|
||||
end
|
||||
if (outbound_caller_id_number ~= nil) then
|
||||
session:execute("set", "caller_id_number="..outbound_caller_id_number);
|
||||
session:execute("set", "effective_caller_id_number="..outbound_caller_id_number);
|
||||
end
|
||||
|
||||
--transfer the call
|
||||
session:transfer(row.destination_number, "XML", row.destination_context);
|
||||
end);
|
||||
|
||||
else
|
||||
--add the function
|
||||
require "resources.functions.explode";
|
||||
|
||||
--define the array/table
|
||||
local var = {}
|
||||
|
||||
--parse the cache
|
||||
key_pairs = explode("&", value);
|
||||
for k,v in pairs(key_pairs) do
|
||||
f = explode("=", v);
|
||||
key = f[1];
|
||||
value = f[2];
|
||||
var[key] = value;
|
||||
end
|
||||
|
||||
--set the outbound caller id
|
||||
if (outbound_caller_id_name ~= nil) then
|
||||
session:execute("set", "caller_id_name="..outbound_caller_id_name);
|
||||
session:execute("set", "effective_caller_id_name="..outbound_caller_id_name);
|
||||
end
|
||||
if (outbound_caller_id_number ~= nil) then
|
||||
session:execute("set", "caller_id_number="..outbound_caller_id_number);
|
||||
session:execute("set", "effective_caller_id_number="..outbound_caller_id_number);
|
||||
end
|
||||
|
||||
--send to the console
|
||||
freeswitch.consoleLog("notice", "[app:dialplan:outbound:is_local] " .. value .. " source: cache\n");
|
||||
|
||||
--transfer the call
|
||||
session:transfer(var["destination_number"], "XML", var["destination_context"]);
|
||||
end
|
||||
@@ -0,0 +1 @@
|
||||
Missed Call from ${caller_id_name} <${caller_id_number}> to ${sip_to_user} ext ${dialed_user}
|
||||
+1
@@ -0,0 +1 @@
|
||||
Missed Call from ${caller_id_name} <${caller_id_number}>
|
||||
@@ -0,0 +1,256 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2015-2018 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--set the debug options
|
||||
debug["sql"] = false;
|
||||
|
||||
--define the explode function
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.trim";
|
||||
|
||||
--set the defaults
|
||||
max_tries = 3;
|
||||
digit_timeout = 5000;
|
||||
max_retries = 3;
|
||||
tries = 0;
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--answer
|
||||
session:answer();
|
||||
|
||||
--sleep
|
||||
session:sleep(500);
|
||||
|
||||
--get the domain_uuid
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
|
||||
--get the variables
|
||||
action = session:getVariable("action");
|
||||
reboot = session:getVariable("reboot");
|
||||
|
||||
--set defaults
|
||||
if (not reboot) then reboot = 'true'; end
|
||||
|
||||
--set the sounds path for the language, dialect and voice
|
||||
default_language = session:getVariable("default_language");
|
||||
default_dialect = session:getVariable("default_dialect");
|
||||
default_voice = session:getVariable("default_voice");
|
||||
if (not default_language) then default_language = 'en'; end
|
||||
if (not default_dialect) then default_dialect = 'us'; end
|
||||
if (not default_voice) then default_voice = 'callie'; end
|
||||
|
||||
--get the user id
|
||||
min_digits = 2;
|
||||
max_digits = 20;
|
||||
user_id = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_id:#", "", "\\d+");
|
||||
--user_id = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-please_enter_extension_followed_by_pound.wav", "", "\\d+");
|
||||
|
||||
--get the user password
|
||||
min_digits = 2;
|
||||
max_digits = 20;
|
||||
password = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_pass:#", "", "\\d+");
|
||||
--password = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-please_enter_pin_followed_by_pound.wav", "", "\\d+");
|
||||
|
||||
--get the user and domain name from the user argv user@domain
|
||||
sip_from_uri = session:getVariable("sip_from_uri");
|
||||
user_table = explode("@",sip_from_uri);
|
||||
domain_table = explode(":",user_table[2]);
|
||||
user = user_table[1];
|
||||
domain = domain_table[1];
|
||||
|
||||
--show the phone that will be overridden
|
||||
if (sip_from_uri ~= nil) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] sip_from_uri: ".. sip_from_uri .. "\n");
|
||||
end
|
||||
if (user ~= nil) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] user: ".. user .. "\n");
|
||||
end
|
||||
if (domain ~= nil) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] domain: ".. domain .. "\n");
|
||||
end
|
||||
|
||||
--get the device uuid for the phone that will have its configuration overridden
|
||||
if (user ~= nil and domain ~= nil and domain_uuid ~= nil) then
|
||||
local sql = [[SELECT device_uuid FROM v_device_lines ]];
|
||||
sql = sql .. [[WHERE user_id = :user ]];
|
||||
sql = sql .. [[AND server_address = :domain ]];
|
||||
sql = sql .. [[AND domain_uuid = :domain_uuid ]];
|
||||
local params = {user = user, domain = domain, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] SQL: ".. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--get device uuid
|
||||
device_uuid = row.device_uuid;
|
||||
freeswitch.consoleLog("NOTICE", "[provision] device_uuid: ".. device_uuid .. "\n");
|
||||
end);
|
||||
end
|
||||
|
||||
--get the alternate device uuid using the device username and password
|
||||
authorized = 'false';
|
||||
if (user_id ~= nil and password ~= nil and domain_uuid ~= nil) then
|
||||
local sql = [[SELECT device_uuid FROM v_devices ]];
|
||||
sql = sql .. [[WHERE device_username = :user_id ]];
|
||||
sql = sql .. [[AND device_password = :password ]]
|
||||
sql = sql .. [[AND domain_uuid = :domain_uuid ]];
|
||||
local params = {user_id = user_id, password = password, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] SQL: ".. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--get the alternate device_uuid
|
||||
device_uuid_alternate = row.device_uuid;
|
||||
freeswitch.consoleLog("NOTICE", "[provision] alternate device_uuid: ".. device_uuid_alternate .. "\n");
|
||||
--authorize the user
|
||||
authorized = 'true';
|
||||
end);
|
||||
end
|
||||
|
||||
--authentication failed
|
||||
if (authorized == 'false') then
|
||||
result = session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-fail_auth.wav");
|
||||
end
|
||||
|
||||
--this device already has an alternate find the correct device_uuid and then override current one
|
||||
if (authorized == 'true' and action == "login" and device_uuid_alternate ~= nil and device_uuid ~= nil and domain_uuid ~= nil) then
|
||||
local sql = [[SELECT * FROM v_devices ]];
|
||||
sql = sql .. [[WHERE device_uuid_alternate = :device_uuid ]];
|
||||
sql = sql .. [[AND domain_uuid = :domain_uuid ]];
|
||||
local params = {device_uuid = device_uuid, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] SQL: ".. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
if (row.device_uuid_alternate ~= nil) then
|
||||
device_uuid = row.device_uuid;
|
||||
end
|
||||
end);
|
||||
end
|
||||
|
||||
--remove the alternate device from another device so that it can be added to this device
|
||||
if (authorized == 'true' and action == "login" and device_uuid_alternate ~= nil and domain_uuid ~= nil) then
|
||||
local sql = [[SELECT * FROM v_device_lines ]];
|
||||
sql = sql .. [[WHERE device_uuid = :device_uuid ]];
|
||||
sql = sql .. [[AND domain_uuid = :domain_uuid ]];
|
||||
local params = {device_uuid = device_uuid_alternate, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] SQL: ".. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--remove the previous alternate device uuid
|
||||
local sql = [[UPDATE v_devices SET device_uuid_alternate = null ]];
|
||||
sql = sql .. [[WHERE device_uuid_alternate = :device_uuid_alternate ]];
|
||||
sql = sql .. [[AND domain_uuid = :domain_uuid ]];
|
||||
local params = {device_uuid_alternate = device_uuid_alternate, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] SQL: ".. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
--get the sip profile
|
||||
api = freeswitch.API();
|
||||
local sofia_contact = trim(api:executeString("sofia_contact */"..row.user_id.."@"..row.server_address));
|
||||
array = explode("/", sofia_contact);
|
||||
profile = array[2];
|
||||
freeswitch.consoleLog("NOTICE", "[provision] profile: ".. profile .. "\n");
|
||||
--send a sync command to the previous device
|
||||
--create the event notify object
|
||||
local event = freeswitch.Event('NOTIFY');
|
||||
--add the headers
|
||||
event:addHeader('profile', profile);
|
||||
event:addHeader('user', row.user_id);
|
||||
event:addHeader('host', row.server_address);
|
||||
event:addHeader('content-type', 'application/simple-message-summary');
|
||||
--check sync
|
||||
event:addHeader('event-string', 'check-sync;reboot='..reboot);
|
||||
--event:addHeader('event-string', 'resync');
|
||||
--send the event
|
||||
event:fire();
|
||||
end);
|
||||
end
|
||||
|
||||
--add the override to the device uuid (login)
|
||||
if (authorized == 'true' and action == "login") then
|
||||
if (device_uuid_alternate ~= nil and device_uuid ~= nil and domain_uuid ~= nil) then
|
||||
--send a hangup
|
||||
session:hangup();
|
||||
--add the new alternate
|
||||
local sql = [[UPDATE v_devices SET device_uuid_alternate = :device_uuid_alternate ]];
|
||||
sql = sql .. [[WHERE device_uuid = :device_uuid ]];
|
||||
sql = sql .. [[AND domain_uuid = :domain_uuid ]];
|
||||
local params = {device_uuid_alternate = device_uuid_alternate,
|
||||
device_uuid = device_uuid, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] SQL: ".. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
end
|
||||
|
||||
--remove the override to the device uuid (logout)
|
||||
if (authorized == 'true' and action == "logout") then
|
||||
if (device_uuid_alternate ~= nil and device_uuid ~= nil and domain_uuid ~= nil) then
|
||||
local sql = [[UPDATE v_devices SET device_uuid_alternate = null ]];
|
||||
sql = sql .. [[WHERE device_uuid_alternate = :device_uuid ]];
|
||||
sql = sql .. [[AND domain_uuid = :domain_uuid ]];
|
||||
local params = {device_uuid = device_uuid, domain_uuid = domain_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("NOTICE", "[provision] sql: ".. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
end
|
||||
|
||||
--found the device send a sync command
|
||||
if (authorized == 'true') then
|
||||
--get the sip profile
|
||||
api = freeswitch.API();
|
||||
local sofia_contact = trim(api:executeString("sofia_contact */"..user.."@"..domain));
|
||||
array = explode("/", sofia_contact);
|
||||
profile = array[2];
|
||||
freeswitch.consoleLog("NOTICE", "[provision] profile: ".. profile .. "\n");
|
||||
--send a hangup
|
||||
session:hangup();
|
||||
--create the event notify object
|
||||
local event = freeswitch.Event('NOTIFY');
|
||||
--add the headers
|
||||
event:addHeader('profile', profile);
|
||||
event:addHeader('user', user);
|
||||
event:addHeader('host', domain);
|
||||
event:addHeader('content-type', 'application/simple-message-summary');
|
||||
--check sync
|
||||
event:addHeader('event-string', 'check-sync;reboot='..reboot);
|
||||
--event:addHeader('event-string', 'resync');
|
||||
--send the event
|
||||
event:fire();
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,199 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2010-2021
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
|
||||
--set default variables
|
||||
local min_digits = 3;
|
||||
local max_digits = 11;
|
||||
local max_tries = 3;
|
||||
local digit_timeout = 3000;
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
|
||||
--include libraries
|
||||
require "resources.functions.channel_utils";
|
||||
local log = require "resources.functions.log".ring_group_call_forward
|
||||
local Database = require "resources.functions.database"
|
||||
local blf = require "resources.functions.blf"
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
local function empty(t)
|
||||
return (not t) or (#t == 0)
|
||||
end
|
||||
|
||||
--check if the session is ready
|
||||
if not session:ready() then return end
|
||||
|
||||
--answer the call
|
||||
session:answer();
|
||||
|
||||
--get the variables
|
||||
local enabled = session:getVariable("enabled");
|
||||
local pin_number = session:getVariable("pin_number");
|
||||
local sounds_dir = session:getVariable("sounds_dir");
|
||||
local domain_uuid = session:getVariable("domain_uuid");
|
||||
local domain_name = session:getVariable("domain_name");
|
||||
local ring_group_number = session:getVariable("ring_group_number");
|
||||
local ring_group_uuid = session:getVariable("ring_group_uuid");
|
||||
local forward_destination = session:getVariable("forward_destination");
|
||||
local forward_reset = session:getVariable("forward_reset");
|
||||
|
||||
--set the sounds path for the language, dialect and voice
|
||||
local default_language = session:getVariable("default_language") or 'en';
|
||||
local default_dialect = session:getVariable("default_dialect") or 'us';
|
||||
local default_voice = session:getVariable("default_voice") or 'callie';
|
||||
|
||||
--a moment to sleep
|
||||
session:sleep(1000);
|
||||
|
||||
--connect to the database
|
||||
local dbh = Database.new('system');
|
||||
|
||||
--check pin code
|
||||
if not empty(pin_number) then
|
||||
--get the pin number
|
||||
local min_digits = 3;
|
||||
local max_digits = 20;
|
||||
local caller_pin_number = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_pass:#", "", "\\d+");
|
||||
if empty(caller_pin_number) then return end
|
||||
|
||||
--check pin number
|
||||
if pin_number ~= caller_pin_number then return end
|
||||
|
||||
--user hangup
|
||||
if not session:ready() then return end
|
||||
end
|
||||
|
||||
--get ring group number
|
||||
if empty(ring_group_number) then
|
||||
--get the ring group extension number
|
||||
local min_digits = 2;
|
||||
local max_digits = 20;
|
||||
ring_group_number = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_id:#", "", "\\d+");
|
||||
if empty(ring_group_number) then return end
|
||||
|
||||
-- user hangup
|
||||
if not session:ready() then return end
|
||||
end
|
||||
|
||||
--user hangup
|
||||
if not session:ready() then return end
|
||||
|
||||
--search ring_group in database
|
||||
local sql = [[SELECT ring_group_uuid as uuid, ring_group_forward_enabled as forward_enabled,
|
||||
ring_group_forward_destination as forward_destination, ring_group_extension as extension
|
||||
FROM v_ring_groups
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
]]
|
||||
local params = {domain_uuid = domain_uuid}
|
||||
if (not empty(ring_group_number) or empty(ring_group_uuid)) then
|
||||
sql = sql .. " AND ring_group_extension=:extension"
|
||||
params.extension = ring_group_number
|
||||
else
|
||||
sql = sql .. " AND ring_group_uuid=:ring_group_uuid"
|
||||
params.ring_group_uuid = ring_group_uuid
|
||||
end
|
||||
if (debug["sql"]) then
|
||||
log.noticef("SQL: %s; params: %s", sql, json.encode(params));
|
||||
end
|
||||
local ring_group = dbh:first_row(sql, params)
|
||||
|
||||
--if can not find ring group
|
||||
if (not ring_group) or (not ring_group.uuid) then return end
|
||||
|
||||
-- user hangup
|
||||
if not session:ready() then return end
|
||||
|
||||
-- get destination number from the database if it not provided
|
||||
if enabled == 'toggle' and empty(forward_destination) then
|
||||
forward_destination = ring_group.forward_destination
|
||||
end
|
||||
|
||||
--toggle enabled
|
||||
if enabled == 'toggle' then
|
||||
-- if we toggle CF and specify new destination number then just enable it
|
||||
if forward_destination == ring_group.forward_destination then
|
||||
enabled = (ring_group.forward_enabled == 'true') and 'false' or 'true'
|
||||
else
|
||||
enabled = 'true'
|
||||
end
|
||||
end
|
||||
|
||||
--get the forward destination
|
||||
if enabled == 'true' and empty(forward_destination) then
|
||||
-- get number
|
||||
forward_destination = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-enter_destination_telephone_number.wav", "", "\\d+");
|
||||
if empty(forward_destination) then return end
|
||||
-- user hangup
|
||||
if not session:ready() then return end
|
||||
end
|
||||
|
||||
--set the values based on conditions
|
||||
forward_enabled = (enabled == 'true') and 'true' or 'false';
|
||||
if (forward_enabled == 'false' and forward_reset == 'true') then
|
||||
forward_destination = '';
|
||||
end
|
||||
|
||||
--update ring group call farward in database
|
||||
local sql = [[UPDATE v_ring_groups
|
||||
SET
|
||||
ring_group_forward_enabled = :forward_enabled,
|
||||
ring_group_forward_destination = :forward_destination
|
||||
WHERE
|
||||
ring_group_uuid = :ring_group_uuid]]
|
||||
local params = {
|
||||
forward_enabled = forward_enabled,
|
||||
forward_destination = forward_destination,
|
||||
ring_group_uuid = ring_group.uuid,
|
||||
}
|
||||
if (debug["sql"]) then
|
||||
log.noticef("SQL: %s; params: %s", sql, json.encode(params));
|
||||
end
|
||||
dbh:query(sql, params)
|
||||
|
||||
--disconnect from database
|
||||
dbh:release()
|
||||
|
||||
--notify caller
|
||||
if enabled == 'true' then
|
||||
--set forward_all_enabled
|
||||
channel_display(session:get_uuid(), "Activated")
|
||||
--say the destination number
|
||||
session:say(forward_destination, default_language, "number", "iterated");
|
||||
--notify the caller
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-call_forwarding_has_been_set.wav");
|
||||
else
|
||||
--set forward_all_enabled
|
||||
channel_display(session:get_uuid(), "Cancelled")
|
||||
--notify the caller
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-call_forwarding_has_been_cancelled.wav");
|
||||
end
|
||||
|
||||
-- BLF for display CF status
|
||||
blf.forward(enabled == 'true', ring_group.extension, nil, ring_group.forward_destination, forward_destination, domain_name)
|
||||
@@ -0,0 +1,136 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2010-2013
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
|
||||
--set variables
|
||||
max_tries = "3";
|
||||
digit_timeout = "5000";
|
||||
|
||||
--define the trim function
|
||||
require "resources.functions.trim";
|
||||
|
||||
--define the explode function
|
||||
require "resources.functions.explode";
|
||||
|
||||
--get the argv values
|
||||
script_name = argv[0];
|
||||
argv_uuid = argv[1];
|
||||
prompt = argv[2];
|
||||
|
||||
--prepare the api
|
||||
api = freeswitch.API();
|
||||
|
||||
--answer the call
|
||||
session:answer();
|
||||
|
||||
--get the variables
|
||||
context = session:getVariable("context");
|
||||
sounds_dir = session:getVariable("sounds_dir");
|
||||
destination_number = session:getVariable("destination_number");
|
||||
uuid = session:getVariable("uuid");
|
||||
|
||||
--set the sounds path for the language, dialect and voice
|
||||
default_language = session:getVariable("default_language");
|
||||
default_dialect = session:getVariable("default_dialect");
|
||||
default_voice = session:getVariable("default_voice");
|
||||
if (not default_language) then default_language = 'en'; end
|
||||
if (not default_dialect) then default_dialect = 'us'; end
|
||||
if (not default_voice) then default_voice = 'callie'; end
|
||||
|
||||
--if an extension answer the call
|
||||
-- user_exists id 1005 voip.fusionpbx.com
|
||||
-- cmd = "user_exists id ".. destination_number .." "..context;
|
||||
-- result = api:executeString(cmd);
|
||||
-- freeswitch.consoleLog("NOTICE", "[confirm] "..cmd.." --"..result.."--\n");
|
||||
-- if (result == "true") then
|
||||
-- prompt = false;
|
||||
-- end
|
||||
|
||||
--prompt for digits
|
||||
if (prompt == "true") then
|
||||
--get the digit
|
||||
min_digits = 1;
|
||||
max_digits = 1;
|
||||
|
||||
--check if the original call exists
|
||||
cmd = "uuid_exists "..argv_uuid;
|
||||
if (trim(api:executeString(cmd)) == "false") then
|
||||
session:hangup("NO_ANSWER");
|
||||
end
|
||||
|
||||
--digit = session:playAndGetDigits(2, 5, 3, 3000, "#", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-accept_reject.wav", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-that_was_an_invalid_entry.wav", "\\d+")
|
||||
digit = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-accept_reject.wav", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-that_was_an_invalid_entry.wav", "\\d+");
|
||||
--process the response
|
||||
if (digit == "1") then
|
||||
--confirmed call accepted
|
||||
confirmed = true;
|
||||
elseif (digit == "2") then
|
||||
freeswitch.consoleLog("NOTICE", "[confirm] reject\n");
|
||||
session:hangup("CALL_REJECTED"); --LOSE_RACE
|
||||
else
|
||||
--freeswitch.consoleLog("NOTICE", "[confirm] no answer\n");
|
||||
session:hangup("NO_ANSWER");
|
||||
end
|
||||
else
|
||||
freeswitch.consoleLog("NOTICE", "[confirm] automatically accepted\n");
|
||||
confirmed = true;
|
||||
end
|
||||
|
||||
if (confirmed) then
|
||||
--cmd = "bgapi sched_transfer +1 "..uuid.." *5901";
|
||||
--freeswitch.consoleLog("NOTICE", "[ring_group] uuid: "..cmd.."\n");
|
||||
--result = api:executeString(cmd);
|
||||
freeswitch.consoleLog("NOTICE", "[confirm] accepted\n");
|
||||
|
||||
--check if the original call exists
|
||||
cmd = "uuid_exists "..argv_uuid;
|
||||
if (trim(api:executeString(cmd)) == "false") then
|
||||
session:hangup("NO_ANSWER");
|
||||
end
|
||||
|
||||
--unschedule the timeout
|
||||
cmd = "sched_del ring_group:"..argv_uuid;
|
||||
freeswitch.consoleLog("NOTICE", "[confirm] cmd: "..cmd.."\n");
|
||||
results = trim(api:executeString(cmd));
|
||||
|
||||
--get the uuids and remove the other calls
|
||||
cmd = "uuid_getvar "..argv_uuid.." uuids";
|
||||
freeswitch.consoleLog("NOTICE", "[confirm] cmd: "..cmd.."\n");
|
||||
uuids = trim(api:executeString(cmd));
|
||||
u = explode(",", uuids);
|
||||
for k,v in pairs(u) do
|
||||
if (uuid ~= v) then
|
||||
cmd = "uuid_kill "..v;
|
||||
freeswitch.consoleLog("NOTICE", "[confirm] cmd: "..cmd.."\n");
|
||||
result = trim(api:executeString(cmd));
|
||||
end
|
||||
end
|
||||
|
||||
--bridge the call
|
||||
cmd = "uuid_bridge "..uuid.." "..argv_uuid;
|
||||
result = trim(api:executeString(cmd));
|
||||
session:execute("valet_park", "confirm "..argv_uuid);
|
||||
end
|
||||
@@ -0,0 +1,204 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2010-2016
|
||||
-- All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Koldo A. Marcos <koldo.aingeru@sarenet.es>
|
||||
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
|
||||
--set debug
|
||||
-- debug["sql"] = true;
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--set default variables
|
||||
sounds_dir = "";
|
||||
recordings_dir = "";
|
||||
pin_number = "";
|
||||
max_tries = "3";
|
||||
digit_timeout = "3000";
|
||||
|
||||
--define uuid function
|
||||
local random = math.random;
|
||||
local function uuid()
|
||||
local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
||||
return string.gsub(template, '[xy]', function (c)
|
||||
local v = (c == 'x') and random(0, 0xf) or random(8, 0xb);
|
||||
return string.format('%x', v);
|
||||
end)
|
||||
end
|
||||
|
||||
--get session variables
|
||||
if (session:ready()) then
|
||||
session:answer();
|
||||
--session:execute("info", "");
|
||||
destination = session:getVariable("destination");
|
||||
pin_number = session:getVariable("pin_number");
|
||||
sounds_dir = session:getVariable("sounds_dir");
|
||||
ring_group_uuid = session:getVariable("ring_group_uuid");
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
end
|
||||
|
||||
--get the domain uuid and set other required variables
|
||||
if (session:ready()) then
|
||||
--get info for the ring group
|
||||
--sql = "SELECT * FROM v_ring_groups ";
|
||||
--sql = sql .. "where ring_group_uuid = '"..ring_group_uuid.."' ";
|
||||
--status = dbh:query(sql, function(row)
|
||||
-- domain_uuid = row["domain_uuid"];
|
||||
--end);
|
||||
|
||||
--set destination defaults
|
||||
destination_timeout = 15;
|
||||
destination_delay = 0;
|
||||
|
||||
--create the primary key uuid
|
||||
ring_group_destination_uuid = uuid();
|
||||
end
|
||||
|
||||
--if the pin number is provided then require it
|
||||
if (pin_number) then
|
||||
min_digits = string.len(pin_number);
|
||||
max_digits = string.len(pin_number)+1;
|
||||
digits = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-please_enter_pin_followed_by_pound.wav", "", "\\d+");
|
||||
if (digits == pin_number) then
|
||||
--pin is correct
|
||||
else
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-pin_or_extension_is-invalid.wav");
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-im_sorry.wav");
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-goodbye.wav");
|
||||
session:hangup("NORMAL_CLEARING");
|
||||
return;
|
||||
end
|
||||
end
|
||||
|
||||
--get the destination
|
||||
--if (session:ready()) then
|
||||
-- if string.len(destination) == 0) then
|
||||
-- destination = session:playAndGetDigits(1, 1, max_tries, digit_timeout, "#", "ivr/ivr-enter_destination_telephone_number.wav", "", "\\d+");
|
||||
-- freeswitch.consoleLog("NOTICE", "[ring_group] destination: "..destination.."\n");
|
||||
-- end
|
||||
--end
|
||||
|
||||
--login or logout
|
||||
if (session:ready()) then
|
||||
menu_selection = session:playAndGetDigits(1, 1, max_tries, digit_timeout, "#", "ivr/ivr-enter_destination_telephone_number.wav", "", "\\d+");
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group] menu_selection: "..menu_selection.."\n");
|
||||
if (menu_selection == "1") then
|
||||
--first, check to see if the destination is already in this ring group
|
||||
local sql = [[
|
||||
SELECT COUNT(*) AS in_group FROM
|
||||
v_ring_group_destinations
|
||||
WHERE
|
||||
domain_uuid = :domain_uuid
|
||||
AND ring_group_uuid = :ring_group_uuid
|
||||
AND destination_number = :destination
|
||||
]];
|
||||
local params = {domain_uuid = domain_uuid, ring_group_uuid = ring_group_uuid,
|
||||
destination = destination};
|
||||
if debug["sql"] then
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group] SQL: " .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
if (row.in_group == "0") then
|
||||
sql = [[
|
||||
INSERT INTO
|
||||
v_ring_group_destinations
|
||||
( ring_group_destination_uuid,
|
||||
domain_uuid,
|
||||
ring_group_uuid,
|
||||
destination_number,
|
||||
destination_delay,
|
||||
destination_timeout
|
||||
)
|
||||
VALUES
|
||||
( :ring_group_destination_uuid,
|
||||
:domain_uuid,
|
||||
:ring_group_uuid,
|
||||
:destination,
|
||||
:destination_delay,
|
||||
:destination_timeout
|
||||
)]];
|
||||
|
||||
params = {
|
||||
ring_group_destination_uuid = ring_group_destination_uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
ring_group_uuid = ring_group_uuid;
|
||||
destination = destination;
|
||||
destination_delay = destination_delay;
|
||||
destination_timeout = destination_timeout;
|
||||
|
||||
};
|
||||
|
||||
if debug["sql"] then
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] SQL: " .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] LOG IN\n");
|
||||
session:streamFile("ivr/ivr-you_are_now_logged_in.wav");
|
||||
else
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] ALREADY LOGGED IN\n");
|
||||
session:streamFile("ivr/ivr-you_are_now_logged_in.wav");
|
||||
end
|
||||
end);
|
||||
end
|
||||
if (menu_selection == "2") then
|
||||
local sql = [[
|
||||
DELETE FROM
|
||||
v_ring_group_destinations
|
||||
WHERE
|
||||
domain_uuid =:domain_uuid
|
||||
AND ring_group_uuid=:ring_group_uuid
|
||||
AND destination_number=:destination
|
||||
]];
|
||||
local params = {domain_uuid = domain_uuid, ring_group_uuid = ring_group_uuid,
|
||||
destination = destination};
|
||||
if debug["sql"] then
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] SQL: " .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] LOG OUT\n");
|
||||
session:streamFile("ivr/ivr-you_are_now_logged_out.wav");
|
||||
end
|
||||
end
|
||||
|
||||
--wait for the file to be written before proceeding
|
||||
if (session:ready()) then
|
||||
--session:sleep(1000);
|
||||
end
|
||||
|
||||
--hangup
|
||||
if (session:ready()) then
|
||||
session:hangup();
|
||||
end
|
||||
@@ -0,0 +1,82 @@
|
||||
-- uuid_hangup.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--Description:
|
||||
--if the uuid does not exist
|
||||
--then run commands
|
||||
|
||||
--get the argv values
|
||||
script_name = argv[0];
|
||||
uuid = argv[1];
|
||||
timeout = argv[2];
|
||||
|
||||
--define the trim function
|
||||
require "resources.functions.trim";
|
||||
|
||||
--define the explode function
|
||||
require "resources.functions.explode";
|
||||
|
||||
--prepare the api
|
||||
api = freeswitch.API();
|
||||
|
||||
--get the list of uuids
|
||||
cmd = "uuid_getvar "..uuid.." uuids";
|
||||
--freeswitch.consoleLog("NOTICE", "[confirm] cmd: "..cmd.."\n");
|
||||
uuids = trim(api:executeString(cmd));
|
||||
|
||||
--monitor the uuid
|
||||
x = 0
|
||||
while true do
|
||||
--sleep a moment to prevent using unecessary resources
|
||||
freeswitch.msleep(1000);
|
||||
|
||||
--check if the uuid exists
|
||||
if (api:executeString("uuid_exists "..uuid) == "false") then
|
||||
--unschedule the timeout
|
||||
cmd = "sched_del ring_group:"..uuid;
|
||||
--freeswitch.consoleLog("NOTICE", "[confirm] cmd: "..cmd.."\n");
|
||||
results = trim(api:executeString(cmd));
|
||||
--end the other uuids
|
||||
u = explode(",", uuids);
|
||||
for k,v in pairs(u) do
|
||||
if (uuid ~= v) then
|
||||
cmd = "uuid_kill "..v;
|
||||
--freeswitch.consoleLog("NOTICE", "[confirm] cmd: "..cmd.."\n");
|
||||
result = trim(api:executeString(cmd));
|
||||
end
|
||||
end
|
||||
|
||||
--end the loop
|
||||
break;
|
||||
end
|
||||
|
||||
--timeout
|
||||
x = x + 1;
|
||||
if (x > tonumber(timeout)) then
|
||||
--end the loop
|
||||
break;
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,165 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2010-2016
|
||||
-- All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Koldo A. Marcos <koldo.aingeru@sarenet.es>
|
||||
|
||||
|
||||
--include config.lua
|
||||
require "resources.functions.config";
|
||||
|
||||
--connect to the database
|
||||
require "resources.functions.database_handle";
|
||||
dbh = database_handle('system');
|
||||
|
||||
--set default variables
|
||||
sounds_dir = "";
|
||||
recordings_dir = "";
|
||||
pin_number = "";
|
||||
max_tries = "3";
|
||||
digit_timeout = "3000";
|
||||
|
||||
--define uuid function
|
||||
local random = math.random;
|
||||
local function uuid()
|
||||
local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
||||
return string.gsub(template, '[xy]', function (c)
|
||||
local v = (c == 'x') and random(0, 0xf) or random(8, 0xb);
|
||||
return string.format('%x', v);
|
||||
end)
|
||||
end
|
||||
|
||||
--get session variables
|
||||
if (session:ready()) then
|
||||
session:answer();
|
||||
--session:execute("info", "");
|
||||
destination_number = session:getVariable("destination_number");
|
||||
pin_number = session:getVariable("pin_number");
|
||||
sounds_dir = session:getVariable("sounds_dir");
|
||||
ring_group_uuid = session:getVariable("ring_group_uuid");
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
end
|
||||
|
||||
--get the domain uuid and set other required variables
|
||||
if (session:ready()) then
|
||||
--get info for the ring group
|
||||
--sql = "SELECT * FROM v_ring_groups ";
|
||||
--sql = sql .. "where ring_group_uuid = '"..ring_group_uuid.."' ";
|
||||
--status = dbh:query(sql, function(row)
|
||||
-- domain_uuid = row["domain_uuid"];
|
||||
--end);
|
||||
|
||||
destination_timeout = 15;
|
||||
destination_delay = 0;
|
||||
|
||||
--create the primary key uuid
|
||||
ring_group_destination_uuid = uuid();
|
||||
end
|
||||
|
||||
--if the pin number is provided then require it
|
||||
if (pin_number) then
|
||||
min_digits = string.len(pin_number);
|
||||
max_digits = string.len(pin_number)+1;
|
||||
digits = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-please_enter_pin_followed_by_pound.wav", "", "\\d+");
|
||||
if (digits == pin_number) then
|
||||
--pin is correct
|
||||
else
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-pin_or_extension_is-invalid.wav");
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/ivr/ivr-im_sorry.wav");
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-goodbye.wav");
|
||||
session:hangup("NORMAL_CLEARING");
|
||||
return;
|
||||
end
|
||||
end
|
||||
|
||||
--press 1 to login and 2 to logout
|
||||
if (session:ready()) then
|
||||
menu_selection = session:playAndGetDigits(1, 1, max_tries, digit_timeout, "#", "ivr/ivr-enter_destination_telephone_number.wav", "", "\\d+");
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group] menu_selection: "..menu_selection.."\n");
|
||||
if (menu_selection == "1") then
|
||||
--first, check to see if the destination is already in this ring group
|
||||
sql = [[
|
||||
SELECT COUNT(*) AS in_group FROM
|
||||
v_ring_group_destinations
|
||||
WHERE
|
||||
domain_uuid = ']]..domain_uuid..[['
|
||||
AND ring_group_uuid = ']]..ring_group_uuid..[['
|
||||
AND destination_number = ']]..destination_number..[['
|
||||
]];
|
||||
--freeswitch.consoleLog("NOTICE", "[ring_group] SQL "..sql.."\n");
|
||||
|
||||
dbh:query(sql, function(row)
|
||||
if (row.in_group == "0") then
|
||||
sql = [[
|
||||
INSERT INTO
|
||||
v_ring_group_destinations
|
||||
( ring_group_destination_uuid,
|
||||
domain_uuid,
|
||||
ring_group_uuid,
|
||||
destination_number,
|
||||
destination_delay,
|
||||
destination_timeout
|
||||
)
|
||||
VALUES
|
||||
( ']]..ring_group_destination_uuid..[[',
|
||||
']]..domain_uuid..[[',
|
||||
']]..ring_group_uuid..[[',
|
||||
']]..destination..[[',
|
||||
]]..destination_delay..[[,
|
||||
]]..destination_timeout..[[
|
||||
)]];
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] SQL "..sql.."\n");
|
||||
dbh:query(sql);
|
||||
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] LOG IN\n");
|
||||
session:streamFile("ivr/ivr-you_are_now_logged_in.wav");
|
||||
else
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] ALREADY LOGGED IN\n");
|
||||
session:streamFile("ivr/ivr-you_are_now_logged_in.wav");
|
||||
end
|
||||
end);
|
||||
end
|
||||
if (menu_selection == "2") then
|
||||
sql = [[
|
||||
DELETE FROM
|
||||
v_ring_group_destinations
|
||||
WHERE
|
||||
domain_uuid =']]..domain_uuid..[['
|
||||
AND ring_group_uuid=']]..ring_group_uuid..[['
|
||||
AND destination_number=']]..destination..[['
|
||||
]];
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] SQL "..sql.."\n");
|
||||
dbh:query(sql);
|
||||
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group][destination] LOG OUT\n");
|
||||
session:streamFile("ivr/ivr-you_are_now_logged_out.wav");
|
||||
end
|
||||
end
|
||||
|
||||
--wait for the file to be written before proceeding
|
||||
if (session:ready()) then
|
||||
--session:sleep(1000);
|
||||
end
|
||||
|
||||
--hangup
|
||||
if (session:ready()) then
|
||||
session:hangup();
|
||||
end
|
||||
@@ -0,0 +1,37 @@
|
||||
--includes
|
||||
require "resources.functions.config";
|
||||
local Database = require "resources.functions.database";
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
dbh = Database.new('system');
|
||||
local settings = Settings.new(dbh, domain_name, domain_uuid);
|
||||
|
||||
|
||||
--define trim
|
||||
function trim (s)
|
||||
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
--get the argv values
|
||||
cmd = argv[1];
|
||||
file = argv[2];
|
||||
|
||||
--get the cache directory
|
||||
local cache_dir = settings:get('cache', 'location', 'text')
|
||||
|
||||
if (cmd ~= nil) then
|
||||
cmd = trim(cmd);
|
||||
freeswitch.consoleLog("NOTICE","api_command: "..cmd .. " cache\n");
|
||||
end
|
||||
|
||||
if (cmd == "flush") then
|
||||
os.execute("rm " .. cache_dir .. "/*");
|
||||
end
|
||||
|
||||
if (cmd == "delete") then
|
||||
if (file ~= nil) then
|
||||
file = trim(file);
|
||||
freeswitch.consoleLog("NOTICE","api_command: delete ".. cache_dir .. "/" .. file .. "\n");
|
||||
os.remove(cache_dir.."/"..file);
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,105 @@
|
||||
--description
|
||||
--monitor custom cache event and clear cache on remote servers
|
||||
--protect xmlrpc using a firewall on the server to limit access by ip address
|
||||
--further protect it by configuring ssl for xmlrpc on the remote server
|
||||
|
||||
--dependencies
|
||||
--install mod_curl freeswitch module
|
||||
--uncomment mod_curl from modules.conf when compiling freeswitch
|
||||
--xmlrpc
|
||||
--open port xmlrpc port for other master server IP addresses
|
||||
--change the password for xmlrpc in system -> settings
|
||||
--conf/autoload_configs/lua.conf.xml
|
||||
-- <param name="startup-script" value="app/server/resources/file_cache.lua"/>
|
||||
--iptables
|
||||
-- /sbin/iptables -I INPUT -j ACCEPT -p tcp --dport 8080 -s x.x.x.x/32
|
||||
-- ubuntu: service iptables-persistent save
|
||||
|
||||
--define the servers running freeswitch do not include local
|
||||
--[[
|
||||
#put this in default settings once for each server. Order doesn't matter.
|
||||
Category: cache
|
||||
Subcategory: remote_servers
|
||||
Type: array
|
||||
value: http://user:password@server_ip:8080
|
||||
]]
|
||||
|
||||
--includes config.lua which will include local.lua if it exists
|
||||
require "resources.functions.config"
|
||||
local Database = require "resources.functions.database";
|
||||
local Settings = require "resources.functions.lazy_settings";
|
||||
|
||||
local db = dbh or Database.new('system');
|
||||
local settings = Settings.new(db, domain_name, domain_uuid)
|
||||
|
||||
local server_list = settings:get('cache', 'remote_servers', 'array')
|
||||
|
||||
--subscribe to the events
|
||||
--events = freeswitch.EventConsumer("all");
|
||||
events = freeswitch.EventConsumer("CUSTOM");
|
||||
|
||||
--define trim
|
||||
function trim (s)
|
||||
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--get the events
|
||||
for event in (function() return events:pop(1) end) do
|
||||
--serialize the data for the console
|
||||
--freeswitch.consoleLog("notice","event:" .. event:serialize("xml") .. "\n");
|
||||
--freeswitch.consoleLog("notice","event:" .. event:serialize("json") .. "\n");
|
||||
|
||||
--get the uuid
|
||||
local api_command = event:getHeader("API-Command");
|
||||
if (api_command ~= nil) then
|
||||
api_command = trim(api_command);
|
||||
freeswitch.consoleLog("NOTICE","api_command: "..api_command .. "\n");
|
||||
end
|
||||
|
||||
|
||||
--check if cache clear command
|
||||
if (api_command ~= "cache") then
|
||||
goto continue
|
||||
end
|
||||
|
||||
cache_updated = false;
|
||||
local api_command_argument = event:getHeader("API-Command-Argument");
|
||||
if (api_command_argument ~= nil) then
|
||||
api_command_argument = trim(api_command_argument);
|
||||
end
|
||||
if (api_command_argument == nil) then
|
||||
goto continue
|
||||
end
|
||||
if (api_command_argument == "flush") then
|
||||
cache_updated = true
|
||||
end
|
||||
if (string.sub(api_command_argument, 0, 6) == "delete") then
|
||||
cache_updated = true
|
||||
end
|
||||
if (not cache_updated) then
|
||||
goto continue
|
||||
end
|
||||
|
||||
--update the server_list
|
||||
server_list = settings:get('cache', 'remote_servers', 'array')
|
||||
|
||||
--check that there is work to do
|
||||
if (server_list == nil) then
|
||||
freeswitch.consoleLog("NOTICE","file_cache.lua: Script loaded but no servers configured\n");
|
||||
goto continue
|
||||
end
|
||||
|
||||
--send the API commands
|
||||
for _, server in ipairs(server_list) do
|
||||
api_command_argument = api_command_argument:gsub(" ", "%%20");
|
||||
url = server..[[/webapi/luarun?app/servers/resources/clear_cache.lua%20]]..api_command_argument;
|
||||
api = freeswitch.API();
|
||||
get_response = api:execute("curl", url);
|
||||
freeswitch.consoleLog("INFO", "[notice] curl ".. url .. " \n");
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
@@ -0,0 +1,96 @@
|
||||
--description
|
||||
--monitor custom memcache event and clear memcache on remote servers
|
||||
--protect xmlrpc using a firewall on the server to limit access by ip address
|
||||
|
||||
--dependencies
|
||||
--install mod_curl freeswitch module
|
||||
--uncomment mod_curl from modules.conf when compiling freeswitch
|
||||
--xmlrpc
|
||||
--open port xmlrpc port for other master server IP addresses
|
||||
--change the password for xmlrpc in system -> settings
|
||||
--conf/autoload_configs/lua.conf.xml
|
||||
-- <param name="startup-script" value="app/server/resources/memcache.lua"/>
|
||||
--iptables
|
||||
-- /sbin/iptables -I INPUT -j ACCEPT -p tcp --dport 8080 -s x.x.x.x/32
|
||||
-- ubuntu: service iptables-persistent save
|
||||
|
||||
--define the servers running freeswitch do not include local
|
||||
--[[
|
||||
#put this in local.lua
|
||||
servers = {}
|
||||
x = 0;
|
||||
servers[x] = {}
|
||||
servers[x]['method'] = "curl";
|
||||
servers[x]['username'] = "freeswitch";
|
||||
servers[x]['password'] = "freeswitch";
|
||||
servers[x]['hostname'] = "x.x.x.x";
|
||||
servers[x]['port'] = "8080";
|
||||
x = x + 1;
|
||||
servers[x] = {}
|
||||
servers[x]['method'] = "curl";
|
||||
servers[x]['username'] = "freeswitch";
|
||||
servers[x]['password'] = "freeswitch";
|
||||
servers[x]['hostname'] = "x.x.x.x";
|
||||
servers[x]['port'] = "8080";
|
||||
]]
|
||||
|
||||
--includes config.lua which will include local.lua if it exists
|
||||
require "resources.functions.config"
|
||||
|
||||
--subscribe to the events
|
||||
--events = freeswitch.EventConsumer("all");
|
||||
events = freeswitch.EventConsumer("CUSTOM");
|
||||
|
||||
--define trim
|
||||
function trim (s)
|
||||
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--get the events
|
||||
for event in (function() return events:pop(1) end) do
|
||||
--serialize the data for the console
|
||||
--freeswitch.consoleLog("notice","event:" .. event:serialize("xml") .. "\n");
|
||||
--freeswitch.consoleLog("notice","event:" .. event:serialize("json") .. "\n");
|
||||
|
||||
--get the uuid
|
||||
local api_command = event:getHeader("API-Command");
|
||||
if (api_command ~= nil) then
|
||||
api_command = trim(api_command);
|
||||
freeswitch.consoleLog("NOTICE","api_command: "..api_command .. "\n");
|
||||
end
|
||||
if (api_command == "memcache") then
|
||||
memcache_updated = false;
|
||||
local api_command_argument = event:getHeader("API-Command-Argument");
|
||||
if (api_command_argument ~= nil) then
|
||||
api_command_argument = trim(api_command_argument);
|
||||
end
|
||||
if (api_command_argument ~= nil) then
|
||||
if (api_command_argument == "flush") then
|
||||
memcache_updated = true
|
||||
end
|
||||
if (string.sub(api_command_argument, 0, 6) == "delete") then
|
||||
memcache_updated = true
|
||||
end
|
||||
if (memcache_updated) then
|
||||
for key,row in pairs(servers) do
|
||||
if (row.method == "ssh") then
|
||||
api_command_argument = api_command_argument:gsub("%%20", " ");
|
||||
cmd = [[ssh ]]..row.username..[[@]]..row.hostname..[[ "fs_cli -x 'memcache ]]..api_command_argument..[['"]];
|
||||
freeswitch.consoleLog("INFO", "[notice] command: ".. cmd .. "\n");
|
||||
os.execute(cmd);
|
||||
end
|
||||
if (row.method == "curl") then
|
||||
api_command_argument = api_command_argument:gsub(" ", "%%20");
|
||||
url = [[http://]]..row.username..[[:]]..row.password..[[@]]..row.hostname..[[:]]..row.port..[[/webapi/memcache?]]..api_command_argument;
|
||||
os.execute("curl "..url);
|
||||
freeswitch.consoleLog("INFO", "[notice] curl ".. url .. " \n");
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,146 @@
|
||||
-- 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 - 2022
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
|
||||
-- load config
|
||||
require "resources.functions.config";
|
||||
|
||||
--set debug
|
||||
-- debug["sql"] = true;
|
||||
|
||||
--load libraries
|
||||
local log = require "resources.functions.log"["app:dialplan:outbound:speed_dial"]
|
||||
local Database = require "resources.functions.database";
|
||||
local cache = require "resources.functions.cache";
|
||||
local json = require "resources.functions.lunajson";
|
||||
|
||||
--get the variables
|
||||
domain_name = session:getVariable("domain_name");
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
context = session:getVariable("context");
|
||||
permissions = session:getVariable("permissions");
|
||||
global = session:getVariable("global") or 'false';
|
||||
user = session:getVariable("sip_auth_username") or session:getVariable("username");
|
||||
|
||||
--set the default
|
||||
if (not permissions) then permissions = 'false'; end
|
||||
|
||||
--get the argv values
|
||||
destination = argv[2];
|
||||
|
||||
-- search in cache first
|
||||
local key = "app:dialplan:speed_dial:" .. destination .. "@" .. domain_name
|
||||
local value = cache.get(key)
|
||||
|
||||
-- decode value from cache
|
||||
if value then
|
||||
local t = json.decode(value)
|
||||
if not (t and t.phone_number) then
|
||||
log.warningf("can not decode value from the cache: %s", value)
|
||||
value = nil
|
||||
else
|
||||
value = t
|
||||
end
|
||||
end
|
||||
|
||||
-- search in database
|
||||
if not value then
|
||||
-- set source flag
|
||||
source = "database"
|
||||
|
||||
-- connect to database
|
||||
local dbh = Database.new('system');
|
||||
|
||||
-- search for the phone number in database using the speed dial
|
||||
if (permissions == 'true') then
|
||||
--advanced, check on user and group permissions
|
||||
sql = [[
|
||||
-- find all contacts with correct user or withot users and groups at all
|
||||
select t0.phone_number --, t6.extension, 'GROUP:' || t3.group_name as user_name
|
||||
from v_contact_phones t0
|
||||
inner join v_contacts t1 on t0.contact_uuid = t1.contact_uuid
|
||||
left outer join v_contact_groups t2 on t1.contact_uuid = t2.contact_uuid
|
||||
left outer join v_user_groups t3 on t2.group_uuid = t3.group_uuid
|
||||
left outer join v_users t4 on t3.user_uuid = t4.user_uuid
|
||||
left outer join v_extension_users t5 on t4.user_uuid = t5.user_uuid
|
||||
left outer join v_extensions t6 on t5.extension_uuid = t6.extension_uuid
|
||||
where t0.domain_uuid = :domain_uuid and t0.phone_speed_dial = :phone_speed_dial
|
||||
and ( (1 = 0)
|
||||
or (t6.domain_uuid = :domain_uuid and (t6.extension = :user or t6.number_alias = :user))
|
||||
or (t2.contact_uuid is null and not exists(select 1 from v_contact_users t where t.contact_uuid = t0.contact_uuid))
|
||||
)
|
||||
|
||||
union
|
||||
|
||||
-- find all contacts with correct group or withot users and groups at all
|
||||
select t0.phone_number -- , t5.extension, 'USER:' || t3.username as user_name
|
||||
from v_contact_phones t0
|
||||
inner join v_contacts t1 on t0.contact_uuid = t1.contact_uuid
|
||||
left outer join v_contact_users t2 on t1.contact_uuid = t2.contact_uuid
|
||||
left outer join v_users t3 on t2.user_uuid = t3.user_uuid
|
||||
left outer join v_extension_users t4 on t3.user_uuid = t4.user_uuid
|
||||
left outer join v_extensions t5 on t4.extension_uuid = t5.extension_uuid
|
||||
where t0.domain_uuid = :domain_uuid and t0.phone_speed_dial = :phone_speed_dial
|
||||
and ( (1 = 0)
|
||||
or (t5.domain_uuid = :domain_uuid and (t5.extension = :user or t5.number_alias = :user))
|
||||
or (t2.contact_user_uuid is null and not exists(select 1 from v_contact_groups t where t.contact_uuid = t0.contact_uuid))
|
||||
)
|
||||
]];
|
||||
log.noticef("[speed dial] advanced");
|
||||
else
|
||||
-- simple, skip looking up user or group permissions
|
||||
sql = "select phone_number ";
|
||||
sql = sql .. "from v_contact_phones ";
|
||||
if (global == 'true') then
|
||||
sql = sql .. "where phone_speed_dial = :phone_speed_dial ";
|
||||
params = {phone_speed_dial = destination};
|
||||
else
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and phone_speed_dial = :phone_speed_dial ";
|
||||
params = {phone_speed_dial = destination, domain_uuid = domain_uuid};
|
||||
end
|
||||
log.noticef("[speed dial] simple");
|
||||
end
|
||||
|
||||
if (debug["sql"]) then
|
||||
log.noticef("SQL: %s; params: %s", sql, json.encode(params));
|
||||
end
|
||||
|
||||
local phone_number = dbh:first_value(sql, params)
|
||||
|
||||
-- release database connection
|
||||
dbh:release()
|
||||
|
||||
-- set the cache
|
||||
if phone_number then
|
||||
value = {phone_number = phone_number}
|
||||
cache.set(key, json.encode(value), expire["speed_dial"])
|
||||
end
|
||||
end
|
||||
|
||||
-- transfer
|
||||
if value then
|
||||
--log the result
|
||||
log.noticef("%s XML %s source: %s", destination, context, source)
|
||||
|
||||
--transfer the call
|
||||
session:transfer(value.phone_number, "XML", context);
|
||||
else
|
||||
log.warningf('can not find number: %s in domain: %s', destination, domain_name)
|
||||
end
|
||||
@@ -0,0 +1,212 @@
|
||||
--
|
||||
-- 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>
|
||||
-- Copyright (C) 2010-2014
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
--
|
||||
-- Contributor(s):
|
||||
-- Riccardo Granchi <riccardo.granchi@nems.it>
|
||||
-- Philippe Rioual <bhouba@gmail.com>
|
||||
-- Alexey Melnichuck <alexeymelnichuck@gmail.com>
|
||||
|
||||
--Configuration
|
||||
-- Define known template names
|
||||
local known_templates = {
|
||||
["mobile" ] = true,
|
||||
["landline" ] = true,
|
||||
["international"] = true,
|
||||
["tollfree" ] = true,
|
||||
["sharedcharge" ] = true,
|
||||
["premium" ] = true,
|
||||
["unknown" ] = true,
|
||||
}
|
||||
|
||||
--Define templates for every toll type for your country
|
||||
local templates = {
|
||||
IT = {
|
||||
{"mobile", "[35]%d%d%d%d%d%d+" },
|
||||
{"landline", "0[123456789]%d+" },
|
||||
{"international", "00%d+" },
|
||||
{"tollfree", "119|1[3456789]%d|19[24]%d|192[01]%d%d|800%d%d%d%d%d+|803%d%d%d+|456%d%d%d%d%d%d+|11[2345678]|15%d%d|116%d%d%d|196%d%d" },
|
||||
{"sharedcharge", "84[0178]%d%d%d%d+|199%d%d%d%d%d+|178%d%d%d%d%d+|12%d%d|10%d%d%d+|1482|149%d+|4[012]%d+|70%d%d%d%d%d+" },
|
||||
{"premium", "89[2459]%d%d%d+|16[456]%d%d%d+|144%d%d%d+|4[346789]%d%d+" },
|
||||
{"unknown", "%d%d+" },
|
||||
};
|
||||
FR = {
|
||||
{"mobile", "0[67]%d%d%d%d%d%d%d%d" },
|
||||
{"landline", "0[1234589]%d%d%d%d%d%d%d%d" },
|
||||
{"international", "00%d+" },
|
||||
{"tollfree", "15|17|18|112|114|115|116%d%d%d|118%d%d%d|119|19[16]|1[06]%d%d|080%d+" },
|
||||
{"sharedcharge", "081%d+|082[0156]%d+|0884%d+|089[0123789]%d+" },
|
||||
{"premium", "%d%d+" },
|
||||
{"unknown", "%d%d+" },
|
||||
};
|
||||
US = {
|
||||
{"unknown", "%d+"},
|
||||
};
|
||||
RU = {
|
||||
{"international", "810%d+|8[89]40%d+|87%d%d%d%d%d%d%d%d%d"};
|
||||
{"mobile", "89%d%d%d%d%d%d%d%d%d" };
|
||||
{"tollfree", "8800%d%d%d%d%d%d%d|10[1-9]" };
|
||||
{"landline", "8[3-68]%d%d%d%d%d%d%d%d%d" };
|
||||
{"unknown", "" };
|
||||
};
|
||||
ZA = {
|
||||
{"international", "00%d+" };
|
||||
{"mobile", "0[6-8]%d%d%d%d%d%d%d%d" };
|
||||
{"landline", "0[1-5]%d%d%d%d%d%d%d%d" };
|
||||
{"unknown", "" };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
--Set to true to allow all calls for extensions without toll_allow
|
||||
local ACCEPT_EMPTY_TOLL_ALLOW = false
|
||||
|
||||
--debug
|
||||
debug["toll_type"] = false
|
||||
|
||||
require "resources.functions.explode";
|
||||
|
||||
--create the api object and get variables
|
||||
local api = freeswitch.API()
|
||||
local uuid = argv[2]
|
||||
|
||||
if not uuid or uuid == "" then
|
||||
return
|
||||
end
|
||||
|
||||
local function hungup()
|
||||
session:hangup("OUTGOING_CALL_BARRED")
|
||||
end
|
||||
|
||||
local function log(level, msg)
|
||||
freeswitch.consoleLog(level, "[toll_allow] " .. msg .. "\n")
|
||||
end
|
||||
|
||||
local function logf(level, ...)
|
||||
return log(level, string.format(...))
|
||||
end
|
||||
|
||||
local function trace(type, ...)
|
||||
if debug[type] then log(...) end
|
||||
end
|
||||
|
||||
local function tracef(type, ...)
|
||||
if debug[type] then logf(...) end
|
||||
end
|
||||
|
||||
local function channel_variable(uuid, name)
|
||||
local result = api:executeString("uuid_getvar " .. uuid .. " " .. name)
|
||||
|
||||
tracef("toll_type", "NOTICE", "channel_variable %s - %s", name, result)
|
||||
|
||||
if result:sub(1, 4) == '-ERR' then return nil end
|
||||
return result
|
||||
end
|
||||
|
||||
local function template_match(prefix, template, called)
|
||||
local parts = explode("|", template)
|
||||
|
||||
for index,part in ipairs(parts) do
|
||||
local pattern = "^" .. prefix .. part .. "$"
|
||||
if ( string.match(called, pattern) ~= nil ) then
|
||||
return pattern
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function get_toll_type(prefix, templates, called)
|
||||
for _,params in ipairs(templates) do
|
||||
local label, template = params[1], params[2]
|
||||
if not known_templates[label] then
|
||||
logf("WARNING", "unknown template name: %s in country template array", label)
|
||||
end
|
||||
|
||||
trace("toll_type", "NOTICE", "checking toll type " .. label .. " template: " .. template)
|
||||
|
||||
local pattern = template_match(prefix, template, called)
|
||||
if pattern then
|
||||
trace("toll_type", "NOTICE", "destination number " .. called .. " matches " .. label .. " pattern: " .. pattern)
|
||||
return label
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function is_undef(str)
|
||||
return (not str) or (#str == 0) or (str == "_undef_")
|
||||
end
|
||||
|
||||
local called = channel_variable(uuid, "destination_number") or ""
|
||||
local caller = channel_variable(uuid, "caller_id_number") or ""
|
||||
local prefix = channel_variable(uuid, "outbound_prefix") or ""
|
||||
local country = channel_variable(uuid, "default_country") or ""
|
||||
local toll_allow = channel_variable(uuid, "toll_allow") or ""
|
||||
|
||||
if (debug["toll_type"]) then
|
||||
logf("NOTICE", "called: %s", called)
|
||||
logf("NOTICE", "prefix: %s", prefix)
|
||||
logf("NOTICE", "country: %s", country)
|
||||
logf("NOTICE", "tollAllow: %s", toll_allow)
|
||||
end
|
||||
|
||||
if is_undef(toll_allow) then
|
||||
if ACCEPT_EMPTY_TOLL_ALLOW then
|
||||
logf("NOTICE", "unknown call authorized from %s to %s", caller, called)
|
||||
return
|
||||
end
|
||||
logf("WARNING", "unknown call not authorized from %s to %s : OUTGOING_CALL_BARRED", caller, called)
|
||||
return hungup()
|
||||
end
|
||||
|
||||
if is_undef(prefix) then
|
||||
prefix = ""
|
||||
end
|
||||
|
||||
if is_undef(country) then
|
||||
log("WARNING", "undefined country")
|
||||
return
|
||||
end
|
||||
|
||||
local templates = templates[country]
|
||||
if not templates then
|
||||
log("WARNING", "undefined templates")
|
||||
return
|
||||
end
|
||||
|
||||
--set toll_type
|
||||
local toll_type = get_toll_type(prefix, templates, called) or "unknown"
|
||||
|
||||
log("NOTICE", "toll type: " .. toll_type)
|
||||
|
||||
local parts = explode(",", toll_allow)
|
||||
|
||||
for i,part in ipairs(parts) do
|
||||
if not known_templates[part] then
|
||||
logf("WARNING", "unknown toll_allow name: %s in extension", part)
|
||||
end
|
||||
|
||||
tracef("toll_type", "NOTICE", "checking toll allow part " .. part)
|
||||
if ( part == toll_type ) then
|
||||
logf("NOTICE", "%s call authorized from %s to %s", toll_type, caller, called)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
logf("WARNING", "%s call not authorized from %s to %s : OUTGOING_CALL_BARRED", toll_type, caller, called)
|
||||
return hungup()
|
||||
@@ -0,0 +1,30 @@
|
||||
text = text or {};
|
||||
|
||||
text['label-download'] = {};
|
||||
text['label-download']['en-us'] = "Download";
|
||||
text['label-download']['es-cl'] = "Descargar";
|
||||
text['label-download']['pt-pt'] = "Baixar";
|
||||
text['label-download']['ru-ru'] = "Скачать";
|
||||
text['label-download']['fr-fr'] = "Télécharger";
|
||||
text['label-download']['de-de'] = "Download";
|
||||
text['label-download']['de-at'] = "Download";
|
||||
|
||||
text['label-listen'] = {};
|
||||
text['label-listen']['en-us'] = "Listen";
|
||||
text['label-listen']['es-cl'] = "Escuchar";
|
||||
text['label-listen']['pt-pt'] = "Ouvir";
|
||||
text['label-listen']['ru-ru'] = "Слушать";
|
||||
text['label-listen']['fr-fr'] = "Écouter";
|
||||
text['label-listen']['de-de'] = "Anhören";
|
||||
text['label-listen']['de-at'] = "Anhören";
|
||||
|
||||
text['label-attached'] = {};
|
||||
text['label-attached']['en-us'] = "Attached";
|
||||
text['label-attached']['es-cl'] = "Adjunto";
|
||||
text['label-attached']['pt-pt'] = "Ligado";
|
||||
text['label-attached']['ru-ru'] = "Вложение";
|
||||
text['label-attached']['fr-fr'] = "Attaché";
|
||||
text['label-attached']['de-de'] = "im Anhang";
|
||||
text['label-attached']['de-at'] = "im Anhang";
|
||||
|
||||
return text
|
||||
@@ -0,0 +1,707 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2023 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--set default values
|
||||
min_digits = 1;
|
||||
max_digits = 8;
|
||||
max_tries = 3;
|
||||
max_timeouts = 3;
|
||||
digit_timeout = 3000;
|
||||
stream_seek = false;
|
||||
|
||||
--direct dial
|
||||
direct_dial = {}
|
||||
direct_dial["enabled"] = "false";
|
||||
direct_dial["max_digits"] = 4;
|
||||
|
||||
--debug
|
||||
--debug["info"] = true;
|
||||
--debug["sql"] = true;
|
||||
|
||||
--get the argv values
|
||||
script_name = argv[1];
|
||||
voicemail_action = argv[2];
|
||||
|
||||
--starting values
|
||||
dtmf_digits = '';
|
||||
timeouts = 0;
|
||||
password_tries = 0;
|
||||
|
||||
--connect to the database
|
||||
Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library (as global object)
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--set the api
|
||||
api = freeswitch.API();
|
||||
|
||||
--if the session exists
|
||||
if (session ~= nil) then
|
||||
|
||||
--get session variables
|
||||
context = session:getVariable("context");
|
||||
sounds_dir = session:getVariable("sounds_dir");
|
||||
domain_name = session:getVariable("domain_name");
|
||||
uuid = session:getVariable("uuid");
|
||||
voicemail_id = session:getVariable("voicemail_id");
|
||||
voicemail_action = session:getVariable("voicemail_action");
|
||||
destination_number = session:getVariable("destination_number");
|
||||
caller_id_name = session:getVariable("caller_id_name");
|
||||
caller_id_number = session:getVariable("caller_id_number");
|
||||
current_time_zone = session:getVariable("timezone");
|
||||
effective_caller_id_number = session:getVariable("effective_caller_id_number");
|
||||
effective_caller_id_name = session:getVariable("effective_caller_id_name");
|
||||
voicemail_greeting_number = session:getVariable("voicemail_greeting_number");
|
||||
skip_instructions = session:getVariable("skip_instructions");
|
||||
skip_greeting = session:getVariable("skip_greeting");
|
||||
vm_message_ext = session:getVariable("vm_message_ext");
|
||||
vm_say_caller_id_number = session:getVariable("vm_say_caller_id_number");
|
||||
vm_say_date_time = session:getVariable("vm_say_date_time");
|
||||
vm_disk_quota = session:getVariable("vm-disk-quota");
|
||||
record_silence_threshold = session:getVariable("record-silence-threshold");
|
||||
voicemail_authorized = session:getVariable("voicemail_authorized");
|
||||
sip_from_user = session:getVariable("sip_from_user");
|
||||
user_name = session:getVariable("user_name");
|
||||
sip_number_alias = session:getVariable("sip_number_alias");
|
||||
origination_callee_id_name = session:getVariable("origination_callee_id_name");
|
||||
|
||||
--modify caller_id_number if effective_caller_id_number is set
|
||||
if (effective_caller_id_number ~= nil) then
|
||||
caller_id_number = effective_caller_id_number;
|
||||
end
|
||||
--modify caller_id_name if effective_caller_id_name is set
|
||||
if (effective_caller_id_name ~= nil) then
|
||||
caller_id_name = effective_caller_id_name;
|
||||
end
|
||||
|
||||
--set default values
|
||||
if (string.sub(caller_id_number, 1, 1) == "/") then
|
||||
caller_id_number = string.sub(caller_id_number, 2, -1);
|
||||
end
|
||||
if (not record_silence_threshold) then
|
||||
record_silence_threshold = 300;
|
||||
end
|
||||
if (not vm_disk_quota) then
|
||||
vm_disk_quota = session:getVariable("vm_disk_quota");
|
||||
end
|
||||
if (not vm_message_ext) then
|
||||
vm_message_ext = 'wav';
|
||||
end
|
||||
|
||||
--set the sounds path for the language, dialect and voice
|
||||
default_language = session:getVariable("default_language");
|
||||
default_dialect = session:getVariable("default_dialect");
|
||||
default_voice = session:getVariable("default_voice");
|
||||
if (not default_language) then default_language = 'en'; end
|
||||
if (not default_dialect) then default_dialect = 'us'; end
|
||||
if (not default_voice) then default_voice = 'callie'; end
|
||||
|
||||
--get the domain_uuid
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
if (domain_uuid == nil) then
|
||||
if (domain_name ~= nil) then
|
||||
local sql = "SELECT domain_uuid FROM v_domains ";
|
||||
sql = sql .. "WHERE domain_name = :domain_name ";
|
||||
local params = {domain_name = domain_name};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(rows)
|
||||
domain_uuid = rows["domain_uuid"];
|
||||
end);
|
||||
end
|
||||
end
|
||||
if (domain_uuid ~= nil) then
|
||||
domain_uuid = string.lower(domain_uuid);
|
||||
end
|
||||
|
||||
--if voicemail_id is non numeric then get the number-alias
|
||||
if (voicemail_id ~= nil) then
|
||||
if (voicemail_id and #voicemail_id == nil) then
|
||||
voicemail_id = api:execute("user_data", voicemail_id .. "@" .. domain_name .. " attr number-alias");
|
||||
end
|
||||
end
|
||||
|
||||
--set the voicemail_dir
|
||||
voicemail_dir = voicemail_dir.."/default/"..domain_name;
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] voicemail_dir: " .. voicemail_dir .. "\n");
|
||||
end
|
||||
|
||||
--settings
|
||||
require "resources.functions.settings";
|
||||
settings = settings(domain_uuid);
|
||||
if (settings['voicemail'] ~= nil) then
|
||||
storage_type = '';
|
||||
if (settings['voicemail']['storage_type'] ~= nil) then
|
||||
if (settings['voicemail']['storage_type']['text'] ~= nil) then
|
||||
storage_type = settings['voicemail']['storage_type']['text'];
|
||||
end
|
||||
end
|
||||
|
||||
storage_path = '';
|
||||
if (settings['voicemail']['storage_path'] ~= nil) then
|
||||
if (settings['voicemail']['storage_path']['text'] ~= nil) then
|
||||
storage_path = settings['voicemail']['storage_path']['text'];
|
||||
storage_path = storage_path:gsub("${domain_name}", domain_name);
|
||||
storage_path = storage_path:gsub("${voicemail_id}", voicemail_id);
|
||||
storage_path = storage_path:gsub("${voicemail_dir}", voicemail_dir);
|
||||
end
|
||||
end
|
||||
|
||||
message_order = '';
|
||||
if (settings['voicemail']['message_order'] ~= nil) then
|
||||
if (settings['voicemail']['message_order']['text'] ~= nil) then
|
||||
message_order = settings['voicemail']['message_order']['text'];
|
||||
end
|
||||
end
|
||||
|
||||
if (settings['voicemail']['message_caller_id_number'] ~= nil) then
|
||||
if (settings['voicemail']['message_caller_id_number']['text'] ~= nil) then
|
||||
vm_say_caller_id_number = settings['voicemail']['message_caller_id_number']['text'];
|
||||
end
|
||||
end;
|
||||
|
||||
if (settings['voicemail']['message_date_time'] ~= nil) then
|
||||
if (settings['voicemail']['message_date_time']['text'] ~= nil) then
|
||||
vm_say_date_time = settings['voicemail']['message_date_time']['text'];
|
||||
end
|
||||
end
|
||||
|
||||
if (not vm_say_caller_id_number) then
|
||||
vm_say_caller_id_number = "before";
|
||||
end
|
||||
|
||||
if (not vm_say_date_time) then
|
||||
vm_say_date_time = "before";
|
||||
end
|
||||
|
||||
remote_access = '';
|
||||
if (settings['voicemail']['remote_access'] ~= nil) then
|
||||
if (settings['voicemail']['remote_access']['boolean'] ~= nil) then
|
||||
remote_access = settings['voicemail']['remote_access']['boolean'];
|
||||
end
|
||||
end
|
||||
|
||||
password_complexity = '';
|
||||
if (settings['voicemail']['password_complexity'] ~= nil) then
|
||||
if (settings['voicemail']['password_complexity']['boolean'] ~= nil) then
|
||||
password_complexity = settings['voicemail']['password_complexity']['boolean'];
|
||||
end
|
||||
end
|
||||
|
||||
password_min_length = '';
|
||||
if (settings['voicemail']['password_min_length'] ~= nil) then
|
||||
if (settings['voicemail']['password_min_length']['numeric'] ~= nil) then
|
||||
password_min_length = settings['voicemail']['password_min_length']['numeric'];
|
||||
end
|
||||
end
|
||||
|
||||
not_found_message = 'false';
|
||||
if (settings['voicemail']['not_found_message'] ~= nil) then
|
||||
if (settings['voicemail']['not_found_message']['boolean'] ~= nil) then
|
||||
not_found_message = settings['voicemail']['not_found_message']['boolean'];
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if (settings['voicemail']) then
|
||||
if settings['voicemail']['voicemail_to_sms'] then
|
||||
voicemail_to_sms = (settings['voicemail']['voicemail_to_sms']['boolean'] == 'true');
|
||||
end
|
||||
if settings['voicemail']['voicemail_to_sms_did'] then
|
||||
voicemail_to_sms_did = settings['voicemail']['voicemail_to_sms_did']['text'];
|
||||
end
|
||||
voicemail_to_sms_did = voicemail_to_sms_did or '';
|
||||
end
|
||||
|
||||
if (not temp_dir) or (#temp_dir == 0) then
|
||||
if (settings['server'] ~= nil) then
|
||||
if (settings['server']['temp'] ~= nil) then
|
||||
if (settings['server']['temp']['dir'] ~= nil) then
|
||||
temp_dir = settings['server']['temp']['dir'];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--get the voicemail settings
|
||||
if (voicemail_id ~= nil) then
|
||||
if (session ~= nil and session:ready()) then
|
||||
--get the information from the database
|
||||
local sql = [[SELECT * FROM v_voicemails
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id
|
||||
AND voicemail_enabled = 'true' ]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = voicemail_id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
voicemail_uuid = string.lower(row["voicemail_uuid"]);
|
||||
voicemail_password = row["voicemail_password"];
|
||||
greeting_id = row["greeting_id"];
|
||||
voicemail_alternate_greet_id = row["voicemail_alternate_greet_id"];
|
||||
voicemail_mail_to = row["voicemail_mail_to"];
|
||||
voicemail_attach_file = row["voicemail_attach_file"];
|
||||
voicemail_local_after_email = row["voicemail_local_after_email"];
|
||||
voicemail_transcription_enabled = row["voicemail_transcription_enabled"];
|
||||
voicemail_tutorial = row["voicemail_tutorial"];
|
||||
end);
|
||||
|
||||
--set default values
|
||||
if (voicemail_local_after_email == nil) then
|
||||
voicemail_local_after_email = "true";
|
||||
end
|
||||
if (voicemail_attach_file == nil) then
|
||||
voicemail_attach_file = "true";
|
||||
end
|
||||
|
||||
--valid voicemail
|
||||
if (voicemail_uuid ~= nil and string.len(voicemail_uuid) > 0) then
|
||||
--answer the session
|
||||
if (session ~= nil and session:ready()) then
|
||||
session:answer();
|
||||
session:sleep('1000');
|
||||
end
|
||||
|
||||
--unset bind meta app
|
||||
session:execute("unbind_meta_app", "");
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--set the callback function
|
||||
if (session ~= nil and session:ready()) then
|
||||
session:setVariable("playback_terminators", "#");
|
||||
session:setInputCallback("on_dtmf", "");
|
||||
end
|
||||
|
||||
--general functions
|
||||
require "resources.functions.base64";
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.file_exists";
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.format_seconds";
|
||||
require "resources.functions.mkdir";
|
||||
require "resources.functions.copy";
|
||||
|
||||
--voicemail functions
|
||||
require "app.voicemail.resources.functions.on_dtmf";
|
||||
require "app.voicemail.resources.functions.get_voicemail_id";
|
||||
require "app.voicemail.resources.functions.check_password";
|
||||
require "app.voicemail.resources.functions.change_password";
|
||||
require "app.voicemail.resources.functions.macro";
|
||||
require "app.voicemail.resources.functions.play_greeting";
|
||||
require "app.voicemail.resources.functions.record_message";
|
||||
require "app.voicemail.resources.functions.record_menu";
|
||||
require "app.voicemail.resources.functions.forward_add_intro";
|
||||
require "app.voicemail.resources.functions.forward_to_extension";
|
||||
require "app.voicemail.resources.functions.main_menu";
|
||||
require "app.voicemail.resources.functions.listen_to_recording";
|
||||
require "app.voicemail.resources.functions.message_waiting";
|
||||
require "app.voicemail.resources.functions.send_email";
|
||||
require "app.voicemail.resources.functions.send_sms";
|
||||
require "app.voicemail.resources.functions.delete_recording";
|
||||
require "app.voicemail.resources.functions.message_saved";
|
||||
require "app.voicemail.resources.functions.return_call";
|
||||
require "app.voicemail.resources.functions.menu_messages";
|
||||
require "app.voicemail.resources.functions.advanced";
|
||||
require "app.voicemail.resources.functions.record_greeting";
|
||||
require "app.voicemail.resources.functions.choose_greeting";
|
||||
require "app.voicemail.resources.functions.record_name";
|
||||
require "app.voicemail.resources.functions.message_count"
|
||||
require "app.voicemail.resources.functions.mwi_notify";
|
||||
require "app.voicemail.resources.functions.blf_notify";
|
||||
require "app.voicemail.resources.functions.tutorial";
|
||||
|
||||
--send a message waiting event
|
||||
if (voicemail_action == "mwi") then
|
||||
--get the mailbox info
|
||||
account = argv[3];
|
||||
array = explode("@", account);
|
||||
voicemail_id = array[1];
|
||||
domain_name = array[2];
|
||||
|
||||
--send information the console
|
||||
debug["info"] = "true";
|
||||
|
||||
--get voicemail message details
|
||||
local sql = [[SELECT * FROM v_domains WHERE domain_name = :domain_name]];
|
||||
local params = {domain_name = domain_name};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
domain_uuid = string.lower(row["domain_uuid"]);
|
||||
end);
|
||||
|
||||
--get voicemail message details
|
||||
if (voicemail_id) then
|
||||
local sql = [[SELECT * FROM v_voicemails
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id]]
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = voicemail_id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
voicemail_local_after_email = row["voicemail_local_after_email"];
|
||||
end);
|
||||
|
||||
--set default values
|
||||
if (voicemail_local_after_email == nil) then
|
||||
voicemail_local_after_email = "true";
|
||||
end
|
||||
|
||||
--get the message count and send the mwi event
|
||||
if (voicemail_local_after_email == 'true') then
|
||||
message_waiting(voicemail_id, domain_uuid);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--check messages
|
||||
if (voicemail_action == "check") then
|
||||
if (session ~= nil and session:ready()) then
|
||||
--check the voicemail password
|
||||
if (voicemail_id) then
|
||||
if (voicemail_authorized) then
|
||||
if (voicemail_authorized == "true") then
|
||||
if (voicemail_id == user_name or voicemail_id == sip_number_alias) then
|
||||
--skip the password check
|
||||
else
|
||||
check_password(voicemail_id, password_tries);
|
||||
end
|
||||
else
|
||||
check_password(voicemail_id, password_tries);
|
||||
end
|
||||
else
|
||||
check_password(voicemail_id, password_tries);
|
||||
end
|
||||
else
|
||||
check_password(voicemail_id, password_tries);
|
||||
end
|
||||
|
||||
--send to the main menu
|
||||
timeouts = 0;
|
||||
if (voicemail_tutorial == "true") then
|
||||
tutorial("intro");
|
||||
else
|
||||
main_menu();
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--leave a message
|
||||
if (voicemail_action == "save") then
|
||||
|
||||
--set the variables
|
||||
if (session ~= nil and session:ready()) then
|
||||
session:setVariable("missed_call", "true");
|
||||
session:setVariable("voicemail_answer_stamp", api:execute("strftime"));
|
||||
session:setVariable("voicemail_answer_epoch", api:execute("strepoch"));
|
||||
end
|
||||
|
||||
--check the voicemail quota
|
||||
if (voicemail_uuid ~= nil and vm_disk_quota ~= nil) then
|
||||
--get voicemail message seconds
|
||||
local sql = [[SELECT coalesce(sum(message_length), 0) as message_sum FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid]]
|
||||
local params = {domain_uuid = domain_uuid, voicemail_uuid = voicemail_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
message_sum = row["message_sum"];
|
||||
end);
|
||||
if (vm_disk_quota and message_sum and #vm_disk_quota <= #message_sum) then
|
||||
--play message mailbox full
|
||||
session:execute("playback", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-mailbox_full.wav")
|
||||
--hangup
|
||||
session:hangup("NORMAL_CLEARING");
|
||||
--set the voicemail_uuid to nil to prevent saving the voicemail
|
||||
voicemail_uuid = nil;
|
||||
end
|
||||
end
|
||||
|
||||
--valid voicemail
|
||||
if (voicemail_uuid ~= nil) then
|
||||
|
||||
--play the greeting
|
||||
timeouts = 0;
|
||||
play_greeting();
|
||||
|
||||
--save the message
|
||||
record_message();
|
||||
|
||||
--process base64
|
||||
if (storage_type == "base64") then
|
||||
--show the storage type
|
||||
freeswitch.consoleLog("notice", "[voicemail] ".. storage_type .. "\n");
|
||||
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
-- build full path to file
|
||||
local full_path = voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext
|
||||
|
||||
if file_exists(full_path) then
|
||||
--read file content as base64 string
|
||||
message_base64 = file.read_base64(full_path);
|
||||
--freeswitch.consoleLog("notice", "[voicemail] ".. message_base64 .. "\n");
|
||||
|
||||
--delete the file
|
||||
os.remove(full_path);
|
||||
end
|
||||
end
|
||||
|
||||
--get the voicemail destinations
|
||||
sql = [[select * from v_voicemail_destinations
|
||||
where voicemail_uuid = :voicemail_uuid]]
|
||||
params = {voicemail_uuid=voicemail_uuid};
|
||||
--freeswitch.consoleLog("notice", "[voicemail][destinations] SQL:" .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
destinations = {};
|
||||
x = 1;
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
destinations[x] = row;
|
||||
x = x + 1;
|
||||
end);
|
||||
table.insert(destinations, {domain_uuid=domain_uuid,voicemail_destination_uuid=voicemail_uuid,voicemail_uuid=voicemail_uuid,voicemail_uuid_copy=voicemail_uuid});
|
||||
--show the storage type
|
||||
freeswitch.consoleLog("notice", "[voicemail] ".. storage_type .. "\n");
|
||||
|
||||
count = 0
|
||||
for k,v in pairs(destinations) do
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
--loop through the voicemail destinations
|
||||
y = 1;
|
||||
for key,row in pairs(destinations) do
|
||||
--determine uuid
|
||||
if (y == count) then
|
||||
voicemail_message_uuid = uuid;
|
||||
else
|
||||
voicemail_message_uuid = api:execute("create_uuid");
|
||||
end
|
||||
y = y + 1;
|
||||
--save the message to the voicemail messages
|
||||
if (message_length ~= nil and message_length > 2) then
|
||||
caller_id_name = string.gsub(caller_id_name,"'","''");
|
||||
local sql = {}
|
||||
table.insert(sql, "INSERT INTO v_voicemail_messages ");
|
||||
table.insert(sql, "(");
|
||||
table.insert(sql, "voicemail_message_uuid, ");
|
||||
table.insert(sql, "domain_uuid, ");
|
||||
table.insert(sql, "voicemail_uuid, ");
|
||||
table.insert(sql, "created_epoch, ");
|
||||
table.insert(sql, "caller_id_name, ");
|
||||
table.insert(sql, "caller_id_number, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(sql, "message_base64, ");
|
||||
end
|
||||
if (transcribe_enabled == "true") and (voicemail_transcription_enabled == "true") then
|
||||
table.insert(sql, "message_transcription, ");
|
||||
end
|
||||
table.insert(sql, "message_length ");
|
||||
--table.insert(sql, "message_status, ");
|
||||
--table.insert(sql, "message_priority, ");
|
||||
table.insert(sql, ") ");
|
||||
table.insert(sql, "VALUES ");
|
||||
table.insert(sql, "( ");
|
||||
table.insert(sql, ":voicemail_message_uuid, ");
|
||||
table.insert(sql, ":domain_uuid, ");
|
||||
table.insert(sql, ":voicemail_uuid, ");
|
||||
table.insert(sql, ":start_epoch, ");
|
||||
table.insert(sql, ":caller_id_name, ");
|
||||
table.insert(sql, ":caller_id_number, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(sql, ":message_base64, ");
|
||||
end
|
||||
if (transcribe_enabled == "true") and (voicemail_transcription_enabled == "true") then
|
||||
table.insert(sql, ":transcription, ");
|
||||
end
|
||||
table.insert(sql, ":message_length ");
|
||||
--table.insert(sql, ":message_status, ");
|
||||
--table.insert(sql, ":message_priority ");
|
||||
table.insert(sql, ") ");
|
||||
sql = table.concat(sql, "\n");
|
||||
local params = {
|
||||
voicemail_message_uuid = voicemail_message_uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
voicemail_uuid = row.voicemail_uuid_copy;
|
||||
start_epoch = start_epoch;
|
||||
caller_id_name = caller_id_name;
|
||||
caller_id_number = caller_id_number;
|
||||
message_base64 = message_base64;
|
||||
transcription = transcription;
|
||||
message_length = message_length;
|
||||
--message_status = message_status;
|
||||
--message_priority = message_priority;
|
||||
};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
if (storage_type == "base64") then
|
||||
local Database = require "resources.functions.database"
|
||||
local dbh = Database.new('system', 'base64');
|
||||
dbh:query(sql, params);
|
||||
dbh:release();
|
||||
else
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
end
|
||||
|
||||
local params = {domain_uuid = domain_uuid, voicemail_uuid = row.voicemail_uuid_copy};
|
||||
|
||||
--get new message count
|
||||
sql = [[SELECT count(*) as new_messages FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid
|
||||
AND (message_status is null or message_status = '') ]];
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(result)
|
||||
new_messages = result["new_messages"];
|
||||
end);
|
||||
|
||||
--get saved message count
|
||||
sql = [[SELECT count(*) as saved_messages FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid
|
||||
AND message_status = 'saved' ]];
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(result)
|
||||
saved_messages = result["saved_messages"];
|
||||
end);
|
||||
|
||||
--get the voicemail_id
|
||||
sql = [[SELECT voicemail_id FROM v_voicemails WHERE voicemail_uuid = :voicemail_uuid]];
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(result)
|
||||
voicemail_id_copy = result["voicemail_id"];
|
||||
end);
|
||||
|
||||
--make sure the voicemail directory exists
|
||||
mkdir(voicemail_dir.."/"..voicemail_id_copy);
|
||||
|
||||
--copy the voicemail to each destination
|
||||
if (file_exists(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext)) then
|
||||
local src = voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext
|
||||
local dst = voicemail_dir.."/"..voicemail_id_copy.."/msg_"..voicemail_message_uuid.."."..vm_message_ext
|
||||
if src ~= dst then
|
||||
copy(src, dst)
|
||||
end
|
||||
end
|
||||
|
||||
--send the message waiting event
|
||||
if (message_length ~= nil and message_length > 2) then
|
||||
message_waiting(voicemail_id_copy, domain_uuid);
|
||||
end
|
||||
|
||||
--send the email with the voicemail recording attached
|
||||
if (message_length ~= nil and message_length > 2) then
|
||||
send_email(voicemail_id_copy, voicemail_message_uuid);
|
||||
if (voicemail_to_sms) then
|
||||
send_sms(voicemail_id_copy, voicemail_message_uuid);
|
||||
end
|
||||
end
|
||||
end --for
|
||||
|
||||
else
|
||||
--voicemail not enabled or does not exist
|
||||
if (session ~= nil and session:ready()) then
|
||||
referred_by = session:getVariable("sip_h_Referred-By");
|
||||
if (referred_by) then
|
||||
referred_by = referred_by:match('[%d]+');
|
||||
session:transfer(referred_by, "XML", context);
|
||||
else
|
||||
if (not_found_message == "true") then
|
||||
session:answer();
|
||||
session:execute("sleep", "1000");
|
||||
session:execute("playback", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-no_answer_no_vm.wav");
|
||||
session:hangup();
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
|
||||
--notes
|
||||
--record the video
|
||||
--records audio only
|
||||
--result = session:execute("set", "enable_file_write_buffering=false");
|
||||
--mkdir(voicemail_dir.."/"..voicemail_id);
|
||||
--session:recordFile("/tmp/recording.fsv", 200, 200, 200);
|
||||
--records audio and video
|
||||
--result = session:execute("record_fsv", "file.fsv");
|
||||
--freeswitch.consoleLog("notice", "[voicemail] SQL: " .. result .. "\n");
|
||||
|
||||
--play the video recording
|
||||
--plays the video
|
||||
--result = session:execute("play_fsv", "/tmp/recording.fsv");
|
||||
--plays the file but without the video
|
||||
--dtmf = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "/tmp/recording.fsv", "", "\\d+");
|
||||
--freeswitch.consoleLog("notice", "[voicemail] SQL: " .. result .. "\n");
|
||||
|
||||
--callback (works with DTMF)
|
||||
--http://wiki.freeswitch.org/wiki/Mod_fsv
|
||||
--mkdir(voicemail_dir.."/"..voicemail_id);
|
||||
--session:recordFile(file_name, max_len_secs, silence_threshold, silence_secs)
|
||||
--session:sayPhrase(macro_name [,macro_data] [,language]);
|
||||
--session:sayPhrase("voicemail_menu", "1:2:3:#", default_language);
|
||||
--session:streamFile("directory/dir-to_select_entry.wav"); --works with setInputCallback
|
||||
--session:streamFile("tone_stream://L=1;%(1000, 0, 640)");
|
||||
--session:say("12345", default_language, "number", "pronounced");
|
||||
|
||||
--speak
|
||||
--session:set_tts_parms("flite", "kal");
|
||||
--session:speak("Please say the name of the person you're trying to contact");
|
||||
|
||||
--callback (execute and executeString does not work with DTMF)
|
||||
--session:execute(api_string);
|
||||
--session:executeString("playback "..mySound);
|
||||
|
||||
--uuid_video_refresh
|
||||
--uuid_video_refresh,<uuid>,Send video refresh.,mod_commands
|
||||
--may be used to clear video buffer before using record_fsv
|
||||
@@ -0,0 +1,68 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define a function for the advanced menu
|
||||
function advanced ()
|
||||
--clear the dtmf
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
|
||||
--play entire menu using phrases
|
||||
if (session:ready()) then
|
||||
dtmf_digits = session:playAndGetDigits(1, 1, max_tries, digit_timeout, "#", "phrase:voicemail_config_menu:1:2:3:6:0", "", "\\d+");
|
||||
end
|
||||
|
||||
--process the dtmf
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == "1") then
|
||||
--To record a greeting press 1
|
||||
timeouts = 0;
|
||||
record_greeting(nil,"advanced");
|
||||
elseif (dtmf_digits == "2") then
|
||||
--To choose greeting press 2
|
||||
timeouts = 0;
|
||||
choose_greeting();
|
||||
elseif (dtmf_digits == "3") then
|
||||
--To record your name 3
|
||||
record_name("advanced");
|
||||
elseif (dtmf_digits == "6") then
|
||||
--To change your password press 6
|
||||
change_password(voicemail_id, "advanced");
|
||||
elseif (dtmf_digits == "0") then
|
||||
--For the main menu press 0
|
||||
timeouts = 0;
|
||||
main_menu();
|
||||
else
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts <= max_timeouts) then
|
||||
advanced();
|
||||
else
|
||||
session:execute("playback", "phrase:voicemail_goodbye");
|
||||
session:hangup();
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
function blf_notify(on, user, uuid)
|
||||
|
||||
require "resources.functions.split"
|
||||
local api = require "resources.functions.api"
|
||||
local log = require "resources.functions.log".presence
|
||||
|
||||
log.debugf('turn_lamp: %s - %s(%s)', tostring(user), tostring(on), type(on))
|
||||
|
||||
local userid, domain, proto = split_first(user, "@", true)
|
||||
proto, userid = split_first(userid, "+", true)
|
||||
if userid then
|
||||
user = userid .. "@" .. domain
|
||||
else
|
||||
proto = "sip"
|
||||
end
|
||||
|
||||
uuid = uuid or api:execute('create_uuid')
|
||||
|
||||
local event = freeswitch.Event("PRESENCE_IN");
|
||||
event:addHeader("proto", proto);
|
||||
event:addHeader("event_type", "presence");
|
||||
event:addHeader("alt_event_type", "dialog");
|
||||
event:addHeader("Presence-Call-Direction", "outbound");
|
||||
event:addHeader("from", user);
|
||||
event:addHeader("login", user);
|
||||
event:addHeader("unique-id", uuid);
|
||||
event:addHeader("status", "Active (1 waiting)");
|
||||
if on then
|
||||
event:addHeader("answer-state", "confirmed");
|
||||
event:addHeader("rpid", "unknown");
|
||||
event:addHeader("event_count", "1");
|
||||
else
|
||||
event:addHeader("answer-state", "terminated");
|
||||
end
|
||||
|
||||
-- log.debug(event:serialize())
|
||||
|
||||
event:fire();
|
||||
end
|
||||
|
||||
return {
|
||||
turn_lamp = turn_lamp;
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--check the voicemail password
|
||||
function change_password(voicemail_id, menu)
|
||||
if (session:ready()) then
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--set password valitity in case of hangup
|
||||
valid_password = "false";
|
||||
--please enter your password followed by pound
|
||||
dtmf_digits = '';
|
||||
password = session:playAndGetDigits(1, 20, max_tries, 5000, "#", "phrase:voicemail_enter_new_pass", "", "\\d+");
|
||||
if (password_complexity ~= "true") then
|
||||
valid_password = "true";
|
||||
end
|
||||
--check password comlexity
|
||||
if (password_complexity == "true") then
|
||||
--check for length
|
||||
if (string.len(password) < tonumber(password_min_length)) then
|
||||
password_error_flag = "1";
|
||||
dtmf_digits = '';
|
||||
--freeswitch.consoleLog("notice", "[voicemail] Not long enough \n");
|
||||
session:execute("playback", "phrase:voicemail_password_below_minimum:" .. password_min_length);
|
||||
timeouts = 0;
|
||||
if (menu == "tutorial") then
|
||||
change_password(voicemail_id, "tutorial");
|
||||
end
|
||||
if (menu == "advanced") then
|
||||
change_password(voicemail_id, "advanced");
|
||||
end
|
||||
end
|
||||
|
||||
--check for repeating digits
|
||||
local repeating = {"000", "111", "222", "333", "444", "555", "666", "777", "888", "999"};
|
||||
for i = 1, 10 do
|
||||
if (string.match(password, repeating[i])) then
|
||||
password_error_flag = "1";
|
||||
dtmf_digits = '';
|
||||
--freeswitch.consoleLog("notice", "[voicemail] You can't use repeating digits like ".. repeating[i] .." \n");
|
||||
session:execute("playback", "phrase:voicemail_password_not_secure");
|
||||
timeouts = 0;
|
||||
if (menu == "tutorial") then
|
||||
change_password(voicemail_id, "tutorial");
|
||||
end
|
||||
if (menu == "advanced") then
|
||||
change_password(voicemail_id, "advanced");
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--check for squential digits
|
||||
local sequential = {"012", "123", "234", "345", "456", "567", "678", "789", "987", "876", "765", "654", "543", "432", "321", "210"};
|
||||
for i = 1, 8 do
|
||||
if (string.match(password, sequential[i])) then
|
||||
password_error_flag = "1";
|
||||
dtmf_digits = '';
|
||||
--freeswitch.consoleLog("notice", "[voicemail] You can't use sequential digits like ".. sequential[i] .." \n");
|
||||
session:execute("playback", "phrase:voicemail_password_not_secure");
|
||||
timeouts = 0;
|
||||
if (menu == "tutorial") then
|
||||
change_password(voicemail_id, "tutorial");
|
||||
end
|
||||
if (menu == "advanced") then
|
||||
change_password(voicemail_id, "advanced");
|
||||
end
|
||||
end
|
||||
end
|
||||
--password is valid
|
||||
if (password_error_flag ~= "1") then
|
||||
freeswitch.consoleLog("notice", "[voicemail] Password is valid! \n");
|
||||
valid_password = "true";
|
||||
end
|
||||
end
|
||||
--update the voicemail password
|
||||
if (valid_password == "true") then
|
||||
local sql = [[UPDATE v_voicemails
|
||||
set voicemail_password = :password
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id
|
||||
AND voicemail_enabled = 'true' ]];
|
||||
local params = {password = password, domain_uuid = domain_uuid,
|
||||
voicemail_id = voicemail_id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
--has been changed to
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_change_pass_repeat_success:" .. password);
|
||||
--advanced menu
|
||||
timeouts = 0;
|
||||
if (menu == "advanced") then
|
||||
advanced();
|
||||
end
|
||||
if (menu == "tutorial") then
|
||||
tutorial("record_greeting");
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,95 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--check the voicemail password
|
||||
function check_password(voicemail_id, password_tries)
|
||||
if (session:ready()) then
|
||||
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
|
||||
--please enter your id followed by pound
|
||||
if (voicemail_id) then
|
||||
--do nothing
|
||||
else
|
||||
timeouts = 0;
|
||||
voicemail_id = get_voicemail_id();
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] voicemail id: " .. voicemail_id .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--get the voicemail settings from the database
|
||||
if (voicemail_id) then
|
||||
if (session:ready()) then
|
||||
local sql = [[SELECT * FROM v_voicemails
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id
|
||||
AND voicemail_enabled = 'true' ]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = voicemail_id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
voicemail_uuid = string.lower(row["voicemail_uuid"]);
|
||||
voicemail_password = row["voicemail_password"];
|
||||
greeting_id = row["greeting_id"];
|
||||
voicemail_mail_to = row["voicemail_mail_to"];
|
||||
voicemail_attach_file = row["voicemail_attach_file"];
|
||||
voicemail_local_after_email = row["voicemail_local_after_email"];
|
||||
end);
|
||||
end
|
||||
end
|
||||
|
||||
--end the session if this is an invalid voicemail box
|
||||
if (not voicemail_uuid) or (#voicemail_uuid == 0) then
|
||||
return session:hangup();
|
||||
end
|
||||
|
||||
--please enter your password followed by pound
|
||||
min_digits = 2;
|
||||
max_digits = 20;
|
||||
digit_timeout = 5000;
|
||||
max_tries = 3;
|
||||
password = session:playAndGetDigits(min_digits, max_digits, max_tries, digit_timeout, "#", "phrase:voicemail_enter_pass:#", "", "\\d+");
|
||||
--freeswitch.consoleLog("notice", "[voicemail] password: " .. password .. "\n");
|
||||
|
||||
--compare the password from the database with the password provided by the user
|
||||
if (voicemail_password ~= password) then
|
||||
--incorrect password
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_fail_auth");
|
||||
if (session:ready()) then
|
||||
password_tries = password_tries + 1;
|
||||
if (password_tries < max_tries) then
|
||||
check_password(voicemail_id, password_tries);
|
||||
else
|
||||
session:execute("playback", "phrase:voicemail_goodbye");
|
||||
session:hangup();
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,167 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
local Database = require "resources.functions.database"
|
||||
|
||||
--define a function to choose the greeting
|
||||
function choose_greeting()
|
||||
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
|
||||
--select the greeting
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
greeting_id = session:playAndGetDigits(1, 1, max_tries, 5000, "#", "phrase:voicemail_choose_greeting", "", "\\d+");
|
||||
end
|
||||
|
||||
--check to see if the greeting file exists
|
||||
if (storage_type == "base64" or storage_type == "http_cache") then
|
||||
greeting_invalid = true;
|
||||
local sql = [[SELECT * FROM v_voicemail_greetings
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id
|
||||
AND greeting_id = :greeting_id]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = voicemail_id,
|
||||
greeting_id = greeting_id};
|
||||
dbh:query(sql, params, function(row)
|
||||
--greeting found
|
||||
greeting_invalid = false;
|
||||
end);
|
||||
if (greeting_invalid) then
|
||||
greeting_id = "invalid";
|
||||
end
|
||||
else
|
||||
if (greeting_id ~= "0") then
|
||||
if (not file_exists(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav")) then
|
||||
--invalid greeting_id file does not exist
|
||||
greeting_id = "invalid";
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--validate the greeting_id
|
||||
if (greeting_id == "0"
|
||||
or greeting_id == "1"
|
||||
or greeting_id == "2"
|
||||
or greeting_id == "3"
|
||||
or greeting_id == "4"
|
||||
or greeting_id == "5"
|
||||
or greeting_id == "6"
|
||||
or greeting_id == "7"
|
||||
or greeting_id == "8"
|
||||
or greeting_id == "9") then
|
||||
|
||||
--valid greeting_id update the database
|
||||
if (session:ready()) then
|
||||
local params = {domain_uuid = domain_uuid, voicemail_uuid = voicemail_uuid};
|
||||
local sql = "UPDATE v_voicemails SET "
|
||||
if (greeting_id == "0") then
|
||||
sql = sql .. "greeting_id = null ";
|
||||
else
|
||||
sql = sql .. "greeting_id = :greeting_id ";
|
||||
params.greeting_id = greeting_id;
|
||||
end
|
||||
sql = sql .. "WHERE domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "AND voicemail_uuid = :voicemail_uuid ";
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
|
||||
--get the greeting from the database
|
||||
if (storage_type == "base64") then
|
||||
local dbh = Database.new('system', 'base64/read')
|
||||
local sql = [[SELECT greeting_base64
|
||||
FROM v_voicemail_greetings
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id
|
||||
AND greeting_id = :greeting_id]];
|
||||
local params = {
|
||||
domain_uuid = domain_uuid;
|
||||
voicemail_id = voicemail_id;
|
||||
greeting_id = greeting_id;
|
||||
};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--set the voicemail message path
|
||||
greeting_location = voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav"; --vm_message_ext;
|
||||
|
||||
--save the greeting to the file system
|
||||
if (string.len(row["greeting_base64"]) > 32) then
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--write decoded string to file
|
||||
assert(file.write_base64(greeting_location, row["greeting_base64"]));
|
||||
end
|
||||
end);
|
||||
|
||||
dbh:release()
|
||||
elseif (storage_type == "http_cache") then
|
||||
greeting_location = storage_path.."/"..voicemail_id.."/greeting_"..greeting_id..".wav"; --vm_message_ext;
|
||||
end
|
||||
|
||||
--play the greeting
|
||||
if (session:ready()) then
|
||||
if (file_exists(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav")) then
|
||||
session:streamFile(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav");
|
||||
end
|
||||
end
|
||||
|
||||
--greeting selected
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_greeting_selected:" .. greeting_id);
|
||||
end
|
||||
|
||||
--advanced menu
|
||||
if (session:ready()) then
|
||||
timeouts = 0;
|
||||
advanced();
|
||||
end
|
||||
else
|
||||
--invalid greeting_id
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_choose_greeting_fail");
|
||||
end
|
||||
|
||||
--send back to choose the greeting
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
choose_greeting();
|
||||
else
|
||||
timeouts = 0;
|
||||
advanced();
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,65 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2016 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--delete the message
|
||||
function delete_recording(voicemail_id, uuid)
|
||||
--message deleted
|
||||
if (session ~= nil) then
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_ack:deleted");
|
||||
end
|
||||
end
|
||||
|
||||
--get the voicemail_uuid
|
||||
local sql = [[SELECT * FROM v_voicemails
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = voicemail_id};
|
||||
dbh:query(sql, params, function(row)
|
||||
db_voicemail_uuid = row["voicemail_uuid"];
|
||||
end);
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--delete the file
|
||||
os.remove(voicemail_dir.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext);
|
||||
os.remove(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext);
|
||||
--delete from the database
|
||||
sql = [[DELETE FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid
|
||||
AND voicemail_message_uuid = :uuid]];
|
||||
params = {domain_uuid = domain_uuid, voicemail_uuid = db_voicemail_uuid, uuid = uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
--log to console
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail][deleted] message: " .. uuid .. "\n");
|
||||
end
|
||||
--clear the variable
|
||||
db_voicemail_uuid = '';
|
||||
end
|
||||
@@ -0,0 +1,122 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2016 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define a function to forward a message to an extension
|
||||
function forward_add_intro(voicemail_id, uuid)
|
||||
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
|
||||
--request whether to add the intro
|
||||
--To add an introduction to this message press 1
|
||||
add_intro_id = session:playAndGetDigits(1, 1, 3, 5000, "#*", "phrase:voicemail_forward_prepend:1:2", "", "\\d+");
|
||||
freeswitch.consoleLog("notice", "[voicemail][forward add intro] "..add_intro_id.."\n");
|
||||
if (add_intro_id == '1') then
|
||||
|
||||
--load libraries
|
||||
local Database = require "resources.functions.database";
|
||||
local Settings = require "resources.functions.lazy_settings";
|
||||
|
||||
--connect to the database
|
||||
local db = dbh or Database.new('system');
|
||||
|
||||
--get the settings.
|
||||
local settings = Settings.new(db, domain_name, domain_uuid);
|
||||
local max_len_seconds = settings:get('voicemail', 'max_len_seconds', 'boolean') or 300;
|
||||
|
||||
--record your message at the tone press any key or stop talking to end the recording
|
||||
if (session:ready()) then
|
||||
session:execute("playback", "phrase:voicemail_record_greeting");
|
||||
session:execute("sleep", "1000");
|
||||
session:streamFile("tone_stream://L=1;%(1000, 0, 640)");
|
||||
end
|
||||
|
||||
--set the file full path
|
||||
message_location = voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext;
|
||||
message_intro_location = voicemail_dir.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext;
|
||||
|
||||
--record the message introduction
|
||||
-- syntax is session:recordFile(file_name, max_len_secs, silence_threshold, silence_secs)
|
||||
silence_seconds = 5;
|
||||
if (storage_path == "http_cache") then
|
||||
result = session:recordFile(message_intro_location, max_len_seconds, record_silence_threshold, silence_seconds);
|
||||
else
|
||||
mkdir(voicemail_dir.."/"..voicemail_id);
|
||||
if (vm_message_ext == "mp3") then
|
||||
shout_exists = trim(api:execute("module_exists", "mod_shout"));
|
||||
if (shout_exists == "true") then
|
||||
freeswitch.consoleLog("notice", "using mod_shout for mp3 encoding\n");
|
||||
--record in mp3 directly
|
||||
result = session:recordFile(message_intro_location, max_len_seconds, record_silence_threshold, silence_seconds);
|
||||
else
|
||||
--create initial wav recording
|
||||
result = session:recordFile(message_intro_location, max_len_seconds, record_silence_threshold, silence_seconds);
|
||||
--use lame to encode, if available
|
||||
if (file_exists("/usr/bin/lame")) then
|
||||
freeswitch.consoleLog("notice", "using lame for mp3 encoding\n");
|
||||
--convert the wav to an mp3 (lame required)
|
||||
resample = "/usr/bin/lame -b 32 --resample 8 -m s "..voicemail_dir.."/"..voicemail_id.."/intro_"..uuid..".wav "..message_intro_location;
|
||||
session:execute("system", resample);
|
||||
--delete the wav file, if mp3 exists
|
||||
if (file_exists(message_intro_location)) then
|
||||
os.remove(voicemail_dir.."/"..voicemail_id.."/intro_"..uuid..".wav");
|
||||
else
|
||||
vm_message_ext = "wav";
|
||||
end
|
||||
else
|
||||
freeswitch.consoleLog("notice", "neither mod_shout or lame found, defaulting to wav\n");
|
||||
vm_message_ext = "wav";
|
||||
end
|
||||
end
|
||||
else
|
||||
result = session:recordFile(message_intro_location, max_len_seconds, record_silence_threshold, silence_seconds);
|
||||
end
|
||||
end
|
||||
|
||||
--save the merged file into the database as base64
|
||||
if (storage_type == "base64") then
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--get the content of the file
|
||||
local file_content = assert(file.read_base64(message_intro_location));
|
||||
|
||||
--save the merged file as base64
|
||||
local sql = [[UPDATE SET v_voicemail_messages
|
||||
SET message_intro_base64 = :file_content
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_message_uuid = :uuid]];
|
||||
local params = {file_content = file_content, domain_uuid = domain_uuid, uuid = uuid};
|
||||
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
local dbh = Database.new('system', 'base64')
|
||||
dbh:query(sql, params)
|
||||
dbh:release()
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define a function to forward a message to an extension
|
||||
function forward_to_extension(voicemail_id, uuid)
|
||||
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
|
||||
--request the forward_voicemail_id
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
forward_voicemail_id = session:playAndGetDigits(1, 20, max_tries, digit_timeout, "#", "phrase:voicemail_forward_message_enter_extension:#", "", "\\d+");
|
||||
if (session:ready()) then
|
||||
if (string.len(forward_voicemail_id) == 0) then
|
||||
dtmf_digits = '';
|
||||
forward_voicemail_id = session:playAndGetDigits(1, 20, max_tries, digit_timeout, "#", "phrase:voicemail_forward_message_enter_extension:#", "", "\\d+");
|
||||
end
|
||||
end
|
||||
end
|
||||
if (session:ready()) then
|
||||
if (string.len(forward_voicemail_id) == 0) then
|
||||
dtmf_digits = '';
|
||||
forward_voicemail_id = session:playAndGetDigits(1, 20, max_tries, digit_timeout, "#", "phrase:voicemail_forward_message_enter_extension:#", "", "\\d+");
|
||||
end
|
||||
end
|
||||
|
||||
--get voicemail message details
|
||||
if (session:ready()) then
|
||||
local sql = [[SELECT * FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid
|
||||
AND voicemail_message_uuid = :uuid]]
|
||||
local params = {domain_uuid = domain_uuid, voicemail_uuid = voicemail_uuid, uuid = uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--get the values from the database
|
||||
created_epoch = row["created_epoch"];
|
||||
caller_id_name = row["caller_id_name"];
|
||||
caller_id_number = row["caller_id_number"];
|
||||
message_length = row["message_length"];
|
||||
message_status = row["message_status"];
|
||||
message_priority = row["message_priority"];
|
||||
message_base64 = row["message_base64"];
|
||||
end);
|
||||
end
|
||||
|
||||
--get the voicemail settings
|
||||
local sql = [[SELECT * FROM v_voicemails
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id
|
||||
AND voicemail_enabled = 'true' ]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = forward_voicemail_id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
forward_voicemail_uuid = string.lower(row["voicemail_uuid"]);
|
||||
forward_voicemail_mail_to = row["voicemail_mail_to"];
|
||||
forward_voicemail_attach_file = row["voicemail_attach_file"];
|
||||
forward_voicemail_local_after_email = row["voicemail_local_after_email"];
|
||||
end);
|
||||
|
||||
--get a new uuid
|
||||
api = freeswitch.API();
|
||||
voicemail_message_uuid = trim(api:execute("create_uuid", ""));
|
||||
|
||||
--save the message to the voicemail messages
|
||||
local sql = {}
|
||||
table.insert(sql, "INSERT INTO v_voicemail_messages ");
|
||||
table.insert(sql, "(");
|
||||
table.insert(sql, "voicemail_message_uuid, ");
|
||||
table.insert(sql, "domain_uuid, ");
|
||||
table.insert(sql, "voicemail_uuid, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(sql, "message_base64, ");
|
||||
end
|
||||
table.insert(sql, "created_epoch, ");
|
||||
table.insert(sql, "caller_id_name, ");
|
||||
table.insert(sql, "caller_id_number, ");
|
||||
table.insert(sql, "message_length ");
|
||||
--table.insert(sql, "message_status, ");
|
||||
--table.insert(sql, "message_priority, ");
|
||||
table.insert(sql, ") ");
|
||||
table.insert(sql, "VALUES ");
|
||||
table.insert(sql, "( ");
|
||||
table.insert(sql, ":voicemail_message_uuid, ");
|
||||
table.insert(sql, ":domain_uuid, ");
|
||||
table.insert(sql, ":forward_voicemail_uuid, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(sql, ":message_base64, ");
|
||||
end
|
||||
table.insert(sql, ":created_epoch, ");
|
||||
table.insert(sql, ":caller_id_name, ");
|
||||
table.insert(sql, ":caller_id_number, ");
|
||||
table.insert(sql, ":message_length ");
|
||||
--table.insert(sql, ":message_status, ");
|
||||
--table.insert(sql, ":message_priority ");
|
||||
table.insert(sql, ") ");
|
||||
sql = table.concat(sql, "\n");
|
||||
local params = {
|
||||
voicemail_message_uuid = voicemail_message_uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
forward_voicemail_uuid = forward_voicemail_uuid;
|
||||
message_base64 = message_base64;
|
||||
created_epoch = created_epoch;
|
||||
caller_id_name = caller_id_name;
|
||||
caller_id_number = caller_id_number;
|
||||
message_length = message_length;
|
||||
-- message_status = message_status;
|
||||
-- message_priority = message_priority;
|
||||
};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
if (storage_type == "base64") then
|
||||
local dbh = Database.new('system', 'base64')
|
||||
dbh:query(sql, params);
|
||||
dbh:release();
|
||||
else
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
|
||||
--offer to add an intro to the forwarded message
|
||||
forward_add_intro(forward_voicemail_id, voicemail_message_uuid);
|
||||
|
||||
--get new and saved message counts
|
||||
local new_messages, saved_messages = message_count_by_id(
|
||||
forward_voicemail_id, domain_uuid
|
||||
)
|
||||
|
||||
--send the message waiting event
|
||||
mwi_notify(forward_voicemail_id.."@"..domain_name, new_messages, saved_messages)
|
||||
blf_notify(tonumber(new_messages) > 0, "voicemail+" .. forward_voicemail_id .. "@" .. domain_name)
|
||||
|
||||
--if local after email is true then copy the recording file
|
||||
if (storage_type ~= "base64") then
|
||||
mkdir(voicemail_dir.."/"..forward_voicemail_id);
|
||||
copy(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext, voicemail_dir.."/"..forward_voicemail_id.."/msg_"..voicemail_message_uuid.."."..vm_message_ext);
|
||||
end
|
||||
|
||||
--send the email with the voicemail recording attached
|
||||
send_email(forward_voicemail_id, voicemail_message_uuid);
|
||||
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-message_forwarded.wav");
|
||||
|
||||
--delete or save the message
|
||||
local action = session:playAndGetDigits(1, 1, max_tries, digit_timeout, "#", "phrase:voicemail_post_forward_action:1:2", "", "^[1-2]$");
|
||||
if (action == "1") then
|
||||
delete_recording(voicemail_id, uuid);
|
||||
message_waiting(voicemail_id, domain_uuid);
|
||||
else
|
||||
message_saved(voicemail_id, uuid);
|
||||
session:execute("playback", "phrase:voicemail_ack:saved");
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--get the voicemail id
|
||||
function get_voicemail_id()
|
||||
session:flushDigits();
|
||||
dtmf_digits = '';
|
||||
voicemail_id = session:playAndGetDigits(1, 20, max_tries, digit_timeout, "#", "phrase:voicemail_enter_id:#", "", "\\d+");
|
||||
if (string.len(voicemail_id) == 0) then
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
voicemail_id = get_voicemail_id();
|
||||
else
|
||||
session:execute("playback", "phrase:voicemail_goodbye");
|
||||
session:hangup();
|
||||
end
|
||||
end
|
||||
end
|
||||
return voicemail_id;
|
||||
end
|
||||
+284
@@ -0,0 +1,284 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2022 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define function to listen to the recording
|
||||
function listen_to_recording (message_number, uuid, created_epoch, caller_id_name, caller_id_number, message_status)
|
||||
|
||||
--set default values
|
||||
dtmf_digits = '';
|
||||
max_digits = 1;
|
||||
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
|
||||
--set the callback function
|
||||
if (session:ready()) then
|
||||
session:setVariable("playback_terminators", "#");
|
||||
session:setInputCallback("on_dtmf", "");
|
||||
end
|
||||
|
||||
--set the display
|
||||
if (session:ready()) then
|
||||
reply = api:executeString("uuid_display "..session:get_uuid().." "..caller_id_number);
|
||||
end
|
||||
|
||||
--say the message number
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
session:execute("playback", "phrase:voicemail_say_message_number:" .. message_status .. ":" .. message_number);
|
||||
end
|
||||
end
|
||||
|
||||
--say the caller id number first (default)
|
||||
if (
|
||||
session:ready() and
|
||||
caller_id_number ~= nil and (
|
||||
vm_say_caller_id_number == nil or
|
||||
vm_say_caller_id_number == "true" or
|
||||
vm_say_caller_id_number == "before"
|
||||
)) then
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-from.wav");
|
||||
session:say(caller_id_number, default_language, "name_spelled", "iterated");
|
||||
end
|
||||
|
||||
--say the message date first (default)
|
||||
if (
|
||||
session:ready() and
|
||||
string.len(dtmf_digits) == 0 and (
|
||||
vm_say_date_time == nil or
|
||||
vm_say_date_time == "true" or
|
||||
vm_say_date_time == "before"
|
||||
)) then
|
||||
if (current_time_zone ~= nil) then
|
||||
session:execute("set", "timezone="..current_time_zone.."");
|
||||
end
|
||||
session:say(created_epoch, default_language, "current_date_time", "pronounced");
|
||||
end
|
||||
|
||||
--get the recordings from the database
|
||||
if (storage_type == "base64") then
|
||||
local dbh = Database.new('system', 'base64/read')
|
||||
|
||||
local sql = [[SELECT * FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_message_uuid = :uuid]];
|
||||
local params = {domain_uuid = domain_uuid, uuid = uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--set the voicemail message path
|
||||
mkdir(voicemail_dir.."/"..voicemail_id);
|
||||
message_intro_location = voicemail_dir.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext;
|
||||
message_location = voicemail_dir.."/"..voicemail_id.."/msg_"..uuid;
|
||||
|
||||
--save the recording to the file system
|
||||
if (string.len(row["message_intro_base64"]) > 32) then
|
||||
local file = io.open(message_intro_location, "w");
|
||||
file:write(base64.decode(row["message_intro_base64"]));
|
||||
file:close();
|
||||
end
|
||||
if (string.len(row["message_base64"]) > 32) then
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--write decoded string to file
|
||||
assert(file.write_base64(message_location, row["message_base64"]));
|
||||
end
|
||||
|
||||
--get the file type
|
||||
command = "file -b --mime-type "..message_location;
|
||||
local handle = io.popen(command);
|
||||
local mime_type = trim(handle:read("*a"));
|
||||
handle:close();
|
||||
if (mime_type == 'audio/x-wav') then
|
||||
vm_message_ext = 'wav';
|
||||
end
|
||||
if (mime_type == 'audio/mpeg') then
|
||||
vm_message_ext = 'mp3';
|
||||
end
|
||||
|
||||
--rename the file
|
||||
os.execute('mv '..message_location..' '..message_location..'.'..vm_message_ext);
|
||||
end);
|
||||
dbh:release()
|
||||
elseif (storage_type == "http_cache") then
|
||||
message_location = storage_path.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext;
|
||||
end
|
||||
|
||||
--play the message intro
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
if (file_exists(voicemail_dir.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext)) then
|
||||
stream_seek = true;
|
||||
if (storage_type == "http_cache") then
|
||||
message_intro_location = storage_path.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext;
|
||||
session:streamFile(storage_path.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext);
|
||||
else
|
||||
if (vm_message_ext == "mp3") then
|
||||
if (api:executeString("module_exists mod_vlc") == "true") then
|
||||
session:streamFile("vlc://"..voicemail_dir.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext);
|
||||
else
|
||||
session:streamFile(voicemail_dir.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext);
|
||||
end
|
||||
else
|
||||
session:streamFile(voicemail_dir.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext);
|
||||
end
|
||||
end
|
||||
stream_seek = false;
|
||||
--session:streamFile("silence_stream://1000");
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--play the message
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
--check if wav file exists then play the file
|
||||
if (file_exists(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".wav")) then
|
||||
stream_seek = true;
|
||||
if (storage_type == "http_cache") then
|
||||
message_location = storage_path.."/"..voicemail_id.."/msg_"..uuid..".wav";
|
||||
session:streamFile(storage_path.."/"..voicemail_id.."/msg_"..uuid..".wav");
|
||||
else
|
||||
session:streamFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".wav");
|
||||
end
|
||||
stream_seek = false;
|
||||
session:streamFile("silence_stream://1000");
|
||||
end
|
||||
|
||||
--check if mp3 file exists then play the file
|
||||
if (file_exists(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".mp3")) then
|
||||
stream_seek = true;
|
||||
if (storage_type == "http_cache") then
|
||||
message_location = storage_path.."/"..voicemail_id.."/msg_"..uuid..".mp3";
|
||||
session:streamFile(storage_path.."/"..voicemail_id.."/msg_"..uuid..".mp3");
|
||||
else
|
||||
if (api:executeString("module_exists mod_vlc") == "true") then
|
||||
session:streamFile("vlc://"..voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".mp3");
|
||||
else
|
||||
session:streamFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".mp3");
|
||||
end
|
||||
end
|
||||
stream_seek = false;
|
||||
session:streamFile("silence_stream://1000");
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--remove the voicemail message
|
||||
if (storage_type == "base64") then
|
||||
os.remove(voicemail_dir.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext);
|
||||
os.remove(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext);
|
||||
end
|
||||
|
||||
--say the caller id number last (optional)
|
||||
if (
|
||||
session:ready() and
|
||||
caller_id_number ~= nil and
|
||||
vm_say_caller_id_number ~= nil and
|
||||
(
|
||||
vm_say_caller_id_number == "last" or
|
||||
vm_say_caller_id_number == "after"
|
||||
)) then
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-from.wav");
|
||||
session:say(caller_id_number, default_language, "name_spelled", "iterated");
|
||||
end
|
||||
|
||||
--say the message date last (optional)
|
||||
if (
|
||||
session:ready() and
|
||||
string.len(dtmf_digits) == 0 and
|
||||
vm_say_date_time ~= nil and
|
||||
(
|
||||
vm_say_date_time == "last" or
|
||||
vm_say_date_time == "after"
|
||||
)) then
|
||||
if (current_time_zone ~= nil) then
|
||||
session:execute("set", "timezone="..current_time_zone.."");
|
||||
end
|
||||
session:say(created_epoch, default_language, "current_date_time", "pronounced");
|
||||
end
|
||||
|
||||
--post listen options
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(1, 1, max_tries, digit_timeout, "#", "phrase:voicemail_listen_file_options:1:2:3:5:7:8:9:0", "", "^[\\d\\*#]$");
|
||||
end
|
||||
end
|
||||
|
||||
--wait for more digits
|
||||
--if (session:ready()) then
|
||||
-- if (string.len(dtmf_digits) == 0) then
|
||||
-- dtmf_digits = session:getDigits(max_digits, "#", 1, 3000);
|
||||
-- end
|
||||
--end
|
||||
|
||||
--process the dtmf
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == "1") then
|
||||
return listen_to_recording(message_number, uuid, created_epoch, caller_id_name, caller_id_number, message_status);
|
||||
elseif (dtmf_digits == "2") then
|
||||
message_saved(voicemail_id, uuid);
|
||||
session:execute("playback", "phrase:voicemail_ack:saved");
|
||||
elseif (dtmf_digits == "3") then
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-from.wav");
|
||||
session:say(caller_id_number, default_language, "name_spelled", "iterated");
|
||||
if (current_time_zone ~= nil) then
|
||||
session:execute("set", "timezone="..current_time_zone.."");
|
||||
end
|
||||
session:say(created_epoch, default_language, "current_date_time", "pronounced");
|
||||
elseif (dtmf_digits == "5") then
|
||||
message_saved(voicemail_id, uuid);
|
||||
return_call(caller_id_number);
|
||||
elseif (dtmf_digits == "7") then
|
||||
delete_recording(voicemail_id, uuid);
|
||||
message_waiting(voicemail_id, domain_uuid);
|
||||
--fix for extensions that start with 0 (Ex: 0712)
|
||||
if (voicemail_id_copy ~= voicemail_id and voicemail_id_copy ~= nil) then
|
||||
message_waiting(voicemail_id_copy, domain_uuid);
|
||||
end
|
||||
elseif (dtmf_digits == "8") then
|
||||
forward_to_extension(voicemail_id, uuid);
|
||||
dtmf_digits = '';
|
||||
elseif (dtmf_digits == "9") then
|
||||
send_email(voicemail_id, uuid);
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_ack:emailed");
|
||||
elseif (dtmf_digits == "*") then
|
||||
timeouts = 0;
|
||||
return main_menu();
|
||||
elseif (dtmf_digits == "0") then
|
||||
message_saved(voicemail_id, uuid);
|
||||
session:transfer("0", "XML", context);
|
||||
elseif (dtmf_digits == "#") then
|
||||
return;
|
||||
else
|
||||
message_saved(voicemail_id, uuid);
|
||||
session:execute("playback", "phrase:voicemail_ack:saved");
|
||||
end
|
||||
session:execute("sleep", "400");
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,365 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 - 2016 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define the macro function
|
||||
function macro(session, name, max_digits, max_timeout, param)
|
||||
if (session:ready()) then
|
||||
--create an empty table
|
||||
actions = {}
|
||||
|
||||
--Please enter your id followed by
|
||||
if (name == "voicemail_id") then
|
||||
table.insert(actions, {app="streamFile",data="phrase:voicemail_enter_id:#"});
|
||||
end
|
||||
--Please enter your id followed by
|
||||
if (name == "voicemail_password") then
|
||||
table.insert(actions, {app="streamFile",data="phrase:voicemail_enter_pass:#"});
|
||||
end
|
||||
--the person at extension 101 is not available record your message at the tone press any key or stop talking to end the recording
|
||||
if (name == "person_not_available_record_message") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-person.wav"});
|
||||
--pronounce the voicemail_id
|
||||
if (voicemail_alternate_greet_id and string.len(voicemail_alternate_greet_id) > 0) then
|
||||
table.insert(actions, {app="say.number.iterated",data=voicemail_alternate_greet_id});
|
||||
elseif (voicemail_greet_id and string.len(voicemail_greet_id) > 0) then
|
||||
table.insert(actions, {app="say.number.iterated",data=voicemail_greet_id});
|
||||
else
|
||||
table.insert(actions, {app="say.number.iterated",data=voicemail_id});
|
||||
end
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-not_available.wav"});
|
||||
end
|
||||
--record your message at the tone press any key or stop talking to end the recording
|
||||
if (name == "record_message") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-record_message.wav"});
|
||||
end
|
||||
--beep
|
||||
if (name == "record_beep") then
|
||||
table.insert(actions, {app="tone_stream",data="L=1;%(1000, 0, 640)"});
|
||||
end
|
||||
--to listen to the recording press 1
|
||||
if (name == "to_listen_to_recording") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-listen_to_recording.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/1.wav"});
|
||||
end
|
||||
--to save the recording press 2
|
||||
if (name == "to_save_recording") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-save_recording.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/2.wav"});
|
||||
end
|
||||
--to rerecord press 3
|
||||
if (name == "to_rerecord") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-rerecord.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/3.wav"});
|
||||
end
|
||||
--You have zero new messages
|
||||
if (name == "new_messages") then
|
||||
table.insert(actions, {app="streamFile",data="phrase:voicemail_message_count:" .. param .. ":new"})
|
||||
end
|
||||
--You have zero saved messages
|
||||
if (name == "saved_messages") then
|
||||
table.insert(actions, {app="streamFile",data="phrase:voicemail_message_count:" .. param .. ":saved"})
|
||||
end
|
||||
--To listen to new messages press 1
|
||||
if (name == "listen_to_new_messages") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-listen_new.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/1.wav"});
|
||||
end
|
||||
--To listen to saved messages press 2
|
||||
if (name == "listen_to_saved_messages") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-listen_saved.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/2.wav"});
|
||||
end
|
||||
|
||||
--For advanced options press 5
|
||||
if (name == "advanced") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-advanced.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/5.wav"});
|
||||
end
|
||||
--Advanced Options Menu
|
||||
--To record a greeting press 1
|
||||
if (name == "to_record_greeting") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-to_record_greeting.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/1.wav"});
|
||||
end
|
||||
--Choose a greeting between 1 and 9
|
||||
if (name == "choose_greeting_choose") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-choose_greeting_choose.wav"});
|
||||
end
|
||||
--Greeting invalid value
|
||||
if (name == "choose_greeting_fail") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-choose_greeting_fail.wav"});
|
||||
end
|
||||
--Record your greeting at the tone press any key or stop talking to end the recording
|
||||
if (name == "record_greeting") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-record_greeting.wav"});
|
||||
table.insert(actions, {app="tone_stream",data="L=1;%(1000, 0, 640)"});
|
||||
end
|
||||
--To choose greeting press 2
|
||||
if (name == "choose_greeting") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-choose_greeting.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/2.wav"});
|
||||
end
|
||||
--Greeting 1 selected
|
||||
if (name == "greeting_selected") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-greeting.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/"..param..".wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-selected.wav"});
|
||||
end
|
||||
|
||||
--To record your name 3
|
||||
if (name == "to_record_name") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-record_name2.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/3.wav"});
|
||||
end
|
||||
--At the tone please record your name press any key or stop talking to end the recording
|
||||
if (name == "record_name") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-record_name1.wav"});
|
||||
table.insert(actions, {app="tone_stream",data="L=1;%(2000, 0, 640)"});
|
||||
end
|
||||
--To change your password press 6
|
||||
if (name == "change_password") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-change_password.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/6.wav"});
|
||||
end
|
||||
--For the main menu press 0
|
||||
if (name == "main_menu") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-main_menu.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/0.wav"});
|
||||
end
|
||||
--To exit press *
|
||||
if (name == "to_exit_press") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-to_exit.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/star.wav"});
|
||||
end
|
||||
--Additional Macros
|
||||
--Please enter your new password then press the # key #
|
||||
if (name == "password_new") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-enter_new_pin.wav"});
|
||||
end
|
||||
--Has been changed to
|
||||
if (name == "password_changed") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-has_been_changed_to.wav"});
|
||||
table.insert(actions, {app="say.number.iterated",data=param});
|
||||
end
|
||||
--Login Incorrect
|
||||
--if (name == "password_not_valid") then
|
||||
-- table.insert(actions, {app="streamFile",data="voicemail/vm-password_not_valid.wav"});
|
||||
--end
|
||||
--Login Incorrect
|
||||
if (name == "password_not_valid") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-fail_auth.wav"});
|
||||
end
|
||||
--Too many failed attempts
|
||||
if (name == "too_many_failed_attempts") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-abort.wav"});
|
||||
end
|
||||
--Message number
|
||||
if (name == "message_number") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-message_number.wav"});
|
||||
end
|
||||
--To listen to the recording press 1
|
||||
if (name == "listen_to_recording") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-listen_to_recording.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/1.wav"});
|
||||
end
|
||||
--To save the recording press 2
|
||||
if (name == "save_recording") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-save_recording.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/2.wav"});
|
||||
end
|
||||
--To delete the recording press 7
|
||||
if (name == "delete_recording") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-delete_recording.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/7.wav"});
|
||||
end
|
||||
--Message deleted
|
||||
if (name == "message_deleted") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-message.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-deleted.wav"});
|
||||
end
|
||||
--To return the call now press 5
|
||||
if (name == "return_call") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-return_call.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/5.wav"});
|
||||
end
|
||||
--To add an introduction to this message press 1
|
||||
if (name == "forward_add_intro") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-forward_add_intro.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/1.wav"});
|
||||
end
|
||||
--To forward this message press 8
|
||||
if (name == "to_forward_message") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-to_forward.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/8.wav"});
|
||||
end
|
||||
--Please enter the extension to forward this message to followed by #
|
||||
if (name == "forward_enter_extension") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-forward_enter_ext.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-followed_by.wav"});
|
||||
table.insert(actions, {app="streamFile",data="ascii/35.wav"});
|
||||
end
|
||||
--To forward this recording to your email press 9
|
||||
if (name == "forward_to_email") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-forward_to_email.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/9.wav"});
|
||||
end
|
||||
--Emailed
|
||||
if (name == "emailed") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-emailed.wav"});
|
||||
end
|
||||
--Please enter the extension to send this message to followed by #
|
||||
--if (name == "send_message_to_extension") then
|
||||
-- table.insert(actions, {app="streamFile",data="voicemail/vm-zzz.wav"});
|
||||
--end
|
||||
--Message saved
|
||||
if (name == "message_saved") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-message.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-saved.wav"});
|
||||
end
|
||||
--Your recording is below the minimal acceptable length, please try again.
|
||||
if (name == "too_small") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-too-small.wav"});
|
||||
end
|
||||
--Goodbye
|
||||
if (name == "goodbye") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-goodbye.wav"});
|
||||
end
|
||||
--Password is not secure
|
||||
if (name == "password_not_secure") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-password_is_not_secure.wav"});
|
||||
end
|
||||
--Password is below minimum length
|
||||
if (name == "password_below_minimum") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-pin_below_minimum_length.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-minimum_pin_length_is.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/"..param..".wav"});
|
||||
end
|
||||
--Tutorial
|
||||
--Tutorial intro
|
||||
if (name == "tutorial_intro") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-tutorial_yes_no.wav"});
|
||||
end
|
||||
|
||||
--Tutorial to record your name 1
|
||||
if (name == "tutorial_to_record_name") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-tutorial_record_name.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-record_name2.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/1.wav"});
|
||||
end
|
||||
|
||||
--Tutorial to change your password press 1
|
||||
if (name == "tutorial_change_password") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-tutorial_change_pin.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-change_password.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/1.wav"});
|
||||
end
|
||||
|
||||
--Tutorial to record your greeting press 1
|
||||
if (name == "tutorial_record_greeting") then
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-to_record_greeting.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/1.wav"});
|
||||
end
|
||||
|
||||
--Tutorial To skip
|
||||
if (name == "tutorial_skip") then
|
||||
table.insert(actions, {app="streamFile",data="ivr/ivr-to_skip.wav"});
|
||||
table.insert(actions, {app="streamFile",data="voicemail/vm-press.wav"});
|
||||
table.insert(actions, {app="streamFile",data="digits/2.wav"});
|
||||
end
|
||||
|
||||
--if actions table exists then process it
|
||||
if (actions) then
|
||||
--set default values
|
||||
tries = 1;
|
||||
timeout = 100;
|
||||
--loop through the action and data
|
||||
for key, row in pairs(actions) do
|
||||
-- freeswitch.consoleLog("notice", "[voicemail] app: " .. row.app .. " data: " .. row.data .. "\n");
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
if (row.app == "streamFile") then
|
||||
if string.find(row.data, ':', nil, true) then
|
||||
session:streamFile(row.data);
|
||||
else
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/"..row.data);
|
||||
end
|
||||
elseif (row.app == "playback") then
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/"..row.data);
|
||||
elseif (row.app == "tone_stream") then
|
||||
session:streamFile("tone_stream://"..row.data);
|
||||
elseif (row.app == "silence_stream") then
|
||||
session:streamFile("silence_stream://100"..row.data);
|
||||
elseif (row.app == "playAndGetDigits") then
|
||||
--playAndGetDigits <min> <max> <tries> <timeout> <terminators> <file> <invalid_file> <var_name> <regexp> <digit_timeout>
|
||||
if (not file_exists(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/"..row.data)) then
|
||||
dtmf_digits = session:playAndGetDigits(min_digits, max_digits, tries, timeout, "#", sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/"..row.data, "", "\\d+", max_timeout);
|
||||
else
|
||||
dtmf_digits = session:playAndGetDigits(min_digits, max_digits, tries, timeout, "#", row.data, "", "\\d+", max_timeout);
|
||||
end
|
||||
elseif (row.app == "say.number.pronounced") then
|
||||
session:say(row.data, default_language, "number", "pronounced");
|
||||
elseif (row.app == "say.number.iterated") then
|
||||
session:say(row.data, default_language, "number", "iterated");
|
||||
end
|
||||
--session:streamFile("silence_stream://100");
|
||||
end --if
|
||||
end --session:ready
|
||||
end --for
|
||||
--get the remaining digits
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) < max_digits) then
|
||||
dtmf_digits = dtmf_digits .. session:getDigits(max_digits, "#", max_timeout);
|
||||
end
|
||||
end
|
||||
--return dtmf the digits
|
||||
return dtmf_digits;
|
||||
else
|
||||
--no dtmf digits to return
|
||||
return '';
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,126 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define function main menu
|
||||
function main_menu ()
|
||||
if (voicemail_uuid) then
|
||||
--clear the value
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
if (session ~= nil) then
|
||||
session:flushDigits();
|
||||
end
|
||||
--answer the session
|
||||
if (session ~= nil) then
|
||||
session:answer();
|
||||
session:execute("sleep", "1000");
|
||||
end
|
||||
|
||||
--new voicemail count
|
||||
if (session:ready()) then
|
||||
local sql = [[SELECT count(*) as new_messages FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid
|
||||
AND (message_status is null or message_status = '') ]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_uuid = voicemail_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
new_messages = row["new_messages"];
|
||||
end);
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 300, "#", "phrase:voicemail_message_count:" .. new_messages .. ":new", "", "\\d+");
|
||||
end
|
||||
--saved voicemail count
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
sql = [[SELECT count(*) as saved_messages FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid
|
||||
AND message_status = 'saved' ]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_uuid = voicemail_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
saved_messages = row["saved_messages"];
|
||||
end);
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 300, "#", "phrase:voicemail_message_count:" .. saved_messages .. ":saved", "", "\\d+");
|
||||
end
|
||||
end
|
||||
|
||||
--to listen to new message
|
||||
if (session:ready() and new_messages ~= '0') then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 100, "#", "phrase:voicemail_main_menu:new:1", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--to listen to saved message
|
||||
if (session:ready() and saved_messages ~= '0') then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 100, "#", "phrase:voicemail_main_menu:saved:2", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--for advanced options
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 3000, "#", "phrase:voicemail_main_menu:advanced:5", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--to exit press #
|
||||
--if (session:ready()) then
|
||||
-- if (string.len(dtmf_digits) == 0) then
|
||||
-- dtmf_digits = macro(session, "to_exit_press", 1, 3000, '');
|
||||
-- end
|
||||
--end
|
||||
--process the dtmf
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == "1") then
|
||||
menu_messages("new");
|
||||
elseif (dtmf_digits == "2") then
|
||||
menu_messages("saved");
|
||||
elseif (dtmf_digits == "5") then
|
||||
timeouts = 0;
|
||||
advanced();
|
||||
elseif (dtmf_digits == "0") then
|
||||
main_menu();
|
||||
elseif (dtmf_digits == "*") then
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_goodbye");
|
||||
session:hangup();
|
||||
else
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
main_menu();
|
||||
else
|
||||
session:execute("playback", "phrase:voicemail_goodbye");
|
||||
session:hangup();
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,116 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2017 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define function for messages menu
|
||||
function menu_messages (message_status)
|
||||
|
||||
--set default values
|
||||
max_timeout = 2000;
|
||||
min_digits = 1;
|
||||
max_digits = 1;
|
||||
tries = 1;
|
||||
timeout = 2000;
|
||||
--clear the dtmf
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
--session:flushDigits();
|
||||
--set the message number
|
||||
message_number = 0;
|
||||
--message_status new,saved
|
||||
if (session:ready()) then
|
||||
if (voicemail_id ~= nil) then
|
||||
--get the voicemail_id
|
||||
--fix for extensions that start with 0 (Ex: 0712)
|
||||
sql = [[SELECT voicemail_id FROM v_voicemails WHERE voicemail_uuid = :voicemail_uuid]];
|
||||
local params = {voicemail_uuid = voicemail_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(result)
|
||||
voicemail_id_copy = result["voicemail_id"];
|
||||
end);
|
||||
|
||||
local sql = [[SELECT voicemail_message_uuid, created_epoch, caller_id_name, caller_id_number
|
||||
FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid ]]
|
||||
if (message_status == "new") then
|
||||
sql = sql .. [[AND (message_status is null or message_status = '') ]];
|
||||
elseif (message_status == "saved") then
|
||||
sql = sql .. [[AND message_status = 'saved' ]];
|
||||
end
|
||||
sql = sql .. [[ORDER BY created_epoch ]]..message_order;
|
||||
local params = {domain_uuid = domain_uuid, voicemail_uuid = voicemail_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--get the values from the database
|
||||
--row["voicemail_message_uuid"];
|
||||
--row["created_epoch"];
|
||||
--row["caller_id_name"];
|
||||
--row["caller_id_number"];
|
||||
--row["message_length"];
|
||||
--row["message_status"];
|
||||
--row["message_priority"];
|
||||
--increment the message count
|
||||
message_number = message_number + 1;
|
||||
--listen to the message
|
||||
if (session:ready()) then
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", message_number.." "..string.lower(row["voicemail_message_uuid"]).." "..row["created_epoch"]);
|
||||
end
|
||||
return listen_to_recording(message_number, string.lower(row["voicemail_message_uuid"]), row["created_epoch"], row["caller_id_name"], row["caller_id_number"], message_status);
|
||||
end
|
||||
end);
|
||||
end
|
||||
end
|
||||
|
||||
--voicemail count if zero new messages set the mwi to no
|
||||
if session:ready() and voicemail_id and voicemail_uuid and #voicemail_uuid > 0 then
|
||||
--get new and saved message counts
|
||||
local new_messages, saved_messages = message_count_by_uuid(
|
||||
voicemail_uuid, domain_uuid
|
||||
)
|
||||
--send the message waiting event
|
||||
mwi_notify(voicemail_id.."@"..domain_name, new_messages, saved_messages)
|
||||
blf_notify(tonumber(new_messages) > 0, "voicemail+" .. voicemail_id .. "@" .. domain_name)
|
||||
--fix for extensions that start with 0 (Ex: 0712)
|
||||
if (voicemail_id_copy ~= voicemail_id and voicemail_id_copy ~= nil) then
|
||||
message_waiting(voicemail_id_copy, domain_uuid);
|
||||
end
|
||||
end
|
||||
|
||||
--set the display
|
||||
if (session:ready()) then
|
||||
reply = api:executeString("uuid_display "..session:get_uuid().." "..destination_number);
|
||||
end
|
||||
|
||||
--send back to the main menu
|
||||
if (session:ready()) then
|
||||
timeouts = 0;
|
||||
return main_menu();
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,74 @@
|
||||
local log = require "resources.functions.log"["voicemail-count"]
|
||||
|
||||
-- Tested SQL on SQLite 3, PgSQL 9.5, MySQL 5.5 and MariaDB 10
|
||||
|
||||
local message_count_by_uuid_sql = [[SELECT
|
||||
( SELECT count(*)
|
||||
FROM v_voicemail_messages
|
||||
WHERE voicemail_uuid = :voicemail_uuid
|
||||
AND (message_status is null or message_status = '')
|
||||
) as new_messages,
|
||||
|
||||
( SELECT count(*)
|
||||
FROM v_voicemail_messages
|
||||
WHERE voicemail_uuid = :voicemail_uuid
|
||||
AND message_status = 'saved'
|
||||
) as saved_messages
|
||||
]]
|
||||
|
||||
function message_count_by_uuid(voicemail_uuid)
|
||||
local new_messages, saved_messages = "0", "0"
|
||||
|
||||
local params = {voicemail_uuid = voicemail_uuid};
|
||||
|
||||
if debug["sql"] then
|
||||
log.noticef("SQL: %s; params: %s", message_count_by_uuid_sql, json.encode(params))
|
||||
end
|
||||
|
||||
dbh:query(message_count_by_uuid_sql, params, function(row)
|
||||
new_messages, saved_messages = row.new_messages, row.saved_messages
|
||||
end)
|
||||
|
||||
if debug["info"] then
|
||||
log.noticef("mailbox uuid: %s messages: %s/%s", voicemail_uuid, new_messages, saved_messages)
|
||||
end
|
||||
|
||||
return new_messages, saved_messages
|
||||
end
|
||||
|
||||
local message_count_by_id_sql = [[SELECT
|
||||
( SELECT count(*)
|
||||
FROM v_voicemail_messages as m inner join v_voicemails as v
|
||||
on v.voicemail_uuid = m.voicemail_uuid
|
||||
WHERE v.voicemail_id = :voicemail_id AND v.domain_uuid = :domain_uuid
|
||||
AND (m.message_status is null or m.message_status = '')
|
||||
) as new_messages,
|
||||
|
||||
( SELECT count(*)
|
||||
FROM v_voicemail_messages as m inner join v_voicemails as v
|
||||
on v.voicemail_uuid = m.voicemail_uuid
|
||||
WHERE v.voicemail_id = :voicemail_id AND v.domain_uuid = :domain_uuid
|
||||
AND m.message_status = 'saved'
|
||||
) as saved_messages
|
||||
]]
|
||||
|
||||
function message_count_by_id(voicemail_id, domain_uuid)
|
||||
local new_messages, saved_messages = "0", "0"
|
||||
|
||||
local params = {voicemail_id = voicemail_id, domain_uuid = domain_uuid};
|
||||
|
||||
if debug["sql"] then
|
||||
log.noticef("SQL: %s; params: %s", message_count_by_id_sql, json.encode(params))
|
||||
end
|
||||
|
||||
dbh:query(message_count_by_id_sql, params, function(row)
|
||||
new_messages, saved_messages = row.new_messages, row.saved_messages
|
||||
end)
|
||||
|
||||
if debug["info"] then
|
||||
log.noticef("mailbox: %s messages: %s/%s", voicemail_id, new_messages, saved_messages)
|
||||
end
|
||||
|
||||
return new_messages, saved_messages
|
||||
end
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--save the message
|
||||
function message_saved(voicemail_id, uuid)
|
||||
--clear the dtmf
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--get the voicemail_uuid
|
||||
local sql = [[SELECT * FROM v_voicemails
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = voicemail_id};
|
||||
dbh:query(sql, params, function(row)
|
||||
db_voicemail_uuid = row["voicemail_uuid"];
|
||||
end);
|
||||
--delete from the database
|
||||
sql = [[UPDATE v_voicemail_messages SET message_status = 'saved'
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid
|
||||
AND voicemail_message_uuid = :uuid]];
|
||||
params = {domain_uuid = domain_uuid, voicemail_uuid = db_voicemail_uuid, uuid = uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
--log to console
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail][saved] id: " .. voicemail_id .. " message: "..uuid.."\n");
|
||||
end
|
||||
--check the message waiting status
|
||||
message_waiting(voicemail_id, domain_uuid);
|
||||
--clear the variable
|
||||
db_voicemail_uuid = '';
|
||||
end
|
||||
@@ -0,0 +1,71 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2016 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--voicemail count if zero new messages set the mwi to no
|
||||
function message_waiting(voicemail_id, domain_uuid)
|
||||
|
||||
--initialize the array and add the voicemail_id
|
||||
local accounts = {}
|
||||
|
||||
--add the current voicemail id to the accounts array
|
||||
table.insert(accounts, voicemail_id);
|
||||
|
||||
--get the voicemail id and all related mwi accounts
|
||||
local sql = [[SELECT extension, number_alias from v_extensions
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND (
|
||||
mwi_account = :voicemail_id
|
||||
or mwi_account = :mwi_account
|
||||
or number_alias = :voicemail_id
|
||||
)]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = voicemail_id,
|
||||
mwi_account = voicemail_id .. "@" .. domain_name};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
table.insert(accounts, row["extension"]);
|
||||
end);
|
||||
|
||||
--get new and saved message counts
|
||||
local new_messages, saved_messages = message_count_by_id(voicemail_id, domain_uuid);
|
||||
|
||||
--send the message waiting event
|
||||
for _,value in ipairs(accounts) do
|
||||
--add the domain to voicemail id
|
||||
local account = value.."@"..domain_name;
|
||||
--send the message waiting notifications
|
||||
mwi_notify(account, new_messages, saved_messages);
|
||||
blf_notify(tonumber(new_messages) > 0, "voicemail+" .. voicemail_id .. "@" .. domain_name)
|
||||
--send information to the console
|
||||
if (debug["info"]) then
|
||||
if new_messages == "0" then
|
||||
freeswitch.consoleLog("notice", "[voicemail] mailbox: "..account.." messages: no new messages\n");
|
||||
else
|
||||
freeswitch.consoleLog("notice", "[voicemail] mailbox: "..account.." messages: " .. new_messages .. " new message(s)\n");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,56 @@
|
||||
|
||||
--define a function to send mwi notify
|
||||
function mwi_notify(account, new_messages, saved_messages)
|
||||
|
||||
--includes
|
||||
require "resources.functions.explode"
|
||||
require "resources.functions.trim"
|
||||
|
||||
--create the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
local sofia_contacts = trim(api:executeString("sofia_contact */"..account));
|
||||
local sofia_contact_table = explode(",", sofia_contacts);
|
||||
|
||||
local sip_profile_table = {};
|
||||
|
||||
for key,value in pairs(sofia_contact_table) do
|
||||
f = explode("/", value);
|
||||
sip_profile = f[2];
|
||||
|
||||
|
||||
--check to see if a notify has already been sent to this profile
|
||||
new = "true";
|
||||
for profile_index, profile_table_value in pairs(sip_profile_table) do
|
||||
if profile_table_value == sip_profile then
|
||||
new = "false";
|
||||
end
|
||||
end
|
||||
|
||||
if new == "true" then
|
||||
--debug info
|
||||
--freeswitch.consoleLog("NOTICE", "sofia_contact */"..account.."\n");
|
||||
--freeswitch.consoleLog("NOTICE", "sip_profile="..sip_profile.."\n");
|
||||
--freeswitch.consoleLog("NOTICE", "sofia_contacts="..sofia_contacts.."\n");
|
||||
|
||||
--set the variables
|
||||
new_messages = tonumber(new_messages) or 0
|
||||
saved_messages = tonumber(saved_messages) or 0
|
||||
|
||||
--set the event and send it
|
||||
local event = freeswitch.Event("message_waiting")
|
||||
event:addHeader("MWI-Messages-Waiting", (new_messages == 0) and "no" or "yes")
|
||||
event:addHeader("MWI-Message-Account", "sip:" .. account)
|
||||
event:addHeader("MWI-Voice-Message", string.format("%d/%d (0/0)", new_messages, saved_messages))
|
||||
event:addHeader("sofia-profile", sip_profile)
|
||||
event:fire()
|
||||
|
||||
table.insert(sip_profile_table,sip_profile);
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--return module value
|
||||
return mwi_notify
|
||||
@@ -0,0 +1,60 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define on_dtmf call back function
|
||||
function on_dtmf(s, type, obj, arg)
|
||||
if (type == "dtmf") then
|
||||
freeswitch.console_log("info", "[voicemail] dtmf digit: " .. obj['digit'] .. ", duration: " .. obj['duration'] .. "\n");
|
||||
if (obj['digit'] == "#") then
|
||||
return 0;
|
||||
else
|
||||
dtmf_digits = dtmf_digits .. obj['digit'];
|
||||
if (debug["info"]) then
|
||||
freeswitch.console_log("info", "[voicemail] dtmf digits: " .. dtmf_digits .. ", length: ".. string.len(dtmf_digits) .." max_digits: " .. max_digits .. "\n");
|
||||
end
|
||||
if (stream_seek == true) then
|
||||
if (dtmf_digits == "4") then
|
||||
dtmf_digits = "";
|
||||
return("seek:-5000");
|
||||
end
|
||||
if (dtmf_digits == "5") then
|
||||
dtmf_digits = "";
|
||||
return("pause");
|
||||
end
|
||||
if (dtmf_digits == "6") then
|
||||
dtmf_digits = "";
|
||||
return("seek:+5000");
|
||||
end
|
||||
end
|
||||
if (string.len(dtmf_digits) >= max_digits) then
|
||||
if (debug["info"]) then
|
||||
freeswitch.console_log("info", "[voicemail] max_digits reached\n");
|
||||
end
|
||||
return 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
return 0;
|
||||
end
|
||||
@@ -0,0 +1,126 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
local Database = require"resources.functions.database"
|
||||
|
||||
--play the greeting
|
||||
function play_greeting()
|
||||
timeout = 100;
|
||||
tries = 1;
|
||||
max_timeout = 200;
|
||||
|
||||
--voicemail prompt
|
||||
if (skip_greeting == "true") then
|
||||
--skip the greeting
|
||||
else
|
||||
if (session:ready()) then
|
||||
--set the greeting based on the voicemail_greeting_number variable
|
||||
if (voicemail_greeting_number ~= nil) then
|
||||
if (string.len(voicemail_greeting_number) > 0) then
|
||||
greeting_id = voicemail_greeting_number;
|
||||
end
|
||||
end
|
||||
|
||||
--play the greeting
|
||||
dtmf_digits = '';
|
||||
if (string.len(greeting_id) > 0 and greeting_id ~= "default") then
|
||||
|
||||
--greeting set to none, return without a greeting
|
||||
if (greeting_id == "0") then
|
||||
return true;
|
||||
end
|
||||
|
||||
--sleep
|
||||
session:execute("playback","silence_stream://200");
|
||||
|
||||
--get the greeting from the database
|
||||
if (storage_type == "base64") then
|
||||
local dbh = Database.new('system', 'base64/read')
|
||||
|
||||
local sql = [[SELECT * FROM v_voicemail_greetings
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id
|
||||
AND greeting_id = :greeting_id ]];
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = voicemail_id,
|
||||
greeting_id = greeting_id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
local saved
|
||||
dbh:query(sql, params, function(row)
|
||||
--set the voicemail message path
|
||||
mkdir(voicemail_dir.."/"..voicemail_id);
|
||||
greeting_location = voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav"; --vm_message_ext;
|
||||
|
||||
--if not found, save greeting to local file system
|
||||
--saved = file_exists(greeting_location)
|
||||
--if not saved then
|
||||
if (string.len(row["greeting_base64"]) > 32) then
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--write decoded string to file
|
||||
saved = file.write_base64(greeting_location, row["greeting_base64"]);
|
||||
end
|
||||
--end
|
||||
end);
|
||||
dbh:release();
|
||||
|
||||
if saved then
|
||||
--play the greeting
|
||||
dtmf_digits = session:playAndGetDigits(0, max_digits, tries, timeout, "#", voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav", "", ".*", max_timeout);
|
||||
--session:execute("playback",voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav");
|
||||
|
||||
--delete the greeting (retain local for better responsiveness)
|
||||
--os.remove(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav");
|
||||
end
|
||||
elseif (storage_type == "http_cache") then
|
||||
dtmf_digits = session:playAndGetDigits(0, max_digits, tries, timeout, "#", voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav", "", ".*", max_timeout);
|
||||
--session:execute("playback",storage_path.."/"..voicemail_id.."/greeting_"..greeting_id..".wav");
|
||||
else
|
||||
greeting_ext = 'wav';
|
||||
if (file_exists(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".mp3")) then
|
||||
greeting_ext = "mp3";
|
||||
end
|
||||
dtmf_digits = session:playAndGetDigits(0, max_digits, tries, timeout, "#", voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id.."."..greeting_ext, "",".*", max_timeout);
|
||||
--session:execute("playback",voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav");
|
||||
end
|
||||
|
||||
else
|
||||
--default greeting
|
||||
session:execute("playback","silence_stream://200");
|
||||
--determine the voicemail_id to say
|
||||
if (voicemail_alternate_greet_id and string.len(voicemail_alternate_greet_id) > 0) then
|
||||
voicemail_id_say = voicemail_alternate_greet_id;
|
||||
elseif (voicemail_greet_id and string.len(voicemail_greet_id) > 0) then
|
||||
voicemail_id_say = voicemail_greet_id;
|
||||
else
|
||||
voicemail_id_say = voicemail_id;
|
||||
end
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 200, "#", "phrase:voicemail_play_greeting:" .. voicemail_id_say, "", ".*");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,139 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--load libraries
|
||||
local Database = require "resources.functions.database"
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
|
||||
--define a function to record the greeting
|
||||
function record_greeting(greeting_id, menu)
|
||||
|
||||
--setup the database connection
|
||||
local db = dbh or Database.new('system')
|
||||
|
||||
--get the voicemail settings
|
||||
local settings = Settings.new(db, domain_name, domain_uuid)
|
||||
|
||||
--set the maximum greeting length
|
||||
local greeting_max_length = settings:get('voicemail', 'greeting_max_length', 'numeric') or 90;
|
||||
local greeting_silence_threshold = settings:get('voicemail', 'greeting_silence_threshold', 'numeric') or 200;
|
||||
local greeting_silence_seconds = settings:get('voicemail', 'greeting_silence_seconds', 'numeric') or 3;
|
||||
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
|
||||
--disable appending to the recording
|
||||
session:setVariable("record_append", "false");
|
||||
|
||||
--choose a greeting between 1 and 9
|
||||
if (greeting_id == nil) then
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
greeting_id = session:playAndGetDigits(1, 1, max_tries, 5000, "#", "phrase:voicemail_choose_greeting", "", "\\d+");
|
||||
freeswitch.consoleLog("notice", "[voicemail] greeting_id: " .. greeting_id .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--validate the greeting_id
|
||||
if (greeting_id == "1"
|
||||
or greeting_id == "2"
|
||||
or greeting_id == "3"
|
||||
or greeting_id == "4"
|
||||
or greeting_id == "5"
|
||||
or greeting_id == "6"
|
||||
or greeting_id == "7"
|
||||
or greeting_id == "8"
|
||||
or greeting_id == "9") then
|
||||
--record your greeting at the tone press any key or stop talking to end the recording
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_record_greeting");
|
||||
session:execute("sleep", "1000");
|
||||
session:streamFile("tone_stream://L=1;%(1000, 0, 640)");
|
||||
end
|
||||
|
||||
--store the voicemail greeting
|
||||
if (storage_type == "http_cache") then
|
||||
freeswitch.consoleLog("notice", "[voicemail] ".. storage_type .. " ".. storage_path .."\n");
|
||||
storage_path = storage_path:gsub("${domain_name}", domain_name);
|
||||
session:execute("record", storage_path .."/"..recording_name);
|
||||
else
|
||||
--prepare to record the greeting
|
||||
if (session:ready()) then
|
||||
silence_seconds = 5;
|
||||
mkdir(voicemail_dir.."/"..voicemail_id);
|
||||
-- syntax is session:recordFile(file_name, max_len_secs, silence_threshold, silence_seconds)
|
||||
result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".tmp.wav", greeting_max_length, greeting_silence_threshold, greeting_silence_seconds);
|
||||
--session:execute("record", voicemail_dir.."/"..uuid.." 180 200");
|
||||
end
|
||||
end
|
||||
|
||||
--play the greeting
|
||||
--if (session:ready()) then
|
||||
-- if (file_exists(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav")) then
|
||||
-- session:streamFile(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav");
|
||||
-- end
|
||||
--end
|
||||
|
||||
--option to play, save, and re-record the greeting
|
||||
if (session:ready()) then
|
||||
timeouts = 0;
|
||||
record_menu("greeting", voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".tmp.wav", greeting_id, menu);
|
||||
end
|
||||
else
|
||||
--invalid greeting_id
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_choose_greeting_fail");
|
||||
session:execute("sleep", "500");
|
||||
end
|
||||
|
||||
--send back to choose the greeting
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
record_greeting(nil, menu);
|
||||
else
|
||||
timeouts = 0;
|
||||
if (menu == "tutorial") then
|
||||
tutorial("finish")
|
||||
end
|
||||
if (menu == "advanced") then
|
||||
advanced();
|
||||
else
|
||||
advanced();
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--clean up any tmp greeting files
|
||||
for gid = 1, 9, 1 do
|
||||
if (file_exists(voicemail_dir.."/"..voicemail_id.."/greeting_"..gid..".tmp.wav")) then
|
||||
os.remove(voicemail_dir.."/"..voicemail_id.."/greeting_"..gid..".tmp.wav");
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,239 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2015 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--record message menu
|
||||
function record_menu(type, tmp_file, greeting_id, menu)
|
||||
if (session:ready()) then
|
||||
--clear the dtmf digits variable
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--to listen to the recording press 1, to save the recording press 2, to re-record press 3
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 3000, "#", "phrase:voicemail_record_file_options:1:2:3", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--process the dtmf
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == "1") then
|
||||
--use sleep for a small pause
|
||||
session:sleep('1000');
|
||||
--listen to the recording
|
||||
session:streamFile(tmp_file);
|
||||
--session:streamFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext);
|
||||
--record menu (1=listen, 2=save, 3=re-record)
|
||||
record_menu(type, tmp_file, greeting_id, menu);
|
||||
elseif (dtmf_digits == "2") then
|
||||
--save the message
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_ack:saved");
|
||||
session:execute("sleep", "500");
|
||||
if (type == "message") then
|
||||
--goodbye
|
||||
session:execute("playback", "phrase:voicemail_goodbye");
|
||||
--hangup the call
|
||||
session:hangup();
|
||||
end
|
||||
if (type == "greeting") then
|
||||
--remove old greeting file, and rename tmp file
|
||||
local real_file = string.gsub(tmp_file, ".tmp", "");
|
||||
if (file_exists(real_file)) then
|
||||
os.remove(real_file);
|
||||
end
|
||||
if (file_exists(tmp_file)) then
|
||||
os.rename(tmp_file, real_file);
|
||||
end
|
||||
if (storage_type == "base64") then
|
||||
--delete the greeting (retain local for better responsiveness)
|
||||
--os.remove(real_file);
|
||||
end
|
||||
|
||||
--if base64, encode file
|
||||
if (storage_type == "base64") then
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--read file content as base64 string
|
||||
greeting_base64 = assert(file.read_base64(real_file));
|
||||
end
|
||||
|
||||
--delete the previous recording
|
||||
local sql = "delete from v_voicemail_greetings ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and voicemail_id = :voicemail_id ";
|
||||
sql = sql .. "and greeting_id = :greeting_id ";
|
||||
local params = {domain_uuid = domain_uuid,
|
||||
voicemail_id = voicemail_id, greeting_id = greeting_id};
|
||||
--freeswitch.consoleLog("notice", "[SQL] DELETING: " .. greeting_id .. "\n");
|
||||
dbh:query(sql, params);
|
||||
|
||||
--get a new uuid
|
||||
voicemail_greeting_uuid = api:execute("create_uuid");
|
||||
|
||||
--save the message to the voicemail messages
|
||||
local array = {}
|
||||
table.insert(array, "INSERT INTO v_voicemail_greetings ");
|
||||
table.insert(array, "(");
|
||||
table.insert(array, "voicemail_greeting_uuid, ");
|
||||
table.insert(array, "domain_uuid, ");
|
||||
table.insert(array, "voicemail_id, ");
|
||||
table.insert(array, "greeting_id, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(array, "greeting_base64, ");
|
||||
end
|
||||
table.insert(array, "greeting_name, ");
|
||||
table.insert(array, "greeting_filename ");
|
||||
table.insert(array, ") ");
|
||||
table.insert(array, "VALUES ");
|
||||
table.insert(array, "( ");
|
||||
table.insert(array, ":greeting_uuid, ");
|
||||
table.insert(array, ":domain_uuid, ");
|
||||
table.insert(array, ":voicemail_id, ");
|
||||
table.insert(array, ":greeting_id, ");
|
||||
if (storage_type == "base64") then
|
||||
table.insert(array, ":greeting_base64, ");
|
||||
end
|
||||
table.insert(array, ":greeting_name, ");
|
||||
table.insert(array, ":greeting_filename ");
|
||||
table.insert(array, ") ");
|
||||
sql = table.concat(array, "\n");
|
||||
params = {
|
||||
greeting_uuid = voicemail_greeting_uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
voicemail_id = voicemail_id;
|
||||
greeting_id = greeting_id;
|
||||
greeting_base64 = greeting_base64;
|
||||
greeting_name = "Greeting "..greeting_id;
|
||||
greeting_filename = "greeting_"..greeting_id..".wav"
|
||||
};
|
||||
--freeswitch.consoleLog("notice", "[SQL] INSERTING: " .. greeting_id .. "\n");
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
if (storage_type == "base64") then
|
||||
local dbh = Database.new('system', 'base64');
|
||||
dbh:query(sql, params);
|
||||
dbh:release();
|
||||
else
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
|
||||
--use the new greeting
|
||||
sql = {}
|
||||
table.insert(sql, "update v_voicemails ");
|
||||
table.insert(sql, "set greeting_id = :greeting_id ");
|
||||
table.insert(sql, "where domain_uuid = :domain_uuid ");
|
||||
table.insert(sql, "and voicemail_id = :voicemail_id ");
|
||||
sql = table.concat(sql, "\n");
|
||||
params = {domain_uuid = domain_uuid, greeting_id = greeting_id,
|
||||
voicemail_id = voicemail_id};
|
||||
dbh:query(sql, params);
|
||||
|
||||
if (menu == "advanced") then
|
||||
advanced();
|
||||
end
|
||||
if (menu == "tutorial") then
|
||||
tutorial("finish")
|
||||
end
|
||||
end
|
||||
if (type == "name") then
|
||||
if (menu == "advanced") then
|
||||
advanced();
|
||||
end
|
||||
if (menu == "tutorial") then
|
||||
tutorial("change_password")
|
||||
end
|
||||
|
||||
end
|
||||
elseif (dtmf_digits == "3") then
|
||||
--re-record the message
|
||||
timeouts = 0;
|
||||
dtmf_digits = '';
|
||||
if (type == "message") then
|
||||
record_message();
|
||||
end
|
||||
if (type == "greeting") then
|
||||
--remove temporary greeting file, if any
|
||||
if (file_exists(tmp_file)) then
|
||||
os.remove(tmp_file);
|
||||
end
|
||||
record_greeting(greeting_id, menu);
|
||||
end
|
||||
if (type == "name") then
|
||||
record_name(menu);
|
||||
end
|
||||
elseif (dtmf_digits == "*") then
|
||||
if (type == "greeting") then
|
||||
--remove temporary greeting file, if any
|
||||
if (file_exists(tmp_file)) then
|
||||
os.remove(tmp_file);
|
||||
end
|
||||
end
|
||||
--hangup
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_goodbye");
|
||||
session:hangup();
|
||||
end
|
||||
else
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
record_menu(type, tmp_file, greeting_id, menu);
|
||||
else
|
||||
if (type == "message") then
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_ack:saved");
|
||||
session:execute("sleep", "300");
|
||||
session:execute("playback", "phrase:voicemail_goodbye");
|
||||
session:hangup();
|
||||
end
|
||||
if (type == "greeting") then
|
||||
--remove temporary greeting file, if any
|
||||
if (file_exists(tmp_file)) then
|
||||
os.remove(tmp_file);
|
||||
end
|
||||
if (menu == "advanced") then
|
||||
advanced();
|
||||
end
|
||||
if (menu == "tutorial") then
|
||||
tutorial("finish")
|
||||
end
|
||||
end
|
||||
if (type == "name") then
|
||||
if (menu == "advanced") then
|
||||
advanced();
|
||||
end
|
||||
if (menu == "tutorial") then
|
||||
tutorial("change_password");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,276 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2022 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--load libraries
|
||||
local Database = require "resources.functions.database"
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
local JSON = require "resources.functions.lunajson"
|
||||
|
||||
--define uuid function
|
||||
local random = math.random;
|
||||
local function gen_uuid()
|
||||
local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
|
||||
return string.gsub(template, '[xy]', function (c)
|
||||
local v = (c == 'x') and random(0, 0xf) or random(8, 0xb);
|
||||
return string.format('%x', v);
|
||||
end)
|
||||
end
|
||||
|
||||
--define escape function (prevents lua injection attacks)
|
||||
local function esc(x)
|
||||
return (x:gsub('%%', '%%%%')
|
||||
:gsub('^%^', '%%^')
|
||||
:gsub('%$$', '%%$')
|
||||
:gsub('%(', '%%(')
|
||||
:gsub('%)', '%%)')
|
||||
:gsub('%.', '%%.')
|
||||
:gsub('%[', '%%[')
|
||||
:gsub('%]', '%%]')
|
||||
:gsub('%*', '%%*')
|
||||
:gsub('%+', '%%+')
|
||||
:gsub('%-', '%%-')
|
||||
:gsub('%?', '%%?'))
|
||||
end
|
||||
|
||||
--save the recording
|
||||
function record_message()
|
||||
|
||||
--set the variables
|
||||
local db = dbh or Database.new('system')
|
||||
local settings = Settings.new(db, domain_name, domain_uuid)
|
||||
local message_max_length = settings:get('voicemail', 'message_max_length', 'numeric') or 300;
|
||||
local message_silence_threshold = settings:get('voicemail', 'message_silence_threshold', 'numeric') or 200;
|
||||
local message_silence_seconds = settings:get('voicemail', 'message_silence_seconds', 'numeric') or 3;
|
||||
local email_queue_enabled = settings:get('email_queue', 'enabled', 'boolean') or "false";
|
||||
|
||||
--record your message at the tone press any key or stop talking to end the recording
|
||||
if (skip_instructions == "true") then
|
||||
--skip the instructions
|
||||
else
|
||||
if (dtmf_digits and string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 500, "#", "phrase:voicemail_record_message", "", "\\d+");
|
||||
end
|
||||
end
|
||||
|
||||
--voicemail ivr options
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == nil) then
|
||||
dtmf_digits = session:getDigits(max_digits, "#", 1000);
|
||||
else
|
||||
dtmf_digits = dtmf_digits .. session:getDigits(max_digits, "#", 1000);
|
||||
end
|
||||
end
|
||||
if (dtmf_digits) then
|
||||
if (string.len(dtmf_digits) > 0) then
|
||||
if (session:ready()) then
|
||||
if (direct_dial["enabled"] == "true") then
|
||||
if (string.len(dtmf_digits) < max_digits) then
|
||||
dtmf_digits = dtmf_digits .. session:getDigits(direct_dial["max_digits"], "#", 3000);
|
||||
end
|
||||
end
|
||||
end
|
||||
if (session:ready()) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] dtmf_digits: " .. string.sub(dtmf_digits, 0, 1) .. "\n");
|
||||
if (dtmf_digits == "*") then
|
||||
if (remote_access == "true") then
|
||||
--check the voicemail password
|
||||
check_password(voicemail_id, password_tries);
|
||||
--send to the main menu
|
||||
timeouts = 0;
|
||||
main_menu();
|
||||
else
|
||||
--remote access is false
|
||||
freeswitch.consoleLog("notice", "[voicemail] remote access is disabled.\n");
|
||||
session:hangup();
|
||||
end
|
||||
elseif (string.sub(dtmf_digits, 0, 1) == "*") then
|
||||
--do not allow dialing numbers prefixed with *
|
||||
session:hangup();
|
||||
else
|
||||
--get the voicemail options
|
||||
local sql = [[SELECT * FROM v_voicemail_options WHERE voicemail_uuid = :voicemail_uuid ORDER BY voicemail_option_order asc ]];
|
||||
local params = {voicemail_uuid = voicemail_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
count = 0;
|
||||
dbh:query(sql, params, function(row)
|
||||
--check for matching options
|
||||
if (tonumber(row.voicemail_option_digits) ~= nil) then
|
||||
row.voicemail_option_digits = "^"..row.voicemail_option_digits.."$";
|
||||
end
|
||||
if (api:execute("regex", "m:~"..dtmf_digits.."~"..row.voicemail_option_digits) == "true") then
|
||||
if (row.voicemail_option_action == "menu-exec-app") then
|
||||
--get the action and data
|
||||
pos = string.find(row.voicemail_option_param, " ", 0, true);
|
||||
action = string.sub( row.voicemail_option_param, 0, pos-1);
|
||||
data = string.sub( row.voicemail_option_param, pos+1);
|
||||
|
||||
--check if the option uses a regex
|
||||
regex = string.find(row.voicemail_option_digits, "(", 0, true);
|
||||
if (regex) then
|
||||
--get the regex result
|
||||
result = trim(api:execute("regex", "m:~"..digits.."~"..row.voicemail_option_digits.."~$1"));
|
||||
if (debug["regex"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] regex m:~"..digits.."~"..row.voicemail_option_digits.."~$1\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] result: "..result.."\n");
|
||||
end
|
||||
|
||||
--replace the $1 and the domain name
|
||||
data = data:gsub("$1", result);
|
||||
data = data:gsub("${domain_name}", domain_name);
|
||||
end --if regex
|
||||
end --if menu-exex-app
|
||||
end --if regex match
|
||||
|
||||
--execute
|
||||
if (action) then
|
||||
if (string.len(action) > 0) then
|
||||
--send to the log
|
||||
if (debug["action"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] action: " .. action .. " data: ".. data .. "\n");
|
||||
end
|
||||
--run the action
|
||||
session:execute(action, data);
|
||||
end
|
||||
end
|
||||
|
||||
--clear the variables
|
||||
action = "";
|
||||
data = "";
|
||||
|
||||
--inrement the option count
|
||||
count = count + 1;
|
||||
end); --end results
|
||||
|
||||
--direct dial
|
||||
if (session:ready()) then
|
||||
if (direct_dial["enabled"] == "true" and count == 0) then
|
||||
if (string.len(dtmf_digits) < max_digits) then
|
||||
dtmf_digits = dtmf_digits .. session:getDigits(direct_dial["max_digits"], "#", 5000);
|
||||
session:transfer(dtmf_digits.." XML "..context);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--play the beep
|
||||
dtmf_digits = '';
|
||||
session:execute("playback","silence_stream://200");
|
||||
session:streamFile("tone_stream://L=1;%(1000, 0, 640)");
|
||||
|
||||
--make sure the voicemail directory exists
|
||||
mkdir(voicemail_dir.."/"..voicemail_id);
|
||||
|
||||
--start epoch
|
||||
start_epoch = os.time();
|
||||
|
||||
--save the recording
|
||||
-- syntax is session:recordFile(file_name, max_len_secs, silence_threshold, silence_secs)
|
||||
if (storage_path == "http_cache") then
|
||||
result = session:recordFile(storage_path.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext, message_max_length, message_silence_threshold, message_silence_seconds);
|
||||
else
|
||||
if (vm_message_ext == "mp3") then
|
||||
shout_exists = trim(api:execute("module_exists", "mod_shout"));
|
||||
if (shout_exists == "true") then
|
||||
--send information to the console
|
||||
freeswitch.consoleLog("notice", "using mod_shout for mp3 encoding\n");
|
||||
|
||||
--record in mp3 directly
|
||||
result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".mp3", message_max_length, message_silence_threshold, message_silence_seconds);
|
||||
else
|
||||
--create initial wav recording
|
||||
result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".wav", message_max_length, message_silence_threshold, message_silence_seconds);
|
||||
--use lame to encode, if available
|
||||
if (file_exists("/usr/bin/lame")) then
|
||||
freeswitch.consoleLog("notice", "using lame for mp3 encoding\n");
|
||||
--convert the wav to an mp3 (lame required)
|
||||
resample = "/usr/bin/lame -b 32 --resample 8 -m s "..voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".wav "..voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".mp3";
|
||||
session:execute("system", resample);
|
||||
--delete the wav file, if mp3 exists
|
||||
if (file_exists(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".mp3")) then
|
||||
os.remove(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".wav");
|
||||
else
|
||||
vm_message_ext = "wav";
|
||||
end
|
||||
else
|
||||
--send information to the console
|
||||
freeswitch.consoleLog("notice", "neither mod_shout or lame found, defaulting to wav\n");
|
||||
|
||||
--use wav format
|
||||
vm_message_ext = "wav";
|
||||
end
|
||||
end
|
||||
else
|
||||
result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext, message_max_length, message_silence_threshold, message_silence_seconds);
|
||||
end
|
||||
end
|
||||
|
||||
--stop epoch
|
||||
stop_epoch = os.time();
|
||||
|
||||
--calculate the message length
|
||||
message_length = stop_epoch - start_epoch;
|
||||
message_length_formatted = format_seconds(message_length);
|
||||
|
||||
--if the recording is below the minimal length then re-record the message
|
||||
if (message_length > 2) then
|
||||
session:setVariable("voicemail_message_seconds", message_length);
|
||||
else
|
||||
if (session:ready()) then
|
||||
--your recording is below the minimal acceptable length, please try again
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_ack:too-small");
|
||||
session:execute("sleep", "500");
|
||||
--record your message at the tone
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
record_message();
|
||||
else
|
||||
timeouts = 0;
|
||||
record_menu("message", voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--instructions press 1 to listen to the recording, press 2 to save the recording, press 3 to re-record
|
||||
if (session:ready()) then
|
||||
if (skip_instructions == "true") then
|
||||
--save the message
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_ack:saved");
|
||||
session:execute("sleep", "300");
|
||||
session:execute("playback", "phrase:voicemail_goodbye");
|
||||
--hangup the call
|
||||
session:hangup();
|
||||
else
|
||||
timeouts = 0;
|
||||
record_menu("message", voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext);
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,106 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define a function to record the name
|
||||
function record_name(menu)
|
||||
if (session:ready()) then
|
||||
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
|
||||
--play the name record
|
||||
dtmf_digits = '';
|
||||
session:execute("playback", "phrase:voicemail_record_name");
|
||||
session:execute("sleep", "1000");
|
||||
session:streamFile("tone_stream://L=1;%(1000, 0, 640)");
|
||||
|
||||
--prepate to record
|
||||
-- syntax is session:recordFile(file_name, max_len_secs, silence_threshold, silence_secs)
|
||||
max_len_seconds = 30;
|
||||
silence_threshold = 30;
|
||||
silence_seconds = 5;
|
||||
|
||||
--make sure the voicemail directory exists
|
||||
mkdir(voicemail_dir.."/"..voicemail_id);
|
||||
|
||||
--record and save the file
|
||||
if (storage_type == "base64") then
|
||||
--set the location
|
||||
voicemail_name_location = voicemail_dir.."/"..voicemail_id.."/recorded_name.wav";
|
||||
|
||||
--record the file to the file system
|
||||
-- syntax is session:recordFile(file_name, max_len_secs, silence_threshold, silence_secs);
|
||||
result = session:recordFile(voicemail_name_location, max_len_seconds, silence_threshold, silence_seconds);
|
||||
--session:execute("record", voicemail_dir.."/"..uuid.." 180 200");
|
||||
|
||||
--show the storage type
|
||||
freeswitch.consoleLog("notice", "[recordings] ".. storage_type .. "\n");
|
||||
|
||||
--base64 encode the file
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--read file content as base64 string
|
||||
voicemail_name_base64 = assert(file.read_base64(voicemail_name_location));
|
||||
|
||||
--update the voicemail name
|
||||
local sql = "UPDATE v_voicemails ";
|
||||
sql = sql .. "set voicemail_name_base64 = :voicemail_name_base64 ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and voicemail_id = :voicemail_id";
|
||||
local params = {voicemail_name_base64 = voicemail_name_base64,
|
||||
domain_uuid = domain_uuid, voicemail_id = voicemail_id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[recording] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
if (storage_type == "base64") then
|
||||
local dbh = Database.new('system', 'base64');
|
||||
dbh:query(sql, params);
|
||||
dbh:release();
|
||||
else
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
elseif (storage_type == "http_cache") then
|
||||
freeswitch.consoleLog("notice", "[voicemail] ".. storage_type .. " ".. storage_path .."\n");
|
||||
session:execute("record", storage_path .."/"..recording_name);
|
||||
else
|
||||
-- syntax is session:recordFile(file_name, max_len_secs, silence_threshold, silence_secs);
|
||||
result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/recorded_name.wav", max_len_seconds, silence_threshold, silence_seconds);
|
||||
end
|
||||
|
||||
--play the name
|
||||
--session:streamFile(voicemail_dir.."/"..voicemail_id.."/recorded_name.wav");
|
||||
|
||||
--option to play, save, and re-record the name
|
||||
if (session:ready()) then
|
||||
timeouts = 0;
|
||||
record_menu("name", voicemail_dir.."/"..voicemail_id.."/recorded_name.wav",nil, menu);
|
||||
if (storage_type == "base64") then
|
||||
--delete the greeting
|
||||
os.remove(voicemail_dir.."/"..voicemail_id.."/recorded_name.wav");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,36 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define a function to return the call
|
||||
function return_call(destination)
|
||||
if (session:ready()) then
|
||||
--clear the dtmf
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--transfer the call
|
||||
session:transfer(destination, "XML", context);
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,305 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 - 2020 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--load libraries
|
||||
local send_mail = require 'resources.functions.send_mail'
|
||||
local Database = require "resources.functions.database"
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
|
||||
--define a function to send email
|
||||
function send_email(id, uuid)
|
||||
local db = dbh or Database.new('system')
|
||||
local settings = Settings.new(db, domain_name, domain_uuid)
|
||||
local transcribe_enabled = settings:get('voicemail', 'transcribe_enabled', 'boolean');
|
||||
local http_protocol = settings:get('domain', 'http_protocol', 'text') or "https";
|
||||
local email_queue_enabled = "true";
|
||||
|
||||
--get voicemail message details
|
||||
local sql = [[SELECT * FROM v_voicemails
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id]]
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
db_voicemail_uuid = string.lower(row["voicemail_uuid"]);
|
||||
--voicemail_password = row["voicemail_password"];
|
||||
--greeting_id = row["greeting_id"];
|
||||
voicemail_mail_to = row["voicemail_mail_to"];
|
||||
voicemail_transcription_enabled = row["voicemail_transcription_enabled"];
|
||||
voicemail_file = row["voicemail_file"];
|
||||
voicemail_local_after_email = row["voicemail_local_after_email"];
|
||||
voicemail_description = row["voicemail_description"];
|
||||
end);
|
||||
|
||||
--set default values
|
||||
if (voicemail_local_after_email == nil) then
|
||||
voicemail_local_after_email = "true";
|
||||
end
|
||||
if (voicemail_file == nil) then
|
||||
voicemail_file = "listen";
|
||||
end
|
||||
|
||||
--require the email address to send the email
|
||||
if (string.len(voicemail_mail_to) > 2) then
|
||||
--include languages file
|
||||
local Text = require "resources.functions.text"
|
||||
local text = Text.new("app.voicemail.app_languages")
|
||||
local dbh = dbh
|
||||
|
||||
--user setting time zone, if set
|
||||
local sql = [[
|
||||
select
|
||||
us.user_setting_value as time_zone
|
||||
from
|
||||
v_user_settings as us,
|
||||
v_extension_users as eu,
|
||||
v_extensions as e,
|
||||
v_voicemails as v
|
||||
where
|
||||
v.voicemail_id = :voicemail_id and
|
||||
v.domain_uuid = :domain_uuid and
|
||||
v.voicemail_id = e.extension and
|
||||
e.domain_uuid = :domain_uuid and
|
||||
e.extension_uuid = eu.extension_uuid and
|
||||
eu.domain_uuid = :domain_uuid and
|
||||
eu.user_uuid = us.user_uuid and
|
||||
us.domain_uuid = :domain_uuid and
|
||||
us.user_setting_category = 'domain' and
|
||||
us.user_setting_subcategory = 'time_zone' and
|
||||
us.user_setting_name = 'name' and
|
||||
us.user_setting_enabled = 'true'
|
||||
order by
|
||||
eu.insert_date asc
|
||||
limit 1
|
||||
]]
|
||||
local params = {domain_uuid = domain_uuid, voicemail_id = id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
time_zone = row["time_zone"];
|
||||
end);
|
||||
|
||||
--default/domain setting time zone
|
||||
if (time_zone == nil or time_zone == '') then
|
||||
time_zone = settings:get('domain', 'time_zone', 'name');
|
||||
end
|
||||
|
||||
--default time zone
|
||||
if (time_zone == nil or time_zone == '') then
|
||||
time_zone = 'UTC';
|
||||
end
|
||||
|
||||
--connect using other backend if needed
|
||||
if storage_type == "base64" then
|
||||
dbh = Database.new('system', 'base64/read')
|
||||
end
|
||||
|
||||
--get voicemail message details
|
||||
local sql = [[SELECT to_char(timezone(:time_zone, to_timestamp(created_epoch)), 'Day DD Mon YYYY HH:MI:SS PM') as message_date, *
|
||||
FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_message_uuid = :uuid]]
|
||||
local params = {domain_uuid = domain_uuid, uuid = uuid, time_zone = time_zone};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--get the values from the database
|
||||
--uuid = row["voicemail_message_uuid"];
|
||||
created_epoch = row["created_epoch"];
|
||||
caller_id_name = row["caller_id_name"];
|
||||
caller_id_number = row["caller_id_number"];
|
||||
message_date = row["message_date"];
|
||||
message_length = row["message_length"];
|
||||
--message_status = row["message_status"];
|
||||
--message_priority = row["message_priority"];
|
||||
--get the recordings from the database
|
||||
if (storage_type == "base64") then
|
||||
--set the voicemail message path
|
||||
message_location = voicemail_dir.."/"..id.."/msg_"..uuid.."."..vm_message_ext;
|
||||
|
||||
--save the recording to the file system
|
||||
if (string.len(row["message_base64"]) > 32) then
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--write decoded string to file
|
||||
file.write_base64(message_location, row["message_base64"]);
|
||||
end
|
||||
end
|
||||
end);
|
||||
|
||||
--close temporary connection
|
||||
if storage_type == "base64" then
|
||||
dbh:release()
|
||||
end
|
||||
|
||||
--format the message length and date
|
||||
message_length_formatted = format_seconds(message_length);
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] message date: " .. message_date .. "\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] message length: " .. message_length .. "\n");
|
||||
end
|
||||
--local message_date = os.date("%A, %d %b %Y %I:%M %p", created_epoch);
|
||||
|
||||
--connect to the database
|
||||
local dbh = Database.new('system');
|
||||
|
||||
--get the templates
|
||||
local sql = "SELECT * FROM v_email_templates ";
|
||||
sql = sql .. "WHERE (domain_uuid = :domain_uuid or domain_uuid is null) ";
|
||||
sql = sql .. "AND template_language = :template_language ";
|
||||
sql = sql .. "AND template_category = 'voicemail' "
|
||||
if (transcribe_enabled == 'true' and voicemail_transcription_enabled == 'true') then
|
||||
sql = sql .. "AND template_subcategory = 'transcription' "
|
||||
else
|
||||
sql = sql .. "AND template_subcategory = 'default' "
|
||||
end
|
||||
sql = sql .. "AND template_enabled = 'true' "
|
||||
sql = sql .. "ORDER BY domain_uuid DESC "
|
||||
local params = {domain_uuid = domain_uuid, template_language = default_language.."-"..default_dialect};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
subject = row["template_subject"];
|
||||
body = row["template_body"];
|
||||
end);
|
||||
|
||||
--get the link_address
|
||||
link_address = http_protocol.."://"..domain_name..project_path;
|
||||
|
||||
--prepare the headers
|
||||
local headers = {
|
||||
["X-FusionPBX-Domain-UUID"] = domain_uuid;
|
||||
["X-FusionPBX-Domain-Name"] = domain_name;
|
||||
["X-FusionPBX-Call-UUID"] = uuid;
|
||||
["X-FusionPBX-Email-Type"] = 'voicemail';
|
||||
["X-FusionPBX-local_after_email"] = voicemail_local_after_email;
|
||||
}
|
||||
|
||||
--prepare the voicemail_name_formatted
|
||||
voicemail_name_formatted = id;
|
||||
local display_domain_name = settings:get('voicemail', 'display_domain_name', 'boolean');
|
||||
|
||||
if (display_domain_name == 'true') then
|
||||
voicemail_name_formatted = id.."@"..domain_name;
|
||||
end
|
||||
if (voicemail_description ~= nil and voicemail_description ~= "" and voicemail_description ~= id) then
|
||||
voicemail_name_formatted = voicemail_name_formatted.." ("..voicemail_description..")";
|
||||
end
|
||||
|
||||
--prepare the subject
|
||||
subject = subject:gsub("${caller_id_name}", caller_id_name);
|
||||
subject = subject:gsub("${caller_id_number}", caller_id_number);
|
||||
subject = subject:gsub("${message_date}", message_date);
|
||||
subject = subject:gsub("${message_duration}", message_length_formatted);
|
||||
subject = subject:gsub("${account}", voicemail_name_formatted);
|
||||
subject = subject:gsub("${voicemail_id}", id);
|
||||
subject = subject:gsub("${voicemail_description}", voicemail_description);
|
||||
subject = subject:gsub("${voicemail_name_formatted}", voicemail_name_formatted);
|
||||
subject = subject:gsub("${domain_name}", domain_name);
|
||||
subject = subject:gsub("${new_messages}", new_messages);
|
||||
subject = trim(subject);
|
||||
subject = '=?utf-8?B?'..base64.encode(subject)..'?=';
|
||||
|
||||
--prepare the body
|
||||
body = body:gsub("${caller_id_name}", caller_id_name);
|
||||
body = body:gsub("${caller_id_number}", caller_id_number);
|
||||
body = body:gsub("${message_date}", message_date);
|
||||
if (transcription ~= nil) then
|
||||
transcription = transcription:gsub("%%", "*");
|
||||
body = body:gsub("${message_text}", transcription);
|
||||
end
|
||||
body = body:gsub("${message_duration}", message_length_formatted);
|
||||
body = body:gsub("${account}", voicemail_name_formatted);
|
||||
body = body:gsub("${voicemail_id}", id);
|
||||
body = body:gsub("${voicemail_description}", voicemail_description);
|
||||
body = body:gsub("${voicemail_name_formatted}", voicemail_name_formatted);
|
||||
body = body:gsub("${domain_name}", domain_name);
|
||||
body = body:gsub("${sip_to_user}", id);
|
||||
if (origination_callee_id_name ~= nil) then
|
||||
body = body:gsub("${origination_callee_id_name}", origination_callee_id_name);
|
||||
end
|
||||
body = body:gsub("${dialed_user}", id);
|
||||
if (voicemail_file == "attach") then
|
||||
body = body:gsub("${message}", text['label-attached']);
|
||||
elseif (voicemail_file == "link") then
|
||||
body = body:gsub("${message}", "<a href='"..link_address.."/app/voicemails/voicemail_messages.php?action=download&id="..id.."&voicemail_uuid="..db_voicemail_uuid.."&uuid="..uuid.."&t=bin'>"..text['label-download'].."</a>");
|
||||
else
|
||||
body = body:gsub("${message}", "<a href='"..link_address.."/app/voicemails/voicemail_messages.php?action=autoplay&id="..db_voicemail_uuid.."&uuid="..uuid.."'>"..text['label-listen'].."</a>");
|
||||
end
|
||||
--body = body:gsub(" ", " ");
|
||||
--body = body:gsub("%s+", "");
|
||||
--body = body:gsub(" ", " ");
|
||||
body = trim(body);
|
||||
|
||||
--prepare file
|
||||
file = voicemail_dir.."/"..id.."/msg_"..uuid.."."..vm_message_ext;
|
||||
|
||||
--send the email
|
||||
send_mail(headers,
|
||||
nil,
|
||||
voicemail_mail_to,
|
||||
{subject, body},
|
||||
(voicemail_file == "attach") and file
|
||||
);
|
||||
end
|
||||
|
||||
--whether to keep the voicemail message and details local after email
|
||||
if (string.len(voicemail_mail_to) > 2 and email_queue_enabled == 'false') then
|
||||
if (voicemail_local_after_email == "false") then
|
||||
--delete the voicemail message details
|
||||
local sql = [[DELETE FROM v_voicemail_messages
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_uuid = :voicemail_uuid
|
||||
AND voicemail_message_uuid = :uuid]]
|
||||
local params = {domain_uuid = domain_uuid,
|
||||
voicemail_uuid = db_voicemail_uuid, uuid = uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
--delete voicemail recording file
|
||||
if (file_exists(file)) then
|
||||
os.remove(file);
|
||||
end
|
||||
--set message waiting indicator
|
||||
message_waiting(id, domain_uuid);
|
||||
--clear the variable
|
||||
db_voicemail_uuid = '';
|
||||
elseif (storage_type == "base64") then
|
||||
--delete voicemail recording file
|
||||
if (file_exists(file)) then
|
||||
os.remove(file);
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,109 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define a function to send sms
|
||||
function send_sms(id, uuid)
|
||||
debug["info"] = true;
|
||||
api = freeswitch.API();
|
||||
|
||||
--get voicemail message details
|
||||
sql = [[SELECT * FROM v_voicemails
|
||||
WHERE domain_uuid = ']] .. domain_uuid ..[['
|
||||
AND voicemail_id = ']] .. id ..[[']]
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n");
|
||||
end
|
||||
status = dbh:query(sql, function(row)
|
||||
db_voicemail_uuid = string.lower(row["voicemail_uuid"]);
|
||||
voicemail_sms_to = row["voicemail_sms_to"];
|
||||
voicemail_file = row["voicemail_file"];
|
||||
end);
|
||||
|
||||
--get the sms_body template
|
||||
if (settings['voicemail']['voicemail_sms_body'] ~= nil) then
|
||||
if (settings['voicemail']['voicemail_sms_body']['text'] ~= nil) then
|
||||
sms_body = settings['voicemail']['voicemail_sms_body']['text'];
|
||||
end
|
||||
else
|
||||
sms_body = 'You have a new voicemail from: ${caller_id_name} - ${caller_id_number} length ${message_length_formatted}';
|
||||
end
|
||||
|
||||
|
||||
--require the sms address to send to
|
||||
if (string.len(voicemail_sms_to) > 2) then
|
||||
--include languages file
|
||||
local Text = require "resources.functions.text"
|
||||
local text = Text.new("app.voicemail.app_languages")
|
||||
|
||||
--get voicemail message details
|
||||
sql = [[SELECT * FROM v_voicemail_messages
|
||||
WHERE domain_uuid = ']] .. domain_uuid ..[['
|
||||
AND voicemail_message_uuid = ']] .. uuid ..[[']]
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n");
|
||||
end
|
||||
status = dbh:query(sql, function(row)
|
||||
--get the values from the database
|
||||
--uuid = row["voicemail_message_uuid"];
|
||||
created_epoch = row["created_epoch"];
|
||||
caller_id_name = row["caller_id_name"];
|
||||
caller_id_number = row["caller_id_number"];
|
||||
message_length = row["message_length"];
|
||||
end);
|
||||
|
||||
--format the message length and date
|
||||
message_length_formatted = format_seconds(message_length);
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail-sms] message length: " .. message_length .. "\n");
|
||||
if (transcription ~= nil) then
|
||||
freeswitch.consoleLog("notice", "[voicemail-sms] transcription: " .. transcription .. "\n");
|
||||
end
|
||||
freeswitch.consoleLog("notice", "[voicemail-sms] domain_name: " .. domain_name .. "\n");
|
||||
end
|
||||
local message_date = os.date("%A, %d %b %Y %I:%M %p", created_epoch)
|
||||
|
||||
sms_body = sms_body:gsub("${caller_id_name}", caller_id_name);
|
||||
sms_body = sms_body:gsub("${caller_id_number}", caller_id_number);
|
||||
sms_body = sms_body:gsub("${message_date}", message_date);
|
||||
sms_body = sms_body:gsub("${message_duration}", message_length_formatted);
|
||||
sms_body = sms_body:gsub("${account}", id);
|
||||
sms_body = sms_body:gsub("${domain_name}", domain_name);
|
||||
sms_body = sms_body:gsub("${sip_to_user}", id);
|
||||
sms_body = sms_body:gsub("${dialed_user}", id);
|
||||
if (transcription ~= nil) then
|
||||
sms_body = sms_body:gsub("${message_text}", transcription);
|
||||
end
|
||||
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail-sms] sms_body: " .. sms_body .. "\n");
|
||||
end
|
||||
|
||||
-- sms_body = "hello";
|
||||
cmd = "luarun app.lua sms outbound " .. voicemail_sms_to .. "@" .. domain_name .. " " .. voicemail_to_sms_did .. " '" .. sms_body .. "'";
|
||||
api:executeString(cmd);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,197 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--define function main menu
|
||||
function tutorial (menu)
|
||||
if (voicemail_uuid) then
|
||||
--intro menu
|
||||
if (menu == "intro") then
|
||||
--clear the value
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--play the tutorial press 1, to skip 2
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 3000, "#", "phrase:tutorial_intro", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--process the dtmf
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == "1") then
|
||||
timeouts = 0;
|
||||
tutorial("record_name");
|
||||
elseif (dtmf_digits == "2") then
|
||||
timeouts = 0;
|
||||
tutorial("finish");
|
||||
else
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
tutorial("intro");
|
||||
else
|
||||
timeouts = 0;
|
||||
tutorial("finish");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--record name menu
|
||||
if (menu == "record_name") then
|
||||
--clear the value
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--play the record name press 1
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 200, "#", "phrase:tutorial_record_name:1", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--skip the name and go to password press 2
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 3000, "#", "phrase:tutorial_skip:2", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--process the dtmf
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == "1") then
|
||||
timeouts = 0;
|
||||
record_name("tutorial");
|
||||
elseif (dtmf_digits == "2") then
|
||||
timeouts = 0;
|
||||
tutorial("change_password");
|
||||
else
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
tutorial("record_name");
|
||||
else
|
||||
tutorial("change_password");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--change password menu
|
||||
if (menu == "change_password") then
|
||||
--clear the value
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--to change your password press 1
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 200, "#", "phrase:tutorial_change_password:1", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--skip the password and go to greeting press 2
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 3000, "#", "phrase:tutorial_skip:2", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--process the dtmf
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == "1") then
|
||||
timeouts = 0;
|
||||
change_password(voicemail_id, "tutorial");
|
||||
elseif (dtmf_digits == "2") then
|
||||
timeouts = 0;
|
||||
tutorial("record_greeting");
|
||||
else
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
tutorial("change_password");
|
||||
else
|
||||
tutorial("record_greeting");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
--change greeting menu
|
||||
if (menu == "record_greeting") then
|
||||
--clear the value
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--to record a greeting press 1
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 200, "#", "phrase:tutorial_record_greeting:1", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--skip the record greeting press 2. finishes the tutorial and routes to main menu
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = session:playAndGetDigits(0, 1, 1, 3000, "#", "phrase:tutorial_skip:2", "", "\\d+");
|
||||
end
|
||||
end
|
||||
--process the dtmf
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == "1") then
|
||||
timeouts = 0;
|
||||
record_greeting(nil, "tutorial");
|
||||
elseif (dtmf_digits == "2") then
|
||||
timeouts = 0;
|
||||
tutorial("finish");
|
||||
else
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
tutorial("record_greeting");
|
||||
else
|
||||
tutorial("finish");
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if (menu == "finish") then
|
||||
--clear the value
|
||||
dtmf_digits = '';
|
||||
--flush dtmf digits from the input buffer
|
||||
session:flushDigits();
|
||||
--update play tutorial in the datebase
|
||||
local sql = [[UPDATE v_voicemails
|
||||
set voicemail_tutorial = 'false'
|
||||
WHERE domain_uuid = :domain_uuid
|
||||
AND voicemail_id = :voicemail_id
|
||||
AND voicemail_enabled = 'true' ]];
|
||||
local params = {domain_uuid = domain_uuid,
|
||||
voicemail_id = voicemail_id};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
--go to main menu
|
||||
main_menu();
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,109 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--include the lua script
|
||||
require "resources.functions.config";
|
||||
|
||||
--define general settings
|
||||
sleep = 300;
|
||||
|
||||
--define the run file
|
||||
run_file = scripts_dir .. "/run/voicemail-mwi.tmp";
|
||||
|
||||
--debug
|
||||
debug["sql"] = false;
|
||||
debug["info"] = false;
|
||||
|
||||
--only run the script a single time
|
||||
runonce = false;
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--used to stop the lua service
|
||||
local file = assert(io.open(run_file, "w"));
|
||||
file:write("remove this file to stop the script");
|
||||
|
||||
--define the trim function
|
||||
require "resources.functions.trim";
|
||||
|
||||
--check if a file exists
|
||||
require "resources.functions.file_exists";
|
||||
|
||||
--send MWI NOTIFY message
|
||||
require "app.voicemail.resources.functions.mwi_notify";
|
||||
|
||||
--get message count for mailbox
|
||||
require "app.voicemail.resources.functions.message_count";
|
||||
|
||||
--create the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--run lua as a service
|
||||
while true do
|
||||
|
||||
--exit the loop when the file does not exist
|
||||
if (not file_exists(run_file)) then
|
||||
freeswitch.consoleLog("NOTICE", run_file.." not found\n");
|
||||
break;
|
||||
end
|
||||
|
||||
--Send MWI events for voicemail boxes with messages
|
||||
local sql = [[SELECT v.voicemail_id, v.voicemail_uuid, v.domain_uuid, d.domain_name, COUNT(*) AS message_count
|
||||
FROM v_voicemail_messages as m, v_voicemails as v, v_domains as d
|
||||
WHERE v.voicemail_uuid = m.voicemail_uuid
|
||||
AND v.domain_uuid = d.domain_uuid
|
||||
AND v.voicemail_enabled = 'true'
|
||||
GROUP BY v.voicemail_id, v.voicemail_uuid, v.domain_uuid, d.domain_name;]];
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n");
|
||||
end
|
||||
dbh:query(sql, function(row)
|
||||
|
||||
--get saved and new message counts
|
||||
local new_messages, saved_messages = message_count_by_uuid(
|
||||
row["voicemail_uuid"], row["domain_uuid"]
|
||||
)
|
||||
|
||||
--send the message waiting event
|
||||
local account = row["voicemail_id"].."@"..row["domain_name"]
|
||||
mwi_notify(account, new_messages, saved_messages)
|
||||
|
||||
--log to console
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] mailbox: "..account.." messages: " .. (new_messages or "0") .. "/" .. (saved_messages or "0") .. " \n");
|
||||
end
|
||||
end);
|
||||
|
||||
if (runonce) then
|
||||
freeswitch.consoleLog("notice", "mwi.lua has ended\n");
|
||||
break;
|
||||
else
|
||||
--slow the loop down
|
||||
os.execute("sleep "..sleep);
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
--get the argv values
|
||||
voicemail_id = argv[1];
|
||||
domain_name = argv[2];
|
||||
new_messages = argv[3] or '0';
|
||||
saved_messages = argv[4] or '0';
|
||||
|
||||
--include the lua script
|
||||
require "resources.functions.config";
|
||||
|
||||
--send MWI NOTIFY message
|
||||
require "app.voicemail.resources.functions.mwi_notify";
|
||||
|
||||
--debug info
|
||||
--freeswitch.consoleLog("NOTICE", "voicemail_id="..voicemail_id.."\n");
|
||||
--freeswitch.consoleLog("NOTICE", "domain_name="..domain_name.."\n");
|
||||
--freeswitch.consoleLog("NOTICE", "new_messages="..new_messages.."\n");
|
||||
--freeswitch.consoleLog("NOTICE", "saved_messages="..saved_messages.."\n");
|
||||
|
||||
--send the message waiting event
|
||||
mwi_notify(voicemail_id..'@'..domain_name, domain_name, new_messages, saved_messages);
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
require "resources.functions.config"
|
||||
require "resources.functions.split"
|
||||
|
||||
local service_name = "mwi"
|
||||
|
||||
local log = require "resources.functions.log"[service_name]
|
||||
local BasicEventService = require "resources.functions.basic_event_service"
|
||||
local Database = require "resources.functions.database"
|
||||
local cache = require "resources.functions.cache"
|
||||
local mwi_notify = require "app.voicemail.resources.functions.mwi_notify"
|
||||
|
||||
local vm_message_count do
|
||||
|
||||
local vm_to_uuid_sql = [[SELECT v.voicemail_uuid
|
||||
FROM v_voicemails as v inner join v_domains as d on v.domain_uuid = d.domain_uuid
|
||||
WHERE v.voicemail_enabled = 'true' and v.voicemail_id = :voicemail_id and d.domain_name = :domain_name]]
|
||||
|
||||
local vm_messages_sql = [[SELECT
|
||||
( SELECT count(*)
|
||||
FROM v_voicemail_messages
|
||||
WHERE voicemail_uuid = :voicemail_uuid
|
||||
AND (message_status is null or message_status = '')
|
||||
) as new_messages,
|
||||
|
||||
( SELECT count(*)
|
||||
FROM v_voicemail_messages
|
||||
WHERE voicemail_uuid = :voicemail_uuid
|
||||
AND message_status = 'saved'
|
||||
) as saved_messages
|
||||
]]
|
||||
|
||||
function vm_message_count(account, use_cache)
|
||||
local id, domain_name = split_first(account, '@', true)
|
||||
if not domain_name then return end
|
||||
|
||||
-- FusionPBX support only numeric voicemail id
|
||||
if not tonumber(id) then
|
||||
log.warningf('non numeric voicemail id: %s', id)
|
||||
return
|
||||
end
|
||||
|
||||
local dbh = Database.new('system')
|
||||
if not dbh then return end
|
||||
|
||||
-- Get the UUID from the cache if enabled/supported
|
||||
local uuid
|
||||
if use_cache and cache.support() then
|
||||
uuid = cache.get('voicemail_uuid:' .. account)
|
||||
end
|
||||
|
||||
-- If no UUID cached or if cache is not enabled/supported get the UUID from the database
|
||||
if not uuid then
|
||||
uuid = dbh:first_value(vm_to_uuid_sql, {
|
||||
voicemail_id = id, domain_name = domain_name
|
||||
})
|
||||
|
||||
if uuid and #uuid > 0 and use_cache and cache.support() then
|
||||
cache.set('voicemail_uuid:' .. account, uuid, 3600)
|
||||
end
|
||||
end
|
||||
|
||||
-- Get the count of unread and read messages from the database if there is a valid voicemail account
|
||||
local row
|
||||
if uuid and #uuid > 0 then
|
||||
row = dbh:first_row(vm_messages_sql, {voicemail_uuid = uuid})
|
||||
end
|
||||
|
||||
dbh:release()
|
||||
|
||||
-- This condition can be hit if the voicemail box is either disabled or non-existent
|
||||
if not row then return end
|
||||
|
||||
return row.new_messages, row.saved_messages
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local service = BasicEventService.new(log, service_name)
|
||||
|
||||
-- MWI SUBSCRIBE
|
||||
service:bind("MESSAGE_QUERY", function(self, name, event)
|
||||
local account_header = event:getHeader('Message-Account')
|
||||
if not account_header then
|
||||
return log.warningf("MWI message without `Message-Account` header")
|
||||
end
|
||||
|
||||
local proto, account = split_first(account_header, ':', true)
|
||||
|
||||
if (not account) or (proto ~= 'sip' and proto ~= 'sips') then
|
||||
return log.warningf("invalid format for voicemail id: %s", account_header)
|
||||
end
|
||||
|
||||
local new_messages, saved_messages = vm_message_count(account)
|
||||
if not new_messages then
|
||||
return log.warningf('can not find voicemail: %s', account)
|
||||
end
|
||||
|
||||
log.noticef('voicemail %s has %s/%s message(s)', account, new_messages, saved_messages)
|
||||
mwi_notify(account, new_messages, saved_messages)
|
||||
end)
|
||||
|
||||
log.notice("start")
|
||||
|
||||
service:run()
|
||||
|
||||
log.notice("stop")
|
||||
@@ -0,0 +1,61 @@
|
||||
<html>
|
||||
<table width="400" border="0" cellspacing="0" cellpadding="0" align="center"
|
||||
style="border: 1px solid #cbcfd5;-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px; border-radius: 4px;">
|
||||
<tr>
|
||||
<td valign="middle" align="center" bgcolor="#e5e9f0" style="background-color: #e5e9f0;
|
||||
color: #000; font-family: Arial; font-size: 14px; padding: 7px;-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px; border-radius: 4px;">
|
||||
<strong>Neue Sprachnachricht</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="padding: 15px;">
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Nebenstelle</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${voicemail_name_formatted}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;" width="20%">
|
||||
<strong>Anrufer</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;" width="80%">
|
||||
${caller_id_number}
|
||||
</td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Received</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${message_date}
|
||||
</td>
|
||||
</tr>
|
||||
-->
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Nachricht</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${message}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Länge</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${message_duration}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Sprachnachricht von ${caller_id_name} <${caller_id_number}> ${message_duration}
|
||||
@@ -0,0 +1,61 @@
|
||||
<html>
|
||||
<table width="400" border="0" cellspacing="0" cellpadding="0" align="center"
|
||||
style="border: 1px solid #cbcfd5;-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px; border-radius: 4px;">
|
||||
<tr>
|
||||
<td valign="middle" align="center" bgcolor="#e5e9f0" style="background-color: #e5e9f0;
|
||||
color: #000; font-family: Arial; font-size: 14px; padding: 7px;-moz-border-radius: 4px;
|
||||
-webkit-border-radius: 4px; border-radius: 4px;">
|
||||
<strong>Neue Sprachnachricht</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top" style="padding: 15px;">
|
||||
<table width="100%" border="0" cellspacing="0" cellpadding="0">
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Nebenstelle</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${voicemail_name_formatted}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;" width="20%">
|
||||
<strong>Anrufer</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;" width="80%">
|
||||
${caller_id_number}
|
||||
</td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Received</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${message_date}
|
||||
</td>
|
||||
</tr>
|
||||
-->
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Nachricht</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${message}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="color: #333; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
<strong>Länge</strong>
|
||||
</td>
|
||||
<td style="color: #666; font-family: Arial; font-size: 12px; padding-bottom: 11px;">
|
||||
${message_duration}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
Sprachnachricht von ${caller_id_name} <${caller_id_number}> ${message_duration}
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
To ${voicemail_name_formatted}
|
||||
Received ${message_date}
|
||||
|
||||
Message ${message}
|
||||
Length ${message_duration}
|
||||
@@ -0,0 +1 @@
|
||||
Voicemail from ${caller_id_name} <${caller_id_number}> ${message_duration}
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
To ${voicemail_name_formatted}
|
||||
Received ${message_date}
|
||||
|
||||
Message ${message}
|
||||
Length ${message_duration}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
|
||||
To ${voicemail_name_formatted}
|
||||
Received ${message_date}
|
||||
|
||||
Message ${message}
|
||||
Length ${message_duration}
|
||||
|
||||
Message Text
|
||||
${message_text}
|
||||
@@ -0,0 +1 @@
|
||||
Voicemail from ${caller_id_name} <${caller_id_number}> ${message_duration}
|
||||
@@ -0,0 +1,108 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 - 2022 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--general functions
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.file_exists";
|
||||
require "resources.functions.explode";
|
||||
|
||||
--if the params class and methods do not exist then add them to prevent errors
|
||||
if (not params) then
|
||||
params = {}
|
||||
function params:getHeader(name)
|
||||
self.name = name;
|
||||
end
|
||||
function params:serialize(name)
|
||||
self.name = name;
|
||||
end
|
||||
end
|
||||
|
||||
--show the params in the console
|
||||
if (debug["params"]) then
|
||||
if (params:serialize() ~= nil) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] Params:\n" .. params:serialize() .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--show the xml request in the console
|
||||
if (debug["xml_request"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] Section: " .. XML_REQUEST["section"] .. "\n");
|
||||
freeswitch.consoleLog("notice", "[xml_handler] Tag Name: " .. XML_REQUEST["tag_name"] .. "\n");
|
||||
freeswitch.consoleLog("notice", "[xml_handler] Key Name: " .. XML_REQUEST["key_name"] .. "\n");
|
||||
freeswitch.consoleLog("notice", "[xml_handler] Key Value: " .. XML_REQUEST["key_value"] .. "\n");
|
||||
end
|
||||
|
||||
--get the params and set them as variables
|
||||
domain_name = params:getHeader("sip_from_host");
|
||||
if (domain_uuid == nil) then
|
||||
domain_uuid = params:getHeader("domain_uuid");
|
||||
end
|
||||
domain_name = params:getHeader("domain");
|
||||
if (domain_name == nil) then
|
||||
domain_name = params:getHeader("domain_name");
|
||||
end
|
||||
if (domain_name == nil) then
|
||||
domain_name = params:getHeader("variable_domain_name");
|
||||
end
|
||||
if (domain_name == nil) then
|
||||
domain_name = params:getHeader("variable_sip_from_host");
|
||||
end
|
||||
purpose = params:getHeader("purpose");
|
||||
profile = params:getHeader("profile");
|
||||
key = params:getHeader("key");
|
||||
user = params:getHeader("user");
|
||||
user_context = params:getHeader("variable_user_context");
|
||||
call_context = params:getHeader("Caller-Context");
|
||||
destination_number = params:getHeader("Caller-Destination-Number");
|
||||
sip_to_user = params:getHeader("variable_sip_to_user");
|
||||
sip_req_user = params:getHeader("variable_sip_req_user");
|
||||
caller_id_number = params:getHeader("Caller-Caller-ID-Number");
|
||||
hunt_context = params:getHeader("Hunt-Context");
|
||||
if (hunt_context ~= nil) then
|
||||
call_context = hunt_context;
|
||||
end
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--process the sections
|
||||
if (XML_REQUEST["section"] == "configuration") then
|
||||
configuration = scripts_dir.."/app/xml_handler/resources/scripts/configuration/"..XML_REQUEST["key_value"]..".lua";
|
||||
if (debug["xml_request"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. configuration .. "\n");
|
||||
end
|
||||
if (file_exists(configuration)) then
|
||||
dofile(configuration);
|
||||
end
|
||||
end
|
||||
if (XML_REQUEST["section"] == "directory") then
|
||||
dofile(scripts_dir.."/app/xml_handler/resources/scripts/directory/directory.lua");
|
||||
end
|
||||
if (XML_REQUEST["section"] == "dialplan") then
|
||||
dofile(scripts_dir.."/app/xml_handler/resources/scripts/dialplan/dialplan.lua");
|
||||
end
|
||||
if (XML_REQUEST["section"] == "languages") then
|
||||
dofile(scripts_dir.."/app/xml_handler/resources/scripts/languages/languages.lua");
|
||||
end
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
-- xml_handler.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2015-2018 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--[[
|
||||
These ACL's are automatically created on startup.
|
||||
rfc1918.auto - RFC1918 Space
|
||||
nat.auto - RFC1918 Excluding your local lan.
|
||||
localnet.auto - ACL for your local lan.
|
||||
loopback.auto - ACL for your local lan.
|
||||
]]
|
||||
|
||||
--include xml library
|
||||
local Xml = require "resources.functions.xml";
|
||||
|
||||
--get the cache
|
||||
local cache = require "resources.functions.cache"
|
||||
local acl_cache_key = "configuration:acl.conf"
|
||||
XML_STRING, err = cache.get(acl_cache_key)
|
||||
|
||||
--set the cache
|
||||
if not XML_STRING then
|
||||
|
||||
--log cache error
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("warning", "[xml_handler] configuration:acl.conf can not be get from the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
|
||||
--set a default value
|
||||
if (expire["acl"] == nil) then
|
||||
expire["acl"]= "3600";
|
||||
end
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--start the xml array
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
xml:append([[<document type="freeswitch/xml">]]);
|
||||
xml:append([[ <section name="configuration">]]);
|
||||
xml:append([[ <configuration name="acl.conf" description="Network Lists">]]);
|
||||
xml:append([[ <network-lists>]]);
|
||||
|
||||
--run the query
|
||||
sql = "select * from v_access_controls ";
|
||||
sql = sql .. "order by access_control_name asc ";
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "\n");
|
||||
end
|
||||
x = 0;
|
||||
dbh:query(sql, function(row)
|
||||
|
||||
--list open tag
|
||||
xml:append([[ <list name="]] .. xml.sanitize(row.access_control_name) .. [[" default="]] .. xml.sanitize(row.access_control_default) .. [[">]]);
|
||||
|
||||
--get the nodes
|
||||
sql = "select * from v_access_control_nodes ";
|
||||
sql = sql .. "where access_control_uuid = :access_control_uuid ";
|
||||
sql = sql .. "and length(node_cidr) > 0 ";
|
||||
local params = {access_control_uuid = row.access_control_uuid}
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
x = 0;
|
||||
dbh:query(sql, params, function(field)
|
||||
xml:append([[ <node type="]] .. xml.sanitize(field.node_type) .. [[" cidr="]] .. xml.sanitize(field.node_cidr) .. [[" description="]] .. xml.sanitize(field.node_description) .. [["/>]]);
|
||||
end)
|
||||
|
||||
--add the domains
|
||||
if (row.access_control_name == 'providers' or row.access_control_name == 'domains') then
|
||||
sql = "select domain_name, domain_description from v_domains ";
|
||||
sql = sql .. "where domain_uuid in (select distinct(domain_uuid) ";
|
||||
sql = sql .. "from v_extensions where enabled = 'true') ";
|
||||
sql = sql .. "and domain_enabled = 'true' ";
|
||||
local params = {}
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. ";\n");
|
||||
end
|
||||
x = 0;
|
||||
dbh:query(sql, params, function(field)
|
||||
xml:append([[ <node type="allow" domain="]] .. xml.sanitize(field.domain_name) .. [[" description="]] .. xml.sanitize(field.domain_description) .. [["/>]]);
|
||||
end)
|
||||
end
|
||||
|
||||
--list close tag
|
||||
xml:append([[ </list>]]);
|
||||
|
||||
end)
|
||||
|
||||
--close the extension tag if it was left open
|
||||
xml:append([[ </network-lists>]]);
|
||||
xml:append([[ </configuration>]]);
|
||||
xml:append([[ </section>]]);
|
||||
xml:append([[</document>]]);
|
||||
XML_STRING = xml:build();
|
||||
if (debug["xml_string"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] XML_STRING: " .. XML_STRING .. "\n");
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
|
||||
--set the cache
|
||||
local ok, err = cache.set(acl_cache_key, XML_STRING, expire["acl"]);
|
||||
if debug["cache"] then
|
||||
if ok then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. acl_cache_key .. " stored in the cache\n");
|
||||
else
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. acl_cache_key .. " can not be stored in the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. acl_cache_key .. " source: database\n");
|
||||
end
|
||||
else
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. acl_cache_key .. " source: cache\n");
|
||||
end
|
||||
end --if XML_STRING
|
||||
|
||||
--send the xml to the console
|
||||
if (debug["xml_string"]) then
|
||||
local file = assert(io.open(temp_dir .. "/acl.conf.xml", "w"));
|
||||
file:write(XML_STRING);
|
||||
file:close();
|
||||
end
|
||||
+347
@@ -0,0 +1,347 @@
|
||||
-- xml_handler.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2015-2022 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--include functions
|
||||
require "resources.functions.format_ringback"
|
||||
|
||||
--include xml library
|
||||
local Xml = require "resources.functions.xml";
|
||||
|
||||
--get the cache
|
||||
local cache = require "resources.functions.cache"
|
||||
hostname = trim(api:execute("switchname", ""));
|
||||
local cc_cache_key = "configuration:callcenter.conf:" .. hostname
|
||||
XML_STRING, err = cache.get(cc_cache_key)
|
||||
|
||||
--set the cache
|
||||
if not XML_STRING then
|
||||
--log cache error
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. cc_cache_key .. " can not be get from the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--get the variables
|
||||
dsn = freeswitch.getGlobalVariable("dsn") or ''
|
||||
dsn_callcenter = freeswitch.getGlobalVariable("dsn_callcenter") or ''
|
||||
|
||||
--start the xml array
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
xml:append([[<document type="freeswitch/xml">]]);
|
||||
xml:append([[ <section name="configuration">]]);
|
||||
xml:append([[ <configuration name="callcenter.conf" description="Call Center">]]);
|
||||
xml:append([[ <settings>]]);
|
||||
if #dsn_callcenter > 0 then
|
||||
xml:append([[ <param name="odbc-dsn" value="]] .. xml.sanitize(dsn_callcenter) .. [["/>]]);
|
||||
elseif #dsn > 0 then
|
||||
xml:append([[ <param name="odbc-dsn" value="]] .. xml.sanitize(database["switch"]) .. [["/>]]);
|
||||
end
|
||||
xml:append([[ <param name="cc-instance-id" value="]] .. xml.sanitize(hostname) .. [["/>]]);
|
||||
-- xml:append([[ <param name="dbname" value="]] .. xml.sanitize(database_dir) .. [[/call_center.db"/>]]);
|
||||
xml:append([[ </settings>]]);
|
||||
|
||||
--write the queues
|
||||
xml:append([[ <queues>]]);
|
||||
sql = "select * from v_call_center_queues as q, v_domains as d ";
|
||||
sql = sql .. "where d.domain_uuid = q.domain_uuid; ";
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "\n");
|
||||
end
|
||||
x = 0;
|
||||
dbh:query(sql, function(row)
|
||||
--set as variables
|
||||
queue_uuid = row.call_center_queue_uuid;
|
||||
domain_uuid = row.domain_uuid;
|
||||
domain_name = row.domain_name;
|
||||
queue_name = row.queue_name;
|
||||
queue_extension = row.queue_extension;
|
||||
queue_strategy = row.queue_strategy;
|
||||
queue_moh_sound = row.queue_moh_sound;
|
||||
queue_record_template = row.queue_record_template;
|
||||
queue_time_base_score = row.queue_time_base_score;
|
||||
queue_max_wait_time = row.queue_max_wait_time;
|
||||
queue_max_wait_time_with_no_agent = row.queue_max_wait_time_with_no_agent;
|
||||
queue_max_wait_time_with_no_agent_time_reached = row.queue_max_wait_time_with_no_agent_time_reached;
|
||||
queue_tier_rules_apply = row.queue_tier_rules_apply;
|
||||
queue_tier_rule_wait_second = row.queue_tier_rule_wait_second;
|
||||
queue_tier_rule_wait_multiply_level = row.queue_tier_rule_wait_multiply_level;
|
||||
queue_tier_rule_no_agent_no_wait = row.queue_tier_rule_no_agent_no_wait;
|
||||
queue_discard_abandoned_after = row.queue_discard_abandoned_after;
|
||||
queue_abandoned_resume_allowed = row.queue_abandoned_resume_allowed;
|
||||
queue_announce_sound = row.queue_announce_sound;
|
||||
queue_announce_frequency = row.queue_announce_frequency;
|
||||
queue_description = row.queue_description;
|
||||
|
||||
--replace the space with a dash
|
||||
queue_name = queue_name:gsub(" ", "-");
|
||||
|
||||
--sanitize the queue_record_template and allow specific variables
|
||||
queue_record_template = xml.sanitize(queue_record_template);
|
||||
queue_record_template = string.gsub(queue_record_template, "{strftime", "${strftime");
|
||||
queue_record_template = string.gsub(queue_record_template, "{uuid}", "${uuid}");
|
||||
queue_record_template = string.gsub(queue_record_template, "{record_ext}", "${record_ext}");
|
||||
|
||||
--start the xml
|
||||
xml:append([[ <queue name="]] .. xml.sanitize(queue_extension) .. [[@]] .. xml.sanitize(domain_name) .. [[" label="]] .. xml.sanitize(queue_name) .. [[@]] .. xml.sanitize(domain_name) .. [[">]]);
|
||||
xml:append([[ <param name="strategy" value="]] .. xml.sanitize(queue_strategy) .. [["/>]]);
|
||||
--set ringback
|
||||
queue_ringback = format_ringback(queue_moh_sound);
|
||||
xml:append([[ <param name="moh-sound" value="]] .. xml.sanitize(queue_ringback) .. [["/>]]);
|
||||
if (queue_record_template ~= nil) then
|
||||
xml:append([[ <param name="record-template" value="]] .. queue_record_template .. [["/>]]);
|
||||
end
|
||||
if (queue_time_base_score ~= nil) then
|
||||
xml:append([[ <param name="time-base-score" value="]] .. xml.sanitize(queue_time_base_score) .. [["/>]]);
|
||||
end
|
||||
if (queue_max_wait_time_with_no_agent ~= nil) then
|
||||
xml:append([[ <param name="max-wait-time" value="]] .. xml.sanitize(queue_max_wait_time) .. [["/>]]);
|
||||
end
|
||||
if (queue_max_wait_time_with_no_agent ~= nil) then
|
||||
xml:append([[ <param name="max-wait-time-with-no-agent" value="]] .. xml.sanitize(queue_max_wait_time_with_no_agent) .. [["/>]]);
|
||||
end
|
||||
if (queue_max_wait_time_with_no_agent_time_reached ~= nil) then
|
||||
xml:append([[ <param name="max-wait-time-with-no-agent-time-reached" value="]] .. xml.sanitize(queue_max_wait_time_with_no_agent_time_reached) .. [["/>]]);
|
||||
end
|
||||
if (queue_tier_rules_apply ~= nil) then
|
||||
xml:append([[ <param name="tier-rules-apply" value="]] .. xml.sanitize(queue_tier_rules_apply) .. [["/>]]);
|
||||
end
|
||||
if (queue_tier_rule_wait_second ~= nil) then
|
||||
xml:append([[ <param name="tier-rule-wait-second" value="]] .. xml.sanitize(queue_tier_rule_wait_second) .. [["/>]]);
|
||||
end
|
||||
if (queue_tier_rule_wait_multiply_level ~= nil) then
|
||||
xml:append([[ <param name="tier-rule-wait-multiply-level" value="]] .. xml.sanitize(queue_tier_rule_wait_multiply_level) .. [["/>]]);
|
||||
end
|
||||
if (queue_tier_rule_no_agent_no_wait ~= nil) then
|
||||
xml:append([[ <param name="tier-rule-no-agent-no-wait" value="]] .. xml.sanitize(queue_tier_rule_no_agent_no_wait) .. [["/>]]);
|
||||
end
|
||||
if (queue_discard_abandoned_after ~= nil) then
|
||||
xml:append([[ <param name="discard-abandoned-after" value="]] .. xml.sanitize(queue_discard_abandoned_after) .. [["/>]]);
|
||||
end
|
||||
if (queue_abandoned_resume_allowed ~= nil) then
|
||||
xml:append([[ <param name="abandoned-resume-allowed" value="]] .. xml.sanitize(queue_abandoned_resume_allowed) .. [["/>]]);
|
||||
end
|
||||
if (queue_announce_sound ~= nil) then
|
||||
xml:append([[ <param name="announce-sound" value="]] .. xml.sanitize(queue_announce_sound) .. [["/>]]);
|
||||
end
|
||||
if (queue_announce_frequency ~= nil) then
|
||||
xml:append([[ <param name="announce-frequency" value="]] .. xml.sanitize(queue_announce_frequency) .. [["/>]]);
|
||||
end
|
||||
xml:append([[ </queue>]]);
|
||||
|
||||
--increment the value of x
|
||||
x = x + 1;
|
||||
end)
|
||||
xml:append([[ </queues>]]);
|
||||
|
||||
--get the agents
|
||||
xml:append([[ <agents>]]);
|
||||
sql = "select SPLIT_PART(SPLIT_PART(a.agent_contact, '/', 2), '@', 1) as extension, ";
|
||||
sql = sql .. "(select extension_uuid from v_extensions where domain_uuid = a.domain_uuid ";
|
||||
sql = sql .. "and extension = SPLIT_PART(SPLIT_PART(a.agent_contact, '/', 2), '@', 1) limit 1) as extension_uuid, ";
|
||||
sql = sql .. "a.*, d.domain_name ";
|
||||
sql = sql .. "from v_call_center_agents as a, v_domains as d ";
|
||||
sql = sql .. "where d.domain_uuid = a.domain_uuid; ";
|
||||
--sql = "select * from v_call_center_agents as a, v_domains as d ";
|
||||
--sql = sql .. "where d.domain_uuid = a.domain_uuid; ";
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "\n");
|
||||
end
|
||||
x = 0;
|
||||
dbh:query(sql, function(row)
|
||||
--get the values from the database and set as variables
|
||||
agent_uuid = row.call_center_agent_uuid;
|
||||
domain_uuid = row.domain_uuid;
|
||||
domain_name = row.domain_name;
|
||||
extension_uuid = row.extension_uuid;
|
||||
agent_name = row.agent_name;
|
||||
agent_type = row.agent_type;
|
||||
agent_call_timeout = row.agent_call_timeout;
|
||||
agent_contact = row.agent_contact;
|
||||
agent_status = row.agent_status;
|
||||
agent_no_answer_delay_time = row.agent_no_answer_delay_time;
|
||||
agent_max_no_answer = row.agent_max_no_answer;
|
||||
agent_wrap_up_time = row.agent_wrap_up_time;
|
||||
agent_reject_delay_time = row.agent_reject_delay_time;
|
||||
agent_busy_delay_time = row.agent_busy_delay_time;
|
||||
agent_record = row.agent_record;
|
||||
|
||||
--get and then set the complete agent_contact with the call_timeout and when necessary confirm
|
||||
--confirm = "group_confirm_file=custom/press_1_to_accept_this_call.wav,group_confirm_key=1";
|
||||
--if you change this variable also change app/call_center/call_center_agent_edit.php
|
||||
confirm = "group_confirm_file=ivr/ivr-accept_reject_voicemail.wav,group_confirm_key=1,group_confirm_read_timeout=2000,leg_timeout="..agent_call_timeout;
|
||||
local record = "";
|
||||
if (agent_record == "true") then
|
||||
record = string.format(",execute_on_pre_bridge='record_session %s/%s/archive/${strftime(%%Y)}/${strftime(%%b)}/${strftime(%%d)}/${uuid}.${record_ext}'", recordings_dir, domain_name)
|
||||
end
|
||||
if (string.find(agent_contact, '}') == nil) then
|
||||
--not found
|
||||
if (string.find(agent_contact, 'sofia/gateway') == nil) then
|
||||
--add the call_timeout
|
||||
agent_contact = "{call_timeout="..agent_call_timeout..",domain_name="..domain_name..",domain_uuid="..domain_uuid..",extension_uuid="..extension_uuid..",sip_h_caller_destination=${caller_destination}"..record.."}"..agent_contact;
|
||||
else
|
||||
--add the call_timeout and confirm
|
||||
agent_contact = "{"..confirm..",call_timeout="..agent_call_timeout..",domain_name="..domain_name..",domain_uuid="..domain_uuid..",sip_h_caller_destination=${caller_destination}}"..agent_contact;
|
||||
end
|
||||
else
|
||||
--found
|
||||
if (string.find(agent_contact, 'sofia/gateway') == nil) then
|
||||
--not found
|
||||
if (string.find(agent_contact, 'call_timeout') == nil) then
|
||||
--add the call_timeout
|
||||
pos = string.find(agent_contact, "}");
|
||||
first = string.sub(agent_contact, 0, pos -1);
|
||||
last = string.sub(agent_contact, pos);
|
||||
agent_contact = first..[[,domain_name=]]..domain_name..[[,domain_uuid=]]..domain_uuid..[[,sip_h_caller_destination=${caller_destination},call_timeout=]]..agent_call_timeout..last;
|
||||
else
|
||||
--add the call_timeout
|
||||
pos = string.find(agent_contact, "}");
|
||||
first = string.sub(agent_contact, 0, pos - 1);
|
||||
last = string.sub(agent_contact, pos);
|
||||
agent_contact = first..[[,sip_h_caller_destination=${caller_destination},call_timeout=]]..agent_call_timeout..last;
|
||||
end
|
||||
else
|
||||
--found
|
||||
pos = string.find(agent_contact, "}");
|
||||
first = string.sub(agent_contact, 0, pos - 1);
|
||||
last = string.sub(agent_contact, pos);
|
||||
if (string.find(agent_contact, 'call_timeout') == nil) then
|
||||
--add the call_timeout and confirm
|
||||
agent_contact = first..','..confirm..',sip_h_caller_destination=${caller_destination},domain_name="..domain_name..",domain_uuid="..domain_uuid..",sip_h_caller_destination=${caller_destination},call_timeout='..agent_call_timeout..last;
|
||||
else
|
||||
--add confirm
|
||||
agent_contact = tmp_first..',domain_name="..domain_name..",domain_uuid="..domain_uuid..",sip_h_caller_destination=${caller_destination},'..confirm..tmp_last;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--sanitize the agent_contact and allow specific variables
|
||||
agent_contact = xml.sanitize(agent_contact);
|
||||
agent_contact = string.gsub(agent_contact, "{caller_destination}", "${caller_destination}");
|
||||
|
||||
--build the xml string
|
||||
xml:append([[ <agent ]]);
|
||||
xml:append([[ name="]] .. xml.sanitize(agent_uuid) .. [[" ]]);
|
||||
xml:append([[ label="]] .. xml.sanitize(agent_name) .. [[@]] .. xml.sanitize(domain_name) .. [[" ]]);
|
||||
xml:append([[ type="]] .. xml.sanitize(agent_type) .. [[" ]]);
|
||||
xml:append([[ contact="]] .. agent_contact .. [[" ]]);
|
||||
xml:append([[ status="]] .. xml.sanitize(agent_status) .. [[" ]]);
|
||||
if (agent_no_answer_delay_time ~= nil) then
|
||||
xml:append([[ no-answer-delay-time="]] .. xml.sanitize(agent_no_answer_delay_time) .. [[" ]]);
|
||||
end
|
||||
if (agent_max_no_answer ~= nil) then
|
||||
xml:append([[ max-no-answer="]] .. xml.sanitize(agent_max_no_answer) .. [[" ]]);
|
||||
end
|
||||
if (agent_wrap_up_time ~= nil) then
|
||||
xml:append([[ wrap-up-time="]] .. xml.sanitize(agent_wrap_up_time) .. [[" ]]);
|
||||
end
|
||||
if (agent_reject_delay_time ~= nil) then
|
||||
xml:append([[ reject-delay-time="]] .. xml.sanitize(agent_reject_delay_time) .. [[" ]]);
|
||||
end
|
||||
if (agent_busy_delay_time ~= nil) then
|
||||
xml:append([[ busy-delay-time="]] .. xml.sanitize(agent_busy_delay_time) .. [[" ]]);
|
||||
end
|
||||
xml:append([[ />]]);
|
||||
end)
|
||||
xml:append([[ </agents>]]);
|
||||
|
||||
--get the tiers
|
||||
sql = "select t.domain_uuid, d.domain_name, t.call_center_agent_uuid, t.call_center_queue_uuid, q.queue_extension, t.tier_level, t.tier_position ";
|
||||
sql = sql .. "from v_call_center_tiers as t, v_domains as d, v_call_center_queues as q ";
|
||||
sql = sql .. "where d.domain_uuid = t.domain_uuid ";
|
||||
sql = sql .. "and t.call_center_queue_uuid = q.call_center_queue_uuid; ";
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "\n");
|
||||
end
|
||||
xml:append([[ <tiers>]]);
|
||||
dbh:query(sql, function(row)
|
||||
--get the values from the database and set as variables
|
||||
domain_uuid = row.domain_uuid;
|
||||
domain_name = row.domain_name;
|
||||
agent_uuid = row.call_center_agent_uuid;
|
||||
queue_uuid = row.call_center_queue_uuid;
|
||||
queue_extension = row.queue_extension;
|
||||
tier_level = row.tier_level;
|
||||
tier_position = row.tier_position;
|
||||
--build the xml
|
||||
xml:append([[ <tier ]]);
|
||||
xml:append([[ agent="]] .. xml.sanitize(agent_uuid) .. [[" ]]);
|
||||
xml:append([[ queue="]] .. xml.sanitize(queue_extension) .. [[@]] .. xml.sanitize(domain_name) .. [[" ]]);
|
||||
xml:append([[ domain_name="]] .. xml.sanitize(domain_name) .. [[" ]]);
|
||||
--xml:append([[ agent_name="]] .. xml.sanitize(agent_name) .. [[" ]]);
|
||||
--xml:append([[ queue_name="]] .. xml.sanitize(queue_name) .. [[" ]]);
|
||||
xml:append([[ level="]] .. xml.sanitize(tier_level) .. [[" ]]);
|
||||
xml:append([[ position="]] .. xml.sanitize(tier_position) .. [[" ]]);
|
||||
xml:append([[ />]]);
|
||||
end)
|
||||
xml:append([[ </tiers>]]);
|
||||
|
||||
--close the extension tag if it was left open
|
||||
xml:append([[ </configuration>]]);
|
||||
xml:append([[ </section>]]);
|
||||
xml:append([[</document>]]);
|
||||
XML_STRING = xml:build();
|
||||
if (debug["xml_string"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] XML_STRING: " .. XML_STRING .. "\n");
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
--freeswitch.consoleLog("notice", "[xml_handler]"..api:execute("eval ${dsn}"));
|
||||
|
||||
--set the cache
|
||||
local ok, err = cache.set(cc_cache_key, XML_STRING, expire["callcenter"]);
|
||||
if debug["cache"] then
|
||||
if ok then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. cc_cache_key .. " stored in the cache\n");
|
||||
else
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. cc_cache_key .. " can not be stored in the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. cc_cache_key .. " source: database\n");
|
||||
end
|
||||
else
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. cc_cache_key .. " source: cache\n");
|
||||
end
|
||||
end --if XML_STRING
|
||||
|
||||
--send the xml to the console
|
||||
if (debug["xml_string"]) then
|
||||
local file = assert(io.open(temp_dir .. "/callcenter.conf.xml", "w"));
|
||||
file:write(XML_STRING);
|
||||
file:close();
|
||||
end
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
-- xml_handler.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2016 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--include xml library
|
||||
local Xml = require "resources.functions.xml";
|
||||
|
||||
--set the xml array
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
xml:append([[<document type="freeswitch/xml">]]);
|
||||
xml:append([[ <section name="configuration">]]);
|
||||
xml:append([[ <configuration name="conference.conf" description="Audio Conference">]]);
|
||||
|
||||
--start the conference controls
|
||||
xml:append([[ <caller-controls>]]);
|
||||
sql = [[SELECT * FROM v_conference_controls
|
||||
WHERE control_enabled = 'true' ]];
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference_control] SQL: " .. sql .. "\n");
|
||||
end
|
||||
dbh:query(sql, function(field)
|
||||
conference_control_uuid = field["conference_control_uuid"];
|
||||
xml:append([[ <group name="]] .. xml.sanitize(field["control_name"]) .. [[">]]);
|
||||
|
||||
--get the conference control details from the database
|
||||
sql = [[SELECT * FROM v_conference_control_details
|
||||
WHERE conference_control_uuid = :conference_control_uuid
|
||||
AND control_enabled = 'true' ]];
|
||||
local params = {conference_control_uuid = conference_control_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference_control] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
--conference_control_uuid = row["conference_control_uuid"];
|
||||
--conference_control_detail_uuid = row["conference_control_detail_uuid"];
|
||||
xml:append([[ <control digits="]] .. xml.sanitize(row["control_digits"]) .. [[" action="]] .. xml.sanitize(row["control_action"]) .. [[" data="]] .. xml.sanitize(row["control_data"]) .. [["/>]]);
|
||||
end);
|
||||
xml:append([[ </group>]]);
|
||||
end);
|
||||
xml:append([[ </caller-controls>]]);
|
||||
|
||||
|
||||
--start the conference profiles
|
||||
xml:append([[ <profiles>]]);
|
||||
sql = [[SELECT * FROM v_conference_profiles
|
||||
WHERE profile_enabled = 'true' ]];
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference_profiles] SQL: " .. sql .. "\n");
|
||||
end
|
||||
dbh:query(sql, function(field)
|
||||
conference_profile_uuid = field["conference_profile_uuid"];
|
||||
xml:append([[ <profile name="]] .. xml.sanitize(field["profile_name"]) .. [[">]]);
|
||||
|
||||
--get the conference profile parameters from the database
|
||||
sql = [[SELECT * FROM v_conference_profile_params
|
||||
WHERE conference_profile_uuid = :conference_profile_uuid
|
||||
AND profile_param_enabled = 'true' ]];
|
||||
local params = {conference_profile_uuid = conference_profile_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[conference_profiles] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
--conference_profile_uuid = row["conference_profile_uuid"];
|
||||
--conference_profile_param_uuid = row["conference_profile_param_uuid"];
|
||||
--profile_param_description = row["profile_param_description"];
|
||||
xml:append([[ <param name="]] .. xml.sanitize(row["profile_param_name"]) .. [[" value="]] .. xml.sanitize(row["profile_param_value"]) .. [["/>]]);
|
||||
end);
|
||||
xml:append([[ </profile>]]);
|
||||
end);
|
||||
xml:append([[ </profiles>]]);
|
||||
|
||||
--set the xml array and then concatenate the array to a string
|
||||
xml:append([[ </configuration>]]);
|
||||
xml:append([[ </section>]]);
|
||||
xml:append([[</document>]]);
|
||||
XML_STRING = xml:build();
|
||||
if (debug["xml_string"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] XML_STRING: " .. XML_STRING .. "\n");
|
||||
end
|
||||
|
||||
--send the xml to the console
|
||||
if (debug["xml_string"]) then
|
||||
local file = assert(io.open(temp_dir .."/conference.conf.xml", "w"));
|
||||
file:write(XML_STRING);
|
||||
file:close();
|
||||
end
|
||||
+358
@@ -0,0 +1,358 @@
|
||||
-- xml_handler.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2016-2022 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--get the ivr name
|
||||
ivr_menu_uuid = params:getHeader("Menu-Name");
|
||||
original_ivr_menu_uuid = ivr_menu_uuid
|
||||
|
||||
local log = require "resources.functions.log".ivr_menu
|
||||
|
||||
--include xml library
|
||||
local Xml = require "resources.functions.xml";
|
||||
|
||||
--get the cache
|
||||
local cache = require "resources.functions.cache"
|
||||
local ivr_menu_cache_key = "configuration:ivr.conf:" .. ivr_menu_uuid
|
||||
XML_STRING, err = cache.get(ivr_menu_cache_key)
|
||||
|
||||
--set the cache
|
||||
if not XML_STRING then
|
||||
--log cache error
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. ivr_menu_cache_key .. " can not be get from the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
|
||||
--required includes
|
||||
local Database = require "resources.functions.database"
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--start the xml array
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
xml:append([[<document type="freeswitch/xml">]]);
|
||||
xml:append([[ <section name="configuration">]]);
|
||||
xml:append([[ <configuration name="ivr.conf" description="IVR Menus">]]);
|
||||
xml:append([[ <menus>]]);
|
||||
|
||||
--set the sound prefix
|
||||
sound_prefix = sounds_dir.."/${default_language}/${default_dialect}/${default_voice}/";
|
||||
|
||||
--connect to the database
|
||||
local dbh = Database.new('system');
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--get the ivr menu from the database
|
||||
local sql = [[
|
||||
with recursive ivr_menus as (
|
||||
select *
|
||||
from v_ivr_menus
|
||||
where ivr_menu_uuid = :ivr_menu_uuid
|
||||
and ivr_menu_enabled = 'true'
|
||||
union all
|
||||
select child.*
|
||||
from v_ivr_menus as child, ivr_menus as parent
|
||||
where child.ivr_menu_parent_uuid = parent.ivr_menu_uuid
|
||||
and child.ivr_menu_enabled = 'true'
|
||||
)
|
||||
select * from ivr_menus
|
||||
]];
|
||||
local params = {ivr_menu_uuid = ivr_menu_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[ivr_menu] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
|
||||
--set the variables
|
||||
domain_uuid = row["domain_uuid"];
|
||||
ivr_menu_uuid = row["ivr_menu_uuid"];
|
||||
ivr_menu_name = row["ivr_menu_name"];
|
||||
ivr_menu_extension = row["ivr_menu_extension"];
|
||||
ivr_menu_greet_long = row["ivr_menu_greet_long"];
|
||||
ivr_menu_greet_short = row["ivr_menu_greet_short"];
|
||||
ivr_menu_invalid_sound = row["ivr_menu_invalid_sound"];
|
||||
ivr_menu_exit_sound = row["ivr_menu_exit_sound"];
|
||||
ivr_menu_pin_number = row["ivr_menu_pin_number"];
|
||||
ivr_menu_confirm_macro = row["ivr_menu_confirm_macro"];
|
||||
ivr_menu_confirm_key = row["ivr_menu_confirm_key"];
|
||||
ivr_menu_tts_engine = row["ivr_menu_tts_engine"];
|
||||
ivr_menu_tts_voice = row["ivr_menu_tts_voice"];
|
||||
ivr_menu_confirm_attempts = row["ivr_menu_confirm_attempts"];
|
||||
ivr_menu_timeout = row["ivr_menu_timeout"];
|
||||
ivr_menu_exit_app = row["ivr_menu_exit_app"];
|
||||
ivr_menu_exit_data = row["ivr_menu_exit_data"];
|
||||
ivr_menu_inter_digit_timeout = row["ivr_menu_inter_digit_timeout"];
|
||||
ivr_menu_max_failures = row["ivr_menu_max_failures"];
|
||||
ivr_menu_max_timeouts = row["ivr_menu_max_timeouts"];
|
||||
ivr_menu_digit_len = row["ivr_menu_digit_len"];
|
||||
ivr_menu_direct_dial = row["ivr_menu_direct_dial"];
|
||||
ivr_menu_ringback = row["ivr_menu_ringback"];
|
||||
ivr_menu_cid_prefix = row["ivr_menu_cid_prefix"];
|
||||
ivr_menu_description = row["ivr_menu_description"];
|
||||
|
||||
--set variables from settings
|
||||
local settings = Settings.new(dbh, domain_name, domain_uuid)
|
||||
|
||||
--direct dial length
|
||||
local direct_dial_digits_min = settings:get('ivr_menu', 'direct_dial_digits_min', 'numeric') or 2;
|
||||
local direct_dial_digits_max = settings:get('ivr_menu', 'direct_dial_digits_max', 'numeric') or 11;
|
||||
|
||||
--storage path
|
||||
local storage_type = settings:get('recordings', 'storage_type', 'text')
|
||||
local storage_path = settings:get('recordings', 'storage_path', 'text')
|
||||
if (storage_path ~= nil) then
|
||||
storage_path = storage_path:gsub("${domain_name}", domain_name)
|
||||
storage_path = storage_path:gsub("${domain_uuid}", domain_uuid)
|
||||
end
|
||||
|
||||
--get the recordings from the database
|
||||
ivr_menu_greet_long_is_base64 = false;
|
||||
ivr_menu_greet_short_is_base64 = false;
|
||||
ivr_menu_invalid_sound_is_base64 = false;
|
||||
ivr_menu_exit_sound_is_base64 = false;
|
||||
if (storage_type == "base64") then
|
||||
--include the file io
|
||||
local file = require "resources.functions.file"
|
||||
|
||||
--connect to db
|
||||
local dbh = Database.new('system', 'base64/read');
|
||||
|
||||
--base path for recordings
|
||||
local base_path = recordings_dir.."/"..domain_name
|
||||
|
||||
--function to get recording to local fs
|
||||
local function load_record(name)
|
||||
local path = base_path .. "/" .. name;
|
||||
local is_base64 = false;
|
||||
|
||||
if not file_exists(path) then
|
||||
local sql = "SELECT recording_base64 FROM v_recordings " ..
|
||||
"WHERE domain_uuid = :domain_uuid " ..
|
||||
"AND recording_filename = :name "
|
||||
local params = {domain_uuid = domain_uuid, name = name};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[ivr_menu] SQL: "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
--save the recording to the file system
|
||||
if #row.recording_base64 > 32 then
|
||||
is_base64 = true;
|
||||
file.write_base64(path, row.recording_base64);
|
||||
--add the full path and file name
|
||||
name = path;
|
||||
end
|
||||
end);
|
||||
end
|
||||
return name, is_base64
|
||||
end
|
||||
|
||||
--greet long
|
||||
if #ivr_menu_greet_long > 1 then
|
||||
ivr_menu_greet_long, ivr_menu_greet_long_is_base64 = load_record(ivr_menu_greet_long)
|
||||
end
|
||||
|
||||
--greet short
|
||||
if #ivr_menu_greet_short > 1 then
|
||||
ivr_menu_greet_short, ivr_menu_greet_short_is_base64 = load_record(ivr_menu_greet_short)
|
||||
end
|
||||
|
||||
--invalid sound
|
||||
if #ivr_menu_invalid_sound > 1 then
|
||||
ivr_menu_invalid_sound, ivr_menu_invalid_sound_is_base64 = load_record(ivr_menu_invalid_sound)
|
||||
end
|
||||
|
||||
--exit sound
|
||||
if #ivr_menu_exit_sound > 1 then
|
||||
ivr_menu_exit_sound, ivr_menu_exit_sound_is_base64 = load_record(ivr_menu_exit_sound)
|
||||
end
|
||||
|
||||
dbh:release()
|
||||
elseif (storage_type == "http_cache") then
|
||||
--add the path to file name
|
||||
ivr_menu_greet_long = storage_path.."/"..ivr_menu_greet_long;
|
||||
ivr_menu_greet_short = storage_path.."/"..ivr_menu_greet_short;
|
||||
ivr_menu_invalid_sound = storage_path.."/"..ivr_menu_invalid_sound;
|
||||
ivr_menu_exit_sound = storage_path.."/"..ivr_menu_exit_sound;
|
||||
end
|
||||
|
||||
--greet long
|
||||
if (not ivr_menu_greet_long_is_base64 and not file_exists(ivr_menu_greet_long)) then
|
||||
if (file_exists(recordings_dir.."/"..domain_name.."/"..ivr_menu_greet_long)) then
|
||||
ivr_menu_greet_long = recordings_dir.."/"..domain_name.."/"..ivr_menu_greet_long;
|
||||
--elseif (file_exists(sounds_dir.."/en/us/callie/8000/"..ivr_menu_greet_long)) then
|
||||
-- ivr_menu_greet_long = sounds_dir.."/${default_language}/${default_dialect}/${default_voice}/"..ivr_menu_greet_long;
|
||||
end
|
||||
end
|
||||
|
||||
--greet short
|
||||
if (string.len(ivr_menu_greet_short) > 1) then
|
||||
if (not ivr_menu_greet_short_is_base64 and not file_exists(ivr_menu_greet_short)) then
|
||||
if (file_exists(recordings_dir.."/"..domain_name.."/"..ivr_menu_greet_short)) then
|
||||
ivr_menu_greet_short = recordings_dir.."/"..domain_name.."/"..ivr_menu_greet_short;
|
||||
--elseif (file_exists(sounds_dir.."/en/us/callie/8000/"..ivr_menu_greet_short)) then
|
||||
-- ivr_menu_greet_short = sounds_dir.."/${default_language}/${default_dialect}/${default_voice}/"..ivr_menu_greet_short;
|
||||
end
|
||||
end
|
||||
else
|
||||
ivr_menu_greet_short = ivr_menu_greet_long;
|
||||
end
|
||||
|
||||
--invalid sound
|
||||
if (not ivr_menu_invalid_sound_is_base64 and not file_exists(ivr_menu_invalid_sound)) then
|
||||
if (file_exists(recordings_dir.."/"..domain_name.. "/"..ivr_menu_invalid_sound)) then
|
||||
ivr_menu_invalid_sound = recordings_dir.."/"..domain_name.."/"..ivr_menu_invalid_sound;
|
||||
elseif (file_exists(sounds_dir.."/en/us/callie/8000/"..ivr_menu_invalid_sound)) then
|
||||
ivr_menu_invalid_sound = sounds_dir.."/${default_language}/${default_dialect}/${default_voice}/"..ivr_menu_invalid_sound;
|
||||
end
|
||||
end
|
||||
|
||||
--exit sound
|
||||
if (not ivr_menu_exit_sound_is_base64 and not file_exists(ivr_menu_exit_sound)) then
|
||||
if (file_exists(recordings_dir.."/"..ivr_menu_exit_sound)) then
|
||||
if (ivr_menu_exit_sound ~= nil and ivr_menu_exit_sound ~= "") then
|
||||
ivr_menu_exit_sound = recordings_dir.."/"..domain_name.."/"..ivr_menu_exit_sound;
|
||||
end
|
||||
elseif (file_exists(sounds_dir.."/en/us/callie/8000/"..ivr_menu_exit_sound)) then
|
||||
ivr_menu_exit_sound = sounds_dir.."/${default_language}/${default_dialect}/${default_voice}/"..ivr_menu_exit_sound;
|
||||
end
|
||||
end
|
||||
|
||||
--add xml to the array
|
||||
xml:append([[ <menu name="]] .. xml.sanitize(ivr_menu_uuid) .. [[" description="]] .. xml.sanitize(ivr_menu_name) .. [[" ]]);
|
||||
xml:append([[ greet-long="]] .. xml.sanitize(ivr_menu_greet_long) .. [[" ]]);
|
||||
xml:append([[ greet-short="]] .. xml.sanitize(ivr_menu_greet_short) .. [[" ]]);
|
||||
xml:append([[ invalid-sound="]] .. xml.sanitize(ivr_menu_invalid_sound) .. [[" ]]);
|
||||
xml:append([[ exit-sound="]] .. xml.sanitize(ivr_menu_exit_sound) .. [[" ]]);
|
||||
xml:append([[ pin="]] .. xml.sanitize(ivr_menu_pin_number) .. [[" ]]);
|
||||
xml:append([[ confirm-macro="]] .. xml.sanitize(ivr_menu_confirm_macro) .. [[" ]]);
|
||||
xml:append([[ confirm-key="]] .. xml.sanitize(ivr_menu_confirm_key) .. [[" ]]);
|
||||
xml:append([[ tts-engine="]] .. xml.sanitize(ivr_menu_tts_engine) .. [[" ]]);
|
||||
xml:append([[ tts-voice="]] .. xml.sanitize(ivr_menu_tts_voice) .. [[" ]]);
|
||||
xml:append([[ confirm-attempts="]] .. xml.sanitize(ivr_menu_confirm_attempts) .. [[" ]]);
|
||||
xml:append([[ timeout="]] .. xml.sanitize(ivr_menu_timeout) .. [[" ]]);
|
||||
xml:append([[ inter-digit-timeout="]] .. xml.sanitize(ivr_menu_inter_digit_timeout) .. [[" ]]);
|
||||
xml:append([[ max-failures="]] .. xml.sanitize(ivr_menu_max_failures) .. [[" ]]);
|
||||
xml:append([[ max-timeouts="]] .. xml.sanitize(ivr_menu_max_timeouts) .. [[" ]]);
|
||||
xml:append([[ digit-len="]] .. xml.sanitize(ivr_menu_digit_len) .. [[" ]]);
|
||||
xml:append([[ ivr_menu_exit_app="]] .. xml.sanitize(ivr_menu_exit_app) .. [[" ]]);
|
||||
xml:append([[ ivr_menu_exit_data="]] .. xml.sanitize(ivr_menu_exit_data) .. [[" ]]);
|
||||
xml:append([[ >]]);
|
||||
|
||||
--get the ivr menu options
|
||||
local sql = [[ SELECT * FROM v_ivr_menu_options WHERE ivr_menu_uuid = :ivr_menu_uuid AND ivr_menu_option_enabled = 'true' ORDER BY ivr_menu_option_order asc ]];
|
||||
local params = {ivr_menu_uuid = ivr_menu_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[ivr_menu] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
local direct_dial_exclude = {};
|
||||
dbh:query(sql, params, function(r)
|
||||
ivr_menu_option_digits = r.ivr_menu_option_digits
|
||||
ivr_menu_option_action = r.ivr_menu_option_action
|
||||
ivr_menu_option_param = r.ivr_menu_option_param
|
||||
ivr_menu_option_description = r.ivr_menu_option_description
|
||||
if (#ivr_menu_option_action > 0) then
|
||||
ivr_menu_option_param = xml.sanitize(ivr_menu_option_param);
|
||||
ivr_menu_option_param = string.gsub(ivr_menu_option_param, "{accountcode}", "${accountcode}");
|
||||
|
||||
xml:append([[ <entry action="]] .. xml.sanitize(ivr_menu_option_action) .. [[" digits="]] .. ivr_menu_option_digits .. [[" param="]] .. ivr_menu_option_param .. [[" description="]] .. xml.sanitize(ivr_menu_option_description) .. [["/>]]);
|
||||
if (tonumber(ivr_menu_option_digits) and #ivr_menu_option_digits >= tonumber(direct_dial_digits_min)) then
|
||||
table.insert(direct_dial_exclude, ivr_menu_option_digits);
|
||||
end
|
||||
end
|
||||
end);
|
||||
|
||||
--direct dial
|
||||
if (ivr_menu_direct_dial == "true") then
|
||||
local negative_lookahead = "";
|
||||
if (#direct_dial_exclude > 0) then
|
||||
negative_lookahead = "(?!^("..table.concat(direct_dial_exclude, "|")..")$)";
|
||||
end
|
||||
local direct_dial_regex = string.format("/^(%s\\d{%s,%s})$/", negative_lookahead, direct_dial_digits_min, direct_dial_digits_max);
|
||||
xml:append([[ <entry action="menu-exec-app" digits="]] .. direct_dial_regex .. [[" param="set ${cond(${user_exists id $1 ]] .. xml.sanitize(domain_name) .. [[} == true ? user_exists=true : user_exists=false)}" description="direct dial"/>\n]]);
|
||||
--xml:append([[ <entry action="menu-exec-app" digits="]] .. xml.sanitize(direct_dial_regex) .. [[" param="set ${cond(${user_exists} == true ? user_exists=true : ivr_max_failures=${system(expr ${ivr_max_failures} + 1)})}" description="increment max failures"/>\n]]);
|
||||
xml:append([[ <entry action="menu-exec-app" digits="]] .. direct_dial_regex .. [[" param="playback ${cond(${user_exists} == true ? ]] .. xml.sanitize(sound_prefix) .. [[ivr/ivr-call_being_transferred.wav : ]] .. xml.sanitize(sound_prefix) .. [[ivr/ivr-that_was_an_invalid_entry.wav)}" description="play sound"/>\n]]);
|
||||
--xml:append([[ <entry action="menu-exec-app" digits="]] .. xml.sanitize(direct_dial_regex) .. [[" param="transfer ${cond(${ivr_max_failures} == ]] .. xml.sanitize(ivr_menu_max_failures) .. [[ ? ]] .. xml.sanitize(ivr_menu_exit_data) .. [[)}" description="max fail transfer"/>\n]]);
|
||||
xml:append([[ <entry action="menu-exec-app" digits="]] .. direct_dial_regex .. [[" param="transfer ${cond(${user_exists} == true ? $1 XML ]] .. xml.sanitize(domain_name) .. [[)}" description="direct dial transfer"/>\n]]);
|
||||
end
|
||||
|
||||
--close the extension tag if it was left open
|
||||
xml:append([[ </menu>]]);
|
||||
|
||||
end);
|
||||
|
||||
--add the xml closing tags
|
||||
xml:append([[ </menus>]]);
|
||||
xml:append([[ </configuration>]]);
|
||||
xml:append([[ </section>]]);
|
||||
xml:append([[</document>]]);
|
||||
|
||||
--save the xml into a string
|
||||
XML_STRING = xml:build();
|
||||
|
||||
--optinonal debug message
|
||||
if (debug["xml_string"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] XML_STRING: " .. XML_STRING .. "\n");
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
--freeswitch.consoleLog("notice", "[xml_handler]"..api:execute("eval ${dsn}"));
|
||||
|
||||
--set the cache
|
||||
local ok, err = cache.set("configuration:ivr.conf:" .. original_ivr_menu_uuid, XML_STRING, expire["ivr"]);
|
||||
if debug["cache"] then
|
||||
if ok then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. ivr_menu_uuid .. " stored in the cache\n");
|
||||
else
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. ivr_menu_uuid .. " can not be stored in the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--send the xml to the console
|
||||
if (debug["xml_string"]) then
|
||||
local file = assert(io.open(temp_dir .. "/ivr-"..ivr_menu_uuid..".conf.xml", "w"));
|
||||
file:write(XML_STRING);
|
||||
file:close();
|
||||
end
|
||||
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. ivr_menu_cache_key .. " source: database\n");
|
||||
end
|
||||
|
||||
else
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. ivr_menu_cache_key .. " source: cache\n");
|
||||
end
|
||||
end --if XML_STRING
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
--include xml library
|
||||
local Xml = require "resources.functions.xml";
|
||||
|
||||
--get the cache
|
||||
local cache = require "resources.functions.cache"
|
||||
local local_stream_cache_key = "configuration:local_stream.conf"
|
||||
XML_STRING, err = cache.get(local_stream_cache_key)
|
||||
|
||||
--set the cache
|
||||
if not XML_STRING then
|
||||
|
||||
--log the cache error
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("warning", "[xml_handler] configuration:local_stream.conf can not be get from cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
|
||||
--set a default value
|
||||
if (expire["default"] == nil) then
|
||||
expire["default"]= "3600";
|
||||
end
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--start the xml array
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
xml:append([[<document type="freeswitch/xml">]]);
|
||||
xml:append([[ <section name="configuration">]]);
|
||||
xml:append([[ <configuration name="local_stream.conf" description="stream files from local dir">]]);
|
||||
|
||||
--run the query
|
||||
sql = "select d.domain_name, s.* "
|
||||
sql = sql .. "from v_music_on_hold as s left outer join v_domains as d "
|
||||
sql = sql .. "on d.domain_uuid = s.domain_uuid "
|
||||
sql = sql .. "order by s.music_on_hold_name asc "
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "\n");
|
||||
end
|
||||
x = 0;
|
||||
dbh:query(sql, function(row)
|
||||
|
||||
--combine the name, domain_name and the rate
|
||||
name = '';
|
||||
if (row.domain_uuid ~= nil and string.len(row.domain_uuid) > 0) then
|
||||
name = row.domain_name..'/';
|
||||
end
|
||||
name = name .. row.music_on_hold_name;
|
||||
if (row.music_on_hold_rate ~= nil and #row.music_on_hold_rate > 0) then
|
||||
name = name .. '/' .. row.music_on_hold_rate;
|
||||
end
|
||||
|
||||
--replace the variable with the path to the sounds directory
|
||||
music_on_hold_path = row.music_on_hold_path:gsub("$${sounds_dir}", sounds_dir);
|
||||
|
||||
--set the rate
|
||||
rate = row.music_on_hold_rate;
|
||||
if rate == '' then
|
||||
rate = '48000';
|
||||
end
|
||||
|
||||
--add the full path to the chime list
|
||||
chime_list = row.music_on_hold_chime_list;
|
||||
if (chime_list ~= nil) then
|
||||
chime_array = explode(",", chime_list);
|
||||
chime_list = "";
|
||||
for k,v in pairs(chime_array) do
|
||||
f = explode("/", v);
|
||||
if (f[1] ~= nil and f[2] ~= nil and file_exists(sounds_dir.."/en/us/callie/"..f[1].."/"..rate.."/"..f[2])) then
|
||||
chime_list = chime_list .. sounds_dir.."/en/us/callie/"..v;
|
||||
else
|
||||
chime_list = chime_list .. v;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--set the default timer name to soft
|
||||
if (row.music_on_hold_timer_name == nil or row.music_on_hold_timer_name == '') then
|
||||
timer_name = "soft";
|
||||
else
|
||||
timer_name = row.music_on_hold_timer_name;
|
||||
end
|
||||
|
||||
--build the xml ]]..row.music_on_hold_name..[["
|
||||
xml:append([[ <directory name="]] .. xml.sanitize(name) .. [[" uuid="]] .. xml.sanitize(row.music_on_hold_uuid) .. [[" path="]] .. xml.sanitize(music_on_hold_path) .. [[">]]);
|
||||
xml:append([[ <param name="rate" value="]] .. xml.sanitize(rate) .. [["/>]]);
|
||||
xml:append([[ <param name="shuffle" value="]] .. xml.sanitize(row.music_on_hold_shuffle) .. [["/>]]);
|
||||
xml:append([[ <param name="channels" value="1"/>]]);
|
||||
xml:append([[ <param name="interval" value="20"/>]]);
|
||||
xml:append([[ <param name="timer-name" value="]] .. xml.sanitize(timer_name) ..[["/>]]);
|
||||
if (chime_list ~= nil) then
|
||||
xml:append([[ <param name="chime-list" value="]] .. xml.sanitize(chime_list) .. [["/>]]);
|
||||
end
|
||||
if (row.music_on_hold_chime_freq ~= nil) then
|
||||
xml:append([[ <param name="chime-freq" value="]] .. xml.sanitize(row.music_on_hold_chime_freq) .. [["/>]]);
|
||||
end
|
||||
if (row.music_on_hold_chime_max ~= nil) then
|
||||
xml:append([[ <param name="chime-max" value="]] .. xml.sanitize(row.music_on_hold_chime_max) .. [["/>]]);
|
||||
end
|
||||
xml:append([[ </directory>]]);
|
||||
|
||||
end)
|
||||
|
||||
--close the extension tag if it was left open
|
||||
xml:append([[ </configuration>]]);
|
||||
xml:append([[ </section>]]);
|
||||
xml:append([[</document>]]);
|
||||
XML_STRING = xml:build();
|
||||
if (debug["xml_string"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] XML_STRING: " .. XML_STRING .. "\n");
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
|
||||
--set the cache
|
||||
local ok, err = cache.set(local_stream_cache_key, XML_STRING, expire["default"]);
|
||||
if debug["cache"] then
|
||||
if ok then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. local_stream_cache_key .. " stored in the cache\n");
|
||||
else
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. local_stream_cache_key .. " can not be stored in the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. local_stream_cache_key .. " source: database\n");
|
||||
end
|
||||
else
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. local_stream_cache_key .. " source: cache\n");
|
||||
end
|
||||
end --if XML_STRING
|
||||
|
||||
--send the xml to the console
|
||||
if (debug["xml_string"]) then
|
||||
local file = assert(io.open(temp_dir .. "/local_stream.conf.xml", "w"));
|
||||
file:write(XML_STRING);
|
||||
file:close();
|
||||
end
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
-- xml_handler.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 - 2022 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--include xml library
|
||||
local Xml = require "resources.functions.xml";
|
||||
|
||||
--get the cache
|
||||
local cache = require "resources.functions.cache"
|
||||
local hostname = trim(api:execute("switchname", ""))
|
||||
local sofia_cache_key = "configuration:sofia.conf:" .. hostname
|
||||
XML_STRING, err = cache.get(sofia_cache_key)
|
||||
|
||||
--set the cache
|
||||
if not XML_STRING then
|
||||
--log cache error
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. sofia_cache_key .. " can not be get from the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
|
||||
--set a default value
|
||||
if (expire["sofia"] == nil) then
|
||||
expire["sofia"]= "3600";
|
||||
end
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--get the variables
|
||||
vars = trim(api:execute("global_getvar", ""));
|
||||
|
||||
--start the xml array
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
xml:append([[<document type="freeswitch/xml">]]);
|
||||
xml:append([[ <section name="configuration">]]);
|
||||
xml:append([[ <configuration name="sofia.conf" description="sofia Endpoint">]]);
|
||||
|
||||
--gt the global settings
|
||||
sql = "select * from v_sofia_global_settings ";
|
||||
sql = sql .. "where global_setting_enabled = 'true' ";
|
||||
sql = sql .. "order by global_setting_name asc ";
|
||||
local params = {};
|
||||
x = 0;
|
||||
xml:append([[ <global_settings>]]);
|
||||
dbh:query(sql, params, function(row)
|
||||
xml:append([[ <param name="]] .. xml.sanitize(row.global_setting_name) .. [[" value="]] .. xml.sanitize(row.global_setting_value) .. [["/>]]);
|
||||
end)
|
||||
xml:append([[ </global_settings>]]);
|
||||
|
||||
--set defaults
|
||||
previous_sip_profile_name = "";
|
||||
profile_tag_status = "closed";
|
||||
|
||||
--run the query
|
||||
sql = "select p.sip_profile_uuid, p.sip_profile_name, p.sip_profile_description, s.sip_profile_setting_name, s.sip_profile_setting_value ";
|
||||
sql = sql .. "from v_sip_profiles as p, v_sip_profile_settings as s ";
|
||||
sql = sql .. "where s.sip_profile_setting_enabled = 'true' ";
|
||||
sql = sql .. "and p.sip_profile_enabled = 'true' ";
|
||||
sql = sql .. "and (p.sip_profile_hostname = :hostname or p.sip_profile_hostname is null or p.sip_profile_hostname = '') ";
|
||||
sql = sql .. "and p.sip_profile_uuid = s.sip_profile_uuid ";
|
||||
sql = sql .. "order by p.sip_profile_name asc ";
|
||||
local params = {hostname = hostname};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
x = 0;
|
||||
xml:append([[ <profiles>]]);
|
||||
dbh:query(sql, params, function(row)
|
||||
--set as variables
|
||||
sip_profile_uuid = row.sip_profile_uuid;
|
||||
sip_profile_name = row.sip_profile_name;
|
||||
--sip_profile_description = row.sip_profile_description;
|
||||
sip_profile_setting_name = row.sip_profile_setting_name;
|
||||
sip_profile_setting_value = row.sip_profile_setting_value;
|
||||
|
||||
--open xml tag
|
||||
if (sip_profile_name ~= previous_sip_profile_name) then
|
||||
if (x > 1) then
|
||||
xml:append([[ </settings>]]);
|
||||
xml:append([[ </profile>]]);
|
||||
end
|
||||
xml:append([[ <profile name="]] .. xml.sanitize(sip_profile_name) .. [[">]]);
|
||||
xml:append([[ <aliases>]]);
|
||||
xml:append([[ </aliases>]]);
|
||||
xml:append([[ <gateways>]]);
|
||||
--xml:append([[ <X-PRE-PROCESS cmd="include" data="]] .. xml.sanitize(sip_profile_name) .. [[/*.xml"/>]]);
|
||||
|
||||
--get the gateways
|
||||
sql = "select * from v_gateways ";
|
||||
sql = sql .. "where profile = :profile ";
|
||||
sql = sql .. "and enabled = 'true' ";
|
||||
sql = sql .. "and (hostname = :hostname or hostname is null or hostname = '') ";
|
||||
local params = {profile = sip_profile_name, hostname = hostname};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
x = 0;
|
||||
dbh:query(sql, params, function(field)
|
||||
xml:append([[ <gateway name="]] .. xml.sanitize(string.lower(field.gateway_uuid)) .. [[">]]);
|
||||
|
||||
if (string.len(field.username) > 0) then
|
||||
xml:append([[ <param name="username" value="]] .. xml.sanitize(field.username) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.distinct_to) > 0) then
|
||||
xml:append([[ <param name="distinct-to" value="]] .. xml.sanitize(field.distinct_to) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.auth_username) > 0) then
|
||||
xml:append([[ <param name="auth-username" value="]] .. xml.sanitize(field.auth_username) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.password) > 0) then
|
||||
xml:append([[ <param name="password" value="]] .. xml.sanitize(field.password) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.realm) > 0) then
|
||||
xml:append([[ <param name="realm" value="]] .. xml.sanitize(field.realm) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.from_user) > 0) then
|
||||
xml:append([[ <param name="from-user" value="]] .. xml.sanitize(field.from_user) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.from_domain) > 0) then
|
||||
xml:append([[ <param name="from-domain" value="]] .. xml.sanitize(field.from_domain) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.proxy) > 0) then
|
||||
xml:append([[ <param name="proxy" value="]] .. xml.sanitize(field.proxy) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.register_proxy) > 0) then
|
||||
xml:append([[ <param name="register-proxy" value="]] .. xml.sanitize(field.register_proxy) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.outbound_proxy) > 0) then
|
||||
xml:append([[ <param name="outbound-proxy" value="]] .. xml.sanitize(field.outbound_proxy) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.expire_seconds) > 0) then
|
||||
xml:append([[ <param name="expire-seconds" value="]] .. xml.sanitize(field.expire_seconds) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.register) > 0) then
|
||||
xml:append([[ <param name="register" value="]] .. xml.sanitize(field.register) .. [["/>]]);
|
||||
end
|
||||
|
||||
if (field.register_transport) then
|
||||
if (field.register_transport == "udp") then
|
||||
xml:append([[ <param name="register-transport" value="udp"/>]]);
|
||||
elseif (field.register_transport == "tcp") then
|
||||
xml:append([[ <param name="register-transport" value="tcp"/>]]);
|
||||
elseif (field.register_transport == "tls") then
|
||||
xml:append([[ <param name="register-transport" value="tls"/>]]);
|
||||
|
||||
else
|
||||
xml:append([[ <param name="register-transport" value="udp"/>]]);
|
||||
end
|
||||
end
|
||||
|
||||
if (field.contact_params) then
|
||||
xml:append([[ <param name="contact-params" value="]] .. xml.sanitize(field.contact_params) .. [["/>]]);
|
||||
end
|
||||
|
||||
if (string.len(field.retry_seconds) > 0) then
|
||||
xml:append([[ <param name="retry-seconds" value="]] .. xml.sanitize(field.retry_seconds) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.extension) > 0) then
|
||||
xml:append([[ <param name="extension" value="]] .. xml.sanitize(field.extension) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.ping) > 0) then
|
||||
xml:append([[ <param name="ping" value="]] .. xml.sanitize(field.ping) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.ping_min) > 0) then
|
||||
xml:append([[ <param name="ping-min" value="]] .. xml.sanitize(field.ping_min) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.ping_max) > 0) then
|
||||
xml:append([[ <param name="ping-max" value="]] .. xml.sanitize(field.ping_max) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.contact_in_ping) > 0) then
|
||||
xml:append([[ <param name="contact-in-ping" value="]] .. xml.sanitize(field.contact_in_ping) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.context) > 0) then
|
||||
xml:append([[ <param name="context" value="]] .. xml.sanitize(field.context) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.caller_id_in_from) > 0) then
|
||||
xml:append([[ <param name="caller-id-in-from" value="]] .. xml.sanitize(field.caller_id_in_from) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.supress_cng) > 0) then
|
||||
xml:append([[ <param name="supress-cng" value="]] .. xml.sanitize(field.supress_cng) .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.extension_in_contact) > 0) then
|
||||
xml:append([[ <param name="extension-in-contact" value="]] .. xml.sanitize(field.extension_in_contact) .. [["/>]]);
|
||||
end
|
||||
xml:append([[ <variables>]]);
|
||||
if (string.len(field.sip_cid_type) > 0) then
|
||||
xml:append([[ <variable name="sip_cid_type" value="]] .. xml.sanitize(field.sip_cid_type) .. [["/>]]);
|
||||
end
|
||||
xml:append([[ </variables>]]);
|
||||
xml:append([[ </gateway>]]);
|
||||
end)
|
||||
|
||||
xml:append([[ </gateways>]]);
|
||||
xml:append([[ <domains>]]);
|
||||
|
||||
--add sip profile domain: name, alias, and parse
|
||||
xml:append([[ <!-- indicator to parse the directory for domains with parse="true" to get gateways-->]]);
|
||||
xml:append([[ <!--<domain name="$${domain}" parse="true"/>-->]]);
|
||||
xml:append([[ <!-- indicator to parse the directory for domains with parse="true" to get gateways and alias every domain to this profile -->]]);
|
||||
xml:append([[ <!--<domain name="all" alias="true" parse="true"/>-->]]);
|
||||
sql = "SELECT sip_profile_domain_name, sip_profile_domain_alias, sip_profile_domain_parse FROM v_sip_profile_domains ";
|
||||
sql = sql .. "WHERE sip_profile_uuid = :sip_profile_uuid";
|
||||
local params = {sip_profile_uuid = sip_profile_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "; sip_profile_uuid:" .. sip_profile_uuid .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
name = row.sip_profile_domain_name;
|
||||
alias = row.sip_profile_domain_alias;
|
||||
parse = row.sip_profile_domain_parse;
|
||||
if (name == nil or name == '') then name = 'false'; end
|
||||
if (alias == nil or alias == '') then alias = 'false'; end
|
||||
if (parse == nil or parse == '') then parse = 'false'; end
|
||||
xml:append([[ <domain name="]] .. xml.sanitize(name) .. [[" alias="]] .. xml.sanitize(alias) .. [[" parse="]] .. xml.sanitize(parse) .. [["/>]]);
|
||||
end);
|
||||
|
||||
xml:append([[ </domains>]]);
|
||||
xml:append([[ <settings>]]);
|
||||
profile_tag_status = "open";
|
||||
end
|
||||
|
||||
--loop through the var array
|
||||
for line in (vars.."\n"):gmatch"(.-)\n" do
|
||||
if (line) then
|
||||
pos = string.find(line, "=", 0, true);
|
||||
--name = string.sub( line, 0, pos-1);
|
||||
--value = string.sub( line, pos+1);
|
||||
sip_profile_setting_value = sip_profile_setting_value:gsub("%$%${"..string.sub( line, 0, pos-1).."}", string.sub( line, pos+1));
|
||||
end
|
||||
end
|
||||
|
||||
--remove $ and replace with ""
|
||||
--if (sip_profile_setting_value) then
|
||||
-- sip_profile_setting_value = sip_profile_setting_value:gsub("%$", "");
|
||||
--end
|
||||
|
||||
--sanitize the sip profile setting value, allow specific safe variables
|
||||
sip_profile_setting_value = xml.sanitize(sip_profile_setting_value);
|
||||
sip_profile_setting_value = string.gsub(sip_profile_setting_value, "{domain_name}", "${domain_name}");
|
||||
sip_profile_setting_value = string.gsub(sip_profile_setting_value, "{strftime", "${strftime");
|
||||
sip_profile_setting_value = string.gsub(sip_profile_setting_value, "{uuid}", "${uuid}");
|
||||
sip_profile_setting_value = string.gsub(sip_profile_setting_value, "{record_ext}", "${record_ext}");
|
||||
|
||||
--set the parameters
|
||||
if (sip_profile_setting_name) then
|
||||
xml:append([[ <param name="]] .. xml.sanitize(sip_profile_setting_name) .. [[" value="]] .. sip_profile_setting_value .. [["/>]]);
|
||||
end
|
||||
|
||||
--set the previous value
|
||||
previous_sip_profile_name = sip_profile_name;
|
||||
|
||||
--increment the value of x
|
||||
x = x + 1;
|
||||
end)
|
||||
|
||||
--close the extension tag if it was left open
|
||||
if (profile_tag_status == "open") then
|
||||
xml:append([[ </settings>]]);
|
||||
xml:append([[ </profile>]]);
|
||||
profile_tag_status = "close";
|
||||
end
|
||||
xml:append([[ </profiles>]]);
|
||||
xml:append([[ </configuration>]]);
|
||||
xml:append([[ </section>]]);
|
||||
xml:append([[</document>]]);
|
||||
XML_STRING = xml:build();
|
||||
if (debug["xml_string"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] XML_STRING: " .. XML_STRING .. "\n");
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
|
||||
--set the cache
|
||||
local ok, err = cache.set(sofia_cache_key, XML_STRING, expire["sofia"])
|
||||
if debug["cache"] then
|
||||
if ok then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. sofia_cache_key .. " stored in the cache\n");
|
||||
else
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. sofia_cache_key .. " can not be stored in the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. sofia_cache_key .. " source: database\n");
|
||||
end
|
||||
else
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. sofia_cache_key .. " source: cache\n");
|
||||
end
|
||||
end --if XML_STRING
|
||||
|
||||
--send the xml to the console
|
||||
if (debug["xml_string"]) then
|
||||
local file = assert(io.open(temp_dir .. "/sofia.conf.xml", "w"));
|
||||
file:write(XML_STRING);
|
||||
file:close();
|
||||
end
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
-- xml_handler.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2018 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--include xml library
|
||||
local Xml = require "resources.functions.xml";
|
||||
|
||||
--get the cache
|
||||
local cache = require "resources.functions.cache"
|
||||
local translate_cache_key = "configuration:translate.conf"
|
||||
XML_STRING, err = cache.get(translate_cache_key)
|
||||
|
||||
--set the cache
|
||||
if not XML_STRING then
|
||||
--log cache error
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. translate_cache_key .. " can not be get from the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
|
||||
--log cache error
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("warning", "[xml_handler] configuration:translate.conf can not be get from the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
|
||||
--set a default value
|
||||
if (expire["translate"] == nil) then
|
||||
expire["translate"]= "3600";
|
||||
end
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--start the xml array
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
xml:append([[<document type="freeswitch/xml">]]);
|
||||
xml:append([[ <section name="configuration">]]);
|
||||
xml:append([[ <configuration name="translate.conf" description="Number Translation Rules" autogenerated="true">]]);
|
||||
xml:append([[ <profiles>]]);
|
||||
|
||||
--run the query
|
||||
sql = "select * from v_number_translations ";
|
||||
sql = sql .. "order by number_translation_name asc ";
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "\n");
|
||||
end
|
||||
x = 0;
|
||||
dbh:query(sql, function(row)
|
||||
|
||||
--list open tag
|
||||
xml:append([[ <profile name="]] .. xml.sanitize(row.number_translation_name) .. [[" description="]] .. xml.sanitize(row.number_translation_description) .. [[">]]);
|
||||
|
||||
--get the nodes
|
||||
sql = "select * from v_number_translation_details ";
|
||||
sql = sql .. "where number_translation_uuid = :number_translation_uuid ";
|
||||
sql = sql .. "order by number_translation_detail_order asc ";
|
||||
local params = {number_translation_uuid = row.number_translation_uuid}
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "\n");
|
||||
end
|
||||
x = 0;
|
||||
dbh:query(sql, params, function(field)
|
||||
if (string.len(field.number_translation_detail_regex) > 0) then
|
||||
xml:append([[ <rule regex="]] .. xml.sanitize(field.number_translation_detail_regex) .. [[" replace="]] .. xml.sanitize(field.number_translation_detail_replace) .. [[" />]]);
|
||||
end
|
||||
end)
|
||||
|
||||
--list close tag
|
||||
xml:append([[ </profile>]]);
|
||||
|
||||
end)
|
||||
|
||||
--close the extension tag if it was left open
|
||||
xml:append([[ </profiles>]]);
|
||||
xml:append([[ </configuration>]]);
|
||||
xml:append([[ </section>]]);
|
||||
xml:append([[</document>]]);
|
||||
XML_STRING = xml:build();
|
||||
if (debug["xml_string"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] XML_STRING: " .. XML_STRING .. "\n");
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
|
||||
--set the cache
|
||||
local ok, err = cache.set(translate_cache_key, XML_STRING, expire["translate"]);
|
||||
if debug["cache"] then
|
||||
if ok then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. translate_cache_key .. " stored in the cache\n");
|
||||
else
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. translate_cache_key .. " can not be stored in the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. translate_cache_key .. " source: database\n");
|
||||
end
|
||||
else
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. translate_cache_key .. " source: cache\n");
|
||||
end
|
||||
end --if XML_STRING
|
||||
|
||||
--send the xml to the console
|
||||
if (debug["xml_string"]) then
|
||||
local file = assert(io.open(temp_dir .. "/translate.conf.xml", "w"));
|
||||
file:write(XML_STRING);
|
||||
file:close();
|
||||
end
|
||||
@@ -0,0 +1,267 @@
|
||||
-- xml_handler.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2022 Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- All rights reserved.
|
||||
--
|
||||
-- Redistribution and use in source and binary forms, with or without
|
||||
-- modification, are permitted provided that the following conditions are met:
|
||||
--
|
||||
-- 1. Redistributions of source code must retain the above copyright notice,
|
||||
-- this list of conditions and the following disclaimer.
|
||||
--
|
||||
-- 2. Redistributions in binary form must reproduce the above copyright
|
||||
-- notice, this list of conditions and the following disclaimer in the
|
||||
-- documentation and/or other materials provided with the distribution.
|
||||
--
|
||||
-- THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
-- INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
-- AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
-- AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
||||
-- OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
-- POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--includes
|
||||
local cache = require"resources.functions.cache"
|
||||
local log = require"resources.functions.log"["xml_handler"]
|
||||
|
||||
--include xml library
|
||||
local Xml = require "resources.functions.xml";
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--needed for cli-command xml_locate dialplan
|
||||
if (call_context == nil) then
|
||||
call_context = "public";
|
||||
end
|
||||
|
||||
--get the dialplan mode from the cache
|
||||
dialplan_destination_key = "dialplan:destination";
|
||||
dialplan_destination, err = cache.get(dialplan_destination_key);
|
||||
|
||||
--if not found in the cache then get it from the database
|
||||
if (err == 'NOT FOUND') then
|
||||
--get the mode from default settings
|
||||
sql = "select default_setting_value from v_default_settings "
|
||||
sql = sql .. "where default_setting_category = 'dialplan' ";
|
||||
sql = sql .. "and default_setting_subcategory = 'destination' ";
|
||||
dialplan_destination = dbh:first_value(sql, nil);
|
||||
if (dialplan_destination) then
|
||||
local ok, err = cache.set(dialplan_destination_key, dialplan_destination, expire["dialplan"]);
|
||||
end
|
||||
|
||||
--set the default
|
||||
if (dialplan_destination == nil or dialplan_destination == '') then
|
||||
dialplan_destination = "destination_number";
|
||||
end
|
||||
|
||||
--send a message to the log
|
||||
if (debug['cache']) then
|
||||
log.notice(dialplan_destination_key.." source: database destination: "..dialplan_destination);
|
||||
end
|
||||
else
|
||||
--send a message to the log
|
||||
if (debug['cache']) then
|
||||
log.notice(dialplan_destination_key.." source: cache destination: "..dialplan_destination);
|
||||
end
|
||||
end
|
||||
|
||||
--get the dialplan mode from the cache
|
||||
dialplan_mode_key = "dialplan:mode";
|
||||
dialplan_mode, err = cache.get(dialplan_mode_key);
|
||||
|
||||
--if not found in the cache then get it from the database
|
||||
if (err == 'NOT FOUND') then
|
||||
--get the mode from default settings
|
||||
sql = "select default_setting_value from v_default_settings "
|
||||
sql = sql .. "where default_setting_category = 'destinations' ";
|
||||
sql = sql .. "and default_setting_subcategory = 'dialplan_mode' ";
|
||||
dialplan_mode = dbh:first_value(sql, nil);
|
||||
if (dialplan_mode) then
|
||||
local ok, err = cache.set(dialplan_mode_key, dialplan_mode, expire["dialplan"]);
|
||||
end
|
||||
|
||||
--set the default
|
||||
if (dialplan_mode == nil or dialplan_mode == '') then
|
||||
dialplan_mode = "multiple";
|
||||
end
|
||||
|
||||
--send a message to the log
|
||||
if (debug['cache']) then
|
||||
log.notice(dialplan_mode_key.." source: database mode: "..dialplan_mode);
|
||||
end
|
||||
else
|
||||
--send a message to the log
|
||||
if (debug['cache']) then
|
||||
log.notice(dialplan_mode_key.." source: cache mode: "..dialplan_mode);
|
||||
end
|
||||
end
|
||||
|
||||
--set the defaults
|
||||
if (dialplan_mode == nil or dialplan_mode == '') then
|
||||
dialplan_mode = "multiple";
|
||||
end
|
||||
domain_name = 'global';
|
||||
|
||||
--get the context
|
||||
local context_name = call_context;
|
||||
if (call_context == "public" or string.sub(call_context, 0, 7) == "public@" or string.sub(call_context, -7) == ".public") then
|
||||
context_name = 'public';
|
||||
end
|
||||
|
||||
--use alternative sip_to_user instead of the default
|
||||
if (dialplan_destination == '${sip_to_user}' or dialplan_destination == 'sip_to_user') then
|
||||
destination_number = api:execute("url_decode", sip_to_user);
|
||||
end
|
||||
|
||||
--use alternative sip_req_user instead of the default
|
||||
if (dialplan_destination == '${sip_req_user}' or dialplan_destination == 'sip_req_user') then
|
||||
destination_number = api:execute("url_decode", sip_req_user);
|
||||
end
|
||||
|
||||
--set the dialplan cache key
|
||||
local dialplan_cache_key = "dialplan:" .. call_context;
|
||||
if (context_name == 'public' and dialplan_mode == "single") then
|
||||
dialplan_cache_key = "dialplan:" .. call_context .. ":" .. destination_number;
|
||||
end
|
||||
|
||||
--log the dialplan mode and dialplan cache key
|
||||
freeswitch.consoleLog("notice", "[xml_handler] ".. dialplan_mode .. " key:" .. dialplan_cache_key .. "\n");
|
||||
|
||||
--get the cache
|
||||
XML_STRING, err = cache.get(dialplan_cache_key);
|
||||
if (debug['cache']) then
|
||||
if XML_STRING then
|
||||
log.notice(dialplan_cache_key.." source: cache");
|
||||
elseif err ~= 'NOT FOUND' then
|
||||
log.notice("get element from the cache: " .. err);
|
||||
end
|
||||
end
|
||||
|
||||
--set the cache
|
||||
if (not XML_STRING) then
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--get the hostname
|
||||
hostname = trim(api:execute("hostname", ""));
|
||||
|
||||
--set the xml array and then concatenate the array to a string
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
xml:append([[<document type="freeswitch/xml">]]);
|
||||
xml:append([[ <section name="dialplan" description="">]]);
|
||||
xml:append([[ <context name="]] .. xml.sanitize(call_context) .. [[" destination_number="]] .. xml.sanitize(destination_number) .. [[" hostname="]] .. xml.sanitize(hostname) .. [[">]]);
|
||||
|
||||
--get the dialplan xml
|
||||
if (context_name == 'public' and dialplan_mode == 'single') then
|
||||
sql = "SELECT (SELECT domain_name FROM v_domains WHERE domain_uuid = p.domain_uuid) as domain_name, "
|
||||
sql = sql .. "(SELECT domain_enabled FROM v_domains WHERE domain_uuid = p.domain_uuid) as domain_enabled, p.dialplan_xml ";
|
||||
sql = sql .. "FROM v_dialplans AS p ";
|
||||
sql = sql .. "WHERE ( ";
|
||||
sql = sql .. " p.dialplan_uuid IN ( ";
|
||||
sql = sql .. " SELECT dialplan_uuid FROM v_destinations ";
|
||||
sql = sql .. " WHERE ( ";
|
||||
sql = sql .. " destination_prefix || destination_area_code || destination_number = :destination_number ";
|
||||
sql = sql .. " OR destination_trunk_prefix || destination_area_code || destination_number = :destination_number ";
|
||||
sql = sql .. " OR destination_prefix || destination_number = :destination_number ";
|
||||
sql = sql .. " OR '+' || destination_prefix || destination_number = :destination_number ";
|
||||
sql = sql .. " OR '+' || destination_prefix || destination_area_code || destination_number = :destination_number ";
|
||||
sql = sql .. " OR destination_area_code || destination_number = :destination_number ";
|
||||
sql = sql .. " OR destination_number = :destination_number ";
|
||||
sql = sql .. " ) ";
|
||||
sql = sql .. " ) ";
|
||||
sql = sql .. " or (p.dialplan_context like '%public%' and p.domain_uuid IS NULL) ";
|
||||
sql = sql .. ") ";
|
||||
sql = sql .. "AND (p.hostname = :hostname OR p.hostname IS NULL) ";
|
||||
sql = sql .. "AND p.dialplan_enabled = 'true' ";
|
||||
sql = sql .. "ORDER BY p.dialplan_order ASC ";
|
||||
local params = {destination_number = destination_number, hostname = hostname};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[dialplan] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
if (row.domain_uuid ~= nil) then
|
||||
domain_name = row.domain_name;
|
||||
else
|
||||
xml:append(row.dialplan_xml);
|
||||
end
|
||||
if (row.domain_enabled == true) then
|
||||
xml:append(row.dialplan_xml);
|
||||
end
|
||||
end);
|
||||
if (xml == nil) then
|
||||
xml:append([[ <extension name="not-found" continue="false" uuid="9913df49-0757-414b-8cf9-bcae2fd81ae7">]]);
|
||||
xml:append([[ <condition field="" expression="">]]);
|
||||
xml:append([[ <action application="set" data="call_direction=inbound" inline="true"/>]]);
|
||||
xml:append([[ <action application="log" data="WARNING [inbound routes] 404 not found ${sip_network_ip}" inline="true"/>]]);
|
||||
xml:append([[ </condition>]]);
|
||||
xml:append([[ </extension>]]);
|
||||
end
|
||||
else
|
||||
sql = "select dialplan_xml from v_dialplans as p ";
|
||||
if (context_name == "public" or string.match(context_name, "@")) then
|
||||
sql = sql .. "where p.dialplan_context = :call_context ";
|
||||
else
|
||||
sql = sql .. "where p.dialplan_context in (:call_context, '${domain_name}', 'global') ";
|
||||
end
|
||||
sql = sql .. "and (p.hostname = :hostname or p.hostname is null) ";
|
||||
sql = sql .. "and p.dialplan_enabled = 'true' ";
|
||||
sql = sql .. "order by p.dialplan_order asc ";
|
||||
local params = {call_context = call_context, hostname = hostname};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[dialplan] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
xml:append(row.dialplan_xml);
|
||||
end);
|
||||
end
|
||||
|
||||
--set the xml array and then concatenate the array to a string
|
||||
xml:append([[ </context>]]);
|
||||
xml:append([[ </section>]]);
|
||||
xml:append([[</document>]]);
|
||||
XML_STRING = xml:build();
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
|
||||
--set the cache
|
||||
local ok, err = cache.set(dialplan_cache_key, XML_STRING, expire["dialplan"]);
|
||||
if debug["cache"] then
|
||||
if ok then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. dialplan_cache_key .. " stored in the cache\n");
|
||||
else
|
||||
freeswitch.consoleLog("warning", "[xml_handler] " .. dialplan_cache_key .. " can not be stored in the cache: " .. tostring(err) .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. dialplan_cache_key .. " source: database\n");
|
||||
end
|
||||
else
|
||||
--send to the console
|
||||
if (debug["cache"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] " .. dialplan_cache_key .. " source: cache\n");
|
||||
end
|
||||
end --if XML_STRING
|
||||
|
||||
--send the xml to the console
|
||||
if (debug["xml_string"]) then
|
||||
local file = assert(io.open(temp_dir .. "/" .. dialplan_cache_key .. ".xml", "w"));
|
||||
file:write(XML_STRING);
|
||||
file:close();
|
||||
end
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database"
|
||||
local log = require "resources.functions.log"["directory_acl"]
|
||||
local dbh = Database.new('system')
|
||||
|
||||
--include xml library
|
||||
local Xml = require "resources.functions.xml";
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--build the xml
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]])
|
||||
xml:append([[<document type="freeswitch/xml">]])
|
||||
xml:append([[ <section name="directory">]])
|
||||
|
||||
--process when the sip profile is rescanned, sofia is reloaded, or sip redirect
|
||||
local sql = "SELECT * FROM v_domains as d, v_extensions as e "
|
||||
sql = sql .. "where d.domain_uuid = e.domain_uuid and e.cidr is not null and e.cidr <> '' "
|
||||
if domain_name then
|
||||
sql = sql .. "and d.domain_name = :domain_name "
|
||||
else
|
||||
sql = sql .. "order by d.domain_name"
|
||||
end
|
||||
local params = {domain_name = domain_name}
|
||||
|
||||
if debug['sql'] then
|
||||
log.noticef("SQL: %s; params: %s", sql, json.encode(params))
|
||||
end
|
||||
|
||||
local prev_domain_name
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
if prev_domain_name ~= row.domain_name then
|
||||
if prev_domain_name then
|
||||
xml:append([[ </users>]])
|
||||
xml:append([[ </group>]])
|
||||
xml:append([[ </groups>]])
|
||||
xml:append([[ </domain>]])
|
||||
end
|
||||
prev_domain_name = row.domain_name
|
||||
xml:append([[ <domain name="]] .. xml.sanitize(row.domain_name) .. [[" alias="true">]])
|
||||
xml:append([[ <groups>]])
|
||||
xml:append([[ <group name="default">]])
|
||||
xml:append([[ <users>]])
|
||||
end
|
||||
|
||||
local cidr = (#row.cidr > 0) and (' cidr="' .. xml.sanitize(row.cidr) .. '"') or ''
|
||||
xml:append([[ <user id="]] .. xml.sanitize(row.extension) .. [["]] .. cidr .. [[/>]])
|
||||
end)
|
||||
|
||||
if prev_domain_name then
|
||||
xml:append([[ </users>]])
|
||||
xml:append([[ </group>]])
|
||||
xml:append([[ </groups>]])
|
||||
xml:append([[ </domain>]])
|
||||
end
|
||||
|
||||
xml:append([[ </section>]])
|
||||
xml:append([[</document>]])
|
||||
XML_STRING = xml:build();
|
||||
|
||||
if (debug["xml_string"]) then
|
||||
log.notice("XML_STRING "..XML_STRING)
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release()
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database"
|
||||
local log = require "resources.functions.log"["directory_dir"]
|
||||
local dbh = Database.new('system')
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--build the xml
|
||||
local xml = Xml:new();
|
||||
xml:append([[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]])
|
||||
xml:append([[<document type="freeswitch/xml">]])
|
||||
xml:append([[ <section name="directory">]])
|
||||
|
||||
--process when the sip profile is rescanned, sofia is reloaded, or sip redirect
|
||||
local sql = "SELECT * FROM v_domains as d, v_extensions as e "
|
||||
sql = sql .. "where d.domain_uuid = e.domain_uuid "
|
||||
sql = sql .. "and (e.directory_visible = 'true' or e.directory_exten_visible='true') "
|
||||
if domain_name then
|
||||
sql = sql .. "and d.domain_name = :domain_name "
|
||||
else
|
||||
sql = sql .. "order by d.domain_name "
|
||||
end
|
||||
local sql_params = {domain_name = domain_name}
|
||||
|
||||
if debug['sql'] then
|
||||
log.noticef("SQL: %s; params: %s", sql, json.encode(sql_params))
|
||||
end
|
||||
|
||||
-- export this params
|
||||
local params = {
|
||||
directory_visible = "directory-visible";
|
||||
directory_exten_visible = "directory-exten-visible";
|
||||
}
|
||||
|
||||
-- export this variables
|
||||
local variables = {
|
||||
effective_caller_id_name = "effective_caller_id_name";
|
||||
directory_full_name = "directory_full_name";
|
||||
}
|
||||
|
||||
local prev_domain_name
|
||||
|
||||
dbh:query(sql, sql_params, function(row)
|
||||
if prev_domain_name ~= row.domain_name then
|
||||
if prev_domain_name then
|
||||
xml:append([[ </users>]])
|
||||
xml:append([[ </group>]])
|
||||
xml:append([[ </groups>]])
|
||||
xml:append([[ </domain>]])
|
||||
end
|
||||
prev_domain_name = row.domain_name
|
||||
xml:append([[ <domain name="]] .. xml.sanitize(row.domain_name) .. [[" alias="true">]])
|
||||
xml:append([[ <groups>]])
|
||||
xml:append([[ <group name="default">]])
|
||||
xml:append([[ <users>]])
|
||||
end
|
||||
|
||||
row.sip_from_user = row.extension
|
||||
row.sip_from_number = (#number_alias > 0) and number_alias or row.extension
|
||||
local number_alias_string = ''
|
||||
if #row.number_alias > 0 then
|
||||
number_alias_string = ' number-alias="' .. xml.sanitize(row.number_alias) .. '"'
|
||||
end
|
||||
|
||||
xml:append([[ <user id="]] .. xml.sanitize(row.extension) .. [["]] .. number_alias_string .. [[>]]);
|
||||
xml:append([[ <params>]])
|
||||
for name, param in pairs(params) do
|
||||
if row[name] and #row[name] > 0 then
|
||||
xml:append([[ <param name="]] .. xml.sanitize(param) .. [[" value="]] .. xml.sanitize(row[name]) .. [["/>]])
|
||||
end
|
||||
end
|
||||
xml:append([[ </params>]])
|
||||
xml:append([[ <variables>]])
|
||||
for name, param in pairs(variables) do
|
||||
if row[name] and #row[name] > 0 then
|
||||
xml:append([[ <variable name="]] .. xml.sanitize(param) .. [[" value="]] .. xml.sanitize(row[name]) .. [["/>]])
|
||||
end
|
||||
end
|
||||
xml:append([[ </variables>]])
|
||||
xml:append([[ </user>]])
|
||||
end)
|
||||
|
||||
if prev_domain_name then
|
||||
xml:append([[ </users>]])
|
||||
xml:append([[ </group>]])
|
||||
xml:append([[ </groups>]])
|
||||
xml:append([[ </domain>]])
|
||||
end
|
||||
|
||||
xml:append([[ </section>]])
|
||||
xml:append([[</document>]])
|
||||
XML_STRING = xml:build();
|
||||
|
||||
if (debug["xml_string"]) then
|
||||
log.notice("XML_STRING "..XML_STRING)
|
||||
end
|
||||
|
||||
--close the database connection
|
||||
dbh:release()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user