qttermtcp/QtTermTCP.cpp

7865 lines
182 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Qt Version of BPQTermTCP
#define VersionString "0.0.0.73"
// .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 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.
// .70 October 2023
// Include some .wav files in resources
// Add Test button to Alert setup dialog
// .71 October 2023
// Add option to use local time
// Fixes for Mac OS
// .72 November 2023
// Don't display "Enable Monitor" on startup
// .73 November 2023
// Raise RTS on KISS serial port
#define _CRT_SECURE_NO_WARNINGS
#define UNUSED(x) (void)(x)
#define USESERIAL
#include "QtTermTCP.h"
#include "TabDialog.h"
#include <time.h>
#include <QVBoxLayout>
#include <QListWidgetItem>
#include <QToolButton>
#include <QInputMethod>
#include "QTreeWidget"
#include <QToolBar>
#include <QLabel>
#include <QActionGroup>
#include <QtWidgets>
#include <QColor>
#ifdef USESERIAL
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#endif
#ifndef WIN32
#define strtok_s strtok_r
#endif
#include <fcntl.h>
#include <errno.h>
#ifndef WIN32
#include <unistd.h>
#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
extern int UseKeywords;
extern QString KeyWordsFile;
QString ConnectWAV("");
QString AlertWAV("");
QString BellWAV("");
QString IntervalWAV("");
extern int MaxRXSize;
extern int AutoTeletext;
// AGW Host Interface stuff
int AGWEnable = 0;
int AGWMonEnable = 0;
int AGWLocalTime = 0;
int AGWMonNodes = 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;
typedef struct AGWUser_t
{
QTcpSocket *socket;
unsigned char data_in[8192];
int data_in_len;
unsigned char AGW_frame_buf[512];
int Monitor;
int Monitor_raw;
Ui_ListenSession * MonSess; // Window for Monitor info
} AGWUser;
extern AGWUser *AGWUsers; // List of currently connected clients
void Send_AGW_m_Frame(QTcpSocket* socket);
QStringList AGWToCalls;
// KISS Interface
int KISSEnable = 0;
extern "C" int KISSMonEnable;
extern "C" int KISSLocalTime;
extern "C" int KISSMonNodes;
extern "C" int KISSListen;
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 = nullptr;
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 *EnableMonitor;
QAction *EnableMonLog;
QAction *MonLocalTime;
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<Ui_ListenSession *> _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 <QStandardPaths>
#include <sys/stat.h>
#include <sys/types.h>
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<QKeyEvent*>(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<QMouseEvent *> (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;
int sessNo = 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->mlocaltime = 0;
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;
Sess->LogMonitor = false;
Sess->monSpan = (char *) "<span style=white-space:pre>";
Sess->monLogfile = nullptr;
Sess->sessNo = sessNo++;
_sessions.append(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<QString>(),
settings->value("PointSize", 12).toInt(),
settings->value("Weight", 50).toInt());
#else
QFont font = QFont(settings.value("FontFamily", "Courier New").value<QString>(),
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;
}
QByteArray timeLoaded = QDateTime::currentDateTime().toString("yymmdd_hhmmss").toUtf8();
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();
GetKeyWordFile();
// 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<QString>(),
mysettings.value("MPointSize", 12).toInt(),
mysettings.value("MWeight", 50).toInt());
#else
menufont = new QFont(mysettings.value("MFontFamily", "Aerial").value<QString>(),
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);
QTabBar* tabBar = tabWidget->tabBar();
// QString style1 = "QTabWidget::tab-bar{left:0;}"; // for Mac
// tabWidget->setStyleSheet(style1);
QString style = "QTabBar::tab:selected{background-color: #d0d0d0;} QTabBar::tab:!selected{background-color: #f0f0f0;}";
tabBar->setStyleSheet(style);
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 app 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();
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()));
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);
setupMenu->addSeparator();
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);
setupMenu->addSeparator();
actChatMode = setupMenuLine(setupMenu, (char *)"Chat Terminal Mode (Send Keepalives)", this, ChatMode);
actAutoTeletext = setupMenuLine(setupMenu, (char *)"Auto switch to Teletext", this, AutoTeletext);
actStripLF = setupMenuLine(setupMenu, (char *)"Strip Line Feeds", this, StripLF);
setupMenu->addSeparator();
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"));
EnableMonitor = setupMenuLine(monitorMenu, (char *)"Enable Monitoring", this, 0);
EnableMonitor->setVisible(0);
EnableMonLog = setupMenuLine(monitorMenu, (char *)"Log to File", this, 0);
MonLocalTime = setupMenuLine(monitorMenu, (char *)"Use local time", this, 0);
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()));
// Place Listen Action in mac app menu, otherwise it doesn't appear
if (is_mac == true)
{
QMenu * app_menu = mymenuBar->addMenu("App Menu");
ListenAction->setMenuRole(QAction::ApplicationSpecificRole);
app_menu->addAction(ListenAction);
}
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;
// Get x coordinate of first tab (on Mac tabs are centre aligned)
QRect rect = tabWidget->tabBar()->geometry();
int left = rect.left();
int n = myPoint.y() - (Wrect.height() - Brect.height());
myPoint.setY(n);
n = myPoint.x() - left;
myPoint.setX(n);
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()));
menu.exec(tabWidget->mapToGlobal(point));
}
void QtTermTCP::autoConnectChecked()
{
QAction * Act = static_cast<QAction*>(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();
}
void FlashifNotActive()
{
if (!mythis->isActiveWindow())
QApplication::alert(mythis, 0);
}
// "Copy on select" Code
void QtTermTCP::onTEselectionChanged()
{
QTextEdit * x = static_cast<QTextEdit*>(QObject::sender());
if (isActiveWindow())
x->copy();
}
void QtTermTCP::onLEselectionChanged()
{
QLineEdit * x = static_cast<QLineEdit*>(QObject::sender());
if (isActiveWindow())
x->copy();
}
void QtTermTCP::setVDMode()
{
QAction * sender = static_cast<QAction*>(QObject::sender());
QTextEdit * window = static_cast<QTextEdit*>(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<QAction*>(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<QAction*>(QObject::sender());
QTextEdit * window = static_cast<QTextEdit*>(sender->parentWidget());
window->clear();
}
void QtTermTCP::showContextMenuMT(const QPoint &pt) // Term Window
{
// Monitor and Terminal (Term Half)
QTextEdit* sender = static_cast<QTextEdit*>(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<QTextEdit*>(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<QTextEdit*>(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<QLabel*>(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<QTextEdit*>(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
EnableMonLog->setChecked(Sess->LogMonitor);
if (AGWUsers && Sess == AGWUsers->MonSess) // AGW Monitor
{
for (int i = 0; i < 64; i++)
SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden
connectMenu->setEnabled(false);
MonTX->setVisible(0);
MonSup->setVisible(0);
MonUI->setVisible(0);
MonColour->setVisible(0);
EnableMonitor->setVisible(1);
EnableMonitor->setChecked(AGWMonEnable);
MonLocalTime->setChecked(Sess->mlocaltime);
MonNodes->setChecked(Sess->MonitorNODES);
}
else if (Sess == KISSMonSess) // KISS Monitor
{
for (int i = 0; i < 64; i++)
SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden
connectMenu->setEnabled(false);
MonTX->setVisible(0);
MonSup->setVisible(0);
MonUI->setVisible(0);
MonColour->setVisible(0);
EnableMonitor->setVisible(1);
EnableMonitor->setChecked(KISSMonEnable);
MonLocalTime->setChecked(Sess->mlocaltime);
MonNodes->setChecked(Sess->MonitorNODES);
}
else
{
EnableMonitor->setVisible(0);
MonTX->setVisible(1);
MonSup->setVisible(1);
MonUI->setVisible(1);
MonColour->setVisible(1);
}
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);
MonLocalTime->setChecked(Sess->mlocaltime);
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<QAction*>(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<QAction*>(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);
Sess->mlocaltime = (Sess->mtxparam >> 7);
Sess->mtxparam &= 1;
MonLocalTime->setChecked(Sess->mlocaltime);
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<QAction*>(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 == EnableMonitor)
ActiveSession->EnableMonitor = state;
else if (Act == EnableMonLog)
ActiveSession->LogMonitor = state;
else if (Act == MonLocalTime)
ActiveSession->mlocaltime = state;
else 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;
}
}
}
if (ActiveSession->clientSocket && ActiveSession->SessionType & Mon)
SendTraceOptions(ActiveSession);
else if (AGWUsers && ActiveSession == AGWUsers->MonSess)
{
AGWMonEnable = ActiveSession->EnableMonitor;
AGWLocalTime = ActiveSession->mlocaltime;
AGWMonNodes = ActiveSession->MonitorNODES;
Send_AGW_m_Frame((QTcpSocket*)ActiveSession->AGWSession);
}
else if (ActiveSession == KISSMonSess)
{
KISSLocalTime = ActiveSession->mlocaltime;
KISSMonEnable = ActiveSession->EnableMonitor;
KISSMonNodes = ActiveSession->MonitorNODES;
}
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<myTcpSocket*>(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<myTcpSocket*>(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(&IntervalWAV);
}
// Alert if QtTerm not active window (unless Mon window)
if((Sess->SessionType & Mon) == 0)
FlashifNotActive();
// 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(&BellWAV);
}
} 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;
}
void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg);
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 (Sess->LogMonitor)
WriteMonitorLog(Sess, 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", ":/PCBeep").toString().toUtf8();
AlertWAV = settings->value("AlertWAV", ":/PCBeep").toString().toUtf8();
BellWAV = settings->value("BellWAV", ":/PCBeep").toString().toUtf8();
IntervalWAV = settings->value("IntervalWAV", ":/PCBeep").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();
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();
AGWLocalTime = settings->value("AGWLocalTime", 0).toInt();
AGWMonNodes = settings->value("AGWMonNodes", 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();
KISSMonEnable = settings->value("KISSMonEnable", 1).toInt();
KISSLocalTime = settings->value("KISSLocalTime", 0).toInt();
KISSMonNodes = settings->value("KISSMonNodes", 0).toInt();
KISSListen = settings->value("KISSListen", 1).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",
&currentHost[0], &currentHost[1], &currentHost[2], &currentHost[3], &currentHost[4],
&currentHost[5], &currentHost[6], &currentHost[7], &currentHost[8], &currentHost[9]);
monBackground = settings->value("monBackground", QColor(255, 255, 255)).value<QColor>();
monRxText = settings->value("monRxText", QColor(0, 0, 255)).value<QColor>();
monTxText = settings->value("monTxText", QColor(255, 0, 0)).value<QColor>();
monOtherText = settings->value("monOtherText", QColor(0, 0, 0)).value<QColor>();
termBackground = settings->value("termBackground", QColor(255, 255, 255)).value<QColor>();
outputText = settings->value("outputText", QColor(0, 0, 255)).value<QColor>();
EchoText = settings->value("EchoText", QColor(0, 0, 0)).value<QColor>();
WarningText = settings->value("WarningText", QColor(255, 0, 0)).value<QColor>();
inputBackground = settings->value("inputBackground", QColor(255, 255, 255)).value<QColor>();
inputText = settings->value("inputText", QColor(0, 0, 0)).value<QColor>();
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("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);
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("AGWLocalTime", AGWLocalTime);
settings->setValue("AGWMonNodes", AGWMonNodes);
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("KISSMonEnable", KISSMonEnable);
settings->setValue("KISSLocalTime", KISSLocalTime);
settings->setValue("KISSMonNodes", KISSMonNodes);
settings->setValue("KISSListen", KISSListen);
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 <QCloseEvent>
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->monLogfile)
Sess->monLogfile->close();
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(QString * WAV)
{
if (useBeep)
{
QApplication::beep();
return;
}
// Using .wav files
// QSoundEffect effect;
// effect.setSource(QUrl::fromLocalFile(*WAV));
// effect.setLoopCount(1);
// effect.setVolume(1.0f);
// effect.play();
QSound::play(*WAV);
}
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<QSerialPortInfo> 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->KISSListen->setChecked(KISSListen);
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();
KISSListen = KISS->KISSListen->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->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->setCurrentText(ConnectWAV);
Alert->bellsFile->setCurrentText(BellWAV);
Alert->intervalFile->setCurrentText(IntervalWAV);
Alert->keywordWAV->setCurrentText(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->testBells, SIGNAL(clicked()), this, SLOT(testBellsWAV()));
QObject::connect(Alert->TestInbound, SIGNAL(clicked()), this, SLOT(testInboundWAV()));
QObject::connect(Alert->testInterval, SIGNAL(clicked()), this, SLOT(testIntervalWAV()));
QObject::connect(Alert->TestKeyAlert, SIGNAL(clicked()), this, SLOT(testAlertWAV()));
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->setCurrentText(ConnectWAV);
}
void QtTermTCP::chooseBellsWAV()
{
BellWAV = QFileDialog::getOpenFileName(this,
tr("Select Wav"), "", tr("Sound Files (*.wav)"));
Alert->bellsFile->setCurrentText(BellWAV);
}
void QtTermTCP::chooseIntervalWAV()
{
IntervalWAV = QFileDialog::getOpenFileName(this,
tr("Select Wav"), "", tr("Sound Files (*.wav)"));
Alert->intervalFile->setCurrentText(IntervalWAV);
}
void QtTermTCP::chooseAlertWAV()
{
AlertWAV = QFileDialog::getOpenFileName(this,
tr("Select Wav"), "", tr("Sound Files (*.wav)"));
Alert->keywordWAV->setCurrentText(AlertWAV);
}
void QtTermTCP::testInboundWAV()
{
QSound::play(Alert->connectFile->currentText());
}
void QtTermTCP::testBellsWAV()
{
QSound::play(Alert->bellsFile->currentText());
}
void QtTermTCP::testIntervalWAV()
{
QSound::play(Alert->intervalFile->currentText());
}
void QtTermTCP::testAlertWAV()
{
QSound::play(Alert->keywordWAV->currentText());
}
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->currentText();
BellWAV = Alert->bellsFile->currentText();
IntervalWAV = Alert->intervalFile->currentText();
AlertWAV = Alert->keywordWAV->currentText();
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(&ConnectWAV);
QApplication::alert(mythis, 0);
}
void QtTermTCP::onSocketStateChanged(QAbstractSocket::SocketState socketState)
{
myTcpSocket* sender = static_cast<myTcpSocket*>(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<QMdiSubWindow *> 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->mlocaltime << 7),
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<QAction*>(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
EnableMonLog->setChecked(Sess->LogMonitor);
if (AGWUsers && Sess == AGWUsers->MonSess) // AGW Monitor
{
for (int i = 0; i < 64; i++)
SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden
connectMenu->setEnabled(false);
MonTX->setVisible(0);
MonSup->setVisible(0);
MonUI->setVisible(0);
MonColour->setVisible(0);
EnableMonitor->setVisible(1);
EnableMonitor->setChecked(AGWMonEnable);
MonLocalTime->setChecked(Sess->mlocaltime);
MonNodes->setChecked(Sess->MonitorNODES);
}
else if (Sess == KISSMonSess) // KISS Monitor
{
for (int i = 0; i < 64; i++)
SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden
connectMenu->setEnabled(false);
MonTX->setVisible(0);
MonSup->setVisible(0);
MonUI->setVisible(0);
MonColour->setVisible(0);
EnableMonitor->setVisible(1);
EnableMonitor->setChecked(KISSMonEnable);
MonLocalTime->setChecked(Sess->mlocaltime);
MonNodes->setChecked(Sess->MonitorNODES);
}
else
{
EnableMonitor->setVisible(0);
MonTX->setVisible(1);
MonSup->setVisible(1);
MonUI->setVisible(1);
MonColour->setVisible(1);
}
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);
MonLocalTime->setChecked(Sess->mlocaltime);
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<myTcpSocket*>(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 VARA Connect from %s %s Mode\r\n", CallFrom, Mode);
}
else
{
sprintf(Title, "Connected to %s", CallFrom);
n = sprintf(Message, "Incoming VARA Connect 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);
if (ConnectBeep)
myBeep(&ConnectWAV);
if (listenCText[0])
VARADataSock->write(listenCText);
QApplication::alert(mythis, 0);
}
}
}
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<myTcpSocket*>(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<myTcpSocket*>(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<myTcpSocket*>(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<QTcpSocket*>(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<QTcpSocket*>(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[] = "<?xml version=\"1.0\"?>\r\n"
"<methodCall><methodName>%s</methodName>\r\n"
"%s"
"</methodCall>\r\n";
void QtTermTCP::FLRigSetPTT(int PTTState)
{
int Len;
char ReqBuf[512];
char SendBuff[512];
char ValueString[256] = "";
sprintf(ValueString, "<params><param><value><i4>%d</i4></value></param></params\r\n>", 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();
boolean rc = 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<myTcpSocket*>(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<myTcpSocket*>(QObject::sender());
QTcpSocket* sender = static_cast<QTcpSocket*>(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 && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess)
{
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 && S->AGWSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess)
{
Sess = S;
break;
}
}
}
else if (TermMode == Single && (singlemodeFormat & Mon))
{
S = _sessions.at(0);
if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess)
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");
Sess->mlocaltime = KISSLocalTime;
Sess->MonitorNODES = KISSMonNodes;
// 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 (Len < 10) // Suppressed NODES
return;
if (Msg[Len - 1] != '\r')
{
Msg[Len++] = '\r';
Msg[Len] = 0;
}
if (KISSMonSess)
WritetoMonWindow(KISSMonSess, (unsigned char *)Msg, Len);
}
extern "C" Ui_ListenSession * ax25IncomingConnect(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 KISS and Term Sessions
AX25Sess->PID = 240;;
Sess->KISSSession = AX25Sess;
setMenus(true);
if (ConnectBeep)
myBeep(&ConnectWAV);
QApplication::alert(mythis, 0);
// 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);
boolean ok = m_serial->setBaudRate(KISSBAUD);
if (m_serial->open(QIODevice::ReadWrite))
{
int i;
ok = m_serial->setRequestToSend(true);
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<QString>(), 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);
}
// Monitor Log FIle routines
char * doXMLTransparency(char * string)
{
// Make sure string doesn't contain forbidden XML chars (<>"'&)
char * newstring = (char *)malloc(5 * strlen(string) + 1); // If len is zero still need null terminator
char * in = string;
char * out = newstring;
char c;
c = *(in++);
while (c)
{
switch (c)
{
case '<':
strcpy(out, "&lt;");
out += 4;
break;
case '>':
strcpy(out, "&gt;");
out += 4;
break;
case '"':
strcpy(out, "&quot;");
out += 6;
break;
case '\'':
strcpy(out, "&apos;");
out += 6;
break;
case '&':
strcpy(out, "&amp;");
out += 5;
break;
default:
*(out++) = c;
}
c = *(in++);
}
*(out++) = 0;
return newstring;
}
void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg)
{
// Write as HTML to preserve formatting
char Line[512];
char * HTMLText;
if (Sess->monLogfile == nullptr)
{
QString FN = "QTTermMonLog" + timeLoaded + "_" + QString::number(Sess->sessNo) + ".html";
Sess->monLogfile = new QFile(FN);
if (Sess->monLogfile)
Sess->monLogfile->open(QIODevice::WriteOnly | QIODevice::Text);
else
return;
}
if (Msg[0] == 0x1b)
{
// Colour Escape
if (Msg[1] == 17)
Sess->monSpan = (char *)"<span style=\"color:blue; white-space:pre;font-family: monospace\">";// , monRxColour.data());
else
Sess->monSpan = (char *)"<span style=\"color:red; white-space:pre;font-family: monospace\">";// , monTxColour.data());
HTMLText = doXMLTransparency(&Msg[2]);
}
else
{
// Leave colour at last set value
HTMLText = doXMLTransparency(Msg);
}
sprintf(Line, "%s%s</span><br>\r\n", Sess->monSpan, HTMLText);
Sess->monLogfile->write(Line);
free(HTMLText);
}