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