2 * Application to send a TIFF file as a FAX
3 * based on app_txfax.c from: Copyright (C) 2003, Steve Underwood <steveu@coppice.org>
4 * PATCHED BY (C) 20007 by Antonio Gallo <agx@linux.it>
6 * - added more env variables
7 * - added logging to external file
12 Desciption: Send a FAX file
18 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29 #include <spandsp/version.h>
31 #include "asterisk/lock.h"
32 #include "asterisk/file.h"
33 #include "asterisk/logger.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/module.h"
37 #include "asterisk/manager.h"
40 #define AST_MODULE "app_txfax"
43 static char *app = "TxFAX";
45 static char *synopsis = "Send a FAX file";
47 static char *descrip =
48 " TxFAX(filename[|caller][|debug][|ecm]): Send a given TIFF file to the channel as a FAX.\n"
49 "The \"caller\" option makes the application behave as a calling machine,\n"
50 "rather than the answering machine. The default behaviour is to behave as\n"
51 "an answering machine.\n"
52 "The \"ecm\" option enables ECM.\n"
53 "Uses LOCALSTATIONID to identify itself to the remote end.\n"
54 " LOCALHEADERINFO to generate a header line on each page.\n"
55 "Sets REMOTESTATIONID to the receiver CSID.\n"
56 " FAXPAGES to the number of pages sent.\n"
57 " FAXBITRATE to the transmition rate.\n"
58 " FAXRESOLUTION to the resolution.\n"
59 " PHASEESTATUS to the phase E result status.\n"
60 " PHASEESTRING to the phase E result string.\n"
61 "Returns -1 when the user hangs up, or if the file does not exist.\n"
62 "Returns 0 otherwise.\n";
64 #define MAX_BLOCK_SIZE 240
66 static FILE *txfax_logfile = NULL;
68 static void file_log(const char *msg)
72 if (txfax_logfile==NULL)
74 fprintf(txfax_logfile, msg);
77 static void span_message(int level, const char *msg)
79 if (msg==NULL) return;
81 if (level == SPAN_LOG_ERROR)
82 ast_level = __LOG_ERROR;
83 else if (level == SPAN_LOG_WARNING)
84 ast_level = __LOG_WARNING;
86 ast_level = __LOG_DEBUG;
87 ast_log(ast_level, _A_, "%s", msg);
90 /*- End of function --------------------------------------------------------*/
93 struct ast_channel *chan;
95 volatile int finished;
98 static void phase_b_handler(t30_state_t *s, void *user_data, int result)
100 if (txfax_logfile!=NULL) {
101 fprintf( txfax_logfile, "[phase_b_handler] mark\n" );
102 fflush(txfax_logfile);
106 static void phase_e_handler(t30_state_t *s, void *user_data, int result)
108 struct ast_channel *chan;
109 char local_ident[21];
114 fax_session *fax = (fax_session *) user_data;
116 t30_get_transfer_statistics(s, &t);
118 t30_get_local_ident(s, local_ident);
119 t30_get_far_ident(s, far_ident);
120 pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident);
121 snprintf(buf, sizeof(buf), "%d", t.pages_transferred);
122 pbx_builtin_setvar_helper(chan, "FAXPAGES", buf);
123 snprintf(buf, sizeof(buf), "%d", t.y_resolution);
124 pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", buf);
125 snprintf(buf, sizeof(buf), "%d", t.bit_rate);
126 pbx_builtin_setvar_helper(chan, "FAXBITRATE", buf);
127 snprintf(buf, sizeof(buf), "%d", result);
128 pbx_builtin_setvar_helper(chan, "PHASEESTATUS", buf);
129 snprintf(buf, sizeof(buf), "%s", t30_completion_code_to_str(result));
130 pbx_builtin_setvar_helper(chan, "PHASEESTRING", buf);
132 // This is to tell asterisk later that the fax has finished (with or without error)
135 ast_log(LOG_DEBUG, "==============================================================================\n");
136 if (result == T30_ERR_OK)
138 ast_log(LOG_DEBUG, "Fax successfully sent.\n");
139 ast_log(LOG_DEBUG, "Remote station id: %s\n", far_ident);
140 ast_log(LOG_DEBUG, "Local station id: %s\n", local_ident);
141 ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred);
142 ast_log(LOG_DEBUG, "Image resolution: %i x %i\n", t.x_resolution, t.y_resolution);
143 ast_log(LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate);
144 manager_event(EVENT_FLAG_CALL,
145 "FaxSent", "Channel: %s\nExten: %s\nCallerID: %s\nRemoteStationID: %s\nLocalStationID: %s\nPagesTransferred: %i\nResolution: %i\nTransferRate: %i\nFileName: %s\n",
148 (chan->cid.cid_num) ? chan->cid.cid_num : "",
155 if (txfax_logfile!=NULL) {
156 fprintf( txfax_logfile, "\n[FAX OK] Remote: %s Local: %s Pages: %i Speed: %i\n\n",
157 far_ident, local_ident, t.pages_transferred, t.bit_rate
159 fflush(txfax_logfile);
164 ast_log(LOG_DEBUG, "Fax send not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result));
165 if (txfax_logfile!=NULL) {
166 fprintf( txfax_logfile, "\n[FAX ERROR] code: %d %s\n\n", result, t30_completion_code_to_str(result) );
167 fflush(txfax_logfile);
170 ast_log(LOG_DEBUG, "==============================================================================\n");
172 /*- End of function --------------------------------------------------------*/
174 static void phase_d_handler(t30_state_t *s, void *user_data, int result)
176 // struct ast_channel *chan;
179 // chan = (struct ast_channel *) user_data;
182 t30_get_transfer_statistics(s, &t);
183 ast_log(LOG_DEBUG, "[ TXFAX ]=====================================================================\n");
184 ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred);
185 ast_log(LOG_DEBUG, "Image size: %i x %i\n", t.width, t.length);
186 ast_log(LOG_DEBUG, "Image resolution %i x %i\n", t.x_resolution, t.y_resolution);
187 ast_log(LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate);
188 ast_log(LOG_DEBUG, "Bad rows %i\n", t.bad_rows);
189 ast_log(LOG_DEBUG, "Longest bad row run %i\n", t.longest_bad_row_run);
190 ast_log(LOG_DEBUG, "Compression type %s\n", t4_encoding_to_str(t.encoding));
191 ast_log(LOG_DEBUG, "Image size (bytes) %i\n", t.image_size);
192 ast_log(LOG_DEBUG, "==============================================================================\n");
193 if (txfax_logfile!=NULL) {
194 fprintf( txfax_logfile, "\n[phase_d_handler] Page: %i at %i\n\n", t.pages_transferred, t.bit_rate );
195 fflush(txfax_logfile);
199 /*- End of function --------------------------------------------------------*/
201 static int txfax_exec(struct ast_channel *chan, void *data)
204 char source_file[256];
213 struct ast_frame *inf = NULL;
214 struct ast_frame outf;
219 struct ast_module_user *u;
221 int original_read_fmt;
222 int original_write_fmt;
226 session.finished = 0;
228 /* Basic initial checkings */
231 ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n");
232 file_log("ERROR: Fax receive channel is NULL. Giving up.\n");
236 span_set_message_handler(span_message);
237 /* make sure they are initialized to zero */
238 memset( &fax, 0, sizeof(fax));
240 /* Resetting channel variables related to T38 */
241 pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", "");
242 pbx_builtin_setvar_helper(chan, "FAXPAGES", "");
243 pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", "");
244 pbx_builtin_setvar_helper(chan, "FAXBITRATE", "");
245 pbx_builtin_setvar_helper(chan, "PHASEESTATUS", "");
246 pbx_builtin_setvar_helper(chan, "PHASEESTRING", "");
248 /* Parsig parameters */
250 /* The next few lines of code parse out the filename and header from the input string */
253 /* No data implies no filename or anything is present */
254 ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n");
255 file_log("ERROR: Txfax requires an argument (filename)\n");
259 calling_party = FALSE;
261 source_file[0] = '\0';
264 for (option = 0, v = s = data; v; option++, s++) {
267 s = (v) ? v : s + strlen(s);
268 strncpy((char *) tbuf, t, s - t);
271 /* The first option is always the file name */
275 strncpy(source_file, t, len);
276 source_file[len] = '\0';
277 } else if (strncmp("caller", t, s - t) == 0) {
278 calling_party = TRUE;
279 } else if (strncmp("debug", t, s - t) == 0) {
281 } else if (strncmp("ecm", t, s - t) == 0) {
288 u = ast_module_user_add(chan);
290 if (chan->_state != AST_STATE_UP)
292 /* Shouldn't need this, but checking to see if channel is already answered
293 * Theoretically asterisk should already have answered before running the app */
294 res = ast_answer(chan);
295 /* NO NEED TO WARN ANYMORE
298 ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
299 file_log("Could not answer channel\n" );
304 /* Setting read and write formats */
306 original_read_fmt = chan->readformat;
307 if (original_read_fmt != AST_FORMAT_SLINEAR)
309 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
312 ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
313 file_log("ERROR: Unable to set to linear read mode, giving up\n");
314 ast_module_user_remove(u);
319 original_write_fmt = chan->writeformat;
320 if (original_write_fmt != AST_FORMAT_SLINEAR)
322 res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
325 ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
326 file_log("Unable to set to linear write mode, giving up\n");
327 res = ast_set_read_format(chan, original_read_fmt);
329 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
330 ast_module_user_remove(u);
335 /* Remove any app level gain adjustments and disable echo cancel. */
338 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &sc, sizeof(sc), 0);
339 ast_channel_setoption(chan, AST_OPTION_TXGAIN, &sc, sizeof(sc), 0);
340 ast_channel_setoption(chan, AST_OPTION_ECHOCAN, &sc, sizeof(sc), 0);
342 /* This is the main loop */
344 uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
345 uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
347 memset(&fax, 0, sizeof(fax));
349 if (fax_init(&fax, calling_party) == NULL)
351 ast_log(LOG_WARNING, "Unable to start FAX\n");
352 file_log("Unable to set to start fax_init\n");
353 ast_module_user_remove(u);
356 fax_set_transmit_on_idle(&fax, TRUE);
357 span_log_set_message_handler(&fax.logging, span_message);
358 span_log_set_message_handler(&fax.t30_state.logging, span_message);
361 span_log_set_level(&fax.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
362 span_log_set_level(&fax.t30_state.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW);
364 x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
366 t30_set_local_ident(&fax.t30_state, x);
367 x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
369 t30_set_header_info(&fax.t30_state, x);
370 t30_set_tx_file(&fax.t30_state, source_file, -1, -1);
371 t30_set_phase_b_handler(&fax.t30_state, phase_b_handler, chan);
372 t30_set_phase_d_handler(&fax.t30_state, phase_d_handler, chan);
373 t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, &session);
375 x = pbx_builtin_getvar_helper(chan, "FAX_DISABLE_V17");
377 t30_set_supported_modems(&(fax.t30_state), T30_SUPPORT_V29 | T30_SUPPORT_V27TER);
379 t30_set_supported_modems(&(fax.t30_state), T30_SUPPORT_V29 | T30_SUPPORT_V27TER | T30_SUPPORT_V17 );
381 /* Support for different image sizes && resolutions*/
382 t30_set_supported_image_sizes(&fax.t30_state, T30_SUPPORT_US_LETTER_LENGTH | T30_SUPPORT_US_LEGAL_LENGTH | T30_SUPPORT_UNLIMITED_LENGTH
383 | T30_SUPPORT_215MM_WIDTH | T30_SUPPORT_255MM_WIDTH | T30_SUPPORT_303MM_WIDTH);
384 t30_set_supported_resolutions(&fax.t30_state, T30_SUPPORT_STANDARD_RESOLUTION | T30_SUPPORT_FINE_RESOLUTION | T30_SUPPORT_SUPERFINE_RESOLUTION
385 | T30_SUPPORT_R8_RESOLUTION | T30_SUPPORT_R16_RESOLUTION);
387 t30_set_ecm_capability(&(fax.t30_state), TRUE);
388 t30_set_supported_compressions(&(fax.t30_state), T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
389 ast_log(LOG_DEBUG, "Enabling ECM mode for app_txfax\n" );
390 file_log("Enabling ECM mode for app_rxfax\n" );
394 /* This is the main loop */
397 while ( (!session.finished) && chan )
399 if (ast_check_hangup(chan)) {
400 ast_log(LOG_WARNING, "TXFAX: Channel has been hanged at fax.\n");
401 file_log("INFO: Channel has been hanged at fax.\n");
406 if ((res = ast_waitfor(chan, 20)) < 0) {
407 ast_log(LOG_WARNING, "TXFAX: ast_waitfor returned less then 0.\n");
408 file_log("WARNING: Channel ast_waitfor < 0.\n");
413 /*if ((fax.current_rx_type == T30_MODEM_DONE) || (fax.current_tx_type == T30_MODEM_DONE)) {
414 ast_log(LOG_WARNING, "Channel T30 DONE < 0.\n");
415 file_log("Channel T30 DONE.\n");
420 inf = ast_read(chan);
423 //ast_log(LOG_WARNING, "TXFAX: transmission done with ast_read(chan) == NULL\n");
424 ast_log(LOG_WARNING, "Channel INF is NULL.\n");
425 file_log("DEBUG: Channel INF is NULL.\n");
427 // While trasmiitting i got: Received a DCN from remote after sending a page
437 //if (inf->frametype == AST_FRAME_VOICE) {
438 /* Check the frame type. Format also must be checked because there is a chance
439 that a frame in old format was already queued before we set chanel format
440 to slinear so it will still be received by ast_read */
441 if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) {
442 if (fax_rx(&fax, inf->data, inf->samples)) {
443 ast_log(LOG_WARNING, "TXFAX: fax_rx returned error\n");
448 samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE;
449 len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
452 ast_log(LOG_WARNING, "len <=0 using samples.\n");
453 file_log("len <= 0 using samples.\n");
456 memset(&outf, 0, sizeof(outf));
457 outf.frametype = AST_FRAME_VOICE;
458 outf.subclass = AST_FORMAT_SLINEAR;
459 outf.datalen = len*sizeof(int16_t);
461 outf.data = &buf[AST_FRIENDLY_OFFSET];
462 outf.offset = AST_FRIENDLY_OFFSET;
465 memset(&buf[AST_FRIENDLY_OFFSET], 0, outf.datalen);
467 if (ast_write(chan, &outf) < 0)
469 ast_log(LOG_WARNING, "TXFAX: Unable to write frame to channel; %s\n", strerror(errno));
470 file_log("FATAL ERROR: Unable to write frame to channel\n");
478 /* TODO put a Watchdog here */
487 t30_terminate(&fax.t30_state);
489 if (session.finished > 0) {
490 ast_log(LOG_WARNING, "Fax Transmission complete, check return code\n");
493 ast_log(LOG_WARNING, "Fax Transmission INCOMPLETE, check error code\n");
497 ast_log(LOG_WARNING, "Transmission RES error\n");
500 /* Restoring initial channel formats. */
502 if (original_read_fmt != AST_FORMAT_SLINEAR)
504 res = ast_set_read_format(chan, original_read_fmt);
506 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
508 if (original_write_fmt != AST_FORMAT_SLINEAR)
510 res = ast_set_write_format(chan, original_write_fmt);
512 ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
514 ast_module_user_remove(u);
517 /*- End of function --------------------------------------------------------*/
519 static int unload_module(void)
522 ast_module_user_hangup_all();
523 res = ast_unregister_application(app);
525 fclose(txfax_logfile);
526 txfax_logfile = NULL;
530 /*- End of function --------------------------------------------------------*/
532 static int load_module(void)
534 ast_log(LOG_NOTICE, "TxFax using spandsp %i %i\n", SPANDSP_RELEASE_DATE, SPANDSP_RELEASE_TIME );
535 txfax_logfile = fopen("/var/log/txfax.log", "w+" );
537 ast_log(LOG_WARNING, "TxFax output also available in /var/log/txfax.log\n" );
538 return ast_register_application(app, txfax_exec, synopsis, descrip);
540 /*- End of function --------------------------------------------------------*/
542 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial FAX Transmit Application");
544 /*- End of file ------------------------------------------------------------*/