From Big Bison, 4 Years ago, written in Plain Text.
- view diff
Embed
  1. -- post_hangup_handler.lua
  2. -- runs after hangup to end CDRs and do cleanup
  3.  
  4. local log      = require "lua.modules.logger.main"
  5. local config   = require "lua.modules.config.main".load()
  6. local Phone    = require "lua.modules.phone.main"
  7. local rex      = require "rex_pcre"
  8. local json     = require "json"
  9. local call_log = require "lua.modules.call_log.main"
  10.  
  11. local function send_mobile_forward_hangup_push(env, status)
  12.   local uuid = env:getHeader('uuid')
  13.   local sip_from_user = env:getHeader('sip_from_user') or ""
  14.   local mobile_forward_voip_phone_id = env:getHeader('mobile_forward_voip_phone_id') or ""
  15.   local linked_uuid = env:getHeader('linked_uuid')
  16.   local hostname = env:getHeader('hostname') or env:getHeader('mobile_forward_hostname')
  17.   local sip_from_display = env:getHeader('sip_from_display') or env:getHeader('caller_id_name') or ""
  18.   local original_called_number = env:getHeader('original_called_number') or ""
  19.  
  20.   local api = freeswitch.API()
  21.   api:executeString("luarun lua/api/http_push_request.lua webcom "
  22.     .. uuid .. " "
  23.     .. sip_from_user .. " "
  24.     .. mobile_forward_voip_phone_id .. " "
  25.     .. linked_uuid .. " "
  26.     .. hostname .. " "
  27.     .. "'" .. sip_from_display .. "' "
  28.     .. original_called_number .. " "
  29.     .. status
  30.   )
  31. end
  32.  
  33. local function check_queue_tmp(env)
  34.   local dbh_unified = assert(freeswitch.Dbh(config.mysql.database.unified.name,
  35.                                             config.mysql.user,
  36.                                             config.mysql.password),
  37.                                             "Could not connect to database")
  38.   local dbh         = assert(freeswitch.Dbh(config.mysql.database.fs_unified.name,
  39.                                             config.mysql.user,
  40.                                             config.mysql.password),
  41.                                             "Could not connect to database")
  42.   -- check table
  43.   local linked_uuid = env:getHeader('linked_uuid')
  44.   local new_linked_uuid = string.gsub(linked_uuid, "-", "_")
  45.   local queue_tmp_check_sql = string.format([[
  46. SELECT queue_uuid, queue_id, member, queue_hold_time
  47. FROM asterisk_queue_tmp
  48. WHERE queue_uuid = '%s'
  49.   ]], new_linked_uuid)
  50.  
  51.   log.console(queue_tmp_check_sql)
  52.  
  53.   local queue_uuid
  54.   local queue_id
  55.   local member
  56.   local queue_hold_time
  57.  
  58.   dbh_unified:query(queue_tmp_check_sql, function(row)
  59.     queue_uuid = row.queue_uuid
  60.     queue_id = row.queue_id
  61.     member = row.member
  62.     queue_hold_time = row.queue_hold_time
  63.   end)
  64.  
  65.   if queue_uuid == nil then log.console("check_queue_tmp() - No queue_uuid") return end
  66.   if queue_id == nil then log.console("check_queue_tmp() - No queue_id") return end
  67.   if member == nil then log.console("check_queue_tmp() - No member") return end
  68.   if queue_hold_time == nil then log.console("check_queue_tmp() - No queue_hold_time") return end
  69.  
  70.   if string.match(member, "^PJSIP/%+1%d+") then
  71.     log.console("check_queue_tmp() - The queue was answered by an external number")
  72.     local called_number = string.match(member, "^PJSIP/(%+1%d+)")
  73.  
  74.     local call_log_object    = {
  75.       called_number = called_number,
  76.       caller_id     = env:getHeader('queue_caller_id_number'),
  77.       type          = 'dial_out',
  78.       voip_id       = env:getHeader('voip_id'),
  79.       queue_hold_time = queue_hold_time,
  80.     }
  81.     call_log.post_hangup_buffered_update(env, call_log_object)
  82.   else
  83.     log.console("check_queue_tmp() - The queue was answered by a voip_device_id")
  84.     local queue_voip_device_id = string.match(member, "^PJSIP/(%d+)")
  85.     local phone, err = Phone.new(dbh, nil, queue_voip_device_id)
  86.     if not phone then
  87.       log.err(err)
  88.       dbh:release()
  89.       dbh_unified:release()
  90.       return
  91.     end
  92.  
  93.     local call_log_object    = {
  94.       voip_phone_id = phone.variables.voip_phone_id,
  95.       caller_id     = env:getHeader('queue_caller_id_number'),
  96.       called_number = phone.variables.extension,
  97.       type          = 'phone',
  98.       voip_id       = phone.variables.voip_id,
  99.       queue_hold_time = queue_hold_time,
  100.     }
  101.     call_log.post_hangup_buffered_update(env, call_log_object)
  102.   end
  103.  
  104.   -- delete row from table
  105.   local queue_tmp_delete_sql = string.format([[
  106. DELETE FROM asterisk_queue_tmp
  107. WHERE queue_uuid='%s'
  108. AND queue_id=%s
  109. AND member='%s'
  110. AND queue_hold_time=%s
  111.   ]], queue_uuid, queue_id, member, queue_hold_time)
  112.  
  113.     log.console(queue_tmp_delete_sql)
  114.  
  115.     dbh_unified:query(queue_tmp_delete_sql)
  116.  
  117.   if dbh_unified:affected_rows() ~= 1 then
  118.     log.err("check_queue_tmp() - Could not delete \n"
  119.                                   .. queue_tmp_delete_sql .. "\n from database.")
  120.   end
  121.  
  122.   dbh:release()
  123.   dbh_unified:release()
  124.  
  125.   return
  126. end
  127.  
  128. local function handle_queue_member_answer_call_log(env)
  129.   local last_sent_callee_id_number = env:getHeader('last_sent_callee_id_number')
  130.  
  131.   if string.match(last_sent_callee_id_number, "^%d?%d?%d?%d?%d?%d?%+1%d+") then
  132.     log.console("handle_queue_member_answer_call_log() - "
  133.                                    .. "last_sent_callee_id_number is an external number. "
  134.                                    .. "Doing dial_out buffered_insert")
  135.  
  136.     local called_number = string.match(last_sent_callee_id_number, "^%d?%d?%d?%d?%d?%d?(%+1%d+)")
  137.     local call_log_object    = {
  138.       called_number = called_number,
  139.       caller_id     = env:getHeader('queue_caller_id_number'),
  140.       type          = 'dial_out',
  141.       voip_id       = env:getHeader('voip_id'),
  142.     }
  143.     call_log.post_hangup_buffered_update(env, call_log_object)
  144.   else
  145.     log.console("last_sent_callee_id_number is a voip_device_id. Doing phone buffered_insert")
  146.     local dbh = assert(freeswitch.Dbh(config.mysql.database.fs_unified.name,config.mysql.user,config.mysql.password),
  147.                                       "Could not connect to database")
  148.     local phone, err = Phone.new(dbh, nil, last_sent_callee_id_number)
  149.     if not phone then
  150.       log.err("Could not get the voip_phone_id for the agent: " .. err)
  151.       dbh:release()
  152.       return
  153.     end
  154.  
  155.     local call_log_object    = {
  156.       voip_phone_id = phone.variables.voip_phone_id,
  157.       caller_id     = env:getHeader('queue_caller_id_number'),
  158.       called_number = phone.variables.extension,
  159.       type          = 'phone',
  160.       voip_id       = phone.variables.voip_id,
  161.     }
  162.     call_log.post_hangup_buffered_update(env, call_log_object)
  163.  
  164.     dbh:release()
  165.   end
  166. end
  167.  
  168. local function cleanup_mobile_push(env)
  169.   local usecs = tonumber( env:getHeader("answerusec") )
  170.   if usecs == 0 then
  171.     local from =  env:getHeader("sip_from_user")
  172.     local voip_phone_id =  env:getHeader("voip_phone_id")
  173.     local uuid =  env:getHeader("uuid")
  174.     local linked_uuid =  env:getHeader("linked_uuid")
  175.     local hostname =  env:getHeader("hostname")
  176.     local caller_contact_name = env:getHeader("sip_from_display") or env:getHeader("original_caller_number") or ""
  177.     local original_called_number = env:getHeader('original_called_number') or ""
  178.  
  179.     log.console("Inside hangup hook, sending cancel push\n")
  180.     local mobile_voip_phone_ids = env:getHeader('mobile_voip_phone_ids')
  181.  
  182.     if not mobile_voip_phone_ids then
  183.       return
  184.     end
  185.  
  186.     local mobile_voip_phone_ids_table = json.decode(mobile_voip_phone_ids)
  187.     for _, voip_phone in ipairs(mobile_voip_phone_ids_table) do
  188.       local api = freeswitch.API()
  189.       api:executeString("luarun lua/api/http_push_request.lua basic "
  190.         .. uuid .. " "
  191.         .. from .. " "
  192.         .. voip_phone .. " "
  193.         .. linked_uuid .. " "
  194.         .. hostname .. " '"
  195.         .. caller_contact_name .. "' "
  196.         .. original_called_number
  197.         .. " canceled")
  198.     end
  199.   else
  200.     log.console("Inside hangup hook, not sending cancel push\n")
  201.   end
  202. end
  203.  
  204. -----------------------------------------------------------------------------
  205. --
  206. --
  207. -- @param
  208. -- @return                     N/A
  209. -----------------------------------------------------------------------------
  210. local function parked_calls_cleanup(uuid, valet_lot_extension)
  211.   local dbh_unified = assert(freeswitch.Dbh(config.mysql.database.unified.name,config.mysql.user,config.mysql.password), "Could not connect to database")
  212.   local delete_voip_parked_call_sql
  213.  
  214.   if uuid ~= nil then
  215.     delete_voip_parked_call_sql = string.format([[
  216. DELETE FROM voip_parked_calls
  217. WHERE linked_uuid='%s'
  218.     ]], uuid)
  219.   else
  220.     delete_voip_parked_call_sql = string.format([[
  221. DELETE FROM voip_parked_calls
  222. WHERE voip_phone_id=%s
  223.     ]], valet_lot_extension)
  224.   end
  225.  
  226.   log.console("post_hangup_handler.lua - parked_calls_cleanup(): " .. delete_voip_parked_call_sql)
  227.  
  228.   dbh_unified:query(delete_voip_parked_call_sql)
  229.  
  230.   dbh_unified:release()
  231. end
  232.  
  233. -----------------------------------------------------------------------------
  234. --
  235. -- https://freeswitch.org/confluence/display/FREESWITCH/api_hangup_hook
  236. --
  237. -- @param
  238. -- @return                     N/A
  239. -----------------------------------------------------------------------------
  240. local function post_hangup_handler(env)
  241.   if not env then
  242.     return
  243.   end
  244.  
  245.   -- See everything
  246.   -- local dat = env:serialize()
  247.   -- log.console("Here's everything:\n" .. dat .. "\n")
  248.   if env:getHeader('is_loopback') == "true" then
  249.     -- we want to skip loopback hangups
  250.     return
  251.   end
  252.  
  253.   if env:getHeader('cc_cause') == "answered" then
  254.     if env:getHeader('is_external_queue_call') == "true" then
  255.       log.console("post_hangup_handler() - This was an external queue call that got answered. "
  256.                                      .. "So, we did an insert into asterisk_queue_tmp table for the original server "
  257.                                      .. " to use in a final buffered_update.")
  258.       return
  259.     end
  260.     log.console("post_hangup_handler() - This was a queue call that got answered on the original "
  261.                                    .. "server that received the call. So, we are just going to make a buffered_update "
  262.                                    .. "file with the answered agents information because we do the final buffered_insert "
  263.                                    .. " to complete the call logs.")
  264.     handle_queue_member_answer_call_log(env)
  265.   end
  266.  
  267.   if env:getHeader('is_queue_call') == "Y" then
  268.     log.console("post_hangup_handler() - This was a queue call that got sent to another server. "
  269.                                    .. "So, we need to check the asterisk_queue_tmp table to see if an agent answered "
  270.                                    .. " so we can do a final buffered_update before the final buffered_insert to end the call logs.")
  271.     check_queue_tmp(env)
  272.   end
  273.  
  274.   if env:getHeader('is_external_queue_call') == "true" then
  275.     log.console("post_hangup_handler() - This is an external queue call that did not get answered. "
  276.                                    .. "Returning without doing anything.")
  277.     return
  278.   end
  279.  
  280.   if env:getHeader('is_mobile_dial') == "Y" then
  281.     cleanup_mobile_push(env)
  282.   end
  283.  
  284.   local callee_number = env:getHeader('last_sent_callee_id_number')
  285.  
  286.   if callee_number then
  287.     local voip_device_id, line = rex.match(callee_number, "^(\\d{2,10})x?(\\d{1,2})?$")
  288.  
  289.     if voip_device_id then
  290.       local dbh = assert(freeswitch.Dbh(config.mysql.database.fs_unified.name,
  291.                                         config.mysql.user,
  292.                                         config.mysql.password),
  293.                                         "Could not connect to database")
  294.       local callee_phone = Phone.new(dbh, nil, voip_device_id, line)
  295.       if callee_phone then
  296.         env:addHeader('voip_phone_id', callee_phone.variables.voip_phone_id)
  297.       end
  298.  
  299.       dbh:release()
  300.     end
  301.   end
  302.  
  303.   -- final buffered call log update
  304.   call_log.final_buffered_insert(env)
  305.  
  306.   if env:getHeader('is_live_answer') == "Y" then
  307.     -- live_answer_cdr_update(env) -- what is this?
  308.   end
  309.  
  310.   if env:getHeader('transfer_disposition') == 'replaced' and env:getHeader('endpoint_disposition') == 'ATTENDED_TRANSFER' then
  311.     local other_uuid = env:getHeader('other_uuid')
  312.     if other_uuid ~= "" and other_uuid ~= nil then
  313.       local channel = require "lua.modules.channel.main"
  314.       if other_uuid then
  315.         channel.set_var(other_uuid, "transfer_destination_id")
  316.       end
  317.     end
  318.   end
  319.  
  320.   if env:getHeader('mobile_forward_voip_phone_id') then
  321.     -- This call had a mobile_forward push
  322.     -- check that is was answered by the mobile device number
  323.     local mobile_forward_number = env:getHeader('mobile_forward_number')
  324.  
  325.     if callee_number then
  326.       local _, number = rex.match(callee_number, "^(\\d{1,6})(\\+\\d+)$")
  327.       if number == mobile_forward_number then
  328.         send_mobile_forward_hangup_push(env, 'disconnect')
  329.       end
  330.     else
  331.       local usecs = tonumber( env:getHeader("answerusec") )
  332.       if usecs == 0 then
  333.         send_mobile_forward_hangup_push(env, 'cancelled')
  334.       end
  335.     end
  336.  
  337.     return
  338.   end
  339.  
  340.   local linked_uuid = env:getHeader('linked_uuid')
  341.   local original_parked_linked_uuid = env:getHeader('original_parked_linked_uuid')
  342.  
  343.   local valet_lot_extension = env:getHeader('valet_lot_extension')
  344.   local parker_leg = env:getHeader('parker_leg')
  345.   if parker_leg then log.console("post_hangup_handler.lua - parker_leg: " .. parker_leg) end
  346.  
  347.   local check = env:getHeader('valet_lot_extension')
  348.   if check then
  349.     log.console("post_hangup_handler.lua - valet_lot_extension: " .. check)
  350.   else
  351.     log.console("No valet_lot_extension found.")
  352.   end
  353.  
  354.   local direction = env:getHeader('sip_h_X-Call-Direction')
  355.   if direction then
  356.     log.console("post_hangup_handler.lua - direction: " .. direction)
  357.   end
  358.  
  359.   if valet_lot_extension then valet_lot_extension = string.match(valet_lot_extension, "^%d+$") end
  360.  
  361.   if original_parked_linked_uuid ~= nil then
  362.     log.console("post_hangup_handler.lua - linked_uuid: " .. linked_uuid ..
  363.                                    " and original_parked_linked_uuid: " .. original_parked_linked_uuid)
  364.   end
  365.  
  366.   if linked_uuid == original_parked_linked_uuid then
  367.     log.console("post_hangup_handler.lua - linked_uuid: " .. linked_uuid ..
  368.                                    " and original_parked_linked_uuid: " .. original_parked_linked_uuid)
  369.     parked_calls_cleanup(linked_uuid)
  370.   elseif valet_lot_extension ~= nil then
  371.     log.console("post_hangup_handler.lua - parked caller hungup"
  372.                                    .. " using valet_lot_extension " .. valet_lot_extension
  373.                                    .. " to clear voip_parked_calls")
  374.     parked_calls_cleanup(nil, valet_lot_extension)
  375.  
  376.         return
  377.   end
  378. end
  379.  
  380. post_hangup_handler(env)