/*--------------------------------------------------------------------------*\ MAIN.C 1995 AVM This demo program shows how to use the CAPI 2.0 Development Kit. When the program is started, it prompts for a number which will be called from the CONNECT routine. After that there is the main loop where the program handles CAPI and keystrokes. Following is a list of available keys: 'l' Listen (CIP mask = 0x1FFF03FF) every service will be indicated 'L' Listen (CIP mask = 0x00000000) no incoming call will be indicated Listen is sent to all available controllers 'c' Connect to specified number on slot 0 'C' Connect to specified number on slot 1 'd' Disconnect slot 0 'D' Disconnect slot 1 's' Send datablock with size "SendBlockSize" on slot 0 'S' Send datablock with size "SendBlockSize" on slot 1 'f' Transfer a file on slot 0 'F' Transfer a file on slot 1 'v' Receive a file on slot 0 'V' Receive a file on slot 1 'a' Accept incoming call on slot 0 'A' Accept incoming call on slot 1 'i' Ignore incoming call on slot 0 'I' Ignore incoming call on slot 1 'r' Reject incoming call on slot 0 'R' Reject incoming call on slot 1 Next is an example how to connect the local 2 B-channels: !! This will cost the same as one telephone call !! After the start press 'l' so that every incoming call will be indicated. Press 'c' and the program asks for a number to call, then dials the number. There should be an incoming call indication on slot 1. Press 'A' and the program answers the call on the second slot. Now everytime you send data with 's' or 'S' there must be an data indication on the opposite slot. Disconnect the slot with 'd' or 'D' \*--------------------------------------------------------------------------*/ #if !defined (NDEBUG) #define DEBUG #define CPROT #endif #include "os.h" #include #include #include #include #include #include "capi20.h" #include "c20msg.h" #include "capi.h" #include "connect.h" #include "contr.h" #include "data.h" #include "id.h" #include "init.h" /*--------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------*/ static char testblock[2048]; /*----- note: you may enter your own number here, but if you -----*/ /*----- supply a wrong number, some PBXs may reject the -----*/ /*----- CAPI messages containing the wrong number -----*/ /*----- e.g.: static char *CallingPartyNumber = "1234567"; -----*/ static char *CallingPartyNumber = NULL; static char CalledPartyNumberArr[40]; #ifdef DEBUG static char CAPI_PROT_BUF[CAPI_PROTOCOL_INIT_BUF_SIZE]; static char ProtocolFileName[80]; static FILE *ProtocolFile; #endif #define INVALID_SLOT -1 #define maxSlots 2 /*----- this demo program handles max. -----*/ /*----- two connections -----*/ static ConnectionID Slot[maxSlots]; #define B1PROTOCOL 0 #define B2PROTOCOL 0 #define B3PROTOCOL 0 #define B3CONFIGURATION NULL #define QueueSize 8 typedef struct __DataElement { char DATA[SendBlockSize]; unsigned short DATA_LENGTH; unsigned SENT; } _DataElement; typedef struct __DataQueue { _DataElement Element[QueueSize]; unsigned Head; unsigned Tail; unsigned Fill; } _DataQueue; _DataQueue Queue; static unsigned FileTransfer = FALSE; /*----- signals if filetransfer is in progress -----*/ static unsigned FileReceive = FALSE; /*----- signals if filetransfer is in progress -----*/ static FILE *File; /*--------------------------------------------------------------------------*\ * Press_Key: \*--------------------------------------------------------------------------*/ int Press_Key(void) { int c; if ((c = getch()) == 0) c = getch()+256; return c; } /*--------------------------------------------------------------------------*\ * GetSlot: returns the slotnumber of the ConnectionID or INVALID_SLOT \*--------------------------------------------------------------------------*/ int GetSlot(ConnectionID Con) { int x; for (x=0; x= QueueSize) Queue.Tail = 0; Queue.Fill--; } # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** datablock slot %d ID %d handle %d has been sent *****\n", GetSlot(Connection), Connection, DataHandle); # endif } /*--------------------------------------------------------------------------*\ * MainStateChange: signals a state change on both B-channels (connected, * disconnected). Whenever a channel changes his state this function is called \*--------------------------------------------------------------------------*/ void MainStateChange(ConnectionID Connection, ConnectionState State) { int index; assert (Connection != INVALID_CONNECTION_ID); index = GetSlot(Connection); # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** state change slot %d ID %d: %s *****\n", index, Connection, ConnectionStateString[State]); # endif if (State == Disconnected) { FreeSlot(index); } } /*--------------------------------------------------------------------------*\ * MainIncomingCall: signals an incoming call * This function will be executed if a CONNECT_INDication appears to * inform the user. \*--------------------------------------------------------------------------*/ void MainIncomingCall(ConnectionID Connection, char *CallingPartyNumber) { int index; assert (Connection != INVALID_CONNECTION_ID); # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** incoming call ,ID %d, caller: \"%s\" *****\n",Connection,CallingPartyNumber); # endif index = AllocSlot(Connection); if (index == INVALID_SLOT) { # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** no free slot available, rejecting call... *****\n"); # endif AnswerCall(Connection, REJECT,0,0,0,NULL); return; } # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** call assigned to slot %d *****\n", index); # endif } #ifdef DEBUG /*--------------------------------------------------------------------------*\ * CAPI_PROT_HANDLE: This is a callback-function that has been specified * with CAPI_PROTOCOL_INIT. The first parameter is a pointer to the protocol- * message which is plain ASCII-text. The parameter t contains the type of * the message which can be CAPI_PROTOCOL_HEADER (appears only once when * calling CAPI_PROTOCOL_INIT), CAPI_PROTOCOL_MSG (the text contains a * decoded CAPI-message) and CAPI_PROTOCOL_TXT (the buffers contains a debug * message or a message sent with the function CAPI_PROTOCOL_TEXT). * If the type of the message is CAPI_PROTOCOL_MSG, the last parameter contains * a pointer to the decoded CAPI-message. \*--------------------------------------------------------------------------*/ void CAPI_PROT_HANDLE(char *Message, CAPI_PROTOCOL_TYP t, CAPI_MESSAGE m) { fprintf(ProtocolFile,"%s",Message); if (t != CAPI_PROTOCOL_MSG) puts(Message); if (t == CAPI_PROTOCOL_MSG) { _cmsg CMSG; CAPI_MESSAGE_2_CMSG(&CMSG, m); if ((FileTransfer || FileReceive) && (CMSG.Command == CAPI_DATA_B3) && (CMSG.Info == 0) && (CMSG.Reason == 0) && (CMSG.Reason_B3 == 0)) { return; } puts(Message); if (CMSG.Info != 0) { printf("Info 0x%04X: %s\n",CMSG.Info,Decode_Info(CMSG.Info)); fprintf(ProtocolFile,"Info 0x%04X: %s\n",CMSG.Info,Decode_Info(CMSG.Info)); } if (CMSG.Reason != 0) { printf("Reason 0x%04X: %s\n",CMSG.Reason,Decode_Info(CMSG.Reason)); fprintf(ProtocolFile,"Reason 0x%04X: %s\n",CMSG.Reason,Decode_Info(CMSG.Reason)); } if (CMSG.Reason_B3 != 0) { printf("Reason_B3 0x%04X: %s\n",CMSG.Reason_B3,Decode_Info(CMSG.Reason_B3)); fprintf(ProtocolFile,"Reason_B3 0x%04X: %s\n",CMSG.Reason_B3,Decode_Info(CMSG.Reason_B3)); } } fflush(ProtocolFile); } /*--------------------------------------------------------------------------*\ * Prot_Init: Initialisation of the protocol \*--------------------------------------------------------------------------*/ int Prot_Init(char *Filename) { char *p; strcpy(ProtocolFileName, Filename); p = strrchr(ProtocolFileName, '.'); if (p) *p = '\0'; strcat(ProtocolFileName, ".prt"); if ((ProtocolFile=fopen(ProtocolFileName, "w"))==NULL) { printf("Can't open protocol-file !!\n"); return FALSE; } CAPI_PROTOCOL_INIT(CAPI_PROT_BUF, CAPI_PROT_HANDLE); return TRUE; } #endif /*--------------------------------------------------------------------------*\ * The following _h functions are 'h'igh level functions for the ones * implemented in CONNECT.C . The _h functions perform some parameter tests * that would cause an assert on the low-level functions. \*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*\ * Connect_h: Asks for a number to call then executes 'Connect' \*--------------------------------------------------------------------------*/ unsigned Connect_h(ConnectionID *Connection, char *CallingPartyNumber, unsigned long Service, unsigned short B1Protocol, unsigned short B2Protocol, unsigned short B3Protocol, unsigned char __far *B3Configuration) { if (*Connection != INVALID_CONNECTION_ID) { printf("Connect_h: Connection is already in use\n"); return 0xFFFF; } printf("Enter Number: "); fflush (stdout); gets(CalledPartyNumberArr); return Connect(Connection, CalledPartyNumberArr, CallingPartyNumber, Service, B1Protocol, B2Protocol, B3Protocol, B3Configuration); } /*--------------------------------------------------------------------------*\ * Disconnect_h: high level Disconnect \*--------------------------------------------------------------------------*/ unsigned Disconnect_h(ConnectionID Connection) { int index; ConnectionState State; if (Connection == INVALID_CONNECTION_ID) { printf("Disconnect_h: ConnectionID is invalid\n"); return 0xFFFF; } State = GetState(Connection); if ((State == Disconnected) || (State == D_DisconnectPending)) { index = GetSlot(Connection); printf("Disconnect_h: slot %d ID %d is disconnected\n",index, Connection); return 0xFFFF; } return Disconnect(Connection); } /*--------------------------------------------------------------------------*\ * SendData_h: high level SendData \*--------------------------------------------------------------------------*/ unsigned SendData_h(ConnectionID Connection, void __far *Data, unsigned short DataLength, unsigned short DataHandle) { int index; ConnectionState State; if (Connection == INVALID_CONNECTION_ID) { printf("SendData_h: ConnectionID is invalid\n"); return 0xFFFF; } State = GetState(Connection); if (State != Connected) { index = GetSlot(Connection); printf("SendData_h: slot %d ID %d is not connected\n",index, Connection); return 0xFFFF; } return SendData(Connection, Data, DataLength, DataHandle); } /*--------------------------------------------------------------------------*\ * AnswerCall_h: high level AnswerCall \*--------------------------------------------------------------------------*/ unsigned AnswerCall_h(ConnectionID Connection, RejectValue Reject, unsigned short B1Protocol, unsigned short B2Protocol, unsigned short B3Protocol, unsigned char __far *B3Configuration) { int index; ConnectionState State; if (Connection == INVALID_CONNECTION_ID) { printf("AnswerCall_h: ConnectionID is invalid\n"); return 0xFFFF; } State = GetState(Connection); if (State != D_ConnectPending) { index = GetSlot(Connection); printf("AnswerCall_h: slot %d ID %d is the wrong state for answering\n",index, Connection); return 0xFFFF; } return AnswerCall(Connection, Reject, B1Protocol, B2Protocol, B3Protocol, B3Configuration); } /*--------------------------------------------------------------------------*\ * InitQueue: resets the data queue \*--------------------------------------------------------------------------*/ void InitQueue(void) { unsigned x; for (x=0; x 0) { t = Queue.Tail; do { if (Queue.Element[t].SENT == FALSE) { error = SendData(index, (void __far *)Queue.Element[t].DATA, Queue.Element[t].DATA_LENGTH, (unsigned short)t); if (error != 0) { printf("Error transfering data: 0x%04X !!!",error); break; } Queue.Element[t].SENT = TRUE; } if (++t >= QueueSize) t = 0; } while (t != Queue.Head); } } /*--------------------------------------------------------------------------*\ * SendFile: Sends a file \*--------------------------------------------------------------------------*/ unsigned SendFile(int index) { char Filename[80]; unsigned count; if (Slot[index] == INVALID_CONNECTION_ID) { printf("SendFile: ConnectionID is invalid\n"); return 1; } if (GetState(Slot[index]) != Connected) { printf("SendFile: slot %d ID %d is not connected\n",index, Slot[index]); return 2; } printf("Enter Filename: "); fflush (stdout); gets(Filename); File = fopen(Filename, "rb"); if (! File) { # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** file not found *****\n"); # endif return 3; } InitQueue(); FileTransfer = TRUE; # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** Starting datatransfer on slot %d, press any key to stop *****\n",index); CAPI_PROTOCOL_TEXT("***** there is no protocol output to the screen during transfer *****\n\n"); # endif do { if ((! feof(File)) && (Queue.Fill < 7)) { /*----- max. 7 outstanding blocks supported by CAPI -----*/ count = fread(&(Queue.Element[Queue.Head].DATA[0]), 1, SendBlockSize, File); if (count > 0) { Queue.Element[Queue.Head].DATA_LENGTH = (unsigned short)count; if (++Queue.Head >= QueueSize) Queue.Head = 0; Queue.Fill++; } } if (GetState(Slot[index]) != Connected) { # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** connection broken *****\n"); # endif break; } if (kbhit()) { # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** interrupted by user *****\n"); # endif break; } TransferData(index); Handle_CAPI_Msg(); } while (Queue.Fill > 0); FileTransfer = FALSE; # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** End of filetransfer *****\n"); # endif fclose(File); return 0; } /*--------------------------------------------------------------------------*\ * ReceiveFile: Receives a file and writes it to disk \*--------------------------------------------------------------------------*/ unsigned ReceiveFile(int index) { char Filename[80]; if (Slot[index] == INVALID_CONNECTION_ID) { printf("ReceiveFile: ConnectionID is invalid\n"); return 1; } if (GetState(Slot[index]) != Connected) { printf("ReceiveFile: slot %d ID %d is not connected\n",index, Slot[index]); return 2; } printf("Enter Filename where incoming data shall be saved: "); fflush (stdout); gets(Filename); File = fopen(Filename, "wb"); if (! File) { # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** could not open file *****\n"); # endif return 3; } InitQueue(); FileReceive = TRUE; # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** Waiting for data on slot %d, press any key to stop *****\n",index); CAPI_PROTOCOL_TEXT("***** there is no protocol output to the screen during transfer *****\n"); # endif do { if (GetState(Slot[index]) != Connected) { # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** connection broken *****\n"); # endif break; } Handle_CAPI_Msg(); } while (! kbhit()); getch(); FileReceive = FALSE; # ifdef DEBUG CAPI_PROTOCOL_TEXT("***** End of filetransfer *****\n"); # endif fclose(File); return 0; } /*---------------------------------------------------------------------------*\ * PrintHelp: tell the user the options \*---------------------------------------------------------------------------*/ static void PrintHelp (void) { puts("\n\n"); puts("'ESC' Exit program"); puts("'l' Listen (CIP mask = 0x1FFF03FF) every service will be indicated"); puts("'L' Listen (CIP mask = 0x00000000) no incoming call will be indicated"); puts("'c'+'C' Connect, the specified number will be called"); puts("'d' Disconnect slot 0"); puts("'D' Disconnect slot 1"); puts("'s' Send datablock with size \"SendBlockSize\" on slot 0"); puts("'S' Send datablock with size \"SendBlockSize\" on slot 1"); puts("'f' Transfer a file on slot 0"); puts("'F' Transfer a file on slot 1"); puts("'v' Receive a file on slot 0"); puts("'V' Receive a file on slot 1"); puts("'a' Accept incoming call on slot 0"); puts("'A' Accept incoming call on slot 1"); puts("'i' Ignore incoming call on slot 0"); puts("'I' Ignore incoming call on slot 1"); puts("'r' Reject incoming call on slot 0"); puts("'R' Reject incoming call on slot 1"); puts("'?' Print this help screen"); } /*--------------------------------------------------------------------------*\ * HandleKeyStroke: Checks the keyboard \*--------------------------------------------------------------------------*/ int HandleKeyStroke(void) { int i; #if defined (TARGET_NW) delay(50); // the netware NLM has to be cooperative #endif if (kbhit()) { i = Press_Key(); switch (i) { case 'q': case 27: { /*----- ESCAPE -----*/ printf("Exit program ? y/n "); fflush (stdout); i = Press_Key(); if ((i == 'y') || (i =='Y')) { puts("Y"); return FALSE; } puts("N"); return TRUE; } case 'l': Listen(ALL_SERVICES); break; case 'L': Listen(NO_SERVICES); break; case 'c': Connect_h(&Slot[0], CallingPartyNumber, DATA_TRANSFER, B1PROTOCOL, B2PROTOCOL, B3PROTOCOL, B3CONFIGURATION); break; case 'C': Connect_h(&Slot[1], CallingPartyNumber, DATA_TRANSFER, B1PROTOCOL, B2PROTOCOL, B3PROTOCOL, B3CONFIGURATION); break; case 'd': Disconnect_h(Slot[0]); break; case 'D': Disconnect_h(Slot[1]); break; case 's': SendData_h(Slot[0], (void __far *)&testblock, SendBlockSize, 1); break; case 'S': SendData_h(Slot[1], (void __far *)&testblock, SendBlockSize, 1); break; case 'f': SendFile(Slot[0]); break; case 'F': SendFile(Slot[1]); break; case 'v': ReceiveFile(Slot[0]); break; case 'V': ReceiveFile(Slot[1]); break; case 'a': AnswerCall_h(Slot[0],ACCEPT,B1PROTOCOL,B2PROTOCOL,B3PROTOCOL,NULL); break; case 'A': AnswerCall_h(Slot[1],ACCEPT,B1PROTOCOL,B2PROTOCOL,B3PROTOCOL,NULL); break; case 'i': AnswerCall_h(Slot[0],IGNORE,0,0,0,NULL); break; case 'I': AnswerCall_h(Slot[1],IGNORE,0,0,0,NULL); break; case 'r': AnswerCall_h(Slot[0],REJECT,0,0,0,NULL); break; case 'R': AnswerCall_h(Slot[1],REJECT,0,0,0,NULL); break; case 'h': case '?': PrintHelp(); break; } } return TRUE; } /*--------------------------------------------------------------------------*\ * Interact: main loop, checks keystrokes and CAPI-messages \*--------------------------------------------------------------------------*/ void Interact(void) { int numController; int BChannels, Contr; numController = GetNumController (); BChannels = 0; for (Contr=1; Contr<=numController; Contr++) BChannels += GetNumOfSupportedBChannels(Contr); printf("Detected %i controllers with %i B-channels overall.\n", numController, BChannels); PrintHelp (); do { Handle_CAPI_Msg(); } while (HandleKeyStroke()); puts("\nProgram terminated\n"); } /*--------------------------------------------------------------------------*\ * Hangup: Disconnect both channels \*--------------------------------------------------------------------------*/ void Hangup(void) { int i; if ((Slot[0] != INVALID_CONNECTION_ID) && (GetState(Slot[0]) != Disconnected) && (GetState(Slot[0]) != D_DisconnectPending)) Disconnect(Slot[0]); if ((Slot[1] != INVALID_CONNECTION_ID) && (GetState(Slot[1]) != Disconnected) && (GetState(Slot[1]) != D_DisconnectPending)) Disconnect(Slot[1]); do { Handle_CAPI_Msg(); if (kbhit()) { while (kbhit()) { getch(); } printf("Exit program ? y/n "); fflush (stdout); i = Press_Key(); if ((i == 'y') || (i =='Y')) { puts("Y"); return; } puts("N"); } } while ((Slot[0] != INVALID_CONNECTION_ID) || (Slot[1] != INVALID_CONNECTION_ID)); } /*--------------------------------------------------------------------------*\ * ctrlchandler: exits on CTRL-C and CTRL-BREAK \*--------------------------------------------------------------------------*/ void ctrlchandler(int sig) { signal( SIGINT, ctrlchandler ); exit(0); sig = 0; /*----- suppress warning -----*/ } /*--------------------------------------------------------------------------*\ * main: Init & exit functions \*--------------------------------------------------------------------------*/ #ifdef DEBUG int main(int ac, char *av[]) { #else int main(void) { #endif Slot[0] = INVALID_CONNECTION_ID; Slot[1] = INVALID_CONNECTION_ID; if (! RegisterCAPI ()) return 1; atexit (ReleaseCAPI); signal(SIGINT, ctrlchandler); InitConnectionIDHandling (); #ifdef DEBUG if (! Prot_Init(av[ac-1])) return 2; #endif #ifdef __linux__ init_tty(); atexit (restore_tty); #endif Interact(); Hangup(); #ifdef DEBUG fclose(ProtocolFile); #endif return 0; }