diff --git a/AGWAPI.c b/AGWAPI.c index c28d8f3..5e46d7e 100644 --- a/AGWAPI.c +++ b/AGWAPI.c @@ -55,11 +55,14 @@ struct AGWSocketConnectionInfo BOOL SocketActive; BOOL RawFlag; BOOL MonFlag; + BOOL useLocalTime; + BOOL doNodes; unsigned char CallSign1[10]; unsigned char CallSign2[10]; BOOL GotHeader; int MsgDataLength; struct AGWHeader AGWRXHeader; + unsigned char * MsgData; }; struct BPQConnectionInfo @@ -75,8 +78,6 @@ struct BPQConnectionInfo char AGWPorts[1000]; -byte AGWMessage[1000]; - struct AGWHeader AGWTXHeader; char SessionList[100]; @@ -127,7 +128,7 @@ int DataSocket_Write(struct AGWSocketConnectionInfo * sockptr, SOCKET sock); int AGWGetSessionKey(char * key, struct AGWSocketConnectionInfo * sockptr); int ProcessAGWCommand(struct AGWSocketConnectionInfo * sockptr); int SendDataToAppl(int Stream, byte * Buffer, int Length); -int InternalAGWDecodeFrame(char * msg, char * buffer, int Stamp, int * FrameType); +int InternalAGWDecodeFrame(char * msg, char * buffer, int Stamp, int * FrameType, int useLocalTime, int doNodes); int AGWDataSocket_Disconnect( struct AGWSocketConnectionInfo * sockptr); int SendRawPacket(struct AGWSocketConnectionInfo * sockptr, char *txmsg, int Length); int ShowApps(); @@ -686,7 +687,7 @@ int AGWDoMonitorData() byte AGWBuffer[1000]; int n; int Stamp, Frametype; - BOOL RXFlag, NeedAGW; + BOOL RXFlag; // Look for Monitor Data @@ -731,24 +732,16 @@ int AGWDoMonitorData() RXFlag = TRUE; } - NeedAGW = FALSE; + // Can now have different mon flags per connection, so need to run decode for each socket for (n = 1; n<= CurrentSockets; n++) { - sockptr=&Sockets[n]; + sockptr = &Sockets[n]; - if (sockptr->SocketActive && sockptr->MonFlag) NeedAGW = TRUE; - } - - if (NeedAGW) - { - if (RXFlag || LoopMonFlag) // only send txed frames if requested + if (sockptr->SocketActive && sockptr->MonFlag && (RXFlag || LoopMonFlag)) { - Length = InternalAGWDecodeFrame(Buffer, AGWBuffer,Stamp, &Frametype); - - // - // Decode frame and send to applications which have requested monitoring - // + Length = InternalAGWDecodeFrame(Buffer, AGWBuffer, Stamp, &Frametype, sockptr->useLocalTime, sockptr->doNodes); + if (Length > 0) { AGWTXHeader.Port = Port - 1; // AGW Ports start from 0 @@ -786,13 +779,7 @@ int AGWDoMonitorData() memset(AGWTXHeader.callfrom, 0,10); ConvFromAX25(monbuff->ORIGIN, AGWTXHeader.callfrom); - for (n = 1; n<= CurrentSockets; n++) - { - sockptr=&Sockets[n]; - - if (sockptr->SocketActive && sockptr->MonFlag) - SendRawPacket(sockptr, AGWBuffer, Length); - } + SendRawPacket(sockptr, AGWBuffer, Length); } } } @@ -1039,10 +1026,13 @@ int AGWDataSocket_Read(struct AGWSocketConnectionInfo * sockptr, SOCKET sock) if (DataLength >= sockptr->MsgDataLength) { // Read Data and Process Command + + sockptr->MsgData = malloc(sockptr->MsgDataLength); - i=recv(sock, AGWMessage, sockptr->MsgDataLength, 0); + i = recv(sock, sockptr->MsgData, sockptr->MsgDataLength, 0); ProcessAGWCommand (sockptr); + free(sockptr->MsgData); sockptr->GotHeader = FALSE; } @@ -1168,7 +1158,7 @@ int ProcessAGWCommand(struct AGWSocketConnectionInfo * sockptr) { // Have digis - char * Digis = AGWMessage; + char * Digis = sockptr->MsgData; int nDigis = Digis[0]; Digis ++; @@ -1205,7 +1195,7 @@ int ProcessAGWCommand(struct AGWSocketConnectionInfo * sockptr) { if (memcmp(AGWConnections[con].CallKey,key,21) == 0) { - SendMsg(AGWConnections[con].BPQStream, AGWMessage, sockptr->MsgDataLength); + SendMsg(AGWConnections[con].BPQStream, sockptr->MsgData, sockptr->MsgDataLength); return 0; } } @@ -1294,15 +1284,28 @@ int ProcessAGWCommand(struct AGWSocketConnectionInfo * sockptr) // Send Raw Frame - SendRaw(sockptr->AGWRXHeader.Port+1,&AGWMessage[1], sockptr->MsgDataLength - 1); + SendRaw(sockptr->AGWRXHeader.Port+1,&sockptr->MsgData[1], sockptr->MsgDataLength - 1); return 0; case 'm': // Toggle Monitor receive - - sockptr->MonFlag = !sockptr->MonFlag; + + if (sockptr->AGWRXHeader.DataLength == 12) // QtTermTCP monitor info + { +// Msg[AGWHDDRRLEN] = AGWUsers->MonSess->mlocaltime; +// Msg[AGWHDDRRLEN + 1] = AGWUsers->MonSess->MonitorNODES; + //Msg[AGWHDDRRLEN + 2] = AGWUsers->MonSess->MonitorColour; +// Msg[AGWHDDRRLEN + 3] = AGWUsers->MonSess->mtxparam; +// memcpy(&Msg[AGWHDDRRLEN + 4], (void *)&AGWUsers->MonSess->portmask, 8); + sockptr->useLocalTime = sockptr->MsgData[0]; + sockptr->doNodes = sockptr->MsgData[1]; + sockptr->MonFlag = 1; + } + else + sockptr->MonFlag = !sockptr->MonFlag; + return 0; @@ -1318,11 +1321,11 @@ int ProcessAGWCommand(struct AGWSocketConnectionInfo * sockptr) if (sockptr->AGWRXHeader.DataKind == 'V') // Unproto with VIA string { - Digis = AGWMessage[0]; // Number of digis + Digis = sockptr->MsgData[0]; // Number of digis for (j = 1; j<= Digis; j++) { - ConvToAX25(&AGWMessage[(j - 1) * 10 + 1],&TXMessage[7+(j*7)]); // No "last" bit + ConvToAX25(&sockptr->MsgData[(j - 1) * 10 + 1],&TXMessage[7+(j*7)]); // No "last" bit } // set end of call @@ -1342,7 +1345,7 @@ int ProcessAGWCommand(struct AGWSocketConnectionInfo * sockptr) else *(TXMessageptr++) = sockptr->AGWRXHeader.PID; - memcpy(TXMessageptr,&AGWMessage[MsgStart], sockptr->MsgDataLength - MsgStart); + memcpy(TXMessageptr,&sockptr->MsgData[MsgStart], sockptr->MsgDataLength - MsgStart); TXMessageptr += (sockptr->MsgDataLength - MsgStart); diff --git a/AGWMoncode.c b/AGWMoncode.c index 418f2df..1610548 100644 --- a/AGWMoncode.c +++ b/AGWMoncode.c @@ -64,12 +64,12 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses char * strlop(char * buf, char delim); UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, int msglen); -static UCHAR * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen); +static UCHAR * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen, int DoNodes); static UCHAR * DISPLAYIPDATAGRAM(IPMSG * IP, UCHAR * Output, int MsgLen); static UCHAR * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output); -int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, int * FrameType) +int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, int * FrameType, int useLocalTime, int DoNodes) { UCHAR * ptr; int n; @@ -81,7 +81,6 @@ int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, int * FrameT char PFCHAR[3] = " "; int MSGFLAG = 0; //CR and V1 flags char * Output = buffer; - int HH, MM, SS; char From[10], To[10]; BOOL Info = 0; BOOL FRMRFLAG = 0; @@ -89,6 +88,13 @@ int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, int * FrameT BOOL TESTFLAG = 0; size_t MsgLen = msg->LENGTH; + struct tm * TM; + + if (useLocalTime) + TM = localtime(&Stamp); + else + TM = gmtime(&Stamp); + // GET THE CONTROL BYTE, TO SEE IF THIS FRAME IS TO BE DISPLAYED n = 8; // MAX DIGIS @@ -124,14 +130,6 @@ int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, int * FrameT *FrameType = CTL; - Stamp = Stamp % 86400; // Secs - HH = Stamp / 3600; - - Stamp -= HH * 3600; - MM = Stamp / 60; - - SS = Stamp - MM * 60; - Output += sprintf((char *)Output, " %d:Fm ", msg->PORT & 0x7f); // Mask TX bit From[ConvFromAX25(msg->ORIGIN, From)] = 0; @@ -297,7 +295,7 @@ int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, int * FrameT } - Output += sprintf((char *)Output, "[%02d:%02d:%02d]", HH, MM, SS); + Output += sprintf((char *)Output, "[%02d:%02d:%02d]", TM->tm_hour, TM->tm_min, TM->tm_sec); if (FRMRFLAG) @@ -345,7 +343,7 @@ int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, int * FrameT } case NETROM_PID: - Output = DISPLAY_NETROM(ADJBUFFER, Output,(int) MsgLen); + Output = DISPLAY_NETROM(ADJBUFFER, Output,(int) MsgLen, DoNodes); break; case IP_PID: @@ -366,6 +364,9 @@ int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, int * FrameT } } + if (Output == NULL) + return NULL; + if (Output[-1] != 13) Output += sprintf((char *)Output, "\r"); @@ -374,7 +375,7 @@ int InternalAGWDecodeFrame(MESSAGE * msg, char * buffer, int Stamp, int * FrameT } // Display NET/ROM data -UCHAR * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen) +UCHAR * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen, int DoNodes) { char Alias[7]= ""; char Dest[10]; @@ -386,6 +387,8 @@ UCHAR * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen) { // Display NODES + if (DoNodes == 0) + return NULL; // If an INP3 RIF (type <> UI) decode as such diff --git a/APRSCode.c b/APRSCode.c index 70327d5..fea004a 100644 --- a/APRSCode.c +++ b/APRSCode.c @@ -2552,6 +2552,8 @@ VOID SendAPRSMessageEx(char * Message, int toPort, char * FromCall, int Gated) else continue; + Msg.DEST[6] |= 0x80; // set Command Bit + ConvToAX25(FromCall, Msg.ORIGIN); Msg.PID = 0xf0; Msg.CTL = 3; @@ -2580,6 +2582,8 @@ VOID SendAPRSMessageEx(char * Message, int toPort, char * FromCall, int Gated) else return; + Msg.DEST[6] |= 0x80; // set Command Bit + ConvToAX25(FromCall, Msg.ORIGIN); Msg.PID = 0xf0; Msg.CTL = 3; @@ -2756,7 +2760,8 @@ void SendBeaconThread(void * Param) Debugprintf("Sending APRS Beacon to port %d", toPort); memcpy(Msg.DEST, &BeaconHeader[toPort][0][0], 10 * 7); // Clear unused digis - + Msg.DEST[6] |= 0x80; // set Command Bit + GetSemaphore(&Semaphore, 12); Send_AX_Datagram(&Msg, Len + 2, toPort); FreeSemaphore(&Semaphore); @@ -2780,6 +2785,8 @@ void SendBeaconThread(void * Param) Msg.CTL = 3; memcpy(Msg.DEST, &BeaconHeader[Port][0][0], 10 * 7); + Msg.DEST[6] |= 0x80; // set Command Bit + GetSemaphore(&Semaphore, 12); Send_AX_Datagram(&Msg, Len + 2, Port); FreeSemaphore(&Semaphore); @@ -2815,6 +2822,8 @@ VOID SendObject(struct OBJECT * Object) Msg.CTL = 3; Len = sprintf(Msg.L2DATA, "%s", Object->Message); memcpy(Msg.DEST, &Object->Path[0][0], Object->PathLen + 1); + Msg.DEST[6] |= 0x80; // set Command Bit + Send_AX_Datagram(&Msg, Len + 2, Port); } } @@ -2881,6 +2890,8 @@ VOID SendIStatus() if (BeaconHddrLen[Port]) // Only send to ports with a DEST defined { memcpy(Msg.DEST, &BeaconHeader[Port][0][0], 10 * 7); + Msg.DEST[6] |= 0x80; // set Command Bit + Send_AX_Datagram(&Msg, Len + 2, Port); } } diff --git a/AlertWords.txt b/AlertWords.txt new file mode 100644 index 0000000..97b746b --- /dev/null +++ b/AlertWords.txt @@ -0,0 +1,2 @@ +g8bpq +very bad phrase diff --git a/BPQChat.vcproj.DESKTOP-TGEL8RC.John.user b/BPQChat.vcproj.DESKTOP-TGEL8RC.John.user deleted file mode 100644 index 40182c4..0000000 --- a/BPQChat.vcproj.DESKTOP-TGEL8RC.John.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/BPQChat.vcproj.SKIGACER.johnw.user b/BPQChat.vcproj.SKIGACER.johnw.user deleted file mode 100644 index b5b0536..0000000 --- a/BPQChat.vcproj.SKIGACER.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/BPQMail-HPLaptop.c b/BPQMail-HPLaptop.c deleted file mode 100644 index 344dc5f..0000000 --- a/BPQMail-HPLaptop.c +++ /dev/null @@ -1,3644 +0,0 @@ -// 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) -// Improve validation of extended FC message (32) -// Improve WP check for SYSTEM as a callsihn (33) -// Improvements to RMS Relay SYNC mode (47) -// Fix BID Hold and Reject filters - - - -#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; -} diff --git a/BPQMail.c b/BPQMail.c index 3475f84..f586b86 100644 --- a/BPQMail.c +++ b/BPQMail.c @@ -1120,7 +1120,10 @@ // 6.0.25.1 ?? -// Aff FBB reject.sys style filters (3) +// Add FBB reject.sys style filters (3) +// Improve Webmail on 64 bit builds + + #include "bpqmail.h" #include "winstdint.h" diff --git a/BPQMail.vcproj b/BPQMail.vcproj index 3bfb0b5..3c7ef20 100644 --- a/BPQMail.vcproj +++ b/BPQMail.vcproj @@ -68,7 +68,7 @@ - - - - - - - - - - diff --git a/BPQMail.vcproj.DESKTOP-TGEL8RC.John.user b/BPQMail.vcproj.DESKTOP-TGEL8RC.John.user deleted file mode 100644 index 40182c4..0000000 --- a/BPQMail.vcproj.DESKTOP-TGEL8RC.John.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/BPQMail.vcproj.HPLAPTOP.johnw.user b/BPQMail.vcproj.HPLAPTOP.johnw.user deleted file mode 100644 index f361c86..0000000 --- a/BPQMail.vcproj.HPLAPTOP.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/BPQMail.vcproj.SKIGACER.johnw.user b/BPQMail.vcproj.SKIGACER.johnw.user deleted file mode 100644 index b5b0536..0000000 --- a/BPQMail.vcproj.SKIGACER.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/BPQRemotePTT.vcproj.DESKTOP-TGEL8RC.John.user b/BPQRemotePTT.vcproj.DESKTOP-TGEL8RC.John.user deleted file mode 100644 index 40182c4..0000000 --- a/BPQRemotePTT.vcproj.DESKTOP-TGEL8RC.John.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/BPQWinAPP.vcproj.DESKTOP-TGEL8RC.John.user b/BPQWinAPP.vcproj.DESKTOP-TGEL8RC.John.user deleted file mode 100644 index 40182c4..0000000 --- a/BPQWinAPP.vcproj.DESKTOP-TGEL8RC.John.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/BPQWinAPP.vcproj.SKIGACER.johnw.user b/BPQWinAPP.vcproj.SKIGACER.johnw.user deleted file mode 100644 index b5b0536..0000000 --- a/BPQWinAPP.vcproj.SKIGACER.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/Bpq32.c b/Bpq32.c index c2a80c3..9d87e34 100644 --- a/Bpq32.c +++ b/Bpq32.c @@ -1193,7 +1193,9 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // Add SDRAngel rig control (11) // Add option to specify config and data directories on linbpq (12) // Allow zero resptime (send RR immediately) (13) -// Fix corruptions in Webmail on 64 bit builds, eg in displaying 7+ files (15) +// Make sure CMD bit is set on UI frames +// Add setting Modem Flags in QtSM AGW mode +// If FT847 om PTC Port send a "Cat On" command (16) #define CKernel @@ -1602,7 +1604,7 @@ char PopupText[30][100] = {""}; // Next 3 should be uninitialised so they are local to each process UCHAR MCOM; -UCHAR MTX; +UCHAR MTX; // Top bit indicates use local time uint64_t MMASK; UCHAR MUIONLY; diff --git a/CBPQ32.suo b/CBPQ32.suo new file mode 100644 index 0000000..b8ffa3c Binary files /dev/null and b/CBPQ32.suo differ diff --git a/CBPQ32.vcproj.DESKTOP-MHE5LO8.johnw.user b/CBPQ32.vcproj.DESKTOP-MHE5LO8.johnw.user deleted file mode 100644 index 2ab49a6..0000000 --- a/CBPQ32.vcproj.DESKTOP-MHE5LO8.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/CBPQ32.vcproj.DESKTOP-TGEL8RC.John.user b/CBPQ32.vcproj.DESKTOP-TGEL8RC.John.user deleted file mode 100644 index fdd7820..0000000 --- a/CBPQ32.vcproj.DESKTOP-TGEL8RC.John.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/CBPQ32.vcproj.HPLAPTOP.johnw.user b/CBPQ32.vcproj.HPLAPTOP.johnw.user deleted file mode 100644 index 58f2ea6..0000000 --- a/CBPQ32.vcproj.HPLAPTOP.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/CBPQ32.vcproj.SKIGACER.johnw.user b/CBPQ32.vcproj.SKIGACER.johnw.user deleted file mode 100644 index 03fb73a..0000000 --- a/CBPQ32.vcproj.SKIGACER.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/Cmd.c b/Cmd.c index 1e2955c..06f9295 100644 --- a/Cmd.c +++ b/Cmd.c @@ -2157,6 +2157,7 @@ VOID CQCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CM ConvToAX25("CQ", CQCALL); memcpy(Msg.DEST, CQCALL, 7); + Msg.DEST[6] |= 0x80; // set Command Bit memcpy(Msg.ORIGIN, Session->L4USER, 7); Msg.ORIGIN[6] ^= 0x1e; // Flip SSID Msg.PID = 0xf0; // Data PID @@ -4714,6 +4715,7 @@ VOID InnerCommandHandler(TRANSPORTENTRY * Session, struct DATAMESSAGE * Buffer) Msg.PORT = Port; Msg.CTL = 3; // UI memcpy(Msg.DEST, Session->UADDRESS, 7); + Msg.DEST[6] |= 0x80; // set Command Bit memcpy(Msg.ORIGIN, Session->L4USER, 7); memcpy(Msg.DIGIS, &Session->UADDRESS[7], Session->UAddrLen - 7); memcpy(&Msg.PID, &Buffer->PID, Len); @@ -5789,6 +5791,7 @@ VOID HELPCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * int UZ7HOSetFreq(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESSAGE buff, PMSGWITHLEN buffptr); int UZ7HOSetModem(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESSAGE buff, PMSGWITHLEN buffptr); +int UZ7HOSetFlags(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESSAGE buff, PMSGWITHLEN buffptr); VOID UZ7HOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * CMD) @@ -5822,7 +5825,7 @@ VOID UZ7HOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * return; } - if (_memicmp(Cmd, "FREQ", 4) == 0 || _memicmp(Cmd, "MODEM", 5) == 0) + if (_memicmp(Cmd, "FREQ", 4) == 0 || _memicmp(Cmd, "MODEM", 5) == 0 || _memicmp(Cmd, "FLAGS", 5) == 0) { // Pass to procesing code in UZ7HO driver. This expects command in a PDATAMESSAGE amd places response in a PMSGWITHLEN buffer @@ -5844,6 +5847,8 @@ VOID UZ7HOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * if (_memicmp(Cmd, "FREQ", 4) == 0) UZ7HOSetFreq(port, TNC, AGW, buff, buffptr); + else if (_memicmp(Cmd, "FLAGS", 5) == 0) + UZ7HOSetFlags(port, TNC, AGW, buff, buffptr); else UZ7HOSetModem(port, TNC, AGW, buff, buffptr); @@ -5854,7 +5859,7 @@ VOID UZ7HOCMD(TRANSPORTENTRY * Session, char * Bufferptr, char * CmdTail, CMDX * ReleaseBuffer(buffptr); } else - Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid UZ7HO Command (not Freq or Modem)\r"); + Bufferptr = Cmdprintf(Session, Bufferptr, "Invalid UZ7HO Command (not Freq Modem or FLAGS)\r"); SendCommandReply(Session, REPLYBUFFER, (int)(Bufferptr - (char *)REPLYBUFFER)); return; diff --git a/HALDriver64.c.bak b/HALDriver64.c.bak deleted file mode 100644 index d093dba..0000000 --- a/HALDriver64.c.bak +++ /dev/null @@ -1,1907 +0,0 @@ -/* -Copyright 2001-2018 John Wiseman G8BPQ - -This file is part of LinBPQ/BPQ32. - -LinBPQ/BPQ32 is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -LinBPQ/BPQ32 is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses -*/ - -// -// DLL to inteface HAL Communications Corp Clover/Pacor controllers to BPQ32 switch -// -// Uses BPQ EXTERNAL interface -// - -#define _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_DEPRECATE - -#include "time.h" - -#include "CHeaders.h" -#include "tncinfo.h" - -#include "bpq32.h" - -#define HAL 1 - -#define SetMYCALL 0x13 -#define ConnectEnable 0x52 -#define ConnectDisable 0x42 -#define SetEAS 0x59 // Echo as Sent -#define SetTones 0xec -#define ClearOnDisc 0x57 - -static char ClassName[]="HALSTATUS"; - -static char WindowTitle[] = "HAL"; -static int RigControlRow = 185; - -struct TNCINFO * TNCInfo[34]; // Records are Malloc'd - -#define SOH 0x01 // CONTROL CODES -#define ETB 0x17 -#define DLE 0x10 - -//int MaxStreams = 0; - -#ifndef LINBPQ -extern HFONT hFont; -#endif - -static char status[23][50] = {"IDLE", "TFC", "RQ", "ERR", "PHS", "OVER", "FSK TX", - "FSK RX", "P-MODE100", "P-MODE200", "HUFMAN ON", "HUFMAN OFF", "P-MODE SBY(LISTEN ON)", - "P-MODE SBY(LISTEN OFF)", "ISS", "IRS", - "AMTOR SBY(LISTEN ON)", "AMTOR SBY(LISTEN OFF)", "AMTOR FEC TX", "AMTOR FEC RX", "P-MODE FEC TX", - "FREE SIGNAL TX (AMTOR)", "FREE SIGNAL TX TIMED OUT (AMTOR)"}; - -struct TNCINFO * CreateTTYInfo(int port, int speed); -BOOL OpenConnection(int); -BOOL SetupConnection(int); -static BOOL WriteCommBlock(struct TNCINFO * TNC); -static void CheckRX(struct TNCINFO * TNC); -VOID HALPoll(int Port); -VOID ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * rxbuff, int len); -VOID ProcessTermModeResponse(struct TNCINFO * TNC); -static VOID DoTNCReinit(struct TNCINFO * TNC); -VOID DoTermModeTimeout(struct TNCINFO * TNC); -VOID ProcessHALBuffer(struct TNCINFO * TNC, int Length); -VOID ProcessHALCmd(struct TNCINFO * TNC); -VOID ProcessHALData(struct TNCINFO * TNC); -VOID ProcessKHOSTPacket(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len); -VOID ProcessKNormCommand(struct TNCINFO * TNC, UCHAR * rxbuffer); -VOID ProcessHostFrame(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len); -VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len); - -BOOL HALConnected(struct TNCINFO * TNC, char * Call); -VOID HALDisconnected(struct TNCINFO * TNC); - -static VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len); -VOID SendCmd(struct TNCINFO * TNC, UCHAR * txbuffer, int Len); -int DLEEncode(UCHAR * inbuff, UCHAR * outbuff, int len); -int DLEDecode(UCHAR * inbuff, UCHAR * outbuff, int len); - -VOID COMClearDTR(HANDLE fd); -VOID COMClearRTS(HANDLE fd); -int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len); - - - -//static HANDLE LogHandle[4] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; - -//char * Logs[4] = {"1", "2", "3", "4"}; - -//char BaseDir[]="c:"; - -static VOID CloseLogfile(int Flags) -{ -// CloseHandle(LogHandle[Flags]); -// LogHandle[Flags] = INVALID_HANDLE_VALUE; -} - -static VOID OpenLogfile(int Flags) -{ -/* -UCHAR FN[MAX_PATH]; - time_t T; - struct tm * tm; - - T = time(NULL); - tm = gmtime(&T); - - sprintf(FN,"%s\\HALLog_%02d%02d%02d_%s.bin", BaseDir, tm->tm_mday, tm->tm_hour, tm->tm_min, Logs[Flags]); - - LogHandle[Flags] = CreateFile(FN, - GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - SetFilePointer(LogHandle[Flags], 0, 0, FILE_END); - - return (LogHandle[Flags] != INVALID_HANDLE_VALUE); -*/ -} - -static void WriteLogLine(int Flags, char * Msg, int MsgLen) -{ -// int cnt; -// WriteFile(LogHandle[Flags] ,Msg , MsgLen, &cnt, NULL); -} - - - -int ProcessLine(char * buf, int Port) -{ - UCHAR * ptr,* p_cmd; - char * p_ipad = 0; - char * p_port = 0; - unsigned short WINMORport = 0; - int BPQport; - int len=510; - struct TNCINFO * TNC; - char errbuf[256]; - - strcpy(errbuf, buf); - - ptr = strtok(buf, " \t\n\r"); - - if(ptr == NULL) return (TRUE); - - if(*ptr =='#') return (TRUE); // comment - - if(*ptr ==';') return (TRUE); // comment - - ptr = strtok(NULL, " \t\n\r"); - - if (_stricmp(buf, "APPL") == 0) // Using BPQ32 COnfig - { - BPQport = Port; - p_cmd = ptr; - } - else - if (_stricmp(buf, "PORT") != 0) // Using Old Config - { - // New config without a PORT or APPL - this is a Config Command - - strcpy(buf, errbuf); - strcat(buf, "\r"); - - BPQport = Port; - - TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO)); - - TNC->InitScript = malloc(1000); - TNC->InitScript[0] = 0; - goto ConfigLine; - } - else - - { - - // Old Config from file - - BPQport=0; - BPQport = atoi(ptr); - - p_cmd = strtok(NULL, " \t\n\r"); - - if (Port && Port != BPQport) - { - // Want a particular port, and this isn't it - - while(TRUE) - { - if (GetLine(buf) == 0) - return TRUE; - - if (memcmp(buf, "****", 4) == 0) - return TRUE; - - } - } - } - if(BPQport > 0 && BPQport < 33) - { - TNC = TNCInfo[BPQport] = zalloc(sizeof(struct TNCINFO)); - TNC->InitScript = malloc(1000); - TNC->InitScript[0] = 0; - - if (p_cmd != NULL) - { - if (p_cmd[0] != ';' && p_cmd[0] != '#') - TNC->ApplCmd=_strdup(p_cmd); - } - - // Read Initialisation lines - - while(TRUE) - { - if (GetLine(buf) == 0) - return TRUE; -ConfigLine: - strcpy(errbuf, buf); - - if (memcmp(buf, "****", 4) == 0) - return TRUE; - - ptr = strchr(buf, ';'); - if (ptr) - { - *ptr++ = 13; - *ptr = 0; - } - - if (_memicmp(buf, "WL2KREPORT", 10) == 0) - { - TNC->WL2K = DecodeWL2KReportLine(buf); - continue; - } - if (_memicmp(buf, "NEEDXONXOFF", 10) == 0) - { - TNC->XONXOFF = TRUE; - continue; - } - - if (_memicmp(buf, "TONES", 5) == 0) - { - int tone1 = 0, tone2 = 0; - - ptr = strtok(&buf[6], " ,/\t\n\r"); - if (ptr) - { - tone1 = atoi(ptr); - ptr = strtok(NULL, " ,/\t\n\r"); - if (ptr) - { - tone2 = atoi(ptr); - ptr = &TNC->InitScript[TNC->InitScriptLen]; - - // Try putting into FSK mode first - - *(ptr++) = 0x84; - *(ptr++) = SetTones; // Set Tones (Mark, Space HI byte first) - *(ptr++) = tone1 >> 8; - *(ptr++) = tone1 & 0xff; - *(ptr++) = tone2 >> 8; - *(ptr++) = tone2 & 0xff; - - TNC->InitScriptLen += 6; - - continue; - } - } - goto BadLine; - } - if (_memicmp(buf, "DEFAULTMODE ", 12) == 0) - { - - ptr = strtok(&buf[12], " ,\t\n\r"); - if (ptr) - { - if (_stricmp(ptr, "CLOVER") == 0) - TNC->DefaultMode = Clover; - else if (_stricmp(ptr, "PACTOR") == 0) - TNC->DefaultMode = Pactor; - else if (_stricmp(ptr, "AMTOR") == 0) - TNC->DefaultMode = AMTOR; - else goto BadLine; - - continue; - } - goto BadLine; - } - } - BadLine: - WritetoConsole(" Bad config record "); - WritetoConsole(errbuf); - WritetoConsole("\r\n"); - } - - return (TRUE); -} - -static size_t ExtProc(int fn, int port , PDATAMESSAGE buff) -{ - int txlen = 0; - PMSGWITHLEN buffptr; - struct TNCINFO * TNC = TNCInfo[port]; - struct STREAMINFO * STREAM; - int Stream; - - if (TNC == NULL) - return 0; - - if (fn < 4 || fn > 5) - if (TNC->hDevice == 0) - return 0; // Port not open - - STREAM = &TNC->Streams[0]; - - switch (fn) - { - case 1: // poll - - while (TNC->PortRecord->UI_Q) // Release anything accidentally put on UI_Q - { - buffptr = Q_REM(&TNC->PortRecord->UI_Q); - ReleaseBuffer(buffptr); - } - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (STREAM->ReportDISC) - { - STREAM->ReportDISC = FALSE; - buff->PORT = 0; - - return -1; - } - } - - CheckRX(TNC); - HALPoll(port); - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (STREAM->PACTORtoBPQ_Q !=0) - { - int datalen; - - buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q); - - datalen = (int)buffptr->Len; - - buff->PORT = 0; // Compatibility with Kam Driver - buff->PID = 0xf0; - memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte - datalen += sizeof(void *) + 4; - - PutLengthinBuffer(buff, datalen); - - - ReleaseBuffer(buffptr); - - return (1); - } - } - - return 0; - - case 2: // send - - buffptr = GetBuff(); - - if (buffptr == 0) return (0); // No buffers, so ignore - - // Find TNC Record - - Stream = buff->PORT; - - if (!TNC->TNCOK) - { - // Send Error Response - - PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); - - if (buffptr == 0) return (0); // No buffers, so ignore - - buffptr->Len = 27; - memcpy(&buffptr->Data[0], "No Connection to PACTOR TNC\r", 27); - - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - return 0; - } - - txlen = GetLengthfromBuffer(buff) - (sizeof(void *) + 4); - - buffptr->Len = txlen; - memcpy(&buffptr->Data[0], &buff->L2DATA[0], txlen); - - C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr); - - STREAM->FramesQueued++; - - return (0); - - - case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding - - Stream = (int)(size_t)buff; - - if (STREAM->FramesQueued > 4) - return (1 | TNC->HostMode << 8); - - return TNC->HostMode << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting - - case 4: // reinit - - return (0); - - case 5: // Close - - CloseCOMPort(TNCInfo[port]->hDevice); - return (0); - - case 6: // Scan Control - - return 0; // None Yet - - } - return 0; - -} - -static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL) -{ - int Len = sprintf(Buff, "" - "HAL Status

HAL Status

"); - - Len += sprintf(&Buff[Len], ""); - - Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); - Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); - Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); - Len += sprintf(&Buff[Len], "", TNC->WEB_STATE); - Len += sprintf(&Buff[Len], "", TNC->WEB_TXRX); - Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); - Len += sprintf(&Buff[Len], ""); - Len += sprintf(&Buff[Len], "", TNC->WEB_LEDS); - Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Status%s
TX/RX State%s
Traffic%s
LEDSSTBY CALL LINK ERROR TX RX
%s
"); - - Len = DoScanLine(TNC, Buff, Len); - - return Len; -} - - -VOID * HALExtInit(EXTPORTDATA * PortEntry) -{ - char msg[500]; - struct TNCINFO * TNC; - int port; - char * ptr; - int len; - char Msg[80]; -#ifndef LINBPQ - HWND x; -#endif - // - // Will be called once for each Pactor Port - // The COM port number is in IOBASE - // - - sprintf(msg,"HAL Driver %s", PortEntry->PORTCONTROL.SerialPortName); - WritetoConsole(msg); - - port=PortEntry->PORTCONTROL.PORTNUMBER; - - ReadConfigFile(port, ProcessLine); - TNC = TNCInfo[port]; - - if (TNC == NULL) - { - // Not defined in Config file - - sprintf(msg," ** Error - no info in BPQ32.cfg for this port"); - WritetoConsole(msg); - - return ExtProc; - } - - TNC->Port = port; - - TNC->Hardware = H_HAL; - - TNC->Interlock = PortEntry->PORTCONTROL.PORTINTERLOCK; - - PortEntry->MAXHOSTMODESESSIONS = 1; // Default - - TNC->PortRecord = PortEntry; - - if (PortEntry->PORTCONTROL.PORTCALL[0] == 0) - { - memcpy(TNC->NodeCall, MYNODECALL, 10); - } - else - { - ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall); - } - - PortEntry->PORTCONTROL.PROTOCOL = 10; - PortEntry->PORTCONTROL.PORTQUALITY = 0; - - if (PortEntry->PORTCONTROL.PORTPACLEN == 0) - PortEntry->PORTCONTROL.PORTPACLEN = 100; - - ptr=strchr(TNC->NodeCall, ' '); - if (ptr) *(ptr) = 0; // Null Terminate - - if (TNC->DefaultMode) - TNC->CurrentMode = TNC->DefaultMode; - else - TNC->CurrentMode = Clover; - - TNC->PollDelay = 999999999; - - // Set Disable +?, ExpandedStatus , Channel Stats Off, ClearOnDisc, EAS and MYCALL - - len = sprintf(Msg, "%c%c%c%c%c%c%s", 0xcc, 0x56, 0x41, ClearOnDisc, SetEAS, SetMYCALL, TNC->NodeCall); - len++; // We include the NULL - - memcpy(&TNC->InitScript[TNC->InitScriptLen], Msg, len); - TNC->InitScriptLen += len; - - PortEntry->PORTCONTROL.TNC = TNC; - - TNC->WebWindowProc = WebProc; - TNC->WebWinX = 510; - TNC->WebWinY = 280; - - TNC->WEB_COMMSSTATE = zalloc(100); - TNC->WEB_TNCSTATE = zalloc(100); - strcpy(TNC->WEB_TNCSTATE, "Free"); - TNC->WEB_MODE = zalloc(100); - TNC->WEB_TRAFFIC = zalloc(100); - TNC->WEB_BUFFERS = zalloc(100); - TNC->WEB_STATE = zalloc(100); - TNC->WEB_TXRX = zalloc(100); - TNC->WEB_LEDS = zalloc(100); - strcpy(TNC->WEB_LEDS, " X X X X X X"); - -#ifndef LINBPQ - - CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 233, ForcedClose); - - x = CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "Status", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_STATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "TX/RX State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_TXRX = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL); - x = TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0 ACKED 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL); - - x = CreateWindowEx(0, "STATIC", "LEDS", WS_CHILD | WS_VISIBLE,10,138,60,20, TNC->hDlg, NULL, hInstance, NULL); - SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0); - x = CreateWindowEx(0, "STATIC", "STBY CALL LINK ERROR TX RX", WS_CHILD | WS_VISIBLE,116,138,280,20, TNC->hDlg, NULL, hInstance, NULL); - SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0); - x = TNC->xIDC_LEDS = CreateWindowEx(0, "STATIC", " X X X X X X", WS_CHILD | WS_VISIBLE,116,158,280,20 , TNC->hDlg, NULL, hInstance, NULL); - SendMessage(x, WM_SETFONT, (WPARAM)hFont, 0); - - TNC->ClientHeight = 233; - TNC->ClientWidth = 500; - - MoveWindows(TNC); -#endif - - OpenCOMMPort(TNC, PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE); - - SendCmd(TNC, "\x09" , 1); // Reset - - WritetoConsole("\n"); - - return ExtProc; -} - - - -static VOID KISSCLOSE(int Port) -{ - struct TNCINFO * conn = TNCInfo[Port]; - - // drop DTR and RTS - - COMClearDTR(conn->hDevice); - COMClearRTS(conn->hDevice); - - // purge any outstanding reads/writes and close device handle - - CloseCOMPort(conn->hDevice); - - return; -} - - -static void CheckRX(struct TNCINFO * TNC) -{ - int Length, Len; - UCHAR * Xptr; - - // only try to read number of bytes in queue - - if (TNC->RXLen == 500) - TNC->RXLen = 0; - - Len = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen); - - if (Len == 0) - return; - - TNC->RXLen += Len; - - Length = TNC->RXLen; - - // We need to konw whether data is received or echoed, so we can't split commands and data here. - // Pass everything to the Command Handler. It will check that there are enough bytes for the command, - // and wait for more if not. - - // The USB version also uses 0x91 0x31 to eacape 0x11, 0x91 0x33 for 0x13 and 0x91 0xB1 for 0x91 - - // If USB version, we might get unescaped xon and xoff, which we must ignore - - if (TNC->XONXOFF) - { - Xptr = memchr(&TNC->RXBuffer, 0x11, Length); - - while(Xptr) - { - Debugprintf("XON Port %d", TNC->Port); - memmove(Xptr, Xptr + 1, Length-- - (TNC->RXBuffer - Xptr)); - Xptr = memchr(&TNC->RXBuffer, 0x11, Length); - } - - Xptr = memchr(&TNC->RXBuffer, 0x13, Length); - - while(Xptr) - { - Debugprintf("XOFF Port %d", TNC->Port); - memmove(Xptr, Xptr + 1, Length-- - (TNC->RXBuffer - Xptr)); - Xptr = memchr(&TNC->RXBuffer, 0x13, Length); - } - - Xptr = memchr(&TNC->RXBuffer, 0x91, Length); // See if packet contains 0x91 escape - - if (Xptr) - - // Make sure we have the escaped char as well - - if ((Xptr - &TNC->RXBuffer[0]) == Length - 1) // x91 is last char - return; - } - - ProcessHALBuffer(TNC, Length); - - TNC->RXLen = 0; - - return; - -} - - - -static BOOL WriteCommBlock(struct TNCINFO * TNC) -{ - WriteCOMBlock(TNC->hDevice, TNC->TXBuffer, TNC->TXLen); - return TRUE; -} - -VOID HALPoll(int Port) -{ - struct TNCINFO * TNC = TNCInfo[Port]; - struct STREAMINFO * STREAM = &TNC->Streams[0]; - - UCHAR * Poll = TNC->TXBuffer; - char Status[80]; - UCHAR TXMsg[1000]; - int datalen; - - if (TNC->Timeout) - { - TNC->Timeout--; - - if (TNC->Timeout) // Still waiting - return; - - // Timed Out - - TNC->TNCOK = FALSE; - TNC->HostMode = 0; - - sprintf(TNC->WEB_COMMSSTATE,"%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName); - MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (TNC->PortRecord->ATTACHEDSESSIONS[0]) // Connected - { - STREAM->Connected = FALSE; // Back to Command Mode - STREAM->ReportDISC = TRUE; // Tell Node - } - } - - } - - // if we have just restarted or TNC appears to be in terminal mode, run Initialisation Sequence - - if (TNC->TNCOK) - if (!TNC->HostMode) - { - DoTNCReinit(TNC); - return; - } - - if (TNC->PortRecord->ATTACHEDSESSIONS[0] && STREAM->Attached == 0) - { - // New Attach - - int calllen; - char Msg[80]; - - STREAM->Attached = TRUE; - - STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = 0; - - calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, STREAM->MyCall); - STREAM->MyCall[calllen] = 0; - - datalen = sprintf(TXMsg, "%c%s", SetMYCALL, STREAM->MyCall); - SendCmd(TNC, TXMsg, datalen + 1); // Send the NULL - - sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - // Stop Scanning - - sprintf(Msg, "%d SCANSTOP", TNC->Port); - - Rig_Command(-1, Msg); - - SendCmd(TNC, "\x42", 1); // Connect Enable off - - return; - - } - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - - if (STREAM->Attached) - CheckForDetach(TNC, 0, STREAM, TidyClose, ForcedClose, CloseComplete); - - if (TNC->NeedPACTOR) - { - TNC->NeedPACTOR--; - - if (TNC->NeedPACTOR == 0) - { - int datalen; - - UCHAR TXMsg[80]; - - datalen = sprintf(TXMsg, "%c%s", SetMYCALL, TNC->NodeCall); - SendCmd(TNC, TXMsg, datalen + 1); // Send the NULL - - // Set Listen Mode - - switch (TNC->CurrentMode) - { - case Pactor: - - SendCmd(TNC, "\x84", 1); // FSK - SendCmd(TNC, "\x83", 1); // Select P-MODE Standby - SendCmd(TNC, "\x58", 1); // Listen - - break; - - case Clover: - - SendCmd(TNC, "\x80", 1); // Clover - SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format - SendCmd(TNC, "\x41", 1); // No Statistics - SendCmd(TNC, "\x60\x09", 2); // Robust Retries - SendCmd(TNC, "\x61\x09", 2); // Normal Retries - - break; - } - - SendCmd(TNC, "\x52", 1); // ConnectEnable - - // Restart Scanning - - sprintf(Status, "%d SCANSTART 15", TNC->Port); - - Rig_Command(-1, Status); - - return; - } - } - -#define MAXHALTX 256 - - //for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (TNC->TNCOK && STREAM->BPQtoPACTOR_Q && (STREAM->BytesTXed - STREAM->BytesAcked < 600)) - { - int datalen; - UINT * buffptr; - UCHAR * MsgPtr; - unsigned char TXMsg[500]; - - buffptr = (UINT * )STREAM->BPQtoPACTOR_Q; - datalen=buffptr[1]; - MsgPtr = (UCHAR *)&buffptr[2]; - - if (STREAM->Connected) - { - if (TNC->SwallowSignon) - { - TNC->SwallowSignon = FALSE; - if (strstr(MsgPtr, "Connected")) // Discard *** connected - { - ReleaseBuffer(buffptr); - STREAM->FramesQueued--; - return; - } - } - - // Must send data in small chunks - the Hal has limited buffer space - - // If in IRS force a turnround - - if (TNC->TXRXState == 'R' && TNC->CurrentMode != Clover) - { - if (TNC->TimeInRX++ > 15) - SendCmd(TNC, "\x87", 1); // Changeover to ISS - else - goto Poll; - } - - TNC->TimeInRX = 0; - - EncodeAndSend(TNC, MsgPtr, datalen); - buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q); - ReleaseBuffer(buffptr); - WriteLogLine(2, MsgPtr, datalen); - - STREAM->BytesTXed += datalen; - STREAM->FramesQueued--; - - ShowTraffic(TNC); - - return; - } - else - { - buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q); - STREAM->FramesQueued--; - - // Command. Do some sanity checking and look for things to process locally - - datalen--; // Exclude CR - MsgPtr[datalen] = 0; // Null Terminate - _strupr(MsgPtr); - - if (memcmp(MsgPtr, "RADIO ", 6) == 0) - { - sprintf(&MsgPtr[40], "%d %s", TNC->Port, &MsgPtr[6]); - if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK->CIRCUITINDEX, &MsgPtr[40])) - { - ReleaseBuffer(buffptr); - } - else - { - buffptr[1] = sprintf((UCHAR *)&buffptr[2], "%s", &MsgPtr[40]); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - } - return; - } - - if (memcmp(MsgPtr, "MODE CLOVER", 11) == 0) - { - TNC->CurrentMode = Clover; - buffptr[1] = sprintf((UCHAR *)&buffptr[2],"HAL} Ok\r"); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - MySetWindowText(TNC->xIDC_MODE, "Clover"); - strcpy(TNC->WEB_MODE, "Clover"); - - SendCmd(TNC, "\x80", 1); // Clover - SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format - SendCmd(TNC, "\x41", 1); // No Statistics - - return; - } - - if (memcmp(MsgPtr, "MODE PACTOR", 11) == 0) - { - TNC->CurrentMode = Pactor; - buffptr[1] = sprintf((UCHAR *)&buffptr[2],"HAL} Ok\r"); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - SendCmd(TNC, "\x84", 1); // FSK - SendCmd(TNC, "\x83", 1); // Select P-MODE Standby - SendCmd(TNC, "\x48", 1); // Listen Off - - return; - } - if (memcmp(MsgPtr, "MODE AMTOR", 11) == 0) - { - TNC->CurrentMode = AMTOR; - buffptr[1] = sprintf((UCHAR *)&buffptr[2],"HAL} Ok\r"); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - return; - } - - if (MsgPtr[0] == 'C' && MsgPtr[1] == ' ' && datalen > 2) // Connect - { - memcpy(STREAM->RemoteCall, &MsgPtr[2], 9); - - switch (TNC->CurrentMode) - { - case Pactor: - - SendCmd(TNC, "\x84", 1); // FSK - SendCmd(TNC, "\x83", 1); // Select P-MODE Standby - - datalen = sprintf(TXMsg, "\x19%s", STREAM->RemoteCall); - - sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - PACTOR", STREAM->MyCall, STREAM->RemoteCall); - - // DOnt set connecting till we get the 19 response so we can trap listen as a fail - break; - - case Clover: - - SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format - SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect - - datalen = sprintf(TXMsg, "\x11%s", STREAM->RemoteCall); - - sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - CLOVER", STREAM->MyCall, STREAM->RemoteCall); - - break; - } - - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - SendCmd(TNC, TXMsg, datalen + 1); // Include NULL - - ReleaseBuffer(buffptr); - - return; - } - - if (memcmp(MsgPtr, "CLOVER ", 7) == 0) - { - memcpy(STREAM->RemoteCall, &MsgPtr[2], 9); - - SendCmd(TNC, "\x54", 1); // Enable adaptive Clover format - SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect - - datalen = sprintf(TXMsg, "\x11%s", STREAM->RemoteCall); - SendCmd(TNC, TXMsg, datalen + 1); // Include NULL - - sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s - CLOVER", - STREAM->MyCall, STREAM->RemoteCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - ReleaseBuffer(buffptr); - - return; - } - - if (memcmp(MsgPtr, "DISCONNECT", datalen) == 0) // Disconnect - { - SendCmd(TNC, "\x07", 1); // Normal Disconnect - TNC->NeedPACTOR = 50; - - STREAM->Connecting = FALSE; - STREAM->ReportDISC = TRUE; - ReleaseBuffer(buffptr); - - return; - } - - // Other Command ?? Treat as HEX string - - datalen = sscanf(MsgPtr, "%X %X %X %X %X %X %X %X %X %X %X %X %X %X %X %X", - (UINT *)&TXMsg[0], (UINT *)&TXMsg[1], (UINT *)&TXMsg[2], (UINT *)&TXMsg[3], (UINT *)&TXMsg[4], - (UINT *)&TXMsg[5], (UINT *)&TXMsg[6], (UINT *)&TXMsg[7], (UINT *)&TXMsg[8], (UINT *)&TXMsg[9], - (UINT *)&TXMsg[10], (UINT *)&TXMsg[11], (UINT *)&TXMsg[12], (UINT *)&TXMsg[13], - (UINT *)&TXMsg[14], (UINT *)&TXMsg[15]); - -// SendCmd(TNC, TXMsg, datalen); - ReleaseBuffer(buffptr); - TNC->InternalCmd = 0; - } - } - } -Poll: - // Nothing doing - send Poll (but not too often) - - TNC->PollDelay++; - - if (TNC->PollDelay < 20) - return; - - TNC->PollDelay = 0; - - if (TNC->TNCOK) - SendCmd(TNC, "\x7d" , 1); // Use Get LEDS as Poll - else - SendCmd(TNC, "\x09" , 1); // Reset - - TNC->Timeout = 100; - - return; -} - -static VOID DoTNCReinit(struct TNCINFO * TNC) -{ - // TNC Has Restarted, send init commands (can probably send all at once) - -// TNC->TXBuffer[0] = 0x1b; -// TNC->TXLen = 1; - - WriteCommBlock(TNC); - - SendCmd(TNC, TNC->InitScript, TNC->InitScriptLen); - - TNC->HostMode = TRUE; // Should now be in Host Mode - TNC->NeedPACTOR = 20; // Need to set Calls and start scan - - TNC->DataMode = RXDATA; // Start with RX Data - - SendCmd(TNC, "\x7d" , 1); // Use Get LEDS as Poll -// SendCmd(TNC, "\xc9" , 1); // Huffman Off - SendCmd(TNC, "\x57", 1); // Enable TX buffer clear on disconnect - - SendCmd(TNC, "\x60\x06", 2); // Robust Mode Retries - -// SendCmd(TNC, "\x6f\x03" , 2); // Undocumented XON/XOFF On - used to see if old or new style modem - - TNC->Timeout = 50; - - return; - -} - -VOID ProcessHALData(struct TNCINFO * TNC) -{ - // Received Data just pass to Appl - - UINT * buffptr; - int Len = TNC->DataLen; - struct STREAMINFO * STREAM = &TNC->Streams[0]; - - TNC->DataLen = 0; - - if (TNC->DataMode == TXDATA) - { - STREAM->BytesAcked += Len; -// Debugprintf("Acked %d", Len); - - if (STREAM->BytesAcked > STREAM->BytesTXed) - Debugprintf("Too Much Acked"); - - if ((STREAM->BPQtoPACTOR_Q == 0) && STREAM->BytesAcked >= STREAM->BytesTXed) - { - // All sent - - if (STREAM->Disconnecting) - TidyClose(TNC, 0); - else - if (TNC->CurrentMode != Clover) - - // turn round link - - SendCmd(TNC, "\x0c" , 1); // Turnround - - } - } - else - { - if (TNC->DataMode == RXDATA) - { -// Debugprintf("RXed %d", Len); - buffptr = GetBuff(); - if (buffptr == NULL) - return; // No buffers, so ignore - - buffptr[1] = Len; // Length - - WriteLogLine(1, TNC->DataBuffer, Len); - - STREAM->BytesRXed += Len; - - memcpy(&buffptr[2], TNC->DataBuffer, Len); - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - } - } - - ShowTraffic(TNC); - - return; -} - - - -VOID ProcessHALBuffer(struct TNCINFO * TNC, int Length) -{ - UCHAR Char; - UCHAR * inptr; - UCHAR * cmdptr; - UCHAR * dataptr; - BOOL CmdEsc, DataEsc; - - inptr = TNC->RXBuffer; - - cmdptr = &TNC->CmdBuffer[TNC->CmdLen]; - dataptr = &TNC->DataBuffer[TNC->DataLen]; - CmdEsc = TNC->CmdEsc; - DataEsc = TNC->DataEsc; - - // HAL uses HEX 80 as a command escape, 81 to ESCAPE 80 and 81 - - // The USB version also uses 0x91 0x31 to eacape 0x11, 0x91 0x33 for 0x13 and 0x91 0xB1 for 0x91 - - // Command Responses can be variable length - - // Command Handler will check for each command/response if it has enough - if not it will wait till more arrives - - while(Length--) - { - Char = *(inptr++); - - if (CmdEsc) - { - CmdEsc = FALSE; - - if (TNC->XONXOFF && Char == 0x91) - { - // XON/XOFF escape. We ensured above that data follows so we can process it inline - - Length--; - Char = *(inptr++) - 0x20; - } - *(cmdptr++) = Char; - } - else if (DataEsc) - { - DataEsc = FALSE; - goto DataChar; - } - else -NotData: - if (Char == 0x80) // Next Char is Command - CmdEsc = TRUE; - else if (Char == 0x81) // Next Char is escaped data (80 or 81) - DataEsc = TRUE; - else - { - // This is a Data Char. We must process any Commands received so far, so we know the type of data - - DataChar: - - TNC->CmdLen = (int)(cmdptr - TNC->CmdBuffer); - ProcessHALCmd(TNC); - cmdptr = &TNC->CmdBuffer[TNC->CmdLen]; - dataptr = &TNC->DataBuffer[TNC->DataLen]; - - *(dataptr++) = Char; // Normal Data - - // Now process any other data chars - - while(Length--) - { - Char = *(inptr++); - - if (TNC->XONXOFF && Char == 0x91) - { - // XON/XOFF escape within data. We ensured above that data follows so we - // can process it here - - Length--; - Char = *(inptr++) - 0x20; - } - - if (Char == 0x80 || Char == 0x81) - { - // Process any data we have, then loop back - - TNC->DataLen = (int)(dataptr - TNC->DataBuffer); - ProcessHALData(TNC); - - goto NotData; - } - *(dataptr++) = Char; // Normal Data - } - - // Used all data - - TNC->DataLen = (int)(dataptr - TNC->DataBuffer); - - ProcessHALData(TNC); - TNC->CmdEsc = CmdEsc; - TNC->DataEsc = DataEsc; - - return; - } - } - - // Save State - - TNC->CmdLen = (int)(cmdptr - TNC->CmdBuffer); - - TNC->CmdEsc = CmdEsc; - TNC->DataEsc = DataEsc; - - if (TNC->DataLen) - ProcessHALData(TNC); - - if (TNC->CmdLen) - ProcessHALCmd(TNC); -} - -VOID mySetWindowText(struct TNCINFO * TNC, char * Msg) -{ - MySetWindowText(TNC->xIDC_STATE, Msg); - strcpy(TNC->WEB_STATE, Msg); -} - -VOID ProcessHALCmd(struct TNCINFO * TNC) -{ - char * Call; - int Stream = 0; - int Opcode; - int StatusByte; - int Leds; - int Len; - int Used; - struct STREAMINFO * STREAM = &TNC->Streams[0]; - -CmdLoop: - - Opcode = TNC->CmdBuffer[0]; - Len = TNC->CmdLen; - - if (Len == 0) - return; - - TNC->TNCOK = TRUE; - TNC->Timeout = 0; - - sprintf(TNC->WEB_COMMSSTATE,"%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName); - MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); - - // We may have more than one response in the buffer, and only each cmd/response decoder knows how many it needs - - switch(Opcode) - { - case 0x09: //Hardware Reset - equivalent to power on reset - - // Hardware has reset - need to reinitialise - - TNC->HostMode = 0; // Force Reinit - - Used = 1; - break; - - case 0x7a: // FSK Modes Status - - // Mixture of mode and state - eg listen huffman on/off irs/iss, so cant just display - - if (Len < 2) return; // Wait for more - - StatusByte = TNC->CmdBuffer[1]; - - switch (StatusByte) - { - case 0x06: // FSK TX (RTTY) - case 0x07: // FSK RX (RTTY) - case 0x10: // AMTOR STANDBY (LISTEN ON) - case 0x11: // AMTOR STANDBY (LISTEN OFF) - case 0x12: // AMTOR FEC TX (AMTOR) - case 0x13: // AMTOR FEC RX (AMTOR) - case 0x14: // P-MODE FEC TX (P-MODE) - case 0x15: // FREE SIGNAL TX (AMTOR) - case 0x16: // FREE SIGNAL TX TIMED OUT (AMTOR) - - // Diaplay Linke Status - - MySetWindowText(TNC->xIDC_MODE, status[StatusByte]); - strcpy(TNC->WEB_MODE, status[StatusByte]); - - break; - - case 0x0C: // P-MODE STANDBY (LISTEN ON) - case 0x0D: // P-MODE STANDBY (LISTEN OFF) - - // if we were connecting, this means connect failed. - - MySetWindowText(TNC->xIDC_MODE, status[StatusByte]); - strcpy(TNC->WEB_MODE, status[StatusByte]); - - if (STREAM->Connecting) - HALDisconnected(TNC); - - break; - - case 0x0E: // ISS (AMTOR/P-MODE) - - MySetWindowText(TNC->xIDC_TXRX,"ISS"); - strcpy(TNC->WEB_TXRX, "ISS"); - TNC->TXRXState = 'S'; - break; - - case 0x0F: // IRS (AMTOR/P-MODE) - - MySetWindowText(TNC->xIDC_TXRX,"IRS"); - strcpy(TNC->WEB_TXRX, "IRS"); - TNC->TXRXState = 'R'; - break; - - case 0x00: // IDLE (AMTOR/P-MODE) - case 0x01: // TFC (AMTOR/P-MODE) - case 0x02: // RQ (AMTOR/P-MODE) - case 0x03: // ERR (AMTOR/P-MODE) - case 0x04: // PHS (AMTOR/P-MODE) - case 0x05: // OVER (AMTOR/P-MODE) (not implemented) - - MySetWindowText(TNC->xIDC_STATE, status[StatusByte]); - strcpy(TNC->WEB_MODE, status[StatusByte]); - - - -//$807A $8008 P-MODE100 (P-MODE) -//$807A $8009 P-MODE200 (P-MODE) -//$807A $800A HUFFMAN ON (P-MODE) -//$807A $800B HUFFMAN OFF (P-MODE) - ; - } - Used = 2; - break; - - - case 0x7d: // Get LED Status - - // We use Get LED Status as a Poll - - if (Len < 2) return; // Wait for more - - Leds = TNC->CmdBuffer[1]; - sprintf(TNC->WEB_LEDS," %c %c %c %c %c %c ", - (Leds & 0x20)? 'X' : ' ', - (Leds & 0x10)? 'X' : ' ', - (Leds & 0x08)? 'X' : ' ', - (Leds & 0x04)? 'X' : ' ', - (Leds & 0x02)? 'X' : ' ', - (Leds & 0x01)? 'X' : ' '); - -// STBY CALL LINK ERROR TX RX - MySetWindowText(TNC->xIDC_LEDS, TNC->WEB_LEDS); - - Used = 2; - break; - - case 0x21: // Monitored FEC CCB - case 0x22: // Monitored ARQ CCB - - // As the reply is variable, make sure we have the terminating NULL - - if (memchr(TNC->CmdBuffer, 0, Len) == NULL) - return; // Wait for more - - Call = &TNC->CmdBuffer[1]; - Used = (int)strlen(Call) + 2; // Opcode and Null - - UpdateMH(TNC, Call, '!', 0); - - break; - - case 0x27: // Clover ARQ LINK REQUEST status message - - //indicates an incoming link request to either MYCALL ($8027 $8000), or MYALTCALL ($8027 $8001). - - if (Len < 2) return; // Wait for more - - // Don't need to do anything (but may eventally use ALTCALL as an APPLCALL - Used = 2; - break; - - case 0x2D: // FSK ARQ Link Request status message - - // $802D $8001 $8000 CLOVER Link Request (not implemented) - // $802D $8002 $8000 AMTOR CCIR-476 Link Request - // $802D $8003 $8000 AMTOR CCIR-625 Link Request - // $802D $8004 $8000 P-MODE Link Request - - if (Len < 3) return; // Wait for more - - // Don't need to do anything (but may save Session type later - - Used = 3; - break; - - - case 0x28: // Monitored Call - - // As the reply is variable, make sure we have the terminating NULL - - if (memchr(TNC->CmdBuffer, 0, Len) == NULL) - return; // Wait for more - - Call = &TNC->CmdBuffer[1]; - Used = (int)strlen(Call) + 2; // Opcode and Null - - // Could possibly be used for APPLCALLS by changing MYCALL when we see a call to one of our calls - - break; - - - case 0x20: // Clover Linked with - Call Connected - case 0x29: // The Linked 476 message indicates the start of a CCIR 476 linked session. - case 0x2A: // The Linked 625 message indicates the start of a CCIR 625 linked session to . - case 0x2B: // P-MODE link to - - // As the reply is variable, make sure we have the terminating NULL - - if (memchr(TNC->CmdBuffer, 0, Len) == NULL) - return; // Wait for more - - Call = &TNC->CmdBuffer[1]; - Used = (int)strlen(Call) + 2; // Opcode and Null - - HALConnected(TNC, Call); - - break; - - case 0x23: // Normal Disconnected - followed by $8000 - case 0x24: // Link failed (any of the link errors) - case 0x25: // Signal Lost (LOS) - - if (Len < 2) return; // Wait for more - - HALDisconnected(TNC); - - Used = 2; - break; - - - // Stream Switch Reports - we will need to do something with these if Echo as Sent is set - // or we do something with the secondary port - - case 0x30: // Switch to Receive Data characters - case 0x31: // Switch to Transmit Data characters - case 0x32: // Switch to RX data from secondary port - - TNC->DataMode = Opcode; - Used = 1; - break; - - case 0x33: // Send TX data to modem - case 0x34: // Send TX data to secondary port - - TNC->TXMode = Opcode; - Used = 1; - break; - - case 0x70: // Channel Spectra Data - // $807F $80xx $8030 Invalid or unimplemented command code - if (Len < 9) return; // Wait for more - - Used = 9; - break; - - case 0x71: // SelCall On/Off - - if (Len < 2) return; // Wait for more - - Used = 2; - break; - - case 0x72: // Channel Spectra Data - // $807F $80xx $8030 Invalid or unimplemented command code - if (Len < 15) return; // Wait for more - - Used = 15; - break; - - case 0x73: // Clover Link state - - if (Len < 2) return; // Wait for more - - StatusByte = TNC->CmdBuffer[1]; - - switch (StatusByte) - { - case 0x00: mySetWindowText(TNC, "Channel idle"); break; - case 0x01: mySetWindowText(TNC, "Channel occupied with non-Clover signal"); break; - case 0x42: mySetWindowText(TNC, "Linked stations monitored"); break; - case 0x64: mySetWindowText(TNC, "Attempting normal link"); break; - case 0x65: mySetWindowText(TNC, "Attempting robust link"); break; - case 0x66: mySetWindowText(TNC, "Calling ARQ CQ"); break; - case 0x78: mySetWindowText(TNC, "Clover Control Block (CCB) send retry"); break; - case 0x79: mySetWindowText(TNC, "Clover Control Block (CCB) receive retry"); break; - case 0x7D: mySetWindowText(TNC, "Clover Control Block (CCB) received successfully"); break; - case 0x8A: mySetWindowText(TNC, "TX data block sent"); break; - case 0x8B: mySetWindowText(TNC, "RX data block received ok (precedes data block)"); break; - case 0x8C: mySetWindowText(TNC, "TX data block re-sent"); break; - case 0x8D: mySetWindowText(TNC, "RX data block decode failed (precedes data block)"); break; - case 0x8E: mySetWindowText(TNC, "TX idle"); break; - case 0x8F: mySetWindowText(TNC, "RX idle"); break; - case 0x9C: mySetWindowText(TNC, "Link failed: CCB send retries exceeded"); break; - case 0x9D: mySetWindowText(TNC, "Link failed: CCB receive retries exceeded"); break; - case 0x9E: mySetWindowText(TNC, "Link failed: protocol error"); break; - case 0xA0: mySetWindowText(TNC, "Receiving FEC SYNC sequence"); break; - } - - Used = 2; - break; - - case 0x75: // Clover waveform format - - if (Len < 5) return; // Wait for more - - Used = 5; - break; - - case 0x7F: // Error $80xx $80yy Error in command $80xx of type $80yy - // $807F $80xx $8030 Invalid or unimplemented command code - // $807F $80xx $8031 Invalid parameter value - // $807F $80xx $8032 Not allowed when connected - // $807F $80xx $8033 Not allowed when disconnected - // $807F $80xx $8034 Not valid in this mode - // $807F $80xx $8035 Not valid in this code - // $807F $8096 $8036 EEPROM write error - - if (Len < 3) return; // Wait for more - - if (TNC->CmdBuffer[1] == 0x6f && TNC->CmdBuffer[2] == 0x31) - { - // Reject of XON/XOFF enable - -// TNC->XONXOFF = FALSE; -// Debugprintf("BPQ32 HAL Port %d - Disabling XON/XOFF mode", TNC->Port); - } - else - Debugprintf("HAL Port %d Command Error Cmd %X Error %X", TNC->Port, TNC->CmdBuffer[1], TNC->CmdBuffer[2]); - - Used = 3; - break; - - // Following are all immediate commands - response is echo of command - - case 0x6f: // XON/XOFF on - -// TNC->XONXOFF = TRUE; // And drop through -// Debugprintf("BPQ32 HAL Port %d - Enabling XON/XOFF mode", TNC->Port); - - case 0x19: // Call P-MODE to - case 0x10: // Robust Link to using MYCALL - case 0x11: // Normal Link to using MYCALL - - STREAM->Connecting = TRUE; - - case 0x00: // P Load LOD file - case 0x01: // P Load S28 file - case 0x02: //Check Unit Error Status - case 0x03: //F Check System Clock - case 0x04: //C Close PTT and transmit Clover waveform - case 0x05: //Open PTT and stop transmit test - case 0x06: //Immediate Abort (Panic Kill) - case 0x07: //Normal disconnect (wait for ACK) - case 0x08: //Software reset - restore all program defaults - case 0x0A: //Send CW ID - case 0x0B: //Close PTT and transmit Single Tone - case 0x0C: //F Normal OVER (AMTOR,P-MODE) - case 0x0D: //F Force RTTY TX (Baudot/ASCII) - case 0x0E: //F Go to RTTY RX (Baudot/ASCII) - case 0x0F: //Go to LOD/S28 file loader - case SetMYCALL: // Set MYCALL Response - - case 0x1E: // Set MYALTCALL Response - - case 0x41: - case 0x42: - case 0x46: - case 0x47: - case 0x48: - case 0x4d: - case 0x52: // Enable adaptive Clover format - case 0x54: // Enable adaptive Clover format - - case 0x56: // Expanded Link State Reports OFF/ON - case 0x57: // Clear buffers on disc - case 0x58: - case 0x59: - case 0x60: // Robust Mode Retries - case 0x61: // Normal Mode Retries - case 0x80: //Switch to CLOVER mode - case 0x81: //Select AMTOR Standby - case 0x82: //Select AMTOR FEC - case 0x83: //Select P-MODE Standby - case 0x84: //Switch to FSK modes - case 0x85: //Select Baudot - case 0x86: //Select ASCII - case 0x87: //Forced OVER (AMTOR, P-MODE) - case 0x88: //Forced END (AMTOR, P-MODE) - case 0x89: //Force LTRS shift - case 0x8A: //Force FIGS shift - case 0x8B: //Send MARK tone - case 0x8C: //Send SPACE tone - case 0x8D: //Send MARK/SPACE tones - case 0x8E: //Received first character on line - case 0x8F: //Close PTT only (no tones) - - case 0xC9: //Huffman Off/On - case 0xCC: - case 0xD9: //Close PTT only (no tones) - - case SetTones: - - Used = 1; - break; - - case 0x91: // ???? - -// if (Len < 2) return; // Wait for more - - Used = 1; - break; - - default: - - // We didn't recognise command, so don't know how long it is - disaster! - - Debugprintf("HAL Port %d Unrecognised Command %x", TNC->Port, Opcode); - TNC->CmdLen = 0; - - return; - } - - if (Used == Len) - { - // All used - most likely case - - TNC->CmdLen = 0; - return; - } - - // Move Command Down buffer, and reenter - - TNC->CmdLen -= Used; - - memmove(TNC->CmdBuffer, &TNC->CmdBuffer[Used], TNC->CmdLen); - - goto CmdLoop; - - -} - - -VOID HALDisconnected(struct TNCINFO * TNC) -{ - struct STREAMINFO * STREAM = &TNC->Streams[0]; - - CloseLogfile(0); - CloseLogfile(1); - CloseLogfile(2); - - if ((STREAM->Connecting | STREAM->Connected) == 0) - { - // Not connected or Connecting. Probably response to going into Pactor Listen Mode - - return; - } - - if (STREAM->Connecting && STREAM->Disconnecting == FALSE) - { - UINT * buffptr; - - // Connect Failed - actually I think HAL uses another code for connect failed, but leave here for now - - buffptr = GetBuff(); - - if (buffptr) - { - buffptr[1] = sprintf((UCHAR *)&buffptr[2], "*** Failure with %s\r", STREAM->RemoteCall); - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - } - - STREAM->Connecting = FALSE; - STREAM->Connected = FALSE; // In case! - STREAM->FramesQueued = 0; - - sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - return; - } - - // Connected, or Disconnecting - Release Session - - STREAM->Connecting = FALSE; - STREAM->Connected = FALSE; // Back to Command Mode - STREAM->FramesQueued = 0; - - if (STREAM->Disconnecting == FALSE) - STREAM->ReportDISC = TRUE; // Tell Node - - STREAM->Disconnecting = FALSE; - - // Need to reset Pactor Call in case it was changed - - TNC->NeedPACTOR = 20; -} - -BOOL HALConnected(struct TNCINFO * TNC, char * Call) -{ - char Msg[80]; - UINT * buffptr; - struct STREAMINFO * STREAM = &TNC->Streams[0]; - char CallCopy[80]; - - strcpy(CallCopy, Call); - strcat(CallCopy, " "); // Some routines expect 10 char calls - - STREAM->BytesRXed = STREAM->BytesTXed = STREAM->BytesAcked = 0; - STREAM->ConnectTime = time(NULL); - - // Stop Scanner - - sprintf(Msg, "%d SCANSTOP", TNC->Port); - - Rig_Command(-1, Msg); - - ShowTraffic(TNC); - - TNC->DataMode = RXDATA; - - OpenLogfile(0); - OpenLogfile(1); - OpenLogfile(2); - - if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0) - { - // Incoming Connect - - ProcessIncommingConnect(TNC, CallCopy, 0, TRUE); - - sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", STREAM->RemoteCall, TNC->NodeCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - if (TNC->CurrentMode != Clover) - SendCmd(TNC, "\x87", 1); // Changeover to ISS - - // If an autoconnect APPL is defined, send it - - if (TNC->ApplCmd) - { - buffptr = GetBuff(); - if (buffptr == 0) return TRUE; // No buffers, so ignore - - buffptr[1] = sprintf((UCHAR *)&buffptr[2], "%s\r", TNC->ApplCmd); - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - TNC->SwallowSignon = TRUE; - - return TRUE; - } - - if (FULL_CTEXT && HFCTEXTLEN == 0) - { - EncodeAndSend(TNC, CTEXTMSG, CTEXTLEN); - WriteLogLine(2, CTEXTMSG, CTEXTLEN); - - STREAM->BytesTXed += CTEXTLEN; - } - return TRUE; - } - - // Connect Complete - - buffptr = GetBuff(); - if (buffptr == 0) return TRUE; // No buffers, so ignore - - buffptr[1] = sprintf((UCHAR *)&buffptr[2], "*** Connected to %s\r", Call);; - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - STREAM->Connecting = FALSE; - STREAM->Connected = TRUE; // Subsequent data to data channel - - sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", TNC->NodeCall, STREAM->RemoteCall); - MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - UpdateMH(TNC, CallCopy, '+', 'O'); - - - return TRUE; -} - - -static VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len) -{ - // Send A Packet With DLE Encoding Encoding - - TNC->TXLen = DLEEncode(txbuffer, TNC->TXBuffer, Len); - - WriteCommBlock(TNC); -} - -VOID SendCmd(struct TNCINFO * TNC, UCHAR * txbuffer, int Len) -{ - // Send A Packet With Command Encoding (preceed each with 0x80 - - int i,txptr=0; - UCHAR * outbuff = TNC->TXBuffer; - - for (i=0; iTXLen = txptr; - WriteCommBlock(TNC); -} - -int DLEEncode(UCHAR * inbuff, UCHAR * outbuff, int len) -{ - int i, txptr = 0; - UCHAR c; - - // Escape x80 and x81 with x81 - -// outbuff[0] = 0x80; -// outbuff[1] = 0x33; // Send data to modem - - for (i=0;iNeedPACTOR = 30; -} - - - - diff --git a/IPCode.c b/IPCode.c index 716c846..8013b61 100644 --- a/IPCode.c +++ b/IPCode.c @@ -1271,6 +1271,8 @@ static VOID Send_AX_Datagram(PMESSAGE Block, DWORD Len, UCHAR Port, UCHAR * HWAD memcpy(Block->DEST, HWADDR, 7); memcpy(Block->ORIGIN, MYCALL, 7); Block->DEST[6] &= 0x7e; // Clear End of Call + Block->DEST[6] |= 0x80; // set Command Bit + Block->ORIGIN[6] |= 1; // Set End of Call Block->CTL = 3; //UI diff --git a/L4Code.c b/L4Code.c index 6383b36..424522d 100644 --- a/L4Code.c +++ b/L4Code.c @@ -1297,14 +1297,11 @@ VOID CONNECTREQUEST(struct _LINKTABLE * LINK, L3MESSAGEBUFFER * L3MSG, UINT Appl char BPQPARAMS[10]; // Extended Connect Params from BPQ Node int CONERROR; int Index; - char xxx[16] = ""; memcpy(BPQPARAMS, &L4T1, 2); // SET DEFAULT T1 IN CASE NOT FROM ANOTHER BPQ NODE BPQPARAMS[2] = 0; // 'SPY' NOT SET - ConvFromAX25(&L3MSG->L4DATA[1], xxx); - if (CheckExcludeList(&L3MSG->L4DATA[1]) == 0) { SendConNAK(LINK, L3MSG); diff --git a/LinBPQ.c~ b/LinBPQ.c~ deleted file mode 100644 index d4dddf4..0000000 --- a/LinBPQ.c~ +++ /dev/null @@ -1,1975 +0,0 @@ -/* -Copyright 2001-2018 John Wiseman G8BPQ - -This file is part of LinBPQ/BPQ32. - -LinBPQ/BPQ32 is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -LinBPQ/BPQ32 is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses -*/ - -// Control Routine for LinBPQ - -#define _CRT_SECURE_NO_DEPRECATE - -#include "CHeaders.h" -#include "bpqmail.h" -#ifdef WIN32 -#include -//#include "C:\Program Files (x86)\GnuWin32\include\iconv.h" -#else -#include -#ifndef MACBPQ -#ifndef FREEBSD -#include -#endif -#endif -#endif - -#include "time.h" - -#define Connect(stream) SessionControl(stream,1,0) -#define Disconnect(stream) SessionControl(stream,2,0) -#define ReturntoNode(stream) SessionControl(stream,3,0) -#define ConnectUsingAppl(stream, appl) SessionControl(stream, 0, appl) - -BOOL APIENTRY Rig_Init(); - -void GetSemaphore(struct SEM * Semaphore, int ID); -void FreeSemaphore(struct SEM * Semaphore); -VOID CopyConfigFile(char * ConfigName); -VOID SendMailForThread(VOID * Param); -VOID GetUIConfig(); -Dll BOOL APIENTRY Init_IP(); -VOID OpenReportingSockets(); -VOID SetupNTSAliases(char * FN); -int DeleteRedundantMessages(); -BOOL InitializeTNCEmulator(); -VOID FindLostBuffers(); -VOID IPClose(); -DllExport BOOL APIENTRY Rig_Close(); -Dll BOOL APIENTRY Poll_IP(); -BOOL Rig_Poll(); -BOOL Rig_Poll(); -VOID CheckWL2KReportTimer(); -VOID TNCTimer(); -VOID SendLocation(); -int ChatPollStreams(); -void ChatTrytoSend(); -VOID BBSSlowTimer(); -int GetHTMLForms(); -char * AddUser(char * Call, char * password, BOOL BBSFlag); -VOID SaveChatConfigFile(char * ConfigName); -VOID SaveMH(); -int upnpClose(); -void SaveAIS(); -void initAIS(); -void DRATSPoll(); - -BOOL IncludesMail = FALSE; -BOOL IncludesChat = FALSE; - -BOOL RunMail = FALSE; -BOOL RunChat = FALSE; -BOOL needAIS= FALSE; -BOOL needADSB = FALSE; - -int CloseOnError = 0; - -VOID Poll_AGW(); -BOOL AGWAPIInit(); -int AGWAPITerminate(); - -BOOL AGWActive = FALSE; - -extern int AGWPort; - -BOOL RigActive = FALSE; - -extern ULONG ChatApplMask; -extern char Verstring[]; - -extern char SignoffMsg[]; -extern char AbortedMsg[]; -extern char InfoBoxText[]; // Text to display in Config Info Popup - -extern int LastVer[4]; // In case we need to do somthing the first time a version is run - -extern HWND MainWnd; -extern char BaseDir[]; -extern char BaseDirRaw[]; -extern char MailDir[]; -extern char WPDatabasePath[]; -extern char RlineVer[50]; - -extern BOOL LogBBS; -extern BOOL LogCHAT; -extern BOOL LogTCP; -extern BOOL ForwardToMe; - -extern int LatestMsg; -extern char BBSName[]; -extern char SYSOPCall[]; -extern char BBSSID[]; -extern char NewUserPrompt[]; - -extern int NumberofStreams; -extern int MaxStreams; -extern ULONG BBSApplMask; -extern int BBSApplNum; -extern int ChatApplNum; -extern int MaxChatStreams; - -extern int NUMBEROFTNCPORTS; - -extern int EnableUI; - -extern BOOL AUTOSAVEMH; - -extern FILE * LogHandle[4]; - -#define MaxSockets 64 - -extern ConnectionInfo Connections[MaxSockets+1]; - -time_t LastTrafficTime; -extern int MaintTime; - -#define LOG_BBS 0 -#define LOG_CHAT 1 -#define LOG_TCP 2 -#define LOG_DEBUG_X 3 - -int _MYTIMEZONE = 0; - -// flags equates - -#define F_Excluded 0x0001 -#define F_LOC 0x0002 -#define F_Expert 0x0004 -#define F_SYSOP 0x0008 -#define F_BBS 0x0010 -#define F_PAG 0x0020 -#define F_GST 0x0040 -#define F_MOD 0x0080 -#define F_PRV 0x0100 -#define F_UNP 0x0200 -#define F_NEW 0x0400 -#define F_PMS 0x0800 -#define F_EMAIL 0x1000 -#define F_HOLDMAIL 0x2000 -#define F_POLLRMS 0x4000 -#define F_SYSOP_IN_LM 0x8000 -#define F_Temp_B2_BBS 0x00010000 - -/* #define F_PWD 0x1000 */ - - -UCHAR BPQDirectory[260]; -UCHAR LogDirectory[260]; - -BOOL GetConfig(char * ConfigName); -VOID DecryptPass(char * Encrypt, unsigned char * Pass, unsigned int len); -int EncryptPass(char * Pass, char * Encrypt); -int APIENTRY FindFreeStream(); -int PollStreams(); -int APIENTRY SetAppl(int stream, int flags, int mask); -int APIENTRY SessionState(int stream, int * state, int * change); -int APIENTRY SessionControl(int stream, int command, int Mask); - -BOOL ChatInit(); -VOID CloseChat(); -VOID CloseTNCEmulator(); - -static config_t cfg; -static config_setting_t * group; - -BOOL MonBBS = TRUE; -BOOL MonCHAT = TRUE; -BOOL MonTCP = TRUE; - -BOOL LogBBS = TRUE; -BOOL LogCHAT = TRUE; -BOOL LogTCP = TRUE; - -extern BOOL LogAPRSIS; - -BOOL UIEnabled[33]; -BOOL UINull[33]; -char * UIDigi[33]; - -extern struct UserInfo ** UserRecPtr; -extern int NumberofUsers; - -extern struct UserInfo * BBSChain; // Chain of users that are BBSes - -extern struct MsgInfo ** MsgHddrPtr; -extern int NumberofMessages; - -extern int FirstMessageIndextoForward; // Lowest Message wirh a forward bit set - limits search - -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]; - -extern char NTSAliasesPath[MAX_PATH]; -extern char NTSAliasesName[MAX_PATH]; - -extern char BaseDir[MAX_PATH]; -extern char BaseDirRaw[MAX_PATH]; // As set in registry - may contain %NAME% -extern char ProperBaseDir[MAX_PATH]; // BPQ Directory/BPQMailChat - -extern char MailDir[MAX_PATH]; - -extern time_t MaintClock; // Time to run housekeeping - -#ifdef WIN32 -BOOL KEEPGOING = 30; // 5 secs to shut down -#else -BOOL KEEPGOING = 50; // 5 secs to shut down -#endif -BOOL Restarting = FALSE; -BOOL CLOSING = FALSE; - -int ProgramErrors; -int Slowtimer = 0; - -#define REPORTINTERVAL 15 * 549; // Magic Ticks Per Minute for PC's nominal 100 ms timer -int ReportTimer = 0; - -// Console Terminal Support - -struct ConTermS -{ - int BPQStream; - BOOL Active; - int Incoming; - - char kbbuf[INPUTLEN]; - int kbptr; - - char * KbdStack[MAXSTACK]; - int StackIndex; - - BOOL CONNECTED; - int SlowTimer; -}; - -struct ConTermS ConTerm = {0, 0}; - - -VOID CheckProgramErrors() -{ - 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"); - -/* - 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); - } -} - -#ifdef WIN32 - -BOOL CtrlHandler(DWORD fdwCtrlType) -{ - switch( fdwCtrlType ) - { - // Handle the CTRL-C signal. - case CTRL_C_EVENT: - printf( "Ctrl-C event\n\n" ); - CLOSING = TRUE; - Beep( 750, 300 ); - return( TRUE ); - - // CTRL-CLOSE: confirm that the user wants to exit. - case CTRL_CLOSE_EVENT: - - CLOSING = TRUE; - printf( "Ctrl-Close event\n\n" ); - Sleep(20000); - Beep( 750, 300 ); - return( TRUE ); - - // Pass other signals to the next handler. - case CTRL_BREAK_EVENT: - Beep( 900, 200 ); - printf( "Ctrl-Break event\n\n" ); - CLOSING = TRUE; - Beep( 750, 300 ); - return FALSE; - - case CTRL_LOGOFF_EVENT: - Beep( 1000, 200 ); - printf( "Ctrl-Logoff event\n\n" ); - return FALSE; - - case CTRL_SHUTDOWN_EVENT: - Beep( 750, 500 ); - printf( "Ctrl-Shutdown event\n\n" ); - CLOSING = TRUE; - Beep( 750, 300 ); - return FALSE; - - default: - return FALSE; - } -} - -#else - -// Linux Signal Handlers - -static void sigterm_handler(int sig) -{ - syslog(LOG_INFO, "terminating on SIGTERM\n"); - CLOSING = TRUE; -} - -static void sigint_handler(int sig) -{ - printf("terminating on SIGINT\n"); - CLOSING = TRUE; -} - - -static void sigusr1_handler(int sig) -{ - signal(SIGUSR1, sigusr1_handler); -} - -#endif - - -#ifndef WIN32 - -BOOL CopyFile(char * In, char * Out, BOOL Failifexists) -{ - FILE * Handle; - DWORD FileSize; - char * Buffer; - struct stat STAT; - - if (stat(In, &STAT) == -1) - return FALSE; - - FileSize = STAT.st_size; - - Handle = fopen(In, "rb"); - - if (Handle == NULL) - return FALSE; - - Buffer = malloc(FileSize+1); - - FileSize = fread(Buffer, 1, STAT.st_size, Handle); - - fclose(Handle); - - if (FileSize != STAT.st_size) - { - free(Buffer); - return FALSE; - } - - Handle = fopen(Out, "wb"); - - if (Handle == NULL) - { - free(Buffer); - return FALSE; - } - - FileSize = fwrite(Buffer, 1, STAT.st_size, Handle); - - fclose(Handle); - free(Buffer); - - return TRUE; -} -#endif - -int RefreshMainWindow() -{ - return 0; -} - -int LastSemGets = 0; - -extern int SemHeldByAPI; - -VOID MonitorThread(void * x) -{ - // Thread to detect stuck semaphore - - do - { - if ((Semaphore.Gets == LastSemGets) && Semaphore.Flag) - { - // It is stuck - try to release - - Debugprintf ("Semaphore locked - Process ID = %d, Held By %d", - Semaphore.SemProcessID, SemHeldByAPI); - - Semaphore.Flag = 0; - } - - LastSemGets = Semaphore.Gets; - - Sleep(30000); -// Debugprintf("Monitor Thread Still going %d %d %d %x %d", LastSemGets, Semaphore.Gets, Semaphore.Flag, Semaphore.SemThreadID, SemHeldByAPI); - - } - while (TRUE); -} - - - - -VOID TIMERINTERRUPT(); - -BOOL Start(); -VOID INITIALISEPORTS(); -Dll BOOL APIENTRY Init_APRS(); -VOID APRSClose(); -Dll VOID APIENTRY Poll_APRS(); -VOID HTTPTimer(); - - -#define CKernel -#include "Versions.h" - -extern struct SEM Semaphore; - -int SemHeldByAPI = 0; -BOOL IGateEnabled = TRUE; -BOOL APRSActive = FALSE; -BOOL ReconfigFlag = FALSE; -BOOL APRSReconfigFlag = FALSE; -BOOL RigReconfigFlag = FALSE; - -BOOL IPActive = FALSE; -extern BOOL IPRequired; - -extern struct WL2KInfo * WL2KReports; - -int InitDone; -char pgm[256] = "LINBPQ"; - -char SESSIONHDDR[80] = ""; -int SESSHDDRLEN = 0; - - -// Next 3 should be uninitialised so they are local to each process - -UCHAR MCOM; -UCHAR MUIONLY; -UCHAR MTX; -uint64_t MMASK; - - -UCHAR AuthorisedProgram; // Local Variable. Set if Program is on secure list - -int SAVEPORT = 0; - -VOID SetApplPorts(); - -char VersionString[50] = Verstring; -char VersionStringWithBuild[50]=Verstring; -int Ver[4] = {Vers}; -char TextVerstring[50] = Verstring; - -extern UCHAR PWLen; -extern char PWTEXT[]; -extern int ISPort; - -extern char ChatConfigName[250]; - -BOOL EventsEnabled = 0; - -UCHAR * GetBPQDirectory() -{ - return BPQDirectory; -} -UCHAR * GetLogDirectory() -{ - return LogDirectory; -} -extern int POP3Timer; - -// Console Terminal Stuff - -#ifndef WIN32 - -#define _getch getchar - -/** - Linux (POSIX) implementation of _kbhit(). - Morgan McGuire, morgan@cs.brown.edu - */ - -#include -#include -#include -//#include - -int _kbhit() { - static const int STDIN = 0; - static int initialized = 0; - - if (! initialized) { - // Use termios to turn off line buffering - struct termios term; - tcgetattr(STDIN, &term); - term.c_lflag &= ~ICANON; - - tcsetattr(STDIN, TCSANOW, &term); - setbuf(stdin, NULL); - initialized = 1; - } - - int bytesWaiting; - ioctl(STDIN, FIONREAD, &bytesWaiting); - return bytesWaiting; -} - -#endif - -void ConTermInput(char * Msg) -{ - int i; - - if (ConTerm.BPQStream == 0) - { - ConTerm.BPQStream = FindFreeStream(); - - if (ConTerm.BPQStream == 255) - { - ConTerm.BPQStream = 0; - printf("No Free Streams\n"); - return; - } - } - - if (!ConTerm.CONNECTED) - SessionControl(ConTerm.BPQStream, 1, 0); - - ConTerm.StackIndex = 0; - - // Stack it - - if (ConTerm.KbdStack[19]) - free(ConTerm.KbdStack[19]); - - for (i = 18; i >= 0; i--) - { - ConTerm.KbdStack[i+1] = ConTerm.KbdStack[i]; - } - - ConTerm.KbdStack[0] = _strdup(ConTerm.kbbuf); - - ConTerm.kbbuf[ConTerm.kbptr]=13; - - SendMsg(ConTerm.BPQStream, ConTerm.kbbuf, ConTerm.kbptr+1); -} - -void ConTermPoll() -{ - int port, sesstype, paclen, maxframe, l4window, len; - int state, change, InputLen, count; - char callsign[11] = ""; - char Msg[300]; - - // Get current Session State. Any state changed is ACK'ed - // automatically. See BPQHOST functions 4 and 5. - - SessionState(ConTerm.BPQStream, &state, &change); - - if (change == 1) - { - if (state == 1) - { - // Connected - - ConTerm.CONNECTED = TRUE; - ConTerm.SlowTimer = 0; - } - else - { - ConTerm.CONNECTED = FALSE; - printf("*** Disconnected\n"); - } - } - - GetMsg(ConTerm.BPQStream, Msg, &InputLen, &count); - - if (InputLen) - { - char * ptr = Msg; - char * ptr2 = ptr; - Msg[InputLen] = 0; - - while (ptr) - { - ptr2 = strlop(ptr, 13); - - // Replace CR with CRLF - - printf(ptr); - - if (ptr2) - printf("\r\n"); - - ptr = ptr2; - } - } - - if (_kbhit()) - { - unsigned char c = _getch(); - - if (c == 0xe0) - { - // Cursor control - - c = _getch(); - - if (c == 75) // cursor left - c = 8; - } - -#ifdef WIN32 - printf("%c", c); -#endif - if (c == 8) - { - if (ConTerm.kbptr) - ConTerm.kbptr--; - printf(" \b"); // Already echoed bs - clear typed char from screen - return; - } - - if (c == 13 || c == 10) - { - ConTermInput(ConTerm.kbbuf); - ConTerm.kbptr = 0; - return; - } - - ConTerm.kbbuf[ConTerm.kbptr++] = c; - fflush(NULL); - - } - - return; - -} - - -int Redirected = 0; - -int main(int argc, char * argv[]) -{ - int i; - struct UserInfo * user = NULL; - ConnectionInfo * conn; - struct stat STAT; - PEXTPORTDATA PORTVEC; - UCHAR LogDir[260]; - -#ifdef WIN32 - - WSADATA WsaData; // receives data from WSAStartup - HWND hWnd = GetForegroundWindow(); - - WSAStartup(MAKEWORD(2, 0), &WsaData); - SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); - - // disable the [x] button. - - if (hWnd != NULL) - { - HMENU hMenu = GetSystemMenu(hWnd, 0); - if (hMenu != NULL) - { - DeleteMenu(hMenu, SC_CLOSE, MF_BYCOMMAND); - DrawMenuBar(hWnd); - } - } - -#else - setlinebuf(stdout); - struct sigaction act; - openlog("LINBPQ", LOG_PID, LOG_DAEMON); -#ifndef MACBPQ -#ifndef FREEBSD - prctl(PR_SET_DUMPABLE, 1); // Enable Core Dumps even with setcap -#endif -#endif - - // Disable Console Terminal if stdout redirected - - if (!isatty(STDOUT_FILENO)) - Redirected = 1; - -#endif - - printf("G8BPQ AX25 Packet Switch System Version %s %s\n", TextVerstring, Datestring); - printf("%s\n", VerCopyright); - - if (argc > 1 && _stricmp(argv[1], "-v") == 0) - return 0; - - sprintf(RlineVer, "LinBPQ%d.%d.%d", Ver[0], Ver[1], Ver[2]); - - - Debugprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring); - -#ifndef MACBPQ - _MYTIMEZONE = _timezone; -#endif - - if (_MYTIMEZONE < -86400 || _MYTIMEZONE > 86400) - _MYTIMEZONE = 0; - -#ifdef WIN32 - GetCurrentDirectory(256, BPQDirectory); - GetCurrentDirectory(256, LogDirectory); -#else - getcwd(BPQDirectory, 256); - getcwd(LogDirectory, 256); -#endif - Consoleprintf("Current Directory is %s\n", BPQDirectory); - - for (i = 1; i < argc; i++) - { - if (_memicmp(argv[i], "logdir=", 7) == 0) - { - strcpy(LogDirectory, &argv[i][7]); - break; - } - } - - - // Make sure logs directory exists - - sprintf(LogDir, "%s/logs", LogDirectory); - -#ifdef WIN32 - CreateDirectory(LogDir, NULL); -#else - mkdir(LogDir, S_IRWXU | S_IRWXG | S_IRWXO); - chmod(LogDir, S_IRWXU | S_IRWXG | S_IRWXO); -#endif - - if (!ProcessConfig()) - { - WritetoConsoleLocal("Configuration File Error\n"); - return (0); - } - - SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for Linux (", TextVerstring); - -#ifdef MACBPQ - SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for MAC (", TextVerstring); -#endif -#ifdef FREEBSD - SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for FreeBSD (", TextVerstring); -#endif - - - GetSemaphore(&Semaphore, 0); - - if (Start() != 0) - { - FreeSemaphore(&Semaphore); - return (0); - } - - for (i=0;PWTEXT[i] > 0x20;i++); //Scan for cr or null - - PWLen=i; - - SetApplPorts(); - - GetUIConfig(); - - INITIALISEPORTS(); - - if (IPRequired) IPActive = Init_IP(); - - APRSActive = Init_APRS(); - - if (ISPort == 0) - IGateEnabled = 0; - - if (needAIS) - initAIS(); - - RigActive = Rig_Init(); - - FreeSemaphore(&Semaphore); - - OpenReportingSockets(); - - initUTF8(); - - InitDone = TRUE; - - Debugprintf("Monitor Thread ID %x", _beginthread(MonitorThread, 0, 0)); - - -#ifdef WIN32 -#else - openlog("LINBPQ", LOG_PID, LOG_DAEMON); - - memset (&act, '\0', sizeof(act)); - - act.sa_handler = &sigint_handler; - if (sigaction(SIGINT, &act, NULL) < 0) - perror ("SIGINT"); - - act.sa_handler = &sigterm_handler; - if (sigaction(SIGTERM, &act, NULL) < 0) - perror ("sigaction"); - - act.sa_handler = SIG_IGN; - if (sigaction(SIGHUP, &act, NULL) < 0) - perror ("SIGHUP"); - - if (sigaction(SIGPIPE, &act, NULL) < 0) - perror ("SIGPIPE"); - -#endif - - for (i = 1; i < argc; i++) - { - if (_stricmp(argv[i], "chat") == 0) - IncludesChat = TRUE; - } - - if (IncludesChat) - { - RunChat = TRUE; - - printf("Starting Chat\n"); - - sprintf (ChatConfigName, "%s/chatconfig.cfg", BPQDirectory); - printf("Config File is %s\n", ChatConfigName); - - if (stat(ChatConfigName, &STAT) == -1) - { - printf("Chat Config File not found - creating a default config\n"); - ChatApplNum = 2; - MaxChatStreams = 10; - SaveChatConfigFile(ChatConfigName); - } - - if (GetChatConfig(ChatConfigName) == EXIT_FAILURE) - { - printf("Chat Config File seems corrupt - check before continuing\n"); - return -1; - } - - if (ChatApplNum) - { - if (ChatInit() == 0) - { - printf("Chat Init Failed\n"); - RunChat = 0; - } - else - { - printf("Chat Started\n"); - } - } - else - { - printf("Chat APPLNUM not defined\n"); - RunChat = 0; - } - CopyConfigFile(ChatConfigName); - } - - // Start Mail if requested by command line or config - - for (i = 1; i < argc; i++) - { - if (_stricmp(argv[i], "mail") == 0) - IncludesMail = TRUE; - } - - - if (IncludesMail) - { - RunMail = TRUE; - - printf("Starting Mail\n"); - - sprintf (ConfigName, "%s/linmail.cfg", BPQDirectory); - printf("Config File is %s\n", ConfigName); - - if (stat(ConfigName, &STAT) == -1) - { - printf("Config File not found - creating a default config\n"); - strcpy(BBSName, MYNODECALL); - strlop(BBSName, '-'); - strlop(BBSName, ' '); - BBSApplNum = 1; - MaxStreams = 10; - SaveConfig(ConfigName); - } - - if (GetConfig(ConfigName) == EXIT_FAILURE) - { - printf("BBS Config File seems corrupt - check before continuing\n"); - return -1; - } - - printf("Config Processed\n"); - - BBSApplMask = 1<<(BBSApplNum-1); - - // See if we need to warn of possible problem with BaseDir moved by installer - - sprintf(BaseDir, "%s", BPQDirectory); - - - // 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"); - -#ifdef WIN32 - CreateDirectory(MailDir, NULL); // Just in case -#else - mkdir(MailDir, S_IRWXU | S_IRWXG | S_IRWXO); - chmod(MailDir, S_IRWXU | S_IRWXG | S_IRWXO); -#endif - - // Make backup copies of Databases - -// CopyConfigFile(ConfigName); - - CopyBIDDatabase(); - CopyMessageDatabase(); - CopyUserDatabase(); - CopyWPDatabase(); - - SetupMyHA(); - SetupFwdAliases(); - SetupNTSAliases(NTSAliasesPath); - - GetWPDatabase(); - - GetMessageDatabase(); - GetUserDatabase(); - GetBIDDatabase(); - GetBadWordFile(); - GetHTMLForms(); - - // 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(); - } - - - // Make sure SYSOPCALL is set - - if (SYSOPCall[0] == 0) - strcpy(SYSOPCall, BBSName); - - // See if just want to add user (mainly for setup scripts) - - if (argc == 5 && _stricmp(argv[1], "--adduser") == 0) - { - BOOL isBBS = FALSE; - char * response; - - if (_stricmp(argv[4], "TRUE") == 0) - isBBS = TRUE; - - printf("Adding User %s\r\n", argv[2]); - response = AddUser(argv[2], argv[3], isBBS); - printf("%s", response); - exit(0); - } - // Allocate Streams - - strcpy(pgm, "BBS"); - - 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); - Disconnect(conn->BPQStream); - } - - strcpy(pgm, "LINBPQ"); - - Debugprintf("POP3 Debug Before Init TCP Timer = %d", POP3Timer); - - InitialiseTCP(); - Debugprintf("POP3 Debug Before Init NNTP Timer = %d", POP3Timer); - InitialiseNNTP(); - - SetupListenSet(); // Master set of listening sockets - - if (EnableUI || MailForInterval) - SetupUIInterface(); - - if (MailForInterval) - _beginthread(SendMailForThread, 0, 0); - - - // 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 = mktime(tm) - (time_t)_MYTIMEZONE; - - 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); - } - } - for (i = 1; i < argc; i++) - { - if (_stricmp(argv[i], "tidymail") == 0) - DeleteRedundantMessages(); - - if (_stricmp(argv[i], "nohomebbs") == 0) - DontNeedHomeBBS = TRUE; - } - - printf("Mail Started\n"); - Logprintf(LOG_BBS, NULL, '!', "Mail Starting"); - - } - } - - Debugprintf("POP3 Debug After Mail Init Timer = %d", POP3Timer); - - if (NUMBEROFTNCPORTS) - InitializeTNCEmulator(); - - AGWActive = AGWAPIInit(); - -#ifndef WIN32 - - for (i = 1; i < argc; i++) - { - if (_stricmp(argv[i], "daemon") == 0) - { - - // Convert to daemon - - pid_t pid, sid; - - /* Fork off the parent process */ - pid = fork(); - - if (pid < 0) - exit(EXIT_FAILURE); - - if (pid > 0) - exit(EXIT_SUCCESS); - - /* Change the file mode mask */ - - umask(0); - - /* Create a new SID for the child process */ - - sid = setsid(); - - if (sid < 0) - exit(EXIT_FAILURE); - - /* Change the current working directory */ - - if ((chdir("/")) < 0) - exit(EXIT_FAILURE); - - /* Close out the standard file descriptors */ - - printf("Entering daemon mode\n"); - - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - break; - } - } -#endif - - while (KEEPGOING) - { - Sleep(100); - GetSemaphore(&Semaphore, 2); - - if (QCOUNT < 10) - { - if (CLOSING == FALSE) - FindLostBuffers(); - CLOSING = TRUE; - } - - if (CLOSING) - { - if (RunChat) - { - CloseChat(); - RunChat = FALSE; - } - - if (RunMail) - { - int BPQStream, n; - - RunMail = FALSE; - - for (n = 0; n < NumberofStreams; n++) - { - BPQStream = Connections[n].BPQStream; - - if (BPQStream) - { - SetAppl(BPQStream, 0, 0); - Disconnect(BPQStream); - DeallocateStream(BPQStream); - } - } - -// SaveUserDatabase(); - SaveMessageDatabase(); - SaveBIDDatabase(); - SaveConfig(ConfigName); - } - - KEEPGOING--; // Give time for links to close - setbuf(stdout, NULL); - printf("Closing... %d \r", KEEPGOING); - } - - - if (RigReconfigFlag) - { - RigReconfigFlag = FALSE; - Rig_Close(); - Sleep(2000); // Allow CATPTT threads to close - RigActive = Rig_Init(); - - Consoleprintf("Rigcontrol Reconfiguration Complete"); - } - - if (APRSReconfigFlag) - { - APRSReconfigFlag = FALSE; - APRSClose(); - APRSActive = Init_APRS(); - - Consoleprintf("APRS Reconfiguration Complete"); - } - - if (ReconfigFlag) - { - int i; - BPQVECSTRUC * HOSTVEC; - PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE; - - ReconfigFlag = FALSE; - -// SetupBPQDirectory(); - - WritetoConsoleLocal("Reconfiguring ...\n\n"); - OutputDebugString("BPQ32 Reconfiguring ...\n"); - - - for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External - { - if (PORTVEC->PORT_EXT_ADDR) - { -// SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); -// SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER); -// CloseDriverWindow(PORTVEC->PORTCONTROL.PORTNUMBER); - PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL); // Close External Ports - } - } - PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL); - PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER; - } - - IPClose(); - APRSClose(); - Rig_Close(); - CloseTNCEmulator(); - - if (AGWActive) - AGWAPITerminate(); - - WL2KReports = NULL; - -// Sleep(2000); - - Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring); - Consoleprintf(VerCopyright); - - Start(); - - INITIALISEPORTS(); - - SetApplPorts(); - - GetUIConfig(); - - FreeConfig(); - - for (i=1; i<68; i++) // Include Telnet, APRS, IP Vec - { - HOSTVEC=&BPQHOSTVECTOR[i-1]; - - HOSTVEC->HOSTTRACEQ=0; - - if (HOSTVEC->HOSTSESSION !=0) - { - // Had a connection - - HOSTVEC->HOSTSESSION=0; - HOSTVEC->HOSTFLAGS |=3; // Disconnected - -// PostMessage(HOSTVEC->HOSTHANDLE, BPQMsg, i, 4); - } - } - - OpenReportingSockets(); - - WritetoConsoleLocal("\n\nReconfiguration Complete\n"); - - if (IPRequired) IPActive = Init_IP(); - - APRSActive = Init_APRS(); - - if (ISPort == 0) - IGateEnabled = 0; - - RigActive = Rig_Init(); - - if (NUMBEROFTNCPORTS) - { - FreeSemaphore(&Semaphore); - InitializeTNCEmulator(); - GetSemaphore(&Semaphore, 2); - } - - FreeSemaphore(&Semaphore); - AGWActive = AGWAPIInit(); - GetSemaphore(&Semaphore, 2); - - OutputDebugString("BPQ32 Reconfiguration Complete\n"); - } - - if (IPActive) Poll_IP(); - if (RigActive) Rig_Poll(); - if (APRSActive) Poll_APRS(); - CheckWL2KReportTimer(); - - TIMERINTERRUPT(); - - FreeSemaphore(&Semaphore); - - if (Redirected == 0) - ConTermPoll(); - - if (NUMBEROFTNCPORTS) - TNCTimer(); - - if (AGWActive) - Poll_AGW(); - - DRATSPoll(); - - HTTPTimer(); - - if (ReportTimer) - { - ReportTimer--; - - if (ReportTimer == 0) - { - ReportTimer = REPORTINTERVAL; - SendLocation(); - } - } - - Slowtimer++; - - if (RunChat) - { - ChatPollStreams(); - ChatTrytoSend(); - - if (Slowtimer > 100) // 10 secs - { - ChatTimer(); - } - } - - if (RunMail) - { - PollStreams(); - - if (Slowtimer > 100) // 10 secs - { - time_t NOW = time(NULL); - struct tm * tm; - - TCPTimer(); - FWDTimerProc(); - BBSSlowTimer(); - - 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) - { - LastTrafficTime = NOW; - CreateBBSTrafficReport(); - } - } - } - TCPFastTimer(); - TrytoSend(); - } - - if (Slowtimer > 100) - Slowtimer = 0; - } - - printf("Closing Ports\n"); - - CloseTNCEmulator(); - - if (AGWActive) - AGWAPITerminate(); - - if (needAIS) - SaveAIS(); - - // Close Ports - - PORTVEC=(PEXTPORTDATA)PORTTABLE; - - for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External - { - if (PORTVEC->PORT_EXT_ADDR) - { - PORTVEC->PORT_EXT_ADDR(5, PORTVEC->PORTCONTROL.PORTNUMBER, NULL); - } - } - PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER; - } - - if (AUTOSAVE) - SaveNodes(); - - if (AUTOSAVEMH) - SaveMH(); - - if (IPActive) - IPClose(); - - if (RunMail) - FreeWebMailMallocs(); - - upnpClose(); - - // Close any open logs - - for (i = 0; i < 4; i++) - { - if (LogHandle[i]) - fclose(LogHandle[i]); - } - - return 0; -} - -int APIENTRY WritetoConsole(char * buff) -{ - return WritetoConsoleLocal(buff); -} - -int WritetoConsoleLocal(char * buff) -{ - return printf("%s", buff); -} - -#ifdef WIN32 -void * VCOMExtInit(struct PORTCONTROL * PortEntry); -void * V4ExtInit(EXTPORTDATA * PortEntry); -#endif -//UINT SoundModemExtInit(EXTPORTDATA * PortEntry); -//UINT BaycomExtInit(EXTPORTDATA * PortEntry); - -void * AEAExtInit(struct PORTCONTROL * PortEntry); -void * MPSKExtInit(EXTPORTDATA * PortEntry); -void * HALExtInit(struct PORTCONTROL * PortEntry); - -void * AGWExtInit(struct PORTCONTROL * PortEntry); -void * KAMExtInit(struct PORTCONTROL * PortEntry); -void * WinmorExtInit(EXTPORTDATA * PortEntry); -void * SCSExtInit(struct PORTCONTROL * PortEntry); -void * TrackerExtInit(EXTPORTDATA * PortEntry); -void * TrackerMExtInit(EXTPORTDATA * PortEntry); - -void * TelnetExtInit(EXTPORTDATA * PortEntry); -void * UZ7HOExtInit(EXTPORTDATA * PortEntry); -void * FLDigiExtInit(EXTPORTDATA * PortEntry); -void * ETHERExtInit(struct PORTCONTROL * PortEntry); -void * AXIPExtInit(struct PORTCONTROL * PortEntry); -void * ARDOPExtInit(EXTPORTDATA * PortEntry); -void * VARAExtInit(EXTPORTDATA * PortEntry); -void * SerialExtInit(EXTPORTDATA * PortEntry); -void * WinRPRExtInit(EXTPORTDATA * PortEntry); -void * HSMODEMExtInit(EXTPORTDATA * PortEntry); -void * FreeDataExtInit(EXTPORTDATA * PortEntry); -void * KISSHFExtInit(EXTPORTDATA * PortEntry); - -void * InitializeExtDriver(PEXTPORTDATA PORTVEC) -{ - // Only works with built in drivers - - UCHAR Value[20]; - - strcpy(Value,PORTVEC->PORT_DLL_NAME); - - _strupr(Value); - -#ifndef FREEBSD -#ifndef MACBPQ - if (strstr(Value, "BPQETHER")) - return ETHERExtInit; -#endif -#endif - if (strstr(Value, "BPQAXIP")) - return AXIPExtInit; - - if (strstr(Value, "BPQTOAGW")) - return AGWExtInit; - - if (strstr(Value, "AEAPACTOR")) - return AEAExtInit; - - if (strstr(Value, "HALDRIVER")) - return HALExtInit; - -#ifdef WIN32 - - if (strstr(Value, "BPQVKISS")) - return VCOMExtInit; - - if (strstr(Value, "V4")) - return V4ExtInit; - -#endif -/* - if (strstr(Value, "SOUNDMODEM")) - return (UINT) SoundModemExtInit; - - if (strstr(Value, "BAYCOM")) - return (UINT) BaycomExtInit; -*/ - if (strstr(Value, "MULTIPSK")) - return MPSKExtInit; - - if (strstr(Value, "KAMPACTOR")) - return KAMExtInit; - - if (strstr(Value, "WINMOR")) - return WinmorExtInit; - - if (strstr(Value, "SCSPACTOR")) - return SCSExtInit; - - if (strstr(Value, "SCSTRACKER")) - return TrackerExtInit; - - if (strstr(Value, "TRKMULTI")) - return TrackerMExtInit; - - if (strstr(Value, "UZ7HO")) - return UZ7HOExtInit; - - if (strstr(Value, "FLDIGI")) - return FLDigiExtInit; - - if (strstr(Value, "TELNET")) - return TelnetExtInit; - - if (strstr(Value, "ARDOP")) - return ARDOPExtInit; - - if (strstr(Value, "VARA")) - return VARAExtInit; - - if (strstr(Value, "KISSHF")) - return KISSHFExtInit; - - if (strstr(Value, "SERIAL")) - return SerialExtInit; - - if (strstr(Value, "WINRPR")) - return WinRPRExtInit; - - if (strstr(Value, "HSMODEM")) - return HSMODEMExtInit; - - if (strstr(Value, "FREEDATA")) - return FreeDataExtInit; - - return(0); -} - -int APIENTRY Restart() -{ - CLOSING = TRUE; - return TRUE; -} - -int APIENTRY Reboot() -{ - // Run sudo shutdown -r -f -#ifdef WIN32 - STARTUPINFO SInfo; - PROCESS_INFORMATION PInfo; - char Cmd[] = "shutdown -r -f"; - - - SInfo.cb=sizeof(SInfo); - SInfo.lpReserved=NULL; - SInfo.lpDesktop=NULL; - SInfo.lpTitle=NULL; - SInfo.dwFlags=0; - SInfo.cbReserved2=0; - SInfo.lpReserved2=NULL; - - return CreateProcess(NULL, Cmd, NULL, NULL, FALSE,0 ,NULL ,NULL, &SInfo, &PInfo); - return 0; -#else - - char * arg_list[] = {NULL, NULL, NULL, NULL, NULL}; - pid_t child_pid; - char * Context; - signal(SIGCHLD, SIG_IGN); // Silently (and portably) reap children. - - arg_list[0] = "sudo"; - arg_list[1] = "shutdown"; - arg_list[2] = "now"; - arg_list[3] = "-r"; - - // Fork and Exec shutdown - - // Duplicate this process. - - child_pid = fork(); - - if (child_pid == -1) - { - printf ("Reboot fork() Failed\n"); - return 0; - } - - if (child_pid == 0) - { - execvp (arg_list[0], arg_list); - - /* The execvp function returns only if an error occurs. */ - - printf ("Failed to run shutdown\n"); - exit(0); // Kill the new process - } - return TRUE; -#endif - -} - -int APIENTRY Reconfig() -{ - if (!ProcessConfig()) - { - return (0); - } - SaveNodes(); - WritetoConsoleLocal("Nodes Saved\n"); - ReconfigFlag=TRUE; - WritetoConsoleLocal("Reconfig requested ... Waiting for Timer Poll\n"); - return 1; -} - -int APRSWriteLog(char * msg); - -VOID MonitorAPRSIS(char * Msg, size_t MsgLen, BOOL TX) -{ - char Line[300]; - char Copy[300]; - int Len; - struct tm * TM; - time_t NOW; - - if (LogAPRSIS == 0) - return; - - if (MsgLen > 250) - return; - - // Mustn't change Msg - - memcpy(Copy, Msg, MsgLen); - Copy[MsgLen] = 0; - - NOW = time(NULL); - TM = gmtime(&NOW); - - Len = sprintf_s(Line, 299, "%02d:%02d:%02d%c %s", TM->tm_hour, TM->tm_min, TM->tm_sec, (TX)? 'T': 'R', Copy); - - APRSWriteLog(Line); - -} - -struct TNCINFO * TNC; - -#ifndef WIN32 - -#include -#include - -#ifndef MACBPQ -#ifdef __MACH__ - -#include - -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 0 - -int clock_gettime(int clk_id, struct timespec *t){ - mach_timebase_info_data_t timebase; - mach_timebase_info(&timebase); - uint64_t time; - time = mach_absolute_time(); - double nseconds = ((double)time * (double)timebase.numer)/((double)timebase.denom); - double seconds = ((double)time * (double)timebase.numer)/((double)timebase.denom * 1e9); - t->tv_sec = seconds; - t->tv_nsec = nseconds; - return 0; -} -#endif -#endif - -int GetTickCount() -{ - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); -} - - - -void SetWindowText(HWND hWnd, char * lpString) -{ - return; -}; - -BOOL SetDlgItemText(HWND hWnd, int item, char * lpString) -{ - return 0; -}; - -#endif - -int GetListeningPortsPID(int Port) -{ -#ifdef WIN32 - - MIB_TCPTABLE_OWNER_PID * TcpTable = NULL; - PMIB_TCPROW_OWNER_PID Row; - int dwSize = 0; - unsigned int n; - - // Get PID of process for this TCP Port - - // Get Length of table - - GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0); - - TcpTable = malloc(dwSize); - GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0); - - for (n = 0; n < TcpTable->dwNumEntries; n++) - { - Row = &TcpTable->table[n]; - - if (Row->dwLocalPort == Port && Row->dwState == MIB_TCP_STATE_LISTEN) - { - return Row->dwOwningPid; - break; - } - } -#endif - return 0; // Not found -} - - - -VOID Check_Timer() -{ -} - -VOID POSTDATAAVAIL(){}; - -COLORREF Colours[256] = {0, - RGB(0,0,0), RGB(0,0,128), RGB(0,0,192), RGB(0,0,255), // 1 - 4 - RGB(0,64,0), RGB(0,64,128), RGB(0,64,192), RGB(0,64,255), // 5 - 8 - RGB(0,128,0), RGB(0,128,128), RGB(0,128,192), RGB(0,128,255), // 9 - 12 - RGB(0,192,0), RGB(0,192,128), RGB(0,192,192), RGB(0,192,255), // 13 - 16 - RGB(0,255,0), RGB(0,255,128), RGB(0,255,192), RGB(0,255,255), // 17 - 20 - - RGB(6425,0,0), RGB(64,0,128), RGB(64,0,192), RGB(0,0,255), // 21 - RGB(64,64,0), RGB(64,64,128), RGB(64,64,192), RGB(64,64,255), - RGB(64,128,0), RGB(64,128,128), RGB(64,128,192), RGB(64,128,255), - RGB(64,192,0), RGB(64,192,128), RGB(64,192,192), RGB(64,192,255), - RGB(64,255,0), RGB(64,255,128), RGB(64,255,192), RGB(64,255,255), - - RGB(128,0,0), RGB(128,0,128), RGB(128,0,192), RGB(128,0,255), // 41 - RGB(128,64,0), RGB(128,64,128), RGB(128,64,192), RGB(128,64,255), - RGB(128,128,0), RGB(128,128,128), RGB(128,128,192), RGB(128,128,255), - RGB(128,192,0), RGB(128,192,128), RGB(128,192,192), RGB(128,192,255), - RGB(128,255,0), RGB(128,255,128), RGB(128,255,192), RGB(128,255,255), - - RGB(192,0,0), RGB(192,0,128), RGB(192,0,192), RGB(192,0,255), // 61 - RGB(192,64,0), RGB(192,64,128), RGB(192,64,192), RGB(192,64,255), - RGB(192,128,0), RGB(192,128,128), RGB(192,128,192), RGB(192,128,255), - RGB(192,192,0), RGB(192,192,128), RGB(192,192,192), RGB(192,192,255), - RGB(192,255,0), RGB(192,255,128), RGB(192,255,192), RGB(192,255,255), - - RGB(255,0,0), RGB(255,0,128), RGB(255,0,192), RGB(255,0,255), // 81 - RGB(255,64,0), RGB(255,64,128), RGB(255,64,192), RGB(255,64,255), - RGB(255,128,0), RGB(255,128,128), RGB(255,128,192), RGB(255,128,255), - RGB(255,192,0), RGB(255,192,128), RGB(255,192,192), RGB(255,192,255), - RGB(255,255,0), RGB(255,255,128), RGB(255,255,192), RGB(255,255,255) -}; - - -//VOID SendRPBeacon(struct TNCINFO * TNC) -//{ -//} - -int PollStreams() -{ - int state,change; - ConnectionInfo * conn; - int n; - struct UserInfo * user = NULL; - char ConnectedMsg[] = "*** CONNECTED "; - - for (n = 0; n < NumberofStreams; n++) - { - conn = &Connections[n]; - - DoReceivedData(conn->BPQStream); - DoBBSMonitorData(conn->BPQStream); - - SessionState(conn->BPQStream, &state, &change); - - if (change == 1) - { - if (state == 1) // Connected - { - GetSemaphore(&ConSemaphore, 0); - Connected(conn->BPQStream); - FreeSemaphore(&ConSemaphore); - } - else - { - GetSemaphore(&ConSemaphore, 0); - Disconnected(conn->BPQStream); - FreeSemaphore(&ConSemaphore); - } - } - } - - return 0; -} - - -VOID CloseConsole(int Stream) -{ -} - -#ifndef WIN32 - -int V4ProcessReceivedData(struct TNCINFO * TNC) -{ - return 0; -} -#endif - -#ifdef FREEBSD - -char * gcvt(double _Val, int _NumOfDigits, char * _DstBuf) -{ - sprintf(_DstBuf, "%f", _Val); - return _DstBuf; -} - -#endif - - - - - diff --git a/MCP2221.vcproj.DESKTOP-TGEL8RC.John.user b/MCP2221.vcproj.DESKTOP-TGEL8RC.John.user deleted file mode 100644 index 40182c4..0000000 --- a/MCP2221.vcproj.DESKTOP-TGEL8RC.John.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/MailNode.ncb b/MailNode.ncb deleted file mode 100644 index 233beff..0000000 Binary files a/MailNode.ncb and /dev/null differ diff --git a/MailNode.vcproj.DESKTOP-MHE5LO8.johnw.user b/MailNode.vcproj.DESKTOP-MHE5LO8.johnw.user deleted file mode 100644 index f8980b0..0000000 --- a/MailNode.vcproj.DESKTOP-MHE5LO8.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/MailNode.vcproj.DESKTOP-TGEL8RC.John.user b/MailNode.vcproj.DESKTOP-TGEL8RC.John.user deleted file mode 100644 index 137b905..0000000 --- a/MailNode.vcproj.DESKTOP-TGEL8RC.John.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/MailNode.vcproj.HPLAPTOP.johnw.user b/MailNode.vcproj.HPLAPTOP.johnw.user deleted file mode 100644 index f361c86..0000000 --- a/MailNode.vcproj.HPLAPTOP.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/MailNode.vcproj.SKIGACER.johnw.user b/MailNode.vcproj.SKIGACER.johnw.user deleted file mode 100644 index 7be11b6..0000000 --- a/MailNode.vcproj.SKIGACER.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/MailNode.vcxproj.user b/MailNode.vcxproj.user new file mode 100644 index 0000000..448994b --- /dev/null +++ b/MailNode.vcxproj.user @@ -0,0 +1,8 @@ + + + + C:\Dev\Msdev2005\projects\bpq32\BPQMail\x64\Debug\LinBPQ.exe + c:\linbpq + WindowsLocalDebugger + + \ No newline at end of file diff --git a/MailTCP-DESKTOP-MHE5LO8.c b/MailTCP-DESKTOP-MHE5LO8.c deleted file mode 100644 index b26f6da..0000000 --- a/MailTCP-DESKTOP-MHE5LO8.c +++ /dev/null @@ -1,4127 +0,0 @@ -/* -Copyright 2001-2018 John Wiseman G8BPQ - -This file is part of LinBPQ/BPQ32. - -LinBPQ/BPQ32 is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -LinBPQ/BPQ32 is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses -*/ - -// Mail and Chat Server for BPQ32 Packet Switch -// -// TCP access module - POP and SMTP - -#include "bpqmail.h" - -VOID ReleaseSock(SOCKET sock); -void Base64EncodeAndSend(SocketConn * sockptr, UCHAR * Msg, int Len); - -#define MaxSockets 64 - -SocketConn * Sockets = NULL; - -int CurrentConnections; - -int CurrentSockets=0; - -#define MAX_PENDING_CONNECTS 4 - -#define VERSION_MAJOR 2 -#define VERSION_MINOR 0 - -static SOCKADDR_IN local_sin; /* Local socket - internet style */ -static PSOCKADDR_IN psin; - -SOCKET smtpsock, pop3sock; - -char szBuff[80]; - -int SMTPInPort; -int POP3InPort; - -BOOL RemoteEmail; // Set to listen on INADDR_ANY rather than LOCALHOST - -BOOL ISP_Gateway_Enabled; - -char MyDomain[50]; // Mail domain for BBS<>Internet Mapping - -char ISPSMTPName[50]; -char ISPEHLOName[50] = ""; - -int ISPSMTPPort; - -char ISPPOP3Name[50]; -int ISPPOP3Port; - -char ISPAccountName[50]; -char ISPAccountPass[50]; -char EncryptedISPAccountPass[100]; -int EncryptedPassLen; - -BOOL SMTPAuthNeeded; - -BOOL GMailMode = FALSE; -char GMailName[50]; - -int POP3Timer=9999; // Run on startup -int ISPPOP3Interval; - -BOOL SMTPMsgCreated=FALSE; // Set to cause SMTP client to send messages to ISP -BOOL SMTPActive=FALSE; // SO we don't try every 10 secs! - -char mycd64[256]; -static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq"; - -char sockTypes[6][12] = {"Undefined", "SMTPServer", "POP3Server", "SMTPClient", "POP3Client", "NNTPServer"}; - -void decodeblock( unsigned char in[4], unsigned char out[3] ); -VOID FormatTime(char * Time, time_t cTime); -static int Socket_Accept(SOCKET SocketId); - -int SendSock(SocketConn * sockptr, char * msg) -{ - int len = (int)strlen(msg), sent; - char * newmsg = malloc(len+10); - - WriteLogLine(NULL, '>',msg, len, LOG_TCP); - - strcpy(newmsg, msg); - - strcat(newmsg, "\r\n"); - - len+=2; - - if (sockptr->SendBuffer) - { - // Already queued, so add to end - - if ((sockptr->SendSize + len) > sockptr->SendBufferSize) - { - sockptr->SendBufferSize += (10000 + len); - sockptr->SendBuffer = realloc(sockptr->SendBuffer, sockptr->SendBufferSize); - } - - memcpy(&sockptr->SendBuffer[sockptr->SendSize], newmsg, len); - sockptr->SendSize += len; - free (newmsg); - return len; - } - - sent = send(sockptr->socket, newmsg, len, 0); - - if (sent < len) - { - int error, remains; - - // Not all could be sent - queue rest - - if (sent == SOCKET_ERROR) - { - error = WSAGetLastError(); - if (error == WSAEWOULDBLOCK) - sent=0; - - // What else?? - } - - remains = len - sent; - - sockptr->SendBufferSize += (10000 + remains); - sockptr->SendBuffer = malloc(sockptr->SendBufferSize); - - memcpy(sockptr->SendBuffer, &newmsg[sent], remains); - - sockptr->SendSize = remains; - sockptr->SendPtr = 0; - - } - - free (newmsg); - - return sent; -} - -VOID __cdecl sockprintf(SocketConn * sockptr, const char * format, ...) -{ - // printf to a socket - - char buff[1000]; - va_list(arglist); - - va_start(arglist, format); - vsprintf(buff, format, arglist); - - SendSock(sockptr, buff); -} - -extern int SMTPMsgs; - -fd_set ListenSet; -SOCKET ListenMax = 0; - -extern SOCKET nntpsock; - -int NNTP_Read(SocketConn * sockptr, SOCKET sock); - -VOID SetupListenSet() -{ - // Set up master set of fd's for checking for incoming calls - - fd_set * readfd = &ListenSet; - SOCKET sock; - - FD_ZERO(readfd); - - sock = nntpsock; - if (sock) - { - FD_SET(sock, readfd); - if (sock > ListenMax) - ListenMax = sock; - } - - sock = smtpsock; - if (sock) - { - FD_SET(sock, readfd); - if (sock > ListenMax) - ListenMax = sock; - } - - sock = pop3sock; - - if (sock) - { - FD_SET(sock, readfd); - if (sock > ListenMax) - ListenMax = sock; - } -} - -VOID Socket_Connected(SocketConn * sockptr, int error) -{ - SOCKET sock = sockptr->socket; - - if (error) - { - Logprintf(LOG_TCP, NULL, '|', "Connect Failed"); - - if (sockptr->Type == SMTPClient) - SMTPActive = FALSE; - - ReleaseSock(sock); - - return; - } - - sockptr->State = WaitingForGreeting; - - if (sockptr->Type == NNTPServer) - SendSock(sockptr, "200 BPQMail NNTP Server ready"); - - else if (sockptr->Type == SMTPServer) - SendSock(sockptr, "220 BPQMail SMTP Server ready"); - - else if (sockptr->Type == POP3SLAVE) - { - SendSock(sockptr, "+OK POP3 server ready"); - sockptr->State = GettingUser; - } -} - -VOID TCPFastTimer() -{ - // we now poll for incoming connections and data - - fd_set readfd, writefd, exceptfd; - struct timeval timeout; - int retval; - SocketConn * sockptr = Sockets; - SOCKET sock; - int Active = 0; - SOCKET maxsock; - - timeout.tv_sec = 0; - timeout.tv_usec = 0; // poll - - if (ListenMax) - { - memcpy(&readfd, &ListenSet, sizeof(fd_set)); - - retval = select((int)ListenMax + 1, &readfd, NULL, NULL, &timeout); - - if (retval == -1) - { - retval = 0; - perror("Listen select"); - } - - if (retval) - { - sock = pop3sock; - if (sock) - if (FD_ISSET(sock, &readfd)) - Socket_Accept(sock); - - sock = smtpsock; - if (sock) - if (FD_ISSET(sock, &readfd)) - Socket_Accept(sock); - - sock = nntpsock; - if (sock) - if (FD_ISSET(sock, &readfd)) - NNTP_Accept(sock); - } - } - - // look for data on any active sockets - - maxsock = 0; - - FD_ZERO(&readfd); - FD_ZERO(&writefd); - FD_ZERO(&exceptfd); - sockptr=Sockets; - - while (sockptr) - { - sockptr->Timeout++; - - if (sockptr->Timeout > 1200) // 2 mins - { - Logprintf(LOG_TCP, NULL, '|', "Timeout on Socket = %d", sockptr->socket); - shutdown(sockptr->socket, 0); - closesocket(sockptr->socket); - ReleaseSock(sockptr->socket); - - return; // We've messed with chain - } - - if (sockptr->State & Connecting) - { - // look for complete or failed - - FD_SET(sockptr->socket, &writefd); - FD_SET(sockptr->socket, &exceptfd); - } - else - FD_SET(sockptr->socket, &readfd); - - Active++; - - if (sockptr->socket > maxsock) - maxsock = sockptr->socket; - - sockptr = sockptr->Next; - } - - if (Active == 0) - return; - - retval = select((int)maxsock + 1, &readfd, &writefd, &exceptfd, &timeout); - - if (retval == -1) - { - perror("select"); - - // we need to do something or the error will recur. - // As there are unlikely to be a lot of open tcp connections perhaps - // simplest is to close all - - sockptr = Sockets; - - while (sockptr) - { - Debugprintf("MAILTCP Select Failed Active %s Socket", sockTypes[sockptr->Type]); - shutdown(sockptr->socket, 0); - closesocket(sockptr->socket); - ReleaseSock(sockptr->socket); - - sockptr = Sockets; // We've messed with chain - } - } - else - { - if (retval) - { - sockptr = Sockets; - - // see who has data - - while (sockptr) - { - sock = sockptr->socket; - - if (FD_ISSET(sock, &readfd)) - { - sockptr->Timeout = 0; - - if (sockptr->Type == NNTPServer) - { - if (NNTP_Read(sockptr, sock) == 0) - break; // We've messed with the chain - } - else - { - if (DataSocket_Read(sockptr, sock) == 0) - break; // We've messed with the chain - } - } - if (FD_ISSET(sockptr->socket, &writefd)) - Socket_Connected(sockptr, 0); - - if (FD_ISSET(sockptr->socket, &exceptfd)) - { - Socket_Connected(sockptr, 1); - return; - } - sockptr = sockptr->Next; - } - } - } -} - -VOID TCPTimer() -{ - POP3Timer+=10; - -// Debugprintf("POP3 Debug Timer = %d Interval = %d Port %d Enabled %d", -// POP3Timer, ISPPOP3Interval, ISPPOP3Port, ISP_Gateway_Enabled); - - if (POP3Timer > ISPPOP3Interval) // 5 mins - { - POP3Timer=0; - - if ((ISPSMTPPort && ISP_Gateway_Enabled)) - SendtoISP(); - - if (ISPPOP3Port && ISP_Gateway_Enabled) - { -// Debugprintf("Calling POP3 Connect"); - POP3Connect(ISPPOP3Name, ISPPOP3Port); - } - - if (SMTPMsgs && ISPSMTPPort && ISP_Gateway_Enabled) - SendtoISP(); - } - else - { - if (SMTPMsgCreated && ISPSMTPPort && ISP_Gateway_Enabled) - SendtoISP(); - } -} -BOOL InitialiseTCP() -{ - int Error; // catches return value of WSAStartup -#ifdef WIN32 - WORD VersionRequested; // passed to WSAStartup - WSADATA WsaData; // receives data from WSAStartup -#endif - int i,j; - - - for (i=0;i<64; i++) - { - j=cb64[i]; - mycd64[j]=i; - } - -#ifdef WIN32 - - VersionRequested = MAKEWORD(VERSION_MAJOR, VERSION_MINOR); - - Error = WSAStartup(VersionRequested, &WsaData); - - if (Error) - { -#ifndef LINBPQ - MessageBox(NULL, - "Could not find high enough version of WinSock", - "BPQMailChat", MB_OK | MB_ICONSTOP | MB_SETFOREGROUND); -#else - printf("Could not find high enough version of WinSock\n"); -#endif - return FALSE; - } - -#endif - -// Create listening sockets - - - if (SMTPInPort) - smtpsock = CreateListeningSocket(SMTPInPort); - - if (POP3InPort) - pop3sock = CreateListeningSocket(POP3InPort); - - if (ISP_Gateway_Enabled) - { - // See if using GMail - - char * ptr = strchr(ISPAccountName, '@'); - - if (ptr) - { - if (_stricmp(&ptr[1], "gmail.com") == 0 || _stricmp(&ptr[1], "googlemail.com") == 0) - { - strcpy(GMailName, ISPAccountName); - strlop(GMailName, '@'); - GMailMode = TRUE; - SMTPAuthNeeded = TRUE; - } - } - } - - return TRUE; - -} - - -SOCKET CreateListeningSocket(int Port) -{ - SOCKET sock; - unsigned int param = 1; - - sock = socket( AF_INET, SOCK_STREAM, 0); - - if (sock == INVALID_SOCKET) - { - sprintf(szBuff, "socket() failed error %d", WSAGetLastError()); -#ifdef LINBPQ - perror(szBuff); -#else - MessageBox(MainWnd, szBuff, "BPQMailChat", MB_OK); -#endif - return FALSE; - } - - setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *)¶m,4); - - psin=&local_sin; - - psin->sin_family = AF_INET; - psin->sin_addr.s_addr = htonl(RemoteEmail ? INADDR_ANY : INADDR_LOOPBACK); // Local Host Olny - - psin->sin_port = htons(Port); /* Convert to network ordering */ - - if (bind( sock, (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR) - { - sprintf(szBuff, "bind(%d) failed Error %d", Port, WSAGetLastError()); -#ifdef LINBPQ - perror(szBuff); -#else - MessageBox(MainWnd, szBuff, "BPQMailChat", MB_OK); -#endif - closesocket( sock ); - return FALSE; - } - - if (listen( sock, MAX_PENDING_CONNECTS ) < 0) - { - sprintf(szBuff, "listen(%d) failed Error %d", Port, WSAGetLastError()); -#ifdef LINBPQ - perror(szBuff); -#else - MessageBox(MainWnd, szBuff, "BPQMailChat", MB_OK); -#endif - closesocket( sock ); - return FALSE; - } - - ioctl(sock, FIONBIO, ¶m); - return sock; -} - -static int Socket_Accept(SOCKET SocketId) -{ - int addrlen; - SocketConn * sockptr; - SOCKET sock; - unsigned int param = 1; - - addrlen=sizeof(struct sockaddr); - - // Allocate a Socket entry - - sockptr = malloc(sizeof(SocketConn)); - memset(sockptr, 0, sizeof (SocketConn)); - - sockptr->Next = Sockets; - Sockets = sockptr; - - sock = accept(SocketId, (struct sockaddr *)&sockptr->sin, &addrlen); - - if (sock == INVALID_SOCKET) - { - Logprintf(LOG_TCP, NULL, '|', " accept() failed Error %d", WSAGetLastError()); - - // get rid of socket record - - Sockets = sockptr->Next; - free(sockptr); - return FALSE; - } - - ioctl(sock, FIONBIO, ¶m); - - - sockptr->socket = sock; - - if (SocketId == pop3sock) - { - sockptr->Type = POP3SLAVE; - SendSock(sockptr, "+OK POP3 server ready"); - sockptr->State = GettingUser; - Logprintf(LOG_TCP, NULL, '|', "Incoming POP3 Connect Socket = %d", sock); - } - else - { - sockptr->Type = SMTPServer; - sockptr->State = WaitingForGreeting; - SendSock(sockptr, "220 BPQMail SMTP Server ready"); - Logprintf(LOG_TCP, NULL, '|', "Incoming SMTP Connect Socket = %d", sock); - } - - return 0; -} - - -VOID ReleaseSock(SOCKET sock) -{ - // remove and free the socket record - - SocketConn * sockptr, * lastptr; - - sockptr=Sockets; - lastptr=NULL; - - while (sockptr) - { - if (sockptr->socket == sock) - { - if (lastptr) - lastptr->Next=sockptr->Next; - else - Sockets=sockptr->Next; - - if (sockptr->POP3User) - sockptr->POP3User->POP3Locked = FALSE; - - if (sockptr->State == WaitingForGreeting) - { - Logprintf(LOG_TCP, NULL, '|', "Premature Close on Socket %d", sock); - - if (sockptr->Type == SMTPClient) - SMTPActive = FALSE; - } - else - Logprintf(LOG_TCP, NULL, '|', "Socket %d Closed", sock); - - - free(sockptr); - return; - } - else - { - lastptr=sockptr; - sockptr=sockptr->Next; - } - } -} - -/* -int Socket_Data(int sock, int error, int eventcode) -{ - SocketConn * sockptr; - - // Find Connection Record - - sockptr=Sockets; - - while (sockptr) - { - if (sockptr->socket == sock) - { - switch (eventcode) - { - case FD_READ: - - return DataSocket_Read(sockptr,sock); - - case FD_WRITE: - - // Either Just connected, or flow contorl cleared - - if (sockptr->SendBuffer) - // Data Queued - SendFromQueue(sockptr); - else - { - if (sockptr->Type == SMTPServer) - SendSock(sockptr, "220 BPQMail SMTP Server ready"); - else - { - if (sockptr->Type == POP3SLAVE) - { - SendSock(sockptr, "+OK POP3 server ready"); - sockptr->State = GettingUser; - } - } - } - return 0; - - case FD_OOB: - - return 0; - - case FD_ACCEPT: - - return 0; - - case FD_CONNECT: - - return 0; - - case FD_CLOSE: - - closesocket(sock); - ReleaseSock(sock); - return 0; - } - return 0; - } - else - sockptr=sockptr->Next; - } - - return 0; -} -*/ -int DataSocket_Read(SocketConn * sockptr, SOCKET sock) -{ - int InputLen, MsgLen; - char * ptr, * ptr2; - char Buffer[2000]; - - // May have several messages per packet, or message split over packets - - if (sockptr->InputLen > 1000) // Shouldnt have lines longer than this in text mode - { - sockptr->InputLen=0; - } - - InputLen=recv(sock, &sockptr->TCPBuffer[sockptr->InputLen], 1000, 0); - - if (InputLen <= 0) - { - int x = WSAGetLastError(); - - closesocket(sock); - ReleaseSock(sock); - - return 0; // Does this mean closed? - } - - sockptr->InputLen += InputLen; - -loop: - - ptr = memchr(sockptr->TCPBuffer, '\n', sockptr->InputLen); - - if (ptr) // CR in buffer - { - ptr2 = &sockptr->TCPBuffer[sockptr->InputLen]; - ptr++; // Assume LF Follows CR - - if (ptr == ptr2) - { - // Usual Case - single meg in buffer - - if (sockptr->Type == SMTPServer) - ProcessSMTPServerMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen); - else - if (sockptr->Type == POP3SLAVE) - ProcessPOP3ServerMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen); - else - if (sockptr->Type == SMTPClient) - ProcessSMTPClientMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen); - else - if (sockptr->Type == POP3Client) - ProcessPOP3ClientMessage(sockptr, sockptr->TCPBuffer, sockptr->InputLen); - - sockptr->InputLen=0; - - } - else - { - // buffer contains more that 1 message - - MsgLen = sockptr->InputLen - (int)(ptr2-ptr); - - memcpy(Buffer, sockptr->TCPBuffer, MsgLen); - - - if (sockptr->Type == SMTPServer) - ProcessSMTPServerMessage(sockptr, Buffer, MsgLen); - else - if (sockptr->Type == POP3SLAVE) - ProcessPOP3ServerMessage(sockptr, Buffer, MsgLen); - else - if (sockptr->Type == SMTPClient) - ProcessSMTPClientMessage(sockptr, Buffer, MsgLen); - else - if (sockptr->Type == POP3Client) - ProcessPOP3ClientMessage(sockptr, Buffer, MsgLen); - - - memmove(sockptr->TCPBuffer, ptr, sockptr->InputLen-MsgLen); - - sockptr->InputLen -= MsgLen; - - goto loop; - - } - } - return TRUE; -} - -char * FindPart(char ** Msg, char * Boundary, int * PartLen) -{ - char * ptr = *Msg, * ptr2; - char * Msgptr = *Msg; - int BLen = (int)strlen(Boundary); - char * Part; - - while(*ptr) // Just in case we run off end - { - ptr2 = strchr(ptr, 10); // Find LF - - if (ptr2 == NULL) return NULL; - - if (*ptr == '-' && *(ptr+1) == '-') - { - if (memcmp(&ptr[2], Boundary, BLen) == 0) - { - // Found Boundary - - int Partlen = (int)(ptr - Msgptr); - Part = malloc(Partlen + 1); - memcpy(Part, Msgptr, Partlen); - Part[Partlen] = 0; - - *Msg = ++ptr2; - - *PartLen = Partlen; - - return Part; - } - } - - ptr = ++ptr2; - } - return NULL; -} - - - - - -BOOL CheckforMIME(SocketConn * sockptr, char * Msg, char ** Body, int * MsgLen) // Will reformat message if necessary. -{ - int i; - char * ptr, * ptr2, * ptr3, * ptr4; - char Boundary[1000]; - BOOL Multipart = FALSE; - BOOL ALT = FALSE; - int Partlen; - char * Save; - BOOL Base64 = FALSE; - BOOL QuotedP = FALSE; - - char FileName[100][250] = {""}; - int FileLen[100]; - char * FileBody[100]; - char * MallocSave[100]; - UCHAR * NewMsg; - - int Files = 0; - - ptr = Msg; - - while(*ptr != 13) - { - ptr2 = strchr(ptr, 10); // Find CR - - while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line - { - ptr2 = strchr(&ptr2[1], 10); // Find CR - } - -// Content-Type: multipart/mixed; -// boundary="----=_NextPart_000_025B_01CAA004.84449180" -// 7.2.2 The Multipart/mixed (primary) subtype -// 7.2.3 The Multipart/alternative subtype - - - if (_memicmp(ptr, "Content-Type: ", 14) == 0) - { - char Line[1000] = ""; - char lcLine[1000] = ""; - - char * ptr3; - - memcpy(Line, &ptr[14], ptr2-ptr-14); - memcpy(lcLine, &ptr[14], ptr2-ptr-14); - _strlwr(lcLine); - - if (_memicmp(Line, "Multipart/", 10) == 0) - { - Multipart = TRUE; - - if (_memicmp(&Line[10], "alternative", 11) == 0) - { - ALT = TRUE; - } - - ptr3 = strstr(Line, "boundary"); - - if (ptr3) - { - ptr3+=9; - - if ((*ptr3) == '"') - ptr3++; - - strcpy(Boundary, ptr3); - ptr3 = strchr(Boundary, '"'); - if (ptr3) *ptr3 = 0; - ptr3 = strchr(Boundary, 13); // CR - if (ptr3) *ptr3 = 0; - - } - else - return FALSE; // Can't do anything without a boundary ?? - } - - } - - else if (_memicmp(ptr, "Content-Transfer-Encoding:", 26) == 0) - { - if (strstr(&ptr[26], "base64")) - Base64 = TRUE; - else - if (strstr(&ptr[26], "quoted-printable")) - QuotedP = TRUE; - } - - - ptr = ptr2; - ptr++; - - } - - if (Multipart == FALSE) - { - // We only have one part, but it could have an odd encoding - - if (Base64) - { - int i = 0, Len = *MsgLen, NewLen; - char * ptr2; - char * End; - - ptr = ptr2 = *Body; - End = ptr + Len; - - while (ptr < End) - { - while (*ptr < 33) - {ptr++;} - - *ptr2++ = *ptr++; - } - - *ptr2 = 0; - - ptr = *Body; - Len = (int)(ptr2 - ptr - 1); - - ptr2 = ptr; - - while (Len > 0) - { - decodeblock(ptr, ptr2); - ptr += 4; - ptr2 += 3; - Len -= 4; - } - - NewLen = (int)(ptr2 - *Body); - - if (*(ptr-1) == '=') - NewLen--; - - if (*(ptr-2) == '=') - NewLen--; - - *MsgLen = NewLen; - } - else if (QuotedP) - { - int i = 0, Len = *MsgLen; - char * ptr2; - char * End; - - ptr = ptr2 =*Body; - - End = ptr + Len; - - while (ptr < End) - { - if ((*ptr) == '=') - { - char c = *(++ptr); - char d; - - c = c - 48; - if (c < 0) - { - // = CRLF as a soft break - - ptr += 2; - continue; - } - - if (c > 9) - c -= 7; - d = *(++ptr); - d = d - 48; - if (d > 9) - d -= 7; - - *(ptr2) = c << 4 | d; - ptr2++; - ptr++; - } - else - { - *ptr2++ = *ptr++; - } - } - *ptr2 = 0; - - *MsgLen = (int)(ptr2 - *Body); - - } - - return FALSE; - } - // FindPart Returns Next Part of Message, Updates Input Pointer - // Skip to first Boundary (over the non MIME Alt Part) - - ptr = FindPart(Body, Boundary, &Partlen); - - if (ptr == NULL) - return FALSE; // Couldn't find separator - - free(ptr); - - if (ALT) - { - // Assume HTML and Plain Text Versions of the same single body. - - ptr = FindPart(Body, Boundary, &Partlen); - - Save = ptr; // For free(); - - // Should be the First (Least desireable part, but the bit we want, as we are only interested in plain text) - - // Skip any headers - - while(*ptr != 13) - { - if (_memicmp(ptr, "Content-Transfer-Encoding:", 26) == 0) - { - if (strstr(&ptr[26], "base64")) - Base64 = TRUE; - else - if (strstr(&ptr[26], "quoted-printable")) - QuotedP = TRUE; - } - - ptr2 = strchr(ptr, 10); // Find CR - - while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line - { - ptr2 = strchr(&ptr2[1], 10); // Find CR - } - - ptr = ++ptr2; - } - - ptr += 2; // Skip rerminating line - - // Should now have a plain text body to return; - - // But could be an odd encoding - - if (Base64) - { - int i = 0, Len = (int)strlen(ptr), NewLen; - char * ptr2; - char * End; - char * Save = ptr; - - ptr2 = ptr; - End = ptr + Len; - - while (ptr < End) - { - while (*ptr < 33) - {ptr++;} - - *ptr2++ = *ptr++; - } - - *ptr2 = 0; - - ptr = Save; - Len = (int)(ptr2 - ptr - 1); - - ptr2 = *Body; - - while (Len > 0) - { - decodeblock(ptr, ptr2); - ptr += 4; - ptr2 += 3; - Len -= 4; - } - - NewLen = (int)(ptr2 - *Body); - - if (*(ptr-1) == '=') - NewLen--; - - if (*(ptr-2) == '=') - NewLen--; - - *MsgLen = NewLen; - } - else if (QuotedP) - { - int i = 0, Len = (int)strlen(ptr); - char * ptr2; - char * End; - char * Save = ptr; - - ptr2 = *Body; - - End = ptr + Len; - - while (ptr < End) - { - if ((*ptr) == '=') - { - char c = *(++ptr); - char d; - - c = c - 48; - if (c < 0) - { - // = CRLF as a soft break - - ptr += 2; - continue; - } - - if (c > 9) - c -= 7; - d = *(++ptr); - d = d - 48; - if (d > 9) - d -= 7; - - *(ptr2) = c << 4 | d; - ptr2++; - ptr++; - } - else - { - *ptr2++ = *ptr++; - } - } - *ptr2 = 0; - - *MsgLen = (int)(ptr2 - *Body); - } - else - { - strcpy(*Body, ptr); - *MsgLen = (int)strlen(ptr); - } - free(Save); - - return FALSE; - } - - // Assume Multipart/Mixed - Message with attachments - - ptr = FindPart(Body, Boundary, &Partlen); - - if (ptr == NULL) - return FALSE; // Couldn't find separator - - while (ptr) - { - BOOL Base64 = FALSE; - BOOL QuotedP = FALSE; - - MallocSave[Files] = ptr; // For free(); - - // Should be the First (Least desireable part, but the bit we want, as we are only interested in plain text) - - // Process headers - looking for Content-Disposition: attachment; - - // The first could also be a Content-Type: multipart/alternative; - if so, feed back to mime handler - - while(*ptr != 13) - { - char lcLine[1000] = ""; - - ptr2 = strchr(ptr, 10); // Find CR - - if (ptr2 == 0) - return FALSE; - - while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line - { - ptr2 = strchr(&ptr2[1], 10); // Find CR - } - - memcpy(lcLine, ptr, ptr2-ptr-1); - _strlwr(lcLine); - - ptr = lcLine; - - if (_memicmp(ptr, "Content-Type: Multipart/alternative", 30) == 0) - { - // Feed Back - int MsgLen; - char * Text = malloc(Partlen+1); - - memcpy(Text, MallocSave[Files], Partlen); - - free(MallocSave[Files]); - MallocSave[Files] = Text; - - - CheckforMIME(sockptr, Text, &Text, &MsgLen); - - FileName[Files][0] = 0; - FileBody[Files] = Text; - - - FileLen[Files++] = MsgLen; - - goto NextPart; - - } - else if (_memicmp(ptr, "Content-Disposition: ", 21) == 0) - { - ptr3 = strstr(&ptr[21], "filename"); - - if (ptr3) - { - ptr3 += 9; - if (*ptr3 == '"') ptr3++; - ptr4 = strchr(ptr3, '"'); - if (ptr4) *ptr4 = 0; - - strcpy(FileName[Files], ptr3); - } - } - - else if (_memicmp(ptr, "Content-Transfer-Encoding:", 26) == 0) - { - if (strstr(&ptr[26], "base64")) - Base64 = TRUE; - else - if (strstr(&ptr[26], "quoted-printable")) - QuotedP = TRUE; - } - - ptr = ++ptr2; - } - - ptr += 2; - - // Should now have file or plain text. If file is Base64 encoded, decode it. - - FileBody[Files] = ptr; - FileLen[Files] = (int)(Partlen - 2 - (ptr - MallocSave[Files])); - - if (Base64) - { - int i = 0, Len = FileLen[Files], NewLen; - char * ptr2 = ptr; - char * End; - - End = ptr + FileLen[Files]; - - while (ptr < End) - { - while (*ptr < 33) - {ptr++;} - - *ptr2++ = *ptr++; - } - *ptr2 = 0; - - ptr = FileBody[Files]; - Len = (int)(ptr2 - ptr - 1); - - ptr2 = ptr; - - while (Len > 0) - { - decodeblock(ptr, ptr2); - ptr += 4; - ptr2 += 3; - Len -= 4; - } - - NewLen = (int)(ptr2 - FileBody[Files]); - - if (*(ptr-1) == '=') - NewLen--; - - if (*(ptr-2) == '=') - NewLen--; - - FileLen[Files] = NewLen; - } - else if (QuotedP) - { - int i = 0, Len = FileLen[Files], NewLen; - char * ptr2 = ptr; - char * End; - - End = ptr + FileLen[Files]; - - while (ptr < End) - { - if ((*ptr) == '=') - { - char c = *(++ptr); - char d; - - c = c - 48; - if (c < 0) - { - // = CRLF as a soft break - - ptr += 2; - continue; - } - - if (c > 9) - c -= 7; - d = *(++ptr); - d = d - 48; - if (d > 9) - d -= 7; - - *(ptr2) = c << 4 | d; - ptr2++; - ptr++; - } - else - { - *ptr2++ = *ptr++; - } - } - *ptr2 = 0; - - NewLen = (int)(ptr2 - FileBody[Files]); - - FileLen[Files] = NewLen; - } - - Files++; - - NextPart: - ptr = FindPart(Body, Boundary, &Partlen); - } - - // Now have all the parts - build a B2 Message. Leave the first part of header for later, - // as we may have multiple recipients. Start with the Body: Line. - - // We need to add the first part of header later, so start message part way down buffer. - // Make sure buffer is big enough. - - if ((sockptr->MailSize + 2000) > sockptr->MailBufferSize) - { - sockptr->MailBufferSize += 2000; - sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize); - - if (sockptr->MailBuffer == NULL) - { - CriticalErrorHandler("Failed to extend Message Buffer"); - shutdown(sockptr->socket, 0); - return FALSE; - } - } - - - NewMsg = sockptr->MailBuffer + 1000; - - NewMsg += sprintf(NewMsg, "Body: %d\r\n", FileLen[0]); - - for (i = 1; i < Files; i++) - { - NewMsg += sprintf(NewMsg, "File: %d %s\r\n", FileLen[i], FileName[i]); - } - - NewMsg += sprintf(NewMsg, "\r\n"); - - for (i = 0; i < Files; i++) - { - memcpy(NewMsg, FileBody[i], FileLen[i]); - NewMsg += FileLen[i]; - free(MallocSave[i]); - NewMsg += sprintf(NewMsg, "\r\n"); - } - - *MsgLen = (int)(NewMsg - (sockptr->MailBuffer + 1000)); - *Body = sockptr->MailBuffer + 1000; - - return TRUE; // B2 Message -} - - -VOID ProcessSMTPServerMessage(SocketConn * sockptr, char * Buffer, int Len) -{ - SOCKET sock; - int i; - time_t Date = 0; - - sock=sockptr->socket; - - WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP); - - if (sockptr->Flags == GETTINGMESSAGE) - { - if(memcmp(Buffer, ".\r\n", 3) == 0) - { - char * ptr1, * ptr2; - int linelen, MsgLen; - char Msgtitle[62]; - BOOL B2Flag; - int ToLen = 0; - char * ToString; - char * Via; - - // Scan headers for a Subject: or Date: Line (Headers end at blank line) - - ptr1 = sockptr->MailBuffer; - Loop: - ptr2 = strchr(ptr1, '\r'); - - if (ptr2 == NULL) - { - SendSock(sockptr, "500 Eh"); - return; - } - - linelen = (int)(ptr2 - ptr1); - - if (_memicmp(ptr1, "Subject:", 8) == 0) - { - if (linelen > 68) linelen = 68; - memcpy(Msgtitle, &ptr1[9], linelen-9); - Msgtitle[linelen-9]=0; - } - - if (_memicmp(ptr1, "Date:", 5) == 0) - { - struct tm rtime; - char * Context; - char seps[] = " ,\t\r"; - char Offset[10] = ""; - int i, HH, MM; - char Copy[500]=""; - - // Copy message, so original isn't messed up by strtok - - memcpy(Copy, ptr1, linelen); - - ptr1 = Copy; - - memset(&rtime, 0, sizeof(struct tm)); - - // Date: Tue, 9 Jun 2009 20:54:55 +0100 - - ptr1 = strtok_s(&ptr1[5], seps, &Context); // Skip Day - ptr1 = strtok_s(NULL, seps, &Context); // Day - - rtime.tm_mday = atoi(ptr1); - - ptr1 = strtok_s(NULL, seps, &Context); // Month - - for (i=0; i < 12; i++) - { - if (strcmp(month[i], ptr1) == 0) - { - rtime.tm_mon = i; - break; - } - } - - sscanf(Context, "%04d %02d:%02d:%02d%s", - &rtime.tm_year, &rtime.tm_hour, &rtime.tm_min, &rtime.tm_sec, Offset); - - rtime.tm_year -= 1900; - - Date = mktime(&rtime) - (time_t)_MYTIMEZONE; - - if (Date == (time_t)-1) - Date = 0; - else - { - if ((Offset[0] == '+') || (Offset[0] == '-')) - { - MM = atoi(&Offset[3]); - Offset[3] = 0; - HH = atoi(&Offset[1]); - MM = MM + (60 * HH); - - if (Offset[0] == '+') - Date -= (60*MM); - else - Date += (60*MM); - - } - } - } - - ptr1 = ptr2 + 2; // Skip crlf - - if (linelen) // Not Null line - { - goto Loop; - } - - ptr2 = ptr1; - ptr1 = sockptr->MailBuffer; - - MsgLen = (int)(sockptr->MailSize - (ptr2 - ptr1)); - - // We Just want the from call, not the full address. - - TidyString(sockptr->MailFrom); - - // Examine Message to look for html formatting and attachments. - - B2Flag = CheckforMIME(sockptr, sockptr->MailBuffer, &ptr2, &MsgLen); // Will reformat message if necessary. - - // If any recipients are via RMS, create one message for them, and separate messages for all others - - ToString = zalloc(sockptr->Recipients * 100); - - for (i=0; i < sockptr->Recipients; i++) - { - char Addr[256]; // Need copy, as we may change it then decide it isn't for RMS - - strcpy(Addr, sockptr->RecpTo[i]); - Debugprintf("To Addr %s", Addr); - - TidyString(Addr); - Debugprintf("To Addr after Tidy %s", Addr); - - if ((_memicmp (Addr, "RMS:", 4) == 0) |(_memicmp (Addr, "RMS/", 4) == 0)) - { - // Add to B2 Message for RMS - - _strlwr(Addr); - - Via = strlop(&Addr[4], '@'); - - if (Via && _stricmp(Via, "winlink.org") == 0) - { - if (CheckifLocalRMSUser(Addr)) // if local RMS - Leave Here - continue; - - ToLen = sprintf(ToString, "%sTo: %s\r\n", ToString, &Addr[4]); - *sockptr->RecpTo[i] = 0; // So we dont create individual one later - continue; - } - - ToLen = sprintf(ToString, "%sTo: %s@%s\r\n", ToString, &Addr[4], Via); - *sockptr->RecpTo[i] = 0; // So we dont create individual one later - continue; - } - - _strupr(Addr); - Debugprintf("To Addr after strupr %s", Addr); - - Via = strlop(Addr, '@'); - Debugprintf("Via %s", Via); - - if (Via && _stricmp(Via, "winlink.org") == 0) - { - if (CheckifLocalRMSUser(Addr)) // if local RMS - Leave Here - continue; - - ToLen = sprintf(ToString, "%sTo: %s\r\n", ToString, Addr); - *sockptr->RecpTo[i] = 0; // So we dont create individual one later - - continue; - } - } - - if (ToLen) // Have some RMS Addresses - { - char B2Hddr[1000]; - int B2HddrLen; - char DateString[80]; - char * NewBody; - struct tm * tm; - struct MsgInfo * Msg; - BIDRec * BIDRec; - - Msg = AllocateMsgRecord(); - - // Set number here so they remain in sequence - - Msg->number = ++LatestMsg; - MsgnotoMsg[Msg->number] = Msg; - Msg->length = MsgLen; - - sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); - - Msg->type = 'P'; - Msg->status = 'N'; - strcpy(Msg->to, "RMS"); - strlop(sockptr->MailFrom, '@'); - if (strlen(sockptr->MailFrom) > 6) sockptr->MailFrom[6]=0; - strcpy(Msg->from, sockptr->MailFrom); - strcpy(Msg->title, Msgtitle); - - BIDRec = AllocateBIDRecord(); - - strcpy(BIDRec->BID, Msg->bid); - BIDRec->mode = Msg->type; - BIDRec->u.msgno = LOWORD(Msg->number); - BIDRec->u.timestamp = LOWORD(time(NULL)/86400); - - Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); - - if (Date) - Msg->datecreated = Date; - - tm = gmtime(&Date); - - sprintf(DateString, "%04d/%02d/%02d %02d:%02d", - tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); - - if (B2Flag) // Message has attachments, so Body: line is present - { - Msg->B2Flags = B2Msg | Attachments; - - B2HddrLen = sprintf(B2Hddr, - "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\n%sSubject: %s\r\nMbo: %s\r\n", - Msg->bid, DateString, "Private", Msg->from, ToString, Msg->title, BBSName); - } - else - { - Msg->B2Flags = B2Msg; - B2HddrLen = sprintf(B2Hddr, - "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\n%sSubject: %s\r\nMbo: %s\r\nBody: %d\r\n\r\n", - Msg->bid, DateString, "Private", Msg->from, ToString, Msg->title, BBSName, Msg->length); - - } - - NewBody = ptr2 - B2HddrLen; - - memcpy(NewBody, B2Hddr, B2HddrLen); - - Msg->length += B2HddrLen; - - free(ToString); - - // Set up forwarding bitmap - - MatchMessagetoBBSList(Msg, 0); - - CreateSMTPMessageFile(NewBody, Msg); - } - - for (i=0; i < sockptr->Recipients; i++) - { - if (*sockptr->RecpTo[i]) // not already sent to RMS? - CreateSMTPMessage(sockptr, i, Msgtitle, Date, ptr2, MsgLen, B2Flag); - else - free(sockptr->RecpTo[i]); - } - - free(sockptr->RecpTo); - sockptr->RecpTo = NULL; - free(sockptr->MailFrom); - free(sockptr->MailBuffer); - - sockptr->MailBufferSize=0; - sockptr->MailBuffer=0; - sockptr->MailSize = 0; - - sockptr->Flags = 0; - sockptr->Recipients = 0; - - SendSock(sockptr, "250 Ok"); - return; - } - - if ((sockptr->MailSize + Len) > sockptr->MailBufferSize) - { - sockptr->MailBufferSize += 10000; - sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize); - - if (sockptr->MailBuffer == NULL) - { - CriticalErrorHandler("Failed to extend Message Buffer"); - shutdown(sock, 0); - return; - } - } - - memcpy(&sockptr->MailBuffer[sockptr->MailSize], Buffer, Len); - sockptr->MailSize += Len; - - return; - } - - if (sockptr->State == GettingUser) - { - char Out[30]; - - Buffer[Len-2]=0; - - decodeblock(Buffer, Out); - decodeblock(&Buffer[4], &Out[3]); - decodeblock(&Buffer[8], &Out[6]); - decodeblock(&Buffer[12], &Out[9]); - - if (strlen(Out) > 10) Out[10] = 0; - - strcpy(sockptr->CallSign, Out); - - sockptr->State = GettingPass; - SendSock(sockptr, "334 UGFzc3dvcmQ6"); - return; - } - - if (sockptr->State == GettingPass) - { - struct UserInfo * user = NULL; - char Out[30]; - - Buffer[Len-2]=0; - - decodeblock(Buffer, Out); - decodeblock(&Buffer[4], &Out[3]); - decodeblock(&Buffer[8], &Out[6]); - decodeblock(&Buffer[12], &Out[9]); - decodeblock(&Buffer[16], &Out[12]); - decodeblock(&Buffer[20], &Out[15]); - - user = LookupCall(sockptr->CallSign); - - if (user) - { - if (strcmp(user->pass, Out) == 0) - { - sockptr->State = Authenticated; - SendSock(sockptr, "235 2.0.0 OK Authenticated"); //535 authorization failed - return; - } - } - - SendSock(sockptr, "535 authorization failed"); - sockptr->State = 0; - return; - } - - - -/*AUTH LOGIN - -334 VXNlcm5hbWU6 -a4msl9ux -334 UGFzc3dvcmQ6 -ZvVx9G1hcg== -235 2.0.0 OK Authenticated -*/ - - - if(memcmp(Buffer, "AUTH LOGIN", 10) == 0) - { - sockptr->State = GettingUser; - SendSock(sockptr, "334 VXNlcm5hbWU6"); - return; - } - - if(memcmp(Buffer, "EHLO",4) == 0) - { - SendSock(sockptr, "250-BPQ Mail Server"); - SendSock(sockptr, "250 AUTH LOGIN"); - - //250-8BITMIME - - return; - } - - if(memcmp(Buffer, "AUTH LOGIN", 10) == 0) - { - sockptr->State = GettingUser; - SendSock(sockptr, "334 VXNlcm5hbWU6"); - return; - } - - - if(memcmp(Buffer, "HELO",4) == 0) - { - SendSock(sockptr, "250 Ok"); - return; - } - - if(_memicmp(Buffer, "MAIL FROM:", 10) == 0) - { - if (sockptr->State != Authenticated) - { - // Accept if from 44/8 and ends in ampr.org - - if (_memicmp(&Buffer[Len - 11], "ampr.org", 8) == 0 && - (sockptr->sin.sin_addr.s_addr & 0xff) == 44) - { - } - else - { - SendSock(sockptr, "530 Authentication required"); - return; - } - } - - sockptr->MailFrom = zalloc(Len); - memcpy(sockptr->MailFrom, &Buffer[10], Len-12); - - SendSock(sockptr, "250 Ok"); - - return; - } - - if(_memicmp(Buffer, "RCPT TO:", 8) == 0) - { - if (sockptr->State != Authenticated) - { - // Accept if from 44/8 and ends in ampr.org - - - - if (_memicmp(&Buffer[Len - 11], "ampr.org", 8) == 0 && - (sockptr->sin.sin_addr.s_addr & 0xff) == 44) - { - } - else - { - SendSock(sockptr, "530 Authentication required"); - return; - } - } - - sockptr->RecpTo=realloc(sockptr->RecpTo, (sockptr->Recipients+1) * sizeof(void *)); - sockptr->RecpTo[sockptr->Recipients] = zalloc(Len); - - memcpy(sockptr->RecpTo[sockptr->Recipients++], &Buffer[8], Len-10); - - SendSock(sockptr, "250 Ok"); - return; - } - - if(memcmp(Buffer, "DATA\r\n", 6) == 0) - { - sockptr->MailBuffer=malloc(10000); - sockptr->MailBufferSize=10000; - - if (sockptr->MailBuffer == NULL) - { - CriticalErrorHandler("Failed to create SMTP Message Buffer"); - SendSock(sockptr, "250 Failed"); - shutdown(sock, 0); - - return; - } - - sockptr->Flags |= GETTINGMESSAGE; - - SendSock(sockptr, "354 End data with ."); - return; - } - - if(memcmp(Buffer, "QUIT\r\n", 6) == 0) - { - SendSock(sockptr, "221 OK"); - Sleep(500); - shutdown(sock, 0); - return; - } - - if(memcmp(Buffer, "RSET\r\n", 6) == 0) - { - SendSock(sockptr, "250 Ok"); - - // This cancelled AUTH which I think is wrong - //sockptr->State = 0; - - if (sockptr->State != Authenticated) - sockptr->State = 0; - - sockptr->Recipients = 0; - - return; - } - - return; -} - - -int CreateSMTPMessage(SocketConn * sockptr, int i, char * MsgTitle, time_t Date, char * MsgBody, int MsgLen, BOOL B2Flag) -{ - struct MsgInfo * Msg; - BIDRec * BIDRec; - char * To; - char * via; - - // Allocate a message Record slot - - Msg = AllocateMsgRecord(); - - // Set number here so they remain in sequence - - Msg->number = ++LatestMsg; - MsgnotoMsg[Msg->number] = Msg; - Msg->length = MsgLen; - - sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); - - Msg->type = 'P'; - Msg->status = 'N'; - - BIDRec = AllocateBIDRecord(); - - strcpy(BIDRec->BID, Msg->bid); - BIDRec->mode = Msg->type; - BIDRec->u.msgno = LOWORD(Msg->number); - BIDRec->u.timestamp = LOWORD(time(NULL)/86400); - - Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); - - if (Date) - Msg->datecreated = Date; - - To = sockptr->RecpTo[i]; - - Debugprintf("To %s", To); - - TidyString(To); - - Debugprintf("To after tidy %s", To); - - if (_memicmp(To, "bull/", 5) == 0) - { - Msg->type = 'B'; - memmove(To, &To[5], strlen(&To[4])); - } - - if ((_memicmp(To, "nts/", 4) == 0) ||(_memicmp(To, "nts:", 4) == 0) || - (_memicmp(To, "nts.", 4) == 0)) - { - Msg->type = 'T'; - memmove(To, &To[4], strlen(&To[3])); - } - - if (_memicmp(To, "rms:", 4) == 0) - { - via = _strlwr(strlop(To, ':')); - } - else if (_memicmp(To, "rms/", 4) == 0) - { - via = _strlwr(strlop(To, '/')); - } - else if (_memicmp(To, "rms.", 4) == 0) - { - via = _strlwr(strlop(To, '.')); - } - else if (_memicmp(To, "smtp:", 5) == 0) - { - via = _strlwr(strlop(To, ':')); - To[0] = 0; - } - else if (_memicmp(To, "smtp/", 5) == 0) - { - via = _strlwr(strlop(To, '/')); - To[0] = 0; - } - else - { - via = strlop(To, '@'); - } - - Debugprintf("via %s", via); - - if (via) - { - int toLen; - - if (strlen(via) > 40) via[40] = 0; - - strcpy(Msg->via, via); // Save before messing with it - - // if ending in AMPR.ORG send via ISP if we have enabled forwarding AMPR - - toLen = (int)strlen(via); - - if (_memicmp(&via[toLen - 8], "ampr.org", 8) == 0) - { - // if our domain keep here. - - // if not, and SendAMPRDirect set, set as ISP, - // else set as RMS - - if (_stricmp(via, AMPRDomain) == 0) - { - // Our Message- dont forward - } - else - { - // AMPR but not us - - if (SendAMPRDirect) - { - sprintf(Msg->via,"%s@%s", To, via); - strcpy(To, "AMPR"); - } - else - { - sprintf(Msg->via,"%s@%s", To, via); - strcpy(To, "RMS"); - } - } - } - else - { - strlop(via, '.'); // Get first part of address - - if (_stricmp(via, BBSName) == 0) - { - // sent via us - clear the name - - Msg->via[0] = 0; - } - } - } - - if (strlen(To) > 6) To[6]=0; - - strcpy(Msg->to, To); - - if (strchr(sockptr->MailFrom, '@')) - { - char * FromHA = strlop(sockptr->MailFrom, '@'); - Msg->emailfrom[0] = '@'; - strcpy(&Msg->emailfrom[1], FromHA); - } - - if (strlen(sockptr->MailFrom) > 6) sockptr->MailFrom[6]=0; - - strcpy(Msg->from, sockptr->MailFrom); - - strcpy(Msg->title, MsgTitle); - - if(Msg->to[0] == 0) - SMTPMsgCreated=TRUE; - - // If NTS message (TO is numeric and AT is NTSxx or NTSxx.NTS - Outlook won't accept x@y) - - if (isdigits(Msg->to) && memcmp(Msg->via, "NTS", 3) == 0) - { - if (Msg->via[5] == 0 || strcmp(&Msg->via[5], ".NTS") == 0) - { - Msg->type = 'T'; - Msg->via[5] = 0; - } - } - - Debugprintf("Msg->Via %s", Msg->via); - - if (B2Flag) - { - char B2Hddr[1000]; - int B2HddrLen; - char B2To[80]; - char * NewBody; - char DateString[80]; - char * TypeString; - struct tm * tm; - - tm = gmtime(&Date); - - sprintf(DateString, "%04d/%02d/%02d %02d:%02d", - tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); - - - if (strcmp(Msg->to, "RMS") == 0) // Address is in via - strcpy(B2To, Msg->via); - else - if (Msg->via[0]) - sprintf(B2To, "%s@%s", Msg->to, Msg->via); - else - strcpy(B2To, Msg->to); - - - Msg->B2Flags = B2Msg | Attachments; - - if (Msg->type == 'P') - TypeString = "Private" ; - else if (Msg->type == 'B') - TypeString = "Bulletin"; - else if (Msg->type == 'T') - TypeString = "Traffic"; - - B2HddrLen = sprintf(B2Hddr, - "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, TypeString, - Msg->from, B2To, Msg->title, BBSName); - - NewBody = MsgBody - B2HddrLen; - - memcpy(NewBody, B2Hddr, B2HddrLen); - - Msg->length += B2HddrLen; - - free(To); - - // Set up forwarding bitmap - - MatchMessagetoBBSList(Msg, 0); - - if (Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0) - Msg->status = '$'; // Has forwarding - - return CreateSMTPMessageFile(NewBody, Msg); - - } - - free(To); - - // Set up forwarding bitmap - - MatchMessagetoBBSList(Msg, 0); - - if (Msg->type == 'B' && memcmp( Msg->fbbs, zeros, NBMASK) != 0) - Msg->status = '$'; // Has forwarding - - return CreateSMTPMessageFile(MsgBody, Msg); - -} - - -BOOL CreateSMTPMessageFile(char * Message, struct MsgInfo * Msg) -{ - char MsgFile[250]; - FILE * hFile; - int WriteLen=0; - char Mess[255]; - int len; - - struct UserInfo * ToUser = LookupCall(Msg->to); - - if (ToUser && ToUser->flags & F_HOLDMAIL) - { - int Length=0; - char * MailBuffer = malloc(100); - char Title[100]; - - Msg->status = 'H'; - - Length += sprintf(MailBuffer, "Message %d Held\r\n", Msg->number); - sprintf(Title, "Message %d Held - %s", Msg->number, "User has Hold Messages flag set"); - SendMessageToSYSOP(Title, MailBuffer, Length); - } - - sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number); - - hFile = fopen(MsgFile, "wb"); - - if (hFile) - { - WriteLen = (int)fwrite(Message, 1, Msg->length, hFile); - fclose(hFile); - } - - if (WriteLen != Msg->length) - { - len = sprintf_s(Mess, sizeof(Mess), "Failed to create Message File\r"); - CriticalErrorHandler(Mess); - - return FALSE; - } - - SaveMessageDatabase(); - SaveBIDDatabase(); - - return TRUE; -} - -int TidyString(char * Address) -{ - // Cleans up a From: or To: Address - - // May have leading or trailing spaces, or be enclosed by <>, or have a " " part - - // From: "John Wiseman" - - char * ptr1, * ptr2; - size_t len; - - _strupr(Address); - - ptr1 = strchr(Address, '<'); - - if (ptr1) - { - ptr1++; - ptr2 = strlop(ptr1, '>'); - len = (int)strlen(ptr1); - memmove(Address, ptr1, len); - Address[len] = 0; - - // Could have surrounding "" "" - - if (Address[0] == '"') - { - int len = (int)strlen(Address) - 1; - - if (Address[len] == '"') - { - Address[len] = 0; - memmove(Address, &Address[1], len); - return 0; - } - - // Thunderbird can put "" round part of address "rms:john.wiseman"@cantab.net - - ptr2 = strchr(&Address[1], '"'); - - if (ptr2) - { - memmove(Address, &Address[1], ptr2 - &Address[1]); - memmove(ptr2 - 1, ptr2 + 1, strlen(ptr2 + 1) + 1); - - } - - - } - - return 0; - } - - ptr1 = Address; - - while (*ptr1 == ' ') ptr1++; - - if (*ptr1 == '"') - { - ptr1++; - ptr1=strlop(ptr1, '"'); - ptr2=strlop(ptr1, ' '); - ptr1=ptr2; - } - - if (*ptr1 == '<') ptr1++; - - ptr2 = strlop(ptr1, '>'); - strlop(ptr1, ' '); - - len = strlen(ptr1); - memmove(Address, ptr1, len); - Address[len] = 0; - - return 0; -} -/* -+OK POP3 server ready -USER john.wiseman -+OK please send PASS command -PASS gb7bpq -+OK john.wiseman is welcome here -STAT -+OK 6 115834 - -UIDL -+OK 6 messages -1 <4A0DC6E0.5020504@hb9bza.net> -2 -3 <1085101c9d5d0$09b15420$16f9280a@phx.gbl> -4 -5 -6 <20090516011401.53DB013804@panix1.panix.com> -. -LIST -+OK 6 messages -1 7167 -2 10160 -3 52898 -4 4746 -5 20218 -6 20645 -. - -*/ - -VOID ProcessPOP3ServerMessage(SocketConn * sockptr, char * Buffer, int Len) -{ - SOCKET sock; - int i; - struct MsgInfo * Msg; - - sock=sockptr->socket; - - WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP); - - if(memcmp(Buffer, "CAPA",4) == 0) - { - SendSock(sockptr, "+OK Capability list follows"); - SendSock(sockptr, "UIDL"); - SendSock(sockptr, "TOP"); - SendSock(sockptr, "EXPIRE 30"); - SendSock(sockptr, "."); - return; - } - - if(memcmp(Buffer, "AUTH",4) == 0) - { - SendSock(sockptr, "-ERR"); - return; - } - if (sockptr->State == GettingUser) - { - - Buffer[Len-2]=0; - if (Len > 15) Buffer[15]=0; - - strcpy(sockptr->CallSign, &Buffer[5]); - - sockptr->State = GettingPass; - SendSock(sockptr, "+OK please send PASS command"); - return; - } - - if (sockptr->State == GettingPass) - { - struct UserInfo * user = NULL; - - Buffer[Len-2]=0; - user = LookupCall(sockptr->CallSign); - - if (user) - { - if (strcmp(user->pass, &Buffer[5]) == 0) - { - if (user->POP3Locked) - { - SendSock(sockptr, "-ERR Mailbox Locked"); - sockptr->State = 0; - return; - } - - sockptr->State = Authenticated; - SendSock(sockptr, "+OK Authenticated"); - - sockptr->POP3User = user; - user->POP3Locked = TRUE; - - // Get Message List - - for (i=0; i<=NumberofMessages; i++) - { - Msg = MsgHddrPtr[i]; - - if ((_stricmp(Msg->to, sockptr->CallSign) == 0) || - ((_stricmp(Msg->to, "SYSOP") == 0) && (user->flags & F_SYSOP) && (Msg->type == 'P'))) - { - if (Msg->status != 'K' && Msg->status != 'H') - { - sockptr->POP3Msgs = realloc(sockptr->POP3Msgs, (sockptr->POP3MsgCount+1) * sizeof(void *)); - sockptr->POP3Msgs[sockptr->POP3MsgCount++] = MsgHddrPtr[i]; - } - } - } - - return; - } - } - - SendSock(sockptr, "-ERR Authentication failed"); - sockptr->State = 0; - return; - } - - if (memcmp(Buffer, "QUIT",4) == 0) - { - SendSock(sockptr, "+OK Finished"); - - if (sockptr->POP3User) - sockptr->POP3User->POP3Locked = FALSE; - - return; - } - - if (memcmp(Buffer, "NOOP",4) == 0) - { - SendSock(sockptr, "+OK "); - return; - } - -// if (memcmp(Buffer, "LAST",4) == 0) -// { -// SendSock(sockptr, "+OK 0"); -// return; -// } - - if (sockptr->State != Authenticated) - { - SendSock(sockptr, "-ERR Need Authentication"); - sockptr->State = 0; - return; - } - - if (memcmp(Buffer, "STAT",4) == 0) - { - char reply[40]; - int i, size=0; - - for (i=0; i< sockptr->POP3MsgCount; i++) - { - size+=sockptr->POP3Msgs[i]->length; - } - - sprintf_s(reply, sizeof(reply), "+OK %d %d", sockptr->POP3MsgCount, size); - - SendSock(sockptr, reply); - return; - } - - if (memcmp(Buffer, "UIDL",4) == 0) - { - char reply[40]; - int i, count=0, size=0; - int MsgNo=1; - - SendSock(sockptr, "+OK "); - - for (i=0; i< sockptr->POP3MsgCount; i++) - { - sprintf_s(reply, sizeof(reply), "%d %s", i+1, sockptr->POP3Msgs[i]->bid); - SendSock(sockptr, reply); - } - - SendSock(sockptr, "."); - return; - } - - if (memcmp(Buffer, "LIST", 4) == 0) - { - char reply[40]; - int i, count=0, size=0; - int MsgNo = atoi(&Buffer[4]); - - if (Buffer[4] == 13) // CR - MsgNo = 0; - - Debugprintf("%s %d", Buffer, MsgNo); - - if (MsgNo) - { - if (MsgNo > sockptr->POP3MsgCount) - sprintf(reply, "-ERR no such message, only %d messages in maildrop", sockptr->POP3MsgCount); - else - sprintf(reply, "+OK %d %d", MsgNo, sockptr->POP3Msgs[MsgNo - 1]->length); - SendSock(sockptr, reply); - return; - } - - - SendSock(sockptr, "+OK "); - - for (i=0; i< sockptr->POP3MsgCount; i++) - { - sprintf_s(reply, sizeof(reply), "%d %d", i+1, sockptr->POP3Msgs[i]->length); - SendSock(sockptr, reply); - } - - SendSock(sockptr, "."); - return; - } - - if (memcmp(Buffer, "RETR", 4) == 0 || memcmp(Buffer, "TOP", 3) == 0) - { - char * ptr; - char Header[120]; - int i, count=0, size=0; - int MsgNo=1; - char * msgbytes; - struct MsgInfo * Msg; - char B2From[80]; - struct UserInfo * FromUser; - char TimeString[64]; - BOOL TOP = FALSE; - int Len; - - if (memcmp(Buffer, "TOP", 3) == 0) - TOP = TRUE; - - ptr=strlop(Buffer, ' '); // Get Number - - i=atoi(ptr); - - if ((i > sockptr->POP3MsgCount) || (i == 0)) - { - SendSock(sockptr, "-ERR no such message"); - return; - } - - Msg = sockptr->POP3Msgs[i-1]; - - msgbytes = ReadMessageFile(Msg->number); - - if (msgbytes == NULL) - { - SendSock(sockptr, "-ERR no such message"); - return; - } - - SendSock(sockptr, "+OK "); - - // Build an RFC822 ish header - -//Received: from [69.147.65.148] by n15.bullet.sp1.yahoo.com with NNFMP; 16 May 2009 02:30:47 -0000 -//Received: from [69.147.108.192] by t11.bullet.mail.sp1.yahoo.com with NNFMP; 16 May 2009 02:30:47 -0000 - - FormatTime(TimeString, (time_t)Msg->datecreated); - - sprintf_s(Header, sizeof(Header), "Date: %s", TimeString); - SendSock(sockptr, Header); - - sprintf_s(Header, sizeof(Header), "To: %s", Msg->to); - SendSock(sockptr, Header); - - sprintf_s(Header, sizeof(Header), "Message-ID: %s", Msg->bid); - SendSock(sockptr, Header); - - if (_stricmp(Msg->from, "smtp:") == 0) - { - sprintf_s(Header, sizeof(Header), "From: smtp/%s", Msg->emailfrom); - SendSock(sockptr, Header); - sprintf_s(Header, sizeof(Header), "Replyto: smtp/%s", Msg->emailfrom); - } - else - { - if (_stricmp(Msg->from, "rms:") == 0) - { - sprintf_s(Header, sizeof(Header), "From: RMS/%s", Msg->emailfrom); - SendSock(sockptr, Header); - sprintf_s(Header, sizeof(Header), "Replyto: RMS/%s", Msg->emailfrom); - } - else - { - // If there is an adddress in Msg->emailfrom use it - - if (Msg->emailfrom[0]) - { - strcpy(B2From, Msg->from); - strcat(B2From, Msg->emailfrom); - } - else - { - // Packet Address. Mail client will need more than just a call to respond to - - strcpy(B2From, Msg->from); - - if (strcmp(Msg->from, "SMTP:") == 0) // Address is in via - strcpy(B2From, Msg->emailfrom); - else - { - FromUser = LookupCall(Msg->from); - - if (FromUser) - { - if (FromUser->HomeBBS[0]) - sprintf(B2From, "%s@%s", Msg->from, FromUser->HomeBBS); - else - sprintf(B2From, "%s@%s", Msg->from, BBSName); - } - else - { - WPRecP WP = LookupWP(Msg->from); - if (WP) - sprintf(B2From, "%s@%s", Msg->from, WP->first_homebbs); - } - } - } - sprintf_s(Header, sizeof(Header), "From: %s", B2From); - SendSock(sockptr, Header); - sprintf_s(Header, sizeof(Header), "Replyto: %s", B2From); - } - } - SendSock(sockptr, Header); - sprintf_s(Header, sizeof(Header), "Subject: %s", Msg->title); - SendSock(sockptr, Header); - - if ((Msg->B2Flags & Attachments) && TOP == FALSE) - { - // B2 Message with Attachments. Create a Mime-Encoded Multipart message - - SendMultiPartMessage(sockptr, Msg, msgbytes); - return; - } - - if (TOP) - { - // Get first i lines of message - - char * ptr1, * ptr2; - - ptr = strlop(ptr, ' '); // Get Number of lines - i = atoi(ptr); - - ptr1 = msgbytes; - ptr2 = --ptr1; // Point both to char before message - - while(i--) - { - ptr2 = strchr(++ptr1, 10); - - if (ptr2 == 0) // No more lines - i = 0; - - ptr1 = ptr2; - } - if (ptr2) - *(ptr2 + 1) = 0; - } - - // If message has characters above 7F convert to UFT8 if necessary and send as Base64 - - Len = (int)strlen(msgbytes); - - if (Is8Bit(msgbytes, Len)) - { - // 8 Bit. Will send as UFT8 - - if (WebIsUTF8(msgbytes, Len) == FALSE) - { - // Must be some other coding - - int code = TrytoGuessCode(msgbytes, Len); - UCHAR * UTF = malloc(Len * 3); - - if (code == 437) - Len = Convert437toUTF8(msgbytes, Len, UTF); - else if (code == 1251) - Len = Convert1251toUTF8(msgbytes, Len, UTF); - else - Len = Convert1252toUTF8(msgbytes, Len, UTF); - - free(msgbytes); - msgbytes = UTF; - } - - SendSock(sockptr, "Content-Type: text/plain; charset=\"utf-8\""); - SendSock(sockptr, "Content-Transfer-Encoding: base64"); - SendSock(sockptr, "Content-Disposition: inline"); - - SendSock(sockptr, ""); // Blank line before body - - Base64EncodeAndSend(sockptr, msgbytes, Len); - - } - else - { - // send as USASCII - - SendSock(sockptr, ""); // Blank line before body - SendSock(sockptr, msgbytes); - } - - SendSock(sockptr, ""); - SendSock(sockptr, "."); - - free(msgbytes); - return; - } - - - if (memcmp(Buffer, "DELE",4) == 0) - { - char * ptr; - int i; - struct MsgInfo * Msg; - - ptr=strlop(Buffer, ' '); // Get Number - - i=atoi(ptr); - - if ((i > sockptr->POP3MsgCount) || (i == 0)) - { - SendSock(sockptr, "-ERR no such message"); - return; - } - - Msg = sockptr->POP3Msgs[i-1]; - - FlagAsKilled(Msg, TRUE); - - SendSock(sockptr, "+OK "); - return; - } - - - if (memcmp(Buffer, "QUIT",4) == 0) - { - SendSock(sockptr, "+OK Finished"); - - if (sockptr->POP3User) - sockptr->POP3User->POP3Locked = FALSE; - - return; - } - - SendSock(sockptr, "-ERR Unrecognised Command"); - -} - - - -/* jer: - * This is the original file, my mods were only to change the name/semantics on the b64decode function - * and remove some dependencies. - */ -/* - LibCGI base64 manipulation functions is extremly based on the work of Bob Tower, - from its projec http://base64.sourceforge.net. The functions were a bit modicated. - Above is the MIT license from b64.c original code: - -LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated - documentation files (the "Software"), to deal in the - Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, - sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, - subject to the following conditions: - - The above copyright notice and this permission notice shall - be included in all copies or substantial portions of the - Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS - OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR - OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE - -*/ -void encodeblock( unsigned char in[3], unsigned char out[4], int len ) -{ - out[0] = cb64[ in[0] >> 2 ]; - out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; - out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='); - out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '='); -} - -void decodeblock( unsigned char in[4], unsigned char out[3]) -{ - char Block[5]; - - Block[0]=mycd64[in[0]]; - Block[1]=mycd64[in[1]]; - Block[2]=mycd64[in[2]]; - Block[3]=mycd64[in[3]]; - - out[0] = (unsigned char ) (Block[0] << 2 | Block[1] >> 4); - out[1] = (unsigned char ) (Block[1] << 4 | Block[2] >> 2); - out[2] = (unsigned char ) (((Block[2] << 6) & 0xc0) | Block[3]); -} - -/** -* @ingroup libcgi_string -* @{ -*/ - -/** -* Encodes a given tring to its base64 form. -* -* @param *str String to convert -* @return Base64 encoded String -* @see str_base64_decode -**/ -char *str_base64_encode(char *str) -{ - unsigned int i = 0, j = 0, len = (int)strlen(str); - char *tmp = str; - char *result = (char *)zalloc((len+1) * sizeof(void *)); - - if (!result) - return NULL; - - while (len > 2 ) - { - encodeblock(&str[i], &result[j],3); - i+=3; - j+=4; - len -=3; - } - if (len) - { - encodeblock(&str[i], &result[j], len); - } - - return result; -} - -SocketConn * SMTPConnect(char * Host, int Port, BOOL AMPR, struct MsgInfo * Msg, char * MsgBody) -{ - int err; - u_long param=1; - BOOL bcopt=TRUE; - - SocketConn * sockptr; - - SOCKADDR_IN sinx; - SOCKADDR_IN destaddr; - int addrlen=sizeof(sinx); - struct hostent * HostEnt; - - // Resolve Name if needed - - destaddr.sin_family = AF_INET; - destaddr.sin_port = htons(Port); - - destaddr.sin_addr.s_addr = inet_addr(Host); - - if (destaddr.sin_addr.s_addr == INADDR_NONE) - { - // Resolve name to address - - HostEnt = gethostbyname (Host); - - if (!HostEnt) - { - Logprintf(LOG_TCP, NULL, '|', "Resolve Failed for SMTP Server %s", Host); - SMTPActive = FALSE; - return FALSE; // Resolve failed - } - memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4); - } - -// Allocate a Socket entry - - sockptr=malloc(sizeof(SocketConn)); - memset(sockptr, 0, sizeof (SocketConn)); - - sockptr->Next=Sockets; - Sockets=sockptr; - - sockptr->socket=socket(AF_INET,SOCK_STREAM,0); - - if (sockptr->socket == INVALID_SOCKET) - { - return FALSE; - } - - sockptr->Type = SMTPClient; - sockptr->AMPR = AMPR; - - if (AMPR) - strcpy(sockptr->FromDomain, AMPRDomain); - else - strcpy(sockptr->FromDomain, MyDomain); - - sockptr->SMTPMsg = Msg; - sockptr->MailBuffer = MsgBody; - - ioctlsocket (sockptr->socket, FIONBIO, ¶m); - - setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4); - - sinx.sin_family = AF_INET; - sinx.sin_addr.s_addr = INADDR_ANY; - sinx.sin_port = 0; - - if (bind(sockptr->socket, (LPSOCKADDR) &sinx, addrlen) != 0 ) - { - // - // Bind Failed - // - - return FALSE; - } - - if (connect(sockptr->socket,(LPSOCKADDR) &destaddr, sizeof(destaddr)) == 0) - { - // - // Connected successful - // - - sockptr->State = WaitingForGreeting; - - return sockptr; - } - else - { - err=WSAGetLastError(); - - if (err == WSAEWOULDBLOCK || err == 115 || err == 36) - { - // - // Connect in Progress - // - - sockptr->State = Connecting; - return sockptr; - } - else - { - // - // Connect failed - // - - printf("SMTP Connect failed immediately\n"); - closesocket(sockptr->socket); - ReleaseSock(sockptr->socket); - return FALSE; - - return FALSE; - } - } - return FALSE; -} - -int TryHELO = 0; // Not thread safe but taking the chance.. - -VOID ProcessSMTPClientMessage(SocketConn * sockptr, char * Buffer, int Len) -{ - SOCKET sock; - - sock=sockptr->socket; - - WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP); - - Buffer[Len] = 0; - - if (sockptr->State == WaitingForGreeting) - { - if (memcmp(Buffer, "220 ",4) == 0) - { - TryHELO = 0; - - if (sockptr->AMPR) - sockprintf(sockptr, "EHLO %s", AMPRDomain); - else if (ISPEHLOName[0]) - sockprintf(sockptr, "EHLO %s", ISPEHLOName); - else - sockprintf(sockptr, "EHLO %s", BBSName); - - sockptr->State = WaitingForHELOResponse; - } - else - { - SendSock(sockptr, "QUIT"); - sockptr->State = 0; - } - - return; - } - - if (sockptr->State == WaitingForHELOResponse) - { -/* - if (memcmp(Buffer, "500 ",4) == 0 && TryHELO == 0) - { - TryHELO = 1; - - if (sockptr->AMPR) - sockprintf(sockptr, "HELO %s", AMPRDomain); - else if (ISPEHLOName[0]) - sockprintf(sockptr, "HELO %s", ISPEHLOName); - else - sockprintf(sockptr, "HELO %s", BBSName); - - return; - } -*/ - if (memcmp(Buffer, "250-",4) == 0) - return; - - if (memcmp(Buffer, "250 ",4) == 0) - { - if (SMTPAuthNeeded && sockptr->AMPR == FALSE) - { - sockprintf(sockptr, "AUTH LOGIN"); - sockptr->State = WaitingForAUTHResponse; - } - else - { - sockprintf(sockptr, "MAIL FROM: <%s@%s>", sockptr->SMTPMsg->from, sockptr->FromDomain); - sockptr->State = WaitingForFROMResponse; - } - } - else - { - SendSock(sockptr, "QUIT"); - sockptr->State = 0; - SMTPActive = FALSE; - - } - - return; - } - - if (sockptr->State == WaitingForAUTHResponse) - { - if (memcmp(Buffer, "334 VXN", 7) == 0) - { - char * Msg = str_base64_encode(ISPAccountName); - SendSock(sockptr, Msg); - free(Msg); - return; - } - else if (memcmp(Buffer, "334 UGF", 7) == 0) - { - char * Msg = str_base64_encode(ISPAccountPass); - SendSock(sockptr, Msg); - free(Msg); - return; - } - else if (memcmp(Buffer, "235 ", 4) == 0) - { - sockprintf(sockptr, "MAIL FROM: <%s@%s>", sockptr->SMTPMsg->from, sockptr->FromDomain); -// sockprintf(sockptr, "MAIL FROM: <%s@%s.%s>", sockptr->SMTPMsg->from, BBSName, HRoute); - sockptr->State = WaitingForFROMResponse; - } - - else - { - SendSock(sockptr, "QUIT"); - sockptr->State = 0; - SMTPActive = FALSE; - } - - return; - - } - - - if (sockptr->State == WaitingForFROMResponse) - { - if (memcmp(Buffer, "250 ",4) == 0) - { - sockprintf(sockptr, "RCPT TO: <%s>", sockptr->SMTPMsg->via); - sockptr->State = WaitingForTOResponse; - } - else - { - sockptr->SMTPMsg->status = 'H'; // Hold for review - SendSock(sockptr, "QUIT"); - sockptr->State = 0; - SMTPActive = FALSE; - } - - return; - } - - if (sockptr->State == WaitingForTOResponse) - { - if (memcmp(Buffer, "250 ",4) == 0) - { - SendSock(sockptr, "DATA"); - sockptr->State = WaitingForDATAResponse; - } - else - { - sockptr->SMTPMsg->status = 'H'; // Hold for review - SendSock(sockptr, "QUIT"); - sockptr->State = 0; - SMTPActive = FALSE; - } - - return; - } - - if (sockptr->State == WaitingForDATAResponse) - { - int Len; - UCHAR * UTF; - - if (memcmp(Buffer, "354 ",4) == 0) - { - sockprintf(sockptr, "To: %s", sockptr->SMTPMsg->via); - sockprintf(sockptr, "From: %s <%s@%s>", sockptr->SMTPMsg->from, sockptr->SMTPMsg->from, sockptr->FromDomain); - sockprintf(sockptr, "Sender: %s@%s", sockptr->SMTPMsg->from, sockptr->FromDomain); - if (GMailMode && sockptr->AMPR == FALSE) - sockprintf(sockptr, "Reply-To: %s+%s@%s", GMailName, sockptr->SMTPMsg->from, sockptr->FromDomain); - else - sockprintf(sockptr, "Reply-To: %s@%s", sockptr->SMTPMsg->from, sockptr->FromDomain); - - sockprintf(sockptr, "Subject: %s", sockptr->SMTPMsg->title); - - sockptr->State = WaitingForBodyResponse; - - if (sockptr->SMTPMsg->B2Flags & Attachments) - { - // B2 Message with Attachments. Create a Mime-Encoded Multipart message - - SendMultiPartMessage(sockptr, sockptr->SMTPMsg, sockptr->MailBuffer); - return; - } - - // If message has characters above 7F convert to UFT8 if necessary and send as Base64 - - - Len = (int)strlen(sockptr->MailBuffer); - - if (Is8Bit(sockptr->MailBuffer, Len)) - { - // 8 Bit. Will send as UFT8 - - SendSock(sockptr, "Content-Type: text/plain; charset=\"utf-8\""); - SendSock(sockptr, "Content-Transfer-Encoding: base64"); - SendSock(sockptr, "Content-Disposition: inline"); - - SendSock(sockptr, ""); // Blank line before body - - if (WebIsUTF8(sockptr->MailBuffer, Len) == FALSE) - { - // Must be some other coding - - int code = TrytoGuessCode(sockptr->MailBuffer, Len); - UTF = malloc(Len * 3); - - if (code == 437) - Len = Convert437toUTF8(sockptr->MailBuffer, Len, UTF); - else if (code == 1251) - Len = Convert1251toUTF8(sockptr->MailBuffer, Len, UTF); - else - Len = Convert1252toUTF8(sockptr->MailBuffer, Len, UTF); // Default - - Base64EncodeAndSend(sockptr, UTF, Len); - free(UTF); - } - else - Base64EncodeAndSend(sockptr, sockptr->MailBuffer, Len); - - } - else - { - // send as USASCII - - SendSock(sockptr, ""); // Blank line before body - SendSock(sockptr, sockptr->MailBuffer); - } - - SendSock(sockptr, "."); - - } - else - { - SendSock(sockptr, "QUIT"); - sockptr->State = 0; - SMTPActive = FALSE; - } - - return; - } - - if (sockptr->State == WaitingForBodyResponse) - { - struct MsgInfo * Msg = sockptr->SMTPMsg; - - if (memcmp(Buffer, "250 ", 4) == 0) - { - // if AMPR, clear forwarding bitmap - - if (sockptr->AMPR) - { - // Mark mail as sent, and look for more - - struct UserInfo * bbs = sockptr->bbs; - - clear_fwd_bit(Msg->fbbs, bbs->BBSNumber); - set_fwd_bit(Msg->forw, bbs->BBSNumber); - - // Only mark as forwarded if sent to all BBSs that should have it - - if (memcmp(Msg->fbbs, zeros, NBMASK) == 0) - { - Msg->status = 'F'; // Mark as forwarded - Msg->datechanged=time(NULL); - } - - bbs->ForwardingInfo->MsgCount--; - bbs->ForwardingInfo->Forwarding = 0; - - // See if any more - - if (bbs->ForwardingInfo->MsgCount) - bbs->ForwardingInfo->FwdTimer = bbs->ForwardingInfo->FwdInterval; // Reschdul send - - } - else - { - Msg->status = 'F'; - SMTPActive = FALSE; - SMTPMsgCreated=TRUE; // See if any more - } - } - - SendSock(sockptr, "QUIT"); - sockptr->State = 0; - - SMTPActive = FALSE; - - SMTPMsgCreated=TRUE; // See if any more - - return; - } -} - -BOOL SendtoAMPR(CIRCUIT * conn) -{ - struct MsgInfo * Msg = conn->FwdMsg; - SocketConn * sockptr; - - char * Body; - int toLen; - char * tocopy; - char * Host; - - // Make sure message exists - - Body = ReadMessageFile(Msg->number); - - if (Body == NULL) - { - FlagAsKilled(Msg, TRUE); - return FALSE; - } - - toLen = (int)strlen(Msg->via); - - tocopy = _strdup(Msg->via); - - Host = strlop(tocopy, '@'); - - if (Host == NULL) - { - Logprintf(LOG_TCP, NULL, '|', "AMPR Forward - Host Name missing from VIA %s for Msg %d", Msg->via, Msg->number); - free(tocopy); - return FALSE; - } - - Logprintf(LOG_TCP, NULL, '|', "Connecting to Server %s to send Msg %d", Host, Msg->number); - - sockptr = SMTPConnect(Host, 25, TRUE, Msg, Body); - - free(tocopy); - - if (sockptr) - { - sockptr->bbs = conn->UserPointer; - - return TRUE; - } - - return FALSE; -} - -BOOL SendtoISP() -{ - // Find a message intended for the Internet and send it - - int m = NumberofMessages; - char * Body; - - struct MsgInfo * Msg; - - if (SMTPActive) - return FALSE; - - do - { - Msg=MsgHddrPtr[m]; - - if ((Msg->status == 'N') && (Msg->to[0] == 0) && (Msg->from[0] != 0)) - { - // Make sure message exists - - Body = ReadMessageFile(Msg->number); - - if (Body == NULL) - { - FlagAsKilled(Msg, TRUE); - return FALSE; - } - - Logprintf(LOG_TCP, NULL, '|', "Connecting to Server %s to send Msg %d", ISPSMTPName, Msg->number); - - SMTPMsgCreated=FALSE; // Stop any more attempts - SMTPConnect(ISPSMTPName, ISPSMTPPort, FALSE, Msg, Body); - - SMTPActive = TRUE; - - return TRUE; - } - - m--; - - } while (m> 0); - - return FALSE; - -} - - -BOOL POP3Connect(char * Host, int Port) -{ - int err; - u_long param=1; - BOOL bcopt=TRUE; - - SocketConn * sockptr; - - SOCKADDR_IN sinx; - SOCKADDR_IN destaddr; - int addrlen=sizeof(sinx); - struct hostent * HostEnt; - - Logprintf(LOG_TCP, NULL, '|', "Connecting to POP3 Server %s", Host); - - // Resolve Name if needed - - destaddr.sin_family = AF_INET; - destaddr.sin_port = htons(Port); - - destaddr.sin_addr.s_addr = inet_addr(Host); - - if (destaddr.sin_addr.s_addr == INADDR_NONE) - { - // Resolve name to address - - HostEnt = gethostbyname (Host); - - if (!HostEnt) - { - Logprintf(LOG_TCP, NULL, '|', "Resolve Failed for POP3 Server %s", Host); - return FALSE; // Resolve failed - } - memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4); - } - -// Allocate a Socket entry - - sockptr = malloc(sizeof(SocketConn)); - memset(sockptr, 0, sizeof (SocketConn)); - - sockptr->Next = Sockets; - Sockets = sockptr; - - sockptr->socket = socket(AF_INET,SOCK_STREAM,0); - - if (sockptr->socket == INVALID_SOCKET) - { - return FALSE; - } - - sockptr->Type = POP3Client; - - ioctlsocket (sockptr->socket, FIONBIO, ¶m); - - setsockopt (sockptr->socket, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt,4); - - sinx.sin_family = AF_INET; - sinx.sin_addr.s_addr = INADDR_ANY; - sinx.sin_port = 0; - - if (bind(sockptr->socket, (LPSOCKADDR) &sinx, addrlen) != 0 ) - { - // - // Bind Failed - // - - return FALSE; - } - - if (connect(sockptr->socket,(LPSOCKADDR) &destaddr, sizeof(destaddr)) == 0) - { - // - // Connected successful - // - - sockptr->State = WaitingForGreeting; - - return TRUE; - } - else - { - err=WSAGetLastError(); - - if (err == WSAEWOULDBLOCK || err == 115 || err == 36) - { - // - // Connect in Progressing - // - - sockptr->State = Connecting; - return TRUE; - } - else - { - // - // Connect failed - // - - printf("Connect failed immediately %d\n", err); - perror("POP Connect"); - closesocket(sockptr->socket); - ReleaseSock(sockptr->socket); - return FALSE; - } - } - return FALSE; -} - -VOID ProcessPOP3ClientMessage(SocketConn * sockptr, char * Buffer, int Len) -{ - SOCKET sock; - time_t Date; - BOOL B2Flag; - - sock=sockptr->socket; - - WriteLogLine(NULL, '<',Buffer, Len-2, LOG_TCP); - - if (sockptr->Flags == GETTINGMESSAGE) - { - if(memcmp(Buffer, ".\r\n", 3) == 0) - { - // File Message - - char * ptr1, * ptr2; - int linelen, MsgLen; - char MsgFrom[62], MsgTo[100], Msgtitle[62]; - - // Scan headers for From: To: and Subject: Line (Headers end at blank line) - - ptr1 = sockptr->MailBuffer; - Loop: - ptr2 = strchr(ptr1, '\r'); - - if (ptr2 == NULL) - { - SendSock(sockptr, "500 Eh"); - return; - } - - linelen = (int)(ptr2 - ptr1); - - // From: "John Wiseman" - // To: - // - - - if (_memicmp(ptr1, "From:", 5) == 0) - { - if (linelen > 65) linelen = 65; - memcpy(MsgFrom, &ptr1[5], linelen-5); - MsgFrom[linelen-5]=0; - } - else - if (_memicmp(ptr1, "To:", 3) == 0) - { - if (linelen > 99) linelen = 99; - memcpy(MsgTo, &ptr1[4], linelen-4); - MsgTo[linelen-4]=0; - } - else - if (_memicmp(ptr1, "Subject:", 8) == 0) - { - if (linelen > 68) linelen = 68; - memcpy(Msgtitle, &ptr1[9], linelen-9); - Msgtitle[linelen-9]=0; - } - else - if (_memicmp(ptr1, "Date:", 5) == 0) - { - struct tm rtime; - char * Context; - char seps[] = " ,\t\r"; - char Offset[10] = ""; - int i, HH, MM; - char Copy[500]=""; - - // Copy message, so original isn't messed up by strtok - - memcpy(Copy, ptr1, linelen); - - ptr1 = Copy; - - memset(&rtime, 0, sizeof(struct tm)); - - // Date: Tue, 9 Jun 2009 20:54:55 +0100 - - ptr1 = strtok_s(&ptr1[5], seps, &Context); // Skip Day - ptr1 = strtok_s(NULL, seps, &Context); // Day - - rtime.tm_mday = atoi(ptr1); - - ptr1 = strtok_s(NULL, seps, &Context); // Month - - for (i=0; i < 12; i++) - { - if (strcmp(month[i], ptr1) == 0) - { - rtime.tm_mon = i; - break; - } - } - - sscanf(Context, "%04d %02d:%02d:%02d%s", - &rtime.tm_year, &rtime.tm_hour, &rtime.tm_min, &rtime.tm_sec, Offset); - - rtime.tm_year -= 1900; - - Date = mktime(&rtime) - (time_t)_MYTIMEZONE; - - if (Date == (time_t)-1) - Date = 0; - else - { - if ((Offset[0] == '+') || (Offset[0] == '-')) - { - MM = atoi(&Offset[3]); - Offset[3] = 0; - HH = atoi(&Offset[1]); - MM = MM + (60 * HH); - - if (Offset[0] == '+') - Date -= (60*MM); - else - Date += (60*MM); - - - } - } - } - - - if (linelen) // Not Null line - { - ptr1 = ptr2 + 2; // Skip crlf - goto Loop; - } - - ptr1 = sockptr->MailBuffer; - - TidyString(MsgFrom); - _strlwr(MsgFrom); - - MsgLen = (int)(sockptr->MailSize - (ptr2 - ptr1)); - - B2Flag = CheckforMIME(sockptr, sockptr->MailBuffer, &ptr2, &MsgLen); // Will reformat message if necessary. - - CreatePOP3Message(MsgFrom, MsgTo, Msgtitle, Date, ptr2, MsgLen, B2Flag); - - free(sockptr->MailBuffer); - sockptr->MailBufferSize=0; - sockptr->MailBuffer=0; - sockptr->MailSize = 0; - - sockptr->Flags &= ~GETTINGMESSAGE; - - if (sockptr->POP3MsgCount > sockptr->POP3MsgNum++) - { - sockprintf(sockptr, "RETR %d", sockptr->POP3MsgNum); - - sockptr->State = WaitingForRETRResponse; - } - else - { - sockptr->POP3MsgNum = 1; - sockprintf(sockptr, "DELE %d", sockptr->POP3MsgNum);; - sockptr->State = WaitingForDELEResponse; - } - - return; - } - - if ((sockptr->MailSize + Len) > sockptr->MailBufferSize) - { - sockptr->MailBufferSize += 10000; - sockptr->MailBuffer = realloc(sockptr->MailBuffer, sockptr->MailBufferSize); - - if (sockptr->MailBuffer == NULL) - { - CriticalErrorHandler("Failed to extend Message Buffer"); - shutdown(sock, 0); - return; - } - } - - memcpy(&sockptr->MailBuffer[sockptr->MailSize], Buffer, Len); - sockptr->MailSize += Len; - - return; - } - - if (sockptr->State == WaitingForGreeting) - { - if (memcmp(Buffer, "+OK", 3) == 0) - { - sockprintf(sockptr, "USER %s", ISPAccountName); - sockptr->State = WaitingForUSERResponse; - } - else - { - SendSock(sockptr, "QUIT"); - sockptr->State = 0; - } - - return; - } - - if (sockptr->State == WaitingForUSERResponse) - { - if (memcmp(Buffer, "+OK", 3) == 0) - { - sockprintf(sockptr, "PASS %s", ISPAccountPass); - sockptr->State = WaitingForPASSResponse; - } - else - { - SendSock(sockptr, "QUIT"); - sockptr->State = WaitingForQUITResponse; - } - - return; - } - - if (sockptr->State == WaitingForPASSResponse) - { - if (memcmp(Buffer, "+OK", 3) == 0) - { - SendSock(sockptr, "STAT"); - sockptr->State = WaitingForSTATResponse; - } - else - { - shutdown(sock, 0); - sockptr->State = 0; - } - - return; - } - - if (sockptr->State == WaitingForSTATResponse) - { - if (memcmp(Buffer, "+OK", 3) == 0) - { - int Msgs = atoi(&Buffer[3]); - - if (Msgs > 0) - { - sockptr->POP3MsgCount = Msgs; - sockptr->POP3MsgNum = 1; - SendSock(sockptr, "RETR 1"); - - sockptr->State = WaitingForRETRResponse; - - } - else - { - SendSock(sockptr, "QUIT"); - sockptr->State = WaitingForQUITResponse; - } - } - else - { - SendSock(sockptr, "QUIT"); - sockptr->State = WaitingForQUITResponse; - } - - return; - } - - if (sockptr->State == WaitingForRETRResponse) - { - if (memcmp(Buffer, "+OK", 3) == 0) - { - sockptr->MailBuffer=malloc(10000); - sockptr->MailBufferSize=10000; - - if (sockptr->MailBuffer == NULL) - { - CriticalErrorHandler("Failed to create POP3 Message Buffer"); - SendSock(sockptr, "QUIT"); - sockptr->State = WaitingForQUITResponse; - shutdown(sock, 0); - - return; - } - - sockptr->Flags |= GETTINGMESSAGE; - - } - else - { - SendSock(sockptr, "QUIT"); - sockptr->State = WaitingForQUITResponse; - } - - return; - } - if (sockptr->State == WaitingForDELEResponse) - { - if (memcmp(Buffer, "+OK", 3) == 0) - { - if (sockptr->POP3MsgCount > sockptr->POP3MsgNum++) - { - sockprintf(sockptr, "DELE %d", sockptr->POP3MsgNum);; - } - else - { - SendSock(sockptr, "QUIT"); - sockptr->Flags = WaitingForQUITResponse; - } - } - else - { - shutdown(sock,0); - sockptr->State = 0; - } - return; - } - - if (sockptr->State == WaitingForQUITResponse) - { - shutdown(sock,0); - sockptr->State = 0; - return; - } - - SendSock(sockptr, "QUIT"); - shutdown(sock,0); - sockptr->State = 0; - -} - -static char Winlink[] = "WINLINK.ORG"; - -int CreatePOP3Message(char * From, char * To, char * MsgTitle, time_t Date, char * MsgBody, int MsgLen, BOOL B2Flag) -{ - struct MsgInfo * Msg; - BIDRec * BIDRec; - - // Allocate a message Record slot - - Msg = AllocateMsgRecord(); - - // Set number here so they remain in sequence - - Msg->number = ++LatestMsg; - MsgnotoMsg[Msg->number] = Msg; - Msg->length = MsgLen; - - - sprintf_s(Msg->bid, sizeof(Msg->bid), "%d_%s", LatestMsg, BBSName); - - Msg->type = 'P'; - Msg->status = 'N'; - Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL); - - if (Date) - Msg->datecreated = Date; - - BIDRec = AllocateBIDRecord(); - - strcpy(BIDRec->BID, Msg->bid); - BIDRec->mode = Msg->type; - BIDRec->u.msgno = LOWORD(Msg->number); - BIDRec->u.timestamp = LOWORD(time(NULL)/86400); - - - TidyString(To); - strlop(To, '@'); - - // Could have surrounding "" "" - - if (To[0] == '"') - { - int len = (int)strlen(To) - 1; - - if (To[len] == '"') - { - To[len] = 0; - memmove(To, &To[1], len); - } - } - - if (GMailMode) - { - // + separates our address and the target user - - char * GMailto; - - GMailto = strlop(To,'+'); - - if (GMailto) - { - char * GmailVia = NULL; - - strcpy(To, GMailto); - GmailVia = strlop(To, '|'); - - if (GmailVia) - strcpy(Msg->via, GmailVia); - } - else - { - // Someone has sent to the GMAIL account without a +. - // This should go to the BBS Call - - strcpy(To, BBSName); - } - } - - if ((_memicmp(To, "bull/", 5) == 0) || (_memicmp(To, "bull.", 5) == 0) - || (_memicmp(To, "bull:", 5) == 0)) - { - Msg->type = 'B'; - memmove(To, &To[5], strlen(&To[4])); - } - - if ((_memicmp(To, "nts/", 4) == 0) || (_memicmp(To, "nts.", 4) == 0) - || (_memicmp(To, "nts:", 4) == 0)) - { - Msg->type = 'T'; - memmove(To, &To[4], strlen(&To[3])); - } - - if (Msg->type == 'P' && Msg->via[0] == 0) - { - // No via - add one from HomeBBS or WP - - struct UserInfo * ToUser = LookupCall(To); - - if (ToUser) - { - // Local User. If Home BBS is specified, use it - - if (ToUser->flags & F_RMSREDIRECT) - { - // sent to Winlink - - strcpy(Msg->via, Winlink); - } - else if (ToUser->HomeBBS[0]) - strcpy(Msg->via, ToUser->HomeBBS); - } - else - { - WPRec * WP = LookupWP(To); - - if (WP) - strcpy(Msg->via, WP->first_homebbs); - } - } - -/* if (_memicmp(To, "rms:", 4) == 0) - { - via = _strlwr(strlop(To, ':')); - } - else if (_memicmp(To, "rms/", 4) == 0) - { - via = _strlwr(strlop(To, '/')); - } - else if (_memicmp(To, "rms.", 4) == 0) - { - via = _strlwr(strlop(To, '.')); - } -*/ - - - if (strlen(To) > 6) To[6]=0; - - strcpy(Msg->to, To); - strcpy(Msg->from, "smtp:"); - strcpy(Msg->emailfrom, From); - strcpy(Msg->title, MsgTitle); - - if(Msg->to[0] == 0) - SMTPMsgCreated=TRUE; - - if (B2Flag) - { - char B2Hddr[1000]; - int B2HddrLen; - char B2To[80]; - char * NewBody; - 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"); - - - tm = gmtime(&Date); - - sprintf(DateString, "%04d/%02d/%02d %02d:%02d", - tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); - - - if (strcmp(Msg->to, "RMS") == 0) // Address is in via - strcpy(B2To, Msg->via); - else - if (Msg->via[0]) - sprintf(B2To, "%s@%s", Msg->to, Msg->via); - else - strcpy(B2To, Msg->to); - - - Msg->B2Flags = B2Msg | Attachments; - - B2HddrLen = sprintf(B2Hddr, - "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, B2To, Msg->title, BBSName); - - NewBody = MsgBody - B2HddrLen; - - memcpy(NewBody, B2Hddr, B2HddrLen); - - Msg->length += B2HddrLen; - - // Set up forwarding bitmap - - MatchMessagetoBBSList(Msg, 0); - - return CreateSMTPMessageFile(NewBody, Msg); - } - - // Set up forwarding bitmap - - MatchMessagetoBBSList(Msg, 0); - - return CreateSMTPMessageFile(MsgBody, Msg); - -} - -VOID base64_encode(char *str, char * result, int len) -{ - unsigned int i = 0, j = 0; - char *tmp = str; - - - while (len > 2 ) - { - encodeblock(&str[i], &result[j],3); - i+=3; - j+=4; - len -=3; - } - if (len) - { - encodeblock(&str[i], &result[j], len); - } - - return; -} - -void Base64EncodeAndSend(SocketConn * sockptr, UCHAR * Msg, int Len) -{ - char Base64Line[80]; - int i = Len; - int j = 0; - - Base64Line[76] = 13; - Base64Line[77] = 10; - Base64Line[78] = 0; - - // Need to encode in 57 byte chunks to give 76 char lines. - - while(i > 57) - { - base64_encode(&Msg[j], Base64Line, 57); - SendSock(sockptr, Base64Line); - - j += 57; - i -= 57; - } - - memset(Base64Line, 0, 79); - - base64_encode(&Msg[j], Base64Line, i); - SendSock(sockptr, Base64Line); - SendSock(sockptr, ""); -} - -VOID SendMultiPartMessage(SocketConn * sockptr, struct MsgInfo * Msg, UCHAR * msgbytes) -{ - char * ptr; - char Header[120]; - char Separator[33]=""; - char FileName[100][250] = {""}; - int FileLen[100]; - int Files = 0; - int BodyLen; - int i; - - CreateOneTimePassword(&Separator[0], "Key", 0); - CreateOneTimePassword(&Separator[16], "Key", 1); - - SendSock(sockptr, "MIME-Version: 1.0"); - - sprintf_s(Header, sizeof(Header), "Content-Type: multipart/mixed; boundary=\"%s\"", Separator); - SendSock(sockptr, Header); - - SendSock(sockptr, ""); // Blank line before body - -// Get Part Sizes and Filenames - - ptr = msgbytes; - - while(*ptr != 13) - { - char * ptr2 = strchr(ptr, 10); // Find CR - - if (memcmp(ptr, "Body: ", 6) == 0) - { - BodyLen = atoi(&ptr[6]); - } - - if (memcmp(ptr, "File: ", 6) == 0) - { - char * ptr1 = strchr(&ptr[6], ' '); // Find Space - - FileLen[Files] = atoi(&ptr[6]); - - memcpy(FileName[Files++], &ptr1[1], (ptr2-ptr1 - 2)); - } - - ptr = ptr2; - ptr++; - } - - ptr += 2; // Over Blank Line - - // Write the none-Mime Part - - SendSock(sockptr, "This is a multi-part message in MIME format."); - SendSock(sockptr, ""); - - // Write the Body as the first part. - - sprintf_s(Header, sizeof(Header), "--%s", Separator); - SendSock(sockptr, Header); - SendSock(sockptr, "Content-Type: text/plain"); - SendSock(sockptr, ""); - - ptr[BodyLen] = 0; - - SendSock(sockptr, ptr); - - ptr += BodyLen; // to first file - ptr += 2; // Over Blank Line - - // Write Each Attachment - - for (i = 0; i < Files; i++) - { - sprintf_s(Header, sizeof(Header), "--%s", Separator); - SendSock(sockptr, Header); -// Content-Type: image/png; name="UserParams.png" - SendSock(sockptr, "Content-Transfer-Encoding: base64"); - - sprintf_s(Header, sizeof(Header), "Content-Disposition: attachment; filename=\"%s\"", FileName[i]); - SendSock(sockptr, Header); - - SendSock(sockptr, ""); - - // base64 encode and send file - - Base64EncodeAndSend(sockptr, ptr, FileLen[i]); - - ptr += FileLen[i]; - ptr +=2; // Over separator - } - - sprintf_s(Header, sizeof(Header), "--%s--", Separator); - SendSock(sockptr, Header); - - SendSock(sockptr, ""); - SendSock(sockptr, "."); - - free(msgbytes); - - return; -} - -BOOL SendAMPRSMTP(CIRCUIT * conn) -{ - struct UserInfo * bbs = conn->UserPointer; - - while (FindMessagestoForward(conn)) - { - if (SendtoAMPR(conn)) - { - bbs->ForwardingInfo->Forwarding = TRUE; - return TRUE; - } - } - - bbs->ForwardingInfo->Forwarding = FALSE; - return FALSE; -} - diff --git a/Moncode.c b/Moncode.c index 762fd6d..091229e 100644 --- a/Moncode.c +++ b/Moncode.c @@ -163,7 +163,6 @@ int IntDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, uint64_t Mask, BO int Port; int MSGFLAG = 0; //CR and V1 flags char * Output = buffer; - int HH, MM, SS; char TR = 'R'; char From[10], To[10]; BOOL Info = 0; @@ -173,6 +172,15 @@ int IntDecodeFrame(MESSAGE * msg, char * buffer, time_t Stamp, uint64_t Mask, BO size_t MsgLen = msg->LENGTH; + // Use gmtime so we can also display in local time + + struct tm * TM; + + if (MTX & 0x80) + TM = localtime(&Stamp); + else + TM = gmtime(&Stamp); + // MINI mode is for Node Listen (remote monitor) Mode. Keep info to minimum /* KO6IZ*>K7TMG-1: @@ -190,7 +198,7 @@ KC6OAR*>ID: if (Port & 0x80) { - if (MTX == 0) + if ((MTX & 1) == 0) return 0; // TRANSMITTED FRAME - SEE IF MTX ON TR = 'T'; @@ -214,17 +222,9 @@ KC6OAR*>ID: // Need Timestamp and T/R - Stamp = Stamp % 86400; // Secs - HH = (int)(Stamp / 3600); - - Stamp -= HH * 3600; - MM = (int)(Stamp / 60); - - SS = (int)(Stamp - MM * 60); - // Add Port: unless Mail Mon (port 64) - Output += sprintf((char *)Output, "%02d:%02d:%02d%c ", HH, MM, SS, TR); + Output += sprintf((char *)Output, "%02d:%02d:%02d%c ", TM->tm_hour, TM->tm_min, TM->tm_sec, TR); strcpy(Output, &msg->DEST[1]); Output += strlen(Output); @@ -286,18 +286,10 @@ KC6OAR*>ID: } - Stamp = Stamp % 86400; // Secs - HH = (int)(Stamp / 3600); - - Stamp -= HH * 3600; - MM = (int)(Stamp / 60); - - SS = (int)(Stamp - MM * 60); - // Add Port: if MINI mode and monitoring more than one port if (MINI == 0) - Output += sprintf((char *)Output, "%02d:%02d:%02d%c ", HH, MM, SS, TR); + Output += sprintf((char *)Output, "%02d:%02d:%02d%c ", TM->tm_hour, TM->tm_min, TM->tm_sec, TR); else if (CountBits64(Mask) > 1) Output += sprintf((char *)Output, "%d:", Port); diff --git a/PCBeep.wav b/PCBeep.wav new file mode 100644 index 0000000..8ff2dd9 Binary files /dev/null and b/PCBeep.wav differ diff --git a/QtTermTCP.ini b/QtTermTCP.ini deleted file mode 100644 index c82399f..0000000 --- a/QtTermTCP.ini +++ /dev/null @@ -1,120 +0,0 @@ -[General] -HostParams0=|0|||| -HostParams1=|0|||| -HostParams2=|0|||| -HostParams3=|0|||| -HostParams4=|0|||| -HostParams5=|0|||| -HostParams6=|0|||| -HostParams7=|0|||| -HostParams8=|0|||| -HostParams9=|0|||| -HostParams10=|0|||| -HostParams11=|0|||| -HostParams12=|0|||| -HostParams13=|0|||| -HostParams14=|0|||| -HostParams15=|0|||| -Split=50 -ChatMode=1 -AutoTeletext=0 -Bells=1 -StripLF=1 -AlertBeep=1 -ConnectBeep=1 -AlertInterval=300 -CurrentHost=0 0 0 0 0 0 0 0 0 0 -YAPPPath= -MaxRXSize=100000 -listenPort=8015 -listenEnable=0 -listenCText= -convUTF8=0 -PTT=None -PTTBAUD=19200 -PTTMode=19200 -CATHex=1 -PTTOffString= -PTTOnString= -pttGPIOPin=17 -pttGPIOPinR=17 -CM108Addr=0xD8C:0x08 -HamLibPort=4532 -HamLibHost=127.0.0.1 -FLRigPort=12345 -FLRigHost=127.0.0.1 -AGWEnable=0 -AGWMonEnable=0 -AGWTermCall= -AGWBeaconDest= -AGWBeaconPath= -AGWBeaconInterval=0 -AGWBeaconPorts= -AGWBeaconText= -AGWHost=127.0.0.1 -AGWPort=8000 -AGWPaclen=80 -AGWToCalls= -KISSEnable=0 -MYCALL= -KISSHost=127.0.0.1 -KISSMode=0 -KISSPort=8100 -KISSSerialPort=None -KISSBAUD=19200 -VARAEnable=0 -VARATermCall= -VARAHost=127.0.0.1 -VARAPort=8300 -VARAInit= -VARAPath=C:\\VARA\\VARA.exe -VARAHostHF=127.0.0.1 -VARAPortHF=8300 -VARAPathHF=C:\\VARA\\VARA.exe -VARAHostFM=127.0.0.1 -VARAPortFM=8300 -VARAPathFM=C:\\VARA\\VARAFM.exe -VARAHostSAT=127.0.0.1 -VARAPortSAT=8300 -VARAPathSAT=C:\\VARA\\VARASAT.exe -VARA500=0 -VARA2300=1 -VARA2750=0 -VARAHF=1 -VARAFM=0 -VARASAT=0 -TabType=1 1 1 1 1 1 1 2 2 0 -AutoConnect=0 0 0 0 0 0 0 0 0 0 -monBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) -monRxText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\xff\xff\0\0) -monTxText=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\0\0\0\0\0\0) -monOtherText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) -termBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) -outputText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\xff\xff\0\0) -EchoText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) -WarningText=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\0\0\0\0\0\0) -inputBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) -inputText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) -useBeep=false -geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x2\x39\0\0\0\xab\0\0\x5\x45\0\0\x3\x64\0\0\x2\x39\0\0\0\xab\0\0\x5\x45\0\0\x3\x64\0\0\0\0\0\0\0\0\a\x80\0\0\x2\x39\0\0\0\xab\0\0\x5\x45\0\0\x3\x64) -windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\x3\r\0\0\x2\xa4\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x3\0\0\0\x1\0\0\0\x16\0m\0\x61\0i\0n\0T\0o\0o\0l\0\x62\0\x61\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0) -ConnectWAV=C:/OneDrive/Dev/Source/bpq32/CommonSource/Ring.wav - -[AX25_A] -Retries=10 -Maxframe=4 -Paclen=128 -FrackTime=8 -IdleTime=180 -SlotTime=100 -Persist=128 -RespTime=1500 -TXFrmMode=1 -FrameCollector=6 -ExcludeCallsigns= -ExcludeAPRSFrmType= -KISSOptimization=0 -DynamicFrack=0 -BitRecovery=0 -IPOLL=80 -MyDigiCall= diff --git a/RigControl.c b/RigControl.c index 57761a4..77b1ffe 100644 --- a/RigControl.c +++ b/RigControl.c @@ -2230,7 +2230,7 @@ DllExport BOOL APIENTRY Rig_Init() TNC->ClientHeight = NeedRig * 20 + 60; TNC->ClientWidth = 550; - for (port = 0; port < 33; port++) + for (port = 0; port < MAXBPQPORTS; port++) { if (RadioConfigMsg[port]) { @@ -2263,7 +2263,7 @@ DllExport BOOL APIENTRY Rig_Init() struct TNCINFO * PTCTNC; int n; - for (n = 1; n < 33; n++) + for (n = 1; n < MAXBPQPORTS; n++) { PTCTNC = TNCInfo[n]; @@ -2346,7 +2346,6 @@ DllExport BOOL APIENTRY Rig_Init() { SDRANGELRunning = 1; ConnecttoSDRANGEL(PORT); - } //---- G7TAJ ---- else if (PORT->HIDDevice) // This is RAWHID, Not CM108 @@ -2363,6 +2362,15 @@ DllExport BOOL APIENTRY Rig_Init() } else PORT->hPTTDevice = PORT->hDevice; // Use same port for PTT + + + // Looks like FT847 Needa a "Cat On" Command. If PTC port need to send it here + + if (PORT->PTC && strcmp(PORT->Rigs[0].RigName, "FT847") == 0) + { + UCHAR CATON[6] = {0,0,0,0,0}; + SendPTCRadioCommand(PORT->PTC, CATON, 5); + } } for (p = 0; p < NumberofPorts; p++) @@ -2573,7 +2581,7 @@ DllExport BOOL APIENTRY Rig_Close() // And free the TNC config info - for (p = 1; p < 33; p++) + for (p = 1; p < MAXBPQPORTS; p++) { TNC = TNCInfo[p]; @@ -2788,7 +2796,6 @@ int OpenRigCOMMPort(struct RIGPORTINFO * PORT, VOID * Port, int Speed) COMClearDTR(PORT->hDevice); else COMSetDTR(PORT->hDevice); - if (strcmp(PORT->Rigs[0].RigName, "FT847") == 0) { // Looks like FT847 Needa a "Cat On" Command @@ -2798,6 +2805,7 @@ int OpenRigCOMMPort(struct RIGPORTINFO * PORT, VOID * Port, int Speed) WriteCOMBlock(PORT->hDevice, CATON, 5); } + if (PORT->PortType == NMEA) { // Looks like NMEA Needs Remote ON @@ -7310,7 +7318,7 @@ VOID SetupScanInterLockGroups(struct RIGINFO *RIG) // Find TNC ports in this Rig's scan group - for (port = 1; port < 33; port++) + for (port = 1; port < MAXBPQPORTS; port++) { TNC = TNCInfo[port]; @@ -7359,7 +7367,7 @@ VOID SetupPortRIGPointers() struct TNCINFO * TNC; int port; - for (port = 1; port < 33; port++) + for (port = 1; port < MAXBPQPORTS; port++) { TNC = TNCInfo[port]; diff --git a/UIARQ.c b/UIARQ.c index 6fdc5e3..99b2b49 100644 --- a/UIARQ.c +++ b/UIARQ.c @@ -634,6 +634,8 @@ static VOID SendPacket(struct TNCINFO * TNC, struct STREAMINFO * STREAM, UCHAR * Block.PID = 0xF0; ConvToAX25(STREAM->RemoteCall, Block.DEST); + Block.DEST[6] |= 0x80; // set Command Bit + memcpy(Block.ORIGIN, MYCALL, 7); Block.L2DATA[0] = STREAM->ARQInfo->FarStream; diff --git a/UZ7HODrv.c b/UZ7HODrv.c index 205273e..f506495 100644 --- a/UZ7HODrv.c +++ b/UZ7HODrv.c @@ -86,6 +86,9 @@ static char ClassName[]="ARDOPSTATUS"; static char WindowTitle[] = "UZ7HO"; static int RigControlRow = 165; +char FX25Modes[8][8] = {"None", "RxOnly", "RX+TX"}; +char IL2PModes[8][10] = {"None", "RxOnly", "RX+TX", "il2pOnly"}; + //LOGFONT LFTTYFONT ; @@ -378,7 +381,7 @@ int UZ7HOSetFreq(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESS return 1; } - if (TNCInfo[MasterPort[port]]->AGWInfo->isQTSM == 3) + if (TNCInfo[MasterPort[port]]->AGWInfo->isQTSM >= 3) { // QtSM so can send Set Freq Command @@ -437,7 +440,7 @@ int UZ7HOSetModem(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMES return 1; } - else if (TNCInfo[MasterPort[port]]->AGWInfo->isQTSM == 3) + else if (TNCInfo[MasterPort[port]]->AGWInfo->isQTSM >= 3) { // Can send modem name to QTSM @@ -452,6 +455,8 @@ int UZ7HOSetModem(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMES strcpy(&Buffer[4], &buff->L2DATA[6]); + Buffer[27] = 1; // Modem can set modem flags + AGW->TXHeader.Port = UZ7HOChannel[port]; AGW->TXHeader.DataKind = 'g'; memset(AGW->TXHeader.callfrom, 0, 10); @@ -496,6 +501,119 @@ int UZ7HOSetModem(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMES return 1; } +int UZ7HOSetFlags(int port, struct TNCINFO * TNC, struct AGWINFO * AGW, PDATAMESSAGE buff, PMSGWITHLEN buffptr) +{ + int txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1); + char Buffer[32] = ""; + int MsgLen = 32; + char * ptr, * context; + int i; + + if (TNCInfo[MasterPort[port]]->AGWInfo->isQTSM != 7) + { + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Sorry Setting UZ7HO flags not supported on this modem\r"); + return 1; + } + + // May be read or set flags + + if (txlen == 6) + { + // Read Flags + + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} fx25 %s il2p %s %s\r", + FX25Modes[TNC->AGWInfo->fx25Flags], IL2PModes[TNC->AGWInfo->il2pFlags], TNC->AGWInfo->il2pcrc?"CRC":""); + + return 1; + } + + ptr = strtok_s(&buff->L2DATA[6], " ,\r", &context); + + while (ptr && ptr[0]) + { + if (_stricmp(ptr, "fx25") == 0) + { + ptr = strtok_s(NULL, " ,\r", &context); + i = 4; + + if (ptr && ptr[0]) + { + for (i = 0; i < 4; i++) + { + if (_stricmp(FX25Modes[i], ptr) == 0) + { + TNC->AGWInfo->fx25Flags = i; + break; + } + } + } + + if (i == 4) + { + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Failed - fx25 flags invalid\r"); + return 1; + } + } + else if (_stricmp(ptr, "il2p") == 0) + { + ptr = strtok_s(NULL, " ,\r", &context); + i = 4; + + if (ptr && ptr[0]) + { + for (i = 0; i < 4; i++) + { + if (_stricmp(IL2PModes[i], ptr) == 0) + { + TNC->AGWInfo->il2pFlags = i; + break; + } + } + } + + if (i == 4) + { + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Failed - il2p flags invalid\r"); + return 1; + + } + } + else if (_stricmp(ptr, "crc") == 0) + TNC->AGWInfo->il2pcrc = 1; + else if (_stricmp(ptr, "nocrc") == 0) + TNC->AGWInfo->il2pcrc = 0; + else + { + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Failed - invalid flag %s\r", ptr); + return 1; + } + + ptr = strtok_s(NULL, " ,\r", &context); + } + + + Buffer[27] = 2; // Set Flags + + Buffer[28] = TNC->AGWInfo->fx25Flags; + Buffer[29] = TNC->AGWInfo->il2pFlags; + Buffer[30] = TNC->AGWInfo->il2pcrc; + + AGW->TXHeader.Port = UZ7HOChannel[port]; + AGW->TXHeader.DataKind = 'g'; + memset(AGW->TXHeader.callfrom, 0, 10); + memset(AGW->TXHeader.callto, 0, 10); +#ifdef __BIG_ENDIAN__ + AGW->TXHeader.DataLength = reverse(MsgLen); +#else + AGW->TXHeader.DataLength = MsgLen; +#endif + send(TNCInfo[MasterPort[port]]->TCPSock, (char *)&AGW->TXHeader, AGWHDDRLEN, 0); + send(TNCInfo[MasterPort[port]]->TCPSock, Buffer, MsgLen, 0); + + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "UZ7HO} Set Modem Flags command sent Ok\r"); + return 1; +} + static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) { @@ -977,6 +1095,18 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) } return 1; } + if (_memicmp(&buff->L2DATA[0], "FLAGS", 5) == 0) + { + PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); + if (buffptr) + { + UZ7HOSetFlags(port, TNC, AGW, buff, buffptr); + C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); + } + return 1; + } + + // See if a Connect Command. if (toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect @@ -1311,7 +1441,7 @@ void * UZ7HOExtInit(EXTPORTDATA * PortEntry) #ifndef LINBPQ - CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 450, ForcedClose); + CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 520, 450, ForcedClose); CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL); TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 120,6,386,20, TNC->hDlg, NULL, hInstance, NULL); @@ -1327,7 +1457,7 @@ void * UZ7HOExtInit(EXTPORTDATA * PortEntry) 0,170,250,300, TNC->hDlg, NULL, hInstance, NULL); TNC->ClientHeight = 450; - TNC->ClientWidth = 500; + TNC->ClientWidth = 520; TNC->hMenu = CreatePopupMenu(); @@ -2615,7 +2745,7 @@ GotStream: if (RXHeader->DataLength == 12) { // First reply - request Modem Freq and Name - for (p = This; p < 33; p++) + for (p = This; p < MAXBPQPORTS; p++) { if (MasterPort[p] == This) { @@ -2627,6 +2757,7 @@ GotStream: int MsgLen = 32; SOCKET sock = TNCInfo[MasterPort[This]]->TCPSock; + Buffer[27] = 1; // Modem can set modem flags TNC->AGWInfo->isQTSM |= 2; @@ -2647,7 +2778,7 @@ GotStream: return; } - if (RXHeader->DataLength == 44) + if (RXHeader->DataLength == 44 || RXHeader->DataLength == 48) { // Modem Freq and Type Report from QtSM @@ -2662,7 +2793,21 @@ GotStream: memcpy(&TNC->AGWInfo->ModemName, &Message[16], 20); memcpy(&TNC->AGWInfo->Version, &Message[38], 4); - sprintf(TNC->WEB_MODE, "%s / %d Hz", TNC->AGWInfo->ModemName, TNC->AGWInfo->CenterFreq); + if (RXHeader->DataLength == 48) + { + // includes modem flags + + TNC->AGWInfo->isQTSM |= 4; // can send flags + TNC->AGWInfo->fx25Flags = (Message[45] & 3); + TNC->AGWInfo->il2pFlags = (Message[46] & 3); + TNC->AGWInfo->il2pcrc = Message[47]; + + sprintf(TNC->WEB_MODE, "%s/%d Hz FX %s IL2P %s %s", TNC->AGWInfo->ModemName, TNC->AGWInfo->CenterFreq, + FX25Modes[TNC->AGWInfo->fx25Flags], IL2PModes[TNC->AGWInfo->il2pFlags], TNC->AGWInfo->il2pcrc?"CRC":""); + } + else + sprintf(TNC->WEB_MODE, "%s/%d Hz ", TNC->AGWInfo->ModemName, TNC->AGWInfo->CenterFreq); + SetWindowText(TNC->xIDC_MODE, TNC->WEB_MODE); } } diff --git a/VARA.c b/VARA.c index 983f77d..6d1ec68 100644 --- a/VARA.c +++ b/VARA.c @@ -2413,6 +2413,7 @@ VOID VARAProcessReceivedData(struct TNCINFO * TNC) Msg->PID = 0xcf; Msg->PORT = TNC->Port | 0x80; Msg->CTL = 3; + Msg->DEST[6] |= 0x80; // set Command Bit Msg->ORIGIN[6] |= 1; // set end of address time(&Msg->Timestamp); BPQTRACE(Msg, FALSE); @@ -2445,6 +2446,8 @@ VOID VARAProcessReceivedData(struct TNCINFO * TNC) ConvToAX25(TNC->NRNeighbour, Buffer->DEST); memcpy(Buffer->ORIGIN, NETROMCALL, 7); Buffer->ORIGIN[6] |= 1; // set end of address + Buffer->DEST[6] |= 0x80; // set Command Bit + time(&Buffer->Timestamp); BPQTRACE(Buffer, FALSE); // TRACE NETROMMSG(TNC->DummyLink, L3MSG); @@ -2886,6 +2889,8 @@ void SendVARANetromMsg(struct TNCINFO * TNC, L3MESSAGEBUFFER * MSG) ConvToAX25(TNC->NRNeighbour, Buffer->DEST); memcpy(Buffer->ORIGIN, NETROMCALL, 7); Buffer->ORIGIN[6] |= 1; // set end of address + Buffer->DEST[6] |= 0x80; // set Command Bit + time(&Buffer->Timestamp); diff --git a/Versions.h b/Versions.h index db6f372..411efe1 100644 --- a/Versions.h +++ b/Versions.h @@ -10,8 +10,8 @@ #endif -#define KVers 6,0,24,15 -#define KVerstring "6.0.24.15\0" +#define KVers 6,0,24,16 +#define KVerstring "6.0.24.16\0" #ifdef CKernel diff --git a/WebMail.c b/WebMail.c index 981a60d..1b4cd33 100644 --- a/WebMail.c +++ b/WebMail.c @@ -1193,6 +1193,10 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu } } } + + if (DisplayHTML && stristr(Message, "")) + DisplayStyle = "div"; // Use div so HTML and XML are interpreted + return sprintf(Reply, WebMailMsgTemplate, BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, DownLoad, Key, Key, Key, DisplayStyle, Message, DisplayStyle); } @@ -1232,9 +1236,7 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu size_t origlen = msgLen + 1; UCHAR * BufferB = malloc(2 * origlen); - #ifdef WIN32 - WCHAR * BufferW = malloc(2 * origlen); int wlen; int len = (int)origlen; @@ -1246,10 +1248,10 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu Save = MsgBytes = BufferB; free(BufferW); msgLen = len - 1; // exclude NULL - #else size_t left = 2 * msgLen; - size_t len = msgLen; + size_t outbuflen = left; + size_t len = msgLen + 1; // include null int ret; UCHAR * BufferBP = BufferB; char * orig = MsgBytes; @@ -1270,15 +1272,18 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu iconv(icu, NULL, NULL, NULL, NULL); // Reset State Machine ret = iconv(icu, &MsgBytes, &len, (char ** __restrict__)&BufferBP, &left); } + + // left is next location to write, so length written is outbuflen - left + // add a null in case iconv didn't complete comversion + + BufferB[outbuflen - left] = 0; + free(Save); Save = MsgBytes = BufferB; msgLen = strlen(MsgBytes); - #endif - } - // ptr += sprintf(ptr, "%s", MsgBytes); memcpy(ptr, MsgBytes, msgLen); @@ -1307,13 +1312,10 @@ int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Nu ptr += sprintf(ptr, "File for Message %d not found\r", Number); } - if (DisplayHTML && stristr(Message, "html>")) + if (DisplayHTML && stristr(Message, "")) DisplayStyle = "div"; // Use div so HTML and XML are interpreted - - - return sprintf(Reply, WebMailMsgTemplate, BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, DownLoad, Key, Key, Key, DisplayStyle, Message, DisplayStyle); } diff --git a/WinRPRHelper.vcproj.DESKTOP-TGEL8RC.John.user b/WinRPRHelper.vcproj.DESKTOP-TGEL8RC.John.user deleted file mode 100644 index d4a1f25..0000000 --- a/WinRPRHelper.vcproj.DESKTOP-TGEL8RC.John.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/WinmorControl.vcproj.DESKTOP-TGEL8RC.John.user b/WinmorControl.vcproj.DESKTOP-TGEL8RC.John.user deleted file mode 100644 index 40182c4..0000000 --- a/WinmorControl.vcproj.DESKTOP-TGEL8RC.John.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/WinmorControl.vcproj.SKIGACER.johnw.user b/WinmorControl.vcproj.SKIGACER.johnw.user deleted file mode 100644 index b5b0536..0000000 --- a/WinmorControl.vcproj.SKIGACER.johnw.user +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - - - - - diff --git a/adif-HPLaptop.h b/adif-HPLaptop.h deleted file mode 100644 index ed6194d..0000000 --- a/adif-HPLaptop.h +++ /dev/null @@ -1,36 +0,0 @@ -// ADIF Logging Bits - -typedef struct ADIF -{ - char Call[16]; - time_t StartTime; - int Mode; - char LOC[7]; - char Band[8]; // ?Derive from freq? - int Freq; - - // Extra fields for Trimode comment fields - - char CMSCall[16]; - char ServerSID[80]; - char UserSID[80]; - char ReportMode[16]; - char Termination[8]; // Last "F" message from CMS - int Sent; - int Received; - int BytesSent; - int BytesReceived; - - char Dirn; // Direction of current transfer (In/Out) - - int FBBIndex; // For saving proposals - int FBBLen[5]; // Proposed messages - BOOL GotFC; // Flag for acking messages on first FC - char PartMessage[256]; // Some modes frame size too small for complete lines - -} ADIF; - -BOOL UpdateADIFRecord(ADIF * ADIF, char * Msg, char Dirn); -BOOL WriteADIFRecord(ADIF * ADIF); - - diff --git a/ding.wav b/ding.wav new file mode 100644 index 0000000..5331129 Binary files /dev/null and b/ding.wav differ diff --git a/getopt.c b/getopt.c index 0e74577..bb6de84 100644 --- a/getopt.c +++ b/getopt.c @@ -1,715 +1,715 @@ -/* - * getopt.c - * - * $Id: getopt.c,v 1.9 2009/02/08 18:02:17 keithmarshall Exp $ - * - * Implementation of the `getopt', `getopt_long' and `getopt_long_only' - * APIs, for inclusion in the MinGW runtime library. - * - * This file is part of the MinGW32 package set. - * - * Contributed by Keith Marshall - * - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Revision: 1.9 $ - * $Author: keithmarshall $ - * $Date: 2009/02/08 18:02:17 $ - * - */ - -// Modified a little to compile as C code, John Wiseman 2018 - -#include -#include -#include -#include "getopt.h" - -/* Identify how to get the calling program name, for use in messages... - */ -#ifdef __CYGWIN__ -/* - * CYGWIN uses this DLL reference... - */ -# define PROGNAME __progname -extern char __declspec(dllimport) *__progname; -#else -/* - * ...while elsewhere, we simply use the first argument passed. - */ -# define PROGNAME *argv -#endif - -/* Initialise the public variables. */ - -int optind = 1; /* index for first non-option arg */ -int opterr = 1; /* enable built-in error messages */ - -char *optarg = NULL; /* pointer to current option argument */ - -#define CHAR char /* argument type selector */ - -#define getopt_switchar '-' /* option prefix character in argv */ -#define getopt_pluschar '+' /* prefix for POSIX mode in optstring */ -#define getopt_takes_argument ':' /* marker for optarg in optstring */ -#define getopt_arg_assign '=' /* longopt argument field separator */ -#define getopt_unknown '?' /* return code for unmatched option */ -#define getopt_ordered 1 /* return code for ordered non-option */ - -#define getopt_all_done -1 /* return code to indicate completion */ - -enum -{ /* All `getopt' API functions are implemented via calls to the - * common static function `getopt_parse()'; these `mode' selectors - * determine the behaviour of `getopt_parse()', to deliver the - * appropriate result in each case. - */ - getopt_mode_standard = 0, /* getopt() */ - getopt_mode_long, /* getopt_long() */ - getopt_mode_long_only /* getopt_long_only() */ -}; - -enum -{ /* When attempting to match a command line argument to a long form option, - * these indicate the status of the match. - */ - getopt_no_match = 0, /* no successful match */ - getopt_abbreviated_match, /* argument is an abbreviation for an option */ - getopt_exact_match /* argument matches the full option name */ -}; - -int optopt = getopt_unknown; /* return value for option being evaluated */ - -/* Some BSD applications expect to be able to reinitialise `getopt' parsing - * by setting a global variable called `optreset'. We provide an obfuscated - * API, which allows applications to emulate this brain damage; however, any - * use of this is non-portable, and is strongly discouraged. - */ -#define optreset __mingw_optreset -int optreset = 0; - -int getopt_missing_arg( const CHAR *optstring ) -{ - /* Helper function to determine the appropriate return value, - * for the case where a required option argument is missing. - */ - if( (*optstring == getopt_pluschar) || (*optstring == getopt_switchar) ) - ++optstring; - return (*optstring == getopt_takes_argument) - ? getopt_takes_argument - : getopt_unknown; -} - -/* `complain' macro facilitates the generation of simple built-in - * error messages, displayed on various fault conditions, provided - * `opterr' is non-zero. - */ -#define complain( MSG, ARG ) if( opterr ) \ - fprintf( stderr, "%s: "MSG"\n", PROGNAME, ARG ) - - -int getopt_argerror( int mode, char *fmt, CHAR *prog, struct option *opt, int retval ) -{ - /* Helper function, to generate more complex built-in error - * messages, for invalid arguments to long form options ... - */ - if( opterr ) - { - /* ... but, displayed only if `opterr' is non-zero. - */ - char flag[] = "--"; - if( mode != getopt_mode_long ) - /* - * only display one hyphen, for implicit long form options, - * improperly resolved by `getopt_long_only()'. - */ - flag[1] = 0; - /* - * always preface the program name ... - */ - fprintf( stderr, "%s: ", prog ); - /* - * to the appropriate, option specific message. - */ - fprintf( stderr, fmt, flag, opt->name ); - } - /* Whether displaying the message, or not, always set `optopt' - * to identify the faulty option ... - */ - optopt = opt->val; - /* - * and return the `invalid option' indicator. - */ - return retval; -} - -/* `getopt_conventions' establish behavioural options, to control - * the operation of `getopt_parse()', e.g. to select between POSIX - * and GNU style argument parsing behaviour. - */ -#define getopt_set_conventions 0x1000 -#define getopt_posixly_correct 0x0010 - - -int getopt_conventions( int flags ) -{ - static int conventions = 0; - - if( (conventions == 0) && ((flags & getopt_set_conventions) == 0) ) - { - /* default conventions have not yet been established; - * initialise them now! - */ - conventions = getopt_set_conventions; - - } - - else if( flags & getopt_set_conventions ) - /* - * default conventions may have already been established, - * but this is a specific request to augment them. - */ - conventions |= flags; - - /* in any event, return the currently established conventions. - */ - return conventions; -} - -int is_switchar( CHAR flag ) -{ - /* A simple helper function, used to identify the switch character - * introducing an optional command line argument. - */ - return flag == getopt_switchar; -} - -const CHAR *getopt_match( CHAR lookup, const CHAR *opt_string ) -{ - /* Helper function, used to identify short form options. - */ - if( (*opt_string == getopt_pluschar) || (*opt_string == getopt_switchar) ) - ++opt_string; - if( *opt_string == getopt_takes_argument ) - ++opt_string; - do if( lookup == *opt_string ) return opt_string; - while( *++opt_string ); - return NULL; -} - -int getopt_match_long( const CHAR *nextchar, const CHAR *optname ) -{ - /* Helper function, used to identify potential matches for - * long form options. - */ - CHAR matchchar; - while( (matchchar = *nextchar++) && (matchchar == *optname) ) - /* - * skip over initial substring which DOES match. - */ - ++optname; - - if( matchchar ) - { - /* did NOT match the entire argument to an initial substring - * of a defined option name ... - */ - if( matchchar != getopt_arg_assign ) - /* - * ... and didn't stop at an `=' internal field separator, - * so this is NOT a possible match. - */ - return getopt_no_match; - - /* DID stop at an `=' internal field separator, - * so this IS a possible match, and what follows is an - * argument to the possibly matched option. - */ - optarg = (char *)(nextchar); - } - return *optname - /* - * if we DIDN'T match the ENTIRE text of the option name, - * then it's a possible abbreviated match ... - */ - ? getopt_abbreviated_match - /* - * but if we DID match the entire option name, - * then it's a DEFINITE EXACT match. - */ - : getopt_exact_match; -} - -int getopt_resolved( int mode, int argc, CHAR *const *argv, int *argind, -struct option *opt, int index, int *retindex, const CHAR *optstring ) -{ - /* Helper function to establish appropriate return conditions, - * on resolution of a long form option. - */ - if( retindex != NULL ) - *retindex = index; - - /* On return, `optind' should normally refer to the argument, if any, - * which follows the current one; it is convenient to set this, before - * checking for the presence of any `optarg'. - */ - optind = *argind + 1; - - if( optarg && (opt[index].has_arg == no_argument) ) - /* - * it is an error for the user to specify an option specific argument - * with an option which doesn't expect one! - */ - return getopt_argerror( mode, "option `%s%s' doesn't accept an argument\n", - PROGNAME, opt + index, getopt_unknown ); - - else if( (optarg == NULL) && (opt[index].has_arg == required_argument) ) - { - /* similarly, it is an error if no argument is specified - * with an option which requires one ... - */ - if( optind < argc ) - /* - * ... except that the requirement may be satisfied from - * the following command line argument, if any ... - */ - optarg = argv[*argind = optind++]; - - else - /* so fail this case, only if no such argument exists! - */ - return getopt_argerror( mode, "option `%s%s' requires an argument\n", - PROGNAME, opt + index, getopt_missing_arg( optstring ) ); - } - - /* when the caller has provided a return buffer ... - */ - if( opt[index].flag != NULL ) - { - /* ... then we place the proper return value there, - * and return a status code of zero ... - */ - *(opt[index].flag) = opt[index].val; - return 0; - } - /* ... otherwise, the return value becomes the status code. - */ - return opt[index].val; -} - -static -#define getopt_std_args int argc, CHAR *const argv[], const CHAR *optstring -int getopt_parse( int mode, getopt_std_args, ... ) -{ - /* Common core implementation for ALL `getopt' functions. - */ - static int argind = 0; - static int optbase = 0; - static const CHAR *nextchar = NULL; - static int optmark = 0; - - if( (optreset |= (optind < 1)) || (optind < optbase) ) - { - /* POSIX does not prescribe any definitive mechanism for restarting - * a `getopt' scan, but some applications may require such capability. - * We will support it, by allowing the caller to adjust the value of - * `optind' downwards, (nominally setting it to zero). Since POSIX - * wants `optind' to have an initial value of one, but we want all - * of our internal place holders to be initialised to zero, when we - * are called for the first time, we will handle such a reset by - * adjusting all of the internal place holders to one less than - * the adjusted `optind' value, (but never to less than zero). - */ - if( optreset ) - { - /* User has explicitly requested reinitialisation... - * We need to reset `optind' to it's normal initial value of 1, - * to avoid a potential infinitely recursive loop; by doing this - * up front, we also ensure that the remaining place holders - * will be correctly reinitialised to no less than zero. - */ - optind = 1; - - /* We also need to clear the `optreset' request... - */ - optreset = 0; - } - - /* Now, we may safely reinitialise the internal place holders, to - * one less than `optind', without fear of making them negative. - */ - optmark = optbase = argind = optind - 1; - nextchar = NULL; - } - - /* From a POSIX perspective, the following is `undefined behaviour'; - * we implement it thus, for compatibility with GNU and BSD getopt. - */ - else if( optind > (argind + 1) ) - { - /* Some applications expect to be able to manipulate `optind', - * causing `getopt' to skip over one or more elements of `argv'; - * POSIX doesn't require us to support this brain-damaged concept; - * (indeed, POSIX defines no particular behaviour, in the event of - * such usage, so it must be considered a bug for an application - * to rely on any particular outcome); nonetheless, Mac-OS-X and - * BSD actually provide *documented* support for this capability, - * so we ensure that our internal place holders keep track of - * external `optind' increments; (`argind' must lag by one). - */ - argind = optind - 1; - - /* When `optind' is misused, in this fashion, we also abandon any - * residual text in the argument we had been parsing; this is done - * without any further processing of such abandoned text, assuming - * that the caller is equipped to handle it appropriately. - */ - nextchar = NULL; - } - - if( nextchar && *nextchar ) - { - /* we are parsing a standard, or short format, option argument ... - */ - const CHAR *optchar; - if( (optchar = getopt_match( optopt = *nextchar++, optstring )) != NULL ) - { - /* we have identified it as valid ... - */ - if( optchar[1] == getopt_takes_argument ) - { - /* and determined that it requires an associated argument ... - */ - if( ! *(optarg = (char *)(nextchar)) ) - { - /* the argument is NOT attached ... - */ - if( optchar[2] == getopt_takes_argument ) - /* - * but this GNU extension marks it as optional, - * so we don't provide one on this occasion. - */ - optarg = NULL; - - /* otherwise this option takes a mandatory argument, - * so, provided there is one available ... - */ - else if( (argc - argind) > 1 ) - /* - * we take the following command line argument, - * as the appropriate option argument. - */ - optarg = argv[++argind]; - - /* but if no further argument is available, - * then there is nothing we can do, except for - * issuing the requisite diagnostic message. - */ - else - { - complain( "option requires an argument -- %c", optopt ); - return getopt_missing_arg( optstring ); - } - } - optind = argind + 1; - nextchar = NULL; - } - else - optarg = NULL; - optind = (nextchar && *nextchar) ? argind : argind + 1; - return optopt; - } - /* if we didn't find a valid match for the specified option character, - * then we fall through to here, so take appropriate diagnostic action. - */ - if( mode == getopt_mode_long_only ) - { - complain( "unrecognised option `-%s'", --nextchar ); - nextchar = NULL; - optopt = 0; - } - else - complain( "invalid option -- %c", optopt ); - optind = (nextchar && *nextchar) ? argind : argind + 1; - return getopt_unknown; - } - - if( optmark > optbase ) - { - /* This can happen, in GNU parsing mode ONLY, when we have - * skipped over non-option arguments, and found a subsequent - * option argument; in this case we permute the arguments. - */ - int index; - /* - * `optspan' specifies the number of contiguous arguments - * which are spanned by the current option, and so must be - * moved together during permutation. - */ - int optspan = argind - optmark + 1; - /* - * we use `this_arg' to store these temporarily. - */ - CHAR *this_arg[100]; - /* - * we cannot manipulate `argv' directly, since the `getopt' - * API prototypes it as `read-only'; this cast to `arglist' - * allows us to work around that restriction. - */ - CHAR **arglist = (char **)(argv); - - /* save temporary copies of the arguments which are associated - * with the current option ... - */ - for( index = 0; index < optspan; ++index ) - this_arg[index] = arglist[optmark + index]; - - /* move all preceding non-option arguments to the right, - * overwriting these saved arguments, while making space - * to replace them in their permuted location. - */ - for( --optmark; optmark >= optbase; --optmark ) - arglist[optmark + optspan] = arglist[optmark]; - - /* restore the temporarily saved option arguments to - * their permuted location. - */ - for( index = 0; index < optspan; ++index ) - arglist[optbase + index] = this_arg[index]; - - /* adjust `optbase', to account for the relocated option. - */ - optbase += optspan; - } - - else - /* no permutation occurred ... - * simply adjust `optbase' for all options parsed so far. - */ - optbase = argind + 1; - - /* enter main parsing loop ... - */ - while( argc > ++argind ) - { - /* inspect each argument in turn, identifying possible options ... - */ - if( is_switchar( *(nextchar = argv[optmark = argind]) ) && *++nextchar ) - { - /* we've found a candidate option argument ... */ - - if( is_switchar( *nextchar ) ) - { - /* it's a double hyphen argument ... */ - - const CHAR *refchar = nextchar; - if( *++refchar ) - { - /* and it looks like a long format option ... - * `getopt_long' mode must be active to accept it as such, - * `getopt_long_only' also qualifies, but we must downgrade - * it to force explicit handling as a long format option. - */ - if( mode >= getopt_mode_long ) - { - nextchar = refchar; - mode = getopt_mode_long; - } - } - else - { - /* this is an explicit `--' end of options marker, so wrap up now! - */ - if( optmark > optbase ) - { - /* permuting the argument list as necessary ... - * (note use of `this_arg' and `arglist', as above). - */ - CHAR *this_arg = argv[optmark]; - CHAR **arglist = (CHAR **)(argv); - - /* move all preceding non-option arguments to the right ... - */ - do arglist[optmark] = arglist[optmark - 1]; - while( optmark-- > optbase ); - - /* reinstate the `--' marker, in its permuted location. - */ - arglist[optbase] = this_arg; - } - /* ... before finally bumping `optbase' past the `--' marker, - * and returning the `all done' completion indicator. - */ - optind = ++optbase; - return getopt_all_done; - } - } - else if( mode < getopt_mode_long_only ) - { - /* it's not an explicit long option, and `getopt_long_only' isn't active, - * so we must explicitly try to match it as a short option. - */ - mode = getopt_mode_standard; - } - - if( mode >= getopt_mode_long ) - { - /* the current argument is a long form option, (either explicitly, - * introduced by a double hyphen, or implicitly because we were called - * by `getopt_long_only'); this is where we parse it. - */ - int lookup; - int matched = -1; - struct option *longopts; - int *optindex; - /* we need to fetch the `extra' function arguments, which are - * specified for the `getopt_long' APIs. - */ - va_list refptr; - va_start( refptr, optstring ); - longopts = va_arg( refptr, struct option * ); - optindex = va_arg( refptr, int * ); - va_end( refptr ); - - /* ensuring that `optarg' does not inherit any junk, from parsing - * preceding arguments ... - */ - optarg = NULL; - for( lookup = 0; longopts && longopts[lookup].name; ++lookup ) - { - /* scan the list of defined long form options ... - */ - switch( getopt_match_long( nextchar, longopts[lookup].name ) ) - { - /* looking for possible matches for the current argument. - */ - case getopt_exact_match: - /* - * when an exact match is found, - * return it immediately, setting `nextchar' to NULL, - * to ensure we don't mistakenly try to match any - * subsequent characters as short form options. - */ - nextchar = NULL; - return getopt_resolved( mode, argc, argv, &argind, - longopts, lookup, optindex, optstring ); - - case getopt_abbreviated_match: - /* - * but, for a partial (initial substring) match ... - */ - if( matched >= 0 ) - { - /* if this is not the first, then we have an ambiguity ... - */ - optopt = 0; - nextchar = NULL; - optind = argind + 1; - complain( "option `%s' is ambiguous", argv[argind] ); - return getopt_unknown; - } - /* otherwise just note that we've found a possible match ... - */ - matched = lookup; - } - } - if( matched >= 0 ) - { - /* if we get to here, then we found exactly one partial match, - * so return it, as for an exact match. - */ - nextchar = NULL; - return getopt_resolved( mode, argc, argv, &argind, - longopts, matched, optindex, optstring ); - } - if( mode < getopt_mode_long_only ) - { - /* if here, then we had what SHOULD have been a long form option, - * but it is unmatched; (perversely, `mode == getopt_mode_long_only' - * allows us to still try to match it as a short form option). - */ - optopt = 0; - nextchar = NULL; - optind = argind + 1; - complain( "unrecognised option `%s'", argv[argind] ); - return getopt_unknown; - } - } - /* fall through to handle standard short form options... - * when the option argument format is neither explictly identified - * as long, nor implicitly matched as such, and the argument isn't - * just a bare hyphen, (which isn't an option), then we make one - * recursive call to explicitly interpret it as short format. - */ - if( *nextchar ) - return getopt_parse( mode, argc, argv, optstring ); - } - /* if we get to here, then we've parsed a non-option argument ... - * in GNU compatibility mode, we step over it, so we can permute - * any subsequent option arguments, but ... - */ - if( *optstring == getopt_switchar ) - { - /* if `optstring' begins with a `-' character, this special - * GNU specific behaviour requires us to return the non-option - * arguments in strict order, as pseudo-arguments to a special - * option, with return value defined as `getopt_ordered'. - */ - nextchar = NULL; - optind = argind + 1; - optarg = argv[argind]; - return getopt_ordered; - } - if( getopt_conventions( *optstring ) & getopt_posixly_correct ) - /* - * otherwise ... - * for POSIXLY_CORRECT behaviour, or if `optstring' begins with - * a `+' character, then we break out of the parsing loop, so that - * the scan ends at the current argument, with no permutation. - */ - break; - } - /* fall through when all arguments have been evaluated, - */ - optind = optbase; - return getopt_all_done; -} - -/* All three public API entry points are trivially defined, - * in terms of the internal `getopt_parse' function. - */ -int getopt( getopt_std_args ) -{ - return getopt_parse( getopt_mode_standard, argc, argv, optstring ); -} - -int getopt_long( getopt_std_args, const struct option *opts, int *index ) -{ - return getopt_parse( getopt_mode_long, argc, argv, optstring, opts, index ); -} - -int getopt_long_only( getopt_std_args, const struct option *opts, int *index ) -{ - return getopt_parse( getopt_mode_long_only, argc, argv, optstring, opts, index ); -} - -#ifdef __weak_alias -/* - * These Microsnot style uglified aliases are provided for compatibility - * with the previous MinGW implementation of the getopt API. - */ -__weak_alias( getopt, _getopt ) -__weak_alias( getopt_long, _getopt_long ) -__weak_alias( getopt_long_only, _getopt_long_only ) -#endif - +/* + * getopt.c + * + * $Id: getopt.c,v 1.9 2009/02/08 18:02:17 keithmarshall Exp $ + * + * Implementation of the `getopt', `getopt_long' and `getopt_long_only' + * APIs, for inclusion in the MinGW runtime library. + * + * This file is part of the MinGW32 package set. + * + * Contributed by Keith Marshall + * + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * $Revision: 1.9 $ + * $Author: keithmarshall $ + * $Date: 2009/02/08 18:02:17 $ + * + */ + +// Modified a little to compile as C code, John Wiseman 2018 + +#include +#include +#include +#include "getopt.h" + +/* Identify how to get the calling program name, for use in messages... + */ +#ifdef __CYGWIN__ +/* + * CYGWIN uses this DLL reference... + */ +# define PROGNAME __progname +extern char __declspec(dllimport) *__progname; +#else +/* + * ...while elsewhere, we simply use the first argument passed. + */ +# define PROGNAME *argv +#endif + +/* Initialise the public variables. */ + +int optind = 1; /* index for first non-option arg */ +int opterr = 1; /* enable built-in error messages */ + +char *optarg = NULL; /* pointer to current option argument */ + +#define CHAR char /* argument type selector */ + +#define getopt_switchar '-' /* option prefix character in argv */ +#define getopt_pluschar '+' /* prefix for POSIX mode in optstring */ +#define getopt_takes_argument ':' /* marker for optarg in optstring */ +#define getopt_arg_assign '=' /* longopt argument field separator */ +#define getopt_unknown '?' /* return code for unmatched option */ +#define getopt_ordered 1 /* return code for ordered non-option */ + +#define getopt_all_done -1 /* return code to indicate completion */ + +enum +{ /* All `getopt' API functions are implemented via calls to the + * common static function `getopt_parse()'; these `mode' selectors + * determine the behaviour of `getopt_parse()', to deliver the + * appropriate result in each case. + */ + getopt_mode_standard = 0, /* getopt() */ + getopt_mode_long, /* getopt_long() */ + getopt_mode_long_only /* getopt_long_only() */ +}; + +enum +{ /* When attempting to match a command line argument to a long form option, + * these indicate the status of the match. + */ + getopt_no_match = 0, /* no successful match */ + getopt_abbreviated_match, /* argument is an abbreviation for an option */ + getopt_exact_match /* argument matches the full option name */ +}; + +int optopt = getopt_unknown; /* return value for option being evaluated */ + +/* Some BSD applications expect to be able to reinitialise `getopt' parsing + * by setting a global variable called `optreset'. We provide an obfuscated + * API, which allows applications to emulate this brain damage; however, any + * use of this is non-portable, and is strongly discouraged. + */ +#define optreset __mingw_optreset +int optreset = 0; + +int getopt_missing_arg( const CHAR *optstring ) +{ + /* Helper function to determine the appropriate return value, + * for the case where a required option argument is missing. + */ + if( (*optstring == getopt_pluschar) || (*optstring == getopt_switchar) ) + ++optstring; + return (*optstring == getopt_takes_argument) + ? getopt_takes_argument + : getopt_unknown; +} + +/* `complain' macro facilitates the generation of simple built-in + * error messages, displayed on various fault conditions, provided + * `opterr' is non-zero. + */ +#define complain( MSG, ARG ) if( opterr ) \ + fprintf( stderr, "%s: "MSG"\n", PROGNAME, ARG ) + + +int getopt_argerror( int mode, char *fmt, CHAR *prog, struct option *opt, int retval ) +{ + /* Helper function, to generate more complex built-in error + * messages, for invalid arguments to long form options ... + */ + if( opterr ) + { + /* ... but, displayed only if `opterr' is non-zero. + */ + char flag[] = "--"; + if( mode != getopt_mode_long ) + /* + * only display one hyphen, for implicit long form options, + * improperly resolved by `getopt_long_only()'. + */ + flag[1] = 0; + /* + * always preface the program name ... + */ + fprintf( stderr, "%s: ", prog ); + /* + * to the appropriate, option specific message. + */ + fprintf( stderr, fmt, flag, opt->name ); + } + /* Whether displaying the message, or not, always set `optopt' + * to identify the faulty option ... + */ + optopt = opt->val; + /* + * and return the `invalid option' indicator. + */ + return retval; +} + +/* `getopt_conventions' establish behavioural options, to control + * the operation of `getopt_parse()', e.g. to select between POSIX + * and GNU style argument parsing behaviour. + */ +#define getopt_set_conventions 0x1000 +#define getopt_posixly_correct 0x0010 + + +int getopt_conventions( int flags ) +{ + static int conventions = 0; + + if( (conventions == 0) && ((flags & getopt_set_conventions) == 0) ) + { + /* default conventions have not yet been established; + * initialise them now! + */ + conventions = getopt_set_conventions; + + } + + else if( flags & getopt_set_conventions ) + /* + * default conventions may have already been established, + * but this is a specific request to augment them. + */ + conventions |= flags; + + /* in any event, return the currently established conventions. + */ + return conventions; +} + +int is_switchar( CHAR flag ) +{ + /* A simple helper function, used to identify the switch character + * introducing an optional command line argument. + */ + return flag == getopt_switchar; +} + +const CHAR *getopt_match( CHAR lookup, const CHAR *opt_string ) +{ + /* Helper function, used to identify short form options. + */ + if( (*opt_string == getopt_pluschar) || (*opt_string == getopt_switchar) ) + ++opt_string; + if( *opt_string == getopt_takes_argument ) + ++opt_string; + do if( lookup == *opt_string ) return opt_string; + while( *++opt_string ); + return NULL; +} + +int getopt_match_long( const CHAR *nextchar, const CHAR *optname ) +{ + /* Helper function, used to identify potential matches for + * long form options. + */ + CHAR matchchar; + while( (matchchar = *nextchar++) && (matchchar == *optname) ) + /* + * skip over initial substring which DOES match. + */ + ++optname; + + if( matchchar ) + { + /* did NOT match the entire argument to an initial substring + * of a defined option name ... + */ + if( matchchar != getopt_arg_assign ) + /* + * ... and didn't stop at an `=' internal field separator, + * so this is NOT a possible match. + */ + return getopt_no_match; + + /* DID stop at an `=' internal field separator, + * so this IS a possible match, and what follows is an + * argument to the possibly matched option. + */ + optarg = (char *)(nextchar); + } + return *optname + /* + * if we DIDN'T match the ENTIRE text of the option name, + * then it's a possible abbreviated match ... + */ + ? getopt_abbreviated_match + /* + * but if we DID match the entire option name, + * then it's a DEFINITE EXACT match. + */ + : getopt_exact_match; +} + +int getopt_resolved( int mode, int argc, CHAR *const *argv, int *argind, +struct option *opt, int index, int *retindex, const CHAR *optstring ) +{ + /* Helper function to establish appropriate return conditions, + * on resolution of a long form option. + */ + if( retindex != NULL ) + *retindex = index; + + /* On return, `optind' should normally refer to the argument, if any, + * which follows the current one; it is convenient to set this, before + * checking for the presence of any `optarg'. + */ + optind = *argind + 1; + + if( optarg && (opt[index].has_arg == no_argument) ) + /* + * it is an error for the user to specify an option specific argument + * with an option which doesn't expect one! + */ + return getopt_argerror( mode, "option `%s%s' doesn't accept an argument\n", + PROGNAME, opt + index, getopt_unknown ); + + else if( (optarg == NULL) && (opt[index].has_arg == required_argument) ) + { + /* similarly, it is an error if no argument is specified + * with an option which requires one ... + */ + if( optind < argc ) + /* + * ... except that the requirement may be satisfied from + * the following command line argument, if any ... + */ + optarg = argv[*argind = optind++]; + + else + /* so fail this case, only if no such argument exists! + */ + return getopt_argerror( mode, "option `%s%s' requires an argument\n", + PROGNAME, opt + index, getopt_missing_arg( optstring ) ); + } + + /* when the caller has provided a return buffer ... + */ + if( opt[index].flag != NULL ) + { + /* ... then we place the proper return value there, + * and return a status code of zero ... + */ + *(opt[index].flag) = opt[index].val; + return 0; + } + /* ... otherwise, the return value becomes the status code. + */ + return opt[index].val; +} + +static +#define getopt_std_args int argc, CHAR *const argv[], const CHAR *optstring +int getopt_parse( int mode, getopt_std_args, ... ) +{ + /* Common core implementation for ALL `getopt' functions. + */ + static int argind = 0; + static int optbase = 0; + static const CHAR *nextchar = NULL; + static int optmark = 0; + + if( (optreset |= (optind < 1)) || (optind < optbase) ) + { + /* POSIX does not prescribe any definitive mechanism for restarting + * a `getopt' scan, but some applications may require such capability. + * We will support it, by allowing the caller to adjust the value of + * `optind' downwards, (nominally setting it to zero). Since POSIX + * wants `optind' to have an initial value of one, but we want all + * of our internal place holders to be initialised to zero, when we + * are called for the first time, we will handle such a reset by + * adjusting all of the internal place holders to one less than + * the adjusted `optind' value, (but never to less than zero). + */ + if( optreset ) + { + /* User has explicitly requested reinitialisation... + * We need to reset `optind' to it's normal initial value of 1, + * to avoid a potential infinitely recursive loop; by doing this + * up front, we also ensure that the remaining place holders + * will be correctly reinitialised to no less than zero. + */ + optind = 1; + + /* We also need to clear the `optreset' request... + */ + optreset = 0; + } + + /* Now, we may safely reinitialise the internal place holders, to + * one less than `optind', without fear of making them negative. + */ + optmark = optbase = argind = optind - 1; + nextchar = NULL; + } + + /* From a POSIX perspective, the following is `undefined behaviour'; + * we implement it thus, for compatibility with GNU and BSD getopt. + */ + else if( optind > (argind + 1) ) + { + /* Some applications expect to be able to manipulate `optind', + * causing `getopt' to skip over one or more elements of `argv'; + * POSIX doesn't require us to support this brain-damaged concept; + * (indeed, POSIX defines no particular behaviour, in the event of + * such usage, so it must be considered a bug for an application + * to rely on any particular outcome); nonetheless, Mac-OS-X and + * BSD actually provide *documented* support for this capability, + * so we ensure that our internal place holders keep track of + * external `optind' increments; (`argind' must lag by one). + */ + argind = optind - 1; + + /* When `optind' is misused, in this fashion, we also abandon any + * residual text in the argument we had been parsing; this is done + * without any further processing of such abandoned text, assuming + * that the caller is equipped to handle it appropriately. + */ + nextchar = NULL; + } + + if( nextchar && *nextchar ) + { + /* we are parsing a standard, or short format, option argument ... + */ + const CHAR *optchar; + if( (optchar = getopt_match( optopt = *nextchar++, optstring )) != NULL ) + { + /* we have identified it as valid ... + */ + if( optchar[1] == getopt_takes_argument ) + { + /* and determined that it requires an associated argument ... + */ + if( ! *(optarg = (char *)(nextchar)) ) + { + /* the argument is NOT attached ... + */ + if( optchar[2] == getopt_takes_argument ) + /* + * but this GNU extension marks it as optional, + * so we don't provide one on this occasion. + */ + optarg = NULL; + + /* otherwise this option takes a mandatory argument, + * so, provided there is one available ... + */ + else if( (argc - argind) > 1 ) + /* + * we take the following command line argument, + * as the appropriate option argument. + */ + optarg = argv[++argind]; + + /* but if no further argument is available, + * then there is nothing we can do, except for + * issuing the requisite diagnostic message. + */ + else + { + complain( "option requires an argument -- %c", optopt ); + return getopt_missing_arg( optstring ); + } + } + optind = argind + 1; + nextchar = NULL; + } + else + optarg = NULL; + optind = (nextchar && *nextchar) ? argind : argind + 1; + return optopt; + } + /* if we didn't find a valid match for the specified option character, + * then we fall through to here, so take appropriate diagnostic action. + */ + if( mode == getopt_mode_long_only ) + { + complain( "unrecognised option `-%s'", --nextchar ); + nextchar = NULL; + optopt = 0; + } + else + complain( "invalid option -- %c", optopt ); + optind = (nextchar && *nextchar) ? argind : argind + 1; + return getopt_unknown; + } + + if( optmark > optbase ) + { + /* This can happen, in GNU parsing mode ONLY, when we have + * skipped over non-option arguments, and found a subsequent + * option argument; in this case we permute the arguments. + */ + int index; + /* + * `optspan' specifies the number of contiguous arguments + * which are spanned by the current option, and so must be + * moved together during permutation. + */ + int optspan = argind - optmark + 1; + /* + * we use `this_arg' to store these temporarily. + */ + CHAR *this_arg[100]; + /* + * we cannot manipulate `argv' directly, since the `getopt' + * API prototypes it as `read-only'; this cast to `arglist' + * allows us to work around that restriction. + */ + CHAR **arglist = (char **)(argv); + + /* save temporary copies of the arguments which are associated + * with the current option ... + */ + for( index = 0; index < optspan; ++index ) + this_arg[index] = arglist[optmark + index]; + + /* move all preceding non-option arguments to the right, + * overwriting these saved arguments, while making space + * to replace them in their permuted location. + */ + for( --optmark; optmark >= optbase; --optmark ) + arglist[optmark + optspan] = arglist[optmark]; + + /* restore the temporarily saved option arguments to + * their permuted location. + */ + for( index = 0; index < optspan; ++index ) + arglist[optbase + index] = this_arg[index]; + + /* adjust `optbase', to account for the relocated option. + */ + optbase += optspan; + } + + else + /* no permutation occurred ... + * simply adjust `optbase' for all options parsed so far. + */ + optbase = argind + 1; + + /* enter main parsing loop ... + */ + while( argc > ++argind ) + { + /* inspect each argument in turn, identifying possible options ... + */ + if( is_switchar( *(nextchar = argv[optmark = argind]) ) && *++nextchar ) + { + /* we've found a candidate option argument ... */ + + if( is_switchar( *nextchar ) ) + { + /* it's a double hyphen argument ... */ + + const CHAR *refchar = nextchar; + if( *++refchar ) + { + /* and it looks like a long format option ... + * `getopt_long' mode must be active to accept it as such, + * `getopt_long_only' also qualifies, but we must downgrade + * it to force explicit handling as a long format option. + */ + if( mode >= getopt_mode_long ) + { + nextchar = refchar; + mode = getopt_mode_long; + } + } + else + { + /* this is an explicit `--' end of options marker, so wrap up now! + */ + if( optmark > optbase ) + { + /* permuting the argument list as necessary ... + * (note use of `this_arg' and `arglist', as above). + */ + CHAR *this_arg = argv[optmark]; + CHAR **arglist = (CHAR **)(argv); + + /* move all preceding non-option arguments to the right ... + */ + do arglist[optmark] = arglist[optmark - 1]; + while( optmark-- > optbase ); + + /* reinstate the `--' marker, in its permuted location. + */ + arglist[optbase] = this_arg; + } + /* ... before finally bumping `optbase' past the `--' marker, + * and returning the `all done' completion indicator. + */ + optind = ++optbase; + return getopt_all_done; + } + } + else if( mode < getopt_mode_long_only ) + { + /* it's not an explicit long option, and `getopt_long_only' isn't active, + * so we must explicitly try to match it as a short option. + */ + mode = getopt_mode_standard; + } + + if( mode >= getopt_mode_long ) + { + /* the current argument is a long form option, (either explicitly, + * introduced by a double hyphen, or implicitly because we were called + * by `getopt_long_only'); this is where we parse it. + */ + int lookup; + int matched = -1; + struct option *longopts; + int *optindex; + /* we need to fetch the `extra' function arguments, which are + * specified for the `getopt_long' APIs. + */ + va_list refptr; + va_start( refptr, optstring ); + longopts = va_arg( refptr, struct option * ); + optindex = va_arg( refptr, int * ); + va_end( refptr ); + + /* ensuring that `optarg' does not inherit any junk, from parsing + * preceding arguments ... + */ + optarg = NULL; + for( lookup = 0; longopts && longopts[lookup].name; ++lookup ) + { + /* scan the list of defined long form options ... + */ + switch( getopt_match_long( nextchar, longopts[lookup].name ) ) + { + /* looking for possible matches for the current argument. + */ + case getopt_exact_match: + /* + * when an exact match is found, + * return it immediately, setting `nextchar' to NULL, + * to ensure we don't mistakenly try to match any + * subsequent characters as short form options. + */ + nextchar = NULL; + return getopt_resolved( mode, argc, argv, &argind, + longopts, lookup, optindex, optstring ); + + case getopt_abbreviated_match: + /* + * but, for a partial (initial substring) match ... + */ + if( matched >= 0 ) + { + /* if this is not the first, then we have an ambiguity ... + */ + optopt = 0; + nextchar = NULL; + optind = argind + 1; + complain( "option `%s' is ambiguous", argv[argind] ); + return getopt_unknown; + } + /* otherwise just note that we've found a possible match ... + */ + matched = lookup; + } + } + if( matched >= 0 ) + { + /* if we get to here, then we found exactly one partial match, + * so return it, as for an exact match. + */ + nextchar = NULL; + return getopt_resolved( mode, argc, argv, &argind, + longopts, matched, optindex, optstring ); + } + if( mode < getopt_mode_long_only ) + { + /* if here, then we had what SHOULD have been a long form option, + * but it is unmatched; (perversely, `mode == getopt_mode_long_only' + * allows us to still try to match it as a short form option). + */ + optopt = 0; + nextchar = NULL; + optind = argind + 1; + complain( "unrecognised option `%s'", argv[argind] ); + return getopt_unknown; + } + } + /* fall through to handle standard short form options... + * when the option argument format is neither explictly identified + * as long, nor implicitly matched as such, and the argument isn't + * just a bare hyphen, (which isn't an option), then we make one + * recursive call to explicitly interpret it as short format. + */ + if( *nextchar ) + return getopt_parse( mode, argc, argv, optstring ); + } + /* if we get to here, then we've parsed a non-option argument ... + * in GNU compatibility mode, we step over it, so we can permute + * any subsequent option arguments, but ... + */ + if( *optstring == getopt_switchar ) + { + /* if `optstring' begins with a `-' character, this special + * GNU specific behaviour requires us to return the non-option + * arguments in strict order, as pseudo-arguments to a special + * option, with return value defined as `getopt_ordered'. + */ + nextchar = NULL; + optind = argind + 1; + optarg = argv[argind]; + return getopt_ordered; + } + if( getopt_conventions( *optstring ) & getopt_posixly_correct ) + /* + * otherwise ... + * for POSIXLY_CORRECT behaviour, or if `optstring' begins with + * a `+' character, then we break out of the parsing loop, so that + * the scan ends at the current argument, with no permutation. + */ + break; + } + /* fall through when all arguments have been evaluated, + */ + optind = optbase; + return getopt_all_done; +} + +/* All three public API entry points are trivially defined, + * in terms of the internal `getopt_parse' function. + */ +int getopt( getopt_std_args ) +{ + return getopt_parse( getopt_mode_standard, argc, argv, optstring ); +} + +int getopt_long( getopt_std_args, const struct option *opts, int *index ) +{ + return getopt_parse( getopt_mode_long, argc, argv, optstring, opts, index ); +} + +int getopt_long_only( getopt_std_args, const struct option *opts, int *index ) +{ + return getopt_parse( getopt_mode_long_only, argc, argv, optstring, opts, index ); +} + +#ifdef __weak_alias +/* + * These Microsnot style uglified aliases are provided for compatibility + * with the previous MinGW implementation of the getopt API. + */ +__weak_alias( getopt, _getopt ) +__weak_alias( getopt_long, _getopt_long ) +__weak_alias( getopt_long_only, _getopt_long_only ) +#endif + /* $RCSfile: getopt.c,v $Revision: 1.9 $: end of file */ \ No newline at end of file diff --git a/getopt.h b/getopt.h index 6cfa016..76ddefa 100644 --- a/getopt.h +++ b/getopt.h @@ -1,108 +1,108 @@ -#ifndef __GETOPT_H__ -/* - * getopt.h - * - * $Id: getopt.h,v 1.4 2009/01/04 17:35:36 keithmarshall Exp $ - * - * Defines constants and function prototypes required to implement - * the `getopt', `getopt_long' and `getopt_long_only' APIs. - * - * This file is part of the MinGW32 package set. - * - * Contributed by Keith Marshall - * - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * $Revision: 1.4 $ - * $Author: keithmarshall $ - * $Date: 2009/01/04 17:35:36 $ - * - */ -#define __GETOPT_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -extern int optind; /* index of first non-option in argv */ -extern int optopt; /* single option character, as parsed */ -extern int opterr; /* flag to enable built-in diagnostics... */ - /* (user may set to zero, to suppress) */ - -extern char *optarg; /* pointer to argument of current option */ - -extern int getopt( int, char * const [], const char * ); - -#ifdef _BSD_SOURCE -/* - * BSD adds the non-standard `optreset' feature, for reinitialisation - * of `getopt' parsing. We support this feature, for applications which - * proclaim their BSD heritage, before including this header; however, - * to maintain portability, developers are advised to avoid it. - */ -# define optreset __mingw_optreset - -extern int optreset; -#endif -#ifdef __cplusplus -} -#endif -/* - * POSIX requires the `getopt' API to be specified in `unistd.h'; - * thus, `unistd.h' includes this header. However, we do not want - * to expose the `getopt_long' or `getopt_long_only' APIs, when - * included in this manner. Thus, close the standard __GETOPT_H__ - * declarations block, and open an additional __GETOPT_LONG_H__ - * specific block, only when *not* __UNISTD_H_SOURCED__, in which - * to declare the extended API. - */ -#endif /* !defined(__GETOPT_H__) */ -#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) -#define __GETOPT_LONG_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -struct option /* specification for a long form option... */ -{ - const char *name; /* option name, without leading hyphens */ - int has_arg; /* does it take an argument? */ - int *flag; /* where to save its status, or NULL */ - int val; /* its associated status value */ -}; - -enum /* permitted values for its `has_arg' field... */ -{ - no_argument = 0, /* option never takes an argument */ - required_argument, /* option always requires an argument */ - optional_argument /* option may take an argument */ -}; - -extern int getopt_long( int, char * const [], const char *, const struct option *, int * ); -extern int getopt_long_only( int, char * const [], const char *, const struct option *, int * ); -/* - * Previous MinGW implementation had... - */ -#ifndef HAVE_DECL_GETOPT -/* - * ...for the long form API only; keep this for compatibility. - */ -# define HAVE_DECL_GETOPT 1 -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ +#ifndef __GETOPT_H__ +/* + * getopt.h + * + * $Id: getopt.h,v 1.4 2009/01/04 17:35:36 keithmarshall Exp $ + * + * Defines constants and function prototypes required to implement + * the `getopt', `getopt_long' and `getopt_long_only' APIs. + * + * This file is part of the MinGW32 package set. + * + * Contributed by Keith Marshall + * + * + * THIS SOFTWARE IS NOT COPYRIGHTED + * + * This source code is offered for use in the public domain. You may + * use, modify or distribute it freely. + * + * This code is distributed in the hope that it will be useful but + * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY + * DISCLAIMED. This includes but is not limited to warranties of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * $Revision: 1.4 $ + * $Author: keithmarshall $ + * $Date: 2009/01/04 17:35:36 $ + * + */ +#define __GETOPT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int optind; /* index of first non-option in argv */ +extern int optopt; /* single option character, as parsed */ +extern int opterr; /* flag to enable built-in diagnostics... */ + /* (user may set to zero, to suppress) */ + +extern char *optarg; /* pointer to argument of current option */ + +extern int getopt( int, char * const [], const char * ); + +#ifdef _BSD_SOURCE +/* + * BSD adds the non-standard `optreset' feature, for reinitialisation + * of `getopt' parsing. We support this feature, for applications which + * proclaim their BSD heritage, before including this header; however, + * to maintain portability, developers are advised to avoid it. + */ +# define optreset __mingw_optreset + +extern int optreset; +#endif +#ifdef __cplusplus +} +#endif +/* + * POSIX requires the `getopt' API to be specified in `unistd.h'; + * thus, `unistd.h' includes this header. However, we do not want + * to expose the `getopt_long' or `getopt_long_only' APIs, when + * included in this manner. Thus, close the standard __GETOPT_H__ + * declarations block, and open an additional __GETOPT_LONG_H__ + * specific block, only when *not* __UNISTD_H_SOURCED__, in which + * to declare the extended API. + */ +#endif /* !defined(__GETOPT_H__) */ +#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) +#define __GETOPT_LONG_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +struct option /* specification for a long form option... */ +{ + const char *name; /* option name, without leading hyphens */ + int has_arg; /* does it take an argument? */ + int *flag; /* where to save its status, or NULL */ + int val; /* its associated status value */ +}; + +enum /* permitted values for its `has_arg' field... */ +{ + no_argument = 0, /* option never takes an argument */ + required_argument, /* option always requires an argument */ + optional_argument /* option may take an argument */ +}; + +extern int getopt_long( int, char * const [], const char *, const struct option *, int * ); +extern int getopt_long_only( int, char * const [], const char *, const struct option *, int * ); +/* + * Previous MinGW implementation had... + */ +#ifndef HAVE_DECL_GETOPT +/* + * ...for the long form API only; keep this for compatibility. + */ +# define HAVE_DECL_GETOPT 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */ /* $RCSfile: getopt.h,v $Revision: 1.4 $: end of file */ \ No newline at end of file diff --git a/tncinfo.h b/tncinfo.h index 8e0272c..2d6ad93 100644 --- a/tncinfo.h +++ b/tncinfo.h @@ -282,6 +282,9 @@ typedef struct AGWINFO int Modem; // Modem number in list char ModemName[20]; unsigned char Version[4]; + unsigned char fx25Flags; + unsigned char il2pFlags; + unsigned char il2pcrc; } *PAGWINFO;