// 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 // 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 ?? 2022 // 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) #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; FARPROCX pRefreshWebMailIndex; FARPROCX pRunEventProgram; 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"); pRefreshWebMailIndex = GetProcAddress(ExtDriver,"_RefreshWebMailIndex@0"); pRunEventProgram = GetProcAddress(ExtDriver,"_RunEventProgram@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(); 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; }