1555 lines
34 KiB
C
1555 lines
34 KiB
C
/*
|
|
Copyright 2001-2022 John Wiseman G8BPQ
|
|
|
|
This file is part of LinBPQ/BPQ32.
|
|
|
|
LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
LinBPQ/BPQ32 is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
|
|
*/
|
|
|
|
//
|
|
// DLL to provide interface to allow G8BPQ switch to use MultoPSK ALE400 Mode
|
|
//
|
|
// Uses BPQ EXTERNAL interface
|
|
//
|
|
|
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
#include "CHeaders.h"
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
|
|
#include "tncinfo.h"
|
|
|
|
#include "bpq32.h"
|
|
|
|
#define VERSION_MAJOR 2
|
|
#define VERSION_MINOR 0
|
|
|
|
#define SD_RECEIVE 0x00
|
|
#define SD_SEND 0x01
|
|
#define SD_BOTH 0x02
|
|
|
|
#define TIMESTAMP 352
|
|
|
|
#define CONTIMEOUT 1200
|
|
|
|
|
|
|
|
#define AGWHDDRLEN sizeof(struct AGWHEADER)
|
|
|
|
extern int (WINAPI FAR *GetModuleFileNameExPtr)();
|
|
|
|
//int ResetExtDriver(int num);
|
|
|
|
static void ConnecttoMPSKThread(void * portptr);
|
|
|
|
void CreateMHWindow();
|
|
int Update_MH_List(struct in_addr ipad, char * call, char proto);
|
|
|
|
static int ConnecttoMPSK(int port);
|
|
static int ProcessReceivedData(int bpqport);
|
|
static int ProcessLine(char * buf, int Port);
|
|
int KillTNC(struct TNCINFO * TNC);
|
|
int RestartTNC(struct TNCINFO * TNC);
|
|
VOID ProcessMPSKPacket(struct TNCINFO * TNC, char * Message, int Len);
|
|
struct TNCINFO * GetSessionKey(char * key, struct TNCINFO * TNC);
|
|
static VOID SendData(struct TNCINFO * TNC, char * Msg, int MsgLen);
|
|
static VOID DoMonitorHddr(struct TNCINFO * TNC, struct AGWHEADER * RXHeader, UCHAR * Msg);
|
|
VOID SendRPBeacon(struct TNCINFO * TNC);
|
|
|
|
extern UCHAR BPQDirectory[];
|
|
|
|
#define MAXMPSKPORTS 16
|
|
|
|
//LOGFONT LFTTYFONT ;
|
|
|
|
//HFONT hFont ;
|
|
|
|
static int MPSKChannel[MAXBPQPORTS+1]; // BPQ Port to MPSK Port
|
|
static int BPQPort[MAXMPSKPORTS][MAXBPQPORTS+1]; // MPSK Port and Connection to BPQ Port
|
|
|
|
extern int MasterPort[MAXBPQPORTS+1]; // Pointer to first BPQ port for a specific MPSK host
|
|
|
|
// Each port may be on a different machine. We only open one connection to each MPSK instance
|
|
|
|
static char * MPSKSignon[MAXBPQPORTS+1]; // Pointer to message for secure signin
|
|
|
|
static unsigned int MPSKInst = 0;
|
|
static int AttachedProcesses=0;
|
|
|
|
static HWND hResWnd,hMHWnd;
|
|
static BOOL GotMsg;
|
|
|
|
static HANDLE STDOUT=0;
|
|
|
|
//SOCKET sock;
|
|
|
|
static SOCKADDR_IN sinx;
|
|
static SOCKADDR_IN rxaddr;
|
|
static SOCKADDR_IN destaddr[MAXBPQPORTS+1];
|
|
|
|
static int addrlen=sizeof(sinx);
|
|
|
|
//static short MPSKPort=0;
|
|
|
|
static time_t ltime,lasttime[MAXBPQPORTS+1];
|
|
|
|
static BOOL CONNECTING[MAXBPQPORTS+1];
|
|
static BOOL CONNECTED[MAXBPQPORTS+1];
|
|
|
|
//HANDLE hInstance;
|
|
|
|
|
|
static fd_set readfs;
|
|
static fd_set writefs;
|
|
static fd_set errorfs;
|
|
static struct timeval timeout;
|
|
|
|
#ifndef LINBPQ
|
|
|
|
static BOOL CALLBACK EnumTNCWindowsProc(HWND hwnd, LPARAM lParam)
|
|
{
|
|
char wtext[200];
|
|
struct TNCINFO * TNC = (struct TNCINFO *)lParam;
|
|
UINT ProcessId;
|
|
char FN[MAX_PATH] = "";
|
|
|
|
if (TNC->ProgramPath == NULL)
|
|
return FALSE;
|
|
|
|
GetWindowText(hwnd, wtext, 199);
|
|
|
|
if (strstr(wtext,"* MULTIPSK"))
|
|
{
|
|
GetWindowThreadProcessId(hwnd, &ProcessId);
|
|
|
|
TNC->PID = ProcessId;
|
|
return FALSE;
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
#endif
|
|
|
|
static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
|
|
{
|
|
PMSGWITHLEN buffptr;
|
|
unsigned int txlen=0;
|
|
struct TNCINFO * TNC = TNCInfo[port];
|
|
int Stream = 0;
|
|
struct STREAMINFO * STREAM;
|
|
int TNCOK;
|
|
|
|
if (TNC == NULL)
|
|
return 0; // Port not defined
|
|
|
|
// Look for attach on any call
|
|
|
|
for (Stream = 0; Stream <= TNC->MPSKInfo->MaxSessions; Stream++)
|
|
{
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && TNC->Streams[Stream].Attached == 0)
|
|
{
|
|
char Cmd[80];
|
|
int len;
|
|
|
|
// New Attach
|
|
|
|
int calllen;
|
|
STREAM->Attached = TRUE;
|
|
|
|
calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, STREAM->MyCall);
|
|
STREAM->MyCall[calllen] = 0;
|
|
STREAM->FramesOutstanding = 0;
|
|
|
|
// Stop Scanning
|
|
|
|
sprintf(Cmd, "%d SCANSTOP", TNC->Port);
|
|
Rig_Command( (TRANSPORTENTRY *) -1, Cmd);
|
|
|
|
len = sprintf(Cmd, "%cSTOP_BEACON_ARQ_FAE\x1b", '\x1a');
|
|
|
|
if (TNC->MPSKInfo->TX)
|
|
TNC->CmdSet = TNC->CmdSave = _strdup(Cmd); // Savde till not transmitting
|
|
else
|
|
send(TNC->TCPSock, Cmd, len, 0);
|
|
|
|
}
|
|
}
|
|
|
|
switch (fn)
|
|
{
|
|
case 1: // poll
|
|
|
|
if (MasterPort[port] == port)
|
|
{
|
|
// Only on first port using a host
|
|
|
|
if (TNC->CONNECTED == FALSE && TNC->CONNECTING == FALSE)
|
|
{
|
|
// See if time to reconnect
|
|
|
|
time( <ime );
|
|
if (ltime-lasttime[port] >9 )
|
|
{
|
|
ConnecttoMPSK(port);
|
|
lasttime[port]=ltime;
|
|
}
|
|
}
|
|
|
|
FD_ZERO(&readfs);
|
|
|
|
if (TNC->CONNECTED) FD_SET(TNC->TCPSock,&readfs);
|
|
|
|
|
|
FD_ZERO(&writefs);
|
|
|
|
if (TNC->CONNECTING) FD_SET(TNC->TCPSock,&writefs); // Need notification of Connect
|
|
|
|
if (TNC->BPQtoWINMOR_Q) FD_SET(TNC->TCPSock,&writefs); // Need notification of busy clearing
|
|
|
|
|
|
|
|
FD_ZERO(&errorfs);
|
|
|
|
if (TNC->CONNECTING ||TNC->CONNECTED) FD_SET(TNC->TCPSock,&errorfs);
|
|
|
|
if (select((int)TNC->TCPSock+ 1, &readfs, &writefs, &errorfs, &timeout) > 0)
|
|
{
|
|
// See what happened
|
|
|
|
if (FD_ISSET(TNC->TCPSock,&readfs))
|
|
{
|
|
// data available
|
|
|
|
ProcessReceivedData(port);
|
|
}
|
|
|
|
if (FD_ISSET(TNC->TCPSock,&writefs))
|
|
{
|
|
// Connect success
|
|
|
|
TNC->CONNECTED = TRUE;
|
|
TNC->CONNECTING = FALSE;
|
|
|
|
// If required, send signon
|
|
|
|
send(TNC->TCPSock,"\x1a", 1, 0);
|
|
send(TNC->TCPSock,"DIGITAL MODE ?", 14, 0);
|
|
send(TNC->TCPSock,"\x1b", 1, 0);
|
|
|
|
// EnumWindows(EnumTNCWindowsProc, (LPARAM)TNC);
|
|
}
|
|
|
|
if (FD_ISSET(TNC->TCPSock,&errorfs))
|
|
{
|
|
|
|
// if connecting, then failed, if connected then has just disconnected
|
|
|
|
// if (CONNECTED[port])
|
|
// if (!CONNECTING[port])
|
|
// {
|
|
// i=sprintf(ErrMsg, "MPSK Connection lost for BPQ Port %d\r\n", port);
|
|
// WritetoConsole(ErrMsg);
|
|
// }
|
|
|
|
CONNECTING[port]=FALSE;
|
|
CONNECTED[port]=FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// See if any frames for this port
|
|
|
|
for (Stream = 0; Stream <= TNC->MPSKInfo->MaxSessions; Stream++)
|
|
{
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
// Have to time out connects, as TNC doesn't report failure
|
|
|
|
if (STREAM->Connecting)
|
|
{
|
|
STREAM->Connecting--;
|
|
|
|
if (STREAM->Connecting == 0)
|
|
{
|
|
// Report Connect Failed, and drop back to command mode
|
|
|
|
buffptr = GetBuff();
|
|
|
|
if (buffptr)
|
|
{
|
|
buffptr->Len = sprintf(buffptr->Data, "MPSK} Failure with %s\r", STREAM->RemoteCall);
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
}
|
|
|
|
STREAM->Connected = FALSE; // Back to Command Mode
|
|
STREAM->DiscWhenAllSent = 10;
|
|
|
|
// Send Disc to TNC
|
|
|
|
TidyClose(TNC, Stream);
|
|
}
|
|
}
|
|
|
|
if (STREAM->Attached)
|
|
CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete);
|
|
|
|
if (STREAM->ReportDISC)
|
|
{
|
|
STREAM->ReportDISC = FALSE;
|
|
buff->PORT = Stream;
|
|
|
|
return -1;
|
|
}
|
|
|
|
// if Busy, send buffer status poll
|
|
|
|
if (STREAM->PACTORtoBPQ_Q == 0)
|
|
{
|
|
if (STREAM->DiscWhenAllSent)
|
|
{
|
|
STREAM->DiscWhenAllSent--;
|
|
if (STREAM->DiscWhenAllSent == 0)
|
|
STREAM->ReportDISC = TRUE; // Dont want to leave session attached. Causes too much confusion
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int datalen;
|
|
|
|
buffptr = Q_REM(&STREAM->PACTORtoBPQ_Q);
|
|
|
|
datalen = (int)buffptr->Len;
|
|
|
|
buff->PORT = Stream; // Compatibility with Kam Driver
|
|
buff->PID = 0xf0;
|
|
memcpy(&buff->L2DATA, &buffptr->Data[0], datalen);
|
|
datalen += sizeof(void *) + 4;
|
|
|
|
PutLengthinBuffer(buff, datalen);
|
|
ReleaseBuffer(buffptr);
|
|
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
if (TNC->PortRecord->UI_Q)
|
|
{
|
|
struct _MESSAGE * buffptr;
|
|
|
|
SOCKET Sock;
|
|
buffptr = Q_REM(&TNC->PortRecord->UI_Q);
|
|
|
|
Sock = TNCInfo[MasterPort[port]]->TCPSock;
|
|
|
|
ReleaseBuffer((UINT *)buffptr);
|
|
}
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
case 2: // send
|
|
|
|
|
|
if (!TNCInfo[MasterPort[port]]->CONNECTED) return 0; // Don't try if not connected to TNC
|
|
|
|
Stream = buff->PORT;
|
|
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
// txlen=(buff[6]<<8) + buff[5] - 8;
|
|
|
|
txlen = GetLengthfromBuffer((PDATAMESSAGE)buff) - 8;
|
|
|
|
if (STREAM->Connected)
|
|
{
|
|
SendData(TNC, buff->L2DATA, txlen);
|
|
}
|
|
else
|
|
{
|
|
char Command[80];
|
|
int len;
|
|
|
|
buff->L2DATA[txlen] = 0;
|
|
|
|
_strupr(buff->L2DATA);
|
|
|
|
if (_memicmp(buff->L2DATA, "D\r", 2) == 0)
|
|
{
|
|
TidyClose(TNC, buff->PORT);
|
|
STREAM->ReportDISC = TRUE; // Tell Node
|
|
return 0;
|
|
}
|
|
|
|
// See if Local command (eg RADIO)
|
|
|
|
if (_memicmp(buff->L2DATA, "RADIO ", 6) == 0)
|
|
{
|
|
sprintf(buff->L2DATA, "%d %s", TNC->Port, &buff->L2DATA[6]);
|
|
|
|
if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, buff->L2DATA))
|
|
{
|
|
}
|
|
else
|
|
{
|
|
PMSGWITHLEN buffptr = GetBuff();
|
|
|
|
if (buffptr == 0) return 1; // No buffers, so ignore
|
|
|
|
buffptr->Len = sprintf(buffptr->Data, "%s", buff->L2DATA);
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
if (STREAM->Connecting && _memicmp(buff->L2DATA, "ABORT", 5) == 0)
|
|
{
|
|
len = sprintf(Command,"%cSTOP_SELECTIVE_CALL_ARQ_FAE\x1b", '\x1a');
|
|
|
|
if (TNC->MPSKInfo->TX)
|
|
TNC->CmdSet = TNC->CmdSave = _strdup(Command); // Save till not transmitting
|
|
else
|
|
send(TNC->TCPSock, Command, len, 0);
|
|
|
|
TNC->InternalCmd = TRUE;
|
|
return (0);
|
|
}
|
|
|
|
if (_memicmp(buff->L2DATA, "MODE", 4) == 0)
|
|
{
|
|
buff->L2DATA[txlen - 1] = 0; // Remove CR
|
|
|
|
len = sprintf(Command,"%cDIGITAL MODE %s\x1b", '\x1a', &buff->L2DATA[5]);
|
|
|
|
if (TNC->MPSKInfo->TX)
|
|
TNC->CmdSet = TNC->CmdSave = _strdup(Command); // Save till not transmitting
|
|
else
|
|
send(TNC->TCPSock, Command, len, 0);
|
|
|
|
TNC->InternalCmd = TRUE;
|
|
return (0);
|
|
}
|
|
|
|
|
|
if (_memicmp(buff->L2DATA, "INUSE?", 6) == 0)
|
|
{
|
|
// Return Error if in use, OK if not
|
|
|
|
PMSGWITHLEN buffptr = GetBuff();
|
|
int s = 0;
|
|
|
|
while(s <= TNC->MPSKInfo->MaxSessions)
|
|
{
|
|
if (s != Stream)
|
|
{
|
|
if (TNC->PortRecord->ATTACHEDSESSIONS[s])
|
|
{
|
|
buffptr->Len = sprintf(buffptr->Data, "MPSK} Error - In use\r");
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
return 1; // Busy
|
|
}
|
|
}
|
|
s++;
|
|
}
|
|
buffptr->Len = sprintf(buffptr->Data, "MPSK} Ok - Not in use\r");
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
|
|
return 1;
|
|
}
|
|
|
|
// See if a Connect Command.
|
|
|
|
if (toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect
|
|
{
|
|
char * ptr;
|
|
char * context;
|
|
|
|
buff->L2DATA[txlen] = 0;
|
|
_strupr(buff->L2DATA);
|
|
|
|
memset(STREAM->RemoteCall, 0, 10);
|
|
|
|
ptr = strtok_s(&buff->L2DATA[2], " ,\r", &context);
|
|
|
|
if (ptr == 0)
|
|
{
|
|
PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
|
|
|
|
if (buffptr)
|
|
{
|
|
buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0],
|
|
"MPSK} Error - Call missing from C command\r", STREAM->MyCall, STREAM->RemoteCall);
|
|
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
}
|
|
|
|
STREAM->DiscWhenAllSent = 10;
|
|
return 0;
|
|
}
|
|
|
|
strcpy(STREAM->RemoteCall, ptr);
|
|
|
|
len = sprintf(Command,"%cCALLSIGN_TO_CALL_ARQ_FAE %s%c%cSELECTIVE_CALL_ARQ_FAE\x1b",
|
|
'\x1a', STREAM->RemoteCall, '\x1b', '\x1a');
|
|
|
|
if (TNC->MPSKInfo->TX)
|
|
TNC->CmdSet = TNC->CmdSave = _strdup(Command); // Save till not transmitting
|
|
else
|
|
send(TNC->TCPSock, Command, len, 0);
|
|
|
|
STREAM->Connecting = TNC->MPSKInfo->ConnTimeOut; // It doesn't report failure
|
|
|
|
// sprintf(Status, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
|
|
// SetDlgItemText(TNC->hDlg, IDC_TNCSTATE, Status);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Send any other command to Multipsk
|
|
|
|
buff->L2DATA[txlen - 1] = 0;
|
|
_strupr(buff->L2DATA);
|
|
|
|
len = sprintf(Command,"%c%s\x1b", '\x1a', buff->L2DATA);
|
|
|
|
if (TNC->MPSKInfo->TX)
|
|
TNC->CmdSet = TNC->CmdSave = _strdup(Command); // Save till not transmitting
|
|
else
|
|
send(TNC->TCPSock, Command, len, 0);
|
|
|
|
TNC->InternalCmd = TRUE;
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
case 3:
|
|
|
|
Stream = (int)(size_t)buff;
|
|
|
|
TNCOK = TNCInfo[MasterPort[port]]->CONNECTED;
|
|
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
if (STREAM->FramesOutstanding > 8)
|
|
return (1 | TNCOK << 8 | STREAM->Disconnecting << 15);
|
|
|
|
return TNCOK << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting
|
|
|
|
break;
|
|
|
|
case 4: // reinit
|
|
|
|
shutdown(TNC->TCPSock, SD_BOTH);
|
|
Sleep(100);
|
|
|
|
closesocket(TNC->TCPSock);
|
|
TNC->CONNECTED = FALSE;
|
|
|
|
if (TNC->PID && TNC->WeStartedTNC)
|
|
{
|
|
KillTNC(TNC);
|
|
RestartTNC(TNC);
|
|
}
|
|
|
|
return (0);
|
|
|
|
case 5: // Close
|
|
|
|
shutdown(TNC->TCPSock, SD_BOTH);
|
|
Sleep(100);
|
|
|
|
closesocket(TNC->TCPSock);
|
|
|
|
if (TNC->PID && TNC->WeStartedTNC)
|
|
{
|
|
KillTNC(TNC);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifndef LINBPQ
|
|
|
|
static KillTNC(struct TNCINFO * TNC)
|
|
{
|
|
HANDLE hProc;
|
|
|
|
if (TNC->PTTMode)
|
|
Rig_PTT(TNC, FALSE); // Make sure PTT is down
|
|
|
|
if (TNC->PID == 0) return 0;
|
|
|
|
hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, TNC->PID);
|
|
|
|
if (hProc)
|
|
{
|
|
TerminateProcess(hProc, 0);
|
|
CloseHandle(hProc);
|
|
}
|
|
|
|
TNC->PID = 0; // So we don't try again
|
|
|
|
return 0;
|
|
}
|
|
|
|
static RestartTNC(struct TNCINFO * TNC)
|
|
{
|
|
STARTUPINFO SInfo; // pointer to STARTUPINFO
|
|
PROCESS_INFORMATION PInfo; // pointer to PROCESS_INFORMATION
|
|
char HomeDir[MAX_PATH];
|
|
int i, ret;
|
|
|
|
SInfo.cb=sizeof(SInfo);
|
|
SInfo.lpReserved=NULL;
|
|
SInfo.lpDesktop=NULL;
|
|
SInfo.lpTitle=NULL;
|
|
SInfo.dwFlags=0;
|
|
SInfo.cbReserved2=0;
|
|
SInfo.lpReserved2=NULL;
|
|
|
|
if (TNC->ProgramPath && TNC->DontRestart == 0)
|
|
{
|
|
strcpy(HomeDir, TNC->ProgramPath);
|
|
i = strlen(HomeDir);
|
|
|
|
while(--i)
|
|
{
|
|
if (HomeDir[i] == '/' || HomeDir[i] == '\\')
|
|
{
|
|
HomeDir[i] = 0;
|
|
break;
|
|
}
|
|
}
|
|
ret = CreateProcess(TNC->ProgramPath, "MultiPSK TCP_IP_ON", NULL, NULL, FALSE,0 ,NULL ,HomeDir, &SInfo, &PInfo);
|
|
|
|
if (ret)
|
|
TNC->PID = PInfo.dwProcessId;
|
|
|
|
return ret;
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void * MPSKExtInit(EXTPORTDATA * PortEntry)
|
|
{
|
|
int i, port;
|
|
char Msg[255];
|
|
struct TNCINFO * TNC;
|
|
char * ptr;
|
|
|
|
//
|
|
// Will be called once for each MPSK port to be mapped to a BPQ Port
|
|
// The MPSK port number is in CHANNEL - A=0, B=1 etc
|
|
//
|
|
// The Socket to connect to is in IOBASE
|
|
//
|
|
|
|
port = PortEntry->PORTCONTROL.PORTNUMBER;
|
|
|
|
ReadConfigFile(port, ProcessLine);
|
|
|
|
TNC = TNCInfo[port];
|
|
|
|
if (TNC == NULL)
|
|
{
|
|
// Not defined in Config file
|
|
|
|
sprintf(Msg," ** Error - no info in BPQ32.cfg for this port\n");
|
|
WritetoConsole(Msg);
|
|
|
|
return ExtProc;
|
|
}
|
|
|
|
TNC->Port = port;
|
|
|
|
TNC->PortRecord = PortEntry;
|
|
|
|
if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
|
|
memcpy(TNC->NodeCall, MYNODECALL, 10);
|
|
else
|
|
ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
|
|
|
|
if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
|
|
TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
|
|
|
|
PortEntry->PORTCONTROL.PROTOCOL = 10;
|
|
PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream
|
|
PortEntry->PORTCONTROL.PORTQUALITY = 0;
|
|
PortEntry->SCANCAPABILITIES = NONE; // Scan Control - None
|
|
|
|
if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
|
|
PortEntry->PORTCONTROL.PORTPACLEN = 64;
|
|
|
|
ptr=strchr(TNC->NodeCall, ' ');
|
|
if (ptr) *(ptr) = 0; // Null Terminate
|
|
|
|
TNC->Hardware = H_MPSK;
|
|
|
|
MPSKChannel[port] = PortEntry->PORTCONTROL.CHANNELNUM-65;
|
|
|
|
PortEntry->MAXHOSTMODESESSIONS = 1;
|
|
|
|
i=sprintf(Msg,"MPSK Host %s Port %d \n",
|
|
TNC->HostName, TNC->TCPPort);
|
|
|
|
WritetoConsole(Msg);
|
|
|
|
// See if we already have a port for this host
|
|
|
|
MasterPort[port] = port;
|
|
|
|
for (i = 1; i < port; i++)
|
|
{
|
|
if (i == port) continue;
|
|
|
|
if (TNCInfo[i] && TNCInfo[i]->TCPPort == TNC->TCPPort &&
|
|
_stricmp(TNCInfo[i]->HostName, TNC->HostName) == 0)
|
|
{
|
|
MasterPort[port] = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
BPQPort[PortEntry->PORTCONTROL.CHANNELNUM-65][MasterPort[port]] = port;
|
|
|
|
#ifndef LINBPQ
|
|
if (MasterPort[port] == port)
|
|
{
|
|
if (EnumWindows(EnumTNCWindowsProc, (LPARAM)TNC))
|
|
if (TNC->ProgramPath)
|
|
TNC->WeStartedTNC = RestartTNC(TNC);
|
|
|
|
ConnecttoMPSK(port);
|
|
}
|
|
#endif
|
|
time(&lasttime[port]); // Get initial time value
|
|
|
|
// SendMessage(0x40eaa, WM_COMMAND, 0x03000eaa, 0x40eaa);
|
|
|
|
return ExtProc;
|
|
}
|
|
|
|
|
|
static int ProcessLine(char * buf, int Port)
|
|
{
|
|
UCHAR * ptr,* p_cmd;
|
|
char * p_ipad = 0;
|
|
char * p_port = 0;
|
|
unsigned short WINMORport = 0;
|
|
int BPQport;
|
|
int len=510;
|
|
struct TNCINFO * TNC;
|
|
struct MPSKINFO * AGW;
|
|
|
|
char errbuf[256];
|
|
|
|
strcpy(errbuf, buf);
|
|
|
|
ptr = strtok(buf, " \t\n\r");
|
|
|
|
if(ptr == NULL) return (TRUE);
|
|
|
|
if(*ptr =='#') return (TRUE); // comment
|
|
|
|
if(*ptr ==';') return (TRUE); // comment
|
|
|
|
if (_stricmp(buf, "ADDR"))
|
|
return FALSE; // Must start with ADDR
|
|
|
|
ptr = strtok(NULL, " \t\n\r");
|
|
|
|
BPQport = Port;
|
|
p_ipad = ptr;
|
|
|
|
TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO));
|
|
AGW = TNC->MPSKInfo = zalloc(sizeof(struct MPSKINFO)); // AGW Sream Mode Specific Data
|
|
|
|
AGW->MaxSessions = 10;
|
|
AGW->ConnTimeOut = CONTIMEOUT;
|
|
|
|
TNC->InitScript = malloc(1000);
|
|
TNC->InitScript[0] = 0;
|
|
|
|
if (p_ipad == NULL)
|
|
p_ipad = strtok(NULL, " \t\n\r");
|
|
|
|
if (p_ipad == NULL) return (FALSE);
|
|
|
|
p_port = strtok(NULL, " \t\n\r");
|
|
|
|
if (p_port == NULL) return (FALSE);
|
|
|
|
TNC->TCPPort = atoi(p_port);
|
|
|
|
TNC->destaddr.sin_family = AF_INET;
|
|
TNC->destaddr.sin_port = htons(TNC->TCPPort);
|
|
TNC->HostName = malloc(strlen(p_ipad)+1);
|
|
|
|
if (TNC->HostName == NULL) return TRUE;
|
|
|
|
strcpy(TNC->HostName,p_ipad);
|
|
|
|
ptr = strtok(NULL, " \t\n\r");
|
|
|
|
if (ptr)
|
|
{
|
|
if (_memicmp(ptr, "PATH", 4) == 0)
|
|
{
|
|
p_cmd = strtok(NULL, "\n\r");
|
|
if (p_cmd) TNC->ProgramPath = _strdup(p_cmd);
|
|
}
|
|
}
|
|
|
|
// Read Initialisation lines
|
|
|
|
while(TRUE)
|
|
{
|
|
if (GetLine(buf) == 0)
|
|
return TRUE;
|
|
|
|
strcpy(errbuf, buf);
|
|
|
|
if (memcmp(buf, "****", 4) == 0)
|
|
return TRUE;
|
|
|
|
ptr = strchr(buf, ';');
|
|
if (ptr)
|
|
{
|
|
*ptr++ = 13;
|
|
*ptr = 0;
|
|
}
|
|
|
|
if (_memicmp(buf, "CONTIMEOUT", 10) == 0)
|
|
AGW->ConnTimeOut = atoi(&buf[11]) * 10;
|
|
else
|
|
if (_memicmp(buf, "UPDATEMAP", 9) == 0)
|
|
TNC->PktUpdateMap = TRUE;
|
|
else
|
|
if (_memicmp(buf, "ALEBEACON", 9) == 0) // Send Beacon after each session
|
|
TNC->MPSKInfo->Beacon = TRUE;
|
|
else
|
|
if (_memicmp(buf, "DEFAULTMODE", 11) == 0) // Send Beacon after each session
|
|
strcpy(TNC->MPSKInfo->DefaultMode, &buf[12]);
|
|
else
|
|
|
|
strcat (TNC->InitScript, buf);
|
|
}
|
|
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
static int ConnecttoMPSK(int port)
|
|
{
|
|
_beginthread(ConnecttoMPSKThread, 0, (void *)(size_t)port);
|
|
|
|
return 0;
|
|
}
|
|
|
|
VOID ConnecttoMPSKThread(void * portptr)
|
|
{
|
|
|
|
int port = (int)(size_t)portptr;
|
|
char Msg[255];
|
|
int err,i;
|
|
u_long param=1;
|
|
BOOL bcopt=TRUE;
|
|
struct hostent * HostEnt;
|
|
struct TNCINFO * TNC = TNCInfo[port];
|
|
|
|
Sleep(5000); // Allow init to complete
|
|
|
|
TNC->destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
|
|
|
|
if (TNC->destaddr.sin_addr.s_addr == INADDR_NONE)
|
|
{
|
|
// Resolve name to address
|
|
|
|
HostEnt = gethostbyname (TNC->HostName);
|
|
|
|
if (!HostEnt) return; // Resolve failed
|
|
|
|
memcpy(&TNC->destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
|
|
memcpy(&TNC->Datadestaddr.sin_addr.s_addr,HostEnt->h_addr,4);
|
|
|
|
}
|
|
|
|
if (TNC->TCPSock)
|
|
closesocket(TNC->TCPSock);
|
|
|
|
TNC->TCPSock = 0;
|
|
|
|
TNC->TCPSock=socket(AF_INET,SOCK_STREAM,0);
|
|
|
|
if (TNC->TCPSock == INVALID_SOCKET)
|
|
{
|
|
i=sprintf(Msg, "Socket Failed for MPSK socket - error code = %d\n", WSAGetLastError());
|
|
WritetoConsole(Msg);
|
|
|
|
return;
|
|
}
|
|
|
|
sinx.sin_family = AF_INET;
|
|
sinx.sin_addr.s_addr = INADDR_ANY;
|
|
sinx.sin_port = 0;
|
|
|
|
TNC->CONNECTING = TRUE;
|
|
|
|
if (connect(TNC->TCPSock,(LPSOCKADDR) &TNC->destaddr,sizeof(TNC->destaddr)) == 0)
|
|
{
|
|
//
|
|
// Connected successful
|
|
//
|
|
|
|
TNC->CONNECTED=TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (TNC->Alerted == FALSE)
|
|
{
|
|
err=WSAGetLastError();
|
|
i=sprintf(Msg, "Connect Failed for MPSK socket - error code = %d\n", err);
|
|
WritetoConsole(Msg);
|
|
MySetWindowText(TNC->xIDC_COMMSSTATE, "Connection to TNC failed");
|
|
|
|
TNC->Alerted = TRUE;
|
|
}
|
|
|
|
TNC->CONNECTING = FALSE;
|
|
return;
|
|
}
|
|
|
|
TNC->LastFreq = 0; // so V4 display will be updated
|
|
|
|
MySetWindowText(TNC->xIDC_COMMSSTATE, "Connected to MPSK TNC");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static int ProcessReceivedData(int port)
|
|
{
|
|
unsigned int bytes;
|
|
int i;
|
|
char ErrMsg[255];
|
|
char Message[500];
|
|
struct TNCINFO * TNC = TNCInfo[port];
|
|
|
|
// Need to extract messages from byte stream
|
|
|
|
bytes = recv(TNC->TCPSock,(char *)&Message, 500, 0);
|
|
|
|
if (bytes == SOCKET_ERROR)
|
|
{
|
|
// i=sprintf(ErrMsg, "Read Failed for MPSK socket - error code = %d\r\n", WSAGetLastError());
|
|
// WritetoConsole(ErrMsg);
|
|
|
|
closesocket(TNC->TCPSock);
|
|
|
|
TNC->CONNECTED = FALSE;
|
|
if (TNC->Streams[0].Attached)
|
|
TNC->Streams[0].ReportDISC = TRUE;
|
|
|
|
return (0);
|
|
}
|
|
|
|
if (bytes == 0)
|
|
{
|
|
// zero bytes means connection closed
|
|
|
|
i=sprintf(ErrMsg, "MPSK Connection closed for BPQ Port %d\n", port);
|
|
WritetoConsole(ErrMsg);
|
|
|
|
TNC->CONNECTED = FALSE;
|
|
if (TNC->Streams[0].Attached)
|
|
TNC->Streams[0].ReportDISC = TRUE;
|
|
|
|
return (0);
|
|
}
|
|
|
|
// Have some data
|
|
|
|
ProcessMPSKPacket(TNC, Message, bytes); // Data may be for another port
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
VOID ProcessMSPKCmd(struct TNCINFO * TNC);
|
|
VOID ProcessMSPKComment(struct TNCINFO * TNC);
|
|
VOID ProcessMSPKData(struct TNCINFO * TNC);
|
|
|
|
VOID ProcessMPSKPacket(struct TNCINFO * TNC, char * Message, int Len)
|
|
{
|
|
char * MPTR = Message;
|
|
|
|
/*
|
|
3) each text character transmitted by the client to the server (for the Multipsk TX text editor) must be preceded by the character CHR(25) or CHR(22) in the case of a special link (KISS in Packet or Pax, for example).
|
|
|
|
4) each command string transmitted by the client to the server must be preceded by the character CHR(26) and finished by CHR(27),
|
|
|
|
5) each character effectively transmitted by Multipsk to the transceiver and transmitted to the client is preceded by the character CHR(28),
|
|
|
|
6) each character received by Multipsk and transmitted to the client is preceded by the character CHR(29),
|
|
|
|
7) each command string transmitted by the server to the client must be preceded by the character CHR(30) and finished by CHR(31),
|
|
|
|
8) all commands (written in readable text ) will have an answer (see further for details),
|
|
|
|
9) each server comment (Call ID or RS ID reception, switch to RX or to TX) string transmitted by the server to the client must be preceded by a string: "CHR(23)RX CALL ID=", "CHR(23)RX RS ID=", "CHR(23)SWITCH=RX", "CHR(23) SWITCH=TX", and finished by CHR(24).
|
|
|
|
10) each server command, for the transceiver control, transmitted by the server to the client must be preceded by the string "CHR(23) XCVR=" and finished by CHR(24).
|
|
|
|
Data
|
|
|
|
End of TX] ARQ FAE CQ[End of TX] ARQ FAE CQ[End of TX] call "THIS I[End of TX] end of link to GM8BPQ[End of TX] sounding "THIS WAS"[End of TX] ARQ FAE CQ[End of TX] ARQ FAE CQ[End of TX] ARQ FAE CQ[End of TX] ARQ FAE CQFAE BEACON OH5RM Kouvola KP30JR
|
|
[End of TX] ARQ FAE selective callGM8BPQ DE OH5RM
|
|
|
|
[Connection made with OH5RM]
|
|
|
|
|
|
18103 but I have to go out to change antenna
|
|
|
|
[End of connection with OH5RM]FAE BEACON OH5RM Kouvola KP30JR
|
|
S" to GM8BPQ
|
|
|
|
10:23:55 AM Comment: SWITCH=RX
|
|
10:24:00 AM Comment: RX RS ID=10:24:00 UTC ALE400 1609 Hz 0 MHz
|
|
10:24:19 AM Comment: RX RS ID=10:24:19 UTC ALE400 1604 Hz 0 MHz
|
|
10:25:04 AM Comment: SWITCH=TX
|
|
10:25:07 AM Comment: SWITCH=RX
|
|
10:25:15 AM Comment: SWITCH=TX
|
|
:30:22 AM Comment: SWITCH=RX
|
|
10:30:25 AM Comment: SWITCH=TX
|
|
10:30:27 AM Comment: SWITCH=RX
|
|
10:30:35 AM Comment: RX RS ID=10:30:35 UTC ALE400 1598 Hz 0 MHz
|
|
|
|
|
|
*/
|
|
|
|
// Reuse the HAL CMD and Data Buffers to build messages from TCP stream
|
|
|
|
// See if sequence split over a packet boundary
|
|
|
|
if (TNC->CmdEsc == 23)
|
|
{
|
|
TNC->CmdEsc = 0;
|
|
goto CommentEsc;
|
|
}
|
|
|
|
if (TNC->CmdEsc == 29)
|
|
{
|
|
TNC->CmdEsc = 0;
|
|
goto DataEsc;
|
|
}
|
|
|
|
if (TNC->CmdEsc == 30)
|
|
{
|
|
TNC->CmdEsc = 0;
|
|
goto CmdEsc;
|
|
}
|
|
|
|
// No Split
|
|
|
|
while(Len)
|
|
{
|
|
switch (*(MPTR++))
|
|
{
|
|
case 29: // Data Char
|
|
|
|
Len--;
|
|
DataEsc:
|
|
if (Len)
|
|
{
|
|
TNC->DataBuffer[TNC->DataLen++] = *MPTR;
|
|
MPTR++;
|
|
Len--;
|
|
goto OuterLoop;
|
|
}
|
|
|
|
TNC->CmdEsc = 29;
|
|
|
|
if (TNC->DataLen)
|
|
ProcessMSPKData(TNC);
|
|
|
|
|
|
return; // Nothing left
|
|
|
|
case 30:
|
|
|
|
Len --;
|
|
CmdEsc:
|
|
while (Len)
|
|
{
|
|
if (*MPTR == 31) // End of String
|
|
{
|
|
ProcessMSPKCmd(TNC);
|
|
TNC->CmdLen = 0;
|
|
|
|
// Process any data left in buffer
|
|
|
|
MPTR++;
|
|
Len--;
|
|
goto OuterLoop;
|
|
}
|
|
|
|
TNC->CmdBuffer[TNC->CmdLen++] = *MPTR;
|
|
MPTR++;
|
|
Len--;
|
|
}
|
|
|
|
TNC->CmdEsc = 30;
|
|
return; // Nothing left
|
|
|
|
case 23: // Server Comment
|
|
|
|
Len --;
|
|
CommentEsc:
|
|
while (Len)
|
|
{
|
|
if (*MPTR == 24) // End of String
|
|
{
|
|
// Process Comment
|
|
|
|
ProcessMSPKCmd(TNC);
|
|
TNC->CmdLen = 0;
|
|
|
|
// Process any data left in buffer
|
|
|
|
MPTR++;
|
|
Len--;
|
|
goto OuterLoop;
|
|
}
|
|
|
|
TNC->CmdBuffer[TNC->CmdLen++] = *MPTR;
|
|
MPTR++;
|
|
Len--;
|
|
}
|
|
|
|
TNC->CmdEsc = 23;
|
|
return; // Nothing left
|
|
|
|
default:
|
|
|
|
Len--;
|
|
|
|
}
|
|
OuterLoop:;
|
|
}
|
|
|
|
if (TNC->DataLen)
|
|
ProcessMSPKData(TNC);
|
|
}
|
|
|
|
VOID ProcessMSPKCmd(struct TNCINFO * TNC)
|
|
{
|
|
TNC->CmdBuffer[TNC->CmdLen] = 0;
|
|
|
|
if (strcmp(TNC->CmdBuffer, "SWITCH=TX") == 0)
|
|
TNC->MPSKInfo->TX = TRUE;
|
|
else
|
|
{
|
|
if (strcmp(TNC->CmdBuffer, "SWITCH=RX") == 0)
|
|
{
|
|
TNC->MPSKInfo->TX = FALSE;
|
|
|
|
// See if a command was queued while busy
|
|
|
|
if (TNC->CmdSet)
|
|
{
|
|
send(TNC->TCPSock, TNC->CmdSet, strlen(TNC->CmdSet), 0);
|
|
free (TNC->CmdSet);
|
|
TNC->CmdSet = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debugprintf("MPSK CMD %s", TNC->CmdBuffer);
|
|
|
|
if (TNC->InternalCmd)
|
|
{
|
|
PMSGWITHLEN buffptr = GetBuff();
|
|
char * ptr = strstr(TNC->CmdBuffer, "OK");
|
|
|
|
if (ptr)
|
|
*(ptr+2) = 0; // Convert OKn to OK for BBS Connect Script
|
|
|
|
TNC->InternalCmd = FALSE;
|
|
|
|
if (buffptr)
|
|
{
|
|
buffptr->Len= sprintf(buffptr->Data, "MPSK} %s\r", TNC->CmdBuffer);
|
|
C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
|
|
}
|
|
|
|
if (strstr(TNC->CmdBuffer, "STOP_SELECTIVE_CALL_ARQ_FAE OK"))
|
|
TNC->Streams[0].Connecting = FALSE;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
VOID ProcessMSPKComment(struct TNCINFO * TNC)
|
|
{
|
|
TNC->CmdBuffer[TNC->CmdLen] = 0;
|
|
Debugprintf("MPSK Comment %s", TNC->CmdBuffer);
|
|
}
|
|
|
|
static int UnStuff(UCHAR * inbuff, int len)
|
|
{
|
|
int i,txptr=0;
|
|
UCHAR c;
|
|
UCHAR * outbuff = inbuff;
|
|
|
|
for (i = 0; i < len; i++)
|
|
{
|
|
c = inbuff[i];
|
|
|
|
if (c == 0xc0)
|
|
c = inbuff[++i] - 0x20;
|
|
|
|
outbuff[txptr++]=c;
|
|
}
|
|
|
|
return txptr;
|
|
}
|
|
|
|
VOID ProcessMSPKData(struct TNCINFO * TNC)
|
|
{
|
|
PMSGWITHLEN buffptr;
|
|
|
|
int Stream = 0;
|
|
struct STREAMINFO * STREAM = &TNC->Streams[0];
|
|
char * ptr;
|
|
int Len = TNC->DataLen;
|
|
|
|
TNC->DataBuffer[TNC->DataLen] = 0;
|
|
|
|
// Process Data
|
|
|
|
if (STREAM->Connected)
|
|
{
|
|
ptr = strstr(TNC->DataBuffer, "[End of connection");
|
|
|
|
if (ptr)
|
|
{
|
|
// Disconnect
|
|
|
|
TNC->DataLen = 0;
|
|
|
|
if (STREAM->DiscWhenAllSent)
|
|
return; // Already notified
|
|
|
|
if (STREAM->Connecting)
|
|
{
|
|
// Report Connect Failed, and drop back to command mode
|
|
|
|
STREAM->Connecting = FALSE;
|
|
buffptr = GetBuff();
|
|
|
|
if (buffptr == 0) return; // No buffers, so ignore
|
|
|
|
buffptr->Len = sprintf(buffptr->Data, "MPSK} Failure with %s\r", STREAM->RemoteCall);
|
|
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
STREAM->DiscWhenAllSent = 10;
|
|
|
|
return;
|
|
}
|
|
|
|
// Release Session
|
|
|
|
STREAM->Connecting = FALSE;
|
|
STREAM->Connected = FALSE; // Back to Command Mode
|
|
STREAM->ReportDISC = TRUE; // Tell Node
|
|
|
|
STREAM->Disconnecting = FALSE;
|
|
STREAM->DiscWhenAllSent = 10;
|
|
STREAM->FramesOutstanding = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
// Pass to Application. Remove any transparency (hex 0xc0 used as an escape)
|
|
|
|
buffptr = GetBuff();
|
|
|
|
if (TNC->DataBuffer[TNC->DataLen - 1] == 0xc0)
|
|
return; // Last char is an escape, so wait for the escaped char to arrive
|
|
|
|
if (buffptr)
|
|
{
|
|
if (memchr(TNC->DataBuffer, 0xc0, TNC->DataLen))
|
|
TNC->DataLen = UnStuff(TNC->DataBuffer, TNC->DataLen);
|
|
|
|
buffptr->Len = TNC->DataLen;
|
|
memcpy(buffptr->Data, TNC->DataBuffer, TNC->DataLen);
|
|
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
|
|
STREAM->bytesRXed += TNC->DataLen;
|
|
}
|
|
|
|
TNC->DataLen = 0;
|
|
return;
|
|
}
|
|
|
|
// Not Connected. We get various status messages, including Connection made,
|
|
// but they may be split across packets, or have more that one to a packet.
|
|
// I think they are all CR/LF terminated . No they aren't!
|
|
|
|
// Look for [] this seems to be what is important
|
|
|
|
DataLoop:
|
|
|
|
if (memcmp(TNC->DataBuffer, "[End of TX] ARQ FAE CQ", 22) == 0)
|
|
{
|
|
// Remove string from buffer
|
|
|
|
if (Len == 22) // Most Likely
|
|
{
|
|
TNC->DataLen = 0;
|
|
return;
|
|
}
|
|
|
|
TNC->DataLen -= 22;
|
|
memmove(TNC->DataBuffer, &TNC->DataBuffer[22], Len - 21); //Copy Null
|
|
Len -= 22;
|
|
goto DataLoop;
|
|
|
|
}
|
|
|
|
ptr = strchr(TNC->DataBuffer, '[');
|
|
|
|
if (ptr)
|
|
{
|
|
// Start of a significant Message
|
|
|
|
char * eptr = strchr(TNC->DataBuffer, ']');
|
|
char CallFrom[20];
|
|
char * cptr ;
|
|
|
|
if (eptr == 0)
|
|
return; // wait for matching []
|
|
|
|
cptr = strstr(TNC->DataBuffer, "[Connection made with ");
|
|
|
|
// TNC->DataLen -= LineLen;
|
|
// memmove(TNC->DataBuffer, &TNC->DataBuffer[LineLen], 1 + Len - LineLen); //Copy Null
|
|
// Len -= LineLen;
|
|
// goto DataLoop;
|
|
|
|
|
|
if (cptr) // Have a connection
|
|
{
|
|
|
|
// Connected
|
|
|
|
memcpy(CallFrom, &cptr[22], 18);
|
|
cptr = strchr(CallFrom, ']');
|
|
if (cptr)
|
|
*cptr = 0;
|
|
|
|
if (STREAM->Connecting)
|
|
{
|
|
// Connect Complete
|
|
|
|
STREAM->Connected = TRUE;
|
|
STREAM->Connecting = FALSE;
|
|
STREAM->ConnectTime = time(NULL);
|
|
STREAM->bytesRXed = STREAM->bytesTXed = 0;
|
|
|
|
buffptr = GetBuff();
|
|
if (buffptr)
|
|
{
|
|
buffptr->Len = sprintf(buffptr->Data, "*** Connected to %s\r", CallFrom);
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Incoming. Look for a free Stream
|
|
|
|
STREAM->Connected = TRUE;
|
|
STREAM->ConnectTime = time(NULL);
|
|
STREAM->bytesRXed = STREAM->bytesTXed = 0;
|
|
|
|
UpdateMH(TNC, CallFrom, '+', 'I');
|
|
|
|
ProcessIncommingConnect(TNC, CallFrom, Stream, FALSE);
|
|
|
|
if (HFCTEXTLEN)
|
|
{
|
|
if (HFCTEXTLEN > 1)
|
|
SendData(TNC, HFCTEXT, HFCTEXTLEN);
|
|
}
|
|
else
|
|
{
|
|
if (FULL_CTEXT)
|
|
{
|
|
int Len = CTEXTLEN, CTPaclen = 50;
|
|
int Next = 0;
|
|
|
|
while (Len > CTPaclen) // CTEXT Paclen
|
|
{
|
|
SendData(TNC, &CTEXTMSG[Next], CTPaclen);
|
|
Next += CTPaclen;
|
|
Len -= CTPaclen;
|
|
}
|
|
SendData(TNC, &CTEXTMSG[Next], Len);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Doesnt contain [ - just discard
|
|
|
|
TNC->DataLen = 0;
|
|
Debugprintf(TNC->DataBuffer);
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
buffptr = GetBuff();
|
|
if (buffptr == 0) return; // No buffers, so ignore
|
|
|
|
buffptr[1] = RXHeader->DataLength;
|
|
memcpy(&buffptr[2], Message, RXHeader->DataLength);
|
|
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
return;
|
|
|
|
return;
|
|
|
|
|
|
case 'd': // Disconnected
|
|
|
|
|
|
|
|
case 'C':
|
|
|
|
// Connect. Can be Incoming or Outgoing
|
|
|
|
// "*** CONNECTED To Station [CALLSIGN]" When the other station starts the connection
|
|
// "*** CONNECTED With [CALLSIGN]" When we started the connection
|
|
|
|
*/
|
|
|
|
|
|
VOID SendData(struct TNCINFO * TNC, char * Msg, int MsgLen)
|
|
{
|
|
// Preceed each data byte with 25 (decimal)
|
|
|
|
char * NewMsg = malloc (MsgLen * 4);
|
|
int n;
|
|
UCHAR c;
|
|
int ExtraLen = 0;
|
|
char * ptr = NewMsg;
|
|
char * inptr = Msg;
|
|
SOCKET sock = TNCInfo[MasterPort[TNC->Port]]->TCPSock;
|
|
|
|
TNC->Streams[0].bytesTXed += MsgLen;
|
|
|
|
for (n = 0; n < MsgLen; n++)
|
|
{
|
|
*(ptr++) = 25;
|
|
c = *inptr++;
|
|
|
|
if (c < 0x20 || c == 0xc0)
|
|
{
|
|
if (c != 0x0d)
|
|
{
|
|
*ptr++ = 0x0c0;
|
|
*(ptr++) = 25;
|
|
*ptr++ = c + 0x20;
|
|
ExtraLen += 2;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
*ptr++ = c;
|
|
}
|
|
|
|
send(sock, NewMsg, MsgLen * 2 + ExtraLen, 0);
|
|
|
|
free(NewMsg);
|
|
}
|
|
|
|
VOID TidyClose(struct TNCINFO * TNC, int Stream)
|
|
{
|
|
char Command[80];
|
|
int len;
|
|
|
|
len = sprintf(Command,"%cSTOP_SELECTIVE_CALL_ARQ_FAE\x1b", '\x1a');
|
|
if (TNC->MPSKInfo->TX)
|
|
TNC->CmdSet = TNC->CmdSave = _strdup(Command); // Savde till not transmitting
|
|
else
|
|
send(TNC->TCPSock, Command, len, 0);
|
|
}
|
|
|
|
VOID ForcedClose(struct TNCINFO * TNC, int Stream)
|
|
{
|
|
TidyClose(TNC, Stream); // I don't think Hostmode has a DD
|
|
}
|
|
|
|
VOID CloseComplete(struct TNCINFO * TNC, int Stream)
|
|
{
|
|
char Cmd[80];
|
|
int Len;
|
|
|
|
sprintf(Cmd, "%d SCANSTART 15", TNC->Port);
|
|
Rig_Command( (TRANSPORTENTRY *) -1, Cmd);
|
|
|
|
Cmd[0] = 0;
|
|
|
|
if (TNC->MPSKInfo->DefaultMode[0])
|
|
sprintf(Cmd, "%cDIGITAL MODE %s\x1b", '\x1a', TNC->MPSKInfo->DefaultMode);
|
|
|
|
if (TNC->MPSKInfo->Beacon)
|
|
sprintf(Cmd, "%s%cBEACON_ARQ_FAE\x1b", Cmd, '\x1a');
|
|
|
|
Len = strlen(Cmd);
|
|
|
|
if(Len)
|
|
{
|
|
if (TNC->MPSKInfo->TX)
|
|
TNC->CmdSet = TNC->CmdSave = _strdup(Cmd); // Savde till not transmitting
|
|
else
|
|
send(TNC->TCPSock, Cmd, Len, 0);
|
|
}
|
|
}
|
|
|