diff --git a/app/switch/resources/conf/languages/en/vm/sounds.xml b/app/switch/resources/conf/languages/en/vm/sounds.xml
index 250cb96e1d..14866b7383 100644
--- a/app/switch/resources/conf/languages/en/vm/sounds.xml
+++ b/app/switch/resources/conf/languages/en/vm/sounds.xml
@@ -104,6 +104,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/switch/resources/conf/languages/en/vm/voicemail.xml b/app/switch/resources/conf/languages/en/vm/voicemail.xml
index 0daec58637..3218186ccc 100644
--- a/app/switch/resources/conf/languages/en/vm/voicemail.xml
+++ b/app/switch/resources/conf/languages/en/vm/voicemail.xml
@@ -65,6 +65,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -96,6 +121,17 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/switch/resources/scripts/app/voicemail/index.lua b/app/switch/resources/scripts/app/voicemail/index.lua
index ebbe781fef..253bfcb43b 100644
--- a/app/switch/resources/scripts/app/voicemail/index.lua
+++ b/app/switch/resources/scripts/app/voicemail/index.lua
@@ -246,6 +246,22 @@
end
end
+ use_deletion_queue = 'false';
+ if (settings['voicemail']['use_deletion_queue'] ~= nil) then
+ if (settings['voicemail']['use_deletion_queue']['boolean'] ~= nil) then
+ use_deletion_queue = settings['voicemail']['use_deletion_queue']['boolean'];
+ end
+ end
+
+ deletion_queue_retention_hours = "24";
+ if (settings['voicemail'] ~= nil) then
+ if (settings['voicemail']['deletion_queue_retention_hours'] ~= nil) then
+ if (settings['voicemail']['deletion_queue_retention_hours']['numeric'] ~= nil) then
+ deletion_queue_retention_hours = settings['voicemail']['deletion_queue_retention_hours']['numeric'];
+ end
+ end
+ end
+
end
if (settings['voicemail']) then
@@ -363,6 +379,7 @@
require "app.voicemail.resources.functions.mwi_notify";
require "app.voicemail.resources.functions.blf_notify";
require "app.voicemail.resources.functions.tutorial";
+ require "app.voicemail.resources.functions.remove_deleted_messages";
--send a message waiting event
if (voicemail_action == "mwi") then
diff --git a/app/switch/resources/scripts/app/voicemail/resources/functions/listen_to_recording.lua b/app/switch/resources/scripts/app/voicemail/resources/functions/listen_to_recording.lua
index 635e160b10..3fc0cfd5f5 100644
--- a/app/switch/resources/scripts/app/voicemail/resources/functions/listen_to_recording.lua
+++ b/app/switch/resources/scripts/app/voicemail/resources/functions/listen_to_recording.lua
@@ -233,7 +233,11 @@
--post listen options
if (session:ready()) then
if (string.len(dtmf_digits) == 0) then
- dtmf_digits = session:playAndGetDigits(1, 1, max_tries, digit_timeout, "#", "phrase:voicemail_listen_file_options:1:2:3:5:7:8:9:0", "", "^[\\d\\*#]$");
+ if (use_deletion_queue == "true" and message_status == "deleted") then
+ dtmf_digits = session:playAndGetDigits(1, 1, max_tries, digit_timeout, "#", "phrase:voicemail_listen_file_options:deleted:1:2:3:5:7:8:9:0", "", "^[\\d\\*#]$");
+ else
+ dtmf_digits = session:playAndGetDigits(1, 1, max_tries, digit_timeout, "#", "phrase:voicemail_listen_file_options:1:2:3:5:7:8:9:0", "", "^[\\d\\*#]$");
+ end
end
end
@@ -264,7 +268,12 @@
message_saved(voicemail_id, uuid);
return_call(caller_id_number);
elseif (dtmf_digits == "7") then
- delete_recording(voicemail_id, uuid);
+ if (use_deletion_queue == "true" and message_status ~= "deleted") then
+ message_saved(voicemail_id, uuid, "deleted");
+ session:execute("playback", "phrase:voicemail_ack:deleted");
+ else
+ delete_recording(voicemail_id, uuid);
+ end
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
diff --git a/app/switch/resources/scripts/app/voicemail/resources/functions/main_menu.lua b/app/switch/resources/scripts/app/voicemail/resources/functions/main_menu.lua
index c69593b248..ea289054f1 100644
--- a/app/switch/resources/scripts/app/voicemail/resources/functions/main_menu.lua
+++ b/app/switch/resources/scripts/app/voicemail/resources/functions/main_menu.lua
@@ -38,6 +38,11 @@
session:execute("sleep", "1000");
end
+ --remove deleted messages in queue
+ if (use_deletion_queue == "true") then
+ remove_deleted_messages(voicemail_id);
+ end
+
--new voicemail count
if (session:ready()) then
local sql = [[SELECT count(*) as new_messages FROM v_voicemail_messages
@@ -70,6 +75,24 @@
dtmf_digits = session:playAndGetDigits(0, 1, 1, 300, "#", "phrase:voicemail_saved_message_count:" .. saved_messages .. ":saved", "", "\\d+");
end
end
+ --deleted messages
+ if (session:ready()) then
+ deleted_messages = 0;
+ if (string.len(dtmf_digits) == 0 and use_deletion_queue == "true") then
+ sql = [[SELECT count(*) as deleted_messages FROM v_voicemail_messages
+ WHERE domain_uuid = :domain_uuid
+ AND voicemail_uuid = :voicemail_uuid
+ AND message_status = 'deleted' ]];
+ 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)
+ deleted_messages = row["deleted_messages"];
+ end);
+ dtmf_digits = session:playAndGetDigits(0, 1, 1, 300, "#", "phrase:voicemail_deleted_message_count:" .. deleted_messages .. ":deleted", "", "\\d+");
+ end
+ end
--to listen to new message
if (session:ready() and new_messages ~= '0') then
@@ -83,6 +106,12 @@
dtmf_digits = session:playAndGetDigits(0, 1, 1, 100, "#", "phrase:voicemail_main_menu:saved:2", "", "\\d+");
end
end
+ --deleted messages
+ if (session:ready() and deleted_messages ~= '0') then
+ if (string.len(dtmf_digits) == 0) then
+ dtmf_digits = session:playAndGetDigits(0, 1, 1, 100, "#", "phrase:voicemail_main_menu:deleted:3", "", "\\d+");
+ end
+ end
--for advanced options
if (session:ready()) then
if (string.len(dtmf_digits) == 0) then
@@ -101,6 +130,8 @@
menu_messages("new");
elseif (dtmf_digits == "2") then
menu_messages("saved");
+ elseif (dtmf_digits == "3" and use_deletion_queue == "true") then
+ menu_messages("deleted");
elseif (dtmf_digits == "5") then
timeouts = 0;
advanced();
diff --git a/app/switch/resources/scripts/app/voicemail/resources/functions/menu_messages.lua b/app/switch/resources/scripts/app/voicemail/resources/functions/menu_messages.lua
index c106823065..e17990a8aa 100644
--- a/app/switch/resources/scripts/app/voicemail/resources/functions/menu_messages.lua
+++ b/app/switch/resources/scripts/app/voicemail/resources/functions/menu_messages.lua
@@ -38,7 +38,7 @@
--session:flushDigits();
--set the message number
message_number = 0;
- --message_status new,saved
+ --message_status new,any
if (session:ready()) then
if (voicemail_id ~= nil) then
--get the voicemail_id
@@ -58,8 +58,8 @@
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' ]];
+ else
+ sql = sql .. "AND message_status = '" .. message_status .. "' ";
end
sql = sql .. [[ORDER BY created_epoch ]]..message_order;
local params = {domain_uuid = domain_uuid, voicemail_uuid = voicemail_uuid};
diff --git a/app/switch/resources/scripts/app/voicemail/resources/functions/message_saved.lua b/app/switch/resources/scripts/app/voicemail/resources/functions/message_saved.lua
index 15bec62635..d48ad0f472 100644
--- a/app/switch/resources/scripts/app/voicemail/resources/functions/message_saved.lua
+++ b/app/switch/resources/scripts/app/voicemail/resources/functions/message_saved.lua
@@ -24,11 +24,15 @@
-- POSSIBILITY OF SUCH DAMAGE.
--save the message
- function message_saved(voicemail_id, uuid)
+ function message_saved(voicemail_id, uuid, status)
--clear the dtmf
dtmf_digits = '';
--flush dtmf digits from the input buffer
session:flushDigits();
+ --set default status
+ if (status == nil) then
+ status = 'saved';
+ end
--get the voicemail_uuid
local sql = [[SELECT * FROM v_voicemails
WHERE domain_uuid = :domain_uuid
@@ -38,18 +42,20 @@
db_voicemail_uuid = row["voicemail_uuid"];
end);
--delete from the database
- sql = [[UPDATE v_voicemail_messages SET message_status = 'saved'
+ sql = [[UPDATE v_voicemail_messages
+ SET message_status = :status,
+ update_date = now()
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};
+ params = {status = status, 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");
+ freeswitch.consoleLog("notice", "[voicemail]["..status.."] id: " .. voicemail_id .. " message: "..uuid.."\n");
end
--check the message waiting status
message_waiting(voicemail_id, domain_uuid);
diff --git a/app/switch/resources/scripts/app/voicemail/resources/functions/remove_deleted_messages.lua b/app/switch/resources/scripts/app/voicemail/resources/functions/remove_deleted_messages.lua
new file mode 100644
index 0000000000..1e8a94bc27
--- /dev/null
+++ b/app/switch/resources/scripts/app/voicemail/resources/functions/remove_deleted_messages.lua
@@ -0,0 +1,92 @@
+-- Part of FusionPBX
+-- Copyright (C) 2013-2025
+-- 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 all deleted messages for a single mailbox
+ function remove_deleted_messages(voicemail_id)
+ --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);
+ if (debug["sql"]) then
+ freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
+ end
+
+ --get messages
+ local sql = [[SELECT * FROM v_voicemail_messages
+ WHERE message_status = 'deleted' ]]
+ sql = sql .. "AND (update_date + interval '" .. deletion_queue_retention_hours .. " hours') < now() "
+ sql = sql .. [[AND voicemail_uuid = :voicemail_uuid
+ AND domain_uuid = :domain_uuid]];
+ local params = {voicemail_uuid = db_voicemail_uuid, domain_uuid = domain_uuid}
+ messages_to_delete = {};
+ dbh:query(sql, params, function(row)
+ table.insert(messages_to_delete, row);
+ end);
+ if (debug["sql"]) then
+ freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "; params:" .. json.encode(params) .. "\n");
+ end
+
+ --flush dtmf digits from the input buffer
+ session:flushDigits();
+
+ total_messages = #messages_to_delete;
+ message_number = 1;
+ while message_number <= total_messages do
+ local message_row = messages_to_delete[message_number];
+ local uuid = message_row["voicemail_message_uuid"];
+
+ --delete the file
+ os.remove(voicemail_dir.."/"..voicemail_id.."/intro_msg_"..uuid.."."..vm_message_ext);
+ 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
+ end
+
+
+ --clear the variable
+ db_voicemail_uuid = '';
+ messages_to_delete = {};
+
+ --flush dtmf digits from the input buffer
+ session:flushDigits();
+
+end
diff --git a/app/switch/resources/scripts/app/voicemail/resources/scripts/delete_messages.lua b/app/switch/resources/scripts/app/voicemail/resources/scripts/delete_messages.lua
new file mode 100644
index 0000000000..4deef47da6
--- /dev/null
+++ b/app/switch/resources/scripts/app/voicemail/resources/scripts/delete_messages.lua
@@ -0,0 +1,120 @@
+-- Part of FusionPBX
+-- Copyright (C) 2013-2025 Mark J Crane
+-- 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
+ Database = require "resources.functions.database";
+ dbh = Database.new('system');
+
+--get settings
+ require "resources.functions.settings";
+ settings = settings();
+
+--set deletion_queue_retention_hours
+ if (settings['voicemail'] ~= nil) then
+ if (settings['voicemail']['deletion_queue_retention_hours'] ~= nil) then
+ if (settings['voicemail']['deletion_queue_retention_hours']['numeric'] ~= nil) then
+ retention_hours = settings['voicemail']['deletion_queue_retention_hours']['numeric'];
+ else
+ retention_hours = "24";
+ end
+ end
+ end
+
+--set the voicemail_dir
+ if (settings['switch'] ~= nil) then
+ if (settings['switch']['voicemail'] ~= nil) then
+ if (settings['switch']['voicemail']['dir'] ~= nil) then
+ voicemail_dir = settings['switch']['voicemail']['dir'].."/default";
+ end
+ end
+ end
+
+--get the voicemail extension
+ sql = "SELECT * FROM v_vars WHERE var_category = 'Defaults' AND var_name = 'vm_message_ext' AND var_enabled = 'true'";
+ dbh:query(sql, function(row)
+ vm_message_ext = row["var_value"];
+ end);
+ if (vm_message_ext == nil) then
+ vm_message_ext = "wav";
+ end
+
+--get messages
+ sql = "SELECT * FROM v_voicemail_messages WHERE message_status = 'deleted' AND (update_date + interval '" .. retention_hours .. " hours') < now()";
+ messages_to_delete = {};
+ dbh:query(sql, function(row)
+ table.insert(messages_to_delete, row);
+ end);
+
+--delete the messages
+ total_messages = #messages_to_delete;
+ message_number = 1;
+ while message_number <= total_messages do
+ local message_row = messages_to_delete[message_number];
+ local uuid = message_row["voicemail_message_uuid"];
+
+ --get domain_name
+ sql = [[SELECT * from v_domains
+ WHERE domain_uuid = :domain_uuid
+ ]];
+ local params = {domain_uuid = message_row["domain_uuid"]};
+ dbh:query(sql, params, function(row)
+ domain_name = row["domain_name"];
+ end);
+
+ --get voicemail_id
+ sql = [[SELECT * from v_voicemails
+ WHERE domain_uuid = :domain_uuid
+ AND voicemail_uuid = :voicemail_uuid
+ ]];
+ local params = {domain_uuid = message_row["domain_uuid"], voicemail_uuid = message_row["voicemail_uuid"]};
+ dbh:query(sql, params, function(row)
+ voicemail_id = row["voicemail_id"];
+ end);
+
+ --delete the file
+ os.remove(voicemail_dir.."/"..domain_name.."/"..voicemail_id.."/intro_msg_"..uuid.."."..vm_message_ext);
+ os.remove(voicemail_dir.."/"..domain_name.."/"..voicemail_id.."/intro_"..uuid.."."..vm_message_ext);
+ os.remove(voicemail_dir.."/"..domain_name.."/"..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]];
+ local params = {
+ domain_uuid = message_row["domain_uuid"],
+ voicemail_uuid = message_row["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
+
+ end
\ No newline at end of file
diff --git a/app/voicemails/app_config.php b/app/voicemails/app_config.php
index a34a4091f2..11d6f974b0 100644
--- a/app/voicemails/app_config.php
+++ b/app/voicemails/app_config.php
@@ -401,6 +401,22 @@
$apps[$x]['default_settings'][$y]['default_setting_value'] = "90";
$apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
$apps[$x]['default_settings'][$y]['default_setting_description'] = "Number of days maintenance application will retain files.";
+ $y++;
+ $apps[$x]['default_settings'][$y]['default_setting_uuid'] = "79d05433-a7ab-4641-ae5d-6eb7810eb560";
+ $apps[$x]['default_settings'][$y]['default_setting_category'] = "voicemail";
+ $apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "use_deletion_queue";
+ $apps[$x]['default_settings'][$y]['default_setting_name'] = "boolean";
+ $apps[$x]['default_settings'][$y]['default_setting_value'] = "false";
+ $apps[$x]['default_settings'][$y]['default_setting_enabled'] = "false";
+ $apps[$x]['default_settings'][$y]['default_setting_description'] = "Instead of deleting voicemails right away when pressing 7; queue them for deletion";
+ $y++;
+ $apps[$x]['default_settings'][$y]['default_setting_uuid'] = "b06cc9df-379e-4b45-8bda-d2d431506317";
+ $apps[$x]['default_settings'][$y]['default_setting_category'] = "voicemail";
+ $apps[$x]['default_settings'][$y]['default_setting_subcategory'] = "deletion_queue_retention_hours";
+ $apps[$x]['default_settings'][$y]['default_setting_name'] = "numeric";
+ $apps[$x]['default_settings'][$y]['default_setting_value'] = "24";
+ $apps[$x]['default_settings'][$y]['default_setting_enabled'] = "true";
+ $apps[$x]['default_settings'][$y]['default_setting_description'] = "Number of hours the voicemail deletion queue will retain deleted voicemails";
//schema details
$y=0;
$apps[$x]['db'][$y]['table']['name'] = "v_voicemails";
@@ -735,4 +751,4 @@
$apps[$x]['db'][$y]['fields'][$z]['type']['mysql'] = "char(36)";
$apps[$x]['db'][$y]['fields'][$z]['description']['en-us'] = "";
-?>
\ No newline at end of file
+?>