// 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  ?????????

//	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

#include "bpqmail.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;

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();

struct _EXCEPTION_POINTERS exinfox;
	
CONTEXT ContextRecord;
EXCEPTION_RECORD ExceptionRecord;

DWORD Stack[16];

BOOL Restarting = FALSE;

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); 
		}

		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");

		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();
				FWDTimerProc();
				if (MaintClock < NOW)
				{
					while (MaintClock < NOW)		// in case large time step
						MaintClock += MaintInterval * 3600;

					Debugprintf("|Enter HouseKeeping");
					DoHouseKeeping(FALSE);
				}
				tm = gmtime(&NOW);	

				if (tm->tm_wday == 0)		// Sunday
				{
					if (GenerateTrafficReport && (LastTrafficTime + 86400) < NOW)
					{
						CreateBBSTrafficReport();
						LastTrafficTime = NOW;	
					}
				}
			}
			My__except_Routine("Slow 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));

			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

SOCKADDR_IN local_sin;  /* Local socket - internet style */

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);

	_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)

	// 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();

	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;
}
