- Added sendfax feature and enhanced result/status variables after

FAX actions.
This commit is contained in:
MelwareDE 2006-06-27 14:54:03 +00:00
parent 25dceb2571
commit 8a0d8977be
4 changed files with 227 additions and 24 deletions

View File

@ -1,6 +1,7 @@
CHANGES
=======
- added capicommand(sendfax)
- dropped compatiblity to versions before Asterisk-1.2.0
- added capicommand(echocancel)
- added CAPI RTP (Eicon DIVA Server cards can do that)

39
README
View File

@ -30,6 +30,9 @@ Hans Petter Selasky
No support for Asterisk 1.0.x any more, you need at least
Asterisk 1.2.x
To support all fax features (e.g. fax polling), you
need version 3 of libcapi20.
This chan_capi version includes:
================================
- Multiple controller support
@ -59,7 +62,7 @@ This chan_capi version includes:
- report correct DIALSTATUS and HANGUPCAUSE.
- Updated to support the new frame->delivery field
- Compiles with different Asterisk versions (automatic build configuration)
- receive faxes over CAPI (see below)
- receive/send faxes over CAPI (see below)
- Fixes and compatibility for BSD (Jan Stocker and Hans Petter Selasky)
- Support 'type of number'.
- ISDN hold.
@ -125,6 +128,12 @@ Fax receive:
exten => s,1,capicommand(receivefax|/tmp/${UNIQUEID}|+49 6137 555123|Asterisk)
(more see below)
Fax send:
Send a fax using CAPI.
Example:
exten => s,1,capicommand(sendfax|/path/to/faxfile.sff|+49 6137 555123|Asterisk)
(more see below)
Enable/Disable echosquelch:
Enable or disable a very primitive echo suppressor.
Disable this before you start recording voicemail or your files may get choppy.
@ -243,10 +252,13 @@ exten => 12345678,1,Dial(SIP/phone1)
exten => 12345678,2,Hangup
Short HOWTO of capicommand(receivefax|<filename>[|<stationid>|<headline>]):
Short HOWTO of capicommand(receivefax...) and capicommand(sendfax...):
==========================================================================
For those of you who have a CAPI card with an on-board DSP (like some Eicon and
DIVA Server), this patch allows you to receive faxes.
DIVA Server), this allows you to receive/send faxes.
capicommand(receivefax|<filename>[|<stationid>|<headline>]):
------------------------------------------------------------
If you want to answer a channel in fax mode, use capicommand(receivefax|...)
instead of Answer()
If you use Answer(), you will be in voice mode. If the hardware DSP detects
@ -279,12 +291,21 @@ With a DIVA Server, following features are provided:
- Color Fax
- JPEG Compression is disabled (not tested yet)
After successful receive of a fax, the following variables will be set for that channel:
FAXRATE : The baud rate of the fax connection
FAXRESOLUTION : 0 = standard, 1 = high
FAXFORMAT : 0 = SFF
FAXPAGES : Number of pages received
FAXID : The ID of the remote fax maschine
capicommand(sendfax|<filename>[|<stationid>|<headline>]):
------------------------------------------------------------
To send a fax, you can use the same mechanism like with receivefax.
Just replace the <filename> with the path to the .SFF file to send.
After disconnect of a fax connection, the following variables
will be set for that channel:
FAXSTATUS : 0 = OK, 1 = Error.
FAXREASON : Value of B3 disconnect reason.
FAXREASONTEXT : Decoded text of FAXREASON value.
FAXRATE : The baud rate of the fax connection.
FAXRESOLUTION : 0 = standard, 1 = high.
FAXFORMAT : 0 = SFF.
FAXPAGES : Number of pages received.
FAXID : The ID of the remote fax maschine.
CLI command "capi show channels"

View File

@ -237,6 +237,30 @@ static struct {
}
};
#ifndef CC_HAVE_NO_GLOBALCONFIGURATION
/*
* set the global-configuration (b-channel operation)
*/
static _cstruct capi_set_global_configuration(struct capi_pvt *i)
{
unsigned short dtedce = 0;
unsigned char *buf = i->tmpbuf;
buf[0] = 2; /* len */
if (i->FaxState & CAPI_FAX_STATE_ACTIVE) {
if ((i->outgoing) && (!(i->FaxState & CAPI_FAX_STATE_SENDMODE)))
dtedce = 2;
if ((!(i->outgoing)) && ((i->FaxState & CAPI_FAX_STATE_SENDMODE)))
dtedce = 1;
}
write_capi_word(&buf[1], dtedce);
if (dtedce == 0)
buf = NULL;
return (_cstruct)buf;
}
#endif
/*
* command to string function
*/
@ -1409,6 +1433,9 @@ static int capi_send_answer(struct ast_channel *c, _cstruct b3conf)
if (!b3conf)
b3conf = b_protocol_table[i->bproto].b3configuration;
CONNECT_RESP_B3CONFIGURATION(&CMSG) = b3conf;
#ifndef CC_HAVE_NO_GLOBALCONFIGURATION
CONNECT_RESP_GLOBALCONFIGURATION(&CMSG) = capi_set_global_configuration(i);
#endif
cc_verbose(3, 0, VERBOSE_PREFIX_2 "%s: Answering for %s\n",
i->vname, dnid);
@ -1535,7 +1562,7 @@ static int pbx_capi_write(struct ast_channel *c, struct ast_frame *f)
return 0;
}
if (i->FaxState & CAPI_FAX_STATE_ACTIVE) {
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: write on fax_receive?\n",
cc_verbose(3, 1, VERBOSE_PREFIX_2 "%s: write on fax activity?\n",
i->vname);
return 0;
}
@ -1650,6 +1677,9 @@ static void cc_select_b(struct capi_pvt *i, _cstruct b3conf)
if (!b3conf)
b3conf = b_protocol_table[i->bproto].b3configuration;
SELECT_B_PROTOCOL_REQ_B3CONFIGURATION(&CMSG) = b3conf;
#ifndef CC_HAVE_NO_GLOBALCONFIGURATION
SELECT_B_PROTOCOL_REQ_GLOBALCONFIGURATION(&CMSG) = capi_set_global_configuration(i);
#endif
_capi_put_cmsg(&CMSG);
}
@ -2110,6 +2140,7 @@ static void capi_change_bchan_fax(struct ast_channel *c, B3_PROTO_FAXG3 *b3conf)
{
struct capi_pvt *i = CC_CHANNEL_PVT(c);
i->isdnstate |= CAPI_ISDN_STATE_B3_SELECT;
cc_disconnect_b3(i, 1);
cc_select_b(i, (_cstruct)b3conf);
return;
@ -2124,14 +2155,13 @@ static int pbx_capi_receive_fax(struct ast_channel *c, char *data)
int res = 0;
char *filename, *stationid, *headline;
B3_PROTO_FAXG3 b3conf;
char buffer[CAPI_MAX_STRING];
if (!data) { /* no data implies no filename or anything is present */
cc_log(LOG_WARNING, "capi receivefax requires a filename\n");
return -1;
}
cc_mutex_lock(&i->lock);
filename = strsep(&data, "|");
stationid = strsep(&data, "|");
headline = data;
@ -2142,7 +2172,6 @@ static int pbx_capi_receive_fax(struct ast_channel *c, char *data)
headline = emptyid;
if ((i->fFax = fopen(filename, "wb")) == NULL) {
cc_mutex_unlock(&i->lock);
cc_log(LOG_WARNING, "can't create fax output file (%s)\n", strerror(errno));
return -1;
}
@ -2156,16 +2185,13 @@ static int pbx_capi_receive_fax(struct ast_channel *c, char *data)
case CAPI_STATE_ALERTING:
case CAPI_STATE_DID:
case CAPI_STATE_INCALL:
cc_mutex_unlock(&i->lock);
capi_send_answer(c, (_cstruct)&b3conf);
break;
case CAPI_STATE_CONNECTED:
cc_mutex_unlock(&i->lock);
capi_change_bchan_fax(c, &b3conf);
break;
default:
i->FaxState &= ~CAPI_FAX_STATE_ACTIVE;
cc_mutex_unlock(&i->lock);
cc_log(LOG_WARNING, "capi receive fax in wrong state (%d)\n",
i->state);
return -1;
@ -2175,12 +2201,12 @@ static int pbx_capi_receive_fax(struct ast_channel *c, char *data)
usleep(10000);
}
res = (i->FaxState & CAPI_FAX_STATE_ERROR) ? -1 : 0;
res = (i->FaxState & CAPI_FAX_STATE_ERROR) ? 1 : 0;
i->FaxState &= ~(CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_ERROR);
/* if the file has zero length */
if (ftell(i->fFax) == 0L) {
res = -1;
res = 1;
}
cc_verbose(2, 1, VERBOSE_PREFIX_3 "Closing fax file...\n");
@ -2196,8 +2222,91 @@ static int pbx_capi_receive_fax(struct ast_channel *c, char *data)
cc_verbose(2, 0,
VERBOSE_PREFIX_1 "capi receivefax: fax receive successful.\n");
}
snprintf(buffer, CAPI_MAX_STRING-1, "%d", res);
pbx_builtin_setvar_helper(c, "FAXSTATUS", buffer);
return res;
return 0;
}
/*
* capicommand 'sendfax'
*/
static int pbx_capi_send_fax(struct ast_channel *c, char *data)
{
struct capi_pvt *i = CC_CHANNEL_PVT(c);
int res = 0;
char *filename, *stationid, *headline;
B3_PROTO_FAXG3 b3conf;
char buffer[CAPI_MAX_STRING];
if (!data) { /* no data implies no filename or anything is present */
cc_log(LOG_WARNING, "capi sendfax requires a filename\n");
return -1;
}
filename = strsep(&data, "|");
stationid = strsep(&data, "|");
headline = data;
if (!stationid)
stationid = emptyid;
if (!headline)
headline = emptyid;
if ((i->fFax = fopen(filename, "rb")) == NULL) {
cc_log(LOG_WARNING, "can't open fax file (%s)\n", strerror(errno));
return -1;
}
i->FaxState |= (CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_SENDMODE);
setup_b3_fax_config(&b3conf, FAX_SFF_FORMAT, stationid, headline);
i->bproto = CC_BPROTO_FAXG3;
switch (i->state) {
case CAPI_STATE_ALERTING:
case CAPI_STATE_DID:
case CAPI_STATE_INCALL:
capi_send_answer(c, (_cstruct)&b3conf);
break;
case CAPI_STATE_CONNECTED:
capi_change_bchan_fax(c, &b3conf);
break;
default:
i->FaxState &= ~CAPI_FAX_STATE_ACTIVE;
cc_log(LOG_WARNING, "capi send fax in wrong state (%d)\n",
i->state);
return -1;
}
while (i->FaxState & CAPI_FAX_STATE_ACTIVE) {
usleep(10000);
}
res = (i->FaxState & CAPI_FAX_STATE_ERROR) ? 1 : 0;
i->FaxState &= ~(CAPI_FAX_STATE_ACTIVE | CAPI_FAX_STATE_ERROR);
/* if the file has zero length */
if (ftell(i->fFax) == 0L) {
res = 1;
}
cc_verbose(2, 1, VERBOSE_PREFIX_3 "Closing fax file...\n");
fclose(i->fFax);
i->fFax = NULL;
if (res != 0) {
cc_verbose(2, 0,
VERBOSE_PREFIX_1 "capi sendfax: fax send failed reason=0x%04x reasonB3=0x%04x\n",
i->reason, i->reasonb3);
} else {
cc_verbose(2, 0,
VERBOSE_PREFIX_1 "capi sendfax: fax sent successful.\n");
}
snprintf(buffer, CAPI_MAX_STRING-1, "%d", res);
pbx_builtin_setvar_helper(c, "FAXSTATUS", buffer);
return 0;
}
/*
@ -2955,12 +3064,14 @@ static void capidev_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, un
return_on_no_interface("DATA_B3_IND");
if (i->fFax) {
/* we are in fax-receive and have a file open */
/* we are in fax mode and have a file open */
cc_verbose(6, 1, VERBOSE_PREFIX_3 "%s: DATA_B3_IND (len=%d) Fax\n",
i->vname, b3len);
if (fwrite(b3buf, 1, b3len, i->fFax) != b3len)
cc_log(LOG_WARNING, "%s : error writing output file (%s)\n",
i->vname, strerror(errno));
if (!(i->FaxState & CAPI_FAX_STATE_SENDMODE)) {
if (fwrite(b3buf, 1, b3len, i->fFax) != b3len)
cc_log(LOG_WARNING, "%s : error writing output file (%s)\n",
i->vname, strerror(errno));
}
return;
}
@ -3045,6 +3156,39 @@ static void capi_signal_answer(struct capi_pvt *i)
}
}
/*
* send the next data
*/
static void capidev_send_faxdata(struct capi_pvt *i)
{
unsigned char faxdata[CAPI_MAX_B3_BLOCK_SIZE];
size_t len;
_cmsg CMSG;
if ((i->fFax) && (!(feof(i->fFax)))) {
len = fread(faxdata, 1, CAPI_MAX_B3_BLOCK_SIZE, i->fFax);
if (len > 0) {
DATA_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
DATA_B3_REQ_NCCI(&CMSG) = i->NCCI;
DATA_B3_REQ_DATALENGTH(&CMSG) = len;
DATA_B3_REQ_FLAGS(&CMSG) = 0;
DATA_B3_REQ_DATAHANDLE(&CMSG) = i->send_buffer_handle;
DATA_B3_REQ_DATA(&CMSG) = faxdata;
i->send_buffer_handle++;
cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: send %d fax bytes.\n",
i->vname, len);
_capi_put_cmsg(&CMSG);
return;
}
}
/* finished send fax, so we hangup */
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: completed faxsend.\n",
i->vname);
DISCONNECT_B3_REQ_HEADER(&CMSG, capi_ApplID, get_capi_MessageNumber(), 0);
DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI;
_capi_put_cmsg(&CMSG);
}
/*
* CAPI CONNECT_ACTIVE_IND
*/
@ -3066,6 +3210,11 @@ static void capidev_handle_connect_active_indication(_cmsg *CMSG, unsigned int P
i->state = CAPI_STATE_CONNECTED;
if ((i->FaxState & CAPI_FAX_STATE_SENDMODE)) {
cc_start_b3(i);
return;
}
if ((i->owner) && (i->FaxState & CAPI_FAX_STATE_ACTIVE)) {
capi_signal_answer(i);
return;
@ -3120,6 +3269,12 @@ static void capidev_handle_connect_b3_active_indication(_cmsg *CMSG, unsigned in
i->B3q = (CAPI_MAX_B3_BLOCK_SIZE * 3);
}
if ((i->FaxState & CAPI_FAX_STATE_SENDMODE)) {
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: Start sending fax.\n",
i->vname);
capidev_send_faxdata(i);
}
if ((i->isdnstate & CAPI_ISDN_STATE_B3_CHANGE)) {
i->isdnstate &= ~CAPI_ISDN_STATE_B3_CHANGE;
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: B3 protocol changed.\n",
@ -3167,8 +3322,16 @@ static void capidev_handle_disconnect_b3_indication(_cmsg *CMSG, unsigned int PL
if ((i->FaxState & CAPI_FAX_STATE_ACTIVE) && (i->owner)) {
char buffer[CAPI_MAX_STRING];
char *infostring;
unsigned char *ncpi = (unsigned char *)DISCONNECT_B3_IND_NCPI(CMSG);
/* if we have fax infos, set them as variables */
snprintf(buffer, CAPI_MAX_STRING-1, "%d", i->reasonb3);
pbx_builtin_setvar_helper(i->owner, "FAXREASON", buffer);
if ((infostring = capi_info_string(i->reasonb3)) != NULL) {
pbx_builtin_setvar_helper(i->owner, "FAXREASONTEXT", infostring);
} else {
pbx_builtin_setvar_helper(i->owner, "FAXREASONTEXT", "");
}
if (ncpi) {
snprintf(buffer, CAPI_MAX_STRING-1, "%d", read_capi_word(&ncpi[1]));
pbx_builtin_setvar_helper(i->owner, "FAXRATE", buffer);
@ -3184,7 +3347,9 @@ static void capidev_handle_disconnect_b3_indication(_cmsg *CMSG, unsigned int PL
}
}
if (i->state == CAPI_STATE_DISCONNECTING) {
if ((i->state == CAPI_STATE_DISCONNECTING) ||
((!(i->isdnstate & CAPI_ISDN_STATE_B3_SELECT)) &&
(i->FaxState & CAPI_FAX_STATE_SENDMODE))) {
/* active disconnect */
DISCONNECT_REQ_HEADER(&CMSG2, capi_ApplID, get_capi_MessageNumber(), 0);
DISCONNECT_REQ_PLCI(&CMSG2) = PLCI;
@ -3672,6 +3837,10 @@ static void capidev_handle_msg(_cmsg *CMSG)
wInfo = SELECT_B_PROTOCOL_CONF_INFO(CMSG);
if(i == NULL) break;
if (!wInfo) {
i->isdnstate &= ~CAPI_ISDN_STATE_B3_SELECT;
if ((i->outgoing) && (i->FaxState & CAPI_FAX_STATE_SENDMODE)) {
cc_start_b3(i);
}
if ((i->owner) && (i->FaxState & CAPI_FAX_STATE_ACTIVE)) {
capi_echo_canceller(i->owner, EC_FUNCTION_DISABLE);
capi_detect_dtmf(i->owner, 0);
@ -3683,6 +3852,9 @@ static void capidev_handle_msg(_cmsg *CMSG)
if ((i) && (i->B3q > 0) && (i->isdnstate & CAPI_ISDN_STATE_RTP)) {
i->B3q--;
}
if ((i) && (i->FaxState & CAPI_FAX_STATE_SENDMODE)) {
capidev_send_faxdata(i);
}
break;
case CAPI_P_CONF(DISCONNECT):
@ -4174,6 +4346,7 @@ static struct capicommands_s {
{ "progress", pbx_capi_signal_progress, 1 },
{ "deflect", pbx_capi_call_deflect, 1 },
{ "receivefax", pbx_capi_receive_fax, 1 },
{ "sendfax", pbx_capi_send_fax, 1 },
{ "echosquelch", pbx_capi_echosquelch, 1 },
{ "echocancel", pbx_capi_echocancel, 1 },
{ "malicious", pbx_capi_malicious, 1 },

View File

@ -36,6 +36,11 @@
#define RTP_HEADER_SIZE 12
#ifndef CONNECT_RESP_GLOBALCONFIGURATION
#define CC_HAVE_NO_GLOBALCONFIGURATION
#warning If you dont update your libcapi20, some fax features are not available
#endif
/* some helper functions */
static inline void write_capi_word(void *m, unsigned short val)
{
@ -187,6 +192,7 @@ typedef struct fax3proto3 B3_PROTO_FAXG3;
#define CAPI_FAX_STATE_HANDLED 0x00010000
#define CAPI_FAX_STATE_ACTIVE 0x00020000
#define CAPI_FAX_STATE_ERROR 0x00040000
#define CAPI_FAX_STATE_SENDMODE 0x00080000
#define CAPI_FAX_STATE_MASK 0xffff0000
struct cc_capi_gains {
@ -209,6 +215,7 @@ struct cc_capi_gains {
#define CAPI_ISDN_STATE_HANGUP 0x00001000
#define CAPI_ISDN_STATE_EC 0x00002000
#define CAPI_ISDN_STATE_DTMF 0x00004000
#define CAPI_ISDN_STATE_B3_SELECT 0x00008000
#define CAPI_ISDN_STATE_PBX 0x80000000
#define CAPI_CHANNELTYPE_B 0
@ -228,6 +235,7 @@ struct capi_pvt {
char name[CAPI_MAX_STRING];
char vname[CAPI_MAX_STRING];
unsigned char tmpbuf[CAPI_MAX_STRING];
/*! Channel we belong to, possibly NULL */
struct ast_channel *owner;