-- post_hangup_handler.lua -- runs after hangup to end CDRs and do cleanup local log = require "lua.modules.logger.main" local config = require "lua.modules.config.main".load() local Phone = require "lua.modules.phone.main" local rex = require "rex_pcre" local json = require "json" local call_log = require "lua.modules.call_log.main" local function send_mobile_forward_hangup_push(env, status) local uuid = env:getHeader('uuid') local sip_from_user = env:getHeader('sip_from_user') or "" local mobile_forward_voip_phone_id = env:getHeader('mobile_forward_voip_phone_id') or "" local linked_uuid = env:getHeader('linked_uuid') local hostname = env:getHeader('hostname') or env:getHeader('mobile_forward_hostname') local sip_from_display = env:getHeader('sip_from_display') or env:getHeader('caller_id_name') or "" local original_called_number = env:getHeader('original_called_number') or "" local api = freeswitch.API() api:executeString("luarun lua/api/http_push_request.lua webcom " .. uuid .. " " .. sip_from_user .. " " .. mobile_forward_voip_phone_id .. " " .. linked_uuid .. " " .. hostname .. " " .. "'" .. sip_from_display .. "' " .. original_called_number .. " " .. status ) end local function check_queue_tmp(env) local dbh_unified = assert(freeswitch.Dbh(config.mysql.database.unified.name, config.mysql.user, config.mysql.password), "Could not connect to database") local dbh = assert(freeswitch.Dbh(config.mysql.database.fs_unified.name, config.mysql.user, config.mysql.password), "Could not connect to database") -- check table local linked_uuid = env:getHeader('linked_uuid') local new_linked_uuid = string.gsub(linked_uuid, "-", "_") local queue_tmp_check_sql = string.format([[ SELECT queue_uuid, queue_id, member, queue_hold_time FROM asterisk_queue_tmp WHERE queue_uuid = '%s' ]], new_linked_uuid) log.console(queue_tmp_check_sql) local queue_uuid local queue_id local member local queue_hold_time dbh_unified:query(queue_tmp_check_sql, function(row) queue_uuid = row.queue_uuid queue_id = row.queue_id member = row.member queue_hold_time = row.queue_hold_time end) if queue_uuid == nil then log.console("check_queue_tmp() - No queue_uuid") return end if queue_id == nil then log.console("check_queue_tmp() - No queue_id") return end if member == nil then log.console("check_queue_tmp() - No member") return end if queue_hold_time == nil then log.console("check_queue_tmp() - No queue_hold_time") return end if string.match(member, "^PJSIP/%+1%d+") then log.console("check_queue_tmp() - The queue was answered by an external number") local called_number = string.match(member, "^PJSIP/(%+1%d+)") local call_log_object = { called_number = called_number, caller_id = env:getHeader('queue_caller_id_number'), type = 'dial_out', voip_id = env:getHeader('voip_id'), queue_hold_time = queue_hold_time, } call_log.post_hangup_buffered_update(env, call_log_object) else log.console("check_queue_tmp() - The queue was answered by a voip_device_id") local queue_voip_device_id = string.match(member, "^PJSIP/(%d+)") local phone, err = Phone.new(dbh, nil, queue_voip_device_id) if not phone then log.err(err) dbh:release() dbh_unified:release() return end local call_log_object = { voip_phone_id = phone.variables.voip_phone_id, caller_id = env:getHeader('queue_caller_id_number'), called_number = phone.variables.extension, type = 'phone', voip_id = phone.variables.voip_id, queue_hold_time = queue_hold_time, } call_log.post_hangup_buffered_update(env, call_log_object) end -- delete row from table local queue_tmp_delete_sql = string.format([[ DELETE FROM asterisk_queue_tmp WHERE queue_uuid='%s' AND queue_id=%s AND member='%s' AND queue_hold_time=%s ]], queue_uuid, queue_id, member, queue_hold_time) log.console(queue_tmp_delete_sql) dbh_unified:query(queue_tmp_delete_sql) if dbh_unified:affected_rows() ~= 1 then log.err("check_queue_tmp() - Could not delete \n" .. queue_tmp_delete_sql .. "\n from database.") end dbh:release() dbh_unified:release() return end local function handle_queue_member_answer_call_log(env) local last_sent_callee_id_number = env:getHeader('last_sent_callee_id_number') if string.match(last_sent_callee_id_number, "^%d?%d?%d?%d?%d?%d?%+1%d+") then log.console("handle_queue_member_answer_call_log() - " .. "last_sent_callee_id_number is an external number. " .. "Doing dial_out buffered_insert") local called_number = string.match(last_sent_callee_id_number, "^%d?%d?%d?%d?%d?%d?(%+1%d+)") local call_log_object = { called_number = called_number, caller_id = env:getHeader('queue_caller_id_number'), type = 'dial_out', voip_id = env:getHeader('voip_id'), } call_log.post_hangup_buffered_update(env, call_log_object) else log.console("last_sent_callee_id_number is a voip_device_id. Doing phone buffered_insert") local dbh = assert(freeswitch.Dbh(config.mysql.database.fs_unified.name,config.mysql.user,config.mysql.password), "Could not connect to database") local phone, err = Phone.new(dbh, nil, last_sent_callee_id_number) if not phone then log.err("Could not get the voip_phone_id for the agent: " .. err) dbh:release() return end local call_log_object = { voip_phone_id = phone.variables.voip_phone_id, caller_id = env:getHeader('queue_caller_id_number'), called_number = phone.variables.extension, type = 'phone', voip_id = phone.variables.voip_id, } call_log.post_hangup_buffered_update(env, call_log_object) dbh:release() end end local function cleanup_mobile_push(env) local usecs = tonumber( env:getHeader("answerusec") ) if usecs == 0 then local from = env:getHeader("sip_from_user") local voip_phone_id = env:getHeader("voip_phone_id") local uuid = env:getHeader("uuid") local linked_uuid = env:getHeader("linked_uuid") local hostname = env:getHeader("hostname") local caller_contact_name = env:getHeader("sip_from_display") or env:getHeader("original_caller_number") or "" local original_called_number = env:getHeader('original_called_number') or "" log.console("Inside hangup hook, sending cancel push\n") local mobile_voip_phone_ids = env:getHeader('mobile_voip_phone_ids') if not mobile_voip_phone_ids then return end local mobile_voip_phone_ids_table = json.decode(mobile_voip_phone_ids) for _, voip_phone in ipairs(mobile_voip_phone_ids_table) do local api = freeswitch.API() api:executeString("luarun lua/api/http_push_request.lua basic " .. uuid .. " " .. from .. " " .. voip_phone .. " " .. linked_uuid .. " " .. hostname .. " '" .. caller_contact_name .. "' " .. original_called_number .. " canceled") end else log.console("Inside hangup hook, not sending cancel push\n") end end ----------------------------------------------------------------------------- -- -- -- @param -- @return N/A ----------------------------------------------------------------------------- local function parked_calls_cleanup(uuid, valet_lot_extension) local dbh_unified = assert(freeswitch.Dbh(config.mysql.database.unified.name,config.mysql.user,config.mysql.password), "Could not connect to database") local delete_voip_parked_call_sql if uuid ~= nil then delete_voip_parked_call_sql = string.format([[ DELETE FROM voip_parked_calls WHERE linked_uuid='%s' ]], uuid) else delete_voip_parked_call_sql = string.format([[ DELETE FROM voip_parked_calls WHERE voip_phone_id=%s ]], valet_lot_extension) end log.console("post_hangup_handler.lua - parked_calls_cleanup(): " .. delete_voip_parked_call_sql) dbh_unified:query(delete_voip_parked_call_sql) dbh_unified:release() end ----------------------------------------------------------------------------- -- -- https://freeswitch.org/confluence/display/FREESWITCH/api_hangup_hook -- -- @param -- @return N/A ----------------------------------------------------------------------------- local function post_hangup_handler(env) if not env then return end -- See everything -- local dat = env:serialize() -- log.console("Here's everything:\n" .. dat .. "\n") if env:getHeader('is_loopback') == "true" then -- we want to skip loopback hangups return end if env:getHeader('cc_cause') == "answered" then if env:getHeader('is_external_queue_call') == "true" then log.console("post_hangup_handler() - This was an external queue call that got answered. " .. "So, we did an insert into asterisk_queue_tmp table for the original server " .. " to use in a final buffered_update.") return end log.console("post_hangup_handler() - This was a queue call that got answered on the original " .. "server that received the call. So, we are just going to make a buffered_update " .. "file with the answered agents information because we do the final buffered_insert " .. " to complete the call logs.") handle_queue_member_answer_call_log(env) end if env:getHeader('is_queue_call') == "Y" then log.console("post_hangup_handler() - This was a queue call that got sent to another server. " .. "So, we need to check the asterisk_queue_tmp table to see if an agent answered " .. " so we can do a final buffered_update before the final buffered_insert to end the call logs.") check_queue_tmp(env) end if env:getHeader('is_external_queue_call') == "true" then log.console("post_hangup_handler() - This is an external queue call that did not get answered. " .. "Returning without doing anything.") return end if env:getHeader('is_mobile_dial') == "Y" then cleanup_mobile_push(env) end local callee_number = env:getHeader('last_sent_callee_id_number') if callee_number then local voip_device_id, line = rex.match(callee_number, "^(\\d{2,10})x?(\\d{1,2})?$") if voip_device_id then local dbh = assert(freeswitch.Dbh(config.mysql.database.fs_unified.name, config.mysql.user, config.mysql.password), "Could not connect to database") local callee_phone = Phone.new(dbh, nil, voip_device_id, line) if callee_phone then env:addHeader('voip_phone_id', callee_phone.variables.voip_phone_id) end dbh:release() end end -- final buffered call log update call_log.final_buffered_insert(env) if env:getHeader('is_live_answer') == "Y" then -- live_answer_cdr_update(env) -- what is this? end if env:getHeader('transfer_disposition') == 'replaced' and env:getHeader('endpoint_disposition') == 'ATTENDED_TRANSFER' then local other_uuid = env:getHeader('other_uuid') if other_uuid ~= "" and other_uuid ~= nil then local channel = require "lua.modules.channel.main" if other_uuid then channel.set_var(other_uuid, "transfer_destination_id") end end end if env:getHeader('mobile_forward_voip_phone_id') then -- This call had a mobile_forward push -- check that is was answered by the mobile device number local mobile_forward_number = env:getHeader('mobile_forward_number') if callee_number then local _, number = rex.match(callee_number, "^(\\d{1,6})(\\+\\d+)$") if number == mobile_forward_number then send_mobile_forward_hangup_push(env, 'disconnect') end else local usecs = tonumber( env:getHeader("answerusec") ) if usecs == 0 then send_mobile_forward_hangup_push(env, 'cancelled') end end return end local linked_uuid = env:getHeader('linked_uuid') local original_parked_linked_uuid = env:getHeader('original_parked_linked_uuid') local valet_lot_extension = env:getHeader('valet_lot_extension') local parker_leg = env:getHeader('parker_leg') if parker_leg then log.console("post_hangup_handler.lua - parker_leg: " .. parker_leg) end local check = env:getHeader('valet_lot_extension') if check then log.console("post_hangup_handler.lua - valet_lot_extension: " .. check) else log.console("No valet_lot_extension found.") end local direction = env:getHeader('sip_h_X-Call-Direction') if direction then log.console("post_hangup_handler.lua - direction: " .. direction) end if valet_lot_extension then valet_lot_extension = string.match(valet_lot_extension, "^%d+$") end if original_parked_linked_uuid ~= nil then log.console("post_hangup_handler.lua - linked_uuid: " .. linked_uuid .. " and original_parked_linked_uuid: " .. original_parked_linked_uuid) end if linked_uuid == original_parked_linked_uuid then log.console("post_hangup_handler.lua - linked_uuid: " .. linked_uuid .. " and original_parked_linked_uuid: " .. original_parked_linked_uuid) parked_calls_cleanup(linked_uuid) elseif valet_lot_extension ~= nil then log.console("post_hangup_handler.lua - parked caller hungup" .. " using valet_lot_extension " .. valet_lot_extension .. " to clear voip_parked_calls") parked_calls_cleanup(nil, valet_lot_extension) return end end post_hangup_handler(env)