Fix version detection for API changes in spandsp.
[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         
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         enum ast_control_t38 t38control;
376
377 #if SPANDSP_RELEASE_DATE >= 20080725
378         /* for spandsp shaphots 0.0.6 and higher */
379         t30state = &fax.t30;
380 #else
381         /* for spandsp release 0.0.5 */
382         t30state = &fax.t30_state;
383 #endif
384
385         original_read_fmt = s->chan->readformat;
386         if (original_read_fmt != AST_FORMAT_SLINEAR) {
387                 res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR);
388                 if (res < 0) {
389                         ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
390                         goto done;
391                 }
392         }
393
394         original_write_fmt = s->chan->writeformat;
395         if (original_write_fmt != AST_FORMAT_SLINEAR) {
396                 res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR);
397                 if (res < 0) {
398                         ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
399                         goto done;
400                 }
401         }
402
403         /* Initialize T30 terminal */
404         fax_init(&fax, s->caller_mode);
405
406         /* Setup logging */
407         set_logging(&fax.logging);
408         set_logging(&t30state->logging);
409
410         /* Configure terminal */
411         set_local_info(t30state, s);
412         set_file(t30state, s);
413         set_ecm(t30state, TRUE);
414
415         fax_set_transmit_on_idle(&fax, TRUE);
416
417         t30_set_phase_e_handler(t30state, phase_e_handler, s);
418
419         if (s->t38state == T38_STATE_UNAVAILABLE) {
420                 ast_debug(1, "T38 is unavailable on %s\n", s->chan->name);
421         } else if (!s->direction) {
422                 /* We are receiving side and this means we are the side which should
423                    request T38 when the fax is detected. Use DSP to detect fax tone */
424                 ast_debug(1, "Setting up CNG detection on %s\n", s->chan->name);
425                 dsp = ast_dsp_new();
426                 ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
427                 ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG);
428                 detect_tone = 1;
429         }
430
431         start = state_change = ast_tvnow();
432
433         ast_activate_generator(s->chan, &generator, &fax);
434
435         while (!s->finished) {
436                 res = ast_waitfor(s->chan, 20);
437                 if (res < 0)
438                         break;
439                 else if (res > 0)
440                         res = 0;
441
442                 inf = ast_read(s->chan);
443                 if (inf == NULL) {
444                         ast_debug(1, "Channel hangup\n");
445                         res = -1;
446                         break;
447                 }
448
449                 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
450
451                 /* Detect fax tone */
452                 if (detect_tone && inf->frametype == AST_FRAME_VOICE) {
453                         /* Duplicate frame because ast_dsp_process may free the frame passed */
454                         fr = ast_frdup(inf);
455
456                         /* Do not pass channel to ast_dsp_process otherwise it may queue modified audio frame back */
457                         fr = ast_dsp_process(NULL, dsp, fr);
458                         if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') {
459                                 ast_debug(1, "Fax tone detected. Requesting T38\n");
460                                 t38control = AST_T38_REQUEST_NEGOTIATE;
461                                 ast_indicate_data(s->chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
462                                 detect_tone = 0;
463                         }
464
465                         ast_frfree(fr);
466                 }
467
468
469                 /* Check the frame type. Format also must be checked because there is a chance
470                    that a frame in old format was already queued before we set chanel format
471                    to slinear so it will still be received by ast_read */
472                 if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) {
473
474                         if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
475                                 /* I know fax_rx never returns errors. The check here is for good style only */
476                                 ast_log(LOG_WARNING, "fax_rx returned error\n");
477                                 res = -1;
478                                 break;
479                         }
480
481                         /* Watchdog */
482                         if (last_state != t30state->state) {
483                                 state_change = ast_tvnow();
484                                 last_state = t30state->state;
485                         }
486                 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
487                                 inf->datalen == sizeof(enum ast_control_t38)) {
488                         t38control =*((enum ast_control_t38 *) inf->data.ptr);
489                         if (t38control == AST_T38_NEGOTIATED) {
490                                 /* T38 switchover completed */
491                                 ast_debug(1, "T38 negotiated, finishing audio loop\n");
492                                 res = 1;
493                                 break;
494                         }
495                 }
496
497                 ast_frfree(inf);
498                 inf = NULL;
499
500                 /* Watchdog */
501                 now = ast_tvnow();
502                 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
503                         ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
504                         res = -1;
505                         break;
506                 }
507         }
508
509         ast_debug(1, "Loop finished, res=%d\n", res);
510
511         if (inf)
512                 ast_frfree(inf);
513
514         if (dsp)
515                 ast_dsp_free(dsp);
516
517         ast_deactivate_generator(s->chan);
518
519         /* If we are switching to T38, remove phase E handler. Otherwise it will be executed
520            by t30_terminate, display diagnostics and set status variables although no transmittion
521            has taken place yet. */
522         if (res > 0) {
523                 t30_set_phase_e_handler(t30state, NULL, NULL);
524         }
525
526         t30_terminate(t30state);
527         fax_release(&fax);
528
529 done:
530         if (original_write_fmt != AST_FORMAT_SLINEAR) {
531                 if (ast_set_write_format(s->chan, original_write_fmt) < 0)
532                         ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name);
533         }
534
535         if (original_read_fmt != AST_FORMAT_SLINEAR) {
536                 if (ast_set_read_format(s->chan, original_read_fmt) < 0)
537                         ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name);
538         }
539
540         return res;
541
542 }
543
544 static int transmit_t38(fax_session *s)
545 {
546         int res = 0;
547         t38_terminal_state_t t38;
548         struct ast_frame *inf = NULL;
549         int last_state = 0;
550         struct timeval now, start, state_change, last_frame;
551         enum ast_control_t38 t38control;
552
553         t30_state_t *t30state;
554         t38_core_state_t *t38state;
555
556 #if SPANDSP_RELEASE_DATE >= 20080725
557         /* for spandsp shaphots 0.0.6 and higher */
558         t30state = &t38.t30;
559         t38state = &t38.t38_fe.t38;
560 #else
561         /* for spandsp releases 0.0.5 */
562         t30state = &t38.t30_state;
563         t38state = &t38.t38;
564 #endif
565
566         /* Initialize terminal */
567         memset(&t38, 0, sizeof(t38));
568         if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
569                 ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
570                 return -1;
571         }
572
573         /* Setup logging */
574         set_logging(&t38.logging);
575         set_logging(&t30state->logging);
576         set_logging(&t38state->logging);
577
578         /* Configure terminal */
579         set_local_info(t30state, s);
580         set_file(t30state, s);
581         set_ecm(t30state, TRUE);
582
583         t30_set_phase_e_handler(t30state, phase_e_handler, s);
584
585         now = start = state_change = ast_tvnow();
586
587         while (!s->finished) {
588
589                 res = ast_waitfor(s->chan, 20);
590                 if (res < 0)
591                         break;
592                 else if (res > 0)
593                         res = 0;
594
595                 last_frame = now;
596                 now = ast_tvnow();
597                 t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
598
599                 inf = ast_read(s->chan);
600                 if (inf == NULL) {
601                         ast_debug(1, "Channel hangup\n");
602                         res = -1;
603                         break;
604                 }
605
606                 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
607
608                 if (inf->frametype == AST_FRAME_MODEM && inf->subclass == AST_MODEM_T38) {
609                         t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
610
611                         /* Watchdog */
612                         if (last_state != t30state->state) {
613                                 state_change = ast_tvnow();
614                                 last_state = t30state->state;
615                         }
616                 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
617                                 inf->datalen == sizeof(enum ast_control_t38)) {
618
619                         t38control = *((enum ast_control_t38 *) inf->data.ptr);
620
621                         if (t38control == AST_T38_TERMINATED || t38control == AST_T38_REFUSED) {
622                                 ast_debug(1, "T38 down, terminating\n");
623                                 res = -1;
624                                 break;
625                         }
626                 }
627
628                 ast_frfree(inf);
629                 inf = NULL;
630
631                 /* Watchdog */
632                 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
633                         ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
634                         res = -1;
635                         break;
636                 }
637         }
638
639         ast_debug(1, "Loop finished, res=%d\n", res);
640
641         if (inf)
642                 ast_frfree(inf);
643
644         t30_terminate(t30state);
645         t38_terminal_release(&t38);
646
647         return res;
648 }
649
650 static int transmit(fax_session *s)
651 {
652         int res = 0;
653
654         /* Clear all channel variables which to be set by the application.
655            Pre-set status to error so in case of any problems we can just leave */
656         pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
657         pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 
658
659         pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
660         pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
661         pbx_builtin_setvar_helper(s->chan, "FAXPAGES", NULL);
662         pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
663         pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); 
664
665         if (s->chan->_state != AST_STATE_UP) {
666                 /* Shouldn't need this, but checking to see if channel is already answered
667                  * Theoretically asterisk should already have answered before running the app */
668                 res = ast_answer(s->chan);
669                 if (res) {
670                         ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
671                         return res;
672                 }
673         }
674
675         s->t38state = ast_channel_get_t38_state(s->chan);
676         if (s->t38state != T38_STATE_NEGOTIATED) {
677                 /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */ 
678                 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio"); 
679                 res = transmit_audio(s);
680                 if (res > 0) {
681                         /* transmit_audio reports switchover to T38. Update t38state */
682                         s->t38state = ast_channel_get_t38_state(s->chan);
683                         if (s->t38state != T38_STATE_NEGOTIATED) {
684                                 ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
685                         }
686                 }
687         }
688
689         if (s->t38state == T38_STATE_NEGOTIATED) {
690                 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38"); 
691                 res = transmit_t38(s);
692         }
693
694         if (res) {
695                 ast_log(LOG_WARNING, "Transmission error\n");
696                 res = -1;
697         } else if (s->finished < 0) {
698                 ast_log(LOG_WARNING, "Transmission failed\n");
699         } else if (s->finished > 0) {
700                 ast_debug(1, "Transmission finished Ok\n");
701         }
702
703         return res;
704 }
705
706 /* === Application functions === */
707
708 static int sndfax_exec(struct ast_channel *chan, const char *data)
709 {
710         int res = 0;
711         char *parse;
712         fax_session session;
713         char restore_digit_detect = 0;
714
715         AST_DECLARE_APP_ARGS(args,
716                 AST_APP_ARG(file_name);
717                 AST_APP_ARG(options);
718         );
719
720         if (chan == NULL) {
721                 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
722                 return -1;
723         }
724
725         /* The next few lines of code parse out the filename and header from the input string */
726         if (ast_strlen_zero(data)) {
727                 /* No data implies no filename or anything is present */
728                 ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
729                 return -1;
730         }
731
732         parse = ast_strdupa(data);
733         AST_STANDARD_APP_ARGS(args, parse);
734         
735         session.caller_mode = TRUE;
736
737         if (args.options) {
738                 if (strchr(args.options, 'a'))
739                         session.caller_mode = FALSE;
740         }
741
742         /* Done parsing */
743         session.direction = 1;
744         session.file_name = args.file_name;
745         session.chan = chan;
746         session.finished = 0;
747
748         /* get current digit detection mode, then disable digit detection if enabled */
749         {
750                 int dummy = sizeof(restore_digit_detect);
751
752                 ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
753         }
754
755         if (restore_digit_detect) {
756                 char new_digit_detect = 0;
757
758                 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
759         }
760
761         /* disable FAX tone detection if enabled */
762         {
763                 char new_fax_detect = 0;
764
765                 ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
766         }
767
768         res = transmit(&session);
769
770         if (restore_digit_detect) {
771                 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
772         }
773
774         return res;
775 }
776
777 static int rcvfax_exec(struct ast_channel *chan, const char *data)
778 {
779         int res = 0;
780         char *parse;
781         fax_session session;
782         char restore_digit_detect = 0;
783
784         AST_DECLARE_APP_ARGS(args,
785                 AST_APP_ARG(file_name);
786                 AST_APP_ARG(options);
787         );
788
789         if (chan == NULL) {
790                 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
791                 return -1;
792         }
793
794         /* The next few lines of code parse out the filename and header from the input string */
795         if (ast_strlen_zero(data)) {
796                 /* No data implies no filename or anything is present */
797                 ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
798                 return -1;
799         }
800
801         parse = ast_strdupa(data);
802         AST_STANDARD_APP_ARGS(args, parse);
803         
804         session.caller_mode = FALSE;
805
806         if (args.options) {
807                 if (strchr(args.options, 'c'))
808                         session.caller_mode = TRUE;
809         }
810
811         /* Done parsing */
812         session.direction = 0;
813         session.file_name = args.file_name;
814         session.chan = chan;
815         session.finished = 0;
816
817         /* get current digit detection mode, then disable digit detection if enabled */
818         {
819                 int dummy = sizeof(restore_digit_detect);
820
821                 ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
822         }
823
824         if (restore_digit_detect) {
825                 char new_digit_detect = 0;
826
827                 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
828         }
829
830         /* disable FAX tone detection if enabled */
831         {
832                 char new_fax_detect = 0;
833
834                 ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
835         }
836
837         res = transmit(&session);
838
839         if (restore_digit_detect) {
840                 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
841         }
842
843         return res;
844 }
845
846 static int unload_module(void)
847 {
848         int res;
849
850         res = ast_unregister_application(app_sndfax_name);      
851         res |= ast_unregister_application(app_rcvfax_name);     
852
853         return res;
854 }
855
856 static int load_module(void)
857 {
858         int res ;
859
860         res = ast_register_application_xml(app_sndfax_name, sndfax_exec);
861         res |= ast_register_application_xml(app_rcvfax_name, rcvfax_exec);
862
863         /* The default SPAN message handler prints to stderr. It is something we do not want */
864         span_set_message_handler(NULL);
865
866         return res;
867 }
868
869
870 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
871                 .load = load_module,
872                 .unload = unload_module,
873                 );
874
875