commit
2346f259ef
@ -0,0 +1,74 @@
|
||||
# Makefile - BinTec Remote CAPI Library
|
||||
#
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
# be sure to get a BINTEC_PUBLIC_RELEASE_1_7 tagged capi, because the HEAD
|
||||
# release is still buggy.
|
||||
CAPIDIR = ../bintec_capi
|
||||
|
||||
CC = gcc
|
||||
LD = ld
|
||||
DEFS = -I. -I/usr/local/include -I$(CAPIDIR)
|
||||
COPTS = -O -Wall
|
||||
CWARN =
|
||||
CFLAGS = $(COPTS) $(CWARN) $(DEFS)
|
||||
LIBS = $(CAPIDIR)/libcapi.a
|
||||
LORDER = sh ./lorder
|
||||
TSORT = tsort
|
||||
LN = ln
|
||||
AR = ar rv
|
||||
INSTALL = install
|
||||
RANLIB = ranlib
|
||||
OSTYPE = `uname -srm | tr " " _`
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .out .o .po .So .s .S .c .cc .cpp .cxx .m .C .f .y .l
|
||||
|
||||
.c.o: isdnlogin.h Makefile
|
||||
${CC} ${CFLAGS} -c $< -o $@
|
||||
|
||||
prefix = /usr/local
|
||||
bindir = $(prefix)/bin
|
||||
libdir = $(prefix)/lib
|
||||
incdir = $(prefix)/include
|
||||
|
||||
CAPIAPP = isdnlogin
|
||||
ISDNLOGIN = isdnlogin.o il_capi.o il_tty.o il_call.o il_poll.o \
|
||||
il_event.o il_proc.o xmodem.o
|
||||
|
||||
all: $(CAPIAPP)
|
||||
|
||||
# dynamically linked version
|
||||
isdnlogin: Makefile $(ISDNLOGIN)
|
||||
$(CC) -o $@ $(CFLAGS) $(ISDNLOGIN) $(LIBS)
|
||||
|
||||
# the static version of isdnlogin app
|
||||
isdnlogin.static: Makefile $(ISDNLOGIN)
|
||||
$(CC) -o $@ $(CFLAGS) $(ISDNLOGIN) $(CAPIDIR)/libcapi.a
|
||||
|
||||
install: all installdirs
|
||||
@for prog in $(CAPIAPP); \
|
||||
do \
|
||||
echo $(INSTALL) $$prog $(bindir); \
|
||||
$(INSTALL) $$prog $(bindir) || exit 1; \
|
||||
done
|
||||
|
||||
installdirs:
|
||||
@$(SHELL) mkinstalldirs $(prefix) $(bindir)
|
||||
|
||||
dist: Makefile isdnlogin
|
||||
@echo "Generating distribution for OS $(OSTYPE)"
|
||||
@rm -f isdnlogin.$(OSTYPE)
|
||||
@rm -f isdnlogin.$(OSTYPE).gz
|
||||
@cp isdnlogin isdnlogin.$(OSTYPE)
|
||||
@strip isdnlogin.$(OSTYPE)
|
||||
@gzip -9 isdnlogin.$(OSTYPE)
|
||||
@echo "Your archive is named 'isdnlogin.$(OSTYPE).gz'."
|
||||
|
||||
clean:
|
||||
rm -f $(CAPIAPP)
|
||||
rm -f core *.o
|
||||
|
||||
distclean: clean
|
||||
rm -f $(CAPIAPP)
|
@ -0,0 +1,319 @@
|
||||
#include "isdnlogin.h"
|
||||
|
||||
extern cfg_t cfg;
|
||||
extern char * prog_logo;
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
call_t *alloc_call(void)
|
||||
{
|
||||
call_t *ptrCall;
|
||||
|
||||
ptrCall = (call_t *)malloc( sizeof(*ptrCall));
|
||||
|
||||
if (!ptrCall) return NULL;
|
||||
memset( ptrCall, 0, sizeof(*ptrCall));
|
||||
|
||||
/*
|
||||
* open file to transmit
|
||||
*/
|
||||
if (cfg.sendfile) {
|
||||
ptrCall->pFilename = cfg.sendfile;
|
||||
if (!(ptrCall->txfp=fopen( ptrCall->pFilename, "r"))) {
|
||||
printf ("Could read from file: <%s>\n", ptrCall->pFilename);
|
||||
exit ( 1 );
|
||||
}
|
||||
if ( cfg.verbose > 2 ) {
|
||||
printf("Reading from file: <%s>\n", ptrCall->pFilename);
|
||||
}
|
||||
}
|
||||
|
||||
/* default call settings */
|
||||
|
||||
/* add service and controller to call */
|
||||
ptrCall->active = 1;
|
||||
ptrCall->ident = cfg.controller; /* controller */
|
||||
ptrCall->service= cfg.service;
|
||||
|
||||
/* set numbers */
|
||||
setCalledPartyNumber( ptrCall, cfg.rmttelno);
|
||||
setCallingPartyNumber( ptrCall, cfg.loctelno, 1);
|
||||
setCalledPartySubaddress( ptrCall, cfg.rmtsubaddr);
|
||||
setCallingPartySubaddress( ptrCall, cfg.locsubaddr);
|
||||
|
||||
/* adjust protocols */
|
||||
setBprotocol( ptrCall);
|
||||
setLLC( ptrCall );
|
||||
setAdditionalInfo( ptrCall );
|
||||
|
||||
return ptrCall;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
void free_call( call_t *ptrCall )
|
||||
{
|
||||
if (ptrCall) {
|
||||
if (ptrCall->txfp) {
|
||||
fclose( ptrCall->txfp);
|
||||
}
|
||||
free(ptrCall);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
struct userdata *setCalledPartyNumber( call_t *ptrCall,
|
||||
char *szCalledPartyNumber)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
ptrCall->CalledPartyNumber.length = 0;
|
||||
if (szCalledPartyNumber) {
|
||||
len = strlen( szCalledPartyNumber);
|
||||
len = min(len, CAPI1_MAXMSGLEN-1);
|
||||
if (len) {
|
||||
ptrCall->CalledPartyNumber.data[0] = 0x81;
|
||||
|
||||
memcpy( &ptrCall->CalledPartyNumber.data[1],
|
||||
szCalledPartyNumber, len);
|
||||
ptrCall->CalledPartyNumber.length = len+1;
|
||||
}
|
||||
}
|
||||
|
||||
return &ptrCall->CalledPartyNumber;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
struct userdata *setCallingPartyNumber( call_t *ptrCall,
|
||||
char *szCallingPartyNumber,
|
||||
int lPresentation)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
ptrCall->CallingPartyNumber.length = 0;
|
||||
if (szCallingPartyNumber) {
|
||||
len = strlen( szCallingPartyNumber);
|
||||
len = min(len, CAPI1_MAXMSGLEN-1);
|
||||
if (len) {
|
||||
ptrCall->CallingPartyNumber.data[0] = 0x01;
|
||||
ptrCall->CallingPartyNumber.data[1] = lPresentation ? 0x80 : 0xa0;
|
||||
|
||||
memcpy( &ptrCall->CallingPartyNumber.data[2],
|
||||
szCallingPartyNumber, len);
|
||||
ptrCall->CallingPartyNumber.length = len+2;
|
||||
}
|
||||
}
|
||||
|
||||
return &ptrCall->CallingPartyNumber;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
struct userdata *setCalledPartySubaddress( ptrCall, szCalledPartySubaddress)
|
||||
call_t *ptrCall;
|
||||
char *szCalledPartySubaddress;
|
||||
{
|
||||
size_t len;
|
||||
|
||||
ptrCall->CalledPartySubaddress.data[0] = 0x80;
|
||||
if ((len = strlen(szCalledPartySubaddress))) {
|
||||
memcpy( &ptrCall->CalledPartySubaddress.data[1],
|
||||
szCalledPartySubaddress, len);
|
||||
} else {
|
||||
ptrCall->CalledPartySubaddress.data[1] = 0;
|
||||
len = 1;
|
||||
}
|
||||
|
||||
ptrCall->CalledPartySubaddress.length = len + 1;
|
||||
return &ptrCall->CalledPartySubaddress;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
struct userdata *setCallingPartySubaddress( call_t *ptrCall,
|
||||
char *szCallingPartySubaddress)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
ptrCall->CallingPartySubaddress.data[0] = 0x80; /* always there */
|
||||
|
||||
if ((len = strlen(szCallingPartySubaddress))) {
|
||||
/* if subaddress suplied use it */
|
||||
memcpy( &ptrCall->CallingPartySubaddress.data[1],
|
||||
szCallingPartySubaddress, len);
|
||||
} else {
|
||||
ptrCall->CallingPartySubaddress.data[1] = 0;
|
||||
len = 1;
|
||||
}
|
||||
|
||||
ptrCall->CallingPartySubaddress.length = len + 1; /* one for the type */
|
||||
return &ptrCall->CallingPartySubaddress;
|
||||
}
|
||||
|
||||
userdata_t *setBprotocol( call_t *ptrCall)
|
||||
{
|
||||
userdata_t *data;
|
||||
struct bprotocol *bprot;
|
||||
struct b1config *b1cfg;
|
||||
struct b1config_modem *b1cfg_mdm;
|
||||
struct b2config *b2cfg;
|
||||
struct b3config *b3cfg;
|
||||
|
||||
bprot = (struct bprotocol *)&ptrCall->Bprotocol;
|
||||
|
||||
/* set layer 1 protocol */
|
||||
PUT_WORD( bprot->b1proto, ptrCall->service->layer1_mask);
|
||||
|
||||
/* depending on service set layer 2 protocol */
|
||||
switch(ptrCall->service->hw) {
|
||||
case ISDN_HDLC:
|
||||
PUT_WORD( bprot->b2proto, B2X75);
|
||||
break;
|
||||
case FAX_G3:
|
||||
PUT_WORD( bprot->b2proto, B2T30);
|
||||
break;
|
||||
case ISDN_V42:
|
||||
PUT_WORD( bprot->b2proto, B2X75V42BIS);
|
||||
break;
|
||||
case V110_ASYNC:
|
||||
case TRANS:
|
||||
case MODEM:
|
||||
default:
|
||||
PUT_WORD( bprot->b2proto, B2TRANS);
|
||||
break;
|
||||
}
|
||||
|
||||
/* check for layer 2 specific settings */
|
||||
switch (ptrCall->service->hw) {
|
||||
case FAX_G3:
|
||||
PUT_WORD( bprot->b3proto, B3T30);
|
||||
break;
|
||||
default:
|
||||
/* layer 3 is always trans for now */
|
||||
PUT_WORD( bprot->b3proto, B3TRANS);
|
||||
break;
|
||||
}
|
||||
data = (userdata_t *)&bprot->structlen;
|
||||
|
||||
/* check if the service has special layer 2 config */
|
||||
switch(ptrCall->service->hw) {
|
||||
case V110_ASYNC:
|
||||
b1cfg = (struct b1config *) data;
|
||||
/* v110 specific layer 2 params */
|
||||
PUT_WORD( b1cfg->rate, cfg.speed);
|
||||
PUT_WORD( b1cfg->bpc, 8);
|
||||
PUT_WORD( b1cfg->parity, 0);
|
||||
PUT_WORD( b1cfg->stopbits, 0);
|
||||
b1cfg->length = sizeof( struct b1config) - 1;
|
||||
break;
|
||||
case MODEM:
|
||||
/* modem specific params */
|
||||
b1cfg_mdm = (b1config_modem_t *) data;
|
||||
PUT_WORD( b1cfg_mdm->rate, cfg.speed); /* 0 = max speed */
|
||||
PUT_WORD( b1cfg_mdm->bpc, 8);
|
||||
PUT_WORD( b1cfg_mdm->parity, 0);
|
||||
PUT_WORD( b1cfg_mdm->stopbits, 0);
|
||||
PUT_WORD( b1cfg_mdm->options, 0);
|
||||
PUT_WORD( b1cfg_mdm->negotiation, 1); /* allow autoneg */
|
||||
b1cfg_mdm->length = sizeof( struct b1config_modem) -1;
|
||||
break;
|
||||
case FAX_G3:
|
||||
/* FAX group 3 params */
|
||||
b1cfg = (struct b1config *) data;
|
||||
PUT_WORD( b1cfg->rate, cfg.speed);
|
||||
PUT_WORD( b1cfg->bpc, 0);
|
||||
PUT_WORD( b1cfg->parity, 0);
|
||||
PUT_WORD( b1cfg->stopbits, 0);
|
||||
b1cfg->length = sizeof( struct b1config) - 1;
|
||||
break;
|
||||
default:
|
||||
data->length = 0;
|
||||
break;
|
||||
}
|
||||
data = (userdata_t *)&data->data[data->length];
|
||||
|
||||
b2cfg = (struct b2config *) data;
|
||||
switch(ptrCall->service->hw) {
|
||||
case ISDN_HDLC:
|
||||
b2cfg->addressA = 3;
|
||||
b2cfg->addressB = 1;
|
||||
b2cfg->moduloMode = 8;
|
||||
b2cfg->windowSize = 7;
|
||||
b2cfg->xidlen = 0;
|
||||
b2cfg->length = sizeof( struct b2config) - 1;
|
||||
break;
|
||||
default:
|
||||
b2cfg->length = 0;
|
||||
break;
|
||||
}
|
||||
data = (userdata_t *)&data->data[data->length];
|
||||
|
||||
/* Layer 3 always transparent */
|
||||
b3cfg = (struct b3config *) data;
|
||||
b3cfg->length = 0;
|
||||
|
||||
bprot->length = (char *)data - (char *)&bprot->length -1;
|
||||
#if 0
|
||||
capi_hexdump((char*) bprot, bprot->length, 16, 2);
|
||||
printf("b1cfg->length=%d\n", b1cfg->length);
|
||||
printf("b1cfg_mdm->length=%d\n", b1cfg_mdm->length);
|
||||
printf("b2cfg->length=%d\n", b2cfg->length);
|
||||
printf("bprot->length=%d\n", bprot->length);
|
||||
printf("data->length=%d\n", data->length);
|
||||
//printf("data->structlen=%d\n", data->structlen);
|
||||
#endif
|
||||
|
||||
return (userdata_t *)bprot;
|
||||
}
|
||||
|
||||
userdata_t *setLLC( call_t *ptrCall ) {
|
||||
userdata_t *llc;
|
||||
/* Lower Layer Compatibility */
|
||||
static char llcs[] = { 0x90, 0x88, 0x90, 0x21, 0x42, 0x00, 0xbb };
|
||||
|
||||
llc = &ptrCall->llc;
|
||||
|
||||
if (ptrCall->service->rate) {
|
||||
llc = (userdata_t *)&ptrCall->llc;
|
||||
|
||||
llcs[4] = cfg.v110_speed; /* set user rate */
|
||||
memcpy(&ptrCall->llc, &llcs, sizeof(llcs));
|
||||
llc->length = sizeof(llcs) - 1;
|
||||
}
|
||||
return llc;
|
||||
}
|
||||
|
||||
userdata_t *setAdditionalInfo( call_t *ptrCall )
|
||||
{
|
||||
struct userdata *add;
|
||||
struct userdata *data;
|
||||
|
||||
add = (struct userdata *)&ptrCall->AdditionalInfo;
|
||||
data = (struct userdata *)add->data;
|
||||
|
||||
data->length = 0; /* b-channel */
|
||||
|
||||
data = (struct userdata *)&data->data[data->length];
|
||||
data->length = 0; /* keypad */
|
||||
|
||||
data = (struct userdata *)&data->data[data->length];
|
||||
memcpy(&data->data[0], prog_logo, strlen(prog_logo));
|
||||
|
||||
data->length = strlen(data->data); /* user user data */
|
||||
|
||||
data = (struct userdata *)&data->data[data->length];
|
||||
data->length = 0; /* facility */
|
||||
|
||||
data = (struct userdata *)&data->data[data->length];
|
||||
add->length = (char *)data - (char *)&add->length - 1;
|
||||
|
||||
return (struct userdata *)add;
|
||||
}
|
@ -0,0 +1,469 @@
|
||||
#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);
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
#include "isdnlogin.h"
|
||||
|
||||
extern global_t global;
|
||||
extern cfg_t cfg;
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
int capi_event( int fd )
|
||||
{
|
||||
int info;
|
||||
int lcause;
|
||||
unsigned long ident;
|
||||
unsigned char proto[1024];
|
||||
unsigned char data[4096];
|
||||
union CAPI_primitives *capi;
|
||||
call_t *ptrCall;
|
||||
|
||||
lcause = capi2_get_message( fd, &capi,
|
||||
(union CAPI_primitives *)proto, data, sizeof(data));
|
||||
|
||||
/*
|
||||
* check for errors
|
||||
*/
|
||||
switch (lcause) {
|
||||
case CAPI2_E_MSG_QUEUE_EMPTY: return 0;
|
||||
case CAPI2_E_INTERNAL_BUSY_CONDITION:
|
||||
case CAPI2_E_ILLEGAL_APPLICATION:
|
||||
case CAPI2_E_OS_RESOURCE_ERROR:
|
||||
/* error occured, stop working */
|
||||
global.endloop = E_CapiError;
|
||||
return -1;
|
||||
default: break;
|
||||
}
|
||||
|
||||
info = getCapiInfo(capi);
|
||||
if (info) {
|
||||
/* TODO: some special output function for local output */
|
||||
capi2_perror("\nCAPI Info", info);
|
||||
}
|
||||
|
||||
/*
|
||||
* get the call structure
|
||||
*/
|
||||
ident = GET_c2IDENT(capi);
|
||||
#if 0
|
||||
ptrCall = getCallbyIdent( ident);
|
||||
printf("CAPI: 0x%08x 0x%08x\n", ident, GET_PRIMTYPE(capi));
|
||||
#endif
|
||||
ptrCall = global.calls;
|
||||
|
||||
|
||||
switch (GET_PRIMTYPE(capi)) {
|
||||
case CAPI2_LISTEN_CONF:
|
||||
break;
|
||||
|
||||
case CAPI2_CONNECT_CONF:
|
||||
#if 0
|
||||
ptrCall = getCallbyMessid(GET_MESSID(capi));
|
||||
#endif
|
||||
if (ptrCall) {
|
||||
ptrCall->ident = ident;
|
||||
if (info) { /* CONNECT_REQ failed -> end program */
|
||||
global.endloop = E_ConnectFailed;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CAPI2_INFO_IND:
|
||||
capi2_info_resp( fd, GET_MESSID(capi), ident);
|
||||
if (ptrCall) {
|
||||
handleInfoInd( ptrCall,
|
||||
GET_WORD(capi->c2info_ind.info),
|
||||
(struct userdata *)&capi->c2info_ind.structlen);
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case CAPI2_CONNECT_IND:
|
||||
if (ptrCall) {
|
||||
capi2_connect_resp( fd,
|
||||
(unsigned short)GET_MESSID(capi),
|
||||
ident,
|
||||
0, /* accept */
|
||||
&ptrCall->Bprotocol,
|
||||
NULL, /* cad */
|
||||
NULL, /* csa */
|
||||
NULL, /* llc */
|
||||
NULL); /* add */
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case CAPI2_CONNECTACTIVE_IND:
|
||||
if (cfg.verbose>8) {
|
||||
printf("CAPI2_CONNECTACTIVE_IND %lx\n", ident);
|
||||
}
|
||||
capi2_connectactive_resp( fd, GET_MESSID(capi), ident);
|
||||
if (ptrCall) {
|
||||
NEWSTATE( ptrCall, D_Connected);
|
||||
if (ptrCall->active) {
|
||||
NEWSTATE( ptrCall, B_ConnectPending);
|
||||
capi2_connectb3_req( fd, ident, NULL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CAPI2_CONNECTB3_CONF:
|
||||
#if 0
|
||||
ptrCall = getCallbyPlci( ident & 0xffff );
|
||||
#endif
|
||||
if (ptrCall) {
|
||||
/*
|
||||
* NCCI allocation -> store NCCI for later use
|
||||
*/
|
||||
ptrCall->ident = ident;
|
||||
}
|
||||
break;
|
||||
|
||||
case CAPI2_CONNECTB3ACTIVE_IND:
|
||||
capi2_connectb3active_resp( fd, GET_MESSID(capi), ident);
|
||||
if (ptrCall) {
|
||||
NEWSTATE( ptrCall, Connected);
|
||||
handleConnectB3ActiveInd( ptrCall );
|
||||
}
|
||||
break;
|
||||
|
||||
case CAPI2_DATAB3_CONF:
|
||||
if (ptrCall) {
|
||||
handleDataB3Conf( ptrCall,
|
||||
GET_MESSID(capi),
|
||||
GET_WORD(capi->c2datab3_conf.handle));
|
||||
}
|
||||
break;
|
||||
|
||||
case CAPI2_DATAB3_IND:
|
||||
if (ptrCall) {
|
||||
if (handleDataB3Ind( ptrCall,
|
||||
GET_MESSID(capi),
|
||||
(char *)GET_DWORD(capi->c2datab3_ind.dataptr),
|
||||
GET_WORD( capi->c2datab3_ind.datalen),
|
||||
GET_WORD( capi->c2datab3_ind.handle),
|
||||
GET_WORD( capi->c2datab3_ind.flags))) {
|
||||
capi2_datab3_resp( fd,
|
||||
GET_MESSID(capi),
|
||||
ident,
|
||||
GET_WORD(capi->c2datab3_ind.handle));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CAPI2_DISCONNECTB3_IND:
|
||||
if (ptrCall) {
|
||||
NEWSTATE( ptrCall, B_DisconnectPending);
|
||||
handleDisconnectB3Ind( ptrCall,
|
||||
GET_WORD(capi->c2disconnectb3_ind.reason_b3),
|
||||
(struct userdata *)&capi->c2disconnectb3_ind.structlen);
|
||||
}
|
||||
capi2_disconnectb3_resp( fd,
|
||||
GET_MESSID(capi),
|
||||
ident);
|
||||
if (ptrCall) NEWSTATE( ptrCall, D_DisconnectPending);
|
||||
capi2_disconnect_req( fd,
|
||||
ident & 0xffff,
|
||||
NULL);
|
||||
break;
|
||||
|
||||
case CAPI2_DISCONNECT_IND:
|
||||
capi2_disconnect_resp( fd,
|
||||
GET_MESSID(capi),
|
||||
ident);
|
||||
|
||||
if (ptrCall) {
|
||||
NEWSTATE( ptrCall, Disconnected);
|
||||
handleDisconnectInd( ptrCall,
|
||||
GET_WORD(capi->c2disconnect_ind.reason));
|
||||
|
||||
}
|
||||
global.endloop = E_Disconnected;
|
||||
break;
|
||||
case CAPI_CONTROL_CONF:
|
||||
/* decrement alive pendings */
|
||||
global.alive_pending--;
|
||||
break;
|
||||
case CAPI2_ALERT_CONF:
|
||||
case CAPI2_INFO_CONF:
|
||||
case CAPI2_DISCONNECTB3_CONF:
|
||||
case CAPI2_DISCONNECT_CONF:
|
||||
case CAPI2_FACILITY_CONF:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,112 @@
|
||||
#include "isdnlogin.h"
|
||||
|
||||
extern global_t global;
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
int pollset( fd, events, func)
|
||||
int fd;
|
||||
int events;
|
||||
int (*func)PROTO((int));
|
||||
{
|
||||
int i;
|
||||
struct pollfd *pfp;
|
||||
pollag_t *pap;
|
||||
|
||||
if (global.npollfds >= MAX_FD) return -1;
|
||||
|
||||
for (i=0, pfp=global.pollfds, pap=global.pollags;
|
||||
i < global.npollfds;
|
||||
++i, ++pfp, ++pap)
|
||||
{
|
||||
if (pfp->fd == fd && pfp->events == events) break;
|
||||
}
|
||||
if ( i < global.npollfds) {
|
||||
printf("poll already set !!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pfp = global.pollfds + global.npollfds;
|
||||
pap = global.pollags + global.npollfds;
|
||||
|
||||
pfp->fd = fd;
|
||||
pfp->events = events;
|
||||
pfp->revents = 0;
|
||||
if (poll(pfp, 1, 0) == -1) return -1;
|
||||
|
||||
pap->func = func;
|
||||
|
||||
global.npollfds ++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
int pollloopt(t)
|
||||
long t;
|
||||
{
|
||||
struct pollfd *pfp;
|
||||
pollag_t *pap;
|
||||
int i;
|
||||
int fds;
|
||||
int donefds;
|
||||
|
||||
while (global.npollfds > 0) {
|
||||
fds = poll(global.pollfds, global.npollfds, t);
|
||||
switch (fds) {
|
||||
case -1:
|
||||
if (errno == EINTR) continue;
|
||||
if (errno == EAGAIN) continue;
|
||||
return -1;
|
||||
case 0:
|
||||
return 0;
|
||||
default:
|
||||
pfp = global.pollfds;
|
||||
pap = global.pollags;
|
||||
donefds = 0;
|
||||
for (i=0; i < global.npollfds; ++i, ++pfp, ++pap) {
|
||||
if (pfp->revents) {
|
||||
(*pap->func)(pfp->fd);
|
||||
pfp->revents = 0;
|
||||
donefds++;
|
||||
}
|
||||
}
|
||||
return donefds;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
int mypolldel(fd)
|
||||
int fd;
|
||||
{
|
||||
struct pollfd *pfp;
|
||||
pollag_t *pap;
|
||||
int i;
|
||||
|
||||
for (i=0, pfp=global.pollfds, pap=global.pollags;
|
||||
i < global.npollfds;
|
||||
++i, ++pfp, ++pap) {
|
||||
if (pfp->fd == fd) break;
|
||||
}
|
||||
|
||||
if (i >= global.npollfds) {
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (++i, ++pfp, ++pap; i < global.npollfds; ++i, ++pfp, ++pap) {
|
||||
pfp[-1] = pfp[0];
|
||||
pap[-1] = pap[0];
|
||||
}
|
||||
global.npollfds --;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,80 @@
|
||||
#include "isdnlogin.h"
|
||||
|
||||
extern global_t global;
|
||||
extern cfg_t cfg;
|
||||
extern char *name;
|
||||
extern char *prog_logo;
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
int my_kill(void)
|
||||
{
|
||||
call_t *ptrCall = NULL;
|
||||
|
||||
/* restore terminal settings */
|
||||
reset_terminal();
|
||||
|
||||
mypolldel( STDIN );
|
||||
|
||||
ptrCall = global.calls;
|
||||
if ( ptrCall ) {
|
||||
free_call( ptrCall );
|
||||
mypolldel( ptrCall->capi_fd );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
void catch_signal( int signo )
|
||||
{
|
||||
switch (signo) {
|
||||
case SIGHUP:
|
||||
check_capi();
|
||||
break;
|
||||
default:
|
||||
if (signo) fprintf( stderr, "\ngot signal (%d)\n", signo);
|
||||
exit ( 1 );
|
||||
}
|
||||
}
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
/*******************************************************************
|
||||
*
|
||||
*******************************************************************/
|
||||
int init_program( int argc, char **argv )
|
||||
{
|
||||
name = argv[0];
|
||||
printf("%s\n", prog_logo);
|
||||
|
||||
global.endloop = 0;
|
||||
global.calls = NULL;
|
||||
|
||||
/* store the actual terminal settings */
|
||||
tcgetattr(0, &(global.oldtermopts));
|
||||
|
||||
/* output completely unbuffered */
|
||||
setbuf(stdout, NULL);
|
||||
setbuf(stderr, NULL);
|
||||
setbuf(stdin, NULL);
|
||||
|
||||
#ifdef __STDC__
|
||||
atexit( my_exit );
|
||||
#else
|
||||
on_exit( my_exit, 0);
|
||||
#endif
|
||||
signal(SIGHUP, catch_signal);
|
||||
signal(SIGINT, catch_signal);
|
||||
signal(SIGQUIT, catch_signal);
|
||||
signal(SIGKILL, catch_signal);
|
||||
signal(SIGTERM, catch_signal);
|
||||
signal(SIGUSR1, catch_signal);
|
||||
signal(SIGUSR2, catch_signal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,160 @@
|
||||
#include "isdnlogin.h"
|
||||
|
||||
extern global_t global;
|
||||
|
||||
int tty_event(int fd)
|
||||
{
|
||||
size_t len;
|
||||
call_t *ptrCall = global.calls;
|
||||
static unsigned short usDataHandle;
|
||||
char out[REG_CAPI_DATA_BLK_SIZE+1];
|
||||
char *c = &out[1];
|
||||
|
||||
len = read(fd, c, sizeof(out));
|
||||
/* check for read errors */
|
||||
if (len <=0) {
|
||||
switch(errno) {
|
||||
case EBADF:
|
||||
printf("read: bad filedescriptor!\n");
|
||||
return 0;
|
||||
case EFAULT:
|
||||
printf("read: Buf points outside the allocated address space.\n");
|
||||
return 0;
|
||||
case EIO:
|
||||
printf("read: An I/O error occurred while reading from the file system.\n");
|
||||
return 0;
|
||||
case EINTR:
|
||||
printf("read: interrupted!\n");
|
||||
return 0;
|
||||
case EINVAL:
|
||||
printf("read: The pointer associated with d was negative.\n");
|
||||
return 0;
|
||||
case EAGAIN:
|
||||
printf("read: no data to read.\n");
|
||||
return 0;
|
||||
default:
|
||||
printf("got read error = %d\n", len);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (TTYS_ESCAPE_RECV == global.tty_state) {
|
||||
switch (*c) {
|
||||
case TERMINATE_CHAR:
|
||||
global.endloop = E_LocalTerminate;
|
||||
break;
|
||||
#if WITH_UNFINISHED_XMODEM
|
||||
case SENDFILE_CHAR:
|
||||
/* this feature is not really working now, the first shot
|
||||
* showed that it's much too slow for ISDN connections. So
|
||||
* maybe i will never implement this. Also the prompt()
|
||||
* feature breaks keepalive feature. readbyte() in xmodem.c
|
||||
* won't work on other messages than DATAB3_IND, so a
|
||||
* disconnect while in transfer will be ignored. Feel free to
|
||||
* integrate this feature */
|
||||
if (ptrCall) {
|
||||
/* send first data now */
|
||||
/* TODO: to be implemented here using prompt() function */
|
||||
|
||||
char buf[256];
|
||||
prompt("Local file name? ", buf, sizeof(buf));
|
||||
printf("buf=%s\n", buf);
|
||||
|
||||
ptrCall->xmodem = xmodem_open( ptrCall, 115200, 1, ptrCall->error_msg,
|
||||
buf);
|
||||
while ( SendXmodemData(ptrCall) );
|
||||
|
||||
if (ptrCall->error_msg) printf("XMODEM error: %s\n", ptrCall->error_msg);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
/* nothing */
|
||||
len++;
|
||||
out[0] = ESCAPE_CHAR;
|
||||
c = &out[0];
|
||||
break;
|
||||
|
||||
}
|
||||
global.tty_state = TTYS_ESCAPE_WAITFOR;
|
||||
} else if (ESCAPE_CHAR == *c) {
|
||||
/* eat the tilde */
|
||||
global.tty_state = TTYS_ESCAPE_RECV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* send data if in right state */
|
||||
if ((ptrCall) && ptrCall->state == Connected) {
|
||||
ptrCall->NotAcknowledged++; /* count pending confirms */
|
||||
|
||||
usDataHandle++;
|
||||
capi2_datab3_req( ptrCall->capi_fd,
|
||||
ptrCall->ident,
|
||||
c,
|
||||
len,
|
||||
0,
|
||||
usDataHandle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* copied from /usr/src/lib/libc/gen/termios.c of FreeBSD because this
|
||||
* is no POSIX compatible function and not available on any OS such as
|
||||
* HP-UX or Solaris */
|
||||
|
||||
/*
|
||||
* Make a pre-existing termios structure into "raw" mode: character-at-a-time
|
||||
* mode with no characters interpreted, 8-bit data path.
|
||||
*/
|
||||
void mymakeraw(struct termios *t)
|
||||
{
|
||||
t->c_iflag &= ~(IMAXBEL|IXOFF|INPCK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IGNPAR);
|
||||
t->c_iflag |= IGNBRK;
|
||||
t->c_oflag &= ~OPOST;
|
||||
t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN|NOFLSH|TOSTOP|PENDIN);
|
||||
t->c_cflag &= ~(CSIZE|PARENB);
|
||||
t->c_cflag |= CS8|CREAD;
|
||||
t->c_cc[VMIN] = 1;
|
||||
t->c_cc[VTIME] = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void reset_terminal(void) {
|
||||
/* restore old terminal opts */
|
||||
tcsetattr(0,TCSANOW, &(global.oldtermopts));
|
||||
}
|
||||
|
||||
void set_raw_terminal(void) {
|
||||
struct termios scheisse;
|
||||
|
||||
/* set terminal to raw mode */
|
||||
memcpy(&scheisse, &(global.oldtermopts), sizeof(scheisse));
|
||||
mymakeraw(&scheisse);
|
||||
tcsetattr(0,TCSANOW, &scheisse);
|
||||
}
|
||||
|
||||
void prompt(char *promptmsg, char *inputbuf, size_t buf_len)
|
||||
{
|
||||
char *bufptr = inputbuf;
|
||||
|
||||
reset_terminal();
|
||||
mypolldel(STDIN);
|
||||
|
||||
printf("%s", promptmsg);
|
||||
while ((*bufptr = getchar())) {
|
||||
if (*bufptr == '\n') break;
|
||||
if (buf_len-- <= 0) break;
|
||||
|
||||
//printf("bufptr=%c buf_len=%d\n", *bufptr, buf_len);
|
||||
bufptr++;
|
||||
}
|
||||
*bufptr = '\0';
|
||||
|
||||
//printf("end of conversation\n");
|
||||
pollset( STDIN, POLLIN, tty_event);
|
||||
set_raw_terminal();
|
||||
}
|
@ -0,0 +1,328 @@
|
||||
/************************************************************************
|
||||
* (C)opyright 1991-1999 Andre Ilie, All Rights Reserved
|
||||
*
|
||||
* Title: <one line description>
|
||||
* Author: <username>
|
||||
* $RCSfile: isdnlogin.c,v $
|
||||
* $Revision: 74 $
|
||||
* $Date: 2005-12-22 01:06:50 +0100 (Thu, 22 Dec 2005) $
|
||||
* $State: Exp $
|
||||
*
|
||||
* Type: streams driver/module | application | library
|
||||
* Products: ALL | XS,XM,XL,XP,BGO,BGP,XCM
|
||||
* Interfaces: IPI, DLPI
|
||||
* Libraries: -
|
||||
* Switches: -
|
||||
* Description: --
|
||||
*-----------------------------------------------------------------------
|
||||
* Current Log:
|
||||
* -
|
||||
***********************************************************************/
|
||||
|
||||
#include "isdnlogin.h"
|
||||
|
||||
/**********************************
|
||||
* global variables
|
||||
**********************************/
|
||||
const char * name = NULL;
|
||||
const char * prog_logo = "BIANCA/CAPI ISDN Login Client 1.51 by Andrei Ilie <bender@duese.org>";
|
||||
const char * rcs_id_isdnlogin_c = "$Id: isdnlogin.c,v 1.52 2003/07/30 12:14:36 shoki Exp $";
|
||||
|
||||
global_t global; /* global program data */
|
||||
|
||||
cfg_t cfg = {
|
||||
"", /* remote telno */
|
||||
"+49 911 12345678", /* local telno */
|
||||
"", /* remote subaddr */
|
||||
"", /* local subaddr */
|
||||
DEFAULT_VERBOSE_LEVEL, /* verbose mode */
|
||||
38400, /* maximum speed */
|
||||
#if WITH_RCAPI_LAYER
|
||||
{ CAPI_HOST_DEFAULT, NULL, 0 },
|
||||
/* capi host info */
|
||||
{ CAPI_USER_DEFAULT, NULL },
|
||||
/* capi auth info */
|
||||
#endif
|
||||
1, /* controller */
|
||||
-1, /* b-channel number */
|
||||
0, /* store start time */
|
||||
0, /* store end time */
|
||||
REG_WINDOW_SIZE, /* Window Size */
|
||||
DEFAULT_WAIT4DATACONF, /* flag */
|
||||
NULL, /* service */
|
||||
0, /* v110_rate */
|
||||
NULL /* file to send */
|
||||
};
|
||||
|
||||
|
||||
/* for service specific parameters */
|
||||
static service_t service[] = {
|
||||
/* name cip rate hw speed layer1_mask */
|
||||
{ "data", CIP_DATA, 0, ISDN_HDLC, 0, B1HDLC },
|
||||
{ "telephony", CIP_PHONE, 0, ISDN_HDLC, 0, B1HDLC },
|
||||
/* TODO: check this out... don't know if it works
|
||||
{ "faxg3", CIP_FAXG3, 0, FAX_G3, 14400, B1FAXG3 },
|
||||
{ "faxg4", CIP_FAXG4, 0, ISDN_HDLC, 0, B1HDLC },
|
||||
{ "t_online", CIP_BTX, 0, ISDN_HDLC, 0, B1HDLC },
|
||||
{ "datex_j", CIP_BTX, |