diff --git a/6pack.c b/6pack.c index 9e0eef0..8f954d8 100644 --- a/6pack.c +++ b/6pack.c @@ -72,7 +72,7 @@ Using code from 6pack Linux Kernel driver with the following licence and credits #include "compatbits.h" #include -#include "CHeaders.h" +#include "cheaders.h" #include "bpq32.h" diff --git a/AEAPactor.c b/AEAPactor.c index 643dae1..2d5af4b 100644 --- a/AEAPactor.c +++ b/AEAPactor.c @@ -45,7 +45,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses //#include //#include -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "bpq32.h" diff --git a/AGWAPI.c b/AGWAPI.c index 462fe86..bf4c7da 100644 --- a/AGWAPI.c +++ b/AGWAPI.c @@ -26,7 +26,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses */ #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #include "bpq32.h" diff --git a/AGWMoncode.c b/AGWMoncode.c index bd5a7e8..7427804 100644 --- a/AGWMoncode.c +++ b/AGWMoncode.c @@ -33,7 +33,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #pragma data_seg("_BPQDATA") -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" // MSGFLAG contains CMD/RESPONSE BITS diff --git a/AISCommon.c b/AISCommon.c index d33f25a..f0b6a6a 100644 --- a/AISCommon.c +++ b/AISCommon.c @@ -7,7 +7,7 @@ #include #include #include "time.h" -#include "CHeaders.h" +#include "cheaders.h" //#include "tncinfo.h" //#include "adif.h" //#include "telnetserver.h" diff --git a/APRSCode.c b/APRSCode.c index 497ea74..7255c7a 100644 --- a/APRSCode.c +++ b/APRSCode.c @@ -25,7 +25,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE #include -#include "CHeaders.h" +#include "cheaders.h" #include "bpq32.h" #include #include "kernelresource.h" diff --git a/ARDOP.c b/ARDOP.c index 704092f..4e4cc8d 100644 --- a/ARDOP.c +++ b/ARDOP.c @@ -45,7 +45,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #endif #endif -#include "CHeaders.h" +#include "cheaders.h" int (WINAPI FAR *GetModuleFileNameExPtr)(); @@ -136,6 +136,9 @@ BOOL ARDOPStopPort(struct PORTCONTROL * PORT) if (TNC->Streams[0].Attached) TNC->Streams[0].ReportDISC = TRUE; + TNC->Streams[0].Connected = 0; + TNC->Streams[0].Attached = 0; + if (TNC->TCPSock) { shutdown(TNC->TCPSock, SD_BOTH); @@ -162,6 +165,9 @@ BOOL ARDOPStopPort(struct PORTCONTROL * PORT) sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Stopped"); MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE); + strcpy(TNC->WEB_TNCSTATE, "Free"); + MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); + return TRUE; } @@ -643,6 +649,12 @@ VOID ARDOPSendCommand(struct TNCINFO * TNC, char * Buff, BOOL Queue) if (Buff[0] == 0) // Terminal Keepalive? return; + if (memcmp(Buff, "LISTEN ", 7) == 0) + { + strcpy(TNC->WEB_MODE, &Buff[7]); + MySetWindowText(TNC->xIDC_MODE, &Buff[7]); + } + EncLen = sprintf(Encoded, "%s\r", Buff); // it is possible for binary data to be dumped into the command @@ -1918,7 +1930,7 @@ static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL) Len += sprintf(&Buff[Len], "Comms State%s", TNC->WEB_COMMSSTATE); Len += sprintf(&Buff[Len], "TNC State%s", TNC->WEB_TNCSTATE); - Len += sprintf(&Buff[Len], "Mode%s", TNC->WEB_MODE); + Len += sprintf(&Buff[Len], "Listen%s", TNC->WEB_MODE); Len += sprintf(&Buff[Len], "Channel State%s   %s", TNC->WEB_CHANSTATE, TNC->WEB_LEVELS); Len += sprintf(&Buff[Len], "Proto State%s", TNC->WEB_PROTOSTATE); Len += sprintf(&Buff[Len], "Traffic%s", TNC->WEB_TRAFFIC); @@ -2134,7 +2146,7 @@ VOID * ARDOPExtInit(EXTPORTDATA * PortEntry) CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 120,28,520,20, TNC->hDlg, NULL, hInstance, NULL); - CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL); + CreateWindowEx(0, "STATIC", "Listen", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 120,50,200,20, TNC->hDlg, NULL, hInstance, NULL); CreateWindowEx(0, "STATIC", "Channel State", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL); @@ -2600,6 +2612,8 @@ VOID ARDOPThread(struct TNCINFO * TNC) TNC->Alerted = TRUE; + ARDOPSendCommand(TNC, "LISTEN TRUE", TRUE); + sprintf(TNC->WEB_COMMSSTATE, "Connected to ARDOP TNC"); MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); @@ -2679,6 +2693,10 @@ VOID ARDOPThread(struct TNCINFO * TNC) sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost"); MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); + strcpy(TNC->WEB_TNCSTATE, "Free"); + MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); + + TNC->CONNECTED = FALSE; TNC->Alerted = FALSE; @@ -3344,6 +3362,9 @@ VOID ARDOPProcessResponse(struct TNCINFO * TNC, UCHAR * Buffer, int MsgLen) RestartTNC(TNC); } + sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall); + MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); + return; } diff --git a/BBSHTMLConfig.c b/BBSHTMLConfig.c index 3234c00..6207298 100644 --- a/BBSHTMLConfig.c +++ b/BBSHTMLConfig.c @@ -19,7 +19,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #include "bpqmail.h" #ifdef WIN32 @@ -2219,21 +2219,21 @@ VOID ProcessUserUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char ptr1 = GetNextParam(&ptr2); // Last Listed USER->lastmsg = atoi(ptr1); ptr1 = GetNextParam(&ptr2); // Name - strcpy(USER->Name, ptr1); + memcpy(USER->Name, ptr1, 17); ptr1 = GetNextParam(&ptr2); // Pass - strcpy(USER->pass, ptr1); + memcpy(USER->pass, ptr1, 12); ptr1 = GetNextParam(&ptr2); // CMS Pass if (memcmp("****************", ptr1, strlen(ptr1) != 0)) { - strcpy(USER->CMSPass, ptr1); + memcpy(USER->CMSPass, ptr1, 15); } ptr1 = GetNextParam(&ptr2); // QTH - strcpy(USER->Address, ptr1); + memcpy(USER->Address, ptr1, 60); ptr1 = GetNextParam(&ptr2); // ZIP - strcpy(USER->ZIP, ptr1); + memcpy(USER->ZIP, ptr1, 8); ptr1 = GetNextParam(&ptr2); // HomeBBS - strcpy(USER->HomeBBS, ptr1); + memcpy(USER->HomeBBS, ptr1, 40); _strupr(USER->HomeBBS); SaveUserDatabase(); @@ -3038,13 +3038,10 @@ static DWORD WINAPI InstanceThread(LPVOID lpvParam) const char * auth_header = "Authorization: Bearer "; char * token_begin = strstr(MsgPtr, auth_header); - int Flags = 0, n; + int Flags = 0; // Node Flags isn't currently used - char * Tok; - char * param; - if (token_begin) { // Using Auth Header diff --git a/BBSUtilities.c b/BBSUtilities.c index 50de210..8e7c10a 100644 --- a/BBSUtilities.c +++ b/BBSUtilities.c @@ -28,6 +28,10 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include #endif +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); + +BOOL GetStringValue(config_setting_t * group, char * name, char * value, int maxlen); BOOL Bells; BOOL FlashOnBell; // Flash instead of Beep @@ -77,7 +81,7 @@ FARPROCX pRefreshWebMailIndex; Dll BOOL APIENTRY APISendAPRSMessage(char * Text, char * ToCall); VOID APIENTRY md5 (char *arg, unsigned char * checksum); int APIENTRY GetRaw(int stream, char * msg, int * len, int * count); -void GetSemaphore(struct SEM * Semaphore, int ID); +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); void FreeSemaphore(struct SEM * Semaphore); int EncryptPass(char * Pass, char * Encrypt); VOID DecryptPass(char * Encrypt, unsigned char * Pass, unsigned int len); @@ -6574,8 +6578,6 @@ VOID CreateMessageFile(ConnectionInfo * conn, struct MsgInfo * Msg) } - - VOID SendUnbuffered(int stream, char * msg, int len) { #ifndef LINBPQ @@ -7302,7 +7304,7 @@ VOID SetupForwardingStruct(struct UserInfo * user) if (ForwardingInfo->ConTimeout == 0) ForwardingInfo->ConTimeout = 120; - GetStringValue(group, "BBSHA", Temp); + GetStringValue(group, "BBSHA", Temp, 100); if (Temp[0]) ForwardingInfo->BBSHA = _strdup(Temp); @@ -10136,15 +10138,20 @@ int GetIntValueWithDefault(config_setting_t * group, char * name, int Default) } -BOOL GetStringValue(config_setting_t * group, char * name, char * value) +BOOL GetStringValue(config_setting_t * group, char * name, char * value, int maxlen) { - const char * str; + char * str; config_setting_t *setting; setting = config_setting_get_member (group, name); if (setting) { - str = config_setting_get_string (setting); + str = (char *)config_setting_get_string (setting); + if (strlen(str) > maxlen) + { + Debugprintf("Suspect config record %s", str); + str[maxlen] = 0; + } strcpy(value, str); return TRUE; } @@ -10221,25 +10228,24 @@ BOOL GetConfig(char * ConfigName) Localtime = GetIntValue(group, "Localtime"); AliasText = GetMultiStringValue(group, "FWDAliases"); - GetStringValue(group, "BBSName", BBSName); - GetStringValue(group, "MailForText", MailForText); - GetStringValue(group, "SYSOPCall", SYSOPCall); - GetStringValue(group, "H-Route", HRoute); - GetStringValue(group, "AMPRDomain", AMPRDomain); + GetStringValue(group, "BBSName", BBSName, 100); + GetStringValue(group, "MailForText", MailForText, 100); + GetStringValue(group, "SYSOPCall", SYSOPCall, 100); + GetStringValue(group, "H-Route", HRoute, 100); + GetStringValue(group, "AMPRDomain", AMPRDomain, 100); SendAMPRDirect = GetIntValue(group, "SendAMPRDirect"); ISP_Gateway_Enabled = GetIntValue(group, "SMTPGatewayEnabled"); ISPPOP3Interval = GetIntValue(group, "POP3PollingInterval"); - GetStringValue(group, "MyDomain", MyDomain); - GetStringValue(group, "ISPSMTPName", ISPSMTPName); - GetStringValue(group, "ISPPOP3Name", ISPPOP3Name); + GetStringValue(group, "MyDomain", MyDomain, 50); + GetStringValue(group, "ISPSMTPName", ISPSMTPName, 50); + GetStringValue(group, "ISPPOP3Name", ISPPOP3Name, 50); ISPSMTPPort = GetIntValue(group, "ISPSMTPPort"); ISPPOP3Port = GetIntValue(group, "ISPPOP3Port"); - GetStringValue(group, "ISPAccountName", ISPAccountName); - GetStringValue(group, "ISPAccountPass", EncryptedISPAccountPass); - GetStringValue(group, "ISPAccountName", ISPAccountName); + GetStringValue(group, "ISPAccountName", ISPAccountName, 50); + GetStringValue(group, "ISPAccountPass", EncryptedISPAccountPass, 100); sprintf(SignoffMsg, "73 de %s\r", BBSName); // Default - GetStringValue(group, "SignoffMsg", SignoffMsg); + GetStringValue(group, "SignoffMsg", ISPAccountName, 50); DecryptPass(EncryptedISPAccountPass, ISPAccountPass, (int)strlen(EncryptedISPAccountPass)); @@ -10251,10 +10257,10 @@ BOOL GetConfig(char * ConfigName) #ifndef LINBPQ - GetStringValue(group, "MonitorSize", Size); + GetStringValue(group, "MonitorSize", Size, sizeof(Size)); sscanf(Size,"%d,%d,%d,%d,%d",&MonitorRect.left,&MonitorRect.right,&MonitorRect.top,&MonitorRect.bottom,&OpenMon); - GetStringValue(group, "WindowSize", Size); + GetStringValue(group, "WindowSize", Size, sizeof(Size)); sscanf(Size,"%d,%d,%d,%d",&MainRect.left,&MainRect.right,&MainRect.top,&MainRect.bottom); Bells = GetIntValue(group, "Bells"); @@ -10267,7 +10273,7 @@ BOOL GetConfig(char * ConfigName) WrapInput = GetIntValue(group, "WrapInput"); FlashOnConnect = GetIntValue(group, "FlashOnConnect"); - GetStringValue(group, "ConsoleSize", Size); + GetStringValue(group, "ConsoleSize", Size, 80); sscanf(Size,"%d,%d,%d,%d,%d", &ConsoleRect.left, &ConsoleRect.right, &ConsoleRect.top, &ConsoleRect.bottom,&OpenConsole); @@ -10346,7 +10352,7 @@ BOOL GetConfig(char * ConfigName) // Get FBB Filters - GetStringValue(group, "FBBFilters", FBBString); + GetStringValue(group, "FBBFilters", FBBString, sizeof(FBBString)); ptr1 = FBBString; @@ -10432,8 +10438,8 @@ BOOL GetConfig(char * ConfigName) SendWP = GetIntValue(group, "SendWP"); SendWPType = GetIntValue(group, "SendWPType"); - GetStringValue(group, "SendWPTO", SendWPTO); - GetStringValue(group, "SendWPVIA", SendWPVIA); + GetStringValue(group, "SendWPTO", SendWPTO, sizeof(SendWPTO)); + GetStringValue(group, "SendWPVIA", SendWPVIA, sizeof(SendWPVIA)); SendWPAddrs = GetMultiStringValue(group, "SendWPAddrs"); @@ -10463,7 +10469,7 @@ BOOL GetConfig(char * ConfigName) SendWPVIA[0] = 0; } - GetStringValue(group, "Version", Size); + GetStringValue(group, "Version", Size, sizeof(Size)); sscanf(Size,"%d,%d,%d,%d", &LastVer[0], &LastVer[1], &LastVer[2], &LastVer[3]); for (i =1 ; i <= GetNumberofPorts(); i++) @@ -10481,7 +10487,7 @@ BOOL GetConfig(char * ConfigName) UIHDDR[i] = GetIntValueWithDefault(group, "SendHDDR", UIEnabled[i]); UINull[i] = GetIntValue(group, "SendNull"); Size[0] = 0; - GetStringValue(group, "Digis", Size); + GetStringValue(group, "Digis", Size, sizeof(Size)); if (Size[0]) UIDigi[i] = _strdup(Size); } diff --git a/BPQINP3.c b/BPQINP3.c index dac41c4..38c49b9 100644 --- a/BPQINP3.c +++ b/BPQINP3.c @@ -28,7 +28,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #pragma data_seg("_BPQDATA") -#include "CHeaders.h" +#include "cheaders.h" #include "time.h" #include "stdio.h" diff --git a/BPQMail.c b/BPQMail.c index 64eb9a3..f566d64 100644 --- a/BPQMail.c +++ b/BPQMail.c @@ -1146,6 +1146,7 @@ // Fix sending ampr.org mail when RMS is not enabled (51) // Send forwarding info to packetnodes.spots.radio database (51) // Fix bug in WP Message processing (56) +// Fix treating addresses ending in WW as Internet (57) #include "bpqmail.h" #include "winstdint.h" @@ -1537,7 +1538,11 @@ VOID WriteMiniDump() } -void GetSemaphore(struct SEM * Semaphore, int ID) + +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) + + +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line) { // // Wait for it to be free diff --git a/BPQNRR.c b/BPQNRR.c index 554b0e5..7a54777 100644 --- a/BPQNRR.c +++ b/BPQNRR.c @@ -36,7 +36,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses //#include "vmm.h" -#include "CHeaders.h" +#include "cheaders.h" extern int SENDNETFRAME(); diff --git a/BPQtoAGW.c b/BPQtoAGW.c index b91a20c..a173c66 100644 --- a/BPQtoAGW.c +++ b/BPQtoAGW.c @@ -56,7 +56,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #ifndef WIN32 #include #include diff --git a/Bpq32-skigdebian.c b/Bpq32-skigdebian.c new file mode 100644 index 0000000..a78510b --- /dev/null +++ b/Bpq32-skigdebian.c @@ -0,0 +1,6741 @@ +/* +Copyright 2001-2022 John Wiseman G8BPQ + +This file is part of LinBPQ/BPQ32. + +LinBPQ/BPQ32 is free software: you can redistribute it and/or modifyextern int HTTP +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 +*/ +// +// 409l Oct 2001 Fix l3timeout for KISS +// +// 409m Oct 2001 Fix Crossband Digi +// +// 409n May 2002 Change error handling on load ext DLL + +// 409p March 2005 Allow Multidigit COM Ports (kiss.c) + +// 409r August 2005 Treat NULL string in Registry as use current directory +// Allow shutdown to close BPQ Applications + +// 409s October 2005 Add DLL:Export entries to API for BPQTNC2 + +// 409t January 2006 +// +// Add API for Perl "GetPerlMsg" +// Add API for BPQ1632 "GETBPQAPI" - returns address of Assembler API routine +// Add Registry Entry "BPQ Directory". If present, overrides "Config File Location" +// Add New API "GetBPQDirectory" - Returns location of config file +// Add New API "ChangeSessionCallsign" - equivalent to "*** linked to" command +// Rename BPQNODES to BPQNODES.dat +// New API "GetAttachedProcesses" - returns number of processes connected. +// Warn if user trys to close Console Window. +// Add Debug entries to record Process Attach/Detach +// Fix recovery following closure of first process + +// 409t Beta 2 February 2006 +// +// Add API Entry "GetPortNumber" +// +// 409u February 2006 +// +// Fix crash if allocate/deallocate called with stream=0 +// Add API to ch +// Display config file path +// Fix saving of Locked Node flag +// Added SAVENODES SYSOP command +// +// 409u 2 March 2006 +// +// Fix SetupBPQDirectory +// Add CopyBPQDirectory (for Basic Programs) +// +// 409u 3 March 2006 +// +// Release streams on DLL unload + +// 409v October 2006 +// +// Support Minimize to Tray for all BPQ progams +// Implement L4 application callsigns + +// 410 November 2006 +// +// Modified to compile with C++ 2005 Express Edition +// Make MCOM MTX MMASK local variables +// +// 410a January 2007 +// +// Add program name to Attach-Detach messages +// Attempt to detect processes which have died +// Fix bug in NETROM and IFrame decode which would cause crash if frame was corrupt +// Add BCALL - origin call for Beacons +// Fix KISS ACKMODE ACK processing +// + +// 410b November 2007 +// +// Allow CTEXT of up to 510, and enforce PACLEN, fragmenting if necessary + +// 410c December 2007 + +// Fix problem with NT introduced in V410a +// Display location of DLL on Console + +// 410d January 2008 + +// Fix crash in DLL Init caused by long path to program +// Invoke Appl2 alias on C command (if enabled) +// Allow C command to be disabled +// Remove debug trap in GETRAWFRAME +// Validate Alias of directly connected node, mainly for KPC3 DISABL Problem +// Move Port statup code out of DLLInit (mainly for perl) +// Changes to allow Load/Unload of bpq32.dll by appl +// CloseBPQ32 API added +// Ext Driver Close routes called +// Changes to release Mutex + +// 410e May 2008 + +// Fix missing SSID on last call of UNPROTO string (CONVTOAX25 in main.asm) +// Fix VCOM Driver (RX Len was 1 byte too long) +// Fix possible crash on L4CODE if L4DACK received out of sequence +// Add basic IP decoding + +// 410f October 2008 + +// Add IP Gateway +// Add Multiport DIGI capability +// Add GetPortDescription API +// Fix potential hangs if RNR lost +// Fix problem if External driver failes to load +// Put pushad/popad round _INITIALISEPORTS (main.asm) +// Add APIs GetApplCallVB and GetPortDescription (mainly for RMS) +// Ensure Route Qual is updated if Port Qual changed +// Add Reload Option, plus menu items for DUMP and SAVENODES + +// 410g December 2008 + +// Restore API Exports BPQHOSTAPIPTR and MONDECODEPTR (accidentally deleted) +// Fix changed init of BPQDirectory (accidentally changed) +// Fix Checks for lost processes (accidentally deleted) +// Support HDLC Cards on W2K and above +// Delete Tray List entries for crashed processes +// Add Option to NODES command to sort by Callsign +// Add options to save or clear BPQNODES before Reconfig. +// Fix Reconfig in Win98 +// Monitor buffering tweaks +// Fix Init for large (>64k) tables +// Fix Nodes count in Stats + +// 410h January 2009 + +// Add Start Minimized Option +// Changes to KISS for WIn98 Virtual COM +// Open \\.\com instead of //./COM +// Extra Dignostics + +// 410i Febuary 2009 + +// Revert KISS Changes +// Save Window positions + +// 410j June 2009 + +// Fix tidying of window List when program crashed +// Add Max Nodes to Stats +// Don't update APPLnALIAS with received NODES info +// Fix MH display in other timezones +// Fix Possible crash when processing NETROM type Zero frames (eg NRR) +// Basic INP3 Stuff +// Add extra diagnostics to Lost Process detection +// Process Netrom Record Route frames. + +// 410k June 2009 + +// Fix calculation of %retries in extended ROUTES display +// Fix corruption of ROUTES table + +// 410l October 2009 + +// Add GetVersionString API call. +// Add GetPortTableEntry API call +// Keep links to neighbouring nodes open + +// Build 2 + +// Fix PE in NOROUTETODEST (missing POP EBX) + +// 410m November 2009 + +// Changes for PACTOR and WINMOR to support the ATTACH command +// Enable INP3 if configured on a route. +// Fix count of nodes in Stats Display +// Overwrite the worst quality unused route if a call is received from a node not in your +// table when the table is full + +// Build 5 + +// Rig Control Interface +// Limit KAM VHF attach and RADIO commands to authorised programs (MailChat and BPQTerminal) + +// Build 6 + +// Fix reading INP3 Flag from BPQNODES + +// Build 7 + +// Add MAXHOPS and MAXRTT config options + +// Build 8 + +// Fix INP3 deletion of Application Nodes. +// Fix GETCALLSIGN for Pactor Sessions +// Add N Call* to display all SSID's of a call +// Fix flow control on Pactor sessions. + +// Build 9 + +// HDLC Support for XP +// Add AUTH routines + +// Build 10 + +// Fix handling commands split over more that one packet. + +// Build 11 + +// Attach cmd changes for winmor disconnecting state +// Option Interlock Winmor/Pactor ports + +// Build 12 + +// Add APPLS export for winmor +// Handle commands ending CR LF + +// Build 13 + +// Incorporate Rig Control in Kernel + +// Build 14 + +// Fix config reload for Rig COntrol + +// 410n March 2010 + +// Implement C P via PACTOR/WINMOR (for Airmail) + +// Build 2 + +// Don't flip SSID bits on Downlink Connect if uplink is Pactor/WINMOR +// Fix resetting IDLE Timer on Pactor/WINMOR sessions +// Send L4 KEEPLI messages based on IDLETIME + +// 410o July 2010 + +// Read bpqcfg.txt instead of .bin +// Support 32 bit MMASK (Allowing 32 Ports) +// Support 32 bit _APPLMASK (Allowing 32 Applications) +// Allow more commands +// Allow longer command aliases +// Fix logic error in RIGControl Port Initialisation (wasn't always raising RTS and DTR +// Clear RIGControl RTS and DTR on close + +// 410o Build 2 August 2010 + +// Fix couple of errors in config (needed APPLICATIONS and BBSCALL/ALIAS/QUAL) +// Fix Kenwood Rig Control when more than one message received at once. +// Save minimzed state of Rigcontrol Window + +// 410o Build 3 August 2010 + +// Fix reporting of set errors in scan to a random session + +// 410o Build 4 August 2010 + +// Change All xxx Ports are in use to no xxxx Ports are available if there are no sessions with _APPLMASK +// Fix validation of TRANSDELAY + +// 410o Build 5 August 2010 + +// Add Repeater Shift and Set Data Mode options to Rigcontrol (for ICOM only) +// Add WINMOR and SCS Pactor mode control option to RigControl +// Extend INFOMSG to 2000 bytes +// Improve Scan freq change lock (check both SCS and WINMOR Ports) + +// 410o Build 6 September 2010 + +// Incorporate IPGateway in main code. +// Fix GetSessionInfo for Pactor/Winmor Ports +// Add Antenna Selection to RigControl +// Allow Bandwidth options on RADIO command line (as well as in Scan definitions) + +// 410o Build 7 September 2010 + +// Move rigconrtol display to driver windows +// Move rigcontrol config to driver config. +// Allow driver and IPGateway config info in bpq32.cfg +// Move IPGateway, AXIP, VKISS, AGW and WINMOR drivers into bpq32.dll +// Add option to reread IP Gateway config. +// Fix Reinit after process with timer closes (error in TellSessions). + +// 410p Build 2 October 2010 + +// Move KAM and SCS drivers to bpq32.dll + +// 410p Build 3 October 2010 + +// Support more than one axip port. + +// 410p Build 4 October 2010 + +// Dynamically load psapi.dll (for 98/ME) + +// 410p Build 5 October 2010 + +// Incorporate TelnetServer +// Fix AXIP ReRead Config +// Report AXIP accept() fails to syslog, not a popup. + +// 410p Build 6 October 2010 + +// Includes HAL support +// Changes to Pactor Drivers disconnect code +// AXIP now sends with source port = dest port, unless overridden by SOURCEPORT param +// Config now checks for duplicate port definitions +// Add Node Map reporting +// Fix WINMOR deferred disconnect. +// Report Pactor PORTCALL to WL2K instead of RMS Applcall + +// 410p Build 7 October 2010 + +// Add In/Out flag to Map reporting, and report centre, not dial +// Write Telnet log to BPQ Directory +// Add Port to AXIP resolver display +// Send Reports to update.g8bpq.net:81 +// Add support for FT100 to Rigcontrol +// Add timeout to Rigcontrol PTT +// Add Save Registry Command + +// 410p Build 8 November 2010 + +// Add NOKEEPALIVES Port Param +// Renumbered for release + +// 410p Build 9 November 2010 + +// Get Bandwith for map report from WL2K Report Command +// Fix freq display for FT100 (was KHz, not MHz) +// Don't try to change SCS mode whilst initialising +// Allow reporting of Lat/Lon as well as Locator +// Fix Telnet Log Name +// Fix starting with Minimized windows when Minimizetotray isn't set +// Extra Program Error trapping in SessionControl +// Fix reporting same freq with different bandwidths at different times. +// Code changes to support SCS Robust Packet Mode. +// Add FT2000 to Rigcontrol +// Only Send CTEXT to connects to Node (not to connects to an Application Call) + +// Released as Build 10 + +// 410p Build 11 January 2011 + +// Fix MH Update for SCS Outgoing Calls +// Add Direct CMS Access to TelnetServer +// Restructure DISCONNECT processing to run in Timer owning process + +// 410p Build 12 January 2011 + +// Add option for Hardware PTT to use a different com port from the scan port +// Add CAT PTT for Yaesu 897 (and maybe others) +// Fix RMS Packet ports busy after restart +// Fix CMS Telnet with MAXSESSIONS > 10 + +// 410p Build 13 January 2011 + +// Fix loss of buffers in TelnetServer +// Add CMS logging. +// Add non - Promiscuous mode option for BPQETHER + +// 410p Build 14 January 2011 + +// Add support for BPQTermTCP +// Allow more that one FBBPORT +// Allow Telnet FBB mode sessions to send CRLF as well as CR on user and pass msgs +// Add session length to CMS Telnet logging. +// Return Secure Session Flag from GetConnectionInfo +// Show Uptime as dd/hh/mm + +// 4.10.16.17 March 2011 + +// Add "Close all programs" command +// Add BPQ Program Directory registry key +// Use HKEY_CURRENT_USER on Vista and above (and move registry if necessary) +// Time out IP Gateway ARP entries, and only reload ax.25 ARP entries +// Add support for SCS Tracker HF Modes +// Fix WL2K Reporting +// Report Version to WL2K +// Add Driver to support Tracker with multiple sessions (but no scanning, wl2k report, etc) + + +// Above released as 5.0.0.1 + +// 5.2.0.1 + +// Add caching of CMS Server IP addresses +// Initialise TNC State on Pactor Dialogs +// Add Shortened (6 digit) AUTH mode. +// Update MH with all frames (not just I/UI) +// Add IPV6 Support for TelnetServer and AXIP +// Fix TNC OK Test for Tracker +// Fix crash in CMS mode if terminal disconnects while tcp commect in progress +// Add WL2K reporting for Robust Packet +// Add option to suppress WL2K reporting for specific frequencies +// Fix Timeband processing for Rig Control +// New Driver for SCS Tracker allowing multiple connects, so Tracker can be used for user access +// New Driver for V4 TNC + +// 5.2.1.3 October 2011 + +// Combine busy detector on Interlocked Ports (SCS PTC, WINMOR or KAM) +// Improved program error logging +// WL2K reporting changed to new format agreed with Lee Inman + +// 5.2.3.1 January 2012 + +// Connects from the console to an APPLCALL or APPLALIAS now invoke any Command Alias that has been defined. +// Fix reporting of Tracker freqs to WL2K. +// Fix Tracker monitoring setup (sending M UISC) +// Fix possible call/application routing error on RP +// Changes for P4Dragon +// Include APRS Digi/IGate +// Tracker monitoring now includes DIGIS +// Support sending UI frames using SCSTRACKER, SCTRKMULTI and UZ7HO drivers +// Include driver for UZ7HO soundcard modem. +// Accept DRIVER as well as DLLNAME, and COMPORT as well as IOADDR in bpq32.cfg. COMPORT is decimal +// No longer supports separate config files, or BPQTELNETSERVER.exe +// Improved flow control for Telnet CMS Sessions +// Fix handling Config file without a newline after last line +// Add non - Promiscuous mode option for BPQETHER +// Change Console Window to a Dialog Box. +// Fix possible corruption and loss of buffers in Tracker drivers +// Add Beacon After Session option to Tracker and UZ7HO Drivers +// Rewrite RigControl and add "Reread Config Command" +// Support User Mode VCOM Driver for VKISS ports + +// 5.2.4.1 January 2012 + +// Remove CR from Telnet User and Password Prompts +// Add Rigcontrol to UZ7HO driver +// Fix corruption of Free Buffer Count by Rigcontol +// Fix WINMOR and V4 PTT +// Add MultiPSK Driver +// Add SendBeacon export for BPQAPRS +// Add SendChatReport function +// Fix check on length of Port Config ID String with trailing spaces +// Fix interlock when Port Number <> Port Slot +// Add NETROMCALL for L3 Activity +// Add support for APRS Application +// Fix Telnet with FBBPORT and no TCPPORT +// Add Reread APRS Config +// Fix switching to Pactor after scanning in normal packet mode (PTC) + +// 5.2.5.1 February 2012 + +// Stop reading Password file. +// Add extra MPSK commands +// Fix MPSK Transparency +// Make LOCATOR command compulsory +// Add MobileBeaconInterval APRS param +// Send Course and Speed when APRS is using GPS +// Fix Robust Packet reporting in PTC driver +// Fix corruption of some MIC-E APRS packets + +// 5.2.6.1 February 2012 + +// Convert to MDI presentation of BPQ32.dll windows +// Send APRS Status packets +// Send QUIT not EXIT in PTC Init +// Implement new WL2K reporting format and include traffic reporting info in CMS signon +// New WL2KREPORT format +// Prevent loops when APPL alias refers to itself +// Add RigControl for Flex radios and ICOM IC-M710 Marine radio + +// 5.2.7.1 + +// Fix opening more thn one console window on Win98 +// Change method of configuring multiple timelots on WL2K reporting +// Add option to update WK2K Sysop Database +// Add Web server +// Add UIONLY port option + +// 5.2.7.2 + +// Fix handling TelnetServer packets over 500 bytes in normal mode + +// 5.2.7.3 + +// Fix Igate handling packets from UIView + +// 5.2.7.4 + +// Prototype Baycom driver. + +// 5.2.7.5 + +// Set WK2K group ref to MARS (3) if using a MARS service code + +// 5.2.7.7 + +// Check for programs calling CloseBPQ32 when holding semaphore +// Try/Except round Status Timer Processing + +// 5.2.7.8 + +// More Try/Except round Timer Processing + +// 5.2.7.9 + +// Enable RX in Baycom, and remove test loopback in tx + +// 5.2.7.10 + +// Try/Except round ProcessHTTPMessage + +// 5.2.7.11 + +// BAYCOM tweaks + +// 5.2.7.13 + +// Release semaphore after program error in Timer Processing +// Check fro valid dest in REFRESHROUTE + + +// Add TNC-X KISSOPTION (includes the ACKMODE bytes in the checksum( + +// Version 5.2.9.1 Sept 2012 + +// Fix using KISS ports with COMn > 16 +// Add "KISS over UDP" driver for PI as a TNC concentrator + +// Version 6.0.1.1 + +// Convert to C for linux portability +// Try to speed up kiss polling + +// Version 6.0.2.1 + +// Fix operation on Win98 +// Fix callsign error with AGWtoBPQ +// Fix PTT problem with WINMOR +// Fix Reread telnet config +// Add Secure CMS signon +// Fix error in cashing addresses of CMS servers +// Fix Port Number when using Send Raw. +// Fix PE in KISS driver if invalid subchannel received +// Fix Orignal address of beacons +// Speed up Telnet port monitoring. +// Add TNC Emulators +// Add CountFramesQueuedOnStream API +// Limit number of frames that can be queued on a session. +// Add XDIGI feature +// Add Winmor Robust Mode switching for compatibility with new Winmor TNC +// Move most APRS code from BPQAPRS to here +// Stop corruption caused by overlong KISS frames + +// Version 6.0.3.1 + +// Add starting/killing WINMOR TNC on remote host +// Fix Program Error when APRS Item or Object name is same as call of reporting station +// Dont digi a frame that we have already digi'ed +// Add ChangeSessionIdleTime API +// Add WK2KSYSOP Command +// Add IDLETIME Command +// Fix Errors in RELAYAPPL processing +// Fix PE cauaed by invalid Rigcontrol Line + +// Version 6.0.4.1 + +// Add frequency dependent autoconnect appls for SCS Pactor +// Fix DED Monitoring of I and UI with no data +// Include AGWPE Emulator (from AGWtoBPQ) +// accept DEL (Hex 7F) as backspace in Telnet +// Fix re-running resolver on re-read AXIP config +// Speed up processing, mainly for Telnet Sessions +// Fix APRS init on restart of bpq32.exe +// Change to 2 stop bits +// Fix scrolling of WINMOR trace window +// Fix Crash when ueing DED TNC Emulator +// Fix Disconnect when using BPQDED2 Driver with Telnet Sessions +// Allow HOST applications even when CMS option is disabled +// Fix processing of APRS DIGIMAP command with no targets (didn't suppress default settings) + +// Version 6.0.5.1 January 2014 + +// Add UTF8 conversion mode to Telnet (converts non-UTF-8 chars to UTF-8) +// Add "Clear" option to MH command +// Add "Connect to RMS Relay" Option +// Revert to one stop bit on serial ports, explictly set two on FT2000 rig control +// Fix routing of first call in Robust Packet +// Add Options to switch input source on rigs with build in soundcards (sor far only IC7100 and Kenwood 590) +// Add RTS>CAT PTT option for Sound Card rigs +// Add Clear Nodes Option (NODE DEL ALL) +// SCS Pactor can set differeant APPLCALLS when scanning. +// Fix possible Scan hangup after a manual requency change with SCS Pactor +// Accept Scan entry of W0 to disable WINMOR on that frequency +// Fix corruption of NETROMCALL by SIMPLE config command +// Enforce Pactor Levels +// Add Telnet outward connect +// Add Relay/Trimode Emulation +// Fix V4 Driver +// Add PTT Mux +// Add Locked ARP Entries (via bpq32.cfg) +// Fix IDLETIME node command +// Fix STAY param on connect +// Add STAY option to Attach and Application Commands +// Fix crash on copying a large AXIP MH Window +// Fix possible crash when bpq32.exe dies +// Fix DIGIPORT for UI frames + +// Version 6.0.6.1 April 2014 + +// FLDigi Interface +// Fix "All CMS Servers are inaccessible" message so Mail Forwarding ELSE works. +// Validate INP3 messages to try to prevent crash +// Fix possible crash if an overlarge KISS frame is received +// Fix error in AXR command +// Add LF to Telnet Outward Connect signin if NEEDLF added to connect line +// Add CBELL to TNC21 emulator +// Add sent objects and third party messages to APRS Dup List +// Incorporate UIUtil +// Use Memory Mapped file to pass APRS info to BPQAPRS, and process APRS HTTP in BPQ32 +// Improvements to FLDIGI interlocking +// Fix TNC State Display for Tracker +// Cache CMS Addresses on LinBPQ +// Fix count error on DED Driver when handling 256 byte packets +// Add basic SNMP interface for MRTG +// Fix memory loss from getaddrinfo +// Process "BUSY" response from Tracker +// Handle serial port writes that don't accept all the data +// Trap Error 10038 and try to reopen socket +// Fix crash if overlong command line received + +// Version 6.0.7.1 Aptil 2014 +// Fix RigContol with no frequencies for Kenwood and Yaesu +// Add busy check to FLDIGI connects + +// Version 6.0.8.1 August 2014 + +// Use HKEY_CURRENT_USER on all OS versions +// Fix crash when APRS symbol is a space. +// Fixes for FT847 CAT +// Fix display of 3rd byte of FRMR +// Add "DEFAULT ROBUST" and "FORCE ROBUST" commands to SCSPactor Driver +// Fix possible memory corruption in WINMOR driver +// Fix FT2000 Modes +// Use new WL2K reporting system (Web API Based) +// APRS Server now cycles through hosts if DNS returns more than one +// BPQ32 can now start and stop FLDIGI +// Fix loss of AXIP Resolver when running more than one AXIP port + +// Version 6.0.9.1 November 2014 + +// Fix setting NOKEEPALIVE flag on route created from incoming L3 message +// Ignore NODES from locked route with quality 0 +// Fix seting source port in AXIP +// Fix Dual Stack (IPV4/V6) on Linux. +// Fix RELAYSOCK if IPv6 is enabled. +// Add support for FT1000 +// Fix hang when APRS Messaging packet received on RF +// Attempt to normalize Node qualies when stations use widely differing Route qualities +// Add NODES VIA command to display nodes reachable via a specified neighbour +// Fix applying "DisconnectOnClose" setting on HOST API connects (Telnet Server) +// Fix buffering large messages in Telnet Host API +// Fix occasional crash in terminal part line processing +// Add "NoFallback" command to Telnet server to disable "fallback to Relay" +// Improved support for APPLCALL scanning with Pactor +// MAXBUFFS config statement is no longer needed. +// Fix USEAPPLCALLS with Tracker when connect to APPLCALL fails +// Implement LISTEN and CQ commands +// FLDIGI driver can now start FLDIGI on a remote system. +// Add IGNOREUNLOCKEDROUTES parameter +// Fix error if too many Telnet server connections + +// Version 6.0.10.1 Feb 2015 + +// Fix crash if corrupt HTML request received. +// Allow SSID's of 'R' and 'T' on non-ax.25 ports for WL2K Radio Only network. +// Make HTTP server HTTP Version 1.1 complient - use persistent conections and close after 2.5 mins +// Add INP3ONLY flag. +// Fix program error if enter UNPROTO without a destination path +// Show client IP address on HTTP sessions in Telnet Server +// Reduce frequency and number of attempts to connect to routes when Keepalives or INP3 is set +// Add FT990 RigControl support, fix FT1000MP support. +// Support ARMV5 processors +// Changes to support LinBPQ APRS Client +// Add IC7410 to supported Soundcard rigs +// Add CAT PTT to NMEA type (for ICOM Marine Radios_ +// Fix ACKMODE +// Add KISS over TCP +// Support ACKMode on VKISS +// Improved reporting of configuration file format errors +// Experimental driver to support ARQ sessions using UI frames + +// Version 6.0.11.1 September 2015 + +// Fixes for IPGateway configuration and Virtual Circuit Mode +// Separate Portmapper from IPGateway +// Add PING Command +// Add ARDOP Driver +// Add basic APPLCALL support for PTC-PRO/Dragon 7800 Packet (using MYALIAS) +// Add "VeryOldMode" for KAM Version 5.02 +// Add KISS over TCP Slave Mode. +// Support Pactor and Packet on P4Dragon on one port +// Add "Remote Staton Quality" to Web ROUTES display +// Add Virtual Host option for IPGateway NET44 Encap +// Add NAT for local hosts to IPGateway +// Fix setting filter from RADIO command for IC7410 +// Add Memory Channel Scanning for ICOM Radios +// Try to reopen Rig Control port if it fails (could be unplugged USB) +// Fix restoring position of Monitor Window +// Stop Codec on Winmor and ARDOP when an interlocked port is attached (instead of listen false) +// Support APRS beacons in RP mode on Dragon// +// Change Virtual MAC address on IPGateway to include last octet of IP Address +// Fix "NOS Fragmentation" in IP over ax.25 Virtual Circuit Mode +// Fix sending I frames before L2 session is up +// Fix Flow control on Telnet outbound sessions. +// Fix reporting of unterminatred comments in config +// Add option for RigControl to not change mode on FT100/FT990/FT1000 +// Add "Attach and Connect" for Telnet ports + +// Version 6.0.12.1 November 2015 + +// Fix logging of IP addresses for connects to FBBPORT +// Allow lower case user and passwords in Telnet "Attach and Connect" +// Fix possible hang in KISS over TCP Slave mode +// Fix duplicating LinBPQ process if running ARDOP fails +// Allow lower case command aliases and increase alias length to 48 +// Fix saving long IP frames pending ARP resolution +// Fix dropping last entry from a RIP44 message. +// Fix displaying Digis in MH list +// Add port name to Monitor config screen port list +// Fix APRS command display filter and add port filter +// Support port names in BPQTermTCP Monitor config +// Add FINDBUFFS command to dump lost buffers to Debugview/Syslog +// Buffer Web Mgmt Edit Config output +// Add WebMail Support +// Fix not closing APRS Send WX file. +// Add RUN option to APRS Config to start APRS Client +// LinBPQ run FindLostBuffers and exit if QCOUNT < 5 +// Close and reopen ARDOP connection if nothing received for 90 secs +// Add facility to bridge traffic between ports (similar to APRS Bridge but for all frame types) +// Add KISSOPTION TRACKER to set SCS Tracker into KISS Mode + +// 6.0.13.1 + +// Allow /ex to exit UNPROTO mode +// Support ARQBW commands. +// Support IC735 +// Fix sending ARDOP beacons after a busy holdoff +// Enable BPQDED driver to beacon via non-ax.25 ports. +// Fix channel number in UZ7HO monitoring +// Add SATGate mode to APRSIS Code. +// Fix crash caused by overlong user name in telnet logon +// Add option to log L4 connects +// Add AUTOADDQuiet mode to AXIP. +// Add EXCLUDE processing +// Support WinmorControl in UZ7HO driver and fix starting TNC on Linux +// Convert calls in MAP entries to upper case. +// Support Linux COM Port names for APRS GPS +// Fix using NETROM serial protocol on ASYNC Port +// Fix setting MYLEVEL by scanner after manual level change. +// Add DEBUGLOG config param to SCS Pactor Driver to log serial port traffic +// Uue #myl to set SCS Pactor MYLEVEL, and add checklevel command +// Add Multicast RX interface to FLDIGI Driver +// Fix processing application aliases to a connect command. +// Fix Buffer loss if radio connected to PTC rig port but BPQ not configured to use it +// Save backups of bpq32.cfg when editing with Web interface and report old and new length +// Add DD command to SCS Pactor, and use it for forced disconnect. +// Add ARDOP mode select to scan config +// ARDOP changes for ARDOP V 0.5+ +// Flip SSID bits on UZ7HO downlink connects + + +// Version 6.0.14.1 + +// Fix Socket leak in ARDOP and FLDIGI drivers. +// Add option to change CMS Server hostname +// ARDOP Changes for 0.8.0+ +// Discard Terminal Keepalive message (two nulls) in ARDOP command hander +// Allow parameters to be passed to ARDOP TNC when starting it +// Fix Web update of Beacon params +// Retry connects to KISS ports after failure +// Add support for ARDOP Serial Interface Native mode. +// Fix gating APRS-IS Messages to RF +// Fix Beacons when PORTNUM used +// Make sure old monitor flag is cleared for TermTCP sessions +// Add CI-V antenna control for IC746 +// Don't allow ARDOP beacons when connected +// Add support for ARDOP Serial over I2C +// Fix possble crash when using manual RADIO messages +// Save out of sequence L2 frames for possible reuse after retry +// Add KISS command to send KISS control frame to TNC +// Stop removing unused digis from packets sent to APRS-IS + +// Processing of ARDOP PING and PINGACK responses +// Handle changed encoding of WL2K update responses. +// Allow anonymous logon to telnet +// Don't use APPL= for RP Calls in Dragon Single mode. +// Add basic messaging page to APRS Web Server +// Add debug log option to SCSTracker and TrkMulti Driver +// Support REBOOT command on LinBPQ +// Allow LISTEN command on all ports that support ax.25 monitoring + +// Version 6.0.15.1 Feb 2018 + +// partial support for ax.25 V2.2 +// Add MHU and MHL commands and MH filter option +// Fix scan interlock with ARDOP +// Add Input source seiect for IC7300 +// Remove % transparency from web terminal signon message +// Fix L4 Connects In count on stats +// Fix crash caused by corrupt CMSInfo.txt +// Add Input peaks display to ARDOP status window +// Add options to show time in local and distances in KM on APRS Web pages +// Add VARA support +// Fix WINMOR Busy left set when port Suspended +// Add ARDOP-Packet Support +// Add Antenna Switching for TS 480 +// Fix possible crash in Web Terminal +// Support different Code Pages on Console sessions +// Use new Winlink API interface (api.winlink.org) +// Support USB/ACC switching on TS590SG +// Fix scanning when ARDOP or WINMOR is used without an Interlocked Pactor port. +// Set NODECALL to first Application Callsign if NODE=0 and BBSCALL not set. +// Add RIGCONTROL TUNE and POWER commands for some ICOM and Kenwwod rigs +// Fix timing out ARDOP PENDING Lock +// Support mixed case WINLINK Passwords +// Add TUNE and POWER Rigcontol Commands for some radios +// ADD LOCALTIME and DISPKM options to APRS Digi/Igate + +// 6.0.16.1 March 2018 + +// Fix Setting data mode and filter for IC7300 radios +// Add VARA to WL2KREPORT +// Add trace to SCS Tracker status window +// Fix possible hang in IPGATEWAY +// Add BeacontoIS parameter to APRSDIGI. Allows you to stop sending beacons to APRS-IS. +// Fix sending CTEXT on WINMOR sessions + +// 6.0.17.1 November 2018 + +// Change WINMOR Restart after connection to Restart after Failure and add same option to ARDOP and VARA +// Add Abort Connection to WINMOR and VARA Interfaces +// Reinstate accidentally removed CMS Access logging +// Fix MH CLEAR +// Fix corruption of NODE table if NODES received from station with null alias +// Fix loss of buffer if session closed with something in PARTCMDBUFFER +// Fix Spurious GUARD ZONE CORRUPT message in IP Code. +// Remove "reread bpq32.cfg and reconfigure" menu options +// Add support for PTT using CM108 based soundcard interfaces +// Datestamp Telnet log files and delete old Telnet and CMSAcces logs + +// 6.0.18.1 January 2019 + +// Fix validation of NODES broadcasts +// Fix HIDENODES +// Check for failure to reread config on axip reconfigure +// Fix crash if STOPPORT or STARTPORT used on KISS over TCP port +// Send Beacons from BCALL or PORTCALL if configured +// Fix possible corruption of last entry in MH display +// Ensure RTS/DTR is down when opening PTT Port +// Remove RECONFIG command +// Preparations for 64 bit version + +// 6.0.19 Sept 2019 +// Fix UZ7HO interlock +// Add commands to set Centre Frequency and Modem with UZ7HO Soundmodem (on Windows only) +// Add option to save and restore MH lists and SAVEMH command +// Add Frequency (if known) to UZ7HO MH lists +// Add Gateway option to Telnet for PAT +// Try to fix SCS Tracker recovery +// Ensure RTS/DTR is down on CAT port if using that line for PTT +// Experimental APRS Messaging in Kernel +// Add Rigcontrol on remote PC's using WinmorControl +// ADD VARAFM and VARAFM96 WL2KREPORT modes +// Fix WL2K sysop update for new Winlink API +// Fix APRS when using PORTNUM higher than the number of ports +// Add Serial Port Type +// Add option to linbpq to log APRS-IS messages. +// Send WL2K Session Reports +// Drop Tunneled Packets from 44.192 - 44.255 +// Log incoming Telnet Connects +// Add IPV4: and IPV6: overrides on AXIP Resolver. +// Add SessionTimeLimit to HF sessions (ARDOP, SCSPactor, WINMOR, VARA) +// Add RADIO FREQ command to display current frequency + +// 6.0.20 April 2020 + +// Trap and reject YAPP file transfer request. +// Fix possible overrun of TCP to Node Buffer +// Fix possible crash if APRS WX file doesn't have a terminating newline +// Change communication with BPQAPRS.exe to restore old message popup behaviour +// Preparation for 64 bit version +// Improve flow control on SCS Dragon +// Fragment messages from network links to L2 links with smaller paclen +// Change WL2K report rate to once every two hours +// Add PASS, CTEXT and CMSG commands and Stream Switch support to TNC2 Emulator +// Add SessionTimeLimit command to HF drivers (ARDOP, SCSPactor, WINMOR, VARA) +// Add links to Ports Web Manangement Page to open individual Driver windows +// Add STOPPORT/STARTPORT support to ARDOP, KAM and SCSPactor drivers +// Add CLOSE and OPEN RADIO command so Rigcontrol port can be freed fpr other use. +// Don't try to send WL2K Traffic report if Internet is down +// Move WL2K Traffic reporting to a separate thread so it doesn't block if it can't connect to server +// ADD AGWAPPL config command to set application number. AGWMASK is still supported +// Register Node Alias with UZ7HO Driver +// Register calls when UZ7HO TNC Restarts and at intervals afterwards +// Fix crash when no IOADDR or COMPORT in async port definition +// Fix Crash with Paclink-Unix when parsing ; VE7SPR-10 DE N7NIX QTC 1 +// Only apply BBSFLAG=NOBBS to APPPLICATION 1 +// Add RIGREONFIG command +// fix APRS RECONFIG on LinBPQ +// Fix Web Terminal scroll to end problem on some browsers +// Add PTT_SETS_INPUT option for IC7600 +// Add TELRECONFIG command to reread users or whole config +// Enforce PACLEN on UZ7HO ports +// Fix PACLEN on Command Output. +// Retry axip resolver if it fails at startup +// Fix AGWAPI connect via digis +// Fix Select() for Linux in MultiPSK, UZ7HO and V4 drivers +// Limit APRS OBJECT length to 80 chars +// UZ7HO disconnect incoming call if no free streams +// Improve response to REJ (no F) followed by RR (F). +// Try to prevent more than MAXFRAME frames outstanding when transmitting +// Allow more than one instance of APRS on Linux +// Stop APRS digi by originating station +// Send driver window trace to main monitor system +// Improve handling of IPOLL messages +// Fix setting end of address bit on dest call on connects to listening sessions +// Set default BBS and CHAT application number and number of streams on LinBPQ +// Support #include in bpq32.cfg processing + +// Version 6.0.21 14 December 2020 + +// Fix occasional missing newlines in some node command reponses +// More 64 bit fixes +// Add option to stop setting PDUPLEX param in SCSPACTOR +// Try to fix buffer loss +// Remove extra space from APRS position reports +// Suppress VARA IAMALIVE messages +// Add display and control of QtSoundModem modems +// Only send "No CMS connection available" message if fallbacktorelay is set. +// Add HAMLIB backend and emulator support to RIGCONTROL +// Ensure all beacons are sent even with very short beacon intervals +// Add VARA500 WL2K Reporting Mode +// Fix problem with prpcessing frame collector +// Temporarily disable L2 and L4 collectors till I can find problem +// Fix possible problem with interactive RADIO commands not giving a response, +// Incease maximum length of NODE command responses to handle maximum length INFO message, +// Allow WL2KREPORT in CONFIG section of UZ7HO port config. +// Fix program error in processing hamlib frame +// Save RestartAfterFailure option for VARA +// Check callsign has a winlink account before sending WL2KREPORT messages +// Add Bandwidth control to VARA scanning +// Renable L2 collector +// Fix TNCPORT reconnect on Linux +// Add SecureTelnet option to limit telnet outward connect to sysop mode sessions or Application Aliases +// Add option to suppress sending call to application in Telnet HOST API +// Add FT991A support to RigControl +// Use background.jpg for Edit Config page +// Send OK response to SCS Pactor commands starting with # +// Resend ICOM PTT OFF command after 30 seconds +// Add WXCall to APRS config +// Fixes for AEAPactor +// Allow PTTMUX to use real or com0com com ports +// Fix monitoring with AGW Emulator +// Derive approx position from packets on APRS ports with a valid 6 char location +// Fix corruption of APRS message lists if the station table fills up. +// Don't accept empty username or password on Relay sessions. +// Fix occasional empty Nodes broadcasts +// Add Digis to UZ7HO Port MH list +// Add PERMITTEDAPPLS port param +// Fix WK2K Session Record Reporting for Airmail and some Pactor Modes. +// Fix handling AX/IP (proto 93) frames +// Fix possible corruption sending APRS messages +// Allow Telnet connections to be made using Connect command as well as Attach then Connect +// Fix Cancel Sysop Signin +// Save axip resolver info and restore on restart +// Add Transparent mode to Telnet Server HOST API +// Fix Tracker driver if WL2KREPRRT is in main config section +// SNMP InOctets count corrected to include all frames and encoding of zero values fixed. +// Change IP Gateway to exclude handling bits of 44 Net sold to Amazon +// Fix crash in Web terminal when processing very long lines + +// Version 6.0.22.1 August 2021 + +// Fix bug in KAM TNCEMULATOR +// Add WinRPR Driver (DED over TCP) +// Fix handling of VARA config commands FM1200 and FM9600 +// Improve Web Termanal Line folding +// Add StartTNC to WinRPR driver +// Add support for VARA2750 Mode +// Add support for VARA connects via a VARA Digipeater +// Add digis to SCSTracker and WinRPR MHeard +// Separate RIGCONTROL config from PORT config and add RigControl window +// Fix crash when a Windows HID device doesn't have a product_string +// Changes to VARA TNC connection and restart process +// Trigger FALLBACKTORELAY if attempt to connect to all CMS servers fail. +// Fix saving part lines in adif log and Winlink Session reporting +// Add port specific CTEXT +// Add FRMR monitoring to UZ7HO driver +// Add audio input switching for IC7610 +// Include Rigcontrol Support for IC-F8101E +// Process any response to KISS command +// Fix NODE ADD command +// Add noUpdate flag to AXIP MAP +// Fix clearing NOFALLBACK flag in Telnet Server +// Allow connects to RMS Relay running on another host +// Allow use of Power setting in Rigcontol scan lines for Kenwood radios +// Prevent problems caused by using "CMS" as a Node Alias +// Include standard APRS Station pages in code +// Fix VALIDCALLS processing in HF drivers +// Send Netrom Link reports to Node Map +// Add REALTELNET mode to Telnet Outward Connect +// Fix using S (Stay) parameter on Telnet connects when using CMDPORT and C HOST +// Add Default frequency to rigcontrol to set a freq/mode to return to after a connection +// Fix long (> 60 seconds) scan intervals +// Improved debugging of stuck semaphores +// Fix potential securiby bug in BPQ Web server +// Send Chat Updates to chatupdate.g8bpq.net port 81 +// Add ReportRelayTraffic to Telnet config to send WL2K traffic reports for connections to RELAY +// Add experimental Mode reporting +// Add SendTandRtoRelay param to SCS Pactor, ARDOP and VARA drivers to divert calls to CMS for -T and -R to RELAY +// Add UPNP Support + +// Version 6.0.23.1 June 2022 + +// Add option to control which applcalls are enabled in VARA +// Add support for rtl_udp to Rig Control +// Fix Telnet Auto Conneect to Application when using TermTCP or Web Terminal +// Allow setting css styles for Web Terminal +// And Kill TNC and Kill and Restart TNC commands to Web Driver Windows +// More flexible RigControl for split frequency operation, eg for QO100 +// Increase stack size for ProcessHTMLMessage (.11) +// Fix HTML Content-Type on images (.12) +// Add AIS and ADSB Support (.13) +// Compress web pages (.14) +// Change minidump routine and close after program error (.15) +// Add RMS Relay SYNC Mode (.17) +// Changes for compatibility with Winlink Hybrid +// Add Rigcontrol CMD feature to Yaesu code (21) +// More diagnostic code +// Trap potential buffer overrun in ax/tcp code +// Fix possible hang in UZ7HO driver if connect takes a long time to succeed or fail +// Add FLRIG as backend for RigControl (.24) +// Fix bug in compressing some management web pages +// Fix bugs in AGW Emulator (.25) +// Add more PTT_Sets_Freq options for split frequency working (.26) +// Allow RIGCONTROL using Radio Number (Rnn) as well as Port (.26) +// Fix Telnet negotiation and backspace processing (.29) +// Fix VARA Mode change when scanning (.30) +// Add Web Mgmt Log Display (.33) +// Fix crash when connecting to RELAY when CMS=0 (.36) +// Send OK to user for manual freq changes with hamlib or flrig +// Fix Rigcontrol leaving port disabled when using an empty timeband +// Fix processing of backspace in Telnet character processing (.40) +// Increase max size of connect script +// Fix HAMLIB Slave Thread control +// Add processing of VARA mode responses and display of VARA Mode (41) +// Fix crash when VARA session aborted on LinBPQ (43) +// Fix handling port selector (2:call or p2 call) on SCS PTC packet ports (44) +// Include APRS Map web page +// Add Enable/Disable to KAMPACTOR scan control (use P0 or P1) (45) +// Add Basic DRATS interface (46) +// Fix MYCALLS on VARA (49) +// Add FreeData driver (51) +// Add additonal Rigcontrol options for QO100 (51) +// Set Content-Type: application/pdf for pdf files downloaded via web interface (51) +// Fix sending large compressed web messages (52) +// Fix freq display when using flrig or hamlib backends to rigcontrol +// Change VARA Driver to send ABORT when Session Time limit expires +// Add Chat Log to Web Logs display +// Fix possible buffer loss in RigControl +// Allow hosts on local lan to be treated as secure +// Improve validation of data sent to Winlink SessionAdd API call +// Add support for FreeDATA modem. +// Add GetLOC API Call +// Change Leaflet link in aprs map. +// Add Connect Log (64) +// Fix crash when Resolve CMS Servers returns ipv6 addresses +// Fix Reporting P4 sessions to Winlink (68) +// Add support for FreeBSD (68) +// Fix Rigcontrol PTCPORT (69) +// Set TNC Emulator sessions as secure (72) +// Fix not always detecting loss of FLRIG (73) +// Add ? and * wildcards to NODES command (74) +// Add Port RADIO config parameter (74) + +// Version 6.0.24.1 August 2023 + +// Apply NODES command wildcard to alias as well a call (2) +// Add STOPPORT/STARTPORT to VARA Driver (2) +// Add bandwidth setting to FLRIG interface. (2) +// Fix N VIA (3) +// Fix NODE ADD and NODE DEL (4) +// Improvements to FLRIG Rigcontrol backend (6, 7) +// Fix UZ7HO Window Title Update +// Reject L2 calls with a blank from call (8) +// Update WinRPR Window header with BPQ Port Description (8) +// Fix error in blank call code (9) +// Change web buttons to white on black when pressed (10) +// Fix Port CTEXT paclen on Tracker and WinRPR drivers (11) +// Add RADIO PTT command for testing PTT (11) +// Fix using APPLCALLs on SCSTracker RP call (12) +// Add Rigcntol Web Page (13) +// Fix scan bandwidth change with ARDOPOFDM (13) +// Fix setting Min Pactor Level in SCSPactor (13) +// Fix length of commands sent via CMD_TO_APPL flag (14) +// Add filter by quality option to N display (15) +// Fix VARA Mode reporting to WL2K (16) +// Add FLRIG POWER and TUNE commands (18) +// Fix crash when processing "C " without a call in UZ7HO, FLDIGI or MULTIPSK drivers (19) +// FLDIGI improvements (19) +// Fix hang at start if Telnet port Number > Number of Telnet Streams (20) +// Fix processing C command if first port driver is SCSPACTROR (20) +// Fix crash in UZ7HO driver if bad raw frame received (21) +// Fix using FLARQ chat mode with FLDIGI ddriover (22) +// Fix to KISSHF driver (23) +// Fix for application buffer loss (24) +// Add Web Sockets auto-refresh option for Webmail index page (25) +// Fix FREEDATA driver for compatibility with FreeData TNC version 0.6.4-alpha.3 (25) +// Add SmartID for bridged frames - Send ID only if packets sent recently (26) +// Add option to save and restore received APRS messages (27) +// Add mechanism to run a user program on certain events (27) +// If BeacontoIS is zero don't Gate any of our messages received locally to APRS-IS (28) +// Add Node Help command (28) +// Add APRS Igate RXOnly option (29) +// Fix RMC message handling with prefixes other than GP (29) +// Add GPSD support for APRS (30) +// Attempt to fix Tracker/WinRPR reconnect code (30) +// Changes to FreeDATA - Don't use deamon and add txlevel and send text commands (31) +// Fix interactive commands in tracker driver (33) +// Fix SESSIONTIMELIMIT processing +// Add STOPPORT/STARTPORT for UZ7HO driver +// Fix processing of extended QtSM 'g' frame (36) +// Allow setting just freq on Yaseu rigs (37) +// Enable KISSHF driver on Linux (40) +// Allow AISHOST and ADSBHOST to be a name as well as an address (41) +// Fix Interlock of incoming UZ7HO connections (41) +// Disable VARA Actions menu if not sysop (41) +// Fix Port CTEXT on UZ7HO B C or D channels (42) +// Fix repeated trigger of SessionTimeLimit (43) +// Fix posible memory corruption in UpateMH (44) +// Add PHG to APRS beacons (45) +// Dont send DM to stations in exclude list(45) +// Improvements to RMS Relay SYNC Mode (46) +// Check L4 connects against EXCLUDE list (47) +// Add vaidation of LOC in WL2K Session Reports (49) +// Change gpsd support for compatibility with Share Gps (50) +// Switch APRS Map to my Tiles (52) +// Fix using ; in UNPROTO Mode messages (52) +// Use sha1 code from https://www.packetizer.com/security/sha1/ instead of openssl (53) +// Fix TNC Emulator Monitoring (53) +// Fix attach and connect on Telnet port bug introduced in .55 (56) +// Fix stopping WinRPR TNC and Start/Stop UZ7HO TNCX on Linux (57) +// Fix stack size in beginthread for MAC (58) +// Add NETROM over VARA (60) +// Add Disconnect Script (64) +// Add node commands to set UZ7HO modem mode and freq (64) +// Trap empty NODECALL or NETROMCALL(65) +// Trap NODES messages with empty From Call (65) +// Add RigControl for SDRConsole (66) +// Fix FLRig crash (66) +// Fix VARA disconnect handling (67) +// Support 64 ports (69) +// Fix Node commands for setting UZ7HO Modem (70) +// Fix processing SABM on an existing session (71) +// Extend KISS Node command to send more than one parameter byte (72) +// Add G7TAJ's code to record activity of HF ports for stats display (72) +// Add option to send KISS command to TNC on startup (73) +// Fix Bug in DED Emulator Monitor code (74) +// Add Filters to DED Monitor code (75) +// Detect loss of DED application (76) +// Fix connects to Application Alias with UZ7HO Driver (76) +// Fix Interlock of ports on same UZ7HO modem. (76) +// Add extended Ports command (77) +// Fix crash in Linbpq when stdout is redirected to /dev/tty? and stdin ia redirected (78) +// Fix Web Terminal (80) +// Trap ENCRYPTION message from VARA (81) +// Fix processing of the Winlink API /account/exists response (82) +// Fix sending CTEXT to L4 connects to Node when FULL_CTEXT is not set + +// Version 6.0.25.? + +// Fix 64 bit compatibility problems in SCSTracker and UZ7HO drivers +// Add Chat PACLEN config (5) +// Fix NC to Application Call (6) +// Fix INP3 L3RTT messages on Linux and correct RTT calculation (9) +// Get Beacon config from config file on Windows (9) +// fix processing DED TNC Emulator M command with space between M and params (10) +// Fix sending UI frames on SCSPACTOR (11) +// Dont allow ports that can't set digi'ed bit in callsigns to digipeat. (11) +// Add SDRAngel rig control (11) +// Add option to specify config and data directories on linbpq (12) +// Allow zero resptime (send RR immediately) (13) +// Make sure CMD bit is set on UI frames +// Add setting Modem Flags in QtSM AGW mode +// If FT847 om PTC Port send a "Cat On" command (17) +// Fix some 63 port bugs in RigCOntrol (17) +// Fix 63 port bug in Bridging (18) +// Add FTDX10 Rigcontrol (19) +// Fix 64 bit bug in displaying INP3 Messages (20) +// Improve restart of WinRPR TNC on remote host (21) +// Fix some Rigcontrol issues with empty timebands (22) +// Fix 64 bit bug in processing INP3 Messages (22) +// First pass at api (24) +// Send OK in response to Rigcontrol CMD (24) +// Disable CTS check in WriteComBlock (26) +// Improvments to reporting to M0LTE Map (26) +// IPGateway fix from github user isavitsky (27) +// Fix possible crash in SCSPactor PTCPORT code (29) +// Add NodeAPI call sendLinks and remove get from other calls (32) +// Improve validation of Web Beacon Config (33) +// Support SNMP via host ip stack as well as IPGateway (34) +// Switch APRS Map to OSM tile servers (36) +// Fix potential buffer overflow in Telnet login (36) +// Allow longer serial device names (37) +// Fix ICF8101 Mode setting (37) +// Kill link if we are getting repeated RR(F) after timeout +// (Indicating other station is seeing our RR(P) but not the resent I frame) (40) +// Change default of SECURETELNET to 1 (41) +// Add optional ATTACH time limit for ARDOP (42) +// Fix buffer overflow risk in HTTP Terminal(42) +// Fix KISSHF Interlock (43) +// Support other than channel A on HFKISS (43) +// Support additional port info reporting for M0LTE Map (44) +// Allow interlocking of KISS and Session mode ports (eg ARDOP and VARA) (45) +// Add ARDOP UI Packets to MH (45) +// Add support for Qtsm Mgmt Interface (45) +// NodeAPI improvements (46) +// Add MQTT Interface (46) +// Fix buffer leak in ARDOP code(46) +// Fix possible crash if MQTT not in use (47) +// Add optional ATTACH time limit for VARA (48) +// API format fixes (48) +// AGWAPI Add protection against accidental connects from a non-agw application (50) +// Save MH and NODES every hour (51) +// Fix handling long unix device names (now max 250 bytes) (52) +// Fix error reporting in api update (53) +// Coding changes to remove some compiler warnings (53, 54) +// Add MQTT reporting of Mail Events (54) +// Fix beaconong on KISSHF ports (55) +// Fix MailAPI msgs endpoint +// Attempt to fix NC going to wrong application. (57) +// Improve ARDOP send of session code (58) + + +#define CKernel + +#include "Versions.h" + +#define _CRT_SECURE_NO_DEPRECATE + +#pragma data_seg("_BPQDATA") + +#include "time.h" +#include "stdio.h" +#include + +#include "compatbits.h" +#include "AsmStrucs.h" + +#include "SHELLAPI.H" +#include "kernelresource.h" + +#include +#include +#include "BPQTermMDI.h" + +#include "GetVersion.h" + +#define DllImport __declspec( dllimport ) + +#define CheckGuardZone() _CheckGuardZone(__FILE__, __LINE__) +void _CheckGuardZone(char * File, int Line); + +#define CHECKLOADED 0 +#define SETAPPLFLAGS 1 +#define SENDBPQFRAME 2 +#define GETBPQFRAME 3 +#define GETSTREAMSTATUS 4 +#define CLEARSTREAMSTATUS 5 +#define BPQCONDIS 6 +#define GETBUFFERSTATUS 7 +#define GETCONNECTIONINFO 8 +#define BPQRETURN 9 // GETCALLS +//#define RAWTX 10 //IE KISS TYPE DATA +#define GETRAWFRAME 11 +#define UPDATESWITCH 12 +#define BPQALLOC 13 +//#define SENDNETFRAME 14 +#define GETTIME 15 + +extern short NUMBEROFPORTS; +extern long PORTENTRYLEN; +extern long LINKTABLELEN; +extern struct PORTCONTROL * PORTTABLE; +extern void * FREE_Q; +extern UINT APPL_Q; // Queue of frames for APRS Appl + +extern TRANSPORTENTRY * L4TABLE; +extern UCHAR NEXTID; +extern DWORD MAXCIRCUITS; +extern DWORD L4DEFAULTWINDOW; +extern DWORD L4T1; +extern APPLCALLS APPLCALLTABLE[]; +extern char * APPLS; + +extern struct WL2KInfo * WL2KReports; + +extern int NUMBEROFTNCPORTS; + + +void * VCOMExtInit(struct PORTCONTROL * PortEntry); +void * AXIPExtInit(struct PORTCONTROL * PortEntry); +void * SCSExtInit(struct PORTCONTROL * PortEntry); +void * AEAExtInit(struct PORTCONTROL * PortEntry); +void * KAMExtInit(struct PORTCONTROL * PortEntry); +void * HALExtInit(struct PORTCONTROL * PortEntry); +void * ETHERExtInit(struct PORTCONTROL * PortEntry); +void * AGWExtInit(struct PORTCONTROL * PortEntry); +void * WinmorExtInit(EXTPORTDATA * PortEntry); +void * TelnetExtInit(EXTPORTDATA * PortEntry); +//void * SoundModemExtInit(EXTPORTDATA * PortEntry); +void * TrackerExtInit(EXTPORTDATA * PortEntry); +void * TrackerMExtInit(EXTPORTDATA * PortEntry); +void * V4ExtInit(EXTPORTDATA * PortEntry); +void * UZ7HOExtInit(EXTPORTDATA * PortEntry); +void * MPSKExtInit(EXTPORTDATA * PortEntry); +void * FLDigiExtInit(EXTPORTDATA * PortEntry); +void * UIARQExtInit(EXTPORTDATA * PortEntry); +void * SerialExtInit(EXTPORTDATA * PortEntry); +void * ARDOPExtInit(EXTPORTDATA * PortEntry); +void * VARAExtInit(EXTPORTDATA * PortEntry); +void * KISSHFExtInit(EXTPORTDATA * PortEntry); +void * WinRPRExtInit(EXTPORTDATA * PortEntry); +void * HSMODEMExtInit(EXTPORTDATA * PortEntry); +void * FreeDataExtInit(EXTPORTDATA * PortEntry); +void * SIXPACKExtInit(EXTPORTDATA * PortEntry); + +extern char * ConfigBuffer; // Config Area +VOID REMOVENODE(dest_list * DEST); +DllExport int ConvFromAX25(unsigned char * incall,unsigned char * outcall); +DllExport int ConvToAX25(unsigned char * incall,unsigned char * outcall); +VOID GetUIConfig(); +VOID ADIFWriteFreqList(); +void SaveAIS(); +void initAIS(); +void initADSB(); + +extern BOOL ADIFLogEnabled; + +int CloseOnError = 0; + +char UIClassName[]="UIMAINWINDOW"; // the main window class name + +HWND UIhWnd; + +extern char AUTOSAVE; +extern char AUTOSAVEMH; + +extern char MYNODECALL; // 10 chars,not null terminated + +extern QCOUNT; +extern BPQVECSTRUC BPQHOSTVECTOR[]; +#define BPQHOSTSTREAMS 64 +#define IPHOSTVECTOR BPQHOSTVECTOR[BPQHOSTSTREAMS + 3] + +extern char * CONFIGFILENAME; + +DllExport BPQVECSTRUC * BPQHOSTVECPTR; + +extern int DATABASESTART; + +extern struct ROUTE * NEIGHBOURS; +extern int ROUTE_LEN; +extern int MAXNEIGHBOURS; + +extern struct DEST_LIST * DESTS; // NODE LIST +extern int DEST_LIST_LEN; +extern int MAXDESTS; // MAX NODES IN SYSTEM + +extern struct _LINKTABLE * LINKS; +extern int LINK_TABLE_LEN; +extern int MAXLINKS; + +extern double LatFromLOC; +extern double LonFromLOC; + + +extern int BPQHOSTAPI(); +extern int INITIALISEPORTS(); +extern int TIMERINTERRUPT(); +extern int MONDECODE(); +extern int BPQMONOPTIONS(); +extern char PWTEXT[]; +extern char PWLen; + +extern int FINDFREEDESTINATION(); +extern int RAWTX(); +extern int RELBUFF(); +extern int SENDNETFRAME(); +extern char MYCALL[]; // 7 chars, ax.25 format + +extern HWND hIPResWnd; +extern BOOL IPMinimized; + +extern int NODESINPROGRESS; +extern VOID * CURRENTNODE; + + +BOOL Start(); + +VOID SaveWindowPos(int port); +VOID SaveAXIPWindowPos(int port); +VOID SetupRTFHddr(); +DllExport VOID APIENTRY CreateNewTrayIcon(); +int DoReceivedData(int Stream); +int DoStateChange(int Stream); +int DoMonData(int Stream); +struct ConsoleInfo * CreateChildWindow(int Stream, BOOL DuringInit); +CloseHostSessions(); +SaveHostSessions(); +VOID SaveBPQ32Windows(); +VOID CloseDriverWindow(int port); +VOID CheckWL2KReportTimer(); +VOID SetApplPorts(); +VOID WriteMiniDump(); +VOID FindLostBuffers(); +BOOL InitializeTNCEmulator(); +VOID TNCTimer(); +char * strlop(char * buf, char delim); + +DllExport int APIENTRY Get_APPLMASK(int Stream); +DllExport int APIENTRY GetStreamPID(int Stream); +DllExport int APIENTRY GetApplFlags(int Stream); +DllExport int APIENTRY GetApplNum(int Stream); +DllExport BOOL APIENTRY GetAllocationState(int Stream); +DllExport int APIENTRY GetMsg(int stream, char * msg, int * len, int * count ); +DllExport int APIENTRY RXCount(int Stream); +DllExport int APIENTRY TXCount(int Stream); +DllExport int APIENTRY MONCount(int Stream); +DllExport int APIENTRY GetCallsign(int stream, char * callsign); +DllExport VOID APIENTRY RelBuff(VOID * Msg); +void SaveMH(); +void DRATSPoll(); + +#define C_Q_ADD(s, b) _C_Q_ADD(s, b, __FILE__, __LINE__); +int _C_Q_ADD(VOID *PQ, VOID *PBUFF, char * File, int Line); + +VOID SetWindowTextSupport(); +int WritetoConsoleSupport(char * buff); +VOID PMClose(); +VOID MySetWindowText(HWND hWnd, char * Msg); +BOOL CreateMonitorWindow(char * MonSize); +VOID FormatTime3(char * Time, time_t cTime); + +char EXCEPTMSG[80] = ""; + +char SIGNONMSG[128] = ""; +char SESSIONHDDR[80] = ""; +int SESSHDDRLEN = 0; + +BOOL IncludesMail = FALSE; +BOOL IncludesChat = FALSE; // Set if pgram is running - used for Web Page Index + + +char WL2KCall[10]; +char WL2KLoc[7]; + +extern char LOCATOR[]; // Locator for Reporting - may be Maidenhead or LAT:LON +extern char MAPCOMMENT[]; // Locator for Reporting - may be Maidenhead or LAT:LON +extern char LOC[7]; // Maidenhead Locator for Reporting +extern char ReportDest[7]; + +extern UCHAR ConfigDirectory[260]; + +extern uint64_t timeLoadedMS; + +VOID __cdecl Debugprintf(const char * format, ...); +VOID __cdecl Consoleprintf(const char * format, ...); + +DllExport int APIENTRY CloseBPQ32(); +DllExport char * APIENTRY GetLOC(); +DllExport int APIENTRY SessionControl(int stream, int command, int param); + +int DoRefreshWebMailIndex(); + +BOOL APIENTRY Init_IP(); +BOOL APIENTRY Poll_IP(); + +BOOL APIENTRY Init_PM(); +BOOL APIENTRY Poll_PM(); + +BOOL APIENTRY Init_APRS(); +BOOL APIENTRY Poll_APRS(); +VOID HTTPTimer(); + +BOOL APIENTRY Rig_Init(); +BOOL APIENTRY Rig_Close(); +BOOL Rig_Poll(); + +VOID IPClose(); +VOID APRSClose(); +VOID CloseTNCEmulator(); + +VOID Poll_AGW(); +void RHPPoll(); +BOOL AGWAPIInit(); +int AGWAPITerminate(); + +int * Flag = (int *)&Flag; // for Dump Analysis +int MAJORVERSION=4; +int MINORVERSION=9; + +struct SEM Semaphore = {0, 0, 0, 0}; +struct SEM APISemaphore = {0, 0, 0, 0}; +int SemHeldByAPI = 0; +int LastSemGets = 0; +UINT Sem_eax = 0; +UINT Sem_ebx = 0; +UINT Sem_ecx = 0; +UINT Sem_edx = 0; +UINT Sem_esi = 0; +UINT Sem_edi = 0; + + +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); +void FreeSemaphore(struct SEM * Semaphore); + +DllExport void * BPQHOSTAPIPTR = &BPQHOSTAPI; +//DllExport long MONDECODEPTR = (long)&MONDECODE; + +extern UCHAR BPQDirectory[]; +extern UCHAR LogDirectory[]; +extern UCHAR BPQProgramDirectory[]; + +static char BPQWinMsg[] = "BPQWindowMessage"; + +static char ClassName[] = "BPQMAINWINDOW"; + +HKEY REGTREE = HKEY_CURRENT_USER; +char REGTREETEXT[100] = "HKEY_CURRENT_USER"; + +UINT BPQMsg=0; + +#define MAXLINELEN 120 +#define MAXSCREENLEN 50 + +#define BGCOLOUR RGB(236,233,216) + +HBRUSH bgBrush = NULL; + +//int LINELEN=120; +//int SCREENLEN=50; + +//char Screen[MAXLINELEN*MAXSCREENLEN]={0}; + +//int lineno=0; +//int col=0; + +#define REPORTINTERVAL 15 * 549; // Magic Ticks Per Minute for PC's nominal 100 ms timer +int ReportTimer = 0; + +HANDLE OpenConfigFile(char * file); + +VOID SetupBPQDirectory(); +VOID SendLocation(); + +//uintptr_t _beginthread(void(*start_address)(), unsigned stack_size, int arglist); + +#define TRAY_ICON_ID 1 // ID number for the Notify Icon +#define MY_TRAY_ICON_MESSAGE WM_APP // the message ID sent to our window + +NOTIFYICONDATA niData; + +int SetupConsoleWindow(); + +BOOL StartMinimized=FALSE; +BOOL MinimizetoTray=TRUE; + +BOOL StatusMinimized = FALSE; +BOOL ConsoleMinimized = FALSE; + +HMENU trayMenu=0; + +HWND hConsWnd = NULL, hWndCons = NULL, hWndBG = NULL, ClientWnd = NULL, FrameWnd = NULL, StatusWnd = NULL; + +BOOL FrameMaximized = FALSE; + +BOOL IGateEnabled = TRUE; +extern int ISDelayTimer; // Time before trying to reopen APRS-IS link +extern int ISPort; + +UINT * WINMORTraceQ = NULL; +UINT * SetWindowTextQ = NULL; + +static RECT Rect = {100,100,400,400}; // Console Window Position +RECT FRect = {100,100,800,600}; // Frame +static RECT StatusRect = {100,100,850,500}; // Status Window + +DllExport int APIENTRY DumpSystem(); +DllExport int APIENTRY SaveNodes (); +DllExport int APIENTRY ClearNodes (); +DllExport int APIENTRY SetupTrayIcon(); + +#define Q_REM(s) _Q_REM(s, __FILE__, __LINE__) + +VOID * _Q_REM(VOID *Q, char * File, int Line); + +UINT ReleaseBuffer(UINT *BUFF); + + +VOID CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime ); + +DllExport int APIENTRY DeallocateStream(int stream); + +int VECTORLENGTH = sizeof (struct _BPQVECSTRUC); + +int FirstEntry = 1; +BOOL CloseLast = TRUE; // If the user started BPQ32.exe, don't close it when other programs close +BOOL Closing = FALSE; // Set if Close All called - prevents respawning bpq32.exe + +BOOL BPQ32_EXE; // Set if Process is running BPQ32.exe. Not initialised. + // Used to Kill surplus BPQ32.exe processes + +DWORD Our_PID; // Our Process ID - local variable + +void * InitDone = 0; +int FirstInitDone = 0; +int PerlReinit = 0; +UINT_PTR TimerHandle = 0; +UINT_PTR SessHandle = 0; + +BOOL EventsEnabled = 0; + +unsigned int TimerInst = 0xffffffff; + +HANDLE hInstance = 0; + +int AttachedProcesses = 0; +int AttachingProcess = 0; +HINSTANCE hIPModule = 0; +HINSTANCE hRigModule = 0; + +BOOL ReconfigFlag = FALSE; +BOOL RigReconfigFlag = FALSE; +BOOL APRSReconfigFlag = FALSE; +BOOL CloseAllNeeded = FALSE; +BOOL NeedWebMailRefresh = FALSE; + +int AttachedPIDList[100] = {0}; + +HWND hWndArray[100] = {0}; +int PIDArray[100] = {0}; +char PopupText[30][100] = {""}; + +// Next 3 should be uninitialised so they are local to each process + +UCHAR MCOM; +UCHAR MTX; // Top bit indicates use local time +uint64_t MMASK; +UCHAR MUIONLY; + +UCHAR AuthorisedProgram; // Local Variable. Set if Program is on secure list + +char pgm[256]; // Uninitialised so per process + +HANDLE Mutex; + +BOOL PartLine = FALSE; +int pindex = 0; +DWORD * WritetoConsoleQ; + + +LARGE_INTEGER lpFrequency = {0}; +LARGE_INTEGER lastRunTime; +LARGE_INTEGER currentTime; + +int ticksPerMillisec; +int interval; + + +VOID CALLBACK SetupTermSessions(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime); + + +TIMERPROC lpTimerFunc = (TIMERPROC) TimerProc; +TIMERPROC lpSetupTermSessions = (TIMERPROC) SetupTermSessions; + + +BOOL ProcessConfig(); +VOID FreeConfig(); + +DllExport int APIENTRY WritetoConsole(char * buff); + +BOOLEAN CheckifBPQ32isLoaded(); +BOOLEAN StartBPQ32(); +DllExport VOID APIENTRY Send_AX(VOID * Block, DWORD len, UCHAR Port); +BOOL LoadIPDriver(); +BOOL Send_IP(VOID * Block, DWORD len); +VOID CheckforLostProcesses(); +BOOL LoadRigDriver(); +VOID SaveConfig(); +VOID CreateRegBackup(); +VOID ResolveUpdateThread(); +VOID OpenReportingSockets(); +DllExport VOID APIENTRY CloseAllPrograms(); +DllExport BOOL APIENTRY SaveReg(char * KeyIn, HANDLE hFile); +int upnpClose(); + +BOOL IPActive = FALSE; +extern BOOL IPRequired; +BOOL PMActive = FALSE; +extern BOOL PMRequired; +BOOL RigRequired = TRUE; +BOOL RigActive = FALSE; +BOOL APRSActive = FALSE; +BOOL AGWActive = FALSE; +BOOL needAIS = FALSE; +int needADSB = 0; + +extern int AGWPort; + +Tell_Sessions(); + + +typedef int (WINAPI FAR *FARPROCX)(); + +FARPROCX CreateToolHelp32SnapShotPtr; +FARPROCX Process32Firstptr; +FARPROCX Process32Nextptr; + +void LoadToolHelperRoutines() +{ + HINSTANCE ExtDriver=0; + int err; + char msg[100]; + + ExtDriver=LoadLibrary("kernel32.dll"); + + if (ExtDriver == NULL) + { + err=GetLastError(); + sprintf(msg,"BPQ32 Error loading kernel32.dll - Error code %d\n", err); + OutputDebugString(msg); + return; + } + + CreateToolHelp32SnapShotPtr = (FARPROCX)GetProcAddress(ExtDriver,"CreateToolhelp32Snapshot"); + Process32Firstptr = (FARPROCX)GetProcAddress(ExtDriver,"Process32First"); + Process32Nextptr = (FARPROCX)GetProcAddress(ExtDriver,"Process32Next"); + + if (CreateToolHelp32SnapShotPtr == 0) + { + err=GetLastError(); + sprintf(msg,"BPQ32 Error getting CreateToolhelp32Snapshot entry point - Error code %d\n", err); + OutputDebugString(msg); + return; + } +} + +BOOL GetProcess(int ProcessID, char * Program) +{ + HANDLE hProcessSnap; + PROCESSENTRY32 pe32; + int p; + + if (CreateToolHelp32SnapShotPtr==0) + { + return (TRUE); // Routine not available + } + // Take a snapshot of all processes in the system. + hProcessSnap = (HANDLE)CreateToolHelp32SnapShotPtr(TH32CS_SNAPPROCESS, 0); + if( hProcessSnap == INVALID_HANDLE_VALUE ) + { + OutputDebugString( "CreateToolhelp32Snapshot (of processes) Failed\n" ); + return( FALSE ); + } + + // Set the size of the structure before using it. + pe32.dwSize = sizeof( PROCESSENTRY32 ); + + // Retrieve information about the first process, + // and exit if unsuccessful + if( !Process32Firstptr( hProcessSnap, &pe32 ) ) + { + OutputDebugString( "Process32First Failed\n" ); // Show cause of failure + CloseHandle( hProcessSnap ); // Must clean up the snapshot object! + return( FALSE ); + } + + // Now walk the snapshot of processes, and + // display information about each process in turn + do + { + if (ProcessID==pe32.th32ProcessID) + { + // if running on 98, program contains the full path - remove it + + for (p = (int)strlen(pe32.szExeFile); p >= 0; p--) + { + if (pe32.szExeFile[p]=='\\') + { + break; + } + } + p++; + + sprintf(Program,"%s", &pe32.szExeFile[p]); + CloseHandle( hProcessSnap ); + return( TRUE ); + } + + } while( Process32Nextptr( hProcessSnap, &pe32 ) ); + + + sprintf(Program,"PID %d Not Found", ProcessID); + CloseHandle( hProcessSnap ); + return(FALSE); +} + +BOOL IsProcess(int ProcessID) +{ + // Check that Process exists + + HANDLE hProcessSnap; + PROCESSENTRY32 pe32; + + if (CreateToolHelp32SnapShotPtr==0) return (TRUE); // Routine not available + + hProcessSnap = (HANDLE)CreateToolHelp32SnapShotPtr(TH32CS_SNAPPROCESS, 0); + + if( hProcessSnap == INVALID_HANDLE_VALUE ) + { + OutputDebugString( "CreateToolhelp32Snapshot (of processes) Failed\n" ); + return(TRUE); // Don't know, so assume ok + } + + pe32.dwSize = sizeof( PROCESSENTRY32 ); + + if( !Process32Firstptr( hProcessSnap, &pe32 ) ) + { + OutputDebugString( "Process32First Failed\n" ); // Show cause of failure + CloseHandle( hProcessSnap ); // Must clean up the snapshot object! + return(TRUE); // Don't know, so assume ok + } + + do + { + if (ProcessID==pe32.th32ProcessID) + { + CloseHandle( hProcessSnap ); + return( TRUE ); + } + + } while( Process32Nextptr( hProcessSnap, &pe32 ) ); + + CloseHandle( hProcessSnap ); + return(FALSE); +} + +#include "DbgHelp.h" + +VOID MonitorThread(int x) +{ + // Thread to detect killed processes. Runs in process owning timer. + + // Obviously can't detect loss of timer owning thread! + + do + { + if (Semaphore.Gets == LastSemGets && Semaphore.Flag) + { + // It is stuck - try to release + + Debugprintf ("Semaphore locked - Process ID = %d, Held By %d from %s Line %d", + Semaphore.SemProcessID, SemHeldByAPI, Semaphore.File, Semaphore.Line); + + // Write a minidump + + WriteMiniDump(); + + Semaphore.Flag = 0; + } + + LastSemGets = Semaphore.Gets; + + Sleep(30000); + CheckforLostProcesses(); + + } while (TRUE); +} + +VOID CheckforLostProcesses() +{ + UCHAR buff[100]; + char Log[80]; + int i, n, ProcessID; + + for (n=0; n < AttachedProcesses; n++) + { + ProcessID=AttachedPIDList[n]; + + if (!IsProcess(ProcessID)) + { + // Process has died - Treat as a detach + + sprintf(Log,"BPQ32 Process %d Died\n", ProcessID); + OutputDebugString(Log); + + // Remove Tray Icon Entry + + for( i = 0; i < 100; ++i ) + { + if (PIDArray[i] == ProcessID) + { + hWndArray[i] = 0; + sprintf(Log,"BPQ32 Removing Tray Item %s\n", PopupText[i]); + OutputDebugString(Log); + DeleteMenu(trayMenu,TRAYBASEID+i,MF_BYCOMMAND); + } + } + + // If process had the semaphore, release it + + if (Semaphore.Flag == 1 && ProcessID == Semaphore.SemProcessID) + { + OutputDebugString("BPQ32 Process was holding Semaphore - attempting recovery\r\n"); + Debugprintf("Last Sem Call %d %x %x %x %x %x %x", SemHeldByAPI, + Sem_eax, Sem_ebx, Sem_ecx, Sem_edx, Sem_esi, Sem_edi); + + Semaphore.Flag = 0; + SemHeldByAPI = 0; + } + + for (i=1;i<65;i++) + { + if (BPQHOSTVECTOR[i-1].STREAMOWNER == AttachedPIDList[n]) + { + DeallocateStream(i); + } + } + + if (TimerInst == ProcessID) + { + KillTimer(NULL,TimerHandle); + TimerHandle=0; + TimerInst=0xffffffff; +// Tell_Sessions(); + OutputDebugString("BPQ32 Process was running timer \n"); + + if (MinimizetoTray) + Shell_NotifyIcon(NIM_DELETE,&niData); + + + } + + // Remove this entry from PID List + + for (i=n; i< AttachedProcesses; i++) + { + AttachedPIDList[i]=AttachedPIDList[i+1]; + } + AttachedProcesses--; + + sprintf(buff,"BPQ32 Lost Process - %d Process(es) Attached\n", AttachedProcesses); + OutputDebugString(buff); + } + } +} +VOID MonitorTimerThread(int x) +{ + // Thread to detect killed timer process. Runs in all other BPQ32 processes. + + do { + + Sleep(60000); + + if (TimerInst != 0xffffffff && !IsProcess(TimerInst)) + { + // Timer owning Process has died - Force a new timer to be created + // New timer thread will detect lost process and tidy up + + Debugprintf("BPQ32 Process %d with Timer died", TimerInst); + + // If process was holding the semaphore, release it + + if (Semaphore.Flag == 1 && TimerInst == Semaphore.SemProcessID) + { + OutputDebugString("BPQ32 Process was holding Semaphore - attempting recovery\r\n"); + Debugprintf("Last Sem Call %d %x %x %x %x %x %x", SemHeldByAPI, + Sem_eax, Sem_ebx, Sem_ecx, Sem_edx, Sem_esi, Sem_edi); + Semaphore.Flag = 0; + SemHeldByAPI = 0; + } + +// KillTimer(NULL,TimerHandle); +// TimerHandle=0; +// TimerInst=0xffffffff; +// Tell_Sessions(); + + CheckforLostProcesses(); // Normally only done in timer thread, which is now dead + + // Timer can only run in BPQ32.exe + + TimerInst=0xffffffff; // So we dont keep doing it + TimerHandle = 0; // So new process attaches + + if (Closing == FALSE && AttachingProcess == FALSE) + { + OutputDebugString("BPQ32 Reloading BPQ32.exe\n"); + StartBPQ32(); + } + +// if (MinimizetoTray) +// Shell_NotifyIcon(NIM_DELETE,&niData); + } + + } while (TRUE); +} + +VOID WritetoTraceSupport(struct TNCINFO * TNC, char * Msg, int Len); + +VOID TimerProcX(); + +VOID CALLBACK TimerProc( + HWND hwnd, // handle of window for timer messages + UINT uMsg, // WM_TIMER message + UINT idEvent, // timer identifier + DWORD dwTime) // current system time +{ + KillTimer(NULL,TimerHandle); + TimerProcX(); + TimerHandle = SetTimer(NULL,0,100,lpTimerFunc); +} +VOID TimerProcX() +{ + struct _EXCEPTION_POINTERS exinfo; + + // + // Get semaphore before proceeeding + // + + GetSemaphore(&Semaphore, 2); + + // Get time since last run + + QueryPerformanceCounter(¤tTime); + + interval = (int)(currentTime.QuadPart - lastRunTime.QuadPart) / ticksPerMillisec; + lastRunTime.QuadPart = currentTime.QuadPart; + + //Debugprintf("%d", interval); + + // Process WINMORTraceQ + + while (WINMORTraceQ) + { + UINT * Buffer = Q_REM(&WINMORTraceQ); + struct TNCINFO * TNC = (struct TNCINFO * )Buffer[1]; + int Len = Buffer[2]; + char * Msg = (char *)&Buffer[3]; + + WritetoTraceSupport(TNC, Msg, Len); + RelBuff(Buffer); + } + + if (SetWindowTextQ) + SetWindowTextSupport(); + + while (WritetoConsoleQ) + { + UINT * Buffer = Q_REM(&WritetoConsoleQ); + WritetoConsoleSupport((char *)&Buffer[2]); + RelBuff(Buffer); + } + + strcpy(EXCEPTMSG, "Timer ReconfigProcessing"); + + __try + { + + if (trayMenu == NULL) + SetupTrayIcon(); + + // See if reconfigure requested + + if (CloseAllNeeded) + { + CloseAllNeeded = FALSE; + CloseAllPrograms(); + } + + if (ReconfigFlag) + { + // Only do it it timer owning process, or we could get in a real mess! + + if(TimerInst == GetCurrentProcessId()) + { + int i; + BPQVECSTRUC * HOSTVEC; + PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE; + WSADATA WsaData; // receives data from WSAStartup + RECT cRect; + + ReconfigFlag = FALSE; + + SetupBPQDirectory(); + + WritetoConsole("Reconfiguring ...\n\n"); + OutputDebugString("BPQ32 Reconfiguring ...\n"); + + GetWindowRect(FrameWnd, &FRect); + + SaveWindowPos(70); // Rigcontrol + + for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External + { + if (PORTVEC->PORT_EXT_ADDR) + { + SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); + SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); + CloseDriverWindow(PORTVEC->PORTCONTROL.PORTNUMBER); + PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL); // Close External Ports + } + } + PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL); + PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER; + } + + IPClose(); + PMClose(); + APRSClose(); + Rig_Close(); + CloseTNCEmulator(); + if (AGWActive) + AGWAPITerminate(); + + WSACleanup(); + + WL2KReports = NULL; + + Sleep(2000); + + WSAStartup(MAKEWORD(2, 0), &WsaData); + + Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring); + Consoleprintf(VerCopyright); + + Start(); + + INITIALISEPORTS(); // Restart Ports + + SetApplPorts(); + + FreeConfig(); + + for (i=1; i<68; i++) // Include Telnet, APRS and IP Vec + { + HOSTVEC=&BPQHOSTVECTOR[i-1]; + + HOSTVEC->HOSTTRACEQ=0; // Clear header (pool has been reinitialized + + if (HOSTVEC->HOSTSESSION !=0) + { + // Had a connection + + HOSTVEC->HOSTSESSION=0; + HOSTVEC->HOSTFLAGS |=3; // Disconnected + + PostMessage(HOSTVEC->HOSTHANDLE, BPQMsg, i, 4); + } + } + + // Free the APRS Appl Q + + APPL_Q = 0; + + OpenReportingSockets(); + + WritetoConsole("\n\nReconfiguration Complete\n"); + + if (IPRequired) IPActive = Init_IP(); + if (PMRequired) PMActive = Init_PM(); + + APRSActive = Init_APRS(); + + if (ISPort == 0) + IGateEnabled = 0; + + CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled); + + GetClientRect(hConsWnd, &cRect); + MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE); + if (APRSActive) + MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE); + else + { + ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE); + MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE); + } + InvalidateRect(hConsWnd, NULL, TRUE); + + RigActive = Rig_Init(); + + if (NUMBEROFTNCPORTS) + { + FreeSemaphore(&Semaphore); + InitializeTNCEmulator(); + GetSemaphore(&Semaphore, 0); + } + + FreeSemaphore(&Semaphore); + AGWActive = AGWAPIInit(); + GetSemaphore(&Semaphore, 0); + + OutputDebugString("BPQ32 Reconfiguration Complete\n"); + } + } + + + if (RigReconfigFlag) + { + // Only do it it timer owning process, or we could get in a real mess! + + if(TimerInst == GetCurrentProcessId()) + { + RigReconfigFlag = FALSE; + CloseDriverWindow(70); + Rig_Close(); + Sleep(6000); // Allow any CATPTT, HAMLIB and FLRIG threads to close + RigActive = Rig_Init(); + + WritetoConsole("Rigcontrol Reconfiguration Complete\n"); + } + } + + if (APRSReconfigFlag) + { + // Only do it it timer owning process, or we could get in a real mess! + + if(TimerInst == GetCurrentProcessId()) + { + APRSReconfigFlag = FALSE; + APRSClose(); + APRSActive = Init_APRS(); + + WritetoConsole("APRS Reconfiguration Complete\n"); + } + } + + } + #include "StdExcept.c" + + if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId()) + FreeSemaphore(&Semaphore); + + } + + strcpy(EXCEPTMSG, "Timer Processing"); + + __try + { + if (IPActive) Poll_IP(); + if (PMActive) Poll_PM(); + if (RigActive) Rig_Poll(); + + if (NeedWebMailRefresh) + DoRefreshWebMailIndex(); + + CheckGuardZone(); + + if (APRSActive) + { + Poll_APRS(); + CheckGuardZone(); + } + + CheckWL2KReportTimer(); + + CheckGuardZone(); + + TIMERINTERRUPT(); + + CheckGuardZone(); + + FreeSemaphore(&Semaphore); // SendLocation needs to get the semaphore + + if (NUMBEROFTNCPORTS) + TNCTimer(); + + if (AGWActive) + Poll_AGW(); + + DRATSPoll(); + RHPPoll(); + + CheckGuardZone(); + + strcpy(EXCEPTMSG, "HTTP Timer Processing"); + + HTTPTimer(); + + CheckGuardZone(); + + strcpy(EXCEPTMSG, "WL2K Report Timer Processing"); + + if (ReportTimer) + { + ReportTimer--; + + if (ReportTimer == 0) + { + ReportTimer = REPORTINTERVAL; + SendLocation(); + } + } + } + + #include "StdExcept.c" + + if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId()) + FreeSemaphore(&Semaphore); + + } + + CheckGuardZone(); + + return; +} + +HANDLE NPHandle; + +int (WINAPI FAR *GetModuleFileNameExPtr)() = NULL; +int (WINAPI FAR *EnumProcessesPtr)() = NULL; + +FirstInit() +{ + WSADATA WsaData; // receives data from WSAStartup + HINSTANCE ExtDriver=0; + RECT cRect; + + + // First Time Ports and Timer init + + // Moved from DLLINIT to sort out perl problem, and meet MS Guidelines on minimising DLLMain + + // Call wsastartup - most systems need winsock, and duplicate statups could be a problem + + WSAStartup(MAKEWORD(2, 0), &WsaData); + + // Load Psapi.dll if possible + + ExtDriver=LoadLibrary("Psapi.dll"); + + SetupTrayIcon(); + + if (ExtDriver) + { + GetModuleFileNameExPtr = (FARPROCX)GetProcAddress(ExtDriver,"GetModuleFileNameExA"); + EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses"); + } + + timeLoadedMS = GetTickCount(); + + INITIALISEPORTS(); + + OpenReportingSockets(); + + WritetoConsole("\n"); + WritetoConsole("Port Initialisation Complete\n"); + + if (IPRequired) IPActive = Init_IP(); + if (PMRequired) PMActive = Init_PM(); + + APRSActive = Init_APRS(); + + if (APRSActive) + { + hWndBG = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 0,0,40,546, hConsWnd, NULL, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "Enable IGate", WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, + 8,0,90,24, hConsWnd, (HMENU)-1, hInstance, NULL); + + CreateWindowEx(0, "BUTTON", "", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP, + 95,1,18,24, hConsWnd, (HMENU)IDC_ENIGATE, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "IGate State - Disconnected", + WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 125, 0, 195, 24, hConsWnd, (HMENU)IGATESTATE, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "IGATE Stats - Msgs 0 Local Stns 0", + WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 320, 0, 240, 24, hConsWnd, (HMENU)IGATESTATS, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "GPS Off", + WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 560, 0, 80, 24, hConsWnd, (HMENU)IDC_GPS, hInstance, NULL); + } + + if (ISPort == 0) + IGateEnabled = 0; + + CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled); + + GetClientRect(hConsWnd, &cRect); + MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE); + if (APRSActive) + MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE); + else + { + ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE); + MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE); + } + InvalidateRect(hConsWnd, NULL, TRUE); + + RigActive = Rig_Init(); + + _beginthread(MonitorThread,0,0); + + TimerHandle=SetTimer(NULL,0,100,lpTimerFunc); + TimerInst=GetCurrentProcessId(); + SessHandle = SetTimer(NULL, 0, 5000, lpSetupTermSessions); + + // If ARIF reporting is enabled write a Trimode Like ini for RMS Analyser + + if (ADIFLogEnabled) + ADIFWriteFreqList(); + + OutputDebugString("BPQ32 Port Initialisation Complete\n"); + + if (needAIS) + initAIS(); + + if (needADSB) + initADSB(); + + return 0; +} + +Check_Timer() +{ + if (Closing) + return 0; + + if (Semaphore.Flag) + return 0; + + if (InitDone == (void *)-1) + { + GetSemaphore(&Semaphore, 3); + Sleep(15000); + FreeSemaphore(&Semaphore); + exit (0); + } + + if (FirstInitDone == 0) + { + GetSemaphore(&Semaphore, 3); + + if (_stricmp(pgm, "bpq32.exe") == 0) + { + FirstInit(); + FreeSemaphore(&Semaphore); + if (NUMBEROFTNCPORTS) + InitializeTNCEmulator(); + + AGWActive = AGWAPIInit(); + FirstInitDone=1; // Only init in BPQ32.exe + return 0; + } + else + { + FreeSemaphore(&Semaphore); + return 0; + } + } + + if (TimerHandle == 0 && FirstInitDone == 1) + { + WSADATA WsaData; // receives data from WSAStartup + HINSTANCE ExtDriver=0; + RECT cRect; + + // Only attach timer to bpq32.exe + + if (_stricmp(pgm, "bpq32.exe") != 0) + { + return 0; + } + + GetSemaphore(&Semaphore, 3); + OutputDebugString("BPQ32 Reinitialising External Ports and Attaching Timer\n"); + + if (!ProcessConfig()) + { + ShowWindow(hConsWnd, SW_RESTORE); + SendMessage(hConsWnd, WM_PAINT, 0, 0); + SetForegroundWindow(hConsWnd); + + InitDone = (void *)-1; + FreeSemaphore(&Semaphore); + + MessageBox(NULL,"Configuration File Error","BPQ32",MB_ICONSTOP); + + exit (0); + } + + GetVersionInfo("bpq32.dll"); + + SetupConsoleWindow(); + + Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring); + Consoleprintf(VerCopyright); + Consoleprintf("Reinitialising..."); + + SetupBPQDirectory(); + + Sleep(1000); // Allow time for sockets to close + + WSAStartup(MAKEWORD(2, 0), &WsaData); + + // Load Psapi.dll if possible + + ExtDriver = LoadLibrary("Psapi.dll"); + + SetupTrayIcon(); + + if (ExtDriver) + { + GetModuleFileNameExPtr = (FARPROCX)GetProcAddress(ExtDriver,"GetModuleFileNameExA"); + EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses"); + } + + Start(); + + INITIALISEPORTS(); + + OpenReportingSockets(); + + NODESINPROGRESS = 0; + CURRENTNODE = 0; + + SetApplPorts(); + + WritetoConsole("\n\nPort Reinitialisation Complete\n"); + + BPQMsg = RegisterWindowMessage(BPQWinMsg); + + CreateMutex(NULL,TRUE,"BPQLOCKMUTEX"); + +// NPHandle=CreateNamedPipe("\\\\.\\pipe\\BPQ32pipe", +// PIPE_ACCESS_DUPLEX,0,64,4096,4096,1000,NULL); + + if (IPRequired) IPActive = Init_IP(); + if (PMRequired) PMActive = Init_PM(); + + RigActive = Rig_Init(); + APRSActive = Init_APRS(); + + if (ISPort == 0) + IGateEnabled = 0; + + CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled); + + GetClientRect(hConsWnd, &cRect); + MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE); + + if (APRSActive) + MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE); + else + { + ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE); + MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE); + } + InvalidateRect(hConsWnd, NULL, TRUE); + + FreeConfig(); + + _beginthread(MonitorThread,0,0); + + ReportTimer = 0; + + OpenReportingSockets(); + + FreeSemaphore(&Semaphore); + + if (NUMBEROFTNCPORTS) + InitializeTNCEmulator(); + + AGWActive = AGWAPIInit(); + + if (StartMinimized) + if (MinimizetoTray) + ShowWindow(FrameWnd, SW_HIDE); + else + ShowWindow(FrameWnd, SW_SHOWMINIMIZED); + else + ShowWindow(FrameWnd, SW_RESTORE); + + TimerHandle=SetTimer(NULL,0,100,lpTimerFunc); + TimerInst=GetCurrentProcessId(); + SessHandle = SetTimer(NULL, 0, 5000, lpSetupTermSessions); + + return (1); + } + + return (0); +} + +DllExport INT APIENTRY CheckTimer() +{ + return Check_Timer(); +} + +Tell_Sessions() +{ + // + // Post a message to all listening sessions, so they call the + // API, and cause a new timer to be allocated + // + HWND hWnd; + int i; + + for (i=1;i<65;i++) + { + if (BPQHOSTVECTOR[i-1].HOSTFLAGS & 0x80) + { + hWnd = BPQHOSTVECTOR[i-1].HOSTHANDLE; + PostMessage(hWnd, BPQMsg,i, 1); + PostMessage(hWnd, BPQMsg,i, 2); + } + } + return (0); +} + +BOOL APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID lpReserved) +{ + DWORD n; + char buf[350]; + + int i; + unsigned int ProcessID; + + OSVERSIONINFO osvi; + + memset(&osvi, 0, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + + GetVersionEx(&osvi); + + + switch( ul_reason_being_called ) + { + case DLL_PROCESS_ATTACH: + + if (sizeof(HDLCDATA) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata + { + // Catastrophic - Refuse to load + + MessageBox(NULL,"BPQ32 Too much HDLC data - Recompile","BPQ32", MB_OK); + return 0; + } + + if (sizeof(struct KISSINFO) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata + { + // Catastrophic - Refuse to load + + MessageBox(NULL,"BPQ32 Too much KISS data - Recompile","BPQ32", MB_OK); + return 0; + } + + if (sizeof(struct _EXTPORTDATA) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata + { + // Catastrophic - Refuse to load + + MessageBox(NULL,"BPQ32 Too much _EXTPORTDATA data - Recompile","BPQ32", MB_OK); + return 0; + } + + if (sizeof(LINKTABLE) != LINK_TABLE_LEN) + { + // Catastrophic - Refuse to load + + MessageBox(NULL,"L2 LINK Table .c and .asm mismatch - fix and rebuild","BPQ32", MB_OK); + return 0; + } + if (sizeof(struct ROUTE) != ROUTE_LEN) + { + // Catastrophic - Refuse to load + + MessageBox(NULL,"ROUTE Table .c and .asm mismatch - fix and rebuild", "BPQ32", MB_OK); + return 0; + } + + if (sizeof(struct DEST_LIST) != DEST_LIST_LEN) + { + // Catastrophic - Refuse to load + + MessageBox(NULL,"NODES Table .c and .asm mismatch - fix and rebuild", "BPQ32", MB_OK); + return 0; + } + + GetSemaphore(&Semaphore, 4); + + BPQHOSTVECPTR = &BPQHOSTVECTOR[0]; + + LoadToolHelperRoutines(); + + Our_PID = GetCurrentProcessId(); + + QueryPerformanceFrequency(&lpFrequency); + + ticksPerMillisec = (int)lpFrequency.QuadPart / 1000; + + lastRunTime.QuadPart = lpFrequency.QuadPart; + + GetProcess(Our_PID, pgm); + + if (_stricmp(pgm, "regsvr32.exe") == 0 || _stricmp(pgm, "bpqcontrol.exe") == 0) + { + AttachedProcesses++; // We will get a detach + FreeSemaphore(&Semaphore); + return 1; + } + + if (_stricmp(pgm,"BPQ32.exe") == 0) + BPQ32_EXE = TRUE; + + if (_stricmp(pgm,"BPQMailChat.exe") == 0) + IncludesMail = TRUE; + + if (_stricmp(pgm,"BPQMail.exe") == 0) + IncludesMail = TRUE; + + if (_stricmp(pgm,"BPQChat.exe") == 0) + IncludesChat = TRUE; + + if (FirstEntry) // If loaded by BPQ32.exe, dont close it at end + { + FirstEntry = 0; + if (BPQ32_EXE) + CloseLast = FALSE; + } + else + { + if (BPQ32_EXE && AttachingProcess == 0) + { + AttachedProcesses++; // We will get a detach + FreeSemaphore(&Semaphore); + MessageBox(NULL,"BPQ32.exe is already running\r\n\r\nIt should only be run once", "BPQ32", MB_OK); + return 0; + } + } + + if (_stricmp(pgm,"BPQTelnetServer.exe") == 0) + { + MessageBox(NULL,"BPQTelnetServer is no longer supported\r\n\r\nUse the TelnetServer in BPQ32.dll", "BPQ32", MB_OK); + AttachedProcesses++; // We will get a detach + FreeSemaphore(&Semaphore); + return 0; + } + + if (_stricmp(pgm,"BPQUIUtil.exe") == 0) + { + MessageBox(NULL,"BPQUIUtil is now part of BPQ32.dll\r\nBPQUIUtil.exe cannot be run\r\n", "BPQ32", MB_OK); + AttachedProcesses++; // We will get a detach + FreeSemaphore(&Semaphore); + return 0; + } + + if (_stricmp(pgm,"BPQMailChat.exe") == 0) + { + MessageBox(NULL,"BPQMailChat is obsolete. Run BPQMail.exe and/or BPQChat.exe instead", "BPQ32", MB_OK); + AttachedProcesses++; // We will get a detach + FreeSemaphore(&Semaphore); + return 0; + } + AuthorisedProgram = TRUE; + + if (InitDone == 0) + { +// #pragma warning(push) +// #pragma warning(disable : 4996) + +// if (_winver < 0x0600) +// #pragma warning(pop) +// { +// // Below Vista +// +// REGTREE = HKEY_LOCAL_MACHINE; +// strcpy(REGTREETEXT, "HKEY_LOCAL_MACHINE"); +// } + + hInstance=hInst; + + Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX"); + + if (Mutex != NULL) + { + OutputDebugString("Another BPQ32.dll is loaded\n"); + i=MessageBox(NULL,"BPQ32 DLL already loaded from another directory\nIf you REALLY want this, hit OK, else hit Cancel","BPQ32",MB_OKCANCEL); + FreeSemaphore(&Semaphore); + + if (i != IDOK) return (0); + + CloseHandle(Mutex); + } + + if (!BPQ32_EXE) + { + if (CheckifBPQ32isLoaded() == FALSE) // Start BPQ32.exe if needed + { + // Wasn't Loaded, so we have started it, and should let it init system + + goto SkipInit; + } + } + + GetVersionInfo("bpq32.dll"); + + sprintf (SIGNONMSG, "G8BPQ AX25 Packet Switch System Version %s %s\r\n%s\r\n", + TextVerstring, Datestring, VerCopyright); + + SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for Win32 (", TextVerstring); + + SetupConsoleWindow(); + SetupBPQDirectory(); + + if (!ProcessConfig()) + { + StartMinimized = FALSE; + MinimizetoTray = FALSE; + ShowWindow(FrameWnd, SW_MAXIMIZE); + ShowWindow(hConsWnd, SW_MAXIMIZE); + ShowWindow(StatusWnd, SW_HIDE); + + SendMessage(hConsWnd, WM_PAINT, 0, 0); + SetForegroundWindow(hConsWnd); + + InitDone = (void *)-1; + FreeSemaphore(&Semaphore); + + MessageBox(NULL,"Configuration File Error\r\nProgram will close in 15 seconds","BPQ32",MB_ICONSTOP); + + return (0); + } + + Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring); + Consoleprintf(VerCopyright); + + if (Start() !=0) + { + Sleep(3000); + FreeSemaphore(&Semaphore); + return (0); + } + else + { + SetApplPorts(); + + GetUIConfig(); + + InitDone = &InitDone; + BPQMsg = RegisterWindowMessage(BPQWinMsg); +// TimerHandle=SetTimer(NULL,0,100,lpTimerFunc); +// TimerInst=GetCurrentProcessId(); + +/* Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX"); + + if (Mutex != NULL) + { + OutputDebugString("Another BPQ32.dll is loaded\n"); + MessageBox(NULL,"BPQ32 DLL already loaded from another directory","BPQ32",MB_ICONSTOP); + FreeSemaphore(&Semaphore); + return (0); + } + +*/ + Mutex=CreateMutex(NULL,TRUE,"BPQLOCKMUTEX"); + +// CreatePipe(&H1,&H2,NULL,1000); + +// GetLastError(); + +// NPHandle=CreateNamedPipe("\\\\.\\pipe\\BPQ32pipe", +// PIPE_ACCESS_DUPLEX,0,64,4096,4096,1000,NULL); + +// GetLastError(); + +/* + // + // Read SYSOP password + // + + if (PWTEXT[0] == 0) + { + handle = OpenConfigFile("PASSWORD.BPQ"); + + if (handle == INVALID_HANDLE_VALUE) + { + WritetoConsole("Can't open PASSWORD.BPQ\n"); + PWLen=0; + PWTEXT[0]=0; + } + else + { + ReadFile(handle,PWTEXT,78,&n,NULL); + CloseHandle(handle); + } + } +*/ + for (i=0;PWTEXT[i] > 0x20;i++); //Scan for cr or null + PWLen=i; + + } + } + else + { + if (InitDone != &InitDone) + { + MessageBox(NULL,"BPQ32 DLL already loaded at another address","BPQ32",MB_ICONSTOP); + FreeSemaphore(&Semaphore); + return (0); + } + } + + // Run timer monitor thread in all processes - it is possible for the TImer thread not to be the first thread +SkipInit: + + _beginthread(MonitorTimerThread,0,0); + + FreeSemaphore(&Semaphore); + + AttachedPIDList[AttachedProcesses++] = GetCurrentProcessId(); + + if (_stricmp(pgm,"bpq32.exe") == 0 && AttachingProcess == 1) AttachingProcess = 0; + + GetProcess(GetCurrentProcessId(),pgm); + n=sprintf(buf,"BPQ32 DLL Attach complete - Program %s - %d Process(es) Attached\n",pgm,AttachedProcesses); + OutputDebugString(buf); + + // Set up local variables + + MCOM=1; + MTX=1; + MMASK=0xffffffffffffffff; + +// if (StartMinimized) +// if (MinimizetoTray) +// ShowWindow(FrameWnd, SW_HIDE); +// else +// ShowWindow(FrameWnd, SW_SHOWMINIMIZED); +// else +// ShowWindow(FrameWnd, SW_RESTORE); + + return 1; + + case DLL_THREAD_ATTACH: + + return 1; + + case DLL_THREAD_DETACH: + + return 1; + + case DLL_PROCESS_DETACH: + + if (_stricmp(pgm,"BPQMailChat.exe") == 0) + IncludesMail = FALSE; + + if (_stricmp(pgm,"BPQChat.exe") == 0) + IncludesChat = FALSE; + + ProcessID=GetCurrentProcessId(); + + Debugprintf("BPQ32 Process %d Detaching", ProcessID); + + // Release any streams that the app has failed to release + + for (i=1;i<65;i++) + { + if (BPQHOSTVECTOR[i-1].STREAMOWNER == ProcessID) + { + // If connected, disconnect + + SessionControl(i, 2, 0); + DeallocateStream(i); + } + } + + // Remove any Tray Icon Entries + + for( i = 0; i < 100; ++i ) + { + if (PIDArray[i] == ProcessID) + { + char Log[80]; + hWndArray[i] = 0; + sprintf(Log,"BPQ32 Removing Tray Item %s\n", PopupText[i]); + OutputDebugString(Log); + DeleteMenu(trayMenu,TRAYBASEID+i,MF_BYCOMMAND); + } + } + + if (Mutex) CloseHandle(Mutex); + + // Remove our entry from PID List + + for (i=0; i< AttachedProcesses; i++) + if (AttachedPIDList[i] == ProcessID) + break; + + for (; i< AttachedProcesses; i++) + { + AttachedPIDList[i]=AttachedPIDList[i+1]; + } + + AttachedProcesses--; + + if (TimerInst == ProcessID) + { + PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE; + + OutputDebugString("BPQ32 Process with Timer closing\n"); + + // Call Port Close Routines + + for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External + { + if (PORTVEC->PORT_EXT_ADDR && PORTVEC->DLLhandle == NULL) // Don't call if real .dll - it's not there! + { + SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); + SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); + PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL); // Close External Ports + } + } + + PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL); + + PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER; + } + + + IPClose(); + PMClose(); + APRSClose(); + Rig_Close(); + CloseTNCEmulator(); + if (AGWActive) + AGWAPITerminate(); + + upnpClose(); + + WSACleanup(); + WSAGetLastError(); + + if (MinimizetoTray) + Shell_NotifyIcon(NIM_DELETE,&niData); + + if (hConsWnd) DestroyWindow(hConsWnd); + + KillTimer(NULL,TimerHandle); + TimerHandle=0; + TimerInst=0xffffffff; + + if (AttachedProcesses && Closing == FALSE && AttachingProcess == 0) // Other processes + { + OutputDebugString("BPQ32 Reloading BPQ32.exe\n"); + StartBPQ32(); + } + } + else + { + // Not Timer Process + + if (AttachedProcesses == 1 && CloseLast) // Only bpq32.exe left + { + Debugprintf("Only BPQ32.exe running - close it"); + CloseAllNeeded = TRUE; + } + } + + if (AttachedProcesses < 2) + { + if (AUTOSAVE) + SaveNodes(); + if (AUTOSAVEMH) + SaveMH(); + + if (needAIS) + SaveAIS(); + } + if (AttachedProcesses == 0) + { + Closing = TRUE; + KillTimer(NULL,TimerHandle); + + if (MinimizetoTray) + Shell_NotifyIcon(NIM_DELETE,&niData); + + // Unload External Drivers + + { + PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE; + + for (i=0;iPORTCONTROL.PORTTYPE == 0x10 && PORTVEC->DLLhandle) + FreeLibrary(PORTVEC->DLLhandle); + + PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER; + } + } + } + + GetProcess(GetCurrentProcessId(),pgm); + n=sprintf(buf,"BPQ32 DLL Detach complete - Program %s - %d Process(es) Attached\n",pgm,AttachedProcesses); + OutputDebugString(buf); + + return 1; + } + return 1; +} + +DllExport int APIENTRY CloseBPQ32() +{ + // Unload External Drivers + + PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE; + int i; + int ProcessID = GetCurrentProcessId(); + + if (Semaphore.Flag == 1 && ProcessID == Semaphore.SemProcessID) + { + OutputDebugString("BPQ32 Process holding Semaphore called CloseBPQ32 - attempting recovery\r\n"); + Debugprintf("Last Sem Call %d %x %x %x %x %x %x", SemHeldByAPI, + Sem_eax, Sem_ebx, Sem_ecx, Sem_edx, Sem_esi, Sem_edi); + + Semaphore.Flag = 0; + SemHeldByAPI = 0; + } + + if (TimerInst == ProcessID) + { + OutputDebugString("BPQ32 Process with Timer called CloseBPQ32\n"); + + if (MinimizetoTray) + Shell_NotifyIcon(NIM_DELETE,&niData); + + for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External + { + if (PORTVEC->PORT_EXT_ADDR) + { + PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL); + } + } + PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL); + + PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER; + } + + KillTimer(NULL,TimerHandle); + TimerHandle=0; + TimerInst=0xffffffff; + + IPClose(); + PMClose(); + APRSClose(); + Rig_Close(); + if (AGWActive) + AGWAPITerminate(); + + upnpClose(); + + CloseTNCEmulator(); + WSACleanup(); + + if (hConsWnd) DestroyWindow(hConsWnd); + + Debugprintf("AttachedProcesses %d ", AttachedProcesses); + + if (AttachedProcesses > 1 && Closing == FALSE && AttachingProcess == 0) // Other processes + { + OutputDebugString("BPQ32 Reloading BPQ32.exe\n"); + StartBPQ32(); + } + } + + return 0; +} + +BOOL CopyReg(HKEY hKeyIn, HKEY hKeyOut); + +VOID SetupBPQDirectory() +{ + HKEY hKey = 0; + HKEY hKeyIn = 0; + HKEY hKeyOut = 0; + int disp; + int retCode,Type,Vallen=MAX_PATH,i; + char msg[512]; + char ValfromReg[MAX_PATH] = ""; + char DLLName[256]="Not Known"; + char LogDir[256]; + char Time[64]; + +/* +•NT4 was/is '4' +•Win 95 is 4.00.950 +•Win 98 is 4.10.1998 +•Win 98 SE is 4.10.2222 +•Win ME is 4.90.3000 +•2000 is NT 5.0.2195 +•XP is actually 5.1 +•Vista is 6.0 +•Win7 is 6.1 + + i = _osver; / Build + i = _winmajor; + i = _winminor; +*/ +/* +#pragma warning(push) +#pragma warning(disable : 4996) + +if (_winver < 0x0600) +#pragma warning(pop) + { + // Below Vista + + REGTREE = HKEY_LOCAL_MACHINE; + strcpy(REGTREETEXT, "HKEY_LOCAL_MACHINE"); + ValfromReg[0] = 0; + } + else +*/ + { + if (_stricmp(pgm, "regsvr32.exe") == 0) + { + Debugprintf("BPQ32 loaded by regsvr32.exe - Registry not copied"); + } + else + { + // If necessary, move reg from HKEY_LOCAL_MACHINE to HKEY_CURRENT_USER + + retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE, + "SOFTWARE\\G8BPQ\\BPQ32", + 0, + KEY_READ, + &hKeyIn); + + retCode = RegCreateKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKeyOut, &disp); + + // See if Version Key exists in HKEY_CURRENT_USER - if it does, we have already done the copy + + Vallen = MAX_PATH; + retCode = RegQueryValueEx(hKeyOut, "Version" ,0 , &Type,(UCHAR *)&msg, &Vallen); + + if (retCode != ERROR_SUCCESS) + if (hKeyIn) + CopyReg(hKeyIn, hKeyOut); + + RegCloseKey(hKeyIn); + RegCloseKey(hKeyOut); + } + } + + GetModuleFileName(hInstance,DLLName,256); + + BPQDirectory[0]=0; + + retCode = RegOpenKeyEx (REGTREE, + "SOFTWARE\\G8BPQ\\BPQ32", + 0, + KEY_QUERY_VALUE, + &hKey); + + if (retCode == ERROR_SUCCESS) + { + // Try "BPQ Directory" + + Vallen = MAX_PATH; + retCode = RegQueryValueEx(hKey,"BPQ Directory",0, + &Type,(UCHAR *)&ValfromReg,&Vallen); + + if (retCode == ERROR_SUCCESS) + { + if (strlen(ValfromReg) == 2 && ValfromReg[0] == '"' && ValfromReg[1] == '"') + ValfromReg[0]=0; + } + + if (ValfromReg[0] == 0) + { + // BPQ Directory absent or = "" - try "Config File Location" + + Vallen = MAX_PATH; + + retCode = RegQueryValueEx(hKey,"Config File Location",0, + &Type,(UCHAR *)&ValfromReg,&Vallen); + + if (retCode == ERROR_SUCCESS) + { + if (strlen(ValfromReg) == 2 && ValfromReg[0] == '"' && ValfromReg[1] == '"') + ValfromReg[0]=0; + } + } + + if (ValfromReg[0] == 0) GetCurrentDirectory(MAX_PATH, ValfromReg); + + // Get StartMinimized and MinimizetoTray flags + + Vallen = 4; + retCode = RegQueryValueEx(hKey, "Start Minimized", 0, &Type, (UCHAR *)&StartMinimized, &Vallen); + + Vallen = 4; + retCode = RegQueryValueEx(hKey, "Minimize to Tray", 0, &Type, (UCHAR *)&MinimizetoTray, &Vallen); + + ExpandEnvironmentStrings(ValfromReg, BPQDirectory, MAX_PATH); + + // Also get "BPQ Program Directory" + + ValfromReg[0] = 0; + Vallen = MAX_PATH; + + retCode = RegQueryValueEx(hKey, "BPQ Program Directory",0 , &Type, (UCHAR *)&ValfromReg, &Vallen); + + if (retCode == ERROR_SUCCESS) + ExpandEnvironmentStrings(ValfromReg, BPQProgramDirectory, MAX_PATH); + + // And Log Directory + + ValfromReg[0] = 0; + Vallen = MAX_PATH; + + retCode = RegQueryValueEx(hKey, "Log Directory",0 , &Type, (UCHAR *)&ValfromReg, &Vallen); + + if (retCode == ERROR_SUCCESS) + ExpandEnvironmentStrings(ValfromReg, LogDirectory, MAX_PATH); + + RegCloseKey(hKey); + } + + strcpy(ConfigDirectory, BPQDirectory); + + if (LogDirectory[0] == 0) + strcpy(LogDirectory, BPQDirectory); + + if (BPQProgramDirectory[0] == 0) + strcpy(BPQProgramDirectory, BPQDirectory); + + sprintf(msg,"BPQ32 Ver %s Loaded from: %s by %s\n", VersionString, DLLName, pgm); + WritetoConsole(msg); + OutputDebugString(msg); + FormatTime3(Time, time(NULL)); + sprintf(msg,"Loaded %s\n", Time); + WritetoConsole(msg); + OutputDebugString(msg); + +#pragma warning(push) +#pragma warning(disable : 4996) + +#if _MSC_VER >= 1400 + +#define _winmajor 6 +#define _winminor 0 + +#endif + + i=sprintf(msg,"Windows Ver %d.%d, Using Registry Key %s\n" ,_winmajor, _winminor, REGTREETEXT); + +#pragma warning(pop) + + WritetoConsole(msg); + OutputDebugString(msg); + + i=sprintf(msg,"BPQ32 Using config from: %s\n\n",BPQDirectory); + WritetoConsole(&msg[6]); + msg[i-1]=0; + OutputDebugString(msg); + + // Don't write the Version Key if loaded by regsvr32.exe (Installer is running with Admin rights, + // so will write the wrong tree on ) + + if (_stricmp(pgm, "regsvr32.exe") == 0) + { + Debugprintf("BPQ32 loaded by regsvr32.exe - Version String not written"); + } + else + { + retCode = RegCreateKeyEx(REGTREE, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp); + + sprintf(msg,"%d,%d,%d,%d", Ver[0], Ver[1], Ver[2], Ver[3]); + retCode = RegSetValueEx(hKey, "Version",0, REG_SZ,(BYTE *)msg, strlen(msg) + 1); + + RegCloseKey(hKey); + } + + // Make sure Logs Directory exists + + sprintf(LogDir, "%s/Logs", LogDirectory); + + CreateDirectory(LogDir, NULL); + + return; +} + +HANDLE OpenConfigFile(char *fn) +{ + HANDLE handle; + UCHAR Value[MAX_PATH]; + FILETIME LastWriteTime; + SYSTEMTIME Time; + char Msg[256]; + + + // If no directory, use current + if (BPQDirectory[0] == 0) + { + strcpy(Value,fn); + } + else + { + strcpy(Value,BPQDirectory); + strcat(Value,"\\"); + strcat(Value,fn); + } + + handle = CreateFile(Value, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + GetFileTime(handle, NULL, NULL, &LastWriteTime); + FileTimeToSystemTime(&LastWriteTime, &Time); + + sprintf(Msg,"BPQ32 Config File %s Created %.2d:%.2d %d/%.2d/%.2d\n", Value, + Time.wHour, Time.wMinute, Time.wYear, Time.wMonth, Time.wDay); + + OutputDebugString(Msg); + + return(handle); +} + +#ifdef _WIN64 +int BPQHOSTAPI() +{ + return 0; +} +#endif + + +DllExport int APIENTRY GETBPQAPI() +{ + return (int)BPQHOSTAPI; +} + +//DllExport UINT APIENTRY GETMONDECODE() +//{ +// return (UINT)MONDECODE; +//} + + +DllExport INT APIENTRY BPQAPI(int Fn, char * params) +{ + +/* +; +; BPQ HOST MODE SUPPORT CODE +; +; 22/11/95 +; +; MOVED FROM TNCODE.ASM COS CONITIONALS WERE GETTING TOO COMPLICATED +; (OS2 VERSION HAD UPSET KANT VERISON +; +; +*/ + + +/* + + BPQHOSTPORT: +; +; SPECIAL INTERFACE, MAINLY FOR EXTERNAL HOST MODE SUPPORT PROGS +; +; COMMANDS SUPPORTED ARE +; +; AH = 0 Get node/switch version number and description. On return +; AH='B',AL='P',BH='Q',BL=' ' +; DH = major version number and DL = minor version number. +; +; +; AH = 1 Set application mask to value in DL (or even DX if 16 +; applications are ever to be supported). +; +; Set application flag(s) to value in CL (or CX). +; whether user gets connected/disconnected messages issued +; by the node etc. +; +; +; AH = 2 Send frame in ES:SI (length CX) +; +; +; AH = 3 Receive frame into buffer at ES:DI, length of frame returned +; in CX. BX returns the number of outstanding frames still to +; be received (ie. after this one) or zero if no more frames +; (ie. this is last one). +; +; +; +; AH = 4 Get stream status. Returns: +; +; CX = 0 if stream disconnected or CX = 1 if stream connected +; DX = 0 if no change of state since last read, or DX = 1 if +; the connected/disconnected state has changed since +; last read (ie. delta-stream status). +; +; +; +; AH = 6 Session control. +; +; CX = 0 Conneect - _APPLMASK in DL +; CX = 1 connect +; CX = 2 disconnect +; CX = 3 return user to node +; +; +; AH = 7 Get buffer counts for stream. Returns: +; +; AX = number of status change messages to be received +; BX = number of frames queued for receive +; CX = number of un-acked frames to be sent +; DX = number of buffers left in node +; SI = number of trace frames queued for receive +; +;AH = 8 Port control/information. Called with a stream number +; in AL returns: +; +; AL = Radio port on which channel is connected (or zero) +; AH = SESSION TYPE BITS +; BX = L2 paclen for the radio port +; CX = L2 maxframe for the radio port +; DX = L4 window size (if L4 circuit, or zero) +; ES:DI = CALLSIGN + +;AH = 9 Fetch node/application callsign & alias. AL = application +; number: +; +; 0 = node +; 1 = BBS +; 2 = HOST +; 3 = SYSOP etc. etc. +; +; Returns string with alias & callsign or application name in +; user's buffer pointed to by ES:SI length CX. For example: +; +; "WORCS:G8TIC" or "TICPMS:G8TIC-10". +; +; +; AH = 10 Unproto transmit frame. Data pointed to by ES:SI, of +; length CX, is transmitted as a HDLC frame on the radio +; port (not stream) in AL. +; +; +; AH = 11 Get Trace (RAW Data) Frame into ES:DI, +; Length to CX, Timestamp to AX +; +; +; AH = 12 Update Switch. At the moment only Beacon Text may be updated +; DX = Function +; 1=update BT. ES:SI, Len CX = Text +; 2=kick off nodes broadcast +; +; AH = 13 Allocate/deallocate stream +; If AL=0, return first free stream +; If AL>0, CL=1, Allocate stream. If aleady allocated, +; return CX nonzero, else allocate, and return CX=0 +; If AL>0, CL=2, Release stream +; +; +; AH = 14 Internal Interface for IP Router +; +; Send frame - to NETROM L3 if DL=0 +; to L2 Session if DL<>0 +; +; +; AH = 15 Get interval timer + + +*/ + + + switch(Fn) + { + + case CHECKLOADED: + + params[0]=MAJORVERSION; + params[1]=MINORVERSION; + params[2]=QCOUNT; + + return (1); + } + return 0; +} + +DllExport int APIENTRY InitSwitch() +{ + return (0); +} + +/*DllExport int APIENTRY SwitchTimer() +{ + GetSemaphore((&Semaphore); + + TIMERINTERRUPT(); + + FreeSemaphore(&Semaphore); + + return (0); +} +*/ +DllExport int APIENTRY GetFreeBuffs() +{ +// Returns number of free buffers +// (BPQHOST function 7 (part)). + return (QCOUNT); +} + +DllExport UCHAR * APIENTRY GetNodeCall() +{ + return (&MYNODECALL); +} + + +DllExport UCHAR * APIENTRY GetNodeAlias() +{ + return (&MYALIASTEXT[0]); +} + +DllExport UCHAR * APIENTRY GetBBSCall() +{ + return (UCHAR *)(&APPLCALLTABLE[0].APPLCALL_TEXT); +} + + +DllExport UCHAR * APIENTRY GetBBSAlias() +{ + return (UCHAR *)(&APPLCALLTABLE[0].APPLALIAS_TEXT); +} + +DllExport VOID APIENTRY GetApplCallVB(int Appl, char * ApplCall) +{ + if (Appl < 1 || Appl > NumberofAppls ) return; + + strncpy(ApplCall,(char *)&APPLCALLTABLE[Appl-1].APPLCALL_TEXT, 10); +} + +BOOL UpdateNodesForApp(int Appl); + +DllExport BOOL APIENTRY SetApplCall(int Appl, char * NewCall) +{ + char Call[10]=" "; + int i; + + if (Appl < 1 || Appl > NumberofAppls ) return FALSE; + + i=strlen(NewCall); + + if (i > 10) i=10; + + strncpy(Call,NewCall,i); + + strncpy((char *)&APPLCALLTABLE[Appl-1].APPLCALL_TEXT,Call,10); + + if (!ConvToAX25(Call,APPLCALLTABLE[Appl-1].APPLCALL)) return FALSE; + + UpdateNodesForApp(Appl); + + return TRUE; + +} + +DllExport BOOL APIENTRY SetApplAlias(int Appl, char * NewCall) +{ + char Call[10]=" "; + int i; + + if (Appl < 1 || Appl > NumberofAppls ) return FALSE; + + i=strlen(NewCall); + + if (i > 10) i=10; + + strncpy(Call,NewCall,i); + + strncpy((char *)&APPLCALLTABLE[Appl-1].APPLALIAS_TEXT,Call,10); + + if (!ConvToAX25(Call,APPLCALLTABLE[Appl-1].APPLALIAS)) return FALSE; + + UpdateNodesForApp(Appl); + + return TRUE; + +} + + + +DllExport BOOL APIENTRY SetApplQual(int Appl, int NewQual) +{ + if (Appl < 1 || Appl > NumberofAppls ) return FALSE; + + APPLCALLTABLE[Appl-1].APPLQUAL=NewQual; + + UpdateNodesForApp(Appl); + + return TRUE; + +} + + +BOOL UpdateNodesForApp(int Appl) +{ + int App=Appl-1; + int DestLen = sizeof (struct DEST_LIST); + int n = MAXDESTS; + + struct DEST_LIST * DEST = APPLCALLTABLE[App].NODEPOINTER; + APPLCALLS * APPL=&APPLCALLTABLE[App]; + + if (DEST == NULL) + { + // No dest at the moment. If we have valid call and Qual, create an entry + + if (APPLCALLTABLE[App].APPLQUAL == 0) return FALSE; + + if (APPLCALLTABLE[App].APPLCALL[0] < 41) return FALSE; + + + GetSemaphore(&Semaphore, 5); + + DEST = DESTS; + + while (n--) + { + if (DEST->DEST_CALL[0] == 0) // Spare + break; + } + + if (n == 0) + { + // no dests + + FreeSemaphore(&Semaphore); + return FALSE; + } + + NUMBEROFNODES++; + APPL->NODEPOINTER = DEST; + + memmove (DEST->DEST_CALL,APPL->APPLCALL,13); + + DEST->DEST_STATE=0x80; // SPECIAL ENTRY + + DEST->NRROUTE[0].ROUT_QUALITY = (BYTE)APPL->APPLQUAL; + DEST->NRROUTE[0].ROUT_OBSCOUNT = 255; + + FreeSemaphore(&Semaphore); + + return TRUE; + } + + // We have a destination. If Quality is zero, remove it, else update it + + if (APPLCALLTABLE[App].APPLQUAL == 0) + { + GetSemaphore(&Semaphore, 6); + + REMOVENODE(DEST); // Clear buffers, Remove from Sorted Nodes chain, and zap entry + + APPL->NODEPOINTER=NULL; + + FreeSemaphore(&Semaphore); + return FALSE; + + } + + if (APPLCALLTABLE[App].APPLCALL[0] < 41) return FALSE; + + GetSemaphore(&Semaphore, 7); + + memmove (DEST->DEST_CALL,APPL->APPLCALL,13); + + DEST->DEST_STATE=0x80; // SPECIAL ENTRY + + DEST->NRROUTE[0].ROUT_QUALITY = (BYTE)APPL->APPLQUAL; + DEST->NRROUTE[0].ROUT_OBSCOUNT = 255; + + FreeSemaphore(&Semaphore); + return TRUE; + +} + + +DllExport UCHAR * APIENTRY GetSignOnMsg() +{ + return (&SIGNONMSG[0]); +} + + +DllExport HKEY APIENTRY GetRegistryKey() +{ + return REGTREE; +} + +DllExport char * APIENTRY GetRegistryKeyText() +{ + return REGTREETEXT;; +} + +DllExport UCHAR * APIENTRY GetBPQDirectory() +{ + while (BPQDirectory[0] == 0) + { + Debugprintf("BPQ Directory not set up - waiting"); + Sleep(1000); + } + return (&BPQDirectory[0]); +} + +DllExport UCHAR * APIENTRY GetProgramDirectory() +{ + return (&BPQProgramDirectory[0]); +} + +DllExport UCHAR * APIENTRY GetLogDirectory() +{ + return (&LogDirectory[0]); +} + +// Version for Visual Basic + +DllExport char * APIENTRY CopyBPQDirectory(char * dir) +{ + return (strcpy(dir,BPQDirectory)); +} + +DllExport int APIENTRY GetMsgPerl(int stream, char * msg) +{ + int len,count; + + GetMsg(stream, msg, &len, &count ); + + return len; +} + +int Rig_Command(int Session, char * Command); + +BOOL Rig_CommandInt(int Session, char * Command) +{ + return Rig_Command(Session, Command); +} + +DllExport int APIENTRY BPQSetHandle(int Stream, HWND hWnd) +{ + BPQHOSTVECTOR[Stream-1].HOSTHANDLE=hWnd; + return (0); +} + +#define L4USER 0 + +BPQVECSTRUC * PORTVEC ; + +VOID * InitializeExtDriver(PEXTPORTDATA PORTVEC) +{ + HINSTANCE ExtDriver=0; + char msg[128]; + int err=0; + HKEY hKey=0; + UCHAR Value[MAX_PATH]; + + // If no directory, use current + + if (BPQDirectory[0] == 0) + { + strcpy(Value,PORTVEC->PORT_DLL_NAME); + } + else + { + strcpy(Value,BPQDirectory); + strcat(Value,"\\"); + strcat(Value,PORTVEC->PORT_DLL_NAME); + } + + // Several Drivers are now built into bpq32.dll + + _strupr(Value); + + if (strstr(Value, "BPQVKISS")) + return VCOMExtInit; + + if (strstr(Value, "BPQAXIP")) + return AXIPExtInit; + + if (strstr(Value, "BPQETHER")) + return ETHERExtInit; + + if (strstr(Value, "BPQTOAGW")) + return AGWExtInit; + + if (strstr(Value, "AEAPACTOR")) + return AEAExtInit; + + if (strstr(Value, "HALDRIVER")) + return HALExtInit; + + if (strstr(Value, "KAMPACTOR")) + return KAMExtInit; + + if (strstr(Value, "SCSPACTOR")) + return SCSExtInit; + + if (strstr(Value, "WINMOR")) + return WinmorExtInit; + + if (strstr(Value, "V4")) + return V4ExtInit; + + if (strstr(Value, "TELNET")) + return TelnetExtInit; + +// if (strstr(Value, "SOUNDMODEM")) +// return SoundModemExtInit; + + if (strstr(Value, "SCSTRACKER")) + return TrackerExtInit; + + if (strstr(Value, "TRKMULTI")) + return TrackerMExtInit; + + if (strstr(Value, "UZ7HO")) + return UZ7HOExtInit; + + if (strstr(Value, "MULTIPSK")) + return MPSKExtInit; + + if (strstr(Value, "FLDIGI")) + return FLDigiExtInit; + + if (strstr(Value, "UIARQ")) + return UIARQExtInit; + +// if (strstr(Value, "BAYCOM")) +// return (UINT) BaycomExtInit; + + if (strstr(Value, "VARA")) + return VARAExtInit; + + if (strstr(Value, "ARDOP")) + return ARDOPExtInit; + + if (strstr(Value, "SERIAL")) + return SerialExtInit; + + if (strstr(Value, "KISSHF")) + return KISSHFExtInit; + + if (strstr(Value, "WINRPR")) + return WinRPRExtInit; + + if (strstr(Value, "HSMODEM")) + return HSMODEMExtInit; + + if (strstr(Value, "FREEDATA")) + return FreeDataExtInit; + + if (strstr(Value, "6PACK")) + return SIXPACKExtInit; + + ExtDriver = LoadLibrary(Value); + + if (ExtDriver == NULL) + { + err=GetLastError(); + + sprintf(msg,"Error loading Driver %s - Error code %d", + PORTVEC->PORT_DLL_NAME,err); + + MessageBox(NULL,msg,"BPQ32",MB_ICONSTOP); + + return(0); + } + + PORTVEC->DLLhandle=ExtDriver; + + return (GetProcAddress(ExtDriver,"_ExtInit@4")); + +} + +/* +_DATABASE LABEL BYTE + +FILLER DB 14 DUP (0) ; PROTECTION AGENST BUFFER PROBLEMS! + DB MAJORVERSION,MINORVERSION +_NEIGHBOURS DD 0 + DW TYPE ROUTE +_MAXNEIGHBOURS DW 20 ; MAX ADJACENT NODES + +_DESTS DD 0 ; NODE LIST + DW TYPE DEST_LIST +MAXDESTS DW 100 ; MAX NODES IN SYSTEM +*/ + + +DllExport int APIENTRY GetAttachedProcesses() +{ + return (AttachedProcesses); +} + +DllExport int * APIENTRY GetAttachedProcessList() +{ + return (&AttachedPIDList[0]); +} + +DllExport int * APIENTRY SaveNodesSupport() +{ + return (&DATABASESTART); +} + +// +// Internal BPQNODES support +// + +#define UCHAR unsigned char + +/* +ROUTE ADD G1HTL-1 2 200 0 0 0 +ROUTE ADD G4IRX-3 2 200 0 0 0 +NODE ADD MAPPLY:G1HTL-1 G1HTL-1 2 200 G4IRX-3 2 98 +NODE ADD NOT:GB7NOT G1HTL-1 2 199 G4IRX-3 2 98 + +*/ + +struct DEST_LIST * Dests; +struct ROUTE * Routes; + +int MaxNodes; +int MaxRoutes; +int NodeLen; +int RouteLen; + +int count; +int cursor; + +int len,i; + +ULONG cnt; +char Normcall[10]; +char Portcall[10]; +char Alias[7]; + +char line[100]; + +HANDLE handle; + +int APIENTRY Restart() +{ + int i, Count = AttachedProcesses; + HANDLE hProc; + DWORD PID; + + for (i = 0; i < Count; i++) + { + PID = AttachedPIDList[i]; + + // Kill Timer Owner last + + if (TimerInst != PID) + { + hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID); + + if (hProc) + { + TerminateProcess(hProc, 0); + CloseHandle(hProc); + } + } + } + + hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, TimerInst); + + if (hProc) + { + TerminateProcess(hProc, 0); + CloseHandle(hProc); + } + + + return 0; +} + +int APIENTRY Reboot() +{ + // Run shutdown -r -f + + STARTUPINFO SInfo; + PROCESS_INFORMATION PInfo; + char Cmd[] = "shutdown -r -f"; + + SInfo.cb=sizeof(SInfo); + SInfo.lpReserved=NULL; + SInfo.lpDesktop=NULL; + SInfo.lpTitle=NULL; + SInfo.dwFlags=0; + SInfo.cbReserved2=0; + SInfo.lpReserved2=NULL; + + return CreateProcess(NULL, Cmd, NULL, NULL, FALSE,0 ,NULL ,NULL, &SInfo, &PInfo); +} +/* +int APIENTRY Reconfig() +{ + if (!ProcessConfig()) + { + return (0); + } + SaveNodes(); + WritetoConsole("Nodes Saved\n"); + ReconfigFlag=TRUE; + WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n"); + return 1; +} +*/ +// Code to support minimizing all BPQ Apps to a single Tray ICON + +// As we can't minimize the console window to the tray, I'll use an ordinary +// window instead. This also gives me somewhere to post the messages to + + +char AppName[] = "BPQ32"; +char Title[80] = "BPQ32.dll Console"; + +int NewLine(); + +char FrameClassName[] = TEXT("MdiFrame"); + +HWND ClientWnd; //This stores the MDI client area window handle + +LOGFONT LFTTYFONT ; + +HFONT hFont ; + +HMENU hPopMenu, hWndMenu; +HMENU hMainFrameMenu = NULL; +HMENU hBaseMenu = NULL; +HMENU hConsMenu = NULL; +HMENU hTermMenu = NULL; +HMENU hMonMenu = NULL; +HMENU hTermActMenu, hTermCfgMenu, hTermEdtMenu, hTermHlpMenu; +HMENU hMonActMenu, hMonCfgMenu, hMonEdtMenu, hMonHlpMenu; + + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +DllExport int APIENTRY DeleteTrayMenuItem(HWND hWnd); + +#define BPQMonitorAvail 1 +#define BPQDataAvail 2 +#define BPQStateChange 4 + +VOID GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value); +SOCKET OpenWL2KHTTPSock(); +SendHTTPRequest(SOCKET sock, char * Request, char * Params, int Len, char * Return); + +BOOL GetWL2KSYSOPInfo(char * Call, char * _REPLYBUFFER); +BOOL UpdateWL2KSYSOPInfo(char * Call, char * SQL); + + +static INT_PTR CALLBACK ConfigWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + char _REPLYBUFFER[1000] = ""; + char Value[1000]; + + if (GetWL2KSYSOPInfo(WL2KCall, _REPLYBUFFER)) + { +// if (strstr(_REPLYBUFFER, "\"ErrorMessage\":") == 0) + + GetJSONValue(_REPLYBUFFER, "\"SysopName\":", Value); + SetDlgItemText(hDlg, NAME, Value); + + GetJSONValue(_REPLYBUFFER, "\"GridSquare\":", Value); + SetDlgItemText(hDlg, IDC_Locator, Value); + + GetJSONValue(_REPLYBUFFER, "\"StreetAddress1\":", Value); + SetDlgItemText(hDlg, ADDR1, Value); + + GetJSONValue(_REPLYBUFFER, "\"StreetAddress2\":", Value); + SetDlgItemText(hDlg, ADDR2, Value); + + GetJSONValue(_REPLYBUFFER, "\"City\":", Value); + SetDlgItemText(hDlg, CITY, Value); + + GetJSONValue(_REPLYBUFFER, "\"State\":", Value); + SetDlgItemText(hDlg, STATE, Value); + + GetJSONValue(_REPLYBUFFER, "\"Country\":", Value); + SetDlgItemText(hDlg, COUNTRY, Value); + + GetJSONValue(_REPLYBUFFER, "\"PostalCode\":", Value); + SetDlgItemText(hDlg, POSTCODE, Value); + + GetJSONValue(_REPLYBUFFER, "\"Email\":", Value); + SetDlgItemText(hDlg, EMAIL, Value); + + GetJSONValue(_REPLYBUFFER, "\"Website\":", Value); + SetDlgItemText(hDlg, WEBSITE, Value); + + GetJSONValue(_REPLYBUFFER, "\"Phones\":", Value); + SetDlgItemText(hDlg, PHONE, Value); + + GetJSONValue(_REPLYBUFFER, "\"Comments\":", Value); + SetDlgItemText(hDlg, ADDITIONALDATA, Value); + + } + + return (INT_PTR)TRUE; + } + case WM_COMMAND: + + switch(LOWORD(wParam)) + { + + case ID_SAVE: + { + char Name[100]; + char PasswordText[100]; + char LocatorText[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]; + + SOCKET sock; + + int Len; + char Message[2048]; + char Reply[2048] = ""; + + + GetDlgItemText(hDlg, NAME, Name, 99); + GetDlgItemText(hDlg, IDC_Password, PasswordText, 99); + GetDlgItemText(hDlg, IDC_Locator, LocatorText, 99); + GetDlgItemText(hDlg, ADDR1, Addr1, 99); + GetDlgItemText(hDlg, ADDR2, Addr2, 99); + GetDlgItemText(hDlg, CITY, City, 99); + GetDlgItemText(hDlg, STATE, State, 99); + GetDlgItemText(hDlg, COUNTRY, Country, 99); + GetDlgItemText(hDlg, POSTCODE, PostCode, 99); + GetDlgItemText(hDlg, EMAIL, Email, 99); + GetDlgItemText(hDlg, WEBSITE, Website, 99); + GetDlgItemText(hDlg, PHONE, Phone, 99); + GetDlgItemText(hDlg, ADDITIONALDATA, Data, 99); + + +//{"Callsign":"String","GridSquare":"String","SysopName":"String", +//"StreetAddress1":"String","StreetAddress2":"String","City":"String", +//"State":"String","Country":"String","PostalCode":"String","Email":"String", +//"Phones":"String","Website":"String","Comments":"String"} + + Len = sprintf(Message, + "\"Callsign\":\"%s\"," + "\"Password\":\"%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, PasswordText, LocatorText, Name, Addr1, Addr2, City, State, Country, PostCode, Email, Phone, Website, Data); + + Debugprintf("Sending %s", Message); + + sock = OpenWL2KHTTPSock(); + + if (sock) + { + char * ptr; + + SendHTTPRequest(sock, + "/sysop/add", Message, Len, Reply); + + ptr = strstr(Reply, "\"ErrorCode\":"); + + if (ptr) + { + ptr = strstr(ptr, "Message"); + if (ptr) + { + ptr += 10; + strlop(ptr, '"'); + MessageBox(NULL ,ptr, "Error", MB_OK); + } + } + else + MessageBox(NULL, "Sysop Record Updated", "BPQ32", MB_OK); + + } + closesocket(sock); + } + + case ID_CANCEL: + { + EndDialog(hDlg, LOWORD(wParam)); + return (INT_PTR)TRUE; + } + break; + } + } + return (INT_PTR)FALSE; +} + + + +LRESULT CALLBACK UIWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +VOID WINAPI OnTabbedDialogInit(HWND hDlg); + +LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + POINT pos; + BOOL ret; + + CLIENTCREATESTRUCT MDIClientCreateStruct; // Structure to be used for MDI client area + //HWND m_hwndSystemInformation = 0; + + if (message == BPQMsg) + { + if (lParam & BPQDataAvail) + DoReceivedData(wParam); + + if (lParam & BPQMonitorAvail) + DoMonData(wParam); + + if (lParam & BPQStateChange) + DoStateChange(wParam); + + return (0); + } + + switch (message) + { + case MY_TRAY_ICON_MESSAGE: + + switch(lParam) + { + case WM_RBUTTONUP: + case WM_LBUTTONUP: + + GetCursorPos(&pos); + + // SetForegroundWindow(FrameWnd); + + TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, FrameWnd, 0); + return 0; + } + + break; + + case WM_CTLCOLORDLG: + return (LONG)bgBrush; + + case WM_SIZING: + case WM_SIZE: + + SendMessage(ClientWnd, WM_MDIICONARRANGE, 0 ,0); + break; + + case WM_NCCREATE: + + ret = DefFrameProc(hWnd, ClientWnd, message, wParam, lParam); + return TRUE; + + case WM_CREATE: + + // On creation of main frame, create the MDI client area + + MDIClientCreateStruct.hWindowMenu = NULL; + MDIClientCreateStruct.idFirstChild = IDM_FIRSTCHILD; + + ClientWnd = CreateWindow(TEXT("MDICLIENT"), // predefined value for MDI client area + NULL, // no caption required + WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE, + 0, // No need to give any x/y or height/width since this client + // will just be used to get client windows created, effectively + // in the main window we will be seeing the mainframe window client area itself. + 0, + 0, + 0, + hWnd, + NULL, + hInstance, + (void *) &MDIClientCreateStruct); + + + return 0; + + case WM_COMMAND: + + wmId = LOWORD(wParam); // Remember, these are... + wmEvent = HIWORD(wParam); // ...different for Win32! + + if (wmId >= TRAYBASEID && wmId < (TRAYBASEID + 100)) + { + handle=hWndArray[wmId-TRAYBASEID]; + + if (handle == FrameWnd) + ShowWindow(handle, SW_NORMAL); + + if (handle == FrameWnd && FrameMaximized == TRUE) + PostMessage(handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0); + else + PostMessage(handle, WM_SYSCOMMAND, SC_RESTORE, 0); + + SetForegroundWindow(handle); + return 0; + } + + switch(wmId) + { + struct ConsoleInfo * Cinfo = NULL; + + case ID_NEWWINDOW: + Cinfo = CreateChildWindow(0, FALSE); + if (Cinfo) + SendMessage(ClientWnd, WM_MDIACTIVATE, (WPARAM)Cinfo->hConsole, 0); + break; + + case ID_WINDOWS_CASCADE: + SendMessage(ClientWnd, WM_MDICASCADE, 0, 0); + return 0; + + case ID_WINDOWS_TILE: + SendMessage(ClientWnd, WM_MDITILE , MDITILE_HORIZONTAL, 0); + return 0; + + case BPQCLOSEALL: + CloseAllPrograms(); + // SendMessage(ClientWnd, WM_MDIICONARRANGE, 0 ,0); + + return 0; + + case BPQUICONFIG: + { + int err, i=0; + char Title[80]; + WNDCLASS wc; + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = UIWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = DLGWINDOWEXTRA; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON) ); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = bgBrush; + + wc.lpszMenuName = NULL; + wc.lpszClassName = UIClassName; + + RegisterClass(&wc); + + UIhWnd = CreateDialog(hInstance, UIClassName, 0, NULL); + + if (!UIhWnd) + { + err=GetLastError(); + return FALSE; + } + + wsprintf(Title,"BPQ32 Beacon Configuration"); + MySetWindowText(UIhWnd, Title); + ShowWindow(UIhWnd, SW_NORMAL); + + OnTabbedDialogInit(UIhWnd); // Set up pages + + // UpdateWindow(UIhWnd); + return 0; + } + + + case IDD_WL2KSYSOP: + + if (WL2KCall[0] == 0) + { + MessageBox(NULL,"WL2K Reporting is not configured","BPQ32", MB_OK); + break; + } + + DialogBox(hInstance, MAKEINTRESOURCE(IDD_WL2KSYSOP), hWnd, ConfigWndProc); + break; + + + // Handle MDI Window commands + + default: + { + if(wmId >= IDM_FIRSTCHILD) + { + DefFrameProc(hWnd, ClientWnd, message, wParam, lParam); + } + else + { + HWND hChild = (HWND)SendMessage(ClientWnd, WM_MDIGETACTIVE,0,0); + + if(hChild) + SendMessage(hChild, WM_COMMAND, wParam, lParam); + } + } + } + + break; + + case WM_INITMENUPOPUP: + { + HWND hChild = (HWND)SendMessage(ClientWnd, WM_MDIGETACTIVE,0,0); + + if(hChild) + SendMessage(hChild, WM_INITMENUPOPUP, wParam, lParam); + } + + case WM_SYSCOMMAND: + + wmId = LOWORD(wParam); // Remember, these are... + wmEvent = HIWORD(wParam); // ...different for Win32! + + switch (wmId) + { + case SC_MAXIMIZE: + + FrameMaximized = TRUE; + break; + + case SC_RESTORE: + + FrameMaximized = FALSE; + break; + + case SC_MINIMIZE: + + if (MinimizetoTray) + { + ShowWindow(hWnd, SW_HIDE); + return TRUE; + } + } + + return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam)); + + case WM_CLOSE: + + PostQuitMessage(0); + + if (MinimizetoTray) + DeleteTrayMenuItem(hWnd); + + break; + + default: + return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam)); + + } + return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam)); +} + +int OffsetH, OffsetW; + +int SetupConsoleWindow() +{ + WNDCLASS wc; + int i; + int retCode, Type, Vallen; + HKEY hKey=0; + char Size[80]; + WNDCLASSEX wndclassMainFrame; + RECT CRect; + + retCode = RegOpenKeyEx (REGTREE, + "SOFTWARE\\G8BPQ\\BPQ32", + 0, + KEY_QUERY_VALUE, + &hKey); + + if (retCode == ERROR_SUCCESS) + { + Vallen=80; + + retCode = RegQueryValueEx(hKey,"FrameWindowSize",0, + (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen); + + if (retCode == ERROR_SUCCESS) + sscanf(Size,"%d,%d,%d,%d",&FRect.left,&FRect.right,&FRect.top,&FRect.bottom); + + if (FRect.top < - 500 || FRect.left < - 500) + { + FRect.left = 0; + FRect.top = 0; + FRect.right = 600; + FRect.bottom = 400; + } + + + Vallen=80; + retCode = RegQueryValueEx(hKey,"WindowSize",0, + (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen); + + if (retCode == ERROR_SUCCESS) + sscanf(Size,"%d,%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom, &ConsoleMinimized); + + if (Rect.top < - 500 || Rect.left < - 500) + { + Rect.left = 0; + Rect.top = 0; + Rect.right = 600; + Rect.bottom = 400; + } + + Vallen=80; + + retCode = RegQueryValueEx(hKey,"StatusWindowSize",0, + (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen); + + if (retCode == ERROR_SUCCESS) + sscanf(Size, "%d,%d,%d,%d,%d", &StatusRect.left, &StatusRect.right, + &StatusRect.top, &StatusRect.bottom, &StatusMinimized); + + if (StatusRect.top < - 500 || StatusRect.left < - 500) + { + StatusRect.left = 0; + StatusRect.top = 0; + StatusRect.right = 850; + StatusRect.bottom = 500; + } + + + // Get StartMinimized and MinimizetoTray flags + + Vallen = 4; + retCode = RegQueryValueEx(hKey, "Start Minimized", 0, &Type, (UCHAR *)&StartMinimized, &Vallen); + + Vallen = 4; + retCode = RegQueryValueEx(hKey, "Minimize to Tray", 0, &Type, (UCHAR *)&MinimizetoTray, &Vallen); + } + + wndclassMainFrame.cbSize = sizeof(WNDCLASSEX); + wndclassMainFrame.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE; + wndclassMainFrame.lpfnWndProc = FrameWndProc; + wndclassMainFrame.cbClsExtra = 0; + wndclassMainFrame.cbWndExtra = 0; + wndclassMainFrame.hInstance = hInstance; + wndclassMainFrame.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON)); + wndclassMainFrame.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclassMainFrame.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH); + wndclassMainFrame.lpszMenuName = NULL; + wndclassMainFrame.lpszClassName = FrameClassName; + wndclassMainFrame.hIconSm = NULL; + + if(!RegisterClassEx(&wndclassMainFrame)) + { + return 0; + } + + pindex = 0; + PartLine = FALSE; + + bgBrush = CreateSolidBrush(BGCOLOUR); + +// hMainFrameMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME_MENU)); + + hBaseMenu = LoadMenu(hInstance, MAKEINTRESOURCE(CONS_MENU)); + hConsMenu = GetSubMenu(hBaseMenu, 1); + hWndMenu = GetSubMenu(hBaseMenu, 0); + + hTermMenu = LoadMenu(hInstance, MAKEINTRESOURCE(TERM_MENU)); + hTermActMenu = GetSubMenu(hTermMenu, 1); + hTermCfgMenu = GetSubMenu(hTermMenu, 2); + hTermEdtMenu = GetSubMenu(hTermMenu, 3); + hTermHlpMenu = GetSubMenu(hTermMenu, 4); + + hMonMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MON_MENU)); + hMonCfgMenu = GetSubMenu(hMonMenu, 1); + hMonEdtMenu = GetSubMenu(hMonMenu, 2); + hMonHlpMenu = GetSubMenu(hMonMenu, 3); + + hMainFrameMenu = CreateMenu(); + AppendMenu(hMainFrameMenu, MF_STRING + MF_POPUP, (UINT)hWndMenu, "Window"); + + //Create the main MDI frame window + + ClientWnd = NULL; + + FrameWnd = CreateWindow(FrameClassName, + "BPQ32 Console", + WS_OVERLAPPEDWINDOW |WS_CLIPCHILDREN, + FRect.left, + FRect.top, + FRect.right - FRect.left, + FRect.bottom - FRect.top, + NULL, // handle to parent window + hMainFrameMenu, // handle to menu + hInstance, // handle to the instance of module + NULL); // Long pointer to a value to be passed to the window through the + // CREATESTRUCT structure passed in the lParam parameter the WM_CREATE message + + + // Get Client Params + + if (FrameWnd == 0) + { + Debugprintf("SetupConsoleWindow Create Frame failed %d", GetLastError()); + return 0; + } + + ShowWindow(FrameWnd, SW_RESTORE); + + + GetWindowRect(FrameWnd, &FRect); + OffsetH = FRect.bottom - FRect.top; + OffsetW = FRect.right - FRect.left; + GetClientRect(FrameWnd, &CRect); + OffsetH -= CRect.bottom; + OffsetW -= CRect.right; + OffsetH -= 4; + + // Create Console Window + + wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE; + wc.lpfnWndProc = (WNDPROC)WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = DLGWINDOWEXTRA; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON)); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = 0; + wc.lpszClassName = ClassName; + + i=RegisterClass(&wc); + + sprintf (Title, "BPQ32.dll Console Version %s", VersionString); + + hConsWnd = CreateMDIWindow(ClassName, "Console", 0, + 0,0,0,0, ClientWnd, hInstance, 1234); + + i = GetLastError(); + + if (!hConsWnd) { + return (FALSE); + } + + wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE; + wc.lpfnWndProc = (WNDPROC)StatusWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = DLGWINDOWEXTRA; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON)); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = 0; + wc.lpszClassName = "Status"; + + i=RegisterClass(&wc); + + if (StatusRect.top < OffsetH) // Make sure not off top of MDI frame + { + int Error = OffsetH - StatusRect.top; + StatusRect.top += Error; + StatusRect.bottom += Error; + } + + StatusWnd = CreateMDIWindow("Status", "Stream Status", 0, + StatusRect.left, StatusRect.top, StatusRect.right - StatusRect.left, + StatusRect.bottom - StatusRect.top, ClientWnd, hInstance, 1234); + + SetTimer(StatusWnd, 1, 1000, NULL); + + hPopMenu = GetSubMenu(hBaseMenu, 1) ; + + if (MinimizetoTray) + CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_CHECKED); + else + CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_UNCHECKED); + + if (StartMinimized) + CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_CHECKED); + else + CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_UNCHECKED); + + DrawMenuBar(hConsWnd); + + // setup default font information + + LFTTYFONT.lfHeight = 12; + LFTTYFONT.lfWidth = 8 ; + LFTTYFONT.lfEscapement = 0 ; + LFTTYFONT.lfOrientation = 0 ; + LFTTYFONT.lfWeight = 0 ; + LFTTYFONT.lfItalic = 0 ; + LFTTYFONT.lfUnderline = 0 ; + LFTTYFONT.lfStrikeOut = 0 ; + LFTTYFONT.lfCharSet = 0; + LFTTYFONT.lfOutPrecision = OUT_DEFAULT_PRECIS ; + LFTTYFONT.lfClipPrecision = CLIP_DEFAULT_PRECIS ; + LFTTYFONT.lfQuality = DEFAULT_QUALITY ; + LFTTYFONT.lfPitchAndFamily = FIXED_PITCH; + lstrcpy(LFTTYFONT.lfFaceName, "FIXEDSYS" ) ; + + hFont = CreateFontIndirect(&LFTTYFONT) ; + + SetWindowText(hConsWnd,Title); + + if (Rect.right < 100 || Rect.bottom < 100) + { + GetWindowRect(hConsWnd, &Rect); + } + + if (Rect.top < OffsetH) // Make sure not off top of MDI frame + { + int Error = OffsetH - Rect.top; + Rect.top += Error; + Rect.bottom += Error; + } + + + MoveWindow(hConsWnd, Rect.left - (OffsetW /2), Rect.top - OffsetH, Rect.right-Rect.left, Rect.bottom-Rect.top, TRUE); + + MoveWindow(StatusWnd, StatusRect.left - (OffsetW /2), StatusRect.top - OffsetH, + StatusRect.right-StatusRect.left, StatusRect.bottom-StatusRect.top, TRUE); + + hWndCons = CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", "", + WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT | + LBS_DISABLENOSCROLL | LBS_NOSEL | WS_VSCROLL | WS_HSCROLL, + Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top, + hConsWnd, NULL, hInstance, NULL); + +// SendMessage(hWndCons, WM_SETFONT, hFont, 0); + + SendMessage(hWndCons, LB_SETHORIZONTALEXTENT , 1000, 0); + + if (ConsoleMinimized) + ShowWindow(hConsWnd, SW_SHOWMINIMIZED); + else + ShowWindow(hConsWnd, SW_RESTORE); + + if (StatusMinimized) + ShowWindow(StatusWnd, SW_SHOWMINIMIZED); + else + ShowWindow(StatusWnd, SW_RESTORE); + + ShowWindow(FrameWnd, SW_RESTORE); + + + LoadLibrary("riched20.dll"); + + if (StartMinimized) + if (MinimizetoTray) + ShowWindow(FrameWnd, SW_HIDE); + else + ShowWindow(FrameWnd, SW_SHOWMINIMIZED); + else + ShowWindow(FrameWnd, SW_RESTORE); + + CreateMonitorWindow(Size); + + return 0; +} + +DllExport int APIENTRY SetupTrayIcon() +{ + if (MinimizetoTray == 0) + return 0; + + trayMenu = CreatePopupMenu(); + + for( i = 0; i < 100; ++i ) + { + if (strcmp(PopupText[i],"BPQ32 Console") == 0) + { + hWndArray[i] = FrameWnd; + goto doneit; + } + } + + for( i = 0; i < 100; ++i ) + { + if (hWndArray[i] == 0) + { + hWndArray[i] = FrameWnd; + strcpy(PopupText[i],"BPQ32 Console"); + break; + } + } +doneit: + + for( i = 0; i < 100; ++i ) + { + if (hWndArray[i] != 0) + AppendMenu(trayMenu,MF_STRING,TRAYBASEID+i,PopupText[i]); + } + + // Set up Tray ICON + + ZeroMemory(&niData,sizeof(NOTIFYICONDATA)); + + niData.cbSize = sizeof(NOTIFYICONDATA); + + // the ID number can be any UINT you choose and will + // be used to identify your icon in later calls to + // Shell_NotifyIcon + + niData.uID = TRAY_ICON_ID; + + // state which structure members are valid + // here you can also choose the style of tooltip + // window if any - specifying a balloon window: + // NIF_INFO is a little more complicated + + strcpy(niData.szTip,"BPQ32 Windows"); + + niData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP; + + // load the icon note: you should destroy the icon + // after the call to Shell_NotifyIcon + + niData.hIcon = + + //LoadIcon(NULL, IDI_APPLICATION); + + (HICON)LoadImage( hInstance, + MAKEINTRESOURCE(BPQICON), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + + // set the window you want to receive event messages + + niData.hWnd = FrameWnd; + + // set the message to send + // note: the message value should be in the + // range of WM_APP through 0xBFFF + + niData.uCallbackMessage = MY_TRAY_ICON_MESSAGE; + + // Call Shell_NotifyIcon. NIM_ADD adds a new tray icon + + if (Shell_NotifyIcon(NIM_ADD,&niData)) + Debugprintf("BPQ32 Create Tray Icon Ok"); +// else +// Debugprintf("BPQ32 Create Tray Icon failed %d", GetLastError()); + + return 0; +} + +VOID SaveConfig() +{ + HKEY hKey=0; + int retCode, disp; + + retCode = RegCreateKeyEx(REGTREE, + "SOFTWARE\\G8BPQ\\BPQ32", + 0, // Reserved + 0, // Class + 0, // Options + KEY_ALL_ACCESS, + NULL, // Security Attrs + &hKey, + &disp); + + if (retCode == ERROR_SUCCESS) + { + retCode = RegSetValueEx(hKey, "Start Minimized", 0, REG_DWORD, (UCHAR *)&StartMinimized, 4); + retCode = RegSetValueEx(hKey, "Minimize to Tray", 0, REG_DWORD, (UCHAR *)&MinimizetoTray, 4); + } +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + POINT pos; + HWND handle; + RECT cRect; + + switch (message) + { + case WM_MDIACTIVATE: + + // Set the system info menu when getting activated + + if (lParam == (LPARAM) hWnd) + { + // Activate + + // GetSubMenu function should retrieve a handle to the drop-down menu or submenu. + + RemoveMenu(hBaseMenu, 1, MF_BYPOSITION); + AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)hConsMenu, "Actions"); + SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hBaseMenu, (LPARAM) hWndMenu); + } + else + { + // Deactivate + + SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL); + } + + DrawMenuBar(FrameWnd); + + return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam); + + case MY_TRAY_ICON_MESSAGE: + + switch(lParam) + { + case WM_RBUTTONUP: + case WM_LBUTTONUP: + + GetCursorPos(&pos); + + SetForegroundWindow(hWnd); + + TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, hWnd, 0); + return 0; + } + + break; + + case WM_CTLCOLORDLG: + return (LONG)bgBrush; + + case WM_COMMAND: + + wmId = LOWORD(wParam); // Remember, these are... + wmEvent = HIWORD(wParam); // ...different for Win32! + + if (wmId == IDC_ENIGATE) + { + int retCode, disp; + HKEY hKey=0; + + IGateEnabled = IsDlgButtonChecked(hWnd, IDC_ENIGATE); + + if (IGateEnabled) + ISDelayTimer = 60; + + retCode = RegCreateKeyEx(REGTREE, + "SOFTWARE\\G8BPQ\\BPQ32", + 0, // Reserved + 0, // Class + 0, // Options + KEY_ALL_ACCESS, + NULL, // Security Attrs + &hKey, + &disp); + + if (retCode == ERROR_SUCCESS) + { + retCode = RegSetValueEx(hKey,"IGateEnabled", 0 , REG_DWORD,(BYTE *)&IGateEnabled, 4); + RegCloseKey(hKey); + } + + return 0; + } + + if (wmId == BPQSAVENODES) + { + SaveNodes(); + WritetoConsole("Nodes Saved\n"); + return 0; + } + if (wmId == BPQCLEARRECONFIG) + { + if (!ProcessConfig()) + { + MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK); + return (0); + } + + ClearNodes(); + WritetoConsole("Nodes file Cleared\n"); + ReconfigFlag=TRUE; + WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n"); + return 0; + } + if (wmId == BPQRECONFIG) + { + if (!ProcessConfig()) + { + MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK); + return (0); + } + SaveNodes(); + WritetoConsole("Nodes Saved\n"); + ReconfigFlag=TRUE; + WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n"); + return 0; + } + + if (wmId == SCANRECONFIG) + { + if (!ProcessConfig()) + { + MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK); + return (0); + } + + RigReconfigFlag = TRUE; + WritetoConsole("Rigcontrol Reconfig requested ... Waiting for Timer Poll\n"); + return 0; + } + + if (wmId == APRSRECONFIG) + { + if (!ProcessConfig()) + { + MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK); + return (0); + } + + APRSReconfigFlag=TRUE; + WritetoConsole("APRS Reconfig requested ... Waiting for Timer Poll\n"); + return 0; + } + if (wmId == BPQDUMP) + { + DumpSystem(); + return 0; + } + + if (wmId == BPQCLOSEALL) + { + CloseAllPrograms(); + return 0; + } + + if (wmId == BPQUICONFIG) + { + int err, i=0; + char Title[80]; + WNDCLASS wc; + + wc.style = CS_HREDRAW | CS_VREDRAW; + wc.lpfnWndProc = UIWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = DLGWINDOWEXTRA; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON) ); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = bgBrush; + + wc.lpszMenuName = NULL; + wc.lpszClassName = UIClassName; + + RegisterClass(&wc); + + UIhWnd = CreateDialog(hInstance, UIClassName,0,NULL); + + if (!UIhWnd) + { + err=GetLastError(); + return FALSE; + } + + wsprintf(Title,"BPQ32 Beacon Utility Version"); + MySetWindowText(UIhWnd, Title); + return 0; + } + + if (wmId == BPQSAVEREG) + { + CreateRegBackup(); + return 0; + } + + if (wmId == BPQMINTOTRAY) + { + MinimizetoTray = !MinimizetoTray; + + if (MinimizetoTray) + CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_CHECKED); + else + CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_UNCHECKED); + + SaveConfig(); + return 0; + } + + if (wmId == BPQSTARTMIN) + { + StartMinimized = !StartMinimized; + + if (StartMinimized) + CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_CHECKED); + else + CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_UNCHECKED); + + SaveConfig(); + return 0; + } + + if (wmId >= TRAYBASEID && wmId < (TRAYBASEID + 100)) + { + handle=hWndArray[wmId-TRAYBASEID]; + + if (handle == FrameWnd && FrameMaximized == TRUE) + PostMessage(handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0); + else + PostMessage(handle, WM_SYSCOMMAND, SC_RESTORE, 0); + + SetForegroundWindow(handle); + return 0; + } + + case WM_SYSCOMMAND: + + wmId = LOWORD(wParam); // Remember, these are... + wmEvent = HIWORD(wParam); // ...different for Win32! + + switch (wmId) + { + case SC_MINIMIZE: + + ConsoleMinimized = TRUE; + break; + + case SC_RESTORE: + + ConsoleMinimized = FALSE; + SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0); + + break; + } + + return DefMDIChildProc(hWnd, message, wParam, lParam); + + + case WM_SIZE: + + GetClientRect(hWnd, &cRect); + + MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE); + + if (APRSActive) + MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE); + else + MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE); + +// InvalidateRect(hWnd, NULL, TRUE); + break; + +/* + case WM_PAINT: + + hdc = BeginPaint (hWnd, &ps); + + hOldFont = SelectObject( hdc, hFont) ; + + for (i=0; i 300) + len = 300; + + memcpy(&buffptr[2], buff, len + 1); + + C_Q_ADD(&WritetoConsoleQ, buffptr); + + return 0; +} + +int WritetoConsoleSupport(char * buff) +{ + + int len=strlen(buff); + char Temp[2000]= ""; + char * ptr; + + if (PartLine) + { + SendMessage(hWndCons, LB_GETTEXT, pindex, (LPARAM)(LPCTSTR) Temp); + SendMessage(hWndCons, LB_DELETESTRING, pindex, 0); + PartLine = FALSE; + } + + if ((strlen(Temp) + strlen(buff)) > 1990) + Temp[0] = 0; // Should never have anything this long + + strcat(Temp, buff); + + ptr = strchr(Temp, '\n'); + + if (ptr) + *ptr = 0; + else + PartLine = TRUE; + + pindex=SendMessage(hWndCons, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR) Temp); + return 0; + } + +DllExport VOID APIENTRY BPQOutputDebugString(char * String) +{ + OutputDebugString(String); + return; + } + +HANDLE handle; +char fn[]="BPQDUMP"; +ULONG cnt; +char * stack; +//char screen[1920]; +//COORD ReadCoord; + +#define DATABYTES 400000 + +extern UCHAR DATAAREA[]; + +DllExport int APIENTRY DumpSystem() +{ + char fn[200]; + char Msg[250]; + + sprintf(fn,"%s\\BPQDUMP",BPQDirectory); + + handle = CreateFile(fn, + GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + +#ifndef _WIN64 + + _asm { + + mov stack,esp + } + + WriteFile(handle,stack,128,&cnt,NULL); +#endif + +// WriteFile(handle,Screen,MAXLINELEN*MAXSCREENLEN,&cnt,NULL); + + WriteFile(handle,DATAAREA, DATABYTES,&cnt,NULL); + + CloseHandle(handle); + + sprintf(Msg, "Dump to %s Completed\n", fn); + WritetoConsole(Msg); + + FindLostBuffers(); + + return (0); +} + +BOOLEAN CheckifBPQ32isLoaded() +{ + HANDLE Mutex; + + // See if BPQ32 is running - if we create it in the NTVDM address space by + // loading bpq32.dll it will not work. + + Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX"); + + if (Mutex == NULL) + { + if (AttachingProcess == 0) // Already starting BPQ32 + { + OutputDebugString("BPQ32 No other bpq32 programs running - Loading BPQ32.exe\n"); + StartBPQ32(); + } + return FALSE; + } + + CloseHandle(Mutex); + + return TRUE; +} + +BOOLEAN StartBPQ32() +{ + UCHAR Value[100]; + + char bpq[]="BPQ32.exe"; + char *fn=(char *)&bpq; + HKEY hKey=0; + int ret,Type,Vallen=99; + + char Errbuff[100]; + char buff[20]; + + STARTUPINFO StartupInfo; // pointer to STARTUPINFO + PROCESS_INFORMATION ProcessInformation; // pointer to PROCESS_INFORMATION + + AttachingProcess = 1; + +// Get address of BPQ Directory + + Value[0]=0; + + ret = RegOpenKeyEx (REGTREE, + "SOFTWARE\\G8BPQ\\BPQ32", + 0, + KEY_QUERY_VALUE, + &hKey); + + if (ret == ERROR_SUCCESS) + { + ret = RegQueryValueEx(hKey, "BPQ Program Directory", 0, &Type,(UCHAR *)&Value, &Vallen); + + if (ret == ERROR_SUCCESS) + { + if (strlen(Value) == 2 && Value[0] == '"' && Value[1] == '"') + Value[0]=0; + } + + + if (Value[0] == 0) + { + + // BPQ Directory absent or = "" - "try Config File Location" + + ret = RegQueryValueEx(hKey,"BPQ Directory",0, + &Type,(UCHAR *)&Value,&Vallen); + + if (ret == ERROR_SUCCESS) + { + if (strlen(Value) == 2 && Value[0] == '"' && Value[1] == '"') + Value[0]=0; + } + + } + RegCloseKey(hKey); + } + + if (Value[0] == 0) + { + strcpy(Value,fn); + } + else + { + strcat(Value,"\\"); + strcat(Value,fn); + } + + StartupInfo.cb=sizeof(StartupInfo); + StartupInfo.lpReserved=NULL; + StartupInfo.lpDesktop=NULL; + StartupInfo.lpTitle=NULL; + StartupInfo.dwFlags=0; + StartupInfo.cbReserved2=0; + StartupInfo.lpReserved2=NULL; + + if (!CreateProcess(Value,NULL,NULL,NULL,FALSE, + CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, + NULL,NULL,&StartupInfo,&ProcessInformation)) + { + ret=GetLastError(); + + _itoa(ret,buff,10); + + strcpy(Errbuff, "BPQ32 Load "); + strcat(Errbuff,Value); + strcat(Errbuff," failed "); + strcat(Errbuff,buff); + OutputDebugString(Errbuff); + AttachingProcess = 0; + return FALSE; + } + + return TRUE; +} + + +DllExport BPQVECSTRUC * APIENTRY GetIPVectorAddr() +{ + return &IPHOSTVECTOR; +} + +DllExport UINT APIENTRY GETSENDNETFRAMEADDR() +{ + return (UINT)&SENDNETFRAME; +} + +DllExport VOID APIENTRY RelBuff(VOID * Msg) +{ + UINT * pointer, * BUFF = Msg; + + if (Semaphore.Flag == 0) + Debugprintf("ReleaseBuffer called without semaphore"); + + pointer = FREE_Q; + + *BUFF =(UINT)pointer; + + FREE_Q = BUFF; + + QCOUNT++; + + return; +} + +extern int MINBUFFCOUNT; + +DllExport VOID * APIENTRY GetBuff() +{ + UINT * Temp = Q_REM(&FREE_Q); + + if (Semaphore.Flag == 0) + Debugprintf("GetBuff called without semaphore"); + + if (Temp) + { + QCOUNT--; + + if (QCOUNT < MINBUFFCOUNT) + MINBUFFCOUNT = QCOUNT; + } + + return Temp; +} + + +VOID __cdecl Debugprintf(const char * format, ...) +{ + char Mess[10000]; + va_list(arglist); + + va_start(arglist, format); + vsprintf(Mess, format, arglist); + strcat(Mess, "\r\n"); + OutputDebugString(Mess); + + return; +} + +unsigned short int compute_crc(unsigned char *buf, int txlen); + +extern SOCKADDR_IN reportdest; + +extern SOCKET ReportSocket; + +extern SOCKADDR_IN Chatreportdest; + +DllExport VOID APIENTRY SendChatReport(SOCKET ChatReportSocket, char * buff, int txlen) +{ + unsigned short int crc = compute_crc(buff, txlen); + + crc ^= 0xffff; + + buff[txlen++] = (crc&0xff); + buff[txlen++] = (crc>>8); + + sendto(ChatReportSocket, buff, txlen, 0, (LPSOCKADDR)&Chatreportdest, sizeof(Chatreportdest)); +} + +VOID CreateRegBackup() +{ + char Backup1[MAX_PATH]; + char Backup2[MAX_PATH]; + char RegFileName[MAX_PATH]; + char Msg[80]; + HANDLE handle; + int len, written; + char RegLine[300]; + +// SHELLEXECUTEINFO sei; +// STARTUPINFO SInfo; +// PROCESS_INFORMATION PInfo; + + sprintf(RegFileName, "%s\\BPQ32.reg", BPQDirectory); + + // Keep 4 Generations + + strcpy(Backup2, RegFileName); + strcat(Backup2, ".bak.3"); + + strcpy(Backup1, RegFileName); + strcat(Backup1, ".bak.2"); + + DeleteFile(Backup2); // Remove old .bak.3 + MoveFile(Backup1, Backup2); // Move .bak.2 to .bak.3 + + strcpy(Backup2, RegFileName); + strcat(Backup2, ".bak.1"); + + MoveFile(Backup2, Backup1); // Move .bak.1 to .bak.2 + + strcpy(Backup1, RegFileName); + strcat(Backup1, ".bak"); + + MoveFile(Backup1, Backup2); //Move .bak to .bak.1 + + strcpy(Backup2, RegFileName); + strcat(Backup2, ".bak"); + + CopyFile(RegFileName, Backup2, FALSE); // Copy to .bak + + handle = CreateFile(RegFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if (handle == INVALID_HANDLE_VALUE) + { + sprintf(Msg, "Failed to open Registry Save File\n"); + WritetoConsole(Msg); + return; + } + + len = sprintf(RegLine, "Windows Registry Editor Version 5.00\r\n\r\n"); + WriteFile(handle, RegLine, len, &written, NULL); + + if (SaveReg("Software\\G8BPQ\\BPQ32", handle)) + WritetoConsole("Registry Save complete\n"); + else + WritetoConsole("Registry Save failed\n"); + + CloseHandle(handle); + return ; +/* + + if (REGTREE == HKEY_LOCAL_MACHINE) // < Vista + { + sprintf(cmd, + "regedit /E \"%s\\BPQ32.reg\" %s\\Software\\G8BPQ\\BPQ32", BPQDirectory, REGTREETEXT); + + ZeroMemory(&SInfo, sizeof(SInfo)); + + SInfo.cb=sizeof(SInfo); + SInfo.lpReserved=NULL; + SInfo.lpDesktop=NULL; + SInfo.lpTitle=NULL; + SInfo.dwFlags=0; + SInfo.cbReserved2=0; + SInfo.lpReserved2=NULL; + + if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0 ,NULL, NULL, &SInfo, &PInfo) == 0) + { + sprintf(Msg, "Error: CreateProcess for regedit failed 0%d\n", GetLastError() ); + WritetoConsole(Msg); + return; + } + } + else + { + + sprintf(cmd, + "/E \"%s\\BPQ32.reg\" %s\\Software\\G8BPQ\\BPQ32", BPQDirectory, REGTREETEXT); + + ZeroMemory(&sei, sizeof(sei)); + + sei.cbSize = sizeof(SHELLEXECUTEINFOW); + sei.hwnd = hWnd; + sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI; + sei.lpVerb = "runas"; + sei.lpFile = "regedit.exe"; + sei.lpParameters = cmd; + sei.nShow = SW_SHOWNORMAL; + + if (!ShellExecuteEx(&sei)) + { + sprintf(Msg, "Error: ShellExecuteEx for regedit failed %d\n", GetLastError() ); + WritetoConsole(Msg); + return; + } + } + + sprintf(Msg, "Registry Save Initiated\n", fn); + WritetoConsole(Msg); + + return ; +*/ +} + +BOOL CALLBACK EnumForCloseProc(HWND hwnd, LPARAM lParam) +{ + struct TNCINFO * TNC = (struct TNCINFO *)lParam; + UINT ProcessId; + + GetWindowThreadProcessId(hwnd, &ProcessId); + + for (i=0; i< AttachedProcesses; i++) + { + if (AttachedPIDList[i] == ProcessId) + { + Debugprintf("BPQ32 Close All Closing PID %d", ProcessId); + PostMessage(hwnd, WM_CLOSE, 1, 1); + // AttachedPIDList[i] = 0; // So we don't do it again + break; + } + } + + return (TRUE); +} +DllExport BOOL APIENTRY RestoreFrameWindow() +{ + return ShowWindow(FrameWnd, SW_RESTORE); +} + +DllExport VOID APIENTRY CreateNewTrayIcon() +{ + Shell_NotifyIcon(NIM_DELETE,&niData); + trayMenu = NULL; +} + +DllExport VOID APIENTRY CloseAllPrograms() +{ +// HANDLE hProc; + + // Close all attached BPQ32 programs + + Closing = TRUE; + + ShowWindow(FrameWnd, SW_RESTORE); + + GetWindowRect(FrameWnd, &FRect); + + SaveBPQ32Windows(); + CloseHostSessions(); + + if (AttachedProcesses == 1) + CloseBPQ32(); + + Debugprintf("BPQ32 Close All Processes %d PIDS %d %d %d %d", AttachedProcesses, AttachedPIDList[0], + AttachedPIDList[1], AttachedPIDList[2], AttachedPIDList[3]); + + if (MinimizetoTray) + Shell_NotifyIcon(NIM_DELETE,&niData); + + EnumWindows(EnumForCloseProc, (LPARAM)NULL); +} + +#define MAX_KEY_LENGTH 255 +#define MAX_VALUE_NAME 16383 +#define MAX_VALUE_DATA 65536 + +BOOL CopyReg(HKEY hKeyIn, HKEY hKeyOut) +{ + TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name + DWORD cbName; // size of name string + TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name + DWORD cchClassName = MAX_PATH; // size of class string + DWORD cSubKeys=0; // number of subkeys + DWORD cbMaxSubKey; // longest subkey size + DWORD cchMaxClass; // longest class string + DWORD cValues; // number of values for key + DWORD cchMaxValue; // longest value name + DWORD cbMaxValueData; // longest value data + DWORD cbSecurityDescriptor; // size of security descriptor + FILETIME ftLastWriteTime; // last write time + + DWORD i, retCode; + + TCHAR achValue[MAX_VALUE_NAME]; + DWORD cchValue = MAX_VALUE_NAME; + + // Get the class name and the value count. + retCode = RegQueryInfoKey( + hKeyIn, // key handle + achClass, // buffer for class name + &cchClassName, // size of class string + NULL, // reserved + &cSubKeys, // number of subkeys + &cbMaxSubKey, // longest subkey size + &cchMaxClass, // longest class string + &cValues, // number of values for this key + &cchMaxValue, // longest value name + &cbMaxValueData, // longest value data + &cbSecurityDescriptor, // security descriptor + &ftLastWriteTime); // last write time + + // Enumerate the subkeys, until RegEnumKeyEx fails. + + if (cSubKeys) + { + Debugprintf( "\nNumber of subkeys: %d\n", cSubKeys); + + for (i=0; i 76) + { + len = sprintf(RegLine, "%s\\\r\n", RegLine); + WriteFile(hFile, RegLine, len, &written, NULL); + strcpy(RegLine, " "); + len = 2; + } + + len = sprintf(RegLine, "%s%02x,", RegLine, Value[k]); + } + RegLine[--len] = 0x0d; + RegLine[++len] = 0x0a; + len++; + + break; + + case REG_DWORD: //( 4 ) // 32-bit number +// case REG_DWORD_LITTLE_ENDIAN: //( 4 ) // 32-bit number (same as REG_DWORD) + + memcpy(&Intval, Value, 4); + len = sprintf(RegLine, "\"%s\"=dword:%08x\r\n", achValue, Intval); + break; + + case REG_DWORD_BIG_ENDIAN: //( 5 ) // 32-bit number + break; + case REG_LINK: //( 6 ) // Symbolic Link (unicode) + break; + case REG_MULTI_SZ: //( 7 ) // Multiple Unicode strings + + len = sprintf(RegLine, "\"%s\"=hex(7):%02x,00,", achValue, Value[0]); + for (k = 1; k < ValLen; k++) + { + if (len > 76) + { + len = sprintf(RegLine, "%s\\\r\n", RegLine); + WriteFile(hFile, RegLine, len, &written, NULL); + strcpy(RegLine, " "); + len = 2; + } + len = sprintf(RegLine, "%s%02x,", RegLine, Value[k]); + if (len > 76) + { + len = sprintf(RegLine, "%s\\\r\n", RegLine); + WriteFile(hFile, RegLine, len, &written, NULL); + strcpy(RegLine, " "); + } + len = sprintf(RegLine, "%s00,", RegLine); + } + + RegLine[--len] = 0x0d; + RegLine[++len] = 0x0a; + len++; + break; + + case REG_RESOURCE_LIST: //( 8 ) // Resource list in the resource map + break; + case REG_FULL_RESOURCE_DESCRIPTOR: //( 9 ) // Resource list in the hardware description + break; + case REG_RESOURCE_REQUIREMENTS_LIST://( 10 ) + break; + case REG_QWORD: //( 11 ) // 64-bit number +// case REG_QWORD_LITTLE_ENDIAN: //( 11 ) // 64-bit number (same as REG_QWORD) + break; + + } + + WriteFile(hFile, RegLine, len, &written, NULL); + } + } + } + + WriteFile(hFile, "\r\n", 2, &written, NULL); + + // Enumerate the subkeys, until RegEnumKeyEx fails. + + if (cSubKeys) + { + for (i=0; i> 1; + } + + Flags=GetApplFlags(i); + + if (OneBits > 1) + sprintf(&NewScreen[(i+1)*54],"%2d%s%3d %3d %3d %03x %3x %10s%-20s", + i, flag, RXCount(i), TXCount(i), MONCount(i), Mask, Flags, callsign, + BPQHOSTVECTOR[i-1].PgmName); + else + sprintf(&NewScreen[(i+1)*54],"%2d%s%3d %3d %3d %3d %3x %10s%-20s", + i, flag, RXCount(i), TXCount(i), MONCount(i), AppNumber, Flags, callsign, + BPQHOSTVECTOR[i-1].PgmName); + + } + } + + #include "StdExcept.c" + + if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId()) + FreeSemaphore(&Semaphore); + + } + + if (memcmp(Screen, NewScreen, 33 * 108) == 0) // No Change + return 0; + + memcpy(Screen, NewScreen, 33 * 108); + InvalidateRect(StatusWnd,NULL,FALSE); + + return(0); +} + +LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + PAINTSTRUCT ps; + HDC hdc; + HFONT hOldFont ; + HGLOBAL hMem; + MINMAXINFO * mmi; + int i; + + switch (message) + { + case WM_TIMER: + + if (Semaphore.Flag == 0) + DoStatus(); + break; + + case WM_MDIACTIVATE: + + // Set the system info menu when getting activated + + if (lParam == (LPARAM) hWnd) + { + // Activate + + RemoveMenu(hBaseMenu, 1, MF_BYPOSITION); + AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)hConsMenu, "Actions"); + SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hBaseMenu, (LPARAM) hWndMenu); + } + else + { + SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL); + } + + DrawMenuBar(FrameWnd); + + return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam); + + case WM_GETMINMAXINFO: + + mmi = (MINMAXINFO *)lParam; + mmi->ptMaxSize.x = 850; + mmi->ptMaxSize.y = 500; + mmi->ptMaxTrackSize.x = 850; + mmi->ptMaxTrackSize.y = 500; + + + case WM_COMMAND: + + wmId = LOWORD(wParam); // Remember, these are... + wmEvent = HIWORD(wParam); // ...different for Win32! + + //Parse the menu selections: + + switch (wmId) + { + +/* + case BPQSTREAMS: + + CheckMenuItem(hMenu,BPQSTREAMS,MF_CHECKED); + CheckMenuItem(hMenu,BPQIPSTATUS,MF_UNCHECKED); + + StreamDisplay = TRUE; + + break; + + case BPQIPSTATUS: + + CheckMenuItem(hMenu,BPQSTREAMS,MF_UNCHECKED); + CheckMenuItem(hMenu,BPQIPSTATUS,MF_CHECKED); + + StreamDisplay = FALSE; + memset(Screen, ' ', 4000); + + + break; + +*/ + + case BPQCOPY: + + // + // Copy buffer to clipboard + // + hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, 33*110); + + if (hMem != 0) + { + if (OpenClipboard(hWnd)) + { +// CopyScreentoBuffer(GlobalLock(hMem)); + GlobalUnlock(hMem); + EmptyClipboard(); + SetClipboardData(CF_TEXT,hMem); + CloseClipboard(); + } + else + { + GlobalFree(hMem); + } + + } + + break; + + } + + return DefMDIChildProc(hWnd, message, wParam, lParam); + + + case WM_SYSCOMMAND: + + wmId = LOWORD(wParam); // Remember, these are... + wmEvent = HIWORD(wParam); // ...different for Win32! + + switch (wmId) + { + case SC_MAXIMIZE: + + break; + + case SC_MINIMIZE: + + StatusMinimized = TRUE; + break; + + case SC_RESTORE: + + StatusMinimized = FALSE; + SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0); + break; + } + + return DefMDIChildProc(hWnd, message, wParam, lParam); + + case WM_PAINT: + + hdc = BeginPaint (hWnd, &ps); + + hOldFont = SelectObject( hdc, hFont) ; + + for (i=0; i<33; i++) + { + TextOut(hdc,0,i*14,&Screen[i*108],108); + } + + SelectObject( hdc, hOldFont ) ; + EndPaint (hWnd, &ps); + + break; + + case WM_DESTROY: + +// PostQuitMessage(0); + + break; + + + default: + + return DefMDIChildProc(hWnd, message, wParam, lParam); + + } + return (0); +} + +VOID SaveMDIWindowPos(HWND hWnd, char * RegKey, char * Value, BOOL Minimized) +{ + HKEY hKey=0; + char Size[80]; + char Key[80]; + int retCode, disp; + RECT Rect; + + if (IsWindow(hWnd) == FALSE) + return; + + ShowWindow(hWnd, SW_RESTORE); + + if (GetWindowRect(hWnd, &Rect) == FALSE) + return; + + // Make relative to Frame + + Rect.top -= FRect.top ; + Rect.left -= FRect.left; + Rect.bottom -= FRect.top; + Rect.right -= FRect.left; + + sprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\%s", RegKey); + + retCode = RegCreateKeyEx(REGTREE, Key, 0, 0, 0, + KEY_ALL_ACCESS, NULL, &hKey, &disp); + + if (retCode == ERROR_SUCCESS) + { + sprintf(Size,"%d,%d,%d,%d,%d", Rect.left, Rect.right, Rect.top ,Rect.bottom, Minimized); + retCode = RegSetValueEx(hKey, Value, 0, REG_SZ,(BYTE *)&Size, strlen(Size)); + RegCloseKey(hKey); + } +} + +extern int GPSPort; +extern char LAT[]; // in standard APRS Format +extern char LON[]; // in standard APRS Format + +VOID SaveBPQ32Windows() +{ + HKEY hKey=0; + char Size[80]; + int retCode, disp; + PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE; + int i; + + retCode = RegCreateKeyEx(REGTREE, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp); + + if (retCode == ERROR_SUCCESS) + { + sprintf(Size,"%d,%d,%d,%d", FRect.left, FRect.right, FRect.top, FRect.bottom); + retCode = RegSetValueEx(hKey, "FrameWindowSize", 0, REG_SZ, (BYTE *)&Size, strlen(Size)); + + // Save GPS Position + + if (GPSPort) + { + sprintf(Size, "%s, %s", LAT, LON); + retCode = RegSetValueEx(hKey, "GPS", 0, REG_SZ,(BYTE *)&Size, strlen(Size)); + } + + RegCloseKey(hKey); + } + + SaveMDIWindowPos(StatusWnd, "", "StatusWindowSize", StatusMinimized); + SaveMDIWindowPos(hConsWnd, "", "WindowSize", ConsoleMinimized); + + for (i=0; iPORTCONTROL.PORTTYPE == 0x10) // External + { + if (PORTVEC->PORT_EXT_ADDR) + { + SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); + SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); + } + } + PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER; + } + + SaveWindowPos(70); // Rigcontrol + + + if (hIPResWnd) + SaveMDIWindowPos(hIPResWnd, "", "IPResSize", IPMinimized); + + SaveHostSessions(); +} + +DllExport BOOL APIENTRY CheckIfOwner() +{ + // + // Returns TRUE if current process is root process + // that loaded the DLL + // + + if (TimerInst == GetCurrentProcessId()) + + return (TRUE); + else + return (FALSE); +} + +VOID GetParam(char * input, char * key, char * value) +{ + char * ptr = strstr(input, key); + char Param[2048]; + char * ptr1, * ptr2; + char c; + + + if (ptr) + { + ptr2 = strchr(ptr, '&'); + if (ptr2) *ptr2 = 0; + strcpy(Param, ptr + strlen(key)); + if (ptr2) *ptr2 = '&'; // Restore string + + // Undo any % transparency + + ptr1 = Param; + ptr2 = Param; + + c = *(ptr1++); + + while (c) + { + if (c == '%') + { + int n; + int m = *(ptr1++) - '0'; + if (m > 9) m = m - 7; + n = *(ptr1++) - '0'; + if (n > 9) n = n - 7; + + *(ptr2++) = m * 16 + n; + } + else if (c == '+') + *(ptr2++) = ' '; + else + *(ptr2++) = c; + + c = *(ptr1++); + } + + *(ptr2++) = 0; + + strcpy(value, Param); + } +} + +int GetListeningPortsPID(int Port) +{ + MIB_TCPTABLE_OWNER_PID * TcpTable = NULL; + PMIB_TCPROW_OWNER_PID Row; + int dwSize = 0; + DWORD n; + + // Get PID of process for this TCP Port + + // Get Length of table + + GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0); + + TcpTable = malloc(dwSize); + + if (TcpTable == NULL) + return 0; + + GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0); + + for (n = 0; n < TcpTable->dwNumEntries; n++) + { + Row = &TcpTable->table[n]; + + if (Row->dwLocalPort == Port && Row->dwState == MIB_TCP_STATE_LISTEN) + { + return Row->dwOwningPid; + break; + } + } + return 0; // Not found +} + +DllExport char * APIENTRY GetLOC() +{ + return LOC; +} + +DllExport void APIENTRY GetLatLon(double * lat, double * lon) +{ + *lat = LatFromLOC; + *lon = LonFromLOC; + return; +} + + +// UZ7HO Dll PTT interface + +// 1 ext_PTT_info +// 2 ext_PTT_settings +// 3 ext_PTT_OFF +// 4 ext_PTT_ON +// 5 ext_PTT_close +// 6 ext_PTT_open + +extern struct RIGINFO * DLLRIG; // Rig record for dll PTT interface (currently only for UZ7HO); + +VOID Rig_PTT(struct TNCINFO * TNC, BOOL PTTState); +VOID Rig_PTTEx(struct RIGINFO * RIG, BOOL PTTState, struct TNCINFO * TNC); + +int WINAPI ext_PTT_info() +{ + return 0; +} + +int WINAPI ext_PTT_settings() +{ + return 0; +} + +int WINAPI ext_PTT_OFF(int Port) +{ + if (DLLRIG) + Rig_PTTEx(DLLRIG, 0, 0); + + return 0; +} + +int WINAPI ext_PTT_ON(int Port) +{ + if (DLLRIG) + Rig_PTTEx(DLLRIG, 1, 0); + + return 0; +} +int WINAPI ext_PTT_close() +{ + if (DLLRIG) + Rig_PTTEx(DLLRIG, 0, 0); + + return 0; +} + +DllExport INT WINAPI ext_PTT_open() +{ + return 1; +} + +char * stristr (char *ch1, char *ch2) +{ + char *chN1, *chN2; + char *chNdx; + char *chRet = NULL; + + chN1 = _strdup(ch1); + chN2 = _strdup(ch2); + + if (chN1 && chN2) + { + chNdx = chN1; + while (*chNdx) + { + *chNdx = (char) tolower(*chNdx); + chNdx ++; + } + chNdx = chN2; + + while (*chNdx) + { + *chNdx = (char) tolower(*chNdx); + chNdx ++; + } + + chNdx = strstr(chN1, chN2); + + if (chNdx) + chRet = ch1 + (chNdx - chN1); + } + + free (chN1); + free (chN2); + return chRet; +} + diff --git a/Bpq32.c b/Bpq32.c index 1a5644f..b6acf29 100644 --- a/Bpq32.c +++ b/Bpq32.c @@ -3,7 +3,7 @@ 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 +LinBPQ/BPQ32 is free software: you can redistribute it and/or modifyextern int HTTP 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. @@ -1241,6 +1241,13 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // Add MQTT reporting of Mail Events (54) // Fix beaconong on KISSHF ports (55) // Fix MailAPI msgs endpoint +// Attempt to fix NC going to wrong application. (57) +// Improve ARDOP end of session code (58) +// Run M0LTE Map repoorting in a separate thread (59) +// Add support fro WhatsPac (59) +// Add timestamps to LIS monitor + + #define CKernel @@ -1503,6 +1510,7 @@ VOID APRSClose(); VOID CloseTNCEmulator(); VOID Poll_AGW(); +void RHPPoll(); BOOL AGWAPIInit(); int AGWAPITerminate(); @@ -1521,7 +1529,9 @@ UINT Sem_edx = 0; UINT Sem_esi = 0; UINT Sem_edi = 0; -void GetSemaphore(struct SEM * Semaphore, int ID); + +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); void FreeSemaphore(struct SEM * Semaphore); DllExport void * BPQHOSTAPIPTR = &BPQHOSTAPI; @@ -1869,8 +1879,8 @@ VOID MonitorThread(int x) { // It is stuck - try to release - Debugprintf ("Semaphore locked - Process ID = %d, Held By %d", - Semaphore.SemProcessID, SemHeldByAPI); + Debugprintf ("Semaphore locked - Process ID = %d, Held By %d from %s Line %d", + Semaphore.SemProcessID, SemHeldByAPI, Semaphore.File, Semaphore.Line); // Write a minidump @@ -2291,6 +2301,7 @@ VOID TimerProcX() Poll_AGW(); DRATSPoll(); + RHPPoll(); CheckGuardZone(); diff --git a/CMSAuth.c b/CMSAuth.c index e2fbd06..ae63e4d 100644 --- a/CMSAuth.c +++ b/CMSAuth.c @@ -23,7 +23,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #ifdef LINBPQ #include "compatbits.h" -char * strlop(const char * buf, char delim); +char * strlop(char * buf, char delim); #define APIENTRY #define VOID void diff --git a/ChatUtilities.c b/ChatUtilities.c index 9a32436..0e5ef79 100644 --- a/ChatUtilities.c +++ b/ChatUtilities.c @@ -39,7 +39,8 @@ VOID __cdecl Logprintf(int LogMode, ChatCIRCUIT * conn, int InOut, const char * return; } -void GetSemaphore(struct SEM * Semaphore, int ID) + +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line) { // // Wait for it to be free @@ -74,6 +75,9 @@ loop1: ; } + Semaphore->Line = Line; + strcpy(Semaphore->File, File); + return; } void FreeSemaphore(struct SEM * Semaphore) diff --git a/Cmd.c b/Cmd.c index cda5b7d..c5f43dd 100644 --- a/Cmd.c +++ b/Cmd.c @@ -35,7 +35,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses //#include "vmm.h" //#include "SHELLAPI.H" -#include "CHeaders.h" +#include "cheaders.h" #include "bpqaprs.h" #include "kiss.h" @@ -988,7 +988,6 @@ VOID CMDSTATS(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct { char * ptr, *Context; int Port = 0, cols = NUMBEROFPORTS, i; - char * uptime; struct PORTCONTROL * PORT = PORTTABLE; struct PORTCONTROL * STARTPORT; diff --git a/CommonCode-skigdebian.c b/CommonCode-skigdebian.c new file mode 100644 index 0000000..90e6a08 --- /dev/null +++ b/CommonCode-skigdebian.c @@ -0,0 +1,5647 @@ +/* +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 +*/ + + + +// General C Routines common to bpq32 and linbpq. Mainly moved from BPQ32.c + +#pragma data_seg("_BPQDATA") + +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include +#include +#include "mqtt.h" + +#pragma data_seg("_BPQDATA") + +#include "cheaders.h" +#include "tncinfo.h" +#include "configstructs.h" + +extern struct CONFIGTABLE xxcfg; + +#define LIBCONFIG_STATIC +#include "libconfig.h" + +#ifndef LINBPQ + +//#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. + +#include "commctrl.h" +#include "Commdlg.h" + +#endif + +struct TNCINFO * TNCInfo[71]; // Records are Malloc'd + +extern int ReportTimer; + +Dll VOID APIENTRY Send_AX(UCHAR * Block, DWORD Len, UCHAR Port); +TRANSPORTENTRY * SetupSessionFromHost(PBPQVECSTRUC HOST, UINT ApplMask); +int Check_Timer(); +VOID SENDUIMESSAGE(struct DATAMESSAGE * Msg); +DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot); +VOID APIENTRY md5 (char *arg, unsigned char * checksum); +VOID COMSetDTR(HANDLE fd); +VOID COMClearDTR(HANDLE fd); +VOID COMSetRTS(HANDLE fd); +VOID COMClearRTS(HANDLE fd); + +VOID WriteMiniDump(); +void printStack(void); +char * FormatMH(PMHSTRUC MH, char Format); +void WriteConnectLog(char * fromCall, char * toCall, UCHAR * Mode); +void SendDataToPktMap(); + +extern BOOL LogAllConnects; +extern BOOL M0LTEMap; + +char * stristr (char *ch1, char *ch2); + +extern VOID * ENDBUFFERPOOL; + + +// Read/Write length field in a buffer header + +// Needed for Big/LittleEndian and ARM5 (unaligned operation problem) portability + + +VOID PutLengthinBuffer(PDATAMESSAGE buff, USHORT datalen) +{ + if (datalen <= sizeof(void *) + 4) + datalen = sizeof(void *) + 4; // Protect + + memcpy(&buff->LENGTH, &datalen, 2); +} + +int GetLengthfromBuffer(PDATAMESSAGE buff) +{ + USHORT Length; + + memcpy(&Length, &buff->LENGTH, 2); + return Length; +} + +BOOL CheckQHeadder(UINT * Q) +{ +#ifdef WIN32 + UINT Test; + + __try + { + Test = *Q; + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + Debugprintf("Invalid Q Header %p", Q); + printStack(); + return FALSE; + } +#endif + return TRUE; +} + +// Get buffer from Queue + + +VOID * _Q_REM(VOID **PQ, char * File, int Line) +{ + void ** Q; + void ** first; + VOID * next; + PMESSAGE Test; + + // PQ may not be word aligned, so copy as bytes (for ARM5) + + Q = PQ; + + if (Semaphore.Flag == 0) + Debugprintf("Q_REM called without semaphore from %s Line %d", File, Line); + + if (CheckQHeadder((UINT *) Q) == 0) + return(0); + + first = Q[0]; + + if (first == 0) + return (0); // Empty + + next = first[0]; // Address of next buffer + + Q[0] = next; + + // Make sure guard zone is zeros + + Test = (PMESSAGE)first; + + if (Test->GuardZone != 0) + { + Debugprintf("Q_REM %p GUARD ZONE CORRUPT %x Called from %s Line %d", first, Test->GuardZone, File, Line); + printStack(); + } + + return first; +} + +// Non=pool version (for IPGateway) + +VOID * _Q_REM_NP(VOID *PQ, char * File, int Line) +{ + void ** Q; + void ** first; + void * next; + + // PQ may not be word aligned, so copy as bytes (for ARM5) + + Q = PQ; + + if (CheckQHeadder((UINT *)Q) == 0) + return(0); + + first = Q[0]; + + if (first == 0) return (0); // Empty + + next = first[0]; // Address of next buffer + + Q[0] = next; + + return first; +} + +// Return Buffer to Free Queue + +extern VOID * BUFFERPOOL; +extern void ** Bufferlist[1000]; +void printStack(void); + +void _CheckGuardZone(char * File, int Line) +{ + int n = 0, i, offset = 0; + PMESSAGE Test; + UINT CodeDump[8]; + unsigned char * ptr; + + n = NUMBEROFBUFFERS; + + while (n--) + { + Test = (PMESSAGE)Bufferlist[n]; + + if (Test && Test->GuardZone) + { + Debugprintf("CheckGuardZone %p GUARD ZONE CORRUPT %d Called from %s Line %d", Test, Test->Process, File, Line); + + offset = 0; + ptr = (unsigned char *)Test; + + while (offset < 400) + { + memcpy(CodeDump, &ptr[offset], 32); + + for (i = 0; i < 8; i++) + CodeDump[i] = htonl(CodeDump[i]); + + Debugprintf("%08x %08x %08x %08x %08x %08x %08x %08x %08x ", + &ptr[offset], CodeDump[0], CodeDump[1], CodeDump[2], CodeDump[3], CodeDump[4], CodeDump[5], CodeDump[6], CodeDump[7]); + + offset += 32; + } + WriteMiniDump(); +#ifdef MDIKERNEL + CloseAllNeeded = 1; +#endif + } + + } +} + +UINT _ReleaseBuffer(VOID *pBUFF, char * File, int Line) +{ + void ** pointer, ** BUFF = pBUFF; + int n = 0; + void ** debug; + PMESSAGE Test; + UINT CodeDump[16]; + int i; + unsigned int rev; + + if (Semaphore.Flag == 0) + Debugprintf("ReleaseBuffer called without semaphore from %s Line %d", File, Line); + + // Make sure address is within pool + + if ((uintptr_t)BUFF < (uintptr_t)BUFFERPOOL || (uintptr_t)BUFF > (uintptr_t)ENDBUFFERPOOL) + { + // Not pointing to a buffer . debug points to the buffer that this is chained from + + // Dump first chunk and source tag + + memcpy(CodeDump, BUFF, 64); + + Debugprintf("Releasebuffer Buffer not in pool from %s Line %d, ptr %p prev %d", File, Line, BUFF, 0); + + for (i = 0; i < 16; i++) + { + rev = (CodeDump[i] & 0xff) << 24; + rev |= (CodeDump[i] & 0xff00) << 8; + rev |= (CodeDump[i] & 0xff0000) >> 8; + rev |= (CodeDump[i] & 0xff000000) >> 24; + + CodeDump[i] = rev; + } + + Debugprintf("%08x %08x %08x %08x %08x %08x %08x %08x %08x ", + Bufferlist[n], CodeDump[0], CodeDump[1], CodeDump[2], CodeDump[3], CodeDump[4], CodeDump[5], CodeDump[6], CodeDump[7]); + + Debugprintf(" %08x %08x %08x %08x %08x %08x %08x %08x", + CodeDump[8], CodeDump[9], CodeDump[10], CodeDump[11], CodeDump[12], CodeDump[13], CodeDump[14], CodeDump[15]); + + + return 0; + } + + Test = (PMESSAGE)pBUFF; + + if (Test->GuardZone != 0) + { + Debugprintf("_ReleaseBuffer %p GUARD ZONE CORRUPT %x Called from %s Line %d", pBUFF, Test->GuardZone, File, Line); + } + + while (n <= NUMBEROFBUFFERS) + { + if (BUFF == Bufferlist[n++]) + goto BOK1; + } + + Debugprintf("ReleaseBuffer %X not in Pool called from %s Line %d", BUFF, File, Line); + printStack(); + + return 0; + +BOK1: + + n = 0; + + // validate free Queue + + pointer = FREE_Q; + debug = &FREE_Q; + + while (pointer) + { + // Validate pointer to make sure it is in pool - it may be a duff address if Q is corrupt + + Test = (PMESSAGE)pointer; + + if (Test->GuardZone || (uintptr_t)pointer < (uintptr_t)BUFFERPOOL || (uintptr_t)pointer > (uintptr_t)ENDBUFFERPOOL) + { + // Not pointing to a buffer . debug points to the buffer that this is chained from + + // Dump first chunk and source tag + + memcpy(CodeDump, debug, 64); + + Debugprintf("Releasebuffer Pool Corruption n = %d, ptr %p prev %p", n, pointer, debug); + + for (i = 0; i < 16; i++) + { + rev = (CodeDump[i] & 0xff) << 24; + rev |= (CodeDump[i] & 0xff00) << 8; + rev |= (CodeDump[i] & 0xff0000) >> 8; + rev |= (CodeDump[i] & 0xff000000) >> 24; + + CodeDump[i] = rev; + } + + Debugprintf("%08x %08x %08x %08x %08x %08x %08x %08x %08x ", + Bufferlist[n], CodeDump[0], CodeDump[1], CodeDump[2], CodeDump[3], CodeDump[4], CodeDump[5], CodeDump[6], CodeDump[7]); + + Debugprintf(" %08x %08x %08x %08x %08x %08x %08x %08x", + CodeDump[8], CodeDump[9], CodeDump[10], CodeDump[11], CodeDump[12], CodeDump[13], CodeDump[14], CodeDump[15]); + + if (debug[400]) + Debugprintf(" %s", &debug[400]); + + } + + // See if already on free Queue + + if (pointer == BUFF) + { + Debugprintf("Trying to free buffer %p when already on FREE_Q called from %s Line %d", BUFF, File, Line); +// WriteMiniDump(); + return 0; + } + +// if (pointer[0] && pointer == pointer[0]) +// { +// Debugprintf("Buffer chained to itself"); +// return 0; +// } + + debug = pointer; + pointer = pointer[0]; + n++; + + if (n > 1000) + { + Debugprintf("Loop searching free chain - pointer = %p %p", debug, pointer); + return 0; + } + } + + pointer = FREE_Q; + + *BUFF = pointer; + + FREE_Q = BUFF; + + QCOUNT++; + + return 0; +} + +int _C_Q_ADD(VOID *PQ, VOID *PBUFF, char * File, int Line) +{ + void ** Q; + void ** BUFF = PBUFF; + void ** next; + PMESSAGE Test; + + + int n = 0; + +// PQ may not be word aligned, so copy as bytes (for ARM5) + + Q = PQ; + + if (Semaphore.Flag == 0) + Debugprintf("C_Q_ADD called without semaphore from %s Line %d", File, Line); + + if (CheckQHeadder((UINT *)Q) == 0) // Make sure Q header is readable + return(0); + + // Make sure guard zone is zeros + + Test = (PMESSAGE)PBUFF; + + if (Test->GuardZone != 0) + { + Debugprintf("C_Q_ADD %p GUARD ZONE CORRUPT %x Called from %s Line %d", PBUFF, Test->GuardZone, File, Line); + } + + Test = (PMESSAGE)Q; + + + + // Make sure address is within pool + + while (n <= NUMBEROFBUFFERS) + { + if (BUFF == Bufferlist[n++]) + goto BOK2; + } + + Debugprintf("C_Q_ADD %X not in Pool called from %s Line %d", BUFF, File, Line); + printStack(); + + return 0; + +BOK2: + + BUFF[0] = 0; // Clear chain in new buffer + + if (Q[0] == 0) // Empty + { + Q[0]=BUFF; // New one on front + return(0); + } + + next = Q[0]; + + while (next[0] != 0) + { + next = next[0]; // Chain to end of queue + } + next[0] = BUFF; // New one on end + + return(0); +} + +// Non-pool version + +int C_Q_ADD_NP(VOID *PQ, VOID *PBUFF) +{ + void ** Q; + void ** BUFF = PBUFF; + void ** next; + int n = 0; + +// PQ may not be word aligned, so copy as bytes (for ARM5) + + Q = PQ; + + if (CheckQHeadder((UINT *)Q) == 0) // Make sure Q header is readable + return(0); + + BUFF[0]=0; // Clear chain in new buffer + + if (Q[0] == 0) // Empty + { + Q[0]=BUFF; // New one on front +// memcpy(PQ, &BUFF, 4); + return 0; + } + next = Q[0]; + + while (next[0] != 0) + next=next[0]; // Chain to end of queue + + next[0] = BUFF; // New one on end + + return(0); +} + + +int C_Q_COUNT(VOID *PQ) +{ + void ** Q; + int count = 0; + +// PQ may not be word aligned, so copy as bytes (for ARM5) + + Q = PQ; + + if (CheckQHeadder((UINT *)Q) == 0) // Make sure Q header is readable + return(0); + + // SEE HOW MANY BUFFERS ATTACHED TO Q HEADER + + while (*Q) + { + count++; + if ((count + QCOUNT) > MAXBUFFS) + { + Debugprintf("C_Q_COUNT Detected corrupt Q %p len %d", PQ, count); + return count; + } + Q = *Q; + } + + return count; +} + +VOID * _GetBuff(char * File, int Line) +{ + UINT * Temp; + MESSAGE * Msg; + char * fptr = 0; + unsigned char * byteaddr; + + Temp = Q_REM(&FREE_Q); + +// FindLostBuffers(); + + if (Semaphore.Flag == 0) + Debugprintf("GetBuff called without semaphore from %s Line %d", File, Line); + + if (Temp) + { + QCOUNT--; + + if (QCOUNT < MINBUFFCOUNT) + MINBUFFCOUNT = QCOUNT; + + Msg = (MESSAGE *)Temp; + fptr = File + (int)strlen(File); + while (*fptr != '\\' && *fptr != '/') + fptr--; + fptr++; + + // Buffer Length is BUFFLEN, but buffers are allocated 512 + // So add file info in gap between + + byteaddr = (unsigned char *)Msg; + + + memset(&byteaddr[0], 0, 64); // simplify debugging lost buffers + memset(&byteaddr[400], 0, 64); // simplify debugging lost buffers + sprintf(&byteaddr[400], "%s %d", fptr, Line); + + Msg->Process = (short)GetCurrentProcessId(); + Msg->Linkptr = NULL; + Msg->Padding[0] = 0; // Used for modem status info + } + else + Debugprintf("Warning - Getbuff returned NULL"); + + return Temp; +} + +void * zalloc(int len) +{ + // malloc and clear + + void * ptr; + + ptr=malloc(len); + + if (ptr) + memset(ptr, 0, len); + + return ptr; +} + +char * strlop(char * buf, char delim) +{ + // Terminate buf at delim, and return rest of string + + char * ptr; + + if (buf == NULL) return NULL; // Protect + + ptr = strchr(buf, delim); + + if (ptr == NULL) return NULL; + + *(ptr)++=0; + + return ptr; +} + +VOID DISPLAYCIRCUIT(TRANSPORTENTRY * L4, char * Buffer) +{ + UCHAR Type = L4->L4CIRCUITTYPE; + struct PORTCONTROL * PORT; + struct _LINKTABLE * LINK; + BPQVECSTRUC * VEC; + struct DEST_LIST * DEST; + + char Normcall[20] = ""; // Could be alias:call + char Normcall2[11] = ""; + char Alias[11] = ""; + + Buffer[0] = 0; + + switch (Type) + { + case PACTOR+UPLINK: + + PORT = L4->L4TARGET.PORT; + + ConvFromAX25(L4->L4USER, Normcall); + strlop(Normcall, ' '); + + if (PORT) + sprintf(Buffer, "%s %d/%d(%s)", "TNC Uplink Port", PORT->PORTNUMBER, L4->KAMSESSION, Normcall); + + return; + + + case PACTOR+DOWNLINK: + + PORT = L4->L4TARGET.PORT; + + if (PORT) + sprintf(Buffer, "%s %d/%d", "Attached to Port", PORT->PORTNUMBER, L4->KAMSESSION); + return; + + + case L2LINK+UPLINK: + + LINK = L4->L4TARGET.LINK; + + ConvFromAX25(L4->L4USER, Normcall); + strlop(Normcall, ' '); + + if (LINK &&LINK->LINKPORT) + sprintf(Buffer, "%s %d(%s)", "Uplink", LINK->LINKPORT->PORTNUMBER, Normcall); + + return; + + case L2LINK+DOWNLINK: + + LINK = L4->L4TARGET.LINK; + + if (LINK == NULL) + return; + + ConvFromAX25(LINK->OURCALL, Normcall); + strlop(Normcall, ' '); + + ConvFromAX25(LINK->LINKCALL, Normcall2); + strlop(Normcall2, ' '); + + sprintf(Buffer, "%s %d(%s %s)", "Downlink", LINK->LINKPORT->PORTNUMBER, Normcall, Normcall2); + return; + + case BPQHOST + UPLINK: + case BPQHOST + DOWNLINK: + + // if the call has a Level 4 address display ALIAS:CALL, else just Call + + if (FindDestination(L4->L4USER, &DEST)) + Normcall[DecodeNodeName(DEST->DEST_CALL, Normcall)] = 0; // null terminate + else + Normcall[ConvFromAX25(L4->L4USER, Normcall)] = 0; + + VEC = L4->L4TARGET.HOST; + sprintf(Buffer, "%s%02d(%s)", "Host", (int)(VEC - BPQHOSTVECTOR) + 1, Normcall); + return; + + case SESSION + DOWNLINK: + case SESSION + UPLINK: + + ConvFromAX25(L4->L4USER, Normcall); + strlop(Normcall, ' '); + + DEST = L4->L4TARGET.DEST; + + if (DEST == NULL) + return; + + ConvFromAX25(DEST->DEST_CALL, Normcall2); + strlop(Normcall2, ' '); + + memcpy(Alias, DEST->DEST_ALIAS, 6); + strlop(Alias, ' '); + + sprintf(Buffer, "Circuit(%s:%s %s)", Alias, Normcall2, Normcall); + + return; + } +} + +VOID CheckForDetach(struct TNCINFO * TNC, int Stream, struct STREAMINFO * STREAM, + VOID TidyCloseProc(struct TNCINFO * TNC, int Stream), VOID ForcedCloseProc(struct TNCINFO * TNC, int Stream), VOID CloseComplete(struct TNCINFO * TNC, int Stream)) +{ + void ** buffptr; + + if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0) + { + // Node has disconnected - clear any connection + + if (STREAM->Disconnecting) + { + // Already detected the detach, and have started to close + + STREAM->DisconnectingTimeout--; + + if (STREAM->DisconnectingTimeout) + return; // Give it a bit longer + + // Close has timed out - force a disc, and clear + + ForcedCloseProc(TNC, Stream); // Send Tidy Disconnect + + goto NotConnected; + } + + // New Disconnect + + Debugprintf("New Disconnect Port %d Q %x", TNC->Port, STREAM->BPQtoPACTOR_Q); + + if (STREAM->Connected || STREAM->Connecting) + { + + // Need to do a tidy close + + STREAM->Connecting = FALSE; + STREAM->Disconnecting = TRUE; + STREAM->DisconnectingTimeout = 300; // 30 Secs + + if (Stream == 0) + SetWindowText(TNC->xIDC_TNCSTATE, "Disconnecting"); + + // Create a traffic record + + hookL4SessionDeleted(TNC, STREAM); + + if (STREAM->BPQtoPACTOR_Q) // Still data to send? + return; // Will close when all acked + +// if (STREAM->FramesOutstanding && TNC->Hardware == H_UZ7HO) +// return; // Will close when all acked + + TidyCloseProc(TNC, Stream); // Send Tidy Disconnect + + return; + } + + // Not connected +NotConnected: + + STREAM->Disconnecting = FALSE; + STREAM->Attached = FALSE; + STREAM->Connecting = FALSE; + STREAM->Connected = FALSE; + + if (Stream == 0) + SetWindowText(TNC->xIDC_TNCSTATE, "Free"); + + STREAM->FramesQueued = 0; + STREAM->FramesOutstanding = 0; + + CloseComplete(TNC, Stream); + + if (TNC->DefaultRXFreq && TNC->RXRadio) + { + char Msg[128]; + + sprintf(Msg, "R%d %f", TNC->RXRadio, TNC->DefaultRXFreq); + Rig_Command( (TRANSPORTENTRY *) -1, Msg); + } + + if (TNC->DefaultTXFreq && TNC->TXRadio && TNC->TXRadio != TNC->RXRadio) + { + char Msg[128]; + + sprintf(Msg, "R%d %f", TNC->TXRadio, TNC->DefaultTXFreq); + Rig_Command( (TRANSPORTENTRY *) -1, Msg); + } + + while(STREAM->BPQtoPACTOR_Q) + { + buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q); + ReleaseBuffer(buffptr); + } + + while(STREAM->PACTORtoBPQ_Q) + { + buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q); + ReleaseBuffer(buffptr); + } + } +} + +char * CheckAppl(struct TNCINFO * TNC, char * Appl) +{ + APPLCALLS * APPL; + BPQVECSTRUC * PORTVEC; + int Allocated = 0, Available = 0; + int App, Stream; + struct TNCINFO * APPLTNC; + +// Debugprintf("Checking if %s is running", Appl); + + for (App = 0; App < 32; App++) + { + APPL=&APPLCALLTABLE[App]; + + if (_memicmp(APPL->APPLCMD, Appl, 12) == 0) + { + int _APPLMASK = 1 << App; + + // If App has an alias, assume it is running , unless a CMS alias - then check CMS + + if (APPL->APPLHASALIAS) + { + if (_memicmp(APPL->APPLCMD, "RELAY ", 6) == 0) + return APPL->APPLCALL_TEXT; // Assume people using RELAY know what they are doing + + if (APPL->APPLPORT && (_memicmp(APPL->APPLCMD, "RMS ", 4) == 0)) + { + APPLTNC = TNCInfo[APPL->APPLPORT]; + { + if (APPLTNC) + { + if (APPLTNC->TCPInfo && !APPLTNC->TCPInfo->CMSOK && !APPLTNC->TCPInfo->FallbacktoRelay) + return NULL; + } + } + } + return APPL->APPLCALL_TEXT; + } + + // See if App is running + + PORTVEC = &BPQHOSTVECTOR[0]; + + for (Stream = 0; Stream < 64; Stream++) + { + if (PORTVEC->HOSTAPPLMASK & _APPLMASK) + { + Allocated++; + + if (PORTVEC->HOSTSESSION == 0 && (PORTVEC->HOSTFLAGS & 3) == 0) + { + // Free and no outstanding report + + return APPL->APPLCALL_TEXT; // Running + } + } + PORTVEC++; + } + } + } + + return NULL; // Not Running +} + +VOID SetApplPorts() +{ + // If any appl has an alias, get port number + + struct APPLCONFIG * App; + APPLCALLS * APPL; + + char C[80]; + char Port[80]; + char Call[80]; + + int i, n; + + App = &xxcfg.C_APPL[0]; + + for (i=0; i < NumberofAppls; i++) + { + APPL=&APPLCALLTABLE[i]; + + if (APPL->APPLHASALIAS) + { + n = sscanf(App->CommandAlias, "%s %s %s", &C[0], &Port[0], &Call[0]); + if (n == 3) + APPL->APPLPORT = atoi(Port); + } + App++; + } +} + + +char Modenames[19][10] = {"WINMOR", "SCS", "KAM", "AEA", "HAL", "TELNET", "TRK", + "V4", "UZ7HO", "MPSK", "FLDIGI", "UIARQ", "ARDOP", "VARA", + "SERIAL", "KISSHF", "WINRPR", "HSMODEM", "FREEDATA"}; + +BOOL ProcessIncommingConnect(struct TNCINFO * TNC, char * Call, int Stream, BOOL SENDCTEXT) +{ + return ProcessIncommingConnectEx(TNC, Call, Stream, SENDCTEXT, FALSE); +} + +BOOL ProcessIncommingConnectEx(struct TNCINFO * TNC, char * Call, int Stream, BOOL SENDCTEXT, BOOL AllowTR) +{ + TRANSPORTENTRY * Session; + int Index = 0; + PMSGWITHLEN buffptr; + int Totallen = 0; + UCHAR * ptr; + struct PORTCONTROL * PORT = (struct PORTCONTROL *)TNC->PortRecord; + struct STREAMINFO * STREAM = &TNC->Streams[Stream]; + + // Stop Scanner + + if (Stream == 0 || TNC->Hardware == H_UZ7HO) + { + char Msg[80]; + + sprintf(Msg, "%d SCANSTOP", TNC->Port); + + Rig_Command( (TRANSPORTENTRY *) -1, Msg); + + UpdateMH(TNC, Call, '+', 'I'); + } + + Session = L4TABLE; + + // Find a free Circuit Entry + + while (Index < MAXCIRCUITS) + { + if (Session->L4USER[0] == 0) + break; + + Session++; + Index++; + } + + if (Index == MAXCIRCUITS) + return FALSE; // Tables Full + + memset(Session, 0, sizeof(TRANSPORTENTRY)); + + memcpy(STREAM->RemoteCall, Call, 9); // Save Text Callsign + + // May be subsequently rejected but a good place to capture calls + + hookL4SessionAccepted(STREAM, Call, TNC->TargetCall); + + if (AllowTR) + ConvToAX25Ex(Call, Session->L4USER); // Allow -T and -R SSID's for MPS + else + ConvToAX25(Call, Session->L4USER); + ConvToAX25(MYNODECALL, Session->L4MYCALL); + Session->CIRCUITINDEX = Index; + Session->CIRCUITID = NEXTID; + NEXTID++; + if (NEXTID == 0) NEXTID++; // Keep non-zero + + TNC->PortRecord->ATTACHEDSESSIONS[Stream] = Session; + STREAM->Attached = TRUE; + + Session->L4TARGET.EXTPORT = TNC->PortRecord; + + Session->L4CIRCUITTYPE = UPLINK+PACTOR; + Session->L4WINDOW = L4DEFAULTWINDOW; + Session->L4STATE = 5; + Session->SESSIONT1 = L4T1; + Session->SESSPACLEN = TNC->PortRecord->PORTCONTROL.PORTPACLEN; + Session->KAMSESSION = Stream; + + STREAM->Connected = TRUE; // Subsequent data to data channel + + if (LogAllConnects) + { + if (TNC->TargetCall[0]) + WriteConnectLog(Call, TNC->TargetCall, Modenames[TNC->Hardware - 1]); + else + WriteConnectLog(Call, MYNODECALL, Modenames[TNC->Hardware - 1]); + } + + if (SENDCTEXT == 0) + return TRUE; + + // if Port CTEXT defined, use it + + if (PORT->CTEXT) + { + Totallen = strlen(PORT->CTEXT); + ptr = PORT->CTEXT; + } + else if (HFCTEXTLEN > 0) + { + Totallen = HFCTEXTLEN; + ptr = HFCTEXT; + } + else + return TRUE; + + while (Totallen > 0) + { + int sendLen = TNC->PortRecord->ATTACHEDSESSIONS[Stream]->SESSPACLEN; + + if (sendLen == 0) + sendLen = 80; + + if (Totallen < sendLen) + sendLen = Totallen; + + buffptr = (PMSGWITHLEN)GetBuff(); + if (buffptr == 0) return TRUE; // No buffers + + buffptr->Len = sendLen; + memcpy(&buffptr->Data[0], ptr, sendLen); + C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr); + Totallen -= sendLen; + ptr += sendLen; + } + return TRUE; +} + +char * Config; +static char * ptr1, * ptr2; + +BOOL ReadConfigFile(int Port, int ProcLine(char * buf, int Port)) +{ + char buf[256],errbuf[256]; + + if (TNCInfo[Port]) // If restarting, free old config + free(TNCInfo[Port]); + + TNCInfo[Port] = NULL; + + Config = PortConfig[Port]; + + if (Config) + { + // Using config from bpq32.cfg + + if (strlen(Config) == 0) + { + // Empty Config File - OK for most types + + struct TNCINFO * TNC = TNCInfo[Port] = zalloc(sizeof(struct TNCINFO)); + + TNC->InitScript = malloc(2); + TNC->InitScript[0] = 0; + + return TRUE; + } + + ptr1 = Config; + + ptr2 = strchr(ptr1, 13); + while(ptr2) + { + memcpy(buf, ptr1, ptr2 - ptr1 + 1); + buf[ptr2 - ptr1 + 1] = 0; + ptr1 = ptr2 + 2; + ptr2 = strchr(ptr1, 13); + + strcpy(errbuf,buf); // save in case of error + + if (!ProcLine(buf, Port)) + { + WritetoConsoleLocal("\n"); + WritetoConsoleLocal("Bad config record "); + WritetoConsoleLocal(errbuf); + } + } + } + else + { + sprintf(buf," ** Error - No Configuration info in bpq32.cfg"); + WritetoConsoleLocal(buf); + } + + return (TRUE); +} +int GetLine(char * buf) +{ +loop: + + if (ptr2 == NULL) + return 0; + + memcpy(buf, ptr1, ptr2 - ptr1 + 2); + buf[ptr2 - ptr1 + 2] = 0; + ptr1 = ptr2 + 2; + ptr2 = strchr(ptr1, 13); + + if (buf[0] < 0x20) goto loop; + if (buf[0] == '#') goto loop; + if (buf[0] == ';') goto loop; + + if (buf[strlen(buf)-1] < 0x20) buf[strlen(buf)-1] = 0; + if (buf[strlen(buf)-1] < 0x20) buf[strlen(buf)-1] = 0; + buf[strlen(buf)] = 13; + + return 1; +} +VOID DigiToMultiplePorts(struct PORTCONTROL * PORTVEC, PMESSAGE Msg) +{ + USHORT Mask=PORTVEC->DIGIMASK; + int i; + + for (i=1; i<=NUMBEROFPORTS; i++) + { + if (Mask & 1) + { + // Block includes the Msg Header (7/11 bytes), Len Does not! + + Msg->PORT = i; + Send_AX((UCHAR *)&Msg, Msg->LENGTH - MSGHDDRLEN, i); + Mask>>=1; + } + } +} + +int CompareAlias(struct DEST_LIST ** a, struct DEST_LIST ** b) +{ + return memcmp(a[0]->DEST_ALIAS, b[0]->DEST_ALIAS, 6); + /* strcmp functions works exactly as expected from comparison function */ +} + + +int CompareNode(struct DEST_LIST ** a, struct DEST_LIST ** b) +{ + return memcmp(a[0]->DEST_CALL, b[0]->DEST_CALL, 7); +} + +DllExport int APIENTRY CountFramesQueuedOnStream(int Stream) +{ + BPQVECSTRUC * PORTVEC = &BPQHOSTVECTOR[Stream-1]; // API counts from 1 + TRANSPORTENTRY * L4 = PORTVEC->HOSTSESSION; + + int Count = 0; + + if (L4) + { + if (L4->L4CROSSLINK) // CONNECTED? + Count = CountFramesQueuedOnSession(L4->L4CROSSLINK); + else + Count = CountFramesQueuedOnSession(L4); + } + return Count; +} + +DllExport int APIENTRY ChangeSessionCallsign(int Stream, unsigned char * AXCall) +{ + // Equivalent to "*** linked to" command + + memcpy(BPQHOSTVECTOR[Stream-1].HOSTSESSION->L4USER, AXCall, 7); + return (0); +} + +DllExport int APIENTRY ChangeSessionPaclen(int Stream, int Paclen) +{ + BPQHOSTVECTOR[Stream-1].HOSTSESSION->SESSPACLEN = Paclen; + return (0); +} + +DllExport int APIENTRY ChangeSessionIdletime(int Stream, int idletime) +{ + if (BPQHOSTVECTOR[Stream-1].HOSTSESSION) + BPQHOSTVECTOR[Stream-1].HOSTSESSION->L4LIMIT = idletime; + return (0); +} + +DllExport int APIENTRY Get_APPLMASK(int Stream) +{ + return BPQHOSTVECTOR[Stream-1].HOSTAPPLMASK; +} +DllExport int APIENTRY GetStreamPID(int Stream) +{ + return BPQHOSTVECTOR[Stream-1].STREAMOWNER; +} + +DllExport int APIENTRY GetApplFlags(int Stream) +{ + return BPQHOSTVECTOR[Stream-1].HOSTAPPLFLAGS; +} + +DllExport int APIENTRY GetApplNum(int Stream) +{ + return BPQHOSTVECTOR[Stream-1].HOSTAPPLNUM; +} + +DllExport int APIENTRY GetApplMask(int Stream) +{ + return BPQHOSTVECTOR[Stream-1].HOSTAPPLMASK; +} + +DllExport BOOL APIENTRY GetAllocationState(int Stream) +{ + return BPQHOSTVECTOR[Stream-1].HOSTFLAGS & 0x80; +} + +VOID Send_AX_Datagram(PDIGIMESSAGE Block, DWORD Len, UCHAR Port); + +extern int InitDone; +extern int SemHeldByAPI; +extern char pgm[256]; // Uninitialised so per process +extern int BPQHOSTAPI(); + + +VOID POSTSTATECHANGE(BPQVECSTRUC * SESS) +{ + // Post a message if requested +#ifndef LINBPQ + if (SESS->HOSTHANDLE) + PostMessage(SESS->HOSTHANDLE, BPQMsg, SESS->HOSTSTREAM, 4); +#endif + return; +} + + +DllExport int APIENTRY SessionControl(int stream, int command, int Mask) +{ + BPQVECSTRUC * SESS; + TRANSPORTENTRY * L4; + + stream--; // API uses 1 - 64 + + if (stream < 0 || stream > 63) + return (0); + + SESS = &BPQHOSTVECTOR[stream]; + + // Send Session Control command (BPQHOST function 6) + //; CL=0 CONNECT USING APPL MASK IN DL + //; CL=1, CONNECT. CL=2 - DISCONNECT. CL=3 RETURN TO NODE + + if (command > 1) + { + // Disconnect + + if (SESS->HOSTSESSION == 0) + { + SESS->HOSTFLAGS |= 1; // State Change + POSTSTATECHANGE(SESS); + return 0; // NOT CONNECTED + } + + if (command == 3) + SESS->HOSTFLAGS |= 0x20; // Set Stay + + SESS->HOSTFLAGS |= 0x40; // SET 'DISC REQ' FLAG + + return 0; + } + + // 0 or 1 - connect + + if (SESS->HOSTSESSION) // ALREADY CONNECTED + { + SESS->HOSTFLAGS |= 1; // State Change + POSTSTATECHANGE(SESS); + return 0; + } + + // SET UP A SESSION FOR THE CONSOLE + + SESS->HOSTFLAGS |= 0x80; // SET ALLOCATED BIT + + if (command == 1) // Zero is mask supplied by caller + Mask = SESS->HOSTAPPLMASK; // SO WE GET CORRECT CALLSIGN + + L4 = SetupSessionFromHost(SESS, Mask); + + if (L4 == 0) // tables Full + { + SESS->HOSTFLAGS |= 3; // State Change + POSTSTATECHANGE(SESS); + return 0; + } + + SESS->HOSTSESSION = L4; + L4->L4CIRCUITTYPE = BPQHOST | UPLINK; + L4->Secure_Session = AuthorisedProgram; // Secure Host Session + + SESS->HOSTFLAGS |= 1; // State Change + POSTSTATECHANGE(SESS); + return 0; // ALREADY CONNECTED +} + +int FindFreeStreamEx(int GetSem); + +int FindFreeStreamNoSem() +{ + return FindFreeStreamEx(0); +} + +DllExport int APIENTRY FindFreeStream() +{ + return FindFreeStreamEx(1); +} + +int FindFreeStreamEx(int GetSem) +{ + int stream, n; + BPQVECSTRUC * PORTVEC; + +// Returns number of first unused BPQHOST stream. If none available, +// returns 255. See API function 13. + + // if init has not yet been run, wait. + + while (InitDone == 0) + { + Debugprintf("Waiting for init to complete"); + Sleep(1000); + } + + if (InitDone == -1) // Init failed + exit(0); + + if (GetSem) + GetSemaphore(&Semaphore, 9); + + stream = 0; + n = 64; + + while (n--) + { + PORTVEC = &BPQHOSTVECTOR[stream++]; + if ((PORTVEC->HOSTFLAGS & 0x80) == 0) + { + PORTVEC->STREAMOWNER=GetCurrentProcessId(); + PORTVEC->HOSTFLAGS = 128; // SET ALLOCATED BIT, clear others + memcpy(&PORTVEC->PgmName[0], pgm, 31); + if (GetSem) + FreeSemaphore(&Semaphore); + return stream; + } + } + + if (GetSem) + FreeSemaphore(&Semaphore); + + return 255; +} + +DllExport int APIENTRY AllocateStream(int stream) +{ +// Allocate stream. If stream is already allocated, return nonzero. +// Otherwise allocate stream, and return zero. + + BPQVECSTRUC * PORTVEC = &BPQHOSTVECTOR[stream -1]; // API counts from 1 + + if ((PORTVEC->HOSTFLAGS & 0x80) == 0) + { + PORTVEC->STREAMOWNER=GetCurrentProcessId(); + PORTVEC->HOSTFLAGS = 128; // SET ALLOCATED BIT, clear others + memcpy(&PORTVEC->PgmName[0], pgm, 31); + FreeSemaphore(&Semaphore); + return 0; + } + + return 1; // Already allocated +} + + +DllExport int APIENTRY DeallocateStream(int stream) +{ + BPQVECSTRUC * PORTVEC; + UINT * monbuff; + BOOL GotSem = Semaphore.Flag; + +// Release stream. + + stream--; + + if (stream < 0 || stream > 63) + return (0); + + PORTVEC=&BPQHOSTVECTOR[stream]; + + PORTVEC->STREAMOWNER=0; + PORTVEC->PgmName[0] = 0; + PORTVEC->HOSTAPPLFLAGS=0; + PORTVEC->HOSTAPPLMASK=0; + PORTVEC->HOSTHANDLE=0; + + // Clear Trace Queue + + if (PORTVEC->HOSTSESSION) + SessionControl(stream + 1, 2, 0); + + if (GotSem == 0) + GetSemaphore(&Semaphore, 0); + + while (PORTVEC->HOSTTRACEQ) + { + monbuff = Q_REM((void *)&PORTVEC->HOSTTRACEQ); + ReleaseBuffer(monbuff); + } + + if (GotSem == 0) + FreeSemaphore(&Semaphore); + + PORTVEC->HOSTFLAGS &= 0x60; // Clear Allocated. Must leave any DISC Pending bits + + return(0); +} +DllExport int APIENTRY SessionState(int stream, int * state, int * change) +{ + // Get current Session State. Any state changed is ACK'ed + // automatically. See BPQHOST functions 4 and 5. + + BPQVECSTRUC * HOST = &BPQHOSTVECTOR[stream -1]; // API counts from 1 + + Check_Timer(); // In case Appl doesnt call it often ehough + + GetSemaphore(&Semaphore, 20); + + // CX = 0 if stream disconnected or CX = 1 if stream connected + // DX = 0 if no change of state since last read, or DX = 1 if + // the connected/disconnected state has changed since + // last read (ie. delta-stream status). + + // HOSTFLAGS = Bit 80 = Allocated + // Bit 40 = Disc Request + // Bit 20 = Stay Flag + // Bit 02 and 01 State Change Bits + + if ((HOST->HOSTFLAGS & 3) == 0) + // No Chaange + *change = 0; + else + *change = 1; + + if (HOST->HOSTSESSION) // LOCAL SESSION + // Connected + *state = 1; + else + *state = 0; + + HOST->HOSTFLAGS &= 0xFC; // Clear Change Bitd + + FreeSemaphore(&Semaphore); + return 0; +} + +DllExport int APIENTRY SessionStateNoAck(int stream, int * state) +{ + // Get current Session State. Dont ACK any change + // See BPQHOST function 4 + + BPQVECSTRUC * HOST = &BPQHOSTVECTOR[stream -1]; // API counts from 1 + + Check_Timer(); // In case Appl doesnt call it often ehough + + if (HOST->HOSTSESSION) // LOCAL SESSION + // Connected + *state = 1; + else + *state = 0; + + return 0; +} + + +int SendMsgEx(int stream, char * msg, int len, int GetSem); + +int SendMsgNoSem(int stream, char * msg, int len) +{ + return SendMsgEx(stream, msg, len, 0); +} + +DllExport int APIENTRY SendMsg(int stream, char * msg, int len) +{ + return SendMsgEx(stream, msg, len, 1); +} + + +int SendMsgEx(int stream, char * msg, int len, int GetSem) +{ + // Send message to stream (BPQHOST Function 2) + + BPQVECSTRUC * SESS; + TRANSPORTENTRY * L4; + TRANSPORTENTRY * Partner; + PDATAMESSAGE MSG; + + Check_Timer(); + + if (len > 256) + return 0; // IGNORE + + if (stream == 0) + { + // Send UNPROTO - SEND FRAME TO ALL RADIO PORTS + + // COPY DATA TO A BUFFER IN OUR SEGMENTS - SIMPLFIES THINGS LATER + + if (QCOUNT < 50) + return 0; // Dont want to run out + + if (GetSem) + GetSemaphore(&Semaphore, 10); + + if ((MSG = GetBuff()) == 0) + { + if (GetSem) + FreeSemaphore(&Semaphore); + return 0; + } + + MSG->PID = 0xF0; // Normal Data PID + + memcpy(&MSG->L2DATA[0], msg, len); + MSG->LENGTH = (len + MSGHDDRLEN + 1); + + SENDUIMESSAGE(MSG); + ReleaseBuffer(MSG); + if (GetSem) + FreeSemaphore(&Semaphore); + return 0; + } + + stream--; // API uses 1 - 64 + + if (stream < 0 || stream > 63) + return 0; + + SESS = &BPQHOSTVECTOR[stream]; + L4 = SESS->HOSTSESSION; + + if (L4 == 0) + return 0; + + if (GetSem) + GetSemaphore(&Semaphore, 22); + + SESS->HOSTFLAGS |= 0x80; // SET ALLOCATED BIT + + if (QCOUNT < 40) // PLENTY FREE? + { + if (GetSem) + FreeSemaphore(&Semaphore); + return 1; + } + + // Dont allow massive queues to form + + if (QCOUNT < 100) + { + int n = CountFramesQueuedOnStream(stream + 1); + + if (n > 100) + { + Debugprintf("Stream %d QCOUNT %d Q Len %d - discarding", stream, QCOUNT, n); + if (GetSem) + FreeSemaphore(&Semaphore); + return 1; + } + } + + if ((MSG = GetBuff()) == 0) + { + if (GetSem) + FreeSemaphore(&Semaphore); + return 1; + } + + MSG->PID = 0xF0; // Normal Data PID + + memcpy(&MSG->L2DATA[0], msg, len); + MSG->LENGTH = len + MSGHDDRLEN + 1; + + // IF CONNECTED, PASS MESSAGE TO TARGET CIRCUIT - FLOW CONTROL AND + // DELAYED DISC ONLY WORK ON ONE SIDE + + Partner = L4->L4CROSSLINK; + + L4->L4KILLTIMER = 0; // RESET SESSION TIMEOUT + + if (Partner && Partner->L4STATE > 4) // Partner and link up + { + // Connected + + Partner->L4KILLTIMER = 0; // RESET SESSION TIMEOUT + C_Q_ADD(&Partner->L4TX_Q, MSG); + PostDataAvailable(Partner); + } + else + C_Q_ADD(&L4->L4RX_Q, MSG); + + if (GetSem) + FreeSemaphore(&Semaphore); + return 0; +} +DllExport int APIENTRY SendRaw(int port, char * msg, int len) +{ + struct PORTCONTROL * PORT; + MESSAGE * MSG; + + Check_Timer(); + + // Send Raw (KISS mode) frame to port (BPQHOST function 10) + + if (len > (MAXDATA - (MSGHDDRLEN + 8))) + return 0; + + if (QCOUNT < 50) + return 1; + + // GET A BUFFER + + PORT = GetPortTableEntryFromSlot(port); + + if (PORT == 0) + return 0; + + GetSemaphore(&Semaphore, 24); + + MSG = GetBuff(); + + if (MSG == 0) + { + FreeSemaphore(&Semaphore); + return 1; + } + + memcpy(MSG->DEST, msg, len); + + MSG->LENGTH = len + MSGHDDRLEN; + + if (PORT->PROTOCOL == 10 && PORT->TNC && PORT->TNC->Hardware != H_KISSHF) // PACTOR/WINMOR Style + { + // Pactor Style. Probably will only be used for Tracker unless we do APRS over V4 or WINMOR + + EXTPORTDATA * EXTPORT = (EXTPORTDATA *) PORT; + + C_Q_ADD(&EXTPORT->UI_Q, MSG); + + FreeSemaphore(&Semaphore); + return 0; + } + + MSG->PORT = PORT->PORTNUMBER; + + PUT_ON_PORT_Q(PORT, MSG); + + FreeSemaphore(&Semaphore); + return 0; +} + +DllExport time_t APIENTRY GetRaw(int stream, char * msg, int * len, int * count) +{ + time_t Stamp; + BPQVECSTRUC * SESS; + PMESSAGE MSG; + int Msglen; + + Check_Timer(); + + *len = 0; + *count = 0; + + stream--; // API uses 1 - 64 + + if (stream < 0 || stream > 63) + return 0; + + SESS = &BPQHOSTVECTOR[stream]; + + GetSemaphore(&Semaphore, 26); + + if (SESS->HOSTTRACEQ == 0) + { + FreeSemaphore(&Semaphore); + return 0; + } + + MSG = Q_REM((void *)&SESS->HOSTTRACEQ); + + Msglen = MSG->LENGTH; + + if (Msglen < 0 || Msglen > 350) + { + FreeSemaphore(&Semaphore); + return 0; + } + + Stamp = MSG->Timestamp; + + memcpy(msg, MSG, BUFFLEN - sizeof(void *)); // To c + + *len = Msglen; + + ReleaseBuffer(MSG); + + *count = C_Q_COUNT(&SESS->HOSTTRACEQ); + FreeSemaphore(&Semaphore); + + return Stamp; +} + +DllExport int APIENTRY GetMsg(int stream, char * msg, int * len, int * count ) +{ +// Get message from stream. Returns length, and count of frames +// still waiting to be collected. (BPQHOST function 3) +// AH = 3 Receive frame into buffer at ES:DI, length of frame returned +// in CX. BX returns the number of outstanding frames still to +// be received (ie. after this one) or zero if no more frames +// (ie. this is last one). +// + + BPQVECSTRUC * SESS; + TRANSPORTENTRY * L4; + PDATAMESSAGE MSG; + int Msglen; + + Check_Timer(); + + *len = 0; + *count = 0; + + stream--; // API uses 1 - 64 + + if (stream < 0 || stream > 63) + return 0; + + + SESS = &BPQHOSTVECTOR[stream]; + L4 = SESS->HOSTSESSION; + + GetSemaphore(&Semaphore, 25); + + if (L4 == 0 || L4->L4TX_Q == 0) + { + FreeSemaphore(&Semaphore); + return 0; + } + + L4->L4KILLTIMER = 0; // RESET SESSION TIMEOUT + + if(L4->L4CROSSLINK) + L4->L4CROSSLINK->L4KILLTIMER = 0; + + MSG = Q_REM((void *)&L4->L4TX_Q); + + Msglen = MSG->LENGTH - (MSGHDDRLEN + 1); // Dont want PID + + if (Msglen < 0) + { + FreeSemaphore(&Semaphore); + return 0; + } + + if (Msglen > 256) + Msglen = 256; + + memcpy(msg, &MSG->L2DATA[0], Msglen); + + *len = Msglen; + + ReleaseBuffer(MSG); + + *count = C_Q_COUNT(&L4->L4TX_Q); + FreeSemaphore(&Semaphore); + + return 0; +} + + +DllExport int APIENTRY RXCount(int stream) +{ +// Returns count of packets waiting on stream +// (BPQHOST function 7 (part)). + + BPQVECSTRUC * SESS; + TRANSPORTENTRY * L4; + + Check_Timer(); + + stream--; // API uses 1 - 64 + + if (stream < 0 || stream > 63) + return 0; + + SESS = &BPQHOSTVECTOR[stream]; + L4 = SESS->HOSTSESSION; + + if (L4 == 0) + return 0; // NOT CONNECTED + + return C_Q_COUNT(&L4->L4TX_Q); +} + +DllExport int APIENTRY TXCount(int stream) +{ +// Returns number of packets on TX queue for stream +// (BPQHOST function 7 (part)). + + BPQVECSTRUC * SESS; + TRANSPORTENTRY * L4; + + Check_Timer(); + + stream--; // API uses 1 - 64 + + if (stream < 0 || stream > 63) + return 0; + + SESS = &BPQHOSTVECTOR[stream]; + L4 = SESS->HOSTSESSION; + + if (L4 == 0) + return 0; // NOT CONNECTED + + L4 = L4->L4CROSSLINK; + + if (L4 == 0) + return 0; // NOTHING ro Q on + + return (CountFramesQueuedOnSession(L4)); +} + +DllExport int APIENTRY MONCount(int stream) +{ +// Returns number of monitor frames available +// (BPQHOST function 7 (part)). + + BPQVECSTRUC * SESS; + + Check_Timer(); + + stream--; // API uses 1 - 64 + + if (stream < 0 || stream > 63) + return 0; + + SESS = &BPQHOSTVECTOR[stream]; + + return C_Q_COUNT(&SESS->HOSTTRACEQ); +} + + +DllExport int APIENTRY GetCallsign(int stream, char * callsign) +{ + // Returns call connected on stream (BPQHOST function 8 (part)). + + BPQVECSTRUC * SESS; + TRANSPORTENTRY * L4; + TRANSPORTENTRY * Partner; + UCHAR Call[11] = "SWITCH "; + UCHAR * AXCall = NULL; + Check_Timer(); + + stream--; // API uses 1 - 64 + + if (stream < 0 || stream > 63) + return 0; + + SESS = &BPQHOSTVECTOR[stream]; + L4 = SESS->HOSTSESSION; + + GetSemaphore(&Semaphore, 26); + + if (L4 == 0) + { + FreeSemaphore(&Semaphore); + return 0; + } + + Partner = L4->L4CROSSLINK; + + if (Partner) + { + // CONNECTED OUT - GET TARGET SESSION + + if (Partner->L4CIRCUITTYPE & BPQHOST) + { + AXCall = &Partner->L4USER[0]; + } + else if (Partner->L4CIRCUITTYPE & L2LINK) + { + struct _LINKTABLE * LINK = Partner->L4TARGET.LINK; + + if (LINK) + AXCall = LINK->LINKCALL; + + if (Partner->L4CIRCUITTYPE & UPLINK) + { + // IF UPLINK, SHOULD USE SESSION CALL, IN CASE *** LINKED HAS BEEN USED + + AXCall = &Partner->L4USER[0]; + } + } + else if (Partner->L4CIRCUITTYPE & PACTOR) + { + // PACTOR Type - Frames are queued on the Port Entry + + EXTPORTDATA * EXTPORT = Partner->L4TARGET.EXTPORT; + + if (EXTPORT) + AXCall = &EXTPORT->ATTACHEDSESSIONS[Partner->KAMSESSION]->L4USER[0]; + + } + else + { + // MUST BE NODE SESSION + + // ANOTHER NODE + + // IF THE HOST IS THE UPLINKING STATION, WE NEED THE TARGET CALL + + if (L4->L4CIRCUITTYPE & UPLINK) + { + struct DEST_LIST *DEST = Partner->L4TARGET.DEST; + + if (DEST) + AXCall = &DEST->DEST_CALL[0]; + } + else + AXCall = Partner->L4USER; + } + if (AXCall) + ConvFromAX25(AXCall, Call); + } + + memcpy(callsign, Call, 10); + + FreeSemaphore(&Semaphore); + return 0; +} + +DllExport int APIENTRY GetConnectionInfo(int stream, char * callsign, + int * port, int * sesstype, int * paclen, + int * maxframe, int * l4window) +{ + // Return the Secure Session Flag rather than not connected + + BPQVECSTRUC * SESS; + TRANSPORTENTRY * L4; + TRANSPORTENTRY * Partner; + UCHAR Call[11] = "SWITCH "; + UCHAR * AXCall; + Check_Timer(); + + stream--; // API uses 1 - 64 + + if (stream < 0 || stream > 63) + return 0; + + SESS = &BPQHOSTVECTOR[stream]; + L4 = SESS->HOSTSESSION; + + GetSemaphore(&Semaphore, 27); + + if (L4 == 0) + { + FreeSemaphore(&Semaphore); + return 0; + } + + Partner = L4->L4CROSSLINK; + + // Return the Secure Session Flag rather than not connected + + // AL = Radio port on which channel is connected (or zero) + // AH = SESSION TYPE BITS + // EBX = L2 paclen for the radio port + // ECX = L2 maxframe for the radio port + // EDX = L4 window size (if L4 circuit, or zero) or -1 if not connected + // ES:DI = CALLSIGN + + *port = 0; + *sesstype = 0; + *paclen = 0; + *maxframe = 0; + *l4window = 0; + if (L4->SESSPACLEN) + *paclen = L4->SESSPACLEN; + else + *paclen = 256; + + if (Partner) + { + // CONNECTED OUT - GET TARGET SESSION + + *l4window = Partner->L4WINDOW; + *sesstype = Partner->L4CIRCUITTYPE; + + if (Partner->L4CIRCUITTYPE & BPQHOST) + { + AXCall = &Partner->L4USER[0]; + } + else if (Partner->L4CIRCUITTYPE & L2LINK) + { + struct _LINKTABLE * LINK = Partner->L4TARGET.LINK; + + // EXTRACT PORT AND MAXFRAME + + *port = LINK->LINKPORT->PORTNUMBER; + *maxframe = LINK->LINKWINDOW; + *l4window = 0; + + AXCall = LINK->LINKCALL; + + if (Partner->L4CIRCUITTYPE & UPLINK) + { + // IF UPLINK, SHOULD USE SESSION CALL, IN CASE *** LINKED HAS BEEN USED + + AXCall = &Partner->L4USER[0]; + } + } + else if (Partner->L4CIRCUITTYPE & PACTOR) + { + // PACTOR Type - Frames are queued on the Port Entry + + EXTPORTDATA * EXTPORT = Partner->L4TARGET.EXTPORT; + + *port = EXTPORT->PORTCONTROL.PORTNUMBER; + AXCall = &EXTPORT->ATTACHEDSESSIONS[Partner->KAMSESSION]->L4USER[0]; + + } + else + { + // MUST BE NODE SESSION + + // ANOTHER NODE + + // IF THE HOST IS THE UPLINKING STATION, WE NEED THE TARGET CALL + + if (L4->L4CIRCUITTYPE & UPLINK) + { + struct DEST_LIST *DEST = Partner->L4TARGET.DEST; + + AXCall = &DEST->DEST_CALL[0]; + } + else + AXCall = Partner->L4USER; + } + ConvFromAX25(AXCall, Call); + } + + memcpy(callsign, Call, 10); + + FreeSemaphore(&Semaphore); + + if (Partner) + return Partner->Secure_Session; + + return 0; +} + + +DllExport int APIENTRY SetAppl(int stream, int flags, int mask) +{ +// Sets Application Flags and Mask for stream. (BPQHOST function 1) +// AH = 1 Set application mask to value in EDX (or even DX if 16 +// applications are ever to be supported). +// +// Set application flag(s) to value in CL (or CX). +// whether user gets connected/disconnected messages issued +// by the node etc. + + + BPQVECSTRUC * PORTVEC; + stream--; + + if (stream < 0 || stream > 63) + return (0); + + PORTVEC=&BPQHOSTVECTOR[stream]; + + PORTVEC->HOSTAPPLFLAGS = flags; + PORTVEC->HOSTAPPLMASK = mask; + + // If either is non-zero, set allocated and Process. This gets round problem with + // stations that don't call allocate stream + + if (flags || mask) + { + if ((PORTVEC->HOSTFLAGS & 128) == 0) // Not allocated + { + PORTVEC->STREAMOWNER=GetCurrentProcessId(); + memcpy(&PORTVEC->PgmName[0], pgm, 31); + PORTVEC->HOSTFLAGS = 128; // SET ALLOCATED BIT, clear others + } + } + + return (0); +} + +DllExport struct PORTCONTROL * APIENTRY GetPortTableEntry(int portslot) // Kept for Legacy apps +{ + struct PORTCONTROL * PORTVEC=PORTTABLE; + + if (portslot>NUMBEROFPORTS) + portslot=NUMBEROFPORTS; + + while (--portslot > 0) + PORTVEC=PORTVEC->PORTPOINTER; + + return PORTVEC; +} + +// Proc below renamed to avoid confusion with GetPortTableEntryFromPortNum + +DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot) +{ + struct PORTCONTROL * PORTVEC=PORTTABLE; + + if (portslot>NUMBEROFPORTS) + portslot=NUMBEROFPORTS; + + while (--portslot > 0) + PORTVEC=PORTVEC->PORTPOINTER; + + return PORTVEC; +} + +int CanPortDigi(int Port) +{ + struct PORTCONTROL * PORTVEC = GetPortTableEntryFromPortNum(Port); + struct TNCINFO * TNC; + + if (PORTVEC == NULL) + return FALSE; + + TNC = PORTVEC->TNC; + + if (TNC == NULL) + return TRUE; + + if (TNC->Hardware == H_SCS || TNC->Hardware == H_TRK || TNC->Hardware == H_TRKM || TNC->Hardware == H_WINRPR) + return FALSE; + + return TRUE; +} + +struct PORTCONTROL * APIENTRY GetPortTableEntryFromPortNum(int portnum) +{ + struct PORTCONTROL * PORTVEC = PORTTABLE; + + do + { + if (PORTVEC->PORTNUMBER == portnum) + return PORTVEC; + + PORTVEC=PORTVEC->PORTPOINTER; + } + while (PORTVEC); + + return NULL; +} + +DllExport UCHAR * APIENTRY GetPortDescription(int portslot, char * Desc) +{ + struct PORTCONTROL * PORTVEC=PORTTABLE; + + if (portslot>NUMBEROFPORTS) + portslot=NUMBEROFPORTS; + + while (--portslot > 0) + PORTVEC=PORTVEC->PORTPOINTER; + + memcpy(Desc, PORTVEC->PORTDESCRIPTION, 30); + Desc[30]=0; + + return 0; +} + +// Standard serial port handling routines, used by lots of modules. + +int OpenCOMMPort(struct TNCINFO * conn, char * Port, int Speed, BOOL Quiet) +{ + if (conn->WEB_COMMSSTATE == NULL) + conn->WEB_COMMSSTATE = zalloc(100); + + if (Port == NULL) + return (FALSE); + + conn->hDevice = OpenCOMPort(Port, Speed, TRUE, TRUE, Quiet, 0); + + if (conn->hDevice == 0) + { + sprintf(conn->WEB_COMMSSTATE,"%s Open failed - Error %d", Port, GetLastError()); + if (conn->xIDC_COMMSSTATE) + SetWindowText(conn->xIDC_COMMSSTATE, conn->WEB_COMMSSTATE); + + return (FALSE); + } + + sprintf(conn->WEB_COMMSSTATE,"%s Open", Port); + + if (conn->xIDC_COMMSSTATE) + SetWindowText(conn->xIDC_COMMSSTATE, conn->WEB_COMMSSTATE); + + return TRUE; +} + + + +#ifdef WIN32 + +HANDLE OpenCOMPort(char * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits) +{ + char szPort[256]; + BOOL fRetVal ; + COMMTIMEOUTS CommTimeOuts ; + int Err; + char buf[100]; + HANDLE fd; + DCB dcb; + + // if Port Name starts COM, convert to \\.\COM or ports above 10 wont work + + if (_memicmp(pPort, "COM", 3) == 0) + { + char * pp = (char *)pPort; + int p = atoi(&pp[3]); + sprintf( szPort, "\\\\.\\COM%d", p); + } + else + strcpy(szPort, pPort); + + // open COMM device + + fd = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, + 0, // exclusive access + NULL, // no security attrs + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if (fd == (HANDLE) -1) + { + if (Quiet == 0) + { + Debugprintf("%s could not be opened %d", pPort, GetLastError()); + } + return (FALSE); + } + + Err = GetFileType(fd); + + // setup device buffers + + SetupComm(fd, 4096, 4096 ) ; + + // purge any information in the buffer + + PurgeComm(fd, PURGE_TXABORT | PURGE_RXABORT | + PURGE_TXCLEAR | PURGE_RXCLEAR ) ; + + // set up for overlapped I/O + + CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF ; + CommTimeOuts.ReadTotalTimeoutMultiplier = 0 ; + CommTimeOuts.ReadTotalTimeoutConstant = 0 ; + CommTimeOuts.WriteTotalTimeoutMultiplier = 0 ; +// CommTimeOuts.WriteTotalTimeoutConstant = 0 ; + CommTimeOuts.WriteTotalTimeoutConstant = 500 ; + SetCommTimeouts(fd, &CommTimeOuts ) ; + + dcb.DCBlength = sizeof( DCB ) ; + + GetCommState(fd, &dcb ) ; + + dcb.BaudRate = speed; + dcb.ByteSize = 8; + dcb.Parity = 0; + dcb.StopBits = TWOSTOPBITS; + dcb.StopBits = Stopbits; + + // setup hardware flow control + + dcb.fOutxDsrFlow = 0; + dcb.fDtrControl = DTR_CONTROL_DISABLE ; + + dcb.fOutxCtsFlow = 0; + dcb.fRtsControl = RTS_CONTROL_DISABLE ; + + // setup software flow control + + dcb.fInX = dcb.fOutX = 0; + dcb.XonChar = 0; + dcb.XoffChar = 0; + dcb.XonLim = 100 ; + dcb.XoffLim = 100 ; + + // other various settings + + dcb.fBinary = TRUE ; + dcb.fParity = FALSE; + + fRetVal = SetCommState(fd, &dcb); + + if (fRetVal) + { + if (SetDTR) + EscapeCommFunction(fd, SETDTR); + else + EscapeCommFunction(fd, CLRDTR); + + if (SetRTS) + EscapeCommFunction(fd, SETRTS); + else + EscapeCommFunction(fd, CLRRTS); + } + else + { + sprintf(buf,"%s Setup Failed %d ", pPort, GetLastError()); + + WritetoConsoleLocal(buf); + OutputDebugString(buf); + CloseHandle(fd); + return 0; + } + + return fd; + +} + +int ReadCOMBlockEx(HANDLE fd, char * Block, int MaxLength, BOOL * Error); + +int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength) +{ + BOOL Error; + return ReadCOMBlockEx(fd, Block, MaxLength, &Error); +} + +// version to pass read error back to caller + +int ReadCOMBlockEx(HANDLE fd, char * Block, int MaxLength, BOOL * Error) +{ + BOOL fReadStat ; + COMSTAT ComStat ; + DWORD dwErrorFlags; + DWORD dwLength; + BOOL ret; + + if (fd == NULL) + return 0; + + // only try to read number of bytes in queue + + ret = ClearCommError(fd, &dwErrorFlags, &ComStat); + + if (ret == 0) + { + int Err = GetLastError(); + *Error = TRUE; + return 0; + } + + + dwLength = min((DWORD) MaxLength, ComStat.cbInQue); + + if (dwLength > 0) + { + fReadStat = ReadFile(fd, Block, dwLength, &dwLength, NULL) ; + + if (!fReadStat) + { + dwLength = 0 ; + ClearCommError(fd, &dwErrorFlags, &ComStat ) ; + } + } + + *Error = FALSE; + + return dwLength; +} + + +BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite) +{ + BOOL fWriteStat; + DWORD BytesWritten; + DWORD ErrorFlags; + COMSTAT ComStat; + DWORD Mask = 0; + int Err; + + Err = GetCommModemStatus(fd, &Mask); + +// if ((Mask & MS_CTS_ON) == 0) // trap com0com other end not open +// return TRUE; + + fWriteStat = WriteFile(fd, Block, BytesToWrite, + &BytesWritten, NULL ); + + if ((!fWriteStat) || (BytesToWrite != BytesWritten)) + { + int Err = GetLastError(); + ClearCommError(fd, &ErrorFlags, &ComStat); + return FALSE; + } + return TRUE; +} + +VOID CloseCOMPort(HANDLE fd) +{ + if (fd == NULL) + return; + + SetCommMask(fd, 0); + + // drop DTR + + COMClearDTR(fd); + + // purge any outstanding reads/writes and close device handle + + PurgeComm(fd, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR ) ; + + CloseHandle(fd); + fd = NULL; +} + + +VOID COMSetDTR(HANDLE fd) +{ + EscapeCommFunction(fd, SETDTR); +} + +VOID COMClearDTR(HANDLE fd) +{ + EscapeCommFunction(fd, CLRDTR); +} + +VOID COMSetRTS(HANDLE fd) +{ + EscapeCommFunction(fd, SETRTS); +} + +VOID COMClearRTS(HANDLE fd) +{ + EscapeCommFunction(fd, CLRRTS); +} + + +#else + +static struct speed_struct +{ + int user_speed; + speed_t termios_speed; +} speed_table[] = { + {300, B300}, + {600, B600}, + {1200, B1200}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, + {19200, B19200}, + {38400, B38400}, + {57600, B57600}, + {115200, B115200}, + {-1, B0} +}; + + +HANDLE OpenCOMPort(VOID * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits) +{ + char Port[256]; + char buf[512]; + + // Linux Version. + + int fd; + int hwflag = 0; + u_long param=1; + struct termios term; + struct speed_struct *s; + + if ((uintptr_t)pPort < 256) + sprintf(Port, "%s/com%d", BPQDirectory, (int)(uintptr_t)pPort); + else + strcpy(Port, pPort); + + if ((fd = open(Port, O_RDWR | O_NDELAY)) == -1) + { + if (Quiet == 0) + { + perror("Com Open Failed"); + sprintf(buf," %s could not be opened \n", Port); + WritetoConsoleLocal(buf); + Debugprintf(buf); + } + return 0; + } + + // Validate Speed Param + + for (s = speed_table; s->user_speed != -1; s++) + if (s->user_speed == speed) + break; + + if (s->user_speed == -1) + { + fprintf(stderr, "tty_speed: invalid speed %d\n", speed); + return FALSE; + } + + if (tcgetattr(fd, &term) == -1) + { + perror("tty_speed: tcgetattr"); + return FALSE; + } + + cfmakeraw(&term); + cfsetispeed(&term, s->termios_speed); + cfsetospeed(&term, s->termios_speed); + + if (tcsetattr(fd, TCSANOW, &term) == -1) + { + perror("tty_speed: tcsetattr"); + return FALSE; + } + + ioctl(fd, FIONBIO, ¶m); + + Debugprintf("LinBPQ Port %s fd %d", Port, fd); + + if (SetDTR) + { + COMSetDTR(fd); + } + else + { + COMClearDTR(fd); + } + + if (SetRTS) + { + COMSetRTS(fd); + } + else + { + COMClearRTS(fd); + } + return fd; +} + +int ReadCOMBlockEx(HANDLE fd, char * Block, int MaxLength, BOOL * Error); + +int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength) +{ + BOOL Error; + return ReadCOMBlockEx(fd, Block, MaxLength, &Error); +} + +// version to pass read error back to caller + +int ReadCOMBlockEx(HANDLE fd, char * Block, int MaxLength, BOOL * Error) +{ + int Length; + + if (fd == 0) + { + *Error = 1; + return 0; + } + + errno = 22222; // to catch zero read (?? file closed ??) + + Length = read(fd, Block, MaxLength); + + *Error = 0; + + if (Length == 0 && errno == 22222) // seems to be result of unpluging USB + { +// printf("KISS read returned zero len and no errno\n"); + *Error = 1; + return 0; + } + + if (Length < 0) + { + if (errno != 11 && errno != 35) // Would Block + { + perror("read"); + printf("Handle %d Errno %d Len %d\n", fd, errno, Length); + *Error = errno; + } + return 0; + } + + return Length; +} + +BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite) +{ + // Some systems seem to have a very small max write size + + int ToSend = BytesToWrite; + int Sent = 0, ret; + int loops = 100; + + while (ToSend && loops-- > 0) + { + ret = write(fd, &Block[Sent], ToSend); + + if (ret >= ToSend) + return TRUE; + + if (ret == -1) + { + if (errno != 11 && errno != 35) // Would Block + return FALSE; + + usleep(10000); + ret = 0; + } + + Sent += ret; + ToSend -= ret; + } + +// if (ToSend) +// { +// // Send timed out. Close and reopen device +// +// } + return TRUE; +} + +VOID CloseCOMPort(HANDLE fd) +{ + if (fd == 0) + return; + + close(fd); + fd = 0; +} + +VOID COMSetDTR(HANDLE fd) +{ + int status; + + ioctl(fd, TIOCMGET, &status); + status |= TIOCM_DTR; + ioctl(fd, TIOCMSET, &status); +} + +VOID COMClearDTR(HANDLE fd) +{ + int status; + + ioctl(fd, TIOCMGET, &status); + status &= ~TIOCM_DTR; + ioctl(fd, TIOCMSET, &status); +} + +VOID COMSetRTS(HANDLE fd) +{ + int status; + + ioctl(fd, TIOCMGET, &status); + status |= TIOCM_RTS; + ioctl(fd, TIOCMSET, &status); +} + +VOID COMClearRTS(HANDLE fd) +{ + int status; + + ioctl(fd, TIOCMGET, &status); + status &= ~TIOCM_RTS; + ioctl(fd, TIOCMSET, &status); +} + +#endif + + +int MaxNodes; +int MaxRoutes; +int NodeLen; +int RouteLen; +struct DEST_LIST * Dests; +struct ROUTE * Routes; + +FILE *file; + +int DoRoutes() +{ + char digis[30] = ""; + int count, len; + char Normcall[10], Portcall[10]; + char line[80]; + + for (count=0; countNEIGHBOUR_CALL[0] != 0) + { + len=ConvFromAX25(Routes->NEIGHBOUR_CALL,Normcall); + Normcall[len]=0; + + if (Routes->NEIGHBOUR_DIGI1[0] != 0) + { + memcpy(digis," VIA ",5); + + len=ConvFromAX25(Routes->NEIGHBOUR_DIGI1,Portcall); + Portcall[len]=0; + strcpy(&digis[5],Portcall); + + if (Routes->NEIGHBOUR_DIGI2[0] != 0) + { + len=ConvFromAX25(Routes->NEIGHBOUR_DIGI2,Portcall); + Portcall[len]=0; + strcat(digis," "); + strcat(digis,Portcall); + } + } + else + digis[0] = 0; + + len=sprintf(line, + "ROUTE ADD %s %d %d %s %d %d %d %d %d\n", + Normcall, + Routes->NEIGHBOUR_PORT, + Routes->NEIGHBOUR_QUAL, digis, + Routes->NBOUR_MAXFRAME, + Routes->NBOUR_FRACK, + Routes->NBOUR_PACLEN, + Routes->INP3Node | (Routes->NoKeepAlive << 2), + Routes->OtherendsRouteQual); + + fputs(line, file); + } + + Routes+=1; + } + + return (0); +} + +int DoNodes() +{ + int count, len, cursor, i; + char Normcall[10], Portcall[10]; + char line[80]; + char Alias[7]; + + Dests-=1; + + for (count=0; countNRROUTE[0].ROUT_NEIGHBOUR == 0) + continue; + + { + len=ConvFromAX25(Dests->DEST_CALL,Normcall); + Normcall[len]=0; + + memcpy(Alias,Dests->DEST_ALIAS,6); + + Alias[6]=0; + + for (i=0;i<6;i++) + { + if (Alias[i] == ' ') + Alias[i] = 0; + } + + cursor=sprintf(line,"NODE ADD %s:%s ", Alias,Normcall); + + if (Dests->NRROUTE[0].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[0].ROUT_NEIGHBOUR->INP3Node == 0) + { + len=ConvFromAX25( + Dests->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall); + Portcall[len]=0; + + len=sprintf(&line[cursor],"%s %d %d ", + Portcall, + Dests->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, + Dests->NRROUTE[0].ROUT_QUALITY); + + cursor+=len; + + if (Dests->NRROUTE[0].ROUT_OBSCOUNT > 127) + { + len=sprintf(&line[cursor],"! "); + cursor+=len; + } + } + + if (Dests->NRROUTE[1].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[1].ROUT_NEIGHBOUR->INP3Node == 0) + { + len=ConvFromAX25( + Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall); + Portcall[len]=0; + + len=sprintf(&line[cursor],"%s %d %d ", + Portcall, + Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, + Dests->NRROUTE[1].ROUT_QUALITY); + + cursor+=len; + + if (Dests->NRROUTE[1].ROUT_OBSCOUNT > 127) + { + len=sprintf(&line[cursor],"! "); + cursor+=len; + } + } + + if (Dests->NRROUTE[2].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[2].ROUT_NEIGHBOUR->INP3Node == 0) + { + len=ConvFromAX25( + Dests->NRROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall); + Portcall[len]=0; + + len=sprintf(&line[cursor],"%s %d %d ", + Portcall, + Dests->NRROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, + Dests->NRROUTE[2].ROUT_QUALITY); + + cursor+=len; + + if (Dests->NRROUTE[2].ROUT_OBSCOUNT > 127) + { + len=sprintf(&line[cursor],"! "); + cursor+=len; + } + } + + if (cursor > 30) + { + line[cursor++]='\n'; + line[cursor++]=0; + fputs(line, file); + } + } + } + return (0); +} + +void SaveMH() +{ + char FN[250]; + struct PORTCONTROL * PORT = PORTTABLE; + FILE *file; + + if (BPQDirectory[0] == 0) + { + strcpy(FN, "MHSave.txt"); + } + else + { + strcpy(FN,BPQDirectory); + strcat(FN,"/"); + strcat(FN,"MHSave.txt"); + } + + if ((file = fopen(FN, "w")) == NULL) + return; + + while (PORT) + { + int Port = 0; + char * ptr; + + MHSTRUC * MH = PORT->PORTMHEARD; + + 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 + + if (MH == NULL) + continue; + + fprintf(file, "Port:%d\n", PORT->PORTNUMBER); + + while (count--) + { + if (MH->MHCALL[0] == 0) + break; + + Digi = 0; + + len = ConvFromAX25(MH->MHCALL, Normcall); + Normcall[len] = 0; + + 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, 'U'); + + ptr[15] = 0; + + if (MH->MHDIGI) + fprintf(file, "%d %6d %-10s%c %s %s|%s|%s\n", (int)MH->MHTIME, MH->MHCOUNT, Normcall, MH->MHDIGI, ptr, DigiList, MH->MHLocator, MH->MHFreq); + else + fprintf(file, "%d %6d %-10s%c %s %s|%s|%s\n", (int)MH->MHTIME, MH->MHCOUNT, Normcall, ' ', ptr, DigiList, MH->MHLocator, MH->MHFreq); + + MH++; + } + PORT = PORT->PORTPOINTER; + } + + fclose(file); + + return; +} + + +int APIENTRY SaveNodes () +{ + char FN[250]; + + Routes = NEIGHBOURS; + RouteLen = ROUTE_LEN; + MaxRoutes = MAXNEIGHBOURS; + + Dests = DESTS; + NodeLen = DEST_LIST_LEN; + MaxNodes = MAXDESTS; + + // Set up pointer to BPQNODES file + + if (BPQDirectory[0] == 0) + { + strcpy(FN,"BPQNODES.dat"); + } + else + { + strcpy(FN,BPQDirectory); + strcat(FN,"/"); + strcat(FN,"BPQNODES.dat"); + } + + if ((file = fopen(FN, "w")) == NULL) + return FALSE; + + DoRoutes(); + DoNodes(); + + fclose(file); + + return (0); +} + +DllExport int APIENTRY ClearNodes () +{ + char FN[250]; + + // Set up pointer to BPQNODES file + + if (BPQDirectory[0] == 0) + { + strcpy(FN,"BPQNODES.dat"); + } + else + { + strcpy(FN,BPQDirectory); + strcat(FN,"/"); + strcat(FN,"BPQNODES.dat"); + } + + if ((file = fopen(FN, "w")) == NULL) + return FALSE; + + fclose(file); + + return (0); +} + + +static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; + + +char * FormatMH(PMHSTRUC MH, char Format) +{ + struct tm * TM; + static char MHTime[50]; + time_t szClock; + char LOC[7]; + + memcpy(LOC, MH->MHLocator, 6); + LOC[6] = 0; + + if (Format == 'U' || Format =='L') + szClock = MH->MHTIME; + else + szClock = time(NULL) - MH->MHTIME; + + if (Format == 'L') + TM = localtime(&szClock); + else + TM = gmtime(&szClock); + + if (Format == 'U' || Format =='L') + sprintf(MHTime, "%s %02d %.2d:%.2d:%.2d %s %s", + month[TM->tm_mon], TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec, MH->MHFreq, LOC); + else + sprintf(MHTime, "%.2d:%.2d:%.2d:%.2d %s %s", + TM->tm_yday, TM->tm_hour, TM->tm_min, TM->tm_sec, MH->MHFreq, LOC); + + return MHTime; + +} + + +Dll VOID APIENTRY CreateOneTimePassword(char * Password, char * KeyPhrase, int TimeOffset) +{ + // Create a time dependent One Time Password from the KeyPhrase + // TimeOffset is used when checking to allow for slight variation in clocks + + time_t NOW = time(NULL); + UCHAR Hash[16]; + char Key[1000]; + int i, chr; + + NOW = NOW/30 + TimeOffset; // Only Change every 30 secs + + sprintf(Key, "%s%x", KeyPhrase, (int)NOW); + + md5(Key, Hash); + + for (i=0; i<16; i++) + { + chr = (Hash[i] & 31); + if (chr > 9) chr += 7; + + Password[i] = chr + 48; + } + + Password[16] = 0; + return; +} + +Dll BOOL APIENTRY CheckOneTimePassword(char * Password, char * KeyPhrase) +{ + char CheckPassword[17]; + int Offsets[10] = {0, -1, 1, -2, 2, -3, 3, -4, 4}; + int i, Pass; + + if (strlen(Password) < 16) + Pass = atoi(Password); + + for (i = 0; i < 9; i++) + { + CreateOneTimePassword(CheckPassword, KeyPhrase, Offsets[i]); + + if (strlen(Password) < 16) + { + // Using a numeric extract + + long long Val; + + memcpy(&Val, CheckPassword, 8); + Val = Val %= 1000000; + + if (Pass == Val) + return TRUE; + } + else + if (memcmp(Password, CheckPassword, 16) == 0) + return TRUE; + } + + return FALSE; +} + + +DllExport BOOL ConvToAX25Ex(unsigned char * callsign, unsigned char * ax25call) +{ + // Allows SSID's of 'T and 'R' + + int i; + + memset(ax25call,0x40,6); // in case short + ax25call[6]=0x60; // default SSID + + for (i=0;i<7;i++) + { + if (callsign[i] == '-') + { + // + // process ssid and return + // + + if (callsign[i+1] == 'T') + { + ax25call[6]=0x42; + return TRUE; + } + + if (callsign[i+1] == 'R') + { + ax25call[6]=0x44; + return TRUE; + } + i = atoi(&callsign[i+1]); + + if (i < 16) + { + ax25call[6] |= i<<1; + return (TRUE); + } + return (FALSE); + } + + if (callsign[i] == 0 || callsign[i] == 13 || callsign[i] == ' ' || callsign[i] == ',') + { + // + // End of call - no ssid + // + return (TRUE); + } + + ax25call[i] = callsign[i] << 1; + } + + // + // Too many chars + // + + return (FALSE); +} + + +DllExport BOOL ConvToAX25(unsigned char * callsign, unsigned char * ax25call) +{ + int i; + + memset(ax25call,0x40,6); // in case short + ax25call[6]=0x60; // default SSID + + for (i=0;i<7;i++) + { + if (callsign[i] == '-') + { + // + // process ssid and return + // + i = atoi(&callsign[i+1]); + + if (i < 16) + { + ax25call[6] |= i<<1; + return (TRUE); + } + return (FALSE); + } + + if (callsign[i] == 0 || callsign[i] == 13 || callsign[i] == ' ' || callsign[i] == ',') + { + // + // End of call - no ssid + // + return (TRUE); + } + + ax25call[i] = callsign[i] << 1; + } + + // + // Too many chars + // + + return (FALSE); +} + + +DllExport int ConvFromAX25(unsigned char * incall,unsigned char * outcall) +{ + int in,out=0; + unsigned char chr; + + memset(outcall,0x20,10); + + for (in=0;in<6;in++) + { + chr=incall[in]; + if (chr == 0x40) + break; + chr >>= 1; + outcall[out++]=chr; + } + + chr=incall[6]; // ssid + + if (chr == 0x42) + { + outcall[out++]='-'; + outcall[out++]='T'; + return out; + } + + if (chr == 0x44) + { + outcall[out++]='-'; + outcall[out++]='R'; + return out; + } + + chr >>= 1; + chr &= 15; + + if (chr > 0) + { + outcall[out++]='-'; + if (chr > 9) + { + chr-=10; + outcall[out++]='1'; + } + chr+=48; + outcall[out++]=chr; + } + return (out); +} + +unsigned short int compute_crc(unsigned char *buf, int txlen); + +SOCKADDR_IN reportdest = {0}; + +SOCKET ReportSocket = 0; + +SOCKADDR_IN Chatreportdest = {0}; + +extern char LOCATOR[]; // Locator for Reporting - may be Maidenhead or LAT:LON +extern char MAPCOMMENT[]; // Locator for Reporting - may be Maidenhead or LAT:LON +extern char LOC[7]; // Maidenhead Locator for Reporting +extern char ReportDest[7]; + + +VOID SendReportMsg(char * buff, int txlen) +{ + unsigned short int crc = compute_crc(buff, txlen); + + crc ^= 0xffff; + + buff[txlen++] = (crc&0xff); + buff[txlen++] = (crc>>8); + + sendto(ReportSocket, buff, txlen, 0, (struct sockaddr *)&reportdest, sizeof(reportdest)); + +} +VOID SendLocation() +{ + MESSAGE AXMSG = {0}; + PMESSAGE AXPTR = &AXMSG; + char Msg[512]; + int Len; + + Len = sprintf(Msg, "%s %s
%s", LOCATOR, VersionString, MAPCOMMENT); + +#ifdef LINBPQ + Len = sprintf(Msg, "%s L%s
%s", LOCATOR, VersionString, MAPCOMMENT); +#endif +#ifdef MACBPQ + Len = sprintf(Msg, "%s M%s
%s", LOCATOR, VersionString, MAPCOMMENT); +#endif +#ifdef FREEBSD + Len = sprintf(Msg, "%s F%s
%s", LOCATOR, VersionString, MAPCOMMENT); +#endif + + if (Len > 256) + Len = 256; + + // Block includes the Msg Header (7 bytes), Len Does not! + + memcpy(AXPTR->DEST, ReportDest, 7); + memcpy(AXPTR->ORIGIN, MYCALL, 7); + AXPTR->DEST[6] &= 0x7e; // Clear End of Call + AXPTR->DEST[6] |= 0x80; // set Command Bit + + AXPTR->ORIGIN[6] |= 1; // Set End of Call + AXPTR->CTL = 3; //UI + AXPTR->PID = 0xf0; + memcpy(AXPTR->L2DATA, Msg, Len); + + SendReportMsg((char *)&AXMSG.DEST, Len + 16); + + if (M0LTEMap) + SendDataToPktMap(); + + return; + +} + + + +VOID SendMH(struct TNCINFO * TNC, char * call, char * freq, char * LOC, char * Mode) +{ + MESSAGE AXMSG; + PMESSAGE AXPTR = &AXMSG; + char Msg[100]; + int Len; + + if (ReportSocket == 0 || LOCATOR[0] == 0) + return; + + Len = sprintf(Msg, "MH %s,%s,%s,%s", call, freq, LOC, Mode); + + // Block includes the Msg Header (7 bytes), Len Does not! + + memcpy(AXPTR->DEST, ReportDest, 7); + + if (TNC && TNC->PortRecord->PORTCONTROL.PORTCALL[0]) + memcpy(AXPTR->ORIGIN, TNC->PortRecord->PORTCONTROL.PORTCALL, 7); + else + memcpy(AXPTR->ORIGIN, MYCALL, 7); + AXPTR->DEST[6] &= 0x7e; // Clear End of Call + AXPTR->DEST[6] |= 0x80; // set Command Bit + + AXPTR->ORIGIN[6] |= 1; // Set End of Call + AXPTR->CTL = 3; //UI + AXPTR->PID = 0xf0; + memcpy(AXPTR->L2DATA, Msg, Len); + + SendReportMsg((char *)&AXMSG.DEST, Len + 16) ; + + return; + +} + +time_t TimeLastNRRouteSent = 0; + +char NRRouteMessage[256]; +int NRRouteLen = 0; + + +VOID SendNETROMRoute(struct PORTCONTROL * PORT, unsigned char * axcall) +{ + // Called to update Link Map when a NODES Broadcast is received + // Batch to reduce Load + + MESSAGE AXMSG; + PMESSAGE AXPTR = &AXMSG; + char Msg[300]; + int Len; + char Call[10]; + char Report[16]; + time_t Now = time(NULL); + int NeedSend = FALSE; + + + if (ReportSocket == 0 || LOCATOR[0] == 0) + return; + + Call[ConvFromAX25(axcall, Call)] = 0; + + sprintf(Report, "%s,%d,", Call, PORT->PORTTYPE); + + if (Now - TimeLastNRRouteSent > 60) + NeedSend = TRUE; + + if (strstr(NRRouteMessage, Report) == 0) // reported recently + strcat(NRRouteMessage, Report); + + if (strlen(NRRouteMessage) > 230 || NeedSend) + { + Len = sprintf(Msg, "LINK %s", NRRouteMessage); + + // Block includes the Msg Header (7 bytes), Len Does not! + + memcpy(AXPTR->DEST, ReportDest, 7); + memcpy(AXPTR->ORIGIN, MYCALL, 7); + AXPTR->DEST[6] &= 0x7e; // Clear End of Call + AXPTR->DEST[6] |= 0x80; // set Command Bit + + AXPTR->ORIGIN[6] |= 1; // Set End of Call + AXPTR->CTL = 3; //UI + AXPTR->PID = 0xf0; + memcpy(AXPTR->L2DATA, Msg, Len); + + SendReportMsg((char *)&AXMSG.DEST, Len + 16) ; + + TimeLastNRRouteSent = Now; + NRRouteMessage[0] = 0; + } + + return; + +} + +DllExport char * APIENTRY GetApplCall(int Appl) +{ + if (Appl < 1 || Appl > NumberofAppls ) return NULL; + + return (UCHAR *)(&APPLCALLTABLE[Appl-1].APPLCALL_TEXT); +} +DllExport char * APIENTRY GetApplAlias(int Appl) +{ + if (Appl < 1 || Appl > NumberofAppls ) return NULL; + + return (UCHAR *)(&APPLCALLTABLE[Appl-1].APPLALIAS_TEXT); +} + +DllExport int32_t APIENTRY GetApplQual(int Appl) +{ + if (Appl < 1 || Appl > NumberofAppls ) return 0; + + return (APPLCALLTABLE[Appl-1].APPLQUAL); +} + +char * GetApplCallFromName(char * App) +{ + int i; + char PaddedAppl[13] = " "; + + memcpy(PaddedAppl, App, (int)strlen(App)); + + for (i = 0; i < NumberofAppls; i++) + { + if (memcmp(&APPLCALLTABLE[i].APPLCMD, PaddedAppl, 12) == 0) + return &APPLCALLTABLE[i].APPLCALL_TEXT[0]; + } + return NULL; +} + + +DllExport char * APIENTRY GetApplName(int Appl) +{ + if (Appl < 1 || Appl > NumberofAppls ) return NULL; + + return (UCHAR *)(&APPLCALLTABLE[Appl-1].APPLCMD); +} + +DllExport int APIENTRY GetNumberofPorts() +{ + return (NUMBEROFPORTS); +} + +DllExport int APIENTRY GetPortNumber(int portslot) +{ + struct PORTCONTROL * PORTVEC=PORTTABLE; + + if (portslot>NUMBEROFPORTS) + portslot=NUMBEROFPORTS; + + while (--portslot > 0) + PORTVEC=PORTVEC->PORTPOINTER; + + return PORTVEC->PORTNUMBER; + +} + +DllExport char * APIENTRY GetVersionString() +{ +// return ((char *)&VersionStringWithBuild); + return ((char *)&VersionString); +} + +#ifdef MACBPQ + +//Fiddle till I find a better solution + +#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1060 +int __sync_lock_test_and_set(int * ptr, int val) +{ + *ptr = val; + return 0; +} +#endif // __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ +#endif // MACBPQ + + +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) + + +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line) +{ + // + // Wait for it to be free + // + + if (Semaphore->Flag != 0) + { + Semaphore->Clashes++; + } + +loop1: + + while (Semaphore->Flag != 0) + { + Sleep(10); + } + + // + // try to get semaphore + // + +#ifdef WIN32 + + { + if (InterlockedExchange(&Semaphore->Flag, 1) != 0) // Failed to get it + goto loop1; // try again;; + } + +#else + + if (__sync_lock_test_and_set(&Semaphore->Flag, 1) != 0) + + // Failed to get it + goto loop1; // try again; + +#endif + + //Ok. got it + + Semaphore->Gets++; + Semaphore->SemProcessID = GetCurrentProcessId(); + Semaphore->SemThreadID = GetCurrentThreadId(); + SemHeldByAPI = ID; + Semaphore->Line = Line; + strcpy(Semaphore->File, File); + + return; +} + +void FreeSemaphore(struct SEM * Semaphore) +{ + if (Semaphore->Flag == 0) + Debugprintf("Free Semaphore Called when Sem not held"); + + Semaphore->Rels++; + Semaphore->Flag = 0; + + return; +} + +#ifdef WIN32 + +#include "DbgHelp.h" +/* +USHORT WINAPI RtlCaptureStackBackTrace( + __in ULONG FramesToSkip, + __in ULONG FramesToCapture, + __out PVOID *BackTrace, + __out_opt PULONG BackTraceHash +); +*/ +#endif + +void printStack(void) +{ +#ifdef WIN32 +#ifdef _DEBUG // So we can use on 98/2K + + unsigned int i; + void * stack[ 100 ]; + unsigned short frames; + SYMBOL_INFO * symbol; + HANDLE process; + + Debugprintf("Stack Backtrace"); + + process = GetCurrentProcess(); + + SymInitialize( process, NULL, TRUE ); + + frames = RtlCaptureStackBackTrace( 0, 60, stack, NULL ); + symbol = ( SYMBOL_INFO * )calloc( sizeof( SYMBOL_INFO ) + 256 * sizeof( char ), 1 ); + symbol->MaxNameLen = 255; + symbol->SizeOfStruct = sizeof( SYMBOL_INFO ); + + for( i = 0; i < frames; i++ ) + { + SymFromAddr( process, ( DWORD64 )( stack[ i ] ), 0, symbol ); + + Debugprintf( "%i: %s - %p", frames - i - 1, symbol->Name, symbol->Address ); + } + + free(symbol); + +#endif +#endif +} + +pthread_t ResolveUpdateThreadId = 0; + +char NodeMapServer[80] = "update.g8bpq.net"; +char ChatMapServer[80] = "chatupdate.g8bpq.net"; + +VOID ResolveUpdateThread(void * Unused) +{ + struct hostent * HostEnt1; + struct hostent * HostEnt2; + + ResolveUpdateThreadId = GetCurrentThreadId(); + + while (TRUE) + { + if (pthread_equal(ResolveUpdateThreadId, GetCurrentThreadId()) == FALSE) + { + Debugprintf("Resolve Update thread %x redundant - closing", GetCurrentThreadId()); + return; + } + + // Resolve name to address + + Debugprintf("Resolving %s", NodeMapServer); + HostEnt1 = gethostbyname (NodeMapServer); +// HostEnt1 = gethostbyname ("192.168.1.64"); + + if (HostEnt1) + memcpy(&reportdest.sin_addr.s_addr,HostEnt1->h_addr,4); + + Debugprintf("Resolving %s", ChatMapServer); + HostEnt2 = gethostbyname (ChatMapServer); +// HostEnt2 = gethostbyname ("192.168.1.64"); + + if (HostEnt2) + memcpy(&Chatreportdest.sin_addr.s_addr,HostEnt2->h_addr,4); + + if (HostEnt1 && HostEnt2) + { + Sleep(1000 * 60 * 30); + continue; + } + + Debugprintf("Resolve Failed for update.g8bpq.net or chatmap.g8bpq.net"); + Sleep(1000 * 60 * 5); + } +} + + +VOID OpenReportingSockets() +{ + u_long param=1; + BOOL bcopt=TRUE; + + if (LOCATOR[0]) + { + // Enable Node Map Reports + + ReportTimer = 1200; // 2 mins - Give Rigcontrol time to start + + ReportSocket = socket(AF_INET,SOCK_DGRAM,0); + + if (ReportSocket == INVALID_SOCKET) + { + Debugprintf("Failed to create Reporting socket"); + ReportSocket = 0; + return; + } + + ioctlsocket (ReportSocket, FIONBIO, ¶m); + setsockopt (ReportSocket, SOL_SOCKET, SO_BROADCAST, (const char FAR *)&bcopt,4); + + reportdest.sin_family = AF_INET; + reportdest.sin_port = htons(81); + ConvToAX25("DUMMY-1", ReportDest); + } + + // Set up Chat Report even if no LOCATOR reportdest.sin_family = AF_INET; + // Socket must be opened in MailChat Process + + Chatreportdest.sin_family = AF_INET; + Chatreportdest.sin_port = htons(81); + + _beginthread(ResolveUpdateThread, 0, NULL); + + printf("MQTT Enabled %d\n", MQTT); + + if (MQTT) + MQTTConnect(MQTT_HOST, MQTT_PORT, MQTT_USER, MQTT_PASS); +} + +VOID WriteMiniDumpThread(); + +time_t lastMiniDump = 0; + +void WriteMiniDump() +{ +#ifdef WIN32 + + _beginthread(WriteMiniDumpThread, 0, 0); + Sleep(3000); +} + +VOID WriteMiniDumpThread() +{ + HANDLE hFile; + BOOL ret; + char FN[256]; + struct tm * TM; + time_t Now = time(NULL); + + if (lastMiniDump == Now) // Not more than one per second + { + Debugprintf("minidump suppressed"); + return; + } + + lastMiniDump = Now; + + TM = gmtime(&Now); + + sprintf(FN, "%s/Logs/MiniDump%d%02d%02d%02d%02d%02d.dmp", BPQDirectory, + TM->tm_year + 1900, TM->tm_mon +1, TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec); + + hFile = CreateFile(FN, GENERIC_READ | GENERIC_WRITE, + 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE)) + { + // Create the minidump + + ret = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), + hFile, MiniDumpNormal, 0, 0, 0 ); + + if(!ret) + Debugprintf("MiniDumpWriteDump failed. Error: %u", GetLastError()); + else + Debugprintf("Minidump %s created.", FN); + CloseHandle(hFile); + } +#endif +} + +// UI Util Code + +#pragma pack(1) + +typedef struct _MESSAGEX +{ +// BASIC LINK LEVEL MESSAGE BUFFER LAYOUT + + struct _MESSAGEX * CHAIN; + + UCHAR PORT; + USHORT LENGTH; + + UCHAR DEST[7]; + UCHAR ORIGIN[7]; + +// MAY BE UP TO 56 BYTES OF DIGIS + + UCHAR CTL; + UCHAR PID; + UCHAR DATA[256]; + UCHAR PADDING[56]; // In case he have Digis + +}MESSAGEX, *PMESSAGEX; + +#pragma pack() + + +int PortNum[MaxBPQPortNo + 1] = {0}; // Tab nunber to port + +char * UIUIDigi[MaxBPQPortNo + 1]= {0}; +char * UIUIDigiAX[MaxBPQPortNo + 1] = {0}; // ax.25 version of digistring +int UIUIDigiLen[MaxBPQPortNo + 1] = {0}; // Length of AX string + +char UIUIDEST[MaxBPQPortNo + 1][11] = {0}; // Dest for Beacons + +char UIAXDEST[MaxBPQPortNo + 1][7] = {0}; + + +UCHAR FN[MaxBPQPortNo + 1][256]; // Filename +int Interval[MaxBPQPortNo + 1]; // Beacon Interval (Mins) +int MinCounter[MaxBPQPortNo + 1]; // Interval Countdown + +BOOL SendFromFile[MaxBPQPortNo + 1]; +char Message[MaxBPQPortNo + 1][1000]; // Beacon Text + +VOID SendUIBeacon(int Port); + +BOOL RunUI = TRUE; + +VOID UIThread(void * Unused) +{ + int Port, MaxPorts = GetNumberofPorts(); + + Sleep(60000); + + while (RunUI) + { + int sleepInterval = 60000; + + for (Port = 1; Port <= MaxPorts; Port++) + { + if (MinCounter[Port]) + { + MinCounter[Port]--; + + if (MinCounter[Port] == 0) + { + MinCounter[Port] = Interval[Port]; + SendUIBeacon(Port); + + // pause beteen beacons but adjust sleep interval to suit + + Sleep(10000); + sleepInterval -= 10000; + } + } + } + + while (sleepInterval <= 0) // just in case we have a crazy config + sleepInterval += 60000; + + Sleep(sleepInterval); + } +} + +int UIRemoveLF(char * Message, int len) +{ + // Remove lf chars + + char * ptr1, * ptr2; + + ptr1 = ptr2 = Message; + + while (len-- > 0) + { + *ptr2 = *ptr1; + + if (*ptr1 == '\r') + if (*(ptr1+1) == '\n') + { + ptr1++; + len--; + } + ptr1++; + ptr2++; + } + + return (int)(ptr2 - Message); +} + + + + +VOID UISend_AX_Datagram(UCHAR * Msg, DWORD Len, UCHAR Port, UCHAR * HWADDR, BOOL Queue) +{ + MESSAGEX AXMSG; + PMESSAGEX AXPTR = &AXMSG; + int DataLen = Len; + struct PORTCONTROL * PORT = GetPortTableEntryFromSlot(Port); + + // Block includes the Msg Header (7 or 11 bytes), Len Does not! + + memcpy(AXPTR->DEST, HWADDR, 7); + + // Get BCALL or PORTCALL if set + + if (PORT && PORT->PORTBCALL[0]) + memcpy(AXPTR->ORIGIN, PORT->PORTBCALL, 7); + else if (PORT && PORT->PORTCALL[0]) + memcpy(AXPTR->ORIGIN, PORT->PORTCALL, 7); + else + memcpy(AXPTR->ORIGIN, MYCALL, 7); + + AXPTR->DEST[6] &= 0x7e; // Clear End of Call + AXPTR->DEST[6] |= 0x80; // set Command Bit + + if (UIUIDigi[Port]) + { + // This port has a digi string + + int DigiLen = UIUIDigiLen[Port]; + UCHAR * ptr; + + memcpy(&AXPTR->CTL, UIUIDigiAX[Port], DigiLen); + + ptr = (UCHAR *)AXPTR; + ptr += DigiLen; + AXPTR = (PMESSAGEX)ptr; + + Len += DigiLen; + } + + AXPTR->ORIGIN[6] |= 1; // Set End of Call + AXPTR->CTL = 3; //UI + AXPTR->PID = 0xf0; + memcpy(AXPTR->DATA, Msg, DataLen); + +// if (Queue) +// QueueRaw(Port, &AXMSG, Len + 16); +// else + SendRaw(Port, (char *)&AXMSG.DEST, Len + 16); + + return; + +} + + + +VOID SendUIBeacon(int Port) +{ + char UIMessage[1024]; + int Len = (int)strlen(Message[Port]); + int Index = 0; + + if (SendFromFile[Port]) + { + FILE * hFile; + + hFile = fopen(FN[Port], "rb"); + + if (hFile == 0) + return; + + Len = (int)fread(UIMessage, 1, 1024, hFile); + + fclose(hFile); + + } + else + strcpy(UIMessage, Message[Port]); + + Len = UIRemoveLF(UIMessage, Len); + + while (Len > 256) + { + UISend_AX_Datagram(&UIMessage[Index], 256, Port, UIAXDEST[Port], TRUE); + Index += 256; + Len -= 256; + Sleep(2000); + } + UISend_AX_Datagram(&UIMessage[Index], Len, Port, UIAXDEST[Port], TRUE); +} + +#ifndef LINBPQ + +typedef struct tag_dlghdr +{ + HWND hwndTab; // tab control + HWND hwndDisplay; // current child dialog box + RECT rcDisplay; // display rectangle for the tab control + + DLGTEMPLATE *apRes[MaxBPQPortNo + 1]; + +} DLGHDR; + +DLGTEMPLATE * WINAPI DoLockDlgRes(LPCSTR lpszResName); + +#endif + +HWND hwndDlg; +int PageCount; +int CurrentPage=0; // Page currently on show in tabbed Dialog + + +VOID WINAPI OnSelChanged(HWND hwndDlg); +VOID WINAPI OnChildDialogInit(HWND hwndDlg); + +#define ICC_STANDARD_CLASSES 0x00004000 + +HWND hwndDisplay; + +#define ID_TEST 102 +#define IDD_DIAGLOG1 103 +#define IDC_FROMFILE 1022 +#define IDC_EDIT1 1054 +#define IDC_FILENAME 1054 +#define IDC_EDIT2 1055 +#define IDC_MESSAGE 1055 +#define IDC_EDIT3 1056 +#define IDC_INTERVAL 1056 +#define IDC_EDIT4 1057 +#define IDC_UIDEST 1057 +#define IDC_FILE 1058 +#define IDC_TAB1 1059 +#define IDC_UIDIGIS 1059 +#define IDC_PORTNAME 1060 + +extern HKEY REGTREE; +HBRUSH bgBrush; + +VOID SetupUI(int Port) +{ + char DigiString[100], * DigiLeft; + + ConvToAX25(UIUIDEST[Port], &UIAXDEST[Port][0]); + + UIUIDigiLen[Port] = 0; + + if (UIUIDigi[Port]) + { + UIUIDigiAX[Port] = zalloc(100); + strcpy(DigiString, UIUIDigi[Port]); + DigiLeft = strlop(DigiString,','); + + while(DigiString[0]) + { + ConvToAX25(DigiString, &UIUIDigiAX[Port][UIUIDigiLen[Port]]); + UIUIDigiLen[Port] += 7; + + if (DigiLeft) + { + memmove(DigiString, DigiLeft, (int)strlen(DigiLeft) + 1); + DigiLeft = strlop(DigiString,','); + } + else + DigiString[0] = 0; + } + } +} + +#ifndef LINBPQ + +VOID SaveIntValue(config_setting_t * group, char * name, int value) +{ + config_setting_t *setting; + + setting = config_setting_add(group, name, CONFIG_TYPE_INT); + if(setting) + config_setting_set_int(setting, value); +} + +VOID SaveStringValue(config_setting_t * group, char * name, char * value) +{ + config_setting_t *setting; + + setting = config_setting_add(group, name, CONFIG_TYPE_STRING); + if (setting) + config_setting_set_string(setting, value); + +} + +#endif + +config_t cfg; + +VOID SaveUIConfig() +{ + config_setting_t *root, *group, *UIGroup; + int Port, MaxPort = GetNumberofPorts(); + char ConfigName[256]; + + if (BPQDirectory[0] == 0) + { + strcpy(ConfigName,"UIUtil.cfg"); + } + else + { + strcpy(ConfigName,BPQDirectory); + strcat(ConfigName,"/"); + strcat(ConfigName,"UIUtil.cfg"); + } + + // Get rid of old config before saving + + config_init(&cfg); + + root = config_root_setting(&cfg); + + group = config_setting_add(root, "main", CONFIG_TYPE_GROUP); + + UIGroup = config_setting_add(group, "UIUtil", CONFIG_TYPE_GROUP); + + for (Port = 1; Port <= MaxPort; Port++) + { + char Key[20]; + + sprintf(Key, "Port%d", Port); + group = config_setting_add(UIGroup, Key, CONFIG_TYPE_GROUP); + + SaveStringValue(group, "UIDEST", &UIUIDEST[Port][0]); + SaveStringValue(group, "FileName", &FN[Port][0]); + SaveStringValue(group, "Message", &Message[Port][0]); + SaveStringValue(group, "Digis", UIUIDigi[Port]); + + SaveIntValue(group, "Interval", Interval[Port]); + SaveIntValue(group, "SendFromFile", SendFromFile[Port]); + } + + if(!config_write_file(&cfg, ConfigName)) + { + fprintf(stderr, "Error while writing file.\n"); + config_destroy(&cfg); + return; + } + + config_destroy(&cfg); +} + +int GetRegConfig(); + +VOID GetUIConfig() +{ + char Key[100]; + char CfgFN[256]; + char Digis[100]; + struct stat STAT; + + config_t cfg; + config_setting_t *group; + int Port, MaxPort = GetNumberofPorts(); + + memset((void *)&cfg, 0, sizeof(config_t)); + + config_init(&cfg); + + if (BPQDirectory[0] == 0) + { + strcpy(CfgFN,"UIUtil.cfg"); + } + else + { + strcpy(CfgFN,BPQDirectory); + strcat(CfgFN,"/"); + strcat(CfgFN,"UIUtil.cfg"); + } + + if (stat(CfgFN, &STAT) == -1) + { + // No file. If Windows try to read from registy + +#ifndef LINBPQ + GetRegConfig(); +#else + Debugprintf("UIUtil Config File not found\n"); +#endif + return; + } + + if(!config_read_file(&cfg, CfgFN)) + { + fprintf(stderr, "UI Util Config Error Line %d - %s\n", config_error_line(&cfg), config_error_text(&cfg)); + + config_destroy(&cfg); + return; + } + + group = config_lookup(&cfg, "main"); + + if (group) + { + for (Port = 1; Port <= MaxPort; Port++) + { + sprintf(Key, "main.UIUtil.Port%d", Port); + + group = config_lookup (&cfg, Key); + + if (group) + { + GetStringValue(group, "UIDEST", &UIUIDEST[Port][0], 11); + GetStringValue(group, "FileName", &FN[Port][0], 256); + GetStringValue(group, "Message", &Message[Port][0], 1000); + GetStringValue(group, "Digis", Digis, 100); + UIUIDigi[Port] = _strdup(Digis); + + Interval[Port] = GetIntValue(group, "Interval"); + MinCounter[Port] = Interval[Port]; + + SendFromFile[Port] = GetIntValue(group, "SendFromFile"); + + SetupUI(Port); + } + } + } + + + _beginthread(UIThread, 0, NULL); + +} + +#ifndef LINBPQ + +int GetIntValue(config_setting_t * group, char * name) +{ + config_setting_t *setting; + + setting = config_setting_get_member (group, name); + if (setting) + return config_setting_get_int (setting); + + return 0; +} + +BOOL GetStringValue(config_setting_t * group, char * name, char * value, int maxlen) +{ + char * str; + config_setting_t *setting; + + setting = config_setting_get_member (group, name); + if (setting) + { + str = (char *)config_setting_get_string(setting); + + if (strlen(str) > maxlen) + { + Debugprintf("Suspect config record %s", str); + str[maxlen] = 0; + } + strcpy(value, str); + return TRUE; + } + value[0] = 0; + return FALSE; +} + +int GetRegConfig() +{ + int retCode, Vallen, Type, i; + char Key[80]; + char Size[80]; + HKEY hKey; + RECT Rect; + + wsprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\UIUtil"); + + retCode = RegOpenKeyEx (REGTREE, Key, 0, KEY_QUERY_VALUE, &hKey); + + if (retCode == ERROR_SUCCESS) + { + Vallen=80; + + retCode = RegQueryValueEx(hKey,"Size",0, + (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen); + + if (retCode == ERROR_SUCCESS) + sscanf(Size,"%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom); + + RegCloseKey(hKey); + } + + for (i=1; i<=32; i++) + { + wsprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\UIUtil\\UIPort%d", i); + + retCode = RegOpenKeyEx (REGTREE, + Key, + 0, + KEY_QUERY_VALUE, + &hKey); + + if (retCode == ERROR_SUCCESS) + { + Vallen=0; + RegQueryValueEx(hKey,"Digis",0, + (ULONG *)&Type, NULL, (ULONG *)&Vallen); + + if (Vallen) + { + UIUIDigi[i] = malloc(Vallen); + RegQueryValueEx(hKey,"Digis",0, + (ULONG *)&Type, UIUIDigi[i], (ULONG *)&Vallen); + } + + Vallen=4; + retCode = RegQueryValueEx(hKey, "Interval", 0, + (ULONG *)&Type, (UCHAR *)&Interval[i], (ULONG *)&Vallen); + + MinCounter[i] = Interval[i]; + + Vallen=4; + retCode = RegQueryValueEx(hKey, "SendFromFile", 0, + (ULONG *)&Type, (UCHAR *)&SendFromFile[i], (ULONG *)&Vallen); + + + Vallen=10; + retCode = RegQueryValueEx(hKey, "UIDEST", 0, &Type, &UIUIDEST[i][0], &Vallen); + + Vallen=255; + retCode = RegQueryValueEx(hKey, "FileName", 0, &Type, &FN[i][0], &Vallen); + + Vallen=999; + retCode = RegQueryValueEx(hKey, "Message", 0, &Type, &Message[i][0], &Vallen); + + SetupUI(i); + + RegCloseKey(hKey); + } + } + + SaveUIConfig(); + + return TRUE; +} + +INT_PTR CALLBACK ChildDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ +// This processes messages from controls on the tab subpages + int Command; + + int retCode, disp; + char Key[80]; + HKEY hKey; + BOOL OK; + OPENFILENAME ofn; + char Digis[100]; + + int Port = PortNum[CurrentPage]; + + + switch (message) + { + case WM_NOTIFY: + + switch (((LPNMHDR)lParam)->code) + { + case TCN_SELCHANGE: + OnSelChanged(hDlg); + return TRUE; + // More cases on WM_NOTIFY switch. + case NM_CHAR: + return TRUE; + } + + break; + case WM_INITDIALOG: + OnChildDialogInit( hDlg); + return (INT_PTR)TRUE; + + case WM_CTLCOLORDLG: + + return (LONG)bgBrush; + + case WM_CTLCOLORSTATIC: + { + HDC hdcStatic = (HDC)wParam; + SetTextColor(hdcStatic, RGB(0, 0, 0)); + SetBkMode(hdcStatic, TRANSPARENT); + return (LONG)bgBrush; + } + + + case WM_COMMAND: + + Command = LOWORD(wParam); + + if (Command == 2002) + return TRUE; + + switch (Command) + { + case IDC_FILE: + + memset(&ofn, 0, sizeof (OPENFILENAME)); + ofn.lStructSize = sizeof (OPENFILENAME); + ofn.hwndOwner = hDlg; + ofn.lpstrFile = &FN[Port][0]; + ofn.nMaxFile = 250; + ofn.lpstrTitle = "File to send as beacon"; + ofn.lpstrInitialDir = BPQDirectory; + + if (GetOpenFileName(&ofn)) + SetDlgItemText(hDlg, IDC_FILENAME, &FN[Port][0]); + + break; + + + case IDOK: + + GetDlgItemText(hDlg, IDC_UIDEST, &UIUIDEST[Port][0], 10); + + if (UIUIDigi[Port]) + { + free(UIUIDigi[Port]); + UIUIDigi[Port] = NULL; + } + + if (UIUIDigiAX[Port]) + { + free(UIUIDigiAX[Port]); + UIUIDigiAX[Port] = NULL; + } + + GetDlgItemText(hDlg, IDC_UIDIGIS, Digis, 99); + + UIUIDigi[Port] = _strdup(Digis); + + GetDlgItemText(hDlg, IDC_FILENAME, &FN[Port][0], 255); + GetDlgItemText(hDlg, IDC_MESSAGE, &Message[Port][0], 1000); + + Interval[Port] = GetDlgItemInt(hDlg, IDC_INTERVAL, &OK, FALSE); + + MinCounter[Port] = Interval[Port]; + + SendFromFile[Port] = IsDlgButtonChecked(hDlg, IDC_FROMFILE); + + wsprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\UIUtil\\UIPort%d", PortNum[CurrentPage]); + + retCode = RegCreateKeyEx(REGTREE, + Key, 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp); + + if (retCode == ERROR_SUCCESS) + { + retCode = RegSetValueEx(hKey, "UIDEST", 0, REG_SZ,(BYTE *)&UIUIDEST[Port][0], (int)strlen(&UIUIDEST[Port][0])); + retCode = RegSetValueEx(hKey, "FileName", 0, REG_SZ,(BYTE *)&FN[Port][0], (int)strlen(&FN[Port][0])); + retCode = RegSetValueEx(hKey, "Message", 0, REG_SZ,(BYTE *)&Message[Port][0], (int)strlen(&Message[Port][0])); + retCode = RegSetValueEx(hKey, "Interval", 0, REG_DWORD,(BYTE *)&Interval[Port], 4); + retCode = RegSetValueEx(hKey, "SendFromFile", 0, REG_DWORD,(BYTE *)&SendFromFile[Port], 4); + retCode = RegSetValueEx(hKey, "Digis",0, REG_SZ, Digis, (int)strlen(Digis)); + + RegCloseKey(hKey); + } + + SetupUI(Port); + + SaveUIConfig(); + + return (INT_PTR)TRUE; + + + case IDCANCEL: + + EndDialog(hDlg, LOWORD(wParam)); + return (INT_PTR)TRUE; + + case ID_TEST: + + SendUIBeacon(Port); + return TRUE; + + } + break; + + } + return (INT_PTR)FALSE; +} + + + +VOID WINAPI OnTabbedDialogInit(HWND hDlg) +{ + DLGHDR *pHdr = (DLGHDR *) LocalAlloc(LPTR, sizeof(DLGHDR)); + DWORD dwDlgBase = GetDialogBaseUnits(); + int cxMargin = LOWORD(dwDlgBase) / 4; + int cyMargin = HIWORD(dwDlgBase) / 8; + + TC_ITEM tie; + RECT rcTab; + + int i, pos, tab = 0; + INITCOMMONCONTROLSEX init; + + char PortNo[60]; + struct _EXTPORTDATA * PORTVEC; + + hwndDlg = hDlg; // Save Window Handle + + // Save a pointer to the DLGHDR structure. + +#define GWL_USERDATA (-21) + + SetWindowLong(hwndDlg, GWL_USERDATA, (LONG) pHdr); + + // Create the tab control. + + + init.dwICC = ICC_STANDARD_CLASSES; + init.dwSize=sizeof(init); + i=InitCommonControlsEx(&init); + + pHdr->hwndTab = CreateWindow(WC_TABCONTROL, "", WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE, + 0, 0, 100, 100, hwndDlg, NULL, hInstance, NULL); + + if (pHdr->hwndTab == NULL) { + + // handle error + + } + + // Add a tab for each of the child dialog boxes. + + tie.mask = TCIF_TEXT | TCIF_IMAGE; + + tie.iImage = -1; + + for (i = 1; i <= NUMBEROFPORTS; i++) + { + // Only allow UI on ax.25 ports + + PORTVEC = (struct _EXTPORTDATA * )GetPortTableEntryFromSlot(i); + + if (PORTVEC->PORTCONTROL.PORTTYPE == 16) // EXTERNAL + if (PORTVEC->PORTCONTROL.PROTOCOL == 10) // Pactor/WINMOR + if (PORTVEC->PORTCONTROL.UICAPABLE == 0) + continue; + + wsprintf(PortNo, "Port %2d", GetPortNumber(i)); + PortNum[tab] = i; + + tie.pszText = PortNo; + TabCtrl_InsertItem(pHdr->hwndTab, tab, &tie); + + pHdr->apRes[tab++] = DoLockDlgRes("PORTPAGE"); + } + + PageCount = tab; + + // Determine the bounding rectangle for all child dialog boxes. + + SetRectEmpty(&rcTab); + + for (i = 0; i < PageCount; i++) + { + if (pHdr->apRes[i]->cx > rcTab.right) + rcTab.right = pHdr->apRes[i]->cx; + + if (pHdr->apRes[i]->cy > rcTab.bottom) + rcTab.bottom = pHdr->apRes[i]->cy; + + } + + MapDialogRect(hwndDlg, &rcTab); + +// rcTab.right = rcTab.right * LOWORD(dwDlgBase) / 4; + +// rcTab.bottom = rcTab.bottom * HIWORD(dwDlgBase) / 8; + + // Calculate how large to make the tab control, so + + // the display area can accomodate all the child dialog boxes. + + TabCtrl_AdjustRect(pHdr->hwndTab, TRUE, &rcTab); + + OffsetRect(&rcTab, cxMargin - rcTab.left, cyMargin - rcTab.top); + + // Calculate the display rectangle. + + CopyRect(&pHdr->rcDisplay, &rcTab); + + TabCtrl_AdjustRect(pHdr->hwndTab, FALSE, &pHdr->rcDisplay); + + // Set the size and position of the tab control, buttons, + + // and dialog box. + + SetWindowPos(pHdr->hwndTab, NULL, rcTab.left, rcTab.top, rcTab.right - rcTab.left, rcTab.bottom - rcTab.top, SWP_NOZORDER); + + // Move the Buttons to bottom of page + + pos=rcTab.left+cxMargin; + + + // Size the dialog box. + + SetWindowPos(hwndDlg, NULL, 0, 0, rcTab.right + cyMargin + 2 * GetSystemMetrics(SM_CXDLGFRAME), + rcTab.bottom + 2 * cyMargin + 2 * GetSystemMetrics(SM_CYDLGFRAME) + GetSystemMetrics(SM_CYCAPTION), + SWP_NOMOVE | SWP_NOZORDER); + + // Simulate selection of the first item. + + OnSelChanged(hwndDlg); + +} + +// DoLockDlgRes - loads and locks a dialog template resource. + +// Returns a pointer to the locked resource. + +// lpszResName - name of the resource + +DLGTEMPLATE * WINAPI DoLockDlgRes(LPCSTR lpszResName) +{ + HRSRC hrsrc = FindResource(hInstance, lpszResName, RT_DIALOG); + HGLOBAL hglb = LoadResource(hInstance, hrsrc); + + return (DLGTEMPLATE *) LockResource(hglb); +} + +//The following function processes the TCN_SELCHANGE notification message for the main dialog box. The function destroys the dialog box for the outgoing page, if any. Then it uses the CreateDialogIndirect function to create a modeless dialog box for the incoming page. + +// OnSelChanged - processes the TCN_SELCHANGE notification. + +// hwndDlg - handle of the parent dialog box + +VOID WINAPI OnSelChanged(HWND hwndDlg) +{ + char PortDesc[40]; + int Port; + + DLGHDR *pHdr = (DLGHDR *) GetWindowLong(hwndDlg, GWL_USERDATA); + + CurrentPage = TabCtrl_GetCurSel(pHdr->hwndTab); + + // Destroy the current child dialog box, if any. + + if (pHdr->hwndDisplay != NULL) + + DestroyWindow(pHdr->hwndDisplay); + + // Create the new child dialog box. + + pHdr->hwndDisplay = CreateDialogIndirect(hInstance, pHdr->apRes[CurrentPage], hwndDlg, ChildDialogProc); + + hwndDisplay = pHdr->hwndDisplay; // Save + + Port = PortNum[CurrentPage]; + // Fill in the controls + + GetPortDescription(PortNum[CurrentPage], PortDesc); + + SetDlgItemText(hwndDisplay, IDC_PORTNAME, PortDesc); + + CheckDlgButton(hwndDisplay, IDC_FROMFILE, SendFromFile[Port]); + + SetDlgItemInt(hwndDisplay, IDC_INTERVAL, Interval[Port], FALSE); + + SetDlgItemText(hwndDisplay, IDC_UIDEST, &UIUIDEST[Port][0]); + SetDlgItemText(hwndDisplay, IDC_UIDIGIS, UIUIDigi[Port]); + + + + SetDlgItemText(hwndDisplay, IDC_FILENAME, &FN[Port][0]); + SetDlgItemText(hwndDisplay, IDC_MESSAGE, &Message[Port][0]); + + ShowWindow(pHdr->hwndDisplay, SW_SHOWNORMAL); + +} + + +//The following function processes the WM_INITDIALOG message for each of the child dialog boxes. You cannot specify the position of a dialog box created using the CreateDialogIndirect function. This function uses the SetWindowPos function to position the child dialog within the tab control's display area. + +// OnChildDialogInit - Positions the child dialog box to fall + +// within the display area of the tab control. + +VOID WINAPI OnChildDialogInit(HWND hwndDlg) +{ + HWND hwndParent = GetParent(hwndDlg); + DLGHDR *pHdr = (DLGHDR *) GetWindowLong(hwndParent, GWL_USERDATA); + + SetWindowPos(hwndDlg, HWND_TOP, pHdr->rcDisplay.left, pHdr->rcDisplay.top, 0, 0, SWP_NOSIZE); +} + + + +LRESULT CALLBACK UIWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + HKEY hKey=0; + + switch (message) { + + case WM_INITDIALOG: + OnTabbedDialogInit(hWnd); + return (INT_PTR)TRUE; + + case WM_NOTIFY: + + switch (((LPNMHDR)lParam)->code) + { + case TCN_SELCHANGE: + OnSelChanged(hWnd); + return TRUE; + // More cases on WM_NOTIFY switch. + case NM_CHAR: + return TRUE; + } + + break; + + + case WM_CTLCOLORDLG: + return (LONG)bgBrush; + + case WM_CTLCOLORSTATIC: + { + HDC hdcStatic = (HDC)wParam; + SetTextColor(hdcStatic, RGB(0, 0, 0)); + SetBkMode(hdcStatic, TRANSPARENT); + + return (LONG)bgBrush; + } + + case WM_COMMAND: + + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + + switch (wmId) { + + case IDOK: + + return TRUE; + + default: + + return 0; + } + + + case WM_SYSCOMMAND: + + wmId = LOWORD(wParam); // Remember, these are... + wmEvent = HIWORD(wParam); // ...different for Win32! + + switch (wmId) + { + case SC_RESTORE: + + return (DefWindowProc(hWnd, message, wParam, lParam)); + + case SC_MINIMIZE: + + if (MinimizetoTray) + return ShowWindow(hWnd, SW_HIDE); + else + return (DefWindowProc(hWnd, message, wParam, lParam)); + + break; + + default: + return (DefWindowProc(hWnd, message, wParam, lParam)); + } + + case WM_CLOSE: + return(DestroyWindow(hWnd)); + + default: + return (DefWindowProc(hWnd, message, wParam, lParam)); + + } + + return (0); +} + +#endif + +extern struct DATAMESSAGE * REPLYBUFFER; +char * __cdecl Cmdprintf(TRANSPORTENTRY * Session, char * Bufferptr, const char * format, ...); + +void GetPortCTEXT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD) +{ + char FN[250]; + FILE *hFile; + struct stat STAT; + struct PORTCONTROL * PORT = PORTTABLE; + char PortList[256] = ""; + + while (PORT) + { + if (PORT->CTEXT) + { + free(PORT->CTEXT); + PORT->CTEXT = 0; + } + + if (BPQDirectory[0] == 0) + sprintf(FN, "Port%dCTEXT.txt", PORT->PORTNUMBER); + else + sprintf(FN, "%s/Port%dCTEXT.txt", BPQDirectory, PORT->PORTNUMBER); + + if (stat(FN, &STAT) == -1) + { + PORT = PORT->PORTPOINTER; + continue; + } + + hFile = fopen(FN, "rb"); + + if (hFile) + { + char * ptr; + + PORT->CTEXT = zalloc(STAT.st_size + 1); + fread(PORT->CTEXT , 1, STAT.st_size, hFile); + fclose(hFile); + + // convert CRLF or LF to CR + + while (ptr = strstr(PORT->CTEXT, "\r\n")) + memmove(ptr, ptr + 1, strlen(ptr)); + + // Now has LF + + while (ptr = strchr(PORT->CTEXT, '\n')) + *ptr = '\r'; + + + sprintf(PortList, "%s,%d", PortList, PORT->PORTNUMBER); + } + + PORT = PORT->PORTPOINTER; + } + + if (Session) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "CTEXT Read for ports %s\r", &PortList[1]); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + } + else + Debugprintf("CTEXT Read for ports %s\r", &PortList[1]); +} + +// Get the current frequency for a port. This can get a bit complicated, especially if looking for centre freq +// rather than dial freq (as this depends on mode). +// +// Used for various reporting functions - MH, Maps, BBS New User message, + +// I think I'll try PORT "PortFreq" setting first then if that isn't available via rigcontrol. +// +// For now at least will report dial freq if using RIGCONTROL + +DllExport uint64_t APIENTRY GetPortFrequency(int PortNo, char * FreqString) +{ + struct PORTCONTROL * PORT = GetPortTableEntryFromPortNum(PortNo); + double freq = 0.0; + uint64_t freqint = 0; + + char * ptr; + int n = 3; + + FreqString[0] = 0; + + if (PORT == 0) + return 0; + + if (PORT->PortFreq) + { + freqint = PORT->PortFreq; + freq = freqint / 1000000.0; + } + else + { + // Try rigcontrol + + + struct TNCINFO * TNC; + struct RIGINFO * RIG = 0; + + if (PORT->RIGPort) + TNC = TNCInfo[PORT->RIGPort]; + else + TNC = TNCInfo[PortNo]; + + if (TNC) + RIG = TNC->RIG; + + if (RIG == 0) + return 0; + + // Frequency should be in valchar + + if (RIG->Valchar[0] == 0) + return 0; + + freq = atof(TNC->RIG->Valchar); + freqint = (int64_t)(freq * 1000000.0); + } + + sprintf(FreqString, "%.6f", freq); + + // Return 3 digits after . (KHz) unless more are significant + + ptr = &FreqString[strlen(FreqString) - 1]; + + while (n-- && *(ptr) == '0') + *ptr-- = 0; + + return freqint; +} + +SOCKET OpenHTTPSock(char * Host) +{ + SOCKET sock = 0; + struct sockaddr_in destaddr; + struct sockaddr_in sinx; + int addrlen=sizeof(sinx); + struct hostent * HostEnt; + int err; + u_long param=1; + BOOL bcopt=TRUE; + + destaddr.sin_family = AF_INET; + destaddr.sin_port = htons(80); + + // Resolve name to address + + HostEnt = gethostbyname (Host); + + if (!HostEnt) + { + err = WSAGetLastError(); + + Debugprintf("Resolve Failed for %s %d %x", Host, err, err); + return 0 ; // Resolve failed + } + + memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4); + + // Allocate a Socket entry + + sock = socket(AF_INET,SOCK_STREAM,0); + + if (sock == INVALID_SOCKET) + return 0; + + setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4); + + sinx.sin_family = AF_INET; + sinx.sin_addr.s_addr = INADDR_ANY; + sinx.sin_port = 0; + + if (bind(sock, (struct sockaddr *) &sinx, addrlen) != 0 ) + return FALSE; + + if (connect(sock,(struct sockaddr *) &destaddr, sizeof(destaddr)) != 0) + { + err=WSAGetLastError(); + closesocket(sock); + return 0; + } + + return sock; +} + +static char HeaderTemplate[] = "POST %s HTTP/1.1\r\n" + "Accept: app N B lication/json\r\n" +// "Accept-Encoding: gzip,deflate,gzip, deflate\r\n" + "Content-Type: application/json\r\n" + "Host: %s:%d\r\n" + "Content-Length: %d\r\n" + "User-Agent: %s%s\r\n" +// "Expect: 100-continue\r\n" + "\r\n"; + + +DllExport VOID WINAPI SendWebRequest(char * Host, char * Request, char * Params, char * Return) +{ + SOCKET sock; + int InputLen = 0; + int inptr = 0; + char Buffer[4096]; + char Header[256]; + char * ptr, * ptr1; + int Sent; + int Len = strlen(Params); + + if (M0LTEMap == 0) + return; + + sock = OpenHTTPSock(Host); + + if (sock == 0) + return; + +#ifdef LINBPQ + sprintf(Header, HeaderTemplate, Request, Host, 80, Len, "linbpq/", VersionString, Params); +#else + sprintf(Header, HeaderTemplate, Request, Host, 80, Len, "bpq32/", VersionString, Params); +#endif + Sent = send(sock, Header, (int)strlen(Header), 0); + Sent = send(sock, Params, (int)strlen(Params), 0); + + if (Sent == -1) + { + int Err = WSAGetLastError(); + Debugprintf("Error %d from Web Update send()", Err); + closesocket(sock); + return; + } + + while (InputLen != -1) + { + InputLen = recv(sock, &Buffer[inptr], 4095 - inptr, 0); + + if (InputLen == -1 || InputLen == 0) + { + int Err = WSAGetLastError(); + Debugprintf("Error %d from Web Update recv()", Err); + closesocket(sock); + return; + } + + inptr += InputLen; + + Buffer[inptr] = 0; + + ptr = strstr(Buffer, "\r\n\r\n"); + + if (ptr) + { + // got header + + int Hddrlen = (int)(ptr - Buffer); + + ptr1 = strstr(Buffer, "Content-Length:"); + + if (ptr1) + { + // Have content length + + int ContentLen = atoi(ptr1 + 16); + + if (ContentLen + Hddrlen + 4 == inptr) + { + // got whole response + + if (strstr(Buffer, " 200 OK")) + { + if (Return) + { + memcpy(Return, ptr + 4, ContentLen); + Return[ContentLen] = 0; + } + else + Debugprintf("Map Database update ok"); + + } + else + { + strlop(Buffer, 13); + Debugprintf("Map Update failed - %s", Buffer); + } + closesocket(sock); + return; + } + } + else + { + ptr1 = strstr(_strlwr(Buffer), "transfer-encoding:"); + + if (ptr1) + { + // Just accept anything until I've sorted things with Lee + + closesocket(sock); + Debugprintf("Web Database update ok"); + return; + } + } + } + } +} + +// https://packetnodes.spots.radio/api/NodeData/{callsign} + +//SendHTTPRequest(sock, "/account/exists", Message, Len, Response); + +#include "kiss.h" + +extern char MYALIASLOPPED[10]; +extern int MasterPort[MAXBPQPORTS+1]; + + +// G7TAJ // +/* + {"mheard": [ + { + "Callsign": "GB7CIP-7", + "Port": "VHF", + "Packets": 70369, + "LastHeard": "2024-12-29 20:26:32" + }, +*/ + +void BuildPortMH(char * MHJSON, struct PORTCONTROL * PORT) +{ + struct tm * TM; + static char MHTIME[50]; + time_t szClock; + MHSTRUC * MH = PORT->PORTMHEARD; + int count = MHENTRIES; + char Normcall[20]; + int len; + char * ptr; + char mhstr[400]; + int i; + char c; + + if (MH == NULL) + return; + + while (count--) + { + if (MH->MHCALL[0] == 0) + break; + + len = ConvFromAX25(MH->MHCALL, Normcall); + Normcall[len] = 0; + + ptr = &MH->MHCALL[6]; // End of Address bit + + if ((*ptr & 1) == 0) + { + // at least one digi - which we are not going to include + MH++; + continue; + } + + // validate call to prevent corruption of json + + for (i=0; i < len; i++) + { + c = Normcall[i]; + + if (!isalnum(c) && !(c == '#') && !(c == ' ') && !(c == '-')) + goto skipit; + } + + + //format TIME + + szClock = MH->MHTIME; + TM = gmtime(&szClock); + sprintf(MHTIME, "%d-%d-%d %02d:%02d:%02d", + TM->tm_year+1900, TM->tm_mon + 1, TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec); + + sprintf(mhstr, "{\"callSign\": \"%s\", \"port\": \"%d\", \"packets\": %d, \"lastHeard\": \"%s\" },\r\n" , + Normcall, PORT->PORTNUMBER, MH->MHCOUNT, MHTIME); + + strcat( MHJSON, mhstr ); +skipit: + MH++; + } +} + +void SendDataToPktMapThread(); + +void SendDataToPktMap() +{ + _beginthread(SendDataToPktMapThread,2048000,0); +} + +void SendDataToPktMapThread() +{ + char Return[256] = ""; + char Request[64]; + char Params[50000]; + + struct PORTCONTROL * PORT = PORTTABLE; + struct PORTCONTROL * SAVEPORT; + struct ROUTE * Routes = NEIGHBOURS; + int MaxRoutes = MAXNEIGHBOURS; + + int PortNo; + int Active; + uint64_t Freq; + int Baud; + int Bitrate; + char * Mode; + char * Use; + char * Type; + char * Modulation; + char * Usage; + + char locked[] = " ! "; + int Percent = 0; + int Port = 0; + char Normcall[10]; + char Copy[20]; + char ID[33]; + + char * ptr = Params; + +// G7TAJ // + char MHJSON[50000]; + char * mhptr; + char * b4Routesptr; + + MHJSON[0]=0; +// G7TAJ // + +// printf("Sending to new map\n"); + + sprintf(Request, "/api/NodeData/%s", MYNODECALL); + +// https://packetnodes.spots.radio/swagger/index.html + + // This builds the request and sends it + + // Minimum header seems to be + + // "nodeAlias": "BPQ", + // "location": {"locator": "IO68VL"}, + // "software": {"name": "BPQ32","version": "6.0.24.3"}, + + ptr += sprintf(ptr, "{\"nodeAlias\": \"%s\",\r\n", MYALIASLOPPED); + + if (strlen(LOCATOR) == 6) + ptr += sprintf(ptr, "\"location\": {\"locator\": \"%s\"},\r\n", LOCATOR); + else + { + // Lat Lon + + double myLat, myLon; + char LocCopy[80]; + char * context; + + strcpy(LocCopy, LOCATOR); + + myLat = atof(strtok_s(LocCopy, ",:; ", &context)); + myLon = atof(context); + + ptr += sprintf(ptr, "\"location\": {\"coords\": {\"lat\": %f, \"lon\": %f}},\r\n", + myLat, myLon); + + } + +#ifdef LINBPQ + ptr += sprintf(ptr, "\"software\": {\"name\": \"LINBPQ\",\"version\": \"%s\"},\r\n", VersionString); +#else + ptr += sprintf(ptr, "\"software\": {\"name\": \"BPQ32\",\"version\": \"%s\"},\r\n", VersionString); +#endif + ptr += sprintf(ptr, "\"source\": \"ReportedByNode\",\r\n"); + +// G7TAJ // + sprintf(MHJSON, ",\"mheard\": ["); +// G7TAJ // + + + //Ports + + ptr += sprintf(ptr, "\"ports\": ["); + + // Get active ports + + while (PORT) + { + PortNo = PORT->PORTNUMBER; + + if (PORT->Hide) + { + PORT = PORT->PORTPOINTER; + continue; + } + + if (PORT->SendtoM0LTEMap == 0) + { + PORT = PORT->PORTPOINTER; + continue; + } + + // Try to get port status - may not be possible with some + + if (PORT->PortStopped) + { + PORT = PORT->PORTPOINTER; + continue; + } + + Active = 0; + Freq = 0; + Baud = 0; + Mode = "ax.25"; + Use = ""; + Type = "RF"; + Bitrate = 0; + Modulation = "FSK"; + Usage = "Access"; + + if (PORT->PortFreq) + Freq = PORT->PortFreq; + + if (PORT->PORTTYPE == 0) + { + struct KISSINFO * KISS = (struct KISSINFO *)PORT; + NPASYINFO Port; + + SAVEPORT = PORT; + + if (KISS->FIRSTPORT && KISS->FIRSTPORT != KISS) + { + // Not first port on device + + PORT = (struct PORTCONTROL *)KISS->FIRSTPORT; + Port = KISSInfo[PortNo]; + } + + Port = KISSInfo[PORT->PORTNUMBER]; + + if (Port) + { + // KISS like - see if connected + + if (PORT->PORTIPADDR.s_addr || PORT->KISSSLAVE) + { + // KISS over UDP or TCP + + if (PORT->KISSTCP) + { + if (Port->Connected) + Active = 1; + } + else + Active = 1; // UDP - Cant tell + } + else + if (Port->idComDev) // Serial port Open + Active = 1; + + PORT = SAVEPORT; + } + } + else if (PORT->PORTTYPE == 14) // Loopback + Active = 0; + + else if (PORT->PORTTYPE == 16) // External + { + if (PORT->PROTOCOL == 10) // 'HF' Port + { + struct TNCINFO * TNC = TNCInfo[PortNo]; + struct AGWINFO * AGW; + + if (TNC == NULL) + { + PORT = PORT->PORTPOINTER; + continue; + } + + if (Freq == 0 && TNC->RIG) + Freq = TNC->RIG->RigFreq * 1000000; + + switch (TNC->Hardware) // Hardware Type + { + case H_KAM: + case H_AEA: + case H_HAL: + case H_SERIAL: + + // Serial + + if (TNC->hDevice) + Active = 1; + + break; + + case H_SCS: + case H_TRK: + case H_WINRPR: + + if (TNC->HostMode) + Active = 1; + + break; + + + case H_UZ7HO: + + if (TNCInfo[MasterPort[PortNo]]->CONNECTED) + Active = 1; + + // Try to get mode and frequency + + AGW = TNC->AGWInfo; + + if (AGW && AGW->isQTSM) + { + if (AGW->ModemName[0]) + { + char * ptr1, * ptr2, *Context; + + strcpy(Copy, AGW->ModemName); + ptr1 = strtok_s(Copy, " ", & Context); + ptr2 = strtok_s(NULL, " ", & Context); + + if (Context) + { + Modulation = Copy; + + if (strstr(ptr1, "BPSK") || strstr(ptr1, "AFSK")) + { + Baud = Bitrate = atoi(Context); + } + else if (strstr(ptr1, "QPSK")) + { + Modulation = "QPSK"; + Bitrate = atoi(Context); + Baud = Bitrate /2; + } + } + } + } + + break; + + case H_KISSHF: + + // Try to get mode from ID then drop through + + if (stristr(PORT->PORTDESCRIPTION, "BPSK")) + { + Modulation = "BPSK"; + } + + case H_WINMOR: + case H_V4: + + case H_MPSK: + case H_FLDIGI: + case H_UIARQ: + case H_ARDOP: + case H_VARA: + + case H_FREEDATA: + + // TCP + + Mode = Modenames[TNC->Hardware - 1]; + + if (TNC->CONNECTED) + Active = 1; + + break; + + case H_TELNET: + + Active = 1; + Type = "Internet"; + Mode = ""; + } + } + else + { + // External but not HF - AXIP, BPQETHER VKISS, ?? + + struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)PORT; + Type = "Internet"; + Active = 1; + } + } + + if (Active) + { + char * ptr2 = &ID[29]; + strcpy(ID, PORT->PORTDESCRIPTION); + while (*(ptr2) == ' ' && ptr2 != ID) + *(ptr2--) = 0; + + if (PORT->M0LTEMapInfo) + { + // Override with user configured values - RF,7.045,BPSK,300,300,Access + + char param[256]; + char *p1, *p2, *p3, *p4, *p5; + + strcpy(param, PORT->M0LTEMapInfo); + + p1 = strlop(param, ','); + p2 = strlop(p1, ','); + p3 = strlop(p2, ','); + p4 = strlop(p3, ','); + p5 = strlop(p4, ','); + + // int n = sscanf(PORT->M0LTEMapInfo, "%s,%s,%s,%s,%s,%s", &p1, &p2, &p3, &p4, &p5, &p6); + + if (p5) + { + if (param[0]) Type = param; + + if (p1[0]) + { + // if set to DIAL+=n and frequency set from config or rigcontrol modify it + + uint64_t offset = 0; + + if (_memicmp(p1, "DIAL+", 5) == 0) + offset = atoi(&p1[5]); + else if (_memicmp(p1, "DIAL-", 5) == 0) + offset = -atoi(&p1[5]); + else + Freq = atof(p1) * 1000000; + + if (Freq != 0) + Freq += offset; + + } + + if (p2[0]) Modulation = p2; + if (p3[0]) Baud = atoi(p3); + if (p4[0]) Bitrate = atoi(p4); + if (p5[0]) Usage = p5; + } + } + + ptr += sprintf(ptr, "{\"id\": \"%d\",\"linkType\": \"%s\"," + "\"freq\": \"%lld\",\"mode\": \"%s\",\"modulation\": \"%s\"," + "\"baud\": \"%d\",\"bitrate\": \"%d\",\"usage\": \"%s\",\"comment\": \"%s\"},\r\n", + PortNo, Type, + Freq, Mode, Modulation, + Baud, Bitrate, Usage, ID); + +// G7TAJ // + // make MH list to be added later + BuildPortMH(MHJSON, PORT); + +// G7TAJ // + + + } + + PORT = PORT->PORTPOINTER; + } + + ptr -= 3; + ptr += sprintf(ptr, "],\r\n"); + + // Neighbours + +// G7TAJ // + b4Routesptr = ptr-3; +// G7TAJ // + + ptr += sprintf(ptr, "\"neighbours\": [\r\n"); + + while (MaxRoutes--) + { + if (Routes->NEIGHBOUR_CALL[0] != 0) + if (Routes->NEIGHBOUR_LINK && Routes->NEIGHBOUR_LINK->L2STATE >= 5) + { + ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall); + strlop(Normcall, ' '); + + ptr += sprintf(ptr, + "{\"node\": \"%s\", \"port\": \"%d\", \"quality\": \"%d\"},\r\n", + Normcall, Routes->NEIGHBOUR_PORT, Routes->NEIGHBOUR_QUAL); + } + + Routes++; + } + +// G7TAJ // + + // if !strstr quality, then there are none, so remove neighbours portion + if ( strstr(Params, "quality") == NULL ) { + ptr = b4Routesptr; + } else { + ptr -= 3; + ptr += sprintf(ptr, "]"); + } + + if ( strlen(MHJSON) > 15 ) { + mhptr = MHJSON + strlen(MHJSON); + mhptr -= 3; + sprintf(mhptr, "]\r\n"); + ptr += sprintf(ptr, "\r\n%s", MHJSON); + + } + + ptr += sprintf(ptr, "}"); + + + +// G7TAJ // + + +/* +{ + "nodeAlias": "BPQ", + "location": {"locator": "IO92KX"}, + "software": {"name": "BPQ32","version": "6.0.24.11 Debug Build "}, + "contact": "G8BPQ", + "sysopComment": "Testing", + "source": "ReportedByNode" +} + + "ports": [ + { + "id": "string", + "linkType": "RF", + "freq": 0, + "mode": "string", + "modulation": "string", + "baud": 0, + "bitrate": 0, + "usage": "Access", + "comment": "string" + } + ], + +*/ + // "contact": "string", + // "neighbours": [{"node": "G7TAJ","port": "30"}] + + SendWebRequest("packetnodes.spots.radio", Request, Params, 0); +} + +// ="{\"neighbours\": [{\"node\": \"G7TAJ\",\"port\": \"30\"}]}"; + +//'POST' \ +// 'https://packetnodes.spots.radio/api/NodeData/GM8BPQ' \ +// -H 'accept: */*' \ +// -H 'Content-Type: application/json' \ +// -d '{ +// "nodeAlias": "BPQ", +// "location": {"locator": "IO68VL"}, +// "software": {"name": "BPQ32","version": "6.0.24.3"}, +// "contact": "string", +// "neighbours": [{"node": "G7TAJ","port": "30"}] +//}' + + + + + + + + + diff --git a/CommonCode.c b/CommonCode.c index b02b0fa..18d412c 100644 --- a/CommonCode.c +++ b/CommonCode.c @@ -32,7 +32,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #pragma data_seg("_BPQDATA") -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "configstructs.h" @@ -69,7 +69,7 @@ VOID WriteMiniDump(); void printStack(void); char * FormatMH(PMHSTRUC MH, char Format); void WriteConnectLog(char * fromCall, char * toCall, UCHAR * Mode); -void SendDataToPktMap(char *Msg); +void SendDataToPktMap(); extern BOOL LogAllConnects; extern BOOL M0LTEMap; @@ -571,7 +571,7 @@ void * zalloc(int len) return ptr; } -char * strlop(const char * buf, char delim) +char * strlop(char * buf, char delim) { // Terminate buf at delim, and return rest of string @@ -1456,7 +1456,21 @@ DllExport int APIENTRY SessionStateNoAck(int stream, int * state) return 0; } + +int SendMsgEx(int stream, char * msg, int len, int GetSem); + +int SendMsgNoSem(int stream, char * msg, int len) +{ + return SendMsgEx(stream, msg, len, 0); +} + DllExport int APIENTRY SendMsg(int stream, char * msg, int len) +{ + return SendMsgEx(stream, msg, len, 1); +} + + +int SendMsgEx(int stream, char * msg, int len, int GetSem) { // Send message to stream (BPQHOST Function 2) @@ -1479,11 +1493,13 @@ DllExport int APIENTRY SendMsg(int stream, char * msg, int len) if (QCOUNT < 50) return 0; // Dont want to run out - GetSemaphore(&Semaphore, 10); + if (GetSem) + GetSemaphore(&Semaphore, 10); if ((MSG = GetBuff()) == 0) { - FreeSemaphore(&Semaphore); + if (GetSem) + FreeSemaphore(&Semaphore); return 0; } @@ -1494,7 +1510,8 @@ DllExport int APIENTRY SendMsg(int stream, char * msg, int len) SENDUIMESSAGE(MSG); ReleaseBuffer(MSG); - FreeSemaphore(&Semaphore); + if (GetSem) + FreeSemaphore(&Semaphore); return 0; } @@ -1509,13 +1526,15 @@ DllExport int APIENTRY SendMsg(int stream, char * msg, int len) if (L4 == 0) return 0; - GetSemaphore(&Semaphore, 22); + if (GetSem) + GetSemaphore(&Semaphore, 22); SESS->HOSTFLAGS |= 0x80; // SET ALLOCATED BIT if (QCOUNT < 40) // PLENTY FREE? { - FreeSemaphore(&Semaphore); + if (GetSem) + FreeSemaphore(&Semaphore); return 1; } @@ -1528,14 +1547,16 @@ DllExport int APIENTRY SendMsg(int stream, char * msg, int len) if (n > 100) { Debugprintf("Stream %d QCOUNT %d Q Len %d - discarding", stream, QCOUNT, n); - FreeSemaphore(&Semaphore); + if (GetSem) + FreeSemaphore(&Semaphore); return 1; } } if ((MSG = GetBuff()) == 0) { - FreeSemaphore(&Semaphore); + if (GetSem) + FreeSemaphore(&Semaphore); return 1; } @@ -1562,7 +1583,8 @@ DllExport int APIENTRY SendMsg(int stream, char * msg, int len) else C_Q_ADD(&L4->L4RX_Q, MSG); - FreeSemaphore(&Semaphore); + if (GetSem) + FreeSemaphore(&Semaphore); return 0; } DllExport int APIENTRY SendRaw(int port, char * msg, int len) @@ -3318,7 +3340,7 @@ VOID SendLocation() SendReportMsg((char *)&AXMSG.DEST, Len + 16); if (M0LTEMap) - SendDataToPktMap(""); + SendDataToPktMap(); return; @@ -3326,7 +3348,6 @@ VOID SendLocation() - VOID SendMH(struct TNCINFO * TNC, char * call, char * freq, char * LOC, char * Mode) { MESSAGE AXMSG; @@ -3342,7 +3363,8 @@ VOID SendMH(struct TNCINFO * TNC, char * call, char * freq, char * LOC, char * M // Block includes the Msg Header (7 bytes), Len Does not! memcpy(AXPTR->DEST, ReportDest, 7); - if (TNC->PortRecord->PORTCONTROL.PORTCALL[0]) + + if (TNC && TNC->PortRecord->PORTCONTROL.PORTCALL[0]) memcpy(AXPTR->ORIGIN, TNC->PortRecord->PORTCONTROL.PORTCALL, 7); else memcpy(AXPTR->ORIGIN, MYCALL, 7); @@ -3502,8 +3524,10 @@ int __sync_lock_test_and_set(int * ptr, int val) #endif // MACBPQ +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) -void GetSemaphore(struct SEM * Semaphore, int ID) + +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line) { // // Wait for it to be free @@ -3547,6 +3571,8 @@ loop1: Semaphore->SemProcessID = GetCurrentProcessId(); Semaphore->SemThreadID = GetCurrentThreadId(); SemHeldByAPI = ID; + Semaphore->Line = Line; + strcpy(Semaphore->File, File); return; } @@ -4171,10 +4197,10 @@ VOID GetUIConfig() if (group) { - GetStringValue(group, "UIDEST", &UIUIDEST[Port][0]); - GetStringValue(group, "FileName", &FN[Port][0]); - GetStringValue(group, "Message", &Message[Port][0]); - GetStringValue(group, "Digis", Digis); + GetStringValue(group, "UIDEST", &UIUIDEST[Port][0], 11); + GetStringValue(group, "FileName", &FN[Port][0], 256); + GetStringValue(group, "Message", &Message[Port][0], 1000); + GetStringValue(group, "Digis", Digis, 100); UIUIDigi[Port] = _strdup(Digis); Interval[Port] = GetIntValue(group, "Interval"); @@ -4205,15 +4231,21 @@ int GetIntValue(config_setting_t * group, char * name) return 0; } -BOOL GetStringValue(config_setting_t * group, char * name, char * value) +BOOL GetStringValue(config_setting_t * group, char * name, char * value, int maxlen) { - const char * str; + char * str; config_setting_t *setting; setting = config_setting_get_member (group, name); if (setting) { - str = config_setting_get_string (setting); + str = (char *)config_setting_get_string(setting); + + if (strlen(str) > maxlen) + { + Debugprintf("Suspect config record %s", str); + str[maxlen] = 0; + } strcpy(value, str); return TRUE; } @@ -5131,10 +5163,16 @@ skipit: } } +void SendDataToPktMapThread(); -void SendDataToPktMap(char *Msg) +void SendDataToPktMap() { - char Return[256]; + _beginthread(SendDataToPktMapThread,2048000,0); +} + +void SendDataToPktMapThread() +{ + char Return[256] = ""; char Request[64]; char Params[50000]; @@ -5582,7 +5620,7 @@ void SendDataToPktMap(char *Msg) // "contact": "string", // "neighbours": [{"node": "G7TAJ","port": "30"}] - SendWebRequest("packetnodes.spots.radio", Request, Params, Return); + SendWebRequest("packetnodes.spots.radio", Request, Params, 0); } // ="{\"neighbours\": [{\"node\": \"G7TAJ\",\"port\": \"30\"}]}"; diff --git a/DOSAPI.c b/DOSAPI.c index 49db0f1..5780608 100644 --- a/DOSAPI.c +++ b/DOSAPI.c @@ -32,7 +32,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "compatbits.h" -#include "CHeaders.h" +#include "cheaders.h" extern QCOUNT; extern BPQVECSTRUC BPQHOSTVECTOR[]; diff --git a/DRATS.c b/DRATS.c index 8c7e9e9..c7b6b83 100644 --- a/DRATS.c +++ b/DRATS.c @@ -21,7 +21,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #include "bpq32.h" #include "telnetserver.h" diff --git a/Events.c b/Events.c index e47e012..6d5f618 100644 --- a/Events.c +++ b/Events.c @@ -125,7 +125,6 @@ void hookL2SessionAccepted(int Port, char * remotecall, char * ourcall, struct _ strcpy(LINK->callingCall, remotecall); strcpy(LINK->receivingCall, ourcall); strcpy(LINK->Direction, "In"); - } void hookL2SessionDeleted(struct _LINKTABLE * LINK) diff --git a/FBBRoutines.c b/FBBRoutines.c index 67ca4ee..1810bf9 100644 --- a/FBBRoutines.c +++ b/FBBRoutines.c @@ -23,6 +23,10 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "bpqmail.h" +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); + + int32_t Encode(char * in, char * out, int32_t inlen, BOOL B1Protocol, int Compress); void MQTTMessageEvent(void* message); diff --git a/FLDigi.c b/FLDigi.c index 89d1597..480a443 100644 --- a/FLDigi.c +++ b/FLDigi.c @@ -23,7 +23,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" extern int (WINAPI FAR *GetModuleFileNameExPtr)(); extern int (WINAPI FAR *EnumProcessesPtr)(); diff --git a/FreeDATA.c b/FreeDATA.c index 01fb151..66ff40a 100644 --- a/FreeDATA.c +++ b/FreeDATA.c @@ -32,7 +32,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #endif #endif -#include "CHeaders.h" +#include "cheaders.h" #include "bpq32.h" #include "tncinfo.h" diff --git a/HALDriver.c b/HALDriver.c index b15d4fe..a914a38 100644 --- a/HALDriver.c +++ b/HALDriver.c @@ -28,7 +28,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "time.h" -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "bpq32.h" diff --git a/HFCommon.c b/HFCommon.c index ba936dd..c0f82d7 100644 --- a/HFCommon.c +++ b/HFCommon.c @@ -30,7 +30,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "kernelresource.h" -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #ifndef LINBPQ #include diff --git a/HSMODEM.c b/HSMODEM.c index a9af669..4efdb80 100644 --- a/HSMODEM.c +++ b/HSMODEM.c @@ -33,7 +33,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #endif -#include "CHeaders.h" +#include "cheaders.h" #pragma pack(1) diff --git a/HTMLCommonCode.c b/HTMLCommonCode.c index 9e2a3eb..b86a7eb 100644 --- a/HTMLCommonCode.c +++ b/HTMLCommonCode.c @@ -27,7 +27,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #pragma data_seg("_BPQDATA") -#include "CHeaders.h" +#include "cheaders.h" #include "templatedefs.c" // Inline definitions from HTLMPages diff --git a/HTTPcode-skigdebian.c b/HTTPcode-skigdebian.c new file mode 100644 index 0000000..ac0a3ff --- /dev/null +++ b/HTTPcode-skigdebian.c @@ -0,0 +1,5175 @@ +/* +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 +*/ + + +//#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#define _CRT_SECURE_NO_DEPRECATE + +#define DllImport + +#include "cheaders.h" +#include + +#include "tncinfo.h" +#include "time.h" +#include "bpq32.h" +#include "telnetserver.h" + +// This is needed to link with a lib built from source + +#ifdef WIN32 +#define ZEXPORT __stdcall +#endif + +#include + +#define CKernel +#include "httpconnectioninfo.h" + +extern int MAXBUFFS, QCOUNT, MINBUFFCOUNT, NOBUFFCOUNT, BUFFERWAITS, L3FRAMES; +extern int NUMBEROFNODES, MAXDESTS, L4CONNECTSOUT, L4CONNECTSIN, L4FRAMESTX, L4FRAMESRX, L4FRAMESRETRIED, OLDFRAMES; +extern int STATSTIME; +extern TRANSPORTENTRY * L4TABLE; +extern BPQVECSTRUC BPQHOSTVECTOR[]; +extern BOOL APRSApplConnected; +extern char VersionString[]; +VOID FormatTime3(char * Time, time_t cTime); +DllExport int APIENTRY Get_APPLMASK(int Stream); +VOID SaveUIConfig(); +int ProcessNodeSignon(SOCKET sock, struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, int LOCAL); +VOID SetupUI(int Port); +VOID SendUIBeacon(int Port); +VOID GetParam(char * input, char * key, char * value); +VOID ARDOPAbort(struct TNCINFO * TNC); +VOID WriteMiniDump(); +BOOL KillTNC(struct TNCINFO * TNC); +BOOL RestartTNC(struct TNCINFO * TNC); +int GetAISPageInfo(char * Buffer, int ais, int adsb); +int GetAPRSPageInfo(char * Buffer, double N, double S, double W, double E, int aprs, int ais, int adsb); +unsigned char * Compressit(unsigned char * In, int Len, int * OutLen); +char * stristr (char *ch1, char *ch2); +int GetAPRSIcon(unsigned char * _REPLYBUFFER, char * NodeURL); +char * GetStandardPage(char * FN, int * Len); +BOOL SHA1PasswordHash(char * String, char * Hash); +char * byte_base64_encode(char *str, int len); +int APIProcessHTTPMessage(char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE); +int RHPProcessHTTPMessage(struct ConnectionInfo * conn, char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE); + +extern struct ROUTE * NEIGHBOURS; +extern int ROUTE_LEN; +extern int MAXNEIGHBOURS; + +extern struct DEST_LIST * DESTS; // NODE LIST +extern int DEST_LIST_LEN; +extern int MAXDESTS; // MAX NODES IN SYSTEM + +extern struct _LINKTABLE * LINKS; +extern int LINK_TABLE_LEN; +extern int MAXLINKS; +extern char * RigWebPage; +extern COLORREF Colours[256]; + +extern BOOL IncludesMail; +extern BOOL IncludesChat; + +extern BOOL APRSWeb; +extern BOOL RigActive; + +extern HKEY REGTREE; + +extern BOOL APRSActive; + +extern UCHAR LogDirectory[]; + +extern struct RIGPORTINFO * PORTInfo[34]; +extern int NumberofPorts; + +extern UCHAR ConfigDirectory[260]; + +VOID sendandcheck(SOCKET sock, const char * Buffer, int Len); +int CompareNode(const void *a, const void *b); +int CompareAlias(const void *a, const void *b); +void ProcessMailHTTPMessage(struct HTTPConnectionInfo * Session, char * Method, char * URL, char * input, char * Reply, int * RLen, int InputLen, char * Token); +void ProcessChatHTTPMessage(struct HTTPConnectionInfo * Session, char * Method, char * URL, char * input, char * Reply, int * RLen); +struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot); +int SetupNodeMenu(char * Buff, int SYSOP); +int StatusProc(char * Buff); +int ProcessMailSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, BOOL WebMail, int LOCAL); +int ProcessMailAPISignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, BOOL WebMail, int LOCAL); +int ProcessChatSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, int LOCAL); +VOID APRSProcessHTTPMessage(SOCKET sock, char * MsgPtr, BOOL LOCAL, BOOL COOKIE); + + +static struct HTTPConnectionInfo * SessionList; // active term mode sessions + +char Mycall[10]; + +char MAILPipeFileName[] = "\\\\.\\pipe\\BPQMAILWebPipe"; +char CHATPipeFileName[] = "\\\\.\\pipe\\BPQCHATWebPipe"; + +char Index[] = "%s's BPQ32 Web Server

" +"" +"" +"
Node PagesAPRS Pages
"; + +char IndexNoAPRS[] = "" +""; + +//char APRSBit[] = "APRS Pages"; + +//char MailBit[] = "Mail Mgmt" +// "WebMail"; +//char ChatBit[] = "Chat Mgmt"; + +char Tail[] = ""; + +char RouteHddr[] = "

Routes

" +""; + +char RouteLine[] = ""; +char xNodeHddr[] = "
" +"
PortCallQualityNode CountFrame CountRetriesPercentMaxframeFrackLast HeardQueuedRem Qual
%s%d%s%c%d%d%d%d%d%%d%d%02d:%02d%d%d
" +"
" +"" +"
" +"

Nodes %s

"; + +char NodeHddr[] = "
" +"" +"" +"
" +"

Nodes %s

"; + +char NodeLine[] = ""; + + +char StatsHddr[] = "

Node Stats

%s:%s
" +""; + +char PortStatsHddr[] = "

Stats for Port %d

"; + +char PortStatsLine[] = ""; + + +char Beacons[] = "

Beacon Configuration for Port %d

You need to be signed in to save changes

%s %d
" +"" +"
" +"" +"" +"" +"" +"" +"
Send Interval (Minutes)
To
Path
Send From File
Text
" +"" + +"

" +""; + + +char LinkHddr[] = "

Links

" +""; + +char LinkLine[] = ""; + +char UserHddr[] = "

Sessions

Far CallOur CallPortax.25 stateLink Typeax.25 Version
%s%s%d%s%s%d
"; + +char UserLine[] = ""; + +char TermSignon[] = "BPQ32 Node %s Terminal Access" +"

BPQ32 Node %s Terminal Access

" +"

Please enter username and password to access the node

" +"" +"
%s%s%s
" +"" +"
User
Password
" +"

" +""; + + +char PassError[] = "

Sorry, User or Password is invalid - please try again

"; + +char BusyError[] = "

Sorry, No sessions available - please try later

"; + +char LostSession[] = "Sorry, Session had been lost - refresh page to sign in again"; +char NoSessions[] = "Sorry, No Sessions available - refresh page to try again"; + +char TermPage[] = "" +"BPQ32 Node %s" +"" +"" +"

BPQ32 Node %s

" +"
" +"

" +"" +"" +""; + +char TermOutput[] = "" +"" +"" +"" +"" +"" +"" +"
\""; + + +// font-family:monospace;background-color:black;color:lawngreen;font-size:12px + +char TermOutputTail[] = "
"; + +/* +char InputLine[] = "" +"
" +"" +"
"; +*/ +char InputLine[] = "" +"
" +"\" id=inp type=text text width=100%% name=input />" +"
"; + +static char NodeSignon[] = "BPQ32 Node SYSOP Access" +"

BPQ32 Node %s SYSOP Access

" +"

This page sets Cookies. Don't continue if you object to this

" +"

Please enter Callsign and Password to access the Node

" +"
" +"" +"" +"
User
Password
" +"

"; + + +static char MailSignon[] = "BPQ32 Mail Server Access" +"

BPQ32 Mail Server %s Access

" +"

Please enter Callsign and Password to access the BBS

" +"
" +"" +"" +"
User
Password
" +"

"; + +static char ChatSignon[] = "BPQ32 Chat Server Access" +"

BPQ32 Chat Server %s Access

" +"

Please enter Callsign and Password to access the Chat Server

" +"
" +"" +"" +"
User
Password
" +"

"; + + +static char MailLostSession[] = "" +"
" +"Sorry, Session had been lost

    " +"
"; + + +static char ConfigEditPage[] = "" +"Edit Config" +"
" +"

" +"
"; + +static char EXCEPTMSG[80] = ""; + + +void UndoTransparency(char * input) +{ + char * ptr1, * ptr2; + char c; + int hex; + + if (input == NULL) + return; + + ptr1 = ptr2 = input; + + // Convert any %xx constructs + + while (1) + { + c = *(ptr1++); + + if (c == 0) + break; + + if (c == '%') + { + c = *(ptr1++); + if(isdigit(c)) + hex = (c - '0') << 4; + else + hex = (tolower(c) - 'a' + 10) << 4; + + c = *(ptr1++); + if(isdigit(c)) + hex += (c - '0'); + else + hex += (tolower(c) - 'a' + 10); + + *(ptr2++) = hex; + } + else if (c == '+') + *(ptr2++) = 32; + else + *(ptr2++) = c; + } + *ptr2 = 0; +} + + + + +VOID PollSession(struct HTTPConnectionInfo * Session) +{ + int state, change; + int count, len; + char Msg[400] = ""; + char Formatted[8192]; + char * ptr1, * ptr2; + char c; + int Line; + + // Poll Node + + SessionState(Session->Stream, &state, &change); + + if (change == 1) + { + int Line = Session->LastLine++; + free(Session->ScreenLines[Line]); + + if (state == 1)// Connected + Session->ScreenLines[Line] = _strdup("*** Connected
\r\n"); + else + Session->ScreenLines[Line] = _strdup("*** Disconnected
\r\n"); + + if (Line == 99) + Session->LastLine = 0; + + Session->Changed = TRUE; + } + + if (RXCount(Session->Stream) > 0) + { + int realLen = 0; + + do + { + GetMsg(Session->Stream, &Msg[0], &len, &count); + + // replace cr with
and space with   + + + ptr1 = Msg; + ptr2 = &Formatted[0]; + + if (Session->PartLine) + { + // Last line was incomplete - append to it + + realLen = Session->PartLine; + + Line = Session->LastLine - 1; + + if (Line < 0) + Line = 99; + + strcpy(Formatted, Session->ScreenLines[Line]); + ptr2 += strlen(Formatted); + + Session->LastLine = Line; + Session->PartLine = FALSE; + } + + while (len--) + { + c = *(ptr1++); + realLen++; + + if (c == 13) + { + int LineLen; + + strcpy(ptr2, "
\r\n"); + + // Write to screen + + Line = Session->LastLine++; + free(Session->ScreenLines[Line]); + + LineLen = (int)strlen(Formatted); + + // if line starts with a colour code, process it + + if (Formatted[0] == 0x1b && LineLen > 1) + { + int ColourCode = Formatted[1] - 10; + COLORREF Colour = Colours[ColourCode]; + char ColString[30]; + + memmove(&Formatted[20], &Formatted[2], LineLen); + sprintf(ColString, "", GetRValue(Colour), GetGValue(Colour), GetBValue(Colour)); + memcpy(Formatted, ColString, 20); + strcat(Formatted, ""); + LineLen =+ 28; + } + + Session->ScreenLineLen[Line] = LineLen; + Session->ScreenLines[Line] = _strdup(Formatted); + + if (Line == 99) + Session->LastLine = 0; + + ptr2 = &Formatted[0]; + realLen = 0; + + } + else if (c == 32) + { + memcpy(ptr2, " ", 6); + ptr2 += 6; + + // Make sure line isn't too long + // but beware of spaces expanded to   - count chars in line + + if ((realLen) > 100) + { + strcpy(ptr2, "
\r\n"); + + Line = Session->LastLine++; + free(Session->ScreenLines[Line]); + + Session->ScreenLines[Line] = _strdup(Formatted); + + if (Line == 99) + Session->LastLine = 0; + + ptr2 = &Formatted[0]; + realLen = 0; + } + } + else if (c == '>') + { + memcpy(ptr2, ">", 4); + ptr2 += 4; + } + else if (c == '<') + { + memcpy(ptr2, "<", 4); + ptr2 += 4; + } + else + *(ptr2++) = c; + + } + + *ptr2 = 0; + + if (ptr2 != &Formatted[0]) + { + // Incomplete line + + // Save to screen + + Line = Session->LastLine++; + free(Session->ScreenLines[Line]); + + Session->ScreenLines[Line] = _strdup(Formatted); + + if (Line == 99) + Session->LastLine = 0; + + Session->PartLine = realLen; + } + + // strcat(Session->ScreenBuffer, Formatted); + Session->Changed = TRUE; + + } while (count > 0); + } +} + + +VOID HTTPTimer() +{ + // Run every tick. Check for status change and data available + + struct HTTPConnectionInfo * Session = SessionList; // active term mode sessions + struct HTTPConnectionInfo * PreviousSession = NULL; + +// inf(); + + while (Session) + { + Session->KillTimer++; + + if (Session->Key[0] != 'T') + { + PreviousSession = Session; + Session = Session->Next; + continue; + } + + if (Session->KillTimer > 3000) // Around 5 mins + { + int i; + int Stream = Session->Stream; + + for (i = 0; i < 100; i++) + { + free(Session->ScreenLines[i]); + } + + SessionControl(Stream, 2, 0); + SessionState(Stream, &i, &i); + DeallocateStream(Stream); + + if (PreviousSession) + PreviousSession->Next = Session->Next; // Remove from chain + else + SessionList = Session->Next; + + free(Session); + + break; + } + + PollSession(Session); + + // if (Session->ResponseTimer == 0 && Session->Changed) + // Debugprintf("Data to send but no outstanding GET"); + + if (Session->ResponseTimer) + { + Session->ResponseTimer--; + + if (Session->ResponseTimer == 0 || Session->Changed) + { + SOCKET sock = Session->sock; + char _REPLYBUFFER[100000]; + int ReplyLen; + char Header[256]; + int HeaderLen; + int Last = Session->LastLine; + int n; + struct TNCINFO * TNC = Session->TNC; + struct TCPINFO * TCP = 0; + + if (TNC) + TCP = TNC->TCPInfo; + + if (TCP && TCP->WebTermCSS) + sprintf(_REPLYBUFFER, TermOutput, TCP->WebTermCSS); + else + sprintf(_REPLYBUFFER, TermOutput, ""); + + for (n = Last;;) + { + if ((strlen(Session->ScreenLines[n]) + strlen(_REPLYBUFFER)) < 99999) + strcat(_REPLYBUFFER, Session->ScreenLines[n]); + + if (n == 99) + n = -1; + + if (++n == Last) + break; + } + + ReplyLen = (int)strlen(_REPLYBUFFER); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", TermOutputTail); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, _REPLYBUFFER, ReplyLen); + + Session->ResponseTimer = Session->Changed = 0; + } + } + PreviousSession = Session; + Session = Session->Next; + } +} + +struct HTTPConnectionInfo * AllocateSession(SOCKET sock, char Mode) +{ + time_t KeyVal; + struct HTTPConnectionInfo * Session = zalloc(sizeof(struct HTTPConnectionInfo)); + int i; + + if (Session == NULL) + return NULL; + + if (Mode == 'T') + { + // Terminal + + for (i = 0; i < 20; i++) + Session->ScreenLines[i] = _strdup("Scroll to end
"); + + for (i = 20; i < 100; i++) + Session->ScreenLines[i] = _strdup("
\r\n"); + + Session->Stream = FindFreeStream(); + + if (Session->Stream == 0) + return NULL; + + SessionControl(Session->Stream, 1, 0); + } + + KeyVal = (int)sock * time(NULL); + + sprintf(Session->Key, "%c%012X", Mode, (int)KeyVal); + + if (SessionList) + Session->Next = SessionList; + + SessionList = Session; + + return Session; +} + +struct HTTPConnectionInfo * FindSession(char * Key) +{ + struct HTTPConnectionInfo * Session = SessionList; + + while (Session) + { + if (strcmp(Session->Key, Key) == 0) + return Session; + + Session = Session->Next; + } + + return NULL; +} + +void ProcessTermInput(SOCKET sock, char * MsgPtr, int MsgLen, char * Key) +{ + char _REPLYBUFFER[2048]; + int ReplyLen; + char Header[256]; + int HeaderLen; + int State; + struct HTTPConnectionInfo * Session = FindSession(Key); + int Stream; + int maxlen = 1000; + + + if (Session == NULL) + { + ReplyLen = sprintf(_REPLYBUFFER, "%s", LostSession); + } + else + { + char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + char * end = &MsgPtr[MsgLen]; + int Line = Session->LastLine++; + char * ptr1, * ptr2; + char c; + UCHAR hex; + + int msglen = end - input; + + struct TNCINFO * TNC = Session->TNC; + struct TCPINFO * TCP = 0; + + if (TNC) + TCP = TNC->TCPInfo; + + if (TCP && TCP->WebTermCSS) + maxlen -= strlen(TCP->WebTermCSS); + + if (MsgLen > maxlen) + { + Session->KillTimer = 99999; // close session + return; + } + + + if (TCP && TCP->WebTermCSS) + ReplyLen = sprintf(_REPLYBUFFER, InputLine, Key, TCP->WebTermCSS); + else + ReplyLen = sprintf(_REPLYBUFFER, InputLine, Key, ""); + + + Stream = Session->Stream; + + input += 10; + ptr1 = ptr2 = input; + + // Convert any %xx constructs + + while (ptr1 != end) + { + c = *(ptr1++); + if (c == '%') + { + c = *(ptr1++); + if(isdigit(c)) + hex = (c - '0') << 4; + else + hex = (tolower(c) - 'a' + 10) << 4; + + c = *(ptr1++); + if(isdigit(c)) + hex += (c - '0'); + else + hex += (tolower(c) - 'a' + 10); + + *(ptr2++) = hex; + } + else if (c == '+') + *(ptr2++) = 32; + else + *(ptr2++) = c; + } + + end = ptr2; + + *ptr2 = 0; + + strcat(input, "
\r\n"); + + free(Session->ScreenLines[Line]); + + Session->ScreenLines[Line] = _strdup(input); + + if (Line == 99) + Session->LastLine = 0; + + *end++ = 13; + *end = 0; + + SessionStateNoAck(Stream, &State); + + if (State == 0) + { + char AXCall[10]; + SessionControl(Stream, 1, 0); + if (BPQHOSTVECTOR[Session->Stream -1].HOSTSESSION == NULL) + { + //No L4 sessions free + + ReplyLen = sprintf(_REPLYBUFFER, "%s", NoSessions); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + return; + } + + ConvToAX25(Session->HTTPCall, AXCall); + ChangeSessionCallsign(Stream, AXCall); + if (Session->USER) + BPQHOSTVECTOR[Session->Stream -1].HOSTSESSION->Secure_Session = Session->USER->Secure; + else + Debugprintf("HTTP Term Session->USER is NULL"); + } + + SendMsg(Stream, input, (int)(end - input)); + Session->Changed = TRUE; + Session->KillTimer = 0; + } + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); +} + + +void ProcessTermClose(SOCKET sock, char * MsgPtr, int MsgLen, char * Key, int LOCAL) +{ + char _REPLYBUFFER[8192]; + int ReplyLen = sprintf(_REPLYBUFFER, InputLine, Key, ""); + char Header[256]; + int HeaderLen; + struct HTTPConnectionInfo * Session = FindSession(Key); + + if (Session) + { + Session->KillTimer = 99999; + } + + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n" + "\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); +} + +int ProcessTermSignon(struct TNCINFO * TNC, SOCKET sock, char * MsgPtr, int MsgLen, int LOCAL) +{ + char _REPLYBUFFER[8192]; + int ReplyLen; + char Header[256]; + int HeaderLen; + char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + char * user, * password, * Context, * Appl; + char NoApp[] = ""; + struct TCPINFO * TCP = TNC->TCPInfo; + + if (input) + { + int i; + struct UserRec * USER; + + UndoTransparency(input); + + if (strstr(input, "Cancel=Cancel")) + { + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + goto Sendit; + } + user = strtok_s(&input[9], "&", &Context); + password = strtok_s(NULL, "=", &Context); + password = strtok_s(NULL, "&", &Context); + + Appl = strtok_s(NULL, "=", &Context); + Appl = strtok_s(NULL, "&", &Context); + + if (Appl == 0) + Appl = NoApp; + + if (password == NULL) + { + ReplyLen = sprintf(_REPLYBUFFER, TermSignon, Mycall, Mycall, Appl); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", PassError); + goto Sendit; + } + + for (i = 0; i < TCP->NumberofUsers; i++) + { + USER = TCP->UserRecPtr[i]; + + if ((strcmp(password, USER->Password) == 0) && + ((_stricmp(user, USER->UserName) == 0 ) || (_stricmp(USER->UserName, "ANON") == 0))) + { + // ok + + struct HTTPConnectionInfo * Session = AllocateSession(sock, 'T'); + + if (Session) + { + char AXCall[10]; + ReplyLen = sprintf(_REPLYBUFFER, TermPage, Mycall, Mycall, Session->Key, Session->Key, Session->Key); + if (_stricmp(USER->UserName, "ANON") == 0) + strcpy(Session->HTTPCall, _strupr(user)); + else + strcpy(Session->HTTPCall, USER->Callsign); + ConvToAX25(Session->HTTPCall, AXCall); + ChangeSessionCallsign(Session->Stream, AXCall); + BPQHOSTVECTOR[Session->Stream -1].HOSTSESSION->Secure_Session = USER->Secure; + Session->USER = USER; + + if (USER->Appl[0]) + SendMsg(Session->Stream, USER->Appl, (int)strlen(USER->Appl)); + } + else + { + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", BusyError); + } + break; + } + } + + if (i == TCP->NumberofUsers) + { + // Not found + + ReplyLen = sprintf(_REPLYBUFFER, TermSignon, Mycall, Mycall, Appl); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", PassError); + } + + } + +Sendit: + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + return 1; +} + +char * LookupKey(char * Key) +{ + if (strcmp(Key, "##MY_CALLSIGN##") == 0) + { + char Mycall[10]; + memcpy(Mycall, &MYNODECALL, 10); + strlop(Mycall, ' '); + + return _strdup(Mycall); + } + return NULL; +} + + +int ProcessSpecialPage(char * Buffer, int FileSize) +{ + // replaces ##xxx### constructs with the requested data + + char * NewMessage = malloc(100000); + char * ptr1 = Buffer, * ptr2, * ptr3, * ptr4, * NewPtr = NewMessage; + int PrevLen; + int BytesLeft = FileSize; + int NewFileSize = FileSize; + char * StripPtr = ptr1; + + // strip comments blocks + + while (ptr4 = strstr(ptr1, ""); + if (ptr2) + { + PrevLen = (int)(ptr4 - ptr1); + memcpy(StripPtr, ptr1, PrevLen); + StripPtr += PrevLen; + ptr1 = ptr2 + 3; + BytesLeft = (int)(FileSize - (ptr1 - Buffer)); + } + } + + memcpy(StripPtr, ptr1, BytesLeft); + StripPtr += BytesLeft; + + BytesLeft = (int)(StripPtr - Buffer); + + FileSize = BytesLeft; + NewFileSize = FileSize; + ptr1 = Buffer; + ptr1[FileSize] = 0; + +loop: + ptr2 = strstr(ptr1, "##"); + + if (ptr2) + { + PrevLen = (int)(ptr2 - ptr1); // Bytes before special text + + ptr3 = strstr(ptr2+2, "##"); + + if (ptr3) + { + char Key[80] = ""; + int KeyLen; + char * NewText; + int NewTextLen; + + ptr3 += 2; + KeyLen = (int)(ptr3 - ptr2); + + if (KeyLen < 80) + memcpy(Key, ptr2, KeyLen); + + NewText = LookupKey(Key); + + if (NewText) + { + NewTextLen = (int)strlen(NewText); + NewFileSize = NewFileSize + NewTextLen - KeyLen; + // NewMessage = realloc(NewMessage, NewFileSize); + + memcpy(NewPtr, ptr1, PrevLen); + NewPtr += PrevLen; + memcpy(NewPtr, NewText, NewTextLen); + NewPtr += NewTextLen; + + free(NewText); + NewText = NULL; + } + else + { + // Key not found, so just leave + + memcpy(NewPtr, ptr1, PrevLen + KeyLen); + NewPtr += (PrevLen + KeyLen); + } + + ptr1 = ptr3; // Continue scan from here + BytesLeft = (int)(Buffer + FileSize - ptr3); + } + else // Unmatched ## + { + memcpy(NewPtr, ptr1, PrevLen + 2); + NewPtr += (PrevLen + 2); + ptr1 = ptr2 + 2; + } + goto loop; + } + + // Copy Rest + + memcpy(NewPtr, ptr1, BytesLeft); + NewMessage[NewFileSize] = 0; + + strcpy(Buffer, NewMessage); + free(NewMessage); + + return NewFileSize; +} + +int SendMessageFile(SOCKET sock, char * FN, BOOL OnlyifExists, int allowDeflate) +{ + int FileSize = 0, Sent, Loops = 0; + char * MsgBytes; + char MsgFile[512]; + FILE * hFile; + int ReadLen; + BOOL Special = FALSE; + int Len; + int HeaderLen; + char Header[256]; + char TimeString[64]; + char FileTimeString[64]; + struct stat STAT; + char * ptr; + char * Compressed = 0; + char Encoding[] = "Content-Encoding: deflate\r\n"; + char Type[64] = "Content-Type: text/html\r\n"; + +#ifdef WIN32 + + struct _EXCEPTION_POINTERS exinfo; + strcpy(EXCEPTMSG, "SendMessageFile"); + + __try { +#endif + + UndoTransparency(FN); + + if (strstr(FN, "..")) + { + FN[0] = '/'; + FN[1] = 0; + } + + if (strlen(FN) > 256) + { + FN[256] = 0; + Debugprintf("HTTP File Name too long %s", FN); + } + + if (strcmp(FN, "/") == 0) + if (APRSActive) + sprintf(MsgFile, "%s/HTML/index.html", BPQDirectory); + else + sprintf(MsgFile, "%s/HTML/indexnoaprs.html", BPQDirectory); + else + sprintf(MsgFile, "%s/HTML%s", BPQDirectory, FN); + + + // First see if file exists so we can override standard ones in code + + if (stat(MsgFile, &STAT) == 0 && (hFile = fopen(MsgFile, "rb"))) + { + FileSize = STAT.st_size; + + MsgBytes = zalloc(FileSize + 1); + + ReadLen = (int)fread(MsgBytes, 1, FileSize, hFile); + + fclose(hFile); + + // ft.QuadPart -= 116444736000000000; + // ft.QuadPart /= 10000000; + + // ctime = ft.LowPart; + + FormatTime3(FileTimeString, STAT.st_ctime); + } + else + { + // See if it is a hard coded file + + MsgBytes = GetStandardPage(&FN[1], &FileSize); + + if (MsgBytes) + { + if (FileSize == 0) + FileSize = strlen(MsgBytes); + + FormatTime3(FileTimeString, 0); + } + else + { + if (OnlyifExists) // Set if we dont want an error response if missing + return -1; + + Len = sprintf(Header, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n"); + send(sock, Header, Len, 0); + return 0; + } + } + + // if HTML file, look for ##...## substitutions + + if ((strcmp(FN, "/") == 0 || strstr(FN, "htm" ) || strstr(FN, "HTM")) && strstr(MsgBytes, "##" )) + { + FileSize = ProcessSpecialPage(MsgBytes, FileSize); + FormatTime3(FileTimeString, time(NULL)); + + } + + FormatTime3(TimeString, time(NULL)); + + ptr = FN; + + while (strchr(ptr, '.')) + { + ptr = strchr(ptr, '.'); + ++ptr; + } + + if (_stricmp(ptr, "js") == 0) + strcpy(Type, "Content-Type: text/javascript\r\n"); + + if (_stricmp(ptr, "css") == 0) + strcpy(Type, "Content-Type: text/css\r\n"); + + if (_stricmp(ptr, "pdf") == 0) + strcpy(Type, "Content-Type: application/pdf\r\n"); + + if (allowDeflate) + { + Compressed = Compressit(MsgBytes, FileSize, &FileSize); + } + else + { + Encoding[0] = 0; + Compressed = MsgBytes; + } + + if (_stricmp(ptr, "jpg") == 0 || _stricmp(ptr, "jpeg") == 0 || _stricmp(ptr, "png") == 0 || + _stricmp(ptr, "gif") == 0 || _stricmp(ptr, "bmp") == 0 || _stricmp(ptr, "ico") == 0) + strcpy(Type, "Content-Type: image\r\n"); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n" + "Date: %s\r\n" + "Last-Modified: %s\r\n" + "%s%s" + "\r\n", FileSize, TimeString, FileTimeString, Type, Encoding); + + send(sock, Header, HeaderLen, 0); + + Sent = send(sock, Compressed, FileSize, 0); + + while (Sent != FileSize && Loops++ < 3000) // 100 secs max + { + if (Sent > 0) // something sent + { +// Debugprintf("%d out of %d sent", Sent, FileSize); + FileSize -= Sent; + memmove(Compressed, &Compressed[Sent], FileSize); + } + + Sleep(30); + Sent = send(sock, Compressed, FileSize, 0); + } + +// Debugprintf("%d out of %d sent %d loops", Sent, FileSize, Loops); + + + free (MsgBytes); + if (allowDeflate) + free (Compressed); + +#ifdef WIN32 + } +#include "StdExcept.c" + Debugprintf("Sending FIle %s", FN); +} +#endif + +return 0; +} + +VOID sendandcheck(SOCKET sock, const char * Buffer, int Len) +{ + int Loops = 0; + int Sent = send(sock, Buffer, Len, 0); + char * Copy = NULL; + + while (Sent != Len && Loops++ < 300) // 10 secs max + { + // Debugprintf("%d out of %d sent %d Loops", Sent, Len, Loops); + + if (Copy == NULL) + { + Copy = malloc(Len); + memcpy(Copy, Buffer, Len); + } + + if (Sent > 0) // something sent + { + Len -= Sent; + memmove(Copy, &Copy[Sent], Len); + } + + Sleep(30); + Sent = send(sock, Copy, Len, 0); + } + + if (Copy) + free(Copy); + + return; +} + +int RefreshTermWindow(struct TCPINFO * TCP, struct HTTPConnectionInfo * Session, char * _REPLYBUFFER) +{ + char Msg[400] = ""; + int HeaderLen, ReplyLen; + char Header[256]; + + PollSession(Session); // See if anything received + + if (Session->Changed) + { + int Last = Session->LastLine; + int n; + + if (TCP && TCP->WebTermCSS) + sprintf(_REPLYBUFFER, TermOutput, TCP->WebTermCSS); + else + sprintf(_REPLYBUFFER, TermOutput, ""); + + for (n = Last;;) + { + strcat(_REPLYBUFFER, Session->ScreenLines[n]); + + if (n == 99) + n = -1; + + if (++n == Last) + break; + } + + Session->Changed = 0; + + ReplyLen = (int)strlen(_REPLYBUFFER); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", TermOutputTail); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen); + sendandcheck(Session->sock, Header, HeaderLen); + sendandcheck(Session->sock, _REPLYBUFFER, ReplyLen); + + return 1; + } + else + return 0; +} + +int SetupNodeMenu(char * Buff, int LOCAL) +{ + int Len = 0, i; + struct TNCINFO * TNC; + int top = 0, left = 0; + + char NodeMenuHeader[] = "%s's BPQ32 Web Server" + "" + + "" + "

BPQ32 Node %s

" + "

" + "" + "" + "" + "" + "" + "" + "%s%s%s%s%s%s"; + + char DriverBit[] = "" + ""; + + char APRSBit[] = ""; + + char MailBit[] = "" + ""; + + char ChatBit[] = ""; + char SigninBit[] = ""; + + char NodeTail[] = + "" + "
RoutesNodesPortsLinksUsersStatsTerminalDriver WindowsStream StatusAPRS PagesMail MgmtWebMailChat MgmtSYSOP SigninEdit Config" + "
"; + + + Len = sprintf(Buff, NodeMenuHeader, Mycall); + + for (i=1; i <= MAXBPQPORTS; i++) + { + TNC = TNCInfo[i]; + if (TNC == NULL) + continue; + + if (TNC->WebWindowProc) + { + Len += sprintf(&Buff[Len], NodeMenuLine, i, TNC->WebWinX, TNC->WebWinY, top, left); + top += 22; + left += 22; + } + } + + Len += sprintf(&Buff[Len], NodeMenuRest, Mycall, + DriverBit, + (APRSWeb)?APRSBit:"", + (IncludesMail)?MailBit:"", (IncludesChat)?ChatBit:"", (LOCAL)?"":SigninBit, NodeTail); + + return Len; +} + +VOID SaveConfigFile(SOCKET sock , char * MsgPtr, char * Rest, int LOCAL) +{ + int ReplyLen = 0; + char * ptr, * ptr1, * ptr2, *input; + char c; + int MsgLen, WriteLen = 0; + char inputname[250]="bpq32.cfg"; + FILE *fp1; + char Header[256]; + int HeaderLen; + char Reply[4096]; + char Mess[256]; + char Backup1[MAX_PATH]; + char Backup2[MAX_PATH]; + struct stat STAT; + + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input) + { + if (strstr(input, "Cancel=Cancel")) + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + // ReplyLen = sprintf(Reply, "%s", ""); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, Reply, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + return; + } + + ptr = strstr(input, "&Save="); + + if (ptr) + { + *ptr = 0; + + // Undo any % transparency + + ptr1 = ptr2 = input + 8; + + c = *(ptr1++); + + while (c) + { + if (c == '%') + { + int n; + int m = *(ptr1++) - '0'; + if (m > 9) m = m - 7; + n = *(ptr1++) - '0'; + if (n > 9) n = n - 7; + + c = m * 16 + n; + } + else if (c == '+') + c = ' '; + +#ifndef WIN32 + if (c != 13) // Strip CR if Linux +#endif + *(ptr2++) = c; + + c = *(ptr1++); + + } + + *(ptr2++) = 0; + + MsgLen = (int)strlen(input + 8); + + if (ConfigDirectory[0] == 0) + { + strcpy(inputname, "bpq32.cfg"); + } + else + { + strcpy(inputname,ConfigDirectory); + strcat(inputname,"/"); + strcat(inputname, "bpq32.cfg"); + } + + // Make a backup of the config + + // Keep 4 Generations + + strcpy(Backup2, inputname); + strcat(Backup2, ".bak.3"); + + strcpy(Backup1, inputname); + strcat(Backup1, ".bak.2"); + + DeleteFile(Backup2); // Remove old .bak.3 + MoveFile(Backup1, Backup2); // Move .bak.2 to .bak.3 + + strcpy(Backup2, inputname); + strcat(Backup2, ".bak.1"); + + MoveFile(Backup2, Backup1); // Move .bak.1 to .bak.2 + + strcpy(Backup1, inputname); + strcat(Backup1, ".bak"); + + MoveFile(Backup1, Backup2); // Move .bak to .bak.1 + + CopyFile(inputname, Backup1, FALSE); // Copy to .bak + + // Get length to compare with new length + + stat(inputname, &STAT); + + fp1 = fopen(inputname, "wb"); + + if (fp1) + { + WriteLen = (int)fwrite(input + 8, 1, MsgLen, fp1); + fclose(fp1); + } + + if (WriteLen != MsgLen) + sprintf_s(Mess, sizeof(Mess), "Failed to write Config File"); + else + sprintf_s(Mess, sizeof(Mess), "Configuration Saved, Orig Length %d New Length %d", + STAT.st_size, MsgLen); + } + + ReplyLen = sprintf(Reply, "", Mess); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, Reply, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + } + return; +} + +// Compress using deflate. Caller must free output buffer after use + +unsigned char * Compressit(unsigned char * In, int Len, int * OutLen) +{ + z_stream defstream; + int maxSize; + unsigned char * Out; + + defstream.zalloc = Z_NULL; + defstream.zfree = Z_NULL; + defstream.opaque = Z_NULL; + + defstream.avail_in = Len; // size of input + defstream.next_in = (Bytef *)In; // input char array + + deflateInit(&defstream, Z_BEST_COMPRESSION); + maxSize = deflateBound(&defstream, Len); + + Out = malloc(maxSize); + + defstream.avail_out = maxSize; // size of output + defstream.next_out = (Bytef *)Out; // output char array + + deflate(&defstream, Z_FINISH); + deflateEnd(&defstream); + + *OutLen = defstream.total_out; + + return Out; +} + + +int InnerProcessHTTPMessage(struct ConnectionInfo * conn) +{ + struct TCPINFO * TCP = conn->TNC->TCPInfo; + SOCKET sock = conn->socket; + char * MsgPtr = conn->InputBuffer; + int MsgLen = conn->InputLen; + int InputLen = 0; + int OutputLen = 0; + int Bufferlen; + struct HTTPConnectionInfo CI; + struct HTTPConnectionInfo * sockptr = &CI; + struct HTTPConnectionInfo * Session = NULL; + + char URL[100000]; + char * ptr; + char * encPtr = 0; + int allowDeflate = 0; + char * Compressed = 0; + char * HostPtr = 0; + + char * Context, * Method, * NodeURL = 0, * Key; + char _REPLYBUFFER[250000]; + char Reply[250000]; + + int ReplyLen = 0; + char Header[256]; + int HeaderLen; + char TimeString[64]; + BOOL LOCAL = FALSE; + BOOL COOKIE = FALSE; + int Len; + char * WebSock = 0; + + char PortsHddr[] = "

Ports

" + ""; + +// char PortLine[] = ""; + + char PortLineWithBeacon[] = "" + "\r\n"; + + char SessionPortLine[] = "" + "\r\n"; + + char PortLineWithDriver[] = "" + "\r\n"; + + + char PortLineWithBeaconAndDriver[] = "" + "" + "\r\n"; + + char RigControlLine[] = "" + "\r\n"; + + + char Encoding[] = "Content-Encoding: deflate\r\n"; + +#ifdef WIN32xx + + struct _EXCEPTION_POINTERS exinfo; + strcpy(EXCEPTMSG, "ProcessHTTPMessage"); + + __try { +#endif + + Len = (int)strlen(MsgPtr); + if (Len > 100000) + return 0; + + strcpy(URL, MsgPtr); + + HostPtr = strstr(MsgPtr, "Host: "); + + WebSock = strstr(MsgPtr, "Upgrade: websocket"); + + if (HostPtr) + { + uint32_t Host; + char Hostname[32]= ""; + struct LOCALNET * LocalNet = conn->TNC->TCPInfo->LocalNets; + + HostPtr += 6; + memcpy(Hostname, HostPtr, 31); + strlop(Hostname, ':'); + Host = inet_addr(Hostname); + + if (strcmp(Hostname, "127.0.0.1") == 0) + LOCAL = TRUE; + else + { + if (conn->sin.sin_family != AF_INET6) + { + while(LocalNet) + { + uint32_t MaskedHost = conn->sin.sin_addr.s_addr & LocalNet->Mask; + if (MaskedHost == LocalNet->Network) + { + LOCAL = 1; + break; + } + LocalNet = LocalNet->Next; + } + } + } + } + + encPtr = stristr(MsgPtr, "Accept-Encoding:"); + + if (encPtr && stristr(encPtr, "deflate")) + allowDeflate = 1; + else + Encoding[0] = 0; + + ptr = strstr(MsgPtr, "BPQSessionCookie=N"); + + if (ptr) + { + COOKIE = TRUE; + Key = ptr + 17; + ptr = strchr(Key, ','); + if (ptr) + { + *ptr = 0; + Session = FindSession(Key); + *ptr = ','; + } + else + { + ptr = strchr(Key, 13); + if (ptr) + { + *ptr = 0; + Session = FindSession(Key); + *ptr = 13; + } + } + } + + if (WebSock) + { + // Websock connection request - Reply and remember state. + + char KeyMsg[128]; + char Webx[] = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; // Fixed UID + char Hash[64] = ""; + char * Hash64; // base 64 version + char * ptr; + + //Sec-WebSocket-Key: l622yZS3n+zI+hR6SVWkPw== + + char ReplyMsg[] = + "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: %s\r\n" +// "Sec-WebSocket-Protocol: chat\r\n" + "\r\n"; + + ptr = strstr(MsgPtr, "Sec-WebSocket-Key:"); + + if (ptr) + { + ptr += 18; + while (*ptr == ' ') + ptr++; + + memcpy(KeyMsg, ptr, 40); + strlop(KeyMsg, 13); + strlop(KeyMsg, ' '); + strcat(KeyMsg, Webx); + + SHA1PasswordHash(KeyMsg, Hash); + Hash64 = byte_base64_encode(Hash, 20); + + conn->WebSocks = 1; + strlop(&URL[4], ' '); + strcpy(conn->WebURL, &URL[4]); + + ReplyLen = sprintf(Reply, ReplyMsg, Hash64); + + free(Hash64); + goto Returnit; + + } + } + + + ptr = strstr(URL, " HTTP"); + + if (ptr) + *ptr = 0; + + Method = strtok_s(URL, " ", &Context); + + memcpy(Mycall, &MYNODECALL, 10); + strlop(Mycall, ' '); + + + // Look for API messages + + if (_memicmp(Context, "/api/", 5) == 0 || _stricmp(Context, "/api") == 0) + { + char * Compressed; + + // if for mail api process signon here and rearrange url from + // api/v1/mail to mail/api/v1 so it goes to mail handler later + + if (_memicmp(Context, "/api/v1/mail/", 13) == 0) + { + memcpy(MsgPtr, "GET /mail/api/v1/", 17); + + if (memcmp(&Context[13], "login", 5) == 0) + { + ReplyLen = ProcessMailAPISignon(TCP, MsgPtr, "M", Reply, &Session, FALSE, LOCAL); + memcpy(MsgPtr, "GET /mail/api/v1/", 17); + + if (ReplyLen) // Error message + goto Returnit; + } + + memcpy(Context, "/mail/api/v1/", 13); + goto doHeader; + } + else + { + ReplyLen = APIProcessHTTPMessage(_REPLYBUFFER, Method, Context, MsgPtr, LOCAL, COOKIE); + + if (memcmp(_REPLYBUFFER, "HTTP", 4) == 0) + { + // Full Message - just send it + + sendandcheck(sock, _REPLYBUFFER, ReplyLen); + + return 0; + } + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = _REPLYBUFFER; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\n" + "Content-Length: %d\r\n" + "Content-Type: application/json\r\n" + "Connection: close\r\n" + "Access-Control-Allow-Origin: *\r\n" + "%s\r\n", ReplyLen, Encoding); + + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + } + } + + if (_memicmp(Context, "/rhp/", 5) == 0 || _stricmp(Context, "/rhp") == 0) + { + { + ReplyLen = RHPProcessHTTPMessage(conn, _REPLYBUFFER, Method, Context, MsgPtr, LOCAL, COOKIE); + + if (memcmp(_REPLYBUFFER, "HTTP", 4) == 0) + { + // Full Message - just send it + + sendandcheck(sock, _REPLYBUFFER, ReplyLen); + + return 0; + } + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = _REPLYBUFFER; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\n" + "Content-Length: %d\r\n" + "Content-Type: application/json\r\n" + "Connection: close\r\n" + "Access-Control-Allow-Origin: *\r\n" + "%s\r\n", ReplyLen, Encoding); + + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + } + } + + + // APRS process internally + + if (_memicmp(Context, "/APRS/", 6) == 0 || _stricmp(Context, "/APRS") == 0) + { + APRSProcessHTTPMessage(sock, MsgPtr, LOCAL, COOKIE); + return 0; + } + + + if (_stricmp(Context, "/Node/Signon?Node") == 0) + { + char * IContext; + + NodeURL = strtok_s(Context, "?", &IContext); + Key = strtok_s(NULL, "?", &IContext); + + ProcessNodeSignon(sock, TCP, MsgPtr, Key, Reply, &Session, LOCAL); + return 0; + + } + + // If for Mail or Chat, check for a session, and send login screen if necessary + + // Moved here to simplify operation with both internal and external clients + + if (_memicmp(Context, "/Mail/", 6) == 0) + { + int RLen = 0; + char Appl; + char * input; + char * IContext; + + NodeURL = strtok_s(Context, "?", &IContext); + Key = strtok_s(NULL, "?", &IContext); + + if (_stricmp(NodeURL, "/Mail/Signon") == 0) + { + ReplyLen = ProcessMailSignon(TCP, MsgPtr, Key, Reply, &Session, FALSE, LOCAL); + + if (ReplyLen) + { + goto Returnit; + } + +#ifdef LINBPQ + strcpy(Context, "/Mail/Header"); +#else + strcpy(MsgPtr, "POST /Mail/Header"); +#endif + goto doHeader; + } + + if (_stricmp(NodeURL, "/Mail/Lost") == 0) + { + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input && strstr(input, "Cancel=Exit")) + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + RLen = ReplyLen; + goto Returnit; + } + if (Key) + Appl = Key[0]; + + Key = 0; + } + + if (Key == 0 || Key[0] == 0) + { + // No Session + + // if not local send a signon screen, else create a user session + + if (LOCAL || COOKIE) + { + Session = AllocateSession(sock, 'M'); + + if (Session) + { + strcpy(Context, "/Mail/Header"); + goto doHeader; + } + else + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); + } + RLen = ReplyLen; + + goto Returnit; + + } + + ReplyLen = sprintf(Reply, MailSignon, Mycall, Mycall); + + RLen = ReplyLen; + goto Returnit; + } + + Session = FindSession(Key); + + + if (Session == NULL && _memicmp(Context, "/Mail/API/", 10) != 0) + { + ReplyLen = sprintf(Reply, MailLostSession, Key); + RLen = ReplyLen; + goto Returnit; + } + } + + if (_memicmp(Context, "/Chat/", 6) == 0) + { + int RLen = 0; + char Appl; + char * input; + char * IContext; + + + HostPtr = strstr(MsgPtr, "Host: "); + + if (HostPtr) + { + uint32_t Host; + char Hostname[32]= ""; + struct LOCALNET * LocalNet = conn->TNC->TCPInfo->LocalNets; + + HostPtr += 6; + memcpy(Hostname, HostPtr, 31); + strlop(Hostname, ':'); + Host = inet_addr(Hostname); + + if (strcmp(Hostname, "127.0.0.1") == 0) + LOCAL = TRUE; + else while(LocalNet) + { + uint32_t MaskedHost = Host & LocalNet->Mask; + if (MaskedHost == LocalNet->Network) + { + char * rest; + LOCAL = 1; + rest = strchr(HostPtr, 13); + if (rest) + { + memmove(HostPtr + 9, rest, strlen(rest) + 1); + memcpy(HostPtr, "127.0.0.1", 9); + break; + } + } + LocalNet = LocalNet->Next; + } + } + + NodeURL = strtok_s(Context, "?", &IContext); + Key = strtok_s(NULL, "?", &IContext); + + if (_stricmp(NodeURL, "/Chat/Signon") == 0) + { + ReplyLen = ProcessChatSignon(TCP, MsgPtr, Key, Reply, &Session, LOCAL); + + if (ReplyLen) + { + goto Returnit; + } + +#ifdef LINBPQ + strcpy(Context, "/Chat/Header"); +#else + strcpy(MsgPtr, "POST /Chat/Header"); +#endif + goto doHeader; + } + + if (_stricmp(NodeURL, "/Chat/Lost") == 0) + { + input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + + if (input && strstr(input, "Cancel=Exit")) + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + RLen = ReplyLen; + goto Returnit; + } + if (Key) + Appl = Key[0]; + + Key = 0; + } + + if (Key == 0 || Key[0] == 0) + { + // No Session + + // if not local send a signon screen, else create a user session + + if (LOCAL || COOKIE) + { + Session = AllocateSession(sock, 'C'); + + if (Session) + { + strcpy(Context, "/Chat/Header"); + goto doHeader; + } + else + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); + } + RLen = ReplyLen; + + goto Returnit; + + } + + ReplyLen = sprintf(Reply, ChatSignon, Mycall, Mycall); + + RLen = ReplyLen; + goto Returnit; + } + + Session = FindSession(Key); + + if (Session == NULL) + { + int Sent, Loops = 0; + ReplyLen = sprintf(Reply, MailLostSession, Key); + RLen = ReplyLen; +Returnit: + if (memcmp(Reply, "HTTP", 4) == 0) + { + // Full Header provided by appl - just send it + + // Send may block + + Sent = send(sock, Reply, ReplyLen, 0); + + while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max + { + // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); + + if (Sent > 0) // something sent + { + InputLen -= Sent; + memmove(Reply, &Reply[Sent], ReplyLen); + } + + Sleep(30); + Sent = send(sock, Reply, ReplyLen, 0); + } + + return 0; + } + + if (NodeURL && _memicmp(NodeURL, "/mail/api/", 10) != 0) + { + // Add tail + + strcpy(&Reply[ReplyLen], Tail); + ReplyLen += strlen(Tail); + } + + // compress if allowed + + if (allowDeflate) + Compressed = Compressit(Reply, ReplyLen, &ReplyLen); + else + Compressed = Reply; + + if (NodeURL && _memicmp(NodeURL, "/mail/api/", 10) == 0) + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: application/json\r\nConnection: close\r\n%s\r\n", ReplyLen, Encoding); + else + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n%s\r\n", ReplyLen, Encoding); + + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + } + } + +doHeader: + +#ifdef LINBPQ + + if ((_memicmp(Context, "/MAIL/", 6) == 0) || (_memicmp(Context, "/WebMail", 8) == 0)) + { + char _REPLYBUFFER[250000]; + struct HTTPConnectionInfo Dummy = {0}; + int Sent, Loops = 0; + char token[16] = ""; + + // look for auth header + + const char * auth_header = "Authorization: Bearer "; + char * token_begin = strstr(MsgPtr, auth_header); + int Flags = 0, n; + + char * Tok; + char * param; + + if (token_begin) + { + // Using Auth Header + + // Extract the token from the request (assuming it's present in the request headers) + + token_begin += strlen(auth_header); // Move to the beginning of the token + strncpy(token, token_begin, 13); + token[13] = '\0'; // Null-terminate the token + } + + ReplyLen = 0; + + if (Session == 0) + Session = &Dummy; + + if (LOCAL) + Session->TNC = (void *)1; // TNC only used for Web Terminal Sessions + else + Session->TNC = (void *)0; + + ProcessMailHTTPMessage(Session, Method, Context, MsgPtr, _REPLYBUFFER, &ReplyLen, MsgLen, token); + + if (Context && _memicmp(Context, "/mail/api/", 10) == 0) + { + if (memcmp(_REPLYBUFFER, "HTTP", 4) == 0) + { + // Full Header provided by appl - just send it + + // Send may block + + Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); + + while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max + { + // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); + + if (Sent > 0) // something sent + { + InputLen -= Sent; + memmove(_REPLYBUFFER, &_REPLYBUFFER[Sent], ReplyLen); + } + + Sleep(30); + Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); + } + return 0; + } + + // compress if allowed + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = _REPLYBUFFER; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: application/json\r\nConnection: close\r\n%s\r\n", ReplyLen, Encoding); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + } + + if (memcmp(_REPLYBUFFER, "HTTP", 4) == 0) + { + // Full Header provided by appl - just send it + + // Send may block + + Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); + + while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max + { + // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); + + if (Sent > 0) // something sent + { + InputLen -= Sent; + memmove(_REPLYBUFFER, &_REPLYBUFFER[Sent], ReplyLen); + } + + Sleep(30); + Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); + } + return 0; + } + + if (Context && _memicmp(Context, "/mail/api/", 10) != 0) + { + + // Add tail + + strcpy(&_REPLYBUFFER[ReplyLen], Tail); + ReplyLen += strlen(Tail); + + } + + // compress if allowed + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = Reply; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n%s\r\n", ReplyLen, Encoding); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + + +/* + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + + // Send may block + + Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); + + if (Sent == -1) + return 0; + + while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max + { + // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); + + if (Sent > 0) // something sent + { + InputLen -= Sent; + memmove(_REPLYBUFFER, &_REPLYBUFFER[Sent], ReplyLen); + } + + Sleep(30); + Sent = send(sock, _REPLYBUFFER, ReplyLen, 0); + } + + send(sock, Tail, (int)strlen(Tail), 0); + return 0; +*/ + } + + if (_memicmp(Context, "/CHAT/", 6) == 0) + { + char _REPLYBUFFER[100000]; + + ReplyLen = 0; + + ProcessChatHTTPMessage(Session, Method, Context, MsgPtr, _REPLYBUFFER, &ReplyLen); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + return 0; + + } + + + /* + Sent = send(sock, _REPLYBUFFER, InputLen, 0); + + while (Sent != InputLen && Loops++ < 3000) // 100 secs max + { + // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); + + if (Sent > 0) // something sent + { + InputLen -= Sent; + memmove(_REPLYBUFFER, &_REPLYBUFFER[Sent], InputLen); + } + + Sleep(30); + Sent = send(sock, _REPLYBUFFER, InputLen, 0); + } + return 0; + } + */ +#else + + // Pass to MailChat if active + + NodeURL = Context; + + if ((_memicmp(Context, "/MAIL/", 6) == 0) || (_memicmp(Context, "/WebMail", 8) == 0)) + { + // If for Mail, Pass to Mail Server via Named Pipe + + HANDLE hPipe; + + hPipe = CreateFile(MAILPipeFileName, GENERIC_READ | GENERIC_WRITE, + 0, // exclusive access + NULL, // no security attrs + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if (hPipe == (HANDLE)-1) + { + InputLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 28\r\n\r\nMail Data is not available\r\n"); + send(sock, Reply, InputLen, 0); + } + else + { + // int Sent; + int Loops = 0; + struct HTTPConnectionInfo Dummy = {0}; + + if (Session == 0) + Session = &Dummy; + + Session->TNC = LOCAL; // TNC is only used on Web Terminal Sessions so can reuse as LOCAL flag + + WriteFile(hPipe, Session, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); + WriteFile(hPipe, MsgPtr, MsgLen, &InputLen, NULL); + + + ReadFile(hPipe, Session, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); + ReadFile(hPipe, Reply, 250000, &ReplyLen, NULL); + if (ReplyLen <= 0) + { + InputLen = GetLastError(); + } + + CloseHandle(hPipe); + goto Returnit; + } + return 0; + } + + if (_memicmp(Context, "/CHAT/", 6) == 0) + { + HANDLE hPipe; + + hPipe = CreateFile(CHATPipeFileName, GENERIC_READ | GENERIC_WRITE, + 0, // exclusive access + NULL, // no security attrs + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if (hPipe == (HANDLE)-1) + { + InputLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 28\r\n\r\nChat Data is not available\r\n"); + send(sock, Reply, InputLen, 0); + } + else + { + // int Sent; + int Loops = 0; + + WriteFile(hPipe, Session, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); + WriteFile(hPipe, MsgPtr, MsgLen, &InputLen, NULL); + + + ReadFile(hPipe, Session, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); + ReadFile(hPipe, Reply, 100000, &ReplyLen, NULL); + if (ReplyLen <= 0) + { + InputLen = GetLastError(); + } + + CloseHandle(hPipe); + goto Returnit; + } + return 0; + } + +#endif + + NodeURL = strtok_s(NULL, "?", &Context); + + if (NodeURL == NULL) + return 0; + + if (strcmp(Method, "POST") == 0) + { + if (_stricmp(NodeURL, "/Node/freqOffset") == 0) + { + char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + int port = atoi(Context); + + if (input == 0) + return 1; + + input += 4; + + if (port > 0 && port <= MaxBPQPortNo) + { + struct TNCINFO * TNC = TNCInfo[port]; + char value[6]; + + if (TNC == 0) + return 1; + + TNC->TXOffset = atoi(input); +#ifdef WIN32 + sprintf(value, "%d", TNC->TXOffset); + MySetWindowText(TNC->xIDC_TXTUNEVAL, value); + SendMessage(TNC->xIDC_TXTUNE, TBM_SETPOS, (WPARAM) TRUE, (LPARAM) TNC->TXOffset); // min. & max. positions + +#endif + } + return 1; + } + + if (_stricmp(NodeURL, "/Node/PortAction") == 0) + { + char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + int port = atoi(Context); + + if (input == 0) + return 1; + + input += 4; + + if (port > 0 && port <= MaxBPQPortNo) + { + struct TNCINFO * TNC = TNCInfo[port]; + + if (TNC == 0) + return 1; + + if (LOCAL == FALSE && COOKIE == FALSE) + return 1; + + if (strcmp(input, "Abort") == 0) + { + if (TNC->ForcedCloseProc) + TNC->ForcedCloseProc(TNC, 0); + } + else if (strcmp(input, "Kill") == 0) + { + TNC->DontRestart = TRUE; + KillTNC(TNC); + } + else if (strcmp(input, "KillRestart") == 0) + { + TNC->DontRestart = FALSE; + KillTNC(TNC); + RestartTNC(TNC); + + } + } + return 1; + } + + if (_stricmp(NodeURL, "/TermInput") == 0) + { + ProcessTermInput(sock, MsgPtr, MsgLen, Context); + return 0; + } + + if (_stricmp(NodeURL, "/Node/TermSignon") == 0) + { + ProcessTermSignon(conn->TNC, sock, MsgPtr, MsgLen, LOCAL); + } + + if (_stricmp(NodeURL, "/Node/Signon") == 0) + { + ProcessNodeSignon(sock, TCP, MsgPtr, Key, Reply, &Session, LOCAL); + return 0; + } + + if (_stricmp(NodeURL, "/Node/TermClose") == 0) + { + ProcessTermClose(sock, MsgPtr, MsgLen, Context, LOCAL); + return 0; + } + + if (_stricmp(NodeURL, "/Node/BeaconAction") == 0) + { + char Header[256]; + int HeaderLen; + char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + int Port; + char Param[100]; +#ifndef LINBPQ + int retCode, disp; + char Key[80]; + HKEY hKey; +#endif + struct PORTCONTROL * PORT; + int Slot = 0; + + + if (LOCAL == FALSE && COOKIE == FALSE) + { + // Send Not Authorized + + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
Not authorized - please sign in"); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + return 1; + } + + if (strstr(input, "Cancel=Cancel")) + { + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + return 1; + } + + GetParam(input, "Port=", &Param[0]); + Port = atoi(&Param[0]); + PORT = GetPortTableEntryFromPortNum(Port); // Need slot not number + if (PORT) + Slot = PORT->PortSlot; + + GetParam(input, "Every=", &Param[0]); + Interval[Slot] = atoi(&Param[0]); + + GetParam(input, "Dest=", &Param[0]); + _strupr(Param); + strcpy(UIUIDEST[Slot], &Param[0]); + + GetParam(input, "Path=", &Param[0]); + _strupr(Param); + if (UIUIDigi[Slot]) + free(UIUIDigi[Slot]); + UIUIDigi[Slot] = _strdup(&Param[0]); + + GetParam(input, "File=", &Param[0]); + strcpy(FN[Slot], &Param[0]); + GetParam(input, "Text=", &Param[0]); + strcpy(Message[Slot], &Param[0]); + + MinCounter[Slot] = Interval[Slot]; + + SendFromFile[Slot] = 0; + + if (FN[Slot][0]) + SendFromFile[Slot] = 1; + + SetupUI(Slot); + +#ifdef LINBPQ + SaveUIConfig(); +#else + SaveUIConfig(); + + wsprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\UIUtil\\UIPort%d", Port); + + retCode = RegCreateKeyEx(REGTREE, + Key, 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp); + + if (retCode == ERROR_SUCCESS) + { + retCode = RegSetValueEx(hKey, "UIDEST", 0, REG_SZ,(BYTE *)&UIUIDEST[Port][0], strlen(&UIUIDEST[Port][0])); + retCode = RegSetValueEx(hKey, "FileName", 0, REG_SZ,(BYTE *)&FN[Port][0], strlen(&FN[Port][0])); + retCode = RegSetValueEx(hKey, "Message", 0, REG_SZ,(BYTE *)&Message[Port][0], strlen(&Message[Port][0])); + retCode = RegSetValueEx(hKey, "Interval", 0, REG_DWORD,(BYTE *)&Interval[Port], 4); + retCode = RegSetValueEx(hKey, "SendFromFile", 0, REG_DWORD,(BYTE *)&SendFromFile[Port], 4); + retCode = RegSetValueEx(hKey, "Digis",0, REG_SZ, UIUIDigi[Port], strlen(UIUIDigi[Port])); + + RegCloseKey(hKey); + } +#endif + if (strstr(input, "Test=Test")) + SendUIBeacon(Slot); + + + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], Beacons, Port, + Interval[Slot], &UIUIDEST[Slot][0], &UIUIDigi[Slot][0], &FN[Slot][0], &Message[Slot][0], Port); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + return 1; + } + + if (_stricmp(NodeURL, "/Node/CfgSave") == 0) + { + // Save Config File + + SaveConfigFile(sock, MsgPtr, Key, LOCAL); + return 0; + } + + if (_stricmp(NodeURL, "/Node/LogAction") == 0) + { + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + return 1; + } + + + if (_stricmp(NodeURL, "/Node/ARDOPAbort") == 0) + { + int port = atoi(Context); + + if (port > 0 && port <= MaxBPQPortNo) + { + struct TNCINFO * TNC = TNCInfo[port]; + + if (TNC && TNC->ForcedCloseProc) + TNC->ForcedCloseProc(TNC, 0); + + + if (TNC && TNC->WebWindowProc) + ReplyLen = TNC->WebWindowProc(TNC, _REPLYBUFFER, LOCAL); + + + ReplyLen = sprintf(Reply, "", "Ok"); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, Reply, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + // goto SendResp; + + // HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + strlen(Tail)); + // send(sock, Header, HeaderLen, 0); + // send(sock, _REPLYBUFFER, ReplyLen, 0); + // send(sock, Tail, strlen(Tail), 0); + + return 1; + } + + } + + send(sock, _REPLYBUFFER, InputLen, 0); + return 0; + } + + if (_stricmp(NodeURL, "/") == 0 || _stricmp(NodeURL, "/Index.html") == 0) + { + // Send if present, else use default + + Bufferlen = SendMessageFile(sock, NodeURL, TRUE, allowDeflate); // return -1 if not found + + if (Bufferlen != -1) + return 0; // We've sent it + else + { + if (APRSApplConnected) + ReplyLen = sprintf(_REPLYBUFFER, Index, Mycall, Mycall); + else + ReplyLen = sprintf(_REPLYBUFFER, IndexNoAPRS, Mycall, Mycall); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + return 0; + } + } + + else if (_stricmp(NodeURL, "/NodeMenu.html") == 0 || _stricmp(NodeURL, "/Node/NodeMenu.html") == 0) + { + // Send if present, else use default + + char Menu[] = "/NodeMenu.html"; + + Bufferlen = SendMessageFile(sock, Menu, TRUE, allowDeflate); // return -1 if not found + + if (Bufferlen != -1) + return 0; // We've sent it + } + + else if (_memicmp(NodeURL, "/aisdata.txt", 12) == 0) + { + char * Compressed; + ReplyLen = GetAISPageInfo(_REPLYBUFFER, 1, 1); + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = _REPLYBUFFER; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: Text\r\n%s\r\n", ReplyLen, Encoding); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + } + + else if (_memicmp(NodeURL, "/aprsdata.txt", 13) == 0) + { + char * Compressed; + char * ptr; + double N, S, W, E; + int aprs = 1, ais = 1, adsb = 1; + + ptr = &NodeURL[14]; + + N = atof(ptr); + ptr = strlop(ptr, '|'); + S = atof(ptr); + ptr = strlop(ptr, '|'); + W = atof(ptr); + ptr = strlop(ptr, '|'); + E = atof(ptr); + ptr = strlop(ptr, '|'); + if (ptr) + { + aprs = atoi(ptr); + ptr = strlop(ptr, '|'); + ais = atoi(ptr); + ptr = strlop(ptr, '|'); + adsb = atoi(ptr); + } + ReplyLen = GetAPRSPageInfo(_REPLYBUFFER, N, S, W, E, aprs, ais, adsb); + + if (ReplyLen < 240000) + ReplyLen += GetAISPageInfo(&_REPLYBUFFER[ReplyLen], ais, adsb); + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = _REPLYBUFFER; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: Text\r\n%s\r\n", ReplyLen, Encoding); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + } + + else if (_memicmp(NodeURL, "/portstats.txt", 15) == 0) + { + char * Compressed; + char * ptr; + int port; + struct PORTCONTROL * PORT; + + ptr = &NodeURL[15]; + + port = atoi(ptr); + + PORT = GetPortTableEntryFromPortNum(port); + + ReplyLen = 0; + + if (PORT && PORT->TX) + { + // We send the last 24 hours worth of data. Buffer is cyclic so oldest byte is at StatsPointer + + int first = PORT->StatsPointer; + int firstlen = 1440 - first; + + memcpy(&_REPLYBUFFER[0], &PORT->TX[first], firstlen); + memcpy(&_REPLYBUFFER[firstlen], PORT->TX, first); + + memcpy(&_REPLYBUFFER[1440], &PORT->BUSY[first], firstlen); + memcpy(&_REPLYBUFFER[1440 + firstlen], PORT->BUSY, first); + + ReplyLen = 2880; + } + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = _REPLYBUFFER; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Length: %d\r\nContent-Type: Text\r\n%s\r\n", ReplyLen, Encoding); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + } + + + else if (_memicmp(NodeURL, "/Icon", 5) == 0 && _memicmp(&NodeURL[10], ".png", 4) == 0) + { + // APRS internal Icon + + char * Compressed; + + ReplyLen = GetAPRSIcon(_REPLYBUFFER, NodeURL); + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = _REPLYBUFFER; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: Text\r\n%s\r\n", ReplyLen, Encoding); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + + } + + else if (_memicmp(NodeURL, "/NODE/", 6)) + { + // Not Node, See if a local file + + Bufferlen = SendMessageFile(sock, NodeURL, FALSE, allowDeflate); // Send error if not found + return 0; + } + + // Node URL + + { + + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + + if (_stricmp(NodeURL, "/Node/webproc.css") == 0) + { + char WebprocCSS[] = + ".dropbtn {position: relative; border: 1px solid black;padding:1px;}\r\n" + ".dropdown {position: relative; display: inline-block;}\r\n" + ".dropdown-content {display: none; position: absolute;background-color: #ccc; " + "min-width: 160px; box-shadow: 0px 8px 16px 0px rgba(0,0,00.2); z-index: 1;}\r\n" + ".dropdown-content a {color: black; padding: 1px 1px;text-decoration:none;display:block;}" + ".dropdown-content a:hover {background-color: #dddfff;}\r\n" + ".dropdown:hover .dropdown-content {display: block;}\r\n" + ".dropdown:hover .dropbtn {background-color: #ddd;}\r\n" + "input.btn:active {background:black;color:white;}\r\n" + "submit.btn:active {background:black;color:white;}\r\n"; + ReplyLen = sprintf(_REPLYBUFFER, "%s", WebprocCSS); + } + + else if (_stricmp(NodeURL, "/Node/Killandrestart") == 0) + { + int port = atoi(Context); + + if (port > 0 && port <= MaxBPQPortNo) + { + struct TNCINFO * TNC = TNCInfo[port]; + + KillTNC(TNC); + TNC->DontRestart = FALSE; + RestartTNC(TNC); + + if (TNC && TNC->WebWindowProc) + ReplyLen = TNC->WebWindowProc(TNC, _REPLYBUFFER, LOCAL); + + } + } + + else if (_stricmp(NodeURL, "/Node/Port") == 0 || _stricmp(NodeURL, "/Node/ARDOPAbort") == 0) + { + int port = atoi(Context); + + if (port > 0 && port <= MaxBPQPortNo) + { + struct TNCINFO * TNC = TNCInfo[port]; + + if (TNC && TNC->WebWindowProc) + ReplyLen = TNC->WebWindowProc(TNC, _REPLYBUFFER, LOCAL); + } + + } + + else if (_stricmp(NodeURL, "/Node/Streams") == 0) + { + ReplyLen = StatusProc(_REPLYBUFFER); + } + + else if (_stricmp(NodeURL, "/Node/Stats.html") == 0) + { + struct tm * TM; + char UPTime[50]; + time_t szClock = STATSTIME * 60; + + TM = gmtime(&szClock); + + sprintf(UPTime, "%.2d:%.2d:%.2d", TM->tm_yday, TM->tm_hour, TM->tm_min); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", StatsHddr); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + "Version", VersionString); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + "Uptime (Days Hours Mins)", UPTime); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + "Semaphore: Get-Rel/Clashes", Semaphore.Gets - Semaphore.Rels, Semaphore.Clashes); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + "Buffers: Max/Cur/Min/Out/Wait", MAXBUFFS, QCOUNT, MINBUFFCOUNT, NOBUFFCOUNT, BUFFERWAITS); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + "Known Nodes/Max Nodes", NUMBEROFNODES, MAXDESTS); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + "L4 Connects Sent/Rxed ", L4CONNECTSOUT, L4CONNECTSIN); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + "L4 Frames TX/RX/Resent/Reseq", L4FRAMESTX, L4FRAMESRX, L4FRAMESRETRIED, OLDFRAMES); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + "L3 Frames Relayed", L3FRAMES); + + } + + else if (_stricmp(NodeURL, "/Node/RigControl.html") == 0) + { + char Test[] = + "\r\n" + "Rigcontrol\r\n" + "\r\n" + "\r\n" + "\r\n" + "
Waiting for data...
\r\n" + "\r\n"; + + + char NoRigCtl[] = + "\r\n" + "Rigcontrol\r\n" + "\r\n" + "\r\n" + "
RigControl Not Configured...
\r\n" + "\r\n"; + + if (RigWebPage) + ReplyLen = sprintf(_REPLYBUFFER, "%s", Test); + else + ReplyLen = sprintf(_REPLYBUFFER, "%s", NoRigCtl); + } + + else if (_stricmp(NodeURL, "/Node/ShowLog.html") == 0) + { + char ShowLogPage[] = + "" + "" + "Log Display" + "" + "
" + "
" +// "" + "" + "" + "
"; + + char * _REPLYBUFFER; + int ReplyLen; + char Header[256]; + int HeaderLen; + char * CfgBytes; + int CfgLen; + char inputname[250]; + FILE *fp1; + struct stat STAT; + char DummyKey[] = "DummyKey"; + time_t T; + struct tm * tm; + char Name[64] = ""; + + T = time(NULL); + tm = gmtime(&T); + + if (LOCAL == FALSE && COOKIE == FALSE) + { + // Send Not Authorized + + char _REPLYBUFFER[4096]; + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
Not authorized - please sign in"); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + return 1; + } + + if (COOKIE == FALSE) + Key = DummyKey; + + if (memcmp(Context, "date=", 5) == 0) + { + memset(tm, 0, sizeof(struct tm)); + tm->tm_year = atoi(&Context[5]) - 1900; + tm->tm_mon = atoi(&Context[10]) - 1; + tm->tm_mday = atoi(&Context[13]); + } + + + + if (strcmp(Context, "input=Back") == 0) + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, Reply, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + return 1; + } + + if (LogDirectory[0] == 0) + { + strcpy(inputname, "logs/"); + } + else + { + strcpy(inputname,LogDirectory); + strcat(inputname,"/"); + strcat(inputname, "/logs/"); + } + + if (strstr(Context, "CMS")) + { + sprintf(Name, "CMSAccess_%04d%02d%02d.log", + tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday); + } + else if (strstr(Context, "Debug")) + { + sprintf(Name, "log_%02d%02d%02d_DEBUG.txt", + tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday); + } + else if (strstr(Context, "BBS")) + { + sprintf(Name, "log_%02d%02d%02d_BBS.txt", + tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday); + } + else if (strstr(Context, "Chat")) + { + sprintf(Name, "log_%02d%02d%02d_CHAT.txt", + tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday); + } + else if (strstr(Context, "Telnet")) + { + sprintf(Name, "Telnet_%02d%02d%02d.log", + tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday); + } + + strcat(inputname, Name); + + if (stat(inputname, &STAT) == -1) + { + CfgBytes = malloc(256); + sprintf(CfgBytes, "Log %s not found", inputname); + CfgLen = strlen(CfgBytes); + } + else + { + fp1 = fopen(inputname, "rb"); + + if (fp1 == 0) + { + CfgBytes = malloc(256); + sprintf(CfgBytes, "Log %s not found", inputname); + CfgLen = strlen(CfgBytes); + } + else + { + CfgLen = STAT.st_size; + + CfgBytes = malloc(CfgLen + 1); + + CfgLen = (int)fread(CfgBytes, 1, CfgLen, fp1); + CfgBytes[CfgLen] = 0; + } + } + + _REPLYBUFFER = malloc(CfgLen + 1000); + + ReplyLen = sprintf(_REPLYBUFFER, ShowLogPage, CfgBytes); + free (CfgBytes); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, _REPLYBUFFER, ReplyLen); + sendandcheck(sock, Tail, (int)strlen(Tail)); + free (_REPLYBUFFER); + + return 1; + } + + else if (_stricmp(NodeURL, "/Node/EditCfg.html") == 0) + { + char * _REPLYBUFFER; + int ReplyLen; + char Header[256]; + int HeaderLen; + char * CfgBytes; + int CfgLen; + char inputname[250]="bpq32.cfg"; + FILE *fp1; + struct stat STAT; + char DummyKey[] = "DummyKey"; + + if (LOCAL == FALSE && COOKIE == FALSE) + { + // Send Not Authorized + + char _REPLYBUFFER[4096]; + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
Not authorized - please sign in"); + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + send(sock, Header, HeaderLen, 0); + send(sock, _REPLYBUFFER, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + return 1; + } + + if (COOKIE ==FALSE) + Key = DummyKey; + + if (ConfigDirectory[0] == 0) + { + strcpy(inputname, "bpq32.cfg"); + } + else + { + strcpy(inputname,ConfigDirectory); + strcat(inputname,"/"); + strcat(inputname, "bpq32.cfg"); + } + + + if (stat(inputname, &STAT) == -1) + { + CfgBytes = _strdup("Config File not found"); + } + else + { + fp1 = fopen(inputname, "rb"); + + if (fp1 == 0) + { + CfgBytes = _strdup("Config File not found"); + } + else + { + CfgLen = STAT.st_size; + + CfgBytes = malloc(CfgLen + 1); + + CfgLen = (int)fread(CfgBytes, 1, CfgLen, fp1); + CfgBytes[CfgLen] = 0; + } + } + + _REPLYBUFFER = malloc(CfgLen + 1000); + + ReplyLen = sprintf(_REPLYBUFFER, ConfigEditPage, Key, CfgBytes); + free (CfgBytes); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", ReplyLen + (int)strlen(Tail)); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, _REPLYBUFFER, ReplyLen); + sendandcheck(sock, Tail, (int)strlen(Tail)); + free (_REPLYBUFFER); + + return 1; + } + + + + if (_stricmp(NodeURL, "/Node/PortBeacons") == 0) + { + char * PortChar = strtok_s(NULL, "&", &Context); + int PortNo = atoi(PortChar); + struct PORTCONTROL * PORT; + int PortSlot = 0; + + PORT = GetPortTableEntryFromPortNum(PortNo); // Need slot not number + if (PORT) + PortSlot = PORT->PortSlot; + + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], Beacons, PortNo, + Interval[PortSlot], &UIUIDEST[PortSlot][0], &UIUIDigi[PortSlot][0], &FN[PortSlot][0], &Message[PortSlot][0], PortNo); + } + + + + if (_stricmp(NodeURL, "/Node/PortStats") == 0) + { + struct _EXTPORTDATA * Port; + + char * PortChar = strtok_s(NULL, "&", &Context); + int PortNo = atoi(PortChar); + int Protocol; + int PortType; + + // char PORTTYPE; // H/W TYPE + // 0 = ASYNC, 2 = PC120, 4 = DRSI + // 6 = TOSH, 8 = QUAD, 10 = RLC100 + // 12 = RLC400 14 = INTERNAL 16 = EXTERNAL + +#define KISS 0 +#define NETROM 2 +#define HDLC 6 +#define L2 8 +#define WINMOR 10 + + + // char PROTOCOL; // PORT PROTOCOL + // 0 = KISS, 2 = NETROM, 4 = BPQKISS + //; 6 = HDLC, 8 = L2 + + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsHddr, PortNo); + + Port = (struct _EXTPORTDATA *)GetPortTableEntryFromPortNum(PortNo); + + if (Port == NULL) + { + ReplyLen = sprintf(_REPLYBUFFER, "Invalid Port"); + goto SendResp; + } + + Protocol = Port->PORTCONTROL.PROTOCOL; + PortType = Port->PORTCONTROL.PROTOCOL; + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Frames Digied", Port->PORTCONTROL.L2DIGIED); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Frames Heard", Port->PORTCONTROL.L2FRAMES); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Frames Received", Port->PORTCONTROL.L2FRAMESFORUS); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Frames Sent", Port->PORTCONTROL.L2FRAMESSENT); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Timeouts", Port->PORTCONTROL.L2TIMEOUTS); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "REJ Frames Received", Port->PORTCONTROL.L2REJCOUNT); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "RX out of Seq", Port->PORTCONTROL.L2OUTOFSEQ); + // ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "L2 Resequenced", Port->PORTCONTROL.L2RESEQ); + if (Protocol == HDLC) + { + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "Underrun", Port->PORTCONTROL.L2URUNC); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "RX Overruns", Port->PORTCONTROL.L2ORUNC); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "RX CRC Errors", Port->PORTCONTROL.RXERRORS); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "Frames abandoned", Port->PORTCONTROL.L1DISCARD); + } + else if ((Protocol == KISS && Port->PORTCONTROL.KISSFLAGS) || Protocol == NETROM) + { + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "Poll Timeout", Port->PORTCONTROL.L2URUNC); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "RX CRC Errors", Port->PORTCONTROL.RXERRORS); + } + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "FRMRs Sent", Port->PORTCONTROL.L2FRMRTX); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortStatsLine, "FRMRs Received", Port->PORTCONTROL.L2FRMRRX); + + // DB 'Link Active % ' + // DD AVSENDING + + } + + if (_stricmp(NodeURL, "/Node/Ports.html") == 0) + { + struct _EXTPORTDATA * ExtPort; + struct PORTCONTROL * Port; + + int count; + char DLL[20]; + char StatsURL[64]; + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", PortsHddr); + + for (count = 1; count <= NUMBEROFPORTS; count++) + { + Port = GetPortTableEntryFromSlot(count); + ExtPort = (struct _EXTPORTDATA *)Port; + + // see if has a stats page + + if (Port->AVACTIVE) + sprintf(StatsURL, " Stats Graph", Port->PORTNUMBER); + else + StatsURL[0] = 0; + + if (Port->PORTTYPE == 0x10) + { + strcpy(DLL, ExtPort->PORT_DLL_NAME); + strlop(DLL, '.'); + } + else if (Port->PORTTYPE == 0) + strcpy(DLL, "ASYNC"); + + else if (Port->PORTTYPE == 22) + strcpy(DLL, "I2C"); + + else if (Port->PORTTYPE == 14) + strcpy(DLL, "INTERNAL"); + + else if (Port->PORTTYPE > 0 && Port->PORTTYPE < 14) + strcpy(DLL, "HDLC"); + + + if (Port->TNC && Port->TNC->WebWindowProc) // Has a Window + { + if (Port->UICAPABLE) + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortLineWithBeaconAndDriver, Port->PORTNUMBER, DLL, + Port->PORTDESCRIPTION, Port->PORTNUMBER, Port->PORTNUMBER, Port->TNC->WebWinX, Port->TNC->WebWinY, 200, 200, StatsURL); + else + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortLineWithDriver, Port->PORTNUMBER, DLL, + Port->PORTDESCRIPTION, Port->PORTNUMBER, Port->TNC->WebWinX, Port->TNC->WebWinY, 200, 200, StatsURL); + + continue; + } + + if (Port->PORTTYPE == 16 && Port->PROTOCOL == 10 && Port->UICAPABLE == 0) // EXTERNAL, Pactor/WINMO + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], SessionPortLine, Port->PORTNUMBER, DLL, + Port->PORTDESCRIPTION, Port->PORTNUMBER, StatsURL); + else + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], PortLineWithBeacon, Port->PORTNUMBER, Port->PORTNUMBER, + DLL, DLL, Port->PORTDESCRIPTION, Port->PORTNUMBER, StatsURL); + } + + if (RigActive) + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], RigControlLine, 64, "Rig Control", "Rig Control", 600, 350, 200, 200); + + } + + if (_stricmp(NodeURL, "/Node/Nodes.html") == 0) + { + struct DEST_LIST * Dests = DESTS; + int count, i; + char Normcall[10]; + char Alias[10]; + int Width = 5; + int x = 0, n = 0; + struct DEST_LIST * List[1000]; + char Param = 0; + + if (Context) + { + _strupr(Context); + Param = Context[0]; + } + + for (count = 0; count < MAXDESTS; count++) + { + if (Dests->DEST_CALL[0] != 0) + { + if (Param != 'T' || Dests->DEST_COUNT) + List[n++] = Dests; + + if (n > 999) + break; + } + + Dests++; + } + + if (n > 1) + { + if (Param == 'C') + qsort(List, n, sizeof(void *), CompareNode); + else + qsort(List, n, sizeof(void *), CompareAlias); + } + + Alias[6] = 0; + + if (Param == 'T') + { + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], NodeHddr, "with traffic"); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], ""); + } + else if (Param == 'C') + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], NodeHddr, "sorted by Call"); + else + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], NodeHddr, "sorted by Alias"); + + for (i = 0; i < n; i++) + { + int len = ConvFromAX25(List[i]->DEST_CALL, Normcall); + Normcall[len]=0; + + memcpy(Alias, List[i]->DEST_ALIAS, 6); + strlop(Alias, ' '); + + if (Param == 'T') + { + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + Normcall, Alias, List[i]->DEST_COUNT, List[i]->DEST_RTT /16, + (List[i]->DEST_STATE & 0x40)? 'B':' ', (List[i]->DEST_STATE & 63)); + + } + else + { + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], NodeLine, Normcall, Alias, Normcall); + + if (++x == Width) + { + x = 0; + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], ""); + } + } + } + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], ""); + } + + if (_stricmp(NodeURL, "/Node/NodeDetail") == 0) + { + UCHAR AXCall[8]; + struct DEST_LIST * Dest = DESTS; + struct NR_DEST_ROUTE_ENTRY * NRRoute; + struct ROUTE * Neighbour; + char Normcall[10]; + int i, len, count, Active; + char Alias[7]; + + Alias[6] = 0; + + _strupr(Context); + + ConvToAX25(Context, AXCall); + + for (count = 0; count < MAXDESTS; count++) + { + if (CompareCalls(Dest->DEST_CALL, AXCall)) + { + break; + } + Dest++; + } + + if (count == MAXDESTS) + { + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "

Call %s not found

", Context); + goto SendResp; + } + + memcpy(Alias, Dest->DEST_ALIAS, 6); + strlop(Alias, ' '); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], + "

Info for Node %s:%s

", Alias, Context); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "

PortDriverIDBeaconsDriver WindowStats Graph
%d %s%s
%d %s%s Beacons %s
%d%s%s %s
%d%s%s Driver Window%s
%d%s%s BeaconsDriver Window%s
%d%s%s Rig Control
%s%s
%s%s
%s%d%d
%s%d%d%d%d%d
%s%d%d
%s%d%d
%s%d%d%d%d
%s%d
CallFramesRTTBPQ?Hops
%s:%s%d%d%c%.0d
"); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
FramesRTTBPQ?Hops
%d%d%c%.0d
", + Dest->DEST_COUNT, Dest->DEST_RTT /16, + (Dest->DEST_STATE & 0x40)? 'B':' ', (Dest->DEST_STATE & 63)); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "

Neighbours

"); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], + "" + ""); + + 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; + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "", + (Active == i)?'>':' ',NRRoute->ROUT_QUALITY, NRRoute->ROUT_OBSCOUNT, Neighbour->NEIGHBOUR_PORT, Normcall); + } + NRRoute++; + } + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "
Qual Obs Port Call
%c %d%d%d%s
"); + + goto SendResp; + + } + /* + + MOV ESI,OFFSET32 NODEROUTEHDDR + MOV ECX,11 + REP MOVSB + + LEA ESI,DEST_CALL[EBX] + CALL DECODENODENAME ; CONVERT TO ALIAS:CALL + REP MOVSB + + CMP DEST_RTT[EBX],0 + JE SHORT @f ; TIMER NOT SET - DEST PROBABLY NOT USED + + MOVSB ; ADD SPACE + CALL DORTT + + @@: + MOV AL,CR + STOSB + + MOV ECX,3 + MOV DH,DEST_ROUTE[EBX] ; CURRENT ACTIVE ROUTE + MOV DL,1 + + push ebx + + PUBLIC CMDN110 + CMDN110: + + MOV ESI,ROUT1_NEIGHBOUR[EBX] + CMP ESI,0 + JE CMDN199 + + + MOV AX,' ' + CMP DH,DL + JNE SHORT CMDN112 ; NOT CURRENT DEST + MOV AX,' >' + + CMDN112: + + STOSW + + PUSH ECX + + MOV AL,ROUT1_QUALITY[EBX] + CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS + + mov AL,' ' + stosb + + MOV AL,ROUT1_OBSCOUNT[EBX] + CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS + + mov AL,' ' + stosb + + MOV AL,NEIGHBOUR_PORT[ESI] ; GET PORT + CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS + + mov AL,' ' + stosb + + + PUSH EDI + CALL CONVFROMAX25 ; CONVERT TO CALL + POP EDI + + MOV ESI,OFFSET32 NORMCALL + REP MOVSB + + MOV AL,CR + STOSB + + ADD EBX,ROUTEVECLEN + INC DL ; ROUTE NUMBER + + POP ECX + DEC ECX + JNZ CMDN110 + + PUBLIC CMDN199 + CMDN199: + + POP EBX + + ; DISPLAY INP3 ROUTES + + MOV ECX,3 + MOV DL,4 + + PUBLIC CMDNINP3 + CMDNINP3: + + MOV ESI,INPROUT1_NEIGHBOUR[EBX] + CMP ESI,0 + JE CMDNINPEND + + MOV AX,' ' + CMP DH,DL + JNE SHORT @F ; NOT CURRENT DEST + MOV AX,' >' + + @@: + + STOSW + + PUSH ECX + + MOV AL, Hops1[EBX] + CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS + + mov AL,' ' + stosb + + MOVZX EAX, SRTT1[EBX] + + MOV EDX,0 + MOV ECX, 100 + DIV ECX + CALL CONV_5DIGITS + MOV AL,'.' + STOSB + MOV EAX, EDX + CALL PRINTNUM + MOV AL,'s' + STOSB + MOV AL,' ' + STOSB + + MOV AL,NEIGHBOUR_PORT[ESI] ; GET PORT + CALL CONV_DIGITS ; CONVERT AL TO DECIMAL DIGITS + + mov AL,' ' + stosb + + PUSH EDI + CALL CONVFROMAX25 ; CONVERT TO CALL + POP EDI + + MOV ESI,OFFSET32 NORMCALL + REP MOVSB + + + MOV AL,CR + STOSB + + ADD EBX,INPROUTEVECLEN + INC DL ; ROUTE NUMBER + + POP ECX + LOOP CMDNINP3 + + CMDNINPEND: + + ret + + */ + + + if (_stricmp(NodeURL, "/Node/Routes.html") == 0) + { + struct ROUTE * Routes = NEIGHBOURS; + int MaxRoutes = MAXNEIGHBOURS; + int count; + char Normcall[10]; + char locked; + int NodeCount; + int Percent = 0; + int Iframes, Retries; + char Active[10]; + int Queued; + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", RouteHddr); + + for (count=0; countNEIGHBOUR_CALL[0] != 0) + { + int len = ConvFromAX25(Routes->NEIGHBOUR_CALL, Normcall); + Normcall[len]=0; + + if ((Routes->NEIGHBOUR_FLAG & 1) == 1) + locked = '!'; + else + locked = ' '; + + NodeCount = COUNTNODES(Routes); + + if (Routes->NEIGHBOUR_LINK) + Queued = COUNT_AT_L2(Routes->NEIGHBOUR_LINK); + else + Queued = 0; + + Iframes = Routes->NBOUR_IFRAMES; + Retries = Routes->NBOUR_RETRIES; + + if (Routes->NEIGHBOUR_LINK && Routes->NEIGHBOUR_LINK->L2STATE >= 5) + strcpy(Active, ">"); + else + strcpy(Active, " "); + + if (Iframes) + Percent = (Retries * 100) / Iframes; + else + Percent = 0; + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], RouteLine, Active, Routes->NEIGHBOUR_PORT, Normcall, locked, + Routes->NEIGHBOUR_QUAL, NodeCount, Iframes, Retries, Percent, Routes->NBOUR_MAXFRAME, Routes->NBOUR_FRACK, + Routes->NEIGHBOUR_TIME >> 8, Routes->NEIGHBOUR_TIME & 0xff, Queued, Routes->OtherendsRouteQual); + } + Routes+=1; + } + } + + if (_stricmp(NodeURL, "/Node/Links.html") == 0) + { + struct _LINKTABLE * Links = LINKS; + int MaxLinks = MAXLINKS; + int count; + char Normcall1[10]; + char Normcall2[10]; + char State[12] = "", Type[12] = "Uplink"; + int axState; + int cctType; + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", LinkHddr); + + for (count=0; countLINKCALL[0] != 0) + { + int len = ConvFromAX25(Links->LINKCALL, Normcall1); + Normcall1[len] = 0; + + len = ConvFromAX25(Links->OURCALL, Normcall2); + Normcall2[len] = 0; + + axState = Links->L2STATE; + + if (axState == 2) + strcpy(State, "Connecting"); + else if (axState == 3) + strcpy(State, "FRMR"); + else if (axState == 4) + strcpy(State, "Closing"); + else if (axState == 5) + strcpy(State, "Active"); + else if (axState == 6) + strcpy(State, "REJ Sent"); + + cctType = Links->LINKTYPE; + + if (cctType == 1) + strcpy(Type, "Uplink"); + else if (cctType == 2) + strcpy(Type, "Downlink"); + else if (cctType == 3) + strcpy(Type, "Node-Node"); + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], LinkLine, Normcall1, Normcall2, Links->LINKPORT->PORTNUMBER, + State, Type, 2 - Links->VER1FLAG ); + + Links+=1; + } + } + } + + if (_stricmp(NodeURL, "/Node/Users.html") == 0) + { + TRANSPORTENTRY * L4 = L4TABLE; + TRANSPORTENTRY * Partner; + int MaxLinks = MAXLINKS; + int count; + char State[12] = "", Type[12] = "Uplink"; + char LHS[50] = "", MID[10] = "", RHS[50] = ""; + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", UserHddr); + + for (count=0; count < MAXCIRCUITS; count++) + { + 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: + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], UserLine, LHS, MID, RHS); + } +CMDS60: + L4++; + } + } + /* + PUBLIC CMDUXX_1 + CMDUXX_1: + push EBX + push ESI + PUSH ECX + push EDI + + call _FINDDESTINATION + pop EDI + + jz SHORT NODE_FOUND + + push EDI ; NET/ROM not found + call CONVFROMAX25 ; CONVERT TO CALL + pop EDI + mov ESI,OFFSET32 NORMCALL + rep movsb + + jmp SHORT END_CMDUXX + + PUBLIC NODE_FOUND + NODE_FOUND: + + lea ESI,DEST_CALL[EBX] + call DECODENODENAME + + REP MOVSB + + PUBLIC END_CMDUXX + END_CMDUXX: + + POP ECX + pop ESI + pop EBX + ret + + }}} + */ + + else if (_stricmp(NodeURL, "/Node/Terminal.html") == 0) + { + if (COOKIE && Session) + { + // Already signed in as sysop + + struct UserRec * USER = Session->USER; + + struct HTTPConnectionInfo * NewSession = AllocateSession(sock, 'T'); + + if (NewSession) + { + char AXCall[10]; + ReplyLen = sprintf(_REPLYBUFFER, TermPage, Mycall, Mycall, NewSession->Key, NewSession->Key, NewSession->Key); + strcpy(NewSession->HTTPCall, USER->Callsign); + ConvToAX25(NewSession->HTTPCall, AXCall); + ChangeSessionCallsign(NewSession->Stream, AXCall); + BPQHOSTVECTOR[NewSession->Stream -1].HOSTSESSION->Secure_Session = USER->Secure; + Session->USER = USER; + NewSession->TNC = conn->TNC; + + + // if (Appl[0]) + // { + // strcat(Appl, "\r"); + // SendMsg(Session->Stream, Appl, strlen(Appl)); + // } + + } + else + { + ReplyLen = SetupNodeMenu(_REPLYBUFFER, LOCAL); + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", BusyError); + } + } + else if (LOCAL) + { + // connected to 127.0.0.1 so sign in using node call + + struct HTTPConnectionInfo * NewSession = AllocateSession(sock, 'T'); + + if (NewSession) + { + ReplyLen = sprintf(_REPLYBUFFER, TermPage, Mycall, Mycall, NewSession->Key, NewSession->Key, NewSession->Key); + strcpy(NewSession->HTTPCall, MYNODECALL); + ChangeSessionCallsign(NewSession->Stream, MYCALL); + BPQHOSTVECTOR[NewSession->Stream -1].HOSTSESSION->Secure_Session = TRUE; + NewSession->TNC = conn->TNC; + } + } + else + ReplyLen = sprintf(_REPLYBUFFER, TermSignon, Mycall, Mycall, Context); + } + + else if (_stricmp(NodeURL, "/Node/Signon.html") == 0) + { + ReplyLen = sprintf(_REPLYBUFFER, NodeSignon, Mycall, Mycall, Context); + } + + else if (_stricmp(NodeURL, "/Node/Drivers") == 0) + { + int Bufferlen = SendMessageFile(sock, "/Drivers.htm", TRUE, allowDeflate); // return -1 if not found + + if (Bufferlen != -1) + return 0; // We've sent it + } + + else if (_stricmp(NodeURL, "/Node/OutputScreen.html") == 0) + { + struct HTTPConnectionInfo * Session = FindSession(Context); + + if (Session == NULL) + { + ReplyLen = sprintf(_REPLYBUFFER, "%s", LostSession); + } + else + { + Session->sock = sock; // socket to reply on + ReplyLen = RefreshTermWindow(TCP, Session, _REPLYBUFFER); + + if (ReplyLen == 0) // Nothing new + { + // Debugprintf("GET with no data avail - response held"); + Session->ResponseTimer = 1200; // Delay response for up to a minute + } + else + { + // Debugprintf("GET - outpur sent, timer was %d, set to zero", Session->ResponseTimer); + Session->ResponseTimer = 0; + } + + Session->KillTimer = 0; + return 0; // Refresh has sent any available output + } + } + + else if (_stricmp(NodeURL, "/Node/InputLine.html") == 0) + { + struct TNCINFO * TNC = conn->TNC; + struct TCPINFO * TCP = 0; + + if (TNC) + TCP = TNC->TCPInfo; + + if (TCP && TCP->WebTermCSS) + ReplyLen = sprintf(_REPLYBUFFER, InputLine, Context, TCP->WebTermCSS); + else + ReplyLen = sprintf(_REPLYBUFFER, InputLine, Context, ""); + + } + + else if (_stricmp(NodeURL, "/Node/PTT") == 0) + { + struct TNCINFO * TNC = conn->TNC; + int x = atoi(Context); + } + + +SendResp: + + FormatTime3(TimeString, time(NULL)); + + strcpy(&_REPLYBUFFER[ReplyLen], Tail); + ReplyLen += (int)strlen(Tail); + + + if (allowDeflate) + { + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + } + else + { + Encoding[0] = 0; + Compressed = _REPLYBUFFER; + } + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n" + "Date: %s\r\n%s\r\n", ReplyLen, TimeString, Encoding); + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + } + return 0; + +#ifdef WIN32xx + } +#include "StdExcept.c" +} +return 0; +#endif +} + +void ProcessHTTPMessage(void * conn) +{ + // conn is a malloc'ed copy to handle reused connections, so need to free it + + InnerProcessHTTPMessage((struct ConnectionInfo *)conn); + free(conn); + return; +} + +static char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; +static char *dat[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + + +VOID FormatTime3(char * Time, time_t cTime) +{ + struct tm * TM; + TM = gmtime(&cTime); + + sprintf(Time, "%s, %02d %s %3d %02d:%02d:%02d GMT", dat[TM->tm_wday], TM->tm_mday, month[TM->tm_mon], + TM->tm_year + 1900, TM->tm_hour, TM->tm_min, TM->tm_sec); + +} + +// Sun, 06 Nov 1994 08:49:37 GMT + +int StatusProc(char * Buff) +{ + int i; + char callsign[12] = ""; + char flag[3]; + UINT Mask, MaskCopy; + int Flags; + int AppNumber; + int OneBits; + int Len = sprintf(Buff, "" + "Stream Status"); + + Len += sprintf(&Buff[Len], ""); + Len += sprintf(&Buff[Len], ""); + Len += sprintf(&Buff[Len], ""); + Len += sprintf(&Buff[Len], ""); + Len += sprintf(&Buff[Len], ""); + Len += sprintf(&Buff[Len], ""); + Len += sprintf(&Buff[Len], ""); + + for (i=1;i<65; i++) + { + callsign[0]=0; + + if (GetAllocationState(i)) + + strcpy(flag,"*"); + else + strcpy(flag," "); + + GetCallsign(i,callsign); + + Mask = MaskCopy = Get_APPLMASK(i); + + // if only one bit set, convert to number + + AppNumber = 0; + OneBits = 0; + + while (MaskCopy) + { + if (MaskCopy & 1) + OneBits++; + + AppNumber++; + MaskCopy = MaskCopy >> 1; + } + + Flags=GetApplFlags(i); + + if (OneBits > 1) + Len += sprintf(&Buff[Len], "" + "", + i, flag, RXCount(i), TXCount(i), MONCount(i), Mask, Flags, callsign, BPQHOSTVECTOR[i-1].PgmName); + + else + Len += sprintf(&Buff[Len], "" + "", + i, flag, RXCount(i), TXCount(i), MONCount(i), AppNumber, Flags, callsign, BPQHOSTVECTOR[i-1].PgmName); + + if ((i & 1) == 0) + Len += sprintf(&Buff[Len], ""); + + } + + Len += sprintf(&Buff[Len], "
    RX   TX   MON  App  Flg Callsign  Program    RX   TX   MON  App  Flg Callsign  Program
%d%s%d%d%d%x%x%s%s%d%s%d%d%d%d%x%s%s
"); + return Len; +} + +int ProcessNodeSignon(SOCKET sock, struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, int LOCAL) +{ + int ReplyLen = 0; + char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + char * user, * password, * Key; + char Header[256]; + int HeaderLen; + struct HTTPConnectionInfo *Sess; + + + if (input) + { + int i; + struct UserRec * USER; + + UndoTransparency(input); + + if (strstr(input, "Cancel=Cancel")) + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n" + "\r\n", (int)(ReplyLen + strlen(Tail))); + send(sock, Header, HeaderLen, 0); + send(sock, Reply, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + } + user = strtok_s(&input[9], "&", &Key); + password = strtok_s(NULL, "=", &Key); + password = Key; + + for (i = 0; i < TCP->NumberofUsers; i++) + { + USER = TCP->UserRecPtr[i]; + + if (user && _stricmp(user, USER->UserName) == 0) + { + if (strcmp(password, USER->Password) == 0 && USER->Secure) + { + // ok + + Sess = *Session = AllocateSession(sock, 'N'); + Sess->USER = USER; + + ReplyLen = SetupNodeMenu(Reply, LOCAL); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n" + "Set-Cookie: BPQSessionCookie=%s; Path = /\r\n\r\n", (int)(ReplyLen + strlen(Tail)), Sess->Key); + send(sock, Header, HeaderLen, 0); + send(sock, Reply, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + return ReplyLen; + } + } + } + } + + ReplyLen = sprintf(Reply, NodeSignon, Mycall, Mycall); + ReplyLen += sprintf(&Reply[ReplyLen], "%s", PassError); + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Type: text/html\r\n\r\n", (int)(ReplyLen + strlen(Tail))); + send(sock, Header, HeaderLen, 0); + send(sock, Reply, ReplyLen, 0); + send(sock, Tail, (int)strlen(Tail), 0); + + return 0; + + + return ReplyLen; +} + +int ProcessMailAPISignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, BOOL WebMail, int LOCAL) +{ + int ReplyLen = 0; + char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + char * user, * password, * Key; + struct HTTPConnectionInfo * NewSession; + int i; + struct UserRec * USER; + + if (strchr(MsgPtr, '?')) + { + // Check Password + + user = strlop(MsgPtr, '?'); + password = strlop(user, '&'); + strlop(password, ' '); + + for (i = 0; i < TCP->NumberofUsers; i++) + { + USER = TCP->UserRecPtr[i]; + + if (user && _stricmp(user, USER->UserName) == 0) + { + if ((strcmp(password, USER->Password) == 0) && (USER->Secure || WebMail)) + { + // ok + + NewSession = AllocateSession(Appl[0], 'M'); + + *Session = NewSession; + + if (NewSession) + { + ReplyLen = 0; + strcpy(NewSession->Callsign, USER->Callsign); + } + else + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); + } + return ReplyLen; + + } + } + } + + // Pass failed attempt to BBS code so it can try a bbs user login + + // Need to put url back together + + if (user && user[0] && password && password[0]) + { + sprintf(MsgPtr, "%s?%s&%s", MsgPtr, user, password); + } + } + + NewSession = AllocateSession(Appl[0], 'M'); + + *Session = NewSession; + + if (NewSession) + ReplyLen = 0; + else + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); + } + + return ReplyLen; +} + + + + +int ProcessMailSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, BOOL WebMail, int LOCAL) +{ + int ReplyLen = 0; + char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + char * user, * password, * Key; + struct HTTPConnectionInfo * NewSession; + + if (input) + { + int i; + struct UserRec * USER; + + UndoTransparency(input); + + if (strstr(input, "Cancel=Cancel")) + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + return ReplyLen; + } + user = strtok_s(&input[9], "&", &Key); + password = strtok_s(NULL, "=", &Key); + password = Key; + + for (i = 0; i < TCP->NumberofUsers; i++) + { + USER = TCP->UserRecPtr[i]; + + if (user && _stricmp(user, USER->UserName) == 0) + { + if (strcmp(password, USER->Password) == 0 && (USER->Secure || WebMail)) + { + // ok + + NewSession = AllocateSession(Appl[0], 'M'); + + *Session = NewSession; + + if (NewSession) + { + + ReplyLen = 0; + strcpy(NewSession->Callsign, USER->Callsign); + } + else + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); + } + return ReplyLen; + } + } + } + } + + ReplyLen = sprintf(Reply, MailSignon, Mycall, Mycall); + ReplyLen += sprintf(&Reply[ReplyLen], "%s", PassError); + + return ReplyLen; +} + + +int ProcessChatSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, struct HTTPConnectionInfo ** Session, int LOCAL) +{ + int ReplyLen = 0; + char * input = strstr(MsgPtr, "\r\n\r\n"); // End of headers + char * user, * password, * Key; + + if (input) + { + int i; + struct UserRec * USER; + + UndoTransparency(input); + + if (strstr(input, "Cancel=Cancel")) + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + return ReplyLen; + } + + user = strtok_s(&input[9], "&", &Key); + password = strtok_s(NULL, "=", &Key); + password = Key; + + + for (i = 0; i < TCP->NumberofUsers; i++) + { + USER = TCP->UserRecPtr[i]; + + if (user && _stricmp(user, USER->UserName) == 0) + { + if (strcmp(password, USER->Password) == 0 && USER->Secure) + { + // ok + + *Session = AllocateSession(Appl[0], 'C'); + + if (Session) + { + ReplyLen = 0; + } + else + { + ReplyLen = SetupNodeMenu(Reply, LOCAL); + ReplyLen += sprintf(&Reply[ReplyLen], "%s", BusyError); + } + return ReplyLen; + } + } + } + } + + ReplyLen = sprintf(Reply, ChatSignon, Mycall, Mycall); + ReplyLen += sprintf(&Reply[ReplyLen], "%s", PassError); + + return ReplyLen; + +} + +#define SHA1_HASH_LEN 20 + +/* + +Copyright (C) 1998, 2009 +Paul E. Jones + +Freeware Public License (FPL) + +This software is licensed as "freeware." Permission to distribute +this software in source and binary forms, including incorporation +into other products, is hereby granted without a fee. THIS SOFTWARE +IS PROVIDED 'AS IS' AND WITHOUT ANY EXPRESSED OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHOR SHALL NOT BE HELD +LIABLE FOR ANY DAMAGES RESULTING FROM THE USE OF THIS SOFTWARE, EITHER +DIRECTLY OR INDIRECTLY, INCLUDING, BUT NOT LIMITED TO, LOSS OF DATA +OR DATA BEING RENDERED INACCURATE. +*/ + +/* sha1.h + * + * Copyright (C) 1998, 2009 + * Paul E. Jones + * All Rights Reserved + * + ***************************************************************************** + * $Id: sha1.h 12 2009-06-22 19:34:25Z paulej $ + ***************************************************************************** + * + * Description: + * This class implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * Many of the variable names in the SHA1Context, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +/* + * This structure will hold context information for the hashing + * operation + */ +typedef struct SHA1Context +{ + unsigned Message_Digest[5]; /* Message Digest (output) */ + + unsigned Length_Low; /* Message length in bits */ + unsigned Length_High; /* Message length in bits */ + + unsigned char Message_Block[64]; /* 512-bit message blocks */ + int Message_Block_Index; /* Index into message block array */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corruped? */ +} SHA1Context; + +/* + * Function Prototypes + */ +void SHA1Reset(SHA1Context *); +int SHA1Result(SHA1Context *); +void SHA1Input( SHA1Context *, const unsigned char *, unsigned); + +#endif + +BOOL SHA1PasswordHash(char * lpszPassword, char * Hash) +{ + SHA1Context sha; + int i; + + SHA1Reset(&sha); + SHA1Input(&sha, lpszPassword, strlen(lpszPassword)); + SHA1Result(&sha); + + // swap byte order if little endian + + for (i = 0; i < 5; i++) + sha.Message_Digest[i] = htonl(sha.Message_Digest[i]); + + memcpy(Hash, &sha.Message_Digest[0], 20); + + return TRUE; +} + +int BuildRigCtlPage(char * _REPLYBUFFER) +{ + int ReplyLen; + + struct RIGPORTINFO * PORT; + struct RIGINFO * RIG; + int p, i; + + char Page[] = + "\r\n" + // "\r\n" + "Rigcontrol\r\n" + "" + "

Rigcontrol

\r\n" + "\r\n" + "\r\n" + "\r\n" + "\r\n" + "\r\n" + "\r\n" + "\r\n" + ""; + char RigLine[] = + "\r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n" + " \r\n"; + char Tail[] = + "
RadioFreqModeSTPorts
%s%s%s/1%c%c%s
\r\n" + "\r\n"; + + ReplyLen = sprintf(_REPLYBUFFER, "%s", Page); + + for (p = 0; p < NumberofPorts; p++) + { + PORT = PORTInfo[p]; + + for (i=0; i< PORT->ConfiguredRigs; i++) + { + RIG = &PORT->Rigs[i]; + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], RigLine, RIG->WEB_Label, RIG->WEB_FREQ, RIG->WEB_MODE, RIG->WEB_SCAN, RIG->WEB_PTT, RIG->WEB_PORTS, RIG->Interlock); + } + } + + ReplyLen += sprintf(&_REPLYBUFFER[ReplyLen], "%s", Tail); + return ReplyLen; +} + + +void SendRigWebPage() +{ + int i, n; + struct ConnectionInfo * sockptr; + struct TNCINFO * TNC; + struct TCPINFO * TCP; + + for (i = 0; i < 33; i++) + { + TNC = TNCInfo[i]; + + if (TNC && TNC->Hardware == H_TELNET) + { + TCP = TNC->TCPInfo; + + if (TCP) + { + for (n = 0; n <= TCP->MaxSessions; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + + if (sockptr->SocketActive) + { + if (sockptr->HTTPMode && sockptr->WebSocks && strcmp(sockptr->WebURL, "RIGCTL") == 0) + { + char RigMsg[8192]; + int RigMsgLen = strlen(RigWebPage); + char* ptr; + + RigMsg[0] = 0x81; // Fin, Data + RigMsg[1] = 126; // Unmasked, Extended Len + RigMsg[2] = RigMsgLen >> 8; + RigMsg[3] = RigMsgLen & 0xff; + strcpy(&RigMsg[4], RigWebPage); + + // If secure session enable PTT button + + if (sockptr->WebSecure) + { + while (ptr = strstr(RigMsg, "hidden")) + memcpy(ptr, " ", 6); + } + + send(sockptr->socket, RigMsg, RigMsgLen + 4, 0); + } + } + } + } + } + } +} + +// Webmail web socket code + +int ProcessWebmailWebSock(char * MsgPtr, char * OutBuffer); + +void ProcessWebmailWebSockThread(void * conn) +{ + // conn is a malloc'ed copy to handle reused connections, so need to free it + + struct ConnectionInfo * sockptr = (struct ConnectionInfo *)conn; + char * URL = sockptr->WebURL; + int Loops = 0; + int Sent; + struct HTTPConnectionInfo Dummy = {0}; + int ReplyLen = 0; + int InputLen = 0; + +#ifdef LINBPQ + + char _REPLYBUFFER[250000]; + + ReplyLen = ProcessWebmailWebSock(URL, _REPLYBUFFER); + + // Send may block + + Sent = send(sockptr->socket, _REPLYBUFFER, ReplyLen, 0); + + while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max + { + if (Sent > 0) // something sent + { + ReplyLen -= Sent; + memmove(_REPLYBUFFER, &_REPLYBUFFER[Sent], ReplyLen); + } + + Sleep(30); + Sent = send(sockptr->socket, _REPLYBUFFER, ReplyLen, 0); + } + +#else + // Send URL to BPQMail via Pipe. Just need a dummy session, as URL contains session key + + HANDLE hPipe; + char Reply[250000]; + + + + hPipe = CreateFile(MAILPipeFileName, GENERIC_READ | GENERIC_WRITE, + 0, // exclusive access + NULL, // no security attrs + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL ); + + if (hPipe == (HANDLE)-1) + { + free(conn); + return; + } + + WriteFile(hPipe, &Dummy, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); + WriteFile(hPipe, URL, strlen(URL), &InputLen, NULL); + + ReadFile(hPipe, &Dummy, sizeof (struct HTTPConnectionInfo), &InputLen, NULL); + ReadFile(hPipe, Reply, 250000, &ReplyLen, NULL); + + if (ReplyLen <= 0) + { + InputLen = GetLastError(); + } + + CloseHandle(hPipe); + + // ?? do we need a thread to handle write which may block + + Sent = send(sockptr->socket, Reply, ReplyLen, 0); + + while (Sent != ReplyLen && Loops++ < 3000) // 100 secs max + { + // Debugprintf("%d out of %d sent %d Loops", Sent, InputLen, Loops); + + if (Sent > 0) // something sent + { + InputLen -= Sent; + memmove(Reply, &Reply[Sent], ReplyLen); + } + + Sleep(30); + Sent = send(sockptr->socket, Reply, ReplyLen, 0); + } +#endif + free(conn); + return; +} + +/* + * sha1.c + * + * Copyright (C) 1998, 2009 + * Paul E. Jones + * All Rights Reserved + * + ***************************************************************************** + * $Id: sha1.c 12 2009-06-22 19:34:25Z paulej $ + ***************************************************************************** + * + * Description: + * This file implements the Secure Hashing Standard as defined + * in FIPS PUB 180-1 published April 17, 1995. + * + * The Secure Hashing Standard, which uses the Secure Hashing + * Algorithm (SHA), produces a 160-bit message digest for a + * given data stream. In theory, it is highly improbable that + * two messages will produce the same message digest. Therefore, + * this algorithm can serve as a means of providing a "fingerprint" + * for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code was + * written with the expectation that the processor has at least + * a 32-bit machine word size. If the machine word size is larger, + * the code should still function properly. One caveat to that + * is that the input functions taking characters and character + * arrays assume that only 8 bits of information are stored in each + * character. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated for + * messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is a + * multiple of the size of an 8-bit character. + * + */ + +/* + * Define the circular shift macro + */ +#define SHA1CircularShift(bits,word) \ + ((((word) << (bits)) & 0xFFFFFFFF) | \ + ((word) >> (32-(bits)))) + +/* Function prototypes */ +void SHA1ProcessMessageBlock(SHA1Context *); +void SHA1PadMessage(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1Reset(SHA1Context *context) +{ + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Message_Digest[0] = 0x67452301; + context->Message_Digest[1] = 0xEFCDAB89; + context->Message_Digest[2] = 0x98BADCFE; + context->Message_Digest[3] = 0x10325476; + context->Message_Digest[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array within the SHA1Context provided + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * + * Returns: + * 1 if successful, 0 if it failed. + * + * Comments: + * + */ +int SHA1Result(SHA1Context *context) +{ + + if (context->Corrupted) + { + return 0; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + context->Computed = 1; + } + + return 1; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion of + * the message. + * + * Parameters: + * context: [in/out] + * The SHA-1 context to update + * message_array: [in] + * An array of characters representing the next portion of the + * message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1Input( SHA1Context *context, + const unsigned char *message_array, + unsigned length) +{ + if (!length) + { + return; + } + + if (context->Computed || context->Corrupted) + { + context->Corrupted = 1; + return; + } + + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (*message_array & 0xFF); + + context->Length_Low += 8; + /* Force it to 32 bits */ + context->Length_Low &= 0xFFFFFFFF; + if (context->Length_Low == 0) + { + context->Length_High++; + /* Force it to 32 bits */ + context->Length_High &= 0xFFFFFFFF; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * Many of the variable names in the SHAContext, especially the + * single character names, were used because those were the names + * used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const unsigned K[] = /* Constants defined in SHA-1 */ + { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + unsigned temp; /* Temporary word value */ + unsigned W[80]; /* Word sequence */ + unsigned A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = ((unsigned) context->Message_Block[t * 4]) << 24; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 1]) << 16; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 2]) << 8; + W[t] |= ((unsigned) context->Message_Block[t * 4 + 3]); + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Message_Digest[0]; + B = context->Message_Digest[1]; + C = context->Message_Digest[2]; + D = context->Message_Digest[3]; + E = context->Message_Digest[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + temp &= 0xFFFFFFFF; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Message_Digest[0] = + (context->Message_Digest[0] + A) & 0xFFFFFFFF; + context->Message_Digest[1] = + (context->Message_Digest[1] + B) & 0xFFFFFFFF; + context->Message_Digest[2] = + (context->Message_Digest[2] + C) & 0xFFFFFFFF; + context->Message_Digest[3] = + (context->Message_Digest[3] + D) & 0xFFFFFFFF; + context->Message_Digest[4] = + (context->Message_Digest[4] + E) & 0xFFFFFFFF; + + context->Message_Block_Index = 0; +} + +/* + * SHA1PadMessage + * + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call SHA1ProcessMessageBlock() + * appropriately. When it returns, it can be assumed that the + * message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * + * Returns: + * Nothing. + * + * Comments: + * + */ +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (context->Length_High >> 24) & 0xFF; + context->Message_Block[57] = (context->Length_High >> 16) & 0xFF; + context->Message_Block[58] = (context->Length_High >> 8) & 0xFF; + context->Message_Block[59] = (context->Length_High) & 0xFF; + context->Message_Block[60] = (context->Length_Low >> 24) & 0xFF; + context->Message_Block[61] = (context->Length_Low >> 16) & 0xFF; + context->Message_Block[62] = (context->Length_Low >> 8) & 0xFF; + context->Message_Block[63] = (context->Length_Low) & 0xFF; + + SHA1ProcessMessageBlock(context); +} + + diff --git a/HTTPcode.c b/HTTPcode.c index 2c0a8dd..54a0614 100644 --- a/HTTPcode.c +++ b/HTTPcode.c @@ -24,7 +24,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define DllImport -#include "CHeaders.h" +#include "cheaders.h" #include #include "tncinfo.h" @@ -70,6 +70,7 @@ char * GetStandardPage(char * FN, int * Len); BOOL SHA1PasswordHash(char * String, char * Hash); char * byte_base64_encode(char *str, int len); int APIProcessHTTPMessage(char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE); +int RHPProcessHTTPMessage(struct ConnectionInfo * conn, char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE); extern struct ROUTE * NEIGHBOURS; extern int ROUTE_LEN; @@ -1852,6 +1853,43 @@ int InnerProcessHTTPMessage(struct ConnectionInfo * conn) } } + if (_memicmp(Context, "/rhp/", 5) == 0 || _stricmp(Context, "/rhp") == 0) + { + { + ReplyLen = RHPProcessHTTPMessage(conn, _REPLYBUFFER, Method, Context, MsgPtr, LOCAL, COOKIE); + + if (memcmp(_REPLYBUFFER, "HTTP", 4) == 0) + { + // Full Message - just send it + + sendandcheck(sock, _REPLYBUFFER, ReplyLen); + + return 0; + } + + if (allowDeflate) + Compressed = Compressit(_REPLYBUFFER, ReplyLen, &ReplyLen); + else + Compressed = _REPLYBUFFER; + + HeaderLen = sprintf(Header, "HTTP/1.1 200 OK\r\n" + "Content-Length: %d\r\n" + "Content-Type: application/json\r\n" + "Connection: close\r\n" + "Access-Control-Allow-Origin: *\r\n" + "%s\r\n", ReplyLen, Encoding); + + sendandcheck(sock, Header, HeaderLen); + sendandcheck(sock, Compressed, ReplyLen); + + if (allowDeflate) + free (Compressed); + + return 0; + } + } + + // APRS process internally if (_memicmp(Context, "/APRS/", 6) == 0 || _stricmp(Context, "/APRS") == 0) @@ -5135,6 +5173,3 @@ void SHA1PadMessage(SHA1Context *context) } - - - diff --git a/HanksRT.c b/HanksRT.c index 79e1044..e8f5ffd 100644 --- a/HanksRT.c +++ b/HanksRT.c @@ -27,7 +27,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #ifdef LINBPQ -#include "CHeaders.h" +#include "cheaders.h" #endif #include "bpqchat.h" @@ -4178,10 +4178,10 @@ BOOL GetChatConfig(char * ConfigName) MaxChatStreams = GetIntValue(group, "MaxStreams"); reportChatEvents = GetIntValue(group, "reportChatEvents"); chatPaclen = GetIntValue(group, "chatPaclen"); - GetStringValue(group, "OtherChatNodes", OtherNodesList); - GetStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg); - GetStringValue(group, "MapPosition", Position); - GetStringValue(group, "MapPopup", PopupText); + GetStringValue(group, "OtherChatNodes", OtherNodesList, 1000); + GetStringValue(group, "ChatWelcomeMsg", ChatWelcomeMsg, 1000); + GetStringValue(group, "MapPosition", Position, 81); + GetStringValue(group, "MapPopup", PopupText, 260); PopupMode = GetIntValue(group, "PopupMode"); if (chatPaclen == 0) diff --git a/Housekeeping.c b/Housekeeping.c index 48ff1e7..bf2c49f 100644 --- a/Housekeeping.c +++ b/Housekeeping.c @@ -21,6 +21,11 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // // Housekeeping Module + + +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) + + #include "bpqmail.h" char * APIENTRY GetBPQDirectory(); diff --git a/IPCode.c b/IPCode.c index 80939d1..17dd412 100644 --- a/IPCode.c +++ b/IPCode.c @@ -81,7 +81,7 @@ TODo ?Multiple Adapters #include #include -#include "CHeaders.h" +#include "cheaders.h" #include "ipcode.h" diff --git a/KAMPactor.c b/KAMPactor.c index 890bcf8..749d561 100644 --- a/KAMPactor.c +++ b/KAMPactor.c @@ -53,7 +53,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include #include "time.h" -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "bpq32.h" diff --git a/KISSHF.c b/KISSHF.c index 368e04f..0c066ff 100644 --- a/KISSHF.c +++ b/KISSHF.c @@ -27,7 +27,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include #include -#include "CHeaders.h" +#include "cheaders.h" extern int (WINAPI FAR *GetModuleFileNameExPtr)(); diff --git a/L2Code.c b/L2Code.c index ab0b1f5..3cac44d 100644 --- a/L2Code.c +++ b/L2Code.c @@ -30,7 +30,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "time.h" #include "stdio.h" -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE @@ -130,7 +130,7 @@ extern int REALTIMETICKS; UCHAR NO_CTEXT = 0; UCHAR ALIASMSG = 0; -extern UINT APPLMASK; + static UCHAR ISNETROMMSG = 0; UCHAR MSGFLAG = 0; extern char * ALIASPTR; @@ -142,6 +142,30 @@ extern BOOL LogAllConnects; APPLCALLS * APPL; + +void SendL2ToMonMap(struct PORTCONTROL * PORT, char * ReportCall, char Mode, char Direction) +{ + // if Port Freq < 30Mhz send to Node Map + + if (PORT->PortFreq && PORT->PortFreq < 30000000) + { + char ReportMode[16]; + char ReportFreq[350] = ""; + + ReportMode[0] = '@'; + ReportMode[1] = Mode; + ReportMode[2] = '?'; + ReportMode[3] = Direction; + ReportMode[4] = 0; + + // If no position see if we have an APRS posn + + _gcvt(PORT->PortFreq, 9, ReportFreq); + + SendMH(0, ReportCall, ReportFreq, 0, ReportMode); + } +} + VOID L2Routine(struct PORTCONTROL * PORT, PMESSAGE Buffer) { // LEVEL 2 PROCESSING @@ -153,6 +177,7 @@ VOID L2Routine(struct PORTCONTROL * PORT, PMESSAGE Buffer) UCHAR CTL; uintptr_t Work; UCHAR c; + unsigned int APPLMASK = 0; // Check for invalid length (< 22 7Header + 7Addr + 7Addr + CTL @@ -166,7 +191,6 @@ VOID L2Routine(struct PORTCONTROL * PORT, PMESSAGE Buffer) PORT->L2FRAMES++; ALIASMSG = 0; - APPLMASK = 0; ISNETROMMSG = 0; MSGFLAG = 0; // CMD/RESP UNDEFINED @@ -238,6 +262,7 @@ VOID L2Routine(struct PORTCONTROL * PORT, PMESSAGE Buffer) if (PORT->PORTMHEARD) MHPROC(PORT, Buffer); + /// TAJ added 07/12/2020 for 'all RX traffic as IfinOctects InOctets[PORT->PORTNUMBER] += Buffer->LENGTH - MSGHDDRLEN; @@ -466,6 +491,8 @@ FORUS: if (PORT->UIHook && CTL == 3) PORT->UIHook(LINK, PORT, Buffer, ADJBUFFER, CTL, MSGFLAG); + LINK->APPLMASK = APPLMASK; + L2FORUS(LINK, PORT, Buffer, ADJBUFFER, CTL, MSGFLAG); } @@ -935,7 +962,7 @@ VOID ProcessXIDCommand(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESS // We need to save APPLMASK and ALIASPTR so following SABM connects to application - LINK->APPLMASK = APPLMASK; + // LINK->APPLMASK now set in L2FORUS LINK->ALIASPTR = ALIASPTR; PUT_ON_PORT_Q(PORT, Buffer); @@ -1062,7 +1089,7 @@ VOID L2LINKACTIVE(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * if (LINK->L2STATE == 1) // Sent XID? { - APPLMASK = LINK->APPLMASK; + LINK->APPLMASK; ALIASPTR = LINK->ALIASPTR; L2SABM(LINK, PORT, Buffer, ADJBUFFER, MSGFLAG); // Process the SABM @@ -1147,7 +1174,7 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe // IF CONNECT TO APPL ADDRESS, SET UP APPL SESSION - if (APPLMASK == 0) + if (LINK->APPLMASK == 0) { // Not ATTACH TO APPL @@ -1163,7 +1190,9 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe WriteConnectLog(fromCall, toCall, "AX.25"); hookL2SessionAccepted(PORT->PORTNUMBER, fromCall, toCall, LINK); - + + SendL2ToMonMap(PORT, fromCall, '+', 'I'); + L2SENDUA(PORT, Buffer, ADJBUFFER); if (PORT->TNC && PORT->TNC->Hardware == H_KISSHF) @@ -1280,6 +1309,8 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe hookL2SessionAccepted(PORT->PORTNUMBER, fromCall, toCall, LINK); + SendL2ToMonMap(PORT, fromCall, '+', 'I'); + if (PORT->TNC && PORT->TNC->Hardware == H_KISSHF) { struct DATAMESSAGE * Msg; @@ -1353,7 +1384,7 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe return; } - if (cATTACHTOBBS(Session, APPLMASK, PORT->PORTPACLEN, &CONERROR) == 0) + if (cATTACHTOBBS(Session, LINK->APPLMASK, PORT->PORTPACLEN, &CONERROR) == 0) { // NO BBS AVAILABLE @@ -1380,7 +1411,8 @@ VOID L2SABM(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * Buffe hookL2SessionAccepted(PORT->PORTNUMBER, fromCall, toCall, LINK); - + SendL2ToMonMap(PORT, fromCall, '+', 'I'); + if (PORT->TNC && PORT->TNC->Hardware == H_KISSHF) { struct DATAMESSAGE * Msg; @@ -1848,8 +1880,14 @@ VOID L2_PROCESS(struct _LINKTABLE * LINK, struct PORTCONTROL * PORT, MESSAGE * B { // RESPONSE TO SABM - SET LINK UP + char fromCall[12]; + + fromCall[ConvFromAX25(Buffer->ORIGIN, fromCall)] = 0; + RESET2X(LINK); // LEAVE QUEUED STUFF + SendL2ToMonMap(PORT, fromCall, '+', 'O'); + LINK->L2STATE = 5; LINK->L2TIMER = 0; // CANCEL TIMER LINK->L2RETRIES = 0; diff --git a/L3Code.c b/L3Code.c index 65db56e..0acd2f2 100644 --- a/L3Code.c +++ b/L3Code.c @@ -49,7 +49,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "stdio.h" #include -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" VOID UPDATEDESTLIST(); diff --git a/L4Code.c b/L4Code.c index 4efd2d1..81870a8 100644 --- a/L4Code.c +++ b/L4Code.c @@ -31,7 +31,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "stdio.h" #include -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" extern BPQVECSTRUC BPQHOSTVECTOR[]; @@ -68,7 +68,7 @@ VOID FRAMEFORUS(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, int ApplMask, void WriteConnectLog(char * fromCall, char * toCall, UCHAR * Mode); void SendVARANetromMsg(struct TNCINFO * TNC, PL3MESSAGEBUFFER MSG); -extern UINT APPLMASK; +static UINT APPLMASK; extern BOOL LogL4Connects; extern BOOL LogAllConnects; diff --git a/LinBPQ-skigdebian.c b/LinBPQ-skigdebian.c new file mode 100644 index 0000000..60f670e --- /dev/null +++ b/LinBPQ-skigdebian.c @@ -0,0 +1,2154 @@ +/* +Copyright 2001-2018 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 +*/ + +// Control Routine for LinBPQ + +#define _CRT_SECURE_NO_DEPRECATE + +#include "cheaders.h" +#include "bpqmail.h" +#ifdef WIN32 +#include +//#include "C:\Program Files (x86)\GnuWin32\include\iconv.h" +#else +#include +#include +#ifndef MACBPQ +#ifndef FREEBSD +#include +#endif +#endif +#endif + +#include "time.h" + +#define Connect(stream) SessionControl(stream,1,0) +#define Disconnect(stream) SessionControl(stream,2,0) +#define ReturntoNode(stream) SessionControl(stream,3,0) +#define ConnectUsingAppl(stream, appl) SessionControl(stream, 0, appl) + +BOOL APIENTRY Rig_Init(); + + + +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) + +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); +void FreeSemaphore(struct SEM * Semaphore); +VOID CopyConfigFile(char * ConfigName); +VOID SendMailForThread(VOID * Param); +VOID GetUIConfig(); +Dll BOOL APIENTRY Init_IP(); +VOID OpenReportingSockets(); +VOID SetupNTSAliases(char * FN); +int DeleteRedundantMessages(); +BOOL InitializeTNCEmulator(); +VOID FindLostBuffers(); +VOID IPClose(); +DllExport BOOL APIENTRY Rig_Close(); +Dll BOOL APIENTRY Poll_IP(); +BOOL Rig_Poll(); +BOOL Rig_Poll(); +VOID CheckWL2KReportTimer(); +VOID TNCTimer(); +VOID SendLocation(); +int ChatPollStreams(); +void ChatTrytoSend(); +VOID BBSSlowTimer(); +int GetHTMLForms(); +char * AddUser(char * Call, char * password, BOOL BBSFlag); +VOID SaveChatConfigFile(char * ConfigName); +VOID SaveMH(); +int upnpClose(); +void SaveAIS(); +void initAIS(); +void DRATSPoll(); +void RHPPoll(); + +VOID GetPGConfig(); +void SendBBSDataToPktMap(); + +extern uint64_t timeLoadedMS; + +BOOL IncludesMail = FALSE; +BOOL IncludesChat = FALSE; + +BOOL RunMail = FALSE; +BOOL RunChat = FALSE; +BOOL needAIS= FALSE; +BOOL needADSB = FALSE; + +int CloseOnError = 0; + +VOID Poll_AGW(); +BOOL AGWAPIInit(); +int AGWAPITerminate(); + +BOOL AGWActive = FALSE; + +extern int AGWPort; + +BOOL RigActive = FALSE; + +extern ULONG ChatApplMask; +extern char Verstring[]; + +extern char SignoffMsg[]; +extern char AbortedMsg[]; +extern char InfoBoxText[]; // Text to display in Config Info Popup + +extern int LastVer[4]; // In case we need to do somthing the first time a version is run + +extern HWND MainWnd; +extern char BaseDir[]; +extern char BaseDirRaw[]; +extern char MailDir[]; +extern char WPDatabasePath[]; +extern char RlineVer[50]; + +extern BOOL LogBBS; +extern BOOL LogCHAT; +extern BOOL LogTCP; +extern BOOL ForwardToMe; + +extern int LatestMsg; +extern char BBSName[]; +extern char SYSOPCall[]; +extern char BBSSID[]; +extern char NewUserPrompt[]; + +extern int NumberofStreams; +extern int MaxStreams; +extern ULONG BBSApplMask; +extern int BBSApplNum; +extern int ChatApplNum; +extern int MaxChatStreams; + +extern int NUMBEROFTNCPORTS; + +extern int EnableUI; + +extern BOOL AUTOSAVEMH; + +extern FILE * LogHandle[4]; + +#define MaxSockets 64 + +extern ConnectionInfo Connections[MaxSockets+1]; + +time_t LastTrafficTime; +extern int MaintTime; + +#define LOG_BBS 0 +#define LOG_CHAT 1 +#define LOG_TCP 2 +#define LOG_DEBUG_X 3 + +int _MYTIMEZONE = 0; + +// flags equates + +#define F_Excluded 0x0001 +#define F_LOC 0x0002 +#define F_Expert 0x0004 +#define F_SYSOP 0x0008 +#define F_BBS 0x0010 +#define F_PAG 0x0020 +#define F_GST 0x0040 +#define F_MOD 0x0080 +#define F_PRV 0x0100 +#define F_UNP 0x0200 +#define F_NEW 0x0400 +#define F_PMS 0x0800 +#define F_EMAIL 0x1000 +#define F_HOLDMAIL 0x2000 +#define F_POLLRMS 0x4000 +#define F_SYSOP_IN_LM 0x8000 +#define F_Temp_B2_BBS 0x00010000 + +/* #define F_PWD 0x1000 */ + + +extern UCHAR BPQDirectory[260]; +extern UCHAR LogDirectory[260]; +extern UCHAR ConfigDirectory[260]; + +// overrides from params +UCHAR LogDir[260] = ""; +UCHAR ConfigDir[260] = ""; +UCHAR DataDir[260] = ""; + + +BOOL GetConfig(char * ConfigName); +VOID DecryptPass(char * Encrypt, unsigned char * Pass, unsigned int len); +int EncryptPass(char * Pass, char * Encrypt); +int APIENTRY FindFreeStream(); +int PollStreams(); +int APIENTRY SetAppl(int stream, int flags, int mask); +int APIENTRY SessionState(int stream, int * state, int * change); +int APIENTRY SessionControl(int stream, int command, int Mask); + +BOOL ChatInit(); +VOID CloseChat(); +VOID CloseTNCEmulator(); + +static config_t cfg; +static config_setting_t * group; + +BOOL MonBBS = TRUE; +BOOL MonCHAT = TRUE; +BOOL MonTCP = TRUE; + +BOOL LogBBS = TRUE; +BOOL LogCHAT = TRUE; +BOOL LogTCP = TRUE; + +extern BOOL LogAPRSIS; + +BOOL UIEnabled[33]; +BOOL UINull[33]; +char * UIDigi[33]; + +extern struct UserInfo ** UserRecPtr; +extern int NumberofUsers; + +extern struct UserInfo * BBSChain; // Chain of users that are BBSes + +extern struct MsgInfo ** MsgHddrPtr; +extern int NumberofMessages; + +extern int FirstMessageIndextoForward; // Lowest Message wirh a forward bit set - limits search + +extern char UserDatabaseName[MAX_PATH]; +extern char UserDatabasePath[MAX_PATH]; + +extern char MsgDatabasePath[MAX_PATH]; +extern char MsgDatabaseName[MAX_PATH]; + +extern char BIDDatabasePath[MAX_PATH]; +extern char BIDDatabaseName[MAX_PATH]; + +extern char WPDatabasePath[MAX_PATH]; +extern char WPDatabaseName[MAX_PATH]; + +extern char BadWordsPath[MAX_PATH]; +extern char BadWordsName[MAX_PATH]; + +extern char NTSAliasesPath[MAX_PATH]; +extern char NTSAliasesName[MAX_PATH]; + +extern char BaseDir[MAX_PATH]; +extern char BaseDirRaw[MAX_PATH]; // As set in registry - may contain %NAME% +extern char ProperBaseDir[MAX_PATH]; // BPQ Directory/BPQMailChat + +extern char MailDir[MAX_PATH]; + +extern time_t MaintClock; // Time to run housekeeping + +#ifdef WIN32 +BOOL KEEPGOING = 30; // 5 secs to shut down +#else +BOOL KEEPGOING = 50; // 5 secs to shut down +#endif +BOOL Restarting = FALSE; +BOOL CLOSING = FALSE; + +int ProgramErrors; +int Slowtimer = 0; + +#define REPORTINTERVAL 15 * 549; // Magic Ticks Per Minute for PC's nominal 100 ms timer +int ReportTimer = 0; + +// Console Terminal Support + +struct ConTermS +{ + int BPQStream; + BOOL Active; + int Incoming; + + char kbbuf[INPUTLEN]; + int kbptr; + + char * KbdStack[MAXSTACK]; + int StackIndex; + + BOOL CONNECTED; + int SlowTimer; +}; + +struct ConTermS ConTerm = {0, 0}; + + +VOID CheckProgramErrors() +{ + if (Restarting) + exit(0); // Make sure can't loop in restarting + + ProgramErrors++; + + if (ProgramErrors > 25) + { + Restarting = TRUE; + + Logprintf(LOG_DEBUG_X, NULL, '!', "Too Many Program Errors - Closing"); + +/* + SInfo.cb=sizeof(SInfo); + SInfo.lpReserved=NULL; + SInfo.lpDesktop=NULL; + SInfo.lpTitle=NULL; + SInfo.dwFlags=0; + SInfo.cbReserved2=0; + SInfo.lpReserved2=NULL; + + GetModuleFileName(NULL, ProgName, 256); + + Debugprintf("Attempting to Restart %s", ProgName); + + CreateProcess(ProgName, "MailChat.exe WAIT", NULL, NULL, FALSE, 0, NULL, NULL, &SInfo, &PInfo); +*/ + exit(0); + } +} + +#ifdef WIN32 + +BOOL CtrlHandler(DWORD fdwCtrlType) +{ + switch( fdwCtrlType ) + { + // Handle the CTRL-C signal. + case CTRL_C_EVENT: + printf( "Ctrl-C event\n\n" ); + CLOSING = TRUE; + Beep( 750, 300 ); + return( TRUE ); + + // CTRL-CLOSE: confirm that the user wants to exit. + case CTRL_CLOSE_EVENT: + + CLOSING = TRUE; + printf( "Ctrl-Close event\n\n" ); + Sleep(20000); + Beep( 750, 300 ); + return( TRUE ); + + // Pass other signals to the next handler. + case CTRL_BREAK_EVENT: + Beep( 900, 200 ); + printf( "Ctrl-Break event\n\n" ); + CLOSING = TRUE; + Beep( 750, 300 ); + return FALSE; + + case CTRL_LOGOFF_EVENT: + Beep( 1000, 200 ); + printf( "Ctrl-Logoff event\n\n" ); + return FALSE; + + case CTRL_SHUTDOWN_EVENT: + Beep( 750, 500 ); + printf( "Ctrl-Shutdown event\n\n" ); + CLOSING = TRUE; + Beep( 750, 300 ); + return FALSE; + + default: + return FALSE; + } +} + +#else + +#include +#include + +// Linux Signal Handlers + +static void segvhandler(int sig) +{ + void *array[10]; + size_t size; + char msg[] = "SIGSEGV Received\n"; + + write(STDERR_FILENO, msg, strlen(msg)); + + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + // print out all the frames to stderr + + backtrace_symbols_fd(array, size, STDERR_FILENO); + + exit(1); +} + +static void abrthandler(int sig) +{ + void *array[10]; + size_t size; + char msg[] = "SIGABRT Received\n"; + + write(STDERR_FILENO, msg, strlen(msg)); + + // get void*'s for all entries on the stack + + size = backtrace(array, 10); + backtrace_symbols_fd(array, size, STDERR_FILENO); + + exit(1); +} + +static void sigterm_handler(int sig) +{ + syslog(LOG_INFO, "terminating on SIGTERM\n"); + CLOSING = TRUE; +} + +static void sigint_handler(int sig) +{ + printf("terminating on SIGINT\n"); + CLOSING = TRUE; +} + + +static void sigusr1_handler(int sig) +{ + signal(SIGUSR1, sigusr1_handler); +} + +#endif + + +#ifndef WIN32 + +BOOL CopyFile(char * In, char * Out, BOOL Failifexists) +{ + FILE * Handle; + DWORD FileSize; + char * Buffer; + struct stat STAT; + + if (stat(In, &STAT) == -1) + return FALSE; + + FileSize = STAT.st_size; + + Handle = fopen(In, "rb"); + + if (Handle == NULL) + return FALSE; + + Buffer = malloc(FileSize+1); + + FileSize = fread(Buffer, 1, STAT.st_size, Handle); + + fclose(Handle); + + if (FileSize != STAT.st_size) + { + free(Buffer); + return FALSE; + } + + Handle = fopen(Out, "wb"); + + if (Handle == NULL) + { + free(Buffer); + return FALSE; + } + + FileSize = fwrite(Buffer, 1, STAT.st_size, Handle); + + fclose(Handle); + free(Buffer); + + return TRUE; +} +#endif + +int RefreshMainWindow() +{ + return 0; +} + +int LastSemGets = 0; + +extern int SemHeldByAPI; + +VOID MonitorThread(void * x) +{ + // Thread to detect stuck semaphore + + do + { + if ((Semaphore.Gets == LastSemGets) && Semaphore.Flag) + { + // It is stuck - try to release + + Debugprintf ("Semaphore locked - Process ID = %d, Held By %d from %s Line %d", + Semaphore.SemProcessID, SemHeldByAPI, Semaphore.File, Semaphore.Line); + + + Semaphore.Flag = 0; + } + + LastSemGets = Semaphore.Gets; + + Sleep(30000); +// Debugprintf("Monitor Thread Still going %d %d %d %x %d", LastSemGets, Semaphore.Gets, Semaphore.Flag, Semaphore.SemThreadID, SemHeldByAPI); + + } + while (TRUE); +} + + + + +VOID TIMERINTERRUPT(); + +BOOL Start(); +VOID INITIALISEPORTS(); +Dll BOOL APIENTRY Init_APRS(); +VOID APRSClose(); +Dll VOID APIENTRY Poll_APRS(); +VOID HTTPTimer(); + + +#define CKernel +#include "Versions.h" + +extern struct SEM Semaphore; + +int SemHeldByAPI = 0; +BOOL IGateEnabled = TRUE; +BOOL APRSActive = FALSE; +BOOL ReconfigFlag = FALSE; +BOOL APRSReconfigFlag = FALSE; +BOOL RigReconfigFlag = FALSE; + +BOOL IPActive = FALSE; +extern BOOL IPRequired; + +extern struct WL2KInfo * WL2KReports; + +int InitDone; +char pgm[256] = "LINBPQ"; + +char SESSIONHDDR[80] = ""; +int SESSHDDRLEN = 0; + + +// Next 3 should be uninitialised so they are local to each process + +UCHAR MCOM; +UCHAR MUIONLY; +UCHAR MTX; +uint64_t MMASK; + + +UCHAR AuthorisedProgram; // Local Variable. Set if Program is on secure list + +int SAVEPORT = 0; + +VOID SetApplPorts(); + +char VersionString[50] = Verstring; +char VersionStringWithBuild[50]=Verstring; +int Ver[4] = {Vers}; +char TextVerstring[50] = Verstring; + +extern UCHAR PWLen; +extern char PWTEXT[]; +extern int ISPort; + +extern char ChatConfigName[250]; + +BOOL EventsEnabled = 0; + +UCHAR * GetBPQDirectory() +{ + return BPQDirectory; +} +UCHAR * GetLogDirectory() +{ + return LogDirectory; +} +extern int POP3Timer; + +// Console Terminal Stuff + +#ifndef WIN32 + + + +#define _getch getchar + +/** + Linux (POSIX) implementation of _kbhit(). + Morgan McGuire, morgan@cs.brown.edu + */ + +#include +#include +#include + +int _kbhit() { + static const int STDIN = 0; + static int initialized = 0; + + if (! initialized) { + // Use termios to turn off line buffering + struct termios term; + tcgetattr(STDIN, &term); + term.c_lflag &= ~ICANON; + + tcsetattr(STDIN, TCSANOW, &term); + setbuf(stdin, NULL); + initialized = 1; + } + + int bytesWaiting; + ioctl(STDIN, FIONREAD, &bytesWaiting); + return bytesWaiting; +} + +#endif + +void ConTermInput(char * Msg) +{ + int i; + + if (ConTerm.BPQStream == 0) + { + ConTerm.BPQStream = FindFreeStream(); + + if (ConTerm.BPQStream == 255) + { + ConTerm.BPQStream = 0; + printf("No Free Streams\n"); + return; + } + } + + if (!ConTerm.CONNECTED) + SessionControl(ConTerm.BPQStream, 1, 0); + + ConTerm.StackIndex = 0; + + // Stack it + + if (ConTerm.KbdStack[19]) + free(ConTerm.KbdStack[19]); + + for (i = 18; i >= 0; i--) + { + ConTerm.KbdStack[i+1] = ConTerm.KbdStack[i]; + } + + ConTerm.KbdStack[0] = _strdup(ConTerm.kbbuf); + + ConTerm.kbbuf[ConTerm.kbptr]=13; + + SendMsg(ConTerm.BPQStream, ConTerm.kbbuf, ConTerm.kbptr+1); +} + +void ConTermPoll() +{ + int port, sesstype, paclen, maxframe, l4window, len; + int state, change, InputLen, count; + char callsign[11] = ""; + char Msg[300]; + + // Get current Session State. Any state changed is ACK'ed + // automatically. See BPQHOST functions 4 and 5. + + SessionState(ConTerm.BPQStream, &state, &change); + + if (change == 1) + { + if (state == 1) + { + // Connected + + ConTerm.CONNECTED = TRUE; + ConTerm.SlowTimer = 0; + } + else + { + ConTerm.CONNECTED = FALSE; + printf("*** Disconnected\n"); + } + } + + GetMsg(ConTerm.BPQStream, Msg, &InputLen, &count); + + if (InputLen) + { + char * ptr = Msg; + char * ptr2 = ptr; + Msg[InputLen] = 0; + + while (ptr) + { + ptr2 = strlop(ptr, 13); + + // Replace CR with CRLF + + printf("%s", ptr); + + if (ptr2) + printf("\r\n"); + + ptr = ptr2; + } + } + + if (_kbhit()) + { + unsigned char c = _getch(); + + if (c == 0xe0) + { + // Cursor control + + c = _getch(); + + if (c == 75) // cursor left + c = 8; + } + +#ifdef WIN32 + printf("%c", c); +#endif + if (c == 8) + { + if (ConTerm.kbptr) + ConTerm.kbptr--; + printf(" \b"); // Already echoed bs - clear typed char from screen + return; + } + + if (c == 13 || c == 10) + { + ConTermInput(ConTerm.kbbuf); + ConTerm.kbptr = 0; + return; + } + + ConTerm.kbbuf[ConTerm.kbptr++] = c; + fflush(NULL); + + } + + return; + +} + +#include + +static struct option long_options[] = +{ + {"logdir", required_argument, 0 , 'l'}, + {"configdir", required_argument, 0 , 'c'}, + {"datadir", required_argument, 0 , 'd'}, + {"help", no_argument, 0 , 'h'}, + { NULL , no_argument , NULL , no_argument } +}; + +char HelpScreen[] = + "Usage:\n" + "Optional Paramters\n" + "-l path or --logdir path Path for log files\n" + "-c path or --configdir path Path to Config file bpq32.cfg\n" + "-d path or --datadir path Path to Data Files\n" + "-v Show version and exit\n"; + +int Redirected = 0; + +static void segvhandler(int sig); +static void abrthandler(int sig); + + +int main(int argc, char * argv[]) +{ + int i; + struct UserInfo * user = NULL; + ConnectionInfo * conn; + struct stat STAT; + PEXTPORTDATA PORTVEC; + +#ifdef WIN32 + + WSADATA WsaData; // receives data from WSAStartup + HWND hWnd = GetForegroundWindow(); + + WSAStartup(MAKEWORD(2, 0), &WsaData); + SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); + + // disable the [x] button. + + if (hWnd != NULL) + { + HMENU hMenu = GetSystemMenu(hWnd, 0); + if (hMenu != NULL) + { + DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND); + DrawMenuBar(hWnd); + } + } + +#else + + signal(SIGSEGV, segvhandler); + signal(SIGABRT, abrthandler); + + setlinebuf(stdout); + struct sigaction act; + openlog("LINBPQ", LOG_PID, LOG_DAEMON); +#ifndef MACBPQ +#ifndef FREEBSD + prctl(PR_SET_DUMPABLE, 1); // Enable Core Dumps even with setcap +#endif +#endif + + // Disable Console Terminal if stdout redirected + +// printf("STDOUT %d\n",isatty(STDOUT_FILENO)); +// printf("STDIN %d\n",isatty(STDIN_FILENO)); + + if (!isatty(STDOUT_FILENO) || !isatty(STDIN_FILENO)) + Redirected = 1; + + timeLoadedMS = GetTickCount(); + +#endif + + printf("G8BPQ AX25 Packet Switch System Version %s %s\n", TextVerstring, Datestring); + printf("%s\n", VerCopyright); + + + // look for optarg format parameters + + { + int val; + UCHAR * ptr1; + UCHAR * ptr2; + int c; + + while (1) + { + int option_index = 0; + + c = getopt_long(argc, argv, "l:c:d:hv", long_options, &option_index); + + // Check for end of operation or error + + if (c == -1) + break; + + // Handle options + switch (c) + { + case 'h': + + printf("%s", HelpScreen); + exit (0); + + case 'l': + strcpy(LogDir, optarg); + printf("cc %s\n", LogDir); + break; + + case 'c': + strcpy(ConfigDir, optarg); + break; + + case 'd': + strcpy(DataDir, optarg); + break; + + + case '?': + /* getopt_long already printed an error message. */ + break; + + case 'v': + return 0; + } + } + } + + sprintf(RlineVer, "LinBPQ%d.%d.%d", Ver[0], Ver[1], Ver[2]); + + + Debugprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring); + +#ifndef MACBPQ + _MYTIMEZONE = _timezone; +#endif + + if (_MYTIMEZONE < -86400 || _MYTIMEZONE > 86400) + _MYTIMEZONE = 0; + +#ifdef WIN32 + GetCurrentDirectory(256, BPQDirectory); +#else + getcwd(BPQDirectory, 256); +#endif + + strcpy(ConfigDirectory, BPQDirectory); + strcpy(LogDirectory, BPQDirectory); + + Consoleprintf("Current Directory is %s", BPQDirectory); + + if (LogDir[0]) + { + strcpy(LogDirectory, LogDir); + } + if (DataDir[0]) + { + strcpy(BPQDirectory, DataDir); + Consoleprintf("Working Directory is %s", BPQDirectory); + } + if (ConfigDir[0]) + { + strcpy(ConfigDirectory, ConfigDir); + Consoleprintf("Config Directory is %s", ConfigDirectory); + } + + for (i = optind; i < argc; i++) + { + if (_memicmp(argv[i], "logdir=", 7) == 0) + { + strcpy(LogDirectory, &argv[i][7]); + Consoleprintf("Log Directory is %s\n", LogDirectory); + break; + } + } + + Consoleprintf("Log Directory is %s", LogDirectory); + + // Make sure logs directory exists + + sprintf(LogDir, "%s/logs", LogDirectory); + +#ifdef WIN32 + CreateDirectory(LogDir, NULL); +#else + printf("Making Directory %s\n", LogDir); + i = mkdir(LogDir, S_IRWXU | S_IRWXG | S_IRWXO); + if (i == -1 && errno != EEXIST) + { + perror("Couldn't create log directory\n"); + return 0; + } + chmod(LogDir, S_IRWXU | S_IRWXG | S_IRWXO); +#endif + + if (!ProcessConfig()) + { + WritetoConsoleLocal("Configuration File Error\n"); + return (0); + } + + SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for Linux (", TextVerstring); + +#ifdef MACBPQ + SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for MAC (", TextVerstring); +#endif +#ifdef FREEBSD + SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for FreeBSD (", TextVerstring); +#endif + + + GetSemaphore(&Semaphore, 0); + + if (Start() != 0) + { + FreeSemaphore(&Semaphore); + return (0); + } + + for (i=0;PWTEXT[i] > 0x20;i++); //Scan for cr or null + + PWLen=i; + + SetApplPorts(); + + GetUIConfig(); + + INITIALISEPORTS(); + + if (IPRequired) IPActive = Init_IP(); + + APRSActive = Init_APRS(); + + if (ISPort == 0) + IGateEnabled = 0; + + if (needAIS) + initAIS(); + + RigActive = Rig_Init(); + + FreeSemaphore(&Semaphore); + + OpenReportingSockets(); + + initUTF8(); + + InitDone = TRUE; + + Debugprintf("Monitor Thread ID %x", _beginthread(MonitorThread, 0, 0)); + + +#ifdef WIN32 +#else + openlog("LINBPQ", LOG_PID, LOG_DAEMON); + + memset (&act, '\0', sizeof(act)); + + act.sa_handler = &sigint_handler; + if (sigaction(SIGINT, &act, NULL) < 0) + perror ("SIGINT"); + + act.sa_handler = &sigterm_handler; + if (sigaction(SIGTERM, &act, NULL) < 0) + perror ("sigaction"); + + act.sa_handler = SIG_IGN; + if (sigaction(SIGHUP, &act, NULL) < 0) + perror ("SIGHUP"); + + if (sigaction(SIGPIPE, &act, NULL) < 0) + perror ("SIGPIPE"); + +#endif + + for (i = optind; i < argc; i++) + { + if (_stricmp(argv[i], "chat") == 0) + IncludesChat = TRUE; + } + + if (IncludesChat) + { + RunChat = TRUE; + + printf("Starting Chat\n"); + + sprintf (ChatConfigName, "%s/chatconfig.cfg", BPQDirectory); + printf("Config File is %s\n", ChatConfigName); + + if (stat(ChatConfigName, &STAT) == -1) + { + printf("Chat Config File not found - creating a default config\n"); + ChatApplNum = 2; + MaxChatStreams = 10; + SaveChatConfigFile(ChatConfigName); + } + + if (GetChatConfig(ChatConfigName) == EXIT_FAILURE) + { + printf("Chat Config File seems corrupt - check before continuing\n"); + return -1; + } + + if (ChatApplNum) + { + if (ChatInit() == 0) + { + printf("Chat Init Failed\n"); + RunChat = 0; + } + else + { + printf("Chat Started\n"); + } + } + else + { + printf("Chat APPLNUM not defined\n"); + RunChat = 0; + } + CopyConfigFile(ChatConfigName); + } + + // Start Mail if requested by command line or config + + for (i = optind; i < argc; i++) + { + if (_stricmp(argv[i], "mail") == 0) + IncludesMail = TRUE; + } + + + if (IncludesMail) + { + RunMail = TRUE; + + printf("Starting Mail\n"); + + sprintf (ConfigName, "%s/linmail.cfg", BPQDirectory); + printf("Config File is %s\n", ConfigName); + + if (stat(ConfigName, &STAT) == -1) + { + printf("Config File not found - creating a default config\n"); + strcpy(BBSName, MYNODECALL); + strlop(BBSName, '-'); + strlop(BBSName, ' '); + BBSApplNum = 1; + MaxStreams = 10; + SaveConfig(ConfigName); + } + + if (GetConfig(ConfigName) == EXIT_FAILURE) + { + printf("BBS Config File seems corrupt - check before continuing\n"); + return -1; + } + + printf("Config Processed\n"); + + BBSApplMask = 1<<(BBSApplNum-1); + + // See if we need to warn of possible problem with BaseDir moved by installer + + sprintf(BaseDir, "%s", BPQDirectory); + + + // Set up file and directory names + + strcpy(UserDatabasePath, BaseDir); + strcat(UserDatabasePath, "/"); + strcat(UserDatabasePath, UserDatabaseName); + + strcpy(MsgDatabasePath, BaseDir); + strcat(MsgDatabasePath, "/"); + strcat(MsgDatabasePath, MsgDatabaseName); + + strcpy(BIDDatabasePath, BaseDir); + strcat(BIDDatabasePath, "/"); + strcat(BIDDatabasePath, BIDDatabaseName); + + strcpy(WPDatabasePath, BaseDir); + strcat(WPDatabasePath, "/"); + strcat(WPDatabasePath, WPDatabaseName); + + strcpy(BadWordsPath, BaseDir); + strcat(BadWordsPath, "/"); + strcat(BadWordsPath, BadWordsName); + + strcpy(NTSAliasesPath, BaseDir); + strcat(NTSAliasesPath, "/"); + strcat(NTSAliasesPath, NTSAliasesName); + + strcpy(MailDir, BaseDir); + strcat(MailDir, "/"); + strcat(MailDir, "Mail"); + +#ifdef WIN32 + CreateDirectory(MailDir, NULL); // Just in case +#else + mkdir(MailDir, S_IRWXU | S_IRWXG | S_IRWXO); + chmod(MailDir, S_IRWXU | S_IRWXG | S_IRWXO); +#endif + + // Make backup copies of Databases + + // CopyConfigFile(ConfigName); + + CopyBIDDatabase(); + CopyMessageDatabase(); + CopyUserDatabase(); + CopyWPDatabase(); + + SetupMyHA(); + SetupFwdAliases(); + SetupNTSAliases(NTSAliasesPath); + + GetWPDatabase(); + + GetMessageDatabase(); + GetUserDatabase(); + GetBIDDatabase(); + GetBadWordFile(); + GetHTMLForms(); + GetPGConfig(); + + // Make sure there is a user record for the BBS, with BBS bit set. + + user = LookupCall(BBSName); + + if (user == NULL) + { + user = AllocateUserRecord(BBSName); + user->Temp = zalloc(sizeof (struct TempUserInfo)); + } + + if ((user->flags & F_BBS) == 0) + { + // Not Defined as a BBS + + if(SetupNewBBS(user)) + user->flags |= F_BBS; + } + + // if forwarding AMPR mail make sure User/BBS AMPR exists + + if (SendAMPRDirect) + { + BOOL NeedSave = FALSE; + + user = LookupCall("AMPR"); + + if (user == NULL) + { + user = AllocateUserRecord("AMPR"); + user->Temp = zalloc(sizeof (struct TempUserInfo)); + NeedSave = TRUE; + } + + if ((user->flags & F_BBS) == 0) + { + // Not Defined as a BBS + + if (SetupNewBBS(user)) + user->flags |= F_BBS; + NeedSave = TRUE; + } + + if (NeedSave) + SaveUserDatabase(); + } + + + // Make sure SYSOPCALL is set + + if (SYSOPCall[0] == 0) + strcpy(SYSOPCall, BBSName); + + // See if just want to add user (mainly for setup scripts) + + if (argc == 5 && _stricmp(argv[1], "--adduser") == 0) + { + BOOL isBBS = FALSE; + char * response; + + if (_stricmp(argv[4], "TRUE") == 0) + isBBS = TRUE; + + printf("Adding User %s\r\n", argv[2]); + response = AddUser(argv[2], argv[3], isBBS); + printf("%s", response); + exit(0); + } + // Allocate Streams + + strcpy(pgm, "BBS"); + + for (i=0; i < MaxStreams; i++) + { + conn = &Connections[i]; + conn->BPQStream = FindFreeStream(); + + if (conn->BPQStream == 255) break; + + NumberofStreams++; + + // BPQSetHandle(conn->BPQStream, hWnd); + + SetAppl(conn->BPQStream, (i == 0 && EnableUI) ? 0x82 : 2, BBSApplMask); + Disconnect(conn->BPQStream); + } + + strcpy(pgm, "LINBPQ"); + + InitialiseTCP(); + InitialiseNNTP(); + + SetupListenSet(); // Master set of listening sockets + + if (EnableUI || MailForInterval) + SetupUIInterface(); + + if (MailForInterval) + _beginthread(SendMailForThread, 0, 0); + + + // Calulate time to run Housekeeping + { + struct tm *tm; + time_t now; + + now = time(NULL); + + tm = gmtime(&now); + + tm->tm_hour = MaintTime / 100; + tm->tm_min = MaintTime % 100; + tm->tm_sec = 0; + + MaintClock = mktime(tm) - (time_t)_MYTIMEZONE; + + while (MaintClock < now) + MaintClock += MaintInterval * 3600; + + Debugprintf("Maint Clock %lld NOW %lld Time to HouseKeeping %lld", (long long)MaintClock, (long long)now, (long long)(MaintClock - now)); + + if (LastHouseKeepingTime) + { + if ((now - LastHouseKeepingTime) > MaintInterval * 3600) + { + DoHouseKeeping(FALSE); + } + } + for (i = optind; i < argc; i++) + + { + if (_stricmp(argv[i], "tidymail") == 0) + DeleteRedundantMessages(); + + if (_stricmp(argv[i], "nohomebbs") == 0) + DontNeedHomeBBS = TRUE; + } + + printf("Mail Started\n"); + Logprintf(LOG_BBS, NULL, '!', "Mail Starting"); + + APIClock = 0; + + SendBBSDataToPktMap(); + + } + } + + if (NUMBEROFTNCPORTS) + InitializeTNCEmulator(); + + AGWActive = AGWAPIInit(); + + if (Redirected == 0) + ConTerm.BPQStream = FindFreeStream(); + + +#ifndef WIN32 + + for (i = 1; i < argc; i++) + { + if (_stricmp(argv[i], "daemon") == 0) + { + + // Convert to daemon + + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + + if (pid < 0) + exit(EXIT_FAILURE); + + if (pid > 0) + exit(EXIT_SUCCESS); + + /* Change the file mode mask */ + + umask(0); + + /* Create a new SID for the child process */ + + sid = setsid(); + + if (sid < 0) + exit(EXIT_FAILURE); + + /* Change the current working directory */ + + if ((chdir("/")) < 0) + exit(EXIT_FAILURE); + + /* Close out the standard file descriptors */ + + printf("Entering daemon mode\n"); + + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + break; + } + } +#endif + + while (KEEPGOING) + { + Sleep(100); + GetSemaphore(&Semaphore, 2); + + if (QCOUNT < 10) + { + if (CLOSING == FALSE) + FindLostBuffers(); + CLOSING = TRUE; + } + + if (CLOSING) + { + if (RunChat) + { + CloseChat(); + RunChat = FALSE; + } + + if (RunMail) + { + int BPQStream, n; + + RunMail = FALSE; + + for (n = 0; n < NumberofStreams; n++) + { + BPQStream = Connections[n].BPQStream; + + if (BPQStream) + { + SetAppl(BPQStream, 0, 0); + Disconnect(BPQStream); + DeallocateStream(BPQStream); + } + } + +// SaveUserDatabase(); + SaveMessageDatabase(); + SaveBIDDatabase(); + SaveConfig(ConfigName); + } + + KEEPGOING--; // Give time for links to close + setbuf(stdout, NULL); + printf("Closing... %d \r", KEEPGOING); + } + + + if (RigReconfigFlag) + { + RigReconfigFlag = FALSE; + Rig_Close(); + Sleep(2000); // Allow CATPTT threads to close + RigActive = Rig_Init(); + + Consoleprintf("Rigcontrol Reconfiguration Complete"); + } + + if (APRSReconfigFlag) + { + APRSReconfigFlag = FALSE; + APRSClose(); + APRSActive = Init_APRS(); + + Consoleprintf("APRS Reconfiguration Complete"); + } + + if (ReconfigFlag) + { + int i; + BPQVECSTRUC * HOSTVEC; + PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE; + + ReconfigFlag = FALSE; + +// SetupBPQDirectory(); + + WritetoConsoleLocal("Reconfiguring ...\n\n"); + OutputDebugString("BPQ32 Reconfiguring ...\n"); + + + for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External + { + if (PORTVEC->PORT_EXT_ADDR) + { +// SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); +// SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); +// CloseDriverWindow(PORTVEC->PORTCONTROL.PORTNUMBER); + PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL); // Close External Ports + } + } + PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL); + PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER; + } + + IPClose(); + APRSClose(); + Rig_Close(); + CloseTNCEmulator(); + + if (AGWActive) + AGWAPITerminate(); + + WL2KReports = NULL; + +// Sleep(2000); + + Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring); + Consoleprintf(VerCopyright); + + Start(); + + INITIALISEPORTS(); + + SetApplPorts(); + + GetUIConfig(); + + FreeConfig(); + + for (i=1; i<68; i++) // Include Telnet, APRS, IP Vec + { + HOSTVEC=&BPQHOSTVECTOR[i-1]; + + HOSTVEC->HOSTTRACEQ=0; + + if (HOSTVEC->HOSTSESSION !=0) + { + // Had a connection + + HOSTVEC->HOSTSESSION=0; + HOSTVEC->HOSTFLAGS |=3; // Disconnected + +// PostMessage(HOSTVEC->HOSTHANDLE, BPQMsg, i, 4); + } + } + + OpenReportingSockets(); + + WritetoConsoleLocal("\n\nReconfiguration Complete\n"); + + if (IPRequired) IPActive = Init_IP(); + + APRSActive = Init_APRS(); + + if (ISPort == 0) + IGateEnabled = 0; + + RigActive = Rig_Init(); + + if (NUMBEROFTNCPORTS) + { + FreeSemaphore(&Semaphore); + InitializeTNCEmulator(); + GetSemaphore(&Semaphore, 2); + } + + FreeSemaphore(&Semaphore); + AGWActive = AGWAPIInit(); + GetSemaphore(&Semaphore, 2); + + OutputDebugString("BPQ32 Reconfiguration Complete\n"); + } + + if (IPActive) Poll_IP(); + if (RigActive) Rig_Poll(); + if (APRSActive) Poll_APRS(); + CheckWL2KReportTimer(); + + TIMERINTERRUPT(); + + FreeSemaphore(&Semaphore); + + if (Redirected == 0) + ConTermPoll(); + + if (NUMBEROFTNCPORTS) + TNCTimer(); + + if (AGWActive) + Poll_AGW(); + + DRATSPoll(); + RHPPoll(); + + HTTPTimer(); + + if (ReportTimer) + { + ReportTimer--; + + if (ReportTimer == 0) + { + ReportTimer = REPORTINTERVAL; + SendLocation(); + } + } + + Slowtimer++; + + if (RunChat) + { + ChatPollStreams(); + ChatTrytoSend(); + + if (Slowtimer > 100) // 10 secs + { + ChatTimer(); + } + } + + if (RunMail) + { + PollStreams(); + + if ((Slowtimer % 20) == 0) + FWDTimerProc(); + + if (Slowtimer > 100) // 10 secs + { + time_t NOW = time(NULL); + struct tm * tm; + + TCPTimer(); + BBSSlowTimer(); + + if (MaintClock < NOW) + { + while (MaintClock < NOW) // in case large time step + MaintClock += MaintInterval * 3600; + + Debugprintf("|Enter HouseKeeping"); + DoHouseKeeping(FALSE); + } + + if (APIClock < NOW) + { + SendBBSDataToPktMap(); + APIClock = NOW + 7200; // Every 2 hours + } + + + tm = gmtime(&NOW); + + if (tm->tm_wday == 0) // Sunday + { + if (GenerateTrafficReport && (LastTrafficTime + 86400) < NOW) + { + CreateBBSTrafficReport(); + LastTrafficTime = NOW; + } + } + } + TCPFastTimer(); + TrytoSend(); + } + + if (Slowtimer > 100) + Slowtimer = 0; + } + + printf("Closing Ports\n"); + + CloseTNCEmulator(); + + if (AGWActive) + AGWAPITerminate(); + + if (needAIS) + SaveAIS(); + + // Close Ports + + PORTVEC=(PEXTPORTDATA)PORTTABLE; + + for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External + { + if (PORTVEC->PORT_EXT_ADDR) + { + PORTVEC->PORT_EXT_ADDR(5, PORTVEC->PORTCONTROL.PORTNUMBER, NULL); + } + } + PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER; + } + + if (AUTOSAVE) + SaveNodes(); + + if (AUTOSAVEMH) + SaveMH(); + + if (IPActive) + IPClose(); + + if (RunMail) + FreeWebMailMallocs(); + + upnpClose(); + + // Close any open logs + + for (i = 0; i < 4; i++) + { + if (LogHandle[i]) + fclose(LogHandle[i]); + } + + return 0; +} + +int APIENTRY WritetoConsole(char * buff) +{ + return WritetoConsoleLocal(buff); +} + +int WritetoConsoleLocal(char * buff) +{ + return printf("%s", buff); +} + +#ifdef WIN32 +void * VCOMExtInit(struct PORTCONTROL * PortEntry); +void * V4ExtInit(EXTPORTDATA * PortEntry); +#endif +//UINT SoundModemExtInit(EXTPORTDATA * PortEntry); +//UINT BaycomExtInit(EXTPORTDATA * PortEntry); + +void * AEAExtInit(struct PORTCONTROL * PortEntry); +void * MPSKExtInit(EXTPORTDATA * PortEntry); +void * HALExtInit(struct PORTCONTROL * PortEntry); + +void * AGWExtInit(struct PORTCONTROL * PortEntry); +void * KAMExtInit(struct PORTCONTROL * PortEntry); +void * WinmorExtInit(EXTPORTDATA * PortEntry); +void * SCSExtInit(struct PORTCONTROL * PortEntry); +void * TrackerExtInit(EXTPORTDATA * PortEntry); +void * TrackerMExtInit(EXTPORTDATA * PortEntry); + +void * TelnetExtInit(EXTPORTDATA * PortEntry); +void * UZ7HOExtInit(EXTPORTDATA * PortEntry); +void * FLDigiExtInit(EXTPORTDATA * PortEntry); +void * ETHERExtInit(struct PORTCONTROL * PortEntry); +void * AXIPExtInit(struct PORTCONTROL * PortEntry); +void * ARDOPExtInit(EXTPORTDATA * PortEntry); +void * VARAExtInit(EXTPORTDATA * PortEntry); +void * SerialExtInit(EXTPORTDATA * PortEntry); +void * WinRPRExtInit(EXTPORTDATA * PortEntry); +void * HSMODEMExtInit(EXTPORTDATA * PortEntry); +void * FreeDataExtInit(EXTPORTDATA * PortEntry); +void * KISSHFExtInit(EXTPORTDATA * PortEntry); + +void * InitializeExtDriver(PEXTPORTDATA PORTVEC) +{ + // Only works with built in drivers + + UCHAR Value[20]; + + strcpy(Value,PORTVEC->PORT_DLL_NAME); + + _strupr(Value); + +#ifndef FREEBSD +#ifndef MACBPQ + if (strstr(Value, "BPQETHER")) + return ETHERExtInit; +#endif +#endif + if (strstr(Value, "BPQAXIP")) + return AXIPExtInit; + + if (strstr(Value, "BPQTOAGW")) + return AGWExtInit; + + if (strstr(Value, "AEAPACTOR")) + return AEAExtInit; + + if (strstr(Value, "HALDRIVER")) + return HALExtInit; + +#ifdef WIN32 + + if (strstr(Value, "BPQVKISS")) + return VCOMExtInit; + + if (strstr(Value, "V4")) + return V4ExtInit; + +#endif +/* + if (strstr(Value, "SOUNDMODEM")) + return (UINT) SoundModemExtInit; + + if (strstr(Value, "BAYCOM")) + return (UINT) BaycomExtInit; +*/ + if (strstr(Value, "MULTIPSK")) + return MPSKExtInit; + + if (strstr(Value, "KAMPACTOR")) + return KAMExtInit; + + if (strstr(Value, "WINMOR")) + return WinmorExtInit; + + if (strstr(Value, "SCSPACTOR")) + return SCSExtInit; + + if (strstr(Value, "SCSTRACKER")) + return TrackerExtInit; + + if (strstr(Value, "TRKMULTI")) + return TrackerMExtInit; + + if (strstr(Value, "UZ7HO")) + return UZ7HOExtInit; + + if (strstr(Value, "FLDIGI")) + return FLDigiExtInit; + + if (strstr(Value, "TELNET")) + return TelnetExtInit; + + if (strstr(Value, "ARDOP")) + return ARDOPExtInit; + + if (strstr(Value, "VARA")) + return VARAExtInit; + + if (strstr(Value, "KISSHF")) + return KISSHFExtInit; + + if (strstr(Value, "SERIAL")) + return SerialExtInit; + + if (strstr(Value, "WINRPR")) + return WinRPRExtInit; + + if (strstr(Value, "HSMODEM")) + return HSMODEMExtInit; + + if (strstr(Value, "FREEDATA")) + return FreeDataExtInit; + + return(0); +} + +int APIENTRY Restart() +{ + CLOSING = TRUE; + return TRUE; +} + +int APIENTRY Reboot() +{ + // Run sudo shutdown -r -f +#ifdef WIN32 + STARTUPINFO SInfo; + PROCESS_INFORMATION PInfo; + char Cmd[] = "shutdown -r -f"; + + + SInfo.cb=sizeof(SInfo); + SInfo.lpReserved=NULL; + SInfo.lpDesktop=NULL; + SInfo.lpTitle=NULL; + SInfo.dwFlags=0; + SInfo.cbReserved2=0; + SInfo.lpReserved2=NULL; + + return CreateProcess(NULL, Cmd, NULL, NULL, FALSE,0 ,NULL ,NULL, &SInfo, &PInfo); + return 0; +#else + + char * arg_list[] = {NULL, NULL, NULL, NULL, NULL}; + pid_t child_pid; + char * Context; + signal(SIGCHLD, SIG_IGN); // Silently (and portably) reap children. + + arg_list[0] = "sudo"; + arg_list[1] = "shutdown"; + arg_list[2] = "now"; + arg_list[3] = "-r"; + + // Fork and Exec shutdown + + // Duplicate this process. + + child_pid = fork(); + + if (child_pid == -1) + { + printf ("Reboot fork() Failed\n"); + return 0; + } + + if (child_pid == 0) + { + execvp (arg_list[0], arg_list); + + /* The execvp function returns only if an error occurs. */ + + printf ("Failed to run shutdown\n"); + exit(0); // Kill the new process + } + return TRUE; +#endif + +} + +int APIENTRY Reconfig() +{ + if (!ProcessConfig()) + { + return (0); + } + SaveNodes(); + WritetoConsoleLocal("Nodes Saved\n"); + ReconfigFlag=TRUE; + WritetoConsoleLocal("Reconfig requested ... Waiting for Timer Poll\n"); + return 1; +} + +int APRSWriteLog(char * msg); + +VOID MonitorAPRSIS(char * Msg, size_t MsgLen, BOOL TX) +{ + char Line[300]; + char Copy[300]; + int Len; + struct tm * TM; + time_t NOW; + + if (LogAPRSIS == 0) + return; + + if (MsgLen > 250) + return; + + // Mustn't change Msg + + memcpy(Copy, Msg, MsgLen); + Copy[MsgLen] = 0; + + NOW = time(NULL); + TM = gmtime(&NOW); + + Len = sprintf_s(Line, 299, "%02d:%02d:%02d%c %s", TM->tm_hour, TM->tm_min, TM->tm_sec, (TX)? 'T': 'R', Copy); + + APRSWriteLog(Line); + +} + +struct TNCINFO * TNC; + +#ifndef WIN32 + +#include +#include + +#ifndef MACBPQ +#ifdef __MACH__ + +#include + +#define CLOCK_REALTIME 0 +#define CLOCK_MONOTONIC 0 + + + +int clock_gettime(int clk_id, struct timespec *t){ + mach_timebase_info_data_t timebase; + mach_timebase_info(&timebase); + uint64_t time; + time = mach_absolute_time(); + double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom); + double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9); + t->tv_sec = seconds; + t->tv_nsec = nseconds; + return 0; +} +#endif +#endif + + +uint64_t GetTickCount() +{ + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); +} + + + +void SetWindowText(HWND hWnd, char * lpString) +{ + return; +}; + +BOOL SetDlgItemText(HWND hWnd, int item, char * lpString) +{ + return 0; +}; + +#endif + +int GetListeningPortsPID(int Port) +{ +#ifdef WIN32 + + MIB_TCPTABLE_OWNER_PID * TcpTable = NULL; + PMIB_TCPROW_OWNER_PID Row; + int dwSize = 0; + unsigned int n; + + // Get PID of process for this TCP Port + + // Get Length of table + + GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0); + + TcpTable = malloc(dwSize); + GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0); + + for (n = 0; n < TcpTable->dwNumEntries; n++) + { + Row = &TcpTable->table[n]; + + if (Row->dwLocalPort == Port && Row->dwState == MIB_TCP_STATE_LISTEN) + { + return Row->dwOwningPid; + break; + } + } +#endif + return 0; // Not found +} + + + +VOID Check_Timer() +{ +} + +VOID POSTDATAAVAIL(){}; + +COLORREF Colours[256] = {0, + RGB(0,0,0), RGB(0,0,128), RGB(0,0,192), RGB(0,0,255), // 1 - 4 + RGB(0,64,0), RGB(0,64,128), RGB(0,64,192), RGB(0,64,255), // 5 - 8 + RGB(0,128,0), RGB(0,128,128), RGB(0,128,192), RGB(0,128,255), // 9 - 12 + RGB(0,192,0), RGB(0,192,128), RGB(0,192,192), RGB(0,192,255), // 13 - 16 + RGB(0,255,0), RGB(0,255,128), RGB(0,255,192), RGB(0,255,255), // 17 - 20 + + RGB(6425,0,0), RGB(64,0,128), RGB(64,0,192), RGB(0,0,255), // 21 + RGB(64,64,0), RGB(64,64,128), RGB(64,64,192), RGB(64,64,255), + RGB(64,128,0), RGB(64,128,128), RGB(64,128,192), RGB(64,128,255), + RGB(64,192,0), RGB(64,192,128), RGB(64,192,192), RGB(64,192,255), + RGB(64,255,0), RGB(64,255,128), RGB(64,255,192), RGB(64,255,255), + + RGB(128,0,0), RGB(128,0,128), RGB(128,0,192), RGB(128,0,255), // 41 + RGB(128,64,0), RGB(128,64,128), RGB(128,64,192), RGB(128,64,255), + RGB(128,128,0), RGB(128,128,128), RGB(128,128,192), RGB(128,128,255), + RGB(128,192,0), RGB(128,192,128), RGB(128,192,192), RGB(128,192,255), + RGB(128,255,0), RGB(128,255,128), RGB(128,255,192), RGB(128,255,255), + + RGB(192,0,0), RGB(192,0,128), RGB(192,0,192), RGB(192,0,255), // 61 + RGB(192,64,0), RGB(192,64,128), RGB(192,64,192), RGB(192,64,255), + RGB(192,128,0), RGB(192,128,128), RGB(192,128,192), RGB(192,128,255), + RGB(192,192,0), RGB(192,192,128), RGB(192,192,192), RGB(192,192,255), + RGB(192,255,0), RGB(192,255,128), RGB(192,255,192), RGB(192,255,255), + + RGB(255,0,0), RGB(255,0,128), RGB(255,0,192), RGB(255,0,255), // 81 + RGB(255,64,0), RGB(255,64,128), RGB(255,64,192), RGB(255,64,255), + RGB(255,128,0), RGB(255,128,128), RGB(255,128,192), RGB(255,128,255), + RGB(255,192,0), RGB(255,192,128), RGB(255,192,192), RGB(255,192,255), + RGB(255,255,0), RGB(255,255,128), RGB(255,255,192), RGB(255,255,255) +}; + + +//VOID SendRPBeacon(struct TNCINFO * TNC) +//{ +//} + +int PollStreams() +{ + int state,change; + ConnectionInfo * conn; + int n; + struct UserInfo * user = NULL; + char ConnectedMsg[] = "*** CONNECTED "; + + for (n = 0; n < NumberofStreams; n++) + { + conn = &Connections[n]; + + DoReceivedData(conn->BPQStream); + DoBBSMonitorData(conn->BPQStream); + + SessionState(conn->BPQStream, &state, &change); + + if (change == 1) + { + if (state == 1) // Connected + { + GetSemaphore(&ConSemaphore, 0); + Connected(conn->BPQStream); + FreeSemaphore(&ConSemaphore); + } + else + { + GetSemaphore(&ConSemaphore, 0); + Disconnected(conn->BPQStream); + FreeSemaphore(&ConSemaphore); + } + } + } + + return 0; +} + + +VOID CloseConsole(int Stream) +{ +} + +#ifndef WIN32 + +int V4ProcessReceivedData(struct TNCINFO * TNC) +{ + return 0; +} +#endif + +#ifdef FREEBSD + +char * gcvt(double _Val, int _NumOfDigits, char * _DstBuf) +{ + sprintf(_DstBuf, "%f", _Val); + return _DstBuf; +} + +#endif + + + + + diff --git a/LinBPQ.c b/LinBPQ.c index bd380e1..295afd8 100644 --- a/LinBPQ.c +++ b/LinBPQ.c @@ -21,7 +21,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #include "bpqmail.h" #ifdef WIN32 #include @@ -45,7 +45,11 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses BOOL APIENTRY Rig_Init(); -void GetSemaphore(struct SEM * Semaphore, int ID); + + +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) + +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); void FreeSemaphore(struct SEM * Semaphore); VOID CopyConfigFile(char * ConfigName); VOID SendMailForThread(VOID * Param); @@ -75,6 +79,8 @@ int upnpClose(); void SaveAIS(); void initAIS(); void DRATSPoll(); +void RHPPoll(); + VOID GetPGConfig(); void SendBBSDataToPktMap(); @@ -374,24 +380,41 @@ BOOL CtrlHandler(DWORD fdwCtrlType) #include #include - // Linux Signal Handlers - static void segvhandler(int sig) { - void *array[10]; - size_t size; + void *array[10]; + size_t size; + char msg[] = "SIGSEGV Received\n"; - // get void*'s for all entries on the stack - size = backtrace(array, 10); + write(STDERR_FILENO, msg, strlen(msg)); + + // get void*'s for all entries on the stack + size = backtrace(array, 10); + + // print out all the frames to stderr + + backtrace_symbols_fd(array, size, STDERR_FILENO); - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); exit(1); } +static void abrthandler(int sig) +{ + void *array[10]; + size_t size; + char msg[] = "SIGABRT Received\n"; + + write(STDERR_FILENO, msg, strlen(msg)); + + // get void*'s for all entries on the stack + + size = backtrace(array, 10); + backtrace_symbols_fd(array, size, STDERR_FILENO); + + exit(1); +} static void sigterm_handler(int sig) { @@ -481,9 +504,10 @@ VOID MonitorThread(void * x) { // It is stuck - try to release - Debugprintf ("Semaphore locked - Process ID = %d, Held By %d", - Semaphore.SemProcessID, SemHeldByAPI); - + Debugprintf ("Semaphore locked - Process ID = %d, Held By %d from %s Line %d", + Semaphore.SemProcessID, SemHeldByAPI, Semaphore.File, Semaphore.Line); + + Semaphore.Flag = 0; } @@ -761,6 +785,8 @@ char HelpScreen[] = int Redirected = 0; static void segvhandler(int sig); +static void abrthandler(int sig); + int main(int argc, char * argv[]) { @@ -792,7 +818,8 @@ int main(int argc, char * argv[]) #else -// signal(SIGSEGV, segvhandler); + signal(SIGSEGV, segvhandler); + signal(SIGABRT, abrthandler); setlinebuf(stdout); struct sigaction act; @@ -1560,6 +1587,7 @@ int main(int argc, char * argv[]) Poll_AGW(); DRATSPoll(); + RHPPoll(); HTTPTimer(); diff --git a/MULTIPSK.c b/MULTIPSK.c index ee14d9a..6f2a9ac 100644 --- a/MULTIPSK.c +++ b/MULTIPSK.c @@ -28,7 +28,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #include #include diff --git a/MailDataDefs.c b/MailDataDefs.c index abfbac2..5c33c08 100644 --- a/MailDataDefs.c +++ b/MailDataDefs.c @@ -133,7 +133,7 @@ char HRoute[100]; char AMPRDomain[100]; BOOL SendAMPRDirect = 0; -char SignoffMsg[100]; +char SignoffMsg[120]; char AbortedMsg[100]="\rOutput aborted\r"; diff --git a/Moncode.c b/Moncode.c index 928811c..c725d0f 100644 --- a/Moncode.c +++ b/Moncode.c @@ -31,7 +31,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #pragma data_seg("_BPQDATA") -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" // MSGFLAG contains CMD/RESPONSE BITS diff --git a/NNTPRoutines.c b/NNTPRoutines.c index d2efbbf..1ceea42 100644 --- a/NNTPRoutines.c +++ b/NNTPRoutines.c @@ -27,6 +27,9 @@ VOID __cdecl Debugprintf(const char * format, ...); VOID ReleaseSock(SOCKET sock); void MQTTMessageEvent(void* message); +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); + struct NNTPRec * FirstNNTPRec = NULL; //int NumberofNNTPRecs=0; diff --git a/PortMapper.c b/PortMapper.c index 7ec25fd..a4021bf 100644 --- a/PortMapper.c +++ b/PortMapper.c @@ -60,7 +60,7 @@ TODo ?Multiple Adapters #include #include -#include "CHeaders.h" +#include "cheaders.h" #include "ipcode.h" diff --git a/RHP-skigdebian.c b/RHP-skigdebian.c new file mode 100644 index 0000000..611e8c7 --- /dev/null +++ b/RHP-skigdebian.c @@ -0,0 +1,641 @@ +/* +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 +*/ + +/* + + Paula (G8PZT)'s Remote Host Protocol interface. + For now only sufficient support for WhatsPac + + +*/ +#define _CRT_SECURE_NO_DEPRECATE + +#include "cheaders.h" +#include "bpq32.h" + +int FindFreeStreamNoSem(); +DllExport int APIENTRY DeallocateStream(int stream); +int SendMsgNoSem(int stream, char * msg, int len); + +static void GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value, int Len); +static int GetJSONInt(char * _REPLYBUFFER, char * Name); + +// Generally Can have multiple RHP connections and each can have multiple RHF Sessions + +struct RHPSessionInfo +{ + SOCKET Socket; // Websocks Socket + int BPQStream; + int Handle; // RHP session ID + int Seq; + char Local[12]; + char Remote[12]; + BOOL Connecting; // Set while waiting for connection to complete + BOOL Listening; + BOOL Connected; +}; + +struct RHPConnectionInfo +{ + SOCKET socket; + struct RHPSessionInfo ** RHPSessions; + int NumberofRHPSessions; +}; + + +struct RHPConnectionInfo ** RHPSockets = NULL; +int NumberofRHPConnections = 0; + +struct RHPSessionInfo ** RHPSessions; +int NumberofRHPSessions; + +char ErrCodes[18][24] = +{"Ok", "Unspecified", "Bad or missing type", "Invalid handle", "No memory", "Bad or missing mode", + + "Invalid local address", + "Invalid remote address" , + "Bad or missing family" , + "Duplicate socket" , + "No such port" , + "Invalid protocol" , + "Bad parameter" , + "No buffers" , + "Unauthorised" , + "No Route" , + "Operation not supported"}; + + + + +extern char pgm[256]; + +SOCKET agwsock; + +extern int SemHeldByAPI; + +char szBuff[80]; + +int WhatsPacConfigured = 1; + + +int RHPPaclen = 236; + + +int processRHCPOpen(struct RHPConnectionInfo * RHPSocket, char * Msg, char * ReplyBuffer); +int processRHCPSend(struct RHPConnectionInfo * RHPSocket, char * Msg, char * ReplyBuffer); +int processRHCPClose(struct RHPConnectionInfo * RHPSocket, char * Msg, char * ReplyBuffer); + + + +void SendWebSockMessage(SOCKET socket, char * Msg, int Len) +{ + int Loops = 0; + int Sent; + int TxLen; + char * OutBuffer = Msg; + + // WebSock Encode. Buffer has 10 bytes on front for header but header len depends on Msg len + + + if (Len < 126) + { + // Two Byte Header + + OutBuffer[8] = 0x81; // Fin, Data + OutBuffer[9] = Len; + + TxLen = Len + 2; + OutBuffer = &Msg[8]; + } + else if (Len < 65536) + { + OutBuffer[6] = 0x81; // Fin, Data + OutBuffer[7] = 126; // Unmasked, Extended Len 16 + OutBuffer[8] = Len >> 8; + OutBuffer[9] = Len & 0xff; + TxLen = Len + 4; + OutBuffer = &Msg[6]; + } + else + { + OutBuffer[0] = 0x81; // Fin, Data + OutBuffer[1] = 127; // Unmasked, Extended Len 64 bits + // Len is 32 bits, so pad with zeros + OutBuffer[2] = 0; + OutBuffer[3] = 0; + OutBuffer[4] = 0; + OutBuffer[5] = 0; + OutBuffer[6] = (Len >> 24) & 0xff; + OutBuffer[7] = (Len >> 16) & 0xff; + OutBuffer[8] = (Len >> 8) & 0xff; + OutBuffer[9] = Len & 0xff; + + TxLen = Len + + 10; + OutBuffer = &Msg[0]; + } + + // Send may block + + Sent = send(socket, OutBuffer, TxLen, 0); + + while (Sent != TxLen && Loops++ < 3000) // 100 secs max + { + if (Sent > 0) // something sent + { + TxLen -= Sent; + memmove(OutBuffer, &OutBuffer[Sent], TxLen); + } + + Sleep(30); + Sent = send(socket, OutBuffer, TxLen, 0); + if (Sent == -1) + break; + } + + free(Msg); + return; +} + + + + +int RHPProcessHTTPMessage(struct ConnectionInfo * conn, char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE) +{ + // RHP messages can be sent over Websocks or normal http but I think WhatsPac only uses WebSocks + return 0; +} + + +void ProcessRHPWebSock(SOCKET socket, char * Msg, int MsgLen) +{ + int Loops = 0; + int InputLen = 0; + int Len; + + char Value[16]; + char * OutBuffer = malloc(250000); + + struct RHPConnectionInfo * RHPSocket = NULL; + int n; + + Msg[MsgLen] = 0; + + // Find Connection Record. If none, create one + + for (n = 0; n < NumberofRHPConnections; n++) + { + if (RHPSockets[n]->socket == socket) + { + RHPSocket = RHPSockets[n]; + break; + } + } + + if (RHPSocket == 0) + { + NumberofRHPConnections; + RHPSockets = realloc(RHPSockets, sizeof(void *) * (NumberofRHPConnections + 1)); + RHPSocket = RHPSockets[NumberofRHPConnections] = zalloc(sizeof (struct RHPConnectionInfo)); + NumberofRHPConnections++; + RHPSocket->socket = socket; + } + + +// {"type":"open","id":5,"pfam":"ax25","mode":"stream","port":"1","local":"G8BPQ","remote":"G8BPQ-2","flags":128} +// {"type": "openReply", "id": 82, "handle": 1, "errCode": 0, "errText": "Ok"} +// {"seqno": 0, "type": "status", "handle": 1, "flags": 0} +// ("seqno": 1, "type": "close", "handle": 1} +// {"id":40,"type":"close","handle":1} + +// {"seqno": 0, "type": "status", "handle": 1, "flags": 2}.~. +// {"seqno": 1, "type": "recv", "handle": 1, "data": "Welcome to G8BPQ's Test Switch in Nottingham \rType ? for list of available commands.\r"}. + + GetJSONValue(Msg, "\"type\":", Value, 15); + + if (_stricmp(Value, "open") == 0) + { + Len = processRHCPOpen(RHPSocket, Msg, &OutBuffer[10]); // Space at front for WebSock Header + if (Len) + SendWebSockMessage(RHPSocket->socket, OutBuffer, Len); + return; + } + + if (_stricmp(Value, "send") == 0) + { + Len = processRHCPSend(RHPSocket, Msg, &OutBuffer[10]); // Space at front for WebSock Header + SendWebSockMessage(RHPSocket->socket, OutBuffer, Len); + return; + } + + if (_stricmp(Value, "close") == 0) + { + Len = processRHCPClose(RHPSocket, Msg, &OutBuffer[10]); // Space at front for WebSock Header + SendWebSockMessage(RHPSocket->socket, OutBuffer, Len); + return; + } + Debugprintf(Msg); +} + +void ProcessRHPWebSockClosed(SOCKET socket) +{ + // Close any connections on this scoket and delete socket entry + + struct RHPConnectionInfo * RHPSocket = NULL; + int n; + + // Find Connection Record. CLear any Sessions + + for (n = 0; n < NumberofRHPConnections; n++) + { + if (RHPSockets[n]->socket == socket) + { + RHPSocket = RHPSockets[n]; + + break; + } + } +} + + + +int processRHCPOpen(struct RHPConnectionInfo * RHPSocket, char * Msg, char * ReplyBuffer) +{ + //{"type":"open","id":5,"pfam":"ax25","mode":"stream","port":"1","local":"G8BPQ","remote":"G8BPQ-2","flags":128} + + struct RHPSessionInfo * RHPSession = 0; + + char * Value = malloc(strlen(Msg)); // Will always be long enough + int ID; + + char pfam[16]; + char Mode[16]; + int Port; + char Local[16]; + char Remote[16]; + int flags; + int Handle = 1; + int Stream; + unsigned char AXCall[10]; + int Len; + int n; + + // ID seems to be used for control commands like open. SeqNo for data within a session (i Think! + + ID = GetJSONInt(Msg, "\"id\":"); + GetJSONValue(Msg, "\"pfam\":", pfam, 15); + GetJSONValue(Msg, "\"mode\":", Mode, 15); + Port = GetJSONInt(Msg, "\"port\":"); + GetJSONValue(Msg, "\"local\":", Local, 15); + GetJSONValue(Msg, "\"remote\":", Remote, 15); + flags = GetJSONInt(Msg, "\"flags\":"); + + if (_stricmp(pfam, "ax25") != 0) + return sprintf(ReplyBuffer, "{\"type\": \"openReply\", \"id\": %d, \"handle\": %d, \"errCode\": 12, \"errText\": \"Bad parameter\"}", ID, 0); + + if (_stricmp(Mode, "stream") == 0) + { + { + // Allocate a RHP Session + + // See if there is an old one we can reuse + + for (n = 0; n < NumberofRHPSessions; n++) + { + if (RHPSessions[n]->BPQStream == 0) + { + RHPSession = RHPSessions[n]; + Handle = n + 1; + Stream = RHPSessions[n]->BPQStream; + + break; + } + } + + if (RHPSession == 0) + { + RHPSessions = realloc(RHPSessions, sizeof(void *) * (NumberofRHPSessions + 1)); + RHPSession = RHPSessions[NumberofRHPSessions] = zalloc(sizeof (struct RHPSessionInfo)); + NumberofRHPSessions++; + + Handle = NumberofRHPSessions; + } + + strcpy(pgm, "RHP"); + Stream = FindFreeStreamNoSem(); + strcpy(pgm, "bpq32.exe"); + + if (Stream == 255) + return sprintf(ReplyBuffer, "{\"type\": \"openReply\", \"id\": %d, \"handle\": %d, \"errCode\": 12, \"errText\": \"Bad parameter\"}", ID, 0); + + RHPSession->BPQStream = Stream; + RHPSession->Handle = Handle; + RHPSession->Connecting = TRUE; + RHPSession->Socket = RHPSocket->socket; + + strcpy(RHPSession->Local, Local); + strcpy(RHPSession->Remote, Remote); + + Connect(Stream); + + ConvToAX25(Local, AXCall); + ChangeSessionCallsign(Stream, AXCall); + + return sprintf(ReplyBuffer, "{\"type\": \"openReply\", \"id\": %d, \"handle\": %d, \"errCode\": 0, \"errText\": \"Ok\"}", ID, Handle); + } + } + return sprintf(ReplyBuffer, "{\"type\": \"openReply\", \"id\": %d, \"handle\": %d, \"errCode\": 12, \"errText\": \"Bad parameter\"}", ID, 0); +} + +int processRHCPSend(struct RHPConnectionInfo * RHPSocket, char * Msg, char * ReplyBuffer) +{ + // {"type":"send","handle":1,"data":";;;;;;\r","id":70} + + struct RHPSessionInfo * RHPSession; + + int ID; + char * Data; + char * ptr; + int c; + int Len; + + int Handle = 1; + + Data = malloc(strlen(Msg)); + + ID = GetJSONInt(Msg, "\"id\":"); + Handle = GetJSONInt(Msg, "\"handle\":"); + GetJSONValue(Msg, "\"data\":", Data, strlen(Msg) - 1); + + if (Handle < 1 || Handle > NumberofRHPSessions) + { + free(Data); + return sprintf(ReplyBuffer, "{\"type\": \"sendReply\", \"id\": %d, \"handle\": %d, \"errCode\": 12, \"errtext\": \"Invalid handle\"}", ID, Handle); + } + + RHPSession = RHPSessions[Handle - 1]; + + // Look for \ escapes + + ptr = Data; + + while (ptr = strchr(ptr, '\\')) + { + c = ptr[1]; + + switch (c) + { + case 'r': + + *ptr = 13; + break; + + case '\\': + + *ptr = '\\'; + break; + + case '"': + + *ptr = '"'; + break; + } + memmove(ptr + 1, ptr + 2, strlen(ptr + 1)); + ptr++; + } + + Debugprintf(Data); + + Len = strlen(Data); + ptr = Data; + + + while (Len > RHPPaclen) + { + SendMsgNoSem(RHPSession->BPQStream, ptr, RHPPaclen); + Len -= RHPPaclen; + ptr += RHPPaclen; + } + + SendMsgNoSem(RHPSession->BPQStream, ptr, Len); + + free(Data); + return sprintf(ReplyBuffer, "{\"type\": \"sendReply\", \"id\": %d, \"handle\": %d, \"errCode\": 0, \"errText\": \"Ok\", \"status\": %d}", ID, Handle, 2); +} + + +int processRHCPClose(struct RHPConnectionInfo * RHPSocket, char * Msg, char * ReplyBuffer) +{ + + // {"id":70,"type":"close","handle":1} + + + struct RHPSessionInfo * RHPSession; + + int ID; + int Handle = 1; + + char * OutBuffer = malloc(256); + + ID = GetJSONInt(Msg, "\"id\":"); + Handle = GetJSONInt(Msg, "\"handle\":"); + + if (Handle < 1 || Handle > NumberofRHPSessions) + return sprintf(ReplyBuffer, "{\"id\": %d, \"type\": \"closeReply\", \"handle\": %d, \"errcode\": 12, \"errtext\": \"Invalid handle\"}", ID, Handle); + + + RHPSession = RHPSessions[Handle - 1]; + Disconnect(RHPSession->BPQStream); + RHPSession->Connected = 0; + RHPSession->Connecting = 0; + + DeallocateStream(RHPSession->BPQStream); + RHPSession->BPQStream = 0; + + return sprintf(ReplyBuffer, "{\"id\": %d, \"type\": \"closeReply\", \"handle\": %d, \"errcode\": 0, \"errtext\": \"Ok\"}", ID, Handle); +} + + + +void RHPPoll() +{ + int Stream; + int n; + int state, change; + int Len; + char * RHPMsg; + unsigned char Buffer[1024]; // Space to escape control chars + int pktlen, count; + + struct RHPSessionInfo * RHPSession; + + for (n = 0; n < NumberofRHPSessions; n++) + { + RHPSession = RHPSessions[n]; + Stream = RHPSession->BPQStream; + + // See if connected state has changed + + SessionState(Stream, &state, &change); + + if (change == 1) + { + if (state == 1) + { + // Connected + + RHPSession->Seq = 0; + RHPSession->Connecting = FALSE; + RHPSession->Connected = TRUE; + + RHPMsg = malloc(256); + Len = sprintf(&RHPMsg[10], "{\"seqno\": %d, \"type\": \"status\", \"handle\": %d, \"flags\": 2}", RHPSession->Seq++, RHPSession->Handle); + SendWebSockMessage(RHPSession->Socket, RHPMsg, Len); + + // Send RHP CTEXT + + RHPMsg = malloc(256); + Len = sprintf(&RHPMsg[10], "{\"seqno\": %d, \"type\": \"recv\", \"handle\": %d, \"data\": \"Connected to RHP Server\\r\"}", RHPSession->Seq++, RHPSession->Handle); + SendWebSockMessage(RHPSession->Socket, RHPMsg, Len); + } + else + { + // Disconnected. Send Close to client + + RHPMsg = malloc(256); + Len = sprintf(&RHPMsg[10], "{\"type\": \"close\", \"seqno\": %d, \"handle\": %d}", RHPSession->Seq++, RHPSession->Handle); + SendWebSockMessage(RHPSession->Socket, RHPMsg, Len); + + RHPSession->Connected = 0; + RHPSession->Connecting = 0; + + DeallocateStream(RHPSession->BPQStream); + RHPSession->BPQStream = 0; + } + } + do + { + GetMsg(Stream, Buffer, &pktlen, &count); + + if (pktlen > 0) + { + char * ptr = Buffer; + char c; + + Buffer[pktlen] = 0; + + // Message is JSON so Convert CR to \r, \ to \\ " to \" + + while (c = *(ptr)) + { + switch (c) + { + case 13: + + memmove(ptr + 2, ptr + 1, strlen(ptr)); + *(ptr++) = '\\'; + *(ptr++) = 'r'; + break; + + case '"': + + memmove(ptr + 2, ptr + 1, strlen(ptr)); + *(ptr++) = '\\'; + *(ptr++) = '"'; + break; + + case '\\': + + memmove(ptr + 2, ptr + 1, strlen(ptr)); + *(ptr++) = '\\'; + *(ptr++) = '\\'; + break; + } + ptr++; + } + + + RHPMsg = malloc(1024); + + Len = sprintf(&RHPMsg[10], "{\"seqno\": %d, \"type\": \"recv\", \"handle\": %d, \"data\": \"%s\"}", RHPSession->Seq++, RHPSession->Handle, Buffer); + SendWebSockMessage(RHPSession->Socket, RHPMsg, Len); + + } + + } + while (count > 0); + + } +} + + + +static void GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value, int Len) +{ + char * ptr1, * ptr2; + + Value[0] = 0; + + ptr1 = strstr(_REPLYBUFFER, Name); + + if (ptr1 == 0) + return; + + ptr1 += (strlen(Name) + 1); + +// "data":"{\"t\":\"c\",\"n\":\"John\",\"c\":\"G8BPQ\",\"lm\":1737912636,\"le\":1737883907,\"led\":1737758451,\"v\":0.33,\"cc\":[{\"cid\":1,\"lp\":1737917257201,\"le\":1737913735726,\"led\":1737905249785},{\"cid\":0,\"lp\":1737324074107,\"le\":1737323831510,\"led\":1737322973662},{\"cid\":5,\"lp\":1737992107419,\"le\":1737931466510,\"led\":1737770056244}]}\r","id":28} + + // There may be escaped " in data stream + + ptr2 = strchr(ptr1, '"'); + + while (*(ptr2 - 1) == '\\') + { + ptr2 = strchr(ptr2 + 2, '"'); + } + + + if (ptr2) + { + size_t ValLen = ptr2 - ptr1; + if (ValLen > Len) + ValLen = Len; + + memcpy(Value, ptr1, ValLen); + Value[ValLen] = 0; + } + + return; +} + + +static int GetJSONInt(char * _REPLYBUFFER, char * Name) +{ + char * ptr1; + + ptr1 = strstr(_REPLYBUFFER, Name); + + if (ptr1 == 0) + return 0; + + ptr1 += (strlen(Name)); + + return atoi(ptr1); +} + + diff --git a/RHP.c b/RHP.c new file mode 100644 index 0000000..b7002be --- /dev/null +++ b/RHP.c @@ -0,0 +1,711 @@ +/* +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 +*/ + +/* + + Paula (G8PZT)'s Remote Host Protocol interface. + For now only sufficient support for WhatsPac + + +*/ +#define _CRT_SECURE_NO_DEPRECATE + +#include "cheaders.h" +#include "bpq32.h" + +int FindFreeStreamNoSem(); +DllExport int APIENTRY DeallocateStream(int stream); +int SendMsgNoSem(int stream, char * msg, int len); + +static void GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value, int Len); +static int GetJSONInt(char * _REPLYBUFFER, char * Name); + +// Generally Can have multiple RHP connections and each can have multiple RHF Sessions + +struct RHPSessionInfo +{ + SOCKET Socket; // Websocks Socket + int BPQStream; + int Handle; // RHP session ID + int Seq; + char Local[12]; + char Remote[12]; + BOOL Connecting; // Set while waiting for connection to complete + BOOL Listening; + BOOL Connected; +}; + +struct RHPConnectionInfo +{ + SOCKET socket; + struct RHPSessionInfo ** RHPSessions; + int NumberofRHPSessions; +}; + +// Struct passed by beginhread + +struct RHPParamBlock +{ + unsigned char * Msg; + int Len; + SOCKET Socket; +}; + + + +//struct RHPConnectionInfo ** RHPSockets = NULL; +//int NumberofRHPConnections = 0; + +struct RHPSessionInfo ** RHPSessions; +int NumberofRHPSessions; + +char ErrCodes[18][24] = +{"Ok", "Unspecified", "Bad or missing type", "Invalid handle", "No memory", "Bad or missing mode", + + "Invalid local address", + "Invalid remote address" , + "Bad or missing family" , + "Duplicate socket" , + "No such port" , + "Invalid protocol" , + "Bad parameter" , + "No buffers" , + "Unauthorised" , + "No Route" , + "Operation not supported"}; + + + + +extern char pgm[256]; + +SOCKET agwsock; + +extern int SemHeldByAPI; + +char szBuff[80]; + +int WhatsPacConfigured = 1; + + +int RHPPaclen = 236; + + +int processRHCPOpen(SOCKET Socket, char * Msg, char * ReplyBuffer); +int processRHCPSend(SOCKET Socket, char * Msg, char * ReplyBuffer); +int processRHCPClose(SOCKET Socket, char * Msg, char * ReplyBuffer); + + + +void SendWebSockMessage(SOCKET socket, char * Msg, int Len) +{ + int Loops = 0; + int Sent; + int TxLen; + char * OutBuffer = Msg; + + // WebSock Encode. Buffer has 10 bytes on front for header but header len depends on Msg len + + + if (Len < 126) + { + // Two Byte Header + + OutBuffer[8] = 0x81; // Fin, Data + OutBuffer[9] = Len; + + TxLen = Len + 2; + OutBuffer = &Msg[8]; + } + else if (Len < 65536) + { + OutBuffer[6] = 0x81; // Fin, Data + OutBuffer[7] = 126; // Unmasked, Extended Len 16 + OutBuffer[8] = Len >> 8; + OutBuffer[9] = Len & 0xff; + TxLen = Len + 4; + OutBuffer = &Msg[6]; + } + else + { + OutBuffer[0] = 0x81; // Fin, Data + OutBuffer[1] = 127; // Unmasked, Extended Len 64 bits + // Len is 32 bits, so pad with zeros + OutBuffer[2] = 0; + OutBuffer[3] = 0; + OutBuffer[4] = 0; + OutBuffer[5] = 0; + OutBuffer[6] = (Len >> 24) & 0xff; + OutBuffer[7] = (Len >> 16) & 0xff; + OutBuffer[8] = (Len >> 8) & 0xff; + OutBuffer[9] = Len & 0xff; + + TxLen = Len + + 10; + OutBuffer = &Msg[0]; + } + + // Send may block + + Sent = send(socket, OutBuffer, TxLen, 0); + + while (Sent != TxLen && Loops++ < 3000) // 100 secs max + { + if (Sent > 0) // something sent + { + TxLen -= Sent; + memmove(OutBuffer, &OutBuffer[Sent], TxLen); + } + + Sleep(30); + Sent = send(socket, OutBuffer, TxLen, 0); + if (Sent == -1) + break; + } + + free(Msg); + return; +} + +void ProcessRHPWebSock(SOCKET Socket, char * Msg, int MsgLen); + +void RHPThread(void * Params) +{ + // Params and data buffer are malloced blocks so free when done with it + + struct RHPParamBlock * Block = (struct RHPParamBlock *)Params; + + ProcessRHPWebSock(Block->Socket, Block->Msg, Block->Len); + + free(Block->Msg); + free(Params); +} + +int RHPProcessHTTPMessage(void * conn, char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE) +{ + // RHP messages can be sent over Websocks or normal http but I think WhatsPac only uses WebSocks + return 0; +} + +void ProcessRHPWebSock(SOCKET Socket, char * Msg, int MsgLen) +{ + int Loops = 0; + int InputLen = 0; + int Len; + + char Value[16]; + char * OutBuffer = malloc(250000); + +// struct RHPConnectionInfo * RHPSocket = NULL; +// int n; + + Msg[MsgLen] = 0; + + // Find Connection Record. If none, create one + + // I dont think I need connection records + +/* + for (n = 0; n < NumberofRHPConnections; n++) + { + if (RHPSockets[n]->socket == socket) + { + RHPSocket = RHPSockets[n]; + break; + } + } + + if (RHPSocket == 0) + { + // See if there is an old one we can reuse + + for (n = 0; n < NumberofRHPConnections; n++) + { + if (RHPSockets[n]-Socket == -1) + { + RHPSocket = RHPSockets[n]; + RHP + + break; + } + } + + if (RHPSocket == 0) + + NumberofRHPConnections; + RHPSockets = realloc(RHPSockets, sizeof(void *) * (NumberofRHPConnections + 1)); + RHPSocket = RHPSockets[NumberofRHPConnections] = zalloc(sizeof (struct RHPConnectionInfo)); + NumberofRHPConnections++; + RHPSocket->socket = socket; + } +*/ + +// {"type":"open","id":5,"pfam":"ax25","mode":"stream","port":"1","local":"G8BPQ","remote":"G8BPQ-2","flags":128} +// {"type": "openReply", "id": 82, "handle": 1, "errCode": 0, "errText": "Ok"} +// {"seqno": 0, "type": "status", "handle": 1, "flags": 0} +// ("seqno": 1, "type": "close", "handle": 1} +// {"id":40,"type":"close","handle":1} + +// {"seqno": 0, "type": "status", "handle": 1, "flags": 2}.~. +// {"seqno": 1, "type": "recv", "handle": 1, "data": "Welcome to G8BPQ's Test Switch in Nottingham \rType ? for list of available commands.\r"}. + + GetJSONValue(Msg, "\"type\":", Value, 15); + + if (_stricmp(Value, "open") == 0) + { + Len = processRHCPOpen(Socket, Msg, &OutBuffer[10]); // Space at front for WebSock Header + if (Len) + SendWebSockMessage(Socket, OutBuffer, Len); + return; + } + + if (_stricmp(Value, "send") == 0) + { + Len = processRHCPSend(Socket, Msg, &OutBuffer[10]); // Space at front for WebSock Header + SendWebSockMessage(Socket, OutBuffer, Len); + return; + } + + if (_stricmp(Value, "close") == 0) + { + Len = processRHCPClose(Socket, Msg, &OutBuffer[10]); // Space at front for WebSock Header + SendWebSockMessage(Socket, OutBuffer, Len); + return; + } + Debugprintf(Msg); +} + +void ProcessRHPWebSockClosed(SOCKET socket) +{ + // Close any connections on this scoket and delete socket entry + + struct RHPSessionInfo * RHPSession = 0; + int n; + + // Find and close any Sessions + + for (n = 0; n < NumberofRHPSessions; n++) + { + if (RHPSessions[n]->Socket == socket) + { + RHPSession = RHPSessions[n]; + + if (RHPSession->BPQStream) + { + Disconnect(RHPSession->BPQStream); + DeallocateStream(RHPSession->BPQStream); + + RHPSession->BPQStream = 0; + + } + + RHPSession->Connecting = 0; + + // We can't send a close to RHP endpont as socket has gone + + RHPSession->Connected = 0; + } + } +} + + + + +int processRHCPOpen(SOCKET Socket, char * Msg, char * ReplyBuffer) +{ + //{"type":"open","id":5,"pfam":"ax25","mode":"stream","port":"1","local":"G8BPQ","remote":"G8BPQ-2","flags":128} + + struct RHPSessionInfo * RHPSession = 0; + + char * Value = malloc(strlen(Msg)); // Will always be long enough + int ID; + + char pfam[16]; + char Mode[16]; + int Port; + char Local[16]; + char Remote[16]; + int flags; + int Handle = 1; + int Stream; + unsigned char AXCall[10]; + int Len; + int n; + + // ID seems to be used for control commands like open. SeqNo for data within a session (i Think! + + ID = GetJSONInt(Msg, "\"id\":"); + GetJSONValue(Msg, "\"pfam\":", pfam, 15); + GetJSONValue(Msg, "\"mode\":", Mode, 15); + Port = GetJSONInt(Msg, "\"port\":"); + GetJSONValue(Msg, "\"local\":", Local, 15); + GetJSONValue(Msg, "\"remote\":", Remote, 15); + flags = GetJSONInt(Msg, "\"flags\":"); + + if (_stricmp(pfam, "ax25") != 0) + return sprintf(ReplyBuffer, "{\"type\": \"openReply\", \"id\": %d, \"handle\": %d, \"errCode\": 12, \"errText\": \"Bad parameter\"}", ID, 0); + + if (_stricmp(Mode, "stream") == 0) + { + { + // Allocate a RHP Session + + // See if there is an old one we can reuse + + for (n = 0; n < NumberofRHPSessions; n++) + { + if (RHPSessions[n]->BPQStream == 0) + { + RHPSession = RHPSessions[n]; + Handle = n + 1; + Stream = RHPSessions[n]->BPQStream; + + break; + } + } + + if (RHPSession == 0) + { + RHPSessions = realloc(RHPSessions, sizeof(void *) * (NumberofRHPSessions + 1)); + RHPSession = RHPSessions[NumberofRHPSessions] = zalloc(sizeof (struct RHPSessionInfo)); + NumberofRHPSessions++; + + Handle = NumberofRHPSessions; + } + + strcpy(pgm, "RHP"); + Stream = FindFreeStreamNoSem(); + strcpy(pgm, "bpq32.exe"); + + if (Stream == 255) + return sprintf(ReplyBuffer, "{\"type\": \"openReply\", \"id\": %d, \"handle\": %d, \"errCode\": 12, \"errText\": \"Bad parameter\"}", ID, 0); + + RHPSession->BPQStream = Stream; + RHPSession->Handle = Handle; + RHPSession->Connecting = TRUE; + RHPSession->Socket = Socket; + + strcpy(RHPSession->Local, Local); + strcpy(RHPSession->Remote, Remote); + + Connect(Stream); + + ConvToAX25(Local, AXCall); + ChangeSessionCallsign(Stream, AXCall); + + return sprintf(ReplyBuffer, "{\"type\": \"openReply\", \"id\": %d, \"handle\": %d, \"errCode\": 0, \"errText\": \"Ok\"}", ID, Handle); + } + } + return sprintf(ReplyBuffer, "{\"type\": \"openReply\", \"id\": %d, \"handle\": %d, \"errCode\": 12, \"errText\": \"Bad parameter\"}", ID, 0); +} + +int processRHCPSend(SOCKET Socket, char * Msg, char * ReplyBuffer) +{ + // {"type":"send","handle":1,"data":";;;;;;\r","id":70} + + struct RHPSessionInfo * RHPSession; + + int ID; + char * Data; + char * ptr; + int c; + int Len; + + int Handle = 1; + + Data = malloc(strlen(Msg)); + + ID = GetJSONInt(Msg, "\"id\":"); + Handle = GetJSONInt(Msg, "\"handle\":"); + GetJSONValue(Msg, "\"data\":", Data, strlen(Msg) - 1); + + if (Handle < 1 || Handle > NumberofRHPSessions) + { + free(Data); + return sprintf(ReplyBuffer, "{\"type\": \"sendReply\", \"id\": %d, \"handle\": %d, \"errCode\": 12, \"errtext\": \"Invalid handle\"}", ID, Handle); + } + + RHPSession = RHPSessions[Handle - 1]; + + // Look for \ escapes + + ptr = Data; + + while (ptr = strchr(ptr, '\\')) + { + c = ptr[1]; + + switch (c) + { + case 'r': + + *ptr = 13; + break; + + case '\\': + + *ptr = '\\'; + break; + + case '"': + + *ptr = '"'; + break; + } + memmove(ptr + 1, ptr + 2, strlen(ptr + 1)); + ptr++; + } + + Debugprintf(Data); + + Len = strlen(Data); + ptr = Data; + + + while (Len > RHPPaclen) + { + SendMsgNoSem(RHPSession->BPQStream, ptr, RHPPaclen); + Len -= RHPPaclen; + ptr += RHPPaclen; + } + + SendMsgNoSem(RHPSession->BPQStream, ptr, Len); + + free(Data); + return sprintf(ReplyBuffer, "{\"type\": \"sendReply\", \"id\": %d, \"handle\": %d, \"errCode\": 0, \"errText\": \"Ok\", \"status\": %d}", ID, Handle, 2); +} + + +int processRHCPClose(SOCKET Socket, char * Msg, char * ReplyBuffer) +{ + + // {"id":70,"type":"close","handle":1} + + + struct RHPSessionInfo * RHPSession; + + int ID; + int Handle = 1; + + char * OutBuffer = malloc(256); + + ID = GetJSONInt(Msg, "\"id\":"); + Handle = GetJSONInt(Msg, "\"handle\":"); + + if (Handle < 1 || Handle > NumberofRHPSessions) + return sprintf(ReplyBuffer, "{\"id\": %d, \"type\": \"closeReply\", \"handle\": %d, \"errcode\": 12, \"errtext\": \"Invalid handle\"}", ID, Handle); + + + RHPSession = RHPSessions[Handle - 1]; + Disconnect(RHPSession->BPQStream); + RHPSession->Connected = 0; + RHPSession->Connecting = 0; + + DeallocateStream(RHPSession->BPQStream); + RHPSession->BPQStream = 0; + + return sprintf(ReplyBuffer, "{\"id\": %d, \"type\": \"closeReply\", \"handle\": %d, \"errcode\": 0, \"errtext\": \"Ok\"}", ID, Handle); +} + +char toHex[] = "0123456789abcdef"; + +void RHPPoll() +{ + int Stream; + int n; + int state, change; + int Len; + char * RHPMsg; + unsigned char Buffer[2048]; // Space to escape control chars + int pktlen, count; + + struct RHPSessionInfo * RHPSession; + + for (n = 0; n < NumberofRHPSessions; n++) + { + RHPSession = RHPSessions[n]; + Stream = RHPSession->BPQStream; + + // See if connected state has changed + + SessionState(Stream, &state, &change); + + if (change == 1) + { + if (state == 1) + { + // Connected + + RHPSession->Seq = 0; + RHPSession->Connecting = FALSE; + RHPSession->Connected = TRUE; + + RHPMsg = malloc(256); + Len = sprintf(&RHPMsg[10], "{\"seqno\": %d, \"type\": \"status\", \"handle\": %d, \"flags\": 2}", RHPSession->Seq++, RHPSession->Handle); + SendWebSockMessage(RHPSession->Socket, RHPMsg, Len); + + // Send RHP CTEXT + + RHPMsg = malloc(256); + Sleep(10); // otherwise WhatsPac doesn't display connected + Len = sprintf(&RHPMsg[10], "{\"seqno\": %d, \"type\": \"recv\", \"handle\": %d, \"data\": \"Connected to RHP Server\\r\"}", RHPSession->Seq++, RHPSession->Handle); + SendWebSockMessage(RHPSession->Socket, RHPMsg, Len); + } + else + { + // Disconnected. Send Close to client + + RHPMsg = malloc(256); + Len = sprintf(&RHPMsg[10], "{\"type\": \"close\", \"seqno\": %d, \"handle\": %d}", RHPSession->Seq++, RHPSession->Handle); + SendWebSockMessage(RHPSession->Socket, RHPMsg, Len); + + RHPSession->Connected = 0; + RHPSession->Connecting = 0; + + DeallocateStream(RHPSession->BPQStream); + RHPSession->BPQStream = 0; + } + } + do + { + GetMsg(Stream, Buffer, &pktlen, &count); + + if (pktlen > 0) + { + char * ptr = Buffer; + unsigned char c; + + Buffer[pktlen] = 0; + + // Message is JSON so Convert CR to \r, \ to \\ " to \" + + // Looks like I need to escape everything not between 0x20 and 0x7f eg \U00c3 + + + while (c = *(ptr)) + { + switch (c) + { + case 13: + + memmove(ptr + 2, ptr + 1, strlen(ptr) + 1); + *(ptr++) = '\\'; + *(ptr++) = 'r'; + break; + + case '"': + + memmove(ptr + 2, ptr + 1, strlen(ptr) + 1); + *(ptr++) = '\\'; + *(ptr++) = '"'; + break; + + case '\\': + + memmove(ptr + 2, ptr + 1, strlen(ptr) + 1); + *(ptr++) = '\\'; + *(ptr++) = '\\'; + break; + + default: + + if (c > 127) + { + memmove(ptr + 6, ptr + 1, strlen(ptr) + 1); + *(ptr++) = '\\'; + *(ptr++) = 'u'; + *(ptr++) = '0'; + *(ptr++) = '0'; + *(ptr++) = toHex[c >> 4]; + *(ptr++) = toHex[c & 15]; + break; + } + else + ptr++; + } + } + + RHPMsg = malloc(2048); + + Len = sprintf(&RHPMsg[10], "{\"seqno\": %d, \"type\": \"recv\", \"handle\": %d, \"data\": \"%s\"}", RHPSession->Seq++, RHPSession->Handle, Buffer); + SendWebSockMessage(RHPSession->Socket, RHPMsg, Len); + + } + + } + while (count > 0); + + } +} + + + +static void GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value, int Len) +{ + char * ptr1, * ptr2; + + Value[0] = 0; + + ptr1 = strstr(_REPLYBUFFER, Name); + + if (ptr1 == 0) + return; + + ptr1 += (strlen(Name) + 1); + +// "data":"{\"t\":\"c\",\"n\":\"John\",\"c\":\"G8BPQ\",\"lm\":1737912636,\"le\":1737883907,\"led\":1737758451,\"v\":0.33,\"cc\":[{\"cid\":1,\"lp\":1737917257201,\"le\":1737913735726,\"led\":1737905249785},{\"cid\":0,\"lp\":1737324074107,\"le\":1737323831510,\"led\":1737322973662},{\"cid\":5,\"lp\":1737992107419,\"le\":1737931466510,\"led\":1737770056244}]}\r","id":28} + + // There may be escaped " in data stream + + ptr2 = strchr(ptr1, '"'); + + while (*(ptr2 - 1) == '\\') + { + ptr2 = strchr(ptr2 + 2, '"'); + } + + + if (ptr2) + { + size_t ValLen = ptr2 - ptr1; + if (ValLen > Len) + ValLen = Len; + + memcpy(Value, ptr1, ValLen); + Value[ValLen] = 0; + } + + return; +} + + +static int GetJSONInt(char * _REPLYBUFFER, char * Name) +{ + char * ptr1; + + ptr1 = strstr(_REPLYBUFFER, Name); + + if (ptr1 == 0) + return 0; + + ptr1 += (strlen(Name)); + + return atoi(ptr1); +} + + diff --git a/RigControl.c b/RigControl.c index 024d17d..6bc414f 100644 --- a/RigControl.c +++ b/RigControl.c @@ -48,7 +48,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include #include "time.h" -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #ifdef WIN32 #include @@ -324,7 +324,7 @@ VOID Rig_PTTEx(struct RIGINFO * RIG, BOOL PTTState, struct TNCINFO * TNC) // Convert to CAT string - sprintf(FreqString, "%012d", txfreq); + sprintf(FreqString, "%012lld", txfreq); switch (PORT->PortType) { @@ -455,7 +455,7 @@ VOID Rig_PTTEx(struct RIGINFO * RIG, BOOL PTTState, struct TNCINFO * TNC) // Convert to CAT string - sprintf(FreqString, "%012d", txfreq); + sprintf(FreqString, "%012lld", txfreq); switch (PORT->PortType) { @@ -896,7 +896,7 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR // if Port starts with 'R' then select Radio (was Interlock) number, not BPQ Port if (Command[0] == 'R') - n = sscanf(Command,"%s %s %s %s %s", &Dummy, &FreqString[0], &Mode[0], &FilterString[0], &Data[0]); + n = sscanf(Command,"%s %s %s %s %s", &Dummy[0], &FreqString[0], &Mode[0], &FilterString[0], &Data[0]); else n = sscanf(Command,"%d %s %s %s %s", &Port, &FreqString[0], &Mode[0], &FilterString[0], &Data[0]); @@ -1117,7 +1117,7 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR if (_stricmp(FreqString, "POWER") == 0) { - char PowerString[8] = ""; + char PowerString[16] = ""; int Power = atoi(Mode); int len; char cmd[80]; @@ -1291,7 +1291,7 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR // use text command - Len = sprintf(CmdPtr, "%S", ptr1); + Len = sprintf(CmdPtr, "%s", ptr1); break; case YAESU: @@ -2072,7 +2072,7 @@ int Rig_CommandEx(struct RIGPORTINFO * PORT, struct RIGINFO * RIG, TRANSPORTENTR case HAMLIB: { - char cmd[80]; + char cmd[200]; int len = sprintf(cmd, "F %s\n+f\nM %s %d\n+m\n", FreqString, Mode, atoi(Data)); @@ -7252,7 +7252,7 @@ CheckScan: } else if (PORT->PortType == FT991A || PORT->PortType == FTDX10) { - FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "FA%s;MD0%X;FA;MD0;", &FreqString, ModeNo); + FreqPtr[0]->Cmd1Len = sprintf(CmdPtr, "FA%s;MD0%X;FA;MD0;", &FreqString[0], ModeNo); } else if (PORT->PortType == FT100 || PORT->PortType == FT990 || PORT->PortType == FT1000) @@ -8139,7 +8139,7 @@ void ProcessFLRIGFrame(struct RIGPORTINFO * PORT) void HLSetMode(SOCKET Sock, struct RIGINFO * RIG, unsigned char * Msg, char sep) { - char Resp[80]; + char Resp[120]; int Len; char mode[80] = ""; int filter = 0; @@ -10164,7 +10164,7 @@ VOID ConnecttoSDRANGEL(struct RIGPORTINFO * PORT) VOID SDRANGELThread(struct RIGPORTINFO * PORT) { // Opens sockets and looks for data - char Msg[255]; + char Msg[512]; int err, i, ret; u_long param=1; BOOL bcopt=TRUE; diff --git a/SCSPactor.c b/SCSPactor.c index ddb8277..bca138a 100644 --- a/SCSPactor.c +++ b/SCSPactor.c @@ -78,7 +78,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define MaxStreams 10 // First is used for Pactor, even though Pactor uses channel 31 -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "bpq32.h" diff --git a/SCSTrackeMulti.c b/SCSTrackeMulti.c index 00174cf..590a61a 100644 --- a/SCSTrackeMulti.c +++ b/SCSTrackeMulti.c @@ -31,7 +31,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define MaxStreams 10 -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "bpq32.h" diff --git a/SCSTracker.c b/SCSTracker.c index e6d356f..5cc106f 100644 --- a/SCSTracker.c +++ b/SCSTracker.c @@ -31,7 +31,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define MaxStreams 1 -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" //#include "bpq32.h" diff --git a/SerialPort.c b/SerialPort.c index 0fb09e7..3cda40e 100644 --- a/SerialPort.c +++ b/SerialPort.c @@ -36,7 +36,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #endif -#include "CHeaders.h" +#include "cheaders.h" extern int (WINAPI FAR *GetModuleFileNameExPtr)(); diff --git a/TNCCode.c b/TNCCode.c index d21deab..37cd8e2 100644 --- a/TNCCode.c +++ b/TNCCode.c @@ -30,7 +30,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "stdio.h" #include -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" int C_Q_COUNT(VOID *PQ); diff --git a/TNCEmulators.c b/TNCEmulators.c index cf32c9a..135d318 100644 --- a/TNCEmulators.c +++ b/TNCEmulators.c @@ -25,7 +25,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" typedef struct _TCMDX { diff --git a/TelnetV6-skigdebian.c b/TelnetV6-skigdebian.c new file mode 100644 index 0000000..8074a4a --- /dev/null +++ b/TelnetV6-skigdebian.c @@ -0,0 +1,7157 @@ +/* +Copyright 2001-2022 John Wiseman G8BPQ + +This file is part of LinBPQ/BPQ32. + +LinBPQ/BPQ32 is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +LinBPQ/BPQ32 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses +*/ + +// +// Telnet Driver for BPQ Switch +// +// Uses BPQ EXTERNAL interface +// + +//#define WIN32_LEAN_AND_MEAN + +#define _CRT_SECURE_NO_WARNINGS +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include +#include "time.h" + +#include "kernelresource.h" + +#define IDM_DISCONNECT 2000 +#define IDM_LOGGING 2100 + +#include "cheaders.h" +#include "tncinfo.h" + +#ifdef WIN32 +#include +#include "WS2tcpip.h" +#else +//#define TIOCOUTQ 0x5411 +#define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */ +#endif + +#include "adif.h" +#include "telnetserver.h" + +#define MAX_PENDING_CONNECTS 4 + +extern UCHAR LogDirectory[]; + + +static char ClassName[]="TELNETSERVER"; +static char WindowTitle[] = "Telnet Server"; +static int RigControlRow = 190; + +UCHAR * APIENTRY GetLogDirectory(); +static BOOL OpenSockets(struct TNCINFO * TNC); +static BOOL OpenSockets6(struct TNCINFO * TNC); +void ProcessHTTPMessage(void * conn); +static VOID SetupListenSet(struct TNCINFO * TNC); +int WritetoConsoleLocal(char * buff); +BOOL TelSendPacket(int Stream, struct STREAMINFO * STREAM, PMSGWITHLEN buffptr, struct ADIF * ADIF); +int GetCMSHash(char * Challenge, char * Password); +int IsUTF8(unsigned char *cpt, int len); +int Convert437toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); +int Convert1251toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); +int Convert1252toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); +VOID initUTF8(); +int TrytoGuessCode(unsigned char * Char, int Len); +DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot); +extern BPQVECSTRUC * TELNETMONVECPTR; +BOOL SendWL2KSessionRecord(ADIF * ADIF, int BytesSent, int BytesReceived); +int DataSocket_ReadSync(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream); +VOID SendWL2KRegisterHybrid(struct TNCINFO * TNC); +int IntSetTraceOptionsEx(uint64_t mask, int mtxparam, int mcomparam, int monUIOnly); +int DataSocket_ReadDRATS(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream); +void processDRATSFrame(unsigned char * Message, int Len, struct ConnectionInfo * sockptr); +void DRATSConnectionLost(struct ConnectionInfo * sockptr); +int BuildRigCtlPage(char * _REPLYBUFFER); +void ProcessWebmailWebSockThread(void * conn); +void ProcessRHPWebSock(SOCKET Socket, char * msg, int Len); +void ProcessRHPWebSockClosed(SOCKET socket); +int ProcessSNMPPayload(UCHAR * Msg, int Len, UCHAR * Reply, int * OffPtr); +int RHPProcessHTTPMessage(struct ConnectionInfo * conn, char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE); + + +#ifndef LINBPQ +extern HKEY REGTREE; +extern HMENU hMainFrameMenu; +extern HMENU hBaseMenu; +extern HMENU hWndMenu; +extern HFONT hFont; +extern HBRUSH bgBrush; + +extern HWND ClientWnd, FrameWnd; + +extern HANDLE hInstance; +static RECT Rect; + +LRESULT CALLBACK TelWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); + +#endif + +extern int REALTIMETICKS; + +#define MaxSockets 26 + +struct UserRec RelayUser; +struct UserRec SyncUser = {"","Sync"};; +struct UserRec CMSUser; +struct UserRec HostUser = {"","Host"}; +struct UserRec TriModeUser; + +static char AttemptsMsg[] = "Too many attempts - Disconnected\r\n"; +static char disMsg[] = "Disconnected by SYSOP\r\n"; + +static char BlankCall[]=" "; + +BOOL LogEnabled = FALSE; +BOOL CMSLogEnabled = TRUE; +extern BOOL IncludesMail; + +extern int HTTPPort; + +static HMENU hMenu, hPopMenu, hPopMenu2, hPopMenu3; // handle of menu + +static int ProcessLine(char * buf, int Port); +VOID __cdecl Debugprintf(const char * format, ...); + + +int DisplaySessions(struct TNCINFO * TNC); +int DoStateChange(int Stream); +int Connected(int Stream); +int Disconnected(int Stream); +//int DeleteConnection(con); +static int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port); +static int Socket_Data(struct TNCINFO * TNC, SOCKET SocketId,int error, int eventcode); +static int DataSocket_Read(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM); +int DataSocket_ReadFBB(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream); +int DataSocket_ReadRelay(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM); +int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream); +int DataSocket_Write(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET TCPSock); +int DataSocket_Disconnect(struct TNCINFO * TNC, struct ConnectionInfo * sockptr); +BOOL ProcessTelnetCommand(struct ConnectionInfo * sockptr, byte * Msg, int * Len); +int ShowConnections(struct TNCINFO * TNC); +int Terminate(); +int SendtoSocket(SOCKET TCPSock,char * Msg); +int WriteLog(char * msg); +VOID WriteCMSLog(char * msg); +byte * EncodeCall(byte * Call); +VOID SendtoNode(struct TNCINFO * TNC, int Stream, char * Msg, int MsgLen); +DllExport int APIENTRY GetNumberofPorts(); + +BOOL CheckCMS(struct TNCINFO * TNC); +int TCPConnect(struct TNCINFO * TNC, struct TCPINFO * TCP, struct STREAMINFO * STREAM, char * Host, int Port, BOOL FBB); +int CMSConnect(struct TNCINFO * TNC, struct TCPINFO * TCP, struct STREAMINFO * STREAM, int Stream); +int Telnet_Connected(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Error); +BOOL ProcessConfig(); +VOID FreeConfig(); +VOID SaveCMSHostInfo(int port, struct TCPINFO * TCP, int CMSNo); +VOID GetCMSCachedInfo(struct TNCINFO * TNC); +BOOL CMSCheck(struct TNCINFO * TNC, struct TCPINFO * TCP); +VOID Tel_Format_Addr(struct ConnectionInfo * sockptr, char * dst); +VOID ProcessTrimodeCommand(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, char * MsgPtr); +VOID ProcessTrimodeResponse(struct TNCINFO * TNC, struct STREAMINFO * STREAM, unsigned char * MsgPtr, int Msglen); +VOID ProcessTriModeDataMessage(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM); + + +static int LogAge = 13; + + + +#ifdef WIN32 + +int DeleteLogFile(char * Log); + +void DeleteTelnetLogFiles() +{ + DeleteLogFile("/logs/Telnet*.log"); + DeleteLogFile("/logs/CMSAccess_*.log"); + DeleteLogFile("/logs/ConnectLog_*.log"); +} + +int DeleteLogFile(char * Log) +{ + + + WIN32_FIND_DATA ffd; + + char szDir[MAX_PATH]; + char File[MAX_PATH]; + HANDLE hFind = INVALID_HANDLE_VALUE; + DWORD dwError=0; + LARGE_INTEGER ft; + time_t now = time(NULL); + int Age; + + // Prepare string for use with FindFile functions. First, copy the + // string to a buffer, then append '\*' to the directory name. + + strcpy(szDir, GetLogDirectory()); + strcat(szDir, Log); + + // Find the first file in the directory. + + hFind = FindFirstFile(szDir, &ffd); + + if (INVALID_HANDLE_VALUE == hFind) + return dwError; + + // List all the files in the directory with some info about them. + + do + { + if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + OutputDebugString(ffd.cFileName); + } + else + { + ft.HighPart = ffd.ftCreationTime.dwHighDateTime; + ft.LowPart = ffd.ftCreationTime.dwLowDateTime; + + ft.QuadPart -= 116444736000000000; + ft.QuadPart /= 10000000; + + Age = (int)((now - ft.LowPart) / 86400); + + if (Age > LogAge) + { + sprintf(File, "%s/logs/%s%c", GetLogDirectory(), ffd.cFileName, 0); + Debugprintf("Deleting %s", File); + DeleteFile(File); + } + } + } + while (FindNextFile(hFind, &ffd) != 0); + + FindClose(hFind); + return dwError; +} + +#else + +#include + +int TelFilter(const struct dirent * dir) +{ + return (memcmp(dir->d_name, "CMSAccess", 9) == 0 + || memcmp(dir->d_name, "Telnet", 6) == 0 + || memcmp(dir->d_name, "ConnectLog", 6) == 0) + && strstr(dir->d_name, ".log"); +} + +int DeleteTelnetLogFiles() +{ + struct dirent **namelist; + int n; + struct stat STAT; + time_t now = time(NULL); + int Age = 0, res; + char FN[256]; + + n = scandir("logs", &namelist, TelFilter, alphasort); + + if (n < 0) + perror("scandir"); + else + { + while(n--) + { + sprintf(FN, "logs/%s", namelist[n]->d_name); + if (stat(FN, &STAT) == 0) + { + Age = (now - STAT.st_mtime) / 86400; + + if (Age > LogAge) + { + Debugprintf("Deleting %s\n", FN); + unlink(FN); + } + } + free(namelist[n]); + } + free(namelist); + } + return 0; +} +#endif + + + +void BuffertoNode(struct ConnectionInfo * sockptr, char * MsgPtr, int InputLen) +{ + // Queue to Node. Data may arrive it large quatities, possibly exceeding node buffer capacity + + if (sockptr->FromHostBuffPutptr + InputLen > sockptr->FromHostBufferSize) + { + if (InputLen > 10000) + sockptr->FromHostBufferSize += InputLen; + else + sockptr->FromHostBufferSize += 10000; + + sockptr->FromHostBuffer = realloc(sockptr->FromHostBuffer, sockptr->FromHostBufferSize); + } + + memcpy(&sockptr->FromHostBuffer[sockptr->FromHostBuffPutptr], MsgPtr, InputLen); + + sockptr->FromHostBuffPutptr += InputLen; + sockptr->InputLen = 0; + + return; + } + +BOOL SendAndCheck(struct ConnectionInfo * sockptr, unsigned char * MsgPtr, int len, int flags) +{ + int err; + int sent = send(sockptr->socket, MsgPtr, len, flags); + + if (sent == len) + return TRUE; // OK + + err = WSAGetLastError(); + + Debugprintf("TCP Send Failed - Sent %d should be %d err %d - requeue data", sent, len, err); + + if (err == 10035 || err == 115 || err == 36) //EWOULDBLOCK + { + // Save unsent data + + if (sent == -1) // -1 means none sent + sent = 0; + + sockptr->ResendBuffer = malloc(len - sent); + sockptr->ResendLen = len - sent; + + memmove(sockptr->ResendBuffer, MsgPtr + sent, len - sent); + } + return FALSE; +} + +VOID SendPortsForMonitor(SOCKET sock, int Secure) +{ + UCHAR PortInfo[3000] = {0xff, 0xff}; + UCHAR * ptr = &PortInfo[2]; + char ID[31] = ""; + struct PORTCONTROL * PORT; + int i, n, p; + + // Sends the ID of each Port to TermTCP + + p = GetNumberofPorts(); + + if (IncludesMail && Secure) + p++; + + ptr += sprintf(ptr, "%d|", p); + + if (IncludesMail && Secure) + { + p--; + ptr += sprintf(ptr,"0 Mail Monitor|"); + } + + for (n=1; n <= p; n++) + { + PORT = GetPortTableEntryFromSlot(n); + + memcpy(ID, PORT->PORTDESCRIPTION, 30); + + for (i = 29; i; i--) + { + if (ID[i] != ' ') + break; + + ID[i] = 0; + } + + ptr += sprintf(ptr,"%d %s|", PORT->PORTNUMBER, ID); + } + + + send(sock, PortInfo, (int)(ptr - PortInfo), 0); +} + +int ProcessLine(char * buf, int Port) +{ + UCHAR * ptr; + UCHAR * ptr1; + + char * p_ipad = 0; + char * p_port = 0; + unsigned short WINMORport = 0; + int len=510; + char errbuf[256]; + char * param; + char * value; + char *User, *Pwd, *UserCall, *Secure, * Appl; + int End = (int)strlen(buf) -1; + struct TNCINFO * TNC; + struct TCPINFO * TCP; + + strcpy(errbuf,buf); // save in case of error + + if (buf[End] == 10) + buf[End]=0; // remove newline + + if(buf[0] =='#') return (TRUE); // comment + + if(buf[0] ==';') return (TRUE); // comment + + ptr=strchr(buf,'='); + + if (!ptr) + ptr=strchr(buf,' '); + + if (!ptr) + return 0; + + if (TNCInfo[Port] == NULL) + { + TNC = TNCInfo[Port] = zalloc(sizeof(struct TNCINFO)); + TCP = TNC->TCPInfo = zalloc(sizeof (struct TCPINFO)); // Telnet Server Specific Data + + TCP->MaxSessions = 10; // Default Values + TNC->Hardware = H_TELNET; + TCP->IPV4 = TRUE; + TCP->SecureTelnet = 1; + strcpy(TCP->CMSServer, "cms.winlink.org"); + } + + TNC = TNCInfo[Port]; + TCP = TNC->TCPInfo; + + param=buf; + *(ptr)=0; + value=ptr+1; + + if (_stricmp(param, "IPV4") == 0) + TCP->IPV4 = atoi(value); + + else if (_stricmp(param, "IPV6") == 0) + TCP->IPV6 = atoi(value); + + else if (_stricmp(param, "CMS") == 0) + TCP->CMS = atoi(value); + + else if (_stricmp(param, "CMSPASS") == 0) + { + char Temp[80]; + + if (strlen(value) > 79) + value[79] = 0; + + strcpy(Temp, value); + strlop(Temp, 32); + strlop(Temp, 13); + strcpy(TCP->SecureCMSPassword, Temp); + + } + + else if (_stricmp(param, "CMSCALL") == 0) + { + if (strlen(value) > 9) + value[9] = 0; + strcpy(TCP->GatewayCall, value); + strlop(TCP->GatewayCall, 13); + _strupr(TCP->GatewayCall); + } + + else if (_stricmp(param, "CMSLOC") == 0) + { + if (strlen(value) > 9) + value[9] = 0; + strcpy(TCP->GatewayLoc, value); + strlop(TCP->GatewayLoc, 13); + _strupr(TCP->GatewayLoc); + } + + else if (_stricmp(param,"ReportHybrid") == 0) + TCP->ReportHybrid = atoi(value); + + else if (_stricmp(param, "HybridServiceCode") == 0) + { + TCP->HybridServiceCode = _strdup(value); + strlop(TCP->HybridServiceCode, 13); + strlop(TCP->HybridServiceCode, ';'); + _strupr(TCP->HybridServiceCode); + } + + else if (_stricmp(param, "HybridFrequencies") == 0) + { + TCP->HybridFrequencies = _strdup(value); + strlop(TCP->HybridFrequencies, 13); + strlop(TCP->HybridFrequencies, ' '); + _strupr(TCP->HybridFrequencies); + } + + else if (_stricmp(param, "HybridCoLocatedRMS") == 0) + { + TCP->HybridCoLocatedRMS = _strdup(value); + strlop(TCP->HybridCoLocatedRMS, 13); + strlop(TCP->HybridCoLocatedRMS, ' '); + _strupr(TCP->HybridCoLocatedRMS); + } + + else if (_stricmp(param,"LOGGING") == 0) + LogEnabled = atoi(value); + + else if (_stricmp(param,"CMSLOGGING") == 0) + CMSLogEnabled = atoi(value); + + else if (_stricmp(param,"DisconnectOnClose") == 0) + TCP->DisconnectOnClose = atoi(value); + + else if (_stricmp(param,"ReportRelayTraffic") == 0) + TCP->ReportRelayTraffic = atoi(value); + + else if (_stricmp(param,"SecureTelnet") == 0) + TCP->SecureTelnet = atoi(value); + + else if (_stricmp(param,"CloseOnDisconnect") == 0) + TCP->DisconnectOnClose = atoi(value); + + else if (_stricmp(param,"TCPPORT") == 0) + TCP->TCPPort = atoi(value); + + else if (_stricmp(param,"DRATSPORT") == 0) + TCP->DRATSPort = atoi(value); + + else if (_stricmp(param,"TRIMODEPORT") == 0) + TCP->TriModePort = atoi(value); + + else if (_stricmp(param,"HTTPPORT") == 0) + HTTPPort = TCP->HTTPPort = atoi(value); + + else if (_stricmp(param,"APIPORT") == 0) + TCP->APIPort = atoi(value); + + else if (_stricmp(param,"SYNCPORT") == 0) + TCP->SyncPort = atoi(value); + + else if (_stricmp(param,"SNMPPORT") == 0) + TCP->SNMPPort = atoi(value); + + else if ((_stricmp(param,"CMDPORT") == 0) || (_stricmp(param,"LINUXPORT") == 0)) + { + int n = 0; + char * context; + char * ptr = strtok_s(value, ", ", &context); + + while (ptr && n < 33) + { + TCP->CMDPort[n++] = atoi(ptr); + ptr = strtok_s(NULL, ", ", &context); + } + } + + else if (_stricmp(param,"CMSSERVER") == 0) + { + int n = 0; + char * context; + char * ptr = strtok_s(value, ", \r", &context); + + strcpy(TCP->CMSServer, ptr); + } + + else if (_stricmp(param,"RELAYHOST") == 0) + { + int n = 0; + char * context; + char * ptr = strtok_s(value, ", \r", &context); + + strcpy(TCP->RELAYHOST, ptr); + } + + + else if (_stricmp(param,"FALLBACKTORELAY") == 0) + { + int n = 0; + char * context; + char * ptr = strtok_s(value, ", \r", &context); + + TCP->FallbacktoRelay = atoi(value); + } + + else if (_stricmp(param,"FBBPORT") == 0) + { + int n = 0; + char * context; + char * ptr = strtok_s(value, ", ", &context); + + while (ptr && n < 99) + { + TCP->FBBPort[n++] = atoi(ptr); + ptr = strtok_s(NULL, ", ", &context); + } + } + + else if (_stricmp(param,"RELAYPORT") == 0) + TCP->RelayPort = atoi(value); + + else if (_stricmp(param,"RELAYAPPL") == 0) + { + if (TCP->RelayPort == 0) + TCP->RelayPort = 8772; + strcpy(TCP->RelayAPPL, value); + strcat(TCP->RelayAPPL, "\r"); + } + + else if (_stricmp(param,"SYNCAPPL") == 0) + { + if (TCP->SyncPort == 0) + TCP->SyncPort = 8780; + strcpy(TCP->SyncAPPL, value); + strcat(TCP->SyncAPPL, "\r"); + } + + // if (strcmp(param,"LOGINRESPONSE") == 0) cfgLOGINRESPONSE = value; + // if (strcmp(param,"PASSWORDRESPONSE") == 0) cfgPASSWORDRESPONSE = value; + + else if (_stricmp(param,"LOGINPROMPT") == 0) + { + ptr1 = strchr(value, 13); + if (ptr1) *ptr1 = 0; + strcpy(TCP->LoginMsg,value); + } + + else if (_stricmp(param,"PASSWORDPROMPT") == 0) + { + ptr1 = strchr(value, 13); + if (ptr1) *ptr1 = 0; + strcpy(TCP->PasswordMsg, value); + } + + else if (_stricmp(param,"HOSTPROMPT") == 0) + strcpy(TCP->cfgHOSTPROMPT, value); + + else if (_stricmp(param,"LOCALECHO") == 0) + strcpy(TCP->cfgLOCALECHO, value); + + else if (_stricmp(param,"MAXSESSIONS") == 0) + { + TCP->MaxSessions = atoi(value); + if (TCP->MaxSessions > MaxSockets ) TCP->MaxSessions = MaxSockets; + } + + else if (_stricmp(param,"CTEXT") == 0 ) + { + int len = (int)strlen (value); + + if (value[len -1] == ' ') + value[len -1] = 0; + + strcpy(TCP->cfgCTEXT, value); + + // Replace \n Signon string with cr lf + + ptr = &TCP->cfgCTEXT[0]; + +scanCTEXT: + + ptr = strstr(ptr, "\\n"); + + if (ptr) + { + *(ptr++)=13; // put in cr + *(ptr++)=10; // put in lf + + goto scanCTEXT; + } + } + + else if (_stricmp(param,"LOCALNET") == 0) + { + uint32_t Network, Mask; + uint32_t IPMask; + char * Netptr, * MaskPtr, *Context; + struct LOCALNET * LocalNet; + int Bits = 24; + + Netptr = strtok_s(value, " /;", &Context); + + if (Netptr) + { + Network = inet_addr(Netptr); + MaskPtr = strtok_s(NULL, " /;", &Context); + + if (MaskPtr) + { + Bits = atoi(MaskPtr); + + if (Bits > 32) + Bits = 32; + } + + if (Bits == 0) + IPMask = 0; + else + IPMask = (0xFFFFFFFF) << (32 - Bits); + + Mask = htonl(IPMask); // Needs to be Network order + + LocalNet = (struct LOCALNET *)zalloc(sizeof(struct LOCALNET)); + + LocalNet->Network = Network; + LocalNet->Mask = Mask; + LocalNet->Next = TNC->TCPInfo->LocalNets; + + TNC->TCPInfo->LocalNets = LocalNet; + + } + } + + + + + else if (_stricmp(param,"USER") == 0) + { + struct UserRec * USER; + char Param[8][256]; + char * ptr1, * ptr2; + int n = 0; + + // USER=user,password,call,appl,SYSOP + + memset(Param, 0, 2048); + strlop(value, 13); + strlop(value, ';'); + + ptr1 = value; + + while (ptr1 && *ptr1 && n < 8) + { + ptr2 = strchr(ptr1, ','); + if (ptr2) *ptr2++ = 0; + + strcpy(&Param[n][0], ptr1); + strlop(Param[n++], ' '); + ptr1 = ptr2; + while(ptr1 && *ptr1 && *ptr1 == ' ') + ptr1++; + } + + + User = &Param[0][0]; + + if (_stricmp(User, "ANON") == 0) + { + strcpy(&Param[2][0], "ANON"); + strcpy(&Param[4][0], ""); // Dont allow SYSOP if ANON + } + + Pwd = &Param[1][0]; + UserCall = &Param[2][0]; + Appl = &Param[3][0]; + Secure = &Param[4][0]; + + if (User[0] == 0 || Pwd[0] == 0 || UserCall[0] == 0) // invalid record + return 0; + + _strupr(UserCall); + + if (TCP->NumberofUsers == 0) + TCP->UserRecPtr = zalloc(sizeof(void *)); + else + TCP->UserRecPtr = realloc(TCP->UserRecPtr, (TCP->NumberofUsers+1) * sizeof(void *)); + + USER = zalloc(sizeof(struct UserRec)); + + TCP->UserRecPtr[TCP->NumberofUsers] = USER; + + USER->Callsign = _strdup(UserCall); + USER->Password = _strdup(Pwd); + USER->UserName = _strdup(User); + USER->Appl = zalloc(32); + USER->Secure = FALSE; + + if (_stricmp(Secure, "SYSOP") == 0) + USER->Secure = TRUE; + + if (Appl[0] && strcmp(Appl, "\"\"") != 0) + { + strcpy(USER->Appl, _strupr(Appl)); + strcat(USER->Appl, "\r\n"); + } + TCP->NumberofUsers += 1; + } + else if (_memicmp(errbuf, "WL2KREPORT", 10) == 0) + TNC->WL2K = DecodeWL2KReportLine(errbuf); + else if (_stricmp(param,"WebTermCSS") == 0) + { + TCP->WebTermCSS = _strdup(value); + } + else + return FALSE; + + return TRUE; +} + +static int MaxStreams = 26; + +void CheckRX(struct TNCINFO * TNC); +VOID TelnetPoll(int Port); +VOID ProcessTermModeResponse(struct TNCINFO * TNC); +VOID DoTNCReinit(struct TNCINFO * TNC); +VOID DoTermModeTimeout(struct TNCINFO * TNC); + +VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len); + + +static VOID WritetoTrace(int Stream, char * Msg, int Len, struct ADIF * ADIF, char Dirn) +{ + int index = 0; + UCHAR * ptr1 = Msg, * ptr2; + UCHAR Line[1000]; + int LineLen, i; + char logmsg[200]; + + Msg[Len] = 0; + +lineloop: + + if (Len > 0) + { + // copy text to file a line at a time + + ptr2 = memchr(ptr1, 13 , Len); + + if (ptr2) + { + ptr2++; + LineLen = (int)(ptr2 - ptr1); + Len -= LineLen; + + if (LineLen > 900) + goto Skip; + + memcpy(Line, ptr1, LineLen); + memcpy(&Line[LineLen - 1], "", 4); + LineLen += 3; + + if ((*ptr2) == 10) + { + memcpy(&Line[LineLen], "", 4); + LineLen += 4; + ptr2++; + Len --; + } + + Line[LineLen] = 0; + + // If line contains any data above 7f, assume binary and dont display + + for (i = 0; i < LineLen; i++) + { + if (Line[i] > 127 || Line[i] < 32) + goto Skip; + } + + if (strlen(Line) < 100) + { + sprintf(logmsg,"%d %s\r\n", Stream, Line); + WriteCMSLog(logmsg); + UpdateADIFRecord(ADIF, Line, Dirn); + } + +Skip: + ptr1 = ptr2; + goto lineloop; + } + + // No CR + + for (i = 0; i < Len; i++) + { + if (ptr1[i] > 127) + break; + } + + if (i == Len) // No binary data + { + if (strlen(ptr1) < 100) + { + sprintf(logmsg,"%d %s\r\n", Stream, ptr1); + WriteCMSLog(logmsg); + UpdateADIFRecord(ADIF, ptr1, Dirn); + } + } + } +} + +static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) +{ + int txlen = 0, n; + PMSGWITHLEN buffptr; + struct TNCINFO * TNC = TNCInfo[port]; + struct TCPINFO * TCP; + + int Stream; + struct ConnectionInfo * sockptr; + struct STREAMINFO * STREAM; + + if (TNC == NULL) + return 0; // Not configured + + switch (fn) + { + case 7: + + // 100 mS Timer. Now needed, as Poll can be called more frequently in some circuymstances + + while (TNC->PortRecord->UI_Q) // Release anything accidentally put on UI_Q + { + buffptr = Q_REM(&TNC->PortRecord->UI_Q); + ReleaseBuffer(buffptr); + } + + TCP = TNC->TCPInfo; + + if (TCP->CMS) + { + TCP->CheckCMSTimer++; + + if (TCP->CMSOK) + { + if (TCP->CheckCMSTimer > 600 * 15) + CheckCMS(TNC); + } + else + { + if (TCP->CheckCMSTimer > 600 * 2) + CheckCMS(TNC); + } + } + + // We now use persistent HTTP sessions, so need to close after a reasonable time + + for (n = 0; n <= TCP->MaxSessions; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + + if (sockptr->SocketActive) + { + if (sockptr->HTTPMode) + { + if (sockptr->WebSocks == 0) + { + if (sockptr->LastSendTime && (REALTIMETICKS - sockptr->LastSendTime) > 1500) // ~ 2.5 mins + { + closesocket(sockptr->socket); + sockptr->SocketActive = FALSE; + ShowConnections(TNC); + } + } + } + else + { + // Time out Login + + if (sockptr->LoginState < 2 && (time(NULL) - sockptr->ConnectTime) > 30) + { + closesocket(sockptr->socket); + sockptr->SocketActive = FALSE; + ShowConnections(TNC); + } + } + } + } + + + + return 0; + + case 1: // poll + + for (Stream = 0; Stream <= MaxStreams; Stream++) + { + TRANSPORTENTRY * SESS; + struct ConnectionInfo * sockptr = TNC->Streams[Stream].ConnectionInfo; + + if (sockptr && sockptr->UserPointer == &CMSUser) // Connected to CMS + { + SESS = TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]; + + if (SESS) + { + n = SESS->L4KILLTIMER; + if (n < (SESS->L4LIMIT - 120)) + { + SESS->L4KILLTIMER = SESS->L4LIMIT - 120; + SESS = SESS->L4CROSSLINK; + if (SESS) + SESS->L4KILLTIMER = SESS->L4LIMIT - 120; + } + } + } + + STREAM = &TNC->Streams[Stream]; + + if (STREAM->NeedDisc) + { + STREAM->NeedDisc--; + + if (STREAM->NeedDisc == 0) + { + // Send the DISCONNECT + + STREAM->ReportDISC = TRUE; + } + } + + if (STREAM->ReportDISC) + { + STREAM->ReportDISC = FALSE; + buff->PORT = Stream; + + return -1; + } + } + + TelnetPoll(port); + + for (Stream = 0; Stream <= MaxStreams; Stream++) + { + STREAM = &TNC->Streams[Stream]; + + if (STREAM->PACTORtoBPQ_Q !=0) + { + int datalen; + + buffptr = Q_REM(&STREAM->PACTORtoBPQ_Q); + + datalen = (int)buffptr->Len; + + buff->PORT = Stream; + buff->PID = 0xf0; + memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte + datalen += sizeof(void *) + 4; + + PutLengthinBuffer(buff, datalen); + + ReleaseBuffer(buffptr); + return (1); + } + } + + return 0; + + case 2: // send + + buffptr = GetBuff(); + + if (buffptr == 0) return (0); // No buffers, so ignore + + // Find TNC Record + + Stream = buff->PORT; + STREAM = &TNC->Streams[Stream]; + + txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1); // 1 as no PID + + buffptr->Len = txlen; + memcpy(&buffptr->Data, &buff->L2DATA, txlen); + + C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr); + STREAM->FramesQueued++; + + return (0); + + + case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding + + Stream = (int)(size_t)buff; + + STREAM = &TNC->Streams[Stream]; + + if (STREAM->FramesQueued > 40) + return (257); // Busy + + return 256; // OK + +#define SD_BOTH 0x02 + + case 4: // reinit + { + struct _EXTPORTDATA * PortRecord; + +#ifndef LINBPQ + HWND SavehDlg, SaveCMS, SaveMonitor; + HMENU SaveMenu1, SaveMenu2, SaveMenu3; +#endif + int n, i; + + if (!ProcessConfig()) + { + Consoleprintf("Failed to reread config file - leaving config unchanged"); + break; + } + + FreeConfig(); + + for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + sockptr->SocketActive = FALSE; + closesocket(sockptr->socket); + } + + TCP = TNC->TCPInfo; + + shutdown(TCP->TCPSock, SD_BOTH); + shutdown(TCP->sock6, SD_BOTH); + + n = 0; + while (TCP->FBBsock[n]) + shutdown(TCP->FBBsock[n++], SD_BOTH); + + shutdown(TCP->Relaysock, SD_BOTH); + shutdown(TCP->HTTPsock, SD_BOTH); + shutdown(TCP->HTTPsock6, SD_BOTH); + + + n = 0; + while (TCP->FBBsock6[n]) + shutdown(TCP->FBBsock[n++], SD_BOTH); + + shutdown(TCP->Relaysock6, SD_BOTH); + Sleep(500); + + closesocket(TCP->TCPSock); + closesocket(TCP->sock6); + + n = 0; + while (TCP->FBBsock[n]) + closesocket(TCP->FBBsock[n++]); + + n = 0; + while (TCP->FBBsock6[n]) + closesocket(TCP->FBBsock6[n++]); + + closesocket(TCP->Relaysock); + closesocket(TCP->Relaysock6); + closesocket(TCP->HTTPsock); + closesocket(TCP->HTTPsock6); + + // Save info from old TNC record + + n = TNC->Port; + PortRecord = TNC->PortRecord; +#ifndef LINBPQ + SavehDlg = TNC->hDlg; + SaveCMS = TCP->hCMSWnd; + SaveMonitor = TNC->hMonitor; + SaveMenu1 = TCP->hActionMenu; + SaveMenu2 = TCP->hDisMenu; + SaveMenu3 = TCP->hLogMenu; +#endif + // Free old TCP Session Stucts + + for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++) + { + free(TNC->Streams[i].ConnectionInfo); + } + + ReadConfigFile(TNC->Port, ProcessLine); + + TNC = TNCInfo[n]; + TNC->Port = n; + TNC->Hardware = H_TELNET; + TNC->RIG = &TNC->DummyRig; // Not using Rig control, so use Dummy + + // Get Menu Handles + + TCP = TNC->TCPInfo; +#ifndef LINBPQ + TNC->hDlg = SavehDlg; + TCP->hCMSWnd = SaveCMS; + TNC->hMonitor = SaveMonitor; + TCP->hActionMenu = SaveMenu1; + TCP->hDisMenu = SaveMenu2; + TCP->hLogMenu = SaveMenu3; + + CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TNC->TCPInfo->CMS<<3); + CheckMenuItem(TCP->hLogMenu, 0, MF_BYPOSITION | LogEnabled<<3); + CheckMenuItem(TCP->hLogMenu, 1, MF_BYPOSITION | CMSLogEnabled<<3); +#endif + // Malloc TCP Session Stucts + + for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++) + { + TNC->Streams[i].ConnectionInfo = zalloc(sizeof(struct ConnectionInfo)); + TCP->CurrentSockets = i; //Record max used to save searching all entries +#ifndef LINBPQ + if (i > 0) + ModifyMenu(TCP->hDisMenu,i - 1 ,MF_BYPOSITION | MF_STRING,IDM_DISCONNECT + 1, "."); +#endif + } + + TNC->PortRecord = PortRecord; + + Sleep(500); + OpenSockets(TNC); + OpenSockets6(TNC); + SetupListenSet(TNC); + CheckCMS(TNC); + ShowConnections(TNC); + } + + break; + + case 5: // Close + + TCP = TNC->TCPInfo; + + for (n = 1; n <= TCP->CurrentSockets; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + closesocket(sockptr->socket); + } + + shutdown(TCP->TCPSock, SD_BOTH); + + n = 0; + while (TCP->FBBsock[n]) + shutdown(TCP->FBBsock[n++], SD_BOTH); + + shutdown(TCP->Relaysock, SD_BOTH); + shutdown(TCP->HTTPsock, SD_BOTH); + shutdown(TCP->HTTPsock6, SD_BOTH); + + shutdown(TCP->sock6, SD_BOTH); + + n = 0; + while (TCP->FBBsock6[n]) + shutdown(TCP->FBBsock6[n++], SD_BOTH); + + shutdown(TCP->Relaysock6, SD_BOTH); + + Sleep(500); + closesocket(TCP->TCPSock); + + n = 0; + while (TCP->FBBsock[n]) + closesocket(TCP->FBBsock[n++]); + + closesocket(TCP->Relaysock); + + closesocket(TCP->sock6); + + n = 0; + while (TCP->FBBsock6[n]) + closesocket(TCP->FBBsock6[n++]); + + closesocket(TCP->Relaysock6); + closesocket(TCP->HTTPsock); + closesocket(TCP->HTTPsock6); + + return (0); + + case 6: // Scan Control + + return 0; // None Yet + + } + return 0; + +} + + + +static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL) +{ + int Len; + char msg[256]; + struct ConnectionInfo * sockptr; + int i,n; + + char CMSStatus[80] = ""; + + if (TNC->TCPInfo->CMS) + { + if (TNC->TCPInfo->CMSOK) + strcpy(CMSStatus, "CMS Ok"); + else + strcpy(CMSStatus, "No CMS"); + } + + Len = sprintf(Buff, "" + "Telnet StatusTelnet Status         %s", CMSStatus); + + Len += sprintf(&Buff[Len], ""); + + + Len += sprintf(&Buff[Len], ""); + + for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++) + { + sockptr=TNC->Streams[n].ConnectionInfo; + + if (!sockptr->SocketActive) + { + strcpy(msg,""); + } + else + { + if (sockptr->UserPointer == 0) + { + if (sockptr->HTTPMode) + { + char Addr[100]; + Tel_Format_Addr(sockptr, Addr); + if (sockptr->WebSocks) + sprintf(msg,"", Addr); + else + sprintf(msg,"", Addr); + } + else if (sockptr->DRATSMode) + { + char Addr[100]; + Tel_Format_Addr(sockptr, Addr); + sprintf(msg,"", Addr); + } + else + strcpy(msg,""); + } + else + { + i=sprintf(msg,"", + sockptr->UserPointer->UserName, sockptr->Callsign, + sockptr->FromHostBuffPutptr - sockptr->FromHostBuffGetptr); + } + } + Len += sprintf(&Buff[Len], "%s", msg); + } + + Len += sprintf(&Buff[Len], "
UserCallsignQueue
Idle  
Websock<%s  
HTTP<%s  
DRATS<%s  
Logging in  
%s%s%d
"); + return Len; +} + + + +void * TelnetExtInit(EXTPORTDATA * PortEntry) +{ + char msg[500]; + struct TNCINFO * TNC; + struct TCPINFO * TCP; + int port; + char * ptr; + int i; + HWND x=0; + +/* + UCHAR NC[257]; + WCHAR WC[1024]; + + int WLen, NLen; + + UINT UTF[256] = {0}; + UINT UTFL[256]; + + int n, u; + + for (n = 0; n < 256; n++) + NC[n] =n ; + + n = MultiByteToWideChar(437, 0, NC, 256, &WC[0], 1024); + + for (n = 0; n < 256; n++) + UTFL[n] = WideCharToMultiByte(CP_UTF8, 0, &WC[n], 1, &UTF[n], 1024 , NULL, NULL); + + // write UTF8 data as source + + { + HANDLE Handle; + int i, n, Len; + char Line [256]; + + + Handle = CreateFile("c:\\UTF8437Data.c", GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + + n = wsprintf (Line, "unsigned int CP437toUTF8Data[128] = {\r\n"); + + WriteFile(Handle, Line ,n , &n, NULL); + + if (Handle != INVALID_HANDLE_VALUE) + { + for (i = 128; i < 256; i += 4) + { + n = wsprintf (Line, " %d, %d, %d, %d, \r\n", + UTF[i], UTF[i+1], UTF[i+2], UTF[i+3]); + WriteFile(Handle, Line ,n , &n, NULL); + + } + + WriteFile(Handle, "};\r\n", 4, &n, NULL); + } + n = wsprintf (Line, "unsigned int CP437toUTF8DataLen[128] = {\r\n"); + + WriteFile(Handle, Line ,n , &n, NULL); + + if (Handle != INVALID_HANDLE_VALUE) + { + for (i = 128; i < 256;i += 4) + { + n = wsprintf (Line, " %d, %d, %d, %d, \r\n", + UTFL[i], UTFL[i+1], UTFL[i+2], UTFL[i+3]); + WriteFile(Handle, Line ,n , &n, NULL); + + } + + WriteFile(Handle, "};\r\n", 4, &n, NULL); + + SetEndOfFile(Handle); + + CloseHandle(Handle); + } + } +*/ + + DeleteTelnetLogFiles(); + + initUTF8(); + + sprintf(msg,"Telnet Server "); + WritetoConsoleLocal(msg); + + port=PortEntry->PORTCONTROL.PORTNUMBER; + + ReadConfigFile(port, ProcessLine); + + TNC = TNCInfo[port]; + + if (TNC == NULL) + { + // Not defined in Config file + + WritetoConsoleLocal("\n"); + return ExtProc; + } + + TCP = TNC->TCPInfo; + + TNC->Port = port; + + TNC->Hardware = H_TELNET; + + PortEntry->MAXHOSTMODESESSIONS = TNC->TCPInfo->MaxSessions + 1; // Default + + TNC->PortRecord = PortEntry; + + if (PortEntry->PORTCONTROL.PORTCALL[0] != 0) + ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall); + + PortEntry->PORTCONTROL.PROTOCOL = 10; // WINMOR/Pactor + PortEntry->PORTCONTROL.PORTQUALITY = 0; + PortEntry->SCANCAPABILITIES = NONE; // No Scan Control + PortEntry->PERMITGATEWAY = TRUE; + + ptr=strchr(TNC->NodeCall, ' '); + if (ptr) *(ptr) = 0; // Null Terminate + + TELNETMONVECPTR->HOSTAPPLFLAGS = 0x80; // Requext Monitoring + + if (TCP->LoginMsg[0] == 0) + strcpy(TCP->LoginMsg, "user:"); + if (TCP->PasswordMsg[0] == 0) + strcpy(TCP->PasswordMsg, "password:"); + if (TCP->cfgCTEXT[0] == 0) + { + char Call[10]; + memcpy(Call, MYNODECALL, 10); + strlop(Call, ' '); + + sprintf(TCP->cfgCTEXT, "Connected to %s's Telnet Server\r\n\r\n", Call); + } + + PortEntry->PORTCONTROL.TNC = TNC; + + TNC->WebWindowProc = WebProc; + TNC->WebWinX = 260; + TNC->WebWinY = 325; + +#ifndef LINBPQ + + CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, TelWndProc, 400, 300, NULL); + + TCP->hCMSWnd = CreateWindowEx(0, "STATIC", "CMS OK ", WS_CHILD | WS_VISIBLE, + 240,0,60,16, TNC->hDlg, NULL, hInstance, NULL); + + SendMessage(TCP->hCMSWnd, WM_SETFONT, (WPARAM)hFont, 0); + + x = CreateWindowEx(0, "STATIC", " User Callsign Queue", WS_CHILD | WS_VISIBLE, + 0,0,240,16, TNC->hDlg, NULL, hInstance, NULL); + + SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0); + + + TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | WS_VSCROLL, + 0,20,400,2800, TNC->hDlg, NULL, hInstance, NULL); + + SendMessage(TNC->hMonitor, WM_SETFONT, (WPARAM)hFont, 0); + + hPopMenu = CreatePopupMenu(); + hPopMenu2 = CreatePopupMenu(); + hPopMenu3 = CreatePopupMenu(); + + AppendMenu(hPopMenu, MF_STRING + MF_POPUP, (UINT)hPopMenu2,"Logging Options"); + AppendMenu(hPopMenu, MF_STRING + MF_POPUP, (UINT)hPopMenu3,"Disconnect User"); + AppendMenu(hPopMenu, MF_STRING, TELNET_RECONFIG, "ReRead Config"); + AppendMenu(hPopMenu, MF_STRING, CMSENABLED, "CMS Access Enabled"); + AppendMenu(hPopMenu, MF_STRING, USECACHEDCMS, "Using Cached CMS Addresses"); + + AppendMenu(hPopMenu2, MF_STRING, IDM_LOGGING, "Log incoming connections"); + AppendMenu(hPopMenu2, MF_STRING, IDM_CMS_LOGGING, "Log CMS Connections"); + + AppendMenu(hPopMenu3, MF_STRING, IDM_DISCONNECT, "1"); + + TCP->hActionMenu = hPopMenu; + + CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3); + + TCP->hLogMenu = hPopMenu2; + TCP->hDisMenu = hPopMenu3; + + CheckMenuItem(TCP->hLogMenu, 0, MF_BYPOSITION | LogEnabled<<3); + CheckMenuItem(TCP->hLogMenu, 1, MF_BYPOSITION | CMSLogEnabled<<3); + +// ModifyMenu(hMenu, 1, MF_BYPOSITION | MF_OWNERDRAW | MF_STRING, 10000, 0); + +#endif + + // Malloc TCP Session Stucts + + for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++) + { + TNC->Streams[i].ConnectionInfo = zalloc(sizeof(struct ConnectionInfo)); + TNC->Streams[i].ConnectionInfo->Number = i; + TCP->CurrentSockets = i; //Record max used to save searching all entries + + sprintf(msg,"%d", i); + +#ifndef LINBPQ + if (i > 1) + AppendMenu(TCP->hDisMenu, MF_STRING, IDM_DISCONNECT ,msg); +#endif + } + + OpenSockets(TNC); + OpenSockets6(TNC); + SetupListenSet(TNC); + TNC->RIG = &TNC->DummyRig; // Not using Rig control, so use Dummy + + if (TCP->CMS) + CheckCMS(TNC); + + WritetoConsoleLocal("\n"); + + ShowConnections(TNC); + + if (TCP->ReportHybrid) + SendWL2KRegisterHybrid(TNC); + + + return ExtProc; +} + +SOCKET OpenUDPSocket(struct TNCINFO * TNC) +{ + u_long param = 1; + struct sockaddr_in sinx; + int err, ret; + struct TCPINFO * TCP = TNC->TCPInfo; + char Msg[80]; + + TCP->SNMPsock = socket(AF_INET,SOCK_DGRAM,0); + + if (TCP->SNMPsock == INVALID_SOCKET) + { + WritetoConsoleLocal("Failed to create SNMP UDP socket"); + return 0; + } + + ioctl (TCP->SNMPsock, FIONBIO, ¶m); + + sinx.sin_family = AF_INET; + sinx.sin_addr.s_addr = INADDR_ANY; + + sinx.sin_port = htons(TCP->SNMPPort); + + ret = bind(TCP->SNMPsock, (struct sockaddr *) &sinx, sizeof(sinx)); + + if (ret != 0) + { + // Bind Failed + + err = WSAGetLastError(); + sprintf(Msg, "Bind Failed for SNMP UDP socket %d - error code = %d", TCP->SNMPPort, err); + WritetoConsoleLocal(Msg); + return 0; + } + + return TCP->SNMPsock; +} + + + +SOCKET OpenSocket4(struct TNCINFO * xTNC, int port) +{ + struct sockaddr_in local_sin; /* Local socket - internet style */ + struct sockaddr_in * psin; + SOCKET sock = 0; + u_long param=1; + + char szBuff[80]; + + psin=&local_sin; + psin->sin_family = AF_INET; + psin->sin_addr.s_addr = INADDR_ANY; + + if (port) + { + sock = socket(AF_INET, SOCK_STREAM, 0); + + if (sock == INVALID_SOCKET) + { + sprintf(szBuff, "socket() failed error %d\n", WSAGetLastError()); + WritetoConsoleLocal(szBuff); + return 0; + } + + setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *)¶m,4); + + + psin->sin_port = htons(port); // Convert to network ordering + + if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) + { + sprintf(szBuff, "bind(sock) failed port %d Error %d\n", port, WSAGetLastError()); + WritetoConsoleLocal(szBuff); + closesocket( sock ); + return FALSE; + } + + if (listen( sock, MAX_PENDING_CONNECTS ) < 0) + { + sprintf(szBuff, "listen(sock) failed port %d Error %d\n", port, WSAGetLastError()); + WritetoConsoleLocal(szBuff); + return FALSE; + } + ioctl(sock, FIONBIO, ¶m); + } + + return sock; +} + +BOOL OpenSockets(struct TNCINFO * TNC) +{ + struct sockaddr_in local_sin; /* Local socket - internet style */ + struct sockaddr_in * psin; + u_long param=1; + struct TCPINFO * TCP = TNC->TCPInfo; + int n; + + if (!TCP->IPV4) + return TRUE; + + psin=&local_sin; + psin->sin_family = AF_INET; + psin->sin_addr.s_addr = INADDR_ANY; + + if (TCP->TCPPort) + TCP->TCPSock = OpenSocket4(TNC, TCP->TCPPort); + + n = 0; + + while (TCP->FBBPort[n]) + { + TCP->FBBsock[n] = OpenSocket4(TNC, TCP->FBBPort[n]); + n++; + } + + if (TCP->RelayPort) + TCP->Relaysock = OpenSocket4(TNC, TCP->RelayPort); + + if (TCP->TriModePort) + { + TCP->TriModeSock = OpenSocket4(TNC, TCP->TriModePort); + TCP->TriModeDataSock = OpenSocket4(TNC, TCP->TriModePort + 1); + } + + if (TCP->HTTPPort) + TCP->HTTPsock = OpenSocket4(TNC, TCP->HTTPPort); + + if (TCP->APIPort) + TCP->APIsock = OpenSocket4(TNC, TCP->APIPort); + + if (TCP->SyncPort) + TCP->Syncsock = OpenSocket4(TNC, TCP->SyncPort); + + if (TCP->DRATSPort) + TCP->DRATSsock = OpenSocket4(TNC, TCP->DRATSPort); + + if (TCP->SNMPPort) + TCP->SNMPsock = OpenUDPSocket(TNC); + + CMSUser.UserName = _strdup("CMS"); + + TriModeUser.Secure = TRUE; + TriModeUser.UserName = _strdup("TRIMODE"); + TriModeUser.Callsign = zalloc(10); + + return TRUE; +} + +SOCKET OpenSocket6(struct TNCINFO * TNC, int port) +{ + + struct sockaddr_in6 local_sin; /* Local socket - internet style */ + struct sockaddr_in6 * psin; + SOCKET sock; + char szBuff[80]; + u_long param=1; + + memset(&local_sin, 0, sizeof(local_sin)); + + psin=&local_sin; + psin->sin6_family = AF_INET6; + psin->sin6_addr = in6addr_any; + psin->sin6_flowinfo = 0; + psin->sin6_scope_id = 0; + + sock = socket(AF_INET6, SOCK_STREAM, 0); + +#ifndef WIN32 + + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, ¶m, sizeof(param)) < 0) + { + perror("setting option IPV6_V6ONLY"); + } + +#endif + + if (sock == INVALID_SOCKET) + { + sprintf(szBuff, "IPV6 socket() failed error %d\n", WSAGetLastError()); + WritetoConsoleLocal(szBuff); + return FALSE; + } + + psin->sin6_port = htons(port); // Convert to network ordering + + if (bind(sock, (struct sockaddr FAR *)psin, sizeof(local_sin)) == SOCKET_ERROR) + { + sprintf(szBuff, "IPV6 bind(sock) failed Port %d Error %d\n", port, WSAGetLastError()); + WritetoConsoleLocal(szBuff); + closesocket( sock ); + + return FALSE; + } + + if (listen( sock, MAX_PENDING_CONNECTS ) < 0) + { + sprintf(szBuff, "IPV6 listen(sock) failed Error %d\n", WSAGetLastError()); + WritetoConsoleLocal(szBuff); + + return FALSE; + } + + ioctl(sock, FIONBIO, ¶m); + return sock; +} + + +BOOL OpenSockets6(struct TNCINFO * TNC) +{ + struct sockaddr_in6 local_sin; /* Local socket - internet style */ + + struct sockaddr_in6 * psin; + struct TCPINFO * TCP = TNC->TCPInfo; + int n; + u_long param=1; + + if (!TCP->IPV6) + return TRUE; + + memset(&local_sin, 0, sizeof(local_sin)); + + psin=&local_sin; + psin->sin6_family = AF_INET6; + psin->sin6_addr = in6addr_any; + psin->sin6_flowinfo = 0; + psin->sin6_scope_id = 0; + + + if (TCP->TCPPort) + TCP->sock6 = OpenSocket6(TNC, TCP->TCPPort); + + n = 0; + + while (TCP->FBBPort[n]) + { + TCP->FBBsock6[n] = OpenSocket6(TNC, TCP->FBBPort[n]); + n++; + } + + if (TCP->RelayPort) + TCP->Relaysock6 = OpenSocket6(TNC, TCP->RelayPort); + + if (TCP->HTTPPort) + TCP->HTTPsock6 = OpenSocket6(TNC, TCP->HTTPPort); + + if (TCP->APIPort) + TCP->APIsock6 = OpenSocket6(TNC, TCP->APIPort); + + if (TCP->SyncPort) + TCP->Syncsock6 = OpenSocket6(TNC, TCP->SyncPort); + + if (TCP->DRATSPort) + TCP->DRATSsock6 = OpenSocket6(TNC, TCP->DRATSPort); + + + CMSUser.UserName = _strdup("CMS"); + + return TRUE; +} + +static VOID SetupListenSet(struct TNCINFO * TNC) +{ + // Set up master set of fd's for checking for incoming calls + + struct TCPINFO * TCP = TNC->TCPInfo; + SOCKET maxsock = 0; + int n; + fd_set * readfd = &TCP->ListenSet; + SOCKET sock; + + FD_ZERO(readfd); + + n = 0; + while (n < 100) + { + sock = TCP->FBBsock[n++]; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + } + + sock = TCP->TCPSock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->Relaysock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->HTTPsock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->APIsock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->Syncsock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->DRATSsock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->TriModeSock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->TriModeDataSock; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + n = 0; + while (n < 100) + { + sock = TCP->FBBsock6[n++]; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + } + + sock = TCP->sock6; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->Relaysock6; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->HTTPsock6; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->APIsock6; + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + + sock = TCP->DRATSsock6; + + if (sock) + { + FD_SET(sock, readfd); + if (sock > maxsock) + maxsock = sock; + } + TCP->maxsock = maxsock; +} + + +VOID TelnetPoll(int Port) +{ + struct TNCINFO * TNC = TNCInfo[Port]; + UCHAR * Poll = TNC->TXBuffer; + struct TCPINFO * TCP = TNC->TCPInfo; + struct STREAMINFO * STREAM; + int Msglen; + int Stream; + + // we now poll for incoming connections + + struct timeval timeout; + int retval; + int n; + struct ConnectionInfo * sockptr; + SOCKET sock; + int Active = 0; + SOCKET maxsock; + + fd_set readfd, writefd, exceptfd; + timeout.tv_sec = 0; + timeout.tv_usec = 0; // poll + + if (TCP->maxsock == 0) + goto nosocks; + + memcpy(&readfd, &TCP->ListenSet, sizeof(fd_set)); + + retval = select((int)(TCP->maxsock) + 1, &readfd, NULL, NULL, &timeout); + + if (retval == -1) + { + retval = WSAGetLastError(); + perror("listen select"); + } + + if (retval) + { + n = 0; + while (TCP->FBBsock[n]) + { + sock = TCP->FBBsock[n]; + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->FBBPort[n]); + + n++; + } + + sock = TCP->TCPSock; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->TCPPort); + } + + sock = TCP->TriModeSock; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->TriModePort); + } + sock = TCP->TriModeDataSock; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->TriModePort + 1); + } + + sock = TCP->Relaysock; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->RelayPort); + } + + sock = TCP->HTTPsock; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->HTTPPort); + } + + sock = TCP->DRATSsock; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->DRATSPort); + } + + sock = TCP->Syncsock; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->SyncPort); + } + + + + n = 0; + + while (TCP->FBBsock6[n]) + { + sock = TCP->FBBsock6[n]; + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->FBBPort[n]); + n++; + } + + sock = TCP->sock6; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->TCPPort); + } + + sock = TCP->Relaysock6; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->RelayPort); + } + + sock = TCP->HTTPsock6; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->HTTPPort); + } + + sock = TCP->DRATSsock6; + if (sock) + { + if (FD_ISSET(sock, &readfd)) + Socket_Accept(TNC, sock, TCP->DRATSPort); + } + } + + // look for data on any active sockets + + maxsock = 0; + + FD_ZERO(&readfd); + FD_ZERO(&writefd); + FD_ZERO(&exceptfd); + + for (n = 0; n <= TCP->MaxSessions; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + + // Should we use write event after a blocked write ???? + + if (sockptr->SocketActive) + { +// if (sockptr->socket == 0) +// { +// Debugprintf("Active Session but zero socket"); +// DataSocket_Disconnect(TNC, sockptr); +// return; +// } + + if (TNC->Streams[n].Connecting) + { + // look for complete or failed + + FD_SET(sockptr->socket, &writefd); + FD_SET(sockptr->socket, &exceptfd); + } + else + { + FD_SET(sockptr->socket, &readfd); + FD_SET(sockptr->socket, &exceptfd); + } + Active++; + if (sockptr->socket > maxsock) + maxsock = sockptr->socket; + + if (sockptr->TriModeDataSock) + { + FD_SET(sockptr->TriModeDataSock, &readfd); + FD_SET(sockptr->TriModeDataSock, &exceptfd); + + if (sockptr->TriModeDataSock > maxsock) + maxsock = sockptr->TriModeDataSock; + } + } + } + + if (Active) + { + retval = select((int)maxsock + 1, &readfd, &writefd, &exceptfd, &timeout); + + if (retval == -1) + { + perror("data select"); + Debugprintf("Telnet Select Error %d Active %d", WSAGetLastError(), Active); + + for (n = 0; n <= TCP->MaxSessions; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + if (sockptr->SocketActive) + Debugprintf("Active Session %d socket %d", n, sockptr->socket); + } + } + else + { + if (retval) + { + // see who has data + + for (n = 0; n <= TCP->MaxSessions; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + + if (sockptr->SocketActive) + { + sock = sockptr->socket; + + if (sockptr->TriModeDataSock) + { + if (FD_ISSET(sockptr->TriModeDataSock, &readfd)) + { + ProcessTriModeDataMessage(TNC, sockptr, sockptr->TriModeDataSock, &TNC->Streams[n]); + } + } + + if (FD_ISSET(sock, &readfd)) + { + if (sockptr->RelayMode) + DataSocket_ReadRelay(TNC, sockptr, sock, &TNC->Streams[n]); + else if (sockptr->HTTPMode) + DataSocket_ReadHTTP(TNC, sockptr, sock, n); + else if (sockptr->SyncMode) + DataSocket_ReadSync(TNC, sockptr, sock, n); + else if (sockptr->FBBMode) + DataSocket_ReadFBB(TNC, sockptr, sock, n); + else if (sockptr->DRATSMode) + DataSocket_ReadDRATS(TNC, sockptr, sock, n); + else + DataSocket_Read(TNC, sockptr, sock, &TNC->Streams[n]); + } + + if (FD_ISSET(sock, &exceptfd)) + { + Debugprintf("exceptfd set"); + Telnet_Connected(TNC, sockptr, sock, 1); + } + + if (FD_ISSET(sock, &writefd)) + Telnet_Connected(TNC, sockptr, sock, 0); + + } + } + } + } + } + + +nosocks: + + // Try SNMP + + if (TCP->SNMPsock) + { + struct sockaddr_in rxaddr; + char rxbuff[500]; + int addrlen = sizeof(struct sockaddr_in); + int Offset = 0; + + int len = recvfrom(TCP->SNMPsock, rxbuff, 500, 0,(struct sockaddr *)&rxaddr, &addrlen); + + if (len > 0) + { + UCHAR Reply[256]; + int SendLen; + + SendLen = ProcessSNMPPayload(rxbuff, len, Reply, &Offset); + + if (SendLen == 0) + return; + + sendto(TCP->SNMPsock, &Reply[Offset], SendLen, 0, (struct sockaddr *)&rxaddr, addrlen); + return; + } + } + while (TELNETMONVECPTR->HOSTTRACEQ) + { + int len; + time_t stamp; + BOOL MonitorNODES = FALSE; + MESSAGE * monbuff; + UCHAR * monchars; + + unsigned char buffer[1024] = "\xff\x1b\xb"; + + monbuff = Q_REM((void **)&TELNETMONVECPTR->HOSTTRACEQ); + monchars = (UCHAR *)monbuff; + + stamp = monbuff->Timestamp; + + if (monbuff->PORT & 0x80) // TX + buffer[2] = 91; + else + buffer[2] = 17; + + for (Stream = 0; Stream <= TCP->MaxSessions; Stream++) + { + STREAM = &TNC->Streams[Stream]; + + if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]) + { + struct ConnectionInfo * sockptr = STREAM->ConnectionInfo; + + if (sockptr->BPQTermMode) + { + if (sizeof(void *) > 4) + monchars += 4; + + if (!sockptr->MonitorNODES && monchars[21] == 3 && monchars[22] == 0xcf && monchars[23] == 0xff) + { + len = 0; + } + else + { + unsigned long long SaveMMASK = MMASK; + BOOL SaveMTX = MTX; + BOOL SaveMCOM = MCOM; + BOOL SaveMUI = MUIONLY; + + IntSetTraceOptionsEx(sockptr->MMASK, sockptr->MTX, sockptr->MCOM, sockptr->MUIOnly); + len = IntDecodeFrame((MESSAGE *)monbuff, &buffer[3], stamp, sockptr->MMASK, FALSE, FALSE); + IntSetTraceOptionsEx(SaveMMASK, SaveMTX, SaveMCOM, SaveMUI); + + if (len) + { + len += 3; + buffer[len++] = 0xfe; + send(STREAM->ConnectionInfo->socket, buffer, len, 0); + } + } + } + } + } + + ReleaseBuffer(monbuff); + } + + for (Stream = 0; Stream <= TCP->MaxSessions; Stream++) + { + STREAM = &TNC->Streams[Stream]; + + if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && STREAM->Attached == 0) + { + // New Attach + + int calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, TNC->Streams[Stream].MyCall); + TNC->Streams[Stream].MyCall[calllen] = 0; + + STREAM->Attached = TRUE; + STREAM->FramesQueued= 0; + STREAM->NoCMSFallback = 0; + + continue; + } + + if (STREAM->Attached) + { + if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0 && STREAM->Attached) + { + // Node has disconnected - clear any connection + + struct ConnectionInfo * sockptr = TNC->Streams[Stream].ConnectionInfo; + SOCKET sock = sockptr->socket; + char Msg[80]; + PMSGWITHLEN buffptr; + + STREAM->Attached = FALSE; + STREAM->Connected = FALSE; + STREAM->NoCMSFallback = FALSE; + + sockptr->FromHostBuffPutptr = sockptr->FromHostBuffGetptr = 0; // clear any queued data + + while(TNC->Streams[Stream].BPQtoPACTOR_Q) + { + buffptr = (PMSGWITHLEN)Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q); + if (TelSendPacket(Stream, &TNC->Streams[Stream], buffptr, sockptr->ADIF) == FALSE) + { + // Send failed, and has saved packet + // free saved and discard any more on queue + + free(sockptr->ResendBuffer); + sockptr->ResendBuffer = NULL; + sockptr->ResendLen = 0; + + while(TNC->Streams[Stream].BPQtoPACTOR_Q) + { + buffptr=Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q); + ReleaseBuffer(buffptr); + } + break; + } + } + + while(TNC->Streams[Stream].PACTORtoBPQ_Q) + { + buffptr=Q_REM(&TNC->Streams[Stream].PACTORtoBPQ_Q); + ReleaseBuffer(buffptr); + } + + if (LogEnabled) + { + char logmsg[120]; + sprintf(logmsg,"%d Disconnected. Bytes Sent = %d Bytes Received %d\n", + sockptr->Number, STREAM->bytesTXed, STREAM->bytesRXed); + + WriteLog (logmsg); + } + + if (!sockptr->FBBMode) + { + sprintf(Msg,"*** Disconnected from Stream %d\r\n",Stream); + send(sock, Msg, (int)strlen(Msg),0); + } + + if (sockptr->UserPointer == &TriModeUser) + { + // Always Disconnect + + send(sockptr->socket, "DISCONNECTED\r\n", 14, 0); + return; + } + + if (sockptr->UserPointer == &CMSUser) + { + if (CMSLogEnabled) + { + char logmsg[120]; + sprintf(logmsg,"%d Disconnected. Bytes Sent = %d Bytes Received %d Time %d Seconds\r\n", + sockptr->Number, STREAM->bytesTXed, STREAM->bytesRXed, (int)(time(NULL) - sockptr->ConnectTime)); + + WriteCMSLog (logmsg); + } + + // Don't report if Internet down unless ReportRelayTraffic set) + + if (sockptr->RelaySession == FALSE || TCP->ReportRelayTraffic) + SendWL2KSessionRecord(sockptr->ADIF, STREAM->bytesTXed, STREAM->bytesRXed); + + WriteADIFRecord(sockptr->ADIF); + + if (sockptr->ADIF) + free(sockptr->ADIF); + + sockptr->ADIF = NULL; + + // Always Disconnect CMS Socket + + DataSocket_Disconnect(TNC, sockptr); + return; + } + + if (sockptr->RelayMode) + { + // Always Disconnect Relay Socket + + Sleep(100); + DataSocket_Disconnect(TNC, sockptr); + return; + } + + if (sockptr->Signon[0] || sockptr->ClientSession) // Outward Connect + { + Sleep(1000); + DataSocket_Disconnect(TNC, sockptr); + return; + } + + + if (TCP->DisconnectOnClose) + { + Sleep(1000); + DataSocket_Disconnect(TNC, sockptr); + } + else + { + char DisfromNodeMsg[] = "Disconnected from Node - Telnet Session kept\r\n"; + send(sockptr->socket, DisfromNodeMsg, (int)strlen(DisfromNodeMsg),0); + } + } + } + } + + for (Stream = 0; Stream <= TCP->MaxSessions; Stream++) + { + struct ConnectionInfo * sockptr = TNC->Streams[Stream].ConnectionInfo; + STREAM = &TNC->Streams[Stream]; + + if (sockptr->SocketActive && sockptr->Keepalive && L4LIMIT) + { +#ifdef WIN32 + if ((REALTIMETICKS - sockptr->LastSendTime) > (L4LIMIT - 60) * 9) // PC Ticks are about 10% slow +#else + if ((REALTIMETICKS - sockptr->LastSendTime) > (L4LIMIT - 60) * 10) +#endif + { + // Send Keepalive + + sockptr->LastSendTime = REALTIMETICKS; + BuffertoNode(sockptr, "Keepalive\r", 10); + } + } + + if (sockptr->ResendBuffer) + { + // Data saved after EWOULDBLOCK returned to send + + UCHAR * ptr = sockptr->ResendBuffer; + sockptr->ResendBuffer = NULL; + + SendAndCheck(sockptr, ptr, sockptr->ResendLen, 0); + free(ptr); + + continue; + } + + while (STREAM->BPQtoPACTOR_Q) + { + int datalen; + PMSGWITHLEN buffptr; + UCHAR * MsgPtr; + + // Make sure there is space. Linux TCP buffer is quite small + // Windows doesn't support SIOCOUTQ + +#ifndef WIN32 + int value = 0, error; + + error = ioctl(sockptr->socket, SIOCOUTQ, &value); + + if (value > 1500) + break; +#endif + buffptr = (PMSGWITHLEN)Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q); + STREAM->FramesQueued--; + datalen = (int)(buffptr->Len); + MsgPtr = &buffptr->Data[0]; + + if (STREAM->ConnectionInfo->TriMode) + { + ProcessTrimodeResponse(TNC, STREAM, MsgPtr, datalen); + ReleaseBuffer(buffptr); + return; + } + + + if (TNC->Streams[Stream].Connected) + { + if (sockptr->SyncMode) + { + // Suppress Conected and SID - Relay doesn't understand them + + if (strstr(buffptr->Data, "Connected to") || memcmp(buffptr->Data, "[BPQ-", 5) == 0) + { + ReleaseBuffer(buffptr); + return; + } + } + + if (TelSendPacket(Stream, STREAM, buffptr, sockptr->ADIF) == FALSE) + { + // Send failed, and has requeued packet + // Dont send any more + + break; + } + } + else // Not Connected + { + // Command. Do some sanity checking and look for things to process locally + + datalen--; // Exclude CR + MsgPtr[datalen] = 0; // Null Terminate + + if (_stricmp(MsgPtr, "NoFallback") == 0) + { + TNC->Streams[Stream].NoCMSFallback = TRUE; + buffptr->Len = sprintf(&buffptr->Data[0], "Ok\r"); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + return; + } + + if (_memicmp(MsgPtr, "D", 1) == 0) + { + TNC->Streams[Stream].ReportDISC = TRUE; // Tell Node + ReleaseBuffer(buffptr); + return; + } + + if ((_memicmp(MsgPtr, "C", 1) == 0) && MsgPtr[1] == ' ' && datalen > 2) // Connect + { + char Host[100] = ""; + char P2[100] = ""; + char P3[100] = ""; + char P4[100] = ""; + char P5[100] = ""; + char P6[100] = ""; + char P7[100] = ""; + unsigned int Port = 0; + int n; + + n = sscanf(&MsgPtr[2], "%s %s %s %s %s %s %s", + &Host[0], &P2[0], &P3[0], &P4[0], &P5[0], &P6[0], &P7[0]); + + sockptr->Signon[0] = 0; // Not outgoing; + sockptr->Keepalive = FALSE; // No Keepalives + sockptr->NoCallsign = FALSE; + sockptr->UTF8 = 0; // Not UTF8 + + if (_stricmp(Host, "HOST") == 0) + { + Port = atoi(P2); + + if (Port > MaxBPQPortNo || TCP->CMDPort[Port] == 0) + { + buffptr->Len = sprintf(&buffptr->Data[0], "Error - Invalid HOST Port\r"); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + STREAM->NeedDisc = 10; + return; + } + + STREAM->Connecting = TRUE; + sockptr->CMSSession = FALSE; + sockptr->FBBMode = FALSE; + + if (P3[0] == 'K' || P4[0] == 'K' || P5[0] == 'K' || P6[0] == 'K') + { + sockptr->Keepalive = TRUE; + sockptr->LastSendTime = REALTIMETICKS; + } + + if (P3[0] == 'S' || P4[0] == 'S' || P5[0] == 'S' || P6[0] == 'S') + { + // Set Say flag on partner session + + struct _TRANSPORTENTRY * Sess = TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->L4CROSSLINK; + if (Sess) + Sess->STAYFLAG = 1; + } + + if (_stricmp(P3, "NOCALL") == 0 || _stricmp(P4, "NOCALL") == 0 || _stricmp(P5, "NOCALL") == 0 || _stricmp(P6, "NOCALL") == 0) + sockptr->NoCallsign = TRUE; + + if (_stricmp(P3, "TRANS") == 0 || _stricmp(P4, "TRANS") == 0 || _stricmp(P5, "TRANS") == 0 || _stricmp(P6, "TRANS") == 0) + { + sockptr->FBBMode = TRUE; + sockptr->NeedLF = TRUE; + } + + TCPConnect(TNC, TCP, STREAM, "127.0.0.1", TCP->CMDPort[Port], sockptr->FBBMode); + ReleaseBuffer(buffptr); + return; + } + + if (_stricmp(Host, "RELAY") == 0) + { + if (P2[0] == 0) + { + strcpy(P2, TCP->RELAYHOST); + strcpy(P3, "8772"); + } + + if (P2[0]) + { + STREAM->Connecting = TRUE; + STREAM->ConnectionInfo->CMSSession = TRUE; + STREAM->ConnectionInfo->RelaySession = TRUE; + TCPConnect(TNC, TCP, STREAM, P2, atoi(P3), TRUE); + ReleaseBuffer(buffptr); + return; + } + } + + if (_stricmp(Host, "SYNC") == 0) + { + if (P2[0] == 0) + { + strcpy(P2, TCP->RELAYHOST); + strcpy(P3, "8780"); + } + + if (P2[0]) + { + sockptr->CMSSession = FALSE; + STREAM->Connecting = TRUE; + STREAM->ConnectionInfo->SyncMode = TRUE; + TCPConnect(TNC, TCP, STREAM, P2, atoi(P3), TRUE); + ReleaseBuffer(buffptr); + return; + } + } + + + if (_stricmp(Host, "CMS") == 0) + { + if (TCP->CMS == 0 || !TCP->CMSOK) + { + if (TCP->RELAYHOST[0] && TCP->FallbacktoRelay && STREAM->NoCMSFallback == 0) + { + STREAM->Connecting = TRUE; + STREAM->ConnectionInfo->CMSSession = TRUE; + STREAM->ConnectionInfo->RelaySession = TRUE; + TCPConnect(TNC, TCP, STREAM, TCP->RELAYHOST, 8772, TRUE); + ReleaseBuffer(buffptr); + return; + } + + buffptr->Len = sprintf(&buffptr->Data[0], "Error - CMS Not Available\r"); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + STREAM->NeedDisc = 10; + CheckCMS(TNC); + + return; + } + + STREAM->Connecting = TRUE; + STREAM->ConnectionInfo->CMSSession = TRUE; + STREAM->ConnectionInfo->RelaySession = FALSE; + CMSConnect(TNC, TCP, STREAM, Stream); + ReleaseBuffer(buffptr); + + return; + } + + // Outward Connect. + + // Only Allow user specified host if Secure Session + + if (TCP->SecureTelnet) + { + struct _TRANSPORTENTRY * Sess = TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]; + +// if (Sess && Sess->L4CROSSLINK) +// Sess = Sess->L4CROSSLINK; + + if (Sess && !Sess->Secure_Session) + { + buffptr->Len = sprintf(&buffptr->Data[0], "Error - Telnet Outward Connect needs SYSOP Status\r"); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + STREAM->NeedDisc = 10; + return; + } + } + + Port = atoi(P2); + + if (Port) + { + int useFBBMode = TRUE; + + STREAM->Connecting = TRUE; + STREAM->ConnectionInfo->CMSSession = FALSE; + STREAM->ConnectionInfo->RelaySession = FALSE; + + if (_stricmp(P3, "TELNET") == 0) + { +// // FBB with CRLF + + STREAM->ConnectionInfo->NeedLF = TRUE; + } + else if (_stricmp(P3, "REALTELNET") == 0) + { +// // Telnet Mode with CRLF + + useFBBMode = FALSE; + STREAM->ConnectionInfo->NeedLF = TRUE; + } + else + STREAM->ConnectionInfo->NeedLF = FALSE; + + + STREAM->ConnectionInfo->FBBMode = TRUE; + + if (_stricmp(P3, "NOCALL") == 0 || _stricmp(P4, "NOCALL") == 0 || _stricmp(P5, "NOCALL") == 0 || _stricmp(P6, "NOCALL") == 0) + { + STREAM->ConnectionInfo->NoCallsign = TRUE; + } + else + { + if (_stricmp(P3, "NEEDLF") == 0 || STREAM->ConnectionInfo->NeedLF) + { + // Send LF after each param + + if (P6[0]) + sprintf(STREAM->ConnectionInfo->Signon, "%s\r\n%s\r\n%s\r\n", P4, P5, P6); + else + if (P5[0]) + sprintf(STREAM->ConnectionInfo->Signon, "%s\r\n%s\r\n", P4, P5); + else + if (P4[0]) + sprintf(STREAM->ConnectionInfo->Signon, "%s\r\n", P4); + } + else + { + if (P5[0]) + sprintf(STREAM->ConnectionInfo->Signon, "%s\r%s\r%s\r", P3, P4, P5); + else + if (P4[0]) + sprintf(STREAM->ConnectionInfo->Signon, "%s\r%s\r", P3, P4); + else + if (P3[0]) + sprintf(STREAM->ConnectionInfo->Signon, "%s\r", P3); + } + } + + TCPConnect(TNC, TCP, STREAM, Host, Port, useFBBMode); + ReleaseBuffer(buffptr); + return; + } + } + + buffptr->Len = sprintf(&buffptr->Data[0], "Error - Invalid Command\r"); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + STREAM->NeedDisc = 10; + return; + } + } + + Msglen = sockptr->FromHostBuffPutptr - sockptr->FromHostBuffGetptr; + + if (Msglen) + { + int Paclen = 0; + int Queued = 0; + TRANSPORTENTRY * Sess1 = TNC->PortRecord->ATTACHEDSESSIONS[Stream]; + TRANSPORTENTRY * Sess2 = NULL; + + if (Sess1) + Sess2 = Sess1->L4CROSSLINK; + + // Can't use TXCount - it is Semaphored= + + Queued = C_Q_COUNT(&TNC->Streams[Stream].PACTORtoBPQ_Q); + Queued += C_Q_COUNT((UINT *)&TNC->PortRecord->PORTCONTROL.PORTRX_Q); + + if (Sess2) + Queued += CountFramesQueuedOnSession(Sess2); + + if (Sess1) + Queued += CountFramesQueuedOnSession(Sess1); + + if (Queued > 15) + continue; + + if (Sess1) + Paclen = Sess1->SESSPACLEN; + + if (Paclen == 0) + Paclen = 256; + + ShowConnections(TNC); + + if (Msglen > Paclen) + Msglen = Paclen; + + if (Sess1) Sess1->L4KILLTIMER = 0; + if (Sess2) Sess2->L4KILLTIMER = 0; + + SendtoNode(TNC, Stream, &sockptr->FromHostBuffer[sockptr->FromHostBuffGetptr], Msglen); + sockptr->FromHostBuffGetptr += Msglen; + sockptr->LastSendTime = REALTIMETICKS; + } + } +} + +#ifndef LINBPQ + +LRESULT CALLBACK TelWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + struct ConnectionInfo * sockptr; + SOCKET sock; + int i, n; + struct TNCINFO * TNC; + struct TCPINFO * TCP; + struct _EXTPORTDATA * PortRecord; + HWND SavehDlg, SaveCMS, SaveMonitor; + HMENU SaveMenu1, SaveMenu2, SaveMenu3; + MINMAXINFO * mmi; + + LPMEASUREITEMSTRUCT lpmis; // pointer to item of data + LPDRAWITEMSTRUCT lpdis; // pointer to item drawing data + +// struct ConnectionInfo * ConnectionInfo; + + for (i=1; i <= MAXBPQPORTS; i++) + { + TNC = TNCInfo[i]; + if (TNC == NULL) + continue; + + if (TNC->hDlg == hWnd) + break; + } + + if (TNC == NULL) + return DefMDIChildProc(hWnd, message, wParam, lParam); + + switch (message) + { +// case WM_SIZING: + case WM_SIZE: + { + RECT rcClient; + int ClientHeight, ClientWidth; + + GetClientRect(TNC->hDlg, &rcClient); + + ClientHeight = rcClient.bottom; + ClientWidth = rcClient.right; + + MoveWindow(TNC->hMonitor, 0,20 ,ClientWidth-4, ClientHeight-25, TRUE); + break; + } + + case WM_GETMINMAXINFO: + + mmi = (MINMAXINFO *)lParam; + mmi->ptMaxSize.x = 400; + mmi->ptMaxSize.y = 500; + mmi->ptMaxTrackSize.x = 400; + mmi->ptMaxTrackSize.y = 500; + break; + + + case WM_MDIACTIVATE: + { + // Set the system info menu when getting activated + + if (lParam == (LPARAM) hWnd) + { + // Activate + + RemoveMenu(hBaseMenu, 1, MF_BYPOSITION); + AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)hPopMenu, "Actions"); + SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hBaseMenu, (LPARAM) hWndMenu); + + } + else + { + // Deactivate + + SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL); + } + + // call DrawMenuBar after the menu items are set + DrawMenuBar(FrameWnd); + + return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam); + + } + + case WM_SYSCOMMAND: + + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + + switch (wmId) + { + case SC_RESTORE: + + TNC->Minimized = FALSE; + SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0); + return DefMDIChildProc(hWnd, message, wParam, lParam); + + case SC_MINIMIZE: + + TNC->Minimized = TRUE; + return DefMDIChildProc(hWnd, message, wParam, lParam); + } + + return DefMDIChildProc(hWnd, message, wParam, lParam); + + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + + if (wmId > IDM_DISCONNECT && wmId < IDM_DISCONNECT+MaxSockets+1) + { + // disconnect user + + sockptr = TNC->Streams[wmId-IDM_DISCONNECT].ConnectionInfo; + + if (sockptr->SocketActive) + { + sock=sockptr->socket; + + send(sock,disMsg, (int)strlen(disMsg),0); + + Sleep (1000); + + shutdown(sock,2); + + DataSocket_Disconnect(TNC, sockptr); + + TNC->Streams[wmId-IDM_DISCONNECT].ReportDISC = TRUE; //Tell Node + + return 0; + } + } + + switch (wmId) + { + case CMSENABLED: + + // Toggle CMS Enabled Flag + + TCP = TNC->TCPInfo; + + TCP->CMS = !TCP->CMS; + CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TCP->CMS<<3); + + if (TCP->CMS) + CheckCMS(TNC); + else + { + TCP->CMSOK = FALSE; + SetWindowText(TCP->hCMSWnd, "CMS Off"); + } + break; + + case IDM_LOGGING: + + // Toggle Logging Flag + + LogEnabled = !LogEnabled; + CheckMenuItem(TNC->TCPInfo->hLogMenu, 0, MF_BYPOSITION | LogEnabled<<3); + + break; + + case IDM_CMS_LOGGING: + + // Toggle Logging Flag + + LogEnabled = !LogEnabled; + CheckMenuItem(TNC->TCPInfo->hLogMenu, 1, MF_BYPOSITION | CMSLogEnabled<<3); + + break; + + case TELNET_RECONFIG: + + if (!ProcessConfig()) + { + Consoleprintf("Failed to reread config file - leaving config unchanged"); + break; + } + + FreeConfig(); + + for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + sockptr->SocketActive = FALSE; + closesocket(sockptr->socket); + } + + TCP = TNC->TCPInfo; + + shutdown(TCP->TCPSock, SD_BOTH); + shutdown(TCP->sock6, SD_BOTH); + + n = 0; + while (TCP->FBBsock[n]) + shutdown(TCP->FBBsock[n++], SD_BOTH); + + shutdown(TCP->Relaysock, SD_BOTH); + shutdown(TCP->HTTPsock, SD_BOTH); + shutdown(TCP->HTTPsock6, SD_BOTH); + + + n = 0; + while (TCP->FBBsock6[n]) + shutdown(TCP->FBBsock[n++], SD_BOTH); + + shutdown(TCP->Relaysock6, SD_BOTH); + + Sleep(500); + + closesocket(TCP->TCPSock); + closesocket(TCP->sock6); + + n = 0; + while (TCP->FBBsock[n]) + closesocket(TCP->FBBsock[n++]); + + n = 0; + while (TCP->FBBsock6[n]) + closesocket(TCP->FBBsock6[n++]); + + closesocket(TCP->Relaysock); + closesocket(TCP->Relaysock6); + closesocket(TCP->HTTPsock); + closesocket(TCP->HTTPsock6); + + // Save info from old TNC record + + n = TNC->Port; + PortRecord = TNC->PortRecord; + SavehDlg = TNC->hDlg; + SaveCMS = TCP->hCMSWnd; + SaveMonitor = TNC->hMonitor; + SaveMenu1 = TCP->hActionMenu; + SaveMenu2 = TCP->hDisMenu; + SaveMenu3 = TCP->hLogMenu; + + // Free old TCP Session Stucts + + for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++) + { + free(TNC->Streams[i].ConnectionInfo); + } + + ReadConfigFile(TNC->Port, ProcessLine); + + TNC = TNCInfo[n]; + TNC->Port = n; + TNC->Hardware = H_TELNET; + TNC->hDlg = SavehDlg; + TNC->RIG = &TNC->DummyRig; // Not using Rig control, so use Dummy + + // Get Menu Handles + + TCP = TNC->TCPInfo; + + TCP->hCMSWnd = SaveCMS; + TNC->hMonitor = SaveMonitor; + TCP->hActionMenu = SaveMenu1; + TCP->hDisMenu = SaveMenu2; + TCP->hLogMenu = SaveMenu3; + + CheckMenuItem(TCP->hActionMenu, 3, MF_BYPOSITION | TNC->TCPInfo->CMS<<3); + CheckMenuItem(TCP->hLogMenu, 0, MF_BYPOSITION | LogEnabled<<3); + CheckMenuItem(TCP->hLogMenu, 1, MF_BYPOSITION | CMSLogEnabled<<3); + + // Malloc TCP Session Stucts + + for (i = 0; i <= TNC->TCPInfo->MaxSessions; i++) + { + TNC->Streams[i].ConnectionInfo = zalloc(sizeof(struct ConnectionInfo)); + TNC->Streams[i].ConnectionInfo->Number = i; + + TCP->CurrentSockets = i; //Record max used to save searching all entries + + if (i > 0) + ModifyMenu(TCP->hDisMenu,i - 1 ,MF_BYPOSITION | MF_STRING,IDM_DISCONNECT + 1, "."); + } + + TNC->PortRecord = PortRecord; + + Sleep(500); + OpenSockets(TNC); + OpenSockets6(TNC); + SetupListenSet(TNC); + CheckCMS(TNC); + ShowConnections(TNC); + + break; + default: + return DefMDIChildProc(hWnd, message, wParam, lParam); + } + break; + + // case WM_SIZE: + +// if (wParam == SIZE_MINIMIZED) +// return (0); + + case WM_CTLCOLORDLG: + + return (LONG)bgBrush; + + + case WM_CTLCOLORSTATIC: + { + HDC hdcStatic = (HDC)wParam; + + if (TNC->TCPInfo->hCMSWnd == (HWND)lParam) + { + if (TNC->TCPInfo->CMSOK) + SetTextColor(hdcStatic, RGB(0, 128, 0)); + else + SetTextColor(hdcStatic, RGB(255, 0, 0)); + } + + SetBkMode(hdcStatic, TRANSPARENT); + return (LONG)bgBrush; + } + case WM_MEASUREITEM: + + // Retrieve pointers to the menu item's + // MEASUREITEMSTRUCT structure and MYITEM structure. + + lpmis = (LPMEASUREITEMSTRUCT) lParam; + lpmis->itemWidth = 300; + + return TRUE; + + case WM_DRAWITEM: + + // Get pointers to the menu item's DRAWITEMSTRUCT + // structure and MYITEM structure. + + lpdis = (LPDRAWITEMSTRUCT) lParam; + + // If the user has selected the item, use the selected + // text and background colors to display the item. + + SetTextColor(lpdis->hDC, RGB(0, 128, 0)); + + if (TNC->TCPInfo->CMS) + { + if (TNC->TCPInfo->CMSOK) + TextOut(lpdis->hDC, 340, lpdis->rcItem.top + 2, "CMS OK", 6); + else + { + SetTextColor(lpdis->hDC, RGB(255, 0, 0)); + TextOut(lpdis->hDC, 340, lpdis->rcItem.top + 2, "NO CMS", 6); + } + } + else + TextOut(lpdis->hDC, 340, lpdis->rcItem.top + 2, " ", 13); + + return TRUE; + + case WM_DESTROY: + + break; + } + + return DefMDIChildProc(hWnd, message, wParam, lParam); + +} +#endif + +int Socket_Accept(struct TNCINFO * TNC, SOCKET SocketId, int Port) +{ + int n, addrlen = sizeof(struct sockaddr_in6); + struct sockaddr_in6 sin6; + + struct ConnectionInfo * sockptr; + SOCKET sock; + char Negotiate[6]={IAC,WILL,suppressgoahead,IAC,WILL,echo}; +// char Negotiate[3]={IAC,WILL,echo}; + struct TCPINFO * TCP = TNC->TCPInfo; + HMENU hDisMenu = TCP->hDisMenu; + u_long param=1; + + // if for TriModeData Session, use the TriMode Control connection entry + + if (SocketId == TCP->TriModeDataSock) + { + sockptr = TNC->TCPInfo->TriModeControlSession; + sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen); + sockptr->TriModeDataSock = sock; + ioctl(sock, FIONBIO, ¶m); + + return 0; + } + +// Find a free Session + + for (n = 1; n <= TCP->MaxSessions; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + + if (sockptr->SocketActive == FALSE) + { + sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen); + + if (sock == INVALID_SOCKET) + { + Debugprintf("BPQ32 Telnet accept() failed Error %d", WSAGetLastError()); + return FALSE; + } + + // Log, including port + + if (LogEnabled) + { + char Addr[256]; + char logmsg[512]; + + Tel_Format_Addr(sockptr, Addr); + + sprintf(logmsg,"%d %s Incoming Connect on Port %d\n", sockptr->Number, Addr, Port); + WriteLog (logmsg); + } + + + +// Debugprintf("BPQ32 Telnet accept() Sock %d", sock); + + ioctl(sock, FIONBIO, ¶m); + + sockptr->socket = sock; + sockptr->SocketActive = TRUE; + sockptr->InputLen = 0; + sockptr->Number = n; + sockptr->LoginState = 0; + sockptr->UserPointer = 0; + sockptr->DoEcho = FALSE; + sockptr->BPQTermMode = FALSE; + sockptr->ConnectTime = time(NULL); + sockptr->Keepalive = FALSE; + sockptr->UTF8 = 0; + + TNC->Streams[n].bytesRXed = TNC->Streams[n].bytesTXed = 0; + TNC->Streams[n].FramesQueued = 0; + + sockptr->HTTPMode = FALSE; + sockptr->APIMode = FALSE; + sockptr->SyncMode = FALSE; + sockptr->DRATSMode = FALSE; + sockptr->FBBMode = FALSE; + sockptr->RelayMode = FALSE; + sockptr->ClientSession = FALSE; + sockptr->NeedLF = FALSE; + sockptr->TNC = TNC; + sockptr->WebSocks = 0; + + if (sockptr->ADIF == NULL) + sockptr->ADIF = malloc(sizeof(struct ADIF)); + + memset(sockptr->ADIF, 0, sizeof(struct ADIF)); + + if (SocketId == TCP->HTTPsock || SocketId == TCP->HTTPsock6) + sockptr->HTTPMode = TRUE; + + if (SocketId == TCP->APIsock || SocketId == TCP->APIsock6) + { + sockptr->HTTPMode = TRUE; // API is a type of HTTP socket + sockptr->APIMode = TRUE; + } + else if (SocketId == TCP->Syncsock || SocketId == TCP->Syncsock6) + sockptr->SyncMode = TRUE; + else if (SocketId == TCP->DRATSsock || SocketId == TCP->DRATSsock6) + sockptr->DRATSMode = TRUE; + + else if (SocketId == TCP->Relaysock || SocketId == TCP->Relaysock6) + { + sockptr->RelayMode = TRUE; + sockptr->FBBMode = TRUE; + } + else if (SocketId == TCP->TriModeSock) + { + sockptr->TriMode = TRUE; + sockptr->FBBMode = TRUE; + TNC->TCPInfo->TriModeControlSession = sockptr; + sockptr->TriModeConnected = FALSE; + sockptr->TriModeDataSock = 0; + } + else if (SocketId != TCP->TCPSock && SocketId != TCP->sock6) // We can have several listening FBB mode sockets + sockptr->FBBMode = TRUE; +#ifndef LINBPQ + ModifyMenu(hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, "."); + DrawMenuBar(TNC->hDlg); +#endif + ShowConnections(TNC); + + if (sockptr->HTTPMode) + return 0; + + if (sockptr->DRATSMode) + { + send(sock, "100 Authentication not required\n", 33, 0); + sockptr->LoginState = 2; + return 0; + } + + if (sockptr->SyncMode) + { + char MyCall[16] = ""; + char Hello[32]; + int Len; + memcpy(MyCall, MYNODECALL, 10); + strlop(MyCall, ' '); + strlop(MyCall, '-'); + + Len = sprintf(Hello, "POSYNCHELLO %s\r", MyCall); + + send(sock, Hello, Len, 0); + return 0; + } + else + if (sockptr->RelayMode) + { + send(sock,"\r\rCallsign :\r", 13,0); + } + else + if (sockptr->TriMode) + { + // Trimode emulator Control Connection. + + sockptr->UserPointer = &TriModeUser; + + + send(sock,"CMD\r\n", 5,0); + sockptr->LoginState = 5; + } + else + if (sockptr->FBBMode == FALSE) + { + send(sock, Negotiate, 6, 0); + send(sock, TCP->LoginMsg, (int)strlen(TCP->LoginMsg), 0); + } + + if (sockptr->FromHostBuffer == 0) + { + sockptr->FromHostBuffer = malloc(10000); + sockptr->FromHostBufferSize = 10000; + } + + sockptr->FromHostBuffPutptr = sockptr->FromHostBuffGetptr = 0; + + return 0; + } + } + + // No free sessions. Must accept() then close + + sock = accept(SocketId, (struct sockaddr *)&sin6, &addrlen); + + send(sock,"No Free Sessions\r\n", 18,0); + Debugprintf("No Free Telnet Sessions"); + + Sleep (1000); + closesocket(sock); + + return 0; +} + +/* +int Socket_Data(struct TNCINFO * TNC, int sock, int error, int eventcode) +{ + int n; + struct ConnectionInfo * sockptr; + struct TCPINFO * TCP = TNC->TCPInfo; + HMENU hDisMenu = TCP->hDisMenu; + + // Find Connection Record + + for (n = 0; n <= TCP->CurrentSockets; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + + if (sockptr->socket == sock && sockptr->SocketActive) + { +#ifndef LINBPQ + switch (eventcode) + { + case FD_READ: + + if (sockptr->RelayMode) + return DataSocket_ReadRelay(TNC, sockptr, sock, &TNC->Streams[n]); + + if (sockptr->HTTPMode) + return DataSocket_ReadHTTP(TNC, sockptr, sock, n); + + if (sockptr->FBBMode) + return DataSocket_ReadFBB(TNC, sockptr, sock, n); + else + return DataSocket_Read(TNC, sockptr, sock, &TNC->Streams[n]); + + case FD_WRITE: + + return 0; + + case FD_OOB: + + return 0; + + case FD_ACCEPT: + + return 0; + + case FD_CONNECT: + + return 0; + + case FD_CLOSE: + + TNC->Streams[n].ReportDISC = TRUE; //Tell Node + DataSocket_Disconnect(TNC, sockptr); + return 0; + } + return 0; +#endif + } + + } + + return 0; +} + +*/ +#define PACLEN 100 + +VOID SendtoNode(struct TNCINFO * TNC, int Stream, char * Msg, int MsgLen) +{ + PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); + + if (buffptr == NULL) + return; // No buffers, so ignore + + if (TNC->Streams[Stream].Connected == 0) + { + // Connection Closed - Get Another + + struct ConnectionInfo * sockptr = TNC->Streams[Stream].ConnectionInfo; + + if (ProcessIncommingConnect(TNC, sockptr->Callsign, sockptr->Number, FALSE) == FALSE) + { + DataSocket_Disconnect(TNC, sockptr); //' Tidy up + return; + } + + if (sockptr->UserPointer) + TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->Secure_Session = sockptr->UserPointer->Secure; + } + + buffptr->Len= MsgLen; // Length + + memcpy(&buffptr->Data, Msg, MsgLen); + + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); +} + +int InnerProcessData(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM, int len); + + +int DataSocket_Read(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM) +{ + int len=0, maxlen; + char NLMsg[3]={13,10,0}; + byte * IACptr; + BOOL wait; + + struct TCPINFO * TCP = TNC->TCPInfo; + int SendIndex = 0; + byte * TelCommand; + int beforeIAC = 0; + int rest = 0; + + ioctl(sock,FIONREAD,&len); + + maxlen = InputBufferLen - sockptr->InputLen; + + if (len > maxlen) len=maxlen; + + len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0); + + if (len == SOCKET_ERROR || len ==0) + { + // Failed or closed - clear connection + + TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node + DataSocket_Disconnect(TNC, sockptr); + return 0; + } + + // If message contains Telnet Commands we should process the data in the buffer first + // and not echo the commands! + + + IACptr = memchr(sockptr->InputBuffer, IAC, sockptr->InputLen + len); + + if (IACptr) + { + beforeIAC = IACptr - sockptr->InputBuffer; + rest = (sockptr->InputLen + len) - beforeIAC; + + if (beforeIAC) + { + TelCommand = malloc(rest); + memcpy(TelCommand, IACptr, rest); + InnerProcessData(TNC, sockptr, sock, STREAM, beforeIAC); + + // There may still be data in buffer, but it may be less than before + // Put IAC and following into buffer + + memcpy(&sockptr->InputBuffer[sockptr->InputLen], TelCommand, rest); + len -= sockptr->InputLen; + free(TelCommand); + } + } + +IACLoop: + + IACptr = memchr(sockptr->InputBuffer, IAC, sockptr->InputLen + len); + + if (IACptr) + { + // There still may be data in the buffer. + + wait = ProcessTelnetCommand(sockptr, IACptr, &rest); + + if (wait) + { + // Need more. + + sockptr->InputLen += len; + return 0; // wait for more chars + } + + // If ProcessTelnet Command returns FALSE, then it has removed the IAC and its + // params from the buffer. There may still be more to process. + + if (rest == 0) + return 0; // Nothing Left + + memmove(&sockptr->InputBuffer[sockptr->InputLen], IACptr + len - rest, rest); + len = rest; + + goto IACLoop; // There may be more + } + + return InnerProcessData(TNC, sockptr, sock, STREAM, len); +} + + +int InnerProcessData(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM, int len) +{ + int InputLen, MsgLen, i, n,charsAfter; + char NLMsg[3]={13,10,0}; + byte * CRPtr; + byte * LFPtr; + byte * BSptr; + byte * MsgPtr; + char logmsg[1000]; + struct UserRec * USER; + struct TCPINFO * TCP = TNC->TCPInfo; + int SendIndex = 0; + + // echo data just read + + if (sockptr->DoEcho && sockptr->LoginState != 1) // Password + send(sockptr->socket,&sockptr->InputBuffer[sockptr->InputLen], len, 0); + + sockptr->InputLen += len; + + // look for backspaces in data just read + + BSptr = memchr(&sockptr->InputBuffer[0], 8, sockptr->InputLen); + + if (BSptr == NULL) + BSptr = memchr(&sockptr->InputBuffer[0], 127, sockptr->InputLen); + + if (BSptr != 0) + { + // single char or BS as last is most likely, and worth treating as a special case + + int n; + + charsAfter = sockptr->InputLen - (int)((BSptr-&sockptr->InputBuffer[0])) - 1; + + if (charsAfter == 0) + { + sockptr->InputLen--; + if (sockptr->InputLen > 0) + sockptr->InputLen--; //Remove last char + + goto noBS; + } + // more than single char. Copy stuff after bs over char before + + memmove(BSptr-1, BSptr+1, charsAfter); + + n = sockptr->InputLen; + + sockptr->InputLen -= 2; // drop bs and char before + + // see if more bs chars +BSCheck: + BSptr = memchr(&sockptr->InputBuffer[0], 8, sockptr->InputLen); + + if (BSptr == NULL) + BSptr = memchr(&sockptr->InputBuffer[0], 127, sockptr->InputLen); + + if (BSptr == NULL) + goto noBS; + + charsAfter = sockptr->InputLen - (int)((BSptr-&sockptr->InputBuffer[0])) - 1; + + if (charsAfter == 0) + { + sockptr->InputLen--; // Remove BS + if (sockptr->InputLen > 0) + sockptr->InputLen--; //Remove last char if not at start + goto noBS; + } + + memmove(BSptr-1, BSptr+1, charsAfter); + sockptr->InputLen--; // Remove BS + if (sockptr->InputLen > 0) sockptr->InputLen--; //Remove last char if not at start + + goto BSCheck; // may be more bs chars + } + +noBS: + + // Extract lines from input stream + + MsgPtr = &sockptr->InputBuffer[0]; + InputLen = sockptr->InputLen; + +MsgLoop: + + // if in Client Mode, accept CR, CR Null, CR LF or LF, and replace with CR + // Also send immediately to client - dont wait for complete lines + + if (sockptr->ClientSession) + { + int n = InputLen; + char * ptr = MsgPtr; + char * Start = MsgPtr; + char c; + int len = 0; + char NodeLine[300]; + char * optr = NodeLine; + + while (n--) + { + c = *(ptr++); + + if (c == 0) + // Ignore Nulls + continue; + + len++; + *(optr++) = c; + + if (c == 13) + { + // See if next is lf or null + + if (n) + { + // Some Left + + if ((*ptr) == 0 || *(ptr) == 10) + { + // skip next + + n--; + ptr++; + } + } + } + else if (c == 10) + { + *(optr - 1) = 13; + } + else + { + // Normal Char + + if (len >= PACLEN) + { + BuffertoNode(sockptr, NodeLine, len); + optr = NodeLine; + len = 0; + } + } + } + + // All scanned - send anything outstanding + + if (len) + BuffertoNode(sockptr, NodeLine, len); + + sockptr->InputLen = 0; + ShowConnections(TNC);; + + return 0; + } + + + // Server Mode + + CRPtr=memchr(MsgPtr, 13, InputLen); + + if (CRPtr) + { + // Convert CR Null to CR LF + + LFPtr=memchr(MsgPtr, 0, InputLen); + + if (LFPtr && *(LFPtr - 1) == 13) // Convert CR NULL to CR LF + { + *LFPtr = 10; // Replace NULL with LF + send(sockptr->socket, LFPtr, 1, 0); // And echo it + } + } + + // could just have LF?? + + LFPtr=memchr(MsgPtr, 10, InputLen); + + if (LFPtr == 0) + if (CRPtr) + { + LFPtr = ++CRPtr; + InputLen++; + } + if (LFPtr == 0) + { + // Check Paclen + + if (InputLen > PACLEN) + { + if (sockptr->LoginState != 2) // Normal Data + { + // Long message received when waiting for user or password - just ignore + + sockptr->InputLen=0; + + return 0; + } + + // Send to Node + + // Line could be up to 500 chars if coming from a program rather than an interative user + // Limit send to node to 255 + + while (InputLen > 255) + { + SendtoNode(TNC, sockptr->Number, MsgPtr, 255); + sockptr->InputLen -= 255; + InputLen -= 255; + + memmove(MsgPtr,MsgPtr+255,InputLen); + } + + SendtoNode(TNC, sockptr->Number, MsgPtr, InputLen); + + sockptr->InputLen = 0; + + } // PACLEN + + return 0; // No CR + } + + // Got a LF + + // Process data up to the cr + + MsgLen = (int)(LFPtr-MsgPtr); // Include the CR but not LF + + switch (sockptr->LoginState) + { + + case 2: + + // Normal Data State + + STREAM->bytesRXed += MsgLen; + SendIndex = 0; + + // Line could be up to 500 chars if coming from a program rather than an interative user + // Limit send to node to 255. Should really use PACLEN instead of 255.... + + while (MsgLen > 255) + { + SendtoNode(TNC, sockptr->Number, MsgPtr + SendIndex, 255); + SendIndex += 255; + MsgLen -= 255; + } + + SendtoNode(TNC, sockptr->Number, MsgPtr + SendIndex, MsgLen); + + MsgLen += SendIndex; + + // If anything left, copy down buffer, and go back + + InputLen=InputLen-MsgLen-1; + + sockptr->InputLen=InputLen; + + if (InputLen > 0) + { + memmove(MsgPtr,LFPtr+1,InputLen); + + goto MsgLoop; + } + + return 0; + + case 0: + + // Check Username + // + + *(LFPtr-1)=0; // remove cr + + // send(sock, NLMsg, 2, 0); + + if (LogEnabled) + { + char Addr[256]; + + Tel_Format_Addr(sockptr, Addr); + + if (strlen(MsgPtr) > 64) + { + MsgPtr[64] = 0; + Debugprintf("Telnet Bad User Name %s", MsgPtr); + } + + sprintf(logmsg,"%d %s User=%s\n", sockptr->Number, Addr, MsgPtr); + WriteLog (logmsg); + } + + for (i = 0; i < TCP->NumberofUsers; i++) + { + USER = TCP->UserRecPtr[i]; + + if (USER == NULL) + continue; + + if (_stricmp(USER->UserName, "ANON") == 0) + { + // Anon Login - Callsign is supplied as user + + sockptr->UserPointer = USER; //' Save pointer for checking password + strcpy(sockptr->Callsign, _strupr(MsgPtr)); //' for *** linked + } + else if (strcmp(MsgPtr,USER->UserName) == 0) + { + sockptr->UserPointer = USER; //' Save pointer for checking password + strcpy(sockptr->Callsign, USER->Callsign); //' for *** linked + } + else + continue; + + send(sock, TCP->PasswordMsg, (int)strlen(TCP->PasswordMsg),0); + + sockptr->Retries = 0; + + sockptr->LoginState = 1; + sockptr->InputLen = 0; + + n=sockptr->Number; +#ifndef LINBPQ + ModifyMenu(TCP->hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, MsgPtr); +#endif + ShowConnections(TNC);; + return 0; + } + + // Not found + + + if (sockptr->Retries++ == 4) + { + send(sock,AttemptsMsg,sizeof(AttemptsMsg),0); + Sleep (1000); + DataSocket_Disconnect(TNC, sockptr); //' Tidy up + } + else + { + send(sock, TCP->LoginMsg, (int)strlen(TCP->LoginMsg), 0); + sockptr->InputLen=0; + } + + return 0; + + case 1: + + *(LFPtr-1)=0; // remove cr + + send(sock, NLMsg, 2, 0); // Need to echo NL, as password is not echoed + + if (LogEnabled) + { + char Addr[256]; + + Tel_Format_Addr(sockptr, Addr); + + if (strlen(MsgPtr) > 64) + { + MsgPtr[64] = 0; + Debugprintf("Telnet Bad Password %s", MsgPtr); + } + + + sprintf(logmsg,"%d %s Password=%s\n", sockptr->Number, Addr, MsgPtr); + WriteLog (logmsg); + } + + if (strcmp(MsgPtr, sockptr->UserPointer->Password) == 0) { + char * ct = TCP->cfgCTEXT; + char * Appl; + int ctlen = (int)strlen(ct); + + if (ProcessIncommingConnect(TNC, sockptr->Callsign, sockptr->Number, FALSE) == FALSE) + { + DataSocket_Disconnect(TNC, sockptr); //' Tidy up + return 0; + } + + TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->Secure_Session = sockptr->UserPointer->Secure; + + sockptr->LoginState = 2; + sockptr->InputLen = 0; + + if (ctlen > 0) send(sock, ct, ctlen, 0); + + STREAM->bytesTXed = ctlen; + + if (LogEnabled) + { + char Addr[100]; + + Tel_Format_Addr(sockptr, Addr); + sprintf(logmsg,"%d %s Call Accepted Callsign=%s\n", sockptr->Number, Addr, sockptr->Callsign); + WriteLog (logmsg); + } + + Appl = sockptr->UserPointer->Appl; + + if (Appl[0]) + SendtoNode(TNC, sockptr->Number, Appl, (int)strlen(Appl)); + + ShowConnections(TNC); + + return 0; + } + + // Bad Password + + if (sockptr->Retries++ == 4) + { + send(sock,AttemptsMsg, (int)strlen(AttemptsMsg),0); + Sleep (1000); + DataSocket_Disconnect (TNC, sockptr); //' Tidy up + } + else + { + send(sock, TCP->PasswordMsg, (int)strlen(TCP->PasswordMsg), 0); + sockptr->InputLen=0; + } + + return 0; + + default: + + return 0; + + } + + return 0; +} + +int DataSocket_ReadRelay(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM) +{ + int len=0, maxlen, InputLen, MsgLen, n; + char NLMsg[3]={13,10,0}; + byte * LFPtr; + byte * MsgPtr; + char logmsg[256]; + char RelayMsg[] = "No CMS connection available - using local BPQMail\r"; + struct TCPINFO * TCP = TNC->TCPInfo; + + ioctl(sock,FIONREAD,&len); + + maxlen = InputBufferLen - sockptr->InputLen; + + if (len > maxlen) len=maxlen; + + len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0); + + + if (len == SOCKET_ERROR || len ==0) + { + // Failed or closed - clear connection + + TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node + DataSocket_Disconnect(TNC, sockptr); + return 0; + } + + sockptr->InputLen+=len; + + // Extract lines from input stream + + MsgPtr = &sockptr->InputBuffer[0]; + InputLen = sockptr->InputLen; + + STREAM->bytesRXed += InputLen; + + if (sockptr->LoginState == 2) + { + // Data. FBB is binary + + // Send to Node + + // Queue to Node. Data may arrive it large quatities, possibly exceeding node buffer capacity + + STREAM->bytesRXed += InputLen; + + if (sockptr->FromHostBuffPutptr + InputLen > sockptr->FromHostBufferSize) + { + if (InputLen > 10000) + sockptr->FromHostBufferSize += InputLen; + else + sockptr->FromHostBufferSize += 10000; + + sockptr->FromHostBuffer = realloc(sockptr->FromHostBuffer, sockptr->FromHostBufferSize); + } + + memcpy(&sockptr->FromHostBuffer[sockptr->FromHostBuffPutptr], MsgPtr, InputLen); + + sockptr->FromHostBuffPutptr += InputLen; + sockptr->InputLen = 0; + + return 0; + } +/* + if (InputLen > 256) + { + SendtoNode(TNC, sockptr->Number, MsgPtr, 256); + sockptr->InputLen -= 256; + + InputLen -= 256; + + memmove(MsgPtr,MsgPtr+256,InputLen); + + goto MsgLoop; + } + + SendtoNode(TNC, sockptr->Number, MsgPtr, InputLen); + sockptr->InputLen = 0; + + return 0; + } +*/ + if (InputLen > 256) + { + // Long message received when waiting for user or password - just ignore + + sockptr->InputLen=0; + + return 0; + } + + LFPtr=memchr(MsgPtr, 13, InputLen); + + if (LFPtr == 0) + return 0; // Waitr for more + + // Got a CR + + // Process data up to the cr + + MsgLen = (int)(LFPtr-MsgPtr); + + switch (sockptr->LoginState) + { + + case 0: + + // Check Username + // + + *(LFPtr)=0; // remove cr + + if (*MsgPtr == '.') + MsgPtr++; + + if (strlen(MsgPtr) == 0) + { + DataSocket_Disconnect(TNC, sockptr); // Silently disconnect - should only be used for automatic systems + return 0; + } + + if (LogEnabled) + { + unsigned char work[4]; + memcpy(work, &sockptr->sin.sin_addr.s_addr, 4); + sprintf(logmsg,"%d %d.%d.%d.%d User=%s\n", + sockptr->Number, + work[0], work[1], work[2], work[3], + MsgPtr); + + WriteLog (logmsg); + } + + strcpy(sockptr->Callsign, _strupr(MsgPtr)); + + // Save callsign for *** linked + + send(sock, "Password :\r", 11,0); + + sockptr->Retries = 0; + sockptr->LoginState = 1; + sockptr->InputLen = 0; + + n=sockptr->Number; +#ifndef LINBPQ + ModifyMenu(TCP->hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, MsgPtr); +#endif + ShowConnections(TNC);; + + return 0; + + + case 1: + + *(LFPtr)=0; // remove cr + + if (strlen(MsgPtr) == 0) + { + DataSocket_Disconnect(TNC, sockptr); // Silently disconnect - should only be used for automatic systems + return 0; + } + + if (LogEnabled) + { + unsigned char work[4]; + memcpy(work, &sockptr->sin.sin_addr.s_addr, 4); + sprintf(logmsg,"%d %d.%d.%d.%d Password=%s\n", + sockptr->Number, + work[0], work[1], work[2], work[3], + MsgPtr); + + WriteLog (logmsg); + } + + if (strchr(MsgPtr, '$')) + { + // Special format Password for PAT Gateway Mode + + char * Port = strlop(MsgPtr, '$'); + char * Call; + int PortNo; + char ConMsg[80]; + + if (Port) + { + Call = strlop(Port, '$'); + + if (Call) + { + struct PORTCONTROL * PORT; + + PortNo = atoi(Port); + PORT = GetPortTableEntryFromPortNum(PortNo); + + if (PORT == NULL || PORT->PROTOCOL < 10) + sprintf(ConMsg, "C %s %s", Port, Call); + else + sprintf(ConMsg, "ATT %s %s", Port, Call); + + } + + if (ProcessIncommingConnect(TNC, sockptr->Callsign, sockptr->Number, FALSE) == 0) + { + DataSocket_Disconnect(TNC, sockptr); //' Tidy up + return 0; + } + + sockptr->LoginState = 2; + + sockptr->InputLen = 0; + + if (LogEnabled) + { + unsigned char work[4]; + memcpy(work, &sockptr->sin.sin_addr.s_addr, 4); + sprintf(logmsg,"%d %d.%d.%d.%d Gateway Connect Call=%s Command=%s\n", + sockptr->Number, + work[0], work[1], work[2], work[3], + sockptr->Callsign,ConMsg); + + WriteLog (logmsg); + } + + // Send Command to Node + + strcat(ConMsg, "\r"); + SendtoNode(TNC, sockptr->Number, ConMsg, (int)strlen(ConMsg)); + } + + return 0; + } + + sockptr->UserPointer = &RelayUser; + + if (ProcessIncommingConnectEx(TNC, sockptr->Callsign, sockptr->Number, FALSE, TRUE) == 0) + { + DataSocket_Disconnect(TNC, sockptr); //' Tidy up + return 0; + } + + if (TCP->FallbacktoRelay) + send(sock, RelayMsg, (int)strlen(RelayMsg), 0); + + sockptr->LoginState = 2; + + sockptr->InputLen = 0; + + if (LogEnabled) + { + unsigned char work[4]; + memcpy(work, &sockptr->sin.sin_addr.s_addr, 4); + sprintf(logmsg,"%d %d.%d.%d.%d Call Accepted Callsign =%s\n", + sockptr->Number, + work[0], work[1], work[2], work[3], + sockptr->Callsign); + + WriteLog (logmsg); + } + + ShowConnections(TNC); + + sockptr->InputLen = 0; + + // Connect to the BBS + + SendtoNode(TNC, sockptr->Number, TCP->RelayAPPL, (int)strlen(TCP->RelayAPPL)); + + ShowConnections(TNC);; + + return 0; + + default: + + return 0; + + } + + return 0; +} +#define ZEXPORT WINAPI + +#include "zlib.h" + +int DataSocket_ReadSync(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream) +{ + int len=0, maxlen, InputLen; + byte * MsgPtr; + struct TCPINFO * TCP = TNC->TCPInfo; + struct STREAMINFO * STREAM = &TNC->Streams[Stream]; + TRANSPORTENTRY * Sess1 = TNC->PortRecord->ATTACHEDSESSIONS[Stream]; + TRANSPORTENTRY * Sess2 = NULL; + + ioctl(sock,FIONREAD,&len); + + maxlen = InputBufferLen - sockptr->InputLen; + + if (len > maxlen) len = maxlen; + + len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0); + + if (len == SOCKET_ERROR || len == 0) + { + // Failed or closed - clear connection + + TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node + DataSocket_Disconnect(TNC, sockptr); + return 0; + } + + sockptr->InputLen+=len; + MsgPtr = &sockptr->InputBuffer[0]; + InputLen = sockptr->InputLen; + MsgPtr[InputLen] = 0; + + STREAM->bytesRXed += InputLen; + + if (sockptr->LoginState == 0) // Initial connection + { + // First Message should be POSYNCLOGON CALL + + // Extract the callsign + + char * call = strlop(MsgPtr, ' '); + + if (call == NULL || strcmp(MsgPtr, "POSYNCLOGON") !=0) + { + DataSocket_Disconnect(TNC, sockptr); //' Tidy up + return 0; + } + + strcpy(sockptr->Callsign, call); + + call --; + *(call) = ' '; + + sockptr->UserPointer = &SyncUser; + + SendtoNode(TNC, sockptr->Number, TCP->SyncAPPL, (int)strlen(TCP->SyncAPPL)); + BuffertoNode(sockptr, MsgPtr, InputLen); + STREAM->RelaySyncStream = 1; + sockptr->LoginState = 2; + + ShowConnections(TNC); + return 0; + } + + // Queue to Node. Data may arrive in large quantities, possibly exceeding node buffer capacity + + BuffertoNode(sockptr, MsgPtr, InputLen); + sockptr->InputLen = 0; + + return 0; +} + + + +int DataSocket_ReadFBB(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream) +{ + int len=0, maxlen, InputLen, MsgLen, i, n; + char NLMsg[3]={13,10,0}; + byte * CRPtr; + byte * MsgPtr; + char logmsg[1000]; + struct UserRec * USER; + struct TCPINFO * TCP = TNC->TCPInfo; + struct STREAMINFO * STREAM = &TNC->Streams[Stream]; + TRANSPORTENTRY * Sess1 = TNC->PortRecord->ATTACHEDSESSIONS[Stream]; + TRANSPORTENTRY * Sess2 = NULL; + + ioctl(sock,FIONREAD,&len); + + maxlen = InputBufferLen - sockptr->InputLen; + + if (len > maxlen) len = maxlen; + + len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0); + + if (len == SOCKET_ERROR || len == 0) + { + // Failed or closed - clear connection + + TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node + DataSocket_Disconnect(TNC, sockptr); + return 0; + } + + sockptr->InputLen+=len; + + // Extract lines from input stream + + MsgPtr = &sockptr->InputBuffer[0]; + InputLen = sockptr->InputLen; + MsgPtr[InputLen] = 0; + + if (sockptr->LoginState == 0) + { + // Look for FLMSG Header + + if (InputLen > 10 && memcmp(MsgPtr, "... start\n", 10) == 0) + { + MsgPtr[9] = 13; // Convert to CR + sockptr->LoginState = 2; // Set Logged in + + SendtoNode(TNC, Stream, "..FLMSG\r", 8); // Dummy command to command handler + + } + } + +MsgLoop: + + if (sockptr->LoginState == 2) + { + // Data. FBB is binary + + int Paclen = 0; + + if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]) + Paclen = TNC->PortRecord->ATTACHEDSESSIONS[Stream]->SESSPACLEN; + +// if (Paclen == 0) + Paclen = 256; + + if (sockptr->BPQTermMode) + { + if (memcmp(MsgPtr, "\\\\\\\\", 4) == 0) + { + // Monitor Control + + int P8 = 0; + + int n = sscanf(&MsgPtr[4], "%llx %x %x %x %x %x %x %x", + &sockptr->MMASK, &sockptr->MTX, &sockptr->MCOM, &sockptr->MonitorNODES, + &sockptr->MonitorColour, &sockptr->MUIOnly, &sockptr->UTF8, &P8); + + if (n == 5) + sockptr->MUIOnly = sockptr->UTF8 = 0; + + if (n == 6) + sockptr->UTF8 = 0; + + if (P8 == 1) + SendPortsForMonitor(sock, sockptr->UserPointer->Secure); + sockptr->InputLen = 0; + return 0; + } + } + + if (sockptr->UserPointer == &CMSUser) + { + WritetoTrace(Stream, MsgPtr, InputLen, sockptr->ADIF, 'R'); + } + + if (InputLen == 8 && memcmp(MsgPtr, ";;;;;;\r\n", 8) == 0) + { + // CMS Keepalive + + sockptr->InputLen = 0; + return 0; + } + + // Queue to Node. Data may arrive it large quantities, possibly exceeding node buffer capacity + + STREAM->bytesRXed += InputLen; + BuffertoNode(sockptr, MsgPtr, InputLen); + sockptr->InputLen = 0; + + return 0; + } + + if (InputLen > 256) + { + // Long message received when waiting for user or password - just ignore + + sockptr->InputLen=0; + + return 0; + } + + if (MsgPtr[0] == 10) // LF + { + // Remove the LF + + InputLen--; + sockptr->InputLen--; + + memmove(MsgPtr, MsgPtr+1, InputLen); + } + + CRPtr = memchr(MsgPtr, 13, InputLen); + + if (CRPtr == 0) + return 0; // Waitr for more + + // Got a CR + + // Process data up to the cr + + MsgLen = (int)(CRPtr - MsgPtr); + + if (MsgLen == 0) // Just CR + { + MsgPtr++; // Skip it + InputLen--; + sockptr->InputLen--; + goto MsgLoop; + } + + + switch (sockptr->LoginState) + { + case 5: + + // Trimode Emulator Command + + *CRPtr = 0; + + ProcessTrimodeCommand(TNC, sockptr, MsgPtr); + + MsgLen++; + + InputLen -= MsgLen; + + memmove(MsgPtr, MsgPtr+MsgLen, InputLen); + sockptr->InputLen = InputLen ; + MsgPtr[InputLen] = 0; + + + goto MsgLoop; + + case 3: + + // CMS Signon + + strlop(MsgPtr, 13); + + sprintf(logmsg,"%d %s\r\n", Stream, MsgPtr); + WriteCMSLog (logmsg); + + if (strstr(MsgPtr, "Callsign :")) + { + char Msg[80]; + int Len; + + if (sockptr->LogonSent) + { + sockptr->InputLen=0; + return TRUE; + } + + sockptr->LogonSent = TRUE; + + if (TCP->SecureCMSPassword[0] && sockptr->RelaySession == 0) + Len = sprintf(Msg, "%s %s\r", TNC->Streams[sockptr->Number].MyCall, TCP->GatewayCall); + else + Len = sprintf(Msg, "%s\r", TNC->Streams[sockptr->Number].MyCall); + + if (sockptr->ADIF == NULL) + { + sockptr->ADIF = malloc(sizeof(struct ADIF)); + memset(sockptr->ADIF, 0, sizeof(struct ADIF)); + } + + strcpy(sockptr->ADIF->CMSCall, TCP->GatewayCall); + + send(sock, Msg, Len, 0); + sprintf(logmsg,"%d %s\n", Stream, Msg); + WriteCMSLog (logmsg); + + sockptr->InputLen=0; + + return TRUE; + } + if (memcmp(MsgPtr, ";SQ: ", 5) == 0) + { + // Secure CMS challenge + + char Msg[80]; + int Len; + int Response = GetCMSHash(&MsgPtr[5], TCP->SecureCMSPassword); + char RespString[12]; + long long Freq = 0; + int Mode = 0; + ADIF * ADIF = sockptr->ADIF; + + strcat(MsgPtr,""); + UpdateADIFRecord(ADIF, MsgPtr, 'R'); + + if (Sess1) + { + Sess2 = Sess1->L4CROSSLINK; + + if (Sess2) + { + // if Session has report info, use it + + if (Sess2->Mode) + { + ADIF->Freq = Freq = Sess2->Frequency; + ADIF->Mode = Mode = Sess2->Mode; + } + else + { + // See if L2 session - if so, get info from WL2K report line + + if (Sess2->L4CIRCUITTYPE & L2LINK) + { + LINKTABLE * LINK = Sess2->L4TARGET.LINK; + PORTCONTROLX * PORT = LINK->LINKPORT; + + ADIF->Freq = Freq = PORT->WL2KInfo.Freq; + ADIF->Mode = Mode = PORT->WL2KInfo.mode; + } + else + { + if (Sess2->RMSCall[0]) + { + ADIF->Freq = Freq = Sess2->Frequency; + ADIF->Mode = Mode = Sess2->Mode; + } + } + } + } + } + + sprintf(RespString, "%010d", Response); + + Len = sprintf(Msg, ";SR: %s %lld %d\r", &RespString[2], Freq, Mode); + + send(sock, Msg, Len,0); + sprintf(logmsg,"%d %s\n", Stream, Msg); + WriteCMSLog (logmsg); + + strcat(Msg,""); + UpdateADIFRecord(ADIF, Msg, 'S'); + + sockptr->InputLen=0; + sockptr->LoginState = 2; // Data + sockptr->LogonSent = FALSE; + + return TRUE; + } + + if (strstr(MsgPtr, "Password :")) + { + // Send "CMSTelnet" + gateway callsign + frequency + emission type if info is available + + TRANSPORTENTRY * Sess1 = TNC->PortRecord->ATTACHEDSESSIONS[Stream]; + TRANSPORTENTRY * Sess2 = NULL; + char Passline[80] = "CMSTELNET\r"; + int len = 10; + ADIF * ADIF = sockptr->ADIF; + + + if (Sess1) + { + Sess2 = Sess1->L4CROSSLINK; + + if (Sess2) + { + // if Session has report info, use it + + if (Sess2->Mode) + { + ADIF->Freq = Sess2->Frequency; + ADIF->Mode = Sess2->Mode; + } + else + { + // See if L2 session - if so, get info from WL2K report line + + if (Sess2->L4CIRCUITTYPE & L2LINK) + { + LINKTABLE * LINK = Sess2->L4TARGET.LINK; + PORTCONTROLX * PORT = LINK->LINKPORT; + + if (PORT->WL2KInfo.Freq) + { + len = sprintf(Passline, "CMSTELNET %s %lld %d\r", PORT->WL2KInfo.RMSCall, PORT->WL2KInfo.Freq, PORT->WL2KInfo.mode); + ADIF->Freq = PORT->WL2KInfo.Freq; + ADIF->Mode = PORT->WL2KInfo.mode; + } + } + else + { + if (Sess2->RMSCall[0]) + { + len = sprintf(Passline, "CMSTELNET %s %lld %d\r", Sess2->RMSCall, Sess2->Frequency, Sess2->Mode); + ADIF->Mode = Sess2->Frequency; + ADIF->Mode = Sess2->Mode; + } + } + } + } + } + send(sock, Passline, len, 0); + sockptr->LoginState = 2; // Data + sockptr->InputLen=0; + sockptr->LogonSent = FALSE; + + if (CMSLogEnabled) + { + char logmsg[120]; + sprintf(logmsg,"%d %s\r\n", sockptr->Number, Passline); + WriteCMSLog (logmsg); + } + + return TRUE; + } + + return TRUE; + + case 0: + + // Check Username + // + + *(CRPtr)=0; // remove cr + + if (LogEnabled) + { + char Addr[256]; + Tel_Format_Addr(sockptr, Addr); + + if (strlen(MsgPtr) > 64) + { + MsgPtr[64] = 0; + Debugprintf("Telnet Bad User Name %s", MsgPtr); + } + + sprintf(logmsg,"%d %s User=%s\n", sockptr->Number, Addr, MsgPtr); + WriteLog (logmsg); + } + for (i = 0; i < TCP->NumberofUsers; i++) + { + USER = TCP->UserRecPtr[i]; + + if (USER == NULL) + continue; + + if (_stricmp(USER->UserName, "ANON") == 0) + { + // Anon Login - Callsign is supplied as user + + sockptr->UserPointer = USER; //' Save pointer for checking password + strcpy(sockptr->Callsign, _strupr(MsgPtr)); //' for *** linked + } + else if (strcmp(MsgPtr,USER->UserName) == 0) + { + sockptr->UserPointer = USER; //' Save pointer for checking password + strcpy(sockptr->Callsign, USER->Callsign); //' for *** linked + + } + else + continue; + + sockptr->Retries = 0; + + sockptr->LoginState = 1; + sockptr->InputLen = 0; + + n=sockptr->Number; + +#ifndef LINBPQ + ModifyMenu(TCP->hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, MsgPtr); +#endif + + ShowConnections(TNC);; + + InputLen=InputLen-(MsgLen+1); + + sockptr->InputLen=InputLen; + + if (InputLen > 0) + { + memmove(MsgPtr, CRPtr+1, InputLen); + goto MsgLoop; + } + + return 0; + } + + // User Not found + + if (sockptr->Retries++ == 4) + { + send(sock,AttemptsMsg,sizeof(AttemptsMsg),0); + Sleep (1000); + DataSocket_Disconnect(TNC, sockptr); //' Tidy up + } + else + { + send(sock, TCP->LoginMsg, (int)strlen(TCP->LoginMsg), 0); + sockptr->InputLen=0; + + } + + return 0; + + case 1: + + *(CRPtr)=0; // remove cr + + if (LogEnabled) + { + char Addr[256]; + Tel_Format_Addr(sockptr, Addr); + + if (strlen(MsgPtr) > 64) + { + MsgPtr[64] = 0; + Debugprintf("Telnet Bad Password %s", MsgPtr); + } + + sprintf(logmsg,"%d %s Password=%s\n", sockptr->Number, Addr, MsgPtr); + WriteLog (logmsg); + } + if (strcmp(MsgPtr, sockptr->UserPointer->Password) == 0) + { + char * Appl; + + if (ProcessIncommingConnect(TNC, sockptr->Callsign, sockptr->Number, FALSE) == FALSE) + { + DataSocket_Disconnect(TNC, sockptr); //' Tidy up + return 0; + } + + TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->Secure_Session = sockptr->UserPointer->Secure; + + sockptr->LoginState = 2; + + sockptr->InputLen = 0; + + if (LogEnabled) + { + char Addr[100]; + Tel_Format_Addr(sockptr, Addr); + sprintf(logmsg,"%d %s Call Accepted. Callsign=%s\n", + sockptr->Number, Addr,sockptr->Callsign); + + WriteLog (logmsg); + } + + ShowConnections(TNC);; + InputLen=InputLen-(MsgLen+1); + + sockptr->InputLen=InputLen; + + // What is left is the Command to connect to the BBS + + if (InputLen > 1) + { + if (*(CRPtr+1) == 10) + { + CRPtr++; + InputLen--; + } + + memmove(MsgPtr, CRPtr+1, InputLen); + + if (_memicmp(MsgPtr, "BPQTermTCP", 10) == 0) + { + send(sock, "Connected to TelnetServer\r", 26, 0); + sockptr->BPQTermMode = TRUE; + sockptr->MMASK = 0; // Make sure defaults to off + sockptr->InputLen -= 11; + + if (sockptr->InputLen) + { + // Monitor control info may arrive in same packet + + int P8 = 0; + + memmove(MsgPtr, &MsgPtr[11], InputLen); + if (memcmp(MsgPtr, "\\\\\\\\", 4) == 0) + { + // Monitor Control + + int n = sscanf(&MsgPtr[4], "%llx %x %x %x %x %x %x %x", + &sockptr->MMASK, &sockptr->MTX, &sockptr->MCOM, &sockptr->MonitorNODES, + &sockptr->MonitorColour, &sockptr->MUIOnly, &sockptr->UTF8, &P8); + + if (n == 5) + sockptr->MUIOnly = sockptr->UTF8 = 0; + + if (n == 6) + sockptr->UTF8 = 0; + + if (P8 == 1) + SendPortsForMonitor(sock, sockptr->UserPointer->Secure); + + + sockptr->InputLen = 0; + } + } + } + else + { + MsgPtr[InputLen] = 13; + SendtoNode(TNC, sockptr->Number, MsgPtr, InputLen+1); + } + sockptr->InputLen = 0; + } + + Appl = sockptr->UserPointer->Appl; + + if (Appl[0]) + SendtoNode(TNC, sockptr->Number, Appl, (int)strlen(Appl)); + + return 0; + } + // Bad Password + + if (sockptr->Retries++ == 4) + { + send(sock,AttemptsMsg, (int)strlen(AttemptsMsg),0); + Sleep (1000); + DataSocket_Disconnect(TNC, sockptr); //' Tidy up + } + else + { + send(sock, TCP->PasswordMsg, (int)strlen(TCP->PasswordMsg), 0); + sockptr->InputLen=0; + } + + return 0; + + default: + + return 0; + } + return 0; +} + +extern char * RigWebPage; + +int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream) +{ + int w =1, x= 1, len=0, y = 2, maxlen, InputLen, ret; + char NLMsg[3]={13,10,0}; + UCHAR * MsgPtr; + UCHAR * CRLFCRLF; + UCHAR * LenPtr; + int BodyLen, ContentLen; + struct ConnectionInfo * sockcopy; + + ret = ioctl(sock,FIONREAD,&w); + + maxlen = InputBufferLen - sockptr->InputLen; + + if (w > maxlen) w = maxlen; + + len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], w, 0); + + if (len == SOCKET_ERROR || len == 0) + { + // Failed or closed - clear connection + + // if Websock connection till app + + if (sockptr->WebSocks) + { + if (memcmp(sockptr->WebURL, "rhp", 3) == 0) + { + ProcessRHPWebSockClosed(sockptr->socket); + return 0; + } + } + else + { + TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node + DataSocket_Disconnect(TNC, sockptr); + return 0; + } + } + + MsgPtr = &sockptr->InputBuffer[0]; + sockptr->InputLen += len; + InputLen = sockptr->InputLen; + + MsgPtr[InputLen] = 0; + + if (sockptr->WebSocks) + { + // Websocks message + + int i, j; + int Fin, Opcode, Len, Mask; + char MaskingKey[4]; + char * ptr; + char * Payload; + + /* + +-+-+-+-+-------+-+-------------+-------------------------------+ + |F|R|R|R| opcode|M| Payload len | Extended payload length | + |I|S|S|S| (4) |A| (7) | (16/64) | + |N|V|V|V| |S| | (if payload len==126/127) | + | |1|2|3| |K| | | + +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + | Extended payload length continued, if payload len == 127 | + + - - - - - - - - - - - - - - - +-------------------------------+ + | |Masking-key, if MASK set to 1 | + +-------------------------------+-------------------------------+ + | Masking-key (continued) | Payload Data | + +-------------------------------- - - - - - - - - - - - - - - - + + : Payload Data continued ... : + + Octet i of the transformed data ("transformed-octet-i") is the XOR of + octet i of the original data ("original-octet-i") with octet at index + i modulo 4 of the masking key ("masking-key-octet-j"): + + j = i MOD 4 + transformed-octet-i = original-octet-i XOR masking-key-octet-j +*/ + Fin = MsgPtr[0] >> 7; + Opcode = MsgPtr[0] & 15; + Mask = MsgPtr[1] >> 7; + Len = MsgPtr[1] & 127; + + if (Len == 126) // Two Byte Len + { + Len = (MsgPtr[2] << 8) + MsgPtr[3]; + memcpy(MaskingKey, &MsgPtr[4], 4); + ptr = &MsgPtr[8]; + } + else + { + memcpy(MaskingKey, &MsgPtr[2], 4); + ptr = &MsgPtr[6]; + } + + Payload = ptr; + + for (i = 0; i < Len; i++) + { + j = i & 3; + + *ptr = *ptr ^ MaskingKey[j]; + ptr++; + } + + if (Opcode == 8) + { + Debugprintf("WebSock Close"); + } + else if (Opcode == 1) + { + if (strcmp(sockptr->WebURL, "RIGCTL") == 0) + { + // PTT Message + + char RigCMD[64]; + + sprintf(RigCMD, "%s PTT", Payload); + Rig_Command( (TRANSPORTENTRY *) -1, RigCMD); + } + else if (memcmp(sockptr->WebURL, "WMRefresh", 9) == 0) + { + sockcopy = malloc(sizeof(struct ConnectionInfo)); + sockptr->TNC = TNC; + sockptr->LastSendTime = REALTIMETICKS; + + memcpy(sockcopy, sockptr, sizeof(struct ConnectionInfo)); + + _beginthread(ProcessWebmailWebSockThread, 2048000, (VOID *)sockcopy); // Needs big stack + return 0; + } + else if (memcmp(sockptr->WebURL, "rhp", 3) == 0) + { + sockcopy = malloc(sizeof(struct ConnectionInfo)); + sockptr->TNC = TNC; + sockptr->LastSendTime = REALTIMETICKS; + + memcpy(sockcopy, sockptr, sizeof(struct ConnectionInfo)); + + ProcessRHPWebSock(sockptr->socket, Payload, Len); + sockptr->InputLen = 0; + return 0; + } + } + else + Debugprintf("WebSock Opcode %d Msg %s", Opcode, &MsgPtr[6]); + + sockptr->InputLen = 0; + return 0; + } + + // Make sure request is complete - should end crlfcrlf, and if a post have the required input message + + + CRLFCRLF = strstr(MsgPtr, "\r\n\r\n"); + + if (CRLFCRLF == 0) + return 0; + + LenPtr = strstr(MsgPtr, "Content-Length:"); + + if (LenPtr) + { + ContentLen = atoi(LenPtr + 15); + BodyLen = InputLen - (int)((CRLFCRLF + 4 - MsgPtr)); + + if (BodyLen < ContentLen) + return 0; + } + + sockcopy = malloc(sizeof(struct ConnectionInfo)); + sockptr->TNC = TNC; + sockptr->LastSendTime = REALTIMETICKS; + + memcpy(sockcopy, sockptr, sizeof(struct ConnectionInfo)); + + if(strstr(MsgPtr, "Upgrade: websocket")) + { + int LOCAL = 0, COOKIE = 0; + char * HostPtr; + char * ptr; + + sockptr->WebSocks = 1; + ShowConnections(TNC); + + memcpy(sockptr->WebURL, &MsgPtr[5], 31); + strlop(sockptr->WebURL, ' '); + if (RigWebPage) + RigWebPage[0] = 0; + + HostPtr = strstr(MsgPtr, "Host: "); + + if (HostPtr) + { + uint32_t Host; + char Hostname[32]= ""; + struct LOCALNET * LocalNet = sockptr->TNC->TCPInfo->LocalNets; + + HostPtr += 6; + memcpy(Hostname, HostPtr, 31); + strlop(Hostname, ':'); + Host = inet_addr(Hostname); + + if (strcmp(Hostname, "127.0.0.1") == 0) + LOCAL = TRUE; + else + { + if (sockptr->sin.sin_family != AF_INET6) + { + while(LocalNet) + { + uint32_t MaskedHost = sockptr->sin.sin_addr.s_addr & LocalNet->Mask; + if (MaskedHost == LocalNet->Network) + { + LOCAL = 1; + break; + } + LocalNet = LocalNet->Next; + } + } + + ptr = strstr(MsgPtr, "BPQSessionCookie=N"); + + if (ptr) + COOKIE = TRUE; + } + sockptr->WebSecure = LOCAL | COOKIE; + } + } + + + _beginthread(ProcessHTTPMessage, 2048000, (VOID *)sockcopy); // Needs big stack + + sockptr->InputLen = 0; + return 0; +} + +int DataSocket_ReadDRATS(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream) +{ + int len=0, maxlen; + + ioctl(sock,FIONREAD,&len); + + maxlen = InputBufferLen - sockptr->InputLen; + + if (len > maxlen) len = maxlen; + + len = recv(sock, &sockptr->InputBuffer[sockptr->InputLen], len, 0); + + if (len == SOCKET_ERROR || len == 0) + { + // Failed or closed - clear connection + + DRATSConnectionLost(sockptr); + DataSocket_Disconnect(TNC, sockptr); + return 0; + } + + // Make sure request is complete - should end [EOB] + + processDRATSFrame(&sockptr->InputBuffer[sockptr->InputLen], len, sockptr); + return 0; +} + + +int DataSocket_Disconnect(struct TNCINFO * TNC, struct ConnectionInfo * sockptr) +{ + int n; + + if (sockptr->SocketActive) + { + if (sockptr->socket) + closesocket(sockptr->socket); + + n = sockptr->Number; +#ifndef LINBPQ + ModifyMenu(TNC->TCPInfo->hDisMenu, n - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + n, "."); +#endif + sockptr->SocketActive = FALSE; + ShowConnections(TNC);; + } + return 0; +} + +int ShowConnections(struct TNCINFO * TNC) +{ +#ifndef LINBPQ + char msg[80]; + struct ConnectionInfo * sockptr; + int i,n; + + SendMessage(TNC->hMonitor,LB_RESETCONTENT,0,0); + + for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++) + { + sockptr=TNC->Streams[n].ConnectionInfo; + + if (!sockptr->SocketActive) + { + strcpy(msg,"Idle"); + } + else + { + if (sockptr->UserPointer == 0) + { + if (sockptr->HTTPMode) + { + char Addr[100]; + Tel_Format_Addr(sockptr, Addr); + + if (sockptr->WebSocks) + sprintf(msg, "Websock From %s", Addr); + else + sprintf(msg, "HTTP From %s", Addr); + } + else if (sockptr->DRATSMode) + { + char Addr[100]; + Tel_Format_Addr(sockptr, Addr); + sprintf(msg, "DRATS From %s", Addr); + } + else + strcpy(msg,"Logging in"); + } + else + { + i=sprintf(msg,"%-10s %-10s %2d", + sockptr->UserPointer->UserName, sockptr->Callsign, sockptr->FromHostBuffPutptr - sockptr->FromHostBuffGetptr); + } + } + SendMessage(TNC->hMonitor, LB_ADDSTRING ,0, (LPARAM)msg); + } +#endif + return 0; +} +byte * EncodeCall(byte * Call) +{ + static char axcall[10]; + + ConvToAX25(Call, axcall); + return &axcall[0]; +} +BOOL ProcessTelnetCommand(struct ConnectionInfo * sockptr, byte * Msg, int * Len) +{ + int cmd, TelOption; + int used; + char WillSupGA[3]={IAC,WILL,suppressgoahead}; + char WillEcho[3]={IAC,WILL,echo}; + char Wont[3]={IAC,WONT,echo}; + char Dont[3]={IAC,DONT,echo}; + + // Note Msg points to the IAC, which may not be at the start of the receive buffer + // Len is number of bytes left in buffer including the IAC + + if (*Len < 2) return TRUE; //' Wait for more + + cmd = Msg[1]; + + if (cmd == DOx || cmd == DONT || cmd == WILL || cmd == WONT) + if (*Len < 3) return TRUE; //' wait for option + + TelOption = Msg[2]; + + switch (cmd) + { + case DOx: + + switch (TelOption) + { + case echo: + sockptr->DoEcho = TRUE; + send(sockptr->socket,WillEcho,3,0); + break; + + case suppressgoahead: + + send(sockptr->socket,WillSupGA,3,0); + break; + + default: + + Wont[2] = TelOption; + send(sockptr->socket,Wont,3,0); + } + + used=3; + + break; + + case DONT: + + // Debug.Print "DONT"; TelOption + + switch (TelOption) + { + case echo: + sockptr->DoEcho = FALSE; + break; + } + + Wont[2] = TelOption; + send(sockptr->socket,Wont,3,0); + + used=3; + + break; + + case WILL: + + // Debug.Print "WILL"; TelOption + +// if (TelOption == echo) sockptr->DoEcho = TRUE; + + Dont[2] = TelOption; + send(sockptr->socket, Dont, 3, 0); + + used=3; + + break; + + case WONT: + +// Debug.Print "WONT"; TelOption + + used=3; + + break; + + default: + + used=2; + + } + + // remove the processed command from the buffer + + *Len -= used; + + return FALSE; +} + + +int WriteLog(char * msg) +{ + FILE *file; + char timebuf[128]; + time_t ltime; + + UCHAR Value[MAX_PATH]; + time_t T; + struct tm * tm; + + T = time(NULL); + tm = gmtime(&T); + + if (LogDirectory[0] == 0) + { + strcpy(Value, "logs/Telnet_"); + } + else + { + strcpy(Value, LogDirectory); + strcat(Value, "/"); + strcat(Value, "logs/Telnet_"); + } + + sprintf(Value, "%s%02d%02d%02d.log", Value, + tm->tm_year - 100, tm->tm_mon+1, tm->tm_mday); + + if ((file = fopen(Value, "a")) == NULL) + return FALSE; + + time(<ime); + +#ifdef LINBPQ + { + struct tm * tmp = localtime(<ime); + strftime( timebuf, 128, + "%d/%m/%Y %H:%M:%S ", tmp ); + } +#else + { + struct tm * today; + + today = localtime(<ime); + strftime(timebuf, 128, "%d/%m/%Y %H:%M:%S ", today); + } +#endif + fputs(timebuf, file); + fputs(msg, file); + fclose(file); + return 0; +} + +char LastCMSLog[256]; + +VOID WriteCMSLog(char * msg) +{ + UCHAR Value[MAX_PATH]; + time_t T; + struct tm * tm; + FILE * Handle; + char LogMsg[256]; + int MsgLen; + + if (CMSLogEnabled == FALSE) + return; + + T = time(NULL); + tm = gmtime(&T); + + if (LogDirectory[0] == 0) + { + strcpy(Value, "logs/CMSAccess"); + } + else + { + strcpy(Value, LogDirectory); + strcat(Value, "/"); + strcat(Value, "logs/CMSAccess"); + } + + sprintf(Value, "%s_%04d%02d%02d.log", Value, + tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday); + + Handle = fopen(Value, "ab"); + + if (Handle == NULL) + return; + + MsgLen = sprintf(LogMsg, "%02d:%02d:%02d %s", tm->tm_hour, tm->tm_min, tm->tm_sec, msg); + + fwrite(LogMsg , 1, MsgLen, Handle); + + fclose(Handle); + +#ifndef WIN32 + + if (strcmp(Value, LastCMSLog)) + { + UCHAR SYMLINK[MAX_PATH]; + + sprintf(SYMLINK,"%s/CMSAccessLatest.log", BPQDirectory); + unlink(SYMLINK); + strcpy(LastCMSLog, Value); + symlink(Value, SYMLINK); + } + +#endif + + return; +} + + + + + + +int Telnet_Connected(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Error) +{ + struct TCPINFO * TCP = TNC->TCPInfo; + PMSGWITHLEN buffptr; + int Stream = sockptr->Number; + char Signon[80]; + int errlen = 4; + + buffptr = (PMSGWITHLEN)GetBuff(); + if (buffptr == 0) return 0; // No buffers, so ignore + +#ifndef WIN32 + +// SO_ERROR codes + +//#define ETIMEDOUT 110 /* Connection timed out */ +//#define ECONNREFUSED 111 /* Connection refused */ +//#define EHOSTDOWN 112 /* Host is down */ +//#define EHOSTUNREACH 113 /* No route to host */ +//#define EALREADY 114 /* Operation already in progress */ +//#define EINPROGRESS 115 /* Operation now in progress */ + + if (Error == 0) + getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&Error, &errlen); + +// Debugprintf("Except Event Error after opts = %d", Error); +#endif + + if (Error) + { + if (sockptr->CMSSession && sockptr->RelaySession == 0) + { + // Try Next + + TCP->CMSFailed[sockptr->CMSIndex] = TRUE; + + if (CMSConnect(TNC, TNC->TCPInfo, &TNC->Streams[Stream], Stream)) + return 0; + + // Connect failure - if no more servers to check look for FALLBACKTORELAY + + return 0; + } + else + { + int err = 0; + int errlen = 4; + + getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&err, &errlen); + + buffptr->Len = sprintf(&buffptr->Data[0], "*** Failed to Connect\r"); + + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + + closesocket(sock); + TNC->Streams[Stream].Connecting = FALSE; + sockptr->SocketActive = FALSE; + ShowConnections(TNC); + TNC->Streams[Stream].NeedDisc = 10; + return 0; + } + } + + sockptr->LogonSent = FALSE; + + if (sockptr->CMSSession) + { + sockptr->LoginState = 3; // Password State + + sockptr->UserPointer = &CMSUser; + strcpy(sockptr->Callsign, TNC->Streams[Stream].MyCall); + + sockptr->DoEcho = FALSE; + sockptr->FBBMode = TRUE; + sockptr->RelayMode = FALSE; + sockptr->ClientSession = FALSE; + sockptr->SyncMode = FALSE; + + if (TCP->CMS) + SaveCMSHostInfo(TNC->Port, TNC->TCPInfo, sockptr->CMSIndex); + + if (CMSLogEnabled) + { + char logmsg[120]; + + if (sockptr->RelaySession) + sprintf(logmsg,"%d %s Connected to RELAY\r\n", sockptr->Number, TNC->Streams[Stream].MyCall); + else + sprintf(logmsg,"%d %s Connected to CMS\r\n", sockptr->Number, TNC->Streams[Stream].MyCall); + + WriteCMSLog (logmsg); + } + + if (sockptr->RelaySession) + buffptr->Len = sprintf(&buffptr->Data[0], "*** %s Connected to RELAY\r", TNC->Streams[Stream].MyCall); + else + buffptr->Len = sprintf(&buffptr->Data[0], "*** %s Connected to CMS\r", TNC->Streams[Stream].MyCall); + } + else + { + sockptr->LoginState = 2; // Data State + sockptr->UserPointer = &HostUser; + strcpy(sockptr->Callsign, TNC->Streams[Stream].MyCall); + sockptr->DoEcho = FALSE; + sockptr->ClientSession = TRUE; + + if (sockptr->SyncMode) + { + char Addr[256]; + Tel_Format_Addr(sockptr, Addr); + + buffptr->Len = sprintf(&buffptr->Data[0], "*** Connected to SYNC %s:%d\r", Addr, htons(sockptr->sin.sin_port)); + send(sockptr->socket, sockptr->Signon, (int)strlen(sockptr->Signon), 0); + } + else + { + if (sockptr->Signon[0]) + { + buffptr->Len = sprintf(&buffptr->Data[0], "*** Connected to Server\r"); + send(sockptr->socket, sockptr->Signon, (int)strlen(sockptr->Signon), 0); + } + else + { + if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4CROSSLINK->APPL[0]) + buffptr->Len = sprintf(&buffptr->Data[0], "*** Connected to %s\r", + TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4CROSSLINK->APPL); + else + buffptr->Len = sprintf(&buffptr->Data[0], "*** Connected to APPL\r"); + + if (sockptr->NoCallsign == FALSE) + send(sockptr->socket, Signon, sprintf(Signon, "%s\r\n", TNC->Streams[Stream].MyCall), 0); + } + } + } + + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + + sockptr->SocketActive = TRUE; + sockptr->InputLen = 0; +// sockptr->Number = Stream; + sockptr->RelayMode = FALSE; + sockptr->ConnectTime = time(NULL); + TNC->Streams[Stream].Connecting = FALSE; + TNC->Streams[Stream].Connected = TRUE; + + if (sockptr->ADIF == NULL) + sockptr->ADIF = malloc(sizeof(struct ADIF)); + + memset(sockptr->ADIF, 0, sizeof(struct ADIF)); + + strcpy(sockptr->ADIF->Call, TNC->Streams[Stream].MyCall); + + ShowConnections(TNC); + + if (sockptr->FromHostBuffer == 0) + { + sockptr->FromHostBuffer = malloc(10000); + sockptr->FromHostBufferSize = 10000; + } + + sockptr->FromHostBuffPutptr = sockptr->FromHostBuffGetptr = 0; + + TNC->Streams[Stream].bytesRXed = TNC->Streams[Stream].bytesTXed = 0; + + return 0; +} + +VOID ReportError(struct STREAMINFO * STREAM, char * Msg) +{ + PMSGWITHLEN buffptr; + + buffptr = (PMSGWITHLEN)GetBuff(); + if (buffptr == 0) return; // No buffers, so ignore + + buffptr->Len = sprintf(&buffptr->Data[0], "Error - %s\r", Msg); + + C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); +} + +VOID Report(struct STREAMINFO * STREAM, char * Msg) +{ + PMSGWITHLEN buffptr; + + buffptr = (PMSGWITHLEN)GetBuff(); + if (buffptr == 0) return; // No buffers, so ignore + + buffptr->Len = sprintf(&buffptr->Data[0], "%s\r", Msg); + + C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); +} + +void CheckCMSThread(void * TNC); + +BOOL CheckCMS(struct TNCINFO * TNC) +{ + if (TNC->TCPInfo->CMS) + { + TNC->TCPInfo->CheckCMSTimer = 0; + _beginthread(CheckCMSThread, 0, (void *)TNC); + } + return 0; +} + +void CheckCMSThread(void * TNCPtr) +{ + // Resolve Name and check connectivity to each address + + struct TNCINFO * TNC = (struct TNCINFO *)TNCPtr; + struct TCPINFO * TCP = TNC->TCPInfo; +// struct hostent * HostEnt; + struct in_addr addr; + struct hostent *remoteHost; + char **pAlias; int i = 0; + BOOL INETOK = FALSE; + struct addrinfo hints, *res = 0, *saveres; + int n; + unsigned long cms; + + TCP->UseCachedCMSAddrs = FALSE; + + // if TCP->CMSServer is an ip address use it + + cms = inet_addr(TCP->CMSServer); + + if (cms != INADDR_NONE) + { + Debugprintf("Using %s for CMS Server", TCP->CMSServer); + TCP->CMSAddr[0].s_addr = cms; + TCP->CMSFailed[0] = FALSE; + TCP->CMSName[0] = _strdup(TCP->CMSServer); // Save Host Name + TCP->NumberofCMSAddrs = 1; + goto CheckServers; + } + + // First make sure we have a functioning DNS + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET6; // use IPv4 or IPv6, whichever + hints.ai_socktype = SOCK_DGRAM; + + n = getaddrinfo("a.root-servers.net", NULL, &hints, &res); + + if (n == 0) + goto rootok; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever + hints.ai_socktype = SOCK_DGRAM; + n = getaddrinfo("b.root-servers.net", NULL, &hints, &res); + + if (n == 0) + goto rootok; + + Debugprintf("Resolve root nameserver failed"); + + // Most likely is a local Internet Outage, but we could have Internet, but no name servers + // Either way, switch to using cached CMS addresses. CMS Validation will check connectivity + + TCP->UseCachedCMSAddrs = TRUE; + goto CheckServers; + +rootok: + + freeaddrinfo(res); + + INETOK = TRUE; // We have connectivity + + res = 0; + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever + hints.ai_socktype = SOCK_DGRAM; + n = getaddrinfo(TCP->CMSServer, NULL, &hints, &res); + + if (n || !res || res->ai_next == 0) // Resolve Failed, or Returned only one Host + { + // Switch to Cached Servers + + if (res) + { + // If Host is amazonaws, allow it + + remoteHost = gethostbyaddr((char *) &res->ai_addr->sa_data[2], 4, AF_INET); + + if (remoteHost && strstr(_strlwr(remoteHost->h_name), "amazonaws")) + goto resok; + + Debugprintf("Resolve CMS returned only one host"); + freeaddrinfo(res); + } + else + Debugprintf("Resolve CMS Failed"); + + TCP->UseCachedCMSAddrs = TRUE; + + goto CheckServers; + } + +resok: + + saveres = res; + + while (res) + { + memcpy(&addr.s_addr, &res->ai_addr->sa_data[2], 4); + TCP->CMSAddr[i] = addr; + TCP->CMSFailed[i] = FALSE; + i++; + res = res->ai_next; + } + + freeaddrinfo(saveres); + + TCP->NumberofCMSAddrs = i; + + i = 0; + + while (i < TCP->NumberofCMSAddrs) + { + if (TCP->CMSName[i]) + free(TCP->CMSName[i]); + + remoteHost = gethostbyaddr((char *) &TCP->CMSAddr[i], 4, AF_INET); + + if (remoteHost == NULL) + { + int dwError = WSAGetLastError(); + + TCP->CMSName[i] = NULL; + + if (dwError != 0) + { + if (dwError == HOST_NOT_FOUND) + Debugprintf("CMS - Host not found"); + else if (dwError == NO_DATA) + Debugprintf("CMS No data record found"); + else + Debugprintf("CMS Gethost failed %d", dwError); + } + } + else + { + Debugprintf("CMS #%d %s Official name : %s",i, inet_ntoa(TCP->CMSAddr[i]), remoteHost->h_name); + + TCP->CMSName[i] = _strdup(remoteHost->h_name); // Save Host Name + + for (pAlias = remoteHost->h_aliases; *pAlias != 0; pAlias++) + { + Debugprintf("\tAlternate name #%d: %s\n", i, *pAlias); + } + } + i++; + } + + TCP->NumberofCMSAddrs = i; + +CheckServers: +#ifndef LINBPQ + CheckMenuItem(TNC->TCPInfo->hActionMenu, 4, MF_BYPOSITION | TCP->UseCachedCMSAddrs<<3); +#endif + if (TCP->UseCachedCMSAddrs) + { + // Get Cached Servers from CMSInfo.txt + + GetCMSCachedInfo(TNC); + } + + if (TCP->NumberofCMSAddrs == 0) + { + TCP->CMSOK = FALSE; +#ifndef LINBPQ + SetWindowText(TCP->hCMSWnd, "NO CMS"); +#endif + return; + } + + // if we don't know we have Internet connectivity, make sure we can connect to at least one of them + + TCP->CMSOK = INETOK | CMSCheck(TNC, TCP); // If we know we have Inet, dont check connectivity + +#ifndef LINBPQ + if (TCP->CMSOK) + MySetWindowText(TCP->hCMSWnd, "CMS OK"); + else + MySetWindowText(TCP->hCMSWnd, "NO CMS"); +#endif + return; +} + +#define MAX_KEY_LENGTH 255 +#define MAX_VALUE_NAME 255 +#define MAX_VALUE_DATA 255 + + + +VOID GetCMSCachedInfo(struct TNCINFO * TNC) +{ + struct TCPINFO * TCP = TNC->TCPInfo; + ULONG IPAD; + char inname[256]; + + FILE *in; + char Buffer[2048]; + char *buf = Buffer; + char *ptr1, *ptr2, *context; + int i = 0; + + if (LogDirectory[0] == 0) + { + strcpy(inname, "logs/CMSInfo.txt"); + } + else + { + strcpy(inname, LogDirectory); + strcat(inname, "/"); + strcat(inname, "logs/CMSInfo.txt"); + } + + TCP->NumberofCMSAddrs = 0; + + in = fopen(inname, "r"); + + if (!(in)) return; + + while(fgets(buf, 128, in)) + { + ptr1 = strtok_s(buf, ", ", &context); + ptr2 = strtok_s(NULL, ", ", &context); // Skip Time + ptr2 = strtok_s(NULL, ", ", &context); + + if (ptr1[0] < 32 || ptr1[0] > 127 || ptr2 == NULL) + continue; + + IPAD = inet_addr(ptr2); + + memcpy(&TCP->CMSAddr[i], &IPAD, 4); + + TCP->CMSFailed[i] = FALSE; + + if (TCP->CMSName[i]) + free(TCP->CMSName[i]); + + TCP->CMSName[i] = _strdup(ptr1); // Save Host Name + i++; + + if (i >= MaxCMS) + break; + } + + fclose(in); + + TCP->NumberofCMSAddrs = i; + + return; +} + +BOOL CMSCheck(struct TNCINFO * TNC, struct TCPINFO * TCP) +{ + // Make sure at least one CMS can be connected to + + u_long param=1; + BOOL bcopt=TRUE; + SOCKET sock; + struct sockaddr_in sinx; + struct sockaddr_in destaddr; + int addrlen=sizeof(sinx); + int n = 0; + + destaddr.sin_family = AF_INET; + destaddr.sin_port = htons(8772); + + sinx.sin_family = AF_INET; + sinx.sin_addr.s_addr = INADDR_ANY; + sinx.sin_port = 0; + + for (n = 0; n < TCP->NumberofCMSAddrs; n++) + { + sock = socket(AF_INET, SOCK_STREAM, 0); + + if (sock == INVALID_SOCKET) + return FALSE; + + memcpy(&destaddr.sin_addr.s_addr, &TCP->CMSAddr[n], 4); + + setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4); + + if (bind(sock, (struct sockaddr *) &sinx, addrlen) != 0 ) + return FALSE; + + if (connect(sock,(struct sockaddr *) &destaddr, sizeof(destaddr)) == 0) + { + closesocket(sock); + return TRUE; + } + + // Failed - try next + + if (TCP->CMSName[n]) + Debugprintf("Check CMS Failed for %s", TCP->CMSName[n]); + closesocket(sock); + } + return FALSE; +} + + + +int CMSConnect(struct TNCINFO * TNC, struct TCPINFO * TCP, struct STREAMINFO * STREAM, int Stream) +{ + int err; + u_long param=1; + BOOL bcopt=TRUE; + struct ConnectionInfo * sockptr; + SOCKET sock; + struct sockaddr_in sinx; + struct sockaddr_in destaddr; + int addrlen=sizeof(sinx); + int n; + char Msg[80]; + + sockptr = STREAM->ConnectionInfo; + + sock = sockptr->socket = socket(AF_INET, SOCK_STREAM, 0); + + if (sock == INVALID_SOCKET) + { + ReportError(STREAM, "Create Socket Failed"); + return FALSE; + } + + if (sockptr->ADIF == NULL) + sockptr->ADIF = malloc(sizeof(struct ADIF)); + + memset(sockptr->ADIF, 0, sizeof(struct ADIF)); + + sockptr->SocketActive = TRUE; + sockptr->InputLen = 0; + sockptr->LoginState = 2; + sockptr->UserPointer = 0; + sockptr->DoEcho = FALSE; + sockptr->BPQTermMode = FALSE; + + sockptr->FBBMode = TRUE; // Raw Data + sockptr->NeedLF = FALSE; + + if (sockptr->ADIF == NULL) + sockptr->ADIF = malloc(sizeof(struct ADIF)); + + memset(sockptr->ADIF, 0, sizeof(struct ADIF)); + + destaddr.sin_family = AF_INET; + destaddr.sin_port = htons(8772); + + // See if current CMS is down + + n = 0; + + while (TCP->CMSFailed[TCP->NextCMSAddr]) + { + TCP->NextCMSAddr++; + if (TCP->NextCMSAddr >= TCP->NumberofCMSAddrs) TCP->NextCMSAddr = 0; + n++; + + if (n == TCP->NumberofCMSAddrs) + { + TCP->CMSOK = FALSE; +#ifndef LINBPQ + DrawMenuBar(TNC->hDlg); +#endif + ReportError(STREAM, "All CMS Servers are inaccessible"); + closesocket(sock); + + if (TCP->RELAYHOST[0] && TCP->FallbacktoRelay && STREAM->NoCMSFallback == 0) + { + STREAM->Connecting = TRUE; + STREAM->ConnectionInfo->CMSSession = TRUE; + STREAM->ConnectionInfo->RelaySession = TRUE; + return TCPConnect(TNC, TCP, STREAM, TCP->RELAYHOST, 8772, TRUE); + } + + STREAM->NeedDisc = 10; + TNC->Streams[Stream].Connecting = FALSE; + sockptr->SocketActive = FALSE; + ShowConnections(TNC); + return FALSE; + } + } + + sockptr->CMSIndex = TCP->NextCMSAddr; + + sprintf(Msg, "Trying %s", TCP->CMSName[TCP->NextCMSAddr]); + + memcpy(&destaddr.sin_addr.s_addr, &TCP->CMSAddr[TCP->NextCMSAddr++], 4); + + if (TCP->NextCMSAddr >= TCP->NumberofCMSAddrs) + TCP->NextCMSAddr = 0; + + ioctl(sockptr->socket, FIONBIO, ¶m); + + setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4); + + sinx.sin_family = AF_INET; + sinx.sin_addr.s_addr = INADDR_ANY; + sinx.sin_port = 0; + + if (bind(sockptr->socket, (struct sockaddr *) &sinx, addrlen) != 0 ) + { + ReportError(STREAM, "Bind Failed"); + return FALSE; + } + +#ifndef LINBPQ + ModifyMenu(TCP->hDisMenu, Stream - 1, MF_BYPOSITION | MF_STRING, IDM_DISCONNECT + Stream, "CMS"); +#endif + + Report(STREAM, Msg); + + if (connect(sockptr->socket,(struct sockaddr *) &destaddr, sizeof(destaddr)) == 0) + { + // + // Connected successful + // + + ReportError(STREAM, "*** Connected"); + return TRUE; + } + else + { + err=WSAGetLastError(); + + if (err == 10035 || err == 115 || err == 36 || err == 150) //EWOULDBLOCK + { + // Connect in Progress + + sockptr->UserPointer = &CMSUser; + return TRUE; + } + else + { + // Connect failed + + closesocket(sockptr->socket); + + if (sockptr->CMSSession && sockptr->RelaySession == 0) + { + // Try Next + + TCP->CMSFailed[sockptr->CMSIndex] = TRUE; + Debugprintf("Connect Failed %d, trying next", err); + CMSConnect(TNC, TNC->TCPInfo, &TNC->Streams[Stream], Stream); + return 0; + } + + ReportError(STREAM, "Connect Failed"); + CheckCMS(TNC); + + STREAM->Connecting = FALSE; + sockptr->SocketActive = FALSE; + ShowConnections(TNC); + STREAM->NeedDisc = 10; + + return FALSE; + } + } + return FALSE; + +} + +VOID SaveCMSHostInfo(int port, struct TCPINFO * TCP, int CMSNo) +{ + char Info[256]; + char inname[256]; + char outname[256]; + + unsigned char work[4]; + FILE *in, *out; + char Buffer[2048]; + char *buf = Buffer; + + if (TCP->CMS == 0) + return; + + if (CMSNo > 9 || CMSNo < 0 || TCP->CMSName[CMSNo] == 0) + { + Debugprintf("SaveCMSHostInfo invalid CMS Number %d", CMSNo); + return; + } + + if (LogDirectory[0] == 0) + { + strcpy(inname, "logs/CMSInfo.txt"); + } + else + { + strcpy(inname, LogDirectory); + strcat(inname, "/"); + strcat(inname, "logs/CMSInfo.txt"); + } + + if (LogDirectory[0] == 0) + { + strcpy(outname, "logs/CMSInfo.tmp"); + } + else + { + strcpy(outname, LogDirectory); + strcat(outname, "/"); + strcat(outname, "logs/CMSInfo.tmp"); + } + + memcpy(work, &TCP->CMSAddr[CMSNo].s_addr, 4); + + sprintf(Info,"%s %d %d.%d.%d.%d\n", TCP->CMSName[CMSNo], (int)time(NULL), + work[0], work[1], work[2], work[3]); + + + in = fopen(inname, "r"); + + if (!(in)) + { + in = fopen(inname, "w"); + + if (!(in)) + { + perror("Failed to create CMSInfo.txt"); + Debugprintf("Failed to create CMSInfo.txt"); + return; + } + fclose(in); + in = fopen(inname, "r"); + } + + if (!(in)) return; + + out = fopen(outname, "w"); + + if (!(out)) return; + + while(fgets(buf, 128, in)) + { + char addr[256]; + time_t t; + char ip[256]; + int n; + + if (sizeof(time_t) == 4) + n = sscanf(buf,"%s %d %s", addr, (int *)&t, ip); + else + n = sscanf(buf, "%s %lld %s", addr, &t, ip); + + if (n == 3) + { + time_t age = time(NULL) - t; + + // if not current server and not too old, copy across + + if (addr[0] > 31 && addr[0] < 127) + if ((age < 86400 * 30) && strcmp(addr, TCP->CMSName[CMSNo]) != 0) + fputs(buf, out); + } + } + + fputs(Info, out); + + fclose(in); + fclose(out); + + remove(inname); + rename(outname, inname); + + return; +} + +int TCPConnect(struct TNCINFO * TNC, struct TCPINFO * TCP, struct STREAMINFO * STREAM, char * Host, int Port, BOOL FBB) +{ + int err; + u_long param=1; + BOOL bcopt=TRUE; + struct ConnectionInfo * sockptr; + SOCKET sock; + struct sockaddr_in sinx; + struct sockaddr_in destaddr; + int addrlen=sizeof(sinx); + int i; + + sockptr = STREAM->ConnectionInfo; + + sock = sockptr->socket = socket(AF_INET, SOCK_STREAM, 0); + + if (sock == INVALID_SOCKET) + { + ReportError(STREAM, "Create Socket Failed"); + return FALSE; + } + + sockptr->SocketActive = TRUE; + sockptr->InputLen = 0; + sockptr->LoginState = 2; + sockptr->UserPointer = 0; + sockptr->DoEcho = FALSE; + + sockptr->FBBMode = FBB; // Raw Data + + if (sockptr->ADIF == NULL) + sockptr->ADIF = malloc(sizeof(struct ADIF)); + + memset(sockptr->ADIF, 0, sizeof(struct ADIF)); + + + // Resolve Name if needed + + sockptr->sin.sin_family = AF_INET; + sockptr->sin.sin_port = htons(Port); + + sockptr->sin.sin_addr.s_addr = inet_addr(Host); + + if (sockptr->sin.sin_addr.s_addr == INADDR_NONE) + { + struct hostent * HostEnt; + + // Resolve name to address + + HostEnt = gethostbyname(Host); + + if (!HostEnt) + { + ReportError(STREAM, "Resolve HostName Failed"); + return FALSE; // Resolve failed + } + i = 0; + while (HostEnt->h_addr_list[i] != 0) + { + struct in_addr addr; + addr.s_addr = *(u_long *) HostEnt->h_addr_list[i++]; + } + memcpy(&sockptr->sin.sin_addr.s_addr, HostEnt->h_addr, 4); + } + + ioctl (sockptr->socket, FIONBIO, ¶m); + + setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4); + + sinx.sin_family = AF_INET; + sinx.sin_addr.s_addr = INADDR_ANY; + sinx.sin_port = 0; + + if (bind(sockptr->socket, (struct sockaddr *) &sinx, addrlen) != 0 ) + { + ReportError(STREAM, "Bind Failed"); + return FALSE; + } + + if (LogEnabled) + { + char logmsg[512]; + + sprintf(logmsg,"%d Outward Connect to %s Port %d\n", sockptr->Number, Host, Port); + WriteLog (logmsg); + } + + + if (connect(sockptr->socket,(struct sockaddr *) &sockptr->sin, sizeof(destaddr)) == 0) + { + // + // Connected successful + // + + ReportError(STREAM, "*** Connected"); + + // Get Send Buffer Size + + return TRUE; + } + else + { + err=WSAGetLastError(); + + if (err == 10035 || err == 115 || err == 36) //EWOULDBLOCK + { + // Connect in Progress + + sockptr->UserPointer = &HostUser; + return TRUE; + } + else + { + // Connect failed + + closesocket(sockptr->socket); + ReportError(STREAM, "Connect Failed"); + STREAM->Connecting = FALSE; + sockptr->SocketActive = FALSE; + ShowConnections(TNC); + STREAM->NeedDisc = 10; + + return FALSE; + } + } + + return FALSE; + +} + + +VOID Tel_Format_Addr(struct ConnectionInfo * sockptr, char * dst) +{ + unsigned char * src; + char zeros[12] = ""; + char * ptr; + struct + { + int base, len; + } best, cur; + unsigned int words[8]; + int i; + + if (sockptr->sin.sin_family != AF_INET6) + { + unsigned char work[4]; + memcpy(work, &sockptr->sin.sin_addr.s_addr, 4); + sprintf(dst,"%d.%d.%d.%d", work[0], work[1], work[2], work[3]); + return; + } + + src = (unsigned char *)&sockptr->sin6.sin6_addr; + + // See if Encapsulated IPV4 addr + + if (src[12] != 0) + { + if (memcmp(src, zeros, 12) == 0) // 12 zeros, followed by non-zero + { + sprintf(dst,"::%d.%d.%d.%d", src[12], src[13], src[14], src[15]); + return; + } + } + + // Convert 16 bytes to 8 words + + for (i = 0; i < 16; i += 2) + words[i / 2] = (src[i] << 8) | src[i + 1]; + + // Look for longest run of zeros + + best.base = -1; + cur.base = -1; + + for (i = 0; i < 8; i++) + { + if (words[i] == 0) + { + if (cur.base == -1) + cur.base = i, cur.len = 1; // New run, save start + else + cur.len++; // Continuation - increment length + } + else + { + // End of a run of zeros + + if (cur.base != -1) + { + // See if this run is longer + + if (best.base == -1 || cur.len > best.len) + best = cur; + + cur.base = -1; // Start again + } + } + } + + if (cur.base != -1) + { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + + if (best.base != -1 && best.len < 2) + best.base = -1; + + ptr = dst; + + for (i = 0; i < 8; i++) + { + /* Are we inside the best run of 0x00's? */ + + if (best.base != -1 && i >= best.base && i < (best.base + best.len)) + { + // Just output one : for whole string of zeros + + *ptr++ = ':'; + i = best.base + best.len - 1; // skip rest of zeros + continue; + } + + /* Are we following an initial run of 0x00s or any real hex? */ + + if (i != 0) + *ptr++ = ':'; + + ptr += sprintf (ptr, "%x", words[i]); + + // Was it a trailing run of 0x00's? + } + + if (best.base != -1 && (best.base + best.len) == 8) + *ptr++ = ':'; + + *ptr++ = '\0'; +} + +BOOL TelSendPacket(int Stream, struct STREAMINFO * STREAM, PMSGWITHLEN buffptr, struct ADIF * ADIF) +{ + int datalen; + UCHAR * MsgPtr; + SOCKET sock; + struct ConnectionInfo * sockptr = STREAM->ConnectionInfo; + + datalen = (int)buffptr->Len; + MsgPtr = &buffptr->Data[0]; + + STREAM->bytesTXed += datalen; + + sock = sockptr->socket; + + if (sockptr->UserPointer == &CMSUser) + { + WritetoTrace(Stream, MsgPtr, datalen, ADIF, 'S'); + } + + if (sockptr->UTF8) + { + // Convert any non-utf8 chars + + if (IsUTF8(MsgPtr, datalen) == FALSE) + { + unsigned char UTF[1024]; + int u, code; + + // Try to guess encoding + + code = TrytoGuessCode(MsgPtr, datalen); + + if (code == 437) + u = Convert437toUTF8(MsgPtr, datalen, UTF); + else if (code == 1251) + u = Convert1251toUTF8(MsgPtr, datalen, UTF); + else + u = Convert1252toUTF8(MsgPtr, datalen, UTF); + + SendAndCheck(sockptr, UTF, u, 0); + ReleaseBuffer(buffptr); + return TRUE; + } + } + + if (sockptr->FBBMode && sockptr->NeedLF == FALSE) + { +/* + // if Outward Connect to FBB, Replace ff with ffff + + if (0) // if we use this need to fix retry + { + char * ptr2, * ptr = &MsgPtr[0]; + int i; + do + { + ptr2 = memchr(ptr, 255, datalen); + + if (ptr2 == 0) + { + // no ff, so just send as is + + xxxsend(sock, ptr, datalen, 0); + i=0; + break; + } + + i=ptr2+1-ptr; + + xxsend(sock,ptr,i,0); + xxsend(sock,"\xff",1,0); + + datalen-=i; + ptr=ptr2+1; + } + while (datalen>0); + } +*/ + // Normal FBB Mode path + + BOOL ret = SendAndCheck(sockptr, MsgPtr, datalen, 0); + ReleaseBuffer(buffptr); + return ret; + } + + // Not FBB mode, or FBB and NEEDLF Replace cr with crlf + + { + unsigned char Out[1024]; + unsigned char c; + unsigned char * ptr2 = Out; + unsigned char * ptr = &MsgPtr[0]; + + while (datalen--) + { + c = (*ptr++); + + if (c == 13) + { + *(ptr2++) = 13; + *(ptr2++) = 10; + } + else + *(ptr2++) = c; + } + + ReleaseBuffer(buffptr); + return SendAndCheck(sockptr, Out, (int)(ptr2 - Out), 0); + } +} + +VOID ProcessTrimodeCommand(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, char * MsgPtr) +{ + struct STREAMINFO * STREAM = &TNC->Streams[sockptr->Number]; + int Port = 4; + + Debugprintf(MsgPtr); + + if (strcmp(MsgPtr, "CLOSE") == 0) + { + if (STREAM->Connected) + { + STREAM->ReportDISC = TRUE; + } + } + +// MYCALLSIGN XE2BNC + else + if (memcmp(MsgPtr, "MYCALLSIGN", 10) == 0) + { + char * call = &MsgPtr[11]; + + if (strlen(call) > 9) + call[9] = 0; + + memcpy(STREAM->MyCall, call, 10); + + ConvToAX25(call, &TNC->PortRecord->ATTACHEDSESSIONS[sockptr->Number]->L4USER[0]); + + strcpy(&TNCInfo[Port]->Streams[0].MyCall[0], call); + } + + +// TARGETCALLSIGN KE7XO + else + if (memcmp(MsgPtr, "TARGETCALLSIGN", 14) == 0) + { + char * call = &MsgPtr[15]; + + if (strlen(call) > 9) + call[9] = 0; + + memcpy(STREAM->RemoteCall, call, 10); + } +// INITIATECALL 50 + else + if (memcmp(MsgPtr, "INITIATECALL", 12) == 0) + { + char Cmd[80]; + int n; + + n = sprintf(Cmd,"C %s\r", STREAM->RemoteCall); + + SendtoNode(TNC, sockptr->Number, Cmd, n); + } + + +// CHANNEL 3586500,None,None + else + if (memcmp(MsgPtr, "CHANNEL", 7) == 0) + { + double Freq = atof(&MsgPtr[8]); + char Radiocmd[80]; + int n; + + strcpy(sockptr->Callsign, "G8BPQ"); + + n = sprintf(Radiocmd,"RADIO %f %s\r", Freq/1000000, "USB"); + + SendtoNode(TNC, sockptr->Number, Radiocmd, n); + } + + else + if (memcmp(MsgPtr, "PROTOCOL", 8) == 0) + { + // Attach the relevant port + + SendtoNode(TNC, sockptr->Number, "ATTACH 4\r", 9); + } + + else + if (strcmp(MsgPtr, "BUSY") == 0) + send(sockptr->socket, "BUSY False\r\n", 12,0); + + + send(sockptr->socket, "CMD\r\n", 5,0); + +// SendtoNode(TNC, sockptr->Number, NodeLine, len); +} + + +VOID ProcessTrimodeResponse(struct TNCINFO * TNC, struct STREAMINFO * STREAM, unsigned char * MsgPtr, int Msglen) +{ + MsgPtr[Msglen] = 0; + + if (STREAM->ConnectionInfo->TriModeConnected) + { + // Send over the Data Socket + + send(STREAM->ConnectionInfo->TriModeDataSock, MsgPtr, Msglen, 0); + + return; + } + + strlop(MsgPtr, 13); + Debugprintf(MsgPtr); + + if (memcmp(MsgPtr, "*** Connected to ", 17) == 0) + { + char Cmd[80]; + int n; + + n = sprintf(Cmd,"CONNECTED %s\r", &MsgPtr[17]); + + STREAM->ConnectionInfo->TriModeConnected = TRUE; + + send(STREAM->ConnectionInfo->socket, Cmd, n, 0); + } +} + +VOID ProcessTriModeDataMessage(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, struct STREAMINFO * STREAM) +{ + int len=0; + char NLMsg[3]={13,10,0}; + char RelayMsg[] = "No CMS connection available - using local BPQMail\r"; + struct TCPINFO * TCP = TNC->TCPInfo; + unsigned char Buffer[256]; + + ioctl(sock,FIONREAD,&len); + + if (len > 256) len = 256; + + len = recv(sock, Buffer, len, 0); + + if (len == SOCKET_ERROR || len ==0) + { + // Failed or closed - clear connection + + closesocket(sock); + return; + } + + SendtoNode(TNC, sockptr->Number, Buffer, len); +} + +extern struct DATAMESSAGE * REPLYBUFFER; +char * __cdecl Cmdprintf(TRANSPORTENTRY * Session, char * Bufferptr, const char * format, ...); + + +VOID RECONFIGTELNET (TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD) +{ + int Port = 0, index =0; + char * ptr, *Context; + struct PORTCONTROL * PORT = NULL; + struct TNCINFO * TNC; + char * ptr1, * ptr2; + char buf[256],errbuf[256]; + char * Config; + struct TCPINFO * TCP; + + ptr = strtok_s(CmdTail, " ", &Context); + + if (ptr) + Port = atoi(ptr); + + if (Port) + PORT = GetPortTableEntryFromPortNum(Port); + + if (PORT == NULL) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + TNC = TNCInfo[Port]; + + if (TNC == NULL || TNC->Hardware != H_TELNET) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet port\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + TCP = TNC->TCPInfo; + + ptr = strtok_s(NULL, " ", &Context); + + if (ptr && _stricmp(ptr, "ALL") == 0) + { + // Use EXTRESTART Code + + PEXTPORTDATA PORTVEC = (PEXTPORTDATA) PORT; + PORTVEC->EXTRESTART = 1; + + Bufferptr = Cmdprintf(Session, Bufferptr, "Reconfig Telnet Ok\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + if (ptr && _stricmp(ptr, "USERS") == 0) + { + // Reconfig Users + + if (!ProcessConfig()) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Failed to reread config file - leaving config unchanged\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + Config = PortConfig[Port]; + + if (Config == NULL) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "No Config Entries found\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + // Don't free old user records - sessions may have pointers to them + + // Free the header + + if (TCP->UserRecPtr) + { + free(TCP->UserRecPtr); + TCP->UserRecPtr = NULL; + } + + TCP->NumberofUsers = 0; + + // Look for USER lines + + ptr1 = Config; + ptr2 = strchr(ptr1, 13); + + while(ptr2) + { + memcpy(buf, ptr1, ptr2 - ptr1 + 1); + buf[ptr2 - ptr1 + 1] = 0; + ptr1 = ptr2 + 2; + ptr2 = strchr(ptr1, 13); + strcpy(errbuf,buf); // save in case of erro + + if (_memicmp(buf, "USER=", 5) == 0 || _memicmp(buf, "USER ", 5) == 0) + { + char *User, *Pwd, *UserCall, *Secure, * Appl; + int End = (int)strlen(buf) -1; + struct UserRec * USER; + char Param[8][256]; + char * ptr1, * ptr2; + int n = 0; + char * value = &buf[5]; + + // USER=user,password,call,appl,SYSOP + + memset(Param, 0, 2048); + strlop(value, 13); + strlop(value, ';'); + + ptr1 = value; + + while (ptr1 && *ptr1 && n < 8) + { + ptr2 = strchr(ptr1, ','); + if (ptr2) *ptr2++ = 0; + + strcpy(&Param[n][0], ptr1); + strlop(Param[n++], ' '); + ptr1 = ptr2; + while(ptr1 && *ptr1 && *ptr1 == ' ') + ptr1++; + } + + + User = &Param[0][0]; + + if (_stricmp(User, "ANON") == 0) + { + strcpy(&Param[2][0], "ANON"); + strcpy(&Param[4][0], ""); // Dont allow SYSOP if ANON + } + + Pwd = &Param[1][0]; + UserCall = &Param[2][0]; + Appl = &Param[3][0]; + Secure = &Param[4][0]; + + if (User[0] == 0 || Pwd[0] == 0 || UserCall[0] == 0) // invalid record + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Bad USER Record %s\r", errbuf); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + _strupr(UserCall); + + if (TCP->NumberofUsers == 0) + TCP->UserRecPtr = malloc(sizeof(void *)); + else + TCP->UserRecPtr = realloc(TCP->UserRecPtr, (TCP->NumberofUsers+1) * sizeof(void *)); + + USER = zalloc(sizeof(struct UserRec)); + + TCP->UserRecPtr[TCP->NumberofUsers] = USER; + + USER->Callsign = _strdup(UserCall); + USER->Password = _strdup(Pwd); + USER->UserName = _strdup(User); + USER->Appl = zalloc(32); + USER->Secure = FALSE; + + if (_stricmp(Secure, "SYSOP") == 0) + USER->Secure = TRUE; + + if (Appl[0] && strcmp(Appl, "\"\"") != 0) + { + strcpy(USER->Appl, _strupr(Appl)); + strcat(USER->Appl, "\r\n"); + } + TCP->NumberofUsers++; + } + } + + Bufferptr = Cmdprintf(Session, Bufferptr, "Reread Telnet Users Ok - %d USER Records\r", TCP->NumberofUsers); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid parameter - use either USERS or ALL \r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); +} + +VOID SHOWTELNET(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD) +{ + // DISPLAY Telnet Server Status Mheard + + int Port = 0, index =0; + char * ptr, *Context; + struct PORTCONTROL * PORT = NULL; + int txlen = 0, n; + struct TNCINFO * TNC; + char msg[80]; + struct ConnectionInfo * sockptr; + int i; + char CMS[] = "CMS Disabled"; + + ptr = strtok_s(CmdTail, " ", &Context); + + if (ptr) + Port = atoi(ptr); + + if (Port) + PORT = GetPortTableEntryFromPortNum(Port); + + if (PORT == NULL) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid Port\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + TNC = TNCInfo[Port]; + + if (TNC == NULL || TNC->Hardware != H_TELNET) + { + Bufferptr = Cmdprintf(Session, Bufferptr, "Not a Telnet port\r"); + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); + return; + } + + if (TNC->TCPInfo->CMS) + if (TNC->TCPInfo->CMSOK) + strcpy(CMS, "CMS Ok"); + else + strcpy(CMS, "No CMS"); + + Bufferptr = Cmdprintf(Session, Bufferptr, "Telnet Status for Port %d %s\r", Port, CMS); + + for (n = 1; n <= TNC->TCPInfo->CurrentSockets; n++) + { + sockptr=TNC->Streams[n].ConnectionInfo; + + if (!sockptr->SocketActive) + { + strcpy(msg,"Idle"); + } + else + { + if (sockptr->UserPointer == 0) + { + if (sockptr->HTTPMode) + { + char Addr[100]; + Tel_Format_Addr(sockptr, Addr); + + if (sockptr->WebSocks) + sprintf(msg, "Websock From %s", Addr); + else + sprintf(msg, "HTTP From %s", Addr); + + } + else if (sockptr->DRATSMode) + { + char Addr[100]; + Tel_Format_Addr(sockptr, Addr); + sprintf(msg, "DRATS From %s", Addr); + } + else + strcpy(msg,"Logging in"); + } + else + { + i=sprintf(msg,"%-10s %-10s %2d", + sockptr->UserPointer->UserName,sockptr->Callsign,sockptr->BPQStream); + } + } + Bufferptr = Cmdprintf(Session, Bufferptr, "%s\r", msg); + } + + SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); +} + + +// Refresh any Web Socket Webmail index display +// Called whenever message database is changed + +#ifdef LINBPQ + +int DoRefreshWebMailIndex(); + +int RefreshWebMailIndex() +{ + DoRefreshWebMailIndex(); + return 0; +} + +#else + +// Have to pass request from BPQMail to DLL as socket can only be accessed in calling process +// Pass request back to WebMail via pipe + +// Code must run in bpq32 process, so set flag here and call code from Timer Routine + +extern BOOL NeedWebMailRefresh; + + +DllExport int APIENTRY RefreshWebMailIndex() +{ + NeedWebMailRefresh = 1; + return 0; +} + +#endif + +int DoRefreshWebMailIndex() +{ + // Loop through all sockets and pick out WebMail Index Connections + + int i, n; + struct ConnectionInfo * sockptr; + struct ConnectionInfo * sockcopy; + struct TNCINFO * TNC; + struct TCPINFO * TCP; + +#ifndef LINBPQ + NeedWebMailRefresh = 0; +#endif + + for (i = 0; i < 33; i++) + { + TNC = TNCInfo[i]; + + if (TNC && TNC->Hardware == H_TELNET) + { + TCP = TNC->TCPInfo; + + if (TCP) + { + for (n = 0; n <= TCP->MaxSessions; n++) + { + sockptr = TNC->Streams[n].ConnectionInfo; + + if (sockptr->SocketActive) + { + if (sockptr->HTTPMode && sockptr->WebSocks && memcmp(sockptr->WebURL, "WMRefresh", 9) == 0) + { + sockcopy = malloc(sizeof(struct ConnectionInfo)); + sockptr->TNC = TNC; + sockptr->LastSendTime = REALTIMETICKS; + + memcpy(sockcopy, sockptr, sizeof(struct ConnectionInfo)); + + _beginthread(ProcessWebmailWebSockThread, 2048000, (VOID *)sockcopy); // Needs big stack + } + } + } + } + } + } + return 0; +} + diff --git a/TelnetV6.c b/TelnetV6.c index b9ed7f1..54b8c92 100644 --- a/TelnetV6.c +++ b/TelnetV6.c @@ -37,7 +37,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define IDM_DISCONNECT 2000 #define IDM_LOGGING 2100 -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #ifdef WIN32 @@ -85,7 +85,11 @@ void processDRATSFrame(unsigned char * Message, int Len, struct ConnectionInfo * void DRATSConnectionLost(struct ConnectionInfo * sockptr); int BuildRigCtlPage(char * _REPLYBUFFER); void ProcessWebmailWebSockThread(void * conn); +void RHPThread(void * Params); +void ProcessRHPWebSockClosed(SOCKET socket); int ProcessSNMPPayload(UCHAR * Msg, int Len, UCHAR * Reply, int * OffPtr); +int RHPProcessHTTPMessage(struct ConnectionInfo * conn, char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE); + #ifndef LINBPQ extern HKEY REGTREE; @@ -123,6 +127,8 @@ BOOL LogEnabled = FALSE; BOOL CMSLogEnabled = TRUE; extern BOOL IncludesMail; +extern int HTTPPort; + static HMENU hMenu, hPopMenu, hPopMenu2, hPopMenu3; // handle of menu static int ProcessLine(char * buf, int Port); @@ -533,7 +539,7 @@ int ProcessLine(char * buf, int Port) TCP->TriModePort = atoi(value); else if (_stricmp(param,"HTTPPORT") == 0) - TCP->HTTPPort = atoi(value); + HTTPPort = TCP->HTTPPort = atoi(value); else if (_stricmp(param,"APIPORT") == 0) TCP->APIPort = atoi(value); @@ -4967,6 +4973,15 @@ MsgLoop: extern char * RigWebPage; +struct RHPParamBlock +{ + unsigned char * Msg; + int Len; + SOCKET Socket; +}; + + + int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, SOCKET sock, int Stream) { int w =1, x= 1, len=0, y = 2, maxlen, InputLen, ret; @@ -4989,9 +5004,23 @@ int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, S { // Failed or closed - clear connection - TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node - DataSocket_Disconnect(TNC, sockptr); - return 0; + // if Websock connection till app + + if (sockptr->WebSocks) + { + if (memcmp(sockptr->WebURL, "rhp", 3) == 0) + { + ProcessRHPWebSockClosed(sockptr->socket); + DataSocket_Disconnect(TNC, sockptr); + return 0; + } + } + else + { + TNC->Streams[sockptr->Number].ReportDISC = TRUE; //Tell Node + DataSocket_Disconnect(TNC, sockptr); + return 0; + } } MsgPtr = &sockptr->InputBuffer[0]; @@ -5008,6 +5037,7 @@ int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, S int Fin, Opcode, Len, Mask; char MaskingKey[4]; char * ptr; + char * Payload; /* +-+-+-+-+-------+-+-------------+-------------------------------+ @@ -5035,8 +5065,20 @@ int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, S Opcode = MsgPtr[0] & 15; Mask = MsgPtr[1] >> 7; Len = MsgPtr[1] & 127; - memcpy(MaskingKey, &MsgPtr[2], 4); - ptr = &MsgPtr[6]; + + if (Len == 126) // Two Byte Len + { + Len = (MsgPtr[2] << 8) + MsgPtr[3]; + memcpy(MaskingKey, &MsgPtr[4], 4); + ptr = &MsgPtr[8]; + } + else + { + memcpy(MaskingKey, &MsgPtr[2], 4); + ptr = &MsgPtr[6]; + } + + Payload = ptr; for (i = 0; i < Len; i++) { @@ -5058,7 +5100,7 @@ int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, S char RigCMD[64]; - sprintf(RigCMD, "%s PTT", &MsgPtr[6]); + sprintf(RigCMD, "%s PTT", Payload); Rig_Command( (TRANSPORTENTRY *) -1, RigCMD); } else if (memcmp(sockptr->WebURL, "WMRefresh", 9) == 0) @@ -5072,6 +5114,21 @@ int DataSocket_ReadHTTP(struct TNCINFO * TNC, struct ConnectionInfo * sockptr, S _beginthread(ProcessWebmailWebSockThread, 2048000, (VOID *)sockcopy); // Needs big stack return 0; } + else if (memcmp(sockptr->WebURL, "rhp", 3) == 0) + { + // Run in thread as it may block; + + struct RHPParamBlock * ParamBlock = malloc(sizeof(struct RHPParamBlock)); + + ParamBlock->Socket = sockptr->socket; + ParamBlock->Len = Len; + ParamBlock->Msg = malloc(Len + 10); + memcpy(ParamBlock->Msg, Payload, Len); + _beginthread(RHPThread, 0, (VOID *)ParamBlock); + + sockptr->InputLen = 0; + return 0; + } } else Debugprintf("WebSock Opcode %d Msg %s", Opcode, &MsgPtr[6]); diff --git a/UIARQ.c b/UIARQ.c index 3dd588f..4d4b779 100644 --- a/UIARQ.c +++ b/UIARQ.c @@ -23,7 +23,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" extern int (WINAPI FAR *GetModuleFileNameExPtr)(); extern int (WINAPI FAR *EnumProcessesPtr)(); diff --git a/UIRoutines.c b/UIRoutines.c index 923725b..d8195cd 100644 --- a/UIRoutines.c +++ b/UIRoutines.c @@ -22,6 +22,8 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // UI Handling Routines #include "bpqmail.h" +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); char UIDEST[10] = "FBB"; diff --git a/UZ7HODrv.c b/UZ7HODrv.c index f9b433b..0a417c7 100644 --- a/UZ7HODrv.c +++ b/UZ7HODrv.c @@ -37,7 +37,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include #include -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "bpq32.h" diff --git a/V4.c b/V4.c index 5bd6880..08f2f23 100644 --- a/V4.c +++ b/V4.c @@ -36,7 +36,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define SD_BOTH 0x02 -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "bpq32.h" diff --git a/VARA.c b/VARA.c index e8fd061..d9fc67e 100644 --- a/VARA.c +++ b/VARA.c @@ -28,7 +28,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include -#include "CHeaders.h" +#include "cheaders.h" #ifdef WIN32 #include diff --git a/Versions-skigdebian.h b/Versions-skigdebian.h new file mode 100644 index 0000000..d5d92c3 --- /dev/null +++ b/Versions-skigdebian.h @@ -0,0 +1,125 @@ + +#ifdef Kernel + +#define Vers 5,2,9,2 +#define Verstring "5.2.9.2\0" +#define Datestring "September 2012" +#define VerComments "G8BPQ Packet Switch V5.2.9.2\0" +#define VerCopyright "Copyright © 2001-2012 John Wiseman G8BPQ\0" +#define VerDesc "BPQ32 Switch\0" + +#endif + +#define KVers 6,0,24,59 +#define KVerstring "6.0.24.59\0" + +#ifdef CKernel + +#define Vers KVers +#define Verstring KVerstring +#define Datestring "January 2025" +#define VerComments "G8BPQ Packet Switch (C Version)" KVerstring +#define VerCopyright "Copyright © 2001-2025 John Wiseman G8BPQ\0" +#define VerDesc "BPQ32 Switch\0" +#define VerProduct "BPQ32" + +#endif + +#ifdef TermTCP + +#define Vers 1,0,16,2 +#define Verstring "1.0.16.2\0" +#define VerComments "Internet Terminal for G8BPQ Packet Switch\0" +#define VerCopyright "Copyright © 2011-2025 John Wiseman G8BPQ\0" +#define VerDesc "Simple TCP Terminal Program for G8BPQ Switch\0" +#define VerProduct "BPQTermTCP" + +#endif + +#ifdef BPQTerm + +#define Vers 2,2,5,2 +#define Verstring "2.2.5.2\0" +#define VerComments "Simple Terminal for G8BPQ Packet Switch\0" +#define VerCopyright "Copyright © 1999-2025 John Wiseman G8BPQ\0" +#define VerDesc "Simple Terminal Program for G8BPQ Switch\0" +#define VerProduct "BPQTerminal" + +#endif + +#ifdef BPQTermMDI + +#define Vers 2,2,0,3 +#define Verstring "2.2.0.3\0" +#define VerComments "MDI Terminal for G8BPQ Packet Switch\0" +#define VerCopyright "Copyright © 1999-2025 John Wiseman G8BPQ\0" +#define VerDesc "MDI Terminal Program for G8BPQ Switch\0" + +#endif + +#ifdef MAIL + +#define Vers KVers +#define Verstring KVerstring +#define VerComments "Mail server for G8BPQ Packet Switch\0" +#define VerCopyright "Copyright © 2009-2025 John Wiseman G8BPQ\0" +#define VerDesc "Mail server for G8BPQ's 32 Bit Switch\0" +#define VerProduct "BPQMail" + +#endif + +#ifdef HOSTMODES + +#define Vers 1,1,8,1 +#define Verstring "1.1.8.1\0" +//#define SPECIALVERSION "Test 3" +#define VerComments "Host Modes Emulator for G8BPQ Packet Switch\0" +#define VerCopyright "Copyright © 2009-2019 John Wiseman G8BPQ\0" +#define VerDesc "Host Modes Emulator for G8BPQ's 32 Bit Switch\0" +#define VerProduct "BPQHostModes" + +#endif + + +#ifdef UIUTIL + +#define Vers 0,1,3,1 +#define Verstring "0.1.3.1\0" +#define VerComments "Beacon Utility for G8BPQ Packet Switch\0" +#define VerCopyright "Copyright © 2011-2019 John Wiseman G8BPQ\0" +#define VerDesc "Beacon Utility for G8BPQ Switch\0" +#define VerProduct "BPQUIUtil" + +#endif + +#ifdef AUTH + +#define Vers 0,1,0,0 +#define Verstring "0.1.0.0\0" +#define VerComments "Password Generation Utility for G8BPQ Packet Switch\0" +#define VerCopyright "Copyright © 2011-2025 John Wiseman G8BPQ\0" +#define VerDesc "Password Generation Utility for G8BPQ Switch\0" + +#endif + +#ifdef APRS + +#define Vers KVers +#define Verstring KVerstring +#define VerComments "APRS Client for G8BPQ Switch\0" +#define VerCopyright "Copyright © 2012-2025 John Wiseman G8BPQ\0" +#define VerDesc "APRS Client for G8BPQ Switch\0" +#define VerProduct "BPQAPRS" + +#endif + +#ifdef CHAT + +#define Vers KVers +#define Verstring KVerstring +#define VerComments "Chat server for G8BPQ Packet Switch\0" +#define VerCopyright "Copyright © 2009-2025 John Wiseman G8BPQ\0" +#define VerDesc "Chat server for G8BPQ's 32 Bit Switch\0" +#define VerProduct "BPQChat" + +#endif diff --git a/Versions.h b/Versions.h index 2428b95..4d7bd3b 100644 --- a/Versions.h +++ b/Versions.h @@ -10,16 +10,16 @@ #endif -#define KVers 6,0,24,56 -#define KVerstring "6.0.24.56\0" +#define KVers 6,0,24,59 +#define KVerstring "6.0.24.59\0" #ifdef CKernel #define Vers KVers #define Verstring KVerstring -#define Datestring "December 2024" +#define Datestring "February 2025" #define VerComments "G8BPQ Packet Switch (C Version)" KVerstring -#define VerCopyright "Copyright © 2001-2024 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2001-2025 John Wiseman G8BPQ\0" #define VerDesc "BPQ32 Switch\0" #define VerProduct "BPQ32" @@ -30,7 +30,7 @@ #define Vers 1,0,16,2 #define Verstring "1.0.16.2\0" #define VerComments "Internet Terminal for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 2011-2024 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2011-2025 John Wiseman G8BPQ\0" #define VerDesc "Simple TCP Terminal Program for G8BPQ Switch\0" #define VerProduct "BPQTermTCP" @@ -41,7 +41,7 @@ #define Vers 2,2,5,2 #define Verstring "2.2.5.2\0" #define VerComments "Simple Terminal for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 1999-2024 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 1999-2025 John Wiseman G8BPQ\0" #define VerDesc "Simple Terminal Program for G8BPQ Switch\0" #define VerProduct "BPQTerminal" @@ -52,7 +52,7 @@ #define Vers 2,2,0,3 #define Verstring "2.2.0.3\0" #define VerComments "MDI Terminal for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 1999-2024 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 1999-2025 John Wiseman G8BPQ\0" #define VerDesc "MDI Terminal Program for G8BPQ Switch\0" #endif @@ -62,7 +62,7 @@ #define Vers KVers #define Verstring KVerstring #define VerComments "Mail server for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 2009-2024 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2009-2025 John Wiseman G8BPQ\0" #define VerDesc "Mail server for G8BPQ's 32 Bit Switch\0" #define VerProduct "BPQMail" @@ -97,7 +97,7 @@ #define Vers 0,1,0,0 #define Verstring "0.1.0.0\0" #define VerComments "Password Generation Utility for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 2011-2024 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2011-2025 John Wiseman G8BPQ\0" #define VerDesc "Password Generation Utility for G8BPQ Switch\0" #endif @@ -107,7 +107,7 @@ #define Vers KVers #define Verstring KVerstring #define VerComments "APRS Client for G8BPQ Switch\0" -#define VerCopyright "Copyright © 2012-2024 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2012-2025 John Wiseman G8BPQ\0" #define VerDesc "APRS Client for G8BPQ Switch\0" #define VerProduct "BPQAPRS" @@ -118,7 +118,7 @@ #define Vers KVers #define Verstring KVerstring #define VerComments "Chat server for G8BPQ Packet Switch\0" -#define VerCopyright "Copyright © 2009-2024 John Wiseman G8BPQ\0" +#define VerCopyright "Copyright © 2009-2025 John Wiseman G8BPQ\0" #define VerDesc "Chat server for G8BPQ's 32 Bit Switch\0" #define VerProduct "BPQChat" diff --git a/WINMOR.c b/WINMOR.c index 7f6763b..51b77e5 100644 --- a/WINMOR.c +++ b/WINMOR.c @@ -70,7 +70,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include #include -#include "CHeaders.h" +#include "cheaders.h" #ifdef WIN32 #include diff --git a/WPRoutines.c b/WPRoutines.c index 0b8e315..0658ecc 100644 --- a/WPRoutines.c +++ b/WPRoutines.c @@ -23,6 +23,9 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include "bpqmail.h" +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); + int CurrentWPIndex; char CurrentWPCall[10]; @@ -121,7 +124,7 @@ VOID GetWPDatabase() sprintf(Key, "R%d", i++); - GetStringValue(group, Key, Record); + GetStringValue(group, Key, Record, 1024); if (Record[0] == 0) // End of List return; @@ -269,23 +272,23 @@ WPOK:; memset(&WPRec, 0, sizeof(WPRec)); - GetStringValue(wpgroup, "c", WPRec.callsign); - GetStringValue(wpgroup, "n", WPRec.name); + GetStringValue(wpgroup, "c", WPRec.callsign, 6); + GetStringValue(wpgroup, "n", WPRec.name, 12); WPRec.Type = GetIntValue(wpgroup, "T"); WPRec.changed = GetIntValue(wpgroup, "ch"); WPRec.seen = GetIntValue(wpgroup, "s"); - GetStringValue(wpgroup, "h", WPRec.first_homebbs); - GetStringValue(wpgroup, "sh", WPRec.secnd_homebbs); - GetStringValue(wpgroup, "z", WPRec.first_zip); - GetStringValue(wpgroup, "sz", WPRec.secnd_zip); + GetStringValue(wpgroup, "h", WPRec.first_homebbs, 40); + GetStringValue(wpgroup, "sh", WPRec.secnd_homebbs, 40); + GetStringValue(wpgroup, "z", WPRec.first_zip, 8); + GetStringValue(wpgroup, "sz", WPRec.secnd_zip, 8); - GetStringValue(wpgroup, "q", Temp); + GetStringValue(wpgroup, "q", Temp, 30); Temp[30] = 0; strcpy(WPRec.first_qth, Temp); - GetStringValue(wpgroup, "sq", Temp); + GetStringValue(wpgroup, "sq", Temp, 30); Temp[30] = 0; strcpy(WPRec.secnd_qth, Temp); diff --git a/WebMail.c b/WebMail.c index 05dc303..a21bf7f 100644 --- a/WebMail.c +++ b/WebMail.c @@ -19,7 +19,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #include "bpqmail.h" #define MAIL diff --git a/WinRPR.c b/WinRPR.c index d087f47..af1a7fb 100644 --- a/WinRPR.c +++ b/WinRPR.c @@ -31,7 +31,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define MaxStreams 1 -#include "CHeaders.h" +#include "cheaders.h" extern int (WINAPI FAR *GetModuleFileNameExPtr)(); diff --git a/adif.c b/adif.c index 040942e..45e734d 100644 --- a/adif.c +++ b/adif.c @@ -26,7 +26,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include #include #include "time.h" -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "adif.h" #include "telnetserver.h" diff --git a/asmstrucs.h b/asmstrucs.h index 268b51a..8a46075 100644 --- a/asmstrucs.h +++ b/asmstrucs.h @@ -1044,6 +1044,8 @@ struct SEM int Rels; DWORD SemProcessID; DWORD SemThreadID; + int Line; // caller file and line + char File[MAX_PATH]; }; diff --git a/bpqaxip.c b/bpqaxip.c index d03f531..07083dd 100644 --- a/bpqaxip.c +++ b/bpqaxip.c @@ -141,7 +141,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #ifndef WIN32 #include #include @@ -3246,15 +3246,21 @@ VOID SaveAXIPCache(struct AXIPPORTINFO * PORT) #ifndef LINBPQ -static BOOL GetStringValue(config_setting_t * group, char * name, char * value) +static BOOL GetStringValue(config_setting_t * group, char * name, char * value, int maxlen) { - const char * str; + char * str; config_setting_t *setting; setting = config_setting_get_member (group, name); if (setting) { - str = config_setting_get_string (setting); + str = (char *)config_setting_get_string (setting); + + if (strlen(str) > maxlen) + { + Debugprintf("Suspect config record %s", str); + str[maxlen] = 0; + } strcpy(value, str); return TRUE; } @@ -3321,7 +3327,7 @@ VOID GetAXIPCache(struct AXIPPORTINFO * PORT) ptr++; } - if (GetStringValue(group, Key, hostaddr)) + if (GetStringValue(group, Key, hostaddr, 64)) { arp->destaddr.sin_addr.s_addr = inet_addr(hostaddr); } diff --git a/bpqchat.h b/bpqchat.h index ea322c8..05d0349 100644 --- a/bpqchat.h +++ b/bpqchat.h @@ -603,7 +603,7 @@ VOID __cdecl nprintf(ChatCIRCUIT * conn, const char * format, ...); VOID nputs(ChatCIRCUIT * conn, char * buf); #endif BOOL matchi(char * p1, char * p2); -char * strlop(const char * buf, char delim); +char * strlop(char * buf, char delim); int rt_cmd(ChatCIRCUIT *circuit, char * Buffer); ChatCIRCUIT *circuit_new(ChatCIRCUIT *circuit, int flags); void makelinks(void); @@ -687,7 +687,11 @@ int RemoveLF(char * Message, int len); struct SEM; BOOL isdigits(char * string); -void GetSemaphore(struct SEM * Semaphore, int ID); + + +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) + +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); void FreeSemaphore(struct SEM * Semaphore); VOID __cdecl Debugprintf(const char * format, ...); diff --git a/bpqether.c b/bpqether.c index 91804c0..8de8801 100644 --- a/bpqether.c +++ b/bpqether.c @@ -52,7 +52,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses //#include -#include "CHeaders.h" +#include "cheaders.h" #include #include "pcap.h" diff --git a/bpqhdlc.c b/bpqhdlc.c index 83765e2..d8e3b3e 100644 --- a/bpqhdlc.c +++ b/bpqhdlc.c @@ -31,7 +31,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include #include -#include "CHeaders.h" +#include "cheaders.h" #include "bpq32.h" diff --git a/bpqmail.h b/bpqmail.h index ba6e27b..0a8bf06 100644 --- a/bpqmail.h +++ b/bpqmail.h @@ -33,7 +33,7 @@ #include "BPQMailrc.h" #include "dbghelp.h" #else -#include "CHeaders.h" +#include "cheaders.h" #endif #include "asmstrucs.h" @@ -879,7 +879,7 @@ struct MSESSION }; VOID __cdecl nprintf(CIRCUIT * conn, const char * format, ...); -char * strlop(const char * buf, char delim); +char * strlop(char * buf, char delim); int rt_cmd(CIRCUIT *circuit, char * Buffer); CIRCUIT *circuit_new(CIRCUIT *circuit, int flags); VOID BBSputs(CIRCUIT * conn, char * buf); @@ -1173,7 +1173,7 @@ int ProcessConnecting(CIRCUIT * circuit, char * Buffer, int Len); VOID SaveConfig(char * ConfigName); BOOL GetConfig(char * ConfigName); int GetIntValue(config_setting_t * group, char * name); -BOOL GetStringValue(config_setting_t * group, char * name, char * value); +//BOOL GetStringValue(config_setting_t * group, char * name, char * value, int maxlen); BOOL GetConfigFromRegistry(); VOID Parse_SID(CIRCUIT * conn, char * SID, int len); VOID ProcessMBLLine(CIRCUIT * conn, struct UserInfo * user, UCHAR* Buffer, int len); @@ -1289,7 +1289,9 @@ int RemoveLF(char * Message, int len); // Utilities BOOL isdigits(char * string); -void GetSemaphore(struct SEM * Semaphore, int ID); + + +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); void FreeSemaphore(struct SEM * Semaphore); VOID __cdecl Debugprintf(const char * format, ...); diff --git a/bpqvkiss.c b/bpqvkiss.c index 760326b..c639cee 100644 --- a/bpqvkiss.c +++ b/bpqvkiss.c @@ -34,7 +34,7 @@ typedef unsigned char byte; -#include "CHeaders.h" +#include "cheaders.h" #include "bpqvkiss.h" #include diff --git a/cMain-skigdebian.c b/cMain-skigdebian.c new file mode 100644 index 0000000..4ae1dea --- /dev/null +++ b/cMain-skigdebian.c @@ -0,0 +1,2788 @@ +/* +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 Main.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 + +#include "kernelresource.h" +#include "cheaders.h" +#include "tncinfo.h" +#include "mqtt.h" + +VOID L2Routine(struct PORTCONTROL * PORT, PMESSAGE Buffer); +VOID ProcessIframe(struct _LINKTABLE * LINK, PDATAMESSAGE Buffer); +VOID FindLostBuffers(); +VOID ReadMH(); +void GetPortCTEXT(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, struct CMDX * CMD); +int upnpInit(); +void AISTimer(); +void ADSBTimer(); +VOID SendSmartID(struct PORTCONTROL * PORT); +int CanPortDigi(int Port); +int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len); +void MQTTTimer(); +void SaveMH(); + +#include "configstructs.h" + +extern struct CONFIGTABLE xxcfg; +extern BOOL needAIS; +extern int needADSB; + +struct PORTCONFIG * PortRec; + +#define RNRSET 0x2 // RNR RECEIVED FROM OTHER END + +// STATION INFORMATION + +char DATABASESTART[14] = ""; +char xMAJORVERSION = 4; +char xMINORVERSION = 9; +char FILLER1[16] = ""; + +struct ROUTE * NEIGHBOURS = NULL; +int ROUTE_LEN = sizeof(struct ROUTE); +int MAXNEIGHBOURS = 20; + +struct DEST_LIST * DESTS = NULL; // NODE LIST +int DEST_LIST_LEN = sizeof(struct DEST_LIST); + +struct _LINKTABLE * LINKS = NULL; +int LINK_TABLE_LEN = sizeof (struct _LINKTABLE); +int MAXLINKS = 30; + + +char MYCALL[7] = ""; // DB 7 DUP (0) ; NODE CALLSIGN (BIT SHIFTED) +char MYALIASTEXT[6] = ""; // DB ' ' ; NODE ALIAS (KEEP TOGETHER) + +char MYALIASLOPPED[10]; +char MYCALLLOPPED[10]; + +UCHAR MYCALLWITHALIAS[13] = ""; + +UCHAR NETROMCALL[7] = ""; // Call used for NETROM (can be MYCALL) + +APPLCALLS APPLCALLTABLE[NumberofAppls] = {0}; + +UCHAR MYNODECALL[10] = ""; // NODE CALLSIGN (ASCII) +UCHAR MYNETROMCALL[10] = ""; // NETROM CALLSIGN (ASCII) +char NODECALLLOPPED[10]; + +VOID * FREE_Q = NULL; + +time_t TimeLoaded = 0; + +struct PORTCONTROL * PORTTABLE = NULL; +int NUMBEROFPORTS = 0; +int PORTENTRYLEN = sizeof(struct PORTCONTROL); + +struct DEST_LIST * ENDDESTLIST = NULL; // ; NODE LIST+1 +; + +VOID * BUFFERPOOL = NULL; // START OF BUFFER POOL +VOID * ENDBUFFERPOOL = NULL; + +int OBSINIT = 5; // INITIAL OBSOLESCENCE VALUE +int OBSMIN = 4; // MINIMUM TO BROADCAST +int L3INTERVAL = 60; // 'NODES' INTERVAL IN MINS +int IDINTERVAL = 20; // 'ID' BROADCAST INTERVAL +int BTINTERVAL = 20; // 'BT' BROADCAST INTERVAL +int MINQUAL = 10; // MIN QUALITY FOR AUTOUPDATES +int HIDENODES = 0; // N * COMMAND SWITCH +int BBSQUAL = 255; // QUALITY OF BBS RELATIVE TO NODE + +int NUMBEROFBUFFERS = 999; // PACKET BUFFERS + +int PACLEN = 100; //MAX PACKET SIZE + +// L2 SYSTEM TIMER RUNS AT 3 HZ + +int T3 = 3*61*3; // LINK VALIDATION TIMER (3 MINS) (+ a bit to reduce RR collisions) + +int L2KILLTIME = 16*60*3; // IDLE LINK TIMER (16 MINS) +int L3LIVES = 15; // MAX L3 HOPS +int L4N2 = 3; // LEVEL 4 RETRY COUNT +int L4LIMIT = 60*15; // IDLE SESSION LIMIT - 15 MINS +int L4DELAY = 5; // L4 DELAYED ACK TIMER + +int BBS = 1; // INCLUDE BBS SUPPORT +int NODE = 1; // INCLUDE SWITCH SUPPORT + +int FULL_CTEXT = 1; // CTEXT ON ALL CONNECTS IF NZ + +BOOL LogL4Connects = FALSE; +BOOL LogAllConnects = FALSE; +BOOL AUTOSAVEMH = TRUE; +extern BOOL ADIFLogEnabled; +extern UCHAR LogDirectory[260]; +extern BOOL EventsEnabled; +extern BOOL SaveAPRSMsgs; +BOOL M0LTEMap = FALSE; +BOOL MQTT = FALSE; +char MQTT_HOST[80] = ""; +int MQTT_PORT = 0; +char MQTT_USER[80] = ""; +char MQTT_PASS[80] = ""; + +int MQTT_Connecting = 0; +int MQTT_Connected = 0; + + +//TNCTABLE DD 0 +//NUMBEROFSTREAMS DD 0 + +extern VOID * ENDPOOL; +extern void * APPL_Q; // Queue of frames for APRS Appl + +extern BOOL APRSActive; + +#define BPQHOSTSTREAMS 64 + +// Although externally streams are numbered 1 to 64, internally offsets are 0 - 63 + +BPQVECSTRUC XDUMMY = {0}; // Needed to force correct order of following + +BPQVECSTRUC BPQHOSTVECTOR[BPQHOSTSTREAMS + 5] = {0}; + +BPQVECSTRUC * TELNETMONVECPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS]; +BPQVECSTRUC * AGWMONVECPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 1]; +BPQVECSTRUC * APRSMONVECPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 2]; +BPQVECSTRUC * IPHOSTVECTORPTR = &BPQHOSTVECTOR[BPQHOSTSTREAMS + 3]; + +int BPQVECLENGTH = sizeof(BPQVECSTRUC); + +int NODEORDER = 0; +UCHAR LINKEDFLAG = 0; + +UCHAR UNPROTOCALL[80] = ""; + +UCHAR ExcludeList[71] = ""; // 10 ENTRIES, 7 BYTES EACH + +char * INFOMSG = NULL; + +char * CTEXTMSG = NULL; +int CTEXTLEN = 0; + +UCHAR MYALIAS[7] = ""; // ALIAS IN AX25 FORM +UCHAR BBSALIAS[7] = ""; + +UCHAR AX25CALL[7] = ""; // WORK AREA FOR AX25 <> NORMAL CALL CONVERSION +UCHAR NORMCALL[10] = ""; // CALLSIGN IN NORMAL FORMAT +int NORMLEN = 0; // LENGTH OF CALL IN NORMCALL + +int CURRENTPORT = 0; // PORT FOR CURRENT MESSAGE +VOID * CURRENTPORTPTR = NULL; // PORT CONTROL TABLE ENTRY FOR CURRENT PORT + +int SDCBYTE = 0; // CONTROL BYTE FOR CURRENT FRAME + +VOID * BUFFER = NULL; // GENERAL SAVE AREA FOR BUFFER ADDR +VOID * ADJBUFFER = NULL; // BASE ADJUSED FOR DIGIS + +UCHAR TEMPFIELD[7] = ""; // ADDRESS WORK FILED + +void * TRACE_Q = NULL; // TRANSMITTED FRAMES TO BE TRACED + +int RANDOM = 0; // 'RANDOM' NUMBER FOR PERSISTENCE CALCS + +int L2TIMERFLAG = 0; // INCREMENTED AT 18HZ BY TIMER INTERRUPT +int L3TIMERFLAG = 0; // DITTO +int L4TIMERFLAG = 0; // DITTO + +char HEADERCHAR = '}'; // CHAR FOR _NODE HEADER MSGS + +VOID * LASTPOINTER = NULL; // PERVIOUS _NODE DURING CHAINING + +int REALTIMETICKS = 0; +int BGTIMER = 0; // TO CONTROL BG SCANS + +VOID * CONFIGPTR = NULL; // Internal Config Get Offset + +int AUTOSAVE = 0; // AUTO SAVE NODES ON EXIT FLAG +int L4APPL = 1; // Application for BBSCALL/ALIAS connects +int CFLAG = 0; // C =HOST Command + +VOID * IDMSG_Q = NULL; // ID/BEACONS WAITING TO BE SENT + +int NODESINPROGRESS = 0; +VOID * CURRENTNODE = NULL; // NEXT _NODE TO SEND +VOID * DESTHEADER = NULL; // HEAD OF SORTED NODES CHAIN + +int L3TIMER = 1; // TIMER FOR 'NODES' MESSAGE +int IDTIMER = 0; // TIMER FOR ID MESSAGE +int BTTIMER = 0; // TIMER FOR BT MESSAGE + +UCHAR * NEXTFREEDATA = NULL; // ADDRESS OF NEXT FREE BYTE of shared memory + +int NEEDMH = 0; + +struct DATAMESSAGE BTHDDR = {0,0,9,240,13}; +struct _MESSAGE IDHDDR = {0,0,23,0,0,3, 240}; + +VOID * IDMSG = &IDHDDR; + +//DD 0 ; CHAIN +// DB 0 ; PORT +int BTLENGTH = 9; // DW 9 ; LENGTH +// DB 0F0H ; PID +char BTEXTFLD[256] ="\r"; + +char BridgeMap[MaxBPQPortNo + 1][MaxBPQPortNo + 1] = {0}; + +// Keep Buffers at end + +#define DATABYTES 600000 // WAS 320000 + +UCHAR DATAAREA[DATABYTES] = ""; + +void ** Bufferlist[1000] = {0}; + +extern BOOL IPRequired; +extern BOOL PMRequired; +extern int MaxHops; +extern int MAXRTT; +extern USHORT CWTABLE[]; +extern struct _TRANSPORTENTRY * L4TABLE; +extern UCHAR ROUTEQUAL; +extern UINT BPQMsg; + +extern int NUMBEROFTNCPORTS; + +extern APPLCALLS APPLCALLTABLE[]; + +// LOOPBACK PORT ROUTINES + +VOID LINKINIT(PEXTPORTDATA PORTVEC) +{ + WritetoConsoleLocal("Loopback\n"); +} + +VOID LINKTX(PEXTPORTDATA PORTVEC, PMESSAGE Buffer) +{ + // LOOP BACK TO SWITCH + struct _LINKTABLE * LINK; + + LINK = Buffer->Linkptr; + + if (LINK) + { + if (LINK->L2TIMER) + LINK->L2TIMER = LINK->L2TIME; + + Buffer->Linkptr = 0; // CLEAR FLAG FROM BUFFER + } + + C_Q_ADD(&PORTVEC->PORTCONTROL.PORTRX_Q, Buffer); +} + + +VOID LINKRX() +{ +} + + +VOID LINKTIMER() +{ +} + +VOID LINKCLOSE() +{ +} + + +VOID EXTCLOSE() +{ +} + +BOOL KISSTXCHECK() +{ + return 0; +} + +BOOL LINKTXCHECK() +{ + return 0; +} + +void * Dummy(int fn, int port, PDATAMESSAGE buff) // Dummy for missing EXT Driver +{ + return 0; +} + +VOID EXTINIT(PEXTPORTDATA PORTVEC) +{ + // LOAD DLL - NAME IS IN PORT_DLL_NAME + + void *(* Startup) (PEXTPORTDATA PORTVEC); // ADDR OF Startup ROUTINE + + PORTVEC->PORT_EXT_ADDR = Dummy; + + Startup = InitializeExtDriver(PORTVEC); + + if (Startup == 0) + { + WritetoConsoleLocal("Driver installation failed\n"); + return; + } + + +// CALL THE ROUTINE TO START IT UP + +// Startup returns address of processing routine + + PORTVEC->PORT_EXT_ADDR = (void *(__cdecl *)(int,int,PDATAMESSAGE))Startup(PORTVEC);; + + if (PORTVEC->PORT_EXT_ADDR == 0) + { + WritetoConsoleLocal("Driver Initialisation failed\n"); + return; + } + +} + +VOID EXTTX(PEXTPORTDATA PORTVEC, MESSAGE * Buffer) +{ + struct _LINKTABLE * LINK; + struct PORTCONTROL * PORT = (struct PORTCONTROL *)PORTVEC; + +// RESET TIMER, unless BAYCOM + + if (PORT->KISSFLAGS == 255) // Used for BAYCOM + { + PORTVEC->PORT_EXT_ADDR(2, PORT->PORTNUMBER, (PDATAMESSAGE)Buffer); + + return; // Baycom driver passes frames to trace once sent + } + + LINK = Buffer->Linkptr; + + if (LINK) + { + if (LINK->L2TIMER) + LINK->L2TIMER = LINK->L2TIME; + + if (PORT->TNC == 0 || PORT->TNC->Hardware != H_KISSHF) + Buffer->Linkptr = 0; // CLEAR FLAG FROM BUFFER + } + + PORTVEC->PORT_EXT_ADDR(2, PORT->PORTNUMBER, (PDATAMESSAGE)Buffer); + + if (PORT->PROTOCOL == 10 && PORT->TNC && PORT->TNC->Hardware != H_KISSHF) + { + ReleaseBuffer(Buffer); + return; + } + + C_Q_ADD(&TRACE_Q, Buffer); + + return; + +} + +VOID EXTRX(PEXTPORTDATA PORTVEC) +{ + struct _MESSAGE * Message; + size_t Len; + struct PORTCONTROL * PORT = (struct PORTCONTROL *)PORTVEC; + +Loop: + + if (QCOUNT < 10) + return; + + Message = GetBuff(); + + if (Message == NULL) + return; + + Len = (size_t)PORTVEC->PORT_EXT_ADDR(1, PORT->PORTNUMBER, (PDATAMESSAGE)Message); + + if (Len == 0) + { + ReleaseBuffer((UINT *)Message); + return; + } + + if (PORT->PROTOCOL == 10) + { + // PACTOR Style Port - Negative values used to report events - for now -1 = Disconnected + + if (Len == -1) + { + int Sessno = Message->PORT; + TRANSPORTENTRY * Session; + + ReleaseBuffer((UINT *)Message); + + // GET RID OF ANY SESSION ENTRIES + + Session = PORTVEC->ATTACHEDSESSIONS[Sessno]; + + if (Session) + { + struct TNCINFO * TNC = PORTVEC->PORTCONTROL.TNC; + + CloseSessionPartner(Session); + + // is this the place to run DisconnectScript? + + if (TNC->DisconnectScript) + { + int n = 0; + struct DATAMESSAGE * Buffer; + + TRANSPORTENTRY Session = {0}; // = TNC->PortRecord->ATTACHEDSESSIONS[Sessno]; + + while (TNC->DisconnectScript[n]) + { + Buffer = GetBuff(); + if (Buffer) + { + Session.Secure_Session = 1; + Session.CIRCUITINDEX = -1; + Buffer->LENGTH = sprintf(Buffer->L2DATA, "%s\r", TNC->DisconnectScript[n++]) + (sizeof(void *) + 4); + CommandHandler(&Session, Buffer); + }; + } + } + + PORTVEC->ATTACHEDSESSIONS[Sessno] = NULL; + } + return; + } + } + + C_Q_ADD(&PORT->PORTRX_Q, (UINT *)Message); + + goto Loop; + + return; +} + +VOID EXTTIMER(PEXTPORTDATA PORTVEC) +{ + // USED TO SEND A RE-INIT IN THE CORRECT PROCESS + + if (PORTVEC->EXTRESTART) + { + PORTVEC->EXTRESTART = 0; //CLEAR + PORTVEC->PORT_EXT_ADDR(4, PORTVEC->PORTCONTROL.PORTNUMBER, 0); + } + + PORTVEC->PORT_EXT_ADDR(7, PORTVEC->PORTCONTROL.PORTNUMBER, 0); // Timer Routine +} + +VOID EXTSLOWTIMER(PEXTPORTDATA PORTVEC) +{ + PORTVEC->PORT_EXT_ADDR(8, PORTVEC->PORTCONTROL.PORTNUMBER, 0); // Timer Routine +} + +size_t EXTTXCHECK(PEXTPORTDATA PORTVEC, int Chan) +{ + uintptr_t Temp = Chan; + + return (size_t)PORTVEC->PORT_EXT_ADDR(3, PORTVEC->PORTCONTROL.PORTNUMBER, (void *)Temp); +} + +VOID PostDataAvailable(TRANSPORTENTRY * Session) +{ +#ifndef LINBPQ + if (Session->L4CIRCUITTYPE & BPQHOST) + { + BPQVECSTRUC * HostSess = Session->L4TARGET.HOST; + + if (HostSess) + { + if (HostSess->HOSTHANDLE) + { + PostMessage(HostSess->HOSTHANDLE, BPQMsg, HostSess->HOSTSTREAM, 2); + } + } + } +#endif +} + +VOID PostStateChange(TRANSPORTENTRY * Session) +{ +#ifndef LINBPQ + if (Session->L4CIRCUITTYPE & BPQHOST) + { + BPQVECSTRUC * HostSess = Session->L4TARGET.HOST; + + if (HostSess) + { + if (HostSess->HOSTHANDLE); + { + PostMessage(HostSess->HOSTHANDLE, BPQMsg, HostSess->HOSTSTREAM, 4); + } + } + } +#endif +} + +#ifdef LINBPQ + +#define HDLCTX KHDLCTX +#define HDLCRX KHDLCRX +#define HDLCTIMER KHDLCTIMER +#define HDLCCLOSE KHDLCCLOSE +#define HDLCTXCHECK KHDLCTXCHECK + +#define PC120INIT KHDLCINIT +#define DRSIINIT KHDLCINIT +#define TOSHINIT KHDLCINIT +#define RLC100INIT KHDLCINIT +#define BAYCOMINIT KHDLCINIT +#define PA0INIT KHDLCINIT + +int KHDLCINIT(PHDLCDATA PORTVEC); +void KHDLCTX(struct KISSINFO * KISS, PMESSAGE Buffer); +int KHDLCRX(PHDLCDATA PORTVEC); +void KHDLCTIMER(PHDLCDATA PORTVEC); +void KHDLCCLOSE(PHDLCDATA PORTVEC); +BOOL KHDLCTXCHECK(); + + +#else + +extern VOID PC120INIT(), DRSIINIT(), TOSHINIT(); +extern VOID RLC100INIT(), BAYCOMINIT(), PA0INIT(); + +extern VOID HDLCTX(); +extern VOID HDLCRX(); +extern VOID HDLCTIMER(); +extern VOID HDLCCLOSE(); +extern VOID HDLCTXCHECK(); + +#endif + +extern VOID KISSINIT(), KISSTX(), KISSRX(), KISSTIMER(), KISSCLOSE(); +extern VOID EXTINIT(PEXTPORTDATA PORTVEC), EXTTX(PEXTPORTDATA PORTVEC, MESSAGE * Buffer), LINKRX(), EXTRX(PEXTPORTDATA PORTVEC); +extern VOID LINKCLOSE(), EXTCLOSE() ,LINKTIMER(), EXTTIMER(PEXTPORTDATA PORTVEC); + +// VECTORS TO HARDWARE DEPENDENT ROUTINES + +VOID * INITCODE[12] = {KISSINIT, PC120INIT, DRSIINIT, TOSHINIT, KISSINIT, +RLC100INIT, RLC100INIT, LINKINIT, EXTINIT, BAYCOMINIT, PA0INIT, KISSINIT}; + +VOID * TXCODE[12] = {KISSTX, HDLCTX, HDLCTX, HDLCTX, KISSTX, + HDLCTX, HDLCTX, LINKTX, EXTTX, HDLCTX, HDLCTX, KISSTX}; + +VOID * RXCODE[12] = {KISSRX, HDLCRX, HDLCRX, HDLCRX, KISSRX, + HDLCRX, HDLCRX, LINKRX, EXTRX, HDLCRX, HDLCRX, KISSRX}; + +VOID * TIMERCODE[12] = {KISSTIMER, HDLCTIMER, HDLCTIMER, HDLCTIMER, KISSTIMER, + HDLCTIMER, HDLCTIMER, LINKTIMER, EXTTIMER, HDLCTIMER, HDLCTIMER, KISSTIMER}; + +VOID * CLOSECODE[12] = {KISSCLOSE, HDLCCLOSE, HDLCCLOSE, HDLCCLOSE, KISSCLOSE, + HDLCCLOSE, HDLCCLOSE, LINKCLOSE, EXTCLOSE, HDLCCLOSE, HDLCCLOSE, KISSCLOSE}; + +VOID * TXCHECKCODE[12] = {KISSTXCHECK, HDLCTXCHECK, HDLCTXCHECK, HDLCTXCHECK, KISSTXCHECK, + HDLCTXCHECK, HDLCTXCHECK, LINKTXCHECK, EXTTXCHECK, HDLCTXCHECK, HDLCTXCHECK, KISSTXCHECK}; + + +extern int BACKGROUND(); +extern int L2TimerProc(); +extern int L3TimerProc(); +extern int L4TimerProc(); +extern int L3FastTimer(); +extern int StatsTimer(); +extern int COMMANDHANDLER(); +VOID SDETX(struct _LINKTABLE * LINK); +extern int L4BG(); +extern int L3BG(); +extern int TNCTimerProc(); +extern int PROCESSIFRAME(); + +int xxxxx = MAXDATA; + +BOOL Start() +{ + struct CONFIGTABLE * cfg = &xxcfg; + struct APPLCONFIG * ptr1; + struct PORTCONTROL * PORT; + struct FULLPORTDATA * FULLPORT; // Including HW Data + struct FULLPORTDATA * NEXTPORT; // Including HW Data + struct _EXTPORTDATA * EXTPORT; + APPLCALLS * APPL; + struct ROUTE * ROUTE; + struct DEST_LIST * DEST; + struct CMDX * CMD; + int PortSlot = 1; + uintptr_t int3; + + unsigned char * ptr2 = 0, * ptr3, * ptr4; + USHORT * CWPTR; + int i, n; + + struct ROUTECONFIG * Rcfg; + + NEXTFREEDATA = &DATAAREA[0]; // For Reinit + + memset(DATAAREA, 0, DATABYTES); + + // Reinit everything in case of restart + + FREE_Q = 0; + TRACE_Q = 0; + IDMSG_Q = 0; + NUMBEROFPORTS = 0; + MAXBUFFS = 0; + QCOUNT = 0; + NUMBEROFNODES = 0; + DESTHEADER = 0; + NODESINPROGRESS = 0; + CURRENTNODE = 0; + L3TIMER = 1; // SEND NODES + + if (cfg->C_NODEALIAS[0] == 0) + memset(cfg->C_NODEALIAS, ' ', 10); + + TimeLoaded = time(NULL); + + AUTOSAVE = cfg->C_AUTOSAVE; + + if (cfg->C_L4APPL) + L4APPL = cfg->C_L4APPL; + + CFLAG = cfg->C_C; + + IPRequired = cfg->C_IP; + PMRequired = cfg->C_PM; + + if (cfg->C_MAXHOPS) + MaxHops = cfg->C_MAXHOPS; + + if (cfg->C_MAXRTT) + MAXRTT = cfg->C_MAXRTT * 100; + + if (cfg->C_NODE == 0 && cfg->C_BBS) + { + // USE BBS CALL FOR NODE if Set, otherwise find first APPLCALL + // Unless BBS also = 0 + + if (cfg->C_BBSCALL[0]) + { + memcpy(MYNODECALL, cfg->C_BBSCALL, 10); + memcpy(MYALIASTEXT, cfg->C_BBSALIAS, 6); + memcpy(MYALIASLOPPED, cfg->C_BBSALIAS, 10); + } + else + { + ptr1 = &cfg->C_APPL[0]; + + for (i = 0; i < NumberofAppls; i++) + { + if (ptr1->ApplCall[0] != ' ') + { + memcpy(MYNODECALL, &ptr1->ApplCall[0], 10); + memcpy(MYALIASTEXT, &ptr1->ApplAlias, 6); + memcpy(MYALIASLOPPED, &ptr1->ApplAlias, 10); + + break; + } + ptr1++; + } + } + + } + else + { + memcpy(MYNODECALL, cfg->C_NODECALL, 10); + memcpy(MYALIASTEXT, cfg->C_NODEALIAS, 6); + memcpy(MYALIASLOPPED, cfg->C_NODEALIAS, 10); + } + + strlop(MYALIASLOPPED, ' '); + + + // IF NO BBS, SET BOTH TO _NODE CALLSIGN + + if (cfg->C_BBS == 0) + { + memcpy(APPLCALLTABLE[0].APPLCALL_TEXT, cfg->C_NODECALL, 10); + memcpy(APPLCALLTABLE[0].APPLALIAS_TEXT, cfg->C_NODEALIAS, 10); + } + else + { + memcpy(APPLCALLTABLE[0].APPLCALL_TEXT, cfg->C_BBSCALL, 10); + memcpy(APPLCALLTABLE[0].APPLALIAS_TEXT, cfg->C_BBSALIAS, 10 ); + } + + BBSQUAL = cfg->C_BBSQUAL; + + // copy MYCALL to NETROMCALL + + memcpy(MYNETROMCALL, MYNODECALL, 10); + + // if NETROMCALL Defined, use it + + if (cfg->C_NETROMCALL[0] && cfg->C_NETROMCALL[0] != ' ') + memcpy(MYNETROMCALL, cfg->C_NETROMCALL, 10); + + strlop(MYNETROMCALL, ' '); + strlop(MYNODECALL, ' '); + + memcpy(NODECALLLOPPED, MYNODECALL, 10); + strlop(NODECALLLOPPED, ' '); + + APPLCALLTABLE[0].APPLQUAL = BBSQUAL; + + if (cfg->C_WASUNPROTO == 0 && cfg->C_BTEXT) + { + char * ptr1 = &cfg->C_BTEXT[0]; + char * ptr2 = BTHDDR.L2DATA; + int len = 120; + + BTHDDR.LENGTH = 1; // PID + + while ((*ptr1) && len--) + { + *(ptr2++) = *(ptr1++); + BTHDDR.LENGTH ++; + } + + } + + OBSINIT = cfg->C_OBSINIT; + OBSMIN = cfg->C_OBSMIN; + L3INTERVAL = cfg->C_NODESINTERVAL; + IDINTERVAL = cfg->C_IDINTERVAL; + if (IDINTERVAL) + IDTIMER = 2; + + BTINTERVAL = cfg->C_BTINTERVAL; + if (BTINTERVAL) + BTTIMER = 2; + + + MINQUAL = cfg->C_MINQUAL; + FULL_CTEXT = cfg->C_FULLCTEXT; + L3LIVES = cfg->C_L3TIMETOLIVE; + L4N2 = cfg->C_L4RETRIES; + L4DEFAULTWINDOW = cfg->C_L4WINDOW; + L4T1 = cfg->C_L4TIMEOUT; + +// MOV AX,C_BUFFERS +// MOV NUMBEROFBUFFERS,AX + + PACLEN = cfg->C_PACLEN; + T3 = cfg->C_T3 * 3; + L4LIMIT = cfg->C_IDLETIME; + if (L4LIMIT && L4LIMIT < 120) + L4LIMIT = 120; // Don't allow stupidly low + L2KILLTIME = L4LIMIT * 3; + L4DELAY = cfg->C_L4DELAY; + BBS = cfg->C_BBS; + NODE = cfg->C_NODE; + LINKEDFLAG = cfg->C_LINKEDFLAG; + MAXLINKS = cfg->C_MAXLINKS; + MAXDESTS = cfg->C_MAXDESTS; + MAXNEIGHBOURS = cfg->C_MAXNEIGHBOURS; + MAXCIRCUITS = cfg->C_MAXCIRCUITS; + HIDENODES = cfg->C_HIDENODES; + + LogL4Connects = cfg->C_LogL4Connects; + LogAllConnects = cfg->C_LogAllConnects; + AUTOSAVEMH = cfg->C_SaveMH; + ADIFLogEnabled = cfg->C_ADIF; + EventsEnabled = cfg->C_EVENTS; + SaveAPRSMsgs = cfg->C_SaveAPRSMsgs; + M0LTEMap = cfg->C_M0LTEMap; + MQTT = cfg->C_MQTT; + strcpy(MQTT_HOST, cfg->C_MQTT_HOST); + MQTT_PORT = cfg->C_MQTT_PORT; + strcpy(MQTT_USER, cfg->C_MQTT_USER); + strcpy(MQTT_PASS, cfg->C_MQTT_PASS); + + // Get pointers to PASSWORD and APPL1 commands + +// int APPL1 = 0; +//int PASSCMD = 0; + + CMD = &COMMANDS[0]; + n = 0; + + for (n = 0; n < NUMBEROFCOMMANDS; n++) + { + if (APPL1 == 0 && CMD->String[0] == '*') // First appl + { + APPLS = (char *)CMD; + APPL1 = n; + } + + if (PASSCMD == 0 && memcmp(CMD->String, "PASSWORD", 8) == 0) + PASSCMD = n; + + CMD++; + } + + +// SET UP APPLICATION LIST + + memset(&CMDALIAS[0][0], ' ', NumberofAppls * ALIASLEN ); + + ptr1 = (struct APPLCONFIG *)&xxcfg.C_APPL[0]; + ptr3 = &CMDALIAS[0][0]; + + for (i = 0; i < NumberofAppls; i++) + { + if (ptr1->Command[0] != ' ') + { + ptr2 = (char *)&COMMANDS[APPL1 + i]; + + memcpy(ptr2, ptr1, 12); + + // See if an Alias + + if (ptr1->CommandAlias[0] != ' ') + memcpy(ptr3, ptr1->CommandAlias, ALIASLEN); + + // SET LENGTH FIELD + + *(ptr2 + 12) = 0; // LENGTH + ptr4 = ptr2; + + while (*(ptr4) > 32) + { + ptr4++; + *(ptr2 + 12) = *(ptr2 + 12) + 1; + } + } + ptr1 ++; + ptr2 += CMDXLEN; + ptr3 += ALIASLEN; + } + + // Set up Exclude List + + memcpy(ExcludeList, cfg->C_EXCLUDE, 71); + + // SET UP PORT TABLE + + PortRec = &cfg->C_PORT[0];// (struct PORTCONFIG *)ptr2; + + PORTTABLE = (VOID *)NEXTFREEDATA; + FULLPORT = (struct FULLPORTDATA *)PORTTABLE; + + while (PortRec->PORTNUM) + { + // SET UP NEXT PORT PTR + + PORT = &FULLPORT->PORTCONTROL; + NEXTPORT = FULLPORT; + NEXTPORT++; + PORT->PORTPOINTER = (struct PORTCONTROL *)NEXTPORT; + + PORT->PORTNUMBER = (UCHAR)PortRec->PORTNUM; + PORT->PortSlot = PortSlot++; + memcpy(PORT->PORTDESCRIPTION, PortRec->ID, 30); + + PORT->PORTTYPE = (char)PortRec->TYPE; + + PORT->PORTINITCODE = INITCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE + PORT->PORTTXROUTINE = TXCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE + PORT->PORTRXROUTINE = RXCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE + PORT->PORTTIMERCODE = TIMERCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE + PORT->PORTCLOSECODE = CLOSECODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE + PORT->PORTTXCHECKCODE = TXCHECKCODE[PORT->PORTTYPE / 2]; // ADDR OF INIT ROUTINE + + + PORT->PROTOCOL = (char)PortRec->PROTOCOL; + PORT->IOBASE = PortRec->IOADDR; + + if (PortRec->SerialPortName && PortRec->SerialPortName[0]) + PORT->SerialPortName = _strdup(PortRec->SerialPortName); + else + { + if (PORT->IOBASE > 0 && PORT->IOBASE < 256) + { + char Name[80]; +#ifndef WIN32 + sprintf(Name, "com%d", PORT->IOBASE); +#else + sprintf(Name, "COM%d", PORT->IOBASE); +#endif + PORT->SerialPortName = _strdup(Name); + } + else + PORT->SerialPortName = _strdup("NOPORT"); + + } + PORT->INTLEVEL = (char)PortRec->INTLEVEL; + PORT->BAUDRATE = PortRec->SPEED; + + if (PORT->BAUDRATE == 49664) + PORT->BAUDRATE = (int)115200; + + PORT->CHANNELNUM = (char)PortRec->CHANNEL; + PORT->PORTQUALITY = (UCHAR)PortRec->QUALITY; + PORT->NormalizeQuality = !PortRec->NoNormalize; + PORT->IgnoreUnlocked = PortRec->IGNOREUNLOCKED; + PORT->INP3ONLY = PortRec->INP3ONLY; + + PORT->PORTWINDOW = (UCHAR)PortRec->MAXFRAME; + + if (PortRec->PROTOCOL == 0 || PORT->PORTTYPE == 22) // KISS or I2C + PORT->PORTTXDELAY = PortRec->TXDELAY /10; + else + PORT->PORTTXDELAY = PortRec->TXDELAY; + + if (PortRec->PROTOCOL == 0 || PORT->PORTTYPE == 22) // KISS or I2C + PORT->PORTSLOTTIME = (UCHAR)PortRec->SLOTTIME / 10; + else + PORT->PORTSLOTTIME = (UCHAR)PortRec->SLOTTIME; + + PORT->PORTPERSISTANCE = (UCHAR)PortRec->PERSIST; + PORT->FULLDUPLEX = (UCHAR)PortRec->FULLDUP; + + PORT->SOFTDCDFLAG = (UCHAR)PortRec->SOFTDCD; + PORT->PORTT1 = PortRec->FRACK / 333; + PORT->PORTT2 = PortRec->RESPTIME /333; + PORT->PORTN2 = (UCHAR)PortRec->RETRIES; + + PORT->PORTPACLEN = (UCHAR)PortRec->PACLEN; + PORT->QUAL_ADJUST = (UCHAR)PortRec->QUALADJUST; + + PORT->DIGIFLAG = PortRec->DIGIFLAG; + if (PortRec->DIGIPORT && CanPortDigi(PortRec->DIGIPORT)) + PORT->DIGIPORT = PortRec->DIGIPORT; + PORT->DIGIMASK = PortRec->DIGIMASK; + PORT->USERS = (UCHAR)PortRec->USERS; + + // PORTTAILTIME - if KISS, set a default, and cnvert to ticks + + if (PORT->PORTTYPE == 0) + { + if (PortRec->TXTAIL) + PORT->PORTTAILTIME = PortRec->TXTAIL / 10; + else + PORT->PORTTAILTIME = 3; // 10ths + } + else + + //; ON HDLC, TAIL TIMER IS USED TO HOLD RTS FOR 'CONTROLLED FULL DUP' - Val in seconds + + PORT->PORTTAILTIME = (UCHAR)PortRec->TXTAIL; + + PORT->PORTBBSFLAG = (char)PortRec->ALIAS_IS_BBS; + PORT->PORTL3FLAG = (char)PortRec->L3ONLY; + PORT->KISSFLAGS = PortRec->KISSOPTIONS; + PORT->PORTINTERLOCK = (UCHAR)PortRec->INTERLOCK; + PORT->NODESPACLEN = (UCHAR)PortRec->NODESPACLEN; + PORT->TXPORT = (UCHAR)PortRec->TXPORT; + + PORT->PORTMINQUAL = PortRec->MINQUAL; + + if (PortRec->MAXDIGIS) + PORT->PORTMAXDIGIS = PortRec->MAXDIGIS; + else + PORT->PORTMAXDIGIS = 8; + + PORT->PortNoKeepAlive = PortRec->DefaultNoKeepAlives; + PORT->PortUIONLY = PortRec->UIONLY; + PORT->TXPORT = (UCHAR)PortRec->TXPORT; + + // SET UP CWID + + if (PortRec->CWIDTYPE == 'o') + PORT->CWTYPE = 'O'; + else + PORT->CWTYPE = PortRec->CWIDTYPE; + + ptr2 = &PortRec->CWID[0]; + CWPTR = &PORT->CWID[0]; + + PORT->CWIDTIMER = (29 - PORT->PORTNUMBER) * 600; // TICKSPERMINUTE + PORT->CWPOINTER = &PORT->CWID[0]; + + for (i = 0; i < 8; i++) // MAX ID LENGTH + { + char c = *(ptr2++); + if (c < 32) + break; + if (c > 'Z') + continue; + + c -= '/'; // Table stats at / + c &= 127; + + *(CWPTR) = CWTABLE[c]; + CWPTR++; + } + + // SEE IF LINK CALLSIGN/ALIAS SPECIFIED + + if (PortRec->PORTCALL[0]) + ConvToAX25(PortRec->PORTCALL, PORT->PORTCALL); + + if (PortRec->PORTALIAS[0]) + ConvToAX25(PortRec->PORTALIAS, PORT->PORTALIAS); + + if (PortRec->PORTALIAS2[0]) + ConvToAX25(PortRec->PORTALIAS2, PORT->PORTALIAS2); + + if (PortRec->DLLNAME[0]) + { + EXTPORT = (struct _EXTPORTDATA *)PORT; + memcpy(EXTPORT->PORT_DLL_NAME, PortRec->DLLNAME, 16); + } + if (PortRec->BCALL[0]) + ConvToAX25(PortRec->BCALL, PORT->PORTBCALL); + + PORT->XDIGIS = PortRec->XDIGIS; // Crossband digi aliases + + memcpy(&PORT->PORTIPADDR, &PortRec->IPADDR, 4); + PORT->ListenPort = PortRec->ListenPort; + + if (PortRec->TCPPORT) + { + PORT->KISSTCP = TRUE; + PORT->IOBASE = PortRec->TCPPORT; + if (PortRec->IPADDR == 0) + PORT->KISSSLAVE = TRUE; + } + + if (PortRec->WL2K) + memcpy(&PORT->WL2KInfo, PortRec->WL2K, sizeof(struct WL2KInfo)); + + PORT->RIGPort = PortRec->RIGPORT; + + if (PortRec->HavePermittedAppls) + PORT->PERMITTEDAPPLS = PortRec->PERMITTEDAPPLS; + else + PORT->PERMITTEDAPPLS = 0xffffffff; // Default to all + + PORT->Hide = PortRec->Hide; + + PORT->SmartIDInterval = PortRec->SmartID; + + if (PortRec->KissParams && (PORT->PORTTYPE == 0 || PORT->PORTTYPE == 22)) + { + struct KISSINFO * KISS = (struct KISSINFO *)PORT; + UCHAR KissString[128]; + int KissLen = 0; + unsigned char * Kissptr = KissString; + char * ptr; + char * Context; + + ptr = strtok_s(PortRec->KissParams, " ", &Context); + + while (ptr && ptr[0] && KissLen < 120) + { + *(Kissptr++) = atoi (ptr); + KissLen++; + ptr = strtok_s(NULL, " ", &Context); + } + + KISS->KISSCMD = malloc(256); + + KISS->KISSCMDLEN = KissEncode(KissString, KISS->KISSCMD, KissLen); + KISS->KISSCMD = realloc(KISS->KISSCMD, KISS->KISSCMDLEN); + } + + PORT->SendtoM0LTEMap = PortRec->SendtoM0LTEMap; + PORT->PortFreq = PortRec->PortFreq; + + PORT->M0LTEMapInfo = PortRec->M0LTEMapInfo; + + PORT->QtSMPort = PortRec->QtSMPort; + + if (PortRec->BBSFLAG) // Appl 1 not permitted - BBSFLAG=NOBBS + PORT->PERMITTEDAPPLS &= 0xfffffffe; // Clear bottom bit + + + // SEE IF PERMITTED LINK CALLSIGNS SPECIFIED + + ptr2 = &PortRec->VALIDCALLS[0]; + + if (*(ptr2)) + { + ptr3 = (char *)PORT->PORTPOINTER; // Permitted Calls follows Port Info + PORT->PERMITTEDCALLS = ptr3; + + while (*(ptr2) > 32) + { + ConvToAX25(ptr2, ptr3); + ptr3 += 7; + PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3; + if (strchr(ptr2, ',')) + { + ptr2 = strchr(ptr2, ','); + ptr2++; + } + else + break; + } + + ptr3 ++; // Terminating NULL + + // Round to word boundary (for ARM5 etc) + + int3 = (uintptr_t)ptr3; + int3 += 7; + int3 &= 0xfffffffffffffff8; + ptr3 = (UCHAR *)int3; + + PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3; + } + + // SEE IF PORT UNPROTO ADDR SPECIFIED + + ptr2 = &PortRec->UNPROTO[0]; + + if (*(ptr2)) + { + ptr3 = (char *)PORT->PORTPOINTER; // Unproto follows port info + PORT->PORTUNPROTO = ptr3; + + while (*(ptr2) > 32) + { + ConvToAX25(ptr2, ptr3); + ptr3 += 7; + PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3; + if (strchr(ptr2, ',')) + { + ptr2 = strchr(ptr2, ','); + ptr2++; + } + else + break; + } + + ptr3 ++; // Terminating NULL + + // Round to word boundsaty (for ARM5 etc) + + int3 = (uintptr_t)ptr3; + int3 += 7; + int3 &= 0xfffffffffffffff8; + ptr3 = (UCHAR *)int3; + + PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3; + } + + // ADD MH AREA IF NEEDED + + if (PortRec->MHEARD != 'N') + { + NEEDMH = 1; // Include MH in Command List + + ptr3 = (char *)PORT->PORTPOINTER; // Permitted Calls follows Port Info + PORT->PORTMHEARD = (PMHSTRUC)ptr3; + + ptr3 += (MHENTRIES + 1)* sizeof(MHSTRUC); + + // Round to word boundsaty (for ARM5 etc) + + int3 = (uintptr_t)ptr3; + int3 += 7; + int3 &= 0xfffffffffffffff8; + ptr3 = (UCHAR *)int3; + + PORT->PORTPOINTER = (struct PORTCONTROL *)ptr3; + } + + PortRec++; + NUMBEROFPORTS ++; + FULLPORT = (struct FULLPORTDATA *)PORT->PORTPOINTER; + } + + PORT->PORTPOINTER = NULL; // End of list + + NEXTFREEDATA = (UCHAR *)FULLPORT; + + // SET UP APPLICATION CALLS AND ALIASES + + APPL = &APPLCALLTABLE[0]; + + ptr1 = (struct APPLCONFIG *)&xxcfg.C_APPL[0]; + + i = NumberofAppls; + + if (ptr1->ApplCall[0] == ' ') + { + // APPL1CALL IS NOT SPECIFED - LEAVE VALUES SET FROM BBSCALL + + APPL++; + ptr1++; + i--; + } + + while (i) + { + memcpy(APPL->APPLCALL_TEXT, ptr1->ApplCall, 10); + ConvToAX25(APPL->APPLCALL_TEXT, APPL->APPLCALL); + memcpy(APPL->APPLALIAS_TEXT, ptr1->ApplAlias, 10); + ConvToAX25(APPL->APPLALIAS_TEXT, APPL->APPLALIAS); + ConvToAX25(ptr1->L2Alias, APPL->L2ALIAS); + memcpy(APPL->APPLCMD, ptr1->Command, 12); + + APPL->APPLQUAL = ptr1->ApplQual; + + if (ptr1->CommandAlias[0] != ' ') + { + APPL->APPLHASALIAS = 1; + memcpy(APPL->APPLALIASVAL, &ptr1->CommandAlias[0], 48); + } + + APPL++; + ptr1++; + i--; + } + + // SET UP VARIOUS CONTROL TABLES + + LINKS = (VOID *)NEXTFREEDATA; + NEXTFREEDATA += MAXLINKS * sizeof(struct _LINKTABLE); + + DESTS = (VOID *)NEXTFREEDATA; + NEXTFREEDATA += MAXDESTS * sizeof(struct DEST_LIST); + ENDDESTLIST = (VOID *)NEXTFREEDATA; + + NEIGHBOURS = (VOID *)NEXTFREEDATA; + NEXTFREEDATA += MAXNEIGHBOURS * sizeof(struct ROUTE); + + L4TABLE = (VOID *)NEXTFREEDATA; + + NEXTFREEDATA += MAXCIRCUITS * sizeof(TRANSPORTENTRY); + + // SET UP DEFAULT ROUTES LIST + + Rcfg = &cfg->C_ROUTE[0]; + + ROUTE = NEIGHBOURS; + + while (Rcfg->call[0]) + { + int FRACK; + char * VIA; + char axcall[8]; + + ConvToAX25(Rcfg->call, ROUTE->NEIGHBOUR_CALL); + + // if VIA convert digis + + VIA = strstr(Rcfg->call, "VIA"); + + if (VIA) + { + VIA += 4; + + if (ConvToAX25(VIA, axcall)) + { + memcpy(ROUTE->NEIGHBOUR_DIGI1, axcall, 7); + + VIA = strchr(VIA, ' '); + + if (VIA) + { + VIA++; + + if (ConvToAX25(VIA, axcall)) + memcpy(ROUTE->NEIGHBOUR_DIGI2, axcall, 7); + + } + } + } + + ROUTE->NEIGHBOUR_QUAL = Rcfg->quality; + ROUTE->NEIGHBOUR_PORT = Rcfg->port; + + PORT = GetPortTableEntryFromPortNum(ROUTE->NEIGHBOUR_PORT); + + if (Rcfg->pwind & 0x40) + ROUTE->NoKeepAlive = 1; + else + if (PORT != NULL) + ROUTE->NoKeepAlive = PORT->PortNoKeepAlive; + + if (Rcfg->pwind & 0x80 || (PORT && PORT->INP3ONLY)) + { + ROUTE->INP3Node = 1; + ROUTE->NoKeepAlive = 0; // Cant have INP3 and NOKEEPALIVES + } + + ROUTE->NBOUR_MAXFRAME = Rcfg->pwind & 0x3f; + + FRACK = Rcfg->pfrack; + ROUTE->NBOUR_FRACK = FRACK / 333; + ROUTE->NBOUR_PACLEN = Rcfg->ppacl; + ROUTE->OtherendsRouteQual = ROUTE->OtherendLocked = Rcfg->farQual; + + ROUTE->NEIGHBOUR_FLAG = 1; // Locked + + Rcfg++; + ROUTE++; + } + + // SET UP INFO MESSAGE + + ptr2 = &cfg->C_INFOMSG[0]; + ptr3 = NEXTFREEDATA; + + INFOMSG = ptr3; + + while ((*ptr2)) + { + *(ptr3++) = *(ptr2++); + } + *ptr3++ = 0; // Null Terminate + + NEXTFREEDATA = ptr3; + + // SET UP CTEXT MESSAGE + + ptr2 = &cfg->C_CTEXT[0]; + ptr3 = NEXTFREEDATA; + + CTEXTMSG = ptr3; + + while ((*ptr2)) + { + *(ptr3++) = *(ptr2++); + } + + CTEXTLEN = (int)(ptr3 - (unsigned char *)CTEXTMSG); + + NEXTFREEDATA = ptr3; + + // SET UP ID MESSAGE + + IDHDDR.DEST[0] = 'I'+'I'; + IDHDDR.DEST[1] = 'D'+'D'; + IDHDDR.DEST[2] = 0x40; + IDHDDR.DEST[3] = 0x40; + IDHDDR.DEST[4] = 0x40; + IDHDDR.DEST[5] = 0x40; + IDHDDR.DEST[6] = 0xe0; // ; ID IN AX25 FORM + + IDHDDR.CTL = 3; + IDHDDR.PID = 0xf0; + + ptr2 = &cfg->C_IDMSG[0]; + ptr3 = &IDHDDR.L2DATA[0]; + + while ((*ptr2)) + { + *(ptr3++) = *(ptr2++); + } + + IDHDDR.LENGTH = (int)(ptr3 - (unsigned char *)&IDHDDR); + + int3 = (uintptr_t)NEXTFREEDATA; + int3 += 7; + int3 &= 0xfffffffffffffff8; + NEXTFREEDATA = (UCHAR *)int3; + ENDBUFFERPOOL = NEXTFREEDATA + DATABYTES; // So init will work, set to actual end later + + BUFFERPOOL = NEXTFREEDATA; + + Consoleprintf("PORTS %p LINKS %p DESTS %p ROUTES %p L4 %p BUFFERS %p\n", + PORTTABLE, LINKS, DESTS, NEIGHBOURS, L4TABLE, BUFFERPOOL); + + Debugprintf("PORTS %p LINKS %p DESTS %p ROUTES %p L4 %p BUFFERS %p END POOL %p", + PORTTABLE, LINKS, DESTS, NEIGHBOURS, L4TABLE, BUFFERPOOL, DATAAREA + DATABYTES); + + i = NUMBEROFBUFFERS; + + NUMBEROFBUFFERS = 0; + + while (i-- && NEXTFREEDATA < (DATAAREA + DATABYTES - (512 + 8192))) // Keep 8K free for anything that needs shared memory + { + Bufferlist[NUMBEROFBUFFERS] = (void **)NEXTFREEDATA; + + ReleaseBuffer((UINT *)NEXTFREEDATA); + NEXTFREEDATA += BUFFALLOC; // was BUFFLEN + + NUMBEROFBUFFERS++; + MAXBUFFS++; + } + + ENDBUFFERPOOL = NEXTFREEDATA; + + + // Copy Bridge Map + + memcpy(BridgeMap, &cfg->CfgBridgeMap, sizeof(BridgeMap)); + +// MOV EAX,_NEXTFREEDATA +// CALL HEXOUT + + // SET UP OUR CALLIGN(S) + + ConvToAX25(MYNETROMCALL, NETROMCALL); + + ConvToAX25(MYNODECALL, MYCALL); + memcpy(&IDHDDR.ORIGIN[0], MYCALL, 7); + IDHDDR.ORIGIN[6] |= 0x61; // SET CMD END AND RESERVED BITS + + ConvToAX25(MYALIASTEXT, MYALIAS); + + // SET UP INITIAL DEST ENTRY FOR APPLICATIONS (IF BOTH NODE AND BBS NEEDED) + // Actually wrong - we need to set up application node entries even if node = 0 + DEST = DESTS; + + // If NODECALL isn't same as NETROMCALL, Add Dest Entry for NODECALL + + if (memcmp(NETROMCALL, MYCALL, 7) != 0) + { + memcpy(DEST->DEST_CALL, MYCALL, 7); + memcpy(DEST->DEST_ALIAS, MYALIASTEXT, 6); + + DEST->DEST_STATE = 0x80; // SPECIAL ENTRY + DEST->NRROUTE[0].ROUT_QUALITY = 255; + DEST->NRROUTE[0].ROUT_OBSCOUNT = 255; + DEST++; + NUMBEROFNODES++; + } + + if (BBS) + { + // Add Application Entries + + APPL = &APPLCALLTABLE[0]; + i = NumberofAppls; + + while (i--) + { + if (APPL->APPLQUAL) + { + memcpy(DEST->DEST_CALL, APPL->APPLCALL, 13); + DEST->DEST_STATE = 0x80; // SPECIAL ENTRY + DEST->NRROUTE[0].ROUT_QUALITY = (UCHAR)APPL->APPLQUAL; + DEST->NRROUTE[0].ROUT_OBSCOUNT = 255; + APPL->NODEPOINTER = DEST; + + DEST++; + + NUMBEROFNODES++; + } + APPL++; + } + } + + // Read Node and MH Recovery Files + + ReadNodes(); + + if (AUTOSAVEMH) + ReadMH(); // Only if AutoSave configured + + // set up stream number in BPQHOSTVECTOR + + for (i = 0; i < 64; i++) + { + BPQHOSTVECTOR[i].HOSTSTREAM = i + 1; + } + + memcpy(MYCALLWITHALIAS, MYCALL, 7); + memcpy(&MYCALLWITHALIAS[7], MYALIASTEXT, 6); + + // Set random start value for NETROM Session ID + + NEXTID = (rand() % 254) + 1; + + GetPortCTEXT(0, 0, 0, 0); + + upnpInit(); + + lastSaveSecs = CurrentSecs = lastSlowSecs = time(NULL); + + return 0; +} + +BOOL CompareCalls(UCHAR * c1, UCHAR * c2) +{ + // COMPARE AX25 CALLSIGNS IGNORING EXTRA BITS IN SSID + + if (memcmp(c1, c2, 6)) + return FALSE; // No Match + + if ((c1[6] & 0x1e) == (c2[6] & 0x1e)) + return TRUE; + + return FALSE; +} +BOOL CompareAliases(UCHAR * c1, UCHAR * c2) +{ + // COMPARE first 6 chars of AX25 CALLSIGNS + + if (memcmp(c1, c2, 6)) + return FALSE; // No Match + + return TRUE; +} +BOOL FindNeighbour(UCHAR * Call, int Port, struct ROUTE ** REQROUTE) +{ + struct ROUTE * ROUTE = NEIGHBOURS; + struct ROUTE * FIRSTSPARE = NULL; + int n = MAXNEIGHBOURS; + + while (n--) + { + if (ROUTE->NEIGHBOUR_CALL[0] == 0) // Spare + if (FIRSTSPARE == NULL) + FIRSTSPARE = ROUTE; + + if (ROUTE->NEIGHBOUR_PORT != Port) + { + ROUTE++; + continue; + } + if (CompareCalls(ROUTE->NEIGHBOUR_CALL, Call)) + { + *REQROUTE = ROUTE; + return TRUE; + } + ROUTE++; + } + + // ENTRY NOT FOUND - FIRSTSPARE HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL + + *REQROUTE = FIRSTSPARE; + return FALSE; +} + +BOOL FindDestination(UCHAR * Call, struct DEST_LIST ** REQDEST) +{ + struct DEST_LIST * DEST = DESTS; + struct DEST_LIST * FIRSTSPARE = NULL; + int n = MAXDESTS; + + while (n--) + { + if (DEST->DEST_CALL[0] == 0) // Spare + { + if (FIRSTSPARE == NULL) + FIRSTSPARE = DEST; + + DEST++; + continue; + } + if (CompareCalls(DEST->DEST_CALL, Call)) + { + *REQDEST = DEST; + return TRUE; + } + DEST++; + } + + // ENTRY NOT FOUND - FIRSTSPARE HAS FIRST FREE ENTRY, OR ZERO IF TABLE FULL + + *REQDEST = FIRSTSPARE; + return FALSE; +} + +extern UCHAR BPQDirectory[]; + +#define LINE_MAX 256 + + +// Reload saved MH file + +VOID ReadMH() +{ + char FN[260]; + FILE *fp; + char line[LINE_MAX]; + UCHAR axcall[7]; + char * ptr, *digi, *locptr, *locend; + char * Context, * Context2; + char seps[] = " \n"; + int Port; + struct PORTCONTROL * PORT = NULL; + MHSTRUC * MH; + int count = MHENTRIES; + char * Digiptr; + BOOL Digiused; + char * HasStar; + + // Set up pointer to BPQNODES file + + if (BPQDirectory[0] == 0) + { + strcpy(FN,"MHSave.txt"); + } + else + { + strcpy(FN,BPQDirectory); + strcat(FN,"/"); + strcat(FN,"MHSave.txt"); + } + + if ((fp = fopen(FN, "r")) == NULL) + { + return; + } + + while (fgets(line, LINE_MAX, fp) != NULL) + { + if (memcmp(line, "Port:", 5) == 0) + { + Port = atoi(&line[5]); + PORT = GetPortTableEntryFromPortNum(Port); + if (PORT) + MH = PORT->PORTMHEARD; + else + MH = NULL; + + continue; + } + + // 1548777630 N9LYA-8 Jan 29 16:00:30 + + if (MH) + { + ptr = strtok_s(line, seps, &Context); + + if (ptr == NULL) + continue; + + MH->MHTIME = atoi(ptr); + + ptr = strtok_s(NULL, seps, &Context); + + if (ptr == NULL) + continue; + + MH->MHCOUNT = atoi(ptr); + + // Get LOC and Freq First before strtok messes with line + + locptr = strchr(Context, '|'); + + if (locptr == NULL) + continue; + + locend = strchr(++locptr, '|'); + + if (locend == NULL) + continue; + + if ((locend - locptr) == 6) + + memcpy(MH->MHLocator, locptr, 6); + + locend++; + + strlop(locend, '\n'); + + if (strlen(locend) < 12) + + strcpy(MH->MHFreq, locend); + + ptr = strtok_s(NULL, "|\n", &Context); + + if (ptr == NULL) + continue; + + if (ConvToAX25(ptr, axcall) == FALSE) + continue; // Duff + + memcpy(MH->MHCALL, axcall, 7); + + if (ptr[10] != ' ') + MH->MHDIGI = ptr[10]; + + // SEE IF ANY DIGIS + + digi = strstr(ptr, " via "); + + if (digi) + { + digi = digi + 5; + Digiptr = &MH->MHDIGIS[0][0]; + + if (strchr(ptr, '*')) + Digiused = 1; // At least one digi used + else + Digiused = 0; + + digi = strtok_s(digi, ",\n", &Context2); + + while(digi) + { + HasStar = strlop(digi, '*'); + + if (ConvToAX25(digi, axcall) == FALSE) + break; + + memcpy(Digiptr, axcall, 7); + + if (Digiused) + Digiptr[6] |= 0x80; // Set used + + if (HasStar) + Digiused = 0; // Only last used has * + + Digiptr += 7; + + digi = strtok_s(NULL, ",/n", &Context2); + } + + *(--Digiptr) |= 1; // Set end of address on last + + } + else + { + // No Digis + + MH->MHCALL[6] |= 1; // Set end of address + } + + MH++; + } + } + + fclose(fp); + return; +} + + +VOID ReadNodes() +{ + char FN[260]; + FILE *fp; + char line[LINE_MAX]; + UCHAR axcall[7]; + char * ptr; + char * Context; + char seps[] = " \r"; + int Port, Qual; + struct PORTCONTROL * PORT; + + // Set up pointer to BPQNODES file + + if (BPQDirectory[0] == 0) + { + strcpy(FN,"BPQNODES.dat"); + } + else + { + strcpy(FN,BPQDirectory); + strcat(FN,"/"); + strcat(FN,"BPQNODES.dat"); + } + + if ((fp = fopen(FN, "r")) == NULL) + { + WritetoConsoleLocal( + "Route/Node recovery file BPQNODES.dat not found - Continuing without it\n"); + return; + } + + // Read the saved ROUTES/NODES file + + while (fgets(line, LINE_MAX, fp) != NULL) + { + if (memcmp(line, "ROUTE ADD", 9) == 0) + { + struct ROUTE * ROUTE = NULL; + + // FORMAT IS ROUTE ADD CALLSIGN PORT QUAL (VIA .... + + ptr = strtok_s(&line[10], seps, &Context); + + if (ConvToAX25(ptr, axcall) == FALSE) + continue; // DUff + + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) continue; + Port = atoi(ptr); + + PORT = GetPortTableEntryFromPortNum(Port); + + if (PORT == NULL) + continue; // Port has gone + + if (FindNeighbour(axcall, Port, &ROUTE)) + continue; // Already added from ROUTES: + + if (ROUTE == NULL) + continue; // Tsble Full + + memcpy(ROUTE->NEIGHBOUR_CALL, axcall, 7); + ROUTE->NEIGHBOUR_PORT = Port; + + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) continue; + Qual = atoi(ptr); + + ROUTE->NEIGHBOUR_QUAL = Qual; + + ptr = strtok_s(NULL, seps, &Context); // MAXFRAME + if (ptr == NULL) continue; + + // I don't thinlk we should load locked flag from save file - only from config + + // But need to parse it until I stop saving it + + if (ptr[0] == '!') + { +// ROUTE->NEIGHBOUR_FLAG = 1; // LOCKED ROUTE + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) continue; + } + + // SEE IF ANY DIGIS + + if (ptr[0] == 'V') + { + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) continue; + + if (ConvToAX25(ptr, axcall) == FALSE) + continue; // DUff + + memcpy(ROUTE->NEIGHBOUR_DIGI1, axcall, 7); + + ROUTE->NEIGHBOUR_FLAG = 1; // LOCKED ROUTE - Digi'ed routes must be locked + + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) continue; + + // See if another digi or MAXFRAME + + if (strlen(ptr) > 2) + { + if (ConvToAX25(ptr, axcall) == FALSE) + continue; // DUff + + memcpy(ROUTE->NEIGHBOUR_DIGI2, axcall, 7); + + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) continue; + } + } + + Qual = atoi(ptr); + ROUTE->NBOUR_MAXFRAME = Qual; + + ptr = strtok_s(NULL, seps, &Context); // FRACK + if (ptr == NULL) continue; + Qual = atoi(ptr); + ROUTE->NBOUR_FRACK = Qual; + + ptr = strtok_s(NULL, seps, &Context); // PACLEN + if (ptr == NULL) continue; + Qual = atoi(ptr); + ROUTE->NBOUR_PACLEN = Qual; + + ptr = strtok_s(NULL, seps, &Context); // INP3 + if (ptr == NULL) continue; + Qual = atoi(ptr); + + // We now take Nokeepalives from the PORT, unless specifically + // Requested + + ROUTE->NoKeepAlive = PORT->PortNoKeepAlive; + + if (Qual & 4) + ROUTE->NoKeepAlive = TRUE; + + if ((Qual & 1) || PORT->INP3ONLY) + { + ROUTE->NoKeepAlive = FALSE; + ROUTE->INP3Node = TRUE; + } + + ptr = strtok_s(NULL, seps, &Context); // INP3 + if (ptr == NULL) continue; + + if (ROUTE->NEIGHBOUR_FLAG == 0 || ROUTE->OtherendLocked == 0); // Not LOCKED ROUTE + ROUTE->OtherendsRouteQual = atoi(ptr); + + continue; + } + + if (memcmp(line, "NODE ADD", 8) == 0) + { + // FORMAT IS NODE ADD ALIAS:CALL ROUTE QUAL + + dest_list * DEST = NULL; + struct ROUTE * ROUTE = NULL; + char * ALIAS; + char FULLALIAS[6] = " "; + int SavedOBSINIT = OBSINIT; + + if (line[9] == ':') + { + // No alias + + Context = &line[10]; + } + else + { + ALIAS = strtok_s(&line[9], ":", &Context); + + if (ALIAS == NULL) + continue; + + memcpy(FULLALIAS, ALIAS, (int)strlen(ALIAS)); + } + + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) + continue; + + if (ConvToAX25(ptr, axcall) == FALSE) + continue; // Duff + + if (CompareCalls(axcall, MYCALL)) + continue; // Shoiuldn't happen, but to be safe! + + if (FindDestination(axcall, &DEST)) + continue; + + if (DEST == NULL) + continue; // Tsble Full + + memcpy(DEST->DEST_CALL, axcall, 7); + memcpy(DEST->DEST_ALIAS, FULLALIAS, 6); + + NUMBEROFNODES++; +RouteLoop: + // GET NEIGHBOURS FOR THIS DESTINATION - CALL PORT QUAL + + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) continue; + + if (ConvToAX25(ptr, axcall) == FALSE) + continue; // DUff + + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) continue; + Port = atoi(ptr); + + ptr = strtok_s(NULL, seps, &Context); + if (ptr == NULL) continue; + Qual = atoi(ptr); + + if (Context[0] == '!') + { + OBSINIT = 255; //; SPECIAL FOR LOCKED + } + + if (FindNeighbour(axcall, Port, &ROUTE)) + { + PROCROUTES(DEST, ROUTE, Qual); + } + + OBSINIT = SavedOBSINIT; + + goto RouteLoop; + } + } + + fclose(fp); + +// loadedmsg DB cr,lf,lf,'Switch loaded and initialised OK',lf,0 + + return; +} + +int DelayBuffers = 0; + +void sendModeReport(); +void sendFreqReport(); + +VOID TIMERINTERRUPT() +{ + // Main Processing loop - CALLED EVERY 100 MS + + int i; + struct PORTCONTROL * PORT = PORTTABLE; + PMESSAGE Buffer; + struct _LINKTABLE * LINK; + struct _MESSAGE * Message; + int toPort; + + CurrentSecs = time(NULL); + + BGTIMER++; + REALTIMETICKS++; + L2TIMERFLAG++; // INCREMENT FLAG FOR BG + L3TIMERFLAG++; // INCREMENT FLAG FOR BG + L4TIMERFLAG++; // INCREMENT FLAG FOR BG + +// CALL PORT TIMER ROUTINES + + for (i = 0; i < NUMBEROFPORTS; i++) + { + PORT->PORTTIMERCODE(PORT); + + // Check Smart ID timer + + if (PORT->SmartIDNeeded && PORT->SmartIDNeeded < time(NULL)) + SendSmartID(PORT); + + PORT = PORT->PORTPOINTER; + } + + // CHECK FOR TIMER ACTIVITY + + if (L2TIMERFLAG >= 3) + { + L2TIMERFLAG -= 3; + L2TimerProc(); // 300 mS + } + + if (CurrentSecs - lastSlowSecs >= 60) // 1 PER MIN + { + lastSlowSecs = CurrentSecs; + + L3TimerProc(); + + if (needAIS) + AISTimer(); + + if (needADSB) + ADSBTimer(); + + if (APRSActive) + Debugprintf("BPQ32 Heartbeat Buffers %d APRS Queues %d %d", QCOUNT, C_Q_COUNT(&APRSMONVECPTR->HOSTTRACEQ), C_Q_COUNT(&APPL_Q)); + else + Debugprintf("BPQ32 Heartbeat Buffers %d", QCOUNT); + + StatsTimer(); + + // Call EXT Port Slow Timer + + PORT = PORTTABLE; + + for (i = 0; i < NUMBEROFPORTS; i++) + { + if (PORT->PROTOCOL == 10) + { + PEXTPORTDATA PORTVEC = (PEXTPORTDATA)PORT; + EXTSLOWTIMER(PORTVEC); + } + + PORT = PORT->PORTPOINTER; + } + + // Call Mode Map support routine + + sendFreqReport(); + sendModeReport(); + + if (MQTT) + MQTTTimer(); + +/* + if (QCOUNT < 200) + { + if (DelayBuffers == 0) + { + FindLostBuffers(); + DelayBuffers = 10; + } + else + { + DelayBuffers--; + } + } +*/ + } + + // Check Autosave Nodes and MH timer + + if (CurrentSecs - lastSaveSecs >= 3600) // 1 per hour + { + lastSaveSecs = CurrentSecs; + + if (AUTOSAVE == 1) + SaveNodes(); + if (AUTOSAVEMH == 1) + SaveMH(); + } + + if (L4TIMERFLAG >= 10) // 1 PER SEC + { + L4TIMERFLAG -= 10; + + L3FastTimer(); + L4TimerProc(); + } + + // SEE IF ANY FRAMES TO TRACE + + Buffer = Q_REM(&TRACE_Q); + + while (Buffer) + { + // IF BUFFER HAS A LINK TABLE ENTRY ON END, RESET TIMEOUT + + LINK = Buffer->Linkptr; + + if (LINK) + { + if (LINK->L2TIMER) + LINK->L2TIMER = LINK->L2TIME; + + Buffer->Linkptr = 0; // CLEAR FLAG FROM BUFFER + } + + Message = (struct _MESSAGE *)Buffer; + Message->PORT |= 0x80; // Set TX Bit + + BPQTRACE(Message, FALSE); // Dont send TX'ed frames to APRS + ReleaseBuffer(Buffer); + + Buffer = Q_REM(&TRACE_Q); + } + + // CHECK FOR MESSAGES RECEIVED FROM COMMS LINKS + + PORT = PORTTABLE; + + for (i = 0; i < NUMBEROFPORTS; i++) + { + int Sent = 0; + + CURRENTPORT = PORT->PORTNUMBER; // PORT NUMBER + CURRENTPORTPTR = PORT; + + Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTRX_Q); + + while (Buffer) + { + Message = (struct _MESSAGE *) Buffer; + if (CURRENTPORT == 30) + Sent = Sent; + + if (PORT->PROTOCOL == 10) + { + int Sessno = Message->PORT; + PEXTPORTDATA PORTVEC = (PEXTPORTDATA)PORT; + TRANSPORTENTRY * Session; + TRANSPORTENTRY * Partner; + + if (PORT->TNC && PORT->TNC->Hardware == H_KISSHF) + { + + // KISSHF - May be L2 packet or Test Response + + if (Message->DEST[0] != 240) // Should only be ax.25 address field + goto L2Packet; + } + + // PACTOR Style Message + + InOctets[PORT->PORTNUMBER] += Message->LENGTH - (MSGHDDRLEN + 1); + PORT->L2FRAMESFORUS++; + + Session = PORTVEC->ATTACHEDSESSIONS[Sessno]; + + if (Session == NULL) + { + // TNC not attached - discard + + ReleaseBuffer(Buffer); + Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTRX_Q); + continue; + } + + Session->L4KILLTIMER = 0; // Reset Idle Timeout + + Partner = Session->L4CROSSLINK; + + if (Partner == NULL) + { + // No Crosslink - pass to command handler + + CommandHandler(Session, (PDATAMESSAGE)Buffer); + break; + } + + if (Partner->L4STATE < 5) + { + // MESSAGE RECEIVED BEFORE SESSION IS UP - CANCEL SESSION + // AND PASS MESSAGE TO COMMAND HANDLER + + if (Partner->L4CIRCUITTYPE & L2LINK) // L2 SESSION? + { + // MUST CANCEL L2 SESSION + + LINK = Partner->L4TARGET.LINK; + LINK->CIRCUITPOINTER = NULL; // CLEAR REVERSE LINK + + LINK->L2STATE = 4; // DISCONNECTING + LINK->L2TIMER = 1; // USE TIMER TO KICK OFF DISC + + LINK->L2RETRIES = LINK->LINKPORT->PORTN2 - 2; //ONLY SEND DISC ONCE + } + + CLEARSESSIONENTRY(Partner); + Session->L4CROSSLINK = 0; // CLEAR CROSS LINK + CommandHandler(Session, (struct DATAMESSAGE *)Buffer); + break; + } + + C_Q_ADD(&Partner->L4TX_Q, Buffer); + PostDataAvailable(Partner); + Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTRX_Q); + continue; + } + + +L2Packet: + // TIME STAMP IT + + time(&Message->Timestamp); + + Message->PORT = CURRENTPORT; + + if (MQTT && PORT->PROTOCOL == 0) + MQTTKISSRX(Buffer); + + // Bridge if requested + + for (toPort = 1; toPort <= MaxBPQPortNo; toPort++) + { + if (BridgeMap[CURRENTPORT][toPort]) + { + MESSAGE * BBuffer = GetBuff(); + struct PORTCONTROL * BPORT; + + if (BBuffer) + { + memcpy(BBuffer, Message, Message->LENGTH); + BBuffer->PORT = toPort; + BPORT = GetPortTableEntryFromPortNum(toPort); + + if (BPORT) + { + if (BPORT->SmartIDInterval && BPORT->SmartIDNeeded == 0) + { + // Using Smart ID, but none scheduled + + BPORT->SmartIDNeeded = time(NULL) + BPORT->SmartIDInterval; + } + PUT_ON_PORT_Q(BPORT, BBuffer); + } + else + ReleaseBuffer(BBuffer); + } + } + } + + L2Routine(PORT, Buffer); + + Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTRX_Q); + continue; + } + + // End of RX_Q + + Sent = 0; + + while (PORT->PORTTX_Q && Sent < 5) + { + int ret; + void * PACTORSAVEQ; + + Buffer = PORT->PORTTX_Q; + Message = (struct _MESSAGE *) Buffer; + + ret = PORT->PORTTXCHECKCODE(PORT, Message->PORT); + + // Busy but not connected means TNC has gone - clear queue + + if (ret == 1) + { + MESSAGE * Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTTX_Q); + + if (Buffer == 0) + break; // WOT!! + +// Debugprintf("Busy but not connected - discard message %s", Buffer->L2DATA); + + ReleaseBuffer(Buffer); + break; + } + + ret = ret & 0xff; // Only check bottom byte + + if (ret == 0) // Not busy + { + MESSAGE * Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTTX_Q); + + if (Buffer == 0) + break; // WOT!! + + if (PORT->PORTDISABLED) + { + ReleaseBuffer(Buffer); + break; + } + + PORT->L2FRAMESSENT++; + OutOctets[PORT->PORTNUMBER] += Buffer->LENGTH - MSGHDDRLEN; + + PORT->PORTTXROUTINE((struct _EXTPORTDATA *)PORT, Buffer); + Sent++; + + continue; + } + + // If a Pactor Port, some channels could be busy whilst others are not. + + if (PORT->PROTOCOL != 10) + break; // BUSY + + // Try passing any other messages on the queue to the node. + + PACTORSAVEQ = 0; + +PACTORLOOP: + + Buffer = PORT->PORTTX_Q; + + if (Buffer == NULL) + goto ENDOFLIST; + + Message = (struct _MESSAGE *) Buffer; + ret = PORT->PORTTXCHECKCODE(PORT, Message->PORT); + ret = ret & 0xff; // Only check bottom byte + + if (ret) // Busy + { + // Save it + + Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTTX_Q); + C_Q_ADD(&PACTORSAVEQ, Buffer); + goto PACTORLOOP; + } + + Buffer = (PMESSAGE)Q_REM((void *)&PORT->PORTTX_Q); + + if (PORT->PORTDISABLED) + { + ReleaseBuffer(Buffer); + goto PACTORLOOP; + } + + PORT->L2FRAMESSENT++; + OutOctets[PORT->PORTNUMBER] += Message->LENGTH; + + PORT->PORTTXROUTINE((struct _EXTPORTDATA *)PORT, Buffer); + Sent++; + + if (Sent < 5) + goto PACTORLOOP; // SEE IF MORE + +ENDOFLIST: + // Move the saved frames back onto Port Q + + PORT->PORTTX_Q = PACTORSAVEQ; + break; + } + + PORT->PORTRXROUTINE((struct _EXTPORTDATA *)PORT); // SEE IF MESSAGE RECEIVED + PORT = PORT->PORTPOINTER; + } + +/* +; +; CHECK FOR INCOMING MESSAGES ON LINK CONTROL TABLE - +; BY NOW ONLY 'I' FRAMES WILL BE PRESENT - +; LEVEL 2 PROTOCOL HANDLING IS DONE IN MESSAGE RECEIVE CODE +; AND LINK HANDLING INTERRUPT ROUTINES +; +*/ + + LINK = LINKS; + i = MAXLINKS; + + while (i--) + { + if (LINK->LINKCALL[0]) + { + Buffer = Q_REM(&LINK->RX_Q); + + while (Buffer) + { + ProcessIframe(LINK, (PDATAMESSAGE)Buffer); + + Buffer =(PMESSAGE)Q_REM((void *)&LINK->RX_Q); + } + + // CHECK FOR OUTGOING MSGS + + if (LINK->L2STATE >= 5) // CANT SEND TEXT TILL CONNECTED + { + // CMP VER1FLAG[EBX],1 + // JE SHORT MAINL35 ; NEED TO RETRY WITH I FRAMES IF VER 1 + + // CMP L2RETRIES[EBX],0 + // JNE SHORT MAINL40 ; CANT SEND TEXT IF RETRYING + + if ((LINK->L2FLAGS & RNRSET) == 0) + SDETX(LINK); + } + } + LINK++; + } + + L4BG(); // DO LEVEL 4 PROCESSING + L3BG(); + TNCTimerProc(); +} + +VOID DoListenMonitor(TRANSPORTENTRY * L4, MESSAGE * Msg) +{ + uint64_t SaveMMASK = MMASK; + BOOL SaveMTX = MTX; + BOOL SaveMCOM = MCOM; + BOOL SaveMUI = MUIONLY; + PDATAMESSAGE Buffer; + char MonBuffer[1024]; + int len; + struct tm * TM; + UCHAR * monchars = (UCHAR *)Msg; + + if (CountFramesQueuedOnSession(L4) > 10) + return; + + if (monchars[21] == 3 && monchars[22] == 0xcf && monchars[23] == 0xff) // Netrom Nodes + return; + + IntSetTraceOptionsEx(L4->LISTEN, 1, 0, 0); + + TM = gmtime(&Msg->Timestamp); + sprintf(MonBuffer, "%02d:%02d:%02d ", TM->tm_hour, TM->tm_min, TM->tm_sec); + + len = IntDecodeFrame(Msg, &MonBuffer[9], Msg->Timestamp, L4->LISTEN, FALSE, TRUE); + + IntSetTraceOptionsEx(SaveMMASK, SaveMTX, SaveMCOM, SaveMUI); + + if (len == 0) + return; + + len += 9; + + if (len > 256) + len = 256; + + Buffer = GetBuff(); + + if (Buffer) + { + char * ptr = &Buffer->L2DATA[0]; + Buffer->PID = 0xf0; + + memcpy(ptr, MonBuffer, len); + + Buffer->LENGTH = (USHORT)len + 4 + sizeof(void *); + + C_Q_ADD(&L4->L4TX_Q, Buffer); + + PostDataAvailable(L4); + } +} + +DllExport int APIENTRY DllBPQTRACE(MESSAGE * Msg, BOOL TOAPRS) +{ + int ret; + GetSemaphore(&Semaphore, 88); + ret = BPQTRACE(Msg, TOAPRS); + FreeSemaphore(&Semaphore); + return ret; +} + +int BPQTRACE(MESSAGE * Msg, BOOL TOAPRS) +{ + // ATTACH A COPY OF FRAME TO ANY BPQ HOST PORTS WITH MONITORING ENABLED + + TRANSPORTENTRY * L4 = L4TABLE; + + MESSAGE * Buffer; + int i = BPQHOSTSTREAMS + 2; // Include Telnet and AGW Stream + + if (TOAPRS) + i++; // Include APRS Stream + + while(i) + { + i--; + + if (QCOUNT < 100) + return FALSE; + + if (BPQHOSTVECTOR[i].HOSTAPPLFLAGS & 0x80) // Trace Enabled? + { + Buffer = GetBuff(); + if (Buffer) + { + memcpy(&Buffer->PORT, &Msg->PORT, BUFFLEN - sizeof(void *)); // Dont copy chain word + C_Q_ADD(&BPQHOSTVECTOR[i].HOSTTRACEQ, Buffer); + +#ifndef LINBPQ + if (BPQHOSTVECTOR[i].HOSTHANDLE) + PostMessage(BPQHOSTVECTOR[i].HOSTHANDLE, BPQMsg, BPQHOSTVECTOR[i].HOSTSTREAM, 1); +#endif + } + } + + } + + // Also pass to any users LISTENING on this port + + i = MAXCIRCUITS; + + if (QCOUNT < 300) + return FALSE; // Until I add by session flow control + + while (i--) + { + if (L4->LISTEN) + if ((((uint64_t)1 << ((Msg->PORT & 0x7f) - 1)) & L4->LISTEN)) + // if ((Msg->PORT & 0x7f) == L4->LISTEN) + DoListenMonitor(L4, Msg); + + L4++; + } + + return TRUE; +} +; + +VOID INITIALISEPORTS() +{ + char INITMSG[80]; + struct PORTCONTROL * PORT = PORTTABLE; + + while (PORT) + { + sprintf(INITMSG, "Initialising Port %02d ", PORT->PORTNUMBER); + WritetoConsoleLocal(INITMSG); + + PORT->PORTINITCODE(PORT); + PORT = PORT->PORTPOINTER; + } +} + +VOID FindLostBuffers() +{ + void ** Buff; + int n, i; + unsigned int rev; + + UINT CodeDump[16]; + char codeText[65] = ""; + unsigned char * codeByte = (unsigned char *) CodeDump; + + PBPQVECSTRUC HOSTSESS = BPQHOSTVECTOR; + struct _TRANSPORTENTRY * L4; // Pointer to Session + + struct DEST_LIST * DEST = DESTS; + + struct ROUTE * Routes = NEIGHBOURS; + int MaxRoutes = MAXNEIGHBOURS; + int Queued; + char Call[10]; + + n = MAXDESTS; + + Debugprintf("Looking for missing Buffers"); + + while (n--) + { + if (DEST->DEST_CALL[0] && DEST->DEST_Q) // Spare + { + Debugprintf("DEST Queue %s %d", DEST->DEST_ALIAS, C_Q_COUNT(&DEST->DEST_Q)); + } + + DEST++; + } + + n = 0; + + while (n < BPQHOSTSTREAMS + 4) + { + // Check Trace Q + + if (HOSTSESS->HOSTTRACEQ) + { + int Count = C_Q_COUNT(&HOSTSESS->HOSTTRACEQ); + + Debugprintf("Trace Buffers Stream %d Count %d", n, Count); + + L4 = HOSTSESS->HOSTSESSION; + + if (L4 && (L4->L4TX_Q || L4->L4RX_Q || L4->L4HOLD_Q || L4->L4RESEQ_Q)) + Debugprintf("Stream %d %d %d %d %d", n, C_Q_COUNT(&L4->L4TX_Q), + C_Q_COUNT(&L4->L4RX_Q), C_Q_COUNT(&L4->L4HOLD_Q), C_Q_COUNT(&L4->L4RESEQ_Q)); + + } + n++; + HOSTSESS++; + } + + n = MAXCIRCUITS; + L4 = L4TABLE; + + while (n--) + { + if (L4->L4USER[0] == 0) + { + L4++; + continue; + } + if (L4->L4TX_Q || L4->L4RX_Q || L4->L4HOLD_Q || L4->L4RESEQ_Q) + Debugprintf("L4 %d TX %d RX %d HOLD %d RESEQ %d", MAXCIRCUITS - n, C_Q_COUNT(&L4->L4TX_Q), + C_Q_COUNT(&L4->L4RX_Q), C_Q_COUNT(&L4->L4HOLD_Q), C_Q_COUNT(&L4->L4RESEQ_Q)); + L4++; + } + + // Routes + + while (MaxRoutes--) + { + if (Routes->NEIGHBOUR_CALL[0] != 0) + { + Call[ConvFromAX25(Routes->NEIGHBOUR_CALL, Call)] = 0; + if (Routes->NEIGHBOUR_LINK) + { + Queued = COUNT_AT_L2(Routes->NEIGHBOUR_LINK); // SEE HOW MANY QUEUED + if (Queued) + Debugprintf("Route %s %d", Call, Queued); + } + } + Routes++; + } + + // Build list of buffers, then mark off all on free Q + + Buff = BUFFERPOOL; + n = 0; + + for (i = 0; i < NUMBEROFBUFFERS; i++) + { + Bufferlist[n++] = Buff; + Buff += (BUFFALLOC / sizeof(void *)); + } + + Buff = FREE_Q; + + while (Buff) + { + n = NUMBEROFBUFFERS; + + while (n--) + { + if (Bufferlist[n] == Buff) + { + Bufferlist[n] = 0; + break; + } + } + Buff = *Buff; + } + n = NUMBEROFBUFFERS; + + while (n--) + { + if (Bufferlist[n]) + { + char * fileptr = (char *)Bufferlist[n]; + MESSAGE * Msg = (MESSAGE *)Bufferlist[n]; + + memcpy(CodeDump, Bufferlist[n], 64); + + for (i = 0; i < 64; i++) + { + if (codeByte[i] > 0x1f && codeByte[i] < 0x80) + codeText[i] = codeByte[i]; + else + codeText[i] = '.'; + } + + for (i = 0; i < 16; i++) + { + rev = (CodeDump[i] & 0xff) << 24; + rev |= (CodeDump[i] & 0xff00) << 8; + rev |= (CodeDump[i] & 0xff0000) >> 8; + rev |= (CodeDump[i] & 0xff000000) >> 24; + + CodeDump[i] = rev; + } + + Debugprintf("%08x %08x %08x %08x %08x %08x %08x %08x %08x ", + Bufferlist[n], CodeDump[0], CodeDump[1], CodeDump[2], CodeDump[3], CodeDump[4], CodeDump[5], CodeDump[6], CodeDump[7]); + + Debugprintf(" %08x %08x %08x %08x %08x %08x %08x %08x %d", + CodeDump[8], CodeDump[9], CodeDump[10], CodeDump[11], CodeDump[12], CodeDump[13], CodeDump[14], CodeDump[15], Msg->Process); + + Debugprintf(" %s %s", &fileptr[400], codeText); + } + } + + // rebuild list for buffer check + Buff = BUFFERPOOL; + n = 0; + + for (i = 0; i < NUMBEROFBUFFERS; i++) + { + Bufferlist[n++] = Buff; + Buff += (BUFFALLOC / sizeof(void *)); + } +} + +void WriteConnectLog(char * fromCall, char * toCall, UCHAR * Mode) +{ + UCHAR FN[MAX_PATH]; + FILE * LogHandle; + time_t T; + struct tm * tm; + char LogMsg[256]; + int MsgLen; + + T = time(NULL); + tm = gmtime(&T); + + sprintf(FN,"%s/logs/ConnectLog_%02d%02d%02d.log", LogDirectory, tm->tm_year - 100, tm->tm_mon + 1, tm->tm_mday); + + LogHandle = fopen(FN, "ab"); + + if (LogHandle == NULL) + return; + + MsgLen = sprintf(LogMsg, "%02d:%02d:%02d Call from %s to %s Mode %s\r\n", tm->tm_hour, tm->tm_min, tm->tm_sec, fromCall, toCall, Mode); + + fwrite(LogMsg , 1, MsgLen, LogHandle); + fclose(LogHandle); +} + + + diff --git a/cMain.c b/cMain.c index 7cf47d0..ea68401 100644 --- a/cMain.c +++ b/cMain.c @@ -34,7 +34,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include #include "kernelresource.h" -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h" #include "mqtt.h" @@ -2468,7 +2468,7 @@ VOID DoListenMonitor(TRANSPORTENTRY * L4, MESSAGE * Msg) PDATAMESSAGE Buffer; char MonBuffer[1024]; int len; - + struct tm * TM; UCHAR * monchars = (UCHAR *)Msg; if (CountFramesQueuedOnSession(L4) > 10) @@ -2478,14 +2478,19 @@ VOID DoListenMonitor(TRANSPORTENTRY * L4, MESSAGE * Msg) return; IntSetTraceOptionsEx(L4->LISTEN, 1, 0, 0); - - len = IntDecodeFrame(Msg, MonBuffer, Msg->Timestamp, L4->LISTEN, FALSE, TRUE); + + TM = gmtime(&Msg->Timestamp); + sprintf(MonBuffer, "%02d:%02d:%02d ", TM->tm_hour, TM->tm_min, TM->tm_sec); + + len = IntDecodeFrame(Msg, &MonBuffer[9], Msg->Timestamp, L4->LISTEN, FALSE, TRUE); IntSetTraceOptionsEx(SaveMMASK, SaveMTX, SaveMCOM, SaveMUI); if (len == 0) return; + len += 9; + if (len > 256) len = 256; diff --git a/CHeaders.h b/cheaders.h similarity index 93% rename from CHeaders.h rename to cheaders.h index beb6380..c4f6c85 100644 --- a/CHeaders.h +++ b/cheaders.h @@ -1,447 +1,451 @@ -// -// Prototypes for BPQ32 Node Functions -// - -#define DllImport - -#define EXCLUDEBITS - -#define _WINSOCK_DEPRECATED_NO_WARNINGS - -#include "compatbits.h" - -#include "asmstrucs.h" - -BOOL CheckExcludeList(UCHAR * Call); - -Dll int ConvFromAX25(unsigned char * incall,unsigned char * outcall); -Dll BOOL ConvToAX25(unsigned char * callsign, unsigned char * ax25call); -DllExport BOOL ConvToAX25Ex(unsigned char * callsign, unsigned char * ax25call); -int WritetoConsoleLocal(char * buff); -VOID Consoleprintf(const char * format, ...); -VOID FreeConfig(); -int GetListeningPortsPID(int Port); - -void * InitializeExtDriver(PEXTPORTDATA PORTVEC); - -VOID PutLengthinBuffer(PDATAMESSAGE buff, USHORT datalen); // Needed for arm5 portability -int GetLengthfromBuffer(PDATAMESSAGE buff); -int IntDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, uint64_t Mask, BOOL APRS, BOOL MCTL); -int IntSetTraceOptionsEx(uint64_t mask, int mtxparam, int mcomparam, int monUIOnly); -int CountBits64(uint64_t in); - -#define GetBuff() _GetBuff(__FILE__, __LINE__) -#define ReleaseBuffer(s) _ReleaseBuffer(s, __FILE__, __LINE__) -#define CheckGuardZone() _CheckGuardZone(__FILE__, __LINE__) - -#define Q_REM(s) _Q_REM(s, __FILE__, __LINE__) -#define Q_REM_NP(s) _Q_REM_NP(s, __FILE__, __LINE__) - -#define C_Q_ADD(s, b) _C_Q_ADD(s, b, __FILE__, __LINE__) - -void _CheckGuardZone(char * File, int Line); - -VOID * _Q_REM(VOID **Q, char * File, int Line); -VOID * _Q_REM_NP(VOID *Q, char * File, int Line); - -int _C_Q_ADD(VOID *Q, VOID *BUFF, char * File, int Line); - -UINT _ReleaseBuffer(VOID *BUFF, char * File, int Line); - -VOID * _GetBuff(char * File, int Line); -int _C_Q_ADD(VOID *PQ, VOID *PBUFF, char * File, int Line); - -int C_Q_COUNT(VOID *Q); - -DllExport char * APIENTRY GetApplCall(int Appl); -DllExport char * APIENTRY GetApplAlias(int Appl); -DllExport int APIENTRY FindFreeStream(); -DllExport int APIENTRY DeallocateStream(int stream); -DllExport int APIENTRY SessionState(int stream, int * state, int * change); -DllExport int APIENTRY SetAppl(int stream, int flags, int mask); -DllExport int APIENTRY GetMsg(int stream, char * msg, int * len, int * count ); -DllExport int APIENTRY GetConnectionInfo(int stream, char * callsign, - int * port, int * sesstype, int * paclen, - int * maxframe, int * l4window); - - -struct config_setting_t; - -int GetIntValue(struct config_setting_t * group, char * name); -BOOL GetStringValue(struct config_setting_t * group, char * name, char * value); -VOID SaveIntValue(struct config_setting_t * group, char * name, int value); -VOID SaveStringValue(struct config_setting_t * group, char * name, char * value); - -int EncryptPass(char * Pass, char * Encrypt); -VOID DecryptPass(char * Encrypt, unsigned char * Pass, unsigned int len); -Dll VOID APIENTRY CreateOneTimePassword(char * Password, char * KeyPhrase, int TimeOffset); -Dll BOOL APIENTRY CheckOneTimePassword(char * Password, char * KeyPhrase); - -DllExport int APIENTRY TXCount(int stream); -DllExport int APIENTRY RXCount(int stream); -DllExport int APIENTRY MONCount(int stream); - -VOID ReadNodes(); -int BPQTRACE(MESSAGE * Msg, BOOL APRS); - -VOID CommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer); - -VOID PostStateChange(TRANSPORTENTRY * Session); - -VOID InnerCommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer); -VOID DoTheCommand(TRANSPORTENTRY * Session); -char * MOVEANDCHECK(TRANSPORTENTRY * Session, char * Bufferptr, char * Source, int Len); -VOID DISPLAYCIRCUIT(TRANSPORTENTRY * L4, char * Buffer); -char * strlop(const char * buf, char delim); -BOOL CompareCalls(UCHAR * c1, UCHAR * c2); - -VOID PostDataAvailable(TRANSPORTENTRY * Session); -int WritetoConsoleLocal(char * buff); -char * CHECKBUFFER(TRANSPORTENTRY * Session, char * Bufferptr); -VOID CLOSECURRENTSESSION(TRANSPORTENTRY * Session); - -VOID SendCommandReply(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer, int Len); - -struct PORTCONTROL * APIENTRY GetPortTableEntryFromPortNum(int portnum); - -int cCOUNT_AT_L2(struct _LINKTABLE * LINK); -VOID SENDL4CONNECT(TRANSPORTENTRY * Session); - -VOID CloseSessionPartner(TRANSPORTENTRY * Session); -int COUNTNODES(struct ROUTE * ROUTE); -int DecodeNodeName(char * NodeName, char * ptr);; -VOID DISPLAYCIRCUIT(TRANSPORTENTRY * L4, char * Buffer); -int cCOUNT_AT_L2(struct _LINKTABLE * LINK); -void * zalloc(int len); -BOOL FindDestination(UCHAR * Call, struct DEST_LIST ** REQDEST); - -BOOL ProcessConfig(); - -VOID PUT_ON_PORT_Q(struct PORTCONTROL * PORT, MESSAGE * Buffer); -VOID CLEAROUTLINK(struct _LINKTABLE * LINK); -VOID TellINP3LinkGone(struct ROUTE * Route); -VOID CLEARACTIVEROUTE(struct ROUTE * ROUTE, int Reason); - -// Reason Equates - -#define NORMALCLOSE 0 -#define RETRIEDOUT 1 -#define SETUPFAILED 2 -#define LINKLOST 3 -#define LINKSTUCK 4 - -int COUNT_AT_L2(struct _LINKTABLE * LINK); -VOID SENDIDMSG(); -VOID SENDBTMSG(); -VOID INP3TIMER(); -VOID REMOVENODE(dest_list * DEST); -BOOL ACTIVATE_DEST(struct DEST_LIST * DEST); -VOID TellINP3LinkSetupFailed(struct ROUTE * Route); -BOOL FindNeighbour(UCHAR * Call, int Port, struct ROUTE ** REQROUTE); -VOID PROCROUTES(struct DEST_LIST * DEST, struct ROUTE * ROUTE, int Qual); -BOOL L2SETUPCROSSLINK(PROUTE ROUTE); -VOID REMOVENODE(dest_list * DEST); -char * SetupNodeHeader(struct DATAMESSAGE * Buffer); -VOID L4CONNECTFAILED(TRANSPORTENTRY * L4); -int CountFramesQueuedOnSession(TRANSPORTENTRY * Session); -VOID CLEARSESSIONENTRY(TRANSPORTENTRY * Session); -VOID __cdecl Debugprintf(const char * format, ...); - -int APIENTRY Restart(); -int APIENTRY Reboot(); -int APIENTRY Reconfig(); -Dll int APIENTRY SaveNodes (); - - -struct SEM; - -void GetSemaphore(struct SEM * Semaphore, int ID); -void FreeSemaphore(struct SEM * Semaphore); - -void MySetWindowText(HWND hWnd, char * Msg); - -Dll int APIENTRY SessionControl(int stream, int command, int Mask); - -HANDLE OpenCOMPort(VOID * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits); -int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength); -BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite); -VOID CloseCOMPort(HANDLE fd); - -VOID initUTF8(); -int Is8Bit(unsigned char *cpt, int len); -int WebIsUTF8(unsigned char *ptr, int len); -int IsUTF8(unsigned char *ptr, int len); -int Convert437toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); -int Convert1251toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); -int Convert1252toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); -int TrytoGuessCode(unsigned char * Char, int Len); - - -#define CMD_TO_APPL 1 // PASS COMMAND TO APPLICATION -#define MSG_TO_USER 2 // SEND 'CONNECTED' TO USER -#define MSG_TO_APPL 4 // SEND 'CONECTED' TO APPL -#define CHECK_FOR_ESC 8 // Look for ^d (^D) to disconnect session) - -#define UI 3 -#define SABM 0x2F -#define DISC 0x43 -#define DM 0x0F -#define UA 0x63 -#define FRMR 0x87 -#define RR 1 -#define RNR 5 -#define REJ 9 - -// V2.2 Types - -#define SREJ 0x0D -#define SABME 0x6F -#define XID 0xAF -#define TEST 0xE3 - -#define SUPPORT2point2 1 - -// XID Optional Functions - -#define OPMustHave 0x02A080 // Sync TEST 16 bit FCS Extended Address -#define OPSREJ 4 -#define OPSREJMult 0x200000 -#define OPREJ 2 -#define OPMod8 0x400 -#define OPMod128 0x800 - -#define BPQHOSTSTREAMS 64 - -extern TRANSPORTENTRY * L4TABLE; -extern unsigned char NEXTID; -extern int MAXCIRCUITS; -extern int L4DEFAULTWINDOW; -extern int L4T1; -extern APPLCALLS APPLCALLTABLE[]; -extern char * APPLS; -extern int NEEDMH; -extern int RFOnly; - -extern char SESSIONHDDR[]; - -extern UCHAR NEXTID; - -extern struct ROUTE * NEIGHBOURS; -extern int MAXNEIGHBOURS; - -extern struct ROUTE * NEIGHBOURS; -extern int ROUTE_LEN; -extern int MAXNEIGHBOURS; - -extern struct DEST_LIST * DESTS; // NODE LIST -extern struct DEST_LIST * ENDDESTLIST; -extern int DEST_LIST_LEN; -extern int MAXDESTS; // MAX NODES IN SYSTEM - -extern struct _LINKTABLE * LINKS; -extern int LINK_TABLE_LEN; -extern int MAXLINKS; - - - -extern char MYCALL[]; // DB 7 DUP (0) ; NODE CALLSIGN (BIT SHIFTED) -extern char MYALIASTEXT[]; // {" " ; NODE ALIAS (KEEP TOGETHER) - -extern UCHAR MYCALLWITHALIAS[13]; -extern APPLCALLS APPLCALLTABLE[NumberofAppls]; - -extern UCHAR MYNODECALL[]; // NODE CALLSIGN (ASCII) -extern char NODECALLLOPPED[]; // NODE CALLSIGN (ASCII). Null terminated -extern UCHAR MYNETROMCALL[]; // NETROM CALLSIGN (ASCII) - -extern UCHAR NETROMCALL[]; // NETORM CALL (AX25) - -extern VOID * FREE_Q; - -extern struct PORTCONTROL * PORTTABLE; -extern int NUMBEROFPORTS; - - -extern int OBSINIT; // INITIAL OBSOLESCENCE VALUE -extern int OBSMIN; // MINIMUM TO BROADCAST -extern int L3INTERVAL; // "NODES" INTERVAL IN MINS -extern int IDINTERVAL; // "ID" BROADCAST INTERVAL -extern int BTINTERVAL; // "BT" BROADCAST INTERVAL -extern int MINQUAL; // MIN QUALITY FOR AUTOUPDATES -extern int HIDENODES; // N * COMMAND SWITCH -extern int BBSQUAL; // QUALITY OF BBS RELATIVE TO NODE - -extern int NUMBEROFBUFFERS; // PACKET BUFFERS -extern int PACLEN; //MAX PACKET SIZE - -// L2 SYSTEM TIMER RUNS AT 3 HZ - -extern int T3; // LINK VALIDATION TIMER (3 MINS) (+ a bit to reduce RR collisions) - -extern int L2KILLTIME; // IDLE LINK TIMER (16 MINS) -extern int L3LIVES; // MAX L3 HOPS -extern int L4N2; // LEVEL 4 RETRY COUNT -extern int L4LIMIT; // IDLE SESSION LIMIT - 15 MINS -extern int L4DELAY; // L4 DELAYED ACK TIMER - -extern int BBS; // INCLUDE BBS SUPPORT -extern int NODE; // INCLUDE SWITCH SUPPORT - -extern int FULL_CTEXT; // CTEXT ON ALL CONNECTS IF NZ - - -// Although externally streams are numbered 1 to 64, internally offsets are 0 - 63 - -extern BPQVECSTRUC DUMMYVEC; // Needed to force correct order of following - -extern BPQVECSTRUC BPQHOSTVECTOR[BPQHOSTSTREAMS + 5]; - -extern int NODEORDER; -extern UCHAR LINKEDFLAG; - -extern UCHAR UNPROTOCALL[80]; - - -extern char * INFOMSG; - -extern char * CTEXTMSG; -extern int CTEXTLEN; - -extern UCHAR MYALIAS[7]; // ALIAS IN AX25 FORM -extern UCHAR BBSALIAS[7]; - -extern VOID * TRACE_Q; // TRANSMITTED FRAMES TO BE TRACED - -extern char HEADERCHAR; // CHAR FOR _NODE HEADER MSGS - -extern int AUTOSAVE; // AUTO SAVE NODES ON EXIT FLAG -extern int L4APPL; // Application for BBSCALL/ALIAS connects -extern int CFLAG; // C =HOST Command - -extern VOID * IDMSG_Q; // ID/BEACONS WAITING TO BE SENT - -extern struct DATAMESSAGE BTHDDR; -extern struct _MESSAGE IDHDDR; - -extern VOID * IDMSG; - -extern int L3TIMER; // TIMER FOR 'NODES' MESSAGE -extern int IDTIMER; // TIMER FOR ID MESSAGE -extern int BTTIMER; // TIMER FOR BT MESSAGE - -extern int STATSTIME; - - -extern BOOL IPRequired; -extern int MaxHops; -extern int MAXRTT; -extern USHORT CWTABLE[]; -extern TRANSPORTENTRY * L4TABLE; -extern UCHAR ROUTEQUAL; -extern UINT BPQMsg; -extern UCHAR ExcludeList[]; - - -extern APPLCALLS APPLCALLTABLE[]; - -extern char VersionStringWithBuild[]; -extern char VersionString[]; - -extern int MAXHEARDENTRIES; -extern int MHLEN; - -extern int APPL1; -extern int PASSCMD; -extern int NUMBEROFCOMMANDS; - -extern char * ConfigBuffer; - -extern char * WL2KReportLine[]; - -extern struct CMDX COMMANDS[]; - -extern int QCOUNT, MAXBUFFS, MAXCIRCUITS, L4DEFAULTWINDOW, L4T1, CMDXLEN; -extern char CMDALIAS[ALIASLEN][NumberofAppls]; - -extern int SEMGETS; -extern int SEMRELEASES; -extern int SEMCLASHES; -extern int MINBUFFCOUNT; - -extern UCHAR BPQDirectory[]; -extern UCHAR BPQProgramDirectory[]; - -extern UCHAR WINMOR[]; -extern UCHAR PACTORCALL[]; - -extern UCHAR MCOM; -extern UCHAR MUIONLY; -extern UCHAR MTX; -extern uint64_t MMASK; - -extern UCHAR NODECALL[]; // NODES in ax.25 - -extern int L4CONNECTSOUT; -extern int L4CONNECTSIN; -extern int L4FRAMESTX; -extern int L4FRAMESRX; -extern int L4FRAMESRETRIED; -extern int OLDFRAMES; -extern int L3FRAMES; - -extern char * PortConfig[]; -extern struct SEM Semaphore; -extern UCHAR AuthorisedProgram; // Local Variable. Set if Program is on secure list - -extern int REALTIMETICKS; - -extern time_t CurrentSecs; -extern time_t lastSlowSecs; -extern time_t lastSaveSecs; - -// SNMP Variables - -extern int InOctets[64]; -extern int OutOctets[64]; - -extern BOOL CloseAllNeeded; -extern int CloseOnError; - -extern char * PortConfig[70]; -extern struct TNCINFO * TNCInfo[71]; // Records are Malloc'd - -#define MaxBPQPortNo 63 // Port 64 reserved for BBS Mon -#define MAXBPQPORTS 63 - -// IP, APRS use port ocnfig slots above the real port range - -#define IPConfigSlot MaxBPQPortNo + 1 -#define PortMapConfigSlot MaxBPQPortNo + 2 -#define APRSConfigSlot MaxBPQPortNo + 3 - - -extern char * UIUIDigi[MaxBPQPortNo + 1]; -extern char UIUIDEST[MaxBPQPortNo + 1][11]; // Dest for Beacons -extern UCHAR FN[MaxBPQPortNo + 1][256]; // Filename -extern int Interval[MaxBPQPortNo + 1]; // Beacon Interval (Mins) -extern char Message[MaxBPQPortNo + 1][1000]; // Beacon Text - -extern int MinCounter[MaxBPQPortNo + 1]; // Interval Countdown -extern BOOL SendFromFile[MaxBPQPortNo + 1]; - -extern BOOL MQTT; -extern char MQTT_HOST[80]; -extern int MQTT_PORT; -extern char MQTT_USER[80]; -extern char MQTT_PASS[80]; - -DllExport uint64_t APIENTRY GetPortFrequency(int PortNo, char * FreqStringMhz); - - -void hookL2SessionAccepted(int Port, char * remotecall, char * ourcall, struct _LINKTABLE * LINK); -void hookL2SessionDeleted(struct _LINKTABLE * LINK); -void hookL2SessionAttempt(int Port, char * ourcall, char * remotecall, struct _LINKTABLE * LINK); - -void hookL4SessionAttempt(void * STREAM, char * remotecall, char * ourcall); -void hookL4SessionAccepted(void * STREAM, char * remotecall, char * ourcall); -void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM); +// +// Prototypes for BPQ32 Node Functions +// + + +#define DllImport + +#define EXCLUDEBITS + +#define _WINSOCK_DEPRECATED_NO_WARNINGS + +#include "compatbits.h" + +#include "asmstrucs.h" + +BOOL CheckExcludeList(UCHAR * Call); + +Dll int ConvFromAX25(unsigned char * incall,unsigned char * outcall); +Dll BOOL ConvToAX25(unsigned char * callsign, unsigned char * ax25call); +DllExport BOOL ConvToAX25Ex(unsigned char * callsign, unsigned char * ax25call); +int WritetoConsoleLocal(char * buff); +VOID Consoleprintf(const char * format, ...); +VOID FreeConfig(); +int GetListeningPortsPID(int Port); + +void * InitializeExtDriver(PEXTPORTDATA PORTVEC); + +VOID PutLengthinBuffer(PDATAMESSAGE buff, USHORT datalen); // Needed for arm5 portability +int GetLengthfromBuffer(PDATAMESSAGE buff); +int IntDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, uint64_t Mask, BOOL APRS, BOOL MCTL); +int IntSetTraceOptionsEx(uint64_t mask, int mtxparam, int mcomparam, int monUIOnly); +int CountBits64(uint64_t in); + + +#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__) + +#define GetBuff() _GetBuff(__FILE__, __LINE__) +#define ReleaseBuffer(s) _ReleaseBuffer(s, __FILE__, __LINE__) +#define CheckGuardZone() _CheckGuardZone(__FILE__, __LINE__) + +#define Q_REM(s) _Q_REM(s, __FILE__, __LINE__) +#define Q_REM_NP(s) _Q_REM_NP(s, __FILE__, __LINE__) + +#define C_Q_ADD(s, b) _C_Q_ADD(s, b, __FILE__, __LINE__) + +void _CheckGuardZone(char * File, int Line); + +VOID * _Q_REM(VOID **Q, char * File, int Line); +VOID * _Q_REM_NP(VOID *Q, char * File, int Line); + +int _C_Q_ADD(VOID *Q, VOID *BUFF, char * File, int Line); + +UINT _ReleaseBuffer(VOID *BUFF, char * File, int Line); + +VOID * _GetBuff(char * File, int Line); +int _C_Q_ADD(VOID *PQ, VOID *PBUFF, char * File, int Line); + +int C_Q_COUNT(VOID *Q); + +DllExport char * APIENTRY GetApplCall(int Appl); +DllExport char * APIENTRY GetApplAlias(int Appl); +DllExport int APIENTRY FindFreeStream(); +DllExport int APIENTRY DeallocateStream(int stream); +DllExport int APIENTRY SessionState(int stream, int * state, int * change); +DllExport int APIENTRY SetAppl(int stream, int flags, int mask); +DllExport int APIENTRY GetMsg(int stream, char * msg, int * len, int * count ); +DllExport int APIENTRY GetConnectionInfo(int stream, char * callsign, + int * port, int * sesstype, int * paclen, + int * maxframe, int * l4window); + +#define LIBCONFIG_STATIC +#include "libconfig.h" + +int GetIntValue(config_setting_t * group, char * name); +BOOL GetStringValue(config_setting_t * group, char * name, char * value, int maxlen); +VOID SaveIntValue(config_setting_t * group, char * name, int value); +VOID SaveStringValue(config_setting_t * group, char * name, char * value); + +int EncryptPass(char * Pass, char * Encrypt); +VOID DecryptPass(char * Encrypt, unsigned char * Pass, unsigned int len); +Dll VOID APIENTRY CreateOneTimePassword(char * Password, char * KeyPhrase, int TimeOffset); +Dll BOOL APIENTRY CheckOneTimePassword(char * Password, char * KeyPhrase); + +DllExport int APIENTRY TXCount(int stream); +DllExport int APIENTRY RXCount(int stream); +DllExport int APIENTRY MONCount(int stream); + +VOID ReadNodes(); +int BPQTRACE(MESSAGE * Msg, BOOL APRS); + +VOID CommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer); + +VOID PostStateChange(TRANSPORTENTRY * Session); + +VOID InnerCommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer); +VOID DoTheCommand(TRANSPORTENTRY * Session); +char * MOVEANDCHECK(TRANSPORTENTRY * Session, char * Bufferptr, char * Source, int Len); +VOID DISPLAYCIRCUIT(TRANSPORTENTRY * L4, char * Buffer); +char * strlop(char * buf, char delim); +BOOL CompareCalls(UCHAR * c1, UCHAR * c2); + +VOID PostDataAvailable(TRANSPORTENTRY * Session); +int WritetoConsoleLocal(char * buff); +char * CHECKBUFFER(TRANSPORTENTRY * Session, char * Bufferptr); +VOID CLOSECURRENTSESSION(TRANSPORTENTRY * Session); + +VOID SendCommandReply(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer, int Len); + +struct PORTCONTROL * APIENTRY GetPortTableEntryFromPortNum(int portnum); + +int cCOUNT_AT_L2(struct _LINKTABLE * LINK); +VOID SENDL4CONNECT(TRANSPORTENTRY * Session); + +VOID CloseSessionPartner(TRANSPORTENTRY * Session); +int COUNTNODES(struct ROUTE * ROUTE); +int DecodeNodeName(char * NodeName, char * ptr);; +VOID DISPLAYCIRCUIT(TRANSPORTENTRY * L4, char * Buffer); +int cCOUNT_AT_L2(struct _LINKTABLE * LINK); +void * zalloc(int len); +BOOL FindDestination(UCHAR * Call, struct DEST_LIST ** REQDEST); + +BOOL ProcessConfig(); + +VOID PUT_ON_PORT_Q(struct PORTCONTROL * PORT, MESSAGE * Buffer); +VOID CLEAROUTLINK(struct _LINKTABLE * LINK); +VOID TellINP3LinkGone(struct ROUTE * Route); +VOID CLEARACTIVEROUTE(struct ROUTE * ROUTE, int Reason); + +// Reason Equates + +#define NORMALCLOSE 0 +#define RETRIEDOUT 1 +#define SETUPFAILED 2 +#define LINKLOST 3 +#define LINKSTUCK 4 + +int COUNT_AT_L2(struct _LINKTABLE * LINK); +VOID SENDIDMSG(); +VOID SENDBTMSG(); +VOID INP3TIMER(); +VOID REMOVENODE(dest_list * DEST); +BOOL ACTIVATE_DEST(struct DEST_LIST * DEST); +VOID TellINP3LinkSetupFailed(struct ROUTE * Route); +BOOL FindNeighbour(UCHAR * Call, int Port, struct ROUTE ** REQROUTE); +VOID PROCROUTES(struct DEST_LIST * DEST, struct ROUTE * ROUTE, int Qual); +BOOL L2SETUPCROSSLINK(PROUTE ROUTE); +VOID REMOVENODE(dest_list * DEST); +char * SetupNodeHeader(struct DATAMESSAGE * Buffer); +VOID L4CONNECTFAILED(TRANSPORTENTRY * L4); +int CountFramesQueuedOnSession(TRANSPORTENTRY * Session); +VOID CLEARSESSIONENTRY(TRANSPORTENTRY * Session); +VOID __cdecl Debugprintf(const char * format, ...); + +int APIENTRY Restart(); +int APIENTRY Reboot(); +int APIENTRY Reconfig(); +Dll int APIENTRY SaveNodes (); + + +struct SEM; + +void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line); +void FreeSemaphore(struct SEM * Semaphore); + +void MySetWindowText(HWND hWnd, char * Msg); + +Dll int APIENTRY SessionControl(int stream, int command, int Mask); + +HANDLE OpenCOMPort(VOID * pPort, int speed, BOOL SetDTR, BOOL SetRTS, BOOL Quiet, int Stopbits); +int ReadCOMBlock(HANDLE fd, char * Block, int MaxLength); +BOOL WriteCOMBlock(HANDLE fd, char * Block, int BytesToWrite); +VOID CloseCOMPort(HANDLE fd); + +VOID initUTF8(); +int Is8Bit(unsigned char *cpt, int len); +int WebIsUTF8(unsigned char *ptr, int len); +int IsUTF8(unsigned char *ptr, int len); +int Convert437toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); +int Convert1251toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); +int Convert1252toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF); +int TrytoGuessCode(unsigned char * Char, int Len); + + +#define CMD_TO_APPL 1 // PASS COMMAND TO APPLICATION +#define MSG_TO_USER 2 // SEND 'CONNECTED' TO USER +#define MSG_TO_APPL 4 // SEND 'CONECTED' TO APPL +#define CHECK_FOR_ESC 8 // Look for ^d (^D) to disconnect session) + +#define UI 3 +#define SABM 0x2F +#define DISC 0x43 +#define DM 0x0F +#define UA 0x63 +#define FRMR 0x87 +#define RR 1 +#define RNR 5 +#define REJ 9 + +// V2.2 Types + +#define SREJ 0x0D +#define SABME 0x6F +#define XID 0xAF +#define TEST 0xE3 + +#define SUPPORT2point2 1 + +// XID Optional Functions + +#define OPMustHave 0x02A080 // Sync TEST 16 bit FCS Extended Address +#define OPSREJ 4 +#define OPSREJMult 0x200000 +#define OPREJ 2 +#define OPMod8 0x400 +#define OPMod128 0x800 + +#define BPQHOSTSTREAMS 64 + +extern TRANSPORTENTRY * L4TABLE; +extern unsigned char NEXTID; +extern int MAXCIRCUITS; +extern int L4DEFAULTWINDOW; +extern int L4T1; +extern APPLCALLS APPLCALLTABLE[]; +extern char * APPLS; +extern int NEEDMH; +extern int RFOnly; + +extern char SESSIONHDDR[]; + +extern UCHAR NEXTID; + +extern struct ROUTE * NEIGHBOURS; +extern int MAXNEIGHBOURS; + +extern struct ROUTE * NEIGHBOURS; +extern int ROUTE_LEN; +extern int MAXNEIGHBOURS; + +extern struct DEST_LIST * DESTS; // NODE LIST +extern struct DEST_LIST * ENDDESTLIST; +extern int DEST_LIST_LEN; +extern int MAXDESTS; // MAX NODES IN SYSTEM + +extern struct _LINKTABLE * LINKS; +extern int LINK_TABLE_LEN; +extern int MAXLINKS; + + + +extern char MYCALL[]; // DB 7 DUP (0) ; NODE CALLSIGN (BIT SHIFTED) +extern char MYALIASTEXT[]; // {" " ; NODE ALIAS (KEEP TOGETHER) + +extern UCHAR MYCALLWITHALIAS[13]; +extern APPLCALLS APPLCALLTABLE[NumberofAppls]; + +extern UCHAR MYNODECALL[]; // NODE CALLSIGN (ASCII) +extern char NODECALLLOPPED[]; // NODE CALLSIGN (ASCII). Null terminated +extern UCHAR MYNETROMCALL[]; // NETROM CALLSIGN (ASCII) + +extern UCHAR NETROMCALL[]; // NETORM CALL (AX25) + +extern VOID * FREE_Q; + +extern struct PORTCONTROL * PORTTABLE; +extern int NUMBEROFPORTS; + + +extern int OBSINIT; // INITIAL OBSOLESCENCE VALUE +extern int OBSMIN; // MINIMUM TO BROADCAST +extern int L3INTERVAL; // "NODES" INTERVAL IN MINS +extern int IDINTERVAL; // "ID" BROADCAST INTERVAL +extern int BTINTERVAL; // "BT" BROADCAST INTERVAL +extern int MINQUAL; // MIN QUALITY FOR AUTOUPDATES +extern int HIDENODES; // N * COMMAND SWITCH +extern int BBSQUAL; // QUALITY OF BBS RELATIVE TO NODE + +extern int NUMBEROFBUFFERS; // PACKET BUFFERS +extern int PACLEN; //MAX PACKET SIZE + +// L2 SYSTEM TIMER RUNS AT 3 HZ + +extern int T3; // LINK VALIDATION TIMER (3 MINS) (+ a bit to reduce RR collisions) + +extern int L2KILLTIME; // IDLE LINK TIMER (16 MINS) +extern int L3LIVES; // MAX L3 HOPS +extern int L4N2; // LEVEL 4 RETRY COUNT +extern int L4LIMIT; // IDLE SESSION LIMIT - 15 MINS +extern int L4DELAY; // L4 DELAYED ACK TIMER + +extern int BBS; // INCLUDE BBS SUPPORT +extern int NODE; // INCLUDE SWITCH SUPPORT + +extern int FULL_CTEXT; // CTEXT ON ALL CONNECTS IF NZ + + +// Although externally streams are numbered 1 to 64, internally offsets are 0 - 63 + +extern BPQVECSTRUC DUMMYVEC; // Needed to force correct order of following + +extern BPQVECSTRUC BPQHOSTVECTOR[BPQHOSTSTREAMS + 5]; + +extern int NODEORDER; +extern UCHAR LINKEDFLAG; + +extern UCHAR UNPROTOCALL[80]; + + +extern char * INFOMSG; + +extern char * CTEXTMSG; +extern int CTEXTLEN; + +extern UCHAR MYALIAS[7]; // ALIAS IN AX25 FORM +extern UCHAR BBSALIAS[7]; + +extern VOID * TRACE_Q; // TRANSMITTED FRAMES TO BE TRACED + +extern char HEADERCHAR; // CHAR FOR _NODE HEADER MSGS + +extern int AUTOSAVE; // AUTO SAVE NODES ON EXIT FLAG +extern int L4APPL; // Application for BBSCALL/ALIAS connects +extern int CFLAG; // C =HOST Command + +extern VOID * IDMSG_Q; // ID/BEACONS WAITING TO BE SENT + +extern struct DATAMESSAGE BTHDDR; +extern struct _MESSAGE IDHDDR; + +extern VOID * IDMSG; + +extern int L3TIMER; // TIMER FOR 'NODES' MESSAGE +extern int IDTIMER; // TIMER FOR ID MESSAGE +extern int BTTIMER; // TIMER FOR BT MESSAGE + +extern int STATSTIME; + + +extern BOOL IPRequired; +extern int MaxHops; +extern int MAXRTT; +extern USHORT CWTABLE[]; +extern TRANSPORTENTRY * L4TABLE; +extern UCHAR ROUTEQUAL; +extern UINT BPQMsg; +extern UCHAR ExcludeList[]; + + +extern APPLCALLS APPLCALLTABLE[]; + +extern char VersionStringWithBuild[]; +extern char VersionString[]; + +extern int MAXHEARDENTRIES; +extern int MHLEN; + +extern int APPL1; +extern int PASSCMD; +extern int NUMBEROFCOMMANDS; + +extern char * ConfigBuffer; + +extern char * WL2KReportLine[]; + +extern struct CMDX COMMANDS[]; + +extern int QCOUNT, MAXBUFFS, MAXCIRCUITS, L4DEFAULTWINDOW, L4T1, CMDXLEN; +extern char CMDALIAS[ALIASLEN][NumberofAppls]; + +extern int SEMGETS; +extern int SEMRELEASES; +extern int SEMCLASHES; +extern int MINBUFFCOUNT; + +extern UCHAR BPQDirectory[]; +extern UCHAR BPQProgramDirectory[]; + +extern UCHAR WINMOR[]; +extern UCHAR PACTORCALL[]; + +extern UCHAR MCOM; +extern UCHAR MUIONLY; +extern UCHAR MTX; +extern uint64_t MMASK; + +extern UCHAR NODECALL[]; // NODES in ax.25 + +extern int L4CONNECTSOUT; +extern int L4CONNECTSIN; +extern int L4FRAMESTX; +extern int L4FRAMESRX; +extern int L4FRAMESRETRIED; +extern int OLDFRAMES; +extern int L3FRAMES; + +extern char * PortConfig[]; +extern struct SEM Semaphore; +extern UCHAR AuthorisedProgram; // Local Variable. Set if Program is on secure list + +extern int REALTIMETICKS; + +extern time_t CurrentSecs; +extern time_t lastSlowSecs; +extern time_t lastSaveSecs; + +// SNMP Variables + +extern int InOctets[64]; +extern int OutOctets[64]; + +extern BOOL CloseAllNeeded; +extern int CloseOnError; + +extern char * PortConfig[70]; +extern struct TNCINFO * TNCInfo[71]; // Records are Malloc'd + +#define MaxBPQPortNo 63 // Port 64 reserved for BBS Mon +#define MAXBPQPORTS 63 + +// IP, APRS use port ocnfig slots above the real port range + +#define IPConfigSlot MaxBPQPortNo + 1 +#define PortMapConfigSlot MaxBPQPortNo + 2 +#define APRSConfigSlot MaxBPQPortNo + 3 + + +extern char * UIUIDigi[MaxBPQPortNo + 1]; +extern char UIUIDEST[MaxBPQPortNo + 1][11]; // Dest for Beacons +extern UCHAR FN[MaxBPQPortNo + 1][256]; // Filename +extern int Interval[MaxBPQPortNo + 1]; // Beacon Interval (Mins) +extern char Message[MaxBPQPortNo + 1][1000]; // Beacon Text + +extern int MinCounter[MaxBPQPortNo + 1]; // Interval Countdown +extern BOOL SendFromFile[MaxBPQPortNo + 1]; + +extern BOOL MQTT; +extern char MQTT_HOST[80]; +extern int MQTT_PORT; +extern char MQTT_USER[80]; +extern char MQTT_PASS[80]; + +DllExport uint64_t APIENTRY GetPortFrequency(int PortNo, char * FreqStringMhz); + + +void hookL2SessionAccepted(int Port, char * remotecall, char * ourcall, struct _LINKTABLE * LINK); +void hookL2SessionDeleted(struct _LINKTABLE * LINK); +void hookL2SessionAttempt(int Port, char * ourcall, char * remotecall, struct _LINKTABLE * LINK); + +void hookL4SessionAttempt(void * STREAM, char * remotecall, char * ourcall); +void hookL4SessionAccepted(void * STREAM, char * remotecall, char * ourcall); +void hookL4SessionDeleted(struct TNCINFO * TNC, void * STREAM); diff --git a/config.c b/config.c index 85a55cd..02b8d4a 100644 --- a/config.c +++ b/config.c @@ -119,7 +119,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #include #include @@ -512,7 +512,6 @@ BOOL ProcessConfig() if ((fp1 = fopen(inputname,"r")) == NULL) { Consoleprintf("Could not open file %s Error code %d", inputname, errno); - return FALSE; } @@ -1532,7 +1531,7 @@ int dotext(char * val, char * key_word, int max) if (len > max) { - Consoleprintf("Text too long: %s\r\n",key_word); + Consoleprintf("Text too long: %s (max %d\r\n",key_word, max); return(0); } diff --git a/kiss.c b/kiss.c index ccfc297..b511296 100644 --- a/kiss.c +++ b/kiss.c @@ -77,7 +77,7 @@ int i2c_smbus_read_byte() #endif -#include "CHeaders.h" +#include "cheaders.h" #include "mqtt.h" #include "kiss.h" diff --git a/linether.c b/linether.c index 806de46..fb3410c 100644 --- a/linether.c +++ b/linether.c @@ -26,7 +26,7 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses #include -#include "CHeaders.h" +#include "cheaders.h" #include #include diff --git a/lzhuf32.c b/lzhuf32.c index a6828ca..f1ef0a4 100644 --- a/lzhuf32.c +++ b/lzhuf32.c @@ -764,14 +764,14 @@ BOOL CheckifPacket(char * Via) return TRUE; // Packet // ptr1 is last element. If a valid continent, it is a packet message - + // should really accept .WW on end as it is valid if (FindContinent(ptr1)) return TRUE; // Packet if (FindCountry(ptr1)) return TRUE; // Packet - if ((_stricmp(ptr1, "MARS") == 0) || (_stricmp(ptr1, "USA") == 0)) // MARS used both + if ((_stricmp(ptr1, "MARS") == 0) || (_stricmp(ptr1, "USA") == 0) || (_stricmp(ptr1, "WW") == 0)) // MARS used both MARS and USA return TRUE; // Packet return FALSE; diff --git a/mailapi.c b/mailapi.c index 690d2b4..2aa1b9b 100644 --- a/mailapi.c +++ b/mailapi.c @@ -7,7 +7,7 @@ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers //#include -#include "CHeaders.h" +#include "cheaders.h" #include #include "bpqmail.h" #include "httpconnectioninfo.h" diff --git a/makefile b/makefile index 58534d7..7f870ff 100644 --- a/makefile +++ b/makefile @@ -13,21 +13,21 @@ OBJS = pngwtran.o pngrtran.o pngset.o pngrio.o pngwio.o pngtrans.o pngrutil.o pn MailCommands.o MailDataDefs.o LinBPQ.o MailRouting.o MailTCP.o MBLRoutines.o md5.o Moncode.o \ NNTPRoutines.o RigControl.o TelnetV6.o WINMOR.o TNCCode.o UZ7HODrv.o WPRoutines.o \ SCSTrackeMulti.o SCSPactor.o SCSTracker.o HanksRT.o UIRoutines.o AGWAPI.o AGWMoncode.o \ - DRATS.o FreeDATA.o base64.o Events.o nodeapi.o mailapi.o mqtt.o + DRATS.o FreeDATA.o base64.o Events.o nodeapi.o mailapi.o mqtt.o RHP.o # Configuration: CC = gcc -all: CFLAGS = -DLINBPQ -MMD -g -fcommon +all: CFLAGS = -DLINBPQ -MMD -g -rdynamic -fcommon all: LDFLAGS = -l:libpaho-mqtt3a.a -l:libjansson.a all: linbpq -nomqtt: CFLAGS = -DLINBPQ -MMD -fcommon -g -DNOMQTT +nomqtt: CFLAGS = -DLINBPQ -MMD -fcommon -g -rdynamic -DNOMQTT nomqtt: linbpq -noi2c: CFLAGS = -DLINBPQ -MMD -DNOI2C -g -fcommon +noi2c: CFLAGS = -DLINBPQ -MMD -DNOI2C -g -rdynamic -fcommon noi2c: linbpq diff --git a/makefile~ b/makefile~ new file mode 100644 index 0000000..58534d7 --- /dev/null +++ b/makefile~ @@ -0,0 +1,43 @@ +# LinBPQ Makefile + +# To exclude i2c support run make noi2c + +OBJS = pngwtran.o pngrtran.o pngset.o pngrio.o pngwio.o pngtrans.o pngrutil.o pngwutil.o\ + pngread.o pngwrite.o png.o pngerror.o pngget.o pngmem.o APRSIconData.o AISCommon.o\ + upnp.o APRSStdPages.o HSMODEM.o WinRPR.o KISSHF.o TNCEmulators.o bpqhdlc.o SerialPort.o\ + adif.o WebMail.o utf8Routines.o VARA.o LzFind.o Alloc.o LzmaDec.o LzmaEnc.o LzmaLib.o \ + Multicast.o ARDOP.o IPCode.o FLDigi.o linether.o CMSAuth.o APRSCode.o BPQtoAGW.o KAMPactor.o\ + AEAPactor.o HALDriver.o MULTIPSK.o BBSHTMLConfig.o ChatHTMLConfig.o BBSUtilities.o bpqaxip.o\ + BPQINP3.o BPQNRR.o cMain.o Cmd.o CommonCode.o HTMLCommonCode.o compatbits.o config.o datadefs.o \ + FBBRoutines.o HFCommon.o Housekeeping.o HTTPcode.o kiss.o L2Code.o L3Code.o L4Code.o lzhuf32.o \ + MailCommands.o MailDataDefs.o LinBPQ.o MailRouting.o MailTCP.o MBLRoutines.o md5.o Moncode.o \ + NNTPRoutines.o RigControl.o TelnetV6.o WINMOR.o TNCCode.o UZ7HODrv.o WPRoutines.o \ + SCSTrackeMulti.o SCSPactor.o SCSTracker.o HanksRT.o UIRoutines.o AGWAPI.o AGWMoncode.o \ + DRATS.o FreeDATA.o base64.o Events.o nodeapi.o mailapi.o mqtt.o + +# Configuration: + +CC = gcc + +all: CFLAGS = -DLINBPQ -MMD -g -fcommon +all: LDFLAGS = -l:libpaho-mqtt3a.a -l:libjansson.a +all: linbpq + + +nomqtt: CFLAGS = -DLINBPQ -MMD -fcommon -g -DNOMQTT +nomqtt: linbpq + +noi2c: CFLAGS = -DLINBPQ -MMD -DNOI2C -g -fcommon +noi2c: linbpq + + +linbpq: $(OBJS) + gcc $(OBJS) -Xlinker -Map=output.map -l:libminiupnpc.a -lrt -lm -lz $(LDFLAGS) -lpthread -lconfig -lpcap -o linbpq + sudo setcap "CAP_NET_ADMIN=ep CAP_NET_RAW=ep CAP_NET_BIND_SERVICE=ep" linbpq + +-include *.d + +clean : + rm *.d + rm linbpq $(OBJS) + diff --git a/mqtt.c b/mqtt.c index 4f7571f..ff1c716 100644 --- a/mqtt.c +++ b/mqtt.c @@ -8,7 +8,7 @@ #include #endif -#include "CHeaders.h" +#include "cheaders.h" #include "asmstrucs.h" #include "mqtt.h" diff --git a/nodeapi-skigdebian.c b/nodeapi-skigdebian.c new file mode 100644 index 0000000..a675a9e --- /dev/null +++ b/nodeapi-skigdebian.c @@ -0,0 +1,858 @@ +// basic JASON API to BPQ Node + +// Authentication is via Telnet USER records. + + +#define _CRT_SECURE_NO_DEPRECATE + +#include "cheaders.h" +#include +#include "tncinfo.h" +#include "asmstrucs.h" +#include "kiss.h" + +// Constants +#define TOKEN_SIZE 32 // Length of the authentication token +#define TOKEN_EXPIRATION 7200 // Token expiration time in seconds (2 hours) + +// Token data structure +typedef struct Token { + char token[TOKEN_SIZE + 1]; + time_t expiration_time; + struct Token* next; +} Token; + +typedef struct API +{ + char *URL; + int URLLen; + int (* APIRoutine)(char * response, char * token, char * param); + int Auth; +} API; + +// Auth defines + +#define AuthNone 0 +#define AuthUser 1 +#define Auth BBSUser 2 +#define AuthSysop 4 + +// Function prototypes +void handle_request(SOCKET client_socket, char * request, char * response); +int verify_token(const char* token); +void remove_expired_tokens(); +char* fetch_data(const char* endpoint); +int request_token(char * response); +int send_http_response(char * response, const char* msg); +int create_json_response(char * response, char* access_token, int expires_in, char* scope); +void add_token_to_list(Token* token); + +Token* find_token(const char* token); +Token* generate_token(); + +int sendPortList(char * response, char * token, char * Rest); +int sendNodeList(char * response, char * token, char * Rest); +int sendUserList(char * response, char * token, char * Rest); +int sendInfo(char * response, char * token, char * Rest); +int sendLinks(char * response, char * token, char * Rest); +int sendPortMHList(char * response, char * token, char * Rest); +int sendWhatsPacState(char * response, char * token, char * param); +int sendWhatsPacConfig(char * response, char * token, char * param); + +void BuildPortMH(char * MHJSON, struct PORTCONTROL * PORT); +DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot); + +// Token list +Token* token_list = NULL; + + +struct API APIList[] = +{ + "/api/ports", 10, sendPortList, 0, + "/api/nodes", 10, sendNodeList, 0, + "/api/info", 9, sendInfo, 0, + "/api/links", 10, sendLinks, 0, + "/api/users", 10, sendUserList, 0, + "/api/mheard", 11, sendPortMHList, 0, + "/api/v1/config", 14, sendWhatsPacConfig, 0, + "/api/v1/state", 13, sendWhatsPacState, 0 +}; + +int APICount = sizeof(APIList) / sizeof(struct API); + +extern int HTTPPort; + + +int xx() +{ + while (1) + { + // Remove expired tokens + remove_expired_tokens(); + + // Handle the client request + // handle_request(); + } + return 0; +} + +int APIProcessHTTPMessage(char * response, char * Method, char * URL, char * request, BOOL LOCAL, BOOL COOKIE) +{ + const char * auth_header = "Authorization: Bearer "; + char * token_begin = strstr(request, auth_header); + char token[TOKEN_SIZE + 1]= ""; + int Flags = 0, n; + + // Node Flags isn't currently used + + char * Tok; + char * param; + + if (token_begin) + { + // Using Auth Header + + // Extract the token from the request (assuming it's present in the request headers) + + if (token_begin == NULL) + { + Debugprintf("Invalid request: No authentication token provided.\n"); + return send_http_response(response, "403 (Forbidden)"); + } + + token_begin += strlen(auth_header); // Move to the beginning of the token + strncpy(token, token_begin, TOKEN_SIZE); + token[TOKEN_SIZE] = '\0'; // Null-terminate the token + + param = strlop(URL, '?'); + } + else + { + // There may be a token as first param, but if auth not needed may be misisng + + Tok = strlop(URL, '?'); + param = strlop(Tok, '&'); + + if (Tok && strlen(Tok) == TOKEN_SIZE) + { + // assume auth token + + strcpy(token, Tok); + } + else param = Tok; + } + + remove_expired_tokens(); // Tidy up + + // Check if the request is for token generation + + if (strcmp(Method, "OPTIONS") == 0) + { + // CORS Request + + char Resp[] = + "HTTP/1.1 200 OK\r\n" + "Access-Control-Allow-Origin: *\r\n" + "Access-Control-Allow-Methods: POST, GET, OPTIONS\r\n" + "Access-Control-Allow-Headers: authorization"; + + return send_http_response(response, Resp); + } + + if (strcmp(Method, "GET") != 0) + return send_http_response(response, "403 (Bad Method)"); + + if (_stricmp(URL, "/api/request_token") == 0) + return request_token(response); + +/* +if (token[0] == 0) + { + // Extract the token from the request (assuming it's present in the request headers) + if (token_begin == NULL) + { + Debugprintf("Invalid request: No authentication token provided.\n"); + return send_http_response(response, "403 (Forbidden)"); + } + token_begin += strlen(auth_header); // Move to the beginning of the token + strncpy(token, token_begin, TOKEN_SIZE); + token[TOKEN_SIZE] = '\0'; // Null-terminate the token + } + + // Verify the token + if (!verify_token(token)) + { + Debugprintf("Invalid authentication token.\n"); + return send_http_response(response, "401 Unauthorized"); + } + + */ + + // Determine the requested API endpoint + + for (n = 0; n < APICount; n++) + { + struct API * APIEntry; + char * rest; + + APIEntry = &APIList[n]; + + if (_memicmp(URL, APIEntry->URL, APIEntry->URLLen) == 0) + { + rest = &request[4 + APIEntry->URLLen]; // Anything following? + + if (rest[0] == ' ' || rest[0] == '/' || rest[0] == '?') + return APIEntry->APIRoutine(response, token, rest); + } + + } + + return send_http_response(response, "401 Invalid API Call"); +} + +int request_token(char * response) +{ + Token * token = generate_token(); + char scope[] = "create"; + + printf("Token generated: %s\n", token->token); + + sprintf(response, "{\"access_token\":\"%s\", \"expires_at\":%ld,\"scope\":\"create\"}\r\n", + token->token, token->expiration_time); + + return strlen(response); +} + +Token * generate_token() +{ + // Generate a random authentication token + + int i; + + Token * token = malloc(sizeof(Token)); + for (i = 0; i < TOKEN_SIZE; i++) + { + token->token[i] = 'A' + rand() % 26; // Random uppercase alphabet character + } + token->token[TOKEN_SIZE] = '\0'; // Null-terminate the token + token->expiration_time = time(NULL) + TOKEN_EXPIRATION; // Set token expiration time + add_token_to_list(token); + return token; +} + +// Function to add the token to the token_list + +void add_token_to_list(Token* token) +{ + if (token_list == NULL) + { + token_list = token; + token->next = NULL; + } + else + { + Token* current = token_list; + + while (current->next != NULL) + current = current->next; + + current->next = token; + token->next = NULL; + } +} + +int verify_token(const char* token) +{ + // Find the token in the token list + Token * existing_token = find_token(token); + + if (existing_token != NULL) + { + // Check if the token has expired + time_t current_time = time(NULL); + if (current_time > existing_token->expiration_time) + { + // Token has expired, remove it from the token list + remove_expired_tokens(); + return 0; + } + // Token is valid + return 1; + } + + // Token doesn't exist in the token list + return 0; +} + +void remove_expired_tokens() +{ + time_t current_time = time(NULL); + Token* current_token = token_list; + Token* prev_token = NULL; + Token* next_token; + + while (current_token != NULL) + { + if (current_time > current_token->expiration_time) + { + // Token has expired, remove it from the token list + if (prev_token == NULL) + { + token_list = current_token->next; + } else { + prev_token->next = current_token->next; + } + next_token = current_token->next; + free(current_token); + current_token = next_token; + } else { + prev_token = current_token; + current_token = current_token->next; + } + } +} + +Token * find_token(const char* token) +{ + Token* current_token = token_list; + while (current_token != NULL) + { + if (strcmp(current_token->token, token) == 0) + { + return current_token; + } + current_token = current_token->next; + } + return NULL; +} + +int send_http_response(char * response, const char* msg) +{ + return sprintf(response, "HTTP/1.1 %s\r\nContent-Length: 0\r\nConnection: close\r\n\r\n", msg); +} + +/* +{ +"access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3", +"expires_in":3600, +"scope":"create" +} +*/ + +/* +{"ports":[ +{"ID":"My Port", "Driver":"KISS", "Number":2, "State":"Active"), +{ ...}, +{...} +]} +*/ + +extern int MasterPort[MAXBPQPORTS+1]; // Pointer to first BPQ port for a specific MPSK or UZ7HO host + +int sendPortList(char * response, char * token, char * param) +{ + char * Array = 0; + int ArrayLen = 0; + int ArrayPtr = 0; + + struct _EXTPORTDATA * ExtPort; + struct PORTCONTROL * Port; + struct PORTCONTROL * SAVEPORT; + int PortNo; + + int count; + char DLL[20]; + char Status[32]="Unknown"; + char ID[33]; + char * ptr; + + ArrayPtr += sprintf(&response[ArrayPtr], "{\"ports\":[\r\n"); + + for (count = 1; count <= NUMBEROFPORTS; count++) + { + Port = GetPortTableEntryFromSlot(count); + ExtPort = (struct _EXTPORTDATA *)Port; + PortNo = Port->PORTNUMBER; + + if (Port->PORTTYPE == 0x10) + { + strcpy(DLL, ExtPort->PORT_DLL_NAME); + strlop(DLL, '.'); + strlop(DLL, ' '); + } + else if (Port->PORTTYPE == 0) + strcpy(DLL, "ASYNC"); + + else if (Port->PORTTYPE == 22) + strcpy(DLL, "I2C"); + + else if (Port->PORTTYPE == 14) + strcpy(DLL, "INTERNAL"); + + else if (Port->PORTTYPE > 0 && Port->PORTTYPE < 14) + strcpy(DLL, "HDLC"); + + + if (Port->PortStopped) + { + strcpy(Status, "Stopped"); + + } + else + { + if (Port->PORTTYPE == 0) + { + struct KISSINFO * KISS = (struct KISSINFO *)Port; + NPASYINFO KPort; + + SAVEPORT = Port; + + if (KISS->FIRSTPORT && KISS->FIRSTPORT != KISS) + { + // Not first port on device + + Port = (struct PORTCONTROL *)KISS->FIRSTPORT; + KPort = KISSInfo[PortNo]; + } + + KPort = KISSInfo[PortNo]; + + if (KPort) + { + // KISS like - see if connected + + if (Port->PORTIPADDR.s_addr || Port->KISSSLAVE) + { + // KISS over UDP or TCP + + if (Port->KISSTCP) + { + if (KPort->Connected) + strcpy(Status, "Open "); + else + if (Port->KISSSLAVE) + strcpy(Status, "Listen"); + else + strcpy(Status, "Closed"); + } + else + strcpy(Status, "UDP"); + } + else + if (KPort->idComDev) // Serial port Open + strcpy(Status, "Open "); + else + strcpy(Status, "Closed"); + + + Port = SAVEPORT; + } + } + + if (Port->PORTTYPE == 14) // Loopback + strcpy(Status, "Open "); + + else if (Port->PORTTYPE == 16) // External + { + if (Port->PROTOCOL == 10) // 'HF' Port + { + struct TNCINFO * TNC = TNCInfo[PortNo]; + + if (TNC) + { + switch (TNC->Hardware) // Hardware Type + { + case H_SCS: + case H_KAM: + case H_AEA: + case H_HAL: + case H_TRK: + case H_SERIAL: + + // Serial + + if (TNC->hDevice) + strcpy(Status, "Open "); + else + strcpy(Status, "Closed"); + + break; + + case H_UZ7HO: + + if (TNCInfo[MasterPort[PortNo]]->CONNECTED) + strcpy(Status, "Open "); + else + strcpy(Status, "Closed"); + + break; + + case H_WINMOR: + case H_V4: + + case H_MPSK: + case H_FLDIGI: + case H_UIARQ: + case H_ARDOP: + case H_VARA: + case H_KISSHF: + case H_WINRPR: + case H_FREEDATA: + + // TCP + + if (TNC->CONNECTED) + { + if (TNC->Streams[0].Attached) + strcpy(Status, "In Use"); + else + strcpy(Status, "Open "); + } + else + strcpy(Status, "Closed"); + + break; + + case H_TELNET: + + strcpy(Status, "Open "); + } + } + } + else + { + // External but not HF - AXIP, BPQETHER VKISS, ?? + + struct _EXTPORTDATA * EXTPORT = (struct _EXTPORTDATA *)Port; + + strcpy(Status, "Open "); + } + } + } + + strlop(Status, ' '); + strcpy(ID, Port->PORTDESCRIPTION); + ptr = &ID[29]; + while (*(ptr) == ' ') + { + *(ptr--) = 0; + } + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"ID\":\"%s\", \"Driver\":\"%s\", \"Number\":%d,\"State\":\"%s\"},\r\n", + ID, DLL, Port->PORTNUMBER, Status); + } + + ArrayPtr -= 3; // remove trailing comma + ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}\r\n"); + + return ArrayPtr; +} + +/* +{"Nodes":[ +{"Call":"xx", "Alias":"xx", "Nbour1 ":"xx", "Quality":192), +{ ...}, +{...} +]} +*/ + +extern int MaxNodes; +extern struct DEST_LIST * DESTS; // NODE LIST +extern int DEST_LIST_LEN; + + +int sendNodeList(char * response, char * token, char * param) +{ + int ArrayPtr = 0; + + int count, len, i; + char Normcall[10], Portcall[10]; + char Alias[7]; + struct DEST_LIST * Dests = DESTS ; + // struct ROUTE * Routes; + + Dests = DESTS; + MaxNodes = MAXDESTS; + + ArrayPtr += sprintf(&response[ArrayPtr], "{\"nodes\":[\r\n"); + + Dests-=1; + + for (count = 0; count < MaxNodes; count++) + { + Dests+=1; + + if (Dests->DEST_CALL[0] == 0) + continue; + + len = ConvFromAX25(Dests->DEST_CALL, Normcall); + Normcall[len] = 0; + + memcpy(Alias, Dests->DEST_ALIAS, 6); + + Alias[6]=0; + + for (i=0;i<6;i++) + { + if (Alias[i] == ' ') + Alias[i] = 0; + } + + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\":\"%s\", \"Alias\":\"%s\", \"Routes\":[", Normcall, Alias); + + + // Add an array with up to 6 objects (3 NR + 3 INP3 Neighbours + + if (Dests->NRROUTE[0].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[0].ROUT_NEIGHBOUR->INP3Node == 0) + { + len = ConvFromAX25(Dests->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall); + Portcall[len] = 0; + + ArrayPtr += sprintf(&response[ArrayPtr], "{\"Call\":\"%s\", \"Port\":%d, \"Quality\":%d},", + Portcall, Dests->NRROUTE[0].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, Dests->NRROUTE[0].ROUT_QUALITY); + + + // if (Dests->NRROUTE[0].ROUT_OBSCOUNT > 127) + // { + // len=sprintf(&line[cursor],"! "); + // cursor+=len; + // } + + + if (Dests->NRROUTE[1].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[1].ROUT_NEIGHBOUR->INP3Node == 0) + { + len=ConvFromAX25(Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall); + Portcall[len]=0; + + + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\":\"%s\", \"Port\":%d, \"Quality\":%d},", + Portcall, Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, Dests->NRROUTE[1].ROUT_QUALITY); + //if (Dests->NRROUTE[1].ROUT_OBSCOUNT > 127) + //{ + //len=sprintf(&line[cursor],"! "); + //cursor+=len; + //} + + } + + if (Dests->NRROUTE[2].ROUT_NEIGHBOUR != 0 && Dests->NRROUTE[2].ROUT_NEIGHBOUR->INP3Node == 0) + { + len=ConvFromAX25(Dests->NRROUTE[2].ROUT_NEIGHBOUR->NEIGHBOUR_CALL,Portcall); + Portcall[len]=0; + + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\":\"%s\", \"Port\":%d, \"Quality\":%d},", + Portcall, Dests->NRROUTE[1].ROUT_NEIGHBOUR->NEIGHBOUR_PORT, Dests->NRROUTE[1].ROUT_QUALITY); + + //if (Dests->NRROUTE[2].ROUT_OBSCOUNT > 127) + //{ + //len=sprintf(&line[cursor],"! "); + //cursor+=len; + + } + ArrayPtr -= 1; // remove comma + } + + ArrayPtr += sprintf(&response[ArrayPtr], "]},\r\n"); + } + + ArrayPtr -= 3; // remove comma + ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}"); + + return ArrayPtr; +} + + +int sendUserList(char * response, char * token, char * param) +{ + int ArrayPtr = 0; + 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]; + char Normcall[10]; + int len; + + ArrayPtr += sprintf(&response[ArrayPtr], "{\"users\":[\r\n"); + + while (n--) + { + if (L4->L4USER[0]) + { + RHS[0] = MID[0] = 0; + + len = ConvFromAX25(L4->L4USER, Normcall); + Normcall[len] = 0; + + ArrayPtr += sprintf(&response[ArrayPtr], " {\"Call\": \"%s\"},\r\n", Normcall); + L4++; + } + } + + if (ArrayPtr == 12) //empty list + { + ArrayPtr -=2; + ArrayPtr += sprintf(&response[ArrayPtr], "]}\r\n"); + } + else + { + ArrayPtr -= 3; // remove trailing comma + ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}\r\n"); + } + return ArrayPtr; +} + +extern char MYALIASLOPPED[]; +extern char TextVerstring[]; +extern char LOCATOR[]; + +int sendInfo(char * response, char * token, char * param) +{ + char call[10]; + + memcpy(call, MYNODECALL, 10); + strlop(call, ' '); + + sprintf(response, "{\"info\":{\"NodeCall\":\"%s\", \"Alias\":\"%s\", \"Locator\":\"%s\", \"Version\":\"%s\"}}\r\n", + call, MYALIASLOPPED, LOCATOR, TextVerstring); + + return strlen(response); +} + +int sendLinks(char * response, char * token, char * param) +{ + struct _LINKTABLE * Links = LINKS; + int MaxLinks = MAXLINKS; + int count; + char Normcall1[10]; + char Normcall2[10]; + char State[12] = "", Type[12] = "Uplink"; + int axState; + int cctType; + int ReplyLen = 0; + ReplyLen += sprintf(&response[ReplyLen],"{\"links\":[\r\n"); + + for (count=0; countLINKCALL[0] != 0) + { + int len = ConvFromAX25(Links->LINKCALL, Normcall1); + Normcall1[len] = 0; + + len = ConvFromAX25(Links->OURCALL, Normcall2); + Normcall2[len] = 0; + + + axState = Links->L2STATE; + + if (axState == 2) + strcpy(State, "Connecting"); + else if (axState == 3) + strcpy(State, "FRMR"); + else if (axState == 4) + strcpy(State, "Closing"); + else if (axState == 5) + strcpy(State, "Active"); + else if (axState == 6) + strcpy(State, "REJ Sent"); + + cctType = Links->LINKTYPE; + + if (cctType == 1) + strcpy(Type, "Uplink"); + else if (cctType == 2) + strcpy(Type, "Downlink"); + else if (cctType == 3) + strcpy(Type, "Node-Node"); + + + + ReplyLen += sprintf(&response[ReplyLen], "{\"farCall\": \"%s\",\"ourCall\": \"%s\", \"port\": \"%d\", \"state\": \"%s\", \"linkType\": \"%s\", \"ax25Version\": \"%d\"},\r\n", + Normcall1, Normcall2, Links->LINKPORT->PORTNUMBER, + State, Type, 2 - Links->VER1FLAG ); + Links+=1; + } + } + + if (ReplyLen < 13) + ReplyLen -= 2; // no links + else + ReplyLen -= 3; // remove trailing comma + + ReplyLen+= sprintf(&response[ReplyLen], "\r\n]}\r\n"); + + return ReplyLen; +} + +int sendPortMHList(char * response, char * token, char * param) +{ + struct PORTCONTROL * PORTVEC ; + int n; + int port = 0; + + if (param[0] = '?' || param[0] == '/') + port = atoi(¶m[1]); + + PORTVEC = GetPortTableEntryFromPortNum(port); + response[0] = 0; + + if (PORTVEC == 0) + return send_http_response(response, "401 Invalid API Call"); + + n = sprintf(response,"{\"mheard\":[\r\n"); + + BuildPortMH(&response[n], PORTVEC ); + + if (response[n] == 0) // No entries + { + response[strlen(response) - 2] = '\0'; // remove \r\n + strcat(response, "]}\r\n"); + } + else + { + response[strlen(response)-3 ] = '\0'; // remove ,\r\n + strcat(response, "\r\n]}\r\n"); +// printf("MH for port %d:\r\n%s\r\n", PORTVEC->PORTNUMBER, response); + } + return strlen(response); +} + +// WhatsPac configuration interface +// WhatsPac also uses Paula's Remote Host Protocol (RHP). This is in a separate module + +extern int WhatsPacConfigured; + + +int sendWhatsPacState(char * response, char * token, char * param) +{ + if (WhatsPacConfigured) + sprintf(response, "{\"configured\": true}\r\n"); + else + sprintf(response, "{\"configured\": false}\r\n"); + + return strlen(response); +} + + +int sendWhatsPacConfig(char * response, char * token, char * param) +{ + char Template[] = + "{\"MODE\": 0," + "\"RHPPORT\": \"%d\"," + "\"AGWPORT\": \"7000\"," + "\"INTERFACES\": [{\"INTERFACE\": 1,\"PROTOCOL\": \"KISS\",\"TYPE\": \"TCP\",\"IOADDR\": \"127.0.0.1\",\"INTNUM\": 8100}]," + "\"PORTS\": [{\"PORT\": 1,\"ID\": \"RHPPORT\", \"INTERFACENUM\": 1}]}"; + + sprintf(response, Template, HTTPPort); + + return strlen(response); +} + + + + diff --git a/nodeapi.c b/nodeapi.c index 0d2fa49..592d92a 100644 --- a/nodeapi.c +++ b/nodeapi.c @@ -5,7 +5,7 @@ #define _CRT_SECURE_NO_DEPRECATE -#include "CHeaders.h" +#include "cheaders.h" #include #include "tncinfo.h" #include "asmstrucs.h" @@ -56,6 +56,8 @@ int sendUserList(char * response, char * token, char * Rest); int sendInfo(char * response, char * token, char * Rest); int sendLinks(char * response, char * token, char * Rest); int sendPortMHList(char * response, char * token, char * Rest); +int sendWhatsPacState(char * response, char * token, char * param); +int sendWhatsPacConfig(char * response, char * token, char * param); void BuildPortMH(char * MHJSON, struct PORTCONTROL * PORT); DllExport struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot); @@ -71,11 +73,14 @@ struct API APIList[] = "/api/info", 9, sendInfo, 0, "/api/links", 10, sendLinks, 0, "/api/users", 10, sendUserList, 0, - "/api/mheard", 11, sendPortMHList, 0 + "/api/mheard", 11, sendPortMHList, 0, + "/api/v1/config", 14, sendWhatsPacConfig, 0, + "/api/v1/state", 13, sendWhatsPacState, 0 }; int APICount = sizeof(APIList) / sizeof(struct API); +extern int HTTPPort; int xx() @@ -817,6 +822,37 @@ int sendPortMHList(char * response, char * token, char * param) return strlen(response); } +// WhatsPac configuration interface +// WhatsPac also uses Paula's Remote Host Protocol (RHP). This is in a separate module + +extern int WhatsPacConfigured; + + +int sendWhatsPacState(char * response, char * token, char * param) +{ + if (WhatsPacConfigured) + sprintf(response, "{\"configured\": true}\r\n"); + else + sprintf(response, "{\"configured\": false}\r\n"); + + return strlen(response); +} + + +int sendWhatsPacConfig(char * response, char * token, char * param) +{ + char Template[] = + "{\"MODE\": 0," + "\"RHPPORT\": \"%d\"," + "\"AGWPORT\": \"7000\"," + "\"INTERFACES\": [{\"INTERFACE\": 1,\"PROTOCOL\": \"KISS\",\"TYPE\": \"TCP\",\"IOADDR\": \"127.0.0.1\",\"INTNUM\": 8100}]," + "\"PORTS\": [{\"PORT\": 1,\"ID\": \"RHPPORT\", \"INTERFACENUM\": 1}]}"; + + sprintf(response, Template, HTTPPort); + + return strlen(response); +} + diff --git a/pibits.c b/pibits.c index b839131..fdefcf9 100644 --- a/pibits.c +++ b/pibits.c @@ -17,7 +17,7 @@ You should have received a copy of the GNU General Public License along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses */ -#include "CHeaders.h" +#include "cheaders.h" #include "tncinfo.h"