7865 lines
182 KiB
C++
7865 lines
182 KiB
C++
// 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",
|
||
¤tHost[0], ¤tHost[1], ¤tHost[2], ¤tHost[3], ¤tHost[4],
|
||
¤tHost[5], ¤tHost[6], ¤tHost[7], ¤tHost[8], ¤tHost[9]);
|
||
|
||
|
||
monBackground = settings->value("monBackground", QColor(255, 255, 255)).value<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, "<");
|
||
out += 4;
|
||
break;
|
||
|
||
case '>':
|
||
|
||
strcpy(out, ">");
|
||
out += 4;
|
||
break;
|
||
|
||
case '"':
|
||
|
||
strcpy(out, """);
|
||
out += 6;
|
||
break;
|
||
|
||
case '\'':
|
||
|
||
strcpy(out, "'");
|
||
out += 6;
|
||
break;
|
||
|
||
case '&':
|
||
|
||
strcpy(out, "&");
|
||
out += 5;
|
||
break;
|
||
|
||
default:
|
||
|
||
*(out++) = c;
|
||
}
|
||
c = *(in++);
|
||
}
|
||
|
||
*(out++) = 0;
|
||
return newstring;
|
||
}
|
||
|
||
void 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);
|
||
|
||
}
|
||
|