2022-08-28 09:35:46 +01:00
|
|
|
/*
|
2022-11-14 14:02:28 +00:00
|
|
|
Copyright 2001-2022 John Wiseman G8BPQ
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
*/
|
|
|
|
|
|
|
|
//
|
|
|
|
// C replacement for cmd.asm
|
|
|
|
//
|
|
|
|
#define Kernel
|
|
|
|
|
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
#pragma data_seg("_BPQDATA")
|
|
|
|
|
|
|
|
//#include "windows.h"
|
|
|
|
//#include "winerror.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "time.h"
|
|
|
|
#include "stdio.h"
|
|
|
|
#include <fcntl.h>
|
|
|
|
//#include "vmm.h"
|
|
|
|
//#include "SHELLAPI.H"
|
|
|
|
|
|
|
|
#include "CHeaders.h"
|
|
|
|
#include "bpqaprs.h"
|
2023-06-29 18:13:31 +01:00
|
|
|
#include "kiss.h"
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
#pragma pack()
|
|
|
|
|
|
|
|
#include "tncinfo.h"
|
|
|
|
#include "telnetserver.h"
|
|
|
|
|
|
|
|
//#include "GetVersion.h"
|
|
|
|
|
|
|
|
//#define DllImport __declspec( dllimport )
|
|
|
|
//#define DllExport __declspec( dllexport )
|
|
|
|
|
|
|
|
BOOL DecodeCallString(char * Calls, BOOL * Stay, BOOL * Spy, UCHAR *AXCalls);
|
|
|
|
VOID Send_AX_Datagram(PDIGIMESSAGE Block, DWORD Len, UCHAR Port);
|
|
|
|
int APIENTRY ClearNodes();
|
|
|
|
VOID GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value);
|
|
|
|
VOID SendHTTPRequest(SOCKET sock, char * Host, int Port, char * Request, char * Params, int Len, char * Return);
|
|
|
|
SOCKET OpenWL2KHTTPSock();
|
|
|
|
VOID FormatTime3(char * Time, time_t cTime);
|
|
|
|
VOID Format_Addr(unsigned char * Addr, char * Output, BOOL IPV6);
|
|
|
|
VOID Tel_Format_Addr(struct ConnectionInfo * sockptr, char * dst);
|
|
|
|
VOID FindLostBuffers();
|
|
|
|
BOOL CheckCMS(struct TNCINFO * TNC);
|
|
|
|
VOID L2SENDXID(struct _LINKTABLE * LINK);
|
|
|
|
int CountBits(unsigned long in);
|
|
|
|
VOID SaveMH();
|
|
|
|
BOOL RestartTNC(struct TNCINFO * TNC);
|
|
|
|
void GetPortCTEXT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID WriteMiniDump();
|
|
|
|
|
|
|
|
char COMMANDBUFFER[81] = ""; // Command Hander input buffer
|
2023-05-25 14:17:53 +01:00
|
|
|
char OrigCmdBuffer[81] = ""; // Command Hander input buffer before toupper
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
struct DATAMESSAGE * REPLYBUFFER = NULL;
|
|
|
|
UINT APPLMASK = 0;
|
|
|
|
UCHAR SAVEDAPPLFLAGS = 0;
|
|
|
|
|
|
|
|
UCHAR ALIASINVOKED = 0;
|
|
|
|
|
|
|
|
|
|
|
|
VOID * CMDPTR = 0;
|
|
|
|
|
|
|
|
short CMDPACLEN = 0;
|
|
|
|
|
|
|
|
char OKMSG[] = "Ok\r";
|
|
|
|
|
|
|
|
char CMDERRMSG[] = "Invalid command - Enter ? for command list\r";
|
|
|
|
#define CMDERRLEN sizeof(CMDERRMSG) - 1
|
|
|
|
|
|
|
|
char PASSWORDMSG[] = "Command requires SYSOP status - enter password\r";
|
|
|
|
#define LPASSMSG sizeof(PASSWORDMSG) - 1
|
|
|
|
|
|
|
|
char CMDLIST[] = "CONNECT BYE INFO NODES PORTS ROUTES USERS MHEARD";
|
|
|
|
|
|
|
|
#define CMDLISTLEN sizeof(CMDLIST) - 1
|
|
|
|
|
|
|
|
char BADMSG[] = "Bad Parameter\r";
|
|
|
|
char BADPORT[] = "Invalid Port Number\r";
|
|
|
|
char NOTEXTPORT[] = "Only valid on EXT ports\r";
|
|
|
|
char NOVALCALLS[] = "No Valid Calls defined on this port\r";
|
|
|
|
|
|
|
|
char BADVALUEMSG[] = "Invalid parameter\r";
|
|
|
|
|
|
|
|
char BADCONFIGMSG[] = "Configuration File check falled - will continue with old config\r";
|
|
|
|
#ifdef LINBPQ
|
|
|
|
char REBOOTOK[] = "Rebooting\r";
|
|
|
|
#else
|
|
|
|
char REBOOTOK[] = "Rebooting in 20 secs\r";
|
|
|
|
#endif
|
|
|
|
char REBOOTFAILED[] = "Shutdown failed\r";
|
|
|
|
|
|
|
|
char RESTARTOK[] = "Restarting\r";
|
|
|
|
char RESTARTFAILED[] = "Restart failed\r";
|
|
|
|
|
|
|
|
UCHAR ARDOP[7] = {'A'+'A','R'+'R','D'+'D','O'+'O','P'+'P',' '+' '}; // ARDOP IN AX25
|
|
|
|
UCHAR VARA[7] = {'V'+'V','A'+'A','R'+'R','A'+'A',' '+' ',' '+' '}; // VARA IN AX25
|
|
|
|
|
|
|
|
int STATSTIME = 0;
|
|
|
|
int MAXBUFFS = 0;
|
|
|
|
int QCOUNT = 0;
|
|
|
|
int MINBUFFCOUNT = 65535;
|
|
|
|
int NOBUFFCOUNT = 0;
|
|
|
|
int BUFFERWAITS = 0;
|
|
|
|
int MAXDESTS = 0;
|
|
|
|
int NUMBEROFNODES = 0;
|
|
|
|
int L4CONNECTSOUT = 0;
|
|
|
|
int L4CONNECTSIN = 0;
|
|
|
|
int L4FRAMESTX = 0;
|
|
|
|
int L4FRAMESRX = 0;
|
|
|
|
int L4FRAMESRETRIED = 0;
|
|
|
|
int OLDFRAMES = 0;
|
|
|
|
int L3FRAMES = 0;
|
|
|
|
|
|
|
|
VOID SENDSABM();
|
|
|
|
VOID RESET2();
|
|
|
|
|
|
|
|
int APPL1 = 0;
|
|
|
|
int PASSCMD = 0;
|
|
|
|
|
|
|
|
#pragma pack(1)
|
|
|
|
|
|
|
|
struct _EXTPORTDATA DP; // Only way I can think of to get offets to port data into cmd table
|
|
|
|
|
|
|
|
char CMDALIAS[ALIASLEN][NumberofAppls] = {0};
|
|
|
|
char * ALIASPTR = &CMDALIAS[0][0];
|
|
|
|
|
|
|
|
extern int RigReconfigFlag;
|
|
|
|
|
|
|
|
CMDX COMMANDS[];
|
|
|
|
|
|
|
|
int CMDXLEN = sizeof (CMDX);
|
|
|
|
|
|
|
|
VOID SENDNODESMSG();
|
|
|
|
VOID KISSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID STOPCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID STARTCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID STOPPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID STARTPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID FINDBUFFS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID WL2KSYSOP(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID AXRESOLVER(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID AXMHEARD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID SHOWTELNET(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID SHOWAGW(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID SHOWARP(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID SHOWNAT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID PING(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID SHOWIPROUTE(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID FLMSG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD);
|
|
|
|
void ListExcludedCalls(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID APRSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
VOID RECONFIGTELNET (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
2022-11-23 10:56:20 +00:00
|
|
|
VOID HELPCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
2023-05-16 16:40:12 +01:00
|
|
|
VOID UZ7HOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD);
|
|
|
|
|
2022-11-23 10:56:20 +00:00
|
|
|
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
char * __cdecl Cmdprintf(TRANSPORTENTRY * Session, char * Bufferptr, const char * format, ...)
|
|
|
|
{
|
|
|
|
// Send Command response checking PACLEN
|
|
|
|
|
|
|
|
char Mess[4096];
|
|
|
|
va_list(arglist);
|
|
|
|
int OldLen;
|
|
|
|
int MsgLen;
|
|
|
|
struct DATAMESSAGE * Buffer;
|
|
|
|
char * Messptr = Mess;
|
|
|
|
int Paclen = Session->SESSPACLEN;
|
|
|
|
|
|
|
|
if (Paclen == 0)
|
|
|
|
Paclen = 255;
|
|
|
|
|
|
|
|
va_start(arglist, format);
|
|
|
|
|
|
|
|
MsgLen = vsprintf(Mess, format, arglist);
|
|
|
|
|
|
|
|
OldLen = (int)(Bufferptr - (char *)REPLYBUFFER->L2DATA);
|
|
|
|
|
|
|
|
while ((OldLen + MsgLen) > Paclen)
|
|
|
|
{
|
|
|
|
// Have to send Paclen then get a new buffer
|
|
|
|
|
|
|
|
int ThisBit = Paclen - OldLen; // What we can send this time
|
|
|
|
|
|
|
|
if (ThisBit < 0)
|
|
|
|
ThisBit = 0; // How can this happen??
|
|
|
|
|
|
|
|
memcpy(Bufferptr, Messptr, ThisBit);
|
|
|
|
Messptr += ThisBit;
|
|
|
|
MsgLen -= ThisBit;
|
|
|
|
|
|
|
|
// QUEUE IT AND GET ANOTHER BUFFER
|
|
|
|
|
|
|
|
Buffer = (struct DATAMESSAGE *)GetBuff();
|
|
|
|
|
|
|
|
if (Buffer == NULL)
|
|
|
|
|
|
|
|
// No buffers, so just reuse the old one (better than crashing !!)
|
|
|
|
|
|
|
|
Buffer = REPLYBUFFER;
|
|
|
|
else
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, Paclen + (4 + sizeof(void *)));
|
|
|
|
|
|
|
|
|
|
|
|
REPLYBUFFER = Buffer;
|
|
|
|
Buffer->PID = 0xf0;
|
|
|
|
|
|
|
|
Bufferptr = &Buffer->L2DATA[0];
|
|
|
|
OldLen = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add last bit to buffer
|
|
|
|
|
|
|
|
memcpy(Bufferptr, Messptr, MsgLen);
|
|
|
|
|
|
|
|
return Bufferptr + MsgLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID SENDNODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
SENDNODESMSG();
|
|
|
|
|
|
|
|
strcpy(Bufferptr, OKMSG);
|
|
|
|
Bufferptr += (int)strlen(OKMSG);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID SAVEMHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
SaveMH();
|
|
|
|
|
|
|
|
strcpy(Bufferptr, OKMSG);
|
|
|
|
Bufferptr += (int)strlen(OKMSG);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID SAVENODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
SaveNodes();
|
|
|
|
|
|
|
|
strcpy(Bufferptr, OKMSG);
|
|
|
|
Bufferptr += (int)strlen(OKMSG);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID DUMPCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
WriteMiniDump();
|
|
|
|
|
|
|
|
strcpy(Bufferptr, OKMSG);
|
|
|
|
Bufferptr += (int)strlen(OKMSG);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID RIGRECONFIG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
if (!ProcessConfig())
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Configuration File check falled - will continue with old config");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RigReconfigFlag = TRUE;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Rigcontrol Reconfig requested");
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID REBOOT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
if (Reboot())
|
|
|
|
{
|
|
|
|
strcpy(Bufferptr, REBOOTOK);
|
|
|
|
Bufferptr += (int)strlen(REBOOTOK);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(Bufferptr, REBOOTFAILED);
|
|
|
|
Bufferptr += (int)strlen(REBOOTFAILED);
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID RESTART(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
if (Restart())
|
|
|
|
{
|
|
|
|
strcpy(Bufferptr, RESTARTOK);
|
|
|
|
Bufferptr += (int)strlen(RESTARTOK);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
strcpy(Bufferptr, RESTARTFAILED);
|
|
|
|
Bufferptr += (int)strlen(RESTARTFAILED);
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID RESTARTTNC(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char * ptr, *Context;
|
|
|
|
int portno;
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
portno = atoi (ptr);
|
|
|
|
|
|
|
|
if (portno && portno < 33)
|
|
|
|
{
|
|
|
|
struct TNCINFO * TNC = TNCInfo[portno];
|
|
|
|
|
|
|
|
if (TNC == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (TNC->ProgramPath)
|
|
|
|
{
|
|
|
|
if (RestartTNC(TNC))
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Restart %s Ok\r", TNC->ProgramPath);
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Restart %s Failed\r", TNC->ProgramPath);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "PATH not defined so can't restart TNC\r");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
UCHAR VALNODESFLAG = 0, EXTONLY = 0;
|
|
|
|
|
|
|
|
VOID PORTVAL (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
|
|
|
|
|
|
|
|
VOID VALNODES(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
VALNODESFLAG = 1;
|
|
|
|
PORTVAL(Session, Bufferptr, CmdTail, CMD);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID EXTPORTVAL(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
EXTONLY = 1;
|
|
|
|
PORTVAL(Session, Bufferptr, CmdTail, CMD);
|
|
|
|
}
|
|
|
|
VOID PORTVAL(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// PROCESS PORT VALUE COMMANDS
|
|
|
|
|
|
|
|
char * ptr, *Context, * ptr1;
|
|
|
|
int portno;
|
|
|
|
UCHAR oldvalue, newvalue;
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
int n = NUMBEROFPORTS;
|
|
|
|
UCHAR * valueptr;
|
|
|
|
|
|
|
|
// Get port number
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
portno = atoi (ptr);
|
|
|
|
|
|
|
|
if (portno)
|
|
|
|
{
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (PORT->PORTNUMBER == portno)
|
|
|
|
{
|
|
|
|
if (VALNODESFLAG)
|
|
|
|
{
|
|
|
|
char * VNPtr = PORT->PERMITTEDCALLS;
|
|
|
|
char Normcall[10];
|
|
|
|
|
|
|
|
VALNODESFLAG = 0;
|
|
|
|
|
|
|
|
if (VNPtr)
|
|
|
|
{
|
|
|
|
while (VNPtr[0])
|
|
|
|
{
|
|
|
|
Normcall[ConvFromAX25(VNPtr, Normcall)] = 0;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s ", Normcall);
|
|
|
|
VNPtr += 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", NOVALCALLS);
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EXTONLY)
|
|
|
|
{
|
|
|
|
// Make sure an Extenal Port
|
|
|
|
|
|
|
|
EXTONLY = 0;
|
|
|
|
|
|
|
|
if (PORT->PORTTYPE != 0x10)
|
|
|
|
{
|
|
|
|
strcpy(Bufferptr, NOTEXTPORT);
|
|
|
|
Bufferptr += (int)strlen(NOTEXTPORT);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
valueptr = (UCHAR *)PORT + CMD->CMDFLAG;
|
|
|
|
oldvalue = *valueptr;
|
|
|
|
|
|
|
|
// Display Param Namee
|
|
|
|
|
|
|
|
ptr1 = &CMD->String[0];
|
|
|
|
n = 12;
|
|
|
|
|
|
|
|
while (*(ptr1) != ' ' && n--)
|
|
|
|
*(Bufferptr++) = *(ptr1++);
|
|
|
|
|
|
|
|
// See if another param - if not, just display current value
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && ptr[0])
|
|
|
|
{
|
|
|
|
// Get new value
|
|
|
|
|
|
|
|
newvalue = atoi(ptr);
|
|
|
|
*valueptr = newvalue;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " was %d now %d\r", oldvalue, newvalue);
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " %d\r", oldvalue);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bad port
|
|
|
|
|
|
|
|
strcpy(Bufferptr, BADPORT);
|
|
|
|
Bufferptr += (int)strlen(BADPORT);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID SWITCHVAL (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// Update switch 8 bit value
|
|
|
|
|
|
|
|
char * ptr, *Context, * ptr1;
|
|
|
|
UCHAR oldvalue, newvalue;
|
|
|
|
int n;
|
|
|
|
UCHAR * valueptr;
|
|
|
|
|
|
|
|
valueptr = (UCHAR *)CMD->CMDFLAG;
|
|
|
|
|
|
|
|
oldvalue = *valueptr;
|
|
|
|
|
|
|
|
// Display Param Name
|
|
|
|
|
|
|
|
ptr1 = &CMD->String[0];
|
|
|
|
n = 12;
|
|
|
|
|
|
|
|
while (*(ptr1) != ' ' && n--)
|
|
|
|
*(Bufferptr++) = *(ptr1++);
|
|
|
|
|
|
|
|
// See if a param - if not, just display current value
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && ptr[0])
|
|
|
|
{
|
|
|
|
// Get new value
|
|
|
|
|
|
|
|
newvalue = atoi(ptr);
|
|
|
|
*valueptr = newvalue;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " was %d now %d\r", oldvalue, newvalue);
|
|
|
|
|
|
|
|
if (memcmp(CMD->String, "NODESINT ", 8) == 0)
|
|
|
|
L3TIMER = L3INTERVAL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " %d\r", oldvalue);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID SWITCHVALW (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// Update switch 16 bit value
|
|
|
|
|
|
|
|
char * ptr, *Context, * ptr1;
|
|
|
|
USHORT oldvalue, newvalue;
|
|
|
|
int n;
|
|
|
|
USHORT * valueptr;
|
|
|
|
|
|
|
|
valueptr = (USHORT *)CMD->CMDFLAG;
|
|
|
|
|
|
|
|
oldvalue = (USHORT)*valueptr;
|
|
|
|
|
|
|
|
// Display Param Name
|
|
|
|
|
|
|
|
ptr1 = &CMD->String[0];
|
|
|
|
n = 12;
|
|
|
|
|
|
|
|
while (*(ptr1) != ' ' && n--)
|
|
|
|
*(Bufferptr++) = *(ptr1++);
|
|
|
|
|
|
|
|
// See if a param - if not, just display current value
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && ptr[0])
|
|
|
|
{
|
|
|
|
// Get new value
|
|
|
|
|
|
|
|
newvalue = atoi(ptr);
|
|
|
|
*valueptr = newvalue;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " was %d now %d\r", oldvalue, newvalue);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " %d\r", oldvalue);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
TRANSPORTENTRY * SetupSessionFromSession(TRANSPORTENTRY * Session, PBPQVECSTRUC HOSTSESS, UINT APPLMASK)
|
|
|
|
{
|
|
|
|
// Create a Transport (L4) session linked to an incoming Session
|
|
|
|
|
|
|
|
TRANSPORTENTRY * NewSess = L4TABLE;
|
|
|
|
int Index = 0;
|
|
|
|
|
|
|
|
while (Index < MAXCIRCUITS)
|
|
|
|
{
|
|
|
|
if (NewSess->L4USER[0] == 0)
|
|
|
|
{
|
|
|
|
// Got One
|
|
|
|
|
|
|
|
UCHAR * ourcall = &MYCALL[0];
|
|
|
|
|
|
|
|
Session->L4CROSSLINK = NewSess;
|
|
|
|
NewSess->L4CROSSLINK = Session;
|
|
|
|
|
|
|
|
if (APPLMASK)
|
|
|
|
{
|
|
|
|
// Circuit for APPL - look for an APPLCALL
|
|
|
|
|
|
|
|
APPLCALLS * APPL = APPLCALLTABLE;
|
|
|
|
|
|
|
|
while ((APPLMASK & 1) == 0)
|
|
|
|
{
|
|
|
|
APPLMASK >>= 1;
|
|
|
|
APPL++;
|
|
|
|
}
|
|
|
|
if (APPL->APPLCALL[0] > 0x40) // We have an applcall
|
|
|
|
ourcall = &APPL->APPLCALL[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(NewSess->L4USER, ourcall, 7);
|
|
|
|
memcpy(NewSess->L4MYCALL, Session->L4MYCALL, 7);
|
|
|
|
|
|
|
|
NewSess->CIRCUITINDEX = Index; //OUR INDEX
|
|
|
|
NewSess->CIRCUITID = NEXTID;
|
|
|
|
|
|
|
|
NEXTID++;
|
|
|
|
if (NEXTID == 0)
|
|
|
|
NEXTID++; // kEEP nON-ZERO
|
|
|
|
|
|
|
|
NewSess->SESSIONT1 = Session->SESSIONT1;
|
|
|
|
NewSess->L4WINDOW = (UCHAR)L4DEFAULTWINDOW;
|
|
|
|
NewSess->SESSPACLEN = PACLEN; // Default;
|
|
|
|
|
|
|
|
NewSess->L4TARGET.HOST = HOSTSESS;
|
|
|
|
NewSess->L4STATE = 5;
|
|
|
|
return NewSess;
|
|
|
|
}
|
|
|
|
Index++;
|
|
|
|
NewSess++;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern int GETCONNECTIONINFO();
|
|
|
|
|
|
|
|
|
|
|
|
BOOL cATTACHTOBBS(TRANSPORTENTRY * Session, UINT Mask, int Paclen, int * AnySessions)
|
|
|
|
{
|
|
|
|
PBPQVECSTRUC HOSTSESS = BPQHOSTVECTOR;
|
|
|
|
TRANSPORTENTRY * NewSess;
|
|
|
|
int ApplNum;
|
|
|
|
int n = BPQHOSTSTREAMS;
|
|
|
|
int ConfigedPorts = 0;
|
|
|
|
|
|
|
|
// LOOK FOR A FREE HOST SESSION
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (HOSTSESS->HOSTAPPLMASK & Mask)
|
|
|
|
{
|
|
|
|
// Right appl
|
|
|
|
|
|
|
|
ConfigedPorts++;
|
|
|
|
|
|
|
|
if (HOSTSESS->HOSTSESSION == NULL && (HOSTSESS->HOSTFLAGS & 3) == 0) // Not attached and no report outstanding
|
|
|
|
{
|
|
|
|
// WEVE GOT A FREE BPQ HOST PORT - USE IT
|
|
|
|
|
|
|
|
NewSess = SetupSessionFromSession(Session, HOSTSESS, Mask);
|
|
|
|
|
|
|
|
if (NewSess == NULL)
|
|
|
|
return FALSE; // Appl not available
|
|
|
|
|
|
|
|
HOSTSESS->HOSTSESSION = NewSess;
|
|
|
|
|
|
|
|
// Convert APPLMASK to APPLNUM
|
|
|
|
|
|
|
|
ApplNum = 1;
|
|
|
|
|
|
|
|
while (APPLMASK && (APPLMASK & 1) == 0)
|
|
|
|
{
|
|
|
|
ApplNum++;
|
|
|
|
APPLMASK >>= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
HOSTSESS->HOSTAPPLNUM = ApplNum;
|
|
|
|
|
|
|
|
HOSTSESS->HOSTFLAGS |= 2; // Indicate State Change
|
|
|
|
|
|
|
|
NewSess->L4CIRCUITTYPE = BPQHOST | DOWNLINK;
|
|
|
|
|
|
|
|
PostStateChange(NewSess);
|
|
|
|
|
|
|
|
NewSess->SESS_APPLFLAGS = HOSTSESS->HOSTAPPLFLAGS;
|
|
|
|
|
|
|
|
NewSess->SESSPACLEN = Paclen;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
HOSTSESS++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*AnySessions = ConfigedPorts; // to distinguish between none and all in use
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID APPLCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
BOOL CONFAILED = 0;
|
|
|
|
UINT CONERROR ;
|
|
|
|
char APPName[13];
|
|
|
|
char * ptr1, *ptr2;
|
|
|
|
int n = 12;
|
|
|
|
BOOL Stay = FALSE;
|
|
|
|
|
|
|
|
// Copy Appl and Null Terminate
|
|
|
|
|
|
|
|
ptr1 = &CMD->String[0];
|
|
|
|
ptr2 = APPName;
|
|
|
|
|
|
|
|
while (*(ptr1) != ' ' && n--)
|
|
|
|
*(ptr2++) = *(ptr1++);
|
|
|
|
|
|
|
|
*(ptr2) = 0;
|
|
|
|
|
|
|
|
if (Session->LISTEN)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Can't use %s while listening\r", APPName);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (CmdTail[0] == 'S')
|
|
|
|
Stay = TRUE;
|
|
|
|
|
|
|
|
Session->STAYFLAG = Stay;
|
|
|
|
|
|
|
|
memcpy(Session->APPL, CMD->String, 12);
|
|
|
|
|
|
|
|
// SEE IF THERE IS AN ALIAS DEFINDED FOR THIS COMMAND
|
|
|
|
|
|
|
|
if (ALIASPTR[0] > ' ')
|
|
|
|
{
|
|
|
|
// COPY ALIAS TO COMMAND BUFFER, THEN REENTER COMMAND HANDLER
|
|
|
|
|
|
|
|
int SaveSecure = Session->Secure_Session;
|
|
|
|
|
|
|
|
memcpy(COMMANDBUFFER, ALIASPTR, ALIASLEN);
|
|
|
|
_strupr(COMMANDBUFFER);
|
|
|
|
memcpy(OrigCmdBuffer, ALIASPTR, ALIASLEN); // In case original case version needed
|
|
|
|
|
|
|
|
ALIASINVOKED = 1; // To prevent Alias Loops
|
|
|
|
|
|
|
|
// Set secure session for application alias in case telnet outward connect
|
|
|
|
|
|
|
|
Session->Secure_Session = 1;
|
|
|
|
DoTheCommand(Session);
|
|
|
|
Session->Secure_Session = SaveSecure;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cATTACHTOBBS(Session, APPLMASK, CMDPACLEN, &CONERROR) == 0)
|
|
|
|
{
|
|
|
|
// No Streams
|
|
|
|
|
|
|
|
if (CONERROR)
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, All %s Ports are in use - Please try later\r", APPName);
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, Application %s is not running - Please try later\r", APPName);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// IF CMD_TO_APPL SET IN APPLFLAGS, SEND INPUT MSG TO APPL
|
|
|
|
|
|
|
|
if (Session->L4CROSSLINK->SESS_APPLFLAGS & CMD_TO_APPL)
|
|
|
|
{
|
|
|
|
struct DATAMESSAGE * Msg = (struct DATAMESSAGE *)GetBuff();
|
|
|
|
TRANSPORTENTRY * XSession = Session->L4CROSSLINK;
|
|
|
|
|
|
|
|
if (Msg)
|
|
|
|
{
|
|
|
|
COMMANDBUFFER[72] = 13;
|
|
|
|
memcpy(Msg->L2DATA, COMMANDBUFFER, 73);
|
|
|
|
Msg->LENGTH = 73 + 4 + sizeof(void *);
|
|
|
|
Msg->PID = 0xf0;
|
|
|
|
|
|
|
|
C_Q_ADD(&XSession->L4TX_Q, (UINT *)Msg);
|
|
|
|
PostDataAvailable(XSession);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Stay)
|
|
|
|
Session->L4CROSSLINK->L4TARGET.HOST->HOSTFLAGS |= 0x20;
|
|
|
|
|
|
|
|
// IF MSG_TO_USER SET, SEND 'CONNECTED' MESSAGE TO USER
|
|
|
|
|
|
|
|
Session->SESS_APPLFLAGS = Session->L4CROSSLINK->SESS_APPLFLAGS;
|
|
|
|
|
|
|
|
if (Session->L4CROSSLINK->SESS_APPLFLAGS & MSG_TO_USER)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Connected to %s\r", APPName);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DONT NEED BUFFER ANY MORE
|
|
|
|
|
|
|
|
ReleaseBuffer((UINT *)REPLYBUFFER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID CMDI00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", INFOMSG);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CMDV00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
if (sizeof(void *) == 4)
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Version %s\r", VersionString);
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Version %s (64 bit)\r", VersionString);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID BYECMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
CLOSECURRENTSESSION(Session); // Kills any crosslink, plus local link
|
|
|
|
ReleaseBuffer((UINT *)REPLYBUFFER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CMDPAC(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// SET PACLEN FOR THIS SESSION
|
|
|
|
|
|
|
|
char * ptr, *Context;
|
|
|
|
int newvalue;
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && ptr[0])
|
|
|
|
{
|
|
|
|
// Get new value
|
|
|
|
|
|
|
|
newvalue = atoi(ptr);
|
|
|
|
if (newvalue > 29 && newvalue < 256)
|
|
|
|
Session->SESSPACLEN = newvalue & 0xff;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "PACLEN - %d\r", Session->SESSPACLEN);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CMDIDLE(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// SET IDLETIME FOR THIS SESSION
|
|
|
|
|
|
|
|
char * ptr, *Context;
|
|
|
|
int newvalue;
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && ptr[0])
|
|
|
|
{
|
|
|
|
// Get new value
|
|
|
|
|
|
|
|
newvalue = atoi(ptr);
|
|
|
|
if (newvalue > 59 && newvalue < 901)
|
|
|
|
Session->L4LIMIT = newvalue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "IDLETIME - %d\r", Session->L4LIMIT);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
|
|
|
}
|
|
|
|
VOID CMDT00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// SET L4 TIMEOUT FOR CONNECTS ON THIS SESSION
|
|
|
|
|
|
|
|
char * ptr, *Context;
|
|
|
|
int newvalue;
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && ptr[0])
|
|
|
|
{
|
|
|
|
// Get new value
|
|
|
|
|
|
|
|
newvalue = atoi(ptr);
|
|
|
|
if (newvalue > 20)
|
|
|
|
Session->SESSIONT1 = newvalue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L4TIMEOUT - %d\r", Session->SESSIONT1);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
UCHAR PWLen;
|
|
|
|
char PWTEXT[80];
|
|
|
|
|
|
|
|
VOID PWDCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char * ptr, *Context;
|
|
|
|
USHORT pwsum = 0;
|
|
|
|
int n = 5, p1, p2, p3, p4, p5;
|
|
|
|
|
|
|
|
if (Session->Secure_Session) // HOST - SET AUTHORISED REGARDLESS
|
|
|
|
{
|
|
|
|
Session->PASSWORD = 0xFFFF; // SET AUTHORISED
|
|
|
|
Session->Secure_Session = 1;
|
|
|
|
strcpy(Bufferptr, OKMSG);
|
|
|
|
Bufferptr += (int)strlen(OKMSG);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && ptr[0])
|
|
|
|
{
|
|
|
|
// Check Password
|
|
|
|
|
|
|
|
n = 5;
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
pwsum += *(ptr++);
|
|
|
|
|
|
|
|
if (Session->PASSWORD == pwsum)
|
|
|
|
{
|
|
|
|
Session->PASSWORD = 0xFFFF; // SET AUTHORISED
|
|
|
|
Session->Secure_Session = 1;
|
|
|
|
strcpy(Bufferptr, OKMSG);
|
|
|
|
Bufferptr += (int)strlen(OKMSG);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseBuffer((UINT *)REPLYBUFFER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// SEND PASSWORD PROMPT
|
|
|
|
|
|
|
|
if (PWLen == 0)
|
|
|
|
PWLen = 1;
|
|
|
|
|
|
|
|
p1 = rand() % PWLen;
|
|
|
|
pwsum += PWTEXT[p1++];
|
|
|
|
|
|
|
|
p2 = rand() % PWLen;
|
|
|
|
pwsum += PWTEXT[p2++];
|
|
|
|
|
|
|
|
p3 = rand() % PWLen;
|
|
|
|
pwsum += PWTEXT[p3++];
|
|
|
|
|
|
|
|
p4 = rand() % PWLen;
|
|
|
|
pwsum += PWTEXT[p4++];
|
|
|
|
|
|
|
|
p5 = rand() % PWLen;
|
|
|
|
pwsum += PWTEXT[p5++];
|
|
|
|
|
|
|
|
Session->PASSWORD = pwsum;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%d %d %d %d %d\r", p1, p2, p3, p4, p5);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CMDSTATS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char * ptr, *Context;
|
|
|
|
int Port = 0, cols = NUMBEROFPORTS, i;
|
|
|
|
char * uptime;
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
struct PORTCONTROL * STARTPORT;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
// SEE IF ANY PARAM
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && ptr[0])
|
|
|
|
Port = atoi(ptr);
|
|
|
|
|
|
|
|
// IF ASKING FOR PORT STATS, DONT DO SYSTEM ONES
|
|
|
|
|
|
|
|
if (Port == 0)
|
|
|
|
{
|
|
|
|
uptime = FormatUptime(STATSTIME);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", uptime);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Semaphore Get-Rel/Clashes %9d%9d\r",
|
|
|
|
Semaphore.Gets - Semaphore.Rels, Semaphore.Clashes);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Buffers:Max/Cur/Min/Out/Wait%9d%9d%9d%9d%9d\r",
|
|
|
|
MAXBUFFS, QCOUNT, MINBUFFCOUNT, NOBUFFCOUNT, BUFFERWAITS);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Known Nodes/Max Nodes %9d%9d\r",
|
|
|
|
NUMBEROFNODES, MAXDESTS);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L4 Connects Sent/Rxed %9d%9d\r",
|
|
|
|
L4CONNECTSOUT, L4CONNECTSIN);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L4 Frames TX/RX/Resent/Reseq%9d%9d%9d%9d\r",
|
|
|
|
L4FRAMESTX, L4FRAMESRX, L4FRAMESRETRIED, OLDFRAMES);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L3 Frames Relayed %9d\r", L3FRAMES);
|
|
|
|
|
|
|
|
if (ptr && ptr[0] == 'S')
|
|
|
|
{
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// POSITION TO REQUESTED PORT
|
|
|
|
|
|
|
|
if (Port)
|
|
|
|
{
|
|
|
|
while (PORT && PORT->PORTNUMBER != Port)
|
|
|
|
{
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
cols--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PORT == NULL) // REQUESTED PORT NOT FOUND
|
|
|
|
{
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
STARTPORT = PORT;
|
|
|
|
|
|
|
|
if (cols > 7)
|
|
|
|
cols = 7;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port %02d ", PORT->PORTNUMBER);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Digied");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2DIGIED);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Heard ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRAMES);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Rxed ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRAMESFORUS);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Frames Sent ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRAMESSENT);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Timeouts ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2TIMEOUTS);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "REJ Frames Rxed ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2REJCOUNT);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "RX out of Seq ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2OUTOFSEQ);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "L2 Resequenced ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2RESEQ);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Undrun/Poll T/o ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2URUNC);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "RX Overruns ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2ORUNC);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "RX CRC Errors ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->RXERRORS);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "FRMRs Sent ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRMRTX);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "FRMRs Received ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L2FRMRRX);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Frames abandoned");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%9d", PORT->L1DISCARD);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
PORT = STARTPORT;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Link Active %% ");
|
|
|
|
|
|
|
|
for (i = 0; i < cols; i++)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " %2d %3d", PORT->AVSENDING, PORT->AVACTIVE);
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CMDL00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// PROCESS 'LINKS' MESSAGE
|
|
|
|
|
|
|
|
struct _LINKTABLE * LINK = LINKS;
|
|
|
|
int n = MAXLINKS;
|
|
|
|
int len;
|
|
|
|
char Normcall[11] = "";
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Links\r");
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (LINK->LINKCALL[0])
|
|
|
|
{
|
|
|
|
len = ConvFromAX25(LINK->LINKCALL, Normcall);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Normcall);
|
|
|
|
|
|
|
|
len = ConvFromAX25(LINK->OURCALL, Normcall);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Normcall);
|
|
|
|
|
|
|
|
if (LINK->Ver2point2)
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " S=%d P=%d T=%d V=2.2\r",
|
|
|
|
LINK->L2STATE, LINK->LINKPORT->PORTNUMBER, LINK->LINKTYPE);
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " S=%d P=%d T=%d V=%d\r",
|
|
|
|
LINK->L2STATE, LINK->LINKPORT->PORTNUMBER, LINK->LINKTYPE, 2 - LINK->VER1FLAG);
|
|
|
|
}
|
|
|
|
LINK++;
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID CMDS00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// PROCESS 'USERS'
|
|
|
|
|
|
|
|
int n = MAXCIRCUITS;
|
|
|
|
TRANSPORTENTRY * L4 = L4TABLE;
|
|
|
|
TRANSPORTENTRY * Partner;
|
|
|
|
int MaxLinks = MAXLINKS;
|
|
|
|
char State[12] = "", Type[12] = "Uplink";
|
|
|
|
char LHS[50] = "", MID[10] = "", RHS[50] = "";
|
|
|
|
char Line[100];
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s%d)\r", SESSIONHDDR, QCOUNT);
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (L4->L4USER[0])
|
|
|
|
{
|
|
|
|
RHS[0] = MID[0] = 0;
|
|
|
|
|
|
|
|
if ((L4->L4CIRCUITTYPE & UPLINK) == 0) //SHORT CMDS10A ; YES
|
|
|
|
{
|
|
|
|
// IF DOWNLINK, ONLY DISPLAY IF NO CROSSLINK
|
|
|
|
|
|
|
|
if (L4->L4CROSSLINK == 0) //jne CMDS60 ; WILL PROCESS FROM OTHER END
|
|
|
|
{
|
|
|
|
// ITS A DOWNLINK WITH NO PARTNER - MUST BE A CLOSING SESSION
|
|
|
|
// DISPLAY TO THE RIGHT FOR NOW
|
|
|
|
|
|
|
|
strcpy(LHS, "(Closing) ");
|
|
|
|
DISPLAYCIRCUIT(L4, RHS);
|
|
|
|
goto CMDS50;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
goto CMDS60; // WILL PROCESS FROM OTHER END
|
|
|
|
}
|
|
|
|
|
|
|
|
if (L4->L4CROSSLINK == 0)
|
|
|
|
{
|
|
|
|
// Single Entry
|
|
|
|
|
|
|
|
DISPLAYCIRCUIT(L4, LHS);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DISPLAYCIRCUIT(L4, LHS);
|
|
|
|
|
|
|
|
Partner = L4->L4CROSSLINK;
|
|
|
|
|
|
|
|
if (Partner->L4STATE == 5)
|
|
|
|
strcpy(MID, "<-->");
|
|
|
|
else
|
|
|
|
strcpy(MID, "<~~>");
|
|
|
|
|
|
|
|
DISPLAYCIRCUIT(Partner, RHS);
|
|
|
|
}
|
|
|
|
CMDS50:
|
|
|
|
memset(Line, 32, 100);
|
|
|
|
memcpy(Line, LHS, (int)strlen(LHS));
|
|
|
|
memcpy(&Line[35], MID, (int)strlen(MID));
|
|
|
|
strcpy(&Line[40], RHS);
|
|
|
|
strcat(&Line[40], "\r");
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Line);
|
|
|
|
}
|
|
|
|
CMDS60:
|
|
|
|
L4++;
|
|
|
|
}
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
2023-06-29 18:13:31 +01:00
|
|
|
extern int MasterPort[MAXBPQPORTS+1]; // Pointer to first BPQ port for a specific MPSK or UZ7HO host
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
VOID CMDP00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// Process PORTS Message
|
|
|
|
|
2023-06-29 18:13:31 +01:00
|
|
|
// If extended show state of TNC (Open, Active, etc)
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
2023-06-29 18:13:31 +01:00
|
|
|
char Extended = CmdTail[0];
|
|
|
|
struct PORTCONTROL * SAVEPORT;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Ports\r");
|
|
|
|
|
|
|
|
while (PORT)
|
|
|
|
{
|
2023-06-29 18:13:31 +01:00
|
|
|
char Status[32] = "???????";
|
|
|
|
int Portno = PORT->PORTNUMBER;
|
|
|
|
|
|
|
|
if (PORT->Hide)
|
|
|
|
{
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Extended != 'E')
|
|
|
|
{
|
2022-08-28 09:35:46 +01:00
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " %2d %s\r", PORT->PORTNUMBER, PORT->PORTDESCRIPTION);
|
|
|
|
|
2023-06-29 18:13:31 +01:00
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to get port status - may not be possible with some
|
|
|
|
|
|
|
|
if (PORT->PortStopped)
|
|
|
|
{
|
|
|
|
strcpy(Status, "Stopped");
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " %2d %-7s %s\r", PORT->PORTNUMBER, Status, PORT->PORTDESCRIPTION);
|
|
|
|
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PORT->PORTTYPE == 0)
|
|
|
|
{
|
|
|
|
struct KISSINFO * KISS = (struct KISSINFO *)PORT;
|
|
|
|
NPASYINFO Port;
|
|
|
|
|
|
|
|
SAVEPORT = PORT;
|
|
|
|
|
|
|
|
if (KISS->FIRSTPORT && KISS->FIRSTPORT != KISS)
|
|
|
|
{
|
|
|
|
// Not first port on device
|
|
|
|
|
|
|
|
PORT = (struct PORTCONTROL *)KISS->FIRSTPORT;
|
|
|
|
Port = KISSInfo[Portno];
|
|
|
|
}
|
|
|
|
|
|
|
|
Port = KISSInfo[PORT->PORTNUMBER];
|
|
|
|
|
|
|
|
if (Port)
|
|
|
|
{
|
|
|
|
// KISS like - see if connected
|
|
|
|
|
|
|
|
if (PORT->PORTIPADDR.s_addr || PORT->KISSSLAVE)
|
|
|
|
{
|
|
|
|
// KISS over UDP or TCP
|
|
|
|
|
|
|
|
if (PORT->KISSTCP)
|
|
|
|
{
|
|
|
|
if (Port->Connected)
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
else
|
|
|
|
if (PORT->KISSSLAVE)
|
|
|
|
strcpy(Status, "Listen");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strcpy(Status, "UDP");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (Port->idComDev) // Serial port Open
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
|
|
|
|
PORT = SAVEPORT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (PORT->PORTTYPE == 14) // Loopback
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
|
|
|
|
else if (PORT->PORTTYPE == 16) // External
|
|
|
|
{
|
|
|
|
if (PORT->PROTOCOL == 10) // 'HF' Port
|
|
|
|
{
|
|
|
|
struct TNCINFO * TNC = TNCInfo[Portno];
|
|
|
|
|
|
|
|
if (TNC == NULL)
|
|
|
|
{
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (TNC->Hardware) // Hardware Type
|
|
|
|
{
|
|
|
|
case H_SCS:
|
|
|
|
case H_KAM:
|
|
|
|
case H_AEA:
|
|
|
|
case H_HAL:
|
|
|
|
case H_TRK:
|
|
|
|
case H_SERIAL:
|
|
|
|
|
|
|
|
// Serial
|
|
|
|
|
|
|
|
if (TNC->hDevice)
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case H_UZ7HO:
|
|
|
|
|
|
|
|
if (TNCInfo[MasterPort[Portno]]->CONNECTED)
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case H_WINMOR:
|
|
|
|
case H_V4:
|
|
|
|
|
|
|
|
case H_MPSK:
|
|
|
|
case H_FLDIGI:
|
|
|
|
case H_UIARQ:
|
|
|
|
case H_ARDOP:
|
|
|
|
case H_VARA:
|
|
|
|
case H_KISSHF:
|
|
|
|
case H_WINRPR:
|
|
|
|
case H_FREEDATA:
|
|
|
|
|
|
|
|
// TCP
|
|
|
|
|
|
|
|
if (TNC->CONNECTED)
|
|
|
|
{
|
|
|
|
if (TNC->Streams[0].Attached)
|
|
|
|
strcpy(Status, "In Use");
|
|
|
|
else
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strcpy(Status, "Closed");
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case H_TELNET:
|
|
|
|
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// External but not HF - AXIP, BPQETHER VKISS, ??
|
|
|
|
|
|
|
|
struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)PORT;
|
|
|
|
|
|
|
|
strcpy(Status, "Open ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " %2d %-7s %s\r", PORT->PORTNUMBER, Status, PORT->PORTDESCRIPTION);
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
char * DisplayRoute(TRANSPORTENTRY * Session, char * Bufferptr, struct ROUTE * Routes, char Verbose)
|
|
|
|
{
|
|
|
|
char Normcall[10];
|
|
|
|
char locked[] = " ! ";
|
|
|
|
int NodeCount;
|
|
|
|
int Percent = 0;
|
|
|
|
char PercentString[20];
|
|
|
|
int Iframes, Retries;
|
|
|
|
char Active[10];
|
|
|
|
int Queued;
|
|
|
|
|
|
|
|
int Port = 0;
|
|
|
|
|
|
|
|
int len = ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall);
|
|
|
|
|
|
|
|
Normcall[9]=0;
|
|
|
|
|
|
|
|
if ((Routes->NEIGHBOUR_FLAG & 1) == 1)
|
|
|
|
strcpy(locked, "!");
|
|
|
|
else
|
|
|
|
strcpy(locked, " ");
|
|
|
|
|
|
|
|
NodeCount = COUNTNODES(Routes);
|
|
|
|
|
|
|
|
if (Routes->NEIGHBOUR_LINK && Routes->NEIGHBOUR_LINK->L2STATE >= 5)
|
|
|
|
strcpy(Active, ">");
|
|
|
|
else
|
|
|
|
strcpy(Active, " ");
|
|
|
|
|
|
|
|
if (Verbose)
|
|
|
|
{
|
|
|
|
if (Routes->NEIGHBOUR_LINK)
|
|
|
|
Queued = COUNT_AT_L2(Routes->NEIGHBOUR_LINK); // SEE HOW MANY QUEUED
|
|
|
|
else
|
|
|
|
Queued = 0;
|
|
|
|
|
|
|
|
Iframes = Routes->NBOUR_IFRAMES;
|
|
|
|
Retries = Routes->NBOUR_RETRIES;
|
|
|
|
|
|
|
|
if (Iframes)
|
|
|
|
{
|
|
|
|
Percent = (Retries * 100) / Iframes;
|
|
|
|
sprintf(PercentString, "%3d%%", Percent);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
strcpy(PercentString, " ");
|
|
|
|
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s%2d %s %3d %3d%s%4d %4d %s %d %d %02d:%02d %d %d",
|
|
|
|
Active, Routes->NEIGHBOUR_PORT, Normcall,
|
|
|
|
Routes->NEIGHBOUR_QUAL, NodeCount, locked, Iframes, Retries, PercentString, Routes->NBOUR_MAXFRAME, Routes->NBOUR_FRACK,
|
|
|
|
Routes->NEIGHBOUR_TIME >> 8, (Routes->NEIGHBOUR_TIME) & 0xff, Queued, Routes->OtherendsRouteQual);
|
|
|
|
|
|
|
|
// IF INP3 DISPLAY SRTT
|
|
|
|
|
|
|
|
if (Routes->INP3Node) // INP3 Enabled?
|
|
|
|
{
|
|
|
|
double srtt = Routes->SRTT/1000.0;
|
|
|
|
double nsrtt = Routes->NeighbourSRTT/1000.0;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " %4.2fs %4.2fs", srtt, nsrtt);
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s %d %s %d %d%s\r",
|
|
|
|
Active, Routes->NEIGHBOUR_PORT, Normcall, Routes->NEIGHBOUR_QUAL, NodeCount, locked);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Bufferptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID CMDR00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
struct ROUTE * Routes = NEIGHBOURS;
|
|
|
|
int MaxRoutes = MAXNEIGHBOURS;
|
|
|
|
char locked[] = " ! ";
|
|
|
|
int Percent = 0;
|
|
|
|
char * ptr, * Context;
|
|
|
|
char Verbose = 0;
|
|
|
|
int Port = 0;
|
|
|
|
char AXCALL[7];
|
|
|
|
BOOL Found;
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && (int)strlen(ptr) > 1)
|
|
|
|
{
|
|
|
|
// Route Update
|
|
|
|
|
|
|
|
goto ROUTEUPDATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
Verbose = ptr[0];
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
if (ptr)
|
|
|
|
Port = atoi(ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Routes\r");
|
|
|
|
|
|
|
|
while (MaxRoutes--)
|
|
|
|
{
|
|
|
|
if (Routes->NEIGHBOUR_CALL[0] != 0)
|
|
|
|
if (Port == 0 || Port == Routes->NEIGHBOUR_PORT)
|
|
|
|
Bufferptr = DisplayRoute(Session, Bufferptr, Routes, Verbose);
|
|
|
|
|
|
|
|
Routes++;
|
|
|
|
}
|
|
|
|
goto SendReply;
|
|
|
|
|
|
|
|
ROUTEUPDATE:
|
|
|
|
|
|
|
|
if (Session->PASSWORD != 0xFFFF)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG);
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Line is
|
|
|
|
|
|
|
|
// ROUTES G8BPQ-2 2 100 - Set quality to 100
|
|
|
|
// ROUTES G8BPQ-2 2 ! - Toggle 'Locked Route' flag
|
|
|
|
// ROUTES G8BPQ-2 2 100 ! - Set quality and toggle 'locked' flag
|
|
|
|
|
|
|
|
|
|
|
|
ConvToAX25(ptr, AXCALL);
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
Port = atoi(ptr);
|
|
|
|
|
|
|
|
if (Port == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port Number Missing \r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
Found = FindNeighbour(AXCALL, Port, &Routes);
|
|
|
|
|
|
|
|
if (Context && Context[0] > 32)
|
|
|
|
{
|
|
|
|
// More Params
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
// Adding
|
|
|
|
|
|
|
|
memcpy(Routes->NEIGHBOUR_CALL, AXCALL, 7); // In case Add
|
|
|
|
Routes->NEIGHBOUR_PORT = Port;
|
|
|
|
Found = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(ptr, "!") == 0)
|
|
|
|
{
|
|
|
|
// Toggle Lock
|
|
|
|
|
|
|
|
Routes->NEIGHBOUR_FLAG ^= 1; // FLIP LOCKED BIT
|
|
|
|
goto Displayit;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(ptr, "Z") == 0)
|
|
|
|
{
|
|
|
|
// Clear Counts
|
|
|
|
|
|
|
|
Routes->NBOUR_IFRAMES = 0;
|
|
|
|
Routes->NBOUR_RETRIES = 0;
|
|
|
|
goto Displayit;
|
|
|
|
}
|
|
|
|
|
|
|
|
Routes->NEIGHBOUR_QUAL = atoi(ptr);
|
|
|
|
|
|
|
|
if (Context && Context[0] == '!')
|
|
|
|
{
|
|
|
|
// Toggle Lock
|
|
|
|
|
|
|
|
Routes->NEIGHBOUR_FLAG ^= 1; // FLIP LOCKED BIT
|
|
|
|
goto Displayit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Displayit:
|
|
|
|
|
|
|
|
// Just display
|
|
|
|
|
|
|
|
if (Found)
|
|
|
|
Bufferptr = DisplayRoute(Session, Bufferptr, Routes, 1);
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not Found\r");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* MOV ROUTEDISP,1
|
|
|
|
|
|
|
|
CMP BYTE PTR [ESI],20H
|
|
|
|
JE SHORT JUSTDISPLAY
|
|
|
|
|
|
|
|
MOV ZAPFLAG,0
|
|
|
|
|
|
|
|
CMP BYTE PTR [ESI],'Z'
|
|
|
|
JNE SHORT NOTZAP
|
|
|
|
|
|
|
|
MOV ZAPFLAG,1
|
|
|
|
JMP SHORT JUSTDISPLAY
|
|
|
|
|
|
|
|
PUBLIC NOTZAP
|
|
|
|
NOTZAP:
|
|
|
|
|
|
|
|
MOV ROUTEDISP,2 ; LOCK UPDATE
|
|
|
|
|
|
|
|
CMP BYTE PTR [ESI],'!'
|
|
|
|
JE SHORT JUSTDISPLAY
|
|
|
|
;
|
|
|
|
; LOOK FOR V FOR ADDING A DIGI
|
|
|
|
;
|
|
|
|
CMP WORD PTR [ESI],' V' ; V [SPACE]
|
|
|
|
JE ADDDIGI
|
|
|
|
|
|
|
|
CALL GETVALUE ; GET NUMBER, UP TO SPACE , CR OR OFFH
|
|
|
|
JC SHORT BADROUTECMD ; INVALID DIGITS
|
|
|
|
|
|
|
|
MOV NEWROUTEVAL,AL
|
|
|
|
|
|
|
|
MOV ROUTEDISP,0
|
|
|
|
|
|
|
|
CALL SCAN ; SEE IF !
|
|
|
|
MOV AH,[ESI]
|
|
|
|
|
|
|
|
|
|
|
|
PUBLIC JUSTDISPLAY
|
|
|
|
JUSTDISPLAY:
|
|
|
|
|
|
|
|
|
|
|
|
MOV ESI,OFFSET32 AX25CALL
|
|
|
|
CALL _FINDNEIGHBOUR
|
|
|
|
JZ SHORT FOUNDROUTE ; IN LIST - OK
|
|
|
|
|
|
|
|
CMP EBX,0
|
|
|
|
JE SHORT BADROUTECMD ; TABLE FULL??
|
|
|
|
|
|
|
|
MOV ECX,7
|
|
|
|
MOV EDI,EBX
|
|
|
|
REP MOVSB ; PUT IN CALL
|
|
|
|
|
|
|
|
MOV AL,SAVEPORT
|
|
|
|
MOV NEIGHBOUR_PORT[EBX],AL
|
|
|
|
|
|
|
|
JMP SHORT FOUNDROUTE
|
|
|
|
|
|
|
|
|
|
|
|
PUBLIC BADROUTECMD
|
|
|
|
BADROUTECMD:
|
|
|
|
|
|
|
|
POP EDI
|
|
|
|
|
|
|
|
JMP PBADVALUE
|
|
|
|
|
|
|
|
PUBLIC FOUNDROUTE
|
|
|
|
FOUNDROUTE:
|
|
|
|
|
|
|
|
CMP ZAPFLAG,1
|
|
|
|
JNE SHORT NOTCLEARCOUNTS
|
|
|
|
|
|
|
|
XOR AX,AX
|
|
|
|
MOV ES:WORD PTR NBOUR_IFRAMES[EDI],AX
|
|
|
|
MOV ES:WORD PTR NBOUR_IFRAMES+2[EDI],AX
|
|
|
|
MOV ES:WORD PTR NBOUR_RETRIES[EDI],AX
|
|
|
|
MOV ES:WORD PTR NBOUR_RETRIES+2[EDI],AX
|
|
|
|
|
|
|
|
JMP SHORT NOUPDATE
|
|
|
|
|
|
|
|
PUBLIC NOTCLEARCOUNTS
|
|
|
|
NOTCLEARCOUNTS:
|
|
|
|
|
|
|
|
CMP ROUTEDISP,1
|
|
|
|
JE SHORT NOUPDATE
|
|
|
|
|
|
|
|
CMP ROUTEDISP,2
|
|
|
|
JE SHORT LOCKUPDATE
|
|
|
|
|
|
|
|
MOV AL,NEWROUTEVAL
|
|
|
|
MOV NEIGHBOUR_QUAL[EBX],AL
|
|
|
|
|
|
|
|
CMP AH,'!'
|
|
|
|
JNE SHORT NOUPDATE
|
|
|
|
|
|
|
|
PUBLIC LOCKUPDATE
|
|
|
|
LOCKUPDATE:
|
|
|
|
|
|
|
|
XOR NEIGHBOUR_FLAG[EBX],1 ; FLIP LOCKED BIT
|
|
|
|
|
|
|
|
PUBLIC NOUPDATE
|
|
|
|
NOUPDATE:
|
|
|
|
|
|
|
|
MOV ESI,EBX
|
|
|
|
POP EDI
|
|
|
|
|
|
|
|
POP EBX
|
|
|
|
CALL DISPLAYROUTE
|
|
|
|
|
|
|
|
JMP SENDCOMMANDREPLY
|
|
|
|
|
|
|
|
PUBLIC ADDDIGI
|
|
|
|
ADDDIGI:
|
|
|
|
|
|
|
|
ADD ESI,2
|
|
|
|
PUSH ESI ; SAVE INPUT BUFFER
|
|
|
|
|
|
|
|
MOV ESI,OFFSET32 AX25CALL
|
|
|
|
CALL _FINDNEIGHBOUR
|
|
|
|
|
|
|
|
POP ESI
|
|
|
|
|
|
|
|
JZ SHORT ADD_FOUND ; IN LIST - OK
|
|
|
|
|
|
|
|
JMP BADROUTECMD
|
|
|
|
|
|
|
|
PUBLIC ADD_FOUND
|
|
|
|
ADD_FOUND:
|
|
|
|
|
|
|
|
CALL CONVTOAX25 ; GET DIGI CALLSIGN
|
|
|
|
|
|
|
|
PUSH ESI
|
|
|
|
|
|
|
|
MOV ESI,OFFSET32 AX25CALL
|
|
|
|
LEA EDI,NEIGHBOUR_DIGI[EBX]
|
|
|
|
MOV ECX,7
|
|
|
|
REP MOVSB
|
|
|
|
|
|
|
|
POP ESI ; MSG BUFFER
|
|
|
|
;
|
|
|
|
; SEE IF ANOTHER DIGI
|
|
|
|
;
|
|
|
|
CMP BYTE PTR [ESI],20H
|
|
|
|
JE SHORT NOMORE
|
|
|
|
|
|
|
|
CALL CONVTOAX25 ; GET DIGI CALLSIGN
|
|
|
|
MOV ESI,OFFSET32 AX25CALL
|
|
|
|
LEA EDI,NEIGHBOUR_DIGI+7[EBX]
|
|
|
|
MOV ECX,7
|
|
|
|
REP MOVSB
|
|
|
|
|
|
|
|
PUBLIC NOMORE
|
|
|
|
NOMORE:
|
|
|
|
|
|
|
|
JMP NOUPDATE
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
SendReply:
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID LISTENCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// PROCESS LISTEN COMMAND
|
|
|
|
|
|
|
|
// for monitoring a remote ax.25 port
|
|
|
|
|
|
|
|
int Port = 0, index =0;
|
2023-05-25 14:17:53 +01:00
|
|
|
uint64_t ListenMask = 0;
|
2022-08-28 09:35:46 +01:00
|
|
|
char * ptr, *Context;
|
|
|
|
struct PORTCONTROL * PORT = NULL;
|
|
|
|
char ListenPortList[128] = "";
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ,", &Context);
|
|
|
|
|
|
|
|
// Now accepts a list of ports
|
|
|
|
|
|
|
|
if (ptr == 0 || memcmp(ptr, "OFF", 3) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Listening disabled\r");
|
|
|
|
Session->LISTEN = 0;
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (ptr)
|
|
|
|
{
|
|
|
|
Port = atoi(ptr);
|
|
|
|
|
|
|
|
if (Port == 0 && NUMBEROFPORTS == 1)
|
|
|
|
Port = 1;
|
|
|
|
|
2023-05-25 14:17:53 +01:00
|
|
|
ptr = strtok_s(NULL, ", ", &Context); // Get port String
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
if (Port)
|
|
|
|
PORT = GetPortTableEntryFromPortNum(Port);
|
|
|
|
|
|
|
|
if (PORT == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port %d\r", Port);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-05-25 14:17:53 +01:00
|
|
|
if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0)
|
2022-08-28 09:35:46 +01:00
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port %d is not an ax.25 port\r", Port);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PORT->PORTL3FLAG)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port %d is for internode traffic only\r", Port);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Session->L4CIRCUITTYPE == L2LINK + UPLINK)
|
|
|
|
{
|
|
|
|
if (Session->L4TARGET.LINK->LINKPORT->PORTNUMBER == Port)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "You can't Listen to the port you are connected on\r");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(ListenPortList, "%s %d", ListenPortList, Port);
|
|
|
|
|
2023-05-25 14:17:53 +01:00
|
|
|
ListenMask |= ((uint64_t)1 << (Port - 1));
|
2022-08-28 09:35:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Session->LISTEN = ListenMask;
|
|
|
|
|
|
|
|
if (ListenMask)
|
|
|
|
{
|
2023-05-25 14:17:53 +01:00
|
|
|
if (CountBits64(ListenMask) == 1)
|
2022-08-28 09:35:46 +01:00
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Listening on port%s. Use CQ to send a beacon, LIS to disable\r", ListenPortList);
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Listening on ports%s. Use LIS to disable\r", ListenPortList);
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID UNPROTOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// PROCESS UNPROTO COMMAND
|
|
|
|
|
|
|
|
int Port = 0, index =0;
|
|
|
|
char * ptr, *Context;
|
|
|
|
struct PORTCONTROL * PORT = NULL;
|
|
|
|
UCHAR axcalls[64];
|
|
|
|
BOOL Stay, Spy;
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
Port = atoi(ptr);
|
|
|
|
|
|
|
|
if (Port == 0 && NUMBEROFPORTS == 1)
|
|
|
|
Port = 1;
|
|
|
|
else
|
|
|
|
ptr = strtok_s(NULL, " ", &Context); // Get Unproto String
|
|
|
|
|
|
|
|
if (Port)
|
|
|
|
PORT = GetPortTableEntryFromPortNum(Port);
|
|
|
|
|
|
|
|
if (PORT == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Destination missing\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ptr[strlen(ptr)] = ' '; // Put param back together
|
|
|
|
|
|
|
|
if (DecodeCallString(ptr, &Stay, &Spy, &axcalls[0]) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is not an ax.25 port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PORT->PORTL3FLAG)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is for internode traffic only\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Copy Address Info to Session Record
|
|
|
|
|
|
|
|
Session->UNPROTO = Port;
|
|
|
|
Session->UAddrLen = (int)strlen(axcalls);
|
|
|
|
memcpy(Session->UADDRESS, axcalls, 63);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Unproto Mode - enter ctrl/z or /ex to exit\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CALCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// PROCESS CAL COMMAND
|
|
|
|
|
|
|
|
int Port = 0, index = 0, Count = 0;
|
|
|
|
char * ptr, *Context;
|
|
|
|
struct PORTCONTROL * PORT = NULL;
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
Port = atoi(ptr);
|
|
|
|
|
|
|
|
if (Port == 0 && NUMBEROFPORTS == 1)
|
|
|
|
Port = 1;
|
|
|
|
else
|
|
|
|
ptr = strtok_s(NULL, " ", &Context); // Get Unproto String
|
|
|
|
|
|
|
|
if (Port)
|
|
|
|
PORT = GetPortTableEntryFromPortNum(Port);
|
|
|
|
|
|
|
|
if (PORT == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is not an ax.25 port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Count Missing\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Count = atoi(ptr);
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context); // Get Unproto String
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Ok\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
VOID CQCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// Send a CQ Beacon on a radio port. Must be in LISTEN state
|
|
|
|
|
|
|
|
DIGIMESSAGE Msg;
|
|
|
|
int Port = 0;
|
|
|
|
int OneBits = 0;
|
2023-05-25 14:17:53 +01:00
|
|
|
uint64_t MaskCopy = Session->LISTEN;
|
2022-08-28 09:35:46 +01:00
|
|
|
int Len;
|
|
|
|
UCHAR CQCALL[7];
|
|
|
|
char Empty[] = "";
|
|
|
|
char * ptr1 = &OrigCmdBuffer[3];
|
|
|
|
UCHAR * axptr = &Msg.DIGIS[0][0];
|
|
|
|
char * ptr2, *Context;
|
|
|
|
|
|
|
|
while (MaskCopy)
|
|
|
|
{
|
|
|
|
if (MaskCopy & 1)
|
|
|
|
OneBits++;
|
|
|
|
|
|
|
|
Port++;
|
|
|
|
MaskCopy = MaskCopy >> 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OneBits == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "You must enter LISTEN before calling CQ\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OneBits > 1)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "You can't call CQ if LISTENing on more than one port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Len = (int)strlen(OrigCmdBuffer) - 3;
|
|
|
|
|
|
|
|
if (Len < 0)
|
|
|
|
Len = 0;
|
|
|
|
|
|
|
|
memset(&Msg, 0, sizeof(Msg));
|
|
|
|
|
|
|
|
Msg.PORT = Port;
|
|
|
|
Msg.CTL = 3; // UI
|
|
|
|
|
|
|
|
// see if a Via specified
|
|
|
|
|
|
|
|
if (_memicmp(ptr1, "via ", 4) == 0)
|
|
|
|
{
|
|
|
|
ptr2 = strtok_s(ptr1 + 4, ",", &Context);
|
|
|
|
|
|
|
|
while (ptr2)
|
|
|
|
{
|
|
|
|
if (ConvToAX25(ptr2, axptr) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid via string\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
axptr += 7;
|
|
|
|
|
|
|
|
if (axptr == &Msg.DIGIS[7][0])
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Too many digis\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ptr1 = ptr2;
|
|
|
|
ptr2 = strtok_s(NULL, ",", &Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ptr1 is start of last digi call. We need to position to data
|
|
|
|
|
|
|
|
ptr1 = strchr(ptr1, ' ');
|
|
|
|
|
|
|
|
if (ptr1 == NULL)
|
|
|
|
ptr1 = Empty;
|
|
|
|
else
|
|
|
|
ptr1++ ; // to message
|
|
|
|
|
|
|
|
Len = (int)strlen(ptr1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ConvToAX25("CQ", CQCALL);
|
|
|
|
memcpy(Msg.DEST, CQCALL, 7);
|
2023-10-31 22:42:23 +00:00
|
|
|
Msg.DEST[6] |= 0x80; // set Command Bit
|
2022-08-28 09:35:46 +01:00
|
|
|
memcpy(Msg.ORIGIN, Session->L4USER, 7);
|
|
|
|
Msg.ORIGIN[6] ^= 0x1e; // Flip SSID
|
|
|
|
Msg.PID = 0xf0; // Data PID
|
|
|
|
memcpy(&Msg.L2DATA, ptr1, Len);
|
|
|
|
|
|
|
|
Send_AX_Datagram(&Msg, Len + 2, Port); // Len is Payload ie CTL, PID and Data
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "CQ sent\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TRANSPORTENTRY * SetupNewSession(TRANSPORTENTRY * Session, char * Bufferptr)
|
|
|
|
{
|
|
|
|
TRANSPORTENTRY * NewSess = L4TABLE;
|
|
|
|
int Index = 0;
|
|
|
|
|
|
|
|
while (Index < MAXCIRCUITS)
|
|
|
|
{
|
|
|
|
if (NewSess->L4USER[0] == 0)
|
|
|
|
{
|
|
|
|
// Got One
|
|
|
|
|
|
|
|
Session->L4CROSSLINK = NewSess;
|
|
|
|
NewSess->L4CROSSLINK = Session;
|
|
|
|
|
|
|
|
memcpy(NewSess->L4USER, Session->L4USER, 7);
|
|
|
|
memcpy(NewSess->L4MYCALL, Session->L4MYCALL, 7);
|
|
|
|
|
|
|
|
|
|
|
|
NewSess->CIRCUITINDEX = Index; //OUR INDEX
|
|
|
|
NewSess->CIRCUITID = NEXTID;
|
|
|
|
|
|
|
|
NEXTID++;
|
|
|
|
if (NEXTID == 0)
|
|
|
|
NEXTID++; // kEEP nON-ZERO
|
|
|
|
|
|
|
|
NewSess->SESSIONT1 = Session->SESSIONT1;
|
|
|
|
NewSess->L4WINDOW = (UCHAR)L4DEFAULTWINDOW;
|
|
|
|
|
|
|
|
return NewSess;
|
|
|
|
}
|
|
|
|
Index++;
|
|
|
|
NewSess++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Bufferptr)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry - System Tables Full\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID DoNetromConnect(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * Dest, BOOL Spy)
|
|
|
|
{
|
|
|
|
TRANSPORTENTRY * NewSess;
|
|
|
|
|
|
|
|
NewSess = SetupNewSession(Session, Bufferptr);
|
|
|
|
|
|
|
|
if (NewSess == NULL)
|
|
|
|
return; // Tables Full
|
|
|
|
|
|
|
|
NewSess->L4CIRCUITTYPE = SESSION + DOWNLINK;
|
|
|
|
|
|
|
|
NewSess->L4TARGET.DEST = Dest;
|
|
|
|
NewSess->L4STATE = 2; // CONNECTING
|
|
|
|
|
|
|
|
NewSess->SPYFLAG = Spy;
|
|
|
|
|
|
|
|
ReleaseBuffer((UINT *)REPLYBUFFER);
|
|
|
|
|
|
|
|
SENDL4CONNECT(NewSess);
|
|
|
|
|
|
|
|
L4CONNECTSOUT++;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL FindLink(UCHAR * LinkCall, UCHAR * OurCall, int Port, struct _LINKTABLE ** REQLINK)
|
|
|
|
{
|
|
|
|
struct _LINKTABLE * LINK = LINKS;
|
|
|
|
struct _LINKTABLE * FIRSTSPARE = NULL;
|
|
|
|
int n = MAXLINKS;
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (LINK->LINKCALL[0] == 0) // Spare
|
|
|
|
{
|
|
|
|
if (FIRSTSPARE == NULL)
|
|
|
|
FIRSTSPARE = LINK;
|
|
|
|
|
|
|
|
LINK++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((LINK->LINKPORT->PORTNUMBER == Port) && CompareCalls(LINK->LINKCALL, LinkCall) && CompareCalls(LINK->OURCALL, OurCall))
|
|
|
|
{
|
|
|
|
*REQLINK = LINK;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
LINK++;
|
|
|
|
}
|
|
|
|
// ENTRY NOT FOUND - FIRSTSPARE HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL
|
|
|
|
|
|
|
|
*REQLINK = FIRSTSPARE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID ATTACHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD);
|
|
|
|
|
|
|
|
VOID CMDC00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// PROCESS CONNECT COMMAND
|
|
|
|
|
|
|
|
TRANSPORTENTRY * NewSess;
|
|
|
|
|
|
|
|
int CONNECTPORT, Port;
|
|
|
|
BOOL CallEvenIfInNodes = FALSE;
|
|
|
|
char * ptr, *Context;
|
|
|
|
UCHAR axcalls[64];
|
|
|
|
UCHAR ourcall[7]; // Call we are using (may have SSID bits inverted
|
|
|
|
int ret;
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
struct _LINKTABLE * LINK;
|
|
|
|
int CQFLAG = 0; // NOT CQ CALL
|
|
|
|
BOOL Stay, Spy;
|
|
|
|
int n;
|
|
|
|
char TextCall[10];
|
|
|
|
int TextCallLen;
|
|
|
|
char PortString[10];
|
|
|
|
char cmdCopy[256];
|
|
|
|
struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)PORT;;
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef EXCLUDEBITS
|
|
|
|
|
|
|
|
if (CheckExcludeList(Session->L4USER) == FALSE)
|
|
|
|
{
|
|
|
|
// CONNECTS FROM THIS STATION ARE NOT ALLOWED
|
|
|
|
|
|
|
|
ReleaseBuffer((UINT *)REPLYBUFFER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (Session->LISTEN)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Can't connect while listening\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CONNECTPORT = 0; // NO PORT SPECIFIED
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
strcpy(cmdCopy, Context); // Save in case Telnet Connect
|
|
|
|
|
|
|
|
if (ptr == 0)
|
|
|
|
{
|
|
|
|
// No param
|
|
|
|
|
|
|
|
if (CFLAG) // C Command Disabled ?
|
|
|
|
{
|
|
|
|
// Convert to HOST (appl 32) command
|
|
|
|
|
|
|
|
//MOV _CMDPTR,OFFSET32 _HOSTCMD
|
|
|
|
//MOV _ALIASPTR,OFFSET32 _HOSTCMD + 32 * 31
|
|
|
|
|
|
|
|
//MOV _APPLMASK, 80000000H ; Internal Term
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Port = atoi(ptr);
|
|
|
|
|
|
|
|
if (Port)
|
|
|
|
{
|
|
|
|
// IF THERE IS NOTHING FOLLOWING THE NUMBER, ASSUME IT IS A
|
|
|
|
// NUMERIC ALIAS INSTEAD OF A PORT
|
|
|
|
|
|
|
|
sprintf(PortString, "%d", Port);
|
|
|
|
|
|
|
|
if (strlen(PortString) < (int)strlen(ptr))
|
|
|
|
goto NoPort;
|
|
|
|
|
|
|
|
PORT = GetPortTableEntryFromPortNum(Port);
|
|
|
|
|
|
|
|
if (PORT == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
EXTPORT = (struct _EXTPORTDATA *)PORT;
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr == 0)
|
|
|
|
{
|
|
|
|
// No param
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CONNECTPORT = Port;
|
|
|
|
|
|
|
|
if (strcmp(ptr, "CMS") == 0 || strcmp(ptr, "HOST") == 0) // In case someeone has CMS or HOST as an alias
|
|
|
|
goto Downlink;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
NoPort:
|
|
|
|
|
|
|
|
ptr[strlen(ptr)] = ' '; // Put param back together
|
|
|
|
|
|
|
|
if (ptr[0] == '!')
|
|
|
|
{
|
|
|
|
CallEvenIfInNodes = TRUE;
|
|
|
|
ptr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (memcmp(ptr, "RELAY ", 5) == 0 || memcmp(ptr, "SYNC ", 5) == 0)
|
|
|
|
{
|
|
|
|
// c p relay with extra parms
|
|
|
|
|
|
|
|
goto Downlink;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip call validation if using a ptc to allow 1:call, 2:call format
|
|
|
|
|
2022-10-03 15:55:07 +01:00
|
|
|
if (Port && PORT->PROTOCOL == 10 && memcmp(EXTPORT->PORT_DLL_NAME, "SCSPACTOR", 9) == 0)
|
2022-08-28 09:35:46 +01:00
|
|
|
{
|
|
|
|
char * p;
|
|
|
|
|
|
|
|
if (p = strstr(cmdCopy, " S "))
|
|
|
|
{
|
|
|
|
Stay = TRUE;
|
|
|
|
p++;
|
|
|
|
*p = ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p = strstr(cmdCopy, " Z "))
|
|
|
|
{
|
|
|
|
Spy = TRUE;
|
|
|
|
p++;
|
|
|
|
*p = ' ';
|
|
|
|
}
|
|
|
|
|
|
|
|
goto Downlink;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (DecodeCallString(ptr, &Stay, &Spy, &axcalls[0]) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Call\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Session->STAYFLAG = Stay;
|
|
|
|
|
|
|
|
TextCallLen = ConvFromAX25(axcalls, TextCall);
|
|
|
|
|
|
|
|
if (CallEvenIfInNodes)
|
|
|
|
goto Downlink;
|
|
|
|
|
|
|
|
// SEE IF CALL TO ANY OF OUR HOST SESSIONS - UNLESS DIGIS SPECIFIED
|
|
|
|
|
|
|
|
if (axcalls[7] == 0)
|
|
|
|
{
|
|
|
|
// If this connect is as a result of a command alias, don't check appls or we will loop
|
|
|
|
|
|
|
|
if (ALIASINVOKED == 0)
|
|
|
|
{
|
|
|
|
APPLCALLS * APPL = APPLCALLTABLE;
|
|
|
|
int n = NumberofAppls;
|
|
|
|
APPLMASK = 1;
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (memcmp(axcalls, APPL->APPLALIAS, 6) == 0 || CompareCalls(axcalls, APPL->APPLCALL))
|
|
|
|
{
|
|
|
|
// Call to an appl
|
|
|
|
|
|
|
|
// Convert to an APPL command, so any alias is actioned
|
|
|
|
|
|
|
|
// SEE IF THERE IS AN ALIAS DEFINDED FOR THIS COMMAND
|
|
|
|
|
|
|
|
if (APPL->APPLHASALIAS && APPL->APPLALIASVAL[0] != 0x20)
|
|
|
|
{
|
|
|
|
// COPY ALIAS TO COMMAND _BUFFER, THEN REENTER COMMAND HANDLER
|
|
|
|
|
|
|
|
memcpy(COMMANDBUFFER, APPL->APPLALIASVAL, ALIASLEN);
|
|
|
|
COMMANDBUFFER[80] = 0;
|
|
|
|
_strupr(COMMANDBUFFER);
|
|
|
|
memcpy(OrigCmdBuffer, APPL->APPLALIASVAL, ALIASLEN); // In case original case version needed
|
|
|
|
|
|
|
|
ALIASINVOKED = TRUE; // To prevent Alias Loops
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
// Copy Appl Command to Command Buffer. Ensure doesn't contain old command
|
|
|
|
|
|
|
|
memset(COMMANDBUFFER, ' ', 72);
|
|
|
|
memcpy(COMMANDBUFFER, APPL->APPLCMD, 12);
|
|
|
|
}
|
|
|
|
DoTheCommand(Session);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
APPL++;
|
|
|
|
APPLMASK <<= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (axcalls[7] == 0)
|
|
|
|
{
|
|
|
|
// SEE IF CALL TO ANOTHER NODE
|
|
|
|
|
|
|
|
struct DEST_LIST * Dest = DESTS;
|
|
|
|
int n = MAXDESTS;
|
|
|
|
|
|
|
|
if (axcalls[6] == 0x60) // if SSID, dont check aliases
|
|
|
|
{
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (memcmp(Dest->DEST_ALIAS, TextCall, 6) == 0)
|
|
|
|
{
|
|
|
|
DoNetromConnect(Session, Bufferptr, Dest, Spy);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Dest++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Dest = DESTS;
|
|
|
|
n = MAXDESTS;
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (CompareCalls(Dest->DEST_CALL, axcalls))
|
|
|
|
{
|
|
|
|
DoNetromConnect(Session, Bufferptr, Dest, Spy);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Dest++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Must be Downlink Connect
|
|
|
|
|
|
|
|
Downlink:
|
|
|
|
|
|
|
|
if (CONNECTPORT == 0 && NUMBEROFPORTS > 1)
|
|
|
|
{
|
|
|
|
// L2 NEEDS PORT NUMBER
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Downlink connect needs port number - C P CALLSIGN\r");
|
|
|
|
|
|
|
|
// Send Port List
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ENSURE PORT IS AVAILABLE FOR L2 USE
|
|
|
|
|
|
|
|
if (PORT->PROTOCOL >= 10) // Pactor=-style port?
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
|
|
|
|
// if Via PACTOR ARDOP WINMOR or VARA, convert to attach and call = Digi's are in AX25STRING (+7)
|
|
|
|
|
|
|
|
if (memcmp(&axcalls[7], &WINMOR[0], 6) == 0 ||
|
|
|
|
memcmp(&axcalls[7], &ARDOP[0], 6) == 0 ||
|
|
|
|
memcmp(&axcalls[7], &VARA[0], 6) == 0 ||
|
|
|
|
memcmp(&axcalls[7], &PACTORCALL[0], 6) == 0)
|
|
|
|
{
|
|
|
|
char newcmd[80];
|
|
|
|
|
|
|
|
TextCall[TextCallLen] = 0;
|
|
|
|
sprintf(newcmd, "%s %s", CmdTail, TextCall);
|
|
|
|
|
|
|
|
ATTACHCMD(Session, Bufferptr, newcmd, NULL);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If on a KAM or SCS with ax.25 on port 2, do an Attach command, then pass on connect
|
|
|
|
|
|
|
|
if (EXTPORT->MAXHOSTMODESESSIONS <= 1)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is not an ax.25 port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only Allow Attach VHF from Secure Applications or if PERMITGATEWAY is set
|
|
|
|
|
|
|
|
if (EXTPORT->PERMITGATEWAY == 0 && Session->Secure_Session == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, you are not allowed to use this port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
count = EXTPORT->MAXHOSTMODESESSIONS;
|
|
|
|
count--; // First is Pactor Stream, count is now last ax.25 session
|
|
|
|
|
|
|
|
while (count)
|
|
|
|
{
|
|
|
|
if (EXTPORT->ATTACHEDSESSIONS[count] == 0)
|
|
|
|
{
|
|
|
|
int Paclen, PortPaclen;
|
|
|
|
struct DATAMESSAGE * Buffer;
|
|
|
|
struct DATAMESSAGE Message = {0};
|
|
|
|
char Callstring[80];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
// Found a free one - use it
|
|
|
|
|
|
|
|
// See if TNC is OK
|
|
|
|
|
|
|
|
Message.PORT = count;
|
|
|
|
|
|
|
|
ret = PORT->PORTTXCHECKCODE(PORT, Message.PORT);
|
|
|
|
|
|
|
|
if ((ret & 0xff00) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Error - TNC Not Ready\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// GET CIRCUIT TABLE ENTRY FOR OTHER END OF LINK
|
|
|
|
|
|
|
|
NewSess = SetupNewSession(Session, Bufferptr);
|
|
|
|
if (NewSess == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// if a UZ7HO port, and the uplink is L2 or Uz7HO invert SSID bits
|
|
|
|
|
|
|
|
// We only get here if multisession
|
|
|
|
|
|
|
|
if (memcmp(EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0)
|
|
|
|
goto noFlip;
|
|
|
|
|
|
|
|
if ((Session->L4CIRCUITTYPE & BPQHOST))// host
|
|
|
|
goto noFlip;
|
|
|
|
|
|
|
|
if ((Session->L4CIRCUITTYPE & PACTOR))
|
|
|
|
{
|
|
|
|
// incoming is Pactorlike - see if UZ7HO
|
|
|
|
|
|
|
|
if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0)
|
|
|
|
goto noFlip;
|
|
|
|
else
|
|
|
|
NewSess->L4USER[6] ^= 0x1e; // UZ7HO Uplink - flip
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
// Must be L2 uplink - flip
|
|
|
|
|
|
|
|
NewSess->L4USER[6] ^= 0x1e; // Flip SSID
|
|
|
|
noFlip:
|
|
|
|
EXTPORT->ATTACHEDSESSIONS[count] = NewSess;
|
|
|
|
|
|
|
|
NewSess->KAMSESSION = count;
|
|
|
|
|
|
|
|
// Set paclen to lower of incoming and outgoing
|
|
|
|
|
|
|
|
Paclen = Session->SESSPACLEN; // Incoming PACLEN
|
|
|
|
|
|
|
|
if (Paclen == 0)
|
|
|
|
Paclen = 256; // 0 = 256
|
|
|
|
|
|
|
|
PortPaclen = PORT->PORTPACLEN;
|
|
|
|
|
|
|
|
if (PortPaclen == 0)
|
|
|
|
PortPaclen = 256; // 0 = 256
|
|
|
|
|
|
|
|
if (PortPaclen < Paclen)
|
|
|
|
Paclen = PortPaclen;
|
|
|
|
|
|
|
|
NewSess->SESSPACLEN = Paclen;
|
|
|
|
Session->SESSPACLEN = Paclen;
|
|
|
|
|
|
|
|
NewSess->L4STATE = 5;
|
|
|
|
NewSess->L4CIRCUITTYPE = DOWNLINK + PACTOR;
|
|
|
|
NewSess->L4TARGET.PORT = PORT;
|
|
|
|
|
|
|
|
// Send the connect command to the TNC
|
|
|
|
|
|
|
|
Buffer = REPLYBUFFER;
|
|
|
|
|
|
|
|
Buffer->PORT = count;
|
|
|
|
Buffer->PID = 0xf0;
|
|
|
|
|
|
|
|
// if on Telnet Port convert use original cmd tail
|
|
|
|
|
|
|
|
// Why just on telnet - what not all ports??
|
|
|
|
|
|
|
|
if (memcmp(EXTPORT->PORT_DLL_NAME, "TELNET", 6) == 0 || memcmp(EXTPORT->PORT_DLL_NAME, "SCSPACTOR", 9) == 0)
|
|
|
|
{
|
|
|
|
NewSess->Secure_Session = Session->Secure_Session;
|
|
|
|
len = sprintf(Callstring,"C %s", cmdCopy);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TextCall[TextCallLen] = 0;
|
|
|
|
|
|
|
|
len = sprintf(Callstring,"C %s", TextCall);
|
|
|
|
|
|
|
|
if (axcalls[7])
|
|
|
|
{
|
|
|
|
int digi = 7;
|
|
|
|
|
|
|
|
// we have digis
|
|
|
|
|
|
|
|
len += sprintf(&Callstring[len], " via");
|
|
|
|
|
|
|
|
while (axcalls[digi])
|
|
|
|
{
|
|
|
|
TextCall[ConvFromAX25(&axcalls[digi], TextCall)] = 0;
|
|
|
|
len += sprintf(&Callstring[len], " %s", TextCall);
|
|
|
|
digi += 7;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Callstring[len++] = 13;
|
|
|
|
Callstring[len] = 0;
|
|
|
|
|
|
|
|
Buffer->LENGTH = len + MSGHDDRLEN + 1;
|
|
|
|
memcpy(Buffer->L2DATA, Callstring, len);
|
|
|
|
C_Q_ADD(&PORT->PORTTX_Q, (UINT *)Buffer);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Error - No free streams on this port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((Session->L4CIRCUITTYPE & BPQHOST) == 0 && PORT->PORTL3FLAG)
|
|
|
|
{
|
|
|
|
//Port only for L3
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is for internode traffic only\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PORT->PortUIONLY)
|
|
|
|
{
|
|
|
|
//Port only for UI
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, port is for UI traffic only\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Session->L4USER[6] == 0x42 || Session->L4USER[6] == 0x44)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry - Can't make ax.25 calls with SSID of T or R\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get Session Entry for Downlink
|
|
|
|
|
|
|
|
NewSess = SetupNewSession(Session, Bufferptr);
|
|
|
|
if (NewSess == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
NewSess->L4CIRCUITTYPE = L2LINK + DOWNLINK;
|
|
|
|
|
|
|
|
// FORMAT LINK TABLE ENTRY FOR THIS CONNECTION
|
|
|
|
|
|
|
|
memcpy(ourcall, NewSess->L4USER, 7);
|
|
|
|
|
|
|
|
// SSID SWAP TEST - LEAVE ALONE FOR HOST or Pactor like (unless UZ7HO)
|
|
|
|
|
|
|
|
if ((Session->L4CIRCUITTYPE & BPQHOST))// host
|
|
|
|
goto noFlip3;
|
|
|
|
|
|
|
|
if ((Session->L4CIRCUITTYPE & PACTOR))
|
|
|
|
{
|
|
|
|
// incoming is Pactorlike - see if UZ7HO
|
|
|
|
|
|
|
|
if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0)
|
|
|
|
goto noFlip3;
|
|
|
|
|
|
|
|
if (Session->L4TARGET.EXTPORT->MAXHOSTMODESESSIONS < 2) // Not multisession
|
|
|
|
goto noFlip3;
|
|
|
|
|
|
|
|
ourcall[6] ^= 0x1e; // UZ7HO Uplink - flip
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
// Must be L2 uplink - flip
|
|
|
|
|
|
|
|
ourcall[6] ^= 0x1e; // Flip SSID
|
|
|
|
|
|
|
|
noFlip3:
|
|
|
|
|
|
|
|
// SET UP NEW SESSION (OR RESET EXISTING ONE)
|
|
|
|
|
|
|
|
FindLink(axcalls, ourcall, Port, &LINK);
|
|
|
|
|
|
|
|
if (LINK == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry - System Tables Full\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
|
|
|
// Should release NewSess
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(LINK->LINKCALL, axcalls, 7);
|
|
|
|
memcpy(LINK->OURCALL, ourcall, 7);
|
|
|
|
|
|
|
|
LINK->LINKPORT = PORT;
|
|
|
|
|
|
|
|
LINK->L2TIME = PORT->PORTT1;
|
|
|
|
|
|
|
|
// Copy Digis
|
|
|
|
|
|
|
|
n = 7;
|
|
|
|
ptr = &LINK->DIGIS[0];
|
|
|
|
|
|
|
|
while (axcalls[n])
|
|
|
|
{
|
|
|
|
memcpy(ptr, &axcalls[n], 7);
|
|
|
|
n += 7;
|
|
|
|
ptr += 7;
|
|
|
|
|
|
|
|
LINK->L2TIME += 2 * PORT->PORTT1; // ADJUST TIMER VALUE FOR 1 DIGI
|
|
|
|
}
|
|
|
|
|
|
|
|
LINK->LINKTYPE = 2; // DOWNLINK
|
|
|
|
LINK->LINKWINDOW = PORT->PORTWINDOW;
|
|
|
|
|
|
|
|
RESET2(LINK); // RESET ALL FLAGS
|
|
|
|
|
|
|
|
if (CMD->String[0] == 'N' && SUPPORT2point2)
|
|
|
|
LINK->L2STATE = 1; // New (2.2) send XID
|
|
|
|
else
|
|
|
|
LINK->L2STATE = 2; // Send SABM
|
|
|
|
|
|
|
|
LINK->CIRCUITPOINTER = NewSess;
|
|
|
|
|
|
|
|
NewSess->L4TARGET.LINK = LINK;
|
|
|
|
|
|
|
|
if (PORT->PORTPACLEN)
|
|
|
|
NewSess->SESSPACLEN = Session->SESSPACLEN = PORT->PORTPACLEN;
|
|
|
|
|
|
|
|
if (CQFLAG == 0) // if a CQ CALL DONT SEND SABM
|
|
|
|
{
|
|
|
|
if (LINK->L2STATE == 1)
|
|
|
|
L2SENDXID(LINK);
|
|
|
|
else
|
|
|
|
SENDSABM(LINK);
|
|
|
|
}
|
|
|
|
ReleaseBuffer((UINT *)REPLYBUFFER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL DecodeCallString(char * Calls, BOOL * Stay, BOOL * Spy, UCHAR * AXCalls)
|
|
|
|
{
|
|
|
|
// CONVERT CALL + OPTIONAL DIGI STRING TO AX25, RETURN
|
|
|
|
// CONVERTED STRING IN AXCALLS. Return FALSE if invalied
|
|
|
|
|
|
|
|
char * axptr = AXCalls;
|
|
|
|
char * ptr, *Context;
|
|
|
|
int CQFLAG = 0; // NOT CQ CALL
|
|
|
|
int n = 8; // Max digis
|
|
|
|
|
|
|
|
*Stay = 0;
|
|
|
|
*Spy = 0;
|
|
|
|
|
|
|
|
memset(AXCalls, 0, 64);
|
|
|
|
|
|
|
|
ptr = strtok_s(Calls, " ,", &Context);
|
|
|
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
// First field is Call
|
|
|
|
|
|
|
|
if (ConvToAX25(ptr, axptr) == 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
axptr += 7;
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ,", &Context);
|
|
|
|
|
|
|
|
while (ptr && n--)
|
|
|
|
{
|
|
|
|
// NEXT FIELD = COULD BE CALLSIGN, VIA, OR S (FOR STAY)
|
|
|
|
|
|
|
|
if (strcmp(ptr, "S") == 0)
|
|
|
|
*Stay = TRUE;
|
|
|
|
else if (strcmp(ptr, "Z") == 0)
|
|
|
|
*Spy = TRUE;
|
|
|
|
else if (memcmp(ptr, "VIA", (int)strlen(ptr)) == 0)
|
|
|
|
{
|
|
|
|
} //skip via
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Convert next digi
|
|
|
|
|
|
|
|
if (ConvToAX25(ptr, axptr) == 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
axptr += 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ,", &Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID LINKCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// PROCESS *** LINKED to CALLSIGN
|
|
|
|
|
|
|
|
char * ptr, *Context;
|
|
|
|
UCHAR axcall[7];
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (LINKEDFLAG == 'Y' || // UNCONDITIONAL?
|
|
|
|
(LINKEDFLAG == 'A' &&
|
|
|
|
((Session->L4CIRCUITTYPE & BPQHOST) || Session->Secure_Session || Session->PASSWORD == 0xffff)))
|
|
|
|
{
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
if (ptr)
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
ret = ConvToAX25Ex(ptr, axcall);
|
|
|
|
|
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
memcpy(Session->L4USER, axcall, 7);
|
|
|
|
strcpy(Bufferptr, OKMSG);
|
|
|
|
Bufferptr += (int)strlen(OKMSG);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(Bufferptr, BADMSG);
|
|
|
|
Bufferptr += (int)strlen(BADMSG);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(Bufferptr, PASSWORDMSG, LPASSMSG);
|
|
|
|
Bufferptr += LPASSMSG;
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
int CompareNode(const void *a, const void *b);
|
|
|
|
int CompareAlias(const void *a, const void *b);
|
|
|
|
|
|
|
|
char * DoOneNode(TRANSPORTENTRY * Session, char * Bufferptr, struct DEST_LIST * Dest)
|
|
|
|
{
|
|
|
|
char Normcall[10];
|
|
|
|
char Alias[10];
|
|
|
|
struct NR_DEST_ROUTE_ENTRY * NRRoute;
|
|
|
|
struct DEST_ROUTE_ENTRY * Route;
|
|
|
|
struct ROUTE * Neighbour;
|
|
|
|
int i, Active, len;
|
|
|
|
|
|
|
|
Alias[6] = 0;
|
|
|
|
|
|
|
|
memcpy(Alias, Dest->DEST_ALIAS, 6);
|
|
|
|
strlop(Alias, ' ');
|
|
|
|
|
|
|
|
Normcall[ConvFromAX25(Dest->DEST_CALL, Normcall)] = 0;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Routes to: %s:%s", Alias, Normcall);
|
|
|
|
|
|
|
|
if (Dest->DEST_COUNT)
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, " RTT=%4.2f FR=%d %c %.1d\r",
|
|
|
|
Dest->DEST_RTT /1000.0, Dest->DEST_COUNT,
|
|
|
|
(Dest->DEST_STATE & 0x40)? 'B':' ', (Dest->DEST_STATE & 63));
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
NRRoute = &Dest->NRROUTE[0];
|
|
|
|
|
|
|
|
Active = Dest->DEST_ROUTE;
|
|
|
|
|
|
|
|
for (i = 1; i < 4; i++)
|
|
|
|
{
|
|
|
|
Neighbour = NRRoute->ROUT_NEIGHBOUR;
|
|
|
|
|
|
|
|
if (Neighbour)
|
|
|
|
{
|
|
|
|
len = ConvFromAX25(Neighbour->NEIGHBOUR_CALL, Normcall);
|
|
|
|
Normcall[len] = 0;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%c %d %d %d %s\r",
|
|
|
|
(Active == i)?'>':' ',NRRoute->ROUT_QUALITY, NRRoute->ROUT_OBSCOUNT, Neighbour->NEIGHBOUR_PORT, Normcall);
|
|
|
|
}
|
|
|
|
NRRoute++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// DISPLAY INP3 ROUTES
|
|
|
|
|
|
|
|
Route = &Dest->ROUTE[0];
|
|
|
|
|
|
|
|
Active = Dest->DEST_ROUTE;
|
|
|
|
|
|
|
|
for (i = 1; i < 4; i++)
|
|
|
|
{
|
|
|
|
Neighbour = Route->ROUT_NEIGHBOUR;
|
|
|
|
|
|
|
|
if (Neighbour)
|
|
|
|
{
|
|
|
|
double srtt = Route->SRTT/1000.0;
|
|
|
|
|
|
|
|
len = ConvFromAX25(Neighbour->NEIGHBOUR_CALL, Normcall);
|
|
|
|
Normcall[len] = 0;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%c %d %4.2fs %d %s\r",
|
|
|
|
(Active == i + 3)?'>':' ',Route->Hops, srtt, Neighbour->NEIGHBOUR_PORT, Normcall);
|
|
|
|
}
|
|
|
|
Route++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Bufferptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int DoViaEntry(struct DEST_LIST * Dest, int n, char * line, int cursor)
|
|
|
|
{
|
|
|
|
char Portcall[10];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (Dest->NRROUTE[n].ROUT_NEIGHBOUR != 0 && Dest->NRROUTE[n].ROUT_NEIGHBOUR->INP3Node == 0)
|
|
|
|
{
|
|
|
|
len=ConvFromAX25(Dest->NRROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Portcall);
|
|
|
|
Portcall[len]=0;
|
|
|
|
|
|
|
|
len=sprintf(&line[cursor],"%s %d %d ",
|
|
|
|
Portcall,
|
|
|
|
Dest->NRROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_PORT,
|
|
|
|
Dest->NRROUTE[n].ROUT_QUALITY);
|
|
|
|
|
|
|
|
cursor+=len;
|
|
|
|
|
|
|
|
if (Dest->NRROUTE[n].ROUT_OBSCOUNT > 127)
|
|
|
|
{
|
|
|
|
len=sprintf(&line[cursor],"! ");
|
|
|
|
cursor+=len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
int DoINP3ViaEntry(struct DEST_LIST * Dest, int n, char * line, int cursor)
|
|
|
|
{
|
|
|
|
char Portcall[10];
|
|
|
|
int len;
|
|
|
|
double srtt;
|
|
|
|
|
|
|
|
if (Dest->ROUTE[n].ROUT_NEIGHBOUR != 0)
|
|
|
|
{
|
|
|
|
srtt = Dest->ROUTE[n].SRTT/1000.0;
|
|
|
|
|
|
|
|
len=ConvFromAX25(Dest->ROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, Portcall);
|
|
|
|
Portcall[len]=0;
|
|
|
|
|
|
|
|
len=sprintf(&line[cursor],"%s %d %d %4.2fs ",
|
|
|
|
Portcall,
|
|
|
|
Dest->ROUTE[n].ROUT_NEIGHBOUR->NEIGHBOUR_PORT,
|
|
|
|
Dest->ROUTE[n].Hops, srtt);
|
|
|
|
|
|
|
|
cursor+=len;
|
|
|
|
|
|
|
|
if (Dest->NRROUTE[n].ROUT_OBSCOUNT > 127)
|
|
|
|
{
|
|
|
|
len=sprintf(&line[cursor],"! ");
|
|
|
|
cursor+=len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return cursor;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WildCmp(char * pattern, char * string)
|
|
|
|
{
|
|
|
|
// Check if string is at end or not.
|
|
|
|
|
|
|
|
if (*pattern == '\0')
|
|
|
|
return *string == '\0';
|
|
|
|
|
|
|
|
// Check for single character missing or match
|
|
|
|
|
|
|
|
if (*pattern == '?' || *pattern == *string)
|
|
|
|
return *string != '\0' && WildCmp(pattern + 1, string + 1);
|
|
|
|
|
|
|
|
if (*pattern == '*')
|
|
|
|
{
|
|
|
|
// Check for multiple character missing
|
|
|
|
|
|
|
|
return WildCmp(pattern + 1, string) || (*string != '\0' && WildCmp(pattern, string + 1));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CMDN00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
struct DEST_LIST * Dest = DESTS;
|
|
|
|
int count = MAXDESTS, i;
|
|
|
|
char Normcall[10];
|
|
|
|
char Alias[10];
|
|
|
|
int Width = 4;
|
|
|
|
int x = 0, n = 0;
|
|
|
|
struct DEST_LIST * List[1000];
|
|
|
|
char Param = 0;
|
|
|
|
char * ptr, * param2,* Context;
|
|
|
|
char Nodeline[21];
|
|
|
|
char AXCALL[7];
|
|
|
|
char * Call;
|
|
|
|
char * Qualptr;
|
|
|
|
int Qual;
|
|
|
|
char line[160];
|
|
|
|
int cursor, len;
|
|
|
|
UCHAR axcall[7];
|
|
|
|
int SavedOBSINIT = OBSINIT;
|
|
|
|
struct ROUTE * ROUTE = NULL;
|
|
|
|
char Pattern[80] = "";
|
|
|
|
char * firststar;
|
|
|
|
int minqual = 0;
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
param2 = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
if (strcmp(ptr, "ADD") == 0)
|
|
|
|
goto NODE_ADD;
|
|
|
|
|
|
|
|
if (strcmp(ptr, "DEL") == 0)
|
|
|
|
goto NODE_DEL;
|
|
|
|
|
|
|
|
if (strcmp(ptr, "VIA") == 0)
|
|
|
|
goto NODE_VIA;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
// Could be C or a pattern. Accept C pattern or pattern C
|
|
|
|
|
|
|
|
if ((int)strlen(ptr) > 1)
|
|
|
|
{
|
|
|
|
strcpy(Pattern, ptr);
|
|
|
|
if (param2 && param2[0] == 'C')
|
|
|
|
Param = 'C';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Param = ptr[0];
|
|
|
|
if (param2)
|
|
|
|
strcpy(Pattern, param2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pattern >nnn selects nodes with at least that quality
|
|
|
|
|
|
|
|
if (Pattern[0] == '>')
|
|
|
|
{
|
|
|
|
minqual = atoi(&Pattern[1]);
|
|
|
|
Pattern[0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We need to pick out CALL or CALL* from other patterns (as call use detail display)
|
|
|
|
|
|
|
|
firststar = strchr(Pattern, '*');
|
|
|
|
|
|
|
|
if ((firststar && *(firststar + 1) != 0)|| strchr(Pattern, '?')) //(* not on end)
|
|
|
|
|
|
|
|
// definitely pattern
|
|
|
|
|
|
|
|
goto DoNodePattern;
|
|
|
|
|
|
|
|
// If it works as CALL*, process, else drop through
|
|
|
|
|
|
|
|
if (Pattern[0])
|
|
|
|
{
|
|
|
|
UCHAR AXCall[8];
|
|
|
|
int count;
|
|
|
|
int paramlen = (int)strlen(ptr);
|
|
|
|
char parampadded[20];
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
Alias[8] = 0;
|
|
|
|
strcpy(parampadded, Pattern);
|
|
|
|
strcat(parampadded, " ");
|
|
|
|
|
|
|
|
ConvToAX25(Pattern, AXCall);
|
|
|
|
|
|
|
|
// if * on end, list all ssids
|
|
|
|
|
|
|
|
if (firststar)
|
|
|
|
{
|
|
|
|
AXCall[6] = 0;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
while (AXCall[6] < 32)
|
|
|
|
{
|
|
|
|
Dest = DESTS;
|
|
|
|
|
|
|
|
for (count = 0; count < MAXDESTS; count++)
|
|
|
|
{
|
|
|
|
if (memcmp(Dest->DEST_ALIAS, parampadded, 6) == 0 || CompareCalls(Dest->DEST_CALL, AXCall))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Dest++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count < MAXDESTS)
|
|
|
|
{
|
|
|
|
Bufferptr = DoOneNode(Session, Bufferptr, Dest);
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
|
|
|
|
AXCall[6] += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n) // Found Some
|
|
|
|
{
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Dest = DESTS; // Reset
|
|
|
|
|
|
|
|
// Drop through to try as pattern
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// process as just call
|
|
|
|
|
|
|
|
for (count = 0; count < MAXDESTS; count++)
|
|
|
|
{
|
|
|
|
if (memcmp(Dest->DEST_ALIAS, parampadded, 6) == 0 || CompareCalls(Dest->DEST_CALL, AXCall))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Dest++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count == MAXDESTS)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not found\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = DoOneNode(Session, Bufferptr, Dest);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DoNodePattern:
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Nodes\r");
|
|
|
|
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
if (Dest->DEST_CALL[0] != 0)
|
|
|
|
{
|
|
|
|
if (Dest->NRROUTE->ROUT_QUALITY >= minqual)
|
|
|
|
if (Param != 'T' || Dest->DEST_COUNT)
|
|
|
|
List[n++] = Dest;
|
|
|
|
|
|
|
|
if (n > 999)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Dest++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Param == 'C')
|
|
|
|
qsort(List, n, sizeof(void *), CompareNode);
|
|
|
|
else
|
|
|
|
qsort(List, n, sizeof(void *), CompareAlias);
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
int len = ConvFromAX25(List[i]->DEST_CALL, Normcall);
|
|
|
|
Normcall[len]=0;
|
|
|
|
|
|
|
|
memcpy(Alias, List[i]->DEST_ALIAS, 6);
|
|
|
|
Alias[6] = 0;
|
|
|
|
strlop(Alias, ' ');
|
|
|
|
|
|
|
|
if (strlen(Alias))
|
|
|
|
strcat(Alias, ":");
|
|
|
|
|
|
|
|
if (Alias[0] == '#' && HIDENODES == 1 && Param != '*') // Hidden Node and not N * command
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (Pattern[0])
|
|
|
|
if (!WildCmp(Pattern, Normcall) && !WildCmp(Pattern, Alias))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (Param == 'T')
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s%s RTT=%4.2f Frames = %d %c %.1d\r",
|
|
|
|
Alias, Normcall, List[i]->DEST_RTT /1000.0, List[i]->DEST_COUNT,
|
|
|
|
(List[i]->DEST_STATE & 0x40)? 'B':' ', (List[i]->DEST_STATE & 63));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
len = sprintf(Nodeline, "%s%s", Alias, Normcall);
|
|
|
|
memset(&Nodeline[len], ' ', 20 - len);
|
|
|
|
Nodeline[20] = 0;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", Nodeline);
|
|
|
|
|
|
|
|
if (++x == Width)
|
|
|
|
{
|
|
|
|
x = 0;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x)
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
goto SendReply;
|
|
|
|
|
|
|
|
|
|
|
|
NODE_VIA:
|
|
|
|
|
|
|
|
// List Nodes reachable via a neighbour
|
|
|
|
|
|
|
|
ptr = param2;
|
|
|
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Call\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
ConvToAX25(ptr, AXCALL);
|
|
|
|
|
|
|
|
Dest = DESTS;
|
|
|
|
|
|
|
|
Dest-=1;
|
|
|
|
|
|
|
|
for (count=0; count<MAXDESTS; count++)
|
|
|
|
{
|
|
|
|
Dest+=1;
|
|
|
|
|
|
|
|
if (Dest->NRROUTE[0].ROUT_NEIGHBOUR == 0 && Dest->ROUTE[0].ROUT_NEIGHBOUR == 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
if ((Dest->NRROUTE[0].ROUT_NEIGHBOUR && CompareCalls(Dest->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL))
|
|
|
|
|| (Dest->NRROUTE[1].ROUT_NEIGHBOUR && CompareCalls(Dest->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL))
|
|
|
|
|| (Dest->NRROUTE[2].ROUT_NEIGHBOUR && CompareCalls(Dest->NRROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL))
|
|
|
|
|
|
|
|
|| (Dest->ROUTE[0].ROUT_NEIGHBOUR && CompareCalls(Dest->ROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL))
|
|
|
|
|| (Dest->ROUTE[1].ROUT_NEIGHBOUR && CompareCalls(Dest->ROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL))
|
|
|
|
|| (Dest->ROUTE[2].ROUT_NEIGHBOUR && CompareCalls(Dest->ROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL, AXCALL)))
|
|
|
|
{
|
|
|
|
len=ConvFromAX25(Dest->DEST_CALL,Normcall);
|
|
|
|
|
|
|
|
Normcall[len]=0;
|
|
|
|
|
|
|
|
memcpy(Alias,Dest->DEST_ALIAS,6);
|
|
|
|
|
|
|
|
Alias[6]=0;
|
|
|
|
|
|
|
|
for (i=0;i<6;i++)
|
|
|
|
{
|
|
|
|
if (Alias[i] == ' ')
|
|
|
|
Alias[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor=sprintf(line,"%s:%s ", Alias,Normcall);
|
|
|
|
|
|
|
|
cursor = DoViaEntry(Dest, 0, line, cursor);
|
|
|
|
cursor = DoViaEntry(Dest, 1, line, cursor);
|
|
|
|
cursor = DoViaEntry(Dest, 2, line, cursor);
|
|
|
|
cursor = DoINP3ViaEntry(Dest, 0, line, cursor);
|
|
|
|
cursor = DoINP3ViaEntry(Dest, 1, line, cursor);
|
|
|
|
cursor = DoINP3ViaEntry(Dest, 2, line, cursor);
|
|
|
|
|
|
|
|
line[cursor++]='\r';
|
|
|
|
line[cursor++]=0;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
goto SendReply;
|
|
|
|
|
|
|
|
NODE_ADD:
|
|
|
|
|
|
|
|
// FORMAT IS NODE ADD ALIAS:CALL QUAL ROUTE PORT
|
|
|
|
|
|
|
|
|
|
|
|
if (Session->PASSWORD != 0xFFFF)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG);
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = param2;
|
|
|
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Alias:Call\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
Call = strlop(ptr, ':');
|
|
|
|
|
|
|
|
if (Call == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Alias:Call\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ConvToAX25(Call, AXCALL);
|
|
|
|
|
|
|
|
Qualptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (Qualptr == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Quality missing\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
Qual = atoi(Qualptr);
|
|
|
|
|
|
|
|
if (Qual < MINQUAL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Quality is below MINQUAL\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FindDestination(AXCALL, &Dest))
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Node already in Table\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Dest == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Node Table Full\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(Dest->DEST_CALL, AXCALL, 7);
|
|
|
|
memcpy(Dest->DEST_ALIAS, ptr, 6);
|
|
|
|
|
|
|
|
NUMBEROFNODES++;
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr == NULL || ptr[0] == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Neighbour missing\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ConvToAX25(ptr, axcall) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Neighbour\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
int Port;
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
if (ptr == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port missing\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
Port = atoi(ptr);
|
|
|
|
|
|
|
|
if (Context[0] == '!')
|
|
|
|
{
|
|
|
|
OBSINIT = 255; //; SPECIAL FOR LOCKED
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FindNeighbour(axcall, Port, &ROUTE))
|
|
|
|
{
|
|
|
|
PROCROUTES(Dest, ROUTE, Qual);
|
|
|
|
}
|
|
|
|
|
|
|
|
OBSINIT = SavedOBSINIT;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Node Added\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
PNODE48:
|
|
|
|
|
|
|
|
|
|
|
|
; GET NEIGHBOURS FOR THIS DESTINATION
|
|
|
|
;
|
|
|
|
CALL CONVTOAX25
|
|
|
|
JNZ SHORT BADROUTE
|
|
|
|
;
|
|
|
|
CALL GETVALUE
|
|
|
|
MOV SAVEPORT,AL ; SET PORT FOR _FINDNEIGHBOUR
|
|
|
|
|
|
|
|
CALL GETVALUE
|
|
|
|
MOV ROUTEQUAL,AL
|
|
|
|
;
|
|
|
|
MOV ESI,OFFSET32 AX25CALL
|
|
|
|
|
|
|
|
PUSH EBX ; SAVE DEST
|
|
|
|
CALL _FINDNEIGHBOUR
|
|
|
|
MOV EAX,EBX ; ROUTE TO AX
|
|
|
|
POP EBX
|
|
|
|
|
|
|
|
JZ SHORT NOTBADROUTE
|
|
|
|
|
|
|
|
JMP SHORT BADROUTE
|
|
|
|
|
|
|
|
NOTBADROUTE:
|
|
|
|
;
|
|
|
|
; UPDATE ROUTE LIST FOR THIS DEST
|
|
|
|
;
|
|
|
|
MOV ROUT1_NEIGHBOUR[EBX],EAX
|
|
|
|
MOV AL,ROUTEQUAL
|
|
|
|
MOV ROUT1_QUALITY[EBX],AL
|
|
|
|
MOV ROUT1_OBSCOUNT[EBX],255 ; LOCKED
|
|
|
|
;
|
|
|
|
POP EDI
|
|
|
|
POP EBX
|
|
|
|
|
|
|
|
INC _NUMBEROFNODES
|
|
|
|
|
|
|
|
JMP SENDOK
|
|
|
|
|
|
|
|
BADROUTE:
|
|
|
|
;
|
|
|
|
; KILL IT
|
|
|
|
;
|
|
|
|
MOV ECX,TYPE DEST_LIST
|
|
|
|
MOV EDI,EBX
|
|
|
|
MOV AL,0
|
|
|
|
REP STOSB
|
|
|
|
|
|
|
|
JMP BADROUTECMD
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
goto SendReply;
|
|
|
|
|
|
|
|
|
|
|
|
NODE_DEL:
|
|
|
|
|
|
|
|
if (Session->PASSWORD != 0xFFFF)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG);
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = param2;
|
|
|
|
|
|
|
|
if (ptr == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Missing Call\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(ptr, "ALL") == 0)
|
|
|
|
{
|
|
|
|
struct DEST_LIST * DEST = DESTS;
|
|
|
|
int n = MAXDESTS;
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (DEST->DEST_CALL[0] && ((DEST->DEST_STATE & 0x80) == 0)) // Don't delete appl node
|
|
|
|
REMOVENODE(DEST);
|
|
|
|
|
|
|
|
DEST++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ClearNodes();
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "All Nodes Deleted\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConvToAX25(ptr, AXCALL);
|
|
|
|
|
|
|
|
if (FindDestination(AXCALL, &Dest) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not Found\r");
|
|
|
|
goto SendReply;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Dest->DEST_STATE & 0x80)
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "APPL Node - Can't delete\r");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
REMOVENODE(Dest);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Node Deleted\r");
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Node Deleted\r");
|
|
|
|
|
|
|
|
SendReply:
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CMDQUERY(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD)
|
|
|
|
{
|
|
|
|
// DISPLAY AVAILABLE COMMANDS
|
|
|
|
|
|
|
|
int n;
|
|
|
|
char * ptr;
|
|
|
|
char ApplList[2048];
|
|
|
|
char * out = ApplList;
|
|
|
|
|
|
|
|
CMDX * CMD = &COMMANDS[APPL1];
|
|
|
|
|
|
|
|
for (n = 0; n < NumberofAppls; n++)
|
|
|
|
{
|
|
|
|
ptr = &CMD->String[0];
|
|
|
|
if (*(ptr) != '*')
|
|
|
|
{
|
|
|
|
while (*ptr != ' ')
|
|
|
|
{
|
|
|
|
*(out++) = *(ptr++);
|
|
|
|
}
|
|
|
|
*(out++) = ' ';
|
|
|
|
}
|
|
|
|
CMD++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*(out) = 0;
|
|
|
|
|
|
|
|
n = CMDLISTLEN;
|
|
|
|
|
|
|
|
if (NEEDMH == 0)
|
|
|
|
n -= 7; // Dont show MH
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s%s\r", ApplList, CMDLIST);
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
char * FormatMH(MHSTRUC * MH, char Format);
|
|
|
|
|
|
|
|
VOID MHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// DISPLAY HEARD LIST
|
|
|
|
|
|
|
|
int Port = 0, sess = 0;
|
|
|
|
char * ptr, *Context, *pattern;
|
|
|
|
struct PORTCONTROL * PORT = NULL;
|
|
|
|
MHSTRUC * MH;
|
|
|
|
int count = MHENTRIES;
|
|
|
|
int n;
|
|
|
|
char Normcall[20];
|
|
|
|
char From[10];
|
|
|
|
char DigiList[100];
|
|
|
|
char * Output;
|
|
|
|
int len;
|
|
|
|
char Digi = 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Note that the MHDIGIS field may contain rubbish. You have to check End of Address bit to find
|
|
|
|
// how many digis there are
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
2023-10-10 22:07:04 +01:00
|
|
|
if (ptr == NULL || ptr[0] == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port Number needed eg MH 1\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
pattern = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (pattern)
|
|
|
|
_strupr(pattern); // Optional filter
|
|
|
|
|
|
|
|
MH = PORT->PORTMHEARD;
|
|
|
|
|
|
|
|
if (MH == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "MHEARD not enabled on that port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pattern && strstr(pattern, "CLEAR"))
|
|
|
|
{
|
|
|
|
if (Session->Secure_Session)
|
|
|
|
{
|
|
|
|
memset(MH, 0, MHENTRIES * sizeof(MHSTRUC));
|
|
|
|
SaveMH();
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Heard List for Port %d Cleared\r", Port);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "MH Clear needs SYSOP status\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (CMD->String[2] == 'V') // MHV
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "MHeard List %s for Port %d\r", MYNODECALL, Port);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Callsign Last heard Pkts RX via Digi ;) \r");
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "--------- ----------- ------- ------------------------------------------\r");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
if (pattern)
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Heard List for Port %d filtered by %s\r", Port, pattern);
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Heard List for Port %d\r", Port);
|
|
|
|
}
|
|
|
|
while (count--)
|
|
|
|
{
|
|
|
|
if (MH->MHCALL[0] == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
Digi = 0;
|
|
|
|
|
|
|
|
len = ConvFromAX25(MH->MHCALL, Normcall);
|
|
|
|
|
|
|
|
Normcall[len++] = MH->MHDIGI;
|
|
|
|
Normcall[len++] = 0;
|
|
|
|
|
|
|
|
if (pattern && strstr(Normcall, pattern) == 0)
|
|
|
|
{
|
|
|
|
MH++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
n = 8; // Max number of digi-peaters
|
|
|
|
|
|
|
|
ptr = &MH->MHCALL[6]; // End of Address bit
|
|
|
|
|
|
|
|
Output = &DigiList[0];
|
|
|
|
|
|
|
|
if ((*ptr & 1) == 0)
|
|
|
|
{
|
|
|
|
// at least one digi
|
|
|
|
|
|
|
|
strcpy(Output, "via ");
|
|
|
|
Output += 4;
|
|
|
|
|
|
|
|
while ((*ptr & 1) == 0)
|
|
|
|
{
|
|
|
|
// MORE TO COME
|
|
|
|
|
|
|
|
From[ConvFromAX25(ptr + 1, From)] = 0;
|
|
|
|
Output += sprintf((char *)Output, "%s", From);
|
|
|
|
|
|
|
|
ptr += 7;
|
|
|
|
n--;
|
|
|
|
|
|
|
|
if (n == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
// See if digi actioned - put a * on last actioned
|
|
|
|
|
|
|
|
if (*ptr & 0x80)
|
|
|
|
{
|
|
|
|
if (*ptr & 1) // if last address, must need *
|
|
|
|
{
|
|
|
|
*(Output++) = '*';
|
|
|
|
Digi = '*';
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
if ((ptr[7] & 0x80) == 0) // Repeased by next?
|
|
|
|
{
|
|
|
|
*(Output++) = '*'; // No, so need *
|
|
|
|
Digi = '*';
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
*(Output++) = ',';
|
|
|
|
}
|
|
|
|
*(--Output) = 0; // remove last comma
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*(Output) = 0;
|
|
|
|
|
|
|
|
// if we used a digi set * on call and display via string
|
|
|
|
|
|
|
|
|
|
|
|
if (Digi)
|
|
|
|
Normcall[len++] = Digi;
|
|
|
|
else
|
|
|
|
DigiList[0] = 0; // Dont show list if not used
|
|
|
|
|
|
|
|
Normcall[len++] = 0;
|
|
|
|
|
|
|
|
|
|
|
|
ptr = FormatMH(MH, CMD->String[2]);
|
|
|
|
|
|
|
|
if (CMD->String[2] == 'V') // MHV
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s %-10s %-10d %-30s\r",
|
|
|
|
Normcall, ptr, MH->MHCOUNT, DigiList);
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s %s %s\r", Normcall, ptr, DigiList);
|
|
|
|
|
|
|
|
MH++;
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
2023-05-16 16:40:12 +01:00
|
|
|
int Rig_Command(TRANSPORTENTRY * Session, char * Command);
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
VOID RADIOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD)
|
|
|
|
{
|
|
|
|
char * ptr;
|
|
|
|
|
2023-05-16 16:40:12 +01:00
|
|
|
if (Rig_Command(Session, CmdTail))
|
2022-08-28 09:35:46 +01:00
|
|
|
{
|
|
|
|
ReleaseBuffer((UINT *)REPLYBUFFER);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Error Message is in buffer
|
|
|
|
|
|
|
|
ptr = strchr(CmdTail, 13);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
int len = (int)(++ptr - CmdTail);
|
|
|
|
|
|
|
|
memcpy(Bufferptr, CmdTail, len);
|
|
|
|
Bufferptr += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID SendNRRecordRoute(struct DEST_LIST * DEST, TRANSPORTENTRY * Session);
|
|
|
|
|
|
|
|
|
|
|
|
VOID NRRCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD)
|
|
|
|
{
|
|
|
|
// PROCESS 'NRR - Netrom Record Route' COMMAND
|
|
|
|
|
|
|
|
char * ptr, *Context;
|
|
|
|
struct DEST_LIST * Dest = DESTS;
|
|
|
|
int count = MAXDESTS;
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
UCHAR AXCall[8];
|
|
|
|
int count;
|
|
|
|
|
|
|
|
ConvToAX25(ptr, AXCall);
|
|
|
|
strcat(ptr, " ");
|
|
|
|
|
|
|
|
for (count = 0; count < MAXDESTS; count++)
|
|
|
|
{
|
|
|
|
if (memcmp(Dest->DEST_ALIAS, ptr, 6) == 0 || CompareCalls(Dest->DEST_CALL, AXCall))
|
|
|
|
{
|
|
|
|
SendNRRecordRoute(Dest, Session);
|
|
|
|
memcpy(Bufferptr, OKMSG, 3);
|
|
|
|
Bufferptr += 3;
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Dest++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not found\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int CHECKINTERLOCK(struct PORTCONTROL * OURPORT)
|
|
|
|
{
|
|
|
|
// See if any Interlocked ports are Busy
|
|
|
|
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
struct _EXTPORTDATA * EXTPORT;
|
|
|
|
|
|
|
|
int n = NUMBEROFPORTS;
|
|
|
|
int ourgroup = OURPORT->PORTINTERLOCK;
|
|
|
|
|
|
|
|
while (PORT)
|
|
|
|
{
|
|
|
|
if (PORT != OURPORT)
|
|
|
|
{
|
|
|
|
if (PORT->PORTINTERLOCK == ourgroup)
|
|
|
|
{
|
|
|
|
// Same Group - is it busy
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
EXTPORT = (struct _EXTPORTDATA *)PORT;
|
|
|
|
|
|
|
|
while (i < 27)
|
|
|
|
if (EXTPORT->ATTACHEDSESSIONS[i++])
|
|
|
|
return PORT->PORTNUMBER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID ATTACHCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD)
|
|
|
|
{
|
|
|
|
// ATTACH to a PACTOR or similar port
|
|
|
|
|
|
|
|
TRANSPORTENTRY * NewSess;
|
|
|
|
struct _EXTPORTDATA * EXTPORT;
|
2023-03-18 07:14:35 +00:00
|
|
|
struct TNCINFO * TNC = 0;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
int Port = 0, sess = 0;
|
|
|
|
char * ptr, *Context;
|
|
|
|
int ret;
|
|
|
|
struct PORTCONTROL * PORT = NULL;
|
|
|
|
struct DATAMESSAGE Message = {0};
|
|
|
|
int Paclen, PortPaclen;
|
|
|
|
struct DATAMESSAGE * Buffer;
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
Port = atoi(ptr);
|
|
|
|
|
|
|
|
if (Port)
|
|
|
|
PORT = GetPortTableEntryFromPortNum(Port);
|
|
|
|
|
|
|
|
if (PORT == NULL || PORT->PROTOCOL < 10)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If attach on telnet port, find a free stream
|
|
|
|
|
|
|
|
EXTPORT = (struct _EXTPORTDATA *)PORT;
|
|
|
|
|
|
|
|
if (strstr(EXTPORT->PORT_DLL_NAME, "TELNET"))
|
|
|
|
{
|
|
|
|
int count = EXTPORT->MAXHOSTMODESESSIONS;
|
|
|
|
count--; // First is Pactor Stream, count is now last ax.25 session
|
|
|
|
|
|
|
|
while (count)
|
|
|
|
{
|
|
|
|
if (EXTPORT->ATTACHEDSESSIONS[count] == 0)
|
|
|
|
{
|
|
|
|
int Paclen, PortPaclen;
|
|
|
|
struct DATAMESSAGE Message = {0};
|
|
|
|
|
|
|
|
// Found a free one - use it
|
|
|
|
|
|
|
|
// See if TNC is OK
|
|
|
|
|
|
|
|
Message.PORT = count;
|
|
|
|
|
|
|
|
ret = PORT->PORTTXCHECKCODE(PORT, Message.PORT);
|
|
|
|
|
|
|
|
if ((ret & 0xff00) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Error - TNC Not Ready\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// GET CIRCUIT TABLE ENTRY FOR OTHER END OF LINK
|
|
|
|
|
|
|
|
NewSess = SetupNewSession(Session, Bufferptr);
|
|
|
|
|
|
|
|
if (NewSess == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
EXTPORT->ATTACHEDSESSIONS[count] = NewSess;
|
|
|
|
|
|
|
|
NewSess->Secure_Session = Session->Secure_Session;
|
|
|
|
|
|
|
|
NewSess->KAMSESSION = count;
|
|
|
|
|
|
|
|
// Set paclen to lower of incoming and outgoing
|
|
|
|
|
|
|
|
Paclen = Session->SESSPACLEN; // Incoming PACLEN
|
|
|
|
|
|
|
|
if (Paclen == 0)
|
|
|
|
Paclen = 256; // 0 = 256
|
|
|
|
|
|
|
|
PortPaclen = PORT->PORTPACLEN;
|
|
|
|
|
|
|
|
if (PortPaclen == 0)
|
|
|
|
PortPaclen = 256; // 0 = 256
|
|
|
|
|
|
|
|
if (PortPaclen < Paclen)
|
|
|
|
Paclen = PortPaclen;
|
|
|
|
|
|
|
|
NewSess->SESSPACLEN = Paclen;
|
|
|
|
Session->SESSPACLEN = Paclen;
|
|
|
|
|
|
|
|
NewSess->L4STATE = 5;
|
|
|
|
NewSess->L4CIRCUITTYPE = DOWNLINK + PACTOR;
|
|
|
|
NewSess->L4TARGET.PORT = PORT;
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
sess = count;
|
|
|
|
|
|
|
|
// Replace command tail with original (before conversion to upper case
|
|
|
|
|
|
|
|
Context = Context + (OrigCmdBuffer - COMMANDBUFFER);
|
|
|
|
|
|
|
|
goto checkattachandcall;
|
|
|
|
|
|
|
|
|
|
|
|
memcpy(Bufferptr, OKMSG, 3);
|
|
|
|
Bufferptr += 3;
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Error - No free streams on this port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Message.PORT = 0;
|
|
|
|
|
|
|
|
ret = PORT->PORTTXCHECKCODE(PORT, Message.PORT);
|
|
|
|
|
|
|
|
if ((ret & 0xff00) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Error - TNC Not Ready\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See if "Attach and Call" (for VHF ports)
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && strcmp(ptr, "S") == 0)
|
|
|
|
{
|
|
|
|
Session->STAYFLAG = TRUE;
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
// we have another param
|
|
|
|
|
|
|
|
// if it is a single char it is a channel number for vhf attach
|
|
|
|
|
|
|
|
if (strlen(ptr) == 1)
|
|
|
|
{
|
|
|
|
// Only Allow Attach VHF from Secure Applications or if PERMITGATEWAY is set
|
|
|
|
|
|
|
|
if (EXTPORT->PERMITGATEWAY == 0 && Session->Secure_Session == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, you are not allowed to use this port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sess = ptr[0] - '@';
|
|
|
|
|
|
|
|
if (sess < 1 || sess > EXTPORT->MAXHOSTMODESESSIONS)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Error - Invalid Channel\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr && strcmp(ptr, "S") == 0)
|
|
|
|
{
|
|
|
|
Session->STAYFLAG = TRUE;
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret & 0x8000) // Disconnecting
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Error - Port in use\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check Interlock. Only ports with a TNC record can be interlocked
|
|
|
|
|
|
|
|
TNC = PORT->TNC;
|
|
|
|
|
|
|
|
if (TNC)
|
|
|
|
{
|
|
|
|
// See if any interlocked ports are in use
|
|
|
|
|
|
|
|
struct TNCINFO * OtherTNC;
|
|
|
|
int i;
|
|
|
|
int rxInterlock = TNC->RXRadio;
|
|
|
|
int txInterlock = TNC->TXRadio;
|
|
|
|
|
|
|
|
if (rxInterlock || txInterlock)
|
|
|
|
{
|
2023-06-21 08:21:04 +01:00
|
|
|
for (i=1; i <= MAXBPQPORTS; i++)
|
2022-08-28 09:35:46 +01:00
|
|
|
{
|
|
|
|
OtherTNC = TNCInfo[i];
|
|
|
|
|
|
|
|
if (OtherTNC == NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (OtherTNC == TNC)
|
|
|
|
continue;
|
|
|
|
|
2023-10-10 22:07:04 +01:00
|
|
|
if (rxInterlock && rxInterlock == OtherTNC->RXRadio || txInterlock && txInterlock == OtherTNC->TXRadio) // Same Group
|
2022-08-28 09:35:46 +01:00
|
|
|
{
|
2023-01-25 10:12:51 +00:00
|
|
|
int n;
|
|
|
|
|
|
|
|
for (n = 0; n <= 26; n++)
|
|
|
|
{
|
|
|
|
if (OtherTNC->PortRecord->ATTACHEDSESSIONS[n])
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, interlocked port %d is in use\r", i);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
2022-08-28 09:35:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (EXTPORT->ATTACHEDSESSIONS[sess])
|
|
|
|
{
|
|
|
|
// In use
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Error - Port in use\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// GET CIRCUIT TABLE ENTRY FOR OTHER END OF LINK
|
|
|
|
|
|
|
|
NewSess = SetupNewSession(Session, Bufferptr);
|
|
|
|
|
|
|
|
if (NewSess == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// if a UZ7HO port, and the uplink is L2 or Uz7HO and multisession,
|
|
|
|
// invert SSID bits
|
|
|
|
|
|
|
|
if (memcmp(EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0)
|
|
|
|
goto noFlip1;
|
|
|
|
|
|
|
|
if (EXTPORT->MAXHOSTMODESESSIONS < 2) // Not multisession
|
|
|
|
goto noFlip1;
|
|
|
|
|
|
|
|
if ((Session->L4CIRCUITTYPE & BPQHOST)) // host
|
|
|
|
goto noFlip1;
|
|
|
|
|
|
|
|
if ((Session->L4CIRCUITTYPE & PACTOR))
|
|
|
|
{
|
|
|
|
// incoming is Pactorlike - see if UZ7HO
|
|
|
|
|
|
|
|
if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0)
|
|
|
|
goto noFlip1;
|
|
|
|
else
|
|
|
|
NewSess->L4USER[6] ^= 0x1e; // UZ7HO Uplink - flip
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
// Must be L2 uplink - flip
|
|
|
|
|
|
|
|
NewSess->L4USER[6] ^= 0x1e; // Flip SSID
|
|
|
|
noFlip1:
|
|
|
|
|
|
|
|
EXTPORT->ATTACHEDSESSIONS[sess] = NewSess;
|
|
|
|
|
|
|
|
NewSess->KAMSESSION = sess;
|
|
|
|
|
|
|
|
// Set paclen to lower of incoming and outgoing
|
|
|
|
|
|
|
|
Paclen = Session->SESSPACLEN; // Incoming PACLEN
|
|
|
|
|
|
|
|
if (Paclen == 0)
|
|
|
|
Paclen = 256; // 0 = 256
|
|
|
|
|
|
|
|
PortPaclen = PORT->PORTPACLEN;
|
|
|
|
|
|
|
|
if (PortPaclen == 0)
|
|
|
|
PortPaclen = 256; // 0 = 256
|
|
|
|
|
|
|
|
if (PortPaclen < Paclen)
|
|
|
|
Paclen = PortPaclen;
|
|
|
|
|
|
|
|
NewSess->SESSPACLEN = Paclen;
|
|
|
|
Session->SESSPACLEN = Paclen;
|
|
|
|
NewSess->L4STATE = 5;
|
|
|
|
NewSess->L4CIRCUITTYPE = DOWNLINK + PACTOR;
|
|
|
|
NewSess->L4TARGET.PORT = PORT;
|
|
|
|
|
|
|
|
checkattachandcall:
|
|
|
|
|
2023-03-16 06:52:27 +00:00
|
|
|
// If set freq on attach is defined, do it
|
|
|
|
|
|
|
|
if (TNC && TNC->ActiveRXFreq && TNC->RXRadio)
|
|
|
|
{
|
|
|
|
char Msg[128];
|
|
|
|
|
|
|
|
sprintf(Msg, "R%d %f", TNC->RXRadio, TNC->ActiveRXFreq);
|
2023-05-16 16:40:12 +01:00
|
|
|
Rig_Command( (TRANSPORTENTRY *) -1, Msg);
|
2023-03-16 06:52:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (TNC && TNC->ActiveTXFreq && TNC->TXRadio && TNC->TXRadio != TNC->RXRadio)
|
|
|
|
{
|
|
|
|
char Msg[128];
|
|
|
|
|
|
|
|
sprintf(Msg, "R%d %f", TNC->TXRadio, TNC->ActiveTXFreq);
|
2023-05-16 16:40:12 +01:00
|
|
|
Rig_Command( (TRANSPORTENTRY *) -1, Msg);
|
2023-03-16 06:52:27 +00:00
|
|
|
}
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
// we have a call to connect to
|
|
|
|
|
|
|
|
char Callstring[80];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
Buffer = REPLYBUFFER;
|
|
|
|
Buffer->PORT = sess;
|
|
|
|
Buffer->PID = 0xf0;
|
|
|
|
|
|
|
|
len = sprintf(Callstring,"C %s", ptr);
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
while (ptr) // if any other params (such as digis) copy them
|
|
|
|
{
|
|
|
|
if (strcmp(ptr, "S") == 0)
|
|
|
|
{
|
|
|
|
Session->STAYFLAG = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
len += sprintf(&Callstring[len], " %s", ptr);
|
|
|
|
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
Callstring[len++] = 13;
|
|
|
|
Callstring[len] = 0;
|
|
|
|
|
|
|
|
Buffer->LENGTH = len + MSGHDDRLEN + 1;
|
|
|
|
memcpy(Buffer->L2DATA, Callstring, len);
|
|
|
|
C_Q_ADD(&PORT->PORTTX_Q, (UINT *)Buffer);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(Bufferptr, OKMSG, 3);
|
|
|
|
Bufferptr += 3;
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// SYSOP COMMANDS
|
|
|
|
|
|
|
|
CMDX COMMANDS[] =
|
|
|
|
{
|
|
|
|
"SAVENODES ",8, SAVENODES, 0,
|
|
|
|
"TELRECONFIG ",4, RECONFIGTELNET, 0,
|
|
|
|
"SAVEMH ",6, SAVEMHCMD, 0,
|
|
|
|
"REBOOT ",6, REBOOT, 0,
|
|
|
|
"RIGRECONFIG ",8 , RIGRECONFIG, 0,
|
|
|
|
"RESTART ",7,RESTART,0,
|
|
|
|
"RESTARTTNC ",10,RESTARTTNC,0,
|
|
|
|
"SENDNODES ",8,SENDNODES,0,
|
|
|
|
"EXTRESTART ",10, EXTPORTVAL, offsetof(EXTPORTDATA, EXTRESTART),
|
|
|
|
"TXDELAY ",3, PORTVAL, offsetof(PORTCONTROLX, PORTTXDELAY),
|
|
|
|
"MAXFRAME ",3, PORTVAL, offsetof(PORTCONTROLX, PORTWINDOW),
|
|
|
|
"RETRIES ",3, PORTVAL, offsetof(PORTCONTROLX, PORTN2),
|
|
|
|
"FRACK ",3,PORTVAL, offsetof(PORTCONTROLX, PORTT1),
|
|
|
|
"RESPTIME ",3,PORTVAL, offsetof(PORTCONTROLX, PORTT2),
|
|
|
|
"PPACLEN ",3,PORTVAL, offsetof(PORTCONTROLX, PORTPACLEN),
|
|
|
|
"QUALITY ",3,PORTVAL, offsetof(PORTCONTROLX, PORTQUALITY),
|
|
|
|
"PERSIST ",2,PORTVAL, offsetof(PORTCONTROLX, PORTPERSISTANCE),
|
|
|
|
"TXTAIL ",3,PORTVAL, offsetof(PORTCONTROLX, PORTTAILTIME),
|
|
|
|
"XMITOFF ",7,PORTVAL, offsetof(PORTCONTROLX, PORTDISABLED),
|
|
|
|
"DIGIFLAG ",5,PORTVAL, offsetof(PORTCONTROLX, DIGIFLAG),
|
|
|
|
"DIGIPORT ",5,PORTVAL, offsetof(PORTCONTROLX, DIGIPORT),
|
|
|
|
"MAXUSERS ",4,PORTVAL, offsetof(PORTCONTROLX, USERS),
|
|
|
|
"L3ONLY ",6,PORTVAL, offsetof(PORTCONTROLX, PORTL3FLAG),
|
|
|
|
"BBSALIAS ",4,PORTVAL, offsetof(PORTCONTROLX, PORTBBSFLAG),
|
|
|
|
"VALIDCALLS ",5,VALNODES,0,
|
|
|
|
"WL2KSYSOP ",5,WL2KSYSOP,0,
|
|
|
|
"STOPPORT ",4,STOPPORT,0,
|
|
|
|
"STARTPORT ",5,STARTPORT,0,
|
|
|
|
"STOPCMS ",7,STOPCMS,0,
|
|
|
|
"STARTCMS ",8,STARTCMS,0,
|
|
|
|
|
|
|
|
"FINDBUFFS ",4,FINDBUFFS,0,
|
|
|
|
"KISS ",4,KISSCMD,0,
|
|
|
|
"GETPORTCTEXT",9,GetPortCTEXT, 0,
|
|
|
|
|
|
|
|
#ifdef EXCLUDEBITS
|
|
|
|
|
|
|
|
"EXCLUDE ",4,ListExcludedCalls,0,
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
"FULLDUP ",4,PORTVAL, offsetof(PORTCONTROLX, FULLDUPLEX),
|
|
|
|
"SOFTDCD ",4,PORTVAL, offsetof(PORTCONTROLX, SOFTDCDFLAG),
|
|
|
|
"OBSINIT ",7,SWITCHVAL,(size_t)&OBSINIT,
|
|
|
|
"OBSMIN ",6,SWITCHVAL,(size_t)&OBSMIN,
|
|
|
|
"NODESINT ",8,SWITCHVAL,(size_t)&L3INTERVAL,
|
|
|
|
"L3TTL ",5,SWITCHVAL,(size_t)&L3LIVES,
|
|
|
|
"L4RETRIES ",5,SWITCHVAL,(size_t)&L4N2,
|
|
|
|
"L4TIMEOUT ",5,SWITCHVALW,(size_t)&L4T1,
|
|
|
|
"T3 ",2,SWITCHVALW,(size_t)&T3,
|
|
|
|
"NODEIDLETIME",8,SWITCHVALW,(size_t)&L4LIMIT,
|
|
|
|
"LINKEDFLAG ",10,SWITCHVAL,(size_t)&LINKEDFLAG,
|
|
|
|
"IDINTERVAL ",5,SWITCHVAL,(size_t)&IDINTERVAL,
|
|
|
|
"MINQUAL ",7,SWITCHVAL,(size_t)&MINQUAL,
|
|
|
|
"FULLCTEXT ",6,SWITCHVAL,(size_t)&FULL_CTEXT,
|
|
|
|
"HIDENODES ",8,SWITCHVAL,(size_t)&HIDENODES,
|
|
|
|
"L4DELAY ",7,SWITCHVAL,(size_t)&L4DELAY,
|
|
|
|
"L4WINDOW ",6,SWITCHVAL,(size_t)&L4DEFAULTWINDOW,
|
|
|
|
"BTINTERVAL ",5,SWITCHVAL,(size_t)&BTINTERVAL,
|
|
|
|
"PASSWORD ", 8, PWDCMD, 0,
|
|
|
|
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0,
|
|
|
|
"************", 12, APPLCMD, 0, // Apppl 32 is internal Terminal
|
|
|
|
"*** LINKED ",10,LINKCMD,0,
|
|
|
|
"CQ ",2,CQCMD,0,
|
|
|
|
"CONNECT ",1,CMDC00,0,
|
|
|
|
"NC ",2,CMDC00,0,
|
|
|
|
"BYE ",1,BYECMD,0,
|
|
|
|
"QUIT ",1,BYECMD,0,
|
|
|
|
"INFO ",1,CMDI00,0,
|
2022-11-23 10:56:20 +00:00
|
|
|
"HELP ",1,HELPCMD,0,
|
2022-08-28 09:35:46 +01:00
|
|
|
"VERSION ",1,CMDV00,0,
|
|
|
|
"NODES ",1,CMDN00,0,
|
|
|
|
"LINKS ",1,CMDL00,0,
|
|
|
|
"LISTEN ",3,LISTENCMD,0,
|
|
|
|
"L4T1 ",2,CMDT00,0,
|
|
|
|
"PORTS ",1,CMDP00,0,
|
|
|
|
"PACLEN ",3,CMDPAC,0,
|
|
|
|
"IDLETIME ",4,CMDIDLE,0,
|
|
|
|
"ROUTES ",1,CMDR00,0,
|
|
|
|
"STATS ",1,CMDSTATS,0,
|
|
|
|
"USERS ",1,CMDS00,0,
|
|
|
|
"UNPROTO ",2,UNPROTOCMD,0,
|
|
|
|
"? ",1,CMDQUERY,0,
|
|
|
|
"DUMP ",4,DUMPCMD,0,
|
|
|
|
"MHU ",3,MHCMD,0, // UTC Times
|
|
|
|
"MHL ",3,MHCMD,0, // Local Times
|
|
|
|
"MHV ",3,MHCMD,0,
|
|
|
|
"MHEARD ",1,MHCMD,0,
|
|
|
|
"APRS ",2,APRSCMD,0,
|
|
|
|
"ATTACH ",1,ATTACHCMD,0,
|
|
|
|
"RADIO ",3,RADIOCMD,0,
|
|
|
|
"AXRESOLVER ",3,AXRESOLVER,0,
|
|
|
|
"AXMHEARD ",3,AXMHEARD,0,
|
|
|
|
"TELSTATUS ",3,SHOWTELNET,0,
|
|
|
|
"NRR ",1,NRRCMD,0,
|
|
|
|
"PING ",2,PING,0,
|
|
|
|
"AGWSTATUS ",3,SHOWAGW,0,
|
|
|
|
"ARP ",3,SHOWARP,0,
|
|
|
|
"NAT ",3,SHOWNAT,0,
|
|
|
|
"IPROUTE ",3,SHOWIPROUTE,0,
|
2023-05-16 16:40:12 +01:00
|
|
|
"UZ7HO ",5,UZ7HOCMD,0,
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
"..FLMSG ",7,FLMSG,0
|
|
|
|
};
|
|
|
|
|
|
|
|
CMDX * CMD = NULL;
|
|
|
|
|
|
|
|
int NUMBEROFCOMMANDS = sizeof(COMMANDS)/sizeof(CMDX);
|
|
|
|
|
|
|
|
char * ReplyPointer; // Pointer into reply buffer
|
|
|
|
|
|
|
|
int DecodeNodeName(char * NodeName, char * ptr)
|
|
|
|
{
|
|
|
|
// NodeName is TABLE ENTRY WITH AX25 CALL AND ALIAS
|
|
|
|
|
|
|
|
// Copyies 20 byte 20 DECODED NAME IN FORM ALIAS:CALL to ptr
|
|
|
|
// Returns significant length of string
|
|
|
|
|
|
|
|
int len;
|
|
|
|
char Normcall[10];
|
|
|
|
char * alias = &NodeName[7];
|
|
|
|
int n = 6;
|
|
|
|
char * start = ptr;
|
|
|
|
|
|
|
|
memset(ptr, ' ', 20);
|
|
|
|
|
|
|
|
len = ConvFromAX25(NodeName, Normcall);
|
|
|
|
|
|
|
|
if (*(alias) > ' ') // Does alias start with a null or a space ?
|
|
|
|
{
|
|
|
|
while (*(alias) > ' ' && n--)
|
|
|
|
{
|
|
|
|
*ptr++ = *alias++;
|
|
|
|
}
|
|
|
|
*ptr++ = ':';
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(ptr, Normcall, len);
|
|
|
|
ptr += len;
|
|
|
|
|
|
|
|
return (int)(ptr - start);
|
|
|
|
}
|
|
|
|
|
|
|
|
char * SetupNodeHeader(struct DATAMESSAGE * Buffer)
|
|
|
|
{
|
|
|
|
char Header[20];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
char * ptr = &Buffer->L2DATA[0];
|
|
|
|
|
|
|
|
len = DecodeNodeName(MYCALLWITHALIAS, Header);
|
|
|
|
|
|
|
|
memcpy (ptr, Header, len);
|
|
|
|
ptr += len;
|
|
|
|
|
|
|
|
(*ptr++) = HEADERCHAR;
|
|
|
|
(*ptr++) = ' ';
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID SendCommandReply(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer, int Len)
|
|
|
|
{
|
|
|
|
if (Len == (4 + sizeof(void *))) // Null Packet
|
|
|
|
{
|
|
|
|
ReleaseBuffer((UINT *)Buffer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Buffer->LENGTH = Len;
|
|
|
|
|
|
|
|
C_Q_ADD(&Session->L4TX_Q, (UINT *)Buffer);
|
|
|
|
|
|
|
|
PostDataAvailable(Session);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID CommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer)
|
|
|
|
{
|
|
|
|
// ignore frames with single NULL (Keepalive)
|
|
|
|
|
|
|
|
if (Buffer->LENGTH == sizeof(void *) + 5 && Buffer->L2DATA[0] == 0)
|
|
|
|
{
|
|
|
|
ReleaseBuffer(Buffer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Buffer->LENGTH > 100)
|
|
|
|
{
|
|
|
|
// Debugprintf("BPQ32 command too long %s", Buffer->L2DATA);
|
|
|
|
ReleaseBuffer(Buffer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
InnerLoop:
|
|
|
|
|
|
|
|
InnerCommandHandler(Session, Buffer);
|
|
|
|
|
|
|
|
// See if any more commands in buffer
|
|
|
|
|
|
|
|
if (Session->PARTCMDBUFFER)
|
|
|
|
{
|
|
|
|
char * ptr1, * ptr2;
|
|
|
|
int len;
|
|
|
|
|
|
|
|
Buffer = Session->PARTCMDBUFFER;
|
|
|
|
|
|
|
|
// Check that message has a CR, if not save buffer and exit
|
|
|
|
|
|
|
|
len = Buffer->LENGTH - (4 + sizeof(void *));
|
|
|
|
ptr1 = &Buffer->L2DATA[0];
|
|
|
|
|
|
|
|
ptr2 = memchr(ptr1, 13, len);
|
|
|
|
|
|
|
|
if (ptr2 == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Session->PARTCMDBUFFER = NULL;
|
|
|
|
|
|
|
|
goto InnerLoop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID InnerCommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer)
|
|
|
|
{
|
|
|
|
char * ptr1, * ptr2, *ptr3;
|
|
|
|
int len, oldlen, newlen, rest, n;
|
|
|
|
struct DATAMESSAGE * OldBuffer;
|
|
|
|
struct DATAMESSAGE * SaveBuffer;
|
|
|
|
char c;
|
|
|
|
|
|
|
|
// If a partial command is stored, append this data to it.
|
|
|
|
|
|
|
|
if (Session->PARTCMDBUFFER)
|
|
|
|
{
|
|
|
|
len = Buffer->LENGTH - (sizeof(void *) + 4);
|
|
|
|
ptr1 = &Buffer->L2DATA[0];
|
|
|
|
|
|
|
|
OldBuffer = Session->PARTCMDBUFFER; // Old Data
|
|
|
|
|
|
|
|
if (OldBuffer == Buffer)
|
|
|
|
{
|
|
|
|
// something has gone horribly wrong
|
|
|
|
|
|
|
|
Session->PARTCMDBUFFER = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
oldlen = OldBuffer->LENGTH;
|
|
|
|
|
|
|
|
newlen = len + oldlen;
|
|
|
|
|
|
|
|
if (newlen > 200)
|
|
|
|
{
|
|
|
|
// Command far too long - ignore previous
|
|
|
|
|
|
|
|
OldBuffer->LENGTH = oldlen = sizeof(void *) + 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
OldBuffer->LENGTH += len;
|
|
|
|
memcpy(&OldBuffer->L2DATA[oldlen - (sizeof(void *) + 4)], Buffer->L2DATA, len);
|
|
|
|
|
|
|
|
ReleaseBuffer((UINT *)Buffer);
|
|
|
|
|
|
|
|
Buffer = OldBuffer;
|
|
|
|
|
|
|
|
Session->PARTCMDBUFFER = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that message has a CR, if not save buffer and exit
|
|
|
|
|
|
|
|
len = Buffer->LENGTH - (sizeof(void *) + 4);
|
|
|
|
ptr1 = &Buffer->L2DATA[0];
|
|
|
|
|
|
|
|
// Check for sending YAPP to Node
|
|
|
|
|
|
|
|
if (len == 2 && ptr1[0] == 5 && ptr1[1] == 1)
|
|
|
|
{
|
|
|
|
ptr1[0] = 0x15; // NAK
|
|
|
|
|
|
|
|
ptr1[1] = sprintf(&ptr1[2], "Node doesn't support YAPP Transfers");
|
|
|
|
|
|
|
|
Buffer->LENGTH += ptr1[1];
|
|
|
|
|
|
|
|
C_Q_ADD(&Session->L4TX_Q, (UINT *)Buffer);
|
|
|
|
PostDataAvailable(Session);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ptr2 = memchr(ptr1, ';', len);
|
|
|
|
|
|
|
|
if (ptr2 == 0)
|
|
|
|
{
|
|
|
|
ptr2 = memchr(ptr1, 13, len);
|
|
|
|
|
|
|
|
if (ptr2 == 0)
|
|
|
|
{
|
|
|
|
// No newline
|
|
|
|
|
|
|
|
Session->PARTCMDBUFFER = Buffer;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr2++;
|
|
|
|
|
|
|
|
rest = len - (int)(ptr2 - ptr1);
|
|
|
|
|
|
|
|
if (rest)
|
|
|
|
{
|
|
|
|
// there are chars beyond the cr in the buffer
|
|
|
|
|
|
|
|
// see if LF after CR
|
|
|
|
|
|
|
|
if ((*ptr2) == 10) // LF
|
|
|
|
{
|
|
|
|
ptr2++;
|
|
|
|
rest--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rest) // May only have had LF
|
|
|
|
{
|
|
|
|
// Get a new buffer, and copy extra data to it.
|
|
|
|
|
|
|
|
SaveBuffer = (struct DATAMESSAGE *)GetBuff();
|
|
|
|
|
|
|
|
if (SaveBuffer) //`Just ignore if no buffers
|
|
|
|
{
|
|
|
|
SaveBuffer->LENGTH = rest + MSGHDDRLEN + 1;
|
|
|
|
SaveBuffer->PID = 0xf0;
|
|
|
|
memcpy(&SaveBuffer->L2DATA[0], ptr2, rest);
|
|
|
|
Session->PARTCMDBUFFER = SaveBuffer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GET PACLEN FOR THIS CONNECTION
|
|
|
|
|
|
|
|
CMDPACLEN = Session->SESSPACLEN;
|
|
|
|
|
|
|
|
if (CMDPACLEN == 0)
|
|
|
|
CMDPACLEN = PACLEN; // Use default if no Session PACLEN
|
|
|
|
|
|
|
|
// If sesion is in UNPROTO Mode, send message as a UI message
|
|
|
|
|
|
|
|
if (Session->UNPROTO)
|
|
|
|
{
|
2023-05-16 16:40:12 +01:00
|
|
|
// char LongMsg[512] =
|
|
|
|
// "VeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessage"
|
|
|
|
// "VeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessageVeryLongMessage";
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
DIGIMESSAGE Msg;
|
|
|
|
int Port = Session->UNPROTO;
|
|
|
|
int Len = Buffer->LENGTH - (MSGHDDRLEN -1); // Need PID
|
|
|
|
|
|
|
|
// First check for UNPROTO exit - ctrl/z or /ex
|
|
|
|
|
|
|
|
if (Buffer->L2DATA[0] == 26 || (Len == 6 && _memicmp(&Buffer->L2DATA[0], "/ex", 3) == 0)) // CTRL/Z or /ex
|
|
|
|
{
|
|
|
|
REPLYBUFFER = Buffer;
|
|
|
|
|
|
|
|
Session->UNPROTO = 0;
|
|
|
|
memset(Session->UADDRESS, 0, 64);
|
|
|
|
|
|
|
|
// SET UP HEADER
|
|
|
|
|
|
|
|
Buffer->PID = 0xf0;
|
|
|
|
ptr1 = SetupNodeHeader(Buffer);
|
|
|
|
memcpy(ptr1, OKMSG, 3);
|
|
|
|
ptr1 += 3;
|
|
|
|
SendCommandReply(Session, Buffer, (int)(ptr1 - (char *)Buffer));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&Msg, 0, sizeof(Msg));
|
|
|
|
|
|
|
|
Msg.PORT = Port;
|
|
|
|
Msg.CTL = 3; // UI
|
|
|
|
memcpy(Msg.DEST, Session->UADDRESS, 7);
|
2023-10-31 22:42:23 +00:00
|
|
|
Msg.DEST[6] |= 0x80; // set Command Bit
|
2022-08-28 09:35:46 +01:00
|
|
|
memcpy(Msg.ORIGIN, Session->L4USER, 7);
|
|
|
|
memcpy(Msg.DIGIS, &Session->UADDRESS[7], Session->UAddrLen - 7);
|
|
|
|
memcpy(&Msg.PID, &Buffer->PID, Len);
|
|
|
|
Send_AX_Datagram(&Msg, Len, Port); // Len is Payload - CTL, PID and Data
|
|
|
|
|
2023-05-16 16:40:12 +01:00
|
|
|
// memcpy(&Msg.PID + 1, LongMsg, 260);
|
|
|
|
// Send_AX_Datagram(&Msg, 241, Port); // Len is Payload - CTL, PID and Data
|
|
|
|
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
// SendUIModeFrame(Session, (PMESSAGE)Buffer, Session->UNPROTO);
|
|
|
|
|
|
|
|
ReleaseBuffer((UINT *)Buffer); // Not using buffer for reply
|
2023-03-16 06:52:27 +00:00
|
|
|
|
|
|
|
// Assume we don't allow multiple lines in buffer with UI
|
|
|
|
|
|
|
|
if (Session->PARTCMDBUFFER)
|
|
|
|
{
|
|
|
|
Buffer = Session->PARTCMDBUFFER;
|
|
|
|
ReleaseBuffer((UINT *)Buffer); // Not using buffer for reply
|
|
|
|
Session->PARTCMDBUFFER = NULL;
|
|
|
|
}
|
2022-08-28 09:35:46 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(COMMANDBUFFER, 32, 80); // Clear to spaces
|
|
|
|
|
|
|
|
ptr1 = &Buffer->L2DATA[0];
|
|
|
|
ptr2 = &COMMANDBUFFER[0];
|
|
|
|
ptr3 = &OrigCmdBuffer[0];
|
|
|
|
|
|
|
|
memset(OrigCmdBuffer, 0, 80);
|
|
|
|
n = 80;
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
c = *(ptr1++) & 0x7f; // Mask paritu
|
|
|
|
|
|
|
|
if (c == 13 || c == ';')
|
|
|
|
break; // CR
|
|
|
|
|
|
|
|
*(ptr3++) = c; // Original Case
|
|
|
|
|
|
|
|
c = toupper(c);
|
|
|
|
*(ptr2++) = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// USE INPUT MESSAGE _BUFFER FOR REPLY
|
|
|
|
|
|
|
|
REPLYBUFFER = Buffer;
|
|
|
|
|
|
|
|
// SET UP HEADER
|
|
|
|
|
|
|
|
Buffer->PID = 0xf0;
|
|
|
|
ptr1 = SetupNodeHeader(Buffer);
|
|
|
|
|
|
|
|
ReplyPointer = ptr1;
|
|
|
|
|
|
|
|
ALIASINVOKED = 0; // Clear "Invoked by APPL ALIAS flag"
|
|
|
|
|
|
|
|
DoTheCommand(Session); // We also call DotheCommand when we need to reprocess - eg for alias handling
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID DoTheCommand(TRANSPORTENTRY * Session)
|
|
|
|
{
|
|
|
|
struct DATAMESSAGE * Buffer = REPLYBUFFER;
|
|
|
|
char * ptr1, * ptr2;
|
|
|
|
int n;
|
|
|
|
|
|
|
|
ptr1 = &COMMANDBUFFER[0]; //
|
|
|
|
|
|
|
|
n = 10;
|
|
|
|
|
|
|
|
while ((*ptr1 == ' ' || *ptr1 == 0) && n--)
|
|
|
|
ptr1++; // STRIP LEADING SPACES and nulls (from keepalive)
|
|
|
|
|
|
|
|
if (n == -1)
|
|
|
|
{
|
|
|
|
// Null command
|
|
|
|
|
|
|
|
ReleaseBuffer((UINT *)Buffer);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr2 = ptr1; // Save
|
|
|
|
|
|
|
|
|
|
|
|
CMD = &COMMANDS[0];
|
|
|
|
n = 0;
|
|
|
|
|
|
|
|
for (n = 0; n < NUMBEROFCOMMANDS; n++)
|
|
|
|
{
|
|
|
|
int CL = CMD->CMDLEN;
|
|
|
|
|
|
|
|
ptr1 = ptr2;
|
|
|
|
|
|
|
|
CMDPTR = CMD;
|
|
|
|
|
|
|
|
if (n == APPL1) // First APPL command
|
|
|
|
{
|
|
|
|
APPLMASK = 1; // FOR APPLICATION ATTACH REQUESTS
|
|
|
|
ALIASPTR = &CMDALIAS[0][0];
|
|
|
|
}
|
|
|
|
|
|
|
|
// ptr1 is input command
|
|
|
|
|
|
|
|
if (memcmp(CMD->String, ptr1, CL) == 0)
|
|
|
|
{
|
|
|
|
// Found match so far - check rest
|
|
|
|
|
|
|
|
char * ptr2 = &CMD->String[CL];
|
|
|
|
|
|
|
|
ptr1 += CL;
|
|
|
|
|
|
|
|
if (*(ptr1) != ' ')
|
|
|
|
{
|
|
|
|
while(*(ptr1) == *ptr2 && *(ptr1) != ' ')
|
|
|
|
{
|
|
|
|
ptr1++;
|
|
|
|
ptr2++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*(ptr1) == ' ')
|
|
|
|
{
|
|
|
|
Session->BADCOMMANDS = 0; // RESET ERROR COUNT
|
|
|
|
|
|
|
|
// SEE IF SYSOP COMMAND, AND IF SO IF PASSWORD HAS BEEN ENTERED
|
|
|
|
|
|
|
|
if (n < PASSCMD)
|
|
|
|
{
|
|
|
|
//NEEDS PASSWORD FOR SYSOP COMMANDS
|
|
|
|
|
|
|
|
if (Session->PASSWORD != 0xFFFF)
|
|
|
|
{
|
|
|
|
ptr1 = ReplyPointer;
|
|
|
|
|
|
|
|
memcpy(ptr1, PASSWORDMSG, LPASSMSG);
|
|
|
|
ptr1 += LPASSMSG;
|
|
|
|
|
|
|
|
SendCommandReply(Session, Buffer, (int)(ptr1 - (char *)Buffer));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// VALNODESFLAG = 0; // NOT VALID NODES COMMAND
|
|
|
|
|
|
|
|
ptr1++; // Skip space
|
|
|
|
|
|
|
|
CMD->CMDPROC(Session, ReplyPointer, ptr1, CMD);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
APPLMASK <<= 1;
|
|
|
|
ALIASPTR += ALIASLEN;
|
|
|
|
|
|
|
|
CMD++;
|
|
|
|
|
|
|
|
}
|
|
|
|
Session->BADCOMMANDS++;
|
|
|
|
|
|
|
|
if (Session->BADCOMMANDS > 6) // TOO MANY ERRORS
|
|
|
|
{
|
|
|
|
ReleaseBuffer((UINT *)Buffer);
|
|
|
|
Session->STAYFLAG = 0;
|
|
|
|
CLOSECURRENTSESSION(Session);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr1 = ReplyPointer;
|
|
|
|
|
|
|
|
memcpy(ptr1, CMDERRMSG, CMDERRLEN);
|
|
|
|
ptr1 += CMDERRLEN;
|
|
|
|
|
|
|
|
SendCommandReply(Session, Buffer, (int)(ptr1 - (char *)Buffer));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID StatsTimer()
|
|
|
|
{
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
int sum;
|
|
|
|
|
|
|
|
while(PORT)
|
|
|
|
{
|
|
|
|
sum = PORT->SENDING / 11;
|
|
|
|
PORT->AVSENDING = sum;
|
|
|
|
|
|
|
|
sum = (PORT->SENDING + PORT->ACTIVE) /11;
|
|
|
|
PORT->AVACTIVE = sum;
|
|
|
|
|
|
|
|
PORT->SENDING = 0;
|
|
|
|
PORT->ACTIVE = 0;
|
|
|
|
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extern struct AXIPPORTINFO * Portlist[];
|
|
|
|
|
|
|
|
#define TCPConnected 4
|
|
|
|
|
|
|
|
|
|
|
|
VOID AXRESOLVER(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// DISPLAY AXIP Resolver info
|
|
|
|
|
|
|
|
int Port = 0, index =0;
|
|
|
|
char * ptr, *Context;
|
|
|
|
struct PORTCONTROL * PORT = NULL;
|
|
|
|
struct AXIPPORTINFO * AXPORT;
|
|
|
|
char Normcall[11];
|
|
|
|
char Flags[10];
|
|
|
|
struct arp_table_entry * arp;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
AXPORT = Portlist[Port];
|
|
|
|
|
|
|
|
if (AXPORT == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not an AXIP port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "AXIP Resolver info for Port %d\r", Port);
|
|
|
|
|
|
|
|
while (index < AXPORT->arp_table_len)
|
|
|
|
{
|
|
|
|
arp = &AXPORT->arp_table[index];
|
|
|
|
|
|
|
|
if (arp->ResolveFlag && arp->error != 0)
|
|
|
|
{
|
|
|
|
// resolver error - Display Error Code
|
|
|
|
sprintf(AXPORT->hostaddr, "Error %d", arp->error);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (arp->IPv6)
|
|
|
|
Format_Addr((unsigned char *)&arp->destaddr6.sin6_addr, AXPORT->hostaddr, TRUE);
|
|
|
|
else
|
|
|
|
Format_Addr((unsigned char *)&arp->destaddr.sin_addr, AXPORT->hostaddr, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
ConvFromAX25(arp->callsign, Normcall);
|
|
|
|
|
|
|
|
Flags[0] = 0;
|
|
|
|
|
|
|
|
if (arp->BCFlag)
|
|
|
|
strcat(Flags, "B ");
|
|
|
|
|
|
|
|
if (arp->TCPState == TCPConnected)
|
|
|
|
strcat(Flags, "C ");
|
|
|
|
|
|
|
|
if (arp->AutoAdded)
|
|
|
|
strcat(Flags, "A");
|
|
|
|
|
|
|
|
if (arp->port == arp->SourcePort)
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr,"%.10s = %.64s %d = %-.42s %s\r",
|
|
|
|
Normcall,
|
|
|
|
arp->hostname,
|
|
|
|
arp->port,
|
|
|
|
AXPORT->hostaddr,
|
|
|
|
Flags);
|
|
|
|
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr,"%.10s = %.64s %d<%d = %-.42s %s\r",
|
|
|
|
Normcall,
|
|
|
|
arp->hostname,
|
|
|
|
arp->port,
|
|
|
|
arp->SourcePort,
|
|
|
|
AXPORT->hostaddr,
|
|
|
|
Flags);
|
|
|
|
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID AXMHEARD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
// DISPLAY AXIP Mheard info
|
|
|
|
|
|
|
|
int Port = 0, index = 0;
|
|
|
|
char * ptr, *Context;
|
|
|
|
struct PORTCONTROL * PORT = NULL;
|
|
|
|
struct AXIPPORTINFO * AXPORT;
|
|
|
|
int n = MHENTRIES;
|
|
|
|
char Normcall[11];
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
AXPORT = Portlist[Port];
|
|
|
|
|
|
|
|
if (AXPORT == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not an AXIP port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "AXIP Mheard for Port %d\r", Port);
|
|
|
|
|
|
|
|
while (index < MaxMHEntries)
|
|
|
|
{
|
|
|
|
if (AXPORT->MHTable[index].proto != 0)
|
|
|
|
{
|
|
|
|
char Addr[80];
|
|
|
|
|
|
|
|
Format_Addr((unsigned char *)&AXPORT->MHTable[index].ipaddr6, Addr, AXPORT->MHTable[index].IPv6);
|
|
|
|
|
|
|
|
Normcall[ConvFromAX25(AXPORT->MHTable[index].callsign, Normcall)] = 0;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%-10s%-15s %c %-6d %-25s%c\r", Normcall,
|
|
|
|
Addr,
|
|
|
|
AXPORT->MHTable[index].proto,
|
|
|
|
AXPORT->MHTable[index].port,
|
|
|
|
asctime(gmtime( &AXPORT->MHTable[index].LastHeard )),
|
|
|
|
(AXPORT->MHTable[index].Keepalive == 0) ? ' ' : 'K');
|
|
|
|
|
|
|
|
Bufferptr[-3] = ' '; // Clear CR returned by asctime
|
|
|
|
}
|
|
|
|
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma pack()
|
|
|
|
|
|
|
|
extern char WL2KCall[10];
|
|
|
|
extern char WL2KLoc[7];
|
|
|
|
|
|
|
|
BOOL GetWL2KSYSOPInfo(char * Call, char * _REPLYBUFFER);
|
|
|
|
BOOL UpdateWL2KSYSOPInfo(char * Call, char * SQL);
|
|
|
|
|
|
|
|
VOID WL2KSYSOP(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char _REPLYBUFFER[1000] = "";
|
|
|
|
|
|
|
|
char LastUpdated[100];
|
|
|
|
char Name[100] = "";
|
|
|
|
char Addr1[100] = "";
|
|
|
|
char Addr2[100] = "";
|
|
|
|
char City[100] = "";
|
|
|
|
char State[100] = "";
|
|
|
|
char Country[100] = "";
|
|
|
|
char PostCode[100] = "";
|
|
|
|
char Email[100] = "";
|
|
|
|
char Website[100] = "";
|
|
|
|
char Phone[100] = "";
|
|
|
|
char Data[100] = "";
|
|
|
|
char LOC[100] = "";
|
|
|
|
BOOL Exists = TRUE;
|
|
|
|
time_t LastUpdateSecs = 0;
|
|
|
|
char * ptr1, * ptr2;
|
|
|
|
|
|
|
|
SOCKET sock;
|
|
|
|
|
|
|
|
int Len;
|
|
|
|
char Message[2048];
|
|
|
|
|
|
|
|
if (WL2KCall[0] < 33)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Winlink reporting is not configured\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (GetWL2KSYSOPInfo(WL2KCall, _REPLYBUFFER) == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Failed to connect to WL2K Database\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strstr(_REPLYBUFFER, "\"ErrorMessage\":"))
|
|
|
|
Exists = FALSE;
|
|
|
|
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"SysopName\":", Name);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"StreetAddress1\":", Addr1);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"StreetAddress2\":", Addr2);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"City\":", City);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"State\":", State);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"Country\":", Country);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"PostalCode\":", PostCode);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"Email\":", Email);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"Website\":", Website);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"Phones\":", Phone);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"Comments\":", Data);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"GridSquare\":", LOC);
|
|
|
|
GetJSONValue(_REPLYBUFFER, "\"Timestamp\":", LastUpdated);
|
|
|
|
|
|
|
|
ptr1 = strchr(LastUpdated, '(');
|
|
|
|
|
|
|
|
if (ptr1)
|
|
|
|
{
|
|
|
|
ptr2 = strchr(++ptr1, ')');
|
|
|
|
|
|
|
|
if (ptr2)
|
|
|
|
{
|
|
|
|
*(ptr2 - 3) = 0; // remove millisecs
|
|
|
|
LastUpdateSecs = atoi(ptr1);
|
|
|
|
|
|
|
|
FormatTime3(LastUpdated, LastUpdateSecs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_memicmp(CmdTail, "SET ", 4) == 0)
|
|
|
|
{
|
|
|
|
if (Exists)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Record already exists in WL2K Database\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set New Values. Any other params are values to set, separated by |
|
|
|
|
|
|
|
|
// ptr1 = strtok_s(&CmdTail[4], ",", &Context);
|
|
|
|
|
|
|
|
// if (ptr1 == NULL)
|
|
|
|
// goto DoReplace;
|
|
|
|
|
|
|
|
// strcpy(Name, ptr1);
|
|
|
|
|
|
|
|
//DoReplace:
|
|
|
|
|
|
|
|
Len = sprintf(Message,
|
|
|
|
"\"Callsign\":\"%s\","
|
|
|
|
"\"GridSquare\":\"%s\","
|
|
|
|
"\"SysopName\":\"%s\","
|
|
|
|
"\"StreetAddress1\":\"%s\","
|
|
|
|
"\"StreetAddress2\":\"%s\","
|
|
|
|
"\"City\":\"%s\","
|
|
|
|
"\"State\":\"%s\","
|
|
|
|
"\"Country\":\"%s\","
|
|
|
|
"\"PostalCode\":\"%s\","
|
|
|
|
"\"Email\":\"%s\","
|
|
|
|
"\"Phones\":\"%s\","
|
|
|
|
"\"Website\":\"%s\","
|
|
|
|
"\"Comments\":\"%s\",",
|
|
|
|
|
|
|
|
WL2KCall, WL2KLoc, Name, Addr1, Addr2, City, State, Country, PostCode, Email, Phone, Website, Data);
|
|
|
|
|
|
|
|
Debugprintf("Sending %s", Message);
|
|
|
|
|
|
|
|
sock = OpenWL2KHTTPSock();
|
|
|
|
|
|
|
|
if (sock)
|
|
|
|
SendHTTPRequest(sock, "api.winlink.org", 80,
|
|
|
|
"/sysop/add", Message, Len, NULL);
|
|
|
|
|
|
|
|
closesocket(sock);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Database Updated\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Exists)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\rWL2K SYSOP Info for %s\r", WL2KCall);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Grid Square: %s\r", LOC);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Name: %s\r", Name);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Addr Line 1: %s\r", Addr1);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Addr Line 2: %s\r", Addr2);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "City: %s\r", City);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "State: %s\r", State);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Country: %s\r", Country);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "PostCode: %s\r", PostCode);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Email Address: %s\r", Email);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Website: %s\r", Website);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Phone: %s\r", Phone);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Additional Data: %s\r", Data);
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Last Updated: %s\r", LastUpdated);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "No SYSOP record for %s\r", WL2KCall);
|
|
|
|
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID CloseKISSPort(struct PORTCONTROL * PortVector);
|
|
|
|
|
|
|
|
VOID STOPCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char _REPLYBUFFER[1000] = "";
|
|
|
|
char * ptr, * Context;
|
|
|
|
|
|
|
|
int portno;
|
|
|
|
|
|
|
|
struct TNCINFO * TNC;
|
|
|
|
struct TCPINFO * TCP;
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
int n = NUMBEROFPORTS;
|
|
|
|
|
|
|
|
// Get port number
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
portno = atoi (ptr);
|
|
|
|
|
|
|
|
if (portno)
|
|
|
|
{
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (PORT->PORTNUMBER == portno)
|
|
|
|
{
|
|
|
|
TNC = TNCInfo[portno];
|
|
|
|
|
|
|
|
if (!TNC || !TNC->TCPInfo)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet Port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
|
|
|
|
TCP->CMS = 0;
|
|
|
|
TCP->CMSOK = FALSE;
|
|
|
|
#ifndef LINBPQ
|
|
|
|
CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3);
|
|
|
|
SetWindowText(TCP->hCMSWnd, "CMS Off");
|
|
|
|
#endif
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "CMS Server Disabled\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bad port
|
|
|
|
|
|
|
|
strcpy(Bufferptr, BADPORT);
|
|
|
|
Bufferptr += (int)strlen(BADPORT);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID STARTCMS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char _REPLYBUFFER[1000] = "";
|
|
|
|
char * ptr, * Context;
|
|
|
|
|
|
|
|
int portno;
|
|
|
|
|
|
|
|
struct TNCINFO * TNC;
|
|
|
|
struct TCPINFO * TCP;
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
int n = NUMBEROFPORTS;
|
|
|
|
|
|
|
|
// Get port number
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
portno = atoi (ptr);
|
|
|
|
|
|
|
|
if (portno)
|
|
|
|
{
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (PORT->PORTNUMBER == portno)
|
|
|
|
{
|
|
|
|
TNC = TNCInfo[portno];
|
|
|
|
|
|
|
|
if (!TNC || !TNC->TCPInfo)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet Port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TCP = TNC->TCPInfo;
|
|
|
|
TCP->CMS = 1;
|
|
|
|
#ifndef LINBPQ
|
|
|
|
CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3);
|
|
|
|
#endif
|
|
|
|
CheckCMS(TNC);
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "CMS Server Enabled\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bad port
|
|
|
|
|
|
|
|
strcpy(Bufferptr, BADPORT);
|
|
|
|
Bufferptr += (int)strlen(BADPORT);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID STOPPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char _REPLYBUFFER[1000] = "";
|
|
|
|
char * ptr, * Context;
|
|
|
|
|
|
|
|
int portno;
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
int n = NUMBEROFPORTS;
|
|
|
|
|
|
|
|
// Get port number
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
portno = atoi (ptr);
|
|
|
|
|
|
|
|
if (portno)
|
|
|
|
{
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (PORT->PORTNUMBER == portno)
|
|
|
|
{
|
|
|
|
struct KISSINFO * KISS;
|
|
|
|
|
|
|
|
if (PORT->PORTSTOPCODE)
|
|
|
|
{
|
|
|
|
// Port has Close Routine
|
|
|
|
|
|
|
|
PORT->PortStopped = TRUE;
|
|
|
|
|
|
|
|
if (PORT->PORTSTOPCODE(PORT))
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port Closed\r");
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port Close Failed\r");
|
|
|
|
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (PORT->PORTTYPE != 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not a KISS Port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PORT->PORTIPADDR.s_addr || PORT->KISSSLAVE)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not a serial port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KISS = (struct KISSINFO *) PORT;
|
|
|
|
|
|
|
|
if (KISS->FIRSTPORT != KISS)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not first port of a Multidrop Set\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CloseKISSPort(PORT);
|
|
|
|
PORT->PortStopped = TRUE;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port Closed\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bad port
|
|
|
|
|
|
|
|
strcpy(Bufferptr, BADPORT);
|
|
|
|
Bufferptr += (int)strlen(BADPORT);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID STARTPORT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char _REPLYBUFFER[1000] = "";
|
|
|
|
char * ptr, * Context;
|
|
|
|
|
|
|
|
int portno;
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
int n = NUMBEROFPORTS;
|
|
|
|
|
|
|
|
// Get port number
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
portno = atoi (ptr);
|
|
|
|
|
|
|
|
if (portno)
|
|
|
|
{
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (PORT->PORTNUMBER == portno)
|
|
|
|
{
|
|
|
|
struct KISSINFO * KISS;
|
|
|
|
|
|
|
|
if (PORT->PORTSTARTCODE)
|
|
|
|
{
|
|
|
|
// Port has Open Routine
|
|
|
|
|
|
|
|
PORT->PortStopped = FALSE;
|
|
|
|
|
|
|
|
if (PORT->PORTSTARTCODE(PORT))
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port Opened\r");
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port Open Failed\r");
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (PORT->PORTTYPE != 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not a KISS Port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PORT->PORTIPADDR.s_addr || PORT->KISSSLAVE)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not a serial port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KISS = (struct KISSINFO *) PORT;
|
|
|
|
|
|
|
|
if (KISS->FIRSTPORT != KISS)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not first port of a Multidrop Set\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-06-21 08:21:04 +01:00
|
|
|
if (OpenConnection(PORT))
|
2022-08-28 09:35:46 +01:00
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port Opened\r");
|
|
|
|
else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Port Open Failed\r");
|
|
|
|
|
|
|
|
PORT->PortStopped = FALSE;
|
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bad port
|
|
|
|
|
|
|
|
strcpy(Bufferptr, BADPORT);
|
|
|
|
Bufferptr += (int)strlen(BADPORT);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int ASYSEND(struct PORTCONTROL * PortVector, char * buffer, int count);
|
2023-06-21 08:21:04 +01:00
|
|
|
int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
VOID KISSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char _REPLYBUFFER[1000] = "";
|
|
|
|
char * ptr, * Context;
|
|
|
|
|
|
|
|
int portno = 0;
|
|
|
|
struct PORTCONTROL * PORT = PORTTABLE;
|
|
|
|
int n = NUMBEROFPORTS;
|
2023-06-21 08:21:04 +01:00
|
|
|
UCHAR KissString[128];
|
|
|
|
UCHAR ENCBUFF[256];
|
|
|
|
int KissLen = 0;
|
|
|
|
unsigned char * Kissptr = KissString;
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
// Send KISS Command to TNC
|
|
|
|
|
|
|
|
// Get port number
|
|
|
|
|
|
|
|
ptr = strtok_s(CmdTail, " ", &Context);
|
|
|
|
|
|
|
|
if (ptr)
|
|
|
|
{
|
|
|
|
portno = atoi (ptr);
|
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
2023-06-21 08:21:04 +01:00
|
|
|
while (ptr && ptr[0] && KissLen < 120)
|
2022-08-28 09:35:46 +01:00
|
|
|
{
|
2023-06-21 08:21:04 +01:00
|
|
|
*(Kissptr++) = atoi (ptr);
|
|
|
|
KissLen++;
|
2022-08-28 09:35:46 +01:00
|
|
|
ptr = strtok_s(NULL, " ", &Context);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-21 08:21:04 +01:00
|
|
|
if (portno == 0 || KissLen == 0)
|
2022-08-28 09:35:46 +01:00
|
|
|
{
|
|
|
|
strcpy(Bufferptr, BADMSG);
|
|
|
|
Bufferptr += (int)strlen(BADMSG);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (n--)
|
|
|
|
{
|
|
|
|
if (PORT->PORTNUMBER == portno)
|
|
|
|
{
|
|
|
|
struct KISSINFO * KISS;
|
|
|
|
|
|
|
|
if (PORT->PORTTYPE != 0 && PORT->PORTTYPE != 22)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not a KISS Port\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
KISS = (struct KISSINFO *) PORT;
|
|
|
|
|
|
|
|
if (KISS->FIRSTPORT != KISS)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Not first port of a Multidrop Set\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send Command
|
|
|
|
|
2023-06-21 08:21:04 +01:00
|
|
|
KissLen = KissEncode(KissString, ENCBUFF, KissLen);
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
PORT = (struct PORTCONTROL *)KISS->FIRSTPORT; // ALL FRAMES GO ON SAME Q
|
|
|
|
|
|
|
|
PORT->Session = Session;
|
|
|
|
PORT->LastKISSCmdTime = time(NULL);
|
|
|
|
|
2023-06-21 08:21:04 +01:00
|
|
|
ASYSEND(PORT, ENCBUFF, KissLen);
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Command Sent\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PORT = PORT->PORTPOINTER;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Bad port
|
|
|
|
|
|
|
|
strcpy(Bufferptr, BADPORT);
|
|
|
|
Bufferptr += (int)strlen(BADPORT);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID FINDBUFFS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
FindLostBuffers();
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Lost buffer info dumped to Debugview\r");
|
|
|
|
#else
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Lost buffer info dumped to syslog\r");
|
|
|
|
#endif
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID FLMSG(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD)
|
|
|
|
{
|
|
|
|
// Telnet Connection from FLMSG
|
|
|
|
CLOSECURRENTSESSION(Session); // Kills any crosslink, plus local link
|
|
|
|
ReleaseBuffer((UINT *)REPLYBUFFER);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL CheckExcludeList(UCHAR * Call)
|
|
|
|
{
|
|
|
|
UCHAR * ptr1 = ExcludeList;
|
|
|
|
|
|
|
|
while (*ptr1)
|
|
|
|
{
|
|
|
|
if (memcmp(Call, ptr1, 6) == 0)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
ptr1 += 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ListExcludedCalls(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
|
|
|
|
UCHAR * ptr = ExcludeList;
|
|
|
|
char Normcall[10] = "";
|
|
|
|
UCHAR AXCall[8] = "";
|
|
|
|
|
|
|
|
if (*CmdTail == ' ')
|
|
|
|
goto DISPLIST;
|
|
|
|
|
|
|
|
if (*CmdTail == 'Z')
|
|
|
|
{
|
|
|
|
// CLEAR LIST
|
|
|
|
|
|
|
|
memset(ExcludeList, 0, 70);
|
|
|
|
goto DISPLIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConvToAX25(CmdTail, AXCall);
|
|
|
|
|
|
|
|
if (strlen(ExcludeList) < 70)
|
|
|
|
strcat(ExcludeList, AXCall);
|
|
|
|
|
|
|
|
DISPLIST:
|
|
|
|
|
|
|
|
while (*ptr)
|
|
|
|
{
|
|
|
|
Normcall[ConvFromAX25(ptr, Normcall)] = 0;
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s ", Normcall);
|
|
|
|
ptr += 7;
|
|
|
|
}
|
|
|
|
|
|
|
|
*(Bufferptr++) = '\r';
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL isSYSOP(TRANSPORTENTRY * Session, char * Bufferptr)
|
|
|
|
{
|
|
|
|
if (Session->PASSWORD != 0xFFFF)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s", PASSWORDMSG);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2022-11-23 10:56:20 +00:00
|
|
|
VOID HELPCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
int FileSize;
|
|
|
|
char MsgFile[MAX_PATH];
|
|
|
|
FILE * hFile;
|
|
|
|
char * MsgBytes;
|
|
|
|
struct stat STAT;
|
|
|
|
char * ptr1, * ptr, * ptr2;
|
|
|
|
|
|
|
|
sprintf_s(MsgFile, sizeof(MsgFile), "%s/%s", BPQDirectory, "NodeHelp.txt");
|
|
|
|
|
|
|
|
if (stat(MsgFile, &STAT) == -1)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Help file not found\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSize = STAT.st_size;
|
|
|
|
|
|
|
|
hFile = fopen(MsgFile, "rb");
|
|
|
|
|
|
|
|
if (hFile == NULL)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Help file not found\r");
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
MsgBytes = malloc(FileSize+1);
|
|
|
|
|
|
|
|
fread(MsgBytes, 1, FileSize, hFile);
|
|
|
|
|
|
|
|
fclose(hFile);
|
|
|
|
|
|
|
|
MsgBytes[FileSize] = 0;
|
|
|
|
|
|
|
|
ptr1 = MsgBytes;
|
|
|
|
|
|
|
|
// Replace LF or CRLF with CR
|
|
|
|
|
|
|
|
// First remove cr from crlf
|
|
|
|
|
|
|
|
while(ptr2 = strstr(ptr1, "\r\n"))
|
|
|
|
{
|
|
|
|
memmove(ptr2, ptr2 + 1, strlen(ptr2));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now replace lf with cr
|
|
|
|
|
|
|
|
ptr1 = MsgBytes;
|
|
|
|
|
|
|
|
while (*ptr1)
|
|
|
|
{
|
|
|
|
if (*ptr1 == '\n')
|
|
|
|
*(ptr1) = '\r';
|
|
|
|
|
|
|
|
ptr1++;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = ptr1 = MsgBytes;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "\r");
|
|
|
|
|
|
|
|
// Read and send a line at a time, converting any line endings into CR
|
|
|
|
|
|
|
|
while (*ptr1)
|
|
|
|
{
|
|
|
|
if (*ptr1 == '\r')
|
|
|
|
{
|
|
|
|
*(ptr1++) = 0;
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "%s\r", ptr);
|
|
|
|
|
|
|
|
ptr = ptr1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ptr1++;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(MsgBytes);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
}
|
|
|
|
|
2023-05-16 16:40:12 +01:00
|
|
|
int UZ7HOSetFreq(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESSAGE buff, PMSGWITHLEN buffptr);
|
|
|
|
int UZ7HOSetModem(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESSAGE buff, PMSGWITHLEN buffptr);
|
2023-10-31 22:42:23 +00:00
|
|
|
int UZ7HOSetFlags(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESSAGE buff, PMSGWITHLEN buffptr);
|
2023-05-16 16:40:12 +01:00
|
|
|
|
|
|
|
|
|
|
|
VOID UZ7HOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
|
|
|
|
{
|
|
|
|
char * Cmd;
|
|
|
|
int port;
|
|
|
|
struct TNCINFO * TNC;
|
|
|
|
struct AGWINFO * AGW = 0;
|
|
|
|
PDATAMESSAGE buff;
|
|
|
|
PMSGWITHLEN buffptr;
|
|
|
|
|
2023-05-25 14:17:53 +01:00
|
|
|
CmdTail = CmdTail + (OrigCmdBuffer - COMMANDBUFFER); // Replace with original case version
|
|
|
|
|
2023-05-16 16:40:12 +01:00
|
|
|
Cmd = strlop(CmdTail, ' ');
|
|
|
|
port = atoi(CmdTail);
|
|
|
|
|
|
|
|
// remove trailing spaces
|
|
|
|
|
|
|
|
while(strlen(Cmd) && Cmd[strlen(Cmd) - 1] == ' ')
|
|
|
|
Cmd[strlen(Cmd) - 1] = 0;
|
|
|
|
|
|
|
|
TNC = TNCInfo[port];
|
|
|
|
|
|
|
|
if (TNC)
|
|
|
|
AGW = TNC->AGWInfo;
|
|
|
|
|
|
|
|
if (TNC == 0 || AGW == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Error - %d is not UZ7HO port\r", port);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-31 22:42:23 +00:00
|
|
|
if (_memicmp(Cmd, "FREQ", 4) == 0 || _memicmp(Cmd, "MODEM", 5) == 0 || _memicmp(Cmd, "FLAGS", 5) == 0)
|
2023-05-16 16:40:12 +01:00
|
|
|
{
|
|
|
|
// Pass to procesing code in UZ7HO driver. This expects command in a PDATAMESSAGE amd places response in a PMSGWITHLEN buffer
|
|
|
|
|
|
|
|
buff = (PDATAMESSAGE)GetBuff();
|
|
|
|
buffptr = (PMSGWITHLEN)GetBuff();
|
|
|
|
|
|
|
|
if (buffptr == 0)
|
|
|
|
{
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "UZ7HO Command Failed - no buffers\r");
|
|
|
|
if (buff)
|
|
|
|
ReleaseBuffer(buff);
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-25 14:17:53 +01:00
|
|
|
|
|
|
|
|
2023-05-16 16:40:12 +01:00
|
|
|
buff->LENGTH = sprintf(buff->L2DATA, "%s\r", Cmd) + MSGHDDRLEN + 1;
|
|
|
|
|
|
|
|
if (_memicmp(Cmd, "FREQ", 4) == 0)
|
|
|
|
UZ7HOSetFreq(port, TNC, AGW, buff, buffptr);
|
2023-10-31 22:42:23 +00:00
|
|
|
else if (_memicmp(Cmd, "FLAGS", 5) == 0)
|
|
|
|
UZ7HOSetFlags(port, TNC, AGW, buff, buffptr);
|
2023-05-16 16:40:12 +01:00
|
|
|
else
|
|
|
|
UZ7HOSetModem(port, TNC, AGW, buff, buffptr);
|
|
|
|
|
|
|
|
|
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, buffptr->Data);
|
|
|
|
|
|
|
|
ReleaseBuffer(buff);
|
|
|
|
ReleaseBuffer(buffptr);
|
|
|
|
}
|
|
|
|
else
|
2023-10-31 22:42:23 +00:00
|
|
|
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid UZ7HO Command (not Freq Modem or FLAGS)\r");
|
2023-05-16 16:40:12 +01:00
|
|
|
|
|
|
|
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-11-23 10:56:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
2022-08-28 09:35:46 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|