initial import from svn
This commit is contained in:
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, 0, ISDN_HDLC, 0, B1HDLC },
|
||||||
|
{ "btx", CIP_BTX, 0, ISDN_HDLC, 0, B1HDLC },
|
||||||
|
{ "v120", CIP_DATA, 0xb9, ISDN_HDLC, 56000, B1HDLC56 },
|
||||||
|
{ "56k", CIP_DATA, 0, ISDN_HDLC, 56000, B1HDLC56 },
|
||||||
|
*/
|
||||||
|
{ "modem", CIP_3KAUDIO,0, MODEM, 0, B1MODEMASYNC },
|
||||||
|
{ "trans", CIP_DATA, 0, TRANS, 0, B1TRANS },
|
||||||
|
{ "compr", CIP_DATA, 0, ISDN_V42, 0, B1HDLC },
|
||||||
|
{ "v110", CIP_DATA, 0x4d, V110_ASYNC, 38400, B1V110TRANS },
|
||||||
|
{ "", 0, 0, 0, 0, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __STDC__
|
||||||
|
void my_exit( void )
|
||||||
|
#else
|
||||||
|
void my_exit( func, arg)
|
||||||
|
int *func;
|
||||||
|
caddr_t arg;
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
my_kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
*
|
||||||
|
*******************************************************************/
|
||||||
|
int usage( void )
|
||||||
|
{
|
||||||
|
service_t *sv;
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
fprintf( stderr, "\nUsage: %s [-%s] <#phone> [service]\n", name,
|
||||||
|
CMD_LINE_ARGS);
|
||||||
|
fprintf( stderr, "\tOptions:\n");
|
||||||
|
#if WITH_RCAPI_LAYER
|
||||||
|
fprintf( stderr, "\t-b: specify remote CAPI host\n");
|
||||||
|
fprintf( stderr, "\t-P: specify remote CAPI port\n");
|
||||||
|
fprintf( stderr, "\t-u: specify remote CAPI user\n");
|
||||||
|
fprintf( stderr, "\t-p: specify remote CAPI password\n");
|
||||||
|
#endif
|
||||||
|
fprintf( stderr, "\t-l: specify local phone number\n");
|
||||||
|
fprintf( stderr, "\t-s: specify maximum transfer speed in bps\n");
|
||||||
|
fprintf( stderr, "\t-c: specify ISDN controller to use [1..n]\n");
|
||||||
|
fprintf( stderr, "\t-q: use quiet mode\n");
|
||||||
|
fprintf( stderr, "\t-C: specify file to send after dialin (autologin)\n");
|
||||||
|
fprintf( stderr, "\t-v: specify verbose level (default=%d)\n",
|
||||||
|
DEFAULT_VERBOSE_LEVEL);
|
||||||
|
fprintf( stderr, "\t-w: specify data window size (default=%d)\n",
|
||||||
|
REG_WINDOW_SIZE);
|
||||||
|
fprintf( stderr, "\t-W: wait for DATAB3_CONF before DISCONNECTB3_REQ (default=%d)\n",
|
||||||
|
DEFAULT_WAIT4DATACONF);
|
||||||
|
|
||||||
|
fprintf( stderr, "\nServices:\n\t" );
|
||||||
|
for (sv = service; *sv->name; sv++) {
|
||||||
|
fprintf(stderr, "%s ", sv->name);
|
||||||
|
if (!(i++%6)) fprintf(stderr, "\n\t");
|
||||||
|
}
|
||||||
|
fprintf( stderr, "\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_service(char *serv)
|
||||||
|
{
|
||||||
|
service_t *sv;
|
||||||
|
|
||||||
|
cfg.service = service; /* default service is the frist one */
|
||||||
|
|
||||||
|
/* get or guess service type */
|
||||||
|
if (serv != NULL) {
|
||||||
|
for (sv = service; *sv->name; sv++) {
|
||||||
|
if (!strncmp( serv, sv->name, strlen(serv))) {
|
||||||
|
/* got service in table, save pointer to it */
|
||||||
|
cfg.service = sv;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!*sv->name) {
|
||||||
|
fprintf( stderr, "Service '%s' not found, using '%s'.\n",
|
||||||
|
serv, cfg.service->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_speed(void)
|
||||||
|
{
|
||||||
|
/* adjust speed setting */
|
||||||
|
switch (cfg.speed) {
|
||||||
|
/* speed is in range */
|
||||||
|
case 1200: cfg.v110_speed = 0x42; break;
|
||||||
|
case 2400: cfg.v110_speed = 0x43; break;
|
||||||
|
case 4800: cfg.v110_speed = 0x45; break;
|
||||||
|
case 9600: cfg.v110_speed = 0x48; break;
|
||||||
|
case 14400: cfg.v110_speed = 0x49; break; /* XXX: broken */
|
||||||
|
case 19200: cfg.v110_speed = 0x4b; break;
|
||||||
|
case 38400: cfg.v110_speed = 0x4d; break;
|
||||||
|
default:
|
||||||
|
/* if service specific max speed given use this */
|
||||||
|
printf("Invalid speed setting %d bps! ", cfg.speed);
|
||||||
|
if (cfg.service->speed) {
|
||||||
|
cfg.speed = cfg.service->speed;
|
||||||
|
cfg.v110_speed = cfg.service->rate;
|
||||||
|
} else {
|
||||||
|
cfg.speed = 1200; /* min rate */
|
||||||
|
cfg.v110_speed = 0x42;
|
||||||
|
}
|
||||||
|
printf("Speed set to %d bps\n", cfg.speed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int exit_handler (exit_t type)
|
||||||
|
{
|
||||||
|
int exitval;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case E_LocalTerminate:
|
||||||
|
printf("Local terminate requested.\n");
|
||||||
|
exitval = 0;
|
||||||
|
break;
|
||||||
|
case E_KeepAliveFailed:
|
||||||
|
printf( "CAPI keepalive failed (%d pending)!\n" ,
|
||||||
|
global.alive_pending);
|
||||||
|
exitval = 1;
|
||||||
|
break;
|
||||||
|
case E_ConnectFailed:
|
||||||
|
printf("Could not connect to remote system!\n");
|
||||||
|
exitval = 1;
|
||||||
|
break;
|
||||||
|
case E_CapiError:
|
||||||
|
printf("Got fatal CAPI error!\n");
|
||||||
|
exitval = 1;
|
||||||
|
break;
|
||||||
|
case E_PollError:
|
||||||
|
printf("Got fatal poll error!\n");
|
||||||
|
exitval = 1;
|
||||||
|
break;
|
||||||
|
case E_Disconnected:
|
||||||
|
exitval = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
exitval = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (exitval);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_options (int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
extern int optind;
|
||||||
|
extern char *optarg;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get options
|
||||||
|
*/
|
||||||
|
while ((i = getopt( argc, argv, CMD_LINE_ARGS )) != EOF) switch (i) {
|
||||||
|
case 'l': strncpy( cfg.loctelno, optarg, sizeof(cfg.loctelno)); break;
|
||||||
|
#if WITH_RCAPI_LAYER
|
||||||
|
case 'b': cfg.capi_host.hostname = strdup(optarg); break;
|
||||||
|
case 'P': cfg.capi_host.port = atoi(optarg); break;
|
||||||
|
case 'u': cfg.capi_auth.user = strdup(optarg); break;
|
||||||
|
case 'p': cfg.capi_auth.passwd = strdup(optarg); break;
|
||||||
|
#endif
|
||||||
|
case 'c': cfg.controller = atoi(optarg); break;
|
||||||
|
case 's': cfg.speed = atoi(optarg); break;
|
||||||
|
case 'q': cfg.verbose = 0; break;
|
||||||
|
case 'v': cfg.verbose = atoi(optarg); break;
|
||||||
|
case 'C': cfg.sendfile = strdup(optarg); break;
|
||||||
|
case 'w': cfg.usWindowSize = atoi(optarg); break;
|
||||||
|
case 'W': cfg.wait4dataconf = atoi(optarg); break;
|
||||||
|
case '?':
|
||||||
|
case 'h':
|
||||||
|
default: usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc) {
|
||||||
|
strncpy( cfg.rmttelno, argv[optind++], sizeof(cfg.rmttelno));
|
||||||
|
} else {
|
||||||
|
usage();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
*
|
||||||
|
*******************************************************************/
|
||||||
|
int main( int argc, char **argv )
|
||||||
|
{
|
||||||
|
call_t *ptrCall;
|
||||||
|
int ret;
|
||||||
|
#if CHECK_CAPI
|
||||||
|
int timeout = KEEP_ALIVE_TIMER;
|
||||||
|
#else
|
||||||
|
int timeout = -1; /* inifinite poll */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
init_program(argc, argv);
|
||||||
|
if (get_options(argc, argv)) exit(1);
|
||||||
|
|
||||||
|
/* service specific settings */
|
||||||
|
get_service(argv[optind]);
|
||||||
|
set_speed();
|
||||||
|
|
||||||
|
/* CAPI stuff */
|
||||||
|
if (get_capi_info()) exit( 1 );
|
||||||
|
|
||||||
|
/* allocate first call instance */
|
||||||
|
ptrCall = alloc_call();
|
||||||
|
global.calls = ptrCall;
|
||||||
|
if (!ptrCall) {
|
||||||
|
fprintf( stderr, "failed to allocate call!\n");
|
||||||
|
exit ( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do register */
|
||||||
|
ptrCall->capi_fd = init_capi();
|
||||||
|
if (ptrCall->capi_fd <= 0) {
|
||||||
|
exit ( 1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// For server mode
|
||||||
|
//setListen(ptrCall, ptrCall->service->cip);
|
||||||
|
|
||||||
|
printf("Trying...\n");
|
||||||
|
doConnect( ptrCall );
|
||||||
|
|
||||||
|
/* poll on STDIN for incoming packets */
|
||||||
|
pollset( STDIN, POLLIN, tty_event);
|
||||||
|
|
||||||
|
/* poll on capi for incoming packets */
|
||||||
|
pollset( ptrCall->capi_fd, POLLIN, capi_event);
|
||||||
|
|
||||||
|
/* poll fds for incoming packets and handel them */
|
||||||
|
while (!global.endloop) {
|
||||||
|
ret = pollloopt(timeout);
|
||||||
|
switch(ret) {
|
||||||
|
case -1:
|
||||||
|
/* poll error */
|
||||||
|
global.endloop = E_PollError;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
/* got timeout */
|
||||||
|
#if CHECK_CAPI
|
||||||
|
/* check capi when we have time for it */
|
||||||
|
check_capi();
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* did some work on fds */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reset terminal to unraw mode and output failure messages */
|
||||||
|
reset_terminal();
|
||||||
|
|
||||||
|
exit(exit_handler(global.endloop));
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,266 @@
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/ioctl.h> /* for tcsetattr */
|
||||||
|
#include <termios.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <libcapi.h> /* for the fucking types CONST &&& */
|
||||||
|
|
||||||
|
#include "xmodem.h"
|
||||||
|
|
||||||
|
#define DEBUG 0
|
||||||
|
|
||||||
|
#define STDIN fileno(stdin)
|
||||||
|
#define STDOUT fileno(stdout)
|
||||||
|
|
||||||
|
#define CAPI_HOST_DEFAULT "struppi.dev.bintec.de"
|
||||||
|
#define CAPI_USER_DEFAULT "default"
|
||||||
|
|
||||||
|
#define MAX_FD 64
|
||||||
|
#define CMD_LINE_ARGS "?hqC:l:c:s:w:W:v:b:p:u:P:"
|
||||||
|
|
||||||
|
#define DEFAULT_VERBOSE_LEVEL 2
|
||||||
|
#define DEFAULT_WAIT4DATACONF 0 /* flag */
|
||||||
|
#define REGISTER_FAIL_TIMER 30 /* seconds */
|
||||||
|
|
||||||
|
#define CHECK_CAPI 1 /* keepalive capi and indicate broken connection */
|
||||||
|
#define MAX_KEEPALIVE_PENDING 0
|
||||||
|
#define KEEP_ALIVE_TIMER 5*1000 /* milliseconds */
|
||||||
|
|
||||||
|
#define LOGIN_SCRIPT_LINE_BY_LINE 0 /* send each login script line
|
||||||
|
* in one data_ind instead of
|
||||||
|
* block based sending
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define WITH_UNFINISHED_XMODEM 0 /* enable/disable Xmodem upload feature
|
||||||
|
* (*broken*)
|
||||||
|
*/
|
||||||
|
#define WITH_RCAPI_LAYER 0 /* enable/disbale using of rcapi functions
|
||||||
|
* which allow to pass a
|
||||||
|
* hostname and user to the
|
||||||
|
* capi. the problem is that
|
||||||
|
* the code is still buggy and
|
||||||
|
* won't work always */
|
||||||
|
|
||||||
|
/* tty stories */
|
||||||
|
#define TTYS_ESCAPE_WAITFOR 0
|
||||||
|
#define TTYS_ESCAPE_RECV 1
|
||||||
|
#define ESCAPE_CHAR '~'
|
||||||
|
#define TERMINATE_CHAR '.'
|
||||||
|
#define SENDFILE_CHAR '>'
|
||||||
|
|
||||||
|
#define MAX_CMD_SIZE 256
|
||||||
|
#define NEWSTATE( ptrCall, newstate) (ptrCall)->state = newstate;
|
||||||
|
|
||||||
|
#define REG_CAPI_MSG_SIZE 1024
|
||||||
|
#define REG_CAPI_LEVEL3CNT 1
|
||||||
|
#define REG_CAPI_DATA_BLK_SIZE 1400 /* mtu=1500-(tcp+capi)header */
|
||||||
|
#define REG_WINDOW_SIZE 7 /* TODO with 10 fax aborts */
|
||||||
|
|
||||||
|
#define ISDN_HDLC 0 /* ISDN HDLC service mode */
|
||||||
|
#define V110_ASYNC 1 /* V.110 Async service */
|
||||||
|
#define TRANS 4 /* transparent */
|
||||||
|
#define MODEM 5 /* modem service */
|
||||||
|
#define FAX_G3 6 /* FAX group 3 */
|
||||||
|
#define ISDN_V42 7 /* HDLC X.75 with V.42bis */
|
||||||
|
|
||||||
|
#define CIP_DATA 2
|
||||||
|
#define CIP_PHONE 1
|
||||||
|
#define CIP_3KAUDIO 4
|
||||||
|
#define CIP_FAXG3 17
|
||||||
|
#define CIP_FAXG4 18
|
||||||
|
#define CIP_BTX 20 /* not sure about this */
|
||||||
|
|
||||||
|
#define TRUE 1
|
||||||
|
#define FALSE 0
|
||||||
|
|
||||||
|
#undef max
|
||||||
|
#undef min
|
||||||
|
#define max(a,b) (((a)>(b))?(a):(b))
|
||||||
|
#define min(a,b) (((a)<(b))?(a):(b))
|
||||||
|
|
||||||
|
/* exit states */
|
||||||
|
enum exit_e {
|
||||||
|
E_LocalTerminate = 1,
|
||||||
|
E_KeepAliveFailed,
|
||||||
|
E_ConnectFailed,
|
||||||
|
E_CapiError,
|
||||||
|
E_PollError,
|
||||||
|
E_Disconnected
|
||||||
|
};
|
||||||
|
typedef enum exit_e exit_t;
|
||||||
|
|
||||||
|
/* call states */
|
||||||
|
enum state_e {
|
||||||
|
Disconnected,
|
||||||
|
D_ConnectPending,
|
||||||
|
D_Connected,
|
||||||
|
B_ConnectPending,
|
||||||
|
Connected,
|
||||||
|
B_DisconnectPending,
|
||||||
|
D_DisconnectPending,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* store services here */
|
||||||
|
typedef struct service_s service_t ;
|
||||||
|
struct service_s {
|
||||||
|
const char *name;
|
||||||
|
unsigned char cip, rate, hw;
|
||||||
|
int speed;
|
||||||
|
int layer1_mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**********************************
|
||||||
|
* call specific data
|
||||||
|
**********************************/
|
||||||
|
typedef struct call_s call_t;
|
||||||
|
struct call_s {
|
||||||
|
call_t *next;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* name and handle for file to transmit
|
||||||
|
*/
|
||||||
|
CONST char *pFilename;
|
||||||
|
FILE *txfp;
|
||||||
|
|
||||||
|
/* for Xmodem sending */
|
||||||
|
xmodem_t *xmodem;
|
||||||
|
char error_msg[80]; /* xmodem error message buffer */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* static configuration data
|
||||||
|
*/
|
||||||
|
struct userdata CallingPartyNumber;
|
||||||
|
struct userdata CalledPartyNumber;
|
||||||
|
struct userdata CallingPartySubaddress;
|
||||||
|
struct userdata CalledPartySubaddress;
|
||||||
|
struct userdata Bprotocol;
|
||||||
|
|
||||||
|
/* service specfic configuration */
|
||||||
|
service_t *service;
|
||||||
|
userdata_t llc;
|
||||||
|
userdata_t AdditionalInfo;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dynamic link data
|
||||||
|
*/
|
||||||
|
int capi_fd;
|
||||||
|
enum state_e state;
|
||||||
|
unsigned short messid; /* message number */
|
||||||
|
unsigned long ident; /* contrl, plci, ncci */
|
||||||
|
|
||||||
|
unsigned active:1; /* active, passive side */
|
||||||
|
unsigned doSend:1;
|
||||||
|
unsigned wasConnected:1;
|
||||||
|
unsigned NotAcknowledged;/* count datab3_req not ack */
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct cfg_s cfg_t;
|
||||||
|
struct cfg_s {
|
||||||
|
char rmttelno[40];
|
||||||
|
char loctelno[40];
|
||||||
|
char rmtsubaddr[40];
|
||||||
|
char locsubaddr[40];
|
||||||
|
int verbose;
|
||||||
|
int speed;
|
||||||
|
#if WITH_RCAPI_LAYER
|
||||||
|
rcapi_host_t capi_host;
|
||||||
|
rcapi_auth_t capi_auth;
|
||||||
|
#endif
|
||||||
|
int controller;
|
||||||
|
int b_channel;
|
||||||
|
time_t starttime;
|
||||||
|
time_t endtime;
|
||||||
|
unsigned short usWindowSize;
|
||||||
|
int wait4dataconf;
|
||||||
|
service_t *service;
|
||||||
|
unsigned char v110_speed;
|
||||||
|
char *sendfile;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct pollag_s pollag_t;
|
||||||
|
struct pollag_s {
|
||||||
|
int (*func)(int);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct global_s global_t;
|
||||||
|
struct global_s {
|
||||||
|
exit_t endloop;
|
||||||
|
call_t *calls;
|
||||||
|
struct termios oldtermopts;
|
||||||
|
size_t alive_pending;
|
||||||
|
int tty_state;
|
||||||
|
/* pollshiting */
|
||||||
|
int npollfds;
|
||||||
|
struct pollfd pollfds[MAX_FD];
|
||||||
|
pollag_t pollags[MAX_FD];
|
||||||
|
};
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* other call struct specific includes
|
||||||
|
*******************************************************************/
|
||||||
|
#include "xmodem.h" /* for xmodem functions */
|
||||||
|
|
||||||
|
/*******************************************************************
|
||||||
|
* local proto's
|
||||||
|
*******************************************************************/
|
||||||
|
void catch_signal (int signo);
|
||||||
|
int start_external (void);
|
||||||
|
int pollset (int fd, int events, int (*func)(int));
|
||||||
|
int pollloopt ( long t );
|
||||||
|
int mypolldel ( int fd );
|
||||||
|
call_t *alloc_call (void);
|
||||||
|
void free_call ( call_t *ptrCall );
|
||||||
|
/* TODO: replace with userdata_t */
|
||||||
|
struct userdata *setCalledPartyNumber ( call_t *ptrCall, char *szCalledPartyNumber);
|
||||||
|
struct userdata *setCallingPartyNumber ( call_t *ptrCall, char *szCallingPartyNumber, int lPresentation);
|
||||||
|
struct userdata *setCalledPartySubaddress ( call_t *ptrCall, char *szCalledPartySubaddress);
|
||||||
|
struct userdata *setCallingPartySubaddress ( call_t *ptrCall, char *szCallingPartySubaddress);
|
||||||
|
userdata_t *setBprotocol( call_t *ptrCall );
|
||||||
|
userdata_t *setLLC ( call_t *ptrCall );
|
||||||
|
userdata_t *setAdditionalInfo( call_t *ptrCall );
|
||||||
|
int setListen( call_t *ptrCall, int mask );
|
||||||
|
int getCapiInfo ( union CAPI_primitives *capi );
|
||||||
|
void doDisconnect ( call_t *ptrCall );
|
||||||
|
void doConnect ( call_t *ptrCall );
|
||||||
|
void SendData ( call_t *ptrCall );
|
||||||
|
void handleConnectB3ActiveInd ( call_t *ptrCall );
|
||||||
|
int handleDataB3Ind ( call_t *ptrCall, unsigned short messid, unsigned char *dataptr, int datalen, unsigned short handle, unsigned short flags );
|
||||||
|
void handleDataB3Conf ( call_t *ptrCall, unsigned short messid, unsigned short handle);
|
||||||
|
void handleInfoInd ( call_t *ptrCall, unsigned short infonumber, struct userdata *data);
|
||||||
|
void handleDisconnectB3Ind ( call_t *ptrCall, unsigned short nReason, struct userdata *ncpi);
|
||||||
|
void handleDisconnectInd ( call_t *ptrCall, unsigned short nReason);
|
||||||
|
int capi_event ( int fd );
|
||||||
|
int usage ( void );
|
||||||
|
int init_capi ( void);
|
||||||
|
int init_program (int argc, char **argv);
|
||||||
|
void mymakeraw (struct termios *t);
|
||||||
|
void reset_terminal (void);
|
||||||
|
void set_raw_terminal (void);
|
||||||
|
int get_capi_info (void);
|
||||||
|
int tty_event (int fd);
|
||||||
|
void prompt (char *promptmsg, char *inputbuf, size_t buf_len);
|
||||||
|
void check_capi (void);
|
||||||
|
int my_kill (void);
|
||||||
|
void get_service (char *serv);
|
||||||
|
void set_speeed (void);
|
||||||
|
int exit_handler (exit_t type);
|
||||||
|
int get_options (int argc, char **argv);
|
||||||
|
int main ( int argc, char **argv );
|
||||||
|
|
||||||
|
#if WITH_UNFINISHED_XMODEM
|
||||||
|
/* XModem stuff */
|
||||||
|
extern xmodem_t *xmodem_open(call_t *ptrCall, int baud, int one_kb, char *emsg, char *filename);
|
||||||
|
extern int xmodem_getpkt(xmodem_t *x, char *rbuf, int *lenp, char *emsg);
|
||||||
|
extern int xmodem_putpkt(xmodem_t *x, char *sbuf, int len, char *emsg);
|
||||||
|
extern void xmodem_cancel(xmodem_t *x);
|
||||||
|
extern void xmodem_close(xmodem_t *x);
|
||||||
|
extern int xmodem_onekb(xmodem_t *x);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __STDC__
|
||||||
|
void my_exit ( void );
|
||||||
|
#else
|
||||||
|
void my_exit ( int *func, caddr_t arg);
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#! /bin/sh
|
||||||
|
# mkinstalldirs --- make directory hierarchy
|
||||||
|
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
|
||||||
|
# Created: 1993-05-16
|
||||||
|
# Public domain
|
||||||
|
|
||||||
|
# $Id: mkinstalldirs,v 1.1 2002/11/08 14:53:43 shoki Exp $
|
||||||
|
|
||||||
|
errstatus=0
|
||||||
|
|
||||||
|
for file
|
||||||
|
do
|
||||||
|
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
|
||||||
|
shift
|
||||||
|
|
||||||
|
pathcomp=
|
||||||
|
for d
|
||||||
|
do
|
||||||
|
pathcomp="$pathcomp$d"
|
||||||
|
case "$pathcomp" in
|
||||||
|
-* ) pathcomp=./$pathcomp ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if test ! -d "$pathcomp"; then
|
||||||
|
echo "mkdir $pathcomp"
|
||||||
|
|
||||||
|
mkdir "$pathcomp" || lasterr=$?
|
||||||
|
|
||||||
|
if test ! -d "$pathcomp"; then
|
||||||
|
errstatus=$lasterr
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
pathcomp="$pathcomp/"
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
exit $errstatus
|
||||||
|
|
||||||
|
# mkinstalldirs ends here
|
|
@ -0,0 +1,679 @@
|
||||||
|
/************************************************************************
|
||||||
|
* (C)opyright 1991-1999 BinTec Communications AG, All Rights Reserved
|
||||||
|
*
|
||||||
|
* Title: XMODEM transfer functions
|
||||||
|
* Author: bernd
|
||||||
|
* $RCSfile: xmodem.c,v $
|
||||||
|
* $Revision: 74 $
|
||||||
|
* $Date: 2005-12-22 01:06:50 +0100 (Thu, 22 Dec 2005) $
|
||||||
|
* $State: Exp $
|
||||||
|
*
|
||||||
|
* Type: library
|
||||||
|
* Products: ALL
|
||||||
|
* Interfaces: -
|
||||||
|
* Libraries: -
|
||||||
|
* Switches: -
|
||||||
|
* Description: --
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* Current Log:
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#ifdef USE_RCSID_C
|
||||||
|
static const char _rcsid_xmodem_c[] __UNUSED = "$Id: xmodem.c,v 1.2 2003/07/30 11:26:56 shoki Exp $";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if WITH_UNFINISHED_XMODEM
|
||||||
|
|
||||||
|
#include "isdnlogin.h"
|
||||||
|
|
||||||
|
#define TRACE printf
|
||||||
|
static void trace(const char *fmt, ...)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CRC-16 constant array... from Usenet contribution by Mark G. Mendel,
|
||||||
|
* Network Systems Corp. (ihnp4!umn-cs!hyper!mark)
|
||||||
|
*/
|
||||||
|
static unsigned short crctab[1 << B] = {
|
||||||
|
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
|
||||||
|
0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
|
||||||
|
0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
|
||||||
|
0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
|
||||||
|
0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
|
||||||
|
0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
|
||||||
|
0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
|
||||||
|
0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
|
||||||
|
0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||||
|
0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
|
||||||
|
0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
|
||||||
|
0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
|
||||||
|
0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
|
||||||
|
0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
|
||||||
|
0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
|
||||||
|
0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
|
||||||
|
0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
|
||||||
|
0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||||
|
0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
|
||||||
|
0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||||
|
0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
|
||||||
|
0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||||
|
0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
|
||||||
|
0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||||
|
0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
|
||||||
|
0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
|
||||||
|
0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
|
||||||
|
0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
|
||||||
|
0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
|
||||||
|
0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
|
||||||
|
0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
|
||||||
|
0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
|
||||||
|
};
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: readbyte
|
||||||
|
* Read one byte from data stream (with timeout)
|
||||||
|
* parameters:
|
||||||
|
* fd i/o pathes of data stream
|
||||||
|
* seconds timeout
|
||||||
|
* return: byte or TIMEOUT
|
||||||
|
******************************************************************************/
|
||||||
|
static int readbyte(rwfd_t fd, int seconds)
|
||||||
|
{
|
||||||
|
struct pollfd pfd;
|
||||||
|
unsigned char c;
|
||||||
|
unsigned char proto[1024];
|
||||||
|
unsigned char data[4096];
|
||||||
|
union CAPI_primitives *capi;
|
||||||
|
int lcause;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (capi2_wait_for_signal(fd.rd, seconds * 1000 ) == CAPI2_E_MSG_QUEUE_EMPTY) {
|
||||||
|
printf("readbyte timeout %d\n", seconds);
|
||||||
|
return TIMEOUT;
|
||||||
|
} else {
|
||||||
|
lcause = capi2_get_message( fd.rd, &capi,
|
||||||
|
(union CAPI_primitives *)proto, &c, 1);
|
||||||
|
//printf("capi=%x\n", GET_PRIMTYPE(capi));
|
||||||
|
}
|
||||||
|
} while (GET_PRIMTYPE(capi) != CAPI2_DATAB3_IND);
|
||||||
|
|
||||||
|
capi2_datab3_resp( fd.rd,
|
||||||
|
GET_MESSID(capi),
|
||||||
|
fd.ident,
|
||||||
|
GET_WORD(capi->c2datab3_ind.handle));
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: readdata
|
||||||
|
* Read block of data from given i/o pathes (with timeout)
|
||||||
|
* parameters:
|
||||||
|
* x xmodem handle
|
||||||
|
* bufsize receiver buffer size
|
||||||
|
* checksum accumulated crc
|
||||||
|
* return: data byte or TIMEOUT
|
||||||
|
******************************************************************************/
|
||||||
|
static int readdata(xmodem_t *x, int bufsize, int *checksum)
|
||||||
|
{
|
||||||
|
int c; /* character being processed */
|
||||||
|
unsigned short chksm; /* working copy of checksum */
|
||||||
|
int j; /* loop index */
|
||||||
|
|
||||||
|
chksm = 0;
|
||||||
|
for (j = 0; j < bufsize; j++) {
|
||||||
|
if ((c = readbyte(x->fd, 1)) == TIMEOUT) { /* 1s timeout */
|
||||||
|
return TIMEOUT;
|
||||||
|
}
|
||||||
|
x->buf[j] = c & 0xff;
|
||||||
|
if (x->crcmode) /* CRC */
|
||||||
|
chksm = (chksm << B) ^ crctab[(chksm >> (W - B)) ^ c];
|
||||||
|
else /* checksum */
|
||||||
|
chksm = ((chksm + c) & 0xff);
|
||||||
|
}
|
||||||
|
*checksum = chksm;
|
||||||
|
|
||||||
|
TRACE("XMODEM read (%d bytes)", j);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: sendbyte
|
||||||
|
* Write one byte to data stream
|
||||||
|
* parameters:
|
||||||
|
* fd i/o pathes of data stream
|
||||||
|
* data data byte
|
||||||
|
* return: -
|
||||||
|
******************************************************************************/
|
||||||
|
static void sendbyte(rwfd_t fd, char data)
|
||||||
|
{
|
||||||
|
TRACE("XMODEM write (%d bytes)", 1);
|
||||||
|
//write(fd.wr, &data, 1);
|
||||||
|
capi2_datab3_req( fd.wr, fd.ident, &data, 1, 0, fd.handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: purge
|
||||||
|
* Wait for the line to clear (read rest)
|
||||||
|
* parameters:
|
||||||
|
* fd i/o pathes of data stream
|
||||||
|
* return: -
|
||||||
|
******************************************************************************/
|
||||||
|
static void purge(rwfd_t fd)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
while ((c = readbyte(fd, 1)) != TIMEOUT) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: purge
|
||||||
|
* Send CAN twice
|
||||||
|
* parameters:
|
||||||
|
* fd i/o pathes of data stream
|
||||||
|
* return: -
|
||||||
|
******************************************************************************/
|
||||||
|
static void cancel(rwfd_t fd)
|
||||||
|
{
|
||||||
|
sendbyte(fd, CAN);
|
||||||
|
sendbyte(fd, CAN);
|
||||||
|
purge(fd);
|
||||||
|
sendbyte(fd, CAN);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: xmodem_open
|
||||||
|
* Open console and set baud rate
|
||||||
|
* parameters:
|
||||||
|
* dev device name (e.g. "consexcl")
|
||||||
|
* or NULL for stdio (baud rate ignored!)
|
||||||
|
* baud baud rate [baud]
|
||||||
|
* one_kb xmodem-1k mode enable
|
||||||
|
* emsg buffer for error message (80 bytes)
|
||||||
|
* return: xmodem ptr or error (NULL)
|
||||||
|
******************************************************************************/
|
||||||
|
xmodem_t *xmodem_open(call_t *ptrCall, int baud, int one_kb, char *emsg, char *filename)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
xmodem_t *x = malloc(sizeof *x);
|
||||||
|
|
||||||
|
if (!x) {
|
||||||
|
if (emsg) sprintf(emsg, "XMODEM: out of memory");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
memset(x, 0, sizeof *x);
|
||||||
|
|
||||||
|
reset_terminal(); /* unraw terminal */
|
||||||
|
|
||||||
|
if (ptrCall) {
|
||||||
|
/*------------------------------+
|
||||||
|
| i/o via stdio pathes |
|
||||||
|
+------------------------------*/
|
||||||
|
TRACE("XMODEM via CAPI");
|
||||||
|
x->conmode = 0;
|
||||||
|
x->fd.rd = ptrCall->capi_fd; /* use stdio pathes */
|
||||||
|
x->fd.wr = ptrCall->capi_fd;
|
||||||
|
x->fd.ident = ptrCall->ident;
|
||||||
|
} else {
|
||||||
|
TRACE("XMODEM via stdio");
|
||||||
|
x->conmode = 0;
|
||||||
|
x->fd.rd = STDIN;
|
||||||
|
x->fd.wr = STDOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filename) {
|
||||||
|
x->sendfp = fopen(filename, "r");
|
||||||
|
/* XXX: check for fopen errors here */
|
||||||
|
if (!x->sendfp) {
|
||||||
|
/* failure */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TRACE("XMODEM no filename to send specified");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
x->failed = FALSE;
|
||||||
|
x->crcmode = TRUE;
|
||||||
|
x->rcvstartch = x->crcmode ? CRCCHR : NAK;
|
||||||
|
x->one_kb = one_kb & 1; /* only relevant for sending packets */
|
||||||
|
x->starttime = time(NULL);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: xmodem_onekb
|
||||||
|
* Return if modem-1k mode enabled
|
||||||
|
* parameters:
|
||||||
|
* x xmodem ptr
|
||||||
|
* return: modem-1k mode enabled (1) or not (0)
|
||||||
|
******************************************************************************/
|
||||||
|
int xmodem_onekb(xmodem_t *x)
|
||||||
|
{
|
||||||
|
return x->one_kb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: xmodem_cancel
|
||||||
|
* Send CAN to stop an unterminated getpkt transfer
|
||||||
|
* parameters:
|
||||||
|
* x xmodem ptr
|
||||||
|
* return: -
|
||||||
|
******************************************************************************/
|
||||||
|
void xmodem_cancel(xmodem_t *x)
|
||||||
|
{
|
||||||
|
cancel(x->fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: xmodem_close
|
||||||
|
* Close device and free memory
|
||||||
|
* parameters:
|
||||||
|
* x xmodem ptr
|
||||||
|
* return: success (0) or error code
|
||||||
|
******************************************************************************/
|
||||||
|
void xmodem_close(xmodem_t *x)
|
||||||
|
{
|
||||||
|
time_t tdiff;
|
||||||
|
|
||||||
|
if (x->fd.rd != -1) {
|
||||||
|
if (x->conmode) {
|
||||||
|
close(x->fd.rd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (x->sendfp) {
|
||||||
|
fclose (x->sendfp); /* close opened file to send */
|
||||||
|
x->sendfp = NULL;
|
||||||
|
}
|
||||||
|
x->fd.rd = -1;
|
||||||
|
|
||||||
|
if (x->starttime) {
|
||||||
|
tdiff = time(NULL) - x->starttime;
|
||||||
|
printf("duration: %d\n", tdiff );
|
||||||
|
}
|
||||||
|
|
||||||
|
free(x);
|
||||||
|
set_raw_terminal(); /* enable raw terminal mode */
|
||||||
|
}
|
||||||
|
#ifdef USE_UNPORTED
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: xmodem_getpkt
|
||||||
|
* Receive one XMODEM-Packet and write it into buf
|
||||||
|
*
|
||||||
|
* The length of the packet is written into (*lenp).
|
||||||
|
* An error message is written into emsg.
|
||||||
|
* The length of data packets (128/1024) is determined by the remote site
|
||||||
|
* parameters:
|
||||||
|
* x xmodem ptr
|
||||||
|
* buf data packet buffer (1024 bytes)
|
||||||
|
* lenp length of the data packet
|
||||||
|
* emsg buffer for error message (80 bytes)
|
||||||
|
* return: status code
|
||||||
|
* XMODEM_RCVPKT: successfully received one packet
|
||||||
|
* XMODEM_EOT: received End-of-Transmission character
|
||||||
|
* XMODEM_ERROR: receive failed
|
||||||
|
******************************************************************************/
|
||||||
|
int xmodem_getpkt(xmodem_t *x, char *buf, int *lenp, char *emsg)
|
||||||
|
{
|
||||||
|
int checksum, /* packet checksum */
|
||||||
|
firstchar, /* first character of a packet */
|
||||||
|
sectcurr, /* second byte of packet--should be packet */
|
||||||
|
/* number (mod 128) */
|
||||||
|
sectcomp, /* third byte of packet--should be complement */
|
||||||
|
/* of sectcurr */
|
||||||
|
errorflag, /* set true when packet (or first char of */
|
||||||
|
/* putative packet) is invalid */
|
||||||
|
inchecksum, /* incoming checksum or CRC */
|
||||||
|
msb, lsb, /* incoming checksum (upper/lower byte) */
|
||||||
|
duplicate, /* got duplicate packet */
|
||||||
|
timeout, /* read timeout */
|
||||||
|
bufsize; /* packet size (128 or 1024) */
|
||||||
|
|
||||||
|
|
||||||
|
sendbyte(x->fd, x->rcvstartch);
|
||||||
|
|
||||||
|
restart:
|
||||||
|
bufsize = 128;
|
||||||
|
errorflag = FALSE;
|
||||||
|
duplicate = FALSE;
|
||||||
|
timeout = FALSE;
|
||||||
|
*lenp = 0;
|
||||||
|
|
||||||
|
do { /* start by reading first byte in packet */
|
||||||
|
if ((firstchar = readbyte(x->fd, 4)) == TIMEOUT) {
|
||||||
|
errorflag = timeout = TRUE;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
} while ((firstchar != SOH)
|
||||||
|
&& (firstchar != STX)
|
||||||
|
&& (firstchar != EOT)
|
||||||
|
&& (firstchar != ACK || x->recvsectcnt > 0)
|
||||||
|
&& (firstchar != CAN));
|
||||||
|
|
||||||
|
if (firstchar == EOT) { /* check for REAL EOT */
|
||||||
|
TRACE("EOT");
|
||||||
|
if (readbyte(x->fd, 1) != TIMEOUT) {
|
||||||
|
errorflag = timeout = TRUE;
|
||||||
|
TRACE("ignoring extra characters");
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (firstchar == CAN) { /* bailing out? */
|
||||||
|
TRACE("CAN");
|
||||||
|
if ((readbyte(x->fd, 3) & 0x7f) == CAN) {
|
||||||
|
sleep(1);
|
||||||
|
if (emsg) strcpy(emsg, "XMODEM: canceled by user");
|
||||||
|
return XMODEM_ERROR;
|
||||||
|
} else {
|
||||||
|
errorflag = TRUE;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (firstchar == SOH || firstchar == STX) { /* start reading packet */
|
||||||
|
bufsize = (firstchar == SOH) ? 128 : 1024;
|
||||||
|
|
||||||
|
if (x->recvsectcnt == 0) { /* 1st data packet, initialize */
|
||||||
|
if (bufsize == 1024) {
|
||||||
|
TRACE("1K packet mode chosen");
|
||||||
|
}
|
||||||
|
x->errors = 0;
|
||||||
|
x->got_eot = 0;
|
||||||
|
}
|
||||||
|
if ((sectcurr = readbyte(x->fd, 3)) == TIMEOUT ||
|
||||||
|
(sectcomp = readbyte(x->fd, 3)) == TIMEOUT) {
|
||||||
|
errorflag = timeout = TRUE;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
TRACE("%s: sectcurr=0x%02x sectcomp=0x%02x",
|
||||||
|
firstchar==SOH ? "SOH":"STX", sectcurr, sectcomp);
|
||||||
|
if ((sectcurr + sectcomp) == 0xff) { /* is packet number
|
||||||
|
* checksum correct? */
|
||||||
|
if (sectcurr == ((x->sectnum + 1) & 0xff)) {
|
||||||
|
/*
|
||||||
|
* Read, process and calculate checksum for a buffer of
|
||||||
|
* data
|
||||||
|
*/
|
||||||
|
if ((readdata(x, bufsize, &checksum)) == TIMEOUT) {
|
||||||
|
errorflag = timeout = TRUE;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
/* verify checksum or CRC */
|
||||||
|
if (x->crcmode) {
|
||||||
|
checksum &= 0xffff;
|
||||||
|
/* get 16-bit CRC */
|
||||||
|
if ((msb = readbyte(x->fd, 3)) == TIMEOUT ||
|
||||||
|
(lsb = readbyte(x->fd, 3)) == TIMEOUT) {
|
||||||
|
errorflag = timeout = TRUE;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
inchecksum = (msb << 8) | lsb;
|
||||||
|
} else {
|
||||||
|
/* get simple 8-bit checksum */
|
||||||
|
if ((inchecksum = readbyte(x->fd, 3)) == TIMEOUT) {
|
||||||
|
errorflag = timeout = TRUE;
|
||||||
|
goto abort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inchecksum == checksum) { /* good checksum, hence
|
||||||
|
* good packet */
|
||||||
|
x->errors = 0;
|
||||||
|
x->recvsectcnt += (bufsize == 128) ? 1 : 8;
|
||||||
|
x->sectnum = sectcurr;
|
||||||
|
memcpy(buf, x->buf, bufsize);
|
||||||
|
*lenp = bufsize;
|
||||||
|
x->rcvstartch = ACK;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Start handling various errors and special
|
||||||
|
* conditions
|
||||||
|
*/
|
||||||
|
else { /* bad checksum */
|
||||||
|
TRACE("checksum error crcmode=%d: inchecksum=%x crc=%x",
|
||||||
|
x->crcmode, inchecksum, checksum);
|
||||||
|
errorflag = TRUE;
|
||||||
|
}
|
||||||
|
} else { /* sector number is wrong */
|
||||||
|
if (sectcurr == x->sectnum) { /* duplicate sector? */
|
||||||
|
errorflag = TRUE;
|
||||||
|
duplicate = TRUE;
|
||||||
|
TRACE("duplicate sector");
|
||||||
|
while (readbyte(x->fd, 3) != TIMEOUT);
|
||||||
|
} else { /* no, real phase error */
|
||||||
|
errorflag = TRUE;
|
||||||
|
x->failed = TRUE;
|
||||||
|
cancel(x->fd);
|
||||||
|
TRACE("phase error, expected sector=%d", x->recvsectcnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { /* bad packet number checksum */
|
||||||
|
TRACE("wrong header sector number");
|
||||||
|
errorflag = TRUE;
|
||||||
|
}
|
||||||
|
} /* END reading packet loop */
|
||||||
|
|
||||||
|
abort:
|
||||||
|
if (timeout) TRACE("timeout sector=%d", x->recvsectcnt);
|
||||||
|
if ((errorflag && !x->failed) || x->recvsectcnt == 0) {
|
||||||
|
if (errorflag) x->errors++;
|
||||||
|
if (x->recvsectcnt != 0) {
|
||||||
|
while (readbyte(x->fd, 3) != TIMEOUT) ;/* wait for line to settle if
|
||||||
|
* not beginning */
|
||||||
|
}
|
||||||
|
if (duplicate) {
|
||||||
|
sendbyte(x->fd, ACK);
|
||||||
|
} else if (x->crcmode && x->recvsectcnt == 0 && x->errors == CRCSWMAX) {
|
||||||
|
x->crcmode = FALSE;
|
||||||
|
TRACE("CRC mode not accepted");
|
||||||
|
purge(x->fd);
|
||||||
|
sendbyte(x->fd, NAK);
|
||||||
|
} else if (!x->crcmode && x->recvsectcnt == 0 && x->errors == CRCSWMAX){
|
||||||
|
x->crcmode = TRUE;
|
||||||
|
TRACE("checksum mode not accepted");
|
||||||
|
purge(x->fd);
|
||||||
|
sendbyte(x->fd, CRCCHR);
|
||||||
|
} else if (x->crcmode && x->recvsectcnt == 0) {
|
||||||
|
purge(x->fd);
|
||||||
|
sendbyte(x->fd, CRCCHR);
|
||||||
|
} else {
|
||||||
|
purge(x->fd);
|
||||||
|
sendbyte(x->fd, NAK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstchar == EOT) {
|
||||||
|
x->got_eot = 1;
|
||||||
|
sendbyte(x->fd, ACK);
|
||||||
|
sleep(1);
|
||||||
|
return XMODEM_EOT;
|
||||||
|
} else if (x->failed || x->errors >= ERRORMAX) {
|
||||||
|
cancel(x->fd);
|
||||||
|
x->failed = 1;
|
||||||
|
if (emsg) strcpy(emsg, "XMODEM: too many errors");
|
||||||
|
return XMODEM_ERROR;
|
||||||
|
} else if (errorflag) {
|
||||||
|
goto restart;
|
||||||
|
} else {
|
||||||
|
return XMODEM_RCVPKT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* function: xmodem_putpkt
|
||||||
|
* Send one XMODEM packet
|
||||||
|
*
|
||||||
|
* The protocol packet length is 128 or 1024 bytes padded with CTRL-Z.
|
||||||
|
* If len argument is not 128/1024, this is the last packet and an EOT is
|
||||||
|
* sent to the remote site after sending the data packet.
|
||||||
|
* If the last packet sent had 128/1024 bytes, the application must invoke
|
||||||
|
* this funktion again with len=0 to indicate EOT.
|
||||||
|
* parameters:
|
||||||
|
* x xmodem ptr
|
||||||
|
* buf data packet buffer (1024 bytes)
|
||||||
|
* len length of the data packet
|
||||||
|
* emsg buffer for error message (80 bytes)
|
||||||
|
* return: 0 if error
|
||||||
|
******************************************************************************/
|
||||||
|
int xmodem_putpkt(xmodem_t *x, char *data, int len, char *emsg)
|
||||||
|
{
|
||||||
|
int bufctr; /* array index for data buffer */
|
||||||
|
unsigned short checksum; /* checksum/crc */
|
||||||
|
int attempts, /* number of attempts made to xmit a packet */
|
||||||
|
sendfin, /* flag that we are sending the last packet */
|
||||||
|
bbufcnt, /* array index for packet */
|
||||||
|
firstchar, /* first character in protocol transaction */
|
||||||
|
bufsize, /* packet size (128 or 1024) */
|
||||||
|
sendresp; /* response char received from remote */
|
||||||
|
char *cp = data;
|
||||||
|
|
||||||
|
bufsize = x->one_kb ? 1024 : 128;
|
||||||
|
sendfin = FALSE;
|
||||||
|
attempts = 0;
|
||||||
|
|
||||||
|
if (!x->got_ack) { /* sending first packet */
|
||||||
|
x->crcmode = FALSE; /* Receiver determines use of crc or checksum */
|
||||||
|
x->sectnum = 1;
|
||||||
|
do {
|
||||||
|
/* wait for and read startup character */
|
||||||
|
while (
|
||||||
|
(firstchar = readbyte(x->fd, 30)) != NAK
|
||||||
|
&& firstchar != CRCCHR
|
||||||
|
&& firstchar != CAN
|
||||||
|
) {
|
||||||
|
if (++attempts > NAKMAX) {
|
||||||
|
if (emsg) strcpy(emsg,
|
||||||
|
"XMODEM: remote system not responding");
|
||||||
|
x->failed = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((firstchar & 0x7f) == CAN) {
|
||||||
|
TRACE("CAN");
|
||||||
|
if (readbyte(x->fd, 3) == CAN) {
|
||||||
|
if (emsg) sprintf(emsg, "XMODEM: canceled by user");
|
||||||
|
x->failed = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (firstchar == CRCCHR) {
|
||||||
|
x->crcmode = TRUE;
|
||||||
|
TRACE("CRC mode requested");
|
||||||
|
}
|
||||||
|
} while (firstchar != NAK && firstchar != CRCCHR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0) goto sendeot;
|
||||||
|
|
||||||
|
bbufcnt = 0; /* start building buf to be sent */
|
||||||
|
x->buf[bbufcnt++] = (bufsize == 1024) ? STX : SOH;
|
||||||
|
x->buf[bbufcnt++] = x->sectnum; /* current sector # */
|
||||||
|
x->buf[bbufcnt++] = ~x->sectnum; /* and its complement */
|
||||||
|
|
||||||
|
checksum = 0;
|
||||||
|
for (bufctr=0; bufctr < bufsize; bufctr++) {
|
||||||
|
if (bufctr >= len) {
|
||||||
|
sendfin = TRUE; /* this is the last sector */
|
||||||
|
x->buf[bbufcnt + bufctr] = CTRLZ; /* Control-Z for CP/M EOF */
|
||||||
|
} else {
|
||||||
|
x->buf[bbufcnt + bufctr] = *cp++;
|
||||||
|
}
|
||||||
|
if (x->crcmode) {
|
||||||
|
checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ x->buf[bbufcnt + bufctr]];
|
||||||
|
} else {
|
||||||
|
checksum = ((checksum + x->buf[bbufcnt + bufctr]) & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bbufcnt += bufsize;
|
||||||
|
|
||||||
|
if (x->crcmode) { /* put in CRC */
|
||||||
|
checksum &= 0xffff;
|
||||||
|
x->buf[bbufcnt++] = ((checksum >> 8) & 0xff);
|
||||||
|
x->buf[bbufcnt++] = (checksum & 0xff);
|
||||||
|
} else { /* put in checksum */
|
||||||
|
x->buf[bbufcnt++] = checksum;
|
||||||
|
}
|
||||||
|
|
||||||
|
attempts = 0;
|
||||||
|
do { /* inner packet loop */
|
||||||
|
TRACE("XMODEM write (%d bytes) ", bbufcnt);
|
||||||
|
//write(x->fd.wr, x->buf, bbufcnt); /* write the buf */
|
||||||
|
x->fd.handle++; /* increase data handle var for capi */
|
||||||
|
capi2_datab3_req( x->fd.wr, x->fd.ident, x->buf, bbufcnt, 0, x->fd.handle);
|
||||||
|
|
||||||
|
TRACE("%s: sectcurr=0x%02x", x->buf[0]==SOH ? "SOH":"STX", x->sectnum);
|
||||||
|
#if 0
|
||||||
|
TRACE("%d byte %02xh (%02xh) sent, checksum %02xh %02xh secnum %d\n",
|
||||||
|
bbufcnt, x->buf[1]&0xff, x->buf[2]&0xff, x->buf[bufsize+3]&0xff,
|
||||||
|
x->buf[bufsize+4]&0xff, x->sectnum
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
attempts++;
|
||||||
|
sendresp = readbyte(x->fd, 10); /* get response from remote */
|
||||||
|
|
||||||
|
if (sendresp != ACK) {
|
||||||
|
x->errors++;
|
||||||
|
|
||||||
|
if ((sendresp & 0x7f) == CAN) {
|
||||||
|
TRACE("CAN");
|
||||||
|
if ((readbyte(x->fd, 3) & 0x7f) == CAN) {
|
||||||
|
if (emsg) strcpy(emsg, "XMODEM: canceled by user");
|
||||||
|
x->failed = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sendresp == TIMEOUT) {
|
||||||
|
TRACE("timeout on sector %d", x->sentsectcnt);
|
||||||
|
} else {
|
||||||
|
TRACE("non-ACK on sector %d", x->sentsectcnt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
x->got_ack = 1;
|
||||||
|
}
|
||||||
|
} while (
|
||||||
|
sendresp != ACK && attempts < RETRYMAX && x->errors < ERRORMAX
|
||||||
|
);
|
||||||
|
|
||||||
|
x->sectnum++;
|
||||||
|
x->sentsectcnt += (bufsize == 128) ? 1 : 8;
|
||||||
|
|
||||||
|
if (attempts >= RETRYMAX) {
|
||||||
|
sendbyte(x->fd, CAN); sendbyte(x->fd, CAN); sendbyte(x->fd, CAN);
|
||||||
|
if (emsg) strcpy(emsg, "XMODEM: remote system not responding");
|
||||||
|
x->failed = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempts > ERRORMAX) {
|
||||||
|
sendbyte(x->fd, CAN); sendbyte(x->fd, CAN); sendbyte(x->fd, CAN);
|
||||||
|
if (emsg) strcpy(emsg, "XMODEM: too many errors");
|
||||||
|
x->failed = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendfin) {
|
||||||
|
sendeot:
|
||||||
|
attempts = 0;
|
||||||
|
sendbyte(x->fd, EOT); /* send 1st EOT to close down transfer */
|
||||||
|
|
||||||
|
/* wait for ACK of EOT */
|
||||||
|
while (readbyte(x->fd, 15) != ACK && attempts++ < RETRYMAX) {
|
||||||
|
TRACE("EOT not acked");
|
||||||
|
sendbyte(x->fd, EOT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attempts >= RETRYMAX) {
|
||||||
|
if (emsg) strcpy(emsg, "XMODEM: last ACK missing");
|
||||||
|
x->failed = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
/************************************************************************
|
||||||
|
* (C)opyright 1991-1999 BinTec Communications AG, All Rights Reserved
|
||||||
|
*
|
||||||
|
* Title: <one line description>
|
||||||
|
* Author: <username>
|
||||||
|
* $RCSfile: xmodem.h,v $
|
||||||
|
* $Revision: 74 $
|
||||||
|
* $Date: 2005-12-22 01:06:50 +0100 (Thu, 22 Dec 2005) $
|
||||||
|
* $State: Exp $
|
||||||
|
*
|
||||||
|
* Type: include file for ..
|
||||||
|
* Products: ALL | XS,XM,XL,XP,BGO,BGP,XCM
|
||||||
|
* Description: --
|
||||||
|
*-----------------------------------------------------------------------
|
||||||
|
* Current Log:
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#ifndef _xmodem_h
|
||||||
|
#define _xmodem_h
|
||||||
|
|
||||||
|
#ifdef USE_RCSID_H
|
||||||
|
static const char _rcsid_xmodem_h[] __UNUSED = "$Id: xmodem.h,v 1.1 2002/12/19 12:53:33 shoki Exp $";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ASCII Constants */
|
||||||
|
#define SOH 001
|
||||||
|
#define STX 002
|
||||||
|
#define ETX 003
|
||||||
|
#define EOT 004
|
||||||
|
#define ENQ 005
|
||||||
|
#define ACK 006
|
||||||
|
#define LF 012 /* Unix LF/NL */
|
||||||
|
#define CR 015
|
||||||
|
#define NAK 025
|
||||||
|
#define SYN 026
|
||||||
|
#define CAN 030
|
||||||
|
#define ESC 033
|
||||||
|
|
||||||
|
/* XMODEM Constants */
|
||||||
|
#define TIMEOUT -1
|
||||||
|
#define ERRORMAX 10 /* maximum errors tolerated */
|
||||||
|
#define CRCSWMAX 4 /* maximum time to try CRC mode before switching */
|
||||||
|
#define KSWMAX 5 /* maximum errors before switching to 128 byte packets */
|
||||||
|
#define NAKMAX 2 /* maximum times to wait for initial NAK when sending */
|
||||||
|
#define RETRYMAX 5 /* maximum retries to be made */
|
||||||
|
#define CRCCHR 'C' /* CRC request character */
|
||||||
|
#define CTRLZ 032 /* CP/M EOF for text (usually!) */
|
||||||
|
|
||||||
|
#undef DEBUG
|
||||||
|
|
||||||
|
/* the CRC polynomial. */
|
||||||
|
#define P 0x1021
|
||||||
|
|
||||||
|
/* number of bits in CRC */
|
||||||
|
#define W 16
|
||||||
|
|
||||||
|
/* this the number of bits per char */
|
||||||
|
#define B 8
|
||||||
|
|
||||||
|
#define XMODEM_EOT 0 /* End of transmission */
|
||||||
|
#define XMODEM_ERROR 1 /* Too many errors */
|
||||||
|
#define XMODEM_RCVPKT 2 /* Received Packet */
|
||||||
|
|
||||||
|
#define BBUFSIZ 1024 /* buffer size */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int rd; /* read path */
|
||||||
|
int wr; /* write path */
|
||||||
|
unsigned long ident; /* for capi ident */
|
||||||
|
unsigned short handle; /* for capi data handle */
|
||||||
|
} rwfd_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
CONST char *filename; /* filename of file to send */
|
||||||
|
FILE *sendfp; /* filepointer to opened file to be sent */
|
||||||
|
time_t starttime; /* when did the transfer start */
|
||||||
|
int sectnum; /* number of last packet (modulo 128) */
|
||||||
|
int errors; /* running cnt of errors(reset when 1st packet starts */
|
||||||
|
int recvsectcnt; /* running sector count (128 byte sectors) */
|
||||||
|
int sentsectcnt;
|
||||||
|
rwfd_t fd; /* i/o pathes */
|
||||||
|
int ldsav; /* saved ld mode */
|
||||||
|
char rcvstartch; /* char to request next packet */
|
||||||
|
unsigned char buf[BBUFSIZ + 6];
|
||||||
|
unsigned one_kb:1; /* 1024 byte mode configured (only sender) */
|
||||||
|
unsigned got_ack:1;
|
||||||
|
unsigned crcmode:1;
|
||||||
|
unsigned failed:1;
|
||||||
|
unsigned got_eot:1; /* end-of-transmission was received */
|
||||||
|
unsigned conmode:1; /* i/o via console */
|
||||||
|
} xmodem_t;
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue