Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Aug 2007 10:31:37 GMT
From:      Vladimir Korkodinov <viper@perm.raid.ru>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   ports/115710: [UPDATE] net/asterisk to 1.4.11(numerous bug fixes)
Message-ID:  <200708221031.l7MAVbga082005@www.freebsd.org>
Resent-Message-ID: <200708221040.l7MAe1ov070387@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         115710
>Category:       ports
>Synopsis:       [UPDATE] net/asterisk to 1.4.11(numerous bug fixes)
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Wed Aug 22 10:40:01 GMT 2007
>Closed-Date:
>Last-Modified:
>Originator:     Vladimir Korkodinov
>Release:        STABLE6
>Organization:
>Environment:
FreeBSD xxxxxx 6.2-STABLE FreeBSD 6.2-STABLE #2: Fri Jul 27 01:04:19 YEKST 2007     viper@xxxxxxx:/usr/obj/usr/src/sys/viper2  i386
>Description:
>From asterisk.org
"This version contains numerous bug fixes. One of these is for a security issue in chan_sip. The issue is that SIP dialog history was being stored in memory regardless if the option for this was turned on or off. This could be abused to cause a system using chan_sip to run out of memory.

The security issue is documented in AST-2007-020. Affected systems include any that are using chan_sip. Also, only Asterisk 1.4 is affected. Asterisk 1.2 is not vulnerable to this issue.

    * http://downloads.digium.com/pub/asa/AST-2007-020.pdf"

>How-To-Repeat:

>Fix:
Apply patch

o Upgrade to 1.4.11.
o Adds to build asterisk with the option IMAP STORAGE.
o Enable fax-related modules. Taken from the site http://soft-switch.org/downloads/snapshots/spandsp/test-apps-asterisk-1.4/
Compiled only with spandsp> 0.0.3

I am not leaving the idea to solve the problem with faxes within the existing port.
I really do not want to open a new port.
I hope maintainer will be forthcoming.

Patch attached with submission follows:

diff -ruN asterisk.orig/Makefile asterisk/Makefile
--- asterisk.orig/Makefile	2007-08-13 23:35:37.000000000 +0600
+++ asterisk/Makefile	2007-08-22 16:09:58.000000000 +0600
@@ -6,7 +6,7 @@
 #
 
 PORTNAME=	asterisk
-PORTVERSION=	1.4.10
+PORTVERSION=	1.4.11
 CATEGORIES=	net
 MASTER_SITES=	http://ftp.digium.com/pub/asterisk/ \
 		http://ftp.digium.com/pub/asterisk/old-releases/
@@ -47,8 +47,11 @@
 		FREETDS		"Enable FreeTDS support" on \
 		JABBER		"Enable Jabber and Gtalk support" on \
 		SQLITE          "Enable SQLITE support" on \
-		CODEC_PATCH	"Apply codec negotiation patch" off
+	        IMAP            "Enable IMAP support" off \
+	        FAX             "Enable FAX support" on						
 
+#		CODEC_PATCH	"Apply codec negotiation patch" off \
+WITH_CODEC_PATCH=no# don`t want build with new release
 .include <bsd.port.pre.mk>
 
 .if ${ARCH} == "i386" || ${ARCH} == "amd64"
@@ -163,8 +166,50 @@
 EXTRA_PATCHES=	${PATCHDIR}/nocodecnego-patch-Makefile
 .endif
 
+.if defined(WITHOUT_FAX)
+PLIST_SUB+=    WITH_FAX="@comment "
+.else
+MAKE_ENV+=     WITH_FAX=yes
+CONFIGURE_ARGS+= --with-spandsp=yes
+BUILD_DEPENDS+= spandsp>=0.0.3:${PORTSDIR}/comms/spandsp
+LIB_DEPENDS+=  spandsp.0:${PORTSDIR}/comms/spandsp
+PLIST_SUB+=    WITH_FAX=""
+.endif
+
+.if defined(WITHOUT_IMAP)
+PLIST_SUB+=    WITH_IMAP="@comment "
+.else
+MAKE_ENV+=     WITH_IMAP=yes
+CONFIGURE_ARGS+= --with-imap=${LOCALBASE}
+LIB_DEPENDS+=  c-client4.8:${PORTSDIR}/mail/cclient
+PLIST_SUB+=    WITH_IMAP
+.endif
+
 
 post-patch:
 	${REINPLACE_CMD} -e 's|/var/lib|${PREFIX}/share|g' ${WRKSRC}/configs/musiconhold.conf.sample
 
+.if defined(WITH_ODBC) && defined(WITH_IMAP)
+        @${ECHO_MSG}    ""
+	@${ECHO_MSG}    "WARNING!!! You can choose only one option for build app_voicemail"
+	@${ECHO_MSG}    ""
+.endif
+.if defined(WITH_ODBC)
+	@${ECHO_MSG}    ""
+	@${ECHO_MSG}    "If necessary, build  with the option ODBC_STORAGE"
+	@${ECHO_MSG}    "press Ctrl-C and run following command:"
+	@${ECHO_MSG}    "1. cd work/asterisk-1.4.x"
+	@${ECHO_MSG}    "2. gmake menuselect"
+	@${ECHO_MSG}    "3. Select 'Voicemail Build Options->ODBC_STORAGE'"
+.endif
+
+.if defined(WITH_IMAP)
+	@${ECHO_MSG}    ""
+	@${ECHO_MSG}    "If necessary, build  with the option IMAP_STORAGE"
+	@${ECHO_MSG}    "press Ctrl-C and run following command:"
+	@${ECHO_MSG}    "1. cd work/asterisk-1.4.x"
+	@${ECHO_MSG}    "2. gmake menuselect"
+	@${ECHO_MSG}    "3. Select 'Voicemail Build Options->IMAP_STORAGE'"
+.endif
+
 .include <bsd.port.post.mk>
diff -ruN asterisk.orig/distinfo asterisk/distinfo
--- asterisk.orig/distinfo	2007-08-13 23:35:37.000000000 +0600
+++ asterisk/distinfo	2007-08-22 16:03:50.000000000 +0600
@@ -1,6 +1,6 @@
-MD5 (asterisk-1.4.10.tar.gz) = 69057e2916287f6e2a1e36dba6d6800d
-SHA256 (asterisk-1.4.10.tar.gz) = 72bbb19e35ec304df06dca717b7ac2cae0d3409fe47c17c2dcf75850f61ddbe1
-SIZE (asterisk-1.4.10.tar.gz) = 11208127
+MD5 (asterisk-1.4.11.tar.gz) = 3ba9b399fedc68de4845b1c5603d167c
+SHA256 (asterisk-1.4.11.tar.gz) = 99928f8aab62e532e71fdecbd18d5af2d211f1bbce27cf9cf2efc34e57a20101
+SIZE (asterisk-1.4.11.tar.gz) = 11218944
 MD5 (asterisk-1.4.10-codec-negotiation-20070810.diff.gz) = ddcd2c8beda46ae569174b3f50d4af2d
 SHA256 (asterisk-1.4.10-codec-negotiation-20070810.diff.gz) = a714f5c9db8d34fb55a601472ae7b6b6555341acc7d774c3a91fd26cdf10476c
 SIZE (asterisk-1.4.10-codec-negotiation-20070810.diff.gz) = 37676
diff -ruN asterisk.orig/files/patch-apps::app_rxfax.c asterisk/files/patch-apps::app_rxfax.c
--- asterisk.orig/files/patch-apps::app_rxfax.c	1970-01-01 05:00:00.000000000 +0500
+++ asterisk/files/patch-apps::app_rxfax.c	2007-07-23 15:01:57.000000000 +0600
@@ -0,0 +1,383 @@
+--- apps/app_rxfax.c.orig	Tue Jul 10 15:28:04 2007
++++ apps/app_rxfax.c	Tue Jul 10 15:27:28 2007
+@@ -0,0 +1,380 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Trivial application to receive a TIFF FAX file
++ * 
++ * Copyright (C) 2003, Steve Underwood
++ *
++ * Steve Underwood <steveu@coppice.org>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++/*** MODULEINFO
++         <depend>spandsp</depend>
++***/
++ 
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision:$")
++
++#include <string.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <inttypes.h>
++#include <pthread.h>
++#include <errno.h>
++#include <tiffio.h>
++
++#include <spandsp.h>
++
++#include "asterisk/lock.h"
++#include "asterisk/file.h"
++#include "asterisk/logger.h"
++#include "asterisk/channel.h"
++#include "asterisk/pbx.h"
++#include "asterisk/module.h"
++#include "asterisk/manager.h"
++
++#ifndef AST_MODULE
++#define AST_MODULE "app_rxfax"
++#endif
++
++static char *app = "RxFAX";
++
++static char *synopsis = "Receive a FAX to a file";
++
++static char *descrip = 
++"  RxFAX(filename[|caller][|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 \"caller\" option makes the application behave as a calling machine,\n"
++"rather than the answering machine. The default behaviour is to behave as\n"
++"an answering machine.\n"
++"Uses LOCALSTATIONID to identify itself to the remote end.\n"
++"     LOCALHEADERINFO to generate a header line on each page.\n"
++"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"
++"Returns -1 when the user hangs up.\n"
++"Returns 0 otherwise.\n";
++
++#define MAX_BLOCK_SIZE 240
++
++static void span_message(int level, const char *msg)
++{
++    int ast_level;
++    
++    if (level == SPAN_LOG_WARNING)
++        ast_level = __LOG_WARNING;
++    else if (level == SPAN_LOG_WARNING)
++        ast_level = __LOG_WARNING;
++    else
++        ast_level = __LOG_DEBUG;
++    ast_log(ast_level, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg);
++}
++/*- End of function --------------------------------------------------------*/
++
++#if 0
++static void t30_flush(t30_state_t *s, int which)
++{
++    /* TODO: */
++}
++/*- End of function --------------------------------------------------------*/
++#endif
++
++static void phase_e_handler(t30_state_t *s, void *user_data, int result)
++{
++    struct ast_channel *chan;
++    t30_stats_t t;
++    char local_ident[21];
++    char far_ident[21];
++    char buf[11];
++    
++    chan = (struct ast_channel *) user_data;
++    if (result == T30_ERR_OK)
++    {
++        t30_get_transfer_statistics(s, &t);
++        t30_get_far_ident(s, far_ident);
++        t30_get_local_ident(s, local_ident);
++        ast_log(LOG_DEBUG, "==============================================================================\n");
++        ast_log(LOG_DEBUG, "Fax successfully received.\n");
++        ast_log(LOG_DEBUG, "Remote station id: %s\n", far_ident);
++        ast_log(LOG_DEBUG, "Local station id:  %s\n", local_ident);
++        ast_log(LOG_DEBUG, "Pages transferred: %i\n", t.pages_transferred);
++        ast_log(LOG_DEBUG, "Image resolution:  %i x %i\n", t.x_resolution, t.y_resolution);
++        ast_log(LOG_DEBUG, "Transfer Rate:     %i\n", t.bit_rate);
++        ast_log(LOG_DEBUG, "==============================================================================\n");
++        manager_event(EVENT_FLAG_CALL,
++                      "FaxReceived", "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  :  "",
++                      far_ident,
++                      local_ident,
++                      t.pages_transferred,
++                      t.y_resolution,
++                      t.bit_rate,
++                      s->rx_file);
++        pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident);
++        snprintf(buf, sizeof(buf), "%i", t.pages_transferred);
++        pbx_builtin_setvar_helper(chan, "FAXPAGES", buf);
++        snprintf(buf, sizeof(buf), "%i", t.y_resolution);
++        pbx_builtin_setvar_helper(chan, "FAXRESOLUTION", buf);
++        snprintf(buf, sizeof(buf), "%i", t.bit_rate);
++        pbx_builtin_setvar_helper(chan, "FAXBITRATE", buf);
++    }
++    else
++    {
++        ast_log(LOG_DEBUG, "==============================================================================\n");
++        ast_log(LOG_DEBUG, "Fax receive not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result));
++        ast_log(LOG_DEBUG, "==============================================================================\n");
++    }
++}
++/*- End of function --------------------------------------------------------*/
++
++static void phase_d_handler(t30_state_t *s, void *user_data, int result)
++{
++    struct ast_channel *chan;
++    t30_stats_t t;
++    
++    chan = (struct ast_channel *) user_data;
++    if (result)
++    {
++        t30_get_transfer_statistics(s, &t);
++        ast_log(LOG_DEBUG, "==============================================================================\n");
++        ast_log(LOG_DEBUG, "Pages transferred:  %i\n", t.pages_transferred);
++        ast_log(LOG_DEBUG, "Image size:         %i x %i\n", t.width, t.length);
++        ast_log(LOG_DEBUG, "Image resolution    %i x %i\n", t.x_resolution, t.y_resolution);
++        ast_log(LOG_DEBUG, "Transfer Rate:      %i\n", t.bit_rate);
++        ast_log(LOG_DEBUG, "Bad rows            %i\n", t.bad_rows);
++        ast_log(LOG_DEBUG, "Longest bad row run %i\n", t.longest_bad_row_run);
++        ast_log(LOG_DEBUG, "Compression type    %i\n", t.encoding);
++        ast_log(LOG_DEBUG, "Image size (bytes)  %i\n", t.image_size);
++        ast_log(LOG_DEBUG, "==============================================================================\n");
++    }
++}
++/*- End of function --------------------------------------------------------*/
++
++static int rxfax_exec(struct ast_channel *chan, void *data)
++{
++    int res = 0;
++    char template_file[256];
++    char target_file[256];
++    char *s;
++    char *t;
++    char *v;
++    const char *x;
++    int option;
++    int len;
++    int i;
++    fax_state_t fax;
++    int calling_party;
++    int verbose;
++    int samples;
++
++    struct ast_module_user *u;
++    struct ast_frame *inf = NULL;
++    struct ast_frame outf;
++
++    int original_read_fmt;
++    int original_write_fmt;
++    
++    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
++    uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
++
++    if (chan == NULL)
++    {
++        ast_log(LOG_WARNING, "Fax receive channel is NULL. Giving up.\n");
++        return -1;
++    }
++
++    span_set_message_handler(span_message);
++
++    /* 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_WARNING, "Rxfax requires an argument (filename)\n");
++        return -1;
++    }
++    
++    calling_party = FALSE;
++    verbose = FALSE;
++    target_file[0] = '\0';
++
++    for (option = 0, v = s = data;  v;  option++, s++)
++    {
++        t = s;
++        v = strchr(s, '|');
++        s = (v)  ?  v  :  s + strlen(s);
++        strncpy((char *) buf, t, s - t);
++        buf[s - t] = '\0';
++        if (option == 0)
++        {
++            /* The first option is always the file name */
++            len = s - t;
++            if (len > 255)
++                len = 255;
++            strncpy(target_file, t, len);
++            target_file[len] = '\0';
++            /* 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(target_file, '%'))  &&  x[1] == 'd')
++            {
++                strcpy(template_file, target_file);
++                i = 0;
++                do
++                {
++                    snprintf(target_file, 256, template_file, 1);
++                    i++;
++                }
++                while (ast_fileexists(target_file, "", chan->language) != -1);
++            }
++        }
++        else if (strncmp("caller", t, s - t) == 0)
++        {
++            calling_party = TRUE;
++        }
++        else if (strncmp("debug", t, s - t) == 0)
++        {
++            verbose = TRUE;
++        }
++    }
++
++    /* Done parsing */
++
++    u = ast_module_user_add(chan);
++
++    if (chan->_state != AST_STATE_UP)
++    {
++        /* Shouldn't need this, but checking to see if channel is already answered
++         * Theoretically asterisk should already have answered before running the app */
++        res = ast_answer(chan);
++    }
++    
++    if (!res)
++    {
++        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, "Unable to set to linear read mode, giving up\n");
++                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_WARNING, "Unable to set to linear write mode, giving up\n");
++                res = ast_set_read_format(chan, original_read_fmt);
++                if (res)
++                    ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
++                return -1;
++            }
++        }
++        fax_init(&fax, calling_party);
++        if (verbose)
++            fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
++        x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
++        if (x  &&  x[0])
++            t30_set_local_ident(&fax.t30_state, x);
++        x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
++        if (x  &&  x[0])
++            t30_set_header_info(&fax.t30_state, x);
++        t30_set_rx_file(&fax.t30_state, target_file, -1);
++        //t30_set_phase_b_handler(&fax.t30_state, phase_b_handler, chan);
++        t30_set_phase_d_handler(&fax.t30_state, phase_d_handler, chan);
++        t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, chan);
++        t30_set_ecm_capability(&fax.t30_state, TRUE);
++        t30_set_supported_compressions(&fax.t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
++        while (ast_waitfor(chan, -1) > -1)
++        {
++            inf = ast_read(chan);
++            if (inf == NULL)
++            {
++                res = -1;
++                break;
++            }
++            if (inf->frametype == AST_FRAME_VOICE)
++            {
++                if (fax_rx(&fax, inf->data, inf->samples))
++                    break;
++                samples = (inf->samples <= MAX_BLOCK_SIZE)  ?  inf->samples  :  MAX_BLOCK_SIZE;
++                len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
++                if (len)
++                {
++                    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 = "RxFAX";
++                    if (ast_write(chan, &outf) < 0)
++                    {
++                        ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
++                        break;
++                    }
++                }
++            }
++            ast_frfree(inf);
++        }
++        if (inf == NULL)
++        {
++            ast_log(LOG_DEBUG, "Got hangup\n");
++            res = -1;
++        }
++        if (original_read_fmt != AST_FORMAT_SLINEAR)
++        {
++            res = ast_set_read_format(chan, original_read_fmt);
++            if (res)
++                ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
++        }
++        if (original_write_fmt != AST_FORMAT_SLINEAR)
++        {
++            res = ast_set_write_format(chan, original_write_fmt);
++            if (res)
++                ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
++        }
++        t30_terminate(&fax.t30_state);
++    }
++    else
++    {
++        ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
++    }
++    ast_module_user_remove(u);
++    return res;
++}
++/*- End of function --------------------------------------------------------*/
++
++static int unload_module(void)
++{
++	int res;
++
++	ast_module_user_hangup_all();
++
++	res = ast_unregister_application(app);	
++	
++
++	return res;
++}
++/*- End of function --------------------------------------------------------*/
++
++static int load_module(void)
++{
++	return ast_register_application(app, rxfax_exec, synopsis, descrip);
++}
++/*- End of function --------------------------------------------------------*/
++
++AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial FAX Receive Application");
++
++/*- End of file ------------------------------------------------------------*/
diff -ruN asterisk.orig/files/patch-apps::app_txfax.c asterisk/files/patch-apps::app_txfax.c
--- asterisk.orig/files/patch-apps::app_txfax.c	1970-01-01 05:00:00.000000000 +0500
+++ asterisk/files/patch-apps::app_txfax.c	2007-07-23 15:01:57.000000000 +0600
@@ -0,0 +1,309 @@
+--- apps/app_txfax.c.orig	Tue Jul 10 15:28:13 2007
++++ apps/app_txfax.c	Tue Jul 10 15:27:37 2007
+@@ -0,0 +1,306 @@
++/*
++ * Asterisk -- A telephony toolkit for Linux.
++ *
++ * Trivial application to send a TIFF file as a FAX
++ * 
++ * Copyright (C) 2003, Steve Underwood
++ *
++ * Steve Underwood <steveu@coppice.org>
++ *
++ * This program is free software, distributed under the terms of
++ * the GNU General Public License
++ */
++
++/*** MODULEINFO
++         <depend>spandsp</depend>
++***/
++ 
++#include "asterisk.h"
++
++ASTERISK_FILE_VERSION(__FILE__, "$Revision:$")
++
++#include <string.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <inttypes.h>
++#include <pthread.h>
++#include <errno.h>
++#include <tiffio.h>
++
++#include <spandsp.h>
++
++#include "asterisk/lock.h"
++#include "asterisk/file.h"
++#include "asterisk/logger.h"
++#include "asterisk/channel.h"
++#include "asterisk/pbx.h"
++#include "asterisk/module.h"
++
++#ifndef AST_MODULE
++#define AST_MODULE "app_txfax"
++#endif
++
++static char *app = "TxFAX";
++
++static char *synopsis = "Send a FAX file";
++
++static char *descrip = 
++"  TxFAX(filename[|caller][|debug]):  Send a given TIFF file to the channel as a FAX.\n"
++"The \"caller\" option makes the application behave as a calling machine,\n"
++"rather than the answering machine. The default behaviour is to behave as\n"
++"an answering machine.\n"
++"Uses LOCALSTATIONID to identify itself to the remote end.\n"
++"     LOCALHEADERINFO to generate a header line on each page.\n"
++"Sets REMOTESTATIONID to the receiver CSID.\n"
++"Returns -1 when the user hangs up, or if the file does not exist.\n"
++"Returns 0 otherwise.\n";
++
++#define MAX_BLOCK_SIZE 240
++
++static void span_message(int level, const char *msg)
++{
++    int ast_level;
++    
++    if (level == SPAN_LOG_WARNING)
++        ast_level = __LOG_WARNING;
++    else if (level == SPAN_LOG_WARNING)
++        ast_level = __LOG_WARNING;
++    else
++        ast_level = __LOG_DEBUG;
++    ast_log(ast_level, __FILE__, __LINE__, __PRETTY_FUNCTION__, msg);
++}
++/*- End of function --------------------------------------------------------*/
++
++#if 0
++static void t30_flush(t30_state_t *s, int which)
++{
++    /* TODO: */
++}
++/*- End of function --------------------------------------------------------*/
++#endif
++
++static void phase_e_handler(t30_state_t *s, void *user_data, int result)
++{
++    struct ast_channel *chan;
++    char far_ident[21];
++    
++    chan = (struct ast_channel *) user_data;
++    if (result == T30_ERR_OK)
++    {
++        t30_get_far_ident(s, far_ident);
++        pbx_builtin_setvar_helper(chan, "REMOTESTATIONID", far_ident);
++    }
++    else
++    {
++        ast_log(LOG_DEBUG, "==============================================================================\n");
++        ast_log(LOG_DEBUG, "Fax send not successful - result (%d) %s.\n", result, t30_completion_code_to_str(result));
++        ast_log(LOG_DEBUG, "==============================================================================\n");
++    }
++}
++/*- End of function --------------------------------------------------------*/
++
++static int txfax_exec(struct ast_channel *chan, void *data)
++{
++    int res = 0;
++    char source_file[256];
++    char *s;
++    char *t;
++    char *v;
++    const char *x;
++    int option;
++    int len;
++    fax_state_t fax;
++    int calling_party;
++    int verbose;
++    int samples;
++    
++    struct ast_module_user *u;
++    struct ast_frame *inf = NULL;
++    struct ast_frame outf;
++
++    int original_read_fmt;
++    int original_write_fmt;
++    
++    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
++    uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;
++
++    if (chan == NULL)
++    {
++        ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n");
++        return -1;
++    }
++
++    span_set_message_handler(span_message);
++
++    /* 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_WARNING, "Txfax requires an argument (filename)\n");
++        return -1;
++    }
++    
++    calling_party = FALSE;
++    verbose = FALSE;
++    source_file[0] = '\0'; 
++
++    for (option = 0, v = s = data;  v;  option++, s++)
++    {
++        t = s;
++        v = strchr(s, '|');
++        s = (v)  ?  v  :  s + strlen(s);
++        strncpy((char *) buf, t, s - t);
++        buf[s - t] = '\0';
++        if (option == 0)
++        {
++            /* The first option is always the file name */
++            len = s - t;
++            if (len > 255)
++                len = 255;
++            strncpy(source_file, t, len);
++            source_file[len] = '\0';
++        }
++        else if (strncmp("caller", t, s - t) == 0)
++        {
++            calling_party = TRUE;
++        }
++        else if (strncmp("debug", t, s - t) == 0)
++        {
++            verbose = TRUE;
++        }
++    }
++
++    /* Done parsing */
++
++    u = ast_module_user_add(chan);
++
++    if (chan->_state != AST_STATE_UP)
++    {
++        /* Shouldn't need this, but checking to see if channel is already answered
++         * Theoretically asterisk should already have answered before running the app */
++        res = ast_answer(chan);
++    }
++    
++    if (!res)
++    {
++        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, "Unable to set to linear read mode, giving up\n");
++                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_WARNING, "Unable to set to linear write mode, giving up\n");
++                res = ast_set_read_format(chan, original_read_fmt);
++                if (res)
++                    ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
++                return -1;
++            }
++        }
++        fax_init(&fax, calling_party);
++        if (verbose)
++	    fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;
++
++        x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
++        if (x  &&  x[0])
++            t30_set_local_ident(&fax.t30_state, x);
++        x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
++        if (x  &&  x[0])
++            t30_set_header_info(&fax.t30_state, x);
++        t30_set_tx_file(&fax.t30_state, source_file, -1, -1);
++        //t30_set_phase_b_handler(&fax.t30_state, phase_b_handler, chan);
++        //t30_set_phase_d_handler(&fax.t30_state, phase_d_handler, chan);
++        t30_set_phase_e_handler(&fax.t30_state, phase_e_handler, chan);
++        t30_set_ecm_capability(&fax.t30_state, TRUE);
++        t30_set_supported_compressions(&fax.t30_state, T30_SUPPORT_T4_1D_COMPRESSION | T30_SUPPORT_T4_2D_COMPRESSION | T30_SUPPORT_T6_COMPRESSION);
++        while (ast_waitfor(chan, -1) > -1)
++        {
++            inf = ast_read(chan);
++            if (inf == NULL)
++            {
++                res = -1;
++                break;
++            }
++            if (inf->frametype == AST_FRAME_VOICE)
++            {
++                if (fax_rx(&fax, inf->data, inf->samples))
++                    break;
++                samples = (inf->samples <= MAX_BLOCK_SIZE)  ?  inf->samples  :  MAX_BLOCK_SIZE;
++                len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
++                if (len)
++                {
++                    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;
++                    if (ast_write(chan, &outf) < 0)
++                    {
++                        ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
++                        break;
++                    }
++                }
++            }
++            ast_frfree(inf);
++        }
++        if (inf == NULL)
++        {
++            ast_log(LOG_DEBUG, "Got hangup\n");
++            res = -1;
++        }
++        if (original_read_fmt != AST_FORMAT_SLINEAR)
++        {
++            res = ast_set_read_format(chan, original_read_fmt);
++            if (res)
++                ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
++        }
++        if (original_write_fmt != AST_FORMAT_SLINEAR)
++        {
++            res = ast_set_write_format(chan, original_write_fmt);
++            if (res)
++                ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
++        }
++        t30_terminate(&fax.t30_state);
++    }
++    else
++    {
++        ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
++    }
++    ast_module_user_remove(u);
++    return res;
++}
++/*- End of function --------------------------------------------------------*/
++
++static int unload_module(void)
++{
++	int res;
++
++	ast_module_user_hangup_all();
++
++	res = ast_unregister_application(app);	
++	
++
++	return res;
++}
++/*- End of function --------------------------------------------------------*/
++
++static int load_module(void)
++{
++    return ast_register_application(app, txfax_exec, synopsis, descrip);
++}
++/*- End of function --------------------------------------------------------*/
++
++AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Trivial FAX Transmit Application");
++
++/*- End of file ------------------------------------------------------------*/


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200708221031.l7MAVbga082005>