diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..1ff0c42
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3c4efe2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,261 @@
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# User-specific files (MonoDevelop/Xamarin Studio)
+*.userprefs
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+#*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
+# NuGet Packages
+*.nupkg
+# The packages folder can be ignored because of Package Restore
+**/packages/*
+# except build/, which is used as an MSBuild target.
+!**/packages/build/
+# Uncomment if necessary however generally it will be regenerated when needed
+#!**/packages/repositories.config
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
\ No newline at end of file
diff --git a/250x1000Hz.wav b/250x1000Hz.wav
new file mode 100644
index 0000000..0079795
Binary files /dev/null and b/250x1000Hz.wav differ
diff --git a/250x600Hz.wav b/250x600Hz.wav
new file mode 100644
index 0000000..3480a76
Binary files /dev/null and b/250x600Hz.wav differ
diff --git a/AGWCode.cpp b/AGWCode.cpp
index 9539b07..2c4a1be 100644
--- a/AGWCode.cpp
+++ b/AGWCode.cpp
@@ -1062,7 +1062,7 @@ void on_AGW_C_frame(AGWUser * AGW, struct AGWHeader * Frame, byte * Msg)
setMenus(true);
if (ConnectBeep)
- myBeep();
+ myBeep(&ConnectWAV);
// Send CText if defined
diff --git a/AlertSetup.ui b/AlertSetup.ui
new file mode 100644
index 0000000..441cc2d
--- /dev/null
+++ b/AlertSetup.ui
@@ -0,0 +1,353 @@
+
+
+ AlertDialog
+
+
+
+ 0
+ 0
+ 558
+ 461
+
+
+
+ Dialog
+
+
+
+
+ 86
+ 373
+ 351
+ 33
+
+
+
+
+ 6
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+ OK
+
+
+
+ -
+
+
+ Cancel
+
+
+
+
+
+
+
+
+ 24
+ 40
+ 201
+ 20
+
+
+
+ Beep on Inbound connect
+
+
+
+
+
+ 24
+ 65
+ 221
+ 21
+
+
+
+ Beep on message after inactivity
+
+
+
+
+
+ 24
+ 90
+ 201
+ 20
+
+
+
+ Beep on keyword
+
+
+
+
+
+ 350
+ 65
+ 51
+ 20
+
+
+
+
+
+
+ 350
+ 95
+ 137
+ 20
+
+
+
+
+
+
+ 24
+ 204
+ 82
+ 20
+
+
+
+ Use Beep
+
+
+ buttonGroup
+
+
+
+
+
+ 148
+ 204
+ 193
+ 20
+
+
+
+ Use Audio Files
+
+
+ buttonGroup
+
+
+
+
+
+ 258
+ 65
+ 47
+ 20
+
+
+
+ Interval
+
+
+
+
+
+ 24
+ 267
+ 107
+ 20
+
+
+
+ Interval .wav File
+
+
+
+
+
+ 200
+ 267
+ 207
+ 20
+
+
+
+
+
+
+ 24
+ 292
+ 169
+ 20
+
+
+
+ Inbound Connect .wav File
+
+
+
+
+
+ 24
+ 317
+ 165
+ 20
+
+
+
+ Keyword Alert .wav File
+
+
+
+
+
+ 258
+ 95
+ 89
+ 20
+
+
+
+ Keyword File
+
+
+
+
+
+ 200
+ 292
+ 207
+ 20
+
+
+
+
+
+
+ 200
+ 317
+ 207
+ 20
+
+
+
+
+
+
+ 20
+ 130
+ 465
+ 65
+
+
+
+ The System Beep function doesn't work on all platform, so you can configure QtTermTCP to play a sound file instead of using Beep. You can set different files for each event if you wish. Some sample wav files are provided.
+
+
+ true
+
+
+
+
+
+ 416
+ 267
+ 61
+ 20
+
+
+
+ Choose
+
+
+
+
+
+ 416
+ 292
+ 61
+ 20
+
+
+
+ Choose
+
+
+
+
+
+ 416
+ 317
+ 61
+ 20
+
+
+
+ Choose
+
+
+
+
+
+ 24
+ 15
+ 289
+ 20
+
+
+
+ Use Bells (ascii BELL char makes a sound)
+
+
+
+
+
+ 200
+ 242
+ 207
+ 20
+
+
+
+
+
+
+ 416
+ 242
+ 61
+ 20
+
+
+
+ Choose
+
+
+
+
+
+ 24
+ 242
+ 107
+ 20
+
+
+
+ Bells .wav File
+
+
+
+
+
+
+
+
+
diff --git a/PCBeep.wav b/PCBeep.wav
new file mode 100644
index 0000000..8ff2dd9
Binary files /dev/null and b/PCBeep.wav differ
diff --git a/QtTermTCP-skigpi4-64.cpp b/QtTermTCP-skigpi4-64.cpp
new file mode 100644
index 0000000..9a26140
--- /dev/null
+++ b/QtTermTCP-skigpi4-64.cpp
@@ -0,0 +1,7423 @@
+// Qt Version of BPQTermTCP
+
+#define VersionString "0.0.0.68"
+
+
+// .12 Save font weight
+// .13 Display incomplete lines (ie without CR)
+// .14 Add YAPP and Listen Mode
+// .15 Reuse windows in Listen Mode
+// .17 MDI Version 7/1/20
+// .18 Fix input window losing focus when data arrives on other window
+// .19 Fix Scrollback
+// .20 WinXP compatibility changes
+// .21 Save Window Positions
+// .22 Open a window on first start
+// .23 Add Tabbed display option
+// .24 Fix crash when setting Monitor flags in Tabbed mode
+// .25 Add AGW mode
+// .26 Add sending CTRL/C CTRL/D and CTRL/Z)
+// .27 Limit size of windows to 10000 lines
+// Fix YAPP in Tabbed Mode
+// .28 Add AGW Beacon
+// .29 Fix allocating Listem sessions to tabs connected using AGW
+// .30 Fix allocationd AGW Monitor Sessions
+// .31 Fix output being written to the wrong place when window is scrolled back
+// .32 Fix connect with digis
+// .33 Add StripLF option
+// .34 Improvements for Andriod
+// Option to change Menu Fonts
+// Fix receiving part lines when scrolled back
+// .35 Fix PE if not in Tabbed Mode
+// .36 Improved dialogs mainly for Android
+// Try to make sure sessions are closed before exiting
+// .37 Replace VT with LF (for pasting from BPQ32 Terminal Window)
+// Dont show AGW status line if AGW interface is disabled
+// Don't show Window Menu in Single Mode
+// .38 Protect against connect to normal Telnet Port.
+// Send CTEXT and Beep for inward AGW Connects
+// Make sending Idle and Connect beeps configurable
+// Change displayed Monitor flags when active window changed.
+// Fix duplicate text on long lines
+// .39 Add option to Convert non-utf8 charaters
+// .40 Prevent crash if AGW monitor Window closed
+// .41 Allow AGW Config and Connect dialogs to be resized with scrollbars
+// Fix disabling connect flag on current session when AGW connects
+// .42 Fix some bugs in AGW session handling
+// .43 Include Ross KD5LPB's fixes for MAC
+// .44 Ctrl/[ sends ESC (0x1b)
+// .45 Add VARA support Nov 2021
+// .46 Fix dialog size on VARA setup
+// .47 Move VARA Status indicator.
+// Add FLRIG PTT for VARA
+// .48 Check that YAPP Receive Directory has been set
+// Save separate configs for VARA, VARAFM and VARASAT
+// .49 Add BBS Monitor Dec 2021
+// .50 Make Serial port support optional for Android Version
+// .51 Add KISS TNC Support May 2022
+// .52 Save partially typed lines on cursor up May 2022
+// .53 Add UI Mode for KISS Sessions May 2022
+// Fix saving KISS Paclen (b)
+// Fix Keepalive (c)
+// .54 Add option to change screen colours June 2022
+// .55 Build without optimisation
+// .56 Add Teletext mode Nov 2022
+// .57 Fix KISS mode incoming call handling
+// .58 Add method to toggle Normal/Teletext Mode
+// Fix KISS multiple session protection
+// .59 Add Teletext double height mode
+// .60 Add option to name sessions Jan 2023
+// .61 Add VARA Init Script Feb 2023
+// .62 Fix running AGW in single session mode Feb 2023
+// .63 Fix handling split monitor frame (no fe in buffer) Apr 2023
+// .64 Add Clear Screen command to context menu Apr 2023
+// .65 Fixes for 63 port version of BPQ May 2023
+// .66 Colour Tab of incoming calls June 2023
+// .67 Add config Yapp RX Size dialog July 2023
+// Fix 63 port montoring
+
+// .68 Remember last used host on restart Sept 2023
+// Add AutoConnect in Tabbed Mode
+// Fix auto copy when QtTerm not active window
+
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#define UNUSED(x) (void)(x)
+
+#define USESERIAL
+
+#include "QtTermTCP.h"
+#include "TabDialog.h"
+#include
+#include
+#include
+#include
+#include
+#include "QTreeWidget"
+#include
+#include
+#include
+#include
+#include
+#ifdef USESERIAL
+#include
+#include
+#endif
+#ifndef WIN32
+#define strtok_s strtok_r
+#endif
+#include
+#include
+#ifndef WIN32
+#include
+#endif
+
+#include "ax25.h"
+
+#define UNREFERENCED_PARAMETER(P) (P)
+
+void DecodeTeleText(Ui_ListenSession * Sess, char * text);
+
+char Host[MAXHOSTS + 1][100] = { "" };
+int Port[MAXHOSTS + 1] = { 0 };
+char UserName[MAXHOSTS + 1][80] = { "" };
+char Password[MAXHOSTS + 1][80] = { "" };
+char MonParams[MAXHOSTS + 1][80] = { "" };
+char SessName[MAXHOSTS + 1][80] = { "" };
+int ListenPort = 8015;
+
+// Session Type Equates
+
+#define Term 1
+#define Mon 2
+#define Listen 4
+
+// Presentation - Single Window, MDI or Tabbed
+
+int TermMode = 0;
+
+#define Single 0
+#define MDI 1
+#define Tabbed 2
+
+int singlemodeFormat = Mon + Term;
+
+char monStyleSheet[128] = "background-color: rgb(0,255,255)";
+char termStyleSheet[128] = "background-color: rgb(255,0,255);";
+char inputStyleSheet[128] = "color: rgb(255, 0, 0); background-color: rgb(255,255,0);";
+
+
+QColor monBackground = qRgb(0, 255, 255);
+QColor monRxText = qRgb(0, 0, 255);
+QColor monTxText = qRgb(255, 0, 0);
+QColor monOtherText = qRgb(0, 0, 0);
+
+QColor termBackground = qRgb(255, 0, 255);
+QColor outputText = qRgb(0, 0, 0);
+QColor EchoText = qRgb(0, 0, 255);
+QColor WarningText = qRgb(255, 0, 0);
+QColor inputBackground = qRgb(255, 255, 0);
+QColor inputText = qRgb(0, 0, 255);
+
+QColor newTabText = qRgb(255, 0, 0); // Red
+QColor oldTabText = qRgb(0, 0, 0); // Black
+
+
+// There is something odd about this. It doesn't match BPQTERMTCP though it looks the same
+
+// Chat uses these (+ 10)
+//{ 0, 4, 9, 11, 13, 16, 17, 42, 45, 50, 61, 64, 66, 72, 81, 84, 85, 86, 87, 89 };
+
+// As we have a white background we need dark colours
+
+// 0 is black. 23 is normal output (blue) 81 is red (used by AGW Mon)
+// for monitor in colour, host sends 17 for RX Text, 81 for TX Text but code converts to monRx/TxText qrgb values
+
+QRgb Colours[256] = { 0,
+ qRgb(0,0,0), qRgb(0,0,128), qRgb(0,0,192), qRgb(0,0,255), // 1 - 4
+ qRgb(0,64,0), qRgb(0,64,128), qRgb(0,64,192), qRgb(0,64,255), // 5 - 8
+ qRgb(0,128,0), qRgb(0,128,128), qRgb(0,128,192), qRgb(0,128,255), // 9 - 12
+ qRgb(0,192,0), qRgb(0,192,128), qRgb(0,192,192), qRgb(0,192,255), // 13 - 16
+ qRgb(0,255,0), qRgb(0,255,128), qRgb(0,255,192), qRgb(0,255,255), // 17 - 20
+
+ qRgb(64,0,0), qRgb(64,0,128), qRgb(64,0,192), qRgb(0,0,255), // 21
+ qRgb(64,64,0), qRgb(64,64,128), qRgb(64,64,192), qRgb(64,64,255),
+ qRgb(64,128,0), qRgb(64,128,128), qRgb(64,128,192), qRgb(64,128,255),
+ qRgb(64,192,0), qRgb(64,192,128), qRgb(64,192,192), qRgb(64,192,255),
+ qRgb(64,255,0), qRgb(64,255,128), qRgb(64,255,192), qRgb(64,255,255),
+
+ qRgb(128,0,0), qRgb(128,0,128), qRgb(128,0,192), qRgb(128,0,255), // 41
+ qRgb(128,64,0), qRgb(128,64,128), qRgb(128,64,192), qRgb(128,64,255),
+ qRgb(128,128,0), qRgb(128,128,128), qRgb(128,128,192), qRgb(128,128,255),
+ qRgb(128,192,0), qRgb(128,192,128), qRgb(128,192,192), qRgb(128,192,255),
+ qRgb(128,255,0), qRgb(128,255,128), qRgb(128,255,192), qRgb(128,255,255),
+
+ qRgb(192,0,0), qRgb(192,0,128), qRgb(192,0,192), qRgb(192,0,255), // 61 - 80
+ qRgb(192,64,0), qRgb(192,64,128), qRgb(192,64,192), qRgb(192,64,255),
+ qRgb(192,128,0), qRgb(192,128,128), qRgb(192,128,192), qRgb(192,128,255),
+ qRgb(192,192,0), qRgb(192,192,128), qRgb(192,192,192), qRgb(192,192,255),
+ qRgb(192,255,0), qRgb(192,255,128), qRgb(192,255,192), qRgb(192,255,255),
+
+ qRgb(255,0,0), qRgb(255,0,128), qRgb(255,0,192), qRgb(255,0,255), // 81 - 100
+ qRgb(255,64,0), qRgb(255,64,128), qRgb(255,64,192), qRgb(255,64,255),
+ qRgb(255,128,0), qRgb(255,128,128), qRgb(255,128,192), qRgb(255,128,255),
+ qRgb(255,192,0), qRgb(255,192,128), qRgb(255,192,192), qRgb(255,192,255),
+ qRgb(255,255,0), qRgb(255,255,128), qRgb(255,255,192), qRgb(255,255,255)
+};
+
+
+
+int SavedHost = 0; // from config
+
+char * sessionList = NULL; // Saved sessions
+
+extern int ChatMode;
+extern int Bells;
+extern int StripLF;
+extern int convUTF8;
+
+extern time_t LastWrite;
+extern int AlertInterval;
+extern int AlertBeep;
+extern int AlertFreq;
+extern int AlertDuration;
+extern int ConnectBeep;
+bool useBeep; // use wav files if not set
+
+QString ConnectWAV("");
+
+extern int MaxRXSize;
+
+extern int AutoTeletext;
+
+// AGW Host Interface stuff
+
+int AGWEnable = 0;
+int AGWMonEnable = 0;
+char AGWTermCall[12] = "";
+char AGWBeaconDest[12] = "";
+char AGWBeaconPath[80] = "";
+int AGWBeaconInterval = 0;
+char AGWBeaconPorts[80];
+char AGWBeaconMsg[260] = "";
+
+char AGWHost[128] = "127.0.0.1";
+int AGWPortNum = 8000;
+int AGWPaclen = 80;
+extern char * AGWPortList;
+extern myTcpSocket * AGWSock;
+
+QStringList AGWToCalls;
+
+// KISS Interface
+
+int KISSEnable = 0;
+char SerialPort[80] = "";
+char KISSHost[128] = "127.0.0.1";
+int KISSPortNum = 1000;
+int KISSBAUD = 19200;
+char MYCALL[32];
+extern "C" UCHAR axMYCALL[7]; // Mycall in ax.25
+
+int KISSMode = 0; // Connected (0) or UI (1)
+
+myTcpSocket * KISSSock;
+
+extern "C" void * KISSSockCopy[4];
+
+int KISSConnected = 0;
+int KISSConnecting = 0;
+
+Ui_ListenSession * KISSMonSess;
+
+QSerialPort * m_serial = nullptr;
+
+// VARA Interface
+
+int VARAEnable = 0;
+char VARAHost[128] = "127.0.0.1";
+char VARAHostHF[128] = "127.0.0.1";
+char VARAHostFM[128] = "127.0.0.1";
+char VARAHostSAT[128] = "127.0.0.1";
+int VARAPortNum = 8000;
+int VARAPortHF = 8000;
+int VARAPortFM = 8000;
+int VARAPortSAT = 8000;
+char VARATermCall[12] = "";
+char VARAPath[256] = "";
+char VARAInit[256] = "";
+char VARAPathHF[256] = "";
+char VARAPathFM[256] = "";
+char VARAPathSAT[256] = "";
+
+int VARA500 = 0;
+int VARA2300 = 1;
+int VARA2750 = 0;
+
+int VARAHF = 1;
+int VARAFM = 0;
+int VARASAT = 0;
+
+myTcpSocket * VARASock;
+myTcpSocket * VARADataSock;
+
+int VARAConnected = 0;
+int VARAConnecting = 0;
+
+
+extern char YAPPPath[256];
+
+void menuChecked(QAction * Act);
+
+// PTT Stuff
+
+#define PTTRTS 1
+#define PTTDTR 2
+#define PTTCAT 4
+#define PTTCM108 8
+#define PTTHAMLIB 16
+#define PTTFLRIG 32
+
+#ifdef USESERIAL
+
+QSerialPort * hPTTDevice = 0;
+#else
+
+
+#endif
+char PTTPort[80] = ""; // Port for Hardware PTT - may be same as control port.
+int PTTBAUD = 19200;
+int PTTMode = PTTRTS; // PTT Control Flags.
+
+char PTTOnString[128] = "";
+char PTTOffString[128] = "";
+
+int CATHex = 1;
+
+unsigned char PTTOnCmd[64];
+int PTTOnCmdLen = 0;
+
+unsigned char PTTOffCmd[64];
+int PTTOffCmdLen = 0;
+
+int pttGPIOPin = 17; // Default
+int pttGPIOPinR = 17;
+bool pttGPIOInvert = false;
+bool useGPIO = false;
+bool gotGPIO = false;
+
+int HamLibPort = 4532;
+char HamLibHost[32] = "192.168.1.14";
+
+int FLRigPort = 12345;
+char FLRigHost[32] = "127.0.0.1";
+
+
+char CM108Addr[80] = "";
+
+int VID = 0;
+int PID = 0;
+
+// CM108 Code
+
+char * CM108Device = NULL;
+
+QProcess *process = NULL;
+
+void GetSettings();
+
+// These widgets defined here as they are accessed from outside the framework
+
+QLabel * Status1;
+QLabel * Status2;
+QLabel * Status3;
+QLabel * Status4;
+
+QAction *actHost[19];
+QAction *actSetup[16];
+
+QAction * TabSingle = NULL;
+QAction * TabBoth = NULL;
+QAction * TabMon = NULL;
+
+QMenu *monitorMenu;
+QMenu * YAPPMenu;
+QMenu *connectMenu;
+QMenu *disconnectMenu;
+
+QAction *MonTX;
+QAction *MonSup;
+QAction *MonNodes;
+QAction *MonUI;
+QAction *MonColour;
+QAction *MonPort[65];
+QAction *actChatMode;
+QAction *actAutoTeletext;
+QAction *actBells;
+QAction *actStripLF;
+QAction *actIntervalBeep;
+QAction *actConnectBeep;
+QAction *actAuto;
+QAction *actnoConv;
+QAction *actCP1251;
+QAction *actCP1252;
+QAction *actCP437;
+
+QAction *actFonts;
+QAction *actmenuFont;
+QAction *actColours;
+QAction *actmyFonts;
+QAction *YAPPSend;
+QAction *YAPPSetRX;
+QAction *YAPPSetSize;
+QAction *singleAct;
+QAction *singleAct2;
+QAction *MDIAct;
+QAction *tabbedAct;
+QAction *discAction;
+QFont * menufont;
+QMenu *windowMenu;
+QMenu *setupMenu;
+QAction *ListenAction;
+
+QTabWidget *tabWidget;
+QMdiArea *mdiArea;
+QWidget * mythis;
+QStatusBar * myStatusBar;
+
+QTcpServer * _server;
+
+QMenuBar *mymenuBar;
+QToolBar *toolBar;
+QToolButton * but1;
+QToolButton * but2;
+QToolButton * but3;
+QToolButton * but4;
+QToolButton * but5;
+
+QList _sessions;
+
+// Session Type Equates
+
+#define Term 1
+#define Mon 2
+#define Listen 4
+
+int TabType[10] = { Term, Term + Mon, Term, Term, Term, Term, Mon, Mon, Mon };
+
+int AutoConnect[10] = {0, 0 ,0, 0, 0, 0, 0, 0, 0, 0};
+
+int currentHost[10] = {0, 0 ,0, 0, 0, 0, 0, 0, 0, 0};
+
+int listenPort = 8015;
+extern "C" int listenEnable;
+char listenCText[4096] = "";
+
+int ConfigHost = 0;
+
+int Split = 50; // Mon/Term size split
+
+int termX;
+
+bool Cascading = false; // Set to stop size being saved when cascading
+
+QMdiSubWindow * ActiveSubWindow = NULL;
+Ui_ListenSession * ActiveSession = NULL;
+
+Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label = nullptr);
+void Send_AGW_C_Frame(Ui_ListenSession * Sess, int Port, char * CallFrom, char * CallTo, char * Data, int DataLen);
+void AGW_AX25_data_in(void * AX25Sess, unsigned char * data, int Len);
+void AGWMonWindowClosing(Ui_ListenSession *Sess);
+void AGWWindowClosing(Ui_ListenSession *Sess);
+extern "C" void KISSDataReceived(void * socket, unsigned char * data, int length);
+void closeSerialPort();
+
+extern void initUTF8();
+int checkUTF8(unsigned char * Msg, int Len, unsigned char * out);
+
+QDialog * deviceUI;
+
+#include
+#include
+#include
+
+
+
+
+void EncodeSettingsLine(int n, char * String)
+{
+ sprintf(String, "%s|%d|%s|%s|%s|%s", Host[n], Port[n], UserName[n], Password[n], MonParams[n], SessName[n]);
+ return;
+}
+
+// This is used for placing discAction in the preference menu
+#ifdef __APPLE__
+bool is_mac = true;
+#else
+bool is_mac = false;
+#endif
+
+QString GetConfPath()
+{
+ std::string conf_path = "QtTermTCP.ini"; // Default conf file stored alongside application.
+
+#ifdef __APPLE__
+
+ // Get configuration path for MacOS.
+
+ // This will usually be placed in /Users/USER/Library/Application Support/QtTermTCP
+
+ std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString();
+
+ conf_path = directory + "/QtTermTCP.ini";
+
+ mkdir(directory.c_str(), 0775);
+
+#endif
+
+ return QString::fromUtf8(conf_path.c_str());
+
+}
+
+
+
+void DecodeSettingsLine(int n, char * String)
+{
+ char * Param = strdup(String);
+ char * Rest;
+ char * Save = Param; // for Free
+
+ Rest = strlop(Param, '|');
+
+ if (Rest == NULL)
+ return;
+
+ strcpy(Host[n], Param);
+ Param = Rest;
+
+ Rest = strlop(Param, '|');
+ Port[n] = atoi(Param);
+ Param = Rest;
+
+ Rest = strlop(Param, '|');
+ strcpy(UserName[n], Param);
+ Param = Rest;
+
+ Rest = strlop(Param, '|');
+ strcpy(Password[n], Param);
+ Param = Rest;
+
+ Rest = strlop(Param, '|');
+ strcpy(MonParams[n], Param);
+
+ if (Rest)
+ strcpy(SessName[n], Rest);
+
+ free(Save);
+ return;
+}
+
+//#ifdef ANDROID
+//#define inputheight 60
+//#else
+#define inputheight 25
+//#endif
+
+extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len);
+
+void DoTermResize(Ui_ListenSession * Sess)
+{
+
+ QRect r = Sess->rect();
+
+ int H, Mid, monHeight, termHeight, Width, Border = 3;
+
+ Width = r.width();
+ H = r.height();
+
+ if (TermMode == Tabbed)
+ {
+ // H -= 20;
+ Width -= 7;
+ }
+ else if (TermMode == Single)
+ {
+ Width -= 7;
+ // H += 20;
+ }
+
+ if (Sess->SessionType == Listen || Sess->SessionType == Term)
+ {
+ // Term and Input
+
+ // Calc Positions of window
+
+ termHeight = H - (inputheight + 3 * Border);
+
+ Sess->termWindow->setGeometry(QRect(Border, Border, Width, termHeight));
+
+ if (Sess->TTActive)
+ {
+ Sess->TTLabel->setGeometry(QRect(Border, Border, 600, 475));
+// Sess->termWindow->setVisible(false);
+ Sess->TTLabel->setVisible(true);
+ }
+ else
+ {
+// Sess->termWindow->setVisible(true);
+ Sess->TTLabel->setVisible(false);
+ }
+
+ Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight));
+ }
+ else if (Sess->SessionType == (Term | Mon))
+ {
+ // All 3
+
+ // Calc Positions of window
+
+ Mid = (H * Split) / 100;
+
+ monHeight = Mid - Border;
+ termX = Mid;
+ termHeight = H - Mid - (inputheight + 3 * Border);
+
+ Sess->monWindow->setGeometry(QRect(Border, Border, Width, monHeight));
+ Sess->termWindow->setGeometry(QRect(Border, Mid + Border, Width, termHeight));
+
+ if (Sess->TTActive)
+ {
+ Sess->TTLabel->setGeometry(QRect(3, Mid + Border, 600, 475));
+// Sess->termWindow->setVisible(false);
+ Sess->TTLabel->setVisible(true);
+ }
+ else
+ {
+// Sess->termWindow->setVisible(true);
+ Sess->TTLabel->setVisible(false);
+ }
+
+ Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight));
+
+ }
+ else
+ {
+ // Should just be Mon only
+
+ Sess->monWindow->setGeometry(QRect(Border, Border, Width, H - 2 * Border));
+ }
+}
+
+bool QtTermTCP::eventFilter(QObject* obj, QEvent *event)
+{
+ // See if from a Listening Session
+
+ Ui_ListenSession * Sess;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ // Sess = _sessions.at(i); for (Ui_ListenSession * Sess : _sessions)
+ // {
+ if (Sess == NULL)
+ continue;
+
+ if (Sess == obj)
+ {
+ if (event->type() == QEvent::Close)
+ {
+ // Window closing
+
+ // This only closed mon sessinos
+
+ if (Sess->AGWMonSession)
+ // AGWMonWindowClosing(Sess);
+ AGWWindowClosing(Sess);
+
+ if (Sess->AGWSession)
+ AGWWindowClosing(Sess);
+
+ if (Sess->clientSocket)
+ {
+ int loops = 100;
+ Sess->clientSocket->disconnectFromHost();
+ while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState)
+ QThread::msleep(10);
+ }
+ _sessions.removeOne(Sess);
+ return QMainWindow::eventFilter(obj, event);
+ }
+
+ if (event->type() == QEvent::Resize)
+ {
+ DoTermResize(Sess);
+ }
+ }
+
+ if (Sess->inputWindow == obj)
+ {
+ if (event->type() == QEvent::KeyPress)
+ {
+ QKeyEvent* keyEvent = static_cast(event);
+
+ int key = keyEvent->key();
+ Qt::KeyboardModifiers modifier = keyEvent->modifiers();
+
+ if (modifier == Qt::ControlModifier)
+ {
+ char Msg[] = "\0\r";
+
+ if (key == Qt::Key_BracketLeft)
+ Msg[0] = 0x1b;
+ if (key == Qt::Key_Z)
+ Msg[0] = 0x1a;
+ else if (key == Qt::Key_C)
+ Msg[0] = 3;
+ else if (key == Qt::Key_D)
+ Msg[0] = 4;
+
+ if (Msg[0])
+ {
+ if (Sess->KISSSession)
+ {
+ // Send to ax.25 code
+
+ SendtoAX25(Sess->KISSSession, (unsigned char *)Msg, (int)strlen(Msg));
+ }
+ else if (Sess->AGWSession)
+ {
+ // Terminal is in AGWPE mode - send as AGW frame
+
+ AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Msg, (int)strlen(Msg));
+
+ }
+ else if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState)
+ {
+ Sess->clientSocket->write(Msg);
+ }
+
+ return true;
+ }
+ }
+
+ if (key == Qt::Key_Up)
+ {
+ // Scroll up
+
+ if (Sess->KbdStack[Sess->StackIndex] == NULL)
+ return true;
+
+ // If anything typed, stack part command
+
+ QByteArray stringData = Sess->inputWindow->text().toUtf8();
+
+ if (stringData.length() && Sess->StackIndex == 0)
+ {
+ if (Sess->KbdStack[49])
+ free(Sess->KbdStack[49]);
+
+ for (int i = 48; i >= 0; i--)
+ {
+ Sess->KbdStack[i + 1] = Sess->KbdStack[i];
+ }
+
+ Sess->KbdStack[0] = qstrdup(stringData.data());
+ Sess->StackIndex++;
+ }
+
+ Sess->inputWindow->setText(Sess->KbdStack[Sess->StackIndex]);
+ Sess->inputWindow->cursorForward(strlen(Sess->KbdStack[Sess->StackIndex]));
+
+ Sess->StackIndex++;
+ if (Sess->StackIndex == 50)
+ Sess->StackIndex = 49;
+
+ return true;
+ }
+ else if (key == Qt::Key_Down)
+ {
+ // Scroll down
+
+ if (Sess->StackIndex == 0)
+ {
+ Sess->inputWindow->setText("");
+ return true;
+ }
+
+ Sess->StackIndex--;
+
+ if (Sess->StackIndex && Sess->KbdStack[Sess->StackIndex - 1])
+ {
+ Sess->inputWindow->setText(Sess->KbdStack[Sess->StackIndex - 1]);
+ Sess->inputWindow->cursorForward(strlen(Sess->KbdStack[Sess->StackIndex - 1]));
+ }
+ else
+ Sess->inputWindow->setText("");
+
+ return true;
+ }
+ else if (key == Qt::Key_Return || key == Qt::Key_Enter)
+ {
+ LreturnPressed(Sess);
+ return true;
+ }
+
+ return false;
+ }
+
+ if (event->type() == QEvent::MouseButtonPress)
+ {
+ QMouseEvent *k = static_cast (event);
+
+ // Paste on Right Click
+
+ if (k->button() == Qt::RightButton)
+ {
+ Sess->inputWindow->paste();
+ return true;
+ }
+ return QMainWindow::eventFilter(obj, event);
+ }
+ }
+ }
+ return QMainWindow::eventFilter(obj, event);
+}
+
+QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State)
+{
+ QAction * Act = new QAction(Label, parent);
+ if (Menu)
+ Menu->addAction(Act);
+
+ Act->setCheckable(true);
+ if (State)
+ Act->setChecked(true);
+
+ parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked()));
+
+ Act->setFont(*menufont);
+
+ return Act;
+}
+
+// This now creates all window types - Term, Mon, Combined, Listen
+
+int xCount = 0;
+
+Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label)
+{
+ Ui_ListenSession * Sess = new(Ui_ListenSession);
+
+ // Need to explicity initialise on Qt4
+
+ Sess->termWindow = NULL;
+ Sess->monWindow = NULL;
+ Sess->inputWindow = NULL;
+
+ for (int i = 0; i < 50; i++)
+ Sess->KbdStack[i] = NULL;
+
+ Sess->StackIndex = 0;
+ Sess->InputMode = 0;
+ Sess->SlowTimer = 0;
+ Sess->MonData = 0;
+ Sess->OutputSaveLen = 0;
+ Sess->MonSaveLen = 0;
+ Sess->PortMonString[0] = 0;
+ Sess->portmask = 0;
+ Sess->portmask = 1;
+ Sess->mtxparam = 1;
+ Sess->mcomparam = 1;
+ Sess->monUI = 0;
+ Sess->MonitorNODES = 0;
+ Sess->MonitorColour = 1;
+ Sess->CurrentHost = 0;
+
+ Sess->SessionType = Type;
+ Sess->clientSocket = NULL;
+ Sess->AGWSession = NULL;
+ Sess->AGWMonSession = NULL;
+ Sess->KISSSession = NULL;
+ Sess->KISSMode = 0;
+ Sess->TTActive = 0;
+ Sess->TTFlashToggle = 0;
+ Sess->pageBuffer[0] = 0;
+ Sess->Tab = 0;
+
+ _sessions.push_back(Sess);
+
+// Sess->TT = new Ui_TeleTextDialog();
+
+// Sess->TT->setupUi(&Sess->TTUI);
+
+// Sess->TTUI.show();
+// Sess->TTUI.raise();
+// Sess->TTUI.activateWindow();
+
+ // Sess->setObjectName(QString::fromUtf8("Sess"));
+
+ if (TermMode == MDI)
+ {
+ Sess->sw = mdiArea->addSubWindow(Sess);
+ // Sess->installEventFilter(parent);
+
+ Sess->sw->resize(800, 600);
+ }
+ else if (TermMode == Tabbed)
+ {
+ Sess->Tab = xCount++;
+
+ if (Type == Mon)
+ tabWidget->addTab(Sess, "Monitor");
+ else
+ tabWidget->addTab(Sess, Label);
+ }
+
+ Sess->installEventFilter(parent);
+
+ QSettings settings(GetConfPath(), QSettings::IniFormat);
+
+#ifdef ANDROID
+ QFont font = QFont(settings->value("FontFamily", "Driod Sans Mono").value(),
+ settings->value("PointSize", 12).toInt(),
+ settings->value("Weight", 50).toInt());
+#else
+ QFont font = QFont(settings.value("FontFamily", "Courier New").value(),
+ settings.value("PointSize", 10).toInt(),
+ settings.value("Weight", 50).toInt());
+#endif
+
+ if ((Type & Mon))
+ {
+ Sess->monWindow = new QTextEdit(Sess);
+ Sess->monWindow->setReadOnly(1);
+ Sess->monWindow->document()->setMaximumBlockCount(10000);
+ Sess->monWindow->setFont(font);
+ Sess->monWindow->setStyleSheet(monStyleSheet);
+ mythis->connect(Sess->monWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged()));
+ }
+
+ if ((Type & (Listen | Term)))
+ {
+ Sess->termWindow = new QTextEdit(Sess);
+ Sess->termWindow->setReadOnly(1);
+ Sess->termWindow->document()->setMaximumBlockCount(10000);
+ Sess->termWindow->setFont(font);
+ Sess->termWindow->setStyleSheet(termStyleSheet);
+
+ Sess->TTLabel = new QLabel(Sess);
+ Sess->TTLabel->setGeometry(QRect(0,0 ,500, 500));
+ Sess->TTLabel->setVisible(false);
+
+ Sess->TTBitmap = new QImage(40 * 15, 25 * 19, QImage::Format_RGB32);
+ Sess->TTBitmap->fill(Qt::black);
+
+/*
+
+ char Page[4096];
+
+ QFile file("/savepage.txt");
+ file.open(QIODevice::ReadOnly);
+ file.read(Page, 4096);
+ file.close();
+
+ Sess->TTActive = 1;
+ strcpy(Sess->pageBuffer, Page);
+ DecodeTeleText(Sess, Sess->pageBuffer);
+
+*/
+
+ Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap));
+
+ Sess->TTLabel->setContextMenuPolicy(Qt::CustomContextMenu);
+ mythis->connect(Sess->TTLabel, SIGNAL(customContextMenuRequested(const QPoint&)),
+ parent, SLOT(showContextMenuL()));
+
+ mythis->connect(Sess->termWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged()));
+
+ Sess->inputWindow = new QLineEdit(Sess);
+ Sess->inputWindow->installEventFilter(parent);
+ Sess->inputWindow->setFont(font);
+ Sess->inputWindow->setStyleSheet(inputStyleSheet);
+ Sess->inputWindow->setContextMenuPolicy(Qt::PreventContextMenu);
+
+ mythis->connect(Sess->inputWindow, SIGNAL(selectionChanged()), parent, SLOT(onLEselectionChanged()));
+ }
+
+ if (Type == Term || Type == Listen)
+ {
+ // Term Only or Listen Only
+
+ Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)),
+ parent, SLOT(showContextMenuT(const QPoint &)));
+
+ }
+
+ if (Type == Mon)
+ {
+ // Monitor Only
+
+ Sess->monWindow->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ mythis->connect(Sess->monWindow, SIGNAL(customContextMenuRequested(const QPoint&)),
+ parent, SLOT(showContextMenuMOnly(const QPoint &)));
+
+ }
+
+ if (Type == (Term | Mon))
+ {
+ // Combined Term and Mon. Add Custom Menu to set Mon/Term Split with Right Click
+
+ Sess->monWindow->setContextMenuPolicy(Qt::CustomContextMenu);
+ Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu);
+
+
+ mythis->connect(Sess->monWindow, SIGNAL(customContextMenuRequested(const QPoint&)),
+ parent, SLOT(showContextMenuM(const QPoint &)));
+
+ mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)),
+ parent, SLOT(showContextMenuMT(const QPoint &)));
+ }
+
+ if (Sess->SessionType == Mon) // Mon Only
+ Sess->setWindowTitle("Monitor Session Disconnected");
+ else if (Sess->SessionType == Listen) // Mon Only
+ Sess->setWindowTitle("Listen Window Disconnected");
+ else
+ Sess->setWindowTitle("Disconnected");
+
+ Sess->installEventFilter(mythis);
+
+ Sess->show();
+
+ int pos = (_sessions.size() - 1) * 20;
+
+ if (TermMode == MDI)
+ {
+ Sess->sw->move(pos, pos);
+ }
+
+ QSize Size(800, 602); // Not actually used, but Event constructor needs it
+
+ QResizeEvent event(Size, Size);
+
+ QApplication::sendEvent(Sess, &event); // Resize Widgets to fix Window
+
+ return Sess;
+}
+
+QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent)
+{
+ int i;
+ char Title[80];
+
+ // Get configuration path for MacOS.
+ std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString();
+ std::string conf_path = directory + "/QtTermTCP.ini";
+
+ //mkdir(directory.c_str(), 0775);
+
+ _server = new QTcpServer();
+
+ mythis = this;
+
+ ui.setupUi(this);
+
+ initUTF8();
+
+ mymenuBar = new QMenuBar(this);
+ mymenuBar->setGeometry(QRect(0, 0, 781, 26));
+ setMenuBar(mymenuBar);
+
+ toolBar = new QToolBar(this);
+ toolBar->setObjectName("mainToolbar");
+ addToolBar(Qt::BottomToolBarArea, toolBar);
+
+ QSettings mysettings(GetConfPath(), QSettings::IniFormat);
+
+ restoreGeometry(mysettings.value("geometry").toByteArray());
+ restoreState(mysettings.value("windowState").toByteArray());
+
+ GetSettings();
+
+ // Set background colours
+
+ sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);",
+ monBackground.red(), monBackground.green(), monBackground.blue());
+
+ sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);",
+ termBackground.red(), termBackground.green(), termBackground.blue());
+
+ sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);",
+ inputText.red(), inputText.green(), inputText.blue(),
+ inputBackground.red(), inputBackground.green(), inputBackground.blue());
+
+
+#ifdef ANDROID
+ menufont = new QFont(mysettings.value("MFontFamily", "Driod Sans").value(),
+ mysettings.value("MPointSize", 12).toInt(),
+ mysettings.value("MWeight", 50).toInt());
+#else
+ menufont = new QFont(mysettings.value("MFontFamily", "Aerial").value(),
+ mysettings.value("MPointSize", 10).toInt(),
+ mysettings.value("MWeight", 50).toInt());
+
+#endif
+ if (TermMode == MDI)
+ {
+ mdiArea = new QMdiArea(ui.centralWidget);
+
+ mdiArea->setGeometry(QRect(0, 0, 771, 571));
+
+ mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+
+ connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(xon_mdiArea_changed()));
+
+ setCentralWidget(mdiArea);
+ }
+ else if (TermMode == Tabbed)
+ {
+ Ui_ListenSession * Sess;
+ int index = 0;
+
+ tabWidget = new QTabWidget(this);
+
+ tabWidget->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ connect(tabWidget, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &)));
+
+ ui.verticalLayout->addWidget(tabWidget);
+
+ tabWidget->setTabPosition(QTabWidget::South);
+
+ Sess = newWindow(this, TabType[0], "Sess 1");
+ Sess->CurrentHost = currentHost[index++];
+ Sess = newWindow(this, TabType[1], "Sess 2");
+ Sess->CurrentHost = currentHost[index++];
+ Sess = newWindow(this, TabType[2], "Sess 3");
+ Sess->CurrentHost = currentHost[index++];
+ Sess = newWindow(this, TabType[3], "Sess 4");
+ Sess->CurrentHost = currentHost[index++];
+ Sess = newWindow(this, TabType[4], "Sess 5");
+ Sess->CurrentHost = currentHost[index++];
+ Sess = newWindow(this, TabType[5], "Sess 6");
+ Sess->CurrentHost = currentHost[index++];
+ Sess = newWindow(this, TabType[6], "Sess 7");
+ Sess->CurrentHost = currentHost[index++];
+ Sess = newWindow(this, TabType[7], "Monitor");
+ Sess->CurrentHost = currentHost[index++];
+ Sess = newWindow(this, TabType[8], "Monitor");
+ Sess->CurrentHost = currentHost[index++];
+
+ ActiveSession = _sessions.at(0);
+
+ connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSelected(int)));
+
+ tabWidget->setFont(*menufont);
+
+ }
+
+ sprintf(Title, "QtTermTCP Version %s", VersionString);
+
+ this->setWindowTitle(Title);
+
+ //#ifdef ANDROID
+ // mymymenuBar->setVisible(false);
+ //#endif
+
+ if (TermMode == Single)
+ windowMenu = mymenuBar->addMenu("");
+ else
+ windowMenu = mymenuBar->addMenu(tr("&Window"));
+
+ connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu()));
+ windowMenu->setFont(*menufont);
+
+ newTermAct = new QAction(tr("New Terminal Window"), this);
+ connect(newTermAct, SIGNAL(triggered()), this, SLOT(doNewTerm()));
+
+ newMonAct = new QAction(tr("New Monitor Window"), this);
+ connect(newMonAct, SIGNAL(triggered()), this, SLOT(doNewMon()));
+
+ newCombinedAct = new QAction(tr("New Combined Term/Mon Window"), this);
+ connect(newCombinedAct, SIGNAL(triggered()), this, SLOT(doNewCombined()));
+
+ if (TermMode == MDI)
+ {
+ closeAct = new QAction(tr("Cl&ose"), this);
+ closeAct->setStatusTip(tr("Close the active window"));
+ connect(closeAct, SIGNAL(triggered()), mdiArea, SLOT(closeActiveSubWindow()));
+
+ closeAllAct = new QAction(tr("Close &All"), this);
+ closeAllAct->setStatusTip(tr("Close all the windows"));
+ connect(closeAllAct, SIGNAL(triggered()), mdiArea, SLOT(closeAllSubWindows()));
+
+ tileAct = new QAction(tr("&Tile"), this);
+ tileAct->setStatusTip(tr("Tile the windows"));
+ connect(tileAct, SIGNAL(triggered()), mdiArea, SLOT(tileSubWindows()));
+
+ cascadeAct = new QAction(tr("&Cascade"), this);
+ cascadeAct->setStatusTip(tr("Cascade the windows"));
+ connect(cascadeAct, SIGNAL(triggered()), this, SLOT(doCascade()));
+
+ nextAct = new QAction(tr("Ne&xt"), this);
+ nextAct->setShortcuts(QKeySequence::NextChild);
+ nextAct->setStatusTip(tr("Move the focus to the next window"));
+ connect(nextAct, SIGNAL(triggered()), mdiArea, SLOT(activateNextSubWindow()));
+
+ previousAct = new QAction(tr("Pre&vious"), this);
+ previousAct->setShortcuts(QKeySequence::PreviousChild);
+ previousAct->setStatusTip(tr("Move the focus to the previous window"));
+ connect(previousAct, SIGNAL(triggered()), mdiArea, SLOT(activatePreviousSubWindow()));
+ }
+
+ quitAction = new QAction(tr("&Quit"), this);
+ connect(quitAction, SIGNAL(triggered()), this, SLOT(doQuit()));
+
+ windowMenuSeparatorAct = new QAction(this);
+ windowMenuSeparatorAct->setSeparator(true);
+
+ updateWindowMenu();
+
+ connectMenu = mymenuBar->addMenu(tr("&Connect"));
+
+ actHost[16] = new QAction("AGW Connect", this);
+ actHost[16]->setFont(*menufont);
+ actHost[16]->setVisible(0);
+ connectMenu->addAction(actHost[16]);
+
+ connect(actHost[16], SIGNAL(triggered()), this, SLOT(Connect()));
+
+ actHost[17] = new QAction("VARA Connect", this);
+ actHost[17]->setFont(*menufont);
+ actHost[17]->setVisible(0);
+ connectMenu->addAction(actHost[17]);
+
+ connect(actHost[17], SIGNAL(triggered()), this, SLOT(Connect()));
+
+ actHost[18] = new QAction("KISS Connect", this);
+ actHost[18]->setFont(*menufont);
+ actHost[18]->setVisible(KISSEnable);
+ actHost[18]->setEnabled(0);
+ connectMenu->addAction(actHost[18]);
+
+ connect(actHost[18], SIGNAL(triggered()), this, SLOT(Connect()));
+
+ for (i = 0; i < MAXHOSTS; i++)
+ {
+ if (SessName[i][0])
+ {
+ char Lable[256];
+ sprintf(Lable, "%s(%s)", Host[i], SessName[i]);
+ actHost[i] = new QAction(Lable, this);
+ }
+ else
+ actHost[i] = new QAction(Host[i], this);
+
+ actHost[i]->setFont(*menufont);
+ connectMenu->addAction(actHost[i]);
+ connect(actHost[i], SIGNAL(triggered()), this, SLOT(Connect()));
+ }
+
+ discAction = mymenuBar->addAction("&Disconnect");
+
+ // Place discAction in mac preferences menu, otherwise it doesn't appear
+ if (is_mac == true) {
+ QMenu * app_menu = mymenuBar->addMenu("App Menu");
+ discAction->setMenuRole(QAction::ApplicationSpecificRole);
+ app_menu->addAction(discAction);
+
+ }
+
+ connect(discAction, SIGNAL(triggered()), this, SLOT(Disconnect()));
+ discAction->setEnabled(false);
+
+ toolBar->setFont(*menufont);
+
+#ifndef ANDROID
+ toolBar->setVisible(false);
+#endif
+ but4 = new QToolButton();
+ but4->setPopupMode(QToolButton::InstantPopup);
+ but4->setText("Window");
+ but4->addAction(windowMenu->menuAction());
+ but4->setFont(*menufont);
+ toolBar->addWidget(but4);
+
+ but5 = new QToolButton();
+ but5->setPopupMode(QToolButton::InstantPopup);
+ but5->setText("Connect");
+ but5->addAction(connectMenu->menuAction());
+ but5->setFont(*menufont);
+
+ toolBar->addWidget(but5);
+
+ toolBar->addAction(discAction);
+
+ setupMenu = mymenuBar->addMenu(tr("&Setup"));
+ hostsubMenu = setupMenu->addMenu("Hosts");
+ hostsubMenu->setFont(*menufont);
+
+ for (i = 0; i < MAXHOSTS; i++)
+ {
+ if (Host[i][0])
+ {
+ char Label[256];
+
+ if (SessName[i][0])
+ sprintf(Label, "%s(%s)", Host[i], SessName[i]);
+ else
+ strcpy(Label, Host[i]);
+
+ actSetup[i] = new QAction(Label, this);
+ }
+ else
+ actSetup[i] = new QAction("New Host", this);
+
+ hostsubMenu->addAction(actSetup[i]);
+ connect(actSetup[i], SIGNAL(triggered()), this, SLOT(SetupHosts()));
+
+ actSetup[i]->setFont(*menufont);
+ }
+
+
+ // Setup Presentation Options
+
+ setupMenu->addSeparator()->setText(tr("Presentation"));
+
+ QActionGroup * termGroup = new QActionGroup(this);
+
+ singleAct = setupMenuLine(nullptr, (char *)"Single Window (Term + Mon)", this, (TermMode == Single) && (singlemodeFormat == Term + Mon));
+ singleAct2 = setupMenuLine(nullptr, (char *)"Single Window (Term only)", this, (TermMode == Single) && (singlemodeFormat == Term));
+ MDIAct = setupMenuLine(nullptr, (char *)"MDI", this, TermMode == MDI);
+ tabbedAct = setupMenuLine(nullptr, (char *)"Tabbed", this, TermMode == Tabbed);
+
+ termGroup->addAction(singleAct);
+ termGroup->addAction(singleAct2);
+ termGroup->addAction(MDIAct);
+ termGroup->addAction(tabbedAct);
+
+ setupMenu->addAction(singleAct);
+ setupMenu->addAction(singleAct2);
+ setupMenu->addAction(MDIAct);
+ setupMenu->addAction(tabbedAct);
+
+ setupMenu->addSeparator();
+
+ actFonts = new QAction("Terminal Font", this);
+ setupMenu->addAction(actFonts);
+ connect(actFonts, SIGNAL(triggered()), this, SLOT(doFonts()));
+ actFonts->setFont(*menufont);
+
+ actmenuFont = new QAction("Menu Font", this);
+ setupMenu->addAction(actmenuFont);
+ connect(actmenuFont, SIGNAL(triggered()), this, SLOT(doMFonts()));
+ actmenuFont->setFont(*menufont);
+
+ actColours = new QAction("Choose Colours", this);
+ setupMenu->addAction(actColours);
+ connect(actColours, SIGNAL(triggered()), this, SLOT(doColours()));
+ actColours->setFont(*menufont);
+
+ AGWAction = new QAction("AGW Setup", this);
+ setupMenu->addAction(AGWAction);
+ connect(AGWAction, SIGNAL(triggered()), this, SLOT(AGWSlot()));
+ AGWAction->setFont(*menufont);
+
+ VARAAction = new QAction("VARA Setup", this);
+ setupMenu->addAction(VARAAction);
+ connect(VARAAction, SIGNAL(triggered()), this, SLOT(VARASlot()));
+ VARAAction->setFont(*menufont);
+
+ KISSAction = new QAction("KISS Setup", this);
+ setupMenu->addAction(KISSAction);
+ connect(KISSAction, SIGNAL(triggered()), this, SLOT(KISSSlot()));
+ KISSAction->setFont(*menufont);
+
+
+ actChatMode = setupMenuLine(setupMenu, (char *)"Chat Terminal Mode (Send Keepalives)", this, ChatMode);
+ actAutoTeletext = setupMenuLine(setupMenu, (char *)"Auto switch to Teletext", this, AutoTeletext);
+ actBells = setupMenuLine(setupMenu, (char *)"Enable Bells", this, Bells);
+ actStripLF = setupMenuLine(setupMenu, (char *)"Strip Line Feeds", this, StripLF);
+
+ AlertAction = new QAction("Alert Setup", this);
+ setupMenu->addAction(AlertAction);
+ connect(AlertAction, SIGNAL(triggered()), this, SLOT(AlertSlot()));
+ AlertAction->setFont(*menufont);
+
+
+ setupMenu->addAction(new QAction("Interpret non-UTF8 input as:", this));
+ setupMenu->setFont(*menufont);
+
+ QActionGroup * cpGroup = new QActionGroup(this);
+
+ actnoConv = setupMenuLine(nullptr, (char *)" Don't Convert (assume is UTF-8)", this, convUTF8 == -1);
+ actAuto = setupMenuLine(nullptr, (char *)" Auto", this, convUTF8 == 0);
+ actCP1251 = setupMenuLine(nullptr, (char *)" CP1251 (Cyrillic)", this, convUTF8 == 1251);
+ actCP1252 = setupMenuLine(nullptr, (char *)" CP1252 (Western Europe)", this, convUTF8 == 1252);
+ actCP437 = setupMenuLine(nullptr, (char *)" CP437 (Windows Line Draw)", this, convUTF8 == 437);
+
+ cpGroup->addAction(actnoConv);
+ cpGroup->addAction(actAuto);
+ cpGroup->addAction(actCP1251);
+ cpGroup->addAction(actCP1252);
+ cpGroup->addAction(actCP437);
+
+ setupMenu->addAction(actnoConv);
+ setupMenu->addAction(actAuto);
+ setupMenu->addAction(actCP1251);
+ setupMenu->addAction(actCP1252);
+ setupMenu->addAction(actCP437);
+
+ monitorMenu = mymenuBar->addMenu(tr("&Monitor"));
+
+ MonTX = setupMenuLine(monitorMenu, (char *)"Monitor TX", this, 1);
+ MonSup = setupMenuLine(monitorMenu, (char *)"Monitor Supervisory", this, 1);
+ MonUI = setupMenuLine(monitorMenu, (char *)"Only Monitor UI Frames", this, 0);
+ MonNodes = setupMenuLine(monitorMenu, (char *)"Monitor NODES Broadcasts", this, 0);
+ MonColour = setupMenuLine(monitorMenu, (char *)"Enable Colour", this, 1);
+
+ for (i = 0; i < MAXPORTS + 1; i++)
+ {
+ MonPort[i] = setupMenuLine(monitorMenu, (char *)"Port", this, 0);
+ MonPort[i]->setVisible(false);
+ }
+
+ but1 = new QToolButton();
+ but1->setPopupMode(QToolButton::InstantPopup);
+ but1->setText("Monitor");
+ but1->addAction(monitorMenu->menuAction());
+ toolBar->addWidget(but1);
+
+ but2 = new QToolButton();
+ but2->setPopupMode(QToolButton::InstantPopup);
+ but2->setText("Setup");
+ but2->addAction(setupMenu->menuAction());
+ toolBar->addWidget(but2);
+
+ ListenAction = mymenuBar->addAction("&Listen");
+ connect(ListenAction, SIGNAL(triggered()), this, SLOT(ListenSlot()));
+
+ toolBar->addAction(ListenAction);
+
+ YAPPMenu = mymenuBar->addMenu(tr("&YAPP"));
+
+ YAPPSend = new QAction("Send File", this);
+ YAPPSetRX = new QAction("Set Receive Directory", this);
+ YAPPSetSize = new QAction("Set Max Size", this);
+ YAPPSend->setFont(*menufont);
+ YAPPSetRX->setFont(*menufont);
+ YAPPSetSize->setFont(*menufont);
+
+ YAPPMenu->addAction(YAPPSend);
+ YAPPMenu->addAction(YAPPSetRX);
+ YAPPMenu->addAction(YAPPSetSize);
+ YAPPSend->setEnabled(false);
+
+ connect(YAPPSend, SIGNAL(triggered()), this, SLOT(doYAPPSend()));
+ connect(YAPPSetRX, SIGNAL(triggered()), this, SLOT(doYAPPSetRX()));
+ connect(YAPPSetSize, SIGNAL(triggered()), this, SLOT(doYAPPSetSize()));
+
+
+ but3 = new QToolButton();
+ but3->setPopupMode(QToolButton::InstantPopup);
+ but3->setText("YAPP");
+ but3->addAction(YAPPMenu->menuAction());
+ but3->setFont(*menufont);
+ toolBar->addWidget(but3);
+
+ toolBar->setFont(*menufont);
+
+ // Set up Status Bar
+
+ setStyleSheet("QStatusBar{border-top: 1px outset black;} QStatusBar::item { border: 1px solid black; border-radius: 3px;}");
+ // setStyleSheet("QStatusBar{border-top: 1px outset black;}");
+
+
+ Status4 = new QLabel("");
+ Status3 = new QLabel(" ");
+ Status2 = new QLabel(" ");
+ Status1 = new QLabel(" Disconnected ");
+
+ Status1->setMinimumWidth(100);
+ Status2->setMinimumWidth(100);
+ Status3->setMinimumWidth(100);
+ Status4->setMinimumWidth(100);
+
+ myStatusBar = statusBar();
+
+ statusBar()->addPermanentWidget(Status4);
+ statusBar()->addPermanentWidget(Status3);
+ statusBar()->addPermanentWidget(Status2);
+ statusBar()->addPermanentWidget(Status1);
+
+ statusBar()->setVisible(AGWEnable | VARAEnable | KISSEnable);
+ // Restore saved sessions
+
+ if (TermMode == Single)
+ {
+ Ui_ListenSession * Sess = newWindow(this, singlemodeFormat);
+
+ ActiveSession = Sess;
+ Sess->CurrentHost = currentHost[0];
+
+ ui.verticalLayout->addWidget(Sess);
+
+ connectMenu->setEnabled(true);
+ discAction->setEnabled(false);
+ YAPPSend->setEnabled(false);
+ }
+
+ if (TermMode == MDI)
+ {
+ int n = atoi(sessionList);
+ int index = 0;
+
+ char *p, *Context;
+ char delim[] = "|";
+
+ int type = 0, host = 0, topx, leftx, bottomx, rightx;
+
+ p = strtok_s((char *)sessionList, delim, &Context);
+
+ while (n--)
+ {
+ p = strtok_s(NULL, delim, &Context);
+
+ sscanf(p, "%d,%d,%d,%d,%d,%d", &type, &host, &topx, &leftx, &bottomx, &rightx);
+
+ Ui_ListenSession * Sess = newWindow(this, type);
+
+ Sess->CurrentHost = currentHost[index++];;
+
+ QRect r(leftx, topx, rightx - leftx, bottomx - topx);
+
+ Sess->sw->setGeometry(r);
+ Sess->sw->move(leftx, topx);
+
+ }
+ }
+
+ QTimer *timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot()));
+ timer->start(10000);
+
+ QTimer *timer2 = new QTimer(this);
+ connect(timer2, SIGNAL(timeout()), this, SLOT(KISSTimerSlot()));
+ timer2->start(100);
+
+ // Run timer now to connect to AGW if configured
+
+ MyTimerSlot();
+
+ if (listenEnable)
+ _server->listen(QHostAddress::Any, listenPort);
+
+ connect(_server, SIGNAL(newConnection()), this, SLOT(onNewConnection()));
+
+ setFonts();
+
+ if (VARAEnable)
+ OpenPTTPort();
+
+ memset(axMYCALL, 0, 7);
+ ConvToAX25(MYCALL, axMYCALL);
+
+ // Do any autoconnects
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ if (AutoConnect[i] > 0)
+ {
+ Ui_ListenSession * Sess = _sessions.at(i);
+
+ Sess->clientSocket = new myTcpSocket();
+ Sess->clientSocket->Sess = Sess;
+
+ connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
+ connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
+
+ Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]);
+ }
+ }
+
+}
+
+void QtTermTCP::showContextMenu(const QPoint &point)
+{
+ if (point.isNull())
+ return;
+
+ QTabBar* tabBar = tabWidget->tabBar();
+ QRect Wrect = tabWidget->rect();
+ QRect Brect = tabBar->rect();
+ QPoint myPoint = point;
+
+ int n = myPoint.y() - (Wrect.height() - Brect.height());
+
+ myPoint.setY(n);
+
+// QPoint tabBarPoint = mapTo(tabBar, point);
+
+ int tabIndex = tabBar->tabAt(myPoint);
+
+ QMenu menu(this);
+
+ QAction * Act = new QAction("AutoConnect on load", this);
+ Act->setObjectName(QString::number(tabIndex));
+
+ menu.addAction(Act);
+
+ Act->setCheckable(true);
+
+ if (AutoConnect[tabIndex] <= 0)
+ Act->setChecked(false);
+ else
+ Act->setChecked(true);
+
+ connect(Act, SIGNAL(triggered()), this, SLOT(autoConnectChecked()));
+
+ QAction * selected_action = menu.exec(tabWidget->mapToGlobal(point));
+
+}
+
+void QtTermTCP::autoConnectChecked()
+{
+ QAction * Act = static_cast(QObject::sender());
+ QString Tab = Act->objectName();
+ int tabNo = Tab.toInt();
+
+ tabWidget->setCurrentIndex(tabNo);
+
+ Ui_ListenSession *Sess = (Ui_ListenSession *)tabWidget->currentWidget();
+ int state = Act->isChecked();
+
+ if (state == 0)
+ AutoConnect[tabNo] = 0;
+ else
+ {
+ if (Sess->clientSocket) // Connected
+ AutoConnect[tabNo] = 1;
+ else
+ AutoConnect[tabNo] = 0;
+ }
+}
+
+
+void QtTermTCP::setFonts()
+{
+ windowMenu->menuAction()->setFont(*menufont);
+ connectMenu->menuAction()->setFont(*menufont);
+ setupMenu->menuAction()->setFont(*menufont);
+ monitorMenu->menuAction()->setFont(*menufont);
+ YAPPMenu->menuAction()->setFont(*menufont);
+
+ if (tabWidget)
+ tabWidget->setFont(*menufont);
+ mymenuBar->setFont(*menufont);
+ toolBar->setFont(*menufont);
+ but1->setFont(*menufont);
+ but2->setFont(*menufont);
+ but3->setFont(*menufont);
+ but4->setFont(*menufont);
+ but5->setFont(*menufont);
+ discAction->setFont(*menufont);
+ ListenAction->setFont(*menufont);
+
+ for (int i = 0; i < MAXHOSTS; i++)
+ {
+ actHost[i]->setFont(*menufont);
+ actSetup[i]->setFont(*menufont);
+ }
+
+ actHost[16]->setFont(*menufont); // AGW Host
+}
+
+void QtTermTCP::doQuit()
+{
+ if (_server->isListening())
+ _server->close();
+
+ SaveSettings();
+
+ QCoreApplication::quit();
+}
+
+// "Copy on select" Code
+
+
+void QtTermTCP::onTEselectionChanged()
+{
+ QTextEdit * x = static_cast(QObject::sender());
+
+ if (isActiveWindow())
+ x->copy();
+}
+
+void QtTermTCP::onLEselectionChanged()
+{
+ QLineEdit * x = static_cast(QObject::sender());
+ if (isActiveWindow())
+ x->copy();
+}
+
+void QtTermTCP::setVDMode()
+{
+ QAction * sender = static_cast(QObject::sender());
+
+ QTextEdit * window = static_cast(sender->parentWidget());
+
+ // Need to find session with this window as owner
+
+ Ui_ListenSession * Sess = NULL;
+
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ if (Sess->termWindow == window)
+ {
+ Sess->TTActive ^= 1;
+ DoTermResize(Sess);
+ break;
+ }
+ }
+}
+
+int splitY; // Value when menu added
+
+void QtTermTCP::setSplit()
+{
+ QAction * sender = static_cast(QObject::sender());
+
+ QWidget * Parent = sender->parentWidget();
+
+ if (Parent)
+ Parent = Parent->parentWidget();
+
+ int y = Parent->rect().height() - 50;
+
+ // y is height of whole windom. splitX is new split position
+ // So split = 100 * splitx/x
+
+ Split = (splitY * 100) / y;
+
+ if (Split < 10)
+ Split = 10;
+ else if (Split > 90)
+ Split = 90;
+
+ QSize size(800, 602);
+ QResizeEvent event(size, size);
+
+ eventFilter(Parent, &event);
+}
+
+void QtTermTCP::ClearScreen()
+{
+ QAction * sender = static_cast(QObject::sender());
+ QTextEdit * window = static_cast(sender->parentWidget());
+ window->clear();
+}
+
+
+void QtTermTCP::showContextMenuMT(const QPoint &pt) // Term Window
+{
+ // Monitor and Terminal (Term Half)
+
+ QTextEdit* sender = static_cast(QObject::sender());
+
+ QMenu *menu = sender->createStandardContextMenu();
+
+ QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}QMenu::separator {height: 2px;background: rgb(58, 80, 116);margin-left: 10px;margin-right: 5px;}";
+ menu->setStyleSheet(style);
+
+ QAction * actSplit = new QAction("Set Monitor/Output Split", sender);
+ QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender);
+ QAction * actClear = new QAction("Clear Screen Buffer", sender);
+
+ menu->addAction(actSplit);
+ menu->addAction(actVDMode);
+ menu->addAction(actClear);
+
+ splitY = pt.y() + termX;
+
+ connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit()));
+ connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode()));
+ connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen()));
+
+ menu->exec(sender->mapToGlobal(pt));
+ delete menu;
+}
+
+void QtTermTCP::showContextMenuMOnly(const QPoint &pt)
+{
+ // Monitor only
+
+ QTextEdit* sender = static_cast(QObject::sender());
+
+ QMenu *menu = sender->createStandardContextMenu();
+
+ QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}QMenu::separator {height: 2px;background: rgb(58, 80, 116);margin-left: 10px;margin-right: 5px;}";
+ menu->setStyleSheet(style);
+
+ QAction * actClear = new QAction("Clear Screen Buffer", sender);
+
+ menu->addAction(actClear);
+ connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen()));
+
+ menu->exec(sender->mapToGlobal(pt));
+ delete menu;
+}
+
+
+void QtTermTCP::showContextMenuT(const QPoint &pt) // Term Window
+{
+ // Just Terminal
+
+ QTextEdit* sender = static_cast(QObject::sender());
+
+ QMenu *menu = sender->createStandardContextMenu();
+
+ QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}";
+ menu->setStyleSheet(style);
+
+
+ QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender);
+ QAction * actClear = new QAction("Clear Screen Buffer", sender);
+
+ menu->addAction(actVDMode);
+ menu->addAction(actClear);
+
+ connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode()));
+ connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen()));
+
+ menu->exec(sender->mapToGlobal(pt));
+ delete menu;
+}
+
+
+void QtTermTCP::showContextMenuL() // Term Window
+{
+ // Teletext Label Right Clicked - cancel TT Mode
+
+ QLabel * sender = static_cast(QObject::sender());
+
+ // Need to find session with this label as owner
+
+ Ui_ListenSession * Sess = NULL;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ if (Sess->TTLabel == sender)
+ {
+ Sess->TTActive ^= 1;
+
+ DoTermResize(Sess);
+ break;
+ }
+ }
+}
+
+
+void QtTermTCP::showContextMenuM(const QPoint &pt) // Mon Window
+{
+ QTextEdit* sender = static_cast(QObject::sender());
+
+ QMenu *menu = sender->createStandardContextMenu();
+ QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}";
+ menu->setStyleSheet(style);
+
+ QAction * actSplit = new QAction("Set Monitor/Output Split", sender);
+ QAction * actClear = new QAction("Clear Screen Buffer", sender);
+
+ menu->addAction(actSplit);
+ menu->addAction(actClear);
+
+ splitY = pt.y();
+
+ connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit()));
+ connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen()));
+
+ menu->exec(sender->mapToGlobal(pt));
+ delete menu;
+}
+
+extern "C" void setMenus(int State)
+{
+ // Sets Connect, Disconnect and YAPP Send enable flags to match connection state
+
+ if (State)
+ {
+ connectMenu->setEnabled(false);
+ discAction->setEnabled(true);
+ YAPPSend->setEnabled(true);
+ }
+ else
+ {
+ connectMenu->setEnabled(true);
+ discAction->setEnabled(false);
+ YAPPSend->setEnabled(false);
+ }
+}
+
+extern "C" void SetSessLabel(Ui_ListenSession * Sess, char * label)
+{
+ if (TermMode == MDI)
+ Sess->setWindowTitle(label);
+ else if (TermMode == Tabbed)
+ tabWidget->setTabText(Sess->Tab, label);
+ else if (TermMode == Single)
+ mythis->setWindowTitle(label);
+}
+
+
+extern "C" void ClearSessLabel(Ui_ListenSession * Sess)
+{
+ if (TermMode == MDI)
+ {
+ if (Sess->SessionType == Mon) // Mon Only
+ Sess->setWindowTitle("Monitor Session Disconnected");
+ else if (Sess->SessionType == Listen) // Mon Only
+ Sess->setWindowTitle("Listen Window Disconnected");
+ else
+ Sess->setWindowTitle("Disconnected");
+ }
+ else if (TermMode == Tabbed)
+ {
+ if (Sess->SessionType == Mon) // Mon Only
+ tabWidget->setTabText(Sess->Tab, "Monitor");
+ else
+ {
+ char Label[16];
+ sprintf(Label, "Sess %d", Sess->Tab + 1);
+ tabWidget->setTabText(Sess->Tab, Label);
+ }
+ }
+ else if (TermMode == Single)
+ {
+ if (Sess->SessionType == Mon) // Mon Only
+ mythis->setWindowTitle("Monitor Session Disconnected");
+ else
+ mythis->setWindowTitle("Disconnected");
+ }
+}
+
+void QtTermTCP::tabSelected(int Current)
+{
+ Ui_ListenSession * Sess = NULL;
+
+ if (Current < _sessions.size())
+ {
+ Sess = _sessions.at(Current);
+
+ if (Sess == nullptr)
+ return;
+
+ ActiveSession = Sess;
+
+ tabWidget->tabBar()->setTabTextColor(tabWidget->currentIndex(), oldTabText);
+
+ if (Sess->clientSocket || Sess->AGWSession || Sess->KISSSession || Sess->KISSMode)
+ {
+ connectMenu->setEnabled(false);
+ discAction->setEnabled(true);
+ YAPPSend->setEnabled(true);
+ }
+ else
+ {
+ connectMenu->setEnabled(true);
+ discAction->setEnabled(false);
+ YAPPSend->setEnabled(false);
+ }
+
+ // If a monitor Window, change Monitor config settings
+
+ if (Sess->PortMonString[0])
+ {
+ char * ptr = (char *)malloc(2048);
+ memcpy(ptr, Sess->PortMonString, 2048);
+
+ int NumberofPorts = atoi((char *)&ptr[2]);
+ char *p, *Context;
+ char msg[80];
+ int portnum, m;
+ char delim[] = "|";
+
+ // Remove old Monitor menu
+
+ for (int i = 0; i < 64; i++)
+ {
+ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden
+ }
+
+ p = strtok_s((char *)&ptr[2], delim, &Context);
+
+ while (NumberofPorts--)
+ {
+ p = strtok_s(NULL, delim, &Context);
+ if (p == NULL)
+ break;
+
+ m = portnum = atoi(p);
+
+ sprintf(msg, "Port %s", p);
+
+ if (m == 0)
+ m = 64;
+
+ if (Sess->portmask & ((uint64_t)1 << (m - 1)))
+ SetPortMonLine(portnum, msg, 1, 1);
+ else
+ SetPortMonLine(portnum, msg, 1, 0);
+ }
+ free(ptr);
+
+ MonTX->setChecked(Sess->mtxparam);
+ MonSup->setChecked(Sess->mcomparam);
+ MonUI->setChecked(Sess->monUI);
+ MonNodes->setChecked(Sess->MonitorNODES);
+ MonColour->setChecked(Sess->MonitorColour);
+ }
+ return;
+ }
+}
+
+void QtTermTCP::SetupHosts()
+{
+ QAction * Act = static_cast(QObject::sender());
+ int i;
+
+ for (i = 0; i < MAXHOSTS; i++)
+ {
+ if (Act == actSetup[i])
+ break;
+ }
+
+ if (i > 15)
+ return;
+
+ ConfigHost = i;
+
+ TabDialog tabdialog(0);
+ tabdialog.exec();
+}
+
+
+void QtTermTCP::Connect()
+{
+ QMdiSubWindow * UI;
+ Ui_ListenSession * Sess = nullptr;
+ QAction * Act = static_cast(QObject::sender());
+
+ int i;
+
+ for (i = 0; i < MAXHOSTS; i++)
+ {
+ if (Act == actHost[i])
+ break;
+ }
+
+ SavedHost = i; // Last used
+
+ if (TermMode == MDI)
+ {
+ UI = mdiArea->activeSubWindow();
+
+ for (i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ if (Sess->sw == UI)
+ break;
+ }
+
+ if (i == _sessions.size())
+ return;
+
+ currentHost[i] = SavedHost;
+ }
+
+ else if (TermMode == Tabbed)
+ {
+ Sess = (Ui_ListenSession *)tabWidget->currentWidget();
+ }
+
+ else if (TermMode == Single)
+ Sess = _sessions.at(0);
+
+ if ((Sess == nullptr || Sess->SessionType & Listen))
+ return;
+
+ Sess->CurrentHost = SavedHost;
+
+ currentHost[Sess->Tab] = SavedHost;
+
+ if (Act == actHost[16])
+ {
+ // This runs the AGW Connection dialog
+
+ Sess->CurrentHost = 16; // Iast used
+ AGWConnect dialog(0);
+ dialog.exec();
+ return;
+ }
+
+
+ if (Act == actHost[17])
+ {
+ // This runs the VARA Connection dialog
+
+ Sess->CurrentHost = 17; // Iast used
+ VARADataSock->Sess = Sess;
+ VARASock->Sess = Sess;
+
+ VARAConnect dialog(0);
+ dialog.exec();
+ WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14);
+
+ return;
+ }
+
+ if (Act == actHost[18])
+ {
+ // This runs the KISS Connection dialog
+
+ Sess->CurrentHost = 18; // Iast used
+
+ KISSConnect dialog(0);
+ dialog.exec();
+ return;
+ }
+
+ // Set Monitor Params for this host
+
+ sscanf(MonParams[Sess->CurrentHost], "%llx %x %x %x %x %x",
+ &Sess->portmask, &Sess->mtxparam, &Sess->mcomparam,
+ &Sess->MonitorNODES, &Sess->MonitorColour, &Sess->monUI);
+
+ MonTX->setChecked(Sess->mtxparam);
+ MonSup->setChecked(Sess->mcomparam);
+ MonUI->setChecked(Sess->monUI);
+ MonNodes->setChecked(Sess->MonitorNODES);
+ MonColour->setChecked(Sess->MonitorColour);
+
+ // Remove old Monitor menu
+
+ for (i = 0; i < 64; i++)
+ {
+ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden
+ }
+
+ delete(Sess->clientSocket);
+
+ Sess->clientSocket = new myTcpSocket();
+ Sess->clientSocket->Sess = Sess;
+
+ connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
+ connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
+
+ Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]);
+ return;
+}
+
+extern "C" void rst_timer(TAX25Port * AX25Sess);
+extern "C" void set_unlink(TAX25Port * AX25Sess, Byte * path);
+
+void QtTermTCP::Disconnect()
+{
+ QMdiSubWindow * UI;
+ Ui_ListenSession * Sess = nullptr;
+
+ if (TermMode == MDI)
+ {
+ int i;
+
+ UI = mdiArea->activeSubWindow();
+
+ for (i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ if (Sess->sw == UI)
+ break;
+ }
+
+ if (i == _sessions.size())
+ return;
+ }
+
+ else if (TermMode == Tabbed)
+ {
+ Sess = (Ui_ListenSession *)tabWidget->currentWidget();
+ }
+
+ else if (TermMode == Single)
+ Sess = _sessions.at(0);
+
+ // if AGW send a d frame else disconnect TCP session
+
+ if (Sess->AGWSession)
+ Send_AGW_Ds_Frame(Sess->AGWSession);
+ else if (VARASock && VARASock->Sess == Sess)
+ VARASock->write("DISCONNECT\r");
+ else if (Sess->KISSSession)
+ {
+ if (Sess->KISSMode == 0)
+ {
+ TAX25Port * Port = (TAX25Port *)Sess->KISSSession;
+
+ rst_timer(Port);
+ set_unlink(Port, Port->Path);
+ }
+ else
+ {
+ // KISS UI Mode
+
+ char Msg[128];
+ int Len = sprintf(Msg, "Disconnected\r");
+
+ Sess->KISSMode = 0;
+ SendtoTerm(Sess, Msg, Len);
+ ClearSessLabel(Sess);
+ setMenus(0);
+ Sess->KISSSession = NULL;
+ }
+ }
+ else
+
+ {
+ if (Sess && Sess->clientSocket)
+ Sess->clientSocket->disconnectFromHost();
+ }
+ return;
+}
+
+
+void QtTermTCP::doYAPPSend()
+{
+ QFileDialog dialog(this);
+ QStringList fileNames;
+ dialog.setFileMode(QFileDialog::AnyFile);
+
+ QMdiSubWindow * UI;
+ Ui_ListenSession * Sess = nullptr;
+ int i;
+
+ if (TermMode == MDI)
+ {
+ UI = mdiArea->activeSubWindow();
+
+ for (i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ if (Sess->sw == UI)
+ break;
+ }
+
+ if (i == _sessions.size())
+ return;
+ }
+
+ else if (TermMode == Tabbed)
+ {
+ Sess = (Ui_ListenSession *)tabWidget->currentWidget();
+ }
+
+ else if (TermMode == Single)
+ Sess = _sessions.at(0);
+
+ if (Sess == nullptr)
+ return;
+
+ if ((Sess->SessionType & Mon))
+ {
+ // Turn off monitoring
+
+ setTraceOff(Sess);
+ }
+
+ if (dialog.exec())
+ {
+ char FN[256];
+
+ fileNames = dialog.selectedFiles();
+ if (fileNames[0].length() < 256)
+ {
+ strcpy(FN, fileNames[0].toUtf8());
+ YAPPSendFile(Sess, FN);
+ }
+ }
+}
+
+void QtTermTCP::doYAPPSetRX()
+{
+ QFileDialog dialog(this);
+ QStringList fileNames;
+ dialog.setFileMode(QFileDialog::Directory);
+ dialog.setDirectory(YAPPPath);
+
+ if (dialog.exec())
+ {
+ fileNames = dialog.selectedFiles();
+ if (fileNames[0].length() < 256)
+ strcpy(YAPPPath, fileNames[0].toUtf8());
+
+ SaveSettings();
+ }
+}
+
+Ui_SizeDialog * YappSize;
+
+void QtTermTCP::doYAPPSetSize()
+{
+ // This runs the VARA Configuration dialog
+
+ char valChar[80];
+
+ YappSize = new(Ui_SizeDialog);
+
+ QDialog UI;
+
+ YappSize->setupUi(&UI);
+
+ UI.setFont(*menufont);
+ deviceUI = &UI;
+
+ sprintf(valChar, "%d", MaxRXSize);
+
+ YappSize->maxSize->setText(valChar);
+
+ QObject::connect(YappSize->okButton, SIGNAL(clicked()), this, SLOT(sizeaccept()));
+ QObject::connect(YappSize->cancelButton, SIGNAL(clicked()), this, SLOT(sizereject()));
+
+ UI.exec();
+}
+
+void QtTermTCP::sizeaccept()
+{
+ QVariant Q;
+ Q = YappSize->maxSize->text();
+
+ MaxRXSize = Q.toInt();
+ SaveSettings();
+ delete(YappSize);
+}
+
+
+void QtTermTCP::sizereject()
+{
+ delete(YappSize);
+ deviceUI->reject();
+}
+
+
+void QtTermTCP::menuChecked()
+{
+ QAction * Act = static_cast(QObject::sender());
+
+ int state = Act->isChecked();
+ int newTermMode = TermMode;
+ int newSingleMode = singlemodeFormat;
+
+ if (Act == TabSingle || Act == TabBoth || Act == TabMon)
+ {
+ // Tabbed Window format had changed
+
+ int i = tabWidget->currentIndex();
+
+ if (Act == TabSingle)
+ TabType[i] = Term;
+ else if (Act == TabBoth)
+ TabType[i] = Term + Mon;
+ else
+ TabType[i] = Mon;
+
+ QMessageBox msgBox;
+ msgBox.setText("Tab Types will change next time program is started.");
+ msgBox.exec();
+
+ }
+
+ if (Act == singleAct || Act == singleAct2 || Act == MDIAct || Act == tabbedAct)
+ {
+ // Term Mode had changed
+
+ if (singleAct->isChecked())
+ {
+ newTermMode = Single;
+ newSingleMode = Mon + Term;
+ }
+ else if (singleAct2->isChecked())
+ {
+ newTermMode = Single;
+ newSingleMode = Term;
+ }
+ else if (MDIAct->isChecked())
+ newTermMode = MDI;
+ else if (tabbedAct->isChecked())
+ newTermMode = Tabbed;
+
+ if (newTermMode != TermMode || newSingleMode != singlemodeFormat)
+ {
+ QSettings settings(GetConfPath(), QSettings::IniFormat);
+ settings.setValue("TermMode", newTermMode);
+ settings.setValue("singlemodeFormat", newSingleMode);
+ QMessageBox msgBox;
+ msgBox.setText("Presentation Mode will change next time program is started.");
+ msgBox.exec();
+ }
+
+ return;
+ }
+
+
+ if (Act == MonTX)
+ ActiveSession->mtxparam = state;
+ else if (Act == MonSup)
+ ActiveSession->mcomparam = state;
+ else if (Act == MonUI)
+ ActiveSession->monUI = state;
+ else if (Act == MonNodes)
+ ActiveSession->MonitorNODES = state;
+ else if (Act == MonColour)
+ ActiveSession->MonitorColour = state;
+ else if (Act == actChatMode)
+ ChatMode = state;
+ else if (Act == actAutoTeletext)
+ AutoTeletext = state;
+ else if (Act == actBells)
+ Bells = state;
+ else if (Act == actStripLF)
+ StripLF = state;
+ else if (Act == actIntervalBeep)
+ AlertBeep = state;
+ else if (Act == actConnectBeep)
+ ConnectBeep = state;
+ else if (Act == actnoConv)
+ convUTF8 = -1;
+ else if (Act == actAuto)
+ convUTF8 = 0;
+ else if (Act == actCP1251)
+ convUTF8 = 1251;
+ else if (Act == actCP1252)
+ convUTF8 = 1252;
+ else if (Act == actCP437)
+ convUTF8 = 437;
+ else
+ {
+ // look for port entry
+ for (int i = 0; i < MAXPORTS + 1; i++)
+ {
+ if (Act == MonPort[i])
+ {
+ uint64_t mmask;
+
+ if (i == 0) // BBS Mon - use bit 63 (Port 64)
+ mmask = (uint64_t)1 << 63;
+ else
+ mmask = (uint64_t)1 << (i - 1);
+
+ if (state)
+ ActiveSession->portmask |= mmask;
+ else
+ ActiveSession->portmask &= ~mmask;
+ break;
+ }
+ }
+ }
+
+ // Get active Session
+/*
+
+ QMdiSubWindow *SW = mdiArea->activeSubWindow();
+
+ Ui_ListenSession * Sess;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+// for (Ui_ListenSession * Sess : _sessions)
+// {
+ if (Sess->sw == SW)
+ {
+ */
+
+ if (ActiveSession->clientSocket && ActiveSession->SessionType & Mon)
+ SendTraceOptions(ActiveSession);
+
+ return;
+}
+
+
+
+
+void QtTermTCP::LDisconnect(Ui_ListenSession * LUI)
+{
+ if (LUI->clientSocket)
+ LUI->clientSocket->disconnectFromHost();
+}
+
+extern QApplication * a;
+
+void QtTermTCP::LreturnPressed(Ui_ListenSession * Sess)
+{
+ QByteArray stringData = Sess->inputWindow->text().toUtf8();
+
+ // if multiline input (eg from copy/paste) replace LF with CR
+
+ char * ptr;
+ char * Msgptr;
+ char * Msg;
+
+ QScrollBar *scrollbar = Sess->termWindow->verticalScrollBar();
+ bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4));
+
+ if (scrollbarAtBottom)
+ Sess->termWindow->moveCursor(QTextCursor::End); // So we don't get blank lines
+
+ // Stack it
+
+ Sess->StackIndex = 0;
+
+ if (Sess->KbdStack[49])
+ free(Sess->KbdStack[49]);
+
+ for (int i = 48; i >= 0; i--)
+ {
+ Sess->KbdStack[i + 1] = Sess->KbdStack[i];
+ }
+
+ Sess->KbdStack[0] = qstrdup(stringData.data());
+
+ stringData.append('\n');
+
+ Msgptr = stringData.data();
+
+ if (Sess->TTActive) // Teletext uses 0x5F for #
+ while ((ptr = strchr(Msgptr, 0x23))) // Replace VT with LF
+ *ptr++ = 0x5f;
+
+
+ while ((ptr = strchr(Msgptr, 11))) // Replace VT with LF
+ *ptr++ = 10;
+
+ LastWrite = time(NULL); // Stop initial beep
+ Sess->SlowTimer = 0;
+
+ Sess->pageBuffer[0] = 0; // Reset Teletext mode screen buffer
+
+ if (Sess->KISSMode == 1)
+ {
+ // UI session. Send as UI Message
+
+ while ((ptr = strchr(Msgptr, '\n')))
+ {
+ *ptr++ = 0;
+
+ Msg = (char *)malloc(strlen(Msgptr) + 10);
+ strcpy(Msg, Msgptr);
+ strcat(Msg, "\r");
+
+ Send_UI(0, 0xF0, MYCALL, Sess->UIDEST, (unsigned char *)Msg, (int)strlen(Msg));
+
+ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg),
+ Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black
+
+ free(Msg);
+
+ Msgptr = ptr;
+ }
+ }
+ else if (Sess->KISSSession)
+ {
+ // Send to ax.25 code
+
+ while ((ptr = strchr(Msgptr, '\n')))
+ {
+ *ptr++ = 0;
+
+ Msg = (char *)malloc(strlen(Msgptr) + 10);
+ strcpy(Msg, Msgptr);
+ strcat(Msg, "\r");
+
+ SendtoAX25(Sess->KISSSession, (unsigned char *)Msg, (int)strlen(Msg));
+
+ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg),
+ Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black
+
+ free(Msg);
+
+ Msgptr = ptr;
+ }
+ }
+
+ else if (Sess->AGWSession)
+ {
+ // Terminal is in AGWPE mode - send as AGW frame
+
+ while ((ptr = strchr(Msgptr, '\n')))
+ {
+ *ptr++ = 0;
+
+ Msg = (char *)malloc(strlen(Msgptr) + 10);
+ strcpy(Msg, Msgptr);
+ strcat(Msg, "\r");
+
+ AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Msg, (int)strlen(Msg));
+
+ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg),
+ Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black
+
+// Sess->termWindow->insertPlainText(Msg);
+
+ free(Msg);
+
+ Msgptr = ptr;
+ }
+ }
+
+ else if (VARASock && VARASock->Sess == Sess)
+ {
+ while ((ptr = strchr(Msgptr, '\n')))
+ {
+ *ptr++ = 0;
+
+ Msg = (char *)malloc(strlen(Msgptr) + 10);
+ strcpy(Msg, Msgptr);
+ strcat(Msg, "\r");
+
+ VARADataSock->write(Msg);
+
+ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg),
+ Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black
+
+// Sess->termWindow->insertPlainText(Msg);
+
+ free(Msg);
+
+ Msgptr = ptr;
+ }
+ }
+
+ else if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState)
+ {
+ while ((ptr = strchr(Msgptr, '\n')))
+ {
+ *ptr++ = 0;
+
+ Msg = (char *)malloc(strlen(Msgptr) + 10);
+ strcpy(Msg, Msgptr);
+ strcat(Msg, "\r");
+
+ Sess->clientSocket->write(Msg);
+
+ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg),
+ Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black
+
+// Sess->termWindow->insertPlainText(Msg);
+
+ free(Msg);
+
+ Msgptr = ptr;
+ }
+ }
+ else
+ {
+ // Not Connected
+
+ if (Sess->SessionType != Listen)
+ {
+ if (Sess->CurrentHost < MAXHOSTS)
+ {
+ // Last connect was TCP
+
+ char Msg[] = "Connecting....\r";
+
+ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg),
+ Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red
+
+ delete(Sess->clientSocket);
+
+ Sess->clientSocket = new myTcpSocket();
+ Sess->clientSocket->Sess = Sess;
+
+ connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
+ connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
+
+ Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]);
+ }
+
+ else if (Sess->CurrentHost == 16) // AGW
+ {
+ // Invoke AGW connect dialog
+
+ AGWConnect dialog(0);
+ dialog.exec();
+
+ WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14);
+ return;
+ }
+
+ else if (Sess->CurrentHost == 17) // VARA
+ {
+ // Invoke VARA connect dialog
+
+ VARAConnect dialog(0);
+ dialog.exec();
+
+ WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14);
+ return;
+ }
+
+ else if (Sess->CurrentHost == 18) // KISS
+ {
+ // Do we send as UI or invoke kiss connect dialog ??
+
+ // Try Connect Dialog for now - may make a menu option
+
+ KISSConnect dialog(0);
+ dialog.exec();
+
+ WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14);
+ return;
+ }
+ }
+ else
+ {
+ char Msg[] = "Incoming Session - Can't Connect\r";
+
+ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg),
+ Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, 81); // Red
+
+ }
+ }
+
+ if (scrollbarAtBottom)
+ Sess->termWindow->moveCursor(QTextCursor::End);
+
+ Sess->inputWindow->setText("");
+ a->inputMethod()->hide();
+}
+
+
+void QtTermTCP::displayError(QAbstractSocket::SocketError socketError)
+{
+ myTcpSocket* sender = static_cast(QObject::sender());
+
+ switch (socketError)
+ {
+ case QAbstractSocket::RemoteHostClosedError:
+ break;
+
+ case QAbstractSocket::HostNotFoundError:
+ QMessageBox::information(this, tr("QtTermTCP"),
+ tr("The host was not found. Please check the "
+ "host name and portsettings->"));
+ break;
+
+ case QAbstractSocket::ConnectionRefusedError:
+ QMessageBox::information(this, tr("QtTermTCP"),
+ tr("The connection was refused by the peer."));
+ break;
+
+ default:
+ QMessageBox::information(this, tr("QtTermTCP"),
+ tr("The following error occurred: %1.")
+ .arg(sender->errorString()));
+ }
+
+ connectMenu->setEnabled(true);
+}
+
+void QtTermTCP::readyRead()
+{
+ int Read;
+ unsigned char Buffer[8192];
+ myTcpSocket* Socket = static_cast(QObject::sender());
+
+ Ui_ListenSession * Sess = (Ui_ListenSession *)Socket->Sess;
+
+ // read the data from the socket
+
+ Read = Socket->read((char *)Buffer, 2047);
+
+ while (Read > 0)
+ {
+ // if (InputMode == 'Y') // Yapp
+ // {
+ // QString myString = QString::fromUtf8((char*)Buffer, Read);
+ // QByteArray ptr = myString.toLocal8Bit();
+ // memcpy(Buffer, ptr.data(), ptr.length());
+ // Read = ptr.length();
+ // }
+
+
+ Buffer[Read] = 0;
+
+ ProcessReceivedData(Sess, Buffer, Read);
+
+ QString myString = QString::fromUtf8((char*)Buffer);
+ // qDebug() << myString;
+ Read = Socket->read((char *)Buffer, 2047);
+ }
+}
+
+extern "C" int SocketSend(Ui_ListenSession * Sess, char * Buffer, int len)
+{
+ myTcpSocket *Socket = Sess->clientSocket;
+
+ if (Socket && Socket->state() == QAbstractSocket::ConnectedState)
+ return Socket->write(Buffer, len);
+
+ return 0;
+}
+
+extern "C" int SocketFlush(Ui_ListenSession * Sess)
+{
+ if (Sess->AGWSession || Sess->KISSSession || (VARASock && VARASock->Sess == Sess))
+ return 0;
+
+ myTcpSocket* Socket = Sess->clientSocket;
+
+ if (Socket && Socket->state() == QAbstractSocket::ConnectedState)
+ return Socket->flush();
+
+ return 0;
+}
+
+extern "C" void mySleep(int ms)
+{
+ QThread::msleep(ms);
+}
+
+extern "C" void SetPortMonLine(int i, char * Text, int visible, int enabled)
+{
+ MonPort[i]->setText(Text);
+ MonPort[i]->setVisible(visible);
+ MonPort[i]->setChecked(enabled);
+}
+
+bool scrollbarAtBottom = 0;
+
+extern "C" void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int * OutputSaveLen, char * OutputSave, QColor Colour);
+
+extern "C" void WritetoOutputWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int len)
+{
+ WritetoOutputWindowEx(Sess, Buffer, len, Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, outputText);
+}
+
+
+extern "C" void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int * OutputSaveLen, char * OutputSave, QColor Colour)
+{
+ unsigned char Copy[8192];
+ unsigned char * ptr1, *ptr2;
+ unsigned char Line[8192];
+ unsigned char out[8192];
+ int outlen;
+
+ int num;
+
+ if (termWindow == NULL)
+ return;
+
+ time_t NOW = time(NULL);
+
+ // Beep if no output for a while
+
+ if (AlertInterval && (NOW - LastWrite) > AlertInterval)
+ {
+ if (AlertBeep)
+ myBeep(AlertBeep);
+ }
+
+ // if tabbed and not active tab set tab label red
+
+ if (TermMode == Tabbed)
+ {
+ if (Sess->monWindow != termWindow) // Not if Monitor
+ {
+ if (ActiveSession != Sess)
+ {
+ tabWidget->tabBar()->setTabTextColor(Sess->Tab, newTabText);
+ }
+ }
+ }
+
+ LastWrite = NOW;
+
+ // Mustn't mess with original buffer
+
+ memcpy(Copy, Buffer, len);
+
+ Copy[len] = 0;
+
+ ptr1 = Copy;
+
+ const QTextCursor old_cursor = termWindow->textCursor();
+ const int old_scrollbar_value = termWindow->verticalScrollBar()->value();
+ const bool is_scrolled_down = old_scrollbar_value == termWindow->verticalScrollBar()->maximum();
+
+ if (*OutputSaveLen)
+ {
+ // Have part line - append to it
+ memcpy(&OutputSave[*OutputSaveLen], Copy, len);
+ *OutputSaveLen += len;
+ ptr1 = (unsigned char *)OutputSave;
+ len = *OutputSaveLen;
+ *OutputSaveLen = 0;
+
+ // part line was written to screen so remove it
+
+// termWindow->setFocus();
+ termWindow->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
+ termWindow->moveCursor(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor);
+ termWindow->moveCursor(QTextCursor::End, QTextCursor::KeepAnchor);
+ termWindow->textCursor().removeSelectedText();
+ // termWindow->textCursor().deletePreviousChar();
+ }
+
+ // Move the cursor to the end of the document.
+
+ termWindow->moveCursor(QTextCursor::End);
+
+ // Insert the text at the position of the cursor (which is the end of the document).
+
+lineloop:
+
+ if (len <= 0)
+ {
+ if (old_cursor.hasSelection() || !is_scrolled_down)
+ {
+ // The user has selected text or scrolled away from the bottom: maintain position.
+ termWindow->setTextCursor(old_cursor);
+ termWindow->verticalScrollBar()->setValue(old_scrollbar_value);
+ }
+ else
+ {
+ // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom.
+ termWindow->moveCursor(QTextCursor::End);
+ termWindow->verticalScrollBar()->setValue(termWindow->verticalScrollBar()->maximum());
+ }
+
+ return;
+ }
+
+
+ // copy text to control a line at a time
+
+ ptr2 = (unsigned char *)memchr(ptr1, 13, len);
+
+ if (ptr2 == 0) // No CR
+ {
+ if (len > 8000)
+ len = 8000; // Should never get lines this long
+
+ memmove(OutputSave, ptr1, len);
+ *OutputSaveLen = len;
+
+ // Write part line to screen
+
+ memcpy(Line, ptr1, len);
+ Line[len] = 0;
+
+ // I don't think I need to worry if UTF8 as will be rewritten when rest arrives
+
+ if (Line[0] == 0x1b) // Colour Escape
+ {
+ if (Sess->MonitorColour)
+ termWindow->setTextColor(Colours[Line[1] - 10]);
+
+ termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2]));
+ }
+ else
+ {
+ termWindow->setTextColor(Colour);
+ termWindow->textCursor().insertText(QString::fromUtf8((char*)Line));
+ }
+
+ // *OutputSaveLen = 0; // Test if we need to delete part line
+
+ // if (scrollbarAtBottom)
+ // termWindow->moveCursor(QTextCursor::End);
+
+ if (old_cursor.hasSelection() || !is_scrolled_down)
+ {
+ // The user has selected text or scrolled away from the bottom: maintain position.
+ termWindow->setTextCursor(old_cursor);
+ termWindow->verticalScrollBar()->setValue(old_scrollbar_value);
+ }
+ else
+ {
+ // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom.
+ termWindow->moveCursor(QTextCursor::End);
+ termWindow->verticalScrollBar()->setValue(termWindow->verticalScrollBar()->maximum());
+ }
+ return;
+ }
+
+ *(ptr2++) = 0;
+
+ if (Bells)
+ {
+ char * ptr;
+
+ do {
+ ptr = (char *)memchr(ptr1, 7, len);
+
+ if (ptr)
+ {
+ *(ptr) = 32;
+ myBeep(Bells);
+ }
+ } while (ptr);
+ }
+
+ num = ptr2 - ptr1 - 1;
+
+ // if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1);
+
+ memcpy(Line, ptr1, num);
+ Line[num++] = 13;
+ Line[num] = 0;
+
+ if (Line[0] == 0x1b) // Colour Escape
+ {
+ if (Sess->MonitorColour)
+ termWindow->setTextColor(Colours[Line[1] - 10]);
+
+ outlen = checkUTF8(&Line[2], num - 2, out);
+ out[outlen] = 0;
+ termWindow->textCursor().insertText(QString::fromUtf8((char*)out));
+ // termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2]));
+ }
+ else
+ {
+ termWindow->setTextColor(Colour);
+
+ outlen = checkUTF8(Line, num, out);
+ out[outlen] = 0;
+ termWindow->textCursor().insertText(QString::fromUtf8((char*)out));
+ // termWindow->textCursor().insertText(QString::fromUtf8((char*)Line));
+ }
+
+ len -= (ptr2 - ptr1);
+
+ ptr1 = ptr2;
+
+ if ((len > 0) && StripLF)
+ {
+ if (*ptr1 == 0x0a) // Line Feed
+ {
+ ptr1++;
+ len--;
+ }
+ }
+
+
+
+ goto lineloop;
+
+}
+
+extern "C" void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Msg, int len)
+{
+ char * ptr1 = (char *)Msg, *ptr2;
+ char Line[512];
+ int num;
+
+ // QScrollBar *scrollbar = Sess->monWindow->verticalScrollBar();
+ // bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4));
+
+ if (Sess->monWindow == nullptr)
+ return;
+
+ Sess->monWindow->setStyleSheet(monStyleSheet);
+
+ const QTextCursor old_cursor = Sess->monWindow->textCursor();
+ const int old_scrollbar_value = Sess->monWindow->verticalScrollBar()->value();
+ const bool is_scrolled_down = old_scrollbar_value == Sess->monWindow->verticalScrollBar()->maximum();
+
+ // Move the cursor to the end of the document.
+ Sess->monWindow->moveCursor(QTextCursor::End);
+
+ // Insert the text at the position of the cursor (which is the end of the document).
+
+
+ // Write a line at a time so we can action colour chars
+
+// Buffer[Len] = 0;
+
+// if (scrollbarAtBottom)
+// Sess->monWindow->moveCursor(QTextCursor::End);
+
+ if (Sess->MonSaveLen)
+ {
+ // Have part line - append to it
+ memcpy(&Sess->MonSave[Sess->MonSaveLen], Msg, len);
+ Sess->MonSaveLen += len;
+ ptr1 = Sess->MonSave;
+ len = Sess->MonSaveLen;
+ Sess->MonSaveLen = 0;
+ }
+
+lineloop:
+
+ if (len <= 0)
+ {
+ // if (scrollbarAtBottom)
+ // Sess->monWindow->moveCursor(QTextCursor::End);
+
+
+ if (old_cursor.hasSelection() || !is_scrolled_down)
+ {
+ // The user has selected text or scrolled away from the bottom: maintain position.
+ Sess->monWindow->setTextCursor(old_cursor);
+ Sess->monWindow->verticalScrollBar()->setValue(old_scrollbar_value);
+ }
+ else
+ {
+ // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom.
+ Sess->monWindow->moveCursor(QTextCursor::End);
+ Sess->monWindow->verticalScrollBar()->setValue(Sess->monWindow->verticalScrollBar()->maximum());
+ }
+
+ return;
+ }
+
+ // copy text to control a line at a time
+
+ ptr2 = (char *)memchr(ptr1, 13, len);
+
+ if (ptr2 == 0) // No CR
+ {
+ memmove(Sess->MonSave, ptr1, len);
+ Sess->MonSaveLen = len;
+ return;
+ }
+
+ *(ptr2++) = 0;
+
+ // if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1);
+
+ num = ptr2 - ptr1 - 1;
+
+ memcpy(Line, ptr1, num);
+ Line[num++] = 13;
+ Line[num] = 0;
+
+ if (Line[0] == 0x1b) // Colour Escape
+ {
+ if (Sess->MonitorColour)
+ {
+ if (Line[1] == 17)
+ Sess->monWindow->setTextColor(monRxText);
+ else
+ Sess->monWindow->setTextColor(monTxText);
+ }
+ else
+ Sess->monWindow->setTextColor(monOtherText);
+
+ Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2]));
+ }
+ else
+ {
+ Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)Line));
+ }
+ len -= (ptr2 - ptr1);
+
+ ptr1 = ptr2;
+
+ goto lineloop;
+
+}
+
+int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len);
+void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len);
+
+// 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
+
+extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len)
+{
+ if (Sess == 0)
+ return;
+
+ Sess->SlowTimer = 0;
+ Msg[Len] = 0;
+
+ if (Sess->InputMode == 'Y') // Yapp
+ {
+ ProcessYAPPMessage(Sess, (unsigned char *)Msg, Len);
+ return;
+ }
+
+ // Could be a YAPP Header
+
+ if (Len == 2 && Msg[0] == ENQ && Msg[1] == 1) // YAPP Send_Init
+ {
+ char YAPPRR[2];
+
+ // Turn off monitoring
+
+ Sess->InputMode = 'Y';
+
+ YAPPRR[0] = ACK;
+ YAPPRR[1] = 1;
+ QueueMsg(Sess, YAPPRR, 2);
+
+ return;
+ }
+
+ if (AutoTeletext && (Msg[0] == 0x1e || Msg[0] == 0x0c))
+ {
+ if (Sess->TTActive == 0)
+ {
+ Sess->TTActive = 1;
+ DoTermResize(Sess);
+ }
+ }
+
+ if (Sess->TTActive)
+ {
+ // Feed to Teletext code
+
+ // We need to decode a whole page. There is no obvious delimiter so process till data stops.
+ // Buffer is cleared when next input is sent
+
+ if (strlen(&Sess->pageBuffer[0] + Len) > 4090)
+ Sess->pageBuffer[0] = 0; // Protect buffer
+
+ strcat(Sess->pageBuffer, (char *)Msg);
+
+ DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end
+ return;
+ }
+
+ WritetoOutputWindow(Sess, (unsigned char *)Msg, Len);
+
+}
+
+QSettings* settings;
+
+// This makes geting settings for more channels easier
+
+char Prefix[16] = "AX25_A";
+
+void GetPortSettings(int Chan);
+
+QVariant getAX25Param(const char * key, QVariant Default)
+{
+ char fullKey[64];
+
+ sprintf(fullKey, "%s/%s", Prefix, key);
+ return settings->value(fullKey, Default);
+}
+
+void getAX25Params(int chan)
+{
+ Prefix[5] = chan + 'A';
+ GetPortSettings(chan);
+}
+
+
+void GetPortSettings(int Chan)
+{
+ maxframe[Chan] = getAX25Param("Maxframe", 4).toInt();
+ fracks[Chan] = getAX25Param("Retries", 10).toInt();
+ frack_time[Chan] = getAX25Param("FrackTime", 8).toInt();
+ persist[Chan] = getAX25Param("Persist", 128).toInt();
+ kisspaclen[Chan] = getAX25Param("Paclen", 128).toInt();
+ idletime[Chan] = getAX25Param("IdleTime", 180).toInt();
+ slottime[Chan] = getAX25Param("SlotTime", 100).toInt();
+ resptime[Chan] = getAX25Param("RespTime", 1500).toInt();
+ TXFrmMode[Chan] = getAX25Param("TXFrmMode", 1).toInt();
+ max_frame_collector[Chan] = getAX25Param("FrameCollector", 6).toInt();
+ //exclude_callsigns[Chan]= getAX25Param("ExcludeCallsigns/");
+ //exclude_APRS_frm[Chan]= getAX25Param("ExcludeAPRSFrmType/");
+ KISS_opt[Chan] = getAX25Param("KISSOptimization", false).toInt();;
+ dyn_frack[Chan] = getAX25Param("DynamicFrack", false).toInt();;
+ IPOLL[Chan] = getAX25Param("IPOLL", 80).toInt();
+
+}
+
+
+void GetSettings()
+{
+ QByteArray qb;
+ int i;
+ char Key[16];
+ char Param[256];
+
+ settings = new QSettings(GetConfPath(), QSettings::IniFormat);
+
+ // Get saved session definitions
+
+ sessionList = strdup(settings->value("Sessions", "1|3, 0, 5, 5, 600, 800|").toString().toUtf8());
+
+ for (i = 0; i < MAXHOSTS; i++)
+ {
+ sprintf(Key, "HostParams%d", i);
+
+ qb = settings->value(Key).toByteArray();
+
+ DecodeSettingsLine(i, qb.data());
+ }
+
+ Split = settings->value("Split", 50).toInt();
+ ChatMode = settings->value("ChatMode", 1).toInt();
+ AutoTeletext = settings->value("AutoTeletext", 0).toInt();
+ Bells = settings->value("Bells", 1).toInt();
+ StripLF = settings->value("StripLF", 1).toInt();
+ useBeep = settings->value("useBeep", true).toBool();
+ AlertBeep = settings->value("AlertBeep", 1).toInt();
+ AlertInterval = settings->value("AlertInterval", 300).toInt();
+ ConnectBeep = settings->value("ConnectBeep", 1).toInt();
+ ConnectWAV = settings->value("ConnectWAV", "").toString().toUtf8();
+
+ SavedHost = settings->value("CurrentHost", 0).toInt();
+ strcpy(YAPPPath, settings->value("YAPPPath", "").toString().toUtf8());
+ MaxRXSize = settings->value("MaxRXSize", 100000).toInt();
+
+ listenPort = settings->value("listenPort", 8015).toInt();
+ listenEnable = settings->value("listenEnable", false).toBool();
+ strcpy(listenCText, settings->value("listenCText", "").toString().toUtf8());
+
+ TermMode = settings->value("TermMode", 0).toInt();
+ singlemodeFormat = settings->value("singlemodeFormat", Term + Mon).toInt();
+
+ AGWEnable = settings->value("AGWEnable", 0).toInt();
+ AGWMonEnable = settings->value("AGWMonEnable", 0).toInt();
+ strcpy(AGWTermCall, settings->value("AGWTermCall", "").toString().toUtf8());
+ strcpy(AGWBeaconDest, settings->value("AGWBeaconDest", "").toString().toUtf8());
+ strcpy(AGWBeaconPath, settings->value("AGWBeaconPath", "").toString().toUtf8());
+ AGWBeaconInterval = settings->value("AGWBeaconInterval", 0).toInt();
+ strcpy(AGWBeaconPorts, settings->value("AGWBeaconPorts", "").toString().toUtf8());
+ strcpy(AGWBeaconMsg, settings->value("AGWBeaconText", "").toString().toUtf8());
+ strcpy(AGWHost, settings->value("AGWHost", "127.0.0.1").toString().toUtf8());
+ AGWPortNum = settings->value("AGWPort", 8000).toInt();
+ AGWPaclen = settings->value("AGWPaclen", 80).toInt();
+ AGWToCalls = settings->value("AGWToCalls", "").toStringList();
+ convUTF8 = settings->value("convUTF8", 0).toInt();
+
+ KISSEnable = settings->value("KISSEnable", 0).toInt();
+ strcpy(MYCALL, settings->value("MYCALL", "").toString().toUtf8());
+ strcpy(KISSHost, settings->value("KISSHost", "127.0.0.1").toString().toUtf8());
+ KISSPortNum = settings->value("KISSPort", 8100).toInt();
+ KISSMode = settings->value("KISSMode", 0).toInt();
+
+ strcpy(SerialPort, settings->value("KISSSerialPort", "None").toString().toUtf8());
+ KISSBAUD = settings->value("KISSBAUD", 19200).toInt();
+ getAX25Params(0);
+
+ VARAEnable = settings->value("VARAEnable", 0).toInt();
+ strcpy(VARAHost, settings->value("VARAHost", "127.0.0.1").toString().toUtf8());
+ strcpy(VARAHostFM, settings->value("VARAHostFM", "127.0.0.1").toString().toUtf8());
+ strcpy(VARAHostHF, settings->value("VARAHostHF", "127.0.0.1").toString().toUtf8());
+ strcpy(VARAHostSAT, settings->value("VARAHostSAT", "127.0.0.1").toString().toUtf8());
+ VARAPortNum = settings->value("VARAPort", 8300).toInt();
+ VARAPortHF = settings->value("VARAPortHF", 8300).toInt();
+ VARAPortFM = settings->value("VARAPortFM", 8300).toInt();
+ VARAPortSAT = settings->value("VARAPortSAT", 8300).toInt();
+ strcpy(VARAPath, settings->value("VARAPath", "C:\\VARA\\VARA.exe").toString().toUtf8());
+ strcpy(VARAPathHF, settings->value("VARAPathHF", "C:\\VARA\\VARA.exe").toString().toUtf8());
+ strcpy(VARAPathFM, settings->value("VARAPathFM", "C:\\VARA\\VARAFM.exe").toString().toUtf8());
+ strcpy(VARAPathSAT, settings->value("VARAPathSAT", "C:\\VARA\\VARASAT.exe").toString().toUtf8());
+ strcpy(VARATermCall, settings->value("VARATermCall", "").toString().toUtf8());
+ VARA500 = settings->value("VARA500", 0).toInt();
+ VARA2300 = settings->value("VARA2300", 1).toInt();
+ VARA2750 = settings->value("VARA2750", 0).toInt();
+ VARAHF = settings->value("VARAHF", 1).toInt();
+ VARAFM = settings->value("VARAFM", 0).toInt();
+ VARASAT = settings->value("VARASAT", 0).toInt();
+ strcpy(VARAInit, settings->value("VARAInit", "").toString().toUtf8());
+
+ strcpy(PTTPort, settings->value("PTT", "None").toString().toUtf8());
+ PTTMode = settings->value("PTTMode", 19200).toInt();
+ PTTBAUD = settings->value("PTTBAUD", 19200).toInt();
+ CATHex = settings->value("CATHex", 1).toInt();
+
+ strcpy(PTTOnString, settings->value("PTTOnString", "").toString().toUtf8());
+ strcpy(PTTOffString, settings->value("PTTOffString", "").toString().toUtf8());
+
+ pttGPIOPin = settings->value("pttGPIOPin", 17).toInt();
+ pttGPIOPinR = settings->value("pttGPIOPinR", 17).toInt();
+
+#ifdef WIN32
+ strcpy(CM108Addr, settings->value("CM108Addr", "0xD8C:0x08").toString().toUtf8());
+#else
+ strcpy(CM108Addr, settings->value("CM108Addr", "/dev/hidraw0").toString().toUtf8());
+#endif
+
+ HamLibPort = settings->value("HamLibPort", 4532).toInt();
+ strcpy(HamLibHost, settings->value("HamLibHost", "127.0.0.1").toString().toUtf8());
+
+ FLRigPort = settings->value("FLRigPort", 12345).toInt();
+ strcpy(FLRigHost, settings->value("FLRigHost", "127.0.0.1").toString().toUtf8());
+
+
+ strcpy(Param, settings->value("TabType", "1 1 1 1 1 1 1 2 2").toString().toUtf8());
+ sscanf(Param, "%d %d %d %d %d %d %d %d %d %d",
+ &TabType[0], &TabType[1], &TabType[2], &TabType[3], &TabType[4],
+ &TabType[5], &TabType[6], &TabType[7], &TabType[8], &TabType[9]);
+
+ strcpy(Param, settings->value("AutoConnect", "0, 0 ,0, 0, 0, 0, 0, 0, 0, 0").toString().toUtf8());
+ sscanf(Param, "%d %d %d %d %d %d %d %d %d %d",
+ &AutoConnect[0], &AutoConnect[1], &AutoConnect[2], &AutoConnect[3], &AutoConnect[4],
+ &AutoConnect[5], &AutoConnect[6], &AutoConnect[7], &AutoConnect[8], &AutoConnect[9]);
+
+ strcpy(Param, settings->value("currentHost", "0, 0 ,0, 0, 0, 0, 0, 0, 0, 0").toString().toUtf8());
+ sscanf(Param, "%d %d %d %d %d %d %d %d %d %d",
+ ¤tHost[0], ¤tHost[1], ¤tHost[2], ¤tHost[3], ¤tHost[4],
+ ¤tHost[5], ¤tHost[6], ¤tHost[7], ¤tHost[8], ¤tHost[9]);
+
+
+ monBackground = settings->value("monBackground", QColor(255, 255, 255)).value();
+ monRxText = settings->value("monRxText", QColor(0, 0, 255)).value();
+ monTxText = settings->value("monTxText", QColor(255, 0, 0)).value();
+ monOtherText = settings->value("monOtherText", QColor(0, 0, 0)).value();
+
+ termBackground = settings->value("termBackground", QColor(255, 255, 255)).value();
+ outputText = settings->value("outputText", QColor(0, 0, 255)).value();
+ EchoText = settings->value("EchoText", QColor(0, 0, 0)).value();
+ WarningText = settings->value("WarningText", QColor(255, 0, 0)).value();
+
+ inputBackground = settings->value("inputBackground", QColor(255, 255, 255)).value();
+ inputText = settings->value("inputText", QColor(0, 0, 0)).value();
+
+ delete(settings);
+}
+
+void SavePortSettings(int Chan);
+
+void saveAX25Param(const char * key, QVariant Value)
+{
+ char fullKey[64];
+
+ sprintf(fullKey, "%s/%s", Prefix, key);
+
+ settings->setValue(fullKey, Value);
+}
+
+void saveAX25Params(int chan)
+{
+ Prefix[5] = chan + 'A';
+ SavePortSettings(chan);
+}
+
+void SavePortSettings(int Chan)
+{
+ saveAX25Param("Retries", fracks[Chan]);
+ saveAX25Param("Maxframe", maxframe[Chan]);
+ saveAX25Param("Paclen", kisspaclen[Chan]);
+ saveAX25Param("FrackTime", frack_time[Chan]);
+ saveAX25Param("IdleTime", idletime[Chan]);
+ saveAX25Param("SlotTime", slottime[Chan]);
+ saveAX25Param("Persist", persist[Chan]);
+ saveAX25Param("RespTime", resptime[Chan]);
+ saveAX25Param("TXFrmMode", TXFrmMode[Chan]);
+ saveAX25Param("FrameCollector", max_frame_collector[Chan]);
+ saveAX25Param("ExcludeCallsigns", exclude_callsigns[Chan]);
+ saveAX25Param("ExcludeAPRSFrmType", exclude_APRS_frm[Chan]);
+ saveAX25Param("KISSOptimization", KISS_opt[Chan]);
+ saveAX25Param("DynamicFrack", dyn_frack[Chan]);
+ saveAX25Param("BitRecovery", recovery[Chan]);
+ saveAX25Param("IPOLL", IPOLL[Chan]);
+ saveAX25Param("MyDigiCall", MyDigiCall[Chan]);
+}
+
+extern "C" void SaveSettings()
+{
+ int i;
+ char Param[512];
+ char Key[16];
+
+ settings = new QSettings(GetConfPath(), QSettings::IniFormat);
+
+ for (i = 0; i < MAXHOSTS; i++)
+ {
+ sprintf(Key, "HostParams%d", i);
+ EncodeSettingsLine(i, Param);
+ settings->setValue(Key, Param);
+ }
+
+ settings->setValue("Split", Split);
+ settings->setValue("ChatMode", ChatMode);
+ settings->setValue("AutoTeletext", AutoTeletext);
+ settings->setValue("Bells", Bells);
+ settings->setValue("StripLF", StripLF);
+ settings->setValue("AlertBeep", AlertBeep);
+ settings->setValue("useBeep", useBeep);
+ settings->setValue("ConnectBeep", ConnectBeep);
+ settings->setValue("ConnectWAV", ConnectWAV);
+ settings->setValue("AlertInterval", AlertInterval);
+ settings->setValue("CurrentHost", SavedHost);
+
+ settings->setValue("YAPPPath", YAPPPath);
+ settings->setValue("MaxRXSize", MaxRXSize);
+
+ settings->setValue("listenPort", listenPort);
+ settings->setValue("listenEnable", listenEnable);
+ settings->setValue("listenCText", listenCText);
+ settings->setValue("convUTF8", convUTF8);
+
+ settings->setValue("PTT", PTTPort);
+ settings->setValue("PTTBAUD", PTTBAUD);
+ settings->setValue("PTTMode", PTTMode);
+
+ settings->setValue("CATHex", CATHex);
+
+ settings->setValue("PTTOffString", PTTOffString);
+ settings->setValue("PTTOnString", PTTOnString);
+
+ settings->setValue("pttGPIOPin", pttGPIOPin);
+ settings->setValue("pttGPIOPinR", pttGPIOPinR);
+
+ settings->setValue("CM108Addr", CM108Addr);
+ settings->setValue("HamLibPort", HamLibPort);
+ settings->setValue("HamLibHost", HamLibHost);
+ settings->setValue("FLRigPort", FLRigPort);
+ settings->setValue("FLRigHost", FLRigHost);
+
+
+ // Save Sessions
+
+ char SessionString[1024];
+ int SessStringLen;
+
+ SessStringLen = sprintf(SessionString, "%d|", _sessions.size());
+
+ if (TermMode == MDI)
+ {
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Ui_ListenSession * Sess = _sessions.at(i);
+
+ QRect r = Sess->sw->geometry();
+
+ SessStringLen += sprintf(&SessionString[SessStringLen],
+ "%d, %d, %d, %d, %d, %d|", Sess->SessionType, Sess->CurrentHost, r.top(), r.left(), r.bottom(), r.right());
+ }
+
+ settings->setValue("Sessions", SessionString);
+ }
+
+ settings->setValue("AGWEnable", AGWEnable);
+ settings->setValue("AGWMonEnable", AGWMonEnable);
+ settings->setValue("AGWTermCall", AGWTermCall);
+ settings->setValue("AGWBeaconDest", AGWBeaconDest);
+ settings->setValue("AGWBeaconPath", AGWBeaconPath);
+ settings->setValue("AGWBeaconInterval", AGWBeaconInterval);
+ settings->setValue("AGWBeaconPorts", AGWBeaconPorts);
+ settings->setValue("AGWBeaconText", AGWBeaconMsg);
+ settings->setValue("AGWHost", AGWHost);
+ settings->setValue("AGWPort", AGWPortNum);
+ settings->setValue("AGWPaclen", AGWPaclen);
+ settings->setValue("AGWToCalls", AGWToCalls);
+
+
+ settings->setValue("KISSEnable", KISSEnable);
+ settings->setValue("MYCALL", MYCALL);
+ settings->setValue("KISSHost", KISSHost);
+ settings->setValue("KISSMode", KISSMode);
+ settings->setValue("KISSPort", KISSPortNum);
+ settings->setValue("KISSSerialPort", SerialPort);
+ settings->setValue("KISSBAUD", KISSBAUD);
+ saveAX25Params(0);
+
+ settings->setValue("VARAEnable", VARAEnable);
+ settings->setValue("VARATermCall", VARATermCall);
+ settings->setValue("VARAHost", VARAHost);
+ settings->setValue("VARAPort", VARAPortNum);
+ settings->setValue("VARAInit", VARAInit);
+ settings->setValue("VARAPath", VARAPath);
+ settings->setValue("VARAHostHF", VARAHostHF);
+ settings->setValue("VARAPortHF", VARAPortHF);
+ settings->setValue("VARAPathHF", VARAPathHF);
+ settings->setValue("VARAHostFM", VARAHostFM);
+ settings->setValue("VARAPortFM", VARAPortFM);
+ settings->setValue("VARAPathFM", VARAPathFM);
+ settings->setValue("VARAHostSAT", VARAHostSAT);
+ settings->setValue("VARAPortSAT", VARAPortSAT);
+ settings->setValue("VARAPathSAT", VARAPathSAT);
+ settings->setValue("VARA500", VARA500);
+ settings->setValue("VARA2300", VARA2300);
+ settings->setValue("VARA2750", VARA2750);
+ settings->setValue("VARAHF", VARAHF);
+ settings->setValue("VARAFM", VARAFM);
+ settings->setValue("VARASAT", VARASAT);
+
+ sprintf(Param, "%d %d %d %d %d %d %d %d %d %d",
+ TabType[0], TabType[1], TabType[2], TabType[3], TabType[4], TabType[5], TabType[6], TabType[7], TabType[8], TabType[9]);
+
+ settings->setValue("TabType", Param);
+
+ sprintf(Param, "%d %d %d %d %d %d %d %d %d %d",
+ AutoConnect[0], AutoConnect[1], AutoConnect[2], AutoConnect[3], AutoConnect[4], AutoConnect[5], AutoConnect[6], AutoConnect[7], AutoConnect[8], AutoConnect[9]);
+
+ settings->setValue("AutoConnect", Param);
+
+ sprintf(Param, "%d %d %d %d %d %d %d %d %d %d",
+ currentHost[0], currentHost[1], currentHost[2], currentHost[3], currentHost[4], currentHost[5], currentHost[6], currentHost[7], currentHost[8], currentHost[9]);
+
+ settings->setValue("currentHost", Param);
+
+ settings->setValue("monBackground", monBackground);
+ settings->setValue("monRxText", monRxText);
+ settings->setValue("monTxText", monTxText);
+ settings->setValue("monOtherText", monOtherText);
+
+ settings->setValue("termBackground", termBackground);
+ settings->setValue("outputText", outputText);
+ settings->setValue("EchoText", EchoText);
+ settings->setValue("WarningText", WarningText);
+
+ settings->setValue("inputBackground", inputBackground);
+ settings->setValue("inputText", inputText);
+
+ settings->sync();
+ delete(settings);
+}
+
+#include
+
+void QtTermTCP::closeEvent(QCloseEvent *event)
+{
+ QMessageBox::StandardButton resBtn = QMessageBox::question(this, "QtTermTCP",
+ tr("Are you sure?\n"),
+ QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes,
+ QMessageBox::Yes);
+ if (resBtn != QMessageBox::Yes) {
+ event->ignore();
+ }
+ else
+ {
+ event->accept();
+#ifdef USESERIAL
+ if (hPTTDevice)
+ hPTTDevice->close();
+#endif
+ if (process)
+ process->close();
+ }
+}
+
+QtTermTCP::~QtTermTCP()
+{
+ Ui_ListenSession * Sess;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ if (Sess->clientSocket)
+ {
+ int loops = 100;
+ Sess->clientSocket->disconnectFromHost();
+ while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState)
+ QThread::msleep(10);
+ }
+
+ }
+
+ if (AGWSock && AGWSock->ConnectedState == QAbstractSocket::ConnectedState)
+ {
+ int loops = 100;
+ AGWSock->disconnectFromHost();
+ QThread::msleep(10);
+ while (AGWSock && loops-- && AGWSock->state() != QAbstractSocket::UnconnectedState)
+ QThread::msleep(10);
+ }
+
+ if (_server->isListening())
+ _server->close();
+
+ delete(_server);
+
+ QSettings mysettings(GetConfPath(), QSettings::IniFormat);
+ mysettings.setValue("geometry", saveGeometry());
+ mysettings.setValue("windowState", saveState());
+
+ SaveSettings();
+}
+
+extern "C" void timer_event();
+
+void QtTermTCP::KISSTimerSlot()
+{
+ // Runs every 100 mS
+
+ timer_event();
+}
+
+void QtTermTCP::MyTimerSlot()
+{
+ // Runs every 10 seconds
+
+ Ui_ListenSession * Sess;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ // for (Ui_ListenSession * Sess : _sessions)
+ // {
+ if (Sess == NULL)
+ continue;
+
+ if (!ChatMode)
+ continue;
+
+ if (Sess->KISSSession ||
+ (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState))
+ {
+ Sess->SlowTimer++;
+
+ if (Sess->SlowTimer > 54) // About 9 mins
+ {
+ unsigned char Msg[2] = "";
+
+ Sess->SlowTimer = 0;
+
+ if (Sess->KISSSession)
+ {
+ TAX25Port * ax25 = (TAX25Port *)Sess->KISSSession;
+
+ if (ax25->status == STAT_LINK)
+ SendtoAX25(Sess->KISSSession, Msg, 1);
+ }
+ else
+ Sess->clientSocket->write("\0", 1);
+ }
+ }
+ }
+
+ if (AGWEnable)
+ AGWTimer();
+
+ if (VARAEnable)
+ VARATimer();
+
+ if (KISSEnable)
+ KISSTimer();
+
+}
+
+extern "C" void myBeep(int Type)
+{
+ if (useBeep)
+ {
+ QApplication::beep();
+ return;
+ }
+}
+
+void QtTermTCP::ListenSlot()
+{
+ // This runs the Listen Configuration dialog
+
+ ListenDialog * xx = new ListenDialog();
+ xx->exec();
+}
+
+void QtTermTCP::AGWSlot()
+{
+ // This runs the AGW Configuration dialog
+
+ AGWDialog dialog(0);
+ dialog.exec();
+}
+
+Ui_Dialog * Dev;
+Ui_AlertDialog * Alert;
+
+static Ui_KISSDialog * KISS;
+static Ui_ColourDialog * COLOURS;
+
+
+char NewPTTPort[80];
+
+int newSoundMode = 0;
+int oldSoundMode = 0;
+
+#ifdef USESERIAL
+QList Ports = QSerialPortInfo::availablePorts();
+#endif
+
+
+void QtTermTCP::KISSSlot()
+{
+ // This runs the KISS Configuration dialog
+
+ KISS = new(Ui_KISSDialog);
+
+ QDialog UI;
+
+ KISS->setupUi(&UI);
+
+ UI.setFont(*menufont);
+
+ deviceUI = &UI;
+ KISS->KISSEnable->setChecked(KISSEnable);
+ KISS->MYCALL->setText(MYCALL);
+
+ // connect(KISS->SerialPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int)));
+
+ QStringList items;
+
+#ifdef USESERIAL
+
+ for (const QSerialPortInfo &info : Ports)
+ {
+ items.append(info.portName());
+ }
+
+ items.sort();
+ items.insert(0, "TCP");
+
+#endif
+
+ for (const QString &info : items)
+ {
+ KISS->SerialPort->addItem(info);
+ }
+
+ KISS->SerialPort->setCurrentIndex(KISS->SerialPort->findText(SerialPort, Qt::MatchFixedString));
+ KISS->Speed->setText(QString::number(KISSBAUD));
+ KISS->Host->setText(KISSHost);
+ KISS->Port->setText(QString::number(KISSPortNum));
+
+ KISS->Paclen->setText(QString::number(kisspaclen[0]));
+ KISS->Maxframe->setText(QString::number(maxframe[0]));
+ KISS->Frack->setText(QString::number(frack_time[0]));
+ KISS->Retries->setText(QString::number(fracks[0]));
+
+ QObject::connect(KISS->okButton, SIGNAL(clicked()), this, SLOT(KISSaccept()));
+ QObject::connect(KISS->cancelButton, SIGNAL(clicked()), this, SLOT(KISSreject()));
+
+ UI.exec();
+
+}
+
+
+void QtTermTCP::KISSaccept()
+{
+ QVariant Q;
+ int OldEnable = KISSEnable;
+ char oldSerialPort[64];
+ int OldPort = KISSPortNum;
+ char oldHost[128];
+
+ strcpy(oldSerialPort, SerialPort);
+ strcpy(oldHost, KISSHost);
+
+ KISSEnable = KISS->KISSEnable->isChecked();
+ actHost[18]->setVisible(KISSEnable); // Show KISS Connect Line
+
+ strcpy(MYCALL, KISS->MYCALL->text().toUtf8().toUpper());
+
+ memset(axMYCALL, 0, 7);
+ ConvToAX25(MYCALL, axMYCALL);
+
+ Q = KISS->Port->text();
+ KISSPortNum = Q.toInt();
+
+ Q = KISS->Speed->text();
+ KISSBAUD = Q.toInt();
+
+ strcpy(KISSHost, KISS->Host->text().toUtf8().toUpper());
+
+ Q = KISS->SerialPort->currentText();
+ strcpy(SerialPort, Q.toString().toUtf8());
+
+ Q = KISS->Paclen->text();
+ kisspaclen[0] = Q.toInt();
+ Q = KISS->Maxframe->text();
+ maxframe[0] = Q.toInt();
+ Q = KISS->Frack->text();
+ frack_time[0] = Q.toInt();
+ Q = KISS->Retries->text();
+ fracks[0] = Q.toInt();
+
+ myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable);
+
+
+ if (KISSEnable != OldEnable || KISSPortNum != OldPort ||
+ strcmp(oldHost, KISSHost) != 0 ||
+ strcmp(oldSerialPort, SerialPort) != 0)
+ {
+ // (re)start connection
+
+ if (OldEnable)
+ {
+ if (KISSEnable)
+ Status3->setText("KISS Closed");
+ else
+ Status3->setText("KISS Disabled");
+
+ KISSConnected = 0;
+
+ if (KISSSock && KISSSock->ConnectedState == QAbstractSocket::ConnectedState)
+ KISSSock->disconnectFromHost();
+ else if (m_serial)
+ closeSerialPort();
+ }
+ }
+
+ delete(KISS);
+ SaveSettings();
+ deviceUI->accept();
+
+ // QSize newSize(this->size());
+ // QSize oldSize(this->size());
+
+ // QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize);
+
+ // QCoreApplication::postEvent(this, myResizeEvent);
+}
+
+void QtTermTCP::KISSreject()
+{
+ delete(KISS);
+ deviceUI->reject();
+}
+
+
+void QtTermTCP::AlertSlot()
+{
+ // This runs the VARA Configuration dialog
+
+ Alert = new(Ui_AlertDialog);
+
+ QDialog UI;
+
+ Alert->setupUi(&UI);
+
+ UI.setFont(*menufont);
+
+ deviceUI = &UI;
+
+ Alert->useBeep->setChecked(useBeep);
+ Alert->useFiles->setChecked(!useBeep);
+
+
+ Alert->InboundBeep->setChecked(ConnectBeep);
+ Alert->InactivityBeep->setChecked(AlertBeep);
+ Alert->Interval->setText(QString::number(AlertInterval));
+
+ Alert->connectFile->setText(ConnectWAV);
+ QObject::connect(Alert->chooseInbound, SIGNAL(clicked()), this, SLOT(chooseInboundWAV()));
+
+
+ QObject::connect(Alert->okButton, SIGNAL(clicked()), this, SLOT(alertAccept()));
+ QObject::connect(Alert->cancelButton, SIGNAL(clicked()), this, SLOT(alertReject()));
+
+ UI.exec();
+}
+
+
+
+
+
+
+void QtTermTCP::chooseInboundWAV()
+{
+ ConnectWAV = QFileDialog::getOpenFileName(this,
+ tr("Select Wav"), "", tr("Sound Files (*.wav)"));
+
+ Alert->connectFile->setText(ConnectWAV);
+
+}
+
+
+void QtTermTCP::alertAccept()
+{
+ QVariant Q;
+
+ useBeep = Alert->useBeep->isChecked();
+
+ ConnectBeep = Alert->InboundBeep->isChecked();
+ AlertBeep = Alert->InactivityBeep->isChecked();
+ AlertInterval = Alert->Interval->text().toInt();
+ ConnectWAV = Alert->connectFile->text();
+
+ delete(Alert);
+ SaveSettings();
+ deviceUI->accept();
+}
+
+void QtTermTCP::alertReject()
+{
+ delete(Alert);
+ deviceUI->reject();
+}
+
+
+
+void QtTermTCP::VARASlot()
+{
+ // This runs the VARA Configuration dialog
+
+ char valChar[80];
+
+ Dev = new(Ui_Dialog);
+
+ QDialog UI;
+
+ Dev->setupUi(&UI);
+
+ UI.setFont(*menufont);
+
+ deviceUI = &UI;
+
+ Dev->VARAEnable->setChecked(VARAEnable);
+ Dev->TermCall->setText(VARATermCall);
+
+ SetVARAParams();
+
+ connect(Dev->VARAHF, SIGNAL(toggled(bool)), this, SLOT(VARAHFChanged(bool)));
+ connect(Dev->VARAFM, SIGNAL(toggled(bool)), this, SLOT(VARAFMChanged(bool)));
+ connect(Dev->VARASAT, SIGNAL(toggled(bool)), this, SLOT(VARASATChanged(bool)));
+
+ if (VARA500)
+ Dev->VARA500->setChecked(true);
+ else if (VARA2750)
+ Dev->VARA2750->setChecked(true);
+ else
+ Dev->VARA2300->setChecked(true);
+
+ if (VARAHF)
+ Dev->VARAHF->setChecked(true);
+ else if (VARAFM)
+ Dev->VARAFM->setChecked(true);
+ else if (VARASAT)
+ Dev->VARASAT->setChecked(true);
+
+ if (VARAHF == 0)
+ Dev->HFMode->setVisible(false);
+
+ connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool)));
+ connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int)));
+
+ if (PTTMode == PTTCAT)
+ Dev->CAT->setChecked(true);
+ else
+ Dev->RTSDTR->setChecked(true);
+
+ if (CATHex)
+ Dev->CATHex->setChecked(true);
+ else
+ Dev->CATText->setChecked(true);
+
+ sprintf(valChar, "%d", pttGPIOPin);
+ Dev->GPIOLeft->setText(valChar);
+ sprintf(valChar, "%d", pttGPIOPinR);
+ Dev->GPIORight->setText(valChar);
+
+ Dev->VIDPID->setText(CM108Addr);
+
+
+ QStringList items;
+
+#ifdef USESERIAL
+
+ for (const QSerialPortInfo &info : Ports)
+ {
+ items.append(info.portName());
+ }
+
+ items.sort();
+
+#endif
+
+ Dev->PTTPort->addItem("None");
+ Dev->PTTPort->addItem("CM108");
+
+#ifdef __ARM_ARCH
+
+ // Dev->PTTPort->addItem("GPIO");
+
+#endif
+
+ Dev->PTTPort->addItem("FLRIG");
+ Dev->PTTPort->addItem("HAMLIB");
+
+ for (const QString &info : items)
+ {
+ Dev->PTTPort->addItem(info);
+ }
+
+ Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString));
+
+ PTTPortChanged(0); // Force reevaluation
+
+ QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept()));
+ QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject()));
+
+ UI.exec();
+
+}
+
+extern QProcess *process;
+
+void ClosePTTPort();
+
+void QtTermTCP::deviceaccept()
+{
+ QVariant Q;
+
+ int OldEnable = VARAEnable;
+ int OldPort = VARAPortNum;
+ char oldHost[128];
+ char oldPath[256];
+
+ strcpy(oldHost, VARAHost);
+ strcpy(oldPath, VARAPath);
+
+ VARAEnable = Dev->VARAEnable->isChecked();
+
+ strcpy(VARATermCall, Dev->TermCall->text().toUtf8().toUpper());
+
+ Q = Dev->Port->text();
+
+ VARAPortNum = Q.toInt();
+ strcpy(VARAHost, Dev->Host->text().toUtf8().toUpper());
+ strcpy(VARAPath, Dev->Path->text().toUtf8());
+ strcpy(VARAInit, Dev->InitCommands->text().toUtf8());
+
+ VARA500 = Dev->VARA500->isChecked();
+ VARA2300 = Dev->VARA2300->isChecked();
+ VARA2750 = Dev->VARA2750->isChecked();
+
+ VARAHF = Dev->VARAHF->isChecked();
+ VARAFM = Dev->VARAFM->isChecked();
+ VARASAT = Dev->VARASAT->isChecked();
+
+ if (VARAHF)
+ {
+ strcpy(VARAHostHF, VARAHost);
+ strcpy(VARAPathHF, VARAPath);
+ VARAPortHF = VARAPortNum;
+ }
+ else if (VARAFM)
+ {
+ strcpy(VARAHostFM, VARAHost);
+ strcpy(VARAPathFM, VARAPath);
+ VARAPortFM = VARAPortNum;
+ }
+ else if (VARASAT)
+ {
+ strcpy(VARAHostSAT, VARAHost);
+ strcpy(VARAPathSAT, VARAPath);
+ VARAPortSAT = VARAPortNum;
+ }
+
+ Q = Dev->PTTPort->currentText();
+ strcpy(PTTPort, Q.toString().toUtf8());
+
+ if (Dev->CAT->isChecked())
+ PTTMode = PTTCAT;
+ else
+ PTTMode = PTTRTS;
+
+ if (Dev->CATHex->isChecked())
+ CATHex = 1;
+ else
+ CATHex = 0;
+
+ Q = Dev->PTTOn->text();
+ strcpy(PTTOnString, Q.toString().toUtf8());
+ Q = Dev->PTTOff->text();
+ strcpy(PTTOffString, Q.toString().toUtf8());
+
+ Q = Dev->CATSpeed->text();
+ PTTBAUD = Q.toInt();
+
+ Q = Dev->GPIOLeft->text();
+ pttGPIOPin = Q.toInt();
+
+ Q = Dev->GPIORight->text();
+ pttGPIOPinR = Q.toInt();
+
+ Q = Dev->VIDPID->text();
+
+ if (strcmp(PTTPort, "CM108") == 0)
+ strcpy(CM108Addr, Q.toString().toUtf8());
+ else if (strcmp(PTTPort, "HAMLIB") == 0)
+ {
+ HamLibPort = Q.toInt();
+ Q = Dev->PTTOn->text();
+ strcpy(HamLibHost, Q.toString().toUtf8());
+ }
+
+ if (VARAEnable != OldEnable || VARAPortNum != OldPort || strcmp(oldHost, VARAHost) != 0)
+ {
+ // (re)start connection
+
+ if (OldEnable && VARASock && VARASock->ConnectedState == QAbstractSocket::ConnectedState)
+ {
+ VARASock->disconnectFromHost();
+ if (VARADataSock)
+ VARADataSock->disconnectFromHost();
+ Status2->setText("VARA Disconnected");
+ }
+ }
+
+ if (process && process->state() == QProcess::Running)
+ if ((VARAEnable == 0 || strcmp(oldPath, VARAPath) != 0))
+ process->close();
+
+ myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable);
+
+ ClosePTTPort();
+ OpenPTTPort();
+
+ delete(Dev);
+ SaveSettings();
+ deviceUI->accept();
+
+ QSize newSize(this->size());
+ QSize oldSize(this->size());
+
+ QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize);
+
+ QCoreApplication::postEvent(this, myResizeEvent);
+}
+
+void QtTermTCP::devicereject()
+{
+ delete(Dev);
+ deviceUI->reject();
+}
+
+// This handles incoming connections
+
+void QtTermTCP::onNewConnection()
+{
+ myTcpSocket *clientSocket = (myTcpSocket *)_server->nextPendingConnection();
+
+ clientSocket->Sess = NULL;
+
+ Ui_ListenSession * S;
+ Ui_ListenSession * Sess = NULL;
+
+ char Title[512];
+ int i = 0;
+
+ QByteArray Host = clientSocket->peerAddress().toString().toUtf8();
+
+ if (TermMode == MDI)
+ {
+ // See if an old session can be reused
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ S = _sessions.at(i);
+
+ // for (Ui_ListenSession * S: _sessions)
+ // {
+ if ((S->SessionType & Listen) && S->clientSocket == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+
+ // Create a window if none found, else reuse old
+
+ if (Sess == NULL)
+ {
+ Sess = newWindow(this, Listen);
+ }
+
+ QByteArray Host = clientSocket->peerAddress().toString().toUtf8();
+ }
+ else
+ {
+ // Single or Tabbed - look for free session
+
+ for (i = 0; i < _sessions.size(); ++i)
+ {
+ S = _sessions.at(i);
+
+ if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+
+ if (Sess == NULL)
+ {
+ // Clear connection
+
+ clientSocket->disconnectFromHost();
+ return;
+ }
+ }
+
+ _sockets.push_back(clientSocket);
+
+ clientSocket->Sess = Sess;
+
+ // See if any data from host - first msg should be callsign
+
+ clientSocket->waitForReadyRead(1000);
+
+ QByteArray datas = clientSocket->readAll();
+
+ datas.chop(2);
+ datas.truncate(10); // Just in case!
+
+ datas.append('\0');
+
+ sprintf(Title, "Inward Connect from %s:%d Call " + datas,
+ Host.data(), clientSocket->peerPort());
+
+ if (TermMode == MDI)
+ {
+ Sess->setWindowTitle(Title);
+ }
+ else if (TermMode == Tabbed)
+ {
+ tabWidget->setTabText(i, datas.data());
+ tabWidget->tabBar()->setTabTextColor(i, newTabText);
+ }
+
+ else if (TermMode == Single)
+ this->setWindowTitle(Title);
+
+ connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead()));
+ connect(clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState)));
+
+ Sess->clientSocket = clientSocket;
+
+ // We need to set Connect and Disconnect if the window is active
+
+ if (TermMode == MDI && Sess->sw == ActiveSubWindow)
+ setMenus(true);
+
+ if (TermMode == Tabbed && Sess->Tab == tabWidget->currentIndex())
+ setMenus(true);
+
+ if (TermMode == Single)
+ setMenus(true); // Single
+
+ // Send CText if defined
+
+ if (listenCText[0])
+ Sess->clientSocket->write(listenCText);
+
+ // Send Message to Terminal
+
+ char Msg[80];
+
+ sprintf(Msg, "Listen Connect from %s\r\r", datas.data());
+
+ WritetoOutputWindow(Sess, (unsigned char *)Msg, (int)strlen(Msg));
+
+ if (ConnectBeep)
+ myBeep(ConnectBeep);
+}
+
+void QtTermTCP::onSocketStateChanged(QAbstractSocket::SocketState socketState)
+{
+ myTcpSocket* sender = static_cast(QObject::sender());
+ Ui_ListenSession * Sess = (Ui_ListenSession *)sender->Sess;
+
+ if (socketState == QAbstractSocket::UnconnectedState)
+ {
+ char Msg[] = "Disconnected\r";
+
+ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg),
+ Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red
+
+ if (TermMode == MDI)
+ {
+ if (Sess->SessionType == Mon) // Mon Only
+ Sess->setWindowTitle("Monitor Session Disconnected");
+ else
+ Sess->setWindowTitle("Disconnected");
+ }
+ else if (TermMode == Tabbed)
+ {
+ if (Sess->SessionType == Mon) // Mon Only
+ tabWidget->setTabText(Sess->Tab, "Monitor");
+ else
+ {
+ char Label[16];
+ sprintf(Label, "Sess %d", Sess->Tab + 1);
+ tabWidget->setTabText(Sess->Tab, Label);
+ }
+ }
+ else if (TermMode == Single)
+ {
+ if (Sess->AGWMonSession)
+ mythis->setWindowTitle("AGW Monitor Window");
+ else
+ {
+ if (Sess->SessionType == Mon) // Mon Only
+ this->setWindowTitle("Monitor Session Disconnected");
+ else
+ this->setWindowTitle("Disconnected");
+ }
+ }
+
+ if (Sess->TTActive)
+ {
+ Sess->TTActive = 0;
+ DoTermResize(Sess);
+ }
+
+ Sess->PortMonString[0] = 0;
+
+ // delete(Sess->clientSocket);
+ Sess->clientSocket = NULL;
+
+ discAction->setEnabled(false);
+
+ if ((Sess->SessionType & Listen))
+ _sockets.removeOne(sender);
+ else
+ {
+ connectMenu->setEnabled(true);
+ YAPPSend->setEnabled(false);
+ }
+ }
+ else if (socketState == QAbstractSocket::ConnectedState)
+ {
+ char Signon[256];
+ char Title[128];
+
+ // only seems to be triggered for outward connect
+
+ sprintf(Signon, "%s\r%s\rBPQTERMTCP\r", UserName[Sess->CurrentHost], Password[Sess->CurrentHost]);
+
+ Sess->clientSocket->write(Signon);
+
+ discAction->setEnabled(true);
+ YAPPSend->setEnabled(true);
+ connectMenu->setEnabled(false);
+
+ SendTraceOptions(Sess);
+
+ Sess->InputMode = 0;
+ Sess->SlowTimer = 0;
+ Sess->MonData = 0;
+ Sess->OutputSaveLen = 0; // Clear any part line
+ Sess->MonSaveLen = 0; // Clear any part line
+
+ if (Sess->SessionType == Mon) // Mon Only
+ sprintf(Title, "Monitor Session Connected to %s", Host[Sess->CurrentHost]);
+ else
+ {
+ char Label[256];
+
+ if (SessName[Sess->CurrentHost][0])
+ sprintf(Label, "%s(%s)", Host[Sess->CurrentHost], SessName[Sess->CurrentHost]);
+ else
+ strcpy(Label, Host[Sess->CurrentHost]);
+
+ sprintf(Title, "Connected to %s", Label);
+ }
+
+ if (TermMode == MDI)
+ Sess->setWindowTitle(Title);
+ else if (TermMode == Tabbed)
+ {
+ if (SessName[Sess->CurrentHost][0])
+ tabWidget->setTabText(Sess->Tab, SessName[Sess->CurrentHost]);
+ else
+ tabWidget->setTabText(Sess->Tab, Host[Sess->CurrentHost]);
+ }
+ else if (TermMode == Single)
+ this->setWindowTitle(Title);
+ }
+}
+
+void QtTermTCP::updateWindowMenu()
+{
+ if (TermMode == MDI)
+ {
+ windowMenu->clear();
+ windowMenu->addAction(newTermAct);
+ windowMenu->addAction(newMonAct);
+ windowMenu->addAction(newCombinedAct);
+ windowMenu->addSeparator();
+ windowMenu->addAction(closeAct);
+ windowMenu->addAction(closeAllAct);
+ windowMenu->addSeparator();
+ windowMenu->addAction(tileAct);
+ windowMenu->addAction(cascadeAct);
+ windowMenu->addSeparator();
+ windowMenu->addAction(nextAct);
+ windowMenu->addAction(previousAct);
+ windowMenu->addAction(quitAction);
+ windowMenu->addAction(windowMenuSeparatorAct);
+
+ QList windows = mdiArea->subWindowList();
+ windowMenuSeparatorAct->setVisible(!windows.isEmpty());
+
+ Ui_ListenSession * Sess;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+ Sess->actActivate = windowMenu->addAction(Sess->sw->windowTitle());
+ QAction::connect(Sess->actActivate, SIGNAL(triggered()), this, SLOT(actActivate()));
+ Sess->actActivate->setCheckable(true);
+ Sess->actActivate->setChecked(ActiveSubWindow == Sess->sw);
+ }
+ }
+ else if (TermMode == Tabbed)
+ {
+ windowMenu->clear();
+
+ Ui_ListenSession * Sess = (Ui_ListenSession *)tabWidget->currentWidget();
+
+ QActionGroup * termGroup = new QActionGroup(this);
+
+ delete(TabSingle);
+ delete(TabBoth);
+ delete(TabMon);
+
+ TabSingle = setupMenuLine(nullptr, (char *)"Terminal Only", this, (Sess->SessionType == Term));
+ TabBoth = setupMenuLine(nullptr, (char *)"Terminal + Monitor", this, (Sess->SessionType == Term + Mon));
+ TabMon = setupMenuLine(nullptr, (char *)"Monitor Only", this, (Sess->SessionType == Mon));
+
+ termGroup->addAction(TabSingle);
+ termGroup->addAction(TabBoth);
+ termGroup->addAction(TabMon);
+
+ windowMenu->addAction(TabSingle);
+ windowMenu->addAction(TabBoth);
+ windowMenu->addAction(TabMon);
+
+ }
+}
+
+Ui_ListenSession::~Ui_ListenSession()
+{
+ if (this->clientSocket)
+ {
+ int loops = 100;
+ this->clientSocket->disconnectFromHost();
+ while (loops-- && this->clientSocket->state() != QAbstractSocket::UnconnectedState)
+ QThread::msleep(10);
+ }
+}
+
+extern "C" void setTraceOff(Ui_ListenSession * Sess)
+{
+ if ((Sess->SessionType & Mon) == 0)
+ return; // Not Monitor
+
+ if (Sess->AGWMonSession)
+ return;
+
+ char Buffer[80];
+ int Len = sprintf(Buffer, "\\\\\\\\0 0 0 0 0 0 0 0\r");
+
+ SocketFlush(Sess);
+ SocketSend(Sess, Buffer, Len);
+ SocketFlush(Sess);
+}
+
+
+extern "C" void SendTraceOptions(Ui_ListenSession * Sess)
+{
+ if ((Sess->SessionType & Mon) == 0)
+ return; // Not Monitor
+
+ if (Sess->AGWMonSession)
+ return;
+
+ char Buffer[80];
+ int Len = sprintf(Buffer, "\\\\\\\\%llx %x %x %x %x %x %x %x\r", Sess->portmask, Sess->mtxparam, Sess->mcomparam,
+ Sess->MonitorNODES, Sess->MonitorColour, Sess->monUI, 0, 1);
+
+ strcpy(&MonParams[Sess->CurrentHost][0], &Buffer[4]);
+ SaveSettings();
+ SocketFlush(Sess);
+ SocketSend(Sess, Buffer, Len);
+ SocketFlush(Sess);
+}
+
+void QtTermTCP::doNewTerm()
+{
+ newWindow(this, Term);
+}
+
+void QtTermTCP::doNewMon()
+{
+ newWindow(this, Mon);
+}
+
+void QtTermTCP::doNewCombined()
+{
+ newWindow(this, Term + Mon);
+}
+
+void QtTermTCP::doCascade()
+{
+ // Qt Cascade Minimizes windows so do it ourselves
+
+ int x = 0, y = 0;
+
+ Ui_ListenSession * Sess;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ Sess->sw->move(x, y);
+ x += 14;
+ y += 30;
+ }
+}
+
+void QtTermTCP::actActivate()
+{
+ QAction * sender = static_cast(QObject::sender());
+
+ Ui_ListenSession * Sess;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ if (Sess->actActivate == sender)
+ {
+ mdiArea->setActiveSubWindow(Sess->sw);
+ return;
+ }
+ }
+}
+
+
+void QtTermTCP::xon_mdiArea_changed()
+{
+ // This is triggered when the Active MDI window changes
+ // and is used to enable/disable Connect, Disconnect and YAPP Send
+
+
+ QMdiSubWindow *SW = mdiArea->activeSubWindow();
+
+ // Dont waste time if not changed
+
+ if (ActiveSubWindow == SW)
+ return;
+
+ ActiveSubWindow = SW;
+
+ Ui_ListenSession * Sess;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ // for (Ui_ListenSession * Sess : _sessions)
+ // {
+ if (Sess->sw == SW)
+ {
+ ActiveSession = Sess;
+
+ if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState)
+ {
+ discAction->setEnabled(true);
+ YAPPSend->setEnabled(true);
+ connectMenu->setEnabled(false);
+ }
+ else if (Sess->AGWMonSession)
+ {
+ // Connected AGW Monitor Session
+
+ discAction->setEnabled(false);
+ YAPPSend->setEnabled(false);
+ connectMenu->setEnabled(false);
+ }
+ else if (Sess->AGWSession || Sess->KISSSession)
+ {
+ // Connected AGW or KISS Terminal Session
+
+ discAction->setEnabled(true);
+ YAPPSend->setEnabled(true);
+ connectMenu->setEnabled(false);
+ }
+ else
+ {
+ // Not connected
+
+ discAction->setEnabled(false);
+ YAPPSend->setEnabled(false);
+
+ if ((Sess->SessionType & Listen)) // Listen Sessions can't connect
+ connectMenu->setEnabled(false);
+ else
+ connectMenu->setEnabled(true);
+ }
+
+ // If a monitor Window, change Monitor config settings
+
+ if (Sess->PortMonString[0])
+ {
+ char * ptr = (char *)malloc(2048);
+ memcpy(ptr, Sess->PortMonString, 2048);
+
+ int NumberofPorts = atoi((char *)&ptr[2]);
+ char *p, *Context;
+ char msg[80];
+ int portnum;
+ char delim[] = "|";
+
+ // Remove old Monitor menu
+
+ for (int i = 0; i < 64; i++)
+ {
+ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden
+ }
+
+ p = strtok_s((char *)&ptr[2], delim, &Context);
+
+ while (NumberofPorts--)
+ {
+ p = strtok_s(NULL, delim, &Context);
+ if (p == NULL)
+ break;
+
+ portnum = atoi(p);
+
+ sprintf(msg, "Port %s", p);
+
+ if (portnum == 0)
+ portnum = 64;
+
+ if (Sess->portmask & (1ll << (portnum - 1)))
+ SetPortMonLine(portnum, msg, 1, 1);
+ else
+ SetPortMonLine(portnum, msg, 1, 0);
+ }
+ free(ptr);
+
+ MonTX->setChecked(Sess->mtxparam);
+ MonSup->setChecked(Sess->mcomparam);
+ MonUI->setChecked(Sess->monUI);
+ MonNodes->setChecked(Sess->MonitorNODES);
+ MonColour->setChecked(Sess->MonitorColour);
+
+ }
+
+ return;
+ }
+ }
+}
+
+void QtTermTCP::doFonts()
+{
+ fontDialog * xx = new fontDialog(0);
+ xx->exec();
+}
+
+void QtTermTCP::doMFonts()
+{
+ fontDialog * xx = new fontDialog(1);
+ xx->exec();
+}
+
+QColor TempmonBackground = monBackground;
+QColor TemptermBackground = termBackground;
+QColor TempinputBackground = inputBackground;
+
+QColor TempmonRxText = monRxText;
+QColor TempmonTxText = monTxText;
+QColor TempmonOtherText = monOtherText;
+
+QColor TempoutputText = outputText;
+QColor TempEchoText = EchoText;
+QColor TempWarningText = WarningText;
+
+
+QColor TempinputText = inputText;
+
+
+void setDialogColours()
+{
+ char monStyle[128];
+
+ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);",
+ TempmonOtherText.red(), TempmonOtherText.green(), TempmonOtherText.blue(),
+ TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue());
+
+ COLOURS->MonitorBG->setStyleSheet(monStyle);
+ COLOURS->MonOther->setStyleSheet(monStyle);
+
+ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);",
+ TempmonTxText.red(), TempmonTxText.green(), TempmonTxText.blue(),
+ TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue());
+ COLOURS->MonTX->setStyleSheet(monStyle);
+
+ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);",
+ TempmonRxText.red(), TempmonRxText.green(), TempmonRxText.blue(),
+ TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue());
+
+ COLOURS->MonRX->setStyleSheet(monStyle);
+
+ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);",
+ TempoutputText.red(), TempoutputText.green(), TempoutputText.blue(),
+ TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue());
+
+ COLOURS->TermBG->setStyleSheet(monStyle);
+ COLOURS->TermNormal->setStyleSheet(monStyle);
+
+ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);",
+ TempEchoText.red(), TempEchoText.green(), TempEchoText.blue(),
+ TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue());
+
+ COLOURS->Echoed->setStyleSheet(monStyle);
+
+ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);",
+ TempWarningText.red(), TempWarningText.green(), TempWarningText.blue(),
+ TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue());
+
+ COLOURS->Warning->setStyleSheet(monStyle);
+
+ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);",
+ TempinputText.red(), TempinputText.green(), TempinputText.blue(),
+ TempinputBackground.red(), TempinputBackground.green(), TempinputBackground.blue());
+
+ COLOURS->InputBG->setStyleSheet(monStyle);
+ COLOURS->InputColour->setStyleSheet(monStyle);
+
+}
+
+void QtTermTCP::doColours()
+{
+ COLOURS = new(Ui_ColourDialog);
+
+ QDialog UI;
+
+ COLOURS->setupUi(&UI);
+
+ UI.setFont(*menufont);
+
+ deviceUI = &UI;
+
+ TempmonBackground = monBackground;
+ TempmonRxText = monRxText;
+ TempmonTxText = monTxText;
+ TempmonOtherText = monOtherText;
+
+ TemptermBackground = termBackground;
+ TempoutputText = outputText;
+ TempEchoText = EchoText;
+ TempWarningText = WarningText;
+
+ TempinputBackground = inputBackground;
+ TempinputText = inputText;
+
+ setDialogColours();
+
+ QObject::connect(COLOURS->MonitorBG, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+ QObject::connect(COLOURS->TermBG, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+ QObject::connect(COLOURS->InputBG, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+ QObject::connect(COLOURS->MonRX, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+ QObject::connect(COLOURS->MonTX, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+ QObject::connect(COLOURS->MonOther, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+ QObject::connect(COLOURS->TermNormal, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+ QObject::connect(COLOURS->Echoed, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+ QObject::connect(COLOURS->Warning, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+ QObject::connect(COLOURS->InputColour, SIGNAL(clicked()), this, SLOT(ColourPressed()));
+
+ QObject::connect(COLOURS->okButton, SIGNAL(clicked()), this, SLOT(Colouraccept()));
+ QObject::connect(COLOURS->cancelButton, SIGNAL(clicked()), this, SLOT(Colourreject()));
+
+ UI.exec();
+
+}
+
+void QtTermTCP::ColourPressed()
+{
+ char Name[32];
+
+ strcpy(Name, sender()->objectName().toUtf8());
+
+ if (strcmp(Name, "MonitorBG") == 0)
+ TempmonBackground = setColor(TempmonBackground);
+
+ else if (strcmp(Name, "MonTX") == 0)
+ TempmonTxText = setColor(TempmonTxText);
+
+ else if (strcmp(Name, "MonRX") == 0)
+ TempmonRxText = setColor(TempmonRxText);
+
+ else if (strcmp(Name, "MonOther") == 0)
+ TempmonOtherText = setColor(TempmonOtherText);
+
+ else if (strcmp(Name, "TermBG") == 0)
+ TemptermBackground = setColor(TemptermBackground);
+
+ else if (strcmp(Name, "InputBG") == 0)
+ TempinputBackground = setColor(TempinputBackground);
+
+ else if (strcmp(Name, "InputColour") == 0)
+ TempinputText = setColor(TempinputText);
+
+ else if (strcmp(Name, "TermNormal") == 0)
+ TempoutputText = setColor(TempoutputText);
+
+ else if (strcmp(Name, "Echoed") == 0)
+ TempEchoText = setColor(TempEchoText);
+
+ else if (strcmp(Name, "Warning") == 0)
+ TempWarningText = setColor(TempWarningText);
+
+ setDialogColours();
+}
+
+
+void QtTermTCP::Colouraccept()
+{
+ monBackground = TempmonBackground;
+ monRxText = TempmonRxText;
+ monTxText = TempmonTxText;
+ monOtherText = TempmonOtherText;
+
+ termBackground = TemptermBackground;
+ EchoText = TempEchoText;
+ WarningText = TempWarningText;
+ outputText = TempoutputText;
+
+ inputBackground = TempinputBackground;
+ inputText = TempinputText;
+
+ // Set background colour for new windows
+
+ sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);",
+ monBackground.red(), monBackground.green(), monBackground.blue());
+
+ sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);",
+ termBackground.red(), termBackground.green(), termBackground.blue());
+
+ sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);",
+ inputText.red(), inputText.green(), inputText.blue(),
+ inputBackground.red(), inputBackground.green(), inputBackground.blue());
+
+ // Update existing windows
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Ui_ListenSession * S = _sessions.at(i);
+
+ if (S->monWindow)
+ S->monWindow->setStyleSheet(monStyleSheet);
+
+ if (S->termWindow)
+ S->termWindow->setStyleSheet(termStyleSheet);
+
+ if (S->inputWindow)
+ S->inputWindow->setStyleSheet(inputStyleSheet);
+
+ }
+
+
+ delete(COLOURS);
+
+ SaveSettings();
+ deviceUI->accept();
+}
+
+void QtTermTCP::Colourreject()
+{
+ delete(COLOURS);
+ deviceUI->reject();
+}
+
+
+void QtTermTCP::ConnecttoVARA()
+{
+
+ delete(VARASock);
+
+ VARASock = new myTcpSocket();
+
+ connect(VARASock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(VARAdisplayError(QAbstractSocket::SocketError)));
+ connect(VARASock, SIGNAL(readyRead()), this, SLOT(VARAreadyRead()));
+ connect(VARASock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onVARASocketStateChanged(QAbstractSocket::SocketState)));
+
+ VARASock->connectToHost(VARAHost, VARAPortNum);
+
+ Status2->setText("VARA Control Connecting");
+
+ return;
+}
+
+
+void QtTermTCP::VARATimer()
+{
+ // Runs every 10 Seconds
+
+ if (VARAConnected == 0 && VARAConnecting == 0)
+ {
+ if (process == nullptr || process->state() == QProcess::NotRunning)
+ {
+ if (VARAPath[0])
+ {
+ process = new QProcess(this);
+ QString file = VARAPath;
+ process->start(file);
+ }
+ }
+ QThread::msleep(1000);
+ VARAConnecting = true;
+ ConnecttoVARA();
+ }
+}
+
+
+void QtTermTCP::VARAdisplayError(QAbstractSocket::SocketError socketError)
+{
+ switch (socketError)
+ {
+ case QAbstractSocket::RemoteHostClosedError:
+ break;
+
+ case QAbstractSocket::HostNotFoundError:
+ QMessageBox::information(this, tr("QtTermTCP"),
+ tr("VARA host was not found. Please check the "
+ "host name and portsettings->"));
+
+ Status2->setText("VARA Connection Failed");
+
+ break;
+
+ case QAbstractSocket::ConnectionRefusedError:
+
+ Status2->setText("VARA Connection Refused");
+ break;
+
+ default:
+
+ Status2->setText("VARA Connection Failed");
+ }
+
+ VARAConnecting = 0;
+ VARAConnected = 0;
+}
+
+void QtTermTCP::VARAreadyRead()
+{
+ int Read;
+ char Buffer[4096];
+ char * ptr;
+ char * Msg;
+ myTcpSocket* Socket = static_cast(QObject::sender());
+
+ // read the data from the socket
+
+ Read = Socket->read((char *)Buffer, 4095);
+
+ Buffer[Read] = 0;
+
+ Msg = Buffer;
+
+ ptr = strchr(Msg, 0x0d);
+
+ while (ptr)
+ {
+ *ptr++ = 0;
+
+ if (strcmp(Msg, "IAMALIVE") == 0)
+ {
+ }
+ else if (strcmp(Msg, "PTT ON") == 0)
+ {
+ RadioPTT(1);
+ }
+ else if (strcmp(Msg, "PTT OFF") == 0)
+ {
+ RadioPTT(0);
+ }
+ else if (strcmp(Msg, "PENDING") == 0)
+ {
+ }
+ else if (strcmp(Msg, "CANCELPENDING") == 0)
+ {
+ }
+ else if (strcmp(Msg, "OK") == 0)
+ {
+ }
+ else if (memcmp(Msg, "CONNECTED ", 10) == 0)
+ {
+ Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess;
+ char Title[128] = "";
+ char CallFrom[64] = "";
+ char CallTo[64] = "";
+ char Mode[64] = "";
+ char Message[128];
+ int n;
+
+
+ sscanf(&Msg[10], "%s %s %s", CallFrom, CallTo, Mode);
+
+ if (Sess)
+ {
+ if (Mode[0])
+ sprintf(Title, "Connected to %s %s Mode", CallTo, Mode);
+ else
+ sprintf(Title, "Connected to %s", CallTo);
+
+ n = sprintf(Message, "%s\r\n", Title);
+ WritetoOutputWindow(Sess, (unsigned char *)Message, n);
+
+ if (TermMode == MDI)
+ Sess->setWindowTitle(Title);
+ else if (TermMode == Tabbed)
+ tabWidget->setTabText(Sess->Tab, CallTo);
+ else if (TermMode == Single)
+ mythis->setWindowTitle(Title);
+
+ setMenus(true);
+ }
+ else
+ {
+ // Incoming Call
+
+ Ui_ListenSession * S;
+ int i = 0;
+
+ if (TermMode == MDI)
+ {
+ // See if an old session can be reused
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ S = _sessions.at(i);
+
+ // for (Ui_ListenSession * S: _sessions)
+ // {
+ if ((S->SessionType & Listen) && S->clientSocket == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+
+ // Create a window if none found, else reuse old
+
+ if (Sess == NULL)
+ {
+ Sess = newWindow(this, Listen);
+ }
+ }
+ else
+ {
+ // Single or Tabbed - look for free session
+
+ for (i = 0; i < _sessions.size(); ++i)
+ {
+ S = _sessions.at(i);
+
+ if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+ }
+
+ if (Sess == NULL)
+ {
+ // Clear connection
+
+ VARASock->write("DISCONNECT\r");
+ }
+ else
+ {
+ if (Mode[0])
+ {
+ sprintf(Title, "Connected to %s Mode %s", CallFrom, Mode);
+ n = sprintf(Message, "Incoming Connected from %s %s Mode\r\n", CallFrom, Mode);
+ }
+ else
+ {
+ sprintf(Title, "Connected to %s", CallFrom);
+ n = sprintf(Message, "Incoming Connected from %s\r\n", CallFrom);
+ }
+
+ WritetoOutputWindow(Sess, (unsigned char *)Message, n);
+
+ VARASock->Sess = Sess;
+ VARADataSock->Sess = Sess;
+
+ if (TermMode == MDI)
+ Sess->setWindowTitle(Title);
+ else if (TermMode == Tabbed)
+ {
+ tabWidget->setTabText(Sess->Tab, CallFrom);
+ tabWidget->tabBar()->setTabTextColor(Sess->Tab, newTabText);
+ }
+ else if (TermMode == Single)
+ mythis->setWindowTitle(Title);
+
+ setMenus(true);
+
+ }
+ }
+ }
+ else if (strcmp(Msg, "DISCONNECTED") == 0)
+ {
+ Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess;
+
+ if (Sess)
+ {
+ WritetoOutputWindow(Sess, (unsigned char *)"Disconnected\r\n", 14);
+ VARASock->Sess = 0;
+ VARADataSock->Sess = 0;
+
+ if (TermMode == MDI)
+ {
+ if (Sess->SessionType == Mon) // Mon Only
+ Sess->setWindowTitle("Monitor Session Disconnected");
+ else
+ Sess->setWindowTitle("Disconnected");
+ }
+ else if (TermMode == Tabbed)
+ {
+ if (Sess->SessionType == Mon) // Mon Only
+ tabWidget->setTabText(Sess->Tab, "Monitor");
+ else
+ {
+ char Label[16];
+ sprintf(Label, "Sess %d", Sess->Tab + 1);
+ tabWidget->setTabText(Sess->Tab, Label);
+ }
+ }
+ else if (TermMode == Single)
+ {
+ if (Sess->AGWMonSession)
+ mythis->setWindowTitle("AGW Monitor Window");
+ else
+ {
+ if (Sess->SessionType == Mon) // Mon Only
+ this->setWindowTitle("Monitor Session Disconnected");
+ else
+ this->setWindowTitle("Disconnected");
+ }
+ }
+
+ setMenus(false);
+ }
+ }
+
+ Msg = ptr;
+
+ ptr = strchr(Msg, 0x0d);
+ }
+
+
+
+}
+
+void QtTermTCP::onVARASocketStateChanged(QAbstractSocket::SocketState socketState)
+{
+ // myTcpSocket* sender = static_cast(QObject::sender());
+
+ if (socketState == QAbstractSocket::UnconnectedState)
+ {
+ // Close any connections
+
+ Status2->setText("VARA Disconnected");
+ actHost[17]->setVisible(0);
+
+ VARAConnecting = VARAConnected = 0;
+ }
+ else if (socketState == QAbstractSocket::ConnectedState)
+ {
+ // Connect Data Session. Leave Connecting till that completes
+
+ VARADataSock = new myTcpSocket();
+
+ connect(VARADataSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(VARADatadisplayError(QAbstractSocket::SocketError)));
+ connect(VARADataSock, SIGNAL(readyRead()), this, SLOT(VARADatareadyRead()));
+ connect(VARADataSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onVARADataSocketStateChanged(QAbstractSocket::SocketState)));
+
+ VARADataSock->connectToHost(VARAHost, VARAPortNum + 1);
+ Status2->setText("VARA Data Connecting");
+ }
+}
+
+
+void QtTermTCP::VARADatadisplayError(QAbstractSocket::SocketError socketError)
+{
+ switch (socketError)
+ {
+ case QAbstractSocket::RemoteHostClosedError:
+ break;
+
+ case QAbstractSocket::HostNotFoundError:
+ QMessageBox::information(this, tr("QtTermTCP"),
+ tr("VARA host was not found. Please check the "
+ "host name and portsettings->"));
+
+ Status2->setText("VARA Connection Failed");
+
+ break;
+
+ case QAbstractSocket::ConnectionRefusedError:
+
+ Status2->setText("VARA Connection Refused");
+ break;
+
+ default:
+
+ Status2->setText("VARA Connection Failed");
+ }
+
+ VARAConnecting = 0;
+ VARAConnected = 0;
+}
+
+void QtTermTCP::VARADatareadyRead()
+{
+ int Read;
+ unsigned char Buffer[4096];
+ myTcpSocket* Socket = static_cast(QObject::sender());
+
+ Ui_ListenSession * Sess = (Ui_ListenSession *)Socket->Sess;
+
+ // read the data from the socket
+
+ Read = Socket->read((char *)Buffer, 2047);
+
+ while (Read > 0)
+ {
+ // if (InputMode == 'Y') // Yapp
+ // {
+ // QString myString = QString::fromUtf8((char*)Buffer, Read);
+ // QByteArray ptr = myString.toLocal8Bit();
+ // memcpy(Buffer, ptr.data(), ptr.length());
+ // Read = ptr.length();
+ // }
+
+ ProcessReceivedData(Sess, Buffer, Read);
+
+ QString myString = QString::fromUtf8((char*)Buffer);
+ // qDebug() << myString;
+ Read = Socket->read((char *)Buffer, 2047);
+ }
+}
+
+
+void QtTermTCP::onVARADataSocketStateChanged(QAbstractSocket::SocketState socketState)
+{
+ // myTcpSocket* sender = static_cast(QObject::sender());
+
+ if (socketState == QAbstractSocket::UnconnectedState)
+ {
+ // Close any connections
+
+ Status2->setText("VARA Disconnected");
+ actHost[17]->setVisible(0);
+
+ VARAConnecting = VARAConnected = 0;
+ }
+ else if (socketState == QAbstractSocket::ConnectedState)
+ {
+ char VARACommand[256];
+
+ VARAConnected = 1;
+ VARAConnecting = 0;
+
+ Status2->setText("VARA Connected");
+
+ actHost[17]->setVisible(1); // Enable VARA Connect Line
+
+ sprintf(VARACommand, "MYCALL %s\r", VARATermCall);
+ VARASock->write(VARACommand);
+
+ if (VARA500)
+ VARASock->write("BW500\r");
+ else if (VARA2300)
+ VARASock->write("BW2300\r");
+ else if (VARA2750)
+ VARASock->write("BW2750\r");
+
+ VARASock->write("COMPRESSION FILES\r");
+
+ if (VARAInit[0])
+ {
+ char Copy[512];
+ char * param, *context;
+
+ strcpy(Copy, VARAInit);
+
+ param = strtok_s(Copy, ",", &context);
+
+ while (param && param[0])
+ {
+ sprintf(VARACommand, "%s\r", param);
+ VARASock->write(VARACommand);
+ param = strtok_s(nullptr, ",", &context);
+ }
+ }
+
+ if (listenEnable)
+ VARASock->write("LISTEN ON\r");
+ }
+}
+
+// PTT Stuff
+
+#include "hidapi.h"
+
+// Serial Port Stuff
+
+
+QTcpSocket * HAMLIBsock;
+int HAMLIBConnected = 0;
+int HAMLIBConnecting = 0;
+
+void QtTermTCP::HAMLIBdisplayError(QAbstractSocket::SocketError socketError)
+{
+ switch (socketError)
+ {
+ case QAbstractSocket::RemoteHostClosedError:
+ break;
+
+ case QAbstractSocket::HostNotFoundError:
+ QMessageBox::information(nullptr, tr("QtSM"),
+ "HAMLIB host was not found. Please check the "
+ "host name and portsettings->");
+
+ break;
+
+ case QAbstractSocket::ConnectionRefusedError:
+
+ qDebug() << "HAMLIB Connection Refused";
+ break;
+
+ default:
+
+ qDebug() << "HAMLIB Connection Failed";
+ break;
+
+ }
+
+ HAMLIBConnecting = 0;
+ HAMLIBConnected = 0;
+}
+
+void QtTermTCP::HAMLIBreadyRead()
+{
+ unsigned char Buffer[4096];
+ QTcpSocket* Socket = static_cast(QObject::sender());
+
+ // read the data from the socket. Don't do anyhing with it at the moment
+
+ Socket->read((char *)Buffer, 4095);
+}
+
+void QtTermTCP::onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState)
+{
+ if (socketState == QAbstractSocket::UnconnectedState)
+ {
+ // Close any connections
+
+ HAMLIBConnected = 0;
+ HAMLIBConnecting = 0;
+
+ // delete (HAMLIBsock);
+ // HAMLIBsock = 0;
+
+ qDebug() << "HAMLIB Connection Closed";
+
+ }
+ else if (socketState == QAbstractSocket::ConnectedState)
+ {
+ HAMLIBConnected = 1;
+ HAMLIBConnecting = 0;
+ qDebug() << "HAMLIB Connected";
+ }
+}
+
+
+void QtTermTCP::ConnecttoHAMLIB()
+{
+ delete(HAMLIBsock);
+
+ HAMLIBConnected = 0;
+ HAMLIBConnecting = 1;
+
+ HAMLIBsock = new QTcpSocket();
+
+ connect(HAMLIBsock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(HAMLIBdisplayError(QAbstractSocket::SocketError)));
+ connect(HAMLIBsock, SIGNAL(readyRead()), this, SLOT(HAMLIBreadyRead()));
+ connect(HAMLIBsock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onHAMLIBSocketStateChanged(QAbstractSocket::SocketState)));
+
+ HAMLIBsock->connectToHost(HamLibHost, HamLibPort);
+
+ return;
+}
+
+void QtTermTCP::HAMLIBSetPTT(int PTTState)
+{
+ char Msg[16];
+
+ if (HAMLIBsock == nullptr || HAMLIBsock->state() != QAbstractSocket::ConnectedState)
+ ConnecttoHAMLIB();
+
+ if (HAMLIBsock == nullptr || HAMLIBsock->state() != QAbstractSocket::ConnectedState)
+ return;
+
+ sprintf(Msg, "T %d\r\n", PTTState);
+ HAMLIBsock->write(Msg);
+
+ HAMLIBsock->waitForBytesWritten(3000);
+
+ QByteArray datas = HAMLIBsock->readAll();
+
+ qDebug(datas.data());
+}
+
+QTcpSocket * FLRigsock;
+int FLRigConnected = 0;
+int FLRigConnecting = 0;
+
+void QtTermTCP::FLRigdisplayError(QAbstractSocket::SocketError socketError)
+{
+ switch (socketError)
+ {
+ case QAbstractSocket::RemoteHostClosedError:
+ break;
+
+ case QAbstractSocket::HostNotFoundError:
+ QMessageBox::information(nullptr, tr("QtSM"),
+ "FLRig host was not found. Please check the "
+ "host name and portsettings->");
+
+ break;
+
+ case QAbstractSocket::ConnectionRefusedError:
+
+ qDebug() << "FLRig Connection Refused";
+ break;
+
+ default:
+
+ qDebug() << "FLRig Connection Failed";
+ break;
+
+ }
+
+ FLRigConnecting = 0;
+ FLRigConnected = 0;
+}
+
+void QtTermTCP::FLRigreadyRead()
+{
+ unsigned char Buffer[4096];
+ QTcpSocket* Socket = static_cast(QObject::sender());
+
+ // read the data from the socket. Don't do anyhing with it at the moment
+
+ Socket->read((char *)Buffer, 4095);
+}
+
+void QtTermTCP::onFLRigSocketStateChanged(QAbstractSocket::SocketState socketState)
+{
+ if (socketState == QAbstractSocket::UnconnectedState)
+ {
+ // Close any connections
+
+ FLRigConnected = 0;
+ FLRigConnecting = 0;
+
+ // delete (FLRigsock);
+ // FLRigsock = 0;
+
+ qDebug() << "FLRig Connection Closed";
+
+ }
+ else if (socketState == QAbstractSocket::ConnectedState)
+ {
+ FLRigConnected = 1;
+ FLRigConnecting = 0;
+ qDebug() << "FLRig Connected";
+ }
+}
+
+
+void QtTermTCP::ConnecttoFLRig()
+{
+ delete(FLRigsock);
+
+ FLRigConnected = 0;
+ FLRigConnecting = 1;
+
+ FLRigsock = new QTcpSocket();
+
+ connect(FLRigsock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(FLRigdisplayError(QAbstractSocket::SocketError)));
+ connect(FLRigsock, SIGNAL(readyRead()), this, SLOT(FLRigreadyRead()));
+ connect(FLRigsock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onFLRigSocketStateChanged(QAbstractSocket::SocketState)));
+
+ FLRigsock->connectToHost(FLRigHost, FLRigPort);
+
+ return;
+}
+
+static char MsgHddr[] = "POST /RPC2 HTTP/1.1\r\n"
+"User-Agent: XMLRPC++ 0.8\r\n"
+"Host: 127.0.0.1:7362\r\n"
+"Content-Type: text/xml\r\n"
+"Content-length: %d\r\n"
+"\r\n%s";
+
+static char Req[] = "\r\n"
+"%s\r\n"
+"%s"
+"\r\n";
+
+void QtTermTCP::FLRigSetPTT(int PTTState)
+{
+ int Len;
+ char ReqBuf[512];
+ char SendBuff[512];
+ char ValueString[256] = "";
+
+ sprintf(ValueString, "%d", PTTState);
+
+ Len = sprintf(ReqBuf, Req, "rig.set_ptt", ValueString);
+ Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf);
+
+ if (FLRigsock == nullptr || FLRigsock->state() != QAbstractSocket::ConnectedState)
+ ConnecttoFLRig();
+
+ if (FLRigsock == nullptr || FLRigsock->state() != QAbstractSocket::ConnectedState)
+ return;
+
+ FLRigsock->write(SendBuff);
+
+ FLRigsock->waitForBytesWritten(3000);
+
+ QByteArray datas = FLRigsock->readAll();
+
+ qDebug(datas.data());
+}
+
+
+
+void QtTermTCP::CATChanged(bool State)
+{
+ UNUSED(State);
+ PTTPortChanged(0);
+}
+
+void QtTermTCP::VARAHFChanged(bool State)
+{
+ Dev->HFMode->setVisible(State);
+
+ if (State)
+ {
+ Dev->TNCInfo->setTitle("VARA HF Paramters");
+ Dev->Host->setText(VARAHostHF);
+ Dev->Port->setText(QString::number(VARAPortHF));
+ Dev->Path->setText(VARAPathHF);
+ }
+}
+
+void QtTermTCP::VARAFMChanged(bool State)
+{
+ if (State)
+ {
+ Dev->TNCInfo->setTitle("VARA FM Paramters");
+ Dev->Host->setText(VARAHostFM);
+ Dev->Port->setText(QString::number(VARAPortFM));
+ Dev->Path->setText(VARAPathFM);
+ }
+}
+
+void QtTermTCP::VARASATChanged(bool State)
+{
+ if (State)
+ {
+ Dev->TNCInfo->setTitle("VARA SAT Paramters");
+ Dev->Host->setText(VARAHostSAT);
+ Dev->Port->setText(QString::number(VARAPortSAT));
+ Dev->Path->setText(VARAPathSAT);
+ }
+}
+
+void QtTermTCP::SetVARAParams()
+{
+ Dev->Host->setText(VARAHost);
+ Dev->Port->setText(QString::number(VARAPortNum));
+ Dev->Path->setText(VARAPath);
+ Dev->InitCommands->setText(VARAInit);
+}
+
+void QtTermTCP::PTTPortChanged(int Selected)
+{
+ UNUSED(Selected);
+
+ QVariant Q = Dev->PTTPort->currentText();
+ strcpy(NewPTTPort, Q.toString().toUtf8());
+
+ Dev->RTSDTR->setVisible(false);
+ Dev->CAT->setVisible(false);
+
+ Dev->PTTOnLab->setVisible(false);
+ Dev->PTTOn->setVisible(false);
+ Dev->PTTOff->setVisible(false);
+ Dev->PTTOffLab->setVisible(false);
+ Dev->CATLabel->setVisible(false);
+ Dev->CATSpeed->setVisible(false);
+ Dev->CATHex->setVisible(false);
+ Dev->CATText->setVisible(false);
+
+ Dev->GPIOLab->setVisible(false);
+ Dev->GPIOLeft->setVisible(false);
+ Dev->GPIORight->setVisible(false);
+ Dev->GPIOLab2->setVisible(false);
+
+ Dev->CM108Label->setVisible(false);
+ Dev->VIDPID->setVisible(false);
+
+ if (strcmp(NewPTTPort, "None") == 0)
+ {
+ }
+ else if (strcmp(NewPTTPort, "GPIO") == 0)
+ {
+ Dev->GPIOLab->setVisible(true);
+ Dev->GPIOLeft->setVisible(true);
+ }
+
+ else if (strcmp(NewPTTPort, "CM108") == 0)
+ {
+ Dev->CM108Label->setVisible(true);
+#ifdef WIN32
+ Dev->CM108Label->setText("CM108 VID/PID");
+#else
+ Dev->CM108Label->setText("CM108 Device");
+#endif
+ Dev->VIDPID->setText(CM108Addr);
+ Dev->VIDPID->setVisible(true);
+ }
+ else if (strcmp(NewPTTPort, "HAMLIB") == 0)
+ {
+ Dev->CM108Label->setVisible(true);
+ Dev->CM108Label->setText("rigctrld Port");
+ Dev->VIDPID->setText(QString::number(HamLibPort));
+ Dev->VIDPID->setVisible(true);
+ Dev->PTTOnLab->setText("rigctrld Host");
+ Dev->PTTOnLab->setVisible(true);
+ Dev->PTTOn->setText(HamLibHost);
+ Dev->PTTOn->setVisible(true);
+ }
+ else if (strcmp(NewPTTPort, "FLRIG") == 0)
+ {
+ Dev->CM108Label->setVisible(true);
+ Dev->CM108Label->setText("FLRig Port");
+ Dev->VIDPID->setText(QString::number(FLRigPort));
+ Dev->VIDPID->setVisible(true);
+ Dev->PTTOnLab->setText("FLRig Host");
+ Dev->PTTOnLab->setVisible(true);
+ Dev->PTTOn->setText(FLRigHost);
+ Dev->PTTOn->setVisible(true);
+ }
+
+ else
+ {
+ Dev->RTSDTR->setVisible(true);
+ Dev->CAT->setVisible(true);
+
+ if (Dev->CAT->isChecked())
+ {
+ Dev->CATHex->setVisible(true);
+ Dev->CATText->setVisible(true);
+ Dev->PTTOnLab->setVisible(true);
+ Dev->PTTOnLab->setText("PTT On String");
+ Dev->PTTOn->setText(PTTOnString);
+ Dev->PTTOn->setVisible(true);
+ Dev->PTTOff->setVisible(true);
+ Dev->PTTOffLab->setVisible(true);
+ Dev->PTTOff->setVisible(true);
+ Dev->PTTOff->setText(PTTOffString);
+ Dev->CATLabel->setVisible(true);
+ Dev->CATSpeed->setVisible(true);
+ Dev->CATSpeed->setText(QString::number(PTTBAUD));
+ }
+ }
+}
+
+
+
+void DecodeCM108(char * ptr)
+{
+ // Called if Device Name or PTT = Param is CM108
+
+#ifdef WIN32
+
+ // Next Param is VID and PID - 0xd8c:0x8 or Full device name
+ // On Windows device name is very long and difficult to find, so
+ // easier to use VID/PID, but allow device in case more than one needed
+
+ char * next;
+ long VID = 0, PID = 0;
+ char product[256] = "Unknown";
+
+ struct hid_device_info *devs, *cur_dev;
+ const char *path_to_open = NULL;
+ hid_device *handle = NULL;
+
+ if (strlen(ptr) > 16)
+ CM108Device = _strdup(ptr);
+ else
+ {
+ VID = strtol(ptr, &next, 0);
+ if (next)
+ PID = strtol(++next, &next, 0);
+
+ // Look for Device
+
+ devs = hid_enumerate((unsigned short)VID, (unsigned short)PID);
+ cur_dev = devs;
+
+ while (cur_dev)
+ {
+ if (cur_dev->product_string)
+ wcstombs(product, cur_dev->product_string, 255);
+
+ printf("HID Device %s VID %X PID %X", product, cur_dev->vendor_id, cur_dev->product_id);
+ if (cur_dev->vendor_id == VID && cur_dev->product_id == PID)
+ {
+ path_to_open = cur_dev->path;
+ break;
+ }
+ cur_dev = cur_dev->next;
+ }
+
+ if (path_to_open)
+ {
+ handle = hid_open_path(path_to_open);
+
+ if (handle)
+ {
+ hid_close(handle);
+ CM108Device = _strdup(path_to_open);
+ }
+ else
+ {
+ printf("Unable to open CM108 device %x %x", VID, PID);
+ }
+ }
+ else
+ printf("Couldn't find CM108 device %x %x", VID, PID);
+
+ hid_free_enumeration(devs);
+ }
+#else
+
+ // Linux - Next Param HID Device, eg /dev/hidraw0
+
+ CM108Device = strdup(ptr);
+#endif
+}
+
+
+void QtTermTCP::OpenPTTPort()
+{
+ PTTMode &= ~PTTCM108;
+ PTTMode &= ~PTTHAMLIB;
+ PTTMode &= ~PTTFLRIG;
+
+ if (PTTPort[0] && strcmp(PTTPort, "None") != 0)
+ {
+ if (PTTMode == PTTCAT)
+ {
+ // convert config strings from Hex
+
+ if (CATHex == 0) // Ascii Strings
+ {
+ strcpy((char *)PTTOffCmd, PTTOffString);
+ PTTOffCmdLen = strlen(PTTOffString);
+
+ strcpy((char *)PTTOnCmd, PTTOnString);
+ PTTOnCmdLen = strlen(PTTOnString);
+ }
+ else
+ {
+ char * ptr1 = PTTOffString;
+ unsigned char * ptr2 = PTTOffCmd;
+ char c;
+ int val;
+
+ while ((c = *(ptr1++)))
+ {
+ val = c - 0x30;
+ if (val > 15) val -= 7;
+ val <<= 4;
+ c = *(ptr1++) - 0x30;
+ if (c > 15) c -= 7;
+ val |= c;
+ *(ptr2++) = val;
+ }
+
+ PTTOffCmdLen = ptr2 - PTTOffCmd;
+
+ ptr1 = PTTOnString;
+ ptr2 = PTTOnCmd;
+
+ while ((c = *(ptr1++)))
+ {
+ val = c - 0x30;
+ if (val > 15) val -= 7;
+ val <<= 4;
+ c = *(ptr1++) - 0x30;
+ if (c > 15) c -= 7;
+ val |= c;
+ *(ptr2++) = val;
+ }
+
+ PTTOnCmdLen = ptr2 - PTTOnCmd;
+ }
+ }
+
+ if (strcmp(PTTPort, "GPIO") == 0)
+ {
+ // Initialise GPIO for PTT if available
+
+#ifdef __ARM_ARCH
+
+// if (gpioInitialise() == 0)
+// {
+// printf("GPIO interface for PTT available\n");
+// gotGPIO = TRUE;
+
+// SetupGPIOPTT();
+// }
+// else
+// printf("Couldn't initialise GPIO interface for PTT\n");
+//
+#else
+ printf("GPIO interface for PTT not available on this platform\n");
+#endif
+
+ }
+ else if (strcmp(PTTPort, "CM108") == 0)
+ {
+ DecodeCM108(CM108Addr);
+ PTTMode |= PTTCM108;
+ }
+
+ else if (strcmp(PTTPort, "HAMLIB") == 0)
+ {
+ PTTMode |= PTTHAMLIB;
+ HAMLIBSetPTT(0); // to open port
+ return;
+ }
+
+ else if (strcmp(PTTPort, "FLRIG") == 0)
+ {
+ PTTMode |= PTTFLRIG;
+ FLRigSetPTT(0); // to open port
+ return;
+ }
+
+ else // Serial Port
+ {
+#ifdef USESERIAL
+ hPTTDevice = new QSerialPort(this);
+ hPTTDevice->setPortName(PTTPort);
+ hPTTDevice->setBaudRate(PTTBAUD);
+ hPTTDevice->setDataBits(QSerialPort::Data8);
+ hPTTDevice->setParity(QSerialPort::NoParity);
+ hPTTDevice->setStopBits(QSerialPort::OneStop);
+ hPTTDevice->setFlowControl(QSerialPort::NoFlowControl);
+ if (hPTTDevice->open(QIODevice::ReadWrite))
+ {
+ qDebug() << "PTT Port Opened";
+ }
+ else
+ {
+ QMessageBox msgBox;
+ msgBox.setText("PTT COM Port Open Failed.");
+ msgBox.exec();
+ qDebug() << "PTT Port Open failed";
+ delete(hPTTDevice);
+ hPTTDevice = 0;
+ }
+#endif
+ }
+ }
+}
+
+void ClosePTTPort()
+{
+#ifdef USESERIAL
+ if (hPTTDevice)
+ hPTTDevice->close();
+ hPTTDevice = 0;
+#endif
+}
+
+
+void CM108_set_ptt(int PTTState)
+{
+ unsigned char io[5];
+ int n;
+
+ io[0] = 0;
+ io[1] = 0;
+ io[2] = 1 << (3 - 1);
+ io[3] = PTTState << (3 - 1);
+ io[4] = 0;
+
+ if (CM108Device == NULL)
+ return;
+
+#ifdef WIN32
+ hid_device *handle;
+
+ handle = hid_open_path(CM108Device);
+
+ if (!handle) {
+ printf("unable to open device\n");
+ return;
+ }
+
+ n = hid_write(handle, io, 5);
+ if (n < 0)
+ {
+ printf("Unable to write()\n");
+ printf("Error: %ls\n", hid_error(handle));
+ }
+
+ hid_close(handle);
+
+#else
+
+ int fd;
+
+ fd = open(CM108Device, O_WRONLY);
+
+ if (fd == -1)
+ {
+ printf("Could not open %s for write, errno=%d\n", CM108Device, errno);
+ return;
+ }
+
+ io[0] = 0;
+ io[1] = 0;
+ io[2] = 1 << (3 - 1);
+ io[3] = PTTState << (3 - 1);
+ io[4] = 0;
+
+ n = write(fd, io, 5);
+ if (n != 5)
+ {
+ printf("Write to %s failed, n=%d, errno=%d\n", CM108Device, n, errno);
+ }
+
+ close(fd);
+#endif
+ return;
+
+}
+
+
+
+void QtTermTCP::RadioPTT(bool PTTState)
+{
+#ifdef __ARM_ARCH
+ if (useGPIO)
+ {
+ // gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState)));
+ // return;
+ }
+
+#endif
+
+ if ((PTTMode & PTTCM108))
+ {
+ CM108_set_ptt(PTTState);
+ return;
+ }
+
+ if ((PTTMode & PTTHAMLIB))
+ {
+ HAMLIBSetPTT(PTTState);
+ return;
+ }
+
+ if ((PTTMode & PTTFLRIG))
+ {
+ FLRigSetPTT(PTTState);
+ return;
+ }
+
+#ifdef USESERIAL
+
+ if (hPTTDevice == 0)
+ return;
+
+ if ((PTTMode & PTTCAT))
+ {
+ if (PTTState)
+ hPTTDevice->write((char *)PTTOnCmd, PTTOnCmdLen);
+ else
+ hPTTDevice->write((char *)PTTOffCmd, PTTOffCmdLen);
+
+ hPTTDevice->flush();
+ // hPTTDevice->error();
+ return;
+
+ }
+
+
+ if ((PTTMode & PTTRTS))
+ {
+ int n = hPTTDevice->setRequestToSend(PTTState);
+ n = n;
+ }
+
+#endif
+
+}
+
+
+
+extern "C" void WriteDebugLog(char * Mess)
+{
+ qDebug() << Mess;
+}
+
+void QtTermTCP::ConnecttoKISS()
+{
+ if (strcmp(SerialPort, "TCP") == 0)
+ {
+ delete(KISSSock);
+
+ KISSSock = new myTcpSocket();
+ KISSSockCopy[0] = (void *)KISSSock;
+
+
+ connect(KISSSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(KISSdisplayError(QAbstractSocket::SocketError)));
+ connect(KISSSock, SIGNAL(readyRead()), this, SLOT(KISSreadyRead()));
+ connect(KISSSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onKISSSocketStateChanged(QAbstractSocket::SocketState)));
+
+ KISSSock->connectToHost(KISSHost, KISSPortNum);
+
+ Status3->setText("KISS Connecting");
+ }
+ else
+ openSerialPort();
+
+ return;
+}
+
+
+void QtTermTCP::KISSTimer()
+{
+ // Runs every 10 Seconds
+
+ if (KISSConnected == 0 && KISSConnecting == 0)
+ {
+ ConnecttoKISS();
+ }
+ else
+ {
+ // Verify Serial port is still ok
+
+ if (m_serial && KISSConnected)
+ {
+ m_serial->clearError();
+ m_serial->isDataTerminalReady();
+
+ if (m_serial->error())
+ {
+ Debugprintf("Serial Port Lost - isOpen %d Error %d", m_serial->isOpen(), m_serial->error());
+ closeSerialPort();
+ }
+ }
+ }
+}
+
+
+
+void QtTermTCP::KISSdisplayError(QAbstractSocket::SocketError socketError)
+{
+ switch (socketError)
+ {
+ case QAbstractSocket::RemoteHostClosedError:
+ break;
+
+ case QAbstractSocket::HostNotFoundError:
+ QMessageBox::information(this, tr("QtTermTCP"),
+ tr("KISS host was not found. Please check the "
+ "host name and portsettings->"));
+
+ Status3->setText("KISS Connection Failed");
+
+ break;
+
+ case QAbstractSocket::ConnectionRefusedError:
+
+ Status3->setText("KISS Connection Refused");
+ break;
+
+ default:
+
+ Status3->setText("KISS Connection Failed");
+ }
+
+ KISSConnecting = 0;
+ KISSConnected = 0;
+}
+
+
+extern "C" void KISSSendtoServer(myTcpSocket* Socket, char * Data, int Length)
+{
+ if (m_serial)
+ {
+ if (m_serial->isOpen())
+ {
+ m_serial->clearError();
+
+ int n = m_serial->write(Data, Length);
+
+ n = m_serial->flush();
+
+ if (m_serial->error())
+ {
+ Debugprintf("Serial Flush Error - Requested = %d Actual %d Error %d", Length, n, m_serial->error());
+ closeSerialPort();
+ }
+ }
+ }
+ else if (Socket)
+ Socket->write(Data, Length);
+}
+
+
+
+void QtTermTCP::KISSreadyRead()
+{
+ int Read;
+ unsigned char Buffer[4096]; myTcpSocket* Socket = static_cast(QObject::sender());
+
+ // read the data from the socket
+
+ Read = Socket->read((char *)Buffer, 4095);
+
+ KISSDataReceived(Socket, Buffer, Read);
+
+}
+
+extern "C" void KISS_del_socket(void * socket);
+extern "C" void KISS_add_stream(void * Socket);
+
+void QtTermTCP::onKISSSocketStateChanged(QAbstractSocket::SocketState socketState)
+{
+ // myTcpSocket* sender = static_cast(QObject::sender());
+
+ QTcpSocket* sender = static_cast(QObject::sender());
+
+ if (socketState == QAbstractSocket::UnconnectedState)
+ {
+ // Close any connections
+
+ Ui_ListenSession * Sess = NULL;
+
+ Status3->setText("KISS Disconnected");
+ actHost[18]->setEnabled(0);
+
+ KISSConnecting = KISSConnected = 0;
+
+ // Free the monitor Window
+
+ if (KISSMonSess)
+ {
+ Sess = KISSMonSess;
+
+ if (TermMode == MDI)
+ Sess->setWindowTitle("Monitor Session Disconnected");
+
+ else if (TermMode == Tabbed)
+ tabWidget->setTabText(Sess->Tab, "Monitor");
+
+ KISSMonSess = nullptr;
+ }
+
+ KISS_del_socket(sender);
+ KISSSock = NULL;
+ }
+ else if (socketState == QAbstractSocket::ConnectedState)
+ {
+ int i;
+
+ KISSConnected = 1;
+ KISSConnecting = 0;
+
+ Status3->setText("KISS Connected");
+ actHost[18]->setEnabled(1); // Enable KISS Connect Line
+
+ KISS_add_stream(sender);
+
+ // Attach a Monitor Window if available
+
+ Ui_ListenSession * Sess = NULL;
+ Ui_ListenSession * S;
+
+ if (TermMode == MDI)
+ {
+ // See if an old session can be reused
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ S = _sessions.at(i);
+
+ // for (Ui_ListenSession * S: _sessions)
+ // {
+ if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+
+ // Create a window if none found, else reuse old
+
+ if (Sess == NULL)
+ {
+ Sess = newWindow((QObject *)mythis, Mon, "");
+ }
+ }
+ else if (TermMode == Tabbed)
+ {
+ // Tabbed - look for free session
+
+ for (i = 8; i; i--)
+ {
+ S = _sessions.at(i);
+
+ if (S->clientSocket == NULL && S->KISSSession == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+ }
+ else if (TermMode == Single && (singlemodeFormat & Mon))
+ {
+ S = _sessions.at(0);
+
+ if (S->clientSocket == NULL && S->KISSSession == NULL)
+ Sess = S;
+
+ }
+
+ if (Sess)
+ {
+ KISSMonSess = Sess; // Flag as in use
+
+ if (TermMode == MDI)
+ Sess->setWindowTitle("KISS Monitor Window");
+ else if (TermMode == Tabbed)
+ tabWidget->setTabText(Sess->Tab, "KISS Mon");
+ else if (TermMode == Single)
+ mythis->setWindowTitle("KISS Monitor Window");
+
+ // if (TermMode == Single)
+ // {
+ // discAction->setEnabled(false);
+ // YAPPSend->setEnabled(false);
+ // connectMenu->setEnabled(false);
+ // }
+ }
+ }
+}
+
+
+extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat);
+extern "C" char * ShortDateTime();
+
+extern "C" void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded)
+{
+ UNUSED(excluded);
+ UNUSED(snd_ch);
+
+ int Len;
+ char Msg[1024];
+
+ if (tx)
+ sprintf(Msg, "\x1b\x10%s", frame_monitor(frame, code, tx));
+ else
+ sprintf(Msg, "\x1b\x11%s", frame_monitor(frame, code, tx));
+
+ Len = strlen(Msg);
+
+ if (Msg[Len - 1] != '\r')
+ {
+ Msg[Len++] = '\r';
+ Msg[Len] = 0;
+ }
+
+ if (KISSMonSess)
+ WritetoMonWindow(KISSMonSess, (unsigned char *)Msg, Len);
+
+}
+
+extern "C" Ui_ListenSession * ax25IncommingConnect(TAX25Port * AX25Sess)
+{
+ // Look for/create Terminal Window for connection
+
+ Ui_ListenSession * Sess = NULL;
+ Ui_ListenSession * S;
+ char Title[80];
+ int i = 0;
+
+ if (TermMode == MDI)
+ {
+ // See if an old session can be reused
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ S = _sessions.at(i);
+
+ if ((S->SessionType & Listen) && S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+
+ // Create a window if none found, else reuse old
+
+ if (Sess == NULL)
+ {
+ Sess = newWindow((QObject *)mythis, Listen, "");
+ }
+ }
+ else
+ {
+ // Single or Tabbed - look for free session
+
+
+ for (i = 0; i < _sessions.size(); ++i)
+ {
+ S = _sessions.at(i);
+
+ if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+
+ if (Sess == NULL)
+ {
+ // Clear connection
+
+ return NULL;
+ }
+ }
+
+ if (Sess)
+ {
+ sprintf(Title, "Connected to %s", AX25Sess->corrcall);
+
+ if (TermMode == MDI)
+ {
+ Sess->setWindowTitle(Title);
+ }
+ else if (TermMode == Tabbed)
+ {
+ tabWidget->setTabText(i, AX25Sess->corrcall);
+ tabWidget->tabBar()->setTabTextColor(i, newTabText);
+ }
+ else if (TermMode == Single)
+ mythis->setWindowTitle(Title);
+
+ AX25Sess->port = 0;
+ AX25Sess->Sess = Sess; // Crosslink AGW and Term Sessions
+ AX25Sess->PID = 240;;
+
+ Sess->KISSSession = AX25Sess;
+
+ setMenus(true);
+
+ if (ConnectBeep)
+ myBeep(ConnectBeep);
+
+ // Send CText if defined
+
+ if (listenCText[0])
+ SendtoAX25(Sess->KISSSession, (unsigned char *)listenCText, (int)strlen(listenCText));
+ }
+ return Sess;
+}
+
+
+extern "C" void AX25_disc(TAX25Port * AX25Sess, Byte mode)
+{
+ char Msg[128];
+ int Len = 0;
+ Ui_ListenSession * Sess = (Ui_ListenSession *)AX25Sess->Sess;
+
+ if (AX25Sess->status == STAT_TRY_LINK)
+ {
+ // Connect failed
+
+ Len = sprintf(Msg, "Connection to %s failed\r", AX25Sess->corrcall);
+ }
+ else
+ {
+ switch (mode)
+ {
+ case MODE_OTHER:
+ case MODE_OUR:
+
+ Len = sprintf(Msg, "Disconnected from %s\r", AX25Sess->corrcall);
+ break;
+
+ case MODE_RETRY:
+
+ Len = sprintf(Msg, "Disconnected from %s - Retry count exceeded\r", AX25Sess->corrcall);
+ break;
+
+ };
+ }
+
+ SendtoTerm(Sess, Msg, Len);
+ ClearSessLabel(Sess);
+ Sess->KISSSession = NULL;
+ AX25Sess->Sess = 0;
+
+ setMenus(0);
+};
+
+int QtTermTCP::openSerialPort()
+{
+ if (m_serial && m_serial->isOpen())
+ {
+ m_serial->close();
+ }
+
+ m_serial = nullptr;
+ m_serial = new QSerialPort(this);
+
+ m_serial->setPortName(SerialPort);
+ m_serial->setBaudRate(KISSBAUD);
+
+ if (m_serial->open(QIODevice::ReadWrite))
+ {
+ int i;
+ connect(m_serial, &QSerialPort::readyRead, this, &QtTermTCP::readSerialData);
+ // connect(m_serial, &QSerialPort::errorOccurred, this, &QtTermTCP::handleError);
+
+ KISSConnected = 1;
+ KISSConnecting = 0;
+
+ Status3->setText("KISS Connected");
+ actHost[18]->setEnabled(1); // Enable KISS Connect Line
+
+ KISS_add_stream(m_serial);
+
+ // Attach a Monitor Window if available
+
+ Ui_ListenSession * Sess = NULL;
+ Ui_ListenSession * S;
+
+ if (TermMode == MDI)
+ {
+ // See if an old session can be reused
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ S = _sessions.at(i);
+
+ // for (Ui_ListenSession * S: _sessions)
+ // {
+ if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+
+ // Create a window if none found, else reuse old
+
+ if (Sess == NULL)
+ {
+ Sess = newWindow((QObject *)mythis, Mon, "");
+ }
+ }
+ else if (TermMode == Tabbed)
+ {
+ // Tabbed - look for free session
+
+ for (i = 8; i; i--)
+ {
+ S = _sessions.at(i);
+
+ if (S->clientSocket == NULL && S->KISSSession == NULL)
+ {
+ Sess = S;
+ break;
+ }
+ }
+ }
+ else if (TermMode == Single && (singlemodeFormat & Mon))
+ {
+ S = _sessions.at(0);
+
+ if (S->clientSocket == NULL && S->KISSSession == NULL)
+ Sess = S;
+
+ }
+
+ if (Sess)
+ {
+ KISSMonSess = Sess; // Flag as in use
+
+ if (TermMode == MDI)
+ Sess->setWindowTitle("KISS Monitor Window");
+ else if (TermMode == Tabbed)
+ tabWidget->setTabText(Sess->Tab, "KISS Mon");
+ else if (TermMode == Single)
+ mythis->setWindowTitle("KISS Monitor Window");
+
+ // if (TermMode == Single)
+ // {
+ // discAction->setEnabled(false);
+ // YAPPSend->setEnabled(false);
+ // connectMenu->setEnabled(false);
+ // }
+ }
+
+
+
+ return 1;
+ }
+ else
+ {
+ Status3->setText("KISS Open Failed");
+ KISSConnected = 0;
+ KISSConnecting = 0;
+ return 0;
+ }
+}
+
+
+
+void closeSerialPort()
+{
+ if (m_serial && m_serial->isOpen())
+ {
+ m_serial->close();
+ m_serial = nullptr;
+ }
+
+ m_serial = nullptr;
+
+ KISSConnected = 0;
+ KISSConnecting = 0;
+
+ Status3->setText("KISS Closed");
+ actHost[18]->setEnabled(0); // Enable KISS Connect Line
+}
+
+void QtTermTCP::readSerialData()
+{
+ int Read;
+ unsigned char Buffer[8192];
+
+ // read the data from the socket
+
+ m_serial->clearError();
+
+ Read = m_serial->read((char *)Buffer, 2047);
+
+ if (m_serial->error())
+ {
+ Debugprintf("Serial Read Error - RC %d Error %d", Read, m_serial->error());
+ closeSerialPort();
+ return;
+ }
+
+
+ while (Read > 0)
+ {
+ KISSDataReceived(m_serial, Buffer, Read);
+ Read = m_serial->read((char *)Buffer, 2047);
+ }
+}
+
+void QtTermTCP::handleError(QSerialPort::SerialPortError serialPortError)
+{
+ Debugprintf("Serial port Error %d", serialPortError);
+ closeSerialPort();
+}
+
+extern "C" void CheckUIFrame(unsigned char * path, string * data)
+{
+ // If we have KISS enabled and dest is UIDEST look for a KISS window in UI Mode
+
+ if (KISSSock == 0)
+ return;
+
+ char Dest[10];
+ char From[10];
+
+ Dest[ConvFromAX25(path, Dest)] = 0;
+ From[ConvFromAX25(&path[7], From)] = 0;
+
+ // ok, Find a Kiss Session with this Dest
+
+ Ui_ListenSession * Sess = NULL;
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ if (Sess->KISSMode == 1 && strcmp(Dest, Sess->UIDEST) == 0)
+ {
+ char Msg[512];
+ int Len;
+
+ data->Data[data->Length] = 0;
+
+ Len = sprintf(Msg, "%s:%s", From, data->Data);
+ SendtoTerm(Sess, Msg, Len);
+ return;
+ }
+ }
+
+}
+
+
+QColor QtTermTCP::setColor(QColor Colour)
+{
+ // const QColorDialog::ColorDialogOptions options = QFlag(colorDialogOptionsWidget->value());
+
+
+ QColor col = Colour;
+
+ QColorDialog dialog;
+ dialog.setCurrentColor(Colour);
+ dialog.setOption(QColorDialog::DontUseNativeDialog);
+
+ if (dialog.exec() == QColorDialog::Accepted)
+ col = QVariant(dialog.currentColor()).toString();
+
+
+ // const QColor color = QColorDialog::getColor(Qt::green, this, "Select Color", 0);
+
+ return col;
+}
+
+// Experimental Viewdata/Teletext/Prestel/CEEFAX Mode
+
+// Uses ideas and some code from
+
+/***************************************************************
+ * Name: wxTEDMain.cpp
+ * Purpose: Teletext editor Application Frame
+ * Author: Peter Kwan (peterk.vt80@gmail.com)
+ * Created: 2014-10-30
+ * Copyright: Peter Kwan
+ * License:
+ *
+ * Copyright (C) 2014-2022, Peter Kwan
+ *
+ * Permission to use, copy, modify, and distribute this software
+ * and its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and this
+ * permission notice and warranty disclaimer appear in supporting
+ * documentation, and that the name of the author not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ *
+ * The author disclaims all warranties with regard to this
+ * software, including all implied warranties of merchantability
+ * and fitness. In no event shall the author be liable for any
+ * special, indirect or consequential damages or any damages
+ * whatsoever resulting from loss of use, data or profits, whether
+ * in an action of contract, negligence or other tortious action,
+ * arising out of or in connection with the use or performance of
+ * this software.
+ *************************************************************************** **/
+
+
+
+int FontWidth = 16;
+int FontHeight = 16;
+
+bool isMosaic(char ch)
+{
+ ch &= 0x7f;
+ return (ch >= 0x20 && ch < 0x40) || ch >= 0x60;
+}
+
+
+void DecodeTeleText(Ui_ListenSession * Sess, char * page)
+{
+
+ // redraw the whole teletext page
+
+ QColor fg = Qt::white;
+ QColor bg = Qt::black;
+ QColor holdColour;
+ QColor holdfg = fg; // Colour for held graphic
+ int usehold = 0;
+ int sep = 0;
+
+ QPainter p(Sess->TTBitmap);
+
+ QSettings settings(GetConfPath(), QSettings::IniFormat);
+
+ //p.setFont(QFont("Courier", 14, QFont::Bold));
+
+ p.setFont(QFont(settings.value("FontFamily", "Courier New").value(), 14));
+
+ p.setPen(QPen(fg));
+
+ bool graphicsMode = false;
+ bool separated = false;
+ bool doubleHeight = false;
+ int skipnextrow = 99;
+ bool flashing = false;
+ bool hold = false;
+ char holdChar = 0;
+ char holdMode = 0;
+ Sess->timer.stop();
+
+ bool concealed = false;
+ char c;
+
+ fg = Qt::white;
+ bg = Qt::black;
+
+ char * ptr = page;
+
+ int col = 0;
+ int line = 0;
+
+ // XXXXXXXXTEEFAX %%# %%a %d %%b C %H:%M.%S
+
+ //p.drawText(0, 19, "P199 HAMFAX");
+
+
+ // interpret data, for now, line by line
+
+
+ while ((c = *(ptr++)))
+ {
+ char ch = c;
+
+ if (c == 0x11) // Curson On ??
+ continue;
+
+ if (c == 0x14) // Curson Off ??
+ continue;
+
+ if (c == 9) // Curson On ??
+ {
+ col++;
+ continue;
+ }
+
+ if (c == 0x0a)
+ {
+ line++;
+
+// if (doubleHeight)
+// line++;
+
+ if (line > 24)
+ line = 0;
+
+ continue;
+ }
+
+ if (c == 0x1e) // Cursor Home
+ {
+ line = col = 0;
+ c = 13; // So we reset page flags below
+ }
+
+ if (c == 12)
+ {
+ // Clear the page
+
+ Sess->TTBitmap->fill(Qt::black);
+ Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap));
+
+ line = col = 0;
+
+ c = 13; // So we reset page flags below
+ }
+
+ if (c == 13)
+ {
+ col = 0;
+
+ graphicsMode = false;
+ separated = false;
+ doubleHeight = false;
+ flashing = false;
+ hold = false;
+ holdChar = 0;
+ concealed = false;
+
+ fg = Qt::white;
+ bg = Qt::black;
+
+ continue; // Next line
+ }
+
+ if (c == 0x1b) // Esc
+ {
+ // I think the control char is displayed as it was before being actioned, sa save current state
+
+ holdfg = holdColour; // Colour if using held - may be changed before displaying
+ usehold = hold; // May be changed
+ sep = holdMode;
+
+ char echar = *(ptr++);
+
+ if (echar == 0)
+ {
+ // Esc pair spilt - wait for rest
+
+ Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap));
+ return;
+ }
+
+ switch (echar)
+ {
+ case '@':
+ fg = Qt::black;
+ concealed = false; // Side effect of colour. It cancels a conceal.
+ graphicsMode = false;
+// hold = false;
+
+ break;
+ case 'A':
+ fg = Qt::red;
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+
+ break;
+ case 'B':
+ fg = Qt::green;
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+ break;
+ case 'C':
+ fg = Qt::yellow;
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+ break;
+ case 'D':
+ fg = Qt::blue;
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+ break;
+ case 'E':
+ fg = Qt::magenta;
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+ break;
+ case 'F':
+ fg = Qt::cyan;
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+ break;
+ case 'G':
+ fg = Qt::white;
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+ break;
+ case 'H': // Flash
+ flashing = true;
+ Sess->timer.start(1000, Sess);
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+
+ break;
+
+ case 'I': // Steady
+ flashing = false;
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+
+ break;
+ //
+ case 'J': //ttxCodeEndBox:
+ case 'K': //ttxCodeStartBox:
+
+ concealed = false;
+ graphicsMode = false;
+ hold = false;
+
+ break;
+ case 'L': // Normal height
+ doubleHeight = false;
+ hold = false;
+ break;
+
+ case 'M': // Double height
+ doubleHeight = true;
+ skipnextrow = line + 1; // ETSI: row to ignore
+ hold = false;
+ holdChar = 0;
+ break;
+ case 'P': // Graphics black
+// concealed = false;
+ graphicsMode = true;
+ holdColour = fg = Qt::black;
+
+ break;
+ case 'Q': // Graphics red
+// concealed = false;
+ graphicsMode = true;
+ holdColour = fg = Qt::red;
+
+ break;
+ case 'R': // Graphics green
+// concealed = false;
+ graphicsMode = true;
+ holdColour = fg = Qt::green;
+
+ break;
+ case 'S': // Graphics yellow
+// concealed = false;
+ graphicsMode = true;
+ holdColour = fg = Qt::yellow;
+
+ break;
+ case 'T': // Graphics blue
+// concealed = false;
+ graphicsMode = true;
+ holdColour = fg = Qt::blue;
+
+ break;
+ case 'U': // Graphics magenta
+// concealed = false;
+ graphicsMode = true;
+ holdColour = fg = Qt::magenta;
+
+ break;
+ case 'V': // Graphics cyan
+// concealed = false;
+ graphicsMode = true;
+ holdColour = fg = Qt::cyan;
+
+ break;
+ case 'W': // Graphics white
+// concealed = false;
+ graphicsMode = true;
+ holdColour = fg = Qt::white;
+
+ break;
+
+ case 'X': // Conceal display
+
+ concealed = 1;
+ break;
+
+ case 'Y': // Contiguous graphics
+
+ separated = false;
+ break;
+
+ case 'Z': // Separated gfx
+
+ separated = true;
+ break;
+
+ case 0x5c: // Background black
+ bg = Qt::black;
+ break;
+
+ case 0x5d: // New background
+
+ bg = fg;
+ break;
+
+ case 0x5e: // Hold gfx
+
+ if (hold == 0)
+ {
+ hold = true;
+ holdColour = fg;
+ holdMode = separated;
+ }
+ break;
+
+ case 0x5f: // Non-hold gfx
+ hold = false;
+ break;
+
+ default:
+ echar++; // For testign
+ break;
+
+ } //end of esc case processing
+
+ if (usehold)
+ {
+ // We set sep and color for held char earlier
+
+ ch = holdChar; // Repeat held char
+ }
+ else
+ ch = 0x0; // Default is space
+
+
+ if (line > skipnextrow)
+ skipnextrow = 99;
+
+ if (line == skipnextrow)
+ {
+ line = line;
+ }
+ else
+ {
+ if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0))
+ {
+ p.fillRect(col * 15, line * 19, 15, 19, bg);
+
+ // if double height also draw background for next row
+
+ if (doubleHeight)
+ p.fillRect(col * 15, line * 19 + 19, 15, 19, bg);
+
+
+ if (sep)
+ {
+ if (ch & 1)
+ p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, holdfg);
+ if (ch & 2)
+ p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, holdfg);
+ if (ch & 4)
+ p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, holdfg);
+ if (ch & 8)
+ p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, holdfg);
+ if (ch & 16)
+ p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, holdfg);
+ if (ch & 32)
+ p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, holdfg);
+
+ }
+ else
+ {
+ if (ch & 1)
+ p.fillRect(col * 15, line * 19, 7, 6, holdfg);
+ if (ch & 2)
+ p.fillRect(col * 15 + 7, line * 19, 8, 6, holdfg);
+ if (ch & 4)
+ p.fillRect(col * 15, line * 19 + 6, 7, 6, holdfg);
+ if (ch & 8)
+ p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, holdfg);
+ if (ch & 16)
+ p.fillRect(col * 15, line * 19 + 12, 7, 7, holdfg);
+ if (ch & 32)
+ p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, holdfg);
+ }
+ }
+ }
+ col++;
+ }
+ else
+ {
+ // Not esc - so normal or graphics
+
+ if (ch < 0x20)
+ continue;
+
+ if (line > skipnextrow)
+ skipnextrow = 99;
+
+ if (line == skipnextrow)
+ {
+ line = line;
+ }
+ else
+ {
+ if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0))
+ {
+ p.fillRect(col * 15, line * 19, 15, 19, bg);
+
+ if (doubleHeight)
+ p.fillRect(col * 15, line * 19 + 19, 15, 19, bg);
+
+ p.setPen(QPen(fg));;
+
+ if (graphicsMode)
+ {
+ if (ch < 0x40)
+ ch -= 0x20;
+ else
+ if (ch >= 0x60)
+ ch -= 0x40;
+ else
+ goto isText;
+
+ holdChar = ch;
+
+ // Now have 00 - 3f
+
+
+ // C is bit mask bit posns are
+ // 01
+ // 23
+ // 45
+ // Char cell is 15 * 19 which is a bit asymetrical
+
+ // Chars are 20 - 3f and 60 to 7f but I cant see a logic to the mapping
+
+
+ if (separated)
+ {
+ if (ch & 1)
+ p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, fg);
+ if (ch & 2)
+ p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, fg);
+ if (ch & 4)
+ p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, fg);
+ if (ch & 8)
+ p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, fg);
+ if (ch & 16)
+ p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, fg);
+ if (ch & 32)
+ p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, fg);
+
+ }
+ else
+ {
+ if (ch & 1)
+ p.fillRect(col * 15, line * 19, 7, 6, fg);
+ if (ch & 2)
+ p.fillRect(col * 15 + 7, line * 19, 8, 6, fg);
+ if (ch & 4)
+ p.fillRect(col * 15, line * 19 + 6, 7, 6, fg);
+ if (ch & 8)
+ p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, fg);
+ if (ch & 16)
+ p.fillRect(col * 15, line * 19 + 12, 7, 7, fg);
+ if (ch & 32)
+ p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, fg);
+ }
+ }
+ else
+ {
+ // Just write char at current col and line
+
+ isText:
+ char s[5];
+ unsigned char su[5] = "";
+
+ // Some chars are in wrong char set
+
+ su[0] = ch;
+
+ if (ch == '_')
+ su[0] = '#';
+
+ else if (ch == 0x7e) // division
+ {
+ su[0] = 0xC3;
+ su[1] = 0xB7;
+ }
+ else if (ch == 0x5e) // up arrow
+ {
+ su[0] = 0xF0;
+ su[1] = 0x9F;
+ su[2] = 0xA0;
+ su[3] = 0x95;
+ }
+ else if (ch == 0x7f) // up arrow
+ {
+ su[0] = 0xE2;
+ su[1] = 0x96;
+ su[2] = 0x88;
+ }
+
+ memcpy(s, su, 5);
+
+// if (doubleHeight)
+ // p.drawText(col * 15, line * 19 + 25, s);
+ // else
+ // p.drawText(col * 15, line * 19 + 15, s);
+
+ // if double height draw normally then copy pixels each row of pixels to two scanlines (starting at the bottom)
+
+ if (doubleHeight)
+ {
+ int inscanline = line * 19 + 18;
+ int outscanline = line * 19 + 35;
+ unsigned char * inptr = Sess->TTBitmap->scanLine(inscanline);
+ unsigned char * outptr = Sess->TTBitmap->scanLine(outscanline);
+ int linelen = Sess->TTBitmap->bytesPerLine();
+ int charlen = linelen / 40; // bytes per char position
+
+ p.drawText(col * 15, line * 19 + 16, s);
+
+ inptr += col * charlen;
+ outptr += col * charlen;
+
+ for (int i = 0; i < 18; i++)
+ {
+ memcpy(outptr, inptr, charlen);
+ outptr -= linelen;
+ memcpy(outptr, inptr, charlen);
+
+ inptr -= linelen;
+ outptr -= linelen;
+
+ }
+ }
+ else
+ p.drawText(col * 15, line * 19 + 15, s);
+
+ }
+ }
+ }
+ col++;
+ }
+
+ if (col > 39)
+ {
+ col = 0;
+ line++;
+ if (line > 24)
+ line = 0;
+
+ graphicsMode = false;
+ separated = false;
+ doubleHeight = false;
+ flashing = false;
+ hold = false;
+ holdChar = 0;
+ concealed = false;
+
+ fg = Qt::white;
+ bg = Qt::black;
+ }
+ }
+ Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap));
+ return;
+
+ QFile file("D:/savepage.txt");
+ file.open(QIODevice::WriteOnly);
+ file.write(Sess->pageBuffer);
+ file.close();
+}
+
+
+void Ui_ListenSession::timerEvent(QTimerEvent *event)
+{
+ Ui_ListenSession * Sess = NULL;
+
+ // Used for flashing - resfresh window
+
+ for (int i = 0; i < _sessions.size(); ++i)
+ {
+ Sess = _sessions.at(i);
+
+ if (Sess->timer.timerId() == event->timerId())
+ {
+ if (Sess->TTActive)
+ {
+ Sess->TTFlashToggle ^= 1;
+
+ // if in Tabbed mode only refresh active tab
+
+ if (TermMode == Tabbed && Sess != ActiveSession)
+ return;
+
+ DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end
+ }
+ else
+ Sess->timer.stop();
+
+ return;
+ }
+ }
+ QWidget::timerEvent(event);
+}
+
diff --git a/QtTermTCP.cpp b/QtTermTCP.cpp
index 3edfb7b..9b03118 100644
--- a/QtTermTCP.cpp
+++ b/QtTermTCP.cpp
@@ -1,6 +1,6 @@
// Qt Version of BPQTermTCP
-#define VersionString "0.0.0.68"
+#define VersionString "0.0.0.69"
// .12 Save font weight
@@ -76,8 +76,17 @@
// .67 Add config Yapp RX Size dialog July 2023
// Fix 63 port montoring
-// .68 Remember last used host on restart Sept 2023
-// Add AutoConnect in Tabbed Mode
+// .68 Sept 2023
+
+// Remember last used host on restart
+// Add AutoConnect in Tabbed Mode
+// Fix auto copy when QtTerm not active window
+
+// .69 October 2023
+
+// Options related to sound alerts moved to a separte menu in Setup
+// Allow use of WAV files instead of Beep sound for sound alerts
+// Enable an alarm to be sounded when one of a list of words or phrases is received.
#define _CRT_SECURE_NO_WARNINGS
@@ -222,6 +231,17 @@ extern int AlertBeep;
extern int AlertFreq;
extern int AlertDuration;
extern int ConnectBeep;
+
+bool useBeep; // use wav files if not set
+
+extern int UseKeywords;
+extern QString KeyWordsFile;
+
+QString ConnectWAV("");
+QString AlertWAV("");
+QString BellWAV("");
+QString IntervalWAV("");
+
extern int MaxRXSize;
extern int AutoTeletext;
@@ -879,6 +899,7 @@ Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label)
Sess->TTActive = 0;
Sess->TTFlashToggle = 0;
Sess->pageBuffer[0] = 0;
+ Sess->Tab = 0;
_sessions.push_back(Sess);
@@ -1078,6 +1099,8 @@ QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent)
GetSettings();
+ GetKeyWordFile();
+
// Set background colours
sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);",
@@ -1340,9 +1363,15 @@ QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent)
setupMenu->addAction(singleAct2);
setupMenu->addAction(MDIAct);
setupMenu->addAction(tabbedAct);
+ setupMenu->addSeparator();
+ AlertAction = new QAction("Sound Alerts Setup", this);
+ setupMenu->addAction(AlertAction);
+ connect(AlertAction, SIGNAL(triggered()), this, SLOT(AlertSlot()));
+ AlertAction->setFont(*menufont);
setupMenu->addSeparator();
+
actFonts = new QAction("Terminal Font", this);
setupMenu->addAction(actFonts);
connect(actFonts, SIGNAL(triggered()), this, SLOT(doFonts()));
@@ -1358,6 +1387,8 @@ QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent)
connect(actColours, SIGNAL(triggered()), this, SLOT(doColours()));
actColours->setFont(*menufont);
+ setupMenu->addSeparator();
+
AGWAction = new QAction("AGW Setup", this);
setupMenu->addAction(AGWAction);
connect(AGWAction, SIGNAL(triggered()), this, SLOT(AGWSlot()));
@@ -1373,13 +1404,13 @@ QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent)
connect(KISSAction, SIGNAL(triggered()), this, SLOT(KISSSlot()));
KISSAction->setFont(*menufont);
+ setupMenu->addSeparator();
actChatMode = setupMenuLine(setupMenu, (char *)"Chat Terminal Mode (Send Keepalives)", this, ChatMode);
actAutoTeletext = setupMenuLine(setupMenu, (char *)"Auto switch to Teletext", this, AutoTeletext);
- actBells = setupMenuLine(setupMenu, (char *)"Enable Bells", this, Bells);
actStripLF = setupMenuLine(setupMenu, (char *)"Strip Line Feeds", this, StripLF);
- actIntervalBeep = setupMenuLine(setupMenu, (char *)"Beep after inactivity", this, AlertBeep);
- actConnectBeep = setupMenuLine(setupMenu, (char *)"Beep on inbound connect", this, ConnectBeep);
+
+ setupMenu->addSeparator();
setupMenu->addAction(new QAction("Interpret non-UTF8 input as:", this));
setupMenu->setFont(*menufont);
@@ -2871,7 +2902,7 @@ extern "C" void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * B
if (AlertInterval && (NOW - LastWrite) > AlertInterval)
{
if (AlertBeep)
- myBeep();
+ myBeep(&IntervalWAV);
}
// if tabbed and not active tab set tab label red
@@ -3011,7 +3042,7 @@ lineloop:
if (ptr)
{
*(ptr) = 32;
- myBeep();
+ myBeep(&BellWAV);
}
} while (ptr);
}
@@ -3321,8 +3352,18 @@ void GetSettings()
AutoTeletext = settings->value("AutoTeletext", 0).toInt();
Bells = settings->value("Bells", 1).toInt();
StripLF = settings->value("StripLF", 1).toInt();
+ useBeep = settings->value("useBeep", true).toBool();
AlertBeep = settings->value("AlertBeep", 1).toInt();
+ AlertInterval = settings->value("AlertInterval", 300).toInt();
ConnectBeep = settings->value("ConnectBeep", 1).toInt();
+ ConnectWAV = settings->value("ConnectWAV", "").toString().toUtf8();
+ AlertWAV = settings->value("AlertWAV", "").toString().toUtf8();
+ BellWAV = settings->value("BellWAV", "").toString().toUtf8();
+ IntervalWAV = settings->value("IntervalWAV", "").toString().toUtf8();
+
+ UseKeywords = settings->value("UseKeywords", 0).toInt();
+ KeyWordsFile = settings->value("KeyWordsFile", "keywords.sys").toString().toUtf8();
+
SavedHost = settings->value("CurrentHost", 0).toInt();
strcpy(YAPPPath, settings->value("YAPPPath", "").toString().toUtf8());
MaxRXSize = settings->value("MaxRXSize", 100000).toInt();
@@ -3495,7 +3536,17 @@ extern "C" void SaveSettings()
settings->setValue("Bells", Bells);
settings->setValue("StripLF", StripLF);
settings->setValue("AlertBeep", AlertBeep);
+ settings->setValue("useBeep", useBeep);
settings->setValue("ConnectBeep", ConnectBeep);
+ settings->setValue("BellWAV", BellWAV);
+ settings->setValue("AlertWAV", AlertWAV);
+ settings->setValue("IntervalWAV", IntervalWAV);
+ settings->setValue("ConnectWAV", ConnectWAV);
+
+ settings->setValue("UseKeywords", UseKeywords);
+ settings->setValue("KeyWordsFile", KeyWordsFile);
+
+ settings->setValue("AlertInterval", AlertInterval);
settings->setValue("CurrentHost", SavedHost);
settings->setValue("YAPPPath", YAPPPath);
@@ -3748,9 +3799,17 @@ void QtTermTCP::MyTimerSlot()
}
-extern "C" void myBeep()
+extern "C" void myBeep(QString * WAV)
{
- QApplication::beep();
+ if (useBeep)
+ {
+ QApplication::beep();
+ return;
+ }
+
+ // Using .wav files
+
+ QSound::play(*WAV);
}
void QtTermTCP::ListenSlot()
@@ -3770,6 +3829,7 @@ void QtTermTCP::AGWSlot()
}
Ui_Dialog * Dev;
+Ui_AlertDialog * Alert;
static Ui_KISSDialog * KISS;
static Ui_ColourDialog * COLOURS;
@@ -3923,6 +3983,113 @@ void QtTermTCP::KISSreject()
}
+void QtTermTCP::AlertSlot()
+{
+ // This runs the VARA Configuration dialog
+
+ Alert = new(Ui_AlertDialog);
+
+ QDialog UI;
+
+ Alert->setupUi(&UI);
+
+ UI.setFont(*menufont);
+
+ deviceUI = &UI;
+
+ Alert->Bells->setChecked(Bells);
+ Alert->InboundBeep->setChecked(ConnectBeep);
+ Alert->InactivityBeep->setChecked(AlertBeep);
+ Alert->Interval->setText(QString::number(AlertInterval));
+ Alert->KeywordBeep->setChecked(UseKeywords);
+ Alert->keywordFile->setText(KeyWordsFile);
+
+ Alert->useBeep->setChecked(useBeep);
+ Alert->useFiles->setChecked(!useBeep);
+
+ Alert->connectFile->setText(ConnectWAV);
+ Alert->bellsFile->setText(BellWAV);
+ Alert->intervalFile->setText(IntervalWAV);
+ Alert->keywordWAV->setText(AlertWAV);
+
+ QObject::connect(Alert->chooseInbound, SIGNAL(clicked()), this, SLOT(chooseInboundWAV()));
+ QObject::connect(Alert->chooseBells, SIGNAL(clicked()), this, SLOT(chooseBellsWAV()));
+ QObject::connect(Alert->chooseInterval, SIGNAL(clicked()), this, SLOT(chooseIntervalWAV()));
+ QObject::connect(Alert->chooseKeyAlert, SIGNAL(clicked()), this, SLOT(chooseAlertWAV()));
+
+ QObject::connect(Alert->okButton, SIGNAL(clicked()), this, SLOT(alertAccept()));
+ QObject::connect(Alert->cancelButton, SIGNAL(clicked()), this, SLOT(alertReject()));
+
+ UI.exec();
+}
+
+
+
+
+
+
+void QtTermTCP::chooseInboundWAV()
+{
+ ConnectWAV = QFileDialog::getOpenFileName(this,
+ tr("Select Wav"), "", tr("Sound Files (*.wav)"));
+
+ Alert->connectFile->setText(ConnectWAV);
+
+}
+
+void QtTermTCP::chooseBellsWAV()
+{
+ BellWAV = QFileDialog::getOpenFileName(this,
+ tr("Select Wav"), "", tr("Sound Files (*.wav)"));
+
+ Alert->bellsFile->setText(BellWAV);
+}
+
+void QtTermTCP::chooseIntervalWAV()
+{
+ IntervalWAV = QFileDialog::getOpenFileName(this,
+ tr("Select Wav"), "", tr("Sound Files (*.wav)"));
+
+ Alert->intervalFile->setText(IntervalWAV);
+}
+
+void QtTermTCP::chooseAlertWAV()
+{
+ AlertWAV = QFileDialog::getOpenFileName(this,
+ tr("Select Wav"), "", tr("Sound Files (*.wav)"));
+
+ Alert->keywordWAV->setText(AlertWAV);
+}
+
+void QtTermTCP::alertAccept()
+{
+ QVariant Q;
+
+ useBeep = Alert->useBeep->isChecked();
+
+ Bells = Alert->Bells->isChecked();
+ ConnectBeep = Alert->InboundBeep->isChecked();
+ AlertBeep = Alert->InactivityBeep->isChecked();
+ AlertInterval = Alert->Interval->text().toInt();
+
+ UseKeywords = Alert->KeywordBeep->isChecked();
+ KeyWordsFile = Alert->keywordFile->text();
+
+ ConnectWAV = Alert->connectFile->text();
+ BellWAV = Alert->bellsFile->text();
+ IntervalWAV = Alert->intervalFile->text();
+ AlertWAV = Alert->keywordWAV->text();
+
+ delete(Alert);
+ SaveSettings();
+ deviceUI->accept();
+}
+
+void QtTermTCP::alertReject()
+{
+ delete(Alert);
+ deviceUI->reject();
+}
@@ -4289,7 +4456,7 @@ void QtTermTCP::onNewConnection()
WritetoOutputWindow(Sess, (unsigned char *)Msg, (int)strlen(Msg));
if (ConnectBeep)
- myBeep();
+ myBeep(&ConnectWAV);
}
void QtTermTCP::onSocketStateChanged(QAbstractSocket::SocketState socketState)
@@ -6419,7 +6586,7 @@ extern "C" Ui_ListenSession * ax25IncommingConnect(TAX25Port * AX25Sess)
setMenus(true);
if (ConnectBeep)
- myBeep();
+ myBeep(&ConnectWAV);
// Send CText if defined
@@ -7198,34 +7365,37 @@ void DecodeTeleText(Ui_ListenSession * Sess, char * page)
// Just write char at current col and line
isText:
- char s[5] = " ";
+ char s[5];
+ unsigned char su[5] = "";
// Some chars are in wrong char set
- s[0] = ch;
+ su[0] = ch;
if (ch == '_')
- s[0] = '#';
+ su[0] = '#';
else if (ch == 0x7e) // division
{
- s[0] = 0xC3;
- s[1] = 0xB7;
+ su[0] = 0xC3;
+ su[1] = 0xB7;
}
else if (ch == 0x5e) // up arrow
{
- s[0] = 0xF0;
- s[1] = 0x9F;
- s[2] = 0xA0;
- s[3] = 0x95;
+ su[0] = 0xF0;
+ su[1] = 0x9F;
+ su[2] = 0xA0;
+ su[3] = 0x95;
}
else if (ch == 0x7f) // up arrow
{
- s[0] = 0xE2;
- s[1] = 0x96;
- s[2] = 0x88;
+ su[0] = 0xE2;
+ su[1] = 0x96;
+ su[2] = 0x88;
}
+ memcpy(s, su, 5);
+
// if (doubleHeight)
// p.drawText(col * 15, line * 19 + 25, s);
// else
diff --git a/QtTermTCP.h b/QtTermTCP.h
index b75d0e1..84bab07 100644
--- a/QtTermTCP.h
+++ b/QtTermTCP.h
@@ -2,7 +2,7 @@
#include
#include "ui_QtTermTCP.h"
-//#include "ui_AGWParams.h"
+#include "ui_AlertSetup.h"
#include "ui_YAPPRxSize.h"
#include "ui_ColourConfig.h"
#include "ui_VARAConfig.h"
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#define MAXHOSTS 16
#define MAXPORTS 64
@@ -152,6 +153,13 @@ private slots:
void KISSTimerSlot();
void ListenSlot();
void AGWSlot();
+ void AlertSlot();
+ void chooseInboundWAV();
+ void chooseBellsWAV();
+ void chooseIntervalWAV();
+ void chooseAlertWAV();
+ void alertAccept();
+ void alertReject();
void VARASlot();
void KISSSlot();
void deviceaccept();
@@ -248,6 +256,7 @@ private:
QAction *AGWAction;
QAction *VARAAction;
QAction *KISSAction;
+ QAction *AlertAction;
QAction *quitAction;
QList _sockets;
@@ -269,15 +278,19 @@ extern "C"
void setTraceOff(Ui_ListenSession * Sess);
void SetPortMonLine(int i, char * Text, int visible, int enabled);
void SaveSettings();
- void myBeep();
+ void myBeep(QString * WAV);
void YAPPSendFile(Ui_ListenSession * Sess, char * FN);
int SocketSend(Ui_ListenSession * Sess, char * Buffer, int len);
void SendTraceOptions(Ui_ListenSession * Sess);
int SocketFlush(Ui_ListenSession * Sess);
extern void mySleep(int ms);
extern void setTraceOff(Ui_ListenSession * Sess);
+ void GetKeyWordFile();
}
+extern QString ConnectWAV;
+extern QString BellWAV;
+extern QString AlertWAV;
char * strlop(char * buf, char delim);
extern "C" void setMenus(int State);
diff --git a/QtTermTCP.ini b/QtTermTCP.ini
deleted file mode 100644
index e30c210..0000000
--- a/QtTermTCP.ini
+++ /dev/null
@@ -1,123 +0,0 @@
-[General]
-HostParams0=nottm.g8bpq.net|8011|gm8bpq|password|5 1 1 0 1 0 0 1\r|Pogo4
-geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\xb6\0\0\0w\0\0\x4J\0\0\x3.\0\0\0\xb6\0\0\0w\0\0\x4J\0\0\x3.\0\0\0\0\0\0\0\0\x5\0\0\0\0\xb6\0\0\0w\0\0\x4J\0\0\x3.)
-HostParams1=192.168.1.63|8011|john|password||Pogo2
-windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\x3\x95\0\0\x2\xa2\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x3\0\0\0\x1\0\0\0\x16\0m\0\x61\0i\0n\0T\0o\0o\0l\0\x62\0\x61\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)
-HostParams2=127.0.0.1|8011|john|password|1 1 1 0 1 0 0 1\r|
-HostParams3=192.168.1.44|8011|john|password|1 1 1 0 1 0 0 1\r|Pogo4
-HostParams4=127.0.0.1|8021|john|password|c000000100000006 1 1 0 1 0 0 1\r|LinBPQ
-HostParams5=192.168.1.14|8011|john|password|c00000010000002e 1 1 0 1 0 0 1\r|
-HostParams6=127.0.0.1|8121|john|password|3 1 1 0 1 0 0 1\r|CB
-HostParams7=|0||||
-HostParams8=|0||||
-HostParams9=|0||||
-HostParams10=|0||||
-HostParams11=|0||||
-HostParams12=|0||||
-HostParams13=|0||||
-HostParams14=|0||||
-HostParams15=|0||||
-Split=58
-ChatMode=1
-AutoTeletext=1
-Bells=1
-StripLF=1
-AlertBeep=1
-ConnectBeep=1
-CurrentHost=3 2 3 2 0 0 0 0 0 0
-YAPPPath=
-listenPort=8015
-listenEnable=1
-listenCText=[PMS-2.3-C]\rHello>\r
-convUTF8=0
-PTT=None
-PTTBAUD=0
-PTTMode=1
-CATHex=1
-PTTOffString=
-PTTOnString=
-pttGPIOPin=17
-pttGPIOPinR=17
-CM108Addr=0xD8C:0x08
-HamLibPort=4532
-HamLibHost=127.0.0.1
-FLRigPort=12345
-FLRigHost=127.0.0.1
-AGWEnable=0
-AGWMonEnable=1
-AGWTermCall=G8BPQ
-AGWBeaconDest=
-AGWBeaconPath=
-AGWBeaconInterval=0
-AGWBeaconPorts=
-AGWBeaconText=
-AGWHost=127.0.0.1
-AGWPort=8001
-AGWPaclen=80
-AGWToCalls=G8BPQ-2, SWITCH,
-KISSEnable=0
-MYCALL=GM8BPQ
-KISSHost=127.0.0.1
-KISSMode=0
-KISSPort=8110
-KISSSerialPort=TCP
-KISSBAUD=19200
-VARAEnable=0
-VARATermCall=G8BPQ
-VARAHost=127.0.0.1
-VARAPort=8310
-VARAPath=C:\\VARA\\VARA.exe
-VARAHostHF=127.0.0.1
-VARAPortHF=8310
-VARAPathHF=C:\\VARA\\VARA.exe
-VARAHostFM=127.0.0.1
-VARAPortFM=8300
-VARAPathFM=C:\\VARA\\VARAFM.exe
-VARAHostSAT=127.0.0.1
-VARAPortSAT=8300
-VARAPathSAT=C:\\VARA\\VARASAT.exe
-VARA500=0
-VARA2300=1
-VARA2750=0
-VARAHF=1
-VARAFM=0
-VARASAT=0
-monBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0)
-monRxText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\xff\xff\0\0)
-monTxText=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\0\0\0\0\0\0)
-monOtherText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0)
-termBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0)
-outputText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\xff\xff\0\0)
-EchoText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0)
-WarningText=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\0\0\0\0\0\0)
-inputBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0)
-inputText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0)
-TermMode=2
-singlemodeFormat=3
-FontFamily=Courier
-PointSize=10
-Weight=50
-Sessions="4|1, 3, 57, 19, 633, 795|2, 2, 18, 42, 605, 833|1, 3, 20, 410, 611, 1201|3, 2, 32, 598, 623, 1389|"
-VARAInit="P2P SESSION,WINLINK SESSION"
-MaxRXSize=100000
-AutoConnect=1 1 1 0 0 0 0 0 0 0
-TabType=1 3 3 1 1 1 1 2 2 0
-
-[AX25_A]
-Retries=10
-Maxframe=4
-Paclen=128
-FrackTime=8
-IdleTime=180
-SlotTime=100
-Persist=128
-RespTime=1500
-TXFrmMode=1
-FrameCollector=6
-ExcludeCallsigns=
-ExcludeAPRSFrmType=
-KISSOptimization=0
-DynamicFrack=0
-BitRecovery=0
-IPOLL=80
-MyDigiCall=
diff --git a/QtTermTCP.pro b/QtTermTCP.pro
index 8719faf..aeb5e0b 100644
--- a/QtTermTCP.pro
+++ b/QtTermTCP.pro
@@ -3,6 +3,7 @@ QT += core gui
QT += network
QT += widgets
QT += serialport
+QT += multimedia
TARGET = QtTermTCP
@@ -41,7 +42,8 @@ FORMS += QtTermTCP.ui\
KISSConfig.ui \
ColourConfig.ui \
YAPPRxSize.ui \
- AGWConnect.ui
+ AGWConnect.ui \
+ AlertSetup.ui
RESOURCES += QtTermTCP.qrc
diff --git a/QtTermTCP.vcxproj b/QtTermTCP.vcxproj
index cc0795c..a911f95 100644
--- a/QtTermTCP.vcxproj
+++ b/QtTermTCP.vcxproj
@@ -22,7 +22,7 @@
{14F3B24E-473C-324E-A99D-3B679FCF5F67}
QtTermTCP
QtVS_v304
- 10.0.19041.0
+ 10.0.17763.0
10.0.19041.0
$(MSBuildProjectDirectory)\QtMsBuild
@@ -153,7 +153,7 @@
true
- shell32.lib;setupapi.lib;%(AdditionalDependencies)
+ shell32.lib;setupapi.lib;C:\Qt\5.14.2\msvc2017\lib\Qt5Multimedia.lib;%(AdditionalDependencies)
C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories)
-no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
true
@@ -279,7 +279,7 @@
true
- shell32.lib;setupapi.lib;%(AdditionalDependencies)
+ shell32.lib;setupapi.lib;%(AdditionalDependencies);C:\Qt\5.14.2\msvc2017\lib\Qt5Multimediad.lib
C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories)
-no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)
true
@@ -435,6 +435,7 @@
+
diff --git a/QtTermTCP.vcxproj.filters b/QtTermTCP.vcxproj.filters
index 9b27731..f0470d1 100644
--- a/QtTermTCP.vcxproj.filters
+++ b/QtTermTCP.vcxproj.filters
@@ -83,7 +83,7 @@
Header Files
- Header Files
+ Generated Files
@@ -95,28 +95,31 @@
-
+
Form Files
-
+
Form Files
-
+
Form Files
-
+
Form Files
-
+
Form Files
-
+
Form Files
-
+
Form Files
-
+
+ Form Files
+
+
Form Files
diff --git a/QtTermTCP.vcxproj.user b/QtTermTCP.vcxproj.user
index 0ccc4d8..765762b 100644
--- a/QtTermTCP.vcxproj.user
+++ b/QtTermTCP.vcxproj.user
@@ -1,6 +1,13 @@

-
+
+ ..\..\bpq32\CommonSource
+ WindowsLocalDebugger
+
+
+ ..\..\..\..\..\DevProgs\BPQ32
+ WindowsLocalDebugger
+
2022-05-19T07:28:47.9186341Z
@@ -8,15 +15,15 @@
2022-05-19T07:28:58.9302359Z
- 2023-08-17T19:39:18.4928536Z
+ 2023-10-09T09:12:25.3524292Z
- 2023-08-17T19:39:18.5988572Z
+ 2023-10-09T09:12:25.6116327Z
- 2023-08-17T19:39:18.2968480Z
+ 2023-10-09T09:12:25.0706672Z
- 2023-08-17T19:39:18.3758517Z
+ 2023-10-09T09:12:25.2024312Z
\ No newline at end of file
diff --git a/Ring.wav b/Ring.wav
new file mode 100644
index 0000000..ea59863
Binary files /dev/null and b/Ring.wav differ
diff --git a/TermTCPCommon.cpp b/TermTCPCommon.cpp
index 920a3ee..71953b0 100644
--- a/TermTCPCommon.cpp
+++ b/TermTCPCommon.cpp
@@ -56,12 +56,12 @@ TCHAR AlertFileName[256] = { 0 };
int ConnectBeep = TRUE;
int UseKeywords = TRUE;
-char KeyWordsName[MAX_PATH] = "Keywords.sys";
+QString KeyWordsFile = "Keywords.sys";
+
char ** KeyWords = NULL;
int NumberofKeyWords = 0;
-
// YAPP stuff
#define SOH 1
@@ -112,6 +112,97 @@ char * strlop(char * buf, char delim)
return ptr;
}
+#ifdef WIN32
+
+char * strcasestr(char *ch1, char *ch2)
+{
+ char *chN1, *chN2;
+ char *chNdx;
+ char *chRet = NULL;
+
+ chN1 = _strdup(ch1);
+ chN2 = _strdup(ch2);
+
+ if (chN1 && chN2)
+ {
+ chNdx = chN1;
+ while (*chNdx)
+ {
+ *chNdx = (char)tolower(*chNdx);
+ chNdx++;
+ }
+ chNdx = chN2;
+
+ while (*chNdx)
+ {
+ *chNdx = (char)tolower(*chNdx);
+ chNdx++;
+ }
+
+ chNdx = strstr(chN1, chN2);
+
+ if (chNdx)
+ chRet = ch1 + (chNdx - chN1);
+ }
+
+ free(chN1);
+ free(chN2);
+ return chRet;
+}
+
+#endif
+
+void GetKeyWordFile()
+{
+ DWORD FileSize;
+ char * ptr1, *ptr2;
+ char * KeyWordFile;
+
+ QFile file(KeyWordsFile);
+
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ if (UseKeywords) // Don't need to alert if not being used
+ {
+ QMessageBox msgBox;
+ msgBox.setText("Keyword File " + KeyWordsFile + " not found");
+ msgBox.exec();
+ }
+ return;
+ }
+
+ FileSize = file.size();
+
+ KeyWordFile = (char *)malloc(FileSize + 1);
+
+ file.read(KeyWordFile, FileSize);
+
+ file.close();
+
+ KeyWordFile[FileSize] = 0;
+
+ ptr1 = KeyWordFile;
+
+ while (ptr1)
+ {
+ if (*ptr1 == '\n') ptr1++;
+
+ ptr2 = strtok_s(NULL, "\r\n", &ptr1);
+ if (ptr2)
+ {
+ if (*ptr2 != '#')
+ {
+ KeyWords = (char **)realloc(KeyWords, (++NumberofKeyWords + 1) * 4);
+ KeyWords[NumberofKeyWords] = ptr2;
+ }
+ }
+ else
+ break;
+ }
+}
+
+
+
int CheckKeyWord(char * Word, char * Msg)
{
char * ptr1 = Msg, *ptr2;
@@ -119,7 +210,7 @@ int CheckKeyWord(char * Word, char * Msg)
while (*ptr1) // Stop at end
{
- ptr2 = strstr(ptr1, Word);
+ ptr2 = strcasestr(ptr1, Word);
if (ptr2 == NULL)
return FALSE; // OK
@@ -140,21 +231,16 @@ int CheckKeyWord(char * Word, char * Msg)
int CheckKeyWords(UCHAR * 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))
+ if (CheckKeyWord(KeyWords[i], (char *)Msg))
{
-// Beep(660, 250);
+ myBeep(&AlertWAV);
return TRUE; // Alert
}
}
diff --git a/debug/moc_predefs.h b/debug/moc_predefs.h
index 8247e15..b857b2e 100644
--- a/debug/moc_predefs.h
+++ b/debug/moc_predefs.h
@@ -1,7 +1,7 @@
#define _MSC_EXTENSIONS
#define _INTEGRAL_MAX_BITS 64
#define _MSC_VER 1916
-#define _MSC_FULL_VER 191627043
+#define _MSC_FULL_VER 191627045
#define _MSC_BUILD 0
#define _WIN32
#define _M_IX86 600
diff --git a/ding.wav b/ding.wav
new file mode 100644
index 0000000..5331129
Binary files /dev/null and b/ding.wav differ
diff --git a/enc_temp_folder/5aa81bc33ffd093ff53c1c62422a77/QtTermTCP.h b/enc_temp_folder/5aa81bc33ffd093ff53c1c62422a77/QtTermTCP.h
new file mode 100644
index 0000000..7b08e46
--- /dev/null
+++ b/enc_temp_folder/5aa81bc33ffd093ff53c1c62422a77/QtTermTCP.h
@@ -0,0 +1,297 @@
+#pragma once
+
+#include
+#include "ui_QtTermTCP.h"
+#include "ui_AlertSetup.h"
+#include "ui_YAPPRxSize.h"
+#include "ui_ColourConfig.h"
+#include "ui_VARAConfig.h"
+#include "ui_KISSConfig.h"
+#include "QTextEdit"
+#include "QSplitter"
+#include "QLineEdit"
+#include "QTcpSocket"
+#include
+#include
+#include "QThread"
+#include "QTcpServer"
+#include "QMdiArea"
+#include
+#include "QMessageBox"
+#include "QTimer"
+#include "QSettings"
+#include "QThread"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#define MAXHOSTS 16
+#define MAXPORTS 64
+
+QT_BEGIN_NAMESPACE
+class QComboBox;
+class QLabel;
+class QLineEdit;
+class QPushButton;
+class QTcpSocket;
+class QNetworkSession;
+
+class myTcpSocket : public QTcpSocket
+{
+public:
+ QWidget * Sess;
+};
+
+
+class Ui_ListenSession : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit Ui_ListenSession(QWidget *Parent = 0) : QMainWindow(Parent) {}
+ ~Ui_ListenSession();
+
+ int SessionType; // Type Mask - Term, Mon, Listen
+ int CurrentWidth;
+ int CurrentHeight; // Saved so can be restored after Cascade
+
+ QTextEdit *termWindow;
+ QTextEdit *monWindow;
+ QLineEdit *inputWindow;
+ QLabel * TTLabel;
+
+ myTcpSocket *clientSocket;
+
+ QAction * actActivate; // From active Windows menu
+
+ char * KbdStack[50];
+ int StackIndex;
+
+ QMdiSubWindow *sw; // The MdiSubwindow is the container for this session
+
+ int InputMode;
+ int SlowTimer;
+ int MonData;
+
+ int OutputSaveLen;
+ char OutputSave[16384];
+
+ int MonSaveLen;
+ char MonSave[4096];
+
+ char PortMonString[2048]; // 64 ports 32 Bytes
+ uint64_t portmask;
+ int mtxparam;
+ int mcomparam;
+ int monUI;
+ int MonitorNODES;
+ int MonitorColour;
+ int CurrentHost;
+ int Tab; // Tab Index if Tabbed Mode
+ void * AGWSession; // Terinal sess - Need to cast to TAGWPort to use it
+ void * AGWMonSession;
+ void * KISSSession;
+ int KISSMode; // Connected or UI
+ char UIDEST[32];
+ char UIPATH[128];
+
+ // For Teletext Emulator
+
+ QImage * TTBitmap; // TT Image buffer
+ QDialog TTUI;
+
+ int TTActive;
+ int TTFlashToggle;
+ char pageBuffer[4096];
+ QBasicTimer timer;
+
+protected:
+
+ void timerEvent(QTimerEvent *event) override;
+
+private:
+
+
+
+private slots:
+
+};
+
+
+class QtTermTCP : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ QtTermTCP(QWidget *parent = NULL);
+ void closeEvent(QCloseEvent * event);
+ static void setFonts();
+ ~QtTermTCP();
+
+private slots:
+ void Disconnect();
+ void doYAPPSend();
+ void doYAPPSetRX();
+ void doYAPPSetSize();
+ void sizeaccept();
+ void sizereject();
+ void menuChecked();
+ void Connect();
+ void displayError(QAbstractSocket::SocketError socketError);
+ void readyRead();
+ void showContextMenu(const QPoint & point);
+ void autoConnectChecked();
+ void LreturnPressed(Ui_ListenSession * LUI);
+ void LDisconnect(Ui_ListenSession * LUI);
+ void SetupHosts();
+ void MyTimerSlot();
+ void KISSTimerSlot();
+ void ListenSlot();
+ void AGWSlot();
+ void AlertSlot();
+ void chooseInboundWAV();
+ void chooseBellsWAV();
+ void chooseIntervalWAV();
+ void chooseAlertWAV();
+ void alertAccept();
+ void alertReject();
+ void VARASlot();
+ void KISSSlot();
+ void deviceaccept();
+ void KISSaccept();
+ void KISSreject();
+ void devicereject();
+ void showContextMenuM(const QPoint &pt);
+ void showContextMenuT(const QPoint &pt);
+ void showContextMenuL();
+ void doQuit();
+ void onTEselectionChanged();
+ void onLEselectionChanged();
+ void setSplit();
+ void ClearScreen();
+ void setVDMode();
+ void showContextMenuMT(const QPoint & pt);
+ void showContextMenuMOnly(const QPoint & pt);
+ void onNewConnection();
+ void onSocketStateChanged(QAbstractSocket::SocketState socketState);
+ void updateWindowMenu();
+ void doNewTerm();
+ void doNewMon();
+ void doNewCombined();
+ void doCascade();
+ void actActivate();
+ void xon_mdiArea_changed();
+ void doFonts();
+ void doMFonts();
+ void ConnecttoVARA();
+ void VARATimer();
+ void AGWdisplayError(QAbstractSocket::SocketError socketError);
+ void AGWreadyRead();
+ void onAGWSocketStateChanged(QAbstractSocket::SocketState socketState);
+ void VARAdisplayError(QAbstractSocket::SocketError socketError);
+ void VARAreadyRead();
+ void onVARASocketStateChanged(QAbstractSocket::SocketState socketState);
+ void KISSdisplayError(QAbstractSocket::SocketError socketError);
+ void KISSreadyRead();
+ void onKISSSocketStateChanged(QAbstractSocket::SocketState socketState);
+ int openSerialPort();
+ void readSerialData();
+ void handleError(QSerialPort::SerialPortError serialPortError);
+ void doColours();
+ void ColourPressed();
+ void Colouraccept();
+ void Colourreject();
+ QColor setColor(QColor Colour);
+ void VARADatadisplayError(QAbstractSocket::SocketError socketError);
+ void VARADatareadyRead();
+ void onVARADataSocketStateChanged(QAbstractSocket::SocketState socketState);
+ void HAMLIBdisplayError(QAbstractSocket::SocketError socketError);
+ void HAMLIBreadyRead();
+ void onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState);
+ void ConnecttoHAMLIB();
+ void HAMLIBSetPTT(int PTTState);
+ void FLRigdisplayError(QAbstractSocket::SocketError socketError);
+ void FLRigreadyRead();
+ void onFLRigSocketStateChanged(QAbstractSocket::SocketState socketState);
+ void ConnecttoFLRig();
+ void FLRigSetPTT(int PTTState);
+ void CATChanged(bool State);
+ void PTTPortChanged(int Selected);
+ void OpenPTTPort();
+ void RadioPTT(bool PTTState);
+ void tabSelected(int);
+ void VARAHFChanged(bool state);
+ void VARAFMChanged(bool State);
+ void VARASATChanged(bool State);
+ void SetVARAParams();
+
+protected:
+ bool eventFilter(QObject* obj, QEvent *event);
+
+private:
+
+ void ConnecttoAGW();
+
+ void AGWTimer();
+
+ Ui::QtTermTCPClass ui;
+
+ QMenu *hostsubMenu;
+
+ QAction *closeAct;
+ QAction *closeAllAct;
+ QAction *tileAct;
+ QAction *cascadeAct;
+ QAction *nextAct;
+ QAction *previousAct;
+ QAction *windowMenuSeparatorAct;
+ QAction *newTermAct;
+ QAction *newMonAct;
+ QAction *newCombinedAct;
+ QAction *AGWAction;
+ QAction *VARAAction;
+ QAction *KISSAction;
+ QAction *AlertAction;
+ QAction *quitAction;
+
+ QList _sockets;
+
+ QWidget *centralWidget;
+ void ConnecttoKISS();
+ void KISSTimer();
+};
+
+extern "C"
+{
+ void EncodeSettingsLine(int n, char * String);
+ void DecodeSettingsLine(int n, char * String);
+ void WritetoOutputWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int Len);
+ void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int *OutputSaveLen, char * OutputSave, QColor Colour);
+ void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int Len);
+ void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len);
+ void SendTraceOptions(Ui_ListenSession * LUI);
+ void setTraceOff(Ui_ListenSession * Sess);
+ void SetPortMonLine(int i, char * Text, int visible, int enabled);
+ void SaveSettings();
+ void myBeep(QString * WAV);
+ void YAPPSendFile(Ui_ListenSession * Sess, char * FN);
+ int SocketSend(Ui_ListenSession * Sess, char * Buffer, int len);
+ void SendTraceOptions(Ui_ListenSession * Sess);
+ int SocketFlush(Ui_ListenSession * Sess);
+ extern void mySleep(int ms);
+ extern void setTraceOff(Ui_ListenSession * Sess);
+ void GetKeyWordFile();
+}
+
+extern QString ConnectWAV;
+extern QString BellWAV;
+extern QString AlertWAV;
+
+char * strlop(char * buf, char delim);
+extern "C" void setMenus(int State);
+void Send_AGW_Ds_Frame(void * AGW);
diff --git a/enc_temp_folder/7a76876058568f76dfb2539c1a2c2b/TermTCPCommon.cpp b/enc_temp_folder/7a76876058568f76dfb2539c1a2c2b/TermTCPCommon.cpp
new file mode 100644
index 0000000..113602a
--- /dev/null
+++ b/enc_temp_folder/7a76876058568f76dfb2539c1a2c2b/TermTCPCommon.cpp
@@ -0,0 +1,1197 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "QtTermTCP.h"
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#define TRUE 1
+#define FALSE 0
+#define UCHAR unsigned char
+#define MAX_PATH 256
+#define WCHAR char
+
+#ifndef WIN32
+#define strtok_s strtok_r
+#endif
+
+
+typedef unsigned long DWORD;
+typedef int BOOL;
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+
+#define MAXHOSTS 16
+
+#define TCHAR char
+
+void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len);
+int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len);
+void SetPortMonLine(int i, char * Text, int visible, int enabled);
+void AGW_AX25_data_in(void * Sess, UCHAR * data, int Len);
+int checkUTF8(unsigned char * Msg, int Len, unsigned char * out);
+void DoTermResize(Ui_ListenSession * Sess);
+void DecodeTeleText(Ui_ListenSession * Sess, char * page);
+
+int Bells = TRUE;
+int StripLF = FALSE;
+int LogMonitor = FALSE;
+int LogOutput = FALSE;
+int SendDisconnected = TRUE;
+int ChatMode = TRUE;
+int AutoTeletext = 1;
+
+int MonPorts = 1;
+int ListenOn = FALSE;
+
+time_t LastWrite = 0xffffffff;
+int AlertInterval = 300;
+int AlertBeep = TRUE;
+int AlertFreq = 600;
+int AlertDuration = 250;
+TCHAR AlertFileName[256] = { 0 };
+int ConnectBeep = TRUE;
+int UseKeywords = TRUE;
+
+QString KeyWordsFile = "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
+
+#define YAPPTX 32768 // Sending YAPP file
+
+int MaxRXSize = 100000;
+char BaseDir[256] = "";
+
+unsigned char InputBuffer[1024];
+
+char YAPPPath[MAX_PATH] = ""; // Path for saving YAPP Files
+
+int paclen = 128;
+
+int InputLen; // Data we have already = Offset of end of an incomplete packet;
+
+unsigned char * 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[200]; // Filename from YAPP Header
+
+unsigned char SavedData[8192]; // Max receive is 4096 is should never get more that 8k
+int SaveLen = 0;
+
+void YAPPSendData(Ui_ListenSession * Sess);
+
+
+char * strlop(char * buf, char delim)
+{
+ // Terminate buf at delim, and return rest of string
+
+ char * ptr = strchr(buf, delim);
+
+ if (ptr == NULL) return NULL;
+
+ *(ptr)++ = 0;
+
+ return ptr;
+}
+
+void GetKeyWordFile()
+{
+ DWORD FileSize;
+ char * ptr1, *ptr2;
+ char * KeyWordFile;
+
+ QFile file(KeyWordsFile);
+
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ if (UseKeywords) // Don't need to alert if not being used
+ {
+ QMessageBox msgBox;
+ msgBox.setText("Keyword File " + KeyWordsFile + " not found");
+ msgBox.exec();
+ }
+ return;
+ }
+
+ FileSize = file.size();
+
+ KeyWordFile = (char *)malloc(FileSize + 1);
+
+ file.read(KeyWordFile, FileSize);
+
+ file.close();
+
+ 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 = (char **)realloc(KeyWords, (++NumberofKeyWords + 1) * 4);
+ KeyWords[NumberofKeyWords] = ptr2;
+ }
+ }
+ else
+ break;
+ }
+}
+
+
+
+int CheckKeyWord(char * Word, char * Msg)
+{
+ char * ptr1 = Msg, *ptr2;
+ int len = (int)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
+}
+
+int CheckKeyWords(UCHAR * 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))
+ {
+ myBeep(&AlertWAV);
+ return TRUE; // Alert
+ }
+ }
+
+ return FALSE; // OK
+
+}
+
+
+void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len)
+{
+ int MonLen = 0;
+ unsigned char * ptr;
+ unsigned char * Buffptr;
+ unsigned char * FEptr = 0;
+
+ if (Sess->InputMode == 'Y') // Yapp
+ {
+ ProcessYAPPMessage(Sess, Buffer, len);
+ return;
+ }
+
+ // See if Teletext data
+
+ // We need to identify a viewdata frame. Seems to start
+
+ //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........
+ //00000170 0a 0a 0a 0a 0a 0a 0a 0a 11 0c 1b
+
+ // Page seems to start 1c
+
+ // After page get
+
+ //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........
+ // 0000049D 0a 0a 0a 0a 0a 0a 0a 0a 11 14 1b 44 1b 5d 1b 43 ........ ...D.].C
+ // 000004AD 53 65 6c 65 Sele
+ // 000004B1 63 74 20 69 74 65 6d 20 6f 72 1b 47 2a 70 61 67 ct item or .G*pag
+ // 000004C1 65 5f 20 3a 20 20 20 20 20 20 20 20 20 20 20 20 e_ :
+ // 000004D1 20 0d 09 09 09 09 09 09 09 09 09 09 09 09 09 09 ....... ........
+ // 000004E1 09 09 09 09 09 09 09 09 09 09 09 09 09 11
+
+ Buffer[len] = 0;
+
+ if (AutoTeletext && (Buffer[0] == 0x1e || Buffer[0] == 0x0c))
+ {
+ if (Sess->TTActive == 0)
+ {
+ Sess->TTActive = 1;
+ DoTermResize(Sess);
+ }
+ }
+
+ if (Sess->TTActive)
+ {
+ // Feed to Teletext code
+
+ // We need to decode a whole page. There is no obvious delimiter so process till data stops.
+ // Buffer is cleared when next input is sent
+
+ if (strlen(&Sess->pageBuffer[0] + len) > 4090)
+ Sess->pageBuffer[0] = 0; // Protect buffer
+
+ strcat(Sess->pageBuffer, (char *)Buffer);
+
+ DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end
+ return;
+ }
+
+
+
+ // mbstowcs(Buffer, BufferB, len);
+
+ // Look for MON delimiters (FF/FE)
+
+
+ Buffptr = Buffer;
+
+ if (Sess->MonData)
+ {
+ // Already in MON State
+
+ FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len);
+
+ if (!FEptr)
+ {
+ // no FE - so send all to monitor
+
+ WritetoMonWindow(Sess, Buffer, len);
+ return;
+ }
+
+ Sess->MonData = FALSE;
+
+ MonLen = FEptr - Buffptr; // Mon Data, Excluding the FE
+
+ WritetoMonWindow(Sess, Buffptr, MonLen);
+
+ Buffptr = ++FEptr; // Char following FE
+
+ if (++MonLen < len)
+ {
+ len -= MonLen;
+ goto MonLoop; // See if next in MON or Data
+ }
+
+ // Nothing Left
+
+ return;
+ }
+
+MonLoop:
+
+ ptr = (UCHAR *)memchr(Buffptr, 0xff, len);
+
+ if (ptr)
+ {
+ unsigned char telcmd[] = "\xff\xfb\x03\xff\xfb\x01";
+
+ // Try to trap connect to normal Telnet Port
+
+ if (memcmp(ptr, telcmd, 6) == 0)
+ return;
+
+ // 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);
+ WritetoOutputWindow(Sess, Buffptr, NormLen);
+ }
+
+ len -= NormLen;
+ Buffptr = ptr;
+ goto MonLoop;
+ }
+
+ if (ptr[1] == 0xff)
+ {
+ // Port Definition String
+
+ int NumberofPorts = atoi((char *)&ptr[2]);
+ char *p, *Context;
+ int i = 1;
+ TCHAR msg[80];
+ int portnum;
+ char delim[] = "|";
+ int m;
+
+ // Save for changes of Window
+
+ if (len < 2048)
+ memcpy(Sess->PortMonString, ptr, len);
+
+
+ // Remove old menu
+
+ for (i = 0; i < 65; i++)
+ {
+ SetPortMonLine(i, (char *)"", 0, 0);
+ }
+
+ p = strtok_s((char *)&ptr[2], delim, &Context);
+
+ while (NumberofPorts--)
+ {
+ p = strtok_s(NULL, delim, &Context);
+ if (p == NULL)
+ break;
+
+ m = portnum = atoi(p);
+ sprintf(msg, "Port %s", p);
+
+ if (m == 0)
+ m = 64;
+
+ if (Sess->portmask & (1ll << (m - 1)))
+ SetPortMonLine(portnum, msg, 1, 1);
+ else
+ SetPortMonLine(portnum, msg, 1, 0);
+ }
+ return;
+ }
+
+ MonLen = len; // in case no fe
+
+ Sess->MonData = 1;
+
+ FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len);
+
+ if (FEptr)
+ {
+ Sess->MonData = 0;
+
+ MonLen = FEptr + 1 - Buffptr; // MonLen includes FF and FE
+
+ WritetoMonWindow(Sess, Buffptr + 1, MonLen - 2);
+
+ len -= MonLen;
+ Buffptr += MonLen; // Char Following FE
+
+ if (len <= 0)
+ {
+ return;
+ }
+ goto MonLoop;
+ }
+ else
+ {
+ // No FE, so rest of buffer is MON Data
+
+ if (MonLen)
+ WritetoMonWindow(Sess, Buffptr + 1, MonLen - 1);
+ return;
+ }
+ }
+
+ // No FF, so must be session data
+
+ if (Sess->InputMode == 'Y') // Yapp
+ {
+ ProcessYAPPMessage(Sess, 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
+ {
+ char YAPPRR[2];
+
+ // Turn off monitoring
+
+ setTraceOff(Sess);
+
+ Sess->InputMode = 'Y';
+
+ YAPPRR[0] = ACK;
+ YAPPRR[1] = 1;
+
+ SocketFlush(Sess); // To give Monitor Msg time to be sent
+ mySleep(1000);
+ QueueMsg(Sess, YAPPRR, 2);
+
+ return;
+ }
+ // Check UTF8
+ {
+ CheckKeyWords(Buffptr, len);
+ WritetoOutputWindow(Sess, Buffptr, len);
+ }
+ Sess->SlowTimer = 0;
+ return;
+}
+
+extern myTcpSocket * VARASock;
+extern myTcpSocket * VARADataSock;
+extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len);
+
+int SendMsg(Ui_ListenSession * Sess, TCHAR * Buffer, int len)
+{
+ if (Sess->KISSSession)
+ {
+ // Send to ax.25 code
+
+ SendtoAX25(Sess->KISSSession, (unsigned char *)Buffer, len);
+ return len;
+ }
+ else if (Sess->AGWSession)
+ {
+ // Terminal is in AGWPE mode - send as AGW frame
+
+ AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Buffer, len);
+ return len;
+ }
+ else if (VARASock && VARASock->Sess == Sess)
+ {
+ VARADataSock->write(Buffer, len);
+ return len;
+ }
+
+ return SocketSend(Sess, Buffer, len);
+}
+
+
+
+void QueueMsg(Ui_ListenSession * Sess, char * Msg, int len)
+{
+ int Sent = SendMsg(Sess, Msg, len);
+
+ if (Sent != len)
+ Sent = 0;
+}
+
+int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len);
+
+int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len)
+{
+ // may have saved data
+
+ memcpy(&SavedData[SaveLen], Msg, Len);
+
+ SaveLen += Len;
+
+ while (SaveLen && Sess->InputMode == 'Y')
+ {
+ int Used = InnerProcessYAPPMessage(Sess, SavedData, SaveLen);
+
+ if (Used == 0)
+ return 0; // Waiting for more
+
+ SaveLen -= Used;
+
+ if (SaveLen)
+ memmove(SavedData, &SavedData[Used], SaveLen);
+ }
+ return 0;
+}
+
+extern int VARAEnable;
+
+int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len)
+{
+ int pktLen = Msg[1];
+ char Reply[2] = { ACK };
+ size_t NameLen, SizeLen, OptLen;
+ char * ptr;
+ int FileSize;
+ WCHAR MsgFile[MAX_PATH];
+ FILE * hFile;
+ char Mess[255];
+ int len;
+ UCHAR Buffer[2000];
+ struct stat STAT;
+
+ 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;
+
+ Sess->InputMode = 'Y';
+ QueueMsg(Sess, Mess, 2);
+
+ // Turn off monitoring
+
+ mySleep(1000); // To give YAPP Msg time to be sent
+
+ setTraceOff(Sess);
+
+ return Len;
+
+ case SOH:
+
+ // HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt)
+
+ // YAPPC has date/time in dos format
+
+ if (Len < Msg[1] + 1)
+ return 0; // Wait till we have it all
+
+ NameLen = strlen((char *)&Msg[2]);
+ strcpy(ARQFilename, (char *)&Msg[2]);
+
+ ptr = (char *)&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 && VARAEnable == 0)
+ {
+ Mess[0] = NAK;
+ Mess[1] = sprintf(&Mess[2], "File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize);
+ mySleep(1000); // To give YAPP Msg time to be sent
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+
+ len = sprintf((char *)Buffer, "YAPP File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+ }
+
+ // Check that Path is set
+
+ if (YAPPPath[0] == 0)
+ {
+ Mess[0] = NAK;
+ Mess[1] = sprintf(&Mess[2], "%s", "YAPP Receive directory not set");
+ mySleep(1000); // To give YAPP Msg time to be sent
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+ len = sprintf((char *)Buffer, "YAPP File Receive Failed - YAPP Receive directory not set\r");
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+ }
+
+ // Make sure file does not exist
+
+ sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename);
+
+ if (stat(MsgFile, &STAT) == 0)
+ {
+ FileSize = STAT.st_size;
+
+ Mess[0] = NAK;
+ Mess[1] = sprintf(&Mess[2], "%s", "File Already Exists");
+ mySleep(1000); // To give YAPP Msg time to be sent
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+ len = sprintf((char *)Buffer, "YAPP File Receive Failed - %s already exists\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+ }
+
+
+ MailBufferSize = FileSize;
+ MailBuffer = (UCHAR *)malloc(FileSize);
+ YAPPLen = 0;
+
+ if (YAPPDate) // If present use YAPPC
+ Reply[1] = ACK; //Receive_TPK
+ else
+ Reply[1] = 2; //Rcv_File
+
+ QueueMsg(Sess, Reply, 2);
+
+ len = sprintf((char *)Buffer, "YAPP Receving File %s size %d\r", ARQFilename, FileSize);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ 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(&Mess[2], "YAPPC Checksum Error");
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+
+ len = sprintf((char *)Buffer, "YAPPC Checksum Error on file %s\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+ return Len;
+ }
+ }
+
+ if ((YAPPLen) + pktLen > MailBufferSize)
+ {
+ // Too Big ??
+
+ Mess[0] = CAN;
+ Mess[1] = sprintf(&Mess[2], "YAPP Too much data received");
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+
+ len = sprintf((char *)Buffer, "YAPP Too much data received on file %s\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+ return Len;
+ }
+
+
+ memcpy(&MailBuffer[YAPPLen], &Msg[2], pktLen);
+ YAPPLen += pktLen;
+
+ if (YAPPDate)
+ ++pktLen; // Add Checksum
+
+// if (YAPPLen == MailBufferSize)
+// pktLen = pktLen;
+
+ return pktLen + 2;
+
+ case ETX:
+
+ // End Data
+
+ if (YAPPLen == MailBufferSize)
+ {
+ // All received
+
+ int Written = 0;
+
+ sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename);
+
+ hFile = fopen(MsgFile, "wb");
+
+ if (hFile)
+ {
+ Written = (int)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;
+ */
+ }
+ }
+
+
+ free(MailBuffer);
+ MailBufferSize = 0;
+ MailBuffer = 0;
+
+ if (Written != YAPPLen)
+ {
+ Mess[0] = CAN;
+ Mess[1] = sprintf(&Mess[2], "Failed to save YAPP File");
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+
+ len = sprintf((char *)Buffer, "Failed to save YAPP File %s\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+ }
+ }
+
+ Reply[1] = 3; //Ack_EOF
+ QueueMsg(Sess, Reply, 2);
+
+ len = sprintf((char *)Buffer, "Reception of file %s complete\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ return Len;
+
+ case EOT:
+
+ // End Session
+
+ Reply[1] = 4; // Ack_EOT
+ QueueMsg(Sess, Reply, 2);
+ SocketFlush(Sess);
+ Sess->InputMode = 0;
+
+ SendTraceOptions(Sess);
+ return Len;
+
+ case CAN:
+
+ // Abort
+
+ Mess[0] = ACK;
+ Mess[1] = 5; // CAN Ack
+ QueueMsg(Sess, Mess, 2);
+
+ if (MailBuffer)
+ {
+ free(MailBuffer);
+ MailBufferSize = 0;
+ MailBuffer = 0;
+ }
+
+ // May have an error message
+
+ len = Msg[1];
+
+ if (len)
+ {
+ len = sprintf((char *)Buffer, "YAPP Transfer cancelled - %s\r", &Msg[2]);
+ }
+ else
+ len = sprintf(Mess, "YAPP Transfer cancelled\r");
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ 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 = (int)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(Sess, Mess, len);
+
+ return Len;
+
+ case 2:
+
+ YAPPDate = 0; // Switch to Normal (No Checksum) Mode
+
+ case 6: // Send using YAPPC
+
+ // Start sending message
+
+ YAPPSendData(Sess);
+ return Len;
+
+ case 3:
+
+ // ACK EOF - Send EOT
+
+ Mess[0] = EOT;
+ Mess[1] = 1;
+ QueueMsg(Sess, Mess, 2);
+
+ return Len;
+
+ case 4:
+
+ // ACK EOT
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ len = sprintf((char *)Buffer, "File transfer complete\r");
+ WritetoOutputWindow(Sess, Buffer, len);
+
+
+ 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((char *)&Msg[4]);
+
+ YAPPLen += posn;
+ MailBufferSize -= posn;
+
+ YAPPSendData(Sess);
+ return Len;
+
+ }
+
+ // May have an error message
+
+ len = Msg[1];
+
+ if (len)
+ {
+ char ws[256];
+
+ Msg[len + 2] = 0;
+
+ strcpy(ws, (char *)&Msg[2]);
+
+ len = sprintf((char *)Buffer, "File rejected - %s\r", ws);
+ }
+ else
+ len = sprintf((char *)Buffer, "File rejected\r");
+
+ WritetoOutputWindow(Sess, Buffer, len);
+
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+
+ }
+
+ len = sprintf((char *)Buffer, "Unexpected message during YAPP Transfer. Transfer cancelled\r");
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+
+}
+
+void YAPPSendFile(Ui_ListenSession * Sess, WCHAR * FN)
+{
+ int FileSize = 0;
+ char MsgFile[MAX_PATH];
+ FILE * hFile;
+ struct stat STAT;
+ UCHAR Buffer[2000];
+ int Len;
+
+ strcpy(MsgFile, FN);
+
+ if (MsgFile[0] == 0)
+ {
+ Len = sprintf((char *)Buffer, "Filename missing\r");
+ WritetoOutputWindow(Sess, Buffer, Len);
+
+ SendTraceOptions(Sess);
+
+ 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;
+// long long ll;
+// SYSTEMTIME st;
+// WORD FatDate;
+// WORD FatTime;
+// struct tm TM;
+
+ strcpy(ARQFilename, MsgFile);
+
+ if (MailBuffer)
+ {
+ free(MailBuffer);
+ MailBufferSize = 0;
+ MailBuffer = 0;
+ }
+
+ MailBuffer = (UCHAR *)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(Sess, Mess, 2);
+ Sess->InputMode = 'Y';
+
+ Len = sprintf((char *)Buffer, "Sending File %s ...\r", FN);
+ WritetoOutputWindow(Sess, Buffer, Len);
+
+ return;
+ }
+ }
+
+ Len = sprintf((char *)Buffer, "File %s not found\r", FN);
+ WritetoOutputWindow(Sess, Buffer, Len);
+
+}
+
+void YAPPSendData(Ui_ListenSession * Sess)
+{
+ char Mess[258];
+
+ while (1)
+ {
+ int Left = MailBufferSize;
+
+ if (Left == 0)
+ {
+ // Finished - send End Data
+
+ Mess[0] = ETX;
+ Mess[1] = 1;
+
+ QueueMsg(Sess, 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 = (UCHAR *)&Mess[2];
+
+ i = Left;
+
+ while (i--)
+ Sum += *(uptr++);
+
+ *(uptr) = Sum;
+
+ Mess[0] = STX;
+ Mess[1] = Left;
+
+ QueueMsg(Sess, Mess, Left + 3);
+ }
+ else
+ {
+ Mess[0] = STX;
+ Mess[1] = Left;
+
+ QueueMsg(Sess, Mess, Left + 2);
+ }
+ }
+}
+
diff --git a/enc_temp_folder/9d787c8a093194efc45ae72cda5d644/TermTCPCommon.cpp b/enc_temp_folder/9d787c8a093194efc45ae72cda5d644/TermTCPCommon.cpp
new file mode 100644
index 0000000..440bfa5
--- /dev/null
+++ b/enc_temp_folder/9d787c8a093194efc45ae72cda5d644/TermTCPCommon.cpp
@@ -0,0 +1,1197 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "QtTermTCP.h"
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#define TRUE 1
+#define FALSE 0
+#define UCHAR unsigned char
+#define MAX_PATH 256
+#define WCHAR char
+
+#ifndef WIN32
+#define strtok_s strtok_r
+#endif
+
+
+typedef unsigned long DWORD;
+typedef int BOOL;
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+
+#define MAXHOSTS 16
+
+#define TCHAR char
+
+void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len);
+int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len);
+void SetPortMonLine(int i, char * Text, int visible, int enabled);
+void AGW_AX25_data_in(void * Sess, UCHAR * data, int Len);
+int checkUTF8(unsigned char * Msg, int Len, unsigned char * out);
+void DoTermResize(Ui_ListenSession * Sess);
+void DecodeTeleText(Ui_ListenSession * Sess, char * page);
+
+int Bells = TRUE;
+int StripLF = FALSE;
+int LogMonitor = FALSE;
+int LogOutput = FALSE;
+int SendDisconnected = TRUE;
+int ChatMode = TRUE;
+int AutoTeletext = 1;
+
+int MonPorts = 1;
+int ListenOn = FALSE;
+
+time_t LastWrite = 0xffffffff;
+int AlertInterval = 300;
+int AlertBeep = TRUE;
+int AlertFreq = 600;
+int AlertDuration = 250;
+TCHAR AlertFileName[256] = { 0 };
+int ConnectBeep = TRUE;
+int UseKeywords = TRUE;
+
+QString KeyWordsFile = "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
+
+#define YAPPTX 32768 // Sending YAPP file
+
+int MaxRXSize = 100000;
+char BaseDir[256] = "";
+
+unsigned char InputBuffer[1024];
+
+char YAPPPath[MAX_PATH] = ""; // Path for saving YAPP Files
+
+int paclen = 128;
+
+int InputLen; // Data we have already = Offset of end of an incomplete packet;
+
+unsigned char * 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[200]; // Filename from YAPP Header
+
+unsigned char SavedData[8192]; // Max receive is 4096 is should never get more that 8k
+int SaveLen = 0;
+
+void YAPPSendData(Ui_ListenSession * Sess);
+
+
+char * strlop(char * buf, char delim)
+{
+ // Terminate buf at delim, and return rest of string
+
+ char * ptr = strchr(buf, delim);
+
+ if (ptr == NULL) return NULL;
+
+ *(ptr)++ = 0;
+
+ return ptr;
+}
+
+void GetKeyWordFile()
+{
+ DWORD FileSize;
+ char * ptr1, *ptr2;
+ char * KeyWordFile;
+
+ QFile file(KeyWordsFile);
+
+ if (!file.open(QIODevice::ReadOnly))
+ {
+ if (UseKeywords) // Don't need to alert if not being used
+ {
+ QMessageBox msgBox;
+ msgBox.setText("Keyword File " + KeyWordsFile + " not found");
+ msgBox.exec();
+ }
+ return;
+ }
+
+ FileSize = file.size();
+
+ KeyWordFile = (char *)malloc(FileSize + 1);
+
+ file.read(KeyWordFile, FileSize);
+
+ file.close();
+
+ 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 = (char **)realloc(KeyWords, (++NumberofKeyWords + 1) * 4);
+ KeyWords[NumberofKeyWords] = ptr2;
+ }
+ }
+ else
+ break;
+ }
+}
+
+
+
+int CheckKeyWord(char * Word, char * Msg)
+{
+ char * ptr1 = Msg, *ptr2;
+ int len = (int)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
+}
+
+int CheckKeyWords(UCHAR * 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))
+ {
+ myBeep(&AlertWAV);
+ return TRUE; // Alert
+ }
+ }
+
+ return FALSE; // OK
+
+}
+
+
+void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len)
+{
+ int MonLen = 0;
+ unsigned char * ptr;
+ unsigned char * Buffptr;
+ unsigned char * FEptr = 0;
+
+ if (Sess->InputMode == 'Y') // Yapp
+ {
+ ProcessYAPPMessage(Sess, Buffer, len);
+ return;
+ }
+
+ // See if Teletext data
+
+ // We need to identify a viewdata frame. Seems to start
+
+ //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........
+ //00000170 0a 0a 0a 0a 0a 0a 0a 0a 11 0c 1b
+
+ // Page seems to start 1c
+
+ // After page get
+
+ //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........
+ // 0000049D 0a 0a 0a 0a 0a 0a 0a 0a 11 14 1b 44 1b 5d 1b 43 ........ ...D.].C
+ // 000004AD 53 65 6c 65 Sele
+ // 000004B1 63 74 20 69 74 65 6d 20 6f 72 1b 47 2a 70 61 67 ct item or .G*pag
+ // 000004C1 65 5f 20 3a 20 20 20 20 20 20 20 20 20 20 20 20 e_ :
+ // 000004D1 20 0d 09 09 09 09 09 09 09 09 09 09 09 09 09 09 ....... ........
+ // 000004E1 09 09 09 09 09 09 09 09 09 09 09 09 09 11
+
+ Buffer[len] = 0;
+
+ if (AutoTeletext && (Buffer[0] == 0x1e || Buffer[0] == 0x0c))
+ {
+ if (Sess->TTActive == 0)
+ {
+ Sess->TTActive = 1;
+ DoTermResize(Sess);
+ }
+ }
+
+ if (Sess->TTActive)
+ {
+ // Feed to Teletext code
+
+ // We need to decode a whole page. There is no obvious delimiter so process till data stops.
+ // Buffer is cleared when next input is sent
+
+ if (strlen(&Sess->pageBuffer[0] + len) > 4090)
+ Sess->pageBuffer[0] = 0; // Protect buffer
+
+ strcat(Sess->pageBuffer, (char *)Buffer);
+
+ DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end
+ return;
+ }
+
+
+
+ // mbstowcs(Buffer, BufferB, len);
+
+ // Look for MON delimiters (FF/FE)
+
+
+ Buffptr = Buffer;
+
+ if (Sess->MonData)
+ {
+ // Already in MON State
+
+ FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len);
+
+ if (!FEptr)
+ {
+ // no FE - so send all to monitor
+
+ WritetoMonWindow(Sess, Buffer, len);
+ return;
+ }
+
+ Sess->MonData = FALSE;
+
+ MonLen = FEptr - Buffptr; // Mon Data, Excluding the FE
+
+ WritetoMonWindow(Sess, Buffptr, MonLen);
+
+ Buffptr = ++FEptr; // Char following FE
+
+ if (++MonLen < len)
+ {
+ len -= MonLen;
+ goto MonLoop; // See if next in MON or Data
+ }
+
+ // Nothing Left
+
+ return;
+ }
+
+MonLoop:
+
+ ptr = (UCHAR *)memchr(Buffptr, 0xff, len);
+
+ if (ptr)
+ {
+ unsigned char telcmd[] = "\xff\xfb\x03\xff\xfb\x01";
+
+ // Try to trap connect to normal Telnet Port
+
+ if (memcmp(ptr, telcmd, 6) == 0)
+ return;
+
+ // 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);
+ WritetoOutputWindow(Sess, Buffptr, NormLen);
+ }
+
+ len -= NormLen;
+ Buffptr = ptr;
+ goto MonLoop;
+ }
+
+ if (ptr[1] == 0xff)
+ {
+ // Port Definition String
+
+ int NumberofPorts = atoi((char *)&ptr[2]);
+ char *p, *Context;
+ int i = 1;
+ TCHAR msg[80];
+ int portnum;
+ char delim[] = "|";
+ int m;
+
+ // Save for changes of Window
+
+ if (len < 2048)
+ memcpy(Sess->PortMonString, ptr, len);
+
+
+ // Remove old menu
+
+ for (i = 0; i < 65; i++)
+ {
+ SetPortMonLine(i, (char *)"", 0, 0);
+ }
+
+ p = strtok_s((char *)&ptr[2], delim, &Context);
+
+ while (NumberofPorts--)
+ {
+ p = strtok_s(NULL, delim, &Context);
+ if (p == NULL)
+ break;
+
+ m = portnum = atoi(p);
+ sprintf(msg, "Port %s", p);
+
+ if (m == 0)
+ m = 64;
+
+ if (Sess->portmask & (1ll << (m - 1)))
+ SetPortMonLine(portnum, msg, 1, 1);
+ else
+ SetPortMonLine(portnum, msg, 1, 0);
+ }
+ return;
+ }
+
+ MonLen = len; // in case no fe
+
+ Sess->MonData = 1;
+
+ FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len);
+
+ if (FEptr)
+ {
+ Sess->MonData = 0;
+
+ MonLen = FEptr + 1 - Buffptr; // MonLen includes FF and FE
+
+ WritetoMonWindow(Sess, Buffptr + 1, MonLen - 2);
+
+ len -= MonLen;
+ Buffptr += MonLen; // Char Following FE
+
+ if (len <= 0)
+ {
+ return;
+ }
+ goto MonLoop;
+ }
+ else
+ {
+ // No FE, so rest of buffer is MON Data
+
+ if (MonLen)
+ WritetoMonWindow(Sess, Buffptr + 1, MonLen - 1);
+ return;
+ }
+ }
+
+ // No FF, so must be session data
+
+ if (Sess->InputMode == 'Y') // Yapp
+ {
+ ProcessYAPPMessage(Sess, 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
+ {
+ char YAPPRR[2];
+
+ // Turn off monitoring
+
+ setTraceOff(Sess);
+
+ Sess->InputMode = 'Y';
+
+ YAPPRR[0] = ACK;
+ YAPPRR[1] = 1;
+
+ SocketFlush(Sess); // To give Monitor Msg time to be sent
+ mySleep(1000);
+ QueueMsg(Sess, YAPPRR, 2);
+
+ return;
+ }
+ // Check UTF8
+ {
+ CheckKeyWords(Buffptr, len);
+ WritetoOutputWindow(Sess, Buffptr, len);
+ }
+ Sess->SlowTimer = 0;
+ return;
+}
+
+extern myTcpSocket * VARASock;
+extern myTcpSocket * VARADataSock;
+extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len);
+
+int SendMsg(Ui_ListenSession * Sess, TCHAR * Buffer, int len)
+{
+ if (Sess->KISSSession)
+ {
+ // Send to ax.25 code
+
+ SendtoAX25(Sess->KISSSession, (unsigned char *)Buffer, len);
+ return len;
+ }
+ else if (Sess->AGWSession)
+ {
+ // Terminal is in AGWPE mode - send as AGW frame
+
+ AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Buffer, len);
+ return len;
+ }
+ else if (VARASock && VARASock->Sess == Sess)
+ {
+ VARADataSock->write(Buffer, len);
+ return len;
+ }
+
+ return SocketSend(Sess, Buffer, len);
+}
+
+
+
+void QueueMsg(Ui_ListenSession * Sess, char * Msg, int len)
+{
+ int Sent = SendMsg(Sess, Msg, len);
+
+ if (Sent != len)
+ Sent = 0;
+}
+
+int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len);
+
+int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len)
+{
+ // may have saved data
+
+ memcpy(&SavedData[SaveLen], Msg, Len);
+
+ SaveLen += Len;
+
+ while (SaveLen && Sess->InputMode == 'Y')
+ {
+ int Used = InnerProcessYAPPMessage(Sess, SavedData, SaveLen);
+
+ if (Used == 0)
+ return 0; // Waiting for more
+
+ SaveLen -= Used;
+
+ if (SaveLen)
+ memmove(SavedData, &SavedData[Used], SaveLen);
+ }
+ return 0;
+}
+
+extern int VARAEnable;
+
+int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len)
+{
+ int pktLen = Msg[1];
+ char Reply[2] = { ACK };
+ size_t NameLen, SizeLen, OptLen;
+ char * ptr;
+ int FileSize;
+ WCHAR MsgFile[MAX_PATH];
+ FILE * hFile;
+ char Mess[255];
+ int len;
+ UCHAR Buffer[2000];
+ struct stat STAT;
+
+ 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;
+
+ Sess->InputMode = 'Y';
+ QueueMsg(Sess, Mess, 2);
+
+ // Turn off monitoring
+
+ mySleep(1000); // To give YAPP Msg time to be sent
+
+ setTraceOff(Sess);
+
+ return Len;
+
+ case SOH:
+
+ // HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt)
+
+ // YAPPC has date/time in dos format
+
+ if (Len < Msg[1] + 1)
+ return 0; // Wait till we have it all
+
+ NameLen = strlen((char *)&Msg[2]);
+ strcpy(ARQFilename, (char *)&Msg[2]);
+
+ ptr = (char *)&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 && VARAEnable == 0)
+ {
+ Mess[0] = NAK;
+ Mess[1] = sprintf(&Mess[2], "File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize);
+ mySleep(1000); // To give YAPP Msg time to be sent
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+
+ len = sprintf((char *)Buffer, "YAPP File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+ }
+
+ // Check that Path is set
+
+ if (YAPPPath[0] == 0)
+ {
+ Mess[0] = NAK;
+ Mess[1] = sprintf(&Mess[2], "%s", "YAPP Receive directory not set");
+ mySleep(1000); // To give YAPP Msg time to be sent
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+ len = sprintf((char *)Buffer, "YAPP File Receive Failed - YAPP Receive directory not set\r");
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+ }
+
+ // Make sure file does not exist
+
+ sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename);
+
+ if (stat(MsgFile, &STAT) == 0)
+ {
+ FileSize = STAT.st_size;
+
+ Mess[0] = NAK;
+ Mess[1] = sprintf(&Mess[2], "%s", "File Already Exists");
+ mySleep(1000); // To give YAPP Msg time to be sent
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+ len = sprintf((char *)Buffer, "YAPP File Receive Failed - %s already exists\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+ }
+
+
+ MailBufferSize = FileSize;
+ MailBuffer = (UCHAR *)malloc(FileSize);
+ YAPPLen = 0;
+
+ if (YAPPDate) // If present use YAPPC
+ Reply[1] = ACK; //Receive_TPK
+ else
+ Reply[1] = 2; //Rcv_File
+
+ QueueMsg(Sess, Reply, 2);
+
+ len = sprintf((char *)Buffer, "YAPP Receving File %s size %d\r", ARQFilename, FileSize);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ 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(&Mess[2], "YAPPC Checksum Error");
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+
+ len = sprintf((char *)Buffer, "YAPPC Checksum Error on file %s\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+ return Len;
+ }
+ }
+
+ if ((YAPPLen) + pktLen > MailBufferSize)
+ {
+ // Too Big ??
+
+ Mess[0] = CAN;
+ Mess[1] = sprintf(&Mess[2], "YAPP Too much data received");
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+
+ len = sprintf((char *)Buffer, "YAPP Too much data received on file %s\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+ return Len;
+ }
+
+
+ memcpy(&MailBuffer[YAPPLen], &Msg[2], pktLen);
+ YAPPLen += pktLen;
+
+ if (YAPPDate)
+ ++pktLen; // Add Checksum
+
+// if (YAPPLen == MailBufferSize)
+// pktLen = pktLen;
+
+ return pktLen + 2;
+
+ case ETX:
+
+ // End Data
+
+ if (YAPPLen == MailBufferSize)
+ {
+ // All received
+
+ int Written = 0;
+
+ sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename);
+
+ hFile = fopen(MsgFile, "wb");
+
+ if (hFile)
+ {
+ Written = (int)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;
+ */
+ }
+ }
+
+
+ free(MailBuffer);
+ MailBufferSize = 0;
+ MailBuffer = 0;
+
+ if (Written != YAPPLen)
+ {
+ Mess[0] = CAN;
+ Mess[1] = sprintf(&Mess[2], "Failed to save YAPP File");
+ QueueMsg(Sess, Mess, Mess[1] + 2);
+
+ len = sprintf((char *)Buffer, "Failed to save YAPP File %s\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+ }
+ }
+
+ Reply[1] = 3; //Ack_EOF
+ QueueMsg(Sess, Reply, 2);
+
+ len = sprintf((char *)Buffer, "Reception of file %s complete\r", MsgFile);
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ return Len;
+
+ case EOT:
+
+ // End Session
+
+ Reply[1] = 4; // Ack_EOT
+ QueueMsg(Sess, Reply, 2);
+ SocketFlush(Sess);
+ Sess->InputMode = 0;
+
+ SendTraceOptions(Sess);
+ return Len;
+
+ case CAN:
+
+ // Abort
+
+ Mess[0] = ACK;
+ Mess[1] = 5; // CAN Ack
+ QueueMsg(Sess, Mess, 2);
+
+ if (MailBuffer)
+ {
+ free(MailBuffer);
+ MailBufferSize = 0;
+ MailBuffer = 0;
+ }
+
+ // May have an error message
+
+ len = Msg[1];
+
+ if (len)
+ {
+ len = sprintf((char *)Buffer, "YAPP Transfer cancelled - %s\r", &Msg[2]);
+ }
+ else
+ len = sprintf(Mess, "YAPP Transfer cancelled\r");
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ 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 = (int)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(Sess, Mess, len);
+
+ return Len;
+
+ case 2:
+
+ YAPPDate = 0; // Switch to Normal (No Checksum) Mode
+
+ case 6: // Send using YAPPC
+
+ // Start sending message
+
+ YAPPSendData(Sess);
+ return Len;
+
+ case 3:
+
+ // ACK EOF - Send EOT
+
+ Mess[0] = EOT;
+ Mess[1] = 1;
+ QueueMsg(Sess, Mess, 2);
+
+ return Len;
+
+ case 4:
+
+ // ACK EOT
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ len = sprintf((char *)Buffer, "File transfer complete\r");
+ WritetoOutputWindow(Sess, Buffer, len);
+
+
+ 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((char *)&Msg[4]);
+
+ YAPPLen += posn;
+ MailBufferSize -= posn;
+
+ YAPPSendData(Sess);
+ return Len;
+
+ }
+
+ // May have an error message
+
+ len = Msg[1];
+
+ if (len)
+ {
+ char ws[256];
+
+ Msg[len + 2] = 0;
+
+ strcpy(ws, (char *)&Msg[2]);
+
+ len = sprintf((char *)Buffer, "File rejected - %s\r", ws);
+ }
+ else
+ len = sprintf((char *)Buffer, "File rejected\r");
+
+ WritetoOutputWindow(Sess, Buffer, len);
+
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+
+ }
+
+ len = sprintf((char *)Buffer, "Unexpected message during YAPP Transfer. Transfer cancelled\r");
+ WritetoOutputWindow(Sess, Buffer, len);
+
+ Sess->InputMode = 0;
+ SendTraceOptions(Sess);
+
+ return Len;
+
+}
+
+void YAPPSendFile(Ui_ListenSession * Sess, WCHAR * FN)
+{
+ int FileSize = 0;
+ char MsgFile[MAX_PATH];
+ FILE * hFile;
+ struct stat STAT;
+ UCHAR Buffer[2000];
+ int Len;
+
+ strcpy(MsgFile, FN);
+
+ if (MsgFile[0] == 0)
+ {
+ Len = sprintf((char *)Buffer, "Filename missing\r");
+ WritetoOutputWindow(Sess, Buffer, Len);
+
+ SendTraceOptions(Sess);
+
+ 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;
+// long long ll;
+// SYSTEMTIME st;
+// WORD FatDate;
+// WORD FatTime;
+// struct tm TM;
+
+ strcpy(ARQFilename, MsgFile);
+
+ if (MailBuffer)
+ {
+ free(MailBuffer);
+ MailBufferSize = 0;
+ MailBuffer = 0;
+ }
+
+ MailBuffer = (UCHAR *)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(Sess, Mess, 2);
+ Sess->InputMode = 'Y';
+
+ Len = sprintf((char *)Buffer, "Sending File %s ...\r", FN);
+ WritetoOutputWindow(Sess, Buffer, Len);
+
+ return;
+ }
+ }
+
+ Len = sprintf((char *)Buffer, "File %s not found\r", FN);
+ WritetoOutputWindow(Sess, Buffer, Len);
+
+}
+
+void YAPPSendData(Ui_ListenSession * Sess)
+{
+ char Mess[258];
+
+ while (1)
+ {
+ int Left = MailBufferSize;
+
+ if (Left == 0)
+ {
+ // Finished - send End Data
+
+ Mess[0] = ETX;
+ Mess[1] = 1;
+
+ QueueMsg(Sess, 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 = (UCHAR *)&Mess[2];
+
+ i = Left;
+
+ while (i--)
+ Sum += *(uptr++);
+
+ *(uptr) = Sum;
+
+ Mess[0] = STX;
+ Mess[1] = Left;
+
+ QueueMsg(Sess, Mess, Left + 3);
+ }
+ else
+ {
+ Mess[0] = STX;
+ Mess[1] = Left;
+
+ QueueMsg(Sess, Mess, Left + 2);
+ }
+ }
+}
+
diff --git a/makeit b/makeit
index bdf2910..0d57f8d 100644
--- a/makeit
+++ b/makeit
@@ -1,10 +1,10 @@
-cp --preserve /mnt/Source/QT/QtTermTCP/*.cpp ./
-cp --preserve /mnt/Source/QT/QtTermTCP/*.c ./
-cp --preserve /mnt/Source/QT/QtTermTCP/*.h ./
-cp --preserve /mnt/Source/QT/QtTermTCP/*.ui ./
-cp --preserve /mnt/Source/QT/QtTermTCP/*.pro ./
-cp --preserve /mnt/Source/QT/QtTermTCP/*.qrc ./
-cp --preserve /mnt/Source/QT/QtTermTCP/*.ico ./
+cp --preserve /mnt/Source/QT/QtTermTCP2/*.cpp ./
+cp --preserve /mnt/Source/QT/QtTermTCP2/*.c ./
+cp --preserve /mnt/Source/QT/QtTermTCP2/*.h ./
+cp --preserve /mnt/Source/QT/QtTermTCP2/*.ui ./
+cp --preserve /mnt/Source/QT/QtTermTCP2/*.pro ./
+cp --preserve /mnt/Source/QT/QtTermTCP2/*.qrc ./
+cp --preserve /mnt/Source/QT/QtTermTCP2/*.ico ./
qmake
make -j4
diff --git a/release/moc_predefs.h b/release/moc_predefs.h
index 4c9c0c7..b1c49a8 100644
--- a/release/moc_predefs.h
+++ b/release/moc_predefs.h
@@ -1,7 +1,7 @@
#define _MSC_EXTENSIONS
#define _INTEGRAL_MAX_BITS 64
#define _MSC_VER 1916
-#define _MSC_FULL_VER 191627043
+#define _MSC_FULL_VER 191627045
#define _MSC_BUILD 0
#define _WIN32
#define _M_IX86 600