mirror of
https://github.com/fusionpbx/fusionpbx.git
synced 2026-01-10 18:48:23 +00:00
Move the scripts to app/scripts/resources/scripts
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
|
||||
The Initial Developer of the Original Code is
|
||||
Mark J Crane <markjcrane@fusionpbx.com>
|
||||
Portions created by the Initial Developer are Copyright (C) 2008-2017
|
||||
Portions created by the Initial Developer are Copyright (C) 2008-2020
|
||||
the Initial Developer. All Rights Reserved.
|
||||
|
||||
Contributor(s):
|
||||
@@ -104,16 +104,16 @@ if (!class_exists('scripts')) {
|
||||
$source_directory = '/usr/share/examples/fusionpbx/scripts';
|
||||
}
|
||||
else {
|
||||
$source_directory = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/resources/install/scripts';
|
||||
$source_directory = $_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'/app/resources/scripts';
|
||||
}
|
||||
if (is_readable($source_directory)) {
|
||||
//copy the main scripts
|
||||
recursive_copy($source_directory,$destination_directory);
|
||||
recursive_copy($source_directory, $destination_directory);
|
||||
unset($source_directory);
|
||||
|
||||
//copy the app/*/resource/install/scripts
|
||||
$app_scripts = glob($_SERVER["DOCUMENT_ROOT"].PROJECT_PATH.'app/*/resource/install/scripts');
|
||||
foreach ($app_scripts as $app_script){
|
||||
foreach ($app_scripts as $app_script) {
|
||||
recursive_copy($app_script, $destination_directory);
|
||||
}
|
||||
unset($app_scripts);
|
||||
|
||||
48
app/scripts/resources/scripts/app.lua
Normal file
48
app/scripts/resources/scripts/app.lua
Normal file
@@ -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);
|
||||
221
app/scripts/resources/scripts/app/agent_status/index.lua
Normal file
221
app/scripts/resources/scripts/app/agent_status/index.lua
Normal file
@@ -0,0 +1,221 @@
|
||||
|
||||
|
||||
--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();
|
||||
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_id = session:getVariable("agent_id");
|
||||
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) 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}
|
||||
local sql = "SELECT * FROM v_call_center_agents ";
|
||||
sql = sql .. "WHERE domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "AND agent_id = :agent_id ";
|
||||
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 (user_status == "Available") then
|
||||
action = "logout";
|
||||
status = 'Logged Out';
|
||||
else
|
||||
action = "login";
|
||||
status = 'Available';
|
||||
end
|
||||
|
||||
--send a login or logout to mod_callcenter
|
||||
cmd = "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") then
|
||||
event = freeswitch.Event("PRESENCE_IN");
|
||||
event:addHeader("proto", "sip");
|
||||
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", agent_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", "sip");
|
||||
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", agent_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
|
||||
);
|
||||
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
|
||||
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
|
||||
19
app/scripts/resources/scripts/app/avmd/index.lua
Normal file
19
app/scripts/resources/scripts/app/avmd/index.lua
Normal file
@@ -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
|
||||
220
app/scripts/resources/scripts/app/call_block/index.lua
Normal file
220
app/scripts/resources/scripts/app/call_block/index.lua
Normal file
@@ -0,0 +1,220 @@
|
||||
--
|
||||
-- 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");
|
||||
caller_id_name = session:getVariable("caller_id_name");
|
||||
caller_id_number = session:getVariable("caller_id_number");
|
||||
context = session:getVariable("context");
|
||||
call_block = session:getVariable("call_block");
|
||||
extension_uuid = session:getVariable("extension_uuid");
|
||||
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;
|
||||
|
||||
--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 ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and call_block_enabled = 'true' ";
|
||||
sql = sql .. "and ( ";
|
||||
sql = sql .. " (call_block_name = :call_block_name and call_block_number = :call_block_number) ";
|
||||
sql = sql .. " or (call_block_name is null and call_block_number = :call_block_number) ";
|
||||
sql = sql .. " or (call_block_name = :call_block_name and call_block_number is null) ";
|
||||
sql = sql .. ") ";
|
||||
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
|
||||
params = {domain_uuid = domain_uuid, call_block_name = caller_id_name, call_block_number = caller_id_number, extension_uuid = extension_uuid};
|
||||
else
|
||||
params = {domain_uuid = domain_uuid, call_block_name = caller_id_name, call_block_number = caller_id_number};
|
||||
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("respond", '607');
|
||||
session:execute('set', 'call_block_uuid='..call_block_uuid);
|
||||
session:execute('set', 'call_block_app=hold');
|
||||
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", '607');
|
||||
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 == '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
|
||||
787
app/scripts/resources/scripts/app/conference_center/index.lua
Normal file
787
app/scripts/resources/scripts/app/conference_center/index.lua
Normal file
@@ -0,0 +1,787 @@
|
||||
-- conference_center/index.lua
|
||||
-- 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.
|
||||
--
|
||||
-- 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;
|
||||
|
||||
--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
|
||||
|
||||
--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_meetings WHERE meeting_uuid = :meeting_uuid";
|
||||
local params = {meeting_uuid = meeting_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 = '{"X-FusionPBX-Domain-UUID":"'..domain_uuid..'",';
|
||||
headers = headers..'"X-FusionPBX-Domain-Name":"'..domain_name..'",';
|
||||
headers = headers..'"X-FusionPBX-Call-UUID":"na",';
|
||||
headers = headers..'"X-FusionPBX-Email-Type":"conference"}';
|
||||
|
||||
--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 = body:gsub("'", "'");
|
||||
body = body:gsub([["]], """);
|
||||
body = trim(body);
|
||||
|
||||
--send the email
|
||||
if (string.len(attachment) > 4) then
|
||||
cmd = "luarun email.lua "..email.." "..email.." '"..headers.."' '"..subject.."' '"..body.."' '"..attachment.."'";
|
||||
else
|
||||
cmd = "luarun email.lua "..email.." "..email.." '"..headers.."' '"..subject.."' '"..body.."'";
|
||||
end
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] cmd: " .. cmd .. "\n");
|
||||
end
|
||||
result = api:executeString(cmd);
|
||||
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 = meeting_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 = meeting_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 "..meeting_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;
|
||||
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
|
||||
--send the email addresses
|
||||
--sql = [[SELECT c.contact_email FROM v_users as u, v_meeting_users as m, v_contacts as c
|
||||
-- WHERE m.domain_uuid = ']] .. domain_uuid ..[['
|
||||
-- AND u.user_uuid = m.user_uuid
|
||||
-- AND m.meeting_uuid = ']] .. meeting_uuid ..[['
|
||||
-- and u.contact_uuid = c.contact_uuid]];
|
||||
--if (debug["sql"]) then
|
||||
-- freeswitch.consoleLog("notice", "[conference center] <email> SQL: " .. sql .. "\n");
|
||||
--end
|
||||
--status = dbh:query(sql, function(row)
|
||||
-- if (row["contact_email"] ~= nil) then
|
||||
-- contact_email = string.lower(row["contact_email"]);
|
||||
-- if (string.len(contact_email) > 3) then
|
||||
-- freeswitch.consoleLog("notice", "[conference center] contact_email: " .. contact_email .. "\n");
|
||||
-- if (record == "true") then
|
||||
-- if (file_exists(conference_recording..".wav")) then
|
||||
-- send_email(contact_email, "", default_language, default_dialect);
|
||||
-- end
|
||||
-- end
|
||||
-- end
|
||||
-- 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
|
||||
session:setHangupHook("session_hangup_hook");
|
||||
|
||||
--add the domain to the recording directory
|
||||
freeswitch.consoleLog("notice", "[conference center] domain_count: " .. domain_count .. "\n");
|
||||
|
||||
--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+");
|
||||
end
|
||||
--use the pin_number to find the conference room
|
||||
if (pin_number ~= "") then
|
||||
local sql = [[SELECT * FROM v_conference_rooms as r, v_meetings as m
|
||||
WHERE r.domain_uuid = :domain_uuid
|
||||
AND r.meeting_uuid = m.meeting_uuid
|
||||
AND m.domain_uuid = :domain_uuid
|
||||
AND (m.moderator_pin = :pin_number or m.participant_pin = :pin_number)
|
||||
AND r.enabled = 'true'
|
||||
AND m.enabled = 'true'
|
||||
AND (
|
||||
( r.start_datetime <> '' AND r.start_datetime is not null AND r.start_datetime <= :timestam ) OR
|
||||
( r.start_datetime = '' OR r.start_datetime is null )
|
||||
)
|
||||
AND (
|
||||
( r.stop_datetime <> '' AND r.stop_datetime is not null AND r.stop_datetime > :timestam ) OR
|
||||
( r.stop_datetime = '' OR r.stop_datetime is null )
|
||||
) ]];
|
||||
local params = {
|
||||
domain_uuid = domain_uuid;
|
||||
pin_number = pin_number;
|
||||
timestam = 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 as r, v_meetings as m
|
||||
WHERE r.domain_uuid = :domain_uuid
|
||||
AND r.meeting_uuid = m.meeting_uuid
|
||||
AND r.conference_center_uuid = :conference_center_uuid
|
||||
AND m.domain_uuid = :domain_uuid
|
||||
AND (m.moderator_pin = :pin_number or m.participant_pin = :pin_number)
|
||||
AND r.enabled = 'true'
|
||||
AND m.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"]);
|
||||
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_pin = row["moderator_pin"];
|
||||
participant_pin = row["participant_pin"];
|
||||
announce = row["announce"];
|
||||
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
|
||||
|
||||
--close the database connection
|
||||
dbh:release();
|
||||
|
||||
--set the meeting uuid
|
||||
if (meeting_uuid) then
|
||||
session:setVariable("meeting_uuid", meeting_uuid);
|
||||
end
|
||||
|
||||
if (meeting_uuid == nil) then
|
||||
--invalid pin number
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/conference/conf-bad-pin.wav");
|
||||
session:hangup("NORMAL_CLEARING");
|
||||
else
|
||||
if (meeting_uuid) then
|
||||
--check if the conference exists
|
||||
cmd = "conference "..meeting_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
|
||||
|
||||
--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 "..meeting_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 == "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);
|
||||
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
|
||||
--flags = flags .. "|endconf";
|
||||
--set the moderator controls
|
||||
session:execute("set","conference_controls=moderator");
|
||||
end
|
||||
|
||||
--get the conference xml_list
|
||||
cmd = "conference "..meeting_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 (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
|
||||
|
||||
--announce the caller
|
||||
if (announce == "true") then
|
||||
--announce the caller - play the recording
|
||||
cmd = "conference "..meeting_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 "..meeting_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 "..meeting_uuid.."@"..domain_name.." play "..enter_sound;
|
||||
response = api:executeString(cmd);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--get the conference member count
|
||||
cmd = "conference "..meeting_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 (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
|
||||
--record the conference
|
||||
if (record == "true") then
|
||||
cmd="sched_api +5 none lua "..scripts_dir.."/app/conference_center/resources/scripts/start_recording.lua "..meeting_uuid.." "..domain_name.." "..record_ext;
|
||||
api:executeString(cmd);
|
||||
end
|
||||
--send the call to the conference
|
||||
cmd = meeting_uuid.."@"..domain_name.."@"..profile.."+flags{".. flags .."}";
|
||||
freeswitch.consoleLog("INFO","[conference center] conference " .. cmd .. "\n");
|
||||
session:execute("conference", cmd);
|
||||
end
|
||||
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 .. " mute " .. data;
|
||||
response = api:executeString(cmd);
|
||||
@@ -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);
|
||||
@@ -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>
|
||||
@@ -0,0 +1 @@
|
||||
New recording available for conference ${moderator_pin} ${conference_date_end}.
|
||||
107
app/scripts/resources/scripts/app/dialplan/index.lua
Normal file
107
app/scripts/resources/scripts/app/dialplan/index.lua
Normal file
@@ -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 (io.popen ("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 (io.popen ("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 (io.popen ("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
|
||||
@@ -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
|
||||
132
app/scripts/resources/scripts/app/emergency_notify/index.lua
Normal file
132
app/scripts/resources/scripts/app/emergency_notify/index.lua
Normal file
@@ -0,0 +1,132 @@
|
||||
--
|
||||
-- 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
|
||||
headers = '{"X-FusionPBX-Domain-UUID":"'..domain_uuid..'",';
|
||||
headers = headers..'"X-FusionPBX-Domain-Name":"'..domain_name..'",';
|
||||
headers = headers..'"X-FusionPBX-Call-UUID":"'..uuid..'",';
|
||||
headers = headers..'"X-FusionPBX-Email-Type":"emergency_call"}';
|
||||
|
||||
--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 = body:gsub("'", "'");
|
||||
body = body:gsub([["]], """);
|
||||
body = trim(body);
|
||||
|
||||
--send the email
|
||||
cmd = "luarun email.lua "..to_email.." "..from_email.." "..headers.." '"..subject.."' '"..body.."'";
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[emergency call] cmd: " .. cmd .. "\n");
|
||||
end
|
||||
api = freeswitch.API();
|
||||
result = api:executeString(cmd);
|
||||
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
|
||||
@@ -0,0 +1 @@
|
||||
${caller_id_name} <${caller_id_number}> made an emergency call to ${sip_to_user}
|
||||
@@ -0,0 +1 @@
|
||||
${caller_id_name} <${caller_id_number}> Made An Emergency Call
|
||||
192
app/scripts/resources/scripts/app/event_notify/index.lua
Normal file
192
app/scripts/resources/scripts/app/event_notify/index.lua
Normal file
@@ -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");
|
||||
253
app/scripts/resources/scripts/app/failure_handler/index.lua
Normal file
253
app/scripts/resources/scripts/app/failure_handler/index.lua
Normal file
@@ -0,0 +1,253 @@
|
||||
--
|
||||
-- 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';
|
||||
|
||||
--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
|
||||
|
||||
--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
|
||||
11
app/scripts/resources/scripts/app/fax/app_languages.lua
Normal file
11
app/scripts/resources/scripts/app/fax/app_languages.lua
Normal file
@@ -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,440 @@
|
||||
--
|
||||
-- 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-2019
|
||||
-- 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
|
||||
|
||||
--define the explode function
|
||||
require "resources.functions.explode";
|
||||
|
||||
--array count
|
||||
require "resources.functions.count";
|
||||
|
||||
local IS_WINDOWS = (package.config:sub(1,1) == '\\')
|
||||
|
||||
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
|
||||
fax_uuid = env:getHeader("fax_uuid");
|
||||
uuid = env:getHeader("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
|
||||
|
||||
--set default values
|
||||
if (not fax_success) then
|
||||
fax_success = "0";
|
||||
fax_result_code = 2;
|
||||
end
|
||||
if (hangup_cause_q850 == "17") then
|
||||
fax_success = "0";
|
||||
fax_result_code = 2;
|
||||
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 = "lua" .. " " .. quote(scripts_dir .. "/fax_to_email.lua") .. " ";
|
||||
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");
|
||||
result = api:execute("system", 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,187 @@
|
||||
-- @usage without queue
|
||||
-- api: originate {fax_file='',wav_file='',fax_dtmf=''}user/108@domain.local &lua(app/fax/resources/scripts/queue/exec.lua)
|
||||
-- @usage with queue task
|
||||
-- api: originate {fax_task_uuid=''}user/108@domain.local &lua(app/fax/resources/scripts/queue/exec.lua)
|
||||
-- @fax_dtmf
|
||||
-- 0-9*# - dtmf symbols
|
||||
-- @200 - dtmf duration in ms
|
||||
-- p - pause 500 ms
|
||||
-- P - pause 1000 ms
|
||||
--
|
||||
-- example: pause 5 sec dial 008 pause 2 sec paly greeting
|
||||
-- PPPPP008@300PP
|
||||
--
|
||||
|
||||
require "resources.functions.config"
|
||||
local log = require "resources.functions.log".fax_task
|
||||
|
||||
-- If we handle queue task
|
||||
local fax_task_uuid = session:getVariable('fax_task_uuid')
|
||||
local task if fax_task_uuid then
|
||||
local Tasks = require "app.fax.resources.scripts.queue.tasks"
|
||||
task = Tasks.select_task(fax_task_uuid)
|
||||
if not task then
|
||||
log.warningf("Can not found fax task: %q", tostring(fax_task_uuid))
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if task then
|
||||
local str = 'Queue task :'
|
||||
for k, v in pairs(task) do
|
||||
str = str .. ('\n %q = %q'):format(k, v)
|
||||
end
|
||||
log.info(str)
|
||||
else
|
||||
log.info('Not queued task')
|
||||
end
|
||||
|
||||
local function empty(t) return (not t) or (#t == 0) end
|
||||
|
||||
local function not_empty(t) if not empty(t) then return t end end
|
||||
|
||||
local dtmf, wav_file, fax_file
|
||||
|
||||
if task then
|
||||
dtmf = not_empty(task.dtmf)
|
||||
wav_file = not_empty(task.wav_file) or not_empty(task.greeting)
|
||||
fax_file = not_empty(task.fax_file)
|
||||
else
|
||||
dtmf = not_empty(session:getVariable('fax_dtmf'))
|
||||
wav_file = not_empty(session:getVariable('wav_file'))
|
||||
fax_file = not_empty(session:getVariable('fax_file'))
|
||||
end
|
||||
|
||||
if not (wav_file or fax_file) then
|
||||
log.warning("No fax or wav file")
|
||||
return
|
||||
end
|
||||
|
||||
local function decode_dtmf(dtmf)
|
||||
local r, sleep, seq = {}
|
||||
dtmf:gsub('P', 'pp'):gsub('.', function(ch)
|
||||
if ch == ';' or ch == ',' then
|
||||
r[#r + 1] = sleep or seq
|
||||
sleep, seq = nil
|
||||
elseif ch == 'p' then
|
||||
r[#r + 1] = seq
|
||||
sleep = (sleep or 0) + 500
|
||||
seq = nil
|
||||
else
|
||||
r[#r + 1] = sleep
|
||||
seq = (seq or '') .. ch
|
||||
sleep = nil
|
||||
end
|
||||
end)
|
||||
r[#r + 1] = sleep or seq
|
||||
return r
|
||||
end
|
||||
|
||||
local function send_fax()
|
||||
session:execute("txfax", fax_file)
|
||||
end
|
||||
|
||||
local function start_fax_detect(detect_duration)
|
||||
if not tone_detect_cb then
|
||||
function tone_detect_cb(s, type, obj, arg)
|
||||
if type == "event" then
|
||||
if obj:getHeader('Event-Name') == 'DETECTED_TONE' then
|
||||
return "false"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
log.notice("Start detecting fax")
|
||||
|
||||
detect_duration = detect_duration or 60000
|
||||
|
||||
session:setInputCallback("tone_detect_cb")
|
||||
session:execute("tone_detect", "txfax 2100 r +" .. tostring(detect_duration) .. " set remote_fax_detected=txfax")
|
||||
session:execute("tone_detect", "rxfax 1100 r +" .. tostring(detect_duration) .. " set remote_fax_detected=rxfax")
|
||||
session:setVariable("sip_api_on_image", "uuid_break " .. session:getVariable("uuid") .. " all")
|
||||
end
|
||||
|
||||
local function stop_fax_detect()
|
||||
session:unsetInputCallback()
|
||||
session:execute("stop_tone_detect")
|
||||
session:setVariable("sip_api_on_image", "")
|
||||
end
|
||||
|
||||
local function fax_deteced()
|
||||
if session:getVariable('has_t38') == 'true' then
|
||||
log.noticef('Detected t38')
|
||||
session:setVariable('remote_fax_detected', 'txfax')
|
||||
end
|
||||
|
||||
if fax_file and session:getVariable('remote_fax_detected') then
|
||||
log.noticef("Detected %s", session:getVariable('remote_fax_detected'))
|
||||
if session:getVariable('remote_fax_detected') == 'txfax' then
|
||||
send_fax()
|
||||
else
|
||||
log.warning('Remote fax try send fax')
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
local function check()
|
||||
if not session:ready() then return false end
|
||||
if fax_deteced() then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
local function task()
|
||||
local session_uuid = session:getVariable('uuid')
|
||||
|
||||
session:setVariable('fax_queue_task_session', session_uuid)
|
||||
|
||||
log.infof("SESSION UUID: %s", session_uuid)
|
||||
|
||||
session:waitForAnswer(session)
|
||||
|
||||
while not session:answered() do
|
||||
if not session:ready() then return end
|
||||
session:sleep(500)
|
||||
end
|
||||
|
||||
if not (session:ready() and session:answered()) then return end
|
||||
|
||||
if fax_file and wav_file then
|
||||
start_fax_detect()
|
||||
end
|
||||
|
||||
if dtmf then
|
||||
dtmf = decode_dtmf(dtmf)
|
||||
for _, element in ipairs(dtmf) do
|
||||
if type(element) == 'number' then
|
||||
session:streamFile("silence_stream://" .. tostring(element))
|
||||
else
|
||||
session:execute("send_dtmf", element)
|
||||
end
|
||||
if not check() then return end
|
||||
end
|
||||
end
|
||||
|
||||
if wav_file then
|
||||
session:streamFile(wav_file)
|
||||
if not check() then return end
|
||||
end
|
||||
|
||||
if fax_file then
|
||||
if wav_file then
|
||||
stop_fax_detect()
|
||||
end
|
||||
send_fax()
|
||||
end
|
||||
end
|
||||
|
||||
log.noticef("START TASK")
|
||||
log.notice("Fax:" .. tostring(fax_file))
|
||||
log.notice("Wav:" .. tostring(wav_file))
|
||||
|
||||
task()
|
||||
|
||||
log.noticef("STOP TASK")
|
||||
log.notice("Ready: " .. tostring(session:ready()))
|
||||
log.notice("Answered: " .. tostring(session:answered()))
|
||||
@@ -0,0 +1,98 @@
|
||||
require "resources.functions.config"
|
||||
|
||||
require "resources.functions.sleep"
|
||||
require "resources.functions.file_exists"
|
||||
local log = require "resources.functions.log".next_fax_task
|
||||
local Tasks = require "app.fax.resources.scripts.queue.tasks"
|
||||
local Esl = require "resources.functions.esl"
|
||||
|
||||
local FAX_OPTIONS = {
|
||||
"fax_use_ecm=false,fax_enable_t38=true,fax_enable_t38_request=true,fax_disable_v17=default";
|
||||
"fax_use_ecm=true,fax_enable_t38=true,fax_enable_t38_request=true,fax_disable_v17=false";
|
||||
"fax_use_ecm=true,fax_enable_t38=false,fax_enable_t38_request=false,fax_disable_v17=false";
|
||||
"fax_use_ecm=true,fax_enable_t38=true,fax_enable_t38_request=true,fax_disable_v17=true";
|
||||
"fax_use_ecm=false,fax_enable_t38=false,fax_enable_t38_request=false,fax_disable_v17=false";
|
||||
}
|
||||
|
||||
local function task_send_mail(task, err)
|
||||
local number_dialed = task.uri:match("/([^/]-)%s*$")
|
||||
|
||||
local Text = require "resources.functions.text"
|
||||
local text = Text.new("app.fax.app_languages")
|
||||
|
||||
local env = {
|
||||
destination_number = number_dialed:match("^([^@]*)");
|
||||
hangup_cause = err;
|
||||
message = text['message-send_fail'];
|
||||
}
|
||||
|
||||
local body = Tasks.build_template(task, 'outbound/fail/body', env)
|
||||
local subject = Tasks.build_template(task, 'outbound/fail/subject', env)
|
||||
|
||||
if not subject then
|
||||
log.warning("Can not find template for email")
|
||||
subject = "Fax to: " .. number_dialed .. " FAILED"
|
||||
end
|
||||
|
||||
Tasks.send_mail_task(task, {subject, body}, nil, file_exists(task.fax_file))
|
||||
end
|
||||
|
||||
local function next_task()
|
||||
local task, err = Tasks.next_task()
|
||||
|
||||
if not task then
|
||||
if err then
|
||||
log.noticef('Can not select next task: %s', tostring(err))
|
||||
else
|
||||
log.notice("No task")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local esl
|
||||
local ok, err = pcall(function()
|
||||
|
||||
local mode = (task.retry_counter % #FAX_OPTIONS) + 1
|
||||
local dial_string = '{' ..
|
||||
task.dial_string .. "api_hangup_hook='lua app/fax/resources/scripts/queue/retry.lua'," ..
|
||||
FAX_OPTIONS[mode] ..
|
||||
'}' .. task.uri
|
||||
|
||||
local originate = 'originate ' .. dial_string .. ' &lua(app/fax/resources/scripts/queue/exec.lua)'
|
||||
|
||||
log.notice(originate)
|
||||
esl = assert(Esl.new())
|
||||
local ok, status, info = esl:api(originate)
|
||||
if not ok then
|
||||
Tasks.wait_task(task, false, info)
|
||||
if task.status ~= 0 then
|
||||
Tasks.remove_task(task)
|
||||
task_send_mail(task, tostring(info))
|
||||
end
|
||||
log.noticef('Can not originate to `%s` cause: %s: %s ', task.uri, tostring(status), tostring(info))
|
||||
else
|
||||
log.noticef("originate successfuly: %s", tostring(info))
|
||||
end
|
||||
end)
|
||||
|
||||
if esl then esl:close() end
|
||||
|
||||
if not ok then
|
||||
Tasks.release_task(task)
|
||||
log.noticef("Error execute task: %s", tostring(err))
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function poll_once()
|
||||
Tasks.cleanup_tasks()
|
||||
while next_task() do
|
||||
sleep(5000)
|
||||
end
|
||||
Tasks.release_db()
|
||||
end
|
||||
|
||||
return {
|
||||
poll_once = poll_once;
|
||||
}
|
||||
@@ -0,0 +1,418 @@
|
||||
-- include libraries
|
||||
require "resources.functions.config";
|
||||
require "resources.functions.split";
|
||||
require "resources.functions.file_exists";
|
||||
|
||||
local log = require "resources.functions.log".fax_retry
|
||||
local Database = require "resources.functions.database"
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
local Tasks = require "app.fax.resources.scripts.queue.tasks"
|
||||
local send_mail = require "resources.functions.send_mail"
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
local fax_task_uuid = env:getHeader('fax_task_uuid')
|
||||
if not fax_task_uuid then
|
||||
log.warning("No [fax_task_uuid] channel variable")
|
||||
return
|
||||
end
|
||||
local task = Tasks.select_task(fax_task_uuid)
|
||||
if not task then
|
||||
log.warningf("Can not find fax task: %q", tostring(fax_task_uuid))
|
||||
return
|
||||
end
|
||||
|
||||
-- show all channel variables
|
||||
if debug["fax_serialize"] then
|
||||
log.noticef("info:\n%s", env:serialize())
|
||||
end
|
||||
|
||||
local dbh = Database.new('system')
|
||||
|
||||
-- Global environment
|
||||
default_language = env:getHeader("default_language")
|
||||
default_dialect = env:getHeader("default_dialect")
|
||||
|
||||
-- Channel/FusionPBX variables
|
||||
local uuid = env:getHeader("uuid")
|
||||
local fax_queue_task_session = env:getHeader('fax_queue_task_session')
|
||||
local domain_uuid = env:getHeader("domain_uuid") or task.domain_uuid
|
||||
local domain_name = env:getHeader("domain_name") or task.domain_name
|
||||
local origination_caller_id_name = env:getHeader("origination_caller_id_name") or '000000000000000'
|
||||
local origination_caller_id_number = env:getHeader("origination_caller_id_number") or '000000000000000'
|
||||
local accountcode = env:getHeader("accountcode") or domain_name
|
||||
local duration = tonumber(env:getHeader("billmsec")) or 0
|
||||
local sip_to_user = env:getHeader("sip_to_user")
|
||||
local bridge_hangup_cause = env:getHeader("bridge_hangup_cause")
|
||||
local hangup_cause_q850 = tonumber(env:getHeader("hangup_cause_q850"))
|
||||
local answered = duration > 0
|
||||
|
||||
-- fax variables
|
||||
local fax_success = env:getHeader('fax_success')
|
||||
local has_t38 = env:getHeader('has_t38') or 'false'
|
||||
local t38_broken_boolean = env:getHeader('t38_broken_boolean') or ''
|
||||
local fax_result_code = tonumber(env:getHeader('fax_result_code')) or 2
|
||||
local fax_result_text = env:getHeader('fax_result_text') or 'FS_NOT_SET'
|
||||
local fax_ecm_used = env:getHeader('fax_ecm_used') or ''
|
||||
local fax_local_station_id = env:getHeader('fax_local_station_id') or ''
|
||||
local fax_document_transferred_pages = env:getHeader('fax_document_transferred_pages') or nil
|
||||
local fax_document_total_pages = env:getHeader('fax_document_total_pages') or nil
|
||||
local fax_image_resolution = env:getHeader('fax_image_resolution') or ''
|
||||
local fax_image_size = env:getHeader('fax_image_size') or nil
|
||||
local fax_bad_rows = env:getHeader('fax_bad_rows') or nil
|
||||
local fax_transfer_rate = env:getHeader('fax_transfer_rate') or nil
|
||||
local fax_v17_disabled = env:getHeader('fax_v17_disabled') or ''
|
||||
local fax_ecm_requested = env:getHeader('fax_ecm_requested') or ''
|
||||
local fax_remote_station_id = env:getHeader('fax_remote_station_id') or ''
|
||||
|
||||
local fax_options = ("fax_use_ecm=%s,fax_enable_t38=%s,fax_enable_t38_request=%s,fax_disable_v17=%s"):format(
|
||||
env:getHeader('fax_use_ecm') or '',
|
||||
env:getHeader('fax_enable_t38') or '',
|
||||
env:getHeader('fax_enable_t38_request') or '',
|
||||
env:getHeader('fax_disable_v17') or ''
|
||||
)
|
||||
|
||||
-- Fax task params
|
||||
local fax_uri = env:getHeader("fax_uri") or task.uri
|
||||
local fax_file = env:getHeader("fax_file") or task.fax_file
|
||||
local wav_file = env:getHeader("wav_file") or task.wav_file
|
||||
local fax_uuid = task.fax_uuid
|
||||
local pdf_file = fax_file and string.gsub(fax_file, '(%.[^\\/]+)$', '.pdf')
|
||||
|
||||
-- Email variables
|
||||
local number_dialed = fax_uri:match("/([^/]-)%s*$")
|
||||
|
||||
log.noticef([[<<< CALL RESULT >>>
|
||||
uuid: = '%s'
|
||||
task_session_uuid: = '%s'
|
||||
answered: = '%s'
|
||||
fax_file: = '%s'
|
||||
wav_file: = '%s'
|
||||
fax_uri: = '%s'
|
||||
sip_to_user: = '%s'
|
||||
accountcode: = '%s'
|
||||
origination_caller_id_name: = '%s'
|
||||
origination_caller_id_number: = '%s'
|
||||
mailto_address: = '%s'
|
||||
hangup_cause_q850: = '%s'
|
||||
fax_options = '%s'
|
||||
]],
|
||||
tostring(uuid) ,
|
||||
tostring(fax_queue_task_session) ,
|
||||
tostring(answered) ,
|
||||
tostring(fax_file) ,
|
||||
tostring(wav_file) ,
|
||||
tostring(fax_uri) ,
|
||||
tostring(sip_to_user) ,
|
||||
tostring(accountcode) ,
|
||||
tostring(origination_caller_id_name) ,
|
||||
tostring(origination_caller_id_number) ,
|
||||
tostring(task.reply_address) ,
|
||||
tostring(hangup_cause_q850) ,
|
||||
fax_options
|
||||
)
|
||||
|
||||
if fax_success then
|
||||
log.noticef([[<<< FAX RESULT >>>
|
||||
fax_success = '%s'
|
||||
has_t38 = '%s'
|
||||
t38_broken_boolean = '%s'
|
||||
fax_result_code = '%s'
|
||||
fax_result_text = '%s'
|
||||
fax_ecm_used = '%s'
|
||||
fax_local_station_id = '%s'
|
||||
fax_document_transferred_pages = '%s'
|
||||
fax_document_total_pages = '%s'
|
||||
fax_image_resolution = '%s'
|
||||
fax_image_size = '%s'
|
||||
fax_bad_rows = '%s'
|
||||
fax_transfer_rate = '%s'
|
||||
fax_v17_disabled = '%s'
|
||||
fax_ecm_requested = '%s'
|
||||
fax_remote_station_id = '%s'
|
||||
'%s'
|
||||
]],
|
||||
fax_success ,
|
||||
has_t38 ,
|
||||
t38_broken_boolean ,
|
||||
fax_result_code ,
|
||||
fax_result_text ,
|
||||
fax_ecm_used ,
|
||||
fax_local_station_id ,
|
||||
fax_document_transferred_pages ,
|
||||
fax_document_total_pages ,
|
||||
fax_image_resolution ,
|
||||
fax_image_size ,
|
||||
fax_bad_rows ,
|
||||
fax_transfer_rate ,
|
||||
fax_v17_disabled ,
|
||||
fax_ecm_requested ,
|
||||
fax_remote_station_id ,
|
||||
'---------------------------------'
|
||||
)
|
||||
end
|
||||
|
||||
log.debug([[<<< DEBUG >>>
|
||||
domain_name = '%s'
|
||||
domain_uuid = '%s'
|
||||
task.domain_name = '%s'
|
||||
task.domain_uuid = '%s'
|
||||
]],
|
||||
tostring(domain_name ),
|
||||
tostring(domain_uuid ),
|
||||
tostring(task.domain_name ),
|
||||
tostring(task.domain_uuid )
|
||||
)
|
||||
|
||||
assert(fax_uuid, 'no fax server uuid')
|
||||
assert(domain_name, 'no domain name')
|
||||
assert(domain_uuid, 'no domain uuid')
|
||||
assert(domain_uuid:lower() == task.domain_uuid:lower(), 'invalid domain uuid')
|
||||
assert(domain_name:lower() == task.domain_name:lower(), 'invalid domain name')
|
||||
|
||||
--settings
|
||||
local settings = Settings.new(dbh, domain_name, domain_uuid)
|
||||
local keep_local = settings:get('fax', 'keep_local', 'boolean')
|
||||
local storage_type = (keep_local == "false") and "" or settings:get('fax', 'storage_type', 'text')
|
||||
|
||||
local function opt(v, default)
|
||||
if v then return "'" .. v .. "'" end
|
||||
return default or 'NULL'
|
||||
end
|
||||
|
||||
local function now_sql()
|
||||
return (database["type"] == "sqlite") and "'"..os.date("%Y-%m-%d %X").."'" or "now()";
|
||||
end
|
||||
|
||||
--add to fax logs
|
||||
do
|
||||
local fields = {
|
||||
"fax_log_uuid";
|
||||
"domain_uuid";
|
||||
"fax_uuid";
|
||||
"fax_success";
|
||||
"fax_result_code";
|
||||
"fax_result_text";
|
||||
"fax_file";
|
||||
"fax_ecm_used";
|
||||
"fax_local_station_id";
|
||||
"fax_document_transferred_pages";
|
||||
"fax_document_total_pages";
|
||||
"fax_image_resolution";
|
||||
"fax_image_size";
|
||||
"fax_bad_rows";
|
||||
"fax_transfer_rate";
|
||||
"fax_retry_attempts";
|
||||
"fax_retry_limit";
|
||||
"fax_retry_sleep";
|
||||
"fax_uri";
|
||||
"fax_epoch";
|
||||
}
|
||||
|
||||
local params = {
|
||||
fax_log_uuid = uuid;
|
||||
domain_uuid = domain_uuid;
|
||||
fax_uuid = fax_uuid or dbh.NULL;
|
||||
fax_success = fax_success or dbh.NULL;
|
||||
fax_result_code = fax_result_code or dbh.NULL;
|
||||
fax_result_text = fax_result_text or dbh.NULL;
|
||||
fax_file = fax_file or dbh.NULL;
|
||||
fax_ecm_used = fax_ecm_used or dbh.NULL;
|
||||
fax_local_station_id = fax_local_station_id or dbh.NULL;
|
||||
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 or dbh.NULL;
|
||||
fax_image_size = fax_image_size or dbh.NULL;
|
||||
fax_bad_rows = fax_bad_rows or dbh.NULL;
|
||||
fax_transfer_rate = fax_transfer_rate or dbh.NULL;
|
||||
fax_retry_attempts = fax_retry_attempts or dbh.NULL;
|
||||
fax_retry_limit = fax_retry_limit or dbh.NULL;
|
||||
fax_retry_sleep = fax_retry_sleep or dbh.NULL;
|
||||
fax_uri = fax_uri or dbh.NULL;
|
||||
fax_epoch = os.time();
|
||||
}
|
||||
|
||||
local values = ":" .. table.concat(fields, ",:")
|
||||
fields = table.concat(fields, ",") .. ",fax_date"
|
||||
|
||||
if database["type"] == "sqlite" then
|
||||
params.fax_date = os.date("%Y-%m-%d %X");
|
||||
values = values .. ",:fax_date"
|
||||
else
|
||||
values = values .. ",now()"
|
||||
end
|
||||
|
||||
local sql = "insert into v_fax_logs(" .. fields .. ")values(" .. values .. ")"
|
||||
|
||||
if (debug["sql"]) then
|
||||
log.noticef("SQL: %s; params: %s", sql, json.encode(params, dbh.NULL));
|
||||
end
|
||||
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
|
||||
-- add the fax files
|
||||
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 = file.read_base64(fax_file);
|
||||
if not fax_base64 then
|
||||
log.waitng("Can not find file %s", fax_file)
|
||||
storage_type = nil
|
||||
end
|
||||
end
|
||||
|
||||
-- build SQL
|
||||
local sql do
|
||||
|
||||
local fields = {
|
||||
"fax_file_uuid";
|
||||
"fax_uuid";
|
||||
"fax_mode";
|
||||
"fax_destination";
|
||||
"fax_file_type";
|
||||
"fax_file_path";
|
||||
"fax_caller_id_name";
|
||||
"fax_caller_id_number";
|
||||
"fax_epoch";
|
||||
"fax_base64";
|
||||
"domain_uuid";
|
||||
}
|
||||
|
||||
local params = {
|
||||
fax_file_uuid = uuid;
|
||||
fax_uuid = fax_uuid or dbh.NULL;
|
||||
fax_mode = "tx";
|
||||
fax_destination = sip_to_user or dbh.NULL;
|
||||
fax_file_type = "tif";
|
||||
fax_file_path = fax_file or dbh.NULL;
|
||||
fax_caller_id_name = origination_caller_id_name or dbh.NULL;
|
||||
fax_caller_id_number = origination_caller_id_number or dbh.NULL;
|
||||
fax_epoch = os.time();
|
||||
fax_base64 = fax_base64 or dbh.NULL;
|
||||
domain_uuid = domain_uuid or dbh.NULL;
|
||||
}
|
||||
|
||||
local values = ":" .. table.concat(fields, ",:")
|
||||
fields = table.concat(fields, ",") .. ",fax_date"
|
||||
|
||||
if database["type"] == "sqlite" then
|
||||
params.fax_date = os.date("%Y-%m-%d %X");
|
||||
values = values .. ",:fax_date"
|
||||
else
|
||||
values = values .. ",now()"
|
||||
end
|
||||
|
||||
local sql = "insert into v_fax_files(" .. fields .. ")values(" .. values .. ")"
|
||||
|
||||
if (debug["sql"]) then
|
||||
log.noticef("SQL: %s; params: %s", sql, json.encode(params, dbh.NULL));
|
||||
end
|
||||
|
||||
if storage_type == "base64" then
|
||||
local dbh = Database.new('system', 'base64');
|
||||
dbh:query(sql, params);
|
||||
dbh:release();
|
||||
else
|
||||
dbh:query(sql, params)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if fax_success == "1" then
|
||||
--Success
|
||||
log.infof("RETRY STATS SUCCESS: GATEWAY[%s]", fax_options);
|
||||
|
||||
Tasks.remove_task(task)
|
||||
|
||||
local Text = require "resources.functions.text"
|
||||
local text = Text.new("app.fax.app_languages")
|
||||
|
||||
local env = {
|
||||
fax_options = fax_options;
|
||||
destination_number = number_dialed:match("^([^@]*)");
|
||||
document_transferred_pages = fax_document_transferred_pages;
|
||||
document_total_pages = fax_document_total_pages;
|
||||
message = text['message-send_success'];
|
||||
}
|
||||
|
||||
local body = Tasks.build_template(task, 'outbound/success/body', env)
|
||||
local subject = Tasks.build_template(task, 'outbound/success/subject', env)
|
||||
|
||||
if not subject then
|
||||
log.warning("Can not find template for email")
|
||||
subject = "Fax to: " .. number_dialed .. " SENT"
|
||||
end
|
||||
|
||||
local attachment = pdf_file and file_exists(pdf_file) or fax_file and file_exists(fax_file)
|
||||
Tasks.send_mail_task(task, {subject, body}, uuid, attachment)
|
||||
|
||||
if keep_local == "false" then
|
||||
os.remove(pdf_file);
|
||||
os.remove(fax_file);
|
||||
end
|
||||
end
|
||||
|
||||
if fax_success ~= "1" then
|
||||
if not answered then
|
||||
log.noticef("no answer: %d", hangup_cause_q850)
|
||||
else
|
||||
if not fax_success then
|
||||
log.noticef("Fax not detected: %s", fax_options)
|
||||
else
|
||||
log.noticef("fax fail %s", fax_options)
|
||||
end
|
||||
end
|
||||
|
||||
-- if task use group call then retry.lua will be called multiple times
|
||||
-- here we check eathre that channel which execute `exec.lua`
|
||||
-- Note that if there no one execute `exec.lua` we do not need call this
|
||||
-- becase it should deal in `next.lua`
|
||||
if fax_queue_task_session == uuid then
|
||||
Tasks.wait_task(task, answered, hangup_cause_q850)
|
||||
if task.status ~= 0 then
|
||||
Tasks.remove_task(task)
|
||||
|
||||
local Text = require "resources.functions.text"
|
||||
local text = Text.new("app.fax.app_languages")
|
||||
|
||||
local env = {
|
||||
fax_options = fax_options;
|
||||
destination_number = number_dialed:match("^([^@]*)");
|
||||
document_transferred_pages = fax_document_transferred_pages;
|
||||
document_total_pages = fax_document_total_pages;
|
||||
hangup_cause = hangup_cause;
|
||||
hangup_cause_q850 = hangup_cause_q850;
|
||||
fax_result_code = fax_result_code;
|
||||
fax_result_text = fax_result_text;
|
||||
message = text['message-send_fail'];
|
||||
}
|
||||
|
||||
local body = Tasks.build_template(task, 'outbound/fail/body', env)
|
||||
local subject = Tasks.build_template(task, 'outbound/fail/subject', env)
|
||||
|
||||
if not subject then
|
||||
log.warning("Can not find template for email")
|
||||
subject = "Fax to: " .. number_dialed .. " FAILED"
|
||||
end
|
||||
|
||||
local attachment = pdf_file and file_exists(pdf_file) or fax_file and file_exists(fax_file)
|
||||
Tasks.send_mail_task(task, {subject, body}, uuid, attachment)
|
||||
|
||||
if keep_local == "false" then
|
||||
os.remove(pdf_file);
|
||||
os.remove(fax_file);
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,330 @@
|
||||
local Database = require "resources.functions.database"
|
||||
local Settings = require "resources.functions.lazy_settings"
|
||||
local send_mail = require "resources.functions.send_mail"
|
||||
|
||||
local db
|
||||
|
||||
local date_utc_now_sql
|
||||
local now_add_sec_sql
|
||||
|
||||
if database.type == 'pgsql' then
|
||||
date_utc_now_sql = "NOW() at time zone 'utc'"
|
||||
now_add_sec_sql = "NOW() at time zone 'utc' + interval '%s second'"
|
||||
elseif database.type == 'mysql' then
|
||||
date_utc_now_sql = "UTC_TIMESTAMP()"
|
||||
now_add_sec_sql = "DATE_ADD(UTC_TIMESTAMP(), INTERVAL %s SECOND)"
|
||||
elseif database.type == 'sqlite' then
|
||||
date_utc_now_sql = "datetime('now')"
|
||||
now_add_sec_sql = "datetime('now', '%s seconds')"
|
||||
else
|
||||
error("unsupported database type: " .. database.type)
|
||||
end
|
||||
|
||||
-- Broken on FS 1.4 with native postgresql
|
||||
-- Fixed on 1.6.0
|
||||
-- Also works with ODBC
|
||||
local ignore_affected_rows = true
|
||||
if dbh_affected_rows_broken ~= nil then
|
||||
ignore_affected_rows = dbh_affected_rows_broken
|
||||
end
|
||||
|
||||
local Q850_TIMEOUT = {
|
||||
[17] = 60;
|
||||
}
|
||||
|
||||
local select_task_common_sql = [[
|
||||
select
|
||||
t1.fax_task_uuid as uuid,
|
||||
t1.fax_uuid as fax_uuid,
|
||||
t3.domain_name,
|
||||
t3.domain_uuid,
|
||||
t1.task_status as status,
|
||||
t1.task_uri as uri,
|
||||
t1.task_dial_string as dial_string,
|
||||
t1.task_dtmf as dtmf,
|
||||
t1.task_fax_file as fax_file,
|
||||
t1.task_wav_file as wav_file,
|
||||
t1.task_reply_address as reply_address,
|
||||
t1.task_no_answer_counter as no_answer_counter,
|
||||
t1.task_no_answer_retry_counter as no_answer_retry_counter,
|
||||
t1.task_retry_counter as retry_counter,
|
||||
t2.fax_send_greeting as greeting
|
||||
from v_fax_tasks t1
|
||||
inner join v_fax t2 on t2.fax_uuid = t1.fax_uuid
|
||||
inner join v_domains t3 on t2.domain_uuid = t3.domain_uuid
|
||||
where t1.task_interrupted <> 'true'
|
||||
]]
|
||||
|
||||
local next_task_sql = select_task_common_sql .. [[
|
||||
and t1.task_status = 0 and t1.task_next_time < ]] .. date_utc_now_sql .. [[
|
||||
and t2.fax_send_channels > (select count(*) from v_fax_tasks as tasks
|
||||
where tasks.fax_uuid = t1.fax_uuid and
|
||||
tasks.task_status > 0 and tasks.task_status <= 2
|
||||
)
|
||||
order by t1.task_next_time
|
||||
]]
|
||||
|
||||
local select_task_sql = select_task_common_sql .. "and t1.fax_task_uuid='%s'"
|
||||
|
||||
local aquire_task_sql = [[
|
||||
update v_fax_tasks set task_status = 1, task_lock_time = ]] .. date_utc_now_sql .. [[
|
||||
where fax_task_uuid = '%s' and task_status = 0
|
||||
]]
|
||||
|
||||
local wait_task_sql = [[
|
||||
update v_fax_tasks
|
||||
set task_status = %s,
|
||||
task_lock_time = NULL,
|
||||
task_no_answer_counter = %s,
|
||||
task_no_answer_retry_counter = %s,
|
||||
task_retry_counter = %s,
|
||||
task_next_time = ]] .. now_add_sec_sql .. [[
|
||||
where fax_task_uuid = '%s'
|
||||
]]
|
||||
|
||||
local remove_task_task_sql = [[
|
||||
delete from v_fax_tasks
|
||||
where fax_task_uuid = '%s'
|
||||
]]
|
||||
|
||||
local release_task_sql = [[
|
||||
update v_fax_tasks
|
||||
set task_status = 0, task_lock_time = NULL,
|
||||
task_next_time = ]] .. now_add_sec_sql .. [[
|
||||
where fax_task_uuid = '%s'
|
||||
]]
|
||||
|
||||
local release_stuck_tasks_sql = [[
|
||||
update v_fax_tasks
|
||||
set task_status = 0, task_lock_time = NULL,
|
||||
task_next_time = ]] .. date_utc_now_sql .. [[
|
||||
where task_lock_time < ]] .. now_add_sec_sql:format('-3600') .. [[
|
||||
]]
|
||||
|
||||
local remove_finished_tasks_sql = [[
|
||||
delete from v_fax_tasks where task_status > 3
|
||||
]]
|
||||
|
||||
local function serialize(task, header)
|
||||
local str = header or ''
|
||||
for k, v in pairs(task) do
|
||||
str = str .. ('\n %q = %q'):format(tostring(k), tostring(v))
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
local function get_db()
|
||||
if not db then
|
||||
db = assert(Database.new('system'))
|
||||
end
|
||||
return db
|
||||
end
|
||||
|
||||
local function next_task()
|
||||
local db = get_db()
|
||||
|
||||
while true do
|
||||
local task, err = db:first_row(next_task_sql)
|
||||
if not task then return nil, err end
|
||||
local ok, err = db:query( aquire_task_sql:format(task.uuid) )
|
||||
if not ok then return nil, err end
|
||||
local rows = db:affected_rows()
|
||||
if ignore_affected_rows then
|
||||
rows = 1
|
||||
end
|
||||
if rows == 1 then
|
||||
task.no_answer_counter = tonumber(task.no_answer_counter)
|
||||
task.no_answer_retry_counter = tonumber(task.no_answer_retry_counter)
|
||||
task.retry_counter = tonumber(task.retry_counter)
|
||||
return task
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function select_task(fax_task_uuid)
|
||||
local db = get_db()
|
||||
|
||||
local task, err = db:first_row(select_task_sql:format(fax_task_uuid))
|
||||
if not task then return nil, err end
|
||||
|
||||
task.no_answer_counter = tonumber(task.no_answer_counter)
|
||||
task.no_answer_retry_counter = tonumber(task.no_answer_retry_counter)
|
||||
task.retry_counter = tonumber(task.retry_counter)
|
||||
|
||||
return task
|
||||
end
|
||||
|
||||
local function wait_task(task, answered, q850)
|
||||
local db = get_db()
|
||||
|
||||
local interval = 30
|
||||
|
||||
local settings = Settings.new(db, task.domain_name, task.domain_uuid)
|
||||
task.status = 0
|
||||
|
||||
if not answered then
|
||||
interval = Q850_TIMEOUT[q850 or 17] or interval
|
||||
end
|
||||
|
||||
if not answered then
|
||||
local fax_send_no_answer_retry_limit = tonumber(settings:get('fax', 'send_no_answer_retry_limit', 'numeric')) or 0
|
||||
task.no_answer_retry_counter = task.no_answer_retry_counter + 1
|
||||
|
||||
if task.no_answer_retry_counter >= fax_send_no_answer_retry_limit then
|
||||
task.no_answer_retry_counter = 0
|
||||
task.no_answer_counter = task.no_answer_counter + 1
|
||||
local fax_send_no_answer_limit = tonumber(settings:get('fax', 'send_no_answer_limit', 'numeric')) or 0
|
||||
if task.no_answer_counter >= fax_send_no_answer_limit then
|
||||
task.status = 4
|
||||
else
|
||||
interval = tonumber(settings:get('fax', 'send_no_answer_interval', 'numeric')) or interval
|
||||
end
|
||||
else
|
||||
interval = tonumber(settings:get('fax', 'send_no_answer_retry_interval', 'numeric')) or interval
|
||||
end
|
||||
else
|
||||
task.retry_counter = task.retry_counter + 1
|
||||
local fax_send_retry_limit = tonumber(settings:get('fax', 'send_retry_limit', 'numeric')) or 0
|
||||
|
||||
if task.retry_counter >= fax_send_retry_limit then
|
||||
task.status = 4
|
||||
else
|
||||
interval = tonumber(settings:get('fax', 'send_retry_interval', 'numeric')) or interval
|
||||
task.task_seq_call_counter = 0
|
||||
end
|
||||
end
|
||||
|
||||
local sql = wait_task_sql:format(
|
||||
tostring(task.status),
|
||||
tostring(task.no_answer_counter),
|
||||
tostring(task.no_answer_retry_counter),
|
||||
tostring(task.retry_counter),
|
||||
tostring(interval),
|
||||
task.uuid
|
||||
)
|
||||
|
||||
local ok, err = db:query( sql )
|
||||
|
||||
if not ok then return nil, err end
|
||||
|
||||
return task
|
||||
end
|
||||
|
||||
local function remove_task(task)
|
||||
local db = get_db()
|
||||
|
||||
local sql = remove_task_task_sql:format(task.uuid)
|
||||
local ok, err = db:query( sql )
|
||||
if not ok then return nil, err end
|
||||
return db:affected_rows()
|
||||
end
|
||||
|
||||
local function release_task(task)
|
||||
local db = get_db()
|
||||
|
||||
local interval = 30
|
||||
|
||||
local sql = release_task_sql:format(
|
||||
tostring(interval),
|
||||
task.uuid
|
||||
)
|
||||
|
||||
local ok, err = db:query( sql )
|
||||
|
||||
if not ok then return nil, err end
|
||||
|
||||
return task
|
||||
end
|
||||
|
||||
local function cleanup_tasks()
|
||||
local db = get_db()
|
||||
|
||||
db:query(release_stuck_tasks_sql)
|
||||
db:query(remove_finished_tasks_sql)
|
||||
end
|
||||
|
||||
local function send_mail_task(task, message, call_uuid, file)
|
||||
if not task.reply_address or #task.reply_address == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local mail_x_headers = {
|
||||
["X-FusionPBX-Domain-UUID"] = task.domain_uuid;
|
||||
["X-FusionPBX-Domain-Name"] = task.domain_name;
|
||||
["X-FusionPBX-Call-UUID"] = call_uuid;
|
||||
["X-FusionPBX-Email-Type"] = 'email2fax';
|
||||
}
|
||||
|
||||
return send_mail(mail_x_headers, task.reply_address, message, file)
|
||||
end
|
||||
|
||||
local function read_file(name, mode)
|
||||
local f, err, code = io.open(name, mode or 'rb')
|
||||
if not f then return nil, err, code end
|
||||
local data = f:read("*all")
|
||||
f:close()
|
||||
return data
|
||||
end
|
||||
|
||||
local function read_template(app, name, lang)
|
||||
local default_language_path = 'en/us'
|
||||
|
||||
local full_path_tpl = scripts_dir .. '/app/' .. app .. '/resources/templates/{lang}/' .. name .. '.tpl'
|
||||
|
||||
local path
|
||||
|
||||
if lang then
|
||||
path = file_exists((full_path_tpl:gsub('{lang}', lang)))
|
||||
end
|
||||
|
||||
if (not path) and (lang ~= default_language_path) then
|
||||
path = file_exists((full_path_tpl:gsub('{lang}', default_language_path)))
|
||||
end
|
||||
|
||||
if path then
|
||||
return read_file(path)
|
||||
end
|
||||
end
|
||||
|
||||
local function build_template(task, templ, env)
|
||||
local lang
|
||||
|
||||
if default_language and default_dialect then
|
||||
lang = (default_language .. '/' .. default_dialect):lower()
|
||||
else
|
||||
local settings = Settings.new(get_db(), task.domain_name, task.domain_uuid)
|
||||
lang = settings:get('domain', 'language', 'code')
|
||||
if lang then lang = lang:gsub('%-', '/'):lower() end
|
||||
end
|
||||
|
||||
local body = read_template('fax', templ, lang)
|
||||
|
||||
body = body:gsub("[^\\](${.-})", function(name)
|
||||
name = name:sub(3, -2)
|
||||
if type(env) == 'table' then
|
||||
return env[name] or ''
|
||||
end
|
||||
if type(env) == 'function' then
|
||||
return env(name) or ''
|
||||
end
|
||||
end)
|
||||
|
||||
return body
|
||||
end
|
||||
|
||||
return {
|
||||
release_db = function()
|
||||
if db then
|
||||
db:release()
|
||||
db = nil
|
||||
end
|
||||
end;
|
||||
next_task = next_task;
|
||||
wait_task = wait_task;
|
||||
select_task = select_task;
|
||||
remove_task = remove_task;
|
||||
release_task = release_task;
|
||||
cleanup_tasks = cleanup_tasks;
|
||||
send_mail_task = send_mail_task;
|
||||
build_template = build_template;
|
||||
}
|
||||
@@ -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>
|
||||
@@ -0,0 +1 @@
|
||||
Fax to: ${destination_number} FAILED
|
||||
@@ -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>
|
||||
@@ -0,0 +1 @@
|
||||
Fax to: ${destination_number} sent
|
||||
454
app/scripts/resources/scripts/app/feature_event/index.lua
Normal file
454
app/scripts/resources/scripts/app/feature_event/index.lua
Normal file
@@ -0,0 +1,454 @@
|
||||
--
|
||||
-- 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 - 2014
|
||||
-- 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 route_to_bridge = require "resources.functions.route_to_bridge"
|
||||
local blf = require "resources.functions.blf"
|
||||
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"] = true;
|
||||
|
||||
--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
|
||||
|
||||
--get the events
|
||||
--if (user == nil) then
|
||||
--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
|
||||
--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_profile = notify.get_profile(user, host);
|
||||
end
|
||||
|
||||
--DND
|
||||
|
||||
--DND enabled
|
||||
if (feature_action == "SetDoNotDisturb" and feature_enabled == "true" and sip_profile ~= nil) then
|
||||
--set a variable
|
||||
dial_string = "error/user_busy";
|
||||
do_not_disturb = "true";
|
||||
--update the extension
|
||||
sql = "update v_extensions set ";
|
||||
sql = sql .. "do_not_disturb = :do_not_disturb, ";
|
||||
sql = sql .. "forward_all_enabled = 'false', ";
|
||||
sql = sql .. "dial_string = :dial_string ";
|
||||
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, dial_string = dial_string};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
|
||||
--update follow me
|
||||
if (follow_me_uuid ~= nil) then
|
||||
if (string.len(follow_me_uuid) > 0) then
|
||||
local sql = "update v_follow_me set ";
|
||||
sql = sql .. "follow_me_enabled = 'false' ";
|
||||
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", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
end
|
||||
|
||||
--send notify to the phone
|
||||
notify.dnd(user, host, sip_profile, do_not_disturb);
|
||||
|
||||
end
|
||||
|
||||
--DND disabled
|
||||
if (feature_action == "SetDoNotDisturb" and feature_enabled == "false" and sip_profile ~= nil ) then
|
||||
--set a variable
|
||||
do_not_disturb = "false";
|
||||
--update the extension
|
||||
sql = "update v_extensions set ";
|
||||
sql = sql .. "do_not_disturb = :do_not_disturb, ";
|
||||
sql = sql .. "forward_all_enabled = 'false', ";
|
||||
sql = sql .. "dial_string = null ";
|
||||
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_profile, do_not_disturb);
|
||||
|
||||
end
|
||||
|
||||
--Call Forward
|
||||
|
||||
--Call Formward All enabled
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "true" and action_name == "forward_immediate" and sip_profile ~= nil) then
|
||||
--set a variable
|
||||
forward_all_destination = action_value;
|
||||
forward_all_enabled = "true";
|
||||
forward_immediate_destination = action_value;
|
||||
forward_immediate_enabled = "true";
|
||||
|
||||
--get the caller_id for outbound call
|
||||
local forward_caller_id = ""
|
||||
if not empty(forward_caller_id_uuid) then
|
||||
local sql = "select destination_number, destination_description,"..
|
||||
"destination_caller_id_number, destination_caller_id_name " ..
|
||||
"from v_destinations where domain_uuid = :domain_uuid and " ..
|
||||
"destination_type = 'inbound' and destination_uuid = :destination_uuid";
|
||||
local params = {domain_uuid = domain_uuid; destination_uuid = forward_caller_id_uuid}
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
local row = dbh:first_row(sql, params)
|
||||
if row then
|
||||
local caller_id_number = row.destination_caller_id_number
|
||||
if empty(caller_id_number) then
|
||||
caller_id_number = row.destination_number
|
||||
end
|
||||
|
||||
local caller_id_name = row.destination_caller_id_name
|
||||
if empty(caller_id_name) then
|
||||
caller_id_name = row.destination_description
|
||||
end
|
||||
|
||||
if not empty(caller_id_number) then
|
||||
forward_caller_id = forward_caller_id ..
|
||||
",outbound_caller_id_number=" .. caller_id_number ..
|
||||
",origination_caller_id_number=" .. caller_id_number
|
||||
end
|
||||
|
||||
if not empty(caller_id_name) then
|
||||
forward_caller_id = forward_caller_id ..
|
||||
",outbound_caller_id_name=" .. caller_id_name ..
|
||||
",origination_caller_id_name=" .. caller_id_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--set the dial string
|
||||
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 .. "dial_string = null ";
|
||||
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);
|
||||
|
||||
--update follow me
|
||||
if (follow_me_uuid ~= nil) then
|
||||
if (string.len(follow_me_uuid) > 0) then
|
||||
local sql = "update v_follow_me set ";
|
||||
sql = sql .. "follow_me_enabled = 'false' ";
|
||||
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", "[feature_event] "..sql.."; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
end
|
||||
|
||||
--send notify to the phone
|
||||
notify.forward_immediate(user, host, sip_profile, forward_immediate_enabled, forward_immediate_destination);
|
||||
end
|
||||
|
||||
--Call Formward All disable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "false" and action_name == "forward_immediate" and sip_profile ~= nil) 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 .. "dial_string = null ";
|
||||
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_profile, forward_immediate_enabled, forward_immediate_destination);
|
||||
end
|
||||
|
||||
--Call Formward BUSY enable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "true" and action_name == "forward_busy" and sip_profile ~= nil) 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_profile, forward_busy_enabled, forward_busy_destination);
|
||||
end
|
||||
|
||||
--Call Formward BUSY disable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "false" and action_name == "forward_busy" and sip_profile ~= nil) 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_profile, forward_busy_enabled, forward_busy_destination);
|
||||
end
|
||||
|
||||
--Call Formward NO ANSWER enable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "true" and action_name == "forward_no_answer" and sip_profile ~= nil) 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_profile, forward_no_answer_enabled, forward_no_answer_destination, ring_count);
|
||||
end
|
||||
|
||||
--Call Formward NO ANSWER disable
|
||||
if (feature_action == "SetCallForward" and feature_enabled == "false" and action_name == "forward_no_answer" and sip_profile ~= nil) 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_profile, 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_profile, do_not_disturb);
|
||||
|
||||
--Forward all
|
||||
forward_immediate_enabled = forward_all_enabled;
|
||||
forward_immediate_destination = forward_all_destination;
|
||||
--notify.forward_immediate(user, host, sip_profile, forward_immediate_enabled, forward_immediate_destination);
|
||||
|
||||
--Forward busy
|
||||
--notify.forward_busy(user, host, sip_profile, forward_busy_enabled, forward_busy_destination);
|
||||
|
||||
--Forward No Answer
|
||||
ring_count = math.ceil (call_timeout / 6);
|
||||
--notify.forward_no_answer(user, host, sip_profile, forward_no_answer_enabled, forward_no_answer_destination, ring_count);
|
||||
notify.init(user,
|
||||
host,
|
||||
sip_profile,
|
||||
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_profile, 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)
|
||||
|
||||
--clear the cache
|
||||
if (feature_enabled ~= nil) then
|
||||
cache.del("directory:"..user.."@"..host)
|
||||
end
|
||||
@@ -0,0 +1,149 @@
|
||||
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;
|
||||
forward_caller_id_uuid = row.forward_caller_id_uuid;
|
||||
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
|
||||
|
||||
function feature_event_notify.get_profile(user, host)
|
||||
--includes
|
||||
require "resources.functions.explode"
|
||||
require "resources.functions.trim"
|
||||
|
||||
local account = user.."@"..host
|
||||
--create the api object
|
||||
api = freeswitch.API();
|
||||
local sofia_contact = trim(api:executeString("sofia_contact */"..account));
|
||||
local array = explode("/", sofia_contact);
|
||||
local sip_profile = array[2];
|
||||
return sip_profile
|
||||
end
|
||||
|
||||
function feature_event_notify.dnd(user, host, sip_profile, do_not_disturb)
|
||||
--set the event and send it
|
||||
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");
|
||||
event:fire()
|
||||
end
|
||||
|
||||
function feature_event_notify.forward_immediate(user, host, sip_profile, forward_immediate_enabled, forward_immediate_destination)
|
||||
--set the event and send it
|
||||
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");
|
||||
event:fire()
|
||||
end
|
||||
|
||||
function feature_event_notify.forward_busy(user, host, sip_profile, forward_busy_enabled, forward_busy_destination)
|
||||
--set the event and send it
|
||||
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)
|
||||
event:fire()
|
||||
end
|
||||
|
||||
function feature_event_notify.forward_no_answer(user, host, sip_profile, forward_no_answer_enabled, forward_no_answer_destination, ring_count)
|
||||
--set the event and send it
|
||||
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)
|
||||
event:fire()
|
||||
end
|
||||
|
||||
function feature_event_notify.init(user, host, sip_profile, 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
|
||||
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)
|
||||
event:fire()
|
||||
end
|
||||
|
||||
return feature_event_notify
|
||||
472
app/scripts/resources/scripts/app/follow_me/index.lua
Normal file
472
app/scripts/resources/scripts/app/follow_me/index.lua
Normal file
@@ -0,0 +1,472 @@
|
||||
-- FusionPBX
|
||||
-- Version: MPL 1.1
|
||||
|
||||
-- The contents of this file are subject to the Mozilla Public License Version
|
||||
-- 1.1 (the "License"); you may not use this file except in compliance with
|
||||
-- the License. You may obtain a copy of the License at
|
||||
-- http://www.mozilla.org/MPL/
|
||||
|
||||
-- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
-- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
-- for the specific language governing rights and limitations under the
|
||||
-- License.
|
||||
|
||||
-- The Original Code is FusionPBX
|
||||
|
||||
-- The Initial Developer of the Original Code is
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- Portions created by the Initial Developer are Copyright (C) 2019
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
|
||||
--includes
|
||||
local Database = require "resources.functions.database";
|
||||
local route_to_bridge = require "resources.functions.route_to_bridge"
|
||||
require "resources.functions.trim";
|
||||
|
||||
--get the variables
|
||||
if (session:ready()) then
|
||||
domain_name = session:getVariable("domain_name");
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
destination_number = session:getVariable("destination_number");
|
||||
caller_id_name = session:getVariable("caller_id_name");
|
||||
caller_id_number = session:getVariable("caller_id_number");
|
||||
outbound_caller_id_name = session:getVariable("outbound_caller_id_name");
|
||||
outbound_caller_id_number = session:getVariable("outbound_caller_id_number");
|
||||
call_direction = session:getVariable("call_direction");
|
||||
original_destination_number = session:getVariable("destination_number");
|
||||
end
|
||||
|
||||
--set caller id
|
||||
if (effective_caller_id_name ~= nil) then
|
||||
caller_id_name = effective_caller_id_name;
|
||||
end
|
||||
if (effective_caller_id_number ~= nil) then
|
||||
caller_id_number = effective_caller_id_number;
|
||||
end
|
||||
|
||||
--default to local if nil
|
||||
if (call_direction == nil) then
|
||||
call_direction = "local";
|
||||
end
|
||||
|
||||
--set the strategy
|
||||
follow_me_strategy = 'simultaneous'; --simultaneous, enterprise
|
||||
|
||||
--include json library
|
||||
debug["sql"] = false;
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson";
|
||||
end
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--get the destination and follow the forward
|
||||
function get_forward_all(count, destination_number, domain_name)
|
||||
cmd = "user_exists id ".. destination_number .." "..domain_name;
|
||||
--freeswitch.consoleLog("notice", "[follow me][call forward all] " .. cmd .. "\n");
|
||||
user_exists = api:executeString(cmd);
|
||||
if (user_exists == "true") then
|
||||
---check to see if the new destination is forwarded
|
||||
cmd = "user_data ".. destination_number .."@" ..domain_name.." var forward_all_enabled";
|
||||
if (api:executeString(cmd) == "true") then
|
||||
--get the toll_allow var
|
||||
cmd = "user_data ".. destination_number .."@" ..domain_name.." var toll_allow";
|
||||
toll_allow = api:executeString(cmd);
|
||||
--freeswitch.consoleLog("notice", "[follow me][call forward all] " .. destination_number .. " toll_allow is ".. toll_allow .."\n");
|
||||
|
||||
--get the new destination
|
||||
cmd = "user_data ".. destination_number .."@" ..domain_name.." var forward_all_destination";
|
||||
destination_number = api:executeString(cmd);
|
||||
--freeswitch.consoleLog("notice", "[follow me][call forward all] " .. count .. " " .. cmd .. " ".. destination_number .."\n");
|
||||
count = count + 1;
|
||||
if (count < 5) then
|
||||
count, destination_number = get_forward_all(count, destination_number, domain_name);
|
||||
end
|
||||
end
|
||||
end
|
||||
return count, destination_number, toll_allow;
|
||||
end
|
||||
|
||||
--connect to the database
|
||||
local dbh = Database.new('system');
|
||||
|
||||
--get the forward busy
|
||||
--cmd = "user_data ".. destination_number .."@"..domain_name.." var forward_busy_enabled=";
|
||||
--forward_busy_enabled = trim(api:executeString(cmd));
|
||||
--cmd = "user_data ".. destination_number .."@"..domain_name.." var forward_busy_destination=";
|
||||
--forward_busy_destination = trim(api:executeString(cmd));
|
||||
|
||||
--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 ";
|
||||
sql = sql .. "from v_extensions ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and ( ";
|
||||
sql = sql .. " extension = :destination_number ";
|
||||
sql = sql .. " OR number_alias = :destination_number ";
|
||||
sql = sql .. ") ";
|
||||
local params = {domain_uuid = domain_uuid,destination_number = destination_number};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "SQL:" .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
status = dbh:query(sql, params, function(row)
|
||||
follow_me_uuid = row["follow_me_uuid"];
|
||||
extension_toll_allow = row["toll_allow"];
|
||||
end);
|
||||
--dbh:query(sql, params, function(row);
|
||||
|
||||
--get the follow me data
|
||||
if (follow_me_uuid ~= nil) then
|
||||
local sql = "select cid_name_prefix, cid_number_prefix, ";
|
||||
sql = sql .. "follow_me_enabled, follow_me_caller_id_uuid, follow_me_ignore_busy ";
|
||||
sql = sql .. "from v_follow_me ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and follow_me_uuid = :follow_me_uuid; ";
|
||||
local params = {domain_uuid = domain_uuid,follow_me_uuid = follow_me_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "SQL:" .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
status = dbh:query(sql, params, function(row)
|
||||
caller_id_name_prefix = row["cid_name_prefix"];
|
||||
caller_id_number_prefix = row["cid_number_prefix"];
|
||||
follow_me_enabled = row["follow_me_enabled"];
|
||||
follow_me_caller_id_uuid = row["follow_me_caller_id_uuid"];
|
||||
follow_me_ignore_busy = row["follow_me_ignore_busy"];
|
||||
end);
|
||||
--dbh:query(sql, params, function(row);
|
||||
end
|
||||
|
||||
--get the follow me destinations
|
||||
if (follow_me_uuid ~= nil) then
|
||||
sql = "select d.domain_uuid, d.domain_name, f.follow_me_destination as destination_number, ";
|
||||
sql = sql .. "f.follow_me_delay as destination_delay, f.follow_me_timeout as destination_timeout, ";
|
||||
sql = sql .. "f.follow_me_prompt as destination_prompt ";
|
||||
sql = sql .. "from v_follow_me_destinations as f, v_domains as d ";
|
||||
sql = sql .. "where f.follow_me_uuid = :follow_me_uuid ";
|
||||
sql = sql .. "and f.domain_uuid = d.domain_uuid ";
|
||||
sql = sql .. "order by f.follow_me_order; ";
|
||||
local params = {follow_me_uuid = follow_me_uuid};
|
||||
destinations = {};
|
||||
destination_count = 0;
|
||||
x = 1;
|
||||
dbh:query(sql, params, function(row)
|
||||
domain_uuid = row["domain_uuid"];
|
||||
domain_name = row["domain_name"];
|
||||
|
||||
if (row.destination_prompt == "1" or row.destination_prompt == "2") then
|
||||
prompt = "true";
|
||||
end
|
||||
|
||||
--follow the forwards
|
||||
count, destination_number, toll_allow = get_forward_all(0, row.destination_number, domain_name);
|
||||
|
||||
--update values
|
||||
row['destination_number'] = destination_number
|
||||
--row['toll_allow'] = toll_allow;
|
||||
|
||||
--check if the user exists
|
||||
cmd = "user_exists id ".. destination_number .." "..domain_name;
|
||||
user_exists = api:executeString(cmd);
|
||||
|
||||
--cmd = "user_exists id ".. destination_number .." "..domain_name;
|
||||
if (user_exists == "true") then
|
||||
--add user_exists true or false to the row array
|
||||
row['user_exists'] = "true";
|
||||
--handle do_not_disturb
|
||||
cmd = "user_data ".. destination_number .."@" ..domain_name.." var do_not_disturb";
|
||||
if (api:executeString(cmd) ~= "true") then
|
||||
--add the row to the destinations array
|
||||
destinations[x] = row;
|
||||
end
|
||||
else
|
||||
--set the values
|
||||
external = "true";
|
||||
row['user_exists'] = "false";
|
||||
--add the row to the destinations array
|
||||
destinations[x] = row;
|
||||
end
|
||||
row['domain_name'] = domain_name;
|
||||
destination_count = destination_count + 1;
|
||||
x = x + 1;
|
||||
end);
|
||||
end
|
||||
|
||||
--get the dialplan data and save it to a table
|
||||
if (external == "true") then
|
||||
dialplans = route_to_bridge.preload_dialplan(
|
||||
dbh, domain_uuid, {hostname = hostname, context = context}
|
||||
)
|
||||
end
|
||||
|
||||
--prepare the array of destinations
|
||||
x = 1;
|
||||
for key, row in pairs(destinations) do
|
||||
--set the values from the database as variables
|
||||
destination_number = row.destination_number;
|
||||
|
||||
--determine if the user is registered if not registered then lookup
|
||||
if (user_exists == "true") then
|
||||
cmd = "sofia_contact */".. destination_number .."@" ..domain_name;
|
||||
if (api:executeString(cmd) == "error/user_not_registered") then
|
||||
freeswitch.consoleLog("NOTICE", "[follow_me] "..cmd.."\n");
|
||||
cmd = "user_data ".. destination_number .."@" ..domain_name.." var forward_user_not_registered_enabled";
|
||||
freeswitch.consoleLog("NOTICE", "[follow_me] "..cmd.."\n");
|
||||
if (api:executeString(cmd) == "true") then
|
||||
--get the new destination number
|
||||
cmd = "user_data ".. destination_number .."@" ..domain_name.." var forward_user_not_registered_destination";
|
||||
freeswitch.consoleLog("NOTICE", "[follow_me] "..cmd.."\n");
|
||||
not_registered_destination_number = api:executeString(cmd);
|
||||
freeswitch.consoleLog("NOTICE", "[follow_me] "..not_registered_destination_number.."\n");
|
||||
if (not_registered_destination_number ~= nil) then
|
||||
destination_number = not_registered_destination_number;
|
||||
destinations[key]['destination_number'] = destination_number;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--process the destinations
|
||||
x = 1;
|
||||
for key, row in pairs(destinations) do
|
||||
freeswitch.consoleLog("NOTICE", "[follow me] destination_number: "..row.destination_number.."\n");
|
||||
end
|
||||
|
||||
--process the destinations
|
||||
x = 1;
|
||||
for key, row in pairs(destinations) do
|
||||
--set the values from the database as variables
|
||||
domain_uuid = row.domain_uuid;
|
||||
destination_number = row.destination_number;
|
||||
destination_delay = row.destination_delay;
|
||||
destination_timeout = row.destination_timeout;
|
||||
destination_prompt = row.destination_prompt;
|
||||
group_confirm_key = row.group_confirm_key;
|
||||
group_confirm_file = row.group_confirm_file;
|
||||
toll_allow = row.toll_allow;
|
||||
user_exists = row.user_exists;
|
||||
|
||||
--follow the forwards
|
||||
count, destination_number = get_forward_all(0, destination_number, domain_name);
|
||||
|
||||
--check if the user exists
|
||||
cmd = "user_exists id ".. destination_number .." "..domain_name;
|
||||
user_exists = api:executeString(cmd);
|
||||
|
||||
--set ringback
|
||||
--follow_me_ringback = format_ringback(follow_me_ringback);
|
||||
--session:setVariable("ringback", follow_me_ringback);
|
||||
--session:setVariable("transfer_ringback", follow_me_ringback);
|
||||
|
||||
--set the timeout if there is only one destination
|
||||
if (session:ready() and destination_count == 1) then
|
||||
session:execute("set", "call_timeout="..row.destination_timeout);
|
||||
end
|
||||
|
||||
--setup the delimiter
|
||||
delimiter = ",";
|
||||
if (follow_me_strategy == "simultaneous") then
|
||||
delimiter = ",";
|
||||
end
|
||||
if (follow_me_strategy == "enterprise") then
|
||||
delimiter = ":_:";
|
||||
end
|
||||
|
||||
--leg delay settings
|
||||
if (follow_me_strategy == "enterprise") then
|
||||
timeout_name = "originate_timeout";
|
||||
delay_name = "originate_delay_start";
|
||||
destination_delay = destination_delay * 500;
|
||||
else
|
||||
timeout_name = "leg_timeout";
|
||||
delay_name = "leg_delay_start";
|
||||
end
|
||||
|
||||
--set confirm
|
||||
if (session:ready() and follow_me_strategy == "simultaneous") then
|
||||
session:execute("set", "group_confirm_key=exec");
|
||||
session:execute("set", "group_confirm_file=lua ".. scripts_dir:gsub('\\','/') .."/confirm.lua");
|
||||
end
|
||||
|
||||
--determine confirm prompt
|
||||
if (destination_prompt == nil) then
|
||||
group_confirm = "confirm=false,";
|
||||
elseif (destination_prompt == "1") then
|
||||
group_confirm = "group_confirm_key=exec,group_confirm_file=lua ".. scripts_dir:gsub('\\','/') .."/confirm.lua,confirm=true";
|
||||
elseif (destination_prompt == "2") then
|
||||
group_confirm = "group_confirm_key=exec,group_confirm_file=lua ".. scripts_dir:gsub('\\','/') .."/confirm.lua,confirm=true";
|
||||
else
|
||||
group_confirm = "confirm=false";
|
||||
end
|
||||
|
||||
--process according to user_exists, sip_uri, external number
|
||||
if (user_exists == "true") then
|
||||
--get the extension_uuid
|
||||
cmd = "user_data ".. destination_number .."@"..domain_name.." var extension_uuid";
|
||||
extension_uuid = trim(api:executeString(cmd));
|
||||
--send to user
|
||||
local dial_string_to_user = "[sip_invite_domain="..domain_name..",call_direction="..call_direction..","..group_confirm..","..timeout_name.."="..destination_timeout..","..delay_name.."="..destination_delay..",dialed_extension=" .. row.destination_number .. ",extension_uuid="..extension_uuid .. "]user/" .. row.destination_number .. "@" .. domain_name;
|
||||
dial_string = dial_string_to_user;
|
||||
elseif (tonumber(destination_number) == nil) then
|
||||
--sip uri
|
||||
dial_string = "[sip_invite_domain="..domain_name..",call_direction="..call_direction..","..group_confirm..","..timeout_name.."="..destination_timeout..","..delay_name.."="..destination_delay.."]" .. row.destination_number;
|
||||
else
|
||||
--external number
|
||||
route_bridge = 'loopback/'..destination_number;
|
||||
if (extension_toll_allow ~= nil) then
|
||||
toll_allow = extension_toll_allow:gsub(",", ":");
|
||||
end
|
||||
|
||||
--set the toll allow to an empty string
|
||||
if (toll_allow == nil) then
|
||||
toll_allow = '';
|
||||
end
|
||||
|
||||
--get the destination caller id name and number
|
||||
if (follow_me_caller_id_uuid ~= nil) then
|
||||
local sql = "select destination_uuid, destination_number, destination_description, destination_caller_id_name, destination_caller_id_number ";
|
||||
sql = sql .. "from v_destinations ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and destination_uuid = :destination_uuid ";
|
||||
sql = sql .. "order by destination_number asc ";
|
||||
local params = {domain_uuid = domain_uuid, destination_uuid = follow_me_caller_id_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "SQL:" .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
status = dbh:query(sql, params, function(field)
|
||||
caller_id_name = field["destination_caller_id_name"];
|
||||
caller_id_number = field["destination_caller_id_number"];
|
||||
end);
|
||||
end
|
||||
|
||||
--check if the user exists
|
||||
if tonumber(caller_id_number) ~= nil then
|
||||
cmd = "user_exists id ".. caller_id_number .." "..domain_name;
|
||||
caller_is_local = api:executeString(cmd);
|
||||
end
|
||||
|
||||
--set the outbound caller id
|
||||
if (session:ready() and caller_is_local) then
|
||||
if (outbound_caller_id_name ~= nil) then
|
||||
caller_id_name = outbound_caller_id_name;
|
||||
end
|
||||
if (outbound_caller_id_number ~= nil) then
|
||||
caller_id_number = outbound_caller_id_number;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--set the caller id
|
||||
caller_id = '';
|
||||
if (caller_id_name ~= nil) then
|
||||
caller_id = "origination_caller_id_name='"..caller_id_name.."'"
|
||||
end
|
||||
if (caller_id_number ~= nil) then
|
||||
caller_id = caller_id .. ",origination_caller_id_number="..caller_id_number;
|
||||
end
|
||||
|
||||
--set the destination dial string
|
||||
dial_string = "[ignore_early_media=true,toll_allow=".. toll_allow ..",".. caller_id ..",sip_invite_domain="..domain_name..",call_direction="..call_direction..","..group_confirm..","..timeout_name.."="..destination_timeout..","..delay_name.."="..destination_delay.."]"..route_bridge
|
||||
end
|
||||
|
||||
--add a delimiter between destinations
|
||||
if (dial_string ~= nil) then
|
||||
--freeswitch.consoleLog("notice", "[follow me] dial_string: " .. dial_string .. "\n");
|
||||
if (x == 1) then
|
||||
if (follow_me_strategy == "enterprise") then
|
||||
app_data = dial_string;
|
||||
else
|
||||
app_data = "{ignore_early_media=true}"..dial_string;
|
||||
end
|
||||
else
|
||||
if (app_data == nil) then
|
||||
if (follow_me_strategy == "enterprise") then
|
||||
app_data = dial_string;
|
||||
else
|
||||
app_data = "{ignore_early_media=true}"..dial_string;
|
||||
end
|
||||
else
|
||||
app_data = app_data .. delimiter .. dial_string;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--increment the value of x
|
||||
x = x + 1;
|
||||
end
|
||||
|
||||
--set ring ready
|
||||
if (session:ready()) then
|
||||
session:execute("ring_ready", "");
|
||||
end
|
||||
|
||||
--send to the console
|
||||
freeswitch.consoleLog("notice", "[app:follow_me] " .. destination_number .. "\n");
|
||||
|
||||
--session execute
|
||||
if (session:ready()) then
|
||||
--set the variables
|
||||
session:execute("set", "hangup_after_bridge=true");
|
||||
session:execute("set", "continue_on_fail=true");
|
||||
|
||||
--execute the bridge
|
||||
if (app_data ~= nil) then
|
||||
if (follow_me_strategy == "enterprise") then
|
||||
app_data = app_data:gsub("%[", "{");
|
||||
app_data = app_data:gsub("%]", "}");
|
||||
end
|
||||
freeswitch.consoleLog("NOTICE", "[follow me] app_data: "..app_data.."\n");
|
||||
session:execute("bridge", app_data);
|
||||
end
|
||||
|
||||
--timeout destination
|
||||
if (app_data ~= nil) then
|
||||
if session:ready() and (
|
||||
session:getVariable("originate_disposition") == "ALLOTTED_TIMEOUT"
|
||||
or session:getVariable("originate_disposition") == "NO_ANSWER"
|
||||
or session:getVariable("originate_disposition") == "NO_USER_RESPONSE"
|
||||
or session:getVariable("originate_disposition") == "USER_NOT_REGISTERED"
|
||||
or session:getVariable("originate_disposition") == "NORMAL_TEMPORARY_FAILURE"
|
||||
or session:getVariable("originate_disposition") == "NO_ROUTE_DESTINATION"
|
||||
or session:getVariable("originate_disposition") == "USER_BUSY"
|
||||
or session:getVariable("originate_disposition") == "RECOVERY_ON_TIMER_EXPIRE"
|
||||
or session:getVariable("originate_disposition") == "failure"
|
||||
) then
|
||||
--get the forward no answer
|
||||
cmd = "user_data ".. original_destination_number .."@"..domain_name.." var forward_no_answer_enabled";
|
||||
forward_no_answer_enabled = trim(api:executeString(cmd));
|
||||
|
||||
cmd = "user_data ".. original_destination_number .."@"..domain_name.." var forward_no_answer_destination";
|
||||
forward_no_answer_destination = trim(api:executeString(cmd));
|
||||
|
||||
cmd = "user_data ".. original_destination_number .."@"..domain_name.." var user_context";
|
||||
user_context = trim(api:executeString(cmd));
|
||||
|
||||
--execute the time out action
|
||||
if (forward_no_answer_enabled == 'true') then
|
||||
session:transfer(forward_no_answer_destination, 'XML', user_context);
|
||||
else
|
||||
session:transfer('*99' .. original_destination_number, 'XML', user_context);
|
||||
end
|
||||
|
||||
--check and report missed call
|
||||
--missed();
|
||||
end
|
||||
end
|
||||
end
|
||||
150
app/scripts/resources/scripts/app/hangup/index.lua
Normal file
150
app/scripts/resources/scripts/app/hangup/index.lua
Normal file
@@ -0,0 +1,150 @@
|
||||
--
|
||||
-- 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');
|
||||
|
||||
--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
|
||||
|
||||
-- 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");
|
||||
|
||||
-- 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
|
||||
|
||||
--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
|
||||
137
app/scripts/resources/scripts/app/is_local/index.lua
Normal file
137
app/scripts/resources/scripts/app/is_local/index.lua
Normal file
@@ -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>
|
||||
-- Portions created by the Initial Developer are Copyright (C) 2014-2019
|
||||
-- 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_number = :destination_number ";
|
||||
sql = sql .. " OR destination_prefix || 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 and variables
|
||||
local var = {}
|
||||
local key = "";
|
||||
local value = "";
|
||||
|
||||
--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
|
||||
335
app/scripts/resources/scripts/app/messages/resources/events.lua
Normal file
335
app/scripts/resources/scripts/app/messages/resources/events.lua
Normal file
@@ -0,0 +1,335 @@
|
||||
--
|
||||
-- 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) 2018
|
||||
|
||||
|
||||
-- Start the script
|
||||
-- <!-- Subscribe to events -->
|
||||
-- <hook event="CUSTOM" subclass="SMS::SEND_MESSAGE" script="app/messages/resources/events.lua"/>
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--define the functions
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.explode";
|
||||
require "resources.functions.base64";
|
||||
|
||||
--include the database class
|
||||
local Database = require "resources.functions.database";
|
||||
|
||||
--set debug
|
||||
debug["sql"] = false;
|
||||
|
||||
--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");
|
||||
|
||||
--intialize settings
|
||||
--from_user = '';
|
||||
|
||||
--get the event variables
|
||||
uuid = event:getHeader("Core-UUID");
|
||||
from_user = event:getHeader("from_user");
|
||||
from_host = event:getHeader("from_host");
|
||||
to_user = event:getHeader("to_user");
|
||||
to_host = event:getHeader("to_host");
|
||||
content_type = event:getHeader("type");
|
||||
message_text = event:getBody();
|
||||
|
||||
--set required variables
|
||||
if (from_user ~= nil and from_host ~= nil) then
|
||||
message_from = from_user .. '@' .. from_host;
|
||||
end
|
||||
if (to_user ~= nil and to_host ~= nil) then
|
||||
message_to = to_user .. '@' .. to_host;
|
||||
end
|
||||
message_type = 'message';
|
||||
|
||||
--connect to the database
|
||||
dbh = Database.new('system');
|
||||
|
||||
--exits the script if we didn't connect properly
|
||||
assert(dbh:connected());
|
||||
|
||||
--set debug
|
||||
debug["sql"] = true;
|
||||
|
||||
--include json library
|
||||
local json
|
||||
if (debug["sql"]) then
|
||||
json = require "resources.functions.lunajson"
|
||||
end
|
||||
|
||||
--check if the from user exits
|
||||
if (from_user ~= nil and from_host ~= nil) then
|
||||
cmd = "user_exists id ".. from_user .." "..from_host;
|
||||
freeswitch.consoleLog("notice", "[messages][from] user exists " .. cmd .. "\n");
|
||||
from_user_exists = api:executeString(cmd);
|
||||
else
|
||||
from_user_exists = 'false';
|
||||
end
|
||||
|
||||
--check if the to user exits
|
||||
if (to_user ~= nil and to_host ~= nil) then
|
||||
cmd = "user_exists id ".. to_user .." "..to_host;
|
||||
freeswitch.consoleLog("notice", "[messages][to] user exists " .. cmd .. "\n");
|
||||
to_user_exists = api:executeString(cmd);
|
||||
else
|
||||
to_user_exists = 'false';
|
||||
end
|
||||
|
||||
--add the message
|
||||
if (from_user_exists == 'true') then
|
||||
--set the direction
|
||||
message_direction = 'send';
|
||||
|
||||
--get the from user_uuid
|
||||
cmd = "user_data ".. from_user .."@"..from_host.." var domain_uuid";
|
||||
domain_uuid = trim(api:executeString(cmd));
|
||||
|
||||
--get the from user_uuid
|
||||
cmd = "user_data ".. from_user .."@"..from_host.." var user_uuid";
|
||||
user_uuid = trim(api:executeString(cmd));
|
||||
|
||||
--get the from contact_uuid
|
||||
cmd = "user_data ".. to_user .."@"..to_host.." var contact_uuid";
|
||||
contact_uuid = trim(api:executeString(cmd));
|
||||
|
||||
--create a new uuid and add it to the uuid list
|
||||
message_uuid = api:executeString("create_uuid");
|
||||
|
||||
--sql statement
|
||||
sql = "INSERT INTO v_messages ";
|
||||
sql = sql .."( ";
|
||||
sql = sql .."domain_uuid, ";
|
||||
sql = sql .."message_uuid, ";
|
||||
sql = sql .."user_uuid, ";
|
||||
if (contact_uuid ~= null and string.len(contact_uuid) > 0) then
|
||||
sql = sql .."contact_uuid, ";
|
||||
end
|
||||
sql = sql .."message_direction, ";
|
||||
sql = sql .."message_date, ";
|
||||
sql = sql .."message_type, ";
|
||||
if (message_from ~= null and string.len(message_from) > 0) then
|
||||
sql = sql .."message_from, ";
|
||||
end
|
||||
sql = sql .."message_to, ";
|
||||
sql = sql .."message_text ";
|
||||
sql = sql ..") ";
|
||||
sql = sql .."VALUES ( ";
|
||||
sql = sql ..":domain_uuid, ";
|
||||
sql = sql ..":message_uuid, ";
|
||||
sql = sql ..":user_uuid, ";
|
||||
if (contact_uuid ~= null and string.len(contact_uuid) > 0) then
|
||||
sql = sql ..":contact_uuid, ";
|
||||
end
|
||||
sql = sql ..":message_direction, ";
|
||||
sql = sql .."now(), ";
|
||||
sql = sql ..":message_type, ";
|
||||
if (message_from ~= null and string.len(message_from) > 0) then
|
||||
sql = sql ..":message_from, ";
|
||||
end
|
||||
sql = sql ..":message_to, ";
|
||||
sql = sql ..":message_text ";
|
||||
sql = sql ..") ";
|
||||
|
||||
--set the parameters
|
||||
local params= {}
|
||||
params['domain_uuid'] = domain_uuid;
|
||||
params['message_uuid'] = message_uuid;
|
||||
params['user_uuid'] = user_uuid;
|
||||
if (contact_uuid ~= null and string.len(contact_uuid) > 0) then
|
||||
params['contact_uuid'] = contact_uuid;
|
||||
end
|
||||
params['message_direction'] = message_direction;
|
||||
params['message_type'] = message_type;
|
||||
if (message_from ~= null) then
|
||||
params['message_from'] = message_from;
|
||||
end
|
||||
params['message_to'] = message_to;
|
||||
params['message_text'] = message_text;
|
||||
|
||||
--show debug info
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[call_center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
--run the query
|
||||
dbh:query(sql, params);
|
||||
end
|
||||
if (to_user_exists == 'true') then
|
||||
--sql statement
|
||||
sql = "INSERT INTO v_messages ";
|
||||
sql = sql .."( ";
|
||||
sql = sql .."domain_uuid, ";
|
||||
sql = sql .."message_uuid, ";
|
||||
sql = sql .."user_uuid, ";
|
||||
if (contact_uuid ~= null and string.len(contact_uuid) > 0) then
|
||||
sql = sql .."contact_uuid, ";
|
||||
end
|
||||
sql = sql .."message_direction, ";
|
||||
sql = sql .."message_date, ";
|
||||
sql = sql .."message_type, ";
|
||||
if (message_from ~= null and string.len(message_from) > 0) then
|
||||
sql = sql .."message_from, ";
|
||||
end
|
||||
sql = sql .."message_to, ";
|
||||
sql = sql .."message_text ";
|
||||
sql = sql ..") ";
|
||||
sql = sql .."VALUES ( ";
|
||||
sql = sql ..":domain_uuid, ";
|
||||
sql = sql ..":message_uuid, ";
|
||||
sql = sql ..":user_uuid, ";
|
||||
if (contact_uuid ~= null and string.len(contact_uuid) > 0) then
|
||||
sql = sql ..":contact_uuid, ";
|
||||
end
|
||||
sql = sql ..":message_direction, ";
|
||||
sql = sql .."now(), ";
|
||||
sql = sql ..":message_type, ";
|
||||
if (message_from ~= null and string.len(message_from) > 0) then
|
||||
sql = sql ..":message_from, ";
|
||||
end
|
||||
sql = sql ..":message_to, ";
|
||||
sql = sql ..":message_text ";
|
||||
sql = sql ..") ";
|
||||
|
||||
--set the direction
|
||||
message_direction = 'receive';
|
||||
|
||||
--get the from user_uuid
|
||||
cmd = "user_data ".. to_user .."@"..to_host.." var domain_uuid";
|
||||
domain_uuid = trim(api:executeString(cmd));
|
||||
|
||||
--get the from user_uuid
|
||||
cmd = "user_data ".. to_user .."@"..to_host.." var user_uuid";
|
||||
user_uuid = trim(api:executeString(cmd));
|
||||
|
||||
--get the from contact_uuid
|
||||
cmd = "user_data ".. to_user .."@"..to_host.." var contact_uuid";
|
||||
contact_uuid = trim(api:executeString(cmd));
|
||||
|
||||
--create a new uuid and add it to the uuid list
|
||||
message_uuid = api:executeString("create_uuid");
|
||||
|
||||
--set the parameters
|
||||
local params= {}
|
||||
params['domain_uuid'] = domain_uuid;
|
||||
params['message_uuid'] = message_uuid;
|
||||
params['user_uuid'] = user_uuid;
|
||||
if (contact_uuid ~= null and string.len(message_from) > 0) then
|
||||
params['contact_uuid'] = contact_uuid;
|
||||
end
|
||||
params['message_direction'] = message_direction;
|
||||
params['message_type'] = message_type;
|
||||
params['message_from'] = message_from;
|
||||
params['message_to'] = message_to;
|
||||
params['message_text'] = message_text;
|
||||
|
||||
--show debug info
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[call_center] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
|
||||
--run the query
|
||||
dbh:query(sql, params);
|
||||
|
||||
else
|
||||
|
||||
--get setttings needed to send the message
|
||||
require "resources.functions.settings";
|
||||
settings = settings(domain_uuid);
|
||||
if (settings['message'] ~= nil) then
|
||||
http_method = '';
|
||||
if (settings['message']['http_method'] ~= nil) then
|
||||
if (settings['message']['http_method']['text'] ~= nil) then
|
||||
http_method = settings['message']['http_method']['text'];
|
||||
end
|
||||
end
|
||||
|
||||
http_content_type = '';
|
||||
if (settings['message']['http_content_type'] ~= nil) then
|
||||
if (settings['message']['http_content_type']['text'] ~= nil) then
|
||||
http_content_type = settings['message']['http_content_type']['text'];
|
||||
end
|
||||
end
|
||||
|
||||
http_destination = '';
|
||||
if (settings['message']['http_destination'] ~= nil) then
|
||||
if (settings['message']['http_destination']['text'] ~= nil) then
|
||||
http_destination = settings['message']['http_destination']['text'];
|
||||
end
|
||||
end
|
||||
|
||||
http_auth_enabled = 'false';
|
||||
if (settings['message']['http_auth_enabled'] ~= nil) then
|
||||
if (settings['message']['http_auth_enabled']['boolean'] ~= nil) then
|
||||
http_auth_enabled = settings['message']['http_auth_enabled']['boolean'];
|
||||
end
|
||||
end
|
||||
|
||||
http_auth_type = '';
|
||||
if (settings['message']['http_auth_type'] ~= nil) then
|
||||
if (settings['message']['http_auth_type']['text'] ~= nil) then
|
||||
http_auth_type = settings['message']['http_auth_type']['text'];
|
||||
end
|
||||
end
|
||||
|
||||
http_auth_user = '';
|
||||
if (settings['message']['http_auth_user'] ~= nil) then
|
||||
if (settings['message']['http_auth_user']['text'] ~= nil) then
|
||||
http_auth_user = settings['message']['http_auth_user']['text'];
|
||||
end
|
||||
end
|
||||
|
||||
http_auth_password = '';
|
||||
if (settings['message']['http_auth_password'] ~= nil) then
|
||||
if (settings['message']['http_auth_password']['text'] ~= nil) then
|
||||
http_auth_password = settings['message']['http_auth_password']['text'];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--get the sip user outbound_caller_id
|
||||
if (from_user ~= nil and from_host ~= nil) then
|
||||
cmd = "user_data ".. from_user .."@"..from_host.." var outbound_caller_id_number";
|
||||
from = trim(api:executeString(cmd));
|
||||
else
|
||||
from = '';
|
||||
end
|
||||
|
||||
--replace variables for their value
|
||||
http_destination = http_destination:gsub("${from}", from);
|
||||
|
||||
--send to the provider using curl
|
||||
if (to_user ~= nil) then
|
||||
cmd = [[curl ]].. http_destination ..[[ ]]
|
||||
cmd = cmd .. [[-H "Content-Type: ]]..http_content_type..[[" ]];
|
||||
if (http_auth_type == 'basic') then
|
||||
cmd = cmd .. [[-H "Authorization: Basic ]]..base64.encode(http_auth_user..":"..http_auth_password)..[[" ]];
|
||||
end
|
||||
cmd = cmd .. [[-d '{"to":"]]..to_user..[[","text":"]]..message_text..[["}']]
|
||||
result = api:executeString("system "..cmd);
|
||||
--status = os.execute (cmd);
|
||||
|
||||
--debug - log the command
|
||||
freeswitch.consoleLog("notice", "[message] " .. cmd.. "\n");
|
||||
end
|
||||
|
||||
end
|
||||
@@ -0,0 +1,73 @@
|
||||
-- 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) 2018
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
|
||||
--get the argv values
|
||||
script_name = argv[0];
|
||||
message_from = argv[1];
|
||||
message_to = argv[2];
|
||||
message_text = argv[3];
|
||||
|
||||
--send a message to the console
|
||||
freeswitch.consoleLog("NOTICE",[[[message] from ]]..message_from);
|
||||
freeswitch.consoleLog("NOTICE",[[[message] to ]] .. message_to);
|
||||
freeswitch.consoleLog("NOTICE",[[[message] from ]]..message_text);
|
||||
|
||||
--connect to the database
|
||||
--local Database = require "resources.functions.database";
|
||||
--dbh = Database.new('system');
|
||||
|
||||
--include functions
|
||||
require "resources.functions.trim";
|
||||
require "resources.functions.explode";
|
||||
--require "resources.functions.file_exists";
|
||||
|
||||
--create the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--get the domain name for the destination
|
||||
array = explode('@', message_to);
|
||||
domain_name = array[2];
|
||||
freeswitch.consoleLog("NOTICE",[[[message] domain_name ]]..domain_name);
|
||||
|
||||
--get the sip profile name
|
||||
local sofia_contact = trim(api:executeString("sofia_contact */"..message_to));
|
||||
local array = explode("/", sofia_contact);
|
||||
local sip_profile = array[2];
|
||||
|
||||
--send the sms message
|
||||
local event = freeswitch.Event("CUSTOM", "SMS::SEND_MESSAGE");
|
||||
event:addHeader("proto", "sip");
|
||||
event:addHeader("dest_proto", "sip");
|
||||
event:addHeader("from", message_from);
|
||||
event:addHeader("from_full", "sip:"..message_from);
|
||||
event:addHeader("to", message_to);
|
||||
event:addHeader("subject", "sip:"..message_to);
|
||||
--event:addHeader("type", "text/html");
|
||||
event:addHeader("type", "text/plain");
|
||||
event:addHeader("hint", "the hint");
|
||||
event:addHeader("replying", "true");
|
||||
event:addHeader("sip_profile", sip_profile);
|
||||
event:addBody(message_text);
|
||||
|
||||
--send info to the console
|
||||
freeswitch.consoleLog("info", event:serialize());
|
||||
|
||||
--send the event
|
||||
event:fire();
|
||||
@@ -0,0 +1 @@
|
||||
Missed Call from ${caller_id_name} <${caller_id_number}> to ${sip_to_user} ext ${dialed_user}
|
||||
@@ -0,0 +1 @@
|
||||
Missed Call from ${caller_id_name} <${caller_id_number}>
|
||||
254
app/scripts/resources/scripts/app/provision/index.lua
Normal file
254
app/scripts/resources/scripts/app/provision/index.lua
Normal file
@@ -0,0 +1,254 @@
|
||||
-- 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);
|
||||
--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);
|
||||
--send the event
|
||||
event:fire();
|
||||
end
|
||||
967
app/scripts/resources/scripts/app/ring_groups/index.lua
Normal file
967
app/scripts/resources/scripts/app/ring_groups/index.lua
Normal file
@@ -0,0 +1,967 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2010-2019 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>
|
||||
|
||||
--include the log
|
||||
log = require "resources.functions.log".ring_group
|
||||
|
||||
--connect to the database
|
||||
local Database = require "resources.functions.database";
|
||||
dbh = Database.new('system');
|
||||
|
||||
--include json library
|
||||
--debug["sql"] = true;
|
||||
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.base64";
|
||||
require "resources.functions.file_exists";
|
||||
require "resources.functions.channel_utils"
|
||||
require "resources.functions.format_ringback"
|
||||
|
||||
--- include libs
|
||||
local route_to_bridge = require "resources.functions.route_to_bridge"
|
||||
local play_file = require "resources.functions.play_file"
|
||||
|
||||
--define the session hangup
|
||||
function session_hangup_hook()
|
||||
|
||||
--send info to the log
|
||||
--freeswitch.consoleLog("notice","[ring_groups] originate_disposition: " .. session:getVariable("originate_disposition") .. "\n");
|
||||
|
||||
--status
|
||||
status = 'answered'
|
||||
|
||||
--run the missed called function
|
||||
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"
|
||||
or session:getVariable("originate_disposition") == "ORIGINATOR_CANCEL"
|
||||
) then
|
||||
--set the status
|
||||
status = 'missed'
|
||||
--send missed call notification
|
||||
missed();
|
||||
end
|
||||
|
||||
--send the ring group event
|
||||
event = freeswitch.Event("CUSTOM", "RING_GROUPS");
|
||||
event:addHeader("domain_uuid", domain_uuid);
|
||||
event:addHeader("domain_name", domain_name);
|
||||
event:addHeader("ring_group_uuid", ring_group_uuid);
|
||||
event:addHeader("user_uuid", user_uuid);
|
||||
event:addHeader("ring_group_name", ring_group_name);
|
||||
event:addHeader("ring_group_extension", ring_group_extension);
|
||||
event:addHeader("status", status);
|
||||
event:addHeader("call_uuid", uuid);
|
||||
event:addHeader("caller_id_name", caller_id_name);
|
||||
event:addHeader("caller_id_number", caller_id_number);
|
||||
event:fire();
|
||||
|
||||
end
|
||||
|
||||
--define iterator function to iterate over key/value pairs in string
|
||||
local function split_vars_pairs(str)
|
||||
local last_pos = 1
|
||||
return function()
|
||||
-- end of string
|
||||
if not str then return end
|
||||
|
||||
-- handle case when there exists comma after kv pair
|
||||
local action, next_pos = string.match(str, "([^=]+=%b''),()", last_pos)
|
||||
if not action then
|
||||
action, next_pos = string.match(str, "([^=]+=[^'][^,]-),()", last_pos)
|
||||
if not action then
|
||||
action, next_pos = string.match(str, "([^=]+=),()", last_pos)
|
||||
end
|
||||
end
|
||||
if action then
|
||||
last_pos = next_pos
|
||||
return action
|
||||
end
|
||||
|
||||
-- last kv pair may not have comma after it
|
||||
if last_pos < #str then
|
||||
action = string.match(str, "([^=]+=%b'')$", last_pos)
|
||||
if not action then
|
||||
action = string.match(str, "([^=]+=[^,]-)$", last_pos)
|
||||
end
|
||||
str = nil -- end of iteration
|
||||
end
|
||||
|
||||
return action
|
||||
end
|
||||
end
|
||||
|
||||
--set the hangup hook function
|
||||
if (session:ready()) then
|
||||
session:setHangupHook("session_hangup_hook");
|
||||
end
|
||||
|
||||
--get the variables
|
||||
if (session:ready()) then
|
||||
session:setAutoHangup(false);
|
||||
ring_group_uuid = session:getVariable("ring_group_uuid");
|
||||
recordings_dir = session:getVariable("recordings_dir");
|
||||
sounds_dir = session:getVariable("sounds_dir");
|
||||
username = session:getVariable("username");
|
||||
dialplan = session:getVariable("dialplan");
|
||||
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");
|
||||
effective_caller_id_name = session:getVariable("effective_caller_id_name");
|
||||
effective_caller_id_number = session:getVariable("effective_caller_id_number");
|
||||
network_addr = session:getVariable("network_addr");
|
||||
ani = session:getVariable("ani");
|
||||
aniii = session:getVariable("aniii");
|
||||
rdnis = session:getVariable("rdnis");
|
||||
destination_number = session:getVariable("destination_number");
|
||||
source = session:getVariable("source");
|
||||
uuid = session:getVariable("uuid");
|
||||
context = session:getVariable("context");
|
||||
call_direction = session:getVariable("call_direction");
|
||||
accountcode = session:getVariable("accountcode");
|
||||
local_ip_v4 = session:getVariable("local_ip_v4")
|
||||
end
|
||||
|
||||
--set caller id
|
||||
if (effective_caller_id_name ~= nil) then
|
||||
caller_id_name = effective_caller_id_name;
|
||||
end
|
||||
if (effective_caller_id_number ~= nil) then
|
||||
caller_id_number = effective_caller_id_number;
|
||||
end
|
||||
|
||||
--default to local if nil
|
||||
if (call_direction == nil) then
|
||||
call_direction = "local";
|
||||
end
|
||||
|
||||
--set ring ready
|
||||
if (session:ready()) then
|
||||
session:execute("ring_ready", "");
|
||||
end
|
||||
|
||||
--define additional variables
|
||||
uuids = "";
|
||||
external = "false";
|
||||
|
||||
--set the sounds path for the language, dialect and voice
|
||||
if (session:ready()) then
|
||||
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
|
||||
|
||||
--get record_ext
|
||||
record_ext = session:getVariable("record_ext");
|
||||
if (not record_ext) then
|
||||
record_ext = "wav";
|
||||
end
|
||||
|
||||
--prepare the api object
|
||||
api = freeswitch.API();
|
||||
|
||||
--define the session hangup
|
||||
--function on_hangup(s,status)
|
||||
-- freeswitch.consoleLog("NOTICE","---- on_hangup: "..status.."\n");
|
||||
-- error();
|
||||
--end
|
||||
|
||||
--get current switchname
|
||||
hostname = trim(api:execute("switchname", ""))
|
||||
|
||||
--get the ring group
|
||||
ring_group_forward_enabled = '';
|
||||
ring_group_forward_destination = '';
|
||||
sql = "SELECT d.domain_name, r.* FROM v_ring_groups as r, v_domains as d ";
|
||||
sql = sql .. "where r.ring_group_uuid = :ring_group_uuid ";
|
||||
sql = sql .. "and r.domain_uuid = d.domain_uuid ";
|
||||
local params = {ring_group_uuid = ring_group_uuid};
|
||||
status = dbh:query(sql, params, function(row)
|
||||
domain_uuid = row["domain_uuid"];
|
||||
domain_name = row["domain_name"];
|
||||
ring_group_name = row["ring_group_name"];
|
||||
ring_group_extension = row["ring_group_extension"];
|
||||
ring_group_greeting = row["ring_group_greeting"];
|
||||
ring_group_forward_enabled = row["ring_group_forward_enabled"];
|
||||
ring_group_forward_destination = row["ring_group_forward_destination"];
|
||||
ring_group_forward_toll_allow = row["ring_group_forward_toll_allow"];
|
||||
ring_group_call_timeout = row["ring_group_call_timeout"];
|
||||
ring_group_caller_id_name = row["ring_group_caller_id_name"];
|
||||
ring_group_caller_id_number = row["ring_group_caller_id_number"];
|
||||
ring_group_cid_name_prefix = row["ring_group_cid_name_prefix"];
|
||||
ring_group_cid_number_prefix = row["ring_group_cid_number_prefix"];
|
||||
ring_group_follow_me_enabled = row["ring_group_follow_me_enabled"];
|
||||
missed_call_app = row["ring_group_missed_call_app"];
|
||||
missed_call_data = row["ring_group_missed_call_data"];
|
||||
end);
|
||||
|
||||
--set the recording path
|
||||
record_path = recordings_dir .. "/" .. domain_name .. "/archive/" .. os.date("%Y/%b/%d");
|
||||
record_path = record_path:gsub("\\", "/");
|
||||
|
||||
--set the recording file name
|
||||
if (session:ready()) then
|
||||
record_name = session:getVariable("record_name");
|
||||
if (not record_name) then
|
||||
record_name = uuid .. "." .. record_ext;
|
||||
end
|
||||
end
|
||||
|
||||
---set the call_timeout to a higher value to prevent the early timeout of the ring group
|
||||
if (session:ready()) then
|
||||
if (ring_group_call_timeout and #ring_group_call_timeout == 0) then
|
||||
ring_group_call_timeout = '300';
|
||||
end
|
||||
session:setVariable("call_timeout", ring_group_call_timeout);
|
||||
end
|
||||
|
||||
--play the greeting
|
||||
if (session:ready()) then
|
||||
if (ring_group_greeting and #ring_group_greeting > 0) then
|
||||
session:answer();
|
||||
session:sleep(1000);
|
||||
play_file(dbh, domain_name, domain_uuid, ring_group_greeting)
|
||||
session:sleep(1000);
|
||||
end
|
||||
end
|
||||
|
||||
--get the ring group user
|
||||
sql = "SELECT r.*, u.user_uuid FROM v_ring_groups as r, v_ring_group_users as u ";
|
||||
sql = sql .. "where r.ring_group_uuid = :ring_group_uuid ";
|
||||
sql = sql .. "and r.ring_group_uuid = u.ring_group_uuid ";
|
||||
local params = {ring_group_uuid = ring_group_uuid};
|
||||
status = dbh:query(sql, params, function(row)
|
||||
user_uuid = row["user_uuid"];
|
||||
end);
|
||||
|
||||
--set the caller id
|
||||
if (session:ready()) then
|
||||
if (ring_group_cid_name_prefix ~= nil and string.len(ring_group_cid_name_prefix) > 0) then
|
||||
session:execute("export", "effective_caller_id_name="..ring_group_cid_name_prefix.."#"..caller_id_name);
|
||||
end
|
||||
if (ring_group_cid_number_prefix ~= nil and string.len(ring_group_cid_number_prefix) > 0) then
|
||||
session:execute("export", "effective_caller_id_number="..ring_group_cid_number_prefix..caller_id_number);
|
||||
end
|
||||
end
|
||||
|
||||
--check the missed calls
|
||||
function missed()
|
||||
|
||||
--send missed call email
|
||||
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
|
||||
|
||||
--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
|
||||
headers = '{"X-FusionPBX-Domain-UUID":"'..domain_uuid..'",';
|
||||
headers = headers..'"X-FusionPBX-Domain-Name":"'..domain_name..'",';
|
||||
headers = headers..'"X-FusionPBX-Call-UUID":"'..uuid..'",';
|
||||
headers = 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("${ring_group_name}", ring_group_name);
|
||||
subject = subject:gsub("${ring_group_extension}", ring_group_extension);
|
||||
subject = subject:gsub("${sip_to_user}", ring_group_name);
|
||||
subject = subject:gsub("${dialed_user}", ring_group_extension);
|
||||
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("${ring_group_name}", ring_group_name);
|
||||
body = body:gsub("${ring_group_extension}", ring_group_extension);
|
||||
body = body:gsub("${sip_to_user}", ring_group_name);
|
||||
body = body:gsub("${dialed_user}", ring_group_extension);
|
||||
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 email
|
||||
cmd = "luarun email.lua "..missed_call_data.." "..missed_call_data.." "..headers.." '"..subject.."' '"..body.."'";
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[missed call] cmd: " .. cmd .. "\n");
|
||||
end
|
||||
api = freeswitch.API();
|
||||
result = api:executeString(cmd);
|
||||
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", "[ring groups][call forward all] " .. cmd .. "\n");
|
||||
user_exists = api:executeString(cmd);
|
||||
if (user_exists == "true") then
|
||||
---check to see if the new destination is forwarded - third forward
|
||||
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 .."@" ..leg_domain_name.." var toll_allow";
|
||||
toll_allow = api:executeString(cmd);
|
||||
--freeswitch.consoleLog("notice", "[ring groups][call forward all] " .. destination_number .. " toll_allow is ".. toll_allow .."\n");
|
||||
|
||||
--get the new destination - third foward
|
||||
cmd = "user_data ".. destination_number .."@" ..domain_name.." var forward_all_destination";
|
||||
destination_number = api:executeString(cmd);
|
||||
--freeswitch.consoleLog("notice", "[ring groups][call forward all] " .. count .. " " .. cmd .. " ".. destination_number .."\n");
|
||||
count = count + 1;
|
||||
if (count < 5) then
|
||||
count, destination_number = get_forward_all(count, destination_number, domain_name);
|
||||
end
|
||||
end
|
||||
end
|
||||
return count, destination_number, toll_allow;
|
||||
end
|
||||
|
||||
--process the ring group
|
||||
if (ring_group_forward_enabled == "true" and string.len(ring_group_forward_destination) > 0) then
|
||||
--forward the ring group
|
||||
session:setVariable("toll_allow", ring_group_forward_toll_allow);
|
||||
session:execute("transfer", ring_group_forward_destination.." XML "..context);
|
||||
else
|
||||
--get the strategy of the ring group, if random, we use random() to order the destinations
|
||||
local sql = [[
|
||||
SELECT
|
||||
r.ring_group_strategy
|
||||
FROM
|
||||
v_ring_groups as r
|
||||
WHERE
|
||||
ring_group_uuid = :ring_group_uuid
|
||||
AND r.domain_uuid = :domain_uuid
|
||||
AND r.ring_group_enabled = 'true'
|
||||
]];
|
||||
|
||||
local params = {ring_group_uuid = ring_group_uuid, domain_uuid = domain_uuid};
|
||||
|
||||
dbh:query(sql, params, function(row)
|
||||
if (row.ring_group_strategy == "random") then
|
||||
if (database["type"] == "mysql") then
|
||||
sql_order = 'rand()'
|
||||
else
|
||||
sql_order = 'random()' --both postgresql and sqlite uses random() instead of rand()
|
||||
end
|
||||
else
|
||||
sql_order='d.destination_delay, d.destination_number asc'
|
||||
end
|
||||
end);
|
||||
|
||||
--get the ring group destinations
|
||||
sql = [[
|
||||
SELECT
|
||||
r.ring_group_strategy, r.ring_group_timeout_app, r.ring_group_distinctive_ring,
|
||||
d.destination_number, d.destination_delay, d.destination_timeout, d.destination_prompt,
|
||||
r.ring_group_caller_id_name, r.ring_group_caller_id_number,
|
||||
r.ring_group_cid_name_prefix, r.ring_group_cid_number_prefix,
|
||||
r.ring_group_timeout_data, r.ring_group_ringback
|
||||
FROM
|
||||
v_ring_groups as r, v_ring_group_destinations as d
|
||||
WHERE
|
||||
d.ring_group_uuid = r.ring_group_uuid
|
||||
AND d.ring_group_uuid = :ring_group_uuid
|
||||
AND r.domain_uuid = :domain_uuid
|
||||
AND r.ring_group_enabled = 'true'
|
||||
ORDER BY
|
||||
]]..sql_order..[[
|
||||
]];
|
||||
if debug["sql"] then
|
||||
freeswitch.consoleLog("notice", "[ring group] SQL:" .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
destinations = {};
|
||||
x = 1;
|
||||
dbh:query(sql, params, function(row)
|
||||
if (row.destination_prompt == "1" or row.destination_prompt == "2") then
|
||||
prompt = "true";
|
||||
end
|
||||
|
||||
local array = explode("@",row.destination_number);
|
||||
if (array[2] == nil) then
|
||||
-- no @
|
||||
leg_domain_name = domain_name;
|
||||
else
|
||||
leg_domain_name = array[2];
|
||||
end
|
||||
|
||||
--follow the forwards
|
||||
count, destination_number, toll_allow = get_forward_all(0, row.destination_number, leg_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 .." "..leg_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 .."@" ..leg_domain_name.." var do_not_disturb";
|
||||
if (api:executeString(cmd) ~= "true") then
|
||||
--add the row to the destinations array
|
||||
destinations[x] = row;
|
||||
end
|
||||
else
|
||||
--set the values
|
||||
external = "true";
|
||||
row['user_exists'] = "false";
|
||||
--add the row to the destinations array
|
||||
destinations[x] = row;
|
||||
end
|
||||
row['domain_name'] = leg_domain_name;
|
||||
x = x + 1;
|
||||
end);
|
||||
--freeswitch.consoleLog("NOTICE", "[ring_group] external "..external.."\n");
|
||||
|
||||
--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
|
||||
|
||||
---add follow me destinations
|
||||
for key, row in pairs(destinations) do
|
||||
|
||||
if (ring_group_follow_me_enabled == "true") then
|
||||
cmd = "user_data ".. row.destination_number .."@" ..row.domain_name.." var follow_me_enabled";
|
||||
if (api:executeString(cmd) == "true") then
|
||||
|
||||
--set the default value to null
|
||||
follow_me_uuid = nil;
|
||||
|
||||
--select data from the database
|
||||
local sql = "select follow_me_uuid, toll_allow ";
|
||||
sql = sql .. "from v_extensions ";
|
||||
sql = sql .. "where domain_uuid = :domain_uuid ";
|
||||
sql = sql .. "and ( ";
|
||||
sql = sql .. " extension = :destination_number ";
|
||||
sql = sql .. " OR number_alias = :destination_number ";
|
||||
sql = sql .. ") ";
|
||||
local params = {domain_uuid = domain_uuid, destination_number = row.destination_number};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "SQL:" .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
status = dbh:query(sql, params, function(field)
|
||||
follow_me_uuid = field["follow_me_uuid"];
|
||||
toll_allow = field["toll_allow"];
|
||||
end);
|
||||
--dbh:query(sql, params, function(row);
|
||||
|
||||
--get the follow me destinations
|
||||
if (follow_me_uuid ~= nil) then
|
||||
sql = "select d.domain_uuid, d.domain_name, f.follow_me_destination as destination_number, ";
|
||||
sql = sql .. "f.follow_me_delay as destination_delay, f.follow_me_timeout as destination_timeout, ";
|
||||
sql = sql .. "f.follow_me_prompt as destination_prompt ";
|
||||
sql = sql .. "from v_follow_me_destinations as f, v_domains as d ";
|
||||
sql = sql .. "where f.follow_me_uuid = :follow_me_uuid ";
|
||||
sql = sql .. "and f.domain_uuid = d.domain_uuid ";
|
||||
sql = sql .. "order by f.follow_me_order; ";
|
||||
local params = {follow_me_uuid = follow_me_uuid};
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "SQL:" .. sql .. "; params: " .. json.encode(params) .. "\n");
|
||||
end
|
||||
x = 1;
|
||||
dbh:query(sql, params, function(field)
|
||||
--check if the user exists
|
||||
cmd = "user_exists id ".. field.destination_number .." "..row.domain_name;
|
||||
user_exists = api:executeString(cmd);
|
||||
|
||||
--prepare the key
|
||||
if (x == 1) then
|
||||
new_key = key;
|
||||
else
|
||||
new_key = #destinations + 1;
|
||||
end
|
||||
|
||||
--Calculate the destination_timeout for follow-me destinations.
|
||||
--The call should honor ring group timeouts with rg delays, follow-me timeouts and follow-me delays factored in.
|
||||
--Destinations with a timeout of 0 or negative numbers should be ignored.
|
||||
if (tonumber(field.destination_timeout) < (tonumber(row.destination_timeout) - tonumber(field.destination_delay))) then
|
||||
new_destination_timeout = field.destination_timeout;
|
||||
else
|
||||
new_destination_timeout = row.destination_timeout - field.destination_delay;
|
||||
end
|
||||
|
||||
--add to the destinations array
|
||||
destinations[new_key] = {}
|
||||
destinations[new_key]['ring_group_strategy'] = row.ring_group_strategy;
|
||||
destinations[new_key]['ring_group_timeout_app'] = row.ring_group_timeout_app;
|
||||
destinations[new_key]['ring_group_timeout_data'] = row.ring_group_timeout_data;
|
||||
destinations[new_key]['ring_group_caller_id_name'] = row.ring_group_caller_id_name;
|
||||
destinations[new_key]['ring_group_caller_id_number'] = row.ring_group_caller_id_number;
|
||||
destinations[new_key]['ring_group_cid_name_prefix'] = row.ring_group_cid_name_prefix;
|
||||
destinations[new_key]['ring_group_cid_number_prefix'] = row.ring_group_cid_number_prefix;
|
||||
destinations[new_key]['ring_group_distinctive_ring'] = row.ring_group_distinctive_ring;
|
||||
destinations[new_key]['ring_group_ringback'] = row.ring_group_ringback;
|
||||
destinations[new_key]['domain_name'] = field.domain_name;
|
||||
destinations[new_key]['destination_number'] = field.destination_number;
|
||||
destinations[new_key]['destination_delay'] = field.destination_delay + row.destination_delay;
|
||||
destinations[new_key]['destination_timeout'] = new_destination_timeout;
|
||||
destinations[new_key]['destination_prompt'] = field.destination_prompt;
|
||||
destinations[new_key]['group_confirm_key'] = row.group_confirm_key;
|
||||
destinations[new_key]['group_confirm_file'] = row.group_confirm_file;
|
||||
destinations[new_key]['toll_allow'] = toll_allow;
|
||||
destinations[new_key]['user_exists'] = user_exists;
|
||||
|
||||
--increment x
|
||||
x = x + 1;
|
||||
end);
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--prepare the array of destinations
|
||||
for key, row in pairs(destinations) do
|
||||
--determine if the user is registered if not registered then lookup
|
||||
if (row.user_exists == "true") then
|
||||
cmd = "sofia_contact */".. row.destination_number .."@" ..domain_name;
|
||||
if (api:executeString(cmd) == "error/user_not_registered") then
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group] "..cmd.."\n");
|
||||
cmd = "user_data ".. row.destination_number .."@" ..domain_name.." var forward_user_not_registered_enabled";
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group] "..cmd.."\n");
|
||||
if (api:executeString(cmd) == "true") then
|
||||
--get the new destination number
|
||||
cmd = "user_data ".. row.destination_number .."@" ..domain_name.." var forward_user_not_registered_destination";
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group] "..cmd.."\n");
|
||||
not_registered_destination_number = api:executeString(cmd);
|
||||
freeswitch.consoleLog("NOTICE", "[ring_group] "..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
|
||||
|
||||
--add the array to the logs
|
||||
for key, row in pairs(destinations) do
|
||||
freeswitch.consoleLog("NOTICE", "[ring group] domain_name: "..row.domain_name.."\n");
|
||||
freeswitch.consoleLog("NOTICE", "[ring group] destination_number: "..row.destination_number.."\n");
|
||||
freeswitch.consoleLog("NOTICE", "[ring group] destination_delay: "..row.destination_delay.."\n");
|
||||
freeswitch.consoleLog("NOTICE", "[ring group] destination_timeout: "..row.destination_timeout.."\n");
|
||||
freeswitch.consoleLog("NOTICE", "[ring group] destination_prompt: "..row.destination_prompt.."\n");
|
||||
end
|
||||
|
||||
--process the destinations
|
||||
x = 1;
|
||||
for key, row in pairs(destinations) do
|
||||
if (tonumber(row.destination_timeout) > 0) then
|
||||
--set the values from the database as variables
|
||||
ring_group_strategy = row.ring_group_strategy;
|
||||
ring_group_timeout_app = row.ring_group_timeout_app;
|
||||
ring_group_timeout_data = row.ring_group_timeout_data;
|
||||
ring_group_caller_id_name = row.ring_group_caller_id_name;
|
||||
ring_group_caller_id_number = row.ring_group_caller_id_number;
|
||||
ring_group_cid_name_prefix = row.ring_group_cid_name_prefix;
|
||||
ring_group_cid_number_prefix = row.ring_group_cid_number_prefix;
|
||||
ring_group_distinctive_ring = row.ring_group_distinctive_ring;
|
||||
ring_group_ringback = row.ring_group_ringback;
|
||||
destination_number = row.destination_number;
|
||||
destination_delay = row.destination_delay;
|
||||
destination_timeout = row.destination_timeout;
|
||||
destination_prompt = row.destination_prompt;
|
||||
group_confirm_key = row.group_confirm_key;
|
||||
group_confirm_file = row.group_confirm_file;
|
||||
toll_allow = row.toll_allow;
|
||||
user_exists = row.user_exists;
|
||||
|
||||
--follow the forwards
|
||||
count, destination_number = get_forward_all(0, destination_number, leg_domain_name);
|
||||
|
||||
--check if the user exists
|
||||
cmd = "user_exists id ".. destination_number .." "..domain_name;
|
||||
user_exists = api:executeString(cmd);
|
||||
|
||||
--set ringback
|
||||
ring_group_ringback = format_ringback(ring_group_ringback);
|
||||
session:setVariable("ringback", ring_group_ringback);
|
||||
session:setVariable("transfer_ringback", ring_group_ringback);
|
||||
|
||||
--set the timeout if there is only one destination
|
||||
if (#destinations == 1) then
|
||||
session:execute("set", "call_timeout="..row.destination_timeout);
|
||||
end
|
||||
|
||||
--setup the delimiter
|
||||
delimiter = ",";
|
||||
if (ring_group_strategy == "rollover") then
|
||||
delimiter = "|";
|
||||
end
|
||||
if (ring_group_strategy == "sequence") then
|
||||
delimiter = "|";
|
||||
end
|
||||
if (ring_group_strategy == "random") then
|
||||
delimiter = "|";
|
||||
end
|
||||
if (ring_group_strategy == "simultaneous") then
|
||||
delimiter = ",";
|
||||
end
|
||||
if (ring_group_strategy == "enterprise") then
|
||||
delimiter = ":_:";
|
||||
end
|
||||
|
||||
--leg delay settings
|
||||
if (ring_group_strategy == "enterprise") then
|
||||
delay_name = "originate_delay_start";
|
||||
destination_delay = destination_delay * 500;
|
||||
else
|
||||
delay_name = "leg_delay_start";
|
||||
end
|
||||
|
||||
--create a new uuid and add it to the uuid list
|
||||
new_uuid = api:executeString("create_uuid");
|
||||
if (string.len(uuids) == 0) then
|
||||
uuids = new_uuid;
|
||||
else
|
||||
uuids = uuids ..",".. new_uuid;
|
||||
end
|
||||
session:execute("set", "uuids="..uuids);
|
||||
|
||||
--export the ringback
|
||||
if (ring_group_distinctive_ring ~= nil) then
|
||||
if (local_ip_v4 ~= nil) then
|
||||
ring_group_distinctive_ring = ring_group_distinctive_ring:gsub("${local_ip_v4}", local_ip_v4);
|
||||
end
|
||||
if (domain_name ~= nil) then
|
||||
ring_group_distinctive_ring = ring_group_distinctive_ring:gsub("${domain_name}", domain_name);
|
||||
end
|
||||
session:execute("export", "sip_h_Alert-Info="..ring_group_distinctive_ring);
|
||||
end
|
||||
|
||||
--set confirm
|
||||
if (ring_group_strategy == "simultaneous"
|
||||
or ring_group_strategy == "sequence"
|
||||
or ring_group_strategy == "rollover") 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
|
||||
|
||||
--get user_record value and determine whether to record the session
|
||||
cmd = "user_data ".. destination_number .."@"..domain_name.." var user_record";
|
||||
user_record = trim(api:executeString(cmd));
|
||||
--set the record_session variable
|
||||
record_session = false;
|
||||
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
|
||||
|
||||
--record the session
|
||||
if (record_session) then
|
||||
record_session = ",api_on_answer='uuid_record "..uuid.." start ".. record_path .. "/" .. record_name .. "',record_path='".. record_path .."',record_name="..record_name;
|
||||
else
|
||||
record_session = ""
|
||||
end
|
||||
row.record_session = record_session
|
||||
|
||||
--process according to user_exists, sip_uri, external number
|
||||
if (user_exists == "true") then
|
||||
--get the extension_uuid
|
||||
cmd = "user_data ".. destination_number .."@"..domain_name.." var extension_uuid";
|
||||
extension_uuid = trim(api:executeString(cmd));
|
||||
--send to user
|
||||
local dial_string_to_user = "[sip_invite_domain="..domain_name..",call_direction="..call_direction..","..group_confirm.."leg_timeout="..destination_timeout..","..delay_name.."="..destination_delay..",dialed_extension=" .. row.destination_number .. ",extension_uuid="..extension_uuid .. row.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.."leg_timeout="..destination_timeout..","..delay_name.."="..destination_delay.."]" .. row.destination_number;
|
||||
else
|
||||
--external number
|
||||
-- have to double destination_delay here due a FS bug requiring a 50% delay value for internal externsions, but not external calls.
|
||||
destination_delay = destination_delay * 2;
|
||||
|
||||
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 caller id
|
||||
caller_id = '';
|
||||
|
||||
--set the outbound caller id
|
||||
if (caller_is_local == 'true' and outbound_caller_id_name ~= nil) then
|
||||
caller_id = "origination_caller_id_name='"..outbound_caller_id_name.."'";
|
||||
end
|
||||
if (caller_is_local == 'true' and outbound_caller_id_number ~= nil) then
|
||||
caller_id = caller_id .. ",origination_caller_id_number='"..outbound_caller_id_number.."'";
|
||||
end
|
||||
if (ring_group_caller_id_name ~= nil and ring_group_caller_id_name ~= '') then
|
||||
caller_id = "origination_caller_id_name='"..ring_group_caller_id_name.."'";
|
||||
end
|
||||
if (ring_group_caller_id_number ~= nil and ring_group_caller_id_number ~= '') then
|
||||
caller_id = caller_id .. ",origination_caller_id_number="..ring_group_caller_id_number..",";
|
||||
end
|
||||
|
||||
--set the destination dial string
|
||||
dial_string = "[ignore_early_media=true,toll_allow=".. toll_allow ..",".. caller_id ..",sip_invite_domain="..domain_name..",call_direction="..call_direction..","..group_confirm.."leg_timeout="..destination_timeout..","..delay_name.."="..destination_delay.."]"..route_bridge
|
||||
end
|
||||
|
||||
--add a delimiter between destinations
|
||||
if (dial_string ~= nil) then
|
||||
--freeswitch.consoleLog("notice", "[ring group] dial_string: " .. dial_string .. "\n");
|
||||
if (x == 1) then
|
||||
if (ring_group_strategy == "enterprise") then
|
||||
app_data = dial_string;
|
||||
else
|
||||
app_data = "{ignore_early_media=true}"..dial_string;
|
||||
end
|
||||
else
|
||||
if (app_data == nil) then
|
||||
if (ring_group_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
|
||||
end
|
||||
|
||||
--session execute
|
||||
if (session:ready()) then
|
||||
--set the variables
|
||||
session:execute("set", "ignore_early_media=true");
|
||||
session:execute("set", "hangup_after_bridge=true");
|
||||
session:execute("set", "continue_on_fail=true");
|
||||
|
||||
-- support conf-xfer feature
|
||||
-- do
|
||||
-- local uuid = api:executeString("create_uuid")
|
||||
-- session:execute("export", "conf_xfer_number=xfer-" .. uuid .. "-" .. domain_name)
|
||||
-- end
|
||||
|
||||
--set bind digit action
|
||||
local bind_target = 'peer'
|
||||
if session:getVariable("sip_authorized") == "true" then
|
||||
bind_target = 'both';
|
||||
end
|
||||
local bindings = {
|
||||
"local,*2,exec:record_session," .. record_path .. "/" .. record_name,
|
||||
-- "local,*0,exec:execute_extension,conf_xfer_from_dialplan XML conf-xfer@" .. context
|
||||
}
|
||||
for _, str in ipairs(bindings) do
|
||||
session:execute("bind_digit_action", str .. "," .. bind_target)
|
||||
end
|
||||
session:execute("digit_action_set_realm", "local");
|
||||
|
||||
--if the user is busy rollover to the next destination
|
||||
if (ring_group_strategy == "rollover") then
|
||||
timeout = 0;
|
||||
x = 0;
|
||||
for key, row in pairs(destinations) do
|
||||
|
||||
--set the app data
|
||||
app_data = '{ignore_early_media=true}';
|
||||
|
||||
--set the values from the database as variables
|
||||
user_exists = row.user_exists;
|
||||
destination_number = row.destination_number;
|
||||
domain_name = row.domain_name;
|
||||
|
||||
--if the timeout was reached exit the loop and go to the timeout action
|
||||
if (tonumber(ring_group_call_timeout) == timeout) then
|
||||
break;
|
||||
end
|
||||
|
||||
--send the call to the destination
|
||||
if (user_exists == "true") then
|
||||
dial_string = "["..group_confirm.."sip_invite_domain="..domain_name..",originate_timeout="..destination_timeout..",call_direction="..call_direction..",dialed_extension=" .. destination_number .. ",domain_name="..domain_name..",domain_uuid="..domain_uuid..row.record_session.."]user/" .. destination_number .. "@" .. domain_name;
|
||||
elseif (tonumber(destination_number) == nil) then
|
||||
dial_string = "["..group_confirm.."sip_invite_domain="..domain_name..",originate_timeout="..destination_timeout..",call_direction=outbound,domain_name="..domain_name..",domain_uuid="..domain_uuid.."]" .. destination_number;
|
||||
else
|
||||
dial_string = "["..group_confirm.."sip_invite_domain="..domain_name..",originate_timeout="..destination_timeout..",domain_name="..domain_name..",domain_uuid="..domain_uuid..",call_direction=outbound]loopback/" .. destination_number;
|
||||
end
|
||||
|
||||
--add the delimiter
|
||||
app_data = app_data .. dial_string;
|
||||
freeswitch.consoleLog("NOTICE", "[ring group] app_data: "..app_data.."\n");
|
||||
session:execute("bridge", app_data);
|
||||
|
||||
if (session:getVariable("originate_disposition") == "NO_ANSWER" ) then
|
||||
timeout = timeout + destination_timeout;
|
||||
end
|
||||
|
||||
--increment the value of x
|
||||
x = x + 1;
|
||||
end
|
||||
end
|
||||
|
||||
--execute the bridge
|
||||
if (app_data ~= nil) then
|
||||
if (ring_group_strategy == "enterprise") then
|
||||
app_data = app_data:gsub("%[", "{");
|
||||
app_data = app_data:gsub("%]", "}");
|
||||
end
|
||||
freeswitch.consoleLog("NOTICE", "[ring group] app_data: "..app_data.."\n");
|
||||
-- log.noticef("bridge begin: originate_disposition:%s answered:%s ready:%s bridged:%s", session:getVariable("originate_disposition"), session:answered() and "true" or "false", session:ready() and "true" or "false", session:bridged() and "true" or "false")
|
||||
if (ring_group_strategy ~= "rollover") then
|
||||
session:execute("bridge", app_data);
|
||||
end
|
||||
-- log.noticef("bridge done: originate_disposition:%s answered:%s ready:%s bridged:%s", session:getVariable("originate_disposition"), session:answered() and "true" or "false", session:ready() and "true" or "false", session:bridged() and "true" or "false")
|
||||
end
|
||||
|
||||
--timeout destination
|
||||
if (app_data ~= nil) then
|
||||
if session:ready() and (
|
||||
session:getVariable("originate_disposition") == "ALLOTTED_TIMEOUT"
|
||||
or session:getVariable("originate_disposition") == "NO_ANSWER"
|
||||
or session:getVariable("originate_disposition") == "NO_USER_RESPONSE"
|
||||
or session:getVariable("originate_disposition") == "USER_NOT_REGISTERED"
|
||||
or session:getVariable("originate_disposition") == "NORMAL_TEMPORARY_FAILURE"
|
||||
or session:getVariable("originate_disposition") == "NO_ROUTE_DESTINATION"
|
||||
or session:getVariable("originate_disposition") == "USER_BUSY"
|
||||
or session:getVariable("originate_disposition") == "RECOVERY_ON_TIMER_EXPIRE"
|
||||
or session:getVariable("originate_disposition") == "failure"
|
||||
) then
|
||||
--execute the time out action
|
||||
if ring_group_timeout_app and #ring_group_timeout_app > 0 then
|
||||
session:execute(ring_group_timeout_app, ring_group_timeout_data);
|
||||
end
|
||||
--check and report missed call
|
||||
missed();
|
||||
end
|
||||
else
|
||||
if (ring_group_timeout_app ~= nil) then
|
||||
--execute the time out action
|
||||
if ring_group_timeout_app and #ring_group_timeout_app > 0 then
|
||||
session:execute(ring_group_timeout_app, ring_group_timeout_data);
|
||||
end
|
||||
else
|
||||
local sql = "SELECT ring_group_timeout_app, ring_group_timeout_data FROM v_ring_groups ";
|
||||
sql = sql .. "where ring_group_uuid = :ring_group_uuid";
|
||||
local params = {ring_group_uuid = ring_group_uuid};
|
||||
if debug["sql"] then
|
||||
freeswitch.consoleLog("notice", "[ring group] SQL:" .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
--execute the time out action
|
||||
if row.ring_group_timeout_app and #row.ring_group_timeout_app > 0 then
|
||||
session:execute(row.ring_group_timeout_app, row.ring_group_timeout_data);
|
||||
end
|
||||
end);
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--actions
|
||||
--ACTIONS = {}
|
||||
--table.insert(ACTIONS, {"set", "hangup_after_bridge=true"});
|
||||
--table.insert(ACTIONS, {"set", "continue_on_fail=true"});
|
||||
--table.insert(ACTIONS, {"bridge", app_data});
|
||||
--table.insert(ACTIONS, {ring_group_timeout_app, ring_group_timeout_data});
|
||||
@@ -0,0 +1,200 @@
|
||||
--
|
||||
-- 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-2017
|
||||
-- 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 request_id = session:getVariable("request_id");
|
||||
local forward_destination = session:getVariable("forward_destination");
|
||||
|
||||
--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');
|
||||
|
||||
-- user hangup
|
||||
if not session:ready() then return end
|
||||
|
||||
if (request_id ~= 'true') and empty(ring_group_number) and empty(ring_group_uuid) then
|
||||
log.warning('can not detect ring group number. Please specify one of this var: ring_group_number, ring_group_uuid or request_id.')
|
||||
return
|
||||
end
|
||||
|
||||
--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 request_id == 'true' 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
|
||||
|
||||
--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 (request_id == "true") 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 form 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
|
||||
|
||||
--update ring group call farward in database
|
||||
local sql = [[UPDATE v_ring_groups
|
||||
SET
|
||||
ring_group_forward_enabled = :enabled,
|
||||
ring_group_forward_destination = :destination
|
||||
WHERE
|
||||
ring_group_uuid = :uuid]]
|
||||
local params = {
|
||||
enabled = (enabled == 'true') and 'true' or 'false',
|
||||
destination = forward_destination,
|
||||
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,90 @@
|
||||
--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 == "cache") then
|
||||
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
|
||||
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 (cache_updated) then
|
||||
for key,row in pairs(servers) do
|
||||
if (row.method == "curl") then
|
||||
api_command_argument = api_command_argument:gsub(" ", "%%20");
|
||||
url = [[http://]]..row.username..[[:]]..row.password..[[@]]..row.hostname..[[:]]..row.port..[[/webapi/luarun?app/servers/resources/clear_cache.lua%20]]..api_command_argument;
|
||||
api:executeString("system curl " .. url );
|
||||
freeswitch.consoleLog("INFO", "[notice] curl ".. url .. " \n");
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
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
|
||||
126
app/scripts/resources/scripts/app/speed_dial/index.lua
Normal file
126
app/scripts/resources/scripts/app/speed_dial/index.lua
Normal file
@@ -0,0 +1,126 @@
|
||||
-- FusionPBX
|
||||
-- Version: MPL 1.1
|
||||
|
||||
-- The contents of this file are subject to the Mozilla Public License Version
|
||||
-- 1.1 (the "License"); you may not use this file except in compliance with
|
||||
-- the License. You may obtain a copy of the License at
|
||||
-- http://www.mozilla.org/MPL/
|
||||
|
||||
-- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
-- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
-- for the specific language governing rights and limitations under the
|
||||
-- License.
|
||||
|
||||
-- The Original Code is FusionPBX
|
||||
|
||||
-- The Initial Developer of the Original Code is
|
||||
-- Mark J Crane <markjcrane@fusionpbx.com>
|
||||
-- Portions created by the Initial Developer are Copyright (C) 2019
|
||||
-- the Initial Developer. All Rights Reserved.
|
||||
|
||||
-- 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");
|
||||
user = session:getVariable("sip_auth_username")
|
||||
or session:getVariable("username");
|
||||
|
||||
--get the argv values
|
||||
destination = argv[2];
|
||||
|
||||
-- search in cache first
|
||||
local key = "app:dialplan:outbound:speed_dial:" .. user .. ":" .. 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 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
|
||||
local 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))
|
||||
)
|
||||
]];
|
||||
local params = {phone_speed_dial = destination, domain_uuid = domain_uuid, user = user};
|
||||
|
||||
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
|
||||
212
app/scripts/resources/scripts/app/toll_allow/index.lua
Normal file
212
app/scripts/resources/scripts/app/toll_allow/index.lua
Normal file
@@ -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
|
||||
667
app/scripts/resources/scripts/app/voicemail/index.lua
Normal file
667
app/scripts/resources/scripts/app/voicemail/index.lua
Normal file
@@ -0,0 +1,667 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2019 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");
|
||||
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");
|
||||
sip_number_alias = session:getVariable("sip_number_alias");
|
||||
|
||||
--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
|
||||
|
||||
--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
|
||||
if (not vm_say_caller_id_number) then
|
||||
vm_say_caller_id_number = "true";
|
||||
end
|
||||
if (not vm_say_date_time) then
|
||||
vm_say_date_time = "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 domain_uuid
|
||||
domain_uuid = session:getVariable("domain_uuid");
|
||||
if (domain_count > 1) then
|
||||
if (domain_uuid == nil) then
|
||||
--get the domain_uuid using the domain name required for multi-tenant
|
||||
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
|
||||
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 tonumber(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
|
||||
|
||||
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:execute("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.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 the message count and send the mwi event
|
||||
message_waiting(voicemail_id, domain_uuid);
|
||||
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 == sip_from_user 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 (tonumber(vm_disk_quota) <= tonumber(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 (tonumber(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 (tonumber(message_length) > 2) then
|
||||
message_waiting(voicemail_id_copy, domain_uuid);
|
||||
end
|
||||
|
||||
--send the email with the voicemail recording attached
|
||||
if (tonumber(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,90 @@
|
||||
-- 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();
|
||||
--To record a greeting press 1
|
||||
if (session:ready()) then
|
||||
dtmf_digits = macro(session, "to_record_greeting", 1, 100, '');
|
||||
end
|
||||
--To choose greeting press 2
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "choose_greeting", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--To record your name 3
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "to_record_name", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--To change your password press 6
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "change_password", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--For the main menu press 0
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "main_menu", 1, 5000, '');
|
||||
end
|
||||
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
|
||||
macro(session, "goodbye", 1, 1000, '');
|
||||
session:hangup();
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -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 = macro(session, "password_new", 20, 5000, '');
|
||||
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");
|
||||
macro(session, "password_below_minimum", 20, 3000, 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");
|
||||
macro(session, "password_not_secure", 20, 3000);
|
||||
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", "345", "456", "567", "678", "789", "987"};
|
||||
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");
|
||||
macro(session, "password_not_secure", 20, 3000);
|
||||
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 = '';
|
||||
macro(session, "password_changed", 20, 3000, 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 = '';
|
||||
macro(session, "password_not_valid", 1, 1000, '');
|
||||
if (session:ready()) then
|
||||
password_tries = password_tries + 1;
|
||||
if (password_tries < max_tries) then
|
||||
check_password(voicemail_id, password_tries);
|
||||
else
|
||||
macro(session, "goodbye", 1, 1000, '');
|
||||
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 = macro(session, "choose_greeting_choose", 1, 5000, '');
|
||||
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 = '';
|
||||
macro(session, "greeting_selected", 1, 100, greeting_id);
|
||||
end
|
||||
|
||||
--advanced menu
|
||||
if (session:ready()) then
|
||||
timeouts = 0;
|
||||
advanced();
|
||||
end
|
||||
else
|
||||
--invalid greeting_id
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
greeting_id = macro(session, "choose_greeting_fail", 1, 100, '');
|
||||
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 = '';
|
||||
macro(session, "message_deleted", 1, 100, '');
|
||||
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,120 @@
|
||||
-- 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", "phrase:invalid_entry", "\\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:sayPhrase("voicemail_record_greeting", "", "en")
|
||||
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
|
||||
@@ -0,0 +1,171 @@
|
||||
-- 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();
|
||||
|
||||
--save the voicemail message
|
||||
message_saved(voicemail_id, uuid);
|
||||
|
||||
--request the forward_voicemail_id
|
||||
if (session:ready()) then
|
||||
dtmf_digits = '';
|
||||
forward_voicemail_id = macro(session, "forward_enter_extension", 20, 5000, '');
|
||||
if (session:ready()) then
|
||||
if (string.len(forward_voicemail_id) == 0) then
|
||||
dtmf_digits = '';
|
||||
forward_voicemail_id = macro(session, "forward_enter_extension", 20, 5000, '');
|
||||
end
|
||||
end
|
||||
end
|
||||
if (session:ready()) then
|
||||
if (string.len(forward_voicemail_id) == 0) then
|
||||
dtmf_digits = '';
|
||||
forward_voicemail_id = macro(session, "forward_enter_extension", 20, 5000, '');
|
||||
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)
|
||||
|
||||
--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);
|
||||
|
||||
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 = macro(session, "voicemail_id", 20, 5000, '');
|
||||
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
|
||||
macro(session, "goodbye", 1, 1000, '');
|
||||
session:hangup();
|
||||
end
|
||||
end
|
||||
end
|
||||
return voicemail_id;
|
||||
end
|
||||
@@ -0,0 +1,243 @@
|
||||
-- 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 function to listen to the recording
|
||||
function listen_to_recording (message_number, uuid, created_epoch, caller_id_name, caller_id_number)
|
||||
|
||||
--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
|
||||
dtmf_digits = macro(session, "message_number", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--say the number
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
session:say(message_number, default_language, "number", "pronounced");
|
||||
end
|
||||
end
|
||||
--say the caller id number
|
||||
if (session:ready() and caller_id_number ~= nil) then
|
||||
if (vm_say_caller_id_number ~= nil) then
|
||||
if (vm_say_caller_id_number == "true") then
|
||||
session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/voicemail/vm-message_from.wav");
|
||||
session:say(caller_id_number, default_language, "name_spelled", "iterated");
|
||||
end
|
||||
end
|
||||
end
|
||||
--say the message date
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
if (vm_say_date_time ~= nil) then
|
||||
if (vm_say_date_time == "true") 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
|
||||
end
|
||||
end
|
||||
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.."."..vm_message_ext;
|
||||
|
||||
--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
|
||||
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
|
||||
if (file_exists(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext)) then
|
||||
stream_seek = true;
|
||||
if (storage_type == "http_cache") then
|
||||
message_location = storage_path.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext;
|
||||
session:streamFile(storage_path.."/"..voicemail_id.."/msg_"..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.."/msg_"..uuid.."."..vm_message_ext);
|
||||
else
|
||||
session:streamFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext);
|
||||
end
|
||||
else
|
||||
session:streamFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext);
|
||||
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
|
||||
--to listen to the recording press 1
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "listen_to_recording", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--to save the recording press 2
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "save_recording", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--to return the call now press 5
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "return_call", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--to delete the recording press 7
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "delete_recording", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--to forward this message press 8
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "to_forward_message", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--to forward this recording to your email press 9
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "forward_to_email", 1, 3000, '');
|
||||
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
|
||||
listen_to_recording(message_number, uuid, created_epoch, caller_id_name, caller_id_number);
|
||||
elseif (dtmf_digits == "2") then
|
||||
message_saved(voicemail_id, uuid);
|
||||
macro(session, "message_saved", 1, 100, '');
|
||||
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 = '';
|
||||
macro(session, "message_saved", 1, 100, '');
|
||||
elseif (dtmf_digits == "9") then
|
||||
send_email(voicemail_id, uuid);
|
||||
dtmf_digits = '';
|
||||
macro(session, "emailed", 1, 100, '');
|
||||
elseif (dtmf_digits == "*") then
|
||||
timeouts = 0;
|
||||
main_menu();
|
||||
elseif (dtmf_digits == "0") then
|
||||
message_saved(voicemail_id, uuid);
|
||||
session:transfer("0", "XML", context);
|
||||
else
|
||||
message_saved(voicemail_id, uuid);
|
||||
macro(session, "message_saved", 1, 100, '');
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,364 @@
|
||||
-- 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_pound.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,124 @@
|
||||
-- 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 = macro(session, "new_messages", 1, 100, new_messages);
|
||||
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 = macro(session, "saved_messages", 1, 100, saved_messages);
|
||||
end
|
||||
end
|
||||
--to listen to new message
|
||||
if (session:ready() and new_messages ~= '0') then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "listen_to_new_messages", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--to listen to saved message
|
||||
if (session:ready() and saved_messages ~= '0') then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "listen_to_saved_messages", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--for advanced options
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "advanced", 1, 100, '');
|
||||
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 = '';
|
||||
macro(session, "goodbye", 1, 100, '');
|
||||
session:hangup();
|
||||
else
|
||||
if (session:ready()) then
|
||||
timeouts = timeouts + 1;
|
||||
if (timeouts < max_timeouts) then
|
||||
main_menu();
|
||||
else
|
||||
macro(session, "goodbye", 1, 1000, '');
|
||||
session:hangup();
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,115 @@
|
||||
-- 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
|
||||
listen_to_recording(message_number, string.lower(row["voicemail_message_uuid"]), row["created_epoch"], row["caller_id_name"], row["caller_id_number"]);
|
||||
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)
|
||||
--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;
|
||||
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,70 @@
|
||||
-- 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);
|
||||
--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,29 @@
|
||||
|
||||
--define a function to send email
|
||||
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_contact = trim(api:executeString("sofia_contact */"..account));
|
||||
array = explode("/", sofia_contact);
|
||||
sip_profile = array[2];
|
||||
|
||||
--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)
|
||||
return event:fire()
|
||||
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,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.
|
||||
|
||||
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) then
|
||||
|
||||
--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(min_digits, 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(min_digits, 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
|
||||
dtmf_digits = session:playAndGetDigits(min_digits, 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");
|
||||
end
|
||||
|
||||
else
|
||||
--default greeting
|
||||
session:execute("playback","silence_stream://200");
|
||||
dtmf_digits = macro(session, "person_not_available_record_message", 1, 200);
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,136 @@
|
||||
-- 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 = macro(session, "choose_greeting_choose", 1, 5000, '');
|
||||
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 = '';
|
||||
macro(session, "record_greeting", 1, 100, '');
|
||||
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 = '';
|
||||
macro(session, "choose_greeting_fail", 1, 100, '');
|
||||
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,247 @@
|
||||
-- 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
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "to_listen_to_recording", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--to save the recording press 2
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "to_save_recording", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--to re-record press 3
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "to_rerecord", 1, 3000, '');
|
||||
end
|
||||
end
|
||||
--process the dtmf
|
||||
if (session:ready()) then
|
||||
if (dtmf_digits == "1") then
|
||||
--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 = '';
|
||||
macro(session, "message_saved", 1, 100, '');
|
||||
if (type == "message") then
|
||||
--goodbye
|
||||
macro(session, "goodbye", 1, 100, '');
|
||||
--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 = '';
|
||||
macro(session, "goodbye", 1, 100, '');
|
||||
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 = '';
|
||||
macro(session, "message_saved", 1, 100, '');
|
||||
macro(session, "goodbye", 1, 1000, '');
|
||||
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,553 @@
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013-2019 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
|
||||
|
||||
local function transcribe(file_path,settings,start_epoch)
|
||||
--transcription variables
|
||||
if (os.time() - start_epoch > 2) then
|
||||
local transcribe_provider = settings:get('voicemail', 'transcribe_provider', 'text') or '';
|
||||
transcribe_language = settings:get('voicemail', 'transcribe_language', 'text') or 'en-US';
|
||||
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] transcribe_provider: " .. transcribe_provider .. "\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] transcribe_language: " .. transcribe_language .. "\n");
|
||||
end
|
||||
|
||||
if (transcribe_provider == "microsoft") then
|
||||
local api_key1 = settings:get('voicemail', 'microsoft_key1', 'text') or '';
|
||||
local api_key2 = settings:get('voicemail', 'microsoft_key2', 'text') or '';
|
||||
if (api_key1 ~= '' and api_key2 ~= '') then
|
||||
access_token_cmd = "curl -X POST \"https://api.cognitive.microsoft.com/sts/v1.0/issueToken\" -H \"Content-type: application/x-www-form-urlencoded\" -H \"Content-Length: 0\" -H \"Ocp-Apim-Subscription-Key: "..api_key1.."\""
|
||||
local handle = io.popen(access_token_cmd);
|
||||
local access_token_result = handle:read("*a");
|
||||
handle:close();
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CMD: " .. access_token_cmd .. "\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] RESULT: " .. access_token_result .. "\n");
|
||||
end
|
||||
--Access token request can fail
|
||||
if (access_token_result == '') then
|
||||
freeswitch.consoleLog("notice", "[voicemail] ACCESS TOKEN: (null) \n");
|
||||
return ''
|
||||
end
|
||||
transcribe_cmd = "curl -X POST \"https://speech.platform.bing.com/recognize?scenarios=smd&appid=D4D52672-91D7-4C74-8AD8-42B1D98141A5&locale=" .. transcribe_language .. "&device.os=Freeswitch&version=3.0&format=json&instanceid=" .. gen_uuid() .. "&requestid=" .. gen_uuid() .. "\" -H 'Authorization: Bearer " .. access_token_result .. "' -H 'Content-type: audio/wav; codec=\"audio/pcm\"; samplerate=8000; trustsourcerate=false' --data-binary @"..file_path
|
||||
local handle = io.popen(transcribe_cmd);
|
||||
local transcribe_result = handle:read("*a");
|
||||
handle:close();
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CMD: " .. transcribe_cmd .. "\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] RESULT: " .. transcribe_result .. "\n");
|
||||
end
|
||||
--Trancribe request can fail
|
||||
if (transcribe_result == '') then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: (null) \n");
|
||||
return ''
|
||||
else
|
||||
status, transcribe_json = pcall(JSON.decode, transcribe_result);
|
||||
if not status then
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] error decoding bing json\n");
|
||||
end
|
||||
return '';
|
||||
end
|
||||
end
|
||||
|
||||
if (debug["info"]) then
|
||||
if (transcribe_json["results"][1]["name"] == nil) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: (null) \n");
|
||||
else
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: " .. transcribe_json["results"][1]["name"] .. "\n");
|
||||
end
|
||||
if (transcribe_json["results"][1]["confidence"] == nil) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CONFIDENCE: (null) \n");
|
||||
else
|
||||
freeswitch.consoleLog("notice", "[voicemail] CONFIDENCE: " .. transcribe_json["results"][1]["confidence"] .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
transcription = transcribe_json["results"][1]["name"];
|
||||
transcription = transcription:gsub("<profanity>.*<%/profanity>","...");
|
||||
confidence = transcribe_json["results"][1]["confidence"];
|
||||
return transcription;
|
||||
end
|
||||
end
|
||||
|
||||
if (transcribe_provider == "azure") then
|
||||
local api_key1 = settings:get('voicemail', 'azure_key1', 'text') or '';
|
||||
local api_server_region = settings:get('voicemail', 'azure_server_region', 'text') or '';
|
||||
if (api_server_region ~= '') then
|
||||
api_server_region = api_server_region .. ".";
|
||||
else
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] azure_server_region default setting must be set\n");
|
||||
end
|
||||
return '';
|
||||
end
|
||||
if (api_key1 ~= '') then
|
||||
-- search in memcache first, azure documentation claims that the access token is valid for 10 minutes
|
||||
local cache = require "resources.functions.cache";
|
||||
local key = "app:voicemail:azure:access_token";
|
||||
local access_token_result = cache.get(key)
|
||||
|
||||
if access_token_result then
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] Azure access_token recovered from memcached\n");
|
||||
end
|
||||
else
|
||||
access_token_cmd = "curl -X POST \"https://"..api_server_region.."api.cognitive.microsoft.com/sts/v1.0/issueToken\" -H \"Content-type: application/x-www-form-urlencoded\" -H \"Content-Length: 0\" -H \"Ocp-Apim-Subscription-Key: "..api_key1.."\"";
|
||||
local handle = io.popen(access_token_cmd);
|
||||
access_token_result = handle:read("*a");
|
||||
handle:close();
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CMD: " .. access_token_cmd .. "\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] ACCESS TOKEN: " .. access_token_result .. "\n");
|
||||
end
|
||||
--Access token request can fail
|
||||
if (access_token_result == '') then
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] ACCESS TOKEN: (null) \n");
|
||||
end
|
||||
return ''
|
||||
end
|
||||
|
||||
--Azure returns JSON when it has to report an error
|
||||
if (string.sub(access_token_result, 1, 1) == '{') then
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] ERROR STRING: ".. access_token_result .. "\n");
|
||||
end
|
||||
return ''
|
||||
end
|
||||
|
||||
cache.set(key, access_token_result, 120);
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] Azure access_token saved into memcached: " .. access_token_result .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
transcribe_cmd = "curl -X POST \"https://"..api_server_region.."stt.speech.microsoft.com/speech/recognition/conversation/cognitiveservices/v1?language=".. transcribe_language .."&format=detailed\" -H 'Authorization: Bearer " .. access_token_result .. "' -H 'Content-type: audio/wav; codec=\"audio/pcm\"; samplerate=8000; trustsourcerate=false' --data-binary @"..file_path
|
||||
local handle = io.popen(transcribe_cmd);
|
||||
local transcribe_result = handle:read("*a");
|
||||
handle:close();
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CMD: " .. transcribe_cmd .. "\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] RESULT: " .. transcribe_result .. "\n");
|
||||
end
|
||||
--Trancribe request can fail
|
||||
if (transcribe_result == '') then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: (null) \n");
|
||||
return ''
|
||||
end
|
||||
local transcribe_json = JSON.decode(transcribe_result);
|
||||
if (debug["info"]) then
|
||||
if (transcribe_json["NBest"][1]["Display"] == nil) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: (null) \n");
|
||||
else
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: " .. transcribe_json["NBest"][1]["Display"] .. "\n");
|
||||
end
|
||||
if (transcribe_json["NBest"][1]["Confidence"] == nil) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CONFIDENCE: (null) \n");
|
||||
else
|
||||
freeswitch.consoleLog("notice", "[voicemail] CONFIDENCE: " .. transcribe_json["NBest"][1]["Confidence"] .. "\n");
|
||||
end
|
||||
end
|
||||
|
||||
transcription = transcribe_json["NBest"][1]["Display"];
|
||||
confidence = transcribe_json["NBest"][1]["Confidence"];
|
||||
return transcription;
|
||||
end
|
||||
end
|
||||
|
||||
--Watson
|
||||
if (transcribe_provider == "watson") then
|
||||
local api_key = settings:get('voicemail', 'watson_key', 'text') or '';
|
||||
local transcription_server = settings:get('voicemail', 'watson_url', 'text') or '';
|
||||
if (api_key ~= '') then
|
||||
if (vm_message_ext == "mp3") then
|
||||
transcribe_cmd = [[ curl -X POST -u "apikey:]]..api_key..[[" --header "Content-type: audio/mp3" --data-binary @]]..file_path..[[ "]]..transcription_server..[[" ]]
|
||||
else
|
||||
transcribe_cmd = [[ curl -X POST -u "apikey:]]..api_key..[[" --header "Content-type: audio/wav" --data-binary @]]..file_path..[[ "]]..transcription_server..[[" ]]
|
||||
end
|
||||
local handle = io.popen(transcribe_cmd);
|
||||
local transcribe_result = handle:read("*a");
|
||||
handle:close();
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CMD: " .. transcribe_cmd .. "\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] RESULT: " .. transcribe_result .. "\n");
|
||||
end
|
||||
|
||||
--Trancribe request can fail
|
||||
if (transcribe_result == '') then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: (null) \n");
|
||||
return ''
|
||||
else
|
||||
status, transcribe_json = pcall(JSON.decode, transcribe_result);
|
||||
|
||||
if not status then
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] error decoding watson json\n");
|
||||
end
|
||||
return '';
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if (transcribe_json["results"] ~= nil) then
|
||||
--Transcription
|
||||
if (transcribe_json["results"][1]["alternatives"][1]["transcript"] ~= nil) then
|
||||
transcription = '';
|
||||
for key, row in pairs(transcribe_json["results"]) do
|
||||
transcription = transcription .. row["alternatives"][1]["transcript"];
|
||||
end
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: " .. transcription .. "\n");
|
||||
end
|
||||
else
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: (null) \n");
|
||||
end
|
||||
return '';
|
||||
end
|
||||
--Confidence
|
||||
if (transcribe_json["results"][1]["alternatives"][1]["confidence"]) then
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CONFIDENCE: " .. transcribe_json["results"][1]["alternatives"][1]["confidence"] .. "\n");
|
||||
end
|
||||
confidence = transcribe_json["results"][1]["alternatives"][1]["confidence"];
|
||||
else
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CONFIDENCE: (null) \n");
|
||||
end
|
||||
end
|
||||
|
||||
return transcription;
|
||||
else
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: json error \n");
|
||||
end
|
||||
return '';
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (transcribe_provider == "custom") then
|
||||
local transcription_server = settings:get('voicemail', 'transcription_server', 'text') or '';
|
||||
local api_key = settings:get('voicemail', 'api_key', 'text') or '';
|
||||
local json_enabled = settings:get('voicemail', 'json_enabled', 'boolean') or "false";
|
||||
if (transcription_server ~= '') then
|
||||
transcribe_cmd = "curl -X POST " .. transcription_server .. " -H 'Authorization: Bearer " .. api_key .. "' -F file=@"..file_path
|
||||
local handle = io.popen(transcribe_cmd);
|
||||
local transcribe_result = esc(handle:read("*a"));
|
||||
handle:close();
|
||||
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] CMD: " .. transcribe_cmd .. "\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] RESULT: " .. transcribe_result .. "\n");
|
||||
end
|
||||
--Trancribe request can fail
|
||||
if (transcribe_result == '') then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: (null) \n");
|
||||
return ''
|
||||
end
|
||||
if (json_enabled == "true") then
|
||||
local transcribe_json = JSON.decode(transcribe_result);
|
||||
if (transcribe_json["message"] == nil) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: " .. transcribe_result .. "\n");
|
||||
transcribe_result = '';
|
||||
end
|
||||
if (transcribe_json["error"] ~= nil) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] TRANSCRIPTION: " .. transcribe_result .. "\n");
|
||||
transcribe_result = '';
|
||||
end
|
||||
transcribe_result = transcribe_json["message"];
|
||||
end
|
||||
return transcribe_result;
|
||||
end
|
||||
end
|
||||
else
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] message too short for transcription.\n");
|
||||
end
|
||||
end
|
||||
|
||||
return '';
|
||||
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;
|
||||
transcribe_enabled = settings:get('voicemail', 'transcribe_enabled', 'boolean') or "false";
|
||||
local transcribe_provider = settings:get('voicemail', 'transcribe_provider', 'text') or '';
|
||||
|
||||
--debug information
|
||||
if (debug["info"]) then
|
||||
freeswitch.consoleLog("notice", "[voicemail] transcribe_enabled: " .. transcribe_enabled .. "\n");
|
||||
freeswitch.consoleLog("notice", "[voicemail] voicemail_transcription_enabled: " .. voicemail_transcription_enabled .. "\n");
|
||||
end
|
||||
|
||||
--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 = macro(session, "record_message", 1, 100);
|
||||
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 = '';
|
||||
result = macro(session, "record_beep", 1, 100);
|
||||
|
||||
--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
|
||||
mkdir(voicemail_dir.."/"..voicemail_id);
|
||||
if (vm_message_ext == "mp3") then
|
||||
shout_exists = trim(api:execute("module_exists", "mod_shout"));
|
||||
if (shout_exists == "true" and transcribe_enabled == "false") or (shout_exists == "true" and transcribe_enabled == "true" and voicemail_transcription_enabled ~= "true") then
|
||||
freeswitch.consoleLog("notice", "using mod_shout for mp3 encoding\n");
|
||||
--record in mp3 directly, no transcription
|
||||
result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".mp3", message_max_length, message_silence_threshold, message_silence_seconds);
|
||||
elseif (shout_exists == "true" and transcribe_enabled == "true" and voicemail_transcription_enabled == "true" and transcribe_provider == "watson") then
|
||||
--record in mp3 directly with mp3 transcription if watson selected
|
||||
result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".mp3", message_max_length, message_silence_threshold, message_silence_seconds);
|
||||
transcription = transcribe(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".mp3",settings,start_epoch);
|
||||
else
|
||||
--create initial wav recording
|
||||
result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".wav", message_max_length, message_silence_threshold, message_silence_seconds);
|
||||
if (transcribe_enabled == "true" and voicemail_transcription_enabled == "true") then
|
||||
transcription = transcribe(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid..".wav",settings,start_epoch);
|
||||
end
|
||||
--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
|
||||
freeswitch.consoleLog("notice", "neither mod_shout or lame found, defaulting to wav\n");
|
||||
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);
|
||||
if (transcribe_enabled == "true" and voicemail_transcription_enabled == "true") then
|
||||
transcription = transcribe(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext,settings,start_epoch);
|
||||
end
|
||||
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
|
||||
--continue
|
||||
else
|
||||
if (session:ready()) then
|
||||
--your recording is below the minimal acceptable length, please try again
|
||||
dtmf_digits = '';
|
||||
macro(session, "too_small", 1, 100);
|
||||
--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 = '';
|
||||
macro(session, "message_saved", 1, 100, '');
|
||||
macro(session, "goodbye", 1, 100, '');
|
||||
--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,102 @@
|
||||
-- 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 = '';
|
||||
macro(session, "record_name", 1, 100, '');
|
||||
|
||||
--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;
|
||||
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,248 @@
|
||||
-- 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 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)
|
||||
|
||||
--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_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
|
||||
|
||||
--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 * 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)
|
||||
--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"];
|
||||
--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 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 (transcription == nil) then
|
||||
sql = sql .. "AND template_subcategory = 'default' "
|
||||
else
|
||||
sql = sql .. "AND template_subcategory = 'transcription' "
|
||||
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';
|
||||
}
|
||||
|
||||
--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 = 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);
|
||||
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&type=vm&t=bin&id="..id.."&voicemail_uuid="..db_voicemail_uuid.."&uuid="..uuid.."&src=email'>"..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,
|
||||
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) 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 = macro(session, "tutorial_intro", 1, 3000, '');
|
||||
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 = macro(session, "tutorial_to_record_name", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--skip the name and go to password press 2
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "tutorial_skip", 1, 3000, '');
|
||||
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 = macro(session, "tutorial_change_password", 1, 100, '');
|
||||
end
|
||||
end
|
||||
--skip the password and go to greeting press 2
|
||||
if (session:ready()) then
|
||||
if (string.len(dtmf_digits) == 0) then
|
||||
dtmf_digits = macro(session, "tutorial_skip", 1, 3000, '');
|
||||
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 = macro(session, "tutorial_record_greeting", 1, 100, '');
|
||||
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 = macro(session, "tutorial_skip", 1, 3000, '');
|
||||
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,108 @@
|
||||
-- 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
|
||||
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,112 @@
|
||||
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_id = :voicemail_id and d.domain_name = :domain_name]]
|
||||
|
||||
local vm_messages_sql = [[SELECT
|
||||
( SELECT count(*)
|
||||
FROM v_voicemail_messages
|
||||
WHERE voicemail_uuid = %s
|
||||
AND (message_status is null or message_status = '')
|
||||
) as new_messages,
|
||||
|
||||
( SELECT count(*)
|
||||
FROM v_voicemail_messages
|
||||
WHERE voicemail_uuid = %s
|
||||
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
|
||||
|
||||
local uuid
|
||||
if use_cache and cache.support() then
|
||||
local uuid = cache.get('voicemail_uuid:' .. account)
|
||||
if not uuid then
|
||||
uuid = dbh:first_value(vm_to_uuid_sql, {
|
||||
voicemail_id = id, domain_name = domain_name
|
||||
})
|
||||
|
||||
if uuid and #uuid > 0 then
|
||||
cache.set('voicemail_uuid:' .. account, uuid, 3600)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local row
|
||||
if uuid and #uuid > 0 then
|
||||
local sql = string.format(vm_messages_sql, ":voicemail_uuid", ":voicemail_uuid")
|
||||
row = dbh:first_row(sql, {voicemail_uuid = uuid})
|
||||
else
|
||||
local uuid_sql = '(' .. vm_to_uuid_sql .. ')'
|
||||
|
||||
local sql = string.format(vm_messages_sql,
|
||||
uuid_sql, uuid_sql
|
||||
)
|
||||
|
||||
row = dbh:first_row(sql, {
|
||||
voicemail_id = id, domain_name = domain_name
|
||||
})
|
||||
end
|
||||
|
||||
dbh:release()
|
||||
|
||||
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}
|
||||
@@ -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}
|
||||
106
app/scripts/resources/scripts/app/xml_handler/index.lua
Normal file
106
app/scripts/resources/scripts/app/xml_handler/index.lua
Normal file
@@ -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.
|
||||
|
||||
--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");
|
||||
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
|
||||
@@ -0,0 +1,146 @@
|
||||
-- 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.
|
||||
]]
|
||||
|
||||
--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 = {}
|
||||
table.insert(xml, [[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
table.insert(xml, [[<document type="freeswitch/xml">]]);
|
||||
table.insert(xml, [[ <section name="configuration">]]);
|
||||
table.insert(xml, [[ <configuration name="acl.conf" description="Network Lists">]]);
|
||||
table.insert(xml, [[ <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
|
||||
table.insert(xml, [[ <list name="]]..row.access_control_name..[[" default="]]..row.access_control_default..[[">]]);
|
||||
|
||||
--get the nodes
|
||||
sql = "select * from v_access_control_nodes ";
|
||||
sql = sql .. "where access_control_uuid = :access_control_uuid";
|
||||
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)
|
||||
if (string.len(field.node_domain) > 0) then
|
||||
table.insert(xml, [[ <node type="]] .. field.node_type .. [[" domain="]] .. field.node_domain .. [[" description="]] .. field.node_description .. [["/>]]);
|
||||
else
|
||||
table.insert(xml, [[ <node type="]] .. field.node_type .. [[" cidr="]] .. field.node_cidr .. [[" description="]] .. field.node_description .. [["/>]]);
|
||||
end
|
||||
end)
|
||||
|
||||
--list close tag
|
||||
table.insert(xml, [[ </list>]]);
|
||||
|
||||
end)
|
||||
|
||||
--close the extension tag if it was left open
|
||||
table.insert(xml, [[ </network-lists>]]);
|
||||
table.insert(xml, [[ </configuration>]]);
|
||||
table.insert(xml, [[ </section>]]);
|
||||
table.insert(xml, [[</document>]]);
|
||||
XML_STRING = table.concat(xml, "\n");
|
||||
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
|
||||
@@ -0,0 +1,318 @@
|
||||
-- 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.
|
||||
|
||||
--include functions
|
||||
require "resources.functions.format_ringback"
|
||||
|
||||
--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 = {}
|
||||
table.insert(xml, [[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
table.insert(xml, [[<document type="freeswitch/xml">]]);
|
||||
table.insert(xml, [[ <section name="configuration">]]);
|
||||
table.insert(xml, [[ <configuration name="callcenter.conf" description="Call Center">]]);
|
||||
table.insert(xml, [[ <settings>]]);
|
||||
if #dsn_callcenter > 0 then
|
||||
table.insert(xml, [[ <param name="odbc-dsn" value="]]..dsn_callcenter..[["/>]]);
|
||||
elseif #dsn > 0 then
|
||||
table.insert(xml, [[ <param name="odbc-dsn" value="]]..database["switch"]..[["/>]]);
|
||||
end
|
||||
-- table.insert(xml, [[ <param name="dbname" value="]]..database_dir..[[/call_center.db"/>]]);
|
||||
table.insert(xml, [[ </settings>]]);
|
||||
|
||||
--write the queues
|
||||
table.insert(xml, [[ <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_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(" ", "-");
|
||||
|
||||
--start the xml
|
||||
table.insert(xml, [[ <queue name="]]..queue_uuid..[[" label="]]..queue_name..[[@]]..domain_name..[[">]]);
|
||||
table.insert(xml, [[ <param name="strategy" value="]]..queue_strategy..[["/>]]);
|
||||
--set ringback
|
||||
queue_ringback = format_ringback(queue_moh_sound);
|
||||
table.insert(xml, [[ <param name="moh-sound" value="]]..queue_ringback..[["/>]]);
|
||||
if (queue_record_template ~= nil) then
|
||||
table.insert(xml, [[ <param name="record-template" value="]]..queue_record_template..[["/>]]);
|
||||
end
|
||||
if (queue_time_base_score ~= nil) then
|
||||
table.insert(xml, [[ <param name="time-base-score" value="]]..queue_time_base_score..[["/>]]);
|
||||
end
|
||||
if (queue_max_wait_time_with_no_agent ~= nil) then
|
||||
table.insert(xml, [[ <param name="max-wait-time" value="]]..queue_max_wait_time..[["/>]]);
|
||||
end
|
||||
if (queue_max_wait_time_with_no_agent ~= nil) then
|
||||
table.insert(xml, [[ <param name="max-wait-time-with-no-agent" value="]]..queue_max_wait_time_with_no_agent..[["/>]]);
|
||||
end
|
||||
if (queue_max_wait_time_with_no_agent_time_reached ~= nil) then
|
||||
table.insert(xml, [[ <param name="max-wait-time-with-no-agent-time-reached" value="]]..queue_max_wait_time_with_no_agent_time_reached..[["/>]]);
|
||||
end
|
||||
if (queue_tier_rules_apply ~= nil) then
|
||||
table.insert(xml, [[ <param name="tier-rules-apply" value="]]..queue_tier_rules_apply..[["/>]]);
|
||||
end
|
||||
if (queue_tier_rule_wait_second ~= nil) then
|
||||
table.insert(xml, [[ <param name="tier-rule-wait-second" value="]]..queue_tier_rule_wait_second..[["/>]]);
|
||||
end
|
||||
if (queue_tier_rule_wait_multiply_level ~= nil) then
|
||||
table.insert(xml, [[ <param name="tier-rule-wait-multiply-level" value="]]..queue_tier_rule_wait_multiply_level..[["/>]]);
|
||||
end
|
||||
if (queue_tier_rule_no_agent_no_wait ~= nil) then
|
||||
table.insert(xml, [[ <param name="tier-rule-no-agent-no-wait" value="]]..queue_tier_rule_no_agent_no_wait..[["/>]]);
|
||||
end
|
||||
if (queue_discard_abandoned_after ~= nil) then
|
||||
table.insert(xml, [[ <param name="discard-abandoned-after" value="]]..queue_discard_abandoned_after..[["/>]]);
|
||||
end
|
||||
if (queue_abandoned_resume_allowed ~= nil) then
|
||||
table.insert(xml, [[ <param name="abandoned-resume-allowed" value="]]..queue_abandoned_resume_allowed..[["/>]]);
|
||||
end
|
||||
if (queue_announce_sound ~= nil) then
|
||||
table.insert(xml, [[ <param name="announce-sound" value="]]..queue_announce_sound..[["/>]]);
|
||||
end
|
||||
if (queue_announce_frequency ~= nil) then
|
||||
table.insert(xml, [[ <param name="announce-frequency" value="]]..queue_announce_frequency..[["/>]]);
|
||||
end
|
||||
table.insert(xml, [[ </queue>]]);
|
||||
|
||||
--increment the value of x
|
||||
x = x + 1;
|
||||
end)
|
||||
table.insert(xml, [[ </queues>]]);
|
||||
|
||||
--get the agents
|
||||
table.insert(xml, [[ <agents>]]);
|
||||
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;
|
||||
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;
|
||||
|
||||
--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=custom/press_1_to_accept_this_call.wav,group_confirm_key=1,group_confirm_read_timeout=2000,leg_timeout="..agent_call_timeout;
|
||||
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..",sip_h_caller_destination=${caller_destination}}"..agent_contact;
|
||||
else
|
||||
--add the call_timeout and confirm
|
||||
tmp_pos = string.find(agent_contact, "}");
|
||||
tmp_first = string.sub(agent_contact, 0, tmp_pos);
|
||||
tmp_last = string.sub(agent_contact, tmp_pos);
|
||||
agent_contact = tmp_first..',call_timeout='..agent_call_timeout..tmp_last;
|
||||
agent_contact = "{"..confirm..",call_timeout="..agent_call_timeout..",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);
|
||||
last = string.sub(agent_contact, tmp_pos);
|
||||
agent_contact = first..[[,sip_h_caller_destination=${caller_destination},call_timeout=]]..agent_call_timeout..last;
|
||||
else
|
||||
--the string has the call timeout
|
||||
agent_contact = agent_contact;
|
||||
end
|
||||
else
|
||||
--found
|
||||
pos = string.find(agent_contact, "}");
|
||||
first = string.sub(agent_contact, 0, pos);
|
||||
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}call_timeout='..agent_call_timeout..last;
|
||||
else
|
||||
--add confirm
|
||||
agent_contact = tmp_first..',sip_h_caller_destination=${caller_destination},'..confirm..tmp_last;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--build the xml string
|
||||
table.insert(xml, [[ <agent ]]);
|
||||
table.insert(xml, [[ name="]]..agent_uuid..[[" ]]);
|
||||
table.insert(xml, [[ label="]]..agent_name..[[@]]..domain_name..[[" ]]);
|
||||
table.insert(xml, [[ type="]]..agent_type..[[" ]]);
|
||||
table.insert(xml, [[ contact="]]..agent_contact..[[" ]]);
|
||||
table.insert(xml, [[ status="]]..agent_status..[[" ]]);
|
||||
if (agent_no_answer_delay_time ~= nil) then
|
||||
table.insert(xml, [[ no-answer-delay-time="]]..agent_no_answer_delay_time..[[" ]]);
|
||||
end
|
||||
if (agent_max_no_answer ~= nil) then
|
||||
table.insert(xml, [[ max-no-answer="]]..agent_max_no_answer..[[" ]]);
|
||||
end
|
||||
if (agent_wrap_up_time ~= nil) then
|
||||
table.insert(xml, [[ wrap-up-time="]]..agent_wrap_up_time..[[" ]]);
|
||||
end
|
||||
if (agent_reject_delay_time ~= nil) then
|
||||
table.insert(xml, [[ reject-delay-time="]]..agent_reject_delay_time..[[" ]]);
|
||||
end
|
||||
if (agent_busy_delay_time ~= nil) then
|
||||
table.insert(xml, [[ busy-delay-time="]]..agent_busy_delay_time..[[" ]]);
|
||||
end
|
||||
table.insert(xml, [[ />]]);
|
||||
end)
|
||||
table.insert(xml, [[ </agents>]]);
|
||||
|
||||
--get the tiers
|
||||
sql = "select * from v_call_center_tiers as t, v_domains as d ";
|
||||
sql = sql .. "where d.domain_uuid = t.domain_uuid; ";
|
||||
if (debug["sql"]) then
|
||||
freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "\n");
|
||||
end
|
||||
table.insert(xml, [[ <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;
|
||||
tier_level = row.tier_level;
|
||||
tier_position = row.tier_position;
|
||||
--build the xml
|
||||
table.insert(xml, [[ <tier ]]);
|
||||
table.insert(xml, [[ agent="]]..agent_uuid..[[" ]]);
|
||||
table.insert(xml, [[ queue="]]..queue_uuid..[[" ]]);
|
||||
table.insert(xml, [[ domain_name="]]..domain_name..[[" ]]);
|
||||
--table.insert(xml, [[ agent_name="]]..agent_name..[[" ]]);
|
||||
--table.insert(xml, [[ queue_name="]]..queue_name..[[" ]]);
|
||||
table.insert(xml, [[ level="]]..tier_level..[[" ]]);
|
||||
table.insert(xml, [[ position="]]..tier_position..[[" ]]);
|
||||
table.insert(xml, [[ />]]);
|
||||
end)
|
||||
table.insert(xml, [[ </tiers>]]);
|
||||
|
||||
--close the extension tag if it was left open
|
||||
table.insert(xml, [[ </configuration>]]);
|
||||
table.insert(xml, [[ </section>]]);
|
||||
table.insert(xml, [[</document>]]);
|
||||
XML_STRING = table.concat(xml, "\n");
|
||||
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
|
||||
@@ -0,0 +1,121 @@
|
||||
-- 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());
|
||||
|
||||
--set the xml array
|
||||
local xml = {}
|
||||
table.insert(xml, [[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
table.insert(xml, [[<document type="freeswitch/xml">]]);
|
||||
table.insert(xml, [[ <section name="configuration">]]);
|
||||
table.insert(xml, [[ <configuration name="conference.conf" description="Audio Conference">]]);
|
||||
|
||||
--start the conference controls
|
||||
table.insert(xml, [[ <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"];
|
||||
table.insert(xml, [[ <group name="]]..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"];
|
||||
table.insert(xml, [[ <control digits="]]..row["control_digits"]..[[" action="]]..row["control_action"]..[[" data="]]..row["control_data"]..[["/>]]);
|
||||
end);
|
||||
table.insert(xml, [[ </group>]]);
|
||||
end);
|
||||
table.insert(xml, [[ </caller-controls>]]);
|
||||
|
||||
|
||||
--start the conference profiles
|
||||
table.insert(xml, [[ <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"];
|
||||
table.insert(xml, [[ <profile name="]]..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"];
|
||||
table.insert(xml, [[ <param name="]]..row["profile_param_name"]..[[" value="]]..row["profile_param_value"]..[["/>]]);
|
||||
end);
|
||||
table.insert(xml, [[ </profile>]]);
|
||||
end);
|
||||
table.insert(xml, [[ </profiles>]]);
|
||||
|
||||
--set the xml array and then concatenate the array to a string
|
||||
table.insert(xml, [[ </configuration>]]);
|
||||
table.insert(xml, [[ </section>]]);
|
||||
table.insert(xml, [[</document>]]);
|
||||
XML_STRING = table.concat(xml, "\n");
|
||||
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
|
||||
@@ -0,0 +1,303 @@
|
||||
-- xml_handler.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2016-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.
|
||||
|
||||
--get the ivr name
|
||||
ivr_menu_uuid = params:getHeader("Menu-Name");
|
||||
|
||||
local log = require "resources.functions.log".ivr_menu
|
||||
|
||||
--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
|
||||
|
||||
--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 = [[SELECT * FROM v_ivr_menus
|
||||
WHERE ivr_menu_uuid = :ivr_menu_uuid
|
||||
AND ivr_menu_enabled = 'true' ]];
|
||||
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)
|
||||
domain_uuid = row["domain_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_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"];
|
||||
end);
|
||||
|
||||
local settings = Settings.new(dbh, domain_name, domain_uuid)
|
||||
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
|
||||
|
||||
--start the xml array
|
||||
local xml = {}
|
||||
table.insert(xml, [[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
table.insert(xml, [[<document type="freeswitch/xml">]]);
|
||||
table.insert(xml, [[ <section name="configuration">]]);
|
||||
table.insert(xml, [[ <configuration name="ivr.conf" description="IVR Menus">]]);
|
||||
table.insert(xml, [[ <menus>]]);
|
||||
table.insert(xml, [[ <menu name="]]..ivr_menu_uuid..[[" description="]]..ivr_menu_name..[[" ]]);
|
||||
table.insert(xml, [[ greet-long="]]..ivr_menu_greet_long..[[" ]]);
|
||||
table.insert(xml, [[ greet-short="]]..ivr_menu_greet_short..[[" ]]);
|
||||
table.insert(xml, [[ invalid-sound="]]..ivr_menu_invalid_sound..[[" ]]);
|
||||
table.insert(xml, [[ exit-sound="]]..ivr_menu_exit_sound..[[" ]]);
|
||||
table.insert(xml, [[ confirm-macro="]]..ivr_menu_confirm_macro..[[" ]]);
|
||||
table.insert(xml, [[ confirm-key="]]..ivr_menu_confirm_key..[[" ]]);
|
||||
table.insert(xml, [[ tts-engine="]]..ivr_menu_tts_engine..[[" ]]);
|
||||
table.insert(xml, [[ tts-voice="]]..ivr_menu_tts_voice..[[" ]]);
|
||||
table.insert(xml, [[ confirm-attempts="]]..ivr_menu_confirm_attempts..[[" ]]);
|
||||
table.insert(xml, [[ timeout="]]..ivr_menu_timeout..[[" ]]);
|
||||
table.insert(xml, [[ inter-digit-timeout="]]..ivr_menu_inter_digit_timeout..[[" ]]);
|
||||
table.insert(xml, [[ max-failures="]]..ivr_menu_max_failures..[[" ]]);
|
||||
table.insert(xml, [[ max-timeouts="]]..ivr_menu_max_timeouts..[[" ]]);
|
||||
table.insert(xml, [[ digit-len="]]..ivr_menu_digit_len..[[" ]]);
|
||||
table.insert(xml, [[ >]]);
|
||||
|
||||
--get the ivr menu options
|
||||
local sql = [[SELECT * FROM v_ivr_menu_options WHERE ivr_menu_uuid = :ivr_menu_uuid 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
|
||||
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
|
||||
table.insert(xml, [[ <entry action="]]..ivr_menu_option_action..[[" digits="]]..ivr_menu_option_digits..[[" param="]]..ivr_menu_option_param..[[" description="]]..ivr_menu_option_description..[["/>]]);
|
||||
end);
|
||||
|
||||
--direct dial
|
||||
if (ivr_menu_direct_dial == "true") then
|
||||
table.insert(xml, [[ <entry action="menu-exec-app" digits="/^(\d{2,11})$/" param="set ${cond(${user_exists id $1 ]]..domain_name..[[} == true ? user_exists=true : user_exists=false)}" description="direct dial"/>\n]]);
|
||||
table.insert(xml, [[ <entry action="menu-exec-app" digits="/^(\d{2,11})$/" param="playback ${cond(${user_exists} == true ? ]]..sound_prefix..[[ivr/ivr-call_being_transferred.wav : ]]..sound_prefix..[[ivr/ivr-that_was_an_invalid_entry.wav)}" description="direct dial"/>\n]]);
|
||||
table.insert(xml, [[ <entry action="menu-exec-app" digits="/^(\d{2,11})$/" param="transfer ${cond(${user_exists} == true ? $1 XML ]]..domain_name..[[)}" description="direct dial"/>\n]]);
|
||||
end
|
||||
|
||||
--close the extension tag if it was left open
|
||||
table.insert(xml, [[ </menu>]]);
|
||||
table.insert(xml, [[ </menus>]]);
|
||||
table.insert(xml, [[ </configuration>]]);
|
||||
table.insert(xml, [[ </section>]]);
|
||||
table.insert(xml, [[</document>]]);
|
||||
XML_STRING = table.concat(xml, "\n");
|
||||
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(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
|
||||
@@ -0,0 +1,150 @@
|
||||
|
||||
--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 = {}
|
||||
table.insert(xml, [[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
table.insert(xml, [[<document type="freeswitch/xml">]]);
|
||||
table.insert(xml, [[ <section name="configuration">]]);
|
||||
table.insert(xml, [[ <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..[["
|
||||
table.insert(xml, [[ <directory name="]]..name..[[" uuid="]]..row.music_on_hold_uuid..[[" path="]]..music_on_hold_path..[[">]]);
|
||||
table.insert(xml, [[ <param name="rate" value="]]..rate..[["/>]]);
|
||||
table.insert(xml, [[ <param name="shuffle" value="]]..row.music_on_hold_shuffle..[["/>]]);
|
||||
table.insert(xml, [[ <param name="channels" value="1"/>]]);
|
||||
table.insert(xml, [[ <param name="interval" value="20"/>]]);
|
||||
table.insert(xml, [[ <param name="timer-name" value="]]..timer_name..[["/>]]);
|
||||
if (chime_list ~= nil) then
|
||||
table.insert(xml, [[ <param name="chime-list" value="]]..chime_list..[["/>]]);
|
||||
end
|
||||
if (row.music_on_hold_chime_freq ~= nil) then
|
||||
table.insert(xml, [[ <param name="chime-freq" value="]]..row.music_on_hold_chime_freq..[["/>]]);
|
||||
end
|
||||
if (row.music_on_hold_chime_max ~= nil) then
|
||||
table.insert(xml, [[ <param name="chime-max" value="]]..row.music_on_hold_chime_max..[["/>]]);
|
||||
end
|
||||
table.insert(xml, [[ </directory>]]);
|
||||
|
||||
end)
|
||||
|
||||
--close the extension tag if it was left open
|
||||
table.insert(xml, [[ </configuration>]]);
|
||||
table.insert(xml, [[ </section>]]);
|
||||
table.insert(xml, [[</document>]]);
|
||||
XML_STRING = table.concat(xml, "\n");
|
||||
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
|
||||
@@ -0,0 +1,321 @@
|
||||
-- xml_handler.lua
|
||||
-- Part of FusionPBX
|
||||
-- Copyright (C) 2013 - 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.
|
||||
|
||||
--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 domain_uuid
|
||||
if (domain_uuid == nil) then
|
||||
--get the domain_uuid
|
||||
if (domain_name ~= nil) then
|
||||
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", "[xml_handler] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
|
||||
end
|
||||
dbh:query(sql, params, function(row)
|
||||
domain_uuid = row.domain_uuid;
|
||||
end);
|
||||
end
|
||||
end
|
||||
|
||||
--get the variables
|
||||
vars = trim(api:execute("global_getvar", ""));
|
||||
|
||||
--start the xml array
|
||||
local xml = {}
|
||||
table.insert(xml, [[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
table.insert(xml, [[<document type="freeswitch/xml">]]);
|
||||
table.insert(xml, [[ <section name="configuration">]]);
|
||||
table.insert(xml, [[ <configuration name="sofia.conf" description="sofia Endpoint">]]);
|
||||
table.insert(xml, [[ <global_settings>]]);
|
||||
table.insert(xml, [[ <param name="log-level" value="0"/>]]);
|
||||
--table.insert(xml, [[ <param name="auto-restart" value="false"/>]]);
|
||||
table.insert(xml, [[ <param name="debug-presence" value="0"/>]]);
|
||||
--table.insert(xml, [[ <param name="capture-server" value="udp:homer.domain.com:5060"/>]]);
|
||||
table.insert(xml, [[ </global_settings>]]);
|
||||
table.insert(xml, [[ <profiles>]]);
|
||||
|
||||
--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;
|
||||
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
|
||||
table.insert(xml, [[ </settings>]]);
|
||||
table.insert(xml, [[ </profile>]]);
|
||||
end
|
||||
table.insert(xml, [[ <profile name="]]..sip_profile_name..[[">]]);
|
||||
table.insert(xml, [[ <aliases>]]);
|
||||
table.insert(xml, [[ </aliases>]]);
|
||||
table.insert(xml, [[ <gateways>]]);
|
||||
--table.insert(xml, [[ <X-PRE-PROCESS cmd="include" data="]]..sip_profile_name..[[/*.xml"/>]]);
|
||||
|
||||
--get the gateways
|
||||
sql = "select * from v_gateways as g, v_domains as d ";
|
||||
sql = sql .. "where g.profile = :profile ";
|
||||
sql = sql .. "and g.enabled = 'true' ";
|
||||
sql = sql .. "and (g.domain_uuid = d.domain_uuid or g.domain_uuid is null) ";
|
||||
sql = sql .. "and (g.hostname = :hostname or g.hostname is null or g.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)
|
||||
table.insert(xml, [[ <gateway name="]] .. string.lower(field.gateway_uuid) .. [[">]]);
|
||||
|
||||
if (string.len(field.username) > 0) then
|
||||
table.insert(xml, [[ <param name="username" value="]] .. field.username .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.distinct_to) > 0) then
|
||||
table.insert(xml, [[ <param name="distinct-to" value="]] .. field.distinct_to .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.auth_username) > 0) then
|
||||
table.insert(xml, [[ <param name="auth-username" value="]] .. field.auth_username .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.password) > 0) then
|
||||
table.insert(xml, [[ <param name="password" value="]] .. field.password .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.realm) > 0) then
|
||||
table.insert(xml, [[ <param name="realm" value="]] .. field.realm .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.from_user) > 0) then
|
||||
table.insert(xml, [[ <param name="from-user" value="]] .. field.from_user .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.from_domain) > 0) then
|
||||
table.insert(xml, [[ <param name="from-domain" value="]] .. field.from_domain .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.proxy) > 0) then
|
||||
table.insert(xml, [[ <param name="proxy" value="]] .. field.proxy .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.register_proxy) > 0) then
|
||||
table.insert(xml, [[ <param name="register-proxy" value="]] .. field.register_proxy .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.outbound_proxy) > 0) then
|
||||
table.insert(xml, [[ <param name="outbound-proxy" value="]] .. field.outbound_proxy .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.expire_seconds) > 0) then
|
||||
table.insert(xml, [[ <param name="expire-seconds" value="]] .. field.expire_seconds .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.register) > 0) then
|
||||
table.insert(xml, [[ <param name="register" value="]] .. field.register .. [["/>]]);
|
||||
end
|
||||
|
||||
if (field.register_transport) then
|
||||
if (field.register_transport == "udp") then
|
||||
table.insert(xml, [[ <param name="register-transport" value="udp"/>]]);
|
||||
elseif (field.register_transport == "tcp") then
|
||||
table.insert(xml, [[ <param name="register-transport" value="tcp"/>]]);
|
||||
elseif (field.register_transport == "tls") then
|
||||
table.insert(xml, [[ <param name="register-transport" value="tls"/>]]);
|
||||
table.insert(xml, [[ <param name="contact-params" value="transport=tls"/>]]);
|
||||
else
|
||||
table.insert(xml, [[ <param name="register-transport" value="udp"/>]]);
|
||||
end
|
||||
end
|
||||
|
||||
if (string.len(field.retry_seconds) > 0) then
|
||||
table.insert(xml, [[ <param name="retry-seconds" value="]] .. field.retry_seconds .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.extension) > 0) then
|
||||
table.insert(xml, [[ <param name="extension" value="]] .. field.extension .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.ping) > 0) then
|
||||
table.insert(xml, [[ <param name="ping" value="]] .. field.ping .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.context) > 0) then
|
||||
table.insert(xml, [[ <param name="context" value="]] .. field.context .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.caller_id_in_from) > 0) then
|
||||
table.insert(xml, [[ <param name="caller-id-in-from" value="]] .. field.caller_id_in_from .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.supress_cng) > 0) then
|
||||
table.insert(xml, [[ <param name="supress-cng" value="]] .. field.supress_cng .. [["/>]]);
|
||||
end
|
||||
if (string.len(field.extension_in_contact) > 0) then
|
||||
table.insert(xml, [[ <param name="extension-in-contact" value="]] .. field.extension_in_contact .. [["/>]]);
|
||||
end
|
||||
table.insert(xml, [[ <variables>]]);
|
||||
if (string.len(field.sip_cid_type) > 0) then
|
||||
table.insert(xml, [[ <variable name="sip_cid_type" value="]] .. field.sip_cid_type .. [["/>]]);
|
||||
end
|
||||
table.insert(xml, [[ </variables>]]);
|
||||
table.insert(xml, [[ </gateway>]]);
|
||||
end)
|
||||
|
||||
table.insert(xml, [[ </gateways>]]);
|
||||
table.insert(xml, [[ <domains>]]);
|
||||
|
||||
--add sip profile domain: name, alias, and parse
|
||||
table.insert(xml, [[ <!-- indicator to parse the directory for domains with parse="true" to get gateways-->]]);
|
||||
table.insert(xml, [[ <!--<domain name="$${domain}" parse="true"/>-->]]);
|
||||
table.insert(xml, [[ <!-- indicator to parse the directory for domains with parse="true" to get gateways and alias every domain to this profile -->]]);
|
||||
table.insert(xml, [[ <!--<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
|
||||
table.insert(xml, [[ <domain name="]] .. name .. [[" alias="]] .. alias .. [[" parse="]] .. parse .. [["/>]]);
|
||||
end);
|
||||
|
||||
table.insert(xml, [[ </domains>]]);
|
||||
table.insert(xml, [[ <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
|
||||
|
||||
--set the parameters
|
||||
if (sip_profile_setting_name) then
|
||||
table.insert(xml, [[ <param name="]]..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
|
||||
table.insert(xml, [[ </settings>]]);
|
||||
table.insert(xml, [[ </profile>]]);
|
||||
profile_tag_status = "close";
|
||||
end
|
||||
table.insert(xml, [[ </profiles>]]);
|
||||
table.insert(xml, [[ </configuration>]]);
|
||||
table.insert(xml, [[ </section>]]);
|
||||
table.insert(xml, [[</document>]]);
|
||||
XML_STRING = table.concat(xml, "\n");
|
||||
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
|
||||
@@ -0,0 +1,141 @@
|
||||
-- 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.
|
||||
|
||||
--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 = {}
|
||||
table.insert(xml, [[<?xml version="1.0" encoding="UTF-8" standalone="no"?>]]);
|
||||
table.insert(xml, [[<document type="freeswitch/xml">]]);
|
||||
table.insert(xml, [[ <section name="configuration">]]);
|
||||
table.insert(xml, [[ <configuration name="translate.conf" description="Number Translation Rules" autogenerated="true">]]);
|
||||
table.insert(xml, [[ <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
|
||||
table.insert(xml, [[ <profile name="]]..row.number_translation_name..[[" description="]]..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
|
||||
table.insert(xml, [[ <rule regex="]] .. field.number_translation_detail_regex .. [[" replace="]] .. field.number_translation_detail_replace .. [[" />]]);
|
||||
end
|
||||
end)
|
||||
|
||||
--list close tag
|
||||
table.insert(xml, [[ </profile>]]);
|
||||
|
||||
end)
|
||||
|
||||
--close the extension tag if it was left open
|
||||
table.insert(xml, [[ </profiles>]]);
|
||||
table.insert(xml, [[ </configuration>]]);
|
||||
table.insert(xml, [[ </section>]]);
|
||||
table.insert(xml, [[</document>]]);
|
||||
XML_STRING = table.concat(xml, "\n");
|
||||
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
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user