diff -Nrd -U3 asterisk-1.4.24.1/apps/Makefile asterisk-1.4.24.1.aleph/apps/Makefile --- asterisk-1.4.24.1/apps/Makefile 2008-07-04 00:20:16.000000000 +0200 +++ asterisk-1.4.24.1.aleph/apps/Makefile 2009-05-12 10:36:21.000000000 +0200 @@ -37,6 +37,9 @@ MENUSELECT_DEPENDS_app_directory+=$(MENUSELECT_DEPENDS_IMAP_STORAGE) endif +MENUSELECT_DEPENDS_app_rxfax+=SPANDSP +MENUSELECT_DEPENDS_app_txfax+=SPANDSP + all: _all include $(ASTTOPDIR)/Makefile.moddir_rules diff -Nrd -U3 asterisk-1.4.24.1/apps/app_fax.c asterisk-1.4.24.1.aleph/apps/app_fax.c --- asterisk-1.4.24.1/apps/app_fax.c 1970-01-01 01:00:00.000000000 +0100 +++ asterisk-1.4.24.1.aleph/apps/app_fax.c 2009-05-12 10:38:03.000000000 +0200 @@ -0,0 +1,632 @@ +/* + * Application to send or receive a TIFF FAX file + * based on app_rxfax.c from: Copyright (C) 2003, Steve Underwood <steveu@coppice.org> + * based on app_rxfax.c from www.callweaver.org, Massimo Cetra & more. + * based on app_rxfax.c from Antonio Gallo + * (C) 2009 by Antonio Gallo <agx@linux.it> + */ + +/*** MODULEINFO +Depends: libspandsp +Desciption: Send or Receive FAXes +DisplayName: FAX + ***/ + +#include "asterisk.h" + +ASTERISK_FILE_VERSION(__FILE__, "$Revision:$") + +#include <errno.h> + +#define SPANDSP_EXPOSE_INTERNAL_STRUCTURES +#include <spandsp.h> +#include <spandsp/version.h> +#if SPANDSP_RELEASE_DATE < 20081212 +#error YOU NEED SPANDSP 0.0.6 pre3 to compile this +#endif + +#include "asterisk/version.h" +#include "asterisk/pbx.h" +#include "asterisk/file.h" +#include "asterisk/module.h" +#include "asterisk/manager.h" +#include "asterisk/options.h" + +#ifndef AST_MODULE +#define AST_MODULE "app_fax" +#endif + +static char *rxfax_app = "RxFAX"; +static char *txfax_app = "TxFAX"; + +static char *rxfax_synopsis = "Receive a FAX to a file"; +static char *txfax_synopsis = "Send a FAX from a file"; + +#define FAX_PROTOCOL_DESC "" \ + " DISABLE_V17 to disable V.17 only\n" \ + " FAX_FORCE_V17 to force V.17 only\n" \ + " FAX_FORCE_V27 to force V.27 only\n" \ + " FAX_FORCE_V29 to force V.29 only\n" \ + " FAX_FORCE_V34 to force V.34 only\n" \ + "\n" + +#define FAX_RESULT_DESC "" \ + "Sets REMOTESTATIONID to the sender CSID.\n" \ + " FAXPAGES to the number of pages received.\n" \ + " FAXBITRATE to the transmition rate.\n" \ + " FAXRESOLUTION to the resolution.\n" \ + " PHASEESTATUS to the phase E result status.\n" \ + " PHASEESTRING to the phase E result string.\n" \ + "\n" + + +static char *rxfax_descrip = + " RxFAX(filename[|debug]): Receives a FAX from the channel into the\n" + "given filename. If the file exists it will be overwritten. The file\n" + "should be in TIFF/F format.\n" + "The \"ecm\" option enables ECM.\n" + "\n" + "Uses LOCALSTATIONID to identify itself to the remote end.\n" + " LOCALSUBADDRESS to specify a sub-address to the remote end.\n" + " LOCALHEADERINFO to generate a header line on each page.\n" + FAX_PROTOCOL_DESC + FAX_RESULT_DESC + "Note that PHASEESTATUS=0 means that the fax was handled correctly. But that doesn't\n" + "imply that any pages were sent. Actually you should also check FAXPAGES to be\n" + "greater than zero.\n" + "Returns -1 when the user hangs up.\n" + "Returns 0 otherwise.\n"; + +static char *txfax_descrip = + " TxFAX(filename[|verbose][|debug][|ecm]): Send a given TIFF file to the channel as a FAX.\n" + "The \"ecm\" option enables ECM.\n" + "\n" + "Uses LOCALSTATIONID to identify itself to the remote end.\n" + " LOCALHEADERINFO to generate a header line on each page.\n" + FAX_PROTOCOL_DESC + FAX_RESULT_DESC + "Returns -1 when the user hangs up, or if the file does not exist.\n" + "Returns 0 otherwise.\n"; + +#define MAX_BLOCK_SIZE 240 + +typedef struct { + struct ast_channel *chan; + fax_state_t fax; + volatile int sendfax; + volatile int finished; +} t_session; + + +static void span_message(int level, const char *msg) +{ + int ast_level; + if (msg==NULL) return; + if ( (level == SPAN_LOG_ERROR) || (level == SPAN_LOG_PROTOCOL_ERROR) ) + ast_level = __LOG_ERROR; + else if ( (level == SPAN_LOG_WARNING) || (level == SPAN_LOG_PROTOCOL_WARNING ) ) + ast_level = __LOG_WARNING; + else if ( (level == SPAN_LOG_FLOW) || (level == SPAN_LOG_FLOW_2) || (level == SPAN_LOG_FLOW_3) ) { + if (option_verbose>=255) { + ast_verbose( VERBOSE_PREFIX_4 "%s", msg); + } + return; + } else { + if (option_verbose>=255) { + ast_verbose( VERBOSE_PREFIX_4 VERBOSE_PREFIX_4 "%s", msg); + } + return; + } + ast_log(ast_level, _A_, "%s", msg); + ast_verbose( VERBOSE_PREFIX_3 "%s", msg); +} + +/*- End of function --------------------------------------------------------*/ + +static int phase_b_handler(t30_state_t *s, void *user_data, int result) +{ + t_session *psession = (t_session *) user_data; + char *appname = (psession->sendfax) ? "TXFAX" : "RXFAX"; + ast_log( LOG_DEBUG, "[%s phase_b_handler] channel: %s\n", appname, psession->chan->name ); + return T30_ERR_OK; +} + +/*- End of function --------------------------------------------------------*/ + +static void phase_e_handler(t30_state_t *s, void *user_data, int result) +{ + struct ast_channel *chan; + const char *tx_ident; + const char *rx_ident; + char buf[128]; + t30_stats_t t; + + t_session *psession = (t_session *) user_data; + chan = psession->chan; + t30_get_transfer_statistics(s, &t); + + tx_ident = t30_get_tx_ident(s); + if (tx_ident == NULL) + tx_ident = ""; + rx_ident = t30_get_rx_ident(s); + if (rx_ident == NULL) + rx_ident = ""; + pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", rx_ident); + snprintf(buf, sizeof(buf), "%d", t.pages_transferred); + pbx_builtin_setvar_helper(chan, "FAXPAGES", buf); + snprintf(buf, sizeof(buf), "%d", t.y_resolution); + pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", buf); + snprintf(buf, sizeof(buf), "%d", t.bit_rate); + pbx_builtin_setvar_helper(chan, "FAXBITRATE", buf); + snprintf(buf, sizeof(buf), "%d", result); + pbx_builtin_setvar_helper(chan, "PHASEESTATUS", buf); + snprintf(buf, sizeof(buf), "%s", t30_completion_code_to_str(result)); + pbx_builtin_setvar_helper(chan, "PHASEESTRING", buf); + + // This is to tell asterisk later that the fax has finished (with or without error) + char *direction = NULL; + if (psession->sendfax) { + psession->finished = TRUE; + direction = "FaxSent"; + } else { + direction = "FaxReceived"; + } + + if (result == T30_ERR_OK) + { + manager_event(EVENT_FLAG_CALL, + direction, "Channel: %s\nExten: %s\nCallerID: %s\nRemoteStationID: %s\nLocalStationID: %s\nPagesTransferred: %i\nResolution: %i\nTransferRate: %i\nFileName: %s\n", + chan->name, + chan->exten, + (chan->cid.cid_num) ? chan->cid.cid_num : "", + rx_ident, + tx_ident, + t.pages_transferred, + t.y_resolution, + t.bit_rate, + s->rx_file); + ast_log(LOG_NOTICE, "[%s OK] Remote: %s Local: %s Pages: %i Speed: %i \n", direction, rx_ident, tx_ident, t.pages_transferred, t.bit_rate ); + ast_verbose(VERBOSE_PREFIX_1 "[%s OK] Remote: %s Local: %s Pages: %i Speed: %i \n", direction, rx_ident, tx_ident, t.pages_transferred, t.bit_rate ); + } + else + { + ast_log(LOG_ERROR, "[%s ERROR] result (%d) %s.\n", direction, result, t30_completion_code_to_str(result)); + ast_verbose(VERBOSE_PREFIX_1 "[%s ERROR] result (%d) %s.\n", direction, result, t30_completion_code_to_str(result)); + } +} +/*- End of function --------------------------------------------------------*/ + +static int phase_d_handler(t30_state_t *s, void *user_data, int result) +{ + t30_stats_t t; + t_session *psession = (t_session *) user_data; + + if (result) + { + char *direction = (psession->sendfax) ? "TXFAX" : "RXFAX"; + t30_get_transfer_statistics(s, &t); + ast_log(LOG_NOTICE, "[%s NEW PAGE]: Channel: %s Pages: %i Speed: %i\n", direction, psession->chan->name, t.pages_transferred, t.bit_rate ); + ast_log(LOG_NOTICE, " Bad rows: %i - Longest bad row run: %i - Compression type: %s\n", t.bad_rows, t.longest_bad_row_run, t4_encoding_to_str(t.encoding)); + ast_log(LOG_NOTICE, " Image size bytes: %i - Image size: %i x %i - Image resolution: %i x %i\n", t.image_size, t.width, t.length, t.x_resolution, t.y_resolution); + ast_verbose(VERBOSE_PREFIX_3 "[%s NEW PAGE]: Channel: %s Pages: %i Speed: %i\n", direction, psession->chan->name, t.pages_transferred, t.bit_rate ); + } + return T30_ERR_OK; +} +/*- End of function --------------------------------------------------------*/ + +static int fax_run(struct ast_channel *chan, void *data, int sendfax) +{ + int res = 0; + char tiff_file[256]; + char template_file[256]; + int samples; + char *s; + char *t; + char *v; + const char *x; + int option; + int len; + struct ast_frame *inf = NULL; + struct ast_frame outf; + int verbose; + int ecm = FALSE; + + struct ast_module_user *u; + + int original_read_fmt; + int original_write_fmt; + int i; + + t_session session; + session.chan = chan; + session.finished = FALSE; + session.sendfax = sendfax; + memset( &session.fax, 0, sizeof(fax_state_t)); + + // Indetify the app + char *appname = (sendfax) ? "TXFAX" : "RXFAX"; + + /* Basic initial checkings */ + + if (chan == NULL) { + ast_log(LOG_ERROR, "%s: channel is NULL. Giving up.\n", appname); + return -1; + } + + + /* Resetting channel variables related to T38 */ + pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", ""); + pbx_builtin_setvar_helper(chan, "FAXPAGES", ""); + pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", ""); + pbx_builtin_setvar_helper(chan, "FAXBITRATE", ""); + pbx_builtin_setvar_helper(chan, "PHASEESTATUS", ""); + pbx_builtin_setvar_helper(chan, "PHASEESTRING", ""); + + /* Parsig parameters */ + + /* The next few lines of code parse out the filename and header from the input string */ + if (data == NULL) + { + /* No data implies no filename or anything is present */ + ast_log(LOG_ERROR, "%s: requires an argument (filename)\n", appname); + return -1; + } + + verbose = FALSE; + tiff_file[0] = '\0'; + + char tbuf[256]; + for (option = 0, v = s = data; v; option++, s++) { + t = s; + v = strchr(s, '|'); + s = (v) ? v : s + strlen(s); + strncpy((char *) tbuf, t, s - t); + tbuf[s - t] = '\0'; + if (option == 0) { + /* The first option is always the file name */ + len = s - t; + if (len > 255) + len = 255; + strncpy(tiff_file, t, len); + tiff_file[len] = '\0'; + if (!sendfax) { + /* Allow the use of %d in the file name for a wild card of sorts, to + create a new file with the specified name scheme */ + if ((x = strchr(tiff_file, '%')) && x[1] == 'd') { + strcpy(template_file, tiff_file); + i = 0; + do { + snprintf(tiff_file, 256, template_file, 1); + i++; + } while (ast_fileexists(tiff_file, "", chan->language) != -1); + } + } + } else if (strncmp("debug", t, s - t) == 0) { + verbose = TRUE; + } else if (strncmp("verbose", t, s - t) == 0) { + verbose = TRUE; + } else if (strncmp("ecm", t, s - t) == 0) { + ecm = TRUE; + } + } + /* Done parsing */ + + u = ast_module_user_add(chan); + + // Answer the channel + if (chan->_state != AST_STATE_UP) + { + ast_log(LOG_DEBUG, "%s: TODO: answering channel '%s'\n", appname, chan->name); + //res = ast_answer(chan); + ast_answer(chan); + } + + /* Setting read and write formats */ + + original_read_fmt = chan->readformat; + if (original_read_fmt != AST_FORMAT_SLINEAR) + { + res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); + if (res < 0) + { + ast_log(LOG_WARNING, "%s: Unable to set to linear read mode, giving up\n", appname); + ast_module_user_remove(u); + return -1; + } + } + + original_write_fmt = chan->writeformat; + if (original_write_fmt != AST_FORMAT_SLINEAR) + { + res = ast_set_write_format(chan, AST_FORMAT_SLINEAR); + if (res < 0) + { + ast_log(LOG_ERROR, "%s: Unable to set to linear write mode, giving up\n", appname); + res = ast_set_read_format(chan, original_read_fmt); + if (res) + ast_log(LOG_WARNING, "%s: Unable to restore read format on '%s'\n", appname, chan->name); + ast_module_user_remove(u); + return -1; + } + } + + /* Remove any app level gain adjustments and disable echo cancel. */ + signed char sc; + sc = 0; + ast_channel_setoption(chan, AST_OPTION_RXGAIN, &sc, sizeof(sc), 0); + ast_channel_setoption(chan, AST_OPTION_TXGAIN, &sc, sizeof(sc), 0); + ast_channel_setoption(chan, AST_OPTION_ECHOCAN, &sc, sizeof(sc), 0); + + /* This is the main loop */ + + uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET]; + uint8_t *buf = __buf + AST_FRIENDLY_OFFSET; + + + if (fax_init(&session.fax, sendfax) == NULL) + { + ast_log(LOG_ERROR, "%s: fax_init() Unable to start\n", appname); + ast_module_user_remove(u); + return -1; + } + fax_set_transmit_on_idle(&session.fax, TRUE); + span_log_set_message_handler(&session.fax.logging, span_message); + span_log_set_message_handler(&session.fax.t30.logging, span_message); + if (verbose) + { + span_log_set_level(&session.fax.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + span_log_set_level(&session.fax.t30.logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + } else { + span_log_set_level(&session.fax.logging, SPAN_LOG_ERROR | SPAN_LOG_WARNING | SPAN_LOG_PROTOCOL_ERROR | SPAN_LOG_PROTOCOL_WARNING ); + span_log_set_level(&session.fax.t30.logging, SPAN_LOG_ERROR | SPAN_LOG_WARNING | SPAN_LOG_PROTOCOL_ERROR | SPAN_LOG_PROTOCOL_WARNING ); + } + x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID"); + if (x && x[0]) + t30_set_tx_ident(&session.fax.t30, x); + x = pbx_builtin_getvar_helper(chan, "LOCALSUBADDRESS"); + if (x && x[0]) + t30_set_tx_sub_address(&session.fax.t30, x); + x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO"); + if (x && x[0]) + t30_set_tx_page_header_info(&session.fax.t30, x); + t30_set_phase_b_handler(&session.fax.t30, phase_b_handler, &session); + t30_set_phase_d_handler(&session.fax.t30, phase_d_handler, &session); + t30_set_phase_e_handler(&session.fax.t30, phase_e_handler, &session); + if (!sendfax) { + t30_set_rx_file(&session.fax.t30, tiff_file, -1); + } else { + t30_set_tx_file(&session.fax.t30, tiff_file, -1, -1); + } + + // Default Support ALL + t30_set_supported_modems(&(session.fax.t30), T30_SUPPORT_V29 | T30_SUPPORT_V27TER | T30_SUPPORT_V17 ); + + x = pbx_builtin_getvar_helper(chan, "FAX_DISABLE_V17"); + if (x && x[0]) + t30_set_supported_modems(&(session.fax.t30), T30_SUPPORT_V29 | T30_SUPPORT_V27TER); + x = pbx_builtin_getvar_helper(chan, "FAX_FORCE_V17"); + if (x && x[0]) + t30_set_supported_modems(&(session.fax.t30), T30_SUPPORT_V17); + x = pbx_builtin_getvar_helper(chan, "FAX_FORCE_V27"); + if (x && x[0]) + t30_set_supported_modems(&(session.fax.t30), T30_SUPPORT_V27TER); + x = pbx_builtin_getvar_helper(chan, "FAX_FORCE_V29"); + if (x && x[0]) + t30_set_supported_modems(&(session.fax.t30), T30_SUPPORT_V29); + x = pbx_builtin_getvar_helper(chan, "FAX_FORCE_V34"); + if (x && x[0]) + t30_set_supported_modems(&(session.fax.t30), T30_SUPPORT_V34); + + /* Support for different image sizes && resolutions*/ + t30_set_supported_image_sizes(&session.fax.t30, T30_SUPPORT_US_LETTER_LENGTH | T30_SUPPORT_US_LEGAL_LENGTH | T30_SUPPORT_UNLIMITED_LENGTH + | T30_SUPPORT_215MM_WIDTH | T30_SUPPORT_255MM_WIDTH | T30_SUPPORT_303MM_WIDTH); + t30_set_supported_resolutions(&session.fax.t30, T30_SUPPORT_STANDARD_RESOLUTION | T30_SUPPORT_FINE_RESOLUTION | T30_SUPPORT_SUPERFINE_RESOLUTION + | T30_SUPPORT_R8_RESOLUTION | T30_SUPPORT_R16_RESOLUTION); + if (ecm) { + t30_set_ecm_capability(&(session.fax.t30), TRUE); + t30_set_supported_compressions(&(session.fax.t30), T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION); + } else { + t30_set_ecm_capability(&(session.fax.t30), FALSE); + t30_set_supported_compressions(&(session.fax.t30), T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION ); + ast_log(LOG_DEBUG, "%s: ECM mode is not enabled\n", appname ); + } + + + /* This is the main loop */ + + res = 0; + + /* temporary workwaround vars */ + int donotspam=10; + int watchdog=256; + + while ( (!session.finished) && chan ) + { + // new from 0.0.6 + if (!t30_call_active(&session.fax.t30)) { + ast_log(LOG_WARNING, "%s: t30_call_active is FALSE.\n", appname); + res = 0; + break; + } + + if ((session.fax.t30.current_rx_type == T30_MODEM_DONE) || (session.fax.t30.current_tx_type == T30_MODEM_DONE)) { + /* Avoid spamming debug info */ + if (donotspam>0) { + ast_log(LOG_WARNING, "%s: Channel T30 DONE < 0.\n", appname); + donotspam--; + } + /* + * Workaround: let 256 more packet to pass thru then definitively hangup + */ + if (watchdog>0) { + watchdog--; + } else { + break; + } + } + + if (ast_check_hangup(chan)) { + ast_log(LOG_WARNING, "%s: Channel has been hanged at fax.\n", appname); + res = 0; + break; + } + + if ((res = ast_waitfor(chan, 20)) < 0) { + ast_log(LOG_WARNING, "%s: Channel ast_waitfor < 0.\n", appname); + res = 0; + break; + } + + /* + * in asterisk 1.4.24 ast_waitfor has been changed + * ast_read generate a warning in channel.c since now ast_waitfor returning 0 + * means "TIMEOUT" + * so if the previous function return 0 we have to loop and try again + */ + if (res == 0) { + continue; + } + + inf = ast_read(chan); + if (inf == NULL) + { + ast_log(LOG_WARNING, "%s: Channel INF is NULL, i will continue...\n", appname); + // PROBABLY: While trasmiitting i got: Received a DCN from remote after sending a page at last page + continue; + } + + /* We got a frame */ + /* Check the frame type. Format also must be checked because there is a chance + that a frame in old format was already queued before we set chanel format + to slinear so it will still be received by ast_read */ + if (inf->frametype == AST_FRAME_VOICE && inf->subclass == AST_FORMAT_SLINEAR) { + if (fax_rx(&session.fax, inf->data, inf->samples)) { + ast_log(LOG_WARNING, "%s: fax_rx returned error\n", appname); + res = -1; + break; + } + + samples = (inf->samples <= MAX_BLOCK_SIZE) ? inf->samples : MAX_BLOCK_SIZE; + len = fax_tx(&session.fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples); + if (len>0) { + memset(&outf, 0, sizeof(outf)); + outf.frametype = AST_FRAME_VOICE; + outf.subclass = AST_FORMAT_SLINEAR; + outf.datalen = len*sizeof(int16_t); + outf.samples = len; + outf.data = &buf[AST_FRIENDLY_OFFSET]; + outf.offset = AST_FRIENDLY_OFFSET; + outf.src = appname; + if (ast_write(chan, &outf) < 0) + { + ast_log(LOG_WARNING, "%s: Unable to write frame to channel; %s\n", appname, strerror(errno)); + res = -1; + break; + } + } + else + { + // Queue empty frame? + len = samples; + memset(&outf, 0, sizeof(outf)); + outf.frametype = AST_FRAME_VOICE; + outf.subclass = AST_FORMAT_SLINEAR; + outf.datalen = len*sizeof(int16_t); + outf.samples = len; + outf.data = &buf[AST_FRIENDLY_OFFSET]; + outf.offset = AST_FRIENDLY_OFFSET; + outf.src = appname; + // clear data before to write + memset(&buf[AST_FRIENDLY_OFFSET], 0, outf.datalen); + if (ast_write(chan, &outf) < 0) + { + ast_log(LOG_WARNING, "%s: Unable to write frame to channel; %s\n", appname, strerror(errno)); + res = -1; + break; + } + } + // end if: len>0 + } + ast_frfree(inf); + inf = NULL; + /* TODO put a Watchdog here */ + } + + if (inf != NULL) + { + ast_frfree(inf); + inf = NULL; + } + + t30_terminate(&session.fax.t30); + fax_release(&session.fax); + if (sendfax) { + if (session.finished) { + ast_log(LOG_WARNING, "TXFAX: Fax Transmission complete, check return code\n"); + res = 0; + } else { + ast_log(LOG_WARNING, "TXFAX: Fax Transmission INCOMPLETE, check error code\n"); + res = -1; + } + if (res!=0) { + ast_log(LOG_WARNING, "TXFAX: Transmission RES error = %i\n", res); + } + } + + /* Restoring initial channel formats. */ + + if (original_read_fmt != AST_FORMAT_SLINEAR) + { + res = ast_set_read_format(chan, original_read_fmt); + if (res) + ast_log(LOG_WARNING, "%s: Unable to restore read format on '%s'\n", appname, chan->name); + } + if (original_write_fmt != AST_FORMAT_SLINEAR) + { + res = ast_set_write_format(chan, original_write_fmt); + if (res) + ast_log(LOG_WARNING, "%s: Unable to restore write format on '%s'\n", appname, chan->name); + } + ast_module_user_remove(u); + return res; +} + +/*- End of function --------------------------------------------------------*/ + +static int rxfax_exec(struct ast_channel *chan, void *data) { + return fax_run(chan,data,FALSE); +} + +static int txfax_exec(struct ast_channel *chan, void *data) { + return fax_run(chan,data,TRUE); +} + +/*- End of function --------------------------------------------------------*/ + +static int unload_module(void) +{ + int res = 0; + ast_module_user_hangup_all(); + res = ast_unregister_application(rxfax_app); + res |= ast_unregister_application(txfax_app); + return res; +} +/*- End of function --------------------------------------------------------*/ + +static int load_module(void) +{ + ast_log(LOG_NOTICE, "app_fax using spandsp %i %i\n", SPANDSP_RELEASE_DATE, SPANDSP_RELEASE_TIME ); + if (ASTERISK_VERSION_NUM != 10424) + ast_log(LOG_WARNING, "app_fax is tested with asterisk 1.4.24\n"); + int res = 0; + res = ast_register_application(rxfax_app, rxfax_exec, rxfax_synopsis, rxfax_descrip); + res |= ast_register_application(txfax_app, txfax_exec, txfax_synopsis, txfax_descrip); + return res; +} + +/*- End of function --------------------------------------------------------*/ + +AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "FAX Application based on SpanDSP"); + +/*- End of file ------------------------------------------------------------*/ + diff -Nrd -U3 asterisk-1.4.24.1/build_tools/menuselect-deps.in asterisk-1.4.24.1.aleph/build_tools/menuselect-deps.in --- asterisk-1.4.24.1/build_tools/menuselect-deps.in 2009-01-29 23:54:29.000000000 +0100 +++ asterisk-1.4.24.1.aleph/build_tools/menuselect-deps.in 2009-05-12 10:36:21.000000000 +0200 @@ -23,6 +23,7 @@ POPT=@PBX_POPT@ PRI=@PBX_PRI@ RADIUS=@PBX_RADIUS@ +SPANDSP=@PBX_SPANDSP@ SPEEX=@PBX_SPEEX@ SPEEXDSP=@PBX_SPEEXDSP@ SPEEX_PREPROCESS=@PBX_SPEEX_PREPROCESS@ diff -Nrd -U3 asterisk-1.4.24.1/configure.ac asterisk-1.4.24.1.aleph/configure.ac --- asterisk-1.4.24.1/configure.ac 2009-05-12 10:35:43.000000000 +0200 +++ asterisk-1.4.24.1.aleph/configure.ac 2009-05-12 10:36:21.000000000 +0200 @@ -210,6 +210,7 @@ AST_EXT_LIB_SETUP([PWLIB], [PWlib], [pwlib]) AST_EXT_LIB_SETUP([OPENH323], [OpenH323], [h323]) AST_EXT_LIB_SETUP([RADIUS], [Radius Client], [radius]) +AST_EXT_LIB_SETUP([SPANDSP], [spandsp Library], [spandsp]) AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex]) AST_EXT_LIB_SETUP([SPEEXDSP], [Speexdsp], [speexdsp]) AST_EXT_LIB_SETUP_DEPENDENT([SPEEX_PREPROCESS], [speex_preprocess_ctl], [], [speex]) @@ -1365,6 +1366,8 @@ AST_EXT_LIB_CHECK([RADIUS], [radiusclient-ng], [rc_read_config], [radiusclient-ng.h]) +AST_EXT_LIB_CHECK([SPANDSP], [spandsp], [fax_init], [spandsp.h], [-ltiff]) + AST_EXT_LIB_CHECK([SPEEX], [speex], [speex_encode], [speex/speex.h], [-lm]) # See if the main speex library contains the preprocess functions diff -Nrd -U3 asterisk-1.4.24.1/makeopts.in asterisk-1.4.24.1.aleph/makeopts.in --- asterisk-1.4.24.1/makeopts.in 2008-11-29 17:58:29.000000000 +0100 +++ asterisk-1.4.24.1.aleph/makeopts.in 2009-05-12 10:36:21.000000000 +0200 @@ -139,6 +139,9 @@ RADIUS_INCLUDE=@RADIUS_INCLUDE@ RADIUS_LIB=@RADIUS_LIB@ +SPANDSP_INCLUDE=@SPANDSP_INCLUDE@ +SPANDSP_LIB=@SPANDSP_LIB@ + SPEEX_INCLUDE=@SPEEX_INCLUDE@ SPEEX_LIB=@SPEEX_LIB@