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 +?>