1-- include libraries 2 require "resources.functions.config"; 3 require "resources.functions.split"; 4 require "resources.functions.file_exists"; 5 6 local log = require "resources.functions.log".fax_retry 7 local Database = require "resources.functions.database" 8 local Settings = require "resources.functions.lazy_settings" 9 local Tasks = require "app.fax.resources.scripts.queue.tasks" 10 local send_mail = require "resources.functions.send_mail" 11 12--include json library 13 local json 14 if (debug["sql"]) then 15 json = require "resources.functions.lunajson" 16 end 17 18 local fax_task_uuid = env:getHeader('fax_task_uuid') 19 if not fax_task_uuid then 20 log.warning("No [fax_task_uuid] channel variable") 21 return 22 end 23 local task = Tasks.select_task(fax_task_uuid) 24 if not task then 25 log.warningf("Can not find fax task: %q", tostring(fax_task_uuid)) 26 return 27 end 28 29-- show all channel variables 30 if debug["fax_serialize"] then 31 log.noticef("info:\n%s", env:serialize()) 32 end 33 34 local dbh = Database.new('system') 35 36-- Global environment 37 default_language = env:getHeader("default_language") 38 default_dialect = env:getHeader("default_dialect") 39 40-- Channel/FusionPBX variables 41 local uuid = env:getHeader("uuid") 42 local fax_queue_task_session = env:getHeader('fax_queue_task_session') 43 local domain_uuid = env:getHeader("domain_uuid") or task.domain_uuid 44 local domain_name = env:getHeader("domain_name") or task.domain_name 45 local origination_caller_id_name = env:getHeader("origination_caller_id_name") or '000000000000000' 46 local origination_caller_id_number = env:getHeader("origination_caller_id_number") or '000000000000000' 47 local accountcode = env:getHeader("accountcode") or domain_name 48 local duration = tonumber(env:getHeader("billmsec")) or 0 49 local sip_to_user = env:getHeader("sip_to_user") 50 local bridge_hangup_cause = env:getHeader("bridge_hangup_cause") 51 local hangup_cause_q850 = tonumber(env:getHeader("hangup_cause_q850")) 52 local answered = duration > 0 53 54-- fax variables 55 local fax_success = env:getHeader('fax_success') 56 local has_t38 = env:getHeader('has_t38') or 'false' 57 local t38_broken_boolean = env:getHeader('t38_broken_boolean') or '' 58 local fax_result_code = tonumber(env:getHeader('fax_result_code')) or 2 59 local fax_result_text = env:getHeader('fax_result_text') or 'FS_NOT_SET' 60 local fax_ecm_used = env:getHeader('fax_ecm_used') or '' 61 local fax_local_station_id = env:getHeader('fax_local_station_id') or '' 62 local fax_document_transferred_pages = env:getHeader('fax_document_transferred_pages') or nil 63 local fax_document_total_pages = env:getHeader('fax_document_total_pages') or nil 64 local fax_image_resolution = env:getHeader('fax_image_resolution') or '' 65 local fax_image_size = env:getHeader('fax_image_size') or nil 66 local fax_bad_rows = env:getHeader('fax_bad_rows') or nil 67 local fax_transfer_rate = env:getHeader('fax_transfer_rate') or nil 68 local fax_v17_disabled = env:getHeader('fax_v17_disabled') or '' 69 local fax_ecm_requested = env:getHeader('fax_ecm_requested') or '' 70 local fax_remote_station_id = env:getHeader('fax_remote_station_id') or '' 71 72 local fax_options = ("fax_use_ecm=%s,fax_enable_t38=%s,fax_enable_t38_request=%s,fax_disable_v17=%s"):format( 73 env:getHeader('fax_use_ecm') or '', 74 env:getHeader('fax_enable_t38') or '', 75 env:getHeader('fax_enable_t38_request') or '', 76 env:getHeader('fax_disable_v17') or '' 77 ) 78 79-- Fax task params 80 local fax_uri = env:getHeader("fax_uri") or task.uri 81 local fax_file = env:getHeader("fax_file") or task.fax_file 82 local wav_file = env:getHeader("wav_file") or task.wav_file 83 local fax_uuid = task.fax_uuid 84 local pdf_file = fax_file and string.gsub(fax_file, '(%.[^\\/]+)$', '.pdf') 85 86-- Email variables 87 local number_dialed = fax_uri:match("/([^/]-)%s*$") 88 89 log.noticef([[<<< CALL RESULT >>> 90 uuid: = '%s' 91 task_session_uuid: = '%s' 92 answered: = '%s' 93 fax_file: = '%s' 94 wav_file: = '%s' 95 fax_uri: = '%s' 96 sip_to_user: = '%s' 97 accountcode: = '%s' 98 origination_caller_id_name: = '%s' 99 origination_caller_id_number: = '%s' 100 mailto_address: = '%s' 101 hangup_cause_q850: = '%s' 102 fax_options = '%s' 103]], 104 tostring(uuid) , 105 tostring(fax_queue_task_session) , 106 tostring(answered) , 107 tostring(fax_file) , 108 tostring(wav_file) , 109 tostring(fax_uri) , 110 tostring(sip_to_user) , 111 tostring(accountcode) , 112 tostring(origination_caller_id_name) , 113 tostring(origination_caller_id_number) , 114 tostring(task.reply_address) , 115 tostring(hangup_cause_q850) , 116 fax_options 117) 118 119 if fax_success then 120 log.noticef([[<<< FAX RESULT >>> 121 fax_success = '%s' 122 has_t38 = '%s' 123 t38_broken_boolean = '%s' 124 fax_result_code = '%s' 125 fax_result_text = '%s' 126 fax_ecm_used = '%s' 127 fax_local_station_id = '%s' 128 fax_document_transferred_pages = '%s' 129 fax_document_total_pages = '%s' 130 fax_image_resolution = '%s' 131 fax_image_size = '%s' 132 fax_bad_rows = '%s' 133 fax_transfer_rate = '%s' 134 fax_v17_disabled = '%s' 135 fax_ecm_requested = '%s' 136 fax_remote_station_id = '%s' 137 '%s' 138]], 139 fax_success , 140 has_t38 , 141 t38_broken_boolean , 142 fax_result_code , 143 fax_result_text , 144 fax_ecm_used , 145 fax_local_station_id , 146 fax_document_transferred_pages , 147 fax_document_total_pages , 148 fax_image_resolution , 149 fax_image_size , 150 fax_bad_rows , 151 fax_transfer_rate , 152 fax_v17_disabled , 153 fax_ecm_requested , 154 fax_remote_station_id , 155 '---------------------------------' 156 ) 157 end 158 159 log.debug([[<<< DEBUG >>> 160 domain_name = '%s' 161 domain_uuid = '%s' 162 task.domain_name = '%s' 163 task.domain_uuid = '%s' 164]], 165 tostring(domain_name ), 166 tostring(domain_uuid ), 167 tostring(task.domain_name ), 168 tostring(task.domain_uuid ) 169) 170 171 assert(fax_uuid, 'no fax server uuid') 172 assert(domain_name, 'no domain name') 173 assert(domain_uuid, 'no domain uuid') 174 assert(domain_uuid:lower() == task.domain_uuid:lower(), 'invalid domain uuid') 175 assert(domain_name:lower() == task.domain_name:lower(), 'invalid domain name') 176 177--settings 178 local settings = Settings.new(dbh, domain_name, domain_uuid) 179 local keep_local = settings:get('fax', 'keep_local', 'boolean') 180 local storage_type = (keep_local == "false") and "" or settings:get('fax', 'storage_type', 'text') 181 182 local function opt(v, default) 183 if v then return "'" .. v .. "'" end 184 return default or 'NULL' 185 end 186 187 local function now_sql() 188 return (database["type"] == "sqlite") and "'"..os.date("%Y-%m-%d %X").."'" or "now()"; 189 end 190 191--add to fax logs 192 do 193 local fields = { 194 "fax_log_uuid"; 195 "domain_uuid"; 196 "fax_uuid"; 197 "fax_success"; 198 "fax_result_code"; 199 "fax_result_text"; 200 "fax_file"; 201 "fax_ecm_used"; 202 "fax_local_station_id"; 203 "fax_document_transferred_pages"; 204 "fax_document_total_pages"; 205 "fax_image_resolution"; 206 "fax_image_size"; 207 "fax_bad_rows"; 208 "fax_transfer_rate"; 209 "fax_retry_attempts"; 210 "fax_retry_limit"; 211 "fax_retry_sleep"; 212 "fax_uri"; 213 "fax_epoch"; 214 } 215 216 local params = { 217 fax_log_uuid = uuid; 218 domain_uuid = domain_uuid; 219 fax_uuid = fax_uuid or dbh.NULL; 220 fax_success = fax_success or dbh.NULL; 221 fax_result_code = fax_result_code or dbh.NULL; 222 fax_result_text = fax_result_text or dbh.NULL; 223 fax_file = fax_file or dbh.NULL; 224 fax_ecm_used = fax_ecm_used or dbh.NULL; 225 fax_local_station_id = fax_local_station_id or dbh.NULL; 226 fax_document_transferred_pages = fax_document_transferred_pages or "'0'"; 227 fax_document_total_pages = fax_document_total_pages or "'0'"; 228 fax_image_resolution = fax_image_resolution or dbh.NULL; 229 fax_image_size = fax_image_size or dbh.NULL; 230 fax_bad_rows = fax_bad_rows or dbh.NULL; 231 fax_transfer_rate = fax_transfer_rate or dbh.NULL; 232 fax_retry_attempts = fax_retry_attempts or dbh.NULL; 233 fax_retry_limit = fax_retry_limit or dbh.NULL; 234 fax_retry_sleep = fax_retry_sleep or dbh.NULL; 235 fax_uri = fax_uri or dbh.NULL; 236 fax_epoch = os.time(); 237 } 238 239 local values = ":" .. table.concat(fields, ",:") 240 fields = table.concat(fields, ",") .. ",fax_date" 241 242 if database["type"] == "sqlite" then 243 params.fax_date = os.date("%Y-%m-%d %X"); 244 values = values .. ",:fax_date" 245 else 246 values = values .. ",now()" 247 end 248 249 local sql = "insert into v_fax_logs(" .. fields .. ")values(" .. values .. ")" 250 251 if (debug["sql"]) then 252 log.noticef("SQL: %s; params: %s", sql, json.encode(params, dbh.NULL)); 253 end 254 255 dbh:query(sql, params); 256 end 257 258-- add the fax files 259 if fax_success == "1" then 260 261 if storage_type == "base64" then 262 --include the file io 263 local file = require "resources.functions.file" 264 265 --read file content as base64 string 266 fax_base64 = file.read_base64(fax_file); 267 if not fax_base64 then 268 log.waitng("Can not find file %s", fax_file) 269 storage_type = nil 270 end 271 end 272 273 -- build SQL 274 local sql do 275 276 local fields = { 277 "fax_file_uuid"; 278 "fax_uuid"; 279 "fax_mode"; 280 "fax_destination"; 281 "fax_file_type"; 282 "fax_file_path"; 283 "fax_caller_id_name"; 284 "fax_caller_id_number"; 285 "fax_epoch"; 286 "fax_base64"; 287 "domain_uuid"; 288 } 289 290 local params = { 291 fax_file_uuid = uuid; 292 fax_uuid = fax_uuid or dbh.NULL; 293 fax_mode = "tx"; 294 fax_destination = sip_to_user or dbh.NULL; 295 fax_file_type = "tif"; 296 fax_file_path = fax_file or dbh.NULL; 297 fax_caller_id_name = origination_caller_id_name or dbh.NULL; 298 fax_caller_id_number = origination_caller_id_number or dbh.NULL; 299 fax_epoch = os.time(); 300 fax_base64 = fax_base64 or dbh.NULL; 301 domain_uuid = domain_uuid or dbh.NULL; 302 } 303 304 local values = ":" .. table.concat(fields, ",:") 305 fields = table.concat(fields, ",") .. ",fax_date" 306 307 if database["type"] == "sqlite" then 308 params.fax_date = os.date("%Y-%m-%d %X"); 309 values = values .. ",:fax_date" 310 else 311 values = values .. ",now()" 312 end 313 314 local sql = "insert into v_fax_files(" .. fields .. ")values(" .. values .. ")" 315 316 if (debug["sql"]) then 317 log.noticef("SQL: %s; params: %s", sql, json.encode(params, dbh.NULL)); 318 end 319 320 if storage_type == "base64" then 321 local dbh = Database.new('system', 'base64'); 322 dbh:query(sql, params); 323 dbh:release(); 324 else 325 dbh:query(sql, params) 326 end 327 end 328 end 329 330 if fax_success == "1" then 331 --Success 332 log.infof("RETRY STATS SUCCESS: GATEWAY[%s]", fax_options); 333 334 Tasks.remove_task(task) 335 336 local Text = require "resources.functions.text" 337 local text = Text.new("app.fax.app_languages") 338 339 local env = { 340 fax_options = fax_options; 341 destination_number = number_dialed:match("^([^@]*)"); 342 document_transferred_pages = fax_document_transferred_pages; 343 document_total_pages = fax_document_total_pages; 344 message = text['message-send_success']; 345 } 346 347 local body = Tasks.build_template(task, 'outbound/success/body', env) 348 local subject = Tasks.build_template(task, 'outbound/success/subject', env) 349 350 if not subject then 351 log.warning("Can not find template for email") 352 subject = "Fax to: " .. number_dialed .. " SENT" 353 end 354 355 local attachment = pdf_file and file_exists(pdf_file) or fax_file and file_exists(fax_file) 356 Tasks.send_mail_task(task, {subject, body}, uuid, attachment) 357 358 if keep_local == "false" then 359 os.remove(pdf_file); 360 os.remove(fax_file); 361 end 362 end 363 364 if fax_success ~= "1" then 365 if not answered then 366 log.noticef("no answer: %d", hangup_cause_q850) 367 else 368 if not fax_success then 369 log.noticef("Fax not detected: %s", fax_options) 370 else 371 log.noticef("fax fail %s", fax_options) 372 end 373 end 374 375 -- if task use group call then retry.lua will be called multiple times 376 -- here we check eathre that channel which execute `exec.lua` 377 -- Note that if there no one execute `exec.lua` we do not need call this 378 -- becase it should deal in `next.lua` 379 if fax_queue_task_session == uuid then 380 Tasks.wait_task(task, answered, hangup_cause_q850) 381 if task.status ~= 0 then 382 Tasks.remove_task(task) 383 384 local Text = require "resources.functions.text" 385 local text = Text.new("app.fax.app_languages") 386 387 local env = { 388 fax_options = fax_options; 389 destination_number = number_dialed:match("^([^@]*)"); 390 document_transferred_pages = fax_document_transferred_pages; 391 document_total_pages = fax_document_total_pages; 392 hangup_cause = hangup_cause; 393 hangup_cause_q850 = hangup_cause_q850; 394 fax_result_code = fax_result_code; 395 fax_result_text = fax_result_text; 396 message = text['message-send_fail']; 397 } 398 399 local body = Tasks.build_template(task, 'outbound/fail/body', env) 400 local subject = Tasks.build_template(task, 'outbound/fail/subject', env) 401 402 if not subject then 403 log.warning("Can not find template for email") 404 subject = "Fax to: " .. number_dialed .. " FAILED" 405 end 406 407 local attachment = pdf_file and file_exists(pdf_file) or fax_file and file_exists(fax_file) 408 Tasks.send_mail_task(task, {subject, body}, uuid, attachment) 409 410 if keep_local == "false" then 411 os.remove(pdf_file); 412 os.remove(fax_file); 413 end 414 415 end 416 end 417 end 418 419