linbpq/Cmd.c

5596 lines
128 KiB
C

/*
Copyright 2001-2022 John Wiseman G8BPQ
This file is part of LinBPQ/BPQ32.
LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
LinBPQ/BPQ32 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
*/
//
// 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"
#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
char OrigCmdBuffer[81] = ""; // Command Hander input buffer
struct DATAMESSAGE * REPLYBUFFER = NULL;
UINT APPLMASK = 0;
UCHAR SAVEDAPPLFLAGS = 0;
UCHAR ALIASINVOKED = 0;
extern struct TNCINFO * TNCInfo[41];
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);
VOID HELPCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD);
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));
}
VOID CMDP00(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
{
// Process PORTS Message
struct PORTCONTROL * PORT = PORTTABLE;
Bufferptr = Cmdprintf(Session, Bufferptr, "Ports\r");
while (PORT)
{
if (PORT->Hide == 0)
Bufferptr = Cmdprintf(Session, Bufferptr, " %2d %s\r", PORT->PORTNUMBER, PORT->PORTDESCRIPTION);
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;
unsigned int ListenMask = 0;
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;
ptr = strtok_s(NULL, ", ", &Context); // Get Unproto String
if (Port)
PORT = GetPortTableEntryFromPortNum(Port);
if (PORT == NULL)
{
Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port %d\r", Port);
continue;
}
if (PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0)
{
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);
ListenMask |= (1 << (Port - 1));
}
Session->LISTEN = ListenMask;
if (ListenMask)
{
if (CountBits(ListenMask) == 1)
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;
unsigned int MaskCopy = Session->LISTEN;
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);
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
if (Port && PORT->PROTOCOL == 10 && memcmp(EXTPORT->PORT_DLL_NAME, "SCSPACTOR", 9) == 0)
{
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);
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));
}
int Rig_Command(int Session, char * Command);
VOID RADIOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * UserCMD)
{
char * ptr;
if (Rig_Command(Session->CIRCUITINDEX, CmdTail))
{
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;
struct TNCINFO * TNC;
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)
{
for (i=1; i<33; i++)
{
OtherTNC = TNCInfo[i];
if (OtherTNC == NULL)
continue;
if (OtherTNC == TNC)
continue;
if (rxInterlock == OtherTNC->RXRadio || txInterlock == OtherTNC->TXRadio) // Same Group
{
if (OtherTNC->PortRecord->ATTACHEDSESSIONS[0])
{
Bufferptr = Cmdprintf(Session, Bufferptr, "Sorry, interlocked port %d is in use\r", i);
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
return;
}
}
}
}
}
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:
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,
"HELP ",1,HELPCMD,0,
"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,
"..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)
{
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);
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
// SendUIModeFrame(Session, (PMESSAGE)Buffer, Session->UNPROTO);
ReleaseBuffer((UINT *)Buffer); // Not using buffer for reply
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 struct TNCINFO * TNCInfo[41];
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);
int OpenConnection(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;
}
if (OpenConnection(PORT), TRUE)
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;
}
#define FEND 0xC0
int ASYSEND(struct PORTCONTROL * PortVector, char * buffer, int count);
VOID KISSCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD)
{
char _REPLYBUFFER[1000] = "";
char * ptr, * Context;
int portno = 0;
int cmd = 0, val = 0;
struct PORTCONTROL * PORT = PORTTABLE;
int n = NUMBEROFPORTS;
// Send KISS Command to TNC
// Get port number
ptr = strtok_s(CmdTail, " ", &Context);
if (ptr)
{
portno = atoi (ptr);
ptr = strtok_s(NULL, " ", &Context);
if (ptr)
{
cmd = atoi (ptr);
ptr = strtok_s(NULL, " ", &Context);
if (ptr)
val = atoi (ptr);
}
}
if (portno == 0 || cmd == 0)
{
strcpy(Bufferptr, BADMSG);
Bufferptr += (int)strlen(BADMSG);
SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER));
return;
}
while (n--)
{
if (PORT->PORTNUMBER == portno)
{
struct KISSINFO * KISS;
UCHAR ENCBUFF[16];
unsigned char * ptr = ENCBUFF;
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
*(ptr++) = FEND;
*(ptr++) = KISS->OURCTRL | cmd;
*(ptr++) = (UCHAR)val;
*(ptr++) = FEND;
PORT = (struct PORTCONTROL *)KISS->FIRSTPORT; // ALL FRAMES GO ON SAME Q
PORT->Session = Session;
PORT->LastKISSCmdTime = time(NULL);
ASYSEND(PORT, ENCBUFF, 4);
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;
}
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));
}