// Qt Version of BPQTermTCP #define VersionString "0.0.0.63" // .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 #define _CRT_SECURE_NO_WARNINGS #define UNUSED(x) (void)(x) #define USESERIAL #include "QtTermTCP.h" #include "TabDialog.h" #include #include #include #include #include #include "QTreeWidget" #include #include #include #include #include #ifdef USESERIAL #include #include #endif #ifndef WIN32 #define strtok_s strtok_r #endif #include #include #ifndef WIN32 #include #endif #include "ax25.h" #define UNREFERENCED_PARAMETER(P) (P) void DecodeTeleText(Ui_ListenSession * Sess, char * text); char Host[MAXHOSTS + 1][100] = { "" }; int Port[MAXHOSTS + 1] = { 0 }; char UserName[MAXHOSTS + 1][80] = { "" }; char Password[MAXHOSTS + 1][80] = { "" }; char MonParams[MAXHOSTS + 1][80] = { "" }; char SessName[MAXHOSTS + 1][80] = { "" }; int ListenPort = 8015; // Session Type Equates #define Term 1 #define Mon 2 #define Listen 4 // Presentation - Single Window, MDI or Tabbed int TermMode = 0; #define Single 0 #define MDI 1 #define Tabbed 2 int singlemodeFormat = Mon + Term; char monStyleSheet[128] = "background-color: rgb(0,255,255)"; char termStyleSheet[128] = "background-color: rgb(255,0,255);"; char inputStyleSheet[128] = "color: rgb(255, 0, 0); background-color: rgb(255,255,0);"; QColor monBackground = qRgb(0, 255, 255); QColor monRxText = qRgb(0, 0, 255); QColor monTxText = qRgb(255, 0, 0); QColor monOtherText = qRgb(0, 0, 0); QColor termBackground = qRgb(255, 0, 255); QColor outputText = qRgb(0, 0, 0); QColor EchoText = qRgb(0, 0, 255); QColor WarningText = qRgb(255, 0, 0); QColor inputBackground = qRgb(255, 255, 0); QColor inputText = qRgb(0, 0, 255); // 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; extern int AutoTeletext; // AGW Host Interface stuff int AGWEnable = 0; int AGWMonEnable = 0; char AGWTermCall[12] = ""; char AGWBeaconDest[12] = ""; char AGWBeaconPath[80] = ""; int AGWBeaconInterval = 0; char AGWBeaconPorts[80]; char AGWBeaconMsg[260] = ""; char AGWHost[128] = "127.0.0.1"; int AGWPortNum = 8000; int AGWPaclen = 80; extern char * AGWPortList; extern myTcpSocket * AGWSock; QStringList AGWToCalls; // KISS Interface int KISSEnable = 0; char SerialPort[80] = ""; char KISSHost[128] = "127.0.0.1"; int KISSPortNum = 1000; int KISSBAUD = 19200; char MYCALL[32]; extern "C" UCHAR axMYCALL[7]; // Mycall in ax.25 int KISSMode = 0; // Connected (0) or UI (1) myTcpSocket * KISSSock; extern "C" void * KISSSockCopy[4]; int KISSConnected = 0; int KISSConnecting = 0; Ui_ListenSession * KISSMonSess; QSerialPort * m_serial = nullptr; // VARA Interface int VARAEnable = 0; char VARAHost[128] = "127.0.0.1"; char VARAHostHF[128] = "127.0.0.1"; char VARAHostFM[128] = "127.0.0.1"; char VARAHostSAT[128] = "127.0.0.1"; int VARAPortNum = 8000; int VARAPortHF = 8000; int VARAPortFM = 8000; int VARAPortSAT = 8000; char VARATermCall[12] = ""; char VARAPath[256] = ""; char VARAInit[256] = ""; char VARAPathHF[256] = ""; char VARAPathFM[256] = ""; char VARAPathSAT[256] = ""; int VARA500 = 0; int VARA2300 = 1; int VARA2750 = 0; int VARAHF = 1; int VARAFM = 0; int VARASAT = 0; myTcpSocket * VARASock; myTcpSocket * VARADataSock; int VARAConnected = 0; int VARAConnecting = 0; extern char YAPPPath[256]; void menuChecked(QAction * Act); // PTT Stuff #define PTTRTS 1 #define PTTDTR 2 #define PTTCAT 4 #define PTTCM108 8 #define PTTHAMLIB 16 #define PTTFLRIG 32 #ifdef USESERIAL QSerialPort * hPTTDevice = 0; #else #endif char PTTPort[80] = ""; // Port for Hardware PTT - may be same as control port. int PTTBAUD = 19200; int PTTMode = PTTRTS; // PTT Control Flags. char PTTOnString[128] = ""; char PTTOffString[128] = ""; int CATHex = 1; unsigned char PTTOnCmd[64]; int PTTOnCmdLen = 0; unsigned char PTTOffCmd[64]; int PTTOffCmdLen = 0; int pttGPIOPin = 17; // Default int pttGPIOPinR = 17; bool pttGPIOInvert = false; bool useGPIO = false; bool gotGPIO = false; int HamLibPort = 4532; char HamLibHost[32] = "192.168.1.14"; int FLRigPort = 12345; char FLRigHost[32] = "127.0.0.1"; char CM108Addr[80] = ""; int VID = 0; int PID = 0; // CM108 Code char * CM108Device = NULL; QProcess *process = NULL; void GetSettings(); // These widgets defined here as they are accessed from outside the framework QLabel * Status1; QLabel * Status2; QLabel * Status3; QLabel * Status4; QAction *actHost[19]; QAction *actSetup[16]; QAction * TabSingle = NULL; QAction * TabBoth = NULL; QAction * TabMon = NULL; QMenu *monitorMenu; QMenu * YAPPMenu; QMenu *connectMenu; QMenu *disconnectMenu; QAction *MonTX; QAction *MonSup; QAction *MonNodes; QAction *MonUI; QAction *MonColour; QAction *MonPort[33]; 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 *singleAct; QAction *singleAct2; QAction *MDIAct; QAction *tabbedAct; QAction *discAction; QFont * menufont; QMenu *windowMenu; QMenu *setupMenu; QAction *ListenAction; QTabWidget *tabWidget; QMdiArea *mdiArea; QWidget * mythis; QStatusBar * myStatusBar; QTcpServer * _server; QMenuBar *mymenuBar; QToolBar *toolBar; QToolButton * but1; QToolButton * but2; QToolButton * but3; QToolButton * but4; QToolButton * but5; QList _sessions; // Session Type Equates #define Term 1 #define Mon 2 #define Listen 4 int TabType[10] = { Term, Term + Mon, Term, Term, Term, Term, Mon, Mon, Mon }; int 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); #include #include #include void EncodeSettingsLine(int n, char * String) { sprintf(String, "%s|%d|%s|%s|%s|%s", Host[n], Port[n], UserName[n], Password[n], MonParams[n], SessName[n]); return; } // This is used for placing discAction in the preference menu #ifdef __APPLE__ bool is_mac = true; #else bool is_mac = false; #endif QString GetConfPath() { std::string conf_path = "QtTermTCP.ini"; // Default conf file stored alongside application. #ifdef __APPLE__ // Get configuration path for MacOS. // This will usually be placed in /Users/USER/Library/Application Support/QtTermTCP std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString(); conf_path = directory + "/QtTermTCP.ini"; mkdir(directory.c_str(), 0775); #endif return QString::fromUtf8(conf_path.c_str()); } void DecodeSettingsLine(int n, char * String) { char * Param = strdup(String); char * Rest; char * Save = Param; // for Free Rest = strlop(Param, '|'); if (Rest == NULL) return; strcpy(Host[n], Param); Param = Rest; Rest = strlop(Param, '|'); Port[n] = atoi(Param); Param = Rest; Rest = strlop(Param, '|'); strcpy(UserName[n], Param); Param = Rest; Rest = strlop(Param, '|'); strcpy(Password[n], Param); Param = Rest; Rest = strlop(Param, '|'); strcpy(MonParams[n], Param); if (Rest) strcpy(SessName[n], Rest); free(Save); return; } //#ifdef ANDROID //#define inputheight 60 //#else #define inputheight 25 //#endif extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len); void DoTermResize(Ui_ListenSession * Sess) { QRect r = Sess->rect(); int H, Mid, monHeight, termHeight, Width, Border = 3; Width = r.width(); H = r.height(); if (TermMode == Tabbed) { // H -= 20; Width -= 7; } else if (TermMode == Single) { Width -= 7; // H += 20; } if (Sess->SessionType == Listen || Sess->SessionType == Term) { // Term and Input // Calc Positions of window termHeight = H - (inputheight + 3 * Border); Sess->termWindow->setGeometry(QRect(Border, Border, Width, termHeight)); if (Sess->TTActive) { Sess->TTLabel->setGeometry(QRect(Border, Border, 600, 475)); // Sess->termWindow->setVisible(false); Sess->TTLabel->setVisible(true); } else { // Sess->termWindow->setVisible(true); Sess->TTLabel->setVisible(false); } Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); } else if (Sess->SessionType == (Term | Mon)) { // All 3 // Calc Positions of window Mid = (H * Split) / 100; monHeight = Mid - Border; termX = Mid; termHeight = H - Mid - (inputheight + 3 * Border); Sess->monWindow->setGeometry(QRect(Border, Border, Width, monHeight)); Sess->termWindow->setGeometry(QRect(Border, Mid + Border, Width, termHeight)); if (Sess->TTActive) { Sess->TTLabel->setGeometry(QRect(3, Mid + Border, 600, 475)); // Sess->termWindow->setVisible(false); Sess->TTLabel->setVisible(true); } else { // Sess->termWindow->setVisible(true); Sess->TTLabel->setVisible(false); } Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); } else { // Should just be Mon only Sess->monWindow->setGeometry(QRect(Border, Border, Width, H - 2 * Border)); } } bool QtTermTCP::eventFilter(QObject* obj, QEvent *event) { // See if from a Listening Session Ui_ListenSession * Sess; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); // Sess = _sessions.at(i); for (Ui_ListenSession * Sess : _sessions) // { if (Sess == NULL) continue; if (Sess == obj) { if (event->type() == QEvent::Close) { // Window closing // This only closed mon sessinos if (Sess->AGWMonSession) // AGWMonWindowClosing(Sess); AGWWindowClosing(Sess); if (Sess->AGWSession) AGWWindowClosing(Sess); if (Sess->clientSocket) { int loops = 100; Sess->clientSocket->disconnectFromHost(); while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState) QThread::msleep(10); } _sessions.removeOne(Sess); return QMainWindow::eventFilter(obj, event); } if (event->type() == QEvent::Resize) { DoTermResize(Sess); } } if (Sess->inputWindow == obj) { if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast(event); int key = keyEvent->key(); Qt::KeyboardModifiers modifier = keyEvent->modifiers(); if (modifier == Qt::ControlModifier) { char Msg[] = "\0\r"; if (key == Qt::Key_BracketLeft) Msg[0] = 0x1b; if (key == Qt::Key_Z) Msg[0] = 0x1a; else if (key == Qt::Key_C) Msg[0] = 3; else if (key == Qt::Key_D) Msg[0] = 4; if (Msg[0]) { if (Sess->KISSSession) { // Send to ax.25 code SendtoAX25(Sess->KISSSession, (unsigned char *)Msg, (int)strlen(Msg)); } else if (Sess->AGWSession) { // Terminal is in AGWPE mode - send as AGW frame AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Msg, (int)strlen(Msg)); } else if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) { Sess->clientSocket->write(Msg); } return true; } } if (key == Qt::Key_Up) { // Scroll up if (Sess->KbdStack[Sess->StackIndex] == NULL) return true; // If anything typed, stack part command QByteArray stringData = Sess->inputWindow->text().toUtf8(); if (stringData.length() && Sess->StackIndex == 0) { if (Sess->KbdStack[49]) free(Sess->KbdStack[49]); for (int i = 48; i >= 0; i--) { Sess->KbdStack[i + 1] = Sess->KbdStack[i]; } Sess->KbdStack[0] = qstrdup(stringData.data()); Sess->StackIndex++; } Sess->inputWindow->setText(Sess->KbdStack[Sess->StackIndex]); Sess->inputWindow->cursorForward(strlen(Sess->KbdStack[Sess->StackIndex])); Sess->StackIndex++; if (Sess->StackIndex == 50) Sess->StackIndex = 49; return true; } else if (key == Qt::Key_Down) { // Scroll down if (Sess->StackIndex == 0) { Sess->inputWindow->setText(""); return true; } Sess->StackIndex--; if (Sess->StackIndex && Sess->KbdStack[Sess->StackIndex - 1]) { Sess->inputWindow->setText(Sess->KbdStack[Sess->StackIndex - 1]); Sess->inputWindow->cursorForward(strlen(Sess->KbdStack[Sess->StackIndex - 1])); } else Sess->inputWindow->setText(""); return true; } else if (key == Qt::Key_Return || key == Qt::Key_Enter) { LreturnPressed(Sess); return true; } return false; } if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *k = static_cast (event); // Paste on Right Click if (k->button() == Qt::RightButton) { Sess->inputWindow->paste(); return true; } return QMainWindow::eventFilter(obj, event); } } } return QMainWindow::eventFilter(obj, event); } QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State) { QAction * Act = new QAction(Label, parent); if (Menu) Menu->addAction(Act); Act->setCheckable(true); if (State) Act->setChecked(true); parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked())); Act->setFont(*menufont); return Act; } // This now creates all window types - Term, Mon, Combined, Listen int xCount = 0; Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label) { Ui_ListenSession * Sess = new(Ui_ListenSession); // Need to explicity initialise on Qt4 Sess->termWindow = NULL; Sess->monWindow = NULL; Sess->inputWindow = NULL; for (int i = 0; i < 50; i++) Sess->KbdStack[i] = NULL; Sess->StackIndex = 0; Sess->InputMode = 0; Sess->SlowTimer = 0; Sess->MonData = 0; Sess->OutputSaveLen = 0; Sess->MonSaveLen = 0; Sess->PortMonString[0] = 0; Sess->portmask = 0; Sess->portmask = 1; Sess->mtxparam = 1; Sess->mcomparam = 1; Sess->monUI = 0; Sess->MonitorNODES = 0; Sess->MonitorColour = 1; Sess->CurrentHost = 0; Sess->SessionType = Type; Sess->clientSocket = NULL; Sess->AGWSession = NULL; Sess->AGWMonSession = NULL; Sess->KISSSession = NULL; Sess->KISSMode = 0; Sess->TTActive = 0; Sess->TTFlashToggle = 0; Sess->pageBuffer[0] = 0; _sessions.push_back(Sess); // Sess->TT = new Ui_TeleTextDialog(); // Sess->TT->setupUi(&Sess->TTUI); // Sess->TTUI.show(); // Sess->TTUI.raise(); // Sess->TTUI.activateWindow(); // Sess->setObjectName(QString::fromUtf8("Sess")); if (TermMode == MDI) { Sess->sw = mdiArea->addSubWindow(Sess); // Sess->installEventFilter(parent); Sess->sw->resize(800, 600); } else if (TermMode == Tabbed) { Sess->Tab = xCount++; if (Type == Mon) tabWidget->addTab(Sess, "Monitor"); else tabWidget->addTab(Sess, Label); } Sess->installEventFilter(parent); QSettings settings(GetConfPath(), QSettings::IniFormat); #ifdef ANDROID QFont font = QFont(settings->value("FontFamily", "Driod Sans Mono").value(), settings->value("PointSize", 12).toInt(), settings->value("Weight", 50).toInt()); #else QFont font = QFont(settings.value("FontFamily", "Courier New").value(), settings.value("PointSize", 10).toInt(), settings.value("Weight", 50).toInt()); #endif if ((Type & Mon)) { Sess->monWindow = new QTextEdit(Sess); Sess->monWindow->setReadOnly(1); Sess->monWindow->document()->setMaximumBlockCount(10000); Sess->monWindow->setFont(font); Sess->monWindow->setStyleSheet(monStyleSheet); mythis->connect(Sess->monWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged())); } if ((Type & (Listen | Term))) { Sess->termWindow = new QTextEdit(Sess); Sess->termWindow->setReadOnly(1); Sess->termWindow->document()->setMaximumBlockCount(10000); Sess->termWindow->setFont(font); Sess->termWindow->setStyleSheet(termStyleSheet); Sess->TTLabel = new QLabel(Sess); Sess->TTLabel->setGeometry(QRect(0,0 ,500, 500)); Sess->TTLabel->setVisible(false); Sess->TTBitmap = new QImage(40 * 15, 25 * 19, QImage::Format_RGB32); Sess->TTBitmap->fill(Qt::black); /* char Page[4096]; QFile file("/savepage.txt"); file.open(QIODevice::ReadOnly); file.read(Page, 4096); file.close(); Sess->TTActive = 1; strcpy(Sess->pageBuffer, Page); DecodeTeleText(Sess, Sess->pageBuffer); */ Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); Sess->TTLabel->setContextMenuPolicy(Qt::CustomContextMenu); mythis->connect(Sess->TTLabel, SIGNAL(customContextMenuRequested(const QPoint&)), parent, SLOT(showContextMenuL())); mythis->connect(Sess->termWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged())); Sess->inputWindow = new QLineEdit(Sess); Sess->inputWindow->installEventFilter(parent); Sess->inputWindow->setFont(font); Sess->inputWindow->setStyleSheet(inputStyleSheet); Sess->inputWindow->setContextMenuPolicy(Qt::PreventContextMenu); mythis->connect(Sess->inputWindow, SIGNAL(selectionChanged()), parent, SLOT(onLEselectionChanged())); } if (Type == Term || Type == Listen) { // Term Only or Listen Only Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu); mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)), parent, SLOT(showContextMenuT(const QPoint &))); } if (Type == (Term | Mon)) { // Combined Term and Mon. Add Custom Menu to set Mon/Term Split with Right Click Sess->monWindow->setContextMenuPolicy(Qt::CustomContextMenu); Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu); mythis->connect(Sess->monWindow, SIGNAL(customContextMenuRequested(const QPoint&)), parent, SLOT(showContextMenuM(const QPoint &))); mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)), parent, SLOT(showContextMenuMT(const QPoint &))); } if (Sess->SessionType == Mon) // Mon Only Sess->setWindowTitle("Monitor Session Disconnected"); else if (Sess->SessionType == Listen) // Mon Only Sess->setWindowTitle("Listen Window Disconnected"); else Sess->setWindowTitle("Disconnected"); Sess->installEventFilter(mythis); Sess->show(); int pos = (_sessions.size() - 1) * 20; if (TermMode == MDI) { Sess->sw->move(pos, pos); } QSize Size(800, 602); // Not actually used, but Event constructor needs it QResizeEvent event(Size, Size); QApplication::sendEvent(Sess, &event); // Resize Widgets to fix Window return Sess; } QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent) { int i; char Title[80]; // Get configuration path for MacOS. std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString(); std::string conf_path = directory + "/QtTermTCP.ini"; //mkdir(directory.c_str(), 0775); _server = new QTcpServer(); mythis = this; ui.setupUi(this); initUTF8(); mymenuBar = new QMenuBar(this); mymenuBar->setGeometry(QRect(0, 0, 781, 26)); setMenuBar(mymenuBar); toolBar = new QToolBar(this); toolBar->setObjectName("mainToolbar"); addToolBar(Qt::BottomToolBarArea, toolBar); QSettings mysettings(GetConfPath(), QSettings::IniFormat); restoreGeometry(mysettings.value("geometry").toByteArray()); restoreState(mysettings.value("windowState").toByteArray()); GetSettings(); // Set background colours sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);", monBackground.red(), monBackground.green(), monBackground.blue()); sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);", termBackground.red(), termBackground.green(), termBackground.blue()); sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", inputText.red(), inputText.green(), inputText.blue(), inputBackground.red(), inputBackground.green(), inputBackground.blue()); #ifdef ANDROID menufont = new QFont(mysettings.value("MFontFamily", "Driod Sans").value(), mysettings.value("MPointSize", 12).toInt(), mysettings.value("MWeight", 50).toInt()); #else menufont = new QFont(mysettings.value("MFontFamily", "Aerial").value(), mysettings.value("MPointSize", 10).toInt(), mysettings.value("MWeight", 50).toInt()); #endif if (TermMode == MDI) { mdiArea = new QMdiArea(ui.centralWidget); mdiArea->setGeometry(QRect(0, 0, 771, 571)); mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(xon_mdiArea_changed())); setCentralWidget(mdiArea); } else if (TermMode == Tabbed) { tabWidget = new QTabWidget(this); ui.verticalLayout->addWidget(tabWidget); tabWidget->setTabPosition(QTabWidget::South); newWindow(this, TabType[0], "Sess 1"); newWindow(this, TabType[1], "Sess 2"); newWindow(this, TabType[2], "Sess 3"); newWindow(this, TabType[3], "Sess 4"); newWindow(this, TabType[4], "Sess 5"); newWindow(this, TabType[5], "Sess 6"); newWindow(this, TabType[6], "Sess 7"); newWindow(this, TabType[7], "Monitor"); newWindow(this, TabType[8], "Monitor"); ActiveSession = _sessions.at(0); connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSelected(int))); tabWidget->setFont(*menufont); } sprintf(Title, "QtTermTCP Version %s", VersionString); this->setWindowTitle(Title); //#ifdef ANDROID // mymymenuBar->setVisible(false); //#endif if (TermMode == Single) windowMenu = mymenuBar->addMenu(""); else windowMenu = mymenuBar->addMenu(tr("&Window")); connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu())); windowMenu->setFont(*menufont); newTermAct = new QAction(tr("New Terminal Window"), this); connect(newTermAct, SIGNAL(triggered()), this, SLOT(doNewTerm())); newMonAct = new QAction(tr("New Monitor Window"), this); connect(newMonAct, SIGNAL(triggered()), this, SLOT(doNewMon())); newCombinedAct = new QAction(tr("New Combined Term/Mon Window"), this); connect(newCombinedAct, SIGNAL(triggered()), this, SLOT(doNewCombined())); if (TermMode == MDI) { closeAct = new QAction(tr("Cl&ose"), this); closeAct->setStatusTip(tr("Close the active window")); connect(closeAct, SIGNAL(triggered()), mdiArea, SLOT(closeActiveSubWindow())); closeAllAct = new QAction(tr("Close &All"), this); closeAllAct->setStatusTip(tr("Close all the windows")); connect(closeAllAct, SIGNAL(triggered()), mdiArea, SLOT(closeAllSubWindows())); tileAct = new QAction(tr("&Tile"), this); tileAct->setStatusTip(tr("Tile the windows")); connect(tileAct, SIGNAL(triggered()), mdiArea, SLOT(tileSubWindows())); cascadeAct = new QAction(tr("&Cascade"), this); cascadeAct->setStatusTip(tr("Cascade the windows")); connect(cascadeAct, SIGNAL(triggered()), this, SLOT(doCascade())); nextAct = new QAction(tr("Ne&xt"), this); nextAct->setShortcuts(QKeySequence::NextChild); nextAct->setStatusTip(tr("Move the focus to the next window")); connect(nextAct, SIGNAL(triggered()), mdiArea, SLOT(activateNextSubWindow())); previousAct = new QAction(tr("Pre&vious"), this); previousAct->setShortcuts(QKeySequence::PreviousChild); previousAct->setStatusTip(tr("Move the focus to the previous window")); connect(previousAct, SIGNAL(triggered()), mdiArea, SLOT(activatePreviousSubWindow())); } quitAction = new QAction(tr("&Quit"), this); connect(quitAction, SIGNAL(triggered()), this, SLOT(doQuit())); windowMenuSeparatorAct = new QAction(this); windowMenuSeparatorAct->setSeparator(true); updateWindowMenu(); connectMenu = mymenuBar->addMenu(tr("&Connect")); actHost[16] = new QAction("AGW Connect", this); actHost[16]->setFont(*menufont); actHost[16]->setVisible(0); connectMenu->addAction(actHost[16]); connect(actHost[16], SIGNAL(triggered()), this, SLOT(Connect())); actHost[17] = new QAction("VARA Connect", this); actHost[17]->setFont(*menufont); actHost[17]->setVisible(0); connectMenu->addAction(actHost[17]); connect(actHost[17], SIGNAL(triggered()), this, SLOT(Connect())); actHost[18] = new QAction("KISS Connect", this); actHost[18]->setFont(*menufont); actHost[18]->setVisible(KISSEnable); actHost[18]->setEnabled(0); connectMenu->addAction(actHost[18]); connect(actHost[18], SIGNAL(triggered()), this, SLOT(Connect())); for (i = 0; i < MAXHOSTS; i++) { if (SessName[i][0]) { char Lable[256]; sprintf(Lable, "%s(%s)", Host[i], SessName[i]); actHost[i] = new QAction(Lable, this); } else actHost[i] = new QAction(Host[i], this); actHost[i]->setFont(*menufont); connectMenu->addAction(actHost[i]); connect(actHost[i], SIGNAL(triggered()), this, SLOT(Connect())); } discAction = mymenuBar->addAction("&Disconnect"); // Place discAction in mac preferences menu, otherwise it doesn't appear if (is_mac == true) { QMenu * app_menu = mymenuBar->addMenu("App Menu"); discAction->setMenuRole(QAction::ApplicationSpecificRole); app_menu->addAction(discAction); } connect(discAction, SIGNAL(triggered()), this, SLOT(Disconnect())); discAction->setEnabled(false); toolBar->setFont(*menufont); #ifndef ANDROID toolBar->setVisible(false); #endif but4 = new QToolButton(); but4->setPopupMode(QToolButton::InstantPopup); but4->setText("Window"); but4->addAction(windowMenu->menuAction()); but4->setFont(*menufont); toolBar->addWidget(but4); but5 = new QToolButton(); but5->setPopupMode(QToolButton::InstantPopup); but5->setText("Connect"); but5->addAction(connectMenu->menuAction()); but5->setFont(*menufont); toolBar->addWidget(but5); toolBar->addAction(discAction); setupMenu = mymenuBar->addMenu(tr("&Setup")); hostsubMenu = setupMenu->addMenu("Hosts"); hostsubMenu->setFont(*menufont); for (i = 0; i < MAXHOSTS; i++) { if (Host[i][0]) { char Label[256]; if (SessName[i][0]) sprintf(Label, "%s(%s)", Host[i], SessName[i]); else strcpy(Label, Host[i]); actSetup[i] = new QAction(Label, this); } else actSetup[i] = new QAction("New Host", this); hostsubMenu->addAction(actSetup[i]); connect(actSetup[i], SIGNAL(triggered()), this, SLOT(SetupHosts())); actSetup[i]->setFont(*menufont); } // Setup Presentation Options setupMenu->addSeparator()->setText(tr("Presentation")); QActionGroup * termGroup = new QActionGroup(this); singleAct = setupMenuLine(nullptr, (char *)"Single Window (Term + Mon)", this, (TermMode == Single) && (singlemodeFormat == Term + Mon)); singleAct2 = setupMenuLine(nullptr, (char *)"Single Window (Term only)", this, (TermMode == Single) && (singlemodeFormat == Term)); MDIAct = setupMenuLine(nullptr, (char *)"MDI", this, TermMode == MDI); tabbedAct = setupMenuLine(nullptr, (char *)"Tabbed", this, TermMode == Tabbed); termGroup->addAction(singleAct); termGroup->addAction(singleAct2); termGroup->addAction(MDIAct); termGroup->addAction(tabbedAct); setupMenu->addAction(singleAct); setupMenu->addAction(singleAct2); setupMenu->addAction(MDIAct); setupMenu->addAction(tabbedAct); setupMenu->addSeparator(); actFonts = new QAction("Terminal Font", this); setupMenu->addAction(actFonts); connect(actFonts, SIGNAL(triggered()), this, SLOT(doFonts())); actFonts->setFont(*menufont); actmenuFont = new QAction("Menu Font", this); setupMenu->addAction(actmenuFont); connect(actmenuFont, SIGNAL(triggered()), this, SLOT(doMFonts())); actmenuFont->setFont(*menufont); actColours = new QAction("Choose Colours", this); setupMenu->addAction(actColours); connect(actColours, SIGNAL(triggered()), this, SLOT(doColours())); actColours->setFont(*menufont); AGWAction = new QAction("AGW Setup", this); setupMenu->addAction(AGWAction); connect(AGWAction, SIGNAL(triggered()), this, SLOT(AGWSlot())); AGWAction->setFont(*menufont); VARAAction = new QAction("VARA Setup", this); setupMenu->addAction(VARAAction); connect(VARAAction, SIGNAL(triggered()), this, SLOT(VARASlot())); VARAAction->setFont(*menufont); KISSAction = new QAction("KISS Setup", this); setupMenu->addAction(KISSAction); connect(KISSAction, SIGNAL(triggered()), this, SLOT(KISSSlot())); KISSAction->setFont(*menufont); actChatMode = setupMenuLine(setupMenu, (char *)"Chat Terminal Mode", this, ChatMode); actAutoTeletext = setupMenuLine(setupMenu, (char *)"Auto switch to Teletext", this, AutoTeletext); actBells = setupMenuLine(setupMenu, (char *)"Enable Bells", this, Bells); actStripLF = setupMenuLine(setupMenu, (char *)"Strip Line Feeds", this, StripLF); actIntervalBeep = setupMenuLine(setupMenu, (char *)"Beep after inactivity", this, AlertBeep); actConnectBeep = setupMenuLine(setupMenu, (char *)"Beep on inbound connect", this, ConnectBeep); setupMenu->addAction(new QAction("Interpret non-UTF8 input as:", this)); setupMenu->setFont(*menufont); QActionGroup * cpGroup = new QActionGroup(this); actnoConv = setupMenuLine(nullptr, (char *)" Don't Convert (assume is UTF-8)", this, convUTF8 == -1); actAuto = setupMenuLine(nullptr, (char *)" Auto", this, convUTF8 == 0); actCP1251 = setupMenuLine(nullptr, (char *)" CP1251 (Cyrillic)", this, convUTF8 == 1251); actCP1252 = setupMenuLine(nullptr, (char *)" CP1252 (Western Europe)", this, convUTF8 == 1252); actCP437 = setupMenuLine(nullptr, (char *)" CP437 (Windows Line Draw)", this, convUTF8 == 437); cpGroup->addAction(actnoConv); cpGroup->addAction(actAuto); cpGroup->addAction(actCP1251); cpGroup->addAction(actCP1252); cpGroup->addAction(actCP437); setupMenu->addAction(actnoConv); setupMenu->addAction(actAuto); setupMenu->addAction(actCP1251); setupMenu->addAction(actCP1252); setupMenu->addAction(actCP437); monitorMenu = mymenuBar->addMenu(tr("&Monitor")); MonTX = setupMenuLine(monitorMenu, (char *)"Monitor TX", this, 1); MonSup = setupMenuLine(monitorMenu, (char *)"Monitor Supervisory", this, 1); MonUI = setupMenuLine(monitorMenu, (char *)"Only Monitor UI Frames", this, 0); MonNodes = setupMenuLine(monitorMenu, (char *)"Monitor NODES Broadcasts", this, 0); MonColour = setupMenuLine(monitorMenu, (char *)"Enable Colour", this, 1); for (i = 0; i < MAXPORTS + 1; i++) { MonPort[i] = setupMenuLine(monitorMenu, (char *)"Port", this, 0); MonPort[i]->setVisible(false); } but1 = new QToolButton(); but1->setPopupMode(QToolButton::InstantPopup); but1->setText("Monitor"); but1->addAction(monitorMenu->menuAction()); toolBar->addWidget(but1); but2 = new QToolButton(); but2->setPopupMode(QToolButton::InstantPopup); but2->setText("Setup"); but2->addAction(setupMenu->menuAction()); toolBar->addWidget(but2); ListenAction = mymenuBar->addAction("&Listen"); connect(ListenAction, SIGNAL(triggered()), this, SLOT(ListenSlot())); toolBar->addAction(ListenAction); YAPPMenu = mymenuBar->addMenu(tr("&YAPP")); YAPPSend = new QAction("Send File", this); YAPPSetRX = new QAction("Set Receive Directory", this); YAPPSend->setFont(*menufont); YAPPSetRX->setFont(*menufont); YAPPMenu->addAction(YAPPSend); YAPPMenu->addAction(YAPPSetRX); YAPPSend->setEnabled(false); connect(YAPPSend, SIGNAL(triggered()), this, SLOT(doYAPPSend())); connect(YAPPSetRX, SIGNAL(triggered()), this, SLOT(doYAPPSetRX())); 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; ui.verticalLayout->addWidget(Sess); connectMenu->setEnabled(true); discAction->setEnabled(false); YAPPSend->setEnabled(false); } if (TermMode == MDI) { int n = atoi(sessionList); 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 = host; 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); } void QtTermTCP::setFonts() { windowMenu->menuAction()->setFont(*menufont); connectMenu->menuAction()->setFont(*menufont); setupMenu->menuAction()->setFont(*menufont); monitorMenu->menuAction()->setFont(*menufont); YAPPMenu->menuAction()->setFont(*menufont); if (tabWidget) tabWidget->setFont(*menufont); mymenuBar->setFont(*menufont); toolBar->setFont(*menufont); but1->setFont(*menufont); but2->setFont(*menufont); but3->setFont(*menufont); but4->setFont(*menufont); but5->setFont(*menufont); discAction->setFont(*menufont); ListenAction->setFont(*menufont); for (int i = 0; i < MAXHOSTS; i++) { actHost[i]->setFont(*menufont); actSetup[i]->setFont(*menufont); } actHost[16]->setFont(*menufont); // AGW Host } void QtTermTCP::doQuit() { if (_server->isListening()) _server->close(); SaveSettings(); QCoreApplication::quit(); } // "Copy on select" Code void QtTermTCP::onTEselectionChanged() { QTextEdit * x = static_cast(QObject::sender()); x->copy(); } void QtTermTCP::onLEselectionChanged() { QLineEdit * x = static_cast(QObject::sender()); x->copy(); } void QtTermTCP::setVDMode() { QAction * sender = static_cast(QObject::sender()); QTextEdit * window = static_cast(sender->parentWidget()); // Need to find session with this window as owner Ui_ListenSession * Sess = NULL; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); if (Sess->termWindow == window) { Sess->TTActive ^= 1; DoTermResize(Sess); break; } } } int splitY; // Value when menu added void QtTermTCP::setSplit() { QAction * sender = static_cast(QObject::sender()); QWidget * Parent = sender->parentWidget(); if (Parent) Parent = Parent->parentWidget(); int y = Parent->rect().height() - 50; // y is height of whole windom. splitX is new split position // So split = 100 * splitx/x Split = (splitY * 100) / y; if (Split < 10) Split = 10; else if (Split > 90) Split = 90; QSize size(800, 602); QResizeEvent event(size, size); eventFilter(Parent, &event); } void QtTermTCP::showContextMenuMT(const QPoint &pt) // Term Window { // Monitor and Terminal (Term Half) QTextEdit* sender = static_cast(QObject::sender()); QMenu *menu = sender->createStandardContextMenu(); QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}QMenu::separator {height: 2px;background: rgb(58, 80, 116);margin-left: 10px;margin-right: 5px;}"; menu->setStyleSheet(style); QAction * actSplit = new QAction("Set Monitor/Output Split", sender); QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender); menu->addAction(actSplit); menu->addAction(actVDMode); splitY = pt.y() + termX; connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit())); connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode())); menu->exec(sender->mapToGlobal(pt)); delete menu; } void QtTermTCP::showContextMenuT(const QPoint &pt) // Term Window { // Just Terminal QTextEdit* sender = static_cast(QObject::sender()); QMenu *menu = sender->createStandardContextMenu(); QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}"; menu->setStyleSheet(style); QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender); menu->addAction(actVDMode); connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode())); menu->exec(sender->mapToGlobal(pt)); delete menu; } void QtTermTCP::showContextMenuL() // Term Window { // Teletext Label Right Clicked - cancel TT Mode QLabel * sender = static_cast(QObject::sender()); // Need to find session with this label as owner Ui_ListenSession * Sess = NULL; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); if (Sess->TTLabel == sender) { Sess->TTActive ^= 1; DoTermResize(Sess); break; } } } void QtTermTCP::showContextMenuM(const QPoint &pt) // Mon Window { QTextEdit* sender = static_cast(QObject::sender()); QMenu *menu = sender->createStandardContextMenu(); QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}"; menu->setStyleSheet(style); QAction * actSplit = new QAction("Set Monitor/Output Split", sender); menu->addAction(actSplit); splitY = pt.y(); connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit())); 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; if (Sess->clientSocket || Sess->AGWSession || Sess->KISSSession || Sess->KISSMode) { connectMenu->setEnabled(false); discAction->setEnabled(true); YAPPSend->setEnabled(true); } else { connectMenu->setEnabled(true); discAction->setEnabled(false); YAPPSend->setEnabled(false); } // If a monitor Window, change Monitor config settings if (Sess->PortMonString[0]) { char * ptr = (char *)malloc(1024); memcpy(ptr, Sess->PortMonString, 1024); 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 < 32; 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 = 33; if (Sess->portmask & (1ll << (m - 1))) SetPortMonLine(portnum, msg, 1, 1); else SetPortMonLine(portnum, msg, 1, 0); } free(ptr); MonTX->setChecked(Sess->mtxparam); MonSup->setChecked(Sess->mcomparam); MonUI->setChecked(Sess->monUI); MonNodes->setChecked(Sess->MonitorNODES); MonColour->setChecked(Sess->MonitorColour); } return; } } void QtTermTCP::SetupHosts() { QAction * Act = static_cast(QObject::sender()); int i; for (i = 0; i < MAXHOSTS; i++) { if (Act == actSetup[i]) break; } if (i > 15) return; ConfigHost = i; TabDialog tabdialog(0); tabdialog.exec(); } void QtTermTCP::Connect() { QMdiSubWindow * UI; Ui_ListenSession * Sess = nullptr; QAction * Act = static_cast(QObject::sender()); int i; for (i = 0; i < MAXHOSTS; i++) { if (Act == actHost[i]) break; } SavedHost = i; // Last used if (TermMode == MDI) { UI = mdiArea->activeSubWindow(); for (i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); if (Sess->sw == UI) break; } if (i == _sessions.size()) return; } 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; if (Act == actHost[16]) { // This runs the AGW Connection dialog Sess->CurrentHost = 16; // Iast used AGWConnect dialog(0); dialog.exec(); return; } if (Act == actHost[17]) { // This runs the VARA Connection dialog Sess->CurrentHost = 17; // Iast used VARADataSock->Sess = Sess; VARASock->Sess = Sess; VARAConnect dialog(0); dialog.exec(); WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); return; } if (Act == actHost[18]) { // This runs the KISS Connection dialog Sess->CurrentHost = 18; // Iast used KISSConnect dialog(0); dialog.exec(); return; } // Set Monitor Params for this host sscanf(MonParams[Sess->CurrentHost], "%llx %x %x %x %x %x", &Sess->portmask, &Sess->mtxparam, &Sess->mcomparam, &Sess->MonitorNODES, &Sess->MonitorColour, &Sess->monUI); MonTX->setChecked(Sess->mtxparam); MonSup->setChecked(Sess->mcomparam); MonUI->setChecked(Sess->monUI); MonNodes->setChecked(Sess->MonitorNODES); MonColour->setChecked(Sess->MonitorColour); // Remove old Monitor menu for (i = 0; i < 32; 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(); } } void QtTermTCP::menuChecked() { QAction * Act = static_cast(QObject::sender()); int state = Act->isChecked(); int newTermMode = TermMode; int newSingleMode = singlemodeFormat; if (Act == TabSingle || Act == TabBoth || Act == TabMon) { // Tabbed Window format had changed int i = tabWidget->currentIndex(); if (Act == TabSingle) TabType[i] = Term; else if (Act == TabBoth) TabType[i] = Term + Mon; else TabType[i] = Mon; QMessageBox msgBox; msgBox.setText("Tab Types will change next time program is started."); msgBox.exec(); } if (Act == singleAct || Act == singleAct2 || Act == MDIAct || Act == tabbedAct) { // Term Mode had changed if (singleAct->isChecked()) { newTermMode = Single; newSingleMode = Mon + Term; } else if (singleAct2->isChecked()) { newTermMode = Single; newSingleMode = Term; } else if (MDIAct->isChecked()) newTermMode = MDI; else if (tabbedAct->isChecked()) newTermMode = Tabbed; if (newTermMode != TermMode || newSingleMode != singlemodeFormat) { QSettings settings(GetConfPath(), QSettings::IniFormat); settings.setValue("TermMode", newTermMode); settings.setValue("singlemodeFormat", newSingleMode); QMessageBox msgBox; msgBox.setText("Presentation Mode will change next time program is started."); msgBox.exec(); } return; } if (Act == MonTX) ActiveSession->mtxparam = state; else if (Act == MonSup) ActiveSession->mcomparam = state; else if (Act == MonUI) ActiveSession->monUI = state; else if (Act == MonNodes) ActiveSession->MonitorNODES = state; else if (Act == MonColour) ActiveSession->MonitorColour = state; else if (Act == actChatMode) ChatMode = state; else if (Act == actAutoTeletext) AutoTeletext = state; else if (Act == actBells) Bells = state; else if (Act == actStripLF) StripLF = state; else if (Act == actIntervalBeep) AlertBeep = state; else if (Act == actConnectBeep) ConnectBeep = state; else if (Act == actnoConv) convUTF8 = -1; else if (Act == actAuto) convUTF8 = 0; else if (Act == actCP1251) convUTF8 = 1251; else if (Act == actCP1252) convUTF8 = 1252; else if (Act == actCP437) convUTF8 = 437; else { // look for port entry for (int i = 0; i < MAXPORTS; i++) { if (Act == MonPort[i]) { unsigned long long mmask; if (i == 0) // BBS Mon - use bit 32 mmask = 1ll << 32; else mmask = 1ll << (i - 1); if (state) ActiveSession->portmask |= mmask; else ActiveSession->portmask &= ~mmask; break; } } } // Get active Session /* QMdiSubWindow *SW = mdiArea->activeSubWindow(); Ui_ListenSession * Sess; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); // for (Ui_ListenSession * Sess : _sessions) // { if (Sess->sw == SW) { */ if (ActiveSession->clientSocket && ActiveSession->SessionType & Mon) SendTraceOptions(ActiveSession); return; } void QtTermTCP::LDisconnect(Ui_ListenSession * LUI) { if (LUI->clientSocket) LUI->clientSocket->disconnectFromHost(); } extern QApplication * a; void QtTermTCP::LreturnPressed(Ui_ListenSession * Sess) { QByteArray stringData = Sess->inputWindow->text().toUtf8(); // if multiline input (eg from copy/paste) replace LF with CR char * ptr; char * Msgptr; char * Msg; QScrollBar *scrollbar = Sess->termWindow->verticalScrollBar(); bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4)); if (scrollbarAtBottom) Sess->termWindow->moveCursor(QTextCursor::End); // So we don't get blank lines // Stack it Sess->StackIndex = 0; if (Sess->KbdStack[49]) free(Sess->KbdStack[49]); for (int i = 48; i >= 0; i--) { Sess->KbdStack[i + 1] = Sess->KbdStack[i]; } Sess->KbdStack[0] = qstrdup(stringData.data()); stringData.append('\n'); Msgptr = stringData.data(); if (Sess->TTActive) // Teletext uses 0x5F for # while ((ptr = strchr(Msgptr, 0x23))) // Replace VT with LF *ptr++ = 0x5f; while ((ptr = strchr(Msgptr, 11))) // Replace VT with LF *ptr++ = 10; LastWrite = time(NULL); // Stop initial beep Sess->SlowTimer = 0; Sess->pageBuffer[0] = 0; // Reset Teletext mode screen buffer if (Sess->KISSMode == 1) { // UI session. Send as UI Message while ((ptr = strchr(Msgptr, '\n'))) { *ptr++ = 0; Msg = (char *)malloc(strlen(Msgptr) + 10); strcpy(Msg, Msgptr); strcat(Msg, "\r"); Send_UI(0, 0xF0, MYCALL, Sess->UIDEST, (unsigned char *)Msg, (int)strlen(Msg)); WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black free(Msg); Msgptr = ptr; } } else if (Sess->KISSSession) { // Send to ax.25 code while ((ptr = strchr(Msgptr, '\n'))) { *ptr++ = 0; Msg = (char *)malloc(strlen(Msgptr) + 10); strcpy(Msg, Msgptr); strcat(Msg, "\r"); SendtoAX25(Sess->KISSSession, (unsigned char *)Msg, (int)strlen(Msg)); WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black free(Msg); Msgptr = ptr; } } else if (Sess->AGWSession) { // Terminal is in AGWPE mode - send as AGW frame while ((ptr = strchr(Msgptr, '\n'))) { *ptr++ = 0; Msg = (char *)malloc(strlen(Msgptr) + 10); strcpy(Msg, Msgptr); strcat(Msg, "\r"); AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Msg, (int)strlen(Msg)); WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black // Sess->termWindow->insertPlainText(Msg); free(Msg); Msgptr = ptr; } } else if (VARASock && VARASock->Sess == Sess) { while ((ptr = strchr(Msgptr, '\n'))) { *ptr++ = 0; Msg = (char *)malloc(strlen(Msgptr) + 10); strcpy(Msg, Msgptr); strcat(Msg, "\r"); VARADataSock->write(Msg); WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black // Sess->termWindow->insertPlainText(Msg); free(Msg); Msgptr = ptr; } } else if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) { while ((ptr = strchr(Msgptr, '\n'))) { *ptr++ = 0; Msg = (char *)malloc(strlen(Msgptr) + 10); strcpy(Msg, Msgptr); strcat(Msg, "\r"); Sess->clientSocket->write(Msg); WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black // Sess->termWindow->insertPlainText(Msg); free(Msg); Msgptr = ptr; } } else { // Not Connected if (Sess->SessionType != Listen) { if (Sess->CurrentHost < MAXHOSTS) { // Last connect was TCP char Msg[] = "Connecting....\r"; WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red delete(Sess->clientSocket); Sess->clientSocket = new myTcpSocket(); Sess->clientSocket->Sess = Sess; connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]); } else if (Sess->CurrentHost == 16) // AGW { // Invoke AGW connect dialog AGWConnect dialog(0); dialog.exec(); WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); return; } else if (Sess->CurrentHost == 17) // VARA { // Invoke VARA connect dialog VARAConnect dialog(0); dialog.exec(); WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); return; } else if (Sess->CurrentHost == 18) // KISS { // Do we send as UI or invoke kiss connect dialog ?? // Try Connect Dialog for now - may make a menu option KISSConnect dialog(0); dialog.exec(); WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); return; } } else { char Msg[] = "Incoming Session - Can't Connect\r"; WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, 81); // Red } } if (scrollbarAtBottom) Sess->termWindow->moveCursor(QTextCursor::End); Sess->inputWindow->setText(""); a->inputMethod()->hide(); } void QtTermTCP::displayError(QAbstractSocket::SocketError socketError) { myTcpSocket* sender = static_cast(QObject::sender()); switch (socketError) { case QAbstractSocket::RemoteHostClosedError: break; case QAbstractSocket::HostNotFoundError: QMessageBox::information(this, tr("QtTermTCP"), tr("The host was not found. Please check the " "host name and portsettings->")); break; case QAbstractSocket::ConnectionRefusedError: QMessageBox::information(this, tr("QtTermTCP"), tr("The connection was refused by the peer.")); break; default: QMessageBox::information(this, tr("QtTermTCP"), tr("The following error occurred: %1.") .arg(sender->errorString())); } connectMenu->setEnabled(true); } void QtTermTCP::readyRead() { int Read; unsigned char Buffer[8192]; myTcpSocket* Socket = static_cast(QObject::sender()); Ui_ListenSession * Sess = (Ui_ListenSession *)Socket->Sess; // read the data from the socket Read = Socket->read((char *)Buffer, 2047); while (Read > 0) { // if (InputMode == 'Y') // Yapp // { // QString myString = QString::fromUtf8((char*)Buffer, Read); // QByteArray ptr = myString.toLocal8Bit(); // memcpy(Buffer, ptr.data(), ptr.length()); // Read = ptr.length(); // } Buffer[Read] = 0; ProcessReceivedData(Sess, Buffer, Read); QString myString = QString::fromUtf8((char*)Buffer); // qDebug() << myString; Read = Socket->read((char *)Buffer, 2047); } } extern "C" int SocketSend(Ui_ListenSession * Sess, char * Buffer, int len) { myTcpSocket *Socket = Sess->clientSocket; if (Socket && Socket->state() == QAbstractSocket::ConnectedState) return Socket->write(Buffer, len); return 0; } extern "C" int SocketFlush(Ui_ListenSession * Sess) { if (Sess->AGWSession || Sess->KISSSession || (VARASock && VARASock->Sess == Sess)) return 0; myTcpSocket* Socket = Sess->clientSocket; if (Socket && Socket->state() == QAbstractSocket::ConnectedState) return Socket->flush(); return 0; } extern "C" void mySleep(int ms) { QThread::msleep(ms); } extern "C" void SetPortMonLine(int i, char * Text, int visible, int enabled) { MonPort[i]->setText(Text); MonPort[i]->setVisible(visible); MonPort[i]->setChecked(enabled); } bool scrollbarAtBottom = 0; extern "C" void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int * OutputSaveLen, char * OutputSave, QColor Colour); extern "C" void WritetoOutputWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int len) { WritetoOutputWindowEx(Sess, Buffer, len, Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, outputText); } extern "C" void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int * OutputSaveLen, char * OutputSave, QColor Colour) { unsigned char Copy[8192]; unsigned char * ptr1, *ptr2; unsigned char Line[8192]; unsigned char out[8192]; int outlen; int num; if (termWindow == NULL) return; time_t NOW = time(NULL); // Beep if no output for a while if (AlertInterval && (NOW - LastWrite) > AlertInterval) { if (AlertBeep) myBeep(); } 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(); } } while (ptr); } num = ptr2 - ptr1 - 1; // if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1); memcpy(Line, ptr1, num); Line[num++] = 13; Line[num] = 0; if (Line[0] == 0x1b) // Colour Escape { if (Sess->MonitorColour) termWindow->setTextColor(Colours[Line[1] - 10]); outlen = checkUTF8(&Line[2], num - 2, out); out[outlen] = 0; termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); // termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); } else { termWindow->setTextColor(Colour); outlen = checkUTF8(Line, num, out); out[outlen] = 0; termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); // termWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); } len -= (ptr2 - ptr1); ptr1 = ptr2; if ((len > 0) && StripLF) { if (*ptr1 == 0x0a) // Line Feed { ptr1++; len--; } } goto lineloop; } extern "C" void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Msg, int len) { char * ptr1 = (char *)Msg, *ptr2; char Line[512]; int num; // QScrollBar *scrollbar = Sess->monWindow->verticalScrollBar(); // bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4)); if (Sess->monWindow == nullptr) return; Sess->monWindow->setStyleSheet(monStyleSheet); const QTextCursor old_cursor = Sess->monWindow->textCursor(); const int old_scrollbar_value = Sess->monWindow->verticalScrollBar()->value(); const bool is_scrolled_down = old_scrollbar_value == Sess->monWindow->verticalScrollBar()->maximum(); // Move the cursor to the end of the document. Sess->monWindow->moveCursor(QTextCursor::End); // Insert the text at the position of the cursor (which is the end of the document). // Write a line at a time so we can action colour chars // Buffer[Len] = 0; // if (scrollbarAtBottom) // Sess->monWindow->moveCursor(QTextCursor::End); if (Sess->MonSaveLen) { // Have part line - append to it memcpy(&Sess->MonSave[Sess->MonSaveLen], Msg, len); Sess->MonSaveLen += len; ptr1 = Sess->MonSave; len = Sess->MonSaveLen; Sess->MonSaveLen = 0; } lineloop: if (len <= 0) { // if (scrollbarAtBottom) // Sess->monWindow->moveCursor(QTextCursor::End); if (old_cursor.hasSelection() || !is_scrolled_down) { // The user has selected text or scrolled away from the bottom: maintain position. Sess->monWindow->setTextCursor(old_cursor); Sess->monWindow->verticalScrollBar()->setValue(old_scrollbar_value); } else { // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. Sess->monWindow->moveCursor(QTextCursor::End); Sess->monWindow->verticalScrollBar()->setValue(Sess->monWindow->verticalScrollBar()->maximum()); } return; } // copy text to control a line at a time ptr2 = (char *)memchr(ptr1, 13, len); if (ptr2 == 0) // No CR { memmove(Sess->MonSave, ptr1, len); Sess->MonSaveLen = len; return; } *(ptr2++) = 0; // if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1); num = ptr2 - ptr1 - 1; memcpy(Line, ptr1, num); Line[num++] = 13; Line[num] = 0; if (Line[0] == 0x1b) // Colour Escape { if (Sess->MonitorColour) { if (Line[1] == 17) Sess->monWindow->setTextColor(monRxText); else Sess->monWindow->setTextColor(monTxText); } else Sess->monWindow->setTextColor(monOtherText); Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); } else { Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); } len -= (ptr2 - ptr1); ptr1 = ptr2; goto lineloop; } int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len); void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len); // YAPP stuff #define SOH 1 #define STX 2 #define ETX 3 #define EOT 4 #define ENQ 5 #define ACK 6 #define DLE 0x10 #define NAK 0x15 #define CAN 0x18 extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len) { if (Sess == 0) return; Sess->SlowTimer = 0; Msg[Len] = 0; if (Sess->InputMode == 'Y') // Yapp { ProcessYAPPMessage(Sess, (unsigned char *)Msg, Len); return; } // Could be a YAPP Header if (Len == 2 && Msg[0] == ENQ && Msg[1] == 1) // YAPP Send_Init { char YAPPRR[2]; // Turn off monitoring Sess->InputMode = 'Y'; YAPPRR[0] = ACK; YAPPRR[1] = 1; QueueMsg(Sess, YAPPRR, 2); return; } if (AutoTeletext && (Msg[0] == 0x1e || Msg[0] == 0x0c)) { if (Sess->TTActive == 0) { Sess->TTActive = 1; DoTermResize(Sess); } } if (Sess->TTActive) { // Feed to Teletext code // We need to decode a whole page. There is no obvious delimiter so process till data stops. // Buffer is cleared when next input is sent if (strlen(&Sess->pageBuffer[0] + Len) > 4090) Sess->pageBuffer[0] = 0; // Protect buffer strcat(Sess->pageBuffer, (char *)Msg); DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end return; } WritetoOutputWindow(Sess, (unsigned char *)Msg, Len); } QSettings* settings; // This makes geting settings for more channels easier char Prefix[16] = "AX25_A"; void GetPortSettings(int Chan); QVariant getAX25Param(const char * key, QVariant Default) { char fullKey[64]; sprintf(fullKey, "%s/%s", Prefix, key); return settings->value(fullKey, Default); } void getAX25Params(int chan) { Prefix[5] = chan + 'A'; GetPortSettings(chan); } void GetPortSettings(int Chan) { maxframe[Chan] = getAX25Param("Maxframe", 4).toInt(); fracks[Chan] = getAX25Param("Retries", 10).toInt(); frack_time[Chan] = getAX25Param("FrackTime", 8).toInt(); persist[Chan] = getAX25Param("Persist", 128).toInt(); kisspaclen[Chan] = getAX25Param("Paclen", 128).toInt(); idletime[Chan] = getAX25Param("IdleTime", 180).toInt(); slottime[Chan] = getAX25Param("SlotTime", 100).toInt(); resptime[Chan] = getAX25Param("RespTime", 1500).toInt(); TXFrmMode[Chan] = getAX25Param("TXFrmMode", 1).toInt(); max_frame_collector[Chan] = getAX25Param("FrameCollector", 6).toInt(); //exclude_callsigns[Chan]= getAX25Param("ExcludeCallsigns/"); //exclude_APRS_frm[Chan]= getAX25Param("ExcludeAPRSFrmType/"); KISS_opt[Chan] = getAX25Param("KISSOptimization", false).toInt();; dyn_frack[Chan] = getAX25Param("DynamicFrack", false).toInt();; IPOLL[Chan] = getAX25Param("IPOLL", 80).toInt(); } void GetSettings() { QByteArray qb; int i; char Key[16]; char Param[256]; settings = new QSettings(GetConfPath(), QSettings::IniFormat); // Get saved session definitions sessionList = strdup(settings->value("Sessions", "1|3, 0, 5, 5, 600, 800|").toString().toUtf8()); for (i = 0; i < MAXHOSTS; i++) { sprintf(Key, "HostParams%d", i); qb = settings->value(Key).toByteArray(); DecodeSettingsLine(i, qb.data()); } Split = settings->value("Split", 50).toInt(); ChatMode = settings->value("ChatMode", 1).toInt(); AutoTeletext = settings->value("AutoTeletext", 0).toInt(); Bells = settings->value("Bells", 1).toInt(); StripLF = settings->value("StripLF", 1).toInt(); AlertBeep = settings->value("AlertBeep", 1).toInt(); ConnectBeep = settings->value("ConnectBeep", 1).toInt(); SavedHost = settings->value("CurrentHost", 0).toInt(); strcpy(YAPPPath, settings->value("YAPPPath", "").toString().toUtf8()); listenPort = settings->value("listenPort", 8015).toInt(); listenEnable = settings->value("listenEnable", false).toBool(); strcpy(listenCText, settings->value("listenCText", "").toString().toUtf8()); TermMode = settings->value("TermMode", 0).toInt(); singlemodeFormat = settings->value("singlemodeFormat", Term + Mon).toInt(); AGWEnable = settings->value("AGWEnable", 0).toInt(); AGWMonEnable = settings->value("AGWMonEnable", 0).toInt(); strcpy(AGWTermCall, settings->value("AGWTermCall", "").toString().toUtf8()); strcpy(AGWBeaconDest, settings->value("AGWBeaconDest", "").toString().toUtf8()); strcpy(AGWBeaconPath, settings->value("AGWBeaconPath", "").toString().toUtf8()); AGWBeaconInterval = settings->value("AGWBeaconInterval", 0).toInt(); strcpy(AGWBeaconPorts, settings->value("AGWBeaconPorts", "").toString().toUtf8()); strcpy(AGWBeaconMsg, settings->value("AGWBeaconText", "").toString().toUtf8()); strcpy(AGWHost, settings->value("AGWHost", "127.0.0.1").toString().toUtf8()); AGWPortNum = settings->value("AGWPort", 8000).toInt(); AGWPaclen = settings->value("AGWPaclen", 80).toInt(); AGWToCalls = settings->value("AGWToCalls", "").toStringList(); convUTF8 = settings->value("convUTF8", 0).toInt(); KISSEnable = settings->value("KISSEnable", 0).toInt(); strcpy(MYCALL, settings->value("MYCALL", "").toString().toUtf8()); strcpy(KISSHost, settings->value("KISSHost", "127.0.0.1").toString().toUtf8()); KISSPortNum = settings->value("KISSPort", 8100).toInt(); KISSMode = settings->value("KISSMode", 0).toInt(); strcpy(SerialPort, settings->value("KISSSerialPort", "None").toString().toUtf8()); KISSBAUD = settings->value("KISSBAUD", 19200).toInt(); getAX25Params(0); VARAEnable = settings->value("VARAEnable", 0).toInt(); strcpy(VARAHost, settings->value("VARAHost", "127.0.0.1").toString().toUtf8()); strcpy(VARAHostFM, settings->value("VARAHostFM", "127.0.0.1").toString().toUtf8()); strcpy(VARAHostHF, settings->value("VARAHostHF", "127.0.0.1").toString().toUtf8()); strcpy(VARAHostSAT, settings->value("VARAHostSAT", "127.0.0.1").toString().toUtf8()); VARAPortNum = settings->value("VARAPort", 8300).toInt(); VARAPortHF = settings->value("VARAPortHF", 8300).toInt(); VARAPortFM = settings->value("VARAPortFM", 8300).toInt(); VARAPortSAT = settings->value("VARAPortSAT", 8300).toInt(); strcpy(VARAPath, settings->value("VARAPath", "C:\\VARA\\VARA.exe").toString().toUtf8()); strcpy(VARAPathHF, settings->value("VARAPathHF", "C:\\VARA\\VARA.exe").toString().toUtf8()); strcpy(VARAPathFM, settings->value("VARAPathFM", "C:\\VARA\\VARAFM.exe").toString().toUtf8()); strcpy(VARAPathSAT, settings->value("VARAPathSAT", "C:\\VARA\\VARASAT.exe").toString().toUtf8()); strcpy(VARATermCall, settings->value("VARATermCall", "").toString().toUtf8()); VARA500 = settings->value("VARA500", 0).toInt(); VARA2300 = settings->value("VARA2300", 1).toInt(); VARA2750 = settings->value("VARA2750", 0).toInt(); VARAHF = settings->value("VARAHF", 1).toInt(); VARAFM = settings->value("VARAFM", 0).toInt(); VARASAT = settings->value("VARASAT", 0).toInt(); strcpy(VARAInit, settings->value("VARAInit", "").toString().toUtf8()); strcpy(PTTPort, settings->value("PTT", "None").toString().toUtf8()); PTTMode = settings->value("PTTMode", 19200).toInt(); PTTBAUD = settings->value("PTTBAUD", 19200).toInt(); CATHex = settings->value("CATHex", 1).toInt(); strcpy(PTTOnString, settings->value("PTTOnString", "").toString().toUtf8()); strcpy(PTTOffString, settings->value("PTTOffString", "").toString().toUtf8()); pttGPIOPin = settings->value("pttGPIOPin", 17).toInt(); pttGPIOPinR = settings->value("pttGPIOPinR", 17).toInt(); #ifdef WIN32 strcpy(CM108Addr, settings->value("CM108Addr", "0xD8C:0x08").toString().toUtf8()); #else strcpy(CM108Addr, settings->value("CM108Addr", "/dev/hidraw0").toString().toUtf8()); #endif HamLibPort = settings->value("HamLibPort", 4532).toInt(); strcpy(HamLibHost, settings->value("HamLibHost", "127.0.0.1").toString().toUtf8()); FLRigPort = settings->value("FLRigPort", 12345).toInt(); strcpy(FLRigHost, settings->value("FLRigHost", "127.0.0.1").toString().toUtf8()); strcpy(Param, settings->value("TabType", "1 1 1 1 1 1 1 2 2").toString().toUtf8()); sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", &TabType[0], &TabType[1], &TabType[2], &TabType[3], &TabType[4], &TabType[5], &TabType[6], &TabType[7], &TabType[8], &TabType[9]); monBackground = settings->value("monBackground", QColor(255, 255, 255)).value(); monRxText = settings->value("monRxText", QColor(0, 0, 255)).value(); monTxText = settings->value("monTxText", QColor(255, 0, 0)).value(); monOtherText = settings->value("monOtherText", QColor(0, 0, 0)).value(); termBackground = settings->value("termBackground", QColor(255, 255, 255)).value(); outputText = settings->value("outputText", QColor(0, 0, 255)).value(); EchoText = settings->value("EchoText", QColor(0, 0, 0)).value(); WarningText = settings->value("WarningText", QColor(255, 0, 0)).value(); inputBackground = settings->value("inputBackground", QColor(255, 255, 255)).value(); inputText = settings->value("inputText", QColor(0, 0, 0)).value(); delete(settings); } void SavePortSettings(int Chan); void saveAX25Param(const char * key, QVariant Value) { char fullKey[64]; sprintf(fullKey, "%s/%s", Prefix, key); settings->setValue(fullKey, Value); } void saveAX25Params(int chan) { Prefix[5] = chan + 'A'; SavePortSettings(chan); } void SavePortSettings(int Chan) { saveAX25Param("Retries", fracks[Chan]); saveAX25Param("Maxframe", maxframe[Chan]); saveAX25Param("Paclen", kisspaclen[Chan]); saveAX25Param("FrackTime", frack_time[Chan]); saveAX25Param("IdleTime", idletime[Chan]); saveAX25Param("SlotTime", slottime[Chan]); saveAX25Param("Persist", persist[Chan]); saveAX25Param("RespTime", resptime[Chan]); saveAX25Param("TXFrmMode", TXFrmMode[Chan]); saveAX25Param("FrameCollector", max_frame_collector[Chan]); saveAX25Param("ExcludeCallsigns", exclude_callsigns[Chan]); saveAX25Param("ExcludeAPRSFrmType", exclude_APRS_frm[Chan]); saveAX25Param("KISSOptimization", KISS_opt[Chan]); saveAX25Param("DynamicFrack", dyn_frack[Chan]); saveAX25Param("BitRecovery", recovery[Chan]); saveAX25Param("IPOLL", IPOLL[Chan]); saveAX25Param("MyDigiCall", MyDigiCall[Chan]); } extern "C" void SaveSettings() { int i; char Param[512]; char Key[16]; settings = new QSettings(GetConfPath(), QSettings::IniFormat); for (i = 0; i < MAXHOSTS; i++) { sprintf(Key, "HostParams%d", i); EncodeSettingsLine(i, Param); settings->setValue(Key, Param); } settings->setValue("Split", Split); settings->setValue("ChatMode", ChatMode); settings->setValue("AutoTeletext", AutoTeletext); settings->setValue("Bells", Bells); settings->setValue("StripLF", StripLF); settings->setValue("AlertBeep", AlertBeep); settings->setValue("ConnectBeep", ConnectBeep); settings->setValue("CurrentHost", SavedHost); settings->setValue("YAPPPath", YAPPPath); settings->setValue("listenPort", listenPort); settings->setValue("listenEnable", listenEnable); settings->setValue("listenCText", listenCText); settings->setValue("convUTF8", convUTF8); settings->setValue("PTT", PTTPort); settings->setValue("PTTBAUD", PTTBAUD); settings->setValue("PTTMode", PTTMode); settings->setValue("CATHex", CATHex); settings->setValue("PTTOffString", PTTOffString); settings->setValue("PTTOnString", PTTOnString); settings->setValue("pttGPIOPin", pttGPIOPin); settings->setValue("pttGPIOPinR", pttGPIOPinR); settings->setValue("CM108Addr", CM108Addr); settings->setValue("HamLibPort", HamLibPort); settings->setValue("HamLibHost", HamLibHost); settings->setValue("FLRigPort", FLRigPort); settings->setValue("FLRigHost", FLRigHost); // Save Sessions char SessionString[1024]; int SessStringLen; SessStringLen = sprintf(SessionString, "%d|", _sessions.size()); if (TermMode == MDI) { for (int i = 0; i < _sessions.size(); ++i) { Ui_ListenSession * Sess = _sessions.at(i); QRect r = Sess->sw->geometry(); SessStringLen += sprintf(&SessionString[SessStringLen], "%d, %d, %d, %d, %d, %d|", Sess->SessionType, Sess->CurrentHost, r.top(), r.left(), r.bottom(), r.right()); } settings->setValue("Sessions", SessionString); } settings->setValue("AGWEnable", AGWEnable); settings->setValue("AGWMonEnable", AGWMonEnable); settings->setValue("AGWTermCall", AGWTermCall); settings->setValue("AGWBeaconDest", AGWBeaconDest); settings->setValue("AGWBeaconPath", AGWBeaconPath); settings->setValue("AGWBeaconInterval", AGWBeaconInterval); settings->setValue("AGWBeaconPorts", AGWBeaconPorts); settings->setValue("AGWBeaconText", AGWBeaconMsg); settings->setValue("AGWHost", AGWHost); settings->setValue("AGWPort", AGWPortNum); settings->setValue("AGWPaclen", AGWPaclen); settings->setValue("AGWToCalls", AGWToCalls); settings->setValue("KISSEnable", KISSEnable); settings->setValue("MYCALL", MYCALL); settings->setValue("KISSHost", KISSHost); settings->setValue("KISSMode", KISSMode); settings->setValue("KISSPort", KISSPortNum); settings->setValue("KISSSerialPort", SerialPort); settings->setValue("KISSBAUD", KISSBAUD); saveAX25Params(0); settings->setValue("VARAEnable", VARAEnable); settings->setValue("VARATermCall", VARATermCall); settings->setValue("VARAHost", VARAHost); settings->setValue("VARAPort", VARAPortNum); settings->setValue("VARAInit", VARAInit); settings->setValue("VARAPath", VARAPath); settings->setValue("VARAHostHF", VARAHostHF); settings->setValue("VARAPortHF", VARAPortHF); settings->setValue("VARAPathHF", VARAPathHF); settings->setValue("VARAHostFM", VARAHostFM); settings->setValue("VARAPortFM", VARAPortFM); settings->setValue("VARAPathFM", VARAPathFM); settings->setValue("VARAHostSAT", VARAHostSAT); settings->setValue("VARAPortSAT", VARAPortSAT); settings->setValue("VARAPathSAT", VARAPathSAT); settings->setValue("VARA500", VARA500); settings->setValue("VARA2300", VARA2300); settings->setValue("VARA2750", VARA2750); settings->setValue("VARAHF", VARAHF); settings->setValue("VARAFM", VARAFM); settings->setValue("VARASAT", VARASAT); sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", TabType[0], TabType[1], TabType[2], TabType[3], TabType[4], TabType[5], TabType[6], TabType[7], TabType[8], TabType[9]); settings->setValue("TabType", Param); settings->setValue("monBackground", monBackground); settings->setValue("monRxText", monRxText); settings->setValue("monTxText", monTxText); settings->setValue("monOtherText", monOtherText); settings->setValue("termBackground", termBackground); settings->setValue("outputText", outputText); settings->setValue("EchoText", EchoText); settings->setValue("WarningText", WarningText); settings->setValue("inputBackground", inputBackground); settings->setValue("inputText", inputText); settings->sync(); delete(settings); } #include void QtTermTCP::closeEvent(QCloseEvent *event) { QMessageBox::StandardButton resBtn = QMessageBox::question(this, "QtTermTCP", tr("Are you sure?\n"), QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes, QMessageBox::Yes); if (resBtn != QMessageBox::Yes) { event->ignore(); } else { event->accept(); #ifdef USESERIAL if (hPTTDevice) hPTTDevice->close(); #endif if (process) process->close(); } } QtTermTCP::~QtTermTCP() { Ui_ListenSession * Sess; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); if (Sess->clientSocket) { int loops = 100; Sess->clientSocket->disconnectFromHost(); while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState) QThread::msleep(10); } } if (AGWSock && AGWSock->ConnectedState == QAbstractSocket::ConnectedState) { int loops = 100; AGWSock->disconnectFromHost(); QThread::msleep(10); while (AGWSock && loops-- && AGWSock->state() != QAbstractSocket::UnconnectedState) QThread::msleep(10); } if (_server->isListening()) _server->close(); delete(_server); QSettings mysettings(GetConfPath(), QSettings::IniFormat); mysettings.setValue("geometry", saveGeometry()); mysettings.setValue("windowState", saveState()); SaveSettings(); } extern "C" void timer_event(); void QtTermTCP::KISSTimerSlot() { // Runs every 100 mS timer_event(); } void QtTermTCP::MyTimerSlot() { // Runs every 10 seconds Ui_ListenSession * Sess; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); // for (Ui_ListenSession * Sess : _sessions) // { if (Sess == NULL) continue; if (!ChatMode) continue; if (Sess->KISSSession || (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState)) { Sess->SlowTimer++; if (Sess->SlowTimer > 54) // About 9 mins { unsigned char Msg[2] = ""; Sess->SlowTimer = 0; if (Sess->KISSSession) { TAX25Port * ax25 = (TAX25Port *)Sess->KISSSession; if (ax25->status == STAT_LINK) SendtoAX25(Sess->KISSSession, Msg, 1); } else Sess->clientSocket->write("\0", 1); } } } if (AGWEnable) AGWTimer(); if (VARAEnable) VARATimer(); if (KISSEnable) KISSTimer(); } extern "C" void myBeep() { QApplication::beep(); } 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; static Ui_KISSDialog * KISS; static Ui_ColourDialog * COLOURS; QDialog * deviceUI; char NewPTTPort[80]; int newSoundMode = 0; int oldSoundMode = 0; #ifdef USESERIAL QList Ports = QSerialPortInfo::availablePorts(); #endif void QtTermTCP::KISSSlot() { // This runs the KISS Configuration dialog KISS = new(Ui_KISSDialog); QDialog UI; KISS->setupUi(&UI); UI.setFont(*menufont); deviceUI = &UI; KISS->KISSEnable->setChecked(KISSEnable); KISS->MYCALL->setText(MYCALL); // connect(KISS->SerialPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); QStringList items; #ifdef USESERIAL for (const QSerialPortInfo &info : Ports) { items.append(info.portName()); } items.sort(); items.insert(0, "TCP"); #endif for (const QString &info : items) { KISS->SerialPort->addItem(info); } KISS->SerialPort->setCurrentIndex(KISS->SerialPort->findText(SerialPort, Qt::MatchFixedString)); KISS->Speed->setText(QString::number(KISSBAUD)); KISS->Host->setText(KISSHost); KISS->Port->setText(QString::number(KISSPortNum)); KISS->Paclen->setText(QString::number(kisspaclen[0])); KISS->Maxframe->setText(QString::number(maxframe[0])); KISS->Frack->setText(QString::number(frack_time[0])); KISS->Retries->setText(QString::number(fracks[0])); QObject::connect(KISS->okButton, SIGNAL(clicked()), this, SLOT(KISSaccept())); QObject::connect(KISS->cancelButton, SIGNAL(clicked()), this, SLOT(KISSreject())); UI.exec(); } void QtTermTCP::KISSaccept() { QVariant Q; int OldEnable = KISSEnable; char oldSerialPort[64]; int OldPort = KISSPortNum; char oldHost[128]; strcpy(oldSerialPort, SerialPort); strcpy(oldHost, KISSHost); KISSEnable = KISS->KISSEnable->isChecked(); actHost[18]->setVisible(KISSEnable); // Show KISS Connect Line strcpy(MYCALL, KISS->MYCALL->text().toUtf8().toUpper()); memset(axMYCALL, 0, 7); ConvToAX25(MYCALL, axMYCALL); Q = KISS->Port->text(); KISSPortNum = Q.toInt(); Q = KISS->Speed->text(); KISSBAUD = Q.toInt(); strcpy(KISSHost, KISS->Host->text().toUtf8().toUpper()); Q = KISS->SerialPort->currentText(); strcpy(SerialPort, Q.toString().toUtf8()); Q = KISS->Paclen->text(); kisspaclen[0] = Q.toInt(); Q = KISS->Maxframe->text(); maxframe[0] = Q.toInt(); Q = KISS->Frack->text(); frack_time[0] = Q.toInt(); Q = KISS->Retries->text(); fracks[0] = Q.toInt(); myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable); if (KISSEnable != OldEnable || KISSPortNum != OldPort || strcmp(oldHost, KISSHost) != 0 || strcmp(oldSerialPort, SerialPort) != 0) { // (re)start connection if (OldEnable) { if (KISSEnable) Status3->setText("KISS Closed"); else Status3->setText("KISS Disabled"); KISSConnected = 0; if (KISSSock && KISSSock->ConnectedState == QAbstractSocket::ConnectedState) KISSSock->disconnectFromHost(); else if (m_serial) closeSerialPort(); } } delete(KISS); SaveSettings(); deviceUI->accept(); // QSize newSize(this->size()); // QSize oldSize(this->size()); // QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); // QCoreApplication::postEvent(this, myResizeEvent); } void QtTermTCP::KISSreject() { delete(KISS); deviceUI->reject(); } void QtTermTCP::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()); } 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(); } void QtTermTCP::onSocketStateChanged(QAbstractSocket::SocketState socketState) { myTcpSocket* sender = static_cast(QObject::sender()); Ui_ListenSession * Sess = (Ui_ListenSession *)sender->Sess; if (socketState == QAbstractSocket::UnconnectedState) { char Msg[] = "Disconnected\r"; WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red if (TermMode == MDI) { if (Sess->SessionType == Mon) // Mon Only Sess->setWindowTitle("Monitor Session Disconnected"); else Sess->setWindowTitle("Disconnected"); } else if (TermMode == Tabbed) { if (Sess->SessionType == Mon) // Mon Only tabWidget->setTabText(Sess->Tab, "Monitor"); else { char Label[16]; sprintf(Label, "Sess %d", Sess->Tab + 1); tabWidget->setTabText(Sess->Tab, Label); } } else if (TermMode == Single) { if (Sess->AGWMonSession) mythis->setWindowTitle("AGW Monitor Window"); else { if (Sess->SessionType == Mon) // Mon Only this->setWindowTitle("Monitor Session Disconnected"); else this->setWindowTitle("Disconnected"); } } if (Sess->TTActive) { Sess->TTActive = 0; DoTermResize(Sess); } Sess->PortMonString[0] = 0; // delete(Sess->clientSocket); Sess->clientSocket = NULL; discAction->setEnabled(false); if ((Sess->SessionType & Listen)) _sockets.removeOne(sender); else { connectMenu->setEnabled(true); YAPPSend->setEnabled(false); } } else if (socketState == QAbstractSocket::ConnectedState) { char Signon[256]; char Title[128]; // only seems to be triggered for outward connect sprintf(Signon, "%s\r%s\rBPQTERMTCP\r", UserName[Sess->CurrentHost], Password[Sess->CurrentHost]); Sess->clientSocket->write(Signon); discAction->setEnabled(true); YAPPSend->setEnabled(true); connectMenu->setEnabled(false); SendTraceOptions(Sess); Sess->InputMode = 0; Sess->SlowTimer = 0; Sess->MonData = 0; Sess->OutputSaveLen = 0; // Clear any part line Sess->MonSaveLen = 0; // Clear any part line if (Sess->SessionType == Mon) // Mon Only sprintf(Title, "Monitor Session Connected to %s", Host[Sess->CurrentHost]); else { char Label[256]; if (SessName[Sess->CurrentHost][0]) sprintf(Label, "%s(%s)", Host[Sess->CurrentHost], SessName[Sess->CurrentHost]); else strcpy(Label, Host[Sess->CurrentHost]); sprintf(Title, "Connected to %s", Label); } if (TermMode == MDI) Sess->setWindowTitle(Title); else if (TermMode == Tabbed) { if (SessName[Sess->CurrentHost][0]) tabWidget->setTabText(tabWidget->currentIndex(), SessName[Sess->CurrentHost]); else tabWidget->setTabText(tabWidget->currentIndex(), Host[Sess->CurrentHost]); } else if (TermMode == Single) this->setWindowTitle(Title); } } void QtTermTCP::updateWindowMenu() { if (TermMode == MDI) { windowMenu->clear(); windowMenu->addAction(newTermAct); windowMenu->addAction(newMonAct); windowMenu->addAction(newCombinedAct); windowMenu->addSeparator(); windowMenu->addAction(closeAct); windowMenu->addAction(closeAllAct); windowMenu->addSeparator(); windowMenu->addAction(tileAct); windowMenu->addAction(cascadeAct); windowMenu->addSeparator(); windowMenu->addAction(nextAct); windowMenu->addAction(previousAct); windowMenu->addAction(quitAction); windowMenu->addAction(windowMenuSeparatorAct); QList windows = mdiArea->subWindowList(); windowMenuSeparatorAct->setVisible(!windows.isEmpty()); Ui_ListenSession * Sess; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); Sess->actActivate = windowMenu->addAction(Sess->sw->windowTitle()); QAction::connect(Sess->actActivate, SIGNAL(triggered()), this, SLOT(actActivate())); Sess->actActivate->setCheckable(true); Sess->actActivate->setChecked(ActiveSubWindow == Sess->sw); } } else if (TermMode == Tabbed) { windowMenu->clear(); Ui_ListenSession * Sess = (Ui_ListenSession *)tabWidget->currentWidget(); QActionGroup * termGroup = new QActionGroup(this); delete(TabSingle); delete(TabBoth); delete(TabMon); TabSingle = setupMenuLine(nullptr, (char *)"Terminal Only", this, (Sess->SessionType == Term)); TabBoth = setupMenuLine(nullptr, (char *)"Terminal + Monitor", this, (Sess->SessionType == Term + Mon)); TabMon = setupMenuLine(nullptr, (char *)"Monitor Only", this, (Sess->SessionType == Mon)); termGroup->addAction(TabSingle); termGroup->addAction(TabBoth); termGroup->addAction(TabMon); windowMenu->addAction(TabSingle); windowMenu->addAction(TabBoth); windowMenu->addAction(TabMon); } } Ui_ListenSession::~Ui_ListenSession() { if (this->clientSocket) { int loops = 100; this->clientSocket->disconnectFromHost(); while (loops-- && this->clientSocket->state() != QAbstractSocket::UnconnectedState) QThread::msleep(10); } } extern "C" void setTraceOff(Ui_ListenSession * Sess) { if ((Sess->SessionType & Mon) == 0) return; // Not Monitor if (Sess->AGWMonSession) return; char Buffer[80]; int Len = sprintf(Buffer, "\\\\\\\\0 0 0 0 0 0 0 0\r"); SocketFlush(Sess); SocketSend(Sess, Buffer, Len); SocketFlush(Sess); } extern "C" void SendTraceOptions(Ui_ListenSession * Sess) { if ((Sess->SessionType & Mon) == 0) return; // Not Monitor if (Sess->AGWMonSession) return; char Buffer[80]; int Len = sprintf(Buffer, "\\\\\\\\%llx %x %x %x %x %x %x %x\r", Sess->portmask, Sess->mtxparam, Sess->mcomparam, Sess->MonitorNODES, Sess->MonitorColour, Sess->monUI, 0, 1); strcpy(&MonParams[Sess->CurrentHost][0], &Buffer[4]); SaveSettings(); SocketFlush(Sess); SocketSend(Sess, Buffer, Len); SocketFlush(Sess); } void QtTermTCP::doNewTerm() { newWindow(this, Term); } void QtTermTCP::doNewMon() { newWindow(this, Mon); } void QtTermTCP::doNewCombined() { newWindow(this, Term + Mon); } void QtTermTCP::doCascade() { // Qt Cascade Minimizes windows so do it ourselves int x = 0, y = 0; Ui_ListenSession * Sess; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); Sess->sw->move(x, y); x += 14; y += 30; } } void QtTermTCP::actActivate() { QAction * sender = static_cast(QObject::sender()); Ui_ListenSession * Sess; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); if (Sess->actActivate == sender) { mdiArea->setActiveSubWindow(Sess->sw); return; } } } void QtTermTCP::xon_mdiArea_changed() { // This is triggered when the Active MDI window changes // and is used to enable/disable Connect, Disconnect and YAPP Send QMdiSubWindow *SW = mdiArea->activeSubWindow(); // Dont waste time if not changed if (ActiveSubWindow == SW) return; ActiveSubWindow = SW; Ui_ListenSession * Sess; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); // for (Ui_ListenSession * Sess : _sessions) // { if (Sess->sw == SW) { ActiveSession = Sess; if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) { discAction->setEnabled(true); YAPPSend->setEnabled(true); connectMenu->setEnabled(false); } else if (Sess->AGWMonSession) { // Connected AGW Monitor Session discAction->setEnabled(false); YAPPSend->setEnabled(false); connectMenu->setEnabled(false); } else if (Sess->AGWSession || Sess->KISSSession) { // Connected AGW or KISS Terminal Session discAction->setEnabled(true); YAPPSend->setEnabled(true); connectMenu->setEnabled(false); } else { // Not connected discAction->setEnabled(false); YAPPSend->setEnabled(false); if ((Sess->SessionType & Listen)) // Listen Sessions can't connect connectMenu->setEnabled(false); else connectMenu->setEnabled(true); } // If a monitor Window, change Monitor config settings if (Sess->PortMonString[0]) { char * ptr = (char *)malloc(1024); memcpy(ptr, Sess->PortMonString, 1024); 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 < 32; 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 = 33; if (Sess->portmask & (1ll << (portnum - 1))) SetPortMonLine(portnum, msg, 1, 1); else SetPortMonLine(portnum, msg, 1, 0); } free(ptr); MonTX->setChecked(Sess->mtxparam); MonSup->setChecked(Sess->mcomparam); MonUI->setChecked(Sess->monUI); MonNodes->setChecked(Sess->MonitorNODES); MonColour->setChecked(Sess->MonitorColour); } return; } } } void QtTermTCP::doFonts() { fontDialog * xx = new fontDialog(0); xx->exec(); } void QtTermTCP::doMFonts() { fontDialog * xx = new fontDialog(1); xx->exec(); } QColor TempmonBackground = monBackground; QColor TemptermBackground = termBackground; QColor TempinputBackground = inputBackground; QColor TempmonRxText = monRxText; QColor TempmonTxText = monTxText; QColor TempmonOtherText = monOtherText; QColor TempoutputText = outputText; QColor TempEchoText = EchoText; QColor TempWarningText = WarningText; QColor TempinputText = inputText; void setDialogColours() { char monStyle[128]; sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", TempmonOtherText.red(), TempmonOtherText.green(), TempmonOtherText.blue(), TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); COLOURS->MonitorBG->setStyleSheet(monStyle); COLOURS->MonOther->setStyleSheet(monStyle); sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", TempmonTxText.red(), TempmonTxText.green(), TempmonTxText.blue(), TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); COLOURS->MonTX->setStyleSheet(monStyle); sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", TempmonRxText.red(), TempmonRxText.green(), TempmonRxText.blue(), TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); COLOURS->MonRX->setStyleSheet(monStyle); sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", TempoutputText.red(), TempoutputText.green(), TempoutputText.blue(), TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); COLOURS->TermBG->setStyleSheet(monStyle); COLOURS->TermNormal->setStyleSheet(monStyle); sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", TempEchoText.red(), TempEchoText.green(), TempEchoText.blue(), TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); COLOURS->Echoed->setStyleSheet(monStyle); sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", TempWarningText.red(), TempWarningText.green(), TempWarningText.blue(), TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); COLOURS->Warning->setStyleSheet(monStyle); sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", TempinputText.red(), TempinputText.green(), TempinputText.blue(), TempinputBackground.red(), TempinputBackground.green(), TempinputBackground.blue()); COLOURS->InputBG->setStyleSheet(monStyle); COLOURS->InputColour->setStyleSheet(monStyle); } void QtTermTCP::doColours() { COLOURS = new(Ui_ColourDialog); QDialog UI; COLOURS->setupUi(&UI); UI.setFont(*menufont); deviceUI = &UI; TempmonBackground = monBackground; TempmonRxText = monRxText; TempmonTxText = monTxText; TempmonOtherText = monOtherText; TemptermBackground = termBackground; TempoutputText = outputText; TempEchoText = EchoText; TempWarningText = WarningText; TempinputBackground = inputBackground; TempinputText = inputText; setDialogColours(); QObject::connect(COLOURS->MonitorBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->TermBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->InputBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->MonRX, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->MonTX, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->MonOther, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->TermNormal, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->Echoed, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->Warning, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->InputColour, SIGNAL(clicked()), this, SLOT(ColourPressed())); QObject::connect(COLOURS->okButton, SIGNAL(clicked()), this, SLOT(Colouraccept())); QObject::connect(COLOURS->cancelButton, SIGNAL(clicked()), this, SLOT(Colourreject())); UI.exec(); } void QtTermTCP::ColourPressed() { char Name[32]; strcpy(Name, sender()->objectName().toUtf8()); if (strcmp(Name, "MonitorBG") == 0) TempmonBackground = setColor(TempmonBackground); else if (strcmp(Name, "MonTX") == 0) TempmonTxText = setColor(TempmonTxText); else if (strcmp(Name, "MonRX") == 0) TempmonRxText = setColor(TempmonRxText); else if (strcmp(Name, "MonOther") == 0) TempmonOtherText = setColor(TempmonOtherText); else if (strcmp(Name, "TermBG") == 0) TemptermBackground = setColor(TemptermBackground); else if (strcmp(Name, "InputBG") == 0) TempinputBackground = setColor(TempinputBackground); else if (strcmp(Name, "InputColour") == 0) TempinputText = setColor(TempinputText); else if (strcmp(Name, "TermNormal") == 0) TempoutputText = setColor(TempoutputText); else if (strcmp(Name, "Echoed") == 0) TempEchoText = setColor(TempEchoText); else if (strcmp(Name, "Warning") == 0) TempWarningText = setColor(TempWarningText); setDialogColours(); } void QtTermTCP::Colouraccept() { monBackground = TempmonBackground; monRxText = TempmonRxText; monTxText = TempmonTxText; monOtherText = TempmonOtherText; termBackground = TemptermBackground; EchoText = TempEchoText; WarningText = TempWarningText; outputText = TempoutputText; inputBackground = TempinputBackground; inputText = TempinputText; // Set background colour for new windows sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);", monBackground.red(), monBackground.green(), monBackground.blue()); sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);", termBackground.red(), termBackground.green(), termBackground.blue()); sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", inputText.red(), inputText.green(), inputText.blue(), inputBackground.red(), inputBackground.green(), inputBackground.blue()); // Update existing windows for (int i = 0; i < _sessions.size(); ++i) { Ui_ListenSession * S = _sessions.at(i); if (S->monWindow) S->monWindow->setStyleSheet(monStyleSheet); if (S->termWindow) S->termWindow->setStyleSheet(termStyleSheet); if (S->inputWindow) S->inputWindow->setStyleSheet(inputStyleSheet); } delete(COLOURS); SaveSettings(); deviceUI->accept(); } void QtTermTCP::Colourreject() { delete(COLOURS); deviceUI->reject(); } void QtTermTCP::ConnecttoVARA() { delete(VARASock); VARASock = new myTcpSocket(); connect(VARASock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(VARAdisplayError(QAbstractSocket::SocketError))); connect(VARASock, SIGNAL(readyRead()), this, SLOT(VARAreadyRead())); connect(VARASock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onVARASocketStateChanged(QAbstractSocket::SocketState))); VARASock->connectToHost(VARAHost, VARAPortNum); Status2->setText("VARA Control Connecting"); return; } void QtTermTCP::VARATimer() { // Runs every 10 Seconds if (VARAConnected == 0 && VARAConnecting == 0) { if (process == nullptr || process->state() == QProcess::NotRunning) { if (VARAPath[0]) { process = new QProcess(this); QString file = VARAPath; process->start(file); } } QThread::msleep(1000); VARAConnecting = true; ConnecttoVARA(); } } void QtTermTCP::VARAdisplayError(QAbstractSocket::SocketError socketError) { switch (socketError) { case QAbstractSocket::RemoteHostClosedError: break; case QAbstractSocket::HostNotFoundError: QMessageBox::information(this, tr("QtTermTCP"), tr("VARA host was not found. Please check the " "host name and portsettings->")); Status2->setText("VARA Connection Failed"); break; case QAbstractSocket::ConnectionRefusedError: Status2->setText("VARA Connection Refused"); break; default: Status2->setText("VARA Connection Failed"); } VARAConnecting = 0; VARAConnected = 0; } void QtTermTCP::VARAreadyRead() { int Read; char Buffer[4096]; char * ptr; char * Msg; myTcpSocket* Socket = static_cast(QObject::sender()); // read the data from the socket Read = Socket->read((char *)Buffer, 4095); Buffer[Read] = 0; Msg = Buffer; ptr = strchr(Msg, 0x0d); while (ptr) { *ptr++ = 0; if (strcmp(Msg, "IAMALIVE") == 0) { } else if (strcmp(Msg, "PTT ON") == 0) { RadioPTT(1); } else if (strcmp(Msg, "PTT OFF") == 0) { RadioPTT(0); } else if (strcmp(Msg, "PENDING") == 0) { } else if (strcmp(Msg, "CANCELPENDING") == 0) { } else if (strcmp(Msg, "OK") == 0) { } else if (memcmp(Msg, "CONNECTED ", 10) == 0) { Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess; char Title[128] = ""; char CallFrom[64] = ""; char CallTo[64] = ""; char Mode[64] = ""; char Message[128]; int n; sscanf(&Msg[10], "%s %s %s", CallFrom, CallTo, Mode); if (Sess) { if (Mode[0]) sprintf(Title, "Connected to %s %s Mode", CallTo, Mode); else sprintf(Title, "Connected to %s", CallTo); n = sprintf(Message, "%s\r\n", Title); WritetoOutputWindow(Sess, (unsigned char *)Message, n); if (TermMode == MDI) Sess->setWindowTitle(Title); else if (TermMode == Tabbed) tabWidget->setTabText(Sess->Tab, CallTo); else if (TermMode == Single) mythis->setWindowTitle(Title); setMenus(true); } else { // Incoming Call Ui_ListenSession * S; int i = 0; if (TermMode == MDI) { // See if an old session can be reused for (int i = 0; i < _sessions.size(); ++i) { S = _sessions.at(i); // for (Ui_ListenSession * S: _sessions) // { if ((S->SessionType & Listen) && S->clientSocket == NULL) { Sess = S; break; } } // Create a window if none found, else reuse old if (Sess == NULL) { Sess = newWindow(this, Listen); } } else { // Single or Tabbed - look for free session for (i = 0; i < _sessions.size(); ++i) { S = _sessions.at(i); if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL) { Sess = S; break; } } } if (Sess == NULL) { // Clear connection VARASock->write("DISCONNECT\r"); } else { if (Mode[0]) { sprintf(Title, "Connected to %s Mode %s", CallFrom, Mode); n = sprintf(Message, "Incoming Connected from %s %s Mode\r\n", CallFrom, Mode); } else { sprintf(Title, "Connected to %s", CallFrom); n = sprintf(Message, "Incoming Connected from %s\r\n", CallFrom); } WritetoOutputWindow(Sess, (unsigned char *)Message, n); VARASock->Sess = Sess; VARADataSock->Sess = Sess; if (TermMode == MDI) Sess->setWindowTitle(Title); else if (TermMode == Tabbed) tabWidget->setTabText(Sess->Tab, CallFrom); else if (TermMode == Single) mythis->setWindowTitle(Title); setMenus(true); } } } else if (strcmp(Msg, "DISCONNECTED") == 0) { Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess; if (Sess) { WritetoOutputWindow(Sess, (unsigned char *)"Disconnected\r\n", 14); VARASock->Sess = 0; VARADataSock->Sess = 0; if (TermMode == MDI) { if (Sess->SessionType == Mon) // Mon Only Sess->setWindowTitle("Monitor Session Disconnected"); else Sess->setWindowTitle("Disconnected"); } else if (TermMode == Tabbed) { if (Sess->SessionType == Mon) // Mon Only tabWidget->setTabText(Sess->Tab, "Monitor"); else { char Label[16]; sprintf(Label, "Sess %d", Sess->Tab + 1); tabWidget->setTabText(Sess->Tab, Label); } } else if (TermMode == Single) { if (Sess->AGWMonSession) mythis->setWindowTitle("AGW Monitor Window"); else { if (Sess->SessionType == Mon) // Mon Only this->setWindowTitle("Monitor Session Disconnected"); else this->setWindowTitle("Disconnected"); } } setMenus(false); } } Msg = ptr; ptr = strchr(Msg, 0x0d); } } void QtTermTCP::onVARASocketStateChanged(QAbstractSocket::SocketState socketState) { // myTcpSocket* sender = static_cast(QObject::sender()); if (socketState == QAbstractSocket::UnconnectedState) { // Close any connections Status2->setText("VARA Disconnected"); actHost[17]->setVisible(0); VARAConnecting = VARAConnected = 0; } else if (socketState == QAbstractSocket::ConnectedState) { // Connect Data Session. Leave Connecting till that completes VARADataSock = new myTcpSocket(); connect(VARADataSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(VARADatadisplayError(QAbstractSocket::SocketError))); connect(VARADataSock, SIGNAL(readyRead()), this, SLOT(VARADatareadyRead())); connect(VARADataSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onVARADataSocketStateChanged(QAbstractSocket::SocketState))); VARADataSock->connectToHost(VARAHost, VARAPortNum + 1); Status2->setText("VARA Data Connecting"); } } void QtTermTCP::VARADatadisplayError(QAbstractSocket::SocketError socketError) { switch (socketError) { case QAbstractSocket::RemoteHostClosedError: break; case QAbstractSocket::HostNotFoundError: QMessageBox::information(this, tr("QtTermTCP"), tr("VARA host was not found. Please check the " "host name and portsettings->")); Status2->setText("VARA Connection Failed"); break; case QAbstractSocket::ConnectionRefusedError: Status2->setText("VARA Connection Refused"); break; default: Status2->setText("VARA Connection Failed"); } VARAConnecting = 0; VARAConnected = 0; } void QtTermTCP::VARADatareadyRead() { int Read; unsigned char Buffer[4096]; myTcpSocket* Socket = static_cast(QObject::sender()); Ui_ListenSession * Sess = (Ui_ListenSession *)Socket->Sess; // read the data from the socket Read = Socket->read((char *)Buffer, 2047); while (Read > 0) { // if (InputMode == 'Y') // Yapp // { // QString myString = QString::fromUtf8((char*)Buffer, Read); // QByteArray ptr = myString.toLocal8Bit(); // memcpy(Buffer, ptr.data(), ptr.length()); // Read = ptr.length(); // } ProcessReceivedData(Sess, Buffer, Read); QString myString = QString::fromUtf8((char*)Buffer); // qDebug() << myString; Read = Socket->read((char *)Buffer, 2047); } } void QtTermTCP::onVARADataSocketStateChanged(QAbstractSocket::SocketState socketState) { // myTcpSocket* sender = static_cast(QObject::sender()); if (socketState == QAbstractSocket::UnconnectedState) { // Close any connections Status2->setText("VARA Disconnected"); actHost[17]->setVisible(0); VARAConnecting = VARAConnected = 0; } else if (socketState == QAbstractSocket::ConnectedState) { char VARACommand[256]; VARAConnected = 1; VARAConnecting = 0; Status2->setText("VARA Connected"); actHost[17]->setVisible(1); // Enable VARA Connect Line sprintf(VARACommand, "MYCALL %s\r", VARATermCall); VARASock->write(VARACommand); if (VARA500) VARASock->write("BW500\r"); else if (VARA2300) VARASock->write("BW2300\r"); else if (VARA2750) VARASock->write("BW2750\r"); VARASock->write("COMPRESSION FILES\r"); if (VARAInit[0]) { char Copy[512]; char * param, *context; strcpy(Copy, VARAInit); param = strtok_s(Copy, ",", &context); while (param && param[0]) { sprintf(VARACommand, "%s\r", param); VARASock->write(VARACommand); param = strtok_s(nullptr, ",", &context); } } if (listenEnable) VARASock->write("LISTEN ON\r"); } } // PTT Stuff #include "hidapi.h" // Serial Port Stuff QTcpSocket * HAMLIBsock; int HAMLIBConnected = 0; int HAMLIBConnecting = 0; void QtTermTCP::HAMLIBdisplayError(QAbstractSocket::SocketError socketError) { switch (socketError) { case QAbstractSocket::RemoteHostClosedError: break; case QAbstractSocket::HostNotFoundError: QMessageBox::information(nullptr, tr("QtSM"), "HAMLIB host was not found. Please check the " "host name and portsettings->"); break; case QAbstractSocket::ConnectionRefusedError: qDebug() << "HAMLIB Connection Refused"; break; default: qDebug() << "HAMLIB Connection Failed"; break; } HAMLIBConnecting = 0; HAMLIBConnected = 0; } void QtTermTCP::HAMLIBreadyRead() { unsigned char Buffer[4096]; QTcpSocket* Socket = static_cast(QObject::sender()); // read the data from the socket. Don't do anyhing with it at the moment Socket->read((char *)Buffer, 4095); } void QtTermTCP::onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState) { if (socketState == QAbstractSocket::UnconnectedState) { // Close any connections HAMLIBConnected = 0; HAMLIBConnecting = 0; // delete (HAMLIBsock); // HAMLIBsock = 0; qDebug() << "HAMLIB Connection Closed"; } else if (socketState == QAbstractSocket::ConnectedState) { HAMLIBConnected = 1; HAMLIBConnecting = 0; qDebug() << "HAMLIB Connected"; } } void QtTermTCP::ConnecttoHAMLIB() { delete(HAMLIBsock); HAMLIBConnected = 0; HAMLIBConnecting = 1; HAMLIBsock = new QTcpSocket(); connect(HAMLIBsock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(HAMLIBdisplayError(QAbstractSocket::SocketError))); connect(HAMLIBsock, SIGNAL(readyRead()), this, SLOT(HAMLIBreadyRead())); connect(HAMLIBsock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onHAMLIBSocketStateChanged(QAbstractSocket::SocketState))); HAMLIBsock->connectToHost(HamLibHost, HamLibPort); return; } void QtTermTCP::HAMLIBSetPTT(int PTTState) { char Msg[16]; if (HAMLIBsock == nullptr || HAMLIBsock->state() != QAbstractSocket::ConnectedState) ConnecttoHAMLIB(); if (HAMLIBsock == nullptr || HAMLIBsock->state() != QAbstractSocket::ConnectedState) return; sprintf(Msg, "T %d\r\n", PTTState); HAMLIBsock->write(Msg); HAMLIBsock->waitForBytesWritten(3000); QByteArray datas = HAMLIBsock->readAll(); qDebug(datas.data()); } QTcpSocket * FLRigsock; int FLRigConnected = 0; int FLRigConnecting = 0; void QtTermTCP::FLRigdisplayError(QAbstractSocket::SocketError socketError) { switch (socketError) { case QAbstractSocket::RemoteHostClosedError: break; case QAbstractSocket::HostNotFoundError: QMessageBox::information(nullptr, tr("QtSM"), "FLRig host was not found. Please check the " "host name and portsettings->"); break; case QAbstractSocket::ConnectionRefusedError: qDebug() << "FLRig Connection Refused"; break; default: qDebug() << "FLRig Connection Failed"; break; } FLRigConnecting = 0; FLRigConnected = 0; } void QtTermTCP::FLRigreadyRead() { unsigned char Buffer[4096]; QTcpSocket* Socket = static_cast(QObject::sender()); // read the data from the socket. Don't do anyhing with it at the moment Socket->read((char *)Buffer, 4095); } void QtTermTCP::onFLRigSocketStateChanged(QAbstractSocket::SocketState socketState) { if (socketState == QAbstractSocket::UnconnectedState) { // Close any connections FLRigConnected = 0; FLRigConnecting = 0; // delete (FLRigsock); // FLRigsock = 0; qDebug() << "FLRig Connection Closed"; } else if (socketState == QAbstractSocket::ConnectedState) { FLRigConnected = 1; FLRigConnecting = 0; qDebug() << "FLRig Connected"; } } void QtTermTCP::ConnecttoFLRig() { delete(FLRigsock); FLRigConnected = 0; FLRigConnecting = 1; FLRigsock = new QTcpSocket(); connect(FLRigsock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(FLRigdisplayError(QAbstractSocket::SocketError))); connect(FLRigsock, SIGNAL(readyRead()), this, SLOT(FLRigreadyRead())); connect(FLRigsock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onFLRigSocketStateChanged(QAbstractSocket::SocketState))); FLRigsock->connectToHost(FLRigHost, FLRigPort); return; } static char MsgHddr[] = "POST /RPC2 HTTP/1.1\r\n" "User-Agent: XMLRPC++ 0.8\r\n" "Host: 127.0.0.1:7362\r\n" "Content-Type: text/xml\r\n" "Content-length: %d\r\n" "\r\n%s"; static char Req[] = "\r\n" "%s\r\n" "%s" "\r\n"; void QtTermTCP::FLRigSetPTT(int PTTState) { int Len; char ReqBuf[512]; char SendBuff[512]; char ValueString[256] = ""; sprintf(ValueString, "%d", PTTState); Len = sprintf(ReqBuf, Req, "rig.set_ptt", ValueString); Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf); if (FLRigsock == nullptr || FLRigsock->state() != QAbstractSocket::ConnectedState) ConnecttoFLRig(); if (FLRigsock == nullptr || FLRigsock->state() != QAbstractSocket::ConnectedState) return; FLRigsock->write(SendBuff); FLRigsock->waitForBytesWritten(3000); QByteArray datas = FLRigsock->readAll(); qDebug(datas.data()); } void QtTermTCP::CATChanged(bool State) { UNUSED(State); PTTPortChanged(0); } void QtTermTCP::VARAHFChanged(bool State) { Dev->HFMode->setVisible(State); if (State) { Dev->TNCInfo->setTitle("VARA HF Paramters"); Dev->Host->setText(VARAHostHF); Dev->Port->setText(QString::number(VARAPortHF)); Dev->Path->setText(VARAPathHF); } } void QtTermTCP::VARAFMChanged(bool State) { if (State) { Dev->TNCInfo->setTitle("VARA FM Paramters"); Dev->Host->setText(VARAHostFM); Dev->Port->setText(QString::number(VARAPortFM)); Dev->Path->setText(VARAPathFM); } } void QtTermTCP::VARASATChanged(bool State) { if (State) { Dev->TNCInfo->setTitle("VARA SAT Paramters"); Dev->Host->setText(VARAHostSAT); Dev->Port->setText(QString::number(VARAPortSAT)); Dev->Path->setText(VARAPathSAT); } } void QtTermTCP::SetVARAParams() { Dev->Host->setText(VARAHost); Dev->Port->setText(QString::number(VARAPortNum)); Dev->Path->setText(VARAPath); Dev->InitCommands->setText(VARAInit); } void QtTermTCP::PTTPortChanged(int Selected) { UNUSED(Selected); QVariant Q = Dev->PTTPort->currentText(); strcpy(NewPTTPort, Q.toString().toUtf8()); Dev->RTSDTR->setVisible(false); Dev->CAT->setVisible(false); Dev->PTTOnLab->setVisible(false); Dev->PTTOn->setVisible(false); Dev->PTTOff->setVisible(false); Dev->PTTOffLab->setVisible(false); Dev->CATLabel->setVisible(false); Dev->CATSpeed->setVisible(false); Dev->CATHex->setVisible(false); Dev->CATText->setVisible(false); Dev->GPIOLab->setVisible(false); Dev->GPIOLeft->setVisible(false); Dev->GPIORight->setVisible(false); Dev->GPIOLab2->setVisible(false); Dev->CM108Label->setVisible(false); Dev->VIDPID->setVisible(false); if (strcmp(NewPTTPort, "None") == 0) { } else if (strcmp(NewPTTPort, "GPIO") == 0) { Dev->GPIOLab->setVisible(true); Dev->GPIOLeft->setVisible(true); } else if (strcmp(NewPTTPort, "CM108") == 0) { Dev->CM108Label->setVisible(true); #ifdef WIN32 Dev->CM108Label->setText("CM108 VID/PID"); #else Dev->CM108Label->setText("CM108 Device"); #endif Dev->VIDPID->setText(CM108Addr); Dev->VIDPID->setVisible(true); } else if (strcmp(NewPTTPort, "HAMLIB") == 0) { Dev->CM108Label->setVisible(true); Dev->CM108Label->setText("rigctrld Port"); Dev->VIDPID->setText(QString::number(HamLibPort)); Dev->VIDPID->setVisible(true); Dev->PTTOnLab->setText("rigctrld Host"); Dev->PTTOnLab->setVisible(true); Dev->PTTOn->setText(HamLibHost); Dev->PTTOn->setVisible(true); } else if (strcmp(NewPTTPort, "FLRIG") == 0) { Dev->CM108Label->setVisible(true); Dev->CM108Label->setText("FLRig Port"); Dev->VIDPID->setText(QString::number(FLRigPort)); Dev->VIDPID->setVisible(true); Dev->PTTOnLab->setText("FLRig Host"); Dev->PTTOnLab->setVisible(true); Dev->PTTOn->setText(FLRigHost); Dev->PTTOn->setVisible(true); } else { Dev->RTSDTR->setVisible(true); Dev->CAT->setVisible(true); if (Dev->CAT->isChecked()) { Dev->CATHex->setVisible(true); Dev->CATText->setVisible(true); Dev->PTTOnLab->setVisible(true); Dev->PTTOnLab->setText("PTT On String"); Dev->PTTOn->setText(PTTOnString); Dev->PTTOn->setVisible(true); Dev->PTTOff->setVisible(true); Dev->PTTOffLab->setVisible(true); Dev->PTTOff->setVisible(true); Dev->PTTOff->setText(PTTOffString); Dev->CATLabel->setVisible(true); Dev->CATSpeed->setVisible(true); Dev->CATSpeed->setText(QString::number(PTTBAUD)); } } } void DecodeCM108(char * ptr) { // Called if Device Name or PTT = Param is CM108 #ifdef WIN32 // Next Param is VID and PID - 0xd8c:0x8 or Full device name // On Windows device name is very long and difficult to find, so // easier to use VID/PID, but allow device in case more than one needed char * next; long VID = 0, PID = 0; char product[256] = "Unknown"; struct hid_device_info *devs, *cur_dev; const char *path_to_open = NULL; hid_device *handle = NULL; if (strlen(ptr) > 16) CM108Device = _strdup(ptr); else { VID = strtol(ptr, &next, 0); if (next) PID = strtol(++next, &next, 0); // Look for Device devs = hid_enumerate((unsigned short)VID, (unsigned short)PID); cur_dev = devs; while (cur_dev) { if (cur_dev->product_string) wcstombs(product, cur_dev->product_string, 255); printf("HID Device %s VID %X PID %X", product, cur_dev->vendor_id, cur_dev->product_id); if (cur_dev->vendor_id == VID && cur_dev->product_id == PID) { path_to_open = cur_dev->path; break; } cur_dev = cur_dev->next; } if (path_to_open) { handle = hid_open_path(path_to_open); if (handle) { hid_close(handle); CM108Device = _strdup(path_to_open); } else { printf("Unable to open CM108 device %x %x", VID, PID); } } else printf("Couldn't find CM108 device %x %x", VID, PID); hid_free_enumeration(devs); } #else // Linux - Next Param HID Device, eg /dev/hidraw0 CM108Device = strdup(ptr); #endif } void QtTermTCP::OpenPTTPort() { PTTMode &= ~PTTCM108; PTTMode &= ~PTTHAMLIB; PTTMode &= ~PTTFLRIG; if (PTTPort[0] && strcmp(PTTPort, "None") != 0) { if (PTTMode == PTTCAT) { // convert config strings from Hex if (CATHex == 0) // Ascii Strings { strcpy((char *)PTTOffCmd, PTTOffString); PTTOffCmdLen = strlen(PTTOffString); strcpy((char *)PTTOnCmd, PTTOnString); PTTOnCmdLen = strlen(PTTOnString); } else { char * ptr1 = PTTOffString; unsigned char * ptr2 = PTTOffCmd; char c; int val; while ((c = *(ptr1++))) { val = c - 0x30; if (val > 15) val -= 7; val <<= 4; c = *(ptr1++) - 0x30; if (c > 15) c -= 7; val |= c; *(ptr2++) = val; } PTTOffCmdLen = ptr2 - PTTOffCmd; ptr1 = PTTOnString; ptr2 = PTTOnCmd; while ((c = *(ptr1++))) { val = c - 0x30; if (val > 15) val -= 7; val <<= 4; c = *(ptr1++) - 0x30; if (c > 15) c -= 7; val |= c; *(ptr2++) = val; } PTTOnCmdLen = ptr2 - PTTOnCmd; } } if (strcmp(PTTPort, "GPIO") == 0) { // Initialise GPIO for PTT if available #ifdef __ARM_ARCH // if (gpioInitialise() == 0) // { // printf("GPIO interface for PTT available\n"); // gotGPIO = TRUE; // SetupGPIOPTT(); // } // else // printf("Couldn't initialise GPIO interface for PTT\n"); // #else printf("GPIO interface for PTT not available on this platform\n"); #endif } else if (strcmp(PTTPort, "CM108") == 0) { DecodeCM108(CM108Addr); PTTMode |= PTTCM108; } else if (strcmp(PTTPort, "HAMLIB") == 0) { PTTMode |= PTTHAMLIB; HAMLIBSetPTT(0); // to open port return; } else if (strcmp(PTTPort, "FLRIG") == 0) { PTTMode |= PTTFLRIG; FLRigSetPTT(0); // to open port return; } else // Serial Port { #ifdef USESERIAL hPTTDevice = new QSerialPort(this); hPTTDevice->setPortName(PTTPort); hPTTDevice->setBaudRate(PTTBAUD); hPTTDevice->setDataBits(QSerialPort::Data8); hPTTDevice->setParity(QSerialPort::NoParity); hPTTDevice->setStopBits(QSerialPort::OneStop); hPTTDevice->setFlowControl(QSerialPort::NoFlowControl); if (hPTTDevice->open(QIODevice::ReadWrite)) { qDebug() << "PTT Port Opened"; } else { QMessageBox msgBox; msgBox.setText("PTT COM Port Open Failed."); msgBox.exec(); qDebug() << "PTT Port Open failed"; delete(hPTTDevice); hPTTDevice = 0; } #endif } } } void ClosePTTPort() { #ifdef USESERIAL if (hPTTDevice) hPTTDevice->close(); hPTTDevice = 0; #endif } void CM108_set_ptt(int PTTState) { unsigned char io[5]; int n; io[0] = 0; io[1] = 0; io[2] = 1 << (3 - 1); io[3] = PTTState << (3 - 1); io[4] = 0; if (CM108Device == NULL) return; #ifdef WIN32 hid_device *handle; handle = hid_open_path(CM108Device); if (!handle) { printf("unable to open device\n"); return; } n = hid_write(handle, io, 5); if (n < 0) { printf("Unable to write()\n"); printf("Error: %ls\n", hid_error(handle)); } hid_close(handle); #else int fd; fd = open(CM108Device, O_WRONLY); if (fd == -1) { printf("Could not open %s for write, errno=%d\n", CM108Device, errno); return; } io[0] = 0; io[1] = 0; io[2] = 1 << (3 - 1); io[3] = PTTState << (3 - 1); io[4] = 0; n = write(fd, io, 5); if (n != 5) { printf("Write to %s failed, n=%d, errno=%d\n", CM108Device, n, errno); } close(fd); #endif return; } void QtTermTCP::RadioPTT(bool PTTState) { #ifdef __ARM_ARCH if (useGPIO) { // gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); // return; } #endif if ((PTTMode & PTTCM108)) { CM108_set_ptt(PTTState); return; } if ((PTTMode & PTTHAMLIB)) { HAMLIBSetPTT(PTTState); return; } if ((PTTMode & PTTFLRIG)) { FLRigSetPTT(PTTState); return; } #ifdef USESERIAL if (hPTTDevice == 0) return; if ((PTTMode & PTTCAT)) { if (PTTState) hPTTDevice->write((char *)PTTOnCmd, PTTOnCmdLen); else hPTTDevice->write((char *)PTTOffCmd, PTTOffCmdLen); hPTTDevice->flush(); // hPTTDevice->error(); return; } if ((PTTMode & PTTRTS)) { int n = hPTTDevice->setRequestToSend(PTTState); n = n; } #endif } extern "C" void WriteDebugLog(char * Mess) { qDebug() << Mess; } void QtTermTCP::ConnecttoKISS() { if (strcmp(SerialPort, "TCP") == 0) { delete(KISSSock); KISSSock = new myTcpSocket(); KISSSockCopy[0] = (void *)KISSSock; connect(KISSSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(KISSdisplayError(QAbstractSocket::SocketError))); connect(KISSSock, SIGNAL(readyRead()), this, SLOT(KISSreadyRead())); connect(KISSSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onKISSSocketStateChanged(QAbstractSocket::SocketState))); KISSSock->connectToHost(KISSHost, KISSPortNum); Status3->setText("KISS Connecting"); } else openSerialPort(); return; } void QtTermTCP::KISSTimer() { // Runs every 10 Seconds if (KISSConnected == 0 && KISSConnecting == 0) { ConnecttoKISS(); } else { // Verify Serial port is still ok if (m_serial && KISSConnected) { m_serial->clearError(); m_serial->isDataTerminalReady(); if (m_serial->error()) { Debugprintf("Serial Port Lost - isOpen %d Error %d", m_serial->isOpen(), m_serial->error()); closeSerialPort(); } } } } void QtTermTCP::KISSdisplayError(QAbstractSocket::SocketError socketError) { switch (socketError) { case QAbstractSocket::RemoteHostClosedError: break; case QAbstractSocket::HostNotFoundError: QMessageBox::information(this, tr("QtTermTCP"), tr("KISS host was not found. Please check the " "host name and portsettings->")); Status3->setText("KISS Connection Failed"); break; case QAbstractSocket::ConnectionRefusedError: Status3->setText("KISS Connection Refused"); break; default: Status3->setText("KISS Connection Failed"); } KISSConnecting = 0; KISSConnected = 0; } extern "C" void KISSSendtoServer(myTcpSocket* Socket, char * Data, int Length) { if (m_serial) { if (m_serial->isOpen()) { m_serial->clearError(); int n = m_serial->write(Data, Length); n = m_serial->flush(); if (m_serial->error()) { Debugprintf("Serial Flush Error - Requested = %d Actual %d Error %d", Length, n, m_serial->error()); closeSerialPort(); } } } else if (Socket) Socket->write(Data, Length); } void QtTermTCP::KISSreadyRead() { int Read; unsigned char Buffer[4096]; myTcpSocket* Socket = static_cast(QObject::sender()); // read the data from the socket Read = Socket->read((char *)Buffer, 4095); KISSDataReceived(Socket, Buffer, Read); } extern "C" void KISS_del_socket(void * socket); extern "C" void KISS_add_stream(void * Socket); void QtTermTCP::onKISSSocketStateChanged(QAbstractSocket::SocketState socketState) { // myTcpSocket* sender = static_cast(QObject::sender()); QTcpSocket* sender = static_cast(QObject::sender()); if (socketState == QAbstractSocket::UnconnectedState) { // Close any connections Ui_ListenSession * Sess = NULL; Status3->setText("KISS Disconnected"); actHost[18]->setEnabled(0); KISSConnecting = KISSConnected = 0; // Free the monitor Window if (KISSMonSess) { Sess = KISSMonSess; if (TermMode == MDI) Sess->setWindowTitle("Monitor Session Disconnected"); else if (TermMode == Tabbed) tabWidget->setTabText(Sess->Tab, "Monitor"); KISSMonSess = nullptr; } KISS_del_socket(sender); KISSSock = NULL; } else if (socketState == QAbstractSocket::ConnectedState) { int i; KISSConnected = 1; KISSConnecting = 0; Status3->setText("KISS Connected"); actHost[18]->setEnabled(1); // Enable KISS Connect Line KISS_add_stream(sender); // Attach a Monitor Window if available Ui_ListenSession * Sess = NULL; Ui_ListenSession * S; if (TermMode == MDI) { // See if an old session can be reused for (int i = 0; i < _sessions.size(); ++i) { S = _sessions.at(i); // for (Ui_ListenSession * S: _sessions) // { if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL) { Sess = S; break; } } // Create a window if none found, else reuse old if (Sess == NULL) { Sess = newWindow((QObject *)mythis, Mon, ""); } } else if (TermMode == Tabbed) { // Tabbed - look for free session for (i = 8; i; i--) { S = _sessions.at(i); if (S->clientSocket == NULL && S->KISSSession == NULL) { Sess = S; break; } } } else if (TermMode == Single && (singlemodeFormat & Mon)) { S = _sessions.at(0); if (S->clientSocket == NULL && S->KISSSession == NULL) Sess = S; } if (Sess) { KISSMonSess = Sess; // Flag as in use if (TermMode == MDI) Sess->setWindowTitle("KISS Monitor Window"); else if (TermMode == Tabbed) tabWidget->setTabText(Sess->Tab, "KISS Mon"); else if (TermMode == Single) mythis->setWindowTitle("KISS Monitor Window"); // if (TermMode == Single) // { // discAction->setEnabled(false); // YAPPSend->setEnabled(false); // connectMenu->setEnabled(false); // } } } } extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat); extern "C" char * ShortDateTime(); extern "C" void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded) { UNUSED(excluded); UNUSED(snd_ch); int Len; char Msg[1024]; if (tx) sprintf(Msg, "\x1b\x10%s", frame_monitor(frame, code, tx)); else sprintf(Msg, "\x1b\x11%s", frame_monitor(frame, code, tx)); Len = strlen(Msg); if (Msg[Len - 1] != '\r') { Msg[Len++] = '\r'; Msg[Len] = 0; } if (KISSMonSess) WritetoMonWindow(KISSMonSess, (unsigned char *)Msg, Len); } extern "C" Ui_ListenSession * ax25IncommingConnect(TAX25Port * AX25Sess) { // Look for/create Terminal Window for connection Ui_ListenSession * Sess = NULL; Ui_ListenSession * S; char Title[80]; int i = 0; if (TermMode == MDI) { // See if an old session can be reused for (int i = 0; i < _sessions.size(); ++i) { S = _sessions.at(i); if ((S->SessionType & Listen) && S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) { Sess = S; break; } } // Create a window if none found, else reuse old if (Sess == NULL) { Sess = newWindow((QObject *)mythis, Listen, ""); } } else { // Single or Tabbed - look for free session for (i = 0; i < _sessions.size(); ++i) { S = _sessions.at(i); if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) { Sess = S; break; } } if (Sess == NULL) { // Clear connection return NULL; } } if (Sess) { sprintf(Title, "Connected to %s", AX25Sess->corrcall); if (TermMode == MDI) { Sess->setWindowTitle(Title); } else if (TermMode == Tabbed) { tabWidget->setTabText(i, AX25Sess->corrcall); } else if (TermMode == Single) mythis->setWindowTitle(Title); AX25Sess->port = 0; AX25Sess->Sess = Sess; // Crosslink AGW and Term Sessions AX25Sess->PID = 240;; Sess->KISSSession = AX25Sess; setMenus(true); if (ConnectBeep) myBeep(); // Send CText if defined if (listenCText[0]) SendtoAX25(Sess->KISSSession, (unsigned char *)listenCText, (int)strlen(listenCText)); } return Sess; } extern "C" void AX25_disc(TAX25Port * AX25Sess, Byte mode) { char Msg[128]; int Len = 0; Ui_ListenSession * Sess = (Ui_ListenSession *)AX25Sess->Sess; if (AX25Sess->status == STAT_TRY_LINK) { // Connect failed Len = sprintf(Msg, "Connection to %s failed\r", AX25Sess->corrcall); } else { switch (mode) { case MODE_OTHER: case MODE_OUR: Len = sprintf(Msg, "Disconnected from %s\r", AX25Sess->corrcall); break; case MODE_RETRY: Len = sprintf(Msg, "Disconnected from %s - Retry count exceeded\r", AX25Sess->corrcall); break; }; } SendtoTerm(Sess, Msg, Len); ClearSessLabel(Sess); Sess->KISSSession = NULL; AX25Sess->Sess = 0; setMenus(0); }; int QtTermTCP::openSerialPort() { if (m_serial && m_serial->isOpen()) { m_serial->close(); } m_serial = nullptr; m_serial = new QSerialPort(this); m_serial->setPortName(SerialPort); m_serial->setBaudRate(KISSBAUD); if (m_serial->open(QIODevice::ReadWrite)) { int i; connect(m_serial, &QSerialPort::readyRead, this, &QtTermTCP::readSerialData); // connect(m_serial, &QSerialPort::errorOccurred, this, &QtTermTCP::handleError); KISSConnected = 1; KISSConnecting = 0; Status3->setText("KISS Connected"); actHost[18]->setEnabled(1); // Enable KISS Connect Line KISS_add_stream(m_serial); // Attach a Monitor Window if available Ui_ListenSession * Sess = NULL; Ui_ListenSession * S; if (TermMode == MDI) { // See if an old session can be reused for (int i = 0; i < _sessions.size(); ++i) { S = _sessions.at(i); // for (Ui_ListenSession * S: _sessions) // { if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL) { Sess = S; break; } } // Create a window if none found, else reuse old if (Sess == NULL) { Sess = newWindow((QObject *)mythis, Mon, ""); } } else if (TermMode == Tabbed) { // Tabbed - look for free session for (i = 8; i; i--) { S = _sessions.at(i); if (S->clientSocket == NULL && S->KISSSession == NULL) { Sess = S; break; } } } else if (TermMode == Single && (singlemodeFormat & Mon)) { S = _sessions.at(0); if (S->clientSocket == NULL && S->KISSSession == NULL) Sess = S; } if (Sess) { KISSMonSess = Sess; // Flag as in use if (TermMode == MDI) Sess->setWindowTitle("KISS Monitor Window"); else if (TermMode == Tabbed) tabWidget->setTabText(Sess->Tab, "KISS Mon"); else if (TermMode == Single) mythis->setWindowTitle("KISS Monitor Window"); // if (TermMode == Single) // { // discAction->setEnabled(false); // YAPPSend->setEnabled(false); // connectMenu->setEnabled(false); // } } return 1; } else { Status3->setText("KISS Open Failed"); KISSConnected = 0; KISSConnecting = 0; return 0; } } void closeSerialPort() { if (m_serial && m_serial->isOpen()) { m_serial->close(); m_serial = nullptr; } m_serial = nullptr; KISSConnected = 0; KISSConnecting = 0; Status3->setText("KISS Closed"); actHost[18]->setEnabled(0); // Enable KISS Connect Line } void QtTermTCP::readSerialData() { int Read; unsigned char Buffer[8192]; // read the data from the socket m_serial->clearError(); Read = m_serial->read((char *)Buffer, 2047); if (m_serial->error()) { Debugprintf("Serial Read Error - RC %d Error %d", Read, m_serial->error()); closeSerialPort(); return; } while (Read > 0) { KISSDataReceived(m_serial, Buffer, Read); Read = m_serial->read((char *)Buffer, 2047); } } void QtTermTCP::handleError(QSerialPort::SerialPortError serialPortError) { Debugprintf("Serial port Error %d", serialPortError); closeSerialPort(); } extern "C" void CheckUIFrame(unsigned char * path, string * data) { // If we have KISS enabled and dest is UIDEST look for a KISS window in UI Mode if (KISSSock == 0) return; char Dest[10]; char From[10]; Dest[ConvFromAX25(path, Dest)] = 0; From[ConvFromAX25(&path[7], From)] = 0; // ok, Find a Kiss Session with this Dest Ui_ListenSession * Sess = NULL; for (int i = 0; i < _sessions.size(); ++i) { Sess = _sessions.at(i); if (Sess->KISSMode == 1 && strcmp(Dest, Sess->UIDEST) == 0) { char Msg[512]; int Len; data->Data[data->Length] = 0; Len = sprintf(Msg, "%s:%s", From, data->Data); SendtoTerm(Sess, Msg, Len); return; } } } QColor QtTermTCP::setColor(QColor Colour) { // const QColorDialog::ColorDialogOptions options = QFlag(colorDialogOptionsWidget->value()); QColor col = Colour; QColorDialog dialog; dialog.setCurrentColor(Colour); dialog.setOption(QColorDialog::DontUseNativeDialog); if (dialog.exec() == QColorDialog::Accepted) col = QVariant(dialog.currentColor()).toString(); // const QColor color = QColorDialog::getColor(Qt::green, this, "Select Color", 0); return col; } // Experimental Viewdata/Teletext/Prestel/CEEFAX Mode // Uses ideas and some code from /*************************************************************** * Name: wxTEDMain.cpp * Purpose: Teletext editor Application Frame * Author: Peter Kwan (peterk.vt80@gmail.com) * Created: 2014-10-30 * Copyright: Peter Kwan * License: * * Copyright (C) 2014-2022, Peter Kwan * * Permission to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that the copyright notice and this * permission notice and warranty disclaimer appear in supporting * documentation, and that the name of the author not be used in * advertising or publicity pertaining to distribution of the * software without specific, written prior permission. * * The author disclaims all warranties with regard to this * software, including all implied warranties of merchantability * and fitness. In no event shall the author be liable for any * special, indirect or consequential damages or any damages * whatsoever resulting from loss of use, data or profits, whether * in an action of contract, negligence or other tortious action, * arising out of or in connection with the use or performance of * this software. *************************************************************************** **/ int FontWidth = 16; int FontHeight = 16; bool isMosaic(char ch) { ch &= 0x7f; return (ch >= 0x20 && ch < 0x40) || ch >= 0x60; } void DecodeTeleText(Ui_ListenSession * Sess, char * page) { // redraw the whole teletext page QColor fg = Qt::white; QColor bg = Qt::black; QColor holdColour; QColor holdfg = fg; // Colour for held graphic int usehold = 0; int sep = 0; QPainter p(Sess->TTBitmap); QSettings settings(GetConfPath(), QSettings::IniFormat); //p.setFont(QFont("Courier", 14, QFont::Bold)); p.setFont(QFont(settings.value("FontFamily", "Courier New").value(), 14)); p.setPen(QPen(fg)); bool graphicsMode = false; bool separated = false; bool doubleHeight = false; int skipnextrow = 99; bool flashing = false; bool hold = false; char holdChar = 0; char holdMode = 0; Sess->timer.stop(); bool concealed = false; char c; fg = Qt::white; bg = Qt::black; char * ptr = page; int col = 0; int line = 0; // XXXXXXXXTEEFAX %%# %%a %d %%b C %H:%M.%S //p.drawText(0, 19, "P199 HAMFAX"); // interpret data, for now, line by line while (c = *(ptr++)) { char ch = c; if (c == 0x11) // Curson On ?? continue; if (c == 0x14) // Curson Off ?? continue; if (c == 9) // Curson On ?? { col++; continue; } if (c == 0x0a) { line++; // if (doubleHeight) // line++; if (line > 24) line = 0; continue; } if (c == 0x1e) // Cursor Home { line = col = 0; c = 13; // So we reset page flags below } if (c == 12) { // Clear the page Sess->TTBitmap->fill(Qt::black); Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); line = col = 0; c = 13; // So we reset page flags below } if (c == 13) { col = 0; graphicsMode = false; separated = false; doubleHeight = false; flashing = false; hold = false; holdChar = 0; concealed = false; fg = Qt::white; bg = Qt::black; continue; // Next line } if (c == 0x1b) // Esc { // I think the control char is displayed as it was before being actioned, sa save current state holdfg = holdColour; // Colour if using held - may be changed before displaying usehold = hold; // May be changed sep = holdMode; char echar = *(ptr++); if (echar == 0) { // Esc pair spilt - wait for rest Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); return; } switch (echar) { case '@': fg = Qt::black; concealed = false; // Side effect of colour. It cancels a conceal. graphicsMode = false; // hold = false; break; case 'A': fg = Qt::red; concealed = false; graphicsMode = false; hold = false; break; case 'B': fg = Qt::green; concealed = false; graphicsMode = false; hold = false; break; case 'C': fg = Qt::yellow; concealed = false; graphicsMode = false; hold = false; break; case 'D': fg = Qt::blue; concealed = false; graphicsMode = false; hold = false; break; case 'E': fg = Qt::magenta; concealed = false; graphicsMode = false; hold = false; break; case 'F': fg = Qt::cyan; concealed = false; graphicsMode = false; hold = false; break; case 'G': fg = Qt::white; concealed = false; graphicsMode = false; hold = false; break; case 'H': // Flash flashing = true; Sess->timer.start(1000, Sess); concealed = false; graphicsMode = false; hold = false; break; case 'I': // Steady flashing = false; concealed = false; graphicsMode = false; hold = false; break; // case 'J': //ttxCodeEndBox: case 'K': //ttxCodeStartBox: concealed = false; graphicsMode = false; hold = false; break; case 'L': // Normal height doubleHeight = false; hold = false; break; case 'M': // Double height doubleHeight = true; skipnextrow = line + 1; // ETSI: row to ignore hold = false; holdChar = 0; break; case 'P': // Graphics black // concealed = false; graphicsMode = true; holdColour = fg = Qt::black; break; case 'Q': // Graphics red // concealed = false; graphicsMode = true; holdColour = fg = Qt::red; break; case 'R': // Graphics green // concealed = false; graphicsMode = true; holdColour = fg = Qt::green; break; case 'S': // Graphics yellow // concealed = false; graphicsMode = true; holdColour = fg = Qt::yellow; break; case 'T': // Graphics blue // concealed = false; graphicsMode = true; holdColour = fg = Qt::blue; break; case 'U': // Graphics magenta // concealed = false; graphicsMode = true; holdColour = fg = Qt::magenta; break; case 'V': // Graphics cyan // concealed = false; graphicsMode = true; holdColour = fg = Qt::cyan; break; case 'W': // Graphics white // concealed = false; graphicsMode = true; holdColour = fg = Qt::white; break; case 'X': // Conceal display concealed = 1; break; case 'Y': // Contiguous graphics separated = false; break; case 'Z': // Separated gfx separated = true; break; case 0x5c: // Background black bg = Qt::black; break; case 0x5d: // New background bg = fg; break; case 0x5e: // Hold gfx if (hold == 0) { hold = true; holdColour = fg; holdMode = separated; } break; case 0x5f: // Non-hold gfx hold = false; break; default: echar++; // For testign break; } //end of esc case processing if (usehold) { // We set sep and color for held char earlier ch = holdChar; // Repeat held char } else ch = 0x0; // Default is space if (line > skipnextrow) skipnextrow = 99; if (line == skipnextrow) { line = line; } else { if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) { p.fillRect(col * 15, line * 19, 15, 19, bg); // if double height also draw background for next row if (doubleHeight) p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); if (sep) { if (ch & 1) p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, holdfg); if (ch & 2) p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, holdfg); if (ch & 4) p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, holdfg); if (ch & 8) p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, holdfg); if (ch & 16) p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, holdfg); if (ch & 32) p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, holdfg); } else { if (ch & 1) p.fillRect(col * 15, line * 19, 7, 6, holdfg); if (ch & 2) p.fillRect(col * 15 + 7, line * 19, 8, 6, holdfg); if (ch & 4) p.fillRect(col * 15, line * 19 + 6, 7, 6, holdfg); if (ch & 8) p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, holdfg); if (ch & 16) p.fillRect(col * 15, line * 19 + 12, 7, 7, holdfg); if (ch & 32) p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, holdfg); } } } col++; } else { // Not esc - so normal or graphics if (ch < 0x20) continue; if (line > skipnextrow) skipnextrow = 99; if (line == skipnextrow) { line = line; } else { if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) { p.fillRect(col * 15, line * 19, 15, 19, bg); if (doubleHeight) p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); p.setPen(QPen(fg));; if (graphicsMode) { if (ch < 0x40) ch -= 0x20; else if (ch >= 0x60) ch -= 0x40; else goto isText; holdChar = ch; // Now have 00 - 3f // C is bit mask bit posns are // 01 // 23 // 45 // Char cell is 15 * 19 which is a bit asymetrical // Chars are 20 - 3f and 60 to 7f but I cant see a logic to the mapping if (separated) { if (ch & 1) p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, fg); if (ch & 2) p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, fg); if (ch & 4) p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, fg); if (ch & 8) p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, fg); if (ch & 16) p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, fg); if (ch & 32) p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, fg); } else { if (ch & 1) p.fillRect(col * 15, line * 19, 7, 6, fg); if (ch & 2) p.fillRect(col * 15 + 7, line * 19, 8, 6, fg); if (ch & 4) p.fillRect(col * 15, line * 19 + 6, 7, 6, fg); if (ch & 8) p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, fg); if (ch & 16) p.fillRect(col * 15, line * 19 + 12, 7, 7, fg); if (ch & 32) p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, fg); } } else { // Just write char at current col and line isText: char s[5] = " "; // Some chars are in wrong char set s[0] = ch; if (ch == '_') s[0] = '#'; else if (ch == 0x7e) // division { s[0] = 0xC3; s[1] = 0xB7; } else if (ch == 0x5e) // up arrow { s[0] = 0xF0; s[1] = 0x9F; s[2] = 0xA0; s[3] = 0x95; } else if (ch == 0x7f) // up arrow { s[0] = 0xE2; s[1] = 0x96; s[2] = 0x88; } // 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); }