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