/*--------------------------------------------------------------------------*\ FAXMAIN.C Version 1.1 1995 AVM 's'+'S' Send fax 'r'+'R' Receive fax \*--------------------------------------------------------------------------*/ #if !defined (NDEBUG) #define DEBUG #define CPROT #endif #include #ifndef __linux__ #include #endif #include #include #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" #include "fax.h" #ifdef __linux__ #include "linuti.h" #include #endif /*--------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------*/ /*----- 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; char SenderID[80]; #endif #define INVALID_SLOT -1 #define maxSlots 2 /*----- this demo program handles max. -----*/ /*----- two connections -----*/ static ConnectionID Slot[maxSlots]; #define B1PROTOCOL 4 #define B2PROTOCOL 4 #define B3PROTOCOL 4 #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; /* ****************************************************************************** */ /* * Ablage von Information in die Datei /var/spool/fax/etc/xferlog */ static void write_xferlog_info( char *path, /* Path der Log Datei */ char *start, /* zB. 10/10/1997 15:19 */ char *cmd, /* zB.: "SEND" */ char *commid, /* zB.: "00000002" */ char *device, /* zB.: "cui2" */ char *jobid, /* zB.: "108" */ char *jobtag, /* zB.: "" */ char *user, /* zB.: "root at Jimlinux.pds.de" */ char *dest, /* zB.: "855675" */ char *csi, /* zB.: "" */ unsigned int params, /* zB.: 65535 */ int npages, /* zB.: 0 */ char *duration, /* zB.: "0:33" */ char *conntime, /* zB.: "0:00" */ char *status /* zB.: "Unknown Problem (Check Modem Power)" */ ) { int fd; char record[600]; char buf[200]; int i; char c; char* cp; record[0]=0; fd = open("/var/spool/fax/etc/xferlog", O_RDWR|O_CREAT|O_APPEND, 0644); if (fd < 0) return; strcat(record,start); // $ 1 = time sprintf(buf,"\t%s", cmd); // $ 2 = SEND|RECV|POLL|PAGE strcat(record,buf); sprintf(buf,"\t%s", commid); // $ 3 = commid strcat(record,buf); sprintf(buf,"\t%s", device); // $ 4 = device strcat(record,buf); sprintf(buf,"\t%s", jobid); // $ 5 = jobid strcat(record,buf); i = 0; for (cp = jobtag; c = *cp; cp++) { if (i == sizeof (buf)-2) // truncate string break; if (c == '\t') // tabs are field delimiters c = ' '; else if (c == '"') // escape quote marks buf[i++] = '\\'; buf[i++] = c; } buf[i] = '\0'; strcat(record,"\t\""); strcat(record,buf); // $ 6 = jobtag strcat(record,"\""); sprintf(buf,"\t%s", user); // $ 7 = sender strcat(record,buf); sprintf(buf,"\t\"%s\"", dest); // $ 8 = dest strcat(record,buf); sprintf(buf,"\t\"%s\"", csi); // $ 9 = csi strcat(record,buf); sprintf(buf,"\t%u", params); // $10 = encoded params strcat(record,buf); sprintf(buf,"\t%d", npages); // $11 = npages strcat(record,buf); sprintf(buf,"\t%s", duration); // $12 = duration strcat(record,buf); sprintf(buf,"\t%s", conntime); // $13 = conntime strcat(record,buf); sprintf(buf,"\t\"%s\"", status); // $14 = status strcat(record,buf); strcat(record,"\n"); flock(fd, LOCK_EX); write(fd, record, strlen(record)); close(fd); // implicit unlock } /* ****************************************************************************** */ /*--------------------------------------------------------------------------*\ * 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--; } CAPI_PROTOCOL_TEXT("***** datablock slot %d ID %d handle %d has been sent *****\n", GetSlot(Connection), Connection, DataHandle); } /*--------------------------------------------------------------------------*\ * 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); CAPI_PROTOCOL_TEXT("***** state change slot %d ID %d: %s *****\n", index, Connection, ConnectionStateString[State]); 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; B3_PROTO_FAXG3 B3conf; assert (Connection != INVALID_CONNECTION_ID); CAPI_PROTOCOL_TEXT("***** incoming call ,ID %d, caller: \"%s\" *****\n",Connection,CallingPartyNumber); index = AllocSlot(Connection); SetupB3Config( &B3conf, FAX_SFF_FORMAT); // SetupB3Config( &B3conf, FAX_TIFF_FORMAT); if (index == INVALID_SLOT) { CAPI_PROTOCOL_TEXT("***** no free slot available, rejecting call... *****\n"); AnswerCall(Connection, REJECT, 4, 4, 4, (_cstruct)&B3conf); return; } CAPI_PROTOCOL_TEXT("***** call assigned to slot %d *****\n", index); AnswerCall(Connection, ACCEPT, 4, 4, 4, (_cstruct)&B3conf); } #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 ((strstr(Message, "NCPI")!=NULL) && (strstr(Message, "default")==NULL)) { char *p; if ((p=strchr(Message, '>'))!=NULL) { strcpy(SenderID, &p[1]); if ((p=strchr(SenderID, '<'))!=NULL) *p = 0; printf("JIM HAT IHN:%s\n", SenderID); fprintf(ProtocolFile,"JIM HAT IHN:%s\n", SenderID); } } 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)); } } } /*--------------------------------------------------------------------------*\ * 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"); */ strcpy(ProtocolFileName, "/tmp/isdnrecv.prot"); 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 to call: "); 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 \*--------------------------------------------------------------------------*/ 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 !!!\n",error); break; } Queue.Element[t].SENT = TRUE; } if (++t >= QueueSize) t = 0; } while (t != Queue.Head); } } int GiveFreeSlot(void) { int i; for(i=0; i 1) seqf = atoi(val); sprintf(Filename, "/var/spool/fax/recvq/fax%05d.sff", seqf); seqf++; fseek(fp, 0, 0); fprintf(fp, "%d\n", seqf); fclose(fp); } char Filename[80]; //char SenderID[80]; extern _cmsg __far *CMSG; /*--------------------------------------------------------------------------*\ * ReceiveFax: Waits for incoming data and stores it to disk \*--------------------------------------------------------------------------*/ unsigned ReceiveFax(int SlotNr) { // char Filename[80]; char *p; /* printf("The default extension for the FAX-data is .sff\n"); printf("Enter Filename where incoming data shall be saved: "); fflush (stdout); gets(Filename); p = strchr(Filename, '.'); if (p) *p = '\0'; strcat(Filename, ".sff"); */ GetNextSeqName(Filename); File = fopen(Filename, "wb"); if (! File) { CAPI_PROTOCOL_TEXT("***** could not open file: \"%s\" *****\n",Filename); return 3; } printf("opening file: \"%s\"\n\n",Filename); InitQueue(); FileReceive = TRUE; CAPI_PROTOCOL_TEXT("***** Waiting for data , press any key to stop *****\n"); CAPI_PROTOCOL_TEXT("***** there is no protocol output to the screen during transfer *****\n"); Listen(0x1FFF03FF); while (GetState(Slot[SlotNr]) != Connected) { Handle_CAPI_Msg(); #ifdef WITH_KBHIT if (kbhit()) { getch(); CAPI_PROTOCOL_TEXT("***** interrupted by user *****\n"); fclose(File); FileReceive = FALSE; return 0; } #endif } // strcpy(SenderID, GetCallingPartyNumber(Slot[SlotNr])); while (GetState(Slot[SlotNr]) != INVAL_STATE) { Handle_CAPI_Msg(); #ifdef WITH_KBHIT if (kbhit()) { getch(); CAPI_PROTOCOL_TEXT("***** interrupted by user *****\n"); FileReceive = FALSE; fclose(File); return 0; } #endif } FileReceive = FALSE; CAPI_PROTOCOL_TEXT("***** End of FAX-receive *****\n"); fclose(File); return 0; } void ShowChannels(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\n", numController, BChannels); } /*--------------------------------------------------------------------------*\ * ValidSlots: Check if connections are not completely closed yet \*--------------------------------------------------------------------------*/ int ValidSlots(void) { int i; for(i=0; i/dev/null 2>/dev/null", Filename, SenderID); system(cmd); { time_t zeitstempel; char tbuf[80]; zeitstempel= time(0); strftime(tbuf, sizeof (tbuf), "%D %H:%M", localtime(&zeitstempel)); write_xferlog_info( "/var/spool/fax/etc/xferlog", tbuf, "IFAX", "00000000", "cuix", "108", "", " ", senderID, "", 0, 10, "0:00", "0:00", "Receive Fax over the CAPI Interface: OK" ); } } else { struct timespec tspec; tspec.tv_sec=10; tspec.tv_nsec=1000; nanosleep(&tspec, NULL); } Hangup(); } // Hangup(); #ifdef DEBUG fclose(ProtocolFile); #endif return (ret); }