bintec-capi-isdnlogin/il_capi.c

470 lines
12 KiB
C

#include "isdnlogin.h"
extern cfg_t cfg;
extern global_t global;
int get_capi_info (void)
{
int i;
int max_controller;
unsigned long controller_mask = 0;
capi_getprofile_t profile;
memset( &profile, 0, sizeof(profile));
#if WITH_RCAPI_LAYER
rcapi_get_profile( 0, &profile, &(cfg.capi_host));
#else
capi2_get_profile( 0, &profile );
#endif
max_controller = profile.ncontrl;
printf("Available CAPI controllers: %d\n", max_controller);
if (max_controller) {
for( i=1; i<33; i++) {
memset( &profile, 0, sizeof(profile));
#if WITH_RCAPI_LAYER
if (!rcapi_get_profile( i, &profile, &(cfg.capi_host))) {
#else
if (!capi2_get_profile( i, &profile)) {
#endif
controller_mask |= (1 << (i-1));
if (!--max_controller) break;
}
}
}
// XXX: doesnt seem to work!
if (!(((1 << cfg.controller)-1) & controller_mask)) {
fprintf( stderr, "No such Controller %d!\n", cfg.controller);
return 1;
}
memset( &profile, 0, sizeof(profile));
#if WITH_RACPI_LAYER
capi2_get_profile( cfg.controller, &profile, &(cfg.capi_host) );
#else
capi2_get_profile( cfg.controller, &profile );
#endif
#if DEBUG /* debug printf */
fprintf( stderr, "ncontrl = 0x%x\n", profile.ncontrl);
fprintf( stderr, "nchannel = 0x%x\n", profile.nchannel);
fprintf( stderr, "options = 0x%x\n", profile.options);
fprintf( stderr, "b1protocol = 0x%x\n", profile.b1protocol);
fprintf( stderr, "b2protocol = 0x%x\n", profile.b2protocol);
fprintf( stderr, "b3protocol = 0x%x\n", profile.b3protocol);
fprintf( stderr, "\n");
#endif
if ( !(profile.b1protocol & (SI_PHONE)) ||
!(profile.b2protocol & (SI_PHONE)) ||
!(profile.b3protocol & (SI_PHONE))) {
fprintf( stderr, "Controller %d: does not support telephony service\n",
cfg.controller);
return 1;
}
return 0;
}
/*******************************************************************
*
*******************************************************************/
int init_capi()
{
int fd;
for(;;) {
if(cfg.verbose > 2){
putchar('R');
}
#if WITH_RCAPI_LAYER
fd = capi2_register( REG_CAPI_MSG_SIZE,
REG_CAPI_LEVEL3CNT,
cfg.usWindowSize,
REG_CAPI_DATA_BLK_SIZE,
NULL,
&(cfg.capi_host),
&(cfg.capi_auth));
#else
fd = capi2_register( REG_CAPI_MSG_SIZE,
REG_CAPI_LEVEL3CNT,
cfg.usWindowSize,
REG_CAPI_DATA_BLK_SIZE,
NULL);
#endif
if(fd >0 ) break;
fprintf( stderr, "capi2_register failed! retry in %d seconds\n",
REGISTER_FAIL_TIMER );
sleep(REGISTER_FAIL_TIMER);
}
return fd;
}
int setListen( call_t *ptrCall, int mask )
{
int ret;
ret = capi2_listen_req( ptrCall->capi_fd,
ptrCall->ident, /* Controller */
0x000001ff, /* Info Mask */
mask, /* CIP Mask */
0, /* CIP Mask2 */
NULL, /* Calling party number */
NULL); /* Calling party subaddress */
return ret;
}
void check_capi (void)
{
if (global.alive_pending > MAX_KEEPALIVE_PENDING) {
global.endloop = E_KeepAliveFailed; /* indicate keepalive overflow */
return;
}
capi_control_req( global.calls->capi_fd, global.calls->ident,
CTRL_CAPISTATE , NULL);
global.alive_pending++;
}
/*******************************************************************
*
*******************************************************************/
int getCapiInfo( union CAPI_primitives *capi )
{
int info;
switch (GET_PRIMTYPE(capi)) {
case CAPI2_LISTEN_CONF:
info = GET_WORD(capi->c2listen_conf.info);
break;
case CAPI2_ALERT_CONF:
info = GET_WORD(capi->c2alert_conf.info);
break;
case CAPI2_CONNECT_CONF:
info = GET_WORD(capi->c2connect_conf.info);
break;
case CAPI2_INFO_CONF:
info = GET_WORD(capi->c2info_conf.info);
break;
case CAPI2_CONNECTB3_CONF:
info = GET_WORD(capi->c2connectb3_conf.info);
break;
case CAPI2_DATAB3_CONF:
info = GET_WORD(capi->c2datab3_conf.info);
break;
case CAPI2_RESETB3_CONF:
info = GET_WORD(capi->c2resetb3_conf.info);
break;
case CAPI2_DISCONNECTB3_CONF:
info = GET_WORD(capi->c2disconnectb3_conf.info);
break;
case CAPI2_DISCONNECT_CONF:
info = GET_WORD(capi->c2disconnect_conf.info);
break;
case CAPI2_FACILITY_CONF:
info = GET_WORD(capi->c2facility_conf.info);
break;
case CAPI2_SELECTB_CONF:
info = GET_WORD(capi->c2selectb_conf.info);
break;
case CAPI2_DISCONNECT_IND:
info = GET_WORD(capi->c2disconnect_ind.reason);
break;
case CAPI2_DISCONNECTB3_IND:
info = GET_WORD(capi->c2disconnectb3_ind.reason_b3);
break;
default:
info = 0;
break;
}
return (info);
}
void doConnect( call_t *ptrCall )
{
ptrCall->messid = capi2_connect_req( ptrCall->capi_fd,
ptrCall->ident & 0x7f,
ptrCall->service->cip,
&ptrCall->CalledPartyNumber,
&ptrCall->CallingPartyNumber,
&ptrCall->CalledPartySubaddress,
&ptrCall->CallingPartySubaddress,
&ptrCall->Bprotocol,
NULL, &ptrCall->llc, NULL,
&ptrCall->AdditionalInfo);
if(cfg.verbose>8) {
printf("messid from capi2_connect_req() == 0x%x\n", ptrCall->messid);
}
NEWSTATE( ptrCall, D_ConnectPending);
}
/*******************************************************************
*
*******************************************************************/
void doDisconnect( call_t *ptrCall )
{
unsigned long plci, ncci;
ncci = ptrCall->ident;
plci = ptrCall->ident & 0xffff;
switch (ptrCall->state) {
case B_ConnectPending:
case Connected:
if(cfg.wait4dataconf && ptrCall->NotAcknowledged) {
if(cfg.verbose>1) {
printf("doDisconnect() wait for %d CAPI2_DATAB3_CONF\n",
ptrCall->NotAcknowledged);
}
/* don't send a capi2_disconnectb3_req() we have to wait */
break;
}
if(ptrCall->NotAcknowledged && cfg.verbose>0) {
printf("doDisconnect() missing %d CAPI2_DATAB3_CONF\n",
ptrCall->NotAcknowledged);
}
capi2_disconnectb3_req( ptrCall->capi_fd,
ncci,
NULL);
break;
case D_ConnectPending:
case B_DisconnectPending:
NEWSTATE( ptrCall, D_DisconnectPending);
capi2_disconnect_req( ptrCall->capi_fd,
plci,
NULL);
break;
case D_DisconnectPending:
case Disconnected:
default:
break;
}
}
#if WITH_UNFINISHED_XMODEM
int SendXmodemData( call_t *ptrCall )
{
char buffer[1024];
size_t len;
xmodem_t *xm = ptrCall->xmodem;
len = fread( buffer, 1, sizeof(buffer), xm->sendfp);
if (len <= 0) {
/* XXX: check for errors */
fclose(xm->sendfp);
}
printf("\nSend XMODEM sector: %d errors: %d ", xm->sentsectcnt, xm->errors);
if (!xmodem_putpkt(xm, buffer, len, ptrCall->error_msg)) {
xmodem_close(xm);
return 0;
}
return 1;
}
#endif
/*******************************************************************
*
*******************************************************************/
void SendData( call_t *ptrCall )
{
static unsigned short usDataHandle;
char buffer[REG_CAPI_DATA_BLK_SIZE];
int len;
if (0== ptrCall->doSend) { return; }
/*
* Read next blk from file into buffer
*/
#if LOGIN_SCRIPT_LINE_BY_LINE
{
char *dataptr;
dataptr = fgets( buffer, sizeof(buffer), ptrCall->txfp);
if (dataptr == NULL) {
/* fgets returned noting, we are out */
ptrCall->doSend = 0;
return;
}
len = strlen(dataptr); /* get line length */
}
#else
/*
* NOTE: Don't know why but if we send data with a length
* equal to REG_CAPI_DATA_BLK_SIZE, the brick gona
* complain about to long packet, so we just send
* half of the max buffer size.
*/
len = fread( buffer, 1, (sizeof(buffer) / 2), ptrCall->txfp);
if (len <= 0) {
if (len < 0) {
perror("\nERR:SendData\n");
}
ptrCall->doSend = 0;
return;
}
#endif
ptrCall->NotAcknowledged++; /* count pending confirms */
usDataHandle++;
capi2_datab3_req( ptrCall->capi_fd,
ptrCall->ident,
buffer,
len,
0,
usDataHandle);
}
/*******************************************************************
*
*******************************************************************/
void handleConnectB3ActiveInd( call_t *ptrCall )
{
if(cfg.verbose > 0) {
printf("Terminate sequence is '%c%c'\n", ESCAPE_CHAR, TERMINATE_CHAR);
}
/* put terminal into raw mode after connect was okay */
set_raw_terminal();
cfg.starttime = time(0);
ptrCall->wasConnected = 1;
ptrCall->doSend = 1;
if (ptrCall->txfp) {
SendData( ptrCall );
}
}
/*******************************************************************
*
*******************************************************************/
int handleDataB3Ind( call_t *ptrCall,
unsigned short messid,
unsigned char *dataptr,
int datalen,
unsigned short handle,
unsigned short flags )
{
#if 0
printf("komisch hab ne data indicationb\n");
capi_hexdump( dataptr, datalen, 16, 2);
#endif
printf("%*.*s", datalen, datalen, dataptr);
return 1; /* response */
}
/*******************************************************************
*
*******************************************************************/
void handleDataB3Conf( call_t *ptrCall,
unsigned short messid,
unsigned short handle )
{
ptrCall->NotAcknowledged--; /* We got a acknowledge */
#ifdef FAX
if(cfg.verbose > 2) {
putchar('c');
}
#endif
if (ptrCall->txfp) {
SendData( ptrCall ); /* Send the next one */
}
}
/*******************************************************************
*
*******************************************************************/
void handleInfoInd( call_t *ptrCall,
unsigned short infonumber,
struct userdata *data )
{
unsigned long mask;
unsigned char *datap = data->data;
switch(infonumber){
default:
if(cfg.verbose>5){
printf("\tINFOIND: 0x%04x\n", infonumber);
capi_hexdump( data->data, data->length, 16, 2);
}
break;
case 0x18: /* IBCHI */
if (*datap & (1<<5)) {
/* primary rate interface */
if (*datap++ & (1<<6)) {
/* interface identifier present */
while((*datap++ & 0x80) == 0);
}
if (*datap++ & (1<<4)) {
cfg.b_channel = 1;
mask = 1;
while(!(mask & *datap)){
mask<<=1;
cfg.b_channel++;
}
}
else {
cfg.b_channel = *datap & 0x7f;
}
}
else {
/* basic rate interface */
cfg.b_channel = *datap & 0x03;
}
if(cfg.verbose>2){
printf("\tINFOIND: ISDN-BCHANNEL %d\n", cfg.b_channel);
}
break;
}
}
/*******************************************************************
*
*******************************************************************/
void handleDisconnectB3Ind( call_t *ptrCall,
unsigned short nReason,
struct userdata *ncpi )
{
int delta_time;
cfg.endtime = time(0);
delta_time = cfg.endtime - cfg.starttime;
reset_terminal();
/* No need for this here
* if (nReason) printf("\tDISCONNECT B3_Reason (0x%04x)\n", nReason);
*/
if(ptrCall->NotAcknowledged && cfg.verbose>0) {
printf("handleDisconnectB3Ind() missing %d CAPI2_DATAB3_CONF\n",
ptrCall->NotAcknowledged);
}
}
/*******************************************************************
*
*******************************************************************/
void handleDisconnectInd( call_t *ptrCall,
unsigned short nReason)
{
printf("ISDN D-channel disconnect, Reason (%04x)\n", nReason);
}