7114 lines
157 KiB
C
7114 lines
157 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
|
|
*/
|
|
|
|
//
|
|
// Telnet Driver for BPQ Switch
|
|
//
|
|
// Uses BPQ EXTERNAL interface
|
|
//
|
|
|
|
//#define WIN32_LEAN_AND_MEAN
|
|
|
|
#define _CRT_SECURE_NO_WARNINGS
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include "time.h"
|
|
|
|
#include "kernelresource.h"
|
|
|
|
#define IDM_DISCONNECT 2000
|
|
#define IDM_LOGGING 2100
|
|
|
|
#include "CHeaders.h"
|
|
#include "tncinfo.h"
|
|
|
|
#ifdef WIN32
|
|
#include <winioctl.h>
|
|
#include "WS2tcpip.h"
|
|
#else
|
|
//#define TIOCOUTQ 0x5411
|
|
#define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */
|
|
#endif
|
|
|
|
#include "adif.h"
|
|
#include "telnetserver.h"
|
|
|
|
#define MAX_PENDING_CONNECTS 4
|
|
|
|
extern UCHAR LogDirectory[];
|
|
|
|
|
|
static char ClassName[]="TELNETSERVER";
|
|
static char WindowTitle[] = "Telnet Server";
|
|
static int RigControlRow = 190;
|
|
|
|
UCHAR * APIENTRY GetLogDirectory();
|
|
static BOOL OpenSockets(struct TNCINFO * TNC);
|
|
static BOOL OpenSockets6(struct TNCINFO * TNC);
|
|
void ProcessHTTPMessage(void * conn);
|
|
static VOID SetupListenSet(struct TNCINFO * TNC);
|
|
int WritetoConsoleLocal(char * buff);
|
|
BOOL TelSendPacket(int Stream, struct STREAMINFO * STREAM, PMSGWITHLEN buffptr, struct ADIF * ADIF);
|
|
int GetCMSHash(char * Challenge, char * Password);
|
|
int IsUTF8(unsigned char *cpt, int len);
|
|
int Convert437toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF);
|
|
int Convert1251toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF);
|
|
int Convert1252toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF);
|
|
VOID initUTF8();
|
|
int TrytoGuessCode(unsigned char * Char, int Len);
|
|
DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot);
|
|
extern BPQVECSTRUC * TELNETMONVECPTR;
|
|
BOOL SendWL2KSessionRecord(ADIF * ADIF, int BytesSent, int BytesReceived);
|
|
int DataSocket_ReadSync(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream);
|
|
VOID SendWL2KRegisterHybrid(struct TNCINFO * TNC);
|
|
int IntSetTraceOptionsEx(uint64_t mask, int mtxparam, int mcomparam, int monUIOnly);
|
|
int DataSocket_ReadDRATS(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream);
|
|
void processDRATSFrame(unsigned char * Message, int Len, struct ConnectionInfo * sockptr);
|
|
void DRATSConnectionLost(struct ConnectionInfo * sockptr);
|
|
int BuildRigCtlPage(char * _REPLYBUFFER);
|
|
void ProcessWebmailWebSockThread(void * conn);
|
|
int ProcessSNMPPayload(UCHAR * Msg, int Len, UCHAR * Reply, int * OffPtr);
|
|
|
|
#ifndef LINBPQ
|
|
extern HKEY REGTREE;
|
|
extern HMENU hMainFrameMenu;
|
|
extern HMENU hBaseMenu;
|
|
extern HMENU hWndMenu;
|
|
extern HFONT hFont;
|
|
extern HBRUSH bgBrush;
|
|
|
|
extern HWND ClientWnd, FrameWnd;
|
|
|
|
extern HANDLE hInstance;
|
|
static RECT Rect;
|
|
|
|
LRESULT CALLBACK TelWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
#endif
|
|
|
|
extern int REALTIMETICKS;
|
|
|
|
#define MaxSockets 26
|
|
|
|
struct UserRec RelayUser;
|
|
struct UserRec SyncUser = {"","Sync"};;
|
|
struct UserRec CMSUser;
|
|
struct UserRec HostUser = {"","Host"};
|
|
struct UserRec TriModeUser;
|
|
|
|
static char AttemptsMsg[] = "Too many attempts - Disconnected\r\n";
|
|
static char disMsg[] = "Disconnected by SYSOP\r\n";
|
|
|
|
static char BlankCall[]=" ";
|
|
|
|
BOOL LogEnabled = FALSE;
|
|
BOOL CMSLogEnabled = TRUE;
|
|
extern BOOL IncludesMail;
|
|
|
|
static HMENU hMenu, hPopMenu, hPopMenu2, hPopMenu3; // handle of menu
|
|
|
|
static int ProcessLine(char * buf, int Port);
|
|
VOID __cdecl Debugprintf(const char * format, ...);
|
|
|
|
|
|
int DisplaySessions(struct TNCINFO * TNC);
|
|
int DoStateChange(int Stream);
|
|
int Connected(int Stream);
|
|
int Disconnected(int Stream);
|
|
//int DeleteConnection(con);
|
|
static int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port);
|
|
static int Socket_Data(struct TNCINFO * TNC, SOCKET SocketId,int error, int eventcode);
|
|
static int DataSocket_Read(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM);
|
|
int DataSocket_ReadFBB(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream);
|
|
int DataSocket_ReadRelay(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM);
|
|
int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream);
|
|
int DataSocket_Write(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET TCPSock);
|
|
int DataSocket_Disconnect(struct TNCINFO * TNC, struct ConnectionInfo * sockptr);
|
|
BOOL ProcessTelnetCommand(struct ConnectionInfo * sockptr, byte * Msg, int * Len);
|
|
int ShowConnections(struct TNCINFO * TNC);
|
|
int Terminate();
|
|
int SendtoSocket(SOCKET TCPSock,char * Msg);
|
|
int WriteLog(char * msg);
|
|
VOID WriteCMSLog(char * msg);
|
|
byte * EncodeCall(byte * Call);
|
|
VOID SendtoNode(struct TNCINFO * TNC, int Stream, char * Msg, int MsgLen);
|
|
DllExport int APIENTRY GetNumberofPorts();
|
|
|
|
BOOL CheckCMS(struct TNCINFO * TNC);
|
|
int TCPConnect(struct TNCINFO * TNC, struct TCPINFO * TCP, struct STREAMINFO * STREAM, char * Host, int Port, BOOL FBB);
|
|
int CMSConnect(struct TNCINFO * TNC, struct TCPINFO * TCP, struct STREAMINFO * STREAM, int Stream);
|
|
int Telnet_Connected(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Error);
|
|
BOOL ProcessConfig();
|
|
VOID FreeConfig();
|
|
VOID SaveCMSHostInfo(int port, struct TCPINFO * TCP, int CMSNo);
|
|
VOID GetCMSCachedInfo(struct TNCINFO * TNC);
|
|
BOOL CMSCheck(struct TNCINFO * TNC, struct TCPINFO * TCP);
|
|
VOID Tel_Format_Addr(struct ConnectionInfo * sockptr, char * dst);
|
|
VOID ProcessTrimodeCommand(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, char * MsgPtr);
|
|
VOID ProcessTrimodeResponse(struct TNCINFO * TNC, struct STREAMINFO * STREAM, unsigned char * MsgPtr, int Msglen);
|
|
VOID ProcessTriModeDataMessage(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM);
|
|
|
|
|
|
static int LogAge = 13;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
int DeleteLogFile(char * Log);
|
|
|
|
void DeleteTelnetLogFiles()
|
|
{
|
|
DeleteLogFile("/logs/Telnet*.log");
|
|
DeleteLogFile("/logs/CMSAccess_*.log");
|
|
DeleteLogFile("/logs/ConnectLog_*.log");
|
|
}
|
|
|
|
int DeleteLogFile(char * Log)
|
|
{
|
|
|
|
|
|
WIN32_FIND_DATA ffd;
|
|
|
|
char szDir[MAX_PATH];
|
|
char File[MAX_PATH];
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
DWORD dwError=0;
|
|
LARGE_INTEGER ft;
|
|
time_t now = time(NULL);
|
|
int Age;
|
|
|
|
// Prepare string for use with FindFile functions. First, copy the
|
|
// string to a buffer, then append '\*' to the directory name.
|
|
|
|
strcpy(szDir, GetLogDirectory());
|
|
strcat(szDir, Log);
|
|
|
|
// Find the first file in the directory.
|
|
|
|
hFind = FindFirstFile(szDir, &ffd);
|
|
|
|
if (INVALID_HANDLE_VALUE == hFind)
|
|
return dwError;
|
|
|
|
// List all the files in the directory with some info about them.
|
|
|
|
do
|
|
{
|
|
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
OutputDebugString(ffd.cFileName);
|
|
}
|
|
else
|
|
{
|
|
ft.HighPart = ffd.ftCreationTime.dwHighDateTime;
|
|
ft.LowPart = ffd.ftCreationTime.dwLowDateTime;
|
|
|
|
ft.QuadPart -= 116444736000000000;
|
|
ft.QuadPart /= 10000000;
|
|
|
|
Age = (int)((now - ft.LowPart) / 86400);
|
|
|
|
if (Age > LogAge)
|
|
{
|
|
sprintf(File, "%s/logs/%s%c", GetLogDirectory(), ffd.cFileName, 0);
|
|
Debugprintf("Deleting %s", File);
|
|
DeleteFile(File);
|
|
}
|
|
}
|
|
}
|
|
while (FindNextFile(hFind, &ffd) != 0);
|
|
|
|
FindClose(hFind);
|
|
return dwError;
|
|
}
|
|
|
|
#else
|
|
|
|
#include <dirent.h>
|
|
|
|
int TelFilter(const struct dirent * dir)
|
|
{
|
|
return (memcmp(dir->d_name, "CMSAccess", 9) == 0
|
|
|| memcmp(dir->d_name, "Telnet", 6) == 0
|
|
|| memcmp(dir->d_name, "ConnectLog", 6) == 0)
|
|
&& strstr(dir->d_name, ".log");
|
|
}
|
|
|
|
int DeleteTelnetLogFiles()
|
|
{
|
|
struct dirent **namelist;
|
|
int n;
|
|
struct stat STAT;
|
|
time_t now = time(NULL);
|
|
int Age = 0, res;
|
|
char FN[256];
|
|
|
|
n = scandir("logs", &namelist, TelFilter, alphasort);
|
|
|
|
if (n < 0)
|
|
perror("scandir");
|
|
else
|
|
{
|
|
while(n--)
|
|
{
|
|
sprintf(FN, "logs/%s", namelist[n]->d_name);
|
|
if (stat(FN, &STAT) == 0)
|
|
{
|
|
Age = (now - STAT.st_mtime) / 86400;
|
|
|
|
if (Age > LogAge)
|
|
{
|
|
Debugprintf("Deleting %s\n", FN);
|
|
unlink(FN);
|
|
}
|
|
}
|
|
free(namelist[n]);
|
|
}
|
|
free(namelist);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
void BuffertoNode(struct ConnectionInfo * sockptr, char * MsgPtr, int InputLen)
|
|
{
|
|
// Queue to Node. Data may arrive it large quatities, possibly exceeding node buffer capacity
|
|
|
|
if (sockptr->FromHostBuffPutptr + InputLen > sockptr->FromHostBufferSize)
|
|
{
|
|
if (InputLen > 10000)
|
|
sockptr->FromHostBufferSize += InputLen;
|
|
else
|
|
sockptr->FromHostBufferSize += 10000;
|
|
|
|
sockptr->FromHostBuffer = realloc(sockptr->FromHostBuffer, sockptr->FromHostBufferSize);
|
|
}
|
|
|
|
memcpy(&sockptr->FromHostBuffer[sockptr->FromHostBuffPutptr], MsgPtr, InputLen);
|
|
|
|
sockptr->FromHostBuffPutptr += InputLen;
|
|
sockptr->InputLen = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL SendAndCheck(struct ConnectionInfo * sockptr, unsigned char * MsgPtr, int len, int flags)
|
|
{
|
|
int err;
|
|
int sent = send(sockptr->socket, MsgPtr, len, flags);
|
|
|
|
if (sent == len)
|
|
return TRUE; // OK
|
|
|
|
err = WSAGetLastError();
|
|
|
|
Debugprintf("TCP Send Failed - Sent %d should be %d err %d - requeue data", sent, len, err);
|
|
|
|
if (err == 10035 || err == 115 || err == 36) //EWOULDBLOCK
|
|
{
|
|
// Save unsent data
|
|
|
|
if (sent == -1) // -1 means none sent
|
|
sent = 0;
|
|
|
|
sockptr->ResendBuffer = malloc(len - sent);
|
|
sockptr->ResendLen = len - sent;
|
|
|
|
memmove(sockptr->ResendBuffer, MsgPtr + sent, len - sent);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
VOID SendPortsForMonitor(SOCKET sock, int Secure)
|
|
{
|
|
UCHAR PortInfo[3000] = {0xff, 0xff};
|
|
UCHAR * ptr = &PortInfo[2];
|
|
char ID[31] = "";
|
|
struct PORTCONTROL * PORT;
|
|
int i, n, p;
|
|
|
|
// Sends the ID of each Port to TermTCP
|
|
|
|
p = GetNumberofPorts();
|
|
|
|
if (IncludesMail && Secure)
|
|
p++;
|
|
|
|
ptr += sprintf(ptr, "%d|", p);
|
|
|
|
if (IncludesMail && Secure)
|
|
{
|
|
p--;
|
|
ptr += sprintf(ptr,"0 Mail Monitor|");
|
|
}
|
|
|
|
for (n=1; n <= p; n++)
|
|
{
|
|
PORT = GetPortTableEntryFromSlot(n);
|
|
|
|
memcpy(ID, PORT->PORTDESCRIPTION, 30);
|
|
|
|
for (i = 29; i; i--)
|
|
{
|
|
if (ID[i] != ' ')
|
|
break;
|
|
|
|
ID[i] = 0;
|
|
}
|
|
|
|
ptr += sprintf(ptr,"%d %s|", PORT->PORTNUMBER, ID);
|
|
}
|
|
|
|
|
|
send(sock, PortInfo, (int)(ptr - PortInfo), 0);
|
|
}
|
|
|
|
int ProcessLine(char * buf, int Port)
|
|
{
|
|
UCHAR * ptr;
|
|
UCHAR * ptr1;
|
|
|
|
char * p_ipad = 0;
|
|
char * p_port = 0;
|
|
unsigned short WINMORport = 0;
|
|
int len=510;
|
|
char errbuf[256];
|
|
char * param;
|
|
char * value;
|
|
char *User, *Pwd, *UserCall, *Secure, * Appl;
|
|
int End = (int)strlen(buf) -1;
|
|
struct TNCINFO * TNC;
|
|
struct TCPINFO * TCP;
|
|
|
|
strcpy(errbuf,buf); // save in case of error
|
|
|
|
if (buf[End] == 10)
|
|
buf[End]=0; // remove newline
|
|
|
|
if(buf[0] =='#') return (TRUE); // comment
|
|
|
|
if(buf[0] ==';') return (TRUE); // comment
|
|
|
|
ptr=strchr(buf,'=');
|
|
|
|
if (!ptr)
|
|
ptr=strchr(buf,' ');
|
|
|
|
if (!ptr)
|
|
return 0;
|
|
|
|
if (TNCInfo[Port] == NULL)
|
|
{
|
|
TNC = TNCInfo[Port] = zalloc(sizeof(struct TNCINFO));
|
|
TCP = TNC->TCPInfo = zalloc(sizeof (struct TCPINFO)); // Telnet Server Specific Data
|
|
|
|
TCP->MaxSessions = 10; // Default Values
|
|
TNC->Hardware = H_TELNET;
|
|
TCP->IPV4 = TRUE;
|
|
TCP->SecureTelnet = 1;
|
|
strcpy(TCP->CMSServer, "cms.winlink.org");
|
|
}
|
|
|
|
TNC = TNCInfo[Port];
|
|
TCP = TNC->TCPInfo;
|
|
|
|
param=buf;
|
|
*(ptr)=0;
|
|
value=ptr+1;
|
|
|
|
if (_stricmp(param, "IPV4") == 0)
|
|
TCP->IPV4 = atoi(value);
|
|
|
|
else if (_stricmp(param, "IPV6") == 0)
|
|
TCP->IPV6 = atoi(value);
|
|
|
|
else if (_stricmp(param, "CMS") == 0)
|
|
TCP->CMS = atoi(value);
|
|
|
|
else if (_stricmp(param, "CMSPASS") == 0)
|
|
{
|
|
char Temp[80];
|
|
|
|
if (strlen(value) > 79)
|
|
value[79] = 0;
|
|
|
|
strcpy(Temp, value);
|
|
strlop(Temp, 32);
|
|
strlop(Temp, 13);
|
|
strcpy(TCP->SecureCMSPassword, Temp);
|
|
|
|
}
|
|
|
|
else if (_stricmp(param, "CMSCALL") == 0)
|
|
{
|
|
if (strlen(value) > 9)
|
|
value[9] = 0;
|
|
strcpy(TCP->GatewayCall, value);
|
|
strlop(TCP->GatewayCall, 13);
|
|
_strupr(TCP->GatewayCall);
|
|
}
|
|
|
|
else if (_stricmp(param, "CMSLOC") == 0)
|
|
{
|
|
if (strlen(value) > 9)
|
|
value[9] = 0;
|
|
strcpy(TCP->GatewayLoc, value);
|
|
strlop(TCP->GatewayLoc, 13);
|
|
_strupr(TCP->GatewayLoc);
|
|
}
|
|
|
|
else if (_stricmp(param,"ReportHybrid") == 0)
|
|
TCP->ReportHybrid = atoi(value);
|
|
|
|
else if (_stricmp(param, "HybridServiceCode") == 0)
|
|
{
|
|
TCP->HybridServiceCode = _strdup(value);
|
|
strlop(TCP->HybridServiceCode, 13);
|
|
strlop(TCP->HybridServiceCode, ';');
|
|
_strupr(TCP->HybridServiceCode);
|
|
}
|
|
|
|
else if (_stricmp(param, "HybridFrequencies") == 0)
|
|
{
|
|
TCP->HybridFrequencies = _strdup(value);
|
|
strlop(TCP->HybridFrequencies, 13);
|
|
strlop(TCP->HybridFrequencies, ' ');
|
|
_strupr(TCP->HybridFrequencies);
|
|
}
|
|
|
|
else if (_stricmp(param, "HybridCoLocatedRMS") == 0)
|
|
{
|
|
TCP->HybridCoLocatedRMS = _strdup(value);
|
|
strlop(TCP->HybridCoLocatedRMS, 13);
|
|
strlop(TCP->HybridCoLocatedRMS, ' ');
|
|
_strupr(TCP->HybridCoLocatedRMS);
|
|
}
|
|
|
|
else if (_stricmp(param,"LOGGING") == 0)
|
|
LogEnabled = atoi(value);
|
|
|
|
else if (_stricmp(param,"CMSLOGGING") == 0)
|
|
CMSLogEnabled = atoi(value);
|
|
|
|
else if (_stricmp(param,"DisconnectOnClose") == 0)
|
|
TCP->DisconnectOnClose = atoi(value);
|
|
|
|
else if (_stricmp(param,"ReportRelayTraffic") == 0)
|
|
TCP->ReportRelayTraffic = atoi(value);
|
|
|
|
else if (_stricmp(param,"SecureTelnet") == 0)
|
|
TCP->SecureTelnet = atoi(value);
|
|
|
|
else if (_stricmp(param,"CloseOnDisconnect") == 0)
|
|
TCP->DisconnectOnClose = atoi(value);
|
|
|
|
else if (_stricmp(param,"TCPPORT") == 0)
|
|
TCP->TCPPort = atoi(value);
|
|
|
|
else if (_stricmp(param,"DRATSPORT") == 0)
|
|
TCP->DRATSPort = atoi(value);
|
|
|
|
else if (_stricmp(param,"TRIMODEPORT") == 0)
|
|
TCP->TriModePort = atoi(value);
|
|
|
|
else if (_stricmp(param,"HTTPPORT") == 0)
|
|
TCP->HTTPPort = atoi(value);
|
|
|
|
else if (_stricmp(param,"APIPORT") == 0)
|
|
TCP->APIPort = atoi(value);
|
|
|
|
else if (_stricmp(param,"SYNCPORT") == 0)
|
|
TCP->SyncPort = atoi(value);
|
|
|
|
else if (_stricmp(param,"SNMPPORT") == 0)
|
|
TCP->SNMPPort = atoi(value);
|
|
|
|
else if ((_stricmp(param,"CMDPORT") == 0) || (_stricmp(param,"LINUXPORT") == 0))
|
|
{
|
|
int n = 0;
|
|
char * context;
|
|
char * ptr = strtok_s(value, ", ", &context);
|
|
|
|
while (ptr && n < 33)
|
|
{
|
|
TCP->CMDPort[n++] = atoi(ptr);
|
|
ptr = strtok_s(NULL, ", ", &context);
|
|
}
|
|
}
|
|
|
|
else if (_stricmp(param,"CMSSERVER") == 0)
|
|
{
|
|
int n = 0;
|
|
char * context;
|
|
char * ptr = strtok_s(value, ", \r", &context);
|
|
|
|
strcpy(TCP->CMSServer, ptr);
|
|
}
|
|
|
|
else if (_stricmp(param,"RELAYHOST") == 0)
|
|
{
|
|
int n = 0;
|
|
char * context;
|
|
char * ptr = strtok_s(value, ", \r", &context);
|
|
|
|
strcpy(TCP->RELAYHOST, ptr);
|
|
}
|
|
|
|
|
|
else if (_stricmp(param,"FALLBACKTORELAY") == 0)
|
|
{
|
|
int n = 0;
|
|
char * context;
|
|
char * ptr = strtok_s(value, ", \r", &context);
|
|
|
|
TCP->FallbacktoRelay = atoi(value);
|
|
}
|
|
|
|
else if (_stricmp(param,"FBBPORT") == 0)
|
|
{
|
|
int n = 0;
|
|
char * context;
|
|
char * ptr = strtok_s(value, ", ", &context);
|
|
|
|
while (ptr && n < 99)
|
|
{
|
|
TCP->FBBPort[n++] = atoi(ptr);
|
|
ptr = strtok_s(NULL, ", ", &context);
|
|
}
|
|
}
|
|
|
|
else if (_stricmp(param,"RELAYPORT") == 0)
|
|
TCP->RelayPort = atoi(value);
|
|
|
|
else if (_stricmp(param,"RELAYAPPL") == 0)
|
|
{
|
|
if (TCP->RelayPort == 0)
|
|
TCP->RelayPort = 8772;
|
|
strcpy(TCP->RelayAPPL, value);
|
|
strcat(TCP->RelayAPPL, "\r");
|
|
}
|
|
|
|
else if (_stricmp(param,"SYNCAPPL") == 0)
|
|
{
|
|
if (TCP->SyncPort == 0)
|
|
TCP->SyncPort = 8780;
|
|
strcpy(TCP->SyncAPPL, value);
|
|
strcat(TCP->SyncAPPL, "\r");
|
|
}
|
|
|
|
// if (strcmp(param,"LOGINRESPONSE") == 0) cfgLOGINRESPONSE = value;
|
|
// if (strcmp(param,"PASSWORDRESPONSE") == 0) cfgPASSWORDRESPONSE = value;
|
|
|
|
else if (_stricmp(param,"LOGINPROMPT") == 0)
|
|
{
|
|
ptr1 = strchr(value, 13);
|
|
if (ptr1) *ptr1 = 0;
|
|
strcpy(TCP->LoginMsg,value);
|
|
}
|
|
|
|
else if (_stricmp(param,"PASSWORDPROMPT") == 0)
|
|
{
|
|
ptr1 = strchr(value, 13);
|
|
if (ptr1) *ptr1 = 0;
|
|
strcpy(TCP->PasswordMsg, value);
|
|
}
|
|
|
|
else if (_stricmp(param,"HOSTPROMPT") == 0)
|
|
strcpy(TCP->cfgHOSTPROMPT, value);
|
|
|
|
else if (_stricmp(param,"LOCALECHO") == 0)
|
|
strcpy(TCP->cfgLOCALECHO, value);
|
|
|
|
else if (_stricmp(param,"MAXSESSIONS") == 0)
|
|
{
|
|
TCP->MaxSessions = atoi(value);
|
|
if (TCP->MaxSessions > MaxSockets ) TCP->MaxSessions = MaxSockets;
|
|
}
|
|
|
|
else if (_stricmp(param,"CTEXT") == 0 )
|
|
{
|
|
int len = (int)strlen (value);
|
|
|
|
if (value[len -1] == ' ')
|
|
value[len -1] = 0;
|
|
|
|
strcpy(TCP->cfgCTEXT, value);
|
|
|
|
// Replace \n Signon string with cr lf
|
|
|
|
ptr = &TCP->cfgCTEXT[0];
|
|
|
|
scanCTEXT:
|
|
|
|
ptr = strstr(ptr, "\\n");
|
|
|
|
if (ptr)
|
|
{
|
|
*(ptr++)=13; // put in cr
|
|
*(ptr++)=10; // put in lf
|
|
|
|
goto scanCTEXT;
|
|
}
|
|
}
|
|
|
|
else if (_stricmp(param,"LOCALNET") == 0)
|
|
{
|
|
uint32_t Network, Mask;
|
|
uint32_t IPMask;
|
|
char * Netptr, * MaskPtr, *Context;
|
|
struct LOCALNET * LocalNet;
|
|
int Bits = 24;
|
|
|
|
Netptr = strtok_s(value, " /;", &Context);
|
|
|
|
if (Netptr)
|
|
{
|
|
Network = inet_addr(Netptr);
|
|
MaskPtr = strtok_s(NULL, " /;", &Context);
|
|
|
|
if (MaskPtr)
|
|
{
|
|
Bits = atoi(MaskPtr);
|
|
|
|
if (Bits > 32)
|
|
Bits = 32;
|
|
}
|
|
|
|
if (Bits == 0)
|
|
IPMask = 0;
|
|
else
|
|
IPMask = (0xFFFFFFFF) << (32 - Bits);
|
|
|
|
Mask = htonl(IPMask); // Needs to be Network order
|
|
|
|
LocalNet = (struct LOCALNET *)zalloc(sizeof(struct LOCALNET));
|
|
|
|
LocalNet->Network = Network;
|
|
LocalNet->Mask = Mask;
|
|
LocalNet->Next = TNC->TCPInfo->LocalNets;
|
|
|
|
TNC->TCPInfo->LocalNets = LocalNet;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (_stricmp(param,"USER") == 0)
|
|
{
|
|
struct UserRec * USER;
|
|
char Param[8][256];
|
|
char * ptr1, * ptr2;
|
|
int n = 0;
|
|
|
|
// USER=user,password,call,appl,SYSOP
|
|
|
|
memset(Param, 0, 2048);
|
|
strlop(value, 13);
|
|
strlop(value, ';');
|
|
|
|
ptr1 = value;
|
|
|
|
while (ptr1 && *ptr1 && n < 8)
|
|
{
|
|
ptr2 = strchr(ptr1, ',');
|
|
if (ptr2) *ptr2++ = 0;
|
|
|
|
strcpy(&Param[n][0], ptr1);
|
|
strlop(Param[n++], ' ');
|
|
ptr1 = ptr2;
|
|
while(ptr1 && *ptr1 && *ptr1 == ' ')
|
|
ptr1++;
|
|
}
|
|
|
|
|
|
User = &Param[0][0];
|
|
|
|
if (_stricmp(User, "ANON") == 0)
|
|
{
|
|
strcpy(&Param[2][0], "ANON");
|
|
strcpy(&Param[4][0], ""); // Dont allow SYSOP if ANON
|
|
}
|
|
|
|
Pwd = &Param[1][0];
|
|
UserCall = &Param[2][0];
|
|
Appl = &Param[3][0];
|
|
Secure = &Param[4][0];
|
|
|
|
if (User[0] == 0 || Pwd[0] == 0 || UserCall[0] == 0) // invalid record
|
|
return 0;
|
|
|
|
_strupr(UserCall);
|
|
|
|
if (TCP->NumberofUsers == 0)
|
|
TCP->UserRecPtr = zalloc(sizeof(void *));
|
|
else
|
|
TCP->UserRecPtr = realloc(TCP->UserRecPtr, (TCP->NumberofUsers+1) * sizeof(void *));
|
|
|
|
USER = zalloc(sizeof(struct UserRec));
|
|
|
|
TCP->UserRecPtr[TCP->NumberofUsers] = USER;
|
|
|
|
USER->Callsign = _strdup(UserCall);
|
|
USER->Password = _strdup(Pwd);
|
|
USER->UserName = _strdup(User);
|
|
USER->Appl = zalloc(32);
|
|
USER->Secure = FALSE;
|
|
|
|
if (_stricmp(Secure, "SYSOP") == 0)
|
|
USER->Secure = TRUE;
|
|
|
|
if (Appl[0] && strcmp(Appl, "\"\"") != 0)
|
|
{
|
|
strcpy(USER->Appl, _strupr(Appl));
|
|
strcat(USER->Appl, "\r\n");
|
|
}
|
|
TCP->NumberofUsers += 1;
|
|
}
|
|
else if (_memicmp(errbuf, "WL2KREPORT", 10) == 0)
|
|
TNC->WL2K = DecodeWL2KReportLine(errbuf);
|
|
else if (_stricmp(param,"WebTermCSS") == 0)
|
|
{
|
|
TCP->WebTermCSS = _strdup(value);
|
|
}
|
|
else
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static int MaxStreams = 26;
|
|
|
|
void CheckRX(struct TNCINFO * TNC);
|
|
VOID TelnetPoll(int Port);
|
|
VOID ProcessTermModeResponse(struct TNCINFO * TNC);
|
|
VOID DoTNCReinit(struct TNCINFO * TNC);
|
|
VOID DoTermModeTimeout(struct TNCINFO * TNC);
|
|
|
|
VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len);
|
|
|
|
|
|
static VOID WritetoTrace(int Stream, char * Msg, int Len, struct ADIF * ADIF, char Dirn)
|
|
{
|
|
int index = 0;
|
|
UCHAR * ptr1 = Msg, * ptr2;
|
|
UCHAR Line[1000];
|
|
int LineLen, i;
|
|
char logmsg[200];
|
|
|
|
Msg[Len] = 0;
|
|
|
|
lineloop:
|
|
|
|
if (Len > 0)
|
|
{
|
|
// copy text to file a line at a time
|
|
|
|
ptr2 = memchr(ptr1, 13 , Len);
|
|
|
|
if (ptr2)
|
|
{
|
|
ptr2++;
|
|
LineLen = (int)(ptr2 - ptr1);
|
|
Len -= LineLen;
|
|
|
|
if (LineLen > 900)
|
|
goto Skip;
|
|
|
|
memcpy(Line, ptr1, LineLen);
|
|
memcpy(&Line[LineLen - 1], "<cr>", 4);
|
|
LineLen += 3;
|
|
|
|
if ((*ptr2) == 10)
|
|
{
|
|
memcpy(&Line[LineLen], "<lf>", 4);
|
|
LineLen += 4;
|
|
ptr2++;
|
|
Len --;
|
|
}
|
|
|
|
Line[LineLen] = 0;
|
|
|
|
// If line contains any data above 7f, assume binary and dont display
|
|
|
|
for (i = 0; i < LineLen; i++)
|
|
{
|
|
if (Line[i] > 127 || Line[i] < 32)
|
|
goto Skip;
|
|
}
|
|
|
|
if (strlen(Line) < 100)
|
|
{
|
|
sprintf(logmsg,"%d %s\r\n", Stream, Line);
|
|
WriteCMSLog(logmsg);
|
|
UpdateADIFRecord(ADIF, Line, Dirn);
|
|
}
|
|
|
|
Skip:
|
|
ptr1 = ptr2;
|
|
goto lineloop;
|
|
}
|
|
|
|
// No CR
|
|
|
|
for (i = 0; i < Len; i++)
|
|
{
|
|
if (ptr1[i] > 127)
|
|
break;
|
|
}
|
|
|
|
if (i == Len) // No binary data
|
|
{
|
|
if (strlen(ptr1) < 100)
|
|
{
|
|
sprintf(logmsg,"%d %s\r\n", Stream, ptr1);
|
|
WriteCMSLog(logmsg);
|
|
UpdateADIFRecord(ADIF, ptr1, Dirn);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
|
|
{
|
|
int txlen = 0, n;
|
|
PMSGWITHLEN buffptr;
|
|
struct TNCINFO * TNC = TNCInfo[port];
|
|
struct TCPINFO * TCP;
|
|
|
|
int Stream;
|
|
struct ConnectionInfo * sockptr;
|
|
struct STREAMINFO * STREAM;
|
|
|
|
if (TNC == NULL)
|
|
return 0; // Not configured
|
|
|
|
switch (fn)
|
|
{
|
|
case 7:
|
|
|
|
// 100 mS Timer. Now needed, as Poll can be called more frequently in some circuymstances
|
|
|
|
while (TNC->PortRecord->UI_Q) // Release anything accidentally put on UI_Q
|
|
{
|
|
buffptr = Q_REM(&TNC->PortRecord->UI_Q);
|
|
ReleaseBuffer(buffptr);
|
|
}
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
if (TCP->CMS)
|
|
{
|
|
TCP->CheckCMSTimer++;
|
|
|
|
if (TCP->CMSOK)
|
|
{
|
|
if (TCP->CheckCMSTimer > 600 * 15)
|
|
CheckCMS(TNC);
|
|
}
|
|
else
|
|
{
|
|
if (TCP->CheckCMSTimer > 600 * 2)
|
|
CheckCMS(TNC);
|
|
}
|
|
}
|
|
|
|
// We now use persistent HTTP sessions, so need to close after a reasonable time
|
|
|
|
for (n = 0; n <= TCP->MaxSessions; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
|
|
if (sockptr->SocketActive)
|
|
{
|
|
if (sockptr->HTTPMode)
|
|
{
|
|
if (sockptr->WebSocks == 0)
|
|
{
|
|
if (sockptr->LastSendTime && (REALTIMETICKS - sockptr->LastSendTime) > 1500) // ~ 2.5 mins
|
|
{
|
|
closesocket(sockptr->socket);
|
|
sockptr->SocketActive = FALSE;
|
|
ShowConnections(TNC);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Time out Login
|
|
|
|
if (sockptr->LoginState < 2 && (time(NULL) - sockptr->ConnectTime) > 30)
|
|
{
|
|
closesocket(sockptr->socket);
|
|
sockptr->SocketActive = FALSE;
|
|
ShowConnections(TNC);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
case 1: // poll
|
|
|
|
for (Stream = 0; Stream <= MaxStreams; Stream++)
|
|
{
|
|
TRANSPORTENTRY * SESS;
|
|
struct ConnectionInfo * sockptr = TNC->Streams[Stream].ConnectionInfo;
|
|
|
|
if (sockptr && sockptr->UserPointer == &CMSUser) // Connected to CMS
|
|
{
|
|
SESS = TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number];
|
|
|
|
if (SESS)
|
|
{
|
|
n = SESS->L4KILLTIMER;
|
|
if (n < (SESS->L4LIMIT - 120))
|
|
{
|
|
SESS->L4KILLTIMER = SESS->L4LIMIT - 120;
|
|
SESS = SESS->L4CROSSLINK;
|
|
if (SESS)
|
|
SESS->L4KILLTIMER = SESS->L4LIMIT - 120;
|
|
}
|
|
}
|
|
}
|
|
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
if (STREAM->NeedDisc)
|
|
{
|
|
STREAM->NeedDisc--;
|
|
|
|
if (STREAM->NeedDisc == 0)
|
|
{
|
|
// Send the DISCONNECT
|
|
|
|
STREAM->ReportDISC = TRUE;
|
|
}
|
|
}
|
|
|
|
if (STREAM->ReportDISC)
|
|
{
|
|
STREAM->ReportDISC = FALSE;
|
|
buff->PORT = Stream;
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
TelnetPoll(port);
|
|
|
|
for (Stream = 0; Stream <= MaxStreams; Stream++)
|
|
{
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
if (STREAM->PACTORtoBPQ_Q !=0)
|
|
{
|
|
int datalen;
|
|
|
|
buffptr = Q_REM(&STREAM->PACTORtoBPQ_Q);
|
|
|
|
datalen = (int)buffptr->Len;
|
|
|
|
buff->PORT = Stream;
|
|
buff->PID = 0xf0;
|
|
memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte
|
|
datalen += sizeof(void *) + 4;
|
|
|
|
PutLengthinBuffer(buff, datalen);
|
|
|
|
ReleaseBuffer(buffptr);
|
|
return (1);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 2: // send
|
|
|
|
buffptr = GetBuff();
|
|
|
|
if (buffptr == 0) return (0); // No buffers, so ignore
|
|
|
|
// Find TNC Record
|
|
|
|
Stream = buff->PORT;
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1); // 1 as no PID
|
|
|
|
buffptr->Len = txlen;
|
|
memcpy(&buffptr->Data, &buff->L2DATA, txlen);
|
|
|
|
C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
|
|
STREAM->FramesQueued++;
|
|
|
|
return (0);
|
|
|
|
|
|
case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding
|
|
|
|
Stream = (int)(size_t)buff;
|
|
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
if (STREAM->FramesQueued > 40)
|
|
return (257); // Busy
|
|
|
|
return 256; // OK
|
|
|
|
#define SD_BOTH 0x02
|
|
|
|
case 4: // reinit
|
|
{
|
|
struct _EXTPORTDATA * PortRecord;
|
|
|
|
#ifndef LINBPQ
|
|
HWND SavehDlg, SaveCMS, SaveMonitor;
|
|
HMENU SaveMenu1, SaveMenu2, SaveMenu3;
|
|
#endif
|
|
int n, i;
|
|
|
|
if (!ProcessConfig())
|
|
{
|
|
Consoleprintf("Failed to reread config file - leaving config unchanged");
|
|
break;
|
|
}
|
|
|
|
FreeConfig();
|
|
|
|
for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
sockptr->SocketActive = FALSE;
|
|
closesocket(sockptr->socket);
|
|
}
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
shutdown(TCP->TCPSock, SD_BOTH);
|
|
shutdown(TCP->sock6, SD_BOTH);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock[n])
|
|
shutdown(TCP->FBBsock[n++], SD_BOTH);
|
|
|
|
shutdown(TCP->Relaysock, SD_BOTH);
|
|
shutdown(TCP->HTTPsock, SD_BOTH);
|
|
shutdown(TCP->HTTPsock6, SD_BOTH);
|
|
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock6[n])
|
|
shutdown(TCP->FBBsock[n++], SD_BOTH);
|
|
|
|
shutdown(TCP->Relaysock6, SD_BOTH);
|
|
Sleep(500);
|
|
|
|
closesocket(TCP->TCPSock);
|
|
closesocket(TCP->sock6);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock[n])
|
|
closesocket(TCP->FBBsock[n++]);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock6[n])
|
|
closesocket(TCP->FBBsock6[n++]);
|
|
|
|
closesocket(TCP->Relaysock);
|
|
closesocket(TCP->Relaysock6);
|
|
closesocket(TCP->HTTPsock);
|
|
closesocket(TCP->HTTPsock6);
|
|
|
|
// Save info from old TNC record
|
|
|
|
n = TNC->Port;
|
|
PortRecord = TNC->PortRecord;
|
|
#ifndef LINBPQ
|
|
SavehDlg = TNC->hDlg;
|
|
SaveCMS = TCP->hCMSWnd;
|
|
SaveMonitor = TNC->hMonitor;
|
|
SaveMenu1 = TCP->hActionMenu;
|
|
SaveMenu2 = TCP->hDisMenu;
|
|
SaveMenu3 = TCP->hLogMenu;
|
|
#endif
|
|
// Free old TCP Session Stucts
|
|
|
|
for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++)
|
|
{
|
|
free(TNC->Streams[i].ConnectionInfo);
|
|
}
|
|
|
|
ReadConfigFile(TNC->Port, ProcessLine);
|
|
|
|
TNC = TNCInfo[n];
|
|
TNC->Port = n;
|
|
TNC->Hardware = H_TELNET;
|
|
TNC->RIG = &TNC->DummyRig; // Not using Rig control, so use Dummy
|
|
|
|
// Get Menu Handles
|
|
|
|
TCP = TNC->TCPInfo;
|
|
#ifndef LINBPQ
|
|
TNC->hDlg = SavehDlg;
|
|
TCP->hCMSWnd = SaveCMS;
|
|
TNC->hMonitor = SaveMonitor;
|
|
TCP->hActionMenu = SaveMenu1;
|
|
TCP->hDisMenu = SaveMenu2;
|
|
TCP->hLogMenu = SaveMenu3;
|
|
|
|
CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TNC->TCPInfo->CMS<<3);
|
|
CheckMenuItem(TCP->hLogMenu, 0, MF_BYPOSITION | LogEnabled<<3);
|
|
CheckMenuItem(TCP->hLogMenu, 1, MF_BYPOSITION | CMSLogEnabled<<3);
|
|
#endif
|
|
// Malloc TCP Session Stucts
|
|
|
|
for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++)
|
|
{
|
|
TNC->Streams[i].ConnectionInfo = zalloc(sizeof(struct ConnectionInfo));
|
|
TCP->CurrentSockets = i; //Record max used to save searching all entries
|
|
#ifndef LINBPQ
|
|
if (i > 0)
|
|
ModifyMenu(TCP->hDisMenu,i - 1 ,MF_BYPOSITION | MF_STRING,IDM_DISCONNECT + 1, ".");
|
|
#endif
|
|
}
|
|
|
|
TNC->PortRecord = PortRecord;
|
|
|
|
Sleep(500);
|
|
OpenSockets(TNC);
|
|
OpenSockets6(TNC);
|
|
SetupListenSet(TNC);
|
|
CheckCMS(TNC);
|
|
ShowConnections(TNC);
|
|
}
|
|
|
|
break;
|
|
|
|
case 5: // Close
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
for (n = 1; n <= TCP->CurrentSockets; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
closesocket(sockptr->socket);
|
|
}
|
|
|
|
shutdown(TCP->TCPSock, SD_BOTH);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock[n])
|
|
shutdown(TCP->FBBsock[n++], SD_BOTH);
|
|
|
|
shutdown(TCP->Relaysock, SD_BOTH);
|
|
shutdown(TCP->HTTPsock, SD_BOTH);
|
|
shutdown(TCP->HTTPsock6, SD_BOTH);
|
|
|
|
shutdown(TCP->sock6, SD_BOTH);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock6[n])
|
|
shutdown(TCP->FBBsock6[n++], SD_BOTH);
|
|
|
|
shutdown(TCP->Relaysock6, SD_BOTH);
|
|
|
|
Sleep(500);
|
|
closesocket(TCP->TCPSock);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock[n])
|
|
closesocket(TCP->FBBsock[n++]);
|
|
|
|
closesocket(TCP->Relaysock);
|
|
|
|
closesocket(TCP->sock6);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock6[n])
|
|
closesocket(TCP->FBBsock6[n++]);
|
|
|
|
closesocket(TCP->Relaysock6);
|
|
closesocket(TCP->HTTPsock);
|
|
closesocket(TCP->HTTPsock6);
|
|
|
|
return (0);
|
|
|
|
case 6: // Scan Control
|
|
|
|
return 0; // None Yet
|
|
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
|
|
{
|
|
int Len;
|
|
char msg[256];
|
|
struct ConnectionInfo * sockptr;
|
|
int i,n;
|
|
|
|
char CMSStatus[80] = "";
|
|
|
|
if (TNC->TCPInfo->CMS)
|
|
{
|
|
if (TNC->TCPInfo->CMSOK)
|
|
strcpy(CMSStatus, "CMS Ok");
|
|
else
|
|
strcpy(CMSStatus, "No CMS");
|
|
}
|
|
|
|
Len = sprintf(Buff, "<html><meta http-equiv=expires content=0><meta http-equiv=refresh content=15>"
|
|
"<head><title>Telnet Status</title></head><body><b>Telnet Status %s</b>", CMSStatus);
|
|
|
|
Len += sprintf(&Buff[Len], "<table style=\"text-align: left; width: 250px; font-family: monospace; align=center \" border=1 cellpadding=2 cellspacing=2>");
|
|
|
|
|
|
Len += sprintf(&Buff[Len], "<tr><th>User</th><th>Callsign</th><th>Queue</th></tr>");
|
|
|
|
for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++)
|
|
{
|
|
sockptr=TNC->Streams[n].ConnectionInfo;
|
|
|
|
if (!sockptr->SocketActive)
|
|
{
|
|
strcpy(msg,"<tr><td>Idle</td><td> </td><td> </td></tr>");
|
|
}
|
|
else
|
|
{
|
|
if (sockptr->UserPointer == 0)
|
|
{
|
|
if (sockptr->HTTPMode)
|
|
{
|
|
char Addr[100];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
if (sockptr->WebSocks)
|
|
sprintf(msg,"<tr><td>Websock<%s</td><td> </td><td> </td></tr>", Addr);
|
|
else
|
|
sprintf(msg,"<tr><td>HTTP<%s</td><td> </td><td> </td></tr>", Addr);
|
|
}
|
|
else if (sockptr->DRATSMode)
|
|
{
|
|
char Addr[100];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
sprintf(msg,"<tr><td>DRATS<%s</td><td> </td><td> </td></tr>", Addr);
|
|
}
|
|
else
|
|
strcpy(msg,"<tr><td>Logging in</td><td> </td><td> </td></tr>");
|
|
}
|
|
else
|
|
{
|
|
i=sprintf(msg,"<tr><td>%s</td><td>%s</td><td>%d</td></tr>",
|
|
sockptr->UserPointer->UserName, sockptr->Callsign,
|
|
sockptr->FromHostBuffPutptr - sockptr->FromHostBuffGetptr);
|
|
}
|
|
}
|
|
Len += sprintf(&Buff[Len], "%s", msg);
|
|
}
|
|
|
|
Len += sprintf(&Buff[Len], "</table>");
|
|
return Len;
|
|
}
|
|
|
|
|
|
|
|
void * TelnetExtInit(EXTPORTDATA * PortEntry)
|
|
{
|
|
char msg[500];
|
|
struct TNCINFO * TNC;
|
|
struct TCPINFO * TCP;
|
|
int port;
|
|
char * ptr;
|
|
int i;
|
|
HWND x=0;
|
|
|
|
/*
|
|
UCHAR NC[257];
|
|
WCHAR WC[1024];
|
|
|
|
int WLen, NLen;
|
|
|
|
UINT UTF[256] = {0};
|
|
UINT UTFL[256];
|
|
|
|
int n, u;
|
|
|
|
for (n = 0; n < 256; n++)
|
|
NC[n] =n ;
|
|
|
|
n = MultiByteToWideChar(437, 0, NC, 256, &WC[0], 1024);
|
|
|
|
for (n = 0; n < 256; n++)
|
|
UTFL[n] = WideCharToMultiByte(CP_UTF8, 0, &WC[n], 1, &UTF[n], 1024 , NULL, NULL);
|
|
|
|
// write UTF8 data as source
|
|
|
|
{
|
|
HANDLE Handle;
|
|
int i, n, Len;
|
|
char Line [256];
|
|
|
|
|
|
Handle = CreateFile("c:\\UTF8437Data.c", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
n = wsprintf (Line, "unsigned int CP437toUTF8Data[128] = {\r\n");
|
|
|
|
WriteFile(Handle, Line ,n , &n, NULL);
|
|
|
|
if (Handle != INVALID_HANDLE_VALUE)
|
|
{
|
|
for (i = 128; i < 256; i += 4)
|
|
{
|
|
n = wsprintf (Line, " %d, %d, %d, %d, \r\n",
|
|
UTF[i], UTF[i+1], UTF[i+2], UTF[i+3]);
|
|
WriteFile(Handle, Line ,n , &n, NULL);
|
|
|
|
}
|
|
|
|
WriteFile(Handle, "};\r\n", 4, &n, NULL);
|
|
}
|
|
n = wsprintf (Line, "unsigned int CP437toUTF8DataLen[128] = {\r\n");
|
|
|
|
WriteFile(Handle, Line ,n , &n, NULL);
|
|
|
|
if (Handle != INVALID_HANDLE_VALUE)
|
|
{
|
|
for (i = 128; i < 256;i += 4)
|
|
{
|
|
n = wsprintf (Line, " %d, %d, %d, %d, \r\n",
|
|
UTFL[i], UTFL[i+1], UTFL[i+2], UTFL[i+3]);
|
|
WriteFile(Handle, Line ,n , &n, NULL);
|
|
|
|
}
|
|
|
|
WriteFile(Handle, "};\r\n", 4, &n, NULL);
|
|
|
|
SetEndOfFile(Handle);
|
|
|
|
CloseHandle(Handle);
|
|
}
|
|
}
|
|
*/
|
|
|
|
DeleteTelnetLogFiles();
|
|
|
|
initUTF8();
|
|
|
|
sprintf(msg,"Telnet Server ");
|
|
WritetoConsoleLocal(msg);
|
|
|
|
port=PortEntry->PORTCONTROL.PORTNUMBER;
|
|
|
|
ReadConfigFile(port, ProcessLine);
|
|
|
|
TNC = TNCInfo[port];
|
|
|
|
if (TNC == NULL)
|
|
{
|
|
// Not defined in Config file
|
|
|
|
WritetoConsoleLocal("\n");
|
|
return ExtProc;
|
|
}
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
TNC->Port = port;
|
|
|
|
TNC->Hardware = H_TELNET;
|
|
|
|
PortEntry->MAXHOSTMODESESSIONS = TNC->TCPInfo->MaxSessions + 1; // Default
|
|
|
|
TNC->PortRecord = PortEntry;
|
|
|
|
if (PortEntry->PORTCONTROL.PORTCALL[0] != 0)
|
|
ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
|
|
|
|
PortEntry->PORTCONTROL.PROTOCOL = 10; // WINMOR/Pactor
|
|
PortEntry->PORTCONTROL.PORTQUALITY = 0;
|
|
PortEntry->SCANCAPABILITIES = NONE; // No Scan Control
|
|
PortEntry->PERMITGATEWAY = TRUE;
|
|
|
|
ptr=strchr(TNC->NodeCall, ' ');
|
|
if (ptr) *(ptr) = 0; // Null Terminate
|
|
|
|
TELNETMONVECPTR->HOSTAPPLFLAGS = 0x80; // Requext Monitoring
|
|
|
|
if (TCP->LoginMsg[0] == 0)
|
|
strcpy(TCP->LoginMsg, "user:");
|
|
if (TCP->PasswordMsg[0] == 0)
|
|
strcpy(TCP->PasswordMsg, "password:");
|
|
if (TCP->cfgCTEXT[0] == 0)
|
|
{
|
|
char Call[10];
|
|
memcpy(Call, MYNODECALL, 10);
|
|
strlop(Call, ' ');
|
|
|
|
sprintf(TCP->cfgCTEXT, "Connected to %s's Telnet Server\r\n\r\n", Call);
|
|
}
|
|
|
|
PortEntry->PORTCONTROL.TNC = TNC;
|
|
|
|
TNC->WebWindowProc = WebProc;
|
|
TNC->WebWinX = 260;
|
|
TNC->WebWinY = 325;
|
|
|
|
#ifndef LINBPQ
|
|
|
|
CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, TelWndProc, 400, 300, NULL);
|
|
|
|
TCP->hCMSWnd = CreateWindowEx(0, "STATIC", "CMS OK ", WS_CHILD | WS_VISIBLE,
|
|
240,0,60,16, TNC->hDlg, NULL, hInstance, NULL);
|
|
|
|
SendMessage(TCP->hCMSWnd, WM_SETFONT, (WPARAM)hFont, 0);
|
|
|
|
x = CreateWindowEx(0, "STATIC", " User Callsign Queue", WS_CHILD | WS_VISIBLE,
|
|
0,0,240,16, TNC->hDlg, NULL, hInstance, NULL);
|
|
|
|
SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0);
|
|
|
|
|
|
TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL,
|
|
0,20,400,2800, TNC->hDlg, NULL, hInstance, NULL);
|
|
|
|
SendMessage(TNC->hMonitor, WM_SETFONT, (WPARAM)hFont, 0);
|
|
|
|
hPopMenu = CreatePopupMenu();
|
|
hPopMenu2 = CreatePopupMenu();
|
|
hPopMenu3 = CreatePopupMenu();
|
|
|
|
AppendMenu(hPopMenu, MF_STRING + MF_POPUP, (UINT)hPopMenu2,"Logging Options");
|
|
AppendMenu(hPopMenu, MF_STRING + MF_POPUP, (UINT)hPopMenu3,"Disconnect User");
|
|
AppendMenu(hPopMenu, MF_STRING, TELNET_RECONFIG, "ReRead Config");
|
|
AppendMenu(hPopMenu, MF_STRING, CMSENABLED, "CMS Access Enabled");
|
|
AppendMenu(hPopMenu, MF_STRING, USECACHEDCMS, "Using Cached CMS Addresses");
|
|
|
|
AppendMenu(hPopMenu2, MF_STRING, IDM_LOGGING, "Log incoming connections");
|
|
AppendMenu(hPopMenu2, MF_STRING, IDM_CMS_LOGGING, "Log CMS Connections");
|
|
|
|
AppendMenu(hPopMenu3, MF_STRING, IDM_DISCONNECT, "1");
|
|
|
|
TCP->hActionMenu = hPopMenu;
|
|
|
|
CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3);
|
|
|
|
TCP->hLogMenu = hPopMenu2;
|
|
TCP->hDisMenu = hPopMenu3;
|
|
|
|
CheckMenuItem(TCP->hLogMenu, 0, MF_BYPOSITION | LogEnabled<<3);
|
|
CheckMenuItem(TCP->hLogMenu, 1, MF_BYPOSITION | CMSLogEnabled<<3);
|
|
|
|
// ModifyMenu(hMenu, 1, MF_BYPOSITION | MF_OWNERDRAW | MF_STRING, 10000, 0);
|
|
|
|
#endif
|
|
|
|
// Malloc TCP Session Stucts
|
|
|
|
for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++)
|
|
{
|
|
TNC->Streams[i].ConnectionInfo = zalloc(sizeof(struct ConnectionInfo));
|
|
TNC->Streams[i].ConnectionInfo->Number = i;
|
|
TCP->CurrentSockets = i; //Record max used to save searching all entries
|
|
|
|
sprintf(msg,"%d", i);
|
|
|
|
#ifndef LINBPQ
|
|
if (i > 1)
|
|
AppendMenu(TCP->hDisMenu, MF_STRING, IDM_DISCONNECT ,msg);
|
|
#endif
|
|
}
|
|
|
|
OpenSockets(TNC);
|
|
OpenSockets6(TNC);
|
|
SetupListenSet(TNC);
|
|
TNC->RIG = &TNC->DummyRig; // Not using Rig control, so use Dummy
|
|
|
|
if (TCP->CMS)
|
|
CheckCMS(TNC);
|
|
|
|
WritetoConsoleLocal("\n");
|
|
|
|
ShowConnections(TNC);
|
|
|
|
if (TCP->ReportHybrid)
|
|
SendWL2KRegisterHybrid(TNC);
|
|
|
|
|
|
return ExtProc;
|
|
}
|
|
|
|
SOCKET OpenUDPSocket(struct TNCINFO * TNC)
|
|
{
|
|
u_long param = 1;
|
|
struct sockaddr_in sinx;
|
|
int err, ret;
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
char Msg[80];
|
|
|
|
TCP->SNMPsock = socket(AF_INET,SOCK_DGRAM,0);
|
|
|
|
if (TCP->SNMPsock == INVALID_SOCKET)
|
|
{
|
|
WritetoConsoleLocal("Failed to create SNMP UDP socket");
|
|
return 0;
|
|
}
|
|
|
|
ioctl (TCP->SNMPsock, FIONBIO, ¶m);
|
|
|
|
sinx.sin_family = AF_INET;
|
|
sinx.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
sinx.sin_port = htons(TCP->SNMPPort);
|
|
|
|
ret = bind(TCP->SNMPsock, (struct sockaddr *) &sinx, sizeof(sinx));
|
|
|
|
if (ret != 0)
|
|
{
|
|
// Bind Failed
|
|
|
|
err = WSAGetLastError();
|
|
sprintf(Msg, "Bind Failed for SNMP UDP socket %d - error code = %d", TCP->SNMPPort, err);
|
|
WritetoConsoleLocal(Msg);
|
|
return 0;
|
|
}
|
|
|
|
return TCP->SNMPsock;
|
|
}
|
|
|
|
|
|
|
|
SOCKET OpenSocket4(struct TNCINFO * xTNC, int port)
|
|
{
|
|
struct sockaddr_in local_sin; /* Local socket - internet style */
|
|
struct sockaddr_in * psin;
|
|
SOCKET sock = 0;
|
|
u_long param=1;
|
|
|
|
char szBuff[80];
|
|
|
|
psin=&local_sin;
|
|
psin->sin_family = AF_INET;
|
|
psin->sin_addr.s_addr = INADDR_ANY;
|
|
|
|
if (port)
|
|
{
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
sprintf(szBuff, "socket() failed error %d\n", WSAGetLastError());
|
|
WritetoConsoleLocal(szBuff);
|
|
return 0;
|
|
}
|
|
|
|
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *)¶m,4);
|
|
|
|
|
|
psin->sin_port = htons(port); // Convert to network ordering
|
|
|
|
if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR)
|
|
{
|
|
sprintf(szBuff, "bind(sock) failed port %d Error %d\n", port, WSAGetLastError());
|
|
WritetoConsoleLocal(szBuff);
|
|
closesocket( sock );
|
|
return FALSE;
|
|
}
|
|
|
|
if (listen( sock, MAX_PENDING_CONNECTS ) < 0)
|
|
{
|
|
sprintf(szBuff, "listen(sock) failed port %d Error %d\n", port, WSAGetLastError());
|
|
WritetoConsoleLocal(szBuff);
|
|
return FALSE;
|
|
}
|
|
ioctl(sock, FIONBIO, ¶m);
|
|
}
|
|
|
|
return sock;
|
|
}
|
|
|
|
BOOL OpenSockets(struct TNCINFO * TNC)
|
|
{
|
|
struct sockaddr_in local_sin; /* Local socket - internet style */
|
|
struct sockaddr_in * psin;
|
|
u_long param=1;
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
int n;
|
|
|
|
if (!TCP->IPV4)
|
|
return TRUE;
|
|
|
|
psin=&local_sin;
|
|
psin->sin_family = AF_INET;
|
|
psin->sin_addr.s_addr = INADDR_ANY;
|
|
|
|
if (TCP->TCPPort)
|
|
TCP->TCPSock = OpenSocket4(TNC, TCP->TCPPort);
|
|
|
|
n = 0;
|
|
|
|
while (TCP->FBBPort[n])
|
|
{
|
|
TCP->FBBsock[n] = OpenSocket4(TNC, TCP->FBBPort[n]);
|
|
n++;
|
|
}
|
|
|
|
if (TCP->RelayPort)
|
|
TCP->Relaysock = OpenSocket4(TNC, TCP->RelayPort);
|
|
|
|
if (TCP->TriModePort)
|
|
{
|
|
TCP->TriModeSock = OpenSocket4(TNC, TCP->TriModePort);
|
|
TCP->TriModeDataSock = OpenSocket4(TNC, TCP->TriModePort + 1);
|
|
}
|
|
|
|
if (TCP->HTTPPort)
|
|
TCP->HTTPsock = OpenSocket4(TNC, TCP->HTTPPort);
|
|
|
|
if (TCP->APIPort)
|
|
TCP->APIsock = OpenSocket4(TNC, TCP->APIPort);
|
|
|
|
if (TCP->SyncPort)
|
|
TCP->Syncsock = OpenSocket4(TNC, TCP->SyncPort);
|
|
|
|
if (TCP->DRATSPort)
|
|
TCP->DRATSsock = OpenSocket4(TNC, TCP->DRATSPort);
|
|
|
|
if (TCP->SNMPPort)
|
|
TCP->SNMPsock = OpenUDPSocket(TNC);
|
|
|
|
CMSUser.UserName = _strdup("CMS");
|
|
|
|
TriModeUser.Secure = TRUE;
|
|
TriModeUser.UserName = _strdup("TRIMODE");
|
|
TriModeUser.Callsign = zalloc(10);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
SOCKET OpenSocket6(struct TNCINFO * TNC, int port)
|
|
{
|
|
|
|
struct sockaddr_in6 local_sin; /* Local socket - internet style */
|
|
struct sockaddr_in6 * psin;
|
|
SOCKET sock;
|
|
char szBuff[80];
|
|
u_long param=1;
|
|
|
|
memset(&local_sin, 0, sizeof(local_sin));
|
|
|
|
psin=&local_sin;
|
|
psin->sin6_family = AF_INET6;
|
|
psin->sin6_addr = in6addr_any;
|
|
psin->sin6_flowinfo = 0;
|
|
psin->sin6_scope_id = 0;
|
|
|
|
sock = socket(AF_INET6, SOCK_STREAM, 0);
|
|
|
|
#ifndef WIN32
|
|
|
|
if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, ¶m, sizeof(param)) < 0)
|
|
{
|
|
perror("setting option IPV6_V6ONLY");
|
|
}
|
|
|
|
#endif
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
sprintf(szBuff, "IPV6 socket() failed error %d\n", WSAGetLastError());
|
|
WritetoConsoleLocal(szBuff);
|
|
return FALSE;
|
|
}
|
|
|
|
psin->sin6_port = htons(port); // Convert to network ordering
|
|
|
|
if (bind(sock, (struct sockaddr FAR *)psin, sizeof(local_sin)) == SOCKET_ERROR)
|
|
{
|
|
sprintf(szBuff, "IPV6 bind(sock) failed Port %d Error %d\n", port, WSAGetLastError());
|
|
WritetoConsoleLocal(szBuff);
|
|
closesocket( sock );
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (listen( sock, MAX_PENDING_CONNECTS ) < 0)
|
|
{
|
|
sprintf(szBuff, "IPV6 listen(sock) failed Error %d\n", WSAGetLastError());
|
|
WritetoConsoleLocal(szBuff);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
ioctl(sock, FIONBIO, ¶m);
|
|
return sock;
|
|
}
|
|
|
|
|
|
BOOL OpenSockets6(struct TNCINFO * TNC)
|
|
{
|
|
struct sockaddr_in6 local_sin; /* Local socket - internet style */
|
|
|
|
struct sockaddr_in6 * psin;
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
int n;
|
|
u_long param=1;
|
|
|
|
if (!TCP->IPV6)
|
|
return TRUE;
|
|
|
|
memset(&local_sin, 0, sizeof(local_sin));
|
|
|
|
psin=&local_sin;
|
|
psin->sin6_family = AF_INET6;
|
|
psin->sin6_addr = in6addr_any;
|
|
psin->sin6_flowinfo = 0;
|
|
psin->sin6_scope_id = 0;
|
|
|
|
|
|
if (TCP->TCPPort)
|
|
TCP->sock6 = OpenSocket6(TNC, TCP->TCPPort);
|
|
|
|
n = 0;
|
|
|
|
while (TCP->FBBPort[n])
|
|
{
|
|
TCP->FBBsock6[n] = OpenSocket6(TNC, TCP->FBBPort[n]);
|
|
n++;
|
|
}
|
|
|
|
if (TCP->RelayPort)
|
|
TCP->Relaysock6 = OpenSocket6(TNC, TCP->RelayPort);
|
|
|
|
if (TCP->HTTPPort)
|
|
TCP->HTTPsock6 = OpenSocket6(TNC, TCP->HTTPPort);
|
|
|
|
if (TCP->APIPort)
|
|
TCP->APIsock6 = OpenSocket6(TNC, TCP->APIPort);
|
|
|
|
if (TCP->SyncPort)
|
|
TCP->Syncsock6 = OpenSocket6(TNC, TCP->SyncPort);
|
|
|
|
if (TCP->DRATSPort)
|
|
TCP->DRATSsock6 = OpenSocket6(TNC, TCP->DRATSPort);
|
|
|
|
|
|
CMSUser.UserName = _strdup("CMS");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static VOID SetupListenSet(struct TNCINFO * TNC)
|
|
{
|
|
// Set up master set of fd's for checking for incoming calls
|
|
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
SOCKET maxsock = 0;
|
|
int n;
|
|
fd_set * readfd = &TCP->ListenSet;
|
|
SOCKET sock;
|
|
|
|
FD_ZERO(readfd);
|
|
|
|
n = 0;
|
|
while (n < 100)
|
|
{
|
|
sock = TCP->FBBsock[n++];
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
}
|
|
|
|
sock = TCP->TCPSock;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->Relaysock;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->HTTPsock;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->APIsock;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->Syncsock;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->DRATSsock;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->TriModeSock;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->TriModeDataSock;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
n = 0;
|
|
while (n < 100)
|
|
{
|
|
sock = TCP->FBBsock6[n++];
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
}
|
|
|
|
sock = TCP->sock6;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->Relaysock6;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->HTTPsock6;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->APIsock6;
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
|
|
sock = TCP->DRATSsock6;
|
|
|
|
if (sock)
|
|
{
|
|
FD_SET(sock, readfd);
|
|
if (sock > maxsock)
|
|
maxsock = sock;
|
|
}
|
|
TCP->maxsock = maxsock;
|
|
}
|
|
|
|
|
|
VOID TelnetPoll(int Port)
|
|
{
|
|
struct TNCINFO * TNC = TNCInfo[Port];
|
|
UCHAR * Poll = TNC->TXBuffer;
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
struct STREAMINFO * STREAM;
|
|
int Msglen;
|
|
int Stream;
|
|
|
|
// we now poll for incoming connections
|
|
|
|
struct timeval timeout;
|
|
int retval;
|
|
int n;
|
|
struct ConnectionInfo * sockptr;
|
|
SOCKET sock;
|
|
int Active = 0;
|
|
SOCKET maxsock;
|
|
|
|
fd_set readfd, writefd, exceptfd;
|
|
timeout.tv_sec = 0;
|
|
timeout.tv_usec = 0; // poll
|
|
|
|
if (TCP->maxsock == 0)
|
|
goto nosocks;
|
|
|
|
memcpy(&readfd, &TCP->ListenSet, sizeof(fd_set));
|
|
|
|
retval = select((int)(TCP->maxsock) + 1, &readfd, NULL, NULL, &timeout);
|
|
|
|
if (retval == -1)
|
|
{
|
|
retval = WSAGetLastError();
|
|
perror("listen select");
|
|
}
|
|
|
|
if (retval)
|
|
{
|
|
n = 0;
|
|
while (TCP->FBBsock[n])
|
|
{
|
|
sock = TCP->FBBsock[n];
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->FBBPort[n]);
|
|
|
|
n++;
|
|
}
|
|
|
|
sock = TCP->TCPSock;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->TCPPort);
|
|
}
|
|
|
|
sock = TCP->TriModeSock;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->TriModePort);
|
|
}
|
|
sock = TCP->TriModeDataSock;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->TriModePort + 1);
|
|
}
|
|
|
|
sock = TCP->Relaysock;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->RelayPort);
|
|
}
|
|
|
|
sock = TCP->HTTPsock;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->HTTPPort);
|
|
}
|
|
|
|
sock = TCP->DRATSsock;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->DRATSPort);
|
|
}
|
|
|
|
sock = TCP->Syncsock;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->SyncPort);
|
|
}
|
|
|
|
|
|
|
|
n = 0;
|
|
|
|
while (TCP->FBBsock6[n])
|
|
{
|
|
sock = TCP->FBBsock6[n];
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->FBBPort[n]);
|
|
n++;
|
|
}
|
|
|
|
sock = TCP->sock6;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->TCPPort);
|
|
}
|
|
|
|
sock = TCP->Relaysock6;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->RelayPort);
|
|
}
|
|
|
|
sock = TCP->HTTPsock6;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->HTTPPort);
|
|
}
|
|
|
|
sock = TCP->DRATSsock6;
|
|
if (sock)
|
|
{
|
|
if (FD_ISSET(sock, &readfd))
|
|
Socket_Accept(TNC, sock, TCP->DRATSPort);
|
|
}
|
|
}
|
|
|
|
// look for data on any active sockets
|
|
|
|
maxsock = 0;
|
|
|
|
FD_ZERO(&readfd);
|
|
FD_ZERO(&writefd);
|
|
FD_ZERO(&exceptfd);
|
|
|
|
for (n = 0; n <= TCP->MaxSessions; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
|
|
// Should we use write event after a blocked write ????
|
|
|
|
if (sockptr->SocketActive)
|
|
{
|
|
// if (sockptr->socket == 0)
|
|
// {
|
|
// Debugprintf("Active Session but zero socket");
|
|
// DataSocket_Disconnect(TNC, sockptr);
|
|
// return;
|
|
// }
|
|
|
|
if (TNC->Streams[n].Connecting)
|
|
{
|
|
// look for complete or failed
|
|
|
|
FD_SET(sockptr->socket, &writefd);
|
|
FD_SET(sockptr->socket, &exceptfd);
|
|
}
|
|
else
|
|
{
|
|
FD_SET(sockptr->socket, &readfd);
|
|
FD_SET(sockptr->socket, &exceptfd);
|
|
}
|
|
Active++;
|
|
if (sockptr->socket > maxsock)
|
|
maxsock = sockptr->socket;
|
|
|
|
if (sockptr->TriModeDataSock)
|
|
{
|
|
FD_SET(sockptr->TriModeDataSock, &readfd);
|
|
FD_SET(sockptr->TriModeDataSock, &exceptfd);
|
|
|
|
if (sockptr->TriModeDataSock > maxsock)
|
|
maxsock = sockptr->TriModeDataSock;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Active)
|
|
{
|
|
retval = select((int)maxsock + 1, &readfd, &writefd, &exceptfd, &timeout);
|
|
|
|
if (retval == -1)
|
|
{
|
|
perror("data select");
|
|
Debugprintf("Telnet Select Error %d Active %d", WSAGetLastError(), Active);
|
|
|
|
for (n = 0; n <= TCP->MaxSessions; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
if (sockptr->SocketActive)
|
|
Debugprintf("Active Session %d socket %d", n, sockptr->socket);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (retval)
|
|
{
|
|
// see who has data
|
|
|
|
for (n = 0; n <= TCP->MaxSessions; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
|
|
if (sockptr->SocketActive)
|
|
{
|
|
sock = sockptr->socket;
|
|
|
|
if (sockptr->TriModeDataSock)
|
|
{
|
|
if (FD_ISSET(sockptr->TriModeDataSock, &readfd))
|
|
{
|
|
ProcessTriModeDataMessage(TNC, sockptr, sockptr->TriModeDataSock, &TNC->Streams[n]);
|
|
}
|
|
}
|
|
|
|
if (FD_ISSET(sock, &readfd))
|
|
{
|
|
if (sockptr->RelayMode)
|
|
DataSocket_ReadRelay(TNC, sockptr, sock, &TNC->Streams[n]);
|
|
else if (sockptr->HTTPMode)
|
|
DataSocket_ReadHTTP(TNC, sockptr, sock, n);
|
|
else if (sockptr->SyncMode)
|
|
DataSocket_ReadSync(TNC, sockptr, sock, n);
|
|
else if (sockptr->FBBMode)
|
|
DataSocket_ReadFBB(TNC, sockptr, sock, n);
|
|
else if (sockptr->DRATSMode)
|
|
DataSocket_ReadDRATS(TNC, sockptr, sock, n);
|
|
else
|
|
DataSocket_Read(TNC, sockptr, sock, &TNC->Streams[n]);
|
|
}
|
|
|
|
if (FD_ISSET(sock, &exceptfd))
|
|
{
|
|
Debugprintf("exceptfd set");
|
|
Telnet_Connected(TNC, sockptr, sock, 1);
|
|
}
|
|
|
|
if (FD_ISSET(sock, &writefd))
|
|
Telnet_Connected(TNC, sockptr, sock, 0);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
nosocks:
|
|
|
|
// Try SNMP
|
|
|
|
if (TCP->SNMPsock)
|
|
{
|
|
struct sockaddr_in rxaddr;
|
|
char rxbuff[500];
|
|
int addrlen = sizeof(struct sockaddr_in);
|
|
int Offset = 0;
|
|
|
|
int len = recvfrom(TCP->SNMPsock, rxbuff, 500, 0,(struct sockaddr *)&rxaddr, &addrlen);
|
|
|
|
if (len > 0)
|
|
{
|
|
UCHAR Reply[256];
|
|
int SendLen;
|
|
|
|
SendLen = ProcessSNMPPayload(rxbuff, len, Reply, &Offset);
|
|
|
|
if (SendLen == 0)
|
|
return;
|
|
|
|
sendto(TCP->SNMPsock, &Reply[Offset], SendLen, 0, (struct sockaddr *)&rxaddr, addrlen);
|
|
return;
|
|
}
|
|
}
|
|
while (TELNETMONVECPTR->HOSTTRACEQ)
|
|
{
|
|
int len;
|
|
time_t stamp;
|
|
BOOL MonitorNODES = FALSE;
|
|
MESSAGE * monbuff;
|
|
UCHAR * monchars;
|
|
|
|
unsigned char buffer[1024] = "\xff\x1b\xb";
|
|
|
|
monbuff = Q_REM((void **)&TELNETMONVECPTR->HOSTTRACEQ);
|
|
monchars = (UCHAR *)monbuff;
|
|
|
|
stamp = monbuff->Timestamp;
|
|
|
|
if (monbuff->PORT & 0x80) // TX
|
|
buffer[2] = 91;
|
|
else
|
|
buffer[2] = 17;
|
|
|
|
for (Stream = 0; Stream <= TCP->MaxSessions; Stream++)
|
|
{
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
if (TNC->PortRecord->ATTACHEDSESSIONS[Stream])
|
|
{
|
|
struct ConnectionInfo * sockptr = STREAM->ConnectionInfo;
|
|
|
|
if (sockptr->BPQTermMode)
|
|
{
|
|
if (sizeof(void *) > 4)
|
|
monchars += 4;
|
|
|
|
if (!sockptr->MonitorNODES && monchars[21] == 3 && monchars[22] == 0xcf && monchars[23] == 0xff)
|
|
{
|
|
len = 0;
|
|
}
|
|
else
|
|
{
|
|
unsigned long long SaveMMASK = MMASK;
|
|
BOOL SaveMTX = MTX;
|
|
BOOL SaveMCOM = MCOM;
|
|
BOOL SaveMUI = MUIONLY;
|
|
|
|
IntSetTraceOptionsEx(sockptr->MMASK, sockptr->MTX, sockptr->MCOM, sockptr->MUIOnly);
|
|
len = IntDecodeFrame((MESSAGE *)monbuff, &buffer[3], stamp, sockptr->MMASK, FALSE, FALSE);
|
|
IntSetTraceOptionsEx(SaveMMASK, SaveMTX, SaveMCOM, SaveMUI);
|
|
|
|
if (len)
|
|
{
|
|
len += 3;
|
|
buffer[len++] = 0xfe;
|
|
send(STREAM->ConnectionInfo->socket, buffer, len, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ReleaseBuffer(monbuff);
|
|
}
|
|
|
|
for (Stream = 0; Stream <= TCP->MaxSessions; Stream++)
|
|
{
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && STREAM->Attached == 0)
|
|
{
|
|
// New Attach
|
|
|
|
int calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, TNC->Streams[Stream].MyCall);
|
|
TNC->Streams[Stream].MyCall[calllen] = 0;
|
|
|
|
STREAM->Attached = TRUE;
|
|
STREAM->FramesQueued= 0;
|
|
STREAM->NoCMSFallback = 0;
|
|
|
|
continue;
|
|
}
|
|
|
|
if (STREAM->Attached)
|
|
{
|
|
if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0 && STREAM->Attached)
|
|
{
|
|
// Node has disconnected - clear any connection
|
|
|
|
struct ConnectionInfo * sockptr = TNC->Streams[Stream].ConnectionInfo;
|
|
SOCKET sock = sockptr->socket;
|
|
char Msg[80];
|
|
PMSGWITHLEN buffptr;
|
|
|
|
STREAM->Attached = FALSE;
|
|
STREAM->Connected = FALSE;
|
|
STREAM->NoCMSFallback = FALSE;
|
|
|
|
sockptr->FromHostBuffPutptr = sockptr->FromHostBuffGetptr = 0; // clear any queued data
|
|
|
|
while(TNC->Streams[Stream].BPQtoPACTOR_Q)
|
|
{
|
|
buffptr = (PMSGWITHLEN)Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q);
|
|
if (TelSendPacket(Stream, &TNC->Streams[Stream], buffptr, sockptr->ADIF) == FALSE)
|
|
{
|
|
// Send failed, and has saved packet
|
|
// free saved and discard any more on queue
|
|
|
|
free(sockptr->ResendBuffer);
|
|
sockptr->ResendBuffer = NULL;
|
|
sockptr->ResendLen = 0;
|
|
|
|
while(TNC->Streams[Stream].BPQtoPACTOR_Q)
|
|
{
|
|
buffptr=Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q);
|
|
ReleaseBuffer(buffptr);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
while(TNC->Streams[Stream].PACTORtoBPQ_Q)
|
|
{
|
|
buffptr=Q_REM(&TNC->Streams[Stream].PACTORtoBPQ_Q);
|
|
ReleaseBuffer(buffptr);
|
|
}
|
|
|
|
if (LogEnabled)
|
|
{
|
|
char logmsg[120];
|
|
sprintf(logmsg,"%d Disconnected. Bytes Sent = %d Bytes Received %d\n",
|
|
sockptr->Number, STREAM->bytesTXed, STREAM->bytesRXed);
|
|
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
if (!sockptr->FBBMode)
|
|
{
|
|
sprintf(Msg,"*** Disconnected from Stream %d\r\n",Stream);
|
|
send(sock, Msg, (int)strlen(Msg),0);
|
|
}
|
|
|
|
if (sockptr->UserPointer == &TriModeUser)
|
|
{
|
|
// Always Disconnect
|
|
|
|
send(sockptr->socket, "DISCONNECTED\r\n", 14, 0);
|
|
return;
|
|
}
|
|
|
|
if (sockptr->UserPointer == &CMSUser)
|
|
{
|
|
if (CMSLogEnabled)
|
|
{
|
|
char logmsg[120];
|
|
sprintf(logmsg,"%d Disconnected. Bytes Sent = %d Bytes Received %d Time %d Seconds\r\n",
|
|
sockptr->Number, STREAM->bytesTXed, STREAM->bytesRXed, (int)(time(NULL) - sockptr->ConnectTime));
|
|
|
|
WriteCMSLog (logmsg);
|
|
}
|
|
|
|
// Don't report if Internet down unless ReportRelayTraffic set)
|
|
|
|
if (sockptr->RelaySession == FALSE || TCP->ReportRelayTraffic)
|
|
SendWL2KSessionRecord(sockptr->ADIF, STREAM->bytesTXed, STREAM->bytesRXed);
|
|
|
|
WriteADIFRecord(sockptr->ADIF);
|
|
|
|
if (sockptr->ADIF)
|
|
free(sockptr->ADIF);
|
|
|
|
sockptr->ADIF = NULL;
|
|
|
|
// Always Disconnect CMS Socket
|
|
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return;
|
|
}
|
|
|
|
if (sockptr->RelayMode)
|
|
{
|
|
// Always Disconnect Relay Socket
|
|
|
|
Sleep(100);
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return;
|
|
}
|
|
|
|
if (sockptr->Signon[0] || sockptr->ClientSession) // Outward Connect
|
|
{
|
|
Sleep(1000);
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return;
|
|
}
|
|
|
|
|
|
if (TCP->DisconnectOnClose)
|
|
{
|
|
Sleep(1000);
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
}
|
|
else
|
|
{
|
|
char DisfromNodeMsg[] = "Disconnected from Node - Telnet Session kept\r\n";
|
|
send(sockptr->socket, DisfromNodeMsg, (int)strlen(DisfromNodeMsg),0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (Stream = 0; Stream <= TCP->MaxSessions; Stream++)
|
|
{
|
|
struct ConnectionInfo * sockptr = TNC->Streams[Stream].ConnectionInfo;
|
|
STREAM = &TNC->Streams[Stream];
|
|
|
|
if (sockptr->SocketActive && sockptr->Keepalive && L4LIMIT)
|
|
{
|
|
#ifdef WIN32
|
|
if ((REALTIMETICKS - sockptr->LastSendTime) > (L4LIMIT - 60) * 9) // PC Ticks are about 10% slow
|
|
#else
|
|
if ((REALTIMETICKS - sockptr->LastSendTime) > (L4LIMIT - 60) * 10)
|
|
#endif
|
|
{
|
|
// Send Keepalive
|
|
|
|
sockptr->LastSendTime = REALTIMETICKS;
|
|
BuffertoNode(sockptr, "Keepalive\r", 10);
|
|
}
|
|
}
|
|
|
|
if (sockptr->ResendBuffer)
|
|
{
|
|
// Data saved after EWOULDBLOCK returned to send
|
|
|
|
UCHAR * ptr = sockptr->ResendBuffer;
|
|
sockptr->ResendBuffer = NULL;
|
|
|
|
SendAndCheck(sockptr, ptr, sockptr->ResendLen, 0);
|
|
free(ptr);
|
|
|
|
continue;
|
|
}
|
|
|
|
while (STREAM->BPQtoPACTOR_Q)
|
|
{
|
|
int datalen;
|
|
PMSGWITHLEN buffptr;
|
|
UCHAR * MsgPtr;
|
|
|
|
// Make sure there is space. Linux TCP buffer is quite small
|
|
// Windows doesn't support SIOCOUTQ
|
|
|
|
#ifndef WIN32
|
|
int value = 0, error;
|
|
|
|
error = ioctl(sockptr->socket, SIOCOUTQ, &value);
|
|
|
|
if (value > 1500)
|
|
break;
|
|
#endif
|
|
buffptr = (PMSGWITHLEN)Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q);
|
|
STREAM->FramesQueued--;
|
|
datalen = (int)(buffptr->Len);
|
|
MsgPtr = &buffptr->Data[0];
|
|
|
|
if (STREAM->ConnectionInfo->TriMode)
|
|
{
|
|
ProcessTrimodeResponse(TNC, STREAM, MsgPtr, datalen);
|
|
ReleaseBuffer(buffptr);
|
|
return;
|
|
}
|
|
|
|
|
|
if (TNC->Streams[Stream].Connected)
|
|
{
|
|
if (sockptr->SyncMode)
|
|
{
|
|
// Suppress Conected and SID - Relay doesn't understand them
|
|
|
|
if (strstr(buffptr->Data, "Connected to") || memcmp(buffptr->Data, "[BPQ-", 5) == 0)
|
|
{
|
|
ReleaseBuffer(buffptr);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (TelSendPacket(Stream, STREAM, buffptr, sockptr->ADIF) == FALSE)
|
|
{
|
|
// Send failed, and has requeued packet
|
|
// Dont send any more
|
|
|
|
break;
|
|
}
|
|
}
|
|
else // Not Connected
|
|
{
|
|
// Command. Do some sanity checking and look for things to process locally
|
|
|
|
datalen--; // Exclude CR
|
|
MsgPtr[datalen] = 0; // Null Terminate
|
|
|
|
if (_stricmp(MsgPtr, "NoFallback") == 0)
|
|
{
|
|
TNC->Streams[Stream].NoCMSFallback = TRUE;
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "Ok\r");
|
|
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
|
|
return;
|
|
}
|
|
|
|
if (_memicmp(MsgPtr, "D", 1) == 0)
|
|
{
|
|
TNC->Streams[Stream].ReportDISC = TRUE; // Tell Node
|
|
ReleaseBuffer(buffptr);
|
|
return;
|
|
}
|
|
|
|
if ((_memicmp(MsgPtr, "C", 1) == 0) && MsgPtr[1] == ' ' && datalen > 2) // Connect
|
|
{
|
|
char Host[100] = "";
|
|
char P2[100] = "";
|
|
char P3[100] = "";
|
|
char P4[100] = "";
|
|
char P5[100] = "";
|
|
char P6[100] = "";
|
|
char P7[100] = "";
|
|
unsigned int Port = 0;
|
|
int n;
|
|
|
|
n = sscanf(&MsgPtr[2], "%s %s %s %s %s %s %s",
|
|
&Host[0], &P2[0], &P3[0], &P4[0], &P5[0], &P6[0], &P7[0]);
|
|
|
|
sockptr->Signon[0] = 0; // Not outgoing;
|
|
sockptr->Keepalive = FALSE; // No Keepalives
|
|
sockptr->NoCallsign = FALSE;
|
|
sockptr->UTF8 = 0; // Not UTF8
|
|
|
|
if (_stricmp(Host, "HOST") == 0)
|
|
{
|
|
Port = atoi(P2);
|
|
|
|
if (Port > MaxBPQPortNo || TCP->CMDPort[Port] == 0)
|
|
{
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "Error - Invalid HOST Port\r");
|
|
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
|
|
STREAM->NeedDisc = 10;
|
|
return;
|
|
}
|
|
|
|
STREAM->Connecting = TRUE;
|
|
sockptr->CMSSession = FALSE;
|
|
sockptr->FBBMode = FALSE;
|
|
|
|
if (P3[0] == 'K' || P4[0] == 'K' || P5[0] == 'K' || P6[0] == 'K')
|
|
{
|
|
sockptr->Keepalive = TRUE;
|
|
sockptr->LastSendTime = REALTIMETICKS;
|
|
}
|
|
|
|
if (P3[0] == 'S' || P4[0] == 'S' || P5[0] == 'S' || P6[0] == 'S')
|
|
{
|
|
// Set Say flag on partner session
|
|
|
|
struct _TRANSPORTENTRY * Sess = TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->L4CROSSLINK;
|
|
if (Sess)
|
|
Sess->STAYFLAG = 1;
|
|
}
|
|
|
|
if (_stricmp(P3, "NOCALL") == 0 || _stricmp(P4, "NOCALL") == 0 || _stricmp(P5, "NOCALL") == 0 || _stricmp(P6, "NOCALL") == 0)
|
|
sockptr->NoCallsign = TRUE;
|
|
|
|
if (_stricmp(P3, "TRANS") == 0 || _stricmp(P4, "TRANS") == 0 || _stricmp(P5, "TRANS") == 0 || _stricmp(P6, "TRANS") == 0)
|
|
{
|
|
sockptr->FBBMode = TRUE;
|
|
sockptr->NeedLF = TRUE;
|
|
}
|
|
|
|
TCPConnect(TNC, TCP, STREAM, "127.0.0.1", TCP->CMDPort[Port], sockptr->FBBMode);
|
|
ReleaseBuffer(buffptr);
|
|
return;
|
|
}
|
|
|
|
if (_stricmp(Host, "RELAY") == 0)
|
|
{
|
|
if (P2[0] == 0)
|
|
{
|
|
strcpy(P2, TCP->RELAYHOST);
|
|
strcpy(P3, "8772");
|
|
}
|
|
|
|
if (P2[0])
|
|
{
|
|
STREAM->Connecting = TRUE;
|
|
STREAM->ConnectionInfo->CMSSession = TRUE;
|
|
STREAM->ConnectionInfo->RelaySession = TRUE;
|
|
TCPConnect(TNC, TCP, STREAM, P2, atoi(P3), TRUE);
|
|
ReleaseBuffer(buffptr);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (_stricmp(Host, "SYNC") == 0)
|
|
{
|
|
if (P2[0] == 0)
|
|
{
|
|
strcpy(P2, TCP->RELAYHOST);
|
|
strcpy(P3, "8780");
|
|
}
|
|
|
|
if (P2[0])
|
|
{
|
|
sockptr->CMSSession = FALSE;
|
|
STREAM->Connecting = TRUE;
|
|
STREAM->ConnectionInfo->SyncMode = TRUE;
|
|
TCPConnect(TNC, TCP, STREAM, P2, atoi(P3), TRUE);
|
|
ReleaseBuffer(buffptr);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
if (_stricmp(Host, "CMS") == 0)
|
|
{
|
|
if (TCP->CMS == 0 || !TCP->CMSOK)
|
|
{
|
|
if (TCP->RELAYHOST[0] && TCP->FallbacktoRelay && STREAM->NoCMSFallback == 0)
|
|
{
|
|
STREAM->Connecting = TRUE;
|
|
STREAM->ConnectionInfo->CMSSession = TRUE;
|
|
STREAM->ConnectionInfo->RelaySession = TRUE;
|
|
TCPConnect(TNC, TCP, STREAM, TCP->RELAYHOST, 8772, TRUE);
|
|
ReleaseBuffer(buffptr);
|
|
return;
|
|
}
|
|
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "Error - CMS Not Available\r");
|
|
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
|
|
STREAM->NeedDisc = 10;
|
|
CheckCMS(TNC);
|
|
|
|
return;
|
|
}
|
|
|
|
STREAM->Connecting = TRUE;
|
|
STREAM->ConnectionInfo->CMSSession = TRUE;
|
|
STREAM->ConnectionInfo->RelaySession = FALSE;
|
|
CMSConnect(TNC, TCP, STREAM, Stream);
|
|
ReleaseBuffer(buffptr);
|
|
|
|
return;
|
|
}
|
|
|
|
// Outward Connect.
|
|
|
|
// Only Allow user specified host if Secure Session
|
|
|
|
if (TCP->SecureTelnet)
|
|
{
|
|
struct _TRANSPORTENTRY * Sess = TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number];
|
|
|
|
// if (Sess && Sess->L4CROSSLINK)
|
|
// Sess = Sess->L4CROSSLINK;
|
|
|
|
if (Sess && !Sess->Secure_Session)
|
|
{
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "Error - Telnet Outward Connect needs SYSOP Status\r");
|
|
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
|
|
STREAM->NeedDisc = 10;
|
|
return;
|
|
}
|
|
}
|
|
|
|
Port = atoi(P2);
|
|
|
|
if (Port)
|
|
{
|
|
int useFBBMode = TRUE;
|
|
|
|
STREAM->Connecting = TRUE;
|
|
STREAM->ConnectionInfo->CMSSession = FALSE;
|
|
STREAM->ConnectionInfo->RelaySession = FALSE;
|
|
|
|
if (_stricmp(P3, "TELNET") == 0)
|
|
{
|
|
// // FBB with CRLF
|
|
|
|
STREAM->ConnectionInfo->NeedLF = TRUE;
|
|
}
|
|
else if (_stricmp(P3, "REALTELNET") == 0)
|
|
{
|
|
// // Telnet Mode with CRLF
|
|
|
|
useFBBMode = FALSE;
|
|
STREAM->ConnectionInfo->NeedLF = TRUE;
|
|
}
|
|
else
|
|
STREAM->ConnectionInfo->NeedLF = FALSE;
|
|
|
|
|
|
STREAM->ConnectionInfo->FBBMode = TRUE;
|
|
|
|
if (_stricmp(P3, "NOCALL") == 0 || _stricmp(P4, "NOCALL") == 0 || _stricmp(P5, "NOCALL") == 0 || _stricmp(P6, "NOCALL") == 0)
|
|
{
|
|
STREAM->ConnectionInfo->NoCallsign = TRUE;
|
|
}
|
|
else
|
|
{
|
|
if (_stricmp(P3, "NEEDLF") == 0 || STREAM->ConnectionInfo->NeedLF)
|
|
{
|
|
// Send LF after each param
|
|
|
|
if (P6[0])
|
|
sprintf(STREAM->ConnectionInfo->Signon, "%s\r\n%s\r\n%s\r\n", P4, P5, P6);
|
|
else
|
|
if (P5[0])
|
|
sprintf(STREAM->ConnectionInfo->Signon, "%s\r\n%s\r\n", P4, P5);
|
|
else
|
|
if (P4[0])
|
|
sprintf(STREAM->ConnectionInfo->Signon, "%s\r\n", P4);
|
|
}
|
|
else
|
|
{
|
|
if (P5[0])
|
|
sprintf(STREAM->ConnectionInfo->Signon, "%s\r%s\r%s\r", P3, P4, P5);
|
|
else
|
|
if (P4[0])
|
|
sprintf(STREAM->ConnectionInfo->Signon, "%s\r%s\r", P3, P4);
|
|
else
|
|
if (P3[0])
|
|
sprintf(STREAM->ConnectionInfo->Signon, "%s\r", P3);
|
|
}
|
|
}
|
|
|
|
TCPConnect(TNC, TCP, STREAM, Host, Port, useFBBMode);
|
|
ReleaseBuffer(buffptr);
|
|
return;
|
|
}
|
|
}
|
|
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "Error - Invalid Command\r");
|
|
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
|
|
STREAM->NeedDisc = 10;
|
|
return;
|
|
}
|
|
}
|
|
|
|
Msglen = sockptr->FromHostBuffPutptr - sockptr->FromHostBuffGetptr;
|
|
|
|
if (Msglen)
|
|
{
|
|
int Paclen = 0;
|
|
int Queued = 0;
|
|
TRANSPORTENTRY * Sess1 = TNC->PortRecord->ATTACHEDSESSIONS[Stream];
|
|
TRANSPORTENTRY * Sess2 = NULL;
|
|
|
|
if (Sess1)
|
|
Sess2 = Sess1->L4CROSSLINK;
|
|
|
|
// Can't use TXCount - it is Semaphored=
|
|
|
|
Queued = C_Q_COUNT(&TNC->Streams[Stream].PACTORtoBPQ_Q);
|
|
Queued += C_Q_COUNT((UINT *)&TNC->PortRecord->PORTCONTROL.PORTRX_Q);
|
|
|
|
if (Sess2)
|
|
Queued += CountFramesQueuedOnSession(Sess2);
|
|
|
|
if (Sess1)
|
|
Queued += CountFramesQueuedOnSession(Sess1);
|
|
|
|
if (Queued > 15)
|
|
continue;
|
|
|
|
if (Sess1)
|
|
Paclen = Sess1->SESSPACLEN;
|
|
|
|
if (Paclen == 0)
|
|
Paclen = 256;
|
|
|
|
ShowConnections(TNC);
|
|
|
|
if (Msglen > Paclen)
|
|
Msglen = Paclen;
|
|
|
|
if (Sess1) Sess1->L4KILLTIMER = 0;
|
|
if (Sess2) Sess2->L4KILLTIMER = 0;
|
|
|
|
SendtoNode(TNC, Stream, &sockptr->FromHostBuffer[sockptr->FromHostBuffGetptr], Msglen);
|
|
sockptr->FromHostBuffGetptr += Msglen;
|
|
sockptr->LastSendTime = REALTIMETICKS;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef LINBPQ
|
|
|
|
LRESULT CALLBACK TelWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int wmId, wmEvent;
|
|
struct ConnectionInfo * sockptr;
|
|
SOCKET sock;
|
|
int i, n;
|
|
struct TNCINFO * TNC;
|
|
struct TCPINFO * TCP;
|
|
struct _EXTPORTDATA * PortRecord;
|
|
HWND SavehDlg, SaveCMS, SaveMonitor;
|
|
HMENU SaveMenu1, SaveMenu2, SaveMenu3;
|
|
MINMAXINFO * mmi;
|
|
|
|
LPMEASUREITEMSTRUCT lpmis; // pointer to item of data
|
|
LPDRAWITEMSTRUCT lpdis; // pointer to item drawing data
|
|
|
|
// struct ConnectionInfo * ConnectionInfo;
|
|
|
|
for (i=1; i <= MAXBPQPORTS; i++)
|
|
{
|
|
TNC = TNCInfo[i];
|
|
if (TNC == NULL)
|
|
continue;
|
|
|
|
if (TNC->hDlg == hWnd)
|
|
break;
|
|
}
|
|
|
|
if (TNC == NULL)
|
|
return DefMDIChildProc(hWnd, message, wParam, lParam);
|
|
|
|
switch (message)
|
|
{
|
|
// case WM_SIZING:
|
|
case WM_SIZE:
|
|
{
|
|
RECT rcClient;
|
|
int ClientHeight, ClientWidth;
|
|
|
|
GetClientRect(TNC->hDlg, &rcClient);
|
|
|
|
ClientHeight = rcClient.bottom;
|
|
ClientWidth = rcClient.right;
|
|
|
|
MoveWindow(TNC->hMonitor, 0,20 ,ClientWidth-4, ClientHeight-25, TRUE);
|
|
break;
|
|
}
|
|
|
|
case WM_GETMINMAXINFO:
|
|
|
|
mmi = (MINMAXINFO *)lParam;
|
|
mmi->ptMaxSize.x = 400;
|
|
mmi->ptMaxSize.y = 500;
|
|
mmi->ptMaxTrackSize.x = 400;
|
|
mmi->ptMaxTrackSize.y = 500;
|
|
break;
|
|
|
|
|
|
case WM_MDIACTIVATE:
|
|
{
|
|
// Set the system info menu when getting activated
|
|
|
|
if (lParam == (LPARAM) hWnd)
|
|
{
|
|
// Activate
|
|
|
|
RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
|
|
AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)hPopMenu, "Actions");
|
|
SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hBaseMenu, (LPARAM) hWndMenu);
|
|
|
|
}
|
|
else
|
|
{
|
|
// Deactivate
|
|
|
|
SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
|
|
}
|
|
|
|
// call DrawMenuBar after the menu items are set
|
|
DrawMenuBar(FrameWnd);
|
|
|
|
return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
|
|
|
|
}
|
|
|
|
case WM_SYSCOMMAND:
|
|
|
|
wmId = LOWORD(wParam);
|
|
wmEvent = HIWORD(wParam);
|
|
|
|
switch (wmId)
|
|
{
|
|
case SC_RESTORE:
|
|
|
|
TNC->Minimized = FALSE;
|
|
SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
|
|
return DefMDIChildProc(hWnd, message, wParam, lParam);
|
|
|
|
case SC_MINIMIZE:
|
|
|
|
TNC->Minimized = TRUE;
|
|
return DefMDIChildProc(hWnd, message, wParam, lParam);
|
|
}
|
|
|
|
return DefMDIChildProc(hWnd, message, wParam, lParam);
|
|
|
|
case WM_COMMAND:
|
|
wmId = LOWORD(wParam);
|
|
wmEvent = HIWORD(wParam);
|
|
// Parse the menu selections:
|
|
|
|
if (wmId > IDM_DISCONNECT && wmId < IDM_DISCONNECT+MaxSockets+1)
|
|
{
|
|
// disconnect user
|
|
|
|
sockptr = TNC->Streams[wmId-IDM_DISCONNECT].ConnectionInfo;
|
|
|
|
if (sockptr->SocketActive)
|
|
{
|
|
sock=sockptr->socket;
|
|
|
|
send(sock,disMsg, (int)strlen(disMsg),0);
|
|
|
|
Sleep (1000);
|
|
|
|
shutdown(sock,2);
|
|
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
|
|
TNC->Streams[wmId-IDM_DISCONNECT].ReportDISC = TRUE; //Tell Node
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
switch (wmId)
|
|
{
|
|
case CMSENABLED:
|
|
|
|
// Toggle CMS Enabled Flag
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
TCP->CMS = !TCP->CMS;
|
|
CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3);
|
|
|
|
if (TCP->CMS)
|
|
CheckCMS(TNC);
|
|
else
|
|
{
|
|
TCP->CMSOK = FALSE;
|
|
SetWindowText(TCP->hCMSWnd, "CMS Off");
|
|
}
|
|
break;
|
|
|
|
case IDM_LOGGING:
|
|
|
|
// Toggle Logging Flag
|
|
|
|
LogEnabled = !LogEnabled;
|
|
CheckMenuItem(TNC->TCPInfo->hLogMenu, 0, MF_BYPOSITION | LogEnabled<<3);
|
|
|
|
break;
|
|
|
|
case IDM_CMS_LOGGING:
|
|
|
|
// Toggle Logging Flag
|
|
|
|
LogEnabled = !LogEnabled;
|
|
CheckMenuItem(TNC->TCPInfo->hLogMenu, 1, MF_BYPOSITION | CMSLogEnabled<<3);
|
|
|
|
break;
|
|
|
|
case TELNET_RECONFIG:
|
|
|
|
if (!ProcessConfig())
|
|
{
|
|
Consoleprintf("Failed to reread config file - leaving config unchanged");
|
|
break;
|
|
}
|
|
|
|
FreeConfig();
|
|
|
|
for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
sockptr->SocketActive = FALSE;
|
|
closesocket(sockptr->socket);
|
|
}
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
shutdown(TCP->TCPSock, SD_BOTH);
|
|
shutdown(TCP->sock6, SD_BOTH);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock[n])
|
|
shutdown(TCP->FBBsock[n++], SD_BOTH);
|
|
|
|
shutdown(TCP->Relaysock, SD_BOTH);
|
|
shutdown(TCP->HTTPsock, SD_BOTH);
|
|
shutdown(TCP->HTTPsock6, SD_BOTH);
|
|
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock6[n])
|
|
shutdown(TCP->FBBsock[n++], SD_BOTH);
|
|
|
|
shutdown(TCP->Relaysock6, SD_BOTH);
|
|
|
|
Sleep(500);
|
|
|
|
closesocket(TCP->TCPSock);
|
|
closesocket(TCP->sock6);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock[n])
|
|
closesocket(TCP->FBBsock[n++]);
|
|
|
|
n = 0;
|
|
while (TCP->FBBsock6[n])
|
|
closesocket(TCP->FBBsock6[n++]);
|
|
|
|
closesocket(TCP->Relaysock);
|
|
closesocket(TCP->Relaysock6);
|
|
closesocket(TCP->HTTPsock);
|
|
closesocket(TCP->HTTPsock6);
|
|
|
|
// Save info from old TNC record
|
|
|
|
n = TNC->Port;
|
|
PortRecord = TNC->PortRecord;
|
|
SavehDlg = TNC->hDlg;
|
|
SaveCMS = TCP->hCMSWnd;
|
|
SaveMonitor = TNC->hMonitor;
|
|
SaveMenu1 = TCP->hActionMenu;
|
|
SaveMenu2 = TCP->hDisMenu;
|
|
SaveMenu3 = TCP->hLogMenu;
|
|
|
|
// Free old TCP Session Stucts
|
|
|
|
for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++)
|
|
{
|
|
free(TNC->Streams[i].ConnectionInfo);
|
|
}
|
|
|
|
ReadConfigFile(TNC->Port, ProcessLine);
|
|
|
|
TNC = TNCInfo[n];
|
|
TNC->Port = n;
|
|
TNC->Hardware = H_TELNET;
|
|
TNC->hDlg = SavehDlg;
|
|
TNC->RIG = &TNC->DummyRig; // Not using Rig control, so use Dummy
|
|
|
|
// Get Menu Handles
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
TCP->hCMSWnd = SaveCMS;
|
|
TNC->hMonitor = SaveMonitor;
|
|
TCP->hActionMenu = SaveMenu1;
|
|
TCP->hDisMenu = SaveMenu2;
|
|
TCP->hLogMenu = SaveMenu3;
|
|
|
|
CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TNC->TCPInfo->CMS<<3);
|
|
CheckMenuItem(TCP->hLogMenu, 0, MF_BYPOSITION | LogEnabled<<3);
|
|
CheckMenuItem(TCP->hLogMenu, 1, MF_BYPOSITION | CMSLogEnabled<<3);
|
|
|
|
// Malloc TCP Session Stucts
|
|
|
|
for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++)
|
|
{
|
|
TNC->Streams[i].ConnectionInfo = zalloc(sizeof(struct ConnectionInfo));
|
|
TNC->Streams[i].ConnectionInfo->Number = i;
|
|
|
|
TCP->CurrentSockets = i; //Record max used to save searching all entries
|
|
|
|
if (i > 0)
|
|
ModifyMenu(TCP->hDisMenu,i - 1 ,MF_BYPOSITION | MF_STRING,IDM_DISCONNECT + 1, ".");
|
|
}
|
|
|
|
TNC->PortRecord = PortRecord;
|
|
|
|
Sleep(500);
|
|
OpenSockets(TNC);
|
|
OpenSockets6(TNC);
|
|
SetupListenSet(TNC);
|
|
CheckCMS(TNC);
|
|
ShowConnections(TNC);
|
|
|
|
break;
|
|
default:
|
|
return DefMDIChildProc(hWnd, message, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
// case WM_SIZE:
|
|
|
|
// if (wParam == SIZE_MINIMIZED)
|
|
// return (0);
|
|
|
|
case WM_CTLCOLORDLG:
|
|
|
|
return (LONG)bgBrush;
|
|
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
{
|
|
HDC hdcStatic = (HDC)wParam;
|
|
|
|
if (TNC->TCPInfo->hCMSWnd == (HWND)lParam)
|
|
{
|
|
if (TNC->TCPInfo->CMSOK)
|
|
SetTextColor(hdcStatic, RGB(0, 128, 0));
|
|
else
|
|
SetTextColor(hdcStatic, RGB(255, 0, 0));
|
|
}
|
|
|
|
SetBkMode(hdcStatic, TRANSPARENT);
|
|
return (LONG)bgBrush;
|
|
}
|
|
case WM_MEASUREITEM:
|
|
|
|
// Retrieve pointers to the menu item's
|
|
// MEASUREITEMSTRUCT structure and MYITEM structure.
|
|
|
|
lpmis = (LPMEASUREITEMSTRUCT) lParam;
|
|
lpmis->itemWidth = 300;
|
|
|
|
return TRUE;
|
|
|
|
case WM_DRAWITEM:
|
|
|
|
// Get pointers to the menu item's DRAWITEMSTRUCT
|
|
// structure and MYITEM structure.
|
|
|
|
lpdis = (LPDRAWITEMSTRUCT) lParam;
|
|
|
|
// If the user has selected the item, use the selected
|
|
// text and background colors to display the item.
|
|
|
|
SetTextColor(lpdis->hDC, RGB(0, 128, 0));
|
|
|
|
if (TNC->TCPInfo->CMS)
|
|
{
|
|
if (TNC->TCPInfo->CMSOK)
|
|
TextOut(lpdis->hDC, 340, lpdis->rcItem.top + 2, "CMS OK", 6);
|
|
else
|
|
{
|
|
SetTextColor(lpdis->hDC, RGB(255, 0, 0));
|
|
TextOut(lpdis->hDC, 340, lpdis->rcItem.top + 2, "NO CMS", 6);
|
|
}
|
|
}
|
|
else
|
|
TextOut(lpdis->hDC, 340, lpdis->rcItem.top + 2, " ", 13);
|
|
|
|
return TRUE;
|
|
|
|
case WM_DESTROY:
|
|
|
|
break;
|
|
}
|
|
|
|
return DefMDIChildProc(hWnd, message, wParam, lParam);
|
|
|
|
}
|
|
#endif
|
|
|
|
int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port)
|
|
{
|
|
int n, addrlen = sizeof(struct sockaddr_in6);
|
|
struct sockaddr_in6 sin6;
|
|
|
|
struct ConnectionInfo * sockptr;
|
|
SOCKET sock;
|
|
char Negotiate[6]={IAC,WILL,suppressgoahead,IAC,WILL,echo};
|
|
// char Negotiate[3]={IAC,WILL,echo};
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
HMENU hDisMenu = TCP->hDisMenu;
|
|
u_long param=1;
|
|
|
|
// if for TriModeData Session, use the TriMode Control connection entry
|
|
|
|
if (SocketId == TCP->TriModeDataSock)
|
|
{
|
|
sockptr = TNC->TCPInfo->TriModeControlSession;
|
|
sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen);
|
|
sockptr->TriModeDataSock = sock;
|
|
ioctl(sock, FIONBIO, ¶m);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Find a free Session
|
|
|
|
for (n = 1; n <= TCP->MaxSessions; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
|
|
if (sockptr->SocketActive == FALSE)
|
|
{
|
|
sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen);
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
Debugprintf("BPQ32 Telnet accept() failed Error %d", WSAGetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
// Log, including port
|
|
|
|
if (LogEnabled)
|
|
{
|
|
char Addr[256];
|
|
char logmsg[512];
|
|
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
|
|
sprintf(logmsg,"%d %s Incoming Connect on Port %d\n", sockptr->Number, Addr, Port);
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
|
|
|
|
// Debugprintf("BPQ32 Telnet accept() Sock %d", sock);
|
|
|
|
ioctl(sock, FIONBIO, ¶m);
|
|
|
|
sockptr->socket = sock;
|
|
sockptr->SocketActive = TRUE;
|
|
sockptr->InputLen = 0;
|
|
sockptr->Number = n;
|
|
sockptr->LoginState = 0;
|
|
sockptr->UserPointer = 0;
|
|
sockptr->DoEcho = FALSE;
|
|
sockptr->BPQTermMode = FALSE;
|
|
sockptr->ConnectTime = time(NULL);
|
|
sockptr->Keepalive = FALSE;
|
|
sockptr->UTF8 = 0;
|
|
|
|
TNC->Streams[n].bytesRXed = TNC->Streams[n].bytesTXed = 0;
|
|
TNC->Streams[n].FramesQueued = 0;
|
|
|
|
sockptr->HTTPMode = FALSE;
|
|
sockptr->APIMode = FALSE;
|
|
sockptr->SyncMode = FALSE;
|
|
sockptr->DRATSMode = FALSE;
|
|
sockptr->FBBMode = FALSE;
|
|
sockptr->RelayMode = FALSE;
|
|
sockptr->ClientSession = FALSE;
|
|
sockptr->NeedLF = FALSE;
|
|
sockptr->TNC = TNC;
|
|
sockptr->WebSocks = 0;
|
|
|
|
if (sockptr->ADIF == NULL)
|
|
sockptr->ADIF = malloc(sizeof(struct ADIF));
|
|
|
|
memset(sockptr->ADIF, 0, sizeof(struct ADIF));
|
|
|
|
if (SocketId == TCP->HTTPsock || SocketId == TCP->HTTPsock6)
|
|
sockptr->HTTPMode = TRUE;
|
|
|
|
if (SocketId == TCP->APIsock || SocketId == TCP->APIsock6)
|
|
{
|
|
sockptr->HTTPMode = TRUE; // API is a type of HTTP socket
|
|
sockptr->APIMode = TRUE;
|
|
}
|
|
else if (SocketId == TCP->Syncsock || SocketId == TCP->Syncsock6)
|
|
sockptr->SyncMode = TRUE;
|
|
else if (SocketId == TCP->DRATSsock || SocketId == TCP->DRATSsock6)
|
|
sockptr->DRATSMode = TRUE;
|
|
|
|
else if (SocketId == TCP->Relaysock || SocketId == TCP->Relaysock6)
|
|
{
|
|
sockptr->RelayMode = TRUE;
|
|
sockptr->FBBMode = TRUE;
|
|
}
|
|
else if (SocketId == TCP->TriModeSock)
|
|
{
|
|
sockptr->TriMode = TRUE;
|
|
sockptr->FBBMode = TRUE;
|
|
TNC->TCPInfo->TriModeControlSession = sockptr;
|
|
sockptr->TriModeConnected = FALSE;
|
|
sockptr->TriModeDataSock = 0;
|
|
}
|
|
else if (SocketId != TCP->TCPSock && SocketId != TCP->sock6) // We can have several listening FBB mode sockets
|
|
sockptr->FBBMode = TRUE;
|
|
#ifndef LINBPQ
|
|
ModifyMenu(hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, ".");
|
|
DrawMenuBar(TNC->hDlg);
|
|
#endif
|
|
ShowConnections(TNC);
|
|
|
|
if (sockptr->HTTPMode)
|
|
return 0;
|
|
|
|
if (sockptr->DRATSMode)
|
|
{
|
|
send(sock, "100 Authentication not required\n", 33, 0);
|
|
sockptr->LoginState = 2;
|
|
return 0;
|
|
}
|
|
|
|
if (sockptr->SyncMode)
|
|
{
|
|
char MyCall[16] = "";
|
|
char Hello[32];
|
|
int Len;
|
|
memcpy(MyCall, MYNODECALL, 10);
|
|
strlop(MyCall, ' ');
|
|
strlop(MyCall, '-');
|
|
|
|
Len = sprintf(Hello, "POSYNCHELLO %s\r", MyCall);
|
|
|
|
send(sock, Hello, Len, 0);
|
|
return 0;
|
|
}
|
|
else
|
|
if (sockptr->RelayMode)
|
|
{
|
|
send(sock,"\r\rCallsign :\r", 13,0);
|
|
}
|
|
else
|
|
if (sockptr->TriMode)
|
|
{
|
|
// Trimode emulator Control Connection.
|
|
|
|
sockptr->UserPointer = &TriModeUser;
|
|
|
|
|
|
send(sock,"CMD\r\n", 5,0);
|
|
sockptr->LoginState = 5;
|
|
}
|
|
else
|
|
if (sockptr->FBBMode == FALSE)
|
|
{
|
|
send(sock, Negotiate, 6, 0);
|
|
send(sock, TCP->LoginMsg, (int)strlen(TCP->LoginMsg), 0);
|
|
}
|
|
|
|
if (sockptr->FromHostBuffer == 0)
|
|
{
|
|
sockptr->FromHostBuffer = malloc(10000);
|
|
sockptr->FromHostBufferSize = 10000;
|
|
}
|
|
|
|
sockptr->FromHostBuffPutptr = sockptr->FromHostBuffGetptr = 0;
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// No free sessions. Must accept() then close
|
|
|
|
sock = accept(SocketId, (struct sockaddr *)&sin6, &addrlen);
|
|
|
|
send(sock,"No Free Sessions\r\n", 18,0);
|
|
Debugprintf("No Free Telnet Sessions");
|
|
|
|
Sleep (1000);
|
|
closesocket(sock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
int Socket_Data(struct TNCINFO * TNC, int sock, int error, int eventcode)
|
|
{
|
|
int n;
|
|
struct ConnectionInfo * sockptr;
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
HMENU hDisMenu = TCP->hDisMenu;
|
|
|
|
// Find Connection Record
|
|
|
|
for (n = 0; n <= TCP->CurrentSockets; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
|
|
if (sockptr->socket == sock && sockptr->SocketActive)
|
|
{
|
|
#ifndef LINBPQ
|
|
switch (eventcode)
|
|
{
|
|
case FD_READ:
|
|
|
|
if (sockptr->RelayMode)
|
|
return DataSocket_ReadRelay(TNC, sockptr, sock, &TNC->Streams[n]);
|
|
|
|
if (sockptr->HTTPMode)
|
|
return DataSocket_ReadHTTP(TNC, sockptr, sock, n);
|
|
|
|
if (sockptr->FBBMode)
|
|
return DataSocket_ReadFBB(TNC, sockptr, sock, n);
|
|
else
|
|
return DataSocket_Read(TNC, sockptr, sock, &TNC->Streams[n]);
|
|
|
|
case FD_WRITE:
|
|
|
|
return 0;
|
|
|
|
case FD_OOB:
|
|
|
|
return 0;
|
|
|
|
case FD_ACCEPT:
|
|
|
|
return 0;
|
|
|
|
case FD_CONNECT:
|
|
|
|
return 0;
|
|
|
|
case FD_CLOSE:
|
|
|
|
TNC->Streams[n].ReportDISC = TRUE; //Tell Node
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return 0;
|
|
}
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
*/
|
|
#define PACLEN 100
|
|
|
|
VOID SendtoNode(struct TNCINFO * TNC, int Stream, char * Msg, int MsgLen)
|
|
{
|
|
PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
|
|
|
|
if (buffptr == NULL)
|
|
return; // No buffers, so ignore
|
|
|
|
if (TNC->Streams[Stream].Connected == 0)
|
|
{
|
|
// Connection Closed - Get Another
|
|
|
|
struct ConnectionInfo * sockptr = TNC->Streams[Stream].ConnectionInfo;
|
|
|
|
if (ProcessIncommingConnect(TNC, sockptr->Callsign, sockptr->Number, FALSE) == FALSE)
|
|
{
|
|
DataSocket_Disconnect(TNC, sockptr); //' Tidy up
|
|
return;
|
|
}
|
|
|
|
if (sockptr->UserPointer)
|
|
TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->Secure_Session = sockptr->UserPointer->Secure;
|
|
}
|
|
|
|
buffptr->Len= MsgLen; // Length
|
|
|
|
memcpy(&buffptr->Data, Msg, MsgLen);
|
|
|
|
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
|
|
}
|
|
|
|
int InnerProcessData(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM, int len);
|
|
|
|
|
|
int DataSocket_Read(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM)
|
|
{
|
|
int len=0, maxlen;
|
|
char NLMsg[3]={13,10,0};
|
|
byte * IACptr;
|
|
BOOL wait;
|
|
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
int SendIndex = 0;
|
|
byte * TelCommand;
|
|
int beforeIAC = 0;
|
|
int rest = 0;
|
|
|
|
ioctl(sock,FIONREAD,&len);
|
|
|
|
maxlen = InputBufferLen - sockptr->InputLen;
|
|
|
|
if (len > maxlen) len=maxlen;
|
|
|
|
len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0);
|
|
|
|
if (len == SOCKET_ERROR || len ==0)
|
|
{
|
|
// Failed or closed - clear connection
|
|
|
|
TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return 0;
|
|
}
|
|
|
|
// If message contains Telnet Commands we should process the data in the buffer first
|
|
// and not echo the commands!
|
|
|
|
|
|
IACptr = memchr(sockptr->InputBuffer, IAC, sockptr->InputLen + len);
|
|
|
|
if (IACptr)
|
|
{
|
|
beforeIAC = IACptr - sockptr->InputBuffer;
|
|
rest = (sockptr->InputLen + len) - beforeIAC;
|
|
|
|
if (beforeIAC)
|
|
{
|
|
TelCommand = malloc(rest);
|
|
memcpy(TelCommand, IACptr, rest);
|
|
InnerProcessData(TNC, sockptr, sock, STREAM, beforeIAC);
|
|
|
|
// There may still be data in buffer, but it may be less than before
|
|
// Put IAC and following into buffer
|
|
|
|
memcpy(&sockptr->InputBuffer[sockptr->InputLen], TelCommand, rest);
|
|
len -= sockptr->InputLen;
|
|
free(TelCommand);
|
|
}
|
|
}
|
|
|
|
IACLoop:
|
|
|
|
IACptr = memchr(sockptr->InputBuffer, IAC, sockptr->InputLen + len);
|
|
|
|
if (IACptr)
|
|
{
|
|
// There still may be data in the buffer.
|
|
|
|
wait = ProcessTelnetCommand(sockptr, IACptr, &rest);
|
|
|
|
if (wait)
|
|
{
|
|
// Need more.
|
|
|
|
sockptr->InputLen += len;
|
|
return 0; // wait for more chars
|
|
}
|
|
|
|
// If ProcessTelnet Command returns FALSE, then it has removed the IAC and its
|
|
// params from the buffer. There may still be more to process.
|
|
|
|
if (rest == 0)
|
|
return 0; // Nothing Left
|
|
|
|
memmove(&sockptr->InputBuffer[sockptr->InputLen], IACptr + len - rest, rest);
|
|
len = rest;
|
|
|
|
goto IACLoop; // There may be more
|
|
}
|
|
|
|
return InnerProcessData(TNC, sockptr, sock, STREAM, len);
|
|
}
|
|
|
|
|
|
int InnerProcessData(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM, int len)
|
|
{
|
|
int InputLen, MsgLen, i, n,charsAfter;
|
|
char NLMsg[3]={13,10,0};
|
|
byte * CRPtr;
|
|
byte * LFPtr;
|
|
byte * BSptr;
|
|
byte * MsgPtr;
|
|
char logmsg[1000];
|
|
struct UserRec * USER;
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
int SendIndex = 0;
|
|
|
|
// echo data just read
|
|
|
|
if (sockptr->DoEcho && sockptr->LoginState != 1) // Password
|
|
send(sockptr->socket,&sockptr->InputBuffer[sockptr->InputLen], len, 0);
|
|
|
|
sockptr->InputLen += len;
|
|
|
|
// look for backspaces in data just read
|
|
|
|
BSptr = memchr(&sockptr->InputBuffer[0], 8, sockptr->InputLen);
|
|
|
|
if (BSptr == NULL)
|
|
BSptr = memchr(&sockptr->InputBuffer[0], 127, sockptr->InputLen);
|
|
|
|
if (BSptr != 0)
|
|
{
|
|
// single char or BS as last is most likely, and worth treating as a special case
|
|
|
|
int n;
|
|
|
|
charsAfter = sockptr->InputLen - (int)((BSptr-&sockptr->InputBuffer[0])) - 1;
|
|
|
|
if (charsAfter == 0)
|
|
{
|
|
sockptr->InputLen--;
|
|
if (sockptr->InputLen > 0)
|
|
sockptr->InputLen--; //Remove last char
|
|
|
|
goto noBS;
|
|
}
|
|
// more than single char. Copy stuff after bs over char before
|
|
|
|
memmove(BSptr-1, BSptr+1, charsAfter);
|
|
|
|
n = sockptr->InputLen;
|
|
|
|
sockptr->InputLen -= 2; // drop bs and char before
|
|
|
|
// see if more bs chars
|
|
BSCheck:
|
|
BSptr = memchr(&sockptr->InputBuffer[0], 8, sockptr->InputLen);
|
|
|
|
if (BSptr == NULL)
|
|
BSptr = memchr(&sockptr->InputBuffer[0], 127, sockptr->InputLen);
|
|
|
|
if (BSptr == NULL)
|
|
goto noBS;
|
|
|
|
charsAfter = sockptr->InputLen - (int)((BSptr-&sockptr->InputBuffer[0])) - 1;
|
|
|
|
if (charsAfter == 0)
|
|
{
|
|
sockptr->InputLen--; // Remove BS
|
|
if (sockptr->InputLen > 0)
|
|
sockptr->InputLen--; //Remove last char if not at start
|
|
goto noBS;
|
|
}
|
|
|
|
memmove(BSptr-1, BSptr+1, charsAfter);
|
|
sockptr->InputLen--; // Remove BS
|
|
if (sockptr->InputLen > 0) sockptr->InputLen--; //Remove last char if not at start
|
|
|
|
goto BSCheck; // may be more bs chars
|
|
}
|
|
|
|
noBS:
|
|
|
|
// Extract lines from input stream
|
|
|
|
MsgPtr = &sockptr->InputBuffer[0];
|
|
InputLen = sockptr->InputLen;
|
|
|
|
MsgLoop:
|
|
|
|
// if in Client Mode, accept CR, CR Null, CR LF or LF, and replace with CR
|
|
// Also send immediately to client - dont wait for complete lines
|
|
|
|
if (sockptr->ClientSession)
|
|
{
|
|
int n = InputLen;
|
|
char * ptr = MsgPtr;
|
|
char * Start = MsgPtr;
|
|
char c;
|
|
int len = 0;
|
|
char NodeLine[300];
|
|
char * optr = NodeLine;
|
|
|
|
while (n--)
|
|
{
|
|
c = *(ptr++);
|
|
|
|
if (c == 0)
|
|
// Ignore Nulls
|
|
continue;
|
|
|
|
len++;
|
|
*(optr++) = c;
|
|
|
|
if (c == 13)
|
|
{
|
|
// See if next is lf or null
|
|
|
|
if (n)
|
|
{
|
|
// Some Left
|
|
|
|
if ((*ptr) == 0 || *(ptr) == 10)
|
|
{
|
|
// skip next
|
|
|
|
n--;
|
|
ptr++;
|
|
}
|
|
}
|
|
}
|
|
else if (c == 10)
|
|
{
|
|
*(optr - 1) = 13;
|
|
}
|
|
else
|
|
{
|
|
// Normal Char
|
|
|
|
if (len >= PACLEN)
|
|
{
|
|
BuffertoNode(sockptr, NodeLine, len);
|
|
optr = NodeLine;
|
|
len = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// All scanned - send anything outstanding
|
|
|
|
if (len)
|
|
BuffertoNode(sockptr, NodeLine, len);
|
|
|
|
sockptr->InputLen = 0;
|
|
ShowConnections(TNC);;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Server Mode
|
|
|
|
CRPtr=memchr(MsgPtr, 13, InputLen);
|
|
|
|
if (CRPtr)
|
|
{
|
|
// Convert CR Null to CR LF
|
|
|
|
LFPtr=memchr(MsgPtr, 0, InputLen);
|
|
|
|
if (LFPtr && *(LFPtr - 1) == 13) // Convert CR NULL to CR LF
|
|
{
|
|
*LFPtr = 10; // Replace NULL with LF
|
|
send(sockptr->socket, LFPtr, 1, 0); // And echo it
|
|
}
|
|
}
|
|
|
|
// could just have LF??
|
|
|
|
LFPtr=memchr(MsgPtr, 10, InputLen);
|
|
|
|
if (LFPtr == 0)
|
|
if (CRPtr)
|
|
{
|
|
LFPtr = ++CRPtr;
|
|
InputLen++;
|
|
}
|
|
if (LFPtr == 0)
|
|
{
|
|
// Check Paclen
|
|
|
|
if (InputLen > PACLEN)
|
|
{
|
|
if (sockptr->LoginState != 2) // Normal Data
|
|
{
|
|
// Long message received when waiting for user or password - just ignore
|
|
|
|
sockptr->InputLen=0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Send to Node
|
|
|
|
// Line could be up to 500 chars if coming from a program rather than an interative user
|
|
// Limit send to node to 255
|
|
|
|
while (InputLen > 255)
|
|
{
|
|
SendtoNode(TNC, sockptr->Number, MsgPtr, 255);
|
|
sockptr->InputLen -= 255;
|
|
InputLen -= 255;
|
|
|
|
memmove(MsgPtr,MsgPtr+255,InputLen);
|
|
}
|
|
|
|
SendtoNode(TNC, sockptr->Number, MsgPtr, InputLen);
|
|
|
|
sockptr->InputLen = 0;
|
|
|
|
} // PACLEN
|
|
|
|
return 0; // No CR
|
|
}
|
|
|
|
// Got a LF
|
|
|
|
// Process data up to the cr
|
|
|
|
MsgLen = (int)(LFPtr-MsgPtr); // Include the CR but not LF
|
|
|
|
switch (sockptr->LoginState)
|
|
{
|
|
|
|
case 2:
|
|
|
|
// Normal Data State
|
|
|
|
STREAM->bytesRXed += MsgLen;
|
|
SendIndex = 0;
|
|
|
|
// Line could be up to 500 chars if coming from a program rather than an interative user
|
|
// Limit send to node to 255. Should really use PACLEN instead of 255....
|
|
|
|
while (MsgLen > 255)
|
|
{
|
|
SendtoNode(TNC, sockptr->Number, MsgPtr + SendIndex, 255);
|
|
SendIndex += 255;
|
|
MsgLen -= 255;
|
|
}
|
|
|
|
SendtoNode(TNC, sockptr->Number, MsgPtr + SendIndex, MsgLen);
|
|
|
|
MsgLen += SendIndex;
|
|
|
|
// If anything left, copy down buffer, and go back
|
|
|
|
InputLen=InputLen-MsgLen-1;
|
|
|
|
sockptr->InputLen=InputLen;
|
|
|
|
if (InputLen > 0)
|
|
{
|
|
memmove(MsgPtr,LFPtr+1,InputLen);
|
|
|
|
goto MsgLoop;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 0:
|
|
|
|
// Check Username
|
|
//
|
|
|
|
*(LFPtr-1)=0; // remove cr
|
|
|
|
// send(sock, NLMsg, 2, 0);
|
|
|
|
if (LogEnabled)
|
|
{
|
|
char Addr[256];
|
|
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
|
|
if (strlen(MsgPtr) > 64)
|
|
{
|
|
MsgPtr[64] = 0;
|
|
Debugprintf("Telnet Bad User Name %s", MsgPtr);
|
|
}
|
|
|
|
sprintf(logmsg,"%d %s User=%s\n", sockptr->Number, Addr, MsgPtr);
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
for (i = 0; i < TCP->NumberofUsers; i++)
|
|
{
|
|
USER = TCP->UserRecPtr[i];
|
|
|
|
if (USER == NULL)
|
|
continue;
|
|
|
|
if (_stricmp(USER->UserName, "ANON") == 0)
|
|
{
|
|
// Anon Login - Callsign is supplied as user
|
|
|
|
sockptr->UserPointer = USER; //' Save pointer for checking password
|
|
strcpy(sockptr->Callsign, _strupr(MsgPtr)); //' for *** linked
|
|
}
|
|
else if (strcmp(MsgPtr,USER->UserName) == 0)
|
|
{
|
|
sockptr->UserPointer = USER; //' Save pointer for checking password
|
|
strcpy(sockptr->Callsign, USER->Callsign); //' for *** linked
|
|
}
|
|
else
|
|
continue;
|
|
|
|
send(sock, TCP->PasswordMsg, (int)strlen(TCP->PasswordMsg),0);
|
|
|
|
sockptr->Retries = 0;
|
|
|
|
sockptr->LoginState = 1;
|
|
sockptr->InputLen = 0;
|
|
|
|
n=sockptr->Number;
|
|
#ifndef LINBPQ
|
|
ModifyMenu(TCP->hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, MsgPtr);
|
|
#endif
|
|
ShowConnections(TNC);;
|
|
return 0;
|
|
}
|
|
|
|
// Not found
|
|
|
|
|
|
if (sockptr->Retries++ == 4)
|
|
{
|
|
send(sock,AttemptsMsg,sizeof(AttemptsMsg),0);
|
|
Sleep (1000);
|
|
DataSocket_Disconnect(TNC, sockptr); //' Tidy up
|
|
}
|
|
else
|
|
{
|
|
send(sock, TCP->LoginMsg, (int)strlen(TCP->LoginMsg), 0);
|
|
sockptr->InputLen=0;
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 1:
|
|
|
|
*(LFPtr-1)=0; // remove cr
|
|
|
|
send(sock, NLMsg, 2, 0); // Need to echo NL, as password is not echoed
|
|
|
|
if (LogEnabled)
|
|
{
|
|
char Addr[256];
|
|
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
|
|
if (strlen(MsgPtr) > 64)
|
|
{
|
|
MsgPtr[64] = 0;
|
|
Debugprintf("Telnet Bad Password %s", MsgPtr);
|
|
}
|
|
|
|
|
|
sprintf(logmsg,"%d %s Password=%s\n", sockptr->Number, Addr, MsgPtr);
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
if (strcmp(MsgPtr, sockptr->UserPointer->Password) == 0) {
|
|
char * ct = TCP->cfgCTEXT;
|
|
char * Appl;
|
|
int ctlen = (int)strlen(ct);
|
|
|
|
if (ProcessIncommingConnect(TNC, sockptr->Callsign, sockptr->Number, FALSE) == FALSE)
|
|
{
|
|
DataSocket_Disconnect(TNC, sockptr); //' Tidy up
|
|
return 0;
|
|
}
|
|
|
|
TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->Secure_Session = sockptr->UserPointer->Secure;
|
|
|
|
sockptr->LoginState = 2;
|
|
sockptr->InputLen = 0;
|
|
|
|
if (ctlen > 0) send(sock, ct, ctlen, 0);
|
|
|
|
STREAM->bytesTXed = ctlen;
|
|
|
|
if (LogEnabled)
|
|
{
|
|
char Addr[100];
|
|
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
sprintf(logmsg,"%d %s Call Accepted Callsign=%s\n", sockptr->Number, Addr, sockptr->Callsign);
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
Appl = sockptr->UserPointer->Appl;
|
|
|
|
if (Appl[0])
|
|
SendtoNode(TNC, sockptr->Number, Appl, (int)strlen(Appl));
|
|
|
|
ShowConnections(TNC);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Bad Password
|
|
|
|
if (sockptr->Retries++ == 4)
|
|
{
|
|
send(sock,AttemptsMsg, (int)strlen(AttemptsMsg),0);
|
|
Sleep (1000);
|
|
DataSocket_Disconnect (TNC, sockptr); //' Tidy up
|
|
}
|
|
else
|
|
{
|
|
send(sock, TCP->PasswordMsg, (int)strlen(TCP->PasswordMsg), 0);
|
|
sockptr->InputLen=0;
|
|
}
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int DataSocket_ReadRelay(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM)
|
|
{
|
|
int len=0, maxlen, InputLen, MsgLen, n;
|
|
char NLMsg[3]={13,10,0};
|
|
byte * LFPtr;
|
|
byte * MsgPtr;
|
|
char logmsg[256];
|
|
char RelayMsg[] = "No CMS connection available - using local BPQMail\r";
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
|
|
ioctl(sock,FIONREAD,&len);
|
|
|
|
maxlen = InputBufferLen - sockptr->InputLen;
|
|
|
|
if (len > maxlen) len=maxlen;
|
|
|
|
len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0);
|
|
|
|
|
|
if (len == SOCKET_ERROR || len ==0)
|
|
{
|
|
// Failed or closed - clear connection
|
|
|
|
TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return 0;
|
|
}
|
|
|
|
sockptr->InputLen+=len;
|
|
|
|
// Extract lines from input stream
|
|
|
|
MsgPtr = &sockptr->InputBuffer[0];
|
|
InputLen = sockptr->InputLen;
|
|
|
|
STREAM->bytesRXed += InputLen;
|
|
|
|
if (sockptr->LoginState == 2)
|
|
{
|
|
// Data. FBB is binary
|
|
|
|
// Send to Node
|
|
|
|
// Queue to Node. Data may arrive it large quatities, possibly exceeding node buffer capacity
|
|
|
|
STREAM->bytesRXed += InputLen;
|
|
|
|
if (sockptr->FromHostBuffPutptr + InputLen > sockptr->FromHostBufferSize)
|
|
{
|
|
if (InputLen > 10000)
|
|
sockptr->FromHostBufferSize += InputLen;
|
|
else
|
|
sockptr->FromHostBufferSize += 10000;
|
|
|
|
sockptr->FromHostBuffer = realloc(sockptr->FromHostBuffer, sockptr->FromHostBufferSize);
|
|
}
|
|
|
|
memcpy(&sockptr->FromHostBuffer[sockptr->FromHostBuffPutptr], MsgPtr, InputLen);
|
|
|
|
sockptr->FromHostBuffPutptr += InputLen;
|
|
sockptr->InputLen = 0;
|
|
|
|
return 0;
|
|
}
|
|
/*
|
|
if (InputLen > 256)
|
|
{
|
|
SendtoNode(TNC, sockptr->Number, MsgPtr, 256);
|
|
sockptr->InputLen -= 256;
|
|
|
|
InputLen -= 256;
|
|
|
|
memmove(MsgPtr,MsgPtr+256,InputLen);
|
|
|
|
goto MsgLoop;
|
|
}
|
|
|
|
SendtoNode(TNC, sockptr->Number, MsgPtr, InputLen);
|
|
sockptr->InputLen = 0;
|
|
|
|
return 0;
|
|
}
|
|
*/
|
|
if (InputLen > 256)
|
|
{
|
|
// Long message received when waiting for user or password - just ignore
|
|
|
|
sockptr->InputLen=0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
LFPtr=memchr(MsgPtr, 13, InputLen);
|
|
|
|
if (LFPtr == 0)
|
|
return 0; // Waitr for more
|
|
|
|
// Got a CR
|
|
|
|
// Process data up to the cr
|
|
|
|
MsgLen = (int)(LFPtr-MsgPtr);
|
|
|
|
switch (sockptr->LoginState)
|
|
{
|
|
|
|
case 0:
|
|
|
|
// Check Username
|
|
//
|
|
|
|
*(LFPtr)=0; // remove cr
|
|
|
|
if (*MsgPtr == '.')
|
|
MsgPtr++;
|
|
|
|
if (strlen(MsgPtr) == 0)
|
|
{
|
|
DataSocket_Disconnect(TNC, sockptr); // Silently disconnect - should only be used for automatic systems
|
|
return 0;
|
|
}
|
|
|
|
if (LogEnabled)
|
|
{
|
|
unsigned char work[4];
|
|
memcpy(work, &sockptr->sin.sin_addr.s_addr, 4);
|
|
sprintf(logmsg,"%d %d.%d.%d.%d User=%s\n",
|
|
sockptr->Number,
|
|
work[0], work[1], work[2], work[3],
|
|
MsgPtr);
|
|
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
strcpy(sockptr->Callsign, _strupr(MsgPtr));
|
|
|
|
// Save callsign for *** linked
|
|
|
|
send(sock, "Password :\r", 11,0);
|
|
|
|
sockptr->Retries = 0;
|
|
sockptr->LoginState = 1;
|
|
sockptr->InputLen = 0;
|
|
|
|
n=sockptr->Number;
|
|
#ifndef LINBPQ
|
|
ModifyMenu(TCP->hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, MsgPtr);
|
|
#endif
|
|
ShowConnections(TNC);;
|
|
|
|
return 0;
|
|
|
|
|
|
case 1:
|
|
|
|
*(LFPtr)=0; // remove cr
|
|
|
|
if (strlen(MsgPtr) == 0)
|
|
{
|
|
DataSocket_Disconnect(TNC, sockptr); // Silently disconnect - should only be used for automatic systems
|
|
return 0;
|
|
}
|
|
|
|
if (LogEnabled)
|
|
{
|
|
unsigned char work[4];
|
|
memcpy(work, &sockptr->sin.sin_addr.s_addr, 4);
|
|
sprintf(logmsg,"%d %d.%d.%d.%d Password=%s\n",
|
|
sockptr->Number,
|
|
work[0], work[1], work[2], work[3],
|
|
MsgPtr);
|
|
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
if (strchr(MsgPtr, '$'))
|
|
{
|
|
// Special format Password for PAT Gateway Mode
|
|
|
|
char * Port = strlop(MsgPtr, '$');
|
|
char * Call;
|
|
int PortNo;
|
|
char ConMsg[80];
|
|
|
|
if (Port)
|
|
{
|
|
Call = strlop(Port, '$');
|
|
|
|
if (Call)
|
|
{
|
|
struct PORTCONTROL * PORT;
|
|
|
|
PortNo = atoi(Port);
|
|
PORT = GetPortTableEntryFromPortNum(PortNo);
|
|
|
|
if (PORT == NULL || PORT->PROTOCOL < 10)
|
|
sprintf(ConMsg, "C %s %s", Port, Call);
|
|
else
|
|
sprintf(ConMsg, "ATT %s %s", Port, Call);
|
|
|
|
}
|
|
|
|
if (ProcessIncommingConnect(TNC, sockptr->Callsign, sockptr->Number, FALSE) == 0)
|
|
{
|
|
DataSocket_Disconnect(TNC, sockptr); //' Tidy up
|
|
return 0;
|
|
}
|
|
|
|
sockptr->LoginState = 2;
|
|
|
|
sockptr->InputLen = 0;
|
|
|
|
if (LogEnabled)
|
|
{
|
|
unsigned char work[4];
|
|
memcpy(work, &sockptr->sin.sin_addr.s_addr, 4);
|
|
sprintf(logmsg,"%d %d.%d.%d.%d Gateway Connect Call=%s Command=%s\n",
|
|
sockptr->Number,
|
|
work[0], work[1], work[2], work[3],
|
|
sockptr->Callsign,ConMsg);
|
|
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
// Send Command to Node
|
|
|
|
strcat(ConMsg, "\r");
|
|
SendtoNode(TNC, sockptr->Number, ConMsg, (int)strlen(ConMsg));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
sockptr->UserPointer = &RelayUser;
|
|
|
|
if (ProcessIncommingConnectEx(TNC, sockptr->Callsign, sockptr->Number, FALSE, TRUE) == 0)
|
|
{
|
|
DataSocket_Disconnect(TNC, sockptr); //' Tidy up
|
|
return 0;
|
|
}
|
|
|
|
if (TCP->FallbacktoRelay)
|
|
send(sock, RelayMsg, (int)strlen(RelayMsg), 0);
|
|
|
|
sockptr->LoginState = 2;
|
|
|
|
sockptr->InputLen = 0;
|
|
|
|
if (LogEnabled)
|
|
{
|
|
unsigned char work[4];
|
|
memcpy(work, &sockptr->sin.sin_addr.s_addr, 4);
|
|
sprintf(logmsg,"%d %d.%d.%d.%d Call Accepted Callsign =%s\n",
|
|
sockptr->Number,
|
|
work[0], work[1], work[2], work[3],
|
|
sockptr->Callsign);
|
|
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
ShowConnections(TNC);
|
|
|
|
sockptr->InputLen = 0;
|
|
|
|
// Connect to the BBS
|
|
|
|
SendtoNode(TNC, sockptr->Number, TCP->RelayAPPL, (int)strlen(TCP->RelayAPPL));
|
|
|
|
ShowConnections(TNC);;
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#define ZEXPORT WINAPI
|
|
|
|
#include "zlib.h"
|
|
|
|
int DataSocket_ReadSync(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream)
|
|
{
|
|
int len=0, maxlen, InputLen;
|
|
byte * MsgPtr;
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
struct STREAMINFO * STREAM = &TNC->Streams[Stream];
|
|
TRANSPORTENTRY * Sess1 = TNC->PortRecord->ATTACHEDSESSIONS[Stream];
|
|
TRANSPORTENTRY * Sess2 = NULL;
|
|
|
|
ioctl(sock,FIONREAD,&len);
|
|
|
|
maxlen = InputBufferLen - sockptr->InputLen;
|
|
|
|
if (len > maxlen) len = maxlen;
|
|
|
|
len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0);
|
|
|
|
if (len == SOCKET_ERROR || len == 0)
|
|
{
|
|
// Failed or closed - clear connection
|
|
|
|
TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return 0;
|
|
}
|
|
|
|
sockptr->InputLen+=len;
|
|
MsgPtr = &sockptr->InputBuffer[0];
|
|
InputLen = sockptr->InputLen;
|
|
MsgPtr[InputLen] = 0;
|
|
|
|
STREAM->bytesRXed += InputLen;
|
|
|
|
if (sockptr->LoginState == 0) // Initial connection
|
|
{
|
|
// First Message should be POSYNCLOGON CALL
|
|
|
|
// Extract the callsign
|
|
|
|
char * call = strlop(MsgPtr, ' ');
|
|
|
|
if (call == NULL || strcmp(MsgPtr, "POSYNCLOGON") !=0)
|
|
{
|
|
DataSocket_Disconnect(TNC, sockptr); //' Tidy up
|
|
return 0;
|
|
}
|
|
|
|
strcpy(sockptr->Callsign, call);
|
|
|
|
call --;
|
|
*(call) = ' ';
|
|
|
|
sockptr->UserPointer = &SyncUser;
|
|
|
|
SendtoNode(TNC, sockptr->Number, TCP->SyncAPPL, (int)strlen(TCP->SyncAPPL));
|
|
BuffertoNode(sockptr, MsgPtr, InputLen);
|
|
STREAM->RelaySyncStream = 1;
|
|
sockptr->LoginState = 2;
|
|
|
|
ShowConnections(TNC);
|
|
return 0;
|
|
}
|
|
|
|
// Queue to Node. Data may arrive in large quantities, possibly exceeding node buffer capacity
|
|
|
|
BuffertoNode(sockptr, MsgPtr, InputLen);
|
|
sockptr->InputLen = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
int DataSocket_ReadFBB(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream)
|
|
{
|
|
int len=0, maxlen, InputLen, MsgLen, i, n;
|
|
char NLMsg[3]={13,10,0};
|
|
byte * CRPtr;
|
|
byte * MsgPtr;
|
|
char logmsg[1000];
|
|
struct UserRec * USER;
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
struct STREAMINFO * STREAM = &TNC->Streams[Stream];
|
|
TRANSPORTENTRY * Sess1 = TNC->PortRecord->ATTACHEDSESSIONS[Stream];
|
|
TRANSPORTENTRY * Sess2 = NULL;
|
|
|
|
ioctl(sock,FIONREAD,&len);
|
|
|
|
maxlen = InputBufferLen - sockptr->InputLen;
|
|
|
|
if (len > maxlen) len = maxlen;
|
|
|
|
len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0);
|
|
|
|
if (len == SOCKET_ERROR || len == 0)
|
|
{
|
|
// Failed or closed - clear connection
|
|
|
|
TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return 0;
|
|
}
|
|
|
|
sockptr->InputLen+=len;
|
|
|
|
// Extract lines from input stream
|
|
|
|
MsgPtr = &sockptr->InputBuffer[0];
|
|
InputLen = sockptr->InputLen;
|
|
MsgPtr[InputLen] = 0;
|
|
|
|
if (sockptr->LoginState == 0)
|
|
{
|
|
// Look for FLMSG Header
|
|
|
|
if (InputLen > 10 && memcmp(MsgPtr, "... start\n", 10) == 0)
|
|
{
|
|
MsgPtr[9] = 13; // Convert to CR
|
|
sockptr->LoginState = 2; // Set Logged in
|
|
|
|
SendtoNode(TNC, Stream, "..FLMSG\r", 8); // Dummy command to command handler
|
|
|
|
}
|
|
}
|
|
|
|
MsgLoop:
|
|
|
|
if (sockptr->LoginState == 2)
|
|
{
|
|
// Data. FBB is binary
|
|
|
|
int Paclen = 0;
|
|
|
|
if (TNC->PortRecord->ATTACHEDSESSIONS[Stream])
|
|
Paclen = TNC->PortRecord->ATTACHEDSESSIONS[Stream]->SESSPACLEN;
|
|
|
|
// if (Paclen == 0)
|
|
Paclen = 256;
|
|
|
|
if (sockptr->BPQTermMode)
|
|
{
|
|
if (memcmp(MsgPtr, "\\\\\\\\", 4) == 0)
|
|
{
|
|
// Monitor Control
|
|
|
|
int P8 = 0;
|
|
|
|
int n = sscanf(&MsgPtr[4], "%llx %x %x %x %x %x %x %x",
|
|
&sockptr->MMASK, &sockptr->MTX, &sockptr->MCOM, &sockptr->MonitorNODES,
|
|
&sockptr->MonitorColour, &sockptr->MUIOnly, &sockptr->UTF8, &P8);
|
|
|
|
if (n == 5)
|
|
sockptr->MUIOnly = sockptr->UTF8 = 0;
|
|
|
|
if (n == 6)
|
|
sockptr->UTF8 = 0;
|
|
|
|
if (P8 == 1)
|
|
SendPortsForMonitor(sock, sockptr->UserPointer->Secure);
|
|
sockptr->InputLen = 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (sockptr->UserPointer == &CMSUser)
|
|
{
|
|
WritetoTrace(Stream, MsgPtr, InputLen, sockptr->ADIF, 'R');
|
|
}
|
|
|
|
if (InputLen == 8 && memcmp(MsgPtr, ";;;;;;\r\n", 8) == 0)
|
|
{
|
|
// CMS Keepalive
|
|
|
|
sockptr->InputLen = 0;
|
|
return 0;
|
|
}
|
|
|
|
// Queue to Node. Data may arrive it large quantities, possibly exceeding node buffer capacity
|
|
|
|
STREAM->bytesRXed += InputLen;
|
|
BuffertoNode(sockptr, MsgPtr, InputLen);
|
|
sockptr->InputLen = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (InputLen > 256)
|
|
{
|
|
// Long message received when waiting for user or password - just ignore
|
|
|
|
sockptr->InputLen=0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (MsgPtr[0] == 10) // LF
|
|
{
|
|
// Remove the LF
|
|
|
|
InputLen--;
|
|
sockptr->InputLen--;
|
|
|
|
memmove(MsgPtr, MsgPtr+1, InputLen);
|
|
}
|
|
|
|
CRPtr = memchr(MsgPtr, 13, InputLen);
|
|
|
|
if (CRPtr == 0)
|
|
return 0; // Waitr for more
|
|
|
|
// Got a CR
|
|
|
|
// Process data up to the cr
|
|
|
|
MsgLen = (int)(CRPtr - MsgPtr);
|
|
|
|
if (MsgLen == 0) // Just CR
|
|
{
|
|
MsgPtr++; // Skip it
|
|
InputLen--;
|
|
sockptr->InputLen--;
|
|
goto MsgLoop;
|
|
}
|
|
|
|
|
|
switch (sockptr->LoginState)
|
|
{
|
|
case 5:
|
|
|
|
// Trimode Emulator Command
|
|
|
|
*CRPtr = 0;
|
|
|
|
ProcessTrimodeCommand(TNC, sockptr, MsgPtr);
|
|
|
|
MsgLen++;
|
|
|
|
InputLen -= MsgLen;
|
|
|
|
memmove(MsgPtr, MsgPtr+MsgLen, InputLen);
|
|
sockptr->InputLen = InputLen ;
|
|
MsgPtr[InputLen] = 0;
|
|
|
|
|
|
goto MsgLoop;
|
|
|
|
case 3:
|
|
|
|
// CMS Signon
|
|
|
|
strlop(MsgPtr, 13);
|
|
|
|
sprintf(logmsg,"%d %s\r\n", Stream, MsgPtr);
|
|
WriteCMSLog (logmsg);
|
|
|
|
if (strstr(MsgPtr, "Callsign :"))
|
|
{
|
|
char Msg[80];
|
|
int Len;
|
|
|
|
if (sockptr->LogonSent)
|
|
{
|
|
sockptr->InputLen=0;
|
|
return TRUE;
|
|
}
|
|
|
|
sockptr->LogonSent = TRUE;
|
|
|
|
if (TCP->SecureCMSPassword[0] && sockptr->RelaySession == 0)
|
|
Len = sprintf(Msg, "%s %s\r", TNC->Streams[sockptr->Number].MyCall, TCP->GatewayCall);
|
|
else
|
|
Len = sprintf(Msg, "%s\r", TNC->Streams[sockptr->Number].MyCall);
|
|
|
|
if (sockptr->ADIF == NULL)
|
|
{
|
|
sockptr->ADIF = malloc(sizeof(struct ADIF));
|
|
memset(sockptr->ADIF, 0, sizeof(struct ADIF));
|
|
}
|
|
|
|
strcpy(sockptr->ADIF->CMSCall, TCP->GatewayCall);
|
|
|
|
send(sock, Msg, Len, 0);
|
|
sprintf(logmsg,"%d %s\n", Stream, Msg);
|
|
WriteCMSLog (logmsg);
|
|
|
|
sockptr->InputLen=0;
|
|
|
|
return TRUE;
|
|
}
|
|
if (memcmp(MsgPtr, ";SQ: ", 5) == 0)
|
|
{
|
|
// Secure CMS challenge
|
|
|
|
char Msg[80];
|
|
int Len;
|
|
int Response = GetCMSHash(&MsgPtr[5], TCP->SecureCMSPassword);
|
|
char RespString[12];
|
|
long long Freq = 0;
|
|
int Mode = 0;
|
|
ADIF * ADIF = sockptr->ADIF;
|
|
|
|
strcat(MsgPtr,"<cr>");
|
|
UpdateADIFRecord(ADIF, MsgPtr, 'R');
|
|
|
|
if (Sess1)
|
|
{
|
|
Sess2 = Sess1->L4CROSSLINK;
|
|
|
|
if (Sess2)
|
|
{
|
|
// if Session has report info, use it
|
|
|
|
if (Sess2->Mode)
|
|
{
|
|
ADIF->Freq = Freq = Sess2->Frequency;
|
|
ADIF->Mode = Mode = Sess2->Mode;
|
|
}
|
|
else
|
|
{
|
|
// See if L2 session - if so, get info from WL2K report line
|
|
|
|
if (Sess2->L4CIRCUITTYPE & L2LINK)
|
|
{
|
|
LINKTABLE * LINK = Sess2->L4TARGET.LINK;
|
|
PORTCONTROLX * PORT = LINK->LINKPORT;
|
|
|
|
ADIF->Freq = Freq = PORT->WL2KInfo.Freq;
|
|
ADIF->Mode = Mode = PORT->WL2KInfo.mode;
|
|
}
|
|
else
|
|
{
|
|
if (Sess2->RMSCall[0])
|
|
{
|
|
ADIF->Freq = Freq = Sess2->Frequency;
|
|
ADIF->Mode = Mode = Sess2->Mode;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
sprintf(RespString, "%010d", Response);
|
|
|
|
Len = sprintf(Msg, ";SR: %s %lld %d\r", &RespString[2], Freq, Mode);
|
|
|
|
send(sock, Msg, Len,0);
|
|
sprintf(logmsg,"%d %s\n", Stream, Msg);
|
|
WriteCMSLog (logmsg);
|
|
|
|
strcat(Msg,"<cr>");
|
|
UpdateADIFRecord(ADIF, Msg, 'S');
|
|
|
|
sockptr->InputLen=0;
|
|
sockptr->LoginState = 2; // Data
|
|
sockptr->LogonSent = FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
if (strstr(MsgPtr, "Password :"))
|
|
{
|
|
// Send "CMSTelnet" + gateway callsign + frequency + emission type if info is available
|
|
|
|
TRANSPORTENTRY * Sess1 = TNC->PortRecord->ATTACHEDSESSIONS[Stream];
|
|
TRANSPORTENTRY * Sess2 = NULL;
|
|
char Passline[80] = "CMSTELNET\r";
|
|
int len = 10;
|
|
ADIF * ADIF = sockptr->ADIF;
|
|
|
|
|
|
if (Sess1)
|
|
{
|
|
Sess2 = Sess1->L4CROSSLINK;
|
|
|
|
if (Sess2)
|
|
{
|
|
// if Session has report info, use it
|
|
|
|
if (Sess2->Mode)
|
|
{
|
|
ADIF->Freq = Sess2->Frequency;
|
|
ADIF->Mode = Sess2->Mode;
|
|
}
|
|
else
|
|
{
|
|
// See if L2 session - if so, get info from WL2K report line
|
|
|
|
if (Sess2->L4CIRCUITTYPE & L2LINK)
|
|
{
|
|
LINKTABLE * LINK = Sess2->L4TARGET.LINK;
|
|
PORTCONTROLX * PORT = LINK->LINKPORT;
|
|
|
|
if (PORT->WL2KInfo.Freq)
|
|
{
|
|
len = sprintf(Passline, "CMSTELNET %s %lld %d\r", PORT->WL2KInfo.RMSCall, PORT->WL2KInfo.Freq, PORT->WL2KInfo.mode);
|
|
ADIF->Freq = PORT->WL2KInfo.Freq;
|
|
ADIF->Mode = PORT->WL2KInfo.mode;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Sess2->RMSCall[0])
|
|
{
|
|
len = sprintf(Passline, "CMSTELNET %s %lld %d\r", Sess2->RMSCall, Sess2->Frequency, Sess2->Mode);
|
|
ADIF->Mode = Sess2->Frequency;
|
|
ADIF->Mode = Sess2->Mode;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
send(sock, Passline, len, 0);
|
|
sockptr->LoginState = 2; // Data
|
|
sockptr->InputLen=0;
|
|
sockptr->LogonSent = FALSE;
|
|
|
|
if (CMSLogEnabled)
|
|
{
|
|
char logmsg[120];
|
|
sprintf(logmsg,"%d %s\r\n", sockptr->Number, Passline);
|
|
WriteCMSLog (logmsg);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
case 0:
|
|
|
|
// Check Username
|
|
//
|
|
|
|
*(CRPtr)=0; // remove cr
|
|
|
|
if (LogEnabled)
|
|
{
|
|
char Addr[256];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
|
|
if (strlen(MsgPtr) > 64)
|
|
{
|
|
MsgPtr[64] = 0;
|
|
Debugprintf("Telnet Bad User Name %s", MsgPtr);
|
|
}
|
|
|
|
sprintf(logmsg,"%d %s User=%s\n", sockptr->Number, Addr, MsgPtr);
|
|
WriteLog (logmsg);
|
|
}
|
|
for (i = 0; i < TCP->NumberofUsers; i++)
|
|
{
|
|
USER = TCP->UserRecPtr[i];
|
|
|
|
if (USER == NULL)
|
|
continue;
|
|
|
|
if (_stricmp(USER->UserName, "ANON") == 0)
|
|
{
|
|
// Anon Login - Callsign is supplied as user
|
|
|
|
sockptr->UserPointer = USER; //' Save pointer for checking password
|
|
strcpy(sockptr->Callsign, _strupr(MsgPtr)); //' for *** linked
|
|
}
|
|
else if (strcmp(MsgPtr,USER->UserName) == 0)
|
|
{
|
|
sockptr->UserPointer = USER; //' Save pointer for checking password
|
|
strcpy(sockptr->Callsign, USER->Callsign); //' for *** linked
|
|
|
|
}
|
|
else
|
|
continue;
|
|
|
|
sockptr->Retries = 0;
|
|
|
|
sockptr->LoginState = 1;
|
|
sockptr->InputLen = 0;
|
|
|
|
n=sockptr->Number;
|
|
|
|
#ifndef LINBPQ
|
|
ModifyMenu(TCP->hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, MsgPtr);
|
|
#endif
|
|
|
|
ShowConnections(TNC);;
|
|
|
|
InputLen=InputLen-(MsgLen+1);
|
|
|
|
sockptr->InputLen=InputLen;
|
|
|
|
if (InputLen > 0)
|
|
{
|
|
memmove(MsgPtr, CRPtr+1, InputLen);
|
|
goto MsgLoop;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// User Not found
|
|
|
|
if (sockptr->Retries++ == 4)
|
|
{
|
|
send(sock,AttemptsMsg,sizeof(AttemptsMsg),0);
|
|
Sleep (1000);
|
|
DataSocket_Disconnect(TNC, sockptr); //' Tidy up
|
|
}
|
|
else
|
|
{
|
|
send(sock, TCP->LoginMsg, (int)strlen(TCP->LoginMsg), 0);
|
|
sockptr->InputLen=0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
case 1:
|
|
|
|
*(CRPtr)=0; // remove cr
|
|
|
|
if (LogEnabled)
|
|
{
|
|
char Addr[256];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
|
|
if (strlen(MsgPtr) > 64)
|
|
{
|
|
MsgPtr[64] = 0;
|
|
Debugprintf("Telnet Bad Password %s", MsgPtr);
|
|
}
|
|
|
|
sprintf(logmsg,"%d %s Password=%s\n", sockptr->Number, Addr, MsgPtr);
|
|
WriteLog (logmsg);
|
|
}
|
|
if (strcmp(MsgPtr, sockptr->UserPointer->Password) == 0)
|
|
{
|
|
char * Appl;
|
|
|
|
if (ProcessIncommingConnect(TNC, sockptr->Callsign, sockptr->Number, FALSE) == FALSE)
|
|
{
|
|
DataSocket_Disconnect(TNC, sockptr); //' Tidy up
|
|
return 0;
|
|
}
|
|
|
|
TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->Secure_Session = sockptr->UserPointer->Secure;
|
|
|
|
sockptr->LoginState = 2;
|
|
|
|
sockptr->InputLen = 0;
|
|
|
|
if (LogEnabled)
|
|
{
|
|
char Addr[100];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
sprintf(logmsg,"%d %s Call Accepted. Callsign=%s\n",
|
|
sockptr->Number, Addr,sockptr->Callsign);
|
|
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
ShowConnections(TNC);;
|
|
InputLen=InputLen-(MsgLen+1);
|
|
|
|
sockptr->InputLen=InputLen;
|
|
|
|
// What is left is the Command to connect to the BBS
|
|
|
|
if (InputLen > 1)
|
|
{
|
|
if (*(CRPtr+1) == 10)
|
|
{
|
|
CRPtr++;
|
|
InputLen--;
|
|
}
|
|
|
|
memmove(MsgPtr, CRPtr+1, InputLen);
|
|
|
|
if (_memicmp(MsgPtr, "BPQTermTCP", 10) == 0)
|
|
{
|
|
send(sock, "Connected to TelnetServer\r", 26, 0);
|
|
sockptr->BPQTermMode = TRUE;
|
|
sockptr->MMASK = 0; // Make sure defaults to off
|
|
sockptr->InputLen -= 11;
|
|
|
|
if (sockptr->InputLen)
|
|
{
|
|
// Monitor control info may arrive in same packet
|
|
|
|
int P8 = 0;
|
|
|
|
memmove(MsgPtr, &MsgPtr[11], InputLen);
|
|
if (memcmp(MsgPtr, "\\\\\\\\", 4) == 0)
|
|
{
|
|
// Monitor Control
|
|
|
|
int n = sscanf(&MsgPtr[4], "%llx %x %x %x %x %x %x %x",
|
|
&sockptr->MMASK, &sockptr->MTX, &sockptr->MCOM, &sockptr->MonitorNODES,
|
|
&sockptr->MonitorColour, &sockptr->MUIOnly, &sockptr->UTF8, &P8);
|
|
|
|
if (n == 5)
|
|
sockptr->MUIOnly = sockptr->UTF8 = 0;
|
|
|
|
if (n == 6)
|
|
sockptr->UTF8 = 0;
|
|
|
|
if (P8 == 1)
|
|
SendPortsForMonitor(sock, sockptr->UserPointer->Secure);
|
|
|
|
|
|
sockptr->InputLen = 0;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MsgPtr[InputLen] = 13;
|
|
SendtoNode(TNC, sockptr->Number, MsgPtr, InputLen+1);
|
|
}
|
|
sockptr->InputLen = 0;
|
|
}
|
|
|
|
Appl = sockptr->UserPointer->Appl;
|
|
|
|
if (Appl[0])
|
|
SendtoNode(TNC, sockptr->Number, Appl, (int)strlen(Appl));
|
|
|
|
return 0;
|
|
}
|
|
// Bad Password
|
|
|
|
if (sockptr->Retries++ == 4)
|
|
{
|
|
send(sock,AttemptsMsg, (int)strlen(AttemptsMsg),0);
|
|
Sleep (1000);
|
|
DataSocket_Disconnect(TNC, sockptr); //' Tidy up
|
|
}
|
|
else
|
|
{
|
|
send(sock, TCP->PasswordMsg, (int)strlen(TCP->PasswordMsg), 0);
|
|
sockptr->InputLen=0;
|
|
}
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
extern char * RigWebPage;
|
|
|
|
int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream)
|
|
{
|
|
int w =1, x= 1, len=0, y = 2, maxlen, InputLen, ret;
|
|
char NLMsg[3]={13,10,0};
|
|
UCHAR * MsgPtr;
|
|
UCHAR * CRLFCRLF;
|
|
UCHAR * LenPtr;
|
|
int BodyLen, ContentLen;
|
|
struct ConnectionInfo * sockcopy;
|
|
|
|
ret = ioctl(sock,FIONREAD,&w);
|
|
|
|
maxlen = InputBufferLen - sockptr->InputLen;
|
|
|
|
if (w > maxlen) w = maxlen;
|
|
|
|
len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], w, 0);
|
|
|
|
if (len == SOCKET_ERROR || len == 0)
|
|
{
|
|
// Failed or closed - clear connection
|
|
|
|
TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return 0;
|
|
}
|
|
|
|
MsgPtr = &sockptr->InputBuffer[0];
|
|
sockptr->InputLen += len;
|
|
InputLen = sockptr->InputLen;
|
|
|
|
MsgPtr[InputLen] = 0;
|
|
|
|
if (sockptr->WebSocks)
|
|
{
|
|
// Websocks message
|
|
|
|
int i, j;
|
|
int Fin, Opcode, Len, Mask;
|
|
char MaskingKey[4];
|
|
char * ptr;
|
|
|
|
/*
|
|
+-+-+-+-+-------+-+-------------+-------------------------------+
|
|
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|
|
|I|S|S|S| (4) |A| (7) | (16/64) |
|
|
|N|V|V|V| |S| | (if payload len==126/127) |
|
|
| |1|2|3| |K| | |
|
|
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
|
|
| Extended payload length continued, if payload len == 127 |
|
|
+ - - - - - - - - - - - - - - - +-------------------------------+
|
|
| |Masking-key, if MASK set to 1 |
|
|
+-------------------------------+-------------------------------+
|
|
| Masking-key (continued) | Payload Data |
|
|
+-------------------------------- - - - - - - - - - - - - - - - +
|
|
: Payload Data continued ... :
|
|
|
|
Octet i of the transformed data ("transformed-octet-i") is the XOR of
|
|
octet i of the original data ("original-octet-i") with octet at index
|
|
i modulo 4 of the masking key ("masking-key-octet-j"):
|
|
|
|
j = i MOD 4
|
|
transformed-octet-i = original-octet-i XOR masking-key-octet-j
|
|
*/
|
|
Fin = MsgPtr[0] >> 7;
|
|
Opcode = MsgPtr[0] & 15;
|
|
Mask = MsgPtr[1] >> 7;
|
|
Len = MsgPtr[1] & 127;
|
|
memcpy(MaskingKey, &MsgPtr[2], 4);
|
|
ptr = &MsgPtr[6];
|
|
|
|
for (i = 0; i < Len; i++)
|
|
{
|
|
j = i & 3;
|
|
|
|
*ptr = *ptr ^ MaskingKey[j];
|
|
ptr++;
|
|
}
|
|
|
|
if (Opcode == 8)
|
|
{
|
|
Debugprintf("WebSock Close");
|
|
}
|
|
else if (Opcode == 1)
|
|
{
|
|
if (strcmp(sockptr->WebURL, "RIGCTL") == 0)
|
|
{
|
|
// PTT Message
|
|
|
|
char RigCMD[64];
|
|
|
|
sprintf(RigCMD, "%s PTT", &MsgPtr[6]);
|
|
Rig_Command( (TRANSPORTENTRY *) -1, RigCMD);
|
|
}
|
|
else if (memcmp(sockptr->WebURL, "WMRefresh", 9) == 0)
|
|
{
|
|
sockcopy = malloc(sizeof(struct ConnectionInfo));
|
|
sockptr->TNC = TNC;
|
|
sockptr->LastSendTime = REALTIMETICKS;
|
|
|
|
memcpy(sockcopy, sockptr, sizeof(struct ConnectionInfo));
|
|
|
|
_beginthread(ProcessWebmailWebSockThread, 2048000, (VOID *)sockcopy); // Needs big stack
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
Debugprintf("WebSock Opcode %d Msg %s", Opcode, &MsgPtr[6]);
|
|
|
|
sockptr->InputLen = 0;
|
|
return 0;
|
|
}
|
|
|
|
// Make sure request is complete - should end crlfcrlf, and if a post have the required input message
|
|
|
|
|
|
CRLFCRLF = strstr(MsgPtr, "\r\n\r\n");
|
|
|
|
if (CRLFCRLF == 0)
|
|
return 0;
|
|
|
|
LenPtr = strstr(MsgPtr, "Content-Length:");
|
|
|
|
if (LenPtr)
|
|
{
|
|
ContentLen = atoi(LenPtr + 15);
|
|
BodyLen = InputLen - (int)((CRLFCRLF + 4 - MsgPtr));
|
|
|
|
if (BodyLen < ContentLen)
|
|
return 0;
|
|
}
|
|
|
|
sockcopy = malloc(sizeof(struct ConnectionInfo));
|
|
sockptr->TNC = TNC;
|
|
sockptr->LastSendTime = REALTIMETICKS;
|
|
|
|
memcpy(sockcopy, sockptr, sizeof(struct ConnectionInfo));
|
|
|
|
if(strstr(MsgPtr, "Upgrade: websocket"))
|
|
{
|
|
int LOCAL = 0, COOKIE = 0;
|
|
char * HostPtr;
|
|
char * ptr;
|
|
|
|
sockptr->WebSocks = 1;
|
|
ShowConnections(TNC);
|
|
|
|
memcpy(sockptr->WebURL, &MsgPtr[5], 31);
|
|
strlop(sockptr->WebURL, ' ');
|
|
if (RigWebPage)
|
|
RigWebPage[0] = 0;
|
|
|
|
HostPtr = strstr(MsgPtr, "Host: ");
|
|
|
|
if (HostPtr)
|
|
{
|
|
uint32_t Host;
|
|
char Hostname[32]= "";
|
|
struct LOCALNET * LocalNet = sockptr->TNC->TCPInfo->LocalNets;
|
|
|
|
HostPtr += 6;
|
|
memcpy(Hostname, HostPtr, 31);
|
|
strlop(Hostname, ':');
|
|
Host = inet_addr(Hostname);
|
|
|
|
if (strcmp(Hostname, "127.0.0.1") == 0)
|
|
LOCAL = TRUE;
|
|
else
|
|
{
|
|
if (sockptr->sin.sin_family != AF_INET6)
|
|
{
|
|
while(LocalNet)
|
|
{
|
|
uint32_t MaskedHost = sockptr->sin.sin_addr.s_addr & LocalNet->Mask;
|
|
if (MaskedHost == LocalNet->Network)
|
|
{
|
|
LOCAL = 1;
|
|
break;
|
|
}
|
|
LocalNet = LocalNet->Next;
|
|
}
|
|
}
|
|
|
|
ptr = strstr(MsgPtr, "BPQSessionCookie=N");
|
|
|
|
if (ptr)
|
|
COOKIE = TRUE;
|
|
}
|
|
sockptr->WebSecure = LOCAL | COOKIE;
|
|
}
|
|
}
|
|
|
|
|
|
_beginthread(ProcessHTTPMessage, 2048000, (VOID *)sockcopy); // Needs big stack
|
|
|
|
sockptr->InputLen = 0;
|
|
return 0;
|
|
}
|
|
|
|
int DataSocket_ReadDRATS(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream)
|
|
{
|
|
int len=0, maxlen;
|
|
|
|
ioctl(sock,FIONREAD,&len);
|
|
|
|
maxlen = InputBufferLen - sockptr->InputLen;
|
|
|
|
if (len > maxlen) len = maxlen;
|
|
|
|
len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0);
|
|
|
|
if (len == SOCKET_ERROR || len == 0)
|
|
{
|
|
// Failed or closed - clear connection
|
|
|
|
DRATSConnectionLost(sockptr);
|
|
DataSocket_Disconnect(TNC, sockptr);
|
|
return 0;
|
|
}
|
|
|
|
// Make sure request is complete - should end [EOB]
|
|
|
|
processDRATSFrame(&sockptr->InputBuffer[sockptr->InputLen], len, sockptr);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int DataSocket_Disconnect(struct TNCINFO * TNC, struct ConnectionInfo * sockptr)
|
|
{
|
|
int n;
|
|
|
|
if (sockptr->SocketActive)
|
|
{
|
|
if (sockptr->socket)
|
|
closesocket(sockptr->socket);
|
|
|
|
n = sockptr->Number;
|
|
#ifndef LINBPQ
|
|
ModifyMenu(TNC->TCPInfo->hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, ".");
|
|
#endif
|
|
sockptr->SocketActive = FALSE;
|
|
ShowConnections(TNC);;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int ShowConnections(struct TNCINFO * TNC)
|
|
{
|
|
#ifndef LINBPQ
|
|
char msg[80];
|
|
struct ConnectionInfo * sockptr;
|
|
int i,n;
|
|
|
|
SendMessage(TNC->hMonitor,LB_RESETCONTENT,0,0);
|
|
|
|
for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++)
|
|
{
|
|
sockptr=TNC->Streams[n].ConnectionInfo;
|
|
|
|
if (!sockptr->SocketActive)
|
|
{
|
|
strcpy(msg,"Idle");
|
|
}
|
|
else
|
|
{
|
|
if (sockptr->UserPointer == 0)
|
|
{
|
|
if (sockptr->HTTPMode)
|
|
{
|
|
char Addr[100];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
|
|
if (sockptr->WebSocks)
|
|
sprintf(msg, "Websock From %s", Addr);
|
|
else
|
|
sprintf(msg, "HTTP From %s", Addr);
|
|
}
|
|
else if (sockptr->DRATSMode)
|
|
{
|
|
char Addr[100];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
sprintf(msg, "DRATS From %s", Addr);
|
|
}
|
|
else
|
|
strcpy(msg,"Logging in");
|
|
}
|
|
else
|
|
{
|
|
i=sprintf(msg,"%-10s %-10s %2d",
|
|
sockptr->UserPointer->UserName, sockptr->Callsign, sockptr->FromHostBuffPutptr - sockptr->FromHostBuffGetptr);
|
|
}
|
|
}
|
|
SendMessage(TNC->hMonitor, LB_ADDSTRING ,0, (LPARAM)msg);
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
byte * EncodeCall(byte * Call)
|
|
{
|
|
static char axcall[10];
|
|
|
|
ConvToAX25(Call, axcall);
|
|
return &axcall[0];
|
|
}
|
|
BOOL ProcessTelnetCommand(struct ConnectionInfo * sockptr, byte * Msg, int * Len)
|
|
{
|
|
int cmd, TelOption;
|
|
int used;
|
|
char WillSupGA[3]={IAC,WILL,suppressgoahead};
|
|
char WillEcho[3]={IAC,WILL,echo};
|
|
char Wont[3]={IAC,WONT,echo};
|
|
char Dont[3]={IAC,DONT,echo};
|
|
|
|
// Note Msg points to the IAC, which may not be at the start of the receive buffer
|
|
// Len is number of bytes left in buffer including the IAC
|
|
|
|
if (*Len < 2) return TRUE; //' Wait for more
|
|
|
|
cmd = Msg[1];
|
|
|
|
if (cmd == DOx || cmd == DONT || cmd == WILL || cmd == WONT)
|
|
if (*Len < 3) return TRUE; //' wait for option
|
|
|
|
TelOption = Msg[2];
|
|
|
|
switch (cmd)
|
|
{
|
|
case DOx:
|
|
|
|
switch (TelOption)
|
|
{
|
|
case echo:
|
|
sockptr->DoEcho = TRUE;
|
|
send(sockptr->socket,WillEcho,3,0);
|
|
break;
|
|
|
|
case suppressgoahead:
|
|
|
|
send(sockptr->socket,WillSupGA,3,0);
|
|
break;
|
|
|
|
default:
|
|
|
|
Wont[2] = TelOption;
|
|
send(sockptr->socket,Wont,3,0);
|
|
}
|
|
|
|
used=3;
|
|
|
|
break;
|
|
|
|
case DONT:
|
|
|
|
// Debug.Print "DONT"; TelOption
|
|
|
|
switch (TelOption)
|
|
{
|
|
case echo:
|
|
sockptr->DoEcho = FALSE;
|
|
break;
|
|
}
|
|
|
|
Wont[2] = TelOption;
|
|
send(sockptr->socket,Wont,3,0);
|
|
|
|
used=3;
|
|
|
|
break;
|
|
|
|
case WILL:
|
|
|
|
// Debug.Print "WILL"; TelOption
|
|
|
|
// if (TelOption == echo) sockptr->DoEcho = TRUE;
|
|
|
|
Dont[2] = TelOption;
|
|
send(sockptr->socket, Dont, 3, 0);
|
|
|
|
used=3;
|
|
|
|
break;
|
|
|
|
case WONT:
|
|
|
|
// Debug.Print "WONT"; TelOption
|
|
|
|
used=3;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
used=2;
|
|
|
|
}
|
|
|
|
// remove the processed command from the buffer
|
|
|
|
*Len -= used;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
int WriteLog(char * msg)
|
|
{
|
|
FILE *file;
|
|
char timebuf[128];
|
|
time_t ltime;
|
|
|
|
UCHAR Value[MAX_PATH];
|
|
time_t T;
|
|
struct tm * tm;
|
|
|
|
T = time(NULL);
|
|
tm = gmtime(&T);
|
|
|
|
if (LogDirectory[0] == 0)
|
|
{
|
|
strcpy(Value, "logs/Telnet_");
|
|
}
|
|
else
|
|
{
|
|
strcpy(Value, LogDirectory);
|
|
strcat(Value, "/");
|
|
strcat(Value, "logs/Telnet_");
|
|
}
|
|
|
|
sprintf(Value, "%s%02d%02d%02d.log", Value,
|
|
tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday);
|
|
|
|
if ((file = fopen(Value, "a")) == NULL)
|
|
return FALSE;
|
|
|
|
time(<ime);
|
|
|
|
#ifdef LINBPQ
|
|
{
|
|
struct tm * tmp = localtime(<ime);
|
|
strftime( timebuf, 128,
|
|
"%d/%m/%Y %H:%M:%S ", tmp );
|
|
}
|
|
#else
|
|
{
|
|
struct tm * today;
|
|
|
|
today = localtime(<ime);
|
|
strftime(timebuf, 128, "%d/%m/%Y %H:%M:%S ", today);
|
|
}
|
|
#endif
|
|
fputs(timebuf, file);
|
|
fputs(msg, file);
|
|
fclose(file);
|
|
return 0;
|
|
}
|
|
|
|
char LastCMSLog[256];
|
|
|
|
VOID WriteCMSLog(char * msg)
|
|
{
|
|
UCHAR Value[MAX_PATH];
|
|
time_t T;
|
|
struct tm * tm;
|
|
FILE * Handle;
|
|
char LogMsg[256];
|
|
int MsgLen;
|
|
|
|
if (CMSLogEnabled == FALSE)
|
|
return;
|
|
|
|
T = time(NULL);
|
|
tm = gmtime(&T);
|
|
|
|
if (LogDirectory[0] == 0)
|
|
{
|
|
strcpy(Value, "logs/CMSAccess");
|
|
}
|
|
else
|
|
{
|
|
strcpy(Value, LogDirectory);
|
|
strcat(Value, "/");
|
|
strcat(Value, "logs/CMSAccess");
|
|
}
|
|
|
|
sprintf(Value, "%s_%04d%02d%02d.log", Value,
|
|
tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday);
|
|
|
|
Handle = fopen(Value, "ab");
|
|
|
|
if (Handle == NULL)
|
|
return;
|
|
|
|
MsgLen = sprintf(LogMsg, "%02d:%02d:%02d %s", tm->tm_hour, tm->tm_min, tm->tm_sec, msg);
|
|
|
|
fwrite(LogMsg , 1, MsgLen, Handle);
|
|
|
|
fclose(Handle);
|
|
|
|
#ifndef WIN32
|
|
|
|
if (strcmp(Value, LastCMSLog))
|
|
{
|
|
UCHAR SYMLINK[MAX_PATH];
|
|
|
|
sprintf(SYMLINK,"%s/CMSAccessLatest.log", BPQDirectory);
|
|
unlink(SYMLINK);
|
|
strcpy(LastCMSLog, Value);
|
|
symlink(Value, SYMLINK);
|
|
}
|
|
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int Telnet_Connected(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Error)
|
|
{
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
PMSGWITHLEN buffptr;
|
|
int Stream = sockptr->Number;
|
|
char Signon[80];
|
|
int errlen = 4;
|
|
|
|
buffptr = (PMSGWITHLEN)GetBuff();
|
|
if (buffptr == 0) return 0; // No buffers, so ignore
|
|
|
|
#ifndef WIN32
|
|
|
|
// SO_ERROR codes
|
|
|
|
//#define ETIMEDOUT 110 /* Connection timed out */
|
|
//#define ECONNREFUSED 111 /* Connection refused */
|
|
//#define EHOSTDOWN 112 /* Host is down */
|
|
//#define EHOSTUNREACH 113 /* No route to host */
|
|
//#define EALREADY 114 /* Operation already in progress */
|
|
//#define EINPROGRESS 115 /* Operation now in progress */
|
|
|
|
if (Error == 0)
|
|
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&Error, &errlen);
|
|
|
|
// Debugprintf("Except Event Error after opts = %d", Error);
|
|
#endif
|
|
|
|
if (Error)
|
|
{
|
|
if (sockptr->CMSSession && sockptr->RelaySession == 0)
|
|
{
|
|
// Try Next
|
|
|
|
TCP->CMSFailed[sockptr->CMSIndex] = TRUE;
|
|
|
|
if (CMSConnect(TNC, TNC->TCPInfo, &TNC->Streams[Stream], Stream))
|
|
return 0;
|
|
|
|
// Connect failure - if no more servers to check look for FALLBACKTORELAY
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
int err = 0;
|
|
int errlen = 4;
|
|
|
|
getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen);
|
|
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "*** Failed to Connect\r");
|
|
|
|
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
|
|
|
|
closesocket(sock);
|
|
TNC->Streams[Stream].Connecting = FALSE;
|
|
sockptr->SocketActive = FALSE;
|
|
ShowConnections(TNC);
|
|
TNC->Streams[Stream].NeedDisc = 10;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
sockptr->LogonSent = FALSE;
|
|
|
|
if (sockptr->CMSSession)
|
|
{
|
|
sockptr->LoginState = 3; // Password State
|
|
|
|
sockptr->UserPointer = &CMSUser;
|
|
strcpy(sockptr->Callsign, TNC->Streams[Stream].MyCall);
|
|
|
|
sockptr->DoEcho = FALSE;
|
|
sockptr->FBBMode = TRUE;
|
|
sockptr->RelayMode = FALSE;
|
|
sockptr->ClientSession = FALSE;
|
|
sockptr->SyncMode = FALSE;
|
|
|
|
if (TCP->CMS)
|
|
SaveCMSHostInfo(TNC->Port, TNC->TCPInfo, sockptr->CMSIndex);
|
|
|
|
if (CMSLogEnabled)
|
|
{
|
|
char logmsg[120];
|
|
|
|
if (sockptr->RelaySession)
|
|
sprintf(logmsg,"%d %s Connected to RELAY\r\n", sockptr->Number, TNC->Streams[Stream].MyCall);
|
|
else
|
|
sprintf(logmsg,"%d %s Connected to CMS\r\n", sockptr->Number, TNC->Streams[Stream].MyCall);
|
|
|
|
WriteCMSLog (logmsg);
|
|
}
|
|
|
|
if (sockptr->RelaySession)
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "*** %s Connected to RELAY\r", TNC->Streams[Stream].MyCall);
|
|
else
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "*** %s Connected to CMS\r", TNC->Streams[Stream].MyCall);
|
|
}
|
|
else
|
|
{
|
|
sockptr->LoginState = 2; // Data State
|
|
sockptr->UserPointer = &HostUser;
|
|
strcpy(sockptr->Callsign, TNC->Streams[Stream].MyCall);
|
|
sockptr->DoEcho = FALSE;
|
|
sockptr->ClientSession = TRUE;
|
|
|
|
if (sockptr->SyncMode)
|
|
{
|
|
char Addr[256];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "*** Connected to SYNC %s:%d\r", Addr, htons(sockptr->sin.sin_port));
|
|
send(sockptr->socket, sockptr->Signon, (int)strlen(sockptr->Signon), 0);
|
|
}
|
|
else
|
|
{
|
|
if (sockptr->Signon[0])
|
|
{
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "*** Connected to Server\r");
|
|
send(sockptr->socket, sockptr->Signon, (int)strlen(sockptr->Signon), 0);
|
|
}
|
|
else
|
|
{
|
|
if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4CROSSLINK->APPL[0])
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "*** Connected to %s\r",
|
|
TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4CROSSLINK->APPL);
|
|
else
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "*** Connected to APPL\r");
|
|
|
|
if (sockptr->NoCallsign == FALSE)
|
|
send(sockptr->socket, Signon, sprintf(Signon, "%s\r\n", TNC->Streams[Stream].MyCall), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
|
|
|
|
sockptr->SocketActive = TRUE;
|
|
sockptr->InputLen = 0;
|
|
// sockptr->Number = Stream;
|
|
sockptr->RelayMode = FALSE;
|
|
sockptr->ConnectTime = time(NULL);
|
|
TNC->Streams[Stream].Connecting = FALSE;
|
|
TNC->Streams[Stream].Connected = TRUE;
|
|
|
|
if (sockptr->ADIF == NULL)
|
|
sockptr->ADIF = malloc(sizeof(struct ADIF));
|
|
|
|
memset(sockptr->ADIF, 0, sizeof(struct ADIF));
|
|
|
|
strcpy(sockptr->ADIF->Call, TNC->Streams[Stream].MyCall);
|
|
|
|
ShowConnections(TNC);
|
|
|
|
if (sockptr->FromHostBuffer == 0)
|
|
{
|
|
sockptr->FromHostBuffer = malloc(10000);
|
|
sockptr->FromHostBufferSize = 10000;
|
|
}
|
|
|
|
sockptr->FromHostBuffPutptr = sockptr->FromHostBuffGetptr = 0;
|
|
|
|
TNC->Streams[Stream].bytesRXed = TNC->Streams[Stream].bytesTXed = 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
VOID ReportError(struct STREAMINFO * STREAM, char * Msg)
|
|
{
|
|
PMSGWITHLEN buffptr;
|
|
|
|
buffptr = (PMSGWITHLEN)GetBuff();
|
|
if (buffptr == 0) return; // No buffers, so ignore
|
|
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "Error - %s\r", Msg);
|
|
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
}
|
|
|
|
VOID Report(struct STREAMINFO * STREAM, char * Msg)
|
|
{
|
|
PMSGWITHLEN buffptr;
|
|
|
|
buffptr = (PMSGWITHLEN)GetBuff();
|
|
if (buffptr == 0) return; // No buffers, so ignore
|
|
|
|
buffptr->Len = sprintf(&buffptr->Data[0], "%s\r", Msg);
|
|
|
|
C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
|
|
}
|
|
|
|
void CheckCMSThread(void * TNC);
|
|
|
|
BOOL CheckCMS(struct TNCINFO * TNC)
|
|
{
|
|
if (TNC->TCPInfo->CMS)
|
|
{
|
|
TNC->TCPInfo->CheckCMSTimer = 0;
|
|
_beginthread(CheckCMSThread, 0, (void *)TNC);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void CheckCMSThread(void * TNCPtr)
|
|
{
|
|
// Resolve Name and check connectivity to each address
|
|
|
|
struct TNCINFO * TNC = (struct TNCINFO *)TNCPtr;
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
// struct hostent * HostEnt;
|
|
struct in_addr addr;
|
|
struct hostent *remoteHost;
|
|
char **pAlias; int i = 0;
|
|
BOOL INETOK = FALSE;
|
|
struct addrinfo hints, *res = 0, *saveres;
|
|
int n;
|
|
unsigned long cms;
|
|
|
|
TCP->UseCachedCMSAddrs = FALSE;
|
|
|
|
// if TCP->CMSServer is an ip address use it
|
|
|
|
cms = inet_addr(TCP->CMSServer);
|
|
|
|
if (cms != INADDR_NONE)
|
|
{
|
|
Debugprintf("Using %s for CMS Server", TCP->CMSServer);
|
|
TCP->CMSAddr[0].s_addr = cms;
|
|
TCP->CMSFailed[0] = FALSE;
|
|
TCP->CMSName[0] = _strdup(TCP->CMSServer); // Save Host Name
|
|
TCP->NumberofCMSAddrs = 1;
|
|
goto CheckServers;
|
|
}
|
|
|
|
// First make sure we have a functioning DNS
|
|
|
|
memset(&hints, 0, sizeof hints);
|
|
hints.ai_family = AF_INET6; // use IPv4 or IPv6, whichever
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
|
n = getaddrinfo("a.root-servers.net", NULL, &hints, &res);
|
|
|
|
if (n == 0)
|
|
goto rootok;
|
|
|
|
memset(&hints, 0, sizeof hints);
|
|
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
n = getaddrinfo("b.root-servers.net", NULL, &hints, &res);
|
|
|
|
if (n == 0)
|
|
goto rootok;
|
|
|
|
Debugprintf("Resolve root nameserver failed");
|
|
|
|
// Most likely is a local Internet Outage, but we could have Internet, but no name servers
|
|
// Either way, switch to using cached CMS addresses. CMS Validation will check connectivity
|
|
|
|
TCP->UseCachedCMSAddrs = TRUE;
|
|
goto CheckServers;
|
|
|
|
rootok:
|
|
|
|
freeaddrinfo(res);
|
|
|
|
INETOK = TRUE; // We have connectivity
|
|
|
|
res = 0;
|
|
memset(&hints, 0, sizeof hints);
|
|
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
n = getaddrinfo(TCP->CMSServer, NULL, &hints, &res);
|
|
|
|
if (n || !res || res->ai_next == 0) // Resolve Failed, or Returned only one Host
|
|
{
|
|
// Switch to Cached Servers
|
|
|
|
if (res)
|
|
{
|
|
// If Host is amazonaws, allow it
|
|
|
|
remoteHost = gethostbyaddr((char *) &res->ai_addr->sa_data[2], 4, AF_INET);
|
|
|
|
if (remoteHost && strstr(_strlwr(remoteHost->h_name), "amazonaws"))
|
|
goto resok;
|
|
|
|
Debugprintf("Resolve CMS returned only one host");
|
|
freeaddrinfo(res);
|
|
}
|
|
else
|
|
Debugprintf("Resolve CMS Failed");
|
|
|
|
TCP->UseCachedCMSAddrs = TRUE;
|
|
|
|
goto CheckServers;
|
|
}
|
|
|
|
resok:
|
|
|
|
saveres = res;
|
|
|
|
while (res)
|
|
{
|
|
memcpy(&addr.s_addr, &res->ai_addr->sa_data[2], 4);
|
|
TCP->CMSAddr[i] = addr;
|
|
TCP->CMSFailed[i] = FALSE;
|
|
i++;
|
|
res = res->ai_next;
|
|
}
|
|
|
|
freeaddrinfo(saveres);
|
|
|
|
TCP->NumberofCMSAddrs = i;
|
|
|
|
i = 0;
|
|
|
|
while (i < TCP->NumberofCMSAddrs)
|
|
{
|
|
if (TCP->CMSName[i])
|
|
free(TCP->CMSName[i]);
|
|
|
|
remoteHost = gethostbyaddr((char *) &TCP->CMSAddr[i], 4, AF_INET);
|
|
|
|
if (remoteHost == NULL)
|
|
{
|
|
int dwError = WSAGetLastError();
|
|
|
|
TCP->CMSName[i] = NULL;
|
|
|
|
if (dwError != 0)
|
|
{
|
|
if (dwError == HOST_NOT_FOUND)
|
|
Debugprintf("CMS - Host not found");
|
|
else if (dwError == NO_DATA)
|
|
Debugprintf("CMS No data record found");
|
|
else
|
|
Debugprintf("CMS Gethost failed %d", dwError);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debugprintf("CMS #%d %s Official name : %s",i, inet_ntoa(TCP->CMSAddr[i]), remoteHost->h_name);
|
|
|
|
TCP->CMSName[i] = _strdup(remoteHost->h_name); // Save Host Name
|
|
|
|
for (pAlias = remoteHost->h_aliases; *pAlias != 0; pAlias++)
|
|
{
|
|
Debugprintf("\tAlternate name #%d: %s\n", i, *pAlias);
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
TCP->NumberofCMSAddrs = i;
|
|
|
|
CheckServers:
|
|
#ifndef LINBPQ
|
|
CheckMenuItem(TNC->TCPInfo->hActionMenu, 4, MF_BYPOSITION | TCP->UseCachedCMSAddrs<<3);
|
|
#endif
|
|
if (TCP->UseCachedCMSAddrs)
|
|
{
|
|
// Get Cached Servers from CMSInfo.txt
|
|
|
|
GetCMSCachedInfo(TNC);
|
|
}
|
|
|
|
if (TCP->NumberofCMSAddrs == 0)
|
|
{
|
|
TCP->CMSOK = FALSE;
|
|
#ifndef LINBPQ
|
|
SetWindowText(TCP->hCMSWnd, "NO CMS");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
// if we don't know we have Internet connectivity, make sure we can connect to at least one of them
|
|
|
|
TCP->CMSOK = INETOK | CMSCheck(TNC, TCP); // If we know we have Inet, dont check connectivity
|
|
|
|
#ifndef LINBPQ
|
|
if (TCP->CMSOK)
|
|
MySetWindowText(TCP->hCMSWnd, "CMS OK");
|
|
else
|
|
MySetWindowText(TCP->hCMSWnd, "NO CMS");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
#define MAX_KEY_LENGTH 255
|
|
#define MAX_VALUE_NAME 255
|
|
#define MAX_VALUE_DATA 255
|
|
|
|
|
|
|
|
VOID GetCMSCachedInfo(struct TNCINFO * TNC)
|
|
{
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
ULONG IPAD;
|
|
char inname[256];
|
|
|
|
FILE *in;
|
|
char Buffer[2048];
|
|
char *buf = Buffer;
|
|
char *ptr1, *ptr2, *context;
|
|
int i = 0;
|
|
|
|
if (LogDirectory[0] == 0)
|
|
{
|
|
strcpy(inname, "logs/CMSInfo.txt");
|
|
}
|
|
else
|
|
{
|
|
strcpy(inname, LogDirectory);
|
|
strcat(inname, "/");
|
|
strcat(inname, "logs/CMSInfo.txt");
|
|
}
|
|
|
|
TCP->NumberofCMSAddrs = 0;
|
|
|
|
in = fopen(inname, "r");
|
|
|
|
if (!(in)) return;
|
|
|
|
while(fgets(buf, 128, in))
|
|
{
|
|
ptr1 = strtok_s(buf, ", ", &context);
|
|
ptr2 = strtok_s(NULL, ", ", &context); // Skip Time
|
|
ptr2 = strtok_s(NULL, ", ", &context);
|
|
|
|
if (ptr1[0] < 32 || ptr1[0] > 127 || ptr2 == NULL)
|
|
continue;
|
|
|
|
IPAD = inet_addr(ptr2);
|
|
|
|
memcpy(&TCP->CMSAddr[i], &IPAD, 4);
|
|
|
|
TCP->CMSFailed[i] = FALSE;
|
|
|
|
if (TCP->CMSName[i])
|
|
free(TCP->CMSName[i]);
|
|
|
|
TCP->CMSName[i] = _strdup(ptr1); // Save Host Name
|
|
i++;
|
|
|
|
if (i >= MaxCMS)
|
|
break;
|
|
}
|
|
|
|
fclose(in);
|
|
|
|
TCP->NumberofCMSAddrs = i;
|
|
|
|
return;
|
|
}
|
|
|
|
BOOL CMSCheck(struct TNCINFO * TNC, struct TCPINFO * TCP)
|
|
{
|
|
// Make sure at least one CMS can be connected to
|
|
|
|
u_long param=1;
|
|
BOOL bcopt=TRUE;
|
|
SOCKET sock;
|
|
struct sockaddr_in sinx;
|
|
struct sockaddr_in destaddr;
|
|
int addrlen=sizeof(sinx);
|
|
int n = 0;
|
|
|
|
destaddr.sin_family = AF_INET;
|
|
destaddr.sin_port = htons(8772);
|
|
|
|
sinx.sin_family = AF_INET;
|
|
sinx.sin_addr.s_addr = INADDR_ANY;
|
|
sinx.sin_port = 0;
|
|
|
|
for (n = 0; n < TCP->NumberofCMSAddrs; n++)
|
|
{
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
return FALSE;
|
|
|
|
memcpy(&destaddr.sin_addr.s_addr, &TCP->CMSAddr[n], 4);
|
|
|
|
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4);
|
|
|
|
if (bind(sock, (struct sockaddr *) &sinx, addrlen) != 0 )
|
|
return FALSE;
|
|
|
|
if (connect(sock,(struct sockaddr *) &destaddr, sizeof(destaddr)) == 0)
|
|
{
|
|
closesocket(sock);
|
|
return TRUE;
|
|
}
|
|
|
|
// Failed - try next
|
|
|
|
if (TCP->CMSName[n])
|
|
Debugprintf("Check CMS Failed for %s", TCP->CMSName[n]);
|
|
closesocket(sock);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
int CMSConnect(struct TNCINFO * TNC, struct TCPINFO * TCP, struct STREAMINFO * STREAM, int Stream)
|
|
{
|
|
int err;
|
|
u_long param=1;
|
|
BOOL bcopt=TRUE;
|
|
struct ConnectionInfo * sockptr;
|
|
SOCKET sock;
|
|
struct sockaddr_in sinx;
|
|
struct sockaddr_in destaddr;
|
|
int addrlen=sizeof(sinx);
|
|
int n;
|
|
char Msg[80];
|
|
|
|
sockptr = STREAM->ConnectionInfo;
|
|
|
|
sock = sockptr->socket = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
ReportError(STREAM, "Create Socket Failed");
|
|
return FALSE;
|
|
}
|
|
|
|
if (sockptr->ADIF == NULL)
|
|
sockptr->ADIF = malloc(sizeof(struct ADIF));
|
|
|
|
memset(sockptr->ADIF, 0, sizeof(struct ADIF));
|
|
|
|
sockptr->SocketActive = TRUE;
|
|
sockptr->InputLen = 0;
|
|
sockptr->LoginState = 2;
|
|
sockptr->UserPointer = 0;
|
|
sockptr->DoEcho = FALSE;
|
|
sockptr->BPQTermMode = FALSE;
|
|
|
|
sockptr->FBBMode = TRUE; // Raw Data
|
|
sockptr->NeedLF = FALSE;
|
|
|
|
if (sockptr->ADIF == NULL)
|
|
sockptr->ADIF = malloc(sizeof(struct ADIF));
|
|
|
|
memset(sockptr->ADIF, 0, sizeof(struct ADIF));
|
|
|
|
destaddr.sin_family = AF_INET;
|
|
destaddr.sin_port = htons(8772);
|
|
|
|
// See if current CMS is down
|
|
|
|
n = 0;
|
|
|
|
while (TCP->CMSFailed[TCP->NextCMSAddr])
|
|
{
|
|
TCP->NextCMSAddr++;
|
|
if (TCP->NextCMSAddr >= TCP->NumberofCMSAddrs) TCP->NextCMSAddr = 0;
|
|
n++;
|
|
|
|
if (n == TCP->NumberofCMSAddrs)
|
|
{
|
|
TCP->CMSOK = FALSE;
|
|
#ifndef LINBPQ
|
|
DrawMenuBar(TNC->hDlg);
|
|
#endif
|
|
ReportError(STREAM, "All CMS Servers are inaccessible");
|
|
closesocket(sock);
|
|
|
|
if (TCP->RELAYHOST[0] && TCP->FallbacktoRelay && STREAM->NoCMSFallback == 0)
|
|
{
|
|
STREAM->Connecting = TRUE;
|
|
STREAM->ConnectionInfo->CMSSession = TRUE;
|
|
STREAM->ConnectionInfo->RelaySession = TRUE;
|
|
return TCPConnect(TNC, TCP, STREAM, TCP->RELAYHOST, 8772, TRUE);
|
|
}
|
|
|
|
STREAM->NeedDisc = 10;
|
|
TNC->Streams[Stream].Connecting = FALSE;
|
|
sockptr->SocketActive = FALSE;
|
|
ShowConnections(TNC);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
sockptr->CMSIndex = TCP->NextCMSAddr;
|
|
|
|
sprintf(Msg, "Trying %s", TCP->CMSName[TCP->NextCMSAddr]);
|
|
|
|
memcpy(&destaddr.sin_addr.s_addr, &TCP->CMSAddr[TCP->NextCMSAddr++], 4);
|
|
|
|
if (TCP->NextCMSAddr >= TCP->NumberofCMSAddrs)
|
|
TCP->NextCMSAddr = 0;
|
|
|
|
ioctl(sockptr->socket, FIONBIO, ¶m);
|
|
|
|
setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4);
|
|
|
|
sinx.sin_family = AF_INET;
|
|
sinx.sin_addr.s_addr = INADDR_ANY;
|
|
sinx.sin_port = 0;
|
|
|
|
if (bind(sockptr->socket, (struct sockaddr *) &sinx, addrlen) != 0 )
|
|
{
|
|
ReportError(STREAM, "Bind Failed");
|
|
return FALSE;
|
|
}
|
|
|
|
#ifndef LINBPQ
|
|
ModifyMenu(TCP->hDisMenu, Stream - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + Stream, "CMS");
|
|
#endif
|
|
|
|
Report(STREAM, Msg);
|
|
|
|
if (connect(sockptr->socket,(struct sockaddr *) &destaddr, sizeof(destaddr)) == 0)
|
|
{
|
|
//
|
|
// Connected successful
|
|
//
|
|
|
|
ReportError(STREAM, "*** Connected");
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
err=WSAGetLastError();
|
|
|
|
if (err == 10035 || err == 115 || err == 36 || err == 150) //EWOULDBLOCK
|
|
{
|
|
// Connect in Progress
|
|
|
|
sockptr->UserPointer = &CMSUser;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Connect failed
|
|
|
|
closesocket(sockptr->socket);
|
|
|
|
if (sockptr->CMSSession && sockptr->RelaySession == 0)
|
|
{
|
|
// Try Next
|
|
|
|
TCP->CMSFailed[sockptr->CMSIndex] = TRUE;
|
|
Debugprintf("Connect Failed %d, trying next", err);
|
|
CMSConnect(TNC, TNC->TCPInfo, &TNC->Streams[Stream], Stream);
|
|
return 0;
|
|
}
|
|
|
|
ReportError(STREAM, "Connect Failed");
|
|
CheckCMS(TNC);
|
|
|
|
STREAM->Connecting = FALSE;
|
|
sockptr->SocketActive = FALSE;
|
|
ShowConnections(TNC);
|
|
STREAM->NeedDisc = 10;
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
VOID SaveCMSHostInfo(int port, struct TCPINFO * TCP, int CMSNo)
|
|
{
|
|
char Info[256];
|
|
char inname[256];
|
|
char outname[256];
|
|
|
|
unsigned char work[4];
|
|
FILE *in, *out;
|
|
char Buffer[2048];
|
|
char *buf = Buffer;
|
|
|
|
if (TCP->CMS == 0)
|
|
return;
|
|
|
|
if (CMSNo > 9 || CMSNo < 0 || TCP->CMSName[CMSNo] == 0)
|
|
{
|
|
Debugprintf("SaveCMSHostInfo invalid CMS Number %d", CMSNo);
|
|
return;
|
|
}
|
|
|
|
if (LogDirectory[0] == 0)
|
|
{
|
|
strcpy(inname, "logs/CMSInfo.txt");
|
|
}
|
|
else
|
|
{
|
|
strcpy(inname, LogDirectory);
|
|
strcat(inname, "/");
|
|
strcat(inname, "logs/CMSInfo.txt");
|
|
}
|
|
|
|
if (LogDirectory[0] == 0)
|
|
{
|
|
strcpy(outname, "logs/CMSInfo.tmp");
|
|
}
|
|
else
|
|
{
|
|
strcpy(outname, LogDirectory);
|
|
strcat(outname, "/");
|
|
strcat(outname, "logs/CMSInfo.tmp");
|
|
}
|
|
|
|
memcpy(work, &TCP->CMSAddr[CMSNo].s_addr, 4);
|
|
|
|
sprintf(Info,"%s %d %d.%d.%d.%d\n", TCP->CMSName[CMSNo], (int)time(NULL),
|
|
work[0], work[1], work[2], work[3]);
|
|
|
|
|
|
in = fopen(inname, "r");
|
|
|
|
if (!(in))
|
|
{
|
|
in = fopen(inname, "w");
|
|
|
|
if (!(in))
|
|
{
|
|
perror("Failed to create CMSInfo.txt");
|
|
Debugprintf("Failed to create CMSInfo.txt");
|
|
return;
|
|
}
|
|
fclose(in);
|
|
in = fopen(inname, "r");
|
|
}
|
|
|
|
if (!(in)) return;
|
|
|
|
out = fopen(outname, "w");
|
|
|
|
if (!(out)) return;
|
|
|
|
while(fgets(buf, 128, in))
|
|
{
|
|
char addr[256];
|
|
time_t t;
|
|
char ip[256];
|
|
int n;
|
|
|
|
if (sizeof(time_t) == 4)
|
|
n = sscanf(buf,"%s %d %s", addr, (int *)&t, ip);
|
|
else
|
|
n = sscanf(buf, "%s %lld %s", addr, &t, ip);
|
|
|
|
if (n == 3)
|
|
{
|
|
time_t age = time(NULL) - t;
|
|
|
|
// if not current server and not too old, copy across
|
|
|
|
if (addr[0] > 31 && addr[0] < 127)
|
|
if ((age < 86400 * 30) && strcmp(addr, TCP->CMSName[CMSNo]) != 0)
|
|
fputs(buf, out);
|
|
}
|
|
}
|
|
|
|
fputs(Info, out);
|
|
|
|
fclose(in);
|
|
fclose(out);
|
|
|
|
remove(inname);
|
|
rename(outname, inname);
|
|
|
|
return;
|
|
}
|
|
|
|
int TCPConnect(struct TNCINFO * TNC, struct TCPINFO * TCP, struct STREAMINFO * STREAM, char * Host, int Port, BOOL FBB)
|
|
{
|
|
int err;
|
|
u_long param=1;
|
|
BOOL bcopt=TRUE;
|
|
struct ConnectionInfo * sockptr;
|
|
SOCKET sock;
|
|
struct sockaddr_in sinx;
|
|
struct sockaddr_in destaddr;
|
|
int addrlen=sizeof(sinx);
|
|
int i;
|
|
|
|
sockptr = STREAM->ConnectionInfo;
|
|
|
|
sock = sockptr->socket = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
ReportError(STREAM, "Create Socket Failed");
|
|
return FALSE;
|
|
}
|
|
|
|
sockptr->SocketActive = TRUE;
|
|
sockptr->InputLen = 0;
|
|
sockptr->LoginState = 2;
|
|
sockptr->UserPointer = 0;
|
|
sockptr->DoEcho = FALSE;
|
|
|
|
sockptr->FBBMode = FBB; // Raw Data
|
|
|
|
if (sockptr->ADIF == NULL)
|
|
sockptr->ADIF = malloc(sizeof(struct ADIF));
|
|
|
|
memset(sockptr->ADIF, 0, sizeof(struct ADIF));
|
|
|
|
|
|
// Resolve Name if needed
|
|
|
|
sockptr->sin.sin_family = AF_INET;
|
|
sockptr->sin.sin_port = htons(Port);
|
|
|
|
sockptr->sin.sin_addr.s_addr = inet_addr(Host);
|
|
|
|
if (sockptr->sin.sin_addr.s_addr == INADDR_NONE)
|
|
{
|
|
struct hostent * HostEnt;
|
|
|
|
// Resolve name to address
|
|
|
|
HostEnt = gethostbyname(Host);
|
|
|
|
if (!HostEnt)
|
|
{
|
|
ReportError(STREAM, "Resolve HostName Failed");
|
|
return FALSE; // Resolve failed
|
|
}
|
|
i = 0;
|
|
while (HostEnt->h_addr_list[i] != 0)
|
|
{
|
|
struct in_addr addr;
|
|
addr.s_addr = *(u_long *) HostEnt->h_addr_list[i++];
|
|
}
|
|
memcpy(&sockptr->sin.sin_addr.s_addr, HostEnt->h_addr, 4);
|
|
}
|
|
|
|
ioctl (sockptr->socket, FIONBIO, ¶m);
|
|
|
|
setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4);
|
|
|
|
sinx.sin_family = AF_INET;
|
|
sinx.sin_addr.s_addr = INADDR_ANY;
|
|
sinx.sin_port = 0;
|
|
|
|
if (bind(sockptr->socket, (struct sockaddr *) &sinx, addrlen) != 0 )
|
|
{
|
|
ReportError(STREAM, "Bind Failed");
|
|
return FALSE;
|
|
}
|
|
|
|
if (LogEnabled)
|
|
{
|
|
char logmsg[512];
|
|
|
|
sprintf(logmsg,"%d Outward Connect to %s Port %d\n", sockptr->Number, Host, Port);
|
|
WriteLog (logmsg);
|
|
}
|
|
|
|
|
|
if (connect(sockptr->socket,(struct sockaddr *) &sockptr->sin, sizeof(destaddr)) == 0)
|
|
{
|
|
//
|
|
// Connected successful
|
|
//
|
|
|
|
ReportError(STREAM, "*** Connected");
|
|
|
|
// Get Send Buffer Size
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
err=WSAGetLastError();
|
|
|
|
if (err == 10035 || err == 115 || err == 36) //EWOULDBLOCK
|
|
{
|
|
// Connect in Progress
|
|
|
|
sockptr->UserPointer = &HostUser;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
// Connect failed
|
|
|
|
closesocket(sockptr->socket);
|
|
ReportError(STREAM, "Connect Failed");
|
|
STREAM->Connecting = FALSE;
|
|
sockptr->SocketActive = FALSE;
|
|
ShowConnections(TNC);
|
|
STREAM->NeedDisc = 10;
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
VOID Tel_Format_Addr(struct ConnectionInfo * sockptr, char * dst)
|
|
{
|
|
unsigned char * src;
|
|
char zeros[12] = "";
|
|
char * ptr;
|
|
struct
|
|
{
|
|
int base, len;
|
|
} best, cur;
|
|
unsigned int words[8];
|
|
int i;
|
|
|
|
if (sockptr->sin.sin_family != AF_INET6)
|
|
{
|
|
unsigned char work[4];
|
|
memcpy(work, &sockptr->sin.sin_addr.s_addr, 4);
|
|
sprintf(dst,"%d.%d.%d.%d", work[0], work[1], work[2], work[3]);
|
|
return;
|
|
}
|
|
|
|
src = (unsigned char *)&sockptr->sin6.sin6_addr;
|
|
|
|
// See if Encapsulated IPV4 addr
|
|
|
|
if (src[12] != 0)
|
|
{
|
|
if (memcmp(src, zeros, 12) == 0) // 12 zeros, followed by non-zero
|
|
{
|
|
sprintf(dst,"::%d.%d.%d.%d", src[12], src[13], src[14], src[15]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Convert 16 bytes to 8 words
|
|
|
|
for (i = 0; i < 16; i += 2)
|
|
words[i / 2] = (src[i] << 8) | src[i + 1];
|
|
|
|
// Look for longest run of zeros
|
|
|
|
best.base = -1;
|
|
cur.base = -1;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
if (words[i] == 0)
|
|
{
|
|
if (cur.base == -1)
|
|
cur.base = i, cur.len = 1; // New run, save start
|
|
else
|
|
cur.len++; // Continuation - increment length
|
|
}
|
|
else
|
|
{
|
|
// End of a run of zeros
|
|
|
|
if (cur.base != -1)
|
|
{
|
|
// See if this run is longer
|
|
|
|
if (best.base == -1 || cur.len > best.len)
|
|
best = cur;
|
|
|
|
cur.base = -1; // Start again
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cur.base != -1)
|
|
{
|
|
if (best.base == -1 || cur.len > best.len)
|
|
best = cur;
|
|
}
|
|
|
|
if (best.base != -1 && best.len < 2)
|
|
best.base = -1;
|
|
|
|
ptr = dst;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
/* Are we inside the best run of 0x00's? */
|
|
|
|
if (best.base != -1 && i >= best.base && i < (best.base + best.len))
|
|
{
|
|
// Just output one : for whole string of zeros
|
|
|
|
*ptr++ = ':';
|
|
i = best.base + best.len - 1; // skip rest of zeros
|
|
continue;
|
|
}
|
|
|
|
/* Are we following an initial run of 0x00s or any real hex? */
|
|
|
|
if (i != 0)
|
|
*ptr++ = ':';
|
|
|
|
ptr += sprintf (ptr, "%x", words[i]);
|
|
|
|
// Was it a trailing run of 0x00's?
|
|
}
|
|
|
|
if (best.base != -1 && (best.base + best.len) == 8)
|
|
*ptr++ = ':';
|
|
|
|
*ptr++ = '\0';
|
|
}
|
|
|
|
BOOL TelSendPacket(int Stream, struct STREAMINFO * STREAM, PMSGWITHLEN buffptr, struct ADIF * ADIF)
|
|
{
|
|
int datalen;
|
|
UCHAR * MsgPtr;
|
|
SOCKET sock;
|
|
struct ConnectionInfo * sockptr = STREAM->ConnectionInfo;
|
|
|
|
datalen = (int)buffptr->Len;
|
|
MsgPtr = &buffptr->Data[0];
|
|
|
|
STREAM->bytesTXed += datalen;
|
|
|
|
sock = sockptr->socket;
|
|
|
|
if (sockptr->UserPointer == &CMSUser)
|
|
{
|
|
WritetoTrace(Stream, MsgPtr, datalen, ADIF, 'S');
|
|
}
|
|
|
|
if (sockptr->UTF8)
|
|
{
|
|
// Convert any non-utf8 chars
|
|
|
|
if (IsUTF8(MsgPtr, datalen) == FALSE)
|
|
{
|
|
unsigned char UTF[1024];
|
|
int u, code;
|
|
|
|
// Try to guess encoding
|
|
|
|
code = TrytoGuessCode(MsgPtr, datalen);
|
|
|
|
if (code == 437)
|
|
u = Convert437toUTF8(MsgPtr, datalen, UTF);
|
|
else if (code == 1251)
|
|
u = Convert1251toUTF8(MsgPtr, datalen, UTF);
|
|
else
|
|
u = Convert1252toUTF8(MsgPtr, datalen, UTF);
|
|
|
|
SendAndCheck(sockptr, UTF, u, 0);
|
|
ReleaseBuffer(buffptr);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if (sockptr->FBBMode && sockptr->NeedLF == FALSE)
|
|
{
|
|
/*
|
|
// if Outward Connect to FBB, Replace ff with ffff
|
|
|
|
if (0) // if we use this need to fix retry
|
|
{
|
|
char * ptr2, * ptr = &MsgPtr[0];
|
|
int i;
|
|
do
|
|
{
|
|
ptr2 = memchr(ptr, 255, datalen);
|
|
|
|
if (ptr2 == 0)
|
|
{
|
|
// no ff, so just send as is
|
|
|
|
xxxsend(sock, ptr, datalen, 0);
|
|
i=0;
|
|
break;
|
|
}
|
|
|
|
i=ptr2+1-ptr;
|
|
|
|
xxsend(sock,ptr,i,0);
|
|
xxsend(sock,"\xff",1,0);
|
|
|
|
datalen-=i;
|
|
ptr=ptr2+1;
|
|
}
|
|
while (datalen>0);
|
|
}
|
|
*/
|
|
// Normal FBB Mode path
|
|
|
|
BOOL ret = SendAndCheck(sockptr, MsgPtr, datalen, 0);
|
|
ReleaseBuffer(buffptr);
|
|
return ret;
|
|
}
|
|
|
|
// Not FBB mode, or FBB and NEEDLF Replace cr with crlf
|
|
|
|
{
|
|
unsigned char Out[1024];
|
|
unsigned char c;
|
|
unsigned char * ptr2 = Out;
|
|
unsigned char * ptr = &MsgPtr[0];
|
|
|
|
while (datalen--)
|
|
{
|
|
c = (*ptr++);
|
|
|
|
if (c == 13)
|
|
{
|
|
*(ptr2++) = 13;
|
|
*(ptr2++) = 10;
|
|
}
|
|
else
|
|
*(ptr2++) = c;
|
|
}
|
|
|
|
ReleaseBuffer(buffptr);
|
|
return SendAndCheck(sockptr, Out, (int)(ptr2 - Out), 0);
|
|
}
|
|
}
|
|
|
|
VOID ProcessTrimodeCommand(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, char * MsgPtr)
|
|
{
|
|
struct STREAMINFO * STREAM = &TNC->Streams[sockptr->Number];
|
|
int Port = 4;
|
|
|
|
Debugprintf(MsgPtr);
|
|
|
|
if (strcmp(MsgPtr, "CLOSE") == 0)
|
|
{
|
|
if (STREAM->Connected)
|
|
{
|
|
STREAM->ReportDISC = TRUE;
|
|
}
|
|
}
|
|
|
|
// MYCALLSIGN XE2BNC
|
|
else
|
|
if (memcmp(MsgPtr, "MYCALLSIGN", 10) == 0)
|
|
{
|
|
char * call = &MsgPtr[11];
|
|
|
|
if (strlen(call) > 9)
|
|
call[9] = 0;
|
|
|
|
memcpy(STREAM->MyCall, call, 10);
|
|
|
|
ConvToAX25(call, &TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->L4USER[0]);
|
|
|
|
strcpy(&TNCInfo[Port]->Streams[0].MyCall[0], call);
|
|
}
|
|
|
|
|
|
// TARGETCALLSIGN KE7XO
|
|
else
|
|
if (memcmp(MsgPtr, "TARGETCALLSIGN", 14) == 0)
|
|
{
|
|
char * call = &MsgPtr[15];
|
|
|
|
if (strlen(call) > 9)
|
|
call[9] = 0;
|
|
|
|
memcpy(STREAM->RemoteCall, call, 10);
|
|
}
|
|
// INITIATECALL 50
|
|
else
|
|
if (memcmp(MsgPtr, "INITIATECALL", 12) == 0)
|
|
{
|
|
char Cmd[80];
|
|
int n;
|
|
|
|
n = sprintf(Cmd,"C %s\r", STREAM->RemoteCall);
|
|
|
|
SendtoNode(TNC, sockptr->Number, Cmd, n);
|
|
}
|
|
|
|
|
|
// CHANNEL 3586500,None,None
|
|
else
|
|
if (memcmp(MsgPtr, "CHANNEL", 7) == 0)
|
|
{
|
|
double Freq = atof(&MsgPtr[8]);
|
|
char Radiocmd[80];
|
|
int n;
|
|
|
|
strcpy(sockptr->Callsign, "G8BPQ");
|
|
|
|
n = sprintf(Radiocmd,"RADIO %f %s\r", Freq/1000000, "USB");
|
|
|
|
SendtoNode(TNC, sockptr->Number, Radiocmd, n);
|
|
}
|
|
|
|
else
|
|
if (memcmp(MsgPtr, "PROTOCOL", 8) == 0)
|
|
{
|
|
// Attach the relevant port
|
|
|
|
SendtoNode(TNC, sockptr->Number, "ATTACH 4\r", 9);
|
|
}
|
|
|
|
else
|
|
if (strcmp(MsgPtr, "BUSY") == 0)
|
|
send(sockptr->socket, "BUSY False\r\n", 12,0);
|
|
|
|
|
|
send(sockptr->socket, "CMD\r\n", 5,0);
|
|
|
|
// SendtoNode(TNC, sockptr->Number, NodeLine, len);
|
|
}
|
|
|
|
|
|
VOID ProcessTrimodeResponse(struct TNCINFO * TNC, struct STREAMINFO * STREAM, unsigned char * MsgPtr, int Msglen)
|
|
{
|
|
MsgPtr[Msglen] = 0;
|
|
|
|
if (STREAM->ConnectionInfo->TriModeConnected)
|
|
{
|
|
// Send over the Data Socket
|
|
|
|
send(STREAM->ConnectionInfo->TriModeDataSock, MsgPtr, Msglen, 0);
|
|
|
|
return;
|
|
}
|
|
|
|
strlop(MsgPtr, 13);
|
|
Debugprintf(MsgPtr);
|
|
|
|
if (memcmp(MsgPtr, "*** Connected to ", 17) == 0)
|
|
{
|
|
char Cmd[80];
|
|
int n;
|
|
|
|
n = sprintf(Cmd,"CONNECTED %s\r", &MsgPtr[17]);
|
|
|
|
STREAM->ConnectionInfo->TriModeConnected = TRUE;
|
|
|
|
send(STREAM->ConnectionInfo->socket, Cmd, n, 0);
|
|
}
|
|
}
|
|
|
|
VOID ProcessTriModeDataMessage(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM)
|
|
{
|
|
int len=0;
|
|
char NLMsg[3]={13,10,0};
|
|
char RelayMsg[] = "No CMS connection available - using local BPQMail\r";
|
|
struct TCPINFO * TCP = TNC->TCPInfo;
|
|
unsigned char Buffer[256];
|
|
|
|
ioctl(sock,FIONREAD,&len);
|
|
|
|
if (len > 256) len = 256;
|
|
|
|
len = recv(sock, Buffer, len, 0);
|
|
|
|
if (len == SOCKET_ERROR || len ==0)
|
|
{
|
|
// Failed or closed - clear connection
|
|
|
|
closesocket(sock);
|
|
return;
|
|
}
|
|
|
|
SendtoNode(TNC, sockptr->Number, Buffer, len);
|
|
}
|
|
|
|
extern struct DATAMESSAGE * REPLYBUFFER;
|
|
char * __cdecl Cmdprintf(TRANSPORTENTRY * Session, char * Bufferptr, const char * format, ...);
|
|
|
|
|
|
VOID RECONFIGTELNET (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD)
|
|
{
|
|
int Port = 0, index =0;
|
|
char * ptr, *Context;
|
|
struct PORTCONTROL * PORT = NULL;
|
|
struct TNCINFO * TNC;
|
|
char * ptr1, * ptr2;
|
|
char buf[256],errbuf[256];
|
|
char * Config;
|
|
struct TCPINFO * TCP;
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
if (ptr)
|
|
Port = atoi(ptr);
|
|
|
|
if (Port)
|
|
PORT = GetPortTableEntryFromPortNum(Port);
|
|
|
|
if (PORT == NULL)
|
|
{
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r");
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
return;
|
|
}
|
|
|
|
TNC = TNCInfo[Port];
|
|
|
|
if (TNC == NULL || TNC->Hardware != H_TELNET)
|
|
{
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet port\r");
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
return;
|
|
}
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
if (ptr && _stricmp(ptr, "ALL") == 0)
|
|
{
|
|
// Use EXTRESTART Code
|
|
|
|
PEXTPORTDATA PORTVEC = (PEXTPORTDATA) PORT;
|
|
PORTVEC->EXTRESTART = 1;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Reconfig Telnet Ok\r");
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
return;
|
|
}
|
|
|
|
if (ptr && _stricmp(ptr, "USERS") == 0)
|
|
{
|
|
// Reconfig Users
|
|
|
|
if (!ProcessConfig())
|
|
{
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Failed to reread config file - leaving config unchanged\r");
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
return;
|
|
}
|
|
|
|
Config = PortConfig[Port];
|
|
|
|
if (Config == NULL)
|
|
{
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "No Config Entries found\r");
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
return;
|
|
}
|
|
|
|
// Don't free old user records - sessions may have pointers to them
|
|
|
|
// Free the header
|
|
|
|
if (TCP->UserRecPtr)
|
|
{
|
|
free(TCP->UserRecPtr);
|
|
TCP->UserRecPtr = NULL;
|
|
}
|
|
|
|
TCP->NumberofUsers = 0;
|
|
|
|
// Look for USER lines
|
|
|
|
ptr1 = Config;
|
|
ptr2 = strchr(ptr1, 13);
|
|
|
|
while(ptr2)
|
|
{
|
|
memcpy(buf, ptr1, ptr2 - ptr1 + 1);
|
|
buf[ptr2 - ptr1 + 1] = 0;
|
|
ptr1 = ptr2 + 2;
|
|
ptr2 = strchr(ptr1, 13);
|
|
strcpy(errbuf,buf); // save in case of erro
|
|
|
|
if (_memicmp(buf, "USER=", 5) == 0 || _memicmp(buf, "USER ", 5) == 0)
|
|
{
|
|
char *User, *Pwd, *UserCall, *Secure, * Appl;
|
|
int End = (int)strlen(buf) -1;
|
|
struct UserRec * USER;
|
|
char Param[8][256];
|
|
char * ptr1, * ptr2;
|
|
int n = 0;
|
|
char * value = &buf[5];
|
|
|
|
// USER=user,password,call,appl,SYSOP
|
|
|
|
memset(Param, 0, 2048);
|
|
strlop(value, 13);
|
|
strlop(value, ';');
|
|
|
|
ptr1 = value;
|
|
|
|
while (ptr1 && *ptr1 && n < 8)
|
|
{
|
|
ptr2 = strchr(ptr1, ',');
|
|
if (ptr2) *ptr2++ = 0;
|
|
|
|
strcpy(&Param[n][0], ptr1);
|
|
strlop(Param[n++], ' ');
|
|
ptr1 = ptr2;
|
|
while(ptr1 && *ptr1 && *ptr1 == ' ')
|
|
ptr1++;
|
|
}
|
|
|
|
|
|
User = &Param[0][0];
|
|
|
|
if (_stricmp(User, "ANON") == 0)
|
|
{
|
|
strcpy(&Param[2][0], "ANON");
|
|
strcpy(&Param[4][0], ""); // Dont allow SYSOP if ANON
|
|
}
|
|
|
|
Pwd = &Param[1][0];
|
|
UserCall = &Param[2][0];
|
|
Appl = &Param[3][0];
|
|
Secure = &Param[4][0];
|
|
|
|
if (User[0] == 0 || Pwd[0] == 0 || UserCall[0] == 0) // invalid record
|
|
{
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Bad USER Record %s\r", errbuf);
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
return;
|
|
}
|
|
|
|
_strupr(UserCall);
|
|
|
|
if (TCP->NumberofUsers == 0)
|
|
TCP->UserRecPtr = malloc(sizeof(void *));
|
|
else
|
|
TCP->UserRecPtr = realloc(TCP->UserRecPtr, (TCP->NumberofUsers+1) * sizeof(void *));
|
|
|
|
USER = zalloc(sizeof(struct UserRec));
|
|
|
|
TCP->UserRecPtr[TCP->NumberofUsers] = USER;
|
|
|
|
USER->Callsign = _strdup(UserCall);
|
|
USER->Password = _strdup(Pwd);
|
|
USER->UserName = _strdup(User);
|
|
USER->Appl = zalloc(32);
|
|
USER->Secure = FALSE;
|
|
|
|
if (_stricmp(Secure, "SYSOP") == 0)
|
|
USER->Secure = TRUE;
|
|
|
|
if (Appl[0] && strcmp(Appl, "\"\"") != 0)
|
|
{
|
|
strcpy(USER->Appl, _strupr(Appl));
|
|
strcat(USER->Appl, "\r\n");
|
|
}
|
|
TCP->NumberofUsers++;
|
|
}
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Reread Telnet Users Ok - %d USER Records\r", TCP->NumberofUsers);
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
return;
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid parameter - use either USERS or ALL \r");
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
}
|
|
|
|
VOID SHOWTELNET(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD)
|
|
{
|
|
// DISPLAY Telnet Server Status Mheard
|
|
|
|
int Port = 0, index =0;
|
|
char * ptr, *Context;
|
|
struct PORTCONTROL * PORT = NULL;
|
|
int txlen = 0, n;
|
|
struct TNCINFO * TNC;
|
|
char msg[80];
|
|
struct ConnectionInfo * sockptr;
|
|
int i;
|
|
char CMS[] = "CMS Disabled";
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
if (ptr)
|
|
Port = atoi(ptr);
|
|
|
|
if (Port)
|
|
PORT = GetPortTableEntryFromPortNum(Port);
|
|
|
|
if (PORT == NULL)
|
|
{
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r");
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
return;
|
|
}
|
|
|
|
TNC = TNCInfo[Port];
|
|
|
|
if (TNC == NULL || TNC->Hardware != H_TELNET)
|
|
{
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet port\r");
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
return;
|
|
}
|
|
|
|
if (TNC->TCPInfo->CMS)
|
|
if (TNC->TCPInfo->CMSOK)
|
|
strcpy(CMS, "CMS Ok");
|
|
else
|
|
strcpy(CMS, "No CMS");
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Telnet Status for Port %d %s\r", Port, CMS);
|
|
|
|
for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++)
|
|
{
|
|
sockptr=TNC->Streams[n].ConnectionInfo;
|
|
|
|
if (!sockptr->SocketActive)
|
|
{
|
|
strcpy(msg,"Idle");
|
|
}
|
|
else
|
|
{
|
|
if (sockptr->UserPointer == 0)
|
|
{
|
|
if (sockptr->HTTPMode)
|
|
{
|
|
char Addr[100];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
|
|
if (sockptr->WebSocks)
|
|
sprintf(msg, "Websock From %s", Addr);
|
|
else
|
|
sprintf(msg, "HTTP From %s", Addr);
|
|
|
|
}
|
|
else if (sockptr->DRATSMode)
|
|
{
|
|
char Addr[100];
|
|
Tel_Format_Addr(sockptr, Addr);
|
|
sprintf(msg, "DRATS From %s", Addr);
|
|
}
|
|
else
|
|
strcpy(msg,"Logging in");
|
|
}
|
|
else
|
|
{
|
|
i=sprintf(msg,"%-10s %-10s %2d",
|
|
sockptr->UserPointer->UserName,sockptr->Callsign,sockptr->BPQStream);
|
|
}
|
|
}
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s\r", msg);
|
|
}
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
}
|
|
|
|
|
|
// Refresh any Web Socket Webmail index display
|
|
// Called whenever message database is changed
|
|
|
|
#ifdef LINBPQ
|
|
|
|
int DoRefreshWebMailIndex();
|
|
|
|
int RefreshWebMailIndex()
|
|
{
|
|
DoRefreshWebMailIndex();
|
|
return 0;
|
|
}
|
|
|
|
#else
|
|
|
|
// Have to pass request from BPQMail to DLL as socket can only be accessed in calling process
|
|
// Pass request back to WebMail via pipe
|
|
|
|
// Code must run in bpq32 process, so set flag here and call code from Timer Routine
|
|
|
|
extern BOOL NeedWebMailRefresh;
|
|
|
|
|
|
DllExport int APIENTRY RefreshWebMailIndex()
|
|
{
|
|
NeedWebMailRefresh = 1;
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
int DoRefreshWebMailIndex()
|
|
{
|
|
// Loop through all sockets and pick out WebMail Index Connections
|
|
|
|
int i, n;
|
|
struct ConnectionInfo * sockptr;
|
|
struct ConnectionInfo * sockcopy;
|
|
struct TNCINFO * TNC;
|
|
struct TCPINFO * TCP;
|
|
|
|
#ifndef LINBPQ
|
|
NeedWebMailRefresh = 0;
|
|
#endif
|
|
|
|
for (i = 0; i < 33; i++)
|
|
{
|
|
TNC = TNCInfo[i];
|
|
|
|
if (TNC && TNC->Hardware == H_TELNET)
|
|
{
|
|
TCP = TNC->TCPInfo;
|
|
|
|
if (TCP)
|
|
{
|
|
for (n = 0; n <= TCP->MaxSessions; n++)
|
|
{
|
|
sockptr = TNC->Streams[n].ConnectionInfo;
|
|
|
|
if (sockptr->SocketActive)
|
|
{
|
|
if (sockptr->HTTPMode && sockptr->WebSocks && memcmp(sockptr->WebURL, "WMRefresh", 9) == 0)
|
|
{
|
|
sockcopy = malloc(sizeof(struct ConnectionInfo));
|
|
sockptr->TNC = TNC;
|
|
sockptr->LastSendTime = REALTIMETICKS;
|
|
|
|
memcpy(sockcopy, sockptr, sizeof(struct ConnectionInfo));
|
|
|
|
_beginthread(ProcessWebmailWebSockThread, 2048000, (VOID *)sockcopy); // Needs big stack
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|