2 * Asterisk -- A telephony toolkit for Linux.
4 * Simple fax applications
6 * 2007-2008, Dmitry Andrianov <asterisk@dima.spb.ru>
8 * Code based on original implementation by Steve Underwood <steveu@coppice.org>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
16 <depend>spandsp</depend>
21 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
33 #include <spandsp/version.h>
35 #include "asterisk/lock.h"
36 #include "asterisk/file.h"
37 #include "asterisk/logger.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/pbx.h"
40 #include "asterisk/app.h"
41 #include "asterisk/dsp.h"
42 #include "asterisk/module.h"
43 #include "asterisk/manager.h"
46 <application name="SendFAX" language="en_US">
51 <parameter name="filename" required="true">
52 <para>Filename of TIFF file to fax</para>
54 <parameter name="a" required="false">
55 <para>Makes the application behave as the answering machine</para>
56 <para>(Default behavior is as calling machine)</para>
60 <para>Send a given TIFF file to the channel as a FAX.</para>
61 <para>This application sets the following channel variables:</para>
63 <variable name="LOCALSTATIONID">
64 <para>To identify itself to the remote end</para>
66 <variable name="LOCALHEADERINFO">
67 <para>To generate a header line on each page</para>
69 <variable name="FAXSTATUS">
70 <value name="SUCCESS"/>
71 <value name="FAILED"/>
73 <variable name="FAXERROR">
74 <para>Cause of failure</para>
76 <variable name="REMOTESTATIONID">
77 <para>The CSID of the remote side</para>
79 <variable name="FAXPAGES">
80 <para>Number of pages sent</para>
82 <variable name="FAXBITRATE">
83 <para>Transmission rate</para>
85 <variable name="FAXRESOLUTION">
86 <para>Resolution of sent fax</para>
91 <application name="ReceiveFAX" language="en_US">
96 <parameter name="filename" required="true">
97 <para>Filename of TIFF file save incoming fax</para>
99 <parameter name="c" required="false">
100 <para>Makes the application behave as the calling machine</para>
101 <para>(Default behavior is as answering machine)</para>
105 <para>Receives a FAX from the channel into the given filename
106 overwriting the file if it already exists.</para>
107 <para>File created will be in TIFF format.</para>
109 <para>This application sets the following channel variables:</para>
111 <variable name="LOCALSTATIONID">
112 <para>To identify itself to the remote end</para>
114 <variable name="LOCALHEADERINFO">
115 <para>To generate a header line on each page</para>
117 <variable name="FAXSTATUS">
118 <value name="SUCCESS"/>
119 <value name="FAILED"/>
121 <variable name="FAXERROR">
122 <para>Cause of failure</para>
124 <variable name="REMOTESTATIONID">
125 <para>The CSID of the remote side</para>
127 <variable name="FAXPAGES">
128 <para>Number of pages sent</para>
130 <variable name="FAXBITRATE">
131 <para>Transmission rate</para>
133 <variable name="FAXRESOLUTION">
134 <para>Resolution of sent fax</para>
142 static const char app_sndfax_name[] = "SendFAX";
143 static const char app_rcvfax_name[] = "ReceiveFAX";
145 #define MAX_SAMPLES 240
147 /* Watchdog. I have seen situations when remote fax disconnects (because of poor line
148 quality) while SpanDSP continues staying in T30_STATE_IV_CTC state forever.
149 To avoid this, we terminate when we see that T30 state does not change for 5 minutes.
150 We also terminate application when more than 30 minutes passed regardless of
151 state changes. This is just a precaution measure - no fax should take that long */
153 #define WATCHDOG_TOTAL_TIMEOUT 30 * 60
154 #define WATCHDOG_STATE_TIMEOUT 5 * 60
157 struct ast_channel *chan;
158 enum ast_t38_state t38state; /* T38 state of the channel */
159 int direction; /* Fax direction: 0 - receiving, 1 - sending */
162 struct ast_control_t38_parameters t38parameters;
163 volatile int finished;
166 static void span_message(int level, const char *msg)
168 if (level == SPAN_LOG_ERROR) {
169 ast_log(LOG_ERROR, "%s", msg);
170 } else if (level == SPAN_LOG_WARNING) {
171 ast_log(LOG_WARNING, "%s", msg);
173 ast_log(LOG_DEBUG, "%s", msg);
177 static int t38_tx_packet_handler(t38_core_state_t *s, void *user_data, const uint8_t *buf, int len, int count)
179 struct ast_channel *chan = (struct ast_channel *) user_data;
181 struct ast_frame outf = {
182 .frametype = AST_FRAME_MODEM,
183 .subclass.integer = AST_MODEM_T38,
187 /* TODO: Asterisk does not provide means of resending the same packet multiple
188 times so count is ignored at the moment */
190 AST_FRAME_SET_BUFFER(&outf, buf, 0, len);
192 if (ast_write(chan, &outf) < 0) {
193 ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
200 static void phase_e_handler(t30_state_t *f, void *user_data, int result)
202 const char *local_ident;
203 const char *far_ident;
205 fax_session *s = (fax_session *) user_data;
207 int pages_transferred;
209 ast_debug(1, "Fax phase E handler. result=%d\n", result);
211 t30_get_transfer_statistics(f, &stat);
213 s = (fax_session *) user_data;
215 if (result != T30_ERR_OK) {
218 /* FAXSTATUS is already set to FAILED */
219 pbx_builtin_setvar_helper(s->chan, "FAXERROR", t30_completion_code_to_str(result));
221 ast_log(LOG_WARNING, "Error transmitting fax. result=%d: %s.\n", result, t30_completion_code_to_str(result));
228 local_ident = t30_get_tx_ident(f);
229 far_ident = t30_get_rx_ident(f);
230 pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "SUCCESS");
231 pbx_builtin_setvar_helper(s->chan, "FAXERROR", NULL);
232 pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", far_ident);
233 #if SPANDSP_RELEASE_DATE >= 20090220
234 pages_transferred = (s->direction) ? stat.pages_tx : stat.pages_rx;
236 pages_transferred = stat.pages_transferred;
238 snprintf(buf, sizeof(buf), "%d", pages_transferred);
239 pbx_builtin_setvar_helper(s->chan, "FAXPAGES", buf);
240 snprintf(buf, sizeof(buf), "%d", stat.y_resolution);
241 pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", buf);
242 snprintf(buf, sizeof(buf), "%d", stat.bit_rate);
243 pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", buf);
245 ast_debug(1, "Fax transmitted successfully.\n");
246 ast_debug(1, " Remote station ID: %s\n", far_ident);
247 ast_debug(1, " Pages transferred: %d\n", pages_transferred);
248 ast_debug(1, " Image resolution: %d x %d\n", stat.x_resolution, stat.y_resolution);
249 ast_debug(1, " Transfer Rate: %d\n", stat.bit_rate);
251 ast_manager_event(s->chan, EVENT_FLAG_CALL,
252 s->direction ? "FaxSent" : "FaxReceived",
256 "RemoteStationID: %s\r\n"
257 "LocalStationID: %s\r\n"
258 "PagesTransferred: %d\r\n"
260 "TransferRate: %d\r\n"
264 S_OR(s->chan->cid.cid_num, ""),
273 /* === Helper functions to configure fax === */
275 /* Setup SPAN logging according to Asterisk debug level */
276 static int set_logging(logging_state_t *state)
278 int level = SPAN_LOG_WARNING + option_debug;
280 span_log_set_message_handler(state, span_message);
281 span_log_set_level(state, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | level);
286 static void set_local_info(t30_state_t *state, fax_session *s)
290 x = pbx_builtin_getvar_helper(s->chan, "LOCALSTATIONID");
291 if (!ast_strlen_zero(x))
292 t30_set_tx_ident(state, x);
294 x = pbx_builtin_getvar_helper(s->chan, "LOCALHEADERINFO");
295 if (!ast_strlen_zero(x))
296 t30_set_tx_page_header_info(state, x);
299 static void set_file(t30_state_t *state, fax_session *s)
302 t30_set_tx_file(state, s->file_name, -1, -1);
304 t30_set_rx_file(state, s->file_name, -1);
307 static void set_ecm(t30_state_t *state, int ecm)
309 t30_set_ecm_capability(state, ecm);
310 t30_set_supported_compressions(state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
313 /* === Generator === */
315 /* This function is only needed to return passed params so
316 generator_activate will save it to channel's generatordata */
317 static void *fax_generator_alloc(struct ast_channel *chan, void *params)
322 static int fax_generator_generate(struct ast_channel *chan, void *data, int len, int samples)
324 fax_state_t *fax = (fax_state_t*) data;
325 uint8_t buffer[AST_FRIENDLY_OFFSET + MAX_SAMPLES * sizeof(uint16_t)];
326 int16_t *buf = (int16_t *) (buffer + AST_FRIENDLY_OFFSET);
328 struct ast_frame outf = {
329 .frametype = AST_FRAME_VOICE,
330 .subclass.codec = AST_FORMAT_SLINEAR,
334 if (samples > MAX_SAMPLES) {
335 ast_log(LOG_WARNING, "Only generating %d samples, where %d requested\n", MAX_SAMPLES, samples);
336 samples = MAX_SAMPLES;
339 if ((len = fax_tx(fax, buf, samples)) > 0) {
341 AST_FRAME_SET_BUFFER(&outf, buffer, AST_FRIENDLY_OFFSET, len * sizeof(int16_t));
343 if (ast_write(chan, &outf) < 0) {
344 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
352 static struct ast_generator generator = {
353 alloc: fax_generator_alloc,
354 generate: fax_generator_generate,
358 /* === Transmission === */
360 static int transmit_audio(fax_session *s)
363 int original_read_fmt = AST_FORMAT_SLINEAR;
364 int original_write_fmt = AST_FORMAT_SLINEAR;
366 t30_state_t *t30state;
367 struct ast_frame *inf = NULL;
369 struct timeval now, start, state_change;
370 enum ast_t38_state t38_state;
371 struct ast_control_t38_parameters t38_parameters = { .version = 0,
373 .rate = AST_T38_RATE_14400,
374 .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
375 .fill_bit_removal = 1,
377 * spandsp has API calls to support MMR and JBIG transcoding, but they aren't
378 * implemented quite yet... so don't offer them to the remote endpoint
379 * .transcoding_mmr = 1,
380 * .transcoding_jbig = 1,
384 /* if in called party mode, try to use T.38 */
385 if (s->caller_mode == FALSE) {
386 /* check if we are already in T.38 mode (unlikely), or if we can request
387 * a switch... if so, request it now and wait for the result, rather
388 * than starting an audio FAX session that will have to be cancelled
390 if ((t38_state = ast_channel_get_t38_state(s->chan)) == T38_STATE_NEGOTIATED) {
392 } else if ((t38_state != T38_STATE_UNAVAILABLE) &&
393 (t38_parameters.request_response = AST_T38_REQUEST_NEGOTIATE,
394 (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0))) {
395 /* wait up to five seconds for negotiation to complete */
396 unsigned int timeout = 5000;
399 ast_debug(1, "Negotiating T.38 for receive on %s\n", s->chan->name);
400 while (timeout > 0) {
401 ms = ast_waitfor(s->chan, 1000);
403 ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", s->chan->name);
407 /* nothing happened */
412 ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 negotiation.\n", s->chan->name);
416 if (!(inf = ast_read(s->chan))) {
419 if ((inf->frametype == AST_FRAME_CONTROL) &&
420 (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
421 (inf->datalen == sizeof(t38_parameters))) {
422 struct ast_control_t38_parameters *parameters = inf->data.ptr;
424 switch (parameters->request_response) {
425 case AST_T38_NEGOTIATED:
426 ast_debug(1, "Negotiated T.38 for receive on %s\n", s->chan->name);
429 case AST_T38_REFUSED:
430 ast_log(LOG_WARNING, "channel '%s' refused to negotiate T.38\n", s->chan->name);
433 ast_log(LOG_ERROR, "channel '%s' failed to negotiate T.38\n", s->chan->name);
448 #if SPANDSP_RELEASE_DATE >= 20080725
449 /* for spandsp shaphots 0.0.6 and higher */
452 /* for spandsp release 0.0.5 */
453 t30state = &fax.t30_state;
456 original_read_fmt = s->chan->readformat;
457 if (original_read_fmt != AST_FORMAT_SLINEAR) {
458 res = ast_set_read_format(s->chan, AST_FORMAT_SLINEAR);
460 ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
465 original_write_fmt = s->chan->writeformat;
466 if (original_write_fmt != AST_FORMAT_SLINEAR) {
467 res = ast_set_write_format(s->chan, AST_FORMAT_SLINEAR);
469 ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
474 /* Initialize T30 terminal */
475 fax_init(&fax, s->caller_mode);
478 set_logging(&fax.logging);
479 set_logging(&t30state->logging);
481 /* Configure terminal */
482 set_local_info(t30state, s);
483 set_file(t30state, s);
484 set_ecm(t30state, TRUE);
486 fax_set_transmit_on_idle(&fax, TRUE);
488 t30_set_phase_e_handler(t30state, phase_e_handler, s);
490 start = state_change = ast_tvnow();
492 ast_activate_generator(s->chan, &generator, &fax);
494 while (!s->finished) {
497 if ((res = ast_waitfor(s->chan, 25)) < 0) {
498 ast_debug(1, "Error waiting for a frame\n");
504 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
505 ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
511 /* There was timeout waiting for a frame. Loop around and wait again */
515 /* There is a frame available. Get it */
518 if (!(inf = ast_read(s->chan))) {
519 ast_debug(1, "Channel hangup\n");
524 ast_debug(10, "frame %d/%llu, len=%d\n", inf->frametype, (unsigned long long) inf->subclass.codec, inf->datalen);
526 /* Check the frame type. Format also must be checked because there is a chance
527 that a frame in old format was already queued before we set channel format
528 to slinear so it will still be received by ast_read */
529 if (inf->frametype == AST_FRAME_VOICE && inf->subclass.codec == AST_FORMAT_SLINEAR) {
530 if (fax_rx(&fax, inf->data.ptr, inf->samples) < 0) {
531 /* I know fax_rx never returns errors. The check here is for good style only */
532 ast_log(LOG_WARNING, "fax_rx returned error\n");
536 if (last_state != t30state->state) {
537 state_change = ast_tvnow();
538 last_state = t30state->state;
540 } else if ((inf->frametype == AST_FRAME_CONTROL) &&
541 (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS)) {
542 struct ast_control_t38_parameters *parameters = inf->data.ptr;
544 if (parameters->request_response == AST_T38_NEGOTIATED) {
545 /* T38 switchover completed */
546 s->t38parameters = *parameters;
547 ast_debug(1, "T38 negotiated, finishing audio loop\n");
550 } else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) {
551 t38_parameters.request_response = AST_T38_NEGOTIATED;
552 ast_debug(1, "T38 request received, accepting\n");
553 /* Complete T38 switchover */
554 ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters));
555 /* Do not break audio loop, wait until channel driver finally acks switchover
556 * with AST_T38_NEGOTIATED
564 ast_debug(1, "Loop finished, res=%d\n", res);
569 ast_deactivate_generator(s->chan);
571 /* If we are switching to T38, remove phase E handler. Otherwise it will be executed
572 by t30_terminate, display diagnostics and set status variables although no transmittion
573 has taken place yet. */
575 t30_set_phase_e_handler(t30state, NULL, NULL);
578 t30_terminate(t30state);
582 if (original_write_fmt != AST_FORMAT_SLINEAR) {
583 if (ast_set_write_format(s->chan, original_write_fmt) < 0)
584 ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", s->chan->name);
587 if (original_read_fmt != AST_FORMAT_SLINEAR) {
588 if (ast_set_read_format(s->chan, original_read_fmt) < 0)
589 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", s->chan->name);
596 static int transmit_t38(fax_session *s)
599 t38_terminal_state_t t38;
600 struct ast_frame *inf = NULL;
602 struct timeval now, start, state_change, last_frame;
603 t30_state_t *t30state;
604 t38_core_state_t *t38state;
606 #if SPANDSP_RELEASE_DATE >= 20080725
607 /* for spandsp shaphots 0.0.6 and higher */
609 t38state = &t38.t38_fe.t38;
611 /* for spandsp releases 0.0.5 */
612 t30state = &t38.t30_state;
616 /* Initialize terminal */
617 memset(&t38, 0, sizeof(t38));
618 if (t38_terminal_init(&t38, s->caller_mode, t38_tx_packet_handler, s->chan) == NULL) {
619 ast_log(LOG_WARNING, "Unable to start T.38 termination.\n");
624 t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp);
626 if (s->t38parameters.fill_bit_removal) {
627 t38_set_fill_bit_removal(t38state, TRUE);
629 if (s->t38parameters.transcoding_mmr) {
630 t38_set_mmr_transcoding(t38state, TRUE);
632 if (s->t38parameters.transcoding_jbig) {
633 t38_set_jbig_transcoding(t38state, TRUE);
637 set_logging(&t38.logging);
638 set_logging(&t30state->logging);
639 set_logging(&t38state->logging);
641 /* Configure terminal */
642 set_local_info(t30state, s);
643 set_file(t30state, s);
644 set_ecm(t30state, TRUE);
646 t30_set_phase_e_handler(t30state, phase_e_handler, s);
648 now = start = state_change = ast_tvnow();
650 while (!s->finished) {
653 if ((res = ast_waitfor(s->chan, 25)) < 0) {
654 ast_debug(1, "Error waiting for a frame\n");
662 if (ast_tvdiff_sec(now, start) > WATCHDOG_TOTAL_TIMEOUT || ast_tvdiff_sec(now, state_change) > WATCHDOG_STATE_TIMEOUT) {
663 ast_log(LOG_WARNING, "It looks like we hung. Aborting.\n");
668 t38_terminal_send_timeout(&t38, ast_tvdiff_us(now, last_frame) / (1000000 / 8000));
671 /* There was timeout waiting for a frame. Loop around and wait again */
675 /* There is a frame available. Get it */
678 if (!(inf = ast_read(s->chan))) {
679 ast_debug(1, "Channel hangup\n");
684 ast_debug(10, "frame %d/%d, len=%d\n", inf->frametype, inf->subclass.integer, inf->datalen);
686 if (inf->frametype == AST_FRAME_MODEM && inf->subclass.integer == AST_MODEM_T38) {
687 t38_core_rx_ifp_packet(t38state, inf->data.ptr, inf->datalen, inf->seqno);
688 if (last_state != t30state->state) {
689 state_change = ast_tvnow();
690 last_state = t30state->state;
692 } else if (inf->frametype == AST_FRAME_CONTROL && inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) {
693 struct ast_control_t38_parameters *parameters = inf->data.ptr;
694 if (parameters->request_response == AST_T38_TERMINATED) {
695 ast_debug(1, "T38 down, finishing\n");
703 ast_debug(1, "Loop finished, res=%d\n", res);
708 t30_terminate(t30state);
709 t38_terminal_release(&t38);
712 /* if we are not the caller, it's our job to shut down the T.38
713 * session when the FAX transmisson is complete.
715 if ((s->caller_mode == FALSE) &&
716 (ast_channel_get_t38_state(s->chan) == T38_STATE_NEGOTIATED)) {
717 struct ast_control_t38_parameters t38_parameters = { .request_response = AST_T38_REQUEST_TERMINATE, };
719 if (ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &t38_parameters, sizeof(t38_parameters)) == 0) {
720 /* wait up to five seconds for negotiation to complete */
721 unsigned int timeout = 5000;
724 ast_debug(1, "Shutting down T.38 on %s\n", s->chan->name);
725 while (timeout > 0) {
726 ms = ast_waitfor(s->chan, 1000);
728 ast_log(LOG_WARNING, "something bad happened while channel '%s' was polling.\n", s->chan->name);
732 /* nothing happened */
737 ast_log(LOG_WARNING, "channel '%s' timed-out during the T.38 shutdown.\n", s->chan->name);
741 if (!(inf = ast_read(s->chan))) {
744 if ((inf->frametype == AST_FRAME_CONTROL) &&
745 (inf->subclass.integer == AST_CONTROL_T38_PARAMETERS) &&
746 (inf->datalen == sizeof(t38_parameters))) {
747 struct ast_control_t38_parameters *parameters = inf->data.ptr;
749 switch (parameters->request_response) {
750 case AST_T38_TERMINATED:
751 ast_debug(1, "Shut down T.38 on %s\n", s->chan->name);
753 case AST_T38_REFUSED:
754 ast_log(LOG_WARNING, "channel '%s' refused to disable T.38\n", s->chan->name);
757 ast_log(LOG_ERROR, "channel '%s' failed to disable T.38\n", s->chan->name);
771 static int transmit(fax_session *s)
775 /* Clear all channel variables which to be set by the application.
776 Pre-set status to error so in case of any problems we can just leave */
777 pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED");
778 pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems");
780 pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
781 pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
782 pbx_builtin_setvar_helper(s->chan, "FAXPAGES", "0");
783 pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
784 pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL);
786 if (s->chan->_state != AST_STATE_UP) {
787 /* Shouldn't need this, but checking to see if channel is already answered
788 * Theoretically asterisk should already have answered before running the app */
789 res = ast_answer(s->chan);
791 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", s->chan->name);
796 s->t38state = ast_channel_get_t38_state(s->chan);
797 if (s->t38state != T38_STATE_NEGOTIATED) {
798 /* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */
799 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio");
800 res = transmit_audio(s);
802 /* transmit_audio reports switchover to T38. Update t38state */
803 s->t38state = ast_channel_get_t38_state(s->chan);
804 if (s->t38state != T38_STATE_NEGOTIATED) {
805 ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
810 if (s->t38state == T38_STATE_NEGOTIATED) {
811 pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38");
812 res = transmit_t38(s);
816 ast_log(LOG_WARNING, "Transmission error\n");
818 } else if (s->finished < 0) {
819 ast_log(LOG_WARNING, "Transmission failed\n");
820 } else if (s->finished > 0) {
821 ast_debug(1, "Transmission finished Ok\n");
827 /* === Application functions === */
829 static int sndfax_exec(struct ast_channel *chan, const char *data)
833 fax_session session = { 0, };
834 char restore_digit_detect = 0;
836 AST_DECLARE_APP_ARGS(args,
837 AST_APP_ARG(file_name);
838 AST_APP_ARG(options);
842 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
846 /* The next few lines of code parse out the filename and header from the input string */
847 if (ast_strlen_zero(data)) {
848 /* No data implies no filename or anything is present */
849 ast_log(LOG_ERROR, "SendFAX requires an argument (filename)\n");
853 parse = ast_strdupa(data);
854 AST_STANDARD_APP_ARGS(args, parse);
856 session.caller_mode = TRUE;
859 if (strchr(args.options, 'a'))
860 session.caller_mode = FALSE;
864 session.direction = 1;
865 session.file_name = args.file_name;
867 session.finished = 0;
869 /* get current digit detection mode, then disable digit detection if enabled */
871 int dummy = sizeof(restore_digit_detect);
873 ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
876 if (restore_digit_detect) {
877 char new_digit_detect = 0;
879 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
882 /* disable FAX tone detection if enabled */
884 char new_fax_detect = 0;
886 ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
889 res = transmit(&session);
891 if (restore_digit_detect) {
892 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
898 static int rcvfax_exec(struct ast_channel *chan, const char *data)
903 char restore_digit_detect = 0;
905 AST_DECLARE_APP_ARGS(args,
906 AST_APP_ARG(file_name);
907 AST_APP_ARG(options);
911 ast_log(LOG_ERROR, "Fax channel is NULL. Giving up.\n");
915 /* The next few lines of code parse out the filename and header from the input string */
916 if (ast_strlen_zero(data)) {
917 /* No data implies no filename or anything is present */
918 ast_log(LOG_ERROR, "ReceiveFAX requires an argument (filename)\n");
922 parse = ast_strdupa(data);
923 AST_STANDARD_APP_ARGS(args, parse);
925 session.caller_mode = FALSE;
928 if (strchr(args.options, 'c'))
929 session.caller_mode = TRUE;
933 session.direction = 0;
934 session.file_name = args.file_name;
936 session.finished = 0;
938 /* get current digit detection mode, then disable digit detection if enabled */
940 int dummy = sizeof(restore_digit_detect);
942 ast_channel_queryoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, &dummy, 0);
945 if (restore_digit_detect) {
946 char new_digit_detect = 0;
948 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &new_digit_detect, sizeof(new_digit_detect), 0);
951 /* disable FAX tone detection if enabled */
953 char new_fax_detect = 0;
955 ast_channel_setoption(chan, AST_OPTION_FAX_DETECT, &new_fax_detect, sizeof(new_fax_detect), 0);
958 res = transmit(&session);
960 if (restore_digit_detect) {
961 ast_channel_setoption(chan, AST_OPTION_DIGIT_DETECT, &restore_digit_detect, sizeof(restore_digit_detect), 0);
967 static int unload_module(void)
971 res = ast_unregister_application(app_sndfax_name);
972 res |= ast_unregister_application(app_rcvfax_name);
977 static int load_module(void)
981 res = ast_register_application_xml(app_sndfax_name, sndfax_exec);
982 res |= ast_register_application_xml(app_rcvfax_name, rcvfax_exec);
984 /* The default SPAN message handler prints to stderr. It is something we do not want */
985 span_set_message_handler(NULL);
991 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Simple FAX Application",
993 .unload = unload_module,