|
|
|
|
|
// Version 2.0.1 November 2007
|
|
|
|
|
|
// Change resizing algorith
|
|
|
|
|
|
|
|
|
// Version 2.0.2 January 2008
|
|
|
|
|
|
// Restore Checked state of Bells and AutoConnect Flags
|
|
|
// Call CheckTimer on startup (for new Initialisation Scheme for perl)
|
|
|
|
|
|
// Version 2.0.3 July 2008
|
|
|
|
|
|
// Display lines received without a terminaing CR
|
|
|
|
|
|
|
|
|
// Version 2.0.4 November 2008
|
|
|
|
|
|
// Add option to remove a Line Feed following a CR
|
|
|
// Add Logging Option
|
|
|
|
|
|
// Version 2.0.5 January 2009
|
|
|
|
|
|
// Add Start Minimized Option
|
|
|
|
|
|
// Version 2.0.6 June 2009
|
|
|
|
|
|
// Add Option to send *** Disconnnected on disconnect
|
|
|
// Add line wrap code
|
|
|
// Add option not to monitor NODES broadcasts
|
|
|
|
|
|
// Version 2.0.7 October 2009
|
|
|
|
|
|
// Add input buffer scrollback.
|
|
|
// Fix monitoring when PORTNUM specified
|
|
|
|
|
|
// Version 2.0.8 December 2009
|
|
|
|
|
|
// Fix use of numeric keypad 2 and 8 (were treated as up and down)
|
|
|
|
|
|
// Version 2.0.9 March 2010
|
|
|
|
|
|
// Add colour for monitor and BPQ Chat
|
|
|
|
|
|
// Version 2.0.0 October 2010
|
|
|
|
|
|
// Add Chat Terminal Mode (sends keepalives)
|
|
|
|
|
|
// Version 1.0.4.1 June 2012
|
|
|
|
|
|
// Add UIOnly Monitor Option
|
|
|
|
|
|
// Version 1.0.5.1 November 2012
|
|
|
|
|
|
// Allow up to 8 hosts
|
|
|
|
|
|
// Version 1.0.6.1 MY 2013
|
|
|
|
|
|
// Send Connect Failed prompt after setting terminal status
|
|
|
|
|
|
// Version 1.0.7.1 Aug 2013
|
|
|
|
|
|
// Allow 16 hosts
|
|
|
// Save host setup when changed instead of on exit
|
|
|
|
|
|
|
|
|
// Version 1.0.8.1 ...
|
|
|
|
|
|
// Operates in UTF-8
|
|
|
|
|
|
// Version 1.0.9.1 Aug 2014
|
|
|
|
|
|
// Add "alert on text" option
|
|
|
|
|
|
// Version 1.0.10.1 Nov 2014
|
|
|
// Fix possible crash on processing part line
|
|
|
|
|
|
// Version 1.0.11.1 Feb 2015
|
|
|
// Add "Alert after interval" feature
|
|
|
// Fix "Copy to Clipboard"
|
|
|
|
|
|
// Version 1.0.12.1 Nov 2015
|
|
|
// Add Port Names to Monitor Config and fix saving monitor option s by host
|
|
|
|
|
|
|
|
|
// Version 1.0.13.1 Sept 2016
|
|
|
|
|
|
// Fix buffer overrun introduced in 1.0.12.1
|
|
|
// Fix saving Alert and Keyword filenames
|
|
|
|
|
|
// Version 1.0.14.1 July 2017
|
|
|
|
|
|
// Add popup if keywords file can't be found
|
|
|
|
|
|
// Version 1.0.15.1 Feb 2018
|
|
|
|
|
|
// Allow use of IPV6 even if host resolves to both V4 and V6 addresses (add IPV6: on front of hostname)
|
|
|
// Add Listen Mode
|
|
|
// Only send UTF-8 option if send in UTF-8 is set
|
|
|
// Drop received Keepalive packets
|
|
|
|
|
|
// Version 1.0.16.1 ??
|
|
|
|
|
|
// Add YAPP File Transfer
|
|
|
|
|
|
// Version 1.0.16.2 August 20203
|
|
|
|
|
|
// Support Monitoring 63 ports
|
|
|
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
|
|
#include "winsock2.h"
|
|
|
#include "WS2tcpip.h"
|
|
|
#include <windows.h>
|
|
|
#include <winstdint.h>
|
|
|
#include <winuser.h>
|
|
|
#include <time.h>
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
#include <stdio.h>
|
|
|
#include <malloc.h>
|
|
|
#include <memory.h>
|
|
|
#include <sys/types.h>
|
|
|
#include <wchar.h>
|
|
|
#include <sys/stat.h>
|
|
|
//#define _RICHEDIT_VER 0x0100
|
|
|
#include <Richedit.h>
|
|
|
#define IDC_STATIC -1
|
|
|
#include "bpqtermTCP.h"
|
|
|
#define TermTCP
|
|
|
#include "Versions.h"
|
|
|
#include "GetVersion.h"
|
|
|
#include "Shlobj.h"
|
|
|
|
|
|
#define BPQICON 2
|
|
|
|
|
|
#define BGCOLOUR RGB(236,233,216)
|
|
|
|
|
|
#define WSA_ACCEPT WM_USER + 1
|
|
|
#define WSA_CONNECT WM_USER + 2
|
|
|
#define WSA_DATA WM_USER + 3
|
|
|
|
|
|
#define BPQBASE 1100
|
|
|
|
|
|
HBRUSH bgBrush;
|
|
|
|
|
|
HINSTANCE hInst;
|
|
|
TCHAR AppName[] = L"BPQTerm 32";
|
|
|
TCHAR ClassName[] = L"BPQMAINWINDOW";
|
|
|
TCHAR Title[80];
|
|
|
|
|
|
BOOL WINE;
|
|
|
|
|
|
BOOL UseKeywords = TRUE;
|
|
|
|
|
|
TCHAR KeyWordsName[MAX_PATH] = L"Keywords.sys";
|
|
|
char ** KeyWords = NULL;
|
|
|
int NumberofKeyWords = 0;
|
|
|
|
|
|
// YAPP stuff
|
|
|
|
|
|
#define SOH 1
|
|
|
#define STX 2
|
|
|
#define ETX 3
|
|
|
#define EOT 4
|
|
|
#define ENQ 5
|
|
|
#define ACK 6
|
|
|
#define DLE 0x10
|
|
|
#define NAK 0x15
|
|
|
#define CAN 0x18
|
|
|
|
|
|
|
|
|
UCHAR InputMode; // Normal or YAPP
|
|
|
WCHAR YAPPPath[MAX_PATH] = L""; // Path for saving YAPP Files
|
|
|
|
|
|
// Foward declarations of functions included in this code module:
|
|
|
|
|
|
ATOM MyRegisterClass(CONST WNDCLASS*);
|
|
|
BOOL InitApplication(HINSTANCE);
|
|
|
BOOL InitInstance(HINSTANCE, int);
|
|
|
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
|
|
|
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
|
|
|
int NewLine();
|
|
|
VOID DoRefresh(struct RTFTerm * OPData);
|
|
|
VOID SendTraceOptions();
|
|
|
int ProcessBuff(char * readbuff,int len);
|
|
|
VOID EnableConnectMenu(HWND hWnd);
|
|
|
VOID EnableDisconnectMenu(HWND hWnd);
|
|
|
VOID DisableConnectMenu(HWND hWnd);
|
|
|
VOID DisableDisconnectMenu(HWND hWnd);
|
|
|
VOID DisableYAPPMenu(HWND hWnd);
|
|
|
VOID EnableYAPPMenu(HWND hWnd);
|
|
|
|
|
|
int DoReceivedData(HWND hWnd);
|
|
|
int DoStateChange(HWND hWnd);
|
|
|
int ToggleFlags(HWND hWnd, int Item, int mask);
|
|
|
int DoMonData(HWND hWnd);
|
|
|
int TogglePort(HWND hWnd, int Item, int mask);
|
|
|
int ToggleMTX(HWND hWnd);
|
|
|
int ToggleMCOM(HWND hWnd);
|
|
|
int ToggleMUI(HWND hWnd);
|
|
|
int ToggleParam(HWND hWnd, BOOL * Param, int Item);
|
|
|
int ToggleChat(HWND hWnd);
|
|
|
void MoveWindows();
|
|
|
void CopyListToClipboard(HWND hWnd);
|
|
|
void CopyRichTextToClipboard(HWND hWnd);
|
|
|
BOOL OpenMonitorLogfile();
|
|
|
void WriteMonitorLine(TCHAR * Msg, int MsgLen);
|
|
|
VOID WritetoOutputWindow(struct RTFTerm * OPData, TCHAR * Msg, int len);
|
|
|
int SendMsg(TCHAR * msg, int len);
|
|
|
TCPConnect(TCHAR * Host, int Port);
|
|
|
int Telnet_Connected(SOCKET sock, int Error);
|
|
|
VOID DataSocket_Read(SOCKET sock);
|
|
|
VOID Socket_Data(int sock, int error, int eventcode);
|
|
|
VOID Socket_Accept(int sock, int error, int eventcode);
|
|
|
SOCKET OpenListenSocket4(int port);
|
|
|
void YAPPSendFile(WCHAR * filename);
|
|
|
void QueueMsg(UCHAR * Msg, int Len);
|
|
|
BOOL ProcessYAPPMessage(UCHAR * Msg, int Len);
|
|
|
|
|
|
COLORREF Colours[256] = {0,
|
|
|
RGB(0,0,0), RGB(0,0,128), RGB(0,0,192), RGB(0,0,255), // 1 - 4
|
|
|
RGB(0,64,0), RGB(0,64,128), RGB(0,64,192), RGB(0,64,255), // 5 - 8
|
|
|
RGB(0,128,0), RGB(0,128,128), RGB(0,128,192), RGB(0,128,255), // 9 - 12
|
|
|
RGB(0,192,0), RGB(0,192,128), RGB(0,192,192), RGB(0,192,255), // 13 - 16
|
|
|
RGB(0,255,0), RGB(0,255,128), RGB(0,255,192), RGB(0,255,255), // 17 - 20
|
|
|
|
|
|
RGB(64,0,0), RGB(64,0,128), RGB(64,0,192), RGB(0,0,255), // 21
|
|
|
RGB(64,64,0), RGB(64,64,128), RGB(64,64,192), RGB(64,64,255),
|
|
|
RGB(64,128,0), RGB(64,128,128), RGB(64,128,192), RGB(64,128,255),
|
|
|
RGB(64,192,0), RGB(64,192,128), RGB(64,192,192), RGB(64,192,255),
|
|
|
RGB(64,255,0), RGB(64,255,128), RGB(64,255,192), RGB(64,255,255),
|
|
|
|
|
|
RGB(128,0,0), RGB(128,0,128), RGB(128,0,192), RGB(128,0,255), // 41
|
|
|
RGB(128,64,0), RGB(128,64,128), RGB(128,64,192), RGB(128,64,255),
|
|
|
RGB(128,128,0), RGB(128,128,128), RGB(128,128,192), RGB(128,128,255),
|
|
|
RGB(128,192,0), RGB(128,192,128), RGB(128,192,192), RGB(128,192,255),
|
|
|
RGB(128,255,0), RGB(128,255,128), RGB(128,255,192), RGB(128,255,255),
|
|
|
|
|
|
RGB(192,0,0), RGB(192,0,128), RGB(192,0,192), RGB(192,0,255), // 61
|
|
|
RGB(192,64,0), RGB(192,64,128), RGB(192,64,192), RGB(192,64,255),
|
|
|
RGB(192,128,0), RGB(192,128,128), RGB(192,128,192), RGB(192,128,255),
|
|
|
RGB(192,192,0), RGB(192,192,128), RGB(192,192,192), RGB(192,192,255),
|
|
|
RGB(192,255,0), RGB(192,255,128), RGB(192,255,192), RGB(192,2552,255),
|
|
|
|
|
|
RGB(255,0,0), RGB(255,0,128), RGB(255,0,192), RGB(255,0,255), // 81
|
|
|
RGB(255,64,0), RGB(255,64,128), RGB(255,64,192), RGB(255,64,255),
|
|
|
RGB(255,128,0), RGB(255,128,128), RGB(255,128,192), RGB(255,128,255),
|
|
|
RGB(255,192,0), RGB(255,192,128), RGB(255,192,192), RGB(255,192,255),
|
|
|
RGB(255,255,0), RGB(255,255,128), RGB(255,255,192), RGB(255,2552,255)
|
|
|
};
|
|
|
|
|
|
LRESULT APIENTRY InputProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ;
|
|
|
//LRESULT APIENTRY OutputProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ;
|
|
|
LRESULT APIENTRY MonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ;
|
|
|
LRESULT APIENTRY SplitProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) ;
|
|
|
|
|
|
|
|
|
LONG_PTR wpOrigInputProc;
|
|
|
//WNDPROC wpOrigOutputProc;
|
|
|
LONG_PTR wpOrigMonProc;
|
|
|
LONG_PTR wpOrigSplitProc;
|
|
|
|
|
|
HWND hwndInput;
|
|
|
HWND hwndOutput;
|
|
|
HWND hwndMon;
|
|
|
HWND hwndSplit;
|
|
|
|
|
|
HMENU trayMenu;
|
|
|
|
|
|
#define AUTO -1
|
|
|
#define CP437 437
|
|
|
#define CP1251 1251
|
|
|
#define CP1252 1252
|
|
|
|
|
|
int RXMode = AUTO;
|
|
|
int TXMode = CP_UTF8;
|
|
|
|
|
|
int xsize,ysize; // Screen size at startup
|
|
|
|
|
|
double Split=0.5;
|
|
|
int SplitPos=300;
|
|
|
#define SplitBarHeight 5
|
|
|
#define InputBoxHeight 25
|
|
|
RECT Rect;
|
|
|
RECT MonRect;
|
|
|
//RECT OutputRect;
|
|
|
RECT SplitRect;
|
|
|
|
|
|
int OutputBoxHeight;
|
|
|
|
|
|
int Height, Width, LastY;
|
|
|
|
|
|
int maxlinelen = 80;
|
|
|
|
|
|
#define MAXHOSTS 16
|
|
|
|
|
|
TCHAR Host[MAXHOSTS + 1][100] = {L"localhost"};
|
|
|
int Port[MAXHOSTS + 1] = {0};
|
|
|
TCHAR UserName[MAXHOSTS + 1][80] = {L""};
|
|
|
TCHAR Password[MAXHOSTS + 1][80] = {L""};
|
|
|
TCHAR MonParams[MAXHOSTS + 1][80] = {L""};
|
|
|
int ListenPort = 8015;
|
|
|
|
|
|
TCHAR HN[MAXHOSTS + 1][7] = {L"Host1", L"Host2", L"Host3", L"Host4", L"Host5", L"Host6", L"Host7", L"Host8",
|
|
|
L"Host9", L"Host10", L"Host11", L"Host12", L"Host13", L"Host14", L"Host15", L"Host16"};
|
|
|
TCHAR PN[MAXHOSTS + 1][7] = {L"Port1", L"Port2", L"Port3", L"Port4", L"Port5", L"Port6", L"Port7", L"Port8",
|
|
|
L"Port9", L"Port10", L"Port11", L"Port12", L"Port13", L"Port14", L"Port15", L"Port16"};
|
|
|
TCHAR UN[MAXHOSTS + 1][7] = {L"User1", L"User2", L"User3", L"User4", L"User5", L"User6", L"User7", L"User8",
|
|
|
L"User9", L"User10", L"User11", L"User12", L"User13", L"User14", L"User15", L"User16"};
|
|
|
TCHAR MON[MAXHOSTS + 1][7] = {L"MON1", L"MON2", L"MON3", L"MON4", L"MON5", L"MON6", L"MON7", L"MON8",
|
|
|
L"MON9", L"MON10", L"MON11", L"MON12", L"MON13", L"MON14", L"MON15", L"MON16"};
|
|
|
TCHAR PASSN[MAXHOSTS + 1][7] = {L"Pass1", L"Pass2", L"Pass3", L"Pass4", L"Pass5", L"Pass6", L"Pass7", L"Pass8",
|
|
|
L"Pass9", L"Pass10", L"Pass11", L"Pass12", L"Pass13", L"Pass14", L"Pass15", L"Pass16"};
|
|
|
|
|
|
|
|
|
#define MAXLINES 1000
|
|
|
#define LINELEN 200
|
|
|
|
|
|
char RTFHeader[4000];
|
|
|
|
|
|
int RTFHddrLen;
|
|
|
|
|
|
typedef struct RTFTerm
|
|
|
{
|
|
|
int CurrentLine; // Line we are writing to in circular buffer.
|
|
|
|
|
|
int Index;
|
|
|
BOOL SendHeader;
|
|
|
BOOL Finished;
|
|
|
|
|
|
TCHAR OutputScreen[MAXLINES][LINELEN];
|
|
|
|
|
|
int Colourvalue[MAXLINES];
|
|
|
int LineLen[MAXLINES];
|
|
|
int CharWidth;
|
|
|
int CurrentColour;
|
|
|
int Thumb;
|
|
|
int FirstTime;
|
|
|
int RTFHeight; // Height of RTF control in pixels
|
|
|
BOOL Scrolled; // Window is scrolled back
|
|
|
|
|
|
};
|
|
|
|
|
|
TCHAR FontName[100] = L"Courier New";
|
|
|
int FontSize = 20;
|
|
|
int FontWidth = 8;
|
|
|
int CodePage = 437;
|
|
|
int CharSet = 0;
|
|
|
|
|
|
|
|
|
struct RTFTerm OutputData;
|
|
|
|
|
|
int CurrentHost = 0;
|
|
|
int CfgNo = 0;
|
|
|
|
|
|
SOCKET sock = 0;
|
|
|
SOCKET ListenSock = 0;
|
|
|
|
|
|
BOOL MonData = FALSE;
|
|
|
|
|
|
TCHAR Key[80];
|
|
|
uint64_t portmask=0;
|
|
|
int mtxparam=1;
|
|
|
int mcomparam=1;
|
|
|
int monUI=0;
|
|
|
|
|
|
TCHAR kbbuf[250];
|
|
|
int kbptr=0;
|
|
|
TCHAR readbuff[100000]; // for stupid bbs programs
|
|
|
|
|
|
//int ptr=0;
|
|
|
|
|
|
int Stream;
|
|
|
int len,count;
|
|
|
|
|
|
TCHAR callsign[10];
|
|
|
int state;
|
|
|
int change;
|
|
|
|
|
|
int PartLinePtr=0;
|
|
|
int PartLineIndex=0; // Listbox index of (last) incomplete line
|
|
|
|
|
|
BOOL Bells = FALSE;
|
|
|
BOOL StripLF = FALSE;
|
|
|
BOOL LogMonitor = FALSE;
|
|
|
BOOL LogOutput = FALSE;
|
|
|
BOOL SendDisconnected = TRUE;
|
|
|
BOOL MonitorNODES = TRUE;
|
|
|
BOOL MonitorColour = TRUE;
|
|
|
BOOL ChatMode = FALSE;
|
|
|
int MonPorts = 1;
|
|
|
BOOL ListenOn = FALSE;
|
|
|
|
|
|
time_t LastWrite = 0xffffffff;
|
|
|
int AlertInterval = 300;
|
|
|
BOOL AlertBeep = TRUE;
|
|
|
int AlertFreq = 600;
|
|
|
int AlertDuration = 250;
|
|
|
TCHAR AlertFileName[MAX_PATH] = {0};
|
|
|
|
|
|
HANDLE MonHandle=INVALID_HANDLE_VALUE;
|
|
|
|
|
|
HCURSOR DragCursor;
|
|
|
HCURSOR Cursor;
|
|
|
|
|
|
BOOL MinimizetoTray=FALSE;
|
|
|
//BOOL StartMinimized = FALSE;
|
|
|
|
|
|
HWND MainWnd, hWnd;
|
|
|
|
|
|
BOOL SocketActive = FALSE;
|
|
|
BOOL Connecting = FALSE;
|
|
|
BOOL Connected = FALSE;
|
|
|
BOOL Disconnecting = FALSE;
|
|
|
|
|
|
VOID CALLBACK TimerProc(HWND hwnd,UINT uMsg,UINT idEvent,DWORD dwTime );
|
|
|
|
|
|
TIMERPROC lpTimerFunc = (TIMERPROC) TimerProc;
|
|
|
|
|
|
int TimerHandle = 0;
|
|
|
|
|
|
int SlowTimer;
|
|
|
|
|
|
VOID __cdecl Debugprintf(const char * format, ...)
|
|
|
{
|
|
|
char Mess[1000];
|
|
|
va_list(arglist);int Len;
|
|
|
|
|
|
va_start(arglist, format);
|
|
|
Len = vsprintf_s(Mess, sizeof(Mess), format, arglist);
|
|
|
strcat(Mess, "\r\n");
|
|
|
OutputDebugStringA(Mess);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
VOID SaveIntValue(TCHAR * Key, int Value)
|
|
|
{
|
|
|
TCHAR Val[100];
|
|
|
|
|
|
wsprintf(Val, L"%d", Value);
|
|
|
WritePrivateProfileString(L"Session 1", Key, Val, L".\\BPQTermTCP.ini");
|
|
|
}
|
|
|
|
|
|
VOID SaveStringValue(TCHAR * Key, TCHAR * Value)
|
|
|
{
|
|
|
WritePrivateProfileString(L"Session 1", Key, Value, L".\\BPQTermTCP.ini");
|
|
|
}
|
|
|
|
|
|
int GetIntValue(TCHAR * Key, int Default)
|
|
|
{
|
|
|
return GetPrivateProfileInt(L"Session 1", Key, Default, L".\\BPQTermTCP.ini");
|
|
|
}
|
|
|
|
|
|
VOID GetStringValue(TCHAR * Key, TCHAR * Value, int Len)
|
|
|
{
|
|
|
GetPrivateProfileString(L"Session 1", Key, L"", Value, Len, L".\\BPQTermTCP.ini");
|
|
|
}
|
|
|
|
|
|
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
|
|
|
{
|
|
|
|
|
|
// entered every 10 secs
|
|
|
|
|
|
if (!Connected)
|
|
|
return;
|
|
|
|
|
|
if (!ChatMode)
|
|
|
return;
|
|
|
|
|
|
SlowTimer++;
|
|
|
|
|
|
if (SlowTimer > 50) // About 9 mins
|
|
|
{
|
|
|
SlowTimer = 0;
|
|
|
SendMsg(L"\0", 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
VOID GetKeyWordFile()
|
|
|
{
|
|
|
FILE * Handle;
|
|
|
DWORD FileSize;
|
|
|
char * ptr1, * ptr2;
|
|
|
struct stat STAT;
|
|
|
char * KeyWordFile;
|
|
|
|
|
|
if (_wstat(KeyWordsName, &STAT) == -1)
|
|
|
{
|
|
|
if (UseKeywords)
|
|
|
{
|
|
|
TCHAR Dir[MAX_PATH];
|
|
|
TCHAR Msg[512];
|
|
|
GetCurrentDirectory(MAX_PATH, Dir);
|
|
|
wsprintf(Msg, L"Couldn't find file %s in %s", KeyWordsName, Dir);
|
|
|
MessageBox(NULL, Msg, L"BPQTermTCP", MB_OK);
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
FileSize = STAT.st_size;
|
|
|
|
|
|
Handle = _wfopen(KeyWordsName, L"rb");
|
|
|
|
|
|
if (Handle == NULL)
|
|
|
return;
|
|
|
|
|
|
KeyWordFile = malloc(FileSize+1);
|
|
|
|
|
|
fread(KeyWordFile, 1, FileSize, Handle);
|
|
|
|
|
|
fclose(Handle);
|
|
|
|
|
|
KeyWordFile[FileSize]=0;
|
|
|
|
|
|
_strlwr(KeyWordFile); // Compares are case-insensitive
|
|
|
|
|
|
ptr1 = KeyWordFile;
|
|
|
|
|
|
while (ptr1)
|
|
|
{
|
|
|
if (*ptr1 == '\n') ptr1++;
|
|
|
|
|
|
ptr2 = strtok_s(NULL, "\r\n", &ptr1);
|
|
|
if (ptr2)
|
|
|
{
|
|
|
if (*ptr2 != '#')
|
|
|
{
|
|
|
KeyWords = realloc(KeyWords,(++NumberofKeyWords+1)*4);
|
|
|
KeyWords[NumberofKeyWords] = ptr2;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
BOOL CheckKeyWord(char * Word, char * Msg)
|
|
|
{
|
|
|
char * ptr1 = Msg, * ptr2;
|
|
|
int len = strlen(Word);
|
|
|
|
|
|
while (*ptr1) // Stop at end
|
|
|
{
|
|
|
ptr2 = strstr(ptr1, Word);
|
|
|
|
|
|
if (ptr2 == NULL)
|
|
|
return FALSE; // OK
|
|
|
|
|
|
// Only bad if it ia not part of a longer word
|
|
|
|
|
|
if ((ptr2 == Msg) || !(isalpha(*(ptr2 - 1)))) // No alpha before
|
|
|
if (!(isalpha(*(ptr2 + len)))) // No alpha after
|
|
|
return TRUE; // Bad word
|
|
|
|
|
|
// Keep searching
|
|
|
|
|
|
ptr1 = ptr2 + len;
|
|
|
}
|
|
|
|
|
|
return FALSE; // OK
|
|
|
}
|
|
|
|
|
|
BOOL CheckKeyWords(char * Msg, int len)
|
|
|
{
|
|
|
char dupMsg[2048];
|
|
|
int i;
|
|
|
|
|
|
if (UseKeywords == 0 || NumberofKeyWords == 0)
|
|
|
return FALSE;
|
|
|
|
|
|
memcpy(dupMsg, Msg, len);
|
|
|
dupMsg[len] = 0;
|
|
|
_strlwr(dupMsg);
|
|
|
|
|
|
for (i = 1; i <= NumberofKeyWords; i++)
|
|
|
{
|
|
|
if (CheckKeyWord(KeyWords[i], dupMsg))
|
|
|
{
|
|
|
Beep(660,250);
|
|
|
return TRUE; // Alert
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return FALSE; // OK
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
// FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
|
|
|
//
|
|
|
// PURPOSE: Entry point for the application.
|
|
|
//
|
|
|
// COMMENTS:
|
|
|
//
|
|
|
// This function initializes the application and processes the
|
|
|
// message loop.
|
|
|
//
|
|
|
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, char * lpCmdLine, int nCmdShow)
|
|
|
{
|
|
|
MSG msg;
|
|
|
TCHAR Size[80];
|
|
|
|
|
|
if (_stricmp(lpCmdLine, "Listen") == 0)
|
|
|
ListenOn = TRUE;
|
|
|
|
|
|
if (!InitApplication(hInstance))
|
|
|
return (FALSE);
|
|
|
|
|
|
if (!InitInstance(hInstance, nCmdShow))
|
|
|
return (FALSE);
|
|
|
|
|
|
if (ListenOn == TRUE)
|
|
|
{
|
|
|
DisableConnectMenu(hWnd);
|
|
|
ListenSock = OpenListenSocket4(ListenPort);
|
|
|
}
|
|
|
|
|
|
DisableYAPPMenu(hWnd);
|
|
|
|
|
|
// Main message loop:
|
|
|
while (GetMessage(&msg, NULL, 0, 0))
|
|
|
{
|
|
|
TranslateMessage(&msg);
|
|
|
DispatchMessage(&msg);
|
|
|
}
|
|
|
|
|
|
SaveIntValue(L"PortMask", portmask);
|
|
|
SaveIntValue(L"Bells", Bells);
|
|
|
SaveIntValue(L"StripLF", StripLF);
|
|
|
|
|
|
SaveIntValue(L"MTX",mtxparam);
|
|
|
SaveIntValue(L"MCOM", mcomparam);
|
|
|
SaveIntValue(L"MUIONLY", monUI);
|
|
|
|
|
|
#pragma warning(push)
|
|
|
#pragma warning(disable:4244)
|
|
|
SaveIntValue(L"Split", Split * 100);
|
|
|
#pragma warning(pop)
|
|
|
|
|
|
SaveIntValue(L"MONColour", MonitorColour);
|
|
|
SaveIntValue(L"MonNODES", MonitorNODES);
|
|
|
SaveIntValue(L"MonPorts", MonPorts);
|
|
|
SaveIntValue(L"ChatMode", ChatMode);
|
|
|
SaveIntValue(L"CurrentHost", CurrentHost);
|
|
|
|
|
|
wsprintf(Size,L"%d,%d,%d,%d",Rect.left,Rect.right,Rect.top,Rect.bottom);
|
|
|
SaveStringValue(L"Size", Size);
|
|
|
|
|
|
SaveStringValue(L"FontName", FontName);
|
|
|
SaveIntValue(L"CharSet", CharSet);
|
|
|
SaveIntValue(L"CodePage", CodePage);
|
|
|
SaveIntValue(L"FontSize", FontSize);
|
|
|
SaveIntValue(L"FontWidth", FontWidth);
|
|
|
SaveIntValue(L"AlertInterval", AlertInterval);
|
|
|
|
|
|
KillTimer(NULL, TimerHandle);
|
|
|
|
|
|
return (msg.wParam);
|
|
|
}
|
|
|
|
|
|
//
|
|
|
|
|
|
//
|
|
|
// FUNCTION: InitApplication(HANDLE)
|
|
|
//
|
|
|
// PURPOSE: Initializes window data and registers window class
|
|
|
//
|
|
|
// COMMENTS:
|
|
|
//
|
|
|
// In this function, we initialize a window class by filling out a data
|
|
|
// structure of type WNDCLASS and calling either RegisterClass or
|
|
|
// the internal MyRegisterClass.
|
|
|
//
|
|
|
BOOL InitApplication(HINSTANCE hInstance)
|
|
|
{
|
|
|
WNDCLASS wc;
|
|
|
|
|
|
bgBrush = CreateSolidBrush(BGCOLOUR);
|
|
|
|
|
|
wc.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
wc.lpfnWndProc = WndProc;
|
|
|
|
|
|
wc.cbClsExtra = 0;
|
|
|
wc.cbWndExtra = DLGWINDOWEXTRA;
|
|
|
wc.hInstance = hInstance;
|
|
|
wc.hIcon = LoadIcon( hInstance, MAKEINTRESOURCE(BPQICON));
|
|
|
wc.hCursor = NULL; //LoadCursor(NULL, IDC_ARROW);
|
|
|
wc.hbrBackground = bgBrush;
|
|
|
|
|
|
wc.lpszMenuName = NULL;
|
|
|
wc.lpszClassName = ClassName;
|
|
|
|
|
|
return (RegisterClass(&wc));
|
|
|
|
|
|
}
|
|
|
|
|
|
HMENU hMenu, hPopMenu1, hPopMenu2, hPopMenu3; // handle of menu
|
|
|
|
|
|
VOID SetupRTFHddr()
|
|
|
{
|
|
|
int i, n;
|
|
|
char RTFColours[3000];
|
|
|
char Temp[1000];
|
|
|
|
|
|
// Set up RTF Header, including Colours String;
|
|
|
|
|
|
memcpy(RTFColours, "{\\colortbl ;", 12);
|
|
|
n = 12;
|
|
|
|
|
|
for (i = 1; i < 100; i++)
|
|
|
{
|
|
|
COLORREF Colour = Colours[i];
|
|
|
n += sprintf(&RTFColours[n], "\\red%d\\green%d\\blue%d;", GetRValue(Colour), GetGValue(Colour),GetBValue(Colour));
|
|
|
}
|
|
|
|
|
|
RTFColours[n++] = '}';
|
|
|
RTFColours[n] = 0;
|
|
|
|
|
|
// wcscpy(RTFHeader, "{\\rtf1\\deff0{\\fonttbl{\\f0\\fmodern\\fprq1\\fcharset204 ;}}");
|
|
|
sprintf(RTFHeader, "{\\rtf1\\deff0{\\fonttbl{\\f0\\fprq1\\cpg%d\\fcharset%d %s;}}", CodePage, CharSet, FontName);
|
|
|
sprintf(RTFHeader, "{\\rtf1\\deff0{\\fonttbl{\\f0\\fmodern\\fprq1;}}");
|
|
|
strcat(RTFHeader, RTFColours);
|
|
|
sprintf(Temp, "\\viewkind4\\uc1\\pard\\f0\\fs%d\\uc0", FontSize);
|
|
|
strcat(RTFHeader, Temp);
|
|
|
|
|
|
RTFHddrLen = strlen(RTFHeader);
|
|
|
}
|
|
|
|
|
|
TCHAR VersionStringW[100];
|
|
|
|
|
|
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
|
|
|
{
|
|
|
int i, n, tempmask=0xffff;
|
|
|
TCHAR msg[20];
|
|
|
TCHAR Size[80];
|
|
|
WSADATA WsaData; // receives data from WSAStartup
|
|
|
struct RTFTerm * OPData;
|
|
|
int retCode;
|
|
|
HKEY hKey=0;
|
|
|
|
|
|
hInst = hInstance; // Store instance handle in our global variable
|
|
|
|
|
|
WSAStartup(MAKEWORD(2, 0), &WsaData);
|
|
|
|
|
|
// See if running under WINE
|
|
|
|
|
|
retCode = RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"SOFTWARE\\Wine", 0, KEY_QUERY_VALUE, &hKey);
|
|
|
|
|
|
if (retCode == ERROR_SUCCESS)
|
|
|
{
|
|
|
RegCloseKey(hKey);
|
|
|
WINE =TRUE;
|
|
|
Debugprintf("Running under WINE");
|
|
|
}
|
|
|
// Get saved config from ini
|
|
|
|
|
|
// MonitorNODES = GetIntValue("MonNODES", 0);
|
|
|
MonPorts = GetIntValue(L"MonPorts", 0);
|
|
|
// mtxparam = GetIntValue("MTX", 0);
|
|
|
// mcomparam = GetIntValue("MCOM", 0);
|
|
|
// monUI = GetIntValue("MUIONLY", 0);
|
|
|
tempmask = GetIntValue(L"PortMask", 0);
|
|
|
ChatMode = GetIntValue(L"ChatMode", 0);
|
|
|
MonitorColour = GetIntValue(L"MONColour", 0);
|
|
|
Bells = GetIntValue(L"Bells", 0);
|
|
|
StripLF = GetIntValue(L"StripLF", 0);
|
|
|
CurrentHost = GetIntValue(L"CurrentHost", 0);
|
|
|
Split = GetIntValue(L"Split", 0);
|
|
|
if (Split == 0)
|
|
|
Split = 50;
|
|
|
|
|
|
Split /= 100; // Stored as a %,used as 0 - 1
|
|
|
|
|
|
for (n = 0; n < MAXHOSTS; n++)
|
|
|
{
|
|
|
GetStringValue(HN[n], Host[n], 100);
|
|
|
GetStringValue(UN[n], UserName[n], 80);
|
|
|
GetStringValue(PASSN[n], Password[n], 80);
|
|
|
Port[n] = GetIntValue(PN[n], 0);
|
|
|
GetStringValue(MON[n], MonParams[n], 80);
|
|
|
}
|
|
|
|
|
|
n = swscanf(MonParams[CurrentHost], L"%x %x %x %x %x %x",
|
|
|
&portmask, &mtxparam, &mcomparam, &MonitorNODES, &MonitorColour, &monUI);
|
|
|
|
|
|
|
|
|
// GetStringValue(L"FontName", FontName, 99);
|
|
|
|
|
|
// if (FontName[0] == 0)
|
|
|
// wcscpy(FontName, L"Courier New");
|
|
|
|
|
|
// CharSet = GetIntValue(L"CharSet", 0);
|
|
|
// CodePage = GetIntValue(L"CodePage", 437);
|
|
|
|
|
|
FontSize = GetIntValue(L"FontSize", 20);
|
|
|
FontWidth = GetIntValue(L"FontWidth", 8);
|
|
|
RXMode = GetIntValue(L"RXMODE", -1);
|
|
|
TXMode = GetIntValue(L"TXMODE", CP_UTF8);
|
|
|
|
|
|
AlertInterval = GetIntValue(L"AlertInterval", 3600);
|
|
|
AlertBeep = GetIntValue(L"AlertBeep", 1);
|
|
|
AlertFreq = GetIntValue(L"AlertFreq", 600);
|
|
|
AlertDuration = GetIntValue(L"AlertDuration", 250);
|
|
|
|
|
|
GetStringValue(L"AlertFileName", AlertFileName, MAX_PATH - 1);
|
|
|
|
|
|
ListenPort = GetIntValue(L"ListenPort", 8515);
|
|
|
|
|
|
UseKeywords = GetIntValue(L"UseKeywords", 1);
|
|
|
GetStringValue(L"AlertKeyFile", KeyWordsName, MAX_PATH - 1);
|
|
|
|
|
|
if (UseKeywords && KeyWordsName[0] == 0)
|
|
|
wcscpy(&KeyWordsName[0], L"Keywords.sys");
|
|
|
|
|
|
GetStringValue(L"YAPPPath", YAPPPath, MAX_PATH - 1);
|
|
|
|
|
|
|
|
|
OutputData.CharWidth = FontWidth;
|
|
|
|
|
|
// Create a dialog box as the main window
|
|
|
|
|
|
hWnd = CreateDialog(hInst,ClassName,0,NULL);
|
|
|
|
|
|
if (!hWnd)
|
|
|
return (FALSE);
|
|
|
|
|
|
MainWnd=hWnd;
|
|
|
|
|
|
GetStringValue(L"Size", Size, 80);
|
|
|
swscanf(Size,L"%d,%d,%d,%d",&Rect.left,&Rect.right,&Rect.top,&Rect.bottom);
|
|
|
|
|
|
if (Rect.right < 100 || Rect.bottom < 100)
|
|
|
{
|
|
|
GetWindowRect(hWnd, &Rect);
|
|
|
}
|
|
|
|
|
|
Height = Rect.bottom-Rect.top;
|
|
|
Width = Rect.right-Rect.left;
|
|
|
|
|
|
#pragma warning(push)
|
|
|
#pragma warning(disable:4244)
|
|
|
SplitPos=Height*Split;
|
|
|
#pragma warning(pop)
|
|
|
|
|
|
SetupRTFHddr();
|
|
|
|
|
|
// Create a Rich Text Control
|
|
|
|
|
|
OPData = &OutputData;
|
|
|
|
|
|
OPData->SendHeader = TRUE;
|
|
|
OPData->Finished = TRUE;
|
|
|
OPData->CurrentColour = 1;
|
|
|
|
|
|
LoadLibrary(L"riched20.dll");
|
|
|
|
|
|
hwndOutput = CreateWindowEx(WS_EX_CLIENTEDGE, RICHEDIT_CLASS, L"",
|
|
|
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_NOHIDESEL | WS_VSCROLL | ES_READONLY,
|
|
|
6,145,290,130, MainWnd, NULL, hInstance, NULL);
|
|
|
|
|
|
// Register for Mouse Events for Copy/Paste
|
|
|
|
|
|
SendMessage(hwndOutput, EM_SETEVENTMASK, (WPARAM)0, (LPARAM)ENM_MOUSEEVENTS | ENM_SCROLLEVENTS | ENM_KEYEVENTS);
|
|
|
SendMessage(hwndOutput, EM_EXLIMITTEXT, 0, MAXLINES * LINELEN);
|
|
|
|
|
|
trayMenu = CreatePopupMenu();
|
|
|
|
|
|
AppendMenu(trayMenu,MF_STRING,40000,L"Copy");
|
|
|
|
|
|
// Retrieve the handlse to the edit controls.
|
|
|
|
|
|
hwndInput = GetDlgItem(hWnd, 118);
|
|
|
hwndSplit = GetDlgItem(hWnd, 119);
|
|
|
hwndMon = GetDlgItem(hWnd, 116);
|
|
|
|
|
|
// Set our own WndProcs for the controls.
|
|
|
|
|
|
wpOrigInputProc = (WNDPROC) SetWindowLongPtr(hwndInput, GWLP_WNDPROC, InputProc);
|
|
|
wpOrigMonProc = (WNDPROC)SetWindowLongPtr(hwndMon, GWLP_WNDPROC, MonProc);
|
|
|
wpOrigSplitProc = (WNDPROC)SetWindowLongPtr(hwndSplit, GWLP_WNDPROC, SplitProc);
|
|
|
|
|
|
MoveWindow(hWnd,Rect.left,Rect.top, Rect.right-Rect.left, Rect.bottom-Rect.top, TRUE);
|
|
|
|
|
|
MoveWindows();
|
|
|
|
|
|
GetVersionInfo(NULL);
|
|
|
|
|
|
mbstowcs(VersionStringW, VersionString, 50);
|
|
|
|
|
|
if (ListenOn)
|
|
|
wsprintf(Title,L"BPQTermTCP Version %s Listening for Calls", VersionStringW);
|
|
|
else
|
|
|
wsprintf(Title,L"BPQTermTCP Version %s", VersionStringW);
|
|
|
|
|
|
SetWindowText(hWnd,Title);
|
|
|
|
|
|
hMenu=GetMenu(hWnd);
|
|
|
|
|
|
hPopMenu1=GetSubMenu(hMenu,4);
|
|
|
|
|
|
if (ListenOn == 0)
|
|
|
{
|
|
|
for (i = 1; i <= MonPorts; i++)
|
|
|
{
|
|
|
wsprintf(msg,L"Port %d",i);
|
|
|
|
|
|
if (tempmask & (1<<(i-1)))
|
|
|
{
|
|
|
AppendMenu(hPopMenu1,MF_STRING | MF_CHECKED,BPQBASE + i, &msg[0]);
|
|
|
portmask |= ((uint64_t)1<<(i-1));
|
|
|
}
|
|
|
else
|
|
|
AppendMenu(hPopMenu1,MF_STRING | MF_UNCHECKED,BPQBASE + i, &msg[0]);
|
|
|
}
|
|
|
}
|
|
|
CheckMenuItem(hMenu, BPQMTX, (mtxparam) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, BPQMCOM, (mcomparam) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, MUIONLY, (monUI) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, BPQBELLS, (Bells) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, BPQStripLF, (StripLF) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, BPQMNODES, (MonitorNODES) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, MONCOLOUR, (MonitorColour) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, CHATTERM, (ChatMode) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, BPQBELLS, (Bells) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, BPQENABLE, (ListenOn) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
|
|
|
for (i = 0; i < MAXHOSTS; i++)
|
|
|
{
|
|
|
if (Host[i][0])
|
|
|
{
|
|
|
ModifyMenu(hMenu, IDC_HOST1 + i, MF_BYCOMMAND, IDC_HOST1 + i, Host[i]);
|
|
|
ModifyMenu(hMenu, BPQCONNECT1 + i, MF_BYCOMMAND, BPQCONNECT1 + i, Host[i]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
EnableMenuItem(hMenu,BPQDISCONNECT,MF_GRAYED);
|
|
|
|
|
|
DrawMenuBar(hWnd);
|
|
|
|
|
|
DragCursor = LoadCursor(hInstance, L"IDC_DragSize");
|
|
|
Cursor = LoadCursor(NULL, IDC_ARROW);
|
|
|
|
|
|
if ((nCmdShow == SW_SHOWMINIMIZED) || (nCmdShow == SW_SHOWMINNOACTIVE))
|
|
|
if (MinimizetoTray)
|
|
|
ShowWindow(hWnd, SW_HIDE);
|
|
|
else
|
|
|
ShowWindow(hWnd, nCmdShow);
|
|
|
else
|
|
|
ShowWindow(hWnd, nCmdShow);
|
|
|
|
|
|
UpdateWindow(hWnd);
|
|
|
|
|
|
GetKeyWordFile(); // Words/Phrases to alert on
|
|
|
|
|
|
TimerHandle = SetTimer(NULL, 0, 10000, lpTimerFunc);
|
|
|
|
|
|
return (TRUE);
|
|
|
}
|
|
|
|
|
|
|
|
|
INT_PTR CALLBACK ConfigWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
int n;
|
|
|
|
|
|
switch (message)
|
|
|
{
|
|
|
case WM_INITDIALOG:
|
|
|
|
|
|
SetDlgItemText(hDlg, IDC_HOST, Host[CfgNo]);
|
|
|
SetDlgItemInt(hDlg, IDC_PORT, Port[CfgNo], FALSE);
|
|
|
SetDlgItemText(hDlg, IDC_USER, UserName[CfgNo]);
|
|
|
SetDlgItemText(hDlg, IDC_PASS, Password[CfgNo]);
|
|
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
case WM_CTLCOLORDLG:
|
|
|
return (LONG)bgBrush;
|
|
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
|
{
|
|
|
HDC hdcStatic = (HDC)wParam;
|
|
|
SetTextColor(hdcStatic, RGB(0, 0, 0));
|
|
|
SetBkMode(hdcStatic, TRANSPARENT);
|
|
|
return (LONG)bgBrush;
|
|
|
}
|
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
|
|
switch (LOWORD(wParam))
|
|
|
{
|
|
|
case IDOK:
|
|
|
|
|
|
GetDlgItemText(hDlg, IDC_HOST, Host[CfgNo], 99);
|
|
|
Port[CfgNo] = GetDlgItemInt(hDlg, IDC_PORT,NULL, FALSE);
|
|
|
GetDlgItemText(hDlg, IDC_USER, UserName[CfgNo], 79);
|
|
|
GetDlgItemText(hDlg, IDC_PASS, Password[CfgNo], 79);
|
|
|
|
|
|
ModifyMenu(hMenu, BPQCONNECT1 + CfgNo, MF_BYCOMMAND, BPQCONNECT1 + CfgNo, Host[CfgNo]);
|
|
|
ModifyMenu(hMenu, IDC_HOST1 + CfgNo, MF_BYCOMMAND, IDC_HOST1 + CfgNo, Host[CfgNo]);
|
|
|
|
|
|
for (n = 0; n < MAXHOSTS; n++)
|
|
|
{
|
|
|
SaveStringValue(HN[n], Host[n]);
|
|
|
SaveStringValue(UN[n], UserName[n]);
|
|
|
SaveStringValue(PASSN[n], Password[n]);
|
|
|
SaveIntValue(PN[n], Port[n]);
|
|
|
SaveStringValue(MON[n], MonParams[n]);
|
|
|
}
|
|
|
|
|
|
|
|
|
case IDCANCEL:
|
|
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
|
return TRUE;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
INT_PTR CALLBACK ListenWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
switch (message)
|
|
|
{
|
|
|
case WM_INITDIALOG:
|
|
|
|
|
|
SetDlgItemInt(hDlg, IDC_LISTENPORT, ListenPort, FALSE);
|
|
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
case WM_CTLCOLORDLG:
|
|
|
return (LONG)bgBrush;
|
|
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
|
{
|
|
|
HDC hdcStatic = (HDC)wParam;
|
|
|
SetTextColor(hdcStatic, RGB(0, 0, 0));
|
|
|
SetBkMode(hdcStatic, TRANSPARENT);
|
|
|
return (LONG)bgBrush;
|
|
|
}
|
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
|
|
switch (LOWORD(wParam))
|
|
|
{
|
|
|
case IDOK:
|
|
|
|
|
|
ListenPort = GetDlgItemInt(hDlg, IDC_LISTENPORT,NULL, FALSE);
|
|
|
|
|
|
SaveIntValue(L"ListenPort", ListenPort);
|
|
|
|
|
|
case IDCANCEL:
|
|
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
|
return TRUE;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
INT_PTR CALLBACK AlertConfigWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
switch (message)
|
|
|
{
|
|
|
case WM_INITDIALOG:
|
|
|
|
|
|
SetDlgItemInt(hDlg, IDC_ALERTINTERVAL, AlertInterval, FALSE);
|
|
|
if (AlertBeep)
|
|
|
CheckDlgButton(hDlg, IDC_RADIO1, TRUE);
|
|
|
else
|
|
|
CheckDlgButton(hDlg, IDC_RADIO2, TRUE);
|
|
|
|
|
|
SetDlgItemInt(hDlg, IDC_FREQ, AlertFreq, FALSE);
|
|
|
SetDlgItemInt(hDlg, IDC_DURATION, AlertDuration, FALSE);
|
|
|
SetDlgItemText(hDlg, IDC_ALERTFILENAME, &AlertFileName[0]);
|
|
|
|
|
|
CheckDlgButton(hDlg, IDC_USEKEYWORDS, UseKeywords);
|
|
|
SetDlgItemText(hDlg, IDC_ALERTKEYNAME, &KeyWordsName[0]);
|
|
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
case WM_CTLCOLORDLG:
|
|
|
return (LONG)bgBrush;
|
|
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
|
{
|
|
|
HDC hdcStatic = (HDC)wParam;
|
|
|
SetTextColor(hdcStatic, RGB(0, 0, 0));
|
|
|
SetBkMode(hdcStatic, TRANSPARENT);
|
|
|
return (LONG)bgBrush;
|
|
|
}
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
switch (LOWORD(wParam))
|
|
|
{
|
|
|
case IDOK:
|
|
|
|
|
|
AlertInterval = GetDlgItemInt(hDlg, IDC_ALERTINTERVAL, NULL, FALSE);
|
|
|
AlertBeep = IsDlgButtonChecked(hDlg,IDC_RADIO1);
|
|
|
AlertFreq = GetDlgItemInt(hDlg, IDC_FREQ, NULL, FALSE);
|
|
|
AlertDuration = GetDlgItemInt(hDlg, IDC_DURATION, NULL, FALSE);
|
|
|
UseKeywords = IsDlgButtonChecked(hDlg, IDC_USEKEYWORDS);
|
|
|
|
|
|
GetDlgItemText(hDlg, IDC_ALERTFILENAME, &AlertFileName[0], MAX_PATH-1 );
|
|
|
GetDlgItemText(hDlg, IDC_ALERTKEYNAME, &KeyWordsName[0], MAX_PATH-1 );
|
|
|
|
|
|
SaveIntValue(L"AlertInterval", AlertInterval);
|
|
|
SaveIntValue(L"AlertBeep", AlertBeep);
|
|
|
SaveIntValue(L"AlertFreq", AlertFreq);
|
|
|
SaveIntValue(L"AlertDuration", AlertDuration);
|
|
|
|
|
|
SaveIntValue(L"UseKeywords", UseKeywords);
|
|
|
SaveStringValue(L"AlertKeyFile", KeyWordsName);
|
|
|
|
|
|
SaveStringValue(L"AlertFileName", AlertFileName);
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
|
return TRUE;
|
|
|
|
|
|
case IDCANCEL:
|
|
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
|
return TRUE;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
INT_PTR CALLBACK FontConfigWndProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
POINT Point;
|
|
|
int Min, Max;
|
|
|
|
|
|
switch (message)
|
|
|
{
|
|
|
case WM_INITDIALOG:
|
|
|
|
|
|
if (RXMode == AUTO)
|
|
|
CheckDlgButton(hDlg, IDC_AUTO, BST_CHECKED);
|
|
|
else if (RXMode == CP1251)
|
|
|
CheckDlgButton(hDlg, IDC_1251, BST_CHECKED);
|
|
|
else if (RXMode == CP1252)
|
|
|
CheckDlgButton(hDlg, IDC_1252, BST_CHECKED);
|
|
|
else if (RXMode == CP437)
|
|
|
CheckDlgButton(hDlg, IDC_437, BST_CHECKED);
|
|
|
|
|
|
if (TXMode == CP_UTF8)
|
|
|
CheckDlgButton(hDlg, IDC_UTF8, BST_CHECKED);
|
|
|
else if (TXMode == CP1251)
|
|
|
CheckDlgButton(hDlg, IDC_Send1251, BST_CHECKED);
|
|
|
else if (TXMode == CP1252)
|
|
|
CheckDlgButton(hDlg, IDC_Send1252, BST_CHECKED);
|
|
|
|
|
|
SetDlgItemInt(hDlg, IDC_FONTSIZE, FontSize, FALSE);
|
|
|
SetDlgItemInt(hDlg, IDC_FONTWIDTH, FontWidth, FALSE);
|
|
|
|
|
|
return (INT_PTR)TRUE;
|
|
|
|
|
|
case WM_CTLCOLORDLG:
|
|
|
return (LONG)bgBrush;
|
|
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
|
{
|
|
|
HDC hdcStatic = (HDC)wParam;
|
|
|
SetTextColor(hdcStatic, RGB(0, 0, 0));
|
|
|
SetBkMode(hdcStatic, TRANSPARENT);
|
|
|
return (LONG)bgBrush;
|
|
|
}
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
switch (LOWORD(wParam))
|
|
|
{
|
|
|
case IDOK:
|
|
|
|
|
|
// GetDlgItemText(hDlg, IDC_FONTNAME, FontName, 99);
|
|
|
// CharSet = GetDlgItemInt(hDlg, IDC_CHARSET, NULL, FALSE);
|
|
|
// CodePage = GetDlgItemInt(hDlg, IDC_CODEPAGE, NULL, FALSE);
|
|
|
|
|
|
FontSize = GetDlgItemInt(hDlg, IDC_FONTSIZE, NULL, FALSE);
|
|
|
FontWidth = GetDlgItemInt(hDlg, IDC_FONTWIDTH, NULL, FALSE);
|
|
|
|
|
|
if (IsDlgButtonChecked(hDlg, IDC_AUTO))
|
|
|
RXMode = AUTO;
|
|
|
else if (IsDlgButtonChecked(hDlg, IDC_1251))
|
|
|
RXMode = CP1251;
|
|
|
else if (IsDlgButtonChecked(hDlg, IDC_1252))
|
|
|
RXMode = CP1252;
|
|
|
else if (IsDlgButtonChecked(hDlg, IDC_437))
|
|
|
RXMode = CP437;
|
|
|
|
|
|
if (IsDlgButtonChecked(hDlg, IDC_UTF8))
|
|
|
TXMode = CP_UTF8;
|
|
|
else if (IsDlgButtonChecked(hDlg, IDC_Send1251))
|
|
|
TXMode = CP1251;
|
|
|
else if (IsDlgButtonChecked(hDlg, IDC_Send1252))
|
|
|
TXMode = CP1252;
|
|
|
|
|
|
// SaveStringValue(L"FontName", FontName);
|
|
|
// SaveIntValue(L"CharSet", CharSet);
|
|
|
// SaveIntValue(L"CodePage", CodePage);
|
|
|
SaveIntValue(L"FontSize", FontSize);
|
|
|
SaveIntValue(L"FontWidth", FontWidth);
|
|
|
SaveIntValue(L"RXMODE", RXMode);
|
|
|
SaveIntValue(L"TXMODE", TXMode);
|
|
|
|
|
|
OutputData.CharWidth = FontWidth;
|
|
|
|
|
|
SetupRTFHddr();
|
|
|
|
|
|
Point.x = 0;
|
|
|
Point.y = 25000; // Should be plenty for any font
|
|
|
|
|
|
SendMessage(hwndOutput, EM_SETSCROLLPOS, 0, (LPARAM) &Point);
|
|
|
OutputData.Scrolled = FALSE;
|
|
|
|
|
|
GetScrollRange(hwndOutput, SB_VERT, &Min, &Max); // Get Actual Height
|
|
|
OutputData.RTFHeight = Max;
|
|
|
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
case IDCANCEL:
|
|
|
|
|
|
EndDialog(hDlg, LOWORD(wParam));
|
|
|
return TRUE;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
//
|
|
|
// FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
|
|
|
//
|
|
|
// PURPOSE: Processes messages for the main window.
|
|
|
//
|
|
|
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
int wmId, wmEvent;
|
|
|
LPRECT lprc;
|
|
|
TCHAR Buffer[1000];
|
|
|
TCHAR * buf = Buffer;
|
|
|
TEXTMETRIC tm;
|
|
|
int y, i;
|
|
|
LPMEASUREITEMSTRUCT lpmis;
|
|
|
LPDRAWITEMSTRUCT lpdis;
|
|
|
OPENFILENAME ofn;
|
|
|
WCHAR FN[MAX_PATH] = L"";
|
|
|
BROWSEINFO bi;
|
|
|
LPITEMIDLIST pidl;
|
|
|
char Mess[64];
|
|
|
|
|
|
|
|
|
switch (message)
|
|
|
{
|
|
|
case WSA_DATA: // Notification on data socket
|
|
|
|
|
|
Socket_Data(wParam, WSAGETSELECTERROR(lParam), WSAGETSELECTEVENT(lParam));
|
|
|
return 0;
|
|
|
|
|
|
case WSA_ACCEPT: /* Notification if a socket connection is pending. */
|
|
|
|
|
|
Socket_Accept(wParam, WSAGETSELECTERROR(lParam), WSAGETSELECTEVENT(lParam));
|
|
|
return 0;
|
|
|
|
|
|
case WSA_CONNECT: /* Notification if a socket connection is pending. */
|
|
|
|
|
|
Telnet_Connected(wParam, WSAGETSELECTERROR(lParam));
|
|
|
return 0;
|
|
|
|
|
|
// case WM_CREATE:
|
|
|
|
|
|
// SendMessage(hWndRichEdit, EM_SETEVENTMASK, (WPARAM)0 (LPARAM)ENM_MOUSEEVENTS);
|
|
|
// break;
|
|
|
|
|
|
|
|
|
case WM_CTLCOLOREDIT:
|
|
|
|
|
|
if (OutputData.Scrolled)
|
|
|
{
|
|
|
HDC hdcStatic = (HDC)wParam;
|
|
|
SetBkMode(hdcStatic, TRANSPARENT);
|
|
|
|
|
|
return (LONG)GetStockObject(LTGRAY_BRUSH);
|
|
|
}
|
|
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
|
|
|
|
|
case WM_NOTIFY:
|
|
|
{
|
|
|
const MSGFILTER * pF = (MSGFILTER *)lParam;
|
|
|
POINT pos;
|
|
|
CHARRANGE Range;
|
|
|
|
|
|
if(pF->nmhdr.hwndFrom == hwndOutput)
|
|
|
{
|
|
|
if(pF->msg == WM_VSCROLL)
|
|
|
{
|
|
|
// OutputData.Thumb = SendMessage(hwndOutput, EM_GETTHUMB, 0, 0);
|
|
|
DoRefresh(&OutputData);
|
|
|
// return TRUE;
|
|
|
}
|
|
|
|
|
|
if(pF->msg == WM_KEYUP)
|
|
|
{
|
|
|
if (pF->wParam == VK_PRIOR || pF->wParam == VK_NEXT)
|
|
|
{
|
|
|
// OutputData.Thumb = SendMessage(hwndOutput, EM_GETTHUMB, 0, 0);
|
|
|
DoRefresh(&OutputData);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if(pF->msg == WM_RBUTTONDOWN)
|
|
|
{
|
|
|
// Only allow popup if something is selected
|
|
|
|
|
|
SendMessage(hwndOutput, EM_EXGETSEL , 0, (WPARAM)&Range);
|
|
|
if (Range.cpMin == Range.cpMax)
|
|
|
return TRUE;
|
|
|
|
|
|
GetCursorPos(&pos);
|
|
|
TrackPopupMenu(trayMenu, 0, pos.x, pos.y, 0, hWnd, 0);
|
|
|
return TRUE;
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case WM_MEASUREITEM:
|
|
|
|
|
|
lpmis = (LPMEASUREITEMSTRUCT) lParam;
|
|
|
return TRUE;
|
|
|
|
|
|
case WM_DRAWITEM:
|
|
|
|
|
|
lpdis = (LPDRAWITEMSTRUCT) lParam;
|
|
|
|
|
|
// If there are no list box items, skip this message.
|
|
|
|
|
|
if (lpdis->itemID == -1)
|
|
|
{
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
|
switch (lpdis->itemAction)
|
|
|
{
|
|
|
case ODA_SELECT:
|
|
|
case ODA_DRAWENTIRE:
|
|
|
|
|
|
// if Chat Console, and message has a colour eacape, action it
|
|
|
|
|
|
SendMessage(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, (LPARAM) Buffer);
|
|
|
|
|
|
GetTextMetrics(lpdis->hDC, &tm);
|
|
|
|
|
|
y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
|
|
|
|
|
|
if (Buffer[0] == 0x1b)
|
|
|
{
|
|
|
SetTextColor(lpdis->hDC, Colours[Buffer[1] - 10]);
|
|
|
buf += 2;
|
|
|
}
|
|
|
// SetBkColor(lpdis->hDC, 0);
|
|
|
|
|
|
TextOut(lpdis->hDC,
|
|
|
6,
|
|
|
y,
|
|
|
buf,
|
|
|
wcslen(buf));
|
|
|
|
|
|
// SetTextColor(lpdis->hDC, OldColour);
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
case WM_ACTIVATE:
|
|
|
|
|
|
SetFocus(hwndInput);
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
|
|
wmId = LOWORD(wParam); // Remember, these are...
|
|
|
wmEvent = HIWORD(wParam); // ...different for Win32!
|
|
|
|
|
|
//Parse the menu selections:
|
|
|
|
|
|
if (wmId > BPQBASE && wmId <= BPQBASE + 64)
|
|
|
{
|
|
|
TogglePort(hWnd,wmId,0x1 << (wmId - (BPQBASE + 1)));
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if (wmId >= BPQCONNECT1 && wmId < BPQCONNECT1 + MAXHOSTS)
|
|
|
{
|
|
|
CurrentHost = wmId - BPQCONNECT1;
|
|
|
|
|
|
i = swscanf(MonParams[CurrentHost], L"%llx %x %x %x %x %x",
|
|
|
&portmask, &mtxparam, &mcomparam, &MonitorNODES, &MonitorColour, &monUI);
|
|
|
|
|
|
for (i = 1; i <= MonPorts; i++)
|
|
|
{
|
|
|
if (portmask & ((uint64_t)1<<(i-1)))
|
|
|
CheckMenuItem(hMenu, BPQBASE + i, MF_CHECKED);
|
|
|
else
|
|
|
CheckMenuItem(hMenu, BPQBASE + i, MF_UNCHECKED);
|
|
|
|
|
|
}
|
|
|
|
|
|
CheckMenuItem(hMenu, BPQMCOM, (mcomparam) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, MUIONLY, (monUI) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, BPQMTX, (mtxparam) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
CheckMenuItem(hMenu, BPQMNODES, (MonitorNODES) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
|
|
|
|
|
|
TCPConnect(Host[CurrentHost], Port[CurrentHost]);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if (wmId >= IDC_HOST1 && wmId < IDC_HOST1 + MAXHOSTS)
|
|
|
{
|
|
|
CfgNo = wmId - IDC_HOST1;
|
|
|
|
|
|
DialogBox(hInst, MAKEINTRESOURCE(IDD_CONFIG), hWnd, ConfigWndProc);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
switch (wmId)
|
|
|
{
|
|
|
case BPQPORT:
|
|
|
|
|
|
DialogBox(hInst, MAKEINTRESOURCE(IDD_LISTEN), hWnd, ListenWndProc);
|
|
|
break;
|
|
|
|
|
|
|
|
|
case 40000:
|
|
|
{
|
|
|
int len=0;
|
|
|
HGLOBAL hMem;
|
|
|
char * ptr;
|
|
|
CHARRANGE Range;
|
|
|
|
|
|
// Copy Rich Text Selection to Clipboard
|
|
|
|
|
|
SendMessage(hwndOutput, EM_EXGETSEL , 0, (WPARAM)&Range);
|
|
|
|
|
|
hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (Range.cpMax - Range.cpMin + 1) * 2);
|
|
|
|
|
|
if (hMem != 0)
|
|
|
{
|
|
|
ptr=GlobalLock(hMem);
|
|
|
|
|
|
if (OpenClipboard(MainWnd))
|
|
|
{
|
|
|
len = SendMessage(hwndOutput, EM_GETSELTEXT , 0, (WPARAM)ptr);
|
|
|
|
|
|
GlobalUnlock(hMem);
|
|
|
EmptyClipboard();
|
|
|
SetClipboardData(CF_UNICODETEXT,hMem);
|
|
|
CloseClipboard();
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
GlobalFree(hMem);
|
|
|
|
|
|
SetFocus(hwndInput);
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
|
case BPQMTX:
|
|
|
|
|
|
ToggleMTX(hWnd);
|
|
|
break;
|
|
|
|
|
|
case BPQMCOM:
|
|
|
|
|
|
ToggleMCOM(hWnd);
|
|
|
break;
|
|
|
|
|
|
case MUIONLY:
|
|
|
|
|
|
ToggleMUI(hWnd);
|
|
|
break;
|
|
|
|
|
|
case BPQDISCONNECT:
|
|
|
|
|
|
if (Disconnecting)
|
|
|
{
|
|
|
// Force close
|
|
|
|
|
|
if (SocketActive)
|
|
|
closesocket(sock);
|
|
|
|
|
|
wsprintf(Title, L"BPQTermTCP Version %s - Disconnected", VersionStringW);
|
|
|
SetWindowText(hWnd,Title);
|
|
|
DisableDisconnectMenu(hWnd);
|
|
|
DisableYAPPMenu(hWnd);
|
|
|
EnableConnectMenu(hWnd);
|
|
|
|
|
|
WritetoOutputWindow(&OutputData , L"*** Disconnected\r", 17);
|
|
|
DoRefresh(&OutputData);
|
|
|
SocketActive = FALSE;
|
|
|
Connected = FALSE;
|
|
|
Disconnecting = FALSE;
|
|
|
InputMode = 0;
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
shutdown(sock, 2); // SD_BOTH
|
|
|
Disconnecting = TRUE;
|
|
|
break;
|
|
|
|
|
|
case BPQBELLS:
|
|
|
|
|
|
ToggleParam(hWnd, &Bells, BPQBELLS);
|
|
|
break;
|
|
|
|
|
|
case BPQENABLE:
|
|
|
|
|
|
ToggleParam(hWnd, &ListenOn, BPQENABLE);
|
|
|
if (ListenOn)
|
|
|
{
|
|
|
DisableConnectMenu(hWnd);
|
|
|
ListenSock = OpenListenSocket4(ListenPort);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
EnableConnectMenu(hWnd);
|
|
|
closesocket(ListenSock);
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
case BPQStripLF:
|
|
|
|
|
|
ToggleParam(hWnd, &StripLF, BPQStripLF);
|
|
|
break;
|
|
|
|
|
|
case BPQLogOutput:
|
|
|
|
|
|
ToggleParam(hWnd, &LogOutput, BPQLogOutput);
|
|
|
break;
|
|
|
|
|
|
case CHATTERM:
|
|
|
|
|
|
ToggleParam(hWnd, &ChatMode, CHATTERM);
|
|
|
break;
|
|
|
|
|
|
|
|
|
case ID_SETUP_FONT:
|
|
|
|
|
|
DialogBox(hInst, MAKEINTRESOURCE(IDD_FONT), hWnd, FontConfigWndProc);
|
|
|
break;
|
|
|
|
|
|
case ID_SETUP_ALERTSETUP:
|
|
|
|
|
|
DialogBox(hInst, MAKEINTRESOURCE(IDD_ALERTDLG), hWnd, AlertConfigWndProc);
|
|
|
break;
|
|
|
|
|
|
case BPQMNODES:
|
|
|
|
|
|
ToggleParam(hWnd, &MonitorNODES, BPQMNODES);
|
|
|
SendTraceOptions();
|
|
|
break;
|
|
|
|
|
|
|
|
|
case MONITOR_ADDPORT:
|
|
|
|
|
|
wsprintf(Buffer, L"Port %d", ++MonPorts);
|
|
|
|
|
|
AppendMenu(hPopMenu1,MF_STRING | MF_UNCHECKED,BPQBASE + MonPorts, Buffer);
|
|
|
|
|
|
|
|
|
case MONCOLOUR:
|
|
|
|
|
|
ToggleParam(hWnd, &MonitorColour, MONCOLOUR);
|
|
|
SendTraceOptions();
|
|
|
break;
|
|
|
|
|
|
case BPQLogMonitor:
|
|
|
|
|
|
ToggleParam(hWnd, &LogMonitor, BPQLogMonitor);
|
|
|
break;
|
|
|
|
|
|
case BPQCLEARMON:
|
|
|
|
|
|
SendMessage(hwndMon,LB_RESETCONTENT, 0, 0);
|
|
|
break;
|
|
|
|
|
|
case BPQCLEAROUT:
|
|
|
|
|
|
for (i = 0; i < MAXLINES; i++)
|
|
|
{
|
|
|
OutputData.OutputScreen[i][0] = 0;
|
|
|
}
|
|
|
|
|
|
OutputData.CurrentLine = 0;
|
|
|
DoRefresh(&OutputData);
|
|
|
break;
|
|
|
|
|
|
case BPQCOPYMON:
|
|
|
|
|
|
CopyListToClipboard(hwndMon);
|
|
|
break;
|
|
|
|
|
|
case BPQCOPYOUT:
|
|
|
|
|
|
CopyRichTextToClipboard(hwndOutput);
|
|
|
break;
|
|
|
|
|
|
case BPQHELP:
|
|
|
|
|
|
// HtmlHelp(hWnd,"BPQTerminal.chm",HH_HELP_FINDER,0);
|
|
|
break;
|
|
|
|
|
|
case YAPPSEND:
|
|
|
|
|
|
memset(&ofn, 0, sizeof (OPENFILENAME));
|
|
|
ofn.lStructSize = sizeof (OPENFILENAME);
|
|
|
ofn.hwndOwner = hWnd;
|
|
|
ofn.lpstrFile = FN;
|
|
|
ofn.nMaxFile = 250;
|
|
|
ofn.lpstrTitle = L"File to send";
|
|
|
// ofn.lpstrInitialDir = BPQDirectory;
|
|
|
|
|
|
// Turn off monitoring
|
|
|
|
|
|
len = sprintf(Mess, "\\\\\\\\%x %x %x %x %x %x %x %x\r", 0, 0, 0, 0, 0, 0, 0, 0);
|
|
|
send(sock, Mess, len, 0);
|
|
|
|
|
|
|
|
|
if (GetOpenFileName(&ofn))
|
|
|
YAPPSendFile(FN);
|
|
|
else
|
|
|
SendTraceOptions();
|
|
|
break;
|
|
|
|
|
|
|
|
|
case YAPPDIR:
|
|
|
|
|
|
memset(&bi, 0, sizeof (BROWSEINFO));
|
|
|
|
|
|
bi.hwndOwner = NULL;
|
|
|
bi.pidlRoot = NULL;
|
|
|
bi.pszDisplayName = FN;
|
|
|
bi.lpszTitle = L"Please select a folder for storing received files";
|
|
|
bi.ulFlags = BIF_RETURNONLYFSDIRS;
|
|
|
bi.lParam = 0;
|
|
|
bi.iImage = 0;
|
|
|
|
|
|
pidl = SHBrowseForFolder(&bi);
|
|
|
|
|
|
if (pidl)
|
|
|
{
|
|
|
SHGetPathFromIDList(pidl, YAPPPath);
|
|
|
wcscat(YAPPPath, L"\\");
|
|
|
SaveStringValue(L"YAPPPath", YAPPPath);
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
case WM_SYSCOMMAND:
|
|
|
|
|
|
wmId = LOWORD(wParam); // Remember, these are...
|
|
|
wmEvent = HIWORD(wParam); // ...different for Win32!
|
|
|
|
|
|
switch (wmId) {
|
|
|
|
|
|
case SC_RESTORE:
|
|
|
|
|
|
case SC_MINIMIZE:
|
|
|
|
|
|
default:
|
|
|
|
|
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
|
|
}
|
|
|
|
|
|
case WM_SIZE:
|
|
|
|
|
|
MoveWindows();
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
case WM_SIZING:
|
|
|
|
|
|
lprc = (LPRECT) lParam;
|
|
|
|
|
|
Height = lprc->bottom-lprc->top;
|
|
|
Width = lprc->right-lprc->left;
|
|
|
|
|
|
#pragma warning(push)
|
|
|
#pragma warning(disable:4244)
|
|
|
SplitPos=Height*Split;
|
|
|
#pragma warning(pop)
|
|
|
|
|
|
MoveWindows();
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
case WM_DESTROY:
|
|
|
|
|
|
// Remove the subclass from the edit control.
|
|
|
|
|
|
GetWindowRect(hWnd, &Rect); // For save soutine
|
|
|
|
|
|
SetWindowLong(hwndInput, -4,
|
|
|
(LONG) wpOrigInputProc);
|
|
|
|
|
|
PostQuitMessage(0);
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
return (DefWindowProc(hWnd, message, wParam, lParam));
|
|
|
|
|
|
}
|
|
|
return (0);
|
|
|
}
|
|
|
|
|
|
static TCHAR * KbdStack[20];
|
|
|
|
|
|
int StackIndex=0;
|
|
|
|
|
|
LRESULT APIENTRY InputProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
TCHAR DisplayLine[250] = L"";
|
|
|
|
|
|
if (uMsg == WM_CTLCOLOREDIT)
|
|
|
{
|
|
|
HBRUSH Brush = CreateSolidBrush(RGB(0, 255, 0));
|
|
|
HDC hdcStatic = (HDC)wParam;
|
|
|
SetTextColor(hdcStatic, RGB(0, 0, 0));
|
|
|
SetBkMode(hdcStatic, TRANSPARENT);
|
|
|
|
|
|
return (LONG)Brush;
|
|
|
}
|
|
|
|
|
|
|
|
|
if (uMsg == WM_KEYUP)
|
|
|
{
|
|
|
unsigned int i;
|
|
|
|
|
|
// Debugprintf("5%x", LOBYTE(HIWORD(lParam)));
|
|
|
|
|
|
if (LOBYTE(HIWORD(lParam)) == 0x48 && wParam == 0x26)
|
|
|
{
|
|
|
// Scroll up
|
|
|
|
|
|
if (KbdStack[StackIndex] == NULL)
|
|
|
return TRUE;
|
|
|
|
|
|
SendMessage(hwndInput, WM_SETTEXT,0,(LPARAM)(LPCSTR) KbdStack[StackIndex]);
|
|
|
|
|
|
for (i = 0; i < wcslen(KbdStack[StackIndex]); i++)
|
|
|
{
|
|
|
SendMessage(hwndInput, WM_KEYDOWN, VK_RIGHT, 0);
|
|
|
SendMessage(hwndInput, WM_KEYUP, VK_RIGHT, 0);
|
|
|
}
|
|
|
|
|
|
StackIndex++;
|
|
|
if (StackIndex == 20)
|
|
|
StackIndex = 19;
|
|
|
|
|
|
return TRUE;
|
|
|
}
|
|
|
|
|
|
if (LOBYTE(HIWORD(lParam)) == 0x50 && wParam == 0x28)
|
|
|
{
|
|
|
// Scroll up
|
|
|
|
|
|
StackIndex--;
|
|
|
if (StackIndex < 0)
|
|
|
StackIndex = 0;
|
|
|
|
|
|
if (KbdStack[StackIndex] == NULL)
|
|
|
return TRUE;
|
|
|
|
|
|
SendMessage(hwndInput,WM_SETTEXT,0,(LPARAM)(LPCSTR) KbdStack[StackIndex]);
|
|
|
|
|
|
for (i = 0; i < wcslen(KbdStack[StackIndex]); i++)
|
|
|
{
|
|
|
SendMessage(hwndInput, WM_KEYDOWN, VK_RIGHT, 0);
|
|
|
SendMessage(hwndInput, WM_KEYUP, VK_RIGHT, 0);
|
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (uMsg == WM_CHAR)
|
|
|
{
|
|
|
if (wParam == 13)
|
|
|
{
|
|
|
int i;
|
|
|
|
|
|
if (!Connected && ! Connecting)
|
|
|
{
|
|
|
TCPConnect(Host[CurrentHost], Port[CurrentHost]);
|
|
|
SendMessage(hwndInput,WM_SETTEXT,0,(LPARAM)(LPCSTR) L"");
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
kbptr=SendMessage(hwndInput,WM_GETTEXT,199,(LPARAM) (LPCSTR) kbbuf);
|
|
|
|
|
|
// Stack it
|
|
|
|
|
|
StackIndex = 0;
|
|
|
|
|
|
if (KbdStack[19])
|
|
|
free(KbdStack[19]);
|
|
|
|
|
|
for (i = 18; i >= 0; i--)
|
|
|
{
|
|
|
KbdStack[i+1] = KbdStack[i];
|
|
|
}
|
|
|
|
|
|
KbdStack[0] = _wcsdup(kbbuf);
|
|
|
|
|
|
kbbuf[kbptr]=13;
|
|
|
|
|
|
SlowTimer = 0;
|
|
|
|
|
|
// Echo, with set Black escape
|
|
|
|
|
|
DisplayLine[0] = 0x1b;
|
|
|
DisplayLine[1] = 0x21;
|
|
|
|
|
|
memcpy(&DisplayLine[2], kbbuf, (kbptr+1) * 2);
|
|
|
|
|
|
if (OutputData.Scrolled)
|
|
|
{
|
|
|
POINT Point;
|
|
|
Point.x = 0;
|
|
|
Point.y = 25000; // Should be plenty for any font
|
|
|
|
|
|
SendMessage(hwndOutput, EM_SETSCROLLPOS, 0, (LPARAM) &Point);
|
|
|
OutputData.Scrolled = FALSE;
|
|
|
}
|
|
|
|
|
|
LastWrite = time(NULL);
|
|
|
|
|
|
WritetoOutputWindow(&OutputData, DisplayLine, kbptr+3);
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
// Replace null with CR, and send to Node
|
|
|
|
|
|
SendMsg(&kbbuf[0], kbptr+1);
|
|
|
|
|
|
SendMessage(hwndInput,WM_SETTEXT,0,(LPARAM)(LPCSTR) L"");
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
if (wParam == 0x1a) // Ctrl/Z
|
|
|
{
|
|
|
kbbuf[0]=0x1a;
|
|
|
kbbuf[1]=13;
|
|
|
|
|
|
SendMsg(&kbbuf[0], 2);
|
|
|
|
|
|
SendMessage(hwndInput,WM_SETTEXT,0,(LPARAM)(LPCSTR) L"");
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
return CallWindowProc(wpOrigInputProc, hwnd, uMsg, wParam, lParam);
|
|
|
}
|
|
|
|
|
|
//int FirstItem=-1, LastItem=-1, SELECTING=FALSE, MOVED=FALSE, LastSelected=0;
|
|
|
|
|
|
LRESULT APIENTRY MonProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
if (uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
|
|
|
return TRUE;
|
|
|
|
|
|
return CallWindowProc(wpOrigMonProc, hwnd, uMsg, wParam, lParam);
|
|
|
}
|
|
|
|
|
|
LRESULT APIENTRY SplitProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
{
|
|
|
int xPos, yPos;
|
|
|
|
|
|
switch (uMsg) {
|
|
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
|
|
SetCapture(hwnd);
|
|
|
return 0;
|
|
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
|
|
xPos = LOWORD(lParam); // horizontal position of cursor
|
|
|
yPos = lParam >> 16; // vertical position of cursor
|
|
|
|
|
|
SplitPos = SplitPos + yPos - 5;
|
|
|
|
|
|
if (SplitPos < 0) SplitPos = 0;
|
|
|
|
|
|
Split=SplitPos;
|
|
|
Split=Split/Height;
|
|
|
|
|
|
ReleaseCapture();
|
|
|
MoveWindows();
|
|
|
DoRefresh(&OutputData);
|
|
|
return 0;
|
|
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
|
|
// Used to size split between Monitor and Output Windows
|
|
|
|
|
|
SetCursor(DragCursor);
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
return CallWindowProc(wpOrigSplitProc, hwnd, uMsg, wParam, lParam);
|
|
|
}
|
|
|
|
|
|
VOID wcstoRTF(char * out, TCHAR * in)
|
|
|
{
|
|
|
TCHAR * ptr1 = in;
|
|
|
char * ptr2 = out;
|
|
|
int val = *ptr1++;
|
|
|
|
|
|
while (val)
|
|
|
{
|
|
|
{
|
|
|
if (val > 127 || val < -128 )
|
|
|
ptr2 += sprintf(ptr2, "\\u%d ", val);
|
|
|
else
|
|
|
*(ptr2++) = val;
|
|
|
}
|
|
|
val = *ptr1++;
|
|
|
}
|
|
|
*ptr2 = 0;
|
|
|
}
|
|
|
|
|
|
DWORD CALLBACK EditStreamCallback(DWORD_PTR Cookie, unsigned char * lpBuff, LONG cb, PLONG pcb)
|
|
|
{
|
|
|
struct RTFTerm * OPData = (struct RTFTerm *)Cookie;
|
|
|
int ReqLen = cb;
|
|
|
int i;
|
|
|
int Line;
|
|
|
char LineB[20000];
|
|
|
|
|
|
// if (cb != 4092)
|
|
|
// return 0;
|
|
|
|
|
|
if (OPData->SendHeader)
|
|
|
{
|
|
|
// Return header
|
|
|
|
|
|
memcpy(lpBuff, RTFHeader, RTFHddrLen);
|
|
|
*pcb = RTFHddrLen;
|
|
|
OPData->SendHeader = FALSE;
|
|
|
OPData->Finished = FALSE;
|
|
|
OPData->Index = 0;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
if (OPData->Finished)
|
|
|
{
|
|
|
*pcb = 0;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
if (BufferLen > cb)
|
|
|
{
|
|
|
memcpy(lpBuff, &Buffer[Offset], cb);
|
|
|
BufferLen -= cb;
|
|
|
Offset += cb;
|
|
|
*pcb = cb;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
memcpy(lpBuff, &Buffer[Offset], BufferLen);
|
|
|
|
|
|
*pcb = BufferLen;
|
|
|
*/
|
|
|
|
|
|
// Return 10 line at a time
|
|
|
|
|
|
for (i = 0; i < 10; i++);
|
|
|
{
|
|
|
Line = OPData->Index++ + OPData->CurrentLine - MAXLINES;
|
|
|
|
|
|
if (Line <0)
|
|
|
Line = Line + MAXLINES;
|
|
|
|
|
|
wcstoRTF(LineB, OPData->OutputScreen[Line]);
|
|
|
|
|
|
sprintf(lpBuff, "\\cf%d ", OPData->Colourvalue[Line]);
|
|
|
strcat(lpBuff, LineB);
|
|
|
strcat(lpBuff, "\\line");
|
|
|
|
|
|
if (OPData->Index == MAXLINES)
|
|
|
{
|
|
|
OPData->Finished = TRUE;
|
|
|
strcat(lpBuff, "}");
|
|
|
i = 10;
|
|
|
}
|
|
|
}
|
|
|
*pcb = strlen(lpBuff);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
VOID ForceRefresh(struct RTFTerm * OPData)
|
|
|
{
|
|
|
OPData->Thumb = 25000;
|
|
|
DoRefresh(OPData);
|
|
|
OPData->Thumb = SendMessage(hwndOutput, EM_GETTHUMB, 0, 0);
|
|
|
}
|
|
|
|
|
|
VOID DoRefresh(struct RTFTerm * OPData)
|
|
|
{
|
|
|
EDITSTREAM es = {0};
|
|
|
int Min, Max, Pos;
|
|
|
POINT Point;
|
|
|
SCROLLINFO ScrollInfo;
|
|
|
int LoopTrap = 0;
|
|
|
|
|
|
if(WINE)
|
|
|
OPData->Thumb = 30000;
|
|
|
else
|
|
|
OPData->Thumb = SendMessage(hwndOutput, EM_GETTHUMB, 0, 0);
|
|
|
|
|
|
Pos = OPData->Thumb + OutputBoxHeight;
|
|
|
|
|
|
if (Pos > OPData->RTFHeight - 10) // Don't bother writing to screen if scrolled back
|
|
|
{
|
|
|
es.pfnCallback = EditStreamCallback;
|
|
|
es.dwCookie = (DWORD_PTR)OPData;
|
|
|
OPData->SendHeader = TRUE;
|
|
|
SendMessage(hwndOutput, EM_STREAMIN, SF_RTF, (LPARAM)&es);
|
|
|
}
|
|
|
// else
|
|
|
// Debugprintf("Pos %d RTFHeight %d - Not refreshing", Pos, OPData->RTFHeight);
|
|
|
|
|
|
GetScrollRange(hwndOutput, SB_VERT, &Min, &Max);
|
|
|
ScrollInfo.cbSize = sizeof(ScrollInfo);
|
|
|
ScrollInfo.fMask = SIF_ALL;
|
|
|
|
|
|
GetScrollInfo(hwndOutput, SB_VERT, &ScrollInfo);
|
|
|
|
|
|
// Debugprintf("Thumb %d Pos %d Min %d Max %d nMax %d ClientH %d RTFHeight %d",
|
|
|
// OPData->Thumb, Pos, Min, Max, ScrollInfo.nMax, OutputBoxHeight, OPData->RTFHeight);
|
|
|
|
|
|
if (OPData->FirstTime == FALSE)
|
|
|
{
|
|
|
// RTF Controls don't immediately scroll to end - don't know why.
|
|
|
|
|
|
OPData->FirstTime = TRUE;
|
|
|
Point.x = 0;
|
|
|
Point.y = 25000; // Should be plenty for any font
|
|
|
|
|
|
while (LoopTrap++ < 20)
|
|
|
{
|
|
|
SendMessage(hwndOutput, EM_SETSCROLLPOS, 0, (LPARAM) &Point);
|
|
|
}
|
|
|
|
|
|
GetScrollRange(hwndOutput, SB_VERT, &Min, &Max); // Get Actual Height
|
|
|
OPData->RTFHeight = Max;
|
|
|
Point.x = 0;
|
|
|
Point.y = OPData->RTFHeight - ScrollInfo.nPage;
|
|
|
SendMessage(hwndOutput, EM_SETSCROLLPOS, 0, (LPARAM) &Point);
|
|
|
OPData->Thumb = SendMessage(hwndOutput, EM_GETTHUMB, 0, 0);
|
|
|
}
|
|
|
|
|
|
Point.x = 0;
|
|
|
Point.y = OPData->RTFHeight - ScrollInfo.nPage;
|
|
|
|
|
|
if (OPData->Thumb > (Point.y - 10)) // Don't Scroll if user has scrolled back
|
|
|
{
|
|
|
// Debugprintf("Scrolling to %d", Point.y);
|
|
|
SendMessage(hwndOutput, EM_SETSCROLLPOS, 0, (LPARAM) &Point);
|
|
|
if (OPData->Scrolled)
|
|
|
{
|
|
|
OPData->Scrolled = FALSE;
|
|
|
InvalidateRect(hwndInput, NULL, TRUE);
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// Debugprintf("Thumb = %d Point.y = %d - Not Scrolling", OPData->Thumb, Point.y);
|
|
|
|
|
|
if (!OPData->Scrolled)
|
|
|
{
|
|
|
OPData->Scrolled = TRUE;
|
|
|
InvalidateRect(hwndInput, NULL, TRUE);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
VOID AddLinetoWindow(struct RTFTerm * OPData, TCHAR * Line)
|
|
|
{
|
|
|
int Len = wcslen(Line);
|
|
|
TCHAR * ptr1 = Line;
|
|
|
TCHAR * ptr2;
|
|
|
int l, Index;
|
|
|
TCHAR LineCopy[LINELEN * 2];
|
|
|
|
|
|
if (Line[0] == 0x1b && Len > 1)
|
|
|
{
|
|
|
// Save Colour Char
|
|
|
|
|
|
OPData->CurrentColour = Line[1] - 10;
|
|
|
ptr1 +=2;
|
|
|
Len -= 2;
|
|
|
}
|
|
|
|
|
|
wcscpy(OPData->OutputScreen[OPData->CurrentLine], ptr1);
|
|
|
|
|
|
// Look for chars we need to escape (\ { })
|
|
|
|
|
|
ptr1 = OPData->OutputScreen[OPData->CurrentLine];
|
|
|
Index = 0;
|
|
|
ptr2 = wcschr(ptr1, L'\\'); // Look for Backslash first, as we may add some later
|
|
|
|
|
|
if (ptr2)
|
|
|
{
|
|
|
while (ptr2)
|
|
|
{
|
|
|
l = ++ptr2 - ptr1;
|
|
|
memcpy(&LineCopy[Index], ptr1, l * 2); // Copy Including found char (\)
|
|
|
Index += l;
|
|
|
LineCopy[Index++] = L'\\'; // Add second \
|
|
|
Len++;
|
|
|
ptr1 = ptr2;
|
|
|
ptr2 = wcschr(ptr1, L'\\');
|
|
|
}
|
|
|
|
|
|
wcscpy(&LineCopy[Index], ptr1); // Copy in rest
|
|
|
wcscpy(OPData->OutputScreen[OPData->CurrentLine], LineCopy);
|
|
|
}
|
|
|
|
|
|
ptr1 = OPData->OutputScreen[OPData->CurrentLine];
|
|
|
Index = 0;
|
|
|
ptr2 = wcschr(ptr1, L'{');
|
|
|
|
|
|
if (ptr2)
|
|
|
{
|
|
|
while (ptr2)
|
|
|
{
|
|
|
l = ptr2 - ptr1;
|
|
|
memcpy(&LineCopy[Index], ptr1, l * 2);
|
|
|
Index += l;
|
|
|
LineCopy[Index++] = L'\\';
|
|
|
LineCopy[Index++] = L'{';
|
|
|
Len++;
|
|
|
ptr1 = ++ptr2;
|
|
|
ptr2 = wcschr(ptr1, L'{');
|
|
|
}
|
|
|
wcscpy(&LineCopy[Index], ptr1); // Copy in rest
|
|
|
wcscpy(OPData->OutputScreen[OPData->CurrentLine], LineCopy);
|
|
|
}
|
|
|
|
|
|
ptr1 = OPData->OutputScreen[OPData->CurrentLine];
|
|
|
Index = 0;
|
|
|
ptr2 = wcschr(ptr1, '}'); // Look for Backslash first, as we may add some later
|
|
|
|
|
|
if (ptr2)
|
|
|
{
|
|
|
while (ptr2)
|
|
|
{
|
|
|
l = ptr2 - ptr1;
|
|
|
memcpy(&LineCopy[Index], ptr1, l * 2); // Copy
|
|
|
Index += l;
|
|
|
LineCopy[Index++] = L'\\';
|
|
|
LineCopy[Index++] = L'}';
|
|
|
Len++;
|
|
|
ptr1 = ++ptr2;
|
|
|
ptr2 = wcschr(ptr1, L'}');
|
|
|
}
|
|
|
wcscpy(&LineCopy[Index], ptr1); // Copy in rest
|
|
|
wcscpy(OPData->OutputScreen[OPData->CurrentLine], LineCopy);
|
|
|
}
|
|
|
|
|
|
|
|
|
OPData->Colourvalue[OPData->CurrentLine] = OPData->CurrentColour;
|
|
|
OPData->LineLen[OPData->CurrentLine++] = Len;
|
|
|
if (OPData->CurrentLine >= MAXLINES) OPData->CurrentLine = 0;
|
|
|
}
|
|
|
|
|
|
VOID WritetoOutputWindow(struct RTFTerm * OPData, TCHAR * Msg, int len)
|
|
|
{
|
|
|
time_t NOW = time(NULL);
|
|
|
TCHAR * ptr1, * ptr2;
|
|
|
|
|
|
if (AlertInterval && (NOW - LastWrite) > AlertInterval)
|
|
|
{
|
|
|
if (AlertBeep)
|
|
|
Beep(AlertFreq, AlertDuration);
|
|
|
else
|
|
|
PlaySound(AlertFileName, NULL, SND_FILENAME | SND_ASYNC);
|
|
|
}
|
|
|
|
|
|
|
|
|
LastWrite = NOW;
|
|
|
|
|
|
if (PartLinePtr != 0)
|
|
|
{
|
|
|
OPData->CurrentLine--; // Overwrite part line in buffer
|
|
|
if (OPData->CurrentLine < 0)
|
|
|
OPData->CurrentLine = MAXLINES - 1;
|
|
|
|
|
|
if (Msg[0] == 0x1b && len > 1)
|
|
|
{
|
|
|
Msg += 2; // Remove Colour Escape
|
|
|
len -= 2;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
memcpy(&readbuff[PartLinePtr], Msg, len * 2);
|
|
|
|
|
|
len += PartLinePtr;
|
|
|
|
|
|
ptr1=&readbuff[0];
|
|
|
readbuff[len]=0;
|
|
|
|
|
|
if (Bells)
|
|
|
{
|
|
|
do {
|
|
|
ptr2 = wmemchr(ptr1,7,len);
|
|
|
|
|
|
if (ptr2)
|
|
|
{
|
|
|
*(ptr2)=32;
|
|
|
Beep(440,250);
|
|
|
}
|
|
|
} while (ptr2);
|
|
|
}
|
|
|
|
|
|
lineloop:
|
|
|
|
|
|
if (len > 0)
|
|
|
{
|
|
|
// copy text to buffer a line at a time
|
|
|
|
|
|
ptr2=wmemchr(ptr1, 13, len);
|
|
|
|
|
|
if (ptr2 == 0)
|
|
|
{
|
|
|
// no newline. Move data to start of buffer and Save pointer
|
|
|
|
|
|
while (len > LINELEN)
|
|
|
{
|
|
|
// Break up
|
|
|
|
|
|
TCHAR * partptr = ptr1 + LINELEN;
|
|
|
TCHAR Save = *partptr;
|
|
|
*ptr1 = 0;
|
|
|
AddLinetoWindow(OPData, ptr1);
|
|
|
*partptr = Save;
|
|
|
ptr1 = partptr;
|
|
|
len -= LINELEN;
|
|
|
}
|
|
|
|
|
|
PartLinePtr = len;
|
|
|
memmove(readbuff, ptr1, len * 2);
|
|
|
AddLinetoWindow(OPData, ptr1);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
*(ptr2++)=0;
|
|
|
|
|
|
if (LogOutput) WriteMonitorLine(ptr1, ptr2 - ptr1);
|
|
|
|
|
|
// If len is greater that screen with, fold
|
|
|
|
|
|
if ((ptr2 - ptr1) > maxlinelen)
|
|
|
{
|
|
|
TCHAR * ptr3;
|
|
|
TCHAR * saveptr1 = ptr1;
|
|
|
int linelen = ptr2 - ptr1;
|
|
|
int foldlen;
|
|
|
TCHAR save;
|
|
|
|
|
|
foldloop:
|
|
|
|
|
|
ptr3 = ptr1 + maxlinelen;
|
|
|
|
|
|
while(*ptr3!= 0x20 && ptr3 > ptr1)
|
|
|
{
|
|
|
ptr3--;
|
|
|
}
|
|
|
foldlen = ptr3 - ptr1 ;
|
|
|
|
|
|
if (foldlen == 0)
|
|
|
{
|
|
|
// No space before, so split at width
|
|
|
|
|
|
foldlen = maxlinelen;
|
|
|
ptr3 = ptr1 + maxlinelen;
|
|
|
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
ptr3++ ; // Omit space
|
|
|
linelen--;
|
|
|
}
|
|
|
save = ptr1[foldlen];
|
|
|
ptr1[foldlen] = 0;
|
|
|
|
|
|
AddLinetoWindow(OPData, ptr1);
|
|
|
|
|
|
ptr1[foldlen] = save;
|
|
|
linelen -= foldlen;
|
|
|
ptr1 = ptr3;
|
|
|
|
|
|
if (linelen > maxlinelen)
|
|
|
goto foldloop;
|
|
|
|
|
|
AddLinetoWindow(OPData, ptr1);
|
|
|
ptr1 = saveptr1;
|
|
|
|
|
|
}
|
|
|
else
|
|
|
AddLinetoWindow(OPData, ptr1);
|
|
|
|
|
|
|
|
|
PartLinePtr=0;
|
|
|
|
|
|
len-=(ptr2-ptr1);
|
|
|
|
|
|
ptr1=ptr2;
|
|
|
|
|
|
if ((len > 0) && StripLF)
|
|
|
{
|
|
|
if (*ptr1 == 0x0a) // Line Feed
|
|
|
{
|
|
|
ptr1++;
|
|
|
len--;
|
|
|
}
|
|
|
}
|
|
|
goto lineloop;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TCHAR MonSave[2000];
|
|
|
int MonSaveLen;
|
|
|
|
|
|
VOID WritetoMonWindow(TCHAR * Msg, int len)
|
|
|
{
|
|
|
TCHAR * ptr1 = Msg, * ptr2;
|
|
|
int index;
|
|
|
|
|
|
if (MonSaveLen)
|
|
|
{
|
|
|
// Have part line - append to it
|
|
|
memcpy(&MonSave[MonSaveLen], Msg, len * 2);
|
|
|
MonSaveLen += len;
|
|
|
ptr1 = MonSave;
|
|
|
len = MonSaveLen;
|
|
|
MonSaveLen = 0;
|
|
|
}
|
|
|
|
|
|
lineloop:
|
|
|
|
|
|
if (len <= 0)
|
|
|
return;
|
|
|
|
|
|
// copy text to control a line at a time
|
|
|
|
|
|
ptr2 = wmemchr(ptr1,13,len);
|
|
|
|
|
|
if (ptr2 == 0) // No CR
|
|
|
{
|
|
|
memmove(MonSave, ptr1, len * 2);
|
|
|
MonSaveLen = len;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
*(ptr2++) = 0;
|
|
|
|
|
|
index = SendMessage(hwndMon, LB_ADDSTRING, 0, (LPARAM)(LPCTSTR) ptr1 );
|
|
|
|
|
|
if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1);
|
|
|
|
|
|
if (index > 1200)
|
|
|
do {index=SendMessage(hwndMon,LB_DELETESTRING, 0, 0);} while (index > 1000);
|
|
|
|
|
|
SendMessage(hwndMon,LB_SETCARETINDEX,(WPARAM) index, MAKELPARAM(FALSE, 0));
|
|
|
|
|
|
len -= (ptr2 - ptr1);
|
|
|
ptr1 = ptr2;
|
|
|
|
|
|
goto lineloop;
|
|
|
}
|
|
|
|
|
|
VOID DisableConnectMenu(HWND hWnd)
|
|
|
{
|
|
|
int n;
|
|
|
|
|
|
for (n = 0; n < MAXHOSTS; n++)
|
|
|
EnableMenuItem(GetMenu(hWnd), BPQCONNECT1 + n, MF_GRAYED);
|
|
|
|
|
|
DrawMenuBar(hWnd);
|
|
|
}
|
|
|
|
|
|
VOID DisableDisconnectMenu(HWND hWnd)
|
|
|
{
|
|
|
EnableMenuItem(GetMenu(hWnd), BPQDISCONNECT, MF_GRAYED);
|
|
|
DrawMenuBar(hWnd);
|
|
|
}
|
|
|
|
|
|
VOID DisableYAPPMenu(HWND hWnd)
|
|
|
{
|
|
|
EnableMenuItem(GetMenu(hWnd), YAPPSEND, MF_GRAYED);
|
|
|
DrawMenuBar(hWnd);
|
|
|
}
|
|
|
|
|
|
VOID EnableYAPPMenu(HWND hWnd)
|
|
|
{
|
|
|
EnableMenuItem(GetMenu(hWnd), YAPPSEND, MF_ENABLED);
|
|
|
DrawMenuBar(hWnd);
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID EnableConnectMenu(HWND hWnd)
|
|
|
{
|
|
|
HMENU hMenu; // handle of menu
|
|
|
int n;
|
|
|
|
|
|
hMenu=GetMenu(hWnd);
|
|
|
|
|
|
for (n = 0; n < MAXHOSTS; n++)
|
|
|
EnableMenuItem(hMenu, BPQCONNECT1 + n, MF_ENABLED);
|
|
|
|
|
|
DrawMenuBar(hWnd);
|
|
|
}
|
|
|
|
|
|
VOID EnableDisconnectMenu(HWND hWnd)
|
|
|
{
|
|
|
EnableMenuItem(GetMenu(hWnd), BPQDISCONNECT, MF_ENABLED);
|
|
|
DrawMenuBar(hWnd);
|
|
|
}
|
|
|
|
|
|
|
|
|
int TogglePort(HWND hWnd, int Item, int mask)
|
|
|
{
|
|
|
portmask ^= mask;
|
|
|
|
|
|
if (portmask & mask)
|
|
|
CheckMenuItem(hMenu,Item,MF_CHECKED);
|
|
|
else
|
|
|
CheckMenuItem(hMenu,Item,MF_UNCHECKED);
|
|
|
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
}
|
|
|
int ToggleMTX(HWND hWnd)
|
|
|
{
|
|
|
mtxparam = mtxparam ^ 1;
|
|
|
CheckMenuItem(hMenu, BPQMTX, (mtxparam) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
}
|
|
|
int ToggleMCOM(HWND hWnd)
|
|
|
{
|
|
|
mcomparam = mcomparam ^ 1;
|
|
|
CheckMenuItem(hMenu, BPQMCOM, (mcomparam) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
}
|
|
|
int ToggleMUI(HWND hWnd)
|
|
|
{
|
|
|
monUI = monUI ^ 1;
|
|
|
CheckMenuItem(hMenu, MUIONLY, (monUI) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return (0);
|
|
|
|
|
|
}
|
|
|
int ToggleParam(HWND hWnd, BOOL * Param, int Item)
|
|
|
{
|
|
|
*Param = !(*Param);
|
|
|
|
|
|
CheckMenuItem(hMenu,Item, (*Param) ? MF_CHECKED : MF_UNCHECKED);
|
|
|
|
|
|
return (0);
|
|
|
}
|
|
|
|
|
|
void MoveWindows()
|
|
|
{
|
|
|
RECT rcMain, rcClient;
|
|
|
int ClientHeight, ClientWidth;
|
|
|
|
|
|
GetWindowRect(hWnd, &rcMain);
|
|
|
GetClientRect(hWnd, &rcClient);
|
|
|
|
|
|
ClientHeight = rcClient.bottom;
|
|
|
ClientWidth = rcClient.right;
|
|
|
|
|
|
if (ClientWidth == 0) // Minimized
|
|
|
return;
|
|
|
|
|
|
OutputBoxHeight = ClientHeight - SplitPos - InputBoxHeight - SplitBarHeight - SplitBarHeight;
|
|
|
|
|
|
MoveWindow(hwndMon,2, 0, ClientWidth-4, SplitPos, TRUE);
|
|
|
MoveWindow(hwndOutput,2, SplitPos+SplitBarHeight, ClientWidth-4, OutputBoxHeight, TRUE);
|
|
|
MoveWindow(hwndInput,2, ClientHeight-InputBoxHeight-2, ClientWidth-4, InputBoxHeight, TRUE);
|
|
|
MoveWindow(hwndSplit,0, SplitPos, ClientWidth, SplitBarHeight, TRUE);
|
|
|
|
|
|
GetClientRect(hwndOutput, &rcClient);
|
|
|
|
|
|
ClientHeight = rcClient.bottom;
|
|
|
ClientWidth = rcClient.right;
|
|
|
|
|
|
if (ClientWidth > 16)
|
|
|
maxlinelen = ClientWidth/OutputData.CharWidth - 1;
|
|
|
|
|
|
InvalidateRect(hWnd, NULL, TRUE);
|
|
|
}
|
|
|
|
|
|
void CopyRichTextToClipboard(HWND hWnd)
|
|
|
{
|
|
|
int len=0;
|
|
|
HGLOBAL hMem;
|
|
|
char * ptr;
|
|
|
|
|
|
// Copy Rich Text to Clipboard
|
|
|
|
|
|
len = SendMessage(hwndOutput, WM_GETTEXTLENGTH, 0, 0);
|
|
|
|
|
|
hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len + 1)*2);
|
|
|
|
|
|
if (hMem != 0)
|
|
|
{
|
|
|
ptr=GlobalLock(hMem);
|
|
|
|
|
|
if (OpenClipboard(MainWnd))
|
|
|
{
|
|
|
len = SendMessage(hwndOutput, WM_GETTEXT , len, (LPARAM)ptr);
|
|
|
|
|
|
GlobalUnlock(hMem);
|
|
|
EmptyClipboard();
|
|
|
SetClipboardData(CF_UNICODETEXT,hMem);
|
|
|
CloseClipboard();
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
GlobalFree(hMem);
|
|
|
}
|
|
|
|
|
|
|
|
|
void CopyListToClipboard(HWND hWnd)
|
|
|
{
|
|
|
int i,n, len=0;
|
|
|
HGLOBAL hMem;
|
|
|
char * ptr;
|
|
|
//
|
|
|
// Copy List Box to clipboard
|
|
|
//
|
|
|
|
|
|
n = SendMessage(hWnd, LB_GETCOUNT, 0, 0);
|
|
|
|
|
|
for (i=0; i<n; i++)
|
|
|
{
|
|
|
len+=SendMessage(hWnd, LB_GETTEXTLEN, i, 0);
|
|
|
}
|
|
|
|
|
|
hMem=GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, (len+n+n+1)*2);
|
|
|
|
|
|
|
|
|
if (hMem != 0)
|
|
|
{
|
|
|
ptr=GlobalLock(hMem);
|
|
|
|
|
|
if (OpenClipboard(MainWnd))
|
|
|
{
|
|
|
// CopyScreentoBuffer(GlobalLock(hMem));
|
|
|
|
|
|
for (i=0; i<n; i++)
|
|
|
{
|
|
|
len=SendMessage(hWnd, LB_GETTEXT, i, (LPARAM) ptr);
|
|
|
ptr += len;
|
|
|
ptr += len; // 2 bytes per char
|
|
|
*(ptr++)=13;
|
|
|
*(ptr++)=0;
|
|
|
*(ptr++)=10;
|
|
|
*(ptr++)=0;
|
|
|
}
|
|
|
|
|
|
*(ptr)=0; // end of data
|
|
|
|
|
|
GlobalUnlock(hMem);
|
|
|
EmptyClipboard();
|
|
|
SetClipboardData(CF_UNICODETEXT,hMem);
|
|
|
CloseClipboard();
|
|
|
}
|
|
|
else
|
|
|
GlobalFree(hMem);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
BOOL OpenMonitorLogfile()
|
|
|
{
|
|
|
TCHAR FN[MAX_PATH];
|
|
|
|
|
|
wsprintf(FN,L"BPQTerm_%d.log", Stream);
|
|
|
|
|
|
MonHandle = CreateFile(FN,
|
|
|
GENERIC_WRITE,
|
|
|
FILE_SHARE_READ,
|
|
|
NULL,
|
|
|
OPEN_ALWAYS,
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
NULL);
|
|
|
|
|
|
SetFilePointer(MonHandle, 0, 0, FILE_END);
|
|
|
|
|
|
return (MonHandle != INVALID_HANDLE_VALUE);
|
|
|
}
|
|
|
|
|
|
void WriteMonitorLine(TCHAR * Msg, int MsgLen)
|
|
|
{
|
|
|
int cnt;
|
|
|
char CRLF[2] = {0x0d,0x0a};
|
|
|
unsigned char MsgB[1000];
|
|
|
|
|
|
if (MonHandle == INVALID_HANDLE_VALUE) OpenMonitorLogfile();
|
|
|
|
|
|
if (MonHandle == INVALID_HANDLE_VALUE) return;
|
|
|
|
|
|
MsgLen = WideCharToMultiByte(TXMode, 0, Msg, MsgLen, MsgB, 1000, NULL, NULL);
|
|
|
|
|
|
WriteFile(MonHandle ,MsgB , MsgLen, &cnt, NULL);
|
|
|
WriteFile(MonHandle ,CRLF , 2, &cnt, NULL);
|
|
|
}
|
|
|
|
|
|
// TCP Interface
|
|
|
|
|
|
TCPConnect(TCHAR * Host, int Port)
|
|
|
{
|
|
|
int err, status;
|
|
|
u_long param=1;
|
|
|
UCHAR bcopt = 1;
|
|
|
int optlen = 1;
|
|
|
SOCKADDR_IN sinx;
|
|
|
|
|
|
int addrlen=sizeof(sinx);
|
|
|
char PortString[10];
|
|
|
char HostB[256];
|
|
|
struct addrinfo hints, *res;
|
|
|
BOOL UseV6 = FALSE;
|
|
|
|
|
|
|
|
|
wcstombs(HostB, Host, 256);
|
|
|
sprintf(PortString, "%d", Port);
|
|
|
|
|
|
if (_memicmp(HostB, "ipv6:", 5) == 0)
|
|
|
UseV6 = TRUE;
|
|
|
|
|
|
// get host info, make socket, and connect it
|
|
|
|
|
|
memset(&hints, 0, sizeof hints);
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
|
|
if (UseV6)
|
|
|
{
|
|
|
hints.ai_family = AF_INET6; // use IPv6
|
|
|
getaddrinfo(&HostB[5], PortString, &hints, &res);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
|
|
|
getaddrinfo(HostB, PortString, &hints, &res);
|
|
|
}
|
|
|
|
|
|
if (!res)
|
|
|
{
|
|
|
MessageBox(NULL, L"Resolve HostName Failed", L"BPQTermTCP", MB_OK);
|
|
|
wsprintf(Title, L"BPQTermTCP Version %s - Disconnected", VersionStringW);
|
|
|
SetWindowText(hWnd,Title);
|
|
|
|
|
|
return FALSE; // Resolve failed
|
|
|
}
|
|
|
|
|
|
sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
|
|
|
|
|
|
WSAAsyncSelect(sock, hWnd, WSA_DATA,
|
|
|
FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
|
|
|
|
|
|
/*
|
|
|
|
|
|
// Resolve Name if needed
|
|
|
|
|
|
destaddr.sin_family = AF_INET;
|
|
|
destaddr.sin_port = htons(Port);
|
|
|
destaddr.sin_addr.s_addr = inet_addr(Host);
|
|
|
|
|
|
if (destaddr.sin_addr.s_addr == INADDR_NONE)
|
|
|
{
|
|
|
struct hostent * HostEnt;
|
|
|
|
|
|
// Resolve name to address
|
|
|
|
|
|
wsprintf(Title,"BPQTermTCP Version %s - Resolving %s", VersionString, Host);
|
|
|
SetWindowText(hWnd,Title);
|
|
|
|
|
|
HostEnt = gethostbyname(Host);
|
|
|
|
|
|
if (!HostEnt)
|
|
|
{
|
|
|
MessageBox(NULL, "Resolve HostName Failed", "BPQTermTCP", MB_OK);
|
|
|
wsprintf(Title,"BPQTermTCP Version %s - Disconnected", VersionString);
|
|
|
SetWindowText(hWnd,Title);
|
|
|
|
|
|
return FALSE; // Resolve failed
|
|
|
}
|
|
|
|
|
|
i = 0;
|
|
|
|
|
|
memcpy(&destaddr.sin_addr.s_addr, HostEnt->h_addr, 4);
|
|
|
}
|
|
|
|
|
|
ioctlsocket (sock, FIONBIO, ¶m);
|
|
|
|
|
|
setsockopt (sock, 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(sock, (LPSOCKADDR) &sinx, addrlen) != 0 )
|
|
|
{
|
|
|
MessageBox(NULL, "Bind Failed", "BPQTermTCP", MB_OK);
|
|
|
return FALSE;
|
|
|
}
|
|
|
*/
|
|
|
if ((status = WSAAsyncSelect(sock, hWnd, WSA_CONNECT, FD_CONNECT)) > 0)
|
|
|
{
|
|
|
closesocket(sock);
|
|
|
return FALSE;
|
|
|
}
|
|
|
|
|
|
if (connect(sock, res->ai_addr, res->ai_addrlen) == 0)
|
|
|
{
|
|
|
//
|
|
|
// Connected successful
|
|
|
//
|
|
|
|
|
|
return TRUE;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
err=WSAGetLastError();
|
|
|
|
|
|
if (err == WSAEWOULDBLOCK)
|
|
|
{
|
|
|
// Connect in Progress
|
|
|
|
|
|
wsprintf(Title,L"BPQTermTCP Version %s - Connecting to %s", VersionStringW, Host);
|
|
|
SetWindowText(hWnd,Title);
|
|
|
|
|
|
EnableDisconnectMenu(hWnd);
|
|
|
DisableConnectMenu(hWnd);
|
|
|
|
|
|
return TRUE;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// Connect failed
|
|
|
|
|
|
closesocket(sock);
|
|
|
MessageBox(NULL, L"Connect Failed", L"BPQTermTCP", MB_OK);
|
|
|
return FALSE;
|
|
|
}
|
|
|
}
|
|
|
return FALSE;
|
|
|
}
|
|
|
|
|
|
int Telnet_Connected(SOCKET sock, int Error)
|
|
|
{
|
|
|
TCHAR Msg[80];
|
|
|
int Len;
|
|
|
int i = 1;
|
|
|
BOOL bcopt = TRUE;
|
|
|
|
|
|
// Connect Complete
|
|
|
|
|
|
if (Error)
|
|
|
{
|
|
|
closesocket(sock);
|
|
|
Connecting = FALSE;
|
|
|
SocketActive = FALSE;
|
|
|
|
|
|
wsprintf(Title,L"BPQTermTCP Version %s - Disconnected", VersionStringW);
|
|
|
SetWindowText(hWnd,Title);
|
|
|
DisableDisconnectMenu(hWnd);
|
|
|
DisableYAPPMenu(hWnd);
|
|
|
EnableConnectMenu(hWnd);
|
|
|
|
|
|
wsprintf(Msg, L"Connect Failed - Error %d\r", Error);
|
|
|
MessageBox(NULL, Msg, L"BPQTermTCP", MB_OK);
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
WSAAsyncSelect(sock, hWnd, WSA_DATA, FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
|
|
|
|
|
|
SocketActive = TRUE;
|
|
|
Connecting = FALSE;
|
|
|
Connected = TRUE;
|
|
|
InputMode = 0;
|
|
|
|
|
|
// Reset Monitor Menu
|
|
|
|
|
|
// Remove old menu
|
|
|
|
|
|
while (i)
|
|
|
{
|
|
|
i = RemoveMenu(hPopMenu1, 6, MF_BYPOSITION);
|
|
|
}
|
|
|
|
|
|
for (i = 1; i <= MonPorts; i++)
|
|
|
{
|
|
|
wsprintf(Msg,L"Port %d",i);
|
|
|
|
|
|
if (portmask & ((uint64_t)1<<(i-1)))
|
|
|
{
|
|
|
AppendMenu(hPopMenu1,MF_STRING | MF_CHECKED,BPQBASE + i, &Msg[0]);
|
|
|
portmask |= ((uint64_t)1<<(i-1));
|
|
|
}
|
|
|
else
|
|
|
AppendMenu(hPopMenu1,MF_STRING | MF_UNCHECKED,BPQBASE + i, &Msg[0]);
|
|
|
}
|
|
|
|
|
|
|
|
|
Len = wsprintf(Msg, L"%s\r%s\rBPQTermTCP\r", UserName[CurrentHost], Password[CurrentHost]);
|
|
|
|
|
|
SendMsg(Msg, Len);
|
|
|
|
|
|
SendTraceOptions();
|
|
|
|
|
|
SlowTimer = 0;
|
|
|
|
|
|
wsprintf(Title, L"BPQTermTCP Version %s - Connected to %s", VersionStringW, Host[CurrentHost]);
|
|
|
SetWindowText(hWnd,Title);
|
|
|
DisableConnectMenu(hWnd);
|
|
|
EnableDisconnectMenu(hWnd);
|
|
|
EnableYAPPMenu(hWnd);
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
VOID Socket_Accept(int SocketId, int error, int eventcode)
|
|
|
{
|
|
|
int i = 1, addrlen = sizeof(struct sockaddr_in6);
|
|
|
struct sockaddr_in sin;
|
|
|
unsigned char work[4];
|
|
|
|
|
|
u_long param=1;
|
|
|
|
|
|
sock = accept(SocketId, (struct sockaddr *)&sin, &addrlen);
|
|
|
|
|
|
WSAAsyncSelect(sock, hWnd, WSA_DATA, FD_READ | FD_WRITE | FD_OOB | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
|
|
|
|
|
|
SocketActive = TRUE;
|
|
|
Connecting = FALSE;
|
|
|
Connected = TRUE;
|
|
|
|
|
|
// Reset Monitor Menu
|
|
|
|
|
|
// Remove old menu
|
|
|
|
|
|
while (i)
|
|
|
{
|
|
|
i = RemoveMenu(hPopMenu1, 6, MF_BYPOSITION);
|
|
|
}
|
|
|
|
|
|
// Len = wsprintf(Msg, L"Connected to BPQTermTCP\r");
|
|
|
// SendMsg(Msg, Len);
|
|
|
|
|
|
// SendTraceOptions();
|
|
|
|
|
|
SlowTimer = 0;
|
|
|
|
|
|
memcpy(work, &sin.sin_addr.s_addr, 4);
|
|
|
wsprintf(Title, L"BPQTermTCP Version %s - Incoming Connection from %d.%d.%d.%d", VersionStringW, work[0], work[1], work[2], work[3]);
|
|
|
SetWindowText(hWnd,Title);
|
|
|
DisableConnectMenu(hWnd);
|
|
|
EnableDisconnectMenu(hWnd);
|
|
|
|
|
|
if (AlertFileName[0])
|
|
|
PlaySound(AlertFileName, NULL, SND_FILENAME | SND_ASYNC);
|
|
|
else
|
|
|
Beep(AlertFreq, AlertDuration);
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID Socket_Data(int sock, int error, int eventcode)
|
|
|
{
|
|
|
TCHAR Title[100];
|
|
|
|
|
|
switch (eventcode)
|
|
|
{
|
|
|
case FD_READ:
|
|
|
|
|
|
DataSocket_Read(sock);
|
|
|
return;
|
|
|
|
|
|
case FD_WRITE:
|
|
|
case FD_OOB:
|
|
|
case FD_ACCEPT:
|
|
|
case FD_CONNECT:
|
|
|
|
|
|
return;
|
|
|
|
|
|
case FD_CLOSE:
|
|
|
|
|
|
if (SocketActive)
|
|
|
closesocket(sock);
|
|
|
|
|
|
if (ListenOn)
|
|
|
wsprintf(Title, L"BPQTermTCP Version %s Listening for Calls", VersionStringW);
|
|
|
else
|
|
|
wsprintf(Title, L"BPQTermTCP Version %s - Disconnected", VersionStringW);
|
|
|
|
|
|
SetWindowText(hWnd,Title);
|
|
|
DisableDisconnectMenu(hWnd);
|
|
|
DisableYAPPMenu(hWnd);
|
|
|
|
|
|
if (ListenOn == 0)
|
|
|
EnableConnectMenu(hWnd);
|
|
|
|
|
|
WritetoOutputWindow(&OutputData, L"*** Disconnected\r", 17);
|
|
|
DoRefresh(&OutputData);
|
|
|
SocketActive = FALSE;
|
|
|
Connected = FALSE;
|
|
|
Disconnecting = FALSE;
|
|
|
return ;
|
|
|
}
|
|
|
return ;
|
|
|
}
|
|
|
int TrytoGuessCode(unsigned char * Char, int Len)
|
|
|
{
|
|
|
int Above127 = 0;
|
|
|
int LineDraw = 0;
|
|
|
int NumericAndSpaces = 0;
|
|
|
int n;
|
|
|
|
|
|
for (n = 0; n < Len; n++)
|
|
|
{
|
|
|
if (Char[n] < 65)
|
|
|
{
|
|
|
NumericAndSpaces++;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (Char[n] > 127)
|
|
|
{
|
|
|
Above127++;
|
|
|
if (Char[n] > 178 && Char[n] < 219)
|
|
|
{
|
|
|
LineDraw++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (Above127 == 0) // DOesn't really matter!
|
|
|
return CP1252;
|
|
|
|
|
|
if (Above127 == LineDraw)
|
|
|
return CP437; // If only Line Draw chars, assume line draw
|
|
|
|
|
|
// If mainly below 128, it is probably Latin if mainly above, probably Cyrillic
|
|
|
|
|
|
if ((Len - (NumericAndSpaces + Above127)) < Above127)
|
|
|
return CP1251;
|
|
|
else
|
|
|
return CP1252;
|
|
|
}
|
|
|
|
|
|
VOID DataSocket_Read(SOCKET sock)
|
|
|
{
|
|
|
int len = 0, MonLen, wlen, err = 0, newlen;
|
|
|
unsigned char Buffer[2000];
|
|
|
UCHAR * ptr;
|
|
|
UCHAR * Buffptr;
|
|
|
UCHAR * FEptr = 0;
|
|
|
TCHAR BufferW[2000];
|
|
|
|
|
|
ioctlsocket(sock, FIONREAD, &len);
|
|
|
|
|
|
if (len > 2000) len = 2000;
|
|
|
|
|
|
len = recv(sock, Buffer, len, 0);
|
|
|
|
|
|
if (len == SOCKET_ERROR || len == 0)
|
|
|
{
|
|
|
// Failed or closed - clear connection
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (InputMode == 'Y') // Yapp
|
|
|
{
|
|
|
ProcessYAPPMessage(Buffer, len);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// mbstowcs(Buffer, BufferB, len);
|
|
|
|
|
|
// Look for MON delimiters (FF/FE)
|
|
|
|
|
|
Buffptr = Buffer;
|
|
|
|
|
|
if (MonData)
|
|
|
{
|
|
|
// Already in MON State
|
|
|
|
|
|
FEptr = memchr(Buffptr, 0xfe, len);
|
|
|
|
|
|
if (!FEptr)
|
|
|
{
|
|
|
// no FE - so send all to monitor
|
|
|
|
|
|
len = MultiByteToWideChar(CP_UTF8, 0, Buffptr, len, BufferW, 2000);
|
|
|
|
|
|
if (len == 0)
|
|
|
return;
|
|
|
|
|
|
WritetoMonWindow(BufferW, len);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
MonData = FALSE;
|
|
|
|
|
|
MonLen = FEptr - Buffptr; // Mon Data, Excluding the FE
|
|
|
|
|
|
wlen = MultiByteToWideChar(CP_UTF8, 0, Buffptr, MonLen, BufferW, 2000);
|
|
|
|
|
|
if (wlen == 0)
|
|
|
return;
|
|
|
|
|
|
WritetoMonWindow(BufferW, wlen);
|
|
|
|
|
|
Buffptr = ++FEptr; // Char following FE
|
|
|
|
|
|
if (++MonLen < len)
|
|
|
{
|
|
|
len -= MonLen;
|
|
|
goto MonLoop; // See if next in MON or Data
|
|
|
}
|
|
|
|
|
|
// Nothing Left
|
|
|
|
|
|
DoRefresh(&OutputData);
|
|
|
return ;
|
|
|
}
|
|
|
|
|
|
MonLoop:
|
|
|
|
|
|
if (ptr = memchr(Buffptr, 0xff, len))
|
|
|
{
|
|
|
// Buffer contains Mon Data
|
|
|
|
|
|
if (ptr > Buffptr)
|
|
|
{
|
|
|
// Some Normal Data before the FF
|
|
|
|
|
|
int NormLen = ptr - Buffptr; // Before the FF
|
|
|
|
|
|
if (NormLen == 1 && Buffptr[0] == 0)
|
|
|
{
|
|
|
// Keepalive
|
|
|
}
|
|
|
|
|
|
else
|
|
|
{
|
|
|
CheckKeyWords(Buffptr, NormLen);
|
|
|
|
|
|
wlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, Buffptr, NormLen, BufferW, 2000);
|
|
|
|
|
|
err = GetLastError();
|
|
|
|
|
|
if (err == ERROR_NO_UNICODE_TRANSLATION)
|
|
|
{
|
|
|
// Input isn't UTF 8. if RXMode = AURO, Try to figure out what it is, otherwise convert usong specified mode
|
|
|
|
|
|
if (RXMode == AUTO)
|
|
|
{
|
|
|
int Table = TrytoGuessCode(Buffptr, NormLen);
|
|
|
|
|
|
wlen = MultiByteToWideChar(Table, 0, Buffptr, NormLen, BufferW, 2000);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
wlen = MultiByteToWideChar(RXMode, 0, Buffptr, NormLen, BufferW, 2000);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (wlen)
|
|
|
WritetoOutputWindow(&OutputData, BufferW, wlen);
|
|
|
}
|
|
|
|
|
|
len -= NormLen;
|
|
|
Buffptr = ptr;
|
|
|
goto MonLoop;
|
|
|
}
|
|
|
|
|
|
if (ptr[1] == 0xff)
|
|
|
{
|
|
|
// Port Definition String
|
|
|
|
|
|
int NumberofPorts = atoi(&ptr[2]);
|
|
|
char *p, *Context;
|
|
|
int i = 1;
|
|
|
TCHAR msg[80];
|
|
|
TCHAR ID[80];
|
|
|
int portnum;
|
|
|
|
|
|
// Remove old menu
|
|
|
|
|
|
while (i)
|
|
|
{
|
|
|
i = RemoveMenu(hPopMenu1, 6, MF_BYPOSITION);
|
|
|
}
|
|
|
|
|
|
p = strtok_s(&ptr[2], "|", &Context);
|
|
|
|
|
|
while(NumberofPorts--)
|
|
|
{
|
|
|
p = strtok_s(NULL, "|", &Context);
|
|
|
if (p == NULL)
|
|
|
break;
|
|
|
|
|
|
portnum = atoi(p);
|
|
|
mbstowcs(ID, p, strlen(p) +1);
|
|
|
|
|
|
wsprintf(msg, L"Port %s", ID);
|
|
|
|
|
|
if (portmask & ((uint64_t)1<<(portnum - 1)))
|
|
|
AppendMenu(hPopMenu1,MF_STRING | MF_CHECKED,BPQBASE + portnum, &msg[0]);
|
|
|
else
|
|
|
AppendMenu(hPopMenu1,MF_STRING | MF_UNCHECKED,BPQBASE + portnum, &msg[0]);
|
|
|
|
|
|
i++;
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
MonData = TRUE;
|
|
|
|
|
|
FEptr = memchr(Buffptr, 0xfe, len);
|
|
|
|
|
|
if (FEptr)
|
|
|
{
|
|
|
MonData = FALSE;
|
|
|
|
|
|
MonLen = FEptr + 1 - Buffptr; // MonLen includes FF and FE
|
|
|
|
|
|
wlen = MultiByteToWideChar(CP_UTF8, 0, Buffptr + 1, MonLen - 2, BufferW, 2000);
|
|
|
|
|
|
if (wlen)
|
|
|
WritetoMonWindow(BufferW, wlen);
|
|
|
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
len -= MonLen;
|
|
|
Buffptr += MonLen; // Char Following FE
|
|
|
|
|
|
if (len <= 0)
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
goto MonLoop;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// No FE, so rest of buffer is MON Data
|
|
|
|
|
|
wlen = MultiByteToWideChar(CP_UTF8, 0, Buffptr + 1, MonLen - 1, BufferW, 2000); // Exclude FF
|
|
|
|
|
|
if (wlen == 0)
|
|
|
return;
|
|
|
|
|
|
WritetoMonWindow(BufferW, wlen);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// No FF, so must be session data
|
|
|
|
|
|
if (InputMode == 'Y') // Yapp
|
|
|
{
|
|
|
ProcessYAPPMessage(Buffer, len);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
if (len == 1 && Buffptr[0] == 0)
|
|
|
return; // Keepalive
|
|
|
|
|
|
// Could be a YAPP Header
|
|
|
|
|
|
|
|
|
if (len == 2 && Buffptr[0] == ENQ && Buffptr[1] == 1) // YAPP Send_Init
|
|
|
{
|
|
|
UCHAR YAPPRR[2];
|
|
|
char Mess[64];
|
|
|
|
|
|
// Turn off monitoring
|
|
|
|
|
|
len = sprintf(Mess, "\\\\\\\\%x %x %x %x %x %x %x %x\r", 0, 0, 0, 0, 0, 0, 0, 0);
|
|
|
send(sock, Mess, len, 0);
|
|
|
InputMode = 'Y';
|
|
|
|
|
|
YAPPRR[0] = ACK;
|
|
|
YAPPRR[1] = 1;
|
|
|
|
|
|
Sleep(1000); // To give Monitor Msg time to be sent
|
|
|
QueueMsg(YAPPRR, 2);
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
CheckKeyWords(Buffptr, len);
|
|
|
|
|
|
newlen = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, Buffptr, len, BufferW, 2000);
|
|
|
|
|
|
err = GetLastError();
|
|
|
|
|
|
if (err == ERROR_NO_UNICODE_TRANSLATION)
|
|
|
{
|
|
|
// Input isn't UTF 8. if RXMode = AURO, Try to figure out what it is, otherwise convert usong specified mode
|
|
|
|
|
|
if (RXMode == AUTO)
|
|
|
{
|
|
|
int Table = TrytoGuessCode(Buffptr, len);
|
|
|
|
|
|
newlen = MultiByteToWideChar(Table, 0, Buffptr, len, BufferW, 2000);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
newlen = MultiByteToWideChar(RXMode, 0, Buffptr, len, BufferW, 2000);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (newlen)
|
|
|
WritetoOutputWindow(&OutputData, BufferW, newlen);
|
|
|
|
|
|
DoRefresh(&OutputData);
|
|
|
SlowTimer = 0;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
int SendMsg(TCHAR * msg, int len)
|
|
|
{
|
|
|
unsigned char MsgB[1000];
|
|
|
|
|
|
len = WideCharToMultiByte(TXMode, 0, msg, len, MsgB, 1000, NULL, NULL);
|
|
|
|
|
|
send(sock, MsgB, len, 0);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
VOID SendTraceOptions()
|
|
|
{
|
|
|
char Buffer[80];
|
|
|
int Len = sprintf(Buffer, "\\\\\\\\%llx %x %x %x %x %x %x %x\r", portmask, mtxparam, mcomparam, MonitorNODES, MonitorColour, monUI, TXMode == CP_UTF8, 1);
|
|
|
mbstowcs(&MonParams[CurrentHost][0], &Buffer[4], Len - 4);
|
|
|
SaveStringValue(MON[CurrentHost], MonParams[CurrentHost]);
|
|
|
Sleep(1000); // To give YAPP Msg tome to be sent
|
|
|
send(sock, Buffer, Len, 0);
|
|
|
|
|
|
}
|
|
|
|
|
|
SOCKET OpenListenSocket4(int port)
|
|
|
{
|
|
|
struct sockaddr_in local_sin; /* Local socket - internet style */
|
|
|
struct sockaddr_in * psin;
|
|
|
SOCKET sock = 0;
|
|
|
u_long param=1;
|
|
|
WCHAR Msg[80];
|
|
|
|
|
|
psin=&local_sin;
|
|
|
psin->sin_family = AF_INET;
|
|
|
psin->sin_addr.s_addr = INADDR_ANY;
|
|
|
|
|
|
if (port)
|
|
|
{
|
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
|
{
|
|
|
wsprintf(Msg, L"socket() failed error %d", WSAGetLastError());
|
|
|
MessageBox(NULL, Msg, L"BPQTermTCP", MB_OK);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (char *)¶m,4);
|
|
|
|
|
|
psin->sin_port = htons(port); // Convert to network ordering
|
|
|
|
|
|
if (bind( sock, (struct sockaddr *) &local_sin, sizeof(local_sin)) == SOCKET_ERROR)
|
|
|
{
|
|
|
wsprintf(Msg, L"bind(sock) failed port %d Error %d", port, WSAGetLastError());
|
|
|
MessageBox(NULL, Msg, L"BPQTermTCP", MB_OK);
|
|
|
closesocket(sock);
|
|
|
return FALSE;
|
|
|
}
|
|
|
|
|
|
if (listen(sock, 4) < 0)
|
|
|
{
|
|
|
wsprintf(Msg, L"listen(sock) failed port %d Error %d", port, WSAGetLastError());
|
|
|
MessageBox(NULL, Msg, L"BPQTermTCP", MB_OK);
|
|
|
closesocket(sock);
|
|
|
}
|
|
|
|
|
|
WSAAsyncSelect(sock, hWnd, WSA_ACCEPT, FD_ACCEPT | FD_CLOSE);
|
|
|
}
|
|
|
return sock;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static unsigned int cp1251Map[256] = {
|
|
|
0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
|
|
|
0x0008, 0x0009, '\n', 0x000B, 0x000C, '\r', 0x000E, 0x000F,
|
|
|
0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
|
|
|
0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
|
|
|
0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, '\'',
|
|
|
0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
|
|
|
0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
|
|
|
0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
|
|
|
0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
|
|
|
0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
|
|
|
0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
|
|
|
0x0058, 0x0059, 0x005A, 0x005B, '\\', 0x005D, 0x005E, 0x005F,
|
|
|
0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
|
|
|
0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
|
|
|
0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
|
|
|
0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F,
|
|
|
0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021,
|
|
|
0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F,
|
|
|
0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
|
|
|
0xFFFD, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F,
|
|
|
0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7,
|
|
|
0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407,
|
|
|
0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7,
|
|
|
0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457,
|
|
|
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417,
|
|
|
0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
|
|
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427,
|
|
|
0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
|
|
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437,
|
|
|
0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
|
|
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447,
|
|
|
0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F
|
|
|
};
|
|
|
|
|
|
#define INCLUDEYAPP
|
|
|
#ifdef INCLUDEYAPP
|
|
|
|
|
|
|
|
|
// YAPP stuff
|
|
|
|
|
|
#define SOH 1
|
|
|
#define STX 2
|
|
|
#define ETX 3
|
|
|
#define EOT 4
|
|
|
#define ENQ 5
|
|
|
#define ACK 6
|
|
|
#define DLE 0x10
|
|
|
#define NAK 0x15
|
|
|
#define CAN 0x18
|
|
|
|
|
|
#define YAPPTX 32768 // Sending YAPP file
|
|
|
|
|
|
int MaxRXSize = 100000;
|
|
|
char BaseDir[256] = "";
|
|
|
|
|
|
UCHAR InputBuffer[1024];
|
|
|
|
|
|
UCHAR InputMode; // Line by Line or Binary or YAPP
|
|
|
int paclen = 128;
|
|
|
|
|
|
int InputLen; // Data we have already = Offset of end of an incomplete packet;
|
|
|
|
|
|
UCHAR * MailBuffer; // Yapp Message being received
|
|
|
int MailBufferSize;
|
|
|
int YAPPLen; // Bytes sent/received of YAPP Message
|
|
|
long YAPPDate; // Date for received file - if set enables YAPPC
|
|
|
char ARQFilename[256]; // Filename from YAPP Header
|
|
|
|
|
|
UCHAR SavedData[4096]; // Max receive is 2000 is should never get more that 4000
|
|
|
int SaveLen = 0;
|
|
|
|
|
|
void YAPPSendData();
|
|
|
|
|
|
void QueueMsg(UCHAR * Msg, int Len)
|
|
|
{
|
|
|
int Sent = send(sock, Msg, Len, 0);
|
|
|
|
|
|
if (Sent != Len)
|
|
|
Sent = 0;
|
|
|
}
|
|
|
|
|
|
int InnerProcessYAPPMessage(UCHAR * Msg, int Len);
|
|
|
|
|
|
BOOL ProcessYAPPMessage(UCHAR * Msg, int Len)
|
|
|
{
|
|
|
// may have saved data
|
|
|
|
|
|
memcpy(&SavedData[SaveLen], Msg, Len);
|
|
|
|
|
|
SaveLen += Len;
|
|
|
|
|
|
while (SaveLen && InputMode == 'Y')
|
|
|
{
|
|
|
int Used = InnerProcessYAPPMessage(SavedData, SaveLen);
|
|
|
|
|
|
if (Used == 0)
|
|
|
return 0; // Waiting for more
|
|
|
|
|
|
SaveLen -= Used;
|
|
|
|
|
|
if (SaveLen)
|
|
|
memmove(SavedData, &SavedData[Used], SaveLen);
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int InnerProcessYAPPMessage(UCHAR * Msg, int Len)
|
|
|
{
|
|
|
int pktLen = Msg[1];
|
|
|
char Reply[2] = {ACK};
|
|
|
int NameLen, SizeLen, OptLen;
|
|
|
char * ptr;
|
|
|
int FileSize;
|
|
|
WCHAR MsgFile[MAX_PATH];
|
|
|
FILE * hFile;
|
|
|
char Mess[255];
|
|
|
int len;
|
|
|
TCHAR BufferW[2000];
|
|
|
WCHAR WFN[MAX_PATH];
|
|
|
|
|
|
switch (Msg[0])
|
|
|
{
|
|
|
case ENQ: // YAPP Send_Init
|
|
|
|
|
|
// Shouldn't occur in session. Reset state and process
|
|
|
|
|
|
if (MailBuffer)
|
|
|
{
|
|
|
free(MailBuffer);
|
|
|
MailBufferSize=0;
|
|
|
MailBuffer=0;
|
|
|
}
|
|
|
|
|
|
Mess[0] = ACK;
|
|
|
Mess[1] = 1;
|
|
|
|
|
|
InputMode = 'Y';
|
|
|
QueueMsg(Mess, 2);
|
|
|
|
|
|
// Turn off monitoring
|
|
|
|
|
|
Sleep(1000); // To give YAPP Msg tome to be sent
|
|
|
|
|
|
len = sprintf(Mess, "\\\\\\\\%x %x %x %x %x %x %x %x\r", 0, 0, 0, 0, 0, 0, 0, 0);
|
|
|
send(sock, Mess, len, 0);
|
|
|
|
|
|
return Len;
|
|
|
|
|
|
case SOH:
|
|
|
|
|
|
// HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt)
|
|
|
|
|
|
// YAPPC has date/time in dos format
|
|
|
|
|
|
NameLen = strlen(&Msg[2]);
|
|
|
strcpy(ARQFilename, &Msg[2]);
|
|
|
|
|
|
// ARQFN normal string. Create WCS copy
|
|
|
|
|
|
mbstowcs(WFN, ARQFilename, MAX_PATH);
|
|
|
|
|
|
|
|
|
ptr = &Msg[3 + NameLen];
|
|
|
SizeLen = strlen(ptr);
|
|
|
FileSize = atoi(ptr);
|
|
|
|
|
|
OptLen = pktLen - (NameLen + SizeLen + 2);
|
|
|
|
|
|
YAPPDate = 0;
|
|
|
|
|
|
if (OptLen >= 8) // We have a Date/Time for YAPPC
|
|
|
{
|
|
|
ptr = ptr + SizeLen + 1;
|
|
|
YAPPDate = strtol(ptr, NULL, 16);
|
|
|
}
|
|
|
|
|
|
// Check Size
|
|
|
|
|
|
if (FileSize > MaxRXSize)
|
|
|
{
|
|
|
Mess[0] = NAK;
|
|
|
Mess[1] = sprintf(&Mess[2], "File %s size %d larger than limit %d\r", WFN, FileSize, MaxRXSize);
|
|
|
Sleep(1000); // To give YAPP Msg tome to be sent
|
|
|
QueueMsg(Mess, Mess[1] + 2);
|
|
|
|
|
|
len = wsprintf(BufferW, L"YAPP File %s size %d larger than limit %d\r", WFN, FileSize, MaxRXSize);
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
InputMode = 0;
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return Len;
|
|
|
}
|
|
|
|
|
|
// Make sure file does not exist
|
|
|
|
|
|
// Path is Wide String, ARQFN normal
|
|
|
|
|
|
wsprintf(MsgFile, L"%s%s", YAPPPath, WFN);
|
|
|
|
|
|
hFile = CreateFile(MsgFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
|
|
if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
|
|
|
{
|
|
|
Mess[0] = NAK;
|
|
|
Mess[1] = sprintf(&Mess[2], "%s", "File Already Exists");
|
|
|
Sleep(1000); // To give YAPP Msg tome to be sent
|
|
|
QueueMsg(Mess, Mess[1] + 2);
|
|
|
len = wsprintf(BufferW, L"YAPP File Receive Failed - %s already exists\r", MsgFile);
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
CloseHandle(hFile);
|
|
|
InputMode = 0;
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return Len;
|
|
|
}
|
|
|
|
|
|
|
|
|
MailBufferSize = FileSize;
|
|
|
MailBuffer = malloc(FileSize);
|
|
|
YAPPLen = 0;
|
|
|
|
|
|
if (YAPPDate) // If present use YAPPC
|
|
|
Reply[1] = ACK; //Receive_TPK
|
|
|
else
|
|
|
Reply[1] = 2; //Rcv_File
|
|
|
|
|
|
QueueMsg( Reply, 2);
|
|
|
|
|
|
len = wsprintf(BufferW, L"YAPP Receving File %s size %d\r", WFN, FileSize);
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
|
|
|
return Len;
|
|
|
|
|
|
case STX:
|
|
|
|
|
|
// Data Packet
|
|
|
|
|
|
// Check we have it all
|
|
|
|
|
|
if (YAPPDate) // If present use YAPPC so have checksum
|
|
|
{
|
|
|
if (pktLen > (Len - 3)) // -2 for header and checksum
|
|
|
return 0; // Wait for rest
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (pktLen > (Len - 2)) // -2 for header
|
|
|
return 0; // Wait for rest
|
|
|
}
|
|
|
|
|
|
// Save data and remove from buffer
|
|
|
|
|
|
// if YAPPC check checksum
|
|
|
|
|
|
if (YAPPDate)
|
|
|
{
|
|
|
UCHAR Sum = 0;
|
|
|
int i;
|
|
|
UCHAR * uptr = &Msg[2];
|
|
|
|
|
|
i = pktLen;
|
|
|
|
|
|
while(i--)
|
|
|
Sum += *(uptr++);
|
|
|
|
|
|
if (Sum != *uptr)
|
|
|
{
|
|
|
// Checksum Error
|
|
|
|
|
|
Mess[0] = CAN;
|
|
|
Mess[1] = sprintf_s(&Mess[2], sizeof(Mess), "YAPPC Checksum Error");
|
|
|
QueueMsg( Mess, Mess[1] + 2);
|
|
|
|
|
|
len = wsprintf(BufferW, L"YAPPC Checksum Error\r", MsgFile);
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
InputMode = 0;
|
|
|
SendTraceOptions();
|
|
|
return Len;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if ((YAPPLen) + pktLen > MailBufferSize)
|
|
|
{
|
|
|
// Too Big ??
|
|
|
|
|
|
Mess[0] = CAN;
|
|
|
Mess[1] = sprintf(&Mess[2], "YAPP Too much data received");
|
|
|
QueueMsg(Mess, Mess[1] + 2);
|
|
|
|
|
|
len = wsprintf(BufferW, L"YAPP Too much data received\r", MsgFile);
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
InputMode = 0;
|
|
|
SendTraceOptions();
|
|
|
return Len;
|
|
|
}
|
|
|
|
|
|
|
|
|
memcpy(&MailBuffer[YAPPLen], &Msg[2], pktLen);
|
|
|
YAPPLen += pktLen;
|
|
|
|
|
|
if (YAPPDate)
|
|
|
++pktLen; // Add Checksum
|
|
|
|
|
|
return pktLen + 2;
|
|
|
|
|
|
case ETX:
|
|
|
|
|
|
// End Data
|
|
|
|
|
|
if (YAPPLen == MailBufferSize)
|
|
|
{
|
|
|
// All received
|
|
|
|
|
|
int ret;
|
|
|
DWORD Written = 0;
|
|
|
WCHAR WFN[MAX_PATH];
|
|
|
|
|
|
// Path is Wide String, ARQFN normal
|
|
|
|
|
|
mbstowcs(WFN, ARQFilename, MAX_PATH);
|
|
|
|
|
|
wsprintf(MsgFile, L"%s%s", YAPPPath, WFN);
|
|
|
|
|
|
#ifdef WIN32
|
|
|
hFile = CreateFile(MsgFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
|
|
|
|
|
if((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
|
|
|
{
|
|
|
ret = WriteFile(hFile, MailBuffer, YAPPLen, &Written, NULL);
|
|
|
|
|
|
if (YAPPDate)
|
|
|
{
|
|
|
FILETIME FileTime;
|
|
|
struct tm TM;
|
|
|
struct timeval times[2];
|
|
|
time_t TT;
|
|
|
/*
|
|
|
The MS-DOS date. The date is a packed value with the following format.
|
|
|
|
|
|
cant use DosDateTimeToFileTime on Linux
|
|
|
|
|
|
Bits Description
|
|
|
0-4 Day of the month (1<>31)
|
|
|
5-8 Month (1 = January, 2 = February, and so on)
|
|
|
9-15 Year offset from 1980 (add 1980 to get actual year)
|
|
|
wFatTime
|
|
|
The MS-DOS time. The time is a packed value with the following format.
|
|
|
Bits Description
|
|
|
0-4 Second divided by 2
|
|
|
5-10 Minute (0<>59)
|
|
|
11-15 Hour (0<>23 on a 24-hour clock)
|
|
|
*/
|
|
|
memset(&TM, 0, sizeof(TM));
|
|
|
|
|
|
TM.tm_sec = (YAPPDate & 0x1f) << 1;
|
|
|
TM.tm_min = ((YAPPDate >> 5) & 0x3f);
|
|
|
TM.tm_hour = ((YAPPDate >> 11) & 0x1f);
|
|
|
|
|
|
TM.tm_mday = ((YAPPDate >> 16) & 0x1f);
|
|
|
TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1;
|
|
|
TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;
|
|
|
|
|
|
Debugprintf("%d %d %d %d %d %d", TM.tm_year, TM.tm_mon, TM.tm_mday, TM.tm_hour, TM.tm_min, TM.tm_sec);
|
|
|
|
|
|
TT = mktime(&TM);
|
|
|
times[0].tv_sec = times[1].tv_sec =
|
|
|
times[0].tv_usec = times[1].tv_usec = 0;
|
|
|
|
|
|
DosDateTimeToFileTime((WORD)(YAPPDate >> 16), (WORD)YAPPDate & 0xFFFF, &FileTime);
|
|
|
ret = SetFileTime(hFile, &FileTime, &FileTime, &FileTime);
|
|
|
ret = GetLastError();
|
|
|
|
|
|
}
|
|
|
CloseHandle(hFile);
|
|
|
}
|
|
|
#else
|
|
|
|
|
|
hFile = fopen(MsgFile, "wb");
|
|
|
if (hFile)
|
|
|
{
|
|
|
Written = fwrite(MailBuffer, 1, YAPPLen, hFile);
|
|
|
fclose(hFile);
|
|
|
|
|
|
if (YAPPDate)
|
|
|
{
|
|
|
struct tm TM;
|
|
|
struct timeval times[2];
|
|
|
/*
|
|
|
The MS-DOS date. The date is a packed value with the following format.
|
|
|
|
|
|
cant use DosDateTimeToFileTime on Linux
|
|
|
|
|
|
Bits Description
|
|
|
0-4 Day of the month (1<>31)
|
|
|
5-8 Month (1 = January, 2 = February, and so on)
|
|
|
9-15 Year offset from 1980 (add 1980 to get actual year)
|
|
|
wFatTime
|
|
|
The MS-DOS time. The time is a packed value with the following format.
|
|
|
Bits Description
|
|
|
0-4 Second divided by 2
|
|
|
5-10 Minute (0<>59)
|
|
|
11-15 Hour (0<>23 on a 24-hour clock)
|
|
|
*/
|
|
|
memset(&TM, 0, sizeof(TM));
|
|
|
|
|
|
TM.tm_sec = (YAPPDate & 0x1f) << 1;
|
|
|
TM.tm_min = ((YAPPDate >> 5) & 0x3f);
|
|
|
TM.tm_hour = ((YAPPDate >> 11) & 0x1f);
|
|
|
|
|
|
TM.tm_mday = ((YAPPDate >> 16) & 0x1f);
|
|
|
TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1;
|
|
|
TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;
|
|
|
|
|
|
Debugprintf("%d %d %d %d %d %d", TM.tm_year, TM.tm_mon, TM.tm_mday, TM.tm_hour, TM.tm_min, TM.tm_sec);
|
|
|
|
|
|
times[0].tv_sec = times[1].tv_sec = mktime(&TM);
|
|
|
times[0].tv_usec = times[1].tv_usec = 0;
|
|
|
}
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
free(MailBuffer);
|
|
|
MailBufferSize=0;
|
|
|
MailBuffer=0;
|
|
|
|
|
|
if (Written != YAPPLen)
|
|
|
{
|
|
|
Mess[0] = CAN;
|
|
|
Mess[1] = sprintf_s(&Mess[2], sizeof(Mess), "Failed to save YAPP File");
|
|
|
QueueMsg(Mess, Mess[1] + 2);
|
|
|
|
|
|
len = wsprintf(BufferW, L"Failed to save YAPP File\r", MsgFile);
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
InputMode = 0;
|
|
|
SendTraceOptions();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Reply[1] = 3; //Ack_EOF
|
|
|
QueueMsg( Reply, 2);
|
|
|
|
|
|
len = wsprintf(BufferW, L"Reception of file %s complete\r", MsgFile);
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
|
|
|
return Len;
|
|
|
|
|
|
case EOT:
|
|
|
|
|
|
// End Session
|
|
|
|
|
|
Reply[1] = 4; // Ack_EOT
|
|
|
QueueMsg( Reply, 2);
|
|
|
InputMode = 0;
|
|
|
|
|
|
SendTraceOptions();
|
|
|
return Len;
|
|
|
|
|
|
case CAN:
|
|
|
|
|
|
// Abort
|
|
|
|
|
|
Mess[0] = ACK;
|
|
|
Mess[1] = 5; // CAN Ack
|
|
|
QueueMsg( Mess, 2);
|
|
|
|
|
|
if (MailBuffer)
|
|
|
{
|
|
|
free(MailBuffer);
|
|
|
MailBufferSize=0;
|
|
|
MailBuffer=0;
|
|
|
}
|
|
|
|
|
|
// May have an error message
|
|
|
|
|
|
len = Msg[1];
|
|
|
|
|
|
if (len)
|
|
|
{
|
|
|
WCHAR ws[256];
|
|
|
|
|
|
Msg[len + 2] = 0;
|
|
|
mbstowcs(ws, &Msg[2], 255);
|
|
|
|
|
|
len = wsprintf(BufferW, L"YAPP Transfer cancelled - %s\r", ws);
|
|
|
}
|
|
|
else
|
|
|
len = sprintf_s(Mess, sizeof(Mess), "YAPP Transfer cancelled\r");
|
|
|
|
|
|
InputMode = 0;
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return Len;
|
|
|
|
|
|
case ACK:
|
|
|
|
|
|
switch (Msg[1])
|
|
|
{
|
|
|
char * ptr;
|
|
|
|
|
|
case 1: // Rcv_Rdy
|
|
|
|
|
|
// HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt)
|
|
|
|
|
|
// Remote only needs filename so remove path
|
|
|
|
|
|
ptr = ARQFilename;
|
|
|
|
|
|
while (strchr(ptr, '\\'))
|
|
|
ptr = strchr(ptr, '\\') + 1;
|
|
|
|
|
|
len = strlen(ptr) + 3;
|
|
|
|
|
|
strcpy(&Mess[2], ptr);
|
|
|
len += sprintf(&Mess[len], "%d", MailBufferSize);
|
|
|
len++; // include null
|
|
|
len += sprintf(&Mess[len], "%8X", YAPPDate);
|
|
|
len++; // include null
|
|
|
Mess[0] = SOH;
|
|
|
Mess[1] = len - 2;
|
|
|
|
|
|
QueueMsg( Mess, len);
|
|
|
|
|
|
return Len;
|
|
|
|
|
|
case 2:
|
|
|
|
|
|
YAPPDate = 0; // Switch to Normal (No Checksum) Mode
|
|
|
|
|
|
case 6: // Send using YAPPC
|
|
|
|
|
|
// Start sending message
|
|
|
|
|
|
YAPPSendData();
|
|
|
return Len;
|
|
|
|
|
|
case 3:
|
|
|
|
|
|
// ACK EOF - Send EOT
|
|
|
|
|
|
Mess[0] = EOT;
|
|
|
Mess[1] = 1;
|
|
|
QueueMsg( Mess, 2);
|
|
|
|
|
|
return Len;
|
|
|
|
|
|
case 4:
|
|
|
|
|
|
// ACK EOT
|
|
|
|
|
|
InputMode = 0;
|
|
|
SendTraceOptions();
|
|
|
|
|
|
len = wsprintf(BufferW, L"File transfer complete\r");
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
return Len;
|
|
|
|
|
|
default:
|
|
|
return Len;
|
|
|
|
|
|
}
|
|
|
|
|
|
case NAK:
|
|
|
|
|
|
// Either Reject or Restart
|
|
|
|
|
|
// RE Resume NAK len R NULL (File size in ASCII) NULL
|
|
|
|
|
|
if (Len > 2 && Msg[2] == 'R' && Msg[3] == 0)
|
|
|
{
|
|
|
int posn = atoi(&Msg[4]);
|
|
|
|
|
|
YAPPLen += posn;
|
|
|
MailBufferSize -= posn;
|
|
|
|
|
|
YAPPSendData();
|
|
|
return Len;
|
|
|
|
|
|
}
|
|
|
|
|
|
// May have an error message
|
|
|
|
|
|
len = Msg[1];
|
|
|
|
|
|
if (len)
|
|
|
{
|
|
|
WCHAR ws[256];
|
|
|
|
|
|
Msg[len + 2] = 0;
|
|
|
|
|
|
mbstowcs(ws, &Msg[2], 255);
|
|
|
|
|
|
len = wsprintf(BufferW, L"File rejected - %s\r", ws);
|
|
|
}
|
|
|
else
|
|
|
len = wsprintf(BufferW, L"File rejected\r");
|
|
|
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
InputMode = 0;
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return Len;
|
|
|
|
|
|
}
|
|
|
|
|
|
len = wsprintf(BufferW, L"Unexpected message during YAPP Transfer. Transfer canncelled\r");
|
|
|
WritetoOutputWindow(&OutputData, BufferW, len);
|
|
|
DoRefresh(&OutputData);
|
|
|
|
|
|
InputMode = 0;
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return Len;
|
|
|
|
|
|
}
|
|
|
|
|
|
void YAPPSendFile(WCHAR * FN)
|
|
|
{
|
|
|
int FileSize;
|
|
|
char MsgFile[MAX_PATH];
|
|
|
FILE * hFile;
|
|
|
struct stat STAT;
|
|
|
TCHAR BufferW[2000];
|
|
|
int Len;
|
|
|
|
|
|
wcstombs(MsgFile, FN, MAX_PATH);
|
|
|
|
|
|
if (MsgFile == NULL)
|
|
|
{
|
|
|
Len = wsprintf(BufferW, L"Filename missing\r");
|
|
|
WritetoOutputWindow(&OutputData, BufferW, Len);
|
|
|
DoRefresh(&OutputData);
|
|
|
SendTraceOptions();
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if (stat(MsgFile, &STAT) != -1)
|
|
|
{
|
|
|
FileSize = STAT.st_size;
|
|
|
|
|
|
hFile = fopen(MsgFile, "rb");
|
|
|
|
|
|
if (hFile)
|
|
|
{
|
|
|
char Mess[255];
|
|
|
time_t UnixTime = STAT.st_mtime;
|
|
|
FILETIME ft;
|
|
|
LONGLONG ll;
|
|
|
SYSTEMTIME st;
|
|
|
WORD FatDate;
|
|
|
WORD FatTime;
|
|
|
struct tm TM;
|
|
|
|
|
|
strcpy(ARQFilename, MsgFile);
|
|
|
MailBuffer = malloc(FileSize);
|
|
|
MailBufferSize = FileSize;
|
|
|
YAPPLen = 0;
|
|
|
fread(MailBuffer, 1, FileSize, hFile);
|
|
|
|
|
|
// Get Date and Time for YAPPC Mode
|
|
|
|
|
|
/* The MS-DOS date. The date is a packed value with the following format.
|
|
|
|
|
|
cant use DosDateTimeToFileTime on Linux
|
|
|
|
|
|
Bits Description
|
|
|
0-4 Day of the month (1<>31)
|
|
|
5-8 Month (1 = January, 2 = February, and so on)
|
|
|
9-15 Year offset from 1980 (add 1980 to get actual year)
|
|
|
wFatTime
|
|
|
The MS-DOS time. The time is a packed value with the following format.
|
|
|
Bits Description
|
|
|
0-4 Second divided by 2
|
|
|
5-10 Minute (0<>59)
|
|
|
11-15 Hour (0<>23 on a 24-hour clock)
|
|
|
|
|
|
memset(&TM, 0, sizeof(TM));
|
|
|
|
|
|
TM.tm_sec = (YAPPDate & 0x1f) << 1;
|
|
|
TM.tm_min = ((YAPPDate >> 5) & 0x3f);
|
|
|
TM.tm_hour = ((YAPPDate >> 11) & 0x1f);
|
|
|
|
|
|
TM.tm_mday = ((YAPPDate >> 16) & 0x1f);
|
|
|
TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1;
|
|
|
TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;
|
|
|
*/
|
|
|
|
|
|
// Note that LONGLONG is a 64-bit value
|
|
|
|
|
|
ll = Int32x32To64(UnixTime, 10000000) + 116444736000000000;
|
|
|
ft.dwLowDateTime = (DWORD)ll;
|
|
|
ll >>= 32;
|
|
|
ft.dwHighDateTime = (DWORD)ll;
|
|
|
|
|
|
FileTimeToSystemTime(&ft, &st);
|
|
|
FileTimeToDosDateTime(&ft, &FatDate, &FatTime);
|
|
|
|
|
|
YAPPDate = (FatDate << 16) + FatTime;
|
|
|
|
|
|
memset(&TM, 0, sizeof(TM));
|
|
|
|
|
|
TM.tm_sec = (YAPPDate & 0x1f) << 1;
|
|
|
TM.tm_min = ((YAPPDate >> 5) & 0x3f);
|
|
|
TM.tm_hour = ((YAPPDate >> 11) & 0x1f);
|
|
|
|
|
|
TM.tm_mday = ((YAPPDate >> 16) & 0x1f);
|
|
|
TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1;
|
|
|
TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80;
|
|
|
|
|
|
fclose(hFile);
|
|
|
|
|
|
Mess[0] = ENQ;
|
|
|
Mess[1] = 1;
|
|
|
|
|
|
QueueMsg(Mess, 2);
|
|
|
InputMode = 'Y';
|
|
|
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Len = wsprintf(BufferW, L"File %s not found\r", FN);
|
|
|
WritetoOutputWindow(&OutputData, BufferW, Len);
|
|
|
DoRefresh(&OutputData);
|
|
|
}
|
|
|
|
|
|
void YAPPSendData()
|
|
|
{
|
|
|
char Mess[258];
|
|
|
|
|
|
while (1)
|
|
|
{
|
|
|
int Left = MailBufferSize;
|
|
|
|
|
|
if (Left == 0)
|
|
|
{
|
|
|
// Finished - send End Data
|
|
|
|
|
|
Mess[0] = ETX;
|
|
|
Mess[1] = 1;
|
|
|
|
|
|
QueueMsg( Mess, 2);
|
|
|
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
if (Left > paclen - 3) // two bytes header and possible checksum
|
|
|
Left = paclen - 3;
|
|
|
|
|
|
memcpy(&Mess[2], &MailBuffer[YAPPLen], Left);
|
|
|
|
|
|
YAPPLen += Left;
|
|
|
MailBufferSize -= Left;
|
|
|
|
|
|
// if YAPPC add checksum
|
|
|
|
|
|
if (YAPPDate)
|
|
|
{
|
|
|
UCHAR Sum = 0;
|
|
|
int i;
|
|
|
UCHAR * uptr = &Mess[2];
|
|
|
|
|
|
i = Left;
|
|
|
|
|
|
while(i--)
|
|
|
Sum += *(uptr++);
|
|
|
|
|
|
*(uptr) = Sum;
|
|
|
|
|
|
Mess[0] = STX;
|
|
|
Mess[1] = Left;
|
|
|
|
|
|
QueueMsg( Mess, Left + 3);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Mess[0] = STX;
|
|
|
Mess[1] = Left;
|
|
|
|
|
|
QueueMsg( Mess, Left + 2);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#endif
|