diff --git a/.svn/pristine/04/04f3425d2266f8ab7e39728796f66092f2be0511.svn-base b/.svn/pristine/04/04f3425d2266f8ab7e39728796f66092f2be0511.svn-base
new file mode 100644
index 0000000..8d243b1
--- /dev/null
+++ b/.svn/pristine/04/04f3425d2266f8ab7e39728796f66092f2be0511.svn-base
@@ -0,0 +1,3356 @@
+/*
+Copyright 2001-2022 John Wiseman G8BPQ
+
+This file is part of LinBPQ/BPQ32.
+
+LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+LinBPQ/BPQ32 is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
+*/
+
+//
+// DLL to provide AXIP support for G8BPQ switch in a
+// 32bit environment,
+//
+// Uses BPQ EXTERNAL interface
+//
+
+// Version 1.1 August 2001
+//
+// Send to all matching entries in map table
+// (Mainly for NODES braodcasts to multiple stations)
+//
+
+// Version 1.2 September 2001
+//
+// Support UDP as well as raw IP
+
+// Version 1.3 October 2001
+//
+// Allow host names as well as numeric IP addresses
+//
+// Version 1.4 November 2002
+//
+// Implement keepalive for NAT routers
+//
+
+// Version 1.5 December 2004
+//
+// Implement a "MHEARD" facility
+//
+
+
+// Version 1.6 August 2005
+//
+// Treat NULL string in Registry as use current directory
+
+
+// Version 1.7 December 2005
+//
+// Create a separate thread to open sockets to avoid hang on XP SP2
+
+
+// Version 1.8 January 2006
+//
+// Get config file location from Node (will check bpq directory)
+
+
+// Version 1.9 March 2006
+//
+// Allow multiple listening UDP ports
+// Kick off resolver on EXTRESTART
+// Remove redundant DYNAMIC processing
+
+// Version 1.10 October 2006
+//
+// Add "Minimize to Tray" option
+// Write diagnostics to BPQ console window instead of STDOUT
+
+// Version 1.11 October 2007
+//
+// Sort MHeard and discard last entry if full
+// Add Commands to re-read config file and manually add an ARP entry
+
+// Version 1.12 February 2008
+//
+// Check received length
+// Changes for unload of bpq32.dll
+// Add Close Driver function
+// Dynamic Load of bpq32.dll
+
+// Version 1.13 October 2008
+//
+// Add Linux-style config of broadcast addressess
+
+// Version 1.13.2 January 2009
+//
+// Add Start Minimized Option
+
+// Version 1.13.3 February 2009
+//
+// Save Window positions
+
+// Version 1.13.4 March 2009
+//
+// Fix loop on config file error
+
+// Version 1.14.1 April 2009
+//
+// Add option to reject messages if sender is not in ARP Table
+// Add option to add received calls to ARP Table
+
+// Version 1.15.1 May 2009
+//
+// Add IP/TCP option
+
+// Version 1.15.2 August 2009
+//
+// Extra Debug Output in TCP Mode
+// Fix problem if TCP entry was first in table
+// Include TCP sessions in MHEARD
+// Add T flag to Resolver window fot TCP Sessions
+// Set SO_KEEPALIVE and SO_CONDITIONAL_ACCEPT socket options
+
+// Version 1.15.4 August 2009
+
+// Recycle Listening Socket if no connect for 60 mins
+// Clear data connections if no data for 60 mins
+// Repaint MH Window after clear.
+
+// Version 1.15.5 Spetmber 2010
+
+// Add option to get config from bpq32.dll
+// Moved to BPQ32.dll - no separate version number onw.
+
+// October 2010
+
+// Allow multiple axip ports.
+
+// June 2011
+
+// Add IPv6 support
+
+#define _CRT_SECURE_NO_DEPRECATE
+
+#include "cheaders.h"
+#ifndef WIN32
+#include
+#include
+#include
+#endif
+#include "bpq32.h"
+
+#ifndef LINBPQ
+#include "kernelresource.h"
+#include
+#endif
+
+#include
+
+#define WSA_ACCEPT WM_USER + 1
+#define WSA_DATA WM_USER + 2
+#define WSA_CONNECT WM_USER + 3
+
+// Cater for only systems without IPV6_V6ONLY
+
+#ifndef IPV6_V6ONLY
+#define IPV6_V6ONLY 0x27
+#endif
+
+#ifndef MAXGETHOSTSTRUCT
+#define MAXGETHOSTSTRUCT 1024
+#endif
+
+
+#define FEND 0xC0 // KISS CONTROL CODES
+#define FESC 0xDB
+#define TFEND 0xDC
+#define TFESC 0xDD
+
+int ResolveDelay = 0;
+
+
+extern BOOL StartMinimized;
+
+VOID * zalloc(int len);
+
+int ResetExtDriver(int num);
+BOOL ProcessConfig();
+VOID FreeConfig();
+
+extern UCHAR BPQDirectory[];
+
+
+extern int OffsetH, OffsetW;
+
+static void ResolveNames(struct AXIPPORTINFO * PORT);
+void OpenSockets(struct AXIPPORTINFO * PORT);
+void CloseSockets(struct AXIPPORTINFO * PORT);
+
+
+static int CONVFROMAX25(char * incall, char * outcall);
+void CreateMHWindow(struct AXIPPORTINFO * PORT);
+int Update_MH_List(struct AXIPPORTINFO * PORT, UCHAR * ipad, char * call, char proto, short port, BOOL IPv6);
+int Update_MH_KeepAlive(struct AXIPPORTINFO * PORT, struct in_addr ipad, char proto, short port);
+unsigned short int compute_crc(unsigned char *buf,int l);
+unsigned int find_arp(unsigned char * call);
+BOOL add_arp_entry(struct AXIPPORTINFO * PORT, unsigned char * call, UCHAR * ip, int len, int port,unsigned char * name,
+ int keepalive, BOOL BCFlag, BOOL AutoAdded, int TCPMode, int SourcePort, BOOL IPv6, int noUpdate, int useSourcePort);
+BOOL add_bc_entry(struct AXIPPORTINFO * PORT, unsigned char * call, int len);
+BOOL convtoax25(unsigned char * callsign, unsigned char * ax25call, int * calllen);
+static BOOL ReadConfigFile(int Port);
+static int ProcessLine(char * buf, struct AXIPPORTINFO * PORT);
+int CheckKeepalives(struct AXIPPORTINFO * PORT);
+BOOL CopyScreentoBuffer(char * buff, struct AXIPPORTINFO * PORT);
+int DumpFrameInHex(unsigned char * msg, int len);
+VOID SendFrame(struct AXIPPORTINFO * PORT, struct arp_table_entry * arp_table, UCHAR * buff, int txlen);
+BOOL CheckSourceisResolvable(struct AXIPPORTINFO * PORT, char * call, int FromPort, VOID * rxaddr, int ToPort);
+int DataSocket_Read(struct arp_table_entry * sockptr, SOCKET sock);
+int GetMessageFromBuffer(struct AXIPPORTINFO * PORT, char * Buffer);
+int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
+int KissDecode(UCHAR * inbuff, int len);
+int Socket_Accept(int SocketId);
+int Socket_Connect(int SocketId, int Error);
+int Socket_Data(int sock, int error, int eventcode);
+VOID TCPConnectThread(struct arp_table_entry * arp);
+VOID __cdecl Debugprintf(const char * format, ...);
+VOID __cdecl Consoleprintf(const char * format, ...);
+BOOL OpenListeningSocket(struct AXIPPORTINFO * PORT, struct arp_table_entry * arp);
+VOID Format_Addr(unsigned char * Addr, char * Output, BOOL IPV6);
+static void CreateResolverWindow(struct AXIPPORTINFO * PORT);
+VOID SaveMDIWindowPos(HWND hWnd, char * RegKey, char * Value, BOOL Minimized);
+VOID SaveAXIPCache(struct AXIPPORTINFO * PORT);
+VOID GetAXIPCache(struct AXIPPORTINFO * PORT);
+
+
+union
+{
+ struct sockaddr_in sinx;
+ struct sockaddr_in6 sinx6;
+} sinx;
+/*
+union
+{
+ struct sockaddr_in destaddr;
+ struct sockaddr_in6 destaddr6;
+} destaddr;
+*/
+
+#define IP_AXIP 93 // IP Protocol for AXIP
+
+#pragma pack(1)
+
+struct iphdr {
+// unsigned int version:4; // Version of IP
+// unsigned int h_len:4; // length of the header
+ unsigned char h_lenvers; // Version + length of the header
+ unsigned char tos; // Type of service
+ unsigned short total_len; // total length of the packet
+ unsigned short ident; // unique identifier
+ unsigned short frag_and_flags; // flags
+ unsigned char ttl;
+ unsigned char proto; // protocol (TCP, UDP etc)
+ unsigned short checksum; // IP checksum
+
+ unsigned int sourceIP;
+ unsigned int destIP;
+
+};
+
+#pragma pack()
+
+
+#define TCPMaster 1
+#define TCPSlave 2
+
+#define TCPListening 1
+#define TCPConnecting 2
+#define TCPConnected 4
+
+#ifndef LINBPQ
+
+LOGFONT LFTTYFONT ;
+
+extern HFONT hFont ;
+
+RECT ResRect;
+RECT MHRect;
+
+extern HKEY REGTREE;
+
+extern HWND ClientWnd, FrameWnd;
+extern HMENU hMainFrameMenu, hBaseMenu, hWndMenu;
+extern HBRUSH bgBrush;
+
+#endif
+
+//struct tagMSG Msg;
+
+//char buf[MAXGETHOSTSTRUCT];
+
+int addrlen6 = sizeof(struct sockaddr_in6);
+int addrlen = sizeof(struct sockaddr_in);
+
+extern unsigned short CRCTAB[];
+unsigned int AXIPInst = 0;
+
+char CantReplyList[512] = ""; // To suppress duplicate "Can't Reply" messages
+
+DWORD n;
+
+struct AXIPPORTINFO * Portlist[MaxBPQPortNo + 1];
+
+int InitAXIP(int Port);
+
+int CurrentResEntries;
+
+static char ConfigClassName[]="CONFIG";
+
+HANDLE hInstance;
+
+VOID SaveAXIPWindowPos(int port)
+{
+#ifndef LINBPQ
+ struct AXIPPORTINFO * PORT;
+ char Key[80];
+
+ PORT = Portlist[port];
+
+ if (PORT == NULL)
+ return;
+
+ sprintf(Key, "PACTOR\\PORT%d", port);
+
+ SaveMDIWindowPos(PORT->hMHWnd, Key, "MHSize", PORT->MHMinimized);
+ SaveMDIWindowPos(PORT->hResWnd, Key, "ResSize", PORT->ResMinimized);
+#endif
+ return;
+}
+
+
+static size_t ExtProc(int fn, int port, PMESSAGE buff)
+{
+ struct iphdr * iphdrptr;
+ int len,txlen=0,err,index,digiptr,i;
+ unsigned short int crc;
+ char rxbuff[5000];
+ char axcall[7];
+ char errmsg[100];
+ union
+ {
+ struct sockaddr_in rxaddr;
+ struct sockaddr_in6 rxaddr6;
+ } RXaddr;
+ struct AXIPPORTINFO * PORT = Portlist[port];
+
+ switch (fn)
+ {
+ case 1: // poll
+
+ //
+ // Check Keepalive timers
+ //
+ time(&PORT->ltime);
+
+ if (PORT->ltime-PORT->lasttime >9 )
+ {
+ PORT->lasttime=PORT->ltime;
+ CheckKeepalives(PORT);
+ }
+
+ if (PORT->needip)
+ {
+ char call[7];
+
+ len = recvfrom(PORT->sock,rxbuff,500,0,(struct sockaddr *)&RXaddr.rxaddr,&addrlen);
+
+ if (len == -1)
+ {
+ err = WSAGetLastError();
+ }
+ else
+ {
+ iphdrptr=(struct iphdr *)&rxbuff;
+
+ if (len == ntohs(iphdrptr->total_len))
+ {
+ len-=20; // IP HEADER
+
+ if (memcmp(&rxbuff[20], "Keepalive", 9) == 0 )
+ {
+ if (PORT->MHEnabled)
+ Update_MH_KeepAlive(PORT, RXaddr.rxaddr.sin_addr,'I',93);
+
+ return 0;
+ }
+ crc = compute_crc(&rxbuff[20], len);
+
+ if (crc == 0xf0b8) // Good CRC
+ {
+ len-=2; // Remove CRC
+
+ if (len > MAXDATA)
+ {
+ sprintf(errmsg,"BPQAXIP Invalid Msg Len=%d Source=%s",len,inet_ntoa(RXaddr.rxaddr.sin_addr));
+ OutputDebugString(errmsg);
+ DumpFrameInHex(&rxbuff[20], len);
+ return 0;
+ }
+
+ memcpy(&buff->DEST, &rxbuff[20],len);
+ len += (3 + sizeof(void *));
+
+ PutLengthinBuffer((PDATAMESSAGE)buff, len); // Needed for arm5 portability
+
+ memcpy(call, &buff->ORIGIN, 7);
+ call[6] &= 0x7e; // Mask End of Address bit
+
+ //
+ // Do MH Proccessing if enabled
+ //
+
+ if (PORT->MHEnabled)
+ Update_MH_List(PORT, (UCHAR *)&RXaddr.rxaddr.sin_addr.s_addr, &buff->ORIGIN[0], 'I', 93, 0);
+
+ // Check Exclude
+
+ if (CheckExcludeList(call) == 0)
+ return 0;
+
+
+ if (PORT->Checkifcanreply)
+ {
+ if (CheckSourceisResolvable(PORT, call, 0, &RXaddr, 0))
+
+ return 1;
+
+ else
+ // Can't reply. If AutoConfig is set, add to table and accept, else reject
+
+ if (PORT->AutoAddARP)
+ return add_arp_entry(PORT, call, (UCHAR *)&RXaddr.rxaddr.sin_addr.s_addr, 7, 0, inet_ntoa(RXaddr.rxaddr.sin_addr), 0, PORT->AutoAddBC, TRUE, 0, 0, FALSE, 0, 0);
+ else
+ {
+ char From[11] = "|";
+ From[ConvFromAX25(call, &From[1]) + 1] = 0;
+ if (strstr(CantReplyList, From) == 0)
+ {
+ if (strlen(CantReplyList) < 500);
+ strcat(CantReplyList, From);
+ Debugprintf("AXIP Packet from %s dropped - can't reply", &From[1]);
+ }
+ return 0;
+ }
+ }
+ else
+ return(1);
+ }
+ //
+ // CRC Error
+ //
+
+ sprintf(errmsg,"BPQAXIP Invalid CRC=%d Source=%s",crc,inet_ntoa(RXaddr.rxaddr.sin_addr));
+ OutputDebugString(errmsg);
+
+ return (0);
+ }
+
+ //
+ // Bad Length
+ //
+
+ return (0);
+ }
+ }
+
+ for (i=0;iNumberofUDPPorts;i++)
+ {
+ char call[7];
+
+ if (PORT->IPv6[i])
+ len = recvfrom(PORT->udpsock[i],rxbuff,500,0,(struct sockaddr *)&RXaddr.rxaddr, &addrlen6);
+ else
+ len = recvfrom(PORT->udpsock[i],rxbuff,500,0,(struct sockaddr *)&RXaddr.rxaddr, &addrlen);
+
+ if (len == -1)
+ {
+ err = WSAGetLastError();
+ }
+ else
+ {
+ if (memcmp(rxbuff, "Keepalive", 9) == 0 )
+ {
+ if (PORT->MHEnabled)
+ Update_MH_KeepAlive(PORT, RXaddr.rxaddr.sin_addr, 'U', PORT->udpport[i]);
+
+ continue;
+ }
+
+ crc = compute_crc(&rxbuff[0], len);
+
+ if (crc == 0xf0b8) // Good CRC
+ {
+ len-=2; // Remove CRC
+
+ if (len > MAXDATA)
+ {
+ sprintf(errmsg,"BPQAXIP Invalid Msg Len=%d Source=%s Port %d",len,inet_ntoa(RXaddr.rxaddr.sin_addr),PORT->udpport[i]);
+ OutputDebugString(errmsg);
+ DumpFrameInHex(&rxbuff[0], len);
+ return 0;
+ }
+
+ memcpy(&buff->DEST, &rxbuff[0], len);
+
+ len += (3 + sizeof(void *));
+
+ PutLengthinBuffer((PDATAMESSAGE)buff, len);
+
+ memcpy(call, &buff->ORIGIN, 7);
+
+ call[6] &= 0x7e; // Mask End of Address bit
+
+ //
+ // Do MH Proccessing if enabled
+ //
+
+ if (PORT->MHEnabled)
+ if (PORT->IPv6[i])
+ Update_MH_List(PORT, (UCHAR *)&RXaddr.rxaddr6.sin6_addr, &buff->ORIGIN[0], 'U', PORT->udpport[i], TRUE);
+ else
+ Update_MH_List(PORT, (UCHAR *)&RXaddr.rxaddr.sin_addr.s_addr, &buff->ORIGIN[0], 'U', PORT->udpport[i], FALSE);
+
+ // Check Exclude
+
+ if (CheckExcludeList(call) == 0)
+ return 0;
+
+ if (PORT->Checkifcanreply)
+ {
+ if (CheckSourceisResolvable(PORT, call, htons(RXaddr.rxaddr.sin_port), &RXaddr, PORT->udpport[i]))
+ return 1;
+ else
+ {
+ // Can't reply. If AutoConfig is set, add to table and accept, else reject
+
+ if (PORT->AutoAddARP)
+ if (PORT->IPv6[i])
+ {
+ char Addr[80];
+ Format_Addr((UCHAR *)&RXaddr.rxaddr6.sin6_addr, Addr, TRUE);
+ return add_arp_entry(PORT, call, (UCHAR *)&RXaddr.rxaddr6.sin6_addr, 7, htons(RXaddr.rxaddr6.sin6_port), Addr, 0, PORT->AutoAddBC, TRUE, 0, PORT->udpport[i], TRUE, 0, 0);
+ }
+ else
+ return add_arp_entry(PORT, call, (UCHAR *)&RXaddr.rxaddr.sin_addr.s_addr, 7, htons(RXaddr.rxaddr.sin_port), inet_ntoa(RXaddr.rxaddr.sin_addr), 0, PORT->AutoAddBC, TRUE, 0, PORT->udpport[i], FALSE, 0, 0);
+ else
+ {
+ char From[11] = "|";
+ From[ConvFromAX25(call, &From[1]) + 1] = 0;
+ if (strstr(CantReplyList, From) == 0)
+ {
+ if (strlen(CantReplyList) < 500);
+ strcat(CantReplyList, From);
+ Debugprintf("AXIP Packet from %s dropped - can't reply", &From[1]);
+ }
+ return 0;
+ }
+ }
+ }
+ else
+ return(1);
+ }
+
+ //
+ // CRC Error
+ //
+
+ sprintf(errmsg,"BPQAXIP Invalid CRC=%d Source=%s Port %d",crc,inet_ntoa(RXaddr.rxaddr.sin_addr),PORT->udpport[i]);
+ Debugprintf(errmsg);
+ rxbuff[len] = 0;
+ Debugprintf(rxbuff);
+
+
+ return (0);
+ }
+ }
+
+ if (PORT->NeedTCP)
+ {
+ len = GetMessageFromBuffer(PORT, rxbuff);
+
+ if (len)
+ {
+ len = KissDecode(rxbuff, len-1); // Len includes FEND
+ len -= 2; // Ignore Checksum
+
+ if (len < MAXDATA)
+ {
+ memcpy(&buff->DEST, &rxbuff[0], len);
+ len += (3 + sizeof(void *));
+
+ PutLengthinBuffer((PDATAMESSAGE)buff, len); // fix big endian issue
+ return 1;
+ }
+ else
+ {
+ Debugprintf("Oversized AX/TCP frame %d", len);
+ return 0;
+ }
+ }
+ }
+
+ return (0);
+
+ case 2: // send
+
+// txlen=(buff[6]<<8) + buff[5] - 5; // Len includes buffer header (7) but we add crc
+
+ txlen = GetLengthfromBuffer((PDATAMESSAGE)buff) - (MSGHDDRLEN - 2); // 2 for CRC
+
+ crc=compute_crc(&buff->DEST[0], txlen - 2);
+ crc ^= 0xffff;
+
+ buff->DEST[txlen - 2] = (crc & 0xff);
+ buff->DEST[txlen - 1] = (crc >> 8);
+
+ memcpy(axcall, &buff->DEST, 7); // Set to send to dest addr
+
+ // if digis are present, scan down list for first non-used call
+
+ if (buff->ORIGIN[6] == 0)
+ {
+ // end of addr bit not set, so scan digis
+
+ digiptr = 13; // start of first digi
+
+ while (((buff->ORIGIN[digiptr] & 0x80) == 0x80) && ((buff->ORIGIN[digiptr] & 0x1) == 0))
+ {
+ // This digi has been used, and it is not the last
+
+ digiptr+=7;
+ }
+
+ // if this has not been used, use it
+
+ if ((buff->ORIGIN[digiptr] & 0x80) == 0)
+ memcpy(axcall,&buff->ORIGIN[digiptr - 6], 7); // get next call
+ }
+
+ axcall[6] &= 0x7e;
+
+// If addresses to a broadcast address, send to all entries
+
+ for (i=0; i< PORT->NumberofBroadcastAddreses; i++)
+ {
+ if (memcmp(axcall, PORT->BroadcastAddresses[i].callsign, 7) == 0)
+ {
+ for (index = 0; index < PORT->arp_table_len; index++)
+ {
+ if (PORT->arp_table[index].BCFlag)
+ SendFrame(PORT, &PORT->arp_table[index], &buff->DEST[0], txlen);
+ }
+ return 0;
+ }
+ }
+
+// Send to all matching calls in arp table
+
+ index = 0;
+
+ while (index < PORT->arp_table_len)
+ {
+ if (memcmp(PORT->arp_table[index].callsign,axcall,PORT->arp_table[index].len) == 0)
+ {
+ SendFrame(PORT, &PORT->arp_table[index],&buff->DEST[0], txlen);
+ }
+ index++;
+ }
+ return (0);
+
+ case 3: // CHECK IF OK TO SEND
+
+ return (0); // OK
+
+ case 4: // reinit
+
+ CloseSockets(PORT);
+
+ if (ProcessConfig())
+ {
+ FreeConfig();
+ ReadConfigFile(port);
+ }
+ else
+ Consoleprintf("Failed to reread config file - leaving config unchanged");
+
+ _beginthread(OpenSockets, 0, PORT );
+
+ GetAXIPCache(PORT);
+
+ ResolveDelay = 2;
+#ifndef LINBPQ
+ InvalidateRect(PORT->hResWnd,NULL,TRUE);
+#endif
+ break;
+
+ case 5: // Terminate
+
+ CloseSockets(PORT);
+#ifndef LINBPQ
+ SendMessage(PORT->hMHWnd, WM_CLOSE, 0, 0);
+ SendMessage(PORT->hResWnd, WM_CLOSE, 0, 0);
+#endif
+ break;
+ }
+ return (0);
+}
+
+VOID SendFrame(struct AXIPPORTINFO * PORT, struct arp_table_entry * arp_table, UCHAR * buff, int txlen)
+{
+ int i;
+ SOCKET txsock, SourceSocket;
+
+ if (arp_table->TCPMode)
+ {
+ if (arp_table->TCPState == TCPConnected)
+ {
+ char outbuff[1000];
+ int newlen;
+
+ newlen = KissEncode(buff, outbuff, txlen);
+ send(arp_table->TCPSock, outbuff, newlen, 0);
+ }
+
+ return;
+ }
+
+ // Select source port by choosing right socket
+
+ // First Set Default for Protocol
+
+ for (i = 0; i < PORT->NumberofUDPPorts; i++)
+ {
+ if (PORT->IPv6[i] == arp_table->IPv6)
+ {
+ SourceSocket = PORT->udpsock[i]; // Use as source socket, therefore source port
+ break;
+ }
+ }
+
+ for (i = 0; i < PORT->NumberofUDPPorts; i++)
+ {
+ if (PORT->udpport[i] == arp_table->SourcePort && PORT->IPv6[i] == arp_table->IPv6)
+ {
+ SourceSocket = PORT->udpsock[i]; // Use as source socket, therefore source port
+ break;
+ }
+ }
+
+ if (arp_table->error == 0)
+ {
+ int sent = 0;
+
+ if (arp_table->port == 0) txsock = PORT->sock; else txsock = SourceSocket;
+
+ if (arp_table->IPv6)
+ sent = sendto(txsock, buff, txlen, 0, (struct sockaddr *)&arp_table->destaddr6, sizeof(arp_table->destaddr6));
+ else
+ if (arp_table->destaddr.sin_addr.s_addr)
+ sent = sendto(txsock, buff, txlen, 0, (struct sockaddr *)&arp_table->destaddr, sizeof(arp_table->destaddr));
+
+ if (sent != txlen)
+ {
+ int i = GetLastError();
+// perror("Sendto");
+ }
+
+ // reset Keepalive Timer
+
+ arp_table->keepalive=arp_table->keepaliveinit;
+ }
+}
+
+unsigned short int compute_crc_ccitt(unsigned char *buf, int len);
+unsigned short CCCITTChecksum(unsigned char* data, unsigned int length);
+
+VOID * AXIPExtInit(struct PORTCONTROL * PortEntry)
+{
+// char Msg[10] = {0xD0, 01, 00, 0x11, 00, 0x0B};
+// unsigned short crc;
+
+// crc = CCCITTChecksum(Msg, 4);
+
+// crc = CalcCRC(Msg, 4);
+
+ WritetoConsole("AXIP ");
+
+ InitAXIP(PortEntry->PORTNUMBER);
+
+ WritetoConsole("\n");
+
+ return ExtProc;
+}
+
+int InitAXIP(int Port)
+{
+ struct AXIPPORTINFO * PORT;
+
+ //
+ // Read config first, to get UDP info if needed
+ //
+
+ if (!ReadConfigFile(Port))
+ return (FALSE);
+
+ PORT = Portlist[Port];
+
+ if (PORT == NULL)
+ return FALSE;
+
+ PORT->Port = Port;
+
+ GetAXIPCache(PORT); // Prime resolver from cache
+
+ //
+ // Start Resolver Thread if needed
+ //
+
+ if (PORT->NeedResolver)
+ {
+ CreateResolverWindow(PORT);
+ _beginthread(ResolveNames, 0, PORT );
+ }
+
+ time(&PORT->lasttime); // Get initial time value
+
+ _beginthread(OpenSockets, 0, PORT );
+
+ // Start TCP outward connect threads
+ //
+ // Open MH window if needed
+
+ if (PORT->MHEnabled)
+ CreateMHWindow(PORT);
+
+ return (TRUE);
+}
+
+void OpenSockets(struct AXIPPORTINFO * PORT)
+{
+ char Msg[255];
+ int err;
+ u_long param=1;
+ BOOL bcopt=TRUE;
+ int i;
+ int index = 0;
+ struct arp_table_entry * arp;
+
+ // Moved from InitAXIP, to avoid hang if started too early on XP SP2
+
+ // Create and bind socket
+
+ if (PORT->needip)
+ {
+ PORT->sock=socket(AF_INET,SOCK_RAW,IP_AXIP);
+
+ if (PORT->sock == INVALID_SOCKET)
+ {
+ err = WSAGetLastError();
+ sprintf(Msg, "AXIP Failed to create RAW socket - Error %d\n", err);
+ WritetoConsole(Msg);
+ }
+ else
+ {
+
+ ioctl (PORT->sock,FIONBIO,¶m);
+
+ setsockopt (PORT->sock,SOL_SOCKET,SO_BROADCAST,(const char FAR *)&bcopt,4);
+
+ sinx.sinx.sin_family = AF_INET;
+ sinx.sinx.sin_addr.s_addr = INADDR_ANY;
+ sinx.sinx.sin_port = 0;
+
+ if (bind(PORT->sock, (struct sockaddr *) &sinx, sizeof(sinx)) != 0 )
+ {
+ //
+ // Bind Failed
+ //
+ err = WSAGetLastError();
+ sprintf(Msg, "Bind Failed for RAW socket - error code = %d", err);
+ WritetoConsole(Msg);
+ return;
+ }
+ }
+ }
+
+ for (i=0;iNumberofUDPPorts;i++)
+ {
+ int ret;
+
+ if (PORT->IPv6[i])
+ PORT->udpsock[i]=socket(AF_INET6,SOCK_DGRAM,0);
+ else
+ PORT->udpsock[i]=socket(AF_INET,SOCK_DGRAM,0);
+
+ if (PORT->udpsock[i] == INVALID_SOCKET)
+ {
+ WritetoConsole("Failed to create UDP socket");
+ err = WSAGetLastError();
+ continue;
+ }
+
+ ioctl (PORT->udpsock[i],FIONBIO,¶m);
+
+ setsockopt (PORT->udpsock[i],SOL_SOCKET,SO_BROADCAST,(const char FAR *)&bcopt,4);
+
+#ifndef WIN32
+
+ if (PORT->IPv6[i])
+ if (setsockopt(PORT->udpsock[i], IPPROTO_IPV6, IPV6_V6ONLY, ¶m, sizeof(param)) < 0)
+ perror("setting option IPV6_V6ONLY");
+
+#endif
+
+ if (PORT->IPv6[i])
+ {
+ sinx.sinx.sin_family = AF_INET6;
+ memset (&sinx.sinx6.sin6_addr, 0, 16);
+ }
+ else
+ {
+ sinx.sinx.sin_family = AF_INET;
+ sinx.sinx.sin_addr.s_addr = INADDR_ANY;
+ }
+
+ sinx.sinx.sin_port = htons(PORT->udpport[i]);
+
+ if (PORT->IPv6[i])
+ ret = bind(PORT->udpsock[i], (struct sockaddr *) &sinx.sinx, sizeof(sinx.sinx6));
+ else
+ ret = bind(PORT->udpsock[i], (struct sockaddr *) &sinx.sinx, sizeof(sinx.sinx));
+
+ if (ret != 0)
+ {
+ // Bind Failed
+
+ err = WSAGetLastError();
+ sprintf(Msg, "Bind Failed for UDP socket %d - error code = %d", PORT->udpport[i], err);
+ WritetoConsole(Msg);
+ continue;
+ }
+ }
+
+ // Open any TCP sockets
+
+ while (index < PORT->arp_table_len)
+ {
+ arp = &PORT->arp_table[index++];
+
+ if (arp->TCPMode == TCPMaster)
+ {
+ arp->TCPBuffer=malloc(4000);
+ arp->TCPState = 0;
+
+ if (arp->TCPThreadID == 0)
+ {
+ arp->TCPThreadID = _beginthread(TCPConnectThread, 0, arp);
+ Debugprintf("TCP Connect thread created for %s Handle %x", arp->hostname, arp->TCPThreadID);
+ }
+ continue;
+ }
+
+ if (arp->TCPMode == TCPSlave)
+ {
+ OpenListeningSocket(PORT, arp);
+ }
+ }
+}
+int OpenListeningSocket(struct AXIPPORTINFO * PORT, struct arp_table_entry * arp)
+{
+ char Msg[255];
+ struct sockaddr_in * psin;
+ BOOL bOptVal = TRUE;
+ struct sockaddr_in local_sin; /* Local socket - internet style */
+ u_long param = 1;
+ arp->TCPBuffer = malloc(4000);
+ arp->TCPState = 0;
+
+ arp->TCPListenSock = socket(AF_INET, SOCK_STREAM, 0);
+
+ ioctl (arp->TCPListenSock, FIONBIO, ¶m);
+
+ if (arp->TCPListenSock == INVALID_SOCKET)
+ {
+ sprintf(Msg, "socket() failed error %d", WSAGetLastError());
+ WritetoConsole(Msg);
+ return FALSE;
+ }
+
+// Debugprintf("TCP Listening Socket Created - socket %d port %d ", arp->TCPListenSock, arp->port);
+
+ setsockopt (arp->TCPListenSock, SOL_SOCKET, SO_REUSEADDR, (char *)¶m,4);
+
+ psin=&local_sin;
+ psin->sin_family = AF_INET;
+ psin->sin_addr.s_addr = htonl(INADDR_ANY); // Local Host Only
+
+ psin->sin_port = htons(arp->port); /* Convert to network ordering */
+
+ if (bind(arp->TCPListenSock , (struct sockaddr FAR *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR)
+ {
+ sprintf(Msg, "bind(sock) failed Port %d Error %d\n", arp->port, WSAGetLastError());
+ Debugprintf(Msg);
+ closesocket(arp->TCPListenSock);
+
+ return FALSE;
+ }
+
+ if (listen(arp->TCPListenSock, 1) < 0)
+ {
+ sprintf(Msg, "listen(sock) failed Error %d", WSAGetLastError());
+ Debugprintf(Msg);
+ closesocket(arp->TCPListenSock);
+ return FALSE;
+ }
+
+ arp->TCPState = TCPListening;
+ return TRUE;
+}
+
+void CloseSockets(struct AXIPPORTINFO * PORT)
+{
+ int i;
+ int index = 0;
+ struct arp_table_entry * arp;
+
+ if (PORT->needip)
+ closesocket(PORT->sock);
+
+ for (i=0;iNumberofUDPPorts;i++)
+ {
+ closesocket(PORT->udpsock[i]);
+ }
+
+ // Close any open or listening TCP sockets
+
+ while (index < PORT->arp_table_len)
+ {
+ arp = &PORT->arp_table[index++];
+
+ if (arp->TCPMode == TCPMaster)
+ {
+ if (arp->TCPState)
+ {
+ closesocket(arp->TCPSock);
+ arp->TCPSock = 0;
+ }
+ continue;
+ }
+
+ if (arp->TCPMode == TCPSlave)
+ {
+ if (arp->TCPState)
+ {
+ closesocket(arp->TCPSock);
+ arp->TCPSock = 0;
+ }
+
+ closesocket(arp->TCPListenSock);
+ continue;
+ }
+ }
+ return ;
+}
+
+#ifndef LINBPQ
+
+static LRESULT CALLBACK AXResWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int wmId, wmEvent;
+ PAINTSTRUCT ps;
+ HDC hdc;
+ HFONT hOldFont ;
+ char line[100];
+ char outcall[10];
+ int index,displayline;
+ struct AXIPPORTINFO * PORT;
+ MINMAXINFO * mmi;
+ int nScrollCode,nPos;
+ int i, Port;
+ char Flags[10];
+ struct arp_table_entry * arp;
+
+ // Find our PORT Entry
+
+ for (Port = 1; Port < 33; Port++)
+ {
+ PORT = Portlist[Port];
+ if (PORT == NULL)
+ continue;
+
+ if (PORT->hResWnd == hWnd)
+ break;
+ }
+
+ if (PORT == NULL)
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ i=1;
+
+ switch (message)
+ {
+ case WM_GETMINMAXINFO:
+
+ mmi = (MINMAXINFO *)lParam;
+ mmi->ptMaxSize.x = 600;
+ mmi->ptMaxSize.y = PORT->MaxResWindowlength;
+ mmi->ptMaxTrackSize.x = 55600;
+ mmi->ptMaxTrackSize.y = PORT->MaxResWindowlength;
+
+ break;
+
+
+ case WM_MDIACTIVATE:
+ {
+ // Set the system info menu when getting activated
+
+ if (lParam == (LPARAM) hWnd)
+ {
+ // Activate
+
+ RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
+ AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT_PTR)PORT->hResMenu, "Actions");
+ SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM)hBaseMenu, (LPARAM)hWndMenu);
+ }
+ else
+ SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
+
+ DrawMenuBar(FrameWnd);
+ return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
+ }
+
+ case WM_CHAR:
+
+ if (PORT->MHEnabled == FALSE && PORT->MHAvailable)
+ {
+ PORT->MHEnabled=TRUE;
+ CreateMHWindow(PORT);
+ ShowWindow(PORT->hMHWnd, SW_RESTORE); // In case Start Minimized set
+ }
+ break;
+
+ case WM_COMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+
+ if (wmId == BPQREREAD)
+ {
+ CloseSockets(PORT);
+
+ if (ProcessConfig())
+ {
+ FreeConfig();
+ ReadConfigFile(Port);
+ }
+ else
+ Consoleprintf("Failed to reread config file - leaving config unchanged");
+
+ _beginthread(OpenSockets, 0, PORT);
+
+ ResolveDelay = 2;
+ InvalidateRect(hWnd,NULL,TRUE);
+
+ return 0;
+ }
+
+ if (wmId == BPQADDARP)
+ {
+ if (PORT->ConfigWnd == 0)
+ {
+ PORT->ConfigWnd=CreateDialog(hInstance, ConfigClassName, 0, NULL);
+
+ if (!PORT->ConfigWnd)
+ {
+ return (FALSE);
+ }
+ ShowWindow(PORT->ConfigWnd, SW_SHOW);
+ UpdateWindow(PORT->ConfigWnd);
+ }
+
+ SetForegroundWindow(PORT->ConfigWnd);
+
+ return(0);
+ }
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ case WM_SYSCOMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+ switch (wmId)
+ {
+ case SC_RESTORE:
+
+ PORT->ResMinimized = FALSE;
+ SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
+
+ break;
+
+ case SC_MINIMIZE:
+
+ PORT->ResMinimized = TRUE;
+
+ break;
+ }
+
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+
+ case WM_VSCROLL:
+
+ nScrollCode = (int) LOWORD(wParam); // scroll bar value
+ nPos = (short int) HIWORD(wParam); // scroll box position
+
+ //hwndScrollBar = (HWND) lParam; // handle of scroll bar
+
+ if (nScrollCode == SB_LINEUP || nScrollCode == SB_PAGEUP)
+ {
+ PORT->baseline--;
+ if (PORT->baseline <0)
+ PORT->baseline=0;
+ }
+
+ if (nScrollCode == SB_LINEDOWN || nScrollCode == SB_PAGEDOWN)
+ {
+ PORT->baseline++;
+ if (PORT->baseline > PORT->arp_table_len)
+ PORT->baseline = PORT->arp_table_len;
+ }
+
+ if (nScrollCode == SB_THUMBTRACK)
+ {
+ PORT->baseline=nPos;
+ }
+
+ SetScrollPos(hWnd,SB_VERT,PORT->baseline,TRUE);
+
+ InvalidateRect(hWnd,NULL,TRUE);
+ break;
+
+
+ case WM_PAINT:
+
+ hdc = BeginPaint (hWnd, &ps);
+
+ hOldFont = SelectObject( hdc, hFont) ;
+
+ index = PORT->baseline;
+ displayline=0;
+
+ while (index < PORT->arp_table_len)
+ {
+ arp = &PORT->arp_table[index];
+
+ Flags[0] = 0;
+
+ if (arp->BCFlag)
+ strcat(Flags, "B ");
+
+ if (arp->TCPState == TCPConnected)
+ strcat(Flags, "C ");
+
+ if (arp->AutoAdded)
+ strcat(Flags, "A");
+
+ if (arp->ResolveFlag && arp->error != 0)
+ {
+ // resolver error - Display Error Code
+ sprintf(PORT->hostaddr,"Error %d",arp->error);
+ }
+ else
+ {
+ if (arp->IPv6)
+ Format_Addr((unsigned char *)&arp->destaddr6.sin6_addr, PORT->hostaddr, TRUE);
+ else
+ Format_Addr((unsigned char *)&arp->destaddr.sin_addr, PORT->hostaddr, FALSE);
+ }
+
+ CONVFROMAX25(arp->callsign,outcall);
+
+ if (arp->port == arp->SourcePort)
+ i=sprintf(line,"%.10s = %.64s %d = %-.30s %s ",
+ outcall,
+ arp->hostname,
+ arp->port,
+ PORT->hostaddr,
+ Flags);
+ else
+ i=sprintf(line,"%.10s = %.64s %d<%d = %-.30s %s ",
+ outcall,
+ arp->hostname,
+ arp->port,
+ arp->SourcePort,
+ PORT->hostaddr,
+ Flags);
+
+ TextOut(hdc, 0, (displayline++)*14+2, line, i);
+
+ index++;
+ }
+
+ SelectObject( hdc, hOldFont ) ;
+ EndPaint (hWnd, &ps);
+
+ break;
+
+ case WM_DESTROY:
+
+// PostQuitMessage(0);
+
+ break;
+
+
+ default:
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ }
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+}
+
+LRESULT FAR PASCAL ConfigWndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam)
+{
+ int cmd,id,i;
+ HWND hwndChild;
+ BOOL OK1,OK2,OK3;
+
+ char call[10], host[65];
+ int Interval;
+ int calllen;
+ int port;
+ char axcall[7];
+ BOOL UDPFlag, BCFlag;
+ struct AXIPPORTINFO * PORT;
+ int useSourcePort = 0;
+
+ for (i=1; i <= MAXBPQPORTS; i++)
+ {
+ PORT = Portlist[i];
+ if (PORT == NULL)
+ continue;
+
+ if (PORT->ConfigWnd == hWnd)
+ break;
+ }
+
+ switch (message)
+ {
+ case WM_CTLCOLORDLG:
+
+ return (LRESULT)bgBrush;
+
+ case WM_COMMAND:
+
+ id = LOWORD(wParam);
+ hwndChild = (HWND)(UINT)lParam;
+ cmd = HIWORD(wParam);
+
+ switch (id)
+ {
+ case ID_SAVE:
+
+ OK1=GetDlgItemText(PORT->ConfigWnd,1001,(LPSTR)call,10);
+ OK2=GetDlgItemText(PORT->ConfigWnd,1002,(LPSTR)host,64);
+ OK3=1;
+
+ for (i=0;i<7;i++)
+ call[i] = toupper(call[i]);
+
+ UDPFlag=IsDlgButtonChecked(PORT->ConfigWnd,1004);
+ BCFlag=IsDlgButtonChecked(PORT->ConfigWnd,1005);
+
+ if (UDPFlag)
+ port=GetDlgItemInt(PORT->ConfigWnd,1003,&OK3,FALSE);
+ else
+ port=0;
+
+ Interval=0;
+
+ if (OK1 && OK2 && OK3==1)
+ {
+ if (convtoax25(call,axcall,&calllen))
+ {
+ add_arp_entry(PORT, axcall,0,calllen,port,host,Interval, BCFlag, FALSE, 0, port, FALSE, 0, useSourcePort);
+ ResolveDelay = 2;
+ return(DestroyWindow(hWnd));
+ }
+ }
+
+ // Validation failed
+
+ if (!OK1) SetDlgItemText(PORT->ConfigWnd,1001,"????");
+ if (!OK2) SetDlgItemText(PORT->ConfigWnd,1002,"????");
+ if (!OK3) SetDlgItemText(PORT->ConfigWnd,1003,"????");
+
+ break;
+
+ case ID_CANCEL:
+
+ return(DestroyWindow(hWnd));
+ }
+ break;
+
+// case WM_CLOSE:
+
+// return(DestroyWindow(hWnd));
+
+ case WM_DESTROY:
+
+ PORT->ConfigWnd=0;
+
+ return(0);
+
+ }
+
+ return (DefWindowProc(hWnd, message, wParam, lParam));
+
+}
+#endif
+
+static void CreateResolverWindow(struct AXIPPORTINFO * PORT)
+{
+#ifndef LINBPQ
+
+ int WindowParam;
+ WNDCLASS wc;
+ char WindowTitle[100];
+ int retCode, Type, Vallen;
+ HKEY hKey=0;
+ char Size[80];
+
+ HWND hResWnd;
+ char Key[80];
+ RECT Rect = {0, 0, 300, 300};
+ int Top, Left, Width, Height;
+
+ sprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\PACTOR\\PORT%d", PORT->Port);
+
+ retCode = RegOpenKeyEx (REGTREE, Key, 0, KEY_QUERY_VALUE, &hKey);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ Vallen=80;
+
+ retCode = RegQueryValueEx(hKey,"ResSize",0,
+ (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
+
+ if (retCode == ERROR_SUCCESS)
+ sscanf(Size,"%d,%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom, &PORT->ResMinimized);
+
+ if (Rect.top < - 500 || Rect.left < - 500)
+ {
+ Rect.left = 0;
+ Rect.top = 0;
+ Rect.right = 600;
+ Rect.bottom = 400;
+ }
+
+ if (Rect.top < OffsetH) // Make sure not off top of MDI frame
+ {
+ int Error = OffsetH - Rect.top;
+ Rect.top += Error;
+ Rect.bottom += Error;
+ }
+
+ RegCloseKey(hKey);
+ }
+
+ Top = Rect.top;
+ Left = Rect.left;
+ Width = Rect.right - Left;
+ Height = Rect.bottom - Top;
+
+ // Register the window classes
+
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
+ wc.lpfnWndProc = (WNDPROC)AXResWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wc.lpszMenuName = NULL ;
+ wc.lpszClassName = "AXAppName";
+
+ RegisterClass(&wc);
+
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+ wc.hInstance = hInstance;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.lpfnWndProc = ConfigWndProc;
+ wc.lpszClassName = ConfigClassName;
+ RegisterClass(&wc);
+
+ WindowParam = WS_OVERLAPPEDWINDOW | WS_VSCROLL;
+
+ sprintf(WindowTitle,"AXIP Port %d Resolver", PORT->Port);
+
+ PORT->hResWnd = hResWnd = CreateMDIWindow("AXAppName", WindowTitle, WindowParam,
+ Left - (OffsetW /2), Top - OffsetH + 4, Width, Height, ClientWnd, hInstance, 1234);
+
+
+ PORT->hResMenu = CreatePopupMenu();
+ AppendMenu(PORT->hResMenu, MF_STRING, BPQREREAD, "ReRead Config");
+ AppendMenu(PORT->hResMenu, MF_STRING, BPQADDARP, "Add Entry");
+
+ SetScrollRange(hResWnd,SB_VERT, 0, PORT->arp_table_len, TRUE);
+
+ if (PORT->ResMinimized)
+ ShowWindow(hResWnd, SW_SHOWMINIMIZED);
+ else
+ ShowWindow(hResWnd, SW_RESTORE);
+#endif
+}
+extern HWND hWndPopup;
+
+
+static void ResolveNames(struct AXIPPORTINFO * PORT)
+{
+ int count = 0;
+
+ PORT->ResolveNamesThreadId = GetCurrentThreadId(); // Detect if another started
+
+ while(TRUE)
+ {
+ count++; // So we can trap first few loops
+
+ ResolveDelay = 15 * 60;
+
+ for (PORT->ResolveIndex=0; PORT->ResolveIndex < PORT->arp_table_len; PORT->ResolveIndex++)
+ {
+ struct arp_table_entry * arp = &PORT->arp_table[PORT->ResolveIndex];
+
+ if (arp->ResolveFlag)
+ {
+ struct addrinfo hints, *res = 0;
+ int n;
+ BOOL UseV6 = FALSE;
+ BOOL ForceV4 = FALSE;
+
+ if (_memicmp(arp->hostname, "ipv6:", 5) == 0)
+ UseV6 = TRUE;
+ else if (_memicmp(arp->hostname, "ipv4:", 5) == 0)
+ ForceV4 = TRUE;
+
+ memset(&hints, 0, sizeof hints);
+ hints.ai_socktype = SOCK_DGRAM;
+
+ if (UseV6)
+ {
+ hints.ai_family = AF_INET6; // use IPv6
+ n = getaddrinfo(&arp->hostname[5], NULL, &hints, &res);
+ }
+ else if (ForceV4)
+ {
+ hints.ai_family = AF_INET; // use IPv4
+ n = getaddrinfo(&arp->hostname[5], NULL, &hints, &res);
+ }
+ else if (PORT->PortIPv6) // Can use IPv6
+ {
+ hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
+ n = getaddrinfo(arp->hostname, NULL, &hints, &res);
+ }
+ else
+ {
+ hints.ai_family = AF_INET; // use IPv4 only
+ n = getaddrinfo(arp->hostname, NULL, &hints, &res);
+ }
+ if (res)
+ {
+ arp->error = 0;
+ if (res->ai_family == AF_INET)
+ {
+ memcpy(&arp->destaddr.sin_addr.s_addr, &res->ai_addr->sa_data[2], 4);
+ arp->IPv6 = FALSE;
+ arp->destaddr.sin_family = AF_INET;
+// Debugprintf("AXIP %s = %d.%d.%d.%d", arp->hostname, (UCHAR)res->ai_addr->sa_data[2],
+// (UCHAR)res->ai_addr->sa_data[3], (UCHAR)res->ai_addr->sa_data[4], (UCHAR)res->ai_addr->sa_data[5]);
+
+ }
+ else
+ {
+ struct sockaddr_in6 * sa6 = (struct sockaddr_in6 *)res->ai_addr;
+
+ memcpy(&arp->destaddr6.sin6_addr, &sa6->sin6_addr, 16);
+ arp->IPv6 = TRUE;
+ arp->destaddr.sin_family = AF_INET6;
+ }
+ arp->destaddr.sin_port = htons(arp->port);
+ freeaddrinfo(res);
+ }
+ else
+ {
+ PORT->arp_table[PORT->ResolveIndex].error = WSAGetLastError();
+
+ if (count < 4)
+ ResolveDelay = 30; // if errors try again soon
+ }
+ }
+ }
+
+ SaveAXIPCache(PORT);
+
+#ifndef LINBPQ
+ InvalidateRect(PORT->hResWnd,NULL,TRUE);
+#endif
+ while(ResolveDelay-- > 0)
+ {
+ if (pthread_equal(PORT->ResolveNamesThreadId, GetCurrentThreadId()) == FALSE)
+ {
+ Debugprintf("AXIP Resolve thread %x redundant - closing", GetCurrentThreadId());
+ return;
+ }
+ Sleep(1000);
+ }
+ }
+ Debugprintf("AXIP Resolve thread exitied");
+}
+
+#ifndef LINBPQ
+
+LRESULT CALLBACK MHWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int wmId, wmEvent;
+ PAINTSTRUCT ps;
+ HDC hdc;
+ HFONT hOldFont ;
+ char line[100];
+ char outcall[10];
+ HGLOBAL hMem;
+ struct AXIPPORTINFO * PORT;
+ int index,displayline;
+ MINMAXINFO * mmi;
+ int nScrollCode,nPos;
+
+
+ int i;
+
+ for (i=1; i <= MAXBPQPORTS; i++)
+ {
+ PORT = Portlist[i];
+ if (PORT == NULL)
+ continue;
+
+ if (PORT->hMHWnd == hWnd)
+ break;
+ }
+
+ if (PORT == NULL)
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ switch (message)
+ {
+ case WM_GETMINMAXINFO:
+
+ mmi = (MINMAXINFO *)lParam;
+ mmi->ptMaxSize.x = 600;
+ mmi->ptMaxSize.y = PORT->MaxMHWindowlength;
+ mmi->ptMaxTrackSize.x = 600;
+ mmi->ptMaxTrackSize.y = PORT->MaxMHWindowlength;
+ break;
+
+ case WM_MDIACTIVATE:
+ {
+ // Set the system info menu when getting activated
+
+ if (lParam == (LPARAM) hWnd)
+ {
+ // Activate
+
+ RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
+ AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)PORT->hMHMenu, "Edit");
+ SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM)hBaseMenu, (LPARAM)hWndMenu);
+ }
+ else
+ SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
+
+ DrawMenuBar(FrameWnd);
+
+ return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ }
+
+ case WM_COMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+ switch (wmId) {
+
+ case BPQCLEAR:
+ memset(PORT->MHTable, 0, sizeof(PORT->MHTable));
+ InvalidateRect(hWnd,NULL,TRUE);
+ return 0;
+
+ case BPQCOPY:
+
+ hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, MaxMHEntries * 100);
+
+ if (hMem != 0)
+ {
+ if (OpenClipboard(hWnd))
+ {
+ CopyScreentoBuffer(GlobalLock(hMem), PORT);
+ GlobalUnlock(hMem);
+ EmptyClipboard();
+ SetClipboardData(CF_TEXT,hMem);
+ CloseClipboard();
+ }
+ else
+ {
+ GlobalFree(hMem);
+ }
+ }
+ return 0;
+
+ default:
+
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+ }
+
+ case WM_SYSCOMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+ switch (wmId)
+ {
+ case SC_RESTORE:
+
+ PORT->MHMinimized = FALSE;
+ SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
+ break;
+
+ case SC_MINIMIZE:
+
+ PORT->MHMinimized = TRUE;
+ break;
+ }
+
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ case WM_VSCROLL:
+
+ nScrollCode = (int) LOWORD(wParam); // scroll bar value
+ nPos = (short int) HIWORD(wParam); // scroll box position
+
+ //hwndScrollBar = (HWND) lParam; // handle of scroll bar
+
+ if (nScrollCode == SB_LINEUP || nScrollCode == SB_PAGEUP)
+ {
+ PORT->mhbaseline--;
+ if (PORT->mhbaseline <0)
+ PORT->mhbaseline=0;
+ }
+
+ if (nScrollCode == SB_LINEDOWN || nScrollCode == SB_PAGEDOWN)
+ {
+ PORT->mhbaseline++;
+ if (PORT->mhbaseline > PORT->CurrentMHEntries)
+ PORT->mhbaseline = PORT->CurrentMHEntries;
+ }
+
+ if (nScrollCode == SB_THUMBTRACK)
+ {
+ PORT->mhbaseline=nPos;
+ }
+
+ SetScrollPos(hWnd,SB_VERT,PORT->mhbaseline,TRUE);
+
+ InvalidateRect(hWnd,NULL,TRUE);
+ break;
+
+
+
+ case WM_PAINT:
+
+ hdc = BeginPaint (hWnd, &ps);
+ hOldFont = SelectObject( hdc, hFont) ;
+
+ index = PORT->mhbaseline;
+ displayline=0;
+
+ PORT->CurrentMHEntries = 0;
+
+ while (index < MaxMHEntries)
+ {
+ if (PORT->MHTable[index].proto != 0)
+ {
+ char Addr[80];
+
+ Format_Addr((unsigned char *)&PORT->MHTable[index].ipaddr6, Addr, PORT->MHTable[index].IPv6);
+
+ CONVFROMAX25(PORT->MHTable[index].callsign,outcall);
+
+ i=sprintf(line,"%-10s%-15s %c %-6d %-25s%c",outcall,
+ Addr,
+ PORT->MHTable[index].proto,
+ PORT->MHTable[index].port,
+ asctime(gmtime( &PORT->MHTable[index].LastHeard )),
+ (PORT->MHTable[index].Keepalive == 0) ? ' ' : 'K');
+
+ line[i-2]= ' '; // Clear CR returned by asctime
+
+ TextOut(hdc,0,(displayline++)*14+2,line,i);
+ PORT->CurrentMHEntries ++;
+ }
+ index++;
+ }
+
+ if (PORT->MaxMHWindowlength < PORT->CurrentMHEntries * 14 + 40)
+ PORT->MaxMHWindowlength = PORT->CurrentMHEntries * 14 + 40;
+
+ SelectObject( hdc, hOldFont ) ;
+ EndPaint (hWnd, &ps);
+
+ break;
+
+ case WM_DESTROY:
+
+ PORT->MHEnabled=FALSE;
+
+ break;
+
+ default:
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ }
+
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+}
+
+#endif
+
+BOOL CopyScreentoBuffer(char * buff, struct AXIPPORTINFO * PORT)
+{
+ int index;
+ char outcall[10];
+
+ index = 0;
+
+ while (index < MaxMHEntries)
+ {
+ if (PORT->MHTable[index].proto != 0)
+ {
+ CONVFROMAX25(PORT->MHTable[index].callsign,outcall);
+
+ buff+=sprintf(buff,"%-10s%-15s %c %-6d %-26s",outcall,
+ inet_ntoa(PORT->MHTable[index].ipaddr),
+ PORT->MHTable[index].proto,
+ PORT->MHTable[index].port,
+ asctime(gmtime( &PORT->MHTable[index].LastHeard )));
+ }
+ *(buff-2)=13;
+ *(buff-1)=10;
+ index++;
+
+ }
+ *(buff)=0;
+
+ return 0;
+}
+
+void CreateMHWindow(struct AXIPPORTINFO * PORT)
+{
+#ifndef LINBPQ
+
+ WNDCLASS wc;
+ char WindowTitle[100];
+ int retCode, Type, Vallen;
+ HKEY hKey=0;
+ char Size[80];
+ HWND hMHWnd;
+ char Key[80];
+ RECT Rect = {0, 0, 300, 300};
+ int Top, Left, Width, Height;
+
+ sprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\PACTOR\\PORT%d", PORT->Port);
+
+ retCode = RegOpenKeyEx (REGTREE, Key, 0, KEY_QUERY_VALUE, &hKey);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ Vallen=80;
+
+ retCode = RegQueryValueEx(hKey,"MHSize",0,
+ (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
+
+ if (retCode == ERROR_SUCCESS)
+ sscanf(Size,"%d,%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom, &PORT->MHMinimized);
+
+ if (Rect.top < - 500 || Rect.left < - 500)
+ {
+ Rect.left = 0;
+ Rect.top = 0;
+ Rect.right = 600;
+ Rect.bottom = 400;
+ }
+
+ if (Rect.top < OffsetH) // Make sure not off top of MDI frame
+ {
+ int Error = OffsetH - Rect.top;
+ Rect.top += Error;
+ Rect.bottom += Error;
+ }
+
+
+ RegCloseKey(hKey);
+ }
+
+ Top = Rect.top;
+ Left = Rect.left;
+ Width = Rect.right - Left;
+ Height = Rect.bottom - Top;
+
+ PORT->MaxMHWindowlength = Height;
+
+ wc.style = CS_HREDRAW | CS_VREDRAW ;//| CS_NOCLOSE;
+ wc.lpfnWndProc = (WNDPROC)MHWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wc.lpszMenuName = NULL ;
+ wc.lpszClassName = "MHAppName";
+
+ RegisterClass(&wc);
+
+ sprintf(WindowTitle,"AXIP Port %d MHEARD", PORT->Port);
+
+ PORT->hMHWnd = hMHWnd = CreateMDIWindow("MHAppName", WindowTitle,
+ WS_OVERLAPPEDWINDOW | WS_VSCROLL,
+ Left - (OffsetW /2), Top - OffsetH, Width, Height, ClientWnd, hInstance, 1234);
+
+ PORT->hMHMenu = CreatePopupMenu();
+ AppendMenu(PORT->hMHMenu, MF_STRING, BPQCOPY, "Copy");
+ AppendMenu(PORT->hMHMenu, MF_STRING, BPQCLEAR, "Clear");
+
+ if (PORT->MHMinimized)
+ ShowWindow(hMHWnd, SW_SHOWMINIMIZED);
+ else
+ ShowWindow(hMHWnd, SW_RESTORE);
+#endif
+}
+
+unsigned short int compute_crc(unsigned char *buf,int len)
+{
+ unsigned short fcs = 0xffff;
+ int i;
+
+ for(i = 0; i < len; i++)
+ fcs = (fcs >>8 ) ^ CRCTAB[(fcs ^ buf[i]) & 0xff];
+
+ return fcs;
+}
+
+/*
+
+static const unsigned short ccittTab[] = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
+ 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
+ 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
+ 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
+ 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
+ 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
+ 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
+ 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
+ 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
+ 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
+ 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
+ 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
+ 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
+ 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
+ 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
+ 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
+ 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
+ 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
+ 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
+ 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
+ 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
+ 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
+ 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0};
+
+unsigned short int compute_crc_ccitt(unsigned char *buf, int len)
+{
+ int i;
+ unsigned short fcs = 0;
+
+ for(i = 0; i < len; i++)
+ fcs = (fcs >>8 ) ^ ccittTab[(fcs ^ buf[i]) & 0xff];
+
+ return fcs;
+}
+
+
+ union {
+ unsigned short m_crc16;
+ unsigned char m_crc8[2U];
+ } fcs;
+
+
+unsigned short CCCITTChecksum(unsigned char* data, unsigned int length)
+{
+ int i;
+
+ fcs.m_crc16 = 0;
+
+ for (i = 0U; i < length; i++)
+ fcs.m_crc16 = (fcs.m_crc8[0U] << 8) ^ ccittTab[fcs.m_crc8[1U] ^ data[i]];
+
+ return fcs.m_crc16;
+}
+
+*/
+
+static BOOL ReadConfigFile(int Port)
+{
+
+/* Linux Format
+
+broadcast QST-0 NODES-0
+#
+# ax.25 route definition, define as many as you need.
+# format is route (call/wildcard) (ip host at destination)
+# ssid of 0 routes all ssid's
+#
+# route [flags]
+#
+# Valid flags are:
+# b - allow broadcasts to be transmitted via this route
+# d - this route is the default route
+#
+#route vk2sut-0 44.136.8.68 b
+#route vk5xxx 44.136.188.221 b
+#route vk2abc 44.1.1.1
+#
+*/
+
+//UDP 9999 # Port we listen on
+//MAP G8BPQ-7 10.2.77.1 # IP 93 for compatibility
+//MAP BPQ7 10.2.77.1 UDP 2222 # UDP port to send to
+//MAP BPQ8 10.2.77.2 UDP 3333 # UDP port to send to
+
+ char buf[256],errbuf[256];
+ HKEY hKey=0;
+ char * Config;
+ struct AXIPPORTINFO * PORT;
+
+ Config = PortConfig[Port];
+
+ if (Portlist[Port]) // Already defined, so must be re-read
+ {
+ PORT = Portlist[Port];
+
+ PORT->NumberofBroadcastAddreses = 0;
+ PORT->needip = FALSE;
+ PORT->NeedTCP = FALSE;
+ PORT->MHAvailable = FALSE;
+ PORT->MHEnabled = FALSE;
+ PORT->NumberofUDPPorts = 0;
+ PORT->NeedResolver = FALSE;
+ PORT->arp_table_len = 0;
+ memset(PORT->arp_table, 0, sizeof(struct arp_table_entry) * MAX_ENTRIES);
+ PORT->AutoAddARP = FALSE;
+ PORT->AutoAddBC = FALSE;
+ }
+ else
+ {
+ Portlist[Port] = PORT = zalloc(sizeof (struct AXIPPORTINFO));
+ }
+
+ PORT->Checkifcanreply = TRUE;
+
+ if (Config)
+ {
+ char * ptr1 = Config, * ptr2;
+
+ // Using config from bpq32.cfg
+
+ ptr2 = strchr(ptr1, 13);
+ while(ptr2)
+ {
+ memcpy(buf, ptr1, ptr2 - ptr1);
+ buf[ptr2 - ptr1] = 0;
+ ptr1 = ptr2 + 2;
+ ptr2 = strchr(ptr1, 13);
+
+ strcpy(errbuf,buf); // save in case of error
+
+ if (!ProcessLine(buf, PORT))
+ {
+ WritetoConsole("BPQAXIP - Bad config record");
+ WritetoConsole(errbuf);
+ WritetoConsole("\n");
+ }
+ }
+
+ if (PORT->NumberofUDPPorts > MAXUDPPORTS)
+ {
+ n=sprintf(buf,"BPQAXIP - Too many UDP= lines - max is %d\n", MAXUDPPORTS);
+ WritetoConsole(buf);
+ }
+ return TRUE;
+ }
+
+ WritetoConsole("No Configuration info in bpq32.cfg");
+
+ return FALSE;
+}
+
+static int ProcessLine(char * buf, struct AXIPPORTINFO * PORT)
+{
+ char * ptr;
+ char * p_call;
+ char * p_ipad;
+ char * p_UDP;
+ char * p_udpport;
+ char * p_Interval;
+
+ int calllen;
+ int port, SourcePort;
+ int bcflag;
+ char axcall[7];
+ int Interval;
+ int noUpdate=FALSE;
+ int TCPMode;
+ int useSourcePort = 0;
+
+ ptr = strtok(buf, " \t\n\r");
+
+ if(ptr == NULL) return (TRUE);
+
+ if(*ptr =='#') return (TRUE); // comment
+
+ if(*ptr ==';') return (TRUE); // comment
+
+ if(_stricmp(ptr,"UDP") == 0)
+ {
+ if (PORT->NumberofUDPPorts > MAXUDPPORTS) PORT->NumberofUDPPorts--;
+
+ p_udpport = strtok(NULL, " ,\t\n\r");
+
+ if (p_udpport == NULL) return (FALSE);
+
+ PORT->udpport[PORT->NumberofUDPPorts] = atoi(p_udpport);
+
+ if (PORT->udpport[PORT->NumberofUDPPorts] == 0) return (FALSE);
+
+ ptr = strtok(NULL, " \t\n\r");
+
+ if (ptr && _stricmp(ptr, "ipv6") == 0)
+ {
+ PORT->PortIPv6 = TRUE;
+ PORT->IPv6[PORT->NumberofUDPPorts] = TRUE;
+ }
+
+ PORT->NumberofUDPPorts++;
+
+ return (TRUE);
+ }
+
+ if(_stricmp(ptr,"MHEARD") == 0)
+ {
+ PORT->MHEnabled = TRUE;
+ PORT->MHAvailable = TRUE;
+
+ return (TRUE);
+ }
+
+ if(_stricmp(ptr,"DONTCHECKSOURCECALL") == 0)
+ {
+ PORT->Checkifcanreply = FALSE;
+ return (TRUE);
+ }
+
+ if(_stricmp(ptr,"AUTOADDMAP") == 0)
+ {
+ PORT->AutoAddARP = TRUE;
+ PORT->AutoAddBC = TRUE;
+ return (TRUE);
+ }
+
+ if(_stricmp(ptr,"AUTOADDQUIET") == 0)
+ {
+ PORT->AutoAddARP = TRUE;
+ PORT->AutoAddBC = FALSE;
+ return (TRUE);
+ }
+
+ if(_stricmp(ptr,"MAP") == 0)
+ {
+ p_call = strtok(NULL, " \t\n\r");
+
+ if (p_call == NULL) return (FALSE);
+
+ _strupr(p_call);
+
+ if (_stricmp(p_call, "DUMMY") == 0)
+ {
+ Consoleprintf("MAP DUMMY is no longer needed - statement ignored");
+ return TRUE;
+ }
+
+ p_ipad = strtok(NULL, " \t\n\r");
+
+ if (p_ipad == NULL) return (FALSE);
+
+ p_UDP = strtok(NULL, " \t\n\r");
+
+ Interval=0;
+ port=0; // Raw IP
+ bcflag=0;
+ TCPMode=0;
+ SourcePort = 0;
+ useSourcePort = 0;
+
+//
+// Look for (optional) KEEPALIVE, DYNAMIC, UDP or BROADCAST params
+//
+ while (p_UDP != NULL)
+ {
+ if (_stricmp(p_UDP,"NOUPDATE") == 0)
+ {
+ noUpdate = TRUE;
+ p_UDP = strtok(NULL, " \t\n\r");
+ continue;
+ }
+
+ if (_stricmp(p_UDP,"KEEPALIVE") == 0)
+ {
+ p_Interval = strtok(NULL, " \t\n\r");
+
+ if (p_Interval == NULL) return (FALSE);
+
+ Interval = atoi(p_Interval);
+ p_UDP = strtok(NULL, " \t\n\r");
+ continue;
+ }
+
+ if (_stricmp(p_UDP,"UDP") == 0)
+ {
+ p_udpport = strtok(NULL, " \t\n\r");
+
+ if (p_udpport == NULL) return (FALSE);
+
+ if (_stricmp(p_udpport,"FROMPORT") == 0)
+ {
+ useSourcePort = TRUE;
+ port = 0;
+ }
+ else
+ port = atoi(p_udpport);
+
+ p_UDP = strtok(NULL, " \t\n\r");
+ continue;
+ }
+
+ if (_stricmp(p_UDP,"SOURCEPORT") == 0)
+ {
+ p_udpport = strtok(NULL, " \t\n\r");
+
+ if (p_udpport == NULL) return (FALSE);
+
+ SourcePort = atoi(p_udpport);
+ p_UDP = strtok(NULL, " \t\n\r");
+ continue;
+ }
+
+ if (_stricmp(p_UDP,"TCP-Master") == 0)
+ {
+ p_udpport = strtok(NULL, " \t\n\r");
+
+ if (p_udpport == NULL) return (FALSE);
+
+ port = atoi(p_udpport);
+ p_UDP = strtok(NULL, " \t\n\r");
+
+ TCPMode=TCPMaster;
+
+ continue;
+ }
+
+ if (_stricmp(p_UDP,"TCP-Slave") == 0)
+ {
+ p_udpport = strtok(NULL, " \t\n\r");
+
+ if (p_udpport == NULL) return (FALSE);
+
+ port = atoi(p_udpport);
+ p_UDP = strtok(NULL, " \t\n\r");
+
+ TCPMode = TCPSlave;
+ continue;
+
+ }
+
+
+ if (_stricmp(p_UDP,"B") == 0)
+ {
+ bcflag =TRUE;
+ p_UDP = strtok(NULL, " \t\n\r");
+ continue;
+ }
+
+ if ((*p_UDP == ';') || (*p_UDP == '#')) break; // Comment on end
+
+ return FALSE;
+
+ }
+
+ if (convtoax25(p_call,axcall,&calllen))
+ {
+ if (SourcePort == 0)
+ SourcePort = port;
+
+ add_arp_entry(PORT, axcall, 0, calllen, port, p_ipad, Interval, bcflag, FALSE, TCPMode, SourcePort, FALSE, noUpdate, useSourcePort);
+ return (TRUE);
+ }
+ } // End of Process MAP
+
+ if(_stricmp(ptr,"BROADCAST") == 0)
+ {
+ p_call = strtok(NULL, " \t\n\r");
+
+ if (p_call == NULL) return (FALSE);
+
+ if (convtoax25(p_call,axcall,&calllen))
+ {
+ add_bc_entry(PORT, axcall,calllen);
+ return (TRUE);
+ }
+
+
+ return (FALSE); // Failed convtoax25
+ }
+
+ //
+ // Bad line
+ //
+ return (FALSE);
+}
+
+int CONVFROMAX25(char * incall, char * outcall)
+{
+ int in,out=0;
+ unsigned char chr;
+//
+// CONVERT AX25 FORMAT CALL IN incall TO NORMAL FORMAT IN out
+// RETURNS LENGTH
+//
+ memset(outcall,0x20,9);
+ outcall[9]=0;
+
+ for (in=0;in<6;in++)
+ {
+ chr=incall[in];
+ if (chr == 0x40)
+ break;
+ chr >>= 1;
+ outcall[out++]=chr;
+ }
+
+ chr=incall[6]; // ssid
+ chr >>= 1;
+ chr &= 15;
+
+ if (chr > 0)
+ {
+ outcall[out++]='-';
+ if (chr > 9)
+ {
+ chr-=10;
+ outcall[out++]='1';
+ }
+ chr+=48;
+ outcall[out++]=chr;
+ }
+ return (out);
+}
+
+
+BOOL convtoax25(unsigned char * callsign, unsigned char * ax25call,int * calllen)
+{
+ int i;
+
+ memset(ax25call,0x40,6); // in case short
+ ax25call[6]=0x60; // default SSID
+
+ for (i=0;i<7;i++)
+ {
+ if (callsign[i] == '-')
+ {
+ //
+ // process ssid and return
+ //
+ i = atoi(&callsign[i+1]);
+
+ if (i < 16)
+ {
+ ax25call[6] |= i<<1;
+ *calllen = 7; // include ssid in test
+ return (TRUE);
+ }
+ return (FALSE);
+ }
+
+ if (callsign[i] == 0 || callsign[i] == ' ')
+ {
+ //
+ // End of call - no ssid
+ //
+ *calllen = 6; // wildcard ssid
+ return (TRUE);
+ }
+
+ ax25call[i] = callsign[i] << 1;
+ }
+
+ //
+ // Too many chars
+ //
+
+ return (FALSE);
+}
+
+BOOL add_arp_entry(struct AXIPPORTINFO * PORT, UCHAR * call, UCHAR * ip, int len, int port,
+ UCHAR * name, int keepalive, BOOL BCFlag, BOOL AutoAdded, int TCPFlag, int SourcePort, BOOL IPv6, int noUpdate, int useSourcePort)
+{
+ struct arp_table_entry * arp;
+
+ if (PORT->arp_table_len == MAX_ENTRIES)
+ //
+ // Table full
+ //
+ return (FALSE);
+
+ arp = &PORT->arp_table[PORT->arp_table_len];
+
+ if (SourcePort)
+ arp->SourcePort = SourcePort;
+ else
+ arp->SourcePort = port;
+
+ arp->PORT = PORT;
+
+ if (port == 0 && arp->replytoSourcePort == 0)
+ PORT->needip = 1; // Enable Raw IP Mode
+
+ arp->ResolveFlag=TRUE;
+ PORT->NeedResolver=TRUE;
+
+ memcpy (&arp->callsign,call,7);
+ strncpy((char *)&arp->hostname,name,64);
+ arp->len = len;
+ arp->port = port;
+ keepalive+=9;
+ keepalive/=10;
+
+ arp->keepalive = keepalive;
+ arp->keepaliveinit = keepalive;
+ arp->BCFlag = BCFlag;
+ arp->AutoAdded = AutoAdded;
+ arp->TCPMode = TCPFlag;
+ arp->noUpdate = noUpdate;
+ PORT->arp_table_len++;
+ arp->replytoSourcePort = useSourcePort;
+
+ if (PORT->MaxResWindowlength < (PORT->arp_table_len * 14) + 70)
+ PORT->MaxResWindowlength = (PORT->arp_table_len * 14) + 70;
+
+ PORT->NeedResolver |= TCPFlag; // Need Resolver window to handle tcp socket messages
+ PORT->NeedTCP |= TCPFlag;
+
+ if (ip)
+ {
+ // Only have an IP address if dynamically added - so update destaddr
+
+ if (IPv6)
+ {
+ memcpy(&arp->destaddr6.sin6_addr, ip, 16);
+ arp->IPv6 = TRUE;
+ arp->destaddr.sin_family = AF_INET6;
+ }
+ else
+ {
+ memcpy(&arp->destaddr.sin_addr.s_addr, ip, 4);
+ arp->IPv6 = FALSE;
+ arp->destaddr.sin_family = AF_INET;
+ }
+ arp->destaddr.sin_port = htons(arp->port);
+#ifndef LINBPQ
+
+ SetScrollRange(PORT->hResWnd,SB_VERT, 0, PORT->arp_table_len, TRUE);
+ InvalidateRect(PORT->hResWnd, NULL, TRUE);
+#endif
+ }
+
+ return (TRUE);
+}
+
+BOOL add_bc_entry(struct AXIPPORTINFO * PORT, unsigned char * call, int len)
+{
+ if (PORT->NumberofBroadcastAddreses == MAX_BROADCASTS)
+ //
+ // Table full
+ //
+ return (FALSE);
+
+ memcpy (PORT->BroadcastAddresses[PORT->NumberofBroadcastAddreses].callsign,call,7);
+ PORT->BroadcastAddresses[PORT->NumberofBroadcastAddreses].len = len;
+ PORT->NumberofBroadcastAddreses++;
+
+ return (TRUE);
+}
+
+
+int CheckKeepalives(struct AXIPPORTINFO * PORT)
+{
+ int index=0;
+ SOCKET txsock;
+ struct arp_table_entry * arp;
+
+ if (PORT->arp_table_len >= MAX_ENTRIES)
+ {
+ Debugprintf("arp_table_len corrupt - %d", PORT->arp_table_len);
+ PORT->arp_table_len = MAX_ENTRIES - 1;
+ }
+
+ while (index < PORT->arp_table_len)
+ {
+ if (PORT->arp_table[index].keepalive != 0)
+ {
+ arp = &PORT->arp_table[index];
+ arp->keepalive--;
+
+ if (arp->keepalive == 0)
+ {
+ //
+ // Send Keepalive Packet
+ //
+ arp->keepalive=arp->keepaliveinit;
+
+ if (arp->error == 0)
+ {
+ if (arp->port == 0) txsock = PORT->sock; else txsock = PORT->udpsock[0];
+
+ sendto(txsock,"Keepalive",9,0,(struct sockaddr *)&arp->destaddr,sizeof(arp->destaddr));
+ }
+ }
+ }
+
+ index++;
+
+ }
+
+ // Decrement MH Keepalive flags
+
+ for (index = 0; index < MaxMHEntries; index++)
+ {
+ if (PORT->MHTable[index].Keepalive != 0)
+ PORT->MHTable[index].Keepalive--;
+ }
+
+ return (0);
+}
+
+BOOL CheckSourceisResolvable(struct AXIPPORTINFO * PORT, char * call, int FromPort, VOID * rxaddr, int ToPort)
+{
+ // Makes sure we can reply to call before accepting message
+
+ int index = 0;
+ struct arp_table_entry * arp;
+
+ while (index < PORT->arp_table_len)
+ {
+ arp = &PORT->arp_table[index];
+
+ if (memcmp(arp->callsign, call, arp->len) == 0)
+ {
+ // Call is present - if AutoAdded, refresh IP address and Port
+
+ // Why not refreesh resolved addresses - if dynamic addr has changed
+ // this will give quicker response
+
+ if (arp->noUpdate == 0)
+ {
+ if (arp->IPv6)
+ {
+ struct sockaddr_in6 * SA6 = rxaddr;
+ memcpy(&arp->destaddr6.sin6_addr, &SA6->sin6_addr, 16);
+ }
+ else
+ {
+ struct sockaddr_in * SA = rxaddr;
+ memcpy(&arp->destaddr.sin_addr.s_addr, &SA->sin_addr, 4);
+ }
+ // Dont think I should update port unless using source port for dest
+
+ if (arp->replytoSourcePort)
+ {
+ arp->port = FromPort;
+ if (arp->SourcePort == 0)
+ arp->SourcePort = ToPort;
+ }
+ }
+ arp->LastHeard = time(NULL);
+ return 1; // Ok to process
+ }
+ index++;
+ }
+
+ return (0); // Not in list
+}
+
+int Update_MH_List(struct AXIPPORTINFO * PORT, UCHAR * ipad, char * call, char proto, short port, BOOL IPv6)
+{
+ int index;
+ char callsign[7];
+ int SaveKeepalive=0;
+ struct MHTableEntry * MH;
+
+ memcpy(callsign,call,7);
+ callsign[6] &= 0x3e; // Mask non-ssid bits
+
+ for (index = 0; index < MaxMHEntries; index++)
+ {
+ MH = &PORT->MHTable[index];
+
+ if (MH->callsign[0] == 0)
+ {
+ // empty entry, so call not present. Move all down, and add to front
+
+#ifdef WIN32
+ SetScrollRange(PORT->hMHWnd, SB_VERT, 0, index + 1, TRUE);
+#endif
+ goto MoveEntries;
+ }
+
+ if (memcmp(MH->callsign,callsign,7) == 0 &&
+ memcmp(&MH->ipaddr, ipad, (MH->IPv6) ? 16 : 4) == 0 &&
+ MH->proto == proto &&
+ MH->port == port)
+ {
+ // Entry found, move preceeding entries down and put on front
+
+ SaveKeepalive = MH->Keepalive;
+ goto MoveEntries;
+ }
+ }
+
+ // Table full move MaxMHEntries-1 entries down, and add on front
+
+ index=MaxMHEntries-1;
+
+MoveEntries:
+
+ //
+ // Move all preceeding entries down one, and put on front
+ //
+
+ if (index > 0)
+ memmove(&PORT->MHTable[1],&PORT->MHTable[0],index*sizeof(struct MHTableEntry));
+
+ MH = &PORT->MHTable[0];
+
+ memcpy(MH->callsign,callsign,7);
+ memcpy(&MH->ipaddr6, ipad, (IPv6) ? 16 : 4);
+ MH->proto = proto;
+
+ MH->port = port;
+ time(&MH->LastHeard);
+ MH->Keepalive = SaveKeepalive;
+ MH->IPv6 = IPv6;
+#ifndef LINBPQ
+ InvalidateRect(PORT->hMHWnd,NULL,TRUE);
+#endif
+ return 0;
+
+}
+
+int Update_MH_KeepAlive(struct AXIPPORTINFO * PORT, struct in_addr ipad, char proto, short port)
+{
+ int index;
+
+ for (index = 0; index < MaxMHEntries; index++)
+ {
+ if (PORT->MHTable[index].callsign[0] == 0)
+
+ // empty entry, so call not present.
+
+ return 0;
+
+ if (memcmp(&PORT->MHTable[index].ipaddr,&ipad,4) == 0 &&
+ PORT->MHTable[index].proto == proto &&
+ PORT->MHTable[index].port == port)
+ {
+ PORT->MHTable[index].Keepalive = 30; // 5 Minutes at 10 sec ticks
+ return 0;
+ }
+ }
+
+ return 0;
+
+}
+
+
+int DumpFrameInHex(unsigned char * msg, int len)
+{
+ char errmsg[100];
+ int i=0;
+
+ for (i=0;iarp_table_len)
+ {
+ sockptr = &PORT->arp_table[index++];
+
+ if (sockptr->TCPMode)
+ {
+ if (sockptr->TCPState == TCPListening)
+ {
+ int addrlen;
+ SOCKET sock;
+ BOOL bOptVal = TRUE;
+ struct sockaddr sin;
+
+ addrlen = sizeof(struct sockaddr);
+
+ sock = accept(sockptr->TCPListenSock, &sin, &addrlen);
+
+ if (sock == INVALID_SOCKET)
+ {
+ int err = WSAGetLastError();
+
+ if (err == 10035 || err == 11)
+ continue;
+
+ if (err == 10038 || err == 9)
+ {
+ // Not a socket
+
+ closesocket(sockptr->TCPListenSock);
+ OpenListeningSocket(PORT, sockptr);
+
+ continue;
+ }
+
+
+ Debugprintf("AXIP accept() failed Error %d", err);
+ continue;
+ }
+
+ Debugprintf("AXIP Connect accepted - Socket %d Port %d", sock, sockptr->port);
+
+ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&bOptVal, 4) != SOCKET_ERROR)
+ Debugprintf("Set SO_KEEPALIVE: ON");
+
+ sockptr->TCPSock = sock;
+ sockptr->TCPState = TCPConnected;
+ }
+
+ if (sockptr->TCPState == TCPConnected)
+ {
+ int InputLen;
+
+ // Poll TCP Connection for data
+
+ // May have several messages per packet, or message split over packets
+
+ if (sockptr->InputLen > 3000) // Shouldnt have lines longer than this in text mode
+ {
+ sockptr->InputLen = 0;
+ }
+
+ ioctl(sockptr->TCPSock, FIONBIO, ¶m);
+
+ InputLen = recv(sockptr->TCPSock, &sockptr->TCPBuffer[sockptr->InputLen], 1000, 0);
+
+ if (InputLen == 0)
+ {
+ Debugprintf("TCP Close received for socket %d", sockptr->TCPSock);
+
+ if (sockptr->TCPMode == TCPSlave)
+ sockptr->TCPState = TCPListening;
+ else
+ sockptr->TCPState = 0;
+ closesocket(sockptr->TCPSock);
+ continue;
+ }
+
+ if (InputLen < 0)
+ {
+ int err = WSAGetLastError();
+
+ if (err == 10035 || err == 11)
+ InputLen = 0;
+ else
+ {
+ if (sockptr->TCPMode == TCPSlave)
+ sockptr->TCPState = TCPListening;
+ else
+ sockptr->TCPState = 0;
+
+ closesocket(sockptr->TCPSock);
+ continue;
+ }
+ }
+
+ sockptr->InputLen += InputLen;
+
+ if (sockptr->InputLen == 0)
+ {
+ sockptr->TCPOK++;
+
+ if (sockptr->TCPOK > 36000) // 60 MINS
+ {
+ if (sockptr->TCPSock)
+ {
+ Debugprintf("No Data for 60 Mins on Data Sock %d State %d",
+ sockptr->TCPListenSock, sockptr->TCPSock, sockptr->TCPState);
+
+ sockptr->TCPState = 0;
+ closesocket(sockptr->TCPSock);
+ sockptr->TCPSock = 0;
+ }
+
+ closesocket(sockptr->TCPListenSock);
+ OpenListeningSocket(PORT, sockptr);
+
+ sockptr->TCPOK = 0;
+ }
+ continue;
+ }
+ }
+
+ ptr = memchr(sockptr->TCPBuffer, FEND, sockptr->InputLen);
+
+ if (ptr) // FEND in buffer
+ {
+ ptr2 = &sockptr->TCPBuffer[sockptr->InputLen];
+ ptr++;
+
+ if (ptr == ptr2)
+ {
+ // Usual Case - single meg in buffer
+
+ MsgLen = sockptr->InputLen;
+ sockptr->InputLen = 0;
+
+ if (MsgLen > 1)
+ {
+ memcpy(Buffer, sockptr->TCPBuffer, MsgLen);
+
+ if (PORT->MHEnabled)
+ Update_MH_List(PORT, (UCHAR *)&sockptr->destaddr.sin_addr.s_addr, &Buffer[7],'T', sockptr->port, 0);
+
+ sockptr->TCPOK = 0;
+
+ return MsgLen;
+ }
+ }
+ else
+ {
+ // buffer contains more that 1 message
+
+ MsgLen = sockptr->InputLen - (int)((ptr2-ptr));
+ memcpy(Buffer, sockptr->TCPBuffer, MsgLen);
+
+ memmove(sockptr->TCPBuffer, ptr, sockptr->InputLen-MsgLen);
+
+ sockptr->InputLen -= MsgLen;
+
+ if (MsgLen > 1)
+ {
+ if (PORT->MHEnabled)
+ Update_MH_List(PORT, (UCHAR *)&sockptr->destaddr.sin_addr.s_addr, &Buffer[7],'T', sockptr->port, 0);
+
+ sockptr->TCPOK = 0;
+
+ return MsgLen;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+
+}
+
+int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len)
+{
+ int i,txptr=0;
+ UCHAR c;
+
+ outbuff[0]=FEND;
+ txptr=1;
+
+ for (i=0;iTCPMode == TCPMaster)
+ {
+ if (arp->TCPState == 0)
+ {
+ arp->TCPSock=socket(AF_INET,SOCK_STREAM,0);
+
+ if (arp->TCPSock == INVALID_SOCKET)
+ {
+ i=sprintf(Msg, "Socket Failed for AX/TCP socket - error code = %d\n", WSAGetLastError());
+ WritetoConsole(Msg);
+ goto wait;
+ }
+
+ setsockopt (arp->TCPSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
+ setsockopt(arp->TCPSock, SOL_SOCKET, SO_KEEPALIVE, (char*)&bcopt, 4);
+
+ sinx.sin_family = AF_INET;
+ sinx.sin_addr.s_addr = INADDR_ANY;
+ sinx.sin_port = 0;
+
+ if (bind(arp->TCPSock, (struct sockaddr *) &sinx, addrlen) != 0 )
+ {
+ //
+ // Bind Failed
+ //
+
+ i=sprintf(Msg, "Bind Failed for AX/TCP socket - error code = %d\n", WSAGetLastError());
+ WritetoConsole(Msg);
+
+ goto wait;
+ }
+
+ arp->TCPState = TCPConnecting;
+
+ if (connect(arp->TCPSock,(struct sockaddr *) &arp->destaddr, sizeof(arp->destaddr)) == 0)
+ {
+ //
+ // Connected successful
+ //
+
+ arp->TCPState = TCPConnected;
+ OutputDebugString("AXTCP Connected\r\n");
+ ioctl (arp->TCPSock, FIONBIO, ¶m);
+ Alerted = 0;
+ }
+ else
+ {
+ err=WSAGetLastError();
+
+ // Connect failed
+ //
+
+ if (Alerted == 0)
+ {
+ i = sprintf(Msg, "Connect Failed for AX/TCP port %d - error code = %d\n", htons(arp->destaddr.sin_port), err);
+ WritetoConsole(Msg);
+ OutputDebugString(Msg);
+ Alerted = 1;
+ }
+ closesocket(arp->TCPSock);
+ arp->TCPSock = 0;
+ arp->TCPState = 0;
+ }
+ }
+wait:
+ Sleep (115000); // 2 Mins
+ }
+
+ Debugprintf("AX/TCP Connect Thread %x Closing", arp->TCPThreadID);
+
+ arp->TCPThreadID = 0;
+
+ return; // Not Used
+
+}
+
+VOID Format_Addr(unsigned char * Addr, char * Output, BOOL IPV6)
+{
+ unsigned char * src;
+ char zeros[12] = "";
+ char * ptr;
+ struct
+ {
+ int base, len;
+ } best, cur;
+ unsigned int words[8];
+ int i;
+
+ if (IPV6 == FALSE)
+ {
+ sprintf((char *)Output, "%d.%d.%d.%d", Addr[0], Addr[1], Addr[2], Addr[3]);
+ return;
+ }
+
+ src = Addr;
+
+ // See if Encapsulated IPV4 addr
+
+ if (src[12] != 0)
+ {
+ if (memcmp(src, zeros, 12) == 0) // 12 zeros, followed by non-zero
+ {
+ sprintf((char *)Output, "::%d.%d.%d.%d", src[12], src[13], src[14], src[15]);
+ return;
+ }
+ }
+
+ // COnvert 16 bytes to 8 words
+
+ for (i = 0; i < 16; i += 2)
+ words[i / 2] = (src[i] << 8) | src[i + 1];
+
+ // Look for longest run of zeros
+
+ best.base = -1;
+ cur.base = -1;
+
+ for (i = 0; i < 8; i++)
+ {
+ if (words[i] == 0)
+ {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1; // New run, save start
+ else
+ cur.len++; // Continuation - increment length
+ }
+ else
+ {
+ // End of a run of zeros
+
+ if (cur.base != -1)
+ {
+ // See if this run is longer
+
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+
+ cur.base = -1; // Start again
+ }
+ }
+ }
+
+ if (cur.base != -1)
+ {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ ptr = Output;
+
+ for (i = 0; i < 8; i++)
+ {
+ /* Are we inside the best run of 0x00's? */
+
+ if (best.base != -1 && i >= best.base && i < (best.base + best.len))
+ {
+ // Just output one : for whole string of zeros
+
+ *ptr++ = ':';
+ i = best.base + best.len - 1; // skip rest of zeros
+ continue;
+ }
+
+ /* Are we following an initial run of 0x00s or any real hex? */
+
+ if (i != 0)
+ *ptr++ = ':';
+
+ ptr += sprintf (ptr, "%x", words[i]);
+
+ // Was it a trailing run of 0x00's?
+ }
+
+ if (best.base != -1 && (best.base + best.len) == 8)
+ *ptr++ = ':';
+
+ *ptr++ = '\0';
+}
+
+
+#define LIBCONFIG_STATIC
+#include "libconfig.h"
+
+
+
+VOID SaveAXIPCache(struct AXIPPORTINFO * PORT)
+{
+ config_setting_t *root, *group;
+ config_t cfg;
+ char ConfigName[256];
+ int index=0;
+ struct arp_table_entry * arp;
+ unsigned char hostaddr[64];
+ char Key[128];
+
+ if (BPQDirectory[0] == 0)
+ {
+ sprintf(ConfigName,"axipcache%d.cfg", PORT->Port);
+ }
+ else
+ {
+ sprintf(ConfigName,"%s/axipcache%d.cfg", BPQDirectory, PORT->Port);
+ }
+
+ // Get rid of old config before saving
+
+ config_init(&cfg);
+
+ root = config_root_setting(&cfg);
+
+ group = config_setting_add(root, "main", CONFIG_TYPE_GROUP);
+
+ if (PORT->arp_table_len >= MAX_ENTRIES)
+ {
+ Debugprintf("arp_table_len corrupt - %d", PORT->arp_table_len);
+ PORT->arp_table_len = MAX_ENTRIES - 1;
+ }
+
+ while (index < PORT->arp_table_len)
+ {
+ char * ptr = Key;
+
+ arp = &PORT->arp_table[index++];
+
+ if (arp->IPv6)
+ Format_Addr((unsigned char *)&arp->destaddr6.sin6_addr, hostaddr, TRUE);
+ else
+ Format_Addr((unsigned char *)&arp->destaddr.sin_addr, hostaddr, FALSE);
+
+ sprintf(Key, "*%s", arp->hostname);
+
+ // libconfig keys can't contain . so replace with *
+
+ while (*ptr)
+ {
+ if (*ptr == '.') *ptr = '*';
+ ptr++;
+ }
+
+ SaveStringValue(group, Key, hostaddr);
+ }
+
+ if(!config_write_file(&cfg, ConfigName))
+ {
+ fprintf(stderr, "Error while writing file.\n");
+ config_destroy(&cfg);
+ return;
+ }
+
+ config_destroy(&cfg);
+}
+
+#ifndef LINBPQ
+
+static BOOL GetStringValue(config_setting_t * group, char * name, char * value, int maxlen)
+{
+ char * str;
+ config_setting_t *setting;
+
+ setting = config_setting_get_member (group, name);
+ if (setting)
+ {
+ str = (char *)config_setting_get_string (setting);
+
+ if (strlen(str) > maxlen)
+ {
+ Debugprintf("Suspect config record %s", str);
+ str[maxlen] = 0;
+ }
+ strcpy(value, str);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+#endif
+
+VOID GetAXIPCache(struct AXIPPORTINFO * PORT)
+{
+ config_setting_t *group;
+ config_t cfg;
+ char ConfigName[256];
+ int index=0;
+ struct arp_table_entry * arp;
+ unsigned char hostaddr[64];
+ char Key[128];
+ struct stat STAT;
+
+ if (BPQDirectory[0] == 0)
+ {
+ sprintf(ConfigName,"axipcache%d.cfg", PORT->Port);
+ }
+ else
+ {
+ sprintf(ConfigName,"%s/axipcache%d.cfg", BPQDirectory, PORT->Port);
+ }
+
+ memset((void *)&cfg, 0, sizeof(config_t));
+
+ config_init(&cfg);
+
+ if (stat(ConfigName, &STAT) == -1)
+ return;
+
+ if(!config_read_file(&cfg, ConfigName))
+ {
+ fprintf(stderr, "AXIP Cache read error line %d - %s\n", config_error_line(&cfg), config_error_text(&cfg));
+ config_destroy(&cfg);
+ return;
+ }
+
+ group = config_lookup(&cfg, "main");
+
+ if (group == NULL)
+ {
+ config_destroy(&cfg);
+ return;
+ }
+
+ while (index < PORT->arp_table_len)
+ {
+ char * ptr = Key;
+
+ arp = &PORT->arp_table[index++];
+
+ sprintf(Key, "*%s", arp->hostname);
+
+ // libconfig keys can't contain . so replace with *
+
+ while (*ptr)
+ {
+ if (*ptr == '.') *ptr = '*';
+ ptr++;
+ }
+
+ if (GetStringValue(group, Key, hostaddr, 64))
+ {
+ arp->destaddr.sin_addr.s_addr = inet_addr(hostaddr);
+ }
+ }
+
+ config_destroy(&cfg);
+}
+
diff --git a/.svn/pristine/0e/0e76009e1f1f816128476fe53b8ac9e78d519dea.svn-base b/.svn/pristine/0e/0e76009e1f1f816128476fe53b8ac9e78d519dea.svn-base
index caa0cc8..6755ea9 100644
--- a/.svn/pristine/0e/0e76009e1f1f816128476fe53b8ac9e78d519dea.svn-base
+++ b/.svn/pristine/0e/0e76009e1f1f816128476fe53b8ac9e78d519dea.svn-base
@@ -1,6764 +1,6764 @@
-/*
-Copyright 2001-2022 John Wiseman G8BPQ
-
-This file is part of LinBPQ/BPQ32.
-
-LinBPQ/BPQ32 is free software: you can redistribute it and/or modifyextern int HTTP
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-LinBPQ/BPQ32 is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
-*/
-//
-// 409l Oct 2001 Fix l3timeout for KISS
-//
-// 409m Oct 2001 Fix Crossband Digi
-//
-// 409n May 2002 Change error handling on load ext DLL
-
-// 409p March 2005 Allow Multidigit COM Ports (kiss.c)
-
-// 409r August 2005 Treat NULL string in Registry as use current directory
-// Allow shutdown to close BPQ Applications
-
-// 409s October 2005 Add DLL:Export entries to API for BPQTNC2
-
-// 409t January 2006
-//
-// Add API for Perl "GetPerlMsg"
-// Add API for BPQ1632 "GETBPQAPI" - returns address of Assembler API routine
-// Add Registry Entry "BPQ Directory". If present, overrides "Config File Location"
-// Add New API "GetBPQDirectory" - Returns location of config file
-// Add New API "ChangeSessionCallsign" - equivalent to "*** linked to" command
-// Rename BPQNODES to BPQNODES.dat
-// New API "GetAttachedProcesses" - returns number of processes connected.
-// Warn if user trys to close Console Window.
-// Add Debug entries to record Process Attach/Detach
-// Fix recovery following closure of first process
-
-// 409t Beta 2 February 2006
-//
-// Add API Entry "GetPortNumber"
-//
-// 409u February 2006
-//
-// Fix crash if allocate/deallocate called with stream=0
-// Add API to ch
-// Display config file path
-// Fix saving of Locked Node flag
-// Added SAVENODES SYSOP command
-//
-// 409u 2 March 2006
-//
-// Fix SetupBPQDirectory
-// Add CopyBPQDirectory (for Basic Programs)
-//
-// 409u 3 March 2006
-//
-// Release streams on DLL unload
-
-// 409v October 2006
-//
-// Support Minimize to Tray for all BPQ progams
-// Implement L4 application callsigns
-
-// 410 November 2006
-//
-// Modified to compile with C++ 2005 Express Edition
-// Make MCOM MTX MMASK local variables
-//
-// 410a January 2007
-//
-// Add program name to Attach-Detach messages
-// Attempt to detect processes which have died
-// Fix bug in NETROM and IFrame decode which would cause crash if frame was corrupt
-// Add BCALL - origin call for Beacons
-// Fix KISS ACKMODE ACK processing
-//
-
-// 410b November 2007
-//
-// Allow CTEXT of up to 510, and enforce PACLEN, fragmenting if necessary
-
-// 410c December 2007
-
-// Fix problem with NT introduced in V410a
-// Display location of DLL on Console
-
-// 410d January 2008
-
-// Fix crash in DLL Init caused by long path to program
-// Invoke Appl2 alias on C command (if enabled)
-// Allow C command to be disabled
-// Remove debug trap in GETRAWFRAME
-// Validate Alias of directly connected node, mainly for KPC3 DISABL Problem
-// Move Port statup code out of DLLInit (mainly for perl)
-// Changes to allow Load/Unload of bpq32.dll by appl
-// CloseBPQ32 API added
-// Ext Driver Close routes called
-// Changes to release Mutex
-
-// 410e May 2008
-
-// Fix missing SSID on last call of UNPROTO string (CONVTOAX25 in main.asm)
-// Fix VCOM Driver (RX Len was 1 byte too long)
-// Fix possible crash on L4CODE if L4DACK received out of sequence
-// Add basic IP decoding
-
-// 410f October 2008
-
-// Add IP Gateway
-// Add Multiport DIGI capability
-// Add GetPortDescription API
-// Fix potential hangs if RNR lost
-// Fix problem if External driver failes to load
-// Put pushad/popad round _INITIALISEPORTS (main.asm)
-// Add APIs GetApplCallVB and GetPortDescription (mainly for RMS)
-// Ensure Route Qual is updated if Port Qual changed
-// Add Reload Option, plus menu items for DUMP and SAVENODES
-
-// 410g December 2008
-
-// Restore API Exports BPQHOSTAPIPTR and MONDECODEPTR (accidentally deleted)
-// Fix changed init of BPQDirectory (accidentally changed)
-// Fix Checks for lost processes (accidentally deleted)
-// Support HDLC Cards on W2K and above
-// Delete Tray List entries for crashed processes
-// Add Option to NODES command to sort by Callsign
-// Add options to save or clear BPQNODES before Reconfig.
-// Fix Reconfig in Win98
-// Monitor buffering tweaks
-// Fix Init for large (>64k) tables
-// Fix Nodes count in Stats
-
-// 410h January 2009
-
-// Add Start Minimized Option
-// Changes to KISS for WIn98 Virtual COM
-// Open \\.\com instead of //./COM
-// Extra Dignostics
-
-// 410i Febuary 2009
-
-// Revert KISS Changes
-// Save Window positions
-
-// 410j June 2009
-
-// Fix tidying of window List when program crashed
-// Add Max Nodes to Stats
-// Don't update APPLnALIAS with received NODES info
-// Fix MH display in other timezones
-// Fix Possible crash when processing NETROM type Zero frames (eg NRR)
-// Basic INP3 Stuff
-// Add extra diagnostics to Lost Process detection
-// Process Netrom Record Route frames.
-
-// 410k June 2009
-
-// Fix calculation of %retries in extended ROUTES display
-// Fix corruption of ROUTES table
-
-// 410l October 2009
-
-// Add GetVersionString API call.
-// Add GetPortTableEntry API call
-// Keep links to neighbouring nodes open
-
-// Build 2
-
-// Fix PE in NOROUTETODEST (missing POP EBX)
-
-// 410m November 2009
-
-// Changes for PACTOR and WINMOR to support the ATTACH command
-// Enable INP3 if configured on a route.
-// Fix count of nodes in Stats Display
-// Overwrite the worst quality unused route if a call is received from a node not in your
-// table when the table is full
-
-// Build 5
-
-// Rig Control Interface
-// Limit KAM VHF attach and RADIO commands to authorised programs (MailChat and BPQTerminal)
-
-// Build 6
-
-// Fix reading INP3 Flag from BPQNODES
-
-// Build 7
-
-// Add MAXHOPS and MAXRTT config options
-
-// Build 8
-
-// Fix INP3 deletion of Application Nodes.
-// Fix GETCALLSIGN for Pactor Sessions
-// Add N Call* to display all SSID's of a call
-// Fix flow control on Pactor sessions.
-
-// Build 9
-
-// HDLC Support for XP
-// Add AUTH routines
-
-// Build 10
-
-// Fix handling commands split over more that one packet.
-
-// Build 11
-
-// Attach cmd changes for winmor disconnecting state
-// Option Interlock Winmor/Pactor ports
-
-// Build 12
-
-// Add APPLS export for winmor
-// Handle commands ending CR LF
-
-// Build 13
-
-// Incorporate Rig Control in Kernel
-
-// Build 14
-
-// Fix config reload for Rig COntrol
-
-// 410n March 2010
-
-// Implement C P via PACTOR/WINMOR (for Airmail)
-
-// Build 2
-
-// Don't flip SSID bits on Downlink Connect if uplink is Pactor/WINMOR
-// Fix resetting IDLE Timer on Pactor/WINMOR sessions
-// Send L4 KEEPLI messages based on IDLETIME
-
-// 410o July 2010
-
-// Read bpqcfg.txt instead of .bin
-// Support 32 bit MMASK (Allowing 32 Ports)
-// Support 32 bit _APPLMASK (Allowing 32 Applications)
-// Allow more commands
-// Allow longer command aliases
-// Fix logic error in RIGControl Port Initialisation (wasn't always raising RTS and DTR
-// Clear RIGControl RTS and DTR on close
-
-// 410o Build 2 August 2010
-
-// Fix couple of errors in config (needed APPLICATIONS and BBSCALL/ALIAS/QUAL)
-// Fix Kenwood Rig Control when more than one message received at once.
-// Save minimzed state of Rigcontrol Window
-
-// 410o Build 3 August 2010
-
-// Fix reporting of set errors in scan to a random session
-
-// 410o Build 4 August 2010
-
-// Change All xxx Ports are in use to no xxxx Ports are available if there are no sessions with _APPLMASK
-// Fix validation of TRANSDELAY
-
-// 410o Build 5 August 2010
-
-// Add Repeater Shift and Set Data Mode options to Rigcontrol (for ICOM only)
-// Add WINMOR and SCS Pactor mode control option to RigControl
-// Extend INFOMSG to 2000 bytes
-// Improve Scan freq change lock (check both SCS and WINMOR Ports)
-
-// 410o Build 6 September 2010
-
-// Incorporate IPGateway in main code.
-// Fix GetSessionInfo for Pactor/Winmor Ports
-// Add Antenna Selection to RigControl
-// Allow Bandwidth options on RADIO command line (as well as in Scan definitions)
-
-// 410o Build 7 September 2010
-
-// Move rigconrtol display to driver windows
-// Move rigcontrol config to driver config.
-// Allow driver and IPGateway config info in bpq32.cfg
-// Move IPGateway, AXIP, VKISS, AGW and WINMOR drivers into bpq32.dll
-// Add option to reread IP Gateway config.
-// Fix Reinit after process with timer closes (error in TellSessions).
-
-// 410p Build 2 October 2010
-
-// Move KAM and SCS drivers to bpq32.dll
-
-// 410p Build 3 October 2010
-
-// Support more than one axip port.
-
-// 410p Build 4 October 2010
-
-// Dynamically load psapi.dll (for 98/ME)
-
-// 410p Build 5 October 2010
-
-// Incorporate TelnetServer
-// Fix AXIP ReRead Config
-// Report AXIP accept() fails to syslog, not a popup.
-
-// 410p Build 6 October 2010
-
-// Includes HAL support
-// Changes to Pactor Drivers disconnect code
-// AXIP now sends with source port = dest port, unless overridden by SOURCEPORT param
-// Config now checks for duplicate port definitions
-// Add Node Map reporting
-// Fix WINMOR deferred disconnect.
-// Report Pactor PORTCALL to WL2K instead of RMS Applcall
-
-// 410p Build 7 October 2010
-
-// Add In/Out flag to Map reporting, and report centre, not dial
-// Write Telnet log to BPQ Directory
-// Add Port to AXIP resolver display
-// Send Reports to update.g8bpq.net:81
-// Add support for FT100 to Rigcontrol
-// Add timeout to Rigcontrol PTT
-// Add Save Registry Command
-
-// 410p Build 8 November 2010
-
-// Add NOKEEPALIVES Port Param
-// Renumbered for release
-
-// 410p Build 9 November 2010
-
-// Get Bandwith for map report from WL2K Report Command
-// Fix freq display for FT100 (was KHz, not MHz)
-// Don't try to change SCS mode whilst initialising
-// Allow reporting of Lat/Lon as well as Locator
-// Fix Telnet Log Name
-// Fix starting with Minimized windows when Minimizetotray isn't set
-// Extra Program Error trapping in SessionControl
-// Fix reporting same freq with different bandwidths at different times.
-// Code changes to support SCS Robust Packet Mode.
-// Add FT2000 to Rigcontrol
-// Only Send CTEXT to connects to Node (not to connects to an Application Call)
-
-// Released as Build 10
-
-// 410p Build 11 January 2011
-
-// Fix MH Update for SCS Outgoing Calls
-// Add Direct CMS Access to TelnetServer
-// Restructure DISCONNECT processing to run in Timer owning process
-
-// 410p Build 12 January 2011
-
-// Add option for Hardware PTT to use a different com port from the scan port
-// Add CAT PTT for Yaesu 897 (and maybe others)
-// Fix RMS Packet ports busy after restart
-// Fix CMS Telnet with MAXSESSIONS > 10
-
-// 410p Build 13 January 2011
-
-// Fix loss of buffers in TelnetServer
-// Add CMS logging.
-// Add non - Promiscuous mode option for BPQETHER
-
-// 410p Build 14 January 2011
-
-// Add support for BPQTermTCP
-// Allow more that one FBBPORT
-// Allow Telnet FBB mode sessions to send CRLF as well as CR on user and pass msgs
-// Add session length to CMS Telnet logging.
-// Return Secure Session Flag from GetConnectionInfo
-// Show Uptime as dd/hh/mm
-
-// 4.10.16.17 March 2011
-
-// Add "Close all programs" command
-// Add BPQ Program Directory registry key
-// Use HKEY_CURRENT_USER on Vista and above (and move registry if necessary)
-// Time out IP Gateway ARP entries, and only reload ax.25 ARP entries
-// Add support for SCS Tracker HF Modes
-// Fix WL2K Reporting
-// Report Version to WL2K
-// Add Driver to support Tracker with multiple sessions (but no scanning, wl2k report, etc)
-
-
-// Above released as 5.0.0.1
-
-// 5.2.0.1
-
-// Add caching of CMS Server IP addresses
-// Initialise TNC State on Pactor Dialogs
-// Add Shortened (6 digit) AUTH mode.
-// Update MH with all frames (not just I/UI)
-// Add IPV6 Support for TelnetServer and AXIP
-// Fix TNC OK Test for Tracker
-// Fix crash in CMS mode if terminal disconnects while tcp commect in progress
-// Add WL2K reporting for Robust Packet
-// Add option to suppress WL2K reporting for specific frequencies
-// Fix Timeband processing for Rig Control
-// New Driver for SCS Tracker allowing multiple connects, so Tracker can be used for user access
-// New Driver for V4 TNC
-
-// 5.2.1.3 October 2011
-
-// Combine busy detector on Interlocked Ports (SCS PTC, WINMOR or KAM)
-// Improved program error logging
-// WL2K reporting changed to new format agreed with Lee Inman
-
-// 5.2.3.1 January 2012
-
-// Connects from the console to an APPLCALL or APPLALIAS now invoke any Command Alias that has been defined.
-// Fix reporting of Tracker freqs to WL2K.
-// Fix Tracker monitoring setup (sending M UISC)
-// Fix possible call/application routing error on RP
-// Changes for P4Dragon
-// Include APRS Digi/IGate
-// Tracker monitoring now includes DIGIS
-// Support sending UI frames using SCSTRACKER, SCTRKMULTI and UZ7HO drivers
-// Include driver for UZ7HO soundcard modem.
-// Accept DRIVER as well as DLLNAME, and COMPORT as well as IOADDR in bpq32.cfg. COMPORT is decimal
-// No longer supports separate config files, or BPQTELNETSERVER.exe
-// Improved flow control for Telnet CMS Sessions
-// Fix handling Config file without a newline after last line
-// Add non - Promiscuous mode option for BPQETHER
-// Change Console Window to a Dialog Box.
-// Fix possible corruption and loss of buffers in Tracker drivers
-// Add Beacon After Session option to Tracker and UZ7HO Drivers
-// Rewrite RigControl and add "Reread Config Command"
-// Support User Mode VCOM Driver for VKISS ports
-
-// 5.2.4.1 January 2012
-
-// Remove CR from Telnet User and Password Prompts
-// Add Rigcontrol to UZ7HO driver
-// Fix corruption of Free Buffer Count by Rigcontol
-// Fix WINMOR and V4 PTT
-// Add MultiPSK Driver
-// Add SendBeacon export for BPQAPRS
-// Add SendChatReport function
-// Fix check on length of Port Config ID String with trailing spaces
-// Fix interlock when Port Number <> Port Slot
-// Add NETROMCALL for L3 Activity
-// Add support for APRS Application
-// Fix Telnet with FBBPORT and no TCPPORT
-// Add Reread APRS Config
-// Fix switching to Pactor after scanning in normal packet mode (PTC)
-
-// 5.2.5.1 February 2012
-
-// Stop reading Password file.
-// Add extra MPSK commands
-// Fix MPSK Transparency
-// Make LOCATOR command compulsory
-// Add MobileBeaconInterval APRS param
-// Send Course and Speed when APRS is using GPS
-// Fix Robust Packet reporting in PTC driver
-// Fix corruption of some MIC-E APRS packets
-
-// 5.2.6.1 February 2012
-
-// Convert to MDI presentation of BPQ32.dll windows
-// Send APRS Status packets
-// Send QUIT not EXIT in PTC Init
-// Implement new WL2K reporting format and include traffic reporting info in CMS signon
-// New WL2KREPORT format
-// Prevent loops when APPL alias refers to itself
-// Add RigControl for Flex radios and ICOM IC-M710 Marine radio
-
-// 5.2.7.1
-
-// Fix opening more thn one console window on Win98
-// Change method of configuring multiple timelots on WL2K reporting
-// Add option to update WK2K Sysop Database
-// Add Web server
-// Add UIONLY port option
-
-// 5.2.7.2
-
-// Fix handling TelnetServer packets over 500 bytes in normal mode
-
-// 5.2.7.3
-
-// Fix Igate handling packets from UIView
-
-// 5.2.7.4
-
-// Prototype Baycom driver.
-
-// 5.2.7.5
-
-// Set WK2K group ref to MARS (3) if using a MARS service code
-
-// 5.2.7.7
-
-// Check for programs calling CloseBPQ32 when holding semaphore
-// Try/Except round Status Timer Processing
-
-// 5.2.7.8
-
-// More Try/Except round Timer Processing
-
-// 5.2.7.9
-
-// Enable RX in Baycom, and remove test loopback in tx
-
-// 5.2.7.10
-
-// Try/Except round ProcessHTTPMessage
-
-// 5.2.7.11
-
-// BAYCOM tweaks
-
-// 5.2.7.13
-
-// Release semaphore after program error in Timer Processing
-// Check fro valid dest in REFRESHROUTE
-
-
-// Add TNC-X KISSOPTION (includes the ACKMODE bytes in the checksum(
-
-// Version 5.2.9.1 Sept 2012
-
-// Fix using KISS ports with COMn > 16
-// Add "KISS over UDP" driver for PI as a TNC concentrator
-
-// Version 6.0.1.1
-
-// Convert to C for linux portability
-// Try to speed up kiss polling
-
-// Version 6.0.2.1
-
-// Fix operation on Win98
-// Fix callsign error with AGWtoBPQ
-// Fix PTT problem with WINMOR
-// Fix Reread telnet config
-// Add Secure CMS signon
-// Fix error in cashing addresses of CMS servers
-// Fix Port Number when using Send Raw.
-// Fix PE in KISS driver if invalid subchannel received
-// Fix Orignal address of beacons
-// Speed up Telnet port monitoring.
-// Add TNC Emulators
-// Add CountFramesQueuedOnStream API
-// Limit number of frames that can be queued on a session.
-// Add XDIGI feature
-// Add Winmor Robust Mode switching for compatibility with new Winmor TNC
-// Move most APRS code from BPQAPRS to here
-// Stop corruption caused by overlong KISS frames
-
-// Version 6.0.3.1
-
-// Add starting/killing WINMOR TNC on remote host
-// Fix Program Error when APRS Item or Object name is same as call of reporting station
-// Dont digi a frame that we have already digi'ed
-// Add ChangeSessionIdleTime API
-// Add WK2KSYSOP Command
-// Add IDLETIME Command
-// Fix Errors in RELAYAPPL processing
-// Fix PE cauaed by invalid Rigcontrol Line
-
-// Version 6.0.4.1
-
-// Add frequency dependent autoconnect appls for SCS Pactor
-// Fix DED Monitoring of I and UI with no data
-// Include AGWPE Emulator (from AGWtoBPQ)
-// accept DEL (Hex 7F) as backspace in Telnet
-// Fix re-running resolver on re-read AXIP config
-// Speed up processing, mainly for Telnet Sessions
-// Fix APRS init on restart of bpq32.exe
-// Change to 2 stop bits
-// Fix scrolling of WINMOR trace window
-// Fix Crash when ueing DED TNC Emulator
-// Fix Disconnect when using BPQDED2 Driver with Telnet Sessions
-// Allow HOST applications even when CMS option is disabled
-// Fix processing of APRS DIGIMAP command with no targets (didn't suppress default settings)
-
-// Version 6.0.5.1 January 2014
-
-// Add UTF8 conversion mode to Telnet (converts non-UTF-8 chars to UTF-8)
-// Add "Clear" option to MH command
-// Add "Connect to RMS Relay" Option
-// Revert to one stop bit on serial ports, explictly set two on FT2000 rig control
-// Fix routing of first call in Robust Packet
-// Add Options to switch input source on rigs with build in soundcards (sor far only IC7100 and Kenwood 590)
-// Add RTS>CAT PTT option for Sound Card rigs
-// Add Clear Nodes Option (NODE DEL ALL)
-// SCS Pactor can set differeant APPLCALLS when scanning.
-// Fix possible Scan hangup after a manual requency change with SCS Pactor
-// Accept Scan entry of W0 to disable WINMOR on that frequency
-// Fix corruption of NETROMCALL by SIMPLE config command
-// Enforce Pactor Levels
-// Add Telnet outward connect
-// Add Relay/Trimode Emulation
-// Fix V4 Driver
-// Add PTT Mux
-// Add Locked ARP Entries (via bpq32.cfg)
-// Fix IDLETIME node command
-// Fix STAY param on connect
-// Add STAY option to Attach and Application Commands
-// Fix crash on copying a large AXIP MH Window
-// Fix possible crash when bpq32.exe dies
-// Fix DIGIPORT for UI frames
-
-// Version 6.0.6.1 April 2014
-
-// FLDigi Interface
-// Fix "All CMS Servers are inaccessible" message so Mail Forwarding ELSE works.
-// Validate INP3 messages to try to prevent crash
-// Fix possible crash if an overlarge KISS frame is received
-// Fix error in AXR command
-// Add LF to Telnet Outward Connect signin if NEEDLF added to connect line
-// Add CBELL to TNC21 emulator
-// Add sent objects and third party messages to APRS Dup List
-// Incorporate UIUtil
-// Use Memory Mapped file to pass APRS info to BPQAPRS, and process APRS HTTP in BPQ32
-// Improvements to FLDIGI interlocking
-// Fix TNC State Display for Tracker
-// Cache CMS Addresses on LinBPQ
-// Fix count error on DED Driver when handling 256 byte packets
-// Add basic SNMP interface for MRTG
-// Fix memory loss from getaddrinfo
-// Process "BUSY" response from Tracker
-// Handle serial port writes that don't accept all the data
-// Trap Error 10038 and try to reopen socket
-// Fix crash if overlong command line received
-
-// Version 6.0.7.1 Aptil 2014
-// Fix RigContol with no frequencies for Kenwood and Yaesu
-// Add busy check to FLDIGI connects
-
-// Version 6.0.8.1 August 2014
-
-// Use HKEY_CURRENT_USER on all OS versions
-// Fix crash when APRS symbol is a space.
-// Fixes for FT847 CAT
-// Fix display of 3rd byte of FRMR
-// Add "DEFAULT ROBUST" and "FORCE ROBUST" commands to SCSPactor Driver
-// Fix possible memory corruption in WINMOR driver
-// Fix FT2000 Modes
-// Use new WL2K reporting system (Web API Based)
-// APRS Server now cycles through hosts if DNS returns more than one
-// BPQ32 can now start and stop FLDIGI
-// Fix loss of AXIP Resolver when running more than one AXIP port
-
-// Version 6.0.9.1 November 2014
-
-// Fix setting NOKEEPALIVE flag on route created from incoming L3 message
-// Ignore NODES from locked route with quality 0
-// Fix seting source port in AXIP
-// Fix Dual Stack (IPV4/V6) on Linux.
-// Fix RELAYSOCK if IPv6 is enabled.
-// Add support for FT1000
-// Fix hang when APRS Messaging packet received on RF
-// Attempt to normalize Node qualies when stations use widely differing Route qualities
-// Add NODES VIA command to display nodes reachable via a specified neighbour
-// Fix applying "DisconnectOnClose" setting on HOST API connects (Telnet Server)
-// Fix buffering large messages in Telnet Host API
-// Fix occasional crash in terminal part line processing
-// Add "NoFallback" command to Telnet server to disable "fallback to Relay"
-// Improved support for APPLCALL scanning with Pactor
-// MAXBUFFS config statement is no longer needed.
-// Fix USEAPPLCALLS with Tracker when connect to APPLCALL fails
-// Implement LISTEN and CQ commands
-// FLDIGI driver can now start FLDIGI on a remote system.
-// Add IGNOREUNLOCKEDROUTES parameter
-// Fix error if too many Telnet server connections
-
-// Version 6.0.10.1 Feb 2015
-
-// Fix crash if corrupt HTML request received.
-// Allow SSID's of 'R' and 'T' on non-ax.25 ports for WL2K Radio Only network.
-// Make HTTP server HTTP Version 1.1 complient - use persistent conections and close after 2.5 mins
-// Add INP3ONLY flag.
-// Fix program error if enter UNPROTO without a destination path
-// Show client IP address on HTTP sessions in Telnet Server
-// Reduce frequency and number of attempts to connect to routes when Keepalives or INP3 is set
-// Add FT990 RigControl support, fix FT1000MP support.
-// Support ARMV5 processors
-// Changes to support LinBPQ APRS Client
-// Add IC7410 to supported Soundcard rigs
-// Add CAT PTT to NMEA type (for ICOM Marine Radios_
-// Fix ACKMODE
-// Add KISS over TCP
-// Support ACKMode on VKISS
-// Improved reporting of configuration file format errors
-// Experimental driver to support ARQ sessions using UI frames
-
-// Version 6.0.11.1 September 2015
-
-// Fixes for IPGateway configuration and Virtual Circuit Mode
-// Separate Portmapper from IPGateway
-// Add PING Command
-// Add ARDOP Driver
-// Add basic APPLCALL support for PTC-PRO/Dragon 7800 Packet (using MYALIAS)
-// Add "VeryOldMode" for KAM Version 5.02
-// Add KISS over TCP Slave Mode.
-// Support Pactor and Packet on P4Dragon on one port
-// Add "Remote Staton Quality" to Web ROUTES display
-// Add Virtual Host option for IPGateway NET44 Encap
-// Add NAT for local hosts to IPGateway
-// Fix setting filter from RADIO command for IC7410
-// Add Memory Channel Scanning for ICOM Radios
-// Try to reopen Rig Control port if it fails (could be unplugged USB)
-// Fix restoring position of Monitor Window
-// Stop Codec on Winmor and ARDOP when an interlocked port is attached (instead of listen false)
-// Support APRS beacons in RP mode on Dragon//
-// Change Virtual MAC address on IPGateway to include last octet of IP Address
-// Fix "NOS Fragmentation" in IP over ax.25 Virtual Circuit Mode
-// Fix sending I frames before L2 session is up
-// Fix Flow control on Telnet outbound sessions.
-// Fix reporting of unterminatred comments in config
-// Add option for RigControl to not change mode on FT100/FT990/FT1000
-// Add "Attach and Connect" for Telnet ports
-
-// Version 6.0.12.1 November 2015
-
-// Fix logging of IP addresses for connects to FBBPORT
-// Allow lower case user and passwords in Telnet "Attach and Connect"
-// Fix possible hang in KISS over TCP Slave mode
-// Fix duplicating LinBPQ process if running ARDOP fails
-// Allow lower case command aliases and increase alias length to 48
-// Fix saving long IP frames pending ARP resolution
-// Fix dropping last entry from a RIP44 message.
-// Fix displaying Digis in MH list
-// Add port name to Monitor config screen port list
-// Fix APRS command display filter and add port filter
-// Support port names in BPQTermTCP Monitor config
-// Add FINDBUFFS command to dump lost buffers to Debugview/Syslog
-// Buffer Web Mgmt Edit Config output
-// Add WebMail Support
-// Fix not closing APRS Send WX file.
-// Add RUN option to APRS Config to start APRS Client
-// LinBPQ run FindLostBuffers and exit if QCOUNT < 5
-// Close and reopen ARDOP connection if nothing received for 90 secs
-// Add facility to bridge traffic between ports (similar to APRS Bridge but for all frame types)
-// Add KISSOPTION TRACKER to set SCS Tracker into KISS Mode
-
-// 6.0.13.1
-
-// Allow /ex to exit UNPROTO mode
-// Support ARQBW commands.
-// Support IC735
-// Fix sending ARDOP beacons after a busy holdoff
-// Enable BPQDED driver to beacon via non-ax.25 ports.
-// Fix channel number in UZ7HO monitoring
-// Add SATGate mode to APRSIS Code.
-// Fix crash caused by overlong user name in telnet logon
-// Add option to log L4 connects
-// Add AUTOADDQuiet mode to AXIP.
-// Add EXCLUDE processing
-// Support WinmorControl in UZ7HO driver and fix starting TNC on Linux
-// Convert calls in MAP entries to upper case.
-// Support Linux COM Port names for APRS GPS
-// Fix using NETROM serial protocol on ASYNC Port
-// Fix setting MYLEVEL by scanner after manual level change.
-// Add DEBUGLOG config param to SCS Pactor Driver to log serial port traffic
-// Uue #myl to set SCS Pactor MYLEVEL, and add checklevel command
-// Add Multicast RX interface to FLDIGI Driver
-// Fix processing application aliases to a connect command.
-// Fix Buffer loss if radio connected to PTC rig port but BPQ not configured to use it
-// Save backups of bpq32.cfg when editing with Web interface and report old and new length
-// Add DD command to SCS Pactor, and use it for forced disconnect.
-// Add ARDOP mode select to scan config
-// ARDOP changes for ARDOP V 0.5+
-// Flip SSID bits on UZ7HO downlink connects
-
-
-// Version 6.0.14.1
-
-// Fix Socket leak in ARDOP and FLDIGI drivers.
-// Add option to change CMS Server hostname
-// ARDOP Changes for 0.8.0+
-// Discard Terminal Keepalive message (two nulls) in ARDOP command hander
-// Allow parameters to be passed to ARDOP TNC when starting it
-// Fix Web update of Beacon params
-// Retry connects to KISS ports after failure
-// Add support for ARDOP Serial Interface Native mode.
-// Fix gating APRS-IS Messages to RF
-// Fix Beacons when PORTNUM used
-// Make sure old monitor flag is cleared for TermTCP sessions
-// Add CI-V antenna control for IC746
-// Don't allow ARDOP beacons when connected
-// Add support for ARDOP Serial over I2C
-// Fix possble crash when using manual RADIO messages
-// Save out of sequence L2 frames for possible reuse after retry
-// Add KISS command to send KISS control frame to TNC
-// Stop removing unused digis from packets sent to APRS-IS
-
-// Processing of ARDOP PING and PINGACK responses
-// Handle changed encoding of WL2K update responses.
-// Allow anonymous logon to telnet
-// Don't use APPL= for RP Calls in Dragon Single mode.
-// Add basic messaging page to APRS Web Server
-// Add debug log option to SCSTracker and TrkMulti Driver
-// Support REBOOT command on LinBPQ
-// Allow LISTEN command on all ports that support ax.25 monitoring
-
-// Version 6.0.15.1 Feb 2018
-
-// partial support for ax.25 V2.2
-// Add MHU and MHL commands and MH filter option
-// Fix scan interlock with ARDOP
-// Add Input source seiect for IC7300
-// Remove % transparency from web terminal signon message
-// Fix L4 Connects In count on stats
-// Fix crash caused by corrupt CMSInfo.txt
-// Add Input peaks display to ARDOP status window
-// Add options to show time in local and distances in KM on APRS Web pages
-// Add VARA support
-// Fix WINMOR Busy left set when port Suspended
-// Add ARDOP-Packet Support
-// Add Antenna Switching for TS 480
-// Fix possible crash in Web Terminal
-// Support different Code Pages on Console sessions
-// Use new Winlink API interface (api.winlink.org)
-// Support USB/ACC switching on TS590SG
-// Fix scanning when ARDOP or WINMOR is used without an Interlocked Pactor port.
-// Set NODECALL to first Application Callsign if NODE=0 and BBSCALL not set.
-// Add RIGCONTROL TUNE and POWER commands for some ICOM and Kenwwod rigs
-// Fix timing out ARDOP PENDING Lock
-// Support mixed case WINLINK Passwords
-// Add TUNE and POWER Rigcontol Commands for some radios
-// ADD LOCALTIME and DISPKM options to APRS Digi/Igate
-
-// 6.0.16.1 March 2018
-
-// Fix Setting data mode and filter for IC7300 radios
-// Add VARA to WL2KREPORT
-// Add trace to SCS Tracker status window
-// Fix possible hang in IPGATEWAY
-// Add BeacontoIS parameter to APRSDIGI. Allows you to stop sending beacons to APRS-IS.
-// Fix sending CTEXT on WINMOR sessions
-
-// 6.0.17.1 November 2018
-
-// Change WINMOR Restart after connection to Restart after Failure and add same option to ARDOP and VARA
-// Add Abort Connection to WINMOR and VARA Interfaces
-// Reinstate accidentally removed CMS Access logging
-// Fix MH CLEAR
-// Fix corruption of NODE table if NODES received from station with null alias
-// Fix loss of buffer if session closed with something in PARTCMDBUFFER
-// Fix Spurious GUARD ZONE CORRUPT message in IP Code.
-// Remove "reread bpq32.cfg and reconfigure" menu options
-// Add support for PTT using CM108 based soundcard interfaces
-// Datestamp Telnet log files and delete old Telnet and CMSAcces logs
-
-// 6.0.18.1 January 2019
-
-// Fix validation of NODES broadcasts
-// Fix HIDENODES
-// Check for failure to reread config on axip reconfigure
-// Fix crash if STOPPORT or STARTPORT used on KISS over TCP port
-// Send Beacons from BCALL or PORTCALL if configured
-// Fix possible corruption of last entry in MH display
-// Ensure RTS/DTR is down when opening PTT Port
-// Remove RECONFIG command
-// Preparations for 64 bit version
-
-// 6.0.19 Sept 2019
-// Fix UZ7HO interlock
-// Add commands to set Centre Frequency and Modem with UZ7HO Soundmodem (on Windows only)
-// Add option to save and restore MH lists and SAVEMH command
-// Add Frequency (if known) to UZ7HO MH lists
-// Add Gateway option to Telnet for PAT
-// Try to fix SCS Tracker recovery
-// Ensure RTS/DTR is down on CAT port if using that line for PTT
-// Experimental APRS Messaging in Kernel
-// Add Rigcontrol on remote PC's using WinmorControl
-// ADD VARAFM and VARAFM96 WL2KREPORT modes
-// Fix WL2K sysop update for new Winlink API
-// Fix APRS when using PORTNUM higher than the number of ports
-// Add Serial Port Type
-// Add option to linbpq to log APRS-IS messages.
-// Send WL2K Session Reports
-// Drop Tunneled Packets from 44.192 - 44.255
-// Log incoming Telnet Connects
-// Add IPV4: and IPV6: overrides on AXIP Resolver.
-// Add SessionTimeLimit to HF sessions (ARDOP, SCSPactor, WINMOR, VARA)
-// Add RADIO FREQ command to display current frequency
-
-// 6.0.20 April 2020
-
-// Trap and reject YAPP file transfer request.
-// Fix possible overrun of TCP to Node Buffer
-// Fix possible crash if APRS WX file doesn't have a terminating newline
-// Change communication with BPQAPRS.exe to restore old message popup behaviour
-// Preparation for 64 bit version
-// Improve flow control on SCS Dragon
-// Fragment messages from network links to L2 links with smaller paclen
-// Change WL2K report rate to once every two hours
-// Add PASS, CTEXT and CMSG commands and Stream Switch support to TNC2 Emulator
-// Add SessionTimeLimit command to HF drivers (ARDOP, SCSPactor, WINMOR, VARA)
-// Add links to Ports Web Manangement Page to open individual Driver windows
-// Add STOPPORT/STARTPORT support to ARDOP, KAM and SCSPactor drivers
-// Add CLOSE and OPEN RADIO command so Rigcontrol port can be freed fpr other use.
-// Don't try to send WL2K Traffic report if Internet is down
-// Move WL2K Traffic reporting to a separate thread so it doesn't block if it can't connect to server
-// ADD AGWAPPL config command to set application number. AGWMASK is still supported
-// Register Node Alias with UZ7HO Driver
-// Register calls when UZ7HO TNC Restarts and at intervals afterwards
-// Fix crash when no IOADDR or COMPORT in async port definition
-// Fix Crash with Paclink-Unix when parsing ; VE7SPR-10 DE N7NIX QTC 1
-// Only apply BBSFLAG=NOBBS to APPPLICATION 1
-// Add RIGREONFIG command
-// fix APRS RECONFIG on LinBPQ
-// Fix Web Terminal scroll to end problem on some browsers
-// Add PTT_SETS_INPUT option for IC7600
-// Add TELRECONFIG command to reread users or whole config
-// Enforce PACLEN on UZ7HO ports
-// Fix PACLEN on Command Output.
-// Retry axip resolver if it fails at startup
-// Fix AGWAPI connect via digis
-// Fix Select() for Linux in MultiPSK, UZ7HO and V4 drivers
-// Limit APRS OBJECT length to 80 chars
-// UZ7HO disconnect incoming call if no free streams
-// Improve response to REJ (no F) followed by RR (F).
-// Try to prevent more than MAXFRAME frames outstanding when transmitting
-// Allow more than one instance of APRS on Linux
-// Stop APRS digi by originating station
-// Send driver window trace to main monitor system
-// Improve handling of IPOLL messages
-// Fix setting end of address bit on dest call on connects to listening sessions
-// Set default BBS and CHAT application number and number of streams on LinBPQ
-// Support #include in bpq32.cfg processing
-
-// Version 6.0.21 14 December 2020
-
-// Fix occasional missing newlines in some node command reponses
-// More 64 bit fixes
-// Add option to stop setting PDUPLEX param in SCSPACTOR
-// Try to fix buffer loss
-// Remove extra space from APRS position reports
-// Suppress VARA IAMALIVE messages
-// Add display and control of QtSoundModem modems
-// Only send "No CMS connection available" message if fallbacktorelay is set.
-// Add HAMLIB backend and emulator support to RIGCONTROL
-// Ensure all beacons are sent even with very short beacon intervals
-// Add VARA500 WL2K Reporting Mode
-// Fix problem with prpcessing frame collector
-// Temporarily disable L2 and L4 collectors till I can find problem
-// Fix possible problem with interactive RADIO commands not giving a response,
-// Incease maximum length of NODE command responses to handle maximum length INFO message,
-// Allow WL2KREPORT in CONFIG section of UZ7HO port config.
-// Fix program error in processing hamlib frame
-// Save RestartAfterFailure option for VARA
-// Check callsign has a winlink account before sending WL2KREPORT messages
-// Add Bandwidth control to VARA scanning
-// Renable L2 collector
-// Fix TNCPORT reconnect on Linux
-// Add SecureTelnet option to limit telnet outward connect to sysop mode sessions or Application Aliases
-// Add option to suppress sending call to application in Telnet HOST API
-// Add FT991A support to RigControl
-// Use background.jpg for Edit Config page
-// Send OK response to SCS Pactor commands starting with #
-// Resend ICOM PTT OFF command after 30 seconds
-// Add WXCall to APRS config
-// Fixes for AEAPactor
-// Allow PTTMUX to use real or com0com com ports
-// Fix monitoring with AGW Emulator
-// Derive approx position from packets on APRS ports with a valid 6 char location
-// Fix corruption of APRS message lists if the station table fills up.
-// Don't accept empty username or password on Relay sessions.
-// Fix occasional empty Nodes broadcasts
-// Add Digis to UZ7HO Port MH list
-// Add PERMITTEDAPPLS port param
-// Fix WK2K Session Record Reporting for Airmail and some Pactor Modes.
-// Fix handling AX/IP (proto 93) frames
-// Fix possible corruption sending APRS messages
-// Allow Telnet connections to be made using Connect command as well as Attach then Connect
-// Fix Cancel Sysop Signin
-// Save axip resolver info and restore on restart
-// Add Transparent mode to Telnet Server HOST API
-// Fix Tracker driver if WL2KREPRRT is in main config section
-// SNMP InOctets count corrected to include all frames and encoding of zero values fixed.
-// Change IP Gateway to exclude handling bits of 44 Net sold to Amazon
-// Fix crash in Web terminal when processing very long lines
-
-// Version 6.0.22.1 August 2021
-
-// Fix bug in KAM TNCEMULATOR
-// Add WinRPR Driver (DED over TCP)
-// Fix handling of VARA config commands FM1200 and FM9600
-// Improve Web Termanal Line folding
-// Add StartTNC to WinRPR driver
-// Add support for VARA2750 Mode
-// Add support for VARA connects via a VARA Digipeater
-// Add digis to SCSTracker and WinRPR MHeard
-// Separate RIGCONTROL config from PORT config and add RigControl window
-// Fix crash when a Windows HID device doesn't have a product_string
-// Changes to VARA TNC connection and restart process
-// Trigger FALLBACKTORELAY if attempt to connect to all CMS servers fail.
-// Fix saving part lines in adif log and Winlink Session reporting
-// Add port specific CTEXT
-// Add FRMR monitoring to UZ7HO driver
-// Add audio input switching for IC7610
-// Include Rigcontrol Support for IC-F8101E
-// Process any response to KISS command
-// Fix NODE ADD command
-// Add noUpdate flag to AXIP MAP
-// Fix clearing NOFALLBACK flag in Telnet Server
-// Allow connects to RMS Relay running on another host
-// Allow use of Power setting in Rigcontol scan lines for Kenwood radios
-// Prevent problems caused by using "CMS" as a Node Alias
-// Include standard APRS Station pages in code
-// Fix VALIDCALLS processing in HF drivers
-// Send Netrom Link reports to Node Map
-// Add REALTELNET mode to Telnet Outward Connect
-// Fix using S (Stay) parameter on Telnet connects when using CMDPORT and C HOST
-// Add Default frequency to rigcontrol to set a freq/mode to return to after a connection
-// Fix long (> 60 seconds) scan intervals
-// Improved debugging of stuck semaphores
-// Fix potential securiby bug in BPQ Web server
-// Send Chat Updates to chatupdate.g8bpq.net port 81
-// Add ReportRelayTraffic to Telnet config to send WL2K traffic reports for connections to RELAY
-// Add experimental Mode reporting
-// Add SendTandRtoRelay param to SCS Pactor, ARDOP and VARA drivers to divert calls to CMS for -T and -R to RELAY
-// Add UPNP Support
-
-// Version 6.0.23.1 June 2022
-
-// Add option to control which applcalls are enabled in VARA
-// Add support for rtl_udp to Rig Control
-// Fix Telnet Auto Conneect to Application when using TermTCP or Web Terminal
-// Allow setting css styles for Web Terminal
-// And Kill TNC and Kill and Restart TNC commands to Web Driver Windows
-// More flexible RigControl for split frequency operation, eg for QO100
-// Increase stack size for ProcessHTMLMessage (.11)
-// Fix HTML Content-Type on images (.12)
-// Add AIS and ADSB Support (.13)
-// Compress web pages (.14)
-// Change minidump routine and close after program error (.15)
-// Add RMS Relay SYNC Mode (.17)
-// Changes for compatibility with Winlink Hybrid
-// Add Rigcontrol CMD feature to Yaesu code (21)
-// More diagnostic code
-// Trap potential buffer overrun in ax/tcp code
-// Fix possible hang in UZ7HO driver if connect takes a long time to succeed or fail
-// Add FLRIG as backend for RigControl (.24)
-// Fix bug in compressing some management web pages
-// Fix bugs in AGW Emulator (.25)
-// Add more PTT_Sets_Freq options for split frequency working (.26)
-// Allow RIGCONTROL using Radio Number (Rnn) as well as Port (.26)
-// Fix Telnet negotiation and backspace processing (.29)
-// Fix VARA Mode change when scanning (.30)
-// Add Web Mgmt Log Display (.33)
-// Fix crash when connecting to RELAY when CMS=0 (.36)
-// Send OK to user for manual freq changes with hamlib or flrig
-// Fix Rigcontrol leaving port disabled when using an empty timeband
-// Fix processing of backspace in Telnet character processing (.40)
-// Increase max size of connect script
-// Fix HAMLIB Slave Thread control
-// Add processing of VARA mode responses and display of VARA Mode (41)
-// Fix crash when VARA session aborted on LinBPQ (43)
-// Fix handling port selector (2:call or p2 call) on SCS PTC packet ports (44)
-// Include APRS Map web page
-// Add Enable/Disable to KAMPACTOR scan control (use P0 or P1) (45)
-// Add Basic DRATS interface (46)
-// Fix MYCALLS on VARA (49)
-// Add FreeData driver (51)
-// Add additonal Rigcontrol options for QO100 (51)
-// Set Content-Type: application/pdf for pdf files downloaded via web interface (51)
-// Fix sending large compressed web messages (52)
-// Fix freq display when using flrig or hamlib backends to rigcontrol
-// Change VARA Driver to send ABORT when Session Time limit expires
-// Add Chat Log to Web Logs display
-// Fix possible buffer loss in RigControl
-// Allow hosts on local lan to be treated as secure
-// Improve validation of data sent to Winlink SessionAdd API call
-// Add support for FreeDATA modem.
-// Add GetLOC API Call
-// Change Leaflet link in aprs map.
-// Add Connect Log (64)
-// Fix crash when Resolve CMS Servers returns ipv6 addresses
-// Fix Reporting P4 sessions to Winlink (68)
-// Add support for FreeBSD (68)
-// Fix Rigcontrol PTCPORT (69)
-// Set TNC Emulator sessions as secure (72)
-// Fix not always detecting loss of FLRIG (73)
-// Add ? and * wildcards to NODES command (74)
-// Add Port RADIO config parameter (74)
-
-// Version 6.0.24.1 August 2023
-
-// Apply NODES command wildcard to alias as well a call (2)
-// Add STOPPORT/STARTPORT to VARA Driver (2)
-// Add bandwidth setting to FLRIG interface. (2)
-// Fix N VIA (3)
-// Fix NODE ADD and NODE DEL (4)
-// Improvements to FLRIG Rigcontrol backend (6, 7)
-// Fix UZ7HO Window Title Update
-// Reject L2 calls with a blank from call (8)
-// Update WinRPR Window header with BPQ Port Description (8)
-// Fix error in blank call code (9)
-// Change web buttons to white on black when pressed (10)
-// Fix Port CTEXT paclen on Tracker and WinRPR drivers (11)
-// Add RADIO PTT command for testing PTT (11)
-// Fix using APPLCALLs on SCSTracker RP call (12)
-// Add Rigcntol Web Page (13)
-// Fix scan bandwidth change with ARDOPOFDM (13)
-// Fix setting Min Pactor Level in SCSPactor (13)
-// Fix length of commands sent via CMD_TO_APPL flag (14)
-// Add filter by quality option to N display (15)
-// Fix VARA Mode reporting to WL2K (16)
-// Add FLRIG POWER and TUNE commands (18)
-// Fix crash when processing "C " without a call in UZ7HO, FLDIGI or MULTIPSK drivers (19)
-// FLDIGI improvements (19)
-// Fix hang at start if Telnet port Number > Number of Telnet Streams (20)
-// Fix processing C command if first port driver is SCSPACTROR (20)
-// Fix crash in UZ7HO driver if bad raw frame received (21)
-// Fix using FLARQ chat mode with FLDIGI ddriover (22)
-// Fix to KISSHF driver (23)
-// Fix for application buffer loss (24)
-// Add Web Sockets auto-refresh option for Webmail index page (25)
-// Fix FREEDATA driver for compatibility with FreeData TNC version 0.6.4-alpha.3 (25)
-// Add SmartID for bridged frames - Send ID only if packets sent recently (26)
-// Add option to save and restore received APRS messages (27)
-// Add mechanism to run a user program on certain events (27)
-// If BeacontoIS is zero don't Gate any of our messages received locally to APRS-IS (28)
-// Add Node Help command (28)
-// Add APRS Igate RXOnly option (29)
-// Fix RMC message handling with prefixes other than GP (29)
-// Add GPSD support for APRS (30)
-// Attempt to fix Tracker/WinRPR reconnect code (30)
-// Changes to FreeDATA - Don't use deamon and add txlevel and send text commands (31)
-// Fix interactive commands in tracker driver (33)
-// Fix SESSIONTIMELIMIT processing
-// Add STOPPORT/STARTPORT for UZ7HO driver
-// Fix processing of extended QtSM 'g' frame (36)
-// Allow setting just freq on Yaseu rigs (37)
-// Enable KISSHF driver on Linux (40)
-// Allow AISHOST and ADSBHOST to be a name as well as an address (41)
-// Fix Interlock of incoming UZ7HO connections (41)
-// Disable VARA Actions menu if not sysop (41)
-// Fix Port CTEXT on UZ7HO B C or D channels (42)
-// Fix repeated trigger of SessionTimeLimit (43)
-// Fix posible memory corruption in UpateMH (44)
-// Add PHG to APRS beacons (45)
-// Dont send DM to stations in exclude list(45)
-// Improvements to RMS Relay SYNC Mode (46)
-// Check L4 connects against EXCLUDE list (47)
-// Add vaidation of LOC in WL2K Session Reports (49)
-// Change gpsd support for compatibility with Share Gps (50)
-// Switch APRS Map to my Tiles (52)
-// Fix using ; in UNPROTO Mode messages (52)
-// Use sha1 code from https://www.packetizer.com/security/sha1/ instead of openssl (53)
-// Fix TNC Emulator Monitoring (53)
-// Fix attach and connect on Telnet port bug introduced in .55 (56)
-// Fix stopping WinRPR TNC and Start/Stop UZ7HO TNCX on Linux (57)
-// Fix stack size in beginthread for MAC (58)
-// Add NETROM over VARA (60)
-// Add Disconnect Script (64)
-// Add node commands to set UZ7HO modem mode and freq (64)
-// Trap empty NODECALL or NETROMCALL(65)
-// Trap NODES messages with empty From Call (65)
-// Add RigControl for SDRConsole (66)
-// Fix FLRig crash (66)
-// Fix VARA disconnect handling (67)
-// Support 64 ports (69)
-// Fix Node commands for setting UZ7HO Modem (70)
-// Fix processing SABM on an existing session (71)
-// Extend KISS Node command to send more than one parameter byte (72)
-// Add G7TAJ's code to record activity of HF ports for stats display (72)
-// Add option to send KISS command to TNC on startup (73)
-// Fix Bug in DED Emulator Monitor code (74)
-// Add Filters to DED Monitor code (75)
-// Detect loss of DED application (76)
-// Fix connects to Application Alias with UZ7HO Driver (76)
-// Fix Interlock of ports on same UZ7HO modem. (76)
-// Add extended Ports command (77)
-// Fix crash in Linbpq when stdout is redirected to /dev/tty? and stdin ia redirected (78)
-// Fix Web Terminal (80)
-// Trap ENCRYPTION message from VARA (81)
-// Fix processing of the Winlink API /account/exists response (82)
-// Fix sending CTEXT to L4 connects to Node when FULL_CTEXT is not set
-
-// Version 6.0.25.?
-
-// Fix 64 bit compatibility problems in SCSTracker and UZ7HO drivers
-// Add Chat PACLEN config (5)
-// Fix NC to Application Call (6)
-// Fix INP3 L3RTT messages on Linux and correct RTT calculation (9)
-// Get Beacon config from config file on Windows (9)
-// fix processing DED TNC Emulator M command with space between M and params (10)
-// Fix sending UI frames on SCSPACTOR (11)
-// Dont allow ports that can't set digi'ed bit in callsigns to digipeat. (11)
-// Add SDRAngel rig control (11)
-// Add option to specify config and data directories on linbpq (12)
-// Allow zero resptime (send RR immediately) (13)
-// Make sure CMD bit is set on UI frames
-// Add setting Modem Flags in QtSM AGW mode
-// If FT847 om PTC Port send a "Cat On" command (17)
-// Fix some 63 port bugs in RigCOntrol (17)
-// Fix 63 port bug in Bridging (18)
-// Add FTDX10 Rigcontrol (19)
-// Fix 64 bit bug in displaying INP3 Messages (20)
-// Improve restart of WinRPR TNC on remote host (21)
-// Fix some Rigcontrol issues with empty timebands (22)
-// Fix 64 bit bug in processing INP3 Messages (22)
-// First pass at api (24)
-// Send OK in response to Rigcontrol CMD (24)
-// Disable CTS check in WriteComBlock (26)
-// Improvments to reporting to M0LTE Map (26)
-// IPGateway fix from github user isavitsky (27)
-// Fix possible crash in SCSPactor PTCPORT code (29)
-// Add NodeAPI call sendLinks and remove get from other calls (32)
-// Improve validation of Web Beacon Config (33)
-// Support SNMP via host ip stack as well as IPGateway (34)
-// Switch APRS Map to OSM tile servers (36)
-// Fix potential buffer overflow in Telnet login (36)
-// Allow longer serial device names (37)
-// Fix ICF8101 Mode setting (37)
-// Kill link if we are getting repeated RR(F) after timeout
-// (Indicating other station is seeing our RR(P) but not the resent I frame) (40)
-// Change default of SECURETELNET to 1 (41)
-// Add optional ATTACH time limit for ARDOP (42)
-// Fix buffer overflow risk in HTTP Terminal(42)
-// Fix KISSHF Interlock (43)
-// Support other than channel A on HFKISS (43)
-// Support additional port info reporting for M0LTE Map (44)
-// Allow interlocking of KISS and Session mode ports (eg ARDOP and VARA) (45)
-// Add ARDOP UI Packets to MH (45)
-// Add support for Qtsm Mgmt Interface (45)
-// NodeAPI improvements (46)
-// Add MQTT Interface (46)
-// Fix buffer leak in ARDOP code(46)
-// Fix possible crash if MQTT not in use (47)
-// Add optional ATTACH time limit for VARA (48)
-// API format fixes (48)
-// AGWAPI Add protection against accidental connects from a non-agw application (50)
-// Save MH and NODES every hour (51)
-// Fix handling long unix device names (now max 250 bytes) (52)
-// Fix error reporting in api update (53)
-// Coding changes to remove some compiler warnings (53, 54)
-// Add MQTT reporting of Mail Events (54)
-// Fix beaconong on KISSHF ports (55)
-// Fix MailAPI msgs endpoint
-// Attempt to fix NC going to wrong application. (57)
-// Improve ARDOP end of session code (58)
-// Run M0LTE Map reporting in a separate thread (59/60)
-// Add RHP support for WhatsPac (59)
-// Add timestamps to LIS monitor (60)
-// Fix problem with L4 frames being delivered out of sequence (60)
-// Add Compression of Netrom connections (62)
-// Improve handling of Locked Routes (62)
-// Add L4 RESET (Paula G8PZT's extension to NETROM)
-// Fix problem using SENDRAW from BPQMail (63)
-// Fix compatibility with latest ardopcf (64)
-// Fix bug in RHP socket timeout code (65)
-// Fix L4 RTT (66)
-// Fix RigConrol with Chanxx but no other settings (66)
-// Add option to compress L2 frames (67)
-// Sort Routes displays (67)
-// Fix Ardop session premature close (70)
-// Add timestamps to log entries in Web Driver windows (70)
-// Generate stack backtrace if SIGSEGV or SIGABRT occur (Linux) (70)
-// Remove some debug logging from L2 code (70)
-// Fix compiling LinBPQ with nomqtt option (70)
-// Improve handling of binary data in RHP interface (70)
-// Fix sending KISS commands to multiport or multidropped TNCs (70)
-// Add MHUV and MHLV commands (Verbose listing with timestamps in clock time) (70)
-
-#define CKernel
-
-#include "Versions.h"
-
-#define _CRT_SECURE_NO_DEPRECATE
-
-#pragma data_seg("_BPQDATA")
-
-#include "time.h"
-#include "stdio.h"
-#include
-
-#include "compatbits.h"
-#include "AsmStrucs.h"
-
-#include "SHELLAPI.H"
-#include "kernelresource.h"
-
-#include
-#include
-#include "BPQTermMDI.h"
-
-#include "GetVersion.h"
-
-#define DllImport __declspec( dllimport )
-
-#define CheckGuardZone() _CheckGuardZone(__FILE__, __LINE__)
-void _CheckGuardZone(char * File, int Line);
-
-#define CHECKLOADED 0
-#define SETAPPLFLAGS 1
-#define SENDBPQFRAME 2
-#define GETBPQFRAME 3
-#define GETSTREAMSTATUS 4
-#define CLEARSTREAMSTATUS 5
-#define BPQCONDIS 6
-#define GETBUFFERSTATUS 7
-#define GETCONNECTIONINFO 8
-#define BPQRETURN 9 // GETCALLS
-//#define RAWTX 10 //IE KISS TYPE DATA
-#define GETRAWFRAME 11
-#define UPDATESWITCH 12
-#define BPQALLOC 13
-//#define SENDNETFRAME 14
-#define GETTIME 15
-
-extern short NUMBEROFPORTS;
-extern long PORTENTRYLEN;
-extern long LINKTABLELEN;
-extern struct PORTCONTROL * PORTTABLE;
-extern void * FREE_Q;
-extern UINT APPL_Q; // Queue of frames for APRS Appl
-
-extern TRANSPORTENTRY * L4TABLE;
-extern UCHAR NEXTID;
-extern DWORD MAXCIRCUITS;
-extern DWORD L4DEFAULTWINDOW;
-extern DWORD L4T1;
-extern APPLCALLS APPLCALLTABLE[];
-extern char * APPLS;
-
-extern struct WL2KInfo * WL2KReports;
-
-extern int NUMBEROFTNCPORTS;
-
-
-void * VCOMExtInit(struct PORTCONTROL * PortEntry);
-void * AXIPExtInit(struct PORTCONTROL * PortEntry);
-void * SCSExtInit(struct PORTCONTROL * PortEntry);
-void * AEAExtInit(struct PORTCONTROL * PortEntry);
-void * KAMExtInit(struct PORTCONTROL * PortEntry);
-void * HALExtInit(struct PORTCONTROL * PortEntry);
-void * ETHERExtInit(struct PORTCONTROL * PortEntry);
-void * AGWExtInit(struct PORTCONTROL * PortEntry);
-void * WinmorExtInit(EXTPORTDATA * PortEntry);
-void * TelnetExtInit(EXTPORTDATA * PortEntry);
-//void * SoundModemExtInit(EXTPORTDATA * PortEntry);
-void * TrackerExtInit(EXTPORTDATA * PortEntry);
-void * TrackerMExtInit(EXTPORTDATA * PortEntry);
-void * V4ExtInit(EXTPORTDATA * PortEntry);
-void * UZ7HOExtInit(EXTPORTDATA * PortEntry);
-void * MPSKExtInit(EXTPORTDATA * PortEntry);
-void * FLDigiExtInit(EXTPORTDATA * PortEntry);
-void * UIARQExtInit(EXTPORTDATA * PortEntry);
-void * SerialExtInit(EXTPORTDATA * PortEntry);
-void * ARDOPExtInit(EXTPORTDATA * PortEntry);
-void * VARAExtInit(EXTPORTDATA * PortEntry);
-void * KISSHFExtInit(EXTPORTDATA * PortEntry);
-void * WinRPRExtInit(EXTPORTDATA * PortEntry);
-void * HSMODEMExtInit(EXTPORTDATA * PortEntry);
-void * FreeDataExtInit(EXTPORTDATA * PortEntry);
-void * SIXPACKExtInit(EXTPORTDATA * PortEntry);
-
-extern char * ConfigBuffer; // Config Area
-VOID REMOVENODE(dest_list * DEST);
-DllExport int ConvFromAX25(unsigned char * incall,unsigned char * outcall);
-DllExport int ConvToAX25(unsigned char * incall,unsigned char * outcall);
-VOID GetUIConfig();
-VOID ADIFWriteFreqList();
-void SaveAIS();
-void initAIS();
-void initADSB();
-
-extern BOOL ADIFLogEnabled;
-
-int CloseOnError = 0;
-
-char UIClassName[]="UIMAINWINDOW"; // the main window class name
-
-HWND UIhWnd;
-
-extern char AUTOSAVE;
-extern char AUTOSAVEMH;
-
-extern char MYNODECALL; // 10 chars,not null terminated
-
-extern QCOUNT;
-extern BPQVECSTRUC BPQHOSTVECTOR[];
-#define BPQHOSTSTREAMS 64
-#define IPHOSTVECTOR BPQHOSTVECTOR[BPQHOSTSTREAMS + 3]
-
-extern char * CONFIGFILENAME;
-
-DllExport BPQVECSTRUC * BPQHOSTVECPTR;
-
-extern int DATABASESTART;
-
-extern struct ROUTE * NEIGHBOURS;
-extern int ROUTE_LEN;
-extern int MAXNEIGHBOURS;
-
-extern struct DEST_LIST * DESTS; // NODE LIST
-extern int DEST_LIST_LEN;
-extern int MAXDESTS; // MAX NODES IN SYSTEM
-
-extern struct _LINKTABLE * LINKS;
-extern int LINK_TABLE_LEN;
-extern int MAXLINKS;
-
-extern double LatFromLOC;
-extern double LonFromLOC;
-
-
-extern int BPQHOSTAPI();
-extern int INITIALISEPORTS();
-extern int TIMERINTERRUPT();
-extern int MONDECODE();
-extern int BPQMONOPTIONS();
-extern char PWTEXT[];
-extern char PWLen;
-
-extern int FINDFREEDESTINATION();
-extern int RAWTX();
-extern int RELBUFF();
-extern int SENDNETFRAME();
-extern char MYCALL[]; // 7 chars, ax.25 format
-
-extern HWND hIPResWnd;
-extern BOOL IPMinimized;
-
-extern int NODESINPROGRESS;
-extern VOID * CURRENTNODE;
-
-
-BOOL Start();
-
-VOID SaveWindowPos(int port);
-VOID SaveAXIPWindowPos(int port);
-VOID SetupRTFHddr();
-DllExport VOID APIENTRY CreateNewTrayIcon();
-int DoReceivedData(int Stream);
-int DoStateChange(int Stream);
-int DoMonData(int Stream);
-struct ConsoleInfo * CreateChildWindow(int Stream, BOOL DuringInit);
-CloseHostSessions();
-SaveHostSessions();
-VOID SaveBPQ32Windows();
-VOID CloseDriverWindow(int port);
-VOID CheckWL2KReportTimer();
-VOID SetApplPorts();
-VOID WriteMiniDump();
-VOID FindLostBuffers();
-BOOL InitializeTNCEmulator();
-VOID TNCTimer();
-char * strlop(char * buf, char delim);
-
-DllExport int APIENTRY Get_APPLMASK(int Stream);
-DllExport int APIENTRY GetStreamPID(int Stream);
-DllExport int APIENTRY GetApplFlags(int Stream);
-DllExport int APIENTRY GetApplNum(int Stream);
-DllExport BOOL APIENTRY GetAllocationState(int Stream);
-DllExport int APIENTRY GetMsg(int stream, char * msg, int * len, int * count );
-DllExport int APIENTRY RXCount(int Stream);
-DllExport int APIENTRY TXCount(int Stream);
-DllExport int APIENTRY MONCount(int Stream);
-DllExport int APIENTRY GetCallsign(int stream, char * callsign);
-DllExport VOID APIENTRY RelBuff(VOID * Msg);
-void SaveMH();
-void DRATSPoll();
-
-#define C_Q_ADD(s, b) _C_Q_ADD(s, b, __FILE__, __LINE__);
-int _C_Q_ADD(VOID *PQ, VOID *PBUFF, char * File, int Line);
-
-VOID SetWindowTextSupport();
-int WritetoConsoleSupport(char * buff);
-VOID PMClose();
-VOID MySetWindowText(HWND hWnd, char * Msg);
-BOOL CreateMonitorWindow(char * MonSize);
-VOID FormatTime3(char * Time, time_t cTime);
-
-char EXCEPTMSG[80] = "";
-
-char SIGNONMSG[128] = "";
-char SESSIONHDDR[80] = "";
-int SESSHDDRLEN = 0;
-
-BOOL IncludesMail = FALSE;
-BOOL IncludesChat = FALSE; // Set if pgram is running - used for Web Page Index
-
-
-char WL2KCall[10];
-char WL2KLoc[7];
-
-extern char LOCATOR[]; // Locator for Reporting - may be Maidenhead or LAT:LON
-extern char MAPCOMMENT[]; // Locator for Reporting - may be Maidenhead or LAT:LON
-extern char LOC[7]; // Maidenhead Locator for Reporting
-extern char ReportDest[7];
-
-extern UCHAR ConfigDirectory[260];
-
-extern uint64_t timeLoadedMS;
-
-VOID __cdecl Debugprintf(const char * format, ...);
-VOID __cdecl Consoleprintf(const char * format, ...);
-
-DllExport int APIENTRY CloseBPQ32();
-DllExport char * APIENTRY GetLOC();
-DllExport int APIENTRY SessionControl(int stream, int command, int param);
-
-int DoRefreshWebMailIndex();
-
-BOOL APIENTRY Init_IP();
-BOOL APIENTRY Poll_IP();
-
-BOOL APIENTRY Init_PM();
-BOOL APIENTRY Poll_PM();
-
-BOOL APIENTRY Init_APRS();
-BOOL APIENTRY Poll_APRS();
-VOID HTTPTimer();
-
-BOOL APIENTRY Rig_Init();
-BOOL APIENTRY Rig_Close();
-BOOL Rig_Poll();
-
-VOID IPClose();
-VOID APRSClose();
-VOID CloseTNCEmulator();
-
-VOID Poll_AGW();
-void RHPPoll();
-BOOL AGWAPIInit();
-int AGWAPITerminate();
-
-int * Flag = (int *)&Flag; // for Dump Analysis
-int MAJORVERSION=4;
-int MINORVERSION=9;
-
-struct SEM Semaphore = {0, 0, 0, 0};
-struct SEM APISemaphore = {0, 0, 0, 0};
-int SemHeldByAPI = 0;
-int LastSemGets = 0;
-UINT Sem_eax = 0;
-UINT Sem_ebx = 0;
-UINT Sem_ecx = 0;
-UINT Sem_edx = 0;
-UINT Sem_esi = 0;
-UINT Sem_edi = 0;
-
-
-#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__)
-void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line);
-void FreeSemaphore(struct SEM * Semaphore);
-
-DllExport void * BPQHOSTAPIPTR = &BPQHOSTAPI;
-//DllExport long MONDECODEPTR = (long)&MONDECODE;
-
-extern UCHAR BPQDirectory[];
-extern UCHAR LogDirectory[];
-extern UCHAR BPQProgramDirectory[];
-
-static char BPQWinMsg[] = "BPQWindowMessage";
-
-static char ClassName[] = "BPQMAINWINDOW";
-
-HKEY REGTREE = HKEY_CURRENT_USER;
-char REGTREETEXT[100] = "HKEY_CURRENT_USER";
-
-UINT BPQMsg=0;
-
-#define MAXLINELEN 120
-#define MAXSCREENLEN 50
-
-#define BGCOLOUR RGB(236,233,216)
-
-HBRUSH bgBrush = NULL;
-
-//int LINELEN=120;
-//int SCREENLEN=50;
-
-//char Screen[MAXLINELEN*MAXSCREENLEN]={0};
-
-//int lineno=0;
-//int col=0;
-
-#define REPORTINTERVAL 15 * 549; // Magic Ticks Per Minute for PC's nominal 100 ms timer
-int ReportTimer = 0;
-
-HANDLE OpenConfigFile(char * file);
-
-VOID SetupBPQDirectory();
-VOID SendLocation();
-
-//uintptr_t _beginthread(void(*start_address)(), unsigned stack_size, int arglist);
-
-#define TRAY_ICON_ID 1 // ID number for the Notify Icon
-#define MY_TRAY_ICON_MESSAGE WM_APP // the message ID sent to our window
-
-NOTIFYICONDATA niData;
-
-int SetupConsoleWindow();
-
-BOOL StartMinimized=FALSE;
-BOOL MinimizetoTray=TRUE;
-
-BOOL StatusMinimized = FALSE;
-BOOL ConsoleMinimized = FALSE;
-
-HMENU trayMenu=0;
-
-HWND hConsWnd = NULL, hWndCons = NULL, hWndBG = NULL, ClientWnd = NULL, FrameWnd = NULL, StatusWnd = NULL;
-
-BOOL FrameMaximized = FALSE;
-
-BOOL IGateEnabled = TRUE;
-extern int ISDelayTimer; // Time before trying to reopen APRS-IS link
-extern int ISPort;
-
-UINT * WINMORTraceQ = NULL;
-UINT * SetWindowTextQ = NULL;
-
-static RECT Rect = {100,100,400,400}; // Console Window Position
-RECT FRect = {100,100,800,600}; // Frame
-static RECT StatusRect = {100,100,850,500}; // Status Window
-
-DllExport int APIENTRY DumpSystem();
-DllExport int APIENTRY SaveNodes ();
-DllExport int APIENTRY ClearNodes ();
-DllExport int APIENTRY SetupTrayIcon();
-
-#define Q_REM(s) _Q_REM(s, __FILE__, __LINE__)
-
-VOID * _Q_REM(VOID *Q, char * File, int Line);
-
-UINT ReleaseBuffer(UINT *BUFF);
-
-
-VOID CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime );
-
-DllExport int APIENTRY DeallocateStream(int stream);
-
-int VECTORLENGTH = sizeof (struct _BPQVECSTRUC);
-
-int FirstEntry = 1;
-BOOL CloseLast = TRUE; // If the user started BPQ32.exe, don't close it when other programs close
-BOOL Closing = FALSE; // Set if Close All called - prevents respawning bpq32.exe
-
-BOOL BPQ32_EXE; // Set if Process is running BPQ32.exe. Not initialised.
- // Used to Kill surplus BPQ32.exe processes
-
-DWORD Our_PID; // Our Process ID - local variable
-
-void * InitDone = 0;
-int FirstInitDone = 0;
-int PerlReinit = 0;
-UINT_PTR TimerHandle = 0;
-UINT_PTR SessHandle = 0;
-
-BOOL EventsEnabled = 0;
-
-unsigned int TimerInst = 0xffffffff;
-
-HANDLE hInstance = 0;
-
-int AttachedProcesses = 0;
-int AttachingProcess = 0;
-HINSTANCE hIPModule = 0;
-HINSTANCE hRigModule = 0;
-
-BOOL ReconfigFlag = FALSE;
-BOOL RigReconfigFlag = FALSE;
-BOOL APRSReconfigFlag = FALSE;
-BOOL CloseAllNeeded = FALSE;
-BOOL NeedWebMailRefresh = FALSE;
-
-int AttachedPIDList[100] = {0};
-
-HWND hWndArray[100] = {0};
-int PIDArray[100] = {0};
-char PopupText[30][100] = {""};
-
-// Next 3 should be uninitialised so they are local to each process
-
-UCHAR MCOM;
-UCHAR MTX; // Top bit indicates use local time
-uint64_t MMASK;
-UCHAR MUIONLY;
-
-UCHAR AuthorisedProgram; // Local Variable. Set if Program is on secure list
-
-char pgm[256]; // Uninitialised so per process
-
-HANDLE Mutex;
-
-BOOL PartLine = FALSE;
-int pindex = 0;
-DWORD * WritetoConsoleQ;
-
-
-LARGE_INTEGER lpFrequency = {0};
-LARGE_INTEGER lastRunTime;
-LARGE_INTEGER currentTime;
-
-int ticksPerMillisec;
-int interval;
-
-
-VOID CALLBACK SetupTermSessions(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime);
-
-
-TIMERPROC lpTimerFunc = (TIMERPROC) TimerProc;
-TIMERPROC lpSetupTermSessions = (TIMERPROC) SetupTermSessions;
-
-
-BOOL ProcessConfig();
-VOID FreeConfig();
-
-DllExport int APIENTRY WritetoConsole(char * buff);
-
-BOOLEAN CheckifBPQ32isLoaded();
-BOOLEAN StartBPQ32();
-DllExport VOID APIENTRY Send_AX(VOID * Block, DWORD len, UCHAR Port);
-BOOL LoadIPDriver();
-BOOL Send_IP(VOID * Block, DWORD len);
-VOID CheckforLostProcesses();
-BOOL LoadRigDriver();
-VOID SaveConfig();
-VOID CreateRegBackup();
-VOID ResolveUpdateThread();
-VOID OpenReportingSockets();
-DllExport VOID APIENTRY CloseAllPrograms();
-DllExport BOOL APIENTRY SaveReg(char * KeyIn, HANDLE hFile);
-int upnpClose();
-
-BOOL IPActive = FALSE;
-extern BOOL IPRequired;
-BOOL PMActive = FALSE;
-extern BOOL PMRequired;
-BOOL RigRequired = TRUE;
-BOOL RigActive = FALSE;
-BOOL APRSActive = FALSE;
-BOOL AGWActive = FALSE;
-BOOL needAIS = FALSE;
-int needADSB = 0;
-
-extern int AGWPort;
-
-Tell_Sessions();
-
-
-typedef int (WINAPI FAR *FARPROCX)();
-
-FARPROCX CreateToolHelp32SnapShotPtr;
-FARPROCX Process32Firstptr;
-FARPROCX Process32Nextptr;
-
-void LoadToolHelperRoutines()
-{
- HINSTANCE ExtDriver=0;
- int err;
- char msg[100];
-
- ExtDriver=LoadLibrary("kernel32.dll");
-
- if (ExtDriver == NULL)
- {
- err=GetLastError();
- sprintf(msg,"BPQ32 Error loading kernel32.dll - Error code %d\n", err);
- OutputDebugString(msg);
- return;
- }
-
- CreateToolHelp32SnapShotPtr = (FARPROCX)GetProcAddress(ExtDriver,"CreateToolhelp32Snapshot");
- Process32Firstptr = (FARPROCX)GetProcAddress(ExtDriver,"Process32First");
- Process32Nextptr = (FARPROCX)GetProcAddress(ExtDriver,"Process32Next");
-
- if (CreateToolHelp32SnapShotPtr == 0)
- {
- err=GetLastError();
- sprintf(msg,"BPQ32 Error getting CreateToolhelp32Snapshot entry point - Error code %d\n", err);
- OutputDebugString(msg);
- return;
- }
-}
-
-BOOL GetProcess(int ProcessID, char * Program)
-{
- HANDLE hProcessSnap;
- PROCESSENTRY32 pe32;
- int p;
-
- if (CreateToolHelp32SnapShotPtr==0)
- {
- return (TRUE); // Routine not available
- }
- // Take a snapshot of all processes in the system.
- hProcessSnap = (HANDLE)CreateToolHelp32SnapShotPtr(TH32CS_SNAPPROCESS, 0);
- if( hProcessSnap == INVALID_HANDLE_VALUE )
- {
- OutputDebugString( "CreateToolhelp32Snapshot (of processes) Failed\n" );
- return( FALSE );
- }
-
- // Set the size of the structure before using it.
- pe32.dwSize = sizeof( PROCESSENTRY32 );
-
- // Retrieve information about the first process,
- // and exit if unsuccessful
- if( !Process32Firstptr( hProcessSnap, &pe32 ) )
- {
- OutputDebugString( "Process32First Failed\n" ); // Show cause of failure
- CloseHandle( hProcessSnap ); // Must clean up the snapshot object!
- return( FALSE );
- }
-
- // Now walk the snapshot of processes, and
- // display information about each process in turn
- do
- {
- if (ProcessID==pe32.th32ProcessID)
- {
- // if running on 98, program contains the full path - remove it
-
- for (p = (int)strlen(pe32.szExeFile); p >= 0; p--)
- {
- if (pe32.szExeFile[p]=='\\')
- {
- break;
- }
- }
- p++;
-
- sprintf(Program,"%s", &pe32.szExeFile[p]);
- CloseHandle( hProcessSnap );
- return( TRUE );
- }
-
- } while( Process32Nextptr( hProcessSnap, &pe32 ) );
-
-
- sprintf(Program,"PID %d Not Found", ProcessID);
- CloseHandle( hProcessSnap );
- return(FALSE);
-}
-
-BOOL IsProcess(int ProcessID)
-{
- // Check that Process exists
-
- HANDLE hProcessSnap;
- PROCESSENTRY32 pe32;
-
- if (CreateToolHelp32SnapShotPtr==0) return (TRUE); // Routine not available
-
- hProcessSnap = (HANDLE)CreateToolHelp32SnapShotPtr(TH32CS_SNAPPROCESS, 0);
-
- if( hProcessSnap == INVALID_HANDLE_VALUE )
- {
- OutputDebugString( "CreateToolhelp32Snapshot (of processes) Failed\n" );
- return(TRUE); // Don't know, so assume ok
- }
-
- pe32.dwSize = sizeof( PROCESSENTRY32 );
-
- if( !Process32Firstptr( hProcessSnap, &pe32 ) )
- {
- OutputDebugString( "Process32First Failed\n" ); // Show cause of failure
- CloseHandle( hProcessSnap ); // Must clean up the snapshot object!
- return(TRUE); // Don't know, so assume ok
- }
-
- do
- {
- if (ProcessID==pe32.th32ProcessID)
- {
- CloseHandle( hProcessSnap );
- return( TRUE );
- }
-
- } while( Process32Nextptr( hProcessSnap, &pe32 ) );
-
- CloseHandle( hProcessSnap );
- return(FALSE);
-}
-
-#include "DbgHelp.h"
-
-VOID MonitorThread(int x)
-{
- // Thread to detect killed processes. Runs in process owning timer.
-
- // Obviously can't detect loss of timer owning thread!
-
- do
- {
- if (Semaphore.Gets == LastSemGets && Semaphore.Flag)
- {
- // It is stuck - try to release
-
- Debugprintf ("Semaphore locked - Process ID = %d, Held By %d from %s Line %d",
- Semaphore.SemProcessID, SemHeldByAPI, Semaphore.File, Semaphore.Line);
-
- // Write a minidump
-
- WriteMiniDump();
-
- Semaphore.Flag = 0;
- }
-
- LastSemGets = Semaphore.Gets;
-
- Sleep(30000);
- CheckforLostProcesses();
-
- } while (TRUE);
-}
-
-VOID CheckforLostProcesses()
-{
- UCHAR buff[100];
- char Log[80];
- int i, n, ProcessID;
-
- for (n=0; n < AttachedProcesses; n++)
- {
- ProcessID=AttachedPIDList[n];
-
- if (!IsProcess(ProcessID))
- {
- // Process has died - Treat as a detach
-
- sprintf(Log,"BPQ32 Process %d Died\n", ProcessID);
- OutputDebugString(Log);
-
- // Remove Tray Icon Entry
-
- for( i = 0; i < 100; ++i )
- {
- if (PIDArray[i] == ProcessID)
- {
- hWndArray[i] = 0;
- sprintf(Log,"BPQ32 Removing Tray Item %s\n", PopupText[i]);
- OutputDebugString(Log);
- DeleteMenu(trayMenu,TRAYBASEID+i,MF_BYCOMMAND);
- }
- }
-
- // If process had the semaphore, release it
-
- if (Semaphore.Flag == 1 && ProcessID == Semaphore.SemProcessID)
- {
- OutputDebugString("BPQ32 Process was holding Semaphore - attempting recovery\r\n");
- Debugprintf("Last Sem Call %d %x %x %x %x %x %x", SemHeldByAPI,
- Sem_eax, Sem_ebx, Sem_ecx, Sem_edx, Sem_esi, Sem_edi);
-
- Semaphore.Flag = 0;
- SemHeldByAPI = 0;
- }
-
- for (i=1;i<65;i++)
- {
- if (BPQHOSTVECTOR[i-1].STREAMOWNER == AttachedPIDList[n])
- {
- DeallocateStream(i);
- }
- }
-
- if (TimerInst == ProcessID)
- {
- KillTimer(NULL,TimerHandle);
- TimerHandle=0;
- TimerInst=0xffffffff;
-// Tell_Sessions();
- OutputDebugString("BPQ32 Process was running timer \n");
-
- if (MinimizetoTray)
- Shell_NotifyIcon(NIM_DELETE,&niData);
-
-
- }
-
- // Remove this entry from PID List
-
- for (i=n; i< AttachedProcesses; i++)
- {
- AttachedPIDList[i]=AttachedPIDList[i+1];
- }
- AttachedProcesses--;
-
- sprintf(buff,"BPQ32 Lost Process - %d Process(es) Attached\n", AttachedProcesses);
- OutputDebugString(buff);
- }
- }
-}
-VOID MonitorTimerThread(int x)
-{
- // Thread to detect killed timer process. Runs in all other BPQ32 processes.
-
- do {
-
- Sleep(60000);
-
- if (TimerInst != 0xffffffff && !IsProcess(TimerInst))
- {
- // Timer owning Process has died - Force a new timer to be created
- // New timer thread will detect lost process and tidy up
-
- Debugprintf("BPQ32 Process %d with Timer died", TimerInst);
-
- // If process was holding the semaphore, release it
-
- if (Semaphore.Flag == 1 && TimerInst == Semaphore.SemProcessID)
- {
- OutputDebugString("BPQ32 Process was holding Semaphore - attempting recovery\r\n");
- Debugprintf("Last Sem Call %d %x %x %x %x %x %x", SemHeldByAPI,
- Sem_eax, Sem_ebx, Sem_ecx, Sem_edx, Sem_esi, Sem_edi);
- Semaphore.Flag = 0;
- SemHeldByAPI = 0;
- }
-
-// KillTimer(NULL,TimerHandle);
-// TimerHandle=0;
-// TimerInst=0xffffffff;
-// Tell_Sessions();
-
- CheckforLostProcesses(); // Normally only done in timer thread, which is now dead
-
- // Timer can only run in BPQ32.exe
-
- TimerInst=0xffffffff; // So we dont keep doing it
- TimerHandle = 0; // So new process attaches
-
- if (Closing == FALSE && AttachingProcess == FALSE)
- {
- OutputDebugString("BPQ32 Reloading BPQ32.exe\n");
- StartBPQ32();
- }
-
-// if (MinimizetoTray)
-// Shell_NotifyIcon(NIM_DELETE,&niData);
- }
-
- } while (TRUE);
-}
-
-VOID WritetoTraceSupport(struct TNCINFO * TNC, char * Msg, int Len);
-
-VOID TimerProcX();
-
-VOID CALLBACK TimerProc(
- HWND hwnd, // handle of window for timer messages
- UINT uMsg, // WM_TIMER message
- UINT idEvent, // timer identifier
- DWORD dwTime) // current system time
-{
- KillTimer(NULL,TimerHandle);
- TimerProcX();
- TimerHandle = SetTimer(NULL,0,100,lpTimerFunc);
-}
-VOID TimerProcX()
-{
- struct _EXCEPTION_POINTERS exinfo;
-
- //
- // Get semaphore before proceeeding
- //
-
- GetSemaphore(&Semaphore, 2);
-
- // Get time since last run
-
- QueryPerformanceCounter(¤tTime);
-
- interval = (int)(currentTime.QuadPart - lastRunTime.QuadPart) / ticksPerMillisec;
- lastRunTime.QuadPart = currentTime.QuadPart;
-
- //Debugprintf("%d", interval);
-
- // Process WINMORTraceQ
-
- while (WINMORTraceQ)
- {
- UINT * Buffer = Q_REM(&WINMORTraceQ);
- struct TNCINFO * TNC = (struct TNCINFO * )Buffer[1];
- int Len = Buffer[2];
- char * Msg = (char *)&Buffer[3];
-
- WritetoTraceSupport(TNC, Msg, Len);
- RelBuff(Buffer);
- }
-
- if (SetWindowTextQ)
- SetWindowTextSupport();
-
- while (WritetoConsoleQ)
- {
- UINT * Buffer = Q_REM(&WritetoConsoleQ);
- WritetoConsoleSupport((char *)&Buffer[2]);
- RelBuff(Buffer);
- }
-
- strcpy(EXCEPTMSG, "Timer ReconfigProcessing");
-
- __try
- {
-
- if (trayMenu == NULL)
- SetupTrayIcon();
-
- // See if reconfigure requested
-
- if (CloseAllNeeded)
- {
- CloseAllNeeded = FALSE;
- CloseAllPrograms();
- }
-
- if (ReconfigFlag)
- {
- // Only do it it timer owning process, or we could get in a real mess!
-
- if(TimerInst == GetCurrentProcessId())
- {
- int i;
- BPQVECSTRUC * HOSTVEC;
- PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
- WSADATA WsaData; // receives data from WSAStartup
- RECT cRect;
-
- ReconfigFlag = FALSE;
-
- SetupBPQDirectory();
-
- WritetoConsole("Reconfiguring ...\n\n");
- OutputDebugString("BPQ32 Reconfiguring ...\n");
-
- GetWindowRect(FrameWnd, &FRect);
-
- SaveWindowPos(70); // Rigcontrol
-
- for (i=0;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();
- PMClose();
- APRSClose();
- Rig_Close();
- CloseTNCEmulator();
- if (AGWActive)
- AGWAPITerminate();
-
- WSACleanup();
-
- WL2KReports = NULL;
-
- Sleep(2000);
-
- WSAStartup(MAKEWORD(2, 0), &WsaData);
-
- Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring);
- Consoleprintf(VerCopyright);
-
- Start();
-
- INITIALISEPORTS(); // Restart Ports
-
- SetApplPorts();
-
- FreeConfig();
-
- for (i=1; i<68; i++) // Include Telnet, APRS and IP Vec
- {
- HOSTVEC=&BPQHOSTVECTOR[i-1];
-
- HOSTVEC->HOSTTRACEQ=0; // Clear header (pool has been reinitialized
-
- if (HOSTVEC->HOSTSESSION !=0)
- {
- // Had a connection
-
- HOSTVEC->HOSTSESSION=0;
- HOSTVEC->HOSTFLAGS |=3; // Disconnected
-
- PostMessage(HOSTVEC->HOSTHANDLE, BPQMsg, i, 4);
- }
- }
-
- // Free the APRS Appl Q
-
- APPL_Q = 0;
-
- OpenReportingSockets();
-
- WritetoConsole("\n\nReconfiguration Complete\n");
-
- if (IPRequired) IPActive = Init_IP();
- if (PMRequired) PMActive = Init_PM();
-
- APRSActive = Init_APRS();
-
- if (ISPort == 0)
- IGateEnabled = 0;
-
- CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled);
-
- GetClientRect(hConsWnd, &cRect);
- MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
- if (APRSActive)
- MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
- else
- {
- ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE);
- MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
- }
- InvalidateRect(hConsWnd, NULL, TRUE);
-
- RigActive = Rig_Init();
-
- if (NUMBEROFTNCPORTS)
- {
- FreeSemaphore(&Semaphore);
- InitializeTNCEmulator();
- GetSemaphore(&Semaphore, 0);
- }
-
- FreeSemaphore(&Semaphore);
- AGWActive = AGWAPIInit();
- GetSemaphore(&Semaphore, 0);
-
- OutputDebugString("BPQ32 Reconfiguration Complete\n");
- }
- }
-
-
- if (RigReconfigFlag)
- {
- // Only do it it timer owning process, or we could get in a real mess!
-
- if(TimerInst == GetCurrentProcessId())
- {
- RigReconfigFlag = FALSE;
- CloseDriverWindow(70);
- Rig_Close();
- Sleep(6000); // Allow any CATPTT, HAMLIB and FLRIG threads to close
- RigActive = Rig_Init();
-
- WritetoConsole("Rigcontrol Reconfiguration Complete\n");
- }
- }
-
- if (APRSReconfigFlag)
- {
- // Only do it it timer owning process, or we could get in a real mess!
-
- if(TimerInst == GetCurrentProcessId())
- {
- APRSReconfigFlag = FALSE;
- APRSClose();
- APRSActive = Init_APRS();
-
- WritetoConsole("APRS Reconfiguration Complete\n");
- }
- }
-
- }
- #include "StdExcept.c"
-
- if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId())
- FreeSemaphore(&Semaphore);
-
- }
-
- strcpy(EXCEPTMSG, "Timer Processing");
-
- __try
- {
- if (IPActive) Poll_IP();
- if (PMActive) Poll_PM();
- if (RigActive) Rig_Poll();
-
- if (NeedWebMailRefresh)
- DoRefreshWebMailIndex();
-
- CheckGuardZone();
-
- if (APRSActive)
- {
- Poll_APRS();
- CheckGuardZone();
- }
-
- CheckWL2KReportTimer();
-
- CheckGuardZone();
-
- TIMERINTERRUPT();
-
- CheckGuardZone();
-
- FreeSemaphore(&Semaphore); // SendLocation needs to get the semaphore
-
- if (NUMBEROFTNCPORTS)
- TNCTimer();
-
- if (AGWActive)
- Poll_AGW();
-
- DRATSPoll();
- RHPPoll();
-
- CheckGuardZone();
-
- strcpy(EXCEPTMSG, "HTTP Timer Processing");
-
- HTTPTimer();
-
- CheckGuardZone();
-
- strcpy(EXCEPTMSG, "WL2K Report Timer Processing");
-
- if (ReportTimer)
- {
- ReportTimer--;
-
- if (ReportTimer == 0)
- {
- ReportTimer = REPORTINTERVAL;
- SendLocation();
- }
- }
- }
-
- #include "StdExcept.c"
-
- if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId())
- FreeSemaphore(&Semaphore);
-
- }
-
- CheckGuardZone();
-
- return;
-}
-
-HANDLE NPHandle;
-
-int (WINAPI FAR *GetModuleFileNameExPtr)() = NULL;
-int (WINAPI FAR *EnumProcessesPtr)() = NULL;
-
-FirstInit()
-{
- WSADATA WsaData; // receives data from WSAStartup
- HINSTANCE ExtDriver=0;
- RECT cRect;
-
-
- // First Time Ports and Timer init
-
- // Moved from DLLINIT to sort out perl problem, and meet MS Guidelines on minimising DLLMain
-
- // Call wsastartup - most systems need winsock, and duplicate statups could be a problem
-
- WSAStartup(MAKEWORD(2, 0), &WsaData);
-
- // Load Psapi.dll if possible
-
- ExtDriver=LoadLibrary("Psapi.dll");
-
- SetupTrayIcon();
-
- if (ExtDriver)
- {
- GetModuleFileNameExPtr = (FARPROCX)GetProcAddress(ExtDriver,"GetModuleFileNameExA");
- EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses");
- }
-
- timeLoadedMS = GetTickCount();
-
- INITIALISEPORTS();
-
- OpenReportingSockets();
-
- WritetoConsole("\n");
- WritetoConsole("Port Initialisation Complete\n");
-
- if (IPRequired) IPActive = Init_IP();
- if (PMRequired) PMActive = Init_PM();
-
- APRSActive = Init_APRS();
-
- if (APRSActive)
- {
- hWndBG = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 0,0,40,546, hConsWnd, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "Enable IGate", WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE,
- 8,0,90,24, hConsWnd, (HMENU)-1, hInstance, NULL);
-
- CreateWindowEx(0, "BUTTON", "", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,
- 95,1,18,24, hConsWnd, (HMENU)IDC_ENIGATE, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "IGate State - Disconnected",
- WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 125, 0, 195, 24, hConsWnd, (HMENU)IGATESTATE, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "IGATE Stats - Msgs 0 Local Stns 0",
- WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 320, 0, 240, 24, hConsWnd, (HMENU)IGATESTATS, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "GPS Off",
- WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 560, 0, 80, 24, hConsWnd, (HMENU)IDC_GPS, hInstance, NULL);
- }
-
- if (ISPort == 0)
- IGateEnabled = 0;
-
- CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled);
-
- GetClientRect(hConsWnd, &cRect);
- MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
- if (APRSActive)
- MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
- else
- {
- ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE);
- MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
- }
- InvalidateRect(hConsWnd, NULL, TRUE);
-
- RigActive = Rig_Init();
-
- _beginthread(MonitorThread,0,0);
-
- TimerHandle=SetTimer(NULL,0,100,lpTimerFunc);
- TimerInst=GetCurrentProcessId();
- SessHandle = SetTimer(NULL, 0, 5000, lpSetupTermSessions);
-
- // If ARIF reporting is enabled write a Trimode Like ini for RMS Analyser
-
- if (ADIFLogEnabled)
- ADIFWriteFreqList();
-
- OutputDebugString("BPQ32 Port Initialisation Complete\n");
-
- if (needAIS)
- initAIS();
-
- if (needADSB)
- initADSB();
-
- return 0;
-}
-
-Check_Timer()
-{
- if (Closing)
- return 0;
-
- if (Semaphore.Flag)
- return 0;
-
- if (InitDone == (void *)-1)
- {
- GetSemaphore(&Semaphore, 3);
- Sleep(15000);
- FreeSemaphore(&Semaphore);
- exit (0);
- }
-
- if (FirstInitDone == 0)
- {
- GetSemaphore(&Semaphore, 3);
-
- if (_stricmp(pgm, "bpq32.exe") == 0)
- {
- FirstInit();
- FreeSemaphore(&Semaphore);
- if (NUMBEROFTNCPORTS)
- InitializeTNCEmulator();
-
- AGWActive = AGWAPIInit();
- FirstInitDone=1; // Only init in BPQ32.exe
- return 0;
- }
- else
- {
- FreeSemaphore(&Semaphore);
- return 0;
- }
- }
-
- if (TimerHandle == 0 && FirstInitDone == 1)
- {
- WSADATA WsaData; // receives data from WSAStartup
- HINSTANCE ExtDriver=0;
- RECT cRect;
-
- // Only attach timer to bpq32.exe
-
- if (_stricmp(pgm, "bpq32.exe") != 0)
- {
- return 0;
- }
-
- GetSemaphore(&Semaphore, 3);
- OutputDebugString("BPQ32 Reinitialising External Ports and Attaching Timer\n");
-
- if (!ProcessConfig())
- {
- ShowWindow(hConsWnd, SW_RESTORE);
- SendMessage(hConsWnd, WM_PAINT, 0, 0);
- SetForegroundWindow(hConsWnd);
-
- InitDone = (void *)-1;
- FreeSemaphore(&Semaphore);
-
- MessageBox(NULL,"Configuration File Error","BPQ32",MB_ICONSTOP);
-
- exit (0);
- }
-
- GetVersionInfo("bpq32.dll");
-
- SetupConsoleWindow();
-
- Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring);
- Consoleprintf(VerCopyright);
- Consoleprintf("Reinitialising...");
-
- SetupBPQDirectory();
-
- Sleep(1000); // Allow time for sockets to close
-
- WSAStartup(MAKEWORD(2, 0), &WsaData);
-
- // Load Psapi.dll if possible
-
- ExtDriver = LoadLibrary("Psapi.dll");
-
- SetupTrayIcon();
-
- if (ExtDriver)
- {
- GetModuleFileNameExPtr = (FARPROCX)GetProcAddress(ExtDriver,"GetModuleFileNameExA");
- EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses");
- }
-
- Start();
-
- INITIALISEPORTS();
-
- OpenReportingSockets();
-
- NODESINPROGRESS = 0;
- CURRENTNODE = 0;
-
- SetApplPorts();
-
- WritetoConsole("\n\nPort Reinitialisation Complete\n");
-
- BPQMsg = RegisterWindowMessage(BPQWinMsg);
-
- CreateMutex(NULL,TRUE,"BPQLOCKMUTEX");
-
-// NPHandle=CreateNamedPipe("\\\\.\\pipe\\BPQ32pipe",
-// PIPE_ACCESS_DUPLEX,0,64,4096,4096,1000,NULL);
-
- if (IPRequired) IPActive = Init_IP();
- if (PMRequired) PMActive = Init_PM();
-
- RigActive = Rig_Init();
- APRSActive = Init_APRS();
-
- if (ISPort == 0)
- IGateEnabled = 0;
-
- CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled);
-
- GetClientRect(hConsWnd, &cRect);
- MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
-
- if (APRSActive)
- MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
- else
- {
- ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE);
- MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
- }
- InvalidateRect(hConsWnd, NULL, TRUE);
-
- FreeConfig();
-
- _beginthread(MonitorThread,0,0);
-
- ReportTimer = 0;
-
- OpenReportingSockets();
-
- FreeSemaphore(&Semaphore);
-
- if (NUMBEROFTNCPORTS)
- InitializeTNCEmulator();
-
- AGWActive = AGWAPIInit();
-
- if (StartMinimized)
- if (MinimizetoTray)
- ShowWindow(FrameWnd, SW_HIDE);
- else
- ShowWindow(FrameWnd, SW_SHOWMINIMIZED);
- else
- ShowWindow(FrameWnd, SW_RESTORE);
-
- TimerHandle=SetTimer(NULL,0,100,lpTimerFunc);
- TimerInst=GetCurrentProcessId();
- SessHandle = SetTimer(NULL, 0, 5000, lpSetupTermSessions);
-
- return (1);
- }
-
- return (0);
-}
-
-DllExport INT APIENTRY CheckTimer()
-{
- return Check_Timer();
-}
-
-Tell_Sessions()
-{
- //
- // Post a message to all listening sessions, so they call the
- // API, and cause a new timer to be allocated
- //
- HWND hWnd;
- int i;
-
- for (i=1;i<65;i++)
- {
- if (BPQHOSTVECTOR[i-1].HOSTFLAGS & 0x80)
- {
- hWnd = BPQHOSTVECTOR[i-1].HOSTHANDLE;
- PostMessage(hWnd, BPQMsg,i, 1);
- PostMessage(hWnd, BPQMsg,i, 2);
- }
- }
- return (0);
-}
-
-BOOL APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID lpReserved)
-{
- DWORD n;
- char buf[350];
-
- int i;
- unsigned int ProcessID;
-
- OSVERSIONINFO osvi;
-
- memset(&osvi, 0, sizeof(OSVERSIONINFO));
- osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
-
- GetVersionEx(&osvi);
-
-
- switch( ul_reason_being_called )
- {
- case DLL_PROCESS_ATTACH:
-
- if (sizeof(HDLCDATA) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata
- {
- // Catastrophic - Refuse to load
-
- MessageBox(NULL,"BPQ32 Too much HDLC data - Recompile","BPQ32", MB_OK);
- return 0;
- }
-
- if (sizeof(struct KISSINFO) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata
- {
- // Catastrophic - Refuse to load
-
- MessageBox(NULL,"BPQ32 Too much KISS data - Recompile","BPQ32", MB_OK);
- return 0;
- }
-
- if (sizeof(struct _EXTPORTDATA) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata
- {
- // Catastrophic - Refuse to load
-
- MessageBox(NULL,"BPQ32 Too much _EXTPORTDATA data - Recompile","BPQ32", MB_OK);
- return 0;
- }
-
- if (sizeof(LINKTABLE) != LINK_TABLE_LEN)
- {
- // Catastrophic - Refuse to load
-
- MessageBox(NULL,"L2 LINK Table .c and .asm mismatch - fix and rebuild","BPQ32", MB_OK);
- return 0;
- }
- if (sizeof(struct ROUTE) != ROUTE_LEN)
- {
- // Catastrophic - Refuse to load
-
- MessageBox(NULL,"ROUTE Table .c and .asm mismatch - fix and rebuild", "BPQ32", MB_OK);
- return 0;
- }
-
- if (sizeof(struct DEST_LIST) != DEST_LIST_LEN)
- {
- // Catastrophic - Refuse to load
-
- MessageBox(NULL,"NODES Table .c and .asm mismatch - fix and rebuild", "BPQ32", MB_OK);
- return 0;
- }
-
- GetSemaphore(&Semaphore, 4);
-
- BPQHOSTVECPTR = &BPQHOSTVECTOR[0];
-
- LoadToolHelperRoutines();
-
- Our_PID = GetCurrentProcessId();
-
- QueryPerformanceFrequency(&lpFrequency);
-
- ticksPerMillisec = (int)lpFrequency.QuadPart / 1000;
-
- lastRunTime.QuadPart = lpFrequency.QuadPart;
-
- GetProcess(Our_PID, pgm);
-
- if (_stricmp(pgm, "regsvr32.exe") == 0 || _stricmp(pgm, "bpqcontrol.exe") == 0)
- {
- AttachedProcesses++; // We will get a detach
- FreeSemaphore(&Semaphore);
- return 1;
- }
-
- if (_stricmp(pgm,"BPQ32.exe") == 0)
- BPQ32_EXE = TRUE;
-
- if (_stricmp(pgm,"BPQMailChat.exe") == 0)
- IncludesMail = TRUE;
-
- if (_stricmp(pgm,"BPQMail.exe") == 0)
- IncludesMail = TRUE;
-
- if (_stricmp(pgm,"BPQChat.exe") == 0)
- IncludesChat = TRUE;
-
- if (FirstEntry) // If loaded by BPQ32.exe, dont close it at end
- {
- FirstEntry = 0;
- if (BPQ32_EXE)
- CloseLast = FALSE;
- }
- else
- {
- if (BPQ32_EXE && AttachingProcess == 0)
- {
- AttachedProcesses++; // We will get a detach
- FreeSemaphore(&Semaphore);
- MessageBox(NULL,"BPQ32.exe is already running\r\n\r\nIt should only be run once", "BPQ32", MB_OK);
- return 0;
- }
- }
-
- if (_stricmp(pgm,"BPQTelnetServer.exe") == 0)
- {
- MessageBox(NULL,"BPQTelnetServer is no longer supported\r\n\r\nUse the TelnetServer in BPQ32.dll", "BPQ32", MB_OK);
- AttachedProcesses++; // We will get a detach
- FreeSemaphore(&Semaphore);
- return 0;
- }
-
- if (_stricmp(pgm,"BPQUIUtil.exe") == 0)
- {
- MessageBox(NULL,"BPQUIUtil is now part of BPQ32.dll\r\nBPQUIUtil.exe cannot be run\r\n", "BPQ32", MB_OK);
- AttachedProcesses++; // We will get a detach
- FreeSemaphore(&Semaphore);
- return 0;
- }
-
- if (_stricmp(pgm,"BPQMailChat.exe") == 0)
- {
- MessageBox(NULL,"BPQMailChat is obsolete. Run BPQMail.exe and/or BPQChat.exe instead", "BPQ32", MB_OK);
- AttachedProcesses++; // We will get a detach
- FreeSemaphore(&Semaphore);
- return 0;
- }
- AuthorisedProgram = TRUE;
-
- if (InitDone == 0)
- {
-// #pragma warning(push)
-// #pragma warning(disable : 4996)
-
-// if (_winver < 0x0600)
-// #pragma warning(pop)
-// {
-// // Below Vista
-//
-// REGTREE = HKEY_LOCAL_MACHINE;
-// strcpy(REGTREETEXT, "HKEY_LOCAL_MACHINE");
-// }
-
- hInstance=hInst;
-
- Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX");
-
- if (Mutex != NULL)
- {
- OutputDebugString("Another BPQ32.dll is loaded\n");
- i=MessageBox(NULL,"BPQ32 DLL already loaded from another directory\nIf you REALLY want this, hit OK, else hit Cancel","BPQ32",MB_OKCANCEL);
- FreeSemaphore(&Semaphore);
-
- if (i != IDOK) return (0);
-
- CloseHandle(Mutex);
- }
-
- if (!BPQ32_EXE)
- {
- if (CheckifBPQ32isLoaded() == FALSE) // Start BPQ32.exe if needed
- {
- // Wasn't Loaded, so we have started it, and should let it init system
-
- goto SkipInit;
- }
- }
-
- GetVersionInfo("bpq32.dll");
-
- sprintf (SIGNONMSG, "G8BPQ AX25 Packet Switch System Version %s %s\r\n%s\r\n",
- TextVerstring, Datestring, VerCopyright);
-
- SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for Win32 (", TextVerstring);
-
- SetupConsoleWindow();
- SetupBPQDirectory();
-
- if (!ProcessConfig())
- {
- StartMinimized = FALSE;
- MinimizetoTray = FALSE;
- ShowWindow(FrameWnd, SW_MAXIMIZE);
- ShowWindow(hConsWnd, SW_MAXIMIZE);
- ShowWindow(StatusWnd, SW_HIDE);
-
- SendMessage(hConsWnd, WM_PAINT, 0, 0);
- SetForegroundWindow(hConsWnd);
-
- InitDone = (void *)-1;
- FreeSemaphore(&Semaphore);
-
- MessageBox(NULL,"Configuration File Error\r\nProgram will close in 15 seconds","BPQ32",MB_ICONSTOP);
-
- return (0);
- }
-
- Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring);
- Consoleprintf(VerCopyright);
-
- if (Start() !=0)
- {
- Sleep(3000);
- FreeSemaphore(&Semaphore);
- return (0);
- }
- else
- {
- SetApplPorts();
-
- GetUIConfig();
-
- InitDone = &InitDone;
- BPQMsg = RegisterWindowMessage(BPQWinMsg);
-// TimerHandle=SetTimer(NULL,0,100,lpTimerFunc);
-// TimerInst=GetCurrentProcessId();
-
-/* Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX");
-
- if (Mutex != NULL)
- {
- OutputDebugString("Another BPQ32.dll is loaded\n");
- MessageBox(NULL,"BPQ32 DLL already loaded from another directory","BPQ32",MB_ICONSTOP);
- FreeSemaphore(&Semaphore);
- return (0);
- }
-
-*/
- Mutex=CreateMutex(NULL,TRUE,"BPQLOCKMUTEX");
-
-// CreatePipe(&H1,&H2,NULL,1000);
-
-// GetLastError();
-
-// NPHandle=CreateNamedPipe("\\\\.\\pipe\\BPQ32pipe",
-// PIPE_ACCESS_DUPLEX,0,64,4096,4096,1000,NULL);
-
-// GetLastError();
-
-/*
- //
- // Read SYSOP password
- //
-
- if (PWTEXT[0] == 0)
- {
- handle = OpenConfigFile("PASSWORD.BPQ");
-
- if (handle == INVALID_HANDLE_VALUE)
- {
- WritetoConsole("Can't open PASSWORD.BPQ\n");
- PWLen=0;
- PWTEXT[0]=0;
- }
- else
- {
- ReadFile(handle,PWTEXT,78,&n,NULL);
- CloseHandle(handle);
- }
- }
-*/
- for (i=0;PWTEXT[i] > 0x20;i++); //Scan for cr or null
- PWLen=i;
-
- }
- }
- else
- {
- if (InitDone != &InitDone)
- {
- MessageBox(NULL,"BPQ32 DLL already loaded at another address","BPQ32",MB_ICONSTOP);
- FreeSemaphore(&Semaphore);
- return (0);
- }
- }
-
- // Run timer monitor thread in all processes - it is possible for the TImer thread not to be the first thread
-SkipInit:
-
- _beginthread(MonitorTimerThread,0,0);
-
- FreeSemaphore(&Semaphore);
-
- AttachedPIDList[AttachedProcesses++] = GetCurrentProcessId();
-
- if (_stricmp(pgm,"bpq32.exe") == 0 && AttachingProcess == 1) AttachingProcess = 0;
-
- GetProcess(GetCurrentProcessId(),pgm);
- n=sprintf(buf,"BPQ32 DLL Attach complete - Program %s - %d Process(es) Attached\n",pgm,AttachedProcesses);
- OutputDebugString(buf);
-
- // Set up local variables
-
- MCOM=1;
- MTX=1;
- MMASK=0xffffffffffffffff;
-
-// if (StartMinimized)
-// if (MinimizetoTray)
-// ShowWindow(FrameWnd, SW_HIDE);
-// else
-// ShowWindow(FrameWnd, SW_SHOWMINIMIZED);
-// else
-// ShowWindow(FrameWnd, SW_RESTORE);
-
- return 1;
-
- case DLL_THREAD_ATTACH:
-
- return 1;
-
- case DLL_THREAD_DETACH:
-
- return 1;
-
- case DLL_PROCESS_DETACH:
-
- if (_stricmp(pgm,"BPQMailChat.exe") == 0)
- IncludesMail = FALSE;
-
- if (_stricmp(pgm,"BPQChat.exe") == 0)
- IncludesChat = FALSE;
-
- ProcessID=GetCurrentProcessId();
-
- Debugprintf("BPQ32 Process %d Detaching", ProcessID);
-
- // Release any streams that the app has failed to release
-
- for (i=1;i<65;i++)
- {
- if (BPQHOSTVECTOR[i-1].STREAMOWNER == ProcessID)
- {
- // If connected, disconnect
-
- SessionControl(i, 2, 0);
- DeallocateStream(i);
- }
- }
-
- // Remove any Tray Icon Entries
-
- for( i = 0; i < 100; ++i )
- {
- if (PIDArray[i] == ProcessID)
- {
- char Log[80];
- hWndArray[i] = 0;
- sprintf(Log,"BPQ32 Removing Tray Item %s\n", PopupText[i]);
- OutputDebugString(Log);
- DeleteMenu(trayMenu,TRAYBASEID+i,MF_BYCOMMAND);
- }
- }
-
- if (Mutex) CloseHandle(Mutex);
-
- // Remove our entry from PID List
-
- for (i=0; i< AttachedProcesses; i++)
- if (AttachedPIDList[i] == ProcessID)
- break;
-
- for (; i< AttachedProcesses; i++)
- {
- AttachedPIDList[i]=AttachedPIDList[i+1];
- }
-
- AttachedProcesses--;
-
- if (TimerInst == ProcessID)
- {
- PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
-
- OutputDebugString("BPQ32 Process with Timer closing\n");
-
- // Call Port Close Routines
-
- for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External
- {
- if (PORTVEC->PORT_EXT_ADDR && PORTVEC->DLLhandle == NULL) // Don't call if real .dll - it's not there!
- {
- SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
- SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
- PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL); // Close External Ports
- }
- }
-
- PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL);
-
- PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
- }
-
-
- IPClose();
- PMClose();
- APRSClose();
- Rig_Close();
- CloseTNCEmulator();
- if (AGWActive)
- AGWAPITerminate();
-
- upnpClose();
-
- WSACleanup();
- WSAGetLastError();
-
- if (MinimizetoTray)
- Shell_NotifyIcon(NIM_DELETE,&niData);
-
- if (hConsWnd) DestroyWindow(hConsWnd);
-
- KillTimer(NULL,TimerHandle);
- TimerHandle=0;
- TimerInst=0xffffffff;
-
- if (AttachedProcesses && Closing == FALSE && AttachingProcess == 0) // Other processes
- {
- OutputDebugString("BPQ32 Reloading BPQ32.exe\n");
- StartBPQ32();
- }
- }
- else
- {
- // Not Timer Process
-
- if (AttachedProcesses == 1 && CloseLast) // Only bpq32.exe left
- {
- Debugprintf("Only BPQ32.exe running - close it");
- CloseAllNeeded = TRUE;
- }
- }
-
- if (AttachedProcesses < 2)
- {
- if (AUTOSAVE)
- SaveNodes();
- if (AUTOSAVEMH)
- SaveMH();
-
- if (needAIS)
- SaveAIS();
- }
- if (AttachedProcesses == 0)
- {
- Closing = TRUE;
- KillTimer(NULL,TimerHandle);
-
- if (MinimizetoTray)
- Shell_NotifyIcon(NIM_DELETE,&niData);
-
- // Unload External Drivers
-
- {
- PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
-
- for (i=0;iPORTCONTROL.PORTTYPE == 0x10 && PORTVEC->DLLhandle)
- FreeLibrary(PORTVEC->DLLhandle);
-
- PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
- }
- }
- }
-
- GetProcess(GetCurrentProcessId(),pgm);
- n=sprintf(buf,"BPQ32 DLL Detach complete - Program %s - %d Process(es) Attached\n",pgm,AttachedProcesses);
- OutputDebugString(buf);
-
- return 1;
- }
- return 1;
-}
-
-DllExport int APIENTRY CloseBPQ32()
-{
- // Unload External Drivers
-
- PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
- int i;
- int ProcessID = GetCurrentProcessId();
-
- if (Semaphore.Flag == 1 && ProcessID == Semaphore.SemProcessID)
- {
- OutputDebugString("BPQ32 Process holding Semaphore called CloseBPQ32 - attempting recovery\r\n");
- Debugprintf("Last Sem Call %d %x %x %x %x %x %x", SemHeldByAPI,
- Sem_eax, Sem_ebx, Sem_ecx, Sem_edx, Sem_esi, Sem_edi);
-
- Semaphore.Flag = 0;
- SemHeldByAPI = 0;
- }
-
- if (TimerInst == ProcessID)
- {
- OutputDebugString("BPQ32 Process with Timer called CloseBPQ32\n");
-
- if (MinimizetoTray)
- Shell_NotifyIcon(NIM_DELETE,&niData);
-
- for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External
- {
- if (PORTVEC->PORT_EXT_ADDR)
- {
- PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL);
- }
- }
- PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL);
-
- PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
- }
-
- KillTimer(NULL,TimerHandle);
- TimerHandle=0;
- TimerInst=0xffffffff;
-
- IPClose();
- PMClose();
- APRSClose();
- Rig_Close();
- if (AGWActive)
- AGWAPITerminate();
-
- upnpClose();
-
- CloseTNCEmulator();
- WSACleanup();
-
- if (hConsWnd) DestroyWindow(hConsWnd);
-
- Debugprintf("AttachedProcesses %d ", AttachedProcesses);
-
- if (AttachedProcesses > 1 && Closing == FALSE && AttachingProcess == 0) // Other processes
- {
- OutputDebugString("BPQ32 Reloading BPQ32.exe\n");
- StartBPQ32();
- }
- }
-
- return 0;
-}
-
-BOOL CopyReg(HKEY hKeyIn, HKEY hKeyOut);
-
-VOID SetupBPQDirectory()
-{
- HKEY hKey = 0;
- HKEY hKeyIn = 0;
- HKEY hKeyOut = 0;
- int disp;
- int retCode,Type,Vallen=MAX_PATH,i;
- char msg[512];
- char ValfromReg[MAX_PATH] = "";
- char DLLName[256]="Not Known";
- char LogDir[256];
- char Time[64];
-
-/*
-•NT4 was/is '4'
-•Win 95 is 4.00.950
-•Win 98 is 4.10.1998
-•Win 98 SE is 4.10.2222
-•Win ME is 4.90.3000
-•2000 is NT 5.0.2195
-•XP is actually 5.1
-•Vista is 6.0
-•Win7 is 6.1
-
- i = _osver; / Build
- i = _winmajor;
- i = _winminor;
-*/
-/*
-#pragma warning(push)
-#pragma warning(disable : 4996)
-
-if (_winver < 0x0600)
-#pragma warning(pop)
- {
- // Below Vista
-
- REGTREE = HKEY_LOCAL_MACHINE;
- strcpy(REGTREETEXT, "HKEY_LOCAL_MACHINE");
- ValfromReg[0] = 0;
- }
- else
-*/
- {
- if (_stricmp(pgm, "regsvr32.exe") == 0)
- {
- Debugprintf("BPQ32 loaded by regsvr32.exe - Registry not copied");
- }
- else
- {
- // If necessary, move reg from HKEY_LOCAL_MACHINE to HKEY_CURRENT_USER
-
- retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
- "SOFTWARE\\G8BPQ\\BPQ32",
- 0,
- KEY_READ,
- &hKeyIn);
-
- retCode = RegCreateKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKeyOut, &disp);
-
- // See if Version Key exists in HKEY_CURRENT_USER - if it does, we have already done the copy
-
- Vallen = MAX_PATH;
- retCode = RegQueryValueEx(hKeyOut, "Version" ,0 , &Type,(UCHAR *)&msg, &Vallen);
-
- if (retCode != ERROR_SUCCESS)
- if (hKeyIn)
- CopyReg(hKeyIn, hKeyOut);
-
- RegCloseKey(hKeyIn);
- RegCloseKey(hKeyOut);
- }
- }
-
- GetModuleFileName(hInstance,DLLName,256);
-
- BPQDirectory[0]=0;
-
- retCode = RegOpenKeyEx (REGTREE,
- "SOFTWARE\\G8BPQ\\BPQ32",
- 0,
- KEY_QUERY_VALUE,
- &hKey);
-
- if (retCode == ERROR_SUCCESS)
- {
- // Try "BPQ Directory"
-
- Vallen = MAX_PATH;
- retCode = RegQueryValueEx(hKey,"BPQ Directory",0,
- &Type,(UCHAR *)&ValfromReg,&Vallen);
-
- if (retCode == ERROR_SUCCESS)
- {
- if (strlen(ValfromReg) == 2 && ValfromReg[0] == '"' && ValfromReg[1] == '"')
- ValfromReg[0]=0;
- }
-
- if (ValfromReg[0] == 0)
- {
- // BPQ Directory absent or = "" - try "Config File Location"
-
- Vallen = MAX_PATH;
-
- retCode = RegQueryValueEx(hKey,"Config File Location",0,
- &Type,(UCHAR *)&ValfromReg,&Vallen);
-
- if (retCode == ERROR_SUCCESS)
- {
- if (strlen(ValfromReg) == 2 && ValfromReg[0] == '"' && ValfromReg[1] == '"')
- ValfromReg[0]=0;
- }
- }
-
- if (ValfromReg[0] == 0) GetCurrentDirectory(MAX_PATH, ValfromReg);
-
- // Get StartMinimized and MinimizetoTray flags
-
- Vallen = 4;
- retCode = RegQueryValueEx(hKey, "Start Minimized", 0, &Type, (UCHAR *)&StartMinimized, &Vallen);
-
- Vallen = 4;
- retCode = RegQueryValueEx(hKey, "Minimize to Tray", 0, &Type, (UCHAR *)&MinimizetoTray, &Vallen);
-
- ExpandEnvironmentStrings(ValfromReg, BPQDirectory, MAX_PATH);
-
- // Also get "BPQ Program Directory"
-
- ValfromReg[0] = 0;
- Vallen = MAX_PATH;
-
- retCode = RegQueryValueEx(hKey, "BPQ Program Directory",0 , &Type, (UCHAR *)&ValfromReg, &Vallen);
-
- if (retCode == ERROR_SUCCESS)
- ExpandEnvironmentStrings(ValfromReg, BPQProgramDirectory, MAX_PATH);
-
- // And Log Directory
-
- ValfromReg[0] = 0;
- Vallen = MAX_PATH;
-
- retCode = RegQueryValueEx(hKey, "Log Directory",0 , &Type, (UCHAR *)&ValfromReg, &Vallen);
-
- if (retCode == ERROR_SUCCESS)
- ExpandEnvironmentStrings(ValfromReg, LogDirectory, MAX_PATH);
-
- RegCloseKey(hKey);
- }
-
- strcpy(ConfigDirectory, BPQDirectory);
-
- if (LogDirectory[0] == 0)
- strcpy(LogDirectory, BPQDirectory);
-
- if (BPQProgramDirectory[0] == 0)
- strcpy(BPQProgramDirectory, BPQDirectory);
-
- sprintf(msg,"BPQ32 Ver %s Loaded from: %s by %s\n", VersionString, DLLName, pgm);
- WritetoConsole(msg);
- OutputDebugString(msg);
- FormatTime3(Time, time(NULL));
- sprintf(msg,"Loaded %s\n", Time);
- WritetoConsole(msg);
- OutputDebugString(msg);
-
-#pragma warning(push)
-#pragma warning(disable : 4996)
-
-#if _MSC_VER >= 1400
-
-#define _winmajor 6
-#define _winminor 0
-
-#endif
-
- i=sprintf(msg,"Windows Ver %d.%d, Using Registry Key %s\n" ,_winmajor, _winminor, REGTREETEXT);
-
-#pragma warning(pop)
-
- WritetoConsole(msg);
- OutputDebugString(msg);
-
- i=sprintf(msg,"BPQ32 Using config from: %s\n\n",BPQDirectory);
- WritetoConsole(&msg[6]);
- msg[i-1]=0;
- OutputDebugString(msg);
-
- // Don't write the Version Key if loaded by regsvr32.exe (Installer is running with Admin rights,
- // so will write the wrong tree on )
-
- if (_stricmp(pgm, "regsvr32.exe") == 0)
- {
- Debugprintf("BPQ32 loaded by regsvr32.exe - Version String not written");
- }
- else
- {
- retCode = RegCreateKeyEx(REGTREE, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp);
-
- sprintf(msg,"%d,%d,%d,%d", Ver[0], Ver[1], Ver[2], Ver[3]);
- retCode = RegSetValueEx(hKey, "Version",0, REG_SZ,(BYTE *)msg, strlen(msg) + 1);
-
- RegCloseKey(hKey);
- }
-
- // Make sure Logs Directory exists
-
- sprintf(LogDir, "%s/Logs", LogDirectory);
-
- CreateDirectory(LogDir, NULL);
-
- return;
-}
-
-HANDLE OpenConfigFile(char *fn)
-{
- HANDLE handle;
- UCHAR Value[MAX_PATH];
- FILETIME LastWriteTime;
- SYSTEMTIME Time;
- char Msg[256];
-
-
- // If no directory, use current
- if (BPQDirectory[0] == 0)
- {
- strcpy(Value,fn);
- }
- else
- {
- strcpy(Value,BPQDirectory);
- strcat(Value,"\\");
- strcat(Value,fn);
- }
-
- handle = CreateFile(Value,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
-
- GetFileTime(handle, NULL, NULL, &LastWriteTime);
- FileTimeToSystemTime(&LastWriteTime, &Time);
-
- sprintf(Msg,"BPQ32 Config File %s Created %.2d:%.2d %d/%.2d/%.2d\n", Value,
- Time.wHour, Time.wMinute, Time.wYear, Time.wMonth, Time.wDay);
-
- OutputDebugString(Msg);
-
- return(handle);
-}
-
-#ifdef _WIN64
-int BPQHOSTAPI()
-{
- return 0;
-}
-#endif
-
-
-DllExport int APIENTRY GETBPQAPI()
-{
- return (int)BPQHOSTAPI;
-}
-
-//DllExport UINT APIENTRY GETMONDECODE()
-//{
-// return (UINT)MONDECODE;
-//}
-
-
-DllExport INT APIENTRY BPQAPI(int Fn, char * params)
-{
-
-/*
-;
-; BPQ HOST MODE SUPPORT CODE
-;
-; 22/11/95
-;
-; MOVED FROM TNCODE.ASM COS CONITIONALS WERE GETTING TOO COMPLICATED
-; (OS2 VERSION HAD UPSET KANT VERISON
-;
-;
-*/
-
-
-/*
-
- BPQHOSTPORT:
-;
-; SPECIAL INTERFACE, MAINLY FOR EXTERNAL HOST MODE SUPPORT PROGS
-;
-; COMMANDS SUPPORTED ARE
-;
-; AH = 0 Get node/switch version number and description. On return
-; AH='B',AL='P',BH='Q',BL=' '
-; DH = major version number and DL = minor version number.
-;
-;
-; AH = 1 Set application mask to value in DL (or even DX if 16
-; applications are ever to be supported).
-;
-; Set application flag(s) to value in CL (or CX).
-; whether user gets connected/disconnected messages issued
-; by the node etc.
-;
-;
-; AH = 2 Send frame in ES:SI (length CX)
-;
-;
-; AH = 3 Receive frame into buffer at ES:DI, length of frame returned
-; in CX. BX returns the number of outstanding frames still to
-; be received (ie. after this one) or zero if no more frames
-; (ie. this is last one).
-;
-;
-;
-; AH = 4 Get stream status. Returns:
-;
-; CX = 0 if stream disconnected or CX = 1 if stream connected
-; DX = 0 if no change of state since last read, or DX = 1 if
-; the connected/disconnected state has changed since
-; last read (ie. delta-stream status).
-;
-;
-;
-; AH = 6 Session control.
-;
-; CX = 0 Conneect - _APPLMASK in DL
-; CX = 1 connect
-; CX = 2 disconnect
-; CX = 3 return user to node
-;
-;
-; AH = 7 Get buffer counts for stream. Returns:
-;
-; AX = number of status change messages to be received
-; BX = number of frames queued for receive
-; CX = number of un-acked frames to be sent
-; DX = number of buffers left in node
-; SI = number of trace frames queued for receive
-;
-;AH = 8 Port control/information. Called with a stream number
-; in AL returns:
-;
-; AL = Radio port on which channel is connected (or zero)
-; AH = SESSION TYPE BITS
-; BX = L2 paclen for the radio port
-; CX = L2 maxframe for the radio port
-; DX = L4 window size (if L4 circuit, or zero)
-; ES:DI = CALLSIGN
-
-;AH = 9 Fetch node/application callsign & alias. AL = application
-; number:
-;
-; 0 = node
-; 1 = BBS
-; 2 = HOST
-; 3 = SYSOP etc. etc.
-;
-; Returns string with alias & callsign or application name in
-; user's buffer pointed to by ES:SI length CX. For example:
-;
-; "WORCS:G8TIC" or "TICPMS:G8TIC-10".
-;
-;
-; AH = 10 Unproto transmit frame. Data pointed to by ES:SI, of
-; length CX, is transmitted as a HDLC frame on the radio
-; port (not stream) in AL.
-;
-;
-; AH = 11 Get Trace (RAW Data) Frame into ES:DI,
-; Length to CX, Timestamp to AX
-;
-;
-; AH = 12 Update Switch. At the moment only Beacon Text may be updated
-; DX = Function
-; 1=update BT. ES:SI, Len CX = Text
-; 2=kick off nodes broadcast
-;
-; AH = 13 Allocate/deallocate stream
-; If AL=0, return first free stream
-; If AL>0, CL=1, Allocate stream. If aleady allocated,
-; return CX nonzero, else allocate, and return CX=0
-; If AL>0, CL=2, Release stream
-;
-;
-; AH = 14 Internal Interface for IP Router
-;
-; Send frame - to NETROM L3 if DL=0
-; to L2 Session if DL<>0
-;
-;
-; AH = 15 Get interval timer
-
-
-*/
-
-
- switch(Fn)
- {
-
- case CHECKLOADED:
-
- params[0]=MAJORVERSION;
- params[1]=MINORVERSION;
- params[2]=QCOUNT;
-
- return (1);
- }
- return 0;
-}
-
-DllExport int APIENTRY InitSwitch()
-{
- return (0);
-}
-
-/*DllExport int APIENTRY SwitchTimer()
-{
- GetSemaphore((&Semaphore);
-
- TIMERINTERRUPT();
-
- FreeSemaphore(&Semaphore);
-
- return (0);
-}
-*/
-DllExport int APIENTRY GetFreeBuffs()
-{
-// Returns number of free buffers
-// (BPQHOST function 7 (part)).
- return (QCOUNT);
-}
-
-DllExport UCHAR * APIENTRY GetNodeCall()
-{
- return (&MYNODECALL);
-}
-
-
-DllExport UCHAR * APIENTRY GetNodeAlias()
-{
- return (&MYALIASTEXT[0]);
-}
-
-DllExport UCHAR * APIENTRY GetBBSCall()
-{
- return (UCHAR *)(&APPLCALLTABLE[0].APPLCALL_TEXT);
-}
-
-
-DllExport UCHAR * APIENTRY GetBBSAlias()
-{
- return (UCHAR *)(&APPLCALLTABLE[0].APPLALIAS_TEXT);
-}
-
-DllExport VOID APIENTRY GetApplCallVB(int Appl, char * ApplCall)
-{
- if (Appl < 1 || Appl > NumberofAppls ) return;
-
- strncpy(ApplCall,(char *)&APPLCALLTABLE[Appl-1].APPLCALL_TEXT, 10);
-}
-
-BOOL UpdateNodesForApp(int Appl);
-
-DllExport BOOL APIENTRY SetApplCall(int Appl, char * NewCall)
-{
- char Call[10]=" ";
- int i;
-
- if (Appl < 1 || Appl > NumberofAppls ) return FALSE;
-
- i=strlen(NewCall);
-
- if (i > 10) i=10;
-
- strncpy(Call,NewCall,i);
-
- strncpy((char *)&APPLCALLTABLE[Appl-1].APPLCALL_TEXT,Call,10);
-
- if (!ConvToAX25(Call,APPLCALLTABLE[Appl-1].APPLCALL)) return FALSE;
-
- UpdateNodesForApp(Appl);
-
- return TRUE;
-
-}
-
-DllExport BOOL APIENTRY SetApplAlias(int Appl, char * NewCall)
-{
- char Call[10]=" ";
- int i;
-
- if (Appl < 1 || Appl > NumberofAppls ) return FALSE;
-
- i=strlen(NewCall);
-
- if (i > 10) i=10;
-
- strncpy(Call,NewCall,i);
-
- strncpy((char *)&APPLCALLTABLE[Appl-1].APPLALIAS_TEXT,Call,10);
-
- if (!ConvToAX25(Call,APPLCALLTABLE[Appl-1].APPLALIAS)) return FALSE;
-
- UpdateNodesForApp(Appl);
-
- return TRUE;
-
-}
-
-
-
-DllExport BOOL APIENTRY SetApplQual(int Appl, int NewQual)
-{
- if (Appl < 1 || Appl > NumberofAppls ) return FALSE;
-
- APPLCALLTABLE[Appl-1].APPLQUAL=NewQual;
-
- UpdateNodesForApp(Appl);
-
- return TRUE;
-
-}
-
-
-BOOL UpdateNodesForApp(int Appl)
-{
- int App=Appl-1;
- int DestLen = sizeof (struct DEST_LIST);
- int n = MAXDESTS;
-
- struct DEST_LIST * DEST = APPLCALLTABLE[App].NODEPOINTER;
- APPLCALLS * APPL=&APPLCALLTABLE[App];
-
- if (DEST == NULL)
- {
- // No dest at the moment. If we have valid call and Qual, create an entry
-
- if (APPLCALLTABLE[App].APPLQUAL == 0) return FALSE;
-
- if (APPLCALLTABLE[App].APPLCALL[0] < 41) return FALSE;
-
-
- GetSemaphore(&Semaphore, 5);
-
- DEST = DESTS;
-
- while (n--)
- {
- if (DEST->DEST_CALL[0] == 0) // Spare
- break;
- }
-
- if (n == 0)
- {
- // no dests
-
- FreeSemaphore(&Semaphore);
- return FALSE;
- }
-
- NUMBEROFNODES++;
- APPL->NODEPOINTER = DEST;
-
- memmove (DEST->DEST_CALL,APPL->APPLCALL,13);
-
- DEST->DEST_STATE=0x80; // SPECIAL ENTRY
-
- DEST->NRROUTE[0].ROUT_QUALITY = (BYTE)APPL->APPLQUAL;
- DEST->NRROUTE[0].ROUT_OBSCOUNT = 255;
-
- FreeSemaphore(&Semaphore);
-
- return TRUE;
- }
-
- // We have a destination. If Quality is zero, remove it, else update it
-
- if (APPLCALLTABLE[App].APPLQUAL == 0)
- {
- GetSemaphore(&Semaphore, 6);
-
- REMOVENODE(DEST); // Clear buffers, Remove from Sorted Nodes chain, and zap entry
-
- APPL->NODEPOINTER=NULL;
-
- FreeSemaphore(&Semaphore);
- return FALSE;
-
- }
-
- if (APPLCALLTABLE[App].APPLCALL[0] < 41) return FALSE;
-
- GetSemaphore(&Semaphore, 7);
-
- memmove (DEST->DEST_CALL,APPL->APPLCALL,13);
-
- DEST->DEST_STATE=0x80; // SPECIAL ENTRY
-
- DEST->NRROUTE[0].ROUT_QUALITY = (BYTE)APPL->APPLQUAL;
- DEST->NRROUTE[0].ROUT_OBSCOUNT = 255;
-
- FreeSemaphore(&Semaphore);
- return TRUE;
-
-}
-
-
-DllExport UCHAR * APIENTRY GetSignOnMsg()
-{
- return (&SIGNONMSG[0]);
-}
-
-
-DllExport HKEY APIENTRY GetRegistryKey()
-{
- return REGTREE;
-}
-
-DllExport char * APIENTRY GetRegistryKeyText()
-{
- return REGTREETEXT;;
-}
-
-DllExport UCHAR * APIENTRY GetBPQDirectory()
-{
- while (BPQDirectory[0] == 0)
- {
- Debugprintf("BPQ Directory not set up - waiting");
- Sleep(1000);
- }
- return (&BPQDirectory[0]);
-}
-
-DllExport UCHAR * APIENTRY GetProgramDirectory()
-{
- return (&BPQProgramDirectory[0]);
-}
-
-DllExport UCHAR * APIENTRY GetLogDirectory()
-{
- return (&LogDirectory[0]);
-}
-
-// Version for Visual Basic
-
-DllExport char * APIENTRY CopyBPQDirectory(char * dir)
-{
- return (strcpy(dir,BPQDirectory));
-}
-
-DllExport int APIENTRY GetMsgPerl(int stream, char * msg)
-{
- int len,count;
-
- GetMsg(stream, msg, &len, &count );
-
- return len;
-}
-
-int Rig_Command(int Session, char * Command);
-
-BOOL Rig_CommandInt(int Session, char * Command)
-{
- return Rig_Command(Session, Command);
-}
-
-DllExport int APIENTRY BPQSetHandle(int Stream, HWND hWnd)
-{
- BPQHOSTVECTOR[Stream-1].HOSTHANDLE=hWnd;
- return (0);
-}
-
-#define L4USER 0
-
-BPQVECSTRUC * PORTVEC ;
-
-VOID * InitializeExtDriver(PEXTPORTDATA PORTVEC)
-{
- HINSTANCE ExtDriver=0;
- char msg[128];
- int err=0;
- HKEY hKey=0;
- UCHAR Value[MAX_PATH];
-
- // If no directory, use current
-
- if (BPQDirectory[0] == 0)
- {
- strcpy(Value,PORTVEC->PORT_DLL_NAME);
- }
- else
- {
- strcpy(Value,BPQDirectory);
- strcat(Value,"\\");
- strcat(Value,PORTVEC->PORT_DLL_NAME);
- }
-
- // Several Drivers are now built into bpq32.dll
-
- _strupr(Value);
-
- if (strstr(Value, "BPQVKISS"))
- return VCOMExtInit;
-
- if (strstr(Value, "BPQAXIP"))
- return AXIPExtInit;
-
- if (strstr(Value, "BPQETHER"))
- return ETHERExtInit;
-
- if (strstr(Value, "BPQTOAGW"))
- return AGWExtInit;
-
- if (strstr(Value, "AEAPACTOR"))
- return AEAExtInit;
-
- if (strstr(Value, "HALDRIVER"))
- return HALExtInit;
-
- if (strstr(Value, "KAMPACTOR"))
- return KAMExtInit;
-
- if (strstr(Value, "SCSPACTOR"))
- return SCSExtInit;
-
- if (strstr(Value, "WINMOR"))
- return WinmorExtInit;
-
- if (strstr(Value, "V4"))
- return V4ExtInit;
-
- if (strstr(Value, "TELNET"))
- return TelnetExtInit;
-
-// if (strstr(Value, "SOUNDMODEM"))
-// return SoundModemExtInit;
-
- if (strstr(Value, "SCSTRACKER"))
- return TrackerExtInit;
-
- if (strstr(Value, "TRKMULTI"))
- return TrackerMExtInit;
-
- if (strstr(Value, "UZ7HO"))
- return UZ7HOExtInit;
-
- if (strstr(Value, "MULTIPSK"))
- return MPSKExtInit;
-
- if (strstr(Value, "FLDIGI"))
- return FLDigiExtInit;
-
- if (strstr(Value, "UIARQ"))
- return UIARQExtInit;
-
-// if (strstr(Value, "BAYCOM"))
-// return (UINT) BaycomExtInit;
-
- if (strstr(Value, "VARA"))
- return VARAExtInit;
-
- if (strstr(Value, "ARDOP"))
- return ARDOPExtInit;
-
- if (strstr(Value, "SERIAL"))
- return SerialExtInit;
-
- if (strstr(Value, "KISSHF"))
- return KISSHFExtInit;
-
- if (strstr(Value, "WINRPR"))
- return WinRPRExtInit;
-
- if (strstr(Value, "HSMODEM"))
- return HSMODEMExtInit;
-
- if (strstr(Value, "FREEDATA"))
- return FreeDataExtInit;
-
- if (strstr(Value, "6PACK"))
- return SIXPACKExtInit;
-
- ExtDriver = LoadLibrary(Value);
-
- if (ExtDriver == NULL)
- {
- err=GetLastError();
-
- sprintf(msg,"Error loading Driver %s - Error code %d",
- PORTVEC->PORT_DLL_NAME,err);
-
- MessageBox(NULL,msg,"BPQ32",MB_ICONSTOP);
-
- return(0);
- }
-
- PORTVEC->DLLhandle=ExtDriver;
-
- return (GetProcAddress(ExtDriver,"_ExtInit@4"));
-
-}
-
-/*
-_DATABASE LABEL BYTE
-
-FILLER DB 14 DUP (0) ; PROTECTION AGENST BUFFER PROBLEMS!
- DB MAJORVERSION,MINORVERSION
-_NEIGHBOURS DD 0
- DW TYPE ROUTE
-_MAXNEIGHBOURS DW 20 ; MAX ADJACENT NODES
-
-_DESTS DD 0 ; NODE LIST
- DW TYPE DEST_LIST
-MAXDESTS DW 100 ; MAX NODES IN SYSTEM
-*/
-
-
-DllExport int APIENTRY GetAttachedProcesses()
-{
- return (AttachedProcesses);
-}
-
-DllExport int * APIENTRY GetAttachedProcessList()
-{
- return (&AttachedPIDList[0]);
-}
-
-DllExport int * APIENTRY SaveNodesSupport()
-{
- return (&DATABASESTART);
-}
-
-//
-// Internal BPQNODES support
-//
-
-#define UCHAR unsigned char
-
-/*
-ROUTE ADD G1HTL-1 2 200 0 0 0
-ROUTE ADD G4IRX-3 2 200 0 0 0
-NODE ADD MAPPLY:G1HTL-1 G1HTL-1 2 200 G4IRX-3 2 98
-NODE ADD NOT:GB7NOT G1HTL-1 2 199 G4IRX-3 2 98
-
-*/
-
-struct DEST_LIST * Dests;
-struct ROUTE * Routes;
-
-int MaxNodes;
-int MaxRoutes;
-int NodeLen;
-int RouteLen;
-
-int count;
-int cursor;
-
-int len,i;
-
-ULONG cnt;
-char Normcall[10];
-char Portcall[10];
-char Alias[7];
-
-char line[100];
-
-HANDLE handle;
-
-int APIENTRY Restart()
-{
- int i, Count = AttachedProcesses;
- HANDLE hProc;
- DWORD PID;
-
- for (i = 0; i < Count; i++)
- {
- PID = AttachedPIDList[i];
-
- // Kill Timer Owner last
-
- if (TimerInst != PID)
- {
- hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID);
-
- if (hProc)
- {
- TerminateProcess(hProc, 0);
- CloseHandle(hProc);
- }
- }
- }
-
- hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, TimerInst);
-
- if (hProc)
- {
- TerminateProcess(hProc, 0);
- CloseHandle(hProc);
- }
-
-
- return 0;
-}
-
-int APIENTRY Reboot()
-{
- // Run shutdown -r -f
-
- STARTUPINFO SInfo;
- PROCESS_INFORMATION PInfo;
- char Cmd[] = "shutdown -r -f";
-
- SInfo.cb=sizeof(SInfo);
- SInfo.lpReserved=NULL;
- SInfo.lpDesktop=NULL;
- SInfo.lpTitle=NULL;
- SInfo.dwFlags=0;
- SInfo.cbReserved2=0;
- SInfo.lpReserved2=NULL;
-
- return CreateProcess(NULL, Cmd, NULL, NULL, FALSE,0 ,NULL ,NULL, &SInfo, &PInfo);
-}
-/*
-int APIENTRY Reconfig()
-{
- if (!ProcessConfig())
- {
- return (0);
- }
- SaveNodes();
- WritetoConsole("Nodes Saved\n");
- ReconfigFlag=TRUE;
- WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n");
- return 1;
-}
-*/
-// Code to support minimizing all BPQ Apps to a single Tray ICON
-
-// As we can't minimize the console window to the tray, I'll use an ordinary
-// window instead. This also gives me somewhere to post the messages to
-
-
-char AppName[] = "BPQ32";
-char Title[80] = "BPQ32.dll Console";
-
-int NewLine();
-
-char FrameClassName[] = TEXT("MdiFrame");
-
-HWND ClientWnd; //This stores the MDI client area window handle
-
-LOGFONT LFTTYFONT ;
-
-HFONT hFont ;
-
-HMENU hPopMenu, hWndMenu;
-HMENU hMainFrameMenu = NULL;
-HMENU hBaseMenu = NULL;
-HMENU hConsMenu = NULL;
-HMENU hTermMenu = NULL;
-HMENU hMonMenu = NULL;
-HMENU hTermActMenu, hTermCfgMenu, hTermEdtMenu, hTermHlpMenu;
-HMENU hMonActMenu, hMonCfgMenu, hMonEdtMenu, hMonHlpMenu;
-
-
-LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
-LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
-
-DllExport int APIENTRY DeleteTrayMenuItem(HWND hWnd);
-
-#define BPQMonitorAvail 1
-#define BPQDataAvail 2
-#define BPQStateChange 4
-
-VOID GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value);
-SOCKET OpenWL2KHTTPSock();
-SendHTTPRequest(SOCKET sock, char * Request, char * Params, int Len, char * Return);
-
-BOOL GetWL2KSYSOPInfo(char * Call, char * _REPLYBUFFER);
-BOOL UpdateWL2KSYSOPInfo(char * Call, char * SQL);
-
-
-static INT_PTR CALLBACK ConfigWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- switch (message)
- {
- case WM_INITDIALOG:
- {
- char _REPLYBUFFER[1000] = "";
- char Value[1000];
-
- if (GetWL2KSYSOPInfo(WL2KCall, _REPLYBUFFER))
- {
-// if (strstr(_REPLYBUFFER, "\"ErrorMessage\":") == 0)
-
- GetJSONValue(_REPLYBUFFER, "\"SysopName\":", Value);
- SetDlgItemText(hDlg, NAME, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"GridSquare\":", Value);
- SetDlgItemText(hDlg, IDC_Locator, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"StreetAddress1\":", Value);
- SetDlgItemText(hDlg, ADDR1, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"StreetAddress2\":", Value);
- SetDlgItemText(hDlg, ADDR2, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"City\":", Value);
- SetDlgItemText(hDlg, CITY, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"State\":", Value);
- SetDlgItemText(hDlg, STATE, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"Country\":", Value);
- SetDlgItemText(hDlg, COUNTRY, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"PostalCode\":", Value);
- SetDlgItemText(hDlg, POSTCODE, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"Email\":", Value);
- SetDlgItemText(hDlg, EMAIL, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"Website\":", Value);
- SetDlgItemText(hDlg, WEBSITE, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"Phones\":", Value);
- SetDlgItemText(hDlg, PHONE, Value);
-
- GetJSONValue(_REPLYBUFFER, "\"Comments\":", Value);
- SetDlgItemText(hDlg, ADDITIONALDATA, Value);
-
- }
-
- return (INT_PTR)TRUE;
- }
- case WM_COMMAND:
-
- switch(LOWORD(wParam))
- {
-
- case ID_SAVE:
- {
- char Name[100];
- char PasswordText[100];
- char LocatorText[100];
- char Addr1[100];
- char Addr2[100];
- char City[100];
- char State[100];
- char Country[100];
- char PostCode[100];
- char Email[100];
- char Website[100];
- char Phone[100];
- char Data[100];
-
- SOCKET sock;
-
- int Len;
- char Message[2048];
- char Reply[2048] = "";
-
-
- GetDlgItemText(hDlg, NAME, Name, 99);
- GetDlgItemText(hDlg, IDC_Password, PasswordText, 99);
- GetDlgItemText(hDlg, IDC_Locator, LocatorText, 99);
- GetDlgItemText(hDlg, ADDR1, Addr1, 99);
- GetDlgItemText(hDlg, ADDR2, Addr2, 99);
- GetDlgItemText(hDlg, CITY, City, 99);
- GetDlgItemText(hDlg, STATE, State, 99);
- GetDlgItemText(hDlg, COUNTRY, Country, 99);
- GetDlgItemText(hDlg, POSTCODE, PostCode, 99);
- GetDlgItemText(hDlg, EMAIL, Email, 99);
- GetDlgItemText(hDlg, WEBSITE, Website, 99);
- GetDlgItemText(hDlg, PHONE, Phone, 99);
- GetDlgItemText(hDlg, ADDITIONALDATA, Data, 99);
-
-
-//{"Callsign":"String","GridSquare":"String","SysopName":"String",
-//"StreetAddress1":"String","StreetAddress2":"String","City":"String",
-//"State":"String","Country":"String","PostalCode":"String","Email":"String",
-//"Phones":"String","Website":"String","Comments":"String"}
-
- Len = sprintf(Message,
- "\"Callsign\":\"%s\","
- "\"Password\":\"%s\","
- "\"GridSquare\":\"%s\","
- "\"SysopName\":\"%s\","
- "\"StreetAddress1\":\"%s\","
- "\"StreetAddress2\":\"%s\","
- "\"City\":\"%s\","
- "\"State\":\"%s\","
- "\"Country\":\"%s\","
- "\"PostalCode\":\"%s\","
- "\"Email\":\"%s\","
- "\"Phones\":\"%s\","
- "\"Website\":\"%s\","
- "\"Comments\":\"%s\"",
-
- WL2KCall, PasswordText, LocatorText, Name, Addr1, Addr2, City, State, Country, PostCode, Email, Phone, Website, Data);
-
- Debugprintf("Sending %s", Message);
-
- sock = OpenWL2KHTTPSock();
-
- if (sock)
- {
- char * ptr;
-
- SendHTTPRequest(sock,
- "/sysop/add", Message, Len, Reply);
-
- ptr = strstr(Reply, "\"ErrorCode\":");
-
- if (ptr)
- {
- ptr = strstr(ptr, "Message");
- if (ptr)
- {
- ptr += 10;
- strlop(ptr, '"');
- MessageBox(NULL ,ptr, "Error", MB_OK);
- }
- }
- else
- MessageBox(NULL, "Sysop Record Updated", "BPQ32", MB_OK);
-
- }
- closesocket(sock);
- }
-
- case ID_CANCEL:
- {
- EndDialog(hDlg, LOWORD(wParam));
- return (INT_PTR)TRUE;
- }
- break;
- }
- }
- return (INT_PTR)FALSE;
-}
-
-
-
-LRESULT CALLBACK UIWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
-VOID WINAPI OnTabbedDialogInit(HWND hDlg);
-
-LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- int wmId, wmEvent;
- POINT pos;
- BOOL ret;
-
- CLIENTCREATESTRUCT MDIClientCreateStruct; // Structure to be used for MDI client area
- //HWND m_hwndSystemInformation = 0;
-
- if (message == BPQMsg)
- {
- if (lParam & BPQDataAvail)
- DoReceivedData(wParam);
-
- if (lParam & BPQMonitorAvail)
- DoMonData(wParam);
-
- if (lParam & BPQStateChange)
- DoStateChange(wParam);
-
- return (0);
- }
-
- switch (message)
- {
- case MY_TRAY_ICON_MESSAGE:
-
- switch(lParam)
- {
- case WM_RBUTTONUP:
- case WM_LBUTTONUP:
-
- GetCursorPos(&pos);
-
- // SetForegroundWindow(FrameWnd);
-
- TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, FrameWnd, 0);
- return 0;
- }
-
- break;
-
- case WM_CTLCOLORDLG:
- return (LONG)bgBrush;
-
- case WM_SIZING:
- case WM_SIZE:
-
- SendMessage(ClientWnd, WM_MDIICONARRANGE, 0 ,0);
- break;
-
- case WM_NCCREATE:
-
- ret = DefFrameProc(hWnd, ClientWnd, message, wParam, lParam);
- return TRUE;
-
- case WM_CREATE:
-
- // On creation of main frame, create the MDI client area
-
- MDIClientCreateStruct.hWindowMenu = NULL;
- MDIClientCreateStruct.idFirstChild = IDM_FIRSTCHILD;
-
- ClientWnd = CreateWindow(TEXT("MDICLIENT"), // predefined value for MDI client area
- NULL, // no caption required
- WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
- 0, // No need to give any x/y or height/width since this client
- // will just be used to get client windows created, effectively
- // in the main window we will be seeing the mainframe window client area itself.
- 0,
- 0,
- 0,
- hWnd,
- NULL,
- hInstance,
- (void *) &MDIClientCreateStruct);
-
-
- return 0;
-
- case WM_COMMAND:
-
- wmId = LOWORD(wParam); // Remember, these are...
- wmEvent = HIWORD(wParam); // ...different for Win32!
-
- if (wmId >= TRAYBASEID && wmId < (TRAYBASEID + 100))
- {
- handle=hWndArray[wmId-TRAYBASEID];
-
- if (handle == FrameWnd)
- ShowWindow(handle, SW_NORMAL);
-
- if (handle == FrameWnd && FrameMaximized == TRUE)
- PostMessage(handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
- else
- PostMessage(handle, WM_SYSCOMMAND, SC_RESTORE, 0);
-
- SetForegroundWindow(handle);
- return 0;
- }
-
- switch(wmId)
- {
- struct ConsoleInfo * Cinfo = NULL;
-
- case ID_NEWWINDOW:
- Cinfo = CreateChildWindow(0, FALSE);
- if (Cinfo)
- SendMessage(ClientWnd, WM_MDIACTIVATE, (WPARAM)Cinfo->hConsole, 0);
- break;
-
- case ID_WINDOWS_CASCADE:
- SendMessage(ClientWnd, WM_MDICASCADE, 0, 0);
- return 0;
-
- case ID_WINDOWS_TILE:
- SendMessage(ClientWnd, WM_MDITILE , MDITILE_HORIZONTAL, 0);
- return 0;
-
- case BPQCLOSEALL:
- CloseAllPrograms();
- // SendMessage(ClientWnd, WM_MDIICONARRANGE, 0 ,0);
-
- return 0;
-
- case BPQUICONFIG:
- {
- int err, i=0;
- char Title[80];
- WNDCLASS wc;
-
- wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.lpfnWndProc = UIWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = DLGWINDOWEXTRA;
- wc.hInstance = hInstance;
- wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON) );
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = bgBrush;
-
- wc.lpszMenuName = NULL;
- wc.lpszClassName = UIClassName;
-
- RegisterClass(&wc);
-
- UIhWnd = CreateDialog(hInstance, UIClassName, 0, NULL);
-
- if (!UIhWnd)
- {
- err=GetLastError();
- return FALSE;
- }
-
- wsprintf(Title,"BPQ32 Beacon Configuration");
- MySetWindowText(UIhWnd, Title);
- ShowWindow(UIhWnd, SW_NORMAL);
-
- OnTabbedDialogInit(UIhWnd); // Set up pages
-
- // UpdateWindow(UIhWnd);
- return 0;
- }
-
-
- case IDD_WL2KSYSOP:
-
- if (WL2KCall[0] == 0)
- {
- MessageBox(NULL,"WL2K Reporting is not configured","BPQ32", MB_OK);
- break;
- }
-
- DialogBox(hInstance, MAKEINTRESOURCE(IDD_WL2KSYSOP), hWnd, ConfigWndProc);
- break;
-
-
- // Handle MDI Window commands
-
- default:
- {
- if(wmId >= IDM_FIRSTCHILD)
- {
- DefFrameProc(hWnd, ClientWnd, message, wParam, lParam);
- }
- else
- {
- HWND hChild = (HWND)SendMessage(ClientWnd, WM_MDIGETACTIVE,0,0);
-
- if(hChild)
- SendMessage(hChild, WM_COMMAND, wParam, lParam);
- }
- }
- }
-
- break;
-
- case WM_INITMENUPOPUP:
- {
- HWND hChild = (HWND)SendMessage(ClientWnd, WM_MDIGETACTIVE,0,0);
-
- if(hChild)
- SendMessage(hChild, WM_INITMENUPOPUP, wParam, lParam);
- }
-
- case WM_SYSCOMMAND:
-
- wmId = LOWORD(wParam); // Remember, these are...
- wmEvent = HIWORD(wParam); // ...different for Win32!
-
- switch (wmId)
- {
- case SC_MAXIMIZE:
-
- FrameMaximized = TRUE;
- break;
-
- case SC_RESTORE:
-
- FrameMaximized = FALSE;
- break;
-
- case SC_MINIMIZE:
-
- if (MinimizetoTray)
- {
- ShowWindow(hWnd, SW_HIDE);
- return TRUE;
- }
- }
-
- return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam));
-
- case WM_CLOSE:
-
- PostQuitMessage(0);
-
- if (MinimizetoTray)
- DeleteTrayMenuItem(hWnd);
-
- break;
-
- default:
- return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam));
-
- }
- return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam));
-}
-
-int OffsetH, OffsetW;
-
-int SetupConsoleWindow()
-{
- WNDCLASS wc;
- int i;
- int retCode, Type, Vallen;
- HKEY hKey=0;
- char Size[80];
- WNDCLASSEX wndclassMainFrame;
- RECT CRect;
-
- retCode = RegOpenKeyEx (REGTREE,
- "SOFTWARE\\G8BPQ\\BPQ32",
- 0,
- KEY_QUERY_VALUE,
- &hKey);
-
- if (retCode == ERROR_SUCCESS)
- {
- Vallen=80;
-
- retCode = RegQueryValueEx(hKey,"FrameWindowSize",0,
- (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
-
- if (retCode == ERROR_SUCCESS)
- sscanf(Size,"%d,%d,%d,%d",&FRect.left,&FRect.right,&FRect.top,&FRect.bottom);
-
- if (FRect.top < - 500 || FRect.left < - 500)
- {
- FRect.left = 0;
- FRect.top = 0;
- FRect.right = 600;
- FRect.bottom = 400;
- }
-
-
- Vallen=80;
- retCode = RegQueryValueEx(hKey,"WindowSize",0,
- (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
-
- if (retCode == ERROR_SUCCESS)
- sscanf(Size,"%d,%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom, &ConsoleMinimized);
-
- if (Rect.top < - 500 || Rect.left < - 500)
- {
- Rect.left = 0;
- Rect.top = 0;
- Rect.right = 600;
- Rect.bottom = 400;
- }
-
- Vallen=80;
-
- retCode = RegQueryValueEx(hKey,"StatusWindowSize",0,
- (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
-
- if (retCode == ERROR_SUCCESS)
- sscanf(Size, "%d,%d,%d,%d,%d", &StatusRect.left, &StatusRect.right,
- &StatusRect.top, &StatusRect.bottom, &StatusMinimized);
-
- if (StatusRect.top < - 500 || StatusRect.left < - 500)
- {
- StatusRect.left = 0;
- StatusRect.top = 0;
- StatusRect.right = 850;
- StatusRect.bottom = 500;
- }
-
-
- // Get StartMinimized and MinimizetoTray flags
-
- Vallen = 4;
- retCode = RegQueryValueEx(hKey, "Start Minimized", 0, &Type, (UCHAR *)&StartMinimized, &Vallen);
-
- Vallen = 4;
- retCode = RegQueryValueEx(hKey, "Minimize to Tray", 0, &Type, (UCHAR *)&MinimizetoTray, &Vallen);
- }
-
- wndclassMainFrame.cbSize = sizeof(WNDCLASSEX);
- wndclassMainFrame.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
- wndclassMainFrame.lpfnWndProc = FrameWndProc;
- wndclassMainFrame.cbClsExtra = 0;
- wndclassMainFrame.cbWndExtra = 0;
- wndclassMainFrame.hInstance = hInstance;
- wndclassMainFrame.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON));
- wndclassMainFrame.hCursor = LoadCursor(NULL, IDC_ARROW);
- wndclassMainFrame.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
- wndclassMainFrame.lpszMenuName = NULL;
- wndclassMainFrame.lpszClassName = FrameClassName;
- wndclassMainFrame.hIconSm = NULL;
-
- if(!RegisterClassEx(&wndclassMainFrame))
- {
- return 0;
- }
-
- pindex = 0;
- PartLine = FALSE;
-
- bgBrush = CreateSolidBrush(BGCOLOUR);
-
-// hMainFrameMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME_MENU));
-
- hBaseMenu = LoadMenu(hInstance, MAKEINTRESOURCE(CONS_MENU));
- hConsMenu = GetSubMenu(hBaseMenu, 1);
- hWndMenu = GetSubMenu(hBaseMenu, 0);
-
- hTermMenu = LoadMenu(hInstance, MAKEINTRESOURCE(TERM_MENU));
- hTermActMenu = GetSubMenu(hTermMenu, 1);
- hTermCfgMenu = GetSubMenu(hTermMenu, 2);
- hTermEdtMenu = GetSubMenu(hTermMenu, 3);
- hTermHlpMenu = GetSubMenu(hTermMenu, 4);
-
- hMonMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MON_MENU));
- hMonCfgMenu = GetSubMenu(hMonMenu, 1);
- hMonEdtMenu = GetSubMenu(hMonMenu, 2);
- hMonHlpMenu = GetSubMenu(hMonMenu, 3);
-
- hMainFrameMenu = CreateMenu();
- AppendMenu(hMainFrameMenu, MF_STRING + MF_POPUP, (UINT)hWndMenu, "Window");
-
- //Create the main MDI frame window
-
- ClientWnd = NULL;
-
- FrameWnd = CreateWindow(FrameClassName,
- "BPQ32 Console",
- WS_OVERLAPPEDWINDOW |WS_CLIPCHILDREN,
- FRect.left,
- FRect.top,
- FRect.right - FRect.left,
- FRect.bottom - FRect.top,
- NULL, // handle to parent window
- hMainFrameMenu, // handle to menu
- hInstance, // handle to the instance of module
- NULL); // Long pointer to a value to be passed to the window through the
- // CREATESTRUCT structure passed in the lParam parameter the WM_CREATE message
-
-
- // Get Client Params
-
- if (FrameWnd == 0)
- {
- Debugprintf("SetupConsoleWindow Create Frame failed %d", GetLastError());
- return 0;
- }
-
- ShowWindow(FrameWnd, SW_RESTORE);
-
-
- GetWindowRect(FrameWnd, &FRect);
- OffsetH = FRect.bottom - FRect.top;
- OffsetW = FRect.right - FRect.left;
- GetClientRect(FrameWnd, &CRect);
- OffsetH -= CRect.bottom;
- OffsetW -= CRect.right;
- OffsetH -= 4;
-
- // Create Console Window
-
- wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
- wc.lpfnWndProc = (WNDPROC)WndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = DLGWINDOWEXTRA;
- wc.hInstance = hInstance;
- wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
- wc.lpszMenuName = 0;
- wc.lpszClassName = ClassName;
-
- i=RegisterClass(&wc);
-
- sprintf (Title, "BPQ32.dll Console Version %s", VersionString);
-
- hConsWnd = CreateMDIWindow(ClassName, "Console", 0,
- 0,0,0,0, ClientWnd, hInstance, 1234);
-
- i = GetLastError();
-
- if (!hConsWnd) {
- return (FALSE);
- }
-
- wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
- wc.lpfnWndProc = (WNDPROC)StatusWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = DLGWINDOWEXTRA;
- wc.hInstance = hInstance;
- wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
- wc.lpszMenuName = 0;
- wc.lpszClassName = "Status";
-
- i=RegisterClass(&wc);
-
- if (StatusRect.top < OffsetH) // Make sure not off top of MDI frame
- {
- int Error = OffsetH - StatusRect.top;
- StatusRect.top += Error;
- StatusRect.bottom += Error;
- }
-
- StatusWnd = CreateMDIWindow("Status", "Stream Status", 0,
- StatusRect.left, StatusRect.top, StatusRect.right - StatusRect.left,
- StatusRect.bottom - StatusRect.top, ClientWnd, hInstance, 1234);
-
- SetTimer(StatusWnd, 1, 1000, NULL);
-
- hPopMenu = GetSubMenu(hBaseMenu, 1) ;
-
- if (MinimizetoTray)
- CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_CHECKED);
- else
- CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_UNCHECKED);
-
- if (StartMinimized)
- CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_CHECKED);
- else
- CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_UNCHECKED);
-
- DrawMenuBar(hConsWnd);
-
- // setup default font information
-
- LFTTYFONT.lfHeight = 12;
- LFTTYFONT.lfWidth = 8 ;
- LFTTYFONT.lfEscapement = 0 ;
- LFTTYFONT.lfOrientation = 0 ;
- LFTTYFONT.lfWeight = 0 ;
- LFTTYFONT.lfItalic = 0 ;
- LFTTYFONT.lfUnderline = 0 ;
- LFTTYFONT.lfStrikeOut = 0 ;
- LFTTYFONT.lfCharSet = 0;
- LFTTYFONT.lfOutPrecision = OUT_DEFAULT_PRECIS ;
- LFTTYFONT.lfClipPrecision = CLIP_DEFAULT_PRECIS ;
- LFTTYFONT.lfQuality = DEFAULT_QUALITY ;
- LFTTYFONT.lfPitchAndFamily = FIXED_PITCH;
- lstrcpy(LFTTYFONT.lfFaceName, "FIXEDSYS" ) ;
-
- hFont = CreateFontIndirect(&LFTTYFONT) ;
-
- SetWindowText(hConsWnd,Title);
-
- if (Rect.right < 100 || Rect.bottom < 100)
- {
- GetWindowRect(hConsWnd, &Rect);
- }
-
- if (Rect.top < OffsetH) // Make sure not off top of MDI frame
- {
- int Error = OffsetH - Rect.top;
- Rect.top += Error;
- Rect.bottom += Error;
- }
-
-
- MoveWindow(hConsWnd, Rect.left - (OffsetW /2), Rect.top - OffsetH, Rect.right-Rect.left, Rect.bottom-Rect.top, TRUE);
-
- MoveWindow(StatusWnd, StatusRect.left - (OffsetW /2), StatusRect.top - OffsetH,
- StatusRect.right-StatusRect.left, StatusRect.bottom-StatusRect.top, TRUE);
-
- hWndCons = CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", "",
- WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
- LBS_DISABLENOSCROLL | LBS_NOSEL | WS_VSCROLL | WS_HSCROLL,
- Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top,
- hConsWnd, NULL, hInstance, NULL);
-
-// SendMessage(hWndCons, WM_SETFONT, hFont, 0);
-
- SendMessage(hWndCons, LB_SETHORIZONTALEXTENT , 1000, 0);
-
- if (ConsoleMinimized)
- ShowWindow(hConsWnd, SW_SHOWMINIMIZED);
- else
- ShowWindow(hConsWnd, SW_RESTORE);
-
- if (StatusMinimized)
- ShowWindow(StatusWnd, SW_SHOWMINIMIZED);
- else
- ShowWindow(StatusWnd, SW_RESTORE);
-
- ShowWindow(FrameWnd, SW_RESTORE);
-
-
- LoadLibrary("riched20.dll");
-
- if (StartMinimized)
- if (MinimizetoTray)
- ShowWindow(FrameWnd, SW_HIDE);
- else
- ShowWindow(FrameWnd, SW_SHOWMINIMIZED);
- else
- ShowWindow(FrameWnd, SW_RESTORE);
-
- CreateMonitorWindow(Size);
-
- return 0;
-}
-
-DllExport int APIENTRY SetupTrayIcon()
-{
- if (MinimizetoTray == 0)
- return 0;
-
- trayMenu = CreatePopupMenu();
-
- for( i = 0; i < 100; ++i )
- {
- if (strcmp(PopupText[i],"BPQ32 Console") == 0)
- {
- hWndArray[i] = FrameWnd;
- goto doneit;
- }
- }
-
- for( i = 0; i < 100; ++i )
- {
- if (hWndArray[i] == 0)
- {
- hWndArray[i] = FrameWnd;
- strcpy(PopupText[i],"BPQ32 Console");
- break;
- }
- }
-doneit:
-
- for( i = 0; i < 100; ++i )
- {
- if (hWndArray[i] != 0)
- AppendMenu(trayMenu,MF_STRING,TRAYBASEID+i,PopupText[i]);
- }
-
- // Set up Tray ICON
-
- ZeroMemory(&niData,sizeof(NOTIFYICONDATA));
-
- niData.cbSize = sizeof(NOTIFYICONDATA);
-
- // the ID number can be any UINT you choose and will
- // be used to identify your icon in later calls to
- // Shell_NotifyIcon
-
- niData.uID = TRAY_ICON_ID;
-
- // state which structure members are valid
- // here you can also choose the style of tooltip
- // window if any - specifying a balloon window:
- // NIF_INFO is a little more complicated
-
- strcpy(niData.szTip,"BPQ32 Windows");
-
- niData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
-
- // load the icon note: you should destroy the icon
- // after the call to Shell_NotifyIcon
-
- niData.hIcon =
-
- //LoadIcon(NULL, IDI_APPLICATION);
-
- (HICON)LoadImage( hInstance,
- MAKEINTRESOURCE(BPQICON),
- IMAGE_ICON,
- GetSystemMetrics(SM_CXSMICON),
- GetSystemMetrics(SM_CYSMICON),
- LR_DEFAULTCOLOR);
-
-
- // set the window you want to receive event messages
-
- niData.hWnd = FrameWnd;
-
- // set the message to send
- // note: the message value should be in the
- // range of WM_APP through 0xBFFF
-
- niData.uCallbackMessage = MY_TRAY_ICON_MESSAGE;
-
- // Call Shell_NotifyIcon. NIM_ADD adds a new tray icon
-
- if (Shell_NotifyIcon(NIM_ADD,&niData))
- Debugprintf("BPQ32 Create Tray Icon Ok");
-// else
-// Debugprintf("BPQ32 Create Tray Icon failed %d", GetLastError());
-
- return 0;
-}
-
-VOID SaveConfig()
-{
- HKEY hKey=0;
- int retCode, disp;
-
- retCode = RegCreateKeyEx(REGTREE,
- "SOFTWARE\\G8BPQ\\BPQ32",
- 0, // Reserved
- 0, // Class
- 0, // Options
- KEY_ALL_ACCESS,
- NULL, // Security Attrs
- &hKey,
- &disp);
-
- if (retCode == ERROR_SUCCESS)
- {
- retCode = RegSetValueEx(hKey, "Start Minimized", 0, REG_DWORD, (UCHAR *)&StartMinimized, 4);
- retCode = RegSetValueEx(hKey, "Minimize to Tray", 0, REG_DWORD, (UCHAR *)&MinimizetoTray, 4);
- }
-}
-
-LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- int wmId, wmEvent;
- POINT pos;
- HWND handle;
- RECT cRect;
-
- switch (message)
- {
- case WM_MDIACTIVATE:
-
- // Set the system info menu when getting activated
-
- if (lParam == (LPARAM) hWnd)
- {
- // Activate
-
- // GetSubMenu function should retrieve a handle to the drop-down menu or submenu.
-
- RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
- AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)hConsMenu, "Actions");
- SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hBaseMenu, (LPARAM) hWndMenu);
- }
- else
- {
- // Deactivate
-
- SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
- }
-
- DrawMenuBar(FrameWnd);
-
- return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
-
- case MY_TRAY_ICON_MESSAGE:
-
- switch(lParam)
- {
- case WM_RBUTTONUP:
- case WM_LBUTTONUP:
-
- GetCursorPos(&pos);
-
- SetForegroundWindow(hWnd);
-
- TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, hWnd, 0);
- return 0;
- }
-
- break;
-
- case WM_CTLCOLORDLG:
- return (LONG)bgBrush;
-
- case WM_COMMAND:
-
- wmId = LOWORD(wParam); // Remember, these are...
- wmEvent = HIWORD(wParam); // ...different for Win32!
-
- if (wmId == IDC_ENIGATE)
- {
- int retCode, disp;
- HKEY hKey=0;
-
- IGateEnabled = IsDlgButtonChecked(hWnd, IDC_ENIGATE);
-
- if (IGateEnabled)
- ISDelayTimer = 60;
-
- retCode = RegCreateKeyEx(REGTREE,
- "SOFTWARE\\G8BPQ\\BPQ32",
- 0, // Reserved
- 0, // Class
- 0, // Options
- KEY_ALL_ACCESS,
- NULL, // Security Attrs
- &hKey,
- &disp);
-
- if (retCode == ERROR_SUCCESS)
- {
- retCode = RegSetValueEx(hKey,"IGateEnabled", 0 , REG_DWORD,(BYTE *)&IGateEnabled, 4);
- RegCloseKey(hKey);
- }
-
- return 0;
- }
-
- if (wmId == BPQSAVENODES)
- {
- SaveNodes();
- WritetoConsole("Nodes Saved\n");
- return 0;
- }
- if (wmId == BPQCLEARRECONFIG)
- {
- if (!ProcessConfig())
- {
- MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
- return (0);
- }
-
- ClearNodes();
- WritetoConsole("Nodes file Cleared\n");
- ReconfigFlag=TRUE;
- WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n");
- return 0;
- }
- if (wmId == BPQRECONFIG)
- {
- if (!ProcessConfig())
- {
- MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
- return (0);
- }
- SaveNodes();
- WritetoConsole("Nodes Saved\n");
- ReconfigFlag=TRUE;
- WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n");
- return 0;
- }
-
- if (wmId == SCANRECONFIG)
- {
- if (!ProcessConfig())
- {
- MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
- return (0);
- }
-
- RigReconfigFlag = TRUE;
- WritetoConsole("Rigcontrol Reconfig requested ... Waiting for Timer Poll\n");
- return 0;
- }
-
- if (wmId == APRSRECONFIG)
- {
- if (!ProcessConfig())
- {
- MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
- return (0);
- }
-
- APRSReconfigFlag=TRUE;
- WritetoConsole("APRS Reconfig requested ... Waiting for Timer Poll\n");
- return 0;
- }
- if (wmId == BPQDUMP)
- {
- DumpSystem();
- return 0;
- }
-
- if (wmId == BPQCLOSEALL)
- {
- CloseAllPrograms();
- return 0;
- }
-
- if (wmId == BPQUICONFIG)
- {
- int err, i=0;
- char Title[80];
- WNDCLASS wc;
-
- wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.lpfnWndProc = UIWndProc;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = DLGWINDOWEXTRA;
- wc.hInstance = hInstance;
- wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON) );
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = bgBrush;
-
- wc.lpszMenuName = NULL;
- wc.lpszClassName = UIClassName;
-
- RegisterClass(&wc);
-
- UIhWnd = CreateDialog(hInstance, UIClassName,0,NULL);
-
- if (!UIhWnd)
- {
- err=GetLastError();
- return FALSE;
- }
-
- wsprintf(Title,"BPQ32 Beacon Utility Version");
- MySetWindowText(UIhWnd, Title);
- return 0;
- }
-
- if (wmId == BPQSAVEREG)
- {
- CreateRegBackup();
- return 0;
- }
-
- if (wmId == BPQMINTOTRAY)
- {
- MinimizetoTray = !MinimizetoTray;
-
- if (MinimizetoTray)
- CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_CHECKED);
- else
- CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_UNCHECKED);
-
- SaveConfig();
- return 0;
- }
-
- if (wmId == BPQSTARTMIN)
- {
- StartMinimized = !StartMinimized;
-
- if (StartMinimized)
- CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_CHECKED);
- else
- CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_UNCHECKED);
-
- SaveConfig();
- return 0;
- }
-
- if (wmId >= TRAYBASEID && wmId < (TRAYBASEID + 100))
- {
- handle=hWndArray[wmId-TRAYBASEID];
-
- if (handle == FrameWnd && FrameMaximized == TRUE)
- PostMessage(handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
- else
- PostMessage(handle, WM_SYSCOMMAND, SC_RESTORE, 0);
-
- SetForegroundWindow(handle);
- return 0;
- }
-
- case WM_SYSCOMMAND:
-
- wmId = LOWORD(wParam); // Remember, these are...
- wmEvent = HIWORD(wParam); // ...different for Win32!
-
- switch (wmId)
- {
- case SC_MINIMIZE:
-
- ConsoleMinimized = TRUE;
- break;
-
- case SC_RESTORE:
-
- ConsoleMinimized = FALSE;
- SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
-
- break;
- }
-
- return DefMDIChildProc(hWnd, message, wParam, lParam);
-
-
- case WM_SIZE:
-
- GetClientRect(hWnd, &cRect);
-
- MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
-
- if (APRSActive)
- MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
- else
- MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
-
-// InvalidateRect(hWnd, NULL, TRUE);
- break;
-
-/*
- case WM_PAINT:
-
- hdc = BeginPaint (hWnd, &ps);
-
- hOldFont = SelectObject( hdc, hFont) ;
-
- for (i=0; i 300)
- len = 300;
-
- memcpy(&buffptr[2], buff, len + 1);
-
- C_Q_ADD(&WritetoConsoleQ, buffptr);
-
- return 0;
-}
-
-int WritetoConsoleSupport(char * buff)
-{
-
- int len=strlen(buff);
- char Temp[2000]= "";
- char * ptr;
-
- if (PartLine)
- {
- SendMessage(hWndCons, LB_GETTEXT, pindex, (LPARAM)(LPCTSTR) Temp);
- SendMessage(hWndCons, LB_DELETESTRING, pindex, 0);
- PartLine = FALSE;
- }
-
- if ((strlen(Temp) + strlen(buff)) > 1990)
- Temp[0] = 0; // Should never have anything this long
-
- strcat(Temp, buff);
-
- ptr = strchr(Temp, '\n');
-
- if (ptr)
- *ptr = 0;
- else
- PartLine = TRUE;
-
- pindex=SendMessage(hWndCons, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR) Temp);
- return 0;
- }
-
-DllExport VOID APIENTRY BPQOutputDebugString(char * String)
-{
- OutputDebugString(String);
- return;
- }
-
-HANDLE handle;
-char fn[]="BPQDUMP";
-ULONG cnt;
-char * stack;
-//char screen[1920];
-//COORD ReadCoord;
-
-#define DATABYTES 400000
-
-extern UCHAR DATAAREA[];
-
-DllExport int APIENTRY DumpSystem()
-{
- char fn[200];
- char Msg[250];
-
- sprintf(fn,"%s\\BPQDUMP",BPQDirectory);
-
- handle = CreateFile(fn,
- GENERIC_WRITE,
- FILE_SHARE_READ,
- NULL,
- CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
-
-#ifndef _WIN64
-
- _asm {
-
- mov stack,esp
- }
-
- WriteFile(handle,stack,128,&cnt,NULL);
-#endif
-
-// WriteFile(handle,Screen,MAXLINELEN*MAXSCREENLEN,&cnt,NULL);
-
- WriteFile(handle,DATAAREA, DATABYTES,&cnt,NULL);
-
- CloseHandle(handle);
-
- sprintf(Msg, "Dump to %s Completed\n", fn);
- WritetoConsole(Msg);
-
- FindLostBuffers();
-
- return (0);
-}
-
-BOOLEAN CheckifBPQ32isLoaded()
-{
- HANDLE Mutex;
-
- // See if BPQ32 is running - if we create it in the NTVDM address space by
- // loading bpq32.dll it will not work.
-
- Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX");
-
- if (Mutex == NULL)
- {
- if (AttachingProcess == 0) // Already starting BPQ32
- {
- OutputDebugString("BPQ32 No other bpq32 programs running - Loading BPQ32.exe\n");
- StartBPQ32();
- }
- return FALSE;
- }
-
- CloseHandle(Mutex);
-
- return TRUE;
-}
-
-BOOLEAN StartBPQ32()
-{
- UCHAR Value[100];
-
- char bpq[]="BPQ32.exe";
- char *fn=(char *)&bpq;
- HKEY hKey=0;
- int ret,Type,Vallen=99;
-
- char Errbuff[100];
- char buff[20];
-
- STARTUPINFO StartupInfo; // pointer to STARTUPINFO
- PROCESS_INFORMATION ProcessInformation; // pointer to PROCESS_INFORMATION
-
- AttachingProcess = 1;
-
-// Get address of BPQ Directory
-
- Value[0]=0;
-
- ret = RegOpenKeyEx (REGTREE,
- "SOFTWARE\\G8BPQ\\BPQ32",
- 0,
- KEY_QUERY_VALUE,
- &hKey);
-
- if (ret == ERROR_SUCCESS)
- {
- ret = RegQueryValueEx(hKey, "BPQ Program Directory", 0, &Type,(UCHAR *)&Value, &Vallen);
-
- if (ret == ERROR_SUCCESS)
- {
- if (strlen(Value) == 2 && Value[0] == '"' && Value[1] == '"')
- Value[0]=0;
- }
-
-
- if (Value[0] == 0)
- {
-
- // BPQ Directory absent or = "" - "try Config File Location"
-
- ret = RegQueryValueEx(hKey,"BPQ Directory",0,
- &Type,(UCHAR *)&Value,&Vallen);
-
- if (ret == ERROR_SUCCESS)
- {
- if (strlen(Value) == 2 && Value[0] == '"' && Value[1] == '"')
- Value[0]=0;
- }
-
- }
- RegCloseKey(hKey);
- }
-
- if (Value[0] == 0)
- {
- strcpy(Value,fn);
- }
- else
- {
- strcat(Value,"\\");
- strcat(Value,fn);
- }
-
- StartupInfo.cb=sizeof(StartupInfo);
- StartupInfo.lpReserved=NULL;
- StartupInfo.lpDesktop=NULL;
- StartupInfo.lpTitle=NULL;
- StartupInfo.dwFlags=0;
- StartupInfo.cbReserved2=0;
- StartupInfo.lpReserved2=NULL;
-
- if (!CreateProcess(Value,NULL,NULL,NULL,FALSE,
- CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
- NULL,NULL,&StartupInfo,&ProcessInformation))
- {
- ret=GetLastError();
-
- _itoa(ret,buff,10);
-
- strcpy(Errbuff, "BPQ32 Load ");
- strcat(Errbuff,Value);
- strcat(Errbuff," failed ");
- strcat(Errbuff,buff);
- OutputDebugString(Errbuff);
- AttachingProcess = 0;
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-DllExport BPQVECSTRUC * APIENTRY GetIPVectorAddr()
-{
- return &IPHOSTVECTOR;
-}
-
-DllExport UINT APIENTRY GETSENDNETFRAMEADDR()
-{
- return (UINT)&SENDNETFRAME;
-}
-
-DllExport VOID APIENTRY RelBuff(VOID * Msg)
-{
- UINT * pointer, * BUFF = Msg;
-
- if (Semaphore.Flag == 0)
- Debugprintf("ReleaseBuffer called without semaphore");
-
- pointer = FREE_Q;
-
- *BUFF =(UINT)pointer;
-
- FREE_Q = BUFF;
-
- QCOUNT++;
-
- return;
-}
-
-extern int MINBUFFCOUNT;
-
-DllExport VOID * APIENTRY GetBuff()
-{
- UINT * Temp = Q_REM(&FREE_Q);
-
- if (Semaphore.Flag == 0)
- Debugprintf("GetBuff called without semaphore");
-
- if (Temp)
- {
- QCOUNT--;
-
- if (QCOUNT < MINBUFFCOUNT)
- MINBUFFCOUNT = QCOUNT;
- }
-
- return Temp;
-}
-
-
-VOID __cdecl Debugprintf(const char * format, ...)
-{
- char Mess[10000];
- va_list(arglist);
-
- va_start(arglist, format);
- vsprintf(Mess, format, arglist);
- strcat(Mess, "\r\n");
- OutputDebugString(Mess);
-
- return;
-}
-
-unsigned short int compute_crc(unsigned char *buf, int txlen);
-
-extern SOCKADDR_IN reportdest;
-
-extern SOCKET ReportSocket;
-
-extern SOCKADDR_IN Chatreportdest;
-
-DllExport VOID APIENTRY SendChatReport(SOCKET ChatReportSocket, char * buff, int txlen)
-{
- unsigned short int crc = compute_crc(buff, txlen);
-
- crc ^= 0xffff;
-
- buff[txlen++] = (crc&0xff);
- buff[txlen++] = (crc>>8);
-
- sendto(ChatReportSocket, buff, txlen, 0, (LPSOCKADDR)&Chatreportdest, sizeof(Chatreportdest));
-}
-
-VOID CreateRegBackup()
-{
- char Backup1[MAX_PATH];
- char Backup2[MAX_PATH];
- char RegFileName[MAX_PATH];
- char Msg[80];
- HANDLE handle;
- int len, written;
- char RegLine[300];
-
-// SHELLEXECUTEINFO sei;
-// STARTUPINFO SInfo;
-// PROCESS_INFORMATION PInfo;
-
- sprintf(RegFileName, "%s\\BPQ32.reg", BPQDirectory);
-
- // Keep 4 Generations
-
- strcpy(Backup2, RegFileName);
- strcat(Backup2, ".bak.3");
-
- strcpy(Backup1, RegFileName);
- strcat(Backup1, ".bak.2");
-
- DeleteFile(Backup2); // Remove old .bak.3
- MoveFile(Backup1, Backup2); // Move .bak.2 to .bak.3
-
- strcpy(Backup2, RegFileName);
- strcat(Backup2, ".bak.1");
-
- MoveFile(Backup2, Backup1); // Move .bak.1 to .bak.2
-
- strcpy(Backup1, RegFileName);
- strcat(Backup1, ".bak");
-
- MoveFile(Backup1, Backup2); //Move .bak to .bak.1
-
- strcpy(Backup2, RegFileName);
- strcat(Backup2, ".bak");
-
- CopyFile(RegFileName, Backup2, FALSE); // Copy to .bak
-
- handle = CreateFile(RegFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (handle == INVALID_HANDLE_VALUE)
- {
- sprintf(Msg, "Failed to open Registry Save File\n");
- WritetoConsole(Msg);
- return;
- }
-
- len = sprintf(RegLine, "Windows Registry Editor Version 5.00\r\n\r\n");
- WriteFile(handle, RegLine, len, &written, NULL);
-
- if (SaveReg("Software\\G8BPQ\\BPQ32", handle))
- WritetoConsole("Registry Save complete\n");
- else
- WritetoConsole("Registry Save failed\n");
-
- CloseHandle(handle);
- return ;
-/*
-
- if (REGTREE == HKEY_LOCAL_MACHINE) // < Vista
- {
- sprintf(cmd,
- "regedit /E \"%s\\BPQ32.reg\" %s\\Software\\G8BPQ\\BPQ32", BPQDirectory, REGTREETEXT);
-
- ZeroMemory(&SInfo, sizeof(SInfo));
-
- SInfo.cb=sizeof(SInfo);
- SInfo.lpReserved=NULL;
- SInfo.lpDesktop=NULL;
- SInfo.lpTitle=NULL;
- SInfo.dwFlags=0;
- SInfo.cbReserved2=0;
- SInfo.lpReserved2=NULL;
-
- if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0 ,NULL, NULL, &SInfo, &PInfo) == 0)
- {
- sprintf(Msg, "Error: CreateProcess for regedit failed 0%d\n", GetLastError() );
- WritetoConsole(Msg);
- return;
- }
- }
- else
- {
-
- sprintf(cmd,
- "/E \"%s\\BPQ32.reg\" %s\\Software\\G8BPQ\\BPQ32", BPQDirectory, REGTREETEXT);
-
- ZeroMemory(&sei, sizeof(sei));
-
- sei.cbSize = sizeof(SHELLEXECUTEINFOW);
- sei.hwnd = hWnd;
- sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
- sei.lpVerb = "runas";
- sei.lpFile = "regedit.exe";
- sei.lpParameters = cmd;
- sei.nShow = SW_SHOWNORMAL;
-
- if (!ShellExecuteEx(&sei))
- {
- sprintf(Msg, "Error: ShellExecuteEx for regedit failed %d\n", GetLastError() );
- WritetoConsole(Msg);
- return;
- }
- }
-
- sprintf(Msg, "Registry Save Initiated\n", fn);
- WritetoConsole(Msg);
-
- return ;
-*/
-}
-
-BOOL CALLBACK EnumForCloseProc(HWND hwnd, LPARAM lParam)
-{
- struct TNCINFO * TNC = (struct TNCINFO *)lParam;
- UINT ProcessId;
-
- GetWindowThreadProcessId(hwnd, &ProcessId);
-
- for (i=0; i< AttachedProcesses; i++)
- {
- if (AttachedPIDList[i] == ProcessId)
- {
- Debugprintf("BPQ32 Close All Closing PID %d", ProcessId);
- PostMessage(hwnd, WM_CLOSE, 1, 1);
- // AttachedPIDList[i] = 0; // So we don't do it again
- break;
- }
- }
-
- return (TRUE);
-}
-DllExport BOOL APIENTRY RestoreFrameWindow()
-{
- return ShowWindow(FrameWnd, SW_RESTORE);
-}
-
-DllExport VOID APIENTRY CreateNewTrayIcon()
-{
- Shell_NotifyIcon(NIM_DELETE,&niData);
- trayMenu = NULL;
-}
-
-DllExport VOID APIENTRY CloseAllPrograms()
-{
-// HANDLE hProc;
-
- // Close all attached BPQ32 programs
-
- Closing = TRUE;
-
- ShowWindow(FrameWnd, SW_RESTORE);
-
- GetWindowRect(FrameWnd, &FRect);
-
- SaveBPQ32Windows();
- CloseHostSessions();
-
- if (AttachedProcesses == 1)
- CloseBPQ32();
-
- Debugprintf("BPQ32 Close All Processes %d PIDS %d %d %d %d", AttachedProcesses, AttachedPIDList[0],
- AttachedPIDList[1], AttachedPIDList[2], AttachedPIDList[3]);
-
- if (MinimizetoTray)
- Shell_NotifyIcon(NIM_DELETE,&niData);
-
- EnumWindows(EnumForCloseProc, (LPARAM)NULL);
-}
-
-#define MAX_KEY_LENGTH 255
-#define MAX_VALUE_NAME 16383
-#define MAX_VALUE_DATA 65536
-
-BOOL CopyReg(HKEY hKeyIn, HKEY hKeyOut)
-{
- TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
- DWORD cbName; // size of name string
- TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
- DWORD cchClassName = MAX_PATH; // size of class string
- DWORD cSubKeys=0; // number of subkeys
- DWORD cbMaxSubKey; // longest subkey size
- DWORD cchMaxClass; // longest class string
- DWORD cValues; // number of values for key
- DWORD cchMaxValue; // longest value name
- DWORD cbMaxValueData; // longest value data
- DWORD cbSecurityDescriptor; // size of security descriptor
- FILETIME ftLastWriteTime; // last write time
-
- DWORD i, retCode;
-
- TCHAR achValue[MAX_VALUE_NAME];
- DWORD cchValue = MAX_VALUE_NAME;
-
- // Get the class name and the value count.
- retCode = RegQueryInfoKey(
- hKeyIn, // key handle
- achClass, // buffer for class name
- &cchClassName, // size of class string
- NULL, // reserved
- &cSubKeys, // number of subkeys
- &cbMaxSubKey, // longest subkey size
- &cchMaxClass, // longest class string
- &cValues, // number of values for this key
- &cchMaxValue, // longest value name
- &cbMaxValueData, // longest value data
- &cbSecurityDescriptor, // security descriptor
- &ftLastWriteTime); // last write time
-
- // Enumerate the subkeys, until RegEnumKeyEx fails.
-
- if (cSubKeys)
- {
- Debugprintf( "\nNumber of subkeys: %d\n", cSubKeys);
-
- for (i=0; i 76)
- {
- len += sprintf(&RegLine[len], "\\\r\n", RegLine);
- strcat(RegLine, "\\\r\n");
- WriteFile(hFile, RegLine, len, &written, NULL);
- strcpy(RegLine, " ");
- len = 2;
- }
-
- len += sprintf(&RegLine[len], "%02x,", Value[k]);
- }
- RegLine[--len] = 0x0d;
- RegLine[++len] = 0x0a;
- len++;
-
- break;
-
- case REG_DWORD: //( 4 ) // 32-bit number
-// case REG_DWORD_LITTLE_ENDIAN: //( 4 ) // 32-bit number (same as REG_DWORD)
-
- memcpy(&Intval, Value, 4);
- len = sprintf(RegLine, "\"%s\"=dword:%08x\r\n", achValue, Intval);
- break;
-
- case REG_DWORD_BIG_ENDIAN: //( 5 ) // 32-bit number
- break;
- case REG_LINK: //( 6 ) // Symbolic Link (unicode)
- break;
- case REG_MULTI_SZ: //( 7 ) // Multiple Unicode strings
-
- len = sprintf(RegLine, "\"%s\"=hex(7):%02x,00,", achValue, Value[0]);
- for (k = 1; k < ValLen; k++)
- {
- if (len > 76)
- {
- len += sprintf(&RegLine[len], "\\\r\n");
- WriteFile(hFile, RegLine, len, &written, NULL);
- strcpy(RegLine, " ");
- len = 2;
- }
-
- len += sprintf(&RegLine[len], "%02x,", Value[k]);
- if (len > 76)
- {
- len += sprintf(&RegLine[len], "\\\r\n");
- WriteFile(hFile, RegLine, len, &written, NULL);
- strcpy(RegLine, " ");
- }
- len += sprintf(&RegLine[len], "00,");
- }
-
- RegLine[--len] = 0x0d;
- RegLine[++len] = 0x0a;
- len++;
- break;
-
- case REG_RESOURCE_LIST: //( 8 ) // Resource list in the resource map
- break;
- case REG_FULL_RESOURCE_DESCRIPTOR: //( 9 ) // Resource list in the hardware description
- break;
- case REG_RESOURCE_REQUIREMENTS_LIST://( 10 )
- break;
- case REG_QWORD: //( 11 ) // 64-bit number
-// case REG_QWORD_LITTLE_ENDIAN: //( 11 ) // 64-bit number (same as REG_QWORD)
- break;
-
- }
-
- WriteFile(hFile, RegLine, len, &written, NULL);
- }
- }
- }
-
- WriteFile(hFile, "\r\n", 2, &written, NULL);
-
- // Enumerate the subkeys, until RegEnumKeyEx fails.
-
- if (cSubKeys)
- {
- for (i=0; i> 1;
- }
-
- Flags=GetApplFlags(i);
-
- if (OneBits > 1)
- sprintf(&NewScreen[(i+1)*54],"%2d%s%3d %3d %3d %03x %3x %10s%-20s",
- i, flag, RXCount(i), TXCount(i), MONCount(i), Mask, Flags, callsign,
- BPQHOSTVECTOR[i-1].PgmName);
- else
- sprintf(&NewScreen[(i+1)*54],"%2d%s%3d %3d %3d %3d %3x %10s%-20s",
- i, flag, RXCount(i), TXCount(i), MONCount(i), AppNumber, Flags, callsign,
- BPQHOSTVECTOR[i-1].PgmName);
-
- }
- }
-
- #include "StdExcept.c"
-
- if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId())
- FreeSemaphore(&Semaphore);
-
- }
-
- if (memcmp(Screen, NewScreen, 33 * 108) == 0) // No Change
- return 0;
-
- memcpy(Screen, NewScreen, 33 * 108);
- InvalidateRect(StatusWnd,NULL,FALSE);
-
- return(0);
-}
-
-LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- int wmId, wmEvent;
- PAINTSTRUCT ps;
- HDC hdc;
- HFONT hOldFont ;
- HGLOBAL hMem;
- MINMAXINFO * mmi;
- int i;
-
- switch (message)
- {
- case WM_TIMER:
-
- if (Semaphore.Flag == 0)
- DoStatus();
- break;
-
- case WM_MDIACTIVATE:
-
- // Set the system info menu when getting activated
-
- if (lParam == (LPARAM) hWnd)
- {
- // Activate
-
- RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
- AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)hConsMenu, "Actions");
- SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hBaseMenu, (LPARAM) hWndMenu);
- }
- else
- {
- SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
- }
-
- DrawMenuBar(FrameWnd);
-
- return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
-
- case WM_GETMINMAXINFO:
-
- mmi = (MINMAXINFO *)lParam;
- mmi->ptMaxSize.x = 850;
- mmi->ptMaxSize.y = 500;
- mmi->ptMaxTrackSize.x = 850;
- mmi->ptMaxTrackSize.y = 500;
-
-
- case WM_COMMAND:
-
- wmId = LOWORD(wParam); // Remember, these are...
- wmEvent = HIWORD(wParam); // ...different for Win32!
-
- //Parse the menu selections:
-
- switch (wmId)
- {
-
-/*
- case BPQSTREAMS:
-
- CheckMenuItem(hMenu,BPQSTREAMS,MF_CHECKED);
- CheckMenuItem(hMenu,BPQIPSTATUS,MF_UNCHECKED);
-
- StreamDisplay = TRUE;
-
- break;
-
- case BPQIPSTATUS:
-
- CheckMenuItem(hMenu,BPQSTREAMS,MF_UNCHECKED);
- CheckMenuItem(hMenu,BPQIPSTATUS,MF_CHECKED);
-
- StreamDisplay = FALSE;
- memset(Screen, ' ', 4000);
-
-
- break;
-
-*/
-
- case BPQCOPY:
-
- //
- // Copy buffer to clipboard
- //
- hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, 33*110);
-
- if (hMem != 0)
- {
- if (OpenClipboard(hWnd))
- {
-// CopyScreentoBuffer(GlobalLock(hMem));
- GlobalUnlock(hMem);
- EmptyClipboard();
- SetClipboardData(CF_TEXT,hMem);
- CloseClipboard();
- }
- else
- {
- GlobalFree(hMem);
- }
-
- }
-
- break;
-
- }
-
- return DefMDIChildProc(hWnd, message, wParam, lParam);
-
-
- case WM_SYSCOMMAND:
-
- wmId = LOWORD(wParam); // Remember, these are...
- wmEvent = HIWORD(wParam); // ...different for Win32!
-
- switch (wmId)
- {
- case SC_MAXIMIZE:
-
- break;
-
- case SC_MINIMIZE:
-
- StatusMinimized = TRUE;
- break;
-
- case SC_RESTORE:
-
- StatusMinimized = FALSE;
- SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
- break;
- }
-
- return DefMDIChildProc(hWnd, message, wParam, lParam);
-
- case WM_PAINT:
-
- hdc = BeginPaint (hWnd, &ps);
-
- hOldFont = SelectObject( hdc, hFont) ;
-
- for (i=0; i<33; i++)
- {
- TextOut(hdc,0,i*14,&Screen[i*108],108);
- }
-
- SelectObject( hdc, hOldFont ) ;
- EndPaint (hWnd, &ps);
-
- break;
-
- case WM_DESTROY:
-
-// PostQuitMessage(0);
-
- break;
-
-
- default:
-
- return DefMDIChildProc(hWnd, message, wParam, lParam);
-
- }
- return (0);
-}
-
-VOID SaveMDIWindowPos(HWND hWnd, char * RegKey, char * Value, BOOL Minimized)
-{
- HKEY hKey=0;
- char Size[80];
- char Key[80];
- int retCode, disp;
- RECT Rect;
-
- if (IsWindow(hWnd) == FALSE)
- return;
-
- ShowWindow(hWnd, SW_RESTORE);
-
- if (GetWindowRect(hWnd, &Rect) == FALSE)
- return;
-
- // Make relative to Frame
-
- Rect.top -= FRect.top ;
- Rect.left -= FRect.left;
- Rect.bottom -= FRect.top;
- Rect.right -= FRect.left;
-
- sprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\%s", RegKey);
-
- retCode = RegCreateKeyEx(REGTREE, Key, 0, 0, 0,
- KEY_ALL_ACCESS, NULL, &hKey, &disp);
-
- if (retCode == ERROR_SUCCESS)
- {
- sprintf(Size,"%d,%d,%d,%d,%d", Rect.left, Rect.right, Rect.top ,Rect.bottom, Minimized);
- retCode = RegSetValueEx(hKey, Value, 0, REG_SZ,(BYTE *)&Size, strlen(Size));
- RegCloseKey(hKey);
- }
-}
-
-extern int GPSPort;
-extern char LAT[]; // in standard APRS Format
-extern char LON[]; // in standard APRS Format
-
-VOID SaveBPQ32Windows()
-{
- HKEY hKey=0;
- char Size[80];
- int retCode, disp;
- PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
- int i;
-
- retCode = RegCreateKeyEx(REGTREE, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp);
-
- if (retCode == ERROR_SUCCESS)
- {
- sprintf(Size,"%d,%d,%d,%d", FRect.left, FRect.right, FRect.top, FRect.bottom);
- retCode = RegSetValueEx(hKey, "FrameWindowSize", 0, REG_SZ, (BYTE *)&Size, strlen(Size));
-
- // Save GPS Position
-
- if (GPSPort)
- {
- sprintf(Size, "%s, %s", LAT, LON);
- retCode = RegSetValueEx(hKey, "GPS", 0, REG_SZ,(BYTE *)&Size, strlen(Size));
- }
-
- RegCloseKey(hKey);
- }
-
- SaveMDIWindowPos(StatusWnd, "", "StatusWindowSize", StatusMinimized);
- SaveMDIWindowPos(hConsWnd, "", "WindowSize", ConsoleMinimized);
-
- for (i=0; iPORTCONTROL.PORTTYPE == 0x10) // External
- {
- if (PORTVEC->PORT_EXT_ADDR)
- {
- SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
- SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
- }
- }
- PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
- }
-
- SaveWindowPos(70); // Rigcontrol
-
-
- if (hIPResWnd)
- SaveMDIWindowPos(hIPResWnd, "", "IPResSize", IPMinimized);
-
- SaveHostSessions();
-}
-
-DllExport BOOL APIENTRY CheckIfOwner()
-{
- //
- // Returns TRUE if current process is root process
- // that loaded the DLL
- //
-
- if (TimerInst == GetCurrentProcessId())
-
- return (TRUE);
- else
- return (FALSE);
-}
-
-VOID GetParam(char * input, char * key, char * value)
-{
- char * ptr = strstr(input, key);
- char Param[2048];
- char * ptr1, * ptr2;
- char c;
-
-
- if (ptr)
- {
- ptr2 = strchr(ptr, '&');
- if (ptr2) *ptr2 = 0;
- strcpy(Param, ptr + strlen(key));
- if (ptr2) *ptr2 = '&'; // Restore string
-
- // Undo any % transparency
-
- ptr1 = Param;
- ptr2 = Param;
-
- c = *(ptr1++);
-
- while (c)
- {
- if (c == '%')
- {
- int n;
- int m = *(ptr1++) - '0';
- if (m > 9) m = m - 7;
- n = *(ptr1++) - '0';
- if (n > 9) n = n - 7;
-
- *(ptr2++) = m * 16 + n;
- }
- else if (c == '+')
- *(ptr2++) = ' ';
- else
- *(ptr2++) = c;
-
- c = *(ptr1++);
- }
-
- *(ptr2++) = 0;
-
- strcpy(value, Param);
- }
-}
-
-int GetListeningPortsPID(int Port)
-{
- MIB_TCPTABLE_OWNER_PID * TcpTable = NULL;
- PMIB_TCPROW_OWNER_PID Row;
- int dwSize = 0;
- DWORD n;
-
- // Get PID of process for this TCP Port
-
- // Get Length of table
-
- GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0);
-
- TcpTable = malloc(dwSize);
-
- if (TcpTable == NULL)
- return 0;
-
- GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0);
-
- for (n = 0; n < TcpTable->dwNumEntries; n++)
- {
- Row = &TcpTable->table[n];
-
- if (Row->dwLocalPort == Port && Row->dwState == MIB_TCP_STATE_LISTEN)
- {
- return Row->dwOwningPid;
- break;
- }
- }
- return 0; // Not found
-}
-
-DllExport char * APIENTRY GetLOC()
-{
- return LOC;
-}
-
-DllExport void APIENTRY GetLatLon(double * lat, double * lon)
-{
- *lat = LatFromLOC;
- *lon = LonFromLOC;
- return;
-}
-
-
-// UZ7HO Dll PTT interface
-
-// 1 ext_PTT_info
-// 2 ext_PTT_settings
-// 3 ext_PTT_OFF
-// 4 ext_PTT_ON
-// 5 ext_PTT_close
-// 6 ext_PTT_open
-
-extern struct RIGINFO * DLLRIG; // Rig record for dll PTT interface (currently only for UZ7HO);
-
-VOID Rig_PTT(struct TNCINFO * TNC, BOOL PTTState);
-VOID Rig_PTTEx(struct RIGINFO * RIG, BOOL PTTState, struct TNCINFO * TNC);
-
-int WINAPI ext_PTT_info()
-{
- return 0;
-}
-
-int WINAPI ext_PTT_settings()
-{
- return 0;
-}
-
-int WINAPI ext_PTT_OFF(int Port)
-{
- if (DLLRIG)
- Rig_PTTEx(DLLRIG, 0, 0);
-
- return 0;
-}
-
-int WINAPI ext_PTT_ON(int Port)
-{
- if (DLLRIG)
- Rig_PTTEx(DLLRIG, 1, 0);
-
- return 0;
-}
-int WINAPI ext_PTT_close()
-{
- if (DLLRIG)
- Rig_PTTEx(DLLRIG, 0, 0);
-
- return 0;
-}
-
-DllExport INT WINAPI ext_PTT_open()
-{
- return 1;
-}
-
-char * stristr (char *ch1, char *ch2)
-{
- char *chN1, *chN2;
- char *chNdx;
- char *chRet = NULL;
-
- chN1 = _strdup(ch1);
- chN2 = _strdup(ch2);
-
- if (chN1 && chN2)
- {
- chNdx = chN1;
- while (*chNdx)
- {
- *chNdx = (char) tolower(*chNdx);
- chNdx ++;
- }
- chNdx = chN2;
-
- while (*chNdx)
- {
- *chNdx = (char) tolower(*chNdx);
- chNdx ++;
- }
-
- chNdx = strstr(chN1, chN2);
-
- if (chNdx)
- chRet = ch1 + (chNdx - chN1);
- }
-
- free (chN1);
- free (chN2);
- return chRet;
-}
-
+/*
+Copyright 2001-2022 John Wiseman G8BPQ
+
+This file is part of LinBPQ/BPQ32.
+
+LinBPQ/BPQ32 is free software: you can redistribute it and/or modifyextern int HTTP
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+LinBPQ/BPQ32 is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
+*/
+//
+// 409l Oct 2001 Fix l3timeout for KISS
+//
+// 409m Oct 2001 Fix Crossband Digi
+//
+// 409n May 2002 Change error handling on load ext DLL
+
+// 409p March 2005 Allow Multidigit COM Ports (kiss.c)
+
+// 409r August 2005 Treat NULL string in Registry as use current directory
+// Allow shutdown to close BPQ Applications
+
+// 409s October 2005 Add DLL:Export entries to API for BPQTNC2
+
+// 409t January 2006
+//
+// Add API for Perl "GetPerlMsg"
+// Add API for BPQ1632 "GETBPQAPI" - returns address of Assembler API routine
+// Add Registry Entry "BPQ Directory". If present, overrides "Config File Location"
+// Add New API "GetBPQDirectory" - Returns location of config file
+// Add New API "ChangeSessionCallsign" - equivalent to "*** linked to" command
+// Rename BPQNODES to BPQNODES.dat
+// New API "GetAttachedProcesses" - returns number of processes connected.
+// Warn if user trys to close Console Window.
+// Add Debug entries to record Process Attach/Detach
+// Fix recovery following closure of first process
+
+// 409t Beta 2 February 2006
+//
+// Add API Entry "GetPortNumber"
+//
+// 409u February 2006
+//
+// Fix crash if allocate/deallocate called with stream=0
+// Add API to ch
+// Display config file path
+// Fix saving of Locked Node flag
+// Added SAVENODES SYSOP command
+//
+// 409u 2 March 2006
+//
+// Fix SetupBPQDirectory
+// Add CopyBPQDirectory (for Basic Programs)
+//
+// 409u 3 March 2006
+//
+// Release streams on DLL unload
+
+// 409v October 2006
+//
+// Support Minimize to Tray for all BPQ progams
+// Implement L4 application callsigns
+
+// 410 November 2006
+//
+// Modified to compile with C++ 2005 Express Edition
+// Make MCOM MTX MMASK local variables
+//
+// 410a January 2007
+//
+// Add program name to Attach-Detach messages
+// Attempt to detect processes which have died
+// Fix bug in NETROM and IFrame decode which would cause crash if frame was corrupt
+// Add BCALL - origin call for Beacons
+// Fix KISS ACKMODE ACK processing
+//
+
+// 410b November 2007
+//
+// Allow CTEXT of up to 510, and enforce PACLEN, fragmenting if necessary
+
+// 410c December 2007
+
+// Fix problem with NT introduced in V410a
+// Display location of DLL on Console
+
+// 410d January 2008
+
+// Fix crash in DLL Init caused by long path to program
+// Invoke Appl2 alias on C command (if enabled)
+// Allow C command to be disabled
+// Remove debug trap in GETRAWFRAME
+// Validate Alias of directly connected node, mainly for KPC3 DISABL Problem
+// Move Port statup code out of DLLInit (mainly for perl)
+// Changes to allow Load/Unload of bpq32.dll by appl
+// CloseBPQ32 API added
+// Ext Driver Close routes called
+// Changes to release Mutex
+
+// 410e May 2008
+
+// Fix missing SSID on last call of UNPROTO string (CONVTOAX25 in main.asm)
+// Fix VCOM Driver (RX Len was 1 byte too long)
+// Fix possible crash on L4CODE if L4DACK received out of sequence
+// Add basic IP decoding
+
+// 410f October 2008
+
+// Add IP Gateway
+// Add Multiport DIGI capability
+// Add GetPortDescription API
+// Fix potential hangs if RNR lost
+// Fix problem if External driver failes to load
+// Put pushad/popad round _INITIALISEPORTS (main.asm)
+// Add APIs GetApplCallVB and GetPortDescription (mainly for RMS)
+// Ensure Route Qual is updated if Port Qual changed
+// Add Reload Option, plus menu items for DUMP and SAVENODES
+
+// 410g December 2008
+
+// Restore API Exports BPQHOSTAPIPTR and MONDECODEPTR (accidentally deleted)
+// Fix changed init of BPQDirectory (accidentally changed)
+// Fix Checks for lost processes (accidentally deleted)
+// Support HDLC Cards on W2K and above
+// Delete Tray List entries for crashed processes
+// Add Option to NODES command to sort by Callsign
+// Add options to save or clear BPQNODES before Reconfig.
+// Fix Reconfig in Win98
+// Monitor buffering tweaks
+// Fix Init for large (>64k) tables
+// Fix Nodes count in Stats
+
+// 410h January 2009
+
+// Add Start Minimized Option
+// Changes to KISS for WIn98 Virtual COM
+// Open \\.\com instead of //./COM
+// Extra Dignostics
+
+// 410i Febuary 2009
+
+// Revert KISS Changes
+// Save Window positions
+
+// 410j June 2009
+
+// Fix tidying of window List when program crashed
+// Add Max Nodes to Stats
+// Don't update APPLnALIAS with received NODES info
+// Fix MH display in other timezones
+// Fix Possible crash when processing NETROM type Zero frames (eg NRR)
+// Basic INP3 Stuff
+// Add extra diagnostics to Lost Process detection
+// Process Netrom Record Route frames.
+
+// 410k June 2009
+
+// Fix calculation of %retries in extended ROUTES display
+// Fix corruption of ROUTES table
+
+// 410l October 2009
+
+// Add GetVersionString API call.
+// Add GetPortTableEntry API call
+// Keep links to neighbouring nodes open
+
+// Build 2
+
+// Fix PE in NOROUTETODEST (missing POP EBX)
+
+// 410m November 2009
+
+// Changes for PACTOR and WINMOR to support the ATTACH command
+// Enable INP3 if configured on a route.
+// Fix count of nodes in Stats Display
+// Overwrite the worst quality unused route if a call is received from a node not in your
+// table when the table is full
+
+// Build 5
+
+// Rig Control Interface
+// Limit KAM VHF attach and RADIO commands to authorised programs (MailChat and BPQTerminal)
+
+// Build 6
+
+// Fix reading INP3 Flag from BPQNODES
+
+// Build 7
+
+// Add MAXHOPS and MAXRTT config options
+
+// Build 8
+
+// Fix INP3 deletion of Application Nodes.
+// Fix GETCALLSIGN for Pactor Sessions
+// Add N Call* to display all SSID's of a call
+// Fix flow control on Pactor sessions.
+
+// Build 9
+
+// HDLC Support for XP
+// Add AUTH routines
+
+// Build 10
+
+// Fix handling commands split over more that one packet.
+
+// Build 11
+
+// Attach cmd changes for winmor disconnecting state
+// Option Interlock Winmor/Pactor ports
+
+// Build 12
+
+// Add APPLS export for winmor
+// Handle commands ending CR LF
+
+// Build 13
+
+// Incorporate Rig Control in Kernel
+
+// Build 14
+
+// Fix config reload for Rig COntrol
+
+// 410n March 2010
+
+// Implement C P via PACTOR/WINMOR (for Airmail)
+
+// Build 2
+
+// Don't flip SSID bits on Downlink Connect if uplink is Pactor/WINMOR
+// Fix resetting IDLE Timer on Pactor/WINMOR sessions
+// Send L4 KEEPLI messages based on IDLETIME
+
+// 410o July 2010
+
+// Read bpqcfg.txt instead of .bin
+// Support 32 bit MMASK (Allowing 32 Ports)
+// Support 32 bit _APPLMASK (Allowing 32 Applications)
+// Allow more commands
+// Allow longer command aliases
+// Fix logic error in RIGControl Port Initialisation (wasn't always raising RTS and DTR
+// Clear RIGControl RTS and DTR on close
+
+// 410o Build 2 August 2010
+
+// Fix couple of errors in config (needed APPLICATIONS and BBSCALL/ALIAS/QUAL)
+// Fix Kenwood Rig Control when more than one message received at once.
+// Save minimzed state of Rigcontrol Window
+
+// 410o Build 3 August 2010
+
+// Fix reporting of set errors in scan to a random session
+
+// 410o Build 4 August 2010
+
+// Change All xxx Ports are in use to no xxxx Ports are available if there are no sessions with _APPLMASK
+// Fix validation of TRANSDELAY
+
+// 410o Build 5 August 2010
+
+// Add Repeater Shift and Set Data Mode options to Rigcontrol (for ICOM only)
+// Add WINMOR and SCS Pactor mode control option to RigControl
+// Extend INFOMSG to 2000 bytes
+// Improve Scan freq change lock (check both SCS and WINMOR Ports)
+
+// 410o Build 6 September 2010
+
+// Incorporate IPGateway in main code.
+// Fix GetSessionInfo for Pactor/Winmor Ports
+// Add Antenna Selection to RigControl
+// Allow Bandwidth options on RADIO command line (as well as in Scan definitions)
+
+// 410o Build 7 September 2010
+
+// Move rigconrtol display to driver windows
+// Move rigcontrol config to driver config.
+// Allow driver and IPGateway config info in bpq32.cfg
+// Move IPGateway, AXIP, VKISS, AGW and WINMOR drivers into bpq32.dll
+// Add option to reread IP Gateway config.
+// Fix Reinit after process with timer closes (error in TellSessions).
+
+// 410p Build 2 October 2010
+
+// Move KAM and SCS drivers to bpq32.dll
+
+// 410p Build 3 October 2010
+
+// Support more than one axip port.
+
+// 410p Build 4 October 2010
+
+// Dynamically load psapi.dll (for 98/ME)
+
+// 410p Build 5 October 2010
+
+// Incorporate TelnetServer
+// Fix AXIP ReRead Config
+// Report AXIP accept() fails to syslog, not a popup.
+
+// 410p Build 6 October 2010
+
+// Includes HAL support
+// Changes to Pactor Drivers disconnect code
+// AXIP now sends with source port = dest port, unless overridden by SOURCEPORT param
+// Config now checks for duplicate port definitions
+// Add Node Map reporting
+// Fix WINMOR deferred disconnect.
+// Report Pactor PORTCALL to WL2K instead of RMS Applcall
+
+// 410p Build 7 October 2010
+
+// Add In/Out flag to Map reporting, and report centre, not dial
+// Write Telnet log to BPQ Directory
+// Add Port to AXIP resolver display
+// Send Reports to update.g8bpq.net:81
+// Add support for FT100 to Rigcontrol
+// Add timeout to Rigcontrol PTT
+// Add Save Registry Command
+
+// 410p Build 8 November 2010
+
+// Add NOKEEPALIVES Port Param
+// Renumbered for release
+
+// 410p Build 9 November 2010
+
+// Get Bandwith for map report from WL2K Report Command
+// Fix freq display for FT100 (was KHz, not MHz)
+// Don't try to change SCS mode whilst initialising
+// Allow reporting of Lat/Lon as well as Locator
+// Fix Telnet Log Name
+// Fix starting with Minimized windows when Minimizetotray isn't set
+// Extra Program Error trapping in SessionControl
+// Fix reporting same freq with different bandwidths at different times.
+// Code changes to support SCS Robust Packet Mode.
+// Add FT2000 to Rigcontrol
+// Only Send CTEXT to connects to Node (not to connects to an Application Call)
+
+// Released as Build 10
+
+// 410p Build 11 January 2011
+
+// Fix MH Update for SCS Outgoing Calls
+// Add Direct CMS Access to TelnetServer
+// Restructure DISCONNECT processing to run in Timer owning process
+
+// 410p Build 12 January 2011
+
+// Add option for Hardware PTT to use a different com port from the scan port
+// Add CAT PTT for Yaesu 897 (and maybe others)
+// Fix RMS Packet ports busy after restart
+// Fix CMS Telnet with MAXSESSIONS > 10
+
+// 410p Build 13 January 2011
+
+// Fix loss of buffers in TelnetServer
+// Add CMS logging.
+// Add non - Promiscuous mode option for BPQETHER
+
+// 410p Build 14 January 2011
+
+// Add support for BPQTermTCP
+// Allow more that one FBBPORT
+// Allow Telnet FBB mode sessions to send CRLF as well as CR on user and pass msgs
+// Add session length to CMS Telnet logging.
+// Return Secure Session Flag from GetConnectionInfo
+// Show Uptime as dd/hh/mm
+
+// 4.10.16.17 March 2011
+
+// Add "Close all programs" command
+// Add BPQ Program Directory registry key
+// Use HKEY_CURRENT_USER on Vista and above (and move registry if necessary)
+// Time out IP Gateway ARP entries, and only reload ax.25 ARP entries
+// Add support for SCS Tracker HF Modes
+// Fix WL2K Reporting
+// Report Version to WL2K
+// Add Driver to support Tracker with multiple sessions (but no scanning, wl2k report, etc)
+
+
+// Above released as 5.0.0.1
+
+// 5.2.0.1
+
+// Add caching of CMS Server IP addresses
+// Initialise TNC State on Pactor Dialogs
+// Add Shortened (6 digit) AUTH mode.
+// Update MH with all frames (not just I/UI)
+// Add IPV6 Support for TelnetServer and AXIP
+// Fix TNC OK Test for Tracker
+// Fix crash in CMS mode if terminal disconnects while tcp commect in progress
+// Add WL2K reporting for Robust Packet
+// Add option to suppress WL2K reporting for specific frequencies
+// Fix Timeband processing for Rig Control
+// New Driver for SCS Tracker allowing multiple connects, so Tracker can be used for user access
+// New Driver for V4 TNC
+
+// 5.2.1.3 October 2011
+
+// Combine busy detector on Interlocked Ports (SCS PTC, WINMOR or KAM)
+// Improved program error logging
+// WL2K reporting changed to new format agreed with Lee Inman
+
+// 5.2.3.1 January 2012
+
+// Connects from the console to an APPLCALL or APPLALIAS now invoke any Command Alias that has been defined.
+// Fix reporting of Tracker freqs to WL2K.
+// Fix Tracker monitoring setup (sending M UISC)
+// Fix possible call/application routing error on RP
+// Changes for P4Dragon
+// Include APRS Digi/IGate
+// Tracker monitoring now includes DIGIS
+// Support sending UI frames using SCSTRACKER, SCTRKMULTI and UZ7HO drivers
+// Include driver for UZ7HO soundcard modem.
+// Accept DRIVER as well as DLLNAME, and COMPORT as well as IOADDR in bpq32.cfg. COMPORT is decimal
+// No longer supports separate config files, or BPQTELNETSERVER.exe
+// Improved flow control for Telnet CMS Sessions
+// Fix handling Config file without a newline after last line
+// Add non - Promiscuous mode option for BPQETHER
+// Change Console Window to a Dialog Box.
+// Fix possible corruption and loss of buffers in Tracker drivers
+// Add Beacon After Session option to Tracker and UZ7HO Drivers
+// Rewrite RigControl and add "Reread Config Command"
+// Support User Mode VCOM Driver for VKISS ports
+
+// 5.2.4.1 January 2012
+
+// Remove CR from Telnet User and Password Prompts
+// Add Rigcontrol to UZ7HO driver
+// Fix corruption of Free Buffer Count by Rigcontol
+// Fix WINMOR and V4 PTT
+// Add MultiPSK Driver
+// Add SendBeacon export for BPQAPRS
+// Add SendChatReport function
+// Fix check on length of Port Config ID String with trailing spaces
+// Fix interlock when Port Number <> Port Slot
+// Add NETROMCALL for L3 Activity
+// Add support for APRS Application
+// Fix Telnet with FBBPORT and no TCPPORT
+// Add Reread APRS Config
+// Fix switching to Pactor after scanning in normal packet mode (PTC)
+
+// 5.2.5.1 February 2012
+
+// Stop reading Password file.
+// Add extra MPSK commands
+// Fix MPSK Transparency
+// Make LOCATOR command compulsory
+// Add MobileBeaconInterval APRS param
+// Send Course and Speed when APRS is using GPS
+// Fix Robust Packet reporting in PTC driver
+// Fix corruption of some MIC-E APRS packets
+
+// 5.2.6.1 February 2012
+
+// Convert to MDI presentation of BPQ32.dll windows
+// Send APRS Status packets
+// Send QUIT not EXIT in PTC Init
+// Implement new WL2K reporting format and include traffic reporting info in CMS signon
+// New WL2KREPORT format
+// Prevent loops when APPL alias refers to itself
+// Add RigControl for Flex radios and ICOM IC-M710 Marine radio
+
+// 5.2.7.1
+
+// Fix opening more thn one console window on Win98
+// Change method of configuring multiple timelots on WL2K reporting
+// Add option to update WK2K Sysop Database
+// Add Web server
+// Add UIONLY port option
+
+// 5.2.7.2
+
+// Fix handling TelnetServer packets over 500 bytes in normal mode
+
+// 5.2.7.3
+
+// Fix Igate handling packets from UIView
+
+// 5.2.7.4
+
+// Prototype Baycom driver.
+
+// 5.2.7.5
+
+// Set WK2K group ref to MARS (3) if using a MARS service code
+
+// 5.2.7.7
+
+// Check for programs calling CloseBPQ32 when holding semaphore
+// Try/Except round Status Timer Processing
+
+// 5.2.7.8
+
+// More Try/Except round Timer Processing
+
+// 5.2.7.9
+
+// Enable RX in Baycom, and remove test loopback in tx
+
+// 5.2.7.10
+
+// Try/Except round ProcessHTTPMessage
+
+// 5.2.7.11
+
+// BAYCOM tweaks
+
+// 5.2.7.13
+
+// Release semaphore after program error in Timer Processing
+// Check fro valid dest in REFRESHROUTE
+
+
+// Add TNC-X KISSOPTION (includes the ACKMODE bytes in the checksum(
+
+// Version 5.2.9.1 Sept 2012
+
+// Fix using KISS ports with COMn > 16
+// Add "KISS over UDP" driver for PI as a TNC concentrator
+
+// Version 6.0.1.1
+
+// Convert to C for linux portability
+// Try to speed up kiss polling
+
+// Version 6.0.2.1
+
+// Fix operation on Win98
+// Fix callsign error with AGWtoBPQ
+// Fix PTT problem with WINMOR
+// Fix Reread telnet config
+// Add Secure CMS signon
+// Fix error in cashing addresses of CMS servers
+// Fix Port Number when using Send Raw.
+// Fix PE in KISS driver if invalid subchannel received
+// Fix Orignal address of beacons
+// Speed up Telnet port monitoring.
+// Add TNC Emulators
+// Add CountFramesQueuedOnStream API
+// Limit number of frames that can be queued on a session.
+// Add XDIGI feature
+// Add Winmor Robust Mode switching for compatibility with new Winmor TNC
+// Move most APRS code from BPQAPRS to here
+// Stop corruption caused by overlong KISS frames
+
+// Version 6.0.3.1
+
+// Add starting/killing WINMOR TNC on remote host
+// Fix Program Error when APRS Item or Object name is same as call of reporting station
+// Dont digi a frame that we have already digi'ed
+// Add ChangeSessionIdleTime API
+// Add WK2KSYSOP Command
+// Add IDLETIME Command
+// Fix Errors in RELAYAPPL processing
+// Fix PE cauaed by invalid Rigcontrol Line
+
+// Version 6.0.4.1
+
+// Add frequency dependent autoconnect appls for SCS Pactor
+// Fix DED Monitoring of I and UI with no data
+// Include AGWPE Emulator (from AGWtoBPQ)
+// accept DEL (Hex 7F) as backspace in Telnet
+// Fix re-running resolver on re-read AXIP config
+// Speed up processing, mainly for Telnet Sessions
+// Fix APRS init on restart of bpq32.exe
+// Change to 2 stop bits
+// Fix scrolling of WINMOR trace window
+// Fix Crash when ueing DED TNC Emulator
+// Fix Disconnect when using BPQDED2 Driver with Telnet Sessions
+// Allow HOST applications even when CMS option is disabled
+// Fix processing of APRS DIGIMAP command with no targets (didn't suppress default settings)
+
+// Version 6.0.5.1 January 2014
+
+// Add UTF8 conversion mode to Telnet (converts non-UTF-8 chars to UTF-8)
+// Add "Clear" option to MH command
+// Add "Connect to RMS Relay" Option
+// Revert to one stop bit on serial ports, explictly set two on FT2000 rig control
+// Fix routing of first call in Robust Packet
+// Add Options to switch input source on rigs with build in soundcards (sor far only IC7100 and Kenwood 590)
+// Add RTS>CAT PTT option for Sound Card rigs
+// Add Clear Nodes Option (NODE DEL ALL)
+// SCS Pactor can set differeant APPLCALLS when scanning.
+// Fix possible Scan hangup after a manual requency change with SCS Pactor
+// Accept Scan entry of W0 to disable WINMOR on that frequency
+// Fix corruption of NETROMCALL by SIMPLE config command
+// Enforce Pactor Levels
+// Add Telnet outward connect
+// Add Relay/Trimode Emulation
+// Fix V4 Driver
+// Add PTT Mux
+// Add Locked ARP Entries (via bpq32.cfg)
+// Fix IDLETIME node command
+// Fix STAY param on connect
+// Add STAY option to Attach and Application Commands
+// Fix crash on copying a large AXIP MH Window
+// Fix possible crash when bpq32.exe dies
+// Fix DIGIPORT for UI frames
+
+// Version 6.0.6.1 April 2014
+
+// FLDigi Interface
+// Fix "All CMS Servers are inaccessible" message so Mail Forwarding ELSE works.
+// Validate INP3 messages to try to prevent crash
+// Fix possible crash if an overlarge KISS frame is received
+// Fix error in AXR command
+// Add LF to Telnet Outward Connect signin if NEEDLF added to connect line
+// Add CBELL to TNC21 emulator
+// Add sent objects and third party messages to APRS Dup List
+// Incorporate UIUtil
+// Use Memory Mapped file to pass APRS info to BPQAPRS, and process APRS HTTP in BPQ32
+// Improvements to FLDIGI interlocking
+// Fix TNC State Display for Tracker
+// Cache CMS Addresses on LinBPQ
+// Fix count error on DED Driver when handling 256 byte packets
+// Add basic SNMP interface for MRTG
+// Fix memory loss from getaddrinfo
+// Process "BUSY" response from Tracker
+// Handle serial port writes that don't accept all the data
+// Trap Error 10038 and try to reopen socket
+// Fix crash if overlong command line received
+
+// Version 6.0.7.1 Aptil 2014
+// Fix RigContol with no frequencies for Kenwood and Yaesu
+// Add busy check to FLDIGI connects
+
+// Version 6.0.8.1 August 2014
+
+// Use HKEY_CURRENT_USER on all OS versions
+// Fix crash when APRS symbol is a space.
+// Fixes for FT847 CAT
+// Fix display of 3rd byte of FRMR
+// Add "DEFAULT ROBUST" and "FORCE ROBUST" commands to SCSPactor Driver
+// Fix possible memory corruption in WINMOR driver
+// Fix FT2000 Modes
+// Use new WL2K reporting system (Web API Based)
+// APRS Server now cycles through hosts if DNS returns more than one
+// BPQ32 can now start and stop FLDIGI
+// Fix loss of AXIP Resolver when running more than one AXIP port
+
+// Version 6.0.9.1 November 2014
+
+// Fix setting NOKEEPALIVE flag on route created from incoming L3 message
+// Ignore NODES from locked route with quality 0
+// Fix seting source port in AXIP
+// Fix Dual Stack (IPV4/V6) on Linux.
+// Fix RELAYSOCK if IPv6 is enabled.
+// Add support for FT1000
+// Fix hang when APRS Messaging packet received on RF
+// Attempt to normalize Node qualies when stations use widely differing Route qualities
+// Add NODES VIA command to display nodes reachable via a specified neighbour
+// Fix applying "DisconnectOnClose" setting on HOST API connects (Telnet Server)
+// Fix buffering large messages in Telnet Host API
+// Fix occasional crash in terminal part line processing
+// Add "NoFallback" command to Telnet server to disable "fallback to Relay"
+// Improved support for APPLCALL scanning with Pactor
+// MAXBUFFS config statement is no longer needed.
+// Fix USEAPPLCALLS with Tracker when connect to APPLCALL fails
+// Implement LISTEN and CQ commands
+// FLDIGI driver can now start FLDIGI on a remote system.
+// Add IGNOREUNLOCKEDROUTES parameter
+// Fix error if too many Telnet server connections
+
+// Version 6.0.10.1 Feb 2015
+
+// Fix crash if corrupt HTML request received.
+// Allow SSID's of 'R' and 'T' on non-ax.25 ports for WL2K Radio Only network.
+// Make HTTP server HTTP Version 1.1 complient - use persistent conections and close after 2.5 mins
+// Add INP3ONLY flag.
+// Fix program error if enter UNPROTO without a destination path
+// Show client IP address on HTTP sessions in Telnet Server
+// Reduce frequency and number of attempts to connect to routes when Keepalives or INP3 is set
+// Add FT990 RigControl support, fix FT1000MP support.
+// Support ARMV5 processors
+// Changes to support LinBPQ APRS Client
+// Add IC7410 to supported Soundcard rigs
+// Add CAT PTT to NMEA type (for ICOM Marine Radios_
+// Fix ACKMODE
+// Add KISS over TCP
+// Support ACKMode on VKISS
+// Improved reporting of configuration file format errors
+// Experimental driver to support ARQ sessions using UI frames
+
+// Version 6.0.11.1 September 2015
+
+// Fixes for IPGateway configuration and Virtual Circuit Mode
+// Separate Portmapper from IPGateway
+// Add PING Command
+// Add ARDOP Driver
+// Add basic APPLCALL support for PTC-PRO/Dragon 7800 Packet (using MYALIAS)
+// Add "VeryOldMode" for KAM Version 5.02
+// Add KISS over TCP Slave Mode.
+// Support Pactor and Packet on P4Dragon on one port
+// Add "Remote Staton Quality" to Web ROUTES display
+// Add Virtual Host option for IPGateway NET44 Encap
+// Add NAT for local hosts to IPGateway
+// Fix setting filter from RADIO command for IC7410
+// Add Memory Channel Scanning for ICOM Radios
+// Try to reopen Rig Control port if it fails (could be unplugged USB)
+// Fix restoring position of Monitor Window
+// Stop Codec on Winmor and ARDOP when an interlocked port is attached (instead of listen false)
+// Support APRS beacons in RP mode on Dragon//
+// Change Virtual MAC address on IPGateway to include last octet of IP Address
+// Fix "NOS Fragmentation" in IP over ax.25 Virtual Circuit Mode
+// Fix sending I frames before L2 session is up
+// Fix Flow control on Telnet outbound sessions.
+// Fix reporting of unterminatred comments in config
+// Add option for RigControl to not change mode on FT100/FT990/FT1000
+// Add "Attach and Connect" for Telnet ports
+
+// Version 6.0.12.1 November 2015
+
+// Fix logging of IP addresses for connects to FBBPORT
+// Allow lower case user and passwords in Telnet "Attach and Connect"
+// Fix possible hang in KISS over TCP Slave mode
+// Fix duplicating LinBPQ process if running ARDOP fails
+// Allow lower case command aliases and increase alias length to 48
+// Fix saving long IP frames pending ARP resolution
+// Fix dropping last entry from a RIP44 message.
+// Fix displaying Digis in MH list
+// Add port name to Monitor config screen port list
+// Fix APRS command display filter and add port filter
+// Support port names in BPQTermTCP Monitor config
+// Add FINDBUFFS command to dump lost buffers to Debugview/Syslog
+// Buffer Web Mgmt Edit Config output
+// Add WebMail Support
+// Fix not closing APRS Send WX file.
+// Add RUN option to APRS Config to start APRS Client
+// LinBPQ run FindLostBuffers and exit if QCOUNT < 5
+// Close and reopen ARDOP connection if nothing received for 90 secs
+// Add facility to bridge traffic between ports (similar to APRS Bridge but for all frame types)
+// Add KISSOPTION TRACKER to set SCS Tracker into KISS Mode
+
+// 6.0.13.1
+
+// Allow /ex to exit UNPROTO mode
+// Support ARQBW commands.
+// Support IC735
+// Fix sending ARDOP beacons after a busy holdoff
+// Enable BPQDED driver to beacon via non-ax.25 ports.
+// Fix channel number in UZ7HO monitoring
+// Add SATGate mode to APRSIS Code.
+// Fix crash caused by overlong user name in telnet logon
+// Add option to log L4 connects
+// Add AUTOADDQuiet mode to AXIP.
+// Add EXCLUDE processing
+// Support WinmorControl in UZ7HO driver and fix starting TNC on Linux
+// Convert calls in MAP entries to upper case.
+// Support Linux COM Port names for APRS GPS
+// Fix using NETROM serial protocol on ASYNC Port
+// Fix setting MYLEVEL by scanner after manual level change.
+// Add DEBUGLOG config param to SCS Pactor Driver to log serial port traffic
+// Uue #myl to set SCS Pactor MYLEVEL, and add checklevel command
+// Add Multicast RX interface to FLDIGI Driver
+// Fix processing application aliases to a connect command.
+// Fix Buffer loss if radio connected to PTC rig port but BPQ not configured to use it
+// Save backups of bpq32.cfg when editing with Web interface and report old and new length
+// Add DD command to SCS Pactor, and use it for forced disconnect.
+// Add ARDOP mode select to scan config
+// ARDOP changes for ARDOP V 0.5+
+// Flip SSID bits on UZ7HO downlink connects
+
+
+// Version 6.0.14.1
+
+// Fix Socket leak in ARDOP and FLDIGI drivers.
+// Add option to change CMS Server hostname
+// ARDOP Changes for 0.8.0+
+// Discard Terminal Keepalive message (two nulls) in ARDOP command hander
+// Allow parameters to be passed to ARDOP TNC when starting it
+// Fix Web update of Beacon params
+// Retry connects to KISS ports after failure
+// Add support for ARDOP Serial Interface Native mode.
+// Fix gating APRS-IS Messages to RF
+// Fix Beacons when PORTNUM used
+// Make sure old monitor flag is cleared for TermTCP sessions
+// Add CI-V antenna control for IC746
+// Don't allow ARDOP beacons when connected
+// Add support for ARDOP Serial over I2C
+// Fix possble crash when using manual RADIO messages
+// Save out of sequence L2 frames for possible reuse after retry
+// Add KISS command to send KISS control frame to TNC
+// Stop removing unused digis from packets sent to APRS-IS
+
+// Processing of ARDOP PING and PINGACK responses
+// Handle changed encoding of WL2K update responses.
+// Allow anonymous logon to telnet
+// Don't use APPL= for RP Calls in Dragon Single mode.
+// Add basic messaging page to APRS Web Server
+// Add debug log option to SCSTracker and TrkMulti Driver
+// Support REBOOT command on LinBPQ
+// Allow LISTEN command on all ports that support ax.25 monitoring
+
+// Version 6.0.15.1 Feb 2018
+
+// partial support for ax.25 V2.2
+// Add MHU and MHL commands and MH filter option
+// Fix scan interlock with ARDOP
+// Add Input source seiect for IC7300
+// Remove % transparency from web terminal signon message
+// Fix L4 Connects In count on stats
+// Fix crash caused by corrupt CMSInfo.txt
+// Add Input peaks display to ARDOP status window
+// Add options to show time in local and distances in KM on APRS Web pages
+// Add VARA support
+// Fix WINMOR Busy left set when port Suspended
+// Add ARDOP-Packet Support
+// Add Antenna Switching for TS 480
+// Fix possible crash in Web Terminal
+// Support different Code Pages on Console sessions
+// Use new Winlink API interface (api.winlink.org)
+// Support USB/ACC switching on TS590SG
+// Fix scanning when ARDOP or WINMOR is used without an Interlocked Pactor port.
+// Set NODECALL to first Application Callsign if NODE=0 and BBSCALL not set.
+// Add RIGCONTROL TUNE and POWER commands for some ICOM and Kenwwod rigs
+// Fix timing out ARDOP PENDING Lock
+// Support mixed case WINLINK Passwords
+// Add TUNE and POWER Rigcontol Commands for some radios
+// ADD LOCALTIME and DISPKM options to APRS Digi/Igate
+
+// 6.0.16.1 March 2018
+
+// Fix Setting data mode and filter for IC7300 radios
+// Add VARA to WL2KREPORT
+// Add trace to SCS Tracker status window
+// Fix possible hang in IPGATEWAY
+// Add BeacontoIS parameter to APRSDIGI. Allows you to stop sending beacons to APRS-IS.
+// Fix sending CTEXT on WINMOR sessions
+
+// 6.0.17.1 November 2018
+
+// Change WINMOR Restart after connection to Restart after Failure and add same option to ARDOP and VARA
+// Add Abort Connection to WINMOR and VARA Interfaces
+// Reinstate accidentally removed CMS Access logging
+// Fix MH CLEAR
+// Fix corruption of NODE table if NODES received from station with null alias
+// Fix loss of buffer if session closed with something in PARTCMDBUFFER
+// Fix Spurious GUARD ZONE CORRUPT message in IP Code.
+// Remove "reread bpq32.cfg and reconfigure" menu options
+// Add support for PTT using CM108 based soundcard interfaces
+// Datestamp Telnet log files and delete old Telnet and CMSAcces logs
+
+// 6.0.18.1 January 2019
+
+// Fix validation of NODES broadcasts
+// Fix HIDENODES
+// Check for failure to reread config on axip reconfigure
+// Fix crash if STOPPORT or STARTPORT used on KISS over TCP port
+// Send Beacons from BCALL or PORTCALL if configured
+// Fix possible corruption of last entry in MH display
+// Ensure RTS/DTR is down when opening PTT Port
+// Remove RECONFIG command
+// Preparations for 64 bit version
+
+// 6.0.19 Sept 2019
+// Fix UZ7HO interlock
+// Add commands to set Centre Frequency and Modem with UZ7HO Soundmodem (on Windows only)
+// Add option to save and restore MH lists and SAVEMH command
+// Add Frequency (if known) to UZ7HO MH lists
+// Add Gateway option to Telnet for PAT
+// Try to fix SCS Tracker recovery
+// Ensure RTS/DTR is down on CAT port if using that line for PTT
+// Experimental APRS Messaging in Kernel
+// Add Rigcontrol on remote PC's using WinmorControl
+// ADD VARAFM and VARAFM96 WL2KREPORT modes
+// Fix WL2K sysop update for new Winlink API
+// Fix APRS when using PORTNUM higher than the number of ports
+// Add Serial Port Type
+// Add option to linbpq to log APRS-IS messages.
+// Send WL2K Session Reports
+// Drop Tunneled Packets from 44.192 - 44.255
+// Log incoming Telnet Connects
+// Add IPV4: and IPV6: overrides on AXIP Resolver.
+// Add SessionTimeLimit to HF sessions (ARDOP, SCSPactor, WINMOR, VARA)
+// Add RADIO FREQ command to display current frequency
+
+// 6.0.20 April 2020
+
+// Trap and reject YAPP file transfer request.
+// Fix possible overrun of TCP to Node Buffer
+// Fix possible crash if APRS WX file doesn't have a terminating newline
+// Change communication with BPQAPRS.exe to restore old message popup behaviour
+// Preparation for 64 bit version
+// Improve flow control on SCS Dragon
+// Fragment messages from network links to L2 links with smaller paclen
+// Change WL2K report rate to once every two hours
+// Add PASS, CTEXT and CMSG commands and Stream Switch support to TNC2 Emulator
+// Add SessionTimeLimit command to HF drivers (ARDOP, SCSPactor, WINMOR, VARA)
+// Add links to Ports Web Manangement Page to open individual Driver windows
+// Add STOPPORT/STARTPORT support to ARDOP, KAM and SCSPactor drivers
+// Add CLOSE and OPEN RADIO command so Rigcontrol port can be freed fpr other use.
+// Don't try to send WL2K Traffic report if Internet is down
+// Move WL2K Traffic reporting to a separate thread so it doesn't block if it can't connect to server
+// ADD AGWAPPL config command to set application number. AGWMASK is still supported
+// Register Node Alias with UZ7HO Driver
+// Register calls when UZ7HO TNC Restarts and at intervals afterwards
+// Fix crash when no IOADDR or COMPORT in async port definition
+// Fix Crash with Paclink-Unix when parsing ; VE7SPR-10 DE N7NIX QTC 1
+// Only apply BBSFLAG=NOBBS to APPPLICATION 1
+// Add RIGREONFIG command
+// fix APRS RECONFIG on LinBPQ
+// Fix Web Terminal scroll to end problem on some browsers
+// Add PTT_SETS_INPUT option for IC7600
+// Add TELRECONFIG command to reread users or whole config
+// Enforce PACLEN on UZ7HO ports
+// Fix PACLEN on Command Output.
+// Retry axip resolver if it fails at startup
+// Fix AGWAPI connect via digis
+// Fix Select() for Linux in MultiPSK, UZ7HO and V4 drivers
+// Limit APRS OBJECT length to 80 chars
+// UZ7HO disconnect incoming call if no free streams
+// Improve response to REJ (no F) followed by RR (F).
+// Try to prevent more than MAXFRAME frames outstanding when transmitting
+// Allow more than one instance of APRS on Linux
+// Stop APRS digi by originating station
+// Send driver window trace to main monitor system
+// Improve handling of IPOLL messages
+// Fix setting end of address bit on dest call on connects to listening sessions
+// Set default BBS and CHAT application number and number of streams on LinBPQ
+// Support #include in bpq32.cfg processing
+
+// Version 6.0.21 14 December 2020
+
+// Fix occasional missing newlines in some node command reponses
+// More 64 bit fixes
+// Add option to stop setting PDUPLEX param in SCSPACTOR
+// Try to fix buffer loss
+// Remove extra space from APRS position reports
+// Suppress VARA IAMALIVE messages
+// Add display and control of QtSoundModem modems
+// Only send "No CMS connection available" message if fallbacktorelay is set.
+// Add HAMLIB backend and emulator support to RIGCONTROL
+// Ensure all beacons are sent even with very short beacon intervals
+// Add VARA500 WL2K Reporting Mode
+// Fix problem with prpcessing frame collector
+// Temporarily disable L2 and L4 collectors till I can find problem
+// Fix possible problem with interactive RADIO commands not giving a response,
+// Incease maximum length of NODE command responses to handle maximum length INFO message,
+// Allow WL2KREPORT in CONFIG section of UZ7HO port config.
+// Fix program error in processing hamlib frame
+// Save RestartAfterFailure option for VARA
+// Check callsign has a winlink account before sending WL2KREPORT messages
+// Add Bandwidth control to VARA scanning
+// Renable L2 collector
+// Fix TNCPORT reconnect on Linux
+// Add SecureTelnet option to limit telnet outward connect to sysop mode sessions or Application Aliases
+// Add option to suppress sending call to application in Telnet HOST API
+// Add FT991A support to RigControl
+// Use background.jpg for Edit Config page
+// Send OK response to SCS Pactor commands starting with #
+// Resend ICOM PTT OFF command after 30 seconds
+// Add WXCall to APRS config
+// Fixes for AEAPactor
+// Allow PTTMUX to use real or com0com com ports
+// Fix monitoring with AGW Emulator
+// Derive approx position from packets on APRS ports with a valid 6 char location
+// Fix corruption of APRS message lists if the station table fills up.
+// Don't accept empty username or password on Relay sessions.
+// Fix occasional empty Nodes broadcasts
+// Add Digis to UZ7HO Port MH list
+// Add PERMITTEDAPPLS port param
+// Fix WK2K Session Record Reporting for Airmail and some Pactor Modes.
+// Fix handling AX/IP (proto 93) frames
+// Fix possible corruption sending APRS messages
+// Allow Telnet connections to be made using Connect command as well as Attach then Connect
+// Fix Cancel Sysop Signin
+// Save axip resolver info and restore on restart
+// Add Transparent mode to Telnet Server HOST API
+// Fix Tracker driver if WL2KREPRRT is in main config section
+// SNMP InOctets count corrected to include all frames and encoding of zero values fixed.
+// Change IP Gateway to exclude handling bits of 44 Net sold to Amazon
+// Fix crash in Web terminal when processing very long lines
+
+// Version 6.0.22.1 August 2021
+
+// Fix bug in KAM TNCEMULATOR
+// Add WinRPR Driver (DED over TCP)
+// Fix handling of VARA config commands FM1200 and FM9600
+// Improve Web Termanal Line folding
+// Add StartTNC to WinRPR driver
+// Add support for VARA2750 Mode
+// Add support for VARA connects via a VARA Digipeater
+// Add digis to SCSTracker and WinRPR MHeard
+// Separate RIGCONTROL config from PORT config and add RigControl window
+// Fix crash when a Windows HID device doesn't have a product_string
+// Changes to VARA TNC connection and restart process
+// Trigger FALLBACKTORELAY if attempt to connect to all CMS servers fail.
+// Fix saving part lines in adif log and Winlink Session reporting
+// Add port specific CTEXT
+// Add FRMR monitoring to UZ7HO driver
+// Add audio input switching for IC7610
+// Include Rigcontrol Support for IC-F8101E
+// Process any response to KISS command
+// Fix NODE ADD command
+// Add noUpdate flag to AXIP MAP
+// Fix clearing NOFALLBACK flag in Telnet Server
+// Allow connects to RMS Relay running on another host
+// Allow use of Power setting in Rigcontol scan lines for Kenwood radios
+// Prevent problems caused by using "CMS" as a Node Alias
+// Include standard APRS Station pages in code
+// Fix VALIDCALLS processing in HF drivers
+// Send Netrom Link reports to Node Map
+// Add REALTELNET mode to Telnet Outward Connect
+// Fix using S (Stay) parameter on Telnet connects when using CMDPORT and C HOST
+// Add Default frequency to rigcontrol to set a freq/mode to return to after a connection
+// Fix long (> 60 seconds) scan intervals
+// Improved debugging of stuck semaphores
+// Fix potential securiby bug in BPQ Web server
+// Send Chat Updates to chatupdate.g8bpq.net port 81
+// Add ReportRelayTraffic to Telnet config to send WL2K traffic reports for connections to RELAY
+// Add experimental Mode reporting
+// Add SendTandRtoRelay param to SCS Pactor, ARDOP and VARA drivers to divert calls to CMS for -T and -R to RELAY
+// Add UPNP Support
+
+// Version 6.0.23.1 June 2022
+
+// Add option to control which applcalls are enabled in VARA
+// Add support for rtl_udp to Rig Control
+// Fix Telnet Auto Conneect to Application when using TermTCP or Web Terminal
+// Allow setting css styles for Web Terminal
+// And Kill TNC and Kill and Restart TNC commands to Web Driver Windows
+// More flexible RigControl for split frequency operation, eg for QO100
+// Increase stack size for ProcessHTMLMessage (.11)
+// Fix HTML Content-Type on images (.12)
+// Add AIS and ADSB Support (.13)
+// Compress web pages (.14)
+// Change minidump routine and close after program error (.15)
+// Add RMS Relay SYNC Mode (.17)
+// Changes for compatibility with Winlink Hybrid
+// Add Rigcontrol CMD feature to Yaesu code (21)
+// More diagnostic code
+// Trap potential buffer overrun in ax/tcp code
+// Fix possible hang in UZ7HO driver if connect takes a long time to succeed or fail
+// Add FLRIG as backend for RigControl (.24)
+// Fix bug in compressing some management web pages
+// Fix bugs in AGW Emulator (.25)
+// Add more PTT_Sets_Freq options for split frequency working (.26)
+// Allow RIGCONTROL using Radio Number (Rnn) as well as Port (.26)
+// Fix Telnet negotiation and backspace processing (.29)
+// Fix VARA Mode change when scanning (.30)
+// Add Web Mgmt Log Display (.33)
+// Fix crash when connecting to RELAY when CMS=0 (.36)
+// Send OK to user for manual freq changes with hamlib or flrig
+// Fix Rigcontrol leaving port disabled when using an empty timeband
+// Fix processing of backspace in Telnet character processing (.40)
+// Increase max size of connect script
+// Fix HAMLIB Slave Thread control
+// Add processing of VARA mode responses and display of VARA Mode (41)
+// Fix crash when VARA session aborted on LinBPQ (43)
+// Fix handling port selector (2:call or p2 call) on SCS PTC packet ports (44)
+// Include APRS Map web page
+// Add Enable/Disable to KAMPACTOR scan control (use P0 or P1) (45)
+// Add Basic DRATS interface (46)
+// Fix MYCALLS on VARA (49)
+// Add FreeData driver (51)
+// Add additonal Rigcontrol options for QO100 (51)
+// Set Content-Type: application/pdf for pdf files downloaded via web interface (51)
+// Fix sending large compressed web messages (52)
+// Fix freq display when using flrig or hamlib backends to rigcontrol
+// Change VARA Driver to send ABORT when Session Time limit expires
+// Add Chat Log to Web Logs display
+// Fix possible buffer loss in RigControl
+// Allow hosts on local lan to be treated as secure
+// Improve validation of data sent to Winlink SessionAdd API call
+// Add support for FreeDATA modem.
+// Add GetLOC API Call
+// Change Leaflet link in aprs map.
+// Add Connect Log (64)
+// Fix crash when Resolve CMS Servers returns ipv6 addresses
+// Fix Reporting P4 sessions to Winlink (68)
+// Add support for FreeBSD (68)
+// Fix Rigcontrol PTCPORT (69)
+// Set TNC Emulator sessions as secure (72)
+// Fix not always detecting loss of FLRIG (73)
+// Add ? and * wildcards to NODES command (74)
+// Add Port RADIO config parameter (74)
+
+// Version 6.0.24.1 August 2023
+
+// Apply NODES command wildcard to alias as well a call (2)
+// Add STOPPORT/STARTPORT to VARA Driver (2)
+// Add bandwidth setting to FLRIG interface. (2)
+// Fix N VIA (3)
+// Fix NODE ADD and NODE DEL (4)
+// Improvements to FLRIG Rigcontrol backend (6, 7)
+// Fix UZ7HO Window Title Update
+// Reject L2 calls with a blank from call (8)
+// Update WinRPR Window header with BPQ Port Description (8)
+// Fix error in blank call code (9)
+// Change web buttons to white on black when pressed (10)
+// Fix Port CTEXT paclen on Tracker and WinRPR drivers (11)
+// Add RADIO PTT command for testing PTT (11)
+// Fix using APPLCALLs on SCSTracker RP call (12)
+// Add Rigcntol Web Page (13)
+// Fix scan bandwidth change with ARDOPOFDM (13)
+// Fix setting Min Pactor Level in SCSPactor (13)
+// Fix length of commands sent via CMD_TO_APPL flag (14)
+// Add filter by quality option to N display (15)
+// Fix VARA Mode reporting to WL2K (16)
+// Add FLRIG POWER and TUNE commands (18)
+// Fix crash when processing "C " without a call in UZ7HO, FLDIGI or MULTIPSK drivers (19)
+// FLDIGI improvements (19)
+// Fix hang at start if Telnet port Number > Number of Telnet Streams (20)
+// Fix processing C command if first port driver is SCSPACTROR (20)
+// Fix crash in UZ7HO driver if bad raw frame received (21)
+// Fix using FLARQ chat mode with FLDIGI ddriover (22)
+// Fix to KISSHF driver (23)
+// Fix for application buffer loss (24)
+// Add Web Sockets auto-refresh option for Webmail index page (25)
+// Fix FREEDATA driver for compatibility with FreeData TNC version 0.6.4-alpha.3 (25)
+// Add SmartID for bridged frames - Send ID only if packets sent recently (26)
+// Add option to save and restore received APRS messages (27)
+// Add mechanism to run a user program on certain events (27)
+// If BeacontoIS is zero don't Gate any of our messages received locally to APRS-IS (28)
+// Add Node Help command (28)
+// Add APRS Igate RXOnly option (29)
+// Fix RMC message handling with prefixes other than GP (29)
+// Add GPSD support for APRS (30)
+// Attempt to fix Tracker/WinRPR reconnect code (30)
+// Changes to FreeDATA - Don't use deamon and add txlevel and send text commands (31)
+// Fix interactive commands in tracker driver (33)
+// Fix SESSIONTIMELIMIT processing
+// Add STOPPORT/STARTPORT for UZ7HO driver
+// Fix processing of extended QtSM 'g' frame (36)
+// Allow setting just freq on Yaseu rigs (37)
+// Enable KISSHF driver on Linux (40)
+// Allow AISHOST and ADSBHOST to be a name as well as an address (41)
+// Fix Interlock of incoming UZ7HO connections (41)
+// Disable VARA Actions menu if not sysop (41)
+// Fix Port CTEXT on UZ7HO B C or D channels (42)
+// Fix repeated trigger of SessionTimeLimit (43)
+// Fix posible memory corruption in UpateMH (44)
+// Add PHG to APRS beacons (45)
+// Dont send DM to stations in exclude list(45)
+// Improvements to RMS Relay SYNC Mode (46)
+// Check L4 connects against EXCLUDE list (47)
+// Add vaidation of LOC in WL2K Session Reports (49)
+// Change gpsd support for compatibility with Share Gps (50)
+// Switch APRS Map to my Tiles (52)
+// Fix using ; in UNPROTO Mode messages (52)
+// Use sha1 code from https://www.packetizer.com/security/sha1/ instead of openssl (53)
+// Fix TNC Emulator Monitoring (53)
+// Fix attach and connect on Telnet port bug introduced in .55 (56)
+// Fix stopping WinRPR TNC and Start/Stop UZ7HO TNCX on Linux (57)
+// Fix stack size in beginthread for MAC (58)
+// Add NETROM over VARA (60)
+// Add Disconnect Script (64)
+// Add node commands to set UZ7HO modem mode and freq (64)
+// Trap empty NODECALL or NETROMCALL(65)
+// Trap NODES messages with empty From Call (65)
+// Add RigControl for SDRConsole (66)
+// Fix FLRig crash (66)
+// Fix VARA disconnect handling (67)
+// Support 64 ports (69)
+// Fix Node commands for setting UZ7HO Modem (70)
+// Fix processing SABM on an existing session (71)
+// Extend KISS Node command to send more than one parameter byte (72)
+// Add G7TAJ's code to record activity of HF ports for stats display (72)
+// Add option to send KISS command to TNC on startup (73)
+// Fix Bug in DED Emulator Monitor code (74)
+// Add Filters to DED Monitor code (75)
+// Detect loss of DED application (76)
+// Fix connects to Application Alias with UZ7HO Driver (76)
+// Fix Interlock of ports on same UZ7HO modem. (76)
+// Add extended Ports command (77)
+// Fix crash in Linbpq when stdout is redirected to /dev/tty? and stdin ia redirected (78)
+// Fix Web Terminal (80)
+// Trap ENCRYPTION message from VARA (81)
+// Fix processing of the Winlink API /account/exists response (82)
+// Fix sending CTEXT to L4 connects to Node when FULL_CTEXT is not set
+
+// Version 6.0.25.?
+
+// Fix 64 bit compatibility problems in SCSTracker and UZ7HO drivers
+// Add Chat PACLEN config (5)
+// Fix NC to Application Call (6)
+// Fix INP3 L3RTT messages on Linux and correct RTT calculation (9)
+// Get Beacon config from config file on Windows (9)
+// fix processing DED TNC Emulator M command with space between M and params (10)
+// Fix sending UI frames on SCSPACTOR (11)
+// Dont allow ports that can't set digi'ed bit in callsigns to digipeat. (11)
+// Add SDRAngel rig control (11)
+// Add option to specify config and data directories on linbpq (12)
+// Allow zero resptime (send RR immediately) (13)
+// Make sure CMD bit is set on UI frames
+// Add setting Modem Flags in QtSM AGW mode
+// If FT847 om PTC Port send a "Cat On" command (17)
+// Fix some 63 port bugs in RigCOntrol (17)
+// Fix 63 port bug in Bridging (18)
+// Add FTDX10 Rigcontrol (19)
+// Fix 64 bit bug in displaying INP3 Messages (20)
+// Improve restart of WinRPR TNC on remote host (21)
+// Fix some Rigcontrol issues with empty timebands (22)
+// Fix 64 bit bug in processing INP3 Messages (22)
+// First pass at api (24)
+// Send OK in response to Rigcontrol CMD (24)
+// Disable CTS check in WriteComBlock (26)
+// Improvments to reporting to M0LTE Map (26)
+// IPGateway fix from github user isavitsky (27)
+// Fix possible crash in SCSPactor PTCPORT code (29)
+// Add NodeAPI call sendLinks and remove get from other calls (32)
+// Improve validation of Web Beacon Config (33)
+// Support SNMP via host ip stack as well as IPGateway (34)
+// Switch APRS Map to OSM tile servers (36)
+// Fix potential buffer overflow in Telnet login (36)
+// Allow longer serial device names (37)
+// Fix ICF8101 Mode setting (37)
+// Kill link if we are getting repeated RR(F) after timeout
+// (Indicating other station is seeing our RR(P) but not the resent I frame) (40)
+// Change default of SECURETELNET to 1 (41)
+// Add optional ATTACH time limit for ARDOP (42)
+// Fix buffer overflow risk in HTTP Terminal(42)
+// Fix KISSHF Interlock (43)
+// Support other than channel A on HFKISS (43)
+// Support additional port info reporting for M0LTE Map (44)
+// Allow interlocking of KISS and Session mode ports (eg ARDOP and VARA) (45)
+// Add ARDOP UI Packets to MH (45)
+// Add support for Qtsm Mgmt Interface (45)
+// NodeAPI improvements (46)
+// Add MQTT Interface (46)
+// Fix buffer leak in ARDOP code(46)
+// Fix possible crash if MQTT not in use (47)
+// Add optional ATTACH time limit for VARA (48)
+// API format fixes (48)
+// AGWAPI Add protection against accidental connects from a non-agw application (50)
+// Save MH and NODES every hour (51)
+// Fix handling long unix device names (now max 250 bytes) (52)
+// Fix error reporting in api update (53)
+// Coding changes to remove some compiler warnings (53, 54)
+// Add MQTT reporting of Mail Events (54)
+// Fix beaconong on KISSHF ports (55)
+// Fix MailAPI msgs endpoint
+// Attempt to fix NC going to wrong application. (57)
+// Improve ARDOP end of session code (58)
+// Run M0LTE Map reporting in a separate thread (59/60)
+// Add RHP support for WhatsPac (59)
+// Add timestamps to LIS monitor (60)
+// Fix problem with L4 frames being delivered out of sequence (60)
+// Add Compression of Netrom connections (62)
+// Improve handling of Locked Routes (62)
+// Add L4 RESET (Paula G8PZT's extension to NETROM)
+// Fix problem using SENDRAW from BPQMail (63)
+// Fix compatibility with latest ardopcf (64)
+// Fix bug in RHP socket timeout code (65)
+// Fix L4 RTT (66)
+// Fix RigConrol with Chanxx but no other settings (66)
+// Add option to compress L2 frames (67)
+// Sort Routes displays (67)
+// Fix Ardop session premature close (70)
+// Add timestamps to log entries in Web Driver windows (70)
+// Generate stack backtrace if SIGSEGV or SIGABRT occur (Linux) (70)
+// Remove some debug logging from L2 code (70)
+// Fix compiling LinBPQ with nomqtt option (70)
+// Improve handling of binary data in RHP interface (70)
+// Fix sending KISS commands to multiport or multidropped TNCs (70)
+// Add MHUV and MHLV commands (Verbose listing with timestamps in clock time) (70)
+
+#define CKernel
+
+#include "Versions.h"
+
+#define _CRT_SECURE_NO_DEPRECATE
+
+#pragma data_seg("_BPQDATA")
+
+#include "time.h"
+#include "stdio.h"
+#include
+
+#include "compatbits.h"
+#include "AsmStrucs.h"
+
+#include "SHELLAPI.H"
+#include "kernelresource.h"
+
+#include
+#include
+#include "BPQTermMDI.h"
+
+#include "GetVersion.h"
+
+#define DllImport __declspec( dllimport )
+
+#define CheckGuardZone() _CheckGuardZone(__FILE__, __LINE__)
+void _CheckGuardZone(char * File, int Line);
+
+#define CHECKLOADED 0
+#define SETAPPLFLAGS 1
+#define SENDBPQFRAME 2
+#define GETBPQFRAME 3
+#define GETSTREAMSTATUS 4
+#define CLEARSTREAMSTATUS 5
+#define BPQCONDIS 6
+#define GETBUFFERSTATUS 7
+#define GETCONNECTIONINFO 8
+#define BPQRETURN 9 // GETCALLS
+//#define RAWTX 10 //IE KISS TYPE DATA
+#define GETRAWFRAME 11
+#define UPDATESWITCH 12
+#define BPQALLOC 13
+//#define SENDNETFRAME 14
+#define GETTIME 15
+
+extern short NUMBEROFPORTS;
+extern long PORTENTRYLEN;
+extern long LINKTABLELEN;
+extern struct PORTCONTROL * PORTTABLE;
+extern void * FREE_Q;
+extern UINT APPL_Q; // Queue of frames for APRS Appl
+
+extern TRANSPORTENTRY * L4TABLE;
+extern UCHAR NEXTID;
+extern DWORD MAXCIRCUITS;
+extern DWORD L4DEFAULTWINDOW;
+extern DWORD L4T1;
+extern APPLCALLS APPLCALLTABLE[];
+extern char * APPLS;
+
+extern struct WL2KInfo * WL2KReports;
+
+extern int NUMBEROFTNCPORTS;
+
+
+void * VCOMExtInit(struct PORTCONTROL * PortEntry);
+void * AXIPExtInit(struct PORTCONTROL * PortEntry);
+void * SCSExtInit(struct PORTCONTROL * PortEntry);
+void * AEAExtInit(struct PORTCONTROL * PortEntry);
+void * KAMExtInit(struct PORTCONTROL * PortEntry);
+void * HALExtInit(struct PORTCONTROL * PortEntry);
+void * ETHERExtInit(struct PORTCONTROL * PortEntry);
+void * AGWExtInit(struct PORTCONTROL * PortEntry);
+void * WinmorExtInit(EXTPORTDATA * PortEntry);
+void * TelnetExtInit(EXTPORTDATA * PortEntry);
+//void * SoundModemExtInit(EXTPORTDATA * PortEntry);
+void * TrackerExtInit(EXTPORTDATA * PortEntry);
+void * TrackerMExtInit(EXTPORTDATA * PortEntry);
+void * V4ExtInit(EXTPORTDATA * PortEntry);
+void * UZ7HOExtInit(EXTPORTDATA * PortEntry);
+void * MPSKExtInit(EXTPORTDATA * PortEntry);
+void * FLDigiExtInit(EXTPORTDATA * PortEntry);
+void * UIARQExtInit(EXTPORTDATA * PortEntry);
+void * SerialExtInit(EXTPORTDATA * PortEntry);
+void * ARDOPExtInit(EXTPORTDATA * PortEntry);
+void * VARAExtInit(EXTPORTDATA * PortEntry);
+void * KISSHFExtInit(EXTPORTDATA * PortEntry);
+void * WinRPRExtInit(EXTPORTDATA * PortEntry);
+void * HSMODEMExtInit(EXTPORTDATA * PortEntry);
+void * FreeDataExtInit(EXTPORTDATA * PortEntry);
+void * SIXPACKExtInit(EXTPORTDATA * PortEntry);
+
+extern char * ConfigBuffer; // Config Area
+VOID REMOVENODE(dest_list * DEST);
+DllExport int ConvFromAX25(unsigned char * incall,unsigned char * outcall);
+DllExport int ConvToAX25(unsigned char * incall,unsigned char * outcall);
+VOID GetUIConfig();
+VOID ADIFWriteFreqList();
+void SaveAIS();
+void initAIS();
+void initADSB();
+
+extern BOOL ADIFLogEnabled;
+
+int CloseOnError = 0;
+
+char UIClassName[]="UIMAINWINDOW"; // the main window class name
+
+HWND UIhWnd;
+
+extern char AUTOSAVE;
+extern char AUTOSAVEMH;
+
+extern char MYNODECALL; // 10 chars,not null terminated
+
+extern QCOUNT;
+extern BPQVECSTRUC BPQHOSTVECTOR[];
+#define BPQHOSTSTREAMS 64
+#define IPHOSTVECTOR BPQHOSTVECTOR[BPQHOSTSTREAMS + 3]
+
+extern char * CONFIGFILENAME;
+
+DllExport BPQVECSTRUC * BPQHOSTVECPTR;
+
+extern int DATABASESTART;
+
+extern struct ROUTE * NEIGHBOURS;
+extern int ROUTE_LEN;
+extern int MAXNEIGHBOURS;
+
+extern struct DEST_LIST * DESTS; // NODE LIST
+extern int DEST_LIST_LEN;
+extern int MAXDESTS; // MAX NODES IN SYSTEM
+
+extern struct _LINKTABLE * LINKS;
+extern int LINK_TABLE_LEN;
+extern int MAXLINKS;
+
+extern double LatFromLOC;
+extern double LonFromLOC;
+
+
+extern int BPQHOSTAPI();
+extern int INITIALISEPORTS();
+extern int TIMERINTERRUPT();
+extern int MONDECODE();
+extern int BPQMONOPTIONS();
+extern char PWTEXT[];
+extern char PWLen;
+
+extern int FINDFREEDESTINATION();
+extern int RAWTX();
+extern int RELBUFF();
+extern int SENDNETFRAME();
+extern char MYCALL[]; // 7 chars, ax.25 format
+
+extern HWND hIPResWnd;
+extern BOOL IPMinimized;
+
+extern int NODESINPROGRESS;
+extern VOID * CURRENTNODE;
+
+
+BOOL Start();
+
+VOID SaveWindowPos(int port);
+VOID SaveAXIPWindowPos(int port);
+VOID SetupRTFHddr();
+DllExport VOID APIENTRY CreateNewTrayIcon();
+int DoReceivedData(int Stream);
+int DoStateChange(int Stream);
+int DoMonData(int Stream);
+struct ConsoleInfo * CreateChildWindow(int Stream, BOOL DuringInit);
+CloseHostSessions();
+SaveHostSessions();
+VOID SaveBPQ32Windows();
+VOID CloseDriverWindow(int port);
+VOID CheckWL2KReportTimer();
+VOID SetApplPorts();
+VOID WriteMiniDump();
+VOID FindLostBuffers();
+BOOL InitializeTNCEmulator();
+VOID TNCTimer();
+char * strlop(char * buf, char delim);
+
+DllExport int APIENTRY Get_APPLMASK(int Stream);
+DllExport int APIENTRY GetStreamPID(int Stream);
+DllExport int APIENTRY GetApplFlags(int Stream);
+DllExport int APIENTRY GetApplNum(int Stream);
+DllExport BOOL APIENTRY GetAllocationState(int Stream);
+DllExport int APIENTRY GetMsg(int stream, char * msg, int * len, int * count );
+DllExport int APIENTRY RXCount(int Stream);
+DllExport int APIENTRY TXCount(int Stream);
+DllExport int APIENTRY MONCount(int Stream);
+DllExport int APIENTRY GetCallsign(int stream, char * callsign);
+DllExport VOID APIENTRY RelBuff(VOID * Msg);
+void SaveMH();
+void DRATSPoll();
+
+#define C_Q_ADD(s, b) _C_Q_ADD(s, b, __FILE__, __LINE__);
+int _C_Q_ADD(VOID *PQ, VOID *PBUFF, char * File, int Line);
+
+VOID SetWindowTextSupport();
+int WritetoConsoleSupport(char * buff);
+VOID PMClose();
+VOID MySetWindowText(HWND hWnd, char * Msg);
+BOOL CreateMonitorWindow(char * MonSize);
+VOID FormatTime3(char * Time, time_t cTime);
+
+char EXCEPTMSG[80] = "";
+
+char SIGNONMSG[128] = "";
+char SESSIONHDDR[80] = "";
+int SESSHDDRLEN = 0;
+
+BOOL IncludesMail = FALSE;
+BOOL IncludesChat = FALSE; // Set if pgram is running - used for Web Page Index
+
+
+char WL2KCall[10];
+char WL2KLoc[7];
+
+extern char LOCATOR[]; // Locator for Reporting - may be Maidenhead or LAT:LON
+extern char MAPCOMMENT[]; // Locator for Reporting - may be Maidenhead or LAT:LON
+extern char LOC[7]; // Maidenhead Locator for Reporting
+extern char ReportDest[7];
+
+extern UCHAR ConfigDirectory[260];
+
+extern uint64_t timeLoadedMS;
+
+VOID __cdecl Debugprintf(const char * format, ...);
+VOID __cdecl Consoleprintf(const char * format, ...);
+
+DllExport int APIENTRY CloseBPQ32();
+DllExport char * APIENTRY GetLOC();
+DllExport int APIENTRY SessionControl(int stream, int command, int param);
+
+int DoRefreshWebMailIndex();
+
+BOOL APIENTRY Init_IP();
+BOOL APIENTRY Poll_IP();
+
+BOOL APIENTRY Init_PM();
+BOOL APIENTRY Poll_PM();
+
+BOOL APIENTRY Init_APRS();
+BOOL APIENTRY Poll_APRS();
+VOID HTTPTimer();
+
+BOOL APIENTRY Rig_Init();
+BOOL APIENTRY Rig_Close();
+BOOL Rig_Poll();
+
+VOID IPClose();
+VOID APRSClose();
+VOID CloseTNCEmulator();
+
+VOID Poll_AGW();
+void RHPPoll();
+BOOL AGWAPIInit();
+int AGWAPITerminate();
+
+int * Flag = (int *)&Flag; // for Dump Analysis
+int MAJORVERSION=4;
+int MINORVERSION=9;
+
+struct SEM Semaphore = {0, 0, 0, 0};
+struct SEM APISemaphore = {0, 0, 0, 0};
+int SemHeldByAPI = 0;
+int LastSemGets = 0;
+UINT Sem_eax = 0;
+UINT Sem_ebx = 0;
+UINT Sem_ecx = 0;
+UINT Sem_edx = 0;
+UINT Sem_esi = 0;
+UINT Sem_edi = 0;
+
+
+#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__)
+void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line);
+void FreeSemaphore(struct SEM * Semaphore);
+
+DllExport void * BPQHOSTAPIPTR = &BPQHOSTAPI;
+//DllExport long MONDECODEPTR = (long)&MONDECODE;
+
+extern UCHAR BPQDirectory[];
+extern UCHAR LogDirectory[];
+extern UCHAR BPQProgramDirectory[];
+
+static char BPQWinMsg[] = "BPQWindowMessage";
+
+static char ClassName[] = "BPQMAINWINDOW";
+
+HKEY REGTREE = HKEY_CURRENT_USER;
+char REGTREETEXT[100] = "HKEY_CURRENT_USER";
+
+UINT BPQMsg=0;
+
+#define MAXLINELEN 120
+#define MAXSCREENLEN 50
+
+#define BGCOLOUR RGB(236,233,216)
+
+HBRUSH bgBrush = NULL;
+
+//int LINELEN=120;
+//int SCREENLEN=50;
+
+//char Screen[MAXLINELEN*MAXSCREENLEN]={0};
+
+//int lineno=0;
+//int col=0;
+
+#define REPORTINTERVAL 15 * 549; // Magic Ticks Per Minute for PC's nominal 100 ms timer
+int ReportTimer = 0;
+
+HANDLE OpenConfigFile(char * file);
+
+VOID SetupBPQDirectory();
+VOID SendLocation();
+
+//uintptr_t _beginthread(void(*start_address)(), unsigned stack_size, int arglist);
+
+#define TRAY_ICON_ID 1 // ID number for the Notify Icon
+#define MY_TRAY_ICON_MESSAGE WM_APP // the message ID sent to our window
+
+NOTIFYICONDATA niData;
+
+int SetupConsoleWindow();
+
+BOOL StartMinimized=FALSE;
+BOOL MinimizetoTray=TRUE;
+
+BOOL StatusMinimized = FALSE;
+BOOL ConsoleMinimized = FALSE;
+
+HMENU trayMenu=0;
+
+HWND hConsWnd = NULL, hWndCons = NULL, hWndBG = NULL, ClientWnd = NULL, FrameWnd = NULL, StatusWnd = NULL;
+
+BOOL FrameMaximized = FALSE;
+
+BOOL IGateEnabled = TRUE;
+extern int ISDelayTimer; // Time before trying to reopen APRS-IS link
+extern int ISPort;
+
+UINT * WINMORTraceQ = NULL;
+UINT * SetWindowTextQ = NULL;
+
+static RECT Rect = {100,100,400,400}; // Console Window Position
+RECT FRect = {100,100,800,600}; // Frame
+static RECT StatusRect = {100,100,850,500}; // Status Window
+
+DllExport int APIENTRY DumpSystem();
+DllExport int APIENTRY SaveNodes ();
+DllExport int APIENTRY ClearNodes ();
+DllExport int APIENTRY SetupTrayIcon();
+
+#define Q_REM(s) _Q_REM(s, __FILE__, __LINE__)
+
+VOID * _Q_REM(VOID *Q, char * File, int Line);
+
+UINT ReleaseBuffer(UINT *BUFF);
+
+
+VOID CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime );
+
+DllExport int APIENTRY DeallocateStream(int stream);
+
+int VECTORLENGTH = sizeof (struct _BPQVECSTRUC);
+
+int FirstEntry = 1;
+BOOL CloseLast = TRUE; // If the user started BPQ32.exe, don't close it when other programs close
+BOOL Closing = FALSE; // Set if Close All called - prevents respawning bpq32.exe
+
+BOOL BPQ32_EXE; // Set if Process is running BPQ32.exe. Not initialised.
+ // Used to Kill surplus BPQ32.exe processes
+
+DWORD Our_PID; // Our Process ID - local variable
+
+void * InitDone = 0;
+int FirstInitDone = 0;
+int PerlReinit = 0;
+UINT_PTR TimerHandle = 0;
+UINT_PTR SessHandle = 0;
+
+BOOL EventsEnabled = 0;
+
+unsigned int TimerInst = 0xffffffff;
+
+HANDLE hInstance = 0;
+
+int AttachedProcesses = 0;
+int AttachingProcess = 0;
+HINSTANCE hIPModule = 0;
+HINSTANCE hRigModule = 0;
+
+BOOL ReconfigFlag = FALSE;
+BOOL RigReconfigFlag = FALSE;
+BOOL APRSReconfigFlag = FALSE;
+BOOL CloseAllNeeded = FALSE;
+BOOL NeedWebMailRefresh = FALSE;
+
+int AttachedPIDList[100] = {0};
+
+HWND hWndArray[100] = {0};
+int PIDArray[100] = {0};
+char PopupText[30][100] = {""};
+
+// Next 3 should be uninitialised so they are local to each process
+
+UCHAR MCOM;
+UCHAR MTX; // Top bit indicates use local time
+uint64_t MMASK;
+UCHAR MUIONLY;
+
+UCHAR AuthorisedProgram; // Local Variable. Set if Program is on secure list
+
+char pgm[256]; // Uninitialised so per process
+
+HANDLE Mutex;
+
+BOOL PartLine = FALSE;
+int pindex = 0;
+DWORD * WritetoConsoleQ;
+
+
+LARGE_INTEGER lpFrequency = {0};
+LARGE_INTEGER lastRunTime;
+LARGE_INTEGER currentTime;
+
+int ticksPerMillisec;
+int interval;
+
+
+VOID CALLBACK SetupTermSessions(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime);
+
+
+TIMERPROC lpTimerFunc = (TIMERPROC) TimerProc;
+TIMERPROC lpSetupTermSessions = (TIMERPROC) SetupTermSessions;
+
+
+BOOL ProcessConfig();
+VOID FreeConfig();
+
+DllExport int APIENTRY WritetoConsole(char * buff);
+
+BOOLEAN CheckifBPQ32isLoaded();
+BOOLEAN StartBPQ32();
+DllExport VOID APIENTRY Send_AX(VOID * Block, DWORD len, UCHAR Port);
+BOOL LoadIPDriver();
+BOOL Send_IP(VOID * Block, DWORD len);
+VOID CheckforLostProcesses();
+BOOL LoadRigDriver();
+VOID SaveConfig();
+VOID CreateRegBackup();
+VOID ResolveUpdateThread();
+VOID OpenReportingSockets();
+DllExport VOID APIENTRY CloseAllPrograms();
+DllExport BOOL APIENTRY SaveReg(char * KeyIn, HANDLE hFile);
+int upnpClose();
+
+BOOL IPActive = FALSE;
+extern BOOL IPRequired;
+BOOL PMActive = FALSE;
+extern BOOL PMRequired;
+BOOL RigRequired = TRUE;
+BOOL RigActive = FALSE;
+BOOL APRSActive = FALSE;
+BOOL AGWActive = FALSE;
+BOOL needAIS = FALSE;
+int needADSB = 0;
+
+extern int AGWPort;
+
+Tell_Sessions();
+
+
+typedef int (WINAPI FAR *FARPROCX)();
+
+FARPROCX CreateToolHelp32SnapShotPtr;
+FARPROCX Process32Firstptr;
+FARPROCX Process32Nextptr;
+
+void LoadToolHelperRoutines()
+{
+ HINSTANCE ExtDriver=0;
+ int err;
+ char msg[100];
+
+ ExtDriver=LoadLibrary("kernel32.dll");
+
+ if (ExtDriver == NULL)
+ {
+ err=GetLastError();
+ sprintf(msg,"BPQ32 Error loading kernel32.dll - Error code %d\n", err);
+ OutputDebugString(msg);
+ return;
+ }
+
+ CreateToolHelp32SnapShotPtr = (FARPROCX)GetProcAddress(ExtDriver,"CreateToolhelp32Snapshot");
+ Process32Firstptr = (FARPROCX)GetProcAddress(ExtDriver,"Process32First");
+ Process32Nextptr = (FARPROCX)GetProcAddress(ExtDriver,"Process32Next");
+
+ if (CreateToolHelp32SnapShotPtr == 0)
+ {
+ err=GetLastError();
+ sprintf(msg,"BPQ32 Error getting CreateToolhelp32Snapshot entry point - Error code %d\n", err);
+ OutputDebugString(msg);
+ return;
+ }
+}
+
+BOOL GetProcess(int ProcessID, char * Program)
+{
+ HANDLE hProcessSnap;
+ PROCESSENTRY32 pe32;
+ int p;
+
+ if (CreateToolHelp32SnapShotPtr==0)
+ {
+ return (TRUE); // Routine not available
+ }
+ // Take a snapshot of all processes in the system.
+ hProcessSnap = (HANDLE)CreateToolHelp32SnapShotPtr(TH32CS_SNAPPROCESS, 0);
+ if( hProcessSnap == INVALID_HANDLE_VALUE )
+ {
+ OutputDebugString( "CreateToolhelp32Snapshot (of processes) Failed\n" );
+ return( FALSE );
+ }
+
+ // Set the size of the structure before using it.
+ pe32.dwSize = sizeof( PROCESSENTRY32 );
+
+ // Retrieve information about the first process,
+ // and exit if unsuccessful
+ if( !Process32Firstptr( hProcessSnap, &pe32 ) )
+ {
+ OutputDebugString( "Process32First Failed\n" ); // Show cause of failure
+ CloseHandle( hProcessSnap ); // Must clean up the snapshot object!
+ return( FALSE );
+ }
+
+ // Now walk the snapshot of processes, and
+ // display information about each process in turn
+ do
+ {
+ if (ProcessID==pe32.th32ProcessID)
+ {
+ // if running on 98, program contains the full path - remove it
+
+ for (p = (int)strlen(pe32.szExeFile); p >= 0; p--)
+ {
+ if (pe32.szExeFile[p]=='\\')
+ {
+ break;
+ }
+ }
+ p++;
+
+ sprintf(Program,"%s", &pe32.szExeFile[p]);
+ CloseHandle( hProcessSnap );
+ return( TRUE );
+ }
+
+ } while( Process32Nextptr( hProcessSnap, &pe32 ) );
+
+
+ sprintf(Program,"PID %d Not Found", ProcessID);
+ CloseHandle( hProcessSnap );
+ return(FALSE);
+}
+
+BOOL IsProcess(int ProcessID)
+{
+ // Check that Process exists
+
+ HANDLE hProcessSnap;
+ PROCESSENTRY32 pe32;
+
+ if (CreateToolHelp32SnapShotPtr==0) return (TRUE); // Routine not available
+
+ hProcessSnap = (HANDLE)CreateToolHelp32SnapShotPtr(TH32CS_SNAPPROCESS, 0);
+
+ if( hProcessSnap == INVALID_HANDLE_VALUE )
+ {
+ OutputDebugString( "CreateToolhelp32Snapshot (of processes) Failed\n" );
+ return(TRUE); // Don't know, so assume ok
+ }
+
+ pe32.dwSize = sizeof( PROCESSENTRY32 );
+
+ if( !Process32Firstptr( hProcessSnap, &pe32 ) )
+ {
+ OutputDebugString( "Process32First Failed\n" ); // Show cause of failure
+ CloseHandle( hProcessSnap ); // Must clean up the snapshot object!
+ return(TRUE); // Don't know, so assume ok
+ }
+
+ do
+ {
+ if (ProcessID==pe32.th32ProcessID)
+ {
+ CloseHandle( hProcessSnap );
+ return( TRUE );
+ }
+
+ } while( Process32Nextptr( hProcessSnap, &pe32 ) );
+
+ CloseHandle( hProcessSnap );
+ return(FALSE);
+}
+
+#include "DbgHelp.h"
+
+VOID MonitorThread(int x)
+{
+ // Thread to detect killed processes. Runs in process owning timer.
+
+ // Obviously can't detect loss of timer owning thread!
+
+ do
+ {
+ if (Semaphore.Gets == LastSemGets && Semaphore.Flag)
+ {
+ // It is stuck - try to release
+
+ Debugprintf ("Semaphore locked - Process ID = %d, Held By %d from %s Line %d",
+ Semaphore.SemProcessID, SemHeldByAPI, Semaphore.File, Semaphore.Line);
+
+ // Write a minidump
+
+ WriteMiniDump();
+
+ Semaphore.Flag = 0;
+ }
+
+ LastSemGets = Semaphore.Gets;
+
+ Sleep(30000);
+ CheckforLostProcesses();
+
+ } while (TRUE);
+}
+
+VOID CheckforLostProcesses()
+{
+ UCHAR buff[100];
+ char Log[80];
+ int i, n, ProcessID;
+
+ for (n=0; n < AttachedProcesses; n++)
+ {
+ ProcessID=AttachedPIDList[n];
+
+ if (!IsProcess(ProcessID))
+ {
+ // Process has died - Treat as a detach
+
+ sprintf(Log,"BPQ32 Process %d Died\n", ProcessID);
+ OutputDebugString(Log);
+
+ // Remove Tray Icon Entry
+
+ for( i = 0; i < 100; ++i )
+ {
+ if (PIDArray[i] == ProcessID)
+ {
+ hWndArray[i] = 0;
+ sprintf(Log,"BPQ32 Removing Tray Item %s\n", PopupText[i]);
+ OutputDebugString(Log);
+ DeleteMenu(trayMenu,TRAYBASEID+i,MF_BYCOMMAND);
+ }
+ }
+
+ // If process had the semaphore, release it
+
+ if (Semaphore.Flag == 1 && ProcessID == Semaphore.SemProcessID)
+ {
+ OutputDebugString("BPQ32 Process was holding Semaphore - attempting recovery\r\n");
+ Debugprintf("Last Sem Call %d %x %x %x %x %x %x", SemHeldByAPI,
+ Sem_eax, Sem_ebx, Sem_ecx, Sem_edx, Sem_esi, Sem_edi);
+
+ Semaphore.Flag = 0;
+ SemHeldByAPI = 0;
+ }
+
+ for (i=1;i<65;i++)
+ {
+ if (BPQHOSTVECTOR[i-1].STREAMOWNER == AttachedPIDList[n])
+ {
+ DeallocateStream(i);
+ }
+ }
+
+ if (TimerInst == ProcessID)
+ {
+ KillTimer(NULL,TimerHandle);
+ TimerHandle=0;
+ TimerInst=0xffffffff;
+// Tell_Sessions();
+ OutputDebugString("BPQ32 Process was running timer \n");
+
+ if (MinimizetoTray)
+ Shell_NotifyIcon(NIM_DELETE,&niData);
+
+
+ }
+
+ // Remove this entry from PID List
+
+ for (i=n; i< AttachedProcesses; i++)
+ {
+ AttachedPIDList[i]=AttachedPIDList[i+1];
+ }
+ AttachedProcesses--;
+
+ sprintf(buff,"BPQ32 Lost Process - %d Process(es) Attached\n", AttachedProcesses);
+ OutputDebugString(buff);
+ }
+ }
+}
+VOID MonitorTimerThread(int x)
+{
+ // Thread to detect killed timer process. Runs in all other BPQ32 processes.
+
+ do {
+
+ Sleep(60000);
+
+ if (TimerInst != 0xffffffff && !IsProcess(TimerInst))
+ {
+ // Timer owning Process has died - Force a new timer to be created
+ // New timer thread will detect lost process and tidy up
+
+ Debugprintf("BPQ32 Process %d with Timer died", TimerInst);
+
+ // If process was holding the semaphore, release it
+
+ if (Semaphore.Flag == 1 && TimerInst == Semaphore.SemProcessID)
+ {
+ OutputDebugString("BPQ32 Process was holding Semaphore - attempting recovery\r\n");
+ Debugprintf("Last Sem Call %d %x %x %x %x %x %x", SemHeldByAPI,
+ Sem_eax, Sem_ebx, Sem_ecx, Sem_edx, Sem_esi, Sem_edi);
+ Semaphore.Flag = 0;
+ SemHeldByAPI = 0;
+ }
+
+// KillTimer(NULL,TimerHandle);
+// TimerHandle=0;
+// TimerInst=0xffffffff;
+// Tell_Sessions();
+
+ CheckforLostProcesses(); // Normally only done in timer thread, which is now dead
+
+ // Timer can only run in BPQ32.exe
+
+ TimerInst=0xffffffff; // So we dont keep doing it
+ TimerHandle = 0; // So new process attaches
+
+ if (Closing == FALSE && AttachingProcess == FALSE)
+ {
+ OutputDebugString("BPQ32 Reloading BPQ32.exe\n");
+ StartBPQ32();
+ }
+
+// if (MinimizetoTray)
+// Shell_NotifyIcon(NIM_DELETE,&niData);
+ }
+
+ } while (TRUE);
+}
+
+VOID WritetoTraceSupport(struct TNCINFO * TNC, char * Msg, int Len);
+
+VOID TimerProcX();
+
+VOID CALLBACK TimerProc(
+ HWND hwnd, // handle of window for timer messages
+ UINT uMsg, // WM_TIMER message
+ UINT idEvent, // timer identifier
+ DWORD dwTime) // current system time
+{
+ KillTimer(NULL,TimerHandle);
+ TimerProcX();
+ TimerHandle = SetTimer(NULL,0,100,lpTimerFunc);
+}
+VOID TimerProcX()
+{
+ struct _EXCEPTION_POINTERS exinfo;
+
+ //
+ // Get semaphore before proceeeding
+ //
+
+ GetSemaphore(&Semaphore, 2);
+
+ // Get time since last run
+
+ QueryPerformanceCounter(¤tTime);
+
+ interval = (int)(currentTime.QuadPart - lastRunTime.QuadPart) / ticksPerMillisec;
+ lastRunTime.QuadPart = currentTime.QuadPart;
+
+ //Debugprintf("%d", interval);
+
+ // Process WINMORTraceQ
+
+ while (WINMORTraceQ)
+ {
+ UINT * Buffer = Q_REM(&WINMORTraceQ);
+ struct TNCINFO * TNC = (struct TNCINFO * )Buffer[1];
+ int Len = Buffer[2];
+ char * Msg = (char *)&Buffer[3];
+
+ WritetoTraceSupport(TNC, Msg, Len);
+ RelBuff(Buffer);
+ }
+
+ if (SetWindowTextQ)
+ SetWindowTextSupport();
+
+ while (WritetoConsoleQ)
+ {
+ UINT * Buffer = Q_REM(&WritetoConsoleQ);
+ WritetoConsoleSupport((char *)&Buffer[2]);
+ RelBuff(Buffer);
+ }
+
+ strcpy(EXCEPTMSG, "Timer ReconfigProcessing");
+
+ __try
+ {
+
+ if (trayMenu == NULL)
+ SetupTrayIcon();
+
+ // See if reconfigure requested
+
+ if (CloseAllNeeded)
+ {
+ CloseAllNeeded = FALSE;
+ CloseAllPrograms();
+ }
+
+ if (ReconfigFlag)
+ {
+ // Only do it it timer owning process, or we could get in a real mess!
+
+ if(TimerInst == GetCurrentProcessId())
+ {
+ int i;
+ BPQVECSTRUC * HOSTVEC;
+ PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
+ WSADATA WsaData; // receives data from WSAStartup
+ RECT cRect;
+
+ ReconfigFlag = FALSE;
+
+ SetupBPQDirectory();
+
+ WritetoConsole("Reconfiguring ...\n\n");
+ OutputDebugString("BPQ32 Reconfiguring ...\n");
+
+ GetWindowRect(FrameWnd, &FRect);
+
+ SaveWindowPos(70); // Rigcontrol
+
+ for (i=0;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();
+ PMClose();
+ APRSClose();
+ Rig_Close();
+ CloseTNCEmulator();
+ if (AGWActive)
+ AGWAPITerminate();
+
+ WSACleanup();
+
+ WL2KReports = NULL;
+
+ Sleep(2000);
+
+ WSAStartup(MAKEWORD(2, 0), &WsaData);
+
+ Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring);
+ Consoleprintf(VerCopyright);
+
+ Start();
+
+ INITIALISEPORTS(); // Restart Ports
+
+ SetApplPorts();
+
+ FreeConfig();
+
+ for (i=1; i<68; i++) // Include Telnet, APRS and IP Vec
+ {
+ HOSTVEC=&BPQHOSTVECTOR[i-1];
+
+ HOSTVEC->HOSTTRACEQ=0; // Clear header (pool has been reinitialized
+
+ if (HOSTVEC->HOSTSESSION !=0)
+ {
+ // Had a connection
+
+ HOSTVEC->HOSTSESSION=0;
+ HOSTVEC->HOSTFLAGS |=3; // Disconnected
+
+ PostMessage(HOSTVEC->HOSTHANDLE, BPQMsg, i, 4);
+ }
+ }
+
+ // Free the APRS Appl Q
+
+ APPL_Q = 0;
+
+ OpenReportingSockets();
+
+ WritetoConsole("\n\nReconfiguration Complete\n");
+
+ if (IPRequired) IPActive = Init_IP();
+ if (PMRequired) PMActive = Init_PM();
+
+ APRSActive = Init_APRS();
+
+ if (ISPort == 0)
+ IGateEnabled = 0;
+
+ CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled);
+
+ GetClientRect(hConsWnd, &cRect);
+ MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
+ if (APRSActive)
+ MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
+ else
+ {
+ ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE);
+ MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
+ }
+ InvalidateRect(hConsWnd, NULL, TRUE);
+
+ RigActive = Rig_Init();
+
+ if (NUMBEROFTNCPORTS)
+ {
+ FreeSemaphore(&Semaphore);
+ InitializeTNCEmulator();
+ GetSemaphore(&Semaphore, 0);
+ }
+
+ FreeSemaphore(&Semaphore);
+ AGWActive = AGWAPIInit();
+ GetSemaphore(&Semaphore, 0);
+
+ OutputDebugString("BPQ32 Reconfiguration Complete\n");
+ }
+ }
+
+
+ if (RigReconfigFlag)
+ {
+ // Only do it it timer owning process, or we could get in a real mess!
+
+ if(TimerInst == GetCurrentProcessId())
+ {
+ RigReconfigFlag = FALSE;
+ CloseDriverWindow(70);
+ Rig_Close();
+ Sleep(6000); // Allow any CATPTT, HAMLIB and FLRIG threads to close
+ RigActive = Rig_Init();
+
+ WritetoConsole("Rigcontrol Reconfiguration Complete\n");
+ }
+ }
+
+ if (APRSReconfigFlag)
+ {
+ // Only do it it timer owning process, or we could get in a real mess!
+
+ if(TimerInst == GetCurrentProcessId())
+ {
+ APRSReconfigFlag = FALSE;
+ APRSClose();
+ APRSActive = Init_APRS();
+
+ WritetoConsole("APRS Reconfiguration Complete\n");
+ }
+ }
+
+ }
+ #include "StdExcept.c"
+
+ if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId())
+ FreeSemaphore(&Semaphore);
+
+ }
+
+ strcpy(EXCEPTMSG, "Timer Processing");
+
+ __try
+ {
+ if (IPActive) Poll_IP();
+ if (PMActive) Poll_PM();
+ if (RigActive) Rig_Poll();
+
+ if (NeedWebMailRefresh)
+ DoRefreshWebMailIndex();
+
+ CheckGuardZone();
+
+ if (APRSActive)
+ {
+ Poll_APRS();
+ CheckGuardZone();
+ }
+
+ CheckWL2KReportTimer();
+
+ CheckGuardZone();
+
+ TIMERINTERRUPT();
+
+ CheckGuardZone();
+
+ FreeSemaphore(&Semaphore); // SendLocation needs to get the semaphore
+
+ if (NUMBEROFTNCPORTS)
+ TNCTimer();
+
+ if (AGWActive)
+ Poll_AGW();
+
+ DRATSPoll();
+ RHPPoll();
+
+ CheckGuardZone();
+
+ strcpy(EXCEPTMSG, "HTTP Timer Processing");
+
+ HTTPTimer();
+
+ CheckGuardZone();
+
+ strcpy(EXCEPTMSG, "WL2K Report Timer Processing");
+
+ if (ReportTimer)
+ {
+ ReportTimer--;
+
+ if (ReportTimer == 0)
+ {
+ ReportTimer = REPORTINTERVAL;
+ SendLocation();
+ }
+ }
+ }
+
+ #include "StdExcept.c"
+
+ if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId())
+ FreeSemaphore(&Semaphore);
+
+ }
+
+ CheckGuardZone();
+
+ return;
+}
+
+HANDLE NPHandle;
+
+int (WINAPI FAR *GetModuleFileNameExPtr)() = NULL;
+int (WINAPI FAR *EnumProcessesPtr)() = NULL;
+
+FirstInit()
+{
+ WSADATA WsaData; // receives data from WSAStartup
+ HINSTANCE ExtDriver=0;
+ RECT cRect;
+
+
+ // First Time Ports and Timer init
+
+ // Moved from DLLINIT to sort out perl problem, and meet MS Guidelines on minimising DLLMain
+
+ // Call wsastartup - most systems need winsock, and duplicate statups could be a problem
+
+ WSAStartup(MAKEWORD(2, 0), &WsaData);
+
+ // Load Psapi.dll if possible
+
+ ExtDriver=LoadLibrary("Psapi.dll");
+
+ SetupTrayIcon();
+
+ if (ExtDriver)
+ {
+ GetModuleFileNameExPtr = (FARPROCX)GetProcAddress(ExtDriver,"GetModuleFileNameExA");
+ EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses");
+ }
+
+ timeLoadedMS = GetTickCount();
+
+ INITIALISEPORTS();
+
+ OpenReportingSockets();
+
+ WritetoConsole("\n");
+ WritetoConsole("Port Initialisation Complete\n");
+
+ if (IPRequired) IPActive = Init_IP();
+ if (PMRequired) PMActive = Init_PM();
+
+ APRSActive = Init_APRS();
+
+ if (APRSActive)
+ {
+ hWndBG = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 0,0,40,546, hConsWnd, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Enable IGate", WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE,
+ 8,0,90,24, hConsWnd, (HMENU)-1, hInstance, NULL);
+
+ CreateWindowEx(0, "BUTTON", "", WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,
+ 95,1,18,24, hConsWnd, (HMENU)IDC_ENIGATE, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "IGate State - Disconnected",
+ WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 125, 0, 195, 24, hConsWnd, (HMENU)IGATESTATE, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "IGATE Stats - Msgs 0 Local Stns 0",
+ WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 320, 0, 240, 24, hConsWnd, (HMENU)IGATESTATS, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "GPS Off",
+ WS_CHILD | WS_VISIBLE | SS_CENTERIMAGE, 560, 0, 80, 24, hConsWnd, (HMENU)IDC_GPS, hInstance, NULL);
+ }
+
+ if (ISPort == 0)
+ IGateEnabled = 0;
+
+ CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled);
+
+ GetClientRect(hConsWnd, &cRect);
+ MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
+ if (APRSActive)
+ MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
+ else
+ {
+ ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE);
+ MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
+ }
+ InvalidateRect(hConsWnd, NULL, TRUE);
+
+ RigActive = Rig_Init();
+
+ _beginthread(MonitorThread,0,0);
+
+ TimerHandle=SetTimer(NULL,0,100,lpTimerFunc);
+ TimerInst=GetCurrentProcessId();
+ SessHandle = SetTimer(NULL, 0, 5000, lpSetupTermSessions);
+
+ // If ARIF reporting is enabled write a Trimode Like ini for RMS Analyser
+
+ if (ADIFLogEnabled)
+ ADIFWriteFreqList();
+
+ OutputDebugString("BPQ32 Port Initialisation Complete\n");
+
+ if (needAIS)
+ initAIS();
+
+ if (needADSB)
+ initADSB();
+
+ return 0;
+}
+
+Check_Timer()
+{
+ if (Closing)
+ return 0;
+
+ if (Semaphore.Flag)
+ return 0;
+
+ if (InitDone == (void *)-1)
+ {
+ GetSemaphore(&Semaphore, 3);
+ Sleep(15000);
+ FreeSemaphore(&Semaphore);
+ exit (0);
+ }
+
+ if (FirstInitDone == 0)
+ {
+ GetSemaphore(&Semaphore, 3);
+
+ if (_stricmp(pgm, "bpq32.exe") == 0)
+ {
+ FirstInit();
+ FreeSemaphore(&Semaphore);
+ if (NUMBEROFTNCPORTS)
+ InitializeTNCEmulator();
+
+ AGWActive = AGWAPIInit();
+ FirstInitDone=1; // Only init in BPQ32.exe
+ return 0;
+ }
+ else
+ {
+ FreeSemaphore(&Semaphore);
+ return 0;
+ }
+ }
+
+ if (TimerHandle == 0 && FirstInitDone == 1)
+ {
+ WSADATA WsaData; // receives data from WSAStartup
+ HINSTANCE ExtDriver=0;
+ RECT cRect;
+
+ // Only attach timer to bpq32.exe
+
+ if (_stricmp(pgm, "bpq32.exe") != 0)
+ {
+ return 0;
+ }
+
+ GetSemaphore(&Semaphore, 3);
+ OutputDebugString("BPQ32 Reinitialising External Ports and Attaching Timer\n");
+
+ if (!ProcessConfig())
+ {
+ ShowWindow(hConsWnd, SW_RESTORE);
+ SendMessage(hConsWnd, WM_PAINT, 0, 0);
+ SetForegroundWindow(hConsWnd);
+
+ InitDone = (void *)-1;
+ FreeSemaphore(&Semaphore);
+
+ MessageBox(NULL,"Configuration File Error","BPQ32",MB_ICONSTOP);
+
+ exit (0);
+ }
+
+ GetVersionInfo("bpq32.dll");
+
+ SetupConsoleWindow();
+
+ Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring);
+ Consoleprintf(VerCopyright);
+ Consoleprintf("Reinitialising...");
+
+ SetupBPQDirectory();
+
+ Sleep(1000); // Allow time for sockets to close
+
+ WSAStartup(MAKEWORD(2, 0), &WsaData);
+
+ // Load Psapi.dll if possible
+
+ ExtDriver = LoadLibrary("Psapi.dll");
+
+ SetupTrayIcon();
+
+ if (ExtDriver)
+ {
+ GetModuleFileNameExPtr = (FARPROCX)GetProcAddress(ExtDriver,"GetModuleFileNameExA");
+ EnumProcessesPtr = (FARPROCX)GetProcAddress(ExtDriver,"EnumProcesses");
+ }
+
+ Start();
+
+ INITIALISEPORTS();
+
+ OpenReportingSockets();
+
+ NODESINPROGRESS = 0;
+ CURRENTNODE = 0;
+
+ SetApplPorts();
+
+ WritetoConsole("\n\nPort Reinitialisation Complete\n");
+
+ BPQMsg = RegisterWindowMessage(BPQWinMsg);
+
+ CreateMutex(NULL,TRUE,"BPQLOCKMUTEX");
+
+// NPHandle=CreateNamedPipe("\\\\.\\pipe\\BPQ32pipe",
+// PIPE_ACCESS_DUPLEX,0,64,4096,4096,1000,NULL);
+
+ if (IPRequired) IPActive = Init_IP();
+ if (PMRequired) PMActive = Init_PM();
+
+ RigActive = Rig_Init();
+ APRSActive = Init_APRS();
+
+ if (ISPort == 0)
+ IGateEnabled = 0;
+
+ CheckDlgButton(hConsWnd, IDC_ENIGATE, IGateEnabled);
+
+ GetClientRect(hConsWnd, &cRect);
+ MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
+
+ if (APRSActive)
+ MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
+ else
+ {
+ ShowWindow(GetDlgItem(hConsWnd, IDC_GPS), SW_HIDE);
+ MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
+ }
+ InvalidateRect(hConsWnd, NULL, TRUE);
+
+ FreeConfig();
+
+ _beginthread(MonitorThread,0,0);
+
+ ReportTimer = 0;
+
+ OpenReportingSockets();
+
+ FreeSemaphore(&Semaphore);
+
+ if (NUMBEROFTNCPORTS)
+ InitializeTNCEmulator();
+
+ AGWActive = AGWAPIInit();
+
+ if (StartMinimized)
+ if (MinimizetoTray)
+ ShowWindow(FrameWnd, SW_HIDE);
+ else
+ ShowWindow(FrameWnd, SW_SHOWMINIMIZED);
+ else
+ ShowWindow(FrameWnd, SW_RESTORE);
+
+ TimerHandle=SetTimer(NULL,0,100,lpTimerFunc);
+ TimerInst=GetCurrentProcessId();
+ SessHandle = SetTimer(NULL, 0, 5000, lpSetupTermSessions);
+
+ return (1);
+ }
+
+ return (0);
+}
+
+DllExport INT APIENTRY CheckTimer()
+{
+ return Check_Timer();
+}
+
+Tell_Sessions()
+{
+ //
+ // Post a message to all listening sessions, so they call the
+ // API, and cause a new timer to be allocated
+ //
+ HWND hWnd;
+ int i;
+
+ for (i=1;i<65;i++)
+ {
+ if (BPQHOSTVECTOR[i-1].HOSTFLAGS & 0x80)
+ {
+ hWnd = BPQHOSTVECTOR[i-1].HOSTHANDLE;
+ PostMessage(hWnd, BPQMsg,i, 1);
+ PostMessage(hWnd, BPQMsg,i, 2);
+ }
+ }
+ return (0);
+}
+
+BOOL APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID lpReserved)
+{
+ DWORD n;
+ char buf[350];
+
+ int i;
+ unsigned int ProcessID;
+
+ OSVERSIONINFO osvi;
+
+ memset(&osvi, 0, sizeof(OSVERSIONINFO));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ GetVersionEx(&osvi);
+
+
+ switch( ul_reason_being_called )
+ {
+ case DLL_PROCESS_ATTACH:
+
+ if (sizeof(HDLCDATA) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata
+ {
+ // Catastrophic - Refuse to load
+
+ MessageBox(NULL,"BPQ32 Too much HDLC data - Recompile","BPQ32", MB_OK);
+ return 0;
+ }
+
+ if (sizeof(struct KISSINFO) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata
+ {
+ // Catastrophic - Refuse to load
+
+ MessageBox(NULL,"BPQ32 Too much KISS data - Recompile","BPQ32", MB_OK);
+ return 0;
+ }
+
+ if (sizeof(struct _EXTPORTDATA) > PORTENTRYLEN + 200) // 200 bytes of Hardwaredata
+ {
+ // Catastrophic - Refuse to load
+
+ MessageBox(NULL,"BPQ32 Too much _EXTPORTDATA data - Recompile","BPQ32", MB_OK);
+ return 0;
+ }
+
+ if (sizeof(LINKTABLE) != LINK_TABLE_LEN)
+ {
+ // Catastrophic - Refuse to load
+
+ MessageBox(NULL,"L2 LINK Table .c and .asm mismatch - fix and rebuild","BPQ32", MB_OK);
+ return 0;
+ }
+ if (sizeof(struct ROUTE) != ROUTE_LEN)
+ {
+ // Catastrophic - Refuse to load
+
+ MessageBox(NULL,"ROUTE Table .c and .asm mismatch - fix and rebuild", "BPQ32", MB_OK);
+ return 0;
+ }
+
+ if (sizeof(struct DEST_LIST) != DEST_LIST_LEN)
+ {
+ // Catastrophic - Refuse to load
+
+ MessageBox(NULL,"NODES Table .c and .asm mismatch - fix and rebuild", "BPQ32", MB_OK);
+ return 0;
+ }
+
+ GetSemaphore(&Semaphore, 4);
+
+ BPQHOSTVECPTR = &BPQHOSTVECTOR[0];
+
+ LoadToolHelperRoutines();
+
+ Our_PID = GetCurrentProcessId();
+
+ QueryPerformanceFrequency(&lpFrequency);
+
+ ticksPerMillisec = (int)lpFrequency.QuadPart / 1000;
+
+ lastRunTime.QuadPart = lpFrequency.QuadPart;
+
+ GetProcess(Our_PID, pgm);
+
+ if (_stricmp(pgm, "regsvr32.exe") == 0 || _stricmp(pgm, "bpqcontrol.exe") == 0)
+ {
+ AttachedProcesses++; // We will get a detach
+ FreeSemaphore(&Semaphore);
+ return 1;
+ }
+
+ if (_stricmp(pgm,"BPQ32.exe") == 0)
+ BPQ32_EXE = TRUE;
+
+ if (_stricmp(pgm,"BPQMailChat.exe") == 0)
+ IncludesMail = TRUE;
+
+ if (_stricmp(pgm,"BPQMail.exe") == 0)
+ IncludesMail = TRUE;
+
+ if (_stricmp(pgm,"BPQChat.exe") == 0)
+ IncludesChat = TRUE;
+
+ if (FirstEntry) // If loaded by BPQ32.exe, dont close it at end
+ {
+ FirstEntry = 0;
+ if (BPQ32_EXE)
+ CloseLast = FALSE;
+ }
+ else
+ {
+ if (BPQ32_EXE && AttachingProcess == 0)
+ {
+ AttachedProcesses++; // We will get a detach
+ FreeSemaphore(&Semaphore);
+ MessageBox(NULL,"BPQ32.exe is already running\r\n\r\nIt should only be run once", "BPQ32", MB_OK);
+ return 0;
+ }
+ }
+
+ if (_stricmp(pgm,"BPQTelnetServer.exe") == 0)
+ {
+ MessageBox(NULL,"BPQTelnetServer is no longer supported\r\n\r\nUse the TelnetServer in BPQ32.dll", "BPQ32", MB_OK);
+ AttachedProcesses++; // We will get a detach
+ FreeSemaphore(&Semaphore);
+ return 0;
+ }
+
+ if (_stricmp(pgm,"BPQUIUtil.exe") == 0)
+ {
+ MessageBox(NULL,"BPQUIUtil is now part of BPQ32.dll\r\nBPQUIUtil.exe cannot be run\r\n", "BPQ32", MB_OK);
+ AttachedProcesses++; // We will get a detach
+ FreeSemaphore(&Semaphore);
+ return 0;
+ }
+
+ if (_stricmp(pgm,"BPQMailChat.exe") == 0)
+ {
+ MessageBox(NULL,"BPQMailChat is obsolete. Run BPQMail.exe and/or BPQChat.exe instead", "BPQ32", MB_OK);
+ AttachedProcesses++; // We will get a detach
+ FreeSemaphore(&Semaphore);
+ return 0;
+ }
+ AuthorisedProgram = TRUE;
+
+ if (InitDone == 0)
+ {
+// #pragma warning(push)
+// #pragma warning(disable : 4996)
+
+// if (_winver < 0x0600)
+// #pragma warning(pop)
+// {
+// // Below Vista
+//
+// REGTREE = HKEY_LOCAL_MACHINE;
+// strcpy(REGTREETEXT, "HKEY_LOCAL_MACHINE");
+// }
+
+ hInstance=hInst;
+
+ Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX");
+
+ if (Mutex != NULL)
+ {
+ OutputDebugString("Another BPQ32.dll is loaded\n");
+ i=MessageBox(NULL,"BPQ32 DLL already loaded from another directory\nIf you REALLY want this, hit OK, else hit Cancel","BPQ32",MB_OKCANCEL);
+ FreeSemaphore(&Semaphore);
+
+ if (i != IDOK) return (0);
+
+ CloseHandle(Mutex);
+ }
+
+ if (!BPQ32_EXE)
+ {
+ if (CheckifBPQ32isLoaded() == FALSE) // Start BPQ32.exe if needed
+ {
+ // Wasn't Loaded, so we have started it, and should let it init system
+
+ goto SkipInit;
+ }
+ }
+
+ GetVersionInfo("bpq32.dll");
+
+ sprintf (SIGNONMSG, "G8BPQ AX25 Packet Switch System Version %s %s\r\n%s\r\n",
+ TextVerstring, Datestring, VerCopyright);
+
+ SESSHDDRLEN = sprintf(SESSIONHDDR, "G8BPQ Network System %s for Win32 (", TextVerstring);
+
+ SetupConsoleWindow();
+ SetupBPQDirectory();
+
+ if (!ProcessConfig())
+ {
+ StartMinimized = FALSE;
+ MinimizetoTray = FALSE;
+ ShowWindow(FrameWnd, SW_MAXIMIZE);
+ ShowWindow(hConsWnd, SW_MAXIMIZE);
+ ShowWindow(StatusWnd, SW_HIDE);
+
+ SendMessage(hConsWnd, WM_PAINT, 0, 0);
+ SetForegroundWindow(hConsWnd);
+
+ InitDone = (void *)-1;
+ FreeSemaphore(&Semaphore);
+
+ MessageBox(NULL,"Configuration File Error\r\nProgram will close in 15 seconds","BPQ32",MB_ICONSTOP);
+
+ return (0);
+ }
+
+ Consoleprintf("G8BPQ AX25 Packet Switch System Version %s %s", TextVerstring, Datestring);
+ Consoleprintf(VerCopyright);
+
+ if (Start() !=0)
+ {
+ Sleep(3000);
+ FreeSemaphore(&Semaphore);
+ return (0);
+ }
+ else
+ {
+ SetApplPorts();
+
+ GetUIConfig();
+
+ InitDone = &InitDone;
+ BPQMsg = RegisterWindowMessage(BPQWinMsg);
+// TimerHandle=SetTimer(NULL,0,100,lpTimerFunc);
+// TimerInst=GetCurrentProcessId();
+
+/* Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX");
+
+ if (Mutex != NULL)
+ {
+ OutputDebugString("Another BPQ32.dll is loaded\n");
+ MessageBox(NULL,"BPQ32 DLL already loaded from another directory","BPQ32",MB_ICONSTOP);
+ FreeSemaphore(&Semaphore);
+ return (0);
+ }
+
+*/
+ Mutex=CreateMutex(NULL,TRUE,"BPQLOCKMUTEX");
+
+// CreatePipe(&H1,&H2,NULL,1000);
+
+// GetLastError();
+
+// NPHandle=CreateNamedPipe("\\\\.\\pipe\\BPQ32pipe",
+// PIPE_ACCESS_DUPLEX,0,64,4096,4096,1000,NULL);
+
+// GetLastError();
+
+/*
+ //
+ // Read SYSOP password
+ //
+
+ if (PWTEXT[0] == 0)
+ {
+ handle = OpenConfigFile("PASSWORD.BPQ");
+
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ WritetoConsole("Can't open PASSWORD.BPQ\n");
+ PWLen=0;
+ PWTEXT[0]=0;
+ }
+ else
+ {
+ ReadFile(handle,PWTEXT,78,&n,NULL);
+ CloseHandle(handle);
+ }
+ }
+*/
+ for (i=0;PWTEXT[i] > 0x20;i++); //Scan for cr or null
+ PWLen=i;
+
+ }
+ }
+ else
+ {
+ if (InitDone != &InitDone)
+ {
+ MessageBox(NULL,"BPQ32 DLL already loaded at another address","BPQ32",MB_ICONSTOP);
+ FreeSemaphore(&Semaphore);
+ return (0);
+ }
+ }
+
+ // Run timer monitor thread in all processes - it is possible for the TImer thread not to be the first thread
+SkipInit:
+
+ _beginthread(MonitorTimerThread,0,0);
+
+ FreeSemaphore(&Semaphore);
+
+ AttachedPIDList[AttachedProcesses++] = GetCurrentProcessId();
+
+ if (_stricmp(pgm,"bpq32.exe") == 0 && AttachingProcess == 1) AttachingProcess = 0;
+
+ GetProcess(GetCurrentProcessId(),pgm);
+ n=sprintf(buf,"BPQ32 DLL Attach complete - Program %s - %d Process(es) Attached\n",pgm,AttachedProcesses);
+ OutputDebugString(buf);
+
+ // Set up local variables
+
+ MCOM=1;
+ MTX=1;
+ MMASK=0xffffffffffffffff;
+
+// if (StartMinimized)
+// if (MinimizetoTray)
+// ShowWindow(FrameWnd, SW_HIDE);
+// else
+// ShowWindow(FrameWnd, SW_SHOWMINIMIZED);
+// else
+// ShowWindow(FrameWnd, SW_RESTORE);
+
+ return 1;
+
+ case DLL_THREAD_ATTACH:
+
+ return 1;
+
+ case DLL_THREAD_DETACH:
+
+ return 1;
+
+ case DLL_PROCESS_DETACH:
+
+ if (_stricmp(pgm,"BPQMailChat.exe") == 0)
+ IncludesMail = FALSE;
+
+ if (_stricmp(pgm,"BPQChat.exe") == 0)
+ IncludesChat = FALSE;
+
+ ProcessID=GetCurrentProcessId();
+
+ Debugprintf("BPQ32 Process %d Detaching", ProcessID);
+
+ // Release any streams that the app has failed to release
+
+ for (i=1;i<65;i++)
+ {
+ if (BPQHOSTVECTOR[i-1].STREAMOWNER == ProcessID)
+ {
+ // If connected, disconnect
+
+ SessionControl(i, 2, 0);
+ DeallocateStream(i);
+ }
+ }
+
+ // Remove any Tray Icon Entries
+
+ for( i = 0; i < 100; ++i )
+ {
+ if (PIDArray[i] == ProcessID)
+ {
+ char Log[80];
+ hWndArray[i] = 0;
+ sprintf(Log,"BPQ32 Removing Tray Item %s\n", PopupText[i]);
+ OutputDebugString(Log);
+ DeleteMenu(trayMenu,TRAYBASEID+i,MF_BYCOMMAND);
+ }
+ }
+
+ if (Mutex) CloseHandle(Mutex);
+
+ // Remove our entry from PID List
+
+ for (i=0; i< AttachedProcesses; i++)
+ if (AttachedPIDList[i] == ProcessID)
+ break;
+
+ for (; i< AttachedProcesses; i++)
+ {
+ AttachedPIDList[i]=AttachedPIDList[i+1];
+ }
+
+ AttachedProcesses--;
+
+ if (TimerInst == ProcessID)
+ {
+ PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
+
+ OutputDebugString("BPQ32 Process with Timer closing\n");
+
+ // Call Port Close Routines
+
+ for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External
+ {
+ if (PORTVEC->PORT_EXT_ADDR && PORTVEC->DLLhandle == NULL) // Don't call if real .dll - it's not there!
+ {
+ SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
+ SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
+ PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL); // Close External Ports
+ }
+ }
+
+ PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL);
+
+ PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
+ }
+
+
+ IPClose();
+ PMClose();
+ APRSClose();
+ Rig_Close();
+ CloseTNCEmulator();
+ if (AGWActive)
+ AGWAPITerminate();
+
+ upnpClose();
+
+ WSACleanup();
+ WSAGetLastError();
+
+ if (MinimizetoTray)
+ Shell_NotifyIcon(NIM_DELETE,&niData);
+
+ if (hConsWnd) DestroyWindow(hConsWnd);
+
+ KillTimer(NULL,TimerHandle);
+ TimerHandle=0;
+ TimerInst=0xffffffff;
+
+ if (AttachedProcesses && Closing == FALSE && AttachingProcess == 0) // Other processes
+ {
+ OutputDebugString("BPQ32 Reloading BPQ32.exe\n");
+ StartBPQ32();
+ }
+ }
+ else
+ {
+ // Not Timer Process
+
+ if (AttachedProcesses == 1 && CloseLast) // Only bpq32.exe left
+ {
+ Debugprintf("Only BPQ32.exe running - close it");
+ CloseAllNeeded = TRUE;
+ }
+ }
+
+ if (AttachedProcesses < 2)
+ {
+ if (AUTOSAVE)
+ SaveNodes();
+ if (AUTOSAVEMH)
+ SaveMH();
+
+ if (needAIS)
+ SaveAIS();
+ }
+ if (AttachedProcesses == 0)
+ {
+ Closing = TRUE;
+ KillTimer(NULL,TimerHandle);
+
+ if (MinimizetoTray)
+ Shell_NotifyIcon(NIM_DELETE,&niData);
+
+ // Unload External Drivers
+
+ {
+ PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
+
+ for (i=0;iPORTCONTROL.PORTTYPE == 0x10 && PORTVEC->DLLhandle)
+ FreeLibrary(PORTVEC->DLLhandle);
+
+ PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
+ }
+ }
+ }
+
+ GetProcess(GetCurrentProcessId(),pgm);
+ n=sprintf(buf,"BPQ32 DLL Detach complete - Program %s - %d Process(es) Attached\n",pgm,AttachedProcesses);
+ OutputDebugString(buf);
+
+ return 1;
+ }
+ return 1;
+}
+
+DllExport int APIENTRY CloseBPQ32()
+{
+ // Unload External Drivers
+
+ PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
+ int i;
+ int ProcessID = GetCurrentProcessId();
+
+ if (Semaphore.Flag == 1 && ProcessID == Semaphore.SemProcessID)
+ {
+ OutputDebugString("BPQ32 Process holding Semaphore called CloseBPQ32 - attempting recovery\r\n");
+ Debugprintf("Last Sem Call %d %x %x %x %x %x %x", SemHeldByAPI,
+ Sem_eax, Sem_ebx, Sem_ecx, Sem_edx, Sem_esi, Sem_edi);
+
+ Semaphore.Flag = 0;
+ SemHeldByAPI = 0;
+ }
+
+ if (TimerInst == ProcessID)
+ {
+ OutputDebugString("BPQ32 Process with Timer called CloseBPQ32\n");
+
+ if (MinimizetoTray)
+ Shell_NotifyIcon(NIM_DELETE,&niData);
+
+ for (i=0;iPORTCONTROL.PORTTYPE == 0x10) // External
+ {
+ if (PORTVEC->PORT_EXT_ADDR)
+ {
+ PORTVEC->PORT_EXT_ADDR(5,PORTVEC->PORTCONTROL.PORTNUMBER, NULL);
+ }
+ }
+ PORTVEC->PORTCONTROL.PORTCLOSECODE(&PORTVEC->PORTCONTROL);
+
+ PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
+ }
+
+ KillTimer(NULL,TimerHandle);
+ TimerHandle=0;
+ TimerInst=0xffffffff;
+
+ IPClose();
+ PMClose();
+ APRSClose();
+ Rig_Close();
+ if (AGWActive)
+ AGWAPITerminate();
+
+ upnpClose();
+
+ CloseTNCEmulator();
+ WSACleanup();
+
+ if (hConsWnd) DestroyWindow(hConsWnd);
+
+ Debugprintf("AttachedProcesses %d ", AttachedProcesses);
+
+ if (AttachedProcesses > 1 && Closing == FALSE && AttachingProcess == 0) // Other processes
+ {
+ OutputDebugString("BPQ32 Reloading BPQ32.exe\n");
+ StartBPQ32();
+ }
+ }
+
+ return 0;
+}
+
+BOOL CopyReg(HKEY hKeyIn, HKEY hKeyOut);
+
+VOID SetupBPQDirectory()
+{
+ HKEY hKey = 0;
+ HKEY hKeyIn = 0;
+ HKEY hKeyOut = 0;
+ int disp;
+ int retCode,Type,Vallen=MAX_PATH,i;
+ char msg[512];
+ char ValfromReg[MAX_PATH] = "";
+ char DLLName[256]="Not Known";
+ char LogDir[256];
+ char Time[64];
+
+/*
+•NT4 was/is '4'
+•Win 95 is 4.00.950
+•Win 98 is 4.10.1998
+•Win 98 SE is 4.10.2222
+•Win ME is 4.90.3000
+•2000 is NT 5.0.2195
+•XP is actually 5.1
+•Vista is 6.0
+•Win7 is 6.1
+
+ i = _osver; / Build
+ i = _winmajor;
+ i = _winminor;
+*/
+/*
+#pragma warning(push)
+#pragma warning(disable : 4996)
+
+if (_winver < 0x0600)
+#pragma warning(pop)
+ {
+ // Below Vista
+
+ REGTREE = HKEY_LOCAL_MACHINE;
+ strcpy(REGTREETEXT, "HKEY_LOCAL_MACHINE");
+ ValfromReg[0] = 0;
+ }
+ else
+*/
+ {
+ if (_stricmp(pgm, "regsvr32.exe") == 0)
+ {
+ Debugprintf("BPQ32 loaded by regsvr32.exe - Registry not copied");
+ }
+ else
+ {
+ // If necessary, move reg from HKEY_LOCAL_MACHINE to HKEY_CURRENT_USER
+
+ retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\G8BPQ\\BPQ32",
+ 0,
+ KEY_READ,
+ &hKeyIn);
+
+ retCode = RegCreateKeyEx(HKEY_CURRENT_USER, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKeyOut, &disp);
+
+ // See if Version Key exists in HKEY_CURRENT_USER - if it does, we have already done the copy
+
+ Vallen = MAX_PATH;
+ retCode = RegQueryValueEx(hKeyOut, "Version" ,0 , &Type,(UCHAR *)&msg, &Vallen);
+
+ if (retCode != ERROR_SUCCESS)
+ if (hKeyIn)
+ CopyReg(hKeyIn, hKeyOut);
+
+ RegCloseKey(hKeyIn);
+ RegCloseKey(hKeyOut);
+ }
+ }
+
+ GetModuleFileName(hInstance,DLLName,256);
+
+ BPQDirectory[0]=0;
+
+ retCode = RegOpenKeyEx (REGTREE,
+ "SOFTWARE\\G8BPQ\\BPQ32",
+ 0,
+ KEY_QUERY_VALUE,
+ &hKey);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ // Try "BPQ Directory"
+
+ Vallen = MAX_PATH;
+ retCode = RegQueryValueEx(hKey,"BPQ Directory",0,
+ &Type,(UCHAR *)&ValfromReg,&Vallen);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ if (strlen(ValfromReg) == 2 && ValfromReg[0] == '"' && ValfromReg[1] == '"')
+ ValfromReg[0]=0;
+ }
+
+ if (ValfromReg[0] == 0)
+ {
+ // BPQ Directory absent or = "" - try "Config File Location"
+
+ Vallen = MAX_PATH;
+
+ retCode = RegQueryValueEx(hKey,"Config File Location",0,
+ &Type,(UCHAR *)&ValfromReg,&Vallen);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ if (strlen(ValfromReg) == 2 && ValfromReg[0] == '"' && ValfromReg[1] == '"')
+ ValfromReg[0]=0;
+ }
+ }
+
+ if (ValfromReg[0] == 0) GetCurrentDirectory(MAX_PATH, ValfromReg);
+
+ // Get StartMinimized and MinimizetoTray flags
+
+ Vallen = 4;
+ retCode = RegQueryValueEx(hKey, "Start Minimized", 0, &Type, (UCHAR *)&StartMinimized, &Vallen);
+
+ Vallen = 4;
+ retCode = RegQueryValueEx(hKey, "Minimize to Tray", 0, &Type, (UCHAR *)&MinimizetoTray, &Vallen);
+
+ ExpandEnvironmentStrings(ValfromReg, BPQDirectory, MAX_PATH);
+
+ // Also get "BPQ Program Directory"
+
+ ValfromReg[0] = 0;
+ Vallen = MAX_PATH;
+
+ retCode = RegQueryValueEx(hKey, "BPQ Program Directory",0 , &Type, (UCHAR *)&ValfromReg, &Vallen);
+
+ if (retCode == ERROR_SUCCESS)
+ ExpandEnvironmentStrings(ValfromReg, BPQProgramDirectory, MAX_PATH);
+
+ // And Log Directory
+
+ ValfromReg[0] = 0;
+ Vallen = MAX_PATH;
+
+ retCode = RegQueryValueEx(hKey, "Log Directory",0 , &Type, (UCHAR *)&ValfromReg, &Vallen);
+
+ if (retCode == ERROR_SUCCESS)
+ ExpandEnvironmentStrings(ValfromReg, LogDirectory, MAX_PATH);
+
+ RegCloseKey(hKey);
+ }
+
+ strcpy(ConfigDirectory, BPQDirectory);
+
+ if (LogDirectory[0] == 0)
+ strcpy(LogDirectory, BPQDirectory);
+
+ if (BPQProgramDirectory[0] == 0)
+ strcpy(BPQProgramDirectory, BPQDirectory);
+
+ sprintf(msg,"BPQ32 Ver %s Loaded from: %s by %s\n", VersionString, DLLName, pgm);
+ WritetoConsole(msg);
+ OutputDebugString(msg);
+ FormatTime3(Time, time(NULL));
+ sprintf(msg,"Loaded %s\n", Time);
+ WritetoConsole(msg);
+ OutputDebugString(msg);
+
+#pragma warning(push)
+#pragma warning(disable : 4996)
+
+#if _MSC_VER >= 1400
+
+#define _winmajor 6
+#define _winminor 0
+
+#endif
+
+ i=sprintf(msg,"Windows Ver %d.%d, Using Registry Key %s\n" ,_winmajor, _winminor, REGTREETEXT);
+
+#pragma warning(pop)
+
+ WritetoConsole(msg);
+ OutputDebugString(msg);
+
+ i=sprintf(msg,"BPQ32 Using config from: %s\n\n",BPQDirectory);
+ WritetoConsole(&msg[6]);
+ msg[i-1]=0;
+ OutputDebugString(msg);
+
+ // Don't write the Version Key if loaded by regsvr32.exe (Installer is running with Admin rights,
+ // so will write the wrong tree on )
+
+ if (_stricmp(pgm, "regsvr32.exe") == 0)
+ {
+ Debugprintf("BPQ32 loaded by regsvr32.exe - Version String not written");
+ }
+ else
+ {
+ retCode = RegCreateKeyEx(REGTREE, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp);
+
+ sprintf(msg,"%d,%d,%d,%d", Ver[0], Ver[1], Ver[2], Ver[3]);
+ retCode = RegSetValueEx(hKey, "Version",0, REG_SZ,(BYTE *)msg, strlen(msg) + 1);
+
+ RegCloseKey(hKey);
+ }
+
+ // Make sure Logs Directory exists
+
+ sprintf(LogDir, "%s/Logs", LogDirectory);
+
+ CreateDirectory(LogDir, NULL);
+
+ return;
+}
+
+HANDLE OpenConfigFile(char *fn)
+{
+ HANDLE handle;
+ UCHAR Value[MAX_PATH];
+ FILETIME LastWriteTime;
+ SYSTEMTIME Time;
+ char Msg[256];
+
+
+ // If no directory, use current
+ if (BPQDirectory[0] == 0)
+ {
+ strcpy(Value,fn);
+ }
+ else
+ {
+ strcpy(Value,BPQDirectory);
+ strcat(Value,"\\");
+ strcat(Value,fn);
+ }
+
+ handle = CreateFile(Value,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ GetFileTime(handle, NULL, NULL, &LastWriteTime);
+ FileTimeToSystemTime(&LastWriteTime, &Time);
+
+ sprintf(Msg,"BPQ32 Config File %s Created %.2d:%.2d %d/%.2d/%.2d\n", Value,
+ Time.wHour, Time.wMinute, Time.wYear, Time.wMonth, Time.wDay);
+
+ OutputDebugString(Msg);
+
+ return(handle);
+}
+
+#ifdef _WIN64
+int BPQHOSTAPI()
+{
+ return 0;
+}
+#endif
+
+
+DllExport int APIENTRY GETBPQAPI()
+{
+ return (int)BPQHOSTAPI;
+}
+
+//DllExport UINT APIENTRY GETMONDECODE()
+//{
+// return (UINT)MONDECODE;
+//}
+
+
+DllExport INT APIENTRY BPQAPI(int Fn, char * params)
+{
+
+/*
+;
+; BPQ HOST MODE SUPPORT CODE
+;
+; 22/11/95
+;
+; MOVED FROM TNCODE.ASM COS CONITIONALS WERE GETTING TOO COMPLICATED
+; (OS2 VERSION HAD UPSET KANT VERISON
+;
+;
+*/
+
+
+/*
+
+ BPQHOSTPORT:
+;
+; SPECIAL INTERFACE, MAINLY FOR EXTERNAL HOST MODE SUPPORT PROGS
+;
+; COMMANDS SUPPORTED ARE
+;
+; AH = 0 Get node/switch version number and description. On return
+; AH='B',AL='P',BH='Q',BL=' '
+; DH = major version number and DL = minor version number.
+;
+;
+; AH = 1 Set application mask to value in DL (or even DX if 16
+; applications are ever to be supported).
+;
+; Set application flag(s) to value in CL (or CX).
+; whether user gets connected/disconnected messages issued
+; by the node etc.
+;
+;
+; AH = 2 Send frame in ES:SI (length CX)
+;
+;
+; AH = 3 Receive frame into buffer at ES:DI, length of frame returned
+; in CX. BX returns the number of outstanding frames still to
+; be received (ie. after this one) or zero if no more frames
+; (ie. this is last one).
+;
+;
+;
+; AH = 4 Get stream status. Returns:
+;
+; CX = 0 if stream disconnected or CX = 1 if stream connected
+; DX = 0 if no change of state since last read, or DX = 1 if
+; the connected/disconnected state has changed since
+; last read (ie. delta-stream status).
+;
+;
+;
+; AH = 6 Session control.
+;
+; CX = 0 Conneect - _APPLMASK in DL
+; CX = 1 connect
+; CX = 2 disconnect
+; CX = 3 return user to node
+;
+;
+; AH = 7 Get buffer counts for stream. Returns:
+;
+; AX = number of status change messages to be received
+; BX = number of frames queued for receive
+; CX = number of un-acked frames to be sent
+; DX = number of buffers left in node
+; SI = number of trace frames queued for receive
+;
+;AH = 8 Port control/information. Called with a stream number
+; in AL returns:
+;
+; AL = Radio port on which channel is connected (or zero)
+; AH = SESSION TYPE BITS
+; BX = L2 paclen for the radio port
+; CX = L2 maxframe for the radio port
+; DX = L4 window size (if L4 circuit, or zero)
+; ES:DI = CALLSIGN
+
+;AH = 9 Fetch node/application callsign & alias. AL = application
+; number:
+;
+; 0 = node
+; 1 = BBS
+; 2 = HOST
+; 3 = SYSOP etc. etc.
+;
+; Returns string with alias & callsign or application name in
+; user's buffer pointed to by ES:SI length CX. For example:
+;
+; "WORCS:G8TIC" or "TICPMS:G8TIC-10".
+;
+;
+; AH = 10 Unproto transmit frame. Data pointed to by ES:SI, of
+; length CX, is transmitted as a HDLC frame on the radio
+; port (not stream) in AL.
+;
+;
+; AH = 11 Get Trace (RAW Data) Frame into ES:DI,
+; Length to CX, Timestamp to AX
+;
+;
+; AH = 12 Update Switch. At the moment only Beacon Text may be updated
+; DX = Function
+; 1=update BT. ES:SI, Len CX = Text
+; 2=kick off nodes broadcast
+;
+; AH = 13 Allocate/deallocate stream
+; If AL=0, return first free stream
+; If AL>0, CL=1, Allocate stream. If aleady allocated,
+; return CX nonzero, else allocate, and return CX=0
+; If AL>0, CL=2, Release stream
+;
+;
+; AH = 14 Internal Interface for IP Router
+;
+; Send frame - to NETROM L3 if DL=0
+; to L2 Session if DL<>0
+;
+;
+; AH = 15 Get interval timer
+
+
+*/
+
+
+ switch(Fn)
+ {
+
+ case CHECKLOADED:
+
+ params[0]=MAJORVERSION;
+ params[1]=MINORVERSION;
+ params[2]=QCOUNT;
+
+ return (1);
+ }
+ return 0;
+}
+
+DllExport int APIENTRY InitSwitch()
+{
+ return (0);
+}
+
+/*DllExport int APIENTRY SwitchTimer()
+{
+ GetSemaphore((&Semaphore);
+
+ TIMERINTERRUPT();
+
+ FreeSemaphore(&Semaphore);
+
+ return (0);
+}
+*/
+DllExport int APIENTRY GetFreeBuffs()
+{
+// Returns number of free buffers
+// (BPQHOST function 7 (part)).
+ return (QCOUNT);
+}
+
+DllExport UCHAR * APIENTRY GetNodeCall()
+{
+ return (&MYNODECALL);
+}
+
+
+DllExport UCHAR * APIENTRY GetNodeAlias()
+{
+ return (&MYALIASTEXT[0]);
+}
+
+DllExport UCHAR * APIENTRY GetBBSCall()
+{
+ return (UCHAR *)(&APPLCALLTABLE[0].APPLCALL_TEXT);
+}
+
+
+DllExport UCHAR * APIENTRY GetBBSAlias()
+{
+ return (UCHAR *)(&APPLCALLTABLE[0].APPLALIAS_TEXT);
+}
+
+DllExport VOID APIENTRY GetApplCallVB(int Appl, char * ApplCall)
+{
+ if (Appl < 1 || Appl > NumberofAppls ) return;
+
+ strncpy(ApplCall,(char *)&APPLCALLTABLE[Appl-1].APPLCALL_TEXT, 10);
+}
+
+BOOL UpdateNodesForApp(int Appl);
+
+DllExport BOOL APIENTRY SetApplCall(int Appl, char * NewCall)
+{
+ char Call[10]=" ";
+ int i;
+
+ if (Appl < 1 || Appl > NumberofAppls ) return FALSE;
+
+ i=strlen(NewCall);
+
+ if (i > 10) i=10;
+
+ strncpy(Call,NewCall,i);
+
+ strncpy((char *)&APPLCALLTABLE[Appl-1].APPLCALL_TEXT,Call,10);
+
+ if (!ConvToAX25(Call,APPLCALLTABLE[Appl-1].APPLCALL)) return FALSE;
+
+ UpdateNodesForApp(Appl);
+
+ return TRUE;
+
+}
+
+DllExport BOOL APIENTRY SetApplAlias(int Appl, char * NewCall)
+{
+ char Call[10]=" ";
+ int i;
+
+ if (Appl < 1 || Appl > NumberofAppls ) return FALSE;
+
+ i=strlen(NewCall);
+
+ if (i > 10) i=10;
+
+ strncpy(Call,NewCall,i);
+
+ strncpy((char *)&APPLCALLTABLE[Appl-1].APPLALIAS_TEXT,Call,10);
+
+ if (!ConvToAX25(Call,APPLCALLTABLE[Appl-1].APPLALIAS)) return FALSE;
+
+ UpdateNodesForApp(Appl);
+
+ return TRUE;
+
+}
+
+
+
+DllExport BOOL APIENTRY SetApplQual(int Appl, int NewQual)
+{
+ if (Appl < 1 || Appl > NumberofAppls ) return FALSE;
+
+ APPLCALLTABLE[Appl-1].APPLQUAL=NewQual;
+
+ UpdateNodesForApp(Appl);
+
+ return TRUE;
+
+}
+
+
+BOOL UpdateNodesForApp(int Appl)
+{
+ int App=Appl-1;
+ int DestLen = sizeof (struct DEST_LIST);
+ int n = MAXDESTS;
+
+ struct DEST_LIST * DEST = APPLCALLTABLE[App].NODEPOINTER;
+ APPLCALLS * APPL=&APPLCALLTABLE[App];
+
+ if (DEST == NULL)
+ {
+ // No dest at the moment. If we have valid call and Qual, create an entry
+
+ if (APPLCALLTABLE[App].APPLQUAL == 0) return FALSE;
+
+ if (APPLCALLTABLE[App].APPLCALL[0] < 41) return FALSE;
+
+
+ GetSemaphore(&Semaphore, 5);
+
+ DEST = DESTS;
+
+ while (n--)
+ {
+ if (DEST->DEST_CALL[0] == 0) // Spare
+ break;
+ }
+
+ if (n == 0)
+ {
+ // no dests
+
+ FreeSemaphore(&Semaphore);
+ return FALSE;
+ }
+
+ NUMBEROFNODES++;
+ APPL->NODEPOINTER = DEST;
+
+ memmove (DEST->DEST_CALL,APPL->APPLCALL,13);
+
+ DEST->DEST_STATE=0x80; // SPECIAL ENTRY
+
+ DEST->NRROUTE[0].ROUT_QUALITY = (BYTE)APPL->APPLQUAL;
+ DEST->NRROUTE[0].ROUT_OBSCOUNT = 255;
+
+ FreeSemaphore(&Semaphore);
+
+ return TRUE;
+ }
+
+ // We have a destination. If Quality is zero, remove it, else update it
+
+ if (APPLCALLTABLE[App].APPLQUAL == 0)
+ {
+ GetSemaphore(&Semaphore, 6);
+
+ REMOVENODE(DEST); // Clear buffers, Remove from Sorted Nodes chain, and zap entry
+
+ APPL->NODEPOINTER=NULL;
+
+ FreeSemaphore(&Semaphore);
+ return FALSE;
+
+ }
+
+ if (APPLCALLTABLE[App].APPLCALL[0] < 41) return FALSE;
+
+ GetSemaphore(&Semaphore, 7);
+
+ memmove (DEST->DEST_CALL,APPL->APPLCALL,13);
+
+ DEST->DEST_STATE=0x80; // SPECIAL ENTRY
+
+ DEST->NRROUTE[0].ROUT_QUALITY = (BYTE)APPL->APPLQUAL;
+ DEST->NRROUTE[0].ROUT_OBSCOUNT = 255;
+
+ FreeSemaphore(&Semaphore);
+ return TRUE;
+
+}
+
+
+DllExport UCHAR * APIENTRY GetSignOnMsg()
+{
+ return (&SIGNONMSG[0]);
+}
+
+
+DllExport HKEY APIENTRY GetRegistryKey()
+{
+ return REGTREE;
+}
+
+DllExport char * APIENTRY GetRegistryKeyText()
+{
+ return REGTREETEXT;;
+}
+
+DllExport UCHAR * APIENTRY GetBPQDirectory()
+{
+ while (BPQDirectory[0] == 0)
+ {
+ Debugprintf("BPQ Directory not set up - waiting");
+ Sleep(1000);
+ }
+ return (&BPQDirectory[0]);
+}
+
+DllExport UCHAR * APIENTRY GetProgramDirectory()
+{
+ return (&BPQProgramDirectory[0]);
+}
+
+DllExport UCHAR * APIENTRY GetLogDirectory()
+{
+ return (&LogDirectory[0]);
+}
+
+// Version for Visual Basic
+
+DllExport char * APIENTRY CopyBPQDirectory(char * dir)
+{
+ return (strcpy(dir,BPQDirectory));
+}
+
+DllExport int APIENTRY GetMsgPerl(int stream, char * msg)
+{
+ int len,count;
+
+ GetMsg(stream, msg, &len, &count );
+
+ return len;
+}
+
+int Rig_Command(int Session, char * Command);
+
+BOOL Rig_CommandInt(int Session, char * Command)
+{
+ return Rig_Command(Session, Command);
+}
+
+DllExport int APIENTRY BPQSetHandle(int Stream, HWND hWnd)
+{
+ BPQHOSTVECTOR[Stream-1].HOSTHANDLE=hWnd;
+ return (0);
+}
+
+#define L4USER 0
+
+BPQVECSTRUC * PORTVEC ;
+
+VOID * InitializeExtDriver(PEXTPORTDATA PORTVEC)
+{
+ HINSTANCE ExtDriver=0;
+ char msg[128];
+ int err=0;
+ HKEY hKey=0;
+ UCHAR Value[MAX_PATH];
+
+ // If no directory, use current
+
+ if (BPQDirectory[0] == 0)
+ {
+ strcpy(Value,PORTVEC->PORT_DLL_NAME);
+ }
+ else
+ {
+ strcpy(Value,BPQDirectory);
+ strcat(Value,"\\");
+ strcat(Value,PORTVEC->PORT_DLL_NAME);
+ }
+
+ // Several Drivers are now built into bpq32.dll
+
+ _strupr(Value);
+
+ if (strstr(Value, "BPQVKISS"))
+ return VCOMExtInit;
+
+ if (strstr(Value, "BPQAXIP"))
+ return AXIPExtInit;
+
+ if (strstr(Value, "BPQETHER"))
+ return ETHERExtInit;
+
+ if (strstr(Value, "BPQTOAGW"))
+ return AGWExtInit;
+
+ if (strstr(Value, "AEAPACTOR"))
+ return AEAExtInit;
+
+ if (strstr(Value, "HALDRIVER"))
+ return HALExtInit;
+
+ if (strstr(Value, "KAMPACTOR"))
+ return KAMExtInit;
+
+ if (strstr(Value, "SCSPACTOR"))
+ return SCSExtInit;
+
+ if (strstr(Value, "WINMOR"))
+ return WinmorExtInit;
+
+ if (strstr(Value, "V4"))
+ return V4ExtInit;
+
+ if (strstr(Value, "TELNET"))
+ return TelnetExtInit;
+
+// if (strstr(Value, "SOUNDMODEM"))
+// return SoundModemExtInit;
+
+ if (strstr(Value, "SCSTRACKER"))
+ return TrackerExtInit;
+
+ if (strstr(Value, "TRKMULTI"))
+ return TrackerMExtInit;
+
+ if (strstr(Value, "UZ7HO"))
+ return UZ7HOExtInit;
+
+ if (strstr(Value, "MULTIPSK"))
+ return MPSKExtInit;
+
+ if (strstr(Value, "FLDIGI"))
+ return FLDigiExtInit;
+
+ if (strstr(Value, "UIARQ"))
+ return UIARQExtInit;
+
+// if (strstr(Value, "BAYCOM"))
+// return (UINT) BaycomExtInit;
+
+ if (strstr(Value, "VARA"))
+ return VARAExtInit;
+
+ if (strstr(Value, "ARDOP"))
+ return ARDOPExtInit;
+
+ if (strstr(Value, "SERIAL"))
+ return SerialExtInit;
+
+ if (strstr(Value, "KISSHF"))
+ return KISSHFExtInit;
+
+ if (strstr(Value, "WINRPR"))
+ return WinRPRExtInit;
+
+ if (strstr(Value, "HSMODEM"))
+ return HSMODEMExtInit;
+
+ if (strstr(Value, "FREEDATA"))
+ return FreeDataExtInit;
+
+ if (strstr(Value, "6PACK"))
+ return SIXPACKExtInit;
+
+ ExtDriver = LoadLibrary(Value);
+
+ if (ExtDriver == NULL)
+ {
+ err=GetLastError();
+
+ sprintf(msg,"Error loading Driver %s - Error code %d",
+ PORTVEC->PORT_DLL_NAME,err);
+
+ MessageBox(NULL,msg,"BPQ32",MB_ICONSTOP);
+
+ return(0);
+ }
+
+ PORTVEC->DLLhandle=ExtDriver;
+
+ return (GetProcAddress(ExtDriver,"_ExtInit@4"));
+
+}
+
+/*
+_DATABASE LABEL BYTE
+
+FILLER DB 14 DUP (0) ; PROTECTION AGENST BUFFER PROBLEMS!
+ DB MAJORVERSION,MINORVERSION
+_NEIGHBOURS DD 0
+ DW TYPE ROUTE
+_MAXNEIGHBOURS DW 20 ; MAX ADJACENT NODES
+
+_DESTS DD 0 ; NODE LIST
+ DW TYPE DEST_LIST
+MAXDESTS DW 100 ; MAX NODES IN SYSTEM
+*/
+
+
+DllExport int APIENTRY GetAttachedProcesses()
+{
+ return (AttachedProcesses);
+}
+
+DllExport int * APIENTRY GetAttachedProcessList()
+{
+ return (&AttachedPIDList[0]);
+}
+
+DllExport int * APIENTRY SaveNodesSupport()
+{
+ return (&DATABASESTART);
+}
+
+//
+// Internal BPQNODES support
+//
+
+#define UCHAR unsigned char
+
+/*
+ROUTE ADD G1HTL-1 2 200 0 0 0
+ROUTE ADD G4IRX-3 2 200 0 0 0
+NODE ADD MAPPLY:G1HTL-1 G1HTL-1 2 200 G4IRX-3 2 98
+NODE ADD NOT:GB7NOT G1HTL-1 2 199 G4IRX-3 2 98
+
+*/
+
+struct DEST_LIST * Dests;
+struct ROUTE * Routes;
+
+int MaxNodes;
+int MaxRoutes;
+int NodeLen;
+int RouteLen;
+
+int count;
+int cursor;
+
+int len,i;
+
+ULONG cnt;
+char Normcall[10];
+char Portcall[10];
+char Alias[7];
+
+char line[100];
+
+HANDLE handle;
+
+int APIENTRY Restart()
+{
+ int i, Count = AttachedProcesses;
+ HANDLE hProc;
+ DWORD PID;
+
+ for (i = 0; i < Count; i++)
+ {
+ PID = AttachedPIDList[i];
+
+ // Kill Timer Owner last
+
+ if (TimerInst != PID)
+ {
+ hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID);
+
+ if (hProc)
+ {
+ TerminateProcess(hProc, 0);
+ CloseHandle(hProc);
+ }
+ }
+ }
+
+ hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, TimerInst);
+
+ if (hProc)
+ {
+ TerminateProcess(hProc, 0);
+ CloseHandle(hProc);
+ }
+
+
+ return 0;
+}
+
+int APIENTRY Reboot()
+{
+ // Run shutdown -r -f
+
+ STARTUPINFO SInfo;
+ PROCESS_INFORMATION PInfo;
+ char Cmd[] = "shutdown -r -f";
+
+ SInfo.cb=sizeof(SInfo);
+ SInfo.lpReserved=NULL;
+ SInfo.lpDesktop=NULL;
+ SInfo.lpTitle=NULL;
+ SInfo.dwFlags=0;
+ SInfo.cbReserved2=0;
+ SInfo.lpReserved2=NULL;
+
+ return CreateProcess(NULL, Cmd, NULL, NULL, FALSE,0 ,NULL ,NULL, &SInfo, &PInfo);
+}
+/*
+int APIENTRY Reconfig()
+{
+ if (!ProcessConfig())
+ {
+ return (0);
+ }
+ SaveNodes();
+ WritetoConsole("Nodes Saved\n");
+ ReconfigFlag=TRUE;
+ WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n");
+ return 1;
+}
+*/
+// Code to support minimizing all BPQ Apps to a single Tray ICON
+
+// As we can't minimize the console window to the tray, I'll use an ordinary
+// window instead. This also gives me somewhere to post the messages to
+
+
+char AppName[] = "BPQ32";
+char Title[80] = "BPQ32.dll Console";
+
+int NewLine();
+
+char FrameClassName[] = TEXT("MdiFrame");
+
+HWND ClientWnd; //This stores the MDI client area window handle
+
+LOGFONT LFTTYFONT ;
+
+HFONT hFont ;
+
+HMENU hPopMenu, hWndMenu;
+HMENU hMainFrameMenu = NULL;
+HMENU hBaseMenu = NULL;
+HMENU hConsMenu = NULL;
+HMENU hTermMenu = NULL;
+HMENU hMonMenu = NULL;
+HMENU hTermActMenu, hTermCfgMenu, hTermEdtMenu, hTermHlpMenu;
+HMENU hMonActMenu, hMonCfgMenu, hMonEdtMenu, hMonHlpMenu;
+
+
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+DllExport int APIENTRY DeleteTrayMenuItem(HWND hWnd);
+
+#define BPQMonitorAvail 1
+#define BPQDataAvail 2
+#define BPQStateChange 4
+
+VOID GetJSONValue(char * _REPLYBUFFER, char * Name, char * Value);
+SOCKET OpenWL2KHTTPSock();
+SendHTTPRequest(SOCKET sock, char * Request, char * Params, int Len, char * Return);
+
+BOOL GetWL2KSYSOPInfo(char * Call, char * _REPLYBUFFER);
+BOOL UpdateWL2KSYSOPInfo(char * Call, char * SQL);
+
+
+static INT_PTR CALLBACK ConfigWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ char _REPLYBUFFER[1000] = "";
+ char Value[1000];
+
+ if (GetWL2KSYSOPInfo(WL2KCall, _REPLYBUFFER))
+ {
+// if (strstr(_REPLYBUFFER, "\"ErrorMessage\":") == 0)
+
+ GetJSONValue(_REPLYBUFFER, "\"SysopName\":", Value);
+ SetDlgItemText(hDlg, NAME, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"GridSquare\":", Value);
+ SetDlgItemText(hDlg, IDC_Locator, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"StreetAddress1\":", Value);
+ SetDlgItemText(hDlg, ADDR1, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"StreetAddress2\":", Value);
+ SetDlgItemText(hDlg, ADDR2, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"City\":", Value);
+ SetDlgItemText(hDlg, CITY, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"State\":", Value);
+ SetDlgItemText(hDlg, STATE, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"Country\":", Value);
+ SetDlgItemText(hDlg, COUNTRY, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"PostalCode\":", Value);
+ SetDlgItemText(hDlg, POSTCODE, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"Email\":", Value);
+ SetDlgItemText(hDlg, EMAIL, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"Website\":", Value);
+ SetDlgItemText(hDlg, WEBSITE, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"Phones\":", Value);
+ SetDlgItemText(hDlg, PHONE, Value);
+
+ GetJSONValue(_REPLYBUFFER, "\"Comments\":", Value);
+ SetDlgItemText(hDlg, ADDITIONALDATA, Value);
+
+ }
+
+ return (INT_PTR)TRUE;
+ }
+ case WM_COMMAND:
+
+ switch(LOWORD(wParam))
+ {
+
+ case ID_SAVE:
+ {
+ char Name[100];
+ char PasswordText[100];
+ char LocatorText[100];
+ char Addr1[100];
+ char Addr2[100];
+ char City[100];
+ char State[100];
+ char Country[100];
+ char PostCode[100];
+ char Email[100];
+ char Website[100];
+ char Phone[100];
+ char Data[100];
+
+ SOCKET sock;
+
+ int Len;
+ char Message[2048];
+ char Reply[2048] = "";
+
+
+ GetDlgItemText(hDlg, NAME, Name, 99);
+ GetDlgItemText(hDlg, IDC_Password, PasswordText, 99);
+ GetDlgItemText(hDlg, IDC_Locator, LocatorText, 99);
+ GetDlgItemText(hDlg, ADDR1, Addr1, 99);
+ GetDlgItemText(hDlg, ADDR2, Addr2, 99);
+ GetDlgItemText(hDlg, CITY, City, 99);
+ GetDlgItemText(hDlg, STATE, State, 99);
+ GetDlgItemText(hDlg, COUNTRY, Country, 99);
+ GetDlgItemText(hDlg, POSTCODE, PostCode, 99);
+ GetDlgItemText(hDlg, EMAIL, Email, 99);
+ GetDlgItemText(hDlg, WEBSITE, Website, 99);
+ GetDlgItemText(hDlg, PHONE, Phone, 99);
+ GetDlgItemText(hDlg, ADDITIONALDATA, Data, 99);
+
+
+//{"Callsign":"String","GridSquare":"String","SysopName":"String",
+//"StreetAddress1":"String","StreetAddress2":"String","City":"String",
+//"State":"String","Country":"String","PostalCode":"String","Email":"String",
+//"Phones":"String","Website":"String","Comments":"String"}
+
+ Len = sprintf(Message,
+ "\"Callsign\":\"%s\","
+ "\"Password\":\"%s\","
+ "\"GridSquare\":\"%s\","
+ "\"SysopName\":\"%s\","
+ "\"StreetAddress1\":\"%s\","
+ "\"StreetAddress2\":\"%s\","
+ "\"City\":\"%s\","
+ "\"State\":\"%s\","
+ "\"Country\":\"%s\","
+ "\"PostalCode\":\"%s\","
+ "\"Email\":\"%s\","
+ "\"Phones\":\"%s\","
+ "\"Website\":\"%s\","
+ "\"Comments\":\"%s\"",
+
+ WL2KCall, PasswordText, LocatorText, Name, Addr1, Addr2, City, State, Country, PostCode, Email, Phone, Website, Data);
+
+ Debugprintf("Sending %s", Message);
+
+ sock = OpenWL2KHTTPSock();
+
+ if (sock)
+ {
+ char * ptr;
+
+ SendHTTPRequest(sock,
+ "/sysop/add", Message, Len, Reply);
+
+ ptr = strstr(Reply, "\"ErrorCode\":");
+
+ if (ptr)
+ {
+ ptr = strstr(ptr, "Message");
+ if (ptr)
+ {
+ ptr += 10;
+ strlop(ptr, '"');
+ MessageBox(NULL ,ptr, "Error", MB_OK);
+ }
+ }
+ else
+ MessageBox(NULL, "Sysop Record Updated", "BPQ32", MB_OK);
+
+ }
+ closesocket(sock);
+ }
+
+ case ID_CANCEL:
+ {
+ EndDialog(hDlg, LOWORD(wParam));
+ return (INT_PTR)TRUE;
+ }
+ break;
+ }
+ }
+ return (INT_PTR)FALSE;
+}
+
+
+
+LRESULT CALLBACK UIWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+VOID WINAPI OnTabbedDialogInit(HWND hDlg);
+
+LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int wmId, wmEvent;
+ POINT pos;
+ BOOL ret;
+
+ CLIENTCREATESTRUCT MDIClientCreateStruct; // Structure to be used for MDI client area
+ //HWND m_hwndSystemInformation = 0;
+
+ if (message == BPQMsg)
+ {
+ if (lParam & BPQDataAvail)
+ DoReceivedData(wParam);
+
+ if (lParam & BPQMonitorAvail)
+ DoMonData(wParam);
+
+ if (lParam & BPQStateChange)
+ DoStateChange(wParam);
+
+ return (0);
+ }
+
+ switch (message)
+ {
+ case MY_TRAY_ICON_MESSAGE:
+
+ switch(lParam)
+ {
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+
+ GetCursorPos(&pos);
+
+ // SetForegroundWindow(FrameWnd);
+
+ TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, FrameWnd, 0);
+ return 0;
+ }
+
+ break;
+
+ case WM_CTLCOLORDLG:
+ return (LONG)bgBrush;
+
+ case WM_SIZING:
+ case WM_SIZE:
+
+ SendMessage(ClientWnd, WM_MDIICONARRANGE, 0 ,0);
+ break;
+
+ case WM_NCCREATE:
+
+ ret = DefFrameProc(hWnd, ClientWnd, message, wParam, lParam);
+ return TRUE;
+
+ case WM_CREATE:
+
+ // On creation of main frame, create the MDI client area
+
+ MDIClientCreateStruct.hWindowMenu = NULL;
+ MDIClientCreateStruct.idFirstChild = IDM_FIRSTCHILD;
+
+ ClientWnd = CreateWindow(TEXT("MDICLIENT"), // predefined value for MDI client area
+ NULL, // no caption required
+ WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE,
+ 0, // No need to give any x/y or height/width since this client
+ // will just be used to get client windows created, effectively
+ // in the main window we will be seeing the mainframe window client area itself.
+ 0,
+ 0,
+ 0,
+ hWnd,
+ NULL,
+ hInstance,
+ (void *) &MDIClientCreateStruct);
+
+
+ return 0;
+
+ case WM_COMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+ if (wmId >= TRAYBASEID && wmId < (TRAYBASEID + 100))
+ {
+ handle=hWndArray[wmId-TRAYBASEID];
+
+ if (handle == FrameWnd)
+ ShowWindow(handle, SW_NORMAL);
+
+ if (handle == FrameWnd && FrameMaximized == TRUE)
+ PostMessage(handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+ else
+ PostMessage(handle, WM_SYSCOMMAND, SC_RESTORE, 0);
+
+ SetForegroundWindow(handle);
+ return 0;
+ }
+
+ switch(wmId)
+ {
+ struct ConsoleInfo * Cinfo = NULL;
+
+ case ID_NEWWINDOW:
+ Cinfo = CreateChildWindow(0, FALSE);
+ if (Cinfo)
+ SendMessage(ClientWnd, WM_MDIACTIVATE, (WPARAM)Cinfo->hConsole, 0);
+ break;
+
+ case ID_WINDOWS_CASCADE:
+ SendMessage(ClientWnd, WM_MDICASCADE, 0, 0);
+ return 0;
+
+ case ID_WINDOWS_TILE:
+ SendMessage(ClientWnd, WM_MDITILE , MDITILE_HORIZONTAL, 0);
+ return 0;
+
+ case BPQCLOSEALL:
+ CloseAllPrograms();
+ // SendMessage(ClientWnd, WM_MDIICONARRANGE, 0 ,0);
+
+ return 0;
+
+ case BPQUICONFIG:
+ {
+ int err, i=0;
+ char Title[80];
+ WNDCLASS wc;
+
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = UIWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON) );
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = bgBrush;
+
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = UIClassName;
+
+ RegisterClass(&wc);
+
+ UIhWnd = CreateDialog(hInstance, UIClassName, 0, NULL);
+
+ if (!UIhWnd)
+ {
+ err=GetLastError();
+ return FALSE;
+ }
+
+ wsprintf(Title,"BPQ32 Beacon Configuration");
+ MySetWindowText(UIhWnd, Title);
+ ShowWindow(UIhWnd, SW_NORMAL);
+
+ OnTabbedDialogInit(UIhWnd); // Set up pages
+
+ // UpdateWindow(UIhWnd);
+ return 0;
+ }
+
+
+ case IDD_WL2KSYSOP:
+
+ if (WL2KCall[0] == 0)
+ {
+ MessageBox(NULL,"WL2K Reporting is not configured","BPQ32", MB_OK);
+ break;
+ }
+
+ DialogBox(hInstance, MAKEINTRESOURCE(IDD_WL2KSYSOP), hWnd, ConfigWndProc);
+ break;
+
+
+ // Handle MDI Window commands
+
+ default:
+ {
+ if(wmId >= IDM_FIRSTCHILD)
+ {
+ DefFrameProc(hWnd, ClientWnd, message, wParam, lParam);
+ }
+ else
+ {
+ HWND hChild = (HWND)SendMessage(ClientWnd, WM_MDIGETACTIVE,0,0);
+
+ if(hChild)
+ SendMessage(hChild, WM_COMMAND, wParam, lParam);
+ }
+ }
+ }
+
+ break;
+
+ case WM_INITMENUPOPUP:
+ {
+ HWND hChild = (HWND)SendMessage(ClientWnd, WM_MDIGETACTIVE,0,0);
+
+ if(hChild)
+ SendMessage(hChild, WM_INITMENUPOPUP, wParam, lParam);
+ }
+
+ case WM_SYSCOMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+ switch (wmId)
+ {
+ case SC_MAXIMIZE:
+
+ FrameMaximized = TRUE;
+ break;
+
+ case SC_RESTORE:
+
+ FrameMaximized = FALSE;
+ break;
+
+ case SC_MINIMIZE:
+
+ if (MinimizetoTray)
+ {
+ ShowWindow(hWnd, SW_HIDE);
+ return TRUE;
+ }
+ }
+
+ return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam));
+
+ case WM_CLOSE:
+
+ PostQuitMessage(0);
+
+ if (MinimizetoTray)
+ DeleteTrayMenuItem(hWnd);
+
+ break;
+
+ default:
+ return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam));
+
+ }
+ return (DefFrameProc(hWnd, ClientWnd, message, wParam, lParam));
+}
+
+int OffsetH, OffsetW;
+
+int SetupConsoleWindow()
+{
+ WNDCLASS wc;
+ int i;
+ int retCode, Type, Vallen;
+ HKEY hKey=0;
+ char Size[80];
+ WNDCLASSEX wndclassMainFrame;
+ RECT CRect;
+
+ retCode = RegOpenKeyEx (REGTREE,
+ "SOFTWARE\\G8BPQ\\BPQ32",
+ 0,
+ KEY_QUERY_VALUE,
+ &hKey);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ Vallen=80;
+
+ retCode = RegQueryValueEx(hKey,"FrameWindowSize",0,
+ (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
+
+ if (retCode == ERROR_SUCCESS)
+ sscanf(Size,"%d,%d,%d,%d",&FRect.left,&FRect.right,&FRect.top,&FRect.bottom);
+
+ if (FRect.top < - 500 || FRect.left < - 500)
+ {
+ FRect.left = 0;
+ FRect.top = 0;
+ FRect.right = 600;
+ FRect.bottom = 400;
+ }
+
+
+ Vallen=80;
+ retCode = RegQueryValueEx(hKey,"WindowSize",0,
+ (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
+
+ if (retCode == ERROR_SUCCESS)
+ sscanf(Size,"%d,%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom, &ConsoleMinimized);
+
+ if (Rect.top < - 500 || Rect.left < - 500)
+ {
+ Rect.left = 0;
+ Rect.top = 0;
+ Rect.right = 600;
+ Rect.bottom = 400;
+ }
+
+ Vallen=80;
+
+ retCode = RegQueryValueEx(hKey,"StatusWindowSize",0,
+ (ULONG *)&Type,(UCHAR *)&Size,(ULONG *)&Vallen);
+
+ if (retCode == ERROR_SUCCESS)
+ sscanf(Size, "%d,%d,%d,%d,%d", &StatusRect.left, &StatusRect.right,
+ &StatusRect.top, &StatusRect.bottom, &StatusMinimized);
+
+ if (StatusRect.top < - 500 || StatusRect.left < - 500)
+ {
+ StatusRect.left = 0;
+ StatusRect.top = 0;
+ StatusRect.right = 850;
+ StatusRect.bottom = 500;
+ }
+
+
+ // Get StartMinimized and MinimizetoTray flags
+
+ Vallen = 4;
+ retCode = RegQueryValueEx(hKey, "Start Minimized", 0, &Type, (UCHAR *)&StartMinimized, &Vallen);
+
+ Vallen = 4;
+ retCode = RegQueryValueEx(hKey, "Minimize to Tray", 0, &Type, (UCHAR *)&MinimizetoTray, &Vallen);
+ }
+
+ wndclassMainFrame.cbSize = sizeof(WNDCLASSEX);
+ wndclassMainFrame.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
+ wndclassMainFrame.lpfnWndProc = FrameWndProc;
+ wndclassMainFrame.cbClsExtra = 0;
+ wndclassMainFrame.cbWndExtra = 0;
+ wndclassMainFrame.hInstance = hInstance;
+ wndclassMainFrame.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON));
+ wndclassMainFrame.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclassMainFrame.hbrBackground = (HBRUSH) GetStockObject(GRAY_BRUSH);
+ wndclassMainFrame.lpszMenuName = NULL;
+ wndclassMainFrame.lpszClassName = FrameClassName;
+ wndclassMainFrame.hIconSm = NULL;
+
+ if(!RegisterClassEx(&wndclassMainFrame))
+ {
+ return 0;
+ }
+
+ pindex = 0;
+ PartLine = FALSE;
+
+ bgBrush = CreateSolidBrush(BGCOLOUR);
+
+// hMainFrameMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MAINFRAME_MENU));
+
+ hBaseMenu = LoadMenu(hInstance, MAKEINTRESOURCE(CONS_MENU));
+ hConsMenu = GetSubMenu(hBaseMenu, 1);
+ hWndMenu = GetSubMenu(hBaseMenu, 0);
+
+ hTermMenu = LoadMenu(hInstance, MAKEINTRESOURCE(TERM_MENU));
+ hTermActMenu = GetSubMenu(hTermMenu, 1);
+ hTermCfgMenu = GetSubMenu(hTermMenu, 2);
+ hTermEdtMenu = GetSubMenu(hTermMenu, 3);
+ hTermHlpMenu = GetSubMenu(hTermMenu, 4);
+
+ hMonMenu = LoadMenu(hInstance, MAKEINTRESOURCE(MON_MENU));
+ hMonCfgMenu = GetSubMenu(hMonMenu, 1);
+ hMonEdtMenu = GetSubMenu(hMonMenu, 2);
+ hMonHlpMenu = GetSubMenu(hMonMenu, 3);
+
+ hMainFrameMenu = CreateMenu();
+ AppendMenu(hMainFrameMenu, MF_STRING + MF_POPUP, (UINT)hWndMenu, "Window");
+
+ //Create the main MDI frame window
+
+ ClientWnd = NULL;
+
+ FrameWnd = CreateWindow(FrameClassName,
+ "BPQ32 Console",
+ WS_OVERLAPPEDWINDOW |WS_CLIPCHILDREN,
+ FRect.left,
+ FRect.top,
+ FRect.right - FRect.left,
+ FRect.bottom - FRect.top,
+ NULL, // handle to parent window
+ hMainFrameMenu, // handle to menu
+ hInstance, // handle to the instance of module
+ NULL); // Long pointer to a value to be passed to the window through the
+ // CREATESTRUCT structure passed in the lParam parameter the WM_CREATE message
+
+
+ // Get Client Params
+
+ if (FrameWnd == 0)
+ {
+ Debugprintf("SetupConsoleWindow Create Frame failed %d", GetLastError());
+ return 0;
+ }
+
+ ShowWindow(FrameWnd, SW_RESTORE);
+
+
+ GetWindowRect(FrameWnd, &FRect);
+ OffsetH = FRect.bottom - FRect.top;
+ OffsetW = FRect.right - FRect.left;
+ GetClientRect(FrameWnd, &CRect);
+ OffsetH -= CRect.bottom;
+ OffsetW -= CRect.right;
+ OffsetH -= 4;
+
+ // Create Console Window
+
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
+ wc.lpfnWndProc = (WNDPROC)WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wc.lpszMenuName = 0;
+ wc.lpszClassName = ClassName;
+
+ i=RegisterClass(&wc);
+
+ sprintf (Title, "BPQ32.dll Console Version %s", VersionString);
+
+ hConsWnd = CreateMDIWindow(ClassName, "Console", 0,
+ 0,0,0,0, ClientWnd, hInstance, 1234);
+
+ i = GetLastError();
+
+ if (!hConsWnd) {
+ return (FALSE);
+ }
+
+ wc.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
+ wc.lpfnWndProc = (WNDPROC)StatusWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE(BPQICON));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
+ wc.lpszMenuName = 0;
+ wc.lpszClassName = "Status";
+
+ i=RegisterClass(&wc);
+
+ if (StatusRect.top < OffsetH) // Make sure not off top of MDI frame
+ {
+ int Error = OffsetH - StatusRect.top;
+ StatusRect.top += Error;
+ StatusRect.bottom += Error;
+ }
+
+ StatusWnd = CreateMDIWindow("Status", "Stream Status", 0,
+ StatusRect.left, StatusRect.top, StatusRect.right - StatusRect.left,
+ StatusRect.bottom - StatusRect.top, ClientWnd, hInstance, 1234);
+
+ SetTimer(StatusWnd, 1, 1000, NULL);
+
+ hPopMenu = GetSubMenu(hBaseMenu, 1) ;
+
+ if (MinimizetoTray)
+ CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_CHECKED);
+ else
+ CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_UNCHECKED);
+
+ if (StartMinimized)
+ CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_CHECKED);
+ else
+ CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_UNCHECKED);
+
+ DrawMenuBar(hConsWnd);
+
+ // setup default font information
+
+ LFTTYFONT.lfHeight = 12;
+ LFTTYFONT.lfWidth = 8 ;
+ LFTTYFONT.lfEscapement = 0 ;
+ LFTTYFONT.lfOrientation = 0 ;
+ LFTTYFONT.lfWeight = 0 ;
+ LFTTYFONT.lfItalic = 0 ;
+ LFTTYFONT.lfUnderline = 0 ;
+ LFTTYFONT.lfStrikeOut = 0 ;
+ LFTTYFONT.lfCharSet = 0;
+ LFTTYFONT.lfOutPrecision = OUT_DEFAULT_PRECIS ;
+ LFTTYFONT.lfClipPrecision = CLIP_DEFAULT_PRECIS ;
+ LFTTYFONT.lfQuality = DEFAULT_QUALITY ;
+ LFTTYFONT.lfPitchAndFamily = FIXED_PITCH;
+ lstrcpy(LFTTYFONT.lfFaceName, "FIXEDSYS" ) ;
+
+ hFont = CreateFontIndirect(&LFTTYFONT) ;
+
+ SetWindowText(hConsWnd,Title);
+
+ if (Rect.right < 100 || Rect.bottom < 100)
+ {
+ GetWindowRect(hConsWnd, &Rect);
+ }
+
+ if (Rect.top < OffsetH) // Make sure not off top of MDI frame
+ {
+ int Error = OffsetH - Rect.top;
+ Rect.top += Error;
+ Rect.bottom += Error;
+ }
+
+
+ MoveWindow(hConsWnd, Rect.left - (OffsetW /2), Rect.top - OffsetH, Rect.right-Rect.left, Rect.bottom-Rect.top, TRUE);
+
+ MoveWindow(StatusWnd, StatusRect.left - (OffsetW /2), StatusRect.top - OffsetH,
+ StatusRect.right-StatusRect.left, StatusRect.bottom-StatusRect.top, TRUE);
+
+ hWndCons = CreateWindowEx(WS_EX_CLIENTEDGE, "LISTBOX", "",
+ WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
+ LBS_DISABLENOSCROLL | LBS_NOSEL | WS_VSCROLL | WS_HSCROLL,
+ Rect.left, Rect.top, Rect.right - Rect.left, Rect.bottom - Rect.top,
+ hConsWnd, NULL, hInstance, NULL);
+
+// SendMessage(hWndCons, WM_SETFONT, hFont, 0);
+
+ SendMessage(hWndCons, LB_SETHORIZONTALEXTENT , 1000, 0);
+
+ if (ConsoleMinimized)
+ ShowWindow(hConsWnd, SW_SHOWMINIMIZED);
+ else
+ ShowWindow(hConsWnd, SW_RESTORE);
+
+ if (StatusMinimized)
+ ShowWindow(StatusWnd, SW_SHOWMINIMIZED);
+ else
+ ShowWindow(StatusWnd, SW_RESTORE);
+
+ ShowWindow(FrameWnd, SW_RESTORE);
+
+
+ LoadLibrary("riched20.dll");
+
+ if (StartMinimized)
+ if (MinimizetoTray)
+ ShowWindow(FrameWnd, SW_HIDE);
+ else
+ ShowWindow(FrameWnd, SW_SHOWMINIMIZED);
+ else
+ ShowWindow(FrameWnd, SW_RESTORE);
+
+ CreateMonitorWindow(Size);
+
+ return 0;
+}
+
+DllExport int APIENTRY SetupTrayIcon()
+{
+ if (MinimizetoTray == 0)
+ return 0;
+
+ trayMenu = CreatePopupMenu();
+
+ for( i = 0; i < 100; ++i )
+ {
+ if (strcmp(PopupText[i],"BPQ32 Console") == 0)
+ {
+ hWndArray[i] = FrameWnd;
+ goto doneit;
+ }
+ }
+
+ for( i = 0; i < 100; ++i )
+ {
+ if (hWndArray[i] == 0)
+ {
+ hWndArray[i] = FrameWnd;
+ strcpy(PopupText[i],"BPQ32 Console");
+ break;
+ }
+ }
+doneit:
+
+ for( i = 0; i < 100; ++i )
+ {
+ if (hWndArray[i] != 0)
+ AppendMenu(trayMenu,MF_STRING,TRAYBASEID+i,PopupText[i]);
+ }
+
+ // Set up Tray ICON
+
+ ZeroMemory(&niData,sizeof(NOTIFYICONDATA));
+
+ niData.cbSize = sizeof(NOTIFYICONDATA);
+
+ // the ID number can be any UINT you choose and will
+ // be used to identify your icon in later calls to
+ // Shell_NotifyIcon
+
+ niData.uID = TRAY_ICON_ID;
+
+ // state which structure members are valid
+ // here you can also choose the style of tooltip
+ // window if any - specifying a balloon window:
+ // NIF_INFO is a little more complicated
+
+ strcpy(niData.szTip,"BPQ32 Windows");
+
+ niData.uFlags = NIF_ICON|NIF_MESSAGE|NIF_TIP;
+
+ // load the icon note: you should destroy the icon
+ // after the call to Shell_NotifyIcon
+
+ niData.hIcon =
+
+ //LoadIcon(NULL, IDI_APPLICATION);
+
+ (HICON)LoadImage( hInstance,
+ MAKEINTRESOURCE(BPQICON),
+ IMAGE_ICON,
+ GetSystemMetrics(SM_CXSMICON),
+ GetSystemMetrics(SM_CYSMICON),
+ LR_DEFAULTCOLOR);
+
+
+ // set the window you want to receive event messages
+
+ niData.hWnd = FrameWnd;
+
+ // set the message to send
+ // note: the message value should be in the
+ // range of WM_APP through 0xBFFF
+
+ niData.uCallbackMessage = MY_TRAY_ICON_MESSAGE;
+
+ // Call Shell_NotifyIcon. NIM_ADD adds a new tray icon
+
+ if (Shell_NotifyIcon(NIM_ADD,&niData))
+ Debugprintf("BPQ32 Create Tray Icon Ok");
+// else
+// Debugprintf("BPQ32 Create Tray Icon failed %d", GetLastError());
+
+ return 0;
+}
+
+VOID SaveConfig()
+{
+ HKEY hKey=0;
+ int retCode, disp;
+
+ retCode = RegCreateKeyEx(REGTREE,
+ "SOFTWARE\\G8BPQ\\BPQ32",
+ 0, // Reserved
+ 0, // Class
+ 0, // Options
+ KEY_ALL_ACCESS,
+ NULL, // Security Attrs
+ &hKey,
+ &disp);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ retCode = RegSetValueEx(hKey, "Start Minimized", 0, REG_DWORD, (UCHAR *)&StartMinimized, 4);
+ retCode = RegSetValueEx(hKey, "Minimize to Tray", 0, REG_DWORD, (UCHAR *)&MinimizetoTray, 4);
+ }
+}
+
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int wmId, wmEvent;
+ POINT pos;
+ HWND handle;
+ RECT cRect;
+
+ switch (message)
+ {
+ case WM_MDIACTIVATE:
+
+ // Set the system info menu when getting activated
+
+ if (lParam == (LPARAM) hWnd)
+ {
+ // Activate
+
+ // GetSubMenu function should retrieve a handle to the drop-down menu or submenu.
+
+ RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
+ AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)hConsMenu, "Actions");
+ SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hBaseMenu, (LPARAM) hWndMenu);
+ }
+ else
+ {
+ // Deactivate
+
+ SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
+ }
+
+ DrawMenuBar(FrameWnd);
+
+ return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ case MY_TRAY_ICON_MESSAGE:
+
+ switch(lParam)
+ {
+ case WM_RBUTTONUP:
+ case WM_LBUTTONUP:
+
+ GetCursorPos(&pos);
+
+ SetForegroundWindow(hWnd);
+
+ TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, hWnd, 0);
+ return 0;
+ }
+
+ break;
+
+ case WM_CTLCOLORDLG:
+ return (LONG)bgBrush;
+
+ case WM_COMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+ if (wmId == IDC_ENIGATE)
+ {
+ int retCode, disp;
+ HKEY hKey=0;
+
+ IGateEnabled = IsDlgButtonChecked(hWnd, IDC_ENIGATE);
+
+ if (IGateEnabled)
+ ISDelayTimer = 60;
+
+ retCode = RegCreateKeyEx(REGTREE,
+ "SOFTWARE\\G8BPQ\\BPQ32",
+ 0, // Reserved
+ 0, // Class
+ 0, // Options
+ KEY_ALL_ACCESS,
+ NULL, // Security Attrs
+ &hKey,
+ &disp);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ retCode = RegSetValueEx(hKey,"IGateEnabled", 0 , REG_DWORD,(BYTE *)&IGateEnabled, 4);
+ RegCloseKey(hKey);
+ }
+
+ return 0;
+ }
+
+ if (wmId == BPQSAVENODES)
+ {
+ SaveNodes();
+ WritetoConsole("Nodes Saved\n");
+ return 0;
+ }
+ if (wmId == BPQCLEARRECONFIG)
+ {
+ if (!ProcessConfig())
+ {
+ MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
+ return (0);
+ }
+
+ ClearNodes();
+ WritetoConsole("Nodes file Cleared\n");
+ ReconfigFlag=TRUE;
+ WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n");
+ return 0;
+ }
+ if (wmId == BPQRECONFIG)
+ {
+ if (!ProcessConfig())
+ {
+ MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
+ return (0);
+ }
+ SaveNodes();
+ WritetoConsole("Nodes Saved\n");
+ ReconfigFlag=TRUE;
+ WritetoConsole("Reconfig requested ... Waiting for Timer Poll\n");
+ return 0;
+ }
+
+ if (wmId == SCANRECONFIG)
+ {
+ if (!ProcessConfig())
+ {
+ MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
+ return (0);
+ }
+
+ RigReconfigFlag = TRUE;
+ WritetoConsole("Rigcontrol Reconfig requested ... Waiting for Timer Poll\n");
+ return 0;
+ }
+
+ if (wmId == APRSRECONFIG)
+ {
+ if (!ProcessConfig())
+ {
+ MessageBox(NULL,"Configuration File check falled - will continue with old config","BPQ32",MB_OK);
+ return (0);
+ }
+
+ APRSReconfigFlag=TRUE;
+ WritetoConsole("APRS Reconfig requested ... Waiting for Timer Poll\n");
+ return 0;
+ }
+ if (wmId == BPQDUMP)
+ {
+ DumpSystem();
+ return 0;
+ }
+
+ if (wmId == BPQCLOSEALL)
+ {
+ CloseAllPrograms();
+ return 0;
+ }
+
+ if (wmId == BPQUICONFIG)
+ {
+ int err, i=0;
+ char Title[80];
+ WNDCLASS wc;
+
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = UIWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON) );
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = bgBrush;
+
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = UIClassName;
+
+ RegisterClass(&wc);
+
+ UIhWnd = CreateDialog(hInstance, UIClassName,0,NULL);
+
+ if (!UIhWnd)
+ {
+ err=GetLastError();
+ return FALSE;
+ }
+
+ wsprintf(Title,"BPQ32 Beacon Utility Version");
+ MySetWindowText(UIhWnd, Title);
+ return 0;
+ }
+
+ if (wmId == BPQSAVEREG)
+ {
+ CreateRegBackup();
+ return 0;
+ }
+
+ if (wmId == BPQMINTOTRAY)
+ {
+ MinimizetoTray = !MinimizetoTray;
+
+ if (MinimizetoTray)
+ CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_CHECKED);
+ else
+ CheckMenuItem(hPopMenu, BPQMINTOTRAY, MF_UNCHECKED);
+
+ SaveConfig();
+ return 0;
+ }
+
+ if (wmId == BPQSTARTMIN)
+ {
+ StartMinimized = !StartMinimized;
+
+ if (StartMinimized)
+ CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_CHECKED);
+ else
+ CheckMenuItem(hPopMenu, BPQSTARTMIN, MF_UNCHECKED);
+
+ SaveConfig();
+ return 0;
+ }
+
+ if (wmId >= TRAYBASEID && wmId < (TRAYBASEID + 100))
+ {
+ handle=hWndArray[wmId-TRAYBASEID];
+
+ if (handle == FrameWnd && FrameMaximized == TRUE)
+ PostMessage(handle, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
+ else
+ PostMessage(handle, WM_SYSCOMMAND, SC_RESTORE, 0);
+
+ SetForegroundWindow(handle);
+ return 0;
+ }
+
+ case WM_SYSCOMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+ switch (wmId)
+ {
+ case SC_MINIMIZE:
+
+ ConsoleMinimized = TRUE;
+ break;
+
+ case SC_RESTORE:
+
+ ConsoleMinimized = FALSE;
+ SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
+
+ break;
+ }
+
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+
+ case WM_SIZE:
+
+ GetClientRect(hWnd, &cRect);
+
+ MoveWindow(hWndBG, 0, 0, cRect.right, 26, TRUE);
+
+ if (APRSActive)
+ MoveWindow(hWndCons, 2, 26, cRect.right-4, cRect.bottom - 32, TRUE);
+ else
+ MoveWindow(hWndCons, 2, 2, cRect.right-4, cRect.bottom - 4, TRUE);
+
+// InvalidateRect(hWnd, NULL, TRUE);
+ break;
+
+/*
+ case WM_PAINT:
+
+ hdc = BeginPaint (hWnd, &ps);
+
+ hOldFont = SelectObject( hdc, hFont) ;
+
+ for (i=0; i 300)
+ len = 300;
+
+ memcpy(&buffptr[2], buff, len + 1);
+
+ C_Q_ADD(&WritetoConsoleQ, buffptr);
+
+ return 0;
+}
+
+int WritetoConsoleSupport(char * buff)
+{
+
+ int len=strlen(buff);
+ char Temp[2000]= "";
+ char * ptr;
+
+ if (PartLine)
+ {
+ SendMessage(hWndCons, LB_GETTEXT, pindex, (LPARAM)(LPCTSTR) Temp);
+ SendMessage(hWndCons, LB_DELETESTRING, pindex, 0);
+ PartLine = FALSE;
+ }
+
+ if ((strlen(Temp) + strlen(buff)) > 1990)
+ Temp[0] = 0; // Should never have anything this long
+
+ strcat(Temp, buff);
+
+ ptr = strchr(Temp, '\n');
+
+ if (ptr)
+ *ptr = 0;
+ else
+ PartLine = TRUE;
+
+ pindex=SendMessage(hWndCons, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR) Temp);
+ return 0;
+ }
+
+DllExport VOID APIENTRY BPQOutputDebugString(char * String)
+{
+ OutputDebugString(String);
+ return;
+ }
+
+HANDLE handle;
+char fn[]="BPQDUMP";
+ULONG cnt;
+char * stack;
+//char screen[1920];
+//COORD ReadCoord;
+
+#define DATABYTES 400000
+
+extern UCHAR DATAAREA[];
+
+DllExport int APIENTRY DumpSystem()
+{
+ char fn[200];
+ char Msg[250];
+
+ sprintf(fn,"%s\\BPQDUMP",BPQDirectory);
+
+ handle = CreateFile(fn,
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+#ifndef _WIN64
+
+ _asm {
+
+ mov stack,esp
+ }
+
+ WriteFile(handle,stack,128,&cnt,NULL);
+#endif
+
+// WriteFile(handle,Screen,MAXLINELEN*MAXSCREENLEN,&cnt,NULL);
+
+ WriteFile(handle,DATAAREA, DATABYTES,&cnt,NULL);
+
+ CloseHandle(handle);
+
+ sprintf(Msg, "Dump to %s Completed\n", fn);
+ WritetoConsole(Msg);
+
+ FindLostBuffers();
+
+ return (0);
+}
+
+BOOLEAN CheckifBPQ32isLoaded()
+{
+ HANDLE Mutex;
+
+ // See if BPQ32 is running - if we create it in the NTVDM address space by
+ // loading bpq32.dll it will not work.
+
+ Mutex=OpenMutex(MUTEX_ALL_ACCESS,FALSE,"BPQLOCKMUTEX");
+
+ if (Mutex == NULL)
+ {
+ if (AttachingProcess == 0) // Already starting BPQ32
+ {
+ OutputDebugString("BPQ32 No other bpq32 programs running - Loading BPQ32.exe\n");
+ StartBPQ32();
+ }
+ return FALSE;
+ }
+
+ CloseHandle(Mutex);
+
+ return TRUE;
+}
+
+BOOLEAN StartBPQ32()
+{
+ UCHAR Value[100];
+
+ char bpq[]="BPQ32.exe";
+ char *fn=(char *)&bpq;
+ HKEY hKey=0;
+ int ret,Type,Vallen=99;
+
+ char Errbuff[100];
+ char buff[20];
+
+ STARTUPINFO StartupInfo; // pointer to STARTUPINFO
+ PROCESS_INFORMATION ProcessInformation; // pointer to PROCESS_INFORMATION
+
+ AttachingProcess = 1;
+
+// Get address of BPQ Directory
+
+ Value[0]=0;
+
+ ret = RegOpenKeyEx (REGTREE,
+ "SOFTWARE\\G8BPQ\\BPQ32",
+ 0,
+ KEY_QUERY_VALUE,
+ &hKey);
+
+ if (ret == ERROR_SUCCESS)
+ {
+ ret = RegQueryValueEx(hKey, "BPQ Program Directory", 0, &Type,(UCHAR *)&Value, &Vallen);
+
+ if (ret == ERROR_SUCCESS)
+ {
+ if (strlen(Value) == 2 && Value[0] == '"' && Value[1] == '"')
+ Value[0]=0;
+ }
+
+
+ if (Value[0] == 0)
+ {
+
+ // BPQ Directory absent or = "" - "try Config File Location"
+
+ ret = RegQueryValueEx(hKey,"BPQ Directory",0,
+ &Type,(UCHAR *)&Value,&Vallen);
+
+ if (ret == ERROR_SUCCESS)
+ {
+ if (strlen(Value) == 2 && Value[0] == '"' && Value[1] == '"')
+ Value[0]=0;
+ }
+
+ }
+ RegCloseKey(hKey);
+ }
+
+ if (Value[0] == 0)
+ {
+ strcpy(Value,fn);
+ }
+ else
+ {
+ strcat(Value,"\\");
+ strcat(Value,fn);
+ }
+
+ StartupInfo.cb=sizeof(StartupInfo);
+ StartupInfo.lpReserved=NULL;
+ StartupInfo.lpDesktop=NULL;
+ StartupInfo.lpTitle=NULL;
+ StartupInfo.dwFlags=0;
+ StartupInfo.cbReserved2=0;
+ StartupInfo.lpReserved2=NULL;
+
+ if (!CreateProcess(Value,NULL,NULL,NULL,FALSE,
+ CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
+ NULL,NULL,&StartupInfo,&ProcessInformation))
+ {
+ ret=GetLastError();
+
+ _itoa(ret,buff,10);
+
+ strcpy(Errbuff, "BPQ32 Load ");
+ strcat(Errbuff,Value);
+ strcat(Errbuff," failed ");
+ strcat(Errbuff,buff);
+ OutputDebugString(Errbuff);
+ AttachingProcess = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+DllExport BPQVECSTRUC * APIENTRY GetIPVectorAddr()
+{
+ return &IPHOSTVECTOR;
+}
+
+DllExport UINT APIENTRY GETSENDNETFRAMEADDR()
+{
+ return (UINT)&SENDNETFRAME;
+}
+
+DllExport VOID APIENTRY RelBuff(VOID * Msg)
+{
+ UINT * pointer, * BUFF = Msg;
+
+ if (Semaphore.Flag == 0)
+ Debugprintf("ReleaseBuffer called without semaphore");
+
+ pointer = FREE_Q;
+
+ *BUFF =(UINT)pointer;
+
+ FREE_Q = BUFF;
+
+ QCOUNT++;
+
+ return;
+}
+
+extern int MINBUFFCOUNT;
+
+DllExport VOID * APIENTRY GetBuff()
+{
+ UINT * Temp = Q_REM(&FREE_Q);
+
+ if (Semaphore.Flag == 0)
+ Debugprintf("GetBuff called without semaphore");
+
+ if (Temp)
+ {
+ QCOUNT--;
+
+ if (QCOUNT < MINBUFFCOUNT)
+ MINBUFFCOUNT = QCOUNT;
+ }
+
+ return Temp;
+}
+
+
+VOID __cdecl Debugprintf(const char * format, ...)
+{
+ char Mess[10000];
+ va_list(arglist);
+
+ va_start(arglist, format);
+ vsprintf(Mess, format, arglist);
+ strcat(Mess, "\r\n");
+ OutputDebugString(Mess);
+
+ return;
+}
+
+unsigned short int compute_crc(unsigned char *buf, int txlen);
+
+extern SOCKADDR_IN reportdest;
+
+extern SOCKET ReportSocket;
+
+extern SOCKADDR_IN Chatreportdest;
+
+DllExport VOID APIENTRY SendChatReport(SOCKET ChatReportSocket, char * buff, int txlen)
+{
+ unsigned short int crc = compute_crc(buff, txlen);
+
+ crc ^= 0xffff;
+
+ buff[txlen++] = (crc&0xff);
+ buff[txlen++] = (crc>>8);
+
+ sendto(ChatReportSocket, buff, txlen, 0, (LPSOCKADDR)&Chatreportdest, sizeof(Chatreportdest));
+}
+
+VOID CreateRegBackup()
+{
+ char Backup1[MAX_PATH];
+ char Backup2[MAX_PATH];
+ char RegFileName[MAX_PATH];
+ char Msg[80];
+ HANDLE handle;
+ int len, written;
+ char RegLine[300];
+
+// SHELLEXECUTEINFO sei;
+// STARTUPINFO SInfo;
+// PROCESS_INFORMATION PInfo;
+
+ sprintf(RegFileName, "%s\\BPQ32.reg", BPQDirectory);
+
+ // Keep 4 Generations
+
+ strcpy(Backup2, RegFileName);
+ strcat(Backup2, ".bak.3");
+
+ strcpy(Backup1, RegFileName);
+ strcat(Backup1, ".bak.2");
+
+ DeleteFile(Backup2); // Remove old .bak.3
+ MoveFile(Backup1, Backup2); // Move .bak.2 to .bak.3
+
+ strcpy(Backup2, RegFileName);
+ strcat(Backup2, ".bak.1");
+
+ MoveFile(Backup2, Backup1); // Move .bak.1 to .bak.2
+
+ strcpy(Backup1, RegFileName);
+ strcat(Backup1, ".bak");
+
+ MoveFile(Backup1, Backup2); //Move .bak to .bak.1
+
+ strcpy(Backup2, RegFileName);
+ strcat(Backup2, ".bak");
+
+ CopyFile(RegFileName, Backup2, FALSE); // Copy to .bak
+
+ handle = CreateFile(RegFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ sprintf(Msg, "Failed to open Registry Save File\n");
+ WritetoConsole(Msg);
+ return;
+ }
+
+ len = sprintf(RegLine, "Windows Registry Editor Version 5.00\r\n\r\n");
+ WriteFile(handle, RegLine, len, &written, NULL);
+
+ if (SaveReg("Software\\G8BPQ\\BPQ32", handle))
+ WritetoConsole("Registry Save complete\n");
+ else
+ WritetoConsole("Registry Save failed\n");
+
+ CloseHandle(handle);
+ return ;
+/*
+
+ if (REGTREE == HKEY_LOCAL_MACHINE) // < Vista
+ {
+ sprintf(cmd,
+ "regedit /E \"%s\\BPQ32.reg\" %s\\Software\\G8BPQ\\BPQ32", BPQDirectory, REGTREETEXT);
+
+ ZeroMemory(&SInfo, sizeof(SInfo));
+
+ SInfo.cb=sizeof(SInfo);
+ SInfo.lpReserved=NULL;
+ SInfo.lpDesktop=NULL;
+ SInfo.lpTitle=NULL;
+ SInfo.dwFlags=0;
+ SInfo.cbReserved2=0;
+ SInfo.lpReserved2=NULL;
+
+ if (CreateProcess(NULL, cmd, NULL, NULL, FALSE, 0 ,NULL, NULL, &SInfo, &PInfo) == 0)
+ {
+ sprintf(Msg, "Error: CreateProcess for regedit failed 0%d\n", GetLastError() );
+ WritetoConsole(Msg);
+ return;
+ }
+ }
+ else
+ {
+
+ sprintf(cmd,
+ "/E \"%s\\BPQ32.reg\" %s\\Software\\G8BPQ\\BPQ32", BPQDirectory, REGTREETEXT);
+
+ ZeroMemory(&sei, sizeof(sei));
+
+ sei.cbSize = sizeof(SHELLEXECUTEINFOW);
+ sei.hwnd = hWnd;
+ sei.fMask = SEE_MASK_FLAG_DDEWAIT | SEE_MASK_FLAG_NO_UI;
+ sei.lpVerb = "runas";
+ sei.lpFile = "regedit.exe";
+ sei.lpParameters = cmd;
+ sei.nShow = SW_SHOWNORMAL;
+
+ if (!ShellExecuteEx(&sei))
+ {
+ sprintf(Msg, "Error: ShellExecuteEx for regedit failed %d\n", GetLastError() );
+ WritetoConsole(Msg);
+ return;
+ }
+ }
+
+ sprintf(Msg, "Registry Save Initiated\n", fn);
+ WritetoConsole(Msg);
+
+ return ;
+*/
+}
+
+BOOL CALLBACK EnumForCloseProc(HWND hwnd, LPARAM lParam)
+{
+ struct TNCINFO * TNC = (struct TNCINFO *)lParam;
+ UINT ProcessId;
+
+ GetWindowThreadProcessId(hwnd, &ProcessId);
+
+ for (i=0; i< AttachedProcesses; i++)
+ {
+ if (AttachedPIDList[i] == ProcessId)
+ {
+ Debugprintf("BPQ32 Close All Closing PID %d", ProcessId);
+ PostMessage(hwnd, WM_CLOSE, 1, 1);
+ // AttachedPIDList[i] = 0; // So we don't do it again
+ break;
+ }
+ }
+
+ return (TRUE);
+}
+DllExport BOOL APIENTRY RestoreFrameWindow()
+{
+ return ShowWindow(FrameWnd, SW_RESTORE);
+}
+
+DllExport VOID APIENTRY CreateNewTrayIcon()
+{
+ Shell_NotifyIcon(NIM_DELETE,&niData);
+ trayMenu = NULL;
+}
+
+DllExport VOID APIENTRY CloseAllPrograms()
+{
+// HANDLE hProc;
+
+ // Close all attached BPQ32 programs
+
+ Closing = TRUE;
+
+ ShowWindow(FrameWnd, SW_RESTORE);
+
+ GetWindowRect(FrameWnd, &FRect);
+
+ SaveBPQ32Windows();
+ CloseHostSessions();
+
+ if (AttachedProcesses == 1)
+ CloseBPQ32();
+
+ Debugprintf("BPQ32 Close All Processes %d PIDS %d %d %d %d", AttachedProcesses, AttachedPIDList[0],
+ AttachedPIDList[1], AttachedPIDList[2], AttachedPIDList[3]);
+
+ if (MinimizetoTray)
+ Shell_NotifyIcon(NIM_DELETE,&niData);
+
+ EnumWindows(EnumForCloseProc, (LPARAM)NULL);
+}
+
+#define MAX_KEY_LENGTH 255
+#define MAX_VALUE_NAME 16383
+#define MAX_VALUE_DATA 65536
+
+BOOL CopyReg(HKEY hKeyIn, HKEY hKeyOut)
+{
+ TCHAR achKey[MAX_KEY_LENGTH]; // buffer for subkey name
+ DWORD cbName; // size of name string
+ TCHAR achClass[MAX_PATH] = TEXT(""); // buffer for class name
+ DWORD cchClassName = MAX_PATH; // size of class string
+ DWORD cSubKeys=0; // number of subkeys
+ DWORD cbMaxSubKey; // longest subkey size
+ DWORD cchMaxClass; // longest class string
+ DWORD cValues; // number of values for key
+ DWORD cchMaxValue; // longest value name
+ DWORD cbMaxValueData; // longest value data
+ DWORD cbSecurityDescriptor; // size of security descriptor
+ FILETIME ftLastWriteTime; // last write time
+
+ DWORD i, retCode;
+
+ TCHAR achValue[MAX_VALUE_NAME];
+ DWORD cchValue = MAX_VALUE_NAME;
+
+ // Get the class name and the value count.
+ retCode = RegQueryInfoKey(
+ hKeyIn, // key handle
+ achClass, // buffer for class name
+ &cchClassName, // size of class string
+ NULL, // reserved
+ &cSubKeys, // number of subkeys
+ &cbMaxSubKey, // longest subkey size
+ &cchMaxClass, // longest class string
+ &cValues, // number of values for this key
+ &cchMaxValue, // longest value name
+ &cbMaxValueData, // longest value data
+ &cbSecurityDescriptor, // security descriptor
+ &ftLastWriteTime); // last write time
+
+ // Enumerate the subkeys, until RegEnumKeyEx fails.
+
+ if (cSubKeys)
+ {
+ Debugprintf( "\nNumber of subkeys: %d\n", cSubKeys);
+
+ for (i=0; i 76)
+ {
+ len += sprintf(&RegLine[len], "\\\r\n", RegLine);
+ strcat(RegLine, "\\\r\n");
+ WriteFile(hFile, RegLine, len, &written, NULL);
+ strcpy(RegLine, " ");
+ len = 2;
+ }
+
+ len += sprintf(&RegLine[len], "%02x,", Value[k]);
+ }
+ RegLine[--len] = 0x0d;
+ RegLine[++len] = 0x0a;
+ len++;
+
+ break;
+
+ case REG_DWORD: //( 4 ) // 32-bit number
+// case REG_DWORD_LITTLE_ENDIAN: //( 4 ) // 32-bit number (same as REG_DWORD)
+
+ memcpy(&Intval, Value, 4);
+ len = sprintf(RegLine, "\"%s\"=dword:%08x\r\n", achValue, Intval);
+ break;
+
+ case REG_DWORD_BIG_ENDIAN: //( 5 ) // 32-bit number
+ break;
+ case REG_LINK: //( 6 ) // Symbolic Link (unicode)
+ break;
+ case REG_MULTI_SZ: //( 7 ) // Multiple Unicode strings
+
+ len = sprintf(RegLine, "\"%s\"=hex(7):%02x,00,", achValue, Value[0]);
+ for (k = 1; k < ValLen; k++)
+ {
+ if (len > 76)
+ {
+ len += sprintf(&RegLine[len], "\\\r\n");
+ WriteFile(hFile, RegLine, len, &written, NULL);
+ strcpy(RegLine, " ");
+ len = 2;
+ }
+
+ len += sprintf(&RegLine[len], "%02x,", Value[k]);
+ if (len > 76)
+ {
+ len += sprintf(&RegLine[len], "\\\r\n");
+ WriteFile(hFile, RegLine, len, &written, NULL);
+ strcpy(RegLine, " ");
+ }
+ len += sprintf(&RegLine[len], "00,");
+ }
+
+ RegLine[--len] = 0x0d;
+ RegLine[++len] = 0x0a;
+ len++;
+ break;
+
+ case REG_RESOURCE_LIST: //( 8 ) // Resource list in the resource map
+ break;
+ case REG_FULL_RESOURCE_DESCRIPTOR: //( 9 ) // Resource list in the hardware description
+ break;
+ case REG_RESOURCE_REQUIREMENTS_LIST://( 10 )
+ break;
+ case REG_QWORD: //( 11 ) // 64-bit number
+// case REG_QWORD_LITTLE_ENDIAN: //( 11 ) // 64-bit number (same as REG_QWORD)
+ break;
+
+ }
+
+ WriteFile(hFile, RegLine, len, &written, NULL);
+ }
+ }
+ }
+
+ WriteFile(hFile, "\r\n", 2, &written, NULL);
+
+ // Enumerate the subkeys, until RegEnumKeyEx fails.
+
+ if (cSubKeys)
+ {
+ for (i=0; i> 1;
+ }
+
+ Flags=GetApplFlags(i);
+
+ if (OneBits > 1)
+ sprintf(&NewScreen[(i+1)*54],"%2d%s%3d %3d %3d %03x %3x %10s%-20s",
+ i, flag, RXCount(i), TXCount(i), MONCount(i), Mask, Flags, callsign,
+ BPQHOSTVECTOR[i-1].PgmName);
+ else
+ sprintf(&NewScreen[(i+1)*54],"%2d%s%3d %3d %3d %3d %3x %10s%-20s",
+ i, flag, RXCount(i), TXCount(i), MONCount(i), AppNumber, Flags, callsign,
+ BPQHOSTVECTOR[i-1].PgmName);
+
+ }
+ }
+
+ #include "StdExcept.c"
+
+ if (Semaphore.Flag && Semaphore.SemProcessID == GetCurrentProcessId())
+ FreeSemaphore(&Semaphore);
+
+ }
+
+ if (memcmp(Screen, NewScreen, 33 * 108) == 0) // No Change
+ return 0;
+
+ memcpy(Screen, NewScreen, 33 * 108);
+ InvalidateRect(StatusWnd,NULL,FALSE);
+
+ return(0);
+}
+
+LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int wmId, wmEvent;
+ PAINTSTRUCT ps;
+ HDC hdc;
+ HFONT hOldFont ;
+ HGLOBAL hMem;
+ MINMAXINFO * mmi;
+ int i;
+
+ switch (message)
+ {
+ case WM_TIMER:
+
+ if (Semaphore.Flag == 0)
+ DoStatus();
+ break;
+
+ case WM_MDIACTIVATE:
+
+ // Set the system info menu when getting activated
+
+ if (lParam == (LPARAM) hWnd)
+ {
+ // Activate
+
+ RemoveMenu(hBaseMenu, 1, MF_BYPOSITION);
+ AppendMenu(hBaseMenu, MF_STRING + MF_POPUP, (UINT)hConsMenu, "Actions");
+ SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hBaseMenu, (LPARAM) hWndMenu);
+ }
+ else
+ {
+ SendMessage(ClientWnd, WM_MDISETMENU, (WPARAM) hMainFrameMenu, (LPARAM) NULL);
+ }
+
+ DrawMenuBar(FrameWnd);
+
+ return TRUE; //DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ case WM_GETMINMAXINFO:
+
+ mmi = (MINMAXINFO *)lParam;
+ mmi->ptMaxSize.x = 850;
+ mmi->ptMaxSize.y = 500;
+ mmi->ptMaxTrackSize.x = 850;
+ mmi->ptMaxTrackSize.y = 500;
+
+
+ case WM_COMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+ //Parse the menu selections:
+
+ switch (wmId)
+ {
+
+/*
+ case BPQSTREAMS:
+
+ CheckMenuItem(hMenu,BPQSTREAMS,MF_CHECKED);
+ CheckMenuItem(hMenu,BPQIPSTATUS,MF_UNCHECKED);
+
+ StreamDisplay = TRUE;
+
+ break;
+
+ case BPQIPSTATUS:
+
+ CheckMenuItem(hMenu,BPQSTREAMS,MF_UNCHECKED);
+ CheckMenuItem(hMenu,BPQIPSTATUS,MF_CHECKED);
+
+ StreamDisplay = FALSE;
+ memset(Screen, ' ', 4000);
+
+
+ break;
+
+*/
+
+ case BPQCOPY:
+
+ //
+ // Copy buffer to clipboard
+ //
+ hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, 33*110);
+
+ if (hMem != 0)
+ {
+ if (OpenClipboard(hWnd))
+ {
+// CopyScreentoBuffer(GlobalLock(hMem));
+ GlobalUnlock(hMem);
+ EmptyClipboard();
+ SetClipboardData(CF_TEXT,hMem);
+ CloseClipboard();
+ }
+ else
+ {
+ GlobalFree(hMem);
+ }
+
+ }
+
+ break;
+
+ }
+
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+
+ case WM_SYSCOMMAND:
+
+ wmId = LOWORD(wParam); // Remember, these are...
+ wmEvent = HIWORD(wParam); // ...different for Win32!
+
+ switch (wmId)
+ {
+ case SC_MAXIMIZE:
+
+ break;
+
+ case SC_MINIMIZE:
+
+ StatusMinimized = TRUE;
+ break;
+
+ case SC_RESTORE:
+
+ StatusMinimized = FALSE;
+ SendMessage(ClientWnd, WM_MDIRESTORE, (WPARAM)hWnd, 0);
+ break;
+ }
+
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ case WM_PAINT:
+
+ hdc = BeginPaint (hWnd, &ps);
+
+ hOldFont = SelectObject( hdc, hFont) ;
+
+ for (i=0; i<33; i++)
+ {
+ TextOut(hdc,0,i*14,&Screen[i*108],108);
+ }
+
+ SelectObject( hdc, hOldFont ) ;
+ EndPaint (hWnd, &ps);
+
+ break;
+
+ case WM_DESTROY:
+
+// PostQuitMessage(0);
+
+ break;
+
+
+ default:
+
+ return DefMDIChildProc(hWnd, message, wParam, lParam);
+
+ }
+ return (0);
+}
+
+VOID SaveMDIWindowPos(HWND hWnd, char * RegKey, char * Value, BOOL Minimized)
+{
+ HKEY hKey=0;
+ char Size[80];
+ char Key[80];
+ int retCode, disp;
+ RECT Rect;
+
+ if (IsWindow(hWnd) == FALSE)
+ return;
+
+ ShowWindow(hWnd, SW_RESTORE);
+
+ if (GetWindowRect(hWnd, &Rect) == FALSE)
+ return;
+
+ // Make relative to Frame
+
+ Rect.top -= FRect.top ;
+ Rect.left -= FRect.left;
+ Rect.bottom -= FRect.top;
+ Rect.right -= FRect.left;
+
+ sprintf(Key, "SOFTWARE\\G8BPQ\\BPQ32\\%s", RegKey);
+
+ retCode = RegCreateKeyEx(REGTREE, Key, 0, 0, 0,
+ KEY_ALL_ACCESS, NULL, &hKey, &disp);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ sprintf(Size,"%d,%d,%d,%d,%d", Rect.left, Rect.right, Rect.top ,Rect.bottom, Minimized);
+ retCode = RegSetValueEx(hKey, Value, 0, REG_SZ,(BYTE *)&Size, strlen(Size));
+ RegCloseKey(hKey);
+ }
+}
+
+extern int GPSPort;
+extern char LAT[]; // in standard APRS Format
+extern char LON[]; // in standard APRS Format
+
+VOID SaveBPQ32Windows()
+{
+ HKEY hKey=0;
+ char Size[80];
+ int retCode, disp;
+ PEXTPORTDATA PORTVEC=(PEXTPORTDATA)PORTTABLE;
+ int i;
+
+ retCode = RegCreateKeyEx(REGTREE, "SOFTWARE\\G8BPQ\\BPQ32", 0, 0, 0, KEY_ALL_ACCESS, NULL, &hKey, &disp);
+
+ if (retCode == ERROR_SUCCESS)
+ {
+ sprintf(Size,"%d,%d,%d,%d", FRect.left, FRect.right, FRect.top, FRect.bottom);
+ retCode = RegSetValueEx(hKey, "FrameWindowSize", 0, REG_SZ, (BYTE *)&Size, strlen(Size));
+
+ // Save GPS Position
+
+ if (GPSPort)
+ {
+ sprintf(Size, "%s, %s", LAT, LON);
+ retCode = RegSetValueEx(hKey, "GPS", 0, REG_SZ,(BYTE *)&Size, strlen(Size));
+ }
+
+ RegCloseKey(hKey);
+ }
+
+ SaveMDIWindowPos(StatusWnd, "", "StatusWindowSize", StatusMinimized);
+ SaveMDIWindowPos(hConsWnd, "", "WindowSize", ConsoleMinimized);
+
+ for (i=0; iPORTCONTROL.PORTTYPE == 0x10) // External
+ {
+ if (PORTVEC->PORT_EXT_ADDR)
+ {
+ SaveWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
+ SaveAXIPWindowPos(PORTVEC->PORTCONTROL.PORTNUMBER);
+ }
+ }
+ PORTVEC=(PEXTPORTDATA)PORTVEC->PORTCONTROL.PORTPOINTER;
+ }
+
+ SaveWindowPos(70); // Rigcontrol
+
+
+ if (hIPResWnd)
+ SaveMDIWindowPos(hIPResWnd, "", "IPResSize", IPMinimized);
+
+ SaveHostSessions();
+}
+
+DllExport BOOL APIENTRY CheckIfOwner()
+{
+ //
+ // Returns TRUE if current process is root process
+ // that loaded the DLL
+ //
+
+ if (TimerInst == GetCurrentProcessId())
+
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+VOID GetParam(char * input, char * key, char * value)
+{
+ char * ptr = strstr(input, key);
+ char Param[2048];
+ char * ptr1, * ptr2;
+ char c;
+
+
+ if (ptr)
+ {
+ ptr2 = strchr(ptr, '&');
+ if (ptr2) *ptr2 = 0;
+ strcpy(Param, ptr + strlen(key));
+ if (ptr2) *ptr2 = '&'; // Restore string
+
+ // Undo any % transparency
+
+ ptr1 = Param;
+ ptr2 = Param;
+
+ c = *(ptr1++);
+
+ while (c)
+ {
+ if (c == '%')
+ {
+ int n;
+ int m = *(ptr1++) - '0';
+ if (m > 9) m = m - 7;
+ n = *(ptr1++) - '0';
+ if (n > 9) n = n - 7;
+
+ *(ptr2++) = m * 16 + n;
+ }
+ else if (c == '+')
+ *(ptr2++) = ' ';
+ else
+ *(ptr2++) = c;
+
+ c = *(ptr1++);
+ }
+
+ *(ptr2++) = 0;
+
+ strcpy(value, Param);
+ }
+}
+
+int GetListeningPortsPID(int Port)
+{
+ MIB_TCPTABLE_OWNER_PID * TcpTable = NULL;
+ PMIB_TCPROW_OWNER_PID Row;
+ int dwSize = 0;
+ DWORD n;
+
+ // Get PID of process for this TCP Port
+
+ // Get Length of table
+
+ GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0);
+
+ TcpTable = malloc(dwSize);
+
+ if (TcpTable == NULL)
+ return 0;
+
+ GetExtendedTcpTable(TcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_LISTENER, 0);
+
+ for (n = 0; n < TcpTable->dwNumEntries; n++)
+ {
+ Row = &TcpTable->table[n];
+
+ if (Row->dwLocalPort == Port && Row->dwState == MIB_TCP_STATE_LISTEN)
+ {
+ return Row->dwOwningPid;
+ break;
+ }
+ }
+ return 0; // Not found
+}
+
+DllExport char * APIENTRY GetLOC()
+{
+ return LOC;
+}
+
+DllExport void APIENTRY GetLatLon(double * lat, double * lon)
+{
+ *lat = LatFromLOC;
+ *lon = LonFromLOC;
+ return;
+}
+
+
+// UZ7HO Dll PTT interface
+
+// 1 ext_PTT_info
+// 2 ext_PTT_settings
+// 3 ext_PTT_OFF
+// 4 ext_PTT_ON
+// 5 ext_PTT_close
+// 6 ext_PTT_open
+
+extern struct RIGINFO * DLLRIG; // Rig record for dll PTT interface (currently only for UZ7HO);
+
+VOID Rig_PTT(struct TNCINFO * TNC, BOOL PTTState);
+VOID Rig_PTTEx(struct RIGINFO * RIG, BOOL PTTState, struct TNCINFO * TNC);
+
+int WINAPI ext_PTT_info()
+{
+ return 0;
+}
+
+int WINAPI ext_PTT_settings()
+{
+ return 0;
+}
+
+int WINAPI ext_PTT_OFF(int Port)
+{
+ if (DLLRIG)
+ Rig_PTTEx(DLLRIG, 0, 0);
+
+ return 0;
+}
+
+int WINAPI ext_PTT_ON(int Port)
+{
+ if (DLLRIG)
+ Rig_PTTEx(DLLRIG, 1, 0);
+
+ return 0;
+}
+int WINAPI ext_PTT_close()
+{
+ if (DLLRIG)
+ Rig_PTTEx(DLLRIG, 0, 0);
+
+ return 0;
+}
+
+DllExport INT WINAPI ext_PTT_open()
+{
+ return 1;
+}
+
+char * stristr (char *ch1, char *ch2)
+{
+ char *chN1, *chN2;
+ char *chNdx;
+ char *chRet = NULL;
+
+ chN1 = _strdup(ch1);
+ chN2 = _strdup(ch2);
+
+ if (chN1 && chN2)
+ {
+ chNdx = chN1;
+ while (*chNdx)
+ {
+ *chNdx = (char) tolower(*chNdx);
+ chNdx ++;
+ }
+ chNdx = chN2;
+
+ while (*chNdx)
+ {
+ *chNdx = (char) tolower(*chNdx);
+ chNdx ++;
+ }
+
+ chNdx = strstr(chN1, chN2);
+
+ if (chNdx)
+ chRet = ch1 + (chNdx - chN1);
+ }
+
+ free (chN1);
+ free (chN2);
+ return chRet;
+}
+
diff --git a/.svn/pristine/10/102d41bc4cd0f242aaba204301966dc699e1ff06.svn-base b/.svn/pristine/10/102d41bc4cd0f242aaba204301966dc699e1ff06.svn-base
index 78e8a98..bc0a854 100644
--- a/.svn/pristine/10/102d41bc4cd0f242aaba204301966dc699e1ff06.svn-base
+++ b/.svn/pristine/10/102d41bc4cd0f242aaba204301966dc699e1ff06.svn-base
@@ -1,2179 +1,2179 @@
-/*
-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
-//
-// FBB Forwarding Routines
-
-#include "bpqmail.h"
-
-#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__)
-void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line);
-
-
-void DeleteRestartData(CIRCUIT * conn);
-
-int32_t Encode(char * in, char * out, int32_t inlen, BOOL B1Protocol, int Compress);
-void MQTTMessageEvent(void* message);
-
-int MaxRXSize = 99999;
-int MaxTXSize = 99999;
-
-struct FBBRestartData ** RestartData = NULL;
-int RestartCount = 0;
-
-struct B2RestartData ** B2RestartRecs = NULL;
-int B2RestartCount = 0;
-
-extern char ProperBaseDir[];
-
-char RestartDir[MAX_PATH] = "";
-
-void GetRestartData()
-{
- int i;
- struct FBBRestartData Restart;
- struct FBBRestartData * RestartRec;
- char MsgFile[MAX_PATH];
- FILE * hFile;
- int FileSize;
- struct stat STAT;
- size_t ReadLen = 0;
- time_t Age;
-
- strcpy(RestartDir, MailDir);
- strcat(RestartDir, "/Restart");
-
- // Make sure RestartDir exists
-
-#ifdef WIN32
- CreateDirectory(RestartDir, NULL); // Just in case
-#else
- mkdir(RestartDir, S_IRWXU | S_IRWXG | S_IRWXO);
- chmod(RestartDir, S_IRWXU | S_IRWXG | S_IRWXO);
-#endif
-
- // look for restart files. These will be numbered from 1 up
-
- for (i = 1; 1; i++)
- {
- sprintf_s(MsgFile, sizeof(MsgFile), "%s/%d", RestartDir, i);
-
- if (stat(MsgFile, &STAT) == -1)
- break;
-
- FileSize = STAT.st_size;
-
- Age = time(NULL) - STAT.st_ctime;
-
- if (Age > 86400 * 2) // Max 2 days
- continue;
-
- hFile = fopen(MsgFile, "rb");
-
- if (hFile == NULL)
- break;
-
- // Read Restart Record
-
- fread(&Restart, 1, sizeof(struct FBBRestartData), hFile);
-
- if ((Restart.MailBufferSize + sizeof(struct FBBRestartData)) != FileSize) // Duff file
- {
- fclose(hFile);
- break;
- }
-
- RestartRec = zalloc(sizeof (struct FBBRestartData));
-
- GetSemaphore(&AllocSemaphore, 0);
-
- RestartData = realloc(RestartData,(++RestartCount+1) * sizeof(void *));
- RestartData[RestartCount] = RestartRec;
-
- FreeSemaphore(&AllocSemaphore);
-
- memcpy(RestartRec, &Restart, sizeof(struct FBBRestartData));
- RestartRec->MailBuffer = malloc(RestartRec->MailBufferSize);
- ReadLen = fread(RestartRec->MailBuffer, 1, RestartRec->MailBufferSize, hFile);
-
- Logprintf(LOG_BBS, 0, '?', "Restart Data for %s %s Len %d Loaded", RestartRec->Call, RestartRec->bid, RestartRec->length);
- fclose(hFile);
- }
-}
-
-
-void SaveRestartData()
-{
- // Save restart data to file so we can reload on restart
- // Restart data has pointers to buffers so we must save copy of data and reconstitue on restart
-
- // Delete and resave all restart data to keep restart directory clean
-
- int i, n = 1;
- char MsgFile[MAX_PATH];
- FILE * hFile;
- size_t WriteLen=0;
- struct FBBRestartData * RestartRec = NULL;
- struct stat STAT;
- time_t NOW = time(NULL);
-
-
- for (i = 1; 1; i++)
- {
- sprintf_s(MsgFile, sizeof(MsgFile), "%s/%d", RestartDir, i);
-
- if (stat(MsgFile, &STAT) == -1)
- break;
-
- DeleteFile(MsgFile);
- }
-
- for (i = 1; i <= RestartCount; i++)
- {
- RestartRec = RestartData[i];
-
- if (RestartRec == 0)
- return; // Shouldn't happen!
-
- if ((NOW - RestartRec->TimeCreated) > 86400 * 2) // Max 2 days
- continue;
-
- sprintf_s(MsgFile, sizeof(MsgFile), "%s/%d", RestartDir, n++);
-
- hFile = fopen(MsgFile, "wb");
-
- if (hFile)
- {
- WriteLen = fwrite(RestartRec, 1, sizeof(struct FBBRestartData), hFile); // Save Header
- WriteLen = fwrite(RestartRec->MailBuffer, 1, RestartRec->MailBufferSize, hFile); // Save Data
- fclose(hFile);
- }
- }
-}
-VOID FBBputs(CIRCUIT * conn, char * buf)
-{
- // Sends to user and logs
-
- int len = (int)strlen(buf);
-
- WriteLogLine(conn, '>', buf, len -1, LOG_BBS);
-
- QueueMsg(conn, buf, len);
-
- if (conn->BBSFlags & NEEDLF)
- QueueMsg(conn, "\n", 1);
-}
-
-
-VOID ProcessFBBLine(CIRCUIT * conn, struct UserInfo * user, UCHAR* Buffer, int len)
-{
- struct FBBHeaderLine * FBBHeader; // The Headers from an FBB forward block
- int i;
- int Index = 0; // Message Type Index for Stats
- char * ptr;
- char * Context;
- char seps[] = " \r";
- int RestartPtr;
- char * Respptr;
- BOOL AllRejected = TRUE;
- char * MPS;
- char * ROChar;
-
- if (conn->Flags & GETTINGMESSAGE)
- {
- ProcessMsgLine(conn, user, Buffer, len);
- if (conn->Flags & GETTINGMESSAGE)
-
- // Still going
- return;
-
- SetupNextFBBMessage(conn);
- return;
- }
-
- if (conn->Flags & GETTINGTITLE)
- {
- ProcessMsgTitle(conn, user, Buffer, len);
- return;
- }
-
- // Should be FA FB F> FS FF FQ
-
- if (Buffer[0] == ';') // winlink comment or BPQ Type Select
- {
- if (memcmp(Buffer, "; MSGTYPES", 7) == 0)
- {
- char * ptr;
-
- conn->SendB = conn->SendP = conn->SendT = FALSE;
-
- ptr = strchr(&Buffer[10], 'B');
-
- if (ptr)
- {
- conn->SendB = TRUE;
- conn->MaxBLen = atoi(++ptr);
- if (conn->MaxBLen == 0) conn->MaxBLen = 99999999;
- }
-
- ptr = strchr(&Buffer[10], 'T');
-
- if (ptr)
- {
- conn->SendT = TRUE;
- conn->MaxTLen = atoi(++ptr);
- if (conn->MaxTLen == 0) conn->MaxTLen = 99999999;
- }
- ptr = strchr(&Buffer[10], 'P');
-
- if (ptr)
- {
- conn->SendP = TRUE;
- conn->MaxPLen = atoi(++ptr);
- if (conn->MaxPLen == 0) conn->MaxPLen = 99999999;
- }
- return;
- }
-
- // Other ; Line - Ignore
-
- return;
- }
-
- if (Buffer[0] != 'F')
- {
- if (strstr(Buffer, "*** Profanity detected") || strstr(Buffer, "*** Unknown message sender"))
- {
- // Winlink Check - hold message
-
- if (conn->FBBMsgsSent)
- HoldSentMessages(conn, user);
- }
-
- if (conn->BBSFlags & DISCONNECTING)
- return; // Ignore if disconnect aleady started
-
- BBSputs(conn, "*** Protocol Error - Line should start with 'F'\r");
- Flush(conn);
- Sleep(500);
- conn->BBSFlags |= DISCONNECTING;
- Disconnect(conn->BPQStream);
-
- return;
- }
-
- switch (Buffer[1])
- {
- case 'F':
-
- // Request Reverse
-
- if (conn->FBBMsgsSent)
- FlagSentMessages(conn, user);
-
- if (!FBBDoForward(conn)) // Send proposal if anthing to forward
- {
- FBBputs(conn, "FQ\r");
-
- conn->BBSFlags |= DISCONNECTING;
-
- // LinFBB needs a Disconnect Here
-
- if (conn->BPQBBS)
- return; // BPQ will close when it sees FQ. Close collisions aren't good!
-
- if ((conn->SessType & Sess_PACTOR) == 0)
- conn->CloseAfterFlush = 20; // 2 Secs
- else
- conn->CloseAfterFlush = 20; // PACTOR/WINMOR drivers support deferred disc so 5 secs should be enough
- }
- return;
-
- case 'S':
-
- // Proposal response
-
- Respptr=&Buffer[2];
-
- for (i=0; i < conn->FBBIndex; i++)
- {
- FBBHeader = &conn->FBBHeaders[i];
-
- if (FBBHeader->MsgType == 'P')
- Index = PMSG;
- else if (FBBHeader->MsgType == 'B')
- Index = BMSG;
- else if (FBBHeader->MsgType == 'T')
- Index = TMSG;
-
- Respptr++;
-
- if (*Respptr == 'E')
- {
- // Rejected
-
- Logprintf(LOG_BBS, conn, '?', "Proposal %d Rejected by far end", i + 1);
- }
-
- if ((*Respptr == '-') || (*Respptr == 'N') || (*Respptr == 'R') || (*Respptr == 'E')) // Not wanted
- {
- user->Total.MsgsRejectedOut[Index]++;
-
- // Zap the entry
-
- if (conn->Paclink || conn->RMSExpress || conn->PAT) // Not using Bit Masks
- {
- // Kill Messages sent to paclink/RMS Express unless BBS FWD bit set
-
- // What if WLE retrieves P message that is queued to differnet BBS?
- // if we dont kill it will be offered again
-
- if (FBBHeader->FwdMsg->type == 'P' || (check_fwd_bit(FBBHeader->FwdMsg->fbbs, user->BBSNumber) == 0))
- FlagAsKilled(FBBHeader->FwdMsg, FALSE);
- }
-
- clear_fwd_bit(FBBHeader->FwdMsg->fbbs, user->BBSNumber);
- set_fwd_bit(FBBHeader->FwdMsg->forw, user->BBSNumber);
-
- FBBHeader->FwdMsg->Locked = 0; // Unlock
-
- // Shouldn't we set P messages as Forwarded
- // (or will check above have killed it if it is P with other FWD bits set)
- // Maybe better to be safe !!
-
- if (FBBHeader->FwdMsg->type == 'P' || memcmp(FBBHeader->FwdMsg->fbbs, zeros, NBMASK) == 0)
- {
- FBBHeader->FwdMsg->status = 'F'; // Mark as forwarded
- FBBHeader->FwdMsg->datechanged=time(NULL);
- }
-
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine));
-
- conn->UserPointer->ForwardingInfo->MsgCount--;
-
- SaveMessageDatabase();
- continue;
- }
-
- // FBB uses H for HOLD, but I've never seen it. RMS Express sends H for Defer.
-
-
- if (*Respptr == '=' || *Respptr == 'L' || (*Respptr == 'H' && conn->RMSExpress)) // Defer
- {
- // Remove entry from forwarding block
-
- FBBHeader->FwdMsg->Defered = 4; // Don't retry for the next few forward cycles
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine));
- continue;
- }
-
- conn->RestartFrom = 0; // Assume Restart from
-
- if ((*Respptr == '!') || (*Respptr == 'A'))
- {
- // Restart
-
- char Num[10];
- char *numptr=&Num[0];
-
- Respptr++;
-
- while (isdigit(*Respptr))
- {
- *(numptr++) = *(Respptr++);
- }
- *numptr = 0;
-
- conn->RestartFrom = atoi(Num);
-
- *(--Respptr) = '+'; // So can drop through
- }
-
- // FBB uses H for HOLD, but I've never seen it. RMS Express sends H for Defer. RMS use trapped above
-
- if ((*Respptr == '+') || (*Respptr == 'Y') || (*Respptr == 'H'))
- {
- struct tm * tm;
- time_t now;
- char * MsgBytes;
-
- conn->FBBMsgsSent = TRUE; // Messages to flag as complete when next command received
- AllRejected = FALSE;
-
- if (conn->BBSFlags & FBBForwarding)
- {
- if (conn->BBSFlags & FBBB2Mode)
- SendCompressedB2(conn, FBBHeader);
- else
- SendCompressed(conn, FBBHeader->FwdMsg);
- }
- else
- {
- nodeprintf(conn, "%s\r\n", FBBHeader->FwdMsg->title);
-
- MsgBytes = ReadMessageFile(FBBHeader->FwdMsg->number);
-
- if (MsgBytes == 0)
- {
- MsgBytes = _strdup("Message file not found\r\n");
- FBBHeader->FwdMsg->length = (int)strlen(MsgBytes);
- }
-
- now = time(NULL);
-
- tm = gmtime(&now);
-
- nodeprintf(conn, "R:%02d%02d%02d/%02d%02dZ %d@%s.%s %s\r\n",
- tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,
- FBBHeader->FwdMsg->number, BBSName, HRoute, RlineVer);
-
- if (memcmp(MsgBytes, "R:", 2) != 0) // No R line, so must be our message - put blank line after header
- BBSputs(conn, "\r\n");
-
- QueueMsg(conn, MsgBytes, FBBHeader->FwdMsg->length);
- free(MsgBytes);
-
- user->Total.MsgsSent[Index]++;
- user->Total.BytesForwardedOut[Index] += FBBHeader->FwdMsg->length;
-
- nodeprintf(conn, "%c\r\n", 26);
- }
- continue;
- }
- BBSputs(conn, "*** Protocol Error - Invalid Proposal Response'\r");
- }
-
- conn->FBBIndex = 0; // ready for next block;
- conn->FBBChecksum = 0;
-
-
- if (AllRejected && (conn->RMSExpress || conn->PAT))
- {
- // RMS Express and PAT don't send FF or proposal after rejecting all messages
-
- FBBputs(conn, "FF\r");
- }
-
- return;
-
- case 'Q':
-
- if (conn->FBBMsgsSent)
- FlagSentMessages(conn, user);
-
- conn->BBSFlags |= DISCONNECTING;
-
- Disconnect(conn->BPQStream);
- return;
-
- case 'A': // Proposal
- case 'B': // Proposal
-
- if (conn->FBBMsgsSent)
- FlagSentMessages(conn, user); // Mark previously sent messages
-
- if (conn->DoReverse == FALSE) // Dont accept messages
- return;
-
- // Accumulate checksum
-
- for (i=0; i< len; i++)
- {
- conn->FBBChecksum+=Buffer[i];
- }
-
- // Parse Header
-
- // Find free line
-
- for (i = 0; i < 5; i++)
- {
- FBBHeader = &conn->FBBHeaders[i];
-
- if (FBBHeader->Format == 0)
- break;
- }
-
- if (i == 5)
- {
- BBSputs(conn, "*** Protocol Error - Too Many Proposals\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
- }
-
- //FA P GM8BPQ G8BPQ G8BPQ 2209_GM8BPQ 8
-
- FBBHeader->Format = Buffer[1];
-
- ptr = strtok_s(&Buffer[3], seps, &Context);
-
- if (ptr == NULL) goto badparam;
-
- if (strlen(ptr) != 1) goto badparam;
-
- FBBHeader->MsgType = *ptr;
-
- if (FBBHeader->MsgType == 'P')
- Index = PMSG;
- else if (FBBHeader->MsgType == 'B')
- Index = BMSG;
- else if (FBBHeader->MsgType == 'T')
- Index = TMSG;
-
-
- ptr = strtok_s(NULL, seps, &Context);
-
- if (ptr == NULL) goto badparam;
- strlop(ptr, '-'); // Remove any (illegal) ssid
-
- if (strlen(ptr) > 6 ) goto badparam;
-
- strcpy(FBBHeader->From, ptr);
-
- ptr = strtok_s(NULL, seps, &Context);
-
- if (ptr == NULL) goto badparam;
-
- if (strlen(ptr) > 40 ) goto badparam;
-
- strcpy(FBBHeader->ATBBS, ptr);
-
- ptr = strtok_s(NULL, seps, &Context);
-
- if (ptr == NULL) goto badparam;
-
- if (strlen(ptr) > 6)
- {
- // Temp fix - reject instead of breaking connection
-
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
- conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
- Logprintf(LOG_BBS, conn, '?', "Message Rejected as TO field too long");
-
- user->Total.MsgsRejectedIn[Index]++;
- return;
- }
-
- strlop(ptr, '-'); // Remove any (illegal) ssid
-
- strcpy(FBBHeader->To, ptr);
-
- ptr = strtok_s(NULL, seps, &Context);
-
- if (ptr == NULL) goto badparam;
-
- if (strlen(ptr) > 12 ) goto badparam;
-
- strcpy(FBBHeader->BID, ptr);
-
- ptr = strtok_s(NULL, seps, &Context);
-
- if (ptr == NULL) goto badparam;
-
- FBBHeader->Size = atoi(ptr);
-
- goto ok;
-
-badparam:
-
- BBSputs(conn, "*** Protocol Error - Proposal format error\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
- return;
-
-ok:
-
- // Check Filters
-
- if (CheckRejFilters(FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->BID, FBBHeader->MsgType, FBBHeader->Size))
- {
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
- conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
- Logprintf(LOG_BBS, conn, '?', "Message Rejected by Filters");
-
- user->Total.MsgsRejectedIn[Index]++;
- }
-
- // If P Message, dont immediately reject on a Duplicate BID. Check if we still have the message
- // If we do, reject it. If not, accept it again. (do we need some loop protection ???)
-
- else if (DoWeWantIt(conn, FBBHeader) == FALSE)
- {
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
- conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
- user->Total.MsgsRejectedIn[Index]++;
- }
- else if ((RestartPtr = LookupRestart(conn, FBBHeader)) > 0)
- {
- conn->FBBReplyIndex += sprintf(&conn->FBBReplyChars[conn->FBBReplyIndex], "!%d", RestartPtr);
- }
- else if (LookupTempBID(FBBHeader->BID))
- {
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
- conn->FBBReplyChars[conn->FBBReplyIndex++] = '=';
- }
- else
- {
-
- // Save BID in temp list in case we are offered it again before completion
-
- BIDRec * TempBID = AllocateTempBIDRecord();
- strcpy(TempBID->BID, FBBHeader->BID);
- TempBID->u.conn = conn;
-
- conn->FBBReplyChars[conn->FBBReplyIndex++] = '+';
- }
-
- FBBHeader->B2Message = FALSE;
-
- return;
-
- case 'C': // B2 Proposal
-
- if (conn->FBBMsgsSent)
- FlagSentMessages(conn, user); // Mark previously sent messages
-
- if (conn->DoReverse == FALSE) // Dont accept messages
- return;
-
- // Accumulate checksum
-
- for (i=0; i< len; i++)
- {
- conn->FBBChecksum+=Buffer[i];
- }
-
- // Parse Header
-
- // Find free line
-
- for (i = 0; i < 5; i++)
- {
- FBBHeader = &conn->FBBHeaders[i];
-
- if (FBBHeader->Format == 0)
- break;
- }
-
- if (i == 5)
- {
- BBSputs(conn, "*** Protocol Error - Too Many Proposals\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
- }
-
-
- // FC EM A3EDD4P00P55 377 281 0
-
- /*
-
- FC Proposal code. Requires B2 SID feature.
- Type Message type ( 1 or 2 alphanumeric characters
-
- CM WinLink 2000 Control message
- EM Encapsulated Message
- ID Unique Message Identifier (max length 12 characters)
- U-Size Uncompressed size of message
- C-size Compressed size of message
-
- */
- FBBHeader->Format = Buffer[1];
-
- ptr = strtok_s(&Buffer[3], seps, &Context);
- if (ptr == NULL) goto badparam2;
- if (strlen(ptr) != 2) goto badparam2;
- FBBHeader->MsgType = 'P'; //ptr[0];
-
- ptr = strtok_s(NULL, seps, &Context);
-
- if (ptr == NULL) goto badparam2;
-
- // Relay In RO mode adds @MPS@R to the MID. Don't know why (yet!)
-
- MPS = strlop(ptr, '@');
- if (MPS)
- ROChar = strlop(MPS, '@');
-
- if (strlen(ptr) > 12 ) goto badparam;
- strcpy(FBBHeader->BID, ptr);
-
- ptr = strtok_s(NULL, seps, &Context);
- if (ptr == NULL) goto badparam2;
- FBBHeader->Size = atoi(ptr);
-
- ptr = strtok_s(NULL, seps, &Context);
- if (ptr == NULL) goto badparam2;
- FBBHeader->CSize = atoi(ptr);
- FBBHeader->B2Message = TRUE;
-
- // If using BPQ Extensions (From To AT in proposal) Check Filters
-
- Buffer[len - 1] = 0;
-
- if (conn->BPQBBS)
- {
- char * From = strtok_s(NULL, seps, &Context);
- char * ATBBS = strtok_s(NULL, seps, &Context);
- char * To = strtok_s(NULL, seps, &Context);
- char * Type = strtok_s(NULL, seps, &Context);
-
- if (From && To && ATBBS && Type && CheckRejFilters(From, To, ATBBS, NULL, *Type, FBBHeader->Size))
- {
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
- conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
- user->Total.MsgsRejectedIn[Index]++;
- Logprintf(LOG_BBS, conn, '?', "Message Rejected by Filters");
-
- return;
- }
- }
- goto ok2;
-
-badparam2:
-
- BBSputs(conn, "*** Protocol Error - Proposal format error\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
- return;
-
-ok2:
- if (LookupBID(FBBHeader->BID))
- {
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
- conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
- Logprintf(LOG_BBS, conn, '?', "Message Rejected by BID Check");
- user->Total.MsgsRejectedIn[Index]++;
-
- }
- else if (FBBHeader->Size > MaxRXSize)
- {
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
- conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
- Logprintf(LOG_BBS, conn, '?', "Message Rejected by Size Limit");
- user->Total.MsgsRejectedIn[Index]++;
-
- }
- else if ((RestartPtr = LookupRestart(conn, FBBHeader)) > 0)
- {
- conn->FBBReplyIndex += sprintf(&conn->FBBReplyChars[conn->FBBReplyIndex], "!%d", RestartPtr);
- }
-
- else if (LookupTempBID(FBBHeader->BID))
- {
- memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
- conn->FBBReplyChars[conn->FBBReplyIndex++] = '=';
- }
- else
- {
- // Save BID in temp list in case we are offered it again before completion
-
- BIDRec * TempBID = AllocateTempBIDRecord();
- strcpy(TempBID->BID, FBBHeader->BID);
- TempBID->u.conn = conn;
-
- conn->FBBReplyChars[conn->FBBReplyIndex++] = 'Y';
- }
-
- return;
-
- case '>':
-
- // Optional Checksum
-
- if (conn->DoReverse == FALSE) // Dont accept messages
- {
- Logprintf(LOG_BBS, conn, '?', "Reverse Forwarding not allowed");
- Disconnect(conn->BPQStream);
- return;
- }
-
- if (len > 3)
- {
- int sum;
-
- sscanf(&Buffer[3], "%x", &sum);
-
- conn->FBBChecksum+=sum;
-
- if (conn->FBBChecksum)
- {
- BBSputs(conn, "*** Proposal Checksum Error\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
- return;
- }
- }
-
- // Return "FS ", followed by +-= for each proposal
-
- conn->FBBReplyChars[conn->FBBReplyIndex] = 0;
- conn->FBBReplyIndex = 0;
-
- nodeprintfEx(conn, "FS %s\r", conn->FBBReplyChars);
-
- // if all rejected, send proposals or prompt, else set up for first message
-
- FBBHeader = &conn->FBBHeaders[0];
-
- if (FBBHeader->MsgType == 0)
- {
- conn->FBBIndex = 0; // ready for first block;
- memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine));
- conn->FBBChecksum = 0;
-
- if (!FBBDoForward(conn)) // Send proposal if anthing to forward
- {
- conn->InputMode = 0;
-
- if (conn->DoReverse)
- FBBputs(conn, "FF\r");
- else
- {
- FBBputs(conn, "FQ\r");
- conn->CloseAfterFlush = 20; // 2 Secs
- }
- }
- }
- else
- {
- if (conn->BBSFlags & FBBForwarding)
- {
- conn->InputMode = 'B';
- }
-
- CreateMessage(conn, FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->MsgType, FBBHeader->BID, NULL);
- }
-
- return;
-
- }
-
- return;
-}
-
-VOID HoldSentMessages(CIRCUIT * conn, struct UserInfo * user)
-{
- struct FBBHeaderLine * FBBHeader; // The Headers from an FBB forward block
- int i;
-
- conn->FBBMsgsSent = FALSE;
-
- for (i=0; i < 5; i++)
- {
- FBBHeader = &conn->FBBHeaders[i];
-
- if (FBBHeader && FBBHeader->MsgType) // Not a zapped entry
- {
- int Length=0;
- char * MailBuffer = malloc(100);
- char Title[100];
-
- Length += sprintf(MailBuffer, "Message %d Held\r\n", FBBHeader->FwdMsg->number);
- sprintf(Title, "Message %d Held - Rejected by Winlink", FBBHeader->FwdMsg->number);
- SendMessageToSYSOP(Title, MailBuffer, Length);
-
- FBBHeader->FwdMsg->status = 'H'; // Mark as Held
- }
- }
- memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine));
- SaveMessageDatabase();
-}
-
-
-
-VOID FlagSentMessages(CIRCUIT * conn, struct UserInfo * user)
-{
- struct FBBHeaderLine * FBBHeader; // The Headers from an FBB forward block
- int i;
-
- // Called if FBB command received after sending a block of messages . Flag as as sent.
-
- conn->FBBMsgsSent = FALSE;
-
- for (i=0; i < 5; i++)
- {
- FBBHeader = &conn->FBBHeaders[i];
-
- if (FBBHeader && FBBHeader->MsgType) // Not a zapped entry
- {
- if ((conn->Paclink || conn->RMSExpress || conn->PAT) &&
-// ((conn->UserPointer->flags & F_NTSMPS) == 0) &&
- (FBBHeader->FwdMsg->type == 'P'))
- {
- // Kill Messages sent to paclink/RMS Express unless BBS FWD bit set
-
- if (check_fwd_bit(FBBHeader->FwdMsg->fbbs, user->BBSNumber) == 0)
- {
- FlagAsKilled(FBBHeader->FwdMsg, FALSE);
- continue;
- }
- }
-
- clear_fwd_bit(FBBHeader->FwdMsg->fbbs, user->BBSNumber);
- set_fwd_bit(FBBHeader->FwdMsg->forw, user->BBSNumber);
-
- // Only mark as forwarded if sent to all BBSs that should have it
-
- if (memcmp(FBBHeader->FwdMsg->fbbs, zeros, NBMASK) == 0)
- {
- FBBHeader->FwdMsg->status = 'F'; // Mark as forwarded
- FBBHeader->FwdMsg->datechanged=time(NULL);
- }
-
-#ifndef NOMQTT
- if (MQTT)
- MQTTMessageEvent(FBBHeader->FwdMsg);
-#endif
-
- FBBHeader->FwdMsg->Locked = 0; // Unlock
- conn->UserPointer->ForwardingInfo->MsgCount--;
- }
- }
- memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine));
- SaveMessageDatabase();
-}
-
-
-VOID SetupNextFBBMessage(CIRCUIT * conn)
-{
- struct FBBHeaderLine * FBBHeader; // The Headers from an FBB forward block
-
- memmove(&conn->FBBHeaders[0], &conn->FBBHeaders[1], 4 * sizeof(struct FBBHeaderLine));
-
- memset(&conn->FBBHeaders[4], 0, sizeof(struct FBBHeaderLine));
-
- FBBHeader = &conn->FBBHeaders[0];
-
- if (FBBHeader->MsgType == 0)
- {
- conn->FBBIndex = 0; // ready for next block;
- memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine));
-
- conn->FBBChecksum = 0;
- conn->InputMode = 0;
-
- if (!FBBDoForward(conn)) // Send proposal if anthing to forward
- {
- conn->InputMode = 0;
- FBBputs(conn, "FF\r");
- }
- }
- else
- {
- if (conn->BBSFlags & FBBForwarding)
- conn->InputMode = 'B';
-
- CreateMessage(conn, FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->MsgType, FBBHeader->BID, NULL);
- }
-}
-
-BOOL FBBDoForward(CIRCUIT * conn)
-{
- int i;
- char proposal[100];
- int proplen;
-
- if (FindMessagestoForward(conn))
- {
- // Send Proposal Block
-
- struct FBBHeaderLine * FBBHeader;
-
- for (i=0; i < conn->FBBIndex; i++)
- {
- FBBHeader = &conn->FBBHeaders[i];
-
- if (conn->BBSFlags & FBBB2Mode)
-
- if (conn->BPQBBS)
-
- // Add From and To Header for Filters
-
- proplen = sprintf(proposal, "FC EM %s %d %d %s %s %s %c\r",
- FBBHeader->BID,
- FBBHeader->Size,
- FBBHeader->CSize,
- FBBHeader->From,
- (FBBHeader->ATBBS[0]) ? FBBHeader->ATBBS : conn->UserPointer->Call,
- FBBHeader->To,
- FBBHeader->MsgType);
-
- else
-
- // FC EM A3EDD4P00P55 377 281 0
-
- proplen = sprintf(proposal, "FC EM %s %d %d %d\r",
- FBBHeader->BID,
- FBBHeader->Size,
- FBBHeader->CSize, 0);
-
- else
- proplen = sprintf(proposal, "%s %c %s %s %s %s %d\r",
- (conn->BBSFlags & FBBCompressed) ? "FA" : "FB",
- FBBHeader->MsgType,
- FBBHeader->From,
- (FBBHeader->ATBBS[0]) ? FBBHeader->ATBBS : conn->UserPointer->Call,
- FBBHeader->To,
- FBBHeader->BID,
- FBBHeader->Size);
-
- // Accumulate checksum
-
- while(proplen > 0)
- {
- conn->FBBChecksum+=proposal[--proplen];
- }
-
- FBBputs(conn, proposal);
- }
-
- conn->FBBChecksum = - conn->FBBChecksum;
-
- nodeprintfEx(conn, "F> %02X\r", conn->FBBChecksum);
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-VOID UnpackFBBBinary(CIRCUIT * conn)
-{
- int MsgLen, i, offset, n;
- UCHAR * ptr;
-
-loop:
-
- if (conn->CloseAfterFlush) // Failed (or complete), so discard rest of input
- {
- conn->InputLen = 0;
- return;
- }
-
-
- ptr = conn->InputBuffer;
-
- if (conn->InputLen < 2)
- return; // All formats need at least two bytes
-
- switch (*ptr)
- {
- case 1: // Header
-
- MsgLen = ptr[1] + 2;
-
- if (conn->InputLen < MsgLen)
- return; // Wait for more
-
- if (strlen(&ptr[2]) > 60)
- {
- memcpy(conn->TempMsg->title, &ptr[2], 60);
- conn->TempMsg->title[60] = 0;
- Debugprintf("FBB Subject too long - truncated, %s", &ptr[2]);
- }
- else
- strcpy(conn->TempMsg->title, &ptr[2]);
-
- offset = atoi(ptr+3+strlen(&ptr[2]));
-
- ptr += MsgLen;
-
- memmove(conn->InputBuffer, ptr, conn->InputLen-MsgLen);
-
- conn->InputLen -= MsgLen;
-
- conn->FBBChecksum = 0;
-
- if (offset)
- {
- struct FBBRestartData * RestartRec;
-
- // Trying to restart - make sure we have restart data
-
- for (i = 1; i <= RestartCount; i++)
- {
- RestartRec = RestartData[i];
-
- if ((strcmp(RestartRec->Call, conn->UserPointer->Call) == 0)
- && (strcmp(RestartRec->bid, conn->TempMsg->bid) == 0))
- {
- if (RestartRec->length <= offset)
- {
- conn->TempMsg->length = RestartRec->length;
- conn->MailBuffer = RestartRec->MailBuffer;
- conn->MailBufferSize = RestartRec->MailBufferSize;
-
- // FBB Seems to insert 6 Byte message
- // It looks like the original csum and length - perhaps a a consistancy check
-
- // But Airmail Sends the Restart Data in the next packet, move the check code.
-
- conn->NeedRestartHeader = TRUE;
-
- goto GotRestart;
- }
- else
- {
- BBSputs(conn, "*** Trying to restart from invalid position.\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
-
- return;
- }
-
- // Remove Restart info
-
- for (n = i; n < RestartCount; n++)
- {
- RestartData[n] = RestartData[n+1]; // move down all following entries
- }
- RestartCount--;
- SaveRestartData();
- }
- }
-
- // No Restart Data
-
- BBSputs(conn, "*** Trying to restart, but no restart data.\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
-
- return;
- }
-
- // Create initial buffer of 10K. Expand if needed later
-
- if (conn->MailBufferSize == 0)
- {
- // Dont allocate if restarting
-
- conn->MailBuffer=malloc(10000);
- conn->MailBufferSize=10000;
- }
-
- GotRestart:
-
- if (conn->MailBuffer == NULL)
- {
- BBSputs(conn, "*** Failed to create Message Buffer\r");
- conn->CloseAfterFlush = 20; // 2 Secs
-
- return;
- }
-
- goto loop;
-
-
-
- case 2: // Data Block
-
- if (ptr[1] == 0)
- MsgLen = 256;
- else
- MsgLen = ptr[1];
-
- if (conn->InputLen < (MsgLen + 2))
- return; // Wait for more
-
- // If waiting for Restart Header, see if it has arrived
-
- if (conn->NeedRestartHeader)
- {
- conn->NeedRestartHeader = FALSE;
-
- if (MsgLen == 6)
- {
- ptr = conn->InputBuffer+2;
- conn->InputLen -=8;
-
- for (i=0; i<6; i++)
- {
- conn->FBBChecksum+=ptr[0];
- ptr++;
- }
- memmove(conn->InputBuffer, ptr, conn->InputLen);
- }
- else
- {
- BBSputs(conn, "*** Restart Header Missing.\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
- }
-
- goto loop;
-
- }
- // Process it
-
- ptr+=2;
-
- for (i=0; i< MsgLen; i++)
- {
- conn->FBBChecksum+=ptr[i];
- }
-
- ptr-=2;
-
- if ((conn->TempMsg->length + MsgLen) > conn->MailBufferSize)
- {
- conn->MailBufferSize += 10000;
- conn->MailBuffer = realloc(conn->MailBuffer, conn->MailBufferSize);
-
- if (conn->MailBuffer == NULL)
- {
- BBSputs(conn, "*** Failed to extend Message Buffer\r");
- conn->CloseAfterFlush = 20; // 2 Secs
-
- return;
- }
- }
-
- memcpy(&conn->MailBuffer[conn->TempMsg->length], &ptr[2], MsgLen);
-
- conn->TempMsg->length += MsgLen;
-
- MsgLen +=2;
-
- ptr += MsgLen;
-
- memmove(conn->InputBuffer, ptr, conn->InputLen-MsgLen);
-
- conn->InputLen -= MsgLen;
-
- goto loop;
-
-
- case 4: // EOM
-
- // Process EOM
-
- conn->FBBChecksum+=ptr[1];
-
- if (conn->FBBChecksum == 0)
- {
-#ifndef LINBPQ
- __try
- {
-#endif
- conn->InputMode = 0; // So we won't save Restart data if decode fails
- DeleteRestartData(conn);
- Decode(conn, 0); // Setup Next Message will reset InputMode if needed
-#ifndef LINBPQ
- }
- __except(EXCEPTION_EXECUTE_HANDLER)
- {
- BBSputs(conn, "*** Program Error Decoding Message\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
- return;
- }
-#endif
- }
-
- else
- {
- BBSputs(conn, "*** Message Checksum Error\r");
- Flush(conn);
- conn->CloseAfterFlush = 20; // 2 Secs
-
- // Don't allow restart, as saved data is probably duff
-
- conn->DontSaveRestartData = TRUE;
- return;
- }
- ptr += 2;
-
- memmove(conn->InputBuffer, ptr, conn->InputLen-2);
-
- conn->InputLen -= 2;
-
- goto loop;
-
- default:
-
- BBSputs(conn, "*** Protocol Error - Invalid Binary Message Format (Invalid Block Type)\r");
- Flush(conn);
-
- if (conn->CloseAfterFlush == 0)
- {
- // Dont do it more than once
-
- conn->CloseAfterFlush = 20; // 2 Secs
-
- // Don't allow restart, as saved data is probably duff
-
- // Actually all but the last block is probably OK, but maybe
- // not worth the risk of restarting
-
- // Actually I think it is
-
- if (conn->TempMsg->length > 256)
- {
- conn->TempMsg->length -= 256;
- conn->DontSaveRestartData = FALSE;
- }
- else
- conn->DontSaveRestartData = TRUE;
- }
- return;
- }
-}
-
-VOID SendCompressed(CIRCUIT * conn, struct MsgInfo * FwdMsg)
-{
- struct tm * tm;
- char * MsgBytes, * Save;
- UCHAR * Compressed, * Compressedptr;
- UCHAR * UnCompressed;
- char * Title;
- UCHAR * Output, * Outputptr;
- int i, OrigLen, MsgLen, CompLen, DataOffset;
- char Rline[80];
- int RLineLen;
- int Index;
- time_t temp;
-
- if (FwdMsg->type == 'P')
- Index = PMSG;
- else if (FwdMsg->type == 'B')
- Index = BMSG;
- else if (FwdMsg->type == 'T')
- Index = TMSG;
-
- MsgBytes = Save = ReadMessageFile(FwdMsg->number);
-
- if (MsgBytes == 0)
- {
- MsgBytes = _strdup("Message file not found\r\n");
- FwdMsg->length = (int)strlen(MsgBytes);
- }
-
- OrigLen = FwdMsg->length;
-
- Title = FwdMsg->title;
-
- Compressed = Compressedptr = zalloc(2 * OrigLen + 200);
- Output = Outputptr = zalloc(2 * OrigLen + 200);
-
- *Outputptr++ = 1;
- *Outputptr++ = (int)strlen(Title) + 8;
- strcpy(Outputptr, Title);
- Outputptr += strlen(Title) +1;
- sprintf(Outputptr, "%6d", conn->RestartFrom);
- Outputptr += 7;
-
- DataOffset = (int)(Outputptr - Output); // Used if restarting
-
- memcpy(&temp, &FwdMsg->datereceived, sizeof(time_t));
- tm = gmtime(&temp);
-
- sprintf(Rline, "R:%02d%02d%02d/%02d%02dZ %d@%s.%s %s\r\n",
- tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,
- FwdMsg->number, BBSName, HRoute, RlineVer);
-
- if (memcmp(MsgBytes, "R:", 2) != 0) // No R line, so must be our message
- strcat(Rline, "\r\n");
-
- RLineLen = (int)strlen(Rline);
-
- MsgLen = OrigLen + RLineLen;
-
- UnCompressed = zalloc(MsgLen+10);
-
- strcpy(UnCompressed, Rline);
-
- // If a B2 Message, Remove B2 Header
-
- if (FwdMsg->B2Flags & B2Msg)
- {
- char * ptr;
- int BodyLen = OrigLen;
-
- // Remove all B2 Headers, and all but the first part.
-
- ptr = strstr(MsgBytes, "Body:");
-
- if (ptr)
- {
- BodyLen = atoi(&ptr[5]);
- ptr= strstr(MsgBytes, "\r\n\r\n"); // Blank Line after headers
-
- if (ptr)
- ptr +=4;
- else
- ptr = MsgBytes;
-
- }
- else
- ptr = MsgBytes;
-
- if (memcmp(ptr, "R:", 2) == 0) // Already have RLines, so remove blank line after new R:line
- RLineLen -= 2;
-
- memcpy(&UnCompressed[RLineLen], ptr, BodyLen);
-
- MsgLen = BodyLen + RLineLen;
- }
- else // Not B2 Message
- {
- memcpy(&UnCompressed[RLineLen], MsgBytes, OrigLen);
- }
-
- CompLen = Encode(UnCompressed, Compressed, MsgLen, conn->BBSFlags & FBBB1Mode, conn->BBSFlags & FBBCompressed);
-
- conn->FBBChecksum = 0;
-
- // If restarting, send the checksum and length as a single record, then data from the restart point
- // The count includes the header, so adjust count and pointers
-
- if (conn->RestartFrom)
- {
- *Outputptr++ = 2;
- *Outputptr++ = 6;
-
- for (i=0; i< 6; i++)
- {
- conn->FBBChecksum+=Compressed[i];
- *Outputptr++ = Compressed[i];
- }
-
- for (i=conn->RestartFrom; i< CompLen; i++)
- {
- conn->FBBChecksum+=Compressed[i];
- }
-
- Compressedptr += conn->RestartFrom;
- CompLen -= conn->RestartFrom;
- }
- else
- {
- for (i=0; i< CompLen; i++)
- {
- conn->FBBChecksum+=Compressed[i];
- }
- }
-
- while (CompLen > 250)
- {
- *Outputptr++ = 2;
- *Outputptr++ = 250;
-
- memcpy(Outputptr, Compressedptr, 250);
- Outputptr += 250;
- Compressedptr += 250;
- CompLen -= 250;
- }
-
- *Outputptr++ = 2;
- *Outputptr++ = CompLen;
-
- memcpy(Outputptr, Compressedptr, CompLen);
-
- Outputptr += CompLen;
-
- *Outputptr++ = 4;
- conn->FBBChecksum = - conn->FBBChecksum;
- *Outputptr++ = conn->FBBChecksum;
-
- if (conn->OpenBCM) // Telnet, so escape any 0xFF
- {
- unsigned char * ptr1 = Output;
- unsigned char * ptr2 = Compressed; // Reuse Compressed buffer
- size_t Len = Outputptr - Output;
- unsigned char c;
-
- while (Len--)
- {
- c = *(ptr1++);
- *(ptr2++) = c;
- if (c == 0xff) // FF becodes FFFF
- *(ptr2++) = c;
- }
-
- QueueMsg(conn, Compressed, (int)(ptr2 - Compressed));
- }
- else
- QueueMsg(conn, Output, (int)(Outputptr - Output));
-
- free(Save);
- free(Compressed);
- free(UnCompressed);
- free(Output);
-
-}
-
-BOOL CreateB2Message(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader, char * Rline)
-{
- char * MsgBytes;
- UCHAR * Compressed;
- UCHAR * UnCompressed;
- int OrigLen, MsgLen, B2HddrLen, CompLen;
- char Date[20];
- struct tm * tm;
- char B2From[80];
- char B2To[80];
- struct MsgInfo * Msg = FBBHeader->FwdMsg;
- struct UserInfo * FromUser;
- int BodyLineToBody;
- int RlineLen = (int)strlen(Rline) ;
- char * TypeString;
-#ifndef LINBPQ
- struct _EXCEPTION_POINTERS exinfo;
-
- __try {
-#endif
-
- if (Msg == NULL)
- Debugprintf("Msg = NULL");
-
-
- MsgBytes = ReadMessageFile(Msg->number);
-
- if (MsgBytes == 0)
- {
- Debugprintf("B2 Message - Message File not found");
- return FALSE;
- }
-
- UnCompressed = zalloc(Msg->length + 2000);
-
- if (UnCompressed == NULL)
- Debugprintf("B2 Message - zalloc for %d failed", Msg->length + 2000);
-
- OrigLen = Msg->length;
-
- // If a B2 Message add R:line at start of Body, but otherwise leave intact.
- // Unless a message to Paclink, when we must remove any HA from the TO address
- // Or to a CMS, when we remove HA from From or Reply-to
-
- if (Msg->B2Flags & B2Msg)
- {
- char * ptr, *ptr2;
- int BodyLen;
- int BodyLineLen;
- int Index;
-
- MsgLen = OrigLen + RlineLen;
-
- if (conn->Paclink)
- {
- // Remove any HA on the TO address
-
- ptr = strstr(MsgBytes, "To:");
- if (ptr)
- {
- ptr2 = strstr(ptr, "\r\n");
- if (ptr2)
- {
- while (ptr < ptr2)
- {
- if (*ptr == '.' || *ptr == '@')
- {
- memset(ptr, ' ', ptr2 - ptr);
- break;
- }
- ptr++;
- }
- }
- }
- }
-
- if (conn->WL2K)
- {
- // Remove any HA on the From or Reply-To address
-
- ptr = strstr(MsgBytes, "From:");
- if (ptr == NULL)
- ptr = strstr(MsgBytes, "Reply-To:");
-
- if (ptr)
- {
- ptr2 = strstr(ptr, "\r\n");
- if (ptr2)
- {
- while (ptr < ptr2)
- {
- if (*ptr == '.' || *ptr == '@')
- {
- memset(ptr, ' ', ptr2 - ptr);
- break;
- }
- ptr++;
- }
- }
- }
- }
-
-
- // Add R: Line at start of body. Will Need to Update Body Length
-
- ptr = strstr(MsgBytes, "Body:");
-
- if (ptr == 0)
- {
- Debugprintf("B2 Messages without Body: Line");
- return FALSE;
- }
- ptr2 = strstr(ptr, "\r\n");
-
- Index = (int)(ptr - MsgBytes); // Bytes Before Body: line
-
- if (Index <= 0 || Index > MsgLen)
- {
- Debugprintf("B2 Message Body: line position invalid - %d", Index);
- return FALSE;
- }
-
- // If message to saildocs adding an R: line will mess up the message processing, so add as an X header
-
- if (strstr(MsgBytes, "To: query@saildocs.com"))
- {
- int x_Len;
-
- memcpy(UnCompressed, MsgBytes, Index); // Up to Old Body;
- x_Len = sprintf(&UnCompressed[Index], "x-R: %s", &Rline[2]);
- MsgLen = OrigLen + x_Len;
- Index +=x_Len;
- goto copyRest;
- }
-
- BodyLen = atoi(&ptr[5]);
-
- if (BodyLen < 0 || BodyLen > MsgLen)
- {
- Debugprintf("B2 Message Length from Body: line invalid - Msg len %d From Body %d", MsgLen, BodyLen);
- return FALSE;
- }
-
- BodyLineLen = (int)(ptr2 - ptr) + 2;
- MsgLen -= BodyLineLen; // Length of Body Line may change
-
- ptr = strstr(ptr2, "\r\n\r\n"); // Blank line before Body
-
- if (ptr == 0)
- {
- Debugprintf("B2 Message - No Blank Line before Body");
- return FALSE;
- }
-
- ptr += 4;
-
- ptr2 += 2; // Line Following Original Body: Line
-
- BodyLineToBody = (int)(ptr - ptr2);
-
- if (memcmp(ptr, "R:", 2) != 0) // No R line, so must be our message
- {
- strcat(Rline, "\r\n");
- RlineLen += 2;
- MsgLen += 2;
- }
- BodyLen += RlineLen;
-
- memcpy(UnCompressed, MsgBytes, Index); // Up to Old Body;
- BodyLineLen = sprintf(&UnCompressed[Index], "Body: %d\r\n", BodyLen);
-
- MsgLen += BodyLineLen; // Length of Body Line may have changed
- Index += BodyLineLen;
-
- if (BodyLineToBody < 0 || BodyLineToBody > 1000)
- {
- Debugprintf("B2 Message - Body too far from Body Line - %d", BodyLineToBody);
- return FALSE;
- }
- memcpy(&UnCompressed[Index], ptr2, BodyLineToBody); // Stuff Between Body: Line and Body
-
- Index += BodyLineToBody;
-
- memcpy(&UnCompressed[Index], Rline, RlineLen);
- Index += RlineLen;
-
-copyRest:
-
- memcpy(&UnCompressed[Index], ptr, MsgLen - Index); // Rest of Message
-
- FBBHeader->Size = MsgLen;
-
- Compressed = zalloc(2 * MsgLen + 200);
-#ifndef LINBPQ
- __try {
-#endif
- CompLen = Encode(UnCompressed, Compressed, MsgLen, TRUE, conn->BBSFlags & FBBCompressed);
-
- FBBHeader->CompressedMsg = Compressed;
- FBBHeader->CSize = CompLen;
-
- free(UnCompressed);
- return TRUE;
-#ifndef LINBPQ
- } My__except_Routine("Encode B2Message");
-#endif
- return FALSE;
- }
-
-
- if (memcmp(MsgBytes, "R:", 2) != 0) // No R line, so must be our message
- {
- strcat(Rline, "\r\n");
- RlineLen += 2;
- }
-
- MsgLen = OrigLen + RlineLen;
-
-// if (conn->RestartFrom == 0)
-// {
-// // save time first sent, or checksum will be wrong when we restart
-//
-// FwdMsg->datechanged=time(NULL);
-// }
-
- tm = gmtime((time_t *)&Msg->datechanged);
-
- sprintf(Date, "%04d/%02d/%02d %02d:%02d",
- tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
-
- // We create the B2 Header
-/*
- MID: XR88I1J160EB
- Date: 2009/07/25 18:17
- Type: Private
- From: SMTP:john.wiseman@ntlworld.com
- To: G8BPQ
- Subject: RE: RMS Test Message
- Mbo: SMTP
- Body: 213
-
-*/
- if (strcmp(Msg->to, "RMS") == 0) // Address is in via
- strcpy(B2To, Msg->via);
- else
- if (Msg->via[0] && (!conn->Paclink))
- sprintf(B2To, "%s@%s", Msg->to, Msg->via);
- else
- strcpy(B2To, Msg->to);
-
- // Try to create a full from: addrsss so RMS Express can reply
-
- strcpy(B2From, Msg->from);
-
- Logprintf(LOG_BBS, conn, '?', "B2 From %s", B2From);
-
- if (strcmp(conn->Callsign, "RMS") != 0 && conn->WL2K == 0) // if going to RMS - just send calll
- {
- if (_stricmp(Msg->from, "SMTP:") == 0) // Address is in via
- strcpy(B2From, Msg->emailfrom);
- else
- {
- FromUser = LookupCall(Msg->from);
-
- if (FromUser)
- {
- Logprintf(LOG_BBS, conn, '?', "B2 From - Local User");
-
- 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);
-
- Logprintf(LOG_BBS, conn, '?', "B2 From - not local User");
-
- if (WP)
- sprintf(B2From, "%s@%s", Msg->from, WP->first_homebbs);
- }
- }
- }
-
- Logprintf(LOG_BBS, conn, '?', "B2 From Finally %s", B2From);
-
- if (Msg->type == 'P')
- TypeString = "Private" ;
- else if (Msg->type == 'B')
- TypeString = "Bulletin";
- else if (Msg->type == 'T')
- TypeString = "Traffic";
-
- B2HddrLen = sprintf(UnCompressed,
- "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nMbo: %s\r\n"
- "Content-Type: text/plain\r\nContent-Transfer-Encoding: 8bit\r\nBody: %d\r\n\r\n",
- Msg->bid, Date, TypeString, B2From, B2To, Msg->title, BBSName, MsgLen);
-
-
- memcpy(&UnCompressed[B2HddrLen], Rline, RlineLen);
- memcpy(&UnCompressed[B2HddrLen + RlineLen], MsgBytes, OrigLen); // Rest of Message
-
- MsgLen += B2HddrLen;
-
- FBBHeader->Size = MsgLen;
-
- Compressed = zalloc(2 * MsgLen + 200);
-
- CompLen = Encode(UnCompressed, Compressed, MsgLen, TRUE, conn->BBSFlags & FBBCompressed);
-
- FBBHeader->CompressedMsg = Compressed;
- FBBHeader->CSize = CompLen;
-
- free(UnCompressed);
-
- return TRUE;
-#ifndef LINBPQ
- } My__except_Routine("CreateB2Message");
-#endif
- return FALSE;
-
-}
-
-VOID SendCompressedB2(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader)
-{
- UCHAR * Compressed, * Compressedptr;
- UCHAR * Output, * Outputptr;
- int i, CompLen;
- int Index;
-
- if (FBBHeader->FwdMsg->type == 'P')
- Index = PMSG;
- else if (FBBHeader->FwdMsg->type == 'B')
- Index = BMSG;
- else if (FBBHeader->FwdMsg->type == 'T')
- Index = TMSG;
-
- Compressed = Compressedptr = FBBHeader->CompressedMsg;
-
- Output = Outputptr = zalloc(FBBHeader->CSize + 10000);
-
- *Outputptr++ = 1;
- *Outputptr++ = (int)strlen(FBBHeader->FwdMsg->title) + 8;
- strcpy(Outputptr, FBBHeader->FwdMsg->title);
- Outputptr += strlen(FBBHeader->FwdMsg->title) +1;
- sprintf(Outputptr, "%06d", conn->RestartFrom);
- Outputptr += 7;
-
- CompLen = FBBHeader->CSize;
-
- conn->FBBChecksum = 0;
-
- // If restarting, send the checksum and length as a single record, then data from the restart point
- // The count includes the header, so adjust count and pointers
-
- if (conn->RestartFrom)
- {
- *Outputptr++ = 2;
- *Outputptr++ = 6;
-
- for (i=0; i< 6; i++)
- {
- conn->FBBChecksum+=Compressed[i];
- *Outputptr++ = Compressed[i];
- }
-
- for (i=conn->RestartFrom; i< CompLen; i++)
- {
- conn->FBBChecksum+=Compressed[i];
- }
-
- Compressedptr += conn->RestartFrom;
- CompLen -= conn->RestartFrom;
- }
- else
- {
- for (i=0; i< CompLen; i++)
- {
- conn->FBBChecksum+=Compressed[i];
- }
- conn->UserPointer->Total.MsgsSent[Index]++;
- conn->UserPointer->Total.BytesForwardedOut[Index] += FBBHeader->FwdMsg->length;
-
- }
-
- while (CompLen > 256)
- {
- *Outputptr++ = 2;
- *Outputptr++ = 0;
-
- memcpy(Outputptr, Compressedptr, 256);
- Outputptr += 256;
- Compressedptr += 256;
- CompLen -= 256;
- }
-
- *Outputptr++ = 2;
- *Outputptr++ = CompLen;
-
- memcpy(Outputptr, Compressedptr, CompLen);
-
- Outputptr += CompLen;
-
- *Outputptr++ = 4;
- conn->FBBChecksum = - conn->FBBChecksum;
- *Outputptr++ = conn->FBBChecksum;
-
- if (conn->OpenBCM) // Telnet, so escape any 0xFF
- {
- unsigned char * ptr1 = Output;
- unsigned char * ptr2 = Compressed; // Reuse Compressed buffer
- int Len = (int)(Outputptr - Output);
- unsigned char c;
-
- while (Len--)
- {
- c = *(ptr1++);
- *(ptr2++) = c;
- if (c == 0xff) // FF becodes FFFF
- *(ptr2++) = c;
- }
-
- QueueMsg(conn, Compressed, (int)(ptr2 - Compressed));
- }
- else
- QueueMsg(conn, Output, (int)(Outputptr - Output));
-
- free(Compressed);
- free(Output);
-}
-
-// Restart Routines.
-
-VOID SaveFBBBinary(CIRCUIT * conn)
-{
- // Disconnected during binary transfer
-
- char Msg[120];
- int i, len;
- struct FBBRestartData * RestartRec = NULL;
-
- if (conn->TempMsg == NULL)
- return;
-
- if (conn->TempMsg->length < 256)
- return; // Not worth it.
-
- // If we already have a restart record, reuse it
-
- for (i = 1; i <= RestartCount; i++)
- {
- RestartRec = RestartData[i];
-
- if ((strcmp(RestartRec->Call, conn->UserPointer->Call) == 0)
- && (strcmp(RestartRec->bid, conn->TempMsg->bid) == 0))
- {
- // Found it, so reuse
-
- // If we have more data, reset retry count
-
- if (RestartRec->length < conn->TempMsg->length)
- RestartRec->Count = 0;;
-
- break;
- }
- }
-
- if (RestartRec == NULL)
- {
- RestartRec = zalloc(sizeof (struct FBBRestartData));
-
- GetSemaphore(&AllocSemaphore, 0);
-
- RestartData=realloc(RestartData,(++RestartCount+1) * sizeof(void *));
- RestartData[RestartCount] = RestartRec;
-
- FreeSemaphore(&AllocSemaphore);
- RestartRec->TimeCreated = time(NULL);
- }
-
- strcpy(RestartRec->Call, conn->UserPointer->Call);
- RestartRec->length = conn->TempMsg->length;
- strcpy(RestartRec->bid, conn->TempMsg->bid);
- RestartRec->MailBuffer = conn->MailBuffer;
- RestartRec->MailBufferSize = conn->MailBufferSize;
-
- len = sprintf_s(Msg, sizeof(Msg), "Disconnect received from %s during Binary Transfer - %d Bytes Saved for restart",
- conn->Callsign, conn->TempMsg->length);
-
- SaveRestartData();
-
- WriteLogLine(conn, '|',Msg, len, LOG_BBS);
-}
-
-void DeleteRestartData(CIRCUIT * conn)
-{
- struct FBBRestartData * RestartRec = NULL;
- int i, n;
-
- if (conn->TempMsg == NULL)
- return;
-
- for (i = 1; i <= RestartCount; i++)
- {
- RestartRec = RestartData[i];
-
- if ((strcmp(RestartRec->Call, conn->UserPointer->Call) == 0)
- && (strcmp(RestartRec->bid, conn->TempMsg->bid) == 0))
- {
- // Remove restrt data
-
- for (n = i; n < RestartCount; n++)
- {
- RestartData[n] = RestartData[n+1]; // move down all following entries
- }
-
- RestartCount--;
- SaveRestartData();
- return;
- }
- }
-}
-
-
-BOOL LookupRestart(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader)
-{
- int i, n;
-
- struct FBBRestartData * RestartRec;
-
- if ((conn->BBSFlags & FBBB1Mode) == 0)
- return FALSE; // Only B1 & B2 support restart
-
- for (i = 1; i <= RestartCount; i++)
- {
- RestartRec = RestartData[i];
-
- if ((strcmp(RestartRec->Call, conn->UserPointer->Call) == 0)
- && (strcmp(RestartRec->bid, FBBHeader->BID) == 0))
- {
- char Msg[120];
- int len;
-
- RestartRec->Count++;
-
- if (RestartRec->Count > 10)
- {
- len = sprintf_s(Msg, sizeof(Msg), "Too many restarts for %s - Requesting restart from beginning",
- FBBHeader->BID);
-
- WriteLogLine(conn, '|',Msg, len, LOG_BBS);
-
- // Remove restrt data
-
- for (n = i; n < RestartCount; n++)
- {
- RestartData[n] = RestartData[n+1]; // move down all following entries
- }
-
- RestartCount--;
- SaveRestartData();
- return FALSE;
- }
-
- len = sprintf_s(Msg, sizeof(Msg), "Restart Data found for %s - Requesting restart from %d",
- FBBHeader->BID, RestartRec->length);
-
- WriteLogLine(conn, '|',Msg, len, LOG_BBS);
-
- return (RestartRec->length);
- }
- }
-
- return FALSE; // Not Found
-}
-
-
-
-BOOL DoWeWantIt(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader)
-{
- struct MsgInfo * Msg;
- BIDRec * BID;
- int m;
-
- if (RefuseBulls && FBBHeader->MsgType == 'B')
- {
- Logprintf(LOG_BBS, conn, '?', "Message Rejected by RefuseBulls");
- return FALSE;
- }
- if (FBBHeader->Size > MaxRXSize)
- {
- Logprintf(LOG_BBS, conn, '?', "Message Rejected by Size Check");
- return FALSE;
- }
-
- BID = LookupBID(FBBHeader->BID);
-
- if (BID)
- {
- if (FBBHeader->MsgType == 'B')
- {
- Logprintf(LOG_BBS, conn, '?', "Message Rejected by BID Check");
- return FALSE;
- }
-
- // Treat P messages to SYSOP@WW as Bulls
-
- if (strcmp(FBBHeader->To, "SYSOP") == 0 && strcmp(FBBHeader->ATBBS, "WW") == 0)
- {
- Logprintf(LOG_BBS, conn, '?', "Message Rejected by BID Check");
- return FALSE;
- }
-
- m = NumberofMessages;
-
- while (m > 0)
- {
- Msg = MsgHddrPtr[m];
-
- if (Msg->number == BID->u.msgno)
- {
- // if the same TO we will assume the same message
-
- if (strcmp(Msg->to, FBBHeader->To) == 0)
- {
- // We have this message. If we have already forwarded it, we should accept it again
-
- if ((Msg->status == 'N') || (Msg->status == 'Y')|| (Msg->status == 'H'))
- {
- Logprintf(LOG_BBS, conn, '?', "Message Rejected by BID Check");
- return FALSE; // Dont want it
- }
- else
- return TRUE; // Get it again
- }
-
- // Same number. but different message (why?) Accept for now
-
- return TRUE;
- }
-
- m--;
- }
-
- return TRUE; // A personal Message we have had before, but don't still have.
- }
- else
- {
- // We don't know the BID
-
- return TRUE; // We want it
- }
-}
-
-
-
-
+/*
+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
+//
+// FBB Forwarding Routines
+
+#include "bpqmail.h"
+
+#define GetSemaphore(Semaphore,ID) _GetSemaphore(Semaphore, ID, __FILE__, __LINE__)
+void _GetSemaphore(struct SEM * Semaphore, int ID, char * File, int Line);
+
+
+void DeleteRestartData(CIRCUIT * conn);
+
+int32_t Encode(char * in, char * out, int32_t inlen, BOOL B1Protocol, int Compress);
+void MQTTMessageEvent(void* message);
+
+int MaxRXSize = 99999;
+int MaxTXSize = 99999;
+
+struct FBBRestartData ** RestartData = NULL;
+int RestartCount = 0;
+
+struct B2RestartData ** B2RestartRecs = NULL;
+int B2RestartCount = 0;
+
+extern char ProperBaseDir[];
+
+char RestartDir[MAX_PATH] = "";
+
+void GetRestartData()
+{
+ int i;
+ struct FBBRestartData Restart;
+ struct FBBRestartData * RestartRec;
+ char MsgFile[MAX_PATH];
+ FILE * hFile;
+ int FileSize;
+ struct stat STAT;
+ size_t ReadLen = 0;
+ time_t Age;
+
+ strcpy(RestartDir, MailDir);
+ strcat(RestartDir, "/Restart");
+
+ // Make sure RestartDir exists
+
+#ifdef WIN32
+ CreateDirectory(RestartDir, NULL); // Just in case
+#else
+ mkdir(RestartDir, S_IRWXU | S_IRWXG | S_IRWXO);
+ chmod(RestartDir, S_IRWXU | S_IRWXG | S_IRWXO);
+#endif
+
+ // look for restart files. These will be numbered from 1 up
+
+ for (i = 1; 1; i++)
+ {
+ sprintf_s(MsgFile, sizeof(MsgFile), "%s/%d", RestartDir, i);
+
+ if (stat(MsgFile, &STAT) == -1)
+ break;
+
+ FileSize = STAT.st_size;
+
+ Age = time(NULL) - STAT.st_ctime;
+
+ if (Age > 86400 * 2) // Max 2 days
+ continue;
+
+ hFile = fopen(MsgFile, "rb");
+
+ if (hFile == NULL)
+ break;
+
+ // Read Restart Record
+
+ fread(&Restart, 1, sizeof(struct FBBRestartData), hFile);
+
+ if ((Restart.MailBufferSize + sizeof(struct FBBRestartData)) != FileSize) // Duff file
+ {
+ fclose(hFile);
+ break;
+ }
+
+ RestartRec = zalloc(sizeof (struct FBBRestartData));
+
+ GetSemaphore(&AllocSemaphore, 0);
+
+ RestartData = realloc(RestartData,(++RestartCount+1) * sizeof(void *));
+ RestartData[RestartCount] = RestartRec;
+
+ FreeSemaphore(&AllocSemaphore);
+
+ memcpy(RestartRec, &Restart, sizeof(struct FBBRestartData));
+ RestartRec->MailBuffer = malloc(RestartRec->MailBufferSize);
+ ReadLen = fread(RestartRec->MailBuffer, 1, RestartRec->MailBufferSize, hFile);
+
+ Logprintf(LOG_BBS, 0, '?', "Restart Data for %s %s Len %d Loaded", RestartRec->Call, RestartRec->bid, RestartRec->length);
+ fclose(hFile);
+ }
+}
+
+
+void SaveRestartData()
+{
+ // Save restart data to file so we can reload on restart
+ // Restart data has pointers to buffers so we must save copy of data and reconstitue on restart
+
+ // Delete and resave all restart data to keep restart directory clean
+
+ int i, n = 1;
+ char MsgFile[MAX_PATH];
+ FILE * hFile;
+ size_t WriteLen=0;
+ struct FBBRestartData * RestartRec = NULL;
+ struct stat STAT;
+ time_t NOW = time(NULL);
+
+
+ for (i = 1; 1; i++)
+ {
+ sprintf_s(MsgFile, sizeof(MsgFile), "%s/%d", RestartDir, i);
+
+ if (stat(MsgFile, &STAT) == -1)
+ break;
+
+ DeleteFile(MsgFile);
+ }
+
+ for (i = 1; i <= RestartCount; i++)
+ {
+ RestartRec = RestartData[i];
+
+ if (RestartRec == 0)
+ return; // Shouldn't happen!
+
+ if ((NOW - RestartRec->TimeCreated) > 86400 * 2) // Max 2 days
+ continue;
+
+ sprintf_s(MsgFile, sizeof(MsgFile), "%s/%d", RestartDir, n++);
+
+ hFile = fopen(MsgFile, "wb");
+
+ if (hFile)
+ {
+ WriteLen = fwrite(RestartRec, 1, sizeof(struct FBBRestartData), hFile); // Save Header
+ WriteLen = fwrite(RestartRec->MailBuffer, 1, RestartRec->MailBufferSize, hFile); // Save Data
+ fclose(hFile);
+ }
+ }
+}
+VOID FBBputs(CIRCUIT * conn, char * buf)
+{
+ // Sends to user and logs
+
+ int len = (int)strlen(buf);
+
+ WriteLogLine(conn, '>', buf, len -1, LOG_BBS);
+
+ QueueMsg(conn, buf, len);
+
+ if (conn->BBSFlags & NEEDLF)
+ QueueMsg(conn, "\n", 1);
+}
+
+
+VOID ProcessFBBLine(CIRCUIT * conn, struct UserInfo * user, UCHAR* Buffer, int len)
+{
+ struct FBBHeaderLine * FBBHeader; // The Headers from an FBB forward block
+ int i;
+ int Index = 0; // Message Type Index for Stats
+ char * ptr;
+ char * Context;
+ char seps[] = " \r";
+ int RestartPtr;
+ char * Respptr;
+ BOOL AllRejected = TRUE;
+ char * MPS;
+ char * ROChar;
+
+ if (conn->Flags & GETTINGMESSAGE)
+ {
+ ProcessMsgLine(conn, user, Buffer, len);
+ if (conn->Flags & GETTINGMESSAGE)
+
+ // Still going
+ return;
+
+ SetupNextFBBMessage(conn);
+ return;
+ }
+
+ if (conn->Flags & GETTINGTITLE)
+ {
+ ProcessMsgTitle(conn, user, Buffer, len);
+ return;
+ }
+
+ // Should be FA FB F> FS FF FQ
+
+ if (Buffer[0] == ';') // winlink comment or BPQ Type Select
+ {
+ if (memcmp(Buffer, "; MSGTYPES", 7) == 0)
+ {
+ char * ptr;
+
+ conn->SendB = conn->SendP = conn->SendT = FALSE;
+
+ ptr = strchr(&Buffer[10], 'B');
+
+ if (ptr)
+ {
+ conn->SendB = TRUE;
+ conn->MaxBLen = atoi(++ptr);
+ if (conn->MaxBLen == 0) conn->MaxBLen = 99999999;
+ }
+
+ ptr = strchr(&Buffer[10], 'T');
+
+ if (ptr)
+ {
+ conn->SendT = TRUE;
+ conn->MaxTLen = atoi(++ptr);
+ if (conn->MaxTLen == 0) conn->MaxTLen = 99999999;
+ }
+ ptr = strchr(&Buffer[10], 'P');
+
+ if (ptr)
+ {
+ conn->SendP = TRUE;
+ conn->MaxPLen = atoi(++ptr);
+ if (conn->MaxPLen == 0) conn->MaxPLen = 99999999;
+ }
+ return;
+ }
+
+ // Other ; Line - Ignore
+
+ return;
+ }
+
+ if (Buffer[0] != 'F')
+ {
+ if (strstr(Buffer, "*** Profanity detected") || strstr(Buffer, "*** Unknown message sender"))
+ {
+ // Winlink Check - hold message
+
+ if (conn->FBBMsgsSent)
+ HoldSentMessages(conn, user);
+ }
+
+ if (conn->BBSFlags & DISCONNECTING)
+ return; // Ignore if disconnect aleady started
+
+ BBSputs(conn, "*** Protocol Error - Line should start with 'F'\r");
+ Flush(conn);
+ Sleep(500);
+ conn->BBSFlags |= DISCONNECTING;
+ Disconnect(conn->BPQStream);
+
+ return;
+ }
+
+ switch (Buffer[1])
+ {
+ case 'F':
+
+ // Request Reverse
+
+ if (conn->FBBMsgsSent)
+ FlagSentMessages(conn, user);
+
+ if (!FBBDoForward(conn)) // Send proposal if anthing to forward
+ {
+ FBBputs(conn, "FQ\r");
+
+ conn->BBSFlags |= DISCONNECTING;
+
+ // LinFBB needs a Disconnect Here
+
+ if (conn->BPQBBS)
+ return; // BPQ will close when it sees FQ. Close collisions aren't good!
+
+ if ((conn->SessType & Sess_PACTOR) == 0)
+ conn->CloseAfterFlush = 20; // 2 Secs
+ else
+ conn->CloseAfterFlush = 20; // PACTOR/WINMOR drivers support deferred disc so 5 secs should be enough
+ }
+ return;
+
+ case 'S':
+
+ // Proposal response
+
+ Respptr=&Buffer[2];
+
+ for (i=0; i < conn->FBBIndex; i++)
+ {
+ FBBHeader = &conn->FBBHeaders[i];
+
+ if (FBBHeader->MsgType == 'P')
+ Index = PMSG;
+ else if (FBBHeader->MsgType == 'B')
+ Index = BMSG;
+ else if (FBBHeader->MsgType == 'T')
+ Index = TMSG;
+
+ Respptr++;
+
+ if (*Respptr == 'E')
+ {
+ // Rejected
+
+ Logprintf(LOG_BBS, conn, '?', "Proposal %d Rejected by far end", i + 1);
+ }
+
+ if ((*Respptr == '-') || (*Respptr == 'N') || (*Respptr == 'R') || (*Respptr == 'E')) // Not wanted
+ {
+ user->Total.MsgsRejectedOut[Index]++;
+
+ // Zap the entry
+
+ if (conn->Paclink || conn->RMSExpress || conn->PAT) // Not using Bit Masks
+ {
+ // Kill Messages sent to paclink/RMS Express unless BBS FWD bit set
+
+ // What if WLE retrieves P message that is queued to differnet BBS?
+ // if we dont kill it will be offered again
+
+ if (FBBHeader->FwdMsg->type == 'P' || (check_fwd_bit(FBBHeader->FwdMsg->fbbs, user->BBSNumber) == 0))
+ FlagAsKilled(FBBHeader->FwdMsg, FALSE);
+ }
+
+ clear_fwd_bit(FBBHeader->FwdMsg->fbbs, user->BBSNumber);
+ set_fwd_bit(FBBHeader->FwdMsg->forw, user->BBSNumber);
+
+ FBBHeader->FwdMsg->Locked = 0; // Unlock
+
+ // Shouldn't we set P messages as Forwarded
+ // (or will check above have killed it if it is P with other FWD bits set)
+ // Maybe better to be safe !!
+
+ if (FBBHeader->FwdMsg->type == 'P' || memcmp(FBBHeader->FwdMsg->fbbs, zeros, NBMASK) == 0)
+ {
+ FBBHeader->FwdMsg->status = 'F'; // Mark as forwarded
+ FBBHeader->FwdMsg->datechanged=time(NULL);
+ }
+
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine));
+
+ conn->UserPointer->ForwardingInfo->MsgCount--;
+
+ SaveMessageDatabase();
+ continue;
+ }
+
+ // FBB uses H for HOLD, but I've never seen it. RMS Express sends H for Defer.
+
+
+ if (*Respptr == '=' || *Respptr == 'L' || (*Respptr == 'H' && conn->RMSExpress)) // Defer
+ {
+ // Remove entry from forwarding block
+
+ FBBHeader->FwdMsg->Defered = 4; // Don't retry for the next few forward cycles
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine));
+ continue;
+ }
+
+ conn->RestartFrom = 0; // Assume Restart from
+
+ if ((*Respptr == '!') || (*Respptr == 'A'))
+ {
+ // Restart
+
+ char Num[10];
+ char *numptr=&Num[0];
+
+ Respptr++;
+
+ while (isdigit(*Respptr))
+ {
+ *(numptr++) = *(Respptr++);
+ }
+ *numptr = 0;
+
+ conn->RestartFrom = atoi(Num);
+
+ *(--Respptr) = '+'; // So can drop through
+ }
+
+ // FBB uses H for HOLD, but I've never seen it. RMS Express sends H for Defer. RMS use trapped above
+
+ if ((*Respptr == '+') || (*Respptr == 'Y') || (*Respptr == 'H'))
+ {
+ struct tm * tm;
+ time_t now;
+ char * MsgBytes;
+
+ conn->FBBMsgsSent = TRUE; // Messages to flag as complete when next command received
+ AllRejected = FALSE;
+
+ if (conn->BBSFlags & FBBForwarding)
+ {
+ if (conn->BBSFlags & FBBB2Mode)
+ SendCompressedB2(conn, FBBHeader);
+ else
+ SendCompressed(conn, FBBHeader->FwdMsg);
+ }
+ else
+ {
+ nodeprintf(conn, "%s\r\n", FBBHeader->FwdMsg->title);
+
+ MsgBytes = ReadMessageFile(FBBHeader->FwdMsg->number);
+
+ if (MsgBytes == 0)
+ {
+ MsgBytes = _strdup("Message file not found\r\n");
+ FBBHeader->FwdMsg->length = (int)strlen(MsgBytes);
+ }
+
+ now = time(NULL);
+
+ tm = gmtime(&now);
+
+ nodeprintf(conn, "R:%02d%02d%02d/%02d%02dZ %d@%s.%s %s\r\n",
+ tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,
+ FBBHeader->FwdMsg->number, BBSName, HRoute, RlineVer);
+
+ if (memcmp(MsgBytes, "R:", 2) != 0) // No R line, so must be our message - put blank line after header
+ BBSputs(conn, "\r\n");
+
+ QueueMsg(conn, MsgBytes, FBBHeader->FwdMsg->length);
+ free(MsgBytes);
+
+ user->Total.MsgsSent[Index]++;
+ user->Total.BytesForwardedOut[Index] += FBBHeader->FwdMsg->length;
+
+ nodeprintf(conn, "%c\r\n", 26);
+ }
+ continue;
+ }
+ BBSputs(conn, "*** Protocol Error - Invalid Proposal Response'\r");
+ }
+
+ conn->FBBIndex = 0; // ready for next block;
+ conn->FBBChecksum = 0;
+
+
+ if (AllRejected && (conn->RMSExpress || conn->PAT))
+ {
+ // RMS Express and PAT don't send FF or proposal after rejecting all messages
+
+ FBBputs(conn, "FF\r");
+ }
+
+ return;
+
+ case 'Q':
+
+ if (conn->FBBMsgsSent)
+ FlagSentMessages(conn, user);
+
+ conn->BBSFlags |= DISCONNECTING;
+
+ Disconnect(conn->BPQStream);
+ return;
+
+ case 'A': // Proposal
+ case 'B': // Proposal
+
+ if (conn->FBBMsgsSent)
+ FlagSentMessages(conn, user); // Mark previously sent messages
+
+ if (conn->DoReverse == FALSE) // Dont accept messages
+ return;
+
+ // Accumulate checksum
+
+ for (i=0; i< len; i++)
+ {
+ conn->FBBChecksum+=Buffer[i];
+ }
+
+ // Parse Header
+
+ // Find free line
+
+ for (i = 0; i < 5; i++)
+ {
+ FBBHeader = &conn->FBBHeaders[i];
+
+ if (FBBHeader->Format == 0)
+ break;
+ }
+
+ if (i == 5)
+ {
+ BBSputs(conn, "*** Protocol Error - Too Many Proposals\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+ }
+
+ //FA P GM8BPQ G8BPQ G8BPQ 2209_GM8BPQ 8
+
+ FBBHeader->Format = Buffer[1];
+
+ ptr = strtok_s(&Buffer[3], seps, &Context);
+
+ if (ptr == NULL) goto badparam;
+
+ if (strlen(ptr) != 1) goto badparam;
+
+ FBBHeader->MsgType = *ptr;
+
+ if (FBBHeader->MsgType == 'P')
+ Index = PMSG;
+ else if (FBBHeader->MsgType == 'B')
+ Index = BMSG;
+ else if (FBBHeader->MsgType == 'T')
+ Index = TMSG;
+
+
+ ptr = strtok_s(NULL, seps, &Context);
+
+ if (ptr == NULL) goto badparam;
+ strlop(ptr, '-'); // Remove any (illegal) ssid
+
+ if (strlen(ptr) > 6 ) goto badparam;
+
+ strcpy(FBBHeader->From, ptr);
+
+ ptr = strtok_s(NULL, seps, &Context);
+
+ if (ptr == NULL) goto badparam;
+
+ if (strlen(ptr) > 40 ) goto badparam;
+
+ strcpy(FBBHeader->ATBBS, ptr);
+
+ ptr = strtok_s(NULL, seps, &Context);
+
+ if (ptr == NULL) goto badparam;
+
+ if (strlen(ptr) > 6)
+ {
+ // Temp fix - reject instead of breaking connection
+
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected as TO field too long");
+
+ user->Total.MsgsRejectedIn[Index]++;
+ return;
+ }
+
+ strlop(ptr, '-'); // Remove any (illegal) ssid
+
+ strcpy(FBBHeader->To, ptr);
+
+ ptr = strtok_s(NULL, seps, &Context);
+
+ if (ptr == NULL) goto badparam;
+
+ if (strlen(ptr) > 12 ) goto badparam;
+
+ strcpy(FBBHeader->BID, ptr);
+
+ ptr = strtok_s(NULL, seps, &Context);
+
+ if (ptr == NULL) goto badparam;
+
+ FBBHeader->Size = atoi(ptr);
+
+ goto ok;
+
+badparam:
+
+ BBSputs(conn, "*** Protocol Error - Proposal format error\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+ return;
+
+ok:
+
+ // Check Filters
+
+ if (CheckRejFilters(FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->BID, FBBHeader->MsgType, FBBHeader->Size))
+ {
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected by Filters");
+
+ user->Total.MsgsRejectedIn[Index]++;
+ }
+
+ // If P Message, dont immediately reject on a Duplicate BID. Check if we still have the message
+ // If we do, reject it. If not, accept it again. (do we need some loop protection ???)
+
+ else if (DoWeWantIt(conn, FBBHeader) == FALSE)
+ {
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
+ user->Total.MsgsRejectedIn[Index]++;
+ }
+ else if ((RestartPtr = LookupRestart(conn, FBBHeader)) > 0)
+ {
+ conn->FBBReplyIndex += sprintf(&conn->FBBReplyChars[conn->FBBReplyIndex], "!%d", RestartPtr);
+ }
+ else if (LookupTempBID(FBBHeader->BID))
+ {
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = '=';
+ }
+ else
+ {
+
+ // Save BID in temp list in case we are offered it again before completion
+
+ BIDRec * TempBID = AllocateTempBIDRecord();
+ strcpy(TempBID->BID, FBBHeader->BID);
+ TempBID->u.conn = conn;
+
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = '+';
+ }
+
+ FBBHeader->B2Message = FALSE;
+
+ return;
+
+ case 'C': // B2 Proposal
+
+ if (conn->FBBMsgsSent)
+ FlagSentMessages(conn, user); // Mark previously sent messages
+
+ if (conn->DoReverse == FALSE) // Dont accept messages
+ return;
+
+ // Accumulate checksum
+
+ for (i=0; i< len; i++)
+ {
+ conn->FBBChecksum+=Buffer[i];
+ }
+
+ // Parse Header
+
+ // Find free line
+
+ for (i = 0; i < 5; i++)
+ {
+ FBBHeader = &conn->FBBHeaders[i];
+
+ if (FBBHeader->Format == 0)
+ break;
+ }
+
+ if (i == 5)
+ {
+ BBSputs(conn, "*** Protocol Error - Too Many Proposals\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+ }
+
+
+ // FC EM A3EDD4P00P55 377 281 0
+
+ /*
+
+ FC Proposal code. Requires B2 SID feature.
+ Type Message type ( 1 or 2 alphanumeric characters
+
+ CM WinLink 2000 Control message
+ EM Encapsulated Message
+ ID Unique Message Identifier (max length 12 characters)
+ U-Size Uncompressed size of message
+ C-size Compressed size of message
+
+ */
+ FBBHeader->Format = Buffer[1];
+
+ ptr = strtok_s(&Buffer[3], seps, &Context);
+ if (ptr == NULL) goto badparam2;
+ if (strlen(ptr) != 2) goto badparam2;
+ FBBHeader->MsgType = 'P'; //ptr[0];
+
+ ptr = strtok_s(NULL, seps, &Context);
+
+ if (ptr == NULL) goto badparam2;
+
+ // Relay In RO mode adds @MPS@R to the MID. Don't know why (yet!)
+
+ MPS = strlop(ptr, '@');
+ if (MPS)
+ ROChar = strlop(MPS, '@');
+
+ if (strlen(ptr) > 12 ) goto badparam;
+ strcpy(FBBHeader->BID, ptr);
+
+ ptr = strtok_s(NULL, seps, &Context);
+ if (ptr == NULL) goto badparam2;
+ FBBHeader->Size = atoi(ptr);
+
+ ptr = strtok_s(NULL, seps, &Context);
+ if (ptr == NULL) goto badparam2;
+ FBBHeader->CSize = atoi(ptr);
+ FBBHeader->B2Message = TRUE;
+
+ // If using BPQ Extensions (From To AT in proposal) Check Filters
+
+ Buffer[len - 1] = 0;
+
+ if (conn->BPQBBS)
+ {
+ char * From = strtok_s(NULL, seps, &Context);
+ char * ATBBS = strtok_s(NULL, seps, &Context);
+ char * To = strtok_s(NULL, seps, &Context);
+ char * Type = strtok_s(NULL, seps, &Context);
+
+ if (From && To && ATBBS && Type && CheckRejFilters(From, To, ATBBS, NULL, *Type, FBBHeader->Size))
+ {
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
+ user->Total.MsgsRejectedIn[Index]++;
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected by Filters");
+
+ return;
+ }
+ }
+ goto ok2;
+
+badparam2:
+
+ BBSputs(conn, "*** Protocol Error - Proposal format error\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+ return;
+
+ok2:
+ if (LookupBID(FBBHeader->BID))
+ {
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected by BID Check");
+ user->Total.MsgsRejectedIn[Index]++;
+
+ }
+ else if (FBBHeader->Size > MaxRXSize)
+ {
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = '-';
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected by Size Limit");
+ user->Total.MsgsRejectedIn[Index]++;
+
+ }
+ else if ((RestartPtr = LookupRestart(conn, FBBHeader)) > 0)
+ {
+ conn->FBBReplyIndex += sprintf(&conn->FBBReplyChars[conn->FBBReplyIndex], "!%d", RestartPtr);
+ }
+
+ else if (LookupTempBID(FBBHeader->BID))
+ {
+ memset(FBBHeader, 0, sizeof(struct FBBHeaderLine)); // Clear header
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = '=';
+ }
+ else
+ {
+ // Save BID in temp list in case we are offered it again before completion
+
+ BIDRec * TempBID = AllocateTempBIDRecord();
+ strcpy(TempBID->BID, FBBHeader->BID);
+ TempBID->u.conn = conn;
+
+ conn->FBBReplyChars[conn->FBBReplyIndex++] = 'Y';
+ }
+
+ return;
+
+ case '>':
+
+ // Optional Checksum
+
+ if (conn->DoReverse == FALSE) // Dont accept messages
+ {
+ Logprintf(LOG_BBS, conn, '?', "Reverse Forwarding not allowed");
+ Disconnect(conn->BPQStream);
+ return;
+ }
+
+ if (len > 3)
+ {
+ int sum;
+
+ sscanf(&Buffer[3], "%x", &sum);
+
+ conn->FBBChecksum+=sum;
+
+ if (conn->FBBChecksum)
+ {
+ BBSputs(conn, "*** Proposal Checksum Error\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+ return;
+ }
+ }
+
+ // Return "FS ", followed by +-= for each proposal
+
+ conn->FBBReplyChars[conn->FBBReplyIndex] = 0;
+ conn->FBBReplyIndex = 0;
+
+ nodeprintfEx(conn, "FS %s\r", conn->FBBReplyChars);
+
+ // if all rejected, send proposals or prompt, else set up for first message
+
+ FBBHeader = &conn->FBBHeaders[0];
+
+ if (FBBHeader->MsgType == 0)
+ {
+ conn->FBBIndex = 0; // ready for first block;
+ memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine));
+ conn->FBBChecksum = 0;
+
+ if (!FBBDoForward(conn)) // Send proposal if anthing to forward
+ {
+ conn->InputMode = 0;
+
+ if (conn->DoReverse)
+ FBBputs(conn, "FF\r");
+ else
+ {
+ FBBputs(conn, "FQ\r");
+ conn->CloseAfterFlush = 20; // 2 Secs
+ }
+ }
+ }
+ else
+ {
+ if (conn->BBSFlags & FBBForwarding)
+ {
+ conn->InputMode = 'B';
+ }
+
+ CreateMessage(conn, FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->MsgType, FBBHeader->BID, NULL);
+ }
+
+ return;
+
+ }
+
+ return;
+}
+
+VOID HoldSentMessages(CIRCUIT * conn, struct UserInfo * user)
+{
+ struct FBBHeaderLine * FBBHeader; // The Headers from an FBB forward block
+ int i;
+
+ conn->FBBMsgsSent = FALSE;
+
+ for (i=0; i < 5; i++)
+ {
+ FBBHeader = &conn->FBBHeaders[i];
+
+ if (FBBHeader && FBBHeader->MsgType) // Not a zapped entry
+ {
+ int Length=0;
+ char * MailBuffer = malloc(100);
+ char Title[100];
+
+ Length += sprintf(MailBuffer, "Message %d Held\r\n", FBBHeader->FwdMsg->number);
+ sprintf(Title, "Message %d Held - Rejected by Winlink", FBBHeader->FwdMsg->number);
+ SendMessageToSYSOP(Title, MailBuffer, Length);
+
+ FBBHeader->FwdMsg->status = 'H'; // Mark as Held
+ }
+ }
+ memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine));
+ SaveMessageDatabase();
+}
+
+
+
+VOID FlagSentMessages(CIRCUIT * conn, struct UserInfo * user)
+{
+ struct FBBHeaderLine * FBBHeader; // The Headers from an FBB forward block
+ int i;
+
+ // Called if FBB command received after sending a block of messages . Flag as as sent.
+
+ conn->FBBMsgsSent = FALSE;
+
+ for (i=0; i < 5; i++)
+ {
+ FBBHeader = &conn->FBBHeaders[i];
+
+ if (FBBHeader && FBBHeader->MsgType) // Not a zapped entry
+ {
+ if ((conn->Paclink || conn->RMSExpress || conn->PAT) &&
+// ((conn->UserPointer->flags & F_NTSMPS) == 0) &&
+ (FBBHeader->FwdMsg->type == 'P'))
+ {
+ // Kill Messages sent to paclink/RMS Express unless BBS FWD bit set
+
+ if (check_fwd_bit(FBBHeader->FwdMsg->fbbs, user->BBSNumber) == 0)
+ {
+ FlagAsKilled(FBBHeader->FwdMsg, FALSE);
+ continue;
+ }
+ }
+
+ clear_fwd_bit(FBBHeader->FwdMsg->fbbs, user->BBSNumber);
+ set_fwd_bit(FBBHeader->FwdMsg->forw, user->BBSNumber);
+
+ // Only mark as forwarded if sent to all BBSs that should have it
+
+ if (memcmp(FBBHeader->FwdMsg->fbbs, zeros, NBMASK) == 0)
+ {
+ FBBHeader->FwdMsg->status = 'F'; // Mark as forwarded
+ FBBHeader->FwdMsg->datechanged=time(NULL);
+ }
+
+#ifndef NOMQTT
+ if (MQTT)
+ MQTTMessageEvent(FBBHeader->FwdMsg);
+#endif
+
+ FBBHeader->FwdMsg->Locked = 0; // Unlock
+ conn->UserPointer->ForwardingInfo->MsgCount--;
+ }
+ }
+ memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine));
+ SaveMessageDatabase();
+}
+
+
+VOID SetupNextFBBMessage(CIRCUIT * conn)
+{
+ struct FBBHeaderLine * FBBHeader; // The Headers from an FBB forward block
+
+ memmove(&conn->FBBHeaders[0], &conn->FBBHeaders[1], 4 * sizeof(struct FBBHeaderLine));
+
+ memset(&conn->FBBHeaders[4], 0, sizeof(struct FBBHeaderLine));
+
+ FBBHeader = &conn->FBBHeaders[0];
+
+ if (FBBHeader->MsgType == 0)
+ {
+ conn->FBBIndex = 0; // ready for next block;
+ memset(&conn->FBBHeaders[0], 0, 5 * sizeof(struct FBBHeaderLine));
+
+ conn->FBBChecksum = 0;
+ conn->InputMode = 0;
+
+ if (!FBBDoForward(conn)) // Send proposal if anthing to forward
+ {
+ conn->InputMode = 0;
+ FBBputs(conn, "FF\r");
+ }
+ }
+ else
+ {
+ if (conn->BBSFlags & FBBForwarding)
+ conn->InputMode = 'B';
+
+ CreateMessage(conn, FBBHeader->From, FBBHeader->To, FBBHeader->ATBBS, FBBHeader->MsgType, FBBHeader->BID, NULL);
+ }
+}
+
+BOOL FBBDoForward(CIRCUIT * conn)
+{
+ int i;
+ char proposal[100];
+ int proplen;
+
+ if (FindMessagestoForward(conn))
+ {
+ // Send Proposal Block
+
+ struct FBBHeaderLine * FBBHeader;
+
+ for (i=0; i < conn->FBBIndex; i++)
+ {
+ FBBHeader = &conn->FBBHeaders[i];
+
+ if (conn->BBSFlags & FBBB2Mode)
+
+ if (conn->BPQBBS)
+
+ // Add From and To Header for Filters
+
+ proplen = sprintf(proposal, "FC EM %s %d %d %s %s %s %c\r",
+ FBBHeader->BID,
+ FBBHeader->Size,
+ FBBHeader->CSize,
+ FBBHeader->From,
+ (FBBHeader->ATBBS[0]) ? FBBHeader->ATBBS : conn->UserPointer->Call,
+ FBBHeader->To,
+ FBBHeader->MsgType);
+
+ else
+
+ // FC EM A3EDD4P00P55 377 281 0
+
+ proplen = sprintf(proposal, "FC EM %s %d %d %d\r",
+ FBBHeader->BID,
+ FBBHeader->Size,
+ FBBHeader->CSize, 0);
+
+ else
+ proplen = sprintf(proposal, "%s %c %s %s %s %s %d\r",
+ (conn->BBSFlags & FBBCompressed) ? "FA" : "FB",
+ FBBHeader->MsgType,
+ FBBHeader->From,
+ (FBBHeader->ATBBS[0]) ? FBBHeader->ATBBS : conn->UserPointer->Call,
+ FBBHeader->To,
+ FBBHeader->BID,
+ FBBHeader->Size);
+
+ // Accumulate checksum
+
+ while(proplen > 0)
+ {
+ conn->FBBChecksum+=proposal[--proplen];
+ }
+
+ FBBputs(conn, proposal);
+ }
+
+ conn->FBBChecksum = - conn->FBBChecksum;
+
+ nodeprintfEx(conn, "F> %02X\r", conn->FBBChecksum);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+VOID UnpackFBBBinary(CIRCUIT * conn)
+{
+ int MsgLen, i, offset, n;
+ UCHAR * ptr;
+
+loop:
+
+ if (conn->CloseAfterFlush) // Failed (or complete), so discard rest of input
+ {
+ conn->InputLen = 0;
+ return;
+ }
+
+
+ ptr = conn->InputBuffer;
+
+ if (conn->InputLen < 2)
+ return; // All formats need at least two bytes
+
+ switch (*ptr)
+ {
+ case 1: // Header
+
+ MsgLen = ptr[1] + 2;
+
+ if (conn->InputLen < MsgLen)
+ return; // Wait for more
+
+ if (strlen(&ptr[2]) > 60)
+ {
+ memcpy(conn->TempMsg->title, &ptr[2], 60);
+ conn->TempMsg->title[60] = 0;
+ Debugprintf("FBB Subject too long - truncated, %s", &ptr[2]);
+ }
+ else
+ strcpy(conn->TempMsg->title, &ptr[2]);
+
+ offset = atoi(ptr+3+strlen(&ptr[2]));
+
+ ptr += MsgLen;
+
+ memmove(conn->InputBuffer, ptr, conn->InputLen-MsgLen);
+
+ conn->InputLen -= MsgLen;
+
+ conn->FBBChecksum = 0;
+
+ if (offset)
+ {
+ struct FBBRestartData * RestartRec;
+
+ // Trying to restart - make sure we have restart data
+
+ for (i = 1; i <= RestartCount; i++)
+ {
+ RestartRec = RestartData[i];
+
+ if ((strcmp(RestartRec->Call, conn->UserPointer->Call) == 0)
+ && (strcmp(RestartRec->bid, conn->TempMsg->bid) == 0))
+ {
+ if (RestartRec->length <= offset)
+ {
+ conn->TempMsg->length = RestartRec->length;
+ conn->MailBuffer = RestartRec->MailBuffer;
+ conn->MailBufferSize = RestartRec->MailBufferSize;
+
+ // FBB Seems to insert 6 Byte message
+ // It looks like the original csum and length - perhaps a a consistancy check
+
+ // But Airmail Sends the Restart Data in the next packet, move the check code.
+
+ conn->NeedRestartHeader = TRUE;
+
+ goto GotRestart;
+ }
+ else
+ {
+ BBSputs(conn, "*** Trying to restart from invalid position.\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+
+ return;
+ }
+
+ // Remove Restart info
+
+ for (n = i; n < RestartCount; n++)
+ {
+ RestartData[n] = RestartData[n+1]; // move down all following entries
+ }
+ RestartCount--;
+ SaveRestartData();
+ }
+ }
+
+ // No Restart Data
+
+ BBSputs(conn, "*** Trying to restart, but no restart data.\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+
+ return;
+ }
+
+ // Create initial buffer of 10K. Expand if needed later
+
+ if (conn->MailBufferSize == 0)
+ {
+ // Dont allocate if restarting
+
+ conn->MailBuffer=malloc(10000);
+ conn->MailBufferSize=10000;
+ }
+
+ GotRestart:
+
+ if (conn->MailBuffer == NULL)
+ {
+ BBSputs(conn, "*** Failed to create Message Buffer\r");
+ conn->CloseAfterFlush = 20; // 2 Secs
+
+ return;
+ }
+
+ goto loop;
+
+
+
+ case 2: // Data Block
+
+ if (ptr[1] == 0)
+ MsgLen = 256;
+ else
+ MsgLen = ptr[1];
+
+ if (conn->InputLen < (MsgLen + 2))
+ return; // Wait for more
+
+ // If waiting for Restart Header, see if it has arrived
+
+ if (conn->NeedRestartHeader)
+ {
+ conn->NeedRestartHeader = FALSE;
+
+ if (MsgLen == 6)
+ {
+ ptr = conn->InputBuffer+2;
+ conn->InputLen -=8;
+
+ for (i=0; i<6; i++)
+ {
+ conn->FBBChecksum+=ptr[0];
+ ptr++;
+ }
+ memmove(conn->InputBuffer, ptr, conn->InputLen);
+ }
+ else
+ {
+ BBSputs(conn, "*** Restart Header Missing.\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+ }
+
+ goto loop;
+
+ }
+ // Process it
+
+ ptr+=2;
+
+ for (i=0; i< MsgLen; i++)
+ {
+ conn->FBBChecksum+=ptr[i];
+ }
+
+ ptr-=2;
+
+ if ((conn->TempMsg->length + MsgLen) > conn->MailBufferSize)
+ {
+ conn->MailBufferSize += 10000;
+ conn->MailBuffer = realloc(conn->MailBuffer, conn->MailBufferSize);
+
+ if (conn->MailBuffer == NULL)
+ {
+ BBSputs(conn, "*** Failed to extend Message Buffer\r");
+ conn->CloseAfterFlush = 20; // 2 Secs
+
+ return;
+ }
+ }
+
+ memcpy(&conn->MailBuffer[conn->TempMsg->length], &ptr[2], MsgLen);
+
+ conn->TempMsg->length += MsgLen;
+
+ MsgLen +=2;
+
+ ptr += MsgLen;
+
+ memmove(conn->InputBuffer, ptr, conn->InputLen-MsgLen);
+
+ conn->InputLen -= MsgLen;
+
+ goto loop;
+
+
+ case 4: // EOM
+
+ // Process EOM
+
+ conn->FBBChecksum+=ptr[1];
+
+ if (conn->FBBChecksum == 0)
+ {
+#ifndef LINBPQ
+ __try
+ {
+#endif
+ conn->InputMode = 0; // So we won't save Restart data if decode fails
+ DeleteRestartData(conn);
+ Decode(conn, 0); // Setup Next Message will reset InputMode if needed
+#ifndef LINBPQ
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ BBSputs(conn, "*** Program Error Decoding Message\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+ return;
+ }
+#endif
+ }
+
+ else
+ {
+ BBSputs(conn, "*** Message Checksum Error\r");
+ Flush(conn);
+ conn->CloseAfterFlush = 20; // 2 Secs
+
+ // Don't allow restart, as saved data is probably duff
+
+ conn->DontSaveRestartData = TRUE;
+ return;
+ }
+ ptr += 2;
+
+ memmove(conn->InputBuffer, ptr, conn->InputLen-2);
+
+ conn->InputLen -= 2;
+
+ goto loop;
+
+ default:
+
+ BBSputs(conn, "*** Protocol Error - Invalid Binary Message Format (Invalid Block Type)\r");
+ Flush(conn);
+
+ if (conn->CloseAfterFlush == 0)
+ {
+ // Dont do it more than once
+
+ conn->CloseAfterFlush = 20; // 2 Secs
+
+ // Don't allow restart, as saved data is probably duff
+
+ // Actually all but the last block is probably OK, but maybe
+ // not worth the risk of restarting
+
+ // Actually I think it is
+
+ if (conn->TempMsg->length > 256)
+ {
+ conn->TempMsg->length -= 256;
+ conn->DontSaveRestartData = FALSE;
+ }
+ else
+ conn->DontSaveRestartData = TRUE;
+ }
+ return;
+ }
+}
+
+VOID SendCompressed(CIRCUIT * conn, struct MsgInfo * FwdMsg)
+{
+ struct tm * tm;
+ char * MsgBytes, * Save;
+ UCHAR * Compressed, * Compressedptr;
+ UCHAR * UnCompressed;
+ char * Title;
+ UCHAR * Output, * Outputptr;
+ int i, OrigLen, MsgLen, CompLen, DataOffset;
+ char Rline[80];
+ int RLineLen;
+ int Index;
+ time_t temp;
+
+ if (FwdMsg->type == 'P')
+ Index = PMSG;
+ else if (FwdMsg->type == 'B')
+ Index = BMSG;
+ else if (FwdMsg->type == 'T')
+ Index = TMSG;
+
+ MsgBytes = Save = ReadMessageFile(FwdMsg->number);
+
+ if (MsgBytes == 0)
+ {
+ MsgBytes = _strdup("Message file not found\r\n");
+ FwdMsg->length = (int)strlen(MsgBytes);
+ }
+
+ OrigLen = FwdMsg->length;
+
+ Title = FwdMsg->title;
+
+ Compressed = Compressedptr = zalloc(2 * OrigLen + 200);
+ Output = Outputptr = zalloc(2 * OrigLen + 200);
+
+ *Outputptr++ = 1;
+ *Outputptr++ = (int)strlen(Title) + 8;
+ strcpy(Outputptr, Title);
+ Outputptr += strlen(Title) +1;
+ sprintf(Outputptr, "%6d", conn->RestartFrom);
+ Outputptr += 7;
+
+ DataOffset = (int)(Outputptr - Output); // Used if restarting
+
+ memcpy(&temp, &FwdMsg->datereceived, sizeof(time_t));
+ tm = gmtime(&temp);
+
+ sprintf(Rline, "R:%02d%02d%02d/%02d%02dZ %d@%s.%s %s\r\n",
+ tm->tm_year-100, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min,
+ FwdMsg->number, BBSName, HRoute, RlineVer);
+
+ if (memcmp(MsgBytes, "R:", 2) != 0) // No R line, so must be our message
+ strcat(Rline, "\r\n");
+
+ RLineLen = (int)strlen(Rline);
+
+ MsgLen = OrigLen + RLineLen;
+
+ UnCompressed = zalloc(MsgLen+10);
+
+ strcpy(UnCompressed, Rline);
+
+ // If a B2 Message, Remove B2 Header
+
+ if (FwdMsg->B2Flags & B2Msg)
+ {
+ char * ptr;
+ int BodyLen = OrigLen;
+
+ // Remove all B2 Headers, and all but the first part.
+
+ ptr = strstr(MsgBytes, "Body:");
+
+ if (ptr)
+ {
+ BodyLen = atoi(&ptr[5]);
+ ptr= strstr(MsgBytes, "\r\n\r\n"); // Blank Line after headers
+
+ if (ptr)
+ ptr +=4;
+ else
+ ptr = MsgBytes;
+
+ }
+ else
+ ptr = MsgBytes;
+
+ if (memcmp(ptr, "R:", 2) == 0) // Already have RLines, so remove blank line after new R:line
+ RLineLen -= 2;
+
+ memcpy(&UnCompressed[RLineLen], ptr, BodyLen);
+
+ MsgLen = BodyLen + RLineLen;
+ }
+ else // Not B2 Message
+ {
+ memcpy(&UnCompressed[RLineLen], MsgBytes, OrigLen);
+ }
+
+ CompLen = Encode(UnCompressed, Compressed, MsgLen, conn->BBSFlags & FBBB1Mode, conn->BBSFlags & FBBCompressed);
+
+ conn->FBBChecksum = 0;
+
+ // If restarting, send the checksum and length as a single record, then data from the restart point
+ // The count includes the header, so adjust count and pointers
+
+ if (conn->RestartFrom)
+ {
+ *Outputptr++ = 2;
+ *Outputptr++ = 6;
+
+ for (i=0; i< 6; i++)
+ {
+ conn->FBBChecksum+=Compressed[i];
+ *Outputptr++ = Compressed[i];
+ }
+
+ for (i=conn->RestartFrom; i< CompLen; i++)
+ {
+ conn->FBBChecksum+=Compressed[i];
+ }
+
+ Compressedptr += conn->RestartFrom;
+ CompLen -= conn->RestartFrom;
+ }
+ else
+ {
+ for (i=0; i< CompLen; i++)
+ {
+ conn->FBBChecksum+=Compressed[i];
+ }
+ }
+
+ while (CompLen > 250)
+ {
+ *Outputptr++ = 2;
+ *Outputptr++ = 250;
+
+ memcpy(Outputptr, Compressedptr, 250);
+ Outputptr += 250;
+ Compressedptr += 250;
+ CompLen -= 250;
+ }
+
+ *Outputptr++ = 2;
+ *Outputptr++ = CompLen;
+
+ memcpy(Outputptr, Compressedptr, CompLen);
+
+ Outputptr += CompLen;
+
+ *Outputptr++ = 4;
+ conn->FBBChecksum = - conn->FBBChecksum;
+ *Outputptr++ = conn->FBBChecksum;
+
+ if (conn->OpenBCM) // Telnet, so escape any 0xFF
+ {
+ unsigned char * ptr1 = Output;
+ unsigned char * ptr2 = Compressed; // Reuse Compressed buffer
+ size_t Len = Outputptr - Output;
+ unsigned char c;
+
+ while (Len--)
+ {
+ c = *(ptr1++);
+ *(ptr2++) = c;
+ if (c == 0xff) // FF becodes FFFF
+ *(ptr2++) = c;
+ }
+
+ QueueMsg(conn, Compressed, (int)(ptr2 - Compressed));
+ }
+ else
+ QueueMsg(conn, Output, (int)(Outputptr - Output));
+
+ free(Save);
+ free(Compressed);
+ free(UnCompressed);
+ free(Output);
+
+}
+
+BOOL CreateB2Message(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader, char * Rline)
+{
+ char * MsgBytes;
+ UCHAR * Compressed;
+ UCHAR * UnCompressed;
+ int OrigLen, MsgLen, B2HddrLen, CompLen;
+ char Date[20];
+ struct tm * tm;
+ char B2From[80];
+ char B2To[80];
+ struct MsgInfo * Msg = FBBHeader->FwdMsg;
+ struct UserInfo * FromUser;
+ int BodyLineToBody;
+ int RlineLen = (int)strlen(Rline) ;
+ char * TypeString;
+#ifndef LINBPQ
+ struct _EXCEPTION_POINTERS exinfo;
+
+ __try {
+#endif
+
+ if (Msg == NULL)
+ Debugprintf("Msg = NULL");
+
+
+ MsgBytes = ReadMessageFile(Msg->number);
+
+ if (MsgBytes == 0)
+ {
+ Debugprintf("B2 Message - Message File not found");
+ return FALSE;
+ }
+
+ UnCompressed = zalloc(Msg->length + 2000);
+
+ if (UnCompressed == NULL)
+ Debugprintf("B2 Message - zalloc for %d failed", Msg->length + 2000);
+
+ OrigLen = Msg->length;
+
+ // If a B2 Message add R:line at start of Body, but otherwise leave intact.
+ // Unless a message to Paclink, when we must remove any HA from the TO address
+ // Or to a CMS, when we remove HA from From or Reply-to
+
+ if (Msg->B2Flags & B2Msg)
+ {
+ char * ptr, *ptr2;
+ int BodyLen;
+ int BodyLineLen;
+ int Index;
+
+ MsgLen = OrigLen + RlineLen;
+
+ if (conn->Paclink)
+ {
+ // Remove any HA on the TO address
+
+ ptr = strstr(MsgBytes, "To:");
+ if (ptr)
+ {
+ ptr2 = strstr(ptr, "\r\n");
+ if (ptr2)
+ {
+ while (ptr < ptr2)
+ {
+ if (*ptr == '.' || *ptr == '@')
+ {
+ memset(ptr, ' ', ptr2 - ptr);
+ break;
+ }
+ ptr++;
+ }
+ }
+ }
+ }
+
+ if (conn->WL2K)
+ {
+ // Remove any HA on the From or Reply-To address
+
+ ptr = strstr(MsgBytes, "From:");
+ if (ptr == NULL)
+ ptr = strstr(MsgBytes, "Reply-To:");
+
+ if (ptr)
+ {
+ ptr2 = strstr(ptr, "\r\n");
+ if (ptr2)
+ {
+ while (ptr < ptr2)
+ {
+ if (*ptr == '.' || *ptr == '@')
+ {
+ memset(ptr, ' ', ptr2 - ptr);
+ break;
+ }
+ ptr++;
+ }
+ }
+ }
+ }
+
+
+ // Add R: Line at start of body. Will Need to Update Body Length
+
+ ptr = strstr(MsgBytes, "Body:");
+
+ if (ptr == 0)
+ {
+ Debugprintf("B2 Messages without Body: Line");
+ return FALSE;
+ }
+ ptr2 = strstr(ptr, "\r\n");
+
+ Index = (int)(ptr - MsgBytes); // Bytes Before Body: line
+
+ if (Index <= 0 || Index > MsgLen)
+ {
+ Debugprintf("B2 Message Body: line position invalid - %d", Index);
+ return FALSE;
+ }
+
+ // If message to saildocs adding an R: line will mess up the message processing, so add as an X header
+
+ if (strstr(MsgBytes, "To: query@saildocs.com"))
+ {
+ int x_Len;
+
+ memcpy(UnCompressed, MsgBytes, Index); // Up to Old Body;
+ x_Len = sprintf(&UnCompressed[Index], "x-R: %s", &Rline[2]);
+ MsgLen = OrigLen + x_Len;
+ Index +=x_Len;
+ goto copyRest;
+ }
+
+ BodyLen = atoi(&ptr[5]);
+
+ if (BodyLen < 0 || BodyLen > MsgLen)
+ {
+ Debugprintf("B2 Message Length from Body: line invalid - Msg len %d From Body %d", MsgLen, BodyLen);
+ return FALSE;
+ }
+
+ BodyLineLen = (int)(ptr2 - ptr) + 2;
+ MsgLen -= BodyLineLen; // Length of Body Line may change
+
+ ptr = strstr(ptr2, "\r\n\r\n"); // Blank line before Body
+
+ if (ptr == 0)
+ {
+ Debugprintf("B2 Message - No Blank Line before Body");
+ return FALSE;
+ }
+
+ ptr += 4;
+
+ ptr2 += 2; // Line Following Original Body: Line
+
+ BodyLineToBody = (int)(ptr - ptr2);
+
+ if (memcmp(ptr, "R:", 2) != 0) // No R line, so must be our message
+ {
+ strcat(Rline, "\r\n");
+ RlineLen += 2;
+ MsgLen += 2;
+ }
+ BodyLen += RlineLen;
+
+ memcpy(UnCompressed, MsgBytes, Index); // Up to Old Body;
+ BodyLineLen = sprintf(&UnCompressed[Index], "Body: %d\r\n", BodyLen);
+
+ MsgLen += BodyLineLen; // Length of Body Line may have changed
+ Index += BodyLineLen;
+
+ if (BodyLineToBody < 0 || BodyLineToBody > 1000)
+ {
+ Debugprintf("B2 Message - Body too far from Body Line - %d", BodyLineToBody);
+ return FALSE;
+ }
+ memcpy(&UnCompressed[Index], ptr2, BodyLineToBody); // Stuff Between Body: Line and Body
+
+ Index += BodyLineToBody;
+
+ memcpy(&UnCompressed[Index], Rline, RlineLen);
+ Index += RlineLen;
+
+copyRest:
+
+ memcpy(&UnCompressed[Index], ptr, MsgLen - Index); // Rest of Message
+
+ FBBHeader->Size = MsgLen;
+
+ Compressed = zalloc(2 * MsgLen + 200);
+#ifndef LINBPQ
+ __try {
+#endif
+ CompLen = Encode(UnCompressed, Compressed, MsgLen, TRUE, conn->BBSFlags & FBBCompressed);
+
+ FBBHeader->CompressedMsg = Compressed;
+ FBBHeader->CSize = CompLen;
+
+ free(UnCompressed);
+ return TRUE;
+#ifndef LINBPQ
+ } My__except_Routine("Encode B2Message");
+#endif
+ return FALSE;
+ }
+
+
+ if (memcmp(MsgBytes, "R:", 2) != 0) // No R line, so must be our message
+ {
+ strcat(Rline, "\r\n");
+ RlineLen += 2;
+ }
+
+ MsgLen = OrigLen + RlineLen;
+
+// if (conn->RestartFrom == 0)
+// {
+// // save time first sent, or checksum will be wrong when we restart
+//
+// FwdMsg->datechanged=time(NULL);
+// }
+
+ tm = gmtime((time_t *)&Msg->datechanged);
+
+ sprintf(Date, "%04d/%02d/%02d %02d:%02d",
+ tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
+
+ // We create the B2 Header
+/*
+ MID: XR88I1J160EB
+ Date: 2009/07/25 18:17
+ Type: Private
+ From: SMTP:john.wiseman@ntlworld.com
+ To: G8BPQ
+ Subject: RE: RMS Test Message
+ Mbo: SMTP
+ Body: 213
+
+*/
+ if (strcmp(Msg->to, "RMS") == 0) // Address is in via
+ strcpy(B2To, Msg->via);
+ else
+ if (Msg->via[0] && (!conn->Paclink))
+ sprintf(B2To, "%s@%s", Msg->to, Msg->via);
+ else
+ strcpy(B2To, Msg->to);
+
+ // Try to create a full from: addrsss so RMS Express can reply
+
+ strcpy(B2From, Msg->from);
+
+ Logprintf(LOG_BBS, conn, '?', "B2 From %s", B2From);
+
+ if (strcmp(conn->Callsign, "RMS") != 0 && conn->WL2K == 0) // if going to RMS - just send calll
+ {
+ if (_stricmp(Msg->from, "SMTP:") == 0) // Address is in via
+ strcpy(B2From, Msg->emailfrom);
+ else
+ {
+ FromUser = LookupCall(Msg->from);
+
+ if (FromUser)
+ {
+ Logprintf(LOG_BBS, conn, '?', "B2 From - Local User");
+
+ 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);
+
+ Logprintf(LOG_BBS, conn, '?', "B2 From - not local User");
+
+ if (WP)
+ sprintf(B2From, "%s@%s", Msg->from, WP->first_homebbs);
+ }
+ }
+ }
+
+ Logprintf(LOG_BBS, conn, '?', "B2 From Finally %s", B2From);
+
+ if (Msg->type == 'P')
+ TypeString = "Private" ;
+ else if (Msg->type == 'B')
+ TypeString = "Bulletin";
+ else if (Msg->type == 'T')
+ TypeString = "Traffic";
+
+ B2HddrLen = sprintf(UnCompressed,
+ "MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nMbo: %s\r\n"
+ "Content-Type: text/plain\r\nContent-Transfer-Encoding: 8bit\r\nBody: %d\r\n\r\n",
+ Msg->bid, Date, TypeString, B2From, B2To, Msg->title, BBSName, MsgLen);
+
+
+ memcpy(&UnCompressed[B2HddrLen], Rline, RlineLen);
+ memcpy(&UnCompressed[B2HddrLen + RlineLen], MsgBytes, OrigLen); // Rest of Message
+
+ MsgLen += B2HddrLen;
+
+ FBBHeader->Size = MsgLen;
+
+ Compressed = zalloc(2 * MsgLen + 200);
+
+ CompLen = Encode(UnCompressed, Compressed, MsgLen, TRUE, conn->BBSFlags & FBBCompressed);
+
+ FBBHeader->CompressedMsg = Compressed;
+ FBBHeader->CSize = CompLen;
+
+ free(UnCompressed);
+
+ return TRUE;
+#ifndef LINBPQ
+ } My__except_Routine("CreateB2Message");
+#endif
+ return FALSE;
+
+}
+
+VOID SendCompressedB2(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader)
+{
+ UCHAR * Compressed, * Compressedptr;
+ UCHAR * Output, * Outputptr;
+ int i, CompLen;
+ int Index;
+
+ if (FBBHeader->FwdMsg->type == 'P')
+ Index = PMSG;
+ else if (FBBHeader->FwdMsg->type == 'B')
+ Index = BMSG;
+ else if (FBBHeader->FwdMsg->type == 'T')
+ Index = TMSG;
+
+ Compressed = Compressedptr = FBBHeader->CompressedMsg;
+
+ Output = Outputptr = zalloc(FBBHeader->CSize + 10000);
+
+ *Outputptr++ = 1;
+ *Outputptr++ = (int)strlen(FBBHeader->FwdMsg->title) + 8;
+ strcpy(Outputptr, FBBHeader->FwdMsg->title);
+ Outputptr += strlen(FBBHeader->FwdMsg->title) +1;
+ sprintf(Outputptr, "%06d", conn->RestartFrom);
+ Outputptr += 7;
+
+ CompLen = FBBHeader->CSize;
+
+ conn->FBBChecksum = 0;
+
+ // If restarting, send the checksum and length as a single record, then data from the restart point
+ // The count includes the header, so adjust count and pointers
+
+ if (conn->RestartFrom)
+ {
+ *Outputptr++ = 2;
+ *Outputptr++ = 6;
+
+ for (i=0; i< 6; i++)
+ {
+ conn->FBBChecksum+=Compressed[i];
+ *Outputptr++ = Compressed[i];
+ }
+
+ for (i=conn->RestartFrom; i< CompLen; i++)
+ {
+ conn->FBBChecksum+=Compressed[i];
+ }
+
+ Compressedptr += conn->RestartFrom;
+ CompLen -= conn->RestartFrom;
+ }
+ else
+ {
+ for (i=0; i< CompLen; i++)
+ {
+ conn->FBBChecksum+=Compressed[i];
+ }
+ conn->UserPointer->Total.MsgsSent[Index]++;
+ conn->UserPointer->Total.BytesForwardedOut[Index] += FBBHeader->FwdMsg->length;
+
+ }
+
+ while (CompLen > 256)
+ {
+ *Outputptr++ = 2;
+ *Outputptr++ = 0;
+
+ memcpy(Outputptr, Compressedptr, 256);
+ Outputptr += 256;
+ Compressedptr += 256;
+ CompLen -= 256;
+ }
+
+ *Outputptr++ = 2;
+ *Outputptr++ = CompLen;
+
+ memcpy(Outputptr, Compressedptr, CompLen);
+
+ Outputptr += CompLen;
+
+ *Outputptr++ = 4;
+ conn->FBBChecksum = - conn->FBBChecksum;
+ *Outputptr++ = conn->FBBChecksum;
+
+ if (conn->OpenBCM) // Telnet, so escape any 0xFF
+ {
+ unsigned char * ptr1 = Output;
+ unsigned char * ptr2 = Compressed; // Reuse Compressed buffer
+ int Len = (int)(Outputptr - Output);
+ unsigned char c;
+
+ while (Len--)
+ {
+ c = *(ptr1++);
+ *(ptr2++) = c;
+ if (c == 0xff) // FF becodes FFFF
+ *(ptr2++) = c;
+ }
+
+ QueueMsg(conn, Compressed, (int)(ptr2 - Compressed));
+ }
+ else
+ QueueMsg(conn, Output, (int)(Outputptr - Output));
+
+ free(Compressed);
+ free(Output);
+}
+
+// Restart Routines.
+
+VOID SaveFBBBinary(CIRCUIT * conn)
+{
+ // Disconnected during binary transfer
+
+ char Msg[120];
+ int i, len;
+ struct FBBRestartData * RestartRec = NULL;
+
+ if (conn->TempMsg == NULL)
+ return;
+
+ if (conn->TempMsg->length < 256)
+ return; // Not worth it.
+
+ // If we already have a restart record, reuse it
+
+ for (i = 1; i <= RestartCount; i++)
+ {
+ RestartRec = RestartData[i];
+
+ if ((strcmp(RestartRec->Call, conn->UserPointer->Call) == 0)
+ && (strcmp(RestartRec->bid, conn->TempMsg->bid) == 0))
+ {
+ // Found it, so reuse
+
+ // If we have more data, reset retry count
+
+ if (RestartRec->length < conn->TempMsg->length)
+ RestartRec->Count = 0;;
+
+ break;
+ }
+ }
+
+ if (RestartRec == NULL)
+ {
+ RestartRec = zalloc(sizeof (struct FBBRestartData));
+
+ GetSemaphore(&AllocSemaphore, 0);
+
+ RestartData=realloc(RestartData,(++RestartCount+1) * sizeof(void *));
+ RestartData[RestartCount] = RestartRec;
+
+ FreeSemaphore(&AllocSemaphore);
+ RestartRec->TimeCreated = time(NULL);
+ }
+
+ strcpy(RestartRec->Call, conn->UserPointer->Call);
+ RestartRec->length = conn->TempMsg->length;
+ strcpy(RestartRec->bid, conn->TempMsg->bid);
+ RestartRec->MailBuffer = conn->MailBuffer;
+ RestartRec->MailBufferSize = conn->MailBufferSize;
+
+ len = sprintf_s(Msg, sizeof(Msg), "Disconnect received from %s during Binary Transfer - %d Bytes Saved for restart",
+ conn->Callsign, conn->TempMsg->length);
+
+ SaveRestartData();
+
+ WriteLogLine(conn, '|',Msg, len, LOG_BBS);
+}
+
+void DeleteRestartData(CIRCUIT * conn)
+{
+ struct FBBRestartData * RestartRec = NULL;
+ int i, n;
+
+ if (conn->TempMsg == NULL)
+ return;
+
+ for (i = 1; i <= RestartCount; i++)
+ {
+ RestartRec = RestartData[i];
+
+ if ((strcmp(RestartRec->Call, conn->UserPointer->Call) == 0)
+ && (strcmp(RestartRec->bid, conn->TempMsg->bid) == 0))
+ {
+ // Remove restrt data
+
+ for (n = i; n < RestartCount; n++)
+ {
+ RestartData[n] = RestartData[n+1]; // move down all following entries
+ }
+
+ RestartCount--;
+ SaveRestartData();
+ return;
+ }
+ }
+}
+
+
+BOOL LookupRestart(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader)
+{
+ int i, n;
+
+ struct FBBRestartData * RestartRec;
+
+ if ((conn->BBSFlags & FBBB1Mode) == 0)
+ return FALSE; // Only B1 & B2 support restart
+
+ for (i = 1; i <= RestartCount; i++)
+ {
+ RestartRec = RestartData[i];
+
+ if ((strcmp(RestartRec->Call, conn->UserPointer->Call) == 0)
+ && (strcmp(RestartRec->bid, FBBHeader->BID) == 0))
+ {
+ char Msg[120];
+ int len;
+
+ RestartRec->Count++;
+
+ if (RestartRec->Count > 10)
+ {
+ len = sprintf_s(Msg, sizeof(Msg), "Too many restarts for %s - Requesting restart from beginning",
+ FBBHeader->BID);
+
+ WriteLogLine(conn, '|',Msg, len, LOG_BBS);
+
+ // Remove restrt data
+
+ for (n = i; n < RestartCount; n++)
+ {
+ RestartData[n] = RestartData[n+1]; // move down all following entries
+ }
+
+ RestartCount--;
+ SaveRestartData();
+ return FALSE;
+ }
+
+ len = sprintf_s(Msg, sizeof(Msg), "Restart Data found for %s - Requesting restart from %d",
+ FBBHeader->BID, RestartRec->length);
+
+ WriteLogLine(conn, '|',Msg, len, LOG_BBS);
+
+ return (RestartRec->length);
+ }
+ }
+
+ return FALSE; // Not Found
+}
+
+
+
+BOOL DoWeWantIt(CIRCUIT * conn, struct FBBHeaderLine * FBBHeader)
+{
+ struct MsgInfo * Msg;
+ BIDRec * BID;
+ int m;
+
+ if (RefuseBulls && FBBHeader->MsgType == 'B')
+ {
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected by RefuseBulls");
+ return FALSE;
+ }
+ if (FBBHeader->Size > MaxRXSize)
+ {
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected by Size Check");
+ return FALSE;
+ }
+
+ BID = LookupBID(FBBHeader->BID);
+
+ if (BID)
+ {
+ if (FBBHeader->MsgType == 'B')
+ {
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected by BID Check");
+ return FALSE;
+ }
+
+ // Treat P messages to SYSOP@WW as Bulls
+
+ if (strcmp(FBBHeader->To, "SYSOP") == 0 && strcmp(FBBHeader->ATBBS, "WW") == 0)
+ {
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected by BID Check");
+ return FALSE;
+ }
+
+ m = NumberofMessages;
+
+ while (m > 0)
+ {
+ Msg = MsgHddrPtr[m];
+
+ if (Msg->number == BID->u.msgno)
+ {
+ // if the same TO we will assume the same message
+
+ if (strcmp(Msg->to, FBBHeader->To) == 0)
+ {
+ // We have this message. If we have already forwarded it, we should accept it again
+
+ if ((Msg->status == 'N') || (Msg->status == 'Y')|| (Msg->status == 'H'))
+ {
+ Logprintf(LOG_BBS, conn, '?', "Message Rejected by BID Check");
+ return FALSE; // Dont want it
+ }
+ else
+ return TRUE; // Get it again
+ }
+
+ // Same number. but different message (why?) Accept for now
+
+ return TRUE;
+ }
+
+ m--;
+ }
+
+ return TRUE; // A personal Message we have had before, but don't still have.
+ }
+ else
+ {
+ // We don't know the BID
+
+ return TRUE; // We want it
+ }
+}
+
+
+
+
diff --git a/.svn/pristine/11/1105d6155b0f09c6edbdbc765bbd700d7d4d582a.svn-base b/.svn/pristine/11/1105d6155b0f09c6edbdbc765bbd700d7d4d582a.svn-base
index 3ea8f94..5103cfe 100644
--- a/.svn/pristine/11/1105d6155b0f09c6edbdbc765bbd700d7d4d582a.svn-base
+++ b/.svn/pristine/11/1105d6155b0f09c6edbdbc765bbd700d7d4d582a.svn-base
@@ -1,402 +1,402 @@
-/*
-Copyright 2001-2022 John Wiseman G8BPQ
-
-This file is part of LinBPQ/BPQ32.
-
-LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-LinBPQ/BPQ32 is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
-*/
-
-//
-// C replacement for TNCCode.asm
-//
-#define Kernel
-
-#define _CRT_SECURE_NO_DEPRECATE
-
-#pragma data_seg("_BPQDATA")
-
-#include "time.h"
-#include "stdio.h"
-#include
-
-#include "cheaders.h"
-#include "tncinfo.h"
-
-int C_Q_COUNT(VOID *PQ);
-VOID SENDUIMESSAGE(struct DATAMESSAGE * Msg);
-
-VOID TNCTimerProc()
-{
- // CALLED AT 10 HZ
-
- int n = BPQHOSTSTREAMS;
- PBPQVECSTRUC HOSTSESS = BPQHOSTVECTOR;
- TRANSPORTENTRY * Session;
- UCHAR DISCFLAG = 0;
-
- while (n--)
- {
- // Action any DISC Requests (must be done in timer owning process)
-
- if (HOSTSESS->HOSTFLAGS & 0x40) // DISC REQUEST
- {
- if (HOSTSESS->HOSTFLAGS & 0x20) // Stay?
- DISCFLAG = 'S';
-
- HOSTSESS->HOSTFLAGS &= 0x9F; // Clear Flags
-
- Session = HOSTSESS->HOSTSESSION;
-
- if (Session == 0) // Gone??
- {
- HOSTSESS->HOSTFLAGS |= 3; // STATE CHANGE
-#ifndef LINBPQ
- if (HOSTSESS->HOSTHANDLE);
- {
- PostMessage(HOSTSESS->HOSTHANDLE, BPQMsg, HOSTSESS->HOSTSTREAM, 4);
- }
-#endif
- continue;
- }
-
- if (Session->L4CROSSLINK)
- Session->L4CROSSLINK->STAYFLAG = DISCFLAG;
-
- HOSTSESS->HOSTSESSION = 0;
- HOSTSESS->HOSTFLAGS |= 3; // STATE CHANGE
-
- PostStateChange(Session);
-
- CloseSessionPartner(Session); // SEND CLOSE TO PARTNER (IF PRESENT)
- }
-
- // Check Trace Q
-
- if (HOSTSESS->HOSTAPPLFLAGS & 0x80)
- {
- if (HOSTSESS->HOSTTRACEQ)
- {
- int Count = C_Q_COUNT(&HOSTSESS->HOSTTRACEQ);
-
- if (Count > 100)
- ReleaseBuffer((void *)Q_REM((void *)&HOSTSESS->HOSTTRACEQ));
- }
- }
- HOSTSESS++;
- }
-}
-
-VOID SendSmartID(struct PORTCONTROL * PORT)
-{
- struct _MESSAGE * ID = IDMSG;
- struct _MESSAGE * Buffer;
-
- PORT->SmartIDNeeded = 0;
-
- Buffer = GetBuff();
-
- if (Buffer)
- {
- memcpy(Buffer, ID, ID->LENGTH);
-
- Buffer->PORT = PORT->PORTNUMBER;
-
- // IF PORT HAS A CALLSIGN DEFINED, SEND THAT INSTEAD
-
- if (PORT->PORTCALL[0] > 0x40)
- {
- memcpy(Buffer->ORIGIN, PORT->PORTCALL, 7);
- Buffer->ORIGIN[6] |= 1; // SET END OF CALL BIT
- }
-
- // If Pactor Style add to UI_Q
-
- if (PORT->PROTOCOL == 10 && PORT->TNC && PORT->TNC->Hardware != H_KISSHF && PORT->UICAPABLE)
- {
- EXTPORTDATA * EXTPORT = (EXTPORTDATA *) PORT;
-
- C_Q_ADD(&EXTPORT->UI_Q, Buffer);
- return;
- }
-
- PUT_ON_PORT_Q(PORT, Buffer);
- }
-}
-
-
-VOID SENDIDMSG()
-{
- struct PORTCONTROL * PORT = PORTTABLE;
- struct _MESSAGE * ID = IDMSG;
- struct _MESSAGE * Buffer;
-
- while (PORT)
- {
- if (PORT->PROTOCOL < 10) // Not Pactor-style
- {
- Buffer = GetBuff();
-
- if (Buffer)
- {
- memcpy(Buffer, ID, ID->LENGTH);
-
- Buffer->PORT = PORT->PORTNUMBER;
-
- // IF PORT HAS A CALLSIGN DEFINED, SEND THAT INSTEAD
-
- if (PORT->PORTCALL[0] > 0x40)
- {
- memcpy(Buffer->ORIGIN, PORT->PORTCALL, 7);
- Buffer->ORIGIN[6] |= 1; // SET END OF CALL BIT
- }
- C_Q_ADD(&IDMSG_Q, Buffer);
- }
- }
- PORT = PORT->PORTPOINTER;
- }
-}
-
-
-
-VOID SENDBTMSG()
-{
- struct PORTCONTROL * PORT = PORTTABLE;
- struct _MESSAGE * Buffer;
- char * ptr1, * ptr2;
-
- while (PORT)
- {
- if (PORT->PROTOCOL >= 10 || PORT->PORTUNPROTO == 0) // Pactor-style or no UNPROTO ADDR?
- {
- PORT = PORT->PORTPOINTER;
- continue;
- }
-
- Buffer = GetBuff();
-
- if (Buffer)
- {
- memcpy(Buffer->DEST, PORT->PORTUNPROTO, 7);
- Buffer->DEST[6] |= 0xC0; // Set Command bits
-
- // Send from BBSCALL unless PORTBCALL defined
-
- if (PORT->PORTBCALL[0] > 32)
- memcpy(Buffer->ORIGIN, PORT->PORTBCALL, 7);
- else if (APPLCALLTABLE->APPLCALL[0] > 32)
- memcpy(Buffer->ORIGIN, APPLCALLTABLE->APPLCALL, 7);
- else
- memcpy(Buffer->ORIGIN, MYCALL, 7);
-
- ptr1 = &PORT->PORTUNPROTO[7]; // First Digi
- ptr2 = &Buffer->CTL; // Digi field in buffer
-
- // Copy any digis
-
- while (*(ptr1))
- {
- memcpy(ptr2, ptr1, 7);
- ptr1 += 7;
- ptr2 += 7;
- }
-
- *(ptr2 - 1) |= 1; // Set End of Address
- *(ptr2++) = UI;
-
- memcpy(ptr2, &BTHDDR.PID, BTHDDR.LENGTH);
- ptr2 += BTHDDR.LENGTH;
- Buffer->LENGTH = (int)(ptr2 - (char *)Buffer);
- Buffer->PORT = PORT->PORTNUMBER;
-
- C_Q_ADD(&IDMSG_Q, Buffer);
- }
- PORT = PORT->PORTPOINTER;
- }
-}
-
-VOID SENDUIMESSAGE(struct DATAMESSAGE * Msg)
-{
- struct PORTCONTROL * PORT = PORTTABLE;
- struct _MESSAGE * Buffer;
- char * ptr1, * ptr2;
-
- Msg->LENGTH -= MSGHDDRLEN; // Remove Header
-
- while (PORT)
- {
- if ((PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0) || PORT->PORTUNPROTO == 0) // Pactor-style or no UNPROTO ADDR?
- {
- PORT = PORT->PORTPOINTER;
- continue;
- }
-
- Buffer = GetBuff();
-
- if (Buffer)
- {
- memcpy(Buffer->DEST, PORT->PORTUNPROTO, 7);
- Buffer->DEST[6] |= 0xC0; // Set Command bits
-
- // Send from BBSCALL unless PORTBCALL defined
-
- if (PORT->PORTBCALL[0] > 32)
- memcpy(Buffer->ORIGIN, PORT->PORTBCALL, 7);
- else if (APPLCALLTABLE->APPLCALL[0] > 32)
- memcpy(Buffer->ORIGIN, APPLCALLTABLE->APPLCALL, 7);
- else
- memcpy(Buffer->ORIGIN, MYCALL, 7);
-
- ptr1 = &PORT->PORTUNPROTO[7]; // First Digi
- ptr2 = &Buffer->CTL; // Digi field in buffer
-
- // Copy any digis
-
- while (*(ptr1))
- {
- memcpy(ptr2, ptr1, 7);
- ptr1 += 7;
- ptr2 += 7;
- }
-
- *(ptr2 - 1) |= 1; // Set End of Address
- *(ptr2++) = UI;
-
- memcpy(ptr2, &Msg->PID, Msg->LENGTH);
- ptr2 += Msg->LENGTH;
- Buffer->LENGTH = (int)(ptr2 - (char *)Buffer);
- Buffer->PORT = PORT->PORTNUMBER;
-
- if (PORT->PROTOCOL == 10)
- {
- EXTPORTDATA * EXTPORT = (EXTPORTDATA *) PORT;
- C_Q_ADD(&EXTPORT->UI_Q, Buffer);
- }
- else
- C_Q_ADD(&IDMSG_Q, Buffer);
- }
- PORT = PORT->PORTPOINTER;
- }
-}
-
-Dll VOID APIENTRY Send_AX(UCHAR * Block, DWORD Len, UCHAR Port)
-{
- // Block included the 7/11 byte header, Len does not
-
- struct PORTCONTROL * PORT;
- PMESSAGE Copy;
-
- if (Len > 360 - 15)
- return;
-
- if (QCOUNT < 50)
- return; // Running low
-
- PORT = GetPortTableEntryFromPortNum(Port);
-
- if (PORT == 0)
- return;
-
- Copy = GetBuff();
-
- if (Copy == 0)
- return;
-
- memcpy(&Copy->DEST[0], &Block[MSGHDDRLEN], Len);
-
- Copy->LENGTH = (USHORT)Len + MSGHDDRLEN;
-
- if (PORT->PROTOCOL == 10 && PORT->TNC && PORT->TNC->Hardware != H_KISSHF)
- {
- // Pactor Style. Probably will only be used for Tracker uneless we do APRS over V4 or WINMOR
-
- EXTPORTDATA * EXTPORT = (EXTPORTDATA *) PORT;
-
- if (EXTPORT->UI_Q)
- C_Q_ADD(&EXTPORT->UI_Q, Copy);
- else
- C_Q_ADD(&EXTPORT->UI_Q, Copy);
- return;
- }
-
- Copy->PORT = Port;
-
- PUT_ON_PORT_Q(PORT, Copy);
-}
-
-
-TRANSPORTENTRY * SetupSessionFromHost(PBPQVECSTRUC HOST, UINT ApplMask)
-{
- // Create a Transport (L4) session linked to an incoming HOST (API) Session
-
- TRANSPORTENTRY * NewSess = L4TABLE;
- int Index = 0;
-
-
- while (Index < MAXCIRCUITS)
- {
- if (NewSess->L4USER[0] == 0)
- {
- // Got One
-
- UCHAR * ourcall = &MYCALL[0];
-
- // IF APPL PORT USE APPL CALL, ELSE NODE CALL
-
- if (ApplMask)
- {
- // Circuit for APPL - look for an APPLCALL
-
- APPLCALLS * APPL = APPLCALLTABLE;
-
- while ((ApplMask & 1) == 0)
- {
- ApplMask >>= 1;
- APPL++;
- }
- if (APPL->APPLCALL[0] > 0x40) // We have an applcall
- ourcall = &APPL->APPLCALL[0];
- }
-
- memcpy(NewSess->L4USER, ourcall, 7);
- memcpy(NewSess->L4MYCALL, ourcall, 7);
-
- NewSess->CIRCUITINDEX = Index; //OUR INDEX
- NewSess->CIRCUITID = NEXTID;
-
- NEXTID++;
- if (NEXTID == 0)
- NEXTID++; // Keep Non-Zero
-
- NewSess->L4TARGET.HOST = HOST;
- NewSess->L4STATE = 5;
-
-
- NewSess->SESSIONT1 = L4T1;
- NewSess->L4WINDOW = (UCHAR)L4DEFAULTWINDOW;
- NewSess->SESSPACLEN = PACLEN; // Default;
-
- return NewSess;
- }
- Index++;
- NewSess++;
- }
-
- // Table Full
-
- return NULL;
-}
-
-
-
-
+/*
+Copyright 2001-2022 John Wiseman G8BPQ
+
+This file is part of LinBPQ/BPQ32.
+
+LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+LinBPQ/BPQ32 is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
+*/
+
+//
+// C replacement for TNCCode.asm
+//
+#define Kernel
+
+#define _CRT_SECURE_NO_DEPRECATE
+
+#pragma data_seg("_BPQDATA")
+
+#include "time.h"
+#include "stdio.h"
+#include
+
+#include "cheaders.h"
+#include "tncinfo.h"
+
+int C_Q_COUNT(VOID *PQ);
+VOID SENDUIMESSAGE(struct DATAMESSAGE * Msg);
+
+VOID TNCTimerProc()
+{
+ // CALLED AT 10 HZ
+
+ int n = BPQHOSTSTREAMS;
+ PBPQVECSTRUC HOSTSESS = BPQHOSTVECTOR;
+ TRANSPORTENTRY * Session;
+ UCHAR DISCFLAG = 0;
+
+ while (n--)
+ {
+ // Action any DISC Requests (must be done in timer owning process)
+
+ if (HOSTSESS->HOSTFLAGS & 0x40) // DISC REQUEST
+ {
+ if (HOSTSESS->HOSTFLAGS & 0x20) // Stay?
+ DISCFLAG = 'S';
+
+ HOSTSESS->HOSTFLAGS &= 0x9F; // Clear Flags
+
+ Session = HOSTSESS->HOSTSESSION;
+
+ if (Session == 0) // Gone??
+ {
+ HOSTSESS->HOSTFLAGS |= 3; // STATE CHANGE
+#ifndef LINBPQ
+ if (HOSTSESS->HOSTHANDLE);
+ {
+ PostMessage(HOSTSESS->HOSTHANDLE, BPQMsg, HOSTSESS->HOSTSTREAM, 4);
+ }
+#endif
+ continue;
+ }
+
+ if (Session->L4CROSSLINK)
+ Session->L4CROSSLINK->STAYFLAG = DISCFLAG;
+
+ HOSTSESS->HOSTSESSION = 0;
+ HOSTSESS->HOSTFLAGS |= 3; // STATE CHANGE
+
+ PostStateChange(Session);
+
+ CloseSessionPartner(Session); // SEND CLOSE TO PARTNER (IF PRESENT)
+ }
+
+ // Check Trace Q
+
+ if (HOSTSESS->HOSTAPPLFLAGS & 0x80)
+ {
+ if (HOSTSESS->HOSTTRACEQ)
+ {
+ int Count = C_Q_COUNT(&HOSTSESS->HOSTTRACEQ);
+
+ if (Count > 100)
+ ReleaseBuffer((void *)Q_REM((void *)&HOSTSESS->HOSTTRACEQ));
+ }
+ }
+ HOSTSESS++;
+ }
+}
+
+VOID SendSmartID(struct PORTCONTROL * PORT)
+{
+ struct _MESSAGE * ID = IDMSG;
+ struct _MESSAGE * Buffer;
+
+ PORT->SmartIDNeeded = 0;
+
+ Buffer = GetBuff();
+
+ if (Buffer)
+ {
+ memcpy(Buffer, ID, ID->LENGTH);
+
+ Buffer->PORT = PORT->PORTNUMBER;
+
+ // IF PORT HAS A CALLSIGN DEFINED, SEND THAT INSTEAD
+
+ if (PORT->PORTCALL[0] > 0x40)
+ {
+ memcpy(Buffer->ORIGIN, PORT->PORTCALL, 7);
+ Buffer->ORIGIN[6] |= 1; // SET END OF CALL BIT
+ }
+
+ // If Pactor Style add to UI_Q
+
+ if (PORT->PROTOCOL == 10 && PORT->TNC && PORT->TNC->Hardware != H_KISSHF && PORT->UICAPABLE)
+ {
+ EXTPORTDATA * EXTPORT = (EXTPORTDATA *) PORT;
+
+ C_Q_ADD(&EXTPORT->UI_Q, Buffer);
+ return;
+ }
+
+ PUT_ON_PORT_Q(PORT, Buffer);
+ }
+}
+
+
+VOID SENDIDMSG()
+{
+ struct PORTCONTROL * PORT = PORTTABLE;
+ struct _MESSAGE * ID = IDMSG;
+ struct _MESSAGE * Buffer;
+
+ while (PORT)
+ {
+ if (PORT->PROTOCOL < 10) // Not Pactor-style
+ {
+ Buffer = GetBuff();
+
+ if (Buffer)
+ {
+ memcpy(Buffer, ID, ID->LENGTH);
+
+ Buffer->PORT = PORT->PORTNUMBER;
+
+ // IF PORT HAS A CALLSIGN DEFINED, SEND THAT INSTEAD
+
+ if (PORT->PORTCALL[0] > 0x40)
+ {
+ memcpy(Buffer->ORIGIN, PORT->PORTCALL, 7);
+ Buffer->ORIGIN[6] |= 1; // SET END OF CALL BIT
+ }
+ C_Q_ADD(&IDMSG_Q, Buffer);
+ }
+ }
+ PORT = PORT->PORTPOINTER;
+ }
+}
+
+
+
+VOID SENDBTMSG()
+{
+ struct PORTCONTROL * PORT = PORTTABLE;
+ struct _MESSAGE * Buffer;
+ char * ptr1, * ptr2;
+
+ while (PORT)
+ {
+ if (PORT->PROTOCOL >= 10 || PORT->PORTUNPROTO == 0) // Pactor-style or no UNPROTO ADDR?
+ {
+ PORT = PORT->PORTPOINTER;
+ continue;
+ }
+
+ Buffer = GetBuff();
+
+ if (Buffer)
+ {
+ memcpy(Buffer->DEST, PORT->PORTUNPROTO, 7);
+ Buffer->DEST[6] |= 0xC0; // Set Command bits
+
+ // Send from BBSCALL unless PORTBCALL defined
+
+ if (PORT->PORTBCALL[0] > 32)
+ memcpy(Buffer->ORIGIN, PORT->PORTBCALL, 7);
+ else if (APPLCALLTABLE->APPLCALL[0] > 32)
+ memcpy(Buffer->ORIGIN, APPLCALLTABLE->APPLCALL, 7);
+ else
+ memcpy(Buffer->ORIGIN, MYCALL, 7);
+
+ ptr1 = &PORT->PORTUNPROTO[7]; // First Digi
+ ptr2 = &Buffer->CTL; // Digi field in buffer
+
+ // Copy any digis
+
+ while (*(ptr1))
+ {
+ memcpy(ptr2, ptr1, 7);
+ ptr1 += 7;
+ ptr2 += 7;
+ }
+
+ *(ptr2 - 1) |= 1; // Set End of Address
+ *(ptr2++) = UI;
+
+ memcpy(ptr2, &BTHDDR.PID, BTHDDR.LENGTH);
+ ptr2 += BTHDDR.LENGTH;
+ Buffer->LENGTH = (int)(ptr2 - (char *)Buffer);
+ Buffer->PORT = PORT->PORTNUMBER;
+
+ C_Q_ADD(&IDMSG_Q, Buffer);
+ }
+ PORT = PORT->PORTPOINTER;
+ }
+}
+
+VOID SENDUIMESSAGE(struct DATAMESSAGE * Msg)
+{
+ struct PORTCONTROL * PORT = PORTTABLE;
+ struct _MESSAGE * Buffer;
+ char * ptr1, * ptr2;
+
+ Msg->LENGTH -= MSGHDDRLEN; // Remove Header
+
+ while (PORT)
+ {
+ if ((PORT->PROTOCOL == 10 && PORT->UICAPABLE == 0) || PORT->PORTUNPROTO == 0) // Pactor-style or no UNPROTO ADDR?
+ {
+ PORT = PORT->PORTPOINTER;
+ continue;
+ }
+
+ Buffer = GetBuff();
+
+ if (Buffer)
+ {
+ memcpy(Buffer->DEST, PORT->PORTUNPROTO, 7);
+ Buffer->DEST[6] |= 0xC0; // Set Command bits
+
+ // Send from BBSCALL unless PORTBCALL defined
+
+ if (PORT->PORTBCALL[0] > 32)
+ memcpy(Buffer->ORIGIN, PORT->PORTBCALL, 7);
+ else if (APPLCALLTABLE->APPLCALL[0] > 32)
+ memcpy(Buffer->ORIGIN, APPLCALLTABLE->APPLCALL, 7);
+ else
+ memcpy(Buffer->ORIGIN, MYCALL, 7);
+
+ ptr1 = &PORT->PORTUNPROTO[7]; // First Digi
+ ptr2 = &Buffer->CTL; // Digi field in buffer
+
+ // Copy any digis
+
+ while (*(ptr1))
+ {
+ memcpy(ptr2, ptr1, 7);
+ ptr1 += 7;
+ ptr2 += 7;
+ }
+
+ *(ptr2 - 1) |= 1; // Set End of Address
+ *(ptr2++) = UI;
+
+ memcpy(ptr2, &Msg->PID, Msg->LENGTH);
+ ptr2 += Msg->LENGTH;
+ Buffer->LENGTH = (int)(ptr2 - (char *)Buffer);
+ Buffer->PORT = PORT->PORTNUMBER;
+
+ if (PORT->PROTOCOL == 10)
+ {
+ EXTPORTDATA * EXTPORT = (EXTPORTDATA *) PORT;
+ C_Q_ADD(&EXTPORT->UI_Q, Buffer);
+ }
+ else
+ C_Q_ADD(&IDMSG_Q, Buffer);
+ }
+ PORT = PORT->PORTPOINTER;
+ }
+}
+
+Dll VOID APIENTRY Send_AX(UCHAR * Block, DWORD Len, UCHAR Port)
+{
+ // Block included the 7/11 byte header, Len does not
+
+ struct PORTCONTROL * PORT;
+ PMESSAGE Copy;
+
+ if (Len > 360 - 15)
+ return;
+
+ if (QCOUNT < 50)
+ return; // Running low
+
+ PORT = GetPortTableEntryFromPortNum(Port);
+
+ if (PORT == 0)
+ return;
+
+ Copy = GetBuff();
+
+ if (Copy == 0)
+ return;
+
+ memcpy(&Copy->DEST[0], &Block[MSGHDDRLEN], Len);
+
+ Copy->LENGTH = (USHORT)Len + MSGHDDRLEN;
+
+ if (PORT->PROTOCOL == 10 && PORT->TNC && PORT->TNC->Hardware != H_KISSHF)
+ {
+ // Pactor Style. Probably will only be used for Tracker uneless we do APRS over V4 or WINMOR
+
+ EXTPORTDATA * EXTPORT = (EXTPORTDATA *) PORT;
+
+ if (EXTPORT->UI_Q)
+ C_Q_ADD(&EXTPORT->UI_Q, Copy);
+ else
+ C_Q_ADD(&EXTPORT->UI_Q, Copy);
+ return;
+ }
+
+ Copy->PORT = Port;
+
+ PUT_ON_PORT_Q(PORT, Copy);
+}
+
+
+TRANSPORTENTRY * SetupSessionFromHost(PBPQVECSTRUC HOST, UINT ApplMask)
+{
+ // Create a Transport (L4) session linked to an incoming HOST (API) Session
+
+ TRANSPORTENTRY * NewSess = L4TABLE;
+ int Index = 0;
+
+
+ while (Index < MAXCIRCUITS)
+ {
+ if (NewSess->L4USER[0] == 0)
+ {
+ // Got One
+
+ UCHAR * ourcall = &MYCALL[0];
+
+ // IF APPL PORT USE APPL CALL, ELSE NODE CALL
+
+ if (ApplMask)
+ {
+ // Circuit for APPL - look for an APPLCALL
+
+ APPLCALLS * APPL = APPLCALLTABLE;
+
+ while ((ApplMask & 1) == 0)
+ {
+ ApplMask >>= 1;
+ APPL++;
+ }
+ if (APPL->APPLCALL[0] > 0x40) // We have an applcall
+ ourcall = &APPL->APPLCALL[0];
+ }
+
+ memcpy(NewSess->L4USER, ourcall, 7);
+ memcpy(NewSess->L4MYCALL, ourcall, 7);
+
+ NewSess->CIRCUITINDEX = Index; //OUR INDEX
+ NewSess->CIRCUITID = NEXTID;
+
+ NEXTID++;
+ if (NEXTID == 0)
+ NEXTID++; // Keep Non-Zero
+
+ NewSess->L4TARGET.HOST = HOST;
+ NewSess->L4STATE = 5;
+
+
+ NewSess->SESSIONT1 = L4T1;
+ NewSess->L4WINDOW = (UCHAR)L4DEFAULTWINDOW;
+ NewSess->SESSPACLEN = PACLEN; // Default;
+
+ return NewSess;
+ }
+ Index++;
+ NewSess++;
+ }
+
+ // Table Full
+
+ return NULL;
+}
+
+
+
+
diff --git a/.svn/pristine/15/151b9ce04ab29bd13f02a3d71b7d4be4b771493b.svn-base b/.svn/pristine/15/151b9ce04ab29bd13f02a3d71b7d4be4b771493b.svn-base
index 83b3f07..2a3d766 100644
--- a/.svn/pristine/15/151b9ce04ab29bd13f02a3d71b7d4be4b771493b.svn-base
+++ b/.svn/pristine/15/151b9ce04ab29bd13f02a3d71b7d4be4b771493b.svn-base
@@ -1,3137 +1,3137 @@
-/*
-Copyright 2001-2022 John Wiseman G8BPQ
-
-This file is part of LinBPQ/BPQ32.
-
-LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-LinBPQ/BPQ32 is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
-*/
-
-//
-// DLL to provide interface to allow G8BPQ switch to use WINMOR as a Port Driver
-//
-// Uses BPQ EXTERNAL interface
-//
-
-
-// Version 1.0 January 2009 - Initial Version
-//
-
-// March 22 2010
-
-// Send FAULTS to Monitor Window
-// Force PROTOCOL = WINMOR/PACTOR (to simplifiy Config)
-
-// July 2010
-// Support up to 32 BPQ Ports
-// Support up to 32 Applications
-
-// Version 1.2.1.2 August 2010
-
-// Save Minimized State
-// Handle new "BLOCKED by Busy channel" message from TNC
-
-// Version 1.2.1.4 August 2010
-
-// Add Scan control of BW setting
-// Reset TNC if stuck in Disconnecting
-// Add option to send reports to WL2K
-// Disconnect if appl not available
-
-// Version 1.2.1.5 August 2010
-
-// Updates to WL2K Reporting
-// Send Watchdog polls every minute and restart if no response.
-// Don't connect if channel is busy (unless specifically overridden)
-
-// Version 1.2.1.6 September 2010
-
-// Add option to kill and restart TNC after each transfer
-// Fix PTT operation after Node reconfig
-
-// Version 1.2.2.1 September 2010
-
-// Add option to get config from bpq32.cfg
-// Merge with BPQ32.dll
-
-
-#define _CRT_SECURE_NO_DEPRECATE
-
-#include
-#include
-
-#include "cheaders.h"
-
-#ifdef WIN32
-#include
-#endif
-
-extern int (WINAPI FAR *GetModuleFileNameExPtr)();
-extern int (WINAPI FAR *EnumProcessesPtr)();
-
-
-#define SD_RECEIVE 0x00
-#define SD_SEND 0x01
-#define SD_BOTH 0x02
-
-#include "bpq32.h"
-
-#include "tncinfo.h"
-
-
-#define WSA_ACCEPT WM_USER + 1
-#define WSA_DATA WM_USER + 2
-#define WSA_CONNECT WM_USER + 3
-
-static int Socket_Data(int sock, int error, int eventcode);
-
-int KillTNC(struct TNCINFO * TNC);
-int RestartTNC(struct TNCINFO * TNC);
-int KillPopups(struct TNCINFO * TNC);
-VOID MoveWindows(struct TNCINFO * TNC);
-int SendReporttoWL2K(struct TNCINFO * TNC);
-char * CheckAppl(struct TNCINFO * TNC, char * Appl);
-int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
-BOOL KillOldTNC(char * Path);
-int standardParams(struct TNCINFO * TNC, char * buf);
-
-static char ClassName[]="WINMORSTATUS";
-static char WindowTitle[] = "WINMOR";
-static int RigControlRow = 165;
-
-#define WINMOR
-#define NARROWMODE 21
-#define WIDEMODE 22
-
-#ifndef LINBPQ
-#include
-#endif
-
-extern int SemHeldByAPI;
-
-static RECT Rect;
-
-static int ProcessLine(char * buf, int Port);
-
-// RIGCONTROL COM60 19200 ICOM IC706 5e 4 14.103/U1w 14.112/u1 18.1/U1n 10.12/l1
-
-// There seem to be timing issues when calling SendMessage from multiple threads.
-// Queue and process in main thread
-
-UINT * WINMORTraceQ;
-UINT * SetWindowTextQ;
-
-VOID WritetoTraceSupport(struct TNCINFO * TNC, char * Msg, int Len)
-{
- int index = 0;
- UCHAR * ptr1 = Msg, * ptr2;
- UCHAR Line[1000];
- int LineLen, i;
- UCHAR Save;
- int SaveLen = Len;
- char Time[16];
- time_t T;
- struct tm * tm;
-
- if (Len < 0)
- return;
-
- Save = Msg[Len];
- Msg[Len] = 0;
-
-#ifndef LINBPQ
- index=SendMessage(TNC->hMonitor, LB_SETCURSEL, -1, 0);
-#endif
-
-lineloop:
-
- if (Len > 0)
- {
- // copy text to control a line at a time
-
- ptr2 = memchr(ptr1, 13, Len);
-
- if (ptr2)
- {
- ptr2++;
- LineLen = (int)(ptr2 - ptr1);
- Len -= LineLen;
- memcpy(Line, ptr1, LineLen);
- memcpy(&Line[LineLen - 1], "", 4);
- LineLen += 3;
-
- if ((*ptr2) == 10)
- {
- memcpy(&Line[LineLen], "", 4);
- LineLen += 4;
- ptr2++;
- Len --;
- }
-
- Line[LineLen] = 0;
-
- // If line contains any data above 7f, assume binary and dont display
-
- for (i = 0; i < LineLen; i++)
- {
- if (Line[i] > 126 || Line[i] < 32)
- goto Skip;
- }
-
- // We now also pass to Monitor Window
-
- if (strlen(Line) < 250)
- {
- MESSAGE Monframe;
- memset(&Monframe, 0, sizeof(Monframe));
-
- Monframe.PORT = TNC->Port;
- Monframe.LENGTH = 12 + strlen(Line);
- Monframe.DEST[0] = 1; // Plain Text Monitor
- strcpy(&Monframe.DEST[1], Line);
-
- time(&Monframe.Timestamp);
- BPQTRACE((MESSAGE *)&Monframe, FALSE);
- }
-
-#ifdef LINBPQ
-#else
- index=SendMessage(TNC->hMonitor, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR) Line);
-#endif
- // Write to Web Buffer
-
- T = time(NULL);
- tm = gmtime(&T);
-
- sprintf_s(Time, sizeof(Time),"%02d:%02d ", tm->tm_hour, tm->tm_min);
-
- strcat(TNC->WebBuffer, Time);
- strcat(TNC->WebBuffer, Line);
- strcat(TNC->WebBuffer, "\r\n");
- if (strlen(TNC->WebBuffer) > 4500)
- memmove(TNC->WebBuffer, &TNC->WebBuffer[500], strlen(&TNC->WebBuffer[500]) + 1); // Make sure null is moved
- Skip:
- ptr1 = ptr2;
-
- goto lineloop;
-
- }
-
- // Process incomplete line
-
- for (i = 0; i < Len; i++)
- {
- if (ptr1[i] > 126 || ptr1[i] < 32)
- break;
- }
-
- if (i == Len)
- {
- if (Len < 250)
- {
- MESSAGE Monframe;
- memset(&Monframe, 0, sizeof(Monframe));
-
- Monframe.PORT = TNC->Port;
- Monframe.LENGTH = 12 + Len;
- Monframe.DEST[0] = 1; // Plain Text Monitor
-
- memcpy(&Monframe.DEST[1], ptr1, Len);
- Monframe.DEST[1 + Len] = 0;
-
- time(&Monframe.Timestamp);
- BPQTRACE((MESSAGE *)&Monframe, FALSE);
- }
-
-
-#ifdef LINBPQ
-#else
- index=SendMessage(TNC->hMonitor, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR) ptr1 );
-#endif
- T = time(NULL);
- tm = gmtime(&T);
-
- sprintf_s(Time, sizeof(Time),"%02d:%02d ", tm->tm_hour, tm->tm_min);
- strcat(TNC->WebBuffer, Time);
-
- strcat(TNC->WebBuffer, ptr1);
- strcat(TNC->WebBuffer, "\r\n");
- if (strlen(TNC->WebBuffer) > 4500)
- memmove(TNC->WebBuffer, &TNC->WebBuffer[500], strlen(&TNC->WebBuffer[500]) + 1); // Make sure null is moved
- }
- }
-
-#ifdef LINBPQ
-#else
-
- if (index > 1200)
- do
- index=index=SendMessage(TNC->hMonitor, LB_DELETESTRING, 0, 0);
- while (index > 1000);
-
- if (index > -1)
- index=SendMessage(TNC->hMonitor, LB_SETCARETINDEX,(WPARAM) index, MAKELPARAM(FALSE, 0));
-#endif
- Msg[SaveLen] = Save;
-
-}
-
-VOID MySetWindowTextWithSem(HWND hWnd, char * Msg)
-{
-#ifndef LINBPQ
-
- PMSGWITHLEN buffptr;
-
- buffptr = GetBuff();
-
- if (buffptr)
- {
- buffptr->Len= (UINT)hWnd;
- memcpy(&buffptr->Data[0], Msg, strlen(Msg) + 1);
-
- C_Q_ADD(&SetWindowTextQ, buffptr);
- }
-
-#endif
-}
-
-int C_Q_ADD_NP(VOID *PQ, VOID *PBUFF);
-
-struct SEM SetWindTextSem = {0, 0, 0, 0};
-
-VOID MySetWindowText(HWND hWnd, char * Msg)
-{
-#ifndef LINBPQ
-
- PMSGWITHLEN buffptr;
-
- GetSemaphore(&SetWindTextSem, 61);
- buffptr = zalloc(400);
-
- if (buffptr)
- {
- buffptr->Len= (UINT)hWnd;
- memcpy(&buffptr->Data[0], Msg, strlen(Msg) + 1);
-
- C_Q_ADD_NP(&SetWindowTextQ, buffptr);
- }
-
- FreeSemaphore(&SetWindTextSem);
-#endif
-}
-
-VOID SetWindowTextSupport()
-{
- PMSGWITHLEN Buffer;
-
- while (SetWindowTextQ)
- {
- GetSemaphore(&SetWindTextSem, 61);
- Buffer = Q_REM_NP(&SetWindowTextQ);
- SetWindowText((HWND)Buffer->Len, Buffer->Data);
- FreeSemaphore(&SetWindTextSem);
- free(Buffer);
- }
-}
-
-
-VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len)
-{
- // It seems writing from multiple threads can cause problems in Windows
- // Queue and process in main thread
-
-#ifdef LINBPQ
- WritetoTraceSupport(TNC, Msg, Len);
-}
-#else
- UINT * buffptr;
- BOOL Sem = FALSE;
-
- if (Len < 0)
- return;
-
- // Get semaphore if it isn't set
-
- if (InterlockedExchange(&Semaphore.Flag, 1) == 0)
- {
- Sem = TRUE;
- Semaphore.Gets++;
- }
-
- buffptr = GetBuff();
-
- if (buffptr)
- {
- if (Len > 340)
- Len = 340;
-
- buffptr[1] = (UINT)TNC;
- buffptr[2] = (UINT)Len;
- memcpy(&buffptr[3], Msg, Len + 1);
-
- C_Q_ADD(&WINMORTraceQ, buffptr);
- }
-
- if (Sem)
- FreeSemaphore(&Semaphore);
-
-}
-#endif
-
-static 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
-
- if (_stricmp(buf, "ADDR"))
- return FALSE; // Must start with ADDR
-
- ptr = strtok(NULL, " \t\n\r");
-
- BPQport = Port;
- p_ipad = ptr;
-
- TNC = TNCInfo[BPQport] = malloc(sizeof(struct TNCINFO));
- memset(TNC, 0, sizeof(struct TNCINFO));
-
- TNC->InitScript = malloc(1000);
- TNC->InitScript[0] = 0;
-
- if (p_ipad == NULL)
- p_ipad = strtok(NULL, " \t\n\r");
-
- if (p_ipad == NULL) return (FALSE);
-
- p_port = strtok(NULL, " \t\n\r");
-
- if (p_port == NULL) return (FALSE);
-
- WINMORport = atoi(p_port);
-
- TNC->destaddr.sin_family = AF_INET;
- TNC->destaddr.sin_port = htons(WINMORport);
- TNC->Datadestaddr.sin_family = AF_INET;
- TNC->Datadestaddr.sin_port = htons(WINMORport+1);
-
- TNC->HostName = malloc(strlen(p_ipad)+1);
-
- if (TNC->HostName == NULL) return TRUE;
-
- strcpy(TNC->HostName,p_ipad);
-
- ptr = strtok(NULL, " \t\n\r");
-
- if (ptr)
- {
- if (_stricmp(ptr, "PTT") == 0)
- {
- ptr = strtok(NULL, " \t\n\r");
-
- if (ptr)
- {
- DecodePTTString(TNC, ptr);
- ptr = strtok(NULL, " \t\n\r");
- }
- }
- }
-
- if (ptr)
- {
- if (_memicmp(ptr, "PATH", 4) == 0)
- {
- p_cmd = strtok(NULL, "\n\r");
- if (p_cmd) TNC->ProgramPath = _strdup(p_cmd);
- }
- }
-
- // Read Initialisation lines
-
- while(TRUE)
- {
- if (GetLine(buf) == 0)
- return TRUE;
-
- strcpy(errbuf, buf);
-
- if (memcmp(buf, "****", 4) == 0)
- return TRUE;
-
- ptr = strchr(buf, ';');
- if (ptr)
- {
- *ptr++ = 13;
- *ptr = 0;
- }
-
- if ((_memicmp(buf, "CAPTURE", 7) == 0) || (_memicmp(buf, "PLAYBACK", 8) == 0))
- {} // Ignore
- else
-/*
- if (_memicmp(buf, "PATH", 4) == 0)
- {
- char * Context;
- p_cmd = strtok_s(&buf[5], "\n\r", &Context);
- if (p_cmd) TNC->ProgramPath = _strdup(p_cmd);
- }
- else
-*/
- if (_memicmp(buf, "STARTINROBUST", 13) == 0)
- TNC->StartInRobust = TRUE;
-
- else
- if (_memicmp(buf, "ROBUST", 6) == 0)
- {
- if (_memicmp(&buf[7], "TRUE", 4) == 0)
- TNC->Robust = TRUE;
-
- strcat (TNC->InitScript, buf);
- }
- else if (standardParams(TNC, buf) == FALSE)
- strcat (TNC->InitScript, buf);
- }
-
-
- return (TRUE);
-}
-
-
-
-void WINMORThread(void * portptr);
-VOID ProcessDataSocketData(int port);
-int ConnecttoWINMOR(int port);
-static int ProcessReceivedData(struct TNCINFO * TNC);
-int V4ProcessReceivedData(struct TNCINFO * TNC);
-VOID ReleaseTNC(struct TNCINFO * TNC);
-VOID SuspendOtherPorts(struct TNCINFO * ThisTNC);
-VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
-VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len);
-
-static time_t ltime;
-
-
-static SOCKADDR_IN sinx;
-static SOCKADDR_IN rxaddr;
-
-static int addrlen=sizeof(sinx);
-
-
-
-VOID ChangeMYC(struct TNCINFO * TNC, char * Call)
-{
- UCHAR TXMsg[100];
- int datalen;
-
- if (strcmp(Call, TNC->CurrentMYC) == 0)
- return; // No Change
-
- strcpy(TNC->CurrentMYC, Call);
-
-// send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
-
- datalen = sprintf(TXMsg, "MYC %s\r\n", Call);
- send(TNC->TCPSock,TXMsg, datalen, 0);
-
-// send(TNC->TCPSock, "CODEC TRUE\r\n", 12, 0);
-// TNC->StartSent = TRUE;
-
- send(TNC->TCPSock, "MYC\r\n", 5, 0);
-}
-
-static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
-{
- int i,winerr;
- size_t datalen;
- PMSGWITHLEN buffptr;
- char txbuff[500];
- unsigned int bytes;
- size_t txlen = 0;
- char ErrMsg[255];
- size_t Param;
- HKEY hKey=0;
- struct TNCINFO * TNC = TNCInfo[port];
- struct STREAMINFO * STREAM = &TNC->Streams[0];
- struct ScanEntry * Scan;
- fd_set readfs;
- fd_set writefs;
- fd_set errorfs;
- struct timeval timeout;
-
- if (TNC == NULL)
- return 0; // Port not defined
-
- switch (fn)
- {
- case 1: // poll
-
- // Check session limit timer
-
- if ((STREAM->Connecting || STREAM->Connected) && !STREAM->Disconnecting)
- {
- if (TNC->SessionTimeLimit && STREAM->ConnectTime && time(NULL) > (TNC->SessionTimeLimit + STREAM->ConnectTime))
- {
- send(TNC->TCPSock,"DISCONNECT\r\n", 12, 0);
- STREAM->Disconnecting = TRUE;
- }
- }
-
- while (TNC->PortRecord->UI_Q) // Release anything accidentally put on UI_Q
- {
- buffptr = Q_REM(&TNC->PortRecord->UI_Q);
- ReleaseBuffer(buffptr);
- }
-
-
- if (TNC->Busy) // Count down to clear
- {
- if ((TNC->BusyFlags & CDBusy) == 0) // TNC Has reported not busy
- {
- TNC->Busy--;
- if (TNC->Busy == 0)
- SetWindowText(TNC->xIDC_CHANSTATE, "Clear");
- strcpy(TNC->WEB_CHANSTATE, "Clear");
- }
- }
-
- if (TNC->ConnectCmd && TNC->BusyDelay)
- {
- // Still Busy?
-
- if (InterlockedCheckBusy(TNC) == FALSE)
- {
- // No, so send
-
- send(TNC->TCPSock, TNC->ConnectCmd, (int)strlen(TNC->ConnectCmd), 0);
- TNC->Streams[0].Connecting = TRUE;
-
- memset(TNC->Streams[0].RemoteCall, 0, 10);
- memcpy(TNC->Streams[0].RemoteCall, &TNC->ConnectCmd[8], strlen(TNC->ConnectCmd)-10);
-
- sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- free(TNC->ConnectCmd);
- TNC->ConnectCmd = 0;
-
- TNC->BusyDelay = 0;
- }
- else
- {
- // Wait Longer
-
- TNC->BusyDelay--;
-
- if (TNC->BusyDelay == 0)
- {
- // Timed out - Send Error Response
-
- PMSGWITHLEN buffptr = GetBuff();
-
- if (buffptr == 0) return (0); // No buffers, so ignore
-
- buffptr->Len = 39;
- memcpy(buffptr->Data,"Sorry, Can't Connect - Channel is busy\r", 39);
-
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
- free(TNC->ConnectCmd);
-
- sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- }
- }
- }
-
- if (TNC->HeartBeat++ > 600 || (TNC->Streams[0].Connected && TNC->HeartBeat > 50)) // Every Minute unless connected
- {
- if (TNC->HeartBeat > 600 && TNC->hWnd)
- {
- char wtext[100];
- sprintf (wtext, "WINMOR Sound Card TNC - BPQ %s", TNC->PortRecord->PORTCONTROL.PORTDESCRIPTION);
- MySetWindowText(TNC->hWnd, wtext);
- }
-
- TNC->HeartBeat = 0;
-
- if (TNC->CONNECTED)
- {
- // Probe link
-
- if (TNC->Streams[0].Connecting || TNC->Streams[0].Connected)
- send(TNC->TCPSock, "MODE\r\n", 6, 0);
- else
- {
- if (time(NULL) - TNC->WinmorRestartCodecTimer > 900) // 15 mins
- {
- send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
- send(TNC->TCPSock, "CODEC TRUE\r\n", 12, 0);
- }
- else
- send(TNC->TCPSock, "STATE\r\n", 7, 0);
- }
- }
- }
-
- if (TNC->FECMode)
- {
- if (TNC->FECIDTimer++ > 6000) // ID every 10 Mins
- {
- if (!TNC->Busy)
- {
- TNC->FECIDTimer = 0;
- send(TNC->TCPSock, "SENDID 0\r\n", 10, 0);
- }
- }
- if (TNC->FECPending) // Check if FEC Send needed
- {
- if (!TNC->Busy)
- {
- TNC->FECPending = 0;
-
- if (TNC->FEC1600)
- send(TNC->TCPSock,"FECSEND 1600\r\n", 14, 0);
- else
- send(TNC->TCPSock,"FECSEND 500\r\n", 13, 0);
- }
- }
- }
-
- if (STREAM->NeedDisc)
- {
- STREAM->NeedDisc--;
-
- if (STREAM->NeedDisc == 0)
- {
- // Send the DISCONNECT
-
- send(TNC->TCPSock, "DISCONNECT\r\n", 12, 0);
- }
- }
-
- if (TNC->DiscPending)
- {
- TNC->DiscPending--;
-
- if (TNC->DiscPending == 0)
- {
- // Too long in Disc Pending - Kill and Restart TNC
-
- if (TNC->PID)
- {
- KillTNC(TNC);
- RestartTNC(TNC);
- }
- }
- }
-
- if (TNC->TimeSinceLast++ > 800) // Allow 10 secs for Keepalive
- {
- // Restart TNC
-
- if (TNC->ProgramPath && TNC->CONNECTED)
- {
- if (strstr(TNC->ProgramPath, "WINMOR TNC"))
- {
- struct tm * tm;
- char Time[80];
-
- TNC->Restarts++;
- TNC->LastRestart = time(NULL);
-
- tm = gmtime(&TNC->LastRestart);
-
- sprintf_s(Time, sizeof(Time),"%04d/%02d/%02d %02d:%02dZ",
- tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
-
- SetWindowText(TNC->xIDC_RESTARTTIME, Time);
- strcpy(TNC->WEB_RESTARTTIME, Time);
-
- sprintf_s(Time, sizeof(Time),"%d", TNC->Restarts);
- SetWindowText(TNC->xIDC_RESTARTS, Time);
- strcpy(TNC->WEB_RESTARTS, Time);
-
- KillTNC(TNC);
- RestartTNC(TNC);
-
- TNC->TimeSinceLast = 0;
- }
- }
- }
-
- if (TNC->PortRecord->ATTACHEDSESSIONS[0] && TNC->Streams[0].Attached == 0)
- {
- // New Attach
-
- int calllen;
- char Msg[80];
-
- TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
-
- TNC->Streams[0].Attached = TRUE;
-
- calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, TNC->Streams[0].MyCall);
- TNC->Streams[0].MyCall[calllen] = 0;
-
- // Stop Listening, and set MYCALL to user's call
-
- send(TNC->TCPSock, "LISTEN FALSE\r\n", 14, 0);
- ChangeMYC(TNC, TNC->Streams[0].MyCall);
-
- // Stop other ports in same group
-
- SuspendOtherPorts(TNC);
-
- sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- // Stop Scanning
-
- sprintf(Msg, "%d SCANSTOP", TNC->Port);
-
- Rig_Command( (TRANSPORTENTRY *) -1, Msg);
-
- }
-
- if (TNC->Streams[0].Attached)
- CheckForDetach(TNC, 0, &TNC->Streams[0], TidyClose, ForcedClose, CloseComplete);
-
- if (TNC->Streams[0].ReportDISC)
- {
- TNC->Streams[0].ReportDISC = FALSE;
- buff->PORT = 0;
- return -1;
- }
-
-
-
- if (TNC->CONNECTED == FALSE && TNC->CONNECTING == FALSE)
- {
- // See if time to reconnect
-
- time(<ime);
- if (ltime - TNC->lasttime > 9 )
- {
- ConnecttoWINMOR(port);
- TNC->lasttime = ltime;
- }
- }
-
- FD_ZERO(&readfs);
-
- if (TNC->CONNECTED) FD_SET(TNC->TCPDataSock,&readfs);
-
- FD_ZERO(&writefs);
-
- if (TNC->BPQtoWINMOR_Q) FD_SET(TNC->TCPDataSock,&writefs); // Need notification of busy clearing
-
- FD_ZERO(&errorfs);
-
- if (TNC->CONNECTING || TNC->CONNECTED) FD_SET(TNC->TCPDataSock,&errorfs);
-
- timeout.tv_sec = 0;
- timeout.tv_usec = 0; // poll
-
- if (select((int)TNC->TCPDataSock + 1, &readfs, &writefs, &errorfs, &timeout) > 0)
- {
- // See what happened
-
- if (FD_ISSET(TNC->TCPDataSock, &readfs))
- ProcessDataSocketData(port);
-
- if (FD_ISSET(TNC->TCPDataSock, &writefs))
- {
- // Write block has cleared. Send rest of packet
-
- buffptr=Q_REM(&TNC->BPQtoWINMOR_Q);
- txlen = buffptr->Len;
- memcpy(txbuff,buffptr->Data,txlen);
- bytes=send(TNC->TCPSock, (const char FAR *)&txbuff, (int)txlen, 0);
- ReleaseBuffer(buffptr);
- }
-
- if (FD_ISSET(TNC->TCPDataSock, &errorfs))
- {
- i=sprintf(ErrMsg, "WINMOR Data Connection lost for BPQ Port %d\r\n", port);
- WritetoConsole(ErrMsg);
- TNC->CONNECTING = FALSE;
- TNC->CONNECTED = FALSE;
- TNC->Streams[0].ReportDISC = TRUE;
- }
- }
-
- // See if any frames for this port
-
- if (TNC->WINMORtoBPQ_Q != 0)
- {
- buffptr=Q_REM(&TNC->WINMORtoBPQ_Q);
-
- datalen = buffptr->Len;
-
- buff->PORT = 0; // Compatibility with Kam Driver
- buff->PID = 0xf0;
- memcpy(&buff->L2DATA[0], buffptr->Data, datalen); // Data goes to +7, but we have an extra byte
- datalen = buffptr->Len;
-
- datalen += sizeof(void *) + 4;
- PutLengthinBuffer(buff, (int)datalen);
-
- ReleaseBuffer(buffptr);
-
- return (1);
- }
-
- return (0);
-
- case 2: // send
-
- if (!TNC->CONNECTED)
- {
- // Send Error Response
-
- PMSGWITHLEN buffptr = GetBuff();
-
- if (buffptr == 0) return (0); // No buffers, so ignore
-
- buffptr->Len = 36;
- memcpy(buffptr->Data, "No Connection to WINMOR Virtual TNC\r", 36);
-
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
-
- return 0; // Don't try if not connected
- }
-
- if (TNC->Streams[0].BPQtoPACTOR_Q) //Used for CTEXT
- {
- PMSGWITHLEN buffptr = Q_REM(&TNC->Streams[0].BPQtoPACTOR_Q);
- txlen = buffptr->Len;
- memcpy(txbuff, buffptr->Data, txlen);
- bytes = send(TNC->TCPDataSock, txbuff, (int)txlen, 0);
- STREAM->bytesTXed += bytes;
- WritetoTrace(TNC, txbuff, (int)txlen);
- ReleaseBuffer(buffptr);
- }
-
- if (TNC->SwallowSignon)
- {
- TNC->SwallowSignon = FALSE; // Discard *** connected
- return 0;
- }
-
- txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1); // 1 as no PID
-
- if (TNC->Streams[0].Connected)
- {
- STREAM->PacketsSent++;
-
- if (STREAM->PacketsSent == 3)
- {
- if (TNC->Robust)
- send(TNC->TCPSock, "ROBUST TRUE\r\n", 13, 0);
- else
- send(TNC->TCPSock, "ROBUST FALSE\r\n", 14, 0);
- }
-
- bytes = send(TNC->TCPDataSock,buff->L2DATA, (int)txlen, 0);
- STREAM->bytesTXed += bytes;
- WritetoTrace(TNC, &buff->L2DATA[0], (int)txlen);
-
- }
- else
- {
- if (_memicmp(buff->L2DATA, "D\r", 2) == 0)
- {
- TNC->Streams[0].ReportDISC = TRUE; // Tell Node
- return 0;
- }
-
- if (TNC->FECMode)
- {
- char Buffer[300];
- int len;
-
- // Send FEC Data
-
- buff->L2DATA[txlen] = 0;
- len = sprintf(Buffer, "%-9s: %s", TNC->Streams[0].MyCall, &buff->L2DATA);
-
- send(TNC->TCPDataSock, Buffer, len, 0);
-
- if (TNC->BusyFlags)
- {
- TNC->FECPending = 1;
- }
- else
- {
- if (TNC->FEC1600)
- send(TNC->TCPSock,"FECSEND 1600\r\n", 14, 0);
- else
- send(TNC->TCPSock,"FECSEND 500\r\n", 13, 0);
- }
- return 0;
- }
-
-
- // See if Local command (eg RADIO)
-
- if (_memicmp(&buff->L2DATA[0], "RADIO ", 6) == 0)
- {
- char cmd[56];
-
- strcpy(cmd, &buff->L2DATA[6]);
- sprintf(&buff->L2DATA[0], "%d %s", TNC->Port, &cmd);
-
-
- if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &buff->L2DATA[0]))
- {
- }
- else
- {
- PMSGWITHLEN buffptr = GetBuff();
-
- if (buffptr == 0) return 1; // No buffers, so ignore
-
- buffptr->Len = sprintf(buffptr->Data, "%s", &buff->L2DATA[0]);
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
- }
- return 1;
- }
-
- if (_memicmp(&buff->L2DATA[0], "OVERRIDEBUSY", 12) == 0)
- {
- PMSGWITHLEN buffptr = GetBuff();
-
- TNC->OverrideBusy = TRUE;
-
- if (buffptr)
- {
- buffptr->Len = sprintf(&buffptr->Data[0], "Winmor} OK\r");
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
- }
-
- return 0;
-
- }
-
- if (_memicmp(&buff->L2DATA[0], "MAXCONREQ", 9) == 0)
- {
- if (buff->L2DATA[9] != 13)
- {
- // Limit connects
-
- int tries = atoi(&buff->L2DATA[10]);
- int len;
-
- if (tries > 10) tries = 10;
- len = sprintf(&buff->L2DATA[0], "MAXCONREQ %d\r\nMAXCONREQ\r\n", tries);
-
- send(TNC->TCPSock, &buff->L2DATA[0], len, 0);
- return 0;
- }
- }
-
- if (_memicmp(&buff->L2DATA[0], "SessionTimeLimit", 16) == 0)
- {
- if (buff->L2DATA[16] != 13)
- {
- PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
-
- TNC->SessionTimeLimit = atoi(&buff->L2DATA[16]) * 60;
-
- if (buffptr)
- {
- buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "Winmor} OK\r");
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
- }
- return 0;
- }
- }
-
- if ((_memicmp(buff->L2DATA, "BW 500", 6) == 0) || (_memicmp(buff->L2DATA, "BW 1600", 7) == 0))
- {
- // Generate a local response
-
- PMSGWITHLEN buffptr = GetBuff();
-
- if (_memicmp(buff->L2DATA, "BW 500", 6) == 0)
- TNC->WL2KMode = 21;
- else
- TNC->WL2KMode = 22;
-
- if (buffptr)
- {
- buffptr->Len = sprintf(&buffptr->Data[0], "Winmor} OK\r");
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
- }
- TNC->WinmorCurrentMode = 0; // So scanner will set next value
- }
-
- if (_memicmp(buff->L2DATA, "CODEC TRUE", 9) == 0)
- TNC->StartSent = TRUE;
-
- if (_memicmp(buff->L2DATA, "ROBUST", 6) == 0)
- {
- if (_memicmp(&buff->L2DATA[7], "TRUE", 4) == 0)
- TNC->Robust = TRUE;
- else
- TNC->Robust = FALSE;
- }
-
- if (_memicmp(buff->L2DATA, "D\r", 2) == 0)
- {
- TNC->Streams[0].ReportDISC = TRUE; // Tell Node
- return 0;
- }
-
- if (_memicmp(buff->L2DATA, "FEC\r", 4) == 0 || _memicmp(buff->L2DATA, "FEC ", 4) == 0)
- {
- TNC->FECMode = TRUE;
- TNC->FECIDTimer = 0;
- send(TNC->TCPSock,"FECRCV TRUE\r\nFECRCV\r\n", 21, 0);
-
- if (_memicmp(buff->L2DATA, "FEC 1600", 8) == 0)
- TNC->FEC1600 = TRUE;
- else
- TNC->FEC1600 = FALSE;
-
- return 0;
- }
-
- // See if a Connect Command. If so, start codec and set Connecting
-
- if (toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect
- {
- char Connect[80] = "CONNECT ";
-
- memcpy(&Connect[8], &buff->L2DATA[2], txlen);
- txlen += 6;
- Connect[txlen++] = 0x0a;
- Connect[txlen] = 0;
-
- _strupr(Connect);
-
- ChangeMYC(TNC, TNC->Streams[0].MyCall);
-
- // See if Busy
-
- if (InterlockedCheckBusy(TNC))
- {
- // Channel Busy. Unless override set, wait
-
- if (TNC->OverrideBusy == 0)
- {
- // Save Command, and wait up to 10 secs
-
- sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- TNC->ConnectCmd = _strdup(Connect);
- TNC->BusyDelay = TNC->BusyWait * 10; // BusyWait secs
- return 0;
- }
- }
-
- TNC->OverrideBusy = FALSE;
-
- bytes = send(TNC->TCPSock, Connect, (int)txlen, 0);
- TNC->Streams[0].Connecting = TRUE;
-
- memset(TNC->Streams[0].RemoteCall, 0, 10);
- memcpy(TNC->Streams[0].RemoteCall, &Connect[8], txlen-10);
-
- sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
- }
- else
- {
- buff->L2DATA[txlen++] = 0x0a;
- bytes = send(TNC->TCPSock, &buff->L2DATA[0], (int)txlen, 0);
- }
- }
- if (bytes != txlen)
- {
-
- // WINMOR doesn't seem to recover from a blocked write. For now just reset
-
- winerr = WSAGetLastError();
- sprintf(ErrMsg, "WINMOR Write Failed for port %d - error code = %d\r\n", port, winerr);
- WritetoConsole(ErrMsg);
- closesocket(TNC->TCPSock);
- TNC->CONNECTED = FALSE;
-
- return (0);
- }
-
- return (0);
-
- case 3:
-
- // CHECK IF OK TO SEND (And check TNC Status)
-
- if (TNC->Streams[0].Attached == 0)
- return TNC->CONNECTED << 8 | 1;
-
- return (TNC->CONNECTED << 8 | TNC->Streams[0].Disconnecting << 15); // OK
-
- break;
-
- case 4: // reinit
-
- return (0);
-
- case 5: // Close
-
- send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
- Sleep(100);
- shutdown(TNC->TCPDataSock, SD_BOTH);
- shutdown(TNC->TCPSock, SD_BOTH);
- Sleep(100);
-
- closesocket(TNC->TCPDataSock);
- closesocket(TNC->TCPSock);
-
- if (TNC->PID && TNC->WeStartedTNC)
- {
- KillTNC(TNC);
- }
-
- return (0);
-
- case 6: // Scan Stop Interface
-
- Param = (size_t)buff;
-
- if (Param == 2) // Check Permission (shouldn't happen)
- {
- Debugprintf("Scan Check Permission called on FLDIGI");
- return 1; // OK to change
- }
-
- if (!TNC->TCPSock)
- return 0; // No connection so no interlock
-
- if (Param == 1) // Request Permission
- {
- if (TNC->ConnectPending)
- return TRUE; // Not OK to Change
-
- if (TNC->CONNECTED)
- {
- TNC->GavePermission = TRUE;
- send(TNC->TCPSock, "LISTEN FALSE\r\n", 14, 0);
- }
- return FALSE;
- }
-
- if (Param == 3) // Release Permission
- {
- if (TNC->CONNECTED)
- {
- if (TNC->GavePermission)
- {
- TNC->GavePermission = FALSE;
- send(TNC->TCPSock, "LISTEN TRUE\r\n", 13, 0);
- }
- }
- return 0;
- }
-
- // Param is Address of a struct ScanEntry
-
- Scan = (struct ScanEntry *)buff;
-
-
- if (Scan->Bandwidth == 'W') // Set Wide Mode
- {
- if (TNC->WinmorCurrentMode != 1600)
- {
- if (TNC->WinmorCurrentMode == 0)
- if (TNC->CONNECTED)
- send(TNC->TCPSock, "LISTEN TRUE\r\n", 13, 0);
-
- if (TNC->CONNECTED)
- send(TNC->TCPSock, "BW 1600\r\n", 9, 0);
- TNC->WinmorCurrentMode = 1600;
- }
- TNC->WL2KMode = 22;
- return 0;
- }
-
-
- if (Scan->Bandwidth == 'N') // Set Narrow Mode
- {
- if (TNC->WinmorCurrentMode != 500)
- {
- if (TNC->WinmorCurrentMode == 0)
- if (TNC->CONNECTED)
- send(TNC->TCPSock, "LISTEN TRUE\r\n", 13, 0);
-
- TNC->WinmorCurrentMode = 500;
- if (TNC->CONNECTED)
- send(TNC->TCPSock, "BW 500\r\n", 8, 0);
- }
- TNC->WL2KMode = 21;
- return 0;
- }
-
- if (Scan->Bandwidth == 'X') // Dont Allow Connects
- {
- if (TNC->WinmorCurrentMode != 0)
- {
- if (TNC->CONNECTED)
- send(TNC->TCPSock, "LISTEN FALSE\r\n", 14, 0);
- TNC->WinmorCurrentMode = 0;
- }
-
- TNC->WL2KMode = 0;
- return 0;
- }
-
- return 0;
- }
- return 0;
-}
-
-VOID ReleaseTNC(struct TNCINFO * TNC)
-{
- // Set mycall back to Node or Port Call, and Start Scanner
-
- UCHAR TXMsg[256];
- char wtext[100];
-
- ChangeMYC(TNC, TNC->NodeCall);
-
- if (TNC->CONNECTED)
- send(TNC->TCPSock, "LISTEN TRUE\r\nMAXCONREQ 4\r\n", 26, 0);
-
- strcpy(TNC->WEB_TNCSTATE, "Free");
- MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- if (TNC->hWnd)
- {
- sprintf (wtext, "WINMOR Sound Card TNC - BPQ %s", TNC->PortRecord->PORTCONTROL.PORTDESCRIPTION);
- MySetWindowText(TNC->hWnd, wtext);
- }
-
- // Start Scanner
-
- sprintf(TXMsg, "%d SCANSTART 15", TNC->Port);
-
- Rig_Command( (TRANSPORTENTRY *) -1, TXMsg);
-
- ReleaseOtherPorts(TNC);
-
-}
-
-VOID SuspendOtherPorts(struct TNCINFO * ThisTNC)
-{
- // Disable other TNCs in same Interlock Group
-
- struct TNCINFO * TNC;
- int i;
- int rxInterlock = ThisTNC->RXRadio;
- int txInterlock = ThisTNC->TXRadio;
-
- if (rxInterlock == 0 || txInterlock == 0)
- return;
-
- for (i = 1; i <= MAXBPQPORTS; i++)
- {
- TNC = TNCInfo[i];
- if (TNC == NULL)
- continue;
-
- if (TNC == ThisTNC)
- continue;
-
- if (rxInterlock == TNC->RXRadio || txInterlock == TNC->TXRadio) // Same Group
- if (TNC->SuspendPortProc)
- TNC->SuspendPortProc(TNC, ThisTNC);
- }
-}
-
-VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC)
-{
- // Enable other TNCs in same Interlock Group
-
- struct TNCINFO * TNC;
- int i;
- int rxInterlock = ThisTNC->RXRadio;
- int txInterlock = ThisTNC->TXRadio;
-
- if (rxInterlock == 0 && txInterlock == 0)
- return;
-
- for (i=1; i <= MAXBPQPORTS; i++)
- {
- TNC = TNCInfo[i];
- if (TNC == NULL)
- continue;
-
- if (TNC == ThisTNC)
- continue;
-
- if (rxInterlock == TNC->RXRadio || txInterlock == TNC->TXRadio) // Same Group
- if (TNC->ReleasePortProc)
- TNC->ReleasePortProc(TNC);
- }
-}
-
-VOID WinmorSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC)
-{
- if (TNC->CONNECTED)
- send(TNC->TCPSock, "CODEC FALSE\r\n", 14, 0);
-
- if (TNC->Busy)
- {
- TNC->Busy = FALSE; // Can't clear detector if CODEC off.
- MySetWindowText(TNC->xIDC_CHANSTATE, "Clear");
- strcpy(TNC->WEB_CHANSTATE, "Clear");
- }
-}
-
-VOID WinmorReleasePort(struct TNCINFO * TNC)
-{
- if (TNC->CONNECTED)
- send(TNC->TCPSock, "CODEC TRUE\r\n", 13, 0);
-}
-
-extern char WebProcTemplate[];
-extern char sliderBit[];
-
-static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
-{
- int Len = sprintf(Buff, WebProcTemplate, TNC->Port, TNC->Port, "WINMOR Status", "WINMOR Status");
-
- if (TNC->TXFreq)
- Len += sprintf(&Buff[Len], sliderBit, TNC->TXOffset, TNC->TXOffset);
-
-
- Len += sprintf(&Buff[Len], "");
- Len += sprintf(&Buff[Len], "| Comms State | %s |
", TNC->WEB_COMMSSTATE);
- Len += sprintf(&Buff[Len], "| TNC State | %s |
", TNC->WEB_TNCSTATE);
- Len += sprintf(&Buff[Len], "| Mode | %s |
", TNC->WEB_MODE);
- Len += sprintf(&Buff[Len], "| Channel State | %s |
", TNC->WEB_CHANSTATE);
- Len += sprintf(&Buff[Len], "| Proto State | %s |
", TNC->WEB_PROTOSTATE);
- Len += sprintf(&Buff[Len], "| Traffic | %s |
", TNC->WEB_TRAFFIC);
-// Len += sprintf(&Buff[Len], "| TNC Restarts | |
", TNC->WEB_RESTARTS);
- Len += sprintf(&Buff[Len], "
");
-
- Len += sprintf(&Buff[Len], "", TNC->WebBuffer);
- Len = DoScanLine(TNC, Buff, Len);
-
- return Len;
-}
-
-
-void * WinmorExtInit(EXTPORTDATA * PortEntry)
-{
- int i, port;
- char Msg[255];
- char * ptr;
- APPLCALLS * APPL;
- struct TNCINFO * TNC;
- char Aux[100] = "MYAUX ";
- char Appl[11];
- char * TempScript;
-
- //
- // Will be called once for each WINMOR port
- //
- // The Socket to connect to is in IOBASE
- //
-
- 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\n");
- WritetoConsole(Msg);
-
- return ExtProc;
- }
-
- TNC->Port = port;
- TNC->PortRecord = PortEntry;
-
- if (TNC->ProgramPath)
- TNC->WeStartedTNC = RestartTNC(TNC);
-
- TNC->PortRecord->PORTCONTROL.HWType = TNC->Hardware = H_WINMOR;
-
- if (TNC->BusyWait == 0)
- TNC->BusyWait = 10;
-
- if (TNC->BusyHold == 0)
- TNC->BusyHold = 1;
-
-
- if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
- memcpy(TNC->NodeCall, MYNODECALL, 10);
- else
- ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
-
- if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
- TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
-
- PortEntry->PORTCONTROL.PROTOCOL = 10;
- PortEntry->PORTCONTROL.PORTQUALITY = 0;
- PortEntry->MAXHOSTMODESESSIONS = 1;
- PortEntry->SCANCAPABILITIES = SIMPLE; // Scan Control - pending connect only
-
- if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
- PortEntry->PORTCONTROL.PORTPACLEN = 236;
-
- TNC->SuspendPortProc = WinmorSuspendPort;
- TNC->ReleasePortProc = WinmorReleasePort;
-
- TNC->ModemCentre = 1500; // WINMOR is always 1500 Offset
-
- ptr=strchr(TNC->NodeCall, ' ');
- if (ptr) *(ptr) = 0; // Null Terminate
-
- // Set Essential Params and MYCALL
-
- // Put overridable ones on front, essential ones on end
-
- TempScript = malloc(1000);
-
- strcpy(TempScript, "DebugLog True\r\n");
- strcat(TempScript, "CWID False\r\n");
- strcat(TempScript, "BW 1600\r\n");
- strcat(TempScript, "ROBUST False\r\n");
- strcat(TempScript, "MODE AUTO\r\n");
-
- strcat(TempScript, TNC->InitScript);
-
- free(TNC->InitScript);
- TNC->InitScript = TempScript;
-
- TNC->WL2KMode = 22; // in case not scanning
-
- // Set MYCALL
-
- strcat(TNC->InitScript,"FECRCV True\r\n");
- strcat(TNC->InitScript,"AUTOBREAK True\r\n");
-
- sprintf(Msg, "MYC %s\r\nCODEC TRUE\r\nLISTEN TRUE\r\nMYC\r\n", TNC->NodeCall);
- strcat(TNC->InitScript, Msg);
- strcat(TNC->InitScript,"PROCESSID\r\n");
-
- for (i = 0; i < 32; i++)
- {
- APPL=&APPLCALLTABLE[i];
-
- if (APPL->APPLCALL_TEXT[0] > ' ')
- {
- char * ptr;
- memcpy(Appl, APPL->APPLCALL_TEXT, 10);
- ptr=strchr(Appl, ' ');
-
- if (ptr)
- {
- *ptr++ = ',';
- *ptr = 0;
- }
-
- strcat(Aux, Appl);
- }
- }
- strcat(TNC->InitScript, Aux);
- strcat(TNC->InitScript,"\r\nMYAUX\r\n");
-
- strcpy(TNC->CurrentMYC, TNC->NodeCall);
-
- if (TNC->WL2K == NULL)
- if (PortEntry->PORTCONTROL.WL2KInfo.RMSCall[0]) // Alrerady decoded
- TNC->WL2K = &PortEntry->PORTCONTROL.WL2KInfo;
-
- if (TNC->destaddr.sin_family == 0)
- {
- // not defined in config file, so use localhost and port from IOBASE
-
- TNC->destaddr.sin_family = AF_INET;
- TNC->destaddr.sin_port = htons(PortEntry->PORTCONTROL.IOBASE);
- TNC->Datadestaddr.sin_family = AF_INET;
- TNC->Datadestaddr.sin_port = htons(PortEntry->PORTCONTROL.IOBASE+1);
-
- TNC->HostName=malloc(10);
-
- if (TNC->HostName != NULL)
- strcpy(TNC->HostName,"127.0.0.1");
-
- }
-
- PortEntry->PORTCONTROL.TNC = TNC;
-
- TNC->WebWindowProc = WebProc;
- TNC->WebWinX = 520;
- TNC->WebWinY = 500;
- TNC->WebBuffer = zalloc(5000);
-
- TNC->WEB_COMMSSTATE = zalloc(100);
- TNC->WEB_TNCSTATE = zalloc(100);
- TNC->WEB_CHANSTATE = zalloc(100);
- TNC->WEB_BUFFERS = zalloc(100);
- TNC->WEB_PROTOSTATE = zalloc(100);
- TNC->WEB_RESTARTTIME = zalloc(100);
- TNC->WEB_RESTARTS = zalloc(100);
-
- TNC->WEB_MODE = zalloc(20);
- TNC->WEB_TRAFFIC = zalloc(100);
-
-
-#ifndef LINBPQ
-
- CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 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, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "Channel State", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_CHANSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "Proto State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_PROTOSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "0 0 0 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "TNC Restarts", WS_CHILD | WS_VISIBLE,10,138,100,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_RESTARTS = CreateWindowEx(0, "STATIC", "0", WS_CHILD | WS_VISIBLE,116,138,40,20 , TNC->hDlg, NULL, hInstance, NULL);
- CreateWindowEx(0, "STATIC", "Last Restart", WS_CHILD | WS_VISIBLE,140,138,100,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_RESTARTTIME = CreateWindowEx(0, "STATIC", "Never", WS_CHILD | WS_VISIBLE,250,138,200,20, TNC->hDlg, NULL, hInstance, NULL);
-
- TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
- LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL,
- 0,170,250,300, TNC->hDlg, NULL, hInstance, NULL);
-
- TNC->ClientHeight = 450;
- TNC->ClientWidth = 500;
-
- TNC->hMenu = CreatePopupMenu();
-
- AppendMenu(TNC->hMenu, MF_STRING, WINMOR_KILL, "Kill Winmor TNC");
- AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTART, "Kill and Restart Winmor TNC");
- AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTARTAFTERFAILURE, "Restart TNC after failed Connection");
- AppendMenu(TNC->hMenu, MF_STRING, ARDOP_ABORT, "Abort Current Session");
-
- CheckMenuItem(TNC->hMenu, WINMOR_RESTARTAFTERFAILURE, (TNC->RestartAfterFailure) ? MF_CHECKED : MF_UNCHECKED);
-
- MoveWindows(TNC);
-#endif
- Consoleprintf("WINMOR Host %s %d", TNC->HostName, htons(TNC->destaddr.sin_port));
-
- ConnecttoWINMOR(port);
-
- time(&TNC->lasttime); // Get initial time value
-
- return ExtProc;
-}
-
-int ConnecttoWINMOR(int port)
-{
- _beginthread(WINMORThread, 0, (void *)(size_t)port);
-
- return 0;
-}
-
-VOID WINMORThread(void * portptr)
-{
- // Opens both sockets and looks for data on control socket. Data socket is polled from BG,
- // but we need fast response to control messages for PTT porcessing
-
- int port = (int)(size_t)portptr;
-
- char Msg[255];
- int err, i, ret;
- u_long param=1;
- BOOL bcopt=TRUE;
- struct hostent * HostEnt;
- struct TNCINFO * TNC = TNCInfo[port];
- fd_set readfs;
- fd_set errorfs;
- struct timeval timeout;
- if (TNC->HostName == NULL)
- return;
-
- TNC->CONNECTING = TRUE;
-
- Sleep(3000); // Allow init to complete
-
-#ifdef WIN32
- if (strcmp(TNC->HostName, "127.0.0.1") == 0)
- {
- // can only check if running on local host
-
- TNC->PID = GetListeningPortsPID(TNC->destaddr.sin_port);
- if (TNC->PID == 0)
- {
- TNC->CONNECTING = FALSE;
- return; // Not listening so no point trying to connect
- }
- }
-#endif
-
-// // If we started the TNC make sure it is still running.
-
-// if (!IsProcess(TNC->PID))
-// {
-// RestartTNC(TNC);
-// Sleep(3000);
-// }
-
-
- TNC->destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
- TNC->Datadestaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
-
- if (TNC->destaddr.sin_addr.s_addr == INADDR_NONE)
- {
- // Resolve name to address
-
- HostEnt = gethostbyname (TNC->HostName);
-
- if (!HostEnt)
- {
- TNC->CONNECTING = FALSE;
- return; // Resolve failed
- }
- memcpy(&TNC->destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
- memcpy(&TNC->Datadestaddr.sin_addr.s_addr,HostEnt->h_addr,4);
-
- }
-
- if (TNC->TCPSock)
- closesocket(TNC->TCPSock);
-
- TNC->TCPSock = 0;
-
- if (TNC->TCPDataSock)
- closesocket(TNC->TCPDataSock);
-
- TNC->TCPDataSock = 0;
-
- TNC->TCPSock=socket(AF_INET,SOCK_STREAM,0);
-
- if (TNC->TCPSock == INVALID_SOCKET)
- {
- i=sprintf(Msg, "Socket Failed for WINMOR socket - error code = %d\r\n", WSAGetLastError());
- WritetoConsole(Msg);
-
- TNC->CONNECTING = FALSE;
- return;
- }
-
- setsockopt (TNC->TCPSock, 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(TNC->TCPSock, (LPSOCKADDR) &sinx, addrlen) != 0 )
- {
- //
- // Bind Failed
- //
-
- i=sprintf(Msg, "Bind Failed for WINMOR socket - error code = %d\r\n", WSAGetLastError());
- WritetoConsole(Msg);
-
- closesocket(TNC->TCPSock);
- TNC->TCPSock = 0;
- TNC->CONNECTING = FALSE;
-
- return;
- }
-
- if (connect(TNC->TCPSock,(LPSOCKADDR) &TNC->destaddr,sizeof(TNC->destaddr)) == 0)
- {
- //
- // Connected successful
- //
- }
- else
- {
- if (TNC->Alerted == FALSE)
- {
- err=WSAGetLastError();
- i=sprintf(Msg, "Connect Failed for WINMOR socket - error code = %d\r\n", err);
- WritetoConsole(Msg);
- sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC failed");
- MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
- TNC->Alerted = TRUE;
- }
-
- closesocket(TNC->TCPSock);
- TNC->CONNECTING = FALSE;
- TNC->TCPSock = 0;
-
- return;
- }
-
- Sleep(1000);
-
- TNC->LastFreq = 0; // so V4 display will be updated
-
- TNC->TCPDataSock=socket(AF_INET,SOCK_STREAM,0);
-
- setsockopt (TNC->TCPDataSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
-
- if (TNC->TCPDataSock == INVALID_SOCKET)
- {
- i=sprintf(Msg, "Socket Failed for WINMOR socket - error code = %d\r\n", WSAGetLastError());
- WritetoConsole(Msg);
-
- closesocket(TNC->TCPSock);
- TNC->TCPSock = 0;
- TNC->CONNECTING = FALSE;
-
- return;
- }
-
- if (bind(TNC->TCPDataSock, (LPSOCKADDR) &sinx, addrlen) != 0 )
- {
- //
- // Bind Failed
- //
-
- i=sprintf(Msg, "Bind Failed for WINMOR Data socket - error code = %d\r\n", WSAGetLastError());
- WritetoConsole(Msg);
-
- closesocket(TNC->TCPSock);
- closesocket(TNC->TCPDataSock);
- TNC->TCPSock = 0;
- TNC->TCPDataSock = 0;
- TNC->CONNECTING = FALSE;
-
- return;
- }
-
- if (connect(TNC->TCPDataSock,(LPSOCKADDR) &TNC->Datadestaddr,sizeof(TNC->Datadestaddr)) == 0)
- {
- ioctlsocket (TNC->TCPDataSock,FIONBIO,¶m); // Set nonblocking
- TNC->CONNECTED = TRUE;
- TNC->CONNECTING = FALSE;
-
- // Send INIT script
-
- send(TNC->TCPSock, TNC->InitScript , (int)strlen(TNC->InitScript), 0);
- TNC->Alerted = TRUE;
-
- if (TNC->Hardware == H_V4)
- sprintf(TNC->WEB_COMMSSTATE, "Connected to V4 TNC");
- else
- sprintf(TNC->WEB_COMMSSTATE, "Connected to WINMOR TNC");
-
- GetSemaphore(&Semaphore, 40);
- MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
- FreeSemaphore(&Semaphore);
-
- }
- else
- {
- sprintf(Msg, "Connect Failed for WINMOR Data socket Port %d - error code = %d\r\n", port, WSAGetLastError());
- WritetoConsole(Msg);
-
- closesocket(TNC->TCPSock);
- closesocket(TNC->TCPDataSock);
- TNC->TCPSock = 0;
- TNC->TCPDataSock = 0;
- TNC->CONNECTING = FALSE;
-
- return;
- }
-
- TNC->HeartBeat = 0;
-
- while (TRUE)
- {
- FD_ZERO(&readfs);
- FD_ZERO(&errorfs);
-
- FD_SET(TNC->TCPSock,&readfs);
- FD_SET(TNC->TCPSock,&errorfs);
-
- timeout.tv_sec = 90;
- timeout.tv_usec = 0; // We should get messages more frequently that this
-
- ret = select((int)TNC->TCPSock + 1, &readfs, NULL, &errorfs, &timeout);
-
- if (ret == SOCKET_ERROR)
- {
- printf("Select failed %d ", WSAGetLastError());
- goto Lost;
- }
- if (ret > 0)
- {
- // See what happened
-
- if (FD_ISSET(TNC->TCPSock, &readfs))
- {
- if (TNC->Hardware == H_V4)
- V4ProcessReceivedData(TNC);
- else
- ProcessReceivedData(TNC);
- }
-
- if (FD_ISSET(TNC->TCPSock, &errorfs))
- {
-Lost:
- sprintf(Msg, "WINMOR Connection lost for Port %d\r\n", TNC->Port);
- WritetoConsole(Msg);
-
- sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
- GetSemaphore(&Semaphore, 40);
- MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
- FreeSemaphore(&Semaphore);
-
- TNC->CONNECTED = FALSE;
- TNC->Alerted = FALSE;
-
- if (TNC->PTTMode)
- Rig_PTT(TNC, FALSE); // Make sure PTT is down
-
- if (TNC->Streams[0].Attached)
- TNC->Streams[0].ReportDISC = TRUE;
-
- closesocket(TNC->TCPSock);
- closesocket(TNC->TCPDataSock);
-
- TNC->TCPSock = 0;
- TNC->TCPDataSock = 0;
-
- return;
- }
- }
- else
- {
- // 90 secs without data. Shouldn't happen
-
- sprintf(Msg, "WINMOR Connection Timeout Port %d\r\n", TNC->Port);
- WritetoConsole(Msg);
-
- sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
- GetSemaphore(&Semaphore, 40);
- MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
- FreeSemaphore(&Semaphore);
-
- TNC->CONNECTED = FALSE;
- TNC->Alerted = FALSE;
-
- if (TNC->PTTMode)
- Rig_PTT(TNC, FALSE); // Make sure PTT is down
-
- if (TNC->Streams[0].Attached)
- TNC->Streams[0].ReportDISC = TRUE;
-
- send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
-
- Sleep(100);
- shutdown(TNC->TCPDataSock, SD_BOTH);
- shutdown(TNC->TCPSock, SD_BOTH);
- Sleep(100);
-
- closesocket(TNC->TCPDataSock);
- closesocket(TNC->TCPSock);
- TNC->TCPDataSock = 0;
- TNC->TCPSock= 0;
-
- if (TNC->PID && TNC->WeStartedTNC)
- {
- KillTNC(TNC);
- RestartTNC(TNC);
- }
- return;
- }
- }
-}
-
-#ifdef WIN32
-
-BOOL CALLBACK EnumTNCWindowsProc(HWND hwnd, LPARAM lParam)
-{
- char wtext[100];
- struct TNCINFO * TNC = (struct TNCINFO *)lParam;
- UINT ProcessId;
-
- GetWindowText(hwnd,wtext,99);
-
- if (memcmp(wtext,"WINMOR Sound Card TNC", 21) == 0)
- {
- GetWindowThreadProcessId(hwnd, &ProcessId);
-
- if (TNC->PID == ProcessId)
- {
- // Our Process
-
- TNC->hWnd = hwnd; // save so we can reset title when sessicn closes
- sprintf (wtext, "WINMOR Sound Card TNC - BPQ %s", TNC->PortRecord->PORTCONTROL.PORTDESCRIPTION);
- SetWindowText(hwnd, wtext);
- return FALSE;
- }
- }
-
- return (TRUE);
-}
-#endif
-
-VOID ProcessResponse(struct TNCINFO * TNC, UCHAR * Buffer, int MsgLen)
-{
- // Response on WINMOR control channel. Could be a reply to a command, or
- // an Async Response
-
- PMSGWITHLEN buffptr;
- struct STREAMINFO * STREAM = &TNC->Streams[0];
-
- Buffer[MsgLen - 2] = 0;
-
- if (_memicmp(Buffer, "FAULT failure to Restart Sound card", 20) == 0)
- {
- Debugprintf(Buffer);
-
- // Force a restart
-
- send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
- send(TNC->TCPSock, "CODEC TRUE\r\n", 12, 0);
- }
- else
- {
- TNC->TimeSinceLast = 0;
- }
-
-
- if (_memicmp(Buffer, "STATE ", 6) == 0)
- {
- Debugprintf(Buffer);
-
- if (_memicmp(&Buffer[6], "OFFLINE", 7) == 0)
- {
- // Force a restart
-
- send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
- send(TNC->TCPSock, "CODEC TRUE\r\n", 12, 0);
- }
- return;
- }
-
- Buffer[MsgLen - 2] = 0; // Remove CRLF
-
- if (_memicmp(Buffer, "PTT T", 5) == 0)
- {
- TNC->Busy = TNC->BusyHold * 10; // BusyHold delay
-
- if (TNC->PTTMode)
- Rig_PTT(TNC, TRUE);
- return;
- }
- if (_memicmp(Buffer, "PTT F", 5) == 0)
- {
- if (TNC->PTTMode)
- Rig_PTT(TNC, FALSE);
- return;
- }
-
- if (_memicmp(Buffer, "BUSY TRUE", 9) == 0)
- {
- TNC->BusyFlags |= CDBusy;
- TNC->Busy = TNC->BusyHold * 10; // BusyHold delay
-
- SetWindowText(TNC->xIDC_CHANSTATE, "Busy");
- strcpy(TNC->WEB_CHANSTATE, "Busy");
-
- TNC->WinmorRestartCodecTimer = time(NULL);
- return;
- }
-
- if (_memicmp(Buffer, "BUSY FALSE", 10) == 0)
- {
- TNC->BusyFlags &= ~CDBusy;
- if (TNC->BusyHold)
- strcpy(TNC->WEB_CHANSTATE, "BusyHold");
- else
- strcpy(TNC->WEB_CHANSTATE, "Clear");
-
- SetWindowText(TNC->xIDC_CHANSTATE, TNC->WEB_CHANSTATE);
- TNC->WinmorRestartCodecTimer = time(NULL);
- return;
- }
-
- if (_memicmp(Buffer, "TARGET", 6) == 0)
- {
- Debugprintf(Buffer);
- GetSemaphore(&Semaphore, 50);
- WritetoTrace(TNC, Buffer, MsgLen - 2);
- FreeSemaphore(&Semaphore);
- memcpy(TNC->TargetCall, &Buffer[7], 10);
- return;
- }
-
- if (_memicmp(Buffer, "OFFSET", 6) == 0)
- {
-// WritetoTrace(TNC, Buffer, MsgLen - 2);
-// memcpy(TNC->TargetCall, &Buffer[7], 10);
- return;
- }
-
- if (_memicmp(Buffer, "CONNECTED", 9) == 0)
- {
- char Call[11];
- char * ptr;
- APPLCALLS * APPL;
- char * ApplPtr = APPLS;
- int App;
- char Appl[10];
- struct WL2KInfo * WL2K = TNC->WL2K;
-
- Debugprintf(Buffer);
-
- GetSemaphore(&Semaphore, 50);
- WritetoTrace(TNC, Buffer, MsgLen - 2);
- FreeSemaphore(&Semaphore);
-
- STREAM->ConnectTime = time(NULL);
- STREAM->bytesRXed = STREAM->bytesTXed = STREAM->PacketsSent = 0;
-
- if (TNC->StartInRobust)
- send(TNC->TCPSock, "ROBUST TRUE\r\n", 13, 0);
-
- memcpy(Call, &Buffer[10], 10);
-
- ptr = strchr(Call, ' ');
- if (ptr) *ptr = 0;
-
- TNC->HadConnect = TRUE;
-
- if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0)
- {
- TRANSPORTENTRY * SESS;
-
- // Incomming Connect
-
- TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
-
- // Stop other ports in same group
-
- SuspendOtherPorts(TNC);
-
- GetSemaphore(&Semaphore, 50);
-
- ProcessIncommingConnectEx(TNC, Call, 0, TRUE, TRUE);
- FreeSemaphore(&Semaphore);
-
- SESS = TNC->PortRecord->ATTACHEDSESSIONS[0];
-
- SESS->Mode = TNC->WL2KMode;
-
- if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT"))
- {
- sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", TNC->Streams[0].RemoteCall, TNC->TargetCall, TNC->RIG->Valchar);
- SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq
- SESS->Mode = TNC->WL2KMode;
- }
- else
- {
- sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", TNC->Streams[0].RemoteCall, TNC->TargetCall);
- if (WL2K)
- {
- SESS->Frequency = WL2K->Freq;
- SESS->Mode = WL2K->mode;
- }
- }
-
- if (WL2K)
- strcpy(SESS->RMSCall, WL2K->RMSCall);
-
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- // Check for ExcludeList
-
- if (ExcludeList[0])
- {
- if (CheckExcludeList(SESS->L4USER) == FALSE)
- {
- char Status[64];
-
- TidyClose(TNC, 0);
- sprintf(Status, "%d SCANSTART 15", TNC->Port);
- Rig_Command( (TRANSPORTENTRY *) -1, Status);
- Debugprintf("WINMOR Call from %s rejected", Call);
- return;
- }
- }
-
- // IF WE HAVE A PERMITTED CALLS LIST, SEE IF HE IS IN IT
-
- if (TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS)
- {
- UCHAR * ptr = TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS;
-
- while (TRUE)
- {
- if (memcmp(SESS->L4USER, ptr, 6) == 0) // Ignore SSID
- break;
-
- ptr += 7;
-
- if ((*ptr) == 0) // Not in list
- {
- char Status[64];
-
- TidyClose(TNC, 0);
- sprintf(Status, "%d SCANSTART 15", TNC->Port);
- Rig_Command( (TRANSPORTENTRY *) -1, Status);
- Debugprintf("WINMOR Call from %s not in ValidCalls - rejected", Call);
- return;
- }
- }
- }
-
- if (STREAM->BPQtoPACTOR_Q) //Used for CTEXT
- {
- PMSGWITHLEN buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q);
-
- send(TNC->TCPDataSock, buffptr->Data, (int)buffptr->Len, 0);
- STREAM->bytesTXed += (int)buffptr->Len;
- WritetoTrace(TNC, buffptr->Data, (int)buffptr->Len);
- ReleaseBuffer(buffptr);
- }
-
- // See which application the connect is for
-
- for (App = 0; App < 32; App++)
- {
- APPL=&APPLCALLTABLE[App];
- memcpy(Appl, APPL->APPLCALL_TEXT, 10);
- ptr=strchr(Appl, ' ');
-
- if (ptr)
- *ptr = 0;
-
- if (_stricmp(TNC->TargetCall, Appl) == 0)
- break;
- }
-
- if (App < 32)
- {
- char AppName[13];
-
- memcpy(AppName, &ApplPtr[App * sizeof(struct CMDX)], 12);
- AppName[12] = 0;
-
- // Make sure app is available
-
- if (CheckAppl(TNC, AppName))
- {
- MsgLen = sprintf(Buffer, "%s\r", AppName);
-
- GetSemaphore(&Semaphore, 50);
-
- buffptr = GetBuff();
-
- if (buffptr == 0)
- {
- FreeSemaphore(&Semaphore);
- return; // No buffers, so ignore
- }
-
- buffptr->Len = MsgLen;
- memcpy(buffptr->Data, Buffer, MsgLen);
-
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
-
- FreeSemaphore(&Semaphore);
-
- TNC->SwallowSignon = TRUE;
-
- // Save Appl Call in case needed for
-
- }
- else
- {
- char Msg[] = "Application not available\r\n";
-
- // Send a Message, then a disconenct
-
- send(TNC->TCPDataSock, Msg, (int)strlen(Msg), 0);
- STREAM->NeedDisc = 100; // 10 secs
- }
- }
-
- return;
- }
- else
- {
- // Connect Complete
-
- char Reply[80];
- int ReplyLen;
-
- GetSemaphore(&Semaphore, 50);
-
- buffptr = GetBuff();
-
- if (buffptr == 0)
- {
- FreeSemaphore(&Semaphore);
- return; // No buffers, so ignore
- }
- ReplyLen = sprintf(Reply, "*** Connected to %s\r", &Buffer[10]);
-
- buffptr->Len = ReplyLen;
- memcpy(buffptr->Data, Reply, ReplyLen);
-
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
-
- FreeSemaphore(&Semaphore);
-
- TNC->Streams[0].Connecting = FALSE;
- TNC->Streams[0].Connected = TRUE; // Subsequent data to data channel
-
-
- if (TNC->RIG)
- sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall, TNC->RIG->Valchar);
- else
- sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
-
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- UpdateMH(TNC, Call, '+', 'O');
- return;
- }
- }
-
- if (_memicmp(Buffer, "DISCONNECTED", 12) == 0)
- {
- Debugprintf(Buffer);
-
- if (TNC->FECMode)
- return;
-
- if (TNC->StartSent)
- {
- TNC->StartSent = FALSE; // Disconnect reported following start codec
- return;
- }
-
- if (TNC->Streams[0].Connecting)
- {
- // Report Connect Failed, and drop back to command mode
-
- TNC->Streams[0].Connecting = FALSE;
-
- GetSemaphore(&Semaphore, 50);
-
- buffptr = GetBuff();
-
- if (buffptr == 0)
- {
- FreeSemaphore(&Semaphore);
- return; // No buffers, so ignore
- }
-
- buffptr->Len = sprintf(buffptr->Data, "Winmor} Failure with %s\r", TNC->Streams[0].RemoteCall);
-
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
-
- FreeSemaphore(&Semaphore);
-
- if (TNC->RestartAfterFailure)
- {
- if (TNC->PID)
- {
- KillTNC(TNC);
- RestartTNC(TNC);
- }
- }
-
- return;
- }
-
-
- // Release Session
-
- if (TNC->Streams[0].Connected)
- {
- hookL4SessionDeleted(TNC, STREAM);
-
- GetSemaphore(&Semaphore, 50);
- WritetoTrace(TNC, Buffer, MsgLen - 2);
- FreeSemaphore(&Semaphore);
- }
-
-
- TNC->Streams[0].Connecting = FALSE;
- TNC->Streams[0].Connected = FALSE; // Back to Command Mode
- TNC->Streams[0].ReportDISC = TRUE; // Tell Node
-
- if (TNC->Streams[0].Disconnecting) //
- ReleaseTNC(TNC);
-
- TNC->Streams[0].Disconnecting = FALSE;
-
- return;
- }
-
- if (_memicmp(Buffer, "MONCALL", 7) == 0)
- {
- Debugprintf(Buffer);
-
- // Add to MHEARD
-
- GetSemaphore(&Semaphore, 50);
- WritetoTrace(TNC, Buffer, MsgLen - 2);
- FreeSemaphore(&Semaphore);
- UpdateMH(TNC, &Buffer[8], '!', 0);
-
- if (!TNC->FECMode)
- return; // If in FEC mode pass ID messages to user.
- }
-
- if (_memicmp(Buffer, "CMD", 3) == 0)
- {
- return;
- }
-
- if (_memicmp(Buffer, "BUFFERS", 7) == 0)
- {
- int inq, inrx, Sent, BPM;
-
- sscanf(&Buffer[8], "%d%d%d%d%d", &inq, &inrx, &TNC->Streams[0].BytesOutstanding, &Sent, &BPM);
-
- if (TNC->Streams[0].BytesOutstanding == 0)
- {
- // all sent
-
- if (TNC->Streams[0].Disconnecting) // Disconnect when all sent
- {
- if (STREAM->NeedDisc == 0)
- STREAM->NeedDisc = 60; // 6 secs
- }
-// else
-// if (TNC->TXRXState == 'S')
-// send(TNC->TCPSock,"OVER\r\n", 6, 0);
-
- }
- else
- {
- // Make sure Node Keepalive doesn't kill session.
-
- TRANSPORTENTRY * SESS = TNC->PortRecord->ATTACHEDSESSIONS[0];
-
- if (SESS)
- {
- SESS->L4KILLTIMER = 0;
- SESS = SESS->L4CROSSLINK;
- if (SESS)
- SESS->L4KILLTIMER = 0;
- }
- }
-
- SetWindowText(TNC->xIDC_TRAFFIC, &Buffer[8]);
- strcpy(TNC->WEB_TRAFFIC, &Buffer[8]);
- return;
- }
-
- Debugprintf(Buffer);
-
- if (_memicmp(Buffer, "MODE", 4) == 0)
- {
- // Debugprintf("WINMOR RX: %s", Buffer);
-
- strcpy(TNC->WEB_MODE, &Buffer[5]);
- GetSemaphore(&Semaphore, 50);
- MySetWindowText(TNC->xIDC_MODE, &Buffer[5]);
- FreeSemaphore(&Semaphore);
- return;
- }
-
- if (_memicmp(Buffer, "PENDING", 6) == 0)
- return;
-
- if (_memicmp(Buffer, "FAULT", 5) == 0)
- {
- WritetoTrace(TNC, Buffer, MsgLen - 2);
- return;
- }
-
- if (_memicmp(Buffer, "NEWSTATE", 8) == 0)
- {
- TNC->WinmorRestartCodecTimer = time(NULL);
-
- SetWindowText(TNC->xIDC_PROTOSTATE, &Buffer[9]);
- strcpy(TNC->WEB_PROTOSTATE, &Buffer[9]);
-
- if (_memicmp(&Buffer[9], "CONNECTPENDING", 14) == 0) // Save Pending state for scan control
- TNC->ConnectPending = TRUE;
- else
- TNC->ConnectPending = FALSE;
-
- if (_memicmp(&Buffer[9], "DISCONNECTING", 13) == 0) // So we can timout stuck discpending
- {
- TNC->DiscPending = 600;
- return;
- }
- if (_memicmp(&Buffer[9], "DISCONNECTED", 12) == 0)
- {
- TNC->DiscPending = FALSE;
- return;
- }
-
- if (strcmp(&Buffer[9], "ISS") == 0) // Save Pending state for scan control
- TNC->TXRXState = 'S';
- else if (strcmp(&Buffer[9], "IRS") == 0)
- TNC->TXRXState = 'R';
-
- return;
- }
-
-
- if (_memicmp(Buffer, "PROCESSID", 9) == 0)
- {
- HANDLE hProc;
- char ExeName[256] = "";
-
- TNC->PID = atoi(&Buffer[10]);
-
-#ifdef WIN32
-
- // Get the File Name in case we want to restart it.
-
- if (TNC->ProgramPath == NULL)
- {
- if (GetModuleFileNameExPtr)
- {
- hProc = OpenProcess(PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, FALSE, TNC->PID);
-
- if (hProc)
- {
- GetModuleFileNameExPtr(hProc, 0, ExeName, 255);
- CloseHandle(hProc);
-
- TNC->ProgramPath = _strdup(ExeName);
- }
- }
- }
-
- // Set Window Title to reflect BPQ Port Description
-
- EnumWindows(EnumTNCWindowsProc, (LPARAM)TNC);
-#endif
- }
-
- if ((_memicmp(Buffer, "FAULT Not from state FEC", 24) == 0) || (_memicmp(Buffer, "FAULT Blocked by Busy Lock", 24) == 0))
- {
- if (TNC->FECMode)
- {
- Sleep(1000);
-
- if (TNC->FEC1600)
- send(TNC->TCPSock,"FECSEND 1600\r\n", 14, 0);
- else
- send(TNC->TCPSock,"FECSEND 500\r\n", 13, 0);
- return;
- }
- }
-
- if (_memicmp(Buffer, "PLAYBACKDEVICES", 15) == 0)
- {
- TNC->PlaybackDevices = _strdup(&Buffer[16]);
- }
- // Others should be responses to commands
-
- if (_memicmp(Buffer, "BLOCKED", 6) == 0)
- {
- WritetoTrace(TNC, Buffer, MsgLen - 2);
- return;
- }
-
- if (_memicmp(Buffer, "OVER", 4) == 0)
- {
- WritetoTrace(TNC, Buffer, MsgLen - 2);
- return;
- }
-
- GetSemaphore(&Semaphore, 50);
-
- buffptr = GetBuff();
-
- if (buffptr == 0)
- {
- FreeSemaphore(&Semaphore);
- return; // No buffers, so ignore
- }
-
- buffptr->Len = sprintf(buffptr->Data, "Winmor} %s\r", Buffer);
-
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
- FreeSemaphore(&Semaphore);
-}
-
-static int ProcessReceivedData(struct TNCINFO * TNC)
-{
- int InputLen, MsgLen;
- char * ptr, * ptr2;
- char Buffer[2000];
-
- // May have several messages per packet, or message split over packets
-
- if (TNC->InputLen > 1000) // Shouldnt have lines longer than this on command connection
- TNC->InputLen=0;
-
- InputLen=recv(TNC->TCPSock, &TNC->TCPBuffer[TNC->InputLen], 1000 - TNC->InputLen, 0);
-
- if (InputLen == 0 || InputLen == SOCKET_ERROR)
- {
- // Does this mean closed?
-
- closesocket(TNC->TCPSock);
- closesocket(TNC->TCPDataSock);
-
- TNC->TCPSock = 0;
- TNC->TCPDataSock = 0;
-
- TNC->CONNECTED = FALSE;
- TNC->Streams[0].ReportDISC = TRUE;
-
- return 0;
- }
-
- TNC->InputLen += InputLen;
-
-loop:
-
- ptr = memchr(TNC->TCPBuffer, '\n', TNC->InputLen);
-
- if (ptr) // CR in buffer
- {
- ptr2 = &TNC->TCPBuffer[TNC->InputLen];
- ptr++; // Assume LF Follows CR
-
- if (ptr == ptr2)
- {
- // Usual Case - single meg in buffer
-
- ProcessResponse(TNC, TNC->TCPBuffer, TNC->InputLen);
- TNC->InputLen=0;
- }
- else
- {
- // buffer contains more that 1 message
-
- MsgLen = TNC->InputLen - (int)(ptr2-ptr);
-
- memcpy(Buffer, TNC->TCPBuffer, MsgLen);
-
- ProcessResponse(TNC, Buffer, MsgLen);
- memmove(TNC->TCPBuffer, ptr, TNC->InputLen-MsgLen);
-
- TNC->InputLen -= MsgLen;
- goto loop;
- }
- }
- return 0;
-}
-
-
-VOID ProcessDataSocketData(int port)
-{
- // Info on Data Socket - just packetize and send on
-
- struct TNCINFO * TNC = TNCInfo[port];
- struct STREAMINFO * STREAM = &TNC->Streams[0];
-
- int InputLen, PacLen = 236;
- PMSGWITHLEN buffptr;
- char * msg;
-
- TNC->TimeSinceLast = 0;
-
-loop:
- buffptr = GetBuff();
-
- if (buffptr == NULL) return; // No buffers, so ignore
-
- InputLen = recv(TNC->TCPDataSock, buffptr->Data, PacLen, 0);
-
- if (InputLen == -1)
- {
- ReleaseBuffer(buffptr);
- return;
- }
-
-
- //Debugprintf("Winmor: RXD %d bytes", InputLen);
-
- if (InputLen == 0)
- {
- // Does this mean closed?
-
- sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
- MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
-
- TNC->CONNECTING = FALSE;
- TNC->CONNECTED = FALSE;
- TNC->Streams[0].ReportDISC = TRUE;
-
- ReleaseBuffer(buffptr);
- return;
- }
-
- STREAM->bytesRXed += InputLen;
-
- msg = &buffptr->Data[0];
- msg[InputLen] = 0;
-
- WritetoTrace(TNC, msg, InputLen);
-
- if (TNC->FECMode)
- {
- InputLen = (int)strlen(&buffptr->Data[0]);
-
- if (msg[InputLen - 1] == 3) // End of errored block
- msg[InputLen++] = 13; // Add CR
-
- }
- buffptr->Len = InputLen;
- C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
-
- goto loop;
-}
-
-/*
-INT_PTR CALLBACK ConfigDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
-{
- int Cmd = LOWORD(wParam);
-
- switch (message)
- {
- case WM_INITDIALOG:
- {
- struct TNCINFO * TNC = (struct TNCINFO * )lParam;
- char * ptr1, *ptr2;
- int ptr3 = 0;
- char Line[1000];
- int len;
-
- ptr1 = TNC->CaptureDevices;
-
- if (!ptr1)
- return 0; // No Devices
-
-
- while (ptr2 = strchr(ptr1, ','))
- {
- len = ptr2 - ptr1;
- memcpy(&Line[ptr3], ptr1, len);
- ptr3 += len;
- Line[ptr3++] = '\r';
- Line[ptr3++] = '\n';
-
- ptr1 = ++ptr2;
- }
- Line[ptr3] = 0;
- strcat(Line, ptr1);
-
- SetDlgItemText(hDlg, IDC_CAPTURE, Line);
-
- ptr3 = 0;
-
- ptr1 = TNC->PlaybackDevices;
-
- if (!ptr1)
- return 0; // No Devices
-
-
- while (ptr2 = strchr(ptr1, ','))
- {
- len = ptr2 - ptr1;
- memcpy(&Line[ptr3], ptr1, len);
- ptr3 += len;
- Line[ptr3++] = '\r';
- Line[ptr3++] = '\n';
-
- ptr1 = ++ptr2;
- }
- Line[ptr3] = 0;
- strcat(Line, ptr1);
-
- SetDlgItemText(hDlg, IDC_PLAYBACK, Line);
-
- SendDlgItemMessage(hDlg, IDC_PLAYBACK, EM_SETSEL, -1, 0);
-
-// KillTNC(TNC);
-
- return TRUE;
- }
-
- case WM_SIZING:
- {
- return TRUE;
- }
-
- case WM_ACTIVATE:
-
-// SendDlgItemMessage(hDlg, IDC_MESSAGE, EM_SETSEL, -1, 0);
-
- break;
-
-
- case WM_COMMAND:
-
-
- if (Cmd == IDCANCEL)
- {
- EndDialog(hDlg, LOWORD(wParam));
- return (INT_PTR)TRUE;
- }
-
- return (INT_PTR)TRUE;
-
- break;
- }
- return (INT_PTR)FALSE;
-}
-*/
-
-#ifdef LINBPQ
-#include
-#include
-#endif
-
-
-int KillTNC(struct TNCINFO * TNC)
-{
- if (TNC->ProgramPath && _memicmp(TNC->ProgramPath, "REMOTE:", 7) == 0)
- {
- // Try to Kill TNC on a remote host
-
- SOCKET sock = socket(AF_INET,SOCK_DGRAM,0);
- struct sockaddr_in destaddr;
- char Msg[256];
- int Len;
-
- if (sock == INVALID_SOCKET)
- return 0;
-
- destaddr.sin_family = AF_INET;
- destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
- destaddr.sin_port = htons(8500);
-
- if (destaddr.sin_addr.s_addr == INADDR_NONE)
- {
- // Resolve name to address
-
- struct hostent * HostEnt = gethostbyname (TNC->HostName);
-
- if (!HostEnt)
- return 0; // Resolve failed
-
- memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
- }
-
- if (TNC->PID)
- Len = sprintf(Msg, "KILL %d", TNC->PID);
- else
- Len = sprintf(Msg, "KILLBYNAME %s", &TNC->ProgramPath[7]);
-
- sendto(sock, Msg, Len, 0, (struct sockaddr *)&destaddr, sizeof(destaddr));
- Sleep(100);
- closesocket(sock);
-
- TNC->PID = 0; // So we don't try again
- return 1; // Cant tell if it worked, but assume ok
- }
-
- if (TNC->PID == 0)
- return 0;
-
-#ifdef WIN32
- {
- HANDLE hProc;
-
- Debugprintf("KillTNC Called for Pid %d", TNC->PID);
-
- if (TNC->PTTMode)
- Rig_PTT(TNC, FALSE); // Make sure PTT is down
-
- hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, TNC->PID);
-
- if (hProc)
- {
- TerminateProcess(hProc, 0);
- CloseHandle(hProc);
- }
- }
-#else
-
- printf("KillTNC Called for Pid %d Returned %d\n", TNC->PID, kill(TNC->PID, SIGTERM));
-
-#endif
- TNC->PID = 0; // So we don't try again
-
- return 0;
-}
-
-BOOL RestartTNC(struct TNCINFO * TNC)
-{
- if (TNC->ProgramPath == NULL || TNC->DontRestart)
- return 0;
-
- if (_memicmp(TNC->ProgramPath, "REMOTE:", 7) == 0)
- {
- int n;
-
- // Try to start TNC on a remote host
-
- SOCKET sock = socket(AF_INET,SOCK_DGRAM,0);
- struct sockaddr_in destaddr;
-
- Debugprintf("trying to restart TNC %s", TNC->ProgramPath);
-
- if (sock == INVALID_SOCKET)
- return 0;
-
- destaddr.sin_family = AF_INET;
- destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
- destaddr.sin_port = htons(8500);
-
- if (destaddr.sin_addr.s_addr == INADDR_NONE)
- {
- // Resolve name to address
-
- struct hostent * HostEnt = gethostbyname (TNC->HostName);
-
- if (!HostEnt)
- return 0; // Resolve failed
-
- memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
- }
-
- n = sendto(sock, TNC->ProgramPath, (int)strlen(TNC->ProgramPath), 0, (struct sockaddr *)&destaddr, sizeof(destaddr));
-
- Debugprintf("Restart TNC - sendto returned %d", n);
-
- Sleep(100);
- closesocket(sock);
-
- return 1; // Cant tell if it worked, but assume ok
- }
-
- // Not Remote
-
- // Extract any parameters from command string
-
-#ifndef WIN32
- {
- char * arg_list[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
- pid_t child_pid;
- char * Copy, * Context;
- signal(SIGCHLD, SIG_IGN); // Silently (and portably) reap children.
-
- Copy = _strdup(TNC->ProgramPath); // Save as strtok mangles it
-
- arg_list[0] = strtok_s(Copy, " \n\r", &Context);
- if (arg_list[0])
- arg_list[1] = strtok_s(NULL, " \n\r", &Context);
- if (arg_list[1])
- arg_list[2] = strtok_s(NULL, " \n\r", &Context);
- if (arg_list[2])
- arg_list[3] = strtok_s(NULL, " \n\r", &Context);
- if (arg_list[3])
- arg_list[4] = strtok_s(NULL, " \n\r", &Context);
- if (arg_list[4])
- arg_list[5] = strtok_s(NULL, " \n\r", &Context);
- if (arg_list[5])
- arg_list[6] = strtok_s(NULL, " \n\r", &Context);
- if (arg_list[6])
- arg_list[7] = strtok_s(NULL, " \n\r", &Context);
-
- // Fork and Exec TNC
-
- printf("Trying to start %s\n", TNC->ProgramPath);
-
- /* Duplicate this process. */
-
- child_pid = fork ();
-
- if (child_pid == -1)
- {
- printf ("StartTNC fork() Failed\n");
- free(Copy);
- return 0;
- }
-
- if (child_pid == 0)
- {
- execvp (arg_list[0], arg_list);
-
- /* The execvp function returns only if an error occurs. */
-
- printf ("Failed to start TNC\n");
- exit(0); // Kill the new process
- }
- else
- {
- TNC->PID = child_pid;
- printf("Started TNC, Process ID = %d\n", TNC->PID);
- }
- free(Copy);
- return TRUE;
- }
-#else
- {
- int n = 0;
-
- STARTUPINFO SInfo; // pointer to STARTUPINFO
- PROCESS_INFORMATION PInfo; // pointer to PROCESS_INFORMATION
- char workingDirectory[256];
- int i = strlen(TNC->ProgramPath);
-
- SInfo.cb=sizeof(SInfo);
- SInfo.lpReserved=NULL;
- SInfo.lpDesktop=NULL;
- SInfo.lpTitle=NULL;
- SInfo.dwFlags=0;
- SInfo.cbReserved2=0;
- SInfo.lpReserved2=NULL;
-
- Debugprintf("RestartTNC Called for %s", TNC->ProgramPath);
-
- strcpy(workingDirectory, TNC->ProgramPath);
-
- while (i--)
- {
- if (workingDirectory[i] == '\\' || workingDirectory[i] == '/')
- {
- workingDirectory[i] = 0;
- break;
- }
- }
-
- while (KillOldTNC(TNC->ProgramPath) && n++ < 100)
- {
- Sleep(100);
- }
-
- if (CreateProcess(NULL, TNC->ProgramPath, NULL, NULL, FALSE,0, NULL, workingDirectory, &SInfo, &PInfo))
- {
- Debugprintf("Restart TNC OK");
- TNC->PID = PInfo.dwProcessId;
- return TRUE;
- }
- else
- {
- Debugprintf("Restart TNC Failed %d ", GetLastError());
- return FALSE;
- }
- }
-#endif
- return 0;
-}
-
-VOID TidyClose(struct TNCINFO * TNC, int Stream)
-{
- // If all acked, send disc
-
- if (TNC->Streams[0].BytesOutstanding == 0)
- send(TNC->TCPSock,"DISCONNECT\r\n", 12, 0);
-}
-
-VOID ForcedClose(struct TNCINFO * TNC, int Stream)
-{
- send(TNC->TCPSock,"DIRTYDISCONNECT\r\n", 17, 0);
-}
-
-VOID CloseComplete(struct TNCINFO * TNC, int Stream)
-{
- ReleaseTNC(TNC);
-
- if (TNC->FECMode)
- {
- TNC->FECMode = FALSE;
- send(TNC->TCPSock,"SENDID 0\r\n", 10, 0);
- }
-}
-
-BOOL KillOldTNC(char * Path)
-{
-#ifdef WIN32
- HANDLE hProc;
- char ExeName[256] = "";
- DWORD Pid = 0;
-
- DWORD Processes[1024], Needed, Count;
- unsigned int i;
-
- if (EnumProcessesPtr == NULL)
- return FALSE;
-
- if (!EnumProcessesPtr(Processes, sizeof(Processes), &Needed))
- return FALSE;
-
- // Calculate how many process identifiers were returned.
-
- Count = Needed / sizeof(DWORD);
-
- for (i = 0; i < Count; i++)
- {
- if (Processes[i] != 0)
- {
- hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, Processes[i]);
-
- if (hProc)
- {
- GetModuleFileNameExPtr(hProc, 0, ExeName, 255);
-
- // Path could have parameters, so use memcmp
-
- if (_memicmp(ExeName, Path, strlen(ExeName)) == 0)
- {
- Debugprintf("Killing Pid %d %s", Processes[i], ExeName);
- TerminateProcess(hProc, 0);
- CloseHandle(hProc);
- return TRUE;
- }
- CloseHandle(hProc);
- }
- }
- }
-#endif
- return FALSE;
-}
+/*
+Copyright 2001-2022 John Wiseman G8BPQ
+
+This file is part of LinBPQ/BPQ32.
+
+LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+LinBPQ/BPQ32 is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
+*/
+
+//
+// DLL to provide interface to allow G8BPQ switch to use WINMOR as a Port Driver
+//
+// Uses BPQ EXTERNAL interface
+//
+
+
+// Version 1.0 January 2009 - Initial Version
+//
+
+// March 22 2010
+
+// Send FAULTS to Monitor Window
+// Force PROTOCOL = WINMOR/PACTOR (to simplifiy Config)
+
+// July 2010
+// Support up to 32 BPQ Ports
+// Support up to 32 Applications
+
+// Version 1.2.1.2 August 2010
+
+// Save Minimized State
+// Handle new "BLOCKED by Busy channel" message from TNC
+
+// Version 1.2.1.4 August 2010
+
+// Add Scan control of BW setting
+// Reset TNC if stuck in Disconnecting
+// Add option to send reports to WL2K
+// Disconnect if appl not available
+
+// Version 1.2.1.5 August 2010
+
+// Updates to WL2K Reporting
+// Send Watchdog polls every minute and restart if no response.
+// Don't connect if channel is busy (unless specifically overridden)
+
+// Version 1.2.1.6 September 2010
+
+// Add option to kill and restart TNC after each transfer
+// Fix PTT operation after Node reconfig
+
+// Version 1.2.2.1 September 2010
+
+// Add option to get config from bpq32.cfg
+// Merge with BPQ32.dll
+
+
+#define _CRT_SECURE_NO_DEPRECATE
+
+#include
+#include
+
+#include "cheaders.h"
+
+#ifdef WIN32
+#include
+#endif
+
+extern int (WINAPI FAR *GetModuleFileNameExPtr)();
+extern int (WINAPI FAR *EnumProcessesPtr)();
+
+
+#define SD_RECEIVE 0x00
+#define SD_SEND 0x01
+#define SD_BOTH 0x02
+
+#include "bpq32.h"
+
+#include "tncinfo.h"
+
+
+#define WSA_ACCEPT WM_USER + 1
+#define WSA_DATA WM_USER + 2
+#define WSA_CONNECT WM_USER + 3
+
+static int Socket_Data(int sock, int error, int eventcode);
+
+int KillTNC(struct TNCINFO * TNC);
+int RestartTNC(struct TNCINFO * TNC);
+int KillPopups(struct TNCINFO * TNC);
+VOID MoveWindows(struct TNCINFO * TNC);
+int SendReporttoWL2K(struct TNCINFO * TNC);
+char * CheckAppl(struct TNCINFO * TNC, char * Appl);
+int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
+BOOL KillOldTNC(char * Path);
+int standardParams(struct TNCINFO * TNC, char * buf);
+
+static char ClassName[]="WINMORSTATUS";
+static char WindowTitle[] = "WINMOR";
+static int RigControlRow = 165;
+
+#define WINMOR
+#define NARROWMODE 21
+#define WIDEMODE 22
+
+#ifndef LINBPQ
+#include
+#endif
+
+extern int SemHeldByAPI;
+
+static RECT Rect;
+
+static int ProcessLine(char * buf, int Port);
+
+// RIGCONTROL COM60 19200 ICOM IC706 5e 4 14.103/U1w 14.112/u1 18.1/U1n 10.12/l1
+
+// There seem to be timing issues when calling SendMessage from multiple threads.
+// Queue and process in main thread
+
+UINT * WINMORTraceQ;
+UINT * SetWindowTextQ;
+
+VOID WritetoTraceSupport(struct TNCINFO * TNC, char * Msg, int Len)
+{
+ int index = 0;
+ UCHAR * ptr1 = Msg, * ptr2;
+ UCHAR Line[1000];
+ int LineLen, i;
+ UCHAR Save;
+ int SaveLen = Len;
+ char Time[16];
+ time_t T;
+ struct tm * tm;
+
+ if (Len < 0)
+ return;
+
+ Save = Msg[Len];
+ Msg[Len] = 0;
+
+#ifndef LINBPQ
+ index=SendMessage(TNC->hMonitor, LB_SETCURSEL, -1, 0);
+#endif
+
+lineloop:
+
+ if (Len > 0)
+ {
+ // copy text to control a line at a time
+
+ ptr2 = memchr(ptr1, 13, Len);
+
+ if (ptr2)
+ {
+ ptr2++;
+ LineLen = (int)(ptr2 - ptr1);
+ Len -= LineLen;
+ memcpy(Line, ptr1, LineLen);
+ memcpy(&Line[LineLen - 1], "", 4);
+ LineLen += 3;
+
+ if ((*ptr2) == 10)
+ {
+ memcpy(&Line[LineLen], "", 4);
+ LineLen += 4;
+ ptr2++;
+ Len --;
+ }
+
+ Line[LineLen] = 0;
+
+ // If line contains any data above 7f, assume binary and dont display
+
+ for (i = 0; i < LineLen; i++)
+ {
+ if (Line[i] > 126 || Line[i] < 32)
+ goto Skip;
+ }
+
+ // We now also pass to Monitor Window
+
+ if (strlen(Line) < 250)
+ {
+ MESSAGE Monframe;
+ memset(&Monframe, 0, sizeof(Monframe));
+
+ Monframe.PORT = TNC->Port;
+ Monframe.LENGTH = 12 + strlen(Line);
+ Monframe.DEST[0] = 1; // Plain Text Monitor
+ strcpy(&Monframe.DEST[1], Line);
+
+ time(&Monframe.Timestamp);
+ BPQTRACE((MESSAGE *)&Monframe, FALSE);
+ }
+
+#ifdef LINBPQ
+#else
+ index=SendMessage(TNC->hMonitor, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR) Line);
+#endif
+ // Write to Web Buffer
+
+ T = time(NULL);
+ tm = gmtime(&T);
+
+ sprintf_s(Time, sizeof(Time),"%02d:%02d ", tm->tm_hour, tm->tm_min);
+
+ strcat(TNC->WebBuffer, Time);
+ strcat(TNC->WebBuffer, Line);
+ strcat(TNC->WebBuffer, "\r\n");
+ if (strlen(TNC->WebBuffer) > 4500)
+ memmove(TNC->WebBuffer, &TNC->WebBuffer[500], strlen(&TNC->WebBuffer[500]) + 1); // Make sure null is moved
+ Skip:
+ ptr1 = ptr2;
+
+ goto lineloop;
+
+ }
+
+ // Process incomplete line
+
+ for (i = 0; i < Len; i++)
+ {
+ if (ptr1[i] > 126 || ptr1[i] < 32)
+ break;
+ }
+
+ if (i == Len)
+ {
+ if (Len < 250)
+ {
+ MESSAGE Monframe;
+ memset(&Monframe, 0, sizeof(Monframe));
+
+ Monframe.PORT = TNC->Port;
+ Monframe.LENGTH = 12 + Len;
+ Monframe.DEST[0] = 1; // Plain Text Monitor
+
+ memcpy(&Monframe.DEST[1], ptr1, Len);
+ Monframe.DEST[1 + Len] = 0;
+
+ time(&Monframe.Timestamp);
+ BPQTRACE((MESSAGE *)&Monframe, FALSE);
+ }
+
+
+#ifdef LINBPQ
+#else
+ index=SendMessage(TNC->hMonitor, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR) ptr1 );
+#endif
+ T = time(NULL);
+ tm = gmtime(&T);
+
+ sprintf_s(Time, sizeof(Time),"%02d:%02d ", tm->tm_hour, tm->tm_min);
+ strcat(TNC->WebBuffer, Time);
+
+ strcat(TNC->WebBuffer, ptr1);
+ strcat(TNC->WebBuffer, "\r\n");
+ if (strlen(TNC->WebBuffer) > 4500)
+ memmove(TNC->WebBuffer, &TNC->WebBuffer[500], strlen(&TNC->WebBuffer[500]) + 1); // Make sure null is moved
+ }
+ }
+
+#ifdef LINBPQ
+#else
+
+ if (index > 1200)
+ do
+ index=index=SendMessage(TNC->hMonitor, LB_DELETESTRING, 0, 0);
+ while (index > 1000);
+
+ if (index > -1)
+ index=SendMessage(TNC->hMonitor, LB_SETCARETINDEX,(WPARAM) index, MAKELPARAM(FALSE, 0));
+#endif
+ Msg[SaveLen] = Save;
+
+}
+
+VOID MySetWindowTextWithSem(HWND hWnd, char * Msg)
+{
+#ifndef LINBPQ
+
+ PMSGWITHLEN buffptr;
+
+ buffptr = GetBuff();
+
+ if (buffptr)
+ {
+ buffptr->Len= (UINT)hWnd;
+ memcpy(&buffptr->Data[0], Msg, strlen(Msg) + 1);
+
+ C_Q_ADD(&SetWindowTextQ, buffptr);
+ }
+
+#endif
+}
+
+int C_Q_ADD_NP(VOID *PQ, VOID *PBUFF);
+
+struct SEM SetWindTextSem = {0, 0, 0, 0};
+
+VOID MySetWindowText(HWND hWnd, char * Msg)
+{
+#ifndef LINBPQ
+
+ PMSGWITHLEN buffptr;
+
+ GetSemaphore(&SetWindTextSem, 61);
+ buffptr = zalloc(400);
+
+ if (buffptr)
+ {
+ buffptr->Len= (UINT)hWnd;
+ memcpy(&buffptr->Data[0], Msg, strlen(Msg) + 1);
+
+ C_Q_ADD_NP(&SetWindowTextQ, buffptr);
+ }
+
+ FreeSemaphore(&SetWindTextSem);
+#endif
+}
+
+VOID SetWindowTextSupport()
+{
+ PMSGWITHLEN Buffer;
+
+ while (SetWindowTextQ)
+ {
+ GetSemaphore(&SetWindTextSem, 61);
+ Buffer = Q_REM_NP(&SetWindowTextQ);
+ SetWindowText((HWND)Buffer->Len, Buffer->Data);
+ FreeSemaphore(&SetWindTextSem);
+ free(Buffer);
+ }
+}
+
+
+VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len)
+{
+ // It seems writing from multiple threads can cause problems in Windows
+ // Queue and process in main thread
+
+#ifdef LINBPQ
+ WritetoTraceSupport(TNC, Msg, Len);
+}
+#else
+ UINT * buffptr;
+ BOOL Sem = FALSE;
+
+ if (Len < 0)
+ return;
+
+ // Get semaphore if it isn't set
+
+ if (InterlockedExchange(&Semaphore.Flag, 1) == 0)
+ {
+ Sem = TRUE;
+ Semaphore.Gets++;
+ }
+
+ buffptr = GetBuff();
+
+ if (buffptr)
+ {
+ if (Len > 340)
+ Len = 340;
+
+ buffptr[1] = (UINT)TNC;
+ buffptr[2] = (UINT)Len;
+ memcpy(&buffptr[3], Msg, Len + 1);
+
+ C_Q_ADD(&WINMORTraceQ, buffptr);
+ }
+
+ if (Sem)
+ FreeSemaphore(&Semaphore);
+
+}
+#endif
+
+static 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
+
+ if (_stricmp(buf, "ADDR"))
+ return FALSE; // Must start with ADDR
+
+ ptr = strtok(NULL, " \t\n\r");
+
+ BPQport = Port;
+ p_ipad = ptr;
+
+ TNC = TNCInfo[BPQport] = malloc(sizeof(struct TNCINFO));
+ memset(TNC, 0, sizeof(struct TNCINFO));
+
+ TNC->InitScript = malloc(1000);
+ TNC->InitScript[0] = 0;
+
+ if (p_ipad == NULL)
+ p_ipad = strtok(NULL, " \t\n\r");
+
+ if (p_ipad == NULL) return (FALSE);
+
+ p_port = strtok(NULL, " \t\n\r");
+
+ if (p_port == NULL) return (FALSE);
+
+ WINMORport = atoi(p_port);
+
+ TNC->destaddr.sin_family = AF_INET;
+ TNC->destaddr.sin_port = htons(WINMORport);
+ TNC->Datadestaddr.sin_family = AF_INET;
+ TNC->Datadestaddr.sin_port = htons(WINMORport+1);
+
+ TNC->HostName = malloc(strlen(p_ipad)+1);
+
+ if (TNC->HostName == NULL) return TRUE;
+
+ strcpy(TNC->HostName,p_ipad);
+
+ ptr = strtok(NULL, " \t\n\r");
+
+ if (ptr)
+ {
+ if (_stricmp(ptr, "PTT") == 0)
+ {
+ ptr = strtok(NULL, " \t\n\r");
+
+ if (ptr)
+ {
+ DecodePTTString(TNC, ptr);
+ ptr = strtok(NULL, " \t\n\r");
+ }
+ }
+ }
+
+ if (ptr)
+ {
+ if (_memicmp(ptr, "PATH", 4) == 0)
+ {
+ p_cmd = strtok(NULL, "\n\r");
+ if (p_cmd) TNC->ProgramPath = _strdup(p_cmd);
+ }
+ }
+
+ // Read Initialisation lines
+
+ while(TRUE)
+ {
+ if (GetLine(buf) == 0)
+ return TRUE;
+
+ strcpy(errbuf, buf);
+
+ if (memcmp(buf, "****", 4) == 0)
+ return TRUE;
+
+ ptr = strchr(buf, ';');
+ if (ptr)
+ {
+ *ptr++ = 13;
+ *ptr = 0;
+ }
+
+ if ((_memicmp(buf, "CAPTURE", 7) == 0) || (_memicmp(buf, "PLAYBACK", 8) == 0))
+ {} // Ignore
+ else
+/*
+ if (_memicmp(buf, "PATH", 4) == 0)
+ {
+ char * Context;
+ p_cmd = strtok_s(&buf[5], "\n\r", &Context);
+ if (p_cmd) TNC->ProgramPath = _strdup(p_cmd);
+ }
+ else
+*/
+ if (_memicmp(buf, "STARTINROBUST", 13) == 0)
+ TNC->StartInRobust = TRUE;
+
+ else
+ if (_memicmp(buf, "ROBUST", 6) == 0)
+ {
+ if (_memicmp(&buf[7], "TRUE", 4) == 0)
+ TNC->Robust = TRUE;
+
+ strcat (TNC->InitScript, buf);
+ }
+ else if (standardParams(TNC, buf) == FALSE)
+ strcat (TNC->InitScript, buf);
+ }
+
+
+ return (TRUE);
+}
+
+
+
+void WINMORThread(void * portptr);
+VOID ProcessDataSocketData(int port);
+int ConnecttoWINMOR(int port);
+static int ProcessReceivedData(struct TNCINFO * TNC);
+int V4ProcessReceivedData(struct TNCINFO * TNC);
+VOID ReleaseTNC(struct TNCINFO * TNC);
+VOID SuspendOtherPorts(struct TNCINFO * ThisTNC);
+VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
+VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len);
+
+static time_t ltime;
+
+
+static SOCKADDR_IN sinx;
+static SOCKADDR_IN rxaddr;
+
+static int addrlen=sizeof(sinx);
+
+
+
+VOID ChangeMYC(struct TNCINFO * TNC, char * Call)
+{
+ UCHAR TXMsg[100];
+ int datalen;
+
+ if (strcmp(Call, TNC->CurrentMYC) == 0)
+ return; // No Change
+
+ strcpy(TNC->CurrentMYC, Call);
+
+// send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
+
+ datalen = sprintf(TXMsg, "MYC %s\r\n", Call);
+ send(TNC->TCPSock,TXMsg, datalen, 0);
+
+// send(TNC->TCPSock, "CODEC TRUE\r\n", 12, 0);
+// TNC->StartSent = TRUE;
+
+ send(TNC->TCPSock, "MYC\r\n", 5, 0);
+}
+
+static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
+{
+ int i,winerr;
+ size_t datalen;
+ PMSGWITHLEN buffptr;
+ char txbuff[500];
+ unsigned int bytes;
+ size_t txlen = 0;
+ char ErrMsg[255];
+ size_t Param;
+ HKEY hKey=0;
+ struct TNCINFO * TNC = TNCInfo[port];
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+ struct ScanEntry * Scan;
+ fd_set readfs;
+ fd_set writefs;
+ fd_set errorfs;
+ struct timeval timeout;
+
+ if (TNC == NULL)
+ return 0; // Port not defined
+
+ switch (fn)
+ {
+ case 1: // poll
+
+ // Check session limit timer
+
+ if ((STREAM->Connecting || STREAM->Connected) && !STREAM->Disconnecting)
+ {
+ if (TNC->SessionTimeLimit && STREAM->ConnectTime && time(NULL) > (TNC->SessionTimeLimit + STREAM->ConnectTime))
+ {
+ send(TNC->TCPSock,"DISCONNECT\r\n", 12, 0);
+ STREAM->Disconnecting = TRUE;
+ }
+ }
+
+ while (TNC->PortRecord->UI_Q) // Release anything accidentally put on UI_Q
+ {
+ buffptr = Q_REM(&TNC->PortRecord->UI_Q);
+ ReleaseBuffer(buffptr);
+ }
+
+
+ if (TNC->Busy) // Count down to clear
+ {
+ if ((TNC->BusyFlags & CDBusy) == 0) // TNC Has reported not busy
+ {
+ TNC->Busy--;
+ if (TNC->Busy == 0)
+ SetWindowText(TNC->xIDC_CHANSTATE, "Clear");
+ strcpy(TNC->WEB_CHANSTATE, "Clear");
+ }
+ }
+
+ if (TNC->ConnectCmd && TNC->BusyDelay)
+ {
+ // Still Busy?
+
+ if (InterlockedCheckBusy(TNC) == FALSE)
+ {
+ // No, so send
+
+ send(TNC->TCPSock, TNC->ConnectCmd, (int)strlen(TNC->ConnectCmd), 0);
+ TNC->Streams[0].Connecting = TRUE;
+
+ memset(TNC->Streams[0].RemoteCall, 0, 10);
+ memcpy(TNC->Streams[0].RemoteCall, &TNC->ConnectCmd[8], strlen(TNC->ConnectCmd)-10);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ free(TNC->ConnectCmd);
+ TNC->ConnectCmd = 0;
+
+ TNC->BusyDelay = 0;
+ }
+ else
+ {
+ // Wait Longer
+
+ TNC->BusyDelay--;
+
+ if (TNC->BusyDelay == 0)
+ {
+ // Timed out - Send Error Response
+
+ PMSGWITHLEN buffptr = GetBuff();
+
+ if (buffptr == 0) return (0); // No buffers, so ignore
+
+ buffptr->Len = 39;
+ memcpy(buffptr->Data,"Sorry, Can't Connect - Channel is busy\r", 39);
+
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+ free(TNC->ConnectCmd);
+
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ }
+ }
+ }
+
+ if (TNC->HeartBeat++ > 600 || (TNC->Streams[0].Connected && TNC->HeartBeat > 50)) // Every Minute unless connected
+ {
+ if (TNC->HeartBeat > 600 && TNC->hWnd)
+ {
+ char wtext[100];
+ sprintf (wtext, "WINMOR Sound Card TNC - BPQ %s", TNC->PortRecord->PORTCONTROL.PORTDESCRIPTION);
+ MySetWindowText(TNC->hWnd, wtext);
+ }
+
+ TNC->HeartBeat = 0;
+
+ if (TNC->CONNECTED)
+ {
+ // Probe link
+
+ if (TNC->Streams[0].Connecting || TNC->Streams[0].Connected)
+ send(TNC->TCPSock, "MODE\r\n", 6, 0);
+ else
+ {
+ if (time(NULL) - TNC->WinmorRestartCodecTimer > 900) // 15 mins
+ {
+ send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
+ send(TNC->TCPSock, "CODEC TRUE\r\n", 12, 0);
+ }
+ else
+ send(TNC->TCPSock, "STATE\r\n", 7, 0);
+ }
+ }
+ }
+
+ if (TNC->FECMode)
+ {
+ if (TNC->FECIDTimer++ > 6000) // ID every 10 Mins
+ {
+ if (!TNC->Busy)
+ {
+ TNC->FECIDTimer = 0;
+ send(TNC->TCPSock, "SENDID 0\r\n", 10, 0);
+ }
+ }
+ if (TNC->FECPending) // Check if FEC Send needed
+ {
+ if (!TNC->Busy)
+ {
+ TNC->FECPending = 0;
+
+ if (TNC->FEC1600)
+ send(TNC->TCPSock,"FECSEND 1600\r\n", 14, 0);
+ else
+ send(TNC->TCPSock,"FECSEND 500\r\n", 13, 0);
+ }
+ }
+ }
+
+ if (STREAM->NeedDisc)
+ {
+ STREAM->NeedDisc--;
+
+ if (STREAM->NeedDisc == 0)
+ {
+ // Send the DISCONNECT
+
+ send(TNC->TCPSock, "DISCONNECT\r\n", 12, 0);
+ }
+ }
+
+ if (TNC->DiscPending)
+ {
+ TNC->DiscPending--;
+
+ if (TNC->DiscPending == 0)
+ {
+ // Too long in Disc Pending - Kill and Restart TNC
+
+ if (TNC->PID)
+ {
+ KillTNC(TNC);
+ RestartTNC(TNC);
+ }
+ }
+ }
+
+ if (TNC->TimeSinceLast++ > 800) // Allow 10 secs for Keepalive
+ {
+ // Restart TNC
+
+ if (TNC->ProgramPath && TNC->CONNECTED)
+ {
+ if (strstr(TNC->ProgramPath, "WINMOR TNC"))
+ {
+ struct tm * tm;
+ char Time[80];
+
+ TNC->Restarts++;
+ TNC->LastRestart = time(NULL);
+
+ tm = gmtime(&TNC->LastRestart);
+
+ sprintf_s(Time, sizeof(Time),"%04d/%02d/%02d %02d:%02dZ",
+ tm->tm_year +1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
+
+ SetWindowText(TNC->xIDC_RESTARTTIME, Time);
+ strcpy(TNC->WEB_RESTARTTIME, Time);
+
+ sprintf_s(Time, sizeof(Time),"%d", TNC->Restarts);
+ SetWindowText(TNC->xIDC_RESTARTS, Time);
+ strcpy(TNC->WEB_RESTARTS, Time);
+
+ KillTNC(TNC);
+ RestartTNC(TNC);
+
+ TNC->TimeSinceLast = 0;
+ }
+ }
+ }
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[0] && TNC->Streams[0].Attached == 0)
+ {
+ // New Attach
+
+ int calllen;
+ char Msg[80];
+
+ TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
+
+ TNC->Streams[0].Attached = TRUE;
+
+ calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, TNC->Streams[0].MyCall);
+ TNC->Streams[0].MyCall[calllen] = 0;
+
+ // Stop Listening, and set MYCALL to user's call
+
+ send(TNC->TCPSock, "LISTEN FALSE\r\n", 14, 0);
+ ChangeMYC(TNC, TNC->Streams[0].MyCall);
+
+ // Stop other ports in same group
+
+ SuspendOtherPorts(TNC);
+
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ // Stop Scanning
+
+ sprintf(Msg, "%d SCANSTOP", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Msg);
+
+ }
+
+ if (TNC->Streams[0].Attached)
+ CheckForDetach(TNC, 0, &TNC->Streams[0], TidyClose, ForcedClose, CloseComplete);
+
+ if (TNC->Streams[0].ReportDISC)
+ {
+ TNC->Streams[0].ReportDISC = FALSE;
+ buff->PORT = 0;
+ return -1;
+ }
+
+
+
+ if (TNC->CONNECTED == FALSE && TNC->CONNECTING == FALSE)
+ {
+ // See if time to reconnect
+
+ time(<ime);
+ if (ltime - TNC->lasttime > 9 )
+ {
+ ConnecttoWINMOR(port);
+ TNC->lasttime = ltime;
+ }
+ }
+
+ FD_ZERO(&readfs);
+
+ if (TNC->CONNECTED) FD_SET(TNC->TCPDataSock,&readfs);
+
+ FD_ZERO(&writefs);
+
+ if (TNC->BPQtoWINMOR_Q) FD_SET(TNC->TCPDataSock,&writefs); // Need notification of busy clearing
+
+ FD_ZERO(&errorfs);
+
+ if (TNC->CONNECTING || TNC->CONNECTED) FD_SET(TNC->TCPDataSock,&errorfs);
+
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0; // poll
+
+ if (select((int)TNC->TCPDataSock + 1, &readfs, &writefs, &errorfs, &timeout) > 0)
+ {
+ // See what happened
+
+ if (FD_ISSET(TNC->TCPDataSock, &readfs))
+ ProcessDataSocketData(port);
+
+ if (FD_ISSET(TNC->TCPDataSock, &writefs))
+ {
+ // Write block has cleared. Send rest of packet
+
+ buffptr=Q_REM(&TNC->BPQtoWINMOR_Q);
+ txlen = buffptr->Len;
+ memcpy(txbuff,buffptr->Data,txlen);
+ bytes=send(TNC->TCPSock, (const char FAR *)&txbuff, (int)txlen, 0);
+ ReleaseBuffer(buffptr);
+ }
+
+ if (FD_ISSET(TNC->TCPDataSock, &errorfs))
+ {
+ i=sprintf(ErrMsg, "WINMOR Data Connection lost for BPQ Port %d\r\n", port);
+ WritetoConsole(ErrMsg);
+ TNC->CONNECTING = FALSE;
+ TNC->CONNECTED = FALSE;
+ TNC->Streams[0].ReportDISC = TRUE;
+ }
+ }
+
+ // See if any frames for this port
+
+ if (TNC->WINMORtoBPQ_Q != 0)
+ {
+ buffptr=Q_REM(&TNC->WINMORtoBPQ_Q);
+
+ datalen = buffptr->Len;
+
+ buff->PORT = 0; // Compatibility with Kam Driver
+ buff->PID = 0xf0;
+ memcpy(&buff->L2DATA[0], buffptr->Data, datalen); // Data goes to +7, but we have an extra byte
+ datalen = buffptr->Len;
+
+ datalen += sizeof(void *) + 4;
+ PutLengthinBuffer(buff, (int)datalen);
+
+ ReleaseBuffer(buffptr);
+
+ return (1);
+ }
+
+ return (0);
+
+ case 2: // send
+
+ if (!TNC->CONNECTED)
+ {
+ // Send Error Response
+
+ PMSGWITHLEN buffptr = GetBuff();
+
+ if (buffptr == 0) return (0); // No buffers, so ignore
+
+ buffptr->Len = 36;
+ memcpy(buffptr->Data, "No Connection to WINMOR Virtual TNC\r", 36);
+
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+
+ return 0; // Don't try if not connected
+ }
+
+ if (TNC->Streams[0].BPQtoPACTOR_Q) //Used for CTEXT
+ {
+ PMSGWITHLEN buffptr = Q_REM(&TNC->Streams[0].BPQtoPACTOR_Q);
+ txlen = buffptr->Len;
+ memcpy(txbuff, buffptr->Data, txlen);
+ bytes = send(TNC->TCPDataSock, txbuff, (int)txlen, 0);
+ STREAM->bytesTXed += bytes;
+ WritetoTrace(TNC, txbuff, (int)txlen);
+ ReleaseBuffer(buffptr);
+ }
+
+ if (TNC->SwallowSignon)
+ {
+ TNC->SwallowSignon = FALSE; // Discard *** connected
+ return 0;
+ }
+
+ txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1); // 1 as no PID
+
+ if (TNC->Streams[0].Connected)
+ {
+ STREAM->PacketsSent++;
+
+ if (STREAM->PacketsSent == 3)
+ {
+ if (TNC->Robust)
+ send(TNC->TCPSock, "ROBUST TRUE\r\n", 13, 0);
+ else
+ send(TNC->TCPSock, "ROBUST FALSE\r\n", 14, 0);
+ }
+
+ bytes = send(TNC->TCPDataSock,buff->L2DATA, (int)txlen, 0);
+ STREAM->bytesTXed += bytes;
+ WritetoTrace(TNC, &buff->L2DATA[0], (int)txlen);
+
+ }
+ else
+ {
+ if (_memicmp(buff->L2DATA, "D\r", 2) == 0)
+ {
+ TNC->Streams[0].ReportDISC = TRUE; // Tell Node
+ return 0;
+ }
+
+ if (TNC->FECMode)
+ {
+ char Buffer[300];
+ int len;
+
+ // Send FEC Data
+
+ buff->L2DATA[txlen] = 0;
+ len = sprintf(Buffer, "%-9s: %s", TNC->Streams[0].MyCall, &buff->L2DATA);
+
+ send(TNC->TCPDataSock, Buffer, len, 0);
+
+ if (TNC->BusyFlags)
+ {
+ TNC->FECPending = 1;
+ }
+ else
+ {
+ if (TNC->FEC1600)
+ send(TNC->TCPSock,"FECSEND 1600\r\n", 14, 0);
+ else
+ send(TNC->TCPSock,"FECSEND 500\r\n", 13, 0);
+ }
+ return 0;
+ }
+
+
+ // See if Local command (eg RADIO)
+
+ if (_memicmp(&buff->L2DATA[0], "RADIO ", 6) == 0)
+ {
+ char cmd[56];
+
+ strcpy(cmd, &buff->L2DATA[6]);
+ sprintf(&buff->L2DATA[0], "%d %s", TNC->Port, &cmd);
+
+
+ if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &buff->L2DATA[0]))
+ {
+ }
+ else
+ {
+ PMSGWITHLEN buffptr = GetBuff();
+
+ if (buffptr == 0) return 1; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "%s", &buff->L2DATA[0]);
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+ }
+ return 1;
+ }
+
+ if (_memicmp(&buff->L2DATA[0], "OVERRIDEBUSY", 12) == 0)
+ {
+ PMSGWITHLEN buffptr = GetBuff();
+
+ TNC->OverrideBusy = TRUE;
+
+ if (buffptr)
+ {
+ buffptr->Len = sprintf(&buffptr->Data[0], "Winmor} OK\r");
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+ }
+
+ return 0;
+
+ }
+
+ if (_memicmp(&buff->L2DATA[0], "MAXCONREQ", 9) == 0)
+ {
+ if (buff->L2DATA[9] != 13)
+ {
+ // Limit connects
+
+ int tries = atoi(&buff->L2DATA[10]);
+ int len;
+
+ if (tries > 10) tries = 10;
+ len = sprintf(&buff->L2DATA[0], "MAXCONREQ %d\r\nMAXCONREQ\r\n", tries);
+
+ send(TNC->TCPSock, &buff->L2DATA[0], len, 0);
+ return 0;
+ }
+ }
+
+ if (_memicmp(&buff->L2DATA[0], "SessionTimeLimit", 16) == 0)
+ {
+ if (buff->L2DATA[16] != 13)
+ {
+ PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff();
+
+ TNC->SessionTimeLimit = atoi(&buff->L2DATA[16]) * 60;
+
+ if (buffptr)
+ {
+ buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "Winmor} OK\r");
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+ }
+ return 0;
+ }
+ }
+
+ if ((_memicmp(buff->L2DATA, "BW 500", 6) == 0) || (_memicmp(buff->L2DATA, "BW 1600", 7) == 0))
+ {
+ // Generate a local response
+
+ PMSGWITHLEN buffptr = GetBuff();
+
+ if (_memicmp(buff->L2DATA, "BW 500", 6) == 0)
+ TNC->WL2KMode = 21;
+ else
+ TNC->WL2KMode = 22;
+
+ if (buffptr)
+ {
+ buffptr->Len = sprintf(&buffptr->Data[0], "Winmor} OK\r");
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+ }
+ TNC->WinmorCurrentMode = 0; // So scanner will set next value
+ }
+
+ if (_memicmp(buff->L2DATA, "CODEC TRUE", 9) == 0)
+ TNC->StartSent = TRUE;
+
+ if (_memicmp(buff->L2DATA, "ROBUST", 6) == 0)
+ {
+ if (_memicmp(&buff->L2DATA[7], "TRUE", 4) == 0)
+ TNC->Robust = TRUE;
+ else
+ TNC->Robust = FALSE;
+ }
+
+ if (_memicmp(buff->L2DATA, "D\r", 2) == 0)
+ {
+ TNC->Streams[0].ReportDISC = TRUE; // Tell Node
+ return 0;
+ }
+
+ if (_memicmp(buff->L2DATA, "FEC\r", 4) == 0 || _memicmp(buff->L2DATA, "FEC ", 4) == 0)
+ {
+ TNC->FECMode = TRUE;
+ TNC->FECIDTimer = 0;
+ send(TNC->TCPSock,"FECRCV TRUE\r\nFECRCV\r\n", 21, 0);
+
+ if (_memicmp(buff->L2DATA, "FEC 1600", 8) == 0)
+ TNC->FEC1600 = TRUE;
+ else
+ TNC->FEC1600 = FALSE;
+
+ return 0;
+ }
+
+ // See if a Connect Command. If so, start codec and set Connecting
+
+ if (toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect
+ {
+ char Connect[80] = "CONNECT ";
+
+ memcpy(&Connect[8], &buff->L2DATA[2], txlen);
+ txlen += 6;
+ Connect[txlen++] = 0x0a;
+ Connect[txlen] = 0;
+
+ _strupr(Connect);
+
+ ChangeMYC(TNC, TNC->Streams[0].MyCall);
+
+ // See if Busy
+
+ if (InterlockedCheckBusy(TNC))
+ {
+ // Channel Busy. Unless override set, wait
+
+ if (TNC->OverrideBusy == 0)
+ {
+ // Save Command, and wait up to 10 secs
+
+ sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ TNC->ConnectCmd = _strdup(Connect);
+ TNC->BusyDelay = TNC->BusyWait * 10; // BusyWait secs
+ return 0;
+ }
+ }
+
+ TNC->OverrideBusy = FALSE;
+
+ bytes = send(TNC->TCPSock, Connect, (int)txlen, 0);
+ TNC->Streams[0].Connecting = TRUE;
+
+ memset(TNC->Streams[0].RemoteCall, 0, 10);
+ memcpy(TNC->Streams[0].RemoteCall, &Connect[8], txlen-10);
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ }
+ else
+ {
+ buff->L2DATA[txlen++] = 0x0a;
+ bytes = send(TNC->TCPSock, &buff->L2DATA[0], (int)txlen, 0);
+ }
+ }
+ if (bytes != txlen)
+ {
+
+ // WINMOR doesn't seem to recover from a blocked write. For now just reset
+
+ winerr = WSAGetLastError();
+ sprintf(ErrMsg, "WINMOR Write Failed for port %d - error code = %d\r\n", port, winerr);
+ WritetoConsole(ErrMsg);
+ closesocket(TNC->TCPSock);
+ TNC->CONNECTED = FALSE;
+
+ return (0);
+ }
+
+ return (0);
+
+ case 3:
+
+ // CHECK IF OK TO SEND (And check TNC Status)
+
+ if (TNC->Streams[0].Attached == 0)
+ return TNC->CONNECTED << 8 | 1;
+
+ return (TNC->CONNECTED << 8 | TNC->Streams[0].Disconnecting << 15); // OK
+
+ break;
+
+ case 4: // reinit
+
+ return (0);
+
+ case 5: // Close
+
+ send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
+ Sleep(100);
+ shutdown(TNC->TCPDataSock, SD_BOTH);
+ shutdown(TNC->TCPSock, SD_BOTH);
+ Sleep(100);
+
+ closesocket(TNC->TCPDataSock);
+ closesocket(TNC->TCPSock);
+
+ if (TNC->PID && TNC->WeStartedTNC)
+ {
+ KillTNC(TNC);
+ }
+
+ return (0);
+
+ case 6: // Scan Stop Interface
+
+ Param = (size_t)buff;
+
+ if (Param == 2) // Check Permission (shouldn't happen)
+ {
+ Debugprintf("Scan Check Permission called on FLDIGI");
+ return 1; // OK to change
+ }
+
+ if (!TNC->TCPSock)
+ return 0; // No connection so no interlock
+
+ if (Param == 1) // Request Permission
+ {
+ if (TNC->ConnectPending)
+ return TRUE; // Not OK to Change
+
+ if (TNC->CONNECTED)
+ {
+ TNC->GavePermission = TRUE;
+ send(TNC->TCPSock, "LISTEN FALSE\r\n", 14, 0);
+ }
+ return FALSE;
+ }
+
+ if (Param == 3) // Release Permission
+ {
+ if (TNC->CONNECTED)
+ {
+ if (TNC->GavePermission)
+ {
+ TNC->GavePermission = FALSE;
+ send(TNC->TCPSock, "LISTEN TRUE\r\n", 13, 0);
+ }
+ }
+ return 0;
+ }
+
+ // Param is Address of a struct ScanEntry
+
+ Scan = (struct ScanEntry *)buff;
+
+
+ if (Scan->Bandwidth == 'W') // Set Wide Mode
+ {
+ if (TNC->WinmorCurrentMode != 1600)
+ {
+ if (TNC->WinmorCurrentMode == 0)
+ if (TNC->CONNECTED)
+ send(TNC->TCPSock, "LISTEN TRUE\r\n", 13, 0);
+
+ if (TNC->CONNECTED)
+ send(TNC->TCPSock, "BW 1600\r\n", 9, 0);
+ TNC->WinmorCurrentMode = 1600;
+ }
+ TNC->WL2KMode = 22;
+ return 0;
+ }
+
+
+ if (Scan->Bandwidth == 'N') // Set Narrow Mode
+ {
+ if (TNC->WinmorCurrentMode != 500)
+ {
+ if (TNC->WinmorCurrentMode == 0)
+ if (TNC->CONNECTED)
+ send(TNC->TCPSock, "LISTEN TRUE\r\n", 13, 0);
+
+ TNC->WinmorCurrentMode = 500;
+ if (TNC->CONNECTED)
+ send(TNC->TCPSock, "BW 500\r\n", 8, 0);
+ }
+ TNC->WL2KMode = 21;
+ return 0;
+ }
+
+ if (Scan->Bandwidth == 'X') // Dont Allow Connects
+ {
+ if (TNC->WinmorCurrentMode != 0)
+ {
+ if (TNC->CONNECTED)
+ send(TNC->TCPSock, "LISTEN FALSE\r\n", 14, 0);
+ TNC->WinmorCurrentMode = 0;
+ }
+
+ TNC->WL2KMode = 0;
+ return 0;
+ }
+
+ return 0;
+ }
+ return 0;
+}
+
+VOID ReleaseTNC(struct TNCINFO * TNC)
+{
+ // Set mycall back to Node or Port Call, and Start Scanner
+
+ UCHAR TXMsg[256];
+ char wtext[100];
+
+ ChangeMYC(TNC, TNC->NodeCall);
+
+ if (TNC->CONNECTED)
+ send(TNC->TCPSock, "LISTEN TRUE\r\nMAXCONREQ 4\r\n", 26, 0);
+
+ strcpy(TNC->WEB_TNCSTATE, "Free");
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ if (TNC->hWnd)
+ {
+ sprintf (wtext, "WINMOR Sound Card TNC - BPQ %s", TNC->PortRecord->PORTCONTROL.PORTDESCRIPTION);
+ MySetWindowText(TNC->hWnd, wtext);
+ }
+
+ // Start Scanner
+
+ sprintf(TXMsg, "%d SCANSTART 15", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, TXMsg);
+
+ ReleaseOtherPorts(TNC);
+
+}
+
+VOID SuspendOtherPorts(struct TNCINFO * ThisTNC)
+{
+ // Disable other TNCs in same Interlock Group
+
+ struct TNCINFO * TNC;
+ int i;
+ int rxInterlock = ThisTNC->RXRadio;
+ int txInterlock = ThisTNC->TXRadio;
+
+ if (rxInterlock == 0 || txInterlock == 0)
+ return;
+
+ for (i = 1; i <= MAXBPQPORTS; i++)
+ {
+ TNC = TNCInfo[i];
+ if (TNC == NULL)
+ continue;
+
+ if (TNC == ThisTNC)
+ continue;
+
+ if (rxInterlock == TNC->RXRadio || txInterlock == TNC->TXRadio) // Same Group
+ if (TNC->SuspendPortProc)
+ TNC->SuspendPortProc(TNC, ThisTNC);
+ }
+}
+
+VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC)
+{
+ // Enable other TNCs in same Interlock Group
+
+ struct TNCINFO * TNC;
+ int i;
+ int rxInterlock = ThisTNC->RXRadio;
+ int txInterlock = ThisTNC->TXRadio;
+
+ if (rxInterlock == 0 && txInterlock == 0)
+ return;
+
+ for (i=1; i <= MAXBPQPORTS; i++)
+ {
+ TNC = TNCInfo[i];
+ if (TNC == NULL)
+ continue;
+
+ if (TNC == ThisTNC)
+ continue;
+
+ if (rxInterlock == TNC->RXRadio || txInterlock == TNC->TXRadio) // Same Group
+ if (TNC->ReleasePortProc)
+ TNC->ReleasePortProc(TNC);
+ }
+}
+
+VOID WinmorSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC)
+{
+ if (TNC->CONNECTED)
+ send(TNC->TCPSock, "CODEC FALSE\r\n", 14, 0);
+
+ if (TNC->Busy)
+ {
+ TNC->Busy = FALSE; // Can't clear detector if CODEC off.
+ MySetWindowText(TNC->xIDC_CHANSTATE, "Clear");
+ strcpy(TNC->WEB_CHANSTATE, "Clear");
+ }
+}
+
+VOID WinmorReleasePort(struct TNCINFO * TNC)
+{
+ if (TNC->CONNECTED)
+ send(TNC->TCPSock, "CODEC TRUE\r\n", 13, 0);
+}
+
+extern char WebProcTemplate[];
+extern char sliderBit[];
+
+static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
+{
+ int Len = sprintf(Buff, WebProcTemplate, TNC->Port, TNC->Port, "WINMOR Status", "WINMOR Status");
+
+ if (TNC->TXFreq)
+ Len += sprintf(&Buff[Len], sliderBit, TNC->TXOffset, TNC->TXOffset);
+
+
+ Len += sprintf(&Buff[Len], "");
+ Len += sprintf(&Buff[Len], "| Comms State | %s |
", TNC->WEB_COMMSSTATE);
+ Len += sprintf(&Buff[Len], "| TNC State | %s |
", TNC->WEB_TNCSTATE);
+ Len += sprintf(&Buff[Len], "| Mode | %s |
", TNC->WEB_MODE);
+ Len += sprintf(&Buff[Len], "| Channel State | %s |
", TNC->WEB_CHANSTATE);
+ Len += sprintf(&Buff[Len], "| Proto State | %s |
", TNC->WEB_PROTOSTATE);
+ Len += sprintf(&Buff[Len], "| Traffic | %s |
", TNC->WEB_TRAFFIC);
+// Len += sprintf(&Buff[Len], "| TNC Restarts | |
", TNC->WEB_RESTARTS);
+ Len += sprintf(&Buff[Len], "
");
+
+ Len += sprintf(&Buff[Len], "", TNC->WebBuffer);
+ Len = DoScanLine(TNC, Buff, Len);
+
+ return Len;
+}
+
+
+void * WinmorExtInit(EXTPORTDATA * PortEntry)
+{
+ int i, port;
+ char Msg[255];
+ char * ptr;
+ APPLCALLS * APPL;
+ struct TNCINFO * TNC;
+ char Aux[100] = "MYAUX ";
+ char Appl[11];
+ char * TempScript;
+
+ //
+ // Will be called once for each WINMOR port
+ //
+ // The Socket to connect to is in IOBASE
+ //
+
+ 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\n");
+ WritetoConsole(Msg);
+
+ return ExtProc;
+ }
+
+ TNC->Port = port;
+ TNC->PortRecord = PortEntry;
+
+ if (TNC->ProgramPath)
+ TNC->WeStartedTNC = RestartTNC(TNC);
+
+ TNC->PortRecord->PORTCONTROL.HWType = TNC->Hardware = H_WINMOR;
+
+ if (TNC->BusyWait == 0)
+ TNC->BusyWait = 10;
+
+ if (TNC->BusyHold == 0)
+ TNC->BusyHold = 1;
+
+
+ if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
+ memcpy(TNC->NodeCall, MYNODECALL, 10);
+ else
+ ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
+
+ if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
+ TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
+
+ PortEntry->PORTCONTROL.PROTOCOL = 10;
+ PortEntry->PORTCONTROL.PORTQUALITY = 0;
+ PortEntry->MAXHOSTMODESESSIONS = 1;
+ PortEntry->SCANCAPABILITIES = SIMPLE; // Scan Control - pending connect only
+
+ if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
+ PortEntry->PORTCONTROL.PORTPACLEN = 236;
+
+ TNC->SuspendPortProc = WinmorSuspendPort;
+ TNC->ReleasePortProc = WinmorReleasePort;
+
+ TNC->ModemCentre = 1500; // WINMOR is always 1500 Offset
+
+ ptr=strchr(TNC->NodeCall, ' ');
+ if (ptr) *(ptr) = 0; // Null Terminate
+
+ // Set Essential Params and MYCALL
+
+ // Put overridable ones on front, essential ones on end
+
+ TempScript = malloc(1000);
+
+ strcpy(TempScript, "DebugLog True\r\n");
+ strcat(TempScript, "CWID False\r\n");
+ strcat(TempScript, "BW 1600\r\n");
+ strcat(TempScript, "ROBUST False\r\n");
+ strcat(TempScript, "MODE AUTO\r\n");
+
+ strcat(TempScript, TNC->InitScript);
+
+ free(TNC->InitScript);
+ TNC->InitScript = TempScript;
+
+ TNC->WL2KMode = 22; // in case not scanning
+
+ // Set MYCALL
+
+ strcat(TNC->InitScript,"FECRCV True\r\n");
+ strcat(TNC->InitScript,"AUTOBREAK True\r\n");
+
+ sprintf(Msg, "MYC %s\r\nCODEC TRUE\r\nLISTEN TRUE\r\nMYC\r\n", TNC->NodeCall);
+ strcat(TNC->InitScript, Msg);
+ strcat(TNC->InitScript,"PROCESSID\r\n");
+
+ for (i = 0; i < 32; i++)
+ {
+ APPL=&APPLCALLTABLE[i];
+
+ if (APPL->APPLCALL_TEXT[0] > ' ')
+ {
+ char * ptr;
+ memcpy(Appl, APPL->APPLCALL_TEXT, 10);
+ ptr=strchr(Appl, ' ');
+
+ if (ptr)
+ {
+ *ptr++ = ',';
+ *ptr = 0;
+ }
+
+ strcat(Aux, Appl);
+ }
+ }
+ strcat(TNC->InitScript, Aux);
+ strcat(TNC->InitScript,"\r\nMYAUX\r\n");
+
+ strcpy(TNC->CurrentMYC, TNC->NodeCall);
+
+ if (TNC->WL2K == NULL)
+ if (PortEntry->PORTCONTROL.WL2KInfo.RMSCall[0]) // Alrerady decoded
+ TNC->WL2K = &PortEntry->PORTCONTROL.WL2KInfo;
+
+ if (TNC->destaddr.sin_family == 0)
+ {
+ // not defined in config file, so use localhost and port from IOBASE
+
+ TNC->destaddr.sin_family = AF_INET;
+ TNC->destaddr.sin_port = htons(PortEntry->PORTCONTROL.IOBASE);
+ TNC->Datadestaddr.sin_family = AF_INET;
+ TNC->Datadestaddr.sin_port = htons(PortEntry->PORTCONTROL.IOBASE+1);
+
+ TNC->HostName=malloc(10);
+
+ if (TNC->HostName != NULL)
+ strcpy(TNC->HostName,"127.0.0.1");
+
+ }
+
+ PortEntry->PORTCONTROL.TNC = TNC;
+
+ TNC->WebWindowProc = WebProc;
+ TNC->WebWinX = 520;
+ TNC->WebWinY = 500;
+ TNC->WebBuffer = zalloc(5000);
+
+ TNC->WEB_COMMSSTATE = zalloc(100);
+ TNC->WEB_TNCSTATE = zalloc(100);
+ TNC->WEB_CHANSTATE = zalloc(100);
+ TNC->WEB_BUFFERS = zalloc(100);
+ TNC->WEB_PROTOSTATE = zalloc(100);
+ TNC->WEB_RESTARTTIME = zalloc(100);
+ TNC->WEB_RESTARTS = zalloc(100);
+
+ TNC->WEB_MODE = zalloc(20);
+ TNC->WEB_TRAFFIC = zalloc(100);
+
+
+#ifndef LINBPQ
+
+ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 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, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Channel State", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_CHANSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Proto State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_PROTOSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "0 0 0 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "TNC Restarts", WS_CHILD | WS_VISIBLE,10,138,100,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_RESTARTS = CreateWindowEx(0, "STATIC", "0", WS_CHILD | WS_VISIBLE,116,138,40,20 , TNC->hDlg, NULL, hInstance, NULL);
+ CreateWindowEx(0, "STATIC", "Last Restart", WS_CHILD | WS_VISIBLE,140,138,100,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_RESTARTTIME = CreateWindowEx(0, "STATIC", "Never", WS_CHILD | WS_VISIBLE,250,138,200,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
+ LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL,
+ 0,170,250,300, TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->ClientHeight = 450;
+ TNC->ClientWidth = 500;
+
+ TNC->hMenu = CreatePopupMenu();
+
+ AppendMenu(TNC->hMenu, MF_STRING, WINMOR_KILL, "Kill Winmor TNC");
+ AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTART, "Kill and Restart Winmor TNC");
+ AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTARTAFTERFAILURE, "Restart TNC after failed Connection");
+ AppendMenu(TNC->hMenu, MF_STRING, ARDOP_ABORT, "Abort Current Session");
+
+ CheckMenuItem(TNC->hMenu, WINMOR_RESTARTAFTERFAILURE, (TNC->RestartAfterFailure) ? MF_CHECKED : MF_UNCHECKED);
+
+ MoveWindows(TNC);
+#endif
+ Consoleprintf("WINMOR Host %s %d", TNC->HostName, htons(TNC->destaddr.sin_port));
+
+ ConnecttoWINMOR(port);
+
+ time(&TNC->lasttime); // Get initial time value
+
+ return ExtProc;
+}
+
+int ConnecttoWINMOR(int port)
+{
+ _beginthread(WINMORThread, 0, (void *)(size_t)port);
+
+ return 0;
+}
+
+VOID WINMORThread(void * portptr)
+{
+ // Opens both sockets and looks for data on control socket. Data socket is polled from BG,
+ // but we need fast response to control messages for PTT porcessing
+
+ int port = (int)(size_t)portptr;
+
+ char Msg[255];
+ int err, i, ret;
+ u_long param=1;
+ BOOL bcopt=TRUE;
+ struct hostent * HostEnt;
+ struct TNCINFO * TNC = TNCInfo[port];
+ fd_set readfs;
+ fd_set errorfs;
+ struct timeval timeout;
+ if (TNC->HostName == NULL)
+ return;
+
+ TNC->CONNECTING = TRUE;
+
+ Sleep(3000); // Allow init to complete
+
+#ifdef WIN32
+ if (strcmp(TNC->HostName, "127.0.0.1") == 0)
+ {
+ // can only check if running on local host
+
+ TNC->PID = GetListeningPortsPID(TNC->destaddr.sin_port);
+ if (TNC->PID == 0)
+ {
+ TNC->CONNECTING = FALSE;
+ return; // Not listening so no point trying to connect
+ }
+ }
+#endif
+
+// // If we started the TNC make sure it is still running.
+
+// if (!IsProcess(TNC->PID))
+// {
+// RestartTNC(TNC);
+// Sleep(3000);
+// }
+
+
+ TNC->destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
+ TNC->Datadestaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
+
+ if (TNC->destaddr.sin_addr.s_addr == INADDR_NONE)
+ {
+ // Resolve name to address
+
+ HostEnt = gethostbyname (TNC->HostName);
+
+ if (!HostEnt)
+ {
+ TNC->CONNECTING = FALSE;
+ return; // Resolve failed
+ }
+ memcpy(&TNC->destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+ memcpy(&TNC->Datadestaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+
+ }
+
+ if (TNC->TCPSock)
+ closesocket(TNC->TCPSock);
+
+ TNC->TCPSock = 0;
+
+ if (TNC->TCPDataSock)
+ closesocket(TNC->TCPDataSock);
+
+ TNC->TCPDataSock = 0;
+
+ TNC->TCPSock=socket(AF_INET,SOCK_STREAM,0);
+
+ if (TNC->TCPSock == INVALID_SOCKET)
+ {
+ i=sprintf(Msg, "Socket Failed for WINMOR socket - error code = %d\r\n", WSAGetLastError());
+ WritetoConsole(Msg);
+
+ TNC->CONNECTING = FALSE;
+ return;
+ }
+
+ setsockopt (TNC->TCPSock, 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(TNC->TCPSock, (LPSOCKADDR) &sinx, addrlen) != 0 )
+ {
+ //
+ // Bind Failed
+ //
+
+ i=sprintf(Msg, "Bind Failed for WINMOR socket - error code = %d\r\n", WSAGetLastError());
+ WritetoConsole(Msg);
+
+ closesocket(TNC->TCPSock);
+ TNC->TCPSock = 0;
+ TNC->CONNECTING = FALSE;
+
+ return;
+ }
+
+ if (connect(TNC->TCPSock,(LPSOCKADDR) &TNC->destaddr,sizeof(TNC->destaddr)) == 0)
+ {
+ //
+ // Connected successful
+ //
+ }
+ else
+ {
+ if (TNC->Alerted == FALSE)
+ {
+ err=WSAGetLastError();
+ i=sprintf(Msg, "Connect Failed for WINMOR socket - error code = %d\r\n", err);
+ WritetoConsole(Msg);
+ sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC failed");
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+ TNC->Alerted = TRUE;
+ }
+
+ closesocket(TNC->TCPSock);
+ TNC->CONNECTING = FALSE;
+ TNC->TCPSock = 0;
+
+ return;
+ }
+
+ Sleep(1000);
+
+ TNC->LastFreq = 0; // so V4 display will be updated
+
+ TNC->TCPDataSock=socket(AF_INET,SOCK_STREAM,0);
+
+ setsockopt (TNC->TCPDataSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4);
+
+ if (TNC->TCPDataSock == INVALID_SOCKET)
+ {
+ i=sprintf(Msg, "Socket Failed for WINMOR socket - error code = %d\r\n", WSAGetLastError());
+ WritetoConsole(Msg);
+
+ closesocket(TNC->TCPSock);
+ TNC->TCPSock = 0;
+ TNC->CONNECTING = FALSE;
+
+ return;
+ }
+
+ if (bind(TNC->TCPDataSock, (LPSOCKADDR) &sinx, addrlen) != 0 )
+ {
+ //
+ // Bind Failed
+ //
+
+ i=sprintf(Msg, "Bind Failed for WINMOR Data socket - error code = %d\r\n", WSAGetLastError());
+ WritetoConsole(Msg);
+
+ closesocket(TNC->TCPSock);
+ closesocket(TNC->TCPDataSock);
+ TNC->TCPSock = 0;
+ TNC->TCPDataSock = 0;
+ TNC->CONNECTING = FALSE;
+
+ return;
+ }
+
+ if (connect(TNC->TCPDataSock,(LPSOCKADDR) &TNC->Datadestaddr,sizeof(TNC->Datadestaddr)) == 0)
+ {
+ ioctlsocket (TNC->TCPDataSock,FIONBIO,¶m); // Set nonblocking
+ TNC->CONNECTED = TRUE;
+ TNC->CONNECTING = FALSE;
+
+ // Send INIT script
+
+ send(TNC->TCPSock, TNC->InitScript , (int)strlen(TNC->InitScript), 0);
+ TNC->Alerted = TRUE;
+
+ if (TNC->Hardware == H_V4)
+ sprintf(TNC->WEB_COMMSSTATE, "Connected to V4 TNC");
+ else
+ sprintf(TNC->WEB_COMMSSTATE, "Connected to WINMOR TNC");
+
+ GetSemaphore(&Semaphore, 40);
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+ FreeSemaphore(&Semaphore);
+
+ }
+ else
+ {
+ sprintf(Msg, "Connect Failed for WINMOR Data socket Port %d - error code = %d\r\n", port, WSAGetLastError());
+ WritetoConsole(Msg);
+
+ closesocket(TNC->TCPSock);
+ closesocket(TNC->TCPDataSock);
+ TNC->TCPSock = 0;
+ TNC->TCPDataSock = 0;
+ TNC->CONNECTING = FALSE;
+
+ return;
+ }
+
+ TNC->HeartBeat = 0;
+
+ while (TRUE)
+ {
+ FD_ZERO(&readfs);
+ FD_ZERO(&errorfs);
+
+ FD_SET(TNC->TCPSock,&readfs);
+ FD_SET(TNC->TCPSock,&errorfs);
+
+ timeout.tv_sec = 90;
+ timeout.tv_usec = 0; // We should get messages more frequently that this
+
+ ret = select((int)TNC->TCPSock + 1, &readfs, NULL, &errorfs, &timeout);
+
+ if (ret == SOCKET_ERROR)
+ {
+ printf("Select failed %d ", WSAGetLastError());
+ goto Lost;
+ }
+ if (ret > 0)
+ {
+ // See what happened
+
+ if (FD_ISSET(TNC->TCPSock, &readfs))
+ {
+ if (TNC->Hardware == H_V4)
+ V4ProcessReceivedData(TNC);
+ else
+ ProcessReceivedData(TNC);
+ }
+
+ if (FD_ISSET(TNC->TCPSock, &errorfs))
+ {
+Lost:
+ sprintf(Msg, "WINMOR Connection lost for Port %d\r\n", TNC->Port);
+ WritetoConsole(Msg);
+
+ sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
+ GetSemaphore(&Semaphore, 40);
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+ FreeSemaphore(&Semaphore);
+
+ TNC->CONNECTED = FALSE;
+ TNC->Alerted = FALSE;
+
+ if (TNC->PTTMode)
+ Rig_PTT(TNC, FALSE); // Make sure PTT is down
+
+ if (TNC->Streams[0].Attached)
+ TNC->Streams[0].ReportDISC = TRUE;
+
+ closesocket(TNC->TCPSock);
+ closesocket(TNC->TCPDataSock);
+
+ TNC->TCPSock = 0;
+ TNC->TCPDataSock = 0;
+
+ return;
+ }
+ }
+ else
+ {
+ // 90 secs without data. Shouldn't happen
+
+ sprintf(Msg, "WINMOR Connection Timeout Port %d\r\n", TNC->Port);
+ WritetoConsole(Msg);
+
+ sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
+ GetSemaphore(&Semaphore, 40);
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+ FreeSemaphore(&Semaphore);
+
+ TNC->CONNECTED = FALSE;
+ TNC->Alerted = FALSE;
+
+ if (TNC->PTTMode)
+ Rig_PTT(TNC, FALSE); // Make sure PTT is down
+
+ if (TNC->Streams[0].Attached)
+ TNC->Streams[0].ReportDISC = TRUE;
+
+ send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
+
+ Sleep(100);
+ shutdown(TNC->TCPDataSock, SD_BOTH);
+ shutdown(TNC->TCPSock, SD_BOTH);
+ Sleep(100);
+
+ closesocket(TNC->TCPDataSock);
+ closesocket(TNC->TCPSock);
+ TNC->TCPDataSock = 0;
+ TNC->TCPSock= 0;
+
+ if (TNC->PID && TNC->WeStartedTNC)
+ {
+ KillTNC(TNC);
+ RestartTNC(TNC);
+ }
+ return;
+ }
+ }
+}
+
+#ifdef WIN32
+
+BOOL CALLBACK EnumTNCWindowsProc(HWND hwnd, LPARAM lParam)
+{
+ char wtext[100];
+ struct TNCINFO * TNC = (struct TNCINFO *)lParam;
+ UINT ProcessId;
+
+ GetWindowText(hwnd,wtext,99);
+
+ if (memcmp(wtext,"WINMOR Sound Card TNC", 21) == 0)
+ {
+ GetWindowThreadProcessId(hwnd, &ProcessId);
+
+ if (TNC->PID == ProcessId)
+ {
+ // Our Process
+
+ TNC->hWnd = hwnd; // save so we can reset title when sessicn closes
+ sprintf (wtext, "WINMOR Sound Card TNC - BPQ %s", TNC->PortRecord->PORTCONTROL.PORTDESCRIPTION);
+ SetWindowText(hwnd, wtext);
+ return FALSE;
+ }
+ }
+
+ return (TRUE);
+}
+#endif
+
+VOID ProcessResponse(struct TNCINFO * TNC, UCHAR * Buffer, int MsgLen)
+{
+ // Response on WINMOR control channel. Could be a reply to a command, or
+ // an Async Response
+
+ PMSGWITHLEN buffptr;
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ Buffer[MsgLen - 2] = 0;
+
+ if (_memicmp(Buffer, "FAULT failure to Restart Sound card", 20) == 0)
+ {
+ Debugprintf(Buffer);
+
+ // Force a restart
+
+ send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
+ send(TNC->TCPSock, "CODEC TRUE\r\n", 12, 0);
+ }
+ else
+ {
+ TNC->TimeSinceLast = 0;
+ }
+
+
+ if (_memicmp(Buffer, "STATE ", 6) == 0)
+ {
+ Debugprintf(Buffer);
+
+ if (_memicmp(&Buffer[6], "OFFLINE", 7) == 0)
+ {
+ // Force a restart
+
+ send(TNC->TCPSock, "CODEC FALSE\r\n", 13, 0);
+ send(TNC->TCPSock, "CODEC TRUE\r\n", 12, 0);
+ }
+ return;
+ }
+
+ Buffer[MsgLen - 2] = 0; // Remove CRLF
+
+ if (_memicmp(Buffer, "PTT T", 5) == 0)
+ {
+ TNC->Busy = TNC->BusyHold * 10; // BusyHold delay
+
+ if (TNC->PTTMode)
+ Rig_PTT(TNC, TRUE);
+ return;
+ }
+ if (_memicmp(Buffer, "PTT F", 5) == 0)
+ {
+ if (TNC->PTTMode)
+ Rig_PTT(TNC, FALSE);
+ return;
+ }
+
+ if (_memicmp(Buffer, "BUSY TRUE", 9) == 0)
+ {
+ TNC->BusyFlags |= CDBusy;
+ TNC->Busy = TNC->BusyHold * 10; // BusyHold delay
+
+ SetWindowText(TNC->xIDC_CHANSTATE, "Busy");
+ strcpy(TNC->WEB_CHANSTATE, "Busy");
+
+ TNC->WinmorRestartCodecTimer = time(NULL);
+ return;
+ }
+
+ if (_memicmp(Buffer, "BUSY FALSE", 10) == 0)
+ {
+ TNC->BusyFlags &= ~CDBusy;
+ if (TNC->BusyHold)
+ strcpy(TNC->WEB_CHANSTATE, "BusyHold");
+ else
+ strcpy(TNC->WEB_CHANSTATE, "Clear");
+
+ SetWindowText(TNC->xIDC_CHANSTATE, TNC->WEB_CHANSTATE);
+ TNC->WinmorRestartCodecTimer = time(NULL);
+ return;
+ }
+
+ if (_memicmp(Buffer, "TARGET", 6) == 0)
+ {
+ Debugprintf(Buffer);
+ GetSemaphore(&Semaphore, 50);
+ WritetoTrace(TNC, Buffer, MsgLen - 2);
+ FreeSemaphore(&Semaphore);
+ memcpy(TNC->TargetCall, &Buffer[7], 10);
+ return;
+ }
+
+ if (_memicmp(Buffer, "OFFSET", 6) == 0)
+ {
+// WritetoTrace(TNC, Buffer, MsgLen - 2);
+// memcpy(TNC->TargetCall, &Buffer[7], 10);
+ return;
+ }
+
+ if (_memicmp(Buffer, "CONNECTED", 9) == 0)
+ {
+ char Call[11];
+ char * ptr;
+ APPLCALLS * APPL;
+ char * ApplPtr = APPLS;
+ int App;
+ char Appl[10];
+ struct WL2KInfo * WL2K = TNC->WL2K;
+
+ Debugprintf(Buffer);
+
+ GetSemaphore(&Semaphore, 50);
+ WritetoTrace(TNC, Buffer, MsgLen - 2);
+ FreeSemaphore(&Semaphore);
+
+ STREAM->ConnectTime = time(NULL);
+ STREAM->bytesRXed = STREAM->bytesTXed = STREAM->PacketsSent = 0;
+
+ if (TNC->StartInRobust)
+ send(TNC->TCPSock, "ROBUST TRUE\r\n", 13, 0);
+
+ memcpy(Call, &Buffer[10], 10);
+
+ ptr = strchr(Call, ' ');
+ if (ptr) *ptr = 0;
+
+ TNC->HadConnect = TRUE;
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0)
+ {
+ TRANSPORTENTRY * SESS;
+
+ // Incomming Connect
+
+ TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit
+
+ // Stop other ports in same group
+
+ SuspendOtherPorts(TNC);
+
+ GetSemaphore(&Semaphore, 50);
+
+ ProcessIncommingConnectEx(TNC, Call, 0, TRUE, TRUE);
+ FreeSemaphore(&Semaphore);
+
+ SESS = TNC->PortRecord->ATTACHEDSESSIONS[0];
+
+ SESS->Mode = TNC->WL2KMode;
+
+ if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT"))
+ {
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", TNC->Streams[0].RemoteCall, TNC->TargetCall, TNC->RIG->Valchar);
+ SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq
+ SESS->Mode = TNC->WL2KMode;
+ }
+ else
+ {
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", TNC->Streams[0].RemoteCall, TNC->TargetCall);
+ if (WL2K)
+ {
+ SESS->Frequency = WL2K->Freq;
+ SESS->Mode = WL2K->mode;
+ }
+ }
+
+ if (WL2K)
+ strcpy(SESS->RMSCall, WL2K->RMSCall);
+
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ // Check for ExcludeList
+
+ if (ExcludeList[0])
+ {
+ if (CheckExcludeList(SESS->L4USER) == FALSE)
+ {
+ char Status[64];
+
+ TidyClose(TNC, 0);
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+ Debugprintf("WINMOR Call from %s rejected", Call);
+ return;
+ }
+ }
+
+ // IF WE HAVE A PERMITTED CALLS LIST, SEE IF HE IS IN IT
+
+ if (TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS)
+ {
+ UCHAR * ptr = TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS;
+
+ while (TRUE)
+ {
+ if (memcmp(SESS->L4USER, ptr, 6) == 0) // Ignore SSID
+ break;
+
+ ptr += 7;
+
+ if ((*ptr) == 0) // Not in list
+ {
+ char Status[64];
+
+ TidyClose(TNC, 0);
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+ Debugprintf("WINMOR Call from %s not in ValidCalls - rejected", Call);
+ return;
+ }
+ }
+ }
+
+ if (STREAM->BPQtoPACTOR_Q) //Used for CTEXT
+ {
+ PMSGWITHLEN buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q);
+
+ send(TNC->TCPDataSock, buffptr->Data, (int)buffptr->Len, 0);
+ STREAM->bytesTXed += (int)buffptr->Len;
+ WritetoTrace(TNC, buffptr->Data, (int)buffptr->Len);
+ ReleaseBuffer(buffptr);
+ }
+
+ // See which application the connect is for
+
+ for (App = 0; App < 32; App++)
+ {
+ APPL=&APPLCALLTABLE[App];
+ memcpy(Appl, APPL->APPLCALL_TEXT, 10);
+ ptr=strchr(Appl, ' ');
+
+ if (ptr)
+ *ptr = 0;
+
+ if (_stricmp(TNC->TargetCall, Appl) == 0)
+ break;
+ }
+
+ if (App < 32)
+ {
+ char AppName[13];
+
+ memcpy(AppName, &ApplPtr[App * sizeof(struct CMDX)], 12);
+ AppName[12] = 0;
+
+ // Make sure app is available
+
+ if (CheckAppl(TNC, AppName))
+ {
+ MsgLen = sprintf(Buffer, "%s\r", AppName);
+
+ GetSemaphore(&Semaphore, 50);
+
+ buffptr = GetBuff();
+
+ if (buffptr == 0)
+ {
+ FreeSemaphore(&Semaphore);
+ return; // No buffers, so ignore
+ }
+
+ buffptr->Len = MsgLen;
+ memcpy(buffptr->Data, Buffer, MsgLen);
+
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+
+ FreeSemaphore(&Semaphore);
+
+ TNC->SwallowSignon = TRUE;
+
+ // Save Appl Call in case needed for
+
+ }
+ else
+ {
+ char Msg[] = "Application not available\r\n";
+
+ // Send a Message, then a disconenct
+
+ send(TNC->TCPDataSock, Msg, (int)strlen(Msg), 0);
+ STREAM->NeedDisc = 100; // 10 secs
+ }
+ }
+
+ return;
+ }
+ else
+ {
+ // Connect Complete
+
+ char Reply[80];
+ int ReplyLen;
+
+ GetSemaphore(&Semaphore, 50);
+
+ buffptr = GetBuff();
+
+ if (buffptr == 0)
+ {
+ FreeSemaphore(&Semaphore);
+ return; // No buffers, so ignore
+ }
+ ReplyLen = sprintf(Reply, "*** Connected to %s\r", &Buffer[10]);
+
+ buffptr->Len = ReplyLen;
+ memcpy(buffptr->Data, Reply, ReplyLen);
+
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+
+ FreeSemaphore(&Semaphore);
+
+ TNC->Streams[0].Connecting = FALSE;
+ TNC->Streams[0].Connected = TRUE; // Subsequent data to data channel
+
+
+ if (TNC->RIG)
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall, TNC->RIG->Valchar);
+ else
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ UpdateMH(TNC, Call, '+', 'O');
+ return;
+ }
+ }
+
+ if (_memicmp(Buffer, "DISCONNECTED", 12) == 0)
+ {
+ Debugprintf(Buffer);
+
+ if (TNC->FECMode)
+ return;
+
+ if (TNC->StartSent)
+ {
+ TNC->StartSent = FALSE; // Disconnect reported following start codec
+ return;
+ }
+
+ if (TNC->Streams[0].Connecting)
+ {
+ // Report Connect Failed, and drop back to command mode
+
+ TNC->Streams[0].Connecting = FALSE;
+
+ GetSemaphore(&Semaphore, 50);
+
+ buffptr = GetBuff();
+
+ if (buffptr == 0)
+ {
+ FreeSemaphore(&Semaphore);
+ return; // No buffers, so ignore
+ }
+
+ buffptr->Len = sprintf(buffptr->Data, "Winmor} Failure with %s\r", TNC->Streams[0].RemoteCall);
+
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+
+ FreeSemaphore(&Semaphore);
+
+ if (TNC->RestartAfterFailure)
+ {
+ if (TNC->PID)
+ {
+ KillTNC(TNC);
+ RestartTNC(TNC);
+ }
+ }
+
+ return;
+ }
+
+
+ // Release Session
+
+ if (TNC->Streams[0].Connected)
+ {
+ hookL4SessionDeleted(TNC, STREAM);
+
+ GetSemaphore(&Semaphore, 50);
+ WritetoTrace(TNC, Buffer, MsgLen - 2);
+ FreeSemaphore(&Semaphore);
+ }
+
+
+ TNC->Streams[0].Connecting = FALSE;
+ TNC->Streams[0].Connected = FALSE; // Back to Command Mode
+ TNC->Streams[0].ReportDISC = TRUE; // Tell Node
+
+ if (TNC->Streams[0].Disconnecting) //
+ ReleaseTNC(TNC);
+
+ TNC->Streams[0].Disconnecting = FALSE;
+
+ return;
+ }
+
+ if (_memicmp(Buffer, "MONCALL", 7) == 0)
+ {
+ Debugprintf(Buffer);
+
+ // Add to MHEARD
+
+ GetSemaphore(&Semaphore, 50);
+ WritetoTrace(TNC, Buffer, MsgLen - 2);
+ FreeSemaphore(&Semaphore);
+ UpdateMH(TNC, &Buffer[8], '!', 0);
+
+ if (!TNC->FECMode)
+ return; // If in FEC mode pass ID messages to user.
+ }
+
+ if (_memicmp(Buffer, "CMD", 3) == 0)
+ {
+ return;
+ }
+
+ if (_memicmp(Buffer, "BUFFERS", 7) == 0)
+ {
+ int inq, inrx, Sent, BPM;
+
+ sscanf(&Buffer[8], "%d%d%d%d%d", &inq, &inrx, &TNC->Streams[0].BytesOutstanding, &Sent, &BPM);
+
+ if (TNC->Streams[0].BytesOutstanding == 0)
+ {
+ // all sent
+
+ if (TNC->Streams[0].Disconnecting) // Disconnect when all sent
+ {
+ if (STREAM->NeedDisc == 0)
+ STREAM->NeedDisc = 60; // 6 secs
+ }
+// else
+// if (TNC->TXRXState == 'S')
+// send(TNC->TCPSock,"OVER\r\n", 6, 0);
+
+ }
+ else
+ {
+ // Make sure Node Keepalive doesn't kill session.
+
+ TRANSPORTENTRY * SESS = TNC->PortRecord->ATTACHEDSESSIONS[0];
+
+ if (SESS)
+ {
+ SESS->L4KILLTIMER = 0;
+ SESS = SESS->L4CROSSLINK;
+ if (SESS)
+ SESS->L4KILLTIMER = 0;
+ }
+ }
+
+ SetWindowText(TNC->xIDC_TRAFFIC, &Buffer[8]);
+ strcpy(TNC->WEB_TRAFFIC, &Buffer[8]);
+ return;
+ }
+
+ Debugprintf(Buffer);
+
+ if (_memicmp(Buffer, "MODE", 4) == 0)
+ {
+ // Debugprintf("WINMOR RX: %s", Buffer);
+
+ strcpy(TNC->WEB_MODE, &Buffer[5]);
+ GetSemaphore(&Semaphore, 50);
+ MySetWindowText(TNC->xIDC_MODE, &Buffer[5]);
+ FreeSemaphore(&Semaphore);
+ return;
+ }
+
+ if (_memicmp(Buffer, "PENDING", 6) == 0)
+ return;
+
+ if (_memicmp(Buffer, "FAULT", 5) == 0)
+ {
+ WritetoTrace(TNC, Buffer, MsgLen - 2);
+ return;
+ }
+
+ if (_memicmp(Buffer, "NEWSTATE", 8) == 0)
+ {
+ TNC->WinmorRestartCodecTimer = time(NULL);
+
+ SetWindowText(TNC->xIDC_PROTOSTATE, &Buffer[9]);
+ strcpy(TNC->WEB_PROTOSTATE, &Buffer[9]);
+
+ if (_memicmp(&Buffer[9], "CONNECTPENDING", 14) == 0) // Save Pending state for scan control
+ TNC->ConnectPending = TRUE;
+ else
+ TNC->ConnectPending = FALSE;
+
+ if (_memicmp(&Buffer[9], "DISCONNECTING", 13) == 0) // So we can timout stuck discpending
+ {
+ TNC->DiscPending = 600;
+ return;
+ }
+ if (_memicmp(&Buffer[9], "DISCONNECTED", 12) == 0)
+ {
+ TNC->DiscPending = FALSE;
+ return;
+ }
+
+ if (strcmp(&Buffer[9], "ISS") == 0) // Save Pending state for scan control
+ TNC->TXRXState = 'S';
+ else if (strcmp(&Buffer[9], "IRS") == 0)
+ TNC->TXRXState = 'R';
+
+ return;
+ }
+
+
+ if (_memicmp(Buffer, "PROCESSID", 9) == 0)
+ {
+ HANDLE hProc;
+ char ExeName[256] = "";
+
+ TNC->PID = atoi(&Buffer[10]);
+
+#ifdef WIN32
+
+ // Get the File Name in case we want to restart it.
+
+ if (TNC->ProgramPath == NULL)
+ {
+ if (GetModuleFileNameExPtr)
+ {
+ hProc = OpenProcess(PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, FALSE, TNC->PID);
+
+ if (hProc)
+ {
+ GetModuleFileNameExPtr(hProc, 0, ExeName, 255);
+ CloseHandle(hProc);
+
+ TNC->ProgramPath = _strdup(ExeName);
+ }
+ }
+ }
+
+ // Set Window Title to reflect BPQ Port Description
+
+ EnumWindows(EnumTNCWindowsProc, (LPARAM)TNC);
+#endif
+ }
+
+ if ((_memicmp(Buffer, "FAULT Not from state FEC", 24) == 0) || (_memicmp(Buffer, "FAULT Blocked by Busy Lock", 24) == 0))
+ {
+ if (TNC->FECMode)
+ {
+ Sleep(1000);
+
+ if (TNC->FEC1600)
+ send(TNC->TCPSock,"FECSEND 1600\r\n", 14, 0);
+ else
+ send(TNC->TCPSock,"FECSEND 500\r\n", 13, 0);
+ return;
+ }
+ }
+
+ if (_memicmp(Buffer, "PLAYBACKDEVICES", 15) == 0)
+ {
+ TNC->PlaybackDevices = _strdup(&Buffer[16]);
+ }
+ // Others should be responses to commands
+
+ if (_memicmp(Buffer, "BLOCKED", 6) == 0)
+ {
+ WritetoTrace(TNC, Buffer, MsgLen - 2);
+ return;
+ }
+
+ if (_memicmp(Buffer, "OVER", 4) == 0)
+ {
+ WritetoTrace(TNC, Buffer, MsgLen - 2);
+ return;
+ }
+
+ GetSemaphore(&Semaphore, 50);
+
+ buffptr = GetBuff();
+
+ if (buffptr == 0)
+ {
+ FreeSemaphore(&Semaphore);
+ return; // No buffers, so ignore
+ }
+
+ buffptr->Len = sprintf(buffptr->Data, "Winmor} %s\r", Buffer);
+
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+ FreeSemaphore(&Semaphore);
+}
+
+static int ProcessReceivedData(struct TNCINFO * TNC)
+{
+ int InputLen, MsgLen;
+ char * ptr, * ptr2;
+ char Buffer[2000];
+
+ // May have several messages per packet, or message split over packets
+
+ if (TNC->InputLen > 1000) // Shouldnt have lines longer than this on command connection
+ TNC->InputLen=0;
+
+ InputLen=recv(TNC->TCPSock, &TNC->TCPBuffer[TNC->InputLen], 1000 - TNC->InputLen, 0);
+
+ if (InputLen == 0 || InputLen == SOCKET_ERROR)
+ {
+ // Does this mean closed?
+
+ closesocket(TNC->TCPSock);
+ closesocket(TNC->TCPDataSock);
+
+ TNC->TCPSock = 0;
+ TNC->TCPDataSock = 0;
+
+ TNC->CONNECTED = FALSE;
+ TNC->Streams[0].ReportDISC = TRUE;
+
+ return 0;
+ }
+
+ TNC->InputLen += InputLen;
+
+loop:
+
+ ptr = memchr(TNC->TCPBuffer, '\n', TNC->InputLen);
+
+ if (ptr) // CR in buffer
+ {
+ ptr2 = &TNC->TCPBuffer[TNC->InputLen];
+ ptr++; // Assume LF Follows CR
+
+ if (ptr == ptr2)
+ {
+ // Usual Case - single meg in buffer
+
+ ProcessResponse(TNC, TNC->TCPBuffer, TNC->InputLen);
+ TNC->InputLen=0;
+ }
+ else
+ {
+ // buffer contains more that 1 message
+
+ MsgLen = TNC->InputLen - (int)(ptr2-ptr);
+
+ memcpy(Buffer, TNC->TCPBuffer, MsgLen);
+
+ ProcessResponse(TNC, Buffer, MsgLen);
+ memmove(TNC->TCPBuffer, ptr, TNC->InputLen-MsgLen);
+
+ TNC->InputLen -= MsgLen;
+ goto loop;
+ }
+ }
+ return 0;
+}
+
+
+VOID ProcessDataSocketData(int port)
+{
+ // Info on Data Socket - just packetize and send on
+
+ struct TNCINFO * TNC = TNCInfo[port];
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ int InputLen, PacLen = 236;
+ PMSGWITHLEN buffptr;
+ char * msg;
+
+ TNC->TimeSinceLast = 0;
+
+loop:
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ InputLen = recv(TNC->TCPDataSock, buffptr->Data, PacLen, 0);
+
+ if (InputLen == -1)
+ {
+ ReleaseBuffer(buffptr);
+ return;
+ }
+
+
+ //Debugprintf("Winmor: RXD %d bytes", InputLen);
+
+ if (InputLen == 0)
+ {
+ // Does this mean closed?
+
+ sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost");
+ MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ TNC->CONNECTING = FALSE;
+ TNC->CONNECTED = FALSE;
+ TNC->Streams[0].ReportDISC = TRUE;
+
+ ReleaseBuffer(buffptr);
+ return;
+ }
+
+ STREAM->bytesRXed += InputLen;
+
+ msg = &buffptr->Data[0];
+ msg[InputLen] = 0;
+
+ WritetoTrace(TNC, msg, InputLen);
+
+ if (TNC->FECMode)
+ {
+ InputLen = (int)strlen(&buffptr->Data[0]);
+
+ if (msg[InputLen - 1] == 3) // End of errored block
+ msg[InputLen++] = 13; // Add CR
+
+ }
+ buffptr->Len = InputLen;
+ C_Q_ADD(&TNC->WINMORtoBPQ_Q, buffptr);
+
+ goto loop;
+}
+
+/*
+INT_PTR CALLBACK ConfigDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int Cmd = LOWORD(wParam);
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ {
+ struct TNCINFO * TNC = (struct TNCINFO * )lParam;
+ char * ptr1, *ptr2;
+ int ptr3 = 0;
+ char Line[1000];
+ int len;
+
+ ptr1 = TNC->CaptureDevices;
+
+ if (!ptr1)
+ return 0; // No Devices
+
+
+ while (ptr2 = strchr(ptr1, ','))
+ {
+ len = ptr2 - ptr1;
+ memcpy(&Line[ptr3], ptr1, len);
+ ptr3 += len;
+ Line[ptr3++] = '\r';
+ Line[ptr3++] = '\n';
+
+ ptr1 = ++ptr2;
+ }
+ Line[ptr3] = 0;
+ strcat(Line, ptr1);
+
+ SetDlgItemText(hDlg, IDC_CAPTURE, Line);
+
+ ptr3 = 0;
+
+ ptr1 = TNC->PlaybackDevices;
+
+ if (!ptr1)
+ return 0; // No Devices
+
+
+ while (ptr2 = strchr(ptr1, ','))
+ {
+ len = ptr2 - ptr1;
+ memcpy(&Line[ptr3], ptr1, len);
+ ptr3 += len;
+ Line[ptr3++] = '\r';
+ Line[ptr3++] = '\n';
+
+ ptr1 = ++ptr2;
+ }
+ Line[ptr3] = 0;
+ strcat(Line, ptr1);
+
+ SetDlgItemText(hDlg, IDC_PLAYBACK, Line);
+
+ SendDlgItemMessage(hDlg, IDC_PLAYBACK, EM_SETSEL, -1, 0);
+
+// KillTNC(TNC);
+
+ return TRUE;
+ }
+
+ case WM_SIZING:
+ {
+ return TRUE;
+ }
+
+ case WM_ACTIVATE:
+
+// SendDlgItemMessage(hDlg, IDC_MESSAGE, EM_SETSEL, -1, 0);
+
+ break;
+
+
+ case WM_COMMAND:
+
+
+ if (Cmd == IDCANCEL)
+ {
+ EndDialog(hDlg, LOWORD(wParam));
+ return (INT_PTR)TRUE;
+ }
+
+ return (INT_PTR)TRUE;
+
+ break;
+ }
+ return (INT_PTR)FALSE;
+}
+*/
+
+#ifdef LINBPQ
+#include
+#include
+#endif
+
+
+int KillTNC(struct TNCINFO * TNC)
+{
+ if (TNC->ProgramPath && _memicmp(TNC->ProgramPath, "REMOTE:", 7) == 0)
+ {
+ // Try to Kill TNC on a remote host
+
+ SOCKET sock = socket(AF_INET,SOCK_DGRAM,0);
+ struct sockaddr_in destaddr;
+ char Msg[256];
+ int Len;
+
+ if (sock == INVALID_SOCKET)
+ return 0;
+
+ destaddr.sin_family = AF_INET;
+ destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
+ destaddr.sin_port = htons(8500);
+
+ if (destaddr.sin_addr.s_addr == INADDR_NONE)
+ {
+ // Resolve name to address
+
+ struct hostent * HostEnt = gethostbyname (TNC->HostName);
+
+ if (!HostEnt)
+ return 0; // Resolve failed
+
+ memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+ }
+
+ if (TNC->PID)
+ Len = sprintf(Msg, "KILL %d", TNC->PID);
+ else
+ Len = sprintf(Msg, "KILLBYNAME %s", &TNC->ProgramPath[7]);
+
+ sendto(sock, Msg, Len, 0, (struct sockaddr *)&destaddr, sizeof(destaddr));
+ Sleep(100);
+ closesocket(sock);
+
+ TNC->PID = 0; // So we don't try again
+ return 1; // Cant tell if it worked, but assume ok
+ }
+
+ if (TNC->PID == 0)
+ return 0;
+
+#ifdef WIN32
+ {
+ HANDLE hProc;
+
+ Debugprintf("KillTNC Called for Pid %d", TNC->PID);
+
+ if (TNC->PTTMode)
+ Rig_PTT(TNC, FALSE); // Make sure PTT is down
+
+ hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, TNC->PID);
+
+ if (hProc)
+ {
+ TerminateProcess(hProc, 0);
+ CloseHandle(hProc);
+ }
+ }
+#else
+
+ printf("KillTNC Called for Pid %d Returned %d\n", TNC->PID, kill(TNC->PID, SIGTERM));
+
+#endif
+ TNC->PID = 0; // So we don't try again
+
+ return 0;
+}
+
+BOOL RestartTNC(struct TNCINFO * TNC)
+{
+ if (TNC->ProgramPath == NULL || TNC->DontRestart)
+ return 0;
+
+ if (_memicmp(TNC->ProgramPath, "REMOTE:", 7) == 0)
+ {
+ int n;
+
+ // Try to start TNC on a remote host
+
+ SOCKET sock = socket(AF_INET,SOCK_DGRAM,0);
+ struct sockaddr_in destaddr;
+
+ Debugprintf("trying to restart TNC %s", TNC->ProgramPath);
+
+ if (sock == INVALID_SOCKET)
+ return 0;
+
+ destaddr.sin_family = AF_INET;
+ destaddr.sin_addr.s_addr = inet_addr(TNC->HostName);
+ destaddr.sin_port = htons(8500);
+
+ if (destaddr.sin_addr.s_addr == INADDR_NONE)
+ {
+ // Resolve name to address
+
+ struct hostent * HostEnt = gethostbyname (TNC->HostName);
+
+ if (!HostEnt)
+ return 0; // Resolve failed
+
+ memcpy(&destaddr.sin_addr.s_addr,HostEnt->h_addr,4);
+ }
+
+ n = sendto(sock, TNC->ProgramPath, (int)strlen(TNC->ProgramPath), 0, (struct sockaddr *)&destaddr, sizeof(destaddr));
+
+ Debugprintf("Restart TNC - sendto returned %d", n);
+
+ Sleep(100);
+ closesocket(sock);
+
+ return 1; // Cant tell if it worked, but assume ok
+ }
+
+ // Not Remote
+
+ // Extract any parameters from command string
+
+#ifndef WIN32
+ {
+ char * arg_list[] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+ pid_t child_pid;
+ char * Copy, * Context;
+ signal(SIGCHLD, SIG_IGN); // Silently (and portably) reap children.
+
+ Copy = _strdup(TNC->ProgramPath); // Save as strtok mangles it
+
+ arg_list[0] = strtok_s(Copy, " \n\r", &Context);
+ if (arg_list[0])
+ arg_list[1] = strtok_s(NULL, " \n\r", &Context);
+ if (arg_list[1])
+ arg_list[2] = strtok_s(NULL, " \n\r", &Context);
+ if (arg_list[2])
+ arg_list[3] = strtok_s(NULL, " \n\r", &Context);
+ if (arg_list[3])
+ arg_list[4] = strtok_s(NULL, " \n\r", &Context);
+ if (arg_list[4])
+ arg_list[5] = strtok_s(NULL, " \n\r", &Context);
+ if (arg_list[5])
+ arg_list[6] = strtok_s(NULL, " \n\r", &Context);
+ if (arg_list[6])
+ arg_list[7] = strtok_s(NULL, " \n\r", &Context);
+
+ // Fork and Exec TNC
+
+ printf("Trying to start %s\n", TNC->ProgramPath);
+
+ /* Duplicate this process. */
+
+ child_pid = fork ();
+
+ if (child_pid == -1)
+ {
+ printf ("StartTNC fork() Failed\n");
+ free(Copy);
+ return 0;
+ }
+
+ if (child_pid == 0)
+ {
+ execvp (arg_list[0], arg_list);
+
+ /* The execvp function returns only if an error occurs. */
+
+ printf ("Failed to start TNC\n");
+ exit(0); // Kill the new process
+ }
+ else
+ {
+ TNC->PID = child_pid;
+ printf("Started TNC, Process ID = %d\n", TNC->PID);
+ }
+ free(Copy);
+ return TRUE;
+ }
+#else
+ {
+ int n = 0;
+
+ STARTUPINFO SInfo; // pointer to STARTUPINFO
+ PROCESS_INFORMATION PInfo; // pointer to PROCESS_INFORMATION
+ char workingDirectory[256];
+ int i = strlen(TNC->ProgramPath);
+
+ SInfo.cb=sizeof(SInfo);
+ SInfo.lpReserved=NULL;
+ SInfo.lpDesktop=NULL;
+ SInfo.lpTitle=NULL;
+ SInfo.dwFlags=0;
+ SInfo.cbReserved2=0;
+ SInfo.lpReserved2=NULL;
+
+ Debugprintf("RestartTNC Called for %s", TNC->ProgramPath);
+
+ strcpy(workingDirectory, TNC->ProgramPath);
+
+ while (i--)
+ {
+ if (workingDirectory[i] == '\\' || workingDirectory[i] == '/')
+ {
+ workingDirectory[i] = 0;
+ break;
+ }
+ }
+
+ while (KillOldTNC(TNC->ProgramPath) && n++ < 100)
+ {
+ Sleep(100);
+ }
+
+ if (CreateProcess(NULL, TNC->ProgramPath, NULL, NULL, FALSE,0, NULL, workingDirectory, &SInfo, &PInfo))
+ {
+ Debugprintf("Restart TNC OK");
+ TNC->PID = PInfo.dwProcessId;
+ return TRUE;
+ }
+ else
+ {
+ Debugprintf("Restart TNC Failed %d ", GetLastError());
+ return FALSE;
+ }
+ }
+#endif
+ return 0;
+}
+
+VOID TidyClose(struct TNCINFO * TNC, int Stream)
+{
+ // If all acked, send disc
+
+ if (TNC->Streams[0].BytesOutstanding == 0)
+ send(TNC->TCPSock,"DISCONNECT\r\n", 12, 0);
+}
+
+VOID ForcedClose(struct TNCINFO * TNC, int Stream)
+{
+ send(TNC->TCPSock,"DIRTYDISCONNECT\r\n", 17, 0);
+}
+
+VOID CloseComplete(struct TNCINFO * TNC, int Stream)
+{
+ ReleaseTNC(TNC);
+
+ if (TNC->FECMode)
+ {
+ TNC->FECMode = FALSE;
+ send(TNC->TCPSock,"SENDID 0\r\n", 10, 0);
+ }
+}
+
+BOOL KillOldTNC(char * Path)
+{
+#ifdef WIN32
+ HANDLE hProc;
+ char ExeName[256] = "";
+ DWORD Pid = 0;
+
+ DWORD Processes[1024], Needed, Count;
+ unsigned int i;
+
+ if (EnumProcessesPtr == NULL)
+ return FALSE;
+
+ if (!EnumProcessesPtr(Processes, sizeof(Processes), &Needed))
+ return FALSE;
+
+ // Calculate how many process identifiers were returned.
+
+ Count = Needed / sizeof(DWORD);
+
+ for (i = 0; i < Count; i++)
+ {
+ if (Processes[i] != 0)
+ {
+ hProc = OpenProcess(PROCESS_TERMINATE | PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, Processes[i]);
+
+ if (hProc)
+ {
+ GetModuleFileNameExPtr(hProc, 0, ExeName, 255);
+
+ // Path could have parameters, so use memcmp
+
+ if (_memicmp(ExeName, Path, strlen(ExeName)) == 0)
+ {
+ Debugprintf("Killing Pid %d %s", Processes[i], ExeName);
+ TerminateProcess(hProc, 0);
+ CloseHandle(hProc);
+ return TRUE;
+ }
+ CloseHandle(hProc);
+ }
+ }
+ }
+#endif
+ return FALSE;
+}
diff --git a/.svn/pristine/18/189d898ab4fc086c05a5870e1f63d0706d6449c3.svn-base b/.svn/pristine/18/189d898ab4fc086c05a5870e1f63d0706d6449c3.svn-base
index 4d12d2d..ec461d3 100644
--- a/.svn/pristine/18/189d898ab4fc086c05a5870e1f63d0706d6449c3.svn-base
+++ b/.svn/pristine/18/189d898ab4fc086c05a5870e1f63d0706d6449c3.svn-base
@@ -1,2172 +1,2172 @@
-/*
-Copyright 2001-2022 John Wiseman G8BPQ
-
-This file is part of LinBPQ/BPQ32.
-
-LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-LinBPQ/BPQ32 is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
-*/
-
-//
-// DLL to inteface KAM TNC in Pactor Mode to BPQ32 switch
-//
-// Uses BPQ EXTERNAL interface
-//
-
-// Version 1.2.1.2 July 2010
-
-// Send Change to ISS before each transmission
-// Support up to 32 BPQ Ports
-
-// Version 1.2.1.3 August 2010
-
-// Drop RTS as well as DTR on close
-
-// Version 1.2.1.4 August 2010
-
-// Save Minimized State
-
-// Version 1.2.1.5 September 2010
-
-// Fix Freq Display after Node reconfig
-// Only use AutoConnect APPL for Pactor Connects
-
-// Version 1.2.2.1 September 2010
-
-// Add option to get config from bpq32.cfg
-
-//#define WIN32_LEAN_AND_MEAN
-#define _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_DEPRECATE
-
-#include
-#include
-#include "time.h"
-
-#include "cheaders.h"
-#include "tncinfo.h"
-
-#include "bpq32.h"
-
-#define NARROWMODE Report_P1
-#define WIDEMODE Report_P1 // Only supports PI
-
-static char ClassName[]="KAMPACTORSTATUS";
-static char WindowTitle[] = "KAM Pactor";
-static int RigControlRow = 165;
-
-extern UCHAR LogDirectory[];
-static RECT Rect;
-
-int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
-VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len);
-VOID SuspendOtherPorts(struct TNCINFO * ThisTNC);
-VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
-
-static FILE * LogHandle[32] = {0};
-
-//char * Logs[4] = {"1", "2", "3", "4"};
-
-static char BaseDir[MAX_PATH]="c:\\";
-
-static BOOL WRITELOG = FALSE;
-
-BOOL KAMStopPort(struct PORTCONTROL * PORT)
-{
- // Disable Port - close TCP Sockets or Serial Port
-
- struct TNCINFO * TNC = PORT->TNC;
-
- TNC->CONNECTED = FALSE;
- TNC->Alerted = FALSE;
-
- if (TNC->Streams[0].Attached)
- TNC->Streams[0].ReportDISC = TRUE;
-
- if (TNC->hDevice)
- {
- CloseCOMPort(TNC->hDevice);
- TNC->hDevice = 0;
- }
-
- TNC->HostMode = FALSE;
-
- sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Stopped");
- MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
-
- return TRUE;
-}
-
-BOOL KAMStartPort(struct PORTCONTROL * PORT)
-{
- // Restart Port - Open Sockets or Serial Port
-
- struct TNCINFO * TNC = PORT->TNC;
-
- TNC->ReopenTimer = 999;
- TNC->ReinitState = 0;
-
- sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Restarted");
- MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
-
- return TRUE;
-}
-
-
-
-static VOID CloseLogFile(int Flags)
-{
- if (WRITELOG)
- {
- fclose(LogHandle[Flags]);
- LogHandle[Flags] = NULL;
- }
-}
-
-static BOOL OpenLogFile(int Flags)
-{
- if (WRITELOG)
- {
- UCHAR FN[MAX_PATH];
-
- time_t T;
- struct tm * tm;
-
- T = time(NULL);
- tm = gmtime(&T);
-
- sprintf(FN,"%s/logs/KAMLog_%02d%02d_%d.txt", LogDirectory, tm->tm_mon + 1, tm->tm_mday, Flags);
-
- LogHandle[Flags] = fopen(FN, "ab");
-
- return (LogHandle[Flags] != NULL);
- }
- return 0;
-}
-
-static void WriteLogLine(int Port, char * Msg, int MsgLen)
-{
- if (WRITELOG)
- {
- OpenLogFile(Port);
-
- if (LogHandle[Port])
- {
- fwrite(Msg, 1, MsgLen, LogHandle[Port]);
- fwrite("\r\n", 1, 2, LogHandle[Port]);
- }
- CloseLogFile(Port);
- }
-}
-
-
-
-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);
-
- BPQport = Port;
-
- TNC = TNCInfo[BPQport] = malloc(sizeof(struct TNCINFO));
- memset(TNC, 0, sizeof(struct TNCINFO));
-
- TNC->InitScript = malloc(1000);
- TNC->InitScript[0] = 0;
-
- goto ConfigLine;
-
-
- // 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, "DEBUGLOG", 8) == 0) // Write Debug Log
- WRITELOG = atoi(&buf[9]);
-
- else if (_memicmp(buf, "APPL", 4) == 0)
- {
- p_cmd = strtok(&buf[5], " \t\n\r");
-
- if (p_cmd && p_cmd[0] != ';' && p_cmd[0] != '#')
- TNC->ApplCmd=_strdup(_strupr(p_cmd));
- }
-
- else if (_memicmp(buf, "OLDMODE", 7) == 0)
- TNC->OldMode = TRUE;
-
- else if (_memicmp(buf, "VERYOLDMODE", 7) == 0)
- {
- TNC->OldMode = TRUE;
- TNC->VeryOldMode = TRUE;
- }
-
- else if (_memicmp(buf, "BUSYWAIT", 8) == 0) // Wait time beofre failing connect if busy
- TNC->BusyWait = atoi(&buf[8]);
-
- else if (_memicmp(buf, "WL2KREPORT", 10) == 0)
- TNC->WL2K = DecodeWL2KReportLine(buf);
-
- else
- strcat (TNC->InitScript, buf);
- }
- return (TRUE);
-}
-
-#define FEND 0xC0 // KISS CONTROL CODES
-#define FESC 0xDB
-#define TFEND 0xDC
-#define TFESC 0xDD
-
-static int MaxStreams = 26;
-
-BOOL CloseConnection(struct TNCINFO * conn);
-static BOOL WriteCommBlock(struct TNCINFO * TNC);
-BOOL DestroyTTYInfo(int port);
-void CheckRXKAM(struct TNCINFO * TNC);
-VOID KAMPoll(int Port);
-VOID ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * rxbuff, int len);
-static VOID ProcessTermModeResponse(struct TNCINFO * TNC);
-static VOID DoTNCReinit(struct TNCINFO * TNC);
-static VOID DoTermModeTimeout(struct TNCINFO * TNC);
-
-VOID ProcessPacket(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len);
-VOID ProcessKPacket(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len);
-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);
-static VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len);
-
-// Note that Kantronics host Mode uses KISS format Packets (without a KISS COntrol Byte)
-
-VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len);
-static int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
-static int KissDecode(UCHAR * inbuff, UCHAR * outbuff, int len);
-
-static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
-{
- int txlen;
- PMSGWITHLEN buffptr;
-
- struct TNCINFO * TNC = TNCInfo[port];
- struct STREAMINFO * STREAM;
-
- int Stream;
-
- size_t Param;
- struct ScanEntry * Scan;
-
- if (TNC == NULL)
- return 0;
-
- if (TNC->hDevice == 0)
- {
- // Clear anything from UI_Q
-
- while (TNC->PortRecord->UI_Q)
- {
- buffptr = Q_REM(&TNC->PortRecord->UI_Q);
- ReleaseBuffer(buffptr);
- }
-
- // Try to reopen every 30 secs
-
- if (fn > 3 && fn < 7)
- goto ok;
-
- TNC->ReopenTimer++;
-
- if (TNC->ReopenTimer < 300)
- return 0;
-
- TNC->ReopenTimer = 0;
-
- if (TNC->PortRecord->PORTCONTROL.PortStopped == 0)
- OpenCOMMPort(TNC, TNC->PortRecord->PORTCONTROL.SerialPortName, TNC->PortRecord->PORTCONTROL.BAUDRATE, TRUE);
-
- if (TNC->hDevice == 0)
- return 0;
- }
-
-ok:
-
- switch (fn)
- {
- case 7:
-
- // 100 mS Timer. May now be needed, as Poll can be called more frequently in some circumstances
-
- // G7TAJ's code to record activity for stats display
-
- if ( TNC->BusyFlags && CDBusy )
- TNC->PortRecord->PORTCONTROL.ACTIVE += 2;
-
- if ( TNC->PTTState )
- TNC->PortRecord->PORTCONTROL.SENDING += 2;
-
- CheckRXKAM(TNC);
- KAMPoll(port);
-
- return 0;
-
- 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++)
- {
- STREAM = &TNC->Streams[Stream];
-
- if (STREAM->ReportDISC)
- {
- STREAM->ReportDISC = FALSE;
- buff->PORT = Stream;
-
- return -1;
- }
- }
-
- for (Stream = 0; Stream <= MaxStreams; Stream++)
- {
- STREAM = &TNC->Streams[Stream];
-
- if (STREAM->PACTORtoBPQ_Q !=0)
- {
- int datalen;
-
- buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q);
-
- datalen = (int)buffptr->Len;
-
- buff->PORT = Stream;
- buff->PID= 0xf0;
- memcpy(buff->L2DATA, buffptr->Data, datalen); // Data goes to +7, but we have an extra byte
- datalen += (MSGHDDRLEN + 1);
-
- 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;
- STREAM = &TNC->Streams[Stream];
-
- if (!TNC->TNCOK)
- {
- // Send Error Response
-
- buffptr->Len = sprintf(buffptr->Data, "No Connection to PACTOR TNC\r");
-
- C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
-
- return 0;
- }
-
- txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1);
-
- buffptr->Len = txlen;
- memcpy(buffptr->Data, buff->L2DATA, txlen);
-
- C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
-
- if(STREAM->Connected)
- {
- STREAM->FramesOutstanding++;
- STREAM->FramesQueued++;
-
- STREAM->BytesOutstanding += txlen;
- }
- return (0);
-
-
- case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding
-
- Stream = (int)(size_t)buff;
-
- STREAM = &TNC->Streams[Stream];
-
- if (Stream == 0)
- {
- if (TNC->HFPacket)
- {
- if (TNC->Mem1 < 2000 || TNC->Streams[0].FramesOutstanding > 4)
- return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15);
-
- }
- else
- {
- if (TNC->Streams[0].FramesQueued > 4)
- return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15);
- }
- }
- else
- {
- if (STREAM->FramesOutstanding > 3 || STREAM->BytesOutstanding > 500 || TNC->Mem1 < 500)
- return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15);
- }
-
- return TNC->HostMode << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting
-
- case 4: // reinit
-
- return (0);
-
- case 5: // Close
-
- EncodeAndSend(TNC, "Q", 1); // Exit Host Mode
- Sleep(50);
-
- CloseCOMPort(TNCInfo[port]->hDevice);
- return (0);
-
- case 6: // Scan Control
-
- // Use P0 to Disable Pactor, P1 to enable
-
- Param = (size_t)buff;
-
- if (Param == 2) // Check Permission (shouldn't happen)
- {
- return 1; // OK to change
- }
-
- if (!TNC->HostMode)
- return 0; // No connection so no interlock
-
- if (Param == 1) // Request Permission
- return 0; // OK to Change // Dont want to mess with disabling it
-
- if (Param == 3) // Release Permission
- return 0;
-
- // Param is Address of a struct ScanEntry
-
- Scan = (struct ScanEntry *)buff;
-
- if (Scan->PMaxLevel >= '0' && Scan->PMaxLevel < '5') // 1 - 4
- {
- if (TNC->Bandwidth != Scan->PMaxLevel)
- {
- // Enable or disable by setting mycall
-
- TNC->Bandwidth = Scan->PMaxLevel;
-
- if (Scan->PMaxLevel == '0')
- {
- EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
- return 0;
- }
- if (TNC->OldMode)
- EncodeAndSend(TNC, "C20PACTOR", 9); // Back to Listen
- else
- EncodeAndSend(TNC, "C20TOR", 6); // Back to Listen
-
- TNC->InternalCmd = 'T';
- }
- }
- }
- return 0;
-}
-
-VOID KAMSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC)
-{
- struct STREAMINFO * STREAM = &TNC->Streams[0];
-
- strcpy(TNC->WEB_TNCSTATE, "Interlocked");
- MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
-// STREAM->CmdSet = STREAM->CmdSave = zalloc(100);
-// sprintf(STREAM->CmdSet, "I%s\r", "SCSPTC"); // Should prevent connects
-
-}
-
-VOID KAMReleasePort(struct TNCINFO * TNC)
-{
- struct STREAMINFO * STREAM = &TNC->Streams[0];
-
- strcpy(TNC->WEB_TNCSTATE, "Free");
- MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
-}
-
-
-static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
-{
- int Len = sprintf(Buff, ""
- "KAM Pactor StatusKAM Pactor Status
");
-
- Len += sprintf(&Buff[Len], "");
-
- Len += sprintf(&Buff[Len], "| Comms State | %s |
", TNC->WEB_COMMSSTATE);
- Len += sprintf(&Buff[Len], "| TNC State | %s |
", TNC->WEB_TNCSTATE);
- Len += sprintf(&Buff[Len], "| Mode | %s |
", TNC->WEB_MODE);
- Len += sprintf(&Buff[Len], "| Status | %s |
", TNC->WEB_STATE);
- Len += sprintf(&Buff[Len], "| TX/RX State | %s |
", TNC->WEB_TXRX);
- Len += sprintf(&Buff[Len], "| Free Space | %s |
", TNC->WEB_BUFFERS);
- Len += sprintf(&Buff[Len], "| Traffic | %s |
", TNC->WEB_TRAFFIC);
- Len += sprintf(&Buff[Len], "
");
-
- Len += sprintf(&Buff[Len], "", TNC->WebBuffer);
- Len = DoScanLine(TNC, Buff, Len);
-
- return Len;
-}
-
-
-void * KAMExtInit(EXTPORTDATA * PortEntry)
-{
- char msg[500];
- struct TNCINFO * TNC;
- int port;
- char * ptr;
- char * TempScript;
-
- port=PortEntry->PORTCONTROL.PORTNUMBER;
-
- sprintf(msg,"KAM Pactor %s", PortEntry->PORTCONTROL.SerialPortName);
- WritetoConsole(msg);
-
- 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\n");
- WritetoConsole(msg);
-
- return ExtProc;
- }
- TNC->Port = port;
- TNC->PortRecord = PortEntry;
-
- TNC->PortRecord->PORTCONTROL.HWType = TNC->Hardware = H_KAM;
-
- if (TNC->BusyWait == 0)
- TNC->BusyWait = 10;
-
- PortEntry->MAXHOSTMODESESSIONS = 11; // Default
-
-
- if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
- memcpy(TNC->NodeCall, MYNODECALL, 10);
- else
- ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
-
- PortEntry->PORTCONTROL.PROTOCOL = 10; // WINMOR/Pactor
- PortEntry->PORTCONTROL.PORTQUALITY = 0;
- PortEntry->SCANCAPABILITIES = NONE; // No Scan Control
-
- if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
- TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
-
- if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
- PortEntry->PORTCONTROL.PORTPACLEN = 100;
-
- PortEntry->PORTCONTROL.PORTSTARTCODE = KAMStartPort;
- PortEntry->PORTCONTROL.PORTSTOPCODE = KAMStopPort;
-
-// TNC->SuspendPortProc = KAMSuspendPort;
-// TNC->ReleasePortProc = KAMReleasePort;
-
-
-
- ptr=strchr(TNC->NodeCall, ' ');
- if (ptr) *(ptr) = 0; // Null Terminate
-
- // Set Essential Params and MYCALL
-
- TempScript = malloc(4000);
-
- strcpy(TempScript, "MARK 1400\r");
- strcat(TempScript, "SPACE 1600\r");
- strcat(TempScript, "SHIFT MODEM\r");
- strcat(TempScript, "INV ON\r");
- strcat(TempScript, "PTERRS 30\r"); // Default Retries
- strcat(TempScript, "MAXUSERS 1/10\r");
- strcat(TempScript, TNC->InitScript);
-
- free(TNC->InitScript);
- TNC->InitScript = TempScript;
-
- // Others go on end so they can't be overriden
-
- strcat(TNC->InitScript, "ECHO OFF\r");
- strcat(TNC->InitScript, "XMITECHO ON\r");
- strcat(TNC->InitScript, "TXFLOW OFF\r");
- strcat(TNC->InitScript, "XFLOW OFF\r");
- strcat(TNC->InitScript, "TRFLOW OFF\r");
- strcat(TNC->InitScript, "AUTOCR 0\r");
- strcat(TNC->InitScript, "AUTOLF OFF\r");
- strcat(TNC->InitScript, "CRADD OFF\r");
- strcat(TNC->InitScript, "CRSUP OFF\r");
- strcat(TNC->InitScript, "CRSUP OFF/OFF\r");
- strcat(TNC->InitScript, "LFADD OFF/OFF\r");
- strcat(TNC->InitScript, "LFADD OFF\r");
- strcat(TNC->InitScript, "LFSUP OFF/OFF\r");
- strcat(TNC->InitScript, "LFSUP OFF\r");
- strcat(TNC->InitScript, "RING OFF\r");
- strcat(TNC->InitScript, "ARQBBS OFF\r");
-
- // Set the ax.25 MYCALL
-
-
- sprintf(msg, "MYCALL %s/%s\r", TNC->NodeCall, TNC->NodeCall);
- strcat(TNC->InitScript, msg);
-
- // look for the MAXUSERS config line, and get the limits
-
- TNC->InitScript = _strupr(TNC->InitScript);
-
- ptr = strstr(TNC->InitScript, "MAXUSERS");
-
- if (ptr)
- {
- ptr = strchr(ptr,'/'); // to the separator
- if (ptr)
- PortEntry->MAXHOSTMODESESSIONS = atoi(++ptr) + 1;
- }
-
- if (PortEntry->MAXHOSTMODESESSIONS > 26)
- PortEntry->MAXHOSTMODESESSIONS = 26;
-
- 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->WebBuffer = zalloc(5000);
-
-#ifndef LINBPQ
-
- CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 500, 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, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "Status", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_STATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "TX/RX State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_TXRX = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "Free Space", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_BUFFERS = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL);
-
- CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,138,80,20, TNC->hDlg, NULL, hInstance, NULL);
- TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0 ACKED 0", WS_CHILD | WS_VISIBLE,116,138,374,20 , TNC->hDlg, NULL, hInstance, NULL);
-
- TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
- LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL,
- 0,RigControlRow + 44,250,300, TNC->hDlg, NULL, hInstance, NULL);
-
- TNC->ClientHeight = 500;
- TNC->ClientWidth = 500;
-
- MoveWindows(TNC);
-#endif
- OpenCOMMPort(TNC, PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE);
-
- WritetoConsole("\n");
-
- return ExtProc;
-}
-
-
-
-void CheckRXKAM(struct TNCINFO * TNC)
-{
- int Length, Len;
- char debug[512] = "RX: ";
-
- // 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;
-
- memcpy(&debug[4], TNC->RXBuffer, TNC->RXLen);
- debug[TNC->RXLen + 4] = 0;
- WriteLogLine(TNC->Port, debug, TNC->RXLen + 4);
-
- Length = TNC->RXLen;
-
- // If first char != FEND, then probably a Terminal Mode Frame. Wait for CR on end
-
- if (TNC->RXBuffer[0] != FEND)
- {
- // Char Mode Frame I think we need to see cmd: on end
-
- // If we think we are in host mode, then to could be noise - just discard.
-
- if (TNC->HostMode)
- {
- TNC->RXLen = 0; // Ready for next frame
- return;
- }
-
- TNC->RXBuffer[TNC->RXLen] = 0;
-
-// if (TNC->RXBuffer[TNC->RXLen-2] != ':')
- if (strstr(TNC->RXBuffer, "cmd:") == 0)
- return; // Wait for rest of frame
-
- // Complete Char Mode Frame
-
- TNC->RXLen = 0; // Ready for next frame
-
- if (TNC->HostMode == 0)
- {
- // We think TNC is in Terminal Mode
- ProcessTermModeResponse(TNC);
- return;
- }
- // We thought it was in Host Mode, but are wrong.
-
- TNC->HostMode = FALSE;
- return;
- }
-
- // Receiving a Host Mode frame
-
- if (TNC->HostMode == 0) // If we are in Term Mode, discard it. Probably in recovery
- {
- TNC->RXLen = 0; // Ready for next frame
- return;
- }
-
- if (Length < 3) // Minimum Frame Sise
- return;
-
- if (TNC->RXBuffer[Length-1] != FEND)
- return; // Wait till we have a full frame
-
- ProcessHostFrame(TNC, TNC->RXBuffer, Length); // Could have multiple packets in buffer
-
- TNC->RXLen = 0; // Ready for next frame
-
-
- return;
-
-}
-
-VOID ProcessHostFrame(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len)
-{
- UCHAR * FendPtr;
- int NewLen;
-
- // Split into KISS Packets. By far the most likely is a single KISS frame
- // so treat as special case
-
- if (rxbuffer[1] == FEND) // Two FENDS - probably got out of sync
- {
- rxbuffer++;
- Len--;
- }
-
- FendPtr = memchr(&rxbuffer[1], FEND, Len-1);
-
- if (FendPtr == &rxbuffer[Len-1])
- {
- ProcessKHOSTPacket(TNC, &rxbuffer[1], Len - 2);
- return;
- }
-
- // Process the first Packet in the buffer
-
- NewLen = (int)(FendPtr - rxbuffer - 1);
-
- ProcessKHOSTPacket(TNC, &rxbuffer[1], NewLen);
-
- // Loop Back
-
- ProcessHostFrame(TNC, FendPtr+1, Len - NewLen - 2);
- return;
-
-}
-
-
-
-static BOOL WriteCommBlock(struct TNCINFO * TNC)
-{
- char debug[512] = "TX: ";
-
- memcpy(&debug[4], TNC->TXBuffer, TNC->TXLen);
- debug[TNC->TXLen + 4] = 0;
-
- WriteLogLine(TNC->Port, debug, TNC->TXLen + 4);
-
- WriteCOMBlock(TNC->hDevice, TNC->TXBuffer, TNC->TXLen);
-
- return TRUE;
-}
-
-VOID KAMPoll(int Port)
-{
- struct TNCINFO * TNC = TNCInfo[Port];
- struct STREAMINFO * STREAM;
-
- UCHAR * Poll = TNC->TXBuffer;
- char Status[80];
- int Stream;
-
- if (TNC->PortRecord == 0)
- Stream = 0;
-
-
- // If Pactor Session has just been attached, drop back to cmd mode and set Pactor Call to
- // the connecting user's callsign
-
- for (Stream = 0; Stream <= MaxStreams; Stream++)
- {
- STREAM = &TNC->Streams[Stream];
-
- if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && STREAM->Attached == 0)
- {
- // New Attach
-
- STREAM->Attached = TRUE;
-
- if (Stream == 0) // HF Port
- {
- int calllen;
- UCHAR TXMsg[1000] = "D20";
- int datalen;
- char Msg[80];
-
- TNC->HFPacket = FALSE;
- TNC->TimeInRX = 0;
-
- calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, TNC->Streams[0].MyCall);
- TNC->Streams[0].MyCall[calllen] = 0;
-
- EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
- if (TNC->VeryOldMode)
- datalen = sprintf(TXMsg, "C20MYCALL %s", TNC->Streams[0].MyCall);
- else
- datalen = sprintf(TXMsg, "C20MYPTCALL %s", TNC->Streams[0].MyCall);
- EncodeAndSend(TNC, TXMsg, datalen);
- TNC->InternalCmd = 'M';
-
- TNC->NeedPACTOR = 0; // Cancel enter Pactor
-
- sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- // Stop Scanning
-
- sprintf(Msg, "%d SCANSTOP", TNC->Port);
-
- Rig_Command( (TRANSPORTENTRY *) -1, Msg);
-
- }
- }
- }
-
- if (TNC->Timeout)
- {
- TNC->Timeout--;
-
- if (TNC->Timeout) // Still waiting
- return;
-
- // Timed Out
-
- if (TNC->HostMode == 0)
- {
- DoTermModeTimeout(TNC);
- return;
- }
-
- // Timed out in host mode - Clear any connection and reinit the TNC
-
- Debugprintf("KAM PACTOR - Link to TNC Lost");
- TNC->TNCOK = FALSE;
- TNC->HostMode = 0;
- TNC->ReinitState = 0;
-
- sprintf(TNC->WEB_COMMSSTATE, "%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName);
- SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
-
- for (Stream = 0; Stream <= MaxStreams; Stream++)
- {
- PMSGWITHLEN buffptr;
-
- STREAM = &TNC->Streams[Stream];
-
- if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]) // Connected
- {
- STREAM->Connected = FALSE; // Back to Command Mode
- STREAM->ReportDISC = TRUE; // Tell Node
- }
-
- STREAM->FramesQueued = 0;
-
- while(STREAM->BPQtoPACTOR_Q)
- {
- buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
- ReleaseBuffer(buffptr);
- }
-
- while(STREAM->PACTORtoBPQ_Q)
- {
- buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q);
- ReleaseBuffer(buffptr);
- }
- }
- }
-
- for (Stream = 0; Stream <= MaxStreams; Stream++)
- {
- STREAM = &TNC->Streams[Stream];
-
- if (STREAM->Attached)
- CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete);
-
- }
-
- // if we have just restarted or TNC appears to be in terminal mode, run Initialisation Sequence
-
- if (!TNC->HostMode)
- {
- DoTNCReinit(TNC);
- return;
- }
-
- if (TNC->BusyDelay) // Waiting to send connect
- {
- // Still Busy?
-
- if (InterlockedCheckBusy(TNC) == 0)
- {
- // No, so send
-
- EncodeAndSend(TNC, TNC->ConnectCmd, (int)strlen(TNC->ConnectCmd));
- free(TNC->ConnectCmd);
-
- TNC->Timeout = 50;
- TNC->InternalCmd = 'C'; // So we dont send the reply to the user.
- STREAM->Connecting = TRUE;
-
- TNC->Streams[0].Connecting = TRUE;
-
- sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- TNC->BusyDelay = 0;
- return;
- }
- else
- {
- // Wait Longer
-
- TNC->BusyDelay--;
-
- if (TNC->BusyDelay == 0)
- {
- // Timed out - Send Error Response
-
- PMSGWITHLEN buffptr = GetBuff();
-
- if (buffptr == 0) return; // No buffers, so ignore
-
- buffptr->Len = sprintf(buffptr->Data, "Sorry, Can't Connect - Channel is busy\r");
-
- C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
-
- free(TNC->ConnectCmd);
-
- }
- }
- }
-
- if (TNC->NeedPACTOR)
- {
- TNC->NeedPACTOR--;
-
- if (TNC->NeedPACTOR == 0)
- {
- int datalen;
- UCHAR TXMsg[80] = "D20";
-
- if (TNC->VeryOldMode)
- datalen = sprintf(TXMsg, "C20MYCALL %s", TNC->NodeCall);
- else
- datalen = sprintf(TXMsg, "C20MYPTCALL %s", TNC->NodeCall);
- EncodeAndSend(TNC, TXMsg, datalen);
-
- if (TNC->OldMode)
- EncodeAndSend(TNC, "C20PACTOR", 9); // Back to Listen
- else
- EncodeAndSend(TNC, "C20TOR", 6); // Back to Listen
-
- TNC->InternalCmd = 'T';
- TNC->Timeout = 50;
- TNC->IntCmdDelay--;
-
- // Restart Scanning
-
- sprintf(Status, "%d SCANSTART 15", TNC->Port);
-
- Rig_Command( (TRANSPORTENTRY *) -1, Status);
-
- return;
- }
- }
-
- for (Stream = 0; Stream <= MaxStreams; Stream++)
- {
- STREAM = &TNC->Streams[Stream];
-
- // If in HF Packet mode, normal flow control doesn't seem to work
- // If more that 4 packets sent, send a status poll. and use response to
- // reset frames outstanding
-
- if ((Stream == 0) && (TNC->HFPacket) && (TNC->Streams[0].FramesOutstanding > 4))
- {
- EncodeAndSend(TNC, "C10S", 4);
- TNC->InternalCmd = 'S';
- TNC->Timeout = 50;
- return;
-
- }
-
- if (TNC->TNCOK && STREAM->BPQtoPACTOR_Q)
- {
- int datalen;
- UCHAR TXMsg[1000] = "D20";
- PMSGWITHLEN buffptr;
- UCHAR * MsgPtr;
- char Status[80];
-
- if (STREAM->Connected)
- {
- int Next;
-
- if (Stream > 0)
- sprintf(TXMsg, "D1%c", Stream + '@');
- else if (TNC->HFPacket)
- memcpy(TXMsg, "D2A", 3);
- else
- {
- // Pactor
-
- // Limit amount in TX, so we keep some on the TX Q and don't send turnround too early
-
- if (TNC->Streams[0].bytesTXed - TNC->Streams[0].BytesAcked > 200)
- continue;
-
- // Dont send if IRS State
- // If in IRS state for too long, force turnround
-
- if (TNC->TXRXState == 'R')
- {
- if (TNC->TimeInRX++ > 15)
- EncodeAndSend(TNC, "T", 1); // Changeover to ISS
- else
- goto Poll;
- }
- TNC->TimeInRX = 0;
- }
-
- buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
- STREAM->FramesQueued--;
-
- datalen = buffptr->Len;
- MsgPtr = buffptr->Data;
-
- if (TNC->SwallowSignon && Stream == 0)
- {
- TNC->SwallowSignon = FALSE;
- if (strstr(MsgPtr, "Connected")) // Discard *** connected
- {
- ReleaseBuffer(buffptr);
- return;
- }
- }
-
- Next = 0;
- STREAM->bytesTXed += datalen;
-
- if (Stream == 0)
- {
- while (datalen > 100) // Limit Pactor Sends
- {
- memcpy(&TXMsg[3], &MsgPtr[Next], 100);
- EncodeAndSend(TNC, TXMsg, 103);
- Next += 100;
- datalen -= 100;
-
- WritetoTrace(TNC, &TXMsg[3], 100);
- }
- }
-
- memcpy(&TXMsg[3], &MsgPtr[Next], datalen);
- EncodeAndSend(TNC, TXMsg, datalen + 3);
-
- WritetoTrace(TNC, &TXMsg[3], datalen);
-
- ReleaseBuffer(buffptr);
-
- if (Stream == 0)
- {
- sprintf(Status, "RX %d TX %d ACKED %d ",
- TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
- SetWindowText(TNC->xIDC_TRAFFIC, Status);
-
- if ((TNC->HFPacket == 0) && (TNC->Streams[0].BPQtoPACTOR_Q == 0)) // Nothing following
- {
- EncodeAndSend(TNC, "E", 1); // Changeover when all sent
- }
- }
-
- if (STREAM->Disconnecting)
- {
- Debugprintf("Send with Disc Pending, Q = %x", STREAM->BPQtoPACTOR_Q);
- if (STREAM->BPQtoPACTOR_Q == 0) // All Sent
-
- // KAM doesnt have a tidy close!
-
- STREAM->DisconnectingTimeout = 100; // Give 5 secs to get to other end
- }
- return;
- }
- else // Not Connected
- {
- buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q);
- datalen = buffptr->Len;
- MsgPtr = buffptr->Data;
-
- // Command. Do some sanity checking and look for things to process locally
-
- datalen--; // Exclude CR
- MsgPtr[datalen] = 0; // Null Terminate
- _strupr(MsgPtr);
-
- if ((Stream == 0) && memcmp(MsgPtr, "RADIO ", 6) == 0)
- {
- sprintf(&MsgPtr[40], "%d %s", TNC->Port, &MsgPtr[6]);
- if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &MsgPtr[40]))
- {
- ReleaseBuffer(buffptr);
- }
- else
- {
- buffptr->Len = sprintf(buffptr->Data, "%s", &MsgPtr[40]);
- C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
- }
- return;
- }
-
- if (_memicmp(MsgPtr, "D\r", 2) == 0)
- {
- STREAM->ReportDISC = TRUE; // Tell Node
- return;
- }
-
- if ((Stream == 0) && memcmp(MsgPtr, "HFPACKET", 8) == 0)
- {
- TNC->HFPacket = TRUE;
- buffptr->Len = sprintf(buffptr->Data, "KAM} 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);
- STREAM->Connecting = TRUE;
-
- // If Stream 0, Convert C CALL to PACTOR CALL
-
- if (Stream == 0)
- {
- if (TNC->HFPacket)
- datalen = sprintf(TXMsg, "C2AC %s", TNC->Streams[0].RemoteCall);
- else
- datalen = sprintf(TXMsg, "C20PACTOR %s", TNC->Streams[0].RemoteCall);
-
- // If Pactor, check busy detecters on any interlocked ports
-
- if (TNC->HFPacket == 0 && InterlockedCheckBusy(TNC) && TNC->OverrideBusy == 0)
- {
- // Channel Busy. Wait
-
- TNC->ConnectCmd = _strdup(TXMsg);
-
- sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- TNC->BusyDelay = TNC->BusyWait * 10;
-
- return;
- }
-
- TNC->OverrideBusy = FALSE;
-
- sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s",
- TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
- }
- else
- datalen = sprintf(TXMsg, "C1%cC %s", Stream + '@', STREAM->RemoteCall);
-
- EncodeAndSend(TNC, TXMsg, datalen);
- TNC->Timeout = 50;
- TNC->InternalCmd = 'C'; // So we dont send the reply to the user.
- ReleaseBuffer(buffptr);
- STREAM->Connecting = TRUE;
-
- return;
- }
-
- if (memcmp(MsgPtr, "GTOR ", 5) == 0) // GTOR Connect
- {
- memcpy(STREAM->RemoteCall, &MsgPtr[5], 9);
- STREAM->Connecting = TRUE;
-
- // If Stream 0, Convert C CALL to PACTOR CALL
-
- if (Stream == 0)
- {
- datalen = sprintf(TXMsg, "C20GTOR %s", TNC->Streams[0].RemoteCall);
-
- // If Pactor, check busy detecters on any interlocked ports
-
- if (TNC->HFPacket == 0 && InterlockedCheckBusy(TNC) && TNC->OverrideBusy == 0)
- {
- // Channel Busy. Wait
-
- TNC->ConnectCmd = _strdup(TXMsg);
-
- sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- TNC->BusyDelay = TNC->BusyWait * 10;
-
- return;
- }
-
- TNC->OverrideBusy = FALSE;
-
- sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s",
- TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
- }
- else
- datalen = sprintf(TXMsg, "C1%cC %s", Stream + '@', STREAM->RemoteCall);
-
- EncodeAndSend(TNC, TXMsg, datalen);
- TNC->Timeout = 50;
- TNC->InternalCmd = 'C'; // So we dont send the reply to the user.
- ReleaseBuffer(buffptr);
- STREAM->Connecting = TRUE;
-
- return;
- }
-
- if (memcmp(MsgPtr, "DISCONNECT", datalen) == 0) // Disconnect
- {
- if (Stream == 0)
- {
- if (TNC->HFPacket)
- EncodeAndSend(TNC, "C2AD", 4); // ??Return to packet mode??
- else
- EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
-
- TNC->NeedPACTOR = 50;
- }
- else
- {
- sprintf(TXMsg, "C1%cD", Stream + '@');
- EncodeAndSend(TNC, TXMsg, 4);
- TNC->CmdStream = Stream;
- TNC->Timeout = 50;
- }
-
- TNC->Timeout = 0; // Don't expect a response
- STREAM->Connecting = FALSE;
- STREAM->ReportDISC = TRUE;
- ReleaseBuffer(buffptr);
-
- return;
- }
-
- // Other Command ??
-
- if (Stream > 0)
- datalen = sprintf(TXMsg, "C1%c%s", Stream + '@', MsgPtr);
- else
- datalen = sprintf(TXMsg, "C20%s", MsgPtr);
- EncodeAndSend(TNC, TXMsg, datalen);
- ReleaseBuffer(buffptr);
- TNC->Timeout = 50;
- TNC->InternalCmd = 0;
- TNC->CmdStream = Stream;
-
- }
- }
- }
-
-Poll:
-
- // Need to poll data and control channel (for responses to commands)
-
- // Also check status if we have data buffered (for flow control)
-
- if (TNC->TNCOK)
- {
- if (TNC->IntCmdDelay == 50)
- {
- EncodeAndSend(TNC, "C10S", 4);
- TNC->InternalCmd = 'S';
- TNC->Timeout = 50;
- TNC->IntCmdDelay--;
- return;
- }
-
- if (TNC->IntCmdDelay <=0)
- {
- if (TNC->VeryOldMode == FALSE)
- {
- EncodeAndSend(TNC, "?", 1);
- TNC->InternalCmd = '?';
- TNC->Timeout = 50;
- }
- TNC->IntCmdDelay = 100; // Every 30
- return;
- }
- else
- TNC->IntCmdDelay--;
- }
-
- return;
-
-}
-
-static VOID DoTNCReinit(struct TNCINFO * TNC)
-{
- UCHAR * Poll = TNC->TXBuffer;
-
- if (TNC->ReinitState == 1) // Forcing back to Term
- TNC->ReinitState = 0; // Got Response, so must be back in term mode
-
- if (TNC->ReinitState == 0)
- {
- // Just Starting - Send a TNC Mode Command to see if in Terminal or Host Mode
-
- sprintf(TNC->WEB_COMMSSTATE,"%s Initialising TNC", TNC->PortRecord->PORTCONTROL.SerialPortName);
- SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
-
- Poll[0] = 13;
- TNC->TXLen = 1;
-
- WriteCommBlock(TNC);
- TNC->Timeout = 50;
-
- return;
- }
-
- if (TNC->ReinitState == 2) // In Term State, Sending Initialisation Commands
- {
- char * start, * end;
- int len;
-
- start = TNC->InitPtr;
-
- if (*(start) == 0) // End of Script
- {
- // Put into Host Mode
-
- memcpy(Poll, "INTFACE HOST\r", 13);
-
- TNC->TXLen = 13;
- WriteCommBlock(TNC);
- TNC->Timeout = 50;
-
- TNC->ReinitState = 4; // Need Reset
-
- return;
- }
-
- end = strchr(start, 13);
- len = (int)(++end - start);
- TNC->InitPtr = end;
- memcpy(Poll, start, len);
-
- TNC->TXLen = len;
- WriteCommBlock(TNC);
- TNC->Timeout = 50;
-
- return;
-
- }
-}
-
-static VOID DoTermModeTimeout(struct TNCINFO * TNC)
-{
- UCHAR * Poll = TNC->TXBuffer;
-
- if (TNC->ReinitState == 0)
- {
- //Checking if in Terminal Mode - Try to set back to Term Mode
-
- TNC->ReinitState = 1;
- Poll[0] = 3;
- Poll[1] = 0x58; // ?? Back to cmd: mode ??
- TNC->TXLen = 2;
-
- Poll[0] = 0xc0;
- Poll[1] = 'Q'; // ?? Back to cmd: mode ??
- Poll[2] = 0xc0;
- TNC->TXLen = 3;
-
- WriteCommBlock(TNC);
-
- return;
- }
- if (TNC->ReinitState == 1)
- {
- // Forcing back to Term Mode
-
- TNC->ReinitState = 0;
- DoTNCReinit(TNC); // See if worked
- return;
- }
-
- if (TNC->ReinitState == 3)
- {
- // Entering Host Mode
-
- // Assume ok
-
- TNC->HostMode = TRUE;
- return;
- }
-}
-
-
-
-static VOID ProcessTermModeResponse(struct TNCINFO * TNC)
-{
- UCHAR * Poll = TNC->TXBuffer;
-
- if (TNC->ReinitState == 0 || TNC->ReinitState == 1)
- {
- // Testing if in Term Mode. It is, so can now send Init Commands
-
- TNC->InitPtr = TNC->InitScript;
- TNC->ReinitState = 2;
- DoTNCReinit(TNC); // Send First Command
- return;
- }
- if (TNC->ReinitState == 2)
- {
- // Sending Init Commands
-
- DoTNCReinit(TNC); // Send Next Command
- return;
- }
-
- if (TNC->ReinitState == 4) // Send INTFACE, Need RESET
- {
- TNC->ReinitState = 5;
-
- memcpy(Poll, "RESET\r", 6);
-
- TNC->TXLen = 6;
- WriteCommBlock(TNC);
- TNC->Timeout = 50;
- TNC->HostMode = TRUE; // Should now be in Host Mode
- TNC->NeedPACTOR = 50; // Need to Send PACTOR command after 5 secs
-
- return;
- }
-
- if (TNC->ReinitState == 5) // RESET sent
- {
- TNC->ReinitState = 5;
-
- return;
- }
-
-
-
-}
-
-VOID ProcessKHOSTPacket(struct TNCINFO * TNC, UCHAR * Msg, int Len)
-{
- PMSGWITHLEN buffptr;
- char * Buffer = &Msg[3]; // Data portion of frame
- char * Call;
- char Status[80];
- int Stream = 0;
- struct STREAMINFO * STREAM;
-
- // Any valid frame is an ACK
-
- TNC->TNCOK = TRUE;
-
- Len = KissDecode(Msg, Msg, Len); // Remove KISS transparency
-
- if (Msg[1] == '0' && Msg[2] == '0')
- Stream = 0;
- else
- if (Msg[1] == '2') Stream = 0; else Stream = Msg[2] - '@';
-
- STREAM = &TNC->Streams[Stream];
-
- // See if Poll Reply or Data
-
- Msg[Len] = 0; // Terminate
-
- if (Msg[0] == 'M') // Monitor
- {
- DoMonitor(TNC, Msg, Len);
- return;
- }
-
-
- if (Msg[0] == 'E') // Data Echo
- {
- if (Msg[1] == '2') // HF Port
- {
- if (TNC->Streams[0].bytesTXed)
- TNC->Streams[0].BytesAcked += Len - 3; // We get an ack before the first send
-
- sprintf(Status, "RX %d TX %d ACKED %d ",
- TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
- SetWindowText(TNC->xIDC_TRAFFIC, Status);
-
- if (TNC->Streams[0].bytesTXed - TNC->Streams[0].BytesAcked < 500)
- TNC->Streams[0].FramesOutstanding = 0;
- }
- return;
- }
-
- if (Msg[0] == 'D') // Data
- {
- // Pass to Appl
-
- buffptr = GetBuff();
- if (buffptr == NULL) return; // No buffers, so ignore
-
- Len-=3; // Remove Header
-
- buffptr->Len = Len; // Length
- STREAM->bytesRXed += Len;
- memcpy(buffptr->Data, Buffer, Len);
-
- C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
-
- if (Stream == 0)
- {
- sprintf(TNC->WEB_TRAFFIC, "RX %d TX %d ACKED %d ",
- TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
- SetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC);
- }
-
- WritetoTrace(TNC, Buffer, Len);
-
- return;
- }
-
-
- if (Msg[0] == 'C') // Command Reponse
- {
- TNC->Timeout = 0;
-
- // See if we need to process locally (Response to our command, Incoming Call, Disconencted, etc
-
- // See if a response to internal command
-
- if (TNC->InternalCmd)
- {
- // Process it
-
- if (TNC->InternalCmd == 'S') // Status
- {
- char * Line;
- char * ptr;
-
- // Message is line giving free bytes, followed by a line for each active (packet) stream
-
- // FREE BYTES 1366/5094
- // A/2 #1145(12) CONNECTED to KE7XO-3
- // S/2 CONNECTED to NLV
-
- // each line is teminated by CR, and by the time it gets here it is null terminated
-
- //FREE BYTES 2628
- //A/H #80(1) CONNECTED to DK0MNL..
-
- if (TNC->HFPacket)
- TNC->Streams[0].FramesOutstanding = 0;
-
- Line = strchr(&Msg[3], 13);
- if (Line == 0) return;
-
- *(Line) = 0;
-
- ptr = strchr(&Msg[13], '/');
- TNC->Mem1 = atoi(&Msg[13]);
- if (ptr)
- TNC->Mem2 = atoi(++ptr);
- else
- TNC->Mem2 = 0;
-
- SetWindowText(TNC->xIDC_BUFFERS, &Msg[14]);
- strcpy(TNC->WEB_BUFFERS, &Msg[14]);
-
- while (Line[1] != 0) // End of stream
- {
- Stream = Line[1] - '@';
- STREAM = &TNC->Streams[Stream];
-
- if (Line[5] == '#')
- {
- STREAM->BytesOutstanding = atoi(&Line[6]);
- ptr = strchr(&Line[6], '(');
- if (ptr)
- STREAM->FramesOutstanding = atoi(++ptr);
- }
- else
- {
- STREAM->BytesOutstanding = 0;
- STREAM->FramesOutstanding = 0;
- }
-
- Line = strchr(&Line[1], 13);
- }
- return;
- }
- return;
- }
-
-
- WritetoTrace(TNC, Buffer, Len);
-
-
- // Pass to Appl
-
- Stream = TNC->CmdStream;
-
-
- buffptr = GetBuff();
-
- if (buffptr == NULL) return; // No buffers, so ignore
-
- buffptr->Len = sprintf(buffptr->Data,"KAM} %s", Buffer);
-
- C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
-
- return;
- }
-
- if (Msg[0] == 'I') // ISS/IRS State
- {
- if (Msg[2] == '1')
- {
- strcpy(TNC->WEB_TXRX, "Sender");
- SetWindowText(TNC->xIDC_TXRX, "Sender");
- TNC->TXRXState = 'S';
- }
- else
- {
- strcpy(TNC->WEB_TXRX, "Receiver");
- SetWindowText(TNC->xIDC_TXRX, "Receiver");
- TNC->TXRXState = 'R';
- }
- return;
- }
-
- if (Msg[0] == '?') // Status
- {
- TNC->Timeout = 0;
- return;
- }
-
- if (Msg[0] == 'S') // Status
- {
- if (Len < 4)
- {
- // Reset Response FEND FEND S00 FEND
-
- TNC->Timeout = 0;
-
- sprintf(TNC->WEB_COMMSSTATE,"%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName);
- SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
-
- return;
- }
-
- // Pass to Appl
-
- if (strstr(Buffer, "STANDBY>") || strstr(Buffer, "*** DISCONNECTED"))
- {
- 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)
- {
- // Connect Failed
-
- buffptr = GetBuff();
- if (buffptr == 0) return; // No buffers, so ignore
-
- buffptr->Len = sprintf(buffptr->Data, "*** Failure with %s\r", STREAM->RemoteCall);
-
- C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
-
- STREAM->Connecting = FALSE;
- STREAM->Connected = FALSE; // In case!
- STREAM->FramesOutstanding = 0;
-
- return;
- }
-
- // Must Have been connected or disconnecting - Release Session
-
- STREAM->Connecting = FALSE;
- STREAM->Connected = FALSE; // Back to Command Mode
- STREAM->FramesOutstanding = 0;
-
- if (STREAM->Disconnecting == FALSE)
- STREAM->ReportDISC = TRUE; // Tell Node
-
- STREAM->Disconnecting = FALSE;
-
- if (Stream == 0)
- {
- // Need to reset Pactor Call in case it was changed
-
- EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
- TNC->NeedPACTOR = 20;
- }
-
- return;
- }
-
- if (Msg[2] == '0')
- Call = strstr(Buffer, "HFPacket == 0)
- {
- Buffer[Len-4] = 0;
- }
-
- STREAM->bytesRXed = STREAM->bytesTXed = STREAM->BytesAcked = 0;
- STREAM->ConnectTime = time(NULL);
-
- if (Stream == 0)
- {
- // Stop Scanner
-
- char Msg[80];
-
- sprintf(Msg, "%d SCANSTOP", TNC->Port);
-
- Rig_Command( (TRANSPORTENTRY *) -1, Msg);
-
- sprintf(TNC->WEB_TRAFFIC, "RX %d TX %d ACKED %d ",
- TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
-
- SetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC);
- }
-
- if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0)
- {
- // Incoming Connect
-
- TRANSPORTENTRY * SESS;
-
- if (Msg[1] == '2' && Msg[2] == 'A')
- TNC->HFPacket = TRUE;
-
- // Stop other ports in same group
-
- SuspendOtherPorts(TNC);
-
- ProcessIncommingConnect(TNC, Call, Stream, TRUE);
-
- SESS = TNC->PortRecord->ATTACHEDSESSIONS[Stream];
-
- if (Stream == 0)
- {
- struct WL2KInfo * WL2K = TNC->WL2K;
- char FreqAppl[10] = ""; // Frequecy-specific application
-
- if (TNC->RIG && TNC->RIG != &TNC->DummyRig)
- {
- sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", TNC->Streams[0].RemoteCall, TNC->NodeCall, TNC->RIG->Valchar);
- SESS->Frequency = (atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq
-
- // If Scan Entry has a Appl, save it
-
- if (TNC->RIG->FreqPtr && TNC->RIG->FreqPtr[0]->APPL[0])
- strcpy(FreqAppl, &TNC->RIG->FreqPtr[0]->APPL[0]);
- }
- else
- {
- sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", TNC->Streams[0].RemoteCall, TNC->NodeCall);
-
- if (WL2K)
- {
- SESS->Frequency = WL2K->Freq;
- }
- }
-
- SESS->Mode = 11; // P1
-
- if (WL2K)
- strcpy(SESS->RMSCall, WL2K->RMSCall);
-
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- EncodeAndSend(TNC, "T", 1); // Changeover to ISS
-
- // If an autoconnect APPL is defined, send it
-
- if (FreqAppl[0]) // Frequency spcific APPL overrides TNC APPL
- {
- buffptr = GetBuff();
- if (buffptr == 0) return; // No buffers, so ignore
-
- buffptr->Len = sprintf(buffptr->Data, "%s\r", FreqAppl);
- C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
- TNC->SwallowSignon = TRUE;
- return;
- }
-
- if (TNC->ApplCmd)
- {
- buffptr = GetBuff();
- if (buffptr == 0) return; // No buffers, so ignore
-
- buffptr->Len = sprintf(buffptr->Data, "%s\r", TNC->ApplCmd);
- C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
-
- TNC->SwallowSignon = TRUE;
- return;
- }
- }
-
- if (FULL_CTEXT && HFCTEXTLEN == 0)
- {
- char CTBuff[300] = "D20";
- int Len = CTEXTLEN, CTPaclen = 50;
- int Next = 0;
-
- if (Stream > 0)
- sprintf(CTBuff, "D1%c", Stream + '@');
-
- while (Len > CTPaclen) // CTEXT Paclen
- {
- memcpy(&CTBuff[3], &CTEXTMSG[Next], CTPaclen);
- EncodeAndSend(TNC, CTBuff, CTPaclen + 3);
- Next += CTPaclen;
- Len -= CTPaclen;
- }
-
- memcpy(&CTBuff[3], &CTEXTMSG[Next], Len);
- EncodeAndSend(TNC, CTBuff, Len + 3);
- EncodeAndSend(TNC, "E", 1); // Changeover when all sent
- TNC->Streams[0].bytesTXed += CTEXTLEN;
- }
- return;
-
- }
- else
- {
- // Connect Complete
-
- buffptr = GetBuff();
- if (buffptr == 0) return; // No buffers, so ignore
-
- buffptr->Len = sprintf(buffptr->Data, "*** Connected to %s\r", Call);;
-
- C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
-
- STREAM->Connecting = FALSE;
- STREAM->Connected = TRUE; // Subsequent data to data channel
-
-
- if (Stream == 0)
- {
- if (TNC->RIG)
- sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall, TNC->RIG->Valchar);
- else
- sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
-
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- UpdateMH(TNC, Call, '+', 'O');
-
- }
-
- return;
- }
- }
- }
-}
-
-
-static int KissDecode(UCHAR * inbuff, UCHAR * outbuff, int len)
-{
- int i,txptr=0;
- UCHAR c;
-
- for (i=0;iTXLen = KissEncode(txbuffer, TNC->TXBuffer, Len);
- WriteCommBlock(TNC);
-}
-
-static int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len)
-{
- int i,txptr=0;
- UCHAR c;
-
- outbuff[0]=FEND;
- txptr=1;
-
- for (i=0;i');
-
- if (ptr) *(ptr) = 0;
-
- UpdateMH(TNC, &Msg[3], ' ', 0);
-
-}
-VOID TidyClose(struct TNCINFO * TNC, int Stream)
-{
- if (Stream == 0) // Pactor Stream
- {
- TNC->TimeInRX = 0;
- if (TNC->HFPacket)
- EncodeAndSend(TNC, "C2AD", 4); // Disconnect
- else
- EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
-// EncodeAndSend(TNC, "C20TOR", 6); // Disconnect
-
- TNC->HFPacket = FALSE;
- }
- else
- {
- UCHAR TXMsg[10];
-
- sprintf(TXMsg, "C1%cD", Stream + '@');
- EncodeAndSend(TNC, TXMsg, 4);
- TNC->Timeout = 50;
- }
-}
-
-VOID ForcedClose(struct TNCINFO * TNC, int Stream)
-{
- if (Stream == 0) // Pactor Stream
- {
- TNC->TimeInRX = 0;
-
- if (TNC->HFPacket)
- EncodeAndSend(TNC, "C2AD", 4); // Disconnect
- else
- EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
-
- TNC->HFPacket = FALSE;
- }
- else
- {
- UCHAR TXMsg[10];
-
- sprintf(TXMsg, "C1%cD", Stream + '@');
- EncodeAndSend(TNC, TXMsg, 4); // Send twice - must force a disconnect
- TNC->Timeout = 50;
- }}
-
-VOID CloseComplete(struct TNCINFO * TNC, int Stream)
-{
- sprintf(TNC->WEB_TNCSTATE, "Free");
- SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
-
- ReleaseOtherPorts(TNC);
- TNC->NeedPACTOR = 50;
-}
-
-
-
-/*
-
-
-MARK 1400
-SPACE 1600
-SHIFT MODEM
-INV ON
-MAXUSERS 1/10
-PTERRS 30
-
- // Others go on end so they can't be overriden
-
-ECHO OFF
-XMITECHO ON
-TXFLOW OFF
-XFLOW OFF
-TRFLOW OFF
-AUTOCR 0
-AUTOLF OFF
-CRADD OFF
-CRSUP OFF
-CRSUP OFF/OFF
-LFADD OFF/OFF
-LFADD OFF
-LFSUP OFF/OFF
-LFSUP OFF
-RING OFF
-ARQBBS OFF
-
-MYCALL
-
-*/
+/*
+Copyright 2001-2022 John Wiseman G8BPQ
+
+This file is part of LinBPQ/BPQ32.
+
+LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+LinBPQ/BPQ32 is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
+*/
+
+//
+// DLL to inteface KAM TNC in Pactor Mode to BPQ32 switch
+//
+// Uses BPQ EXTERNAL interface
+//
+
+// Version 1.2.1.2 July 2010
+
+// Send Change to ISS before each transmission
+// Support up to 32 BPQ Ports
+
+// Version 1.2.1.3 August 2010
+
+// Drop RTS as well as DTR on close
+
+// Version 1.2.1.4 August 2010
+
+// Save Minimized State
+
+// Version 1.2.1.5 September 2010
+
+// Fix Freq Display after Node reconfig
+// Only use AutoConnect APPL for Pactor Connects
+
+// Version 1.2.2.1 September 2010
+
+// Add option to get config from bpq32.cfg
+
+//#define WIN32_LEAN_AND_MEAN
+#define _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_DEPRECATE
+
+#include
+#include
+#include "time.h"
+
+#include "cheaders.h"
+#include "tncinfo.h"
+
+#include "bpq32.h"
+
+#define NARROWMODE Report_P1
+#define WIDEMODE Report_P1 // Only supports PI
+
+static char ClassName[]="KAMPACTORSTATUS";
+static char WindowTitle[] = "KAM Pactor";
+static int RigControlRow = 165;
+
+extern UCHAR LogDirectory[];
+static RECT Rect;
+
+int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len);
+VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len);
+VOID SuspendOtherPorts(struct TNCINFO * ThisTNC);
+VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC);
+
+static FILE * LogHandle[32] = {0};
+
+//char * Logs[4] = {"1", "2", "3", "4"};
+
+static char BaseDir[MAX_PATH]="c:\\";
+
+static BOOL WRITELOG = FALSE;
+
+BOOL KAMStopPort(struct PORTCONTROL * PORT)
+{
+ // Disable Port - close TCP Sockets or Serial Port
+
+ struct TNCINFO * TNC = PORT->TNC;
+
+ TNC->CONNECTED = FALSE;
+ TNC->Alerted = FALSE;
+
+ if (TNC->Streams[0].Attached)
+ TNC->Streams[0].ReportDISC = TRUE;
+
+ if (TNC->hDevice)
+ {
+ CloseCOMPort(TNC->hDevice);
+ TNC->hDevice = 0;
+ }
+
+ TNC->HostMode = FALSE;
+
+ sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Stopped");
+ MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
+
+ return TRUE;
+}
+
+BOOL KAMStartPort(struct PORTCONTROL * PORT)
+{
+ // Restart Port - Open Sockets or Serial Port
+
+ struct TNCINFO * TNC = PORT->TNC;
+
+ TNC->ReopenTimer = 999;
+ TNC->ReinitState = 0;
+
+ sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Restarted");
+ MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE);
+
+ return TRUE;
+}
+
+
+
+static VOID CloseLogFile(int Flags)
+{
+ if (WRITELOG)
+ {
+ fclose(LogHandle[Flags]);
+ LogHandle[Flags] = NULL;
+ }
+}
+
+static BOOL OpenLogFile(int Flags)
+{
+ if (WRITELOG)
+ {
+ UCHAR FN[MAX_PATH];
+
+ time_t T;
+ struct tm * tm;
+
+ T = time(NULL);
+ tm = gmtime(&T);
+
+ sprintf(FN,"%s/logs/KAMLog_%02d%02d_%d.txt", LogDirectory, tm->tm_mon + 1, tm->tm_mday, Flags);
+
+ LogHandle[Flags] = fopen(FN, "ab");
+
+ return (LogHandle[Flags] != NULL);
+ }
+ return 0;
+}
+
+static void WriteLogLine(int Port, char * Msg, int MsgLen)
+{
+ if (WRITELOG)
+ {
+ OpenLogFile(Port);
+
+ if (LogHandle[Port])
+ {
+ fwrite(Msg, 1, MsgLen, LogHandle[Port]);
+ fwrite("\r\n", 1, 2, LogHandle[Port]);
+ }
+ CloseLogFile(Port);
+ }
+}
+
+
+
+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);
+
+ BPQport = Port;
+
+ TNC = TNCInfo[BPQport] = malloc(sizeof(struct TNCINFO));
+ memset(TNC, 0, sizeof(struct TNCINFO));
+
+ TNC->InitScript = malloc(1000);
+ TNC->InitScript[0] = 0;
+
+ goto ConfigLine;
+
+
+ // 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, "DEBUGLOG", 8) == 0) // Write Debug Log
+ WRITELOG = atoi(&buf[9]);
+
+ else if (_memicmp(buf, "APPL", 4) == 0)
+ {
+ p_cmd = strtok(&buf[5], " \t\n\r");
+
+ if (p_cmd && p_cmd[0] != ';' && p_cmd[0] != '#')
+ TNC->ApplCmd=_strdup(_strupr(p_cmd));
+ }
+
+ else if (_memicmp(buf, "OLDMODE", 7) == 0)
+ TNC->OldMode = TRUE;
+
+ else if (_memicmp(buf, "VERYOLDMODE", 7) == 0)
+ {
+ TNC->OldMode = TRUE;
+ TNC->VeryOldMode = TRUE;
+ }
+
+ else if (_memicmp(buf, "BUSYWAIT", 8) == 0) // Wait time beofre failing connect if busy
+ TNC->BusyWait = atoi(&buf[8]);
+
+ else if (_memicmp(buf, "WL2KREPORT", 10) == 0)
+ TNC->WL2K = DecodeWL2KReportLine(buf);
+
+ else
+ strcat (TNC->InitScript, buf);
+ }
+ return (TRUE);
+}
+
+#define FEND 0xC0 // KISS CONTROL CODES
+#define FESC 0xDB
+#define TFEND 0xDC
+#define TFESC 0xDD
+
+static int MaxStreams = 26;
+
+BOOL CloseConnection(struct TNCINFO * conn);
+static BOOL WriteCommBlock(struct TNCINFO * TNC);
+BOOL DestroyTTYInfo(int port);
+void CheckRXKAM(struct TNCINFO * TNC);
+VOID KAMPoll(int Port);
+VOID ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * rxbuff, int len);
+static VOID ProcessTermModeResponse(struct TNCINFO * TNC);
+static VOID DoTNCReinit(struct TNCINFO * TNC);
+static VOID DoTermModeTimeout(struct TNCINFO * TNC);
+
+VOID ProcessPacket(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len);
+VOID ProcessKPacket(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len);
+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);
+static VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len);
+
+// Note that Kantronics host Mode uses KISS format Packets (without a KISS COntrol Byte)
+
+VOID EncodeAndSend(struct TNCINFO * TNC, UCHAR * txbuffer, int Len);
+static int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len);
+static int KissDecode(UCHAR * inbuff, UCHAR * outbuff, int len);
+
+static size_t ExtProc(int fn, int port, PDATAMESSAGE buff)
+{
+ int txlen;
+ PMSGWITHLEN buffptr;
+
+ struct TNCINFO * TNC = TNCInfo[port];
+ struct STREAMINFO * STREAM;
+
+ int Stream;
+
+ size_t Param;
+ struct ScanEntry * Scan;
+
+ if (TNC == NULL)
+ return 0;
+
+ if (TNC->hDevice == 0)
+ {
+ // Clear anything from UI_Q
+
+ while (TNC->PortRecord->UI_Q)
+ {
+ buffptr = Q_REM(&TNC->PortRecord->UI_Q);
+ ReleaseBuffer(buffptr);
+ }
+
+ // Try to reopen every 30 secs
+
+ if (fn > 3 && fn < 7)
+ goto ok;
+
+ TNC->ReopenTimer++;
+
+ if (TNC->ReopenTimer < 300)
+ return 0;
+
+ TNC->ReopenTimer = 0;
+
+ if (TNC->PortRecord->PORTCONTROL.PortStopped == 0)
+ OpenCOMMPort(TNC, TNC->PortRecord->PORTCONTROL.SerialPortName, TNC->PortRecord->PORTCONTROL.BAUDRATE, TRUE);
+
+ if (TNC->hDevice == 0)
+ return 0;
+ }
+
+ok:
+
+ switch (fn)
+ {
+ case 7:
+
+ // 100 mS Timer. May now be needed, as Poll can be called more frequently in some circumstances
+
+ // G7TAJ's code to record activity for stats display
+
+ if ( TNC->BusyFlags && CDBusy )
+ TNC->PortRecord->PORTCONTROL.ACTIVE += 2;
+
+ if ( TNC->PTTState )
+ TNC->PortRecord->PORTCONTROL.SENDING += 2;
+
+ CheckRXKAM(TNC);
+ KAMPoll(port);
+
+ return 0;
+
+ 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++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (STREAM->ReportDISC)
+ {
+ STREAM->ReportDISC = FALSE;
+ buff->PORT = Stream;
+
+ return -1;
+ }
+ }
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (STREAM->PACTORtoBPQ_Q !=0)
+ {
+ int datalen;
+
+ buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q);
+
+ datalen = (int)buffptr->Len;
+
+ buff->PORT = Stream;
+ buff->PID= 0xf0;
+ memcpy(buff->L2DATA, buffptr->Data, datalen); // Data goes to +7, but we have an extra byte
+ datalen += (MSGHDDRLEN + 1);
+
+ 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;
+ STREAM = &TNC->Streams[Stream];
+
+ if (!TNC->TNCOK)
+ {
+ // Send Error Response
+
+ buffptr->Len = sprintf(buffptr->Data, "No Connection to PACTOR TNC\r");
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ return 0;
+ }
+
+ txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1);
+
+ buffptr->Len = txlen;
+ memcpy(buffptr->Data, buff->L2DATA, txlen);
+
+ C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr);
+
+ if(STREAM->Connected)
+ {
+ STREAM->FramesOutstanding++;
+ STREAM->FramesQueued++;
+
+ STREAM->BytesOutstanding += txlen;
+ }
+ return (0);
+
+
+ case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding
+
+ Stream = (int)(size_t)buff;
+
+ STREAM = &TNC->Streams[Stream];
+
+ if (Stream == 0)
+ {
+ if (TNC->HFPacket)
+ {
+ if (TNC->Mem1 < 2000 || TNC->Streams[0].FramesOutstanding > 4)
+ return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15);
+
+ }
+ else
+ {
+ if (TNC->Streams[0].FramesQueued > 4)
+ return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15);
+ }
+ }
+ else
+ {
+ if (STREAM->FramesOutstanding > 3 || STREAM->BytesOutstanding > 500 || TNC->Mem1 < 500)
+ return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15);
+ }
+
+ return TNC->HostMode << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting
+
+ case 4: // reinit
+
+ return (0);
+
+ case 5: // Close
+
+ EncodeAndSend(TNC, "Q", 1); // Exit Host Mode
+ Sleep(50);
+
+ CloseCOMPort(TNCInfo[port]->hDevice);
+ return (0);
+
+ case 6: // Scan Control
+
+ // Use P0 to Disable Pactor, P1 to enable
+
+ Param = (size_t)buff;
+
+ if (Param == 2) // Check Permission (shouldn't happen)
+ {
+ return 1; // OK to change
+ }
+
+ if (!TNC->HostMode)
+ return 0; // No connection so no interlock
+
+ if (Param == 1) // Request Permission
+ return 0; // OK to Change // Dont want to mess with disabling it
+
+ if (Param == 3) // Release Permission
+ return 0;
+
+ // Param is Address of a struct ScanEntry
+
+ Scan = (struct ScanEntry *)buff;
+
+ if (Scan->PMaxLevel >= '0' && Scan->PMaxLevel < '5') // 1 - 4
+ {
+ if (TNC->Bandwidth != Scan->PMaxLevel)
+ {
+ // Enable or disable by setting mycall
+
+ TNC->Bandwidth = Scan->PMaxLevel;
+
+ if (Scan->PMaxLevel == '0')
+ {
+ EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
+ return 0;
+ }
+ if (TNC->OldMode)
+ EncodeAndSend(TNC, "C20PACTOR", 9); // Back to Listen
+ else
+ EncodeAndSend(TNC, "C20TOR", 6); // Back to Listen
+
+ TNC->InternalCmd = 'T';
+ }
+ }
+ }
+ return 0;
+}
+
+VOID KAMSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC)
+{
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ strcpy(TNC->WEB_TNCSTATE, "Interlocked");
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+// STREAM->CmdSet = STREAM->CmdSave = zalloc(100);
+// sprintf(STREAM->CmdSet, "I%s\r", "SCSPTC"); // Should prevent connects
+
+}
+
+VOID KAMReleasePort(struct TNCINFO * TNC)
+{
+ struct STREAMINFO * STREAM = &TNC->Streams[0];
+
+ strcpy(TNC->WEB_TNCSTATE, "Free");
+ MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+}
+
+
+static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL)
+{
+ int Len = sprintf(Buff, ""
+ "KAM Pactor StatusKAM Pactor Status
");
+
+ Len += sprintf(&Buff[Len], "");
+
+ Len += sprintf(&Buff[Len], "| Comms State | %s |
", TNC->WEB_COMMSSTATE);
+ Len += sprintf(&Buff[Len], "| TNC State | %s |
", TNC->WEB_TNCSTATE);
+ Len += sprintf(&Buff[Len], "| Mode | %s |
", TNC->WEB_MODE);
+ Len += sprintf(&Buff[Len], "| Status | %s |
", TNC->WEB_STATE);
+ Len += sprintf(&Buff[Len], "| TX/RX State | %s |
", TNC->WEB_TXRX);
+ Len += sprintf(&Buff[Len], "| Free Space | %s |
", TNC->WEB_BUFFERS);
+ Len += sprintf(&Buff[Len], "| Traffic | %s |
", TNC->WEB_TRAFFIC);
+ Len += sprintf(&Buff[Len], "
");
+
+ Len += sprintf(&Buff[Len], "", TNC->WebBuffer);
+ Len = DoScanLine(TNC, Buff, Len);
+
+ return Len;
+}
+
+
+void * KAMExtInit(EXTPORTDATA * PortEntry)
+{
+ char msg[500];
+ struct TNCINFO * TNC;
+ int port;
+ char * ptr;
+ char * TempScript;
+
+ port=PortEntry->PORTCONTROL.PORTNUMBER;
+
+ sprintf(msg,"KAM Pactor %s", PortEntry->PORTCONTROL.SerialPortName);
+ WritetoConsole(msg);
+
+ 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\n");
+ WritetoConsole(msg);
+
+ return ExtProc;
+ }
+ TNC->Port = port;
+ TNC->PortRecord = PortEntry;
+
+ TNC->PortRecord->PORTCONTROL.HWType = TNC->Hardware = H_KAM;
+
+ if (TNC->BusyWait == 0)
+ TNC->BusyWait = 10;
+
+ PortEntry->MAXHOSTMODESESSIONS = 11; // Default
+
+
+ if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
+ memcpy(TNC->NodeCall, MYNODECALL, 10);
+ else
+ ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
+
+ PortEntry->PORTCONTROL.PROTOCOL = 10; // WINMOR/Pactor
+ PortEntry->PORTCONTROL.PORTQUALITY = 0;
+ PortEntry->SCANCAPABILITIES = NONE; // No Scan Control
+
+ if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
+ TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
+
+ if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
+ PortEntry->PORTCONTROL.PORTPACLEN = 100;
+
+ PortEntry->PORTCONTROL.PORTSTARTCODE = KAMStartPort;
+ PortEntry->PORTCONTROL.PORTSTOPCODE = KAMStopPort;
+
+// TNC->SuspendPortProc = KAMSuspendPort;
+// TNC->ReleasePortProc = KAMReleasePort;
+
+
+
+ ptr=strchr(TNC->NodeCall, ' ');
+ if (ptr) *(ptr) = 0; // Null Terminate
+
+ // Set Essential Params and MYCALL
+
+ TempScript = malloc(4000);
+
+ strcpy(TempScript, "MARK 1400\r");
+ strcat(TempScript, "SPACE 1600\r");
+ strcat(TempScript, "SHIFT MODEM\r");
+ strcat(TempScript, "INV ON\r");
+ strcat(TempScript, "PTERRS 30\r"); // Default Retries
+ strcat(TempScript, "MAXUSERS 1/10\r");
+ strcat(TempScript, TNC->InitScript);
+
+ free(TNC->InitScript);
+ TNC->InitScript = TempScript;
+
+ // Others go on end so they can't be overriden
+
+ strcat(TNC->InitScript, "ECHO OFF\r");
+ strcat(TNC->InitScript, "XMITECHO ON\r");
+ strcat(TNC->InitScript, "TXFLOW OFF\r");
+ strcat(TNC->InitScript, "XFLOW OFF\r");
+ strcat(TNC->InitScript, "TRFLOW OFF\r");
+ strcat(TNC->InitScript, "AUTOCR 0\r");
+ strcat(TNC->InitScript, "AUTOLF OFF\r");
+ strcat(TNC->InitScript, "CRADD OFF\r");
+ strcat(TNC->InitScript, "CRSUP OFF\r");
+ strcat(TNC->InitScript, "CRSUP OFF/OFF\r");
+ strcat(TNC->InitScript, "LFADD OFF/OFF\r");
+ strcat(TNC->InitScript, "LFADD OFF\r");
+ strcat(TNC->InitScript, "LFSUP OFF/OFF\r");
+ strcat(TNC->InitScript, "LFSUP OFF\r");
+ strcat(TNC->InitScript, "RING OFF\r");
+ strcat(TNC->InitScript, "ARQBBS OFF\r");
+
+ // Set the ax.25 MYCALL
+
+
+ sprintf(msg, "MYCALL %s/%s\r", TNC->NodeCall, TNC->NodeCall);
+ strcat(TNC->InitScript, msg);
+
+ // look for the MAXUSERS config line, and get the limits
+
+ TNC->InitScript = _strupr(TNC->InitScript);
+
+ ptr = strstr(TNC->InitScript, "MAXUSERS");
+
+ if (ptr)
+ {
+ ptr = strchr(ptr,'/'); // to the separator
+ if (ptr)
+ PortEntry->MAXHOSTMODESESSIONS = atoi(++ptr) + 1;
+ }
+
+ if (PortEntry->MAXHOSTMODESESSIONS > 26)
+ PortEntry->MAXHOSTMODESESSIONS = 26;
+
+ 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->WebBuffer = zalloc(5000);
+
+#ifndef LINBPQ
+
+ CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 500, 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, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Status", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_STATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "TX/RX State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TXRX = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Free Space", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_BUFFERS = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,138,80,20, TNC->hDlg, NULL, hInstance, NULL);
+ TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0 ACKED 0", WS_CHILD | WS_VISIBLE,116,138,374,20 , TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT |
+ LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL,
+ 0,RigControlRow + 44,250,300, TNC->hDlg, NULL, hInstance, NULL);
+
+ TNC->ClientHeight = 500;
+ TNC->ClientWidth = 500;
+
+ MoveWindows(TNC);
+#endif
+ OpenCOMMPort(TNC, PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE);
+
+ WritetoConsole("\n");
+
+ return ExtProc;
+}
+
+
+
+void CheckRXKAM(struct TNCINFO * TNC)
+{
+ int Length, Len;
+ char debug[512] = "RX: ";
+
+ // 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;
+
+ memcpy(&debug[4], TNC->RXBuffer, TNC->RXLen);
+ debug[TNC->RXLen + 4] = 0;
+ WriteLogLine(TNC->Port, debug, TNC->RXLen + 4);
+
+ Length = TNC->RXLen;
+
+ // If first char != FEND, then probably a Terminal Mode Frame. Wait for CR on end
+
+ if (TNC->RXBuffer[0] != FEND)
+ {
+ // Char Mode Frame I think we need to see cmd: on end
+
+ // If we think we are in host mode, then to could be noise - just discard.
+
+ if (TNC->HostMode)
+ {
+ TNC->RXLen = 0; // Ready for next frame
+ return;
+ }
+
+ TNC->RXBuffer[TNC->RXLen] = 0;
+
+// if (TNC->RXBuffer[TNC->RXLen-2] != ':')
+ if (strstr(TNC->RXBuffer, "cmd:") == 0)
+ return; // Wait for rest of frame
+
+ // Complete Char Mode Frame
+
+ TNC->RXLen = 0; // Ready for next frame
+
+ if (TNC->HostMode == 0)
+ {
+ // We think TNC is in Terminal Mode
+ ProcessTermModeResponse(TNC);
+ return;
+ }
+ // We thought it was in Host Mode, but are wrong.
+
+ TNC->HostMode = FALSE;
+ return;
+ }
+
+ // Receiving a Host Mode frame
+
+ if (TNC->HostMode == 0) // If we are in Term Mode, discard it. Probably in recovery
+ {
+ TNC->RXLen = 0; // Ready for next frame
+ return;
+ }
+
+ if (Length < 3) // Minimum Frame Sise
+ return;
+
+ if (TNC->RXBuffer[Length-1] != FEND)
+ return; // Wait till we have a full frame
+
+ ProcessHostFrame(TNC, TNC->RXBuffer, Length); // Could have multiple packets in buffer
+
+ TNC->RXLen = 0; // Ready for next frame
+
+
+ return;
+
+}
+
+VOID ProcessHostFrame(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len)
+{
+ UCHAR * FendPtr;
+ int NewLen;
+
+ // Split into KISS Packets. By far the most likely is a single KISS frame
+ // so treat as special case
+
+ if (rxbuffer[1] == FEND) // Two FENDS - probably got out of sync
+ {
+ rxbuffer++;
+ Len--;
+ }
+
+ FendPtr = memchr(&rxbuffer[1], FEND, Len-1);
+
+ if (FendPtr == &rxbuffer[Len-1])
+ {
+ ProcessKHOSTPacket(TNC, &rxbuffer[1], Len - 2);
+ return;
+ }
+
+ // Process the first Packet in the buffer
+
+ NewLen = (int)(FendPtr - rxbuffer - 1);
+
+ ProcessKHOSTPacket(TNC, &rxbuffer[1], NewLen);
+
+ // Loop Back
+
+ ProcessHostFrame(TNC, FendPtr+1, Len - NewLen - 2);
+ return;
+
+}
+
+
+
+static BOOL WriteCommBlock(struct TNCINFO * TNC)
+{
+ char debug[512] = "TX: ";
+
+ memcpy(&debug[4], TNC->TXBuffer, TNC->TXLen);
+ debug[TNC->TXLen + 4] = 0;
+
+ WriteLogLine(TNC->Port, debug, TNC->TXLen + 4);
+
+ WriteCOMBlock(TNC->hDevice, TNC->TXBuffer, TNC->TXLen);
+
+ return TRUE;
+}
+
+VOID KAMPoll(int Port)
+{
+ struct TNCINFO * TNC = TNCInfo[Port];
+ struct STREAMINFO * STREAM;
+
+ UCHAR * Poll = TNC->TXBuffer;
+ char Status[80];
+ int Stream;
+
+ if (TNC->PortRecord == 0)
+ Stream = 0;
+
+
+ // If Pactor Session has just been attached, drop back to cmd mode and set Pactor Call to
+ // the connecting user's callsign
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && STREAM->Attached == 0)
+ {
+ // New Attach
+
+ STREAM->Attached = TRUE;
+
+ if (Stream == 0) // HF Port
+ {
+ int calllen;
+ UCHAR TXMsg[1000] = "D20";
+ int datalen;
+ char Msg[80];
+
+ TNC->HFPacket = FALSE;
+ TNC->TimeInRX = 0;
+
+ calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, TNC->Streams[0].MyCall);
+ TNC->Streams[0].MyCall[calllen] = 0;
+
+ EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
+ if (TNC->VeryOldMode)
+ datalen = sprintf(TXMsg, "C20MYCALL %s", TNC->Streams[0].MyCall);
+ else
+ datalen = sprintf(TXMsg, "C20MYPTCALL %s", TNC->Streams[0].MyCall);
+ EncodeAndSend(TNC, TXMsg, datalen);
+ TNC->InternalCmd = 'M';
+
+ TNC->NeedPACTOR = 0; // Cancel enter Pactor
+
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ // Stop Scanning
+
+ sprintf(Msg, "%d SCANSTOP", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Msg);
+
+ }
+ }
+ }
+
+ if (TNC->Timeout)
+ {
+ TNC->Timeout--;
+
+ if (TNC->Timeout) // Still waiting
+ return;
+
+ // Timed Out
+
+ if (TNC->HostMode == 0)
+ {
+ DoTermModeTimeout(TNC);
+ return;
+ }
+
+ // Timed out in host mode - Clear any connection and reinit the TNC
+
+ Debugprintf("KAM PACTOR - Link to TNC Lost");
+ TNC->TNCOK = FALSE;
+ TNC->HostMode = 0;
+ TNC->ReinitState = 0;
+
+ sprintf(TNC->WEB_COMMSSTATE, "%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ PMSGWITHLEN buffptr;
+
+ STREAM = &TNC->Streams[Stream];
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]) // Connected
+ {
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->ReportDISC = TRUE; // Tell Node
+ }
+
+ STREAM->FramesQueued = 0;
+
+ while(STREAM->BPQtoPACTOR_Q)
+ {
+ buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
+ ReleaseBuffer(buffptr);
+ }
+
+ while(STREAM->PACTORtoBPQ_Q)
+ {
+ buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q);
+ ReleaseBuffer(buffptr);
+ }
+ }
+ }
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (STREAM->Attached)
+ CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete);
+
+ }
+
+ // if we have just restarted or TNC appears to be in terminal mode, run Initialisation Sequence
+
+ if (!TNC->HostMode)
+ {
+ DoTNCReinit(TNC);
+ return;
+ }
+
+ if (TNC->BusyDelay) // Waiting to send connect
+ {
+ // Still Busy?
+
+ if (InterlockedCheckBusy(TNC) == 0)
+ {
+ // No, so send
+
+ EncodeAndSend(TNC, TNC->ConnectCmd, (int)strlen(TNC->ConnectCmd));
+ free(TNC->ConnectCmd);
+
+ TNC->Timeout = 50;
+ TNC->InternalCmd = 'C'; // So we dont send the reply to the user.
+ STREAM->Connecting = TRUE;
+
+ TNC->Streams[0].Connecting = TRUE;
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ TNC->BusyDelay = 0;
+ return;
+ }
+ else
+ {
+ // Wait Longer
+
+ TNC->BusyDelay--;
+
+ if (TNC->BusyDelay == 0)
+ {
+ // Timed out - Send Error Response
+
+ PMSGWITHLEN buffptr = GetBuff();
+
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "Sorry, Can't Connect - Channel is busy\r");
+
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+
+ free(TNC->ConnectCmd);
+
+ }
+ }
+ }
+
+ if (TNC->NeedPACTOR)
+ {
+ TNC->NeedPACTOR--;
+
+ if (TNC->NeedPACTOR == 0)
+ {
+ int datalen;
+ UCHAR TXMsg[80] = "D20";
+
+ if (TNC->VeryOldMode)
+ datalen = sprintf(TXMsg, "C20MYCALL %s", TNC->NodeCall);
+ else
+ datalen = sprintf(TXMsg, "C20MYPTCALL %s", TNC->NodeCall);
+ EncodeAndSend(TNC, TXMsg, datalen);
+
+ if (TNC->OldMode)
+ EncodeAndSend(TNC, "C20PACTOR", 9); // Back to Listen
+ else
+ EncodeAndSend(TNC, "C20TOR", 6); // Back to Listen
+
+ TNC->InternalCmd = 'T';
+ TNC->Timeout = 50;
+ TNC->IntCmdDelay--;
+
+ // Restart Scanning
+
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+
+ return;
+ }
+ }
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ // If in HF Packet mode, normal flow control doesn't seem to work
+ // If more that 4 packets sent, send a status poll. and use response to
+ // reset frames outstanding
+
+ if ((Stream == 0) && (TNC->HFPacket) && (TNC->Streams[0].FramesOutstanding > 4))
+ {
+ EncodeAndSend(TNC, "C10S", 4);
+ TNC->InternalCmd = 'S';
+ TNC->Timeout = 50;
+ return;
+
+ }
+
+ if (TNC->TNCOK && STREAM->BPQtoPACTOR_Q)
+ {
+ int datalen;
+ UCHAR TXMsg[1000] = "D20";
+ PMSGWITHLEN buffptr;
+ UCHAR * MsgPtr;
+ char Status[80];
+
+ if (STREAM->Connected)
+ {
+ int Next;
+
+ if (Stream > 0)
+ sprintf(TXMsg, "D1%c", Stream + '@');
+ else if (TNC->HFPacket)
+ memcpy(TXMsg, "D2A", 3);
+ else
+ {
+ // Pactor
+
+ // Limit amount in TX, so we keep some on the TX Q and don't send turnround too early
+
+ if (TNC->Streams[0].bytesTXed - TNC->Streams[0].BytesAcked > 200)
+ continue;
+
+ // Dont send if IRS State
+ // If in IRS state for too long, force turnround
+
+ if (TNC->TXRXState == 'R')
+ {
+ if (TNC->TimeInRX++ > 15)
+ EncodeAndSend(TNC, "T", 1); // Changeover to ISS
+ else
+ goto Poll;
+ }
+ TNC->TimeInRX = 0;
+ }
+
+ buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
+ STREAM->FramesQueued--;
+
+ datalen = buffptr->Len;
+ MsgPtr = buffptr->Data;
+
+ if (TNC->SwallowSignon && Stream == 0)
+ {
+ TNC->SwallowSignon = FALSE;
+ if (strstr(MsgPtr, "Connected")) // Discard *** connected
+ {
+ ReleaseBuffer(buffptr);
+ return;
+ }
+ }
+
+ Next = 0;
+ STREAM->bytesTXed += datalen;
+
+ if (Stream == 0)
+ {
+ while (datalen > 100) // Limit Pactor Sends
+ {
+ memcpy(&TXMsg[3], &MsgPtr[Next], 100);
+ EncodeAndSend(TNC, TXMsg, 103);
+ Next += 100;
+ datalen -= 100;
+
+ WritetoTrace(TNC, &TXMsg[3], 100);
+ }
+ }
+
+ memcpy(&TXMsg[3], &MsgPtr[Next], datalen);
+ EncodeAndSend(TNC, TXMsg, datalen + 3);
+
+ WritetoTrace(TNC, &TXMsg[3], datalen);
+
+ ReleaseBuffer(buffptr);
+
+ if (Stream == 0)
+ {
+ sprintf(Status, "RX %d TX %d ACKED %d ",
+ TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
+ SetWindowText(TNC->xIDC_TRAFFIC, Status);
+
+ if ((TNC->HFPacket == 0) && (TNC->Streams[0].BPQtoPACTOR_Q == 0)) // Nothing following
+ {
+ EncodeAndSend(TNC, "E", 1); // Changeover when all sent
+ }
+ }
+
+ if (STREAM->Disconnecting)
+ {
+ Debugprintf("Send with Disc Pending, Q = %x", STREAM->BPQtoPACTOR_Q);
+ if (STREAM->BPQtoPACTOR_Q == 0) // All Sent
+
+ // KAM doesnt have a tidy close!
+
+ STREAM->DisconnectingTimeout = 100; // Give 5 secs to get to other end
+ }
+ return;
+ }
+ else // Not Connected
+ {
+ buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q);
+ datalen = buffptr->Len;
+ MsgPtr = buffptr->Data;
+
+ // Command. Do some sanity checking and look for things to process locally
+
+ datalen--; // Exclude CR
+ MsgPtr[datalen] = 0; // Null Terminate
+ _strupr(MsgPtr);
+
+ if ((Stream == 0) && memcmp(MsgPtr, "RADIO ", 6) == 0)
+ {
+ sprintf(&MsgPtr[40], "%d %s", TNC->Port, &MsgPtr[6]);
+ if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &MsgPtr[40]))
+ {
+ ReleaseBuffer(buffptr);
+ }
+ else
+ {
+ buffptr->Len = sprintf(buffptr->Data, "%s", &MsgPtr[40]);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ return;
+ }
+
+ if (_memicmp(MsgPtr, "D\r", 2) == 0)
+ {
+ STREAM->ReportDISC = TRUE; // Tell Node
+ return;
+ }
+
+ if ((Stream == 0) && memcmp(MsgPtr, "HFPACKET", 8) == 0)
+ {
+ TNC->HFPacket = TRUE;
+ buffptr->Len = sprintf(buffptr->Data, "KAM} 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);
+ STREAM->Connecting = TRUE;
+
+ // If Stream 0, Convert C CALL to PACTOR CALL
+
+ if (Stream == 0)
+ {
+ if (TNC->HFPacket)
+ datalen = sprintf(TXMsg, "C2AC %s", TNC->Streams[0].RemoteCall);
+ else
+ datalen = sprintf(TXMsg, "C20PACTOR %s", TNC->Streams[0].RemoteCall);
+
+ // If Pactor, check busy detecters on any interlocked ports
+
+ if (TNC->HFPacket == 0 && InterlockedCheckBusy(TNC) && TNC->OverrideBusy == 0)
+ {
+ // Channel Busy. Wait
+
+ TNC->ConnectCmd = _strdup(TXMsg);
+
+ sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ TNC->BusyDelay = TNC->BusyWait * 10;
+
+ return;
+ }
+
+ TNC->OverrideBusy = FALSE;
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s",
+ TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ }
+ else
+ datalen = sprintf(TXMsg, "C1%cC %s", Stream + '@', STREAM->RemoteCall);
+
+ EncodeAndSend(TNC, TXMsg, datalen);
+ TNC->Timeout = 50;
+ TNC->InternalCmd = 'C'; // So we dont send the reply to the user.
+ ReleaseBuffer(buffptr);
+ STREAM->Connecting = TRUE;
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "GTOR ", 5) == 0) // GTOR Connect
+ {
+ memcpy(STREAM->RemoteCall, &MsgPtr[5], 9);
+ STREAM->Connecting = TRUE;
+
+ // If Stream 0, Convert C CALL to PACTOR CALL
+
+ if (Stream == 0)
+ {
+ datalen = sprintf(TXMsg, "C20GTOR %s", TNC->Streams[0].RemoteCall);
+
+ // If Pactor, check busy detecters on any interlocked ports
+
+ if (TNC->HFPacket == 0 && InterlockedCheckBusy(TNC) && TNC->OverrideBusy == 0)
+ {
+ // Channel Busy. Wait
+
+ TNC->ConnectCmd = _strdup(TXMsg);
+
+ sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ TNC->BusyDelay = TNC->BusyWait * 10;
+
+ return;
+ }
+
+ TNC->OverrideBusy = FALSE;
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s",
+ TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ }
+ else
+ datalen = sprintf(TXMsg, "C1%cC %s", Stream + '@', STREAM->RemoteCall);
+
+ EncodeAndSend(TNC, TXMsg, datalen);
+ TNC->Timeout = 50;
+ TNC->InternalCmd = 'C'; // So we dont send the reply to the user.
+ ReleaseBuffer(buffptr);
+ STREAM->Connecting = TRUE;
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "DISCONNECT", datalen) == 0) // Disconnect
+ {
+ if (Stream == 0)
+ {
+ if (TNC->HFPacket)
+ EncodeAndSend(TNC, "C2AD", 4); // ??Return to packet mode??
+ else
+ EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
+
+ TNC->NeedPACTOR = 50;
+ }
+ else
+ {
+ sprintf(TXMsg, "C1%cD", Stream + '@');
+ EncodeAndSend(TNC, TXMsg, 4);
+ TNC->CmdStream = Stream;
+ TNC->Timeout = 50;
+ }
+
+ TNC->Timeout = 0; // Don't expect a response
+ STREAM->Connecting = FALSE;
+ STREAM->ReportDISC = TRUE;
+ ReleaseBuffer(buffptr);
+
+ return;
+ }
+
+ // Other Command ??
+
+ if (Stream > 0)
+ datalen = sprintf(TXMsg, "C1%c%s", Stream + '@', MsgPtr);
+ else
+ datalen = sprintf(TXMsg, "C20%s", MsgPtr);
+ EncodeAndSend(TNC, TXMsg, datalen);
+ ReleaseBuffer(buffptr);
+ TNC->Timeout = 50;
+ TNC->InternalCmd = 0;
+ TNC->CmdStream = Stream;
+
+ }
+ }
+ }
+
+Poll:
+
+ // Need to poll data and control channel (for responses to commands)
+
+ // Also check status if we have data buffered (for flow control)
+
+ if (TNC->TNCOK)
+ {
+ if (TNC->IntCmdDelay == 50)
+ {
+ EncodeAndSend(TNC, "C10S", 4);
+ TNC->InternalCmd = 'S';
+ TNC->Timeout = 50;
+ TNC->IntCmdDelay--;
+ return;
+ }
+
+ if (TNC->IntCmdDelay <=0)
+ {
+ if (TNC->VeryOldMode == FALSE)
+ {
+ EncodeAndSend(TNC, "?", 1);
+ TNC->InternalCmd = '?';
+ TNC->Timeout = 50;
+ }
+ TNC->IntCmdDelay = 100; // Every 30
+ return;
+ }
+ else
+ TNC->IntCmdDelay--;
+ }
+
+ return;
+
+}
+
+static VOID DoTNCReinit(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->ReinitState == 1) // Forcing back to Term
+ TNC->ReinitState = 0; // Got Response, so must be back in term mode
+
+ if (TNC->ReinitState == 0)
+ {
+ // Just Starting - Send a TNC Mode Command to see if in Terminal or Host Mode
+
+ sprintf(TNC->WEB_COMMSSTATE,"%s Initialising TNC", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ Poll[0] = 13;
+ TNC->TXLen = 1;
+
+ WriteCommBlock(TNC);
+ TNC->Timeout = 50;
+
+ return;
+ }
+
+ if (TNC->ReinitState == 2) // In Term State, Sending Initialisation Commands
+ {
+ char * start, * end;
+ int len;
+
+ start = TNC->InitPtr;
+
+ if (*(start) == 0) // End of Script
+ {
+ // Put into Host Mode
+
+ memcpy(Poll, "INTFACE HOST\r", 13);
+
+ TNC->TXLen = 13;
+ WriteCommBlock(TNC);
+ TNC->Timeout = 50;
+
+ TNC->ReinitState = 4; // Need Reset
+
+ return;
+ }
+
+ end = strchr(start, 13);
+ len = (int)(++end - start);
+ TNC->InitPtr = end;
+ memcpy(Poll, start, len);
+
+ TNC->TXLen = len;
+ WriteCommBlock(TNC);
+ TNC->Timeout = 50;
+
+ return;
+
+ }
+}
+
+static VOID DoTermModeTimeout(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->ReinitState == 0)
+ {
+ //Checking if in Terminal Mode - Try to set back to Term Mode
+
+ TNC->ReinitState = 1;
+ Poll[0] = 3;
+ Poll[1] = 0x58; // ?? Back to cmd: mode ??
+ TNC->TXLen = 2;
+
+ Poll[0] = 0xc0;
+ Poll[1] = 'Q'; // ?? Back to cmd: mode ??
+ Poll[2] = 0xc0;
+ TNC->TXLen = 3;
+
+ WriteCommBlock(TNC);
+
+ return;
+ }
+ if (TNC->ReinitState == 1)
+ {
+ // Forcing back to Term Mode
+
+ TNC->ReinitState = 0;
+ DoTNCReinit(TNC); // See if worked
+ return;
+ }
+
+ if (TNC->ReinitState == 3)
+ {
+ // Entering Host Mode
+
+ // Assume ok
+
+ TNC->HostMode = TRUE;
+ return;
+ }
+}
+
+
+
+static VOID ProcessTermModeResponse(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->ReinitState == 0 || TNC->ReinitState == 1)
+ {
+ // Testing if in Term Mode. It is, so can now send Init Commands
+
+ TNC->InitPtr = TNC->InitScript;
+ TNC->ReinitState = 2;
+ DoTNCReinit(TNC); // Send First Command
+ return;
+ }
+ if (TNC->ReinitState == 2)
+ {
+ // Sending Init Commands
+
+ DoTNCReinit(TNC); // Send Next Command
+ return;
+ }
+
+ if (TNC->ReinitState == 4) // Send INTFACE, Need RESET
+ {
+ TNC->ReinitState = 5;
+
+ memcpy(Poll, "RESET\r", 6);
+
+ TNC->TXLen = 6;
+ WriteCommBlock(TNC);
+ TNC->Timeout = 50;
+ TNC->HostMode = TRUE; // Should now be in Host Mode
+ TNC->NeedPACTOR = 50; // Need to Send PACTOR command after 5 secs
+
+ return;
+ }
+
+ if (TNC->ReinitState == 5) // RESET sent
+ {
+ TNC->ReinitState = 5;
+
+ return;
+ }
+
+
+
+}
+
+VOID ProcessKHOSTPacket(struct TNCINFO * TNC, UCHAR * Msg, int Len)
+{
+ PMSGWITHLEN buffptr;
+ char * Buffer = &Msg[3]; // Data portion of frame
+ char * Call;
+ char Status[80];
+ int Stream = 0;
+ struct STREAMINFO * STREAM;
+
+ // Any valid frame is an ACK
+
+ TNC->TNCOK = TRUE;
+
+ Len = KissDecode(Msg, Msg, Len); // Remove KISS transparency
+
+ if (Msg[1] == '0' && Msg[2] == '0')
+ Stream = 0;
+ else
+ if (Msg[1] == '2') Stream = 0; else Stream = Msg[2] - '@';
+
+ STREAM = &TNC->Streams[Stream];
+
+ // See if Poll Reply or Data
+
+ Msg[Len] = 0; // Terminate
+
+ if (Msg[0] == 'M') // Monitor
+ {
+ DoMonitor(TNC, Msg, Len);
+ return;
+ }
+
+
+ if (Msg[0] == 'E') // Data Echo
+ {
+ if (Msg[1] == '2') // HF Port
+ {
+ if (TNC->Streams[0].bytesTXed)
+ TNC->Streams[0].BytesAcked += Len - 3; // We get an ack before the first send
+
+ sprintf(Status, "RX %d TX %d ACKED %d ",
+ TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
+ SetWindowText(TNC->xIDC_TRAFFIC, Status);
+
+ if (TNC->Streams[0].bytesTXed - TNC->Streams[0].BytesAcked < 500)
+ TNC->Streams[0].FramesOutstanding = 0;
+ }
+ return;
+ }
+
+ if (Msg[0] == 'D') // Data
+ {
+ // Pass to Appl
+
+ buffptr = GetBuff();
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ Len-=3; // Remove Header
+
+ buffptr->Len = Len; // Length
+ STREAM->bytesRXed += Len;
+ memcpy(buffptr->Data, Buffer, Len);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ if (Stream == 0)
+ {
+ sprintf(TNC->WEB_TRAFFIC, "RX %d TX %d ACKED %d ",
+ TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
+ SetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC);
+ }
+
+ WritetoTrace(TNC, Buffer, Len);
+
+ return;
+ }
+
+
+ if (Msg[0] == 'C') // Command Reponse
+ {
+ TNC->Timeout = 0;
+
+ // See if we need to process locally (Response to our command, Incoming Call, Disconencted, etc
+
+ // See if a response to internal command
+
+ if (TNC->InternalCmd)
+ {
+ // Process it
+
+ if (TNC->InternalCmd == 'S') // Status
+ {
+ char * Line;
+ char * ptr;
+
+ // Message is line giving free bytes, followed by a line for each active (packet) stream
+
+ // FREE BYTES 1366/5094
+ // A/2 #1145(12) CONNECTED to KE7XO-3
+ // S/2 CONNECTED to NLV
+
+ // each line is teminated by CR, and by the time it gets here it is null terminated
+
+ //FREE BYTES 2628
+ //A/H #80(1) CONNECTED to DK0MNL..
+
+ if (TNC->HFPacket)
+ TNC->Streams[0].FramesOutstanding = 0;
+
+ Line = strchr(&Msg[3], 13);
+ if (Line == 0) return;
+
+ *(Line) = 0;
+
+ ptr = strchr(&Msg[13], '/');
+ TNC->Mem1 = atoi(&Msg[13]);
+ if (ptr)
+ TNC->Mem2 = atoi(++ptr);
+ else
+ TNC->Mem2 = 0;
+
+ SetWindowText(TNC->xIDC_BUFFERS, &Msg[14]);
+ strcpy(TNC->WEB_BUFFERS, &Msg[14]);
+
+ while (Line[1] != 0) // End of stream
+ {
+ Stream = Line[1] - '@';
+ STREAM = &TNC->Streams[Stream];
+
+ if (Line[5] == '#')
+ {
+ STREAM->BytesOutstanding = atoi(&Line[6]);
+ ptr = strchr(&Line[6], '(');
+ if (ptr)
+ STREAM->FramesOutstanding = atoi(++ptr);
+ }
+ else
+ {
+ STREAM->BytesOutstanding = 0;
+ STREAM->FramesOutstanding = 0;
+ }
+
+ Line = strchr(&Line[1], 13);
+ }
+ return;
+ }
+ return;
+ }
+
+
+ WritetoTrace(TNC, Buffer, Len);
+
+
+ // Pass to Appl
+
+ Stream = TNC->CmdStream;
+
+
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data,"KAM} %s", Buffer);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (Msg[0] == 'I') // ISS/IRS State
+ {
+ if (Msg[2] == '1')
+ {
+ strcpy(TNC->WEB_TXRX, "Sender");
+ SetWindowText(TNC->xIDC_TXRX, "Sender");
+ TNC->TXRXState = 'S';
+ }
+ else
+ {
+ strcpy(TNC->WEB_TXRX, "Receiver");
+ SetWindowText(TNC->xIDC_TXRX, "Receiver");
+ TNC->TXRXState = 'R';
+ }
+ return;
+ }
+
+ if (Msg[0] == '?') // Status
+ {
+ TNC->Timeout = 0;
+ return;
+ }
+
+ if (Msg[0] == 'S') // Status
+ {
+ if (Len < 4)
+ {
+ // Reset Response FEND FEND S00 FEND
+
+ TNC->Timeout = 0;
+
+ sprintf(TNC->WEB_COMMSSTATE,"%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ return;
+ }
+
+ // Pass to Appl
+
+ if (strstr(Buffer, "STANDBY>") || strstr(Buffer, "*** DISCONNECTED"))
+ {
+ 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)
+ {
+ // Connect Failed
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "*** Failure with %s\r", STREAM->RemoteCall);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // In case!
+ STREAM->FramesOutstanding = 0;
+
+ return;
+ }
+
+ // Must Have been connected or disconnecting - Release Session
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->FramesOutstanding = 0;
+
+ if (STREAM->Disconnecting == FALSE)
+ STREAM->ReportDISC = TRUE; // Tell Node
+
+ STREAM->Disconnecting = FALSE;
+
+ if (Stream == 0)
+ {
+ // Need to reset Pactor Call in case it was changed
+
+ EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
+ TNC->NeedPACTOR = 20;
+ }
+
+ return;
+ }
+
+ if (Msg[2] == '0')
+ Call = strstr(Buffer, "HFPacket == 0)
+ {
+ Buffer[Len-4] = 0;
+ }
+
+ STREAM->bytesRXed = STREAM->bytesTXed = STREAM->BytesAcked = 0;
+ STREAM->ConnectTime = time(NULL);
+
+ if (Stream == 0)
+ {
+ // Stop Scanner
+
+ char Msg[80];
+
+ sprintf(Msg, "%d SCANSTOP", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Msg);
+
+ sprintf(TNC->WEB_TRAFFIC, "RX %d TX %d ACKED %d ",
+ TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
+
+ SetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC);
+ }
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0)
+ {
+ // Incoming Connect
+
+ TRANSPORTENTRY * SESS;
+
+ if (Msg[1] == '2' && Msg[2] == 'A')
+ TNC->HFPacket = TRUE;
+
+ // Stop other ports in same group
+
+ SuspendOtherPorts(TNC);
+
+ ProcessIncommingConnect(TNC, Call, Stream, TRUE);
+
+ SESS = TNC->PortRecord->ATTACHEDSESSIONS[Stream];
+
+ if (Stream == 0)
+ {
+ struct WL2KInfo * WL2K = TNC->WL2K;
+ char FreqAppl[10] = ""; // Frequecy-specific application
+
+ if (TNC->RIG && TNC->RIG != &TNC->DummyRig)
+ {
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", TNC->Streams[0].RemoteCall, TNC->NodeCall, TNC->RIG->Valchar);
+ SESS->Frequency = (atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq
+
+ // If Scan Entry has a Appl, save it
+
+ if (TNC->RIG->FreqPtr && TNC->RIG->FreqPtr[0]->APPL[0])
+ strcpy(FreqAppl, &TNC->RIG->FreqPtr[0]->APPL[0]);
+ }
+ else
+ {
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", TNC->Streams[0].RemoteCall, TNC->NodeCall);
+
+ if (WL2K)
+ {
+ SESS->Frequency = WL2K->Freq;
+ }
+ }
+
+ SESS->Mode = 11; // P1
+
+ if (WL2K)
+ strcpy(SESS->RMSCall, WL2K->RMSCall);
+
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ EncodeAndSend(TNC, "T", 1); // Changeover to ISS
+
+ // If an autoconnect APPL is defined, send it
+
+ if (FreqAppl[0]) // Frequency spcific APPL overrides TNC APPL
+ {
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "%s\r", FreqAppl);
+ C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr);
+ TNC->SwallowSignon = TRUE;
+ return;
+ }
+
+ if (TNC->ApplCmd)
+ {
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "%s\r", TNC->ApplCmd);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ TNC->SwallowSignon = TRUE;
+ return;
+ }
+ }
+
+ if (FULL_CTEXT && HFCTEXTLEN == 0)
+ {
+ char CTBuff[300] = "D20";
+ int Len = CTEXTLEN, CTPaclen = 50;
+ int Next = 0;
+
+ if (Stream > 0)
+ sprintf(CTBuff, "D1%c", Stream + '@');
+
+ while (Len > CTPaclen) // CTEXT Paclen
+ {
+ memcpy(&CTBuff[3], &CTEXTMSG[Next], CTPaclen);
+ EncodeAndSend(TNC, CTBuff, CTPaclen + 3);
+ Next += CTPaclen;
+ Len -= CTPaclen;
+ }
+
+ memcpy(&CTBuff[3], &CTEXTMSG[Next], Len);
+ EncodeAndSend(TNC, CTBuff, Len + 3);
+ EncodeAndSend(TNC, "E", 1); // Changeover when all sent
+ TNC->Streams[0].bytesTXed += CTEXTLEN;
+ }
+ return;
+
+ }
+ else
+ {
+ // Connect Complete
+
+ buffptr = GetBuff();
+ if (buffptr == 0) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data, "*** Connected to %s\r", Call);;
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = TRUE; // Subsequent data to data channel
+
+
+ if (Stream == 0)
+ {
+ if (TNC->RIG)
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall, TNC->RIG->Valchar);
+ else
+ sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ UpdateMH(TNC, Call, '+', 'O');
+
+ }
+
+ return;
+ }
+ }
+ }
+}
+
+
+static int KissDecode(UCHAR * inbuff, UCHAR * outbuff, int len)
+{
+ int i,txptr=0;
+ UCHAR c;
+
+ for (i=0;iTXLen = KissEncode(txbuffer, TNC->TXBuffer, Len);
+ WriteCommBlock(TNC);
+}
+
+static int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len)
+{
+ int i,txptr=0;
+ UCHAR c;
+
+ outbuff[0]=FEND;
+ txptr=1;
+
+ for (i=0;i');
+
+ if (ptr) *(ptr) = 0;
+
+ UpdateMH(TNC, &Msg[3], ' ', 0);
+
+}
+VOID TidyClose(struct TNCINFO * TNC, int Stream)
+{
+ if (Stream == 0) // Pactor Stream
+ {
+ TNC->TimeInRX = 0;
+ if (TNC->HFPacket)
+ EncodeAndSend(TNC, "C2AD", 4); // Disconnect
+ else
+ EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
+// EncodeAndSend(TNC, "C20TOR", 6); // Disconnect
+
+ TNC->HFPacket = FALSE;
+ }
+ else
+ {
+ UCHAR TXMsg[10];
+
+ sprintf(TXMsg, "C1%cD", Stream + '@');
+ EncodeAndSend(TNC, TXMsg, 4);
+ TNC->Timeout = 50;
+ }
+}
+
+VOID ForcedClose(struct TNCINFO * TNC, int Stream)
+{
+ if (Stream == 0) // Pactor Stream
+ {
+ TNC->TimeInRX = 0;
+
+ if (TNC->HFPacket)
+ EncodeAndSend(TNC, "C2AD", 4); // Disconnect
+ else
+ EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
+
+ TNC->HFPacket = FALSE;
+ }
+ else
+ {
+ UCHAR TXMsg[10];
+
+ sprintf(TXMsg, "C1%cD", Stream + '@');
+ EncodeAndSend(TNC, TXMsg, 4); // Send twice - must force a disconnect
+ TNC->Timeout = 50;
+ }}
+
+VOID CloseComplete(struct TNCINFO * TNC, int Stream)
+{
+ sprintf(TNC->WEB_TNCSTATE, "Free");
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ ReleaseOtherPorts(TNC);
+ TNC->NeedPACTOR = 50;
+}
+
+
+
+/*
+
+
+MARK 1400
+SPACE 1600
+SHIFT MODEM
+INV ON
+MAXUSERS 1/10
+PTERRS 30
+
+ // Others go on end so they can't be overriden
+
+ECHO OFF
+XMITECHO ON
+TXFLOW OFF
+XFLOW OFF
+TRFLOW OFF
+AUTOCR 0
+AUTOLF OFF
+CRADD OFF
+CRSUP OFF
+CRSUP OFF/OFF
+LFADD OFF/OFF
+LFADD OFF
+LFSUP OFF/OFF
+LFSUP OFF
+RING OFF
+ARQBBS OFF
+
+MYCALL
+
+*/
diff --git a/.svn/pristine/1a/1aa9d4e92ce6b8878c3ec022bb10c4789a6bed84.svn-base b/.svn/pristine/1a/1aa9d4e92ce6b8878c3ec022bb10c4789a6bed84.svn-base
index 239598b..6510618 100644
--- a/.svn/pristine/1a/1aa9d4e92ce6b8878c3ec022bb10c4789a6bed84.svn-base
+++ b/.svn/pristine/1a/1aa9d4e92ce6b8878c3ec022bb10c4789a6bed84.svn-base
@@ -1,6472 +1,6472 @@
-/*
-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
-*/
-
-#define _CRT_SECURE_NO_DEPRECATE
-
-#include "cheaders.h"
-#include "bpqmail.h"
-
-#define MAIL
-#include "httpconnectioninfo.h"
-
-#ifdef WIN32
-//#include "C:\Program Files (x86)\GnuWin32\include\iconv.h"
-#else
-#include
-#include
-#endif
-
-static struct HTTPConnectionInfo * FindSession(char * Key);
-int APIENTRY SessionControl(int stream, int command, int param);
-int SetupNodeMenu(char * Buff);
-VOID SetMultiStringValue(char ** values, char * Multi);
-char * GetTemplateFromFile(int Version, char * FN);
-VOID FormatTime(char * Time, time_t cTime);
-struct MsgInfo * GetMsgFromNumber(int msgno);
-BOOL CheckUserMsg(struct MsgInfo * Msg, char * Call, BOOL SYSOP);
-BOOL OkToKillMessage(BOOL SYSOP, char * Call, struct MsgInfo * Msg);
-int DisplayWebForm(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * FileName, char * XML, char * Reply, char * RawMessage, int RawLen);
-struct HTTPConnectionInfo * AllocateWebMailSession();
-VOID SaveNewMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest, int InputLen);
-void ConvertTitletoUTF8(WebMailInfo * WebMail, char * Title, char * UTF8Title, int Len);
-char *stristr (char *ch1, char *ch2);
-char * ReadTemplate(char * FormSet, char * DirName, char * FileName);
-VOID DoStandardTemplateSubsitutions(struct HTTPConnectionInfo * Session, char * txtFile);
-BOOL CheckifPacket(char * Via);
-int GetHTMLFormSet(char * FormSet);
-void ProcessFormInput(struct HTTPConnectionInfo * Session, char * input, char * Reply, int * RLen, int InputLen);
-char * WebFindPart(char ** Msg, char * Boundary, int * PartLen, char * End);
-struct HTTPConnectionInfo * FindWMSession(char * Key);
-int SendWebMailHeaderEx(char * Reply, char * Key, struct HTTPConnectionInfo * Session, char * Alert);
-char * BuildFormMessage(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * Keys[1000], char * Values[1000], int NumKeys);
-char * FindXMLVariable(WebMailInfo * WebMail, char * Var);
-int ReplyToFormsMessage(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * Reply, BOOL Reenter);
-BOOL ParsetxtTemplate(struct HTTPConnectionInfo * Session, struct HtmlFormDir * Dir, char * FN, BOOL isReply);
-VOID UpdateFormAction(char * Template, char * Key);
-BOOL APIENTRY GetAPRSLatLon(double * PLat, double * PLon);
-BOOL APIENTRY GetAPRSLatLonString(char * PLat, char * PLon);
-void FreeWebMailFields(WebMailInfo * WebMail);
-VOID BuildXMLAttachment(struct HTTPConnectionInfo * Session, char * Keys[1000], char * Values[1000], int NumKeys);
-VOID SaveTemplateMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
-VOID DownloadAttachments(struct HTTPConnectionInfo * Session, char * Reply, int * RLen, char * Rest);
-VOID getAttachmentList(struct HTTPConnectionInfo * Session, char * Reply, int * RLen, char * Rest);
-char * BuildB2Header(WebMailInfo * WebMail, struct MsgInfo * Msg, char ** ToCalls, int Calls);
-VOID FormatTime2(char * Time, time_t cTime);
-VOID ProcessSelectResponse(struct HTTPConnectionInfo * Session, char * URLParams);
-VOID ProcessAskResponse(struct HTTPConnectionInfo * Session, char * URLParams);
-char * CheckFile(struct HtmlFormDir * Dir, char * FN);
-VOID GetPage(struct HTTPConnectionInfo * Session, char * NodeURL);
-VOID SendTemplateSelectScreen(struct HTTPConnectionInfo * Session, char *URLParams, int InputLen);
-BOOL isAMPRMsg(char * Addr);
-char * doXMLTransparency(char * string);
-Dll BOOL APIENTRY APISendAPRSMessage(char * Text, char * ToCall);
-void SendMessageReadEvent(char * Call, struct MsgInfo * Msg);
-void SendNewMessageEvent(char * call, struct MsgInfo * Msg);
-void MQTTMessageEvent(void* message);
-
-extern char NodeTail[];
-extern char BBSName[10];
-
-extern char LTFROMString[2048];
-extern char LTTOString[2048];
-extern char LTATString[2048];
-
- UCHAR BPQDirectory[260];
-
-int LineCount = 35; // Lines per page on message list
-
-// Forms
-
-struct HtmlFormDir ** HtmlFormDirs = NULL;
-int FormDirCount = 0;
-
-struct HtmlForm
-{
- char * FileName;
- BOOL HasInitial;
- BOOL HasViewer;
- BOOL HasReply;
- BOOL HasReplyViewer;
-};
-
-struct HtmlFormDir
-{
- char * FormSet;
- char * DirName;
- struct HtmlForm ** Forms;
- int FormCount;
- struct HtmlFormDir ** Dirs; // Nested Directories
- int DirCount;
-};
-
-
-char FormDirList[4][MAX_PATH] = {"Standard_Templates", "Standard Templates", "Local_Templates"};
-
-static char PassError[] = "Sorry, User or Password is invalid - please try again
";
-static char BusyError[] = "Sorry, No sessions available - please try later
";
-
-extern char MailSignon[];
-
-char WebMailSignon[] = "BPQ32 Mail Server Access"
- "BPQ32 Mail Server %s Access
"
- "Please enter Callsign and Password to access WebMail
"
- "";
-
-static char MsgInputPage[] = ""
- ""
- ""
- ""
- ""
- "Webmail Interface - Message Input Form
"
- "";
-
-static char CheckFormMsgPage[] = ""
- ""
- ""
- "Webmail Forms Interface - Check Message
"
- "";
-
-
-extern char * WebMailTemplate;
-extern char * WebMailMsgTemplate;
-extern char * jsTemplate;
-
-static char *dat[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
-char *longday[] = {"Sunday", "Monday", "Tusday", "Wednesday", "Thusday", "Friday", "Saturday"};
-
-static struct HTTPConnectionInfo * WebSessionList = NULL; // active WebMail sessions
-
-#ifdef LINBPQ
-UCHAR * GetBPQDirectory();
-#endif
-
-void UndoTransparency(char * input);
-
-#ifndef LINBPQ
-
-void UndoTransparency(char * input)
-{
- char * ptr1, * ptr2;
- char c;
- int hex;
-
- if (input == NULL)
- return;
-
- ptr1 = ptr2 = input;
-
- // Convert any %xx constructs
-
- while (1)
- {
- c = *(ptr1++);
-
- if (c == 0)
- break;
-
- if (c == '%')
- {
- c = *(ptr1++);
- if(isdigit(c))
- hex = (c - '0') << 4;
- else
- hex = (tolower(c) - 'a' + 10) << 4;
-
- c = *(ptr1++);
- if(isdigit(c))
- hex += (c - '0');
- else
- hex += (tolower(c) - 'a' + 10);
-
- *(ptr2++) = hex;
- }
- else if (c == '+')
- *(ptr2++) = 32;
- else
- *(ptr2++) = c;
- }
- *ptr2 = 0;
-}
-#endif
-
-void ReleaseWebMailStruct(WebMailInfo * WebMail)
-{
- // release any malloc'ed resources
-
- if (WebMail == NULL)
- return;
-
- FreeWebMailFields(WebMail);
- free(WebMail);
- return;
-}
-
-VOID FreeWebMailMallocs()
-{
- // called when closing. Not really needed, but simplifies tracking down real memory leaks
-
- struct HTTPConnectionInfo * Session, * SaveNext;
- int i;
- Session = WebSessionList;
-
- while (Session)
- {
- SaveNext = Session->Next;
-
- // Release amy malloc'ed resouces
-
- ReleaseWebMailStruct(Session->WebMail);
- free(Session);
- Session = SaveNext;
- }
-
- for (i = 0; i < FormDirCount; i++)
- {
- struct HtmlFormDir * Dir = HtmlFormDirs[i];
-
- int j;
-
- for (j = 0; j < Dir->FormCount; j++)
- {
- free(Dir->Forms[j]->FileName);
- free(Dir->Forms[j]);
- }
-
- if (Dir->DirCount)
- {
- struct HtmlFormDir * SubDir;
-
- int k, l;
-
- for (l = 0; l < Dir->DirCount; l++)
- {
- SubDir = Dir->Dirs[l];
-
- for (k = 0; k < Dir->Dirs[l]->FormCount; k++)
- {
- free(SubDir->Forms[k]->FileName);
- free(SubDir->Forms[k]);
- }
- free(SubDir->DirName);
- free(SubDir->Forms);
- free(SubDir->FormSet);
-
- free(Dir->Dirs[l]);
- }
- }
- free(Dir->DirName);
- free(Dir->Forms);
- free(Dir->FormSet);
- free(Dir);
- }
-
- free(HtmlFormDirs);
- return;
-}
-
-char * initMultipartUnpack(char ** Input)
-{
- // Check if Multipart and return Boundary. Update Input to first part
-
- // look through header for Content-Type line, and if multipart
- // find boundary string.
-
- char * ptr, * ptr2;
- char Boundary[128];
- BOOL Multipart = FALSE;
-
- ptr = *Input;
-
- 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
-
- if (_memicmp(ptr, "Content-Type: ", 14) == 0)
- {
- char Line[256] = "";
- char * ptr3;
- size_t len = ptr2-ptr-14;
-
- if (len >255)
- return NULL;
-
- memcpy(Line, &ptr[14], len);
-
- if (_memicmp(Line, "Multipart/", 10) == 0)
- {
- ptr3 = stristr(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;
- break;
- }
- else
- return NULL; // Can't do anything without a boundary ??
- }
- }
- ptr = ptr2;
- ptr++;
- }
-
- // Find First part - there is a boundary before it
-
- ptr = strstr(ptr2, Boundary);
-
- // Next should be crlf then part
-
- ptr = strstr(ptr, "\r\n");
-
- if (ptr)
- ptr += 2; // Over CRLF
-
- *Input = ptr; // Return first part or NULL
- return _strdup(Boundary);
-}
-
-BOOL unpackPart(char * Boundary, char ** Input, char ** Name, char ** Value, int * ValLen, char * End)
-{
- // Format seems to be
-/*
- ------WebKitFormBoundaryABJaEbBWB5SuAHmq
- Content-Disposition: form-data; name="Subj"
-
- subj
- ------WebKitFormBoundaryABJaEbBWB5SuAHmq
- Content-Disposition: form-data; name="myFile[]"; filename="exiftool.txt"
- Content-Type: text/plain
-
- c:\exiftool "-filenameTo = _strdup(Value);
- else if (strcmp(Name, "CC") == 0)
- WebMail->CC = _strdup(Value);
- else if (strcmp(Name, "Subj") == 0)
- WebMail->Subject = _strdup(Value);
- else if (strcmp(Name, "Type") == 0)
- WebMail->Type = Value[0];
- else if (strcmp(Name, "BID") == 0)
- WebMail->BID = _strdup(Value);
- else if (strcmp(Name, "Msg") == 0)
- WebMail->Body = _strdup(Value);
-
- else if (_memicmp(Name, "myFile[]", 8) == 0)
- {
- // Get File Name from param string - myFile[]"; filename="exiftool.txt" \r\nContent-Type: text/plain
-
- char * fn = strstr(Name, "filename=");
- char * endfn;
- if (fn)
- {
- fn += 10;
-
- endfn = strchr(fn, '"');
- if (endfn)
- {
- *endfn = 0;
-
- if (strlen(fn))
- {
- WebMail->FileName[WebMail->Files] = _strdup(fn);
- WebMail->FileBody[WebMail->Files] = malloc(ValLength);
- memcpy(WebMail->FileBody[WebMail->Files], Value, ValLength);
- WebMail->FileLen[WebMail->Files++] = ValLength;
- }
- }
- }
- }
-
- else if (_memicmp(Name, "myFile2[]", 8) == 0)
- {
- // Get File Name from param string - myFile[]"; filename="exiftool.txt" \r\nContent-Type: text/plain
-
- char * fn = strstr(Name, "filename=");
- char * endfn;
- if (fn)
- {
- fn += 10;
-
- endfn = strchr(fn, '"');
- if (endfn)
- {
- *endfn = 0;
-
- if (strlen(fn))
- {
- WebMail->Header = malloc(ValLength + 1);
- memcpy(WebMail->Header, Value, ValLength + 1);
- WebMail->HeaderLen = RemoveLF(WebMail->Header, ValLength);
- }
- }
- }
- }
-
- else if (_memicmp(Name, "myFile3[]", 8) == 0)
- {
- // Get File Name from param string - myFile[]"; filename="exiftool.txt" \r\nContent-Type: text/plain
-
- char * fn = strstr(Name, "filename=");
- char * endfn;
- if (fn)
- {
- fn += 10;
-
- endfn = strchr(fn, '"');
- if (endfn)
- {
- *endfn = 0;
-
- if (strlen(fn))
- {
- WebMail->Footer = malloc(ValLength + 1);
- memcpy(WebMail->Footer, Value, ValLength + 1);
- WebMail->FooterLen = RemoveLF(WebMail->Footer, ValLength);
- }
- }
- }
- }
-
- return TRUE;
-}
-
-
-struct HTTPConnectionInfo * AllocateWebMailSession()
-{
- int KeyVal;
- struct HTTPConnectionInfo * Session, * SaveNext;
- time_t NOW = time(NULL);
-
- // First see if any session records havent been used for a while
-
- Session = WebSessionList;
-
- while (Session)
- {
- if (NOW - Session->WebMailLastUsed > 1200) // 20 Mins
- {
- SaveNext = Session->Next;
-
- // Release amy malloc'ed resouces
-
- ReleaseWebMailStruct(Session->WebMail);
-
- memset(Session, 0, sizeof(struct HTTPConnectionInfo));
-
- Session->Next = SaveNext;
- goto UseThis;
- }
- Session = Session->Next;
- }
-
- Session = zalloc(sizeof(struct HTTPConnectionInfo));
-
- if (Session == NULL)
- return NULL;
-
- if (WebSessionList)
- Session->Next = WebSessionList;
-
- WebSessionList = Session;
-
-UseThis:
-
- Session->WebMail = zalloc(sizeof(WebMailInfo));
-
- KeyVal = ((rand() % 100) + 1);
-
- KeyVal *= (int)time(NULL);
-
- sprintf(Session->Key, "%c%08X", 'W', KeyVal);
-
- return Session;
-}
-
-struct HTTPConnectionInfo * FindWMSession(char * Key)
-{
- struct HTTPConnectionInfo * Session = WebSessionList;
-
- while (Session)
- {
- if (strcmp(Session->Key, Key) == 0)
- {
- Session->WebMailLastUsed = time(NULL);
- return Session;
- }
- Session = Session->Next;
- }
-
- return NULL;
-}
-
-
-// Build list of available forms
-
-VOID ProcessFormDir(char * FormSet, char * DirName, struct HtmlFormDir *** xxx, int * DirCount)
-{
- struct HtmlFormDir * FormDir;
- struct HtmlFormDir ** FormDirs = *xxx;
- struct HtmlForm * Form;
- char Search[MAX_PATH];
- int count = *DirCount;
-
-#ifdef WIN32
- HANDLE hFind = INVALID_HANDLE_VALUE;
- WIN32_FIND_DATA ffd;
-#else
- DIR *dir;
- struct dirent *entry;
- char name[256];
-#endif
-
- FormDir = zalloc(sizeof (struct HtmlFormDir));
-
- FormDir->DirName = _strdup(DirName);
- FormDir->FormSet = _strdup(FormSet);
- FormDirs=realloc(FormDirs, (count + 1) * sizeof(void *));
- FormDirs[count++] = FormDir;
-
- *DirCount = count;
- *xxx = FormDirs;
-
-
- // Scan Directory for .txt files
-
- sprintf(Search, "%s/%s/%s/*", GetBPQDirectory(), FormSet, DirName);
-
- // Find the first file in the directory.
-
-#ifdef WIN32
-
- hFind = FindFirstFile(Search, &ffd);
-
- if (INVALID_HANDLE_VALUE == hFind)
- return;
-
- do
- {
- if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- char Dir[MAX_PATH];
-
- if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0)
- continue;
-
- // Recurse in subdir
-
- sprintf(Dir, "%s/%s", DirName, ffd.cFileName);
-
- ProcessFormDir(FormSet, Dir, &FormDir->Dirs, &FormDir->DirCount);
-
- continue;
-
- }
-
- // Add to list
-
- Form = zalloc(sizeof (struct HtmlForm));
-
- Form->FileName = _strdup(ffd.cFileName);
-
- FormDir->Forms=realloc(FormDir->Forms, (FormDir->FormCount + 1) * sizeof(void *));
- FormDir->Forms[FormDir->FormCount++] = Form;
- }
-
- while (FindNextFile(hFind, &ffd) != 0);
-
- FindClose(hFind);
-
-#else
-
- sprintf(Search, "%s/%s/%s", GetBPQDirectory(), FormSet, DirName);
-
- if (!(dir = opendir(Search)))
- {
- Debugprintf("%s %d %d", "cant open forms dir", errno, dir);
- return ;
- }
- while ((entry = readdir(dir)) != NULL)
- {
- if (entry->d_type == DT_DIR)
- {
- char Dir[MAX_PATH];
-
- if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
- continue;
-
- // Recurse in subdir
-
- sprintf(Dir, "%s/%s", DirName, entry->d_name);
-
- ProcessFormDir(FormSet, Dir, &FormDir->Dirs, &FormDir->DirCount);
- continue;
- }
-
- // Add to list
-
- Form = zalloc(sizeof (struct HtmlForm));
-
- Form->FileName = _strdup(entry->d_name);
-
- FormDir->Forms=realloc(FormDir->Forms, (FormDir->FormCount + 1) * sizeof(void *));
- FormDir->Forms[FormDir->FormCount++] = Form;
- }
- closedir(dir);
-#endif
- return;
-}
-
-int GetHTMLForms()
-{
- int n = 0;
-
- while (FormDirList[n][0])
- GetHTMLFormSet(FormDirList[n++]);
-
- return 0;
-}
-
-int GetHTMLFormSet(char * FormSet)
-{
- int i;
-
-#ifdef WIN32
-
- WIN32_FIND_DATA ffd;
- char szDir[MAX_PATH];
- HANDLE hFind = INVALID_HANDLE_VALUE;
- DWORD dwError=0;
-
- sprintf(szDir, "%s/%s/*", BPQDirectory, FormSet);
-
- // Find the first file in the directory.
-
- hFind = FindFirstFile(szDir, &ffd);
-
- if (INVALID_HANDLE_VALUE == hFind)
- {
- // Accept either
- return 0;
- }
-
- // Scan all directories looking for file
-
- do
- {
- if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0)
- continue;
-
- // Add to Directory List
-
- ProcessFormDir(FormSet, ffd.cFileName, &HtmlFormDirs, &FormDirCount);
- }
- }
-
- while (FindNextFile(hFind, &ffd) != 0);
-
- FindClose(hFind);
-
-#else
-
- DIR *dir;
- struct dirent *entry;
- char name[256];
-
- sprintf(name, "%s/%s", BPQDirectory, FormSet);
-
- if (!(dir = opendir(name)))
- {
- Debugprintf("cant open forms dir %s %d %d", name, errno, dir);
- }
- else
- {
- while ((entry = readdir(dir)) != NULL)
- {
- if (entry->d_type == DT_DIR)
- {
- if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
- continue;
-
- // Add to Directory List
-
- ProcessFormDir(FormSet, entry->d_name, &HtmlFormDirs, &FormDirCount);
- }
- }
- closedir(dir);
- }
-#endif
-
- // List for testing
-
- return 0;
-
- Debugprintf("%d form dirs", FormDirCount);
-
- for (i = 0; i < FormDirCount; i++)
- {
- struct HtmlFormDir * Dir = HtmlFormDirs[i];
-
- int j;
- Debugprintf("%3d %s", Dir->FormCount, Dir->DirName);
-
- for (j = 0; j < Dir->FormCount; j++)
- Debugprintf(" %s", Dir->Forms[j]->FileName);
-
- if (Dir->DirCount)
- {
- int k, l;
-
- for (l = 0; l < Dir->DirCount; l++)
- {
- Debugprintf("Subdir %3d %s", Dir->Dirs[l]->DirCount, Dir->Dirs[l]->DirName);
- for (k = 0; k < Dir->Dirs[l]->FormCount; k++)
- Debugprintf(" %s", Dir->Dirs[l]->Forms[k]->FileName);
- }
- }
- }
-
-
- return 0;
-}
-
-
-static int compare(const void *arg1, const void *arg2)
-{
- // Compare Calls. Fortunately call is at start of stuct
-
- return _stricmp(*(char**)arg1 , *(char**)arg2);
-}
-
-
-int SendWebMailHeader(char * Reply, char * Key, struct HTTPConnectionInfo * Session)
-{
- return SendWebMailHeaderEx(Reply, Key, Session, NULL);
-}
-
-
-int SendWebMailHeaderEx(char * Reply, char * Key, struct HTTPConnectionInfo * Session, char * Alert)
-{
- // Ex includes an alert string to be sent before message
-
- struct UserInfo * User = Session->User;
- char Messages[245000];
- int m;
- struct MsgInfo * Msg;
- char * ptr = Messages;
- int n = NumberofMessages; //LineCount;
- char Via[64];
- int Count = 0;
-
- Messages[0] = 0;
-
- if (Alert && Alert[0])
- ptr += sprintf(Messages, "", Alert, Key);
-
- ptr += sprintf(ptr, "%s", " # Date XX Len To @ From Subject\r\n\r\n");
-
- for (m = LatestMsg; m >= 1; m--)
- {
- if (ptr > &Messages[244000])
- break; // protect buffer
-
- Msg = GetMsgFromNumber(m);
-
- if (Msg == 0 || Msg->type == 0 || Msg->status == 0)
- continue; // Protect against corrupt messages
-
- if (Msg && CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP))
- {
- char UTF8Title[4096];
- char * EncodedTitle;
-
- // List if it is the right type and in the page range we want
-
- if (Session->WebMailTypes[0] && strchr(Session->WebMailTypes, Msg->type) == 0)
- continue;
-
- // All Types or right Type. Check Mine Flag
-
- if (Session->WebMailMine)
- {
- // Only list if to or from me
-
- if (strcmp(User->Call, Msg->to) != 0 && strcmp(User->Call, Msg->from) != 0)
- continue;
- }
-
- if (Session->WebMailMyTX)
- {
- // Only list if to or from me
-
- if (strcmp(User->Call, Msg->from) != 0)
- continue;
- }
-
- if (Session->WebMailMyRX)
- {
- // Only list if to or from me
-
- if (strcmp(User->Call, Msg->to)!= 0)
- continue;
- }
-
- if (Count++ < Session->WebMailSkip)
- continue;
-
- strcpy(Via, Msg->via);
- strlop(Via, '.');
-
- // make sure title is HTML safe (no < > etc) and UTF 8 encoded
-
- EncodedTitle = doXMLTransparency(Msg->title);
-
- memset(UTF8Title, 0, 4096); // In case convert fails part way through
- ConvertTitletoUTF8(Session->WebMail, EncodedTitle, UTF8Title, 4095);
-
- free(EncodedTitle);
-
- ptr += sprintf(ptr, "%6d %s %c%c %5d %-8s%-8s%-8s%s\r\n",
- Key, Msg->number, Msg->number,
- FormatDateAndTime((time_t)Msg->datecreated, TRUE), Msg->type,
- Msg->status, Msg->length, Msg->to, Via,
- Msg->from, UTF8Title);
-
- n--;
-
- if (n == 0)
- break;
- }
- }
-
- if (WebMailTemplate == NULL)
- WebMailTemplate = GetTemplateFromFile(6, "WebMailPage.txt");
-
- return sprintf(Reply, WebMailTemplate, BBSName, User->Call, Key, Key, Key, Key, Key, Key, Key, Key, Key, Key, Messages);
-}
-
-int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Number, BOOL DisplayHTML)
-{
- char * Key = Session->Key;
- struct UserInfo * User = Session->User;
- WebMailInfo * WebMail = Session->WebMail;
- char * DisplayStyle;
-
- char Message[200000] = "";
- struct MsgInfo * Msg;
- char * ptr = Message;
- char * MsgBytes, * Save;
- int msgLen;
-
- char FullTo[100];
- char UTF8Title[4096];
- int Index;
- char * crcrptr;
- char DownLoad[256] = "";
-
- DisplayStyle = "textarea"; // Prevents interpretation of html and xml
-
- Msg = GetMsgFromNumber(Number);
-
- if (Msg == NULL)
- {
- ptr += sprintf(ptr, "Message %d not found\r\n", Number);
- return sprintf(Reply, WebMailTemplate, BBSName, User->Call, Key, Key, Key, Key, Key, Key, Key, Message);
- }
-
- // New Display so free any old values
-
- FreeWebMailFields(WebMail);
-
- WebMail->CurrentMessageIndex = Number;
-
-
- if (!CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP))
- {
- ptr += sprintf(ptr, "Message %d not for you\r", Number);
- return sprintf(Reply, WebMailTemplate, BBSName, User->Call, Key, Key, Key, Key, Key, Key, Key, Message);
- }
-
- if (_stricmp(Msg->to, "RMS") == 0)
- sprintf(FullTo, "RMS:%s", Msg->via);
- else
- if (Msg->to[0] == 0)
- sprintf(FullTo, "smtp:%s", Msg->via);
- else
- strcpy(FullTo, Msg->to);
-
- // make sure title is UTF 8 encoded
-
- memset(UTF8Title, 0, 4096); // In case convert fails part way through
- ConvertTitletoUTF8(Session->WebMail, Msg->title, UTF8Title, 4095);
-
- // if a B2 message diplay B2 Header instead of a locally generated one
-
- if ((Msg->B2Flags & B2Msg) == 0)
- {
- ptr += sprintf(ptr, "From: %s%s\nTo: %s\nType/Status: %c%c\nDate/Time: %s\nBid: %s\nTitle: %s\n\n",
- Msg->from, Msg->emailfrom, FullTo, Msg->type, Msg->status, FormatDateAndTime((time_t)Msg->datecreated, FALSE), Msg->bid, UTF8Title);
- }
-
- MsgBytes = Save = ReadMessageFile(Number);
-
- msgLen = Msg->length;
-
- if (Msg->type == 'P')
- Index = PMSG;
- else if (Msg->type == 'B')
- Index = BMSG;
- else
- Index = TMSG;
-
- if (MsgBytes)
- {
- if (Msg->B2Flags & B2Msg)
- {
- char * ptr1;
-
- // if message has attachments, display them if plain text
-
- if (Msg->B2Flags & Attachments)
- {
- int BodyLen, NewLen;
- int i;
- char *ptr2, *attptr;
-
- sprintf(DownLoad, "Save Attachments | ", Key, Msg->number);
-
- WebMail->Files = 0;
-
- ptr1 = MsgBytes;
-
- // ptr += sprintf(ptr, "Message has Attachments\r\n\r\n");
-
- while(*ptr1 != 13)
- {
- ptr2 = strchr(ptr1, 10); // Find CR
-
- if (memcmp(ptr1, "Body: ", 6) == 0)
- {
- BodyLen = atoi(&ptr1[6]);
- }
-
- if (memcmp(ptr1, "File: ", 6) == 0)
- {
- char * ptr3 = strchr(&ptr1[6], ' '); // Find Space
- *(ptr2 - 1) = 0;
-
- WebMail->FileLen[WebMail->Files] = atoi(&ptr1[6]);
- WebMail->FileName[WebMail->Files++] = _strdup(&ptr3[1]);
- *(ptr2 - 1) = ' '; // put space back
- }
-
- ptr1 = ptr2;
- ptr1++;
- }
-
- ptr1 += 2; // Over Blank Line and Separator
-
- // ptr1 is pointing to body. Save for possible reply
-
- WebMail->Body = malloc(BodyLen + 2);
- memcpy(WebMail->Body, ptr1, BodyLen);
- WebMail->Body[BodyLen] = 0;
-
- *(ptr1 + BodyLen) = 0;
-
- ptr += sprintf(ptr, "%s", MsgBytes); // B2 Header and Body
-
- ptr1 += BodyLen + 2; // to first file
-
- // Save pointers to file
-
- attptr = ptr1;
-
- for (i = 0; i < WebMail->Files; i++)
- {
- WebMail->FileBody[i] = malloc(WebMail->FileLen[i]);
- memcpy(WebMail->FileBody[i], attptr, WebMail->FileLen[i]);
- attptr += (WebMail->FileLen[i] + 2);
- }
-
- // if first (only??) attachment is XML and filename
- // starts "RMS_Express_Form" process as HTML Form
-
- if (DisplayHTML && _memicmp(ptr1, "FileName[0], "RMS_Express_Form_", 16) == 0)
- {
- int Len = DisplayWebForm(Session, Msg, WebMail->FileName[0], ptr1, Reply, MsgBytes, BodyLen + 32); // 32 for added "has attachments"
- free(MsgBytes);
-
- // Flag as read
-
- if ((_stricmp(Msg->to, User->Call) == 0) || ((User->flags & F_SYSOP) && (_stricmp(Msg->to, "SYSOP") == 0)))
- {
- if ((Msg->status != 'K') && (Msg->status != 'H') && (Msg->status != 'F') && (Msg->status != 'D'))
- {
- if (Msg->status != 'Y')
- {
- Msg->status = 'Y';
- Msg->datechanged=time(NULL);
- SaveMessageDatabase();
- SendMessageReadEvent(Session->Callsign, Msg);
- }
- }
- }
-
- return Len;
- }
-
- for (i = 0; i < WebMail->Files; i++)
- {
- int n;
- char * p = ptr1;
- char c;
-
- // Check if message is probably binary
-
- int BinCount = 0;
-
- NewLen = WebMail->FileLen[i];
-
- for (n = 0; n < NewLen; n++)
- {
- c = *p;
-
- if (c==0 || (c & 128))
- BinCount++;
-
- p++;
-
- }
-
- if (BinCount > NewLen/10)
- {
- // File is probably Binary
-
- ptr += sprintf(ptr, "\rAttachment %s is a binary file\r", WebMail->FileName[i]);
- }
- else
- {
- *(ptr1 + NewLen) = 0;
- ptr += sprintf(ptr, "\rAttachment %s\r\r", WebMail->FileName[i]);
- RemoveLF(ptr1, NewLen + 1); // Removes LF after CR but not on its own
-
- ptr += sprintf(ptr, "%s\r\r", ptr1);
-
- User->Total.MsgsSent[Index] ++;
- User->Total.BytesForwardedOut[Index] += NewLen;
- }
-
- ptr1 += WebMail->FileLen[i];
- ptr1 +=2; // Over separator
- }
-
- free(Save);
-
- ptr += sprintf(ptr, "\r\r[End of Message #%d from %s]\r", Number, Msg->from);
-
- RemoveLF(Message, (int)strlen(Message) + 1); // Removes LF after CR but not on its own
-
- if ((_stricmp(Msg->to, User->Call) == 0) || ((User->flags & F_SYSOP) && (_stricmp(Msg->to, "SYSOP") == 0)))
- {
- if ((Msg->status != 'K') && (Msg->status != 'H') && (Msg->status != 'F') && (Msg->status != 'D'))
- {
- if (Msg->status != 'Y')
- {
- Msg->status = 'Y';
- Msg->datechanged=time(NULL);
- SaveMessageDatabase();
- SendMessageReadEvent(Session->Callsign, Msg);
- }
- }
- }
-
- 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);
- }
-
- // Remove B2 Headers (up to the File: Line)
-
- // ptr1 = strstr(MsgBytes, "Body:");
-
- // if (ptr1)
- // MsgBytes = ptr1;
- }
-
- // Body may have cr cr lf which causes double space
-
- crcrptr = strstr(MsgBytes, "\r\r\n");
-
- while (crcrptr)
- {
- *crcrptr = ' ';
- crcrptr = strstr(crcrptr, "\r\r\n");
- }
-
- // Remove lf chars
-
- msgLen = RemoveLF(MsgBytes, msgLen);
-
- User->Total.MsgsSent[Index] ++;
- // User->Total.BytesForwardedOut[Index] += Length;
-
- // if body not UTF-8, convert it
-
- if (WebIsUTF8(MsgBytes, msgLen) == FALSE)
- {
- int code = TrytoGuessCode(MsgBytes, msgLen);
-
- UCHAR * UTF = malloc(msgLen * 3);
-
- if (code == 437)
- msgLen = Convert437toUTF8(MsgBytes, msgLen, UTF);
- else if (code == 1251)
- msgLen = Convert1251toUTF8(MsgBytes, msgLen, UTF);
- else
- msgLen = Convert1252toUTF8(MsgBytes, msgLen, UTF);
-
- free(MsgBytes);
- Save = MsgBytes = UTF;
-
- MsgBytes[msgLen] = 0;
- }
-
- // ptr += sprintf(ptr, "%s", MsgBytes);
-
- memcpy(ptr, MsgBytes, msgLen);
- ptr += msgLen;
- ptr[0] = 0;
-
- free(Save);
-
- ptr += sprintf(ptr, "\r\r[End of Message #%d from %s]\r", Number, Msg->from);
-
- if ((_stricmp(Msg->to, User->Call) == 0) || ((User->flags & F_SYSOP) && (_stricmp(Msg->to, "SYSOP") == 0)))
- {
- if ((Msg->status != 'K') && (Msg->status != 'H') && (Msg->status != 'F') && (Msg->status != 'D'))
- {
- if (Msg->status != 'Y')
- {
- Msg->status = 'Y';
- Msg->datechanged=time(NULL);
- SaveMessageDatabase();
- SendMessageReadEvent(Session->Callsign, Msg);
- }
- }
- }
- }
- else
- {
- ptr += sprintf(ptr, "File for Message %d not found\r", Number);
- }
-
- 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);
-}
-
-int KillWebMailMessage(char * Reply, char * Key, struct UserInfo * User, int Number)
-{
- struct MsgInfo * Msg;
- char Message[100] = "";
-
- Msg = GetMsgFromNumber(Number);
-
- if (Msg == NULL)
- {
- sprintf(Message, "Message %d not found", Number);
- goto returnit;
- }
-
- if (OkToKillMessage(User->flags & F_SYSOP, User->Call, Msg))
- {
- FlagAsKilled(Msg, TRUE);
- sprintf(Message, "Message #%d Killed\r", Number);
- goto returnit;
- }
-
- sprintf(Message, "Not your message\r");
-
-returnit:
- return sprintf(Reply, WebMailMsgTemplate, BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, "", Key, Key, Key, "div", Message, "div");
-}
-
-void freeKeys(KeyValues * Keys)
-{
- while (Keys->Key)
- {
- free(Keys->Key);
- free(Keys->Value);
- Keys++;
- }
-}
-
-void FreeWebMailFields(WebMailInfo * WebMail)
-{
- // release any malloc'ed resources
-
- int i;
- char * SaveReply;
- int * SaveRlen;
-
- if (WebMail == NULL)
- return;
-
- if (WebMail->txtFile)
- free(WebMail->txtFile);
-
- if (WebMail->txtFileName)
- free(WebMail->txtFileName);
-
- if (WebMail->InputHTMLName)
- free(WebMail->InputHTMLName);
-
- if (WebMail->DisplayHTMLName)
- free(WebMail->DisplayHTMLName);
-
- if (WebMail->ReplyHTMLName)
- free(WebMail->ReplyHTMLName);
-
- if (WebMail->To)
- free(WebMail->To);
- if (WebMail->CC)
- free(WebMail->CC);
- if (WebMail->Subject)
- free(WebMail->Subject);
- if (WebMail->BID)
- free(WebMail->BID);
- if (WebMail->Body)
- free(WebMail->Body);
- if (WebMail->XML)
- free(WebMail->XML);
- if (WebMail->XMLName)
- free(WebMail->XMLName);
-
- if (WebMail->OrigTo)
- free(WebMail->OrigTo);
- if (WebMail->OrigSubject)
- free(WebMail->OrigSubject);
- if (WebMail->OrigBID)
- free(WebMail->OrigBID);
- if (WebMail->OrigBody)
- free(WebMail->OrigBody);
-
- freeKeys(WebMail->txtKeys);
- freeKeys(WebMail->XMLKeys);
-
- for (i = 0; i < WebMail->Files; i++)
- {
- free(WebMail->FileBody[i]);
- free(WebMail->FileName[i]);
- }
-
- if (WebMail->Header)
- free(WebMail->Header);
- if (WebMail->Footer)
- free(WebMail->Footer);
-
- SaveReply = WebMail->Reply;
- SaveRlen = WebMail->RLen;
-
-#ifndef WIN32
- if (WebMail->iconv_toUTF8)
- iconv_close(WebMail->iconv_toUTF8);
-#endif
-
- memset(WebMail, 0, sizeof(WebMailInfo));
-
- WebMail->Reply = SaveReply;
- WebMail->RLen = SaveRlen;
-
- return;
-}
-
-
-void ProcessWebMailMessage(struct HTTPConnectionInfo * Session, char * Key, BOOL LOCAL, char * Method, char * NodeURL, char * input, char * Reply, int * RLen, int InputLen)
-{
- char * URLParams = strlop(Key, '&');
- int ReplyLen;
- char Appl = 'M';
-
- // Webmail doesn't use the normal Mail Key.
-
- // webscript.js doesn't need a key
-
- if (_stricmp(NodeURL, "/WebMail/webscript.js") == 0)
- {
- if (jsTemplate)
- free(jsTemplate);
-
- jsTemplate = GetTemplateFromFile(2, "webscript.js");
-
- ReplyLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
- "Cache-Control: max-age=60\r\nContent-Type: text/javascript\r\n\r\n%s", (int)strlen(jsTemplate), jsTemplate);
- *RLen = ReplyLen;
- return;
- }
-
- // Neither do js or file downloads
-
- // This could be a request for a Template file
- // WebMail/Local_Templates/My Forms/inc/logo_ad63.png
- // WebMail/Standard Templates/
-
-
- if (_memicmp(NodeURL, "/WebMail/Local", 14) == 0 || (_memicmp(NodeURL, "/WebMail/Standard", 17) == 0))
- {
- int FileSize;
- char * MsgBytes;
- char MsgFile[512];
- FILE * hFile;
- size_t ReadLen;
- char TimeString[64];
- char FileTimeString[64];
- struct stat STAT;
- char * FN = &NodeURL[9];
- char * fileBit = FN;
- char * ext;
- char Type[64] = "Content-Type: text/html\r\n";
-
- UndoTransparency(FN);
- ext = strchr(FN, '.');
-
- sprintf(MsgFile, "%s/%s", BPQDirectory, FN);
-
- while (strchr(fileBit, '/'))
- fileBit = strlop(fileBit, '/');
-
- if (stat(MsgFile, &STAT) == -1)
- {
- *RLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n");
- return;
- }
-
- hFile = fopen(MsgFile, "rb");
-
- if (hFile == 0)
- {
- *RLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n");
- return;
- }
-
- FileSize = STAT.st_size;
- MsgBytes = malloc(FileSize + 1);
- ReadLen = fread(MsgBytes, 1, FileSize, hFile);
-
- fclose(hFile);
-
- FormatTime2(FileTimeString, STAT.st_ctime);
- FormatTime2(TimeString, time(NULL));
-
- ext++;
-
- if (_stricmp(ext, "js") == 0)
- strcpy(Type, "Content-Type: text/javascript\r\n");
-
- if (_stricmp(ext, "css") == 0)
- strcpy(Type, "Content-Type: text/css\r\n");
-
- if (_stricmp(ext, "pdf") == 0)
- strcpy(Type, "Content-Type: application/pdf\r\n");
-
- if (_stricmp(ext, "jpg") == 0 || _stricmp(ext, "jpeg") == 0 || _stricmp(ext, "png") == 0 ||
- _stricmp(ext, "gif") == 0 || _stricmp(ext, "bmp") == 0 || _stricmp(ext, "ico") == 0)
- strcpy(Type, "Content-Type: image\r\n");
-
- // File may be binary so output header then copy in message
-
- *RLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
- "%s"
- "Date: %s\r\n"
- "Last-Modified: %s\r\n"
- "\r\n", FileSize, Type,TimeString, FileTimeString);
-
- memcpy(&Reply[*RLen], MsgBytes, FileSize);
- *RLen += FileSize;
- free (MsgBytes);
- return;
- }
-
- //
-
- if (_memicmp(NodeURL, "/WebMail/WMFile/", 16) == 0)
- {
- int FileSize;
- char * MsgBytes;
- char MsgFile[512];
- FILE * hFile;
- size_t ReadLen;
- char TimeString[64];
- char FileTimeString[64];
- struct stat STAT;
- char * FN = &NodeURL[16];
- char * fileBit = FN;
- char * ext;
- char Type[64] = "Content-Type: text/html\r\n";
-
-
- UndoTransparency(FN);
- ext = strchr(FN, '.');
-
- sprintf(MsgFile, "%s/%s", BPQDirectory, FN);
-
- while (strchr(fileBit, '/'))
- fileBit = strlop(fileBit, '/');
-
- if (stat(MsgFile, &STAT) == -1)
- {
- *RLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n");
- return;
- }
-
- hFile = fopen(MsgFile, "rb");
-
- if (hFile == 0)
- {
- *RLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n");
- return;
- }
-
- FileSize = STAT.st_size;
- MsgBytes = malloc(FileSize + 1);
- ReadLen = fread(MsgBytes, 1, FileSize, hFile);
-
- fclose(hFile);
-
- FormatTime2(FileTimeString, STAT.st_ctime);
- FormatTime2(TimeString, time(NULL));
-
- ext++;
-
- if (_stricmp(ext, "js") == 0)
- strcpy(Type, "Content-Type: text/javascript\r\n");
-
- if (_stricmp(ext, "css") == 0)
- strcpy(Type, "Content-Type: text/css\r\n");
-
- if (_stricmp(ext, "pdf") == 0)
- strcpy(Type, "Content-Type: application/pdf\r\n");
-
- if (_stricmp(ext, "jpg") == 0 || _stricmp(ext, "jpeg") == 0 || _stricmp(ext, "png") == 0 ||
- _stricmp(ext, "gif") == 0 || _stricmp(ext, "bmp") == 0 || _stricmp(ext, "ico") == 0)
- strcpy(Type, "Content-Type: image\r\n");
-
- // File may be binary so output header then copy in message
-
- *RLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
- "%s"
- "Date: %s\r\n"
- "Last-Modified: %s\r\n"
- "\r\n", FileSize, Type,TimeString, FileTimeString);
-
- memcpy(&Reply[*RLen], MsgBytes, FileSize);
- *RLen += FileSize;
- free (MsgBytes);
- return;
- }
-
- Session = NULL;
-
- if (Key && Key[0])
- Session = FindWMSession(Key);
-
- if (Session == NULL)
- {
- // Lost Session
-
- if (LOCAL)
- {
- Session = AllocateWebMailSession();
-
- Key = Session->Key;
-
- if (SYSOPCall[0])
- Session->User = LookupCall(SYSOPCall);
- else
- Session->User = LookupCall(BBSName);
-
- if (Session->User)
- {
- strcpy(NodeURL, "/WebMail/WebMail");
- Session->WebMailSkip = 0;
- Session->WebMailLastUsed = time(NULL);
- }
- }
- else
- {
- // Send Login Page unless Signon request
-
- if (_stricmp(NodeURL, "/WebMail/Signon") != 0 || strcmp(Method, "POST") != 0)
- {
- ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
- *RLen = ReplyLen;
- return;
- }
- }
- }
-
- if (strcmp(Method, "POST") == 0)
- {
- if (_stricmp(NodeURL, "/WebMail/Signon") == 0)
- {
- char * msg = strstr(input, "\r\n\r\n"); // End of headers
- char * user, * password, * Key;
- char Msg[128];
- int n;
-
- if (msg)
- {
- struct UserInfo * User;
-
- if (strstr(msg, "Cancel=Cancel"))
- {
- *RLen = sprintf(Reply, "");
- return;
- }
- // Webmail Gets Here with a dummy Session
-
- Session = AllocateWebMailSession();
- Session->WebMail->Reply = Reply;
- Session->WebMail->RLen = RLen;
-
-
- Key = Session->Key;
-
- user = strtok_s(&msg[9], "&", &Key);
- password = strtok_s(NULL, "=", &Key);
- password = Key;
-
- Session->User = User = LookupCall(user);
-
- if (User)
- {
- // Check Password
-
- if (password[0] && strcmp(User->pass, password) == 0)
- {
- // send Message Index
-
- Session->WebMailLastUsed = time(NULL);
- Session->WebMailSkip = 0;
- Session->WebMailMyTX = FALSE;
- Session->WebMailMyRX = FALSE;
- Session->WebMailMine = FALSE;
-
- if (WebMailTemplate)
- {
- free(WebMailTemplate);
- WebMailTemplate = NULL;
- }
-
- if (User->flags & F_Excluded)
- {
- n = sprintf_s(Msg, sizeof(Msg), "Webmail Connect from %s Rejected by Exclude Flag", _strupr(user));
- WriteLogLine(NULL, '|',Msg, n, LOG_BBS);
- ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
- *RLen = ReplyLen;
- return;
- }
-
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- n=sprintf_s(Msg, sizeof(Msg), "Webmail Connect from %s", _strupr(user));
- WriteLogLine(NULL, '|',Msg, n, LOG_BBS);
-
- return;
- }
-
- }
-
- // Bad User or Pass
-
- ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
- *RLen = ReplyLen;
- return;
- }
- }
-
- Session->WebMail->Reply = Reply;
- Session->WebMail->RLen = RLen;
-
- if (_stricmp(NodeURL, "/WebMail/EMSave") == 0)
- {
- // Save New Message
-
- SaveNewMessage(Session, input, Reply, RLen, Key, InputLen);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/Submit") == 0)
- {
- // Get the POST data from the page and place in message
-
- char * param = strstr(input, "\r\n\r\n"); // End of headers
- WebMailInfo * WebMail = Session->WebMail;
-
- if (WebMail == NULL)
- return; // Can't proceed if we have no info on form
-
- ProcessFormInput(Session, input, Reply, RLen, InputLen);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/FormMsgSave") == 0)
- {
- // Save New Message
-
- SaveTemplateMessage(Session, input, Reply, RLen, Key);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/GetTemplates") == 0)
- {
- SendTemplateSelectScreen(Session, input, InputLen);
- return;
- }
-
- // End of POST section
- }
-
- if (_stricmp(NodeURL, "/WebMail/WMLogout") == 0)
- {
- Session->Key[0] = 0;
- Session->WebMailLastUsed = 0;
- ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
- *RLen = ReplyLen;
- return;
- }
-
- if ((_stricmp(NodeURL, "/WebMail/MailEntry") == 0) ||
- (_stricmp(NodeURL, "/WebMail") == 0) ||
- (_stricmp(NodeURL, "/WebMail/") == 0))
- {
- // Entry from Menu if signed in, continue. If not and Localhost
- // signin as sysop.
-
- if (Session->User == NULL)
- {
- // Not yet signed in
-
- if (LOCAL)
- {
- // Webmail Gets Here with a dummy Session
-
- Session = AllocateWebMailSession();
- Session->WebMail->Reply = Reply;
- Session->WebMail->RLen = RLen;
-
- Key = Session->Key;
-
- if (SYSOPCall[0])
- Session->User = LookupCall(SYSOPCall);
- else
- Session->User = LookupCall(BBSName);
-
- if (Session->User)
- {
- strcpy(NodeURL, "/WebMail/WebMail");
- Session->WebMailSkip = 0;
- Session->WebMailLastUsed = time(NULL);
- }
- }
- else
- {
- // Send Login Page
-
- ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
- *RLen = ReplyLen;
- return;
- }
- }
- }
-
- Session->WebMail->Reply = Reply;
- Session->WebMail->RLen = RLen;
-
- if (_stricmp(NodeURL, "/WebMail/WebMail") == 0)
- {
- if (WebMailTemplate)
- {
- free(WebMailTemplate);
- WebMailTemplate = NULL;
- }
-
- Session->WebMailSkip = 0;
- Session->WebMailMine = FALSE;
- Session->WebMailMyTX = FALSE;
- Session->WebMailMyRX = FALSE;
-
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/WMAll") == 0)
- {
- Session->WebMailSkip = 0;
- Session->WebMailTypes[0] = 0;
- Session->WebMailMine = FALSE;
- Session->WebMailMyTX = FALSE;
- Session->WebMailMyRX = FALSE;
-
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/WMB") == 0)
- {
- Session->WebMailSkip = 0;
- strcpy(Session->WebMailTypes, "B");
- Session->WebMailMine = FALSE;
- Session->WebMailMyTX = FALSE;
- Session->WebMailMyRX = FALSE;
-
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/WMP") == 0)
- {
- Session->WebMailSkip = 0;
- strcpy(Session->WebMailTypes, "P");
- Session->WebMailMine = FALSE;
- Session->WebMailMyTX = FALSE;
- Session->WebMailMyRX = FALSE;
-
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/WMT") == 0)
- {
- Session->WebMailSkip = 0;
- strcpy(Session->WebMailTypes, "T");
- Session->WebMailMine = FALSE;
- Session->WebMailMyTX = FALSE;
- Session->WebMailMyRX = FALSE;
-
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/WMMine") == 0)
- {
- Session->WebMailSkip = 0;
- Session->WebMailTypes[0] = 0;
- Session->WebMailMine = TRUE;
- Session->WebMailMyTX = FALSE;
- Session->WebMailMyRX = FALSE;
-
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/WMtoMe") == 0)
- {
- Session->WebMailSkip = 0;
- Session->WebMailTypes[0] = 0;
- Session->WebMailMine = FALSE;
- Session->WebMailMyTX = FALSE;
- Session->WebMailMyRX = TRUE;
-
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/WMfromMe") == 0)
- {
- Session->WebMailSkip = 0;
- Session->WebMailTypes[0] = 0;
- Session->WebMailMine = TRUE;
- Session->WebMailMyTX = TRUE;
- Session->WebMailMyRX = FALSE;
-
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- return;
- }
-
-
- if (_stricmp(NodeURL, "/WebMail/WMSame") == 0)
- {
- *RLen = SendWebMailHeader(Reply, Session->Key, Session);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/WMAuto") == 0)
- {
- // Auto Refresh Version of index page. Uses Web Sockets
-
- char Page[4096];
-
- char WebSockPage[] =
- "\r\n"
- " \r\n"
- " \r\n"
- " \r\n"
- " \r\n"
- "\r\n"
- "\r\n"
-
- "\r\n"
- "WebMail \r\n"
- "\r\n"
-
- "\r\n"
- " %s Webmail Interface - User %s - Message List
\r\n"
- "\r\n"
- "
\r\n"
-
- "Waiting for data...
\r\n"
- "\r\n";
-
- sprintf(Page, WebSockPage, Key, Key ,BBSName, Session->User->Call, Key, Key, Key, Key, Key, Key, Key, Key, Key, Key);
-
- *RLen = sprintf(Reply, "%s", Page);
- return;
- }
-
-
- if (memcmp(NodeURL, "/WebMail/QuoteOriginal/", 15) == 0)
- {
- // Reply to Message
-
- int n, len;
- struct MsgInfo * Msg;
- char Message[100] = "";
- char Title[100];
- char * MsgBytes, * Save, * NewBytes;
- char * ptr;
- char * ptr1, * ptr2;
- char * EncodedTitle;
-
- n = Session->WebMail->CurrentMessageIndex;
-
- Msg = GetMsgFromNumber(n);
-
- if (Msg == NULL)
- {
- sprintf(Message, "Message %d not found", n);
- *RLen = sprintf(Reply, "%s", Message);
- return;
- }
-
- Session->WebMail->Msg = Msg;
-
- if (stristr(Msg->title, "Re:") == 0)
- sprintf(Title, "Re:%s", Msg->title);
- else
- sprintf(Title, "%s", Msg->title);
-
- MsgBytes = Save = ReadMessageFile(n);
-
-
- ptr = NewBytes = malloc((Msg->length * 2) + 256);
-
- // Copy a line at a time with "> " in front of each
-
- ptr += sprintf(ptr, "%s", "\r\n\r\n\r\n\r\n\r\nOriginal Message\r\n\r\n> ");
-
- ptr1 = ptr2 = MsgBytes;
- len = (int)strlen(MsgBytes);
-
- while (len-- > 0)
- {
- *ptr++ = *ptr1;
-
- if (*(ptr1) == '\n')
- {
- *ptr++ = '>';
- *ptr++ = ' ';
- }
-
- ptr1++;
- }
-
- *ptr++ = 0;
-
- EncodedTitle = doXMLTransparency(Msg->title);
-
- *RLen = sprintf(Reply, MsgInputPage, Key, Msg->from, "", EncodedTitle , NewBytes);
-
- free(EncodedTitle);
-
- free(MsgBytes);
- free(NewBytes);
-
- return;
- }
-
-
-
- if (memcmp(NodeURL, "/WebMail/Reply/", 15) == 0)
- {
- // Reply to Message
-
- int n = atoi(&NodeURL[15]);
- struct MsgInfo * Msg;
- char Message[100] = "";
- char Title[100];
- char * EncodedTitle;
-
- // Quote Original
-
- char Button[] =
- " "
- "";
-
- char Temp[1024];
- char ReplyAddr[128];
-
- Msg = GetMsgFromNumber(n);
-
- if (Msg == NULL)
- {
- sprintf(Message, "Message %d not found", n);
- *RLen = sprintf(Reply, "%s", Message);
- return;
- }
-
- Session->WebMail->Msg = Msg;
-
- // See if the message was displayed in an HTML form with a reply template
-
- *RLen = ReplyToFormsMessage(Session, Msg, Reply, FALSE);
-
- // If couldn't build reply form use normal text reply
-
- if (*RLen)
- return;
-
-
- sprintf(Temp, Button, Key);
-
- if (stristr(Msg->title, "Re:") == 0)
- sprintf(Title, "Re:%s", Msg->title);
- else
- sprintf(Title, "%s", Msg->title);
-
- strcpy(ReplyAddr, Msg->from);
- strcat(ReplyAddr, Msg->emailfrom);
-
- EncodedTitle = doXMLTransparency(Msg->title);
-
- *RLen = sprintf(Reply, MsgInputPage, Key, Msg->from, Temp, EncodedTitle , "");
-
- free(EncodedTitle);
- return;
- }
-
- if (strcmp(NodeURL, "/WebMail/WM") == 0)
- {
- // Read Message
-
- int n = 0;
-
- if (URLParams)
- n = atoi(URLParams);
-
- if (WebMailMsgTemplate)
- free(WebMailMsgTemplate);
-
- WebMailMsgTemplate = GetTemplateFromFile(5, "WebMailMsg.txt");
-
- *RLen = ViewWebMailMessage(Session, Reply, n, TRUE);
-
- return;
- }
-
- if (strcmp(NodeURL, "/WebMail/WMPrev") == 0)
- {
- // Read Previous Message
-
- int m;
- struct MsgInfo * Msg;
- struct UserInfo * User = Session->User;
-
-
- for (m = Session->WebMail->CurrentMessageIndex - 1; m >= 1; m--)
- {
-
- Msg = GetMsgFromNumber(m);
-
- if (Msg == 0 || Msg->type == 0 || Msg->status == 0)
- continue; // Protect against corrupt messages
-
- if (Msg && CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP))
- {
- // Display if it is the right type and in the page range we want
-
- if (Session->WebMailTypes[0] && strchr(Session->WebMailTypes, Msg->type) == 0)
- continue;
-
- // All Types or right Type. Check Mine Flag
-
- if (Session->WebMailMine)
- {
- // Only list if to or from me
-
- if (strcmp(User->Call, Msg->to) != 0 && strcmp(User->Call, Msg->from) != 0)
- continue;
- }
-
- if (Session->WebMailMyTX)
- {
- // Only list if to or from me
-
- if (strcmp(User->Call, Msg->from) != 0)
- continue;
- }
-
- if (Session->WebMailMyRX)
- {
- // Only list if to or from me
-
- if (strcmp(User->Call, Msg->to) != 0)
- continue;
- }
- *RLen = ViewWebMailMessage(Session, Reply, m, TRUE);
-
- return;
- }
- }
-
- // No More
-
- *RLen = sprintf(Reply, "", Session->Key);
- return;
-
- }
-
- if (strcmp(NodeURL, "/WebMail/WMNext") == 0)
- {
- // Read Previous Message
-
- int m;
- struct MsgInfo * Msg;
- struct UserInfo * User = Session->User;
-
- for (m = Session->WebMail->CurrentMessageIndex + 1; m <= LatestMsg; m++)
- {
- Msg = GetMsgFromNumber(m);
-
- if (Msg == 0 || Msg->type == 0 || Msg->status == 0)
- continue; // Protect against corrupt messages
-
- if (Msg && CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP))
- {
- // Display if it is the right type and in the page range we want
-
- if (Session->WebMailTypes[0] && strchr(Session->WebMailTypes, Msg->type) == 0)
- continue;
-
- // All Types or right Type. Check Mine Flag
-
- if (Session->WebMailMine)
- {
- // Only list if to or from me
-
- if (strcmp(User->Call, Msg->to) != 0 && strcmp(User->Call, Msg->from) != 0)
- continue;
- }
-
- if (Session->WebMailMyTX)
- {
- // Only list if to or from me
-
- if (strcmp(User->Call, Msg->from) != 0)
- continue;
- }
-
- if (Session->WebMailMyRX)
- {
- // Only list if to or from me
-
- if (strcmp(User->Call, Msg->to) != 0)
- continue;
- }
- *RLen = ViewWebMailMessage(Session, Reply, m, TRUE);
-
- return;
- }
- }
-
- // No More
-
- *RLen = sprintf(Reply, "", Session->Key);
- return;
-
- }
-
-
- if (strcmp(NodeURL, "/WebMail/DisplayText") == 0)
- {
- // Read Message
-
- int n = 0;
-
- if (URLParams)
- n = atoi(URLParams);
-
- if (WebMailMsgTemplate)
- free(WebMailMsgTemplate);
-
- WebMailMsgTemplate = GetTemplateFromFile(5, "WebMailMsg.txt");
-
- *RLen = ViewWebMailMessage(Session, Reply, n, FALSE);
-
- return;
- }
- if (memcmp(NodeURL, "/WebMail/WMDel/", 15) == 0)
- {
- // Kill Message
-
- int n = atoi(&NodeURL[15]);
-
- *RLen = KillWebMailMessage(Reply, Session->Key, Session->User, n);
-
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/NewMsg") == 0)
- {
- // Add HTML Template Button if we have any HTML Form
-
- char Button[] =
- " "
- "";
-
- char Temp[1024];
-
- FreeWebMailFields(Session->WebMail); // Tidy up for new message
-
- sprintf(Temp, Button, Key);
-
- if (FormDirCount == 0)
- *RLen = sprintf(Reply, MsgInputPage, Key, "", "", "", "");
- else
- *RLen = sprintf(Reply, MsgInputPage, Key, "", Temp, "", "");
-
- return;
- }
-
- if (_memicmp(NodeURL, "/WebMail/GetPage/", 17) == 0)
- {
- // Read and Parse Template File
-
- GetPage(Session, NodeURL);
- return;
- }
-
- if (_memicmp(NodeURL, "/WebMail/GetList/", 17) == 0)
- {
- // Send Select Template Popup
-
- char * SubDir;
- int DirNo = 0;
- int SubDirNo = 0;
- char popup[10000];
-
- char popuphddr[] =
-
- ""
- ""
- ""
- "Select Required Template from %s
"
- "
");
-
- *RLen = sprintf(Reply, "%s", popup);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/DL") == 0)
- {
- getAttachmentList(Session, Reply, RLen, URLParams);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/GetDownLoad") == 0)
- {
- DownloadAttachments(Session, Reply, RLen, URLParams);
- return;
- }
-
- if (_stricmp(NodeURL, "/WebMail/DoSelect") == 0)
- {
- // User has selected item from Template
");
-
- *WebMail->RLen = sprintf(WebMail->Reply, "%s", popup);
-
- free(Boundary);
- return;
-}
-
-static char WinlinkAddr[] = "WINLINK.ORG";
-
-VOID SaveNewMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest, int InputLen)
-{
- int i, ReplyLen = 0;
- struct MsgInfo * Msg;
- FILE * hFile;
- int Template=0;
- char * via = NULL;
- BIDRec * BIDRec;
- char MsgFile[MAX_PATH];
- size_t WriteLen=0;
- char * HDest;
- char * HDestCopy;
- char * HDestRest;
- char * Vptr = NULL;
- char * FileList = NULL;
- char Prompt[256] = "Message Saved";
- char OrigTo[256];
- WebMailInfo * WebMail = Session->WebMail;
- struct UserInfo * user;
- CIRCUIT conn;
-
- // So we can have attachments input is now Content-Type: multipart/form-data;
-
- char * Input;
- size_t MsgLen = 0;
- char * Boundary;
-
- strcpy(conn.Callsign, Session->User->Call);
-
- Input = MsgPtr;
-
- Boundary = initMultipartUnpack(&Input);
-
- if (Boundary == NULL)
- return; // Can't work without one
-
- // Input points to start of part. Normally preceeded by \r\n which is Boundary Terminator. If preceeded by -- we have used last part
-
- while(Input && Input[-1] != '-')
- {
- char * Name, * Value;
- int ValLen;
-
- if (unpackPart(Boundary, &Input, &Name, &Value, &ValLen, MsgPtr + InputLen) == FALSE)
- {
- // ReportCorrupt(WebMail);
- free(Boundary);
- return;
- }
- if (SaveInputValue(WebMail, Name, Value, ValLen) == FALSE)
- {
- *RLen = sprintf(Reply, "", Session->Key);
- return;
- }
- }
-
-
- if (WebMail->txtFileName)
- {
- // Processing Form Input
-
- SaveTemplateMessage(Session, MsgPtr, Reply, RLen, Rest);
-
- // Prevent re-entry
-
- free(WebMail->txtFileName);
- WebMail->txtFileName = NULL;
-
- return;
- }
-
- // If we aren't using a template then all the information is in the WebMail fields, as we haven't been here before.
-
- strlop(WebMail->BID, ' ');
- if (strlen(WebMail->BID) > 12)
- WebMail->BID[12] = 0;
-
- UndoTransparency(WebMail->BID);
- UndoTransparency(WebMail->To);
- UndoTransparency(WebMail->Subject);
- UndoTransparency(WebMail->Body);
-
- MsgLen = strlen(WebMail->Body);
-
- // We will need to mess about with To field. Create a copy so the original can go in B2 header if we use one
-
- if (WebMail->To[0] == 0)
- {
- *RLen = sprintf(Reply, "%s", "");
- FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
- return;
- }
-
- if (strlen(WebMail->To) > 255)
- {
- *RLen = sprintf(Reply, "%s", "");
- FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
- return;
- }
-
- HDest = _strdup(WebMail->To);
-
- if (strlen(WebMail->BID))
- {
- if (LookupBID(WebMail->BID))
- {
- // Duplicate bid
- *RLen = sprintf(Reply, "%s", "");
- FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
- return;
- }
- }
-
- if (WebMail->Type == 'B')
- {
- if (RefuseBulls)
- {
- *RLen = sprintf(Reply, "%s", "");
- FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
- return;
- }
- }
-
- // ?? Can we just loop though the rest of the code to allow multiple dests ??
-
- HDestCopy = HDest;
-
- while (HDest && HDest[0])
- {
- HDestRest = strlop(HDest, ';');
-
- Msg = AllocateMsgRecord();
-
- // Set number here so they remain in sequence
-
- Msg->number = ++LatestMsg;
- MsgnotoMsg[Msg->number] = Msg;
-
- strcpy(Msg->from, Session->User->Call);
-
- if (_memicmp(HDest, "rms:", 4) == 0 || _memicmp(HDest, "rms/", 4) == 0)
- {
- Vptr=&HDest[4];
- strcpy(Msg->to, "RMS");
- }
- else if (_memicmp(HDest, "smtp:", 5) == 0)
- {
- if (ISP_Gateway_Enabled)
- {
- Vptr=&HDest[5];
- Msg->to[0] = 0;
- }
- }
- else if (strchr(HDest, '@'))
- {
- strcpy(OrigTo, HDest);
-
- Vptr = strlop(HDest, '@');
-
- if (Vptr)
- {
- // If looks like a valid email address, treat as such
-
- if (strlen(HDest) > 6 || !CheckifPacket(Vptr))
- {
- // Assume Email address
-
- Vptr = OrigTo;
-
- if (FindRMS() || strchr(Vptr, '!')) // have RMS or source route
- strcpy(Msg->to, "RMS");
- else if (ISP_Gateway_Enabled)
- Msg->to[0] = 0;
- else if (isAMPRMsg(OrigTo))
- strcpy(Msg->to, "RMS"); // Routing will redirect it
- else
- {
- *RLen = sprintf(Reply, "%s", "");
- FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
- return;
-
- }
- }
- else
- strcpy(Msg->to, _strupr(HDest));
- }
- }
- else
- {
- // No @
-
- if (strlen(HDest) > 6)
- HDest[6] = 0;
-
- strcpy(Msg->to, _strupr(HDest));
- }
-
- if (SendBBStoSYSOPCall)
- if (_stricmp(HDest, BBSName) == 0)
- strcpy(Msg->to, SYSOPCall);
-
- if (Vptr)
- {
- if (strlen(Vptr) > 40)
- Vptr[40] = 0;
-
- strcpy(Msg->via, _strupr(Vptr));
- }
- else
- {
- // No via. If not local user try to add BBS
-
- struct UserInfo * ToUser = LookupCall(Msg->to);
-
- if (ToUser)
- {
- // Local User. If Home BBS is specified, use it
-
- if (ToUser->flags & F_RMSREDIRECT)
- {
- // sent to Winlink
-
- strcpy(Msg->via, WinlinkAddr);
- sprintf(Prompt, "Redirecting to winlink.org\r");
- }
- else if (ToUser->HomeBBS[0])
- {
- strcpy(Msg->via, ToUser->HomeBBS);
- sprintf(Prompt, "%s added from HomeBBS. Message Saved", Msg->via);
- }
- }
- else
- {
- // Not local user - Check WP
-
- WPRecP WP = LookupWP(Msg->to);
-
- if (WP)
- {
- strcpy(Msg->via, WP->first_homebbs);
- sprintf(Prompt, "%s added from WP", Msg->via);
- }
- }
- }
-
- if (strlen(WebMail->Subject) > 60)
- WebMail->Subject[60] = 0;
-
- strcpy(Msg->title, WebMail->Subject);
- Msg->type = WebMail->Type;
-
- if (Session->User->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);
- }
- else
- Msg->status = 'N';
-
- if (strlen(WebMail->BID) == 0)
- sprintf(Msg->bid, "%d_%s", LatestMsg, BBSName);
- else
- strcpy(Msg->bid, WebMail->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);
-
- Msg->length = (int)MsgLen + WebMail->HeaderLen + WebMail->FooterLen;
-
- sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
-
- // BuildFormMessage(Session, Msg);
-
- if (WebMail->Files)
- {
- // Send as B2
-
- char * B2Header = BuildB2Header(WebMail, Msg, NULL, 0);
-
- hFile = fopen(MsgFile, "wb");
-
- if (hFile)
- {
- WriteLen = fwrite(B2Header, 1, strlen(B2Header), hFile);
- WriteLen += fwrite(WebMail->Header, 1, WebMail->HeaderLen, hFile);
- WriteLen += fwrite(WebMail->Body, 1, MsgLen, hFile);
- WriteLen += fwrite(WebMail->Footer, 1, WebMail->FooterLen, hFile);
- WriteLen += fwrite("\r\n", 1, 2, hFile);
-
- for (i = 0; i < WebMail->Files; i++)
- {
- WriteLen += fwrite(WebMail->FileBody[i], 1, WebMail->FileLen[i], hFile);
- WriteLen += fwrite("\r\n", 1, 2, hFile);
- }
- fclose(hFile);
- free(B2Header);
-
- Msg->length = (int)WriteLen;
- }
- }
- else
- {
- hFile = fopen(MsgFile, "wb");
-
- if (hFile)
- {
- WriteLen += fwrite(WebMail->Header, 1, WebMail->HeaderLen, hFile);
- WriteLen += fwrite(WebMail->Body, 1, MsgLen, hFile);
- WriteLen += fwrite(WebMail->Footer, 1, WebMail->FooterLen, hFile);
- fclose(hFile);
- }
- }
- MatchMessagetoBBSList(Msg, &conn);
-
- BuildNNTPList(Msg); // Build NNTP Groups list
-
- if (Msg->status != 'H' && Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0)
- Msg->status = '$'; // Has forwarding
-
-
- if (EnableUI)
- SendMsgUI(Msg);
-
- user = LookupCall(Msg->to);
-
- // If Event Notifications enabled report a new message event
-
- SendNewMessageEvent(user->Call, Msg);
-
-#ifndef NOMQTT
- if (MQTT)
- MQTTMessageEvent(Msg);
-#endif
-
- if (user && (user->flags & F_APRSMFOR))
- {
- char APRS[128];
- char Call[16];
- int SSID = user->flags >> 28;
-
- if (SSID)
- sprintf(Call, "%s-%d", Msg->to, SSID);
- else
- strcpy(Call, Msg->to);
-
- sprintf(APRS, "New BBS Message %s From %s", Msg->title, Msg->from);
- APISendAPRSMessage(APRS, Call);
- }
-
- HDest = HDestRest;
- }
-
- *RLen = SendWebMailHeaderEx(Reply, Session->Key, Session, Prompt);
-
- SaveMessageDatabase();
- SaveBIDDatabase();
- FreeWebMailFields(WebMail);
- free(HDestCopy);
-
- return;
-}
-
-
-
-
-
-
-// RMS Express Forms Support
-
-char * GetHTMLViewerTemplate(char * FN, struct HtmlFormDir ** FormDir)
-{
- int i, j, k, l;
-
- // Seach list of forms for base file (without .html)
-
- for (i = 0; i < FormDirCount; i++)
- {
- struct HtmlFormDir * Dir = HtmlFormDirs[i];
-
- for (j = 0; j < Dir->FormCount; j++)
- {
- if (strcmp(FN, Dir->Forms[j]->FileName) == 0)
- {
- *FormDir = Dir;
- return CheckFile(Dir, FN);
- }
- }
-
- if (Dir->DirCount)
- {
- for (l = 0; l < Dir->DirCount; l++)
- {
- struct HtmlFormDir * SDir = Dir->Dirs[l];
-
- if (SDir->DirCount)
- {
- struct HtmlFormDir * SSDir = SDir->Dirs[0];
- int x = 1;
- }
-
- for (k = 0; k < SDir->FormCount; k++)
- {
- if (_stricmp(FN, SDir->Forms[k]->FileName) == 0)
- {
- *FormDir = SDir;
- return CheckFile(SDir, SDir->Forms[k]->FileName);
- }
- }
- if (SDir->DirCount)
- {
- struct HtmlFormDir * SSDir = SDir->Dirs[0];
- int x = 1;
- }
- }
- }
- }
-
- return NULL;
-}
-VOID GetReply(struct HTTPConnectionInfo * Session, char * NodeURL)
-{
-}
-
-VOID GetPage(struct HTTPConnectionInfo * Session, char * NodeURL)
-{
- // Read the HTML Template file and do any needed substitutions
-
- WebMailInfo * WebMail = Session->WebMail;
- KeyValues * txtKey = WebMail->txtKeys;
-
- int DirNo;
- char * ptr;
- int FileNo = 0;
- char * SubDir;
- int SubDirNo;
- int i;
- struct HtmlFormDir * Dir;
- char * Template;
- char * inptr;
- char FormDir[MAX_PATH] = "";
- char FN[MAX_PATH] = "";
- char * InputName = NULL; // HTML to input message
- char * ReplyName = NULL;
- char * To = NULL;
- char * CC = NULL;
- char * BID = NULL;
- char Type = 0;
- char * Subject = NULL;
- char * MsgBody = NULL;
- char * varptr;
- char * endptr;
- size_t varlen, vallen = 0;
- char val[256]=""; // replacement text
- char var[100] = "\"";
- char * MsgBytes;
- char Submit[64];
-
- if (NodeURL == NULL)
- {
- //rentry after processing or
-
- goto reEnter;
- }
-
- DirNo = atoi(&NodeURL[17]);
- ptr = strchr(&NodeURL[17], ',');
- Dir = HtmlFormDirs[DirNo];
-
-
- if (DirNo == -1)
- {
- *WebMail->RLen = sprintf(WebMail->Reply, "", Session->Key);
- return;
- }
-
- SubDir = strlop(&NodeURL[17], ':');
- if (SubDir)
- {
- SubDirNo = atoi(SubDir);
- Dir = Dir->Dirs[SubDirNo];
- }
-
- sprintf(Submit, "/Webmail/Submit?%s", Session->Key);
-
- if (ptr)
- FileNo = atoi(ptr + 1);
-
- // First we read the .txt. then get name of input .html from it
-
- if (WebMail->txtFile)
- free(WebMail->txtFile);
-
- WebMail->txtFile = NULL;
-
- if (WebMail->txtFileName)
- free(WebMail->txtFileName);
-
- WebMail->txtFileName = _strdup(Dir->Forms[FileNo]->FileName);
-
- // Read the file here to simplify reentry if we do or substitutions
-
- // if Dir not specified search all for Filename
-
- if (Dir == NULL)
- {
- for (i = 0; i < FormDirCount; i++)
- {
- int n;
-
- Dir = HtmlFormDirs[i];
-
- MsgBytes = CheckFile(Dir, WebMail->txtFileName);
- if (MsgBytes)
- goto gotFile;
-
- // Recurse any Subdirs
-
- n = 0;
- while (n < Dir->DirCount)
- {
- MsgBytes = CheckFile(Dir->Dirs[n], FN);
- if (MsgBytes)
- {
- Dir = Dir->Dirs[n];
- goto gotFile;
- }
- n++;
- }
- }
- return;
- }
- else
- MsgBytes = CheckFile(Dir, WebMail->txtFileName);
-
-gotFile:
-
- WebMail->Dir = Dir;
-
- if (WebMail->txtFile)
- free(WebMail->txtFile);
-
- WebMail->txtFile = MsgBytes;
-
-reEnter:
-
- if (ParsetxtTemplate(Session, Dir, WebMail->txtFileName, FALSE) == FALSE)
- {
- // Template has or tags and value has been requested
-
- return;
- }
-
- if (WebMail->InputHTMLName == NULL)
- {
- // This is a plain text template without HTML
-
- if (To == NULL &&WebMail->To && WebMail->To[0])
- To = WebMail->To;
- else
- To = "";
-
- if (CC == NULL && WebMail->CC && WebMail->CC[0])
- CC = WebMail->CC;
- else
- CC = "";
-
-
- if (Subject == NULL && WebMail->Subject && WebMail->Subject[0])
- Subject = WebMail->Subject;
- else
- Subject = "";
-
- if (BID == NULL && WebMail->BID && WebMail->BID[0])
- BID = WebMail->BID;
- else
- BID = "";
-
- if (Type == 0 && WebMail->Type)
- Type = WebMail->Type;
- else
- Type = 'P';
-
- if (MsgBody == NULL)
- MsgBody = "";
-
- if (MsgBody[0] == 0 && WebMail->Body && WebMail->Body[0])
- MsgBody = WebMail->Body;
-
- *WebMail->RLen = sprintf(WebMail->Reply, CheckFormMsgPage, Session->Key, To, CC, Subject,
- (Type =='P') ? "Selected" : "", (Type =='B') ? "Selected" : "", (Type =='T') ? "Selected" : "", BID, MsgBody);
- return;
- }
-
- Template = CheckFile(Dir, WebMail->InputHTMLName);
-
- if (Template == NULL)
- {
- *WebMail->RLen = sprintf(WebMail->Reply, "%s", "HTML Template not found");
- return;
- }
-
- // I've going to update the template in situ, as I can't see a better way
- // of making sure all occurances of variables in any order are substituted.
- // The space allocated to Template is twice the size of the file
- // to allow for insertions
-
- // First find the Form Action string and replace with our URL. It should have
- // action="http://{FormServer}:{FormPort}" but some forms have localhost:8001 instead
-
- // Also remove the OnSubmit if it contains the standard popup about having to close browser
-
- UpdateFormAction(Template, Session->Key);
-
- // Search for "{var }" strings in form and replace with
- // corresponding variable
-
- // we run through the Template once for each variable
-
- while (txtKey->Key)
- {
- char Key[256] = "{";
-
- strcpy(&Key[1], &txtKey->Key[1]);
-
- ptr = strchr(Key, '>');
- if (ptr)
- *ptr = '}';
-
- inptr = Template;
- varptr = stristr(inptr, Key);
-
- while (varptr)
- {
- // Move the remaining message up/down the buffer to make space for substitution
-
- varlen = strlen(Key);
- if (txtKey->Value)
- vallen = strlen(txtKey->Value);
- else vallen = 0;
-
- endptr = varptr + varlen;
-
- memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
- memcpy(varptr, txtKey->Value, vallen);
-
- inptr = endptr + 1;
-
- varptr = stristr(inptr, Key);
- }
- txtKey++;
- }
-
- // Remove from end as we add it on later
-
- ptr = stristr(Template, "");
-
- if (ptr)
- *ptr = 0;
-
- *WebMail->RLen = sprintf(WebMail->Reply, "%s", Template);
- free(Template);
- return;
-}
-
-
-
-char * xxReadTemplate(char * FormSet, char * DirName, char *FileName)
-{
- int FileSize;
- char * MsgBytes;
- char MsgFile[265];
- size_t ReadLen;
- struct stat STAT;
- FILE * hFile;
-
-#ifndef WIN32
-
- // Need to do case insensitive file search
-
- DIR *dir;
- struct dirent *entry;
- char name[256];
-
- sprintf(name, "%s/%s/%s", BPQDirectory, FormSet, DirName);
-
- if (!(dir = opendir(name)))
- {
- Debugprintf("cant open forms dir %s %d %d", name, errno, dir);
- return 0;
- }
-
- while ((entry = readdir(dir)) != NULL)
- {
- if (entry->d_type == DT_DIR)
- continue;
-
- if (stristr(entry->d_name, FileName))
- {
- sprintf(MsgFile, "%s/%s/%s/%s", GetBPQDirectory(), FormSet, DirName, entry->d_name);
- closedir(dir);
- break;
- }
- }
- closedir(dir);
-
-#else
-
- sprintf(MsgFile, "%s/%s/%s/%s", GetBPQDirectory(), FormSet, DirName, FileName);
-
-#endif
-
- if (stat(MsgFile, &STAT) != -1)
- {
- hFile = fopen(MsgFile, "rb");
-
- if (hFile == 0)
- {
- MsgBytes = _strdup("File is missing");
- return MsgBytes;
- }
-
- FileSize = STAT.st_size;
- MsgBytes = malloc(FileSize * 2); // Allow plenty of room for template substitution
- ReadLen = fread(MsgBytes, 1, FileSize, hFile);
- MsgBytes[FileSize] = 0;
- fclose(hFile);
-
- return MsgBytes;
- }
-
- return NULL;
-}
-
-int ReturnRawMessage(struct UserInfo * User, struct MsgInfo * Msg, char * Key, char * Reply, char * RawMessage, int len, char * ErrorString)
-{
- char * ErrorMsg = malloc(len + 100);
- char * ptr;
- char DownLoad[256];
-
- sprintf(DownLoad, "Save Attachments | ", Key, Msg->number);
-
- RawMessage[strlen(RawMessage)] = '.'; // We null terminated file name
- RawMessage[strlen(RawMessage)] = ' '; // We null terminated file name Len = XML - RawMessage;
-
- RawMessage[len] = 0;
-
- // Body seems to have cr cr lf which causes double space
-
- ptr = strstr(RawMessage, "\r\r");
-
- while (ptr)
- {
- *ptr = ' ';
- ptr = strstr(ptr, "\r\r");
- }
-
- sprintf(ErrorMsg, ErrorString, RawMessage);
-
- len = sprintf(Reply, WebMailMsgTemplate, BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, DownLoad, Key, Key, Key, "textarea", ErrorMsg, "textarea");
- free(ErrorMsg);
- return len;
-}
-
-char * FindXMLVariable(WebMailInfo * WebMail, char * Var)
-{
- KeyValues * XMLKey = &WebMail->XMLKeys[0];
-
- while (XMLKey->Key)
- {
- if (_stricmp(Var, XMLKey->Key) == 0)
- {
- return XMLKey->Value;
- }
-
- XMLKey++;
- }
- return NULL;
-}
-
-
-BOOL ParseXML(WebMailInfo * WebMail, char * XMLOrig)
-{
- char * XML = _strdup(XMLOrig); // Get copy so we can mess about with it
- char * ptr1, * ptr2, * ptr3;
- KeyValues * XMLKeys = &WebMail->XMLKeys[0];
-
- // Extract Fields (stuff between < and >. Ignore Whitespace between fields
-
- // Add FormFolder Key with our folder
-
-// XMLKeys->Key = "FormFolder";
-// XMLKeys->Value = _strdup(FormDir);
-
-// XMLKeys++;
-
- ptr1 = strstr(XML, "");
-
- while (ptr1)
- {
- ptr2 = strchr(++ptr1, '>');
-
- if (ptr2 == NULL)
- goto quit;
-
- *ptr2++ = 0;
-
- ptr3 = strstr(ptr2, ""); // end of value string
- if (ptr3 == NULL)
- goto quit;
-
- *ptr3++ = 0;
-
- XMLKeys->Key = _strdup(ptr1);
- XMLKeys->Value = _strdup(ptr2);
-
- XMLKeys++;
-
- ptr1 = strchr(ptr3, '<');
-
- if (_memicmp(ptr1, "", 2) == 0)
- {
- // end of a parameter block. Find start of next block
-
- ptr1 = strchr(++ptr1, '<');
- ptr1 = strchr(++ptr1, '<'); // Skip start of next block
- }
- }
-
-
-
-
-quit:
- free(XML);
- return TRUE;
-}
-/*
-?xml version="1.0"?>
-
-
- 1,0
- 6.0.16.38 Debug Build
- 20181022105202
- G8BPQ
-
- Alaska_ARES_ICS213_Initial_Viewer.html
- Alaska_ARES_ICS213_SendReply.txt
-
-
- g8bpq
-
- G8BPQ
-
-
- false
- false
- false
- false
- G8BPQ-1
- Routine
-
-
-
- Here
-
- 2018-10-22
- Test
- John
- John
- Test
- 2018-10-22 11:51
-
- Me
- Me
- Submit
-
-
-*/
-
-
-char HTMLNotFoundMsg[] = " *** HTML Template for message not found - displaying raw content ***\r\n\r\n%s";
-char VarNotFoundMsg[] = " *** Variable {%s} not found in message - displaying raw content ***\r\n\r\n%s";
-char BadXMLMsg[] = " *** XML for Variable {%s} invalid - displaying raw content ***\r\n\r\n%s";
-char BadTemplateMsg[] = " *** Template near \"%s\" invalid - displaying raw content ***\r\n\r\n%s";
-
-int DisplayWebForm(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * FileName, char * XML, char * Reply, char * RawMessage, int RawLen)
-{
- WebMailInfo * WebMail = Session->WebMail;
- struct UserInfo * User = Session->User;
- char * Key = Session->Key;
- int Len = 0;
- char * Form;
- char * SaveReply = Reply;
- char FN[MAX_PATH] = "";
- char * formptr, * varptr, * xmlptr;
- char * ptr = NULL, * endptr, * xmlend;
- size_t varlen, xmllen;
- char var[100] = "<";
- KeyValues * KeyValue;
- struct HtmlFormDir * Dir;
- char FormDir[MAX_PATH];
-
- if (ParseXML(WebMail, XML))
- ptr = FindXMLVariable(WebMail, "display_form");
-
- if (ptr == NULL) // ?? No Display Form Specified??
- {
- // Not found - just display as normal message
-
- return ReturnRawMessage(User, Msg, Key, Reply, RawMessage, (int)(XML - RawMessage), HTMLNotFoundMsg);
- }
-
- strcpy(FN, ptr);
-
- Form = GetHTMLViewerTemplate(FN, &Dir);
-
- sprintf(FormDir, "WMFile/%s/%s/", Dir->FormSet, Dir->DirName);
-
-
-
- if (Form == NULL)
- {
- // Not found - just display as normal message
-
- return ReturnRawMessage(User, Msg, Key, Reply, RawMessage, (int)(XML - RawMessage), HTMLNotFoundMsg);
- }
-
- formptr = Form;
-
- // Search for {var xxx} strings in form and replace with
- // corresponding variable in xml
-
- // Don't know why, but {MsgOriginalBody} is sent instead of {var MsgOriginalBody}
-
- // So is {FormFolder} instread of {var FormFolder}
-
- // As a fiddle replace {FormFolder} with {var Folder} and look for that
-
- while (varptr = stristr(Form, "{FormFolder}"))
- {
- memcpy(varptr, "{var ", 5);
- }
-
- varptr = stristr(Form, "{MsgOriginalBody}");
- {
- char * temp, * tempsave;
- char * xvar, * varsave, * ptr;
-
- if (varptr)
- {
- varptr++;
-
- endptr = strchr(varptr, '}');
- varlen = endptr - varptr;
-
- if (endptr == NULL || varlen > 99)
- {
- // corrupt template - display raw message
-
- char Err[256];
-
- varptr[20] = 0;
-
- sprintf(Err, BadTemplateMsg, varptr - 5, "%s");
- return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
- }
-
- memcpy(var + 1, varptr, varlen);
- var[++varlen] = '>';
- var[++varlen] = 0;
-
- xmlptr = stristr(XML, var);
-
- if (xmlptr)
- {
- xmlptr += varlen;
-
- xmlend = strstr(xmlptr, "");
-
- if (xmlend == NULL)
- {
- // Bad XML - return error message
-
- char Err[256];
-
- // remove <> from var as it confuses html
-
- var[strlen(var) -1] = 0;
-
- sprintf(Err, BadXMLMsg, var + 1, "%s");
- return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
- }
-
- xmllen = xmlend - xmlptr;
- }
- else
- {
- // Variable not found - return error message
-
- char Err[256];
-
- // remove <> from var as it confuses html
-
- var[strlen(var) -1] = 0;
-
- sprintf(Err, VarNotFoundMsg, var + 1, "%s");
- return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
- }
-
- // Ok, we have the position of the variable and the substitution text.
- // Copy message up to variable to Result, then copy value
-
- // We create a copy so we can rescan later.
- // We also need to replace CR or CRLF with
-
- xvar = varsave = malloc(xmllen * 2);
-
- ptr = xmlptr;
-
- while(ptr < xmlend)
- {
- while (*ptr == '\n')
- ptr++;
-
- if (*ptr == '\r')
- {
- *ptr++;
- strcpy(xvar, "
");
- xvar += 4;
- }
- else
- *(xvar++) = *(ptr++);
- }
- *xvar = 0;
-
- temp = tempsave = malloc(strlen(Form) + strlen(XML));
-
- memcpy(temp, formptr, varptr - formptr - 1); // omit "{"
- temp += (varptr - formptr - 1);
-
- strcpy(temp, varsave);
- temp += strlen(varsave);
- free(varsave);
-
- formptr = endptr + 1;
- strcpy(temp, formptr);
- strcpy(Form, tempsave);
- free(tempsave);
- }
- }
-
- formptr = Form;
-
- varptr = stristr(Form, "{var ");
-
- while (varptr)
- {
- varptr+= 5;
-
- endptr = strchr(varptr, '}');
-
- varlen = endptr - varptr;
-
- if (endptr == NULL || varlen > 99)
- {
- // corrupt template - display raw message
-
- char Err[256];
-
- varptr[20] = 0;
-
- sprintf(Err, BadTemplateMsg, varptr - 5, "%s");
- return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
- }
-
- memcpy(var, varptr, varlen);
- var[varlen] = 0;
-
- KeyValue = &WebMail->XMLKeys[0];
-
- while (KeyValue->Key)
- {
- if (_stricmp(var, "Folder") == 0)
- {
- // Local form folder, not senders
-
- xmllen = strlen(FormDir);
-
- // Ok, we have the position of the variable and the substitution text.
- // Copy message up to variable to Result, then copy value
-
- memcpy(Reply, formptr, varptr - formptr - 5); // omit "{var "
- Reply += (varptr - formptr - 5);
-
- strcpy(Reply, FormDir);
- Reply += xmllen;
- break;
- }
-
- if (_stricmp(var, KeyValue->Key) == 0)
- {
- xmllen = strlen(KeyValue->Value);
-
- // Ok, we have the position of the variable and the substitution text.
- // Copy message up to variable to Result, then copy value
-
- memcpy(Reply, formptr, varptr - formptr - 5); // omit "{var "
- Reply += (varptr - formptr - 5);
-
- strcpy(Reply, KeyValue->Value);
- Reply += xmllen;
- break;
- }
-
- KeyValue++;
-
- if (KeyValue->Key == NULL)
- {
- // Not found in XML
-
- char Err[256];
-
- sprintf(Err, VarNotFoundMsg, var, "%s");
- return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
- }
-
- }
-
- formptr = endptr + 1;
-
- varptr = stristr(endptr, "{var ");
- }
-
- // copy remaining
-
- // Remove as we add it later
-
- ptr = strstr(formptr, "");
-
- if (ptr)
- *ptr = 0;
-
- strcpy(Reply, formptr);
-
- // Add Webmail header between and form data
-
- ptr = stristr(SaveReply, "');
- if (ptr)
- {
- char * temp = malloc(strlen(SaveReply) + 1000);
- size_t len = ++ptr - SaveReply;
- memcpy(temp, SaveReply, len);
-
- sprintf(&temp[len],
- ""
- " %s Webmail Interface - User %s - Message %d
"
- "", BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, Key, Msg->number, Key, Key, Key);
-
- strcat(temp, ptr);
-
- strcpy(SaveReply, temp);
- free(temp);
- }
- }
-
- if (Form)
- free(Form);
-
- return (int)strlen(SaveReply);
-}
-
-char * BuildB2Header(WebMailInfo * WebMail, struct MsgInfo * Msg, char ** ToCalls, int Calls)
-{
- // Create B2 Header
-
- char * NewMsg = malloc(100000);
- char * SaveMsg = NewMsg;
- char DateString[80];
- struct tm * tm;
- int n;
- char Type[16] = "Private";
-
- // Get Type
-
- if (Msg->type == 'B')
- strcpy(Type, "Bulletin");
- else if (Msg->type == 'T')
- strcpy(Type, "Traffic");
-
- 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);
-
- NewMsg += sprintf(NewMsg,
- "MID: %s\r\n"
- "Date: %s\r\n"
- "Type: %s\r\n"
- "From: %s\r\n",
- Msg->bid, DateString, Type, Msg->from);
-
- if (ToCalls)
- {
- int i;
-
- for (i = 0; i < Calls; i++)
- NewMsg += sprintf(NewMsg, "To: %s\r\n", ToCalls[i]);
- }
- else
- {
- NewMsg += sprintf(NewMsg, "To: %s\r\n",
- WebMail->To);
- }
- if (WebMail->CC && WebMail->CC[0])
- NewMsg += sprintf(NewMsg, "CC: %s\r\n", WebMail->CC);
-
- NewMsg += sprintf(NewMsg,
- "Subject: %s\r\n"
- "Mbo: %s\r\n",
- Msg->title, BBSName);
-
- NewMsg += sprintf(NewMsg, "Body: %d\r\n", (int)strlen(WebMail->Body) + WebMail->HeaderLen + WebMail->FooterLen);
-
- Msg->B2Flags = B2Msg;
-
- if (WebMail->XML)
- {
- Msg->B2Flags |= Attachments;
- NewMsg += sprintf(NewMsg, "File: %d %s\r\n",
- WebMail->XMLLen, WebMail->XMLName);
- }
-
- for (n = 0; n < WebMail->Files; n++)
- {
- Msg->B2Flags |= Attachments;
- NewMsg += sprintf(NewMsg, "File: %d %s\r\n",
- WebMail->FileLen[n], WebMail->FileName[n]);
- }
-
- NewMsg += sprintf(NewMsg, "\r\n"); // Blank Line to end header
-
- return SaveMsg;
-}
-
-VOID WriteOneRecipient(struct MsgInfo * Msg, WebMailInfo * WebMail, int MsgLen, char ** ToCalls, int Calls, char * BID)
-{
- FILE * hFile;
- char * via = NULL;
- BIDRec * BIDRec;
- char MsgFile[MAX_PATH];
- size_t WriteLen=0;
- char * B2Header;
-
- if (strlen(WebMail->Subject) > 60)
- WebMail->Subject[60] = 0;
-
- strcpy(Msg->title, WebMail->Subject);
-
- if (strlen(BID) == 0)
- sprintf_s(BID, 32, "%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);
-
- Msg->length = MsgLen;
-
- sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
-
- // We write a B2 Header, Body and XML attachment if present
-
- B2Header = BuildB2Header(WebMail, Msg, ToCalls, Calls);
-
- hFile = fopen(MsgFile, "wb");
-
- if (hFile)
- {
- int i;
-
- WriteLen = fwrite(B2Header, 1, strlen(B2Header), hFile);
- WriteLen += fwrite(WebMail->Body, 1, Msg->length, hFile);
- WriteLen += fwrite("\r\n", 1, 2, hFile);
- if (WebMail->XML)
- {
- WriteLen += fwrite(WebMail->XML, 1, WebMail->XMLLen, hFile);
- WriteLen += fwrite("\r\n", 1, 2, hFile);
- }
- // Do any attachments
-
- for (i = 0; i < WebMail->Files; i++)
- {
- WriteLen += fwrite(WebMail->FileBody[i], 1, WebMail->FileLen[i], hFile);
- WriteLen += fwrite("\r\n", 1, 2, hFile);
- }
- fclose(hFile);
- }
-
- free(B2Header);
-
- Msg->length = (int)WriteLen;
-
- MatchMessagetoBBSList(Msg, 0);
-
- if (Msg->status != 'H' && Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0)
- Msg->status = '$'; // Has forwarding
-
- BuildNNTPList(Msg); // Build NNTP Groups list
-
-#ifndef NOMQTT
- if (MQTT)
- MQTTMessageEvent(Msg);
-#endif
-
-}
-
-
-VOID SaveTemplateMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
-{
- int ReplyLen = 0;
- struct MsgInfo * Msg;
- char * ptr, *input, *context;
- size_t MsgLen;
- char Type;
- char * via = NULL;
- char BID[32];
- size_t WriteLen=0;
- char * Body = NULL;
- char * To = NULL;
- char * CC = NULL;
- char * HDest = NULL;
- char * Title = NULL;
- char * Vptr = NULL;
- char * Context;
- char Prompt[256] = "Message Saved";
- char OrigTo[256];
- WebMailInfo * WebMail = Session->WebMail;
- BOOL SendMsg = FALSE;
- BOOL SendReply = FALSE;
-
- char * RMSTo[1000] = {NULL}; // Winlink addressees
- char * PKTT0[1000] = {NULL}; // Packet addressees
-
- __int32 Recipients = 0;
- __int32 RMSMsgs = 0, BBSMsgs = 0;
-
-
- input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
-
- if (input == NULL)
- return;
-
- if (strstr(input, "Cancel=Cancel"))
- {
- *RLen = sprintf(Reply, "", Session->Key);
- return;
- }
-
- if (WebMail->txtFileName == NULL)
- {
- // No template, so user must have used back button
-
- *RLen = sprintf(Reply, "", Session->Key);
- return;
- }
-
- ptr = strtok_s(input + 4, "&", &Context);
-
- while (ptr)
- {
- char * val = strlop(ptr, '=');
-
- if (strcmp(ptr, "To") == 0)
- HDest = To = val;
- else if (strcmp(ptr, "CC") == 0)
- CC = val;
- else if (strcmp(ptr, "Subj") == 0)
- Title = val;
- else if (strcmp(ptr, "Type") == 0)
- Type = val[0];
- else if (strcmp(ptr, "BID") == 0)
- strcpy(BID, val);
- else if (strcmp(ptr, "Msg") == 0)
- Body = _strdup(val);
-
- ptr = strtok_s(NULL, "&", &Context);
-
- }
- strlop(BID, ' ');
- if (strlen(BID) > 12)
- BID[12] = 0;
-
- UndoTransparency(To);
- UndoTransparency(CC);
- UndoTransparency(BID);
- UndoTransparency(HDest);
- UndoTransparency(Title);
- UndoTransparency(Body);
-
- MsgLen = strlen(Body);
-
- // The user could have changed any of the input fields.
-
- if (To && To[0])
- {
- free (WebMail->To);
- WebMail->To = _strdup(To);
- }
-
- if (CC && CC[0])
- {
- free (WebMail->CC);
- WebMail->CC = _strdup(CC);
- }
-
- if (Title && Title[0])
- {
- free (WebMail->Subject);
- WebMail->Subject = _strdup(Title);
- }
-
- if (Body && Body[0])
- {
- free (WebMail->Body);
- WebMail->Body = _strdup(Body);
- }
-
- // We will put the supplied address in the B2 header
-
- // We may need to change the HDest to make sure message
- // is delivered to Internet or Packet as requested
-
- if (HDest == NULL || HDest[0] == 0)
- {
- *RLen = sprintf(Reply, "%s", "");
- return;
- }
-
- // Multiple TO fields could be more than 255 bytes long
-
-// if (strlen(HDest) > 255)
-// {
-// *RLen = sprintf(Reply, "%s", "");
-// return;
-// }
-
- if (strlen(BID))
- {
- if (LookupBID(BID))
- {
- // Duplicate bid
- *RLen = sprintf(Reply, "%s", "");
- return;
- }
- }
-
- if (Type == 'B')
- {
- if (RefuseBulls)
- {
- *RLen = sprintf(Reply, "%s", "");
- return;
- }
- }
-
- // We should be able to handle multiple recipients, with all Winlink addresses sent in one message and
- // multiple copies for packet addressess. For Winlink we should use multiple To@ lines in B2 Header
-
- ptr = strtok_s(HDest, " ;", &context);
-
- while (ptr && ptr[0])
- {
- int Winlink = 0;
- int AMPR = 0;
-
- char * dest = zalloc(256);
- char * via = NULL;
-
- strcpy(dest, ptr);
-
- // See if packet or Winlink
-
- // If Type=Winlink specified send plain call as @winlink.org
-
- if (strchr(dest, '@') == 0 && WebMail->Winlink)
- strcat(dest, "@winlink.org");
-
- if (_memicmp(dest, "rms:", 4) == 0 || _memicmp(dest, "rms/", 4) == 0)
- {
- memcpy(dest, &dest[4], strlen(dest));
- Winlink = 1;
- RMSTo[RMSMsgs++] = dest;
- ptr = strtok_s(NULL, " ;", &context);
- continue;
- }
-
- else if (_memicmp(dest, "smtp:", 5) == 0)
- {
- if (ISP_Gateway_Enabled)
- {
- via = &dest[5];
- dest[0] = 0;
- }
- }
- else if (strchr(dest, '@'))
- {
- strcpy(OrigTo, dest);
-
- via = strlop(dest, '@');
-
- if (via)
- {
- // If looks like a valid email address, treat as such
-
- if (strlen(via) > 6 || !CheckifPacket(via))
- {
- // Assume Email address. See if to send via RMS or SMTP
-
- if (isAMPRMsg(OrigTo))
- {
- dest[strlen(dest)] = '@'; // Put back together
- memmove(&dest[1], dest, strlen(dest));
- dest[0] = 0;
- via = &dest[1];
- AMPR = 1;
- }
- else if (FindRMS() || strchr(via, '!')) // have RMS or source route
- {
- dest[strlen(dest)] = '@'; // Put back together
- Winlink = 1;
- RMSTo[RMSMsgs++] = dest;
- ptr = strtok_s(NULL, " ;", &context);
- continue;
- }
- else if (ISP_Gateway_Enabled)
- {
- dest[strlen(dest)] = '@'; // Put back together
- memmove(dest, &dest[1], strlen(dest));
- dest[0] = 0;
- }
- else
- {
- *RLen = sprintf(Reply, "%s", "");
- return;
-
- }
- }
- }
- }
- else
- {
- // No @
-
- if (strlen(dest) > 6)
- dest[6] = 0;
- }
-
- // This isn't an RMS Message, so can queue now
-
- Msg = AllocateMsgRecord();
-
- // Set number here so they remain in sequence
-
- Msg->number = ++LatestMsg;
- MsgnotoMsg[Msg->number] = Msg;
-
- strcpy(Msg->title, WebMail->Subject);
- Msg->type = Type;
- Msg->status = 'N';
-
-
- strcpy(Msg->from, Session->User->Call);
-
- strcpy(Msg->to, _strupr(dest));
-
- if (SendBBStoSYSOPCall)
- if (_stricmp(dest, BBSName) == 0)
- strcpy(Msg->to, SYSOPCall);
-
- if (via)
- {
- if (strlen(via) > 40)
- via[40] = 0;
-
- strcpy(Msg->via, _strupr(via));
- }
- else
- {
- // No via. If not local user try to add BBS
-
- struct UserInfo * ToUser = LookupCall(Msg->to);
-
- if (ToUser)
- {
- // Local User. If Home BBS is specified, use it
-
- if (ToUser->flags & F_RMSREDIRECT)
- {
- // sent to Winlink
-
- strcpy(Msg->via, WinlinkAddr);
- sprintf(Prompt, "Redirecting to winlink.org\r");
- }
- else if (ToUser->HomeBBS[0])
- {
- strcpy(Msg->via, ToUser->HomeBBS);
- sprintf(Prompt, "%s added from HomeBBS. Message Saved", Msg->via);
- }
- }
- else
- {
- // Not local user - Check WP
-
- WPRecP WP = LookupWP(Msg->to);
-
- if (WP)
- {
- strcpy(Msg->via, WP->first_homebbs);
- sprintf(Prompt, "%s added from WP", Msg->via);
- }
- }
- }
- WriteOneRecipient(Msg, WebMail, MsgLen, NULL, 0, BID);
- ptr = strtok_s(NULL, " ;", &context);
- free(dest);
- BID[0] = 0; // Can't use more than once
- }
-
- if (RMSMsgs)
- {
- // Write one message to all Winlink addresses
-
- int i;
-
- Msg = AllocateMsgRecord();
-
- // Set number here so they remain in sequence
-
- Msg->number = ++LatestMsg;
- MsgnotoMsg[Msg->number] = Msg;
-
- strcpy(Msg->title, WebMail->Subject);
- Msg->type = Type;
- Msg->status = 'N';
-
- strcpy(Msg->from, Session->User->Call);
- strcpy(Msg->to, "RMS");
-
- WriteOneRecipient(Msg, WebMail, MsgLen, RMSTo, RMSMsgs, BID);
-
- for (i = 0; i < RMSMsgs; i++)
- free(RMSTo[i]);
-
- }
-
- SaveMessageDatabase();
- SaveBIDDatabase();
-
- *RLen = SendWebMailHeaderEx(Reply, Session->Key, Session, Prompt);
-
- FreeWebMailFields(WebMail);
-
- return;
-}
-
-
-
-VOID DoStandardTemplateSubsitutions(struct HTTPConnectionInfo * Session, char * txtFile)
-{
- WebMailInfo * WebMail = Session->WebMail;
- struct UserInfo * User = Session->User;
- KeyValues * txtKey = WebMail->txtKeys;
-
- char * inptr, * varptr, * endptr;
- int varlen, vallen;
-
- while (txtKey->Key != NULL)
- {
- inptr = WebMail->txtFile;
-
- varptr = stristr(inptr, txtKey->Key);
-
- while (varptr)
- {
- // Move the remaining message up/down the buffer to make space for substitution
-
- varlen = (int)strlen(txtKey->Key);
-
- if (txtKey->Value)
- vallen = (int)strlen(txtKey->Value);
- else
- vallen = 0;
-
- endptr = varptr + varlen;
-
- memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
- memcpy(varptr, txtKey->Value, vallen);
-
- inptr = endptr + 1;
-
- varptr = stristr(inptr, txtKey->Key);
- }
- txtKey++;
- }
-}
-
-
-
-VOID BuildMessageFromHTMLInput(struct HTTPConnectionInfo * Session, char * Reply, int * RLen, char * Keys[1000], char * Values[1000], int NumKeys)
-{
- int ReplyLen = 0;
- struct MsgInfo * Msg;
- int MsgLen;
- FILE * hFile;
- char Type = 'P';
- BIDRec * BIDRec;
- char * MailBuffer;
- char MsgFile[MAX_PATH];
- int WriteLen=0;
- char Prompt[256] = "Message Saved";
- char OrigTo[256];
- WebMailInfo * WebMail = Session->WebMail;
- char * HDest = _strdup(WebMail->To);
- char * Vptr = NULL;
- char BID[16] = "";
-
-/// if (strlen(HDest) > 255)
-/// {
-// *RLen = sprintf(Reply, "%s", "");
-// return;
-// }
-
- MsgLen = (int)strlen(WebMail->Body);
- Msg = AllocateMsgRecord();
-
- // Set number here so they remain in sequence
-
- Msg->number = ++LatestMsg;
- MsgnotoMsg[Msg->number] = Msg;
-
- strcpy(Msg->from, Session->User->Call);
-
- if (_memicmp(HDest, "rms:", 4) == 0 || _memicmp(HDest, "rms/", 4) == 0)
- {
- Vptr=&HDest[4];
- strcpy(Msg->to, "RMS");
- }
- else if (_memicmp(HDest, "smtp:", 5) == 0)
- {
- if (ISP_Gateway_Enabled)
- {
- Vptr=&HDest[5];
- Msg->to[0] = 0;
- }
- }
- else if (strchr(HDest, '@'))
- {
- strcpy(OrigTo, HDest);
-
- Vptr = strlop(HDest, '@');
-
- if (Vptr)
- {
- // If looks like a valid email address, treat as such
-
- if (strlen(HDest) > 6 || !CheckifPacket(Vptr))
- {
- // Assume Email address
-
- Vptr = OrigTo;
-
- if (FindRMS() || strchr(Vptr, '!')) // have RMS or source route
- strcpy(Msg->to, "RMS");
- else if (ISP_Gateway_Enabled)
- Msg->to[0] = 0;
- else if (isAMPRMsg(OrigTo))
- strcpy(Msg->to, "RMS"); // Routing will redirect it
- else
- {
- *RLen = sprintf(Reply, "%s", "");
- return;
-
- }
- }
- }
- }
-
- else
- {
- if (strlen(HDest) > 6)
- HDest[6] = 0;
-
- strcpy(Msg->to, _strupr(HDest));
- }
-
- if (SendBBStoSYSOPCall)
- if (_stricmp(HDest, BBSName) == 0)
- strcpy(Msg->to, SYSOPCall);
-
- if (Vptr)
- {
- if (strlen(Vptr) > 40)
- Vptr[40] = 0;
-
- strcpy(Msg->via, _strupr(Vptr));
- }
- else
- {
- // No via. If not local user try to add BBS
-
- struct UserInfo * ToUser = LookupCall(Msg->to);
-
- if (ToUser)
- {
- // Local User. If Home BBS is specified, use it
-
- if (ToUser->flags & F_RMSREDIRECT)
- {
- // sent to Winlink
-
- strcpy(Msg->via, WinlinkAddr);
- sprintf(Prompt, "Redirecting to winlink.org\r");
- }
- else if (ToUser->HomeBBS[0])
- {
- strcpy(Msg->via, ToUser->HomeBBS);
- sprintf(Prompt, "%s added from HomeBBS", Msg->via);
- }
- }
- else
- {
- // Not local user - Check WP
-
- WPRecP WP = LookupWP(Msg->to);
-
- if (WP)
- {
- strcpy(Msg->via, WP->first_homebbs);
- sprintf(Prompt, "%s added from WP", Msg->via);
- }
- }
- }
-
- if (strlen(WebMail->Subject) > 60)
- WebMail->Subject[60] = 0;
-
- strcpy(Msg->title, WebMail->Subject);
- Msg->type = Type;
- 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);
-
- MailBuffer = malloc(MsgLen + 2000); // Allow for a B2 Header if attachments
-
- Msg->length = MsgLen;
-
- BuildFormMessage(Session, Msg, Keys, Values, NumKeys);
-
- sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
-
- hFile = fopen(MsgFile, "wb");
-
- if (hFile)
- {
- WriteLen = (int)fwrite(WebMail->Body, 1, Msg->length, hFile);
- fclose(hFile);
- }
-
- free(WebMail->Body);
- free(HDest);
-
- WebMail->Body = NULL;
-
- MatchMessagetoBBSList(Msg, 0);
-
- if (Msg->status != 'H' && Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0)
- Msg->status = '$'; // Has forwarding
-
- BuildNNTPList(Msg); // Build NNTP Groups list
-
-#ifndef NOMQTT
- if (MQTT)
- MQTTMessageEvent(Msg);
-#endif
-
-
- SaveMessageDatabase();
- SaveBIDDatabase();
-
- *RLen = sprintf(Reply, "", Prompt);
-
- return;
-}
-
-
-
-
-
-
-
-
-
-void ProcessFormInput(struct HTTPConnectionInfo * Session, char * input, char * Reply, int * RLen, int InputLen)
-{
- // If there is no display html defined place data in a normal
- // input window, else build the Message body and XML attachment and send
-
- // I now think it is better to put data in a normal input window
- // even if there is a display form so user can view it before submission
-
- WebMailInfo * WebMail = Session->WebMail;
-
- char * info = strstr(input, "\r\n\r\n"); // To end of HTML header
-
- // look through header for Content-Type line, and if multipart
- // find boundary string.
-
- char * ptr, * saveptr, * ptr1, * ptr2, * inptr;
- char Boundary[1000];
- BOOL Multipart = FALSE;
- int Partlen;
- char ** Body = &info;
- int i;
- char * Keys[1000];
- char * Values[1000];
- char * saveForfree[1000];
-
- int NumKeys = 0;
- char * varptr;
- char * endptr;
- int varlen, vallen = 0;
- char *crcrptr;
-
- if (WebMail->txtFile == NULL)
- {
- // No template, so user must have used back button
-
- *RLen = sprintf(Reply, "", Session->Key);
- return;
- }
-
- ptr = input;
-
- 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;
-
-
- 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; // Can't do anything without a boundary ??
- }
-
- }
-
- ptr = ptr2;
- ptr++;
-
- }
-
- if (info == NULL)
- return; // Wot!
-
- // Extract the Key/Value pairs from input data
-
- saveptr = ptr = WebFindPart(Body, Boundary, &Partlen, input + InputLen);
-
- if (ptr == NULL)
- return; // Couldn't find separator
-
- // Now extract fields
-
- while (ptr)
- {
- char * endptr;
- char * val;
-// Debugprintf(ptr);
-
- // Format seems to be
-
- //Content-Disposition: form-data; name="FieldName"
- // crlf crlf
- // field value
- // crlf crlf
-
- // No, is actually
-
- // ------WebKitFormBoundary7XHZ1i7Jc8tOZJbw
- // Content-Disposition: form-data; name="State"
- //
- // UK
- // ------WebKitFormBoundary7XHZ1i7Jc8tOZJbw
-
- // ie Value is terminated by ------WebKitFormBoundary7XHZ1i7Jc8tOZJbw
- // But FindPart has returned length, so can use that
- // Be aware that Part and PartLen include the CRLF which is actually part of the Boundary string so should be removed.
-
-
- ptr = strstr(ptr, "name=");
-
- if (ptr)
- {
- endptr = strstr(ptr, "\"\r\n\r\n"); // "/r/n/r/n
- if (endptr)
- {
- *endptr = 0;
- ptr += 6; // to start of name string
- val = endptr + 5;
-
- // val was Null Terminated by FindPart so can just use it. This assumes all fields are text,
- // which I think is safe enough here.
-
- saveptr[Partlen - 2] = 0;
-
- // Now have key value pair
-
- Keys[NumKeys] = ptr;
- Values[NumKeys] = val;
- saveForfree[NumKeys++] = saveptr; // so we can free() when finished with it
- }
- else
- free(saveptr);
- }
- else
- free(saveptr);
-
- saveptr = ptr = WebFindPart(Body, Boundary, &Partlen, input + InputLen);
- }
-
- if (info == NULL)
- return; // Wot!
-
- info += 4;
-
- // It looks like some standard variables can be used in User->Call;
- Keys[NumKeys] = "MsgSubject";
- Values[NumKeys++] = "";
- Keys[NumKeys] = "MsgBody";
-// if (WebMail->OrigBody)
-// txtKey++->Value = _strdup(WebMail->OrigBody);
-// else
- Values[NumKeys++] = "";
-
- Keys[NumKeys] = _strdup("MsgP2P");
- Values[NumKeys++] = _strdup("");
-
- Keys[NumKeys] = _strdup("MsgIsReply");
- if (WebMail->isReply)
- Values[NumKeys++] = "True";
- else
- Values[NumKeys++] = "True";
-
- Keys[NumKeys] = "MsgIsForward";
- Values[NumKeys++] = "False";
- Keys[NumKeys] = "MsgIsAcknowledgement";
- Values[NumKeys++] = "False";
-
-
- // Update Template with variables from the form
-
- // I've going to update the template in situ, as I can't see a better way
- // of making sure all occurances of variables in any order are substituted.
- // The space allocated to Template is twice the size of the file
- // to allow for insertions
-
- inptr = WebMail->txtFile;
-
- // Search for "" strings in form and replace with
- // corresponding variable
-
- // we run through the Template once for each variable
-
- i = 0;
-
- while (i < NumKeys)
- {
- char Key[256];
-
- sprintf(Key, "", Keys[i]);
-
- inptr = WebMail->txtFile;
- varptr = stristr(inptr, Key);
-
- while (varptr)
- {
- // Move the remaining message up/down the buffer to make space for substitution
-
- varlen = (int)strlen(Key);
- vallen = (int)strlen(Values[i]);
-
- endptr = varptr + varlen;
-
- memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
- memcpy(varptr, Values[i], vallen);
-
- inptr = endptr + 1;
-
- varptr = stristr(inptr, Key);
- }
- i++;
- }
-
- // We need to look for To:, CC: and Subject lines, and remove any other
- // Var: lines. Use everything following Msg: as the plain text body
-
- // Find start of Message body
-
- ptr = WebMail->txtFile;
-
- ptr1 = strchr(ptr, '\r');
-
- while (ptr1)
- {
- if (_memicmp(ptr, "Msg:", 4) == 0)
- {
- // Rest is message body. substitutions have been done
-
- if (WebMail->Body)
- free(WebMail->Body);
-
- WebMail->Body = _strdup(ptr + 4); // Remove Msg:
- break;
- }
-
- // Can now terminate lines
-
- *ptr1++ = 0;
-
- while (*ptr1 == '\r' || *ptr1 == '\n')
- *ptr1++ = 0;
-
- if (_memicmp(ptr, "To:", 3) == 0)
- {
- if (strlen(ptr) > 5)
- WebMail->To = _strdup(&ptr[3]);
- }
- else if (_memicmp(ptr, "CC:", 3) == 0)
- {
- if (strlen(ptr) > 5)
- WebMail->CC = _strdup(&ptr[3]);
- }
- else if (_memicmp(ptr, "Subj:", 5) == 0)
- {
- if (ptr[5] == ' ') // May have space after :
- ptr++;
- if (strlen(ptr) > 6)
- WebMail->Subject = _strdup(&ptr[5]);
- }
-
- else if (_memicmp(ptr, "Subject:", 8) == 0)
- {
- if (ptr[8] == ' ')
- ptr++;
- if (strlen(ptr) > 9)
- WebMail->Subject = _strdup(&ptr[8]);
- }
- ptr = ptr1;
- ptr1 = strchr(ptr, '\r');
- }
-
- if (WebMail->Subject == NULL)
- WebMail->Subject = _strdup("");
-
- if (WebMail->To == NULL)
- WebMail->To = _strdup("");
-
- if (WebMail->CC == NULL)
- WebMail->CC = _strdup("");
-
- // Replace var in Subject
-
- if (_memicmp(WebMail->Subject, "Subject = realloc(WebMail->Subject, 512); // Plenty of space
- i = 0;
-
- while (i < NumKeys)
- {
- char Key[256];
-
- sprintf(Key, "", Keys[i]);
-
- inptr = WebMail->Subject;
- varptr = stristr(inptr, Key);
-
- while (varptr)
- {
- // Move the remaining message up/down the buffer to make space for substitution
-
- varlen = (int)strlen(Key);
- vallen = (int)strlen(Values[i]);
-
- endptr = varptr + varlen;
-
- memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
- memcpy(varptr, Values[i], vallen);
-
- inptr = endptr + 1;
-
- varptr = stristr(inptr, Key);
- }
- i++;
- }
- }
-
-
-
- // Build XML Attachment if Display Form is defined
-
- if (WebMail->DisplayHTMLName)
- BuildXMLAttachment(Session, Keys, Values, NumKeys);
-
- // if Reply, attach original message to Body;
-
- if (WebMail->isReply && WebMail->OrigBody)
- {
- char * NewBody = malloc(strlen(WebMail->Body) + strlen(WebMail->OrigBody) + 100);
- sprintf(NewBody, "%s\r\n%s", WebMail->Body, WebMail->OrigBody);
- free(WebMail->Body);
- WebMail->Body = NewBody;
- }
-
- // Display Message for user to check and send
-
- // fix any cr cr lf sequence
-
- crcrptr = strstr(WebMail->Body, "\r\r");
-
- while (crcrptr)
- {
- *crcrptr = ' ';
- crcrptr = strstr(crcrptr, "\r\r");
- }
-
- if (WebMail->BID == NULL)
- WebMail->BID = _strdup("");
-
- *RLen = sprintf(Reply, CheckFormMsgPage, Session->Key, WebMail->To, WebMail->CC, WebMail->Subject, "Selected", "", "", WebMail->BID, WebMail->Body);
-
- // Free the part strings
-
- i = 0;
-
- while (saveForfree[i])
- free(saveForfree[i++]);
-}
-
-// XML Template Stuff
-
-char XMLHeader [] =
- "\r\n"
- "\r\n"
- " \r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " \r\n"
- "\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n"
- " %s\r\n";
-
-
-char XMLLine[] = " <%s>%s%s>\r\n";
-
-char XMLTrailer[] = "\r\n\r\n";
-
-char * doXMLTransparency(char * string)
-{
- // Make sure string doesn't contain forbidden XML chars (<>"'&)
-
- char * newstring = malloc(5 * strlen(string) + 1); // If len is zero still need null terminator
-
- char * in = string;
- char * out = newstring;
- char c;
-
- c = *(in++);
-
- while (c)
- {
- switch (c)
- {
- case '<':
-
- strcpy(out, "<");
- out += 4;
- break;
-
- case '>':
-
- strcpy(out, ">");
- out += 4;
- break;
-
- case '"':
-
- strcpy(out, """);
- out += 6;
- break;
-
- case '\'':
-
- strcpy(out, "'");
- out += 6;
- break;
-
- case '&':
-
- strcpy(out, "&");
- out += 5;
- break;
-
- default:
-
- *(out++) = c;
- }
- c = *(in++);
- }
-
- *(out++) = 0;
- return newstring;
-}
-
-
-VOID BuildXMLAttachment(struct HTTPConnectionInfo * Session, char * Keys[1000], char * Values[1000], int NumKeys)
-{
- // Create XML Attachment for form
-
- WebMailInfo * WebMail = Session->WebMail;
- char XMLName[MAX_PATH];
- char * XMLPtr;
- char DateString[80];
- struct tm * tm;
- time_t NOW = time(NULL);
-
- int n;
- int TotalFileSize = 0;
-
- tm = gmtime(&NOW);
-
- sprintf(DateString, "%04d%02d%02d%02d%02d%02d",
- tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
-
- strcpy(XMLName, WebMail->DisplayHTMLName);
- XMLName[strlen(XMLName) - 5] = 0; // remove .html
-
- WebMail->XMLName = malloc(MAX_PATH);
- WebMail->XML = XMLPtr = malloc(100000);
- WebMail->XMLLen = 0;
-
- sprintf(WebMail->XMLName, "RMS_Express_Form_%s.xml", XMLName);
-
- XMLPtr += sprintf(XMLPtr, XMLHeader,
- "1,0", VersionString,
- DateString,
- Session->User->Call,
- "", //Grid
- WebMail->DisplayHTMLName,
- WebMail->ReplyHTMLName,
- WebMail->To,
- WebMail->CC,
- Session->User->Call,
- WebMail->OrigSubject,
- "", // WebMail->OrigBody,
- "False", // P2P
- WebMail->isReply ? "True": "False",
- "False", // Forward,
- "False"); // Ack
-
- // create XML lines for Key/Value Pairs
-
- for (n = 0; n < NumKeys; n++)
- {
- if (Values[n] == NULL)
- Values[n] = _strdup("");
-
- XMLPtr += sprintf(XMLPtr, XMLLine, Keys[n], Values[n], Keys[n]);
- }
- if (WebMail->isReply)
- {
- if (WebMail->OrigBody)
- {
- char * goodXML = doXMLTransparency(WebMail->OrigBody);
- XMLPtr += sprintf(XMLPtr, XMLLine, "MsgOriginalBody", goodXML, "MsgOriginalBody");
- }
- else
- XMLPtr += sprintf(XMLPtr, XMLLine, "MsgOriginalBody", "", "MsgOriginalBody");
- }
-
- XMLPtr += sprintf(XMLPtr, "%s", XMLTrailer);
- WebMail->XMLLen = (int)(XMLPtr - WebMail->XML);
-}
-
-char * BuildFormMessage(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * Keys[1000], char * Values[1000], int NumKeys)
-{
-
- // Create B2 message with template body and xml attachment
-
- char * NewMsg = malloc(100000);
- char * SaveMsg = NewMsg;
- char * XMLPtr;
-
- char DateString[80];
- struct tm * tm;
-
- char * FileName[100];
- int FileLen[100];
- char * FileBody[100];
- int n, Files = 0;
- int TotalFileSize = 0;
- char Type[16] = "Private";
-
- WebMailInfo * WebMail = Session->WebMail;
-
- // Create a B2 Message
-
- tm = gmtime((time_t *)&Msg->datecreated);
-
- sprintf(DateString, "%04d%02d%02d%02d%02d%02d",
- tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
-
- if (WebMail->DisplayHTMLName)
- {
- char XMLName[MAX_PATH];
-
- strcpy(XMLName, WebMail->DisplayHTMLName);
-
- XMLName[strlen(XMLName) - 5] = 0; // remove .html
-
- FileName[0] = malloc(MAX_PATH);
- FileBody[0] = malloc(100000);
- Files = 1;
- FileLen[0] = 0;
-
- sprintf(FileName[0], "RMS_Express_Form_%s.xml", XMLName);
-
- XMLPtr = FileBody[0];
-
- XMLPtr += sprintf(XMLPtr, XMLHeader,
- "1,0", VersionString,
- DateString,
- Session->User->Call,
- "", //Grid
- WebMail->DisplayHTMLName,
- WebMail->ReplyHTMLName,
- WebMail->OrigTo,
- "", // CC
- Session->User->Call,
- WebMail->OrigSubject,
- WebMail->OrigBody,
- "false", // P2P,
- "false", //Reply
- "false", //Forward,
- "false"); // Ack
-
- // create XML lines for Key/Value Pairs
-
- for (n = 0; n < NumKeys; n++)
- {
- if (Values[n] == NULL)
- Values[n] = _strdup("");
-
- XMLPtr += sprintf(XMLPtr, XMLLine, Keys[n], Values[n], Keys[n]);
- }
- XMLPtr += sprintf(XMLPtr, "%s", XMLTrailer);
-
- FileLen[0] = (int)(XMLPtr - FileBody[0]);
-
- }
-
- sprintf(DateString, "%04d/%02d/%02d %02d:%02d",
- tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
-
-
- // Get Type
-
- if (Msg->type == 'B')
- strcpy(Type, "Bulletin");
- else if (Msg->type == 'T')
- strcpy(Type, "NTS");
-
- // We put original To call in B2 Header
-
- 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, WebMail->To, Msg->title, BBSName);
-
-
- NewMsg += sprintf(NewMsg, "Body: %d\r\n", (int)strlen(WebMail->Body));
-
- 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");
- strcpy(NewMsg, WebMail->Body);
- NewMsg += strlen(WebMail->Body);
- NewMsg += sprintf(NewMsg, "\r\n");
-
- for (n = 0; n < Files; n++)
- {
- memcpy(NewMsg, FileBody[n], FileLen[n]);
- NewMsg += FileLen[n];
- free(FileName[n]);
- free(FileBody[n]);
- NewMsg += sprintf(NewMsg, "\r\n");
- }
-
- Msg->length = (int)strlen(SaveMsg);
- Msg->B2Flags = B2Msg;
-
- if (Files)
- Msg->B2Flags |= Attachments;
-
- if (WebMail->Body)
- free(WebMail->Body);
-
- WebMail->Body = SaveMsg;
-
- return NULL;
-}
-
-VOID UpdateFormAction(char * Template, char * Key)
-{
- char * inptr, * saveptr;
- char * varptr, * endptr;
- size_t varlen, vallen;
- char Submit[64];
-
- sprintf(Submit, "/Webmail/Submit?%s", Key);
-
- // First find the Form Action string and replace with our URL. It should have
- // action="http://{FormServer}:{FormPort}" but some forms have localhost:8001 instead
-
- // Also remove the OnSubmit if it contains the standard popup about having to close browser
-
- inptr = Template;
- saveptr = varptr = stristr(inptr, "