From 047824cad7cb181221b34d1098cdd1a0b2ed99ee Mon Sep 17 00:00:00 2001 From: markjcrane Date: Tue, 6 Jun 2023 10:33:59 -0600 Subject: [PATCH] Remove Fax tasks as replaced with the fax queue --- .../app/fax/resources/scripts/queue/exec.lua | 187 -------- .../app/fax/resources/scripts/queue/next.lua | 98 ---- .../app/fax/resources/scripts/queue/retry.lua | 418 ------------------ .../app/fax/resources/scripts/queue/tasks.lua | 330 -------------- 4 files changed, 1033 deletions(-) delete mode 100644 app/scripts/resources/scripts/app/fax/resources/scripts/queue/exec.lua delete mode 100644 app/scripts/resources/scripts/app/fax/resources/scripts/queue/next.lua delete mode 100644 app/scripts/resources/scripts/app/fax/resources/scripts/queue/retry.lua delete mode 100644 app/scripts/resources/scripts/app/fax/resources/scripts/queue/tasks.lua diff --git a/app/scripts/resources/scripts/app/fax/resources/scripts/queue/exec.lua b/app/scripts/resources/scripts/app/fax/resources/scripts/queue/exec.lua deleted file mode 100644 index c2ca5fad26..0000000000 --- a/app/scripts/resources/scripts/app/fax/resources/scripts/queue/exec.lua +++ /dev/null @@ -1,187 +0,0 @@ --- @usage without queue --- api: originate {fax_file='',wav_file='',fax_dtmf=''}user/108@domain.local &lua(app/fax/resources/scripts/queue/exec.lua) --- @usage with queue task --- api: originate {fax_task_uuid=''}user/108@domain.local &lua(app/fax/resources/scripts/queue/exec.lua) --- @fax_dtmf --- 0-9*# - dtmf symbols --- @200 - dtmf duration in ms --- p - pause 500 ms --- P - pause 1000 ms --- --- example: pause 5 sec dial 008 pause 2 sec play greeting --- PPPPP008@300PP --- - -require "resources.functions.config" -local log = require "resources.functions.log".fax_task - --- If we handle queue task -local fax_task_uuid = session:getVariable('fax_task_uuid') -local task if fax_task_uuid then - local Tasks = require "app.fax.resources.scripts.queue.tasks" - task = Tasks.select_task(fax_task_uuid) - if not task then - log.warningf("Can not found fax task: %q", tostring(fax_task_uuid)) - return - end -end - -if task then - local str = 'Queue task :' - for k, v in pairs(task) do - str = str .. ('\n %q = %q'):format(k, v) - end - log.info(str) -else - log.info('Not queued task') -end - -local function empty(t) return (not t) or (#t == 0) end - -local function not_empty(t) if not empty(t) then return t end end - -local dtmf, wav_file, fax_file - -if task then - dtmf = not_empty(task.dtmf) - wav_file = not_empty(task.wav_file) or not_empty(task.greeting) - fax_file = not_empty(task.fax_file) -else - dtmf = not_empty(session:getVariable('fax_dtmf')) - wav_file = not_empty(session:getVariable('wav_file')) - fax_file = not_empty(session:getVariable('fax_file')) -end - -if not (wav_file or fax_file) then - log.warning("No fax or wav file") - return -end - -local function decode_dtmf(dtmf) - local r, sleep, seq = {} - dtmf:gsub('P', 'pp'):gsub('.', function(ch) - if ch == ';' or ch == ',' then - r[#r + 1] = sleep or seq - sleep, seq = nil - elseif ch == 'p' then - r[#r + 1] = seq - sleep = (sleep or 0) + 500 - seq = nil - else - r[#r + 1] = sleep - seq = (seq or '') .. ch - sleep = nil - end - end) - r[#r + 1] = sleep or seq - return r -end - -local function send_fax() - session:execute("txfax", fax_file) -end - -local function start_fax_detect(detect_duration) - if not tone_detect_cb then - function tone_detect_cb(s, type, obj, arg) - if type == "event" then - if obj:getHeader('Event-Name') == 'DETECTED_TONE' then - return "false" - end - end - end - end - - log.notice("Start detecting fax") - - detect_duration = detect_duration or 60000 - - session:setInputCallback("tone_detect_cb") - session:execute("tone_detect", "txfax 2100 r +" .. tostring(detect_duration) .. " set remote_fax_detected=txfax") - session:execute("tone_detect", "rxfax 1100 r +" .. tostring(detect_duration) .. " set remote_fax_detected=rxfax") - session:setVariable("sip_api_on_image", "uuid_break " .. session:getVariable("uuid") .. " all") -end - -local function stop_fax_detect() - session:unsetInputCallback() - session:execute("stop_tone_detect") - session:setVariable("sip_api_on_image", "") -end - -local function fax_deteced() - if session:getVariable('has_t38') == 'true' then - log.noticef('Detected t38') - session:setVariable('remote_fax_detected', 'txfax') - end - - if fax_file and session:getVariable('remote_fax_detected') then - log.noticef("Detected %s", session:getVariable('remote_fax_detected')) - if session:getVariable('remote_fax_detected') == 'txfax' then - send_fax() - else - log.warning('Remote fax try send fax') - end - return true - end -end - -local function check() - if not session:ready() then return false end - if fax_deteced() then return false end - return true -end - -local function task() - local session_uuid = session:getVariable('uuid') - - session:setVariable('fax_queue_task_session', session_uuid) - - log.infof("SESSION UUID: %s", session_uuid) - - session:waitForAnswer(session) - - while not session:answered() do - if not session:ready() then return end - session:sleep(500) - end - - if not (session:ready() and session:answered()) then return end - - if fax_file and wav_file then - start_fax_detect() - end - - if dtmf then - dtmf = decode_dtmf(dtmf) - for _, element in ipairs(dtmf) do - if type(element) == 'number' then - session:streamFile("silence_stream://" .. tostring(element)) - else - session:execute("send_dtmf", element) - end - if not check() then return end - end - end - - if wav_file then - session:streamFile(wav_file) - if not check() then return end - end - - if fax_file then - if wav_file then - stop_fax_detect() - end - send_fax() - end -end - -log.noticef("START TASK") -log.notice("Fax:" .. tostring(fax_file)) -log.notice("Wav:" .. tostring(wav_file)) - -task() - -log.noticef("STOP TASK") -log.notice("Ready: " .. tostring(session:ready())) -log.notice("Answered: " .. tostring(session:answered())) diff --git a/app/scripts/resources/scripts/app/fax/resources/scripts/queue/next.lua b/app/scripts/resources/scripts/app/fax/resources/scripts/queue/next.lua deleted file mode 100644 index a4eee7e7ab..0000000000 --- a/app/scripts/resources/scripts/app/fax/resources/scripts/queue/next.lua +++ /dev/null @@ -1,98 +0,0 @@ -require "resources.functions.config" - -require "resources.functions.sleep" -require "resources.functions.file_exists" -local log = require "resources.functions.log".next_fax_task -local Tasks = require "app.fax.resources.scripts.queue.tasks" -local Esl = require "resources.functions.esl" - -local FAX_OPTIONS = { - "fax_use_ecm=false,fax_enable_t38=true,fax_enable_t38_request=true,fax_disable_v17=default"; - "fax_use_ecm=true,fax_enable_t38=true,fax_enable_t38_request=true,fax_disable_v17=false"; - "fax_use_ecm=true,fax_enable_t38=false,fax_enable_t38_request=false,fax_disable_v17=false"; - "fax_use_ecm=true,fax_enable_t38=true,fax_enable_t38_request=true,fax_disable_v17=true"; - "fax_use_ecm=false,fax_enable_t38=false,fax_enable_t38_request=false,fax_disable_v17=false"; -} - -local function task_send_mail(task, err) - local number_dialed = task.uri:match("/([^/]-)%s*$") - - local Text = require "resources.functions.text" - local text = Text.new("app.fax.app_languages") - - local env = { - destination_number = number_dialed:match("^([^@]*)"); - hangup_cause = err; - message = text['message-send_fail']; - } - - local body = Tasks.build_template(task, 'outbound/fail/body', env) - local subject = Tasks.build_template(task, 'outbound/fail/subject', env) - - if not subject then - log.warning("Can not find template for email") - subject = "Fax to: " .. number_dialed .. " FAILED" - end - - Tasks.send_mail_task(task, {subject, body}, nil, file_exists(task.fax_file)) -end - -local function next_task() - local task, err = Tasks.next_task() - - if not task then - if err then - log.noticef('Can not select next task: %s', tostring(err)) - else - log.notice("No task") - end - return - end - - local esl - local ok, err = pcall(function() - - local mode = (task.retry_counter % #FAX_OPTIONS) + 1 - local dial_string = '{' .. - task.dial_string .. "api_hangup_hook='lua app/fax/resources/scripts/queue/retry.lua'," .. - FAX_OPTIONS[mode] .. - '}' .. task.uri - - local originate = 'originate ' .. dial_string .. ' &lua(app/fax/resources/scripts/queue/exec.lua)' - - log.notice(originate) - esl = assert(Esl.new()) - local ok, status, info = esl:api(originate) - if not ok then - Tasks.wait_task(task, false, info) - if task.status ~= 0 then - Tasks.remove_task(task) - task_send_mail(task, tostring(info)) - end - log.noticef('Can not originate to `%s` cause: %s: %s ', task.uri, tostring(status), tostring(info)) - else - log.noticef("originate successfuly: %s", tostring(info)) - end - end) - - if esl then esl:close() end - - if not ok then - Tasks.release_task(task) - log.noticef("Error execute task: %s", tostring(err)) - end - - return true -end - -local function poll_once() - Tasks.cleanup_tasks() - while next_task() do - sleep(5000) - end - Tasks.release_db() -end - -return { - poll_once = poll_once; -} diff --git a/app/scripts/resources/scripts/app/fax/resources/scripts/queue/retry.lua b/app/scripts/resources/scripts/app/fax/resources/scripts/queue/retry.lua deleted file mode 100644 index f168ea1182..0000000000 --- a/app/scripts/resources/scripts/app/fax/resources/scripts/queue/retry.lua +++ /dev/null @@ -1,418 +0,0 @@ --- include libraries - require "resources.functions.config"; - require "resources.functions.split"; - require "resources.functions.file_exists"; - - local log = require "resources.functions.log".fax_retry - local Database = require "resources.functions.database" - local Settings = require "resources.functions.lazy_settings" - local Tasks = require "app.fax.resources.scripts.queue.tasks" - local send_mail = require "resources.functions.send_mail" - ---include json library - local json - if (debug["sql"]) then - json = require "resources.functions.lunajson" - end - - local fax_task_uuid = env:getHeader('fax_task_uuid') - if not fax_task_uuid then - log.warning("No [fax_task_uuid] channel variable") - return - end - local task = Tasks.select_task(fax_task_uuid) - if not task then - log.warningf("Can not find fax task: %q", tostring(fax_task_uuid)) - return - end - --- show all channel variables - if debug["fax_serialize"] then - log.noticef("info:\n%s", env:serialize()) - end - - local dbh = Database.new('system') - --- Global environment - default_language = env:getHeader("default_language") - default_dialect = env:getHeader("default_dialect") - --- Channel/FusionPBX variables - local uuid = env:getHeader("uuid") - local fax_queue_task_session = env:getHeader('fax_queue_task_session') - local domain_uuid = env:getHeader("domain_uuid") or task.domain_uuid - local domain_name = env:getHeader("domain_name") or task.domain_name - local origination_caller_id_name = env:getHeader("origination_caller_id_name") or '000000000000000' - local origination_caller_id_number = env:getHeader("origination_caller_id_number") or '000000000000000' - local accountcode = env:getHeader("accountcode") or domain_name - local duration = tonumber(env:getHeader("billmsec")) or 0 - local sip_to_user = env:getHeader("sip_to_user") - local bridge_hangup_cause = env:getHeader("bridge_hangup_cause") - local hangup_cause_q850 = tonumber(env:getHeader("hangup_cause_q850")) - local answered = duration > 0 - --- fax variables - local fax_success = env:getHeader('fax_success') - local has_t38 = env:getHeader('has_t38') or 'false' - local t38_broken_boolean = env:getHeader('t38_broken_boolean') or '' - local fax_result_code = tonumber(env:getHeader('fax_result_code')) or 2 - local fax_result_text = env:getHeader('fax_result_text') or 'FS_NOT_SET' - local fax_ecm_used = env:getHeader('fax_ecm_used') or '' - local fax_local_station_id = env:getHeader('fax_local_station_id') or '' - local fax_document_transferred_pages = env:getHeader('fax_document_transferred_pages') or nil - local fax_document_total_pages = env:getHeader('fax_document_total_pages') or nil - local fax_image_resolution = env:getHeader('fax_image_resolution') or '' - local fax_image_size = env:getHeader('fax_image_size') or nil - local fax_bad_rows = env:getHeader('fax_bad_rows') or nil - local fax_transfer_rate = env:getHeader('fax_transfer_rate') or nil - local fax_v17_disabled = env:getHeader('fax_v17_disabled') or '' - local fax_ecm_requested = env:getHeader('fax_ecm_requested') or '' - local fax_remote_station_id = env:getHeader('fax_remote_station_id') or '' - - local fax_options = ("fax_use_ecm=%s,fax_enable_t38=%s,fax_enable_t38_request=%s,fax_disable_v17=%s"):format( - env:getHeader('fax_use_ecm') or '', - env:getHeader('fax_enable_t38') or '', - env:getHeader('fax_enable_t38_request') or '', - env:getHeader('fax_disable_v17') or '' - ) - --- Fax task params - local fax_uri = env:getHeader("fax_uri") or task.uri - local fax_file = env:getHeader("fax_file") or task.fax_file - local wav_file = env:getHeader("wav_file") or task.wav_file - local fax_uuid = task.fax_uuid - local pdf_file = fax_file and string.gsub(fax_file, '(%.[^\\/]+)$', '.pdf') - --- Email variables - local number_dialed = fax_uri:match("/([^/]-)%s*$") - - log.noticef([[<<< CALL RESULT >>> - uuid: = '%s' - task_session_uuid: = '%s' - answered: = '%s' - fax_file: = '%s' - wav_file: = '%s' - fax_uri: = '%s' - sip_to_user: = '%s' - accountcode: = '%s' - origination_caller_id_name: = '%s' - origination_caller_id_number: = '%s' - mailto_address: = '%s' - hangup_cause_q850: = '%s' - fax_options = '%s' -]], - tostring(uuid) , - tostring(fax_queue_task_session) , - tostring(answered) , - tostring(fax_file) , - tostring(wav_file) , - tostring(fax_uri) , - tostring(sip_to_user) , - tostring(accountcode) , - tostring(origination_caller_id_name) , - tostring(origination_caller_id_number) , - tostring(task.reply_address) , - tostring(hangup_cause_q850) , - fax_options -) - - if fax_success then - log.noticef([[<<< FAX RESULT >>> - fax_success = '%s' - has_t38 = '%s' - t38_broken_boolean = '%s' - fax_result_code = '%s' - fax_result_text = '%s' - fax_ecm_used = '%s' - fax_local_station_id = '%s' - fax_document_transferred_pages = '%s' - fax_document_total_pages = '%s' - fax_image_resolution = '%s' - fax_image_size = '%s' - fax_bad_rows = '%s' - fax_transfer_rate = '%s' - fax_v17_disabled = '%s' - fax_ecm_requested = '%s' - fax_remote_station_id = '%s' - '%s' -]], - fax_success , - has_t38 , - t38_broken_boolean , - fax_result_code , - fax_result_text , - fax_ecm_used , - fax_local_station_id , - fax_document_transferred_pages , - fax_document_total_pages , - fax_image_resolution , - fax_image_size , - fax_bad_rows , - fax_transfer_rate , - fax_v17_disabled , - fax_ecm_requested , - fax_remote_station_id , - '---------------------------------' - ) - end - - log.debug([[<<< DEBUG >>> - domain_name = '%s' - domain_uuid = '%s' - task.domain_name = '%s' - task.domain_uuid = '%s' -]], - tostring(domain_name ), - tostring(domain_uuid ), - tostring(task.domain_name ), - tostring(task.domain_uuid ) -) - - assert(fax_uuid, 'no fax server uuid') - assert(domain_name, 'no domain name') - assert(domain_uuid, 'no domain uuid') - assert(domain_uuid:lower() == task.domain_uuid:lower(), 'invalid domain uuid') - assert(domain_name:lower() == task.domain_name:lower(), 'invalid domain name') - ---settings - local settings = Settings.new(dbh, domain_name, domain_uuid) - local keep_local = settings:get('fax', 'keep_local', 'boolean') - local storage_type = (keep_local == "false") and "" or settings:get('fax', 'storage_type', 'text') - - local function opt(v, default) - if v then return "'" .. v .. "'" end - return default or 'NULL' - end - - local function now_sql() - return (database["type"] == "sqlite") and "'"..os.date("%Y-%m-%d %X").."'" or "now()"; - end - ---add to fax logs - do - local fields = { - "fax_log_uuid"; - "domain_uuid"; - "fax_uuid"; - "fax_success"; - "fax_result_code"; - "fax_result_text"; - "fax_file"; - "fax_ecm_used"; - "fax_local_station_id"; - "fax_document_transferred_pages"; - "fax_document_total_pages"; - "fax_image_resolution"; - "fax_image_size"; - "fax_bad_rows"; - "fax_transfer_rate"; - "fax_retry_attempts"; - "fax_retry_limit"; - "fax_retry_sleep"; - "fax_uri"; - "fax_epoch"; - } - - local params = { - fax_log_uuid = uuid; - domain_uuid = domain_uuid; - fax_uuid = fax_uuid or dbh.NULL; - fax_success = fax_success or dbh.NULL; - fax_result_code = fax_result_code or dbh.NULL; - fax_result_text = fax_result_text or dbh.NULL; - fax_file = fax_file or dbh.NULL; - fax_ecm_used = fax_ecm_used or dbh.NULL; - fax_local_station_id = fax_local_station_id or dbh.NULL; - fax_document_transferred_pages = fax_document_transferred_pages or '0'; - fax_document_total_pages = fax_document_total_pages or '0'; - fax_image_resolution = fax_image_resolution or dbh.NULL; - fax_image_size = fax_image_size or dbh.NULL; - fax_bad_rows = fax_bad_rows or dbh.NULL; - fax_transfer_rate = fax_transfer_rate or dbh.NULL; - fax_retry_attempts = fax_retry_attempts or dbh.NULL; - fax_retry_limit = fax_retry_limit or dbh.NULL; - fax_retry_sleep = fax_retry_sleep or dbh.NULL; - fax_uri = fax_uri or dbh.NULL; - fax_epoch = os.time(); - } - - local values = ":" .. table.concat(fields, ",:") - fields = table.concat(fields, ",") .. ",fax_date" - - if database["type"] == "sqlite" then - params.fax_date = os.date("%Y-%m-%d %X"); - values = values .. ",:fax_date" - else - values = values .. ",now()" - end - - local sql = "insert into v_fax_logs(" .. fields .. ")values(" .. values .. ")" - - if (debug["sql"]) then - log.noticef("SQL: %s; params: %s", sql, json.encode(params, dbh.NULL)); - end - - dbh:query(sql, params); - end - --- add the fax files - if fax_success == "1" then - - if storage_type == "base64" then - --include the file io - local file = require "resources.functions.file" - - --read file content as base64 string - fax_base64 = file.read_base64(fax_file); - if not fax_base64 then - log.waitng("Can not find file %s", fax_file) - storage_type = nil - end - end - - -- build SQL - local sql do - - local fields = { - "fax_file_uuid"; - "fax_uuid"; - "fax_mode"; - "fax_destination"; - "fax_file_type"; - "fax_file_path"; - "fax_caller_id_name"; - "fax_caller_id_number"; - "fax_epoch"; - "fax_base64"; - "domain_uuid"; - } - - local params = { - fax_file_uuid = uuid; - fax_uuid = fax_uuid or dbh.NULL; - fax_mode = "tx"; - fax_destination = sip_to_user or dbh.NULL; - fax_file_type = "tif"; - fax_file_path = fax_file or dbh.NULL; - fax_caller_id_name = origination_caller_id_name or dbh.NULL; - fax_caller_id_number = origination_caller_id_number or dbh.NULL; - fax_epoch = os.time(); - fax_base64 = fax_base64 or dbh.NULL; - domain_uuid = domain_uuid or dbh.NULL; - } - - local values = ":" .. table.concat(fields, ",:") - fields = table.concat(fields, ",") .. ",fax_date" - - if database["type"] == "sqlite" then - params.fax_date = os.date("%Y-%m-%d %X"); - values = values .. ",:fax_date" - else - values = values .. ",now()" - end - - local sql = "insert into v_fax_files(" .. fields .. ")values(" .. values .. ")" - - if (debug["sql"]) then - log.noticef("SQL: %s; params: %s", sql, json.encode(params, dbh.NULL)); - end - - if storage_type == "base64" then - local dbh = Database.new('system', 'base64'); - dbh:query(sql, params); - dbh:release(); - else - dbh:query(sql, params) - end - end - end - - if fax_success == "1" then - --Success - log.infof("RETRY STATS SUCCESS: GATEWAY[%s]", fax_options); - - Tasks.remove_task(task) - - local Text = require "resources.functions.text" - local text = Text.new("app.fax.app_languages") - - local env = { - fax_options = fax_options; - destination_number = number_dialed:match("^([^@]*)"); - document_transferred_pages = fax_document_transferred_pages; - document_total_pages = fax_document_total_pages; - message = text['message-send_success']; - } - - local body = Tasks.build_template(task, 'outbound/success/body', env) - local subject = Tasks.build_template(task, 'outbound/success/subject', env) - - if not subject then - log.warning("Can not find template for email") - subject = "Fax to: " .. number_dialed .. " SENT" - end - - local attachment = pdf_file and file_exists(pdf_file) or fax_file and file_exists(fax_file) - Tasks.send_mail_task(task, {subject, body}, uuid, attachment) - - if keep_local == "false" then - os.remove(pdf_file); - os.remove(fax_file); - end - end - - if fax_success ~= "1" then - if not answered then - log.noticef("no answer: %d", hangup_cause_q850) - else - if not fax_success then - log.noticef("Fax not detected: %s", fax_options) - else - log.noticef("fax fail %s", fax_options) - end - end - - -- if task use group call then retry.lua will be called multiple times - -- here we check eathre that channel which execute `exec.lua` - -- Note that if there no one execute `exec.lua` we do not need call this - -- becase it should deal in `next.lua` - if fax_queue_task_session == uuid then - Tasks.wait_task(task, answered, hangup_cause_q850) - if task.status ~= 0 then - Tasks.remove_task(task) - - local Text = require "resources.functions.text" - local text = Text.new("app.fax.app_languages") - - local env = { - fax_options = fax_options; - destination_number = number_dialed:match("^([^@]*)"); - document_transferred_pages = fax_document_transferred_pages; - document_total_pages = fax_document_total_pages; - hangup_cause = hangup_cause; - hangup_cause_q850 = hangup_cause_q850; - fax_result_code = fax_result_code; - fax_result_text = fax_result_text; - message = text['message-send_fail']; - } - - local body = Tasks.build_template(task, 'outbound/fail/body', env) - local subject = Tasks.build_template(task, 'outbound/fail/subject', env) - - if not subject then - log.warning("Can not find template for email") - subject = "Fax to: " .. number_dialed .. " FAILED" - end - - local attachment = pdf_file and file_exists(pdf_file) or fax_file and file_exists(fax_file) - Tasks.send_mail_task(task, {subject, body}, uuid, attachment) - - if keep_local == "false" then - os.remove(pdf_file); - os.remove(fax_file); - end - - end - end - end - diff --git a/app/scripts/resources/scripts/app/fax/resources/scripts/queue/tasks.lua b/app/scripts/resources/scripts/app/fax/resources/scripts/queue/tasks.lua deleted file mode 100644 index df6dc57580..0000000000 --- a/app/scripts/resources/scripts/app/fax/resources/scripts/queue/tasks.lua +++ /dev/null @@ -1,330 +0,0 @@ -local Database = require "resources.functions.database" -local Settings = require "resources.functions.lazy_settings" -local send_mail = require "resources.functions.send_mail" - -local db - -local date_utc_now_sql -local now_add_sec_sql - -if database.type == 'pgsql' then - date_utc_now_sql = "NOW() at time zone 'utc'" - now_add_sec_sql = "NOW() at time zone 'utc' + interval '%s second'" -elseif database.type == 'mysql' then - date_utc_now_sql = "UTC_TIMESTAMP()" - now_add_sec_sql = "DATE_ADD(UTC_TIMESTAMP(), INTERVAL %s SECOND)" -elseif database.type == 'sqlite' then - date_utc_now_sql = "datetime('now')" - now_add_sec_sql = "datetime('now', '%s seconds')" -else - error("unsupported database type: " .. database.type) -end - --- Broken on FS 1.4 with native postgresql --- Fixed on 1.6.0 --- Also works with ODBC -local ignore_affected_rows = true -if dbh_affected_rows_broken ~= nil then - ignore_affected_rows = dbh_affected_rows_broken -end - -local Q850_TIMEOUT = { - [17] = 60; -} - -local select_task_common_sql = [[ -select - t1.fax_task_uuid as uuid, - t1.fax_uuid as fax_uuid, - t3.domain_name, - t3.domain_uuid, - t1.task_status as status, - t1.task_uri as uri, - t1.task_dial_string as dial_string, - t1.task_dtmf as dtmf, - t1.task_fax_file as fax_file, - t1.task_wav_file as wav_file, - t1.task_reply_address as reply_address, - t1.task_no_answer_counter as no_answer_counter, - t1.task_no_answer_retry_counter as no_answer_retry_counter, - t1.task_retry_counter as retry_counter, - t2.fax_send_greeting as greeting -from v_fax_tasks t1 - inner join v_fax t2 on t2.fax_uuid = t1.fax_uuid - inner join v_domains t3 on t2.domain_uuid = t3.domain_uuid -where t1.task_interrupted <> 'true' -]] - -local next_task_sql = select_task_common_sql .. [[ -and t1.task_status = 0 and t1.task_next_time < ]] .. date_utc_now_sql .. [[ -and t2.fax_send_channels > (select count(*) from v_fax_tasks as tasks - where tasks.fax_uuid = t1.fax_uuid and - tasks.task_status > 0 and tasks.task_status <= 2 -) -order by t1.task_next_time -]] - -local select_task_sql = select_task_common_sql .. "and t1.fax_task_uuid='%s'" - -local aquire_task_sql = [[ - update v_fax_tasks set task_status = 1, task_lock_time = ]] .. date_utc_now_sql .. [[ - where fax_task_uuid = '%s' and task_status = 0 -]] - -local wait_task_sql = [[ - update v_fax_tasks - set task_status = %s, - task_lock_time = NULL, - task_no_answer_counter = %s, - task_no_answer_retry_counter = %s, - task_retry_counter = %s, - task_next_time = ]] .. now_add_sec_sql .. [[ - where fax_task_uuid = '%s' -]] - -local remove_task_task_sql = [[ - delete from v_fax_tasks - where fax_task_uuid = '%s' -]] - -local release_task_sql = [[ - update v_fax_tasks - set task_status = 0, task_lock_time = NULL, - task_next_time = ]] .. now_add_sec_sql .. [[ - where fax_task_uuid = '%s' -]] - -local release_stuck_tasks_sql = [[ - update v_fax_tasks - set task_status = 0, task_lock_time = NULL, - task_next_time = ]] .. date_utc_now_sql .. [[ - where task_lock_time < ]] .. now_add_sec_sql:format('-3600') .. [[ -]] - -local remove_finished_tasks_sql = [[ - delete from v_fax_tasks where task_status > 3 -]] - -local function serialize(task, header) - local str = header or '' - for k, v in pairs(task) do - str = str .. ('\n %q = %q'):format(tostring(k), tostring(v)) - end - return str -end - -local function get_db() - if not db then - db = assert(Database.new('system')) - end - return db -end - -local function next_task() - local db = get_db() - - while true do - local task, err = db:first_row(next_task_sql) - if not task then return nil, err end - local ok, err = db:query( aquire_task_sql:format(task.uuid) ) - if not ok then return nil, err end - local rows = db:affected_rows() - if ignore_affected_rows then - rows = 1 - end - if rows == 1 then - task.no_answer_counter = tonumber(task.no_answer_counter) - task.no_answer_retry_counter = tonumber(task.no_answer_retry_counter) - task.retry_counter = tonumber(task.retry_counter) - return task - end - end -end - -local function select_task(fax_task_uuid) - local db = get_db() - - local task, err = db:first_row(select_task_sql:format(fax_task_uuid)) - if not task then return nil, err end - - task.no_answer_counter = tonumber(task.no_answer_counter) - task.no_answer_retry_counter = tonumber(task.no_answer_retry_counter) - task.retry_counter = tonumber(task.retry_counter) - - return task -end - -local function wait_task(task, answered, q850) - local db = get_db() - - local interval = 30 - - local settings = Settings.new(db, task.domain_name, task.domain_uuid) - task.status = 0 - - if not answered then - interval = Q850_TIMEOUT[q850 or 17] or interval - end - - if not answered then - local fax_send_no_answer_retry_limit = tonumber(settings:get('fax', 'send_no_answer_retry_limit', 'numeric')) or 0 - task.no_answer_retry_counter = task.no_answer_retry_counter + 1 - - if task.no_answer_retry_counter >= fax_send_no_answer_retry_limit then - task.no_answer_retry_counter = 0 - task.no_answer_counter = task.no_answer_counter + 1 - local fax_send_no_answer_limit = tonumber(settings:get('fax', 'send_no_answer_limit', 'numeric')) or 0 - if task.no_answer_counter >= fax_send_no_answer_limit then - task.status = 4 - else - interval = tonumber(settings:get('fax', 'send_no_answer_interval', 'numeric')) or interval - end - else - interval = tonumber(settings:get('fax', 'send_no_answer_retry_interval', 'numeric')) or interval - end - else - task.retry_counter = task.retry_counter + 1 - local fax_send_retry_limit = tonumber(settings:get('fax', 'send_retry_limit', 'numeric')) or 0 - - if task.retry_counter >= fax_send_retry_limit then - task.status = 4 - else - interval = tonumber(settings:get('fax', 'send_retry_interval', 'numeric')) or interval - task.task_seq_call_counter = 0 - end - end - - local sql = wait_task_sql:format( - tostring(task.status), - tostring(task.no_answer_counter), - tostring(task.no_answer_retry_counter), - tostring(task.retry_counter), - tostring(interval), - task.uuid - ) - - local ok, err = db:query( sql ) - - if not ok then return nil, err end - - return task -end - -local function remove_task(task) - local db = get_db() - - local sql = remove_task_task_sql:format(task.uuid) - local ok, err = db:query( sql ) - if not ok then return nil, err end - return db:affected_rows() -end - -local function release_task(task) - local db = get_db() - - local interval = 30 - - local sql = release_task_sql:format( - tostring(interval), - task.uuid - ) - - local ok, err = db:query( sql ) - - if not ok then return nil, err end - - return task -end - -local function cleanup_tasks() - local db = get_db() - - db:query(release_stuck_tasks_sql) - db:query(remove_finished_tasks_sql) -end - -local function send_mail_task(task, message, call_uuid, file) - if not task.reply_address or #task.reply_address == 0 then - return - end - - local mail_x_headers = { - ["X-FusionPBX-Domain-UUID"] = task.domain_uuid; - ["X-FusionPBX-Domain-Name"] = task.domain_name; - ["X-FusionPBX-Call-UUID"] = call_uuid; - ["X-FusionPBX-Email-Type"] = 'email2fax'; - } - - return send_mail(mail_x_headers, nil, task.reply_address, message, file) -end - -local function read_file(name, mode) - local f, err, code = io.open(name, mode or 'rb') - if not f then return nil, err, code end - local data = f:read("*all") - f:close() - return data -end - -local function read_template(app, name, lang) - local default_language_path = 'en/us' - - local full_path_tpl = scripts_dir .. '/app/' .. app .. '/resources/templates/{lang}/' .. name .. '.tpl' - - local path - - if lang then - path = file_exists((full_path_tpl:gsub('{lang}', lang))) - end - - if (not path) and (lang ~= default_language_path) then - path = file_exists((full_path_tpl:gsub('{lang}', default_language_path))) - end - - if path then - return read_file(path) - end -end - -local function build_template(task, templ, env) - local lang - - if default_language and default_dialect then - lang = (default_language .. '/' .. default_dialect):lower() - else - local settings = Settings.new(get_db(), task.domain_name, task.domain_uuid) - lang = settings:get('domain', 'language', 'code') - if lang then lang = lang:gsub('%-', '/'):lower() end - end - - local body = read_template('fax', templ, lang) - - body = body:gsub("[^\\](${.-})", function(name) - name = name:sub(3, -2) - if type(env) == 'table' then - return env[name] or '' - end - if type(env) == 'function' then - return env(name) or '' - end - end) - - return body -end - -return { - release_db = function() - if db then - db:release() - db = nil - end - end; - next_task = next_task; - wait_task = wait_task; - select_task = select_task; - remove_task = remove_task; - release_task = release_task; - cleanup_tasks = cleanup_tasks; - send_mail_task = send_mail_task; - build_template = build_template; -}