Improve T.38 negotiation by exchanging session parameters between application and...
[asterisk/asterisk.git] / apps / app_fax.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Simple fax applications
5  * 
6  * 2007-2008, Dmitry Andrianov <asterisk@dima.spb.ru>
7  *
8  * Code based on original implementation by Steve Underwood <steveu@coppice.org>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  *
13  */
14
15 /*** MODULEINFO
16          <depend>spandsp</depend>
17 ***/
18  
19 #include "asterisk.h"
20
21 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
22
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <inttypes.h>
27 #include <pthread.h>
28 #include <errno.h>
29 #include <tiffio.h>
30
31 #include <spandsp.h>
32 #ifdef HAVE_SPANDSP_EXPOSE_H
33 #include <spandsp/expose.h>
34 #endif
35 #include <spandsp/version.h>
36
37 #include "asterisk/lock.h"
38 #include "asterisk/file.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/app.h"
43 #include "asterisk/dsp.h"
44 #include "asterisk/module.h"
45 #include "asterisk/manager.h"
46
47 /*** DOCUMENTATION
48         <application name="SendFAX" language="en_US">
49                 <synopsis>
50                         Send a Fax
51                 </synopsis>
52                 <syntax>
53                         <parameter name="filename" required="true">
54                                 <para>Filename of TIFF file to fax</para>
55                         </parameter>
56                         <parameter name="a" required="false">
57                                 <para>Makes the application behave as the answering machine</para>
58                                 <para>(Default behavior is as calling machine)</para>
59                         </parameter>
60                 </syntax>
61                 <description>
62                         <para>Send a given TIFF file to the channel as a FAX.</para>
63                         <para>This application sets the following channel variables:</para>
64                         <variablelist>
65                                 <variable name="LOCALSTATIONID">
66                                         <para>To identify itself to the remote end</para>
67                                 </variable>
68                                 <variable name="LOCALHEADERINFO">
69                                         <para>To generate a header line on each page</para>
70                                 </variable>
71                                 <variable name="FAXSTATUS">
72                                         <value name="SUCCESS"/>
73                                         <value name="FAILED"/>
74                                 </variable>
75                                 <variable name="FAXERROR">
76                                         <para>Cause of failure</para>
77                                 </variable>
78                                 <variable name="REMOTESTATIONID">
79                                         <para>The CSID of the remote side</para>
80                                 </variable>
81                                 <variable name="FAXPAGES">
82                                         <para>Number of pages sent</para>
83                                 </variable>
84                                 <variable name="FAXBITRATE">
85                                         <para>Transmission rate</para>
86                                 </variable>
87                                 <variable name="FAXRESOLUTION">
88                                         <para>Resolution of sent fax</para>
89                                 </variable>
90                         </variablelist>
91                 </description>
92         </application>
93         <application name="ReceiveFAX" language="en_US">
94                 <synopsis>
95                         Receive a Fax
96                 </synopsis>
97                 <syntax>
98                         <parameter name="filename" required="true">
99                                 <para>Filename of TIFF file save incoming fax</para>
100                         </parameter>
101                         <parameter name="c" required="false">
102                                 <para>Makes the application behave as the calling machine</para> 
103                                 <para>(Default behavior is as answering machine)</para>
104                         </parameter>
105                 </syntax>
106                 <description>
107                         <para>Receives a FAX from the channel into the given filename 
108                         overwriting the file if it already exists.</para>
109                         <para>File created will be in TIFF format.</para>
110
111                         <para>This application sets the following channel variables:</para>
112                         <variablelist>
113                                 <variable name="LOCALSTATIONID">
114                                         <para>To identify itself to the remote end</para>
115                                 </variable>
116                                 <variable name="LOCALHEADERINFO">
117                                         <para>To generate a header line on each page</para>
118                                 </variable>
119                                 <variable name="FAXSTATUS">
120                                         <value name="SUCCESS"/>
121                                         <value name="FAILED"/>
122                                 </variable>
123                                 <variable name="FAXERROR">
124                                         <para>Cause of failure</para>
125                                 </variable>
126                                 <variable name="REMOTESTATIONID">
127                                         <para>The CSID of the remote side</para>
128                                 </variable>
129                                 <variable name="FAXPAGES">
130                                         <para>Number of pages sent</para>
131                                 </variable>
132                                 <variable name="FAXBITRATE">
133                                         <para>Transmission rate</para>
134                                 </variable>
135                                 <variable name="FAXRESOLUTION">
136                                         <para>Resolution of sent fax</para>
137                                 </variable>
138                         </variablelist>
139                 </description>
140         </application>
141
142  ***/
143
144 static const char app_sndfax_name[] = "SendFAX";
145 static const char app_rcvfax_name[] = "ReceiveFAX";
146
147 #define MAX_SAMPLES 240
148
149 /* Watchdog. I have seen situations when remote fax disconnects (because of poor line
150    quality) while SpanDSP continues staying in T30_STATE_IV_CTC state forever.
151    To avoid this, we terminate when we see that T30 state does not change for 5 minutes.
152    We also terminate application when more than 30 minutes passed regardless of
153    state changes. This is just a precaution measure - no fax should take that long */
154
155 #define WATCHDOG_TOTAL_TIMEOUT  30 * 60
156 #define WATCHDOG_STATE_TIMEOUT  5 * 60
157
158 typedef struct {
159         struct ast_channel *chan;
160         enum ast_t38_state t38state;    /* T38 state of the channel */
161         int direction;                  /* Fax direction: 0 - receiving, 1 - sending */
162         int caller_mode;
163         char *file_name;
164         struct ast_control_t38_parameters t38parameters;
165         volatile int finished;
166 } fax_session;
167
168 static void span_message(int level, const char *msg)
169 {
170         if (level == SPAN_LOG_ERROR) {
171                 ast_log(LOG_ERROR, "%s", msg);
172         } else if (level == SPAN_LOG_WARNING) {
173                 ast_log(LOG_WARNING, "%s", msg);
174         } else {
175                 ast_log(LOG_DEBUG, "%s", msg);
176         }
177 }
178
179 static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
180 {
181         struct ast_channel *chan = (struct ast_channel *) user_data;
182
183         struct ast_frame outf = {
184                 .frametype = AST_FRAME_MODEM,
185                 .subclass = AST_MODEM_T38,
186                 .src = __FUNCTION__,
187         };
188
189         /* TODO: Asterisk does not provide means of resending the same packet multiple
190           times so count is ignored at the moment */
191
192         AST_FRAME_SET_BUFFER(&outf, buf, 0, len);
193
194         if (ast_write(chan, &outf) < 0) {
195                 ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
196                 return -1;
197         }
198
199         return 0;
200 }
201
202 static void phase_e_handler(t30_state_t *f, void *user_data, int result)
203 {
204         const char *local_ident;
205         const char *far_ident;
206         char buf[20];
207         fax_session *s = (fax_session *) user_data;
208         t30_stats_t stat;
209         int pages_transferred;
210
211         ast_debug(1, "Fax phase E handler. result=%d\n", result);
212
213         t30_get_transfer_statistics(f, &stat);
214
215         s = (fax_session *) user_data;
216
217         if (result != T30_ERR_OK) {
218                 s->finished = -1;
219
220                 /* FAXSTATUS is already set to FAILED */
221                 pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));
222
223                 ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));
224
225                 return;
226         }
227         
228         s->finished = 1; 
229         
230         local_ident = t30_get_tx_ident(f);
231         far_ident = t30_get_rx_ident(f);
232         pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS"); 
233         pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL); 
234         pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
235 #if SPANDSP_RELEASE_DATE >= 20090220
236         pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx;
237 #else
238         pages_transferred = stat.pages_transferred;
239 #endif
240         snprintf(buf, sizeof(buf), "%d", pages_transferred);
241         pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
242         snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
243         pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
244         snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
245         pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf); 
246         
247         ast_debug(1, "Fax transmitted successfully.\n");
248         ast_debug(1, "  Remote station ID: %s\n", far_ident);
249         ast_debug(1, "  Pages transferred: %d\n", pages_transferred);
250         ast_debug(1, "  Image resolution:  %d x %d\n", stat.x_resolution, stat.y_resolution);
251         ast_debug(1, "  Transfer Rate:     %d\n", stat.bit_rate);
252         
253         manager_event(EVENT_FLAG_CALL,
254                       s->direction ? "FaxSent" : "FaxReceived", 
255                       "Channel: %s\r\n"
256                       "Exten: %s\r\n"
257                       "CallerID: %s\r\n"
258                       "RemoteStationID: %s\r\n"
259                       "LocalStationID: %s\r\n"
260                       "PagesTransferred: %d\r\n"
261                       "Resolution: %d\r\n"
262                       "TransferRate: %d\r\n"
263                       "FileName: %s\r\n",
264                       s->chan->name,
265                       s->chan->exten,
266                       S_OR(s->chan->cid.cid_num, ""),
267                       far_ident,
268                       local_ident,
269                       pages_transferred,
270                       stat.y_resolution,
271                       stat.bit_rate,
272                       s->file_name);
273 }
274
275 /* === Helper functions to configure fax === */
276
277 /* Setup SPAN logging according to Asterisk debug level */
278 static int set_logging(logging_state_t *state)
279 {
280         int level = SPAN_LOG_WARNING + option_debug;
281
282         span_log_set_message_handler(state, span_message);
283         span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level); 
284
285         return 0;
286 }
287
288 static void set_local_info(t30_state_t *state, fax_session *s)
289 {
290         const char *x;
291
292         x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID");
293         if (!ast_strlen_zero(x))
294                 t30_set_tx_ident(state, x);
295
296         x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO");
297         if (!ast_strlen_zero(x))
298                 t30_set_tx_page_header_info(state, x);
299 }
300
301 static void set_file(t30_state_t *state, fax_session *s)
302 {
303         if (s->direction)
304                 t30_set_tx_file(state, s->file_name, -1, -1);
305         else
306                 t30_set_rx_file(state, s->file_name, -1);
307 }
308
309 static void set_ecm(t30_state_t *state, int ecm)
310 {
311         t30_set_ecm_capability(state, ecm);
312         t30_set_supported_compressions(state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
313 }
314
315 /* === Generator === */
316
317 /* This function is only needed to return passed params so
318    generator_activate will save it to channel's generatordata */
319 static void *fax_generator_alloc(struct ast_channel *chan, void *params)
320 {
321         return params;
322 }
323
324 static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
325 {
326         fax_state_t *fax = (fax_state_t*) data;
327         uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
328         int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
329     
330         struct ast_frame outf = {
331                 .frametype = AST_FRAME_VOICE,
332                 .subclass = AST_FORMAT_SLINEAR,
333                 .src = __FUNCTION__,
334         };
335
336         if (samples > MAX_SAMPLES) {
337                 ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
338                 samples = MAX_SAMPLES;
339         }
340         
341         if ((len = fax_tx(fax, buf, samples)) > 0) {
342                 outf.samples = len;
343                 AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
344
345                 if (ast_write(chan, &outf) < 0) {
346                         ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
347                         return -1;
348                 }
349         }
350
351         return 0;
352 }
353
354 static struct ast_generator generator = {
355         alloc:          fax_generator_alloc,
356         generate:       fax_generator_generate,
357 };
358
359
360 /* === Transmission === */
361
362 static int transmit_audio(fax_session *s)
363 {
364         int res = -1;
365         int original_read_fmt = AST_FORMAT_SLINEAR;
366         int original_write_fmt = AST_FORMAT_SLINEAR;
367         fax_state_t fax;
368         t30_state_t *t30state;
369         struct ast_dsp *dsp = NULL;
370         int detect_tone = 0;
371         struct ast_frame *inf = NULL;
372         struct ast_frame *fr;
373         int last_state = 0;
374         struct timeval now, start, state_change;
375
376 #if SPANDSP_RELEASE_DATE >= 20080725
377         /* for spandsp shaphots 0.0.6 and higher */
378         t30state = &fax.t30;
379 #else
380         /* for spandsp release 0.0.5 */
381         t30state = &fax.t30_state;
382 #endif
383
384         original_read_fmt = s->chan->readformat;
385         if (original_read_fmt != AST_FORMAT_SLINEAR) {
386                 res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR);
387                 if (res < 0) {
388                         ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
389                         goto done;
390                 }
391         }
392
393         original_write_fmt = s->chan->writeformat;
394         if (original_write_fmt != AST_FORMAT_SLINEAR) {
395                 res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR);
396                 if (res < 0) {
397                         ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
398                         goto done;
399                 }
400         }
401
402         /* Initialize T30 terminal */
403         fax_init(&fax, s->caller_mode);
404
405         /* Setup logging */
406         set_logging(&fax.logging);
407         set_logging(&t30state->logging);
408
409         /* Configure terminal */
410         set_local_info(t30state, s);
411         set_file(t30state, s);
412         set_ecm(t30state, TRUE);
413
414         fax_set_transmit_on_idle(&fax, TRUE);
415
416         t30_set_phase_e_handler(t30state, phase_e_handler, s);
417
418         if (s->t38state == T38_STATE_UNAVAILABLE) {
419                 ast_debug(1, "T38 is unavailable on %s\n", s->chan->name);
420         } else if (!s->direction) {
421                 /* We are receiving side and this means we are the side which should
422                    request T38 when the fax is detected. Use DSP to detect fax tone */
423                 ast_debug(1, "Setting up CNG detection on %s\n", s->chan->name);
424                 dsp = ast_dsp_new();
425                 ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
426                 ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG);
427                 detect_tone = 1;
428         }
429
430         start = state_change = ast_tvnow();
431
432         ast_activate_generator(s->chan, &generator, &fax);
433
434         while (!s->finished) {
435                 res = ast_waitfor(s->chan, 20);
436                 if (res < 0)
437                         break;
438                 else if (res > 0)
439                         res = 0;
440
441                 inf = ast_read(s->chan);
442                 if (inf == NULL) {
443                         ast_debug(1, "Channel hangup\n");
444                         res = -1;
445                         break;
446                 }
447
448                 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
449
450                 /* Detect fax tone */
451                 if (detect_tone && inf->frametype == AST_FRAME_VOICE) {
452                         /* Duplicate frame because ast_dsp_process may free the frame passed */
453                         fr = ast_frdup(inf);
454
455                         /* Do not pass channel to ast_dsp_process otherwise it may queue modified audio frame back */
456                         fr = ast_dsp_process(NULL, dsp, fr);
457                         if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') {
458                                 struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_NEGOTIATE,
459                                                                                  .version = 0,
460                                                                                  .max_datagram = 400,
461                                                                                  .rate = AST_T38_RATE_9600,
462                                                                                  .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERED_TCF,
463                                                                                  .fill_bit_removal = 1,
464                                                                                  .transcoding_mmr = 1,
465                                 };
466                                 ast_debug(1, "Fax tone detected. Requesting T38\n");
467                                 ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
468                                 detect_tone = 0;
469                         }
470
471                         ast_frfree(fr);
472                 }
473
474
475                 /* Check the frame type. Format also must be checked because there is a chance
476                    that a frame in old format was already queued before we set chanel format
477                    to slinear so it will still be received by ast_read */
478                 if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) {
479
480                         if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
481                                 /* I know fax_rx never returns errors. The check here is for good style only */
482                                 ast_log(LOG_WARNING, "fax_rx returned error\n");
483                                 res = -1;
484                                 break;
485                         }
486
487                         /* Watchdog */
488                         if (last_state != t30state->state) {
489                                 state_change = ast_tvnow();
490                                 last_state = t30state->state;
491                         }
492                 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38_PARAMETERS) {
493                         struct ast_control_t38_parameters *parameters = inf->data.ptr;
494                         if (parameters->request_response == AST_T38_NEGOTIATED) {
495                                 /* T38 switchover completed */
496                                 s->t38parameters = *parameters;
497                                 ast_debug(1, "T38 negotiated, finishing audio loop\n");
498                                 res = 1;
499                                 break;
500                         }
501                 }
502
503                 ast_frfree(inf);
504                 inf = NULL;
505
506                 /* Watchdog */
507                 now = ast_tvnow();
508                 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
509                         ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
510                         res = -1;
511                         break;
512                 }
513         }
514
515         ast_debug(1, "Loop finished, res=%d\n", res);
516
517         if (inf)
518                 ast_frfree(inf);
519
520         if (dsp)
521                 ast_dsp_free(dsp);
522
523         ast_deactivate_generator(s->chan);
524
525         /* If we are switching to T38, remove phase E handler. Otherwise it will be executed
526            by t30_terminate, display diagnostics and set status variables although no transmittion
527            has taken place yet. */
528         if (res > 0) {
529                 t30_set_phase_e_handler(t30state, NULL, NULL);
530         }
531
532         t30_terminate(t30state);
533         fax_release(&fax);
534
535 done:
536         if (original_write_fmt != AST_FORMAT_SLINEAR) {
537                 if (ast_set_write_format(s->chan, original_write_fmt) < 0)
538                         ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name);
539         }
540
541         if (original_read_fmt != AST_FORMAT_SLINEAR) {
542                 if (ast_set_read_format(s->chan, original_read_fmt) < 0)
543                         ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name);
544         }
545
546         return res;
547
548 }
549
550 static int transmit_t38(fax_session *s)
551 {
552         int res = 0;
553         t38_terminal_state_t t38;
554         struct ast_frame *inf = NULL;
555         int last_state = 0;
556         struct timeval now, start, state_change, last_frame;
557         t30_state_t *t30state;
558         t38_core_state_t *t38state;
559
560 #if SPANDSP_RELEASE_DATE >= 20080725
561         /* for spandsp shaphots 0.0.6 and higher */
562         t30state = &t38.t30;
563         t38state = &t38.t38_fe.t38;
564 #else
565         /* for spandsp releases 0.0.5 */
566         t30state = &t38.t30_state;
567         t38state = &t38.t38;
568 #endif
569
570         /* Initialize terminal */
571         memset(&t38, 0, sizeof(t38));
572         if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
573                 ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
574                 return -1;
575         }
576
577         t38_set_max_datagram_size(t38state, s->t38parameters.max_datagram);
578
579         if (s->t38parameters.fill_bit_removal) {
580                 t38_set_fill_bit_removal(t38state, TRUE);
581         }
582         if (s->t38parameters.transcoding_mmr) {
583                 t38_set_mmr_transcoding(t38state, TRUE);
584         } else if (s->t38parameters.transcoding_jbig) {
585                 t38_set_jbig_transcoding(t38state, TRUE);
586         }
587
588         /* Setup logging */
589         set_logging(&t38.logging);
590         set_logging(&t30state->logging);
591         set_logging(&t38state->logging);
592
593         /* Configure terminal */
594         set_local_info(t30state, s);
595         set_file(t30state, s);
596         set_ecm(t30state, TRUE);
597
598         t30_set_phase_e_handler(t30state, phase_e_handler, s);
599
600         now = start = state_change = ast_tvnow();
601
602         while (!s->finished) {
603
604                 res = ast_waitfor(s->chan, 20);
605                 if (res < 0)
606                         break;
607                 else if (res > 0)
608                         res = 0;
609
610                 last_frame = now;
611                 now = ast_tvnow();
612                 t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
613
614                 inf = ast_read(s->chan);
615                 if (inf == NULL) {
616                         ast_debug(1, "Channel hangup\n");
617                         res = -1;
618                         break;
619                 }
620
621                 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
622
623                 if (inf->frametype == AST_FRAME_MODEM && inf->subclass == AST_MODEM_T38) {
624                         t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
625
626                         /* Watchdog */
627                         if (last_state != t30state->state) {
628                                 state_change = ast_tvnow();
629                                 last_state = t30state->state;
630                         }
631                 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38_PARAMETERS) {
632                         struct ast_control_t38_parameters *parameters = inf->data.ptr;
633                         if (parameters->request_response == AST_T38_TERMINATED || parameters->request_response == AST_T38_REFUSED) {
634                                 ast_debug(1, "T38 down, terminating\n");
635                                 res = -1;
636                                 break;
637                         }
638                 }
639
640                 ast_frfree(inf);
641                 inf = NULL;
642
643                 /* Watchdog */
644                 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
645                         ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
646                         res = -1;
647                         break;
648                 }
649         }
650
651         ast_debug(1, "Loop finished, res=%d\n", res);
652
653         if (inf)
654                 ast_frfree(inf);
655
656         t30_terminate(t30state);
657         t38_terminal_release(&t38);
658
659         return res;
660 }
661
662 static int transmit(fax_session *s)
663 {
664         int res = 0;
665
666         /* Clear all channel variables which to be set by the application.
667            Pre-set status to error so in case of any problems we can just leave */
668         pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
669         pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 
670
671         pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
672         pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
673         pbx_builtin_setvar_helper(s->chan, "FAXPAGES", NULL);
674         pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
675         pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); 
676
677         if (s->chan->_state != AST_STATE_UP) {
678                 /* Shouldn't need this, but checking to see if channel is already answered
679                  * Theoretically asterisk should already have answered before running the app */
680                 res = ast_answer(s->chan);
681                 if (res) {
682                         ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
683                         return res;
684                 }
685         }
686
687         s->t38state = ast_channel_get_t38_state(s->chan);
688         if (s->t38state != T38_STATE_NEGOTIATED) {
689                 /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */ 
690                 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio"); 
691                 res = transmit_audio(s);
692                 if (res > 0) {
693                         /* transmit_audio reports switchover to T38. Update t38state */
694                         s->t38state = ast_channel_get_t38_state(s->chan);
695                         if (s->t38state != T38_STATE_NEGOTIATED) {
696                                 ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
697                         }
698                 }
699         }
700
701         if (s->t38state == T38_STATE_NEGOTIATED) {
702                 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38"); 
703                 res = transmit_t38(s);
704         }
705
706         if (res) {
707                 ast_log(LOG_WARNING, "Transmission error\n");
708                 res = -1;
709         } else if (s->finished < 0) {
710                 ast_log(LOG_WARNING, "Transmission failed\n");
711         } else if (s->finished > 0) {
712                 ast_debug(1, "Transmission finished Ok\n");
713         }
714
715         return res;
716 }
717
718 /* === Application functions === */
719
720 static int sndfax_exec(struct ast_channel *chan, const char *data)
721 {
722         int res = 0;
723         char *parse;
724         fax_session session = { 0, };
725         char restore_digit_detect = 0;
726
727         AST_DECLARE_APP_ARGS(args,
728                 AST_APP_ARG(file_name);
729                 AST_APP_ARG(options);
730         );
731
732         if (chan == NULL) {
733                 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
734                 return -1;
735         }
736
737         /* The next few lines of code parse out the filename and header from the input string */
738         if (ast_strlen_zero(data)) {
739                 /* No data implies no filename or anything is present */
740                 ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
741                 return -1;
742         }
743
744         parse = ast_strdupa(data);
745         AST_STANDARD_APP_ARGS(args, parse);
746         
747         session.caller_mode = TRUE;
748
749         if (args.options) {
750                 if (strchr(args.options, 'a'))
751                         session.caller_mode = FALSE;
752         }
753
754         /* Done parsing */
755         session.direction = 1;
756         session.file_name = args.file_name;
757         session.chan = chan;
758         session.finished = 0;
759
760         /* get current digit detection mode, then disable digit detection if enabled */
761         {
762                 int dummy = sizeof(restore_digit_detect);
763
764                 ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
765         }
766
767         if (restore_digit_detect) {
768                 char new_digit_detect = 0;
769
770                 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
771         }
772
773         /* disable FAX tone detection if enabled */
774         {
775                 char new_fax_detect = 0;
776
777                 ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
778         }
779
780         res = transmit(&session);
781
782         if (restore_digit_detect) {
783                 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
784         }
785
786         return res;
787 }
788
789 static int rcvfax_exec(struct ast_channel *chan, const char *data)
790 {
791         int res = 0;
792         char *parse;
793         fax_session session;
794         char restore_digit_detect = 0;
795
796         AST_DECLARE_APP_ARGS(args,
797                 AST_APP_ARG(file_name);
798                 AST_APP_ARG(options);
799         );
800
801         if (chan == NULL) {
802                 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
803                 return -1;
804         }
805
806         /* The next few lines of code parse out the filename and header from the input string */
807         if (ast_strlen_zero(data)) {
808                 /* No data implies no filename or anything is present */
809                 ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
810                 return -1;
811         }
812
813         parse = ast_strdupa(data);
814         AST_STANDARD_APP_ARGS(args, parse);
815         
816         session.caller_mode = FALSE;
817
818         if (args.options) {
819                 if (strchr(args.options, 'c'))
820                         session.caller_mode = TRUE;
821         }
822
823         /* Done parsing */
824         session.direction = 0;
825         session.file_name = args.file_name;
826         session.chan = chan;
827         session.finished = 0;
828
829         /* get current digit detection mode, then disable digit detection if enabled */
830         {
831                 int dummy = sizeof(restore_digit_detect);
832
833                 ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
834         }
835
836         if (restore_digit_detect) {
837                 char new_digit_detect = 0;
838
839                 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
840         }
841
842         /* disable FAX tone detection if enabled */
843         {
844                 char new_fax_detect = 0;
845
846                 ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
847         }
848
849         res = transmit(&session);
850
851         if (restore_digit_detect) {
852                 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
853         }
854
855         return res;
856 }
857
858 static int unload_module(void)
859 {
860         int res;
861
862         res = ast_unregister_application(app_sndfax_name);      
863         res |= ast_unregister_application(app_rcvfax_name);     
864
865         return res;
866 }
867
868 static int load_module(void)
869 {
870         int res ;
871
872         res = ast_register_application_xml(app_sndfax_name, sndfax_exec);
873         res |= ast_register_application_xml(app_rcvfax_name, rcvfax_exec);
874
875         /* The default SPAN message handler prints to stderr. It is something we do not want */
876         span_set_message_handler(NULL);
877
878         return res;
879 }
880
881
882 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
883                 .load = load_module,
884                 .unload = unload_module,
885                 );
886
887