linbpq/BPQMail.c

3724 lines
92 KiB
C

// Mail and Chat Server for BPQ32 Packet Switch
//
//
// Version 1.0.0.17re
// Split Messasge, User and BBS Editing from Main Config.
// Add word wrap to Console input and output
// Flash Console on chat user connect
// Fix processing Name response in chat mode
// Fix processing of *RTL from station not defined as a Chat Node
// Fix overlength lines ln List responses
// Housekeeping expires BIDs
// Killing a message removes it from the forwarding counts
// Version 1.0.0.18
// Save User Database when name is entered or updated so it is not lost on a crash
// Fix Protocol Error in Compressed Forwarding when switching direction
// Add Housekeeping results dialog.
// Version 1.0.0.19
// Allow PACLEN in forward scripts.
// Store and forward messages with CRLF as line ends
// Send Disconnect after FQ ( for LinFBB)
// "Last Listed" is saved if MailChat is closed without closing Console
// Maximum acceptable message length can be specified (in Forwarding Config)
// Version 1.0.0.20
// Fix error in saving forwarding config (introduced in .19)
// Limit size of FBB forwarding block.
// Clear old connection (instead of new) if duplicate connect on Chat Node-Node link
// Send FA for Compressed Mail (was sending FB for both Compressed and Uncompressed)
// Version 1.0.0.21
// Fix Connect Script Processing (wasn't waiting for CONNECTED from last step)
// Implement Defer
// Fix MBL-style forwarding
// Fix Add User (Params were not saved)
// Add SC (Send Copy) Command
// Accept call@bbs as well as call @ bbs
// Version 1.0.0.22
// Implement RB RP LN LR LF LN L$ Commands.
// Implement QTH and ZIP Commands.
// Entering an empty Title cancels the message.
// Uses HomeBBS field to set @ field for local users.
// Creates basic WP Database.
// Uses WP to lookup @ field for non-local calls.
// Console "Actions" Menu renamed "Options".
// Excluded flag is actioned.
// Asks user to set HomeBBS if not already set.
// Fix "Shrinking Message" problem, where message got shorter each time it was read Initroduced in .19).
// Flash Server window when anyone connects to chat (If Console Option "Flash on Chat User Connect" set).
// Version 1.0.0.23
// Fix R: line scan bug
// Version 1.0.0.24
// Fix closing console window on 'B'.
// Fix Message Creation time.
// Enable Delete function in WP edit dialog
// Version 1.0.0.25
// Implement K< and K> commands
// Experimental support for B1 and B2 forwarding
// Experimental UI System
// Fix extracting QTH from WP updates
// Version 1.0.0.26
// Add YN etc responses for FBB B1/B2
// Version 1.0.0.27
// Fix crash if NULL received as start of a packet.
// Add Save WP command
// Make B2 flag BBS-specific.
// Implement B2 Send
// Version 1.0.0.28
// Fix parsing of smtp to addresses - eg smtp:john.wiseman@cantab.net
// Flag messages as Held if smtp server rejects from or to addresses
// Fix Kill to (K> Call)
// Edit Message dialog shows latest first
// Add chat debug window to try to track down occasional chat connection problems
// Version 1.0.0.29
// Add loads of try/excspt
// Version 1.0.0.30
// Writes Debug output to LOG_DEBUG_X and Monitor Window
// Version 1.0.0.32
// Allow use of GoogleMail for ISP functions
// Accept SYSOP as alias for SYSOPCall - ie user can do SP SYSOP, and it will appear in sysop's LM, RM, etc
// Email Housekeeping Results to SYSOP
// Version 1.0.0.33
// Housekeeping now runs at Maintenance Time. Maintenance Interval removed.
// Allow multiple numbers on R and K commands
// Fix L command with single number
// Log if Forward count is out of step with messages to forward.
// UI Processing improved and F< command implemented
// Version 1.0.0.34
// Semaphore Chat Messages
// Display Semaphore Clashes
// More Program Error Traps
// Kill Messages more than BIDLifetime old
// Version 1.0.0.35
// Test for Mike - Remove B1 check from Parse_SID
// Version 1.0.0.36
// Fix calculation of Housekeeping Time.
// Set dialog box background explicitly.
// Remove tray entry for chat debug window.
// Add date to log file name.
// Add Actions Menu option to disable logging.
// Fix size of main window when it changes between versions.
// Version 1.0.0.37
// Implement Paging.
// Fix L< command (was giving no messages).
// Implement LR LR mmm-nnn LR nnn- (and L nnn-)
// KM should no longer kill SYSOP bulls.
// ISP interfaces allows SMTP Auth to be configured
// SMTP Client would fail to send any more messages if a connection failed
// Version 1.0.0.38
// Don't include killed messages in L commands (except LK!)
// Implement l@
// Add forwarding timebands
// Allow resizing of main window.
// Add Ver command.
// Version 1.0.1.1
// First Public Beta
// Fix part line handling in Console
// Maintenance deletes old log files.
// Add option to delete files to the recycle bin.
// Version 1.0.2.1
// Allow all Node SYSOP commands in connect scripts.
// Implement FBB B1 Protocol with Resume
// Make FBB Max Block size settable for each BBS.
// Add extra logging when Chat Sessions refused.
// Fix Crash on invalid housekeeping override.
// Add Hold Messages option.
// Trap CRT Errors
// Sort Actions/Start Forwarding List
// Version 1.0.2.2
// Fill in gaps in BBS Number sequence
// Fix PE if ctext contains }
// Run Houskeeping at startup if previous Housekeeping was missed
// Version 1.0.2.3
// Add configured nodes to /p listing
// Version 1.0.2.4
// Fix RMS (it wanted B2 not B12)
// Send messages if available after rejecting all proposals
// Dont try to send msg back to originator.
// Version 1.0.2.5
// Fix timeband processing when none specified.
// Improved Chat Help display.
// Add helpful responses to /n /q and /t
// Version 1.0.2.6
// Kill Personal WP messages after processing
// Make sure a node doesnt try to "join" or "leave" a node as a user.
// More tracing to try to track down lost topic links.
// Add command recall to Console
// Show users in new topic when changing topic
// Add Send From Clipboard" Action
// Version 1.0.2.7
// Hold messages from the future, or with invalid dates.
// Add KH (kill held) command.
// Send Message to SYSOP when a new user connects.
// Version 1.0.2.8
// Don't reject personal message on Dup BID unless we already have an unforwarded copy.
// Hold Looping messages.
// Warn SYSOP of held messages.
// Version 1.0.2.9
// Close connecton on receipt of *** DONE (MBL style forwarding).
// Improved validation in link_drop (Chat Node)
// Change to welcome prompt and Msg Header for Outpost.
// Fix Connect Script processing for KA Nodes
// Version 1.0.3.1
// Fix incorrect sending of NO - BID.
// Fix problems caused by a user being connected to more than one chat node.
// Show idle time on Chat /u display.
// Rewrite forwarding by HA.
// Add "Bad Words" Test.
// Add reason for holding to SYSOP "Message Held" Message.
// Make topics case-insensitive.
// Allow SR for smtp mail.
// Try to fix some user's "Add User" problem.
// Version 1.0.3.2
// Fix program error when prcessing - response in FBB forwarding.
// Fix code to flag messages as sent.
// Version 1.0.3.3
// Attempt to fix message loop on topic_change
// Fix loop if compressed size is greater than 32K when receiving with B1 protocol.
// Fix selection of B1
// Version 1.0.3.4
// Add "KISS ONLY" Flag to R: Lines (Needs Node Version 4.10.12 (4.10l) or above)
// Add Basic NNTP Interface
// Fix possible loop in lzhuf encode
// Version 1.0.3.5
// Fix forwarding of Held Messages
// More attempts to fix Chat crashes.
// Limit join/leave problem with mismatched nodes.
// Add Chat Node Monitoring System.
// Change order of elements in nntp addresses (now to.at, was at.to)
// Version 1.0.3.6
// Restart and Exit if too many errors
// Fix forwarding of killed messages.
// Fix Forwarding to PaKet.
// Fix problem if BBS signon contains words from the "Fail" list
// Version 1.0.3.7
// re-fix loop if compressed size is greater than 32K - reintroduced in 1.0.3.4
// Add last message to edit users
// Change Console and Monitor Buffer sizes
// Don't flag msg as 'Y' on read if it was Held or Killed
// Version 1.0.3.8
// Don't connect if all messages for a BBS are held.
// Hold message if From or To are missing.
// Fix parsing of /n and /q commands
// fix possible loop on changing name or qth
// Version 1.0.3.9
// More Chat fixes and monitoring
// Added additional console for chat
// Version 1.0.3.10
// Fix for corruption of CIrcuit-Node chain.
// Version 1.0.3.11
// Fix flow control for SMTP and NNTP
// Version 1.0.3.12
// Fix crash in SendChatStatus if no Chat Links Defined.
// Disable Chat Mode if there is no ApplCall for ChatApplNum,
// Add Edit Message to Manage Messages Dialog
// NNTP needs authentication
// Version 1.0.3.13
// Fix Chat ApplCall warning when ChatAppl = 0
// Add NNTP NEWGROUPS Command
// Fix MBL Forwarding (remove extra > prompt after SP)
// Version 1.0.3.14
// Fix topic switch code.
// Send SYSOP messages on POP3 interface if User SYSOP flag is set.
// NNTP only needs Authentication for posting, not reading.
// Version 1.0.3.15
// Fix reset of First to Forward after househeeping
// Version 1.0.3.16
// Fix check of HA for terminating WW
// MBL Mode remove extra > prompts
// Fix program error if WP record has unexpected format
// Connect Script changes for WINMOR
// Fix typo in unconfigured node has connected message
// Version 1.0.3.17
// Fix forwarding of Personals
// Version 1.0.3.18
// Fix detection of misconfigured nodes to work with new nodes.
// Limit connection attempt rate when a chat node is unavailable.
// Fix Program Error on long input lines (> ~250 chars).
// Version 1.0.3.19
// Fix Restart of B2 mode transfers.
// Fix error if other end offers B1 and you are configured for B2 only.
// Version 1.0.3.20
// Fix Paging in Chat Mode.
// Report Node Versions.
// Version 1.0.3.21
// Check node is not already known when processing OK
// Add option to suppress emailing of housekeeping results
// Version 1.0.3.22
// Correct Version processing when user connects via the network
// Add time controlled forwarding scripts
// Version 1.0.3.23
// Changes to RMS forwarding
// Version 1.0.3.24
// Fix RMS: from SMTP interface
// Accept RMS/ instead of RMS: for Thunderbird
// Version 1.0.3.25
// Accept smtp: addresses from smtp client, and route to ISP gateway.
// Set FROM address of messages from RMS that are delivered to smtp client so a reply will go back via RMS.
// Version 1.0.3.26
// Improve display of rms and smtp messages in message lists and message display.
// Version 1.0.3.27
// Correct code that prevents mail being retured to originating BBS.
// Tidy stuck Nodes and Topics when all links close
// Fix B2 handling of @ to TO Address.
// Version 1.0.3.28
// Ensure user Record for the BBS Call has BBS bit set.
// Don't send messages addressed @winlink.org if addressee is a local user with Poll RMS set.
// Add user configurable welcome messages.
// Version 1.0.3.29
// Add AUTH feature to Rig Control
// Version 1.0.3.30
// Process Paclink Header (;FW:)
// Version 1.0.3.31
// Process Messages with attachments.
// Add inactivity timeout to Chat Console sessions.
// Version 1.0.3.32
// Fix for Paclink > BBS Addresses
// Version 1.0.3.33
// Fix multiple transfers per session for B2.
// Kill messages eent to paclink.
// Add option to forward messages on arrival.
// Version 1.0.3.34
// Fix bbs addresses to winlink.
// Fix adding @winlink.org to imcoming paclink msgs
// Version 1.0.3.35
// Fix bbs addresses to winlink. (Again)
// Version 1.0.3.36
// Restart changes for RMS/paclink
// Version 1.0.3.37
// Fix for RMS Express forwarding
// Version 1.0.3.38
// Fixes for smtp and lower case packet addresses from Airmail
// Fix missing > afer NO - Bid in MBL mode
// Version 1.0.3.39
// Use ;FW: for RMS polling.
// Version 1.0.3.40
// Add ELSE Option to connect scripts.
// Version 1.0.3.41
// Improved handling of Multiple Addresses
// Add user colours to chat.
// Version 1.0.3.42
// Poll multiple SSID's for RMS
// Colour support for BPQTEerminal
// New /C chat command to toggle colour on or off.
// Version 1.0.3.43
// Add SKIPPROMPT command to forward scripts
// Version 1.0.4.1
// Non - Beta Release
// Fix possible crash/corruption with long B2 messages
// Version 1.0.4.2
// Add @winlink.org to the B2 From addresss if it is just a callsign
// Route Flood Bulls on TO as well as @
// Version 1.0.4.3
// Handle Packet Addresses from RMS Express
// Fix for Housekeeping B$ messages
// Version 1.0.4.4
// Remove B2 header and all but the Body part from messages forwared using MBL
// Fix handling of ;FW: from RMS Express
// Version 1.0.4.5
// Disable Paging on forwarding sessions.
// Kill Msgs sent to RMS Exxpress
// Add Name to Chat *** Joined msg
// Version 1.0.4.6
// Pass smtp:winlink.org messages from Airmail to local user check
// Only apply local user check to RMS: messages @winlink.org
// Check locally input smtp: messages for local winlink.org users
// Provide facility to allow only one connect on a port
// Version 1.0.4.8
// Only reset last listed on L or LR commands.
// Version 1.0.4.9
// Fix error in handling smtp: messages to winlink.org addresses from Airmail
// Version 1.0.4.10
// Fix Badwords processing
// Add Connect Script PAUSE command
// Version 1.0.4.11
// Suppress display and listing of held messages
// Add option to exclude SYSOP messages from LM, KM, etc
// Fix crash whan receiving messages with long lines via plain text forwarding
// Version 1.0.4.12 Jul 2010
// Route P messages on AT
// Allow Applications above 8
// Version 1.0.4.13 Aug 2010
// Fix TidyString for addresses of form John Wiseman <john.wiseman@ntlworld.com>
// Add Try/Except around socket routines
// Version 1.0.4.14 Aug 2010
// Trap "Error - TNC Not Ready" in forward script response
// Fix restart after program error
// Add INFO command
// Add SYSOP-configurable HELP Text.
// Version 1.0.4.15 Aug 2010
// Semaphore Connect/Disconnect
// Semaphore RemoveTempBIDS
// Version 1.0.4.16 Aug 2010
// Remove prompt after receiving unrecognised line in MBL mode. (for MSYS)
// Version 1.0.4.17 Aug 2010
// Fix receiving multiple messages in FBB Uncompressed Mode
// Try to trap phantom chat node connections
// Add delay to close
// Version 1.0.4.18 Aug 2010
// Add "Send SYSTEM messages to SYSOP Call" Option
// set fwd bit on local winlink.org msgs if user is a BBS
// add winlink.org to from address of messages from WL2K that don't already have an @
// Version 1.0.4.19 Sept 2010
// Build a B2 From: address if possible, so RMS Express can reply to packet messages.
// Fix handling of addresses from WL2K with SSID's
// L@ now only matches up to length of input string.
// Remove "Type H for help" from login prompt.
// Version 1.0.4.20 Sept 2010
// Process FBB 'E' response
// Handle FROM addresses with an @BBS
// Fix FROM addresses with @ on end.
// Extend delay before close after sending FQ on winmor/pactor sessions.
// Version 1.0.4.21 Sept 2010
// Fix handling B2 From: with an HA
// Add "Expert User" welcome message.
// Version 1.0.4.22 Sept 2010
// Version 1.0.4.23 Oct 2010
// Add Dup message supression
// Dont change B2 from if going to RMS
// Version 1.0.4.24 Oct 2010
// Add "Save Registry Config" command
// Add forwarding on wildcarded TO for NTS
// Add option to force text mode forwarding
// Define new users as a temporaty BBS if SID received in reply to Name prompt
// Reduce delay before sending close after sending FQ on pactor sessions
// Fix processing of MIME boundary from GMail
// Send /ex instead of ctrl/z for text mode forwarding
// Send [WL2K-BPQ... SID if user flagged as RMS Express
// Fix Chat Map reporting when more than one AXIP port
// Add Message State D for NTS Messages
// Forward messages in priority order - T, P, B
// Add Reject and Hold Filters
// Fix holding messages to local RMS users when received as part of a multiple addressee message
// Version 1.0.4.25 Nov 2010
// Renumbered for release
// Add option to save Registry Config during Housekeeping
// Version 1.0.4.26 Nov 2010
// Fix F> loop when doing MBL forwarding between BPQ BBSes
// Allow multiple To: addresses, separated by ;
// Allow Houskeeping Lifetime Overrides to apply to Unsent Messages.
// Set Unforwarded Bulls to status '$'
// Accept MARS and USA as continent codes for MARS Packet Addresses
// Add option to send Non-delivery notifications.
// Version 1.0.4.27 Dec 2010
// Add MSGTYPES fwd file option
// Version 1.0.4.28 Dec 2010
// Renumbered to for release
// Version 1.0.4.30 Dec 2010
// Fix rescan requeuing where bull was rejected by a BBS
// Fiz flagging bulls received by NNTP with $ if they need to be forwarded.
// Add Chat Keepalive option.
// Fix bug in non-delivery notification.
// Version 1.0.4.32 Jan 2011
// Allow "Send from Clipboard" to send to rms: or smtp:
// Allow messages received via SMTP to be bulls (TO preceeded by bull/) or NTS (to nnnnn@NTSXX or nnnnn@NTSXX.NTS)
// Fix corruption of messages converted to B2 if body contains binary data
// Fix occasional program error when forwarding B2 messages
// Limit FBB protocol data blocks to 250 to try to fix restart problem.
// Add F2 to F5 to open windows.
// Version 1.0.4.33 Jan 2011
// Fix holding old bulls with forwarding info.
// Version 1.0.4.33 Jan 2011
// Prevent transfer restarting after a program error.
// Allow Housekeeping to kill held messages.
// Version 1.0.4.35 Jan 2011
// Add Size limits for P and T messages to MSGTYPES command
// Fix Error in MBL processing when blank lines received (introduced in .33)
// Trap possible PE in Send_MON_Datagram
// Don't use paging on chat sessions
// Version 1.0.4.36 Jan 2011
// Fix error after handling first FBB block.
// Add $X and $x welcome message options.
// Version 1.0.4.37 Jan 2011
// Change L command not to list the last message if no new ones are available
// Add LC I I@ IH IZ commands
// Add option to send warning to sysop if forwarded P or T message has nowhere to go
// Fixes for Winpack Compressed Download
// Fix Houskeeping when "Apply Overrides to Unsent Bulls" is set.
// Add console copy/paste.
// Add "No Bulls" Option.
// Add "Mail For" Beacon.
// Tidied up Tab order in config dialogs to help text-to-speech programs.
// Limit MaxMsgno to 99000.
// Version 1.0.4.38 Feb 2011
// Renumbered for release
// Version 1.0.4.40 April 2011
// Add POLLRMS command
// Changes for Vista/Win7 (registry key change)
// Workaround for changes to RMS Express
// Fix AUTH bug in SMTP server
// Add filter to Edit Messages dialog
// Version 1.0.4.41 April 2011
// Extend B2 proposals to other BPQMail systems so Reject Filter will work.
// Add Edit User Command
// Use internal Registry Save routine instead of Regedit
// Fix Start Forward/All
// Allow Winpack Compressed Upload/Download if PMS flag set (as well as BBS flag)
// Add FWD SYSOP command
// Fix security on POLLRMS command
// Add AUTH command
// Leave selection in same place after Delete User
// Combine SMTP server messages to multiple WL2K addresses into one message to WL2k
// Add option to show name as well as call on Chat messages
// Fix program error if you try to define more than 80 BBS's
// Version 1.0.4.45 October 2011
// Changes to program error reporting.
// BBS "Returh to Node" command added
// Move config to "Standard" location (BPQ Directory/BPQMailChat) .
// Fix crash if "Edit Message" clicked with no message selected.
// Version 1.0.4.46 October 2011
// Fix BaseDir test when BaseDir ends with \ or /
// Fix long BaseDir values (>50 chars)
// Version 1.4.47.1 January 2012
// Call CloseBPQ32 on exit
// Add option to flash window instead of sounding bell on Chat Connects
// Add ShowRMS SYSOP command
// Update WP with I records from R: lines
// Send WP Updates
// Fix Paclen on Pactor-like sessions
// Fix SID and Prompt when RMS Express User is set
// Try to stop loop in Program Error/Restarting code
// Trap "UNABLE TO CONNECT" response in connect script
// Add facility to print messages or save them to a text file
// Version 1.4.48.1 January 2012
// Add Send Message (as well as Send from Clipboard)
// Fix Email From: Address when forwaring using B2
// Send WP from BBSCALL not SYSOPCALL
// Send Chat Map reports via BPQ32.dll
// Version 1.4.49.1 February 2012
// Fix Setting Paclink mode on SNOS connects
// Remove creation of debugging file for each message
// Add Message Export and Import functions
// All printing of more than one message at a time
// Add command to toggle "Expert" status
// Version 1.4.50.1 February 2012
// Fix forwarding to RMS Express users
// Route messages received via B2 to an Internet email address to RMS
// Add Reverse Poll interval
// Add full FROM address to POP3 messages
// Include HOMEBBS command in Help
// Version 1.4.51.1 June 2012
// Allow bulls to be sent from RMS Express.
// Handle BASE64 and Quoted-printable encoding of single part messages
// Work round for RMS Express "All proposals rejected" Bug.
// Version 1.4.52.1 August 2012
// Fix size limit on B2 To List when sending to multiple dests
// Fix initialisation of DIRMES.SYS control record
// Allow use of Tracker and UZ7HO ports for UI messages
// Version 1.4.53.1 September 2012
// Fix crash if R: line with out a CR found.
// Version 1.4.54.1 ?? 2012
// Add configurable prompts
// Fix KISS-Only Test
// Send EHLO instead of HELO when Authentication is needed on SMTP session
// Add option to use local tome for bbs forwarding config
// Allow comment lines (; or @) or single space in fwd scripts
// Fix loss of forwarding info if SAVE is clicked before selecting a call
// Version 1.4.55.1 June 2013
// Add option to remove users that have not connected for a long time.
// Add l@ smtp:
// Fix From: sent to POP3 Client when meaages is from RMS
// Display Email From on Manage Messages
// Version 1.4.56.1 July 2013
// Add timeout
// Verify prompts
// Add IDLETIME command
// Version 1.4.57.1
// Change default IDLETIME
// Fix display of BBS's in Web "Manage Messages"
// Add separate househeeping lifetines for T messages
// Don't change flag on forwarded or delivered messages if they sre subsequently read
// Speed up processing, mainly to stop RMS Express timing out when connecting via Telnet
// Don't append winlink.org to RMS Express or Paclink addresses if RMS is not configured
// Fix receiving NTS messages via B2
// Add option to send "Mail For", but not FBB Headers
// Fix corruption caused with Subject longer than 60 bytes reveived from Winlink systems
// Fix Endian bug in FBB Compression code
// Version 1.4.58.1
// Change control of appending winlink.org to RMS Express or Paclink addresses to a user flag
// Lookup HomeBBS and WP for calls without a via received from RMS Express or Paclink
// Treat call@bpq as request to look up address in Home BBS/WP for messages received from RMS Express or Paclink
// Collect stats by message type
// Fix Non-Delivery notifications to SMTP messages
// Add Message Type Stats to BBS Trafic Report
// Add "Batch forward to email"
// Add EXPORT command
// Allow more BBS records
// Allow lower case connect scripts
// Fix POP3 LIST command
// Fix MIME Multipart Alternate with first part Base64 or Quoted Printable encoding
// Fix duplicates of SP SYSOP@WW Messages
// Add command line option (tidymail) to delete redundant Mail files
// Add command line option (nohomebbs) to suppress HomeBBS prompt
// 59 April 2014
// Add FLARQ Mail Mode
// Fix possible crash saving restart data
// Add script command ADDLF for connect scripts over Telnet
// Add recogniton of URONODE connected message
// Add option to stop Name prompt
// Add new RMS Express users with "RMS Express User" flag set
// Validate HTML Pages
// Add NTS swap file
// Add basic File list and read functions
// Fix Traffic report
// 60
// Fix security hole in readfile
// 61 August 2014
// Set Messages to NTS:nnnnn@NTSXX to type 'T' and remove NTS
// Dont treat "Attempting downlink" as a failure
// Add option to read messages during a list
// Fix crash during message renumber on MAC
// Timeout response to SID to try to avoid hang on an incomplete connection.
// Save config in file instead of registry
// Fix Manage Messages "EXPORT" option and check filename on EXPORT command
// Fix reverse forward prompt in MBL mode.
// Fix From address in POP3 messages where path is @winlink.org
// Fix possible program error in T message procesing
// Add MaxAge param (for incoming Bulls)
//62 November 2014
// Add ZIP and Permit Bulls flag to Manage Users
// Allow users to kill their own B and anyone to kill T messages
// Improve saving of "Last Listed"
// Fix LL when paging
// Send Date received in R: Line (should fix B2 message restarts)
// Fix occasional crash in terminal part line processing
// Add "SKIPCON" forwarding command to handle nodes that include "Connected" in their CTEXT
// Fix possible retry loop when message is deferred (FBB '=' response);
// Don't remove Attachments from received bulls.
//63 Feb 2015
// Fix creating Bulls from RMS Express messages.
// Fix PE if message with no To: received.
// Fix setting "RMS Express User" flag on new connects from RMS Express
// Fix deleting 'T' messages downloaded by RMS Express
// Include MPS messages in count of messages to forward.
// Add new Welcome Message variable $F for messages to forward
// Fix setting Type in B2 header when usong NTS: or BULL:
// Remove trailing spaces from BID when Creating Message from Clipboard.
// Improved handling of FBB B1/B2 Restarts.
//64 September 2015
// Fix Message Type in msgs from RMS Express to Internet
// Reopen Monitor window if open when program list closed
// Only apply NTS alias file to NTS Messages
// Fix failure to store some encrypted ISP passwords
// Allow EDITUSER to change "RMS Express User" flag
// Fix reporting of Config File errors
// Fix Finding MPS Messages (First to Forward was being used incorrectly)
// Add "Save Attachment" to Web Mgmt Interface
// Support Secure Signon on Forwarding sessions to CMS
// Save Forwarding config when BBS flag on user is cleared
// Pass internally generated SYSOP messages through routing process
// Add POP3 TOP command.
// Don't set 'T' messages to 'Y' when read.
// Add optional temporary connect script on "FWD NOW" command
// Add automatic import facility
// Accept RMS mail to BBS Call even if "Poll RMS" not set.
// 65 November 2015
// Fix loading Housekeeping value for forwarded bulls.
// Fix re-using Fwd script override in timer driven forwarding.
// Add ampr.org handling
// Add "Dont forward" match on TO address for NTS
// Allow listing a combinatiom of state and type, such as LNT or LPF
// Fix handling ISP messages from gmail without a '+'
// Add basic WebMail support
// 66
// Autoimport messages as Dummy Call, not SYSOP Call
// Add "My Messages" display option to WebMail
// Create .csv extract of User List during hourekeeping.
// Fix processing of NTS Alising of @ Addresses
// Don't reroute Delivered NTS Messages
// Add option to stop users killing T messages
// Add multicast Receive
// Fix initialising new message database format field
// Fix "Forward Messages to BBS Call" option.
// Add Filter WP Bulls option and allow multiple WP "TO" addresses
// Fix deleting P WP messages for other stations
// Fix saving blank lines in forwarding config
// Fix paging on L@ and l<
// Fix removing DELETE from IMPORT XXX DELETE and allow multiple IMPORT lines in script
// Run DeleteRedundantMessages before renumbering messages
// Connect script now tries ELSE lines if prompt not received from remote BBS
// Send connecting call instead of BBS Name when connecting to CMS server.
// Add BID filter to Manage Messages
// Fix handling of over long suject lines in IMPORT
// Allow comments before ELSE in connect script
// Add Copy and Clear to Multicast Window
// Fix possible duplicate messages with MBL forwarding
// Set "Permit EMail" on IMPORT dummy User.
// Fix repeated running of housekeeping if clock is stepped forward.
// Fix corruption of CMS Pass field by Web interface
// Kill B2 WP bulls if FilterWPBulls set
// Include Message Type in BPQ B2 proposal extensions
// 6.0.14.1 July 2017
// Fix corruption of BBSNumber if RMS Ex User and BBS both checked
// Tread B messages without an AT as Flood.
// Make sure Message headers are always saved to disk when a message status changes
// Reject message instead of failing session if TO address too long in FBB forwarding
// Fix error when FBB restart data exactly fills a packet.
// Fix possible generation of msg number zero in send nondlivery notification
// Fix problem with Web "Manage Messages" when stray message number zero appears
// Fix Crash in AMPR forward when host missing from VIA
// Fix possible addition of an spurious password entry to the ;FW: line when connecting to CMS
// Fix test for Status "D" in forward check.
// Don't cancel AUTH on SMTP RSET
// Fix "nowhere to go" message on some messages sent to smtp addresses
// Add @ from Home BBS or WP is not spcified in "Send from Clipboard"
// 6.0.15.1 Feb 2018
// Fix PE if Filename missing from FILE connect script command
// Suppress reporting errors after receiving FQ
// Fix problem caused by trailing spaces on callsign in WP database
// Support mixed case WINLINK Passwords
// 6.0.16.1 March 2018
// Make sure messages sent to WL2K don;'t have @ on from: address
// If message to saildocs add R: line as an X header instead of to body
// Close session if more than 4 Invalid Commmad responses sent
// Report TOP in POP3 CAPA list. Allows POP3 to work with Windows Mail client
// 6.0.17.1 November 2018
// Add source routing using ! eg sp g8bpq@winlink.org!gm8bpq to send via RMS on gm8bpq
// Accept an internet email address without rms: or smtp:
// Fix "Forward messages for BBS Call" when TO isn't BBS Call
// Accept NNTP commands in either case
// Add NNTP BODY command
// Timeout POP or SMTP TCP connections that are open too long
// Add YAPP support
// Fix connect script when Node CTEXT contains "} BBS "
// Fix handling null H Route
// Detect and correct duplicate BBS Numbers
// Fix problem if BBS requests FBB blocked forwarding without compression (ie SID of F without B)
// Fix crash if YAPP entered without filenmame and send BBS prompt after YAPP error messages
// Add support for Winlink HTML Forms to WebMail interface
// Update B2 header when using NTS alias file with B2 messages
// 6.0.18.1 January 2019
// Ensure callsigns in WP database are upper case.
// Various fixes for Webmail
// Fix sending direct to ampr.org addresses
// Use SYSOP Call as default for Webmail if set
// Preparations for 64 bit version
// 6.0.19.1 September 2019
// Trap missing HTML reply Template or HTML files
// Fix case problems in HTML Templates
// Fix setting To call on reply to HTML messages
// More preparations for 64 bit including saving WP info as a text file.
// Set "RMS Express User" when a new user connects using PAT
// Increace maximum length on Forwarding Alias string in Web interface
// Expand multiaddress messages from Winlink Express if "Don't add @Winlink.org" set or no RMS BBS
// Fix program error if READ used without a filename
// Trap reject messages from Winlink CMS
// Fix "delete to recycle bin" on Linux
// Handle Radio Only Messages (-T or -R suffix on calling station)
// Fix program error on saving empty Alias list on Web Forwarding page
// Add REQDIR and REQFIL
// Experimental Blocked Uncompressed forwarding
// Security fix for YAPP
// Fix WebMail Cancel Send Message
// Fix processing Hold Message response from Winlink Express
// 6.0.20.1 April 2020
// Improvments to YAPP
// Add Copy forwarding config
// Add Next and Previous buttons to Webmail message read screen
// Move HTML templates from HTMLPages to inline code.
// Fix Paclen on YAPP send
// Fix bug in handling "RMS Express User"
// Fix WINPACK compressed forwarding
// Add option to send P messages to more than one BBS
// Add "Default to Don't Add WINLINK.ORG" Config option
// Re-read Badwords.sys during Housekeeping
// Add BID Hold and Reject Filters
// On SMTP Send try HELO if EHLO rejected
// Allow SID response timeout to be configured per BBS
// Fix sending bulls with PAT
// Set "Forward Messages to BBS Call" when routing Bulls on TO
// Add option to send Mail For Message to APRS
// Fix WP update
// Fix Holding messages from Webmail Interface
// Add RMR command
// Add REROUTEMSGS BBS SYSOP command
// Disable null passwords and check Exclude flag in Webmail Signin
// Add basic Webmail logging
// 6.0.21.1 December 2020
// Remove nulls from displayed messages.
// Fix Holding messages from SMTP and POP3 Interfaces
// Various fixes for handling messages to/from Internet email addresses
// Fix saving Email From field in Manage Messages
// Fix sending WL2K traffic reports via TriMode.
// Fix removing successive CR from Webmail Message display
// Fix Wildcarded @ forwarding
// Fix message type when receiving NTS Msgs form Airmail
// Fix address on SERVICE messages from Winlink
// Add multiple TO processing to Webmail non-template messages
// Don't backup config file if reading it fails
// Include Port and Freq on Connected log record
// Make sure welcome mesages don't end in >
// Allow flagging unread T messages as Delivered
// Replace \ with # in forward script so commands starting with # can be sent
// Fix forwarding NTS on TO field
// Fix possible crash in text mode forwarding
// Allow decimals of days in P message lifetimes and allow Houskeeping interval to be configured
// Add DOHOUSEKEEPING sysop command
// Add MARS continent code
// Try to trap 'zombie' BBS Sessions
// On Linux if "Delete to Recycle Bin" is set move deleted messages and logs to directory Deleted under current directory.
// Fix corruption of message length when reading R2 message via Read command
// Fix paging on List command and add new combinations of List options
// Fix NNTP list and LC command when bulls are killed
// 6.0.22.1 August 2021
// Fix flagging messages with attachments as read.
// Fix possible corruption of WP database and subsequent crash on reloading.
// Fix format of Web Manage Messages display
// Include SETNEXTMESSAGENUMBER in SYSOP Help Message
// Fix occasional "Incoming Connect from SWITCH"
// Fix L> with numeric dests
// Improved diagnostic for MailTCP select() error.
// Clear "RMS Express User" if user is changed to a BBS
// Fix saving Window positions on exit
// Fix parsing ReplyTemplate name in Webmail
// Handle multiple addressees for WebMail Forms messages to packet stations
// Add option to allow only known users to connect
// Add basic callsign validation to From address
// Add option to forward a user's messages to Winlink
// Move User config to main config file.
// Update message status whne reading a Forms Webmail message
// Speed up killing multiple messages
// Allow SendWL2KFW as well as the (incorrect)SendWL2KPM command
// 6.0.23.1 June 2022
// Fix crash when ; added to call in send commands
// Allow smtp/ override for messages from RMS Express to send via ISP gateway
// Send Internet email from RMS Express to ISP Gateway if enabled and RMS BBS not configured
// Recompiled for Web Interface changes in Node
// Add RMS Relay SYNC Mode (.17)
// Add Protocol changes for Relay RO forwarding
// Add SendWL2KPM command to connect script to allow users other than RMS to send ;FW: string to RMS Relay
// Fix B2 Header Date in Webmail message with sttachments.
// Fix bug when using YAPP with VARA (.27)
// Allow SendWL2KFW as well as the (incorrect)SendWL2KPM command
// Add mechsnism to send bbs log records to qttermtcp. (32)
// Add MFJ forwarding Mode (No @BBS on send)
// Fix handling CR/LF split over packet boundaries
// Add Header and Footers for Webmail Send (42)
// Fix Maintenance Interval in LinBPQ (53)
// Add RMS: to valid from addresses (.56)
// Fix Web management on Android deviced (.58)
// Disconnect immediately if "Invalid Command" "*** Protocol Error" or "Already Connected" received (.70)
// Check Badword and Reject filters before processing WP Messages
// 6.0.24.1 August 2023
// Fix ' in Webmail subject (8)
// Change web buttons to white on black when pressed (10)
// Add auto-refresh option to Webmail index page (25)
// Fix displaying help and info files with crlf line endings on Linux (28)
// Improve validation of extended FC message (32)
// Improve WP check for SYSTEM as a callsign (33)
// Improvements to RMS Relay SYNC mode (47)
// Fix BID Hold and Reject filters
// Fix Webmail auto-refresh when page exceeds 64K bytes (54)
// Fix Webmail send when using both headers/footers and attachmonts (55)
// Fix R: line corruption on some 64 bit builds
// Dont drop empty lines in TEXTFORWARDING (61)
// Dont wait for body prompt for TEXTFORWARDING for SID [PMS-3.2-C$] (62)
// Add forwarding mode SETCALLTOSENDER for PMS Systems that don't accept < in SP (63)
// QtTerm Monitoring fixed for 63 port version of BPQ (69)
// Fix to UI system to support up to 63 ports (79)
// Fix recently introduced crash when "Don't allow new users" is set (81)
// Skip comments before TIMES at start of Connect Script (83)
// 6.0.25.1 ??
// Add FBB reject.sys style filters (3)
// Improve Webmail on 64 bit builds
// Fix setting status '$' on Bulls sent via WebMail (22)
// Implement New Message and Message Read Events (23)
// Start adding json api (25)
// Fix reading nested directories when loading Standard Templates and other template bugs (25)
// Add TO and AT to "Message has nowhere to go" message (28)
// Add My Sent and My Received filter options to Webmail (30)
// Add Send P to multiple BBS's when routing on HR (30)
// Fix Traffic stats for T messages received via B2 forwarding (31)
// Fix possible failure to update last listed count when user disconnects without using B command
// Add short random delay (<30 secs) when forward new Messages immediately is enabled (35)
// Fix Connect Script IDLETIME (38)
// Add "Mail Mgmt" to Webmail menu bar and "WebMail" to Mail Mgmt Menu (39)
// Improve "New User" frequency determination (39)
// Allow selection of 2 or 4 character country codes for forward processing (39)
// Fix Send P to multiple BBS's when routing on HR (40)
// Rewrite PG server code on Lunux (41)
// Fix SendPToMultiple not stopping at Implied AT match (45)
// Log Our HA when checking for flood bulls (45)
// Semaphore calls to SaveConfig
// Include SERVIC as valid from call (for Winlink Service messages) (49)
// Attempt to detect line draw characters in Webmail (50)
// Fix sending ampr.org mail when RMS is not enabled (51)
// Send forwarding info to packetnodes.spots.radio database (51)
#include "bpqmail.h"
#include "winstdint.h"
#define MAIL
#include "Versions.h"
#include "GetVersion.h"
#define MAX_LOADSTRING 100
typedef int (WINAPI FAR *FARPROCX)();
typedef int (WINAPI FAR *FARPROCZ)();
FARPROCX pDllBPQTRACE;
FARPROCZ pGetLOC;
FARPROCX pRefreshWebMailIndex;
FARPROCX pRunEventProgram;
FARPROCX pGetPortFrequency;
FARPROCX pSendWebRequest;
FARPROCX pGetLatLon;
BOOL WINE = FALSE;
INT_PTR CALLBACK UserEditDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK MsgEditDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK FwdEditDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK WPEditDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
VOID SetupNTSAliases(char * FN);
HKEY REGTREE = HKEY_LOCAL_MACHINE; // Default
char * REGTREETEXT = "HKEY_LOCAL_MACHINE";
// Global Variables:
HINSTANCE hInst; // current instance
TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
extern int LastVer[4]; // In case we need to do somthing the first time a version is run
UINT BPQMsg;
HWND MainWnd;
HWND hWndSess;
RECT MainRect;
HMENU hActionMenu;
static HMENU hMenu;
HMENU hDisMenu; // Disconnect Menu Handle
HMENU hFWDMenu; // Forward Menu Handle
int SessX, SessY, SessWidth; // Params for Session Window
char szBuff[80];
#define MaxSockets 64
int _MYTIMEZONE = 0;
ConnectionInfo Connections[MaxSockets+1];
//struct SEM AllocSemaphore = {0, 0};
//struct SEM ConSemaphore = {0, 0};
//struct SEM OutputSEM = {0, 0};
//struct UserInfo ** UserRecPtr=NULL;
//int NumberofUsers=0;
//struct UserInfo * BBSChain = NULL; // Chain of users that are BBSes
//struct MsgInfo ** MsgHddrPtr=NULL;
//int NumberofMessages=0;
//int FirstMessageIndextoForward=0; // Lowest Message wirh a forward bit set - limits search
//BIDRec ** BIDRecPtr=NULL;
//int NumberofBIDs=0;
extern BIDRec ** TempBIDRecPtr;
//int NumberofTempBIDs=0;
//WPRec ** WPRecPtr=NULL;
//int NumberofWPrecs=0;
extern char ** BadWords;
//int NumberofBadWords=0;
extern char * BadFile;
//int LatestMsg = 0;
//struct SEM MsgNoSemaphore = {0, 0}; // For locking updates to LatestMsg
//int HighestBBSNumber = 0;
//int MaxMsgno = 60000;
//int BidLifetime = 60;
//int MaintInterval = 24;
//int MaintTime = 0;
//int UserLifetime = 0;
BOOL cfgMinToTray;
BOOL DisconnectOnClose;
extern char PasswordMsg[100];
char cfgHOSTPROMPT[100];
char cfgCTEXT[100];
char cfgLOCALECHO[100];
char AttemptsMsg[];
char disMsg[];
char LoginMsg[];
char BlankCall[];
ULONG BBSApplMask;
ULONG ChatApplMask;
int BBSApplNum;
//int StartStream=0;
int NumberofStreams;
int MaxStreams;
extern char BBSSID[];
extern char ChatSID[];
extern char NewUserPrompt[100];
extern char * WelcomeMsg;
extern char * NewWelcomeMsg;
extern char * ExpertWelcomeMsg;
extern char * Prompt;
extern char * NewPrompt;
extern char * ExpertPrompt;
extern BOOL DontNeedHomeBBS;
char BBSName[100];
char MailForText[100];
char SignoffMsg[100];
char AbortedMsg[100];
extern char UserDatabaseName[MAX_PATH];
extern char UserDatabasePath[MAX_PATH];
extern char MsgDatabasePath[MAX_PATH];
extern char MsgDatabaseName[MAX_PATH];
extern char BIDDatabasePath[MAX_PATH];
extern char BIDDatabaseName[MAX_PATH];
extern char WPDatabasePath[MAX_PATH];
extern char WPDatabaseName[MAX_PATH];
extern char BadWordsPath[MAX_PATH];
extern char BadWordsName[MAX_PATH];
char NTSAliasesPath[MAX_PATH];
extern char NTSAliasesName[MAX_PATH];
char BaseDir[MAX_PATH];
char BaseDirRaw[MAX_PATH]; // As set in registry - may contain %NAME%
char MailDir[MAX_PATH];
char RlineVer[50];
extern BOOL KISSOnly;
extern BOOL OpenMon;
extern struct ALIAS ** NTSAliases;
extern int EnableUI;
extern int RefuseBulls;
extern int SendSYStoSYSOPCall;
extern int SendBBStoSYSOPCall;
extern int DontHoldNewUsers;
extern int ForwardToMe;
extern int MailForInterval;
char zeros[NBMASK]; // For forward bitmask tests
time_t MaintClock; // Time to run housekeeping
struct MsgInfo * MsgnotoMsg[100000]; // Message Number to Message Slot List.
// Filter Params
char ** RejFrom; // Reject on FROM Call
char ** RejTo; // Reject on TO Call
char ** RejAt; // Reject on AT Call
char ** RejBID; // Reject on BID
char ** HoldFrom; // Hold on FROM Call
char ** HoldTo; // Hold on TO Call
char ** HoldAt; // Hold on AT Call
char ** HoldBID; // Hold on BID
// Send WP Params
BOOL SendWP;
char SendWPVIA[81];
char SendWPTO[11];
int SendWPType;
int ProgramErrors = 0;
UCHAR BPQDirectory[260] = "";
// Forward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
ATOM RegisterMainWindowClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK ClpMsgDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK SendMsgDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK ChatMapDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
unsigned long _beginthread( void( *start_address )(VOID * DParam),
unsigned stack_size, VOID * DParam);
VOID SendMailForThread(VOID * Param);
BOOL CreatePipeThread();
int DeleteRedundantMessages();
VOID BBSSlowTimer();
VOID CopyConfigFile(char * ConfigName);
BOOL CreateMulticastConsole();
char * CheckToAddress(CIRCUIT * conn, char * Addr);
BOOL CheckifPacket(char * Via);
int GetHTMLForms();
VOID GetPGConfig();
void SendBBSDataToPktMap();
struct _EXCEPTION_POINTERS exinfox;
CONTEXT ContextRecord;
EXCEPTION_RECORD ExceptionRecord;
DWORD Stack[16];
BOOL Restarting = FALSE;
void Dump_Process_State(struct _EXCEPTION_POINTERS * exinfo, char * Msg)
{
unsigned int SPPtr;
unsigned int SPVal;
memcpy(&ContextRecord, exinfo->ContextRecord, sizeof(ContextRecord));
memcpy(&ExceptionRecord, exinfo->ExceptionRecord, sizeof(ExceptionRecord));
SPPtr = ContextRecord.Esp;
Debugprintf("BPQMail *** Program Error %x at %x in %s",
ExceptionRecord.ExceptionCode, ExceptionRecord.ExceptionAddress, Msg);
__asm{
mov eax, SPPtr
mov SPVal,eax
lea edi,Stack
mov esi,eax
mov ecx,64
rep movsb
}
Debugprintf("EAX %x EBX %x ECX %x EDX %x ESI %x EDI %x ESP %x",
ContextRecord.Eax, ContextRecord.Ebx, ContextRecord.Ecx,
ContextRecord.Edx, ContextRecord.Esi, ContextRecord.Edi, SPVal);
Debugprintf("Stack:");
Debugprintf("%08x %08x %08x %08x %08x %08x %08x %08x %08x ",
SPVal, Stack[0], Stack[1], Stack[2], Stack[3], Stack[4], Stack[5], Stack[6], Stack[7]);
Debugprintf("%08x %08x %08x %08x %08x %08x %08x %08x %08x ",
SPVal+32, Stack[8], Stack[9], Stack[10], Stack[11], Stack[12], Stack[13], Stack[14], Stack[15]);
}
void myInvalidParameterHandler(const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
unsigned int line,
uintptr_t pReserved)
{
Logprintf(LOG_DEBUG_X, NULL, '!', "*** Error **** C Run Time Invalid Parameter Handler Called");
if (expression && function && file)
{
Logprintf(LOG_DEBUG_X, NULL, '!', "Expression = %S", expression);
Logprintf(LOG_DEBUG_X, NULL, '!', "Function %S", function);
Logprintf(LOG_DEBUG_X, NULL, '!', "File %S Line %d", file, line);
}
}
// If program gets too many program errors, it will restart itself and shut down
VOID CheckProgramErrors()
{
STARTUPINFO SInfo; // pointer to STARTUPINFO
PROCESS_INFORMATION PInfo; // pointer to PROCESS_INFORMATION
char ProgName[256];
if (Restarting)
exit(0); // Make sure can't loop in restarting
ProgramErrors++;
if (ProgramErrors > 25)
{
Restarting = TRUE;
Logprintf(LOG_DEBUG_X, NULL, '!', "Too Many Program Errors - Closing");
if (cfgMinToTray)
{
DeleteTrayMenuItem(MainWnd);
if (ConsHeader[0]->hConsole)
DeleteTrayMenuItem(ConsHeader[0]->hConsole);
if (ConsHeader[1]->hConsole)
DeleteTrayMenuItem(ConsHeader[1]->hConsole);
if (hMonitor)
DeleteTrayMenuItem(hMonitor);
}
SInfo.cb=sizeof(SInfo);
SInfo.lpReserved=NULL;
SInfo.lpDesktop=NULL;
SInfo.lpTitle=NULL;
SInfo.dwFlags=0;
SInfo.cbReserved2=0;
SInfo.lpReserved2=NULL;
GetModuleFileName(NULL, ProgName, 256);
Debugprintf("Attempting to Restart %s", ProgName);
CreateProcess(ProgName, "MailChat.exe WAIT", NULL, NULL, FALSE, 0, NULL, NULL, &SInfo, &PInfo);
exit(0);
}
}
VOID WriteMiniDump()
{
#ifdef WIN32
HANDLE hFile;
BOOL ret;
char FN[256];
sprintf(FN, "%s/Logs/MiniDump%x.dmp", GetBPQDirectory(), time(NULL));
hFile = CreateFile(FN, GENERIC_READ | GENERIC_WRITE,
0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
{
// Create the minidump
ret = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
hFile, MiniDumpNormal, 0, 0, 0 );
if(!ret)
Debugprintf("MiniDumpWriteDump failed. Error: %u", GetLastError());
else
Debugprintf("Minidump %s created.", FN);
CloseHandle(hFile);
}
#endif
}
void GetSemaphore(struct SEM * Semaphore, int ID)
{
//
// Wait for it to be free
//
#ifdef WIN32
if (Semaphore->Flag != 0)
{
Semaphore->Clashes++;
}
loop1:
while (Semaphore->Flag != 0)
{
Sleep(10);
}
//
// try to get semaphore
//
_asm{
mov eax,1
mov ebx, Semaphore
xchg [ebx],eax // this instruction is locked
cmp eax,0
jne loop1 // someone else got it - try again
;
; ok, weve got the semaphore
;
}
#else
while (Semaphore->Flag)
usleep(10000);
Semaphore->Flag = 1;
#endif
return;
}
void FreeSemaphore(struct SEM * Semaphore)
{
Semaphore->Flag = 0;
return;
}
char * CmdLine;
extern int configSaved;
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HACCEL hAccelTable;
int BPQStream, n;
struct UserInfo * user;
struct _EXCEPTION_POINTERS exinfo;
_invalid_parameter_handler oldHandler, newHandler;
char Msg[100];
int i = 60;
struct NNTPRec * NNTPREC;
struct NNTPRec * SaveNNTPREC;
CmdLine = _strdup(lpCmdLine);
_strlwr(CmdLine);
if (_stricmp(lpCmdLine, "Wait") == 0) // If AutoRestart then Delay 60 Secs
{
hWnd = CreateWindow("STATIC", "Mail Restarting after Failure - Please Wait", 0,
CW_USEDEFAULT, 100, 550, 70,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
while (i-- > 0)
{
sprintf(Msg, "Mail Restarting after Failure - Please Wait %d secs.", i);
SetWindowText(hWnd, Msg);
Sleep(1000);
}
DestroyWindow(hWnd);
}
__try {
// Trap CRT Errors
newHandler = myInvalidParameterHandler;
oldHandler = _set_invalid_parameter_handler(newHandler);
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_BPQMailChat, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_BPQMailChat));
// Main message loop:
Logprintf(LOG_DEBUG_X, NULL, '!', "Program Starting");
Logprintf(LOG_BBS, NULL, '!', "BPQMail Starting");
Debugprintf("BPQMail Starting");
if (pDllBPQTRACE == 0)
Logprintf(LOG_BBS, NULL, '!', "Remote Monitor Log not available - update BPQ32.dll to enable");
} My__except_Routine("Init");
while (GetMessage(&msg, NULL, 0, 0))
{
__try
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#define EXCEPTMSG "GetMessageLoop"
#include "StdExcept.c"
CheckProgramErrors();
}
}
__try
{
for (n = 0; n < NumberofStreams; n++)
{
BPQStream=Connections[n].BPQStream;
if (BPQStream)
{
SetAppl(BPQStream, 0, 0);
Disconnect(BPQStream);
DeallocateStream(BPQStream);
}
}
hWnd = CreateWindow("STATIC", "Mail Closing - Please Wait", 0,
150, 200, 350, 40, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
Sleep(1000); // A bit of time for links to close
DestroyWindow(hWnd);
if (ConsHeader[0]->hConsole)
DestroyWindow(ConsHeader[0]->hConsole);
if (ConsHeader[1]->hConsole)
DestroyWindow(ConsHeader[1]->hConsole);
if (hMonitor)
{
DestroyWindow(hMonitor);
hMonitor = (HWND)1; // For status Save
}
// SaveUserDatabase();
SaveMessageDatabase();
SaveBIDDatabase();
configSaved = 1;
SaveConfig(ConfigName);
if (cfgMinToTray)
{
DeleteTrayMenuItem(MainWnd);
if (ConsHeader[0]->hConsole)
DeleteTrayMenuItem(ConsHeader[0]->hConsole);
if (ConsHeader[1]->hConsole)
DeleteTrayMenuItem(ConsHeader[1]->hConsole);
if (hMonitor)
DeleteTrayMenuItem(hMonitor);
}
// Free all allocated memory
for (n = 0; n <= NumberofUsers; n++)
{
user = UserRecPtr[n];
if (user->ForwardingInfo)
{
FreeForwardingStruct(user);
free(user->ForwardingInfo);
}
/* ---------- TAJ --PG Server------*/
if (user->Temp && user->Temp->RUNPGPARAMS ) {
printf("Also freeing RUNPGARGS\n");
free(user->Temp->RUNPGPARAMS);
}
/* --------------------------------*/
free(user->Temp);
free(user);
}
free(UserRecPtr);
for (n = 0; n <= NumberofMessages; n++)
free(MsgHddrPtr[n]);
free(MsgHddrPtr);
for (n = 0; n <= NumberofWPrecs; n++)
free(WPRecPtr[n]);
free(WPRecPtr);
for (n = 0; n <= NumberofBIDs; n++)
free(BIDRecPtr[n]);
free(BIDRecPtr);
if (TempBIDRecPtr)
free(TempBIDRecPtr);
NNTPREC = FirstNNTPRec;
while (NNTPREC)
{
SaveNNTPREC = NNTPREC->Next;
free(NNTPREC);
NNTPREC = SaveNNTPREC;
}
if (BadWords) free(BadWords);
if (BadFile) free(BadFile);
n = 0;
if (Aliases)
{
while(Aliases[n])
{
free(Aliases[n]->Dest);
free(Aliases[n]);
n++;
}
free(Aliases);
FreeList(AliasText);
}
n = 0;
if (NTSAliases)
{
while(NTSAliases[n])
{
free(NTSAliases[n]->Dest);
free(NTSAliases[n]);
n++;
}
free(NTSAliases);
}
FreeOverrides();
FreeList(RejFrom);
FreeList(RejTo);
FreeList(RejAt);
FreeList(RejBID);
FreeList(HoldFrom);
FreeList(HoldTo);
FreeList(HoldAt);
FreeList(HoldBID);
FreeList(SendWPAddrs);
Free_UI();
for (n=1; n<20; n++)
{
if (MyElements[n]) free(MyElements[n]);
}
free(WelcomeMsg);
free(NewWelcomeMsg);
free(ExpertWelcomeMsg);
free(Prompt);
free(NewPrompt);
free(ExpertPrompt);
FreeWebMailMallocs();
free(CmdLine);
_CrtDumpMemoryLeaks();
}
My__except_Routine("Close Processing");
CloseBPQ32(); // Close Ext Drivers if last bpq32 process
return (int) msg.wParam;
}
//
// FUNCTION: MyRegisterClass()
//
// PURPOSE: Registers the window class.
//
// COMMENTS:
//
// This function and its usage are only necessary if you want this code
// to be compatible with Win32 systems prior to the 'RegisterClassEx'
// function that was added to Windows 95. It is important to call this function
// so that the application will get 'well formed' small icons associated
// with it.
//
//
#define BGCOLOUR RGB(236,233,216)
//#define BGCOLOUR RGB(245,245,245)
HBRUSH bgBrush;
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
bgBrush = CreateSolidBrush(BGCOLOUR);
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = DLGWINDOWEXTRA;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(BPQICON));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = bgBrush;
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_BPQMailChat);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(BPQICON));
return RegisterClassEx(&wcex);
}
//
// FUNCTION: InitInstance(HINSTANCE, int)
//
// PURPOSE: Saves instance handle and creates main window
//
// COMMENTS:
//
// In this function, we save the instance handle in a global variable and
// create and display the main program window.
//
HWND hWnd;
int AXIPPort = 0;
char LOC[7] = "";
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
char Title[80];
WSADATA WsaData;
HMENU hTopMenu; // handle of menu
HKEY hKey=0;
int retCode;
RECT InitRect;
RECT SessRect;
struct _EXCEPTION_POINTERS exinfo;
HMODULE ExtDriver = LoadLibrary("bpq32.dll");
if (ExtDriver)
{
pDllBPQTRACE = GetProcAddress(ExtDriver,"_DllBPQTRACE@8");
pGetLOC = GetProcAddress(ExtDriver,"_GetLOC@0");
pRefreshWebMailIndex = GetProcAddress(ExtDriver,"_RefreshWebMailIndex@0");
pRunEventProgram = GetProcAddress(ExtDriver,"_RunEventProgram@8");
pGetPortFrequency = GetProcAddress(ExtDriver,"_GetPortFrequency@8");
pSendWebRequest = GetProcAddress(ExtDriver,"_SendWebRequest@16");
pGetLatLon = GetProcAddress(ExtDriver,"_GetLatLon@8");
if (pGetLOC)
{
char * pLOC = (char *)pGetLOC();
memcpy(LOC, pLOC, 6);
}
}
// See if running under WINE
retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SOFTWARE\\Wine", 0, KEY_QUERY_VALUE, &hKey);
if (retCode == ERROR_SUCCESS)
{
RegCloseKey(hKey);
WINE =TRUE;
Debugprintf("Running under WINE");
}
REGTREE = GetRegistryKey();
REGTREETEXT = GetRegistryKeyText();
Sleep(1000);
{
int n;
struct _EXTPORTDATA * PORTVEC;
KISSOnly = TRUE;
for (n=1; n <= GetNumberofPorts(); n++)
{
PORTVEC = (struct _EXTPORTDATA * )GetPortTableEntryFromSlot(n);
if (PORTVEC->PORTCONTROL.PORTTYPE == 16) // EXTERNAL
{
if (_memicmp(PORTVEC->PORT_DLL_NAME, "TELNET", 6) == 0)
KISSOnly = FALSE;
if (PORTVEC->PORTCONTROL.PROTOCOL != 10) // Pactor/WINMOR
KISSOnly = FALSE;
if (AXIPPort == 0)
{
if (_memicmp(PORTVEC->PORT_DLL_NAME, "BPQAXIP", 7) == 0)
{
AXIPPort = PORTVEC->PORTCONTROL.PORTNUMBER;
KISSOnly = FALSE;
}
}
}
}
}
hInst = hInstance;
hWnd=CreateDialog(hInst,szWindowClass,0,NULL);
if (!hWnd)
{
return FALSE;
}
MainWnd = hWnd;
GetVersionInfo(NULL);
sprintf(Title,"G8BPQ Mail Server Version %s", VersionString);
sprintf(RlineVer, "BPQ%s%d.%d.%d", (KISSOnly) ? "K" : "", Ver[0], Ver[1], Ver[2]);
SetWindowText(hWnd,Title);
hWndSess = GetDlgItem(hWnd, 100);
GetWindowRect(hWnd, &InitRect);
GetWindowRect(hWndSess, &SessRect);
SessX = SessRect.left - InitRect.left ;
SessY = SessRect.top -InitRect.top;
SessWidth = SessRect.right - SessRect.left;
// Get handles for updating menu items
hTopMenu=GetMenu(MainWnd);
hActionMenu=GetSubMenu(hTopMenu,0);
hFWDMenu=GetSubMenu(hActionMenu,0);
hMenu=GetSubMenu(hActionMenu,1);
hDisMenu=GetSubMenu(hActionMenu,2);
CheckTimer();
cfgMinToTray = GetMinimizetoTrayFlag();
if ((nCmdShow == SW_SHOWMINIMIZED) || (nCmdShow == SW_SHOWMINNOACTIVE))
if (cfgMinToTray)
{
ShowWindow(hWnd, SW_HIDE);
}
else
{
ShowWindow(hWnd, nCmdShow);
}
else
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
WSAStartup(MAKEWORD(2, 0), &WsaData);
__try {
return Initialise();
}My__except_Routine("Initialise");
return FALSE;
}
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
int state,change;
ConnectionInfo * conn;
struct _EXCEPTION_POINTERS exinfo;
if (message == BPQMsg)
{
if (lParam & BPQMonitorAvail)
{
__try
{
DoBBSMonitorData(wParam);
}
My__except_Routine("DoMonitorData");
return 0;
}
if (lParam & BPQDataAvail)
{
// Dont trap error at this level - let Node error handler pick it up
// __try
// {
DoReceivedData(wParam);
// }
// My__except_Routine("DoReceivedData")
return 0;
}
if (lParam & BPQStateChange)
{
// Get current Session State. Any state changed is ACK'ed
// automatically. See BPQHOST functions 4 and 5.
__try
{
SessionState(wParam, &state, &change);
if (change == 1)
{
if (state == 1) // Connected
{
GetSemaphore(&ConSemaphore, 0);
__try {Connected(wParam);}
My__except_Routine("Connected");
FreeSemaphore(&ConSemaphore);
}
else
{
GetSemaphore(&ConSemaphore, 0);
__try{Disconnected(wParam);}
My__except_Routine("Disconnected");
FreeSemaphore(&ConSemaphore);
}
}
}
My__except_Routine("DoStateChange");
}
return 0;
}
switch (message)
{
case WM_KEYUP:
switch (wParam)
{
case VK_F2:
CreateConsole(-1);
return 0;
case VK_F3:
CreateMulticastConsole();
return 0;
case VK_F4:
CreateMonitor();
return 0;
case VK_TAB:
return TRUE;
break;
}
return 0;
case WM_TIMER:
if (wParam == 1) // Slow = 10 secs
{
__try
{
time_t NOW = time(NULL);
struct tm * tm;
RefreshMainWindow();
CheckTimer();
TCPTimer();
BBSSlowTimer();
if (MaintClock < NOW)
{
while (MaintClock < NOW) // in case large time step
MaintClock += MaintInterval * 3600;
Debugprintf("|Enter HouseKeeping");
DoHouseKeeping(FALSE);
}
if (APIClock < NOW)
{
SendBBSDataToPktMap();
APIClock = NOW + 7200; // Every 2 hours
}
tm = gmtime(&NOW);
if (tm->tm_wday == 0) // Sunday
{
if (GenerateTrafficReport && (LastTrafficTime + 86400) < NOW)
{
CreateBBSTrafficReport();
LastTrafficTime = NOW;
}
}
}
My__except_Routine("Slow Timer");
}
if (wParam == 3) // Forward (2 Secs)
{
__try
{
FWDTimerProc();
}
My__except_Routine("Fwd Timer");
}
else
__try
{
TrytoSend();
TCPFastTimer();
}
My__except_Routine("TrytoSend");
return (0);
case WM_CTLCOLORDLG:
return (LONG)bgBrush;
case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC)wParam;
SetTextColor(hdcStatic, RGB(0, 0, 0));
SetBkMode(hdcStatic, TRANSPARENT);
return (LONG)bgBrush;
}
case WM_INITMENUPOPUP:
if (wParam == (WPARAM)hActionMenu)
{
if (IsClipboardFormatAvailable(CF_TEXT))
EnableMenuItem(hActionMenu,ID_ACTIONS_SENDMSGFROMCLIPBOARD, MF_BYCOMMAND | MF_ENABLED);
else
EnableMenuItem(hActionMenu,ID_ACTIONS_SENDMSGFROMCLIPBOARD, MF_BYCOMMAND | MF_GRAYED );
return TRUE;
}
if (wParam == (WPARAM)hFWDMenu)
{
// Set up Forward Menu
struct UserInfo * user;
char MenuLine[30];
for (user = BBSChain; user; user = user->BBSNext)
{
sprintf(MenuLine, "%s %d Msgs", user->Call, CountMessagestoForward(user));
if (ModifyMenu(hFWDMenu, IDM_FORWARD_ALL + user->BBSNumber,
MF_BYCOMMAND | MF_STRING, IDM_FORWARD_ALL + user->BBSNumber, MenuLine) == 0)
AppendMenu(hFWDMenu, MF_STRING,IDM_FORWARD_ALL + user->BBSNumber, MenuLine);
}
return TRUE;
}
if (wParam == (WPARAM)hDisMenu)
{
// Set up Disconnect Menu
CIRCUIT * conn;
char MenuLine[30];
int n;
for (n = 0; n <= NumberofStreams-1; n++)
{
conn=&Connections[n];
RemoveMenu(hDisMenu, IDM_DISCONNECT + n, MF_BYCOMMAND);
if (conn->Active)
{
sprintf_s(MenuLine, 30, "%d %s", conn->BPQStream, conn->Callsign);
AppendMenu(hDisMenu, MF_STRING, IDM_DISCONNECT + n, MenuLine);
}
}
return TRUE;
}
break;
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
if (wmEvent == LBN_DBLCLK)
break;
if (wmId >= IDM_DISCONNECT && wmId < IDM_DISCONNECT+MaxSockets+1)
{
// disconnect user
conn=&Connections[wmId-IDM_DISCONNECT];
if (conn->Active)
{
Disconnect(conn->BPQStream);
}
}
if (wmId >= IDM_FORWARD_ALL && wmId < IDM_FORWARD_ALL + 100)
{
StartForwarding(wmId - IDM_FORWARD_ALL, NULL);
return 0;
}
switch (wmId)
{
case IDM_LOGBBS:
ToggleParam(hMenu, hWnd, &LogBBS, IDM_LOGBBS);
break;
case IDM_LOGCHAT:
ToggleParam(hMenu, hWnd, &LogCHAT, IDM_LOGCHAT);
break;
case IDM_LOGTCP:
ToggleParam(hMenu, hWnd, &LogTCP, IDM_LOGTCP);
break;
case IDM_HOUSEKEEPING:
DoHouseKeeping(TRUE);
break;
case IDM_CONSOLE:
CreateConsole(-1);
break;
case IDM_MCMONITOR:
CreateMulticastConsole();
break;
case IDM_MONITOR:
CreateMonitor();
break;
case RESCANMSGS:
ReRouteMessages();
break;
case IDM_IMPORT:
ImportMessages(NULL, "", FALSE);
break;
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case ID_HELP_ONLINEHELP:
ShellExecute(hWnd,"open",
"http://www.cantab.net/users/john.wiseman/Documents/MailServer.html",
"", NULL, SW_SHOWNORMAL);
break;
case IDM_CONFIG:
DialogBox(hInst, MAKEINTRESOURCE(IDD_CONFIG), hWnd, ConfigWndProc);
break;
case IDM_USERS:
DialogBox(hInst, MAKEINTRESOURCE(IDD_USEREDIT), hWnd, UserEditDialogProc);
break;
case IDM_FWD:
DialogBox(hInst, MAKEINTRESOURCE(IDD_FORWARDING), hWnd, FwdEditDialogProc);
break;
case IDM_MESSAGES:
DialogBox(hInst, MAKEINTRESOURCE(IDD_MSGEDIT), hWnd, MsgEditDialogProc);
break;
case IDM_WP:
DialogBox(hInst, MAKEINTRESOURCE(IDD_EDITWP), hWnd, WPEditDialogProc);
break;
case ID_ACTIONS_SENDMSGFROMCLIPBOARD:
DialogBox(hInst, MAKEINTRESOURCE(IDD_MSGFROMCLIPBOARD), hWnd, ClpMsgDialogProc);
break;
case ID_ACTIONS_SENDMESSAGE:
DialogBox(hInst, MAKEINTRESOURCE(IDD_MSGFROMCLIPBOARD), hWnd, SendMsgDialogProc);
break;
case ID_MULTICAST:
MulticastRX = !MulticastRX;
CheckMenuItem(hActionMenu, ID_MULTICAST, (MulticastRX) ? MF_CHECKED : MF_UNCHECKED);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_SIZE:
if (wParam == SIZE_MINIMIZED)
if (cfgMinToTray)
return ShowWindow(hWnd, SW_HIDE);
return (0);
case WM_SIZING:
{
LPRECT lprc = (LPRECT) lParam;
int Height = lprc->bottom-lprc->top;
int Width = lprc->right-lprc->left;
MoveWindow(hWndSess, 0, 30, SessWidth, Height - 100, TRUE);
return TRUE;
}
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
GetWindowRect(MainWnd, &MainRect); // For save soutine
if (ConsHeader[0]->hConsole)
GetWindowRect(ConsHeader[0]->hConsole, &ConsHeader[0]->ConsoleRect); // For save soutine
if (ConsHeader[1]->hConsole)
GetWindowRect(ConsHeader[1]->hConsole, &ConsHeader[1]->ConsoleRect); // For save soutine
if (hMonitor)
GetWindowRect(hMonitor, &MonitorRect); // For save soutine
KillTimer(hWnd,1);
KillTimer(hWnd,2);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
INT_PTR CALLBACK SendMsgDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
SendDlgItemMessage(hDlg, IDC_MSGTYPE, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "B");
SendDlgItemMessage(hDlg, IDC_MSGTYPE, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "P");
SendDlgItemMessage(hDlg, IDC_MSGTYPE, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR) "T");
SendDlgItemMessage(hDlg, IDC_MSGTYPE, CB_SETCURSEL, 0, 0);
return TRUE;
case WM_SIZING:
{
HWND hWndEdit = GetDlgItem(hDlg, IDC_EDIT1);
LPRECT lprc = (LPRECT) lParam;
int Height = lprc->bottom-lprc->top;
int Width = lprc->right-lprc->left;
MoveWindow(hWndEdit, 5, 90, Width-20, Height - 140, TRUE);
return TRUE;
}
case WM_COMMAND:
if (LOWORD(wParam) == IDSEND)
{
char status [3];
struct MsgInfo * Msg;
char * via = NULL;
char BID[13];
char FileList[32768];
BIDRec * BIDRec;
int MsgLen;
char * MailBuffer;
char MsgFile[MAX_PATH];
HANDLE hFile = INVALID_HANDLE_VALUE;
int WriteLen=0;
char HDest[61];
char Destcopy[61];
char * Vptr;
char * FileName[100];
int FileLen[100];
char * FileBody[100];
int n, Files = 0;
int TotalFileSize = 0;
char * NewMsg;
GetDlgItemText(hDlg, IDC_MSGTO, HDest, 60);
strcpy(Destcopy, HDest);
GetDlgItemText(hDlg, IDC_MSGBID, BID, 13);
strlop(BID, ' ');
GetDlgItemText(hDlg, IDC_ATTACHMENTS, FileList, 32767);
// if there are attachments, check that they can be opened ane read
n = 0;
if (FileList[0])
{
FILE * Handle;
struct stat STAT;
char * ptr1 = FileList, * ptr2;
while(ptr1 && ptr1[0])
{
ptr2 = strchr(ptr1, ';');
if (ptr2)
*(ptr2++) = 0;
FileName[n++] = ptr1;
ptr1 = ptr2;
}
FileName[n] = 0;
// read the files
Files = n;
n = 0;
while (FileName[n])
{
if (stat(FileName[n], &STAT) == -1)
{
char ErrorMessage[512];
sprintf(ErrorMessage,"Can't find file %s", FileName[n]);
MessageBox(NULL, ErrorMessage, "BPQMail", MB_ICONERROR);
return TRUE;
}
FileLen[n] = STAT.st_size;
Handle = fopen(FileName[n], "rb");
if (Handle == NULL)
{
char ErrorMessage[512];
sprintf(ErrorMessage,"Can't open file %s", FileName[n]);
MessageBox(NULL, ErrorMessage, "BPQMail", MB_ICONERROR);
return TRUE;
}
FileBody[n] = malloc(FileLen[n]+1);
fread(FileBody[n], 1, FileLen[n], Handle);
fclose(Handle);
TotalFileSize += FileLen[n];
n++;
}
}
if (strlen(HDest) == 0)
{
MessageBox(NULL, "To: Call Missing!", "BPQMail", MB_ICONERROR);
return TRUE;
}
if (strlen(BID))
{
if (LookupBID(BID))
{
// Duplicate bid
MessageBox(NULL, "Duplicate BID", "BPQMail", MB_ICONERROR);
return TRUE;
}
}
Msg = AllocateMsgRecord();
// Set number here so they remain in sequence
Msg->number = ++LatestMsg;
MsgnotoMsg[Msg->number] = Msg;
strcpy(Msg->from, SYSOPCall);
Vptr = strlop(Destcopy, '@');
if (Vptr == 0 && strchr(Destcopy, '!')) // Bang route without @
{
Vptr = strchr(Destcopy, '!');
strcpy(Msg->via, Vptr);
strlop(Destcopy, '!');
if (strlen(Destcopy) > 6)
memcpy(Msg->to, Destcopy, 6);
else
strcpy(Msg->to, Destcopy);
goto gotAddr;
}
if (strlen(Destcopy) > 6)
memcpy(Msg->to, Destcopy, 6);
else
strcpy(Msg->to, Destcopy);
_strupr(Msg->to);
if (_memicmp(HDest, "rms:", 4) == 0 || _memicmp(HDest, "rms/", 4) == 0)
{
Vptr = HDest;
memmove(HDest, &HDest[4], strlen(HDest));
strcpy(Msg->to, "RMS");
}
else if (_memicmp(HDest, "smtp:", 5) == 0)
{
if (ISP_Gateway_Enabled)
{
Vptr = HDest;
memmove(HDest, &HDest[5], strlen(HDest));
Msg->to[0] = 0;
}
}
else if (Vptr)
{
// If looks like a valid email address, treat as such
int tolen = (Vptr - Destcopy) - 1;
if (tolen > 6 || !CheckifPacket(Vptr))
{
// Assume Email address
Vptr = HDest;
if (FindRMS() || strchr(Vptr, '!')) // have RMS or source route
strcpy(Msg->to, "RMS");
else if (ISP_Gateway_Enabled)
Msg->to[0] = 0;
else
{
MessageBox(NULL, "Sending to Internet Email not available", "BPQMail", MB_ICONERROR);
return TRUE;
}
}
}
if (Vptr)
{
if (strlen(Vptr) > 40)
Vptr[40] = 0;
strcpy(Msg->via, Vptr);
}
gotAddr:
GetDlgItemText(hDlg, IDC_MSGTITLE, Msg->title, 61);
GetDlgItemText(hDlg, IDC_MSGTYPE, status, 2);
Msg->type = status[0];
Msg->status = 'N';
if (strlen(BID) == 0)
sprintf_s(BID, sizeof(BID), "%d_%s", LatestMsg, BBSName);
strcpy(Msg->bid, BID);
Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL);
BIDRec = AllocateBIDRecord();
strcpy(BIDRec->BID, Msg->bid);
BIDRec->mode = Msg->type;
BIDRec->u.msgno = LOWORD(Msg->number);
BIDRec->u.timestamp = LOWORD(time(NULL)/86400);
MsgLen = SendDlgItemMessage(hDlg, IDC_EDIT1, WM_GETTEXTLENGTH, 0 ,0);
MailBuffer = malloc(MsgLen + TotalFileSize + 2000); // Allow for a B2 Header if attachments
if (Files)
{
char DateString[80];
struct tm * tm;
char Type[16] = "Private";
// Get Type
if (Msg->type == 'B')
strcpy(Type, "Bulletin");
else if (Msg->type == 'T')
strcpy(Type, "Traffic");
// Create a B2 Message
// B2 Header
NewMsg = MailBuffer + 1000;
tm = gmtime((time_t *)&Msg->datecreated);
sprintf(DateString, "%04d/%02d/%02d %02d:%02d",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
// Remove last Source Route
if (strchr(HDest, '!'))
{
char * bang = HDest + strlen(HDest);
while (*(--bang) != '!'); // Find last !
*(bang) = 0; // remove it;
}
NewMsg += sprintf(NewMsg,
"MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nMbo: %s\r\n",
Msg->bid, DateString, Type, Msg->from, HDest, Msg->title, BBSName);
NewMsg += sprintf(NewMsg, "Body: %d\r\n", MsgLen);
for (n = 0; n < Files; n++)
{
char * p = FileName[n], * q;
// Remove any path
q = strchr(p, '\\');
while (q)
{
if (q)
*q++ = 0;
p = q;
q = strchr(p, '\\');
}
NewMsg += sprintf(NewMsg, "File: %d %s\r\n", FileLen[n], p);
}
NewMsg += sprintf(NewMsg, "\r\n");
GetDlgItemText(hDlg, IDC_EDIT1, NewMsg, MsgLen+1);
NewMsg += MsgLen;
NewMsg += sprintf(NewMsg, "\r\n");
for (n = 0; n < Files; n++)
{
memcpy(NewMsg, FileBody[n], FileLen[n]);
NewMsg += FileLen[n];
free(FileBody[n]);
NewMsg += sprintf(NewMsg, "\r\n");
}
Msg->length = NewMsg - (MailBuffer + 1000);
NewMsg = MailBuffer + 1000;
Msg->B2Flags = B2Msg | Attachments;
}
else
{
GetDlgItemText(hDlg, IDC_EDIT1, MailBuffer, MsgLen+1);
Msg->length = MsgLen;
NewMsg = MailBuffer;
}
sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
hFile = CreateFile(MsgFile,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
WriteFile(hFile, NewMsg, Msg->length, &WriteLen, NULL);
CloseHandle(hFile);
}
free(MailBuffer);
MatchMessagetoBBSList(Msg, 0);
BuildNNTPList(Msg); // Build NNTP Groups list
SaveMessageDatabase();
SaveBIDDatabase();
EndDialog(hDlg, LOWORD(wParam));
#ifndef NOMQTT
if (MQTT)
MQTTMessageEvent(Msg);
#endif
return TRUE;
}
if (LOWORD(wParam) == IDSelectFiles)
{
char FileNames[2048];
char FullFileNames[32768];
OPENFILENAME Ofn;
int err;
FileNames[0] = 0;
memset(&Ofn, 0, sizeof(Ofn));
Ofn.lStructSize = sizeof(OPENFILENAME);
Ofn.hInstance = hInst;
Ofn.hwndOwner = hDlg;
Ofn.lpstrFilter = NULL;
Ofn.lpstrFile= FileNames;
Ofn.nMaxFile = 2048;
Ofn.lpstrFileTitle = NULL;
Ofn.nMaxFileTitle = 0;
Ofn.lpstrInitialDir = (LPSTR)NULL;
Ofn.Flags = OFN_SHOWHELP | OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT | OFN_EXPLORER;
Ofn.lpstrTitle = NULL;//;
if (GetOpenFileName(&Ofn))
{
// if one is selected, a single string is returned, if more than one, a single
// path, followed by all the strings, duuble null terminated.
char * Names[101]; // Allow up to 100 names
int n = 0;
char * ptr = FileNames;
while (*ptr)
{
Names[n++] = ptr;
ptr += strlen(ptr);
ptr++;
}
GetDlgItemText(hDlg, IDC_ATTACHMENTS, FullFileNames, 32768);
if (strlen(FullFileNames))
strcat(FullFileNames, ";");
if (n == 1)
{
// Single Select
strcat(FullFileNames, FileNames);
}
else
{
int i = 1;
while(i < n)
{
strcat(FullFileNames, Names[0]);
strcat(FullFileNames, "\\");
strcat(FullFileNames, Names[i]);
i++;
if (i < n)
strcat(FullFileNames, ";");
}
}
SetDlgItemText(hDlg, IDC_ATTACHMENTS, FullFileNames);
}
else
err = GetLastError();
return (INT_PTR)TRUE;
}
if (LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
return (INT_PTR)TRUE;
break;
}
return (INT_PTR)FALSE;
}
INT_PTR CALLBACK ClpMsgDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
HGLOBAL hglb;
LPTSTR lptstr;
switch (message)
{
case WM_INITDIALOG:
SetWindowText(hDlg, "Send Message from Clipboard");
if (!IsClipboardFormatAvailable(CF_TEXT))
break;
if (!OpenClipboard(hDlg))
break;
hglb = GetClipboardData(CF_TEXT);
if (hglb != NULL)
{
lptstr = GlobalLock(hglb);
if (lptstr != NULL)
{
SetDlgItemText(hDlg, IDC_EDIT1, lptstr);
GlobalUnlock(hglb);
}
}
CloseClipboard();
}
return SendMsgDialogProc(hDlg, message, wParam, lParam);
}
// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message)
{
case WM_INITDIALOG:
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
{
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
return (INT_PTR)TRUE;
break;
}
return (INT_PTR)FALSE;
}
SMTPMsgs = 0;
int RefreshMainWindow()
{
char msg[80];
CIRCUIT * conn;
int i,n, SYSOPMsgs = 0, HeldMsgs = 0;
time_t now;
struct tm * tm;
char tim[20];
SendDlgItemMessage(MainWnd,100,LB_RESETCONTENT,0,0);
SMTPMsgs = 0;
for (n = 0; n < NumberofStreams; n++)
{
conn=&Connections[n];
if (!conn->Active)
{
strcpy(msg,"Idle");
}
else
{
{
if (conn->UserPointer == 0)
strcpy(msg,"Logging in");
else
{
i=sprintf_s(msg, sizeof(msg), "%-10s %-10s %2d %-10s%5d",
conn->UserPointer->Name, conn->UserPointer->Call, conn->BPQStream,
"BBS", conn->OutputQueueLength - conn->OutputGetPointer);
}
}
}
SendDlgItemMessage(MainWnd,100,LB_ADDSTRING,0,(LPARAM)msg);
}
SetDlgItemInt(hWnd, IDC_MSGS, NumberofMessages, FALSE);
n = 0;
for (i=1; i <= NumberofMessages; i++)
{
if (MsgHddrPtr[i]->status == 'N')
{
if (_stricmp(MsgHddrPtr[i]->to, SYSOPCall) == 0 || _stricmp(MsgHddrPtr[i]->to, "SYSOP") == 0)
SYSOPMsgs++;
else
if (MsgHddrPtr[i]->to[0] == 0)
SMTPMsgs++;
}
else
{
if (MsgHddrPtr[i]->status == 'H')
HeldMsgs++;
}
}
SetDlgItemInt(hWnd, IDC_SYSOPMSGS, SYSOPMsgs, FALSE);
SetDlgItemInt(hWnd, IDC_HELD, HeldMsgs, FALSE);
SetDlgItemInt(hWnd, IDC_SMTP, SMTPMsgs, FALSE);
SetDlgItemInt(hWnd, IDC_MSGSEM, MsgNoSemaphore.Clashes, FALSE);
SetDlgItemInt(hWnd, IDC_ALLOCSEM, AllocSemaphore.Clashes, FALSE);
SetDlgItemInt(hWnd, IDC_CONSEM, ConSemaphore.Clashes, FALSE);
now = time(NULL);
tm = gmtime(&now);
sprintf_s(tim, sizeof(tim), "%02d:%02d", tm->tm_hour, tm->tm_min);
SetDlgItemText(hWnd, IDC_UTC, tim);
tm = localtime(&now);
sprintf_s(tim, sizeof(tim), "%02d:%02d", tm->tm_hour, tm->tm_min);
SetDlgItemText(hWnd, IDC_LOCAL, tim);
return 0;
}
#define MAX_PENDING_CONNECTS 4
#define VERSION_MAJOR 2
#define VERSION_MINOR 0
static SOCKADDR_IN local_sin; /* Local socket - internet style */
static PSOCKADDR_IN psin;
SOCKET sock;
BOOL Initialise()
{
int i, len;
ConnectionInfo * conn;
struct UserInfo * user = NULL;
HKEY hKey=0;
char * ptr1;
int Attrs, ret;
char msg[500];
TIME_ZONE_INFORMATION TimeZoneInformation;
struct stat STAT;
GetTimeZoneInformation(&TimeZoneInformation);
Debugprintf("%d", sizeof(struct MsgInfo));
_tzset();
_MYTIMEZONE = timezone;
_MYTIMEZONE = TimeZoneInformation.Bias * 60;
// Register message for posting by BPQDLL
BPQMsg = RegisterWindowMessage(BPQWinMsg);
// See if we need to warn of possible problem with BaseDir moved by installer
strcpy(BPQDirectory, GetBPQDirectory());
sprintf(BaseDir, "%s/BPQMailChat", BPQDirectory);
len = strlen(BaseDir);
ptr1 = BaseDir;
while (*ptr1)
{
if (*(ptr1) == '/') *(ptr1) = '\\';
ptr1++;
}
// Make Sure BASEDIR Exists
Attrs = GetFileAttributes(BaseDir);
if (Attrs == -1)
{
sprintf_s(msg, sizeof(msg), "Base Directory %s not found - should it be created?", BaseDir);
ret = MessageBox(NULL, msg, "BPQMail", MB_YESNO);
if (ret == IDYES)
{
ret = CreateDirectory(BaseDir, NULL);
if (ret == 0)
{
MessageBox(NULL, "Failed to created Base Directory - exiting", "BPQMail", MB_ICONSTOP);
return FALSE;
}
}
else
{
MessageBox(NULL, "Can't Continue without a Base Directory - exiting", "BPQMailChat", MB_ICONSTOP);
return FALSE;
}
}
else
{
if (!(Attrs & FILE_ATTRIBUTE_DIRECTORY))
{
sprintf_s(msg, sizeof(msg), "Base Directory %s is a file not a directory - exiting", BaseDir);
ret = MessageBox(NULL, msg, "BPQMail", MB_ICONSTOP);
return FALSE;
}
}
initUTF8();
// Set up file and directory names
strcpy(UserDatabasePath, BaseDir);
strcat(UserDatabasePath, "\\");
strcat(UserDatabasePath, UserDatabaseName);
strcpy(MsgDatabasePath, BaseDir);
strcat(MsgDatabasePath, "\\");
strcat(MsgDatabasePath, MsgDatabaseName);
strcpy(BIDDatabasePath, BaseDir);
strcat(BIDDatabasePath, "\\");
strcat(BIDDatabasePath, BIDDatabaseName);
strcpy(WPDatabasePath, BaseDir);
strcat(WPDatabasePath, "\\");
strcat(WPDatabasePath, WPDatabaseName);
strcpy(BadWordsPath, BaseDir);
strcat(BadWordsPath, "\\");
strcat(BadWordsPath, BadWordsName);
strcpy(NTSAliasesPath, BaseDir);
strcat(NTSAliasesPath, "/");
strcat(NTSAliasesPath, NTSAliasesName);
strcpy(MailDir, BaseDir);
strcat(MailDir, "\\");
strcat(MailDir, "Mail");
CreateDirectory(MailDir, NULL); // Just in case
strcpy(ConfigName, BaseDir);
strcat(ConfigName, "\\");
strcat(ConfigName, "BPQMail.cfg");
UsingingRegConfig = FALSE;
// if config file exists use it else try to get from Registry
if (stat(ConfigName, &STAT) == -1)
{
UsingingRegConfig = TRUE;
if (GetConfigFromRegistry())
{
SaveConfig(ConfigName);
}
else
{
int retCode;
strcpy(BBSName, GetNodeCall());
strlop(BBSName, '-');
strlop(BBSName, ' ');
sprintf(msg, "No configuration found - Dummy Config created");
retCode = MessageBox(NULL, msg, "BPQMailChat", MB_OKCANCEL);
if (retCode == IDCANCEL)
return FALSE;
SaveConfig(ConfigName);
}
}
if (GetConfig(ConfigName) == EXIT_FAILURE)
{
ret = MessageBox(NULL,
"BBS Config File seems corrupt - check before continuing", "BPQMail", MB_ICONSTOP);
return FALSE;
}
// Got a Config File
if (MainRect.right < 100 || MainRect.bottom < 100)
{
GetWindowRect(MainWnd, &MainRect);
}
MoveWindow(MainWnd, MainRect.left, MainRect.top, MainRect.right-MainRect.left, MainRect.bottom-MainRect.top, TRUE);
if (OpenMon)
CreateMonitor();
BBSApplMask = 1<<(BBSApplNum-1);
ShowWindow(GetDlgItem(MainWnd, 901), SW_HIDE);
ShowWindow(GetDlgItem(MainWnd, 902), SW_HIDE);
ShowWindow(GetDlgItem(MainWnd, 903), SW_HIDE);
// Make backup copies of Databases
CopyBIDDatabase();
CopyMessageDatabase();
CopyUserDatabase();
CopyWPDatabase();
SetupMyHA();
SetupFwdAliases();
SetupNTSAliases(NTSAliasesPath);
GetWPDatabase();
GetMessageDatabase();
GetUserDatabase();
GetBIDDatabase();
GetBadWordFile();
GetHTMLForms();
UsingingRegConfig = FALSE;
// Make sure SYSOPCALL is set
if (SYSOPCall[0] == 0)
strcpy(SYSOPCall, BBSName);
// Make sure there is a user record for the BBS, with BBS bit set.
user = LookupCall(BBSName);
if (user == NULL)
{
user = AllocateUserRecord(BBSName);
user->Temp = zalloc(sizeof (struct TempUserInfo));
}
if ((user->flags & F_BBS) == 0)
{
// Not Defined as a BBS
if (SetupNewBBS(user))
user->flags |= F_BBS;
}
// if forwarding AMPR mail make sure User/BBS AMPR exists
if (SendAMPRDirect)
{
BOOL NeedSave = FALSE;
user = LookupCall("AMPR");
if (user == NULL)
{
user = AllocateUserRecord("AMPR");
user->Temp = zalloc(sizeof (struct TempUserInfo));
NeedSave = TRUE;
}
if ((user->flags & F_BBS) == 0)
{
// Not Defined as a BBS
if (SetupNewBBS(user))
user->flags |= F_BBS;
NeedSave = TRUE;
}
if (NeedSave)
SaveUserDatabase();
}
// Allocate Streams
for (i=0; i < MaxStreams; i++)
{
conn = &Connections[i];
conn->BPQStream = FindFreeStream();
if (conn->BPQStream == 255) break;
NumberofStreams++;
BPQSetHandle(conn->BPQStream, hWnd);
SetAppl(conn->BPQStream, (i == 0 && EnableUI) ? 0x82 : 2, BBSApplMask | ChatApplMask);
Disconnect(conn->BPQStream);
}
InitialiseTCP();
InitialiseNNTP();
SetupListenSet(); // Master set of listening sockets
if (BBSApplNum)
{
SetupUIInterface();
if (MailForInterval)
_beginthread(SendMailForThread, 0, 0);
}
if (cfgMinToTray)
{
AddTrayMenuItem(MainWnd, "Mail Server");
}
SetTimer(hWnd,1,10000,NULL); // Slow Timer (10 Secs)
SetTimer(hWnd,2,100,NULL); // Send to Node and TCP Poll (100 ms)
SetTimer(hWnd,3,2000,NULL); // Forward Check (2 secs)
// Calulate time to run Housekeeping
{
struct tm *tm;
time_t now;
now = time(NULL);
tm = gmtime(&now);
tm->tm_hour = MaintTime / 100;
tm->tm_min = MaintTime % 100;
tm->tm_sec = 0;
MaintClock = _mkgmtime(tm);
while (MaintClock < now)
MaintClock += MaintInterval * 3600;
Debugprintf("Maint Clock %lld NOW %lld Time to HouseKeeping %lld", (long long)MaintClock, (long long)now, (long long)(MaintClock - now));
if (LastHouseKeepingTime)
{
if ((now - LastHouseKeepingTime) > MaintInterval * 3600)
{
DoHouseKeeping(FALSE);
}
}
}
if (strstr(CmdLine, "tidymail"))
DeleteRedundantMessages();
if (strstr(CmdLine, "nohomebbs"))
DontNeedHomeBBS = TRUE;
if (strstr(CmdLine, "DontCheckFromCall"))
DontCheckFromCall = TRUE;
CheckMenuItem(hMenu,IDM_LOGBBS, (LogBBS) ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_LOGTCP, (LogTCP) ? MF_CHECKED : MF_UNCHECKED);
CheckMenuItem(hMenu,IDM_LOGCHAT, (LogCHAT) ? MF_CHECKED : MF_UNCHECKED);
RefreshMainWindow();
// CreateWPReport();
CreatePipeThread();
GetPGConfig();
APIClock = 0;
return TRUE;
}
int ConnectState(Stream)
{
int state;
SessionStateNoAck(Stream, &state);
return state;
}
UCHAR * EncodeCall(UCHAR * Call)
{
static char axcall[10];
ConvToAX25(Call, axcall);
return &axcall[0];
}
/*
VOID FindNextRMSUser(struct BBSForwardingInfo * FWDInfo)
{
struct UserInfo * user;
int i = FWDInfo->UserIndex;
if (i == -1)
{
FWDInfo->UserIndex = FWDInfo->UserCall[0] = 0; // Not scanning users
}
for (i++; i <= NumberofUsers; i++)
{
user = UserRecPtr[i];
if (user->flags & F_POLLRMS)
{
FWDInfo->UserIndex = i;
strcpy(FWDInfo->UserCall, user->Call);
FWDInfo->FwdTimer = FWDInfo->FwdInterval - 20;
return ;
}
}
// Finished Scan
FWDInfo->UserIndex = FWDInfo->FwdTimer = FWDInfo->UserCall[0] = 0;
}
*/
#ifndef NEWROUTING
VOID SetupHAddreses(struct BBSForwardingInfo * ForwardingInfo)
{
}
VOID SetupMyHA()
{
}
VOID SetupFwdAliases()
{
}
int MatchMessagetoBBSList(struct MsgInfo * Msg, CIRCUIT * conn)
{
struct UserInfo * bbs;
struct BBSForwardingInfo * ForwardingInfo;
char ATBBS[41];
char * HRoute;
int Count =0;
strcpy(ATBBS, Msg->via);
HRoute = strlop(ATBBS, '.');
if (Msg->type == 'P')
{
// P messages are only sent to one BBS, but check the TO and AT of all BBSs before routing on HA
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (CheckBBSToList(Msg, bbs, ForwardingInfo))
{
if (_stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here!
{
if ((conn == NULL) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0)) // Dont send back
{
set_fwd_bit(Msg->fbbs, bbs->BBSNumber);
ForwardingInfo->MsgCount++;
}
}
return 1;
}
}
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (CheckBBSAtList(Msg, ForwardingInfo, ATBBS))
{
if (_stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here!
{
if ((conn == NULL) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0)) // Dont send back
{
set_fwd_bit(Msg->fbbs, bbs->BBSNumber);
ForwardingInfo->MsgCount++;
}
}
return 1;
}
}
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (CheckBBSHList(Msg, bbs, ForwardingInfo, ATBBS, HRoute))
{
if (_stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here!
{
if ((conn == NULL) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0)) // Dont send back
{
set_fwd_bit(Msg->fbbs, bbs->BBSNumber);
ForwardingInfo->MsgCount++;
}
}
return 1;
}
}
return FALSE;
}
// Bulls go to all matching BBSs, so the order of checking doesn't matter
for (bbs = BBSChain; bbs; bbs = bbs->BBSNext)
{
ForwardingInfo = bbs->ForwardingInfo;
if (CheckABBS(Msg, bbs, ForwardingInfo, ATBBS, HRoute))
{
if (_stricmp(bbs->Call, BBSName) != 0) // Dont forward to ourself - already here!
{
if ((conn == NULL) || (_stricmp(conn->UserPointer->Call, bbs->Call) != 0)) // Dont send back
{
set_fwd_bit(Msg->fbbs, bbs->BBSNumber);
ForwardingInfo->MsgCount++;
}
}
Count++;
}
}
return Count;
}
BOOL CheckABBS(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char * HRoute)
{
char ** Calls;
char ** HRoutes;
int i, j;
if (strcmp(ATBBS, bbs->Call) == 0) // @BBS = BBS
return TRUE;
// Check TO distributions
if (ForwardingInfo->TOCalls)
{
Calls = ForwardingInfo->TOCalls;
while(Calls[0])
{
if (strcmp(Calls[0], Msg->to) == 0)
return TRUE;
Calls++;
}
}
// Check AT distributions
if (ForwardingInfo->ATCalls)
{
Calls = ForwardingInfo->ATCalls;
while(Calls[0])
{
if (strcmp(Calls[0], ATBBS) == 0)
return TRUE;
Calls++;
}
}
if ((HRoute) && (ForwardingInfo->Haddresses))
{
// Match on Routes
HRoutes = ForwardingInfo->Haddresses;
while(HRoutes[0])
{
i = strlen(HRoutes[0]) - 1;
j = strlen(HRoute) - 1;
while ((i >= 0) && (j >= 0)) // Until one string rus out
{
if (HRoutes[0][i--] != HRoute[j--]) // Compare backwards
goto next;
}
return TRUE;
next:
HRoutes++;
}
}
return FALSE;
}
BOOL CheckBBSToList(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo)
{
char ** Calls;
// Check TO distributions
if (ForwardingInfo->TOCalls)
{
Calls = ForwardingInfo->TOCalls;
while(Calls[0])
{
if (strcmp(Calls[0], Msg->to) == 0)
return TRUE;
Calls++;
}
}
return FALSE;
}
BOOL CheckBBSAtList(struct MsgInfo * Msg, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS)
{
char ** Calls;
// Check AT distributions
if (strcmp(ATBBS, bbs->Call) == 0) // @BBS = BBS
return TRUE;
if (ForwardingInfo->ATCalls)
{
Calls = ForwardingInfo->ATCalls;
while(Calls[0])
{
if (strcmp(Calls[0], ATBBS) == 0)
return TRUE;
Calls++;
}
}
return FALSE;
}
BOOL CheckBBSHList(struct MsgInfo * Msg, struct UserInfo * bbs, struct BBSForwardingInfo * ForwardingInfo, char * ATBBS, char * HRoute)
{
char ** HRoutes;
int i, j;
if ((HRoute) && (ForwardingInfo->Haddresses))
{
// Match on Routes
HRoutes = ForwardingInfo->Haddresses;
while(HRoutes[0])
{
i = strlen(HRoutes[0]) - 1;
j = strlen(HRoute) - 1;
while ((i >= 0) && (j >= 0)) // Until one string rus out
{
if (HRoutes[0][i--] != HRoute[j--]) // Compare backwards
goto next;
}
return TRUE;
next:
HRoutes++;
}
}
return FALSE;
}
#endif
char * strlop(char * buf, char delim)
{
// Terminate buf at delim, and return rest of string
char * ptr;
if (buf == NULL) return NULL; // Protect
ptr = strchr(buf, delim);
if (ptr == NULL) return NULL;
*(ptr)++=0;
return ptr;
}