linbpq/VARA.c

2540 lines
60 KiB
C

/*
Copyright 2001-2015 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
*/
//
// Interface to allow G8BPQ switch to use VARA Virtual TNC in a form
// of ax.25
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <time.h>
#include "CHeaders.h"
#ifdef WIN32
#include <Psapi.h>
#endif
int (WINAPI FAR *GetModuleFileNameExPtr)();
extern int (WINAPI FAR *EnumProcessesPtr)();
#define SD_RECEIVE 0x00
#define SD_SEND 0x01
#define SD_BOTH 0x02
#include "bpq32.h"
#include "tncinfo.h"
#define WSA_ACCEPT WM_USER + 1
#define WSA_DATA WM_USER + 2
#define WSA_CONNECT WM_USER + 3
static int Socket_Data(int sock, int error, int eventcode);
int KillTNC(struct TNCINFO * TNC);
int RestartTNC(struct TNCINFO * TNC);
int KillPopups(struct TNCINFO * TNC);
VOID MoveWindows(struct TNCINFO * TNC);
int SendReporttoWL2K(struct TNCINFO * TNC);
char * CheckAppl(struct TNCINFO * TNC, char * Appl);
int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
BOOL KillOldTNC(char * Path);
int VARASendData(struct TNCINFO * TNC, UCHAR * Buff, int Len);
VOID VARASendCommand(struct TNCINFO * TNC, char * Buff, BOOL Queue);
VOID VARAProcessDataPacket(struct TNCINFO * TNC, UCHAR * Data, int Length);
void CountRestarts(struct TNCINFO * TNC);
#ifndef LINBPQ
BOOL CALLBACK EnumVARAWindowsProc(HWND hwnd, LPARAM lParam);
#endif
static char ClassName[]="VARASTATUS";
static char WindowTitle[] = "VARA";
static int RigControlRow = 165;
#define WINMOR
#define NARROWMODE 21
#define WIDEMODE 22
#ifndef LINBPQ
#include <commctrl.h>
#endif
extern char * PortConfig[33];
extern int SemHeldByAPI;
static RECT Rect;
extern struct TNCINFO * TNCInfo[41]; // Records are Malloc'd
BOOL VARAStopPort(struct PORTCONTROL * PORT)
{
// Disable Port - close TCP Sockets or Serial Port
struct TNCINFO * TNC = PORT->TNC;
TNC->CONNECTED = FALSE;
TNC->Alerted = FALSE;
if (TNC->PTTMode)
Rig_PTT(TNC, FALSE); // Make sure PTT is down
if (TNC->Streams[0].Attached)
TNC->Streams[0].ReportDISC = TRUE;
if (TNC->TCPSock)
{
shutdown(TNC->TCPSock, SD_BOTH);
Sleep(100);
closesocket(TNC->TCPSock);
}
if (TNC->TCPDataSock)
{
shutdown(TNC->TCPDataSock, SD_BOTH);
Sleep(100);
closesocket(TNC->TCPDataSock);
}
TNC->TCPSock = 0;
TNC->TCPDataSock = 0;
KillTNC(TNC);
sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Stopped");
MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
return TRUE;
}
int ConnecttoVARA(int port);
BOOL VARAStartPort(struct PORTCONTROL * PORT)
{
// Restart Port - Open Sockets or Serial Port
struct TNCINFO * TNC = PORT->TNC;
ConnecttoVARA(TNC->Port);
TNC->lasttime = time(NULL);;
sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Restarted");
MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
return TRUE;
}
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;
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] = malloc(sizeof(struct TNCINFO));
memset(TNC, 0, sizeof(struct TNCINFO));
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);
WINMORport = atoi(p_port);
TNC->destaddr.sin_family = AF_INET;
TNC->destaddr.sin_port = htons(WINMORport);
TNC->Datadestaddr.sin_family = AF_INET;
TNC->Datadestaddr.sin_port = htons(WINMORport+1);
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 (_stricmp(ptr, "PTT") == 0)
{
ptr = strtok(NULL, " \t\n\r");
if (ptr)
{
DecodePTTString(TNC, ptr);
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);
}
}
TNC->MaxConReq = 10; // Default
// 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;
}
else if (_memicmp(buf, "BW2300", 6) == 0)
{
TNC->ARDOPCurrentMode[0] = 'W'; // Save current state for scanning
strcat(TNC->InitScript, buf);
TNC->DefaultMode = TNC->WL2KMode = 50;
}
else if (_memicmp(buf, "BW500", 5) == 0)
{
TNC->ARDOPCurrentMode[0] = 'N';
strcat(TNC->InitScript, buf);
TNC->DefaultMode = TNC->WL2KMode = 53;
}
else if (_memicmp(buf, "BW2750", 6) == 0)
{
TNC->ARDOPCurrentMode[0] = 'W'; // Save current state for scanning
strcat(TNC->InitScript, buf);
TNC->DefaultMode = TNC->WL2KMode = 54;
}
else if (_memicmp(buf, "FM1200", 6) == 0)
TNC->DefaultMode = TNC->WL2KMode = 51;
else if (_memicmp(buf, "FM9600", 5) == 0)
TNC->DefaultMode = TNC->WL2KMode = 52;
else if (standardParams(TNC, buf) == FALSE)
strcat(TNC->InitScript, buf);
}
return (TRUE);
}
void VARAThread(void * portptr);
int ConnecttoVARA(int port);
VOID VARAProcessReceivedData(struct TNCINFO * TNC);
VOID VARAProcessReceivedControl(struct TNCINFO * TNC);
VOID VARAReleaseTNC(struct TNCINFO * TNC);
VOID SuspendOtherPorts(struct TNCINFO * ThisTNC);
VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len);
#define MAXBPQPORTS 32
static time_t ltime;
static SOCKADDR_IN sinx;
static SOCKADDR_IN rxaddr;
static int addrlen=sizeof(sinx);
static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
{
size_t datalen;
PMSGWITHLEN buffptr;
char txbuff[500];
unsigned int bytes,txlen=0;
size_t Param;
HKEY hKey=0;
struct TNCINFO * TNC = TNCInfo[port];
struct STREAMINFO * STREAM = &TNC->Streams[0];
struct ScanEntry * Scan;
if (TNC == NULL)
return 0; // Port not defined
if (TNC->CONNECTED == 0)
{
// clear Q if not connected
while(TNC->BPQtoWINMOR_Q)
{
buffptr = Q_REM(&TNC->BPQtoWINMOR_Q);
if (buffptr)
ReleaseBuffer(buffptr);
}
}
switch (fn)
{
case 8:
return 0;
case 7:
// approx 100 mS Timer. May now be needed, as Poll can be called more frequently in some circumstances
// Check session limit timer
if ((STREAM->Connecting || STREAM->Connected) && !STREAM->Disconnecting)
{
if (TNC->SessionTimeLimit && STREAM->ConnectTime && time(NULL) > (TNC->SessionTimeLimit + STREAM->ConnectTime))
{
VARASendCommand(TNC, "ABORT\r", TRUE);
STREAM->Disconnecting = TRUE;
}
}
while (TNC->PortRecord->UI_Q)
{
buffptr = Q_REM(&TNC->PortRecord->UI_Q);
ReleaseBuffer(buffptr);
}
if (TNC->Busy) // Count down to clear
{
if ((TNC->BusyFlags & CDBusy) == 0) // TNC Has reported not busy
{
TNC->Busy--;
if (TNC->Busy == 0)
SetWindowText(TNC->xIDC_CHANSTATE, "Clear");
strcpy(TNC->WEB_CHANSTATE, "Clear");
}
}
if (TNC->BusyDelay)
{
// Still Busy?
if (InterlockedCheckBusy(TNC) == FALSE)
{
// No, so send
VARASendCommand(TNC, TNC->ConnectCmd, TRUE);
TNC->Streams[0].Connecting = TRUE;
memset(TNC->Streams[0].RemoteCall, 0, 10);
memcpy(TNC->Streams[0].RemoteCall, &TNC->ConnectCmd[8], strlen(TNC->ConnectCmd)-10);
sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
free(TNC->ConnectCmd);
TNC->BusyDelay = 0;
}
else
{
// Wait Longer
TNC->BusyDelay--;
if (TNC->BusyDelay == 0)
{
// Timed out - Send Error Response
PMSGWITHLEN buffptr = GetBuff();
TNC->Streams[0].Connecting = FALSE;
if (buffptr == 0) return (0); // No buffers, so ignore
buffptr->Len = 39;
memcpy(buffptr->Data,"Sorry, Can't Connect - Channel is busy\r", 39);
C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
free(TNC->ConnectCmd);
sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
}
}
}
return 0;
case 1: // poll
if (STREAM->NeedDisc)
{
STREAM->NeedDisc--;
if (STREAM->NeedDisc == 0)
{
// Send the DISCONNECT
VARASendCommand(TNC, "DISCONNECT\r", TRUE);
}
}
/*
{
struct tm * tm;
char Time[80];
TNC->Restarts++;
TNC->LastRestart = time(NULL);
tm = gmtime(&TNC->LastRestart);
sprintf_s(Time, sizeof(Time),"%04d/%02d/%02d %02d:%02dZ",
tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
MySetWindowText(TNC->xIDC_RESTARTTIME, Time);
strcpy(TNC->WEB_RESTARTTIME, Time);
sprintf_s(Time, sizeof(Time),"%d", TNC->Restarts);
MySetWindowText(TNC->xIDC_RESTARTS, Time);
strcpy(TNC->WEB_RESTARTS, Time);
*/
if (TNC->PortRecord->ATTACHEDSESSIONS[0] && TNC->Streams[0].Attached == 0)
{
// New Attach
int calllen;
char Msg[80];
TNC->Streams[0].Attached = TRUE;
calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, TNC->Streams[0].MyCall);
TNC->Streams[0].MyCall[calllen] = 0;
// Stop Listening, and set MYCALL to user's call
VARASendCommand(TNC, "LISTEN OFF\r", TRUE);
TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
// Stop other ports in same group
SuspendOtherPorts(TNC);
sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
// Stop Scanning
sprintf(Msg, "%d SCANSTOP", TNC->Port);
Rig_Command(-1, Msg);
}
if (TNC->Streams[0].Attached)
CheckForDetach(TNC, 0, &TNC->Streams[0], TidyClose, ForcedClose, CloseComplete);
if (TNC->Streams[0].ReportDISC)
{
TNC->Streams[0].ReportDISC = FALSE;
buff->PORT = 0;
return -1;
}
if (TNC->CONNECTED == FALSE && TNC->CONNECTING == FALSE)
{
// See if time to reconnect
time(&ltime);
if (ltime - TNC->lasttime > 9 )
{
TNC->lasttime = ltime;
ConnecttoVARA(port);
}
}
// See if any frames for this port
if (TNC->Streams[0].BPQtoPACTOR_Q) //Used for CTEXT
{
PMSGWITHLEN buffptr = Q_REM(&TNC->Streams[0].BPQtoPACTOR_Q);
txlen = (int)buffptr->Len;
memcpy(txbuff, buffptr->Data, txlen);
bytes = VARASendData(TNC, &txbuff[0], txlen);
STREAM->BytesTXed += bytes;
ReleaseBuffer(buffptr);
}
if (TNC->WINMORtoBPQ_Q != 0)
{
buffptr=Q_REM(&TNC->WINMORtoBPQ_Q);
datalen = buffptr->Len;
buff->PORT = 0; // Compatibility with Kam Driver
buff->PID = 0xf0;
memcpy(&buff->L2DATA[0], buffptr->Data, datalen);
datalen += sizeof(void *) + 4;
PutLengthinBuffer(buff, (int)datalen);
ReleaseBuffer(buffptr);
return (1);
}
return (0);
case 2: // send
if (!TNC->CONNECTED)
{
// Send Error Response
PMSGWITHLEN buffptr = GetBuff();
if (buffptr == 0) return (0); // No buffers, so ignore
buffptr->Len=36;
memcpy(buffptr->Data,"No Connection to VARA TNC\r", 36);
C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
return 0; // Don't try if not connected
}
if (TNC->Streams[0].BPQtoPACTOR_Q) //Used for CTEXT
{
PMSGWITHLEN buffptr = Q_REM(&TNC->Streams[0].BPQtoPACTOR_Q);
txlen = (int)buffptr->Len;
memcpy(txbuff, buffptr->Data, txlen);
bytes=send(TNC->TCPDataSock, buff->L2DATA, txlen, 0);
STREAM->BytesTXed += bytes;
WritetoTrace(TNC, txbuff, txlen);
ReleaseBuffer(buffptr);
}
if (TNC->SwallowSignon)
{
TNC->SwallowSignon = FALSE; // Discard *** connected
return 0;
}
txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1); // 1 as no PID
if (TNC->Streams[0].Connected)
{
STREAM->PacketsSent++;
bytes=send(TNC->TCPDataSock, buff->L2DATA, txlen, 0);
STREAM->BytesTXed += bytes;
WritetoTrace(TNC, buff->L2DATA, txlen);
}
else
{
if (_memicmp(buff->L2DATA, "D\r", 2) == 0 || _memicmp(buff->L2DATA, "BYE\r", 4) == 0)
{
TNC->Streams[0].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->CIRCUITINDEX, 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(&TNC->WINMORtoBPQ_Q, buffptr);
}
return 1;
}
if (_memicmp(buff->L2DATA, "OVERRIDEBUSY", 12) == 0)
{
PMSGWITHLEN buffptr = GetBuff();
TNC->OverrideBusy = TRUE;
if (buffptr)
{
buffptr->Len = sprintf(buffptr->Data, "VARA} OK\r");
C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
}
return 0;
}
if (_memicmp(&buff->L2DATA[0], "SessionTimeLimit", 16) == 0)
{
if (buff->L2DATA[16] != 13)
{
PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
TNC->SessionTimeLimit = atoi(&buff->L2DATA[16]) * 60;
if (buffptr)
{
buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "VARA} OK\r");
C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
}
return 0;
}
}
if (_memicmp(&buff->L2DATA[0], "CODEC TRUE", 9) == 0)
TNC->StartSent = TRUE;
if (_memicmp(&buff->L2DATA[0], "BW2300", 6) == 0)
{
TNC->ARDOPCurrentMode[0] = 'W'; // Save current state for scanning
TNC->WL2KMode = 50;
}
if (_memicmp(&buff->L2DATA[0], "BW500", 5) == 0)
{
TNC->ARDOPCurrentMode[0] = 'N';
TNC->WL2KMode = 53;
}
if (_memicmp(&buff->L2DATA[0], "D\r", 2) == 0)
{
TNC->Streams[0].ReportDISC = TRUE; // Tell Node
return 0;
}
// See if a Connect Command. If so set Connecting
if (toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect
{
char Connect[80];
char * ptr = strchr(&buff->L2DATA[2], 13);
if (ptr)
*ptr = 0;
_strupr(&buff->L2DATA[2]);
sprintf(Connect, "CONNECT %s %s\r", TNC->Streams[0].MyCall, &buff->L2DATA[2]);
// Need to set connecting here as if we delay for busy we may incorrectly process OK response
TNC->Streams[0].Connecting = TRUE;
// See if Busy
if (InterlockedCheckBusy(TNC))
{
// Channel Busy. Unless override set, wait
if (TNC->OverrideBusy == 0)
{
// Save Command, and wait up to 10 secs
sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
TNC->ConnectCmd = _strdup(Connect);
TNC->BusyDelay = TNC->BusyWait * 10; // BusyWait secs
return 0;
}
}
TNC->OverrideBusy = FALSE;
VARASendCommand(TNC, Connect, TRUE);
memset(TNC->Streams[0].RemoteCall, 0, 10);
strcpy(TNC->Streams[0].RemoteCall, &buff->L2DATA[2]);
sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
}
else
{
buff->L2DATA[(txlen++) - 1] = 13;
buff->L2DATA[(txlen) - 1] = 0;
VARASendCommand(TNC, &buff->L2DATA[0], TRUE);
}
}
return (0);
case 3:
// CHECK IF OK TO SEND (And check TNC Status)
if (TNC->Streams[0].Attached == 0)
return TNC->CONNECTED << 8 | 1;
return (TNC->CONNECTED << 8 | TNC->Streams[0].Disconnecting << 15); // OK
case 4: // reinit
shutdown(TNC->TCPSock, SD_BOTH);
Sleep(100);
closesocket(TNC->TCPSock);
if (TNC->PID && TNC->WeStartedTNC)
{
KillTNC(TNC);
RestartTNC(TNC);
}
return 0;
case 5: // Close
if (TNC->CONNECTED)
{
// GetSemaphore(&Semaphore, 52);
// VARASendCommand(TNC, "CLOSE", FALSE);
// FreeSemaphore(&Semaphore);
// Sleep(100);
}
shutdown(TNC->TCPSock, SD_BOTH);
Sleep(100);
closesocket(TNC->TCPSock);
if (TNC->WeStartedTNC)
KillTNC(TNC);
return 0;
case 6: // Scan Stop Interface
Param = (size_t)buff;
if (Param == 2) // Check Permission (shouldn't happen)
{
Debugprintf("Scan Check Permission called on VARA");
return 1; // OK to change
}
if (!TNC->CONNECTED)
return 0; // No connection so no interlock
if (Param == 1) // Request Permission
{
if (TNC->ConnectPending == 0 && TNC->PTTState == 0)
{
VARASendCommand(TNC, "LISTEN OFF\r", TRUE);
TNC->GavePermission = TRUE;
return 0; // OK to Change
}
if (TNC->ConnectPending)
TNC->ConnectPending--; // Time out if set too long
if (!TNC->ConnectPending)
return 0; // OK to Change
return TRUE;
}
if (Param == 3) // Release Permission
{
if (TNC->GavePermission)
{
TNC->GavePermission = FALSE;
if (TNC->ARDOPCurrentMode[0] != 'S') // Skip
VARASendCommand(TNC, "LISTEN ON\r", TRUE);
}
return 0;
}
// Param is Address of a struct ScanEntry
Scan = (struct ScanEntry *)buff;
if (Scan->VARAMode != TNC->ARDOPCurrentMode[0])
{
// Mode changed
if (TNC->ARDOPCurrentMode[0] == 'S')
{
VARASendCommand(TNC, "LISTEN ON\r", TRUE);
}
if (Scan->VARAMode == 'W') // Set Wide Mode
{
VARASendCommand(TNC, "BW2300\r", TRUE);
TNC->WL2KMode = 50;
}
if (Scan->VARAMode == 'T') // Set Wide Mode
{
VARASendCommand(TNC, "BW2750\r", TRUE);
TNC->WL2KMode = 54;
}
else if (Scan->VARAMode == 'N') // Set Narrow Mode
{
VARASendCommand(TNC, "BW500\r", TRUE);
TNC->WL2KMode = 53;
}
else if (Scan->VARAMode == 'S') // Skip
{
VARASendCommand(TNC, "LISTEN OFF\r", TRUE);
}
TNC->ARDOPCurrentMode[0] = Scan->VARAMode;
}
return 0;
}
return 0;
}
void CountRestarts(struct TNCINFO * TNC)
{
struct tm * tm;
char Time[80];
TNC->Restarts++;
TNC->LastRestart = time(NULL);
tm = gmtime(&TNC->LastRestart);
sprintf_s(Time, sizeof(Time),"%04d/%02d/%02d %02d:%02dZ",
tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
//MySetWindowText(TNC->xIDC_RESTARTTIME, Time);
//strcpy(TNC->WEB_RESTARTTIME, Time);
sprintf_s(Time, sizeof(Time),"%d", TNC->Restarts);
MySetWindowText(TNC->xIDC_RESTARTS, Time);
strcpy(TNC->WEB_RESTARTS, Time);
}
/*
char WebProcTemplate[] = "<html><meta http-equiv=expires content=0><meta http-equiv=refresh content=15>"
"<link rel='stylesheet' href='webproc.css'>\r\n"
"<script type=\"text/javascript\">\r\n"
"function ScrollOutput()\r\n"
"{var textarea = document.getElementById('textarea');"
"textarea.scrollTop = textarea.scrollHeight;}\r\n"
"function xxx(data){\r\n"
"req = new XMLHttpRequest();\r\n"
"req.open('POST', 'PortAction?%d', true);\r\n"
"req.send(data);alert(data + ' Sent');}\r\n"
"</script>"
"</head><title>%s</title></head><body id=Text onload=\"ScrollOutput()\">"
"<span class='dropdown'>"
"<button class='dropbtn'>Actions</button><span style=\"margin-left:120px;font-size:16px\"><b>%s</b></span>"
"<div class='dropdown-content'>"
"<a href='javascript:xxx(\"Abort\");'>Abort Session</a>"
"<a href='javascript:xxx(\"Kill\");'>Kill TNC</a>"
"<a href='javascript:xxx(\"KillRestart\");'>Kill and Restart TNC</a>"
"</div></span>";
*/
char WebProcTemplate[] = "<html><meta http-equiv=expires content=0>"
"<link rel='stylesheet' href='webproc.css'>\r\n"
"<script type=\"text/javascript\">\r\n"
"function ScrollOutput()\r\n"
"{var textarea = document.getElementById('textarea');"
"textarea.scrollTop = textarea.scrollHeight;}\r\n"
"function xxx(data){\r\n"
"req = new XMLHttpRequest();\r\n"
"req.open('POST', 'PortAction?%d', true);\r\n"
"req.send(data);alert(data + ' Sent');}\r\n"
"function yyy(data){\r\n"
"req = new XMLHttpRequest();\r\n"
"req.open('POST', 'freqOffset?%d', true);\r\n"
"req.send(data);}\r\n"
"myInt = setInterval('Refresh()', 15000 );\n"
"function Refresh( )\n"
"{location.reload()}\n"
"</script>\r\n"
"</head><title>%s</title></head><body id=Text onload=\"ScrollOutput()\">\r\n"
"<h2 style=\"margin-bottom: 0.2em; text-align:center\">%s</h2>"
"<span class='dropdown' style=\"position: absolute; left: 10;top: 12;\">"
"<button class='dropbtn'>Actions</button>\r\n"
"<span class='dropdown-content'>"
"<a href='javascript:xxx(\"Abort\");'>Abort Session</a>"
"<a href='javascript:xxx(\"Kill\");'>Kill TNC</a>"
"<a href='javascript:xxx(\"KillRestart\");'>Kill and Restart TNC</a>"
"</span></span>";
char sliderBit[] = "<span style=\"position: absolute; left: 380;top: 2;\"> TX Offset <span id='val'>%d</span></span>"
"<span style=\"position: absolute; left: 350;top: 22;\"><input type='range' min=-200 max=200 value=%d class='slider' id='myRange'></span>\r\n"
"<script>\r\n"
"var slider = document.getElementById('myRange');"
"var output = document.getElementById('val');"
"slider.oninput = function() {output.innerHTML = this.value;}\r\n"
"slider.onmouseout = function() {myInt = setInterval('Refresh()', 15000 );"
"output.innerHTML = this.value;yyy(this.value);}\r\n"
"slider.onmouseover = function() {clearInterval(myInt)};"
"</script>\r\n";
static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
{
int Len = sprintf(Buff, WebProcTemplate, TNC->Port, TNC->Port, "VARA Status", "VARA Status");
if (TNC->TXFreq)
Len += sprintf(&Buff[Len], sliderBit, TNC->TXOffset, TNC->TXOffset);
Len += sprintf(&Buff[Len], "<table style=\"text-align: left; width: 500px; font-family: monospace; align=center \" border=1 cellpadding=2 cellspacing=2>");
Len += sprintf(&Buff[Len], "<tr><td width=110px>Comms State</td><td>%s</td></tr>", TNC->WEB_COMMSSTATE);
Len += sprintf(&Buff[Len], "<tr><td>TNC State</td><td>%s</td></tr>", TNC->WEB_TNCSTATE);
Len += sprintf(&Buff[Len], "<tr><td>Mode</td><td>%s</td></tr>", TNC->WEB_MODE);
Len += sprintf(&Buff[Len], "<tr><td>Channel State</td><td>%s</td></tr>", TNC->WEB_CHANSTATE);
Len += sprintf(&Buff[Len], "<tr><td>S/N</td><td>%s</td></tr>", TNC->WEB_PROTOSTATE);
Len += sprintf(&Buff[Len], "<tr><td>Traffic</td><td>%s</td></tr>", TNC->WEB_TRAFFIC);
// Len += sprintf(&Buff[Len], "<tr><td>TNC Restarts</td><td></td></tr>", TNC->WEB_RESTARTS);
Len += sprintf(&Buff[Len], "</table>");
Len += sprintf(&Buff[Len], "<textarea rows=10 style=\"width:500px; height:250px;\" id=textarea >%s</textarea>", TNC->WebBuffer);
Len = DoScanLine(TNC, Buff, Len);
return Len;
}
VOID VARASuspendPort(struct TNCINFO * TNC)
{
VARASendCommand(TNC, "LISTEN OFF\r", TRUE);
}
VOID VARAReleasePort(struct TNCINFO * TNC)
{
VARASendCommand(TNC, "LISTEN ON\r", TRUE);
}
void * VARAExtInit(EXTPORTDATA * PortEntry)
{
int i, port;
char Msg[255];
char * ptr;
APPLCALLS * APPL;
struct TNCINFO * TNC;
int AuxCount = 0;
char Appl[11];
char * TempScript;
int line;
struct PORTCONTROL * PORT = &PortEntry->PORTCONTROL;
//
// Will be called once for each VARA port
//
// The Socket to connect to is in IOBASE
//
port = PortEntry->PORTCONTROL.PORTNUMBER;
ReadConfigFile(port, ProcessLine);
TNC = TNCInfo[port];
if (TNC->AutoStartDelay == 0)
TNC->AutoStartDelay = 2000;
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->ARDOPBuffer = malloc(8192);
TNC->ARDOPDataBuffer = malloc(8192);
if (TNC->ProgramPath)
TNC->WeStartedTNC = 1;
TNC->Hardware = H_VARA;
if (TNC->BusyWait == 0)
TNC->BusyWait = 10;
if (TNC->BusyHold == 0)
TNC->BusyHold = 1;
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->PORTCONTROL.PORTQUALITY = 0;
PortEntry->MAXHOSTMODESESSIONS = 1;
PortEntry->SCANCAPABILITIES = SIMPLE; // Scan Control - pending connect only
PortEntry->PORTCONTROL.UICAPABLE = FALSE;
if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
PortEntry->PORTCONTROL.PORTPACLEN = 236;
TNC->SuspendPortProc = VARASuspendPort;
TNC->ReleasePortProc = VARAReleasePort;
PortEntry->PORTCONTROL.PORTSTARTCODE = VARAStartPort;
PortEntry->PORTCONTROL.PORTSTOPCODE = VARAStopPort;
TNC->ModemCentre = 1500; // WINMOR is always 1500 Offset
ptr=strchr(TNC->NodeCall, ' ');
if (ptr) *(ptr) = 0; // Null Terminate
// Set Essential Params and MYCALL
// Put overridable ones on front, essential ones on end
TempScript = zalloc(1000);
// strcat(TempScript, "ROBUST False\r");
// Set MYCALL(S)
if (TNC->LISTENCALLS)
{
sprintf(Msg, "MYCALL %s", TNC->LISTENCALLS);
}
else
{
sprintf(Msg, "MYCALL %s", TNC->NodeCall);
for (i = 0; i < 32; i++)
{
APPL=&APPLCALLTABLE[i];
if (APPL->APPLCALL_TEXT[0] > ' ')
{
char * ptr;
memcpy(Appl, APPL->APPLCALL_TEXT, 10);
ptr=strchr(Appl, ' ');
if (ptr)
{
// *ptr++ = ' ';
*ptr = 0;
}
strcat(Msg, " ");
strcat(Msg, Appl);
AuxCount++;
if (AuxCount == 4) // Max 5 in MYCALL
break;
}
}
}
strcat(Msg, "\r");
strcat(TempScript, Msg);
strcat(TempScript, TNC->InitScript);
free(TNC->InitScript);
TNC->InitScript = TempScript;
strcat(TNC->InitScript,"LISTEN ON\r");
strcpy(TNC->CurrentMYC, TNC->NodeCall);
if (TNC->WL2K == NULL)
if (PortEntry->PORTCONTROL.WL2KInfo.RMSCall[0]) // Alrerady decoded
TNC->WL2K = &PortEntry->PORTCONTROL.WL2KInfo;
// if mode hasn't been set explicitly or via WL2KREPORT set to HF Wide mode (BW2300)
if (TNC->DefaultMode == 0)
{
if (TNC->WL2K && TNC->WL2K->mode >= 50 && TNC->WL2K->mode <= 53) // A VARA Mode
TNC->DefaultMode = TNC->WL2KMode = TNC->WL2K->mode;
else
TNC->DefaultMode = TNC->WL2KMode = 50; // Default to 2300
}
if (TNC->destaddr.sin_family == 0)
{
// not defined in config file, so use localhost and port from IOBASE
TNC->destaddr.sin_family = AF_INET;
TNC->destaddr.sin_port = htons(PortEntry->PORTCONTROL.IOBASE);
TNC->Datadestaddr.sin_family = AF_INET;
TNC->Datadestaddr.sin_port = htons(PortEntry->PORTCONTROL.IOBASE+1);
TNC->HostName=malloc(10);
if (TNC->HostName != NULL)
strcpy(TNC->HostName,"127.0.0.1");
}
PortEntry->PORTCONTROL.TNC = TNC;
TNC->WebWindowProc = WebProc;
TNC->WebWinX = 520;
TNC->WebWinY = 500;
TNC->WebBuffer = zalloc(5000);
TNC->WEB_COMMSSTATE = zalloc(100);
TNC->WEB_TNCSTATE = zalloc(100);
TNC->WEB_CHANSTATE = zalloc(100);
TNC->WEB_BUFFERS = zalloc(100);
TNC->WEB_PROTOSTATE = zalloc(100);
TNC->WEB_RESTARTTIME = zalloc(100);
TNC->WEB_RESTARTS = zalloc(100);
TNC->WEB_MODE = zalloc(20);
TNC->WEB_TRAFFIC = zalloc(100);
#ifndef LINBPQ
line = 6;
if (TNC->TXFreq)
{
CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow + 22, PacWndProc, 550, 450, ForcedClose);
InitCommonControls(); // loads common control's DLL
CreateWindowEx(0, "STATIC", "TX Tune", WS_CHILD | WS_VISIBLE, 10,line,120,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_TXTUNE = CreateWindowEx(0, TRACKBAR_CLASS, "", WS_CHILD | WS_VISIBLE, 116,line,200,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_TXTUNEVAL = CreateWindowEx(0, "STATIC", "0", WS_CHILD | WS_VISIBLE, 320,line,30,20, TNC->hDlg, NULL, hInstance, NULL);
SendMessage(TNC->xIDC_TXTUNE, TBM_SETRANGE, (WPARAM) TRUE, (LPARAM) MAKELONG(-200, 200)); // min. & max. positions
line += 22;
}
else
CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 450, ForcedClose);
CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,line,120,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,line,386,20, TNC->hDlg, NULL, hInstance, NULL);
line += 22;
CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,line,106,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,line,520,20, TNC->hDlg, NULL, hInstance, NULL);
line += 22;
CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,line,100,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,line,200,20, TNC->hDlg, NULL, hInstance, NULL);
line += 22;
CreateWindowEx(0, "STATIC", "Channel State", WS_CHILD | WS_VISIBLE, 10,line,110,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_CHANSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,line,144,20, TNC->hDlg, NULL, hInstance, NULL);
line += 22;
CreateWindowEx(0, "STATIC", "S/N", WS_CHILD | WS_VISIBLE,10,line,80,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_PROTOSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,line,374,20 , TNC->hDlg, NULL, hInstance, NULL);
line += 22;
CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,line,80,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "0 0 0 0", WS_CHILD | WS_VISIBLE,line,116,374,20 , TNC->hDlg, NULL, hInstance, NULL);
line += 22;
CreateWindowEx(0, "STATIC", "TNC Restarts", WS_CHILD | WS_VISIBLE,10,line,100,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_RESTARTS = CreateWindowEx(0, "STATIC", "0", WS_CHILD | WS_VISIBLE,116,line,20,20 , TNC->hDlg, NULL, hInstance, NULL);
CreateWindowEx(0, "STATIC", "Last Restart", WS_CHILD | WS_VISIBLE,140,line,100,20, TNC->hDlg, NULL, hInstance, NULL);
TNC->xIDC_RESTARTTIME = CreateWindowEx(0, "STATIC", "Never", WS_CHILD | WS_VISIBLE,250,line,200,20, TNC->hDlg, NULL, hInstance, NULL);
line += 22;
TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL,
0,line,250,300, TNC->hDlg, NULL, hInstance, NULL);
TNC->ClientHeight = 450;
TNC->ClientWidth = 500;
TNC->hMenu = CreatePopupMenu();
AppendMenu(TNC->hMenu, MF_STRING, WINMOR_KILL, "Kill VARA TNC");
AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTART, "Kill and Restart VARA TNC");
AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTARTAFTERFAILURE, "Restart TNC after failed Connection");
CheckMenuItem(TNC->hMenu, WINMOR_RESTARTAFTERFAILURE, (TNC->RestartAfterFailure) ? MF_CHECKED : MF_UNCHECKED);
AppendMenu(TNC->hMenu, MF_STRING, ARDOP_ABORT, "Abort Current Session");
MoveWindows(TNC);
#endif
Consoleprintf("VARA Host %s %d", TNC->HostName, htons(TNC->destaddr.sin_port));
ConnecttoVARA(port);
time(&TNC->lasttime); // Get initial time value
return ExtProc;
}
int ConnecttoVARA(int port)
{
if (TNCInfo[port]->CONNECTING || TNCInfo[port]->PortRecord->PORTCONTROL.PortStopped)
return 0;
_beginthread(VARAThread, 0, (void *)(size_t)port);
return 0;
}
VOID VARAThread(void * portptr)
{
// Opens sockets and looks for data on control and data sockets.
int port = (int)(size_t)portptr;
char Msg[255];
int err, i, ret;
u_long param=1;
BOOL bcopt=TRUE;
struct hostent * HostEnt;
struct TNCINFO * TNC = TNCInfo[port];
fd_set readfs;
fd_set errorfs;
struct timeval timeout;
char * ptr1;
char * ptr2;
PMSGWITHLEN buffptr;
if (TNC->HostName == NULL)
return;
TNC->BusyFlags = 0;
TNC->CONNECTING = TRUE;
Sleep(3000); // Allow init to complete
if (TNCInfo[port]->PortRecord->PORTCONTROL.PortStopped)
{
TNC->CONNECTING = FALSE;
return;
}
// printf("Starting VARA Thread\n");
// if on Windows and Localhost see if TNC is running
#ifdef WIN32
if (strcmp(TNC->HostName, "127.0.0.1") == 0)
{
// can only check if running on local host
TNC->PID = GetListeningPortsPID(TNC->destaddr.sin_port);
if (TNC->PID == 0)
goto TNCNotRunning;
// Get the File Name in case we want to restart it.
if (TNC->ProgramPath == NULL)
{
if (GetModuleFileNameExPtr)
{
HANDLE hProc;
char ExeName[256] = "";
hProc = OpenProcess(PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, FALSE, TNC->PID);
if (hProc)
{
GetModuleFileNameExPtr(hProc, 0, ExeName, 255);
CloseHandle(hProc);
TNC->ProgramPath = _strdup(ExeName);
}
}
}
goto TNCRunning;
}
#endif
TNCNotRunning:
// Not running or can't check, restart if we have a path
if (TNC->ProgramPath)
{
Consoleprintf("Trying to (re)start TNC %s", TNC->ProgramPath);
if (RestartTNC(TNC))
CountRestarts(TNC);
Sleep(TNC->AutoStartDelay);
}
TNCRunning:
if (TNC->Alerted == FALSE)
{
sprintf(TNC->WEB_COMMSSTATE, "Connecting to TNC");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
}
TNC->destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
TNC->Datadestaddr.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)
{
TNC->CONNECTING = FALSE;
sprintf(Msg, "Resolve Failed for VARA socket - error code = %d\r\n", WSAGetLastError());
WritetoConsole(Msg);
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);
}
// closesocket(TNC->TCPSock);
// closesocket(TNC->TCPDataSock);
TNC->TCPSock=socket(AF_INET,SOCK_STREAM,0);
if (TNC->TCPSock == INVALID_SOCKET)
{
i=sprintf(Msg, "Socket Failed for VARA socket - error code = %d\r\n", WSAGetLastError());
WritetoConsole(Msg);
TNC->CONNECTING = FALSE;
return;
}
TNC->TCPDataSock = socket(AF_INET,SOCK_STREAM,0);
if (TNC->TCPDataSock == INVALID_SOCKET)
{
i=sprintf(Msg, "Socket Failed for VARA Data socket - error code = %d\r\n", WSAGetLastError());
WritetoConsole(Msg);
TNC->CONNECTING = FALSE;
closesocket(TNC->TCPSock);
return;
}
setsockopt(TNC->TCPSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
setsockopt(TNC->TCPDataSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
// setsockopt(TNC->TCPDataSock, IPPROTO_TCP, TCP_NODELAY, (const char FAR *)&bcopt, 4);
sinx.sin_family = AF_INET;
sinx.sin_addr.s_addr = INADDR_ANY;
sinx.sin_port = 0;
// printf("Trying to connect to VARA TNC\n");
if (connect(TNC->TCPSock,(LPSOCKADDR) &TNC->destaddr,sizeof(TNC->destaddr)) == 0)
{
// Connected successful
goto VConnected;
}
if (TNC->Alerted == FALSE)
{
err=WSAGetLastError();
sprintf(Msg, "Connect Failed for VARA socket - error code = %d Port %d\n",
err, htons(TNC->destaddr.sin_port));
WritetoConsole(Msg);
TNC->Alerted = TRUE;
sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC failed");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
}
// printf("VARA Connect failed\n");
closesocket(TNC->TCPSock);
closesocket(TNC->TCPDataSock);
TNC->TCPSock = 0;
TNC->CONNECTING = FALSE;
return;
VConnected:
// Connect Data Port
if (connect(TNC->TCPDataSock,(LPSOCKADDR) &TNC->Datadestaddr,sizeof(TNC->Datadestaddr)) == 0)
{
//
// Connected successful
//
}
else
{
if (TNC->Alerted == FALSE)
{
err=WSAGetLastError();
i=sprintf(Msg, "Connect Failed for VARA Data socket - error code = %d\r\n", err);
WritetoConsole(Msg);
sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC failed");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
TNC->Alerted = TRUE;
}
closesocket(TNC->TCPSock);
closesocket(TNC->TCPDataSock);
TNC->TCPSock = 0;
TNC->CONNECTING = FALSE;
RestartTNC(TNC);
return;
}
Sleep(1000);
TNC->LastFreq = 0;
TNC->CONNECTING = FALSE;
TNC->CONNECTED = TRUE;
TNC->BusyFlags = 0;
TNC->InputLen = 0;
// Send INIT script
// VARA needs each command in a separate send
ptr1 = &TNC->InitScript[0];
// We should wait for first RDY. Cheat by queueing a null command
GetSemaphore(&Semaphore, 52);
while(TNC->BPQtoWINMOR_Q)
{
buffptr = Q_REM(&TNC->BPQtoWINMOR_Q);
if (buffptr)
ReleaseBuffer(buffptr);
}
while (ptr1 && ptr1[0])
{
unsigned char c;
ptr2 = strchr(ptr1, 13);
if (ptr2)
{
c = *(ptr2 + 1); // Save next char
*(ptr2 + 1) = 0; // Terminate string
}
VARASendCommand(TNC, ptr1, TRUE);
if (ptr2)
*(1 + ptr2++) = c; // Put char back
ptr1 = ptr2;
}
TNC->Alerted = TRUE;
sprintf(TNC->WEB_COMMSSTATE, "Connected to VARA TNC");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
FreeSemaphore(&Semaphore);
sprintf(Msg, "Connected to VARA TNC Port %d\r\n", TNC->Port);
WritetoConsole(Msg);
#ifndef LINBPQ
// FreeSemaphore(&Semaphore);
Sleep(1000); // Give VARA time to update Window title
EnumWindows(EnumVARAWindowsProc, (LPARAM)TNC);
// GetSemaphore(&Semaphore, 52);
#endif
while (TNC->CONNECTED)
{
FD_ZERO(&readfs);
FD_ZERO(&errorfs);
FD_SET(TNC->TCPSock,&readfs);
FD_SET(TNC->TCPSock,&errorfs);
if (TNC->CONNECTED) FD_SET(TNC->TCPDataSock,&readfs);
// FD_ZERO(&writefs);
// if (TNC->BPQtoWINMOR_Q) FD_SET(TNC->TCPDataSock,&writefs); // Need notification of busy clearing
if (TNC->CONNECTING || TNC->CONNECTED) FD_SET(TNC->TCPDataSock,&errorfs);
timeout.tv_sec = 90;
timeout.tv_usec = 0; // We should get messages more frequently that this
ret = select((int)TNC->TCPDataSock + 1, &readfs, NULL, &errorfs, &timeout);
if (ret == SOCKET_ERROR)
{
Debugprintf("VARA Select failed %d ", WSAGetLastError());
goto Lost;
}
if (ret > 0)
{
// See what happened
if (FD_ISSET(TNC->TCPSock, &readfs))
{
GetSemaphore(&Semaphore, 52);
VARAProcessReceivedControl(TNC);
FreeSemaphore(&Semaphore);
}
if (FD_ISSET(TNC->TCPDataSock, &readfs))
{
GetSemaphore(&Semaphore, 52);
VARAProcessReceivedData(TNC);
FreeSemaphore(&Semaphore);
}
if (FD_ISSET(TNC->TCPSock, &errorfs))
{
Lost:
sprintf(Msg, "VARA Connection lost for Port %d\r\n", TNC->Port);
WritetoConsole(Msg);
sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
TNC->CONNECTED = FALSE;
TNC->Alerted = FALSE;
if (TNC->PTTMode)
Rig_PTT(TNC, FALSE); // Make sure PTT is down
if (TNC->Streams[0].Attached)
TNC->Streams[0].ReportDISC = TRUE;
closesocket(TNC->TCPSock);
closesocket(TNC->TCPDataSock);
TNC->TCPSock = 0;
break;
}
if (FD_ISSET(TNC->TCPDataSock, &errorfs))
{
sprintf(Msg, "VARA Connection lost for Port %d\r\n", TNC->Port);
WritetoConsole(Msg);
sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
TNC->CONNECTED = FALSE;
TNC->Alerted = FALSE;
if (TNC->PTTMode)
Rig_PTT(TNC, FALSE); // Make sure PTT is down
if (TNC->Streams[0].Attached)
TNC->Streams[0].ReportDISC = TRUE;
closesocket(TNC->TCPSock);
closesocket(TNC->TCPDataSock);
TNC->TCPSock = 0;
break;
}
continue;
}
else
{
// 60 secs without data. Shouldn't happen
continue;
sprintf(Msg, "VARA No Data Timeout Port %d\r\n", TNC->Port);
WritetoConsole(Msg);
// sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
// GetSemaphore(&Semaphore, 52);
// MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
// FreeSemaphore(&Semaphore);
TNC->CONNECTED = FALSE;
TNC->Alerted = FALSE;
if (TNC->PTTMode)
Rig_PTT(TNC, FALSE); // Make sure PTT is down
if (TNC->Streams[0].Attached)
TNC->Streams[0].ReportDISC = TRUE;
// GetSemaphore(&Semaphore, 52);
// VARASendCommand(TNC, "CODEC FALSE", FALSE);
// FreeSemaphore(&Semaphore);
Sleep(100);
shutdown(TNC->TCPSock, SD_BOTH);
Sleep(100);
closesocket(TNC->TCPSock);
Sleep(100);
shutdown(TNC->TCPDataSock, SD_BOTH);
Sleep(100);
closesocket(TNC->TCPDataSock);
// if (TNC->PID && TNC->WeStartedTNC)
// {
// KillTNC(TNC);
//
break;
}
}
if (TNC->TCPSock)
{
shutdown(TNC->TCPSock, SD_BOTH);
Sleep(100);
closesocket(TNC->TCPSock);
}
if (TNC->TCPDataSock)
{
shutdown(TNC->TCPDataSock, SD_BOTH);
Sleep(100);
closesocket(TNC->TCPDataSock);
}
sprintf(Msg, "VARA Thread Terminated Port %d\r\n", TNC->Port);
WritetoConsole(Msg);
}
VOID VARAProcessResponse(struct TNCINFO * TNC, UCHAR * Buffer, int MsgLen)
{
PMSGWITHLEN buffptr;
struct STREAMINFO * STREAM = &TNC->Streams[0];
Buffer[MsgLen - 1] = 0; // Remove CR
TNC->TimeSinceLast = 0;
if (_memicmp(Buffer, "PTT ON", 6) == 0)
{
// Debugprintf("PTT On");
TNC->Busy = TNC->BusyHold * 10; // BusyHold delay
if (TNC->PTTMode)
Rig_PTT(TNC, TRUE);
return;
}
if (_memicmp(Buffer, "PTT OFF", 6) == 0)
{
// Debugprintf("PTT Off");
if (TNC->PTTMode)
Rig_PTT(TNC, FALSE);
return;
}
if (_memicmp(Buffer, "SN ", 3) == 0)
{
strcpy(TNC->WEB_PROTOSTATE, &Buffer[3]);
MySetWindowText(TNC->xIDC_PROTOSTATE, TNC->WEB_PROTOSTATE);
TNC->SNR = atof(&Buffer[3]);
return;
}
if (_stricmp(Buffer, "BUSY ON") == 0)
{
TNC->BusyFlags |= CDBusy;
TNC->Busy = TNC->BusyHold * 10; // BusyHold delay
MySetWindowText(TNC->xIDC_CHANSTATE, "Busy");
strcpy(TNC->WEB_CHANSTATE, "Busy");
TNC->WinmorRestartCodecTimer = time(NULL);
return;
}
if (_stricmp(Buffer, "BUSY OFF") == 0)
{
TNC->BusyFlags &= ~CDBusy;
if (TNC->BusyHold)
strcpy(TNC->WEB_CHANSTATE, "BusyHold");
else
strcpy(TNC->WEB_CHANSTATE, "Clear");
MySetWindowText(TNC->xIDC_CHANSTATE, TNC->WEB_CHANSTATE);
TNC->WinmorRestartCodecTimer = time(NULL);
return;
}
if (_memicmp(&Buffer[0], "PENDING", 7) == 0) // Save Pending state for scan control
{
TNC->ConnectPending = 6; // Time out after 6 Scanintervals
Debugprintf(Buffer);
// WritetoTrace(TNC, Buffer, MsgLen - 1);
return;
}
if (_memicmp(&Buffer[0], "CANCELPENDING", 13) == 0)
{
TNC->ConnectPending = FALSE;
Debugprintf(Buffer);
// If a callsign is present it is the calling station - add to MH
if (TNC->SeenCancelPending == 0)
{
WritetoTrace(TNC, Buffer, MsgLen - 1);
TNC->SeenCancelPending = 1;
}
if (Buffer[13] == ' ')
UpdateMH(TNC, &Buffer[14], '!', 'I');
return;
}
TNC->SeenCancelPending = 0;
if (strcmp(Buffer, "OK") == 0)
{
// Need to discard response to LISTEN OFF after attach
if (TNC->DiscardNextOK)
{
TNC->DiscardNextOK = 0;
return;
}
if (TNC->Streams[0].Connecting == TRUE)
return; // Discard response or it will mess up connect scripts
}
if (_memicmp(Buffer, "BUFFER", 6) == 0)
{
Debugprintf(Buffer);
sscanf(&Buffer[7], "%d", &TNC->Streams[0].BytesOutstanding);
if (TNC->Streams[0].BytesOutstanding == 0)
{
// all sent
if (TNC->Streams[0].Disconnecting) // Disconnect when all sent
{
if (STREAM->NeedDisc == 0)
STREAM->NeedDisc = 60; // 6 secs
}
}
else
{
// Make sure Node Keepalive doesn't kill session.
TRANSPORTENTRY * SESS = TNC->PortRecord->ATTACHEDSESSIONS[0];
if (SESS)
{
SESS->L4KILLTIMER = 0;
SESS = SESS->L4CROSSLINK;
if (SESS)
SESS->L4KILLTIMER = 0;
}
}
sprintf(TNC->WEB_TRAFFIC, "Sent %d RXed %d Queued %s",
STREAM->BytesTXed, STREAM->BytesRXed, &Buffer[7]);
MySetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC);
return;
}
if (_memicmp(Buffer, "CONNECTED ", 10) == 0)
{
char Call[11];
char * ptr;
APPLCALLS * APPL;
char * ApplPtr = APPLS;
int App;
char Appl[10];
struct WL2KInfo * WL2K = TNC->WL2K;
int Speed = 0;
Debugprintf(Buffer);
WritetoTrace(TNC, Buffer, MsgLen - 1);
STREAM->ConnectTime = time(NULL);
STREAM->BytesRXed = STREAM->BytesTXed = STREAM->PacketsSent = 0;
strcpy(TNC->WEB_MODE, "");
if (strstr(Buffer, "2300"))
{
Speed = 50;
strcpy(TNC->WEB_MODE, "2300");
}
else if (strstr(Buffer, "NARROW"))
{
Speed = 51;
strcpy(TNC->WEB_MODE, "NARROW");
}
else if (strstr(Buffer, "WIDE"))
{
Speed = 52;
strcpy(TNC->WEB_MODE, "WIDE");
}
else if (strstr(Buffer, "500"))
{
Speed = 53;
strcpy(TNC->WEB_MODE, "500");
}
else if (strstr(Buffer, "2750"))
{
Speed = 54;
strcpy(TNC->WEB_MODE, "2750");
}
MySetWindowText(TNC->xIDC_MODE, TNC->WEB_MODE);
memcpy(Call, &Buffer[10], 10);
ptr = strchr(Call, ' ');
if (ptr) *ptr = 0;
// Get Target Call
ptr = strchr(&Buffer[10], ' ');
if (ptr)
{
memcpy(TNC->TargetCall, ++ptr, 10);
strlop(TNC->TargetCall, ' ');
}
TNC->HadConnect = TRUE;
if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0)
{
TRANSPORTENTRY * SESS;
// Incoming Connect
// Stop other ports in same group
SuspendOtherPorts(TNC);
TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
ProcessIncommingConnectEx(TNC, Call, 0, TRUE, TRUE);
SESS = TNC->PortRecord->ATTACHEDSESSIONS[0];
if (Speed)
SESS->Mode = Speed;
else
SESS->Mode = TNC->WL2KMode;
TNC->ConnectPending = FALSE;
if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT"))
{
sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", TNC->Streams[0].RemoteCall, TNC->TargetCall, TNC->RIG->Valchar);
SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq
if (SESS->Frequency == 1500)
{
// try to get from WL2K record
if (WL2K)
SESS->Frequency = WL2K->Freq;
}
}
else
{
sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", TNC->Streams[0].RemoteCall, TNC->TargetCall);
if (WL2K)
SESS->Frequency = WL2K->Freq;
}
if (WL2K)
strcpy(SESS->RMSCall, WL2K->RMSCall);
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
// Check for ExcludeList
if (ExcludeList[0])
{
if (CheckExcludeList(SESS->L4USER) == FALSE)
{
char Status[64];
TidyClose(TNC, 0);
sprintf(Status, "%d SCANSTART 15", TNC->Port);
Rig_Command(-1, Status);
Debugprintf("VARA Call from %s rejected", Call);
return;
}
}
// IF WE HAVE A PERMITTED CALLS LIST, SEE IF HE IS IN IT
if (TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS)
{
UCHAR * ptr = TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS;
while (TRUE)
{
if (memcmp(SESS->L4USER, ptr, 6) == 0) // Ignore SSID
break;
ptr += 7;
if ((*ptr) == 0) // Not in list
{
char Status[64];
TidyClose(TNC, 0);
sprintf(Status, "%d SCANSTART 15", TNC->Port);
Rig_Command(-1, Status);
Debugprintf("VARA Call from %s not in ValidCalls - rejected", Call);
return;
}
}
}
// See which application the connect is for
for (App = 0; App < 32; App++)
{
APPL=&APPLCALLTABLE[App];
memcpy(Appl, APPL->APPLCALL_TEXT, 10);
ptr=strchr(Appl, ' ');
if (ptr)
*ptr = 0;
if (_stricmp(TNC->TargetCall, Appl) == 0)
break;
}
if (App < 32)
{
char AppName[13];
memcpy(AppName, &ApplPtr[App * sizeof(CMDX)], 12);
AppName[12] = 0;
// if SendTandRtoRelay set and Appl is RMS change to RELAY
if (TNC->SendTandRtoRelay && memcmp(AppName, "RMS ", 4) == 0
&& (strstr(Call, "-T" ) || strstr(Call, "-R")))
strcpy(AppName, "RELAY ");
// Make sure app is available
if (CheckAppl(TNC, AppName))
{
MsgLen = sprintf(Buffer, "%s\r", AppName);
buffptr = GetBuff();
if (buffptr == 0)
{
return; // No buffers, so ignore
}
buffptr->Len = MsgLen;
memcpy(buffptr->Data, Buffer, MsgLen);
C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
TNC->SwallowSignon = TRUE;
// Save Appl Call in case needed for
}
else
{
char Msg[] = "Application not available\r";
// Send a Message, then a disconenct
// Send CTEXT First
if (TNC->Streams[0].BPQtoPACTOR_Q) //Used for CTEXT
{
PMSGWITHLEN buffptr = Q_REM(&TNC->Streams[0].BPQtoPACTOR_Q);
int txlen = (int)buffptr->Len;
VARASendData(TNC, buffptr->Data, txlen);
ReleaseBuffer(buffptr);
}
VARASendData(TNC, Msg, (int)strlen(Msg));
STREAM->NeedDisc = 100; // 10 secs
}
}
return;
}
else
{
// Connect Complete
char Reply[80];
int ReplyLen;
buffptr = GetBuff();
if (buffptr == 0)
{
return; // No buffers, so ignore
}
ReplyLen = sprintf(Reply, "*** Connected to %s\r", TNC->TargetCall);
buffptr->Len = ReplyLen;
memcpy(buffptr->Data, Reply, ReplyLen);
C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
TNC->Streams[0].Connecting = FALSE;
TNC->Streams[0].Connected = TRUE; // Subsequent data to data channel
if (TNC->RIG && TNC->RIG->Valchar[0])
sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall, TNC->RIG->Valchar);
else
sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
UpdateMH(TNC, TNC->TargetCall, '+', 'O');
return;
}
}
if (_memicmp(Buffer, "DISCONNECTED", 12) == 0)
{
Debugprintf(Buffer);
TNC->ConnectPending = FALSE; // Cancel Scan Lock
if (TNC->StartSent)
{
TNC->StartSent = FALSE; // Disconnect reported following start codec
return;
}
if (TNC->Streams[0].Connecting)
{
// Report Connect Failed, and drop back to command mode
TNC->Streams[0].Connecting = FALSE;
buffptr = GetBuff();
if (buffptr == 0)
{
return; // No buffers, so ignore
}
buffptr->Len = sprintf(buffptr->Data, "VARA} Failure with %s\r", TNC->Streams[0].RemoteCall);
C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
if (TNC->RestartAfterFailure)
{
if (TNC->ProgramPath)
KillTNC(TNC);
}
return;
}
WritetoTrace(TNC, Buffer, MsgLen - 1);
// Release Session
if (TNC->Streams[0].Connected)
{
// Create a traffic record
char logmsg[120];
time_t Duration;
Duration = time(NULL) - STREAM->ConnectTime;
if (Duration == 0)
Duration = 1;
sprintf(logmsg,"Port %2d %9s Bytes Sent %d BPS %d Bytes Received %d BPS %d Time %d Seconds",
TNC->Port, STREAM->RemoteCall,
STREAM->BytesTXed, (int)(STREAM->BytesTXed/Duration),
STREAM->BytesRXed, (int)(STREAM->BytesRXed/Duration), (int)Duration);
Debugprintf(logmsg);
}
TNC->Streams[0].Connecting = FALSE;
TNC->Streams[0].Connected = FALSE; // Back to Command Mode
TNC->Streams[0].ReportDISC = TRUE; // Tell Node
if (TNC->Streams[0].Disconnecting) //
VARAReleaseTNC(TNC);
TNC->Streams[0].Disconnecting = FALSE;
return;
}
if (_memicmp(Buffer, "IAMALIVE", 8) == 0)
{
// strcat(Buffer, "\r\n");
// WritetoTrace(TNC, Buffer, strlen(Buffer));
return;
}
// Debugprintf(Buffer);
if (_memicmp(Buffer, "FAULT", 5) == 0)
{
WritetoTrace(TNC, Buffer, MsgLen - 3);
// return;
}
if (_memicmp(Buffer, "REGISTERED", 9) == 0)
{
strcat(Buffer, "\r");
WritetoTrace(TNC, Buffer, (int)strlen(Buffer));
return;
}
if (_memicmp(Buffer, "MISSING SOUNDCARD", 17) == 0)
{
strcat(Buffer, "\r");
WritetoTrace(TNC, Buffer, (int)strlen(Buffer));
return;
}
// Others should be responses to commands
// Return others to user (if attached but not connected)
if (TNC->Streams[0].Attached == 0)
return;
if (TNC->Streams[0].Connected)
return;
if (MsgLen > 200)
MsgLen = 200;
buffptr = GetBuff();
if (buffptr == 0)
{
return; // No buffers, so ignore
}
buffptr->Len = sprintf(buffptr->Data, "VARA} %s\r", Buffer);
C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
}
VOID VARAProcessReceivedData(struct TNCINFO * TNC)
{
int InputLen;
InputLen = recv(TNC->TCPDataSock, TNC->ARDOPDataBuffer, 8192, 0);
if (InputLen == 0 || InputLen == SOCKET_ERROR)
{
// Does this mean closed?
// closesocket(TNC->TCPSock);
sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
TNC->CONNECTED = FALSE;
TNC->Alerted = FALSE;
if (TNC->PTTMode)
Rig_PTT(TNC, FALSE); // Make sure PTT is down
if (TNC->Streams[0].Attached)
TNC->Streams[0].ReportDISC = TRUE;
closesocket(TNC->TCPDataSock);
TNC->TCPSock = 0;
return;
}
TNC->DataInputLen += InputLen;
VARAProcessDataPacket(TNC, TNC->ARDOPDataBuffer, TNC->DataInputLen);
TNC->DataInputLen=0;
return;
}
VOID VARAProcessReceivedControl(struct TNCINFO * TNC)
{
int InputLen, MsgLen;
char * ptr, * ptr2;
char Buffer[4096];
// shouldn't get several messages per packet, as each should need an ack
// May get message split over packets
if (TNC->InputLen > 8000) // Shouldnt have packets longer than this
TNC->InputLen=0;
// I don't think it likely we will get packets this long, but be aware...
// We can get pretty big ones in the faster
InputLen=recv(TNC->TCPSock, &TNC->ARDOPBuffer[TNC->InputLen], 8192 - TNC->InputLen, 0);
if (InputLen == 0 || InputLen == SOCKET_ERROR)
{
// Does this mean closed?
closesocket(TNC->TCPSock);
TNC->TCPSock = 0;
TNC->CONNECTED = FALSE;
TNC->Streams[0].ReportDISC = TRUE;
sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
return;
}
TNC->InputLen += InputLen;
loop:
ptr = memchr(TNC->ARDOPBuffer, '\r', TNC->InputLen);
if (ptr == 0) // CR in buffer
return; // Wait for it
ptr2 = &TNC->ARDOPBuffer[TNC->InputLen];
if ((ptr2 - ptr) == 1) // CR
{
// Usual Case - single meg in buffer
VARAProcessResponse(TNC, TNC->ARDOPBuffer, TNC->InputLen);
TNC->InputLen=0;
return;
}
else
{
MsgLen = TNC->InputLen - (int)(ptr2-ptr) + 1; // Include CR
memcpy(Buffer, TNC->ARDOPBuffer, MsgLen);
VARAProcessResponse(TNC, Buffer, MsgLen);
if (TNC->InputLen < MsgLen)
{
TNC->InputLen = 0;
return;
}
memmove(TNC->ARDOPBuffer, ptr + 1, TNC->InputLen-MsgLen);
TNC->InputLen -= MsgLen;
goto loop;
}
return;
}
VOID VARAProcessDataPacket(struct TNCINFO * TNC, UCHAR * Data, int Length)
{
// Info on Data Socket - just packetize and send on
struct STREAMINFO * STREAM = &TNC->Streams[0];
int PacLen = 236;
PMSGWITHLEN buffptr;
TNC->TimeSinceLast = 0;
STREAM->BytesRXed += Length;
Data[Length] = 0;
Debugprintf("VARA: RXD %d bytes", Length);
sprintf(TNC->WEB_TRAFFIC, "Sent %d RXed %d Queued %d",
STREAM->BytesTXed, STREAM->BytesRXed,STREAM->BytesOutstanding);
MySetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC);
// May need to fragment
while (Length)
{
int Fraglen = Length;
if (Length > PACLEN)
Fraglen = PACLEN;
Length -= Fraglen;
buffptr = GetBuff();
if (buffptr == 0)
return; // No buffers, so ignore
memcpy(buffptr->Data, Data, Fraglen);
WritetoTrace(TNC, Data, Fraglen);
Data += Fraglen;
buffptr->Len = Fraglen;
C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
}
return;
}
static VOID TidyClose(struct TNCINFO * TNC, int Stream)
{
// If all acked, send disc
if (TNC->Streams[0].BytesOutstanding == 0)
VARASendCommand(TNC, "DISCONNECT\r", TRUE);
}
static VOID ForcedClose(struct TNCINFO * TNC, int Stream)
{
char Abort[] = "ABORT\r";
VARASendCommand(TNC, Abort, TRUE);
WritetoTrace(TNC, Abort, 5);
}
static VOID CloseComplete(struct TNCINFO * TNC, int Stream)
{
VARAReleaseTNC(TNC);
TNC->ARDOPCurrentMode[0] = 0; // Force Mode select on next scan change
// Also reset mode in case incoming call has changed it
if (TNC->DefaultMode == 50)
VARASendCommand(TNC, "BW2300\r", TRUE);
else if (TNC->DefaultMode == 53)
VARASendCommand(TNC, "BW500\r", TRUE);
else if (TNC->DefaultMode == 54)
VARASendCommand(TNC, "BW2750\r", TRUE);
}
VOID VARASendCommand(struct TNCINFO * TNC, char * Buff, BOOL Queue)
{
int SentLen;
if (Buff[0] == 0) // Terminal Keepalive?
return;
if (memcmp(Buff, "LISTEN O", 8) == 0)
TNC->DiscardNextOK = TRUE; // Responding to LISTEN messes up forwarding
if (TNC->CONNECTED == 0)
return;
if (TNC->TCPSock)
{
SentLen = send(TNC->TCPSock, Buff, (int)strlen(Buff), 0);
if (SentLen != strlen(Buff))
{
int winerr=WSAGetLastError();
char ErrMsg[80];
sprintf(ErrMsg, "VARA Write Failed for port %d - error code = %d\r\n", TNC->Port, winerr);
WritetoConsole(ErrMsg);
closesocket(TNC->TCPSock);
TNC->TCPSock = 0;
TNC->CONNECTED = FALSE;
return;
}
}
return;
}
int VARASendData(struct TNCINFO * TNC, UCHAR * Buff, int Len)
{
struct STREAMINFO * STREAM = &TNC->Streams[0];
int bytes=send(TNC->TCPDataSock,(const char FAR *)Buff, Len, 0);
STREAM->BytesTXed += bytes;
WritetoTrace(TNC, Buff, Len);
return bytes;
}
#ifndef LINBPQ
BOOL CALLBACK EnumVARAWindowsProc(HWND hwnd, LPARAM lParam)
{
char wtext[128];
struct TNCINFO * TNC = (struct TNCINFO *)lParam;
UINT ProcessId;
int n;
n = GetWindowText(hwnd, wtext, 127);
if (memcmp(wtext,"VARA", 4) == 0)
{
GetWindowThreadProcessId(hwnd, &ProcessId);
if (TNC->PID == ProcessId)
{
// Our Process
char msg[512];
char ID[64] = "";
int i = 29;
memcpy(ID, TNC->PortRecord->PORTCONTROL.PORTDESCRIPTION, 30);
while (ID[i] == ' ')
ID[i--] = 0;
wtext[n] = 0;
sprintf (msg, "BPQ %s - %s", ID, wtext);
SetWindowText(hwnd, msg);
return FALSE;
}
}
return (TRUE);
}
#endif
VOID VARAReleaseTNC(struct TNCINFO * TNC)
{
// Set mycall back to Node or Port Call, and Start Scanner
UCHAR TXMsg[1000];
// ARDOPChangeMYC(TNC, TNC->NodeCall);
VARASendCommand(TNC, "LISTEN ON\r", TRUE);
strcpy(TNC->WEB_TNCSTATE, "Free");
MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
// Start Scanner
if (TNC->DefaultRadioCmd)
{
sprintf(TXMsg, "%d %s", TNC->Port, TNC->DefaultRadioCmd);
Rig_Command(-1, TXMsg);
}
sprintf(TXMsg, "%d SCANSTART 15", TNC->Port);
Rig_Command(-1, TXMsg);
ReleaseOtherPorts(TNC);
}