-- voicemail.lua -- Part of FusionPBX -- Copyright (C) 2013 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. --set default values min_digits = 1; max_digits = 8; max_tries = 3; max_timeouts = 3; digit_timeout = 3000; --direct dial direct_dial = {} direct_dial["enabled"] = "true"; direct_dial["max_digits"] = 4; --debug debug["info"] = false; debug["sql"] = false; --get the argv values script_name = argv[0]; voicemail_action = argv[1]; --starting values dtmf_digits = ''; timeouts = 0; password_tries = 0; --include the lua script scripts_dir = string.sub(debug.getinfo(1).source,2,string.len(debug.getinfo(1).source)-(string.len(argv[0])+1)); include = assert(loadfile(scripts_dir .. "/resources/config.lua")); include(); --connect to the database --ODBC - data source name if (dsn_name) then dbh = freeswitch.Dbh(dsn_name,dsn_username,dsn_password); end --FreeSWITCH core db handler if (db_type == "sqlite") then dbh = freeswitch.Dbh("core:"..db_path.."/"..db_name); end --set the api api = freeswitch.API(); --if the session exists if (session ~= nil) then --answer the session if (session:ready()) then session:answer(); end --set the callback function if (session:ready()) then session:setVariable("playback_terminators", "#"); session:setInputCallback("on_dtmf", ""); end --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"); base_dir = session:getVariable("base_dir"); destination_number = session:getVariable("destination_number"); caller_id_name = session:getVariable("caller_id_name"); caller_id_number = session:getVariable("caller_id_number"); skip_instructions = session:getVariable("skip_instructions"); skip_greeting = session:getVariable("skip_greeting"); vm_message_ext = session:getVariable("vm_message_ext"); if (not vm_message_ext) then vm_message_ext = 'wav'; end --set the sounds path for the language, dialect and voice default_language = session:getVariable("default_language"); default_dialect = session:getVariable("default_dialect"); default_voice = session:getVariable("default_voice"); if (not default_language) then default_language = 'en'; end if (not default_dialect) then default_dialect = 'us'; end if (not default_voice) then default_voice = 'callie'; end --get the domain_uuid domain_uuid = session:getVariable("domain_uuid"); if (domain_uuid == nil) then --get the domain_uuid if (domain_name ~= nil) then sql = "SELECT domain_uuid FROM v_domains "; sql = sql .. "WHERE domain_name = '" .. domain_name .. "' "; if (debug["sql"]) then freeswitch.consoleLog("notice", "[xml_handler] SQL: " .. sql .. "\n"); end status = dbh:query(sql, function(rows) domain_uuid = rows["domain_uuid"]; end); end end domain_uuid = string.lower(domain_uuid); --set the voicemail_dir voicemail_dir = base_dir.."/storage/voicemail/default/"..domain_name; if (debug["info"]) then freeswitch.consoleLog("notice", "[voicemail] voicemail_dir: " .. voicemail_dir .. "\n"); end --get the voicemail settings if (voicemail_id ~= nil) then if (session:ready()) then --get the information from the database sql = [[SELECT * FROM v_voicemails WHERE domain_uuid = ']] .. domain_uuid ..[[' AND voicemail_id = ']] .. voicemail_id ..[[' AND voicemail_enabled = 'true' ]]; if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end status = dbh:query(sql, 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); --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 end end end --check if a file exists function file_exists(name) local f=io.open(name,"r") if f~=nil then io.close(f) return true else return false end end --add the explode function function explode ( seperator, str ) local pos, arr = 0, {} for st, sp in function() return string.find( str, seperator, pos, true ) end do -- for each divider found table.insert( arr, string.sub( str, pos, st-1 ) ) -- attach chars left of current divider pos = sp + 1 -- jump past current divider end table.insert( arr, string.sub( str, pos ) ) -- attach chars right of last divider return arr end --format seconds to 00:00:00 function format_seconds(seconds) local seconds = tonumber(seconds); if seconds == 0 then return "00:00:00"; else hours = string.format("%02.f", math.floor(seconds/3600)); minutes = string.format("%02.f", math.floor(seconds/60 - (hours*60))); seconds = string.format("%02.f", math.floor(seconds - hours*3600 - minutes *60)); return string.format("%02d:%02d:%02d", hours, minutes, seconds); end end --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 (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 --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 --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 sql = [[SELECT * FROM v_voicemails WHERE domain_uuid = ']] .. domain_uuid ..[[' AND voicemail_id = ']] .. voicemail_id ..[[' AND voicemail_enabled = 'true' ]]; if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end status = dbh:query(sql, 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 --please enter your password followed by pound dtmf_digits = ''; password = macro(session, "voicemail_password", 20, 5000, ''); --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 --check the voicemail password function change_password(voicemail_id) if (session:ready()) then --flush dtmf digits from the input buffer session:flushDigits(); --please enter your password followed by pound dtmf_digits = ''; password = macro(session, "password_new", 20, 5000, ''); --update the voicemail password sql = [[UPDATE v_voicemails set voicemail_password = ']] .. password ..[[' WHERE domain_uuid = ']] .. domain_uuid ..[[' AND voicemail_id = ']] .. voicemail_id ..[[' AND voicemail_enabled = 'true' ]]; if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end dbh:query(sql); --has been changed to dtmf_digits = ''; macro(session, "password_changed", 20, 3000, password); --advanced menu timeouts = 0; advanced(); end end --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="voicemail/vm-enter_id.wav"}); table.insert(actions, {app="streamFile",data="digits/pound.wav"}); end --Please enter your id followed by if (name == "voicemail_password") then table.insert(actions, {app="streamFile",data="voicemail/vm-enter_pass.wav"}); table.insert(actions, {app="streamFile",data="digits/pound.wav"}); 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 table.insert(actions, {app="say.number.iterated",data=voicemail_id}); 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="voicemail/vm-you_have.wav"}); table.insert(actions, {app="say.number.pronounced",data=param}); table.insert(actions, {app="streamFile",data="voicemail/vm-new.wav"}); if (param == "1") then table.insert(actions, {app="streamFile",data="voicemail/vm-message.wav"}); else table.insert(actions, {app="streamFile",data="voicemail/vm-messages.wav"}); end end --You have zero saved messages if (name == "saved_messages") then table.insert(actions, {app="streamFile",data="voicemail/vm-you_have.wav"}); table.insert(actions, {app="say.number.pronounced",data=param}); table.insert(actions, {app="streamFile",data="voicemail/vm-saved.wav"}); if (param == "1") then table.insert(actions, {app="streamFile",data="voicemail/vm-message.wav"}); else table.insert(actions, {app="streamFile",data="voicemail/vm-messages.wav"}); end 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;%(1000, 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 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 --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 session:streamFile(sounds_dir.."/"..default_language.."/"..default_dialect.."/"..default_voice.."/"..row.data); 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 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 --play the greeting function play_greeting() --voicemail prompt if (skip_greeting == "true") then --skip the greeting else if (session:ready()) then dtmf_digits = ''; if (string.len(greeting_id) > 0) then --play the custom greeting session:streamFile(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav"); session:streamFile("silence_stream://200"); else --play the default greeting dtmf_digits = macro(session, "person_not_available_record_message", 1, 200); end end end end --save the recording function record_message() --record your message at the tone press any key or stop talking to end the recording if (skip_greeting == "true") then --skip the greeting else if (string.len(dtmf_digits) == 0) then dtmf_digits = macro(session, "record_message", 1, 100); end end --direct dial 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"], "#", 5000); end end end if (session:ready()) then freeswitch.consoleLog("notice", "[voicemail] dtmf_digits: " .. string.sub(dtmf_digits, 0, 1) .. "\n"); if (dtmf_digits == "*") then --check the voicemail password check_password(voicemail_id, password_tries); --send to the main menu timeouts = 0; main_menu(); elseif (string.sub(dtmf_digits, 0, 1) == "*") then --do not allow dialing numbers prefixed with * session:hangup(); else session:transfer(dtmf_digits, "XML", context); 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) max_len_seconds = 30; silence_threshold = 30; silence_seconds = 5; os.execute("mkdir -p " .. voicemail_dir.."/"..voicemail_id); result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext, max_len_seconds, silence_threshold, silence_seconds); --session:execute("record", voicemail_dir.."/"..uuid.." 180 200"); --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 minmal 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 --record message menu function record_menu(type, file) 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(file); --session:streamFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext); --record menu 1 listen to the recording, 2 save the recording, 3 re-record record_menu(type, file); 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 advanced(); end if (type == "name") then advanced(); 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 record_greeting(); end if (type == "name") then record_name(); end elseif (dtmf_digits == "*") then --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, file); else if (type == "message") then macro(session, "goodbye", 1, 1000, ''); session:hangup(); end if (type == "greeting") then advanced(); end if (type == "name") then advanced(); end end end end end end end --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 sql = [[SELECT * FROM v_voicemail_messages WHERE domain_uuid = ']] .. domain_uuid ..[[' AND voicemail_uuid = ']] .. voicemail_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 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"]; end); end --get the voicemail settings sql = [[SELECT * FROM v_voicemails WHERE domain_uuid = ']] .. domain_uuid ..[[' AND voicemail_id = ']] .. forward_voicemail_id ..[[' AND voicemail_enabled = 'true' ]]; if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end status = dbh:query(sql, 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); --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, "); 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, "'".. uuid .."', "); table.insert(sql, "'".. domain_uuid .."', "); table.insert(sql, "'".. forward_voicemail_uuid .."', "); 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"); if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end dbh:query(sql); --set the message waiting event local event = freeswitch.Event("message_waiting"); event:addHeader("MWI-Messages-Waiting", "yes"); event:addHeader("MWI-Message-Account", "sip:"..forward_voicemail_id.."@"..domain_name); event:fire(); --if local after email is true then copy the recording file os.execute("mkdir -p " .. voicemail_dir.."/"..forward_voicemail_id); os.execute("cp "..voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext.." "..voicemail_dir.."/"..forward_voicemail_id.."/msg_"..uuid.."."..vm_message_ext); --send the email with the voicemail recording attached send_email(forward_voicemail_id, uuid); end --define function main menu function main_menu () if (voicemail_uuid) then --clear the value dtmf_digits = ''; --flush dtmf digits from the input buffer session:flushDigits(); --new voicemail count if (session:ready()) then 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 .. "\n"); end status = dbh:query(sql, 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' ]]; if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end status = dbh:query(sql, 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()) 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()) 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 --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 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 message date if (session:ready()) then if (string.len(dtmf_digits) == 0) then session:say(created_epoch, default_language, "CURRENT_DATE_TIME", "pronounced"); end end --play the message if (session:ready()) then if (string.len(dtmf_digits) == 0) then session:streamFile(voicemail_dir.."/"..voicemail_id.."/msg_"..uuid.."."..vm_message_ext); session:streamFile("silence_stream://1000"); end 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); 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 --voicemail count if zero new messages set the mwi to no function message_waiting(voicemail_id, domain_uuid) sql = [[SELECT count(*) as message_count FROM v_voicemail_messages as m, v_voicemails as v WHERE v.domain_uuid = ']] .. domain_uuid ..[[' AND v.voicemail_uuid = m.voicemail_uuid AND v.voicemail_id = ']] .. voicemail_id ..[[' AND (m.message_status is null or m.message_status = '') ]]; if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end status = dbh:query(sql, function(row) --send the message waiting event local event = freeswitch.Event("message_waiting"); if (row["message_count"] == "0") then event:addHeader("MWI-Messages-Waiting", "no"); else event:addHeader("MWI-Messages-Waiting", "yes"); end event:addHeader("MWI-Message-Account", "sip:"..voicemail_id.."@"..domain_name); event:fire(); --log to console if (debug["info"]) then freeswitch.consoleLog("notice", "[voicemail] mailbox: "..voicemail_id.."@"..domain_name.." messages: " .. row["message_count"] .. " \n"); end end); end --define a function to send email function send_email(id, uuid) --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_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); --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 --require the email address to send the email if (string.len(voicemail_mail_to) > 2) then --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"]; --message_status = row["message_status"]; --message_priority = row["message_priority"]; end); --format the message length message_length_formatted = format_seconds(message_length); if (debug["info"]) then freeswitch.consoleLog("notice", "[voicemail] message length: " .. message_length .. "\n"); end --send the email subject = [[Voicemail from ]]..caller_id_name..[[ <]]..caller_id_number..[[> ]]..message_length_formatted; local message = {} table.insert(message, [[]]); table.insert(message, [[Message From "]]..caller_id_name..[[" ]]..caller_id_number..[[
]]); table.insert(message, [[
]]); table.insert(message, [[Created: ]]..os.date("%A, %d %b %Y %I:%M %p", created_epoch)..[[
]]); table.insert(message, [[Duration: ]]..message_length_formatted..[[
]]); table.insert(message, [[Account: ]]..id..[[@]]..domain_name..[[
]]); table.insert(message, [[
]]); body = table.concat(message, ""); body = body:gsub("'", "'"); body = body:gsub([["]], """); if (voicemail_attach_file == "true") then if (voicemail_local_after_email == "false") then delete = "true"; else delete = "false"; end file = voicemail_dir.."/"..id.."/msg_"..uuid.."."..vm_message_ext; cmd = "luarun email.lua "..voicemail_mail_to.." "..voicemail_mail_to.." '"..subject.."' '"..body.."' '"..file.."' "..delete; else cmd = "luarun email.lua "..voicemail_mail_to.." "..voicemail_mail_to.." '"..subject.."' '"..body.."'"; end if (debug["info"]) then freeswitch.consoleLog("notice", "[voicemail] cmd: " .. cmd .. "\n"); end result = api:executeString(cmd); end --whether to keep the voicemail message and details local after email if (voicemail_local_after_email == "false") then --delete the voicemail message details sql = [[DELETE FROM v_voicemail_messages WHERE domain_uuid = ']] .. domain_uuid ..[[' AND voicemail_uuid = ']] .. db_voicemail_uuid ..[[' AND voicemail_message_uuid = ']] .. uuid ..[[']] if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end status = dbh:query(sql); --set message waiting indicator message_waiting(id, domain_uuid); --clear the variable db_voicemail_uuid = ''; end end --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 sql = [[SELECT * FROM v_voicemails WHERE domain_uuid = ']] .. domain_uuid ..[[' AND voicemail_id = ']] .. voicemail_id ..[[']]; status = dbh:query(sql, 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.."/msg_"..uuid.."."..vm_message_ext); --delete from the database sql = [[DELETE FROM v_voicemail_messages WHERE domain_uuid = ']] .. domain_uuid ..[[' AND voicemail_uuid = ']] .. db_voicemail_uuid ..[[' AND voicemail_message_uuid = ']] .. uuid ..[[']]; if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end dbh:query(sql); --log to console if (debug["info"]) then freeswitch.consoleLog("notice", "[voicemail][deleted] message: " .. uuid .. "\n"); end --clear the variable db_voicemail_uuid = ''; end --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 sql = [[SELECT * FROM v_voicemails WHERE domain_uuid = ']] .. domain_uuid ..[[' AND voicemail_id = ']] .. voicemail_id ..[[']]; status = dbh:query(sql, 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 = ']] .. db_voicemail_uuid ..[[' AND voicemail_message_uuid = ']] .. uuid ..[[']]; if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end dbh:query(sql); --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 --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 --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 sql = [[SELECT * 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 if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end status = dbh:query(sql, 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()) then if (voicemail_id ~= nil) then 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 .. "\n"); end status = dbh:query(sql, function(row) if (row["new_messages"] == "0") then --send the message waiting event local event = freeswitch.Event("message_waiting"); event:addHeader("MWI-Messages-Waiting", "no"); event:addHeader("MWI-Message-Account", "sip:"..voicemail_id.."@"..domain_name); event:fire(); end end); 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 --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(); 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(); elseif (dtmf_digits == "6") then --To change your password press 6 change_password(voicemail_id); 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 --define a function to record the greeting function record_greeting() --flush dtmf digits from the input buffer session:flushDigits(); --Choose a greeting between 1 and 9 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 --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 --record the greeting if (session:ready()) then max_len_seconds = 30; silence_threshold = 30; silence_seconds = 5; os.execute("mkdir -p " .. voicemail_dir.."/"..voicemail_id); -- syntax is session:recordFile(file_name, max_len_secs, silence_threshold, silence_secs) result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/greeting_"..greeting_id..".wav", max_len_seconds, silence_threshold, silence_seconds); --session:execute("record", voicemail_dir.."/"..uuid.." 180 200"); 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..".wav"); 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(); else timeouts = 0; advanced(); end end end end --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 (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 --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 if (greeting_id == "0") then sql = [[UPDATE v_voicemails SET greeting_id = null ]]; else sql = [[UPDATE v_voicemails SET 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 .. "\n"); end dbh:query(sql); 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 --define a function to record the name function record_name() 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, ''); --save the recording -- syntax is session:recordFile(file_name, max_len_secs, silence_threshold, silence_secs) max_len_seconds = 30; silence_threshold = 30; silence_seconds = 5; os.execute("mkdir -p " .. voicemail_dir.."/"..voicemail_id); result = session:recordFile(voicemail_dir.."/"..voicemail_id.."/recorded_name.wav", max_len_seconds, silence_threshold, silence_seconds); --session:execute("record", voicemail_dir.."/"..uuid.." 180 200"); --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"); end end end --send a message waiting event if (voicemail_action == "mwi") then --get the mailbox info account = argv[2]; array = explode("@", account); voicemail_id = array[1]; domain_name = array[2]; --send information the console debug["info"] = "true"; --get voicemail message details sql = [[SELECT * FROM v_domains WHERE domain_name = ']] .. domain_name ..[[']] if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end status = dbh:query(sql, 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:ready()) then --check the voicemail password check_password(voicemail_id, password_tries); --send to the main menu timeouts = 0; main_menu(); end end --leave a message if (voicemail_action == "save") then --save the recording timeouts = 0; play_greeting(); record_message(); --save the message to the voicemail messages if (message_length > 2) then 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, "); 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, "'".. 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 .."', "); table.insert(sql, "'".. message_length .."' "); --table.insert(sql, "'".. message_status .."', "); --table.insert(sql, "'".. message_priority .."' "); table.insert(sql, ") "); sql = table.concat(sql, "\n"); if (debug["sql"]) then freeswitch.consoleLog("notice", "[voicemail] SQL: " .. sql .. "\n"); end dbh:query(sql); end --set the message waiting event if (message_length > 2) then local event = freeswitch.Event("message_waiting"); event:addHeader("MWI-Messages-Waiting", "yes"); event:addHeader("MWI-Message-Account", "sip:"..voicemail_id.."@"..domain_name); event:fire(); end --send the email with the voicemail recording attached if (message_length > 2) then send_email(voicemail_id, uuid); end end --close the database connection dbh:release(); --notes --record the video --records audio only --result = session:execute("set", "enable_file_write_buffering=false"); --os.execute("mkdir -p " .. 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 --os.execute("mkdir -p " .. 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,,Send video refresh.,mod_commands --may be used to clear video buffer before using record_fsv