Make app_fax compatible with newer versions of spandsp. This remains backwards compat...
[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 char *app_sndfax_name = "SendFAX";
145 static 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
210         ast_debug(1, "Fax phase E handler. result=%d\n", result);
211
212         t30_get_transfer_statistics(f, &stat);
213
214         s = (fax_session *) user_data;
215
216         if (result != T30_ERR_OK) {
217                 s->finished = -1;
218
219                 /* FAXSTATUS is already set to FAILED */
220                 pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));
221
222                 ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));
223
224                 return;
225         }
226         
227         s->finished = 1; 
228         
229         local_ident = t30_get_tx_ident(f);
230         far_ident = t30_get_rx_ident(f);
231         pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS"); 
232         pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL); 
233         pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
234         snprintf(buf, sizeof(buf), "%d", stat.pages_transferred);
235         pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
236         snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
237         pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
238         snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
239         pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf); 
240         
241         ast_debug(1, "Fax transmitted successfully.\n");
242         ast_debug(1, "  Remote station ID: %s\n", far_ident);
243         ast_debug(1, "  Pages transferred: %d\n", stat.pages_transferred);
244         ast_debug(1, "  Image resolution:  %d x %d\n", stat.x_resolution, stat.y_resolution);
245         ast_debug(1, "  Transfer Rate:     %d\n", stat.bit_rate);
246         
247         manager_event(EVENT_FLAG_CALL,
248                       s->direction ? "FaxSent" : "FaxReceived", 
249                       "Channel: %s\r\n"
250                       "Exten: %s\r\n"
251                       "CallerID: %s\r\n"
252                       "RemoteStationID: %s\r\n"
253                       "LocalStationID: %s\r\n"
254                       "PagesTransferred: %d\r\n"
255                       "Resolution: %d\r\n"
256                       "TransferRate: %d\r\n"
257                       "FileName: %s\r\n",
258                       s->chan->name,
259                       s->chan->exten,
260                       S_OR(s->chan->cid.cid_num, ""),
261                       far_ident,
262                       local_ident,
263                       stat.pages_transferred,
264                       stat.y_resolution,
265                       stat.bit_rate,
266                       s->file_name);
267 }
268
269 /* === Helper functions to configure fax === */
270
271 /* Setup SPAN logging according to Asterisk debug level */
272 static int set_logging(logging_state_t *state)
273 {
274         int level = SPAN_LOG_WARNING + option_debug;
275
276         span_log_set_message_handler(state, span_message);
277         span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level); 
278
279         return 0;
280 }
281
282 static void set_local_info(t30_state_t *state, fax_session *s)
283 {
284         const char *x;
285
286         x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID");
287         if (!ast_strlen_zero(x))
288                 t30_set_tx_ident(state, x);
289
290         x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO");
291         if (!ast_strlen_zero(x))
292                 t30_set_tx_page_header_info(state, x);
293 }
294
295 static void set_file(t30_state_t *state, fax_session *s)
296 {
297         if (s->direction)
298                 t30_set_tx_file(state, s->file_name, -1, -1);
299         else
300                 t30_set_rx_file(state, s->file_name, -1);
301 }
302
303 static void set_ecm(t30_state_t *state, int ecm)
304 {
305         t30_set_ecm_capability(state, ecm);
306         t30_set_supported_compressions(state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
307 }
308
309 /* === Generator === */
310
311 /* This function is only needed to return passed params so
312    generator_activate will save it to channel's generatordata */
313 static void *fax_generator_alloc(struct ast_channel *chan, void *params)
314 {
315         return params;
316 }
317
318 static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
319 {
320         fax_state_t *fax = (fax_state_t*) data;
321         uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
322         int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
323     
324         struct ast_frame outf = {
325                 .frametype = AST_FRAME_VOICE,
326                 .subclass = AST_FORMAT_SLINEAR,
327                 .src = __FUNCTION__,
328         };
329
330         if (samples > MAX_SAMPLES) {
331                 ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
332                 samples = MAX_SAMPLES;
333         }
334         
335         if ((len = fax_tx(fax, buf, samples)) > 0) {
336                 outf.samples = len;
337                 AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
338
339                 if (ast_write(chan, &outf) < 0) {
340                         ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
341                         return -1;
342                 }
343         }
344
345         return 0;
346 }
347
348 struct ast_generator generator = {
349         alloc:          fax_generator_alloc,
350         generate:       fax_generator_generate,
351 };
352
353
354 /* === Transmission === */
355
356 static int transmit_audio(fax_session *s)
357 {
358         int res = -1;
359         int original_read_fmt = AST_FORMAT_SLINEAR;
360         int original_write_fmt = AST_FORMAT_SLINEAR;
361         fax_state_t fax;
362         t30_state_t *t30state;
363         struct ast_dsp *dsp = NULL;
364         int detect_tone = 0;
365         struct ast_frame *inf = NULL;
366         struct ast_frame *fr;
367         int last_state = 0;
368         struct timeval now, start, state_change;
369         enum ast_control_t38 t38control;
370
371 #if SPANDSP_RELEASE_DATE >= 20081012
372         /* for spandsp shaphots 0.0.6 and higher */
373         t30state = &fax.t30;
374 #else
375         /* for spandsp release 0.0.5 */
376         t30state = &fax.t30_state;
377 #endif
378
379         original_read_fmt = s->chan->readformat;
380         if (original_read_fmt != AST_FORMAT_SLINEAR) {
381                 res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR);
382                 if (res < 0) {
383                         ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
384                         goto done;
385                 }
386         }
387
388         original_write_fmt = s->chan->writeformat;
389         if (original_write_fmt != AST_FORMAT_SLINEAR) {
390                 res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR);
391                 if (res < 0) {
392                         ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
393                         goto done;
394                 }
395         }
396
397         /* Initialize T30 terminal */
398         fax_init(&fax, s->caller_mode);
399
400         /* Setup logging */
401         set_logging(&fax.logging);
402         set_logging(&t30state->logging);
403
404         /* Configure terminal */
405         set_local_info(t30state, s);
406         set_file(t30state, s);
407         set_ecm(t30state, TRUE);
408
409         fax_set_transmit_on_idle(&fax, TRUE);
410
411         t30_set_phase_e_handler(t30state, phase_e_handler, s);
412
413         if (s->t38state == T38_STATE_UNAVAILABLE) {
414                 ast_debug(1, "T38 is unavailable on %s\n", s->chan->name);
415         } else if (!s->direction) {
416                 /* We are receiving side and this means we are the side which should
417                    request T38 when the fax is detected. Use DSP to detect fax tone */
418                 ast_debug(1, "Setting up CNG detection on %s\n", s->chan->name);
419                 dsp = ast_dsp_new();
420                 ast_dsp_set_features(dsp, DSP_FEATURE_FAX_DETECT);
421                 ast_dsp_set_faxmode(dsp, DSP_FAXMODE_DETECT_CNG);
422                 detect_tone = 1;
423         }
424
425         start = state_change = ast_tvnow();
426
427         ast_activate_generator(s->chan, &generator, &fax);
428
429         while (!s->finished) {
430                 res = ast_waitfor(s->chan, 20);
431                 if (res < 0)
432                         break;
433                 else if (res > 0)
434                         res = 0;
435
436                 inf = ast_read(s->chan);
437                 if (inf == NULL) {
438                         ast_debug(1, "Channel hangup\n");
439                         res = -1;
440                         break;
441                 }
442
443                 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
444
445                 /* Detect fax tone */
446                 if (detect_tone && inf->frametype == AST_FRAME_VOICE) {
447                         /* Duplicate frame because ast_dsp_process may free the frame passed */
448                         fr = ast_frdup(inf);
449
450                         /* Do not pass channel to ast_dsp_process otherwise it may queue modified audio frame back */
451                         fr = ast_dsp_process(NULL, dsp, fr);
452                         if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') {
453                                 ast_debug(1, "Fax tone detected. Requesting T38\n");
454                                 t38control = AST_T38_REQUEST_NEGOTIATE;
455                                 ast_indicate_data(s->chan, AST_CONTROL_T38, &t38control, sizeof(t38control));
456                                 detect_tone = 0;
457                         }
458
459                         ast_frfree(fr);
460                 }
461
462
463                 /* Check the frame type. Format also must be checked because there is a chance
464                    that a frame in old format was already queued before we set chanel format
465                    to slinear so it will still be received by ast_read */
466                 if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) {
467
468                         if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
469                                 /* I know fax_rx never returns errors. The check here is for good style only */
470                                 ast_log(LOG_WARNING, "fax_rx returned error\n");
471                                 res = -1;
472                                 break;
473                         }
474
475                         /* Watchdog */
476                         if (last_state != t30state->state) {
477                                 state_change = ast_tvnow();
478                                 last_state = t30state->state;
479                         }
480                 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
481                                 inf->datalen == sizeof(enum ast_control_t38)) {
482                         t38control =*((enum ast_control_t38 *) inf->data.ptr);
483                         if (t38control == AST_T38_NEGOTIATED) {
484                                 /* T38 switchover completed */
485                                 ast_debug(1, "T38 negotiated, finishing audio loop\n");
486                                 res = 1;
487                                 break;
488                         }
489                 }
490
491                 ast_frfree(inf);
492                 inf = NULL;
493
494                 /* Watchdog */
495                 now = ast_tvnow();
496                 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
497                         ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
498                         res = -1;
499                         break;
500                 }
501         }
502
503         ast_debug(1, "Loop finished, res=%d\n", res);
504
505         if (inf)
506                 ast_frfree(inf);
507
508         if (dsp)
509                 ast_dsp_free(dsp);
510
511         ast_deactivate_generator(s->chan);
512
513         /* If we are switching to T38, remove phase E handler. Otherwise it will be executed
514            by t30_terminate, display diagnostics and set status variables although no transmittion
515            has taken place yet. */
516         if (res > 0) {
517                 t30_set_phase_e_handler(t30state, NULL, NULL);
518         }
519
520         t30_terminate(t30state);
521         fax_release(&fax);
522
523 done:
524         if (original_write_fmt != AST_FORMAT_SLINEAR) {
525                 if (ast_set_write_format(s->chan, original_write_fmt) < 0)
526                         ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name);
527         }
528
529         if (original_read_fmt != AST_FORMAT_SLINEAR) {
530                 if (ast_set_read_format(s->chan, original_read_fmt) < 0)
531                         ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name);
532         }
533
534         return res;
535
536 }
537
538 static int transmit_t38(fax_session *s)
539 {
540         int res = 0;
541         t38_terminal_state_t t38;
542         struct ast_frame *inf = NULL;
543         int last_state = 0;
544         struct timeval now, start, state_change, last_frame;
545         enum ast_control_t38 t38control;
546
547         t30_state_t *t30state;
548         t38_core_state_t *t38state;
549
550 #if SPANDSP_RELEASE_DATE >= 20081012
551         /* for spandsp shaphots 0.0.6 and higher */
552         t30state = &t38.t30;
553         t38state = &t38.t38_fe.t38;
554 #else
555         /* for spandsp releases 0.0.5 */
556         t30state = &t38.t30_state;
557         t38state = &t38.t38;
558 #endif
559
560         /* Initialize terminal */
561         memset(&t38, 0, sizeof(t38));
562         if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
563                 ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
564                 return -1;
565         }
566
567         /* Setup logging */
568         set_logging(&t38.logging);
569         set_logging(&t30state->logging);
570         set_logging(&t38state->logging);
571
572         /* Configure terminal */
573         set_local_info(t30state, s);
574         set_file(t30state, s);
575         set_ecm(t30state, TRUE);
576
577         t30_set_phase_e_handler(t30state, phase_e_handler, s);
578
579         now = start = state_change = ast_tvnow();
580
581         while (!s->finished) {
582
583                 res = ast_waitfor(s->chan, 20);
584                 if (res < 0)
585                         break;
586                 else if (res > 0)
587                         res = 0;
588
589                 last_frame = now;
590                 now = ast_tvnow();
591                 t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
592
593                 inf = ast_read(s->chan);
594                 if (inf == NULL) {
595                         ast_debug(1, "Channel hangup\n");
596                         res = -1;
597                         break;
598                 }
599
600                 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass, inf->datalen);
601
602                 if (inf->frametype == AST_FRAME_MODEM && inf->subclass == AST_MODEM_T38) {
603                         t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
604
605                         /* Watchdog */
606                         if (last_state != t30state->state) {
607                                 state_change = ast_tvnow();
608                                 last_state = t30state->state;
609                         }
610                 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass == AST_CONTROL_T38 &&
611                                 inf->datalen == sizeof(enum ast_control_t38)) {
612
613                         t38control = *((enum ast_control_t38 *) inf->data.ptr);
614
615                         if (t38control == AST_T38_TERMINATED || t38control == AST_T38_REFUSED) {
616                                 ast_debug(1, "T38 down, terminating\n");
617                                 res = -1;
618                                 break;
619                         }
620                 }
621
622                 ast_frfree(inf);
623                 inf = NULL;
624
625                 /* Watchdog */
626                 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
627                         ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
628                         res = -1;
629                         break;
630                 }
631         }
632
633         ast_debug(1, "Loop finished, res=%d\n", res);
634
635         if (inf)
636                 ast_frfree(inf);
637
638         t30_terminate(t30state);
639         t38_terminal_release(&t38);
640
641         return res;
642 }
643
644 static int transmit(fax_session *s)
645 {
646         int res = 0;
647
648         /* Clear all channel variables which to be set by the application.
649            Pre-set status to error so in case of any problems we can just leave */
650         pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
651         pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 
652
653         pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
654         pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
655         pbx_builtin_setvar_helper(s->chan, "FAXPAGES", NULL);
656         pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
657         pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); 
658
659         if (s->chan->_state != AST_STATE_UP) {
660                 /* Shouldn't need this, but checking to see if channel is already answered
661                  * Theoretically asterisk should already have answered before running the app */
662                 res = ast_answer(s->chan);
663                 if (res) {
664                         ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
665                         return res;
666                 }
667         }
668
669         s->t38state = ast_channel_get_t38_state(s->chan);
670         if (s->t38state != T38_STATE_NEGOTIATED) {
671                 /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */ 
672                 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio"); 
673                 res = transmit_audio(s);
674                 if (res > 0) {
675                         /* transmit_audio reports switchover to T38. Update t38state */
676                         s->t38state = ast_channel_get_t38_state(s->chan);
677                         if (s->t38state != T38_STATE_NEGOTIATED) {
678                                 ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
679                         }
680                 }
681         }
682
683         if (s->t38state == T38_STATE_NEGOTIATED) {
684                 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38"); 
685                 res = transmit_t38(s);
686         }
687
688         if (res) {
689                 ast_log(LOG_WARNING, "Transmission error\n");
690                 res = -1;
691         } else if (s->finished < 0) {
692                 ast_log(LOG_WARNING, "Transmission failed\n");
693         } else if (s->finished > 0) {
694                 ast_debug(1, "Transmission finished Ok\n");
695         }
696
697         return res;
698 }
699
700 /* === Application functions === */
701
702 static int sndfax_exec(struct ast_channel *chan, void *data)
703 {
704         int res = 0;
705         char *parse;
706         fax_session session;
707
708         AST_DECLARE_APP_ARGS(args,
709                 AST_APP_ARG(file_name);
710                 AST_APP_ARG(options);
711         );
712
713         if (chan == NULL) {
714                 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
715                 return -1;
716         }
717
718         /* The next few lines of code parse out the filename and header from the input string */
719         if (ast_strlen_zero(data)) {
720                 /* No data implies no filename or anything is present */
721                 ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
722                 return -1;
723         }
724
725         parse = ast_strdupa(data);
726         AST_STANDARD_APP_ARGS(args, parse);
727         
728         session.caller_mode = TRUE;
729
730         if (args.options) {
731                 if (strchr(args.options, 'a'))
732                         session.caller_mode = FALSE;
733         }
734
735         /* Done parsing */
736         session.direction = 1;
737         session.file_name = args.file_name;
738         session.chan = chan;
739         session.finished = 0;
740
741         res = transmit(&session);
742
743         return res;
744 }
745
746 static int rcvfax_exec(struct ast_channel *chan, void *data)
747 {
748         int res = 0;
749         char *parse;
750         fax_session session;
751
752         AST_DECLARE_APP_ARGS(args,
753                 AST_APP_ARG(file_name);
754                 AST_APP_ARG(options);
755         );
756
757         if (chan == NULL) {
758                 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
759                 return -1;
760         }
761
762         /* The next few lines of code parse out the filename and header from the input string */
763         if (ast_strlen_zero(data)) {
764                 /* No data implies no filename or anything is present */
765                 ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
766                 return -1;
767         }
768
769         parse = ast_strdupa(data);
770         AST_STANDARD_APP_ARGS(args, parse);
771         
772         session.caller_mode = FALSE;
773
774         if (args.options) {
775                 if (strchr(args.options, 'c'))
776                         session.caller_mode = TRUE;
777         }
778
779         /* Done parsing */
780         session.direction = 0;
781         session.file_name = args.file_name;
782         session.chan = chan;
783         session.finished = 0;
784
785         res = transmit(&session);
786
787         return res;
788 }
789
790 static int unload_module(void)
791 {
792         int res;
793
794         res = ast_unregister_application(app_sndfax_name);      
795         res |= ast_unregister_application(app_rcvfax_name);     
796
797         return res;
798 }
799
800 static int load_module(void)
801 {
802         int res ;
803
804         res = ast_register_application_xml(app_sndfax_name, sndfax_exec);
805         res |= ast_register_application_xml(app_rcvfax_name, rcvfax_exec);
806
807         /* The default SPAN message handler prints to stderr. It is something we do not want */
808         span_set_message_handler(NULL);
809
810         return res;
811 }
812
813
814 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
815                 .load = load_module,
816                 .unload = unload_module,
817                 );
818
819