linbpq/Bpq32.c

6733 lines
173 KiB
C
Raw Permalink Blame History

/*
Copyright 2001-2022 John Wiseman G8BPQ
This file is part of LinBPQ/BPQ32.
LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
LinBPQ/BPQ32 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
*/
//
// 409l Oct 2001 Fix l3timeout for KISS
//
// 409m Oct 2001 Fix Crossband Digi
//
// 409n May 2002 Change error handling on load ext DLL
// 409p March 2005 Allow Multidigit COM Ports (kiss.c)
// 409r August 2005 Treat NULL string in Registry as use current directory
// Allow shutdown to close BPQ Applications
// 409s October 2005 Add DLL:Export entries to API for BPQTNC2
// 409t January 2006
//
// Add API for Perl "GetPerlMsg"
// Add API for BPQ1632 "GETBPQAPI" - returns address of Assembler API routine
// Add Registry Entry "BPQ Directory". If present, overrides "Config File Location"
// Add New API "GetBPQDirectory" - Returns location of config file
// Add New API "ChangeSessionCallsign" - equivalent to "*** linked to" command
// Rename BPQNODES to BPQNODES.dat
// New API "GetAttachedProcesses" - returns number of processes connected.
// Warn if user trys to close Console Window.
// Add Debug entries to record Process Attach/Detach
// Fix recovery following closure of first process
// 409t Beta 2 February 2006
//
// Add API Entry "GetPortNumber"
//
// 409u February 2006
//
// Fix crash if allocate/deallocate called with stream=0
// Add API to ch
// Display config file path
// Fix saving of Locked Node flag
// Added SAVENODES SYSOP command
//
// 409u 2 March 2006
//
// Fix SetupBPQDirectory
// Add CopyBPQDirectory (for Basic Programs)
//
// 409u 3 March 2006
//
// Release streams on DLL unload
// 409v October 2006
//
// Support Minimize to Tray for all BPQ progams
// Implement L4 application callsigns
// 410 November 2006
//
// Modified to compile with C++ 2005 Express Edition
// Make MCOM MTX MMASK local variables
//
// 410a January 2007
//
// Add program name to Attach-Detach messages
// Attempt to detect processes which have died
// Fix bug in NETROM and IFrame decode which would cause crash if frame was corrupt
// Add BCALL - origin call for Beacons
// Fix KISS ACKMODE ACK processing
//
// 410b November 2007
//
// Allow CTEXT of up to 510, and enforce PACLEN, fragmenting if necessary
// 410c December 2007
// Fix problem with NT introduced in V410a
// Display location of DLL on Console
// 410d January 2008
// Fix crash in DLL Init caused by long path to program
// Invoke Appl2 alias on C command (if enabled)
// Allow C command to be disabled
// Remove debug trap in GETRAWFRAME
// Validate Alias of directly connected node, mainly for KPC3 DISABL Problem
// Move Port statup code out of DLLInit (mainly for perl)
// Changes to allow Load/Unload of bpq32.dll by appl
// CloseBPQ32 API added
// Ext Driver Close routes called
// Changes to release Mutex
// 410e May 2008
// Fix missing SSID on last call of UNPROTO string (CONVTOAX25 in main.asm)
// Fix VCOM Driver (RX Len was 1 byte too long)
// Fix possible crash on L4CODE if L4DACK received out of sequence
// Add basic IP decoding
// 410f October 2008
// Add IP Gateway
// Add Multiport DIGI capability
// Add GetPortDescription API
// Fix potential hangs if RNR lost
// Fix problem if External driver failes to load
// Put pushad/popad round _INITIALISEPORTS (main.asm)
// Add APIs GetApplCallVB and GetPortDescription (mainly for RMS)
// Ensure Route Qual is updated if Port Qual changed
// Add Reload Option, plus menu items for DUMP and SAVENODES
// 410g December 2008
// Restore API Exports BPQHOSTAPIPTR and MONDECODEPTR (accidentally deleted)
// Fix changed init of BPQDirectory (accidentally changed)
// Fix Checks for lost processes (accidentally deleted)
// Support HDLC Cards on W2K and above
// Delete Tray List entries for crashed processes
// Add Option to NODES command to sort by Callsign
// Add options to save or clear BPQNODES before Reconfig.
// Fix Reconfig in Win98
// Monitor buffering tweaks
// Fix Init for large (>64k) tables
// Fix Nodes count in Stats
// 410h January 2009
// Add Start Minimized Option
// Changes to KISS for WIn98 Virtual COM
// Open \\.\com instead of //./COM
// Extra Dignostics
// 410i Febuary 2009
// Revert KISS Changes
// Save Window positions
// 410j June 2009
// Fix tidying of window List when program crashed
// Add Max Nodes to Stats
// Don't update APPLnALIAS with received NODES info
// Fix MH display in other timezones
// Fix Possible crash when processing NETROM type Zero frames (eg NRR)
// Basic INP3 Stuff
// Add extra diagnostics to Lost Process detection
// Process Netrom Record Route frames.
// 410k June 2009
// Fix calculation of %retries in extended ROUTES display
// Fix corruption of ROUTES table
// 410l October 2009
// Add GetVersionString API call.
// Add GetPortTableEntry API call
// Keep links to neighbouring nodes open
// Build 2
// Fix PE in NOROUTETODEST (missing POP EBX)
// 410m November 2009
// Changes for PACTOR and WINMOR to support the ATTACH command
// Enable INP3 if configured on a route.
// Fix count of nodes in Stats Display
// Overwrite the worst quality unused route if a call is received from a node not in your
// table when the table is full
// Build 5
// Rig Control Interface
// Limit KAM VHF attach and RADIO commands to authorised programs (MailChat and BPQTerminal)
// Build 6
// Fix reading INP3 Flag from BPQNODES
// Build 7
// Add MAXHOPS and MAXRTT config options
// Build 8
// Fix INP3 deletion of Application Nodes.
// Fix GETCALLSIGN for Pactor Sessions
// Add N Call* to display all SSID's of a call
// Fix flow control on Pactor sessions.
// Build 9
// HDLC Support for XP
// Add AUTH routines
// Build 10
// Fix handling commands split over more that one packet.
// Build 11
// Attach cmd changes for winmor disconnecting state
// Option Interlock Winmor/Pactor ports
// Build 12
// Add APPLS export for winmor
// Handle commands ending CR LF
// Build 13
// Incorporate Rig Control in Kernel
// Build 14
// Fix config reload for Rig COntrol
// 410n March 2010
// Implement C P via PACTOR/WINMOR (for Airmail)
// Build 2
// Don't flip SSID bits on Downlink Connect if uplink is Pactor/WINMOR
// Fix resetting IDLE Timer on Pactor/WINMOR sessions
// Send L4 KEEPLI messages based on IDLETIME
// 410o July 2010
// Read bpqcfg.txt instead of .bin
// Support 32 bit MMASK (Allowing 32 Ports)
// Support 32 bit _APPLMASK (Allowing 32 Applications)
// Allow more commands
// Allow longer command aliases
// Fix logic error in RIGControl Port Initialisation (wasn't always raising RTS and DTR
// Clear RIGControl RTS and DTR on close
// 410o Build 2 August 2010
// Fix couple of errors in config (needed APPLICATIONS and BBSCALL/ALIAS/QUAL)
// Fix Kenwood Rig Control when more than one message received at once.
// Save minimzed state of Rigcontrol Window
// 410o Build 3 August 2010
// Fix reporting of set errors in scan to a random session
// 410o Build 4 August 2010
// Change All xxx Ports are in use to no xxxx Ports are available if there are no sessions with _APPLMASK
// Fix validation of TRANSDELAY
// 410o Build 5 August 2010
// Add Repeater Shift and Set Data Mode options to Rigcontrol (for ICOM only)
// Add WINMOR and SCS Pactor mode control option to RigControl
// Extend INFOMSG to 2000 bytes
// Improve Scan freq change lock (check both SCS and WINMOR Ports)
// 410o Build 6 September 2010
// Incorporate IPGateway in main code.
// Fix GetSessionInfo for Pactor/Winmor Ports
// Add Antenna Selection to RigControl
// Allow Bandwidth options on RADIO command line (as well as in Scan definitions)
// 410o Build 7 September 2010
// Move rigconrtol display to driver windows
// Move rigcontrol config to driver config.
// Allow driver and IPGateway config info in bpq32.cfg
// Move IPGateway, AXIP, VKISS, AGW and WINMOR drivers into bpq32.dll
// Add option to reread IP Gateway config.
// Fix Reinit after process with timer closes (error in TellSessions).
// 410p Build 2 October 2010
// Move KAM and SCS drivers to bpq32.dll
// 410p Build 3 October 2010
// Support more than one axip port.
// 410p Build 4 October 2010
// Dynamically load psapi.dll (for 98/ME)
// 410p Build 5 October 2010
// Incorporate TelnetServer
// Fix AXIP ReRead Config
// Report AXIP accept() fails to syslog, not a popup.
// 410p Build 6 October 2010
// Includes HAL support
// Changes to Pactor Drivers disconnect code
// AXIP now sends with source port = dest port, unless overridden by SOURCEPORT param
// Config now checks for duplicate port definitions
// Add Node Map reporting
// Fix WINMOR deferred disconnect.
// Report Pactor PORTCALL to WL2K instead of RMS Applcall
// 410p Build 7 October 2010
// Add In/Out flag to Map reporting, and report centre, not dial
// Write Telnet log to BPQ Directory
// Add Port to AXIP resolver display
// Send Reports to update.g8bpq.net:81
// Add support for FT100 to Rigcontrol
// Add timeout to Rigcontrol PTT
// Add Save Registry Command
// 410p Build 8 November 2010
// Add NOKEEPALIVES Port Param
// Renumbered for release
// 410p Build 9 November 2010
// Get Bandwith for map report from WL2K Report Command
// Fix freq display for FT100 (was KHz, not MHz)
// Don't try to change SCS mode whilst initialising
// Allow reporting of Lat/Lon as well as Locator
// Fix Telnet Log Name
// Fix starting with Minimized windows when Minimizetotray isn't set
// Extra Program Error trapping in SessionControl
// Fix reporting same freq with different bandwidths at different times.
// Code changes to support SCS Robust Packet Mode.
// Add FT2000 to Rigcontrol
// Only Send CTEXT to connects to Node (not to connects to an Application Call)
// Released as Build 10
// 410p Build 11 January 2011
// Fix MH Update for SCS Outgoing Calls
// Add Direct CMS Access to TelnetServer
// Restructure DISCONNECT processing to run in Timer owning process
// 410p Build 12 January 2011
// Add option for Hardware PTT to use a different com port from the scan port
// Add CAT PTT for Yaesu 897 (and maybe others)
// Fix RMS Packet ports busy after restart
// Fix CMS Telnet with MAXSESSIONS > 10
// 410p Build 13 January 2011
// Fix loss of buffers in TelnetServer
// Add CMS logging.
// Add non - Promiscuous mode option for BPQETHER
// 410p Build 14 January 2011
// Add support for BPQTermTCP
// Allow more that one FBBPORT
// Allow Telnet FBB mode sessions to send CRLF as well as CR on user and pass msgs
// Add session length to CMS Telnet logging.
// Return Secure Session Flag from GetConnectionInfo
// Show Uptime as dd/hh/mm
// 4.10.16.17 March 2011
// Add "Close all programs" command
// Add BPQ Program Directory registry key
// Use HKEY_CURRENT_USER on Vista and above (and move registry if necessary)
// Time out IP Gateway ARP entries, and only reload ax.25 ARP entries
// Add support for SCS Tracker HF Modes
// Fix WL2K Reporting
// Report Version to WL2K
// Add Driver to support Tracker with multiple sessions (but no scanning, wl2k report, etc)
// Above released as 5.0.0.1
// 5.2.0.1
// Add caching of CMS Server IP addresses
// Initialise TNC State on Pactor Dialogs
// Add Shortened (6 digit) AUTH mode.
// Update MH with all frames (not just I/UI)
// Add IPV6 Support for TelnetServer and AXIP
// Fix TNC OK Test for Tracker
// Fix crash in CMS mode if terminal disconnects while tcp commect in progress
// Add WL2K reporting for Robust Packet
// Add option to suppress WL2K reporting for specific frequencies
// Fix Timeband processing for Rig Control
// New Driver for SCS Tracker allowing multiple connects, so Tracker can be used for user access
// New Driver for V4 TNC
// 5.2.1.3 October 2011
// Combine busy detector on Interlocked Ports (SCS PTC, WINMOR or KAM)
// Improved program error logging
// WL2K reporting changed to new format agreed with Lee Inman
// 5.2.3.1 January 2012
// Connects from the console to an APPLCALL or APPLALIAS now invoke any Command Alias that has been defined.
// Fix reporting of Tracker freqs to WL2K.
// Fix Tracker monitoring setup (sending M UISC)
// Fix possible call/application routing error on RP
// Changes for P4Dragon
// Include APRS Digi/IGate
// Tracker monitoring now includes DIGIS
// Support sending UI frames using SCSTRACKER, SCTRKMULTI and UZ7HO drivers
// Include driver for UZ7HO soundcard modem.
// Accept DRIVER as well as DLLNAME, and COMPORT as well as IOADDR in bpq32.cfg. COMPORT is decimal
// No longer supports separate config files, or BPQTELNETSERVER.exe
// Improved flow control for Telnet CMS Sessions
// Fix handling Config file without a newline after last line
// Add non - Promiscuous mode option for BPQETHER
// Change Console Window to a Dialog Box.
// Fix possible corruption and loss of buffers in Tracker drivers
// Add Beacon After Session option to Tracker and UZ7HO Drivers
// Rewrite RigControl and add "Reread Config Command"
// Support User Mode VCOM Driver for VKISS ports
// 5.2.4.1 January 2012
// Remove CR from Telnet User and Password Prompts
// Add Rigcontrol to UZ7HO driver
// Fix corruption of Free Buffer Count by Rigcontol
// Fix WINMOR and V4 PTT
// Add MultiPSK Driver
// Add SendBeacon export for BPQAPRS
// Add SendChatReport function
// Fix check on length of Port Config ID String with trailing spaces
// Fix interlock when Port Number <> Port Slot
// Add NETROMCALL for L3 Activity
// Add support for APRS Application
// Fix Telnet with FBBPORT and no TCPPORT
// Add Reread APRS Config
// Fix switching to Pactor after scanning in normal packet mode (PTC)
// 5.2.5.1 February 2012
// Stop reading Password file.
// Add extra MPSK commands
// Fix MPSK Transparency
// Make LOCATOR command compulsory
// Add MobileBeaconInterval APRS param
// Send Course and Speed when APRS is using GPS
// Fix Robust Packet reporting in PTC driver
// Fix corruption of some MIC-E APRS packets
// 5.2.6.1 February 2012
// Convert to MDI presentation of BPQ32.dll windows
// Send APRS Status packets
// Send QUIT not EXIT in PTC Init
// Implement new WL2K reporting format and include traffic reporting info in CMS signon
// New WL2KREPORT format
// Prevent loops when APPL alias refers to itself
// Add RigControl for Flex radios and ICOM IC-M710 Marine radio
// 5.2.7.1
// Fix opening more thn one console window on Win98
// Change method of configuring multiple timelots on WL2K reporting
// Add option to update WK2K Sysop Database
// Add Web server
// Add UIONLY port option
// 5.2.7.2
// Fix handling TelnetServer packets over 500 bytes in normal mode
// 5.2.7.3
// Fix Igate handling packets from UIView
// 5.2.7.4
// Prototype Baycom driver.
// 5.2.7.5
// Set WK2K group ref to MARS (3) if using a MARS service code
// 5.2.7.7
// Check for programs calling CloseBPQ32 when holding semaphore
// Try/Except round Status Timer Processing
// 5.2.7.8
// More Try/Except round Timer Processing
// 5.2.7.9
// Enable RX in Baycom, and remove test loopback in tx
// 5.2.7.10
// Try/Except round ProcessHTTPMessage
// 5.2.7.11
// BAYCOM tweaks
// 5.2.7.13
// Release semaphore after program error in Timer Processing
// Check fro valid dest in REFRESHROUTE
// Add TNC-X KISSOPTION (includes the ACKMODE bytes in the checksum(
// Version 5.2.9.1 Sept 2012
// Fix using KISS ports with COMn > 16
// Add "KISS over UDP" driver for PI as a TNC concentrator
// Version 6.0.1.1
// Convert to C for linux portability
// Try to speed up kiss polling
// Version 6.0.2.1
// Fix operation on Win98
// Fix callsign error with AGWtoBPQ
// Fix PTT problem with WINMOR
// Fix Reread telnet config
// Add Secure CMS signon
// Fix error in cashing addresses of CMS servers
// Fix Port Number when using Send Raw.
// Fix PE in KISS driver if invalid subchannel received
// Fix Orignal address of beacons
// Speed up Telnet port monitoring.
// Add TNC Emulators
// Add CountFramesQueuedOnStream API
// Limit number of frames that can be queued on a session.
// Add XDIGI feature
// Add Winmor Robust Mode switching for compatibility with new Winmor TNC
// Move most APRS code from BPQAPRS to here
// Stop corruption caused by overlong KISS frames
// Version 6.0.3.1
// Add starting/killing WINMOR TNC on remote host
// Fix Program Error when APRS Item or Object name is same as call of reporting station
// Dont digi a frame that we have already digi'ed
// Add ChangeSessionIdleTime API
// Add WK2KSYSOP Command
// Add IDLETIME Command
// Fix Errors in RELAYAPPL processing
// Fix PE cauaed by invalid Rigcontrol Line
// Version 6.0.4.1
// Add frequency dependent autoconnect appls for SCS Pactor
// Fix DED Monitoring of I and UI with no data
// Include AGWPE Emulator (from AGWtoBPQ)
// accept DEL (Hex 7F) as backspace in Telnet
// Fix re-running resolver on re-read AXIP config
// Speed up processing, mainly for Telnet Sessions
// Fix APRS init on restart of bpq32.exe
// Change to 2 stop bits
// Fix scrolling of WINMOR trace window
// Fix Crash when ueing DED TNC Emulator
// Fix Disconnect when using BPQDED2 Driver with Telnet Sessions
// Allow HOST applications even when CMS option is disabled
// Fix processing of APRS DIGIMAP command with no targets (didn't suppress default settings)
// Version 6.0.5.1 January 2014
// Add UTF8 conversion mode to Telnet (converts non-UTF-8 chars to UTF-8)
// Add "Clear" option to MH command
// Add "Connect to RMS Relay" Option
// Revert to one stop bit on serial ports, explictly set two on FT2000 rig control
// Fix routing of first call in Robust Packet
// Add Options to switch input source on rigs with build in soundcards (sor far only IC7100 and Kenwood 590)
// Add RTS>CAT PTT option for Sound Card rigs
// Add Clear Nodes Option (NODE DEL ALL)
// SCS Pactor can set differeant APPLCALLS when scanning.
// Fix possible Scan hangup after a manual requency change with SCS Pactor
// Accept Scan entry of W0 to disable WINMOR on that frequency
// Fix corruption of NETROMCALL by SIMPLE config command
// Enforce Pactor Levels
// Add Telnet outward connect
// Add Relay/Trimode Emulation
// Fix V4 Driver
// Add PTT Mux
// Add Locked ARP Entries (via bpq32.cfg)
// Fix IDLETIME node command
// Fix STAY param on connect
// Add STAY option to Attach and Application Commands
// Fix crash on copying a large AXIP MH Window
// Fix possible crash when bpq32.exe dies
// Fix DIGIPORT for UI frames
// Version 6.0.6.1 April 2014
// FLDigi Interface
// Fix "All CMS Servers are inaccessible" message so Mail Forwarding ELSE works.
// Validate INP3 messages to try to prevent crash
// Fix possible crash if an overlarge KISS frame is received
// Fix error in AXR command
// Add LF to Telnet Outward Connect signin if NEEDLF added to connect line
// Add CBELL to TNC21 emulator
// Add sent objects and third party messages to APRS Dup List
// Incorporate UIUtil
// Use Memory Mapped file to pass APRS info to BPQAPRS, and process APRS HTTP in BPQ32
// Improvements to FLDIGI interlocking
// Fix TNC State Display for Tracker
// Cache CMS Addresses on LinBPQ
// Fix count error on DED Driver when handling 256 byte packets
// Add basic SNMP interface for MRTG
// Fix memory loss from getaddrinfo
// Process "BUSY" response from Tracker
// Handle serial port writes that don't accept all the data
// Trap Error 10038 and try to reopen socket
// Fix crash if overlong command line received
// Version 6.0.7.1 Aptil 2014
// Fix RigContol with no frequencies for Kenwood and Yaesu
// Add busy check to FLDIGI connects
// Version 6.0.8.1 August 2014
// Use HKEY_CURRENT_USER on all OS versions
// Fix crash when APRS symbol is a space.
// Fixes for FT847 CAT
// Fix display of 3rd byte of FRMR
// Add "DEFAULT ROBUST" and "FORCE ROBUST" commands to SCSPactor Driver
// Fix possible memory corruption in WINMOR driver
// Fix FT2000 Modes
// Use new WL2K reporting system (Web API Based)
// APRS Server now cycles through hosts if DNS returns more than one
// BPQ32 can now start and stop FLDIGI
// Fix loss of AXIP Resolver when running more than one AXIP port
// Version 6.0.9.1 November 2014
// Fix setting NOKEEPALIVE flag on route created from incoming L3 message
// Ignore NODES from locked route with quality 0
// Fix seting source port in AXIP
// Fix Dual Stack (IPV4/V6) on Linux.
// Fix RELAYSOCK if IPv6 is enabled.
// Add support for FT1000
// Fix hang when APRS Messaging packet received on RF
// Attempt to normalize Node qualies when stations use widely differing Route qualities
// Add NODES VIA command to display nodes reachable via a specified neighbour
// Fix applying "DisconnectOnClose" setting on HOST API connects (Telnet Server)
// Fix buffering large messages in Telnet Host API
// Fix occasional crash in terminal part line processing
// Add "NoFallback" command to Telnet server to disable "fallback to Relay"
// Improved support for APPLCALL scanning with Pactor
// MAXBUFFS config statement is no longer needed.
// Fix USEAPPLCALLS with Tracker when connect to APPLCALL fails
// Implement LISTEN and CQ commands
// FLDIGI driver can now start FLDIGI on a remote system.
// Add IGNOREUNLOCKEDROUTES parameter
// Fix error if too many Telnet server connections
// Version 6.0.10.1 Feb 2015
// Fix crash if corrupt HTML request received.
// Allow SSID's of 'R' and 'T' on non-ax.25 ports for WL2K Radio Only network.
// Make HTTP server HTTP Version 1.1 complient - use persistent conections and close after 2.5 mins
// Add INP3ONLY flag.
// Fix program error if enter UNPROTO without a destination path
// Show client IP address on HTTP sessions in Telnet Server
// Reduce frequency and number of attempts to connect to routes when Keepalives or INP3 is set
// Add FT990 RigControl support, fix FT1000MP support.
// Support ARMV5 processors
// Changes to support LinBPQ APRS Client
// Add IC7410 to supported Soundcard rigs
// Add CAT PTT to NMEA type (for ICOM Marine Radios_
// Fix ACKMODE
// Add KISS over TCP
// Support ACKMode on VKISS
// Improved reporting of configuration file format errors
// Experimental driver to support ARQ sessions using UI frames
// Version 6.0.11.1 September 2015
// Fixes for IPGateway configuration and Virtual Circuit Mode
// Separate Portmapper from IPGateway
// Add PING Command
// Add ARDOP Driver
// Add basic APPLCALL support for PTC-PRO/Dragon 7800 Packet (using MYALIAS)
// Add "VeryOldMode" for KAM Version 5.02
// Add KISS over TCP Slave Mode.
// Support Pactor and Packet on P4Dragon on one port
// Add "Remote Staton Quality" to Web ROUTES display
// Add Virtual Host option for IPGateway NET44 Encap
// Add NAT for local hosts to IPGateway
// Fix setting filter from RADIO command for IC7410
// Add Memory Channel Scanning for ICOM Radios
// Try to reopen Rig Control port if it fails (could be unplugged USB)
// Fix restoring position of Monitor Window
// Stop Codec on Winmor and ARDOP when an interlocked port is attached (instead of listen false)
// Support APRS beacons in RP mode on Dragon//
// Change Virtual MAC address on IPGateway to include last octet of IP Address
// Fix "NOS Fragmentation" in IP over ax.25 Virtual Circuit Mode
// Fix sending I frames before L2 session is up
// Fix Flow control on Telnet outbound sessions.
// Fix reporting of unterminatred comments in config
// Add option for RigControl to not change mode on FT100/FT990/FT1000
// Add "Attach and Connect" for Telnet ports
// Version 6.0.12.1 November 2015
// Fix logging of IP addresses for connects to FBBPORT
// Allow lower case user and passwords in Telnet "Attach and Connect"
// Fix possible hang in KISS over TCP Slave mode
// Fix duplicating LinBPQ process if running ARDOP fails
// Allow lower case command aliases and increase alias length to 48
// Fix saving long IP frames pending ARP resolution
// Fix dropping last entry from a RIP44 message.
// Fix displaying Digis in MH list
// Add port name to Monitor config screen port list
// Fix APRS command display filter and add port filter
// Support port names in BPQTermTCP Monitor config
// Add FINDBUFFS command to dump lost buffers to Debugview/Syslog
// Buffer Web Mgmt Edit Config output
// Add WebMail Support
// Fix not closing APRS Send WX file.
// Add RUN option to APRS Config to start APRS Client
// LinBPQ run FindLostBuffers and exit if QCOUNT < 5
// Close and reopen ARDOP connection if nothing received for 90 secs
// Add facility to bridge traffic between ports (similar to APRS Bridge but for all frame types)
// Add KISSOPTION TRACKER to set SCS Tracker into KISS Mode
// 6.0.13.1
// Allow /ex to exit UNPROTO mode
// Support ARQBW commands.
// Support IC735
// Fix sending ARDOP beacons after a busy holdoff
// Enable BPQDED driver to beacon via non-ax.25 ports.
// Fix channel number in UZ7HO monitoring
// Add SATGate mode to APRSIS Code.
// Fix crash caused by overlong user name in telnet logon
// Add option to log L4 connects
// Add AUTOADDQuiet mode to AXIP.
// Add EXCLUDE processing
// Support WinmorControl in UZ7HO driver and fix starting TNC on Linux
// Convert calls in MAP entries to upper case.
// Support Linux COM Port names for APRS GPS
// Fix using NETROM serial protocol on ASYNC Port
// Fix setting MYLEVEL by scanner after manual level change.
// Add DEBUGLOG config param to SCS Pactor Driver to log serial port traffic
// Uue #myl to set SCS Pactor MYLEVEL, and add checklevel command
// Add Multicast RX interface to FLDIGI Driver
// Fix processing application aliases to a connect command.
// Fix Buffer loss if radio connected to PTC rig port but BPQ not configured to use it
// Save backups of bpq32.cfg when editing with Web interface and report old and new length
// Add DD command to SCS Pactor, and use it for forced disconnect.
// Add ARDOP mode select to scan config
// ARDOP changes for ARDOP V 0.5+
// Flip SSID bits on UZ7HO downlink connects
// Version 6.0.14.1
// Fix Socket leak in ARDOP and FLDIGI drivers.
// Add option to change CMS Server hostname
// ARDOP Changes for 0.8.0+
// Discard Terminal Keepalive message (two nulls) in ARDOP command hander
// Allow parameters to be passed to ARDOP TNC when starting it
// Fix Web update of Beacon params
// Retry connects to KISS ports after failure
// Add support for ARDOP Serial Interface Native mode.
// Fix gating APRS-IS Messages to RF
// Fix Beacons when PORTNUM used
// Make sure old monitor flag is cleared for TermTCP sessions
// Add CI-V antenna control for IC746
// Don't allow ARDOP beacons when connected
// Add support for ARDOP Serial over I2C
// Fix possble crash when using manual RADIO messages
// Save out of sequence L2 frames for possible reuse after retry
// Add KISS command to send KISS control frame to TNC
// Stop removing unused digis from packets sent to APRS-IS
// Processing of ARDOP PING and PINGACK responses
// Handle changed encoding of WL2K update responses.
// Allow anonymous logon to telnet
// Don't use APPL= for RP Calls in Dragon Single mode.
// Add basic messaging page to APRS Web Server
// Add debug log option to SCSTracker and TrkMulti Driver
// Support REBOOT command on LinBPQ
// Allow LISTEN command on all ports that support ax.25 monitoring
// Version 6.0.15.1 Feb 2018
// partial support for ax.25 V2.2
// Add MHU and MHL commands and MH filter option
// Fix scan interlock with ARDOP
// Add Input source seiect for IC7300
// Remove % transparency from web terminal signon message
// Fix L4 Connects In count on stats
// Fix crash caused by corrupt CMSInfo.txt
// Add Input peaks display to ARDOP status window
// Add options to show time in local and distances in KM on APRS Web pages
// Add VARA support
// Fix WINMOR Busy left set when port Suspended
// Add ARDOP-Packet Support
// Add Antenna Switching for TS 480
// Fix possible crash in Web Terminal
// Support different Code Pages on Console sessions
// Use new Winlink API interface (api.winlink.org)
// Support USB/ACC switching on TS590SG
// Fix scanning when ARDOP or WINMOR is used without an Interlocked Pactor port.
// Set NODECALL to first Application Callsign if NODE=0 and BBSCALL not set.
// Add RIGCONTROL TUNE and POWER commands for some ICOM and Kenwwod rigs
// Fix timing out ARDOP PENDING Lock
// Support mixed case WINLINK Passwords
// Add TUNE and POWER Rigcontol Commands for some radios
// ADD LOCALTIME and DISPKM options to APRS Digi/Igate
// 6.0.16.1 March 2018
// Fix Setting data mode and filter for IC7300 radios
// Add VARA to WL2KREPORT
// Add trace to SCS Tracker status window
// Fix possible hang in IPGATEWAY
// Add BeacontoIS parameter to APRSDIGI. Allows you to stop sending beacons to APRS-IS.
// Fix sending CTEXT on WINMOR sessions
// 6.0.17.1 November 2018
// Change WINMOR Restart after connection to Restart after Failure and add same option to ARDOP and VARA
// Add Abort Connection to WINMOR and VARA Interfaces
// Reinstate accidentally removed CMS Access logging
// Fix MH CLEAR
// Fix corruption of NODE table if NODES received from station with null alias
// Fix loss of buffer if session closed with something in PARTCMDBUFFER
// Fix Spurious GUARD ZONE CORRUPT message in IP Code.
// Remove "reread bpq32.cfg and reconfigure" menu options
// Add support for PTT using CM108 based soundcard interfaces
// Datestamp Telnet log files and delete old Telnet and CMSAcces logs
// 6.0.18.1 January 2019
// Fix validation of NODES broadcasts
// Fix HIDENODES
// Check for failure to reread config on axip reconfigure
// Fix crash if STOPPORT or STARTPORT used on KISS over TCP port
// Send Beacons from BCALL or PORTCALL if configured
// Fix possible corruption of last entry in MH display
// Ensure RTS/DTR is down when opening PTT Port
// Remove RECONFIG command
// Preparations for 64 bit version
// 6.0.19 Sept 2019
// Fix UZ7HO interlock
// Add commands to set Centre Frequency and Modem with UZ7HO Soundmodem (on Windows only)
// Add option to save and restore MH lists and SAVEMH command
// Add Frequency (if known) to UZ7HO MH lists
// Add Gateway option to Telnet for PAT
// Try to fix SCS Tracker recovery
// Ensure RTS/DTR is down on CAT port if using that line for PTT
// Experimental APRS Messaging in Kernel
// Add Rigcontrol on remote PC's using WinmorControl
// ADD VARAFM and VARAFM96 WL2KREPORT modes
// Fix WL2K sysop update for new Winlink API
// Fix APRS when using PORTNUM higher than the number of ports
// Add Serial Port Type
// Add option to linbpq to log APRS-IS messages.
// Send WL2K Session Reports
// Drop Tunneled Packets from 44.192 - 44.255
// Log incoming Telnet Connects
// Add IPV4: and IPV6: overrides on AXIP Resolver.
// Add SessionTimeLimit to HF sessions (ARDOP, SCSPactor, WINMOR, VARA)
// Add RADIO FREQ command to display current frequency
// 6.0.20 April 2020
// Trap and reject YAPP file transfer request.
// Fix possible overrun of TCP to Node Buffer
// Fix possible crash if APRS WX file doesn't have a terminating newline
// Change communication with BPQAPRS.exe to restore old message popup behaviour
// Preparation for 64 bit version
// Improve flow control on SCS Dragon
// Fragment messages from network links to L2 links with smaller paclen
// Change WL2K report rate to once every two hours
// Add PASS, CTEXT and CMSG commands and Stream Switch support to TNC2 Emulator
// Add SessionTimeLimit command to HF drivers (ARDOP, SCSPactor, WINMOR, VARA)
// Add links to Ports Web Manangement Page to open individual Driver windows
// Add STOPPORT/STARTPORT support to ARDOP, KAM and SCSPactor drivers
// Add CLOSE and OPEN RADIO command so Rigcontrol port can be freed fpr other use.
// Don't try to send WL2K Traffic report if Internet is down
// Move WL2K Traffic reporting to a separate thread so it doesn't block if it can't connect to server
// ADD AGWAPPL config command to set application number. AGWMASK is still supported
// Register Node Alias with UZ7HO Driver
// Register calls when UZ7HO TNC Restarts and at intervals afterwards
// Fix crash when no IOADDR or COMPORT in async port definition
// Fix Crash with Paclink-Unix when parsing ; VE7SPR-10 DE N7NIX QTC 1
// Only apply BBSFLAG=NOBBS to APPPLICATION 1
// Add RIGREONFIG command
// fix APRS RECONFIG on LinBPQ
// Fix Web Terminal scroll to end problem on some browsers
// Add PTT_SETS_INPUT option for IC7600
// Add TELRECONFIG command to reread users or whole config
// Enforce PACLEN on UZ7HO ports
// Fix PACLEN on Command Output.
// Retry axip resolver if it fails at startup
// Fix AGWAPI connect via digis
// Fix Select() for Linux in MultiPSK, UZ7HO and V4 drivers
// Limit APRS OBJECT length to 80 chars
// UZ7HO disconnect incoming call if no free streams
// Improve response to REJ (no F) followed by RR (F).
// Try to prevent more than MAXFRAME frames outstanding when transmitting
// Allow more than one instance of APRS on Linux
// Stop APRS digi by originating station
// Send driver window trace to main monitor system
// Improve handling of IPOLL messages
// Fix setting end of address bit on dest call on connects to listening sessions
// Set default BBS and CHAT application number and number of streams on LinBPQ
// Support #include in bpq32.cfg processing
// Version 6.0.21 14 December 2020
// Fix occasional missing newlines in some node command reponses
// More 64 bit fixes
// Add option to stop setting PDUPLEX param in SCSPACTOR
// Try to fix buffer loss
// Remove extra space from APRS position reports
// Suppress VARA IAMALIVE messages
// Add display and control of QtSoundModem modems
// Only send "No CMS connection available" message if fallbacktorelay is set.
// Add HAMLIB backend and emulator support to RIGCONTROL
// Ensure all beacons are sent even with very short beacon intervals
// Add VARA500 WL2K Reporting Mode
// Fix problem with prpcessing frame collector
// Temporarily disable L2 and L4 collectors till I can find problem
// Fix possible problem with interactive RADIO commands not giving a response,
// Incease maximum length of NODE command responses to handle maximum length INFO message,
// Allow WL2KREPORT in CONFIG section of UZ7HO port config.
// Fix program error in processing hamlib frame
// Save RestartAfterFailure option for VARA
// Check callsign has a winlink account before sending WL2KREPORT messages
// Add Bandwidth control to VARA scanning
// Renable L2 collector
// Fix TNCPORT reconnect on Linux
// Add SecureTelnet option to limit telnet outward connect to sysop mode sessions or Application Aliases
// Add option to suppress sending call to application in Telnet HOST API
// Add FT991A support to RigControl
// Use background.jpg for Edit Config page
// Send OK response to SCS Pactor commands starting with #
// Resend ICOM PTT OFF command after 30 seconds
// Add WXCall to APRS config
// Fixes for AEAPactor
// Allow PTTMUX to use real or com0com com ports
// Fix monitoring with AGW Emulator
// Derive approx position from packets on APRS ports with a valid 6 char location
// Fix corruption of APRS message lists if the station table fills up.
// Don't accept empty username or password on Relay sessions.
// Fix occasional empty Nodes broadcasts
// Add Digis to UZ7HO Port MH list
// Add PERMITTEDAPPLS port param
// Fix WK2K Session Record Reporting for Airmail and some Pactor Modes.
// Fix handling AX/IP (proto 93) frames
// Fix possible corruption sending APRS messages
// Allow Telnet connections to be made using Connect command as well as Attach then Connect
// Fix Cancel Sysop Signin
// Save axip resolver info and restore on restart
// Add Transparent mode to Telnet Server HOST API
// Fix Tracker driver if WL2KREPRRT is in main config section
// SNMP InOctets count corrected to include all frames and encoding of zero values fixed.
// Change IP Gateway to exclude handling bits of 44 Net sold to Amazon
// Fix crash in Web terminal when processing very long lines
// Version 6.0.22.1 August 2021
// Fix bug in KAM TNCEMULATOR
// Add WinRPR Driver (DED over TCP)
// Fix handling of VARA config commands FM1200 and FM9600
// Improve Web Termanal Line folding
// Add StartTNC to WinRPR driver
// Add support for VARA2750 Mode
// Add support for VARA connects via a VARA Digipeater
// Add digis to SCSTracker and WinRPR MHeard
// Separate RIGCONTROL config from PORT config and add RigControl window
// Fix crash when a Windows HID device doesn't have a product_string
// Changes to VARA TNC connection and restart process
// Trigger FALLBACKTORELAY if attempt to connect to all CMS servers fail.
// Fix saving part lines in adif log and Winlink Session reporting
// Add port specific CTEXT
// Add FRMR monitoring to UZ7HO driver
// Add audio input switching for IC7610
// Include Rigcontrol Support for IC-F8101E
// Process any response to KISS command
// Fix NODE ADD command
// Add noUpdate flag to AXIP MAP
// Fix clearing NOFALLBACK flag in Telnet Server
// Allow connects to RMS Relay running on another host
// Allow use of Power setting in Rigcontol scan lines for Kenwood radios
// Prevent problems caused by using "CMS" as a Node Alias
// Include standard APRS Station pages in code
// Fix VALIDCALLS processing in HF drivers
// Send Netrom Link reports to Node Map
// Add REALTELNET mode to Telnet Outward Connect
// Fix using S (Stay) parameter on Telnet connects when using CMDPORT and C HOST
// Add Default frequency to rigcontrol to set a freq/mode to return to after a connection
// Fix long (> 60 seconds) scan intervals
// Improved debugging of stuck semaphores
// Fix potential securiby bug in BPQ Web server
// Send Chat Updates to chatupdate.g8bpq.net port 81
// Add ReportRelayTraffic to Telnet config to send WL2K traffic reports for connections to RELAY
// Add experimental Mode reporting
// Add SendTandRtoRelay param to SCS Pactor, ARDOP and VARA drivers to divert calls to CMS for -T and -R to RELAY
// Add UPNP Support
// Version 6.0.23.1 June 2022
// Add option to control which applcalls are enabled in VARA
// Add support for rtl_udp to Rig Control
// Fix Telnet Auto Conneect to Application when using TermTCP or Web Terminal
// Allow setting css styles for Web Terminal
// And Kill TNC and Kill and Restart TNC commands to Web Driver Windows
// More flexible RigControl for split frequency operation, eg for QO100
// Increase stack size for ProcessHTMLMessage (.11)
// Fix HTML Content-Type on images (.12)
// Add AIS and ADSB Support (.13)
// Compress web pages (.14)
// Change minidump routine and close after program error (.15)
// Add RMS Relay SYNC Mode (.17)
// Changes for compatibility with Winlink Hybrid
// Add Rigcontrol CMD feature to Yaesu code (21)
// More diagnostic code
// Trap potential buffer overrun in ax/tcp code
// Fix possible hang in UZ7HO driver if connect takes a long time to succeed or fail
// Add FLRIG as backend for RigControl (.24)
// Fix bug in compressing some management web pages
// Fix bugs in AGW Emulator (.25)
// Add more PTT_Sets_Freq options for split frequency working (.26)
// Allow RIGCONTROL using Radio Number (Rnn) as well as Port (.26)
// Fix Telnet negotiation and backspace processing (.29)
// Fix VARA Mode change when scanning (.30)
// Add Web Mgmt Log Display (.33)
// Fix crash when connecting to RELAY when CMS=0 (.36)
// Send OK to user for manual freq changes with hamlib or flrig
// Fix Rigcontrol leaving port disabled when using an empty timeband
// Fix processing of backspace in Telnet character processing (.40)
// Increase max size of connect script
// Fix HAMLIB Slave Thread control
// Add processing of VARA mode responses and display of VARA Mode (41)
// Fix crash when VARA session aborted on LinBPQ (43)
// Fix handling port selector (2:call or p2 call) on SCS PTC packet ports (44)
// Include APRS Map web page
// Add Enable/Disable to KAMPACTOR scan control (use P0 or P1) (45)
// Add Basic DRATS interface (46)
// Fix MYCALLS on VARA (49)
// Add FreeData driver (51)
// Add additonal Rigcontrol options for QO100 (51)
// Set Content-Type: application/pdf for pdf files downloaded via web interface (51)
// Fix sending large compressed web messages (52)
// Fix freq display when using flrig or hamlib backends to rigcontrol
// Change VARA Driver to send ABORT when Session Time limit expires
// Add Chat Log to Web Logs display
// Fix possible buffer loss in RigControl
// Allow hosts on local lan to be treated as secure
// Improve validation of data sent to Winlink SessionAdd API call
// Add support for FreeDATA modem.
// Add GetLOC API Call
// Change Leaflet link in aprs map.
// Add Connect Log (64)
// Fix crash when Resolve CMS Servers returns ipv6 addresses
// Fix Reporting P4 sessions to Winlink (68)
// Add support for FreeBSD (68)
// Fix Rigcontrol PTCPORT (69)
// Set TNC Emulator sessions as secure (72)
// Fix not always detecting loss of FLRIG (73)
// Add ? and * wildcards to NODES command (74)
// Add Port RADIO config parameter (74)
// Version 6.0.24.1 August 2023
// Apply NODES command wildcard to alias as well a call (2)
// Add STOPPORT/STARTPORT to VARA Driver (2)
// Add bandwidth setting to FLRIG interface. (2)
// Fix N VIA (3)
// Fix NODE ADD and NODE DEL (4)
// Improvements to FLRIG Rigcontrol backend (6, 7)
// Fix UZ7HO Window Title Update
// Reject L2 calls with a blank from call (8)
// Update WinRPR Window header with BPQ Port Description (8)
// Fix error in blank call code (9)
// Change web buttons to white on black when pressed (10)
// Fix Port CTEXT paclen on Tracker and WinRPR drivers (11)
// Add RADIO PTT command for testing PTT (11)
// Fix using APPLCALLs on SCSTracker RP call (12)
// Add Rigcntol Web Page (13)
// Fix scan bandwidth change with ARDOPOFDM (13)
// Fix setting Min Pactor Level in SCSPactor (13)
// Fix length of commands sent via CMD_TO_APPL flag (14)
// Add filter by quality option to N display (15)
// Fix VARA Mode reporting to WL2K (16)
// Add FLRIG POWER and TUNE commands (18)
// Fix crash when processing "C " without a call in UZ7HO, FLDIGI or MULTIPSK drivers (19)
// FLDIGI improvements (19)
// Fix hang at start if Telnet port Number > Number of Telnet Streams (20)
// Fix processing C command if first port driver is SCSPACTROR (20)
// Fix crash in UZ7HO driver if bad raw frame received (21)
// Fix using FLARQ chat mode with FLDIGI ddriover (22)
// Fix to KISSHF driver (23)
// Fix for application buffer loss (24)
// Add Web Sockets auto-refresh option for Webmail index page (25)
// Fix FREEDATA driver for compatibility with FreeData TNC version 0.6.4-alpha.3 (25)
// Add SmartID for bridged frames - Send ID only if packets sent recently (26)
// Add option to save and restore received APRS messages (27)
// Add mechanism to run a user program on certain events (27)
// If BeacontoIS is zero don't Gate any of our messages received locally to APRS-IS (28)
// Add Node Help command (28)
// Add APRS Igate RXOnly option (29)
// Fix RMC message handling with prefixes other than GP (29)
// Add GPSD support for APRS (30)
// Attempt to fix Tracker/WinRPR reconnect code (30)
// Changes to FreeDATA - Don't use deamon and add txlevel and send text commands (31)
// Fix interactive commands in tracker driver (33)
// Fix SESSIONTIMELIMIT processing
// Add STOPPORT/STARTPORT for UZ7HO driver
// Fix processing of extended QtSM 'g' frame (36)
// Allow setting just freq on Yaseu rigs (37)
// Enable KISSHF driver on Linux (40)
// Allow AISHOST and ADSBHOST to be a name as well as an address (41)
// Fix Interlock of incoming UZ7HO connections (41)
// Disable VARA Actions menu if not sysop (41)
// Fix Port CTEXT on UZ7HO B C or D channels (42)
// Fix repeated trigger of SessionTimeLimit (43)
// Fix posible memory corruption in UpateMH (44)
// Add PHG to APRS beacons (45)
// Dont send DM to stations in exclude list(45)
// Improvements to RMS Relay SYNC Mode (46)
// Check L4 connects against EXCLUDE list (47)
// Add vaidation of LOC in WL2K Session Reports (49)
// Change gpsd support for compatibility with Share Gps (50)
// Switch APRS Map to my Tiles (52)
// Fix using ; in UNPROTO Mode messages (52)
// Use sha1 code from https://www.packetizer.com/security/sha1/ instead of openssl (53)
// Fix TNC Emulator Monitoring (53)
// Fix attach and connect on Telnet port bug introduced in .55 (56)
// Fix stopping WinRPR TNC and Start/Stop UZ7HO TNCX on Linux (57)
// Fix stack size in beginthread for MAC (58)
// Add NETROM over VARA (60)
// Add Disconnect Script (64)
// Add node commands to set UZ7HO modem mode and freq (64)
// Trap empty NODECALL or NETROMCALL(65)
// Trap NODES messages with empty From Call (65)
// Add RigControl for SDRConsole (66)
// Fix FLRig crash (66)
// Fix VARA disconnect handling (67)
// Support 64 ports (69)
// Fix Node commands for setting UZ7HO Modem (70)
// Fix processing SABM on an existing session (71)
// Extend KISS Node command to send more than one parameter byte (72)
// Add G7TAJ's code to record activity of HF ports for stats display (72)
// Add option to send KISS command to TNC on startup (73)
// Fix Bug in DED Emulator Monitor code (74)
// Add Filters to DED Monitor code (75)
// Detect loss of DED application (76)
// Fix connects to Application Alias with UZ7HO Driver (76)
// Fix Interlock of ports on same UZ7HO modem. (76)
// Add extended Ports command (77)
// Fix crash in Linbpq when stdout is redirected to /dev/tty? and stdin ia redirected (78)
// Fix Web Terminal (80)
// Trap ENCRYPTION message from VARA (81)
// Fix processing of the Winlink API /account/exists response (82)
// Fix sending CTEXT to L4 connects to Node when FULL_CTEXT is not set
// Version 6.0.25.?
// Fix 64 bit compatibility problems in SCSTracker and UZ7HO drivers
// Add Chat PACLEN config (5)
// Fix NC to Application Call (6)
// Fix INP3 L3RTT messages on Linux and correct RTT calculation (9)
// Get Beacon config from config file on Windows (9)
// fix processing DED TNC Emulator M command with space between M and params (10)
// Fix sending UI frames on SCSPACTOR (11)
// Dont allow ports that can't set digi'ed bit in callsigns to digipeat. (11)
// Add SDRAngel rig control (11)
// Add option to specify config and data directories on linbpq (12)
// Allow zero resptime (send RR immediately) (13)
// Make sure CMD bit is set on UI frames
// Add setting Modem Flags in QtSM AGW mode
// If FT847 om PTC Port send a "Cat On" command (17)
// Fix some 63 port bugs in RigCOntrol (17)
// Fix 63 port bug in Bridging (18)
// Add FTDX10 Rigcontrol (19)
// Fix 64 bit bug in displaying INP3 Messages (20)
// Improve restart of WinRPR TNC on remote host (21)
// Fix some Rigcontrol issues with empty timebands (22)
// Fix 64 bit bug in processing INP3 Messages (22)
// First pass at api (24)
// Send OK in response to Rigcontrol CMD (24)
// Disable CTS check in WriteComBlock (26)
// Improvments to reporting to M0LTE Map (26)
// IPGateway fix from github user isavitsky (27)
// Fix possible crash in SCSPactor PTCPORT code (29)
// Add NodeAPI call sendLinks and remove get from other calls (32)
// Improve validation of Web Beacon Config (33)
// Support SNMP via host ip stack as well as IPGateway (34)
// Switch APRS Map to OSM tile servers (36)
// Fix potential buffer overflow in Telnet login (36)
// Allow longer serial device names (37)
// Fix ICF8101 Mode setting (37)
// Kill link if we are getting repeated RR(F) after timeout
// (Indicating other station is seeing our RR(P) but not the resent I frame) (40)
// Change default of SECURETELNET to 1 (41)
// Add optional ATTACH time limit for ARDOP (42)
// Fix buffer overflow risk in HTTP Terminal(42)
// Fix KISSHF Interlock (43)
// Support other than channel A on HFKISS (43)
// Support additional port info reporting for M0LTE Map (44)
// Allow interlocking of KISS and Session mode ports (eg ARDOP and VARA) (45)
// Add ARDOP UI Packets to MH (45)
// Add support for Qtsm Mgmt Interface (45)
// NodeAPI improvements (46)
// Add MQTT Interface (46)
// Fix buffer leak in ARDOP code(46)
// Fix possible crash if MQTT not in use (47)
// Add optional ATTACH time limit for VARA (48)
// API format fixes (48)
// AGWAPI Add protection against accidental connects from a non-agw application (50)
// Save MH and NODES every hour (51)
// Fix handling long unix device names (now max 250 bytes) (52)
// Fix error reporting in api update (53)
// Coding changes to remove some compiler warnings (53, 54)
// Add MQTT reporting o
#define CKernel
#include "Versions.h"
#define _CRT_SECURE_NO_DEPRECATE
#pragma data_seg("_BPQDATA")
#include "time.h"
#include "stdio.h"
#include <fcntl.h>
#include "compatbits.h"
#include "AsmStrucs.h"
#include "SHELLAPI.H"
#include "kernelresource.h"
#include <tlhelp32.h>
#include <Iphlpapi.h>
#include "BPQTermMDI.h"
#include "GetVersion.h"
#define DllImport __declspec( dllimport )
#define CheckGuardZone() _CheckGuardZone(__FILE__, __LINE__)
void _CheckGuardZone(char * File, int Line);
#define CHECKLOADED 0
#define SETAPPLFLAGS 1
#define SENDBPQFRAME 2
#define GETBPQFRAME 3
#define GETSTREAMSTATUS 4
#define CLEARSTREAMSTATUS 5
#define BPQCONDIS 6
#define GETBUFFERSTATUS 7
#define GETCONNECTIONINFO 8
#define BPQRETURN 9 // GETCALLS
//#define RAWTX 10 //IE KISS TYPE DATA
#define GETRAWFRAME 11
#define UPDATESWITCH 12
#define BPQALLOC 13
//#define SENDNETFRAME 14
#define GETTIME 15
extern short NUMBEROFPORTS;
extern long PORTENTRYLEN;
extern long LINKTABLELEN;
extern struct PORTCONTROL * PORTTABLE;
extern void * FREE_Q;
extern UINT APPL_Q; // Queue of frames for APRS Appl
extern TRANSPORTENTRY * L4TABLE;
extern UCHAR NEXTID;
extern DWORD MAXCIRCUITS;
extern DWORD L4DEFAULTWINDOW;
extern DWORD L4T1;
extern APPLCALLS APPLCALLTABLE[];
extern char * APPLS;
extern struct WL2KInfo * WL2KReports;
extern int NUMBEROFTNCPORTS;
void * VCOMExtInit(struct PORTCONTROL * PortEntry);
void * AXIPExtInit(struct PORTCONTROL * PortEntry);
void * SCSExtInit(struct PORTCONTROL * PortEntry);
void * AEAExtInit(struct PORTCONTROL * PortEntry);
void * KAMExtInit(struct PORTCONTROL * PortEntry);
void * HALExtInit(struct PORTCONTROL * PortEntry);
void * ETHERExtInit(struct PORTCONTROL * PortEntry);
void * AGWExtInit(struct PORTCONTROL * PortEntry);
void * WinmorExtInit(EXTPORTDATA * PortEntry);
void * TelnetExtInit(EXTPORTDATA * PortEntry);
//void * SoundModemExtInit(EXTPORTDATA * PortEntry);
void * TrackerExtInit(EXTPORTDATA * PortEntry);
void * TrackerMExtInit(EXTPORTDATA * PortEntry);
void * V4ExtInit(EXTPORTDATA * PortEntry);
void * UZ7HOExtInit(EXTPORTDATA * PortEntry);
void * MPSKExtInit(EXTPORTDATA * PortEntry);
void * FLDigiExtInit(EXTPORTDATA * PortEntry);
void * UIARQExtInit(EXTPORTDATA * PortEntry);
void * SerialExtInit(EXTPORTDATA * PortEntry);
void * ARDOPExtInit(EXTPORTDATA * PortEntry);
void * VARAExtInit(EXTPORTDATA * PortEntry);
void * KISSHFExtInit(EXTPORTDATA * PortEntry);
void * WinRPRExtInit(EXTPORTDATA * PortEntry);
void * HSMODEMExtInit(EXTPORTDATA * PortEntry);
void * FreeDataExtInit(EXTPORTDATA * PortEntry);
void * SIXPACKExtInit(EXTPORTDATA * PortEntry);
extern char * ConfigBuffer; // Config Area
VOID REMOVENODE(dest_list * DEST);
DllExport int ConvFromAX25(unsigned char * incall,unsigned char * outcall);
DllExport int ConvToAX25(unsigned char * incall,unsigned char * outcall);
VOID GetUIConfig();
VOID ADIFWriteFreqList();
void SaveAIS();
void initAIS();
void initADSB();
extern BOOL ADIFLogEnabled;
int CloseOnError = 0;
char UIClassName[]="UIMAINWINDOW"; // the main window class name
HWND UIhWnd;
extern char AUTOSAVE;
extern char AUTOSAVEMH;
extern char MYNODECALL; // 10 chars,not null terminated
extern QCOUNT;
extern BPQVECSTRUC BPQHOSTVECTOR[];
#define BPQHOSTSTREAMS 64
#define IPHOSTVECTOR BPQHOSTVECTOR[BPQHOSTSTREAMS + 3]
extern char * CONFIGFILENAME;
DllExport BPQVECSTRUC * BPQHOSTVECPTR;
extern int DATABASESTART;
extern struct ROUTE * NEIGHBOURS;
extern int ROUTE_LEN;
extern int MAXNEIGHBOURS;
extern struct DEST_LIST * DESTS; // NODE LIST
extern int DEST_LIST_LEN;
extern int MAXDESTS; // MAX NODES IN SYSTEM
extern struct _LINKTABLE * LINKS;
extern int LINK_TABLE_LEN;
extern int MAXLINKS;
extern double LatFromLOC;
extern double LonFromLOC;
extern int BPQHOSTAPI();
extern int INITIALISEPORTS();
extern int TIMERINTERRUPT();
extern int MONDECODE();
extern int BPQMONOPTIONS();
extern char PWTEXT[];
extern char PWLen;
extern int FINDFREEDESTINATION();
extern int RAWTX();
extern int RELBUFF();
extern int SENDNETFRAME();
extern char MYCALL[]; // 7 chars, ax.25 format
extern HWND hIPResWnd;
extern BOOL IPMinimized;
extern int NODESINPROGRESS;
extern VOID * CURRENTNODE;
BOOL Start();
VOID SaveWindowPos(int port);
VOID SaveAXIPWindowPos(int port);
VOID SetupRTFHddr();
DllExport VOID APIENTRY CreateNewTrayIcon();
int DoReceivedData(int Stream);
int DoStateChange(int Stream);
int DoMonData(int Stream);
struct ConsoleInfo * CreateChildWindow(int Stream, BOOL DuringInit);
CloseHostSessions();
SaveHostSessions();
VOID SaveBPQ32Windows();
VOID CloseDriverWindow(int port);
VOID CheckWL2KReportTimer();
VOID SetApplPorts();
VOID WriteMiniDump();
VOID FindLostBuffers();
BOOL InitializeTNCEmulator();
VOID TNCTimer();
char * strlop(char * buf, char delim);
DllExport int APIENTRY Get_APPLMASK(int Stream);
DllExport int APIENTRY GetStreamPID(int Stream);
DllExport int APIENTRY GetApplFlags(int Stream);
DllExport int APIENTRY GetApplNum(int Stream);
DllExport BOOL APIENTRY GetAllocationState(int Stream);
DllExport int APIENTRY GetMsg(int stream, char * msg, int * len, int * count );
DllExport int APIENTRY RXCount(int Stream);
DllExport int APIENTRY TXCount(int Stream);
DllExport int APIENTRY MONCount(int Stream);
DllExport int APIENTRY GetCallsign(int stream, char * callsign);
DllExport VOID APIENTRY RelBuff(VOID * Msg);
void SaveMH();
void DRATSPoll();
#define C_Q_ADD(s, b) _C_Q_ADD(s, b, __FILE__, __LINE__);
int _C_Q_ADD(VOID *PQ, VOID *PBUFF, char * File, int Line);
VOID SetWindowTextSupport();
int WritetoConsoleSupport(char * buff);
VOID PMClose();
VOID MySetWindowText(HWND hWnd, char * Msg);
BOOL CreateMonitorWindow(char * MonSize);
VOID FormatTime3(char * Time, time_t cTime);
char EXCEPTMSG[80] = "";
char SIGNONMSG[128] = "";
char SESSIONHDDR[80] = "";
int SESSHDDRLEN = 0;
BOOL IncludesMail = FALSE;
BOOL IncludesChat = FALSE; // Set if pgram is running - used for Web Page Index
char WL2KCall[10];
char WL2KLoc[7];
extern char LOCATOR[]; // Locator for Reporting - may be Maidenhead or LAT:LON
extern char MAPCOMMENT[]; // Locator for Reporting - may be Maidenhead or LAT:LON
extern char LOC[7]; // Maidenhead Locator for Reporting
extern char ReportDest[7];
extern UCHAR ConfigDirectory[260];
extern uint64_t timeLoadedMS;
VOID __cdecl Debugprintf(const char * format, ...);
VOID __cdecl Consoleprintf(const char * format, ...);
DllExport int APIENTRY CloseBPQ32();
DllExport char * APIENTRY GetLOC();
DllExport int APIENTRY SessionControl(int stream, int command, int param);
int DoRefreshWebMailIndex();
BOOL APIENTRY Init_IP();
BOOL APIENTRY Poll_IP();
BOOL APIENTRY Init_PM();
BOOL APIENTRY Poll_PM();
BOOL APIENTRY Init_APRS();
BOOL APIENTRY Poll_APRS();
VOID HTTPTimer();
BOOL APIENTRY Rig_Init();
BOOL APIENTRY Rig_Close();
BOOL Rig_Poll();
VOID IPClose();
VOID APRSClose();
VOID CloseTNCEmulator();
VOID Poll_AGW();
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;
BOOL EventsEnabled = 0;
unsigned int TimerInst = 0xffffffff;
HANDLE hInstance = 0;
int AttachedProcesses = 0;
int AttachingProcess = 0;
HINSTANCE hIPModule = 0;
HINSTANCE hRigModule = 0;
BOOL ReconfigFlag = FALSE;
BOOL RigReconfigFlag = FALSE;
BOOL APRSReconfigFlag = FALSE;
BOOL CloseAllNeeded = FALSE;
BOOL NeedWebMailRefresh = FALSE;
int AttachedPIDList[100] = {0};
HWND hWndArray[100] = {0};
int PIDArray[100] = {0};
char PopupText[30][100] = {""};
// Next 3 should be uninitialised so they are local to each process
UCHAR MCOM;
UCHAR MTX; // Top bit indicates use local time
uint64_t MMASK;
UCHAR MUIONLY;
UCHAR AuthorisedProgram; // Local Variable. Set if Program is on secure list
char pgm[256]; // Uninitialised so per process
HANDLE Mutex;
BOOL PartLine = FALSE;
int pindex = 0;
DWORD * WritetoConsoleQ;
LARGE_INTEGER lpFrequency = {0};
LARGE_INTEGER lastRunTime;
LARGE_INTEGER currentTime;
int ticksPerMillisec;
int interval;
VOID CALLBACK SetupTermSessions(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime);
TIMERPROC lpTimerFunc = (TIMERPROC) TimerProc;
TIMERPROC lpSetupTermSessions = (TIMERPROC) SetupTermSessions;
BOOL ProcessConfig();
VOID FreeConfig();
DllExport int APIENTRY WritetoConsole(char * buff);
BOOLEAN CheckifBPQ32isLoaded();
BOOLEAN StartBPQ32();
DllExport VOID APIENTRY Send_AX(VOID * Block, DWORD len, UCHAR Port);
BOOL LoadIPDriver();
BOOL Send_IP(VOID * Block, DWORD len);
VOID CheckforLostProcesses();
BOOL LoadRigDriver();
VOID SaveConfig();
VOID CreateRegBackup();
VOID ResolveUpdateThread();
VOID OpenReportingSockets();
DllExport VOID APIENTRY CloseAllPrograms();
DllExport BOOL APIENTRY SaveReg(char * KeyIn, HANDLE hFile);
int upnpClose();
BOOL IPActive = FALSE;
extern BOOL IPRequired;
BOOL PMActive = FALSE;
extern BOOL PMRequired;
BOOL RigRequired = TRUE;
BOOL RigActive = FALSE;
BOOL APRSActive = FALSE;
BOOL AGWActive = FALSE;
BOOL needAIS = FALSE;
int needADSB = 0;
extern int AGWPort;
Tell_Sessions();
typedef int (WINAPI FAR *FARPROCX)();
FARPROCX CreateToolHelp32SnapShotPtr;
FARPROCX Process32Firstptr;
FARPROCX Process32Nextptr;
void LoadToolHelperRoutines()
{
HINSTANCE ExtDriver=0;
int err;
char msg[100];
ExtDriver=LoadLibrary("kernel32.dll");
if (ExtDriver == NULL)
{
err=GetLastError();
sprintf(msg,"BPQ32 Error loading kernel32.dll - Error code %d\n", err);
OutputDebugString(msg);
return;
}
CreateToolHelp32SnapShotPtr = (FARPROCX)GetProcAddress(ExtDriver,"CreateToolhelp32Snapshot");
Process32Firstptr = (FARPROCX)GetProcAddress(ExtDriver,"Process32First");
Process32Nextptr = (FARPROCX)GetProcAddress(ExtDriver,"Process32Next");
if (CreateToolHelp32SnapShotPtr == 0)
{
err=GetLastError();
sprintf(msg,"BPQ32 Error getting CreateToolhelp32Snapshot entry point - Error code %d\n", err);
OutputDebugString(msg);
return;
}
}
BOOL GetProcess(int ProcessID, char * Program)
{
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
int p;
if (CreateToolHelp32SnapShotPtr==0)
{
return (TRUE); // Routine not available
}
// Take a snapshot of all processes in the system.
hProcessSnap = (HANDLE)CreateToolHelp32SnapShotPtr(TH32CS_SNAPPROCESS, 0);
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
OutputDebugString( "CreateToolhelp32Snapshot (of processes) Failed\n" );
return( FALSE );
}
// Set the size of the structure before using it.
pe32.dwSize = sizeof( PROCESSENTRY32 );
// Retrieve information about the first process,
// and exit if unsuccessful
if( !Process32Firstptr( hProcessSnap, &pe32 ) )
{
OutputDebugString( "Process32First Failed\n" ); // Show cause of failure
CloseHandle( hProcessSnap ); // Must clean up the snapshot object!
return( FALSE );
}
// Now walk the snapshot of processes, and
// display information about each process in turn
do
{
if (ProcessID==pe32.th32ProcessID)
{
// if running on 98, program contains the full path - remove it
for (p = (int)strlen(pe32.szExeFile); p >= 0; p--)
{
if (pe32.szExeFile[p]=='\\')
{
break;
}
}
p++;
sprintf(Program,"%s", &pe32.szExeFile[p]);
CloseHandle( hProcessSnap );
return( TRUE );
}
} while( Process32Nextptr( hProcessSnap, &pe32 ) );
sprintf(Program,"PID %d Not Found", ProcessID);
CloseHandle( hProcessSnap );
return(FALSE);
}
BOOL IsProcess(int ProcessID)
{
// Check that Process exists
HANDLE hProcessSnap;
PROCESSENTRY32 pe32;
if (CreateToolHelp32SnapShotPtr==0) return (TRUE); // Routine not available
hProcessSnap = (HANDLE)CreateToolHelp32SnapShotPtr(TH32CS_SNAPPROCESS, 0);
if( hProcessSnap == INVALID_HANDLE_VALUE )
{
OutputDebugString( "CreateToolhelp32Snapshot (of processes) Failed\n" );
return(TRUE); // Don't know, so assume ok
}
pe32.dwSize = sizeof( PROCESSENTRY32 );
if( !Process32Firstptr( hProcessSnap, &pe32 ) )
{
OutputDebugString( "Process32First Failed\n" ); // Show cause of failure
CloseHandle( hProcessSnap ); // Must clean up the snapshot object!
return(TRUE); // Don't know, so assume ok
}
do
{
if (ProcessID==pe32.th32ProcessID)
{
CloseHandle( hProcessSnap );
return( TRUE );
}
} while( Process32Nextptr( hProcessSnap, &pe32 ) );
CloseHandle( hProcessSnap );
return(FALSE);
}
#include "DbgHelp.h"
VOID MonitorThread(int x)
{
// Thread to detect killed processes. Runs in process owning timer.
// Obviously can't detect loss of timer owning thread!
do
{
if (Semaphore.Gets == LastSemGets && Semaphore.Flag)
{
// It is stuck - try to release
Debugprintf ("Semaphore locked - Process ID = %d, Held By %d",
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(&currentTime);
interval = (int)(currentTime.QuadPart - lastRunTime.QuadPart) / ticksPerMillisec;
lastRunTime.QuadPart = currentTime.QuadPart;
//Debugprintf("%d", interval);
// Process WINMORTraceQ
while (WINMORTraceQ)
{
UINT * Buffer = Q_REM(&WINMORTraceQ);
struct TNCINFO * TNC = (struct TNCINFO * )Buffer[1];
int Len = Buffer[2];
char * Msg = (char *)&Buffer[3];
WritetoTraceSupport(TNC, Msg, Len);
RelBuff(Buffer);
}
if (SetWindowTextQ)
SetWindowTextSupport();
while (WritetoConsoleQ)
{
UINT * Buffer = Q_REM(&WritetoConsoleQ);
WritetoConsoleSupport((char *)&Buffer[2]);
RelBuff(Buffer);
}
strcpy(EXCEPTMSG, "Timer ReconfigProcessing");
__try
{
if (trayMenu == NULL)
SetupTrayIcon();
// See if reconfigure requested
if (CloseAllNeeded)
{
CloseAllNeeded = FALSE;
CloseAllPrograms();
}
if (ReconfigFlag)
{
// Only do it it timer owning process, or we could get in a real mess!
if(TimerInst == GetCurrentProcessId())
{
int i;
BPQVECSTRUC * HOSTVEC;
PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
WSADATA WsaData; // receives data from WSAStartup
RECT cRect;
ReconfigFlag = FALSE;
SetupBPQDirectory();
WritetoConsole("Reconfiguring ...\n\n");
OutputDebugString("BPQ32 Reconfiguring ...\n");
GetWindowRect(FrameWnd, &FRect);
SaveWindowPos(70); // Rigcontrol
for (i=0;i<NUMBEROFPORTS;i++)
{
if (PORTVEC->PORTCONTROL.PORTTYPE == 0x10) // External
{
if (PORTVEC->PORT_EXT_ADDR)
{
SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
CloseDriverWindow(PORTVEC->PORTCONTROL.PORTNUMBER);
PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL); // Close External Ports
}
}
PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL);
PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
}
IPClose();
PMClose();
APRSClose();
Rig_Close();
CloseTNCEmulator();
if (AGWActive)
AGWAPITerminate();
WSACleanup();
WL2KReports = NULL;
Sleep(2000);
WSAStartup(MAKEWORD(2, 0), &WsaData);
Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring);
Consoleprintf(VerCopyright);
Start();
INITIALISEPORTS(); // Restart Ports
SetApplPorts();
FreeConfig();
for (i=1; i<68; i++) // Include Telnet, APRS and IP Vec
{
HOSTVEC=&BPQHOSTVECTOR[i-1];
HOSTVEC->HOSTTRACEQ=0; // Clear header (pool has been reinitialized
if (HOSTVEC->HOSTSESSION !=0)
{
// Had a connection
HOSTVEC->HOSTSESSION=0;
HOSTVEC->HOSTFLAGS |=3; // Disconnected
PostMessage(HOSTVEC->HOSTHANDLE, BPQMsg, i, 4);
}
}
// Free the APRS Appl Q
APPL_Q = 0;
OpenReportingSockets();
WritetoConsole("\n\nReconfiguration Complete\n");
if (IPRequired) IPActive = Init_IP();
if (PMRequired) PMActive = Init_PM();
APRSActive = Init_APRS();
if (ISPort == 0)
IGateEnabled = 0;
CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled);
GetClientRect(hConsWnd, &cRect);
MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
if (APRSActive)
MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
else
{
ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE);
MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
}
InvalidateRect(hConsWnd, NULL, TRUE);
RigActive = Rig_Init();
if (NUMBEROFTNCPORTS)
{
FreeSemaphore(&Semaphore);
InitializeTNCEmulator();
GetSemaphore(&Semaphore, 0);
}
FreeSemaphore(&Semaphore);
AGWActive = AGWAPIInit();
GetSemaphore(&Semaphore, 0);
OutputDebugString("BPQ32 Reconfiguration Complete\n");
}
}
if (RigReconfigFlag)
{
// Only do it it timer owning process, or we could get in a real mess!
if(TimerInst == GetCurrentProcessId())
{
RigReconfigFlag = FALSE;
CloseDriverWindow(70);
Rig_Close();
Sleep(6000); // Allow any CATPTT, HAMLIB and FLRIG threads to close
RigActive = Rig_Init();
WritetoConsole("Rigcontrol Reconfiguration Complete\n");
}
}
if (APRSReconfigFlag)
{
// Only do it it timer owning process, or we could get in a real mess!
if(TimerInst == GetCurrentProcessId())
{
APRSReconfigFlag = FALSE;
APRSClose();
APRSActive = Init_APRS();
WritetoConsole("APRS Reconfiguration Complete\n");
}
}
}
#include "StdExcept.c"
if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId())
FreeSemaphore(&Semaphore);
}
strcpy(EXCEPTMSG, "Timer Processing");
__try
{
if (IPActive) Poll_IP();
if (PMActive) Poll_PM();
if (RigActive) Rig_Poll();
if (NeedWebMailRefresh)
DoRefreshWebMailIndex();
CheckGuardZone();
if (APRSActive)
{
Poll_APRS();
CheckGuardZone();
}
CheckWL2KReportTimer();
CheckGuardZone();
TIMERINTERRUPT();
CheckGuardZone();
FreeSemaphore(&Semaphore); // SendLocation needs to get the semaphore
if (NUMBEROFTNCPORTS)
TNCTimer();
if (AGWActive)
Poll_AGW();
DRATSPoll();
CheckGuardZone();
strcpy(EXCEPTMSG, "HTTP Timer Processing");
HTTPTimer();
CheckGuardZone();
strcpy(EXCEPTMSG, "WL2K Report Timer Processing");
if (ReportTimer)
{
ReportTimer--;
if (ReportTimer == 0)
{
ReportTimer = REPORTINTERVAL;
SendLocation();
}
}
}
#include "StdExcept.c"
if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId())
FreeSemaphore(&Semaphore);
}
CheckGuardZone();
return;
}
HANDLE NPHandle;
int (WINAPI FAR *GetModuleFileNameExPtr)() = NULL;
int (WINAPI FAR *EnumProcessesPtr)() = NULL;
FirstInit()
{
WSADATA WsaData; // receives data from WSAStartup
HINSTANCE ExtDriver=0;
RECT cRect;
// First Time Ports and Timer init
// Moved from DLLINIT to sort out perl problem, and meet MS Guidelines on minimising DLLMain
// Call wsastartup - most systems need winsock, and duplicate statups could be a problem
WSAStartup(MAKEWORD(2, 0), &WsaData);
// Load Psapi.dll if possible
ExtDriver=LoadLibrary("Psapi.dll");
SetupTrayIcon();
if (ExtDriver)
{
GetModuleFileNameExPtr = (FARPROCX)GetProcAddress(ExtDriver,"GetModuleFileNameExA");
EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses");
}
timeLoadedMS = GetTickCount();
INITIALISEPORTS();
OpenReportingSockets();
WritetoConsole("\n");
WritetoConsole("Port Initialisation Complete\n");
if (IPRequired) IPActive = Init_IP();
if (PMRequired) PMActive = Init_PM();
APRSActive = Init_APRS();
if (APRSActive)
{
hWndBG = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 0,0,40,546, hConsWnd, NULL, hInstance, NULL);
CreateWindowEx(0, "STATIC", "Enable IGate", WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE,
8,0,90,24, hConsWnd, (HMENU)-1, hInstance, NULL);
CreateWindowEx(0, "BUTTON", "", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,
95,1,18,24, hConsWnd, (HMENU)IDC_ENIGATE, hInstance, NULL);
CreateWindowEx(0, "STATIC", "IGate State - Disconnected",
WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 125, 0, 195, 24, hConsWnd, (HMENU)IGATESTATE, hInstance, NULL);
CreateWindowEx(0, "STATIC", "IGATE Stats - Msgs 0 Local Stns 0",
WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 320, 0, 240, 24, hConsWnd, (HMENU)IGATESTATS, hInstance, NULL);
CreateWindowEx(0, "STATIC", "GPS Off",
WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 560, 0, 80, 24, hConsWnd, (HMENU)IDC_GPS, hInstance, NULL);
}
if (ISPort == 0)
IGateEnabled = 0;
CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled);
GetClientRect(hConsWnd, &cRect);
MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
if (APRSActive)
MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
else
{
ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE);
MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
}
InvalidateRect(hConsWnd, NULL, TRUE);
RigActive = Rig_Init();
_beginthread(MonitorThread,0,0);
TimerHandle=SetTimer(NULL,0,100,lpTimerFunc);
TimerInst=GetCurrentProcessId();
SessHandle = SetTimer(NULL, 0, 5000, lpSetupTermSessions);
// If ARIF reporting is enabled write a Trimode Like ini for RMS Analyser
if (ADIFLogEnabled)
ADIFWriteFreqList();
OutputDebugString("BPQ32 Port Initialisation Complete\n");
if (needAIS)
initAIS();
if (needADSB)
initADSB();
return 0;
}
Check_Timer()
{
if (Closing)
return 0;
if (Semaphore.Flag)
return 0;
if (InitDone == (void *)-1)
{
GetSemaphore(&Semaphore, 3);
Sleep(15000);
FreeSemaphore(&Semaphore);
exit (0);
}
if (FirstInitDone == 0)
{
GetSemaphore(&Semaphore, 3);
if (_stricmp(pgm, "bpq32.exe") == 0)
{
FirstInit();
FreeSemaphore(&Semaphore);
if (NUMBEROFTNCPORTS)
InitializeTNCEmulator();
AGWActive = AGWAPIInit();
FirstInitDone=1; // Only init in BPQ32.exe
return 0;
}
else
{
FreeSemaphore(&Semaphore);
return 0;
}
}
if (TimerHandle == 0 && FirstInitDone == 1)
{
WSADATA WsaData; // receives data from WSAStartup
HINSTANCE ExtDriver=0;
RECT cRect;
// Only attach timer to bpq32.exe
if (_stricmp(pgm, "bpq32.exe") != 0)
{
return 0;
}
GetSemaphore(&Semaphore, 3);
OutputDebugString("BPQ32 Reinitialising External Ports and Attaching Timer\n");
if (!ProcessConfig())
{
ShowWindow(hConsWnd, SW_RESTORE);
SendMessage(hConsWnd, WM_PAINT, 0, 0);
SetForegroundWindow(hConsWnd);
InitDone = (void *)-1;
FreeSemaphore(&Semaphore);
MessageBox(NULL,"Configuration File Error","BPQ32",MB_ICONSTOP);
exit (0);
}
GetVersionInfo("bpq32.dll");
SetupConsoleWindow();
Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring);
Consoleprintf(VerCopyright);
Consoleprintf("Reinitialising...");
SetupBPQDirectory();
Sleep(1000); // Allow time for sockets to close
WSAStartup(MAKEWORD(2, 0), &WsaData);
// Load Psapi.dll if possible
ExtDriver = LoadLibrary("Psapi.dll");
SetupTrayIcon();
if (ExtDriver)
{
GetModuleFileNameExPtr = (FARPROCX)GetProcAddress(ExtDriver,"GetModuleFileNameExA");
EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses");
}
Start();
INITIALISEPORTS();
OpenReportingSockets();
NODESINPROGRESS = 0;
CURRENTNODE = 0;
SetApplPorts();
WritetoConsole("\n\nPort Reinitialisation Complete\n");
BPQMsg = RegisterWindowMessage(BPQWinMsg);
CreateMutex(NULL,TRUE,"BPQLOCKMUTEX");
// NPHandle=CreateNamedPipe("\\\\.\\pipe\\BPQ32pipe",
// PIPE_ACCESS_DUPLEX,0,64,4096,4096,1000,NULL);
if (IPRequired) IPActive = Init_IP();
if (PMRequired) PMActive = Init_PM();
RigActive = Rig_Init();
APRSActive = Init_APRS();
if (ISPort == 0)
IGateEnabled = 0;
CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled);
GetClientRect(hConsWnd, &cRect);
MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
if (APRSActive)
MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
else
{
ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE);
MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
}
InvalidateRect(hConsWnd, NULL, TRUE);
FreeConfig();
_beginthread(MonitorThread,0,0);
ReportTimer = 0;
OpenReportingSockets();
FreeSemaphore(&Semaphore);
if (NUMBEROFTNCPORTS)
InitializeTNCEmulator();
AGWActive = AGWAPIInit();
if (StartMinimized)
if (MinimizetoTray)
ShowWindow(FrameWnd, SW_HIDE);
else
ShowWindow(FrameWnd, SW_SHOWMINIMIZED);
else
ShowWindow(FrameWnd, SW_RESTORE);
TimerHandle=SetTimer(NULL,0,100,lpTimerFunc);
TimerInst=GetCurrentProcessId();
SessHandle = SetTimer(NULL, 0, 5000, lpSetupTermSessions);
return (1);
}
return (0);
}
DllExport INT APIENTRY CheckTimer()
{
return Check_Timer();
}
Tell_Sessions()
{
//
// Post a message to all listening sessions, so they call the
// API, and cause a new timer to be allocated
//
HWND hWnd;
int i;
for (i=1;i<65;i++)
{
if (BPQHOSTVECTOR[i-1].HOSTFLAGS & 0x80)
{
hWnd = BPQHOSTVECTOR[i-1].HOSTHANDLE;
PostMessage(hWnd, BPQMsg,i, 1);
PostMessage(hWnd, BPQMsg,i, 2);
}
}
return (0);
}
BOOL APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID lpReserved)
{
DWORD n;
char buf[350];
int i;
unsigned int ProcessID;
OSVERSIONINFO osvi;
memset(&osvi, 0, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
switch( ul_reason_being_called )
{
case DLL_PROCESS_ATTACH:
if (sizeof(HDLCDATA) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata
{
// Catastrophic - Refuse to load
MessageBox(NULL,"BPQ32 Too much HDLC data - Recompile","BPQ32", MB_OK);
return 0;
}
if (sizeof(struct KISSINFO) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata
{
// Catastrophic - Refuse to load
MessageBox(NULL,"BPQ32 Too much KISS data - Recompile","BPQ32", MB_OK);
return 0;
}
if (sizeof(struct _EXTPORTDATA) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata
{
// Catastrophic - Refuse to load
MessageBox(NULL,"BPQ32 Too much _EXTPORTDATA data - Recompile","BPQ32", MB_OK);
return 0;
}
if (sizeof(LINKTABLE) != LINK_TABLE_LEN)
{
// Catastrophic - Refuse to load
MessageBox(NULL,"L2 LINK Table .c and .asm mismatch - fix and rebuild","BPQ32", MB_OK);
return 0;
}
if (sizeof(struct ROUTE) != ROUTE_LEN)
{
// Catastrophic - Refuse to load
MessageBox(NULL,"ROUTE Table .c and .asm mismatch - fix and rebuild", "BPQ32", MB_OK);
return 0;
}
if (sizeof(struct DEST_LIST) != DEST_LIST_LEN)
{
// Catastrophic - Refuse to load
MessageBox(NULL,"NODES Table .c and .asm mismatch - fix and rebuild", "BPQ32", MB_OK);
return 0;
}
GetSemaphore(&Semaphore, 4);
BPQHOSTVECPTR = &BPQHOSTVECTOR[0];
LoadToolHelperRoutines();
Our_PID = GetCurrentProcessId();
QueryPerformanceFrequency(&lpFrequency);
ticksPerMillisec = (int)lpFrequency.QuadPart / 1000;
lastRunTime.QuadPart = lpFrequency.QuadPart;
GetProcess(Our_PID, pgm);
if (_stricmp(pgm, "regsvr32.exe") == 0 || _stricmp(pgm, "bpqcontrol.exe") == 0)
{
AttachedProcesses++; // We will get a detach
FreeSemaphore(&Semaphore);
return 1;
}
if (_stricmp(pgm,"BPQ32.exe") == 0)
BPQ32_EXE = TRUE;
if (_stricmp(pgm,"BPQMailChat.exe") == 0)
IncludesMail = TRUE;
if (_stricmp(pgm,"BPQMail.exe") == 0)
IncludesMail = TRUE;
if (_stricmp(pgm,"BPQChat.exe") == 0)
IncludesChat = TRUE;
if (FirstEntry) // If loaded by BPQ32.exe, dont close it at end
{
FirstEntry = 0;
if (BPQ32_EXE)
CloseLast = FALSE;
}
else
{
if (BPQ32_EXE && AttachingProcess == 0)
{
AttachedProcesses++; // We will get a detach
FreeSemaphore(&Semaphore);
MessageBox(NULL,"BPQ32.exe is already running\r\n\r\nIt should only be run once", "BPQ32", MB_OK);
return 0;
}
}
if (_stricmp(pgm,"BPQTelnetServer.exe") == 0)
{
MessageBox(NULL,"BPQTelnetServer is no longer supported\r\n\r\nUse the TelnetServer in BPQ32.dll", "BPQ32", MB_OK);
AttachedProcesses++; // We will get a detach
FreeSemaphore(&Semaphore);
return 0;
}
if (_stricmp(pgm,"BPQUIUtil.exe") == 0)
{
MessageBox(NULL,"BPQUIUtil is now part of BPQ32.dll\r\nBPQUIUtil.exe cannot be run\r\n", "BPQ32", MB_OK);
AttachedProcesses++; // We will get a detach
FreeSemaphore(&Semaphore);
return 0;
}
if (_stricmp(pgm,"BPQMailChat.exe") == 0)
{
MessageBox(NULL,"BPQMailChat is obsolete. Run BPQMail.exe and/or BPQChat.exe instead", "BPQ32", MB_OK);
AttachedProcesses++; // We will get a detach
FreeSemaphore(&Semaphore);
return 0;
}
AuthorisedProgram = TRUE;
if (InitDone == 0)
{
// #pragma warning(push)
// #pragma warning(disable : 4996)
// if (_winver < 0x0600)
// #pragma warning(pop)
// {
// // Below Vista
//
// REGTREE = HKEY_LOCAL_MACHINE;
// strcpy(REGTREETEXT, "HKEY_LOCAL_MACHINE");
// }
hInstance=hInst;
Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX");
if (Mutex != NULL)
{
OutputDebugString("Another BPQ32.dll is loaded\n");
i=MessageBox(NULL,"BPQ32 DLL already loaded from another directory\nIf you REALLY want this, hit OK, else hit Cancel","BPQ32",MB_OKCANCEL);
FreeSemaphore(&Semaphore);
if (i != IDOK) return (0);
CloseHandle(Mutex);
}
if (!BPQ32_EXE)
{
if (CheckifBPQ32isLoaded() == FALSE) // Start BPQ32.exe if needed
{
// Wasn't Loaded, so we have started it, and should let it init system
goto SkipInit;
}
}
GetVersionInfo("bpq32.dll");
sprintf (SIGNONMSG, "G8BPQ AX25 Packet Switch System Version %s %s\r\n%s\r\n",
TextVerstring, Datestring, VerCopyright);
SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for Win32 (", TextVerstring);
SetupConsoleWindow();
SetupBPQDirectory();
if (!ProcessConfig())
{
StartMinimized = FALSE;
MinimizetoTray = FALSE;
ShowWindow(FrameWnd, SW_MAXIMIZE);
ShowWindow(hConsWnd, SW_MAXIMIZE);
ShowWindow(StatusWnd, SW_HIDE);
SendMessage(hConsWnd, WM_PAINT, 0, 0);
SetForegroundWindow(hConsWnd);
InitDone = (void *)-1;
FreeSemaphore(&Semaphore);
MessageBox(NULL,"Configuration File Error\r\nProgram will close in 15 seconds","BPQ32",MB_ICONSTOP);
return (0);
}
Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring);
Consoleprintf(VerCopyright);
if (Start() !=0)
{
Sleep(3000);
FreeSemaphore(&Semaphore);
return (0);
}
else
{
SetApplPorts();
GetUIConfig();
InitDone = &InitDone;
BPQMsg = RegisterWindowMessage(BPQWinMsg);
// TimerHandle=SetTimer(NULL,0,100,lpTimerFunc);
// TimerInst=GetCurrentProcessId();
/* Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX");
if (Mutex != NULL)
{
OutputDebugString("Another BPQ32.dll is loaded\n");
MessageBox(NULL,"BPQ32 DLL already loaded from another directory","BPQ32",MB_ICONSTOP);
FreeSemaphore(&Semaphore);
return (0);
}
*/
Mutex=CreateMutex(NULL,TRUE,"BPQLOCKMUTEX");
// CreatePipe(&H1,&H2,NULL,1000);
// GetLastError();
// NPHandle=CreateNamedPipe("\\\\.\\pipe\\BPQ32pipe",
// PIPE_ACCESS_DUPLEX,0,64,4096,4096,1000,NULL);
// GetLastError();
/*
//
// Read SYSOP password
//
if (PWTEXT[0] == 0)
{
handle = OpenConfigFile("PASSWORD.BPQ");
if (handle == INVALID_HANDLE_VALUE)
{
WritetoConsole("Can't open PASSWORD.BPQ\n");
PWLen=0;
PWTEXT[0]=0;
}
else
{
ReadFile(handle,PWTEXT,78,&n,NULL);
CloseHandle(handle);
}
}
*/
for (i=0;PWTEXT[i] > 0x20;i++); //Scan for cr or null
PWLen=i;
}
}
else
{
if (InitDone != &InitDone)
{
MessageBox(NULL,"BPQ32 DLL already loaded at another address","BPQ32",MB_ICONSTOP);
FreeSemaphore(&Semaphore);
return (0);
}
}
// Run timer monitor thread in all processes - it is possible for the TImer thread not to be the first thread
SkipInit:
_beginthread(MonitorTimerThread,0,0);
FreeSemaphore(&Semaphore);
AttachedPIDList[AttachedProcesses++] = GetCurrentProcessId();
if (_stricmp(pgm,"bpq32.exe") == 0 && AttachingProcess == 1) AttachingProcess = 0;
GetProcess(GetCurrentProcessId(),pgm);
n=sprintf(buf,"BPQ32 DLL Attach complete - Program %s - %d Process(es) Attached\n",pgm,AttachedProcesses);
OutputDebugString(buf);
// Set up local variables
MCOM=1;
MTX=1;
MMASK=0xffffffffffffffff;
// if (StartMinimized)
// if (MinimizetoTray)
// ShowWindow(FrameWnd, SW_HIDE);
// else
// ShowWindow(FrameWnd, SW_SHOWMINIMIZED);
// else
// ShowWindow(FrameWnd, SW_RESTORE);
return 1;
case DLL_THREAD_ATTACH:
return 1;
case DLL_THREAD_DETACH:
return 1;
case DLL_PROCESS_DETACH:
if (_stricmp(pgm,"BPQMailChat.exe") == 0)
IncludesMail = FALSE;
if (_stricmp(pgm,"BPQChat.exe") == 0)
IncludesChat = FALSE;
ProcessID=GetCurrentProcessId();
Debugprintf("BPQ32 Process %d Detaching", ProcessID);
// Release any streams that the app has failed to release
for (i=1;i<65;i++)
{
if (BPQHOSTVECTOR[i-1].STREAMOWNER == ProcessID)
{
// If connected, disconnect
SessionControl(i, 2, 0);
DeallocateStream(i);
}
}
// Remove any Tray Icon Entries
for( i = 0; i < 100; ++i )
{
if (PIDArray[i] == ProcessID)
{
char Log[80];
hWndArray[i] = 0;
sprintf(Log,"BPQ32 Removing Tray Item %s\n", PopupText[i]);
OutputDebugString(Log);
DeleteMenu(trayMenu,TRAYBASEID+i,MF_BYCOMMAND);
}
}
if (Mutex) CloseHandle(Mutex);
// Remove our entry from PID List
for (i=0; i< AttachedProcesses; i++)
if (AttachedPIDList[i] == ProcessID)
break;
for (; i< AttachedProcesses; i++)
{
AttachedPIDList[i]=AttachedPIDList[i+1];
}
AttachedProcesses--;
if (TimerInst == ProcessID)
{
PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
OutputDebugString("BPQ32 Process with Timer closing\n");
// Call Port Close Routines
for (i=0;i<NUMBEROFPORTS;i++)
{
if (PORTVEC->PORTCONTROL.PORTTYPE == 0x10) // External
{
if (PORTVEC->PORT_EXT_ADDR && PORTVEC->DLLhandle == NULL) // Don't call if real .dll - it's not there!
{
SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL); // Close External Ports
}
}
PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL);
PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
}
IPClose();
PMClose();
APRSClose();
Rig_Close();
CloseTNCEmulator();
if (AGWActive)
AGWAPITerminate();
upnpClose();
WSACleanup();
WSAGetLastError();
if (MinimizetoTray)
Shell_NotifyIcon(NIM_DELETE,&niData);
if (hConsWnd) DestroyWindow(hConsWnd);
KillTimer(NULL,TimerHandle);
TimerHandle=0;
TimerInst=0xffffffff;
if (AttachedProcesses && Closing == FALSE && AttachingProcess == 0) // Other processes
{
OutputDebugString("BPQ32 Reloading BPQ32.exe\n");
StartBPQ32();
}
}
else
{
// Not Timer Process
if (AttachedProcesses == 1 && CloseLast) // Only bpq32.exe left
{
Debugprintf("Only BPQ32.exe running - close it");
CloseAllNeeded = TRUE;
}
}
if (AttachedProcesses < 2)
{
if (AUTOSAVE)
SaveNodes();
if (AUTOSAVEMH)
SaveMH();
if (needAIS)
SaveAIS();
}
if (AttachedProcesses == 0)
{
Closing = TRUE;
KillTimer(NULL,TimerHandle);
if (MinimizetoTray)
Shell_NotifyIcon(NIM_DELETE,&niData);
// Unload External Drivers
{
PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
for (i=0;i<NUMBEROFPORTS;i++)
{
if (PORTVEC->PORTCONTROL.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;i<NUMBEROFPORTS;i++)
{
if (PORTVEC->PORTCONTROL.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];
/*
<EFBFBD>NT4 was/is '4'
<EFBFBD>Win 95 is 4.00.950
<EFBFBD>Win 98 is 4.10.1998
<EFBFBD>Win 98 SE is 4.10.2222
<EFBFBD>Win ME is 4.90.3000
<EFBFBD>2000 is NT 5.0.2195
<EFBFBD>XP is actually 5.1
<EFBFBD>Vista is 6.0
<EFBFBD>Win7 is 6.1
i = _osver; / Build
i = _winmajor;
i = _winminor;
*/
/*
#pragma warning(push)
#pragma warning(disable : 4996)
if (_winver < 0x0600)
#pragma warning(pop)
{
// Below Vista
REGTREE = HKEY_LOCAL_MACHINE;
strcpy(REGTREETEXT, "HKEY_LOCAL_MACHINE");
ValfromReg[0] = 0;
}
else
*/
{
if (_stricmp(pgm, "regsvr32.exe") == 0)
{
Debugprintf("BPQ32 loaded by regsvr32.exe - Registry not copied");
}
else
{
// If necessary, move reg from HKEY_LOCAL_MACHINE to HKEY_CURRENT_USER
retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
"SOFTWARE\\G8BPQ\\BPQ32",
0,
KEY_READ,
&hKeyIn);
retCode = RegCreateKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKeyOut, &disp);
// See if Version Key exists in HKEY_CURRENT_USER - if it does, we have already done the copy
Vallen = MAX_PATH;
retCode = RegQueryValueEx(hKeyOut, "Version" ,0 , &Type,(UCHAR *)&msg, &Vallen);
if (retCode != ERROR_SUCCESS)
if (hKeyIn)
CopyReg(hKeyIn, hKeyOut);
RegCloseKey(hKeyIn);
RegCloseKey(hKeyOut);
}
}
GetModuleFileName(hInstance,DLLName,256);
BPQDirectory[0]=0;
retCode = RegOpenKeyEx (REGTREE,
"SOFTWARE\\G8BPQ\\BPQ32",
0,
KEY_QUERY_VALUE,
&hKey);
if (retCode == ERROR_SUCCESS)
{
// Try "BPQ Directory"
Vallen = MAX_PATH;
retCode = RegQueryValueEx(hKey,"BPQ Directory",0,
&Type,(UCHAR *)&ValfromReg,&Vallen);
if (retCode == ERROR_SUCCESS)
{
if (strlen(ValfromReg) == 2 && ValfromReg[0] == '"' && ValfromReg[1] == '"')
ValfromReg[0]=0;
}
if (ValfromReg[0] == 0)
{
// BPQ Directory absent or = "" - try "Config File Location"
Vallen = MAX_PATH;
retCode = RegQueryValueEx(hKey,"Config File Location",0,
&Type,(UCHAR *)&ValfromReg,&Vallen);
if (retCode == ERROR_SUCCESS)
{
if (strlen(ValfromReg) == 2 && ValfromReg[0] == '"' && ValfromReg[1] == '"')
ValfromReg[0]=0;
}
}
if (ValfromReg[0] == 0) GetCurrentDirectory(MAX_PATH, ValfromReg);
// Get StartMinimized and MinimizetoTray flags
Vallen = 4;
retCode = RegQueryValueEx(hKey, "Start Minimized", 0, &Type, (UCHAR *)&StartMinimized, &Vallen);
Vallen = 4;
retCode = RegQueryValueEx(hKey, "Minimize to Tray", 0, &Type, (UCHAR *)&MinimizetoTray, &Vallen);
ExpandEnvironmentStrings(ValfromReg, BPQDirectory, MAX_PATH);
// Also get "BPQ Program Directory"
ValfromReg[0] = 0;
Vallen = MAX_PATH;
retCode = RegQueryValueEx(hKey, "BPQ Program Directory",0 , &Type, (UCHAR *)&ValfromReg, &Vallen);
if (retCode == ERROR_SUCCESS)
ExpandEnvironmentStrings(ValfromReg, BPQProgramDirectory, MAX_PATH);
// And Log Directory
ValfromReg[0] = 0;
Vallen = MAX_PATH;
retCode = RegQueryValueEx(hKey, "Log Directory",0 , &Type, (UCHAR *)&ValfromReg, &Vallen);
if (retCode == ERROR_SUCCESS)
ExpandEnvironmentStrings(ValfromReg, LogDirectory, MAX_PATH);
RegCloseKey(hKey);
}
strcpy(ConfigDirectory, BPQDirectory);
if (LogDirectory[0] == 0)
strcpy(LogDirectory, BPQDirectory);
if (BPQProgramDirectory[0] == 0)
strcpy(BPQProgramDirectory, BPQDirectory);
sprintf(msg,"BPQ32 Ver %s Loaded from: %s by %s\n", VersionString, DLLName, pgm);
WritetoConsole(msg);
OutputDebugString(msg);
FormatTime3(Time, time(NULL));
sprintf(msg,"Loaded %s\n", Time);
WritetoConsole(msg);
OutputDebugString(msg);
#pragma warning(push)
#pragma warning(disable : 4996)
#if _MSC_VER >= 1400
#define _winmajor 6
#define _winminor 0
#endif
i=sprintf(msg,"Windows Ver %d.%d, Using Registry Key %s\n" ,_winmajor, _winminor, REGTREETEXT);
#pragma warning(pop)
WritetoConsole(msg);
OutputDebugString(msg);
i=sprintf(msg,"BPQ32 Using config from: %s\n\n",BPQDirectory);
WritetoConsole(&msg[6]);
msg[i-1]=0;
OutputDebugString(msg);
// Don't write the Version Key if loaded by regsvr32.exe (Installer is running with Admin rights,
// so will write the wrong tree on )
if (_stricmp(pgm, "regsvr32.exe") == 0)
{
Debugprintf("BPQ32 loaded by regsvr32.exe - Version String not written");
}
else
{
retCode = RegCreateKeyEx(REGTREE, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp);
sprintf(msg,"%d,%d,%d,%d", Ver[0], Ver[1], Ver[2], Ver[3]);
retCode = RegSetValueEx(hKey, "Version",0, REG_SZ,(BYTE *)msg, strlen(msg) + 1);
RegCloseKey(hKey);
}
// Make sure Logs Directory exists
sprintf(LogDir, "%s/Logs", LogDirectory);
CreateDirectory(LogDir, NULL);
return;
}
HANDLE OpenConfigFile(char *fn)
{
HANDLE handle;
UCHAR Value[MAX_PATH];
FILETIME LastWriteTime;
SYSTEMTIME Time;
char Msg[256];
// If no directory, use current
if (BPQDirectory[0] == 0)
{
strcpy(Value,fn);
}
else
{
strcpy(Value,BPQDirectory);
strcat(Value,"\\");
strcat(Value,fn);
}
handle = CreateFile(Value,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
GetFileTime(handle, NULL, NULL, &LastWriteTime);
FileTimeToSystemTime(&LastWriteTime, &Time);
sprintf(Msg,"BPQ32 Config File %s Created %.2d:%.2d %d/%.2d/%.2d\n", Value,
Time.wHour, Time.wMinute, Time.wYear, Time.wMonth, Time.wDay);
OutputDebugString(Msg);
return(handle);
}
#ifdef _WIN64
int BPQHOSTAPI()
{
return 0;
}
#endif
DllExport int APIENTRY GETBPQAPI()
{
return (int)BPQHOSTAPI;
}
//DllExport UINT APIENTRY GETMONDECODE()
//{
// return (UINT)MONDECODE;
//}
DllExport INT APIENTRY BPQAPI(int Fn, char * params)
{
/*
;
; BPQ HOST MODE SUPPORT CODE
;
; 22/11/95
;
; MOVED FROM TNCODE.ASM COS CONITIONALS WERE GETTING TOO COMPLICATED
; (OS2 VERSION HAD UPSET KANT VERISON
;
;
*/
/*
BPQHOSTPORT:
;
; SPECIAL INTERFACE, MAINLY FOR EXTERNAL HOST MODE SUPPORT PROGS
;
; COMMANDS SUPPORTED ARE
;
; AH = 0 Get node/switch version number and description. On return
; AH='B',AL='P',BH='Q',BL=' '
; DH = major version number and DL = minor version number.
;
;
; AH = 1 Set application mask to value in DL (or even DX if 16
; applications are ever to be supported).
;
; Set application flag(s) to value in CL (or CX).
; whether user gets connected/disconnected messages issued
; by the node etc.
;
;
; AH = 2 Send frame in ES:SI (length CX)
;
;
; AH = 3 Receive frame into buffer at ES:DI, length of frame returned
; in CX. BX returns the number of outstanding frames still to
; be received (ie. after this one) or zero if no more frames
; (ie. this is last one).
;
;
;
; AH = 4 Get stream status. Returns:
;
; CX = 0 if stream disconnected or CX = 1 if stream connected
; DX = 0 if no change of state since last read, or DX = 1 if
; the connected/disconnected state has changed since
; last read (ie. delta-stream status).
;
;
;
; AH = 6 Session control.
;
; CX = 0 Conneect - _APPLMASK in DL
; CX = 1 connect
; CX = 2 disconnect
; CX = 3 return user to node
;
;
; AH = 7 Get buffer counts for stream. Returns:
;
; AX = number of status change messages to be received
; BX = number of frames queued for receive
; CX = number of un-acked frames to be sent
; DX = number of buffers left in node
; SI = number of trace frames queued for receive
;
;AH = 8 Port control/information. Called with a stream number
; in AL returns:
;
; AL = Radio port on which channel is connected (or zero)
; AH = SESSION TYPE BITS
; BX = L2 paclen for the radio port
; CX = L2 maxframe for the radio port
; DX = L4 window size (if L4 circuit, or zero)
; ES:DI = CALLSIGN
;AH = 9 Fetch node/application callsign & alias. AL = application
; number:
;
; 0 = node
; 1 = BBS
; 2 = HOST
; 3 = SYSOP etc. etc.
;
; Returns string with alias & callsign or application name in
; user's buffer pointed to by ES:SI length CX. For example:
;
; "WORCS:G8TIC" or "TICPMS:G8TIC-10".
;
;
; AH = 10 Unproto transmit frame. Data pointed to by ES:SI, of
; length CX, is transmitted as a HDLC frame on the radio
; port (not stream) in AL.
;
;
; AH = 11 Get Trace (RAW Data) Frame into ES:DI,
; Length to CX, Timestamp to AX
;
;
; AH = 12 Update Switch. At the moment only Beacon Text may be updated
; DX = Function
; 1=update BT. ES:SI, Len CX = Text
; 2=kick off nodes broadcast
;
; AH = 13 Allocate/deallocate stream
; If AL=0, return first free stream
; If AL>0, CL=1, Allocate stream. If aleady allocated,
; return CX nonzero, else allocate, and return CX=0
; If AL>0, CL=2, Release stream
;
;
; AH = 14 Internal Interface for IP Router
;
; Send frame - to NETROM L3 if DL=0
; to L2 Session if DL<>0
;
;
; AH = 15 Get interval timer
*/
switch(Fn)
{
case CHECKLOADED:
params[0]=MAJORVERSION;
params[1]=MINORVERSION;
params[2]=QCOUNT;
return (1);
}
return 0;
}
DllExport int APIENTRY InitSwitch()
{
return (0);
}
/*DllExport int APIENTRY SwitchTimer()
{
GetSemaphore((&Semaphore);
TIMERINTERRUPT();
FreeSemaphore(&Semaphore);
return (0);
}
*/
DllExport int APIENTRY GetFreeBuffs()
{
// Returns number of free buffers
// (BPQHOST function 7 (part)).
return (QCOUNT);
}
DllExport UCHAR * APIENTRY GetNodeCall()
{
return (&MYNODECALL);
}
DllExport UCHAR * APIENTRY GetNodeAlias()
{
return (&MYALIASTEXT[0]);
}
DllExport UCHAR * APIENTRY GetBBSCall()
{
return (UCHAR *)(&APPLCALLTABLE[0].APPLCALL_TEXT);
}
DllExport UCHAR * APIENTRY GetBBSAlias()
{
return (UCHAR *)(&APPLCALLTABLE[0].APPLALIAS_TEXT);
}
DllExport VOID APIENTRY GetApplCallVB(int Appl, char * ApplCall)
{
if (Appl < 1 || Appl > NumberofAppls ) return;
strncpy(ApplCall,(char *)&APPLCALLTABLE[Appl-1].APPLCALL_TEXT, 10);
}
BOOL UpdateNodesForApp(int Appl);
DllExport BOOL APIENTRY SetApplCall(int Appl, char * NewCall)
{
char Call[10]=" ";
int i;
if (Appl < 1 || Appl > NumberofAppls ) return FALSE;
i=strlen(NewCall);
if (i > 10) i=10;
strncpy(Call,NewCall,i);
strncpy((char *)&APPLCALLTABLE[Appl-1].APPLCALL_TEXT,Call,10);
if (!ConvToAX25(Call,APPLCALLTABLE[Appl-1].APPLCALL)) return FALSE;
UpdateNodesForApp(Appl);
return TRUE;
}
DllExport BOOL APIENTRY SetApplAlias(int Appl, char * NewCall)
{
char Call[10]=" ";
int i;
if (Appl < 1 || Appl > NumberofAppls ) return FALSE;
i=strlen(NewCall);
if (i > 10) i=10;
strncpy(Call,NewCall,i);
strncpy((char *)&APPLCALLTABLE[Appl-1].APPLALIAS_TEXT,Call,10);
if (!ConvToAX25(Call,APPLCALLTABLE[Appl-1].APPLALIAS)) return FALSE;
UpdateNodesForApp(Appl);
return TRUE;
}
DllExport BOOL APIENTRY SetApplQual(int Appl, int NewQual)
{
if (Appl < 1 || Appl > NumberofAppls ) return FALSE;
APPLCALLTABLE[Appl-1].APPLQUAL=NewQual;
UpdateNodesForApp(Appl);
return TRUE;
}
BOOL UpdateNodesForApp(int Appl)
{
int App=Appl-1;
int DestLen = sizeof (struct DEST_LIST);
int n = MAXDESTS;
struct DEST_LIST * DEST = APPLCALLTABLE[App].NODEPOINTER;
APPLCALLS * APPL=&APPLCALLTABLE[App];
if (DEST == NULL)
{
// No dest at the moment. If we have valid call and Qual, create an entry
if (APPLCALLTABLE[App].APPLQUAL == 0) return FALSE;
if (APPLCALLTABLE[App].APPLCALL[0] < 41) return FALSE;
GetSemaphore(&Semaphore, 5);
DEST = DESTS;
while (n--)
{
if (DEST->DEST_CALL[0] == 0) // Spare
break;
}
if (n == 0)
{
// no dests
FreeSemaphore(&Semaphore);
return FALSE;
}
NUMBEROFNODES++;
APPL->NODEPOINTER = DEST;
memmove (DEST->DEST_CALL,APPL->APPLCALL,13);
DEST->DEST_STATE=0x80; // SPECIAL ENTRY
DEST->NRROUTE[0].ROUT_QUALITY = (BYTE)APPL->APPLQUAL;
DEST->NRROUTE[0].ROUT_OBSCOUNT = 255;
FreeSemaphore(&Semaphore);
return TRUE;
}
// We have a destination. If Quality is zero, remove it, else update it
if (APPLCALLTABLE[App].APPLQUAL == 0)
{
GetSemaphore(&Semaphore, 6);
REMOVENODE(DEST); // Clear buffers, Remove from Sorted Nodes chain, and zap entry
APPL->NODEPOINTER=NULL;
FreeSemaphore(&Semaphore);
return FALSE;
}
if (APPLCALLTABLE[App].APPLCALL[0] < 41) return FALSE;
GetSemaphore(&Semaphore, 7);
memmove (DEST->DEST_CALL,APPL->APPLCALL,13);
DEST->DEST_STATE=0x80; // SPECIAL ENTRY
DEST->NRROUTE[0].ROUT_QUALITY = (BYTE)APPL->APPLQUAL;
DEST->NRROUTE[0].ROUT_OBSCOUNT = 255;
FreeSemaphore(&Semaphore);
return TRUE;
}
DllExport UCHAR * APIENTRY GetSignOnMsg()
{
return (&SIGNONMSG[0]);
}
DllExport HKEY APIENTRY GetRegistryKey()
{
return REGTREE;
}
DllExport char * APIENTRY GetRegistryKeyText()
{
return REGTREETEXT;;
}
DllExport UCHAR * APIENTRY GetBPQDirectory()
{
while (BPQDirectory[0] == 0)
{
Debugprintf("BPQ Directory not set up - waiting");
Sleep(1000);
}
return (&BPQDirectory[0]);
}
DllExport UCHAR * APIENTRY GetProgramDirectory()
{
return (&BPQProgramDirectory[0]);
}
DllExport UCHAR * APIENTRY GetLogDirectory()
{
return (&LogDirectory[0]);
}
// Version for Visual Basic
DllExport char * APIENTRY CopyBPQDirectory(char * dir)
{
return (strcpy(dir,BPQDirectory));
}
DllExport int APIENTRY GetMsgPerl(int stream, char * msg)
{
int len,count;
GetMsg(stream, msg, &len, &count );
return len;
}
int Rig_Command(int Session, char * Command);
BOOL Rig_CommandInt(int Session, char * Command)
{
return Rig_Command(Session, Command);
}
DllExport int APIENTRY BPQSetHandle(int Stream, HWND hWnd)
{
BPQHOSTVECTOR[Stream-1].HOSTHANDLE=hWnd;
return (0);
}
#define L4USER 0
BPQVECSTRUC * PORTVEC ;
VOID * InitializeExtDriver(PEXTPORTDATA PORTVEC)
{
HINSTANCE ExtDriver=0;
char msg[128];
int err=0;
HKEY hKey=0;
UCHAR Value[MAX_PATH];
// If no directory, use current
if (BPQDirectory[0] == 0)
{
strcpy(Value,PORTVEC->PORT_DLL_NAME);
}
else
{
strcpy(Value,BPQDirectory);
strcat(Value,"\\");
strcat(Value,PORTVEC->PORT_DLL_NAME);
}
// Several Drivers are now built into bpq32.dll
_strupr(Value);
if (strstr(Value, "BPQVKISS"))
return VCOMExtInit;
if (strstr(Value, "BPQAXIP"))
return AXIPExtInit;
if (strstr(Value, "BPQETHER"))
return ETHERExtInit;
if (strstr(Value, "BPQTOAGW"))
return AGWExtInit;
if (strstr(Value, "AEAPACTOR"))
return AEAExtInit;
if (strstr(Value, "HALDRIVER"))
return HALExtInit;
if (strstr(Value, "KAMPACTOR"))
return KAMExtInit;
if (strstr(Value, "SCSPACTOR"))
return SCSExtInit;
if (strstr(Value, "WINMOR"))
return WinmorExtInit;
if (strstr(Value, "V4"))
return V4ExtInit;
if (strstr(Value, "TELNET"))
return TelnetExtInit;
// if (strstr(Value, "SOUNDMODEM"))
// return SoundModemExtInit;
if (strstr(Value, "SCSTRACKER"))
return TrackerExtInit;
if (strstr(Value, "TRKMULTI"))
return TrackerMExtInit;
if (strstr(Value, "UZ7HO"))
return UZ7HOExtInit;
if (strstr(Value, "MULTIPSK"))
return MPSKExtInit;
if (strstr(Value, "FLDIGI"))
return FLDigiExtInit;
if (strstr(Value, "UIARQ"))
return UIARQExtInit;
// if (strstr(Value, "BAYCOM"))
// return (UINT) BaycomExtInit;
if (strstr(Value, "VARA"))
return VARAExtInit;
if (strstr(Value, "ARDOP"))
return ARDOPExtInit;
if (strstr(Value, "SERIAL"))
return SerialExtInit;
if (strstr(Value, "KISSHF"))
return KISSHFExtInit;
if (strstr(Value, "WINRPR"))
return WinRPRExtInit;
if (strstr(Value, "HSMODEM"))
return HSMODEMExtInit;
if (strstr(Value, "FREEDATA"))
return FreeDataExtInit;
if (strstr(Value, "6PACK"))
return SIXPACKExtInit;
ExtDriver = LoadLibrary(Value);
if (ExtDriver == NULL)
{
err=GetLastError();
sprintf(msg,"Error loading Driver %s - Error code %d",
PORTVEC->PORT_DLL_NAME,err);
MessageBox(NULL,msg,"BPQ32",MB_ICONSTOP);
return(0);
}
PORTVEC->DLLhandle=ExtDriver;
return (GetProcAddress(ExtDriver,"_ExtInit@4"));
}
/*
_DATABASE LABEL BYTE
FILLER DB 14 DUP (0) ; PROTECTION AGENST BUFFER PROBLEMS!
DB MAJORVERSION,MINORVERSION
_NEIGHBOURS DD 0
DW TYPE ROUTE
_MAXNEIGHBOURS DW 20 ; MAX ADJACENT NODES
_DESTS DD 0 ; NODE LIST
DW TYPE DEST_LIST
MAXDESTS DW 100 ; MAX NODES IN SYSTEM
*/
DllExport int APIENTRY GetAttachedProcesses()
{
return (AttachedProcesses);
}
DllExport int * APIENTRY GetAttachedProcessList()
{
return (&AttachedPIDList[0]);
}
DllExport int * APIENTRY SaveNodesSupport()
{
return (&DATABASESTART);
}
//
// Internal BPQNODES support
//
#define UCHAR unsigned char
/*
ROUTE ADD G1HTL-1 2 200 0 0 0
ROUTE ADD G4IRX-3 2 200 0 0 0
NODE ADD MAPPLY:G1HTL-1 G1HTL-1 2 200 G4IRX-3 2 98
NODE ADD NOT:GB7NOT G1HTL-1 2 199 G4IRX-3 2 98
*/
struct DEST_LIST * Dests;
struct ROUTE * Routes;
int MaxNodes;
int MaxRoutes;
int NodeLen;
int RouteLen;
int count;
int cursor;
int len,i;
ULONG cnt;
char Normcall[10];
char Portcall[10];
char Alias[7];
char line[100];
HANDLE handle;
int APIENTRY Restart()
{
int i, Count = AttachedProcesses;
HANDLE hProc;
DWORD PID;
for (i = 0; i < Count; i++)
{
PID = AttachedPIDList[i];
// Kill Timer Owner last
if (TimerInst != PID)
{
hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID);
if (hProc)
{
TerminateProcess(hProc, 0);
CloseHandle(hProc);
}
}
}
hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, TimerInst);
if (hProc)
{
TerminateProcess(hProc, 0);
CloseHandle(hProc);
}
return 0;
}
int APIENTRY Reboot()
{
// Run shutdown -r -f
STARTUPINFO SInfo;
PROCESS_INFORMATION PInfo;
char Cmd[] = "shutdown -r -f";
SInfo.cb=sizeof(SInfo);
SInfo.lpReserved=NULL;
SInfo.lpDesktop=NULL;
SInfo.lpTitle=NULL;
SInfo.dwFlags=0;
SInfo.cbReserved2=0;
SInfo.lpReserved2=NULL;
return CreateProcess(NULL, Cmd, NULL, NULL, FALSE,0 ,NULL ,NULL, &SInfo, &PInfo);
}
/*
int APIENTRY Reconfig()
{
if (!ProcessConfig())
{
return (0);
}
SaveNodes();
WritetoConsole("Nodes Saved\n");
ReconfigFlag=TRUE;
WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n");
return 1;
}
*/
// Code to support minimizing all BPQ Apps to a single Tray ICON
// As we can't minimize the console window to the tray, I'll use an ordinary
// window instead. This also gives me somewhere to post the messages to
char AppName[] = "BPQ32";
char Title[80] = "BPQ32.dll Console";
int NewLine();
char FrameClassName[] = TEXT("MdiFrame");
HWND ClientWnd; //This stores the MDI client area window handle
LOGFONT LFTTYFONT ;
HFONT hFont ;
HMENU hPopMenu, hWndMenu;
HMENU hMainFrameMenu = NULL;
HMENU hBaseMenu = NULL;
HMENU hConsMenu = NULL;
HMENU hTermMenu = NULL;
HMENU hMonMenu = NULL;
HMENU hTermActMenu, hTermCfgMenu, hTermEdtMenu, hTermHlpMenu;
HMENU hMonActMenu, hMonCfgMenu, hMonEdtMenu, hMonHlpMenu;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
DllExport int APIENTRY DeleteTrayMenuItem(HWND hWnd);
#define BPQMonitorAvail 1
#define BPQDataAvail 2
#define BPQStateChange 4
VOID GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value);
SOCKET OpenWL2KHTTPSock();
SendHTTPRequest(SOCKET sock, char * Request, char * Params, int Len, char * Return);
BOOL GetWL2KSYSOPInfo(char * Call, char * _REPLYBUFFER);
BOOL UpdateWL2KSYSOPInfo(char * Call, char * SQL);
static INT_PTR CALLBACK ConfigWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
char _REPLYBUFFER[1000] = "";
char Value[1000];
if (GetWL2KSYSOPInfo(WL2KCall, _REPLYBUFFER))
{
// if (strstr(_REPLYBUFFER, "\"ErrorMessage\":") == 0)
GetJSONValue(_REPLYBUFFER, "\"SysopName\":", Value);
SetDlgItemText(hDlg, NAME, Value);
GetJSONValue(_REPLYBUFFER, "\"GridSquare\":", Value);
SetDlgItemText(hDlg, IDC_Locator, Value);
GetJSONValue(_REPLYBUFFER, "\"StreetAddress1\":", Value);
SetDlgItemText(hDlg, ADDR1, Value);
GetJSONValue(_REPLYBUFFER, "\"StreetAddress2\":", Value);
SetDlgItemText(hDlg, ADDR2, Value);
GetJSONValue(_REPLYBUFFER, "\"City\":", Value);
SetDlgItemText(hDlg, CITY, Value);
GetJSONValue(_REPLYBUFFER, "\"State\":", Value);
SetDlgItemText(hDlg, STATE, Value);
GetJSONValue(_REPLYBUFFER, "\"Country\":", Value);
SetDlgItemText(hDlg, COUNTRY, Value);
GetJSONValue(_REPLYBUFFER, "\"PostalCode\":", Value);
SetDlgItemText(hDlg, POSTCODE, Value);
GetJSONValue(_REPLYBUFFER, "\"Email\":", Value);
SetDlgItemText(hDlg, EMAIL, Value);
GetJSONValue(_REPLYBUFFER, "\"Website\":", Value);
SetDlgItemText(hDlg, WEBSITE, Value);
GetJSONValue(_REPLYBUFFER, "\"Phones\":", Value);
SetDlgItemText(hDlg, PHONE, Value);
GetJSONValue(_REPLYBUFFER, "\"Comments\":", Value);
SetDlgItemText(hDlg, ADDITIONALDATA, Value);
}
return (INT_PTR)TRUE;
}
case WM_COMMAND:
switch(LOWORD(wParam))
{
case ID_SAVE:
{
char Name[100];
char PasswordText[100];
char LocatorText[100];
char Addr1[100];
char Addr2[100];
char City[100];
char State[100];
char Country[100];
char PostCode[100];
char Email[100];
char Website[100];
char Phone[100];
char Data[100];
SOCKET sock;
int Len;
char Message[2048];
char Reply[2048] = "";
GetDlgItemText(hDlg, NAME, Name, 99);
GetDlgItemText(hDlg, IDC_Password, PasswordText, 99);
GetDlgItemText(hDlg, IDC_Locator, LocatorText, 99);
GetDlgItemText(hDlg, ADDR1, Addr1, 99);
GetDlgItemText(hDlg, ADDR2, Addr2, 99);
GetDlgItemText(hDlg, CITY, City, 99);
GetDlgItemText(hDlg, STATE, State, 99);
GetDlgItemText(hDlg, COUNTRY, Country, 99);
GetDlgItemText(hDlg, POSTCODE, PostCode, 99);
GetDlgItemText(hDlg, EMAIL, Email, 99);
GetDlgItemText(hDlg, WEBSITE, Website, 99);
GetDlgItemText(hDlg, PHONE, Phone, 99);
GetDlgItemText(hDlg, ADDITIONALDATA, Data, 99);
//{"Callsign":"String","GridSquare":"String","SysopName":"String",
//"StreetAddress1":"String","StreetAddress2":"String","City":"String",
//"State":"String","Country":"String","PostalCode":"String","Email":"String",
//"Phones":"String","Website":"String","Comments":"String"}
Len = sprintf(Message,
"\"Callsign\":\"%s\","
"\"Password\":\"%s\","
"\"GridSquare\":\"%s\","
"\"SysopName\":\"%s\","
"\"StreetAddress1\":\"%s\","
"\"StreetAddress2\":\"%s\","
"\"City\":\"%s\","
"\"State\":\"%s\","
"\"Country\":\"%s\","
"\"PostalCode\":\"%s\","
"\"Email\":\"%s\","
"\"Phones\":\"%s\","
"\"Website\":\"%s\","
"\"Comments\":\"%s\"",
WL2KCall, PasswordText, LocatorText, Name, Addr1, Addr2, City, State, Country, PostCode, Email, Phone, Website, Data);
Debugprintf("Sending %s", Message);
sock = OpenWL2KHTTPSock();
if (sock)
{
char * ptr;
SendHTTPRequest(sock,
"/sysop/add", Message, Len, Reply);
ptr = strstr(Reply, "\"ErrorCode\":");
if (ptr)
{
ptr = strstr(ptr, "Message");
if (ptr)
{
ptr += 10;
strlop(ptr, '"');
MessageBox(NULL ,ptr, "Error", MB_OK);
}
}
else
MessageBox(NULL, "Sysop Record Updated", "BPQ32", MB_OK);
}
closesocket(sock);
}
case ID_CANCEL:
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
}
return (INT_PTR)FALSE;
}
LRESULT CALLBACK UIWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
VOID WINAPI OnTabbedDialogInit(HWND hDlg);
LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
POINT pos;
BOOL ret;
CLIENTCREATESTRUCT MDIClientCreateStruct; // Structure to be used for MDI client area
//HWND m_hwndSystemInformation = 0;
if (message == BPQMsg)
{
if (lParam & BPQDataAvail)
DoReceivedData(wParam);
if (lParam & BPQMonitorAvail)
DoMonData(wParam);
if (lParam & BPQStateChange)
DoStateChange(wParam);
return (0);
}
switch (message)
{
case MY_TRAY_ICON_MESSAGE:
switch(lParam)
{
case WM_RBUTTONUP:
case WM_LBUTTONUP:
GetCursorPos(&pos);
// SetForegroundWindow(FrameWnd);
TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, FrameWnd, 0);
return 0;
}
break;
case WM_CTLCOLORDLG:
return (LONG)bgBrush;
case WM_SIZING:
case WM_SIZE:
SendMessage(ClientWnd, WM_MDIICONARRANGE, 0 ,0);
break;
case WM_NCCREATE:
ret = DefFrameProc(hWnd, ClientWnd, message, wParam, lParam);
return TRUE;
case WM_CREATE:
// On creation of main frame, create the MDI client area
MDIClientCreateStruct.hWindowMenu = NULL;
MDIClientCreateStruct.idFirstChild = IDM_FIRSTCHILD;
ClientWnd = CreateWindow(TEXT("MDICLIENT"), // predefined value for MDI client area
NULL, // no caption required
WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
0, // No need to give any x/y or height/width since this client
// will just be used to get client windows created, effectively
// in the main window we will be seeing the mainframe window client area itself.
0,
0,
0,
hWnd,
NULL,
hInstance,
(void *) &MDIClientCreateStruct);
return 0;
case WM_COMMAND:
wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!
if (wmId >= TRAYBASEID && wmId < (TRAYBASEID + 100))
{
handle=hWndArray[wmId-TRAYBASEID];
if (handle == FrameWnd)
ShowWindow(handle, SW_NORMAL);
if (handle == FrameWnd && FrameMaximized == TRUE)
PostMessage(handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
else
PostMessage(handle, WM_SYSCOMMAND, SC_RESTORE, 0);
SetForegroundWindow(handle);
return 0;
}
switch(wmId)
{
struct ConsoleInfo * Cinfo = NULL;
case ID_NEWWINDOW:
Cinfo = CreateChildWindow(0, FALSE);
if (Cinfo)
SendMessage(ClientWnd, WM_MDIACTIVATE, (WPARAM)Cinfo->hConsole, 0);
break;
case ID_WINDOWS_CASCADE:
SendMessage(ClientWnd, WM_MDICASCADE, 0, 0);
return 0;
case ID_WINDOWS_TILE:
SendMessage(ClientWnd, WM_MDITILE , MDITILE_HORIZONTAL, 0);
return 0;
case BPQCLOSEALL:
CloseAllPrograms();
// SendMessage(ClientWnd, WM_MDIICONARRANGE, 0 ,0);
return 0;
case BPQUICONFIG:
{
int err, i=0;
char Title[80];
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = UIWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON) );
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = bgBrush;
wc.lpszMenuName = NULL;
wc.lpszClassName = UIClassName;
RegisterClass(&wc);
UIhWnd = CreateDialog(hInstance, UIClassName, 0, NULL);
if (!UIhWnd)
{
err=GetLastError();
return FALSE;
}
wsprintf(Title,"BPQ32 Beacon Configuration");
MySetWindowText(UIhWnd, Title);
ShowWindow(UIhWnd, SW_NORMAL);
OnTabbedDialogInit(UIhWnd); // Set up pages
// UpdateWindow(UIhWnd);
return 0;
}
case IDD_WL2KSYSOP:
if (WL2KCall[0] == 0)
{
MessageBox(NULL,"WL2K Reporting is not configured","BPQ32", MB_OK);
break;
}
DialogBox(hInstance, MAKEINTRESOURCE(IDD_WL2KSYSOP), hWnd, ConfigWndProc);
break;
// Handle MDI Window commands
default:
{
if(wmId >= IDM_FIRSTCHILD)
{
DefFrameProc(hWnd, ClientWnd, message, wParam, lParam);
}
else
{
HWND hChild = (HWND)SendMessage(ClientWnd, WM_MDIGETACTIVE,0,0);
if(hChild)
SendMessage(hChild, WM_COMMAND, wParam, lParam);
}
}
}
break;
case WM_INITMENUPOPUP:
{
HWND hChild = (HWND)SendMessage(ClientWnd, WM_MDIGETACTIVE,0,0);
if(hChild)
SendMessage(hChild, WM_INITMENUPOPUP, wParam, lParam);
}
case WM_SYSCOMMAND:
wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!
switch (wmId)
{
case SC_MAXIMIZE:
FrameMaximized = TRUE;
break;
case SC_RESTORE:
FrameMaximized = FALSE;
break;
case SC_MINIMIZE:
if (MinimizetoTray)
{
ShowWindow(hWnd, SW_HIDE);
return TRUE;
}
}
return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam));
case WM_CLOSE:
PostQuitMessage(0);
if (MinimizetoTray)
DeleteTrayMenuItem(hWnd);
break;
default:
return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam));
}
return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam));
}
int OffsetH, OffsetW;
int SetupConsoleWindow()
{
WNDCLASS wc;
int i;
int retCode, Type, Vallen;
HKEY hKey=0;
char Size[80];
WNDCLASSEX wndclassMainFrame;
RECT CRect;
retCode = RegOpenKeyEx (REGTREE,
"SOFTWARE\\G8BPQ\\BPQ32",
0,
KEY_QUERY_VALUE,
&hKey);
if (retCode == ERROR_SUCCESS)
{
Vallen=80;
retCode = RegQueryValueEx(hKey,"FrameWindowSize",0,
(ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
if (retCode == ERROR_SUCCESS)
sscanf(Size,"%d,%d,%d,%d",&FRect.left,&FRect.right,&FRect.top,&FRect.bottom);
if (FRect.top < - 500 || FRect.left < - 500)
{
FRect.left = 0;
FRect.top = 0;
FRect.right = 600;
FRect.bottom = 400;
}
Vallen=80;
retCode = RegQueryValueEx(hKey,"WindowSize",0,
(ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
if (retCode == ERROR_SUCCESS)
sscanf(Size,"%d,%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom, &ConsoleMinimized);
if (Rect.top < - 500 || Rect.left < - 500)
{
Rect.left = 0;
Rect.top = 0;
Rect.right = 600;
Rect.bottom = 400;
}
Vallen=80;
retCode = RegQueryValueEx(hKey,"StatusWindowSize",0,
(ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
if (retCode == ERROR_SUCCESS)
sscanf(Size, "%d,%d,%d,%d,%d", &StatusRect.left, &StatusRect.right,
&StatusRect.top, &StatusRect.bottom, &StatusMinimized);
if (StatusRect.top < - 500 || StatusRect.left < - 500)
{
StatusRect.left = 0;
StatusRect.top = 0;
StatusRect.right = 850;
StatusRect.bottom = 500;
}
// Get StartMinimized and MinimizetoTray flags
Vallen = 4;
retCode = RegQueryValueEx(hKey, "Start Minimized", 0, &Type, (UCHAR *)&StartMinimized, &Vallen);
Vallen = 4;
retCode = RegQueryValueEx(hKey, "Minimize to Tray", 0, &Type, (UCHAR *)&MinimizetoTray, &Vallen);
}
wndclassMainFrame.cbSize = sizeof(WNDCLASSEX);
wndclassMainFrame.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
wndclassMainFrame.lpfnWndProc = FrameWndProc;
wndclassMainFrame.cbClsExtra = 0;
wndclassMainFrame.cbWndExtra = 0;
wndclassMainFrame.hInstance = hInstance;
wndclassMainFrame.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON));
wndclassMainFrame.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclassMainFrame.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
wndclassMainFrame.lpszMenuName = NULL;
wndclassMainFrame.lpszClassName = FrameClassName;
wndclassMainFrame.hIconSm = NULL;
if(!RegisterClassEx(&wndclassMainFrame))
{
return 0;
}
pindex = 0;
PartLine = FALSE;
bgBrush = CreateSolidBrush(BGCOLOUR);
// hMainFrameMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME_MENU));
hBaseMenu = LoadMenu(hInstance, MAKEINTRESOURCE(CONS_MENU));
hConsMenu = GetSubMenu(hBaseMenu, 1);
hWndMenu = GetSubMenu(hBaseMenu, 0);
hTermMenu = LoadMenu(hInstance, MAKEINTRESOURCE(TERM_MENU));
hTermActMenu = GetSubMenu(hTermMenu, 1);
hTermCfgMenu = GetSubMenu(hTermMenu, 2);
hTermEdtMenu = GetSubMenu(hTermMenu, 3);
hTermHlpMenu = GetSubMenu(hTermMenu, 4);
hMonMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MON_MENU));
hMonCfgMenu = GetSubMenu(hMonMenu, 1);
hMonEdtMenu = GetSubMenu(hMonMenu, 2);
hMonHlpMenu = GetSubMenu(hMonMenu, 3);
hMainFrameMenu = CreateMenu();
AppendMenu(hMainFrameMenu, MF_STRING + MF_POPUP, (UINT)hWndMenu, "Window");
//Create the main MDI frame window
ClientWnd = NULL;
FrameWnd = CreateWindow(FrameClassName,
"BPQ32 Console",
WS_OVERLAPPEDWINDOW |WS_CLIPCHILDREN,
FRect.left,
FRect.top,
FRect.right - FRect.left,
FRect.bottom - FRect.top,
NULL, // handle to parent window
hMainFrameMenu, // handle to menu
hInstance, // handle to the instance of module
NULL); // Long pointer to a value to be passed to the window through the
// CREATESTRUCT structure passed in the lParam parameter the WM_CREATE message
// Get Client Params
if (FrameWnd == 0)
{
Debugprintf("SetupConsoleWindow Create Frame failed %d", GetLastError());
return 0;
}
ShowWindow(FrameWnd, SW_RESTORE);
GetWindowRect(FrameWnd, &FRect);
OffsetH = FRect.bottom - FRect.top;
OffsetW = FRect.right - FRect.left;
GetClientRect(FrameWnd, &CRect);
OffsetH -= CRect.bottom;
OffsetW -= CRect.right;
OffsetH -= 4;
// Create Console Window
wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = 0;
wc.lpszClassName = ClassName;
i=RegisterClass(&wc);
sprintf (Title, "BPQ32.dll Console Version %s", VersionString);
hConsWnd = CreateMDIWindow(ClassName, "Console", 0,
0,0,0,0, ClientWnd, hInstance, 1234);
i = GetLastError();
if (!hConsWnd) {
return (FALSE);
}
wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
wc.lpfnWndProc = (WNDPROC)StatusWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wc.lpszMenuName = 0;
wc.lpszClassName = "Status";
i=RegisterClass(&wc);
if (StatusRect.top < OffsetH) // Make sure not off top of MDI frame
{
int Error = OffsetH - StatusRect.top;
StatusRect.top += Error;
StatusRect.bottom += Error;
}
StatusWnd = CreateMDIWindow("Status", "Stream Status", 0,
StatusRect.left, StatusRect.top, StatusRect.right - StatusRect.left,
StatusRect.bottom - StatusRect.top, ClientWnd, hInstance, 1234);
SetTimer(StatusWnd, 1, 1000, NULL);
hPopMenu = GetSubMenu(hBaseMenu, 1) ;
if (MinimizetoTray)
CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_CHECKED);
else
CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_UNCHECKED);
if (StartMinimized)
CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_CHECKED);
else
CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_UNCHECKED);
DrawMenuBar(hConsWnd);
// setup default font information
LFTTYFONT.lfHeight = 12;
LFTTYFONT.lfWidth = 8 ;
LFTTYFONT.lfEscapement = 0 ;
LFTTYFONT.lfOrientation = 0 ;
LFTTYFONT.lfWeight = 0 ;
LFTTYFONT.lfItalic = 0 ;
LFTTYFONT.lfUnderline = 0 ;
LFTTYFONT.lfStrikeOut = 0 ;
LFTTYFONT.lfCharSet = 0;
LFTTYFONT.lfOutPrecision = OUT_DEFAULT_PRECIS ;
LFTTYFONT.lfClipPrecision = CLIP_DEFAULT_PRECIS ;
LFTTYFONT.lfQuality = DEFAULT_QUALITY ;
LFTTYFONT.lfPitchAndFamily = FIXED_PITCH;
lstrcpy(LFTTYFONT.lfFaceName, "FIXEDSYS" ) ;
hFont = CreateFontIndirect(&LFTTYFONT) ;
SetWindowText(hConsWnd,Title);
if (Rect.right < 100 || Rect.bottom < 100)
{
GetWindowRect(hConsWnd, &Rect);
}
if (Rect.top < OffsetH) // Make sure not off top of MDI frame
{
int Error = OffsetH - Rect.top;
Rect.top += Error;
Rect.bottom += Error;
}
MoveWindow(hConsWnd, Rect.left - (OffsetW /2), Rect.top - OffsetH, Rect.right-Rect.left, Rect.bottom-Rect.top, TRUE);
MoveWindow(StatusWnd, StatusRect.left - (OffsetW /2), StatusRect.top - OffsetH,
StatusRect.right-StatusRect.left, StatusRect.bottom-StatusRect.top, TRUE);
hWndCons = CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", "",
WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
LBS_DISABLENOSCROLL | LBS_NOSEL | WS_VSCROLL | WS_HSCROLL,
Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top,
hConsWnd, NULL, hInstance, NULL);
// SendMessage(hWndCons, WM_SETFONT, hFont, 0);
SendMessage(hWndCons, LB_SETHORIZONTALEXTENT , 1000, 0);
if (ConsoleMinimized)
ShowWindow(hConsWnd, SW_SHOWMINIMIZED);
else
ShowWindow(hConsWnd, SW_RESTORE);
if (StatusMinimized)
ShowWindow(StatusWnd, SW_SHOWMINIMIZED);
else
ShowWindow(StatusWnd, SW_RESTORE);
ShowWindow(FrameWnd, SW_RESTORE);
LoadLibrary("riched20.dll");
if (StartMinimized)
if (MinimizetoTray)
ShowWindow(FrameWnd, SW_HIDE);
else
ShowWindow(FrameWnd, SW_SHOWMINIMIZED);
else
ShowWindow(FrameWnd, SW_RESTORE);
CreateMonitorWindow(Size);
return 0;
}
DllExport int APIENTRY SetupTrayIcon()
{
if (MinimizetoTray == 0)
return 0;
trayMenu = CreatePopupMenu();
for( i = 0; i < 100; ++i )
{
if (strcmp(PopupText[i],"BPQ32 Console") == 0)
{
hWndArray[i] = FrameWnd;
goto doneit;
}
}
for( i = 0; i < 100; ++i )
{
if (hWndArray[i] == 0)
{
hWndArray[i] = FrameWnd;
strcpy(PopupText[i],"BPQ32 Console");
break;
}
}
doneit:
for( i = 0; i < 100; ++i )
{
if (hWndArray[i] != 0)
AppendMenu(trayMenu,MF_STRING,TRAYBASEID+i,PopupText[i]);
}
// Set up Tray ICON
ZeroMemory(&niData,sizeof(NOTIFYICONDATA));
niData.cbSize = sizeof(NOTIFYICONDATA);
// the ID number can be any UINT you choose and will
// be used to identify your icon in later calls to
// Shell_NotifyIcon
niData.uID = TRAY_ICON_ID;
// state which structure members are valid
// here you can also choose the style of tooltip
// window if any - specifying a balloon window:
// NIF_INFO is a little more complicated
strcpy(niData.szTip,"BPQ32 Windows");
niData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
// load the icon note: you should destroy the icon
// after the call to Shell_NotifyIcon
niData.hIcon =
//LoadIcon(NULL, IDI_APPLICATION);
(HICON)LoadImage( hInstance,
MAKEINTRESOURCE(BPQICON),
IMAGE_ICON,
GetSystemMetrics(SM_CXSMICON),
GetSystemMetrics(SM_CYSMICON),
LR_DEFAULTCOLOR);
// set the window you want to receive event messages
niData.hWnd = FrameWnd;
// set the message to send
// note: the message value should be in the
// range of WM_APP through 0xBFFF
niData.uCallbackMessage = MY_TRAY_ICON_MESSAGE;
// Call Shell_NotifyIcon. NIM_ADD adds a new tray icon
if (Shell_NotifyIcon(NIM_ADD,&niData))
Debugprintf("BPQ32 Create Tray Icon Ok");
// else
// Debugprintf("BPQ32 Create Tray Icon failed %d", GetLastError());
return 0;
}
VOID SaveConfig()
{
HKEY hKey=0;
int retCode, disp;
retCode = RegCreateKeyEx(REGTREE,
"SOFTWARE\\G8BPQ\\BPQ32",
0, // Reserved
0, // Class
0, // Options
KEY_ALL_ACCESS,
NULL, // Security Attrs
&hKey,
&disp);
if (retCode == ERROR_SUCCESS)
{
retCode = RegSetValueEx(hKey, "Start Minimized", 0, REG_DWORD, (UCHAR *)&StartMinimized, 4);
retCode = RegSetValueEx(hKey, "Minimize to Tray", 0, REG_DWORD, (UCHAR *)&MinimizetoTray, 4);
}
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
POINT pos;
HWND handle;
RECT cRect;
switch (message)
{
case WM_MDIACTIVATE:
// Set the system info menu when getting activated
if (lParam == (LPARAM) hWnd)
{
// Activate
// GetSubMenu function should retrieve a handle to the drop-down menu or submenu.
RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)hConsMenu, "Actions");
SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hBaseMenu, (LPARAM) hWndMenu);
}
else
{
// Deactivate
SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
}
DrawMenuBar(FrameWnd);
return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
case MY_TRAY_ICON_MESSAGE:
switch(lParam)
{
case WM_RBUTTONUP:
case WM_LBUTTONUP:
GetCursorPos(&pos);
SetForegroundWindow(hWnd);
TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, hWnd, 0);
return 0;
}
break;
case WM_CTLCOLORDLG:
return (LONG)bgBrush;
case WM_COMMAND:
wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!
if (wmId == IDC_ENIGATE)
{
int retCode, disp;
HKEY hKey=0;
IGateEnabled = IsDlgButtonChecked(hWnd, IDC_ENIGATE);
if (IGateEnabled)
ISDelayTimer = 60;
retCode = RegCreateKeyEx(REGTREE,
"SOFTWARE\\G8BPQ\\BPQ32",
0, // Reserved
0, // Class
0, // Options
KEY_ALL_ACCESS,
NULL, // Security Attrs
&hKey,
&disp);
if (retCode == ERROR_SUCCESS)
{
retCode = RegSetValueEx(hKey,"IGateEnabled", 0 , REG_DWORD,(BYTE *)&IGateEnabled, 4);
RegCloseKey(hKey);
}
return 0;
}
if (wmId == BPQSAVENODES)
{
SaveNodes();
WritetoConsole("Nodes Saved\n");
return 0;
}
if (wmId == BPQCLEARRECONFIG)
{
if (!ProcessConfig())
{
MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
return (0);
}
ClearNodes();
WritetoConsole("Nodes file Cleared\n");
ReconfigFlag=TRUE;
WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n");
return 0;
}
if (wmId == BPQRECONFIG)
{
if (!ProcessConfig())
{
MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
return (0);
}
SaveNodes();
WritetoConsole("Nodes Saved\n");
ReconfigFlag=TRUE;
WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n");
return 0;
}
if (wmId == SCANRECONFIG)
{
if (!ProcessConfig())
{
MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
return (0);
}
RigReconfigFlag = TRUE;
WritetoConsole("Rigcontrol Reconfig requested ... Waiting for Timer Poll\n");
return 0;
}
if (wmId == APRSRECONFIG)
{
if (!ProcessConfig())
{
MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
return (0);
}
APRSReconfigFlag=TRUE;
WritetoConsole("APRS Reconfig requested ... Waiting for Timer Poll\n");
return 0;
}
if (wmId == BPQDUMP)
{
DumpSystem();
return 0;
}
if (wmId == BPQCLOSEALL)
{
CloseAllPrograms();
return 0;
}
if (wmId == BPQUICONFIG)
{
int err, i=0;
char Title[80];
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = UIWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = DLGWINDOWEXTRA;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON) );
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = bgBrush;
wc.lpszMenuName = NULL;
wc.lpszClassName = UIClassName;
RegisterClass(&wc);
UIhWnd = CreateDialog(hInstance, UIClassName,0,NULL);
if (!UIhWnd)
{
err=GetLastError();
return FALSE;
}
wsprintf(Title,"BPQ32 Beacon Utility Version");
MySetWindowText(UIhWnd, Title);
return 0;
}
if (wmId == BPQSAVEREG)
{
CreateRegBackup();
return 0;
}
if (wmId == BPQMINTOTRAY)
{
MinimizetoTray = !MinimizetoTray;
if (MinimizetoTray)
CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_CHECKED);
else
CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_UNCHECKED);
SaveConfig();
return 0;
}
if (wmId == BPQSTARTMIN)
{
StartMinimized = !StartMinimized;
if (StartMinimized)
CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_CHECKED);
else
CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_UNCHECKED);
SaveConfig();
return 0;
}
if (wmId >= TRAYBASEID && wmId < (TRAYBASEID + 100))
{
handle=hWndArray[wmId-TRAYBASEID];
if (handle == FrameWnd && FrameMaximized == TRUE)
PostMessage(handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
else
PostMessage(handle, WM_SYSCOMMAND, SC_RESTORE, 0);
SetForegroundWindow(handle);
return 0;
}
case WM_SYSCOMMAND:
wmId = LOWORD(wParam); // Remember, these are...
wmEvent = HIWORD(wParam); // ...different for Win32!
switch (wmId)
{
case SC_MINIMIZE:
ConsoleMinimized = TRUE;
break;
case SC_RESTORE:
ConsoleMinimized = FALSE;
SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
break;
}
return DefMDIChildProc(hWnd, message, wParam, lParam);
case WM_SIZE:
GetClientRect(hWnd, &cRect);
MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
if (APRSActive)
MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
else
MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
// InvalidateRect(hWnd, NULL, TRUE);
break;
/*
case WM_PAINT:
hdc = BeginPaint (hWnd, &ps);
hOldFont = SelectObject( hdc, hFont) ;
for (i=0; i<SCREENLEN; i++)
{
TextOut(hdc,0,i*14,&Screen[i*LINELEN],LINELEN);
}
SelectObject( hdc, hOldFont ) ;
EndPaint (hWnd, &ps);
break;
*/
case WM_DESTROY:
// SessionControl(Stream, 2, 0);
// DeallocateStream(Stream);
// PostQuitMessage(0);
break;
case WM_CHAR:
if (wParam == 03)
{
DumpSystem();
return 0;
}
case WM_CLOSE:
break;
default:
return DefMDIChildProc(hWnd, message, wParam, lParam);
}
return DefMDIChildProc(hWnd, message, wParam, lParam);
}
DllExport BOOL APIENTRY GetMinimizetoTrayFlag()
{
while (InitDone == 0)
{
Debugprintf("Waiting for init to complete");
Sleep(1000);
}
if (InitDone == (VOID *)-1) // Init failed
exit(0);
return MinimizetoTray;
}
DllExport BOOL APIENTRY GetStartMinimizedFlag()
{
return StartMinimized;
}
DllExport int APIENTRY AddTrayMenuItem(HWND hWnd, char * Label)
{
int i;
for( i = 0; i < 100; ++i )
{
if (hWndArray[i] == 0)
{
hWndArray[i]=hWnd;
PIDArray[i] = GetCurrentProcessId();
strcpy(PopupText[i],Label);
AppendMenu(trayMenu,MF_STRING,TRAYBASEID+i,Label);
CreateNewTrayIcon();
return 0;
}
}
return -1;
}
DllExport int APIENTRY DeleteTrayMenuItem(HWND hWnd)
{
int i;
for( i = 0; i < 100; ++i )
{
if (hWndArray[i] == hWnd)
{
hWndArray[i] = 0;
PIDArray[i] = 0;
DeleteMenu(trayMenu,TRAYBASEID+i,MF_BYCOMMAND);
CreateNewTrayIcon();
return 0;
}
}
return -1;
}
int WritetoConsoleLocal(char * buff);
DllExport int APIENTRY WritetoConsole(char * buff)
{
return WritetoConsoleLocal(buff);
}
DllExport VOID * APIENTRY GetBuff();
int WritetoConsoleLocal(char * buff)
{
int len=strlen(buff);
UINT * buffptr;
if (Semaphore.Flag == 0)
return WritetoConsoleSupport(buff);
buffptr = GetBuff();
if (buffptr == 0) // No buffers, so send direct
return WritetoConsoleSupport(buff);
if (len > 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<cSubKeys; i++)
{
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(hKeyIn, i,
achKey,
&cbName,
NULL,
NULL,
NULL,
&ftLastWriteTime);
if (retCode == ERROR_SUCCESS)
{
HKEY NextKeyIn;
HKEY NextKeyOut;
int disp;
Debugprintf(TEXT("(%d) %s\n"), i+1, achKey);
retCode = RegOpenKeyEx(hKeyIn, achKey, 0, KEY_READ, &NextKeyIn);
retCode += RegCreateKeyEx(hKeyOut, achKey, 0, 0, 0, KEY_ALL_ACCESS, NULL, &NextKeyOut, &disp);
if (retCode == 0)
CopyReg(NextKeyIn, NextKeyOut);
}
}
}
// Enumerate the key values.
if (cValues)
{
Debugprintf( "\nNumber of values: %d\n", cValues);
for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++)
{
int Type;
int ValLen = MAX_VALUE_DATA;
UCHAR Value[MAX_VALUE_DATA] = "";
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
retCode = RegEnumValue(hKeyIn, i,
achValue,
&cchValue,
NULL,
&Type,
&Value[0],
&ValLen);
if (retCode == ERROR_SUCCESS )
{
if (ValLen == 4)
Debugprintf(TEXT("(%d) %s = %x len %d\n"), i+1, achValue, *Value, ValLen);
else
Debugprintf(TEXT("(%d) %s = %s len %d\n"), i+1, achValue, Value, ValLen);
retCode = RegSetValueEx(hKeyOut, achValue, 0 , Type, (BYTE *)&Value[0], ValLen);
}
}
}
return TRUE;
}
DllExport BOOL APIENTRY SaveReg(char * KeyIn, HANDLE hFile)
{
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;
HKEY hKeyIn;
TCHAR achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
int len, written;
char RegLine[300];
char * ptr1, * ptr2;
char c;
retCode = RegOpenKeyEx (REGTREE, KeyIn, 0, KEY_READ, &hKeyIn);
if (retCode != ERROR_SUCCESS)
{
Debugprintf("Open Reg Key %s failed", KeyIn);
return FALSE;
}
len = sprintf(RegLine, "[%s\\%s]\r\n", REGTREETEXT, KeyIn);
WriteFile(hFile, RegLine, len, &written, NULL);
// 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 key values.
if (cValues)
{
for (i=0, retCode=ERROR_SUCCESS; i<cValues; i++)
{
int Type, k;
int ValLen = MAX_VALUE_DATA;
UCHAR Value[MAX_VALUE_DATA] = "";
UCHAR ValCopy[MAX_VALUE_DATA];
UINT Intval;
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
retCode = RegEnumValue(hKeyIn, i,
achValue,
&cchValue,
NULL,
&Type,
&Value[0],
&ValLen);
if (retCode == ERROR_SUCCESS )
{
// Encode the param depending on Type
switch(Type)
{
case REG_NONE: //( 0 ) // No value type
break;
case REG_SZ: //( 1 ) // Unicode nul terminated string
// Need to escape any \ or " in Value
ptr1 = Value;
ptr2 = ValCopy;
c = *ptr1++;
while (c)
{
switch (c)
{
case '\\':
case '"':
*ptr2++ = '\\';
}
*ptr2++ = c;
c = *ptr1++;
}
*ptr2 = 0;
len = sprintf(RegLine, "\"%s\"=\"%s\"\r\n", achValue, ValCopy);
break;
case REG_EXPAND_SZ: //( 2 ) // Unicode nul terminated string
// (with environment variable references)
break;
case REG_BINARY: //( 3 ) // Free form binary - hex:86,50 etc
len = sprintf(RegLine, "\"%s\"=hex:%02x,", 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]);
}
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<cSubKeys; i++)
{
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(hKeyIn, i,
achKey,
&cbName,
NULL,
NULL,
NULL,
&ftLastWriteTime);
if (retCode == ERROR_SUCCESS)
{
char NextKeyIn[MAX_KEY_LENGTH];
sprintf(NextKeyIn, "%s\\%s", KeyIn, achKey);
SaveReg(NextKeyIn, hFile);
}
}
}
return TRUE;
}
char Screen[4000];
char NewScreen[4000];
int DoStatus()
{
int i;
char callsign[12] = "";
char flag[3];
UINT Mask, MaskCopy;
int Flags;
int AppNumber;
int OneBits;
struct _EXCEPTION_POINTERS exinfo;
memset(NewScreen, ' ', 33 * 108);
strcpy(NewScreen," RX TX MON App Flg Callsign Program RX TX MON App Flg Callsign Program");
strcpy(EXCEPTMSG, "Status Timer Processing");
__try
{
for (i=1;i<65; i++)
{
callsign[0]=0;
if (GetAllocationState(i))
strcpy(flag,"*");
else
strcpy(flag," ");
GetCallsign(i,callsign);
Mask = MaskCopy = Get_APPLMASK(i);
// if only one bit set, convert to number
AppNumber = 0;
OneBits = 0;
while (MaskCopy)
{
if (MaskCopy & 1)
OneBits++;
AppNumber++;
MaskCopy = MaskCopy >> 1;
}
Flags=GetApplFlags(i);
if (OneBits > 1)
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; i<NUMBEROFPORTS; i++)
{
if (PORTVEC->PORTCONTROL.PORTTYPE == 0x10) // External
{
if (PORTVEC->PORT_EXT_ADDR)
{
SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
}
}
PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
}
SaveWindowPos(70); // Rigcontrol
if (hIPResWnd)
SaveMDIWindowPos(hIPResWnd, "", "IPResSize", IPMinimized);
SaveHostSessions();
}
DllExport BOOL APIENTRY CheckIfOwner()
{
//
// Returns TRUE if current process is root process
// that loaded the DLL
//
if (TimerInst == GetCurrentProcessId())
return (TRUE);
else
return (FALSE);
}
VOID GetParam(char * input, char * key, char * value)
{
char * ptr = strstr(input, key);
char Param[2048];
char * ptr1, * ptr2;
char c;
if (ptr)
{
ptr2 = strchr(ptr, '&');
if (ptr2) *ptr2 = 0;
strcpy(Param, ptr + strlen(key));
if (ptr2) *ptr2 = '&'; // Restore string
// Undo any % transparency
ptr1 = Param;
ptr2 = Param;
c = *(ptr1++);
while (c)
{
if (c == '%')
{
int n;
int m = *(ptr1++) - '0';
if (m > 9) m = m - 7;
n = *(ptr1++) - '0';
if (n > 9) n = n - 7;
*(ptr2++) = m * 16 + n;
}
else if (c == '+')
*(ptr2++) = ' ';
else
*(ptr2++) = c;
c = *(ptr1++);
}
*(ptr2++) = 0;
strcpy(value, Param);
}
}
int GetListeningPortsPID(int Port)
{
MIB_TCPTABLE_OWNER_PID * TcpTable = NULL;
PMIB_TCPROW_OWNER_PID Row;
int dwSize = 0;
DWORD n;
// Get PID of process for this TCP Port
// Get Length of table
GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0);
TcpTable = malloc(dwSize);
if (TcpTable == NULL)
return 0;
GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0);
for (n = 0; n < TcpTable->dwNumEntries; n++)
{
Row = &TcpTable->table[n];
if (Row->dwLocalPort == Port && Row->dwState == MIB_TCP_STATE_LISTEN)
{
return Row->dwOwningPid;
break;
}
}
return 0; // Not found
}
DllExport char * APIENTRY GetLOC()
{
return LOC;
}
DllExport void APIENTRY GetLatLon(double * lat, double * lon)
{
*lat = LatFromLOC;
*lon = LonFromLOC;
return;
}
// UZ7HO Dll PTT interface
// 1 ext_PTT_info
// 2 ext_PTT_settings
// 3 ext_PTT_OFF
// 4 ext_PTT_ON
// 5 ext_PTT_close
// 6 ext_PTT_open
extern struct RIGINFO * DLLRIG; // Rig record for dll PTT interface (currently only for UZ7HO);
VOID Rig_PTT(struct TNCINFO * TNC, BOOL PTTState);
VOID Rig_PTTEx(struct RIGINFO * RIG, BOOL PTTState, struct TNCINFO * TNC);
int WINAPI ext_PTT_info()
{
return 0;
}
int WINAPI ext_PTT_settings()
{
return 0;
}
int WINAPI ext_PTT_OFF(int Port)
{
if (DLLRIG)
Rig_PTTEx(DLLRIG, 0, 0);
return 0;
}
int WINAPI ext_PTT_ON(int Port)
{
if (DLLRIG)
Rig_PTTEx(DLLRIG, 1, 0);
return 0;
}
int WINAPI ext_PTT_close()
{
if (DLLRIG)
Rig_PTTEx(DLLRIG, 0, 0);
return 0;
}
DllExport INT WINAPI ext_PTT_open()
{
return 1;
}
char * stristr (char *ch1, char *ch2)
{
char *chN1, *chN2;
char *chNdx;
char *chRet = NULL;
chN1 = _strdup(ch1);
chN2 = _strdup(ch2);
if (chN1 && chN2)
{
chNdx = chN1;
while (*chNdx)
{
*chNdx = (char) tolower(*chNdx);
chNdx ++;
}
chNdx = chN2;
while (*chNdx)
{
*chNdx = (char) tolower(*chNdx);
chNdx ++;
}
chNdx = strstr(chN1, chN2);
if (chNdx)
chRet = ch1 + (chNdx - chN1);
}
free (chN1);
free (chN2);
return chRet;
}