- added capiFax feature by Frank Sautter

- further cleanup
This commit is contained in:
MelwareDE 2005-06-04 14:28:52 +00:00
parent c16ca054a5
commit 376160b461
7 changed files with 580 additions and 73 deletions

View File

@ -48,7 +48,8 @@ LIBS=-ldl -lpthread -lm
CC=gcc
INSTALL=install
SHAREDOS=chan_capi.so app_capiCD.so app_capiHOLD.so app_capiRETRIEVE.so app_capiECT.so app_capiMCID.so app_capiNoES.so
SHAREDOS=chan_capi.so app_capiCD.so app_capiHOLD.so app_capiRETRIEVE.so \
app_capiECT.so app_capiMCID.so app_capiNoES.so app_capiFax.so
CFLAGS+=-Wno-missing-prototypes -Wno-missing-declarations

30
README
View File

@ -18,6 +18,8 @@ Gareth Watts <gareth@omnipotent.net>
Jeff Noxon <jeff@planetfall.com>
Petr Michalek <petr.michalek@aca.cz>
Jan Stocker
Frank Sautter, levigo group
(...and all the others that i forgot..) :-)
This chan_capi version includes:
@ -142,6 +144,34 @@ exten => 12345678,1,Dial(SIP/phone1)
exten => 12345678,2,Hangup
short HOWTO of 'capiAnswerFax':
===============================
For those of you who have a CAPI card with an on-board DSP (like some Eicon+Diva Server), this patch allows you to receive faxes.
If you want to answer a channel in fax mode, use capiAnswerFax() instead of+Answer()
If you use Answer(), you will be in voice mode. If the hardware DSP detects+a fax tone, you can switch from voice to fax mode by calling
capiAnswerFax().
Example of use :
line number 123, play something, if a fax tone is detected, handle it
line number 124, answer directly in fax mode
[incoming]
exten => 123,1,Answer()
exten => 123,2,BackGround(jpop)
exten => 124,1,Goto(handle_fax,s,1)
exten => fax,1,Goto(handle_fax,s,1)
[handle_fax]
exten => s,1,capiAnswerFax(/tmp/${UNIQUEID})
exten => s,2,Hangup()
exten => h,1,deadagi,fax.php // Run sfftobmp and mail it.
The output of capiAnswerFax is a SFF file. Use sfftobmp to convert it.
With a Diva Server, theses features are allowed : fax up to 33600, high
resolution. Color Fax /JPEG Compression is disabled (I can't test it).
------
More information/documentation and commercial support can be found at:
http://www.junghanns.net/asterisk/

251
app_capiFax.c Normal file
View File

@ -0,0 +1,251 @@
/*
* (CAPI*)
*
* Receive a fax with CAPI API.
* Usage : capiAnswerFax(path_output_file.SFF)
*
* This function can be called even after a regular Answer (voice mode),
* the channel will be changed to Fax Mode.
*
* Example of use :
* line number 123, play something, if a fax tone is detected, handle it
* line number 124, answer directly in fax mode
*
* [incoming]
* exten => 123,1,Answer()
* exten => 123,2,BackGround(jpop)
* exten => 124,1,Goto(handle_fax,s,1)
* exten => fax,1,Goto(handle_fax,s,1)
*
* [handle_fax]
* exten => s,1,capiAnswerFax(/tmp/${UNIQUEID})
* exten => s,2,Hangup()
* exten => h,1,deadagi,fax.php // Run SFF2TIFF and mail it.
*
* This program is free software and may be modified and
* distributed under the terms of the GNU Public License.
*
* (c) 2004,2005 by Carl Sempla, Cedrik Hans, Frank Sautter
*
*/
#include "config.h"
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#ifndef CC_AST_HAVE_TECH_PVT
#include <asterisk/channel_pvt.h>
#endif
#include <asterisk/logger.h>
#include <asterisk/options.h>
#include <asterisk/pbx.h>
#include <asterisk/module.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <linux/capi.h>
#include <capi20.h>
#include "chan_capi_pvt.h"
#include "chan_capi_app.h"
/* FAX Resolutions */
#define FAX_STANDARD_RESOLUTION 0
#define FAX_HIGH_RESOLUTION 1
/* FAX Formats */
#define FAX_SFF_FORMAT 0
#define FAX_PLAIN_FORMAT 1
#define FAX_PCX_FORMAT 2
#define FAX_DCX_FORMAT 3
#define FAX_TIFF_FORMAT 4
#define FAX_ASCII_FORMAT 5
#define FAX_EXTENDED_ASCII_FORMAT 6
#define FAX_BINARY_FILE_TRANSFER_FORMAT 7
typedef struct fax3proto3 {
unsigned char len;
unsigned short resolution __attribute__ ((packed));
unsigned short format __attribute__ ((packed));
unsigned char Infos[100] __attribute__ ((packed));
} B3_PROTO_FAXG3;
static char *tdesc = "(CAPI*) Receive Faxes.";
static char *app = "capiAnswerFax";
static char *synopsis = "Answer Fax with CAPI";
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
void SetupB3Config(B3_PROTO_FAXG3 *B3conf, int FAX_Format)
{
int len1;
int len2;
char *stationID = "00000000";
char *headLine = "CAPI FAXServer";
B3conf->resolution = FAX_HIGH_RESOLUTION;
B3conf->format = (unsigned short)FAX_Format;
len1 = strlen(stationID);
B3conf->Infos[0] = (unsigned char)len1;
strcpy((char *)&B3conf->Infos[1], stationID);
len2 = strlen(headLine);
B3conf->Infos[len1 + 1] = (unsigned char)len2;
strcpy((char *)&B3conf->Infos[len1 + 2], headLine);
B3conf->len = (unsigned char)(2 * sizeof(unsigned short) + len1 + len2 + 2);
}
static int capi_change_bchan_fax(struct ast_channel *c)
{
struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c);
MESSAGE_EXCHANGE_ERROR error;
_cmsg CMSG;
B3_PROTO_FAXG3 B3conf;
SetupB3Config(&B3conf, FAX_SFF_FORMAT); /* Format ignored by eicon cards */
DISCONNECT_B3_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0);
DISCONNECT_B3_REQ_NCCI(&CMSG) = i->NCCI;
if ((error = _capi_put_cmsg(&CMSG)) == 0) {
cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "sent DISCONNECT_B3_REQ NCCI=%#x\n",i->NCCI);
}
/* wait for the B3 layer to go down */
while (i->state != CAPI_STATE_CONNECTED) {
usleep(10000);
}
SELECT_B_PROTOCOL_REQ_HEADER(&CMSG, ast_capi_ApplID, get_ast_capi_MessageNumber(), 0);
SELECT_B_PROTOCOL_REQ_PLCI(&CMSG) = i->PLCI;
SELECT_B_PROTOCOL_REQ_B1PROTOCOL(&CMSG) = 4;
SELECT_B_PROTOCOL_REQ_B2PROTOCOL(&CMSG) = 4;
SELECT_B_PROTOCOL_REQ_B3PROTOCOL(&CMSG) = 4;
SELECT_B_PROTOCOL_REQ_B1CONFIGURATION(&CMSG) = NULL;
SELECT_B_PROTOCOL_REQ_B2CONFIGURATION(&CMSG) = NULL;
SELECT_B_PROTOCOL_REQ_B3CONFIGURATION(&CMSG) = (_cstruct)&B3conf;
if ((error = _capi_put_cmsg(&CMSG)) == 0)
cc_ast_verbose(5, 0, VERBOSE_PREFIX_4 "capiAnswerFax sent SELECT_B_PROTOCOL\n");
return 0;
}
static int capi_answer_fax(struct ast_channel *c)
{
struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c);
MESSAGE_EXCHANGE_ERROR error;
_cmsg CMSG;
char buf[AST_CAPI_MAX_STRING];
char *dnid;
B3_PROTO_FAXG3 B3conf;
if (i->isdnmode && (strlen(i->incomingmsn) < strlen(i->dnid))) {
dnid = i->dnid + strlen(i->incomingmsn);
} else {
dnid = i->dnid;
}
SetupB3Config(&B3conf, FAX_SFF_FORMAT); /* Format ignored by eicon cards */
CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0);
CONNECT_RESP_PLCI(&CMSG) = i->PLCI;
CONNECT_RESP_REJECT(&CMSG) = 0;
buf[0] = strlen(dnid)+2;
buf[1] = 0x0;
buf[2] = 0x80;
strncpy(&buf[3],dnid,sizeof(buf)-4);
CONNECT_RESP_CONNECTEDNUMBER(&CMSG) = buf;
CONNECT_RESP_CONNECTEDSUBADDRESS(&CMSG) = NULL;
CONNECT_RESP_LLC(&CMSG) = NULL;
CONNECT_RESP_B1PROTOCOL(&CMSG) = 4; /* T.30 modem for Group 3 fax */
CONNECT_RESP_B2PROTOCOL(&CMSG) = 4; /* T.30 for Group 3 fax */
CONNECT_RESP_B3PROTOCOL(&CMSG) = 4; /* T.30 for Group 3 fax */
CONNECT_RESP_B3CONFIGURATION(&CMSG) = (_cstruct)&B3conf;
cc_ast_verbose(3, 0, VERBOSE_PREFIX_3 "CAPI Answering in fax mode for MSN %s\n", dnid);
if ((error = _capi_put_cmsg(&CMSG)) != 0) {
return -1;
}
cc_ast_verbose(5, 1, VERBOSE_PREFIX_4 "sent CONNECT_RESP PLCI = %#x DNID = %s\n",i->PLCI,i->dnid);
i->state = CAPI_STATE_ANSWERING;
i->doB3 = AST_CAPI_B3_DONT;
i->outgoing = 0;
i->earlyB3 = -1;
return 0;
}
static int capianswerfax_exec(struct ast_channel *chan, void *data)
{
int res = 0;
struct localuser *u;
char *vdata;
struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(chan);
if (!data) { /* no data implies no filename or anything is present */
ast_log(LOG_WARNING, "capiAnswerFax requires an argument (filename)\n");
return -1;
}
vdata = ast_strdupa(data);
LOCAL_USER_ADD(u);
if (strcasecmp("CAPI", chan->type) == 0) {
i->fFax = fopen(vdata, "wb");
if (i->fFax == NULL) {
ast_log(LOG_WARNING, "capiAnswerFax can't create the output file (%s)\n", strerror(errno));
res = -1;
} else {
if (i->state != CAPI_STATE_BCONNECTED) {
capi_answer_fax(chan);
} else {
capi_change_bchan_fax(chan);
}
while (i->state != CAPI_STATE_DISCONNECTED) {
sleep(1);
}
}
} else {
ast_log(LOG_WARNING, "capiFax only works on CAPI channels, check your extensions.conf!\n");
res = -1;
}
LOCAL_USER_REMOVE(u);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(app);
}
int load_module(void)
{
return ast_register_application(app, capianswerfax_exec, synopsis, tdesc);
}
char *description(void)
{
return tdesc;
}
int usecount(void)
{
int res;
STANDARD_USECOUNT(res);
return res;
}
char *key()
{
return ASTERISK_GPL_KEY;
}

View File

@ -106,7 +106,7 @@ static struct capi_pipe *pipelist = NULL;
static struct ast_capi_controller *capi_controllers[AST_CAPI_MAX_CONTROLLERS];
static int capi_num_controllers = 0;
static int capi_counter = 0;
static unsigned long capi_used_controllers=0;
static unsigned long capi_used_controllers = 0;
static char capi_send_buffer[AST_CAPI_MAX_B3_BLOCKS * AST_CAPI_MAX_B3_BLOCK_SIZE];
static int capi_send_buffer_handle = 0;
@ -116,18 +116,7 @@ char capi_international_prefix[AST_MAX_EXTENSION];
int capidebug = 0;
/*
* helper for ast_verbose with different verbose settings
*/
#define cc_ast_verbose(o_v, c_d, text...) \
do { \
if ((o_v == 0) || (option_verbose > o_v)) { \
if ((!c_d) || ((c_d) && (capidebug))) { \
ast_verbose(text); \
} \
} \
} while(0)
/* */
#define return_on_no_pipe(x) \
if (!p) { \
ast_log(LOG_ERROR, "CAPI: %s no pipe PLCI=%#x\n", x, PLCI); \
@ -238,6 +227,99 @@ static unsigned ListenOnController(unsigned long CIPmask, unsigned controller)
#define EC_OPTION_DISABLE_G164_OR_G165 (1<<1 | 1<<2)
#define EC_DEFAULT_TAIL 64
#ifdef CC_AST_CHANNEL_HAS_TRANSFERCAP
/*
* TCAP -> CIP Translation Table (TransferCapability->CommonIsdnProfile)
*/
static struct {
unsigned short tcap;
unsigned short cip;
} translate_tcap2cip[] = {
{ PRI_TRANS_CAP_SPEECH, CAPI_CIP_SPEECH },
{ PRI_TRANS_CAP_DIGITAL, CAPI_CIP_DIGITAL },
{ PRI_TRANS_CAP_RESTRICTED_DIGITAL, CAPI_CIP_RESTRICTED_DIGITAL },
{ PRI_TRANS_CAP_3K1AUDIO, CAPI_CIP_3K1AUDIO },
{ PRI_TRANS_CAP_DIGITAL_W_TONES, CAPI_CIP_DIGITAL_W_TONES },
{ PRI_TRANS_CAP_VIDEO, CAPI_CIP_VIDEO }
};
static int tcap2cip(unsigned short tcap)
{
int x;
for (x = 0; x < sizeof(translate_tcap2cip) / sizeof(translate_tcap2cip[0]); x++) {
if (translate_tcap2cip[x].tcap == tcap)
return (int)translate_tcap2cip[x].cip;
}
return 0;
}
/*
* CIP -> TCAP Translation Table (CommonIsdnProfile->TransferCapability)
*/
static struct {
unsigned short cip;
unsigned short tcap;
} translate_cip2tcap[] = {
{ CAPI_CIP_SPEECH, PRI_TRANS_CAP_SPEECH },
{ CAPI_CIP_DIGITAL, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_RESTRICTED_DIGITAL, PRI_TRANS_CAP_RESTRICTED_DIGITAL },
{ CAPI_CIP_3K1AUDIO, PRI_TRANS_CAP_3K1AUDIO },
{ CAPI_CIP_7KAUDIO, PRI_TRANS_CAP_DIGITAL_W_TONES },
{ CAPI_CIP_VIDEO, PRI_TRANS_CAP_VIDEO },
{ CAPI_CIP_PACKET_MODE, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_56KBIT_RATE_ADAPTION, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_DIGITAL_W_TONES, PRI_TRANS_CAP_DIGITAL_W_TONES },
{ CAPI_CIP_TELEPHONY, PRI_TRANS_CAP_SPEECH },
{ CAPI_CIP_FAX_G2_3, PRI_TRANS_CAP_3K1AUDIO },
{ CAPI_CIP_FAX_G4C1, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_FAX_G4C2_3, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_TELETEX_PROCESSABLE, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_TELETEX_BASIC, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_VIDEOTEX, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_TELEX, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_X400, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_X200, PRI_TRANS_CAP_DIGITAL },
{ CAPI_CIP_7K_TELEPHONY, PRI_TRANS_CAP_DIGITAL_W_TONES },
{ CAPI_CIP_VIDEO_TELEPHONY_C1, PRI_TRANS_CAP_DIGITAL_W_TONES },
{ CAPI_CIP_VIDEO_TELEPHONY_C2, PRI_TRANS_CAP_DIGITAL }
};
static unsigned short cip2tcap(int cip)
{
int x;
for (x = 0;x < sizeof(translate_cip2tcap) / sizeof(translate_cip2tcap[0]); x++) {
if (translate_cip2tcap[x].cip == (unsigned short)cip)
return translate_cip2tcap[x].tcap;
}
return 0;
}
/*
* TransferCapability to String conversion
*/
static char *transfercapability2str(int transfercapability)
{
switch(transfercapability) {
case PRI_TRANS_CAP_SPEECH:
return "SPEECH";
case PRI_TRANS_CAP_DIGITAL:
return "DIGITAL";
case PRI_TRANS_CAP_RESTRICTED_DIGITAL:
return "RESTRICTED_DIGITAL";
case PRI_TRANS_CAP_3K1AUDIO:
return "3K1AUDIO";
case PRI_TRANS_CAP_DIGITAL_W_TONES:
return "DIGITAL_W_TONES";
case PRI_TRANS_CAP_VIDEO:
return "VIDEO";
default:
return "UNKNOWN";
}
}
#endif /* CC_AST_CHANNEL_HAS_TRANSFERCAP */
static void capi_echo_canceller(struct ast_channel *c, int function)
{
struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c);
@ -749,7 +831,11 @@ int capi_call(struct ast_channel *c, char *idest, int timeout)
i->MessageNumber = get_ast_capi_MessageNumber();
CONNECT_REQ_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, i->controller);
CONNECT_REQ_CONTROLLER(&CMSG) = i->controller;
CONNECT_REQ_CIPVALUE(&CMSG) = 0x10; /* Telephony, could also use 0x04 (3.1Khz audio) */
#ifdef CC_AST_CHANNEL_HAS_TRANSFERCAP
CONNECT_REQ_CIPVALUE(&CMSG) = tcap2cip(c->transfercapability);
#else
CONNECT_REQ_CIPVALUE(&CMSG) = 0x10; /* Telephony */
#endif
called[0] = strlen(dest) + 1;
called[1] = 0x80;
strncpy(&called[2], dest, sizeof(called) - 2);
@ -814,7 +900,7 @@ static int capi_answer(struct ast_channel *c)
{
struct ast_capi_pvt *i = CC_AST_CHANNEL_PVT(c);
_cmsg CMSG;
char buf[AST_MAX_EXTENSION];
char buf[AST_CAPI_MAX_STRING];
char *dnid;
if ((i->isdnmode == AST_CAPI_ISDNMODE_PTP) &&
@ -824,6 +910,9 @@ static int capi_answer(struct ast_channel *c)
dnid = i->dnid;
}
i->fFax = NULL;
i->faxhandled = 0;
CONNECT_RESP_HEADER(&CMSG, ast_capi_ApplID, i->MessageNumber, 0);
CONNECT_RESP_PLCI(&CMSG) = i->PLCI;
CONNECT_RESP_REJECT(&CMSG) = 0;
@ -1071,7 +1160,7 @@ static struct ast_channel *capi_new(struct ast_capi_pvt *i, int state)
int fmt;
int fds[2];
tmp = ast_channel_alloc(1);
tmp = ast_channel_alloc(0);
if (tmp == NULL) {
ast_log(LOG_ERROR,"Unable to allocate channel!\n");
@ -1169,6 +1258,12 @@ static struct ast_channel *capi_new(struct ast_capi_pvt *i, int state)
#else
tmp->callerid = strdup(i->cid);
#endif
#ifdef CC_AST_CHANNEL_HAS_TRANSFERCAP
tmp->transfercapability = cip2tcap(i->cip);
pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", transfercapability2str(tmp->transfercapability));
#endif
strncpy(tmp->exten, i->dnid, sizeof(tmp->exten) - 1);
strncpy(tmp->accountcode, i->accountcode, sizeof(tmp->accountcode) - 1);
i->owner = tmp;
@ -1204,7 +1299,7 @@ struct ast_channel *capi_request(char *type, int format, void *data)
struct ast_capi_pvt *i;
struct ast_channel *tmp = NULL;
char *dest, *interface;
char buffer[AST_MAX_EXTENSION];
char buffer[AST_CAPI_MAX_STRING];
unsigned int capigroup = 0, controller = 0;
unsigned int foundcontroller;
int notfound = 1;
@ -1285,6 +1380,44 @@ struct ast_channel *capi_request(char *type, int format, void *data)
return NULL;
}
/*
* Fax guard tone -- Handle and return NULL
*/
static void capi_handle_dtmf_fax(struct ast_channel *ast)
{
struct ast_capi_pvt *p = CC_AST_CHANNEL_PVT(ast);
char *cid;
if (p->faxhandled) {
ast_log(LOG_DEBUG, "Fax already handled\n");
return;
}
p->faxhandled++;
if (!strcmp(ast->exten, "fax")) {
ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
return;
}
#ifdef CC_AST_CHANNEL_HAS_CID
cid = ast->cid.cid_num;
#else
cid = ast->callerid;
#endif
if (!ast_exists_extension(ast, ast->context, "fax", 1, cid)) {
ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
return;
}
cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name);
/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
if (ast_async_goto(ast, ast->context, "fax", 1))
ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, ast->context);
}
/*
* find a pipe in our pipe-list
*/
@ -1630,6 +1763,8 @@ static void capi_handle_facility_indication(_cmsg *CMSG, unsigned int PLCI, unsi
}
if (dtmflen == 1) {
dtmf = (FACILITY_IND_FACILITYINDICATIONPARAMETER(CMSG))[0];
if ((dtmf == 'X') || (dtmf == 'Y'))
capi_handle_dtmf_fax(p->c);
fr.frametype = AST_FRAME_DTMF;
fr.subclass = dtmf;
cc_ast_verbose(1, 1, VERBOSE_PREFIX_3 "c_dtmf = %c\n", dtmf);
@ -1711,6 +1846,15 @@ static void capi_handle_data_b3_indication(_cmsg *CMSG, unsigned int PLCI, unsig
p->i->B3in = AST_CAPI_MAX_B3_BLOCKS;
ast_mutex_unlock(&p->i->lockB3in);
#endif
if (p->i->fFax) {
/* we are in fax-receive */
cc_ast_verbose(6, 1, VERBOSE_PREFIX_3 "DATA_B3_IND (len=%d) Fax\n",
b3len);
if (fwrite((char *)&b3buf[AST_FRIENDLY_OFFSET], 1, b3len, p->i->fFax) != b3len)
ast_log(LOG_WARNING, "capiAnswerFax : error writing output file (%s)\n", strerror(errno));
return;
}
if ((p->i->doES == 1)) {
for (j = 0; j < b3len; j++) {
@ -1978,6 +2122,13 @@ static void capi_handle_disconnect_indication(_cmsg *CMSG, unsigned int PLCI, un
p->i->state = CAPI_STATE_DISCONNECTED;
p->i->faxhandled = 0;
if (p->i->fFax) {
cc_ast_verbose(2, 0, VERBOSE_PREFIX_3 "Closing fax file...\n");
fclose(p->i->fFax);
p->i->fFax = NULL;
}
fr.frametype = AST_FRAME_CONTROL;
if (DISCONNECT_IND_REASON(CMSG) == 0x34a2) {
fr.subclass = AST_CONTROL_BUSY;
@ -2017,7 +2168,7 @@ static void capi_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, unsig
int NPLAN=0;
int controller = 0;
char *msn;
char buffer[AST_MAX_EXTENSION];
char buffer[AST_CAPI_MAX_STRING];
char *magicmsn = "*\0";
char *emptyid = "\0";
char *emptydnid = "s\0";
@ -2091,6 +2242,7 @@ static void capi_handle_connect_indication(_cmsg *CMSG, unsigned int PLCI, unsig
} else
strncpy(i->cid, emptyid, sizeof(i->cid) - 1);
i->cip = CONNECT_IND_CIPVALUE(CMSG);
i->controller = controller;
i->PLCI = PLCI;
i->MessageNumber = CMSG->Messagenumber;
@ -2275,16 +2427,26 @@ static void capi_handle_confirmation(_cmsg *CMSG, unsigned int PLCI, unsigned in
case CAPI_ALERT:
if (!p)
break;
p->i->state = CAPI_STATE_ALERTING;
if (p->c->_state == AST_STATE_RING) {
p->c->rings = 1;
if (ALERT_CONF_INFO(CMSG) == 0) {
p->i->state = CAPI_STATE_ALERTING;
if (p->c->_state == AST_STATE_RING) {
p->c->rings = 1;
}
} else {
ast_log(LOG_ERROR, "CAPI: ALERT conf_error 0x%x Command.Subcommand = %#x.%#x\n",
CMSG->Info, CMSG->Command, CMSG->Subcommand);
}
break;
case CAPI_DISCONNECT:
case CAPI_DISCONNECT_B3:
case CAPI_SELECT_B_PROTOCOL:
case CAPI_LISTEN:
case CAPI_INFO:
case CAPI_DATA_B3:
/* we do nothing here */
if (CMSG->Info) {
ast_log(LOG_ERROR, "CAPI: conf_error 0x%x Command.Subcommand = %#x.%#x\n",
CMSG->Info, CMSG->Command, CMSG->Subcommand);
}
break;
default:
ast_log(LOG_ERROR,"CAPI: Command.Subcommand = %#x.%#x\n",
@ -2441,7 +2603,7 @@ int mkif(char *incomingmsn, char *context, char *controllerstr, int devices,
{
struct ast_capi_pvt *tmp;
int i = 0;
char buffer[100];
char buffer[AST_CAPI_MAX_STRING];
char *contr;
unsigned long contrmap = 0;
@ -2756,13 +2918,13 @@ int load_module(void)
struct ast_config *cfg;
struct ast_variable *v;
char *config = "capi.conf";
char incomingmsn[AST_MAX_EXTENSION] = "";
char incomingmsn[AST_CAPI_MAX_STRING] = "";
char context[AST_MAX_EXTENSION] = "";
char prefix[AST_MAX_EXTENSION] = "";
char accountcode[20] = "";
char *empty = "\0";
char deflect2[AST_MAX_EXTENSION] = "";
char controllerstr[AST_MAX_EXTENSION] = "";
char controllerstr[AST_CAPI_MAX_STRING] = "";
int res = 0;
int controller = 0;
int softdtmf = 0;

View File

@ -32,4 +32,17 @@ extern int capi_call(struct ast_channel *c, char *idest, int timeout);
extern int capi_detect_dtmf(struct ast_channel *c, int flag);
extern MESSAGE_EXCHANGE_ERROR _capi_put_cmsg(_cmsg *CMSG);
/*
* helper for ast_verbose with different verbose settings
*/
#define cc_ast_verbose(o_v, c_d, text...) \
do { \
if ((o_v == 0) || (option_verbose > o_v)) { \
if ((!c_d) || ((c_d) && (capidebug))) { \
ast_verbose(text); \
} \
} \
} while(0)
#endif

View File

@ -19,22 +19,22 @@
#ifndef _ASTERISK_CAPI_H
#define _ASTERISK_CAPI_H
#define AST_CAPI_MAX_CONTROLLERS 16
#define AST_CAPI_MAX_DEVICES 30
#define AST_CAPI_MAX_BUF 160
#define AST_CAPI_MAX_CONTROLLERS 16
#define AST_CAPI_MAX_DEVICES 30
#define AST_CAPI_MAX_BUF 160
#define AST_CAPI_MAX_B3_BLOCKS 7
#define AST_CAPI_MAX_B3_BLOCKS 7
/* was : 130 bytes Alaw = 16.25 ms audio not suitable for VoIP */
/* now : 160 bytes Alaw = 20 ms audio */
/* you can tune this to your need. higher value == more latency */
#define AST_CAPI_MAX_B3_BLOCK_SIZE 160
#define AST_CAPI_MAX_B3_BLOCK_SIZE 160
#define AST_CAPI_BCHANS 120
#define ALL_SERVICES 0x1FFF03FF
#define AST_CAPI_BCHANS 120
#define ALL_SERVICES 0x1FFF03FF
#define AST_CAPI_ISDNMODE_PTMP 0
#define AST_CAPI_ISDNMODE_PTP 1
#define AST_CAPI_ISDNMODE_PTMP 0
#define AST_CAPI_ISDNMODE_PTP 1
/* some helper functions */
static inline void write_capi_word(void *m, unsigned short val)
@ -59,14 +59,14 @@ static inline void write_capi_word(void *m, unsigned short val)
/* duration in ms for sending and detecting dtmfs */
#define AST_CAPI_DTMF_DURATION 0x40
#define AST_CAPI_DTMF_DURATION 0x40
#define AST_CAPI_NATIONAL_PREF "0"
#define AST_CAPI_INTERNAT_PREF "00"
#define ECHO_TX_COUNT 5 // 5 x 20ms = 100ms
#define ECHO_EFFECTIVE_TX_COUNT 3 // 2 x 20ms = 40ms == 40-100ms ... ignore first 40ms
#define ECHO_TXRX_RATIO 2.3 // if( rx < (txavg/ECHO_TXRX_RATIO) ) rx=0;
#define ECHO_TX_COUNT 5 /* 5 x 20ms = 100ms */
#define ECHO_EFFECTIVE_TX_COUNT 3 /* 2 x 20ms = 40ms == 40-100ms ... ignore first 40ms */
#define ECHO_TXRX_RATIO 2.3 /* if( rx < (txavg/ECHO_TXRX_RATIO) ) rx=0; */
#define FACILITYSELECTOR_DTMF 1
#define FACILITYSELECTOR_SUPPLEMENTARY 3
@ -80,41 +80,43 @@ static inline void write_capi_word(void *m, unsigned short val)
* DIS -> CONP -> BCONNECTED -> CON -> DIS
*/
#define CAPI_STATE_ALERTING 1
#define CAPI_STATE_CONNECTED 2
#define CAPI_STATE_BCONNECTED 3
#define CAPI_STATE_ALERTING 1
#define CAPI_STATE_CONNECTED 2
#define CAPI_STATE_BCONNECTED 3
#define CAPI_STATE_DISCONNECTING 4
#define CAPI_STATE_DISCONNECTED 5
#define CAPI_STATE_REMOTE_HANGUP 6
#define CAPI_STATE_DISCONNECTING 4
#define CAPI_STATE_DISCONNECTED 5
#define CAPI_STATE_REMOTE_HANGUP 6
#define CAPI_STATE_CONNECTPENDING 7
#define CAPI_STATE_ONHOLD 8
#define CAPI_STATE_NETWORKHANGUP 9
#define CAPI_STATE_ANSWERING 10
#define CAPI_STATE_PUTTINGONHOLD 11
#define CAPI_STATE_RETRIEVING 12
#define CAPI_STATE_CONNECTPENDING 7
#define CAPI_STATE_ONHOLD 8
#define CAPI_STATE_NETWORKHANGUP 9
#define CAPI_STATE_ANSWERING 10
#define CAPI_STATE_PUTTINGONHOLD 11
#define CAPI_STATE_RETRIEVING 12
#define CAPI_STATE_DID 13
#define CAPI_STATE_DID 13
#define AST_CAPI_B3_DONT 0
#define AST_CAPI_B3_ALWAYS 1
#define AST_CAPI_B3_ON_SUCCESS 2
#define AST_CAPI_B3_DONT 0
#define AST_CAPI_B3_ALWAYS 1
#define AST_CAPI_B3_ON_SUCCESS 2
#define AST_CAPI_MAX_STRING 2048
struct ast_capi_gains {
unsigned char txgains[256];
unsigned char rxgains[256];
};
#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00
#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01
#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02
#define PRES_ALLOWED_NETWORK_NUMBER 0x03
#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20
#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21
#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22
#define PRES_PROHIB_NETWORK_NUMBER 0x23
#define PRES_NUMBER_NOT_AVAILABLE 0x43
#define PRES_ALLOWED_USER_NUMBER_NOT_SCREENED 0x00
#define PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN 0x01
#define PRES_ALLOWED_USER_NUMBER_FAILED_SCREEN 0x02
#define PRES_ALLOWED_NETWORK_NUMBER 0x03
#define PRES_PROHIB_USER_NUMBER_NOT_SCREENED 0x20
#define PRES_PROHIB_USER_NUMBER_PASSED_SCREEN 0x21
#define PRES_PROHIB_USER_NUMBER_FAILED_SCREEN 0x22
#define PRES_PROHIB_NETWORK_NUMBER 0x23
#define PRES_NUMBER_NOT_AVAILABLE 0x43
/* ! Private data for a capi device */
@ -159,7 +161,7 @@ struct ast_capi_pvt {
char context[AST_MAX_EXTENSION];
/*! Multiple Subscriber Number we listen to (, seperated list) */
char incomingmsn[AST_MAX_EXTENSION];
char incomingmsn[AST_CAPI_MAX_STRING];
/*! Prefix to Build CID */
char prefix[AST_MAX_EXTENSION];
/*! Caller ID if available */
@ -197,6 +199,14 @@ struct ast_capi_pvt {
/* isdnmode ptp or ptm */
int isdnmode;
/* Common ISDN Profile (CIP) */
int cip;
/* if not null, receiving a fax */
FILE *fFax;
/* Has a fax tone already been handled? */
int faxhandled;
/* deflect on circuitbusy */
char deflect2[AST_MAX_EXTENSION];
@ -287,17 +297,49 @@ struct ast_capi_controller {
/* ETSI 300 102-1 information element identifiers */
#define CAPI_ETSI_IE_CAUSE 0x08;
#define CAPI_ETSI_IE_PROGRESS_INDICATOR 0x1e;
#define CAPI_ETSI_IE_CALLED_PARTY_NUMBER 0x70;
#define CAPI_ETSI_IE_CAUSE 0x08
#define CAPI_ETSI_IE_PROGRESS_INDICATOR 0x1e
#define CAPI_ETSI_IE_CALLED_PARTY_NUMBER 0x70
/* ETIS 300 102-1 message types */
#define CAPI_ETSI_ALERTING 0x01;
#define CAPI_ETSI_SETUP_ACKKNOWLEDGE 0x0d;
#define CAPI_ETSI_DISCONNECT 0x45;
#define CAPI_ETSI_ALERTING 0x01
#define CAPI_ETSI_SETUP_ACKKNOWLEDGE 0x0d
#define CAPI_ETSI_DISCONNECT 0x45
/* ETSI 300 102-1 Numbering Plans */
#define CAPI_ETSI_NPLAN_NATIONAL 0x20
#define CAPI_ETSI_NPLAN_INTERNAT 0x10
#define CAPI_ETSI_NPLAN_NATIONAL 0x20
#define CAPI_ETSI_NPLAN_INTERNAT 0x10
/* Common ISDN Profiles (CIP) */
#define CAPI_CIP_SPEECH 0x01
#define CAPI_CIP_DIGITAL 0x02
#define CAPI_CIP_RESTRICTED_DIGITAL 0x03
#define CAPI_CIP_3K1AUDIO 0x04
#define CAPI_CIP_7KAUDIO 0x05
#define CAPI_CIP_VIDEO 0x06
#define CAPI_CIP_PACKET_MODE 0x07
#define CAPI_CIP_56KBIT_RATE_ADAPTION 0x08
#define CAPI_CIP_DIGITAL_W_TONES 0x09
#define CAPI_CIP_TELEPHONY 0x10
#define CAPI_CIP_FAX_G2_3 0x11
#define CAPI_CIP_FAX_G4C1 0x12
#define CAPI_CIP_FAX_G4C2_3 0x13
#define CAPI_CIP_TELETEX_PROCESSABLE 0x14
#define CAPI_CIP_TELETEX_BASIC 0x15
#define CAPI_CIP_VIDEOTEX 0x16
#define CAPI_CIP_TELEX 0x17
#define CAPI_CIP_X400 0x18
#define CAPI_CIP_X200 0x19
#define CAPI_CIP_7K_TELEPHONY 0x1a
#define CAPI_CIP_VIDEO_TELEPHONY_C1 0x1b
#define CAPI_CIP_VIDEO_TELEPHONY_C2 0x1c
/* Transfer capabilities */
#define PRI_TRANS_CAP_SPEECH 0x00
#define PRI_TRANS_CAP_DIGITAL 0x08
#define PRI_TRANS_CAP_RESTRICTED_DIGITAL 0x09
#define PRI_TRANS_CAP_3K1AUDIO 0x10
#define PRI_TRANS_CAP_DIGITAL_W_TONES 0x11
#define PRI_TRANS_CAP_VIDEO 0x18
#endif

View File

@ -66,6 +66,14 @@ else
echo " * no 'struct timeval delivery'"
fi
if grep -q "transfercapability" $INCLUDEDIR/channel.h; then
echo "#define CC_AST_CHANNEL_HAS_TRANSFERCAP" >>$CONFIGFILE
echo " * found 'transfercapability'"
else
echo "#undef CC_AST_CHANNEL_HAS_TRANSFERCAP" >>$CONFIGFILE
echo " * no 'transfercapability'"
fi
echo "" >>$CONFIGFILE
echo "#endif /* CHAN_CAPI_CONFIG_H */" >>$CONFIGFILE