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