diff --git a/debian/patches/Sure-whynot b/debian/patches/Sure-whynot new file mode 100644 index 0000000..387a125 --- /dev/null +++ b/debian/patches/Sure-whynot @@ -0,0 +1,46805 @@ +Description: This is what's needed to make it build + The whole bastarding codebase in one patch + . + qttermtcp (0.0.0.79-1) UNRELEASED; urgency=medium + . + * Update the debian branch for import + * New upstream version 0.0.0.79 +Author: Dave Hibberd + +--- qttermtcp-0.0.0.79.orig/AGWCode.cpp ++++ qttermtcp-0.0.0.79/AGWCode.cpp +@@ -1,1625 +1,1625 @@ +-// AGW Interface +- +-#include "QtTermTCP.h" +-#include "TabDialog.h" +-#include +-#include +-#include +- +-#ifndef WIN32 +-#define strtok_s strtok_r +-#endif +- +-#define UCHAR unsigned char +-#define byte unsigned char +- +-myTcpSocket * AGWSock; +- +-extern QColor monRxText; +-extern QColor monTxText; +- +-extern QColor outputText; +-extern QColor EchoText; +-extern QColor WarningText; +- +-extern QColor newTabText; +- +-extern QTabWidget *tabWidget; +-extern QWidget * mythis; +- +-extern int AGWEnable; +-extern int AGWMonEnable; +-extern int AGWLocalTime; +-extern int AGWMonNodes; +-extern char AGWTermCall[12]; +-extern char AGWBeaconDest[12]; +-extern char AGWBeaconPath[80]; +-extern int AGWBeaconInterval; +-extern char AGWBeaconPorts[80]; +-extern char AGWBeaconMsg[260]; +- +-extern char AGWHost[128]; +-extern int AGWPortNum; +-extern int AGWPaclen; +- +-extern Ui_ListenSession * KISSMonSess; +- +-extern char listenCText[4096]; +-extern int ConnectBeep; +- +-extern QList _sessions; +- +-extern QLabel * Status1; +-extern QLabel * Status2; +-extern QLabel * Status3; +-extern QLabel * Status4; +- +-extern QMenu *connectMenu; +-extern QAction *discAction; +-extern QAction *YAPPSend; +- +-extern QAction *actHost[17]; +- +-// Session Type Equates +- +-#define Term 1 +-#define Mon 2 +-#define Listen 4 +- +-extern int TermMode; +- +-#define Single 0 +-#define MDI 1 +-#define Tabbed 2 +- +-extern int singlemodeFormat; +- +-typedef struct AGWUser_t +-{ +- QTcpSocket *socket; +- unsigned char data_in[8192]; +- int data_in_len; +- unsigned char AGW_frame_buf[512]; +- int Monitor; +- int Monitor_raw; +- Ui_ListenSession * MonSess; // Window for Monitor info +- +-} AGWUser; +- +- +-struct AGWHeader +-{ +- int Port; +- unsigned char DataKind; +- unsigned char filler2; +- unsigned char PID; +- unsigned char filler3; +- char callfrom[10]; +- char callto[10]; +- int DataLength; +- int reserved; +-}; +- +-#define AGWHDDRRLEN sizeof(struct AGWHeader) +- +-typedef struct TAGWPort_t +-{ +- byte PID; +- int port; +- char corrcall[10]; +- char mycall[10]; +- int Active; +- QTcpSocket * socket; +- Ui_ListenSession * Sess; // Terminal Session +- +-} TAGWPort; +- +- +-int AGWConnected = 0; +-int AGWConnecting = 0; +- +-char * AGWPortList = NULL; +- +-#define max_sessions 8 +- +-TAGWPort AGWPort[max_sessions]; +- +-#define LSB 29 +-#define MSB 30 +-#define MON_ON '1' +-#define MON_OFF '0' +-#define MODE_OUR 0 +-#define MODE_OTHER 1 +-#define MODE_RETRY 2 +- +-// Don't think we will support more than one, but leave in option +- +-AGWUser *AGWUsers = NULL; // List of currently connected clients +- +-void AGW_add_socket(QTcpSocket * socket); +-void AGW_Process_Input(AGWUser * AGW); +-void Send_AGW_X_Frame(QTcpSocket* socket, char * CallFrom); +-void Send_AGW_G_Frame(QTcpSocket* socket); +-void Send_AGW_m_Frame(QTcpSocket* socket); +-void Send_AGW_R_Frame(QTcpSocket* socket); +- +-Ui_ListenSession * FindFreeWindow(); +-Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label = nullptr); +-void AGW_frame_header(UCHAR * Msg, char AGWPort, char DataKind, unsigned char PID, const char * CallFrom, const char * CallTo, int Len); +- +- +-void Debugprintf(const char * format, ...) +-{ +- char Mess[10000]; +- va_list arglist; +- +- va_start(arglist, format); +- vsprintf(Mess, format, arglist); +- qDebug() << Mess; +- +- return; +-} +- +-int ConvToAX25(char * callsign, unsigned char * ax25call) +-{ +- int i; +- +- memset(ax25call, 0x40, 6); // in case short +- ax25call[6] = 0x60; // default SSID +- +- for (i = 0; i < 7; i++) +- { +- if (callsign[i] == '-') +- { +- // +- // process ssid and return +- // +- i = atoi(&callsign[i + 1]); +- +- if (i < 16) +- { +- ax25call[6] |= i << 1; +- return (1); +- } +- return (0); +- } +- +- if (callsign[i] == 0 || callsign[i] == 13 || callsign[i] == ' ' || callsign[i] == ',') +- { +- // +- // End of call - no ssid +- // +- return (1); +- } +- +- ax25call[i] = callsign[i] << 1; +- } +- +- // +- // Too many chars +- // +- +- return (0); +-} +- +- +-int ConvFromAX25(unsigned char * incall, char * outcall) +-{ +- int in, out = 0; +- unsigned char chr; +- +- memset(outcall, 0x20, 10); +- +- for (in = 0; in < 6; in++) +- { +- chr = incall[in]; +- if (chr == 0x40) +- break; +- chr >>= 1; +- outcall[out++] = chr; +- } +- +- chr = incall[6]; // ssid +- +- if (chr == 0x42) +- { +- outcall[out++] = '-'; +- outcall[out++] = 'T'; +- return out; +- } +- +- if (chr == 0x44) +- { +- outcall[out++] = '-'; +- outcall[out++] = 'R'; +- return out; +- } +- +- chr >>= 1; +- chr &= 15; +- +- if (chr > 0) +- { +- outcall[out++] = '-'; +- if (chr > 9) +- { +- chr -= 10; +- outcall[out++] = '1'; +- } +- chr += 48; +- outcall[out++] = chr; +- } +- return (out); +-} +- +-void doAGWBeacon() +-{ +- if (AGWBeaconDest[0] && AGWBeaconPorts[0]) +- { +- // Send as M or V depending on Digis +- +- UCHAR Msg[512]; +- char ports[80]; +- +- char * ptr, * context; +- int DataLen; +- +- strcpy(ports, AGWBeaconPorts); // strtok changes it +- +- +- // Replace newlines with CR +- +- while ((ptr = strchr(AGWBeaconMsg, 10))) +- *ptr = 13; +- +- ptr = strtok_s(ports, " ,", &context); +- +- if (AGWBeaconPath[0]) +- { +- +- } +- else +- { +- while (ptr) +- { +- DataLen = (int)strlen(AGWBeaconMsg); +- +- AGW_frame_header(Msg, atoi(ptr) - 1, 'M', 240, AGWTermCall, AGWBeaconDest, DataLen); +- memcpy(&Msg[AGWHDDRRLEN], AGWBeaconMsg, DataLen); +- DataLen += AGWHDDRRLEN; +- AGWSock->write((char *)Msg, DataLen); +- +- ptr = strtok_s(NULL, " ,", &context); +- } +- } +- } +-} +- +-TAGWPort * get_free_port() +-{ +- int i = 0; +- +- while (i < max_sessions) +- { +- if (AGWPort[i].Active == 0) +- return &AGWPort[i]; +- +- i++; +- } +- return nullptr; +-} +- +-TAGWPort * findSession(int AGWChan, char * MyCall, char * OtherCall) +-{ +- int i = 0; +- +- TAGWPort * Sess = nullptr; +- +- while (i < max_sessions) +- { +- Sess = &AGWPort[i]; +- +- if (Sess->Active && Sess->port == AGWChan && strcmp(Sess->corrcall, OtherCall) == 0 && strcmp(Sess->mycall, MyCall) == 0) +- return Sess; +- +- i++; +- } +- return nullptr; +-} +- +- +- +-void QtTermTCP::AGWdisplayError(QAbstractSocket::SocketError socketError) +-{ +- switch (socketError) +- { +- case QAbstractSocket::RemoteHostClosedError: +- break; +- +- case QAbstractSocket::HostNotFoundError: +- QMessageBox::information(this, tr("QtTermTCP"), +- tr("AGW host was not found. Please check the " +- "host name and port settings.")); +- +- Status1->setText("AGW Connection Failed"); +- +- break; +- +- case QAbstractSocket::ConnectionRefusedError: +- +- Status1->setText("AGW Connection Refused"); +- break; +- +- default: +- +- Status1->setText("AGW Connection Failed"); +- } +- +- AGWConnecting = 0; +- AGWConnected = 0; +-} +- +-void QtTermTCP::AGWreadyRead() +-{ +- int Read; +- unsigned char Buffer[4096]; +- myTcpSocket* Socket = static_cast(QObject::sender()); +- +- // read the data from the socket +- +- Read = Socket->read((char *)Buffer, 4095); +- +- int AGWHeaderLen = sizeof(struct AGWHeader); +- +- AGWUser * AGW = NULL; +- +- AGW = AGWUsers; +- +- if (AGW == NULL) +- return; +- +- memcpy(&AGW->data_in[AGW->data_in_len], Buffer, Read); +- +- AGW->data_in_len += Read; +- +- while (AGW->data_in_len >= AGWHeaderLen) // Make sure have at least header +- { +- struct AGWHeader * Hddr = (struct AGWHeader *)AGW->data_in; +- +- int AgwLen = Hddr->DataLength + AGWHeaderLen; +- +- if (AGW->data_in_len >= AgwLen) +- { +- // Have frame as well +- +- AGW_Process_Input(AGW); +- +- AGW->data_in_len -= AgwLen; +- +- memmove(AGW->data_in, &AGW->data_in[AgwLen], AGW->data_in_len); +- } +- else +- return; // Wait for the data +- } +- +-} +- +-void QtTermTCP::onAGWSocketStateChanged(QAbstractSocket::SocketState socketState) +-{ +- myTcpSocket* sender = static_cast(QObject::sender()); +- Ui_ListenSession * Sess = (Ui_ListenSession *)sender->Sess; +- int i; +- +- if (socketState == QAbstractSocket::UnconnectedState) +- { +- // Close any connections +- +- Status1->setText("AGW Disconnected"); +- actHost[16]->setVisible(0); +- +- int i = 0; +- +- TAGWPort * AGW = nullptr; +- +- for (i = 0; i < max_sessions; i++) +- { +- AGW = &AGWPort[i]; +- +- if (AGW->Active && AGW->socket) +- { +- AGW->Active = 0; +- AGW->socket = nullptr; +- +- Sess = AGW->Sess; +- +- if (Sess) +- { +- // Send Disconnected +- +- 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[32]; +- 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"); +- } +- +- setMenus(false); +- +- // if Single Split or Monitor leave session allocated to AGW +- +- if (TermMode == Single && (Sess->SessionType & Mon)) +- { +- return; +- } +- +- Sess->AGWSession = nullptr; +- AGW->Sess = nullptr; +- } +- } +- } +- +- // Free the monitor Window +- +- if (AGWUsers && AGWUsers->MonSess) +- { +- Sess = AGWUsers->MonSess; +- +- char Msg[] = "Disconnected\r"; +- +- WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), +- Sess->monWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red +- +- if (TermMode == MDI) +- Sess->setWindowTitle("Monitor Session Disconnected"); +- +- else if (TermMode == Tabbed) +- tabWidget->setTabText(Sess->Tab, "Monitor"); +- +- Sess->AGWSession = nullptr; +- AGWUsers->MonSess = nullptr; +- } +- +- if (TermMode == Single && (singlemodeFormat & Mon)) +- { +- //Re-renable TCP connects +- +- for (int i = 0; i < MAXHOSTS; i++) +- actHost[i]->setVisible(1); +- } +- +- +- AGWConnected = 0; +- } +- else if (socketState == QAbstractSocket::ConnectedState) +- { +- AGWConnected = 1; +- AGWConnecting = 0; +- +- Status1->setText("AGW Connected"); +- +- AGW_add_socket(sender); +- +- actHost[16]->setVisible(1); // Enable AGW Connect Line +- +- // Send X frame to register Term Call +- +- if (AGWTermCall[0]) +- Send_AGW_X_Frame(sender, AGWTermCall); +- +- Send_AGW_G_Frame(sender); // Request Port List +- +- // 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->AGWSession == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) +- { +- Sess = S; +- break; +- } +- } +- +- // Create a window if none found, else reuse old +- +- if (Sess == NULL) +- { +- Sess = newWindow((QObject *)mythis, Mon, ""); +- } +- } +- else if (TermMode == Tabbed) +- { +- // Tabbed - look for free session +- +- for (i = 8; i; i--) +- { +- S = _sessions.at(i); +- +- if (S->clientSocket == NULL && S->KISSSession == NULL && S->AGWSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) +- { +- Sess = S; +- break; +- } +- } +- } +- else if (TermMode == Single && (singlemodeFormat & Mon)) +- { +- S = _sessions.at(0); +- +- if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) +- Sess = S; +- +- } +- +- if (Sess) +- { +- AGWUsers->MonSess = Sess; +-// Sess->AGWSession = sender; // Flag as in use +- +- if (TermMode == MDI) +- Sess->setWindowTitle("AGW Monitor Window"); +- else if (TermMode == Tabbed) +- tabWidget->setTabText(Sess->Tab, "AGW Mon"); +- else if (TermMode == Single) +- mythis->setWindowTitle("AGW Monitor Window"); +- +- if (TermMode == Single && (singlemodeFormat & Mon)) +- { +- // Can't be connected, so leave state alone, but disable TCP connects +- +- for (int i = 0; i < MAXHOSTS; i++) +- actHost[i]->setVisible(0); +- +- } +- else if (TermMode != Tabbed) // Not ideal, but AGW mon window is unlikely to be active window +- { +- discAction->setEnabled(false); +- YAPPSend->setEnabled(false); +- connectMenu->setEnabled(false); +- } +- +- Sess->mlocaltime = AGWLocalTime; +- Sess->MonitorNODES = AGWMonNodes; +- +- Send_AGW_R_Frame(sender); // Request Version +- Send_AGW_m_Frame(sender); // Request Monitor Frames +- } +- } +-} +- +- +-void QtTermTCP::ConnecttoAGW() +-{ +- delete(AGWSock); +- +- AGWSock = new myTcpSocket(); +- +- connect(AGWSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(AGWdisplayError(QAbstractSocket::SocketError))); +- connect(AGWSock, SIGNAL(readyRead()), this, SLOT(AGWreadyRead())); +- connect(AGWSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onAGWSocketStateChanged(QAbstractSocket::SocketState))); +- +- AGWSock->connectToHost(AGWHost, AGWPortNum); +- +- Status1->setText("AGW Connecting"); +- +- return; +-} +- +-int AGWBeaconTimer = 0; +- +- +-void QtTermTCP::AGWTimer() +-{ +- // Runs every 10 Seconds +- +- if (AGWConnected == 0 && AGWConnecting == 0) +- { +- AGWConnecting = true; +- ConnecttoAGW(); +- } +- +- if (AGWBeaconInterval) +- { +- AGWBeaconTimer++; +- +- if (AGWBeaconTimer >= AGWBeaconInterval * 6) +- { +- AGWBeaconTimer = 0; +- +- if (AGWConnected) +- doAGWBeacon(); +- } +- } +-} +- +- +-void AGW_del_socket(void * socket) +-{ +- if (AGWUsers->socket == socket) +- { +- free(AGWUsers); +- AGWUsers = nullptr; +- } +-} +- +- +- +-void AGW_add_socket(QTcpSocket * socket) +-{ +- AGWUser * User = (struct AGWUser_t *)malloc(sizeof(struct AGWUser_t)); // One Client +- memset(User, 0, sizeof(struct AGWUser_t)); +- +- User->socket = socket; +- +- AGWUsers = User; +-}; +- +-void AGWWindowClosing(Ui_ListenSession *Sess) +-{ +- if (AGWUsers && AGWUsers->MonSess == Sess) +- AGWUsers->MonSess = NULL; +-} +- +- +- +-void AGW_frame_header(UCHAR * Msg, char AGWPort, char DataKind, unsigned char PID, const char * CallFrom, const char * CallTo, int Len) +-{ +- struct AGWHeader * Hddr = (struct AGWHeader *)Msg; +- memset(Hddr, 0, sizeof(struct AGWHeader)); +- +- Hddr->Port = AGWPort; +- Hddr->DataLength = Len; +- Hddr->DataKind = DataKind; +- Hddr->PID = PID; +- strcpy(Hddr->callfrom, CallFrom); +- strcpy(Hddr->callto, CallTo); +-}; +- +- +-/* +- +-// AGW to APP frames +- +-UCHAR * AGW_R_Frame() +-{ +- UCHAR * Msg = AGW_frame_header(0, 'R', 0, "", "", 8); +- +-// stringAdd(Msg, (UCHAR *)AGWVersion, 8); +- +- return Msg; +-}; +-*/ +- +- +-void Send_AGW_X_Frame(QTcpSocket* socket, char * CallFrom) +-{ +- UCHAR Msg[512]; +- +- AGW_frame_header(Msg, 0, 'X', 0, CallFrom, "", 0); +- socket->write((char *)Msg, AGWHDDRRLEN); +-} +- +-void Send_AGW_G_Frame(QTcpSocket* socket) +-{ +- UCHAR Msg[512]; +- +- AGW_frame_header(Msg, 0, 'G', 0, "", "", 0); +- socket->write((char *)Msg, AGWHDDRRLEN); +-} +- +-void Send_AGW_m_Frame(QTcpSocket* socket) +-{ +- UCHAR Msg[512]; +- +- // Request Monitoring. Add Extended form if connected to BPQ +- +- AGW_frame_header(Msg, 0, 'm', 0, "", "", 12); +- +- Msg[AGWHDDRRLEN] = AGWLocalTime; +- Msg[AGWHDDRRLEN + 1] = AGWMonNodes; +- Msg[AGWHDDRRLEN + 2] = AGWMonEnable; +- Msg[AGWHDDRRLEN + 3] = 0; +- +- memcpy(&Msg[AGWHDDRRLEN + 4], (void *)&AGWUsers->MonSess->portmask, 8); +- +- socket->write((char *)Msg, AGWHDDRRLEN + 12); +-} +- +-void Send_AGW_R_Frame(QTcpSocket* socket) +-{ +- UCHAR Msg[512]; +- +- // Request Version +- +- AGW_frame_header(Msg, 0, 'R', 0, "", "", 0); +- socket->write((char *)Msg, AGWHDDRRLEN); +-} +- +- +-/* +- +- +-UCHAR * AGW_Y_Frame(int port, char * CallFrom, char *CallTo, int frame_outstanding) +-{ +- UCHAR * Msg; +- +- Msg = AGW_frame_header(port, 'Y', 0, CallFrom, CallTo, 4); +- +- stringAdd(Msg, (UCHAR *)&frame_outstanding, 4); +- return Msg; +-} +- +- +- +-*/ +- +- +-void Send_AGW_C_Frame(Ui_ListenSession * Sess, int Port, char * CallFrom, char * CallTo, char * Data, int DataLen) +-{ +- UCHAR Msg[512]; +- char Title[64]; +- +- // We should allocate a AGW session record +- +- TAGWPort * AX25Sess; +- +- // FIrst check that we don't already have a session between these calla +- +- if (Port == -1) +- return; +- +- Debugprintf("Send_AGW_C_Frame"); +- +- AX25Sess = findSession(Port, CallTo, CallFrom); +- +- if (AX25Sess) +- { +- // Seems this can be called twice +- +- if (Sess->AGWSession == nullptr) +- QMessageBox::information(mythis, "QtTermTCP", "You already have a conenction to that call"); +- +- return; +- } +- +- AX25Sess = get_free_port(); +- +- if (AX25Sess) +- { +- AX25Sess->Active = 1; +- AX25Sess->port = Port; +- AX25Sess->Sess = Sess; // Crosslink AGW and Term Sessions +- AX25Sess->PID = 240; +- +- Sess->AGWSession = AX25Sess; +- +- strcpy(AX25Sess->mycall, CallTo); +- strcpy(AX25Sess->corrcall, CallFrom); +- +- AX25Sess->socket = AGWSock; +- +- if (DataLen) // Digis so use 'v' frame +- { +- AGW_frame_header(Msg, Port, 'v', 240, CallFrom, CallTo, DataLen); +- memcpy(&Msg[AGWHDDRRLEN], (UCHAR *)Data, DataLen); +- } +- else +- { +- AGW_frame_header(Msg, Port, 'C', 240, CallFrom, CallTo, DataLen); +- } +- +- DataLen += AGWHDDRRLEN; +- +- AGWSock->write((char *)Msg, DataLen); +- +- sprintf(Title, "Connecting to %s", CallTo); +- +- if (TermMode == MDI) +- Sess->setWindowTitle(Title); +- else if (TermMode == Tabbed) +- tabWidget->setTabText(Sess->Tab, "Connecting"); +- else if (TermMode == Single) +- mythis->setWindowTitle(Title); +- +- } +-} +- +- +-void Send_AGW_Ds_Frame(void * Sess) +-{ +- TAGWPort * AGW = (TAGWPort *)Sess; +- UCHAR Msg[512]; +- +- AGW_frame_header(Msg, AGW->port, 'd', 240, AGW->corrcall, AGW->mycall, 0); +- if (AGW->socket) +- AGW->socket->write((char *)Msg, AGWHDDRRLEN); +-} +- +- +- +-void Send_AGW_D_Frame(TAGWPort * AGW, UCHAR * Data, int DataLen) +-{ +- UCHAR Msg[512]; +- +- AGW_frame_header(Msg, AGW->port, 'D', AGW->PID, AGW->corrcall, AGW->mycall, DataLen); +- +- memcpy(&Msg[AGWHDDRRLEN], Data, DataLen); +- +- DataLen += AGWHDDRRLEN; +- +- AGW->socket->write((char *)Msg, DataLen); +-} +- +- +- +-/* +- +-UCHAR * AGW_T_Frame(int port, char * CallFrom, char * CallTo, char * Data) +-{ +- UCHAR * Msg; +- int DataLen; +- +- DataLen = strlen(Data); +- +- Msg = AGW_frame_header(port, 'T', 0, CallFrom, CallTo, DataLen); +- +- stringAdd(Msg, (byte *)Data, DataLen); +- +- return Msg; +-} +- +-// Raw Monitor +-UCHAR * AGW_K_Frame(int port, int PID, char * CallFrom, char * CallTo, UCHAR * Data, int DataLen) +-{ +- UCHAR Msg[512]; +- +- DataLen = Data->Length; +- +- AGW_frame_header(Msg, port, 'K', PID, CallFrom, CallTo, DataLen); +- +-// stringAdd(Msg, Data->Data, Data->Length); +- +-// freeString(Data); +- +- return Msg; +-} +- +-// APP to AGW frames +- +-void on_AGW_P_frame(AGWUser * AGW) +-{ +- +-} +- +-*/ +- +-void on_AGW_G_frame(unsigned char * Data) +-{ +- if (AGWPortList) +- free(AGWPortList); +- +- AGWPortList = (char *)strdup((char *)Data); +-}; +- +-/* +- +-void on_AGW_Ms_frame(AGWUser * AGW) +-{ +- AGW->Monitor ^= 1; // Flip State +-} +- +- +-void on_AGW_R_frame(AGWUser * AGW) +-{ +-// AGW_send_to_app(AGW->socket, AGW_R_Frame()); +-} +- +- +- +-void on_AGW_Y_frame(void * socket, int snd_ch, char * CallFrom, char * CallTo) +-{ +- int frames; +- TAGWPort * AX25Sess; +- +-// AX25Sess = get_user_port_by_calls(snd_ch, CallFrom, CallTo); +- +-// if (AX25Sess) +-// { +- //frames = AX25port[snd_ch][user_port].in_data_buf.Count; +-// frames = AX25Sess->in_data_buf.Count + AX25Sess->I_frame_buf.Count; +-// ; +-// AGW_send_to_app(socket, AGW_Y_Frame(snd_ch, CallFrom, CallTo, frames)); +-// } +-} +- +-// UI Transmit +- +-void on_AGW_M_frame(int port, byte PID, char * CallFrom, char *CallTo, byte * Msg, int MsgLen) +-{ +- byte path[80]; +- char Calls[80]; +- UCHAR * Data = newString(); +- +- stringAdd(Data, Msg, MsgLen); +- +- sprintf(Calls, "%s,%s", CallTo, CallFrom); +- +- get_addr(Calls, 0, 0, path); +- +- Add(&all_frame_buf[port], +- make_frame(Data, path, PID, 0, 0, U_FRM, U_UI, FALSE, SET_F, SET_C)); +- +-} +- +-*/ +-void on_AGW_C_frame(AGWUser * AGW, struct AGWHeader * Frame, byte * Msg) +-{ +- int snd_ch = Frame->Port; +- char * CallFrom = Frame->callfrom; +- char * CallTo = Frame->callto; +- char Title[64]; +- int i = 0; +- +- TAGWPort * AX25Sess; +- +- // Connection received - may be incoming or response to our connect +- +- // See if incoming +- +- if (strstr((char *)Msg, (const char *)"CONNECTED To")) +- { +- // incoming call +- +- AX25Sess = get_free_port(); +- +- if (AX25Sess) +- { +- // Look for/create Terminal Window for connection +- +- 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 & Listen) && S->clientSocket == NULL) +- { +- Sess = S; +- break; +- } +- } +- +- // Create a window if none found, else reuse old +- +- if (Sess == NULL) +- { +- Sess = newWindow((QObject *)mythis, Listen, ""); +- } +- } +- else if (TermMode == Tabbed) +- { +- // Single 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; +- } +- } +- } +- else +- { +- // Single - Only one available +- S = _sessions.at(0); +- +- if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) +- Sess = S; +- } +- +- if (Sess == NULL) +- { +- // Clear connection by sendinf d fraame +- +- UCHAR Msg[512]; +- +- int snd_ch = Frame->Port; +- char * CallFrom = Frame->callfrom; +- char * CallTo = Frame->callto; +- +- AGW_frame_header(Msg, Frame->Port, 'd', 240, Frame->callto, Frame->callfrom, 0); +- if (AGW->socket) +- AGW->socket->write((char *)Msg, AGWHDDRRLEN); +- +- return; +- } +- +- if (Sess) +- { +- sprintf(Title, "Connected to %s", CallFrom); +- +- QApplication::alert(mythis, 0); +- +- if (TermMode == MDI) +- { +- Sess->setWindowTitle(Title); +- } +- else if (TermMode == Tabbed) +- { +- tabWidget->setTabText(i, CallFrom); +- tabWidget->tabBar()->setTabTextColor(i, newTabText); +- } +- +- else if (TermMode == Single) +- mythis->setWindowTitle(Title); +- +- AX25Sess->Active = 1; +- AX25Sess->port = snd_ch; +- AX25Sess->Sess = Sess; // Crosslink AGW and Term Sessions +- AX25Sess->PID = 240;; +- +- Sess->AGWSession = AX25Sess; +- +- strcpy(AX25Sess->mycall, CallFrom); +- strcpy(AX25Sess->corrcall, CallTo); +- +- AX25Sess->socket = AGW->socket; +- +- setMenus(true); +- +- if (ConnectBeep) +- myBeep(&ConnectWAV); +- +- // Send CText if defined +- +- if (listenCText[0]) +- Send_AGW_D_Frame(AX25Sess, (unsigned char *)listenCText, (int)strlen(listenCText)); +- +- // Send Message to Terminal +- +- char Msg[80]; +- +- sprintf(Msg, "Incoming AGW Connection from %s\r\r", CallFrom); +- +- WritetoOutputWindow(Sess, (unsigned char *)Msg, (int)strlen(Msg)); +- return; +- } +- } +- } +- +- // Reply to out connect request - look for our connection +- +- AX25Sess = findSession(snd_ch, CallFrom, CallTo); +- +- if (AX25Sess) +- { +- Ui_ListenSession * Sess = AX25Sess->Sess; +- +- sprintf(Title, "Connected to %s", CallFrom); +- +- if (TermMode == MDI) +- Sess->setWindowTitle(Title); +- else if (TermMode == Tabbed) +- tabWidget->setTabText(Sess->Tab, CallFrom); +- else if (TermMode == Single) +- mythis->setWindowTitle(Title); +- +- setMenus(true); +- +- int Len = sprintf(Title, "*** Connected to %s\r", CallFrom); +- +- ProcessReceivedData(Sess, (unsigned char *)Title, Len); +- } +- +-} +- +- +- +-void on_AGW_D_frame(int snd_ch, char * CallFrom, char * CallTo, byte * Msg, int Len) +-{ +- TAGWPort * AX25Sess; +- +- AX25Sess = findSession(snd_ch, CallFrom, CallTo); +- +- if (AX25Sess) +- { +- ProcessReceivedData(AX25Sess->Sess, Msg, Len); +- } +-} +- +-extern "C" void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Msg, int len); +- +-void on_AGW_Mon_frame(byte * Msg, int Len, char Type) +-{ +- if (AGWUsers && AGWUsers->MonSess && AGWUsers->MonSess->monWindow) +- { +- unsigned char copy[512]; +- +- copy[0] = 0x1b; +- if (Type == 'T') +- copy[1] = 91; +- else +- copy[1] = 17; +- +- memcpy(©[2], Msg, Len); +- WritetoMonWindow(AGWUsers->MonSess, copy, Len + 2); +- } +-} +- +- +- +-void on_AGW_Ds_frame(int AGWChan, char * CallFrom, char * CallTo, struct AGWHeader * Frame) +-{ +- TAGWPort * AX25Sess; +- char * Msg = (char *)Frame; +- Msg = &Msg[36]; +- +- char Reply[128] = ""; +- +- memcpy(Reply, Msg, Frame->DataLength); +- +- // Disconnect Sessiom +- +- AX25Sess = findSession(AGWChan, CallFrom, CallTo); +- +- if (AX25Sess) +- { +- Ui_ListenSession * Sess = AX25Sess->Sess; +- +- WritetoOutputWindowEx(Sess, (unsigned char *)Reply, (int)strlen(Reply), +- 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[32]; +- 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"); +- } +- +- Sess->AGWSession = nullptr; +- AX25Sess->Sess = nullptr; +- AX25Sess->Active = 0; +- +- setMenus(false); +- } +- else +- { +- // Session not found +- } +-} +- +- +-void AGW_AX25_data_in(void * Sess, UCHAR * data, int Len) +-{ +- TAGWPort * AX25Sess = (TAGWPort *)Sess; +- int len = 250, sendlen; +- UCHAR pkt[512]; +- +- while (Len) +- { +- if (Len > len) +- sendlen = len; +- else +- sendlen = Len; +- +- memcpy(pkt, data, sendlen); +- +- Len -= sendlen; +- +- memmove(data, &data[sendlen], Len); +- +- Send_AGW_D_Frame(AX25Sess, pkt, sendlen); +- } +- +-} +- +- +-/* +- +-void AGW_frame_monitor(byte snd_ch, byte * path, UCHAR * data, byte pid, byte nr, byte ns, byte f_type, byte f_id, byte rpt, byte pf, byte cr, byte RX) +-{ +- char mon_frm[512]; +- char AGW_path[256]; +- UCHAR * AGW_data; +- +- const char * frm; +- byte * datap = data->Data; +- byte _data[512]; +- byte * p_data = _data; +- int _datalen; +- +- char agw_port; +- char CallFrom[10], CallTo[10], Digi[80]; +- +- int i; +- const char * ctrl; +- int len; +- +- AGWUser * AGW; +- +- UNUSED(rpt); +- +- len = data->Length; +- +- // if (pid == 0xCF) +- // data = parse_NETROM(data, f_id); +- // IP parsing +- // else if (pid == 0xCC) +- // data = parse_IP(data); +- // ARP parsing +- // else if (pid == 0xCD) +- // data = parse_ARP(data); +- // +- +- if (len > 0) +- { +- for (i = 0; i < len; i++) +- { +- if (datap[i] > 31 || datap[i] == 13 || datap[i] == 9) +- *(p_data++) = datap[i]; +- } +- } +- +- _datalen = p_data - _data; +- +- if (_datalen) +- { +- byte * ptr = _data; +- i = 0; +- +- // remove successive cr or cr on end while (i < _datalen) +- +- while (i < _datalen) +- { +- if ((_data[i] == 13) && (_data[i + 1] = 13)) +- i++; +- else +- *(ptr++) = _data[i++]; +- } +- +- if (*(ptr - 1) == 13) +- ptr--; +- +- *ptr = 0; +- +- _datalen = ptr - _data; +- } +- +- agw_port = snd_ch; +- +- get_monitor_path(path, CallTo, CallFrom, Digi); +- +- ctrl = ""; +- frm = ""; +- +- switch (f_id) +- { +- case I_I: +- +- frm = "I"; +- if (cr == SET_C && pf == SET_P) +- ctrl = " P"; +- +- break; +- +- case S_RR: +- +- frm = "RR"; +- if (pf == SET_P) +- ctrl = " P/F"; +- +- break; +- +- case S_RNR: +- +- frm = "RNR"; +- if (pf == SET_P) +- ctrl = " P/F"; +- +- break; +- +- case S_REJ: +- +- frm = "REJ"; +- if (pf == SET_P) +- ctrl = " P/F"; +- +- break; +- +- case U_SABM: +- +- frm = "SABM"; +- if (cr == SET_C && pf == SET_P) +- ctrl = " P"; +- +- break; +- +- case U_DISC: +- +- frm = "DISC"; +- if (cr == SET_C && pf == SET_P) +- ctrl = " P"; +- break; +- +- case U_DM: +- +- frm = "DM"; +- if ((cr == SET_R) && (pf == SET_P)) +- ctrl = " F "; +- break; +- +- case U_UA: +- +- frm = "UA"; +- if ((cr == SET_R) && (pf == SET_P)) +- ctrl = " F "; +- +- break; +- +- case U_FRMR: +- +- frm = "FRMR"; +- if ((cr == SET_R) && (pf == SET_P)) +- ctrl = " F "; +- break; +- +- case U_UI: +- +- frm = "UI"; +- if ((pf == SET_P)) +- ctrl = " P/F"; +- } +- +- if (Digi[0]) +- sprintf(AGW_path, " %d:Fm %s To %s Via %s <%s", snd_ch + 1, CallFrom, CallTo, Digi, frm); +- else +- sprintf(AGW_path, " %d:Fm %s To %s <%s", snd_ch + 1, CallFrom, CallTo, frm); +- +- +- switch (f_type) +- { +- case I_FRM: +- +- //mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' S' + inttostr(ns) + ' pid=' + dec2hex(pid) + ' Len=' + inttostr(len) + ' >' + time_now + #13 + _data + #13#13; +- sprintf(mon_frm, "%s%s R%d S%d pid=%X Len=%d >[%s]\r%s\r", AGW_path, ctrl, nr, ns, pid, len, ShortDateTime(), _data); +- +- break; +- +- case U_FRM: +- +- if (f_id == U_UI) +- { +- sprintf(mon_frm, "%s pid=%X Len=%d >[%s]\r%s\r", AGW_path, pid, len, ShortDateTime(), _data); // "= AGW_path + ctrl + '>' + time_now + #13; +- } +- else if (f_id == U_FRMR) +- { +- // _data = copy(_data + #0#0#0, 1, 3); +- // mon_frm = AGW_path + ctrl + '>' + time_now + #13 + inttohex((byte(data[1]) shl 16) or (byte(data[2]) shl 8) or byte(data[3]), 6) + #13#13; +- } +- else +- sprintf(mon_frm, "%s%s>[%s]\r", AGW_path, ctrl, ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13; +- +- break; +- +- case S_FRM: +- +- // mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' >' + time_now + #13; +- sprintf(mon_frm, "%s%s R%d>[%s]\r", AGW_path, ctrl, nr, ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13; +- +- break; +- +- } +- +- // stringAdd(mon_frm, "", 1); // Add 0 at the end of each frame +- +- // I think we send to all AGW sockets +- +- for (i = 0; i < AGWConCount; i++) +- { +- AGW = AGWUsers[i]; +- +- if (AGW->Monitor) +- { +- if (RX) +- { +- +- +- case f_id of +- I_I : AGW_data = AGW_I_frame(agw_port,CallFrom,CallTo,mon_frm); +- S_RR : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); +- S_RNR : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); +- S_REJ : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); +- U_SABM: AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); +- U_DISC: AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); +- U_DM : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); +- U_UA : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); +- U_FRMR: AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); +- U_UI : AGW_data = AGW_U_frame(agw_port,CallFrom,CallTo,mon_frm); +- +- AGW_send_to_app(AGW->socket, AGW_data); +- +- +- } +- else +- { +- AGW_data = AGW_T_Frame(agw_port, CallFrom, CallTo, mon_frm); +- AGW_send_to_app(AGW->socket, AGW_data); +- } +- } +- } +-} +- +-*/ +- +- +- +- +-void AGW_Process_Input(AGWUser * AGW) +-{ +- struct AGWHeader * Frame = (struct AGWHeader *)AGW->data_in; +- byte * Data = &AGW->data_in[36]; +- +- switch (Frame->DataKind) +- { +- case 'P': +- +-// on_AGW_P_frame(AGW); +-// return; +- +- case 'X': +- +- // Registration response - no need to process +- +- return; +- +- case 'G': +- +- on_AGW_G_frame(Data); +- return; +-/* +- +- case 'x': +- +- on_AGW_Xs_frame(Frame->callfrom); +- return; +- +- +- +- case 'm': +- +- on_AGW_Ms_frame(AGW); +- return; +- +- case 'R': +- +- on_AGW_R_frame(AGW); +- return; +- +- +- // 'g': on_AGW_Gs_frame(AGW,Frame->Port); +- // 'H': on_AGW_H_frame(AGW,Frame->Port); +- // 'y': on_AGW_Ys_frame(AGW,Frame->Port); +- +- case 'Y': +- on_AGW_Y_frame(AGW->socket, Frame->Port, Frame->callfrom, Frame->callto); +- break; +- +- case 'M': +- +- on_AGW_M_frame(Frame->Port, Frame->PID, Frame->callfrom, Frame->callto, Data, Frame->DataLength); +- break; +-*/ +- +- case 'C': +-// case 'v': // Call with digis +- +- on_AGW_C_frame(AGW, Frame, Data); +- return; +- +- +- case 'D': +- +- on_AGW_D_frame(Frame->Port, Frame->callfrom, Frame->callto, Data, Frame->DataLength); +- return; +- +- case 'd': +- +- on_AGW_Ds_frame(Frame->Port, Frame->callfrom, Frame->callto, Frame); +- return; +- +- case 'U': +- case 'S': +- case 'I': +- case 'T': +- +- // Monitor Data +- +- if (AGWMonEnable) +- on_AGW_Mon_frame(Data, Frame->DataLength, Frame->DataKind); +- +- return; +- +-/* +- +- // 'V': on_AGW_V_frame(AGW,Frame->Port,PID,CallFrom,CallTo,Data); +- // 'c': on_AGW_Cs_frame(sAGWocket,Frame->Port,PID,CallFrom,CallTo); +- +- +- case 'K': +- +- on_AGW_K_frame(Frame); +- return; +- +- case 'k': +- on_AGW_Ks_frame(AGW); +- return; +- */ +- default: +- Debugprintf("AGW %c", Frame->DataKind); +- } +-} ++// AGW Interface ++ ++#include "QtTermTCP.h" ++#include "TabDialog.h" ++#include ++#include ++#include ++ ++#ifndef WIN32 ++#define strtok_s strtok_r ++#endif ++ ++#define UCHAR unsigned char ++#define byte unsigned char ++ ++myTcpSocket * AGWSock; ++ ++extern QColor monRxText; ++extern QColor monTxText; ++ ++extern QColor outputText; ++extern QColor EchoText; ++extern QColor WarningText; ++ ++extern QColor newTabText; ++ ++extern QTabWidget *tabWidget; ++extern QWidget * mythis; ++ ++extern int AGWEnable; ++extern int AGWMonEnable; ++extern int AGWLocalTime; ++extern int AGWMonNodes; ++extern char AGWTermCall[12]; ++extern char AGWBeaconDest[12]; ++extern char AGWBeaconPath[80]; ++extern int AGWBeaconInterval; ++extern char AGWBeaconPorts[80]; ++extern char AGWBeaconMsg[260]; ++ ++extern char AGWHost[128]; ++extern int AGWPortNum; ++extern int AGWPaclen; ++ ++extern Ui_ListenSession * KISSMonSess; ++ ++extern char listenCText[4096]; ++extern int ConnectBeep; ++ ++extern QList _sessions; ++ ++extern QLabel * Status1; ++extern QLabel * Status2; ++extern QLabel * Status3; ++extern QLabel * Status4; ++ ++extern QMenu *connectMenu; ++extern QAction *discAction; ++extern QAction *YAPPSend; ++ ++extern QAction *actHost[17]; ++ ++// Session Type Equates ++ ++#define Term 1 ++#define Mon 2 ++#define Listen 4 ++ ++extern int TermMode; ++ ++#define Single 0 ++#define MDI 1 ++#define Tabbed 2 ++ ++extern int singlemodeFormat; ++ ++typedef struct AGWUser_t ++{ ++ QTcpSocket *socket; ++ unsigned char data_in[8192]; ++ int data_in_len; ++ unsigned char AGW_frame_buf[512]; ++ int Monitor; ++ int Monitor_raw; ++ Ui_ListenSession * MonSess; // Window for Monitor info ++ ++} AGWUser; ++ ++ ++struct AGWHeader ++{ ++ int Port; ++ unsigned char DataKind; ++ unsigned char filler2; ++ unsigned char PID; ++ unsigned char filler3; ++ char callfrom[10]; ++ char callto[10]; ++ int DataLength; ++ int reserved; ++}; ++ ++#define AGWHDDRRLEN sizeof(struct AGWHeader) ++ ++typedef struct TAGWPort_t ++{ ++ byte PID; ++ int port; ++ char corrcall[10]; ++ char mycall[10]; ++ int Active; ++ QTcpSocket * socket; ++ Ui_ListenSession * Sess; // Terminal Session ++ ++} TAGWPort; ++ ++ ++int AGWConnected = 0; ++int AGWConnecting = 0; ++ ++char * AGWPortList = NULL; ++ ++#define max_sessions 8 ++ ++TAGWPort AGWPort[max_sessions]; ++ ++#define LSB 29 ++#define MSB 30 ++#define MON_ON '1' ++#define MON_OFF '0' ++#define MODE_OUR 0 ++#define MODE_OTHER 1 ++#define MODE_RETRY 2 ++ ++// Don't think we will support more than one, but leave in option ++ ++AGWUser *AGWUsers = NULL; // List of currently connected clients ++ ++void AGW_add_socket(QTcpSocket * socket); ++void AGW_Process_Input(AGWUser * AGW); ++void Send_AGW_X_Frame(QTcpSocket* socket, char * CallFrom); ++void Send_AGW_G_Frame(QTcpSocket* socket); ++void Send_AGW_m_Frame(QTcpSocket* socket); ++void Send_AGW_R_Frame(QTcpSocket* socket); ++ ++Ui_ListenSession * FindFreeWindow(); ++Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label = nullptr); ++void AGW_frame_header(UCHAR * Msg, char AGWPort, char DataKind, unsigned char PID, const char * CallFrom, const char * CallTo, int Len); ++ ++ ++void Debugprintf(const char * format, ...) ++{ ++ char Mess[10000]; ++ va_list arglist; ++ ++ va_start(arglist, format); ++ vsprintf(Mess, format, arglist); ++ qDebug() << Mess; ++ ++ return; ++} ++ ++int ConvToAX25(char * callsign, unsigned char * ax25call) ++{ ++ int i; ++ ++ memset(ax25call, 0x40, 6); // in case short ++ ax25call[6] = 0x60; // default SSID ++ ++ for (i = 0; i < 7; i++) ++ { ++ if (callsign[i] == '-') ++ { ++ // ++ // process ssid and return ++ // ++ i = atoi(&callsign[i + 1]); ++ ++ if (i < 16) ++ { ++ ax25call[6] |= i << 1; ++ return (1); ++ } ++ return (0); ++ } ++ ++ if (callsign[i] == 0 || callsign[i] == 13 || callsign[i] == ' ' || callsign[i] == ',') ++ { ++ // ++ // End of call - no ssid ++ // ++ return (1); ++ } ++ ++ ax25call[i] = callsign[i] << 1; ++ } ++ ++ // ++ // Too many chars ++ // ++ ++ return (0); ++} ++ ++ ++int ConvFromAX25(unsigned char * incall, char * outcall) ++{ ++ int in, out = 0; ++ unsigned char chr; ++ ++ memset(outcall, 0x20, 10); ++ ++ for (in = 0; in < 6; in++) ++ { ++ chr = incall[in]; ++ if (chr == 0x40) ++ break; ++ chr >>= 1; ++ outcall[out++] = chr; ++ } ++ ++ chr = incall[6]; // ssid ++ ++ if (chr == 0x42) ++ { ++ outcall[out++] = '-'; ++ outcall[out++] = 'T'; ++ return out; ++ } ++ ++ if (chr == 0x44) ++ { ++ outcall[out++] = '-'; ++ outcall[out++] = 'R'; ++ return out; ++ } ++ ++ chr >>= 1; ++ chr &= 15; ++ ++ if (chr > 0) ++ { ++ outcall[out++] = '-'; ++ if (chr > 9) ++ { ++ chr -= 10; ++ outcall[out++] = '1'; ++ } ++ chr += 48; ++ outcall[out++] = chr; ++ } ++ return (out); ++} ++ ++void doAGWBeacon() ++{ ++ if (AGWBeaconDest[0] && AGWBeaconPorts[0]) ++ { ++ // Send as M or V depending on Digis ++ ++ UCHAR Msg[512]; ++ char ports[80]; ++ ++ char * ptr, * context; ++ int DataLen; ++ ++ strcpy(ports, AGWBeaconPorts); // strtok changes it ++ ++ ++ // Replace newlines with CR ++ ++ while ((ptr = strchr(AGWBeaconMsg, 10))) ++ *ptr = 13; ++ ++ ptr = strtok_s(ports, " ,", &context); ++ ++ if (AGWBeaconPath[0]) ++ { ++ ++ } ++ else ++ { ++ while (ptr) ++ { ++ DataLen = (int)strlen(AGWBeaconMsg); ++ ++ AGW_frame_header(Msg, atoi(ptr) - 1, 'M', 240, AGWTermCall, AGWBeaconDest, DataLen); ++ memcpy(&Msg[AGWHDDRRLEN], AGWBeaconMsg, DataLen); ++ DataLen += AGWHDDRRLEN; ++ AGWSock->write((char *)Msg, DataLen); ++ ++ ptr = strtok_s(NULL, " ,", &context); ++ } ++ } ++ } ++} ++ ++TAGWPort * get_free_port() ++{ ++ int i = 0; ++ ++ while (i < max_sessions) ++ { ++ if (AGWPort[i].Active == 0) ++ return &AGWPort[i]; ++ ++ i++; ++ } ++ return nullptr; ++} ++ ++TAGWPort * findSession(int AGWChan, char * MyCall, char * OtherCall) ++{ ++ int i = 0; ++ ++ TAGWPort * Sess = nullptr; ++ ++ while (i < max_sessions) ++ { ++ Sess = &AGWPort[i]; ++ ++ if (Sess->Active && Sess->port == AGWChan && strcmp(Sess->corrcall, OtherCall) == 0 && strcmp(Sess->mycall, MyCall) == 0) ++ return Sess; ++ ++ i++; ++ } ++ return nullptr; ++} ++ ++ ++ ++void QtTermTCP::AGWdisplayError(QAbstractSocket::SocketError socketError) ++{ ++ switch (socketError) ++ { ++ case QAbstractSocket::RemoteHostClosedError: ++ break; ++ ++ case QAbstractSocket::HostNotFoundError: ++ QMessageBox::information(this, tr("QtTermTCP"), ++ tr("AGW host was not found. Please check the " ++ "host name and port settings.")); ++ ++ Status1->setText("AGW Connection Failed"); ++ ++ break; ++ ++ case QAbstractSocket::ConnectionRefusedError: ++ ++ Status1->setText("AGW Connection Refused"); ++ break; ++ ++ default: ++ ++ Status1->setText("AGW Connection Failed"); ++ } ++ ++ AGWConnecting = 0; ++ AGWConnected = 0; ++} ++ ++void QtTermTCP::AGWreadyRead() ++{ ++ int Read; ++ unsigned char Buffer[4096]; ++ myTcpSocket* Socket = static_cast(QObject::sender()); ++ ++ // read the data from the socket ++ ++ Read = Socket->read((char *)Buffer, 4095); ++ ++ int AGWHeaderLen = sizeof(struct AGWHeader); ++ ++ AGWUser * AGW = NULL; ++ ++ AGW = AGWUsers; ++ ++ if (AGW == NULL) ++ return; ++ ++ memcpy(&AGW->data_in[AGW->data_in_len], Buffer, Read); ++ ++ AGW->data_in_len += Read; ++ ++ while (AGW->data_in_len >= AGWHeaderLen) // Make sure have at least header ++ { ++ struct AGWHeader * Hddr = (struct AGWHeader *)AGW->data_in; ++ ++ int AgwLen = Hddr->DataLength + AGWHeaderLen; ++ ++ if (AGW->data_in_len >= AgwLen) ++ { ++ // Have frame as well ++ ++ AGW_Process_Input(AGW); ++ ++ AGW->data_in_len -= AgwLen; ++ ++ memmove(AGW->data_in, &AGW->data_in[AgwLen], AGW->data_in_len); ++ } ++ else ++ return; // Wait for the data ++ } ++ ++} ++ ++void QtTermTCP::onAGWSocketStateChanged(QAbstractSocket::SocketState socketState) ++{ ++ myTcpSocket* sender = static_cast(QObject::sender()); ++ Ui_ListenSession * Sess = (Ui_ListenSession *)sender->Sess; ++ int i; ++ ++ if (socketState == QAbstractSocket::UnconnectedState) ++ { ++ // Close any connections ++ ++ Status1->setText("AGW Disconnected"); ++ actHost[16]->setVisible(0); ++ ++ int i = 0; ++ ++ TAGWPort * AGW = nullptr; ++ ++ for (i = 0; i < max_sessions; i++) ++ { ++ AGW = &AGWPort[i]; ++ ++ if (AGW->Active && AGW->socket) ++ { ++ AGW->Active = 0; ++ AGW->socket = nullptr; ++ ++ Sess = AGW->Sess; ++ ++ if (Sess) ++ { ++ // Send Disconnected ++ ++ 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[32]; ++ 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"); ++ } ++ ++ setMenus(false); ++ ++ // if Single Split or Monitor leave session allocated to AGW ++ ++ if (TermMode == Single && (Sess->SessionType & Mon)) ++ { ++ return; ++ } ++ ++ Sess->AGWSession = nullptr; ++ AGW->Sess = nullptr; ++ } ++ } ++ } ++ ++ // Free the monitor Window ++ ++ if (AGWUsers && AGWUsers->MonSess) ++ { ++ Sess = AGWUsers->MonSess; ++ ++ char Msg[] = "Disconnected\r"; ++ ++ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), ++ Sess->monWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red ++ ++ if (TermMode == MDI) ++ Sess->setWindowTitle("Monitor Session Disconnected"); ++ ++ else if (TermMode == Tabbed) ++ tabWidget->setTabText(Sess->Tab, "Monitor"); ++ ++ Sess->AGWSession = nullptr; ++ AGWUsers->MonSess = nullptr; ++ } ++ ++ if (TermMode == Single && (singlemodeFormat & Mon)) ++ { ++ //Re-renable TCP connects ++ ++ for (int i = 0; i < MAXHOSTS; i++) ++ actHost[i]->setVisible(1); ++ } ++ ++ ++ AGWConnected = 0; ++ } ++ else if (socketState == QAbstractSocket::ConnectedState) ++ { ++ AGWConnected = 1; ++ AGWConnecting = 0; ++ ++ Status1->setText("AGW Connected"); ++ ++ AGW_add_socket(sender); ++ ++ actHost[16]->setVisible(1); // Enable AGW Connect Line ++ ++ // Send X frame to register Term Call ++ ++ if (AGWTermCall[0]) ++ Send_AGW_X_Frame(sender, AGWTermCall); ++ ++ Send_AGW_G_Frame(sender); // Request Port List ++ ++ // 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->AGWSession == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ ++ // Create a window if none found, else reuse old ++ ++ if (Sess == NULL) ++ { ++ Sess = newWindow((QObject *)mythis, Mon, ""); ++ } ++ } ++ else if (TermMode == Tabbed) ++ { ++ // Tabbed - look for free session ++ ++ for (i = 8; i; i--) ++ { ++ S = _sessions.at(i); ++ ++ if (S->clientSocket == NULL && S->KISSSession == NULL && S->AGWSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ } ++ else if (TermMode == Single && (singlemodeFormat & Mon)) ++ { ++ S = _sessions.at(0); ++ ++ if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) ++ Sess = S; ++ ++ } ++ ++ if (Sess) ++ { ++ AGWUsers->MonSess = Sess; ++// Sess->AGWSession = sender; // Flag as in use ++ ++ if (TermMode == MDI) ++ Sess->setWindowTitle("AGW Monitor Window"); ++ else if (TermMode == Tabbed) ++ tabWidget->setTabText(Sess->Tab, "AGW Mon"); ++ else if (TermMode == Single) ++ mythis->setWindowTitle("AGW Monitor Window"); ++ ++ if (TermMode == Single && (singlemodeFormat & Mon)) ++ { ++ // Can't be connected, so leave state alone, but disable TCP connects ++ ++ for (int i = 0; i < MAXHOSTS; i++) ++ actHost[i]->setVisible(0); ++ ++ } ++ else if (TermMode != Tabbed) // Not ideal, but AGW mon window is unlikely to be active window ++ { ++ discAction->setEnabled(false); ++ YAPPSend->setEnabled(false); ++ connectMenu->setEnabled(false); ++ } ++ ++ Sess->mlocaltime = AGWLocalTime; ++ Sess->MonitorNODES = AGWMonNodes; ++ ++ Send_AGW_R_Frame(sender); // Request Version ++ Send_AGW_m_Frame(sender); // Request Monitor Frames ++ } ++ } ++} ++ ++ ++void QtTermTCP::ConnecttoAGW() ++{ ++ delete(AGWSock); ++ ++ AGWSock = new myTcpSocket(); ++ ++ connect(AGWSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(AGWdisplayError(QAbstractSocket::SocketError))); ++ connect(AGWSock, SIGNAL(readyRead()), this, SLOT(AGWreadyRead())); ++ connect(AGWSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onAGWSocketStateChanged(QAbstractSocket::SocketState))); ++ ++ AGWSock->connectToHost(AGWHost, AGWPortNum); ++ ++ Status1->setText("AGW Connecting"); ++ ++ return; ++} ++ ++int AGWBeaconTimer = 0; ++ ++ ++void QtTermTCP::AGWTimer() ++{ ++ // Runs every 10 Seconds ++ ++ if (AGWConnected == 0 && AGWConnecting == 0) ++ { ++ AGWConnecting = true; ++ ConnecttoAGW(); ++ } ++ ++ if (AGWBeaconInterval) ++ { ++ AGWBeaconTimer++; ++ ++ if (AGWBeaconTimer >= AGWBeaconInterval * 6) ++ { ++ AGWBeaconTimer = 0; ++ ++ if (AGWConnected) ++ doAGWBeacon(); ++ } ++ } ++} ++ ++ ++void AGW_del_socket(void * socket) ++{ ++ if (AGWUsers->socket == socket) ++ { ++ free(AGWUsers); ++ AGWUsers = nullptr; ++ } ++} ++ ++ ++ ++void AGW_add_socket(QTcpSocket * socket) ++{ ++ AGWUser * User = (struct AGWUser_t *)malloc(sizeof(struct AGWUser_t)); // One Client ++ memset(User, 0, sizeof(struct AGWUser_t)); ++ ++ User->socket = socket; ++ ++ AGWUsers = User; ++}; ++ ++void AGWWindowClosing(Ui_ListenSession *Sess) ++{ ++ if (AGWUsers && AGWUsers->MonSess == Sess) ++ AGWUsers->MonSess = NULL; ++} ++ ++ ++ ++void AGW_frame_header(UCHAR * Msg, char AGWPort, char DataKind, unsigned char PID, const char * CallFrom, const char * CallTo, int Len) ++{ ++ struct AGWHeader * Hddr = (struct AGWHeader *)Msg; ++ memset(Hddr, 0, sizeof(struct AGWHeader)); ++ ++ Hddr->Port = AGWPort; ++ Hddr->DataLength = Len; ++ Hddr->DataKind = DataKind; ++ Hddr->PID = PID; ++ strcpy(Hddr->callfrom, CallFrom); ++ strcpy(Hddr->callto, CallTo); ++}; ++ ++ ++/* ++ ++// AGW to APP frames ++ ++UCHAR * AGW_R_Frame() ++{ ++ UCHAR * Msg = AGW_frame_header(0, 'R', 0, "", "", 8); ++ ++// stringAdd(Msg, (UCHAR *)AGWVersion, 8); ++ ++ return Msg; ++}; ++*/ ++ ++ ++void Send_AGW_X_Frame(QTcpSocket* socket, char * CallFrom) ++{ ++ UCHAR Msg[512]; ++ ++ AGW_frame_header(Msg, 0, 'X', 0, CallFrom, "", 0); ++ socket->write((char *)Msg, AGWHDDRRLEN); ++} ++ ++void Send_AGW_G_Frame(QTcpSocket* socket) ++{ ++ UCHAR Msg[512]; ++ ++ AGW_frame_header(Msg, 0, 'G', 0, "", "", 0); ++ socket->write((char *)Msg, AGWHDDRRLEN); ++} ++ ++void Send_AGW_m_Frame(QTcpSocket* socket) ++{ ++ UCHAR Msg[512]; ++ ++ // Request Monitoring. Add Extended form if connected to BPQ ++ ++ AGW_frame_header(Msg, 0, 'm', 0, "", "", 12); ++ ++ Msg[AGWHDDRRLEN] = AGWLocalTime; ++ Msg[AGWHDDRRLEN + 1] = AGWMonNodes; ++ Msg[AGWHDDRRLEN + 2] = AGWMonEnable; ++ Msg[AGWHDDRRLEN + 3] = 0; ++ ++ memcpy(&Msg[AGWHDDRRLEN + 4], (void *)&AGWUsers->MonSess->portmask, 8); ++ ++ socket->write((char *)Msg, AGWHDDRRLEN + 12); ++} ++ ++void Send_AGW_R_Frame(QTcpSocket* socket) ++{ ++ UCHAR Msg[512]; ++ ++ // Request Version ++ ++ AGW_frame_header(Msg, 0, 'R', 0, "", "", 0); ++ socket->write((char *)Msg, AGWHDDRRLEN); ++} ++ ++ ++/* ++ ++ ++UCHAR * AGW_Y_Frame(int port, char * CallFrom, char *CallTo, int frame_outstanding) ++{ ++ UCHAR * Msg; ++ ++ Msg = AGW_frame_header(port, 'Y', 0, CallFrom, CallTo, 4); ++ ++ stringAdd(Msg, (UCHAR *)&frame_outstanding, 4); ++ return Msg; ++} ++ ++ ++ ++*/ ++ ++ ++void Send_AGW_C_Frame(Ui_ListenSession * Sess, int Port, char * CallFrom, char * CallTo, char * Data, int DataLen) ++{ ++ UCHAR Msg[512]; ++ char Title[64]; ++ ++ // We should allocate a AGW session record ++ ++ TAGWPort * AX25Sess; ++ ++ // FIrst check that we don't already have a session between these calla ++ ++ if (Port == -1) ++ return; ++ ++ Debugprintf("Send_AGW_C_Frame"); ++ ++ AX25Sess = findSession(Port, CallTo, CallFrom); ++ ++ if (AX25Sess) ++ { ++ // Seems this can be called twice ++ ++ if (Sess->AGWSession == nullptr) ++ QMessageBox::information(mythis, "QtTermTCP", "You already have a conenction to that call"); ++ ++ return; ++ } ++ ++ AX25Sess = get_free_port(); ++ ++ if (AX25Sess) ++ { ++ AX25Sess->Active = 1; ++ AX25Sess->port = Port; ++ AX25Sess->Sess = Sess; // Crosslink AGW and Term Sessions ++ AX25Sess->PID = 240; ++ ++ Sess->AGWSession = AX25Sess; ++ ++ strcpy(AX25Sess->mycall, CallTo); ++ strcpy(AX25Sess->corrcall, CallFrom); ++ ++ AX25Sess->socket = AGWSock; ++ ++ if (DataLen) // Digis so use 'v' frame ++ { ++ AGW_frame_header(Msg, Port, 'v', 240, CallFrom, CallTo, DataLen); ++ memcpy(&Msg[AGWHDDRRLEN], (UCHAR *)Data, DataLen); ++ } ++ else ++ { ++ AGW_frame_header(Msg, Port, 'C', 240, CallFrom, CallTo, DataLen); ++ } ++ ++ DataLen += AGWHDDRRLEN; ++ ++ AGWSock->write((char *)Msg, DataLen); ++ ++ sprintf(Title, "Connecting to %s", CallTo); ++ ++ if (TermMode == MDI) ++ Sess->setWindowTitle(Title); ++ else if (TermMode == Tabbed) ++ tabWidget->setTabText(Sess->Tab, "Connecting"); ++ else if (TermMode == Single) ++ mythis->setWindowTitle(Title); ++ ++ } ++} ++ ++ ++void Send_AGW_Ds_Frame(void * Sess) ++{ ++ TAGWPort * AGW = (TAGWPort *)Sess; ++ UCHAR Msg[512]; ++ ++ AGW_frame_header(Msg, AGW->port, 'd', 240, AGW->corrcall, AGW->mycall, 0); ++ if (AGW->socket) ++ AGW->socket->write((char *)Msg, AGWHDDRRLEN); ++} ++ ++ ++ ++void Send_AGW_D_Frame(TAGWPort * AGW, UCHAR * Data, int DataLen) ++{ ++ UCHAR Msg[512]; ++ ++ AGW_frame_header(Msg, AGW->port, 'D', AGW->PID, AGW->corrcall, AGW->mycall, DataLen); ++ ++ memcpy(&Msg[AGWHDDRRLEN], Data, DataLen); ++ ++ DataLen += AGWHDDRRLEN; ++ ++ AGW->socket->write((char *)Msg, DataLen); ++} ++ ++ ++ ++/* ++ ++UCHAR * AGW_T_Frame(int port, char * CallFrom, char * CallTo, char * Data) ++{ ++ UCHAR * Msg; ++ int DataLen; ++ ++ DataLen = strlen(Data); ++ ++ Msg = AGW_frame_header(port, 'T', 0, CallFrom, CallTo, DataLen); ++ ++ stringAdd(Msg, (byte *)Data, DataLen); ++ ++ return Msg; ++} ++ ++// Raw Monitor ++UCHAR * AGW_K_Frame(int port, int PID, char * CallFrom, char * CallTo, UCHAR * Data, int DataLen) ++{ ++ UCHAR Msg[512]; ++ ++ DataLen = Data->Length; ++ ++ AGW_frame_header(Msg, port, 'K', PID, CallFrom, CallTo, DataLen); ++ ++// stringAdd(Msg, Data->Data, Data->Length); ++ ++// freeString(Data); ++ ++ return Msg; ++} ++ ++// APP to AGW frames ++ ++void on_AGW_P_frame(AGWUser * AGW) ++{ ++ ++} ++ ++*/ ++ ++void on_AGW_G_frame(unsigned char * Data) ++{ ++ if (AGWPortList) ++ free(AGWPortList); ++ ++ AGWPortList = (char *)strdup((char *)Data); ++}; ++ ++/* ++ ++void on_AGW_Ms_frame(AGWUser * AGW) ++{ ++ AGW->Monitor ^= 1; // Flip State ++} ++ ++ ++void on_AGW_R_frame(AGWUser * AGW) ++{ ++// AGW_send_to_app(AGW->socket, AGW_R_Frame()); ++} ++ ++ ++ ++void on_AGW_Y_frame(void * socket, int snd_ch, char * CallFrom, char * CallTo) ++{ ++ int frames; ++ TAGWPort * AX25Sess; ++ ++// AX25Sess = get_user_port_by_calls(snd_ch, CallFrom, CallTo); ++ ++// if (AX25Sess) ++// { ++ //frames = AX25port[snd_ch][user_port].in_data_buf.Count; ++// frames = AX25Sess->in_data_buf.Count + AX25Sess->I_frame_buf.Count; ++// ; ++// AGW_send_to_app(socket, AGW_Y_Frame(snd_ch, CallFrom, CallTo, frames)); ++// } ++} ++ ++// UI Transmit ++ ++void on_AGW_M_frame(int port, byte PID, char * CallFrom, char *CallTo, byte * Msg, int MsgLen) ++{ ++ byte path[80]; ++ char Calls[80]; ++ UCHAR * Data = newString(); ++ ++ stringAdd(Data, Msg, MsgLen); ++ ++ sprintf(Calls, "%s,%s", CallTo, CallFrom); ++ ++ get_addr(Calls, 0, 0, path); ++ ++ Add(&all_frame_buf[port], ++ make_frame(Data, path, PID, 0, 0, U_FRM, U_UI, FALSE, SET_F, SET_C)); ++ ++} ++ ++*/ ++void on_AGW_C_frame(AGWUser * AGW, struct AGWHeader * Frame, byte * Msg) ++{ ++ int snd_ch = Frame->Port; ++ char * CallFrom = Frame->callfrom; ++ char * CallTo = Frame->callto; ++ char Title[64]; ++ int i = 0; ++ ++ TAGWPort * AX25Sess; ++ ++ // Connection received - may be incoming or response to our connect ++ ++ // See if incoming ++ ++ if (strstr((char *)Msg, (const char *)"CONNECTED To")) ++ { ++ // incoming call ++ ++ AX25Sess = get_free_port(); ++ ++ if (AX25Sess) ++ { ++ // Look for/create Terminal Window for connection ++ ++ 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 & Listen) && S->clientSocket == NULL) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ ++ // Create a window if none found, else reuse old ++ ++ if (Sess == NULL) ++ { ++ Sess = newWindow((QObject *)mythis, Listen, ""); ++ } ++ } ++ else if (TermMode == Tabbed) ++ { ++ // Single 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; ++ } ++ } ++ } ++ else ++ { ++ // Single - Only one available ++ S = _sessions.at(0); ++ ++ if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) ++ Sess = S; ++ } ++ ++ if (Sess == NULL) ++ { ++ // Clear connection by sendinf d fraame ++ ++ UCHAR Msg[512]; ++ ++ int snd_ch = Frame->Port; ++ char * CallFrom = Frame->callfrom; ++ char * CallTo = Frame->callto; ++ ++ AGW_frame_header(Msg, Frame->Port, 'd', 240, Frame->callto, Frame->callfrom, 0); ++ if (AGW->socket) ++ AGW->socket->write((char *)Msg, AGWHDDRRLEN); ++ ++ return; ++ } ++ ++ if (Sess) ++ { ++ sprintf(Title, "Connected to %s", CallFrom); ++ ++ QApplication::alert(mythis, 0); ++ ++ if (TermMode == MDI) ++ { ++ Sess->setWindowTitle(Title); ++ } ++ else if (TermMode == Tabbed) ++ { ++ tabWidget->setTabText(i, CallFrom); ++ tabWidget->tabBar()->setTabTextColor(i, newTabText); ++ } ++ ++ else if (TermMode == Single) ++ mythis->setWindowTitle(Title); ++ ++ AX25Sess->Active = 1; ++ AX25Sess->port = snd_ch; ++ AX25Sess->Sess = Sess; // Crosslink AGW and Term Sessions ++ AX25Sess->PID = 240;; ++ ++ Sess->AGWSession = AX25Sess; ++ ++ strcpy(AX25Sess->mycall, CallFrom); ++ strcpy(AX25Sess->corrcall, CallTo); ++ ++ AX25Sess->socket = AGW->socket; ++ ++ setMenus(true); ++ ++ if (ConnectBeep) ++ myBeep(&ConnectWAV); ++ ++ // Send CText if defined ++ ++ if (listenCText[0]) ++ Send_AGW_D_Frame(AX25Sess, (unsigned char *)listenCText, (int)strlen(listenCText)); ++ ++ // Send Message to Terminal ++ ++ char Msg[80]; ++ ++ sprintf(Msg, "Incoming AGW Connection from %s\r\r", CallFrom); ++ ++ WritetoOutputWindow(Sess, (unsigned char *)Msg, (int)strlen(Msg)); ++ return; ++ } ++ } ++ } ++ ++ // Reply to out connect request - look for our connection ++ ++ AX25Sess = findSession(snd_ch, CallFrom, CallTo); ++ ++ if (AX25Sess) ++ { ++ Ui_ListenSession * Sess = AX25Sess->Sess; ++ ++ sprintf(Title, "Connected to %s", CallFrom); ++ ++ if (TermMode == MDI) ++ Sess->setWindowTitle(Title); ++ else if (TermMode == Tabbed) ++ tabWidget->setTabText(Sess->Tab, CallFrom); ++ else if (TermMode == Single) ++ mythis->setWindowTitle(Title); ++ ++ setMenus(true); ++ ++ int Len = sprintf(Title, "*** Connected to %s\r", CallFrom); ++ ++ ProcessReceivedData(Sess, (unsigned char *)Title, Len); ++ } ++ ++} ++ ++ ++ ++void on_AGW_D_frame(int snd_ch, char * CallFrom, char * CallTo, byte * Msg, int Len) ++{ ++ TAGWPort * AX25Sess; ++ ++ AX25Sess = findSession(snd_ch, CallFrom, CallTo); ++ ++ if (AX25Sess) ++ { ++ ProcessReceivedData(AX25Sess->Sess, Msg, Len); ++ } ++} ++ ++extern "C" void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Msg, int len); ++ ++void on_AGW_Mon_frame(byte * Msg, int Len, char Type) ++{ ++ if (AGWUsers && AGWUsers->MonSess && AGWUsers->MonSess->monWindow) ++ { ++ unsigned char copy[512]; ++ ++ copy[0] = 0x1b; ++ if (Type == 'T') ++ copy[1] = 91; ++ else ++ copy[1] = 17; ++ ++ memcpy(©[2], Msg, Len); ++ WritetoMonWindow(AGWUsers->MonSess, copy, Len + 2); ++ } ++} ++ ++ ++ ++void on_AGW_Ds_frame(int AGWChan, char * CallFrom, char * CallTo, struct AGWHeader * Frame) ++{ ++ TAGWPort * AX25Sess; ++ char * Msg = (char *)Frame; ++ Msg = &Msg[36]; ++ ++ char Reply[128] = ""; ++ ++ memcpy(Reply, Msg, Frame->DataLength); ++ ++ // Disconnect Sessiom ++ ++ AX25Sess = findSession(AGWChan, CallFrom, CallTo); ++ ++ if (AX25Sess) ++ { ++ Ui_ListenSession * Sess = AX25Sess->Sess; ++ ++ WritetoOutputWindowEx(Sess, (unsigned char *)Reply, (int)strlen(Reply), ++ 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[32]; ++ 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"); ++ } ++ ++ Sess->AGWSession = nullptr; ++ AX25Sess->Sess = nullptr; ++ AX25Sess->Active = 0; ++ ++ setMenus(false); ++ } ++ else ++ { ++ // Session not found ++ } ++} ++ ++ ++void AGW_AX25_data_in(void * Sess, UCHAR * data, int Len) ++{ ++ TAGWPort * AX25Sess = (TAGWPort *)Sess; ++ int len = 250, sendlen; ++ UCHAR pkt[512]; ++ ++ while (Len) ++ { ++ if (Len > len) ++ sendlen = len; ++ else ++ sendlen = Len; ++ ++ memcpy(pkt, data, sendlen); ++ ++ Len -= sendlen; ++ ++ memmove(data, &data[sendlen], Len); ++ ++ Send_AGW_D_Frame(AX25Sess, pkt, sendlen); ++ } ++ ++} ++ ++ ++/* ++ ++void AGW_frame_monitor(byte snd_ch, byte * path, UCHAR * data, byte pid, byte nr, byte ns, byte f_type, byte f_id, byte rpt, byte pf, byte cr, byte RX) ++{ ++ char mon_frm[512]; ++ char AGW_path[256]; ++ UCHAR * AGW_data; ++ ++ const char * frm; ++ byte * datap = data->Data; ++ byte _data[512]; ++ byte * p_data = _data; ++ int _datalen; ++ ++ char agw_port; ++ char CallFrom[10], CallTo[10], Digi[80]; ++ ++ int i; ++ const char * ctrl; ++ int len; ++ ++ AGWUser * AGW; ++ ++ UNUSED(rpt); ++ ++ len = data->Length; ++ ++ // if (pid == 0xCF) ++ // data = parse_NETROM(data, f_id); ++ // IP parsing ++ // else if (pid == 0xCC) ++ // data = parse_IP(data); ++ // ARP parsing ++ // else if (pid == 0xCD) ++ // data = parse_ARP(data); ++ // ++ ++ if (len > 0) ++ { ++ for (i = 0; i < len; i++) ++ { ++ if (datap[i] > 31 || datap[i] == 13 || datap[i] == 9) ++ *(p_data++) = datap[i]; ++ } ++ } ++ ++ _datalen = p_data - _data; ++ ++ if (_datalen) ++ { ++ byte * ptr = _data; ++ i = 0; ++ ++ // remove successive cr or cr on end while (i < _datalen) ++ ++ while (i < _datalen) ++ { ++ if ((_data[i] == 13) && (_data[i + 1] = 13)) ++ i++; ++ else ++ *(ptr++) = _data[i++]; ++ } ++ ++ if (*(ptr - 1) == 13) ++ ptr--; ++ ++ *ptr = 0; ++ ++ _datalen = ptr - _data; ++ } ++ ++ agw_port = snd_ch; ++ ++ get_monitor_path(path, CallTo, CallFrom, Digi); ++ ++ ctrl = ""; ++ frm = ""; ++ ++ switch (f_id) ++ { ++ case I_I: ++ ++ frm = "I"; ++ if (cr == SET_C && pf == SET_P) ++ ctrl = " P"; ++ ++ break; ++ ++ case S_RR: ++ ++ frm = "RR"; ++ if (pf == SET_P) ++ ctrl = " P/F"; ++ ++ break; ++ ++ case S_RNR: ++ ++ frm = "RNR"; ++ if (pf == SET_P) ++ ctrl = " P/F"; ++ ++ break; ++ ++ case S_REJ: ++ ++ frm = "REJ"; ++ if (pf == SET_P) ++ ctrl = " P/F"; ++ ++ break; ++ ++ case U_SABM: ++ ++ frm = "SABM"; ++ if (cr == SET_C && pf == SET_P) ++ ctrl = " P"; ++ ++ break; ++ ++ case U_DISC: ++ ++ frm = "DISC"; ++ if (cr == SET_C && pf == SET_P) ++ ctrl = " P"; ++ break; ++ ++ case U_DM: ++ ++ frm = "DM"; ++ if ((cr == SET_R) && (pf == SET_P)) ++ ctrl = " F "; ++ break; ++ ++ case U_UA: ++ ++ frm = "UA"; ++ if ((cr == SET_R) && (pf == SET_P)) ++ ctrl = " F "; ++ ++ break; ++ ++ case U_FRMR: ++ ++ frm = "FRMR"; ++ if ((cr == SET_R) && (pf == SET_P)) ++ ctrl = " F "; ++ break; ++ ++ case U_UI: ++ ++ frm = "UI"; ++ if ((pf == SET_P)) ++ ctrl = " P/F"; ++ } ++ ++ if (Digi[0]) ++ sprintf(AGW_path, " %d:Fm %s To %s Via %s <%s", snd_ch + 1, CallFrom, CallTo, Digi, frm); ++ else ++ sprintf(AGW_path, " %d:Fm %s To %s <%s", snd_ch + 1, CallFrom, CallTo, frm); ++ ++ ++ switch (f_type) ++ { ++ case I_FRM: ++ ++ //mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' S' + inttostr(ns) + ' pid=' + dec2hex(pid) + ' Len=' + inttostr(len) + ' >' + time_now + #13 + _data + #13#13; ++ sprintf(mon_frm, "%s%s R%d S%d pid=%X Len=%d >[%s]\r%s\r", AGW_path, ctrl, nr, ns, pid, len, ShortDateTime(), _data); ++ ++ break; ++ ++ case U_FRM: ++ ++ if (f_id == U_UI) ++ { ++ sprintf(mon_frm, "%s pid=%X Len=%d >[%s]\r%s\r", AGW_path, pid, len, ShortDateTime(), _data); // "= AGW_path + ctrl + '>' + time_now + #13; ++ } ++ else if (f_id == U_FRMR) ++ { ++ // _data = copy(_data + #0#0#0, 1, 3); ++ // mon_frm = AGW_path + ctrl + '>' + time_now + #13 + inttohex((byte(data[1]) shl 16) or (byte(data[2]) shl 8) or byte(data[3]), 6) + #13#13; ++ } ++ else ++ sprintf(mon_frm, "%s%s>[%s]\r", AGW_path, ctrl, ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13; ++ ++ break; ++ ++ case S_FRM: ++ ++ // mon_frm = AGW_path + ctrl + ' R' + inttostr(nr) + ' >' + time_now + #13; ++ sprintf(mon_frm, "%s%s R%d>[%s]\r", AGW_path, ctrl, nr, ShortDateTime()); // "= AGW_path + ctrl + '>' + time_now + #13; ++ ++ break; ++ ++ } ++ ++ // stringAdd(mon_frm, "", 1); // Add 0 at the end of each frame ++ ++ // I think we send to all AGW sockets ++ ++ for (i = 0; i < AGWConCount; i++) ++ { ++ AGW = AGWUsers[i]; ++ ++ if (AGW->Monitor) ++ { ++ if (RX) ++ { ++ ++ ++ case f_id of ++ I_I : AGW_data = AGW_I_frame(agw_port,CallFrom,CallTo,mon_frm); ++ S_RR : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); ++ S_RNR : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); ++ S_REJ : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); ++ U_SABM: AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); ++ U_DISC: AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); ++ U_DM : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); ++ U_UA : AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); ++ U_FRMR: AGW_data = AGW_S_frame(agw_port,CallFrom,CallTo,mon_frm); ++ U_UI : AGW_data = AGW_U_frame(agw_port,CallFrom,CallTo,mon_frm); ++ ++ AGW_send_to_app(AGW->socket, AGW_data); ++ ++ ++ } ++ else ++ { ++ AGW_data = AGW_T_Frame(agw_port, CallFrom, CallTo, mon_frm); ++ AGW_send_to_app(AGW->socket, AGW_data); ++ } ++ } ++ } ++} ++ ++*/ ++ ++ ++ ++ ++void AGW_Process_Input(AGWUser * AGW) ++{ ++ struct AGWHeader * Frame = (struct AGWHeader *)AGW->data_in; ++ byte * Data = &AGW->data_in[36]; ++ ++ switch (Frame->DataKind) ++ { ++ case 'P': ++ ++// on_AGW_P_frame(AGW); ++// return; ++ ++ case 'X': ++ ++ // Registration response - no need to process ++ ++ return; ++ ++ case 'G': ++ ++ on_AGW_G_frame(Data); ++ return; ++/* ++ ++ case 'x': ++ ++ on_AGW_Xs_frame(Frame->callfrom); ++ return; ++ ++ ++ ++ case 'm': ++ ++ on_AGW_Ms_frame(AGW); ++ return; ++ ++ case 'R': ++ ++ on_AGW_R_frame(AGW); ++ return; ++ ++ ++ // 'g': on_AGW_Gs_frame(AGW,Frame->Port); ++ // 'H': on_AGW_H_frame(AGW,Frame->Port); ++ // 'y': on_AGW_Ys_frame(AGW,Frame->Port); ++ ++ case 'Y': ++ on_AGW_Y_frame(AGW->socket, Frame->Port, Frame->callfrom, Frame->callto); ++ break; ++ ++ case 'M': ++ ++ on_AGW_M_frame(Frame->Port, Frame->PID, Frame->callfrom, Frame->callto, Data, Frame->DataLength); ++ break; ++*/ ++ ++ case 'C': ++// case 'v': // Call with digis ++ ++ on_AGW_C_frame(AGW, Frame, Data); ++ return; ++ ++ ++ case 'D': ++ ++ on_AGW_D_frame(Frame->Port, Frame->callfrom, Frame->callto, Data, Frame->DataLength); ++ return; ++ ++ case 'd': ++ ++ on_AGW_Ds_frame(Frame->Port, Frame->callfrom, Frame->callto, Frame); ++ return; ++ ++ case 'U': ++ case 'S': ++ case 'I': ++ case 'T': ++ ++ // Monitor Data ++ ++ if (AGWMonEnable) ++ on_AGW_Mon_frame(Data, Frame->DataLength, Frame->DataKind); ++ ++ return; ++ ++/* ++ ++ // 'V': on_AGW_V_frame(AGW,Frame->Port,PID,CallFrom,CallTo,Data); ++ // 'c': on_AGW_Cs_frame(sAGWocket,Frame->Port,PID,CallFrom,CallTo); ++ ++ ++ case 'K': ++ ++ on_AGW_K_frame(Frame); ++ return; ++ ++ case 'k': ++ on_AGW_Ks_frame(AGW); ++ return; ++ */ ++ default: ++ Debugprintf("AGW %c", Frame->DataKind); ++ } ++} +--- qttermtcp-0.0.0.79.orig/AGWConnect.ui ++++ qttermtcp-0.0.0.79/AGWConnect.ui +@@ -1,148 +1,148 @@ +- +- +- AGWConnectDkg +- +- +- +- 0 +- 0 +- 500 +- 400 +- +- +- +- Dialog +- +- +- +- +- 10 +- 10 +- 480 +- 380 +- +- +- +- +- +- +- +- +- Call From +- +- +- +- +- +- +- +- +- +- Call To +- +- +- +- +- +- +- true +- +- +- QComboBox::NoInsert +- +- +- +- +- +- +- Digis +- +- +- +- +- +- +- +- +- +- +- +- Radio Ports +- +- +- +- +- +- +- +- +- +- 6 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- +- +- OK +- +- +- +- +- +- +- Cancel +- +- +- +- +- +- +- +- +- +- +- +- okButton +- clicked() +- AGWConnectDkg +- accept() +- +- +- 278 +- 253 +- +- +- 96 +- 254 +- +- +- +- +- cancelButton +- clicked() +- AGWConnectDkg +- reject() +- +- +- 369 +- 253 +- +- +- 179 +- 282 +- +- +- +- +- ++ ++ ++ AGWConnectDkg ++ ++ ++ ++ 0 ++ 0 ++ 500 ++ 400 ++ ++ ++ ++ Dialog ++ ++ ++ ++ ++ 10 ++ 10 ++ 480 ++ 380 ++ ++ ++ ++ ++ ++ ++ ++ ++ Call From ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Call To ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ QComboBox::NoInsert ++ ++ ++ ++ ++ ++ ++ Digis ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Radio Ports ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 6 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ OK ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ okButton ++ clicked() ++ AGWConnectDkg ++ accept() ++ ++ ++ 278 ++ 253 ++ ++ ++ 96 ++ 254 ++ ++ ++ ++ ++ cancelButton ++ clicked() ++ AGWConnectDkg ++ reject() ++ ++ ++ 369 ++ 253 ++ ++ ++ 179 ++ 282 ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/AGWParams.ui ++++ qttermtcp-0.0.0.79/AGWParams.ui +@@ -1,395 +1,395 @@ +- +- +- AGWParams +- +- +- +- 0 +- 0 +- 562 +- 491 +- +- +- +- Dialog +- +- +- +- +- 120 +- 50 +- 113 +- 20 +- +- +- +- +- +- +- 12 +- 83 +- 537 +- 215 +- +- +- +- Beacon Setup +- +- +- +- +- 110 +- 24 +- 113 +- 20 +- +- +- +- +- +- +- 110 +- 54 +- 113 +- 20 +- +- +- +- +- +- +- 108 +- 84 +- 45 +- 20 +- +- +- +- +- +- +- 110 +- 114 +- 43 +- 20 +- +- +- +- +- +- +- 14 +- 22 +- 75 +- 21 +- +- +- +- Destination +- +- +- +- +- +- 14 +- 52 +- 75 +- 21 +- +- +- +- Digipeaters +- +- +- +- +- +- 14 +- 82 +- 75 +- 21 +- +- +- +- Interval +- +- +- +- +- +- 14 +- 112 +- 75 +- 21 +- +- +- +- Ports +- +- +- +- +- +- 176 +- 82 +- 75 +- 22 +- +- +- +- Minutes +- +- +- +- +- +- 176 +- 112 +- 137 +- 21 +- +- +- +- (Separate with commas) +- +- +- +- +- +- 14 +- 144 +- 75 +- 21 +- +- +- +- Message +- +- +- +- +- +- 110 +- 140 +- 425 +- 63 +- +- +- +- +- +- +- 14 +- 158 +- 95 +- 21 +- +- +- +- (max 256 chars) +- +- +- +- +- +- +- 12 +- 300 +- 537 +- 123 +- +- +- +- TNC Setup +- +- +- +- +- 110 +- 24 +- 101 +- 20 +- +- +- +- +- +- +- 110 +- 54 +- 47 +- 20 +- +- +- +- +- +- +- 110 +- 84 +- 47 +- 20 +- +- +- +- +- +- +- 16 +- 24 +- 47 +- 13 +- +- +- +- Host +- +- +- +- +- +- 16 +- 54 +- 47 +- 13 +- +- +- +- Port +- +- +- +- +- +- 16 +- 84 +- 47 +- 13 +- +- +- +- Paclen +- +- +- +- +- +- +- 18 +- 48 +- 111 +- 21 +- +- +- +- Terminal Callsign +- +- +- +- +- +- 180 +- 440 +- 95 +- 23 +- +- +- +- OK +- +- +- +- +- +- 292 +- 440 +- 79 +- 23 +- +- +- +- Cancel +- +- +- +- +- +- 152 +- 16 +- 23 +- 25 +- +- +- +- Qt::RightToLeft +- +- +- +- +- +- +- +- +- 20 +- 18 +- 135 +- 21 +- +- +- +- Enable AGW Interface +- +- +- +- +- +- 255 +- 18 +- 216 +- 21 +- +- +- +- Qt::RightToLeft +- +- +- Enable AGW Monitor Window +- +- +- +- +- +- +- cancelButton +- clicked() +- AGWParams +- reject() +- +- +- 369 +- 253 +- +- +- 179 +- 282 +- +- +- +- +- okButton +- clicked() +- AGWParams +- accept() +- +- +- 278 +- 253 +- +- +- 96 +- 254 +- +- +- +- +- ++ ++ ++ AGWParams ++ ++ ++ ++ 0 ++ 0 ++ 562 ++ 491 ++ ++ ++ ++ Dialog ++ ++ ++ ++ ++ 120 ++ 50 ++ 113 ++ 20 ++ ++ ++ ++ ++ ++ ++ 12 ++ 83 ++ 537 ++ 215 ++ ++ ++ ++ Beacon Setup ++ ++ ++ ++ ++ 110 ++ 24 ++ 113 ++ 20 ++ ++ ++ ++ ++ ++ ++ 110 ++ 54 ++ 113 ++ 20 ++ ++ ++ ++ ++ ++ ++ 108 ++ 84 ++ 45 ++ 20 ++ ++ ++ ++ ++ ++ ++ 110 ++ 114 ++ 43 ++ 20 ++ ++ ++ ++ ++ ++ ++ 14 ++ 22 ++ 75 ++ 21 ++ ++ ++ ++ Destination ++ ++ ++ ++ ++ ++ 14 ++ 52 ++ 75 ++ 21 ++ ++ ++ ++ Digipeaters ++ ++ ++ ++ ++ ++ 14 ++ 82 ++ 75 ++ 21 ++ ++ ++ ++ Interval ++ ++ ++ ++ ++ ++ 14 ++ 112 ++ 75 ++ 21 ++ ++ ++ ++ Ports ++ ++ ++ ++ ++ ++ 176 ++ 82 ++ 75 ++ 22 ++ ++ ++ ++ Minutes ++ ++ ++ ++ ++ ++ 176 ++ 112 ++ 137 ++ 21 ++ ++ ++ ++ (Separate with commas) ++ ++ ++ ++ ++ ++ 14 ++ 144 ++ 75 ++ 21 ++ ++ ++ ++ Message ++ ++ ++ ++ ++ ++ 110 ++ 140 ++ 425 ++ 63 ++ ++ ++ ++ ++ ++ ++ 14 ++ 158 ++ 95 ++ 21 ++ ++ ++ ++ (max 256 chars) ++ ++ ++ ++ ++ ++ ++ 12 ++ 300 ++ 537 ++ 123 ++ ++ ++ ++ TNC Setup ++ ++ ++ ++ ++ 110 ++ 24 ++ 101 ++ 20 ++ ++ ++ ++ ++ ++ ++ 110 ++ 54 ++ 47 ++ 20 ++ ++ ++ ++ ++ ++ ++ 110 ++ 84 ++ 47 ++ 20 ++ ++ ++ ++ ++ ++ ++ 16 ++ 24 ++ 47 ++ 13 ++ ++ ++ ++ Host ++ ++ ++ ++ ++ ++ 16 ++ 54 ++ 47 ++ 13 ++ ++ ++ ++ Port ++ ++ ++ ++ ++ ++ 16 ++ 84 ++ 47 ++ 13 ++ ++ ++ ++ Paclen ++ ++ ++ ++ ++ ++ ++ 18 ++ 48 ++ 111 ++ 21 ++ ++ ++ ++ Terminal Callsign ++ ++ ++ ++ ++ ++ 180 ++ 440 ++ 95 ++ 23 ++ ++ ++ ++ OK ++ ++ ++ ++ ++ ++ 292 ++ 440 ++ 79 ++ 23 ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ 152 ++ 16 ++ 23 ++ 25 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ ++ ++ ++ ++ ++ ++ 20 ++ 18 ++ 135 ++ 21 ++ ++ ++ ++ Enable AGW Interface ++ ++ ++ ++ ++ ++ 255 ++ 18 ++ 216 ++ 21 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ Enable AGW Monitor Window ++ ++ ++ ++ ++ ++ ++ cancelButton ++ clicked() ++ AGWParams ++ reject() ++ ++ ++ 369 ++ 253 ++ ++ ++ 179 ++ 282 ++ ++ ++ ++ ++ okButton ++ clicked() ++ AGWParams ++ accept() ++ ++ ++ 278 ++ 253 ++ ++ ++ 96 ++ 254 ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/ColourConfig.ui ++++ qttermtcp-0.0.0.79/ColourConfig.ui +@@ -1,440 +1,440 @@ +- +- +- ColourDialog +- +- +- +- 0 +- 0 +- 342 +- 407 +- +- +- +- Colour Selection +- +- +- +- +- 66 +- 350 +- 199 +- 33 +- +- +- +- +- 6 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- +- +- OK +- +- +- +- +- +- +- Cancel +- +- +- +- +- +- +- +- +- 216 +- 15 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- +- +- +- +- +- +- 216 +- 247 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- +- +- +- +- +- +- 216 +- 276 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- Input +- +- +- +- +- +- 216 +- 44 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- Normal +- +- +- +- +- +- 216 +- 73 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- Echoed +- +- +- +- +- +- 216 +- 102 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- Warning +- +- +- +- +- +- 21 +- 16 +- 187 +- 16 +- +- +- +- Terminal Background +- +- +- +- +- +- 21 +- 45 +- 185 +- 16 +- +- +- +- Normal Text +- +- +- +- +- +- 21 +- 74 +- 191 +- 16 +- +- +- +- Echoed Text +- +- +- +- +- +- 21 +- 103 +- 185 +- 16 +- +- +- +- Warning Text +- +- +- +- +- +- 21 +- 248 +- 189 +- 16 +- +- +- +- Input Background +- +- +- +- +- +- 21 +- 277 +- 183 +- 16 +- +- +- +- Input Text +- +- +- +- +- +- 216 +- 189 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- RX Text +- +- +- +- +- +- 216 +- 131 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- +- +- +- +- +- +- 216 +- 218 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- Other Text +- +- +- +- +- +- 216 +- 160 +- 75 +- 23 +- +- +- +- +- 75 +- 0 +- +- +- +- +- 75 +- 16777215 +- +- +- +- TX Text +- +- +- +- +- +- 21 +- 132 +- 187 +- 16 +- +- +- +- Monitor Background +- +- +- +- +- +- 21 +- 161 +- 183 +- 16 +- +- +- +- TX Text +- +- +- +- +- +- 21 +- 190 +- 187 +- 16 +- +- +- +- RX Text +- +- +- +- +- +- 21 +- 219 +- 189 +- 16 +- +- +- +- Other Text +- +- +- +- +- +- ++ ++ ++ ColourDialog ++ ++ ++ ++ 0 ++ 0 ++ 342 ++ 407 ++ ++ ++ ++ Colour Selection ++ ++ ++ ++ ++ 66 ++ 350 ++ 199 ++ 33 ++ ++ ++ ++ ++ 6 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ OK ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ 216 ++ 15 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 216 ++ 247 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 216 ++ 276 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ Input ++ ++ ++ ++ ++ ++ 216 ++ 44 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ Normal ++ ++ ++ ++ ++ ++ 216 ++ 73 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ Echoed ++ ++ ++ ++ ++ ++ 216 ++ 102 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ Warning ++ ++ ++ ++ ++ ++ 21 ++ 16 ++ 187 ++ 16 ++ ++ ++ ++ Terminal Background ++ ++ ++ ++ ++ ++ 21 ++ 45 ++ 185 ++ 16 ++ ++ ++ ++ Normal Text ++ ++ ++ ++ ++ ++ 21 ++ 74 ++ 191 ++ 16 ++ ++ ++ ++ Echoed Text ++ ++ ++ ++ ++ ++ 21 ++ 103 ++ 185 ++ 16 ++ ++ ++ ++ Warning Text ++ ++ ++ ++ ++ ++ 21 ++ 248 ++ 189 ++ 16 ++ ++ ++ ++ Input Background ++ ++ ++ ++ ++ ++ 21 ++ 277 ++ 183 ++ 16 ++ ++ ++ ++ Input Text ++ ++ ++ ++ ++ ++ 216 ++ 189 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ RX Text ++ ++ ++ ++ ++ ++ 216 ++ 131 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 216 ++ 218 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ Other Text ++ ++ ++ ++ ++ ++ 216 ++ 160 ++ 75 ++ 23 ++ ++ ++ ++ ++ 75 ++ 0 ++ ++ ++ ++ ++ 75 ++ 16777215 ++ ++ ++ ++ TX Text ++ ++ ++ ++ ++ ++ 21 ++ 132 ++ 187 ++ 16 ++ ++ ++ ++ Monitor Background ++ ++ ++ ++ ++ ++ 21 ++ 161 ++ 183 ++ 16 ++ ++ ++ ++ TX Text ++ ++ ++ ++ ++ ++ 21 ++ 190 ++ 187 ++ 16 ++ ++ ++ ++ RX Text ++ ++ ++ ++ ++ ++ 21 ++ 219 ++ 189 ++ 16 ++ ++ ++ ++ Other Text ++ ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/DialogButtonBottom.ui ++++ qttermtcp-0.0.0.79/DialogButtonBottom.ui +@@ -1,100 +1,100 @@ +- +- +- +- +- Dialog +- +- +- +- 0 +- 0 +- 400 +- 300 +- +- +- +- Dialog +- +- +- +- +- 20 +- 250 +- 351 +- 33 +- +- +- +- +- 0 +- +- +- 6 +- +- +- +- +- Qt::Horizontal +- +- +- +- 131 +- 31 +- +- +- +- +- +- +- +- OK +- +- +- +- +- +- +- Cancel +- +- +- +- +- +- +- +- +- +- +- okButton +- clicked() +- Dialog +- accept() +- +- +- 278 +- 253 +- +- +- 96 +- 254 +- +- +- +- +- cancelButton +- clicked() +- Dialog +- reject() +- +- +- 369 +- 253 +- +- +- 179 +- 282 +- +- +- +- +- ++ ++ ++ ++ ++ Dialog ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 300 ++ ++ ++ ++ Dialog ++ ++ ++ ++ ++ 20 ++ 250 ++ 351 ++ 33 ++ ++ ++ ++ ++ 0 ++ ++ ++ 6 ++ ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ ++ 131 ++ 31 ++ ++ ++ ++ ++ ++ ++ ++ OK ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ okButton ++ clicked() ++ Dialog ++ accept() ++ ++ ++ 278 ++ 253 ++ ++ ++ 96 ++ 254 ++ ++ ++ ++ ++ cancelButton ++ clicked() ++ Dialog ++ reject() ++ ++ ++ 369 ++ 253 ++ ++ ++ 179 ++ 282 ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/KISSConfig.ui ++++ qttermtcp-0.0.0.79/KISSConfig.ui +@@ -1,536 +1,536 @@ +- +- +- KISSDialog +- +- +- +- 0 +- 0 +- 432 +- 399 +- +- +- +- KISS Configuration +- +- +- +- +- 40 +- 360 +- 351 +- 33 +- +- +- +- +- 6 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- +- +- OK +- +- +- +- +- +- +- Cancel +- +- +- +- +- +- +- +- +- 10 +- 168 +- 401 +- 57 +- +- +- +- TCP Setup +- +- +- +- +- 78 +- 20 +- 111 +- 22 +- +- +- +- +- +- +- 290 +- 21 +- 47 +- 22 +- +- +- +- +- +- +- 16 +- 24 +- 47 +- 13 +- +- +- +- Host +- +- +- +- +- +- 222 +- 24 +- 47 +- 13 +- +- +- +- Port +- +- +- +- +- +- 85 +- 63 +- 47 +- 22 +- +- +- +- +- +- +- 20 +- 66 +- 47 +- 13 +- +- +- +- Port +- +- +- +- +- +- +- 10 +- 118 +- 411 +- 51 +- +- +- +- Serial TNC +- +- +- +- +- 138 +- 20 +- 111 +- 22 +- +- +- +- +- +- +- 20 +- 23 +- 131 +- 16 +- +- +- +- Select Device +- +- +- +- +- +- 276 +- 20 +- 47 +- 22 +- +- +- +- Speed +- +- +- +- +- +- 328 +- 21 +- 51 +- 22 +- +- +- +- 19200 +- +- +- +- +- +- +- 12 +- 10 +- 149 +- 21 +- +- +- +- Enable KISS Interface +- +- +- +- +- +- 158 +- 9 +- 23 +- 25 +- +- +- +- Qt::RightToLeft +- +- +- +- +- +- +- +- +- 214 +- 11 +- 61 +- 17 +- +- +- +- MYCALL +- +- +- +- +- +- 292 +- 10 +- 91 +- 22 +- +- +- +- +- +- +- 25 +- 240 +- 47 +- 13 +- +- +- +- Paclen +- +- +- +- +- +- 98 +- 240 +- 47 +- 22 +- +- +- +- +- +- +- 213 +- 240 +- 66 +- 16 +- +- +- +- MaxFrame +- +- +- +- +- +- 288 +- 240 +- 47 +- 22 +- +- +- +- +- +- +- 25 +- 270 +- 47 +- 20 +- +- +- +- Frack +- +- +- +- +- +- 98 +- 270 +- 36 +- 22 +- +- +- +- +- +- +- 213 +- 273 +- 47 +- 13 +- +- +- +- Retries +- +- +- +- +- +- 288 +- 270 +- 36 +- 22 +- +- +- +- +- +- +- 12 +- 35 +- 149 +- 21 +- +- +- +- Allow incoming connects +- +- +- +- +- +- 158 +- 34 +- 23 +- 21 +- +- +- +- Qt::RightToLeft +- +- +- +- +- +- +- +- +- 160 +- 60 +- 20 +- 20 +- +- +- +- Qt::RightToLeft +- +- +- +- +- +- +- +- +- 12 +- 60 +- 141 +- 20 +- +- +- +- Enable checksum +- +- +- +- +- +- 160 +- 84 +- 20 +- 20 +- +- +- +- Qt::RightToLeft +- +- +- +- +- +- +- +- +- 12 +- 85 +- 141 +- 20 +- +- +- +- Enable ACKMODE +- +- +- +- +- +- 150 +- 300 +- 111 +- 21 +- +- +- +- Qt::RightToLeft +- +- +- Set TXDelay +- +- +- +- +- +- 99 +- 300 +- 36 +- 22 +- +- +- +- +- +- +- 26 +- 302 +- 71 +- 16 +- +- +- +- TXDelay +- +- +- +- +- +- 200 +- 80 +- 151 +- 30 +- +- +- +- Open MH Window +- +- +- +- +- +- 390 +- 83 +- 20 +- 20 +- +- +- +- Qt::RightToLeft +- +- +- +- +- +- +- +- +- +- okButton +- clicked() +- KISSDialog +- accept() +- +- +- 278 +- 253 +- +- +- 96 +- 254 +- +- +- +- +- cancelButton +- clicked() +- KISSDialog +- reject() +- +- +- 369 +- 253 +- +- +- 179 +- 282 +- +- +- +- +- ++ ++ ++ KISSDialog ++ ++ ++ ++ 0 ++ 0 ++ 432 ++ 399 ++ ++ ++ ++ KISS Configuration ++ ++ ++ ++ ++ 40 ++ 360 ++ 351 ++ 33 ++ ++ ++ ++ ++ 6 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ OK ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ 10 ++ 168 ++ 401 ++ 57 ++ ++ ++ ++ TCP Setup ++ ++ ++ ++ ++ 78 ++ 20 ++ 111 ++ 22 ++ ++ ++ ++ ++ ++ ++ 290 ++ 21 ++ 47 ++ 22 ++ ++ ++ ++ ++ ++ ++ 16 ++ 24 ++ 47 ++ 13 ++ ++ ++ ++ Host ++ ++ ++ ++ ++ ++ 222 ++ 24 ++ 47 ++ 13 ++ ++ ++ ++ Port ++ ++ ++ ++ ++ ++ 85 ++ 63 ++ 47 ++ 22 ++ ++ ++ ++ ++ ++ ++ 20 ++ 66 ++ 47 ++ 13 ++ ++ ++ ++ Port ++ ++ ++ ++ ++ ++ ++ 10 ++ 118 ++ 411 ++ 51 ++ ++ ++ ++ Serial TNC ++ ++ ++ ++ ++ 138 ++ 20 ++ 111 ++ 22 ++ ++ ++ ++ ++ ++ ++ 20 ++ 23 ++ 131 ++ 16 ++ ++ ++ ++ Select Device ++ ++ ++ ++ ++ ++ 276 ++ 20 ++ 47 ++ 22 ++ ++ ++ ++ Speed ++ ++ ++ ++ ++ ++ 328 ++ 21 ++ 51 ++ 22 ++ ++ ++ ++ 19200 ++ ++ ++ ++ ++ ++ ++ 12 ++ 10 ++ 149 ++ 21 ++ ++ ++ ++ Enable KISS Interface ++ ++ ++ ++ ++ ++ 158 ++ 9 ++ 23 ++ 25 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ ++ ++ ++ ++ ++ ++ 214 ++ 11 ++ 61 ++ 17 ++ ++ ++ ++ MYCALL ++ ++ ++ ++ ++ ++ 292 ++ 10 ++ 91 ++ 22 ++ ++ ++ ++ ++ ++ ++ 25 ++ 240 ++ 47 ++ 13 ++ ++ ++ ++ Paclen ++ ++ ++ ++ ++ ++ 98 ++ 240 ++ 47 ++ 22 ++ ++ ++ ++ ++ ++ ++ 213 ++ 240 ++ 66 ++ 16 ++ ++ ++ ++ MaxFrame ++ ++ ++ ++ ++ ++ 288 ++ 240 ++ 47 ++ 22 ++ ++ ++ ++ ++ ++ ++ 25 ++ 270 ++ 47 ++ 20 ++ ++ ++ ++ Frack ++ ++ ++ ++ ++ ++ 98 ++ 270 ++ 36 ++ 22 ++ ++ ++ ++ ++ ++ ++ 213 ++ 273 ++ 47 ++ 13 ++ ++ ++ ++ Retries ++ ++ ++ ++ ++ ++ 288 ++ 270 ++ 36 ++ 22 ++ ++ ++ ++ ++ ++ ++ 12 ++ 35 ++ 149 ++ 21 ++ ++ ++ ++ Allow incoming connects ++ ++ ++ ++ ++ ++ 158 ++ 34 ++ 23 ++ 21 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ ++ ++ ++ ++ ++ ++ 160 ++ 60 ++ 20 ++ 20 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ ++ ++ ++ ++ ++ ++ 12 ++ 60 ++ 141 ++ 20 ++ ++ ++ ++ Enable checksum ++ ++ ++ ++ ++ ++ 160 ++ 84 ++ 20 ++ 20 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ ++ ++ ++ ++ ++ ++ 12 ++ 85 ++ 141 ++ 20 ++ ++ ++ ++ Enable ACKMODE ++ ++ ++ ++ ++ ++ 150 ++ 300 ++ 111 ++ 21 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ Set TXDelay ++ ++ ++ ++ ++ ++ 99 ++ 300 ++ 36 ++ 22 ++ ++ ++ ++ ++ ++ ++ 26 ++ 302 ++ 71 ++ 16 ++ ++ ++ ++ TXDelay ++ ++ ++ ++ ++ ++ 200 ++ 80 ++ 151 ++ 30 ++ ++ ++ ++ Open MH Window ++ ++ ++ ++ ++ ++ 390 ++ 83 ++ 20 ++ 20 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ okButton ++ clicked() ++ KISSDialog ++ accept() ++ ++ ++ 278 ++ 253 ++ ++ ++ 96 ++ 254 ++ ++ ++ ++ ++ cancelButton ++ clicked() ++ KISSDialog ++ reject() ++ ++ ++ 369 ++ 253 ++ ++ ++ 179 ++ 282 ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/ListenPort.ui ++++ qttermtcp-0.0.0.79/ListenPort.ui +@@ -1,140 +1,140 @@ +- +- +- ListenPort +- +- +- +- 0 +- 0 +- 445 +- 654 +- +- +- +- Dialog +- +- +- +- +- 0 +- 0 +- 431 +- 301 +- +- +- +- +- +- +- +- +- +- 100 +- 30 +- +- +- +- +- 100 +- 30 +- +- +- +- Port +- +- +- +- +- +- +- +- 0 +- 30 +- +- +- +- +- 100 +- 30 +- +- +- +- +- +- +- +- +- 0 +- 30 +- +- +- +- +- 16777215 +- 30 +- +- +- +- CText +- +- +- +- +- +- +- +- 0 +- 150 +- +- +- +- +- 401 +- 150 +- +- +- +- +- +- +- +- +- +- +- +- 0 +- 50 +- +- +- +- +- 16777215 +- 50 +- +- +- +- Qt::RightToLeft +- +- +- QDialogButtonBox::Save +- +- +- +- +- +- +- Qt::LeftToRight +- +- +- Enable Listen +- +- +- +- +- +- +- +- +- +- +- ++ ++ ++ ListenPort ++ ++ ++ ++ 0 ++ 0 ++ 445 ++ 654 ++ ++ ++ ++ Dialog ++ ++ ++ ++ ++ 0 ++ 0 ++ 431 ++ 301 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 100 ++ 30 ++ ++ ++ ++ ++ 100 ++ 30 ++ ++ ++ ++ Port ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 30 ++ ++ ++ ++ ++ 100 ++ 30 ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 30 ++ ++ ++ ++ ++ 16777215 ++ 30 ++ ++ ++ ++ CText ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 150 ++ ++ ++ ++ ++ 401 ++ 150 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ 50 ++ ++ ++ ++ ++ 16777215 ++ 50 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ QDialogButtonBox::Save ++ ++ ++ ++ ++ ++ ++ Qt::LeftToRight ++ ++ ++ Enable Listen ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/QtTermTCP.cpp ++++ qttermtcp-0.0.0.79/QtTermTCP.cpp +@@ -1,8165 +1,8165 @@ +-// Qt Version of BPQTermTCP +- +-// Application icon design by Red PE1RRR +- +-#define VersionString "0.0.0.79" +- +- +-// .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 arrivn other window +-// .19 Fix Scrollback +-// .20 WinXP compatibility changes +-// .21 Save Window Positions +-// .22 Open a window on first start +-// .23 Add Tabbed display option +-// .24 Fix crash when setting Monitor flags in Tabbed mode +-// .25 Add AGW mode +-// .26 Add sending CTRL/C CTRL/D and CTRL/Z) +-// .27 Limit size of windows to 10000 lines +-// Fix YAPP in Tabbed Mode +-// .28 Add AGW Beacon +-// .29 Fix allocating Listem sessions to tabs connected using AGW +-// .30 Fix allocationd AGW Monitor Sessions +-// .31 Fix output being written to the wrong place when window is scrolled back +-// .32 Fix connect with digis +-// .33 Add StripLF option +-// .34 Improvements for Andriod +-// Option to change Menu Fonts +-// Fix receiving part lines when scrolled back +-// .35 Fix PE if not in Tabbed Mode +-// .36 Improved dialogs mainly for Android +-// Try to make sure sessions are closed before exiting +-// .37 Replace VT with LF (for pasting from BPQ32 Terminal Window) +-// Dont show AGW status line if AGW interface is disabled +-// Don't show Window Menu in Single Mode +-// .38 Protect against connect to normal Telnet Port. +-// Send CTEXT and Beep for inward AGW Connects +-// Make sending Idle and Connect beeps configurable +-// Change displayed Monitor flags when active window changed. +-// Fix duplicate text on long lines +-// .39 Add option to Convert non-utf8 charaters +-// .40 Prevent crash if AGW monitor Window closed +-// .41 Allow AGW Config and Connect dialogs to be resized with scrollbars +-// Fix disabling connect flag on current session when AGW connects +-// .42 Fix some bugs in AGW session handling +-// .43 Include Ross KD5LPB's fixes for MAC +-// .44 Ctrl/[ sends ESC (0x1b) +-// .45 Add VARA support Nov 2021 +-// .46 Fix dialog size on VARA setup +-// .47 Move VARA Status indicator. +-// Add FLRIG PTT for VARA +-// .48 Check that YAPP Receive Directory has been set +-// Save separate configs for VARA, VARAFM and VARASAT +-// .49 Add BBS Monitor Dec 2021 +-// .50 Make Serial port support optional for Android Version +-// .51 Add KISS TNC Support May 2022 +-// .52 Save partially typed lines on cursor up May 2022 +-// .53 Add UI Mode for KISS Sessions May 2022 +-// Fix saving KISS Paclen (b) +-// Fix Keepalive (c) +-// .54 Add option to change screen colours June 2022 +-// .55 Build without optimisation +-// .56 Add Teletext mode Nov 2022 +-// .57 Fix KISS mode incoming call handling +-// .58 Add method to toggle Normal/Teletext Mode +-// Fix KISS multiple session protection +-// .59 Add Teletext double height mode +-// .60 Add option to name sessions Jan 2023 +-// .61 Add VARA Init Script Feb 2023 +-// .62 Fix running AGW in single session mode Feb 2023 +-// .63 Fix handling split monitor frame (no fe in buffer) Apr 2023 +-// .64 Add Clear Screen command to context menu Apr 2023 +-// .65 Fixes for 63 port version of BPQ May 2023 +-// .66 Colour Tab of incoming calls June 2023 +-// .67 Add config Yapp RX Size dialog July 2023 +-// Fix 63 port montoring +- +-// .68 Sept 2023 +- +-// Remember last used host on restart +-// Add AutoConnect in Tabbed Mode +-// Fix auto copy when QtTerm not active window +- +-// .69 October 2023 +- +-// Options related to sound alerts moved to a separte menu in Setup +-// Allow use of WAV files instead of Beep sound for sound alerts +-// Enable an alarm to be sounded when one of a list of words or phrases is received. +- +-// .70 October 2023 +- +-// Include some .wav files in resources +-// Add Test button to Alert setup dialog +- +-// .71 October 2023 +- +-// Add option to use local time +-// Fixes for Mac OS +- +-// .72 November 2023 +-// Don't display "Enable Monitor" on startup +- +-// .73 November 2023 +-// Raise RTS on KISS serial port +- +-// .74 April 2024 +-// Support BPQKISS TNCs with CHECKSUM and/or ACKMODE enabled +- +-// .75 May 2024 +-// Flush Monitor log file every minute +- +-// .76 August 2024 +-// Fix using digs in KISS UI mode. +-// Add option to send TXDELAY to KISS TNC +- +-// .77 +-// Support multichannel KISS TNCs (Beta 1) +-// Fix using AGW listen in single terminal mode +- +-// .78 +-// Fix restoring monitor flags when connecting to current host +- +- +-// .79 +-// Add KISS MHEARD Window (Feb 2025) +- +- +-#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 +-#include +-#ifdef USESERIAL +-#include +-#include +-#endif +-#ifndef WIN32 +-#define strtok_s strtok_r +-#endif +-#include +-#include +-#ifndef WIN32 +-#include +-#endif +- +-#include "ax25.h" +- +-#define UNREFERENCED_PARAMETER(P) (P) +- +-void DecodeTeleText(Ui_ListenSession * Sess, char * text); +- +-char Host[MAXHOSTS + 1][100] = { "" }; +-int Port[MAXHOSTS + 1] = { 0 }; +-char UserName[MAXHOSTS + 1][80] = { "" }; +-char Password[MAXHOSTS + 1][80] = { "" }; +-char MonParams[MAXHOSTS + 1][80] = { "" }; +-char SessName[MAXHOSTS + 1][80] = { "" }; +-int ListenPort = 8015; +- +-// Session Type Equates +- +-#define Term 1 +-#define Mon 2 +-#define Listen 4 +- +-// Presentation - Single Window, MDI or Tabbed +- +-int TermMode = 0; +- +-#define Single 0 +-#define MDI 1 +-#define Tabbed 2 +- +-int singlemodeFormat = Mon + Term; +- +-char monStyleSheet[128] = "background-color: rgb(0,255,255)"; +-char termStyleSheet[128] = "background-color: rgb(255,0,255);"; +-char inputStyleSheet[128] = "color: rgb(255, 0, 0); background-color: rgb(255,255,0);"; +- +-QColor monBackground = qRgb(0, 255, 255); +-QColor monRxText = qRgb(0, 0, 255); +-QColor monTxText = qRgb(255, 0, 0); +-QColor monOtherText = qRgb(0, 0, 0); +- +-QColor termBackground = qRgb(255, 0, 255); +-QColor outputText = qRgb(0, 0, 0); +-QColor EchoText = qRgb(0, 0, 255); +-QColor WarningText = qRgb(255, 0, 0); +-QColor inputBackground = qRgb(255, 255, 0); +-QColor inputText = qRgb(0, 0, 255); +- +-QColor newTabText = qRgb(255, 0, 0); // Red +-QColor oldTabText = qRgb(0, 0, 0); // Black +- +- +-// There is something odd about this. It doesn't match BPQTERMTCP though it looks the same +- +-// Chat uses these (+ 10) +-//{ 0, 4, 9, 11, 13, 16, 17, 42, 45, 50, 61, 64, 66, 72, 81, 84, 85, 86, 87, 89 }; +- +-// As we have a white background we need dark colours +- +-// 0 is black. 23 is normal output (blue) 81 is red (used by AGW Mon) +-// for monitor in colour, host sends 17 for RX Text, 81 for TX Text but code converts to monRx/TxText qrgb values +- +-QRgb Colours[256] = { 0, +- qRgb(0,0,0), qRgb(0,0,128), qRgb(0,0,192), qRgb(0,0,255), // 1 - 4 +- qRgb(0,64,0), qRgb(0,64,128), qRgb(0,64,192), qRgb(0,64,255), // 5 - 8 +- qRgb(0,128,0), qRgb(0,128,128), qRgb(0,128,192), qRgb(0,128,255), // 9 - 12 +- qRgb(0,192,0), qRgb(0,192,128), qRgb(0,192,192), qRgb(0,192,255), // 13 - 16 +- qRgb(0,255,0), qRgb(0,255,128), qRgb(0,255,192), qRgb(0,255,255), // 17 - 20 +- +- qRgb(64,0,0), qRgb(64,0,128), qRgb(64,0,192), qRgb(0,0,255), // 21 +- qRgb(64,64,0), qRgb(64,64,128), qRgb(64,64,192), qRgb(64,64,255), +- qRgb(64,128,0), qRgb(64,128,128), qRgb(64,128,192), qRgb(64,128,255), +- qRgb(64,192,0), qRgb(64,192,128), qRgb(64,192,192), qRgb(64,192,255), +- qRgb(64,255,0), qRgb(64,255,128), qRgb(64,255,192), qRgb(64,255,255), +- +- qRgb(128,0,0), qRgb(128,0,128), qRgb(128,0,192), qRgb(128,0,255), // 41 +- qRgb(128,64,0), qRgb(128,64,128), qRgb(128,64,192), qRgb(128,64,255), +- qRgb(128,128,0), qRgb(128,128,128), qRgb(128,128,192), qRgb(128,128,255), +- qRgb(128,192,0), qRgb(128,192,128), qRgb(128,192,192), qRgb(128,192,255), +- qRgb(128,255,0), qRgb(128,255,128), qRgb(128,255,192), qRgb(128,255,255), +- +- qRgb(192,0,0), qRgb(192,0,128), qRgb(192,0,192), qRgb(192,0,255), // 61 - 80 +- qRgb(192,64,0), qRgb(192,64,128), qRgb(192,64,192), qRgb(192,64,255), +- qRgb(192,128,0), qRgb(192,128,128), qRgb(192,128,192), qRgb(192,128,255), +- qRgb(192,192,0), qRgb(192,192,128), qRgb(192,192,192), qRgb(192,192,255), +- qRgb(192,255,0), qRgb(192,255,128), qRgb(192,255,192), qRgb(192,255,255), +- +- qRgb(255,0,0), qRgb(255,0,128), qRgb(255,0,192), qRgb(255,0,255), // 81 - 100 +- qRgb(255,64,0), qRgb(255,64,128), qRgb(255,64,192), qRgb(255,64,255), +- qRgb(255,128,0), qRgb(255,128,128), qRgb(255,128,192), qRgb(255,128,255), +- qRgb(255,192,0), qRgb(255,192,128), qRgb(255,192,192), qRgb(255,192,255), +- qRgb(255,255,0), qRgb(255,255,128), qRgb(255,255,192), qRgb(255,255,255) +-}; +- +- +- +-int SavedHost = 0; // from config +- +-char * sessionList = NULL; // Saved sessions +- +-extern int ChatMode; +-extern int Bells; +-extern int StripLF; +-extern int convUTF8; +- +-extern time_t LastWrite; +-extern int AlertInterval; +-extern int AlertBeep; +-extern int AlertFreq; +-extern int AlertDuration; +-extern int ConnectBeep; +- +-bool useBeep; // use wav files if not set +- +-extern int UseKeywords; +-extern QString KeyWordsFile; +- +-QString ConnectWAV(""); +-QString AlertWAV(""); +-QString BellWAV(""); +-QString IntervalWAV(""); +- +-extern int MaxRXSize; +- +-extern int AutoTeletext; +- +-// AGW Host Interface stuff +- +-int AGWEnable = 0; +-int AGWMonEnable = 0; +-int AGWLocalTime = 0; +-int AGWMonNodes = 0; +-char AGWTermCall[12] = ""; +-char AGWBeaconDest[12] = ""; +-char AGWBeaconPath[80] = ""; +-int AGWBeaconInterval = 0; +-char AGWBeaconPorts[80]; +-char AGWBeaconMsg[260] = ""; +- +- +-char AGWHost[128] = "127.0.0.1"; +-int AGWPortNum = 8000; +-int AGWPaclen = 80; +-extern char * AGWPortList; +-extern myTcpSocket * AGWSock; +- +-typedef struct AGWUser_t +-{ +- QTcpSocket *socket; +- unsigned char data_in[8192]; +- int data_in_len; +- unsigned char AGW_frame_buf[512]; +- int Monitor; +- int Monitor_raw; +- Ui_ListenSession * MonSess; // Window for Monitor info +- +-} AGWUser; +- +-extern AGWUser *AGWUsers; // List of currently connected clients +-void Send_AGW_m_Frame(QTcpSocket* socket); +- +- +-QStringList AGWToCalls; +- +-// KISS Interface +- +-int KISSEnable = 0; +-extern "C" int KISSMonEnable; +-extern "C" int KISSLocalTime; +-extern "C" int KISSMonNodes; +-extern "C" int KISSListen; +-extern "C" int KISSChecksum; +-extern "C" int KISSAckMode; +-extern "C" int KISSMH; +- +-extern "C" short txtail[5]; +-extern "C" short txdelay[5]; +-extern "C" int sendTXDelay[4]; +- +- +- +-char SerialPort[80] = ""; +-char KISSHost[128] = "127.0.0.1"; +-int KISSPortNum = 1000; +-int KISSBAUD = 19200; +-char KISSMYCALL[32]; +-char KISSVia[128]; // Digi String +- +-extern "C" UCHAR axMYCALL[7]; // Mycall in ax.25 +- +-int KISSMode = 0; // Connected (0) or UI (1) +- +-myTcpSocket * KISSSock; +- +-extern "C" void * KISSSockCopy[4]; +- +-int KISSConnected = 0; +-int KISSConnecting = 0; +- +-Ui_ListenSession * KISSMonSess = nullptr; +- +-QSerialPort * m_serial = nullptr; +- +-// VARA Interface +- +-int VARAEnable = 0; +-char VARAHost[128] = "127.0.0.1"; +-char VARAHostHF[128] = "127.0.0.1"; +-char VARAHostFM[128] = "127.0.0.1"; +-char VARAHostSAT[128] = "127.0.0.1"; +-int VARAPortNum = 8000; +-int VARAPortHF = 8000; +-int VARAPortFM = 8000; +-int VARAPortSAT = 8000; +-char VARATermCall[12] = ""; +-char VARAPath[256] = ""; +-char VARAInit[256] = ""; +-char VARAPathHF[256] = ""; +-char VARAPathFM[256] = ""; +-char VARAPathSAT[256] = ""; +- +-int VARA500 = 0; +-int VARA2300 = 1; +-int VARA2750 = 0; +- +-int VARAHF = 1; +-int VARAFM = 0; +-int VARASAT = 0; +- +-myTcpSocket * VARASock; +-myTcpSocket * VARADataSock; +- +-int VARAConnected = 0; +-int VARAConnecting = 0; +- +- +-extern char YAPPPath[256]; +- +-void menuChecked(QAction * Act); +- +-// PTT Stuff +- +-#define PTTRTS 1 +-#define PTTDTR 2 +-#define PTTCAT 4 +-#define PTTCM108 8 +-#define PTTHAMLIB 16 +-#define PTTFLRIG 32 +- +-#ifdef USESERIAL +- +-QSerialPort * hPTTDevice = 0; +-#else +- +- +-#endif +-char PTTPort[80] = ""; // Port for Hardware PTT - may be same as control port. +-int PTTBAUD = 19200; +-int PTTMode = PTTRTS; // PTT Control Flags. +- +-char PTTOnString[128] = ""; +-char PTTOffString[128] = ""; +- +-int CATHex = 1; +- +-unsigned char PTTOnCmd[64]; +-int PTTOnCmdLen = 0; +- +-unsigned char PTTOffCmd[64]; +-int PTTOffCmdLen = 0; +- +-int pttGPIOPin = 17; // Default +-int pttGPIOPinR = 17; +-bool pttGPIOInvert = false; +-bool useGPIO = false; +-bool gotGPIO = false; +- +-int HamLibPort = 4532; +-char HamLibHost[32] = "192.168.1.14"; +- +-int FLRigPort = 12345; +-char FLRigHost[32] = "127.0.0.1"; +- +- +-char CM108Addr[80] = ""; +- +-int VID = 0; +-int PID = 0; +- +-// CM108 Code +- +-char * CM108Device = NULL; +- +-QProcess *process = NULL; +- +-void GetSettings(); +- +-// These widgets defined here as they are accessed from outside the framework +- +-QLabel * Status1; +-QLabel * Status2; +-QLabel * Status3; +-QLabel * Status4; +- +-QAction *actHost[19]; +-QAction *actSetup[16]; +- +-QAction * TabSingle = NULL; +-QAction * TabBoth = NULL; +-QAction * TabMon = NULL; +- +-QMenu *monitorMenu; +-QMenu * YAPPMenu; +-QMenu *connectMenu; +-QMenu *disconnectMenu; +- +-QAction *EnableMonitor; +-QAction *EnableMonLog; +-QAction *MonLocalTime; +-QAction *MonTX; +-QAction *MonSup; +-QAction *MonNodes; +-QAction *MonUI; +-QAction *MonColour; +-QAction *MonPort[65]; +-QAction *actChatMode; +-QAction *actAutoTeletext; +-QAction *actBells; +-QAction *actStripLF; +-QAction *actIntervalBeep; +-QAction *actConnectBeep; +-QAction *actAuto; +-QAction *actnoConv; +-QAction *actCP1251; +-QAction *actCP1252; +-QAction *actCP437; +- +-QAction *actFonts; +-QAction *actmenuFont; +-QAction *actColours; +-QAction *actmyFonts; +-QAction *YAPPSend; +-QAction *YAPPSetRX; +-QAction *YAPPSetSize; +-QAction *singleAct; +-QAction *singleAct2; +-QAction *MDIAct; +-QAction *tabbedAct; +-QAction *discAction; +-QFont * menufont; +-QMenu *windowMenu; +-QMenu *setupMenu; +-QAction *ListenAction; +- +-QTabWidget *tabWidget; +-QMdiArea *mdiArea; +-QWidget * mythis; +-QStatusBar * myStatusBar; +- +-QTcpServer * _server; +- +-QMenuBar *mymenuBar; +-QToolBar *toolBar; +-QToolButton * but1; +-QToolButton * but2; +-QToolButton * but3; +-QToolButton * but4; +-QToolButton * but5; +- +-QList _sessions; +- +-// Session Type Equates +- +-#define Term 1 +-#define Mon 2 +-#define Listen 4 +- +-int TabType[10] = { Term, Term + Mon, Term, Term, Term, Term, Mon, Mon, Mon }; +- +-int AutoConnect[10] = {0, 0 ,0, 0, 0, 0, 0, 0, 0, 0}; +- +-int currentHost[10] = {0, 0 ,0, 0, 0, 0, 0, 0, 0, 0}; +- +-int listenPort = 8015; +-extern "C" int listenEnable; +-char listenCText[4096] = ""; +- +-int ConfigHost = 0; +- +-int Split = 50; // Mon/Term size split +- +-int termX; +- +-bool Cascading = false; // Set to stop size being saved when cascading +- +-QMdiSubWindow * ActiveSubWindow = NULL; +-Ui_ListenSession * ActiveSession = NULL; +- +-Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label = nullptr); +-void Send_AGW_C_Frame(Ui_ListenSession * Sess, int Port, char * CallFrom, char * CallTo, char * Data, int DataLen); +-void AGW_AX25_data_in(void * AX25Sess, unsigned char * data, int Len); +-void AGWMonWindowClosing(Ui_ListenSession *Sess); +-void AGWWindowClosing(Ui_ListenSession *Sess); +-extern "C" void KISSDataReceived(void * socket, unsigned char * data, int length); +-void closeSerialPort(); +-int newMHWindow(QObject * parent, int Type, const char * Label); +- +-extern void initUTF8(); +-int checkUTF8(unsigned char * Msg, int Len, unsigned char * out); +- +-QDialog * deviceUI; +- +-#include +-#include +-#include +- +- +- +- +-void EncodeSettingsLine(int n, char * String) +-{ +- sprintf(String, "%s|%d|%s|%s|%s|%s", Host[n], Port[n], UserName[n], Password[n], MonParams[n], SessName[n]); +- return; +-} +- +-// This is used for placing discAction in the preference menu +-#ifdef __APPLE__ +-bool is_mac = true; +-#else +-bool is_mac = false; +-#endif +- +-QString GetConfPath() +-{ +- std::string conf_path = "QtTermTCP.ini"; // Default conf file stored alongside application. +- +-#ifdef __APPLE__ +- +- // Get configuration path for MacOS. +- +- // This will usually be placed in /Users/USER/Library/Application Support/QtTermTCP +- +- std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString(); +- +- conf_path = directory + "/QtTermTCP.ini"; +- +- mkdir(directory.c_str(), 0775); +- +-#endif +- +- return QString::fromUtf8(conf_path.c_str()); +- +-} +- +- +- +-void DecodeSettingsLine(int n, char * String) +-{ +- char * Param = strdup(String); +- char * Rest; +- char * Save = Param; // for Free +- +- Rest = strlop(Param, '|'); +- +- if (Rest == NULL) +- return; +- +- strcpy(Host[n], Param); +- Param = Rest; +- +- Rest = strlop(Param, '|'); +- Port[n] = atoi(Param); +- Param = Rest; +- +- Rest = strlop(Param, '|'); +- strcpy(UserName[n], Param); +- Param = Rest; +- +- Rest = strlop(Param, '|'); +- strcpy(Password[n], Param); +- Param = Rest; +- +- Rest = strlop(Param, '|'); +- strcpy(MonParams[n], Param); +- +- if (Rest) +- strcpy(SessName[n], Rest); +- +- free(Save); +- return; +-} +- +-//#ifdef ANDROID +-//#define inputheight 60 +-//#else +-#define inputheight 25 +-//#endif +- +-extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len); +- +-void DoTermResize(Ui_ListenSession * Sess) +-{ +- +- QRect r = Sess->rect(); +- +- int H, Mid, monHeight, termHeight, Width, Border = 3; +- +- Width = r.width(); +- H = r.height(); +- +- if (TermMode == Tabbed) +- { +- // H -= 20; +- Width -= 7; +- } +- else if (TermMode == Single) +- { +- Width -= 7; +- // H += 20; +- } +- +- if (Sess->SessionType == Listen || Sess->SessionType == Term) +- { +- // Term and Input +- +- // Calc Positions of window +- +- termHeight = H - (inputheight + 3 * Border); +- +- Sess->termWindow->setGeometry(QRect(Border, Border, Width, termHeight)); +- +- if (Sess->TTActive) +- { +- Sess->TTLabel->setGeometry(QRect(Border, Border, 600, 475)); +-// Sess->termWindow->setVisible(false); +- Sess->TTLabel->setVisible(true); +- } +- else +- { +-// Sess->termWindow->setVisible(true); +- Sess->TTLabel->setVisible(false); +- } +- +- Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); +- } +- else if (Sess->SessionType == (Term | Mon)) +- { +- // All 3 +- +- // Calc Positions of window +- +- Mid = (H * Split) / 100; +- +- monHeight = Mid - Border; +- termX = Mid; +- termHeight = H - Mid - (inputheight + 3 * Border); +- +- Sess->monWindow->setGeometry(QRect(Border, Border, Width, monHeight)); +- Sess->termWindow->setGeometry(QRect(Border, Mid + Border, Width, termHeight)); +- +- if (Sess->TTActive) +- { +- Sess->TTLabel->setGeometry(QRect(3, Mid + Border, 600, 475)); +-// Sess->termWindow->setVisible(false); +- Sess->TTLabel->setVisible(true); +- } +- else +- { +-// Sess->termWindow->setVisible(true); +- Sess->TTLabel->setVisible(false); +- } +- +- Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); +- +- } +- else +- { +- // Should just be Mon only +- +- Sess->monWindow->setGeometry(QRect(Border, Border, Width, H - 2 * Border)); +- } +-} +- +- +-extern "C" Ui_ListenSession * MHWindow; +- +-bool QtTermTCP::eventFilter(QObject* obj, QEvent *event) +-{ +- // See if from a Listening Session +- +- Ui_ListenSession * Sess; +- +- if (obj == MHWindow) +- { +- if (event->type() == QEvent::Resize) +- { +- QRect r = MHWindow->rect(); +- +- int H, Width, Border = 3; +- +- Width = r.width() - 6; +- H = r.height() - 6; +- +- MHWindow->monWindow->setGeometry(QRect(Border, Border, Width, H)); +- return true; +- } +- if (event->type() == QEvent::Close) +- { +- QSettings mysettings(GetConfPath(), QSettings::IniFormat); +- mysettings.setValue("MHgeometry", MHWindow->saveGeometry()); +- SaveSettings(); +- MHWindow = 0; +- } +- } +- +- +- 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) +- { +- // Get clipboard data and process a line at a time +- +- QClipboard *clipboard = QGuiApplication::clipboard(); +- QString Text = clipboard->text(); +- QByteArray ba = Text.toLocal8Bit(); +- char * Msg = ba.data(); +- +- +- Sess->inputWindow->paste(); +- return true; +- } +- return QMainWindow::eventFilter(obj, event); +- } +- } +- } +- return QMainWindow::eventFilter(obj, event); +-} +- +-QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State) +-{ +- QAction * Act = new QAction(Label, parent); +- if (Menu) +- Menu->addAction(Act); +- +- Act->setCheckable(true); +- if (State) +- Act->setChecked(true); +- +- parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked())); +- +- Act->setFont(*menufont); +- +- return Act; +-} +- +-// This now creates all window types - Term, Mon, Combined, Listen +- +-int xCount = 0; +-int sessNo = 0; +- +-Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label) +-{ +- Ui_ListenSession * Sess = new(Ui_ListenSession); +- +- // Need to explicity initialise on Qt4 +- +- Sess->termWindow = NULL; +- Sess->monWindow = NULL; +- Sess->inputWindow = NULL; +- +- for (int i = 0; i < 50; i++) +- Sess->KbdStack[i] = NULL; +- +- Sess->StackIndex = 0; +- Sess->InputMode = 0; +- Sess->SlowTimer = 0; +- Sess->MonData = 0; +- Sess->OutputSaveLen = 0; +- Sess->MonSaveLen = 0; +- Sess->PortMonString[0] = 0; +- Sess->portmask = 0; +- Sess->portmask = 1; +- Sess->mtxparam = 1; +- Sess->mlocaltime = 0; +- Sess->mcomparam = 1; +- Sess->monUI = 0; +- Sess->MonitorNODES = 0; +- Sess->MonitorColour = 1; +- Sess->CurrentHost = 0; +- +- Sess->SessionType = Type; +- Sess->clientSocket = NULL; +- Sess->AGWSession = NULL; +- Sess->AGWMonSession = NULL; +- Sess->KISSSession = NULL; +- Sess->KISSMode = 0; +- Sess->TTActive = 0; +- Sess->TTFlashToggle = 0; +- Sess->pageBuffer[0] = 0; +- Sess->Tab = 0; +- +- Sess->LogMonitor = false; +- Sess->monSpan = (char *) ""; +- Sess->monLogfile = nullptr; +- Sess->sessNo = sessNo++; +- +- _sessions.append(Sess); +- +-// Sess->TT = new Ui_TeleTextDialog(); +- +-// Sess->TT->setupUi(&Sess->TTUI); +- +-// Sess->TTUI.show(); +-// Sess->TTUI.raise(); +-// Sess->TTUI.activateWindow(); +- +- // Sess->setObjectName(QString::fromUtf8("Sess")); +- +- if (TermMode == MDI) +- { +- Sess->sw = mdiArea->addSubWindow(Sess); +- // Sess->installEventFilter(parent); +- +- Sess->sw->resize(800, 600); +- } +- else if (TermMode == Tabbed) +- { +- Sess->Tab = xCount++; +- +- if (Type == Mon) +- tabWidget->addTab(Sess, "Monitor"); +- else +- tabWidget->addTab(Sess, Label); +- } +- +- Sess->installEventFilter(parent); +- +- QSettings settings(GetConfPath(), QSettings::IniFormat); +- +-#ifdef ANDROID +- QFont font = QFont(settings.value("FontFamily", "Driod Sans Mono").value(), +- settings.value("PointSize", 12).toInt(), +- settings.value("Weight", 50).toInt()); +-#else +- QFont font = QFont(settings.value("FontFamily", "Courier New").value(), +- settings.value("PointSize", 10).toInt(), +- settings.value("Weight", 50).toInt()); +-#endif +- +- if ((Type & Mon)) +- { +- Sess->monWindow = new QTextEdit(Sess); +- Sess->monWindow->setReadOnly(1); +- Sess->monWindow->document()->setMaximumBlockCount(10000); +- Sess->monWindow->setFont(font); +- Sess->monWindow->setStyleSheet(monStyleSheet); +- mythis->connect(Sess->monWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged())); +- } +- +- if ((Type & (Listen | Term))) +- { +- Sess->termWindow = new QTextEdit(Sess); +- Sess->termWindow->setReadOnly(1); +- Sess->termWindow->document()->setMaximumBlockCount(10000); +- Sess->termWindow->setFont(font); +- Sess->termWindow->setStyleSheet(termStyleSheet); +- +- Sess->TTLabel = new QLabel(Sess); +- Sess->TTLabel->setGeometry(QRect(0,0 ,500, 500)); +- Sess->TTLabel->setVisible(false); +- +- Sess->TTBitmap = new QImage(40 * 15, 25 * 19, QImage::Format_RGB32); +- Sess->TTBitmap->fill(Qt::black); +- +-/* +- +- char Page[4096]; +- +- QFile file("/savepage.txt"); +- file.open(QIODevice::ReadOnly); +- file.read(Page, 4096); +- file.close(); +- +- Sess->TTActive = 1; +- strcpy(Sess->pageBuffer, Page); +- DecodeTeleText(Sess, Sess->pageBuffer); +- +-*/ +- +- Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); +- +- Sess->TTLabel->setContextMenuPolicy(Qt::CustomContextMenu); +- mythis->connect(Sess->TTLabel, SIGNAL(customContextMenuRequested(const QPoint&)), +- parent, SLOT(showContextMenuL())); +- +- mythis->connect(Sess->termWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged())); +- +- Sess->inputWindow = new QLineEdit(Sess); +- Sess->inputWindow->installEventFilter(parent); +- Sess->inputWindow->setFont(font); +- Sess->inputWindow->setStyleSheet(inputStyleSheet); +- Sess->inputWindow->setContextMenuPolicy(Qt::PreventContextMenu); +- +- mythis->connect(Sess->inputWindow, SIGNAL(selectionChanged()), parent, SLOT(onLEselectionChanged())); +- } +- +- if (Type == Term || Type == Listen) +- { +- // Term Only or Listen Only +- +- Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu); +- +- mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)), +- parent, SLOT(showContextMenuT(const QPoint &))); +- +- } +- +- if (Type == Mon) +- { +- // Monitor Only +- +- Sess->monWindow->setContextMenuPolicy(Qt::CustomContextMenu); +- +- mythis->connect(Sess->monWindow, SIGNAL(customContextMenuRequested(const QPoint&)), +- parent, SLOT(showContextMenuMOnly(const QPoint &))); +- +- } +- +- if (Type == (Term | Mon)) +- { +- // Combined Term and Mon. Add Custom Menu to set Mon/Term Split with Right Click +- +- Sess->monWindow->setContextMenuPolicy(Qt::CustomContextMenu); +- Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu); +- +- +- mythis->connect(Sess->monWindow, SIGNAL(customContextMenuRequested(const QPoint&)), +- parent, SLOT(showContextMenuM(const QPoint &))); +- +- mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)), +- parent, SLOT(showContextMenuMT(const QPoint &))); +- } +- +- if (Sess->SessionType == Mon) // Mon Only +- Sess->setWindowTitle("Monitor Session Disconnected"); +- else if (Sess->SessionType == Listen) // Mon Only +- Sess->setWindowTitle("Listen Window Disconnected"); +- else +- Sess->setWindowTitle("Disconnected"); +- +- Sess->installEventFilter(mythis); +- +- Sess->show(); +- +- int pos = (_sessions.size() - 1) * 20; +- +- if (TermMode == MDI) +- { +- Sess->sw->move(pos, pos); +- } +- +- QSize Size(800, 602); // Not actually used, but Event constructor needs it +- +- QResizeEvent event(Size, Size); +- +- QApplication::sendEvent(Sess, &event); // Resize Widgets to fix Window +- +- return Sess; +-} +- +-QByteArray timeLoaded = QDateTime::currentDateTime().toString("yymmdd_hhmmss").toUtf8(); +- +-QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent) +-{ +- int i; +- char Title[80]; +- +- // Get configuration path for MacOS. +- std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString(); +- std::string conf_path = directory + "/QtTermTCP.ini"; +- +- //mkdir(directory.c_str(), 0775); +- +- _server = new QTcpServer(); +- +- mythis = this; +- +- ui.setupUi(this); +- +- initUTF8(); +- +- mymenuBar = new QMenuBar(this); +- mymenuBar->setGeometry(QRect(0, 0, 781, 26)); +- setMenuBar(mymenuBar); +- +- toolBar = new QToolBar(this); +- toolBar->setObjectName("mainToolbar"); +- addToolBar(Qt::BottomToolBarArea, toolBar); +- +- QSettings mysettings(GetConfPath(), QSettings::IniFormat); +- +- restoreGeometry(mysettings.value("geometry").toByteArray()); +- restoreState(mysettings.value("windowState").toByteArray()); +- +- GetSettings(); +- +- GetKeyWordFile(); +- +- // Set background colours +- +- sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);", +- monBackground.red(), monBackground.green(), monBackground.blue()); +- +- sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);", +- termBackground.red(), termBackground.green(), termBackground.blue()); +- +- sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", +- inputText.red(), inputText.green(), inputText.blue(), +- inputBackground.red(), inputBackground.green(), inputBackground.blue()); +- +- +-#ifdef ANDROID +- menufont = new QFont(mysettings.value("MFontFamily", "Driod Sans").value(), +- mysettings.value("MPointSize", 12).toInt(), +- mysettings.value("MWeight", 50).toInt()); +-#else +- menufont = new QFont(mysettings.value("MFontFamily", "Aerial").value(), +- mysettings.value("MPointSize", 10).toInt(), +- mysettings.value("MWeight", 50).toInt()); +- +-#endif +- if (TermMode == MDI) +- { +- mdiArea = new QMdiArea(ui.centralWidget); +- mdiArea->setGeometry(QRect(0, 0, 771, 571)); +- +- mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- +- connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(xon_mdiArea_changed())); +- +- setCentralWidget(mdiArea); +- } +- else if (TermMode == Tabbed) +- { +- Ui_ListenSession * Sess; +- int index = 0; +- +- tabWidget = new QTabWidget(this); +- QTabBar* tabBar = tabWidget->tabBar(); +- +-// QString style1 = "QTabWidget::tab-bar{left:0;}"; // for Mac +-// tabWidget->setStyleSheet(style1); +- +- QString style = "QTabBar::tab:selected{background-color: #d0d0d0;} QTabBar::tab:!selected{background-color: #f0f0f0;}"; +- +- tabBar->setStyleSheet(style); +- +- tabWidget->setContextMenuPolicy(Qt::CustomContextMenu); +- +- connect(tabWidget, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &))); +- +- ui.verticalLayout->addWidget(tabWidget); +- tabWidget->setTabPosition(QTabWidget::South); +- +- Sess = newWindow(this, TabType[0], "Sess 1"); +- Sess->CurrentHost = currentHost[index++]; +- Sess = newWindow(this, TabType[1], "Sess 2"); +- Sess->CurrentHost = currentHost[index++]; +- Sess = newWindow(this, TabType[2], "Sess 3"); +- Sess->CurrentHost = currentHost[index++]; +- Sess = newWindow(this, TabType[3], "Sess 4"); +- Sess->CurrentHost = currentHost[index++]; +- Sess = newWindow(this, TabType[4], "Sess 5"); +- Sess->CurrentHost = currentHost[index++]; +- Sess = newWindow(this, TabType[5], "Sess 6"); +- Sess->CurrentHost = currentHost[index++]; +- Sess = newWindow(this, TabType[6], "Sess 7"); +- Sess->CurrentHost = currentHost[index++]; +- Sess = newWindow(this, TabType[7], "Monitor"); +- Sess->CurrentHost = currentHost[index++]; +- Sess = newWindow(this, TabType[8], "Monitor"); +- Sess->CurrentHost = currentHost[index++]; +- +- ActiveSession = _sessions.at(0); +- +- connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSelected(int))); +- +- tabWidget->setFont(*menufont); +- +- } +- +- sprintf(Title, "QtTermTCP Version %s", VersionString); +- +- this->setWindowTitle(Title); +- +- //#ifdef ANDROID +- // mymymenuBar->setVisible(false); +- //#endif +- +- if (TermMode == Single) +- windowMenu = mymenuBar->addMenu(""); +- else +- windowMenu = mymenuBar->addMenu(tr("&Window")); +- +- connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu())); +- windowMenu->setFont(*menufont); +- +- newTermAct = new QAction(tr("New Terminal Window"), this); +- connect(newTermAct, SIGNAL(triggered()), this, SLOT(doNewTerm())); +- +- newMonAct = new QAction(tr("New Monitor Window"), this); +- connect(newMonAct, SIGNAL(triggered()), this, SLOT(doNewMon())); +- +- newCombinedAct = new QAction(tr("New Combined Term/Mon Window"), this); +- connect(newCombinedAct, SIGNAL(triggered()), this, SLOT(doNewCombined())); +- +- if (TermMode == MDI) +- { +- closeAct = new QAction(tr("Cl&ose"), this); +- closeAct->setStatusTip(tr("Close the active window")); +- connect(closeAct, SIGNAL(triggered()), mdiArea, SLOT(closeActiveSubWindow())); +- +- closeAllAct = new QAction(tr("Close &All"), this); +- closeAllAct->setStatusTip(tr("Close all the windows")); +- connect(closeAllAct, SIGNAL(triggered()), mdiArea, SLOT(closeAllSubWindows())); +- +- tileAct = new QAction(tr("&Tile"), this); +- tileAct->setStatusTip(tr("Tile the windows")); +- connect(tileAct, SIGNAL(triggered()), mdiArea, SLOT(tileSubWindows())); +- +- cascadeAct = new QAction(tr("&Cascade"), this); +- cascadeAct->setStatusTip(tr("Cascade the windows")); +- connect(cascadeAct, SIGNAL(triggered()), this, SLOT(doCascade())); +- +- nextAct = new QAction(tr("Ne&xt"), this); +- nextAct->setShortcuts(QKeySequence::NextChild); +- nextAct->setStatusTip(tr("Move the focus to the next window")); +- connect(nextAct, SIGNAL(triggered()), mdiArea, SLOT(activateNextSubWindow())); +- +- previousAct = new QAction(tr("Pre&vious"), this); +- previousAct->setShortcuts(QKeySequence::PreviousChild); +- previousAct->setStatusTip(tr("Move the focus to the previous window")); +- connect(previousAct, SIGNAL(triggered()), mdiArea, SLOT(activatePreviousSubWindow())); +- } +- +- quitAction = new QAction(tr("&Quit"), this); +- connect(quitAction, SIGNAL(triggered()), this, SLOT(doQuit())); +- +- windowMenuSeparatorAct = new QAction(this); +- windowMenuSeparatorAct->setSeparator(true); +- +- updateWindowMenu(); +- +- if (KISSEnable && KISSMH) +- { +- newMHWindow(this, 0, "KISS MH"); +- MHWindow->restoreGeometry(mysettings.value("MHgeometry").toByteArray()); +- } +- +- connectMenu = mymenuBar->addMenu(tr("&Connect")); +- +- actHost[16] = new QAction("AGW Connect", this); +- actHost[16]->setFont(*menufont); +- actHost[16]->setVisible(0); +- connectMenu->addAction(actHost[16]); +- +- connect(actHost[16], SIGNAL(triggered()), this, SLOT(Connect())); +- +- actHost[17] = new QAction("VARA Connect", this); +- actHost[17]->setFont(*menufont); +- actHost[17]->setVisible(0); +- connectMenu->addAction(actHost[17]); +- +- connect(actHost[17], SIGNAL(triggered()), this, SLOT(Connect())); +- +- actHost[18] = new QAction("KISS Connect", this); +- actHost[18]->setFont(*menufont); +- actHost[18]->setVisible(KISSEnable); +- actHost[18]->setEnabled(0); +- connectMenu->addAction(actHost[18]); +- +- connect(actHost[18], SIGNAL(triggered()), this, SLOT(Connect())); +- +- for (i = 0; i < MAXHOSTS; i++) +- { +- if (SessName[i][0]) +- { +- char Lable[256]; +- sprintf(Lable, "%s(%s)", Host[i], SessName[i]); +- actHost[i] = new QAction(Lable, this); +- } +- else +- actHost[i] = new QAction(Host[i], this); +- +- actHost[i]->setFont(*menufont); +- connectMenu->addAction(actHost[i]); +- connect(actHost[i], SIGNAL(triggered()), this, SLOT(Connect())); +- } +- +- discAction = mymenuBar->addAction("&Disconnect"); +- +- // Place discAction in mac app menu, otherwise it doesn't appear +- if (is_mac == true) { +- QMenu * app_menu = mymenuBar->addMenu("App Menu"); +- discAction->setMenuRole(QAction::ApplicationSpecificRole); +- app_menu->addAction(discAction); +- +- } +- +- connect(discAction, SIGNAL(triggered()), this, SLOT(Disconnect())); +- discAction->setEnabled(false); +- +- toolBar->setFont(*menufont); +- +-#ifndef ANDROID +- toolBar->setVisible(false); +-#endif +- but4 = new QToolButton(); +- but4->setPopupMode(QToolButton::InstantPopup); +- but4->setText("Window"); +- but4->addAction(windowMenu->menuAction()); +- but4->setFont(*menufont); +- toolBar->addWidget(but4); +- +- but5 = new QToolButton(); +- but5->setPopupMode(QToolButton::InstantPopup); +- but5->setText("Connect"); +- but5->addAction(connectMenu->menuAction()); +- but5->setFont(*menufont); +- +- toolBar->addWidget(but5); +- +- toolBar->addAction(discAction); +- +- setupMenu = mymenuBar->addMenu(tr("&Setup")); +- hostsubMenu = setupMenu->addMenu("Hosts"); +- hostsubMenu->setFont(*menufont); +- +- for (i = 0; i < MAXHOSTS; i++) +- { +- if (Host[i][0]) +- { +- char Label[256]; +- +- if (SessName[i][0]) +- sprintf(Label, "%s(%s)", Host[i], SessName[i]); +- else +- strcpy(Label, Host[i]); +- +- actSetup[i] = new QAction(Label, this); +- } +- else +- actSetup[i] = new QAction("New Host", this); +- +- hostsubMenu->addAction(actSetup[i]); +- connect(actSetup[i], SIGNAL(triggered()), this, SLOT(SetupHosts())); +- +- actSetup[i]->setFont(*menufont); +- } +- +- +- // Setup Presentation Options +- +- setupMenu->addSeparator()->setText(tr("Presentation")); +- +- QActionGroup * termGroup = new QActionGroup(this); +- +- singleAct = setupMenuLine(nullptr, (char *)"Single Window (Term + Mon)", this, (TermMode == Single) && (singlemodeFormat == Term + Mon)); +- singleAct2 = setupMenuLine(nullptr, (char *)"Single Window (Term only)", this, (TermMode == Single) && (singlemodeFormat == Term)); +- MDIAct = setupMenuLine(nullptr, (char *)"MDI", this, TermMode == MDI); +- tabbedAct = setupMenuLine(nullptr, (char *)"Tabbed", this, TermMode == Tabbed); +- +- termGroup->addAction(singleAct); +- termGroup->addAction(singleAct2); +- termGroup->addAction(MDIAct); +- termGroup->addAction(tabbedAct); +- +- setupMenu->addAction(singleAct); +- setupMenu->addAction(singleAct2); +- setupMenu->addAction(MDIAct); +- setupMenu->addAction(tabbedAct); +- setupMenu->addSeparator(); +- AlertAction = new QAction("Sound Alerts Setup", this); +- +- setupMenu->addAction(AlertAction); +- connect(AlertAction, SIGNAL(triggered()), this, SLOT(AlertSlot())); +- AlertAction->setFont(*menufont); +- setupMenu->addSeparator(); +- +- actFonts = new QAction("Terminal Font", this); +- setupMenu->addAction(actFonts); +- connect(actFonts, SIGNAL(triggered()), this, SLOT(doFonts())); +- actFonts->setFont(*menufont); +- +- actmenuFont = new QAction("Menu Font", this); +- setupMenu->addAction(actmenuFont); +- connect(actmenuFont, SIGNAL(triggered()), this, SLOT(doMFonts())); +- actmenuFont->setFont(*menufont); +- +- actColours = new QAction("Choose Colours", this); +- setupMenu->addAction(actColours); +- connect(actColours, SIGNAL(triggered()), this, SLOT(doColours())); +- actColours->setFont(*menufont); +- +- setupMenu->addSeparator(); +- +- AGWAction = new QAction("AGW Setup", this); +- setupMenu->addAction(AGWAction); +- connect(AGWAction, SIGNAL(triggered()), this, SLOT(AGWSlot())); +- AGWAction->setFont(*menufont); +- +- VARAAction = new QAction("VARA Setup", this); +- setupMenu->addAction(VARAAction); +- connect(VARAAction, SIGNAL(triggered()), this, SLOT(VARASlot())); +- VARAAction->setFont(*menufont); +- +- KISSAction = new QAction("KISS Setup", this); +- setupMenu->addAction(KISSAction); +- connect(KISSAction, SIGNAL(triggered()), this, SLOT(KISSSlot())); +- KISSAction->setFont(*menufont); +- +- setupMenu->addSeparator(); +- +- actChatMode = setupMenuLine(setupMenu, (char *)"Chat Terminal Mode (Send Keepalives)", this, ChatMode); +- actAutoTeletext = setupMenuLine(setupMenu, (char *)"Auto switch to Teletext", this, AutoTeletext); +- actStripLF = setupMenuLine(setupMenu, (char *)"Strip Line Feeds", this, StripLF); +- +- setupMenu->addSeparator(); +- +- setupMenu->addAction(new QAction("Interpret non-UTF8 input as:", this)); +- setupMenu->setFont(*menufont); +- +- QActionGroup * cpGroup = new QActionGroup(this); +- +- actnoConv = setupMenuLine(nullptr, (char *)" Don't Convert (assume is UTF-8)", this, convUTF8 == -1); +- actAuto = setupMenuLine(nullptr, (char *)" Auto", this, convUTF8 == 0); +- actCP1251 = setupMenuLine(nullptr, (char *)" CP1251 (Cyrillic)", this, convUTF8 == 1251); +- actCP1252 = setupMenuLine(nullptr, (char *)" CP1252 (Western Europe)", this, convUTF8 == 1252); +- actCP437 = setupMenuLine(nullptr, (char *)" CP437 (Windows Line Draw)", this, convUTF8 == 437); +- +- cpGroup->addAction(actnoConv); +- cpGroup->addAction(actAuto); +- cpGroup->addAction(actCP1251); +- cpGroup->addAction(actCP1252); +- cpGroup->addAction(actCP437); +- +- setupMenu->addAction(actnoConv); +- setupMenu->addAction(actAuto); +- setupMenu->addAction(actCP1251); +- setupMenu->addAction(actCP1252); +- setupMenu->addAction(actCP437); +- +- monitorMenu = mymenuBar->addMenu(tr("&Monitor")); +- +- EnableMonitor = setupMenuLine(monitorMenu, (char *)"Enable Monitoring", this, 0); +- EnableMonitor->setVisible(0); +- EnableMonLog = setupMenuLine(monitorMenu, (char *)"Log to File", this, 0); +- MonLocalTime = setupMenuLine(monitorMenu, (char *)"Use local time", this, 0); +- MonTX = setupMenuLine(monitorMenu, (char *)"Monitor TX", this, 1); +- MonSup = setupMenuLine(monitorMenu, (char *)"Monitor Supervisory", this, 1); +- MonUI = setupMenuLine(monitorMenu, (char *)"Only Monitor UI Frames", this, 0); +- MonNodes = setupMenuLine(monitorMenu, (char *)"Monitor NODES Broadcasts", this, 0); +- MonColour = setupMenuLine(monitorMenu, (char *)"Enable Colour", this, 1); +- +- for (i = 0; i < MAXPORTS + 1; i++) +- { +- MonPort[i] = setupMenuLine(monitorMenu, (char *)"Port", this, 0); +- MonPort[i]->setVisible(false); +- } +- +- but1 = new QToolButton(); +- but1->setPopupMode(QToolButton::InstantPopup); +- but1->setText("Monitor"); +- but1->addAction(monitorMenu->menuAction()); +- toolBar->addWidget(but1); +- +- but2 = new QToolButton(); +- but2->setPopupMode(QToolButton::InstantPopup); +- but2->setText("Setup"); +- but2->addAction(setupMenu->menuAction()); +- toolBar->addWidget(but2); +- +- ListenAction = mymenuBar->addAction("&Listen"); +- connect(ListenAction, SIGNAL(triggered()), this, SLOT(ListenSlot())); +- +- +- // Place Listen Action in mac app menu, otherwise it doesn't appear +- if (is_mac == true) +- { +- QMenu * app_menu = mymenuBar->addMenu("App Menu"); +- ListenAction->setMenuRole(QAction::ApplicationSpecificRole); +- app_menu->addAction(ListenAction); +- } +- +- toolBar->addAction(ListenAction); +- +- YAPPMenu = mymenuBar->addMenu(tr("&YAPP")); +- +- YAPPSend = new QAction("Send File", this); +- YAPPSetRX = new QAction("Set Receive Directory", this); +- YAPPSetSize = new QAction("Set Max Size", this); +- YAPPSend->setFont(*menufont); +- YAPPSetRX->setFont(*menufont); +- YAPPSetSize->setFont(*menufont); +- +- YAPPMenu->addAction(YAPPSend); +- YAPPMenu->addAction(YAPPSetRX); +- YAPPMenu->addAction(YAPPSetSize); +- YAPPSend->setEnabled(false); +- +- connect(YAPPSend, SIGNAL(triggered()), this, SLOT(doYAPPSend())); +- connect(YAPPSetRX, SIGNAL(triggered()), this, SLOT(doYAPPSetRX())); +- connect(YAPPSetSize, SIGNAL(triggered()), this, SLOT(doYAPPSetSize())); +- +- but3 = new QToolButton(); +- but3->setPopupMode(QToolButton::InstantPopup); +- but3->setText("YAPP"); +- but3->addAction(YAPPMenu->menuAction()); +- but3->setFont(*menufont); +- toolBar->addWidget(but3); +- +- toolBar->setFont(*menufont); +- +- // Set up Status Bar +- +- setStyleSheet("QStatusBar{border-top: 1px outset black;} QStatusBar::item { border: 1px solid black; border-radius: 3px;}"); +- // setStyleSheet("QStatusBar{border-top: 1px outset black;}"); +- +- +- Status4 = new QLabel(""); +- Status3 = new QLabel(" "); +- Status2 = new QLabel(" "); +- Status1 = new QLabel(" Disconnected "); +- +- Status1->setMinimumWidth(100); +- Status2->setMinimumWidth(100); +- Status3->setMinimumWidth(100); +- Status4->setMinimumWidth(100); +- +- myStatusBar = statusBar(); +- +- statusBar()->addPermanentWidget(Status4); +- statusBar()->addPermanentWidget(Status3); +- statusBar()->addPermanentWidget(Status2); +- statusBar()->addPermanentWidget(Status1); +- +- statusBar()->setVisible(AGWEnable | VARAEnable | KISSEnable); +- // Restore saved sessions +- +- if (TermMode == Single) +- { +- Ui_ListenSession * Sess = newWindow(this, singlemodeFormat); +- +- ActiveSession = Sess; +- Sess->CurrentHost = currentHost[0]; +- +- ui.verticalLayout->addWidget(Sess); +- +- connectMenu->setEnabled(true); +- discAction->setEnabled(false); +- YAPPSend->setEnabled(false); +- } +- +- if (TermMode == MDI) +- { +- int n = atoi(sessionList); +- int index = 0; +- +- char *p, *Context; +- char delim[] = "|"; +- +- int type = 0, host = 0, topx, leftx, bottomx, rightx; +- +- p = strtok_s((char *)sessionList, delim, &Context); +- +- while (n--) +- { +- p = strtok_s(NULL, delim, &Context); +- +- sscanf(p, "%d,%d,%d,%d,%d,%d", &type, &host, &topx, &leftx, &bottomx, &rightx); +- +- Ui_ListenSession * Sess = newWindow(this, type); +- +- Sess->CurrentHost = currentHost[index++];; +- +- QRect r(leftx, topx, rightx - leftx, bottomx - topx); +- +- Sess->sw->setGeometry(r); +- Sess->sw->move(leftx, topx); +- +- } +- } +- +- QTimer *timer = new QTimer(this); +- connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); +- timer->start(10000); +- +- QTimer *timer2 = new QTimer(this); +- connect(timer2, SIGNAL(timeout()), this, SLOT(KISSTimerSlot())); +- timer2->start(100); +- +- QTimer *timer3 = new QTimer(this); +- connect(timer3, SIGNAL(timeout()), this, SLOT(SlowTimerSlot())); +- timer3->start(60000); +- +- // 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(KISSMYCALL, axMYCALL); +- +- // Do any autoconnects +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- if (AutoConnect[i] > 0) +- { +- Ui_ListenSession * Sess = _sessions.at(i); +- +- Sess->clientSocket = new myTcpSocket(); +- Sess->clientSocket->Sess = Sess; +- +- connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); +- connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); +- connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); +- +- Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]); +- } +- } +- +-} +- +-void QtTermTCP::showContextMenu(const QPoint &point) +-{ +- if (point.isNull()) +- return; +- +- QTabBar* tabBar = tabWidget->tabBar(); +- QRect Wrect = tabWidget->rect(); +- QRect Brect = tabBar->rect(); +- QPoint myPoint = point; +- +- // Get x coordinate of first tab (on Mac tabs are centre aligned) +- +- QRect rect = tabWidget->tabBar()->geometry(); +- int left = rect.left(); +- +- +- int n = myPoint.y() - (Wrect.height() - Brect.height()); +- myPoint.setY(n); +- n = myPoint.x() - left; +- +- myPoint.setX(n); +- +- int tabIndex = tabBar->tabAt(myPoint); +- +- QMenu menu(this); +- +- QAction * Act = new QAction("AutoConnect on load", this); +- Act->setObjectName(QString::number(tabIndex)); +- +- menu.addAction(Act); +- +- Act->setCheckable(true); +- +- if (AutoConnect[tabIndex] <= 0) +- Act->setChecked(false); +- else +- Act->setChecked(true); +- +- connect(Act, SIGNAL(triggered()), this, SLOT(autoConnectChecked())); +- +- menu.exec(tabWidget->mapToGlobal(point)); +- +-} +- +-void QtTermTCP::autoConnectChecked() +-{ +- QAction * Act = static_cast(QObject::sender()); +- QString Tab = Act->objectName(); +- int tabNo = Tab.toInt(); +- +- tabWidget->setCurrentIndex(tabNo); +- +- Ui_ListenSession *Sess = (Ui_ListenSession *)tabWidget->currentWidget(); +- int state = Act->isChecked(); +- +- if (state == 0) +- AutoConnect[tabNo] = 0; +- else +- { +- if (Sess->clientSocket) // Connected +- AutoConnect[tabNo] = 1; +- else +- AutoConnect[tabNo] = 0; +- } +-} +- +- +-void QtTermTCP::setFonts() +-{ +- windowMenu->menuAction()->setFont(*menufont); +- connectMenu->menuAction()->setFont(*menufont); +- setupMenu->menuAction()->setFont(*menufont); +- monitorMenu->menuAction()->setFont(*menufont); +- YAPPMenu->menuAction()->setFont(*menufont); +- +- if (tabWidget) +- tabWidget->setFont(*menufont); +- mymenuBar->setFont(*menufont); +- toolBar->setFont(*menufont); +- but1->setFont(*menufont); +- but2->setFont(*menufont); +- but3->setFont(*menufont); +- but4->setFont(*menufont); +- but5->setFont(*menufont); +- discAction->setFont(*menufont); +- ListenAction->setFont(*menufont); +- +- for (int i = 0; i < MAXHOSTS; i++) +- { +- actHost[i]->setFont(*menufont); +- actSetup[i]->setFont(*menufont); +- } +- +- actHost[16]->setFont(*menufont); // AGW Host +-} +- +-void QtTermTCP::doQuit() +-{ +- if (_server->isListening()) +- _server->close(); +- +- SaveSettings(); +- +- QCoreApplication::quit(); +-} +- +-void FlashifNotActive() +-{ +- if (!mythis->isActiveWindow()) +- QApplication::alert(mythis, 0); +-} +- +- +-// "Copy on select" Code +- +- +-void QtTermTCP::onTEselectionChanged() +-{ +- QTextEdit * x = static_cast(QObject::sender()); +- +- if (isActiveWindow()) +- x->copy(); +-} +- +-void QtTermTCP::onLEselectionChanged() +-{ +- QLineEdit * x = static_cast(QObject::sender()); +- if (isActiveWindow()) +- x->copy(); +-} +- +-void QtTermTCP::setVDMode() +-{ +- QAction * sender = static_cast(QObject::sender()); +- +- QTextEdit * window = static_cast(sender->parentWidget()); +- +- // Need to find session with this window as owner +- +- Ui_ListenSession * Sess = NULL; +- +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->termWindow == window) +- { +- Sess->TTActive ^= 1; +- DoTermResize(Sess); +- break; +- } +- } +-} +- +-int splitY; // Value when menu added +- +-void QtTermTCP::setSplit() +-{ +- QAction * sender = static_cast(QObject::sender()); +- +- QWidget * Parent = sender->parentWidget(); +- +- if (Parent) +- Parent = Parent->parentWidget(); +- +- int y = Parent->rect().height() - 50; +- +- // y is height of whole windom. splitX is new split position +- // So split = 100 * splitx/x +- +- Split = (splitY * 100) / y; +- +- if (Split < 10) +- Split = 10; +- else if (Split > 90) +- Split = 90; +- +- QSize size(800, 602); +- QResizeEvent event(size, size); +- +- eventFilter(Parent, &event); +-} +- +-void QtTermTCP::ClearScreen() +-{ +- QAction * sender = static_cast(QObject::sender()); +- QTextEdit * window = static_cast(sender->parentWidget()); +- window->clear(); +-} +- +- +-void QtTermTCP::showContextMenuMT(const QPoint &pt) // Term Window +-{ +- // Monitor and Terminal (Term Half) +- +- QTextEdit* sender = static_cast(QObject::sender()); +- +- QMenu *menu = sender->createStandardContextMenu(); +- +- QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}QMenu::separator {height: 2px;background: rgb(58, 80, 116);margin-left: 10px;margin-right: 5px;}"; +- menu->setStyleSheet(style); +- +- QAction * actSplit = new QAction("Set Monitor/Output Split", sender); +- QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender); +- QAction * actClear = new QAction("Clear Screen Buffer", sender); +- +- menu->addAction(actSplit); +- menu->addAction(actVDMode); +- menu->addAction(actClear); +- +- splitY = pt.y() + termX; +- +- connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit())); +- connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode())); +- connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); +- +- menu->exec(sender->mapToGlobal(pt)); +- delete menu; +-} +- +-void QtTermTCP::showContextMenuMOnly(const QPoint &pt) +-{ +- // Monitor only +- +- QTextEdit* sender = static_cast(QObject::sender()); +- +- QMenu *menu = sender->createStandardContextMenu(); +- +- QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}QMenu::separator {height: 2px;background: rgb(58, 80, 116);margin-left: 10px;margin-right: 5px;}"; +- menu->setStyleSheet(style); +- +- QAction * actClear = new QAction("Clear Screen Buffer", sender); +- +- menu->addAction(actClear); +- connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); +- +- menu->exec(sender->mapToGlobal(pt)); +- delete menu; +-} +- +- +-void QtTermTCP::showContextMenuT(const QPoint &pt) // Term Window +-{ +- // Just Terminal +- +- QTextEdit* sender = static_cast(QObject::sender()); +- +- QMenu *menu = sender->createStandardContextMenu(); +- +- QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}"; +- menu->setStyleSheet(style); +- +- +- QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender); +- QAction * actClear = new QAction("Clear Screen Buffer", sender); +- +- menu->addAction(actVDMode); +- menu->addAction(actClear); +- +- connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode())); +- connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); +- +- menu->exec(sender->mapToGlobal(pt)); +- delete menu; +-} +- +- +-void QtTermTCP::showContextMenuL() // Term Window +-{ +- // Teletext Label Right Clicked - cancel TT Mode +- +- QLabel * sender = static_cast(QObject::sender()); +- +- // Need to find session with this label as owner +- +- Ui_ListenSession * Sess = NULL; +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->TTLabel == sender) +- { +- Sess->TTActive ^= 1; +- +- DoTermResize(Sess); +- break; +- } +- } +-} +- +- +-void QtTermTCP::showContextMenuM(const QPoint &pt) // Mon Window +-{ +- QTextEdit* sender = static_cast(QObject::sender()); +- +- QMenu *menu = sender->createStandardContextMenu(); +- QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}"; +- menu->setStyleSheet(style); +- +- QAction * actSplit = new QAction("Set Monitor/Output Split", sender); +- QAction * actClear = new QAction("Clear Screen Buffer", sender); +- +- menu->addAction(actSplit); +- menu->addAction(actClear); +- +- splitY = pt.y(); +- +- connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit())); +- connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); +- +- menu->exec(sender->mapToGlobal(pt)); +- delete menu; +-} +- +-extern "C" void setMenus(int State) +-{ +- // Sets Connect, Disconnect and YAPP Send enable flags to match connection state +- +- if (State) +- { +- connectMenu->setEnabled(false); +- discAction->setEnabled(true); +- YAPPSend->setEnabled(true); +- } +- else +- { +- connectMenu->setEnabled(true); +- discAction->setEnabled(false); +- YAPPSend->setEnabled(false); +- } +-} +- +-extern "C" void SetSessLabel(Ui_ListenSession * Sess, char * label) +-{ +- if (TermMode == MDI) +- Sess->setWindowTitle(label); +- else if (TermMode == Tabbed) +- tabWidget->setTabText(Sess->Tab, label); +- else if (TermMode == Single) +- mythis->setWindowTitle(label); +-} +- +- +-extern "C" void ClearSessLabel(Ui_ListenSession * Sess) +-{ +- if (TermMode == MDI) +- { +- if (Sess->SessionType == Mon) // Mon Only +- Sess->setWindowTitle("Monitor Session Disconnected"); +- else if (Sess->SessionType == Listen) // Mon Only +- Sess->setWindowTitle("Listen Window Disconnected"); +- else +- Sess->setWindowTitle("Disconnected"); +- } +- else if (TermMode == Tabbed) +- { +- if (Sess->SessionType == Mon) // Mon Only +- tabWidget->setTabText(Sess->Tab, "Monitor"); +- else +- { +- char Label[16]; +- sprintf(Label, "Sess %d", Sess->Tab + 1); +- tabWidget->setTabText(Sess->Tab, Label); +- } +- } +- else if (TermMode == Single) +- { +- if (Sess->SessionType == Mon) // Mon Only +- mythis->setWindowTitle("Monitor Session Disconnected"); +- else +- mythis->setWindowTitle("Disconnected"); +- } +-} +- +-void QtTermTCP::tabSelected(int Current) +-{ +- Ui_ListenSession * Sess = NULL; +- +- if (Current < _sessions.size()) +- { +- Sess = _sessions.at(Current); +- +- if (Sess == nullptr) +- return; +- +- ActiveSession = Sess; +- +- tabWidget->tabBar()->setTabTextColor(tabWidget->currentIndex(), oldTabText); +- +- if (Sess->clientSocket || Sess->AGWSession || Sess->KISSSession || Sess->KISSMode) +- { +- connectMenu->setEnabled(false); +- discAction->setEnabled(true); +- YAPPSend->setEnabled(true); +- } +- else +- { +- connectMenu->setEnabled(true); +- discAction->setEnabled(false); +- YAPPSend->setEnabled(false); +- } +- +- // If a monitor Window, change Monitor config settings +- +- EnableMonLog->setChecked(Sess->LogMonitor); +- +- if (AGWUsers && Sess == AGWUsers->MonSess) // AGW Monitor +- { +- for (int i = 0; i < 64; i++) +- SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden +- +- connectMenu->setEnabled(false); +- MonTX->setVisible(0); +- MonSup->setVisible(0); +- MonUI->setVisible(0); +- MonColour->setVisible(0); +- +- EnableMonitor->setVisible(1); +- EnableMonitor->setChecked(AGWMonEnable); +- MonLocalTime->setChecked(Sess->mlocaltime); +- MonNodes->setChecked(Sess->MonitorNODES); +- } +- else if (Sess == KISSMonSess) // KISS Monitor +- { +- for (int i = 0; i < 64; i++) +- SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden +- +- connectMenu->setEnabled(false); +- MonTX->setVisible(0); +- MonSup->setVisible(0); +- MonUI->setVisible(0); +- MonColour->setVisible(0); +- +- EnableMonitor->setVisible(1); +- EnableMonitor->setChecked(KISSMonEnable); +- MonLocalTime->setChecked(Sess->mlocaltime); +- MonNodes->setChecked(Sess->MonitorNODES); +- } +- else +- { +- EnableMonitor->setVisible(0); +- MonTX->setVisible(1); +- MonSup->setVisible(1); +- MonUI->setVisible(1); +- MonColour->setVisible(1); +- } +- +- if (Sess->PortMonString[0]) +- { +- char * ptr = (char *)malloc(2048); +- memcpy(ptr, Sess->PortMonString, 2048); +- +- int NumberofPorts = atoi((char *)&ptr[2]); +- char *p, *Context; +- char msg[80]; +- int portnum, m; +- char delim[] = "|"; +- +- // Remove old Monitor menu +- +- for (int i = 0; i < 64; i++) +- { +- SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden +- } +- +- p = strtok_s((char *)&ptr[2], delim, &Context); +- +- while (NumberofPorts--) +- { +- p = strtok_s(NULL, delim, &Context); +- if (p == NULL) +- break; +- +- m = portnum = atoi(p); +- +- sprintf(msg, "Port %s", p); +- +- if (m == 0) +- m = 64; +- +- if (Sess->portmask & ((uint64_t)1 << (m - 1))) +- SetPortMonLine(portnum, msg, 1, 1); +- else +- SetPortMonLine(portnum, msg, 1, 0); +- } +- free(ptr); +- +- MonLocalTime->setChecked(Sess->mlocaltime); +- MonTX->setChecked(Sess->mtxparam); +- MonSup->setChecked(Sess->mcomparam); +- MonUI->setChecked(Sess->monUI); +- MonNodes->setChecked(Sess->MonitorNODES); +- MonColour->setChecked(Sess->MonitorColour); +- } +- return; +- } +-} +- +-void QtTermTCP::SetupHosts() +-{ +- QAction * Act = static_cast(QObject::sender()); +- int i; +- +- for (i = 0; i < MAXHOSTS; i++) +- { +- if (Act == actSetup[i]) +- break; +- } +- +- if (i > 15) +- return; +- +- ConfigHost = i; +- +- TabDialog tabdialog(0); +- tabdialog.exec(); +-} +- +- +-void QtTermTCP::Connect() +-{ +- QMdiSubWindow * UI; +- Ui_ListenSession * Sess = nullptr; +- QAction * Act = static_cast(QObject::sender()); +- +- int i; +- +- for (i = 0; i < MAXHOSTS; i++) +- { +- if (Act == actHost[i]) +- break; +- } +- +- SavedHost = i; // Last used +- +- if (TermMode == MDI) +- { +- UI = mdiArea->activeSubWindow(); +- +- for (i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->sw == UI) +- break; +- } +- +- if (i == _sessions.size()) +- return; +- +- currentHost[i] = SavedHost; +- } +- +- else if (TermMode == Tabbed) +- { +- Sess = (Ui_ListenSession *)tabWidget->currentWidget(); +- } +- +- else if (TermMode == Single) +- Sess = _sessions.at(0); +- +- if ((Sess == nullptr || Sess->SessionType & Listen)) +- return; +- +- Sess->CurrentHost = SavedHost; +- +- currentHost[Sess->Tab] = SavedHost; +- +- if (Act == actHost[16]) +- { +- // This runs the AGW Connection dialog +- +- Sess->CurrentHost = 16; // Iast used +- AGWConnect dialog(0); +- dialog.exec(); +- return; +- } +- +- +- if (Act == actHost[17]) +- { +- // This runs the VARA Connection dialog +- +- Sess->CurrentHost = 17; // Iast used +- VARADataSock->Sess = Sess; +- VARASock->Sess = Sess; +- +- VARAConnect dialog(0); +- dialog.exec(); +- WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); +- +- return; +- } +- +- if (Act == actHost[18]) +- { +- // This runs the KISS Connection dialog +- +- Sess->CurrentHost = 18; // Iast used +- +- KISSConnect dialog(0); +- dialog.exec(); +- return; +- } +- +- // Set Monitor Params for this host +- +- sscanf(MonParams[Sess->CurrentHost], "%llx %x %x %x %x %x", +- &Sess->portmask, &Sess->mtxparam, &Sess->mcomparam, +- &Sess->MonitorNODES, &Sess->MonitorColour, &Sess->monUI); +- +- Sess->mlocaltime = (Sess->mtxparam >> 7); +- Sess->mtxparam &= 1; +- +- MonLocalTime->setChecked(Sess->mlocaltime); +- MonTX->setChecked(Sess->mtxparam); +- MonSup->setChecked(Sess->mcomparam); +- MonUI->setChecked(Sess->monUI); +- MonNodes->setChecked(Sess->MonitorNODES); +- MonColour->setChecked(Sess->MonitorColour); +- +- // Remove old Monitor menu +- +- for (i = 0; i < 64; i++) +- { +- SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden +- } +- +- delete(Sess->clientSocket); +- +- Sess->clientSocket = new myTcpSocket(); +- Sess->clientSocket->Sess = Sess; +- +- connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); +- connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); +- connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); +- +- Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]); +- return; +-} +- +-extern "C" void rst_timer(TAX25Port * AX25Sess); +-extern "C" void set_unlink(TAX25Port * AX25Sess, Byte * path); +- +-void QtTermTCP::Disconnect() +-{ +- QMdiSubWindow * UI; +- Ui_ListenSession * Sess = nullptr; +- +- if (TermMode == MDI) +- { +- int i; +- +- UI = mdiArea->activeSubWindow(); +- +- for (i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->sw == UI) +- break; +- } +- +- if (i == _sessions.size()) +- return; +- } +- +- else if (TermMode == Tabbed) +- { +- Sess = (Ui_ListenSession *)tabWidget->currentWidget(); +- } +- +- else if (TermMode == Single) +- Sess = _sessions.at(0); +- +- // if AGW send a d frame else disconnect TCP session +- +- if (Sess->AGWSession) +- Send_AGW_Ds_Frame(Sess->AGWSession); +- else if (VARASock && VARASock->Sess == Sess) +- VARASock->write("DISCONNECT\r"); +- else if (Sess->KISSSession) +- { +- if (Sess->KISSMode == 0) +- { +- TAX25Port * Port = (TAX25Port *)Sess->KISSSession; +- +- rst_timer(Port); +- set_unlink(Port, Port->Path); +- } +- else +- { +- // KISS UI Mode +- +- char Msg[128]; +- int Len = sprintf(Msg, "Disconnected\r"); +- +- Sess->KISSMode = 0; +- SendtoTerm(Sess, Msg, Len); +- ClearSessLabel(Sess); +- setMenus(0); +- Sess->KISSSession = NULL; +- } +- } +- else +- +- { +- if (Sess && Sess->clientSocket) +- Sess->clientSocket->disconnectFromHost(); +- } +- return; +-} +- +- +-void QtTermTCP::doYAPPSend() +-{ +- QFileDialog dialog(this); +- QStringList fileNames; +- dialog.setFileMode(QFileDialog::AnyFile); +- +- QMdiSubWindow * UI; +- Ui_ListenSession * Sess = nullptr; +- int i; +- +- if (TermMode == MDI) +- { +- UI = mdiArea->activeSubWindow(); +- +- for (i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->sw == UI) +- break; +- } +- +- if (i == _sessions.size()) +- return; +- } +- +- else if (TermMode == Tabbed) +- { +- Sess = (Ui_ListenSession *)tabWidget->currentWidget(); +- } +- +- else if (TermMode == Single) +- Sess = _sessions.at(0); +- +- if (Sess == nullptr) +- return; +- +- if ((Sess->SessionType & Mon)) +- { +- // Turn off monitoring +- +- setTraceOff(Sess); +- } +- +- if (dialog.exec()) +- { +- char FN[256]; +- +- fileNames = dialog.selectedFiles(); +- if (fileNames[0].length() < 256) +- { +- strcpy(FN, fileNames[0].toUtf8()); +- YAPPSendFile(Sess, FN); +- } +- } +-} +- +-void QtTermTCP::doYAPPSetRX() +-{ +- QFileDialog dialog(this); +- QStringList fileNames; +- dialog.setFileMode(QFileDialog::Directory); +- dialog.setDirectory(YAPPPath); +- +- if (dialog.exec()) +- { +- fileNames = dialog.selectedFiles(); +- if (fileNames[0].length() < 256) +- strcpy(YAPPPath, fileNames[0].toUtf8()); +- +- SaveSettings(); +- } +-} +- +-Ui_SizeDialog * YappSize; +- +-void QtTermTCP::doYAPPSetSize() +-{ +- // This runs the VARA Configuration dialog +- +- char valChar[80]; +- +- YappSize = new(Ui_SizeDialog); +- +- QDialog UI; +- +- YappSize->setupUi(&UI); +- +- UI.setFont(*menufont); +- deviceUI = &UI; +- +- sprintf(valChar, "%d", MaxRXSize); +- +- YappSize->maxSize->setText(valChar); +- +- QObject::connect(YappSize->okButton, SIGNAL(clicked()), this, SLOT(sizeaccept())); +- QObject::connect(YappSize->cancelButton, SIGNAL(clicked()), this, SLOT(sizereject())); +- +- UI.exec(); +-} +- +-void QtTermTCP::sizeaccept() +-{ +- QVariant Q; +- Q = YappSize->maxSize->text(); +- +- MaxRXSize = Q.toInt(); +- SaveSettings(); +- delete(YappSize); +-} +- +- +-void QtTermTCP::sizereject() +-{ +- delete(YappSize); +- deviceUI->reject(); +-} +- +- +-void QtTermTCP::menuChecked() +-{ +- QAction * Act = static_cast(QObject::sender()); +- +- int state = Act->isChecked(); +- int newTermMode = TermMode; +- int newSingleMode = singlemodeFormat; +- +- if (Act == TabSingle || Act == TabBoth || Act == TabMon) +- { +- // Tabbed Window format had changed +- +- int i = tabWidget->currentIndex(); +- +- if (Act == TabSingle) +- TabType[i] = Term; +- else if (Act == TabBoth) +- TabType[i] = Term + Mon; +- else +- TabType[i] = Mon; +- +- QMessageBox msgBox; +- msgBox.setText("Tab Types will change next time program is started."); +- msgBox.exec(); +- +- } +- +- if (Act == singleAct || Act == singleAct2 || Act == MDIAct || Act == tabbedAct) +- { +- // Term Mode had changed +- +- if (singleAct->isChecked()) +- { +- newTermMode = Single; +- newSingleMode = Mon + Term; +- } +- else if (singleAct2->isChecked()) +- { +- newTermMode = Single; +- newSingleMode = Term; +- } +- else if (MDIAct->isChecked()) +- newTermMode = MDI; +- else if (tabbedAct->isChecked()) +- newTermMode = Tabbed; +- +- if (newTermMode != TermMode || newSingleMode != singlemodeFormat) +- { +- QSettings settings(GetConfPath(), QSettings::IniFormat); +- settings.setValue("TermMode", newTermMode); +- settings.setValue("singlemodeFormat", newSingleMode); +- QMessageBox msgBox; +- msgBox.setText("Presentation Mode will change next time program is started."); +- msgBox.exec(); +- } +- +- return; +- } +- +- if (Act == EnableMonitor) +- ActiveSession->EnableMonitor = state; +- else if (Act == EnableMonLog) +- ActiveSession->LogMonitor = state; +- else if (Act == MonLocalTime) +- ActiveSession->mlocaltime = state; +- else if (Act == MonTX) +- ActiveSession->mtxparam = state; +- else if (Act == MonSup) +- ActiveSession->mcomparam = state; +- else if (Act == MonUI) +- ActiveSession->monUI = state; +- else if (Act == MonNodes) +- ActiveSession->MonitorNODES = state; +- else if (Act == MonColour) +- ActiveSession->MonitorColour = state; +- else if (Act == actChatMode) +- ChatMode = state; +- else if (Act == actAutoTeletext) +- AutoTeletext = state; +- else if (Act == actBells) +- Bells = state; +- else if (Act == actStripLF) +- StripLF = state; +- else if (Act == actIntervalBeep) +- AlertBeep = state; +- else if (Act == actConnectBeep) +- ConnectBeep = state; +- else if (Act == actnoConv) +- convUTF8 = -1; +- else if (Act == actAuto) +- convUTF8 = 0; +- else if (Act == actCP1251) +- convUTF8 = 1251; +- else if (Act == actCP1252) +- convUTF8 = 1252; +- else if (Act == actCP437) +- convUTF8 = 437; +- else +- { +- // look for port entry +- for (int i = 0; i < MAXPORTS + 1; i++) +- { +- if (Act == MonPort[i]) +- { +- uint64_t mmask; +- +- if (i == 0) // BBS Mon - use bit 63 (Port 64) +- mmask = (uint64_t)1 << 63; +- else +- mmask = (uint64_t)1 << (i - 1); +- +- if (state) +- ActiveSession->portmask |= mmask; +- else +- ActiveSession->portmask &= ~mmask; +- break; +- } +- } +- } +- +- +- if (ActiveSession->clientSocket && ActiveSession->SessionType & Mon) +- SendTraceOptions(ActiveSession); +- +- else if (AGWUsers && ActiveSession == AGWUsers->MonSess) +- { +- AGWMonEnable = ActiveSession->EnableMonitor; +- AGWLocalTime = ActiveSession->mlocaltime; +- AGWMonNodes = ActiveSession->MonitorNODES; +- Send_AGW_m_Frame((QTcpSocket*)ActiveSession->AGWSession); +- } +- +- else if (ActiveSession == KISSMonSess) +- { +- KISSLocalTime = ActiveSession->mlocaltime; +- KISSMonEnable = ActiveSession->EnableMonitor; +- KISSMonNodes = ActiveSession->MonitorNODES; +- } +- return; +-} +- +- +- +- +-void QtTermTCP::LDisconnect(Ui_ListenSession * LUI) +-{ +- if (LUI->clientSocket) +- LUI->clientSocket->disconnectFromHost(); +-} +- +-extern QApplication * a; +- +-void QtTermTCP::LreturnPressed(Ui_ListenSession * Sess) +-{ +- QByteArray stringData = Sess->inputWindow->text().toUtf8(); +- +- // if multiline input (eg from copy/paste) replace LF with CR +- +- char * ptr; +- char * Msgptr; +- char * Msg; +- +- QScrollBar *scrollbar = Sess->termWindow->verticalScrollBar(); +- bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4)); +- +- if (scrollbarAtBottom) +- Sess->termWindow->moveCursor(QTextCursor::End); // So we don't get blank lines +- +- // Stack it +- +- Sess->StackIndex = 0; +- +- if (Sess->KbdStack[49]) +- free(Sess->KbdStack[49]); +- +- for (int i = 48; i >= 0; i--) +- { +- Sess->KbdStack[i + 1] = Sess->KbdStack[i]; +- } +- +- Sess->KbdStack[0] = qstrdup(stringData.data()); +- +- stringData.append('\n'); +- +- Msgptr = stringData.data(); +- +- if (Sess->TTActive) // Teletext uses 0x5F for # +- while ((ptr = strchr(Msgptr, 0x23))) // Replace VT with LF +- *ptr++ = 0x5f; +- +- +- while ((ptr = strchr(Msgptr, 11))) // Replace VT with LF +- *ptr++ = 10; +- +- LastWrite = time(NULL); // Stop initial beep +- Sess->SlowTimer = 0; +- +- Sess->pageBuffer[0] = 0; // Reset Teletext mode screen buffer +- +- if (Sess->KISSMode == 1) +- { +- // UI session. Send as UI Message +- +- while ((ptr = strchr(Msgptr, '\n'))) +- { +- *ptr++ = 0; +- +- Msg = (char *)malloc(strlen(Msgptr) + 10); +- strcpy(Msg, Msgptr); +- strcat(Msg, "\r"); +- +- +- Send_UI(Sess->UIPORT, 0xF0, KISSMYCALL, Sess->UIDEST, Sess->UIPATH, (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); +- Sess->clientSocket->flush(); +-// QThread::msleep(1500); // Try to force as separate packets +- 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))); +- +- +- // Set Monitor Params for this host +- +- sscanf(MonParams[Sess->CurrentHost], "%llx %x %x %x %x %x", +- &Sess->portmask, &Sess->mtxparam, &Sess->mcomparam, +- &Sess->MonitorNODES, &Sess->MonitorColour, &Sess->monUI); +- +- Sess->mlocaltime = (Sess->mtxparam >> 7); +- Sess->mtxparam &= 1; +- +- MonLocalTime->setChecked(Sess->mlocaltime); +- MonTX->setChecked(Sess->mtxparam); +- MonSup->setChecked(Sess->mcomparam); +- MonUI->setChecked(Sess->monUI); +- MonNodes->setChecked(Sess->MonitorNODES); +- MonColour->setChecked(Sess->MonitorColour); +- +- 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(&IntervalWAV); +- +- } +- +- // Alert if QtTerm not active window (unless Mon window) +- +- if((Sess->SessionType & Mon) == 0) +- FlashifNotActive(); +- +- // if tabbed and not active tab set tab label red +- +- if (TermMode == Tabbed) +- { +- if (Sess->monWindow != termWindow) // Not if Monitor +- { +- if (ActiveSession != Sess) +- { +- tabWidget->tabBar()->setTabTextColor(Sess->Tab, newTabText); +- } +- } +- } +- +- LastWrite = NOW; +- +- // Mustn't mess with original buffer +- +- memcpy(Copy, Buffer, len); +- +- Copy[len] = 0; +- +- ptr1 = Copy; +- +- const QTextCursor old_cursor = termWindow->textCursor(); +- const int old_scrollbar_value = termWindow->verticalScrollBar()->value(); +- const bool is_scrolled_down = old_scrollbar_value == termWindow->verticalScrollBar()->maximum(); +- +- if (*OutputSaveLen) +- { +- // Have part line - append to it +- memcpy(&OutputSave[*OutputSaveLen], Copy, len); +- *OutputSaveLen += len; +- ptr1 = (unsigned char *)OutputSave; +- len = *OutputSaveLen; +- *OutputSaveLen = 0; +- +- // part line was written to screen so remove it +- +-// termWindow->setFocus(); +- termWindow->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); +- termWindow->moveCursor(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor); +- termWindow->moveCursor(QTextCursor::End, QTextCursor::KeepAnchor); +- termWindow->textCursor().removeSelectedText(); +- // termWindow->textCursor().deletePreviousChar(); +- } +- +- // Move the cursor to the end of the document. +- +- termWindow->moveCursor(QTextCursor::End); +- +- // Insert the text at the position of the cursor (which is the end of the document). +- +-lineloop: +- +- if (len <= 0) +- { +- if (old_cursor.hasSelection() || !is_scrolled_down) +- { +- // The user has selected text or scrolled away from the bottom: maintain position. +- termWindow->setTextCursor(old_cursor); +- termWindow->verticalScrollBar()->setValue(old_scrollbar_value); +- } +- else +- { +- // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. +- termWindow->moveCursor(QTextCursor::End); +- termWindow->verticalScrollBar()->setValue(termWindow->verticalScrollBar()->maximum()); +- } +- +- return; +- } +- +- +- // copy text to control a line at a time +- +- ptr2 = (unsigned char *)memchr(ptr1, 13, len); +- +- if (ptr2 == 0) // No CR +- { +- if (len > 8000) +- len = 8000; // Should never get lines this long +- +- memmove(OutputSave, ptr1, len); +- *OutputSaveLen = len; +- +- // Write part line to screen +- +- memcpy(Line, ptr1, len); +- Line[len] = 0; +- +- // I don't think I need to worry if UTF8 as will be rewritten when rest arrives +- +- if (Line[0] == 0x1b) // Colour Escape +- { +- if (Sess->MonitorColour) +- termWindow->setTextColor(Colours[Line[1] - 10]); +- +- termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); +- } +- else +- { +- termWindow->setTextColor(Colour); +- termWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); +- } +- +- // *OutputSaveLen = 0; // Test if we need to delete part line +- +- // if (scrollbarAtBottom) +- // termWindow->moveCursor(QTextCursor::End); +- +- if (old_cursor.hasSelection() || !is_scrolled_down) +- { +- // The user has selected text or scrolled away from the bottom: maintain position. +- termWindow->setTextCursor(old_cursor); +- termWindow->verticalScrollBar()->setValue(old_scrollbar_value); +- } +- else +- { +- // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. +- termWindow->moveCursor(QTextCursor::End); +- termWindow->verticalScrollBar()->setValue(termWindow->verticalScrollBar()->maximum()); +- } +- return; +- } +- +- *(ptr2++) = 0; +- +- if (Bells) +- { +- char * ptr; +- +- do { +- ptr = (char *)memchr(ptr1, 7, len); +- +- if (ptr) +- { +- *(ptr) = 32; +- myBeep(&BellWAV); +- } +- } while (ptr); +- } +- +- num = ptr2 - ptr1 - 1; +- +- // if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1); +- +- memcpy(Line, ptr1, num); +- Line[num++] = 13; +- Line[num] = 0; +- +- if (Line[0] == 0x1b) // Colour Escape +- { +- if (Sess->MonitorColour) +- termWindow->setTextColor(Colours[Line[1] - 10]); +- +- outlen = checkUTF8(&Line[2], num - 2, out); +- out[outlen] = 0; +- termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); +- // termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); +- } +- else +- { +- termWindow->setTextColor(Colour); +- +- outlen = checkUTF8(Line, num, out); +- out[outlen] = 0; +- termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); +- // termWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); +- } +- +- len -= (ptr2 - ptr1); +- +- ptr1 = ptr2; +- +- if ((len > 0) && StripLF) +- { +- if (*ptr1 == 0x0a) // Line Feed +- { +- ptr1++; +- len--; +- } +- } +- +- +- +- goto lineloop; +- +-} +- +-void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg); +- +-extern "C" void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Msg, int len) +-{ +- char * ptr1 = (char *)Msg, *ptr2; +- char Line[512]; +- int num; +- +- // QScrollBar *scrollbar = Sess->monWindow->verticalScrollBar(); +- // bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4)); +- +- if (Sess->monWindow == nullptr) +- return; +- +- Sess->monWindow->setStyleSheet(monStyleSheet); +- +- const QTextCursor old_cursor = Sess->monWindow->textCursor(); +- const int old_scrollbar_value = Sess->monWindow->verticalScrollBar()->value(); +- const bool is_scrolled_down = old_scrollbar_value == Sess->monWindow->verticalScrollBar()->maximum(); +- +- // Move the cursor to the end of the document. +- Sess->monWindow->moveCursor(QTextCursor::End); +- +- // Insert the text at the position of the cursor (which is the end of the document). +- +- +- // Write a line at a time so we can action colour chars +- +-// Buffer[Len] = 0; +- +-// if (scrollbarAtBottom) +-// Sess->monWindow->moveCursor(QTextCursor::End); +- +- if (Sess->MonSaveLen) +- { +- // Have part line - append to it +- memcpy(&Sess->MonSave[Sess->MonSaveLen], Msg, len); +- Sess->MonSaveLen += len; +- ptr1 = Sess->MonSave; +- len = Sess->MonSaveLen; +- Sess->MonSaveLen = 0; +- } +- +-lineloop: +- +- if (len <= 0) +- { +- // if (scrollbarAtBottom) +- // Sess->monWindow->moveCursor(QTextCursor::End); +- +- +- if (old_cursor.hasSelection() || !is_scrolled_down) +- { +- // The user has selected text or scrolled away from the bottom: maintain position. +- Sess->monWindow->setTextCursor(old_cursor); +- Sess->monWindow->verticalScrollBar()->setValue(old_scrollbar_value); +- } +- else +- { +- // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. +- Sess->monWindow->moveCursor(QTextCursor::End); +- Sess->monWindow->verticalScrollBar()->setValue(Sess->monWindow->verticalScrollBar()->maximum()); +- } +- +- return; +- } +- +- // copy text to control a line at a time +- +- ptr2 = (char *)memchr(ptr1, 13, len); +- +- if (ptr2 == 0) // No CR +- { +- memmove(Sess->MonSave, ptr1, len); +- Sess->MonSaveLen = len; +- return; +- } +- +- *(ptr2++) = 0; +- +- +- if (Sess->LogMonitor) +- WriteMonitorLog(Sess, ptr1); +- +- num = ptr2 - ptr1 - 1; +- +- memcpy(Line, ptr1, num); +- Line[num++] = 13; +- Line[num] = 0; +- +- if (Line[0] == 0x1b) // Colour Escape +- { +- if (Sess->MonitorColour) +- { +- if (Line[1] == 17) +- Sess->monWindow->setTextColor(monRxText); +- else +- Sess->monWindow->setTextColor(monTxText); +- } +- else +- Sess->monWindow->setTextColor(monOtherText); +- +- Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); +- } +- else +- { +- Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); +- } +- len -= (ptr2 - ptr1); +- +- ptr1 = ptr2; +- +- goto lineloop; +- +-} +- +-int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len); +-void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len); +- +-// YAPP stuff +- +-#define SOH 1 +-#define STX 2 +-#define ETX 3 +-#define EOT 4 +-#define ENQ 5 +-#define ACK 6 +-#define DLE 0x10 +-#define NAK 0x15 +-#define CAN 0x18 +- +-extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len) +-{ +- if (Sess == 0) +- return; +- +- Sess->SlowTimer = 0; +- Msg[Len] = 0; +- +- if (Sess->InputMode == 'Y') // Yapp +- { +- ProcessYAPPMessage(Sess, (unsigned char *)Msg, Len); +- return; +- } +- +- // Could be a YAPP Header +- +- if (Len == 2 && Msg[0] == ENQ && Msg[1] == 1) // YAPP Send_Init +- { +- char YAPPRR[2]; +- +- // Turn off monitoring +- +- Sess->InputMode = 'Y'; +- +- YAPPRR[0] = ACK; +- YAPPRR[1] = 1; +- QueueMsg(Sess, YAPPRR, 2); +- +- return; +- } +- +- if (AutoTeletext && (Msg[0] == 0x1e || Msg[0] == 0x0c)) +- { +- if (Sess->TTActive == 0) +- { +- Sess->TTActive = 1; +- DoTermResize(Sess); +- } +- } +- +- if (Sess->TTActive) +- { +- // Feed to Teletext code +- +- // We need to decode a whole page. There is no obvious delimiter so process till data stops. +- // Buffer is cleared when next input is sent +- +- if (strlen(&Sess->pageBuffer[0] + Len) > 4090) +- Sess->pageBuffer[0] = 0; // Protect buffer +- +- strcat(Sess->pageBuffer, (char *)Msg); +- +- DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end +- return; +- } +- +- WritetoOutputWindow(Sess, (unsigned char *)Msg, Len); +- +-} +- +-QSettings* settings; +- +-// This makes geting settings for more channels easier +- +-char Prefix[16] = "AX25_A"; +- +-void GetPortSettings(int Chan); +- +-QVariant getAX25Param(const char * key, QVariant Default) +-{ +- char fullKey[64]; +- +- sprintf(fullKey, "%s/%s", Prefix, key); +- return settings->value(fullKey, Default); +-} +- +-void getAX25Params(int chan) +-{ +- Prefix[5] = chan + 'A'; +- GetPortSettings(chan); +-} +- +- +-void GetPortSettings(int Chan) +-{ +- txdelay[Chan] = getAX25Param("TXDelay", 250).toInt(); +- sendTXDelay[Chan] = getAX25Param("sendTXDelay", 0).toInt(); +- maxframe[Chan] = getAX25Param("Maxframe", 4).toInt(); +- fracks[Chan] = getAX25Param("Retries", 10).toInt(); +- frack_time[Chan] = getAX25Param("FrackTime", 8).toInt(); +- persist[Chan] = getAX25Param("Persist", 128).toInt(); +- kisspaclen[Chan] = getAX25Param("Paclen", 128).toInt(); +- idletime[Chan] = getAX25Param("IdleTime", 180).toInt(); +- slottime[Chan] = getAX25Param("SlotTime", 100).toInt(); +- resptime[Chan] = getAX25Param("RespTime", 1500).toInt(); +- TXFrmMode[Chan] = getAX25Param("TXFrmMode", 1).toInt(); +- max_frame_collector[Chan] = getAX25Param("FrameCollector", 6).toInt(); +- //exclude_callsigns[Chan]= getAX25Param("ExcludeCallsigns/"); +- //exclude_APRS_frm[Chan]= getAX25Param("ExcludeAPRSFrmType/"); +- KISS_opt[Chan] = getAX25Param("KISSOptimization", false).toInt();; +- dyn_frack[Chan] = getAX25Param("DynamicFrack", false).toInt();; +- IPOLL[Chan] = getAX25Param("IPOLL", 80).toInt(); +- +-} +- +- +-void GetSettings() +-{ +- QByteArray qb; +- int i; +- char Key[16]; +- char Param[256]; +- +- settings = new QSettings(GetConfPath(), QSettings::IniFormat); +- +- // Get saved session definitions +- +- sessionList = strdup(settings->value("Sessions", "1|3, 0, 5, 5, 600, 800|").toString().toUtf8()); +- +- for (i = 0; i < MAXHOSTS; i++) +- { +- sprintf(Key, "HostParams%d", i); +- +- qb = settings->value(Key).toByteArray(); +- +- DecodeSettingsLine(i, qb.data()); +- } +- +- Split = settings->value("Split", 50).toInt(); +- ChatMode = settings->value("ChatMode", 1).toInt(); +- AutoTeletext = settings->value("AutoTeletext", 0).toInt(); +- Bells = settings->value("Bells", 1).toInt(); +- StripLF = settings->value("StripLF", 1).toInt(); +- useBeep = settings->value("useBeep", true).toBool(); +- AlertBeep = settings->value("AlertBeep", 1).toInt(); +- AlertInterval = settings->value("AlertInterval", 300).toInt(); +- ConnectBeep = settings->value("ConnectBeep", 1).toInt(); +- ConnectWAV = settings->value("ConnectWAV", ":/PCBeep").toString().toUtf8(); +- AlertWAV = settings->value("AlertWAV", ":/PCBeep").toString().toUtf8(); +- BellWAV = settings->value("BellWAV", ":/PCBeep").toString().toUtf8(); +- IntervalWAV = settings->value("IntervalWAV", ":/PCBeep").toString().toUtf8(); +- +- UseKeywords = settings->value("UseKeywords", 0).toInt(); +- KeyWordsFile = settings->value("KeyWordsFile", "keywords.sys").toString().toUtf8(); +- +- SavedHost = settings->value("CurrentHost", 0).toInt(); +- strcpy(YAPPPath, settings->value("YAPPPath", "").toString().toUtf8()); +- MaxRXSize = settings->value("MaxRXSize", 100000).toInt(); +- +- listenPort = settings->value("listenPort", 8015).toInt(); +- listenEnable = settings->value("listenEnable", false).toBool(); +- strcpy(listenCText, settings->value("listenCText", "").toString().toUtf8()); +- +- TermMode = settings->value("TermMode", 0).toInt(); +- singlemodeFormat = settings->value("singlemodeFormat", Term + Mon).toInt(); +- +- AGWEnable = settings->value("AGWEnable", 0).toInt(); +- AGWMonEnable = settings->value("AGWMonEnable", 0).toInt(); +- AGWLocalTime = settings->value("AGWLocalTime", 0).toInt(); +- AGWMonNodes = settings->value("AGWMonNodes", 0).toInt(); +- strcpy(AGWTermCall, settings->value("AGWTermCall", "").toString().toUtf8()); +- strcpy(AGWBeaconDest, settings->value("AGWBeaconDest", "").toString().toUtf8()); +- strcpy(AGWBeaconPath, settings->value("AGWBeaconPath", "").toString().toUtf8()); +- AGWBeaconInterval = settings->value("AGWBeaconInterval", 0).toInt(); +- strcpy(AGWBeaconPorts, settings->value("AGWBeaconPorts", "").toString().toUtf8()); +- strcpy(AGWBeaconMsg, settings->value("AGWBeaconText", "").toString().toUtf8()); +- strcpy(AGWHost, settings->value("AGWHost", "127.0.0.1").toString().toUtf8()); +- AGWPortNum = settings->value("AGWPort", 8000).toInt(); +- AGWPaclen = settings->value("AGWPaclen", 80).toInt(); +- AGWToCalls = settings->value("AGWToCalls", "").toStringList(); +- convUTF8 = settings->value("convUTF8", 0).toInt(); +- +- KISSEnable = settings->value("KISSEnable", 0).toInt(); +- KISSMonEnable = settings->value("KISSMonEnable", 1).toInt(); +- KISSLocalTime = settings->value("KISSLocalTime", 0).toInt(); +- KISSMonNodes = settings->value("KISSMonNodes", 0).toInt(); +- +- KISSListen = settings->value("KISSListen", 1).toInt(); +- KISSChecksum = settings->value("KISSChecksum", 0).toInt(); +- KISSAckMode = settings->value("KISSAckMode", 0).toInt(); +- KISSMH = settings->value("KISSMH", 1).toInt(); +- strcpy(KISSMYCALL, 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(KISSVia, settings->value("KISSVia", "").toString().toUtf8()); +- +- strcpy(SerialPort, settings->value("KISSSerialPort", "None").toString().toUtf8()); +- KISSBAUD = settings->value("KISSBAUD", 19200).toInt(); +- getAX25Params(0); +- +- VARAEnable = settings->value("VARAEnable", 0).toInt(); +- strcpy(VARAHost, settings->value("VARAHost", "127.0.0.1").toString().toUtf8()); +- strcpy(VARAHostFM, settings->value("VARAHostFM", "127.0.0.1").toString().toUtf8()); +- strcpy(VARAHostHF, settings->value("VARAHostHF", "127.0.0.1").toString().toUtf8()); +- strcpy(VARAHostSAT, settings->value("VARAHostSAT", "127.0.0.1").toString().toUtf8()); +- VARAPortNum = settings->value("VARAPort", 8300).toInt(); +- VARAPortHF = settings->value("VARAPortHF", 8300).toInt(); +- VARAPortFM = settings->value("VARAPortFM", 8300).toInt(); +- VARAPortSAT = settings->value("VARAPortSAT", 8300).toInt(); +- strcpy(VARAPath, settings->value("VARAPath", "C:\\VARA\\VARA.exe").toString().toUtf8()); +- strcpy(VARAPathHF, settings->value("VARAPathHF", "C:\\VARA\\VARA.exe").toString().toUtf8()); +- strcpy(VARAPathFM, settings->value("VARAPathFM", "C:\\VARA\\VARAFM.exe").toString().toUtf8()); +- strcpy(VARAPathSAT, settings->value("VARAPathSAT", "C:\\VARA\\VARASAT.exe").toString().toUtf8()); +- strcpy(VARATermCall, settings->value("VARATermCall", "").toString().toUtf8()); +- VARA500 = settings->value("VARA500", 0).toInt(); +- VARA2300 = settings->value("VARA2300", 1).toInt(); +- VARA2750 = settings->value("VARA2750", 0).toInt(); +- VARAHF = settings->value("VARAHF", 1).toInt(); +- VARAFM = settings->value("VARAFM", 0).toInt(); +- VARASAT = settings->value("VARASAT", 0).toInt(); +- strcpy(VARAInit, settings->value("VARAInit", "").toString().toUtf8()); +- +- strcpy(PTTPort, settings->value("PTT", "None").toString().toUtf8()); +- PTTMode = settings->value("PTTMode", 19200).toInt(); +- PTTBAUD = settings->value("PTTBAUD", 19200).toInt(); +- CATHex = settings->value("CATHex", 1).toInt(); +- +- strcpy(PTTOnString, settings->value("PTTOnString", "").toString().toUtf8()); +- strcpy(PTTOffString, settings->value("PTTOffString", "").toString().toUtf8()); +- +- pttGPIOPin = settings->value("pttGPIOPin", 17).toInt(); +- pttGPIOPinR = settings->value("pttGPIOPinR", 17).toInt(); +- +-#ifdef WIN32 +- strcpy(CM108Addr, settings->value("CM108Addr", "0xD8C:0x08").toString().toUtf8()); +-#else +- strcpy(CM108Addr, settings->value("CM108Addr", "/dev/hidraw0").toString().toUtf8()); +-#endif +- +- HamLibPort = settings->value("HamLibPort", 4532).toInt(); +- strcpy(HamLibHost, settings->value("HamLibHost", "127.0.0.1").toString().toUtf8()); +- +- FLRigPort = settings->value("FLRigPort", 12345).toInt(); +- strcpy(FLRigHost, settings->value("FLRigHost", "127.0.0.1").toString().toUtf8()); +- +- +- strcpy(Param, settings->value("TabType", "1 1 1 1 1 1 1 2 2").toString().toUtf8()); +- sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", +- &TabType[0], &TabType[1], &TabType[2], &TabType[3], &TabType[4], +- &TabType[5], &TabType[6], &TabType[7], &TabType[8], &TabType[9]); +- +- strcpy(Param, settings->value("AutoConnect", "0, 0 ,0, 0, 0, 0, 0, 0, 0, 0").toString().toUtf8()); +- sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", +- &AutoConnect[0], &AutoConnect[1], &AutoConnect[2], &AutoConnect[3], &AutoConnect[4], +- &AutoConnect[5], &AutoConnect[6], &AutoConnect[7], &AutoConnect[8], &AutoConnect[9]); +- +- strcpy(Param, settings->value("currentHost", "0, 0 ,0, 0, 0, 0, 0, 0, 0, 0").toString().toUtf8()); +- sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", +- ¤tHost[0], ¤tHost[1], ¤tHost[2], ¤tHost[3], ¤tHost[4], +- ¤tHost[5], ¤tHost[6], ¤tHost[7], ¤tHost[8], ¤tHost[9]); +- +- +- monBackground = settings->value("monBackground", QColor(255, 255, 255)).value(); +- monRxText = settings->value("monRxText", QColor(0, 0, 255)).value(); +- monTxText = settings->value("monTxText", QColor(255, 0, 0)).value(); +- monOtherText = settings->value("monOtherText", QColor(0, 0, 0)).value(); +- +- termBackground = settings->value("termBackground", QColor(255, 255, 255)).value(); +- outputText = settings->value("outputText", QColor(0, 0, 255)).value(); +- EchoText = settings->value("EchoText", QColor(0, 0, 0)).value(); +- WarningText = settings->value("WarningText", QColor(255, 0, 0)).value(); +- +- inputBackground = settings->value("inputBackground", QColor(255, 255, 255)).value(); +- inputText = settings->value("inputText", QColor(0, 0, 0)).value(); +- +- delete(settings); +-} +- +-void SavePortSettings(int Chan); +- +-void saveAX25Param(const char * key, QVariant Value) +-{ +- char fullKey[64]; +- +- sprintf(fullKey, "%s/%s", Prefix, key); +- +- settings->setValue(fullKey, Value); +-} +- +-void saveAX25Params(int chan) +-{ +- Prefix[5] = chan + 'A'; +- SavePortSettings(chan); +-} +- +-void SavePortSettings(int Chan) +-{ +- saveAX25Param("TXDelay", txdelay[Chan]); +- saveAX25Param("sendTXDelay", sendTXDelay[Chan]); +- saveAX25Param("Maxframe", maxframe[Chan]); +- saveAX25Param("Paclen", kisspaclen[Chan]); +- saveAX25Param("FrackTime", frack_time[Chan]); +- saveAX25Param("IdleTime", idletime[Chan]); +- saveAX25Param("SlotTime", slottime[Chan]); +- saveAX25Param("Persist", persist[Chan]); +- saveAX25Param("RespTime", resptime[Chan]); +- saveAX25Param("TXFrmMode", TXFrmMode[Chan]); +- saveAX25Param("FrameCollector", max_frame_collector[Chan]); +- saveAX25Param("ExcludeCallsigns", exclude_callsigns[Chan]); +- saveAX25Param("ExcludeAPRSFrmType", exclude_APRS_frm[Chan]); +- saveAX25Param("KISSOptimization", KISS_opt[Chan]); +- saveAX25Param("DynamicFrack", dyn_frack[Chan]); +- saveAX25Param("BitRecovery", recovery[Chan]); +- saveAX25Param("IPOLL", IPOLL[Chan]); +- saveAX25Param("MyDigiCall", MyDigiCall[Chan]); +-} +- +-extern "C" void SaveSettings() +-{ +- int i; +- char Param[512]; +- char Key[16]; +- +- settings = new QSettings(GetConfPath(), QSettings::IniFormat); +- +- for (i = 0; i < MAXHOSTS; i++) +- { +- sprintf(Key, "HostParams%d", i); +- EncodeSettingsLine(i, Param); +- settings->setValue(Key, Param); +- } +- +- settings->setValue("Split", Split); +- settings->setValue("ChatMode", ChatMode); +- settings->setValue("AutoTeletext", AutoTeletext); +- settings->setValue("Bells", Bells); +- settings->setValue("StripLF", StripLF); +- settings->setValue("AlertBeep", AlertBeep); +- settings->setValue("useBeep", useBeep); +- settings->setValue("ConnectBeep", ConnectBeep); +- settings->setValue("BellWAV", BellWAV); +- settings->setValue("AlertWAV", AlertWAV); +- settings->setValue("IntervalWAV", IntervalWAV); +- settings->setValue("ConnectWAV", ConnectWAV); +- +- settings->setValue("UseKeywords", UseKeywords); +- settings->setValue("KeyWordsFile", KeyWordsFile); +- +- settings->setValue("AlertInterval", AlertInterval); +- settings->setValue("CurrentHost", SavedHost); +- +- settings->setValue("YAPPPath", YAPPPath); +- settings->setValue("MaxRXSize", MaxRXSize); +- +- settings->setValue("listenPort", listenPort); +- settings->setValue("listenEnable", listenEnable); +- settings->setValue("listenCText", listenCText); +- settings->setValue("convUTF8", convUTF8); +- +- settings->setValue("PTT", PTTPort); +- settings->setValue("PTTBAUD", PTTBAUD); +- settings->setValue("PTTMode", PTTMode); +- +- settings->setValue("CATHex", CATHex); +- +- settings->setValue("PTTOffString", PTTOffString); +- settings->setValue("PTTOnString", PTTOnString); +- +- settings->setValue("pttGPIOPin", pttGPIOPin); +- settings->setValue("pttGPIOPinR", pttGPIOPinR); +- +- settings->setValue("CM108Addr", CM108Addr); +- settings->setValue("HamLibPort", HamLibPort); +- settings->setValue("HamLibHost", HamLibHost); +- settings->setValue("FLRigPort", FLRigPort); +- settings->setValue("FLRigHost", FLRigHost); +- +- +- // Save Sessions +- +- char SessionString[1024]; +- int SessStringLen; +- +- SessStringLen = sprintf(SessionString, "%d|", _sessions.size()); +- +- if (TermMode == MDI) +- { +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Ui_ListenSession * Sess = _sessions.at(i); +- +- QRect r = Sess->sw->geometry(); +- +- SessStringLen += sprintf(&SessionString[SessStringLen], +- "%d, %d, %d, %d, %d, %d|", Sess->SessionType, Sess->CurrentHost, r.top(), r.left(), r.bottom(), r.right()); +- } +- +- settings->setValue("Sessions", SessionString); +- } +- +- settings->setValue("AGWEnable", AGWEnable); +- settings->setValue("AGWMonEnable", AGWMonEnable); +- settings->setValue("AGWLocalTime", AGWLocalTime); +- settings->setValue("AGWMonNodes", AGWMonNodes); +- settings->setValue("AGWTermCall", AGWTermCall); +- settings->setValue("AGWBeaconDest", AGWBeaconDest); +- settings->setValue("AGWBeaconPath", AGWBeaconPath); +- settings->setValue("AGWBeaconInterval", AGWBeaconInterval); +- settings->setValue("AGWBeaconPorts", AGWBeaconPorts); +- settings->setValue("AGWBeaconText", AGWBeaconMsg); +- settings->setValue("AGWHost", AGWHost); +- settings->setValue("AGWPort", AGWPortNum); +- settings->setValue("AGWPaclen", AGWPaclen); +- settings->setValue("AGWToCalls", AGWToCalls); +- +- settings->setValue("KISSEnable", KISSEnable); +- settings->setValue("KISSMonEnable", KISSMonEnable); +- settings->setValue("KISSLocalTime", KISSLocalTime); +- settings->setValue("KISSMonNodes", KISSMonNodes); +- +- settings->setValue("KISSListen", KISSListen); +- settings->setValue("KISSChecksum", KISSChecksum); +- settings->setValue("KISSAckMode", KISSAckMode); +- settings->setValue("KISSMH", KISSMH); +- settings->setValue("MYCALL", KISSMYCALL); +- settings->setValue("KISSHost", KISSHost); +- settings->setValue("KISSMode", KISSMode); +- settings->setValue("KISSPort", KISSPortNum); +- settings->setValue("KISSSerialPort", SerialPort); +- settings->setValue("KISSBAUD", KISSBAUD); +- settings->setValue("KISSVia", KISSVia); +- +- saveAX25Params(0); +- +- settings->setValue("VARAEnable", VARAEnable); +- settings->setValue("VARATermCall", VARATermCall); +- settings->setValue("VARAHost", VARAHost); +- settings->setValue("VARAPort", VARAPortNum); +- settings->setValue("VARAInit", VARAInit); +- settings->setValue("VARAPath", VARAPath); +- settings->setValue("VARAHostHF", VARAHostHF); +- settings->setValue("VARAPortHF", VARAPortHF); +- settings->setValue("VARAPathHF", VARAPathHF); +- settings->setValue("VARAHostFM", VARAHostFM); +- settings->setValue("VARAPortFM", VARAPortFM); +- settings->setValue("VARAPathFM", VARAPathFM); +- settings->setValue("VARAHostSAT", VARAHostSAT); +- settings->setValue("VARAPortSAT", VARAPortSAT); +- settings->setValue("VARAPathSAT", VARAPathSAT); +- settings->setValue("VARA500", VARA500); +- settings->setValue("VARA2300", VARA2300); +- settings->setValue("VARA2750", VARA2750); +- settings->setValue("VARAHF", VARAHF); +- settings->setValue("VARAFM", VARAFM); +- settings->setValue("VARASAT", VARASAT); +- +- sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", +- TabType[0], TabType[1], TabType[2], TabType[3], TabType[4], TabType[5], TabType[6], TabType[7], TabType[8], TabType[9]); +- +- settings->setValue("TabType", Param); +- +- sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", +- AutoConnect[0], AutoConnect[1], AutoConnect[2], AutoConnect[3], AutoConnect[4], AutoConnect[5], AutoConnect[6], AutoConnect[7], AutoConnect[8], AutoConnect[9]); +- +- settings->setValue("AutoConnect", Param); +- +- sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", +- currentHost[0], currentHost[1], currentHost[2], currentHost[3], currentHost[4], currentHost[5], currentHost[6], currentHost[7], currentHost[8], currentHost[9]); +- +- settings->setValue("currentHost", Param); +- +- settings->setValue("monBackground", monBackground); +- settings->setValue("monRxText", monRxText); +- settings->setValue("monTxText", monTxText); +- settings->setValue("monOtherText", monOtherText); +- +- settings->setValue("termBackground", termBackground); +- settings->setValue("outputText", outputText); +- settings->setValue("EchoText", EchoText); +- settings->setValue("WarningText", WarningText); +- +- settings->setValue("inputBackground", inputBackground); +- settings->setValue("inputText", inputText); +- +- settings->sync(); +- delete(settings); +-} +- +-#include +- +-void QtTermTCP::closeEvent(QCloseEvent *event) +-{ +- QMessageBox::StandardButton resBtn = QMessageBox::question(this, "QtTermTCP", +- tr("Are you sure?\n"), +- QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes, +- QMessageBox::Yes); +- if (resBtn != QMessageBox::Yes) { +- event->ignore(); +- } +- else +- { +- event->accept(); +-#ifdef USESERIAL +- if (hPTTDevice) +- hPTTDevice->close(); +-#endif +- if (process) +- process->close(); +- +- if (MHWindow) +- MHWindow->close(); +- +- } +-} +- +-QtTermTCP::~QtTermTCP() +-{ +- Ui_ListenSession * Sess; +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->monLogfile) +- Sess->monLogfile->close(); +- +- if (Sess->clientSocket) +- { +- int loops = 100; +- Sess->clientSocket->disconnectFromHost(); +- while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState) +- QThread::msleep(10); +- } +- } +- +- if (AGWSock && AGWSock->ConnectedState == QAbstractSocket::ConnectedState) +- { +- int loops = 100; +- AGWSock->disconnectFromHost(); +- QThread::msleep(10); +- while (AGWSock && loops-- && AGWSock->state() != QAbstractSocket::UnconnectedState) +- QThread::msleep(10); +- } +- +- if (_server->isListening()) +- _server->close(); +- +- delete(_server); +- +- QSettings mysettings(GetConfPath(), QSettings::IniFormat); +- mysettings.setValue("geometry", saveGeometry()); +- mysettings.setValue("windowState", saveState()); +- +- if (MHWindow) +- { +- mysettings.setValue("MHgeometry", MHWindow->saveGeometry()); +- MHWindow->close(); +- } +- 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(); +- +-} +- +-void QtTermTCP::SlowTimerSlot() +-{ +- // Runs every 60 S +- +- Ui_ListenSession * Sess; +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->monLogfile) +- { +- Sess->monLogfile->close(); +- Sess->monLogfile = nullptr; +- } +- } +- +-} +- +- +- +-extern "C" void myBeep(QString * WAV) +-{ +- if (useBeep) +- { +- QApplication::beep(); +- return; +- } +- +- // Using .wav files +- +-// QSoundEffect effect; +-// effect.setSource(QUrl::fromLocalFile(*WAV)); +-// effect.setLoopCount(1); +-// effect.setVolume(1.0f); +-// effect.play(); +- +- QSound::play(*WAV); +-} +- +-void QtTermTCP::ListenSlot() +-{ +- // This runs the Listen Configuration dialog +- +- ListenDialog * xx = new ListenDialog(); +- xx->exec(); +-} +- +-void QtTermTCP::AGWSlot() +-{ +- // This runs the AGW Configuration dialog +- +- AGWDialog dialog(0); +- dialog.exec(); +-} +- +-Ui_Dialog * Dev; +-Ui_AlertDialog * Alert; +- +-static Ui_KISSDialog * KISS; +-static Ui_ColourDialog * COLOURS; +- +- +-char NewPTTPort[80]; +- +-int newSoundMode = 0; +-int oldSoundMode = 0; +- +-#ifdef USESERIAL +-QList Ports = QSerialPortInfo::availablePorts(); +-#endif +- +- +-void QtTermTCP::KISSSlot() +-{ +- // This runs the KISS Configuration dialog +- +- KISS = new(Ui_KISSDialog); +- +- QDialog UI; +- +- KISS->setupUi(&UI); +- +- UI.setFont(*menufont); +- +- deviceUI = &UI; +- KISS->KISSEnable->setChecked(KISSEnable); +- KISS->KISSListen->setChecked(KISSListen); +- KISS->KISSChecksum->setChecked(KISSChecksum); +- KISS->KISSACKMODE->setChecked(KISSAckMode); +- KISS->KISSMH->setChecked(KISSMH); +- KISS->MYCALL->setText(KISSMYCALL); +- +- KISS->TXDELAY->setText(QString::number(txdelay[0])); +- KISS->SetTXDelay->setChecked(sendTXDelay[0]); +- +- // connect(KISS->SerialPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); +- +- QStringList items; +- +-#ifdef USESERIAL +- +- for (const QSerialPortInfo &info : Ports) +- { +- items.append(info.portName()); +- } +- +- items.sort(); +- items.insert(0, "TCP"); +- +-#endif +- +- for (const QString &info : items) +- { +- KISS->SerialPort->addItem(info); +- } +- +- KISS->SerialPort->setCurrentIndex(KISS->SerialPort->findText(SerialPort, Qt::MatchFixedString)); +- KISS->Speed->setText(QString::number(KISSBAUD)); +- KISS->Host->setText(KISSHost); +- KISS->Port->setText(QString::number(KISSPortNum)); +- +- KISS->Paclen->setText(QString::number(kisspaclen[0])); +- KISS->Maxframe->setText(QString::number(maxframe[0])); +- KISS->Frack->setText(QString::number(frack_time[0])); +- KISS->Retries->setText(QString::number(fracks[0])); +- +- QObject::connect(KISS->okButton, SIGNAL(clicked()), this, SLOT(KISSaccept())); +- QObject::connect(KISS->cancelButton, SIGNAL(clicked()), this, SLOT(KISSreject())); +- +- UI.exec(); +- +-} +- +- +-void QtTermTCP::KISSaccept() +-{ +- QVariant Q; +- int OldEnable = KISSEnable; +- char oldSerialPort[64]; +- int OldPort = KISSPortNum; +- char oldHost[128]; +- +- strcpy(oldSerialPort, SerialPort); +- strcpy(oldHost, KISSHost); +- +- KISSEnable = KISS->KISSEnable->isChecked(); +- KISSListen = KISS->KISSListen->isChecked(); +- KISSChecksum = KISS->KISSChecksum->isChecked(); +- KISSAckMode = KISS->KISSACKMODE->isChecked(); +- KISSMH = KISS->KISSMH->isChecked(); +- actHost[18]->setVisible(KISSEnable); // Show KISS Connect Line +- +- strcpy(KISSMYCALL, KISS->MYCALL->text().toUtf8().toUpper()); +- +- memset(axMYCALL, 0, 7); +- ConvToAX25(KISSMYCALL, 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(); +- +- Q = KISS->TXDELAY->text(); +- txdelay[0] = Q.toInt(); +- sendTXDelay[0] = KISS->SetTXDelay->isChecked(); +- +- 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(); +- } +- } +- +- if (KISSEnable == 0 && MHWindow) +- { +- MHWindow->close(); +- MHWindow = 0; +- } +- +- if (KISSEnable && KISSMH && MHWindow == 0) +- { +- newMHWindow(this, 0, "KISS MH"); +- QSettings mysettings(GetConfPath(), QSettings::IniFormat); +- MHWindow->restoreGeometry(mysettings.value("MHgeometry").toByteArray()); +- } +- +- if (!KISSMH && MHWindow) +- { +- MHWindow->close(); +- MHWindow = 0; +- } +- +- +- delete(KISS); +- SaveSettings(); +- deviceUI->accept(); +- +- // QSize newSize(this->size()); +- // QSize oldSize(this->size()); +- +- // QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); +- +- // QCoreApplication::postEvent(this, myResizeEvent); +-} +- +-void QtTermTCP::KISSreject() +-{ +- delete(KISS); +- deviceUI->reject(); +-} +- +- +-void QtTermTCP::AlertSlot() +-{ +- // This runs the VARA Configuration dialog +- +- Alert = new(Ui_AlertDialog); +- +- QDialog UI; +- +- Alert->setupUi(&UI); +- +- UI.setFont(*menufont); +- +- deviceUI = &UI; +- +- Alert->Bells->setChecked(Bells); +- Alert->InboundBeep->setChecked(ConnectBeep); +- Alert->InactivityBeep->setChecked(AlertBeep); +- Alert->Interval->setText(QString::number(AlertInterval)); +- Alert->KeywordBeep->setChecked(UseKeywords); +- Alert->keywordFile->setText(KeyWordsFile); +- +- Alert->useBeep->setChecked(useBeep); +- Alert->useFiles->setChecked(!useBeep); +- +- Alert->connectFile->setCurrentText(ConnectWAV); +- Alert->bellsFile->setCurrentText(BellWAV); +- Alert->intervalFile->setCurrentText(IntervalWAV); +- Alert->keywordWAV->setCurrentText(AlertWAV); +- +- QObject::connect(Alert->chooseInbound, SIGNAL(clicked()), this, SLOT(chooseInboundWAV())); +- QObject::connect(Alert->chooseBells, SIGNAL(clicked()), this, SLOT(chooseBellsWAV())); +- QObject::connect(Alert->chooseInterval, SIGNAL(clicked()), this, SLOT(chooseIntervalWAV())); +- QObject::connect(Alert->chooseKeyAlert, SIGNAL(clicked()), this, SLOT(chooseAlertWAV())); +- +- QObject::connect(Alert->testBells, SIGNAL(clicked()), this, SLOT(testBellsWAV())); +- QObject::connect(Alert->TestInbound, SIGNAL(clicked()), this, SLOT(testInboundWAV())); +- QObject::connect(Alert->testInterval, SIGNAL(clicked()), this, SLOT(testIntervalWAV())); +- QObject::connect(Alert->TestKeyAlert, SIGNAL(clicked()), this, SLOT(testAlertWAV())); +- +- QObject::connect(Alert->okButton, SIGNAL(clicked()), this, SLOT(alertAccept())); +- QObject::connect(Alert->cancelButton, SIGNAL(clicked()), this, SLOT(alertReject())); +- +- UI.exec(); +-} +- +- +- +- +- +- +-void QtTermTCP::chooseInboundWAV() +-{ +- ConnectWAV = QFileDialog::getOpenFileName(this, +- tr("Select Wav"), "", tr("Sound Files (*.wav)")); +- +- Alert->connectFile->setCurrentText(ConnectWAV); +- +-} +- +-void QtTermTCP::chooseBellsWAV() +-{ +- BellWAV = QFileDialog::getOpenFileName(this, +- tr("Select Wav"), "", tr("Sound Files (*.wav)")); +- +- Alert->bellsFile->setCurrentText(BellWAV); +-} +- +-void QtTermTCP::chooseIntervalWAV() +-{ +- IntervalWAV = QFileDialog::getOpenFileName(this, +- tr("Select Wav"), "", tr("Sound Files (*.wav)")); +- +- Alert->intervalFile->setCurrentText(IntervalWAV); +-} +- +-void QtTermTCP::chooseAlertWAV() +-{ +- AlertWAV = QFileDialog::getOpenFileName(this, +- tr("Select Wav"), "", tr("Sound Files (*.wav)")); +- +- Alert->keywordWAV->setCurrentText(AlertWAV); +-} +- +-void QtTermTCP::testInboundWAV() +-{ +- QSound::play(Alert->connectFile->currentText()); +-} +- +-void QtTermTCP::testBellsWAV() +-{ +- QSound::play(Alert->bellsFile->currentText()); +-} +- +-void QtTermTCP::testIntervalWAV() +-{ +- QSound::play(Alert->intervalFile->currentText()); +-} +- +-void QtTermTCP::testAlertWAV() +-{ +- QSound::play(Alert->keywordWAV->currentText()); +-} +- +- +- +-void QtTermTCP::alertAccept() +-{ +- QVariant Q; +- +- useBeep = Alert->useBeep->isChecked(); +- +- Bells = Alert->Bells->isChecked(); +- ConnectBeep = Alert->InboundBeep->isChecked(); +- AlertBeep = Alert->InactivityBeep->isChecked(); +- AlertInterval = Alert->Interval->text().toInt(); +- +- UseKeywords = Alert->KeywordBeep->isChecked(); +- KeyWordsFile = Alert->keywordFile->text(); +- +- ConnectWAV = Alert->connectFile->currentText(); +- BellWAV = Alert->bellsFile->currentText(); +- IntervalWAV = Alert->intervalFile->currentText(); +- AlertWAV = Alert->keywordWAV->currentText(); +- +- delete(Alert); +- SaveSettings(); +- deviceUI->accept(); +-} +- +-void QtTermTCP::alertReject() +-{ +- delete(Alert); +- deviceUI->reject(); +-} +- +- +- +-void QtTermTCP::VARASlot() +-{ +- // This runs the VARA Configuration dialog +- +- char valChar[80]; +- +- Dev = new(Ui_Dialog); +- +- QDialog UI; +- +- Dev->setupUi(&UI); +- +- UI.setFont(*menufont); +- +- deviceUI = &UI; +- +- Dev->VARAEnable->setChecked(VARAEnable); +- Dev->TermCall->setText(VARATermCall); +- +- SetVARAParams(); +- +- connect(Dev->VARAHF, SIGNAL(toggled(bool)), this, SLOT(VARAHFChanged(bool))); +- connect(Dev->VARAFM, SIGNAL(toggled(bool)), this, SLOT(VARAFMChanged(bool))); +- connect(Dev->VARASAT, SIGNAL(toggled(bool)), this, SLOT(VARASATChanged(bool))); +- +- if (VARA500) +- Dev->VARA500->setChecked(true); +- else if (VARA2750) +- Dev->VARA2750->setChecked(true); +- else +- Dev->VARA2300->setChecked(true); +- +- if (VARAHF) +- Dev->VARAHF->setChecked(true); +- else if (VARAFM) +- Dev->VARAFM->setChecked(true); +- else if (VARASAT) +- Dev->VARASAT->setChecked(true); +- +- if (VARAHF == 0) +- Dev->HFMode->setVisible(false); +- +- connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool))); +- connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); +- +- if (PTTMode == PTTCAT) +- Dev->CAT->setChecked(true); +- else +- Dev->RTSDTR->setChecked(true); +- +- if (CATHex) +- Dev->CATHex->setChecked(true); +- else +- Dev->CATText->setChecked(true); +- +- sprintf(valChar, "%d", pttGPIOPin); +- Dev->GPIOLeft->setText(valChar); +- sprintf(valChar, "%d", pttGPIOPinR); +- Dev->GPIORight->setText(valChar); +- +- Dev->VIDPID->setText(CM108Addr); +- +- +- QStringList items; +- +-#ifdef USESERIAL +- +- for (const QSerialPortInfo &info : Ports) +- { +- items.append(info.portName()); +- } +- +- items.sort(); +- +-#endif +- +- Dev->PTTPort->addItem("None"); +- Dev->PTTPort->addItem("CM108"); +- +-#ifdef __ARM_ARCH +- +- // Dev->PTTPort->addItem("GPIO"); +- +-#endif +- +- Dev->PTTPort->addItem("FLRIG"); +- Dev->PTTPort->addItem("HAMLIB"); +- +- for (const QString &info : items) +- { +- Dev->PTTPort->addItem(info); +- } +- +- Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString)); +- +- PTTPortChanged(0); // Force reevaluation +- +- QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept())); +- QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject())); +- +- UI.exec(); +- +-} +- +-extern QProcess *process; +- +-void ClosePTTPort(); +- +-void QtTermTCP::deviceaccept() +-{ +- QVariant Q; +- +- int OldEnable = VARAEnable; +- int OldPort = VARAPortNum; +- char oldHost[128]; +- char oldPath[256]; +- +- strcpy(oldHost, VARAHost); +- strcpy(oldPath, VARAPath); +- +- VARAEnable = Dev->VARAEnable->isChecked(); +- +- strcpy(VARATermCall, Dev->TermCall->text().toUtf8().toUpper()); +- +- Q = Dev->Port->text(); +- +- VARAPortNum = Q.toInt(); +- strcpy(VARAHost, Dev->Host->text().toUtf8().toUpper()); +- strcpy(VARAPath, Dev->Path->text().toUtf8()); +- strcpy(VARAInit, Dev->InitCommands->text().toUtf8()); +- +- VARA500 = Dev->VARA500->isChecked(); +- VARA2300 = Dev->VARA2300->isChecked(); +- VARA2750 = Dev->VARA2750->isChecked(); +- +- VARAHF = Dev->VARAHF->isChecked(); +- VARAFM = Dev->VARAFM->isChecked(); +- VARASAT = Dev->VARASAT->isChecked(); +- +- if (VARAHF) +- { +- strcpy(VARAHostHF, VARAHost); +- strcpy(VARAPathHF, VARAPath); +- VARAPortHF = VARAPortNum; +- } +- else if (VARAFM) +- { +- strcpy(VARAHostFM, VARAHost); +- strcpy(VARAPathFM, VARAPath); +- VARAPortFM = VARAPortNum; +- } +- else if (VARASAT) +- { +- strcpy(VARAHostSAT, VARAHost); +- strcpy(VARAPathSAT, VARAPath); +- VARAPortSAT = VARAPortNum; +- } +- +- Q = Dev->PTTPort->currentText(); +- strcpy(PTTPort, Q.toString().toUtf8()); +- +- if (Dev->CAT->isChecked()) +- PTTMode = PTTCAT; +- else +- PTTMode = PTTRTS; +- +- if (Dev->CATHex->isChecked()) +- CATHex = 1; +- else +- CATHex = 0; +- +- Q = Dev->PTTOn->text(); +- strcpy(PTTOnString, Q.toString().toUtf8()); +- Q = Dev->PTTOff->text(); +- strcpy(PTTOffString, Q.toString().toUtf8()); +- +- Q = Dev->CATSpeed->text(); +- PTTBAUD = Q.toInt(); +- +- Q = Dev->GPIOLeft->text(); +- pttGPIOPin = Q.toInt(); +- +- Q = Dev->GPIORight->text(); +- pttGPIOPinR = Q.toInt(); +- +- Q = Dev->VIDPID->text(); +- +- if (strcmp(PTTPort, "CM108") == 0) +- strcpy(CM108Addr, Q.toString().toUtf8()); +- else if (strcmp(PTTPort, "HAMLIB") == 0) +- { +- HamLibPort = Q.toInt(); +- Q = Dev->PTTOn->text(); +- strcpy(HamLibHost, Q.toString().toUtf8()); +- } +- +- if (VARAEnable != OldEnable || VARAPortNum != OldPort || strcmp(oldHost, VARAHost) != 0) +- { +- // (re)start connection +- +- if (OldEnable && VARASock && VARASock->ConnectedState == QAbstractSocket::ConnectedState) +- { +- VARASock->disconnectFromHost(); +- if (VARADataSock) +- VARADataSock->disconnectFromHost(); +- Status2->setText("VARA Disconnected"); +- } +- } +- +- if (process && process->state() == QProcess::Running) +- if ((VARAEnable == 0 || strcmp(oldPath, VARAPath) != 0)) +- process->close(); +- +- myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable); +- +- ClosePTTPort(); +- OpenPTTPort(); +- +- delete(Dev); +- SaveSettings(); +- deviceUI->accept(); +- +- QSize newSize(this->size()); +- QSize oldSize(this->size()); +- +- QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); +- +- QCoreApplication::postEvent(this, myResizeEvent); +-} +- +-void QtTermTCP::devicereject() +-{ +- delete(Dev); +- deviceUI->reject(); +-} +- +-// This handles incoming connections +- +-void QtTermTCP::onNewConnection() +-{ +- myTcpSocket *clientSocket = (myTcpSocket *)_server->nextPendingConnection(); +- +- clientSocket->Sess = NULL; +- +- Ui_ListenSession * S; +- Ui_ListenSession * Sess = NULL; +- +- char Title[512]; +- int i = 0; +- +- QByteArray Host = clientSocket->peerAddress().toString().toUtf8(); +- +- if (TermMode == MDI) +- { +- // See if an old session can be reused +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- S = _sessions.at(i); +- +- // for (Ui_ListenSession * S: _sessions) +- // { +- if ((S->SessionType & Listen) && S->clientSocket == NULL) +- { +- Sess = S; +- break; +- } +- } +- +- // Create a window if none found, else reuse old +- +- if (Sess == NULL) +- { +- Sess = newWindow(this, Listen); +- } +- +- QByteArray Host = clientSocket->peerAddress().toString().toUtf8(); +- } +- else +- { +- // Single or Tabbed - look for free session +- +- for (i = 0; i < _sessions.size(); ++i) +- { +- S = _sessions.at(i); +- +- if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL) +- { +- Sess = S; +- break; +- } +- } +- +- if (Sess == NULL) +- { +- // Clear connection +- +- clientSocket->disconnectFromHost(); +- return; +- } +- } +- +- _sockets.push_back(clientSocket); +- +- clientSocket->Sess = Sess; +- +- // See if any data from host - first msg should be callsign +- +- clientSocket->waitForReadyRead(1000); +- +- QByteArray datas = clientSocket->readAll(); +- +- datas.chop(2); +- datas.truncate(10); // Just in case! +- +- strlop(datas.data(), 13); +- +- if (datas.data()[0] == 0) +- datas.append("UNKNOWN\0"); +- +- datas.append('\0'); +- +- sprintf(Title, "Inward Connect from %s:%d Call %s", +- Host.data(), clientSocket->peerPort(), datas.data()); +- +- if (TermMode == MDI) +- { +- Sess->setWindowTitle(Title); +- } +- else if (TermMode == Tabbed) +- { +- tabWidget->setTabText(i, datas.data()); +- tabWidget->tabBar()->setTabTextColor(i, newTabText); +- } +- +- else if (TermMode == Single) +- this->setWindowTitle(Title); +- +- connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); +- connect(clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); +- +- Sess->clientSocket = clientSocket; +- +- // We need to set Connect and Disconnect if the window is active +- +- if (TermMode == MDI && Sess->sw == ActiveSubWindow) +- setMenus(true); +- +- if (TermMode == Tabbed && Sess->Tab == tabWidget->currentIndex()) +- setMenus(true); +- +- if (TermMode == Single) +- setMenus(true); // Single +- +- // Send CText if defined +- +- if (listenCText[0]) +- Sess->clientSocket->write(listenCText); +- +- // Send Message to Terminal +- +- char Msg[80]; +- +- sprintf(Msg, "Listen Connect from %s\r\r", datas.data()); +- +- WritetoOutputWindow(Sess, (unsigned char *)Msg, (int)strlen(Msg)); +- +- if (ConnectBeep) +- myBeep(&ConnectWAV); +- +- QApplication::alert(mythis, 0); +-} +- +-void QtTermTCP::onSocketStateChanged(QAbstractSocket::SocketState socketState) +-{ +- myTcpSocket* sender = static_cast(QObject::sender()); +- Ui_ListenSession * Sess = (Ui_ListenSession *)sender->Sess; +- +- if (socketState == QAbstractSocket::UnconnectedState) +- { +- char Msg[] = "Disconnected\r"; +- +- WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), +- Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red +- +- if (TermMode == MDI) +- { +- if (Sess->SessionType == Mon) // Mon Only +- Sess->setWindowTitle("Monitor Session Disconnected"); +- else +- Sess->setWindowTitle("Disconnected"); +- } +- else if (TermMode == Tabbed) +- { +- if (Sess->SessionType == Mon) // Mon Only +- tabWidget->setTabText(Sess->Tab, "Monitor"); +- else +- { +- char Label[16]; +- sprintf(Label, "Sess %d", Sess->Tab + 1); +- tabWidget->setTabText(Sess->Tab, Label); +- } +- } +- else if (TermMode == Single) +- { +- if (Sess->AGWMonSession) +- mythis->setWindowTitle("AGW Monitor Window"); +- else +- { +- if (Sess->SessionType == Mon) // Mon Only +- this->setWindowTitle("Monitor Session Disconnected"); +- else +- this->setWindowTitle("Disconnected"); +- } +- } +- +- if (Sess->TTActive) +- { +- Sess->TTActive = 0; +- DoTermResize(Sess); +- } +- +- Sess->PortMonString[0] = 0; +- +- // delete(Sess->clientSocket); +- Sess->clientSocket = NULL; +- +- discAction->setEnabled(false); +- +- if ((Sess->SessionType & Listen)) +- _sockets.removeOne(sender); +- else +- { +- connectMenu->setEnabled(true); +- YAPPSend->setEnabled(false); +- } +- } +- else if (socketState == QAbstractSocket::ConnectedState) +- { +- char Signon[256]; +- char Title[128]; +- +- // only seems to be triggered for outward connect +- +- sprintf(Signon, "%s\r%s\rBPQTERMTCP\r", UserName[Sess->CurrentHost], Password[Sess->CurrentHost]); +- +- Sess->clientSocket->write(Signon); +- +- discAction->setEnabled(true); +- YAPPSend->setEnabled(true); +- connectMenu->setEnabled(false); +- +- SendTraceOptions(Sess); +- +- Sess->InputMode = 0; +- Sess->SlowTimer = 0; +- Sess->MonData = 0; +- Sess->OutputSaveLen = 0; // Clear any part line +- Sess->MonSaveLen = 0; // Clear any part line +- +- if (Sess->SessionType == Mon) // Mon Only +- sprintf(Title, "Monitor Session Connected to %s", Host[Sess->CurrentHost]); +- else +- { +- char Label[256]; +- +- if (SessName[Sess->CurrentHost][0]) +- sprintf(Label, "%s(%s)", Host[Sess->CurrentHost], SessName[Sess->CurrentHost]); +- else +- strcpy(Label, Host[Sess->CurrentHost]); +- +- sprintf(Title, "Connected to %s", Label); +- } +- +- if (TermMode == MDI) +- Sess->setWindowTitle(Title); +- else if (TermMode == Tabbed) +- { +- if (SessName[Sess->CurrentHost][0]) +- tabWidget->setTabText(Sess->Tab, SessName[Sess->CurrentHost]); +- else +- tabWidget->setTabText(Sess->Tab, Host[Sess->CurrentHost]); +- } +- else if (TermMode == Single) +- this->setWindowTitle(Title); +- } +-} +- +-void QtTermTCP::updateWindowMenu() +-{ +- if (TermMode == MDI) +- { +- windowMenu->clear(); +- windowMenu->addAction(newTermAct); +- windowMenu->addAction(newMonAct); +- windowMenu->addAction(newCombinedAct); +- windowMenu->addSeparator(); +- windowMenu->addAction(closeAct); +- windowMenu->addAction(closeAllAct); +- windowMenu->addSeparator(); +- windowMenu->addAction(tileAct); +- windowMenu->addAction(cascadeAct); +- windowMenu->addSeparator(); +- windowMenu->addAction(nextAct); +- windowMenu->addAction(previousAct); +- windowMenu->addAction(quitAction); +- windowMenu->addAction(windowMenuSeparatorAct); +- +- QList windows = mdiArea->subWindowList(); +- windowMenuSeparatorAct->setVisible(!windows.isEmpty()); +- +- Ui_ListenSession * Sess; +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- Sess->actActivate = windowMenu->addAction(Sess->sw->windowTitle()); +- QAction::connect(Sess->actActivate, SIGNAL(triggered()), this, SLOT(actActivate())); +- Sess->actActivate->setCheckable(true); +- Sess->actActivate->setChecked(ActiveSubWindow == Sess->sw); +- } +- } +- else if (TermMode == Tabbed) +- { +- windowMenu->clear(); +- +- Ui_ListenSession * Sess = (Ui_ListenSession *)tabWidget->currentWidget(); +- +- QActionGroup * termGroup = new QActionGroup(this); +- +- delete(TabSingle); +- delete(TabBoth); +- delete(TabMon); +- +- TabSingle = setupMenuLine(nullptr, (char *)"Terminal Only", this, (Sess->SessionType == Term)); +- TabBoth = setupMenuLine(nullptr, (char *)"Terminal + Monitor", this, (Sess->SessionType == Term + Mon)); +- TabMon = setupMenuLine(nullptr, (char *)"Monitor Only", this, (Sess->SessionType == Mon)); +- +- termGroup->addAction(TabSingle); +- termGroup->addAction(TabBoth); +- termGroup->addAction(TabMon); +- +- windowMenu->addAction(TabSingle); +- windowMenu->addAction(TabBoth); +- windowMenu->addAction(TabMon); +- +- } +-} +- +-Ui_ListenSession::~Ui_ListenSession() +-{ +- if (this->clientSocket) +- { +- int loops = 100; +- this->clientSocket->disconnectFromHost(); +- while (loops-- && this->clientSocket->state() != QAbstractSocket::UnconnectedState) +- QThread::msleep(10); +- } +-} +- +-extern "C" void setTraceOff(Ui_ListenSession * Sess) +-{ +- if ((Sess->SessionType & Mon) == 0) +- return; // Not Monitor +- +- if (Sess->AGWMonSession) +- return; +- +- char Buffer[80]; +- int Len = sprintf(Buffer, "\\\\\\\\0 0 0 0 0 0 0 0\r"); +- +- SocketFlush(Sess); +- SocketSend(Sess, Buffer, Len); +- SocketFlush(Sess); +-} +- +- +-extern "C" void SendTraceOptions(Ui_ListenSession * Sess) +-{ +- if ((Sess->SessionType & Mon) == 0) +- return; // Not Monitor +- +- if (Sess->AGWMonSession) +- return; +- +- char Buffer[80]; +- int Len = sprintf(Buffer, "\\\\\\\\%llx %x %x %x %x %x %x %x\r", Sess->portmask, Sess->mtxparam | (Sess->mlocaltime << 7), +- Sess->mcomparam, Sess->MonitorNODES, Sess->MonitorColour, Sess->monUI, 0, 1); +- +- strcpy(&MonParams[Sess->CurrentHost][0], &Buffer[4]); +- SaveSettings(); +- SocketFlush(Sess); +- SocketSend(Sess, Buffer, Len); +- SocketFlush(Sess); +-} +- +-void QtTermTCP::doNewTerm() +-{ +- newWindow(this, Term); +-} +- +-void QtTermTCP::doNewMon() +-{ +- newWindow(this, Mon); +-} +- +-void QtTermTCP::doNewCombined() +-{ +- newWindow(this, Term + Mon); +-} +- +-void QtTermTCP::doCascade() +-{ +- // Qt Cascade Minimizes windows so do it ourselves +- +- int x = 0, y = 0; +- +- Ui_ListenSession * Sess; +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- Sess->sw->move(x, y); +- x += 14; +- y += 30; +- } +-} +- +-void QtTermTCP::actActivate() +-{ +- QAction * sender = static_cast(QObject::sender()); +- +- Ui_ListenSession * Sess; +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->actActivate == sender) +- { +- mdiArea->setActiveSubWindow(Sess->sw); +- return; +- } +- } +-} +- +- +-void QtTermTCP::xon_mdiArea_changed() +-{ +- // This is triggered when the Active MDI window changes +- // and is used to enable/disable Connect, Disconnect and YAPP Send +- +- +- QMdiSubWindow *SW = mdiArea->activeSubWindow(); +- +- // Dont waste time if not changed +- +- if (ActiveSubWindow == SW) +- return; +- +- ActiveSubWindow = SW; +- +- Ui_ListenSession * Sess; +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- // for (Ui_ListenSession * Sess : _sessions) +- // { +- if (Sess->sw == SW) +- { +- ActiveSession = Sess; +- +- if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) +- { +- discAction->setEnabled(true); +- YAPPSend->setEnabled(true); +- connectMenu->setEnabled(false); +- } +- else if (Sess->AGWMonSession) +- { +- // Connected AGW Monitor Session +- +- discAction->setEnabled(false); +- YAPPSend->setEnabled(false); +- connectMenu->setEnabled(false); +- } +- else if (Sess->AGWSession || Sess->KISSSession) +- { +- // Connected AGW or KISS Terminal Session +- +- discAction->setEnabled(true); +- YAPPSend->setEnabled(true); +- connectMenu->setEnabled(false); +- } +- else +- { +- // Not connected +- +- discAction->setEnabled(false); +- YAPPSend->setEnabled(false); +- +- if ((Sess->SessionType & Listen)) // Listen Sessions can't connect +- connectMenu->setEnabled(false); +- else +- connectMenu->setEnabled(true); +- } +- +- // If a monitor Window, change Monitor config settings +- +- EnableMonLog->setChecked(Sess->LogMonitor); +- +- if (AGWUsers && Sess == AGWUsers->MonSess) // AGW Monitor +- { +- for (int i = 0; i < 64; i++) +- SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden +- +- connectMenu->setEnabled(false); +- MonTX->setVisible(0); +- MonSup->setVisible(0); +- MonUI->setVisible(0); +- MonColour->setVisible(0); +- +- EnableMonitor->setVisible(1); +- EnableMonitor->setChecked(AGWMonEnable); +- +- MonLocalTime->setChecked(Sess->mlocaltime); +- MonNodes->setChecked(Sess->MonitorNODES); +- } +- else if (Sess == KISSMonSess) // KISS Monitor +- { +- for (int i = 0; i < 64; i++) +- SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden +- +- connectMenu->setEnabled(false); +- MonTX->setVisible(0); +- MonSup->setVisible(0); +- MonUI->setVisible(0); +- MonColour->setVisible(0); +- +- EnableMonitor->setVisible(1); +- EnableMonitor->setChecked(KISSMonEnable); +- MonLocalTime->setChecked(Sess->mlocaltime); +- MonNodes->setChecked(Sess->MonitorNODES); +- } +- +- else +- { +- EnableMonitor->setVisible(0); +- MonTX->setVisible(1); +- MonSup->setVisible(1); +- MonUI->setVisible(1); +- MonColour->setVisible(1); +- } +- +- if (Sess->PortMonString[0]) +- { +- char * ptr = (char *)malloc(2048); +- memcpy(ptr, Sess->PortMonString, 2048); +- +- int NumberofPorts = atoi((char *)&ptr[2]); +- char *p, *Context; +- char msg[80]; +- int portnum; +- char delim[] = "|"; +- +- // Remove old Monitor menu +- +- for (int i = 0; i < 64; i++) +- { +- SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden +- } +- +- p = strtok_s((char *)&ptr[2], delim, &Context); +- +- while (NumberofPorts--) +- { +- p = strtok_s(NULL, delim, &Context); +- if (p == NULL) +- break; +- +- portnum = atoi(p); +- +- sprintf(msg, "Port %s", p); +- +- if (portnum == 0) +- portnum = 64; +- +- if (Sess->portmask & (1ll << (portnum - 1))) +- SetPortMonLine(portnum, msg, 1, 1); +- else +- SetPortMonLine(portnum, msg, 1, 0); +- } +- free(ptr); +- +- MonLocalTime->setChecked(Sess->mlocaltime); +- MonTX->setChecked(Sess->mtxparam); +- MonSup->setChecked(Sess->mcomparam); +- MonUI->setChecked(Sess->monUI); +- MonNodes->setChecked(Sess->MonitorNODES); +- MonColour->setChecked(Sess->MonitorColour); +- +- } +- +- return; +- } +- } +-} +- +-void QtTermTCP::doFonts() +-{ +- fontDialog * xx = new fontDialog(0); +- xx->exec(); +-} +- +-void QtTermTCP::doMFonts() +-{ +- fontDialog * xx = new fontDialog(1); +- xx->exec(); +-} +- +-QColor TempmonBackground = monBackground; +-QColor TemptermBackground = termBackground; +-QColor TempinputBackground = inputBackground; +- +-QColor TempmonRxText = monRxText; +-QColor TempmonTxText = monTxText; +-QColor TempmonOtherText = monOtherText; +- +-QColor TempoutputText = outputText; +-QColor TempEchoText = EchoText; +-QColor TempWarningText = WarningText; +- +- +-QColor TempinputText = inputText; +- +- +-void setDialogColours() +-{ +- char monStyle[128]; +- +- sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", +- TempmonOtherText.red(), TempmonOtherText.green(), TempmonOtherText.blue(), +- TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); +- +- COLOURS->MonitorBG->setStyleSheet(monStyle); +- COLOURS->MonOther->setStyleSheet(monStyle); +- +- sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", +- TempmonTxText.red(), TempmonTxText.green(), TempmonTxText.blue(), +- TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); +- COLOURS->MonTX->setStyleSheet(monStyle); +- +- sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", +- TempmonRxText.red(), TempmonRxText.green(), TempmonRxText.blue(), +- TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); +- +- COLOURS->MonRX->setStyleSheet(monStyle); +- +- sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", +- TempoutputText.red(), TempoutputText.green(), TempoutputText.blue(), +- TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); +- +- COLOURS->TermBG->setStyleSheet(monStyle); +- COLOURS->TermNormal->setStyleSheet(monStyle); +- +- sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", +- TempEchoText.red(), TempEchoText.green(), TempEchoText.blue(), +- TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); +- +- COLOURS->Echoed->setStyleSheet(monStyle); +- +- sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", +- TempWarningText.red(), TempWarningText.green(), TempWarningText.blue(), +- TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); +- +- COLOURS->Warning->setStyleSheet(monStyle); +- +- sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", +- TempinputText.red(), TempinputText.green(), TempinputText.blue(), +- TempinputBackground.red(), TempinputBackground.green(), TempinputBackground.blue()); +- +- COLOURS->InputBG->setStyleSheet(monStyle); +- COLOURS->InputColour->setStyleSheet(monStyle); +- +-} +- +-void QtTermTCP::doColours() +-{ +- COLOURS = new(Ui_ColourDialog); +- +- QDialog UI; +- +- COLOURS->setupUi(&UI); +- +- UI.setFont(*menufont); +- +- deviceUI = &UI; +- +- TempmonBackground = monBackground; +- TempmonRxText = monRxText; +- TempmonTxText = monTxText; +- TempmonOtherText = monOtherText; +- +- TemptermBackground = termBackground; +- TempoutputText = outputText; +- TempEchoText = EchoText; +- TempWarningText = WarningText; +- +- TempinputBackground = inputBackground; +- TempinputText = inputText; +- +- setDialogColours(); +- +- QObject::connect(COLOURS->MonitorBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- QObject::connect(COLOURS->TermBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- QObject::connect(COLOURS->InputBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- QObject::connect(COLOURS->MonRX, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- QObject::connect(COLOURS->MonTX, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- QObject::connect(COLOURS->MonOther, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- QObject::connect(COLOURS->TermNormal, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- QObject::connect(COLOURS->Echoed, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- QObject::connect(COLOURS->Warning, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- QObject::connect(COLOURS->InputColour, SIGNAL(clicked()), this, SLOT(ColourPressed())); +- +- QObject::connect(COLOURS->okButton, SIGNAL(clicked()), this, SLOT(Colouraccept())); +- QObject::connect(COLOURS->cancelButton, SIGNAL(clicked()), this, SLOT(Colourreject())); +- +- UI.exec(); +- +-} +- +-void QtTermTCP::ColourPressed() +-{ +- char Name[32]; +- +- strcpy(Name, sender()->objectName().toUtf8()); +- +- if (strcmp(Name, "MonitorBG") == 0) +- TempmonBackground = setColor(TempmonBackground); +- +- else if (strcmp(Name, "MonTX") == 0) +- TempmonTxText = setColor(TempmonTxText); +- +- else if (strcmp(Name, "MonRX") == 0) +- TempmonRxText = setColor(TempmonRxText); +- +- else if (strcmp(Name, "MonOther") == 0) +- TempmonOtherText = setColor(TempmonOtherText); +- +- else if (strcmp(Name, "TermBG") == 0) +- TemptermBackground = setColor(TemptermBackground); +- +- else if (strcmp(Name, "InputBG") == 0) +- TempinputBackground = setColor(TempinputBackground); +- +- else if (strcmp(Name, "InputColour") == 0) +- TempinputText = setColor(TempinputText); +- +- else if (strcmp(Name, "TermNormal") == 0) +- TempoutputText = setColor(TempoutputText); +- +- else if (strcmp(Name, "Echoed") == 0) +- TempEchoText = setColor(TempEchoText); +- +- else if (strcmp(Name, "Warning") == 0) +- TempWarningText = setColor(TempWarningText); +- +- setDialogColours(); +-} +- +- +-void QtTermTCP::Colouraccept() +-{ +- monBackground = TempmonBackground; +- monRxText = TempmonRxText; +- monTxText = TempmonTxText; +- monOtherText = TempmonOtherText; +- +- termBackground = TemptermBackground; +- EchoText = TempEchoText; +- WarningText = TempWarningText; +- outputText = TempoutputText; +- +- inputBackground = TempinputBackground; +- inputText = TempinputText; +- +- // Set background colour for new windows +- +- sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);", +- monBackground.red(), monBackground.green(), monBackground.blue()); +- +- sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);", +- termBackground.red(), termBackground.green(), termBackground.blue()); +- +- sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", +- inputText.red(), inputText.green(), inputText.blue(), +- inputBackground.red(), inputBackground.green(), inputBackground.blue()); +- +- // Update existing windows +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Ui_ListenSession * S = _sessions.at(i); +- +- if (S->monWindow) +- S->monWindow->setStyleSheet(monStyleSheet); +- +- if (S->termWindow) +- S->termWindow->setStyleSheet(termStyleSheet); +- +- if (S->inputWindow) +- S->inputWindow->setStyleSheet(inputStyleSheet); +- +- } +- +- +- delete(COLOURS); +- +- SaveSettings(); +- deviceUI->accept(); +-} +- +-void QtTermTCP::Colourreject() +-{ +- delete(COLOURS); +- deviceUI->reject(); +-} +- +- +-void QtTermTCP::ConnecttoVARA() +-{ +- +- delete(VARASock); +- +- VARASock = new myTcpSocket(); +- +- connect(VARASock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(VARAdisplayError(QAbstractSocket::SocketError))); +- connect(VARASock, SIGNAL(readyRead()), this, SLOT(VARAreadyRead())); +- connect(VARASock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onVARASocketStateChanged(QAbstractSocket::SocketState))); +- +- VARASock->connectToHost(VARAHost, VARAPortNum); +- +- Status2->setText("VARA Control Connecting"); +- +- return; +-} +- +- +-void QtTermTCP::VARATimer() +-{ +- // Runs every 10 Seconds +- +- if (VARAConnected == 0 && VARAConnecting == 0) +- { +- if (process == nullptr || process->state() == QProcess::NotRunning) +- { +- if (VARAPath[0]) +- { +- process = new QProcess(this); +- QString file = VARAPath; +- process->start(file); +- } +- } +- QThread::msleep(1000); +- VARAConnecting = true; +- ConnecttoVARA(); +- } +-} +- +- +-void QtTermTCP::VARAdisplayError(QAbstractSocket::SocketError socketError) +-{ +- switch (socketError) +- { +- case QAbstractSocket::RemoteHostClosedError: +- break; +- +- case QAbstractSocket::HostNotFoundError: +- QMessageBox::information(this, tr("QtTermTCP"), +- tr("VARA host was not found. Please check the " +- "host name and portsettings->")); +- +- Status2->setText("VARA Connection Failed"); +- +- break; +- +- case QAbstractSocket::ConnectionRefusedError: +- +- Status2->setText("VARA Connection Refused"); +- break; +- +- default: +- +- Status2->setText("VARA Connection Failed"); +- } +- +- VARAConnecting = 0; +- VARAConnected = 0; +-} +- +-void QtTermTCP::VARAreadyRead() +-{ +- int Read; +- char Buffer[4096]; +- char * ptr; +- char * Msg; +- myTcpSocket* Socket = static_cast(QObject::sender()); +- +- // read the data from the socket +- +- Read = Socket->read((char *)Buffer, 4095); +- +- Buffer[Read] = 0; +- +- Msg = Buffer; +- +- ptr = strchr(Msg, 0x0d); +- +- while (ptr) +- { +- *ptr++ = 0; +- +- if (strcmp(Msg, "IAMALIVE") == 0) +- { +- } +- else if (strcmp(Msg, "PTT ON") == 0) +- { +- RadioPTT(1); +- } +- else if (strcmp(Msg, "PTT OFF") == 0) +- { +- RadioPTT(0); +- } +- else if (strcmp(Msg, "PENDING") == 0) +- { +- } +- else if (strcmp(Msg, "CANCELPENDING") == 0) +- { +- } +- else if (strcmp(Msg, "OK") == 0) +- { +- } +- else if (memcmp(Msg, "CONNECTED ", 10) == 0) +- { +- Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess; +- char Title[128] = ""; +- char CallFrom[64] = ""; +- char CallTo[64] = ""; +- char Mode[64] = ""; +- char Message[128]; +- int n; +- +- +- sscanf(&Msg[10], "%s %s %s", CallFrom, CallTo, Mode); +- +- if (Sess) +- { +- if (Mode[0]) +- sprintf(Title, "Connected to %s %s Mode", CallTo, Mode); +- else +- sprintf(Title, "Connected to %s", CallTo); +- +- n = sprintf(Message, "%s\r\n", Title); +- WritetoOutputWindow(Sess, (unsigned char *)Message, n); +- +- if (TermMode == MDI) +- Sess->setWindowTitle(Title); +- else if (TermMode == Tabbed) +- tabWidget->setTabText(Sess->Tab, CallTo); +- else if (TermMode == Single) +- mythis->setWindowTitle(Title); +- +- setMenus(true); +- } +- else +- { +- // Incoming Call +- +- Ui_ListenSession * S; +- int i = 0; +- +- if (TermMode == MDI) +- { +- // See if an old session can be reused +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- S = _sessions.at(i); +- +- // for (Ui_ListenSession * S: _sessions) +- // { +- if ((S->SessionType & Listen) && S->clientSocket == NULL) +- { +- Sess = S; +- break; +- } +- } +- +- // Create a window if none found, else reuse old +- +- if (Sess == NULL) +- { +- Sess = newWindow(this, Listen); +- } +- } +- else +- { +- // Single or Tabbed - look for free session +- +- for (i = 0; i < _sessions.size(); ++i) +- { +- S = _sessions.at(i); +- +- if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL) +- { +- Sess = S; +- break; +- } +- } +- } +- +- if (Sess == NULL) +- { +- // Clear connection +- +- VARASock->write("DISCONNECT\r"); +- } +- else +- { +- if (Mode[0]) +- { +- sprintf(Title, "Connected to %s Mode %s", CallFrom, Mode); +- n = sprintf(Message, "Incoming VARA Connect from %s %s Mode\r\n", CallFrom, Mode); +- } +- else +- { +- sprintf(Title, "Connected to %s", CallFrom); +- n = sprintf(Message, "Incoming VARA Connect from %s\r\n", CallFrom); +- } +- +- WritetoOutputWindow(Sess, (unsigned char *)Message, n); +- +- VARASock->Sess = Sess; +- VARADataSock->Sess = Sess; +- +- if (TermMode == MDI) +- Sess->setWindowTitle(Title); +- else if (TermMode == Tabbed) +- { +- tabWidget->setTabText(Sess->Tab, CallFrom); +- tabWidget->tabBar()->setTabTextColor(Sess->Tab, newTabText); +- } +- else if (TermMode == Single) +- mythis->setWindowTitle(Title); +- +- setMenus(true); +- +- if (ConnectBeep) +- myBeep(&ConnectWAV); +- +- if (listenCText[0]) +- VARADataSock->write(listenCText); +- +- QApplication::alert(mythis, 0); +- +- } +- } +- } +- else if (strcmp(Msg, "DISCONNECTED") == 0) +- { +- Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess; +- +- if (Sess) +- { +- WritetoOutputWindow(Sess, (unsigned char *)"Disconnected\r\n", 14); +- VARASock->Sess = 0; +- VARADataSock->Sess = 0; +- +- if (TermMode == MDI) +- { +- if (Sess->SessionType == Mon) // Mon Only +- Sess->setWindowTitle("Monitor Session Disconnected"); +- else +- Sess->setWindowTitle("Disconnected"); +- } +- else if (TermMode == Tabbed) +- { +- if (Sess->SessionType == Mon) // Mon Only +- tabWidget->setTabText(Sess->Tab, "Monitor"); +- else +- { +- char Label[16]; +- sprintf(Label, "Sess %d", Sess->Tab + 1); +- tabWidget->setTabText(Sess->Tab, Label); +- } +- } +- else if (TermMode == Single) +- { +- if (Sess->AGWMonSession) +- mythis->setWindowTitle("AGW Monitor Window"); +- else +- { +- if (Sess->SessionType == Mon) // Mon Only +- this->setWindowTitle("Monitor Session Disconnected"); +- else +- this->setWindowTitle("Disconnected"); +- } +- } +- +- setMenus(false); +- } +- } +- +- Msg = ptr; +- +- ptr = strchr(Msg, 0x0d); +- } +- +- +- +-} +- +-void QtTermTCP::onVARASocketStateChanged(QAbstractSocket::SocketState socketState) +-{ +- // myTcpSocket* sender = static_cast(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 +-} +- +-#ifndef ANDRIOD +- +-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; +- +-} +- +-#endif +- +-void QtTermTCP::RadioPTT(bool PTTState) +-{ +-#ifdef __ARM_ARCH +- if (useGPIO) +- { +- // gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); +- // return; +- } +- +-#endif +- +- if ((PTTMode & PTTCM108)) +- { +- CM108_set_ptt(PTTState); +- return; +- } +- +- if ((PTTMode & PTTHAMLIB)) +- { +- HAMLIBSetPTT(PTTState); +- return; +- } +- +- if ((PTTMode & PTTFLRIG)) +- { +- FLRigSetPTT(PTTState); +- return; +- } +- +-#ifdef USESERIAL +- +- if (hPTTDevice == 0) +- return; +- +- if ((PTTMode & PTTCAT)) +- { +- if (PTTState) +- hPTTDevice->write((char *)PTTOnCmd, PTTOnCmdLen); +- else +- hPTTDevice->write((char *)PTTOffCmd, PTTOffCmdLen); +- +- hPTTDevice->flush(); +- // hPTTDevice->error(); +- return; +- +- } +- +- +- if ((PTTMode & PTTRTS)) +- { +- int n = hPTTDevice->setRequestToSend(PTTState); +- n = n; +- } +- +-#endif +- +-} +- +- +- +-extern "C" void WriteDebugLog(char * Mess) +-{ +- qDebug() << Mess; +-} +- +-void QtTermTCP::ConnecttoKISS() +-{ +- if (strcmp(SerialPort, "TCP") == 0) +- { +- delete(KISSSock); +- +- KISSSock = new myTcpSocket(); +- KISSSockCopy[0] = (void *)KISSSock; +- +- +- connect(KISSSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(KISSdisplayError(QAbstractSocket::SocketError))); +- connect(KISSSock, SIGNAL(readyRead()), this, SLOT(KISSreadyRead())); +- connect(KISSSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onKISSSocketStateChanged(QAbstractSocket::SocketState))); +- +- KISSSock->connectToHost(KISSHost, KISSPortNum); +- +- Status3->setText("KISS Connecting"); +- } +- else +- openSerialPort(); +- +- return; +-} +- +- +-void QtTermTCP::KISSTimer() +-{ +- // Runs every 10 Seconds +- +- if (KISSConnected == 0 && KISSConnecting == 0) +- { +- ConnecttoKISS(); +- } +- else +- { +- // Verify Serial port is still ok +- +- if (m_serial && KISSConnected) +- { +- m_serial->clearError(); +- boolean rc = m_serial->isDataTerminalReady(); +- +- if (m_serial->error()) +- { +- Debugprintf("Serial Port Lost - isOpen %d Error %d", m_serial->isOpen(), m_serial->error()); +- closeSerialPort(); +- } +- } +- } +-} +- +- +- +-void QtTermTCP::KISSdisplayError(QAbstractSocket::SocketError socketError) +-{ +- switch (socketError) +- { +- case QAbstractSocket::RemoteHostClosedError: +- break; +- +- case QAbstractSocket::HostNotFoundError: +- QMessageBox::information(this, tr("QtTermTCP"), +- tr("KISS host was not found. Please check the " +- "host name and portsettings->")); +- +- Status3->setText("KISS Connection Failed"); +- +- break; +- +- case QAbstractSocket::ConnectionRefusedError: +- +- Status3->setText("KISS Connection Refused"); +- break; +- +- default: +- +- Status3->setText("KISS Connection Failed"); +- } +- +- KISSConnecting = 0; +- KISSConnected = 0; +-} +- +- +-extern "C" void KISSSendtoServer(myTcpSocket* Socket, char * Data, int Length) +-{ +- if (m_serial) +- { +- if (m_serial->isOpen()) +- { +- m_serial->clearError(); +- +- int n = m_serial->write(Data, Length); +- +- n = m_serial->flush(); +- +- if (m_serial->error()) +- { +- Debugprintf("Serial Flush Error - Requested = %d Actual %d Error %d", Length, n, m_serial->error()); +- closeSerialPort(); +- } +- } +- } +- else if (Socket) +- Socket->write(Data, Length); +-} +- +- +- +-void QtTermTCP::KISSreadyRead() +-{ +- int Read; +- unsigned char Buffer[4096]; myTcpSocket* Socket = static_cast(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); +- +- // send TXDelay if enabled +- +- if (sendTXDelay[0]) +- { +- unsigned char Msg[5] = { FEND, 1, 25 , FEND }; +- +- Msg[2] = txdelay[0] / 10; +- KISSSock->write((char *)Msg, 4); +- } +- +- // Attach a Monitor Window if available +- +- Ui_ListenSession * Sess = NULL; +- Ui_ListenSession * S; +- +- if (TermMode == MDI) +- { +- // See if an old session can be reused +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- S = _sessions.at(i); +- +- // for (Ui_ListenSession * S: _sessions) +- // { +- if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) +- { +- Sess = S; +- break; +- } +- } +- +- // Create a window if none found, else reuse old +- +- if (Sess == NULL) +- { +- Sess = newWindow((QObject *)mythis, Mon, ""); +- } +- } +- else if (TermMode == Tabbed) +- { +- // Tabbed - look for free session +- +- for (i = 8; i; i--) +- { +- S = _sessions.at(i); +- +- if (S->clientSocket == NULL && S->KISSSession == NULL && S->AGWSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) +- { +- Sess = S; +- break; +- } +- } +- } +- else if (TermMode == Single && (singlemodeFormat & Mon)) +- { +- S = _sessions.at(0); +- +- if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) +- Sess = S; +- +- } +- +- if (Sess) +- { +- KISSMonSess = Sess; // Flag as in use +- +- if (TermMode == MDI) +- Sess->setWindowTitle("KISS Monitor Window"); +- else if (TermMode == Tabbed) +- tabWidget->setTabText(Sess->Tab, "KISS Mon"); +- else if (TermMode == Single) +- mythis->setWindowTitle("KISS Monitor Window"); +- +- Sess->mlocaltime = KISSLocalTime; +- Sess->MonitorNODES = KISSMonNodes; +- +- // if (TermMode == Single) +- // { +- // discAction->setEnabled(false); +- // YAPPSend->setEnabled(false); +- // connectMenu->setEnabled(false); +- // } +- } +- } +-} +- +- +-extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat); +-extern "C" char * ShortDateTime(); +- +-extern "C" void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded) +-{ +- UNUSED(excluded); +- UNUSED(snd_ch); +- +- int Len; +- char Msg[1024]; +- +- if (tx) +- sprintf(Msg, "\x1b\x10%s", frame_monitor(frame, code, tx)); +- else +- sprintf(Msg, "\x1b\x11%s", frame_monitor(frame, code, tx)); +- +- Len = strlen(Msg); +- +- if (Len < 10) // Suppressed NODES +- return; +- +- if (Msg[Len - 1] != '\r') +- { +- Msg[Len++] = '\r'; +- Msg[Len] = 0; +- } +- +- if (KISSMonSess) +- WritetoMonWindow(KISSMonSess, (unsigned char *)Msg, Len); +- +-} +- +-extern "C" Ui_ListenSession * ax25IncomingConnect(TAX25Port * AX25Sess) +-{ +- // Look for/create Terminal Window for connection +- +- Ui_ListenSession * Sess = NULL; +- Ui_ListenSession * S; +- char Title[80]; +- int i = 0; +- +- if (TermMode == MDI) +- { +- // See if an old session can be reused +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- S = _sessions.at(i); +- +- if ((S->SessionType & Listen) && S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) +- { +- Sess = S; +- break; +- } +- } +- +- // Create a window if none found, else reuse old +- +- if (Sess == NULL) +- { +- Sess = newWindow((QObject *)mythis, Listen, ""); +- } +- } +- else +- { +- // Single or Tabbed - look for free session +- +- +- for (i = 0; i < _sessions.size(); ++i) +- { +- S = _sessions.at(i); +- +- if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) +- { +- Sess = S; +- break; +- } +- } +- +- if (Sess == NULL) +- { +- // Clear connection +- +- return NULL; +- } +- } +- +- if (Sess) +- { +- sprintf(Title, "Connected to %s", AX25Sess->corrcall); +- +- if (TermMode == MDI) +- { +- Sess->setWindowTitle(Title); +- } +- else if (TermMode == Tabbed) +- { +- tabWidget->setTabText(i, AX25Sess->corrcall); +- tabWidget->tabBar()->setTabTextColor(i, newTabText); +- } +- else if (TermMode == Single) +- mythis->setWindowTitle(Title); +- +- AX25Sess->port = 0; +- AX25Sess->Sess = Sess; // Crosslink KISS and Term Sessions +- AX25Sess->PID = 240;; +- +- Sess->KISSSession = AX25Sess; +- +- setMenus(true); +- +- if (ConnectBeep) +- myBeep(&ConnectWAV); +- +- QApplication::alert(mythis, 0); +- +- // Send CText if defined +- +- if (listenCText[0]) +- SendtoAX25(Sess->KISSSession, (unsigned char *)listenCText, (int)strlen(listenCText)); +- } +- return Sess; +-} +- +- +-extern "C" void AX25_disc(TAX25Port * AX25Sess, Byte mode) +-{ +- char Msg[128]; +- int Len = 0; +- Ui_ListenSession * Sess = (Ui_ListenSession *)AX25Sess->Sess; +- +- if (AX25Sess->status == STAT_TRY_LINK) +- { +- // Connect failed +- +- Len = sprintf(Msg, "Connection to %s failed\r", AX25Sess->corrcall); +- } +- else +- { +- switch (mode) +- { +- case MODE_OTHER: +- case MODE_OUR: +- +- Len = sprintf(Msg, "Disconnected from %s\r", AX25Sess->corrcall); +- break; +- +- case MODE_RETRY: +- +- Len = sprintf(Msg, "Disconnected from %s - Retry count exceeded\r", AX25Sess->corrcall); +- break; +- +- }; +- } +- +- SendtoTerm(Sess, Msg, Len); +- ClearSessLabel(Sess); +- Sess->KISSSession = NULL; +- AX25Sess->Sess = 0; +- +- setMenus(0); +-}; +- +-int QtTermTCP::openSerialPort() +-{ +- if (m_serial && m_serial->isOpen()) +- { +- m_serial->close(); +- } +- +- m_serial = nullptr; +- m_serial = new QSerialPort(this); +- +- m_serial->setPortName(SerialPort); +- boolean ok = m_serial->setBaudRate(KISSBAUD); +- +- if (m_serial->open(QIODevice::ReadWrite)) +- { +- int i; +- +- ok = m_serial->setRequestToSend(true); +- +- connect(m_serial, &QSerialPort::readyRead, this, &QtTermTCP::readSerialData); +- // connect(m_serial, &QSerialPort::errorOccurred, this, &QtTermTCP::handleError); +- +- KISSConnected = 1; +- KISSConnecting = 0; +- +- Status3->setText("KISS Connected"); +- actHost[18]->setEnabled(1); // Enable KISS Connect Line +- +- KISS_add_stream(m_serial); +- +- // send TXDelay if enabled +- +- if (sendTXDelay[0]) +- { +- unsigned char Msg[5] = { FEND, 1, 25 , FEND }; +- +- Msg[2] = txdelay[0] / 10; +- m_serial->write((char *)Msg, 4); +- } +- +- // Attach a Monitor Window if available +- +- Ui_ListenSession * Sess = NULL; +- Ui_ListenSession * S; +- +- if (TermMode == MDI) +- { +- // See if an old session can be reused +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- S = _sessions.at(i); +- +- // for (Ui_ListenSession * S: _sessions) +- // +- if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL) +- { +- Sess = S; +- break; +- } +- } +- +- // Create a window if none found, else reuse old +- +- if (Sess == NULL) +- { +- Sess = newWindow((QObject *)mythis, Mon, ""); +- } +- } +- else if (TermMode == Tabbed) +- { +- // Tabbed - look for free session +- +- for (i = 8; i; i--) +- { +- S = _sessions.at(i); +- +- if (S->clientSocket == NULL && S->KISSSession == NULL) +- { +- Sess = S; +- break; +- } +- } +- } +- else if (TermMode == Single && (singlemodeFormat & Mon)) +- { +- S = _sessions.at(0); +- +- if (S->clientSocket == NULL && S->KISSSession == NULL) +- Sess = S; +- +- } +- +- if (Sess) +- { +- KISSMonSess = Sess; // Flag as in use +- +- if (TermMode == MDI) +- Sess->setWindowTitle("KISS Monitor Window"); +- else if (TermMode == Tabbed) +- tabWidget->setTabText(Sess->Tab, "KISS Mon"); +- else if (TermMode == Single) +- mythis->setWindowTitle("KISS Monitor Window"); +- +- // if (TermMode == Single) +- // { +- // discAction->setEnabled(false); +- // YAPPSend->setEnabled(false); +- // connectMenu->setEnabled(false); +- // } +- } +- +- +- +- return 1; +- } +- else +- { +- Status3->setText("KISS Open Failed"); +- KISSConnected = 0; +- KISSConnecting = 0; +- return 0; +- } +-} +- +- +- +-void closeSerialPort() +-{ +- if (m_serial && m_serial->isOpen()) +- { +- m_serial->close(); +- m_serial = nullptr; +- } +- +- m_serial = nullptr; +- +- KISSConnected = 0; +- KISSConnecting = 0; +- +- Status3->setText("KISS Closed"); +- actHost[18]->setEnabled(0); // Enable KISS Connect Line +-} +- +-void QtTermTCP::readSerialData() +-{ +- int Read; +- unsigned char Buffer[8192]; +- +- // read the data from the socket +- +- m_serial->clearError(); +- +- Read = m_serial->read((char *)Buffer, 2047); +- +- if (m_serial->error()) +- { +- Debugprintf("Serial Read Error - RC %d Error %d", Read, m_serial->error()); +- closeSerialPort(); +- return; +- } +- +- +- while (Read > 0) +- { +- KISSDataReceived(m_serial, Buffer, Read); +- Read = m_serial->read((char *)Buffer, 2047); +- } +-} +- +-void QtTermTCP::handleError(QSerialPort::SerialPortError serialPortError) +-{ +- Debugprintf("Serial port Error %d", serialPortError); +- closeSerialPort(); +-} +- +-extern "C" void CheckUIFrame(unsigned char * path, string * data) +-{ +- // If we have KISS enabled and dest is UIDEST look for a KISS window in UI Mode +- +- if (KISSSock == 0) +- return; +- +- char Dest[10]; +- char From[10]; +- +- Dest[ConvFromAX25(path, Dest)] = 0; +- From[ConvFromAX25(&path[7], From)] = 0; +- +- // ok, Find a Kiss Session with this Dest +- +- Ui_ListenSession * Sess = NULL; +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->KISSMode == 1 && strcmp(Dest, Sess->UIDEST) == 0) +- { +- char Msg[512]; +- int Len; +- +- data->Data[data->Length] = 0; +- +- Len = sprintf(Msg, "%s:%s", From, data->Data); +- SendtoTerm(Sess, Msg, Len); +- return; +- } +- } +- +-} +- +- +-QColor QtTermTCP::setColor(QColor Colour) +-{ +- // const QColorDialog::ColorDialogOptions options = QFlag(colorDialogOptionsWidget->value()); +- +- +- QColor col = Colour; +- +- QColorDialog dialog; +- dialog.setCurrentColor(Colour); +- dialog.setOption(QColorDialog::DontUseNativeDialog); +- +- if (dialog.exec() == QColorDialog::Accepted) +- col = QVariant(dialog.currentColor()).toString(); +- +- +- // const QColor color = QColorDialog::getColor(Qt::green, this, "Select Color", 0); +- +- return col; +-} +- +-// Experimental Viewdata/Teletext/Prestel/CEEFAX Mode +- +-// Uses ideas and some code from +- +-/*************************************************************** +- * Name: wxTEDMain.cpp +- * Purpose: Teletext editor Application Frame +- * Author: Peter Kwan (peterk.vt80@gmail.com) +- * Created: 2014-10-30 +- * Copyright: Peter Kwan +- * License: +- * +- * Copyright (C) 2014-2022, Peter Kwan +- * +- * Permission to use, copy, modify, and distribute this software +- * and its documentation for any purpose and without fee is hereby +- * granted, provided that the above copyright notice appear in all +- * copies and that both that the copyright notice and this +- * permission notice and warranty disclaimer appear in supporting +- * documentation, and that the name of the author not be used in +- * advertising or publicity pertaining to distribution of the +- * software without specific, written prior permission. +- * +- * The author disclaims all warranties with regard to this +- * software, including all implied warranties of merchantability +- * and fitness. In no event shall the author be liable for any +- * special, indirect or consequential damages or any damages +- * whatsoever resulting from loss of use, data or profits, whether +- * in an action of contract, negligence or other tortious action, +- * arising out of or in connection with the use or performance of +- * this software. +- *************************************************************************** **/ +- +- +- +-int FontWidth = 16; +-int FontHeight = 16; +- +-bool isMosaic(char ch) +-{ +- ch &= 0x7f; +- return (ch >= 0x20 && ch < 0x40) || ch >= 0x60; +-} +- +- +-void DecodeTeleText(Ui_ListenSession * Sess, char * page) +-{ +- +- // redraw the whole teletext page +- +- QColor fg = Qt::white; +- QColor bg = Qt::black; +- QColor holdColour; +- QColor holdfg = fg; // Colour for held graphic +- int usehold = 0; +- int sep = 0; +- +- QPainter p(Sess->TTBitmap); +- +- QSettings settings(GetConfPath(), QSettings::IniFormat); +- +- //p.setFont(QFont("Courier", 14, QFont::Bold)); +- +- p.setFont(QFont(settings.value("FontFamily", "Courier New").value(), 14)); +- +- p.setPen(QPen(fg)); +- +- bool graphicsMode = false; +- bool separated = false; +- bool doubleHeight = false; +- int skipnextrow = 99; +- bool flashing = false; +- bool hold = false; +- char holdChar = 0; +- char holdMode = 0; +- Sess->timer.stop(); +- +- bool concealed = false; +- char c; +- +- fg = Qt::white; +- bg = Qt::black; +- +- char * ptr = page; +- +- int col = 0; +- int line = 0; +- +- // XXXXXXXXTEEFAX %%# %%a %d %%b C %H:%M.%S +- +- //p.drawText(0, 19, "P199 HAMFAX"); +- +- +- // interpret data, for now, line by line +- +- +- while ((c = *(ptr++))) +- { +- char ch = c; +- +- if (c == 0x11) // Curson On ?? +- continue; +- +- if (c == 0x14) // Curson Off ?? +- continue; +- +- if (c == 9) // Curson On ?? +- { +- col++; +- continue; +- } +- +- if (c == 0x0a) +- { +- line++; +- +-// if (doubleHeight) +-// line++; +- +- if (line > 24) +- line = 0; +- +- continue; +- } +- +- if (c == 0x1e) // Cursor Home +- { +- line = col = 0; +- c = 13; // So we reset page flags below +- } +- +- if (c == 12) +- { +- // Clear the page +- +- Sess->TTBitmap->fill(Qt::black); +- Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); +- +- line = col = 0; +- +- c = 13; // So we reset page flags below +- } +- +- if (c == 13) +- { +- col = 0; +- +- graphicsMode = false; +- separated = false; +- doubleHeight = false; +- flashing = false; +- hold = false; +- holdChar = 0; +- concealed = false; +- +- fg = Qt::white; +- bg = Qt::black; +- +- continue; // Next line +- } +- +- if (c == 0x1b) // Esc +- { +- // I think the control char is displayed as it was before being actioned, sa save current state +- +- holdfg = holdColour; // Colour if using held - may be changed before displaying +- usehold = hold; // May be changed +- sep = holdMode; +- +- char echar = *(ptr++); +- +- if (echar == 0) +- { +- // Esc pair spilt - wait for rest +- +- Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); +- return; +- } +- +- switch (echar) +- { +- case '@': +- fg = Qt::black; +- concealed = false; // Side effect of colour. It cancels a conceal. +- graphicsMode = false; +-// hold = false; +- +- break; +- case 'A': +- fg = Qt::red; +- concealed = false; +- graphicsMode = false; +- hold = false; +- +- break; +- case 'B': +- fg = Qt::green; +- concealed = false; +- graphicsMode = false; +- hold = false; +- break; +- case 'C': +- fg = Qt::yellow; +- concealed = false; +- graphicsMode = false; +- hold = false; +- break; +- case 'D': +- fg = Qt::blue; +- concealed = false; +- graphicsMode = false; +- hold = false; +- break; +- case 'E': +- fg = Qt::magenta; +- concealed = false; +- graphicsMode = false; +- hold = false; +- break; +- case 'F': +- fg = Qt::cyan; +- concealed = false; +- graphicsMode = false; +- hold = false; +- break; +- case 'G': +- fg = Qt::white; +- concealed = false; +- graphicsMode = false; +- hold = false; +- break; +- case 'H': // Flash +- flashing = true; +- Sess->timer.start(1000, Sess); +- concealed = false; +- graphicsMode = false; +- hold = false; +- +- break; +- +- case 'I': // Steady +- flashing = false; +- concealed = false; +- graphicsMode = false; +- hold = false; +- +- break; +- // +- case 'J': //ttxCodeEndBox: +- case 'K': //ttxCodeStartBox: +- +- concealed = false; +- graphicsMode = false; +- hold = false; +- +- break; +- case 'L': // Normal height +- doubleHeight = false; +- hold = false; +- break; +- +- case 'M': // Double height +- doubleHeight = true; +- skipnextrow = line + 1; // ETSI: row to ignore +- hold = false; +- holdChar = 0; +- break; +- case 'P': // Graphics black +-// concealed = false; +- graphicsMode = true; +- holdColour = fg = Qt::black; +- +- break; +- case 'Q': // Graphics red +-// concealed = false; +- graphicsMode = true; +- holdColour = fg = Qt::red; +- +- break; +- case 'R': // Graphics green +-// concealed = false; +- graphicsMode = true; +- holdColour = fg = Qt::green; +- +- break; +- case 'S': // Graphics yellow +-// concealed = false; +- graphicsMode = true; +- holdColour = fg = Qt::yellow; +- +- break; +- case 'T': // Graphics blue +-// concealed = false; +- graphicsMode = true; +- holdColour = fg = Qt::blue; +- +- break; +- case 'U': // Graphics magenta +-// concealed = false; +- graphicsMode = true; +- holdColour = fg = Qt::magenta; +- +- break; +- case 'V': // Graphics cyan +-// concealed = false; +- graphicsMode = true; +- holdColour = fg = Qt::cyan; +- +- break; +- case 'W': // Graphics white +-// concealed = false; +- graphicsMode = true; +- holdColour = fg = Qt::white; +- +- break; +- +- case 'X': // Conceal display +- +- concealed = 1; +- break; +- +- case 'Y': // Contiguous graphics +- +- separated = false; +- break; +- +- case 'Z': // Separated gfx +- +- separated = true; +- break; +- +- case 0x5c: // Background black +- bg = Qt::black; +- break; +- +- case 0x5d: // New background +- +- bg = fg; +- break; +- +- case 0x5e: // Hold gfx +- +- if (hold == 0) +- { +- hold = true; +- holdColour = fg; +- holdMode = separated; +- } +- break; +- +- case 0x5f: // Non-hold gfx +- hold = false; +- break; +- +- default: +- echar++; // For testign +- break; +- +- } //end of esc case processing +- +- if (usehold) +- { +- // We set sep and color for held char earlier +- +- ch = holdChar; // Repeat held char +- } +- else +- ch = 0x0; // Default is space +- +- +- if (line > skipnextrow) +- skipnextrow = 99; +- +- if (line == skipnextrow) +- { +- line = line; +- } +- else +- { +- if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) +- { +- p.fillRect(col * 15, line * 19, 15, 19, bg); +- +- // if double height also draw background for next row +- +- if (doubleHeight) +- p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); +- +- +- if (sep) +- { +- if (ch & 1) +- p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, holdfg); +- if (ch & 2) +- p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, holdfg); +- if (ch & 4) +- p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, holdfg); +- if (ch & 8) +- p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, holdfg); +- if (ch & 16) +- p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, holdfg); +- if (ch & 32) +- p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, holdfg); +- +- } +- else +- { +- if (ch & 1) +- p.fillRect(col * 15, line * 19, 7, 6, holdfg); +- if (ch & 2) +- p.fillRect(col * 15 + 7, line * 19, 8, 6, holdfg); +- if (ch & 4) +- p.fillRect(col * 15, line * 19 + 6, 7, 6, holdfg); +- if (ch & 8) +- p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, holdfg); +- if (ch & 16) +- p.fillRect(col * 15, line * 19 + 12, 7, 7, holdfg); +- if (ch & 32) +- p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, holdfg); +- } +- } +- } +- col++; +- } +- else +- { +- // Not esc - so normal or graphics +- +- if (ch < 0x20) +- continue; +- +- if (line > skipnextrow) +- skipnextrow = 99; +- +- if (line == skipnextrow) +- { +- line = line; +- } +- else +- { +- if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) +- { +- p.fillRect(col * 15, line * 19, 15, 19, bg); +- +- if (doubleHeight) +- p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); +- +- p.setPen(QPen(fg));; +- +- if (graphicsMode) +- { +- if (ch < 0x40) +- ch -= 0x20; +- else +- if (ch >= 0x60) +- ch -= 0x40; +- else +- goto isText; +- +- holdChar = ch; +- +- // Now have 00 - 3f +- +- +- // C is bit mask bit posns are +- // 01 +- // 23 +- // 45 +- // Char cell is 15 * 19 which is a bit asymetrical +- +- // Chars are 20 - 3f and 60 to 7f but I cant see a logic to the mapping +- +- +- if (separated) +- { +- if (ch & 1) +- p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, fg); +- if (ch & 2) +- p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, fg); +- if (ch & 4) +- p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, fg); +- if (ch & 8) +- p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, fg); +- if (ch & 16) +- p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, fg); +- if (ch & 32) +- p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, fg); +- +- } +- else +- { +- if (ch & 1) +- p.fillRect(col * 15, line * 19, 7, 6, fg); +- if (ch & 2) +- p.fillRect(col * 15 + 7, line * 19, 8, 6, fg); +- if (ch & 4) +- p.fillRect(col * 15, line * 19 + 6, 7, 6, fg); +- if (ch & 8) +- p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, fg); +- if (ch & 16) +- p.fillRect(col * 15, line * 19 + 12, 7, 7, fg); +- if (ch & 32) +- p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, fg); +- } +- } +- else +- { +- // Just write char at current col and line +- +- isText: +- char s[5]; +- unsigned char su[5] = ""; +- +- // Some chars are in wrong char set +- +- su[0] = ch; +- +- if (ch == '_') +- su[0] = '#'; +- +- else if (ch == 0x7e) // division +- { +- su[0] = 0xC3; +- su[1] = 0xB7; +- } +- else if (ch == 0x5e) // up arrow +- { +- su[0] = 0xF0; +- su[1] = 0x9F; +- su[2] = 0xA0; +- su[3] = 0x95; +- } +- else if (ch == 0x7f) // up arrow +- { +- su[0] = 0xE2; +- su[1] = 0x96; +- su[2] = 0x88; +- } +- +- memcpy(s, su, 5); +- +-// if (doubleHeight) +- // p.drawText(col * 15, line * 19 + 25, s); +- // else +- // p.drawText(col * 15, line * 19 + 15, s); +- +- // if double height draw normally then copy pixels each row of pixels to two scanlines (starting at the bottom) +- +- if (doubleHeight) +- { +- int inscanline = line * 19 + 18; +- int outscanline = line * 19 + 35; +- unsigned char * inptr = Sess->TTBitmap->scanLine(inscanline); +- unsigned char * outptr = Sess->TTBitmap->scanLine(outscanline); +- int linelen = Sess->TTBitmap->bytesPerLine(); +- int charlen = linelen / 40; // bytes per char position +- +- p.drawText(col * 15, line * 19 + 16, s); +- +- inptr += col * charlen; +- outptr += col * charlen; +- +- for (int i = 0; i < 18; i++) +- { +- memcpy(outptr, inptr, charlen); +- outptr -= linelen; +- memcpy(outptr, inptr, charlen); +- +- inptr -= linelen; +- outptr -= linelen; +- +- } +- } +- else +- p.drawText(col * 15, line * 19 + 15, s); +- +- } +- } +- } +- col++; +- } +- +- if (col > 39) +- { +- col = 0; +- line++; +- if (line > 24) +- line = 0; +- +- graphicsMode = false; +- separated = false; +- doubleHeight = false; +- flashing = false; +- hold = false; +- holdChar = 0; +- concealed = false; +- +- fg = Qt::white; +- bg = Qt::black; +- } +- } +- Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); +- return; +- +- QFile file("D:/savepage.txt"); +- file.open(QIODevice::WriteOnly); +- file.write(Sess->pageBuffer); +- file.close(); +-} +- +- +-void Ui_ListenSession::timerEvent(QTimerEvent *event) +-{ +- Ui_ListenSession * Sess = NULL; +- +- // Used for flashing - resfresh window +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->timer.timerId() == event->timerId()) +- { +- if (Sess->TTActive) +- { +- Sess->TTFlashToggle ^= 1; +- +- // if in Tabbed mode only refresh active tab +- +- if (TermMode == Tabbed && Sess != ActiveSession) +- return; +- +- DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end +- } +- else +- Sess->timer.stop(); +- +- return; +- } +- } +- QWidget::timerEvent(event); +-} +- +-// Monitor Log FIle routines +- +-char * doXMLTransparency(char * string) +-{ +- // Make sure string doesn't contain forbidden XML chars (<>"'&) +- +- char * newstring = (char *)malloc(5 * strlen(string) + 1); // If len is zero still need null terminator +- +- char * in = string; +- char * out = newstring; +- char c; +- +- c = *(in++); +- +- while (c) +- { +- switch (c) +- { +- case '<': +- +- strcpy(out, "<"); +- out += 4; +- break; +- +- case '>': +- +- strcpy(out, ">"); +- out += 4; +- break; +- +- case '"': +- +- strcpy(out, """); +- out += 6; +- break; +- +- case '\'': +- +- strcpy(out, "'"); +- out += 6; +- break; +- +- case '&': +- +- strcpy(out, "&"); +- out += 5; +- break; +- +- default: +- +- *(out++) = c; +- } +- c = *(in++); +- } +- +- *(out++) = 0; +- return newstring; +-} +- +-void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg) +-{ +- // Write as HTML to preserve formatting +- +- char Line[512]; +- char * HTMLText; +- +- if (Sess->monLogfile == nullptr) +- { +- QString FN = "QTTermMonLog" + timeLoaded + "_" + QString::number(Sess->sessNo) + ".html"; +- Sess->monLogfile = new QFile(FN); +- +- if (Sess->monLogfile) +- Sess->monLogfile->open(QIODevice::Append); +- else +- return; +- } +- +- if (Msg[0] == 0x1b) +- { +- // Colour Escape +- +- if (Msg[1] == 17) +- Sess->monSpan = (char *)"";// , monRxColour.data()); +- else +- Sess->monSpan = (char *)"";// , monTxColour.data()); +- +- HTMLText = doXMLTransparency(&Msg[2]); +- } +- else +- { +- // Leave colour at last set value +- +- HTMLText = doXMLTransparency(Msg); +- } +- +- sprintf(Line, "%s%s
\r\n", Sess->monSpan, HTMLText); +- +- Sess->monLogfile->write(Line); +- +- free(HTMLText); +- +-} +- +-// Create MH Window +- +- +- +-int newMHWindow(QObject * parent, int Type, const char * Label) +-{ +- Ui_ListenSession * Sess = new(Ui_ListenSession); +- +- MHWindow = Sess; +- +- // Need to explicity initialise on Qt4 +- +- Sess->termWindow = NULL; +- Sess->monWindow = NULL; +- Sess->inputWindow = NULL; +- +- Sess->StackIndex = 0; +- Sess->InputMode = 0; +- Sess->SlowTimer = 0; +- Sess->MonData = 0; +- Sess->OutputSaveLen = 0; +- Sess->MonSaveLen = 0; +- Sess->PortMonString[0] = 0; +- Sess->portmask = 0; +- Sess->portmask = 1; +- Sess->mtxparam = 1; +- Sess->mlocaltime = 0; +- Sess->mcomparam = 1; +- Sess->monUI = 0; +- Sess->MonitorNODES = 0; +- Sess->MonitorColour = 1; +- Sess->CurrentHost = 0; +- +- Sess->SessionType = Type; +- Sess->clientSocket = NULL; +- Sess->AGWSession = NULL; +- Sess->AGWMonSession = NULL; +- Sess->KISSSession = NULL; +- Sess->KISSMode = 0; +- Sess->TTActive = 0; +- Sess->TTFlashToggle = 0; +- Sess->pageBuffer[0] = 0; +- Sess->Tab = 0; +- +- Sess->LogMonitor = false; +- Sess->monSpan = (char *) ""; +- Sess->monLogfile = nullptr; +- Sess->sessNo = sessNo++; +- +- 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 +- +- Sess->monWindow = new QTextEdit(Sess); +- Sess->monWindow->setReadOnly(1); +- Sess->monWindow->document()->setMaximumBlockCount(10000); +- Sess->monWindow->setFont(font); +- Sess->monWindow->setStyleSheet(monStyleSheet); +- +- Sess->setWindowTitle(Label); +- +- Sess->installEventFilter(mythis); +- +- Sess->show(); +- +- +- +- Sess->monWindow->setGeometry(QRect(2, 2, 400, 400)); +- Sess->setGeometry(QRect(400, 400, 400, 400)); +- +- +- 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 true; +-} +- +-extern "C" void WritetoMHWindow(char * Buffer) +-{ +- unsigned char Copy[8192]; +- unsigned char * ptr1, *ptr2; +- unsigned char Line[8192]; +- unsigned char out[8192]; +- int outlen; +- +- int num; +- +- if (MHWindow == NULL || MHWindow->monWindow == NULL) +- return; +- +- MHWindow->monWindow->setText(Buffer); +-} ++// Qt Version of BPQTermTCP ++ ++// Application icon design by Red PE1RRR ++ ++#define VersionString "0.0.0.79" ++ ++ ++// .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 arrivn other window ++// .19 Fix Scrollback ++// .20 WinXP compatibility changes ++// .21 Save Window Positions ++// .22 Open a window on first start ++// .23 Add Tabbed display option ++// .24 Fix crash when setting Monitor flags in Tabbed mode ++// .25 Add AGW mode ++// .26 Add sending CTRL/C CTRL/D and CTRL/Z) ++// .27 Limit size of windows to 10000 lines ++// Fix YAPP in Tabbed Mode ++// .28 Add AGW Beacon ++// .29 Fix allocating Listem sessions to tabs connected using AGW ++// .30 Fix allocationd AGW Monitor Sessions ++// .31 Fix output being written to the wrong place when window is scrolled back ++// .32 Fix connect with digis ++// .33 Add StripLF option ++// .34 Improvements for Andriod ++// Option to change Menu Fonts ++// Fix receiving part lines when scrolled back ++// .35 Fix PE if not in Tabbed Mode ++// .36 Improved dialogs mainly for Android ++// Try to make sure sessions are closed before exiting ++// .37 Replace VT with LF (for pasting from BPQ32 Terminal Window) ++// Dont show AGW status line if AGW interface is disabled ++// Don't show Window Menu in Single Mode ++// .38 Protect against connect to normal Telnet Port. ++// Send CTEXT and Beep for inward AGW Connects ++// Make sending Idle and Connect beeps configurable ++// Change displayed Monitor flags when active window changed. ++// Fix duplicate text on long lines ++// .39 Add option to Convert non-utf8 charaters ++// .40 Prevent crash if AGW monitor Window closed ++// .41 Allow AGW Config and Connect dialogs to be resized with scrollbars ++// Fix disabling connect flag on current session when AGW connects ++// .42 Fix some bugs in AGW session handling ++// .43 Include Ross KD5LPB's fixes for MAC ++// .44 Ctrl/[ sends ESC (0x1b) ++// .45 Add VARA support Nov 2021 ++// .46 Fix dialog size on VARA setup ++// .47 Move VARA Status indicator. ++// Add FLRIG PTT for VARA ++// .48 Check that YAPP Receive Directory has been set ++// Save separate configs for VARA, VARAFM and VARASAT ++// .49 Add BBS Monitor Dec 2021 ++// .50 Make Serial port support optional for Android Version ++// .51 Add KISS TNC Support May 2022 ++// .52 Save partially typed lines on cursor up May 2022 ++// .53 Add UI Mode for KISS Sessions May 2022 ++// Fix saving KISS Paclen (b) ++// Fix Keepalive (c) ++// .54 Add option to change screen colours June 2022 ++// .55 Build without optimisation ++// .56 Add Teletext mode Nov 2022 ++// .57 Fix KISS mode incoming call handling ++// .58 Add method to toggle Normal/Teletext Mode ++// Fix KISS multiple session protection ++// .59 Add Teletext double height mode ++// .60 Add option to name sessions Jan 2023 ++// .61 Add VARA Init Script Feb 2023 ++// .62 Fix running AGW in single session mode Feb 2023 ++// .63 Fix handling split monitor frame (no fe in buffer) Apr 2023 ++// .64 Add Clear Screen command to context menu Apr 2023 ++// .65 Fixes for 63 port version of BPQ May 2023 ++// .66 Colour Tab of incoming calls June 2023 ++// .67 Add config Yapp RX Size dialog July 2023 ++// Fix 63 port montoring ++ ++// .68 Sept 2023 ++ ++// Remember last used host on restart ++// Add AutoConnect in Tabbed Mode ++// Fix auto copy when QtTerm not active window ++ ++// .69 October 2023 ++ ++// Options related to sound alerts moved to a separte menu in Setup ++// Allow use of WAV files instead of Beep sound for sound alerts ++// Enable an alarm to be sounded when one of a list of words or phrases is received. ++ ++// .70 October 2023 ++ ++// Include some .wav files in resources ++// Add Test button to Alert setup dialog ++ ++// .71 October 2023 ++ ++// Add option to use local time ++// Fixes for Mac OS ++ ++// .72 November 2023 ++// Don't display "Enable Monitor" on startup ++ ++// .73 November 2023 ++// Raise RTS on KISS serial port ++ ++// .74 April 2024 ++// Support BPQKISS TNCs with CHECKSUM and/or ACKMODE enabled ++ ++// .75 May 2024 ++// Flush Monitor log file every minute ++ ++// .76 August 2024 ++// Fix using digs in KISS UI mode. ++// Add option to send TXDELAY to KISS TNC ++ ++// .77 ++// Support multichannel KISS TNCs (Beta 1) ++// Fix using AGW listen in single terminal mode ++ ++// .78 ++// Fix restoring monitor flags when connecting to current host ++ ++ ++// .79 ++// Add KISS MHEARD Window (Feb 2025) ++ ++ ++#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 ++#include ++#ifdef USESERIAL ++#include ++#include ++#endif ++#ifndef WIN32 ++#define strtok_s strtok_r ++#endif ++#include ++#include ++#ifndef WIN32 ++#include ++#endif ++ ++#include "ax25.h" ++ ++#define UNREFERENCED_PARAMETER(P) (P) ++ ++void DecodeTeleText(Ui_ListenSession * Sess, char * text); ++ ++char Host[MAXHOSTS + 1][100] = { "" }; ++int Port[MAXHOSTS + 1] = { 0 }; ++char UserName[MAXHOSTS + 1][80] = { "" }; ++char Password[MAXHOSTS + 1][80] = { "" }; ++char MonParams[MAXHOSTS + 1][80] = { "" }; ++char SessName[MAXHOSTS + 1][80] = { "" }; ++int ListenPort = 8015; ++ ++// Session Type Equates ++ ++#define Term 1 ++#define Mon 2 ++#define Listen 4 ++ ++// Presentation - Single Window, MDI or Tabbed ++ ++int TermMode = 0; ++ ++#define Single 0 ++#define MDI 1 ++#define Tabbed 2 ++ ++int singlemodeFormat = Mon + Term; ++ ++char monStyleSheet[128] = "background-color: rgb(0,255,255)"; ++char termStyleSheet[128] = "background-color: rgb(255,0,255);"; ++char inputStyleSheet[128] = "color: rgb(255, 0, 0); background-color: rgb(255,255,0);"; ++ ++QColor monBackground = qRgb(0, 255, 255); ++QColor monRxText = qRgb(0, 0, 255); ++QColor monTxText = qRgb(255, 0, 0); ++QColor monOtherText = qRgb(0, 0, 0); ++ ++QColor termBackground = qRgb(255, 0, 255); ++QColor outputText = qRgb(0, 0, 0); ++QColor EchoText = qRgb(0, 0, 255); ++QColor WarningText = qRgb(255, 0, 0); ++QColor inputBackground = qRgb(255, 255, 0); ++QColor inputText = qRgb(0, 0, 255); ++ ++QColor newTabText = qRgb(255, 0, 0); // Red ++QColor oldTabText = qRgb(0, 0, 0); // Black ++ ++ ++// There is something odd about this. It doesn't match BPQTERMTCP though it looks the same ++ ++// Chat uses these (+ 10) ++//{ 0, 4, 9, 11, 13, 16, 17, 42, 45, 50, 61, 64, 66, 72, 81, 84, 85, 86, 87, 89 }; ++ ++// As we have a white background we need dark colours ++ ++// 0 is black. 23 is normal output (blue) 81 is red (used by AGW Mon) ++// for monitor in colour, host sends 17 for RX Text, 81 for TX Text but code converts to monRx/TxText qrgb values ++ ++QRgb Colours[256] = { 0, ++ qRgb(0,0,0), qRgb(0,0,128), qRgb(0,0,192), qRgb(0,0,255), // 1 - 4 ++ qRgb(0,64,0), qRgb(0,64,128), qRgb(0,64,192), qRgb(0,64,255), // 5 - 8 ++ qRgb(0,128,0), qRgb(0,128,128), qRgb(0,128,192), qRgb(0,128,255), // 9 - 12 ++ qRgb(0,192,0), qRgb(0,192,128), qRgb(0,192,192), qRgb(0,192,255), // 13 - 16 ++ qRgb(0,255,0), qRgb(0,255,128), qRgb(0,255,192), qRgb(0,255,255), // 17 - 20 ++ ++ qRgb(64,0,0), qRgb(64,0,128), qRgb(64,0,192), qRgb(0,0,255), // 21 ++ qRgb(64,64,0), qRgb(64,64,128), qRgb(64,64,192), qRgb(64,64,255), ++ qRgb(64,128,0), qRgb(64,128,128), qRgb(64,128,192), qRgb(64,128,255), ++ qRgb(64,192,0), qRgb(64,192,128), qRgb(64,192,192), qRgb(64,192,255), ++ qRgb(64,255,0), qRgb(64,255,128), qRgb(64,255,192), qRgb(64,255,255), ++ ++ qRgb(128,0,0), qRgb(128,0,128), qRgb(128,0,192), qRgb(128,0,255), // 41 ++ qRgb(128,64,0), qRgb(128,64,128), qRgb(128,64,192), qRgb(128,64,255), ++ qRgb(128,128,0), qRgb(128,128,128), qRgb(128,128,192), qRgb(128,128,255), ++ qRgb(128,192,0), qRgb(128,192,128), qRgb(128,192,192), qRgb(128,192,255), ++ qRgb(128,255,0), qRgb(128,255,128), qRgb(128,255,192), qRgb(128,255,255), ++ ++ qRgb(192,0,0), qRgb(192,0,128), qRgb(192,0,192), qRgb(192,0,255), // 61 - 80 ++ qRgb(192,64,0), qRgb(192,64,128), qRgb(192,64,192), qRgb(192,64,255), ++ qRgb(192,128,0), qRgb(192,128,128), qRgb(192,128,192), qRgb(192,128,255), ++ qRgb(192,192,0), qRgb(192,192,128), qRgb(192,192,192), qRgb(192,192,255), ++ qRgb(192,255,0), qRgb(192,255,128), qRgb(192,255,192), qRgb(192,255,255), ++ ++ qRgb(255,0,0), qRgb(255,0,128), qRgb(255,0,192), qRgb(255,0,255), // 81 - 100 ++ qRgb(255,64,0), qRgb(255,64,128), qRgb(255,64,192), qRgb(255,64,255), ++ qRgb(255,128,0), qRgb(255,128,128), qRgb(255,128,192), qRgb(255,128,255), ++ qRgb(255,192,0), qRgb(255,192,128), qRgb(255,192,192), qRgb(255,192,255), ++ qRgb(255,255,0), qRgb(255,255,128), qRgb(255,255,192), qRgb(255,255,255) ++}; ++ ++ ++ ++int SavedHost = 0; // from config ++ ++char * sessionList = NULL; // Saved sessions ++ ++extern int ChatMode; ++extern int Bells; ++extern int StripLF; ++extern int convUTF8; ++ ++extern time_t LastWrite; ++extern int AlertInterval; ++extern int AlertBeep; ++extern int AlertFreq; ++extern int AlertDuration; ++extern int ConnectBeep; ++ ++bool useBeep; // use wav files if not set ++ ++extern int UseKeywords; ++extern QString KeyWordsFile; ++ ++QString ConnectWAV(""); ++QString AlertWAV(""); ++QString BellWAV(""); ++QString IntervalWAV(""); ++ ++extern int MaxRXSize; ++ ++extern int AutoTeletext; ++ ++// AGW Host Interface stuff ++ ++int AGWEnable = 0; ++int AGWMonEnable = 0; ++int AGWLocalTime = 0; ++int AGWMonNodes = 0; ++char AGWTermCall[12] = ""; ++char AGWBeaconDest[12] = ""; ++char AGWBeaconPath[80] = ""; ++int AGWBeaconInterval = 0; ++char AGWBeaconPorts[80]; ++char AGWBeaconMsg[260] = ""; ++ ++ ++char AGWHost[128] = "127.0.0.1"; ++int AGWPortNum = 8000; ++int AGWPaclen = 80; ++extern char * AGWPortList; ++extern myTcpSocket * AGWSock; ++ ++typedef struct AGWUser_t ++{ ++ QTcpSocket *socket; ++ unsigned char data_in[8192]; ++ int data_in_len; ++ unsigned char AGW_frame_buf[512]; ++ int Monitor; ++ int Monitor_raw; ++ Ui_ListenSession * MonSess; // Window for Monitor info ++ ++} AGWUser; ++ ++extern AGWUser *AGWUsers; // List of currently connected clients ++void Send_AGW_m_Frame(QTcpSocket* socket); ++ ++ ++QStringList AGWToCalls; ++ ++// KISS Interface ++ ++int KISSEnable = 0; ++extern "C" int KISSMonEnable; ++extern "C" int KISSLocalTime; ++extern "C" int KISSMonNodes; ++extern "C" int KISSListen; ++extern "C" int KISSChecksum; ++extern "C" int KISSAckMode; ++extern "C" int KISSMH; ++ ++extern "C" short txtail[5]; ++extern "C" short txdelay[5]; ++extern "C" int sendTXDelay[4]; ++ ++ ++ ++char SerialPort[80] = ""; ++char KISSHost[128] = "127.0.0.1"; ++int KISSPortNum = 1000; ++int KISSBAUD = 19200; ++char KISSMYCALL[32]; ++char KISSVia[128]; // Digi String ++ ++extern "C" UCHAR axMYCALL[7]; // Mycall in ax.25 ++ ++int KISSMode = 0; // Connected (0) or UI (1) ++ ++myTcpSocket * KISSSock; ++ ++extern "C" void * KISSSockCopy[4]; ++ ++int KISSConnected = 0; ++int KISSConnecting = 0; ++ ++Ui_ListenSession * KISSMonSess = nullptr; ++ ++QSerialPort * m_serial = nullptr; ++ ++// VARA Interface ++ ++int VARAEnable = 0; ++char VARAHost[128] = "127.0.0.1"; ++char VARAHostHF[128] = "127.0.0.1"; ++char VARAHostFM[128] = "127.0.0.1"; ++char VARAHostSAT[128] = "127.0.0.1"; ++int VARAPortNum = 8000; ++int VARAPortHF = 8000; ++int VARAPortFM = 8000; ++int VARAPortSAT = 8000; ++char VARATermCall[12] = ""; ++char VARAPath[256] = ""; ++char VARAInit[256] = ""; ++char VARAPathHF[256] = ""; ++char VARAPathFM[256] = ""; ++char VARAPathSAT[256] = ""; ++ ++int VARA500 = 0; ++int VARA2300 = 1; ++int VARA2750 = 0; ++ ++int VARAHF = 1; ++int VARAFM = 0; ++int VARASAT = 0; ++ ++myTcpSocket * VARASock; ++myTcpSocket * VARADataSock; ++ ++int VARAConnected = 0; ++int VARAConnecting = 0; ++ ++ ++extern char YAPPPath[256]; ++ ++void menuChecked(QAction * Act); ++ ++// PTT Stuff ++ ++#define PTTRTS 1 ++#define PTTDTR 2 ++#define PTTCAT 4 ++#define PTTCM108 8 ++#define PTTHAMLIB 16 ++#define PTTFLRIG 32 ++ ++#ifdef USESERIAL ++ ++QSerialPort * hPTTDevice = 0; ++#else ++ ++ ++#endif ++char PTTPort[80] = ""; // Port for Hardware PTT - may be same as control port. ++int PTTBAUD = 19200; ++int PTTMode = PTTRTS; // PTT Control Flags. ++ ++char PTTOnString[128] = ""; ++char PTTOffString[128] = ""; ++ ++int CATHex = 1; ++ ++unsigned char PTTOnCmd[64]; ++int PTTOnCmdLen = 0; ++ ++unsigned char PTTOffCmd[64]; ++int PTTOffCmdLen = 0; ++ ++int pttGPIOPin = 17; // Default ++int pttGPIOPinR = 17; ++bool pttGPIOInvert = false; ++bool useGPIO = false; ++bool gotGPIO = false; ++ ++int HamLibPort = 4532; ++char HamLibHost[32] = "192.168.1.14"; ++ ++int FLRigPort = 12345; ++char FLRigHost[32] = "127.0.0.1"; ++ ++ ++char CM108Addr[80] = ""; ++ ++int VID = 0; ++int PID = 0; ++ ++// CM108 Code ++ ++char * CM108Device = NULL; ++ ++QProcess *process = NULL; ++ ++void GetSettings(); ++ ++// These widgets defined here as they are accessed from outside the framework ++ ++QLabel * Status1; ++QLabel * Status2; ++QLabel * Status3; ++QLabel * Status4; ++ ++QAction *actHost[19]; ++QAction *actSetup[16]; ++ ++QAction * TabSingle = NULL; ++QAction * TabBoth = NULL; ++QAction * TabMon = NULL; ++ ++QMenu *monitorMenu; ++QMenu * YAPPMenu; ++QMenu *connectMenu; ++QMenu *disconnectMenu; ++ ++QAction *EnableMonitor; ++QAction *EnableMonLog; ++QAction *MonLocalTime; ++QAction *MonTX; ++QAction *MonSup; ++QAction *MonNodes; ++QAction *MonUI; ++QAction *MonColour; ++QAction *MonPort[65]; ++QAction *actChatMode; ++QAction *actAutoTeletext; ++QAction *actBells; ++QAction *actStripLF; ++QAction *actIntervalBeep; ++QAction *actConnectBeep; ++QAction *actAuto; ++QAction *actnoConv; ++QAction *actCP1251; ++QAction *actCP1252; ++QAction *actCP437; ++ ++QAction *actFonts; ++QAction *actmenuFont; ++QAction *actColours; ++QAction *actmyFonts; ++QAction *YAPPSend; ++QAction *YAPPSetRX; ++QAction *YAPPSetSize; ++QAction *singleAct; ++QAction *singleAct2; ++QAction *MDIAct; ++QAction *tabbedAct; ++QAction *discAction; ++QFont * menufont; ++QMenu *windowMenu; ++QMenu *setupMenu; ++QAction *ListenAction; ++ ++QTabWidget *tabWidget; ++QMdiArea *mdiArea; ++QWidget * mythis; ++QStatusBar * myStatusBar; ++ ++QTcpServer * _server; ++ ++QMenuBar *mymenuBar; ++QToolBar *toolBar; ++QToolButton * but1; ++QToolButton * but2; ++QToolButton * but3; ++QToolButton * but4; ++QToolButton * but5; ++ ++QList _sessions; ++ ++// Session Type Equates ++ ++#define Term 1 ++#define Mon 2 ++#define Listen 4 ++ ++int TabType[10] = { Term, Term + Mon, Term, Term, Term, Term, Mon, Mon, Mon }; ++ ++int AutoConnect[10] = {0, 0 ,0, 0, 0, 0, 0, 0, 0, 0}; ++ ++int currentHost[10] = {0, 0 ,0, 0, 0, 0, 0, 0, 0, 0}; ++ ++int listenPort = 8015; ++extern "C" int listenEnable; ++char listenCText[4096] = ""; ++ ++int ConfigHost = 0; ++ ++int Split = 50; // Mon/Term size split ++ ++int termX; ++ ++bool Cascading = false; // Set to stop size being saved when cascading ++ ++QMdiSubWindow * ActiveSubWindow = NULL; ++Ui_ListenSession * ActiveSession = NULL; ++ ++Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label = nullptr); ++void Send_AGW_C_Frame(Ui_ListenSession * Sess, int Port, char * CallFrom, char * CallTo, char * Data, int DataLen); ++void AGW_AX25_data_in(void * AX25Sess, unsigned char * data, int Len); ++void AGWMonWindowClosing(Ui_ListenSession *Sess); ++void AGWWindowClosing(Ui_ListenSession *Sess); ++extern "C" void KISSDataReceived(void * socket, unsigned char * data, int length); ++void closeSerialPort(); ++int newMHWindow(QObject * parent, int Type, const char * Label); ++ ++extern void initUTF8(); ++int checkUTF8(unsigned char * Msg, int Len, unsigned char * out); ++ ++QDialog * deviceUI; ++ ++#include ++#include ++#include ++ ++ ++ ++ ++void EncodeSettingsLine(int n, char * String) ++{ ++ sprintf(String, "%s|%d|%s|%s|%s|%s", Host[n], Port[n], UserName[n], Password[n], MonParams[n], SessName[n]); ++ return; ++} ++ ++// This is used for placing discAction in the preference menu ++#ifdef __APPLE__ ++bool is_mac = true; ++#else ++bool is_mac = false; ++#endif ++ ++QString GetConfPath() ++{ ++ std::string conf_path = "QtTermTCP.ini"; // Default conf file stored alongside application. ++ ++#ifdef __APPLE__ ++ ++ // Get configuration path for MacOS. ++ ++ // This will usually be placed in /Users/USER/Library/Application Support/QtTermTCP ++ ++ std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString(); ++ ++ conf_path = directory + "/QtTermTCP.ini"; ++ ++ mkdir(directory.c_str(), 0775); ++ ++#endif ++ ++ return QString::fromUtf8(conf_path.c_str()); ++ ++} ++ ++ ++ ++void DecodeSettingsLine(int n, char * String) ++{ ++ char * Param = strdup(String); ++ char * Rest; ++ char * Save = Param; // for Free ++ ++ Rest = strlop(Param, '|'); ++ ++ if (Rest == NULL) ++ return; ++ ++ strcpy(Host[n], Param); ++ Param = Rest; ++ ++ Rest = strlop(Param, '|'); ++ Port[n] = atoi(Param); ++ Param = Rest; ++ ++ Rest = strlop(Param, '|'); ++ strcpy(UserName[n], Param); ++ Param = Rest; ++ ++ Rest = strlop(Param, '|'); ++ strcpy(Password[n], Param); ++ Param = Rest; ++ ++ Rest = strlop(Param, '|'); ++ strcpy(MonParams[n], Param); ++ ++ if (Rest) ++ strcpy(SessName[n], Rest); ++ ++ free(Save); ++ return; ++} ++ ++//#ifdef ANDROID ++//#define inputheight 60 ++//#else ++#define inputheight 25 ++//#endif ++ ++extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len); ++ ++void DoTermResize(Ui_ListenSession * Sess) ++{ ++ ++ QRect r = Sess->rect(); ++ ++ int H, Mid, monHeight, termHeight, Width, Border = 3; ++ ++ Width = r.width(); ++ H = r.height(); ++ ++ if (TermMode == Tabbed) ++ { ++ // H -= 20; ++ Width -= 7; ++ } ++ else if (TermMode == Single) ++ { ++ Width -= 7; ++ // H += 20; ++ } ++ ++ if (Sess->SessionType == Listen || Sess->SessionType == Term) ++ { ++ // Term and Input ++ ++ // Calc Positions of window ++ ++ termHeight = H - (inputheight + 3 * Border); ++ ++ Sess->termWindow->setGeometry(QRect(Border, Border, Width, termHeight)); ++ ++ if (Sess->TTActive) ++ { ++ Sess->TTLabel->setGeometry(QRect(Border, Border, 600, 475)); ++// Sess->termWindow->setVisible(false); ++ Sess->TTLabel->setVisible(true); ++ } ++ else ++ { ++// Sess->termWindow->setVisible(true); ++ Sess->TTLabel->setVisible(false); ++ } ++ ++ Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); ++ } ++ else if (Sess->SessionType == (Term | Mon)) ++ { ++ // All 3 ++ ++ // Calc Positions of window ++ ++ Mid = (H * Split) / 100; ++ ++ monHeight = Mid - Border; ++ termX = Mid; ++ termHeight = H - Mid - (inputheight + 3 * Border); ++ ++ Sess->monWindow->setGeometry(QRect(Border, Border, Width, monHeight)); ++ Sess->termWindow->setGeometry(QRect(Border, Mid + Border, Width, termHeight)); ++ ++ if (Sess->TTActive) ++ { ++ Sess->TTLabel->setGeometry(QRect(3, Mid + Border, 600, 475)); ++// Sess->termWindow->setVisible(false); ++ Sess->TTLabel->setVisible(true); ++ } ++ else ++ { ++// Sess->termWindow->setVisible(true); ++ Sess->TTLabel->setVisible(false); ++ } ++ ++ Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); ++ ++ } ++ else ++ { ++ // Should just be Mon only ++ ++ Sess->monWindow->setGeometry(QRect(Border, Border, Width, H - 2 * Border)); ++ } ++} ++ ++ ++extern "C" Ui_ListenSession * MHWindow; ++ ++bool QtTermTCP::eventFilter(QObject* obj, QEvent *event) ++{ ++ // See if from a Listening Session ++ ++ Ui_ListenSession * Sess; ++ ++ if (obj == MHWindow) ++ { ++ if (event->type() == QEvent::Resize) ++ { ++ QRect r = MHWindow->rect(); ++ ++ int H, Width, Border = 3; ++ ++ Width = r.width() - 6; ++ H = r.height() - 6; ++ ++ MHWindow->monWindow->setGeometry(QRect(Border, Border, Width, H)); ++ return true; ++ } ++ if (event->type() == QEvent::Close) ++ { ++ QSettings mysettings(GetConfPath(), QSettings::IniFormat); ++ mysettings.setValue("MHgeometry", MHWindow->saveGeometry()); ++ SaveSettings(); ++ MHWindow = 0; ++ } ++ } ++ ++ ++ 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) ++ { ++ // Get clipboard data and process a line at a time ++ ++ QClipboard *clipboard = QGuiApplication::clipboard(); ++ QString Text = clipboard->text(); ++ QByteArray ba = Text.toLocal8Bit(); ++ char * Msg = ba.data(); ++ ++ ++ Sess->inputWindow->paste(); ++ return true; ++ } ++ return QMainWindow::eventFilter(obj, event); ++ } ++ } ++ } ++ return QMainWindow::eventFilter(obj, event); ++} ++ ++QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State) ++{ ++ QAction * Act = new QAction(Label, parent); ++ if (Menu) ++ Menu->addAction(Act); ++ ++ Act->setCheckable(true); ++ if (State) ++ Act->setChecked(true); ++ ++ parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked())); ++ ++ Act->setFont(*menufont); ++ ++ return Act; ++} ++ ++// This now creates all window types - Term, Mon, Combined, Listen ++ ++int xCount = 0; ++int sessNo = 0; ++ ++Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label) ++{ ++ Ui_ListenSession * Sess = new(Ui_ListenSession); ++ ++ // Need to explicity initialise on Qt4 ++ ++ Sess->termWindow = NULL; ++ Sess->monWindow = NULL; ++ Sess->inputWindow = NULL; ++ ++ for (int i = 0; i < 50; i++) ++ Sess->KbdStack[i] = NULL; ++ ++ Sess->StackIndex = 0; ++ Sess->InputMode = 0; ++ Sess->SlowTimer = 0; ++ Sess->MonData = 0; ++ Sess->OutputSaveLen = 0; ++ Sess->MonSaveLen = 0; ++ Sess->PortMonString[0] = 0; ++ Sess->portmask = 0; ++ Sess->portmask = 1; ++ Sess->mtxparam = 1; ++ Sess->mlocaltime = 0; ++ Sess->mcomparam = 1; ++ Sess->monUI = 0; ++ Sess->MonitorNODES = 0; ++ Sess->MonitorColour = 1; ++ Sess->CurrentHost = 0; ++ ++ Sess->SessionType = Type; ++ Sess->clientSocket = NULL; ++ Sess->AGWSession = NULL; ++ Sess->AGWMonSession = NULL; ++ Sess->KISSSession = NULL; ++ Sess->KISSMode = 0; ++ Sess->TTActive = 0; ++ Sess->TTFlashToggle = 0; ++ Sess->pageBuffer[0] = 0; ++ Sess->Tab = 0; ++ ++ Sess->LogMonitor = false; ++ Sess->monSpan = (char *) ""; ++ Sess->monLogfile = nullptr; ++ Sess->sessNo = sessNo++; ++ ++ _sessions.append(Sess); ++ ++// Sess->TT = new Ui_TeleTextDialog(); ++ ++// Sess->TT->setupUi(&Sess->TTUI); ++ ++// Sess->TTUI.show(); ++// Sess->TTUI.raise(); ++// Sess->TTUI.activateWindow(); ++ ++ // Sess->setObjectName(QString::fromUtf8("Sess")); ++ ++ if (TermMode == MDI) ++ { ++ Sess->sw = mdiArea->addSubWindow(Sess); ++ // Sess->installEventFilter(parent); ++ ++ Sess->sw->resize(800, 600); ++ } ++ else if (TermMode == Tabbed) ++ { ++ Sess->Tab = xCount++; ++ ++ if (Type == Mon) ++ tabWidget->addTab(Sess, "Monitor"); ++ else ++ tabWidget->addTab(Sess, Label); ++ } ++ ++ Sess->installEventFilter(parent); ++ ++ QSettings settings(GetConfPath(), QSettings::IniFormat); ++ ++#ifdef ANDROID ++ QFont font = QFont(settings.value("FontFamily", "Driod Sans Mono").value(), ++ settings.value("PointSize", 12).toInt(), ++ settings.value("Weight", 50).toInt()); ++#else ++ QFont font = QFont(settings.value("FontFamily", "Courier New").value(), ++ settings.value("PointSize", 10).toInt(), ++ settings.value("Weight", 50).toInt()); ++#endif ++ ++ if ((Type & Mon)) ++ { ++ Sess->monWindow = new QTextEdit(Sess); ++ Sess->monWindow->setReadOnly(1); ++ Sess->monWindow->document()->setMaximumBlockCount(10000); ++ Sess->monWindow->setFont(font); ++ Sess->monWindow->setStyleSheet(monStyleSheet); ++ mythis->connect(Sess->monWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged())); ++ } ++ ++ if ((Type & (Listen | Term))) ++ { ++ Sess->termWindow = new QTextEdit(Sess); ++ Sess->termWindow->setReadOnly(1); ++ Sess->termWindow->document()->setMaximumBlockCount(10000); ++ Sess->termWindow->setFont(font); ++ Sess->termWindow->setStyleSheet(termStyleSheet); ++ ++ Sess->TTLabel = new QLabel(Sess); ++ Sess->TTLabel->setGeometry(QRect(0,0 ,500, 500)); ++ Sess->TTLabel->setVisible(false); ++ ++ Sess->TTBitmap = new QImage(40 * 15, 25 * 19, QImage::Format_RGB32); ++ Sess->TTBitmap->fill(Qt::black); ++ ++/* ++ ++ char Page[4096]; ++ ++ QFile file("/savepage.txt"); ++ file.open(QIODevice::ReadOnly); ++ file.read(Page, 4096); ++ file.close(); ++ ++ Sess->TTActive = 1; ++ strcpy(Sess->pageBuffer, Page); ++ DecodeTeleText(Sess, Sess->pageBuffer); ++ ++*/ ++ ++ Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); ++ ++ Sess->TTLabel->setContextMenuPolicy(Qt::CustomContextMenu); ++ mythis->connect(Sess->TTLabel, SIGNAL(customContextMenuRequested(const QPoint&)), ++ parent, SLOT(showContextMenuL())); ++ ++ mythis->connect(Sess->termWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged())); ++ ++ Sess->inputWindow = new QLineEdit(Sess); ++ Sess->inputWindow->installEventFilter(parent); ++ Sess->inputWindow->setFont(font); ++ Sess->inputWindow->setStyleSheet(inputStyleSheet); ++ Sess->inputWindow->setContextMenuPolicy(Qt::PreventContextMenu); ++ ++ mythis->connect(Sess->inputWindow, SIGNAL(selectionChanged()), parent, SLOT(onLEselectionChanged())); ++ } ++ ++ if (Type == Term || Type == Listen) ++ { ++ // Term Only or Listen Only ++ ++ Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu); ++ ++ mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)), ++ parent, SLOT(showContextMenuT(const QPoint &))); ++ ++ } ++ ++ if (Type == Mon) ++ { ++ // Monitor Only ++ ++ Sess->monWindow->setContextMenuPolicy(Qt::CustomContextMenu); ++ ++ mythis->connect(Sess->monWindow, SIGNAL(customContextMenuRequested(const QPoint&)), ++ parent, SLOT(showContextMenuMOnly(const QPoint &))); ++ ++ } ++ ++ if (Type == (Term | Mon)) ++ { ++ // Combined Term and Mon. Add Custom Menu to set Mon/Term Split with Right Click ++ ++ Sess->monWindow->setContextMenuPolicy(Qt::CustomContextMenu); ++ Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu); ++ ++ ++ mythis->connect(Sess->monWindow, SIGNAL(customContextMenuRequested(const QPoint&)), ++ parent, SLOT(showContextMenuM(const QPoint &))); ++ ++ mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)), ++ parent, SLOT(showContextMenuMT(const QPoint &))); ++ } ++ ++ if (Sess->SessionType == Mon) // Mon Only ++ Sess->setWindowTitle("Monitor Session Disconnected"); ++ else if (Sess->SessionType == Listen) // Mon Only ++ Sess->setWindowTitle("Listen Window Disconnected"); ++ else ++ Sess->setWindowTitle("Disconnected"); ++ ++ Sess->installEventFilter(mythis); ++ ++ Sess->show(); ++ ++ int pos = (_sessions.size() - 1) * 20; ++ ++ if (TermMode == MDI) ++ { ++ Sess->sw->move(pos, pos); ++ } ++ ++ QSize Size(800, 602); // Not actually used, but Event constructor needs it ++ ++ QResizeEvent event(Size, Size); ++ ++ QApplication::sendEvent(Sess, &event); // Resize Widgets to fix Window ++ ++ return Sess; ++} ++ ++QByteArray timeLoaded = QDateTime::currentDateTime().toString("yymmdd_hhmmss").toUtf8(); ++ ++QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent) ++{ ++ int i; ++ char Title[80]; ++ ++ // Get configuration path for MacOS. ++ std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString(); ++ std::string conf_path = directory + "/QtTermTCP.ini"; ++ ++ //mkdir(directory.c_str(), 0775); ++ ++ _server = new QTcpServer(); ++ ++ mythis = this; ++ ++ ui.setupUi(this); ++ ++ initUTF8(); ++ ++ mymenuBar = new QMenuBar(this); ++ mymenuBar->setGeometry(QRect(0, 0, 781, 26)); ++ setMenuBar(mymenuBar); ++ ++ toolBar = new QToolBar(this); ++ toolBar->setObjectName("mainToolbar"); ++ addToolBar(Qt::BottomToolBarArea, toolBar); ++ ++ QSettings mysettings(GetConfPath(), QSettings::IniFormat); ++ ++ restoreGeometry(mysettings.value("geometry").toByteArray()); ++ restoreState(mysettings.value("windowState").toByteArray()); ++ ++ GetSettings(); ++ ++ GetKeyWordFile(); ++ ++ // Set background colours ++ ++ sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);", ++ monBackground.red(), monBackground.green(), monBackground.blue()); ++ ++ sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);", ++ termBackground.red(), termBackground.green(), termBackground.blue()); ++ ++ sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", ++ inputText.red(), inputText.green(), inputText.blue(), ++ inputBackground.red(), inputBackground.green(), inputBackground.blue()); ++ ++ ++#ifdef ANDROID ++ menufont = new QFont(mysettings.value("MFontFamily", "Driod Sans").value(), ++ mysettings.value("MPointSize", 12).toInt(), ++ mysettings.value("MWeight", 50).toInt()); ++#else ++ menufont = new QFont(mysettings.value("MFontFamily", "Aerial").value(), ++ mysettings.value("MPointSize", 10).toInt(), ++ mysettings.value("MWeight", 50).toInt()); ++ ++#endif ++ if (TermMode == MDI) ++ { ++ mdiArea = new QMdiArea(ui.centralWidget); ++ mdiArea->setGeometry(QRect(0, 0, 771, 571)); ++ ++ mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ ++ connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(xon_mdiArea_changed())); ++ ++ setCentralWidget(mdiArea); ++ } ++ else if (TermMode == Tabbed) ++ { ++ Ui_ListenSession * Sess; ++ int index = 0; ++ ++ tabWidget = new QTabWidget(this); ++ QTabBar* tabBar = tabWidget->tabBar(); ++ ++// QString style1 = "QTabWidget::tab-bar{left:0;}"; // for Mac ++// tabWidget->setStyleSheet(style1); ++ ++ QString style = "QTabBar::tab:selected{background-color: #d0d0d0;} QTabBar::tab:!selected{background-color: #f0f0f0;}"; ++ ++ tabBar->setStyleSheet(style); ++ ++ tabWidget->setContextMenuPolicy(Qt::CustomContextMenu); ++ ++ connect(tabWidget, SIGNAL(customContextMenuRequested(const QPoint &)), SLOT(showContextMenu(const QPoint &))); ++ ++ ui.verticalLayout->addWidget(tabWidget); ++ tabWidget->setTabPosition(QTabWidget::South); ++ ++ Sess = newWindow(this, TabType[0], "Sess 1"); ++ Sess->CurrentHost = currentHost[index++]; ++ Sess = newWindow(this, TabType[1], "Sess 2"); ++ Sess->CurrentHost = currentHost[index++]; ++ Sess = newWindow(this, TabType[2], "Sess 3"); ++ Sess->CurrentHost = currentHost[index++]; ++ Sess = newWindow(this, TabType[3], "Sess 4"); ++ Sess->CurrentHost = currentHost[index++]; ++ Sess = newWindow(this, TabType[4], "Sess 5"); ++ Sess->CurrentHost = currentHost[index++]; ++ Sess = newWindow(this, TabType[5], "Sess 6"); ++ Sess->CurrentHost = currentHost[index++]; ++ Sess = newWindow(this, TabType[6], "Sess 7"); ++ Sess->CurrentHost = currentHost[index++]; ++ Sess = newWindow(this, TabType[7], "Monitor"); ++ Sess->CurrentHost = currentHost[index++]; ++ Sess = newWindow(this, TabType[8], "Monitor"); ++ Sess->CurrentHost = currentHost[index++]; ++ ++ ActiveSession = _sessions.at(0); ++ ++ connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSelected(int))); ++ ++ tabWidget->setFont(*menufont); ++ ++ } ++ ++ sprintf(Title, "QtTermTCP Version %s", VersionString); ++ ++ this->setWindowTitle(Title); ++ ++ //#ifdef ANDROID ++ // mymymenuBar->setVisible(false); ++ //#endif ++ ++ if (TermMode == Single) ++ windowMenu = mymenuBar->addMenu(""); ++ else ++ windowMenu = mymenuBar->addMenu(tr("&Window")); ++ ++ connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu())); ++ windowMenu->setFont(*menufont); ++ ++ newTermAct = new QAction(tr("New Terminal Window"), this); ++ connect(newTermAct, SIGNAL(triggered()), this, SLOT(doNewTerm())); ++ ++ newMonAct = new QAction(tr("New Monitor Window"), this); ++ connect(newMonAct, SIGNAL(triggered()), this, SLOT(doNewMon())); ++ ++ newCombinedAct = new QAction(tr("New Combined Term/Mon Window"), this); ++ connect(newCombinedAct, SIGNAL(triggered()), this, SLOT(doNewCombined())); ++ ++ if (TermMode == MDI) ++ { ++ closeAct = new QAction(tr("Cl&ose"), this); ++ closeAct->setStatusTip(tr("Close the active window")); ++ connect(closeAct, SIGNAL(triggered()), mdiArea, SLOT(closeActiveSubWindow())); ++ ++ closeAllAct = new QAction(tr("Close &All"), this); ++ closeAllAct->setStatusTip(tr("Close all the windows")); ++ connect(closeAllAct, SIGNAL(triggered()), mdiArea, SLOT(closeAllSubWindows())); ++ ++ tileAct = new QAction(tr("&Tile"), this); ++ tileAct->setStatusTip(tr("Tile the windows")); ++ connect(tileAct, SIGNAL(triggered()), mdiArea, SLOT(tileSubWindows())); ++ ++ cascadeAct = new QAction(tr("&Cascade"), this); ++ cascadeAct->setStatusTip(tr("Cascade the windows")); ++ connect(cascadeAct, SIGNAL(triggered()), this, SLOT(doCascade())); ++ ++ nextAct = new QAction(tr("Ne&xt"), this); ++ nextAct->setShortcuts(QKeySequence::NextChild); ++ nextAct->setStatusTip(tr("Move the focus to the next window")); ++ connect(nextAct, SIGNAL(triggered()), mdiArea, SLOT(activateNextSubWindow())); ++ ++ previousAct = new QAction(tr("Pre&vious"), this); ++ previousAct->setShortcuts(QKeySequence::PreviousChild); ++ previousAct->setStatusTip(tr("Move the focus to the previous window")); ++ connect(previousAct, SIGNAL(triggered()), mdiArea, SLOT(activatePreviousSubWindow())); ++ } ++ ++ quitAction = new QAction(tr("&Quit"), this); ++ connect(quitAction, SIGNAL(triggered()), this, SLOT(doQuit())); ++ ++ windowMenuSeparatorAct = new QAction(this); ++ windowMenuSeparatorAct->setSeparator(true); ++ ++ updateWindowMenu(); ++ ++ if (KISSEnable && KISSMH) ++ { ++ newMHWindow(this, 0, "KISS MH"); ++ MHWindow->restoreGeometry(mysettings.value("MHgeometry").toByteArray()); ++ } ++ ++ connectMenu = mymenuBar->addMenu(tr("&Connect")); ++ ++ actHost[16] = new QAction("AGW Connect", this); ++ actHost[16]->setFont(*menufont); ++ actHost[16]->setVisible(0); ++ connectMenu->addAction(actHost[16]); ++ ++ connect(actHost[16], SIGNAL(triggered()), this, SLOT(Connect())); ++ ++ actHost[17] = new QAction("VARA Connect", this); ++ actHost[17]->setFont(*menufont); ++ actHost[17]->setVisible(0); ++ connectMenu->addAction(actHost[17]); ++ ++ connect(actHost[17], SIGNAL(triggered()), this, SLOT(Connect())); ++ ++ actHost[18] = new QAction("KISS Connect", this); ++ actHost[18]->setFont(*menufont); ++ actHost[18]->setVisible(KISSEnable); ++ actHost[18]->setEnabled(0); ++ connectMenu->addAction(actHost[18]); ++ ++ connect(actHost[18], SIGNAL(triggered()), this, SLOT(Connect())); ++ ++ for (i = 0; i < MAXHOSTS; i++) ++ { ++ if (SessName[i][0]) ++ { ++ char Lable[256]; ++ sprintf(Lable, "%s(%s)", Host[i], SessName[i]); ++ actHost[i] = new QAction(Lable, this); ++ } ++ else ++ actHost[i] = new QAction(Host[i], this); ++ ++ actHost[i]->setFont(*menufont); ++ connectMenu->addAction(actHost[i]); ++ connect(actHost[i], SIGNAL(triggered()), this, SLOT(Connect())); ++ } ++ ++ discAction = mymenuBar->addAction("&Disconnect"); ++ ++ // Place discAction in mac app menu, otherwise it doesn't appear ++ if (is_mac == true) { ++ QMenu * app_menu = mymenuBar->addMenu("App Menu"); ++ discAction->setMenuRole(QAction::ApplicationSpecificRole); ++ app_menu->addAction(discAction); ++ ++ } ++ ++ connect(discAction, SIGNAL(triggered()), this, SLOT(Disconnect())); ++ discAction->setEnabled(false); ++ ++ toolBar->setFont(*menufont); ++ ++#ifndef ANDROID ++ toolBar->setVisible(false); ++#endif ++ but4 = new QToolButton(); ++ but4->setPopupMode(QToolButton::InstantPopup); ++ but4->setText("Window"); ++ but4->addAction(windowMenu->menuAction()); ++ but4->setFont(*menufont); ++ toolBar->addWidget(but4); ++ ++ but5 = new QToolButton(); ++ but5->setPopupMode(QToolButton::InstantPopup); ++ but5->setText("Connect"); ++ but5->addAction(connectMenu->menuAction()); ++ but5->setFont(*menufont); ++ ++ toolBar->addWidget(but5); ++ ++ toolBar->addAction(discAction); ++ ++ setupMenu = mymenuBar->addMenu(tr("&Setup")); ++ hostsubMenu = setupMenu->addMenu("Hosts"); ++ hostsubMenu->setFont(*menufont); ++ ++ for (i = 0; i < MAXHOSTS; i++) ++ { ++ if (Host[i][0]) ++ { ++ char Label[256]; ++ ++ if (SessName[i][0]) ++ sprintf(Label, "%s(%s)", Host[i], SessName[i]); ++ else ++ strcpy(Label, Host[i]); ++ ++ actSetup[i] = new QAction(Label, this); ++ } ++ else ++ actSetup[i] = new QAction("New Host", this); ++ ++ hostsubMenu->addAction(actSetup[i]); ++ connect(actSetup[i], SIGNAL(triggered()), this, SLOT(SetupHosts())); ++ ++ actSetup[i]->setFont(*menufont); ++ } ++ ++ ++ // Setup Presentation Options ++ ++ setupMenu->addSeparator()->setText(tr("Presentation")); ++ ++ QActionGroup * termGroup = new QActionGroup(this); ++ ++ singleAct = setupMenuLine(nullptr, (char *)"Single Window (Term + Mon)", this, (TermMode == Single) && (singlemodeFormat == Term + Mon)); ++ singleAct2 = setupMenuLine(nullptr, (char *)"Single Window (Term only)", this, (TermMode == Single) && (singlemodeFormat == Term)); ++ MDIAct = setupMenuLine(nullptr, (char *)"MDI", this, TermMode == MDI); ++ tabbedAct = setupMenuLine(nullptr, (char *)"Tabbed", this, TermMode == Tabbed); ++ ++ termGroup->addAction(singleAct); ++ termGroup->addAction(singleAct2); ++ termGroup->addAction(MDIAct); ++ termGroup->addAction(tabbedAct); ++ ++ setupMenu->addAction(singleAct); ++ setupMenu->addAction(singleAct2); ++ setupMenu->addAction(MDIAct); ++ setupMenu->addAction(tabbedAct); ++ setupMenu->addSeparator(); ++ AlertAction = new QAction("Sound Alerts Setup", this); ++ ++ setupMenu->addAction(AlertAction); ++ connect(AlertAction, SIGNAL(triggered()), this, SLOT(AlertSlot())); ++ AlertAction->setFont(*menufont); ++ setupMenu->addSeparator(); ++ ++ actFonts = new QAction("Terminal Font", this); ++ setupMenu->addAction(actFonts); ++ connect(actFonts, SIGNAL(triggered()), this, SLOT(doFonts())); ++ actFonts->setFont(*menufont); ++ ++ actmenuFont = new QAction("Menu Font", this); ++ setupMenu->addAction(actmenuFont); ++ connect(actmenuFont, SIGNAL(triggered()), this, SLOT(doMFonts())); ++ actmenuFont->setFont(*menufont); ++ ++ actColours = new QAction("Choose Colours", this); ++ setupMenu->addAction(actColours); ++ connect(actColours, SIGNAL(triggered()), this, SLOT(doColours())); ++ actColours->setFont(*menufont); ++ ++ setupMenu->addSeparator(); ++ ++ AGWAction = new QAction("AGW Setup", this); ++ setupMenu->addAction(AGWAction); ++ connect(AGWAction, SIGNAL(triggered()), this, SLOT(AGWSlot())); ++ AGWAction->setFont(*menufont); ++ ++ VARAAction = new QAction("VARA Setup", this); ++ setupMenu->addAction(VARAAction); ++ connect(VARAAction, SIGNAL(triggered()), this, SLOT(VARASlot())); ++ VARAAction->setFont(*menufont); ++ ++ KISSAction = new QAction("KISS Setup", this); ++ setupMenu->addAction(KISSAction); ++ connect(KISSAction, SIGNAL(triggered()), this, SLOT(KISSSlot())); ++ KISSAction->setFont(*menufont); ++ ++ setupMenu->addSeparator(); ++ ++ actChatMode = setupMenuLine(setupMenu, (char *)"Chat Terminal Mode (Send Keepalives)", this, ChatMode); ++ actAutoTeletext = setupMenuLine(setupMenu, (char *)"Auto switch to Teletext", this, AutoTeletext); ++ actStripLF = setupMenuLine(setupMenu, (char *)"Strip Line Feeds", this, StripLF); ++ ++ setupMenu->addSeparator(); ++ ++ setupMenu->addAction(new QAction("Interpret non-UTF8 input as:", this)); ++ setupMenu->setFont(*menufont); ++ ++ QActionGroup * cpGroup = new QActionGroup(this); ++ ++ actnoConv = setupMenuLine(nullptr, (char *)" Don't Convert (assume is UTF-8)", this, convUTF8 == -1); ++ actAuto = setupMenuLine(nullptr, (char *)" Auto", this, convUTF8 == 0); ++ actCP1251 = setupMenuLine(nullptr, (char *)" CP1251 (Cyrillic)", this, convUTF8 == 1251); ++ actCP1252 = setupMenuLine(nullptr, (char *)" CP1252 (Western Europe)", this, convUTF8 == 1252); ++ actCP437 = setupMenuLine(nullptr, (char *)" CP437 (Windows Line Draw)", this, convUTF8 == 437); ++ ++ cpGroup->addAction(actnoConv); ++ cpGroup->addAction(actAuto); ++ cpGroup->addAction(actCP1251); ++ cpGroup->addAction(actCP1252); ++ cpGroup->addAction(actCP437); ++ ++ setupMenu->addAction(actnoConv); ++ setupMenu->addAction(actAuto); ++ setupMenu->addAction(actCP1251); ++ setupMenu->addAction(actCP1252); ++ setupMenu->addAction(actCP437); ++ ++ monitorMenu = mymenuBar->addMenu(tr("&Monitor")); ++ ++ EnableMonitor = setupMenuLine(monitorMenu, (char *)"Enable Monitoring", this, 0); ++ EnableMonitor->setVisible(0); ++ EnableMonLog = setupMenuLine(monitorMenu, (char *)"Log to File", this, 0); ++ MonLocalTime = setupMenuLine(monitorMenu, (char *)"Use local time", this, 0); ++ MonTX = setupMenuLine(monitorMenu, (char *)"Monitor TX", this, 1); ++ MonSup = setupMenuLine(monitorMenu, (char *)"Monitor Supervisory", this, 1); ++ MonUI = setupMenuLine(monitorMenu, (char *)"Only Monitor UI Frames", this, 0); ++ MonNodes = setupMenuLine(monitorMenu, (char *)"Monitor NODES Broadcasts", this, 0); ++ MonColour = setupMenuLine(monitorMenu, (char *)"Enable Colour", this, 1); ++ ++ for (i = 0; i < MAXPORTS + 1; i++) ++ { ++ MonPort[i] = setupMenuLine(monitorMenu, (char *)"Port", this, 0); ++ MonPort[i]->setVisible(false); ++ } ++ ++ but1 = new QToolButton(); ++ but1->setPopupMode(QToolButton::InstantPopup); ++ but1->setText("Monitor"); ++ but1->addAction(monitorMenu->menuAction()); ++ toolBar->addWidget(but1); ++ ++ but2 = new QToolButton(); ++ but2->setPopupMode(QToolButton::InstantPopup); ++ but2->setText("Setup"); ++ but2->addAction(setupMenu->menuAction()); ++ toolBar->addWidget(but2); ++ ++ ListenAction = mymenuBar->addAction("&Listen"); ++ connect(ListenAction, SIGNAL(triggered()), this, SLOT(ListenSlot())); ++ ++ ++ // Place Listen Action in mac app menu, otherwise it doesn't appear ++ if (is_mac == true) ++ { ++ QMenu * app_menu = mymenuBar->addMenu("App Menu"); ++ ListenAction->setMenuRole(QAction::ApplicationSpecificRole); ++ app_menu->addAction(ListenAction); ++ } ++ ++ toolBar->addAction(ListenAction); ++ ++ YAPPMenu = mymenuBar->addMenu(tr("&YAPP")); ++ ++ YAPPSend = new QAction("Send File", this); ++ YAPPSetRX = new QAction("Set Receive Directory", this); ++ YAPPSetSize = new QAction("Set Max Size", this); ++ YAPPSend->setFont(*menufont); ++ YAPPSetRX->setFont(*menufont); ++ YAPPSetSize->setFont(*menufont); ++ ++ YAPPMenu->addAction(YAPPSend); ++ YAPPMenu->addAction(YAPPSetRX); ++ YAPPMenu->addAction(YAPPSetSize); ++ YAPPSend->setEnabled(false); ++ ++ connect(YAPPSend, SIGNAL(triggered()), this, SLOT(doYAPPSend())); ++ connect(YAPPSetRX, SIGNAL(triggered()), this, SLOT(doYAPPSetRX())); ++ connect(YAPPSetSize, SIGNAL(triggered()), this, SLOT(doYAPPSetSize())); ++ ++ but3 = new QToolButton(); ++ but3->setPopupMode(QToolButton::InstantPopup); ++ but3->setText("YAPP"); ++ but3->addAction(YAPPMenu->menuAction()); ++ but3->setFont(*menufont); ++ toolBar->addWidget(but3); ++ ++ toolBar->setFont(*menufont); ++ ++ // Set up Status Bar ++ ++ setStyleSheet("QStatusBar{border-top: 1px outset black;} QStatusBar::item { border: 1px solid black; border-radius: 3px;}"); ++ // setStyleSheet("QStatusBar{border-top: 1px outset black;}"); ++ ++ ++ Status4 = new QLabel(""); ++ Status3 = new QLabel(" "); ++ Status2 = new QLabel(" "); ++ Status1 = new QLabel(" Disconnected "); ++ ++ Status1->setMinimumWidth(100); ++ Status2->setMinimumWidth(100); ++ Status3->setMinimumWidth(100); ++ Status4->setMinimumWidth(100); ++ ++ myStatusBar = statusBar(); ++ ++ statusBar()->addPermanentWidget(Status4); ++ statusBar()->addPermanentWidget(Status3); ++ statusBar()->addPermanentWidget(Status2); ++ statusBar()->addPermanentWidget(Status1); ++ ++ statusBar()->setVisible(AGWEnable | VARAEnable | KISSEnable); ++ // Restore saved sessions ++ ++ if (TermMode == Single) ++ { ++ Ui_ListenSession * Sess = newWindow(this, singlemodeFormat); ++ ++ ActiveSession = Sess; ++ Sess->CurrentHost = currentHost[0]; ++ ++ ui.verticalLayout->addWidget(Sess); ++ ++ connectMenu->setEnabled(true); ++ discAction->setEnabled(false); ++ YAPPSend->setEnabled(false); ++ } ++ ++ if (TermMode == MDI) ++ { ++ int n = atoi(sessionList); ++ int index = 0; ++ ++ char *p, *Context; ++ char delim[] = "|"; ++ ++ int type = 0, host = 0, topx, leftx, bottomx, rightx; ++ ++ p = strtok_s((char *)sessionList, delim, &Context); ++ ++ while (n--) ++ { ++ p = strtok_s(NULL, delim, &Context); ++ ++ sscanf(p, "%d,%d,%d,%d,%d,%d", &type, &host, &topx, &leftx, &bottomx, &rightx); ++ ++ Ui_ListenSession * Sess = newWindow(this, type); ++ ++ Sess->CurrentHost = currentHost[index++];; ++ ++ QRect r(leftx, topx, rightx - leftx, bottomx - topx); ++ ++ Sess->sw->setGeometry(r); ++ Sess->sw->move(leftx, topx); ++ ++ } ++ } ++ ++ QTimer *timer = new QTimer(this); ++ connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); ++ timer->start(10000); ++ ++ QTimer *timer2 = new QTimer(this); ++ connect(timer2, SIGNAL(timeout()), this, SLOT(KISSTimerSlot())); ++ timer2->start(100); ++ ++ QTimer *timer3 = new QTimer(this); ++ connect(timer3, SIGNAL(timeout()), this, SLOT(SlowTimerSlot())); ++ timer3->start(60000); ++ ++ // 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(KISSMYCALL, axMYCALL); ++ ++ // Do any autoconnects ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ if (AutoConnect[i] > 0) ++ { ++ Ui_ListenSession * Sess = _sessions.at(i); ++ ++ Sess->clientSocket = new myTcpSocket(); ++ Sess->clientSocket->Sess = Sess; ++ ++ connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); ++ connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); ++ connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); ++ ++ Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]); ++ } ++ } ++ ++} ++ ++void QtTermTCP::showContextMenu(const QPoint &point) ++{ ++ if (point.isNull()) ++ return; ++ ++ QTabBar* tabBar = tabWidget->tabBar(); ++ QRect Wrect = tabWidget->rect(); ++ QRect Brect = tabBar->rect(); ++ QPoint myPoint = point; ++ ++ // Get x coordinate of first tab (on Mac tabs are centre aligned) ++ ++ QRect rect = tabWidget->tabBar()->geometry(); ++ int left = rect.left(); ++ ++ ++ int n = myPoint.y() - (Wrect.height() - Brect.height()); ++ myPoint.setY(n); ++ n = myPoint.x() - left; ++ ++ myPoint.setX(n); ++ ++ int tabIndex = tabBar->tabAt(myPoint); ++ ++ QMenu menu(this); ++ ++ QAction * Act = new QAction("AutoConnect on load", this); ++ Act->setObjectName(QString::number(tabIndex)); ++ ++ menu.addAction(Act); ++ ++ Act->setCheckable(true); ++ ++ if (AutoConnect[tabIndex] <= 0) ++ Act->setChecked(false); ++ else ++ Act->setChecked(true); ++ ++ connect(Act, SIGNAL(triggered()), this, SLOT(autoConnectChecked())); ++ ++ menu.exec(tabWidget->mapToGlobal(point)); ++ ++} ++ ++void QtTermTCP::autoConnectChecked() ++{ ++ QAction * Act = static_cast(QObject::sender()); ++ QString Tab = Act->objectName(); ++ int tabNo = Tab.toInt(); ++ ++ tabWidget->setCurrentIndex(tabNo); ++ ++ Ui_ListenSession *Sess = (Ui_ListenSession *)tabWidget->currentWidget(); ++ int state = Act->isChecked(); ++ ++ if (state == 0) ++ AutoConnect[tabNo] = 0; ++ else ++ { ++ if (Sess->clientSocket) // Connected ++ AutoConnect[tabNo] = 1; ++ else ++ AutoConnect[tabNo] = 0; ++ } ++} ++ ++ ++void QtTermTCP::setFonts() ++{ ++ windowMenu->menuAction()->setFont(*menufont); ++ connectMenu->menuAction()->setFont(*menufont); ++ setupMenu->menuAction()->setFont(*menufont); ++ monitorMenu->menuAction()->setFont(*menufont); ++ YAPPMenu->menuAction()->setFont(*menufont); ++ ++ if (tabWidget) ++ tabWidget->setFont(*menufont); ++ mymenuBar->setFont(*menufont); ++ toolBar->setFont(*menufont); ++ but1->setFont(*menufont); ++ but2->setFont(*menufont); ++ but3->setFont(*menufont); ++ but4->setFont(*menufont); ++ but5->setFont(*menufont); ++ discAction->setFont(*menufont); ++ ListenAction->setFont(*menufont); ++ ++ for (int i = 0; i < MAXHOSTS; i++) ++ { ++ actHost[i]->setFont(*menufont); ++ actSetup[i]->setFont(*menufont); ++ } ++ ++ actHost[16]->setFont(*menufont); // AGW Host ++} ++ ++void QtTermTCP::doQuit() ++{ ++ if (_server->isListening()) ++ _server->close(); ++ ++ SaveSettings(); ++ ++ QCoreApplication::quit(); ++} ++ ++void FlashifNotActive() ++{ ++ if (!mythis->isActiveWindow()) ++ QApplication::alert(mythis, 0); ++} ++ ++ ++// "Copy on select" Code ++ ++ ++void QtTermTCP::onTEselectionChanged() ++{ ++ QTextEdit * x = static_cast(QObject::sender()); ++ ++ if (isActiveWindow()) ++ x->copy(); ++} ++ ++void QtTermTCP::onLEselectionChanged() ++{ ++ QLineEdit * x = static_cast(QObject::sender()); ++ if (isActiveWindow()) ++ x->copy(); ++} ++ ++void QtTermTCP::setVDMode() ++{ ++ QAction * sender = static_cast(QObject::sender()); ++ ++ QTextEdit * window = static_cast(sender->parentWidget()); ++ ++ // Need to find session with this window as owner ++ ++ Ui_ListenSession * Sess = NULL; ++ ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->termWindow == window) ++ { ++ Sess->TTActive ^= 1; ++ DoTermResize(Sess); ++ break; ++ } ++ } ++} ++ ++int splitY; // Value when menu added ++ ++void QtTermTCP::setSplit() ++{ ++ QAction * sender = static_cast(QObject::sender()); ++ ++ QWidget * Parent = sender->parentWidget(); ++ ++ if (Parent) ++ Parent = Parent->parentWidget(); ++ ++ int y = Parent->rect().height() - 50; ++ ++ // y is height of whole windom. splitX is new split position ++ // So split = 100 * splitx/x ++ ++ Split = (splitY * 100) / y; ++ ++ if (Split < 10) ++ Split = 10; ++ else if (Split > 90) ++ Split = 90; ++ ++ QSize size(800, 602); ++ QResizeEvent event(size, size); ++ ++ eventFilter(Parent, &event); ++} ++ ++void QtTermTCP::ClearScreen() ++{ ++ QAction * sender = static_cast(QObject::sender()); ++ QTextEdit * window = static_cast(sender->parentWidget()); ++ window->clear(); ++} ++ ++ ++void QtTermTCP::showContextMenuMT(const QPoint &pt) // Term Window ++{ ++ // Monitor and Terminal (Term Half) ++ ++ QTextEdit* sender = static_cast(QObject::sender()); ++ ++ QMenu *menu = sender->createStandardContextMenu(); ++ ++ QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}QMenu::separator {height: 2px;background: rgb(58, 80, 116);margin-left: 10px;margin-right: 5px;}"; ++ menu->setStyleSheet(style); ++ ++ QAction * actSplit = new QAction("Set Monitor/Output Split", sender); ++ QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender); ++ QAction * actClear = new QAction("Clear Screen Buffer", sender); ++ ++ menu->addAction(actSplit); ++ menu->addAction(actVDMode); ++ menu->addAction(actClear); ++ ++ splitY = pt.y() + termX; ++ ++ connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit())); ++ connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode())); ++ connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); ++ ++ menu->exec(sender->mapToGlobal(pt)); ++ delete menu; ++} ++ ++void QtTermTCP::showContextMenuMOnly(const QPoint &pt) ++{ ++ // Monitor only ++ ++ QTextEdit* sender = static_cast(QObject::sender()); ++ ++ QMenu *menu = sender->createStandardContextMenu(); ++ ++ QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}QMenu::separator {height: 2px;background: rgb(58, 80, 116);margin-left: 10px;margin-right: 5px;}"; ++ menu->setStyleSheet(style); ++ ++ QAction * actClear = new QAction("Clear Screen Buffer", sender); ++ ++ menu->addAction(actClear); ++ connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); ++ ++ menu->exec(sender->mapToGlobal(pt)); ++ delete menu; ++} ++ ++ ++void QtTermTCP::showContextMenuT(const QPoint &pt) // Term Window ++{ ++ // Just Terminal ++ ++ QTextEdit* sender = static_cast(QObject::sender()); ++ ++ QMenu *menu = sender->createStandardContextMenu(); ++ ++ QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}"; ++ menu->setStyleSheet(style); ++ ++ ++ QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender); ++ QAction * actClear = new QAction("Clear Screen Buffer", sender); ++ ++ menu->addAction(actVDMode); ++ menu->addAction(actClear); ++ ++ connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode())); ++ connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); ++ ++ menu->exec(sender->mapToGlobal(pt)); ++ delete menu; ++} ++ ++ ++void QtTermTCP::showContextMenuL() // Term Window ++{ ++ // Teletext Label Right Clicked - cancel TT Mode ++ ++ QLabel * sender = static_cast(QObject::sender()); ++ ++ // Need to find session with this label as owner ++ ++ Ui_ListenSession * Sess = NULL; ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->TTLabel == sender) ++ { ++ Sess->TTActive ^= 1; ++ ++ DoTermResize(Sess); ++ break; ++ } ++ } ++} ++ ++ ++void QtTermTCP::showContextMenuM(const QPoint &pt) // Mon Window ++{ ++ QTextEdit* sender = static_cast(QObject::sender()); ++ ++ QMenu *menu = sender->createStandardContextMenu(); ++ QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}"; ++ menu->setStyleSheet(style); ++ ++ QAction * actSplit = new QAction("Set Monitor/Output Split", sender); ++ QAction * actClear = new QAction("Clear Screen Buffer", sender); ++ ++ menu->addAction(actSplit); ++ menu->addAction(actClear); ++ ++ splitY = pt.y(); ++ ++ connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit())); ++ connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); ++ ++ menu->exec(sender->mapToGlobal(pt)); ++ delete menu; ++} ++ ++extern "C" void setMenus(int State) ++{ ++ // Sets Connect, Disconnect and YAPP Send enable flags to match connection state ++ ++ if (State) ++ { ++ connectMenu->setEnabled(false); ++ discAction->setEnabled(true); ++ YAPPSend->setEnabled(true); ++ } ++ else ++ { ++ connectMenu->setEnabled(true); ++ discAction->setEnabled(false); ++ YAPPSend->setEnabled(false); ++ } ++} ++ ++extern "C" void SetSessLabel(Ui_ListenSession * Sess, char * label) ++{ ++ if (TermMode == MDI) ++ Sess->setWindowTitle(label); ++ else if (TermMode == Tabbed) ++ tabWidget->setTabText(Sess->Tab, label); ++ else if (TermMode == Single) ++ mythis->setWindowTitle(label); ++} ++ ++ ++extern "C" void ClearSessLabel(Ui_ListenSession * Sess) ++{ ++ if (TermMode == MDI) ++ { ++ if (Sess->SessionType == Mon) // Mon Only ++ Sess->setWindowTitle("Monitor Session Disconnected"); ++ else if (Sess->SessionType == Listen) // Mon Only ++ Sess->setWindowTitle("Listen Window Disconnected"); ++ else ++ Sess->setWindowTitle("Disconnected"); ++ } ++ else if (TermMode == Tabbed) ++ { ++ if (Sess->SessionType == Mon) // Mon Only ++ tabWidget->setTabText(Sess->Tab, "Monitor"); ++ else ++ { ++ char Label[16]; ++ sprintf(Label, "Sess %d", Sess->Tab + 1); ++ tabWidget->setTabText(Sess->Tab, Label); ++ } ++ } ++ else if (TermMode == Single) ++ { ++ if (Sess->SessionType == Mon) // Mon Only ++ mythis->setWindowTitle("Monitor Session Disconnected"); ++ else ++ mythis->setWindowTitle("Disconnected"); ++ } ++} ++ ++void QtTermTCP::tabSelected(int Current) ++{ ++ Ui_ListenSession * Sess = NULL; ++ ++ if (Current < _sessions.size()) ++ { ++ Sess = _sessions.at(Current); ++ ++ if (Sess == nullptr) ++ return; ++ ++ ActiveSession = Sess; ++ ++ tabWidget->tabBar()->setTabTextColor(tabWidget->currentIndex(), oldTabText); ++ ++ if (Sess->clientSocket || Sess->AGWSession || Sess->KISSSession || Sess->KISSMode) ++ { ++ connectMenu->setEnabled(false); ++ discAction->setEnabled(true); ++ YAPPSend->setEnabled(true); ++ } ++ else ++ { ++ connectMenu->setEnabled(true); ++ discAction->setEnabled(false); ++ YAPPSend->setEnabled(false); ++ } ++ ++ // If a monitor Window, change Monitor config settings ++ ++ EnableMonLog->setChecked(Sess->LogMonitor); ++ ++ if (AGWUsers && Sess == AGWUsers->MonSess) // AGW Monitor ++ { ++ for (int i = 0; i < 64; i++) ++ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden ++ ++ connectMenu->setEnabled(false); ++ MonTX->setVisible(0); ++ MonSup->setVisible(0); ++ MonUI->setVisible(0); ++ MonColour->setVisible(0); ++ ++ EnableMonitor->setVisible(1); ++ EnableMonitor->setChecked(AGWMonEnable); ++ MonLocalTime->setChecked(Sess->mlocaltime); ++ MonNodes->setChecked(Sess->MonitorNODES); ++ } ++ else if (Sess == KISSMonSess) // KISS Monitor ++ { ++ for (int i = 0; i < 64; i++) ++ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden ++ ++ connectMenu->setEnabled(false); ++ MonTX->setVisible(0); ++ MonSup->setVisible(0); ++ MonUI->setVisible(0); ++ MonColour->setVisible(0); ++ ++ EnableMonitor->setVisible(1); ++ EnableMonitor->setChecked(KISSMonEnable); ++ MonLocalTime->setChecked(Sess->mlocaltime); ++ MonNodes->setChecked(Sess->MonitorNODES); ++ } ++ else ++ { ++ EnableMonitor->setVisible(0); ++ MonTX->setVisible(1); ++ MonSup->setVisible(1); ++ MonUI->setVisible(1); ++ MonColour->setVisible(1); ++ } ++ ++ if (Sess->PortMonString[0]) ++ { ++ char * ptr = (char *)malloc(2048); ++ memcpy(ptr, Sess->PortMonString, 2048); ++ ++ int NumberofPorts = atoi((char *)&ptr[2]); ++ char *p, *Context; ++ char msg[80]; ++ int portnum, m; ++ char delim[] = "|"; ++ ++ // Remove old Monitor menu ++ ++ for (int i = 0; i < 64; i++) ++ { ++ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden ++ } ++ ++ p = strtok_s((char *)&ptr[2], delim, &Context); ++ ++ while (NumberofPorts--) ++ { ++ p = strtok_s(NULL, delim, &Context); ++ if (p == NULL) ++ break; ++ ++ m = portnum = atoi(p); ++ ++ sprintf(msg, "Port %s", p); ++ ++ if (m == 0) ++ m = 64; ++ ++ if (Sess->portmask & ((uint64_t)1 << (m - 1))) ++ SetPortMonLine(portnum, msg, 1, 1); ++ else ++ SetPortMonLine(portnum, msg, 1, 0); ++ } ++ free(ptr); ++ ++ MonLocalTime->setChecked(Sess->mlocaltime); ++ MonTX->setChecked(Sess->mtxparam); ++ MonSup->setChecked(Sess->mcomparam); ++ MonUI->setChecked(Sess->monUI); ++ MonNodes->setChecked(Sess->MonitorNODES); ++ MonColour->setChecked(Sess->MonitorColour); ++ } ++ return; ++ } ++} ++ ++void QtTermTCP::SetupHosts() ++{ ++ QAction * Act = static_cast(QObject::sender()); ++ int i; ++ ++ for (i = 0; i < MAXHOSTS; i++) ++ { ++ if (Act == actSetup[i]) ++ break; ++ } ++ ++ if (i > 15) ++ return; ++ ++ ConfigHost = i; ++ ++ TabDialog tabdialog(0); ++ tabdialog.exec(); ++} ++ ++ ++void QtTermTCP::Connect() ++{ ++ QMdiSubWindow * UI; ++ Ui_ListenSession * Sess = nullptr; ++ QAction * Act = static_cast(QObject::sender()); ++ ++ int i; ++ ++ for (i = 0; i < MAXHOSTS; i++) ++ { ++ if (Act == actHost[i]) ++ break; ++ } ++ ++ SavedHost = i; // Last used ++ ++ if (TermMode == MDI) ++ { ++ UI = mdiArea->activeSubWindow(); ++ ++ for (i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->sw == UI) ++ break; ++ } ++ ++ if (i == _sessions.size()) ++ return; ++ ++ currentHost[i] = SavedHost; ++ } ++ ++ else if (TermMode == Tabbed) ++ { ++ Sess = (Ui_ListenSession *)tabWidget->currentWidget(); ++ } ++ ++ else if (TermMode == Single) ++ Sess = _sessions.at(0); ++ ++ if ((Sess == nullptr || Sess->SessionType & Listen)) ++ return; ++ ++ Sess->CurrentHost = SavedHost; ++ ++ currentHost[Sess->Tab] = SavedHost; ++ ++ if (Act == actHost[16]) ++ { ++ // This runs the AGW Connection dialog ++ ++ Sess->CurrentHost = 16; // Iast used ++ AGWConnect dialog(0); ++ dialog.exec(); ++ return; ++ } ++ ++ ++ if (Act == actHost[17]) ++ { ++ // This runs the VARA Connection dialog ++ ++ Sess->CurrentHost = 17; // Iast used ++ VARADataSock->Sess = Sess; ++ VARASock->Sess = Sess; ++ ++ VARAConnect dialog(0); ++ dialog.exec(); ++ WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); ++ ++ return; ++ } ++ ++ if (Act == actHost[18]) ++ { ++ // This runs the KISS Connection dialog ++ ++ Sess->CurrentHost = 18; // Iast used ++ ++ KISSConnect dialog(0); ++ dialog.exec(); ++ return; ++ } ++ ++ // Set Monitor Params for this host ++ ++ sscanf(MonParams[Sess->CurrentHost], "%llx %x %x %x %x %x", ++ &Sess->portmask, &Sess->mtxparam, &Sess->mcomparam, ++ &Sess->MonitorNODES, &Sess->MonitorColour, &Sess->monUI); ++ ++ Sess->mlocaltime = (Sess->mtxparam >> 7); ++ Sess->mtxparam &= 1; ++ ++ MonLocalTime->setChecked(Sess->mlocaltime); ++ MonTX->setChecked(Sess->mtxparam); ++ MonSup->setChecked(Sess->mcomparam); ++ MonUI->setChecked(Sess->monUI); ++ MonNodes->setChecked(Sess->MonitorNODES); ++ MonColour->setChecked(Sess->MonitorColour); ++ ++ // Remove old Monitor menu ++ ++ for (i = 0; i < 64; i++) ++ { ++ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden ++ } ++ ++ delete(Sess->clientSocket); ++ ++ Sess->clientSocket = new myTcpSocket(); ++ Sess->clientSocket->Sess = Sess; ++ ++ connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); ++ connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); ++ connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); ++ ++ Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]); ++ return; ++} ++ ++extern "C" void rst_timer(TAX25Port * AX25Sess); ++extern "C" void set_unlink(TAX25Port * AX25Sess, Byte * path); ++ ++void QtTermTCP::Disconnect() ++{ ++ QMdiSubWindow * UI; ++ Ui_ListenSession * Sess = nullptr; ++ ++ if (TermMode == MDI) ++ { ++ int i; ++ ++ UI = mdiArea->activeSubWindow(); ++ ++ for (i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->sw == UI) ++ break; ++ } ++ ++ if (i == _sessions.size()) ++ return; ++ } ++ ++ else if (TermMode == Tabbed) ++ { ++ Sess = (Ui_ListenSession *)tabWidget->currentWidget(); ++ } ++ ++ else if (TermMode == Single) ++ Sess = _sessions.at(0); ++ ++ // if AGW send a d frame else disconnect TCP session ++ ++ if (Sess->AGWSession) ++ Send_AGW_Ds_Frame(Sess->AGWSession); ++ else if (VARASock && VARASock->Sess == Sess) ++ VARASock->write("DISCONNECT\r"); ++ else if (Sess->KISSSession) ++ { ++ if (Sess->KISSMode == 0) ++ { ++ TAX25Port * Port = (TAX25Port *)Sess->KISSSession; ++ ++ rst_timer(Port); ++ set_unlink(Port, Port->Path); ++ } ++ else ++ { ++ // KISS UI Mode ++ ++ char Msg[128]; ++ int Len = sprintf(Msg, "Disconnected\r"); ++ ++ Sess->KISSMode = 0; ++ SendtoTerm(Sess, Msg, Len); ++ ClearSessLabel(Sess); ++ setMenus(0); ++ Sess->KISSSession = NULL; ++ } ++ } ++ else ++ ++ { ++ if (Sess && Sess->clientSocket) ++ Sess->clientSocket->disconnectFromHost(); ++ } ++ return; ++} ++ ++ ++void QtTermTCP::doYAPPSend() ++{ ++ QFileDialog dialog(this); ++ QStringList fileNames; ++ dialog.setFileMode(QFileDialog::AnyFile); ++ ++ QMdiSubWindow * UI; ++ Ui_ListenSession * Sess = nullptr; ++ int i; ++ ++ if (TermMode == MDI) ++ { ++ UI = mdiArea->activeSubWindow(); ++ ++ for (i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->sw == UI) ++ break; ++ } ++ ++ if (i == _sessions.size()) ++ return; ++ } ++ ++ else if (TermMode == Tabbed) ++ { ++ Sess = (Ui_ListenSession *)tabWidget->currentWidget(); ++ } ++ ++ else if (TermMode == Single) ++ Sess = _sessions.at(0); ++ ++ if (Sess == nullptr) ++ return; ++ ++ if ((Sess->SessionType & Mon)) ++ { ++ // Turn off monitoring ++ ++ setTraceOff(Sess); ++ } ++ ++ if (dialog.exec()) ++ { ++ char FN[256]; ++ ++ fileNames = dialog.selectedFiles(); ++ if (fileNames[0].length() < 256) ++ { ++ strcpy(FN, fileNames[0].toUtf8()); ++ YAPPSendFile(Sess, FN); ++ } ++ } ++} ++ ++void QtTermTCP::doYAPPSetRX() ++{ ++ QFileDialog dialog(this); ++ QStringList fileNames; ++ dialog.setFileMode(QFileDialog::Directory); ++ dialog.setDirectory(YAPPPath); ++ ++ if (dialog.exec()) ++ { ++ fileNames = dialog.selectedFiles(); ++ if (fileNames[0].length() < 256) ++ strcpy(YAPPPath, fileNames[0].toUtf8()); ++ ++ SaveSettings(); ++ } ++} ++ ++Ui_SizeDialog * YappSize; ++ ++void QtTermTCP::doYAPPSetSize() ++{ ++ // This runs the VARA Configuration dialog ++ ++ char valChar[80]; ++ ++ YappSize = new(Ui_SizeDialog); ++ ++ QDialog UI; ++ ++ YappSize->setupUi(&UI); ++ ++ UI.setFont(*menufont); ++ deviceUI = &UI; ++ ++ sprintf(valChar, "%d", MaxRXSize); ++ ++ YappSize->maxSize->setText(valChar); ++ ++ QObject::connect(YappSize->okButton, SIGNAL(clicked()), this, SLOT(sizeaccept())); ++ QObject::connect(YappSize->cancelButton, SIGNAL(clicked()), this, SLOT(sizereject())); ++ ++ UI.exec(); ++} ++ ++void QtTermTCP::sizeaccept() ++{ ++ QVariant Q; ++ Q = YappSize->maxSize->text(); ++ ++ MaxRXSize = Q.toInt(); ++ SaveSettings(); ++ delete(YappSize); ++} ++ ++ ++void QtTermTCP::sizereject() ++{ ++ delete(YappSize); ++ deviceUI->reject(); ++} ++ ++ ++void QtTermTCP::menuChecked() ++{ ++ QAction * Act = static_cast(QObject::sender()); ++ ++ int state = Act->isChecked(); ++ int newTermMode = TermMode; ++ int newSingleMode = singlemodeFormat; ++ ++ if (Act == TabSingle || Act == TabBoth || Act == TabMon) ++ { ++ // Tabbed Window format had changed ++ ++ int i = tabWidget->currentIndex(); ++ ++ if (Act == TabSingle) ++ TabType[i] = Term; ++ else if (Act == TabBoth) ++ TabType[i] = Term + Mon; ++ else ++ TabType[i] = Mon; ++ ++ QMessageBox msgBox; ++ msgBox.setText("Tab Types will change next time program is started."); ++ msgBox.exec(); ++ ++ } ++ ++ if (Act == singleAct || Act == singleAct2 || Act == MDIAct || Act == tabbedAct) ++ { ++ // Term Mode had changed ++ ++ if (singleAct->isChecked()) ++ { ++ newTermMode = Single; ++ newSingleMode = Mon + Term; ++ } ++ else if (singleAct2->isChecked()) ++ { ++ newTermMode = Single; ++ newSingleMode = Term; ++ } ++ else if (MDIAct->isChecked()) ++ newTermMode = MDI; ++ else if (tabbedAct->isChecked()) ++ newTermMode = Tabbed; ++ ++ if (newTermMode != TermMode || newSingleMode != singlemodeFormat) ++ { ++ QSettings settings(GetConfPath(), QSettings::IniFormat); ++ settings.setValue("TermMode", newTermMode); ++ settings.setValue("singlemodeFormat", newSingleMode); ++ QMessageBox msgBox; ++ msgBox.setText("Presentation Mode will change next time program is started."); ++ msgBox.exec(); ++ } ++ ++ return; ++ } ++ ++ if (Act == EnableMonitor) ++ ActiveSession->EnableMonitor = state; ++ else if (Act == EnableMonLog) ++ ActiveSession->LogMonitor = state; ++ else if (Act == MonLocalTime) ++ ActiveSession->mlocaltime = state; ++ else if (Act == MonTX) ++ ActiveSession->mtxparam = state; ++ else if (Act == MonSup) ++ ActiveSession->mcomparam = state; ++ else if (Act == MonUI) ++ ActiveSession->monUI = state; ++ else if (Act == MonNodes) ++ ActiveSession->MonitorNODES = state; ++ else if (Act == MonColour) ++ ActiveSession->MonitorColour = state; ++ else if (Act == actChatMode) ++ ChatMode = state; ++ else if (Act == actAutoTeletext) ++ AutoTeletext = state; ++ else if (Act == actBells) ++ Bells = state; ++ else if (Act == actStripLF) ++ StripLF = state; ++ else if (Act == actIntervalBeep) ++ AlertBeep = state; ++ else if (Act == actConnectBeep) ++ ConnectBeep = state; ++ else if (Act == actnoConv) ++ convUTF8 = -1; ++ else if (Act == actAuto) ++ convUTF8 = 0; ++ else if (Act == actCP1251) ++ convUTF8 = 1251; ++ else if (Act == actCP1252) ++ convUTF8 = 1252; ++ else if (Act == actCP437) ++ convUTF8 = 437; ++ else ++ { ++ // look for port entry ++ for (int i = 0; i < MAXPORTS + 1; i++) ++ { ++ if (Act == MonPort[i]) ++ { ++ uint64_t mmask; ++ ++ if (i == 0) // BBS Mon - use bit 63 (Port 64) ++ mmask = (uint64_t)1 << 63; ++ else ++ mmask = (uint64_t)1 << (i - 1); ++ ++ if (state) ++ ActiveSession->portmask |= mmask; ++ else ++ ActiveSession->portmask &= ~mmask; ++ break; ++ } ++ } ++ } ++ ++ ++ if (ActiveSession->clientSocket && ActiveSession->SessionType & Mon) ++ SendTraceOptions(ActiveSession); ++ ++ else if (AGWUsers && ActiveSession == AGWUsers->MonSess) ++ { ++ AGWMonEnable = ActiveSession->EnableMonitor; ++ AGWLocalTime = ActiveSession->mlocaltime; ++ AGWMonNodes = ActiveSession->MonitorNODES; ++ Send_AGW_m_Frame((QTcpSocket*)ActiveSession->AGWSession); ++ } ++ ++ else if (ActiveSession == KISSMonSess) ++ { ++ KISSLocalTime = ActiveSession->mlocaltime; ++ KISSMonEnable = ActiveSession->EnableMonitor; ++ KISSMonNodes = ActiveSession->MonitorNODES; ++ } ++ return; ++} ++ ++ ++ ++ ++void QtTermTCP::LDisconnect(Ui_ListenSession * LUI) ++{ ++ if (LUI->clientSocket) ++ LUI->clientSocket->disconnectFromHost(); ++} ++ ++extern QApplication * a; ++ ++void QtTermTCP::LreturnPressed(Ui_ListenSession * Sess) ++{ ++ QByteArray stringData = Sess->inputWindow->text().toUtf8(); ++ ++ // if multiline input (eg from copy/paste) replace LF with CR ++ ++ char * ptr; ++ char * Msgptr; ++ char * Msg; ++ ++ QScrollBar *scrollbar = Sess->termWindow->verticalScrollBar(); ++ bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4)); ++ ++ if (scrollbarAtBottom) ++ Sess->termWindow->moveCursor(QTextCursor::End); // So we don't get blank lines ++ ++ // Stack it ++ ++ Sess->StackIndex = 0; ++ ++ if (Sess->KbdStack[49]) ++ free(Sess->KbdStack[49]); ++ ++ for (int i = 48; i >= 0; i--) ++ { ++ Sess->KbdStack[i + 1] = Sess->KbdStack[i]; ++ } ++ ++ Sess->KbdStack[0] = qstrdup(stringData.data()); ++ ++ stringData.append('\n'); ++ ++ Msgptr = stringData.data(); ++ ++ if (Sess->TTActive) // Teletext uses 0x5F for # ++ while ((ptr = strchr(Msgptr, 0x23))) // Replace VT with LF ++ *ptr++ = 0x5f; ++ ++ ++ while ((ptr = strchr(Msgptr, 11))) // Replace VT with LF ++ *ptr++ = 10; ++ ++ LastWrite = time(NULL); // Stop initial beep ++ Sess->SlowTimer = 0; ++ ++ Sess->pageBuffer[0] = 0; // Reset Teletext mode screen buffer ++ ++ if (Sess->KISSMode == 1) ++ { ++ // UI session. Send as UI Message ++ ++ while ((ptr = strchr(Msgptr, '\n'))) ++ { ++ *ptr++ = 0; ++ ++ Msg = (char *)malloc(strlen(Msgptr) + 10); ++ strcpy(Msg, Msgptr); ++ strcat(Msg, "\r"); ++ ++ ++ Send_UI(Sess->UIPORT, 0xF0, KISSMYCALL, Sess->UIDEST, Sess->UIPATH, (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); ++ Sess->clientSocket->flush(); ++// QThread::msleep(1500); // Try to force as separate packets ++ 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))); ++ ++ ++ // Set Monitor Params for this host ++ ++ sscanf(MonParams[Sess->CurrentHost], "%llx %x %x %x %x %x", ++ &Sess->portmask, &Sess->mtxparam, &Sess->mcomparam, ++ &Sess->MonitorNODES, &Sess->MonitorColour, &Sess->monUI); ++ ++ Sess->mlocaltime = (Sess->mtxparam >> 7); ++ Sess->mtxparam &= 1; ++ ++ MonLocalTime->setChecked(Sess->mlocaltime); ++ MonTX->setChecked(Sess->mtxparam); ++ MonSup->setChecked(Sess->mcomparam); ++ MonUI->setChecked(Sess->monUI); ++ MonNodes->setChecked(Sess->MonitorNODES); ++ MonColour->setChecked(Sess->MonitorColour); ++ ++ 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(&IntervalWAV); ++ ++ } ++ ++ // Alert if QtTerm not active window (unless Mon window) ++ ++ if((Sess->SessionType & Mon) == 0) ++ FlashifNotActive(); ++ ++ // if tabbed and not active tab set tab label red ++ ++ if (TermMode == Tabbed) ++ { ++ if (Sess->monWindow != termWindow) // Not if Monitor ++ { ++ if (ActiveSession != Sess) ++ { ++ tabWidget->tabBar()->setTabTextColor(Sess->Tab, newTabText); ++ } ++ } ++ } ++ ++ LastWrite = NOW; ++ ++ // Mustn't mess with original buffer ++ ++ memcpy(Copy, Buffer, len); ++ ++ Copy[len] = 0; ++ ++ ptr1 = Copy; ++ ++ const QTextCursor old_cursor = termWindow->textCursor(); ++ const int old_scrollbar_value = termWindow->verticalScrollBar()->value(); ++ const bool is_scrolled_down = old_scrollbar_value == termWindow->verticalScrollBar()->maximum(); ++ ++ if (*OutputSaveLen) ++ { ++ // Have part line - append to it ++ memcpy(&OutputSave[*OutputSaveLen], Copy, len); ++ *OutputSaveLen += len; ++ ptr1 = (unsigned char *)OutputSave; ++ len = *OutputSaveLen; ++ *OutputSaveLen = 0; ++ ++ // part line was written to screen so remove it ++ ++// termWindow->setFocus(); ++ termWindow->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); ++ termWindow->moveCursor(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor); ++ termWindow->moveCursor(QTextCursor::End, QTextCursor::KeepAnchor); ++ termWindow->textCursor().removeSelectedText(); ++ // termWindow->textCursor().deletePreviousChar(); ++ } ++ ++ // Move the cursor to the end of the document. ++ ++ termWindow->moveCursor(QTextCursor::End); ++ ++ // Insert the text at the position of the cursor (which is the end of the document). ++ ++lineloop: ++ ++ if (len <= 0) ++ { ++ if (old_cursor.hasSelection() || !is_scrolled_down) ++ { ++ // The user has selected text or scrolled away from the bottom: maintain position. ++ termWindow->setTextCursor(old_cursor); ++ termWindow->verticalScrollBar()->setValue(old_scrollbar_value); ++ } ++ else ++ { ++ // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. ++ termWindow->moveCursor(QTextCursor::End); ++ termWindow->verticalScrollBar()->setValue(termWindow->verticalScrollBar()->maximum()); ++ } ++ ++ return; ++ } ++ ++ ++ // copy text to control a line at a time ++ ++ ptr2 = (unsigned char *)memchr(ptr1, 13, len); ++ ++ if (ptr2 == 0) // No CR ++ { ++ if (len > 8000) ++ len = 8000; // Should never get lines this long ++ ++ memmove(OutputSave, ptr1, len); ++ *OutputSaveLen = len; ++ ++ // Write part line to screen ++ ++ memcpy(Line, ptr1, len); ++ Line[len] = 0; ++ ++ // I don't think I need to worry if UTF8 as will be rewritten when rest arrives ++ ++ if (Line[0] == 0x1b) // Colour Escape ++ { ++ if (Sess->MonitorColour) ++ termWindow->setTextColor(Colours[Line[1] - 10]); ++ ++ termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); ++ } ++ else ++ { ++ termWindow->setTextColor(Colour); ++ termWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); ++ } ++ ++ // *OutputSaveLen = 0; // Test if we need to delete part line ++ ++ // if (scrollbarAtBottom) ++ // termWindow->moveCursor(QTextCursor::End); ++ ++ if (old_cursor.hasSelection() || !is_scrolled_down) ++ { ++ // The user has selected text or scrolled away from the bottom: maintain position. ++ termWindow->setTextCursor(old_cursor); ++ termWindow->verticalScrollBar()->setValue(old_scrollbar_value); ++ } ++ else ++ { ++ // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. ++ termWindow->moveCursor(QTextCursor::End); ++ termWindow->verticalScrollBar()->setValue(termWindow->verticalScrollBar()->maximum()); ++ } ++ return; ++ } ++ ++ *(ptr2++) = 0; ++ ++ if (Bells) ++ { ++ char * ptr; ++ ++ do { ++ ptr = (char *)memchr(ptr1, 7, len); ++ ++ if (ptr) ++ { ++ *(ptr) = 32; ++ myBeep(&BellWAV); ++ } ++ } while (ptr); ++ } ++ ++ num = ptr2 - ptr1 - 1; ++ ++ // if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1); ++ ++ memcpy(Line, ptr1, num); ++ Line[num++] = 13; ++ Line[num] = 0; ++ ++ if (Line[0] == 0x1b) // Colour Escape ++ { ++ if (Sess->MonitorColour) ++ termWindow->setTextColor(Colours[Line[1] - 10]); ++ ++ outlen = checkUTF8(&Line[2], num - 2, out); ++ out[outlen] = 0; ++ termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); ++ // termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); ++ } ++ else ++ { ++ termWindow->setTextColor(Colour); ++ ++ outlen = checkUTF8(Line, num, out); ++ out[outlen] = 0; ++ termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); ++ // termWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); ++ } ++ ++ len -= (ptr2 - ptr1); ++ ++ ptr1 = ptr2; ++ ++ if ((len > 0) && StripLF) ++ { ++ if (*ptr1 == 0x0a) // Line Feed ++ { ++ ptr1++; ++ len--; ++ } ++ } ++ ++ ++ ++ goto lineloop; ++ ++} ++ ++void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg); ++ ++extern "C" void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Msg, int len) ++{ ++ char * ptr1 = (char *)Msg, *ptr2; ++ char Line[512]; ++ int num; ++ ++ // QScrollBar *scrollbar = Sess->monWindow->verticalScrollBar(); ++ // bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4)); ++ ++ if (Sess->monWindow == nullptr) ++ return; ++ ++ Sess->monWindow->setStyleSheet(monStyleSheet); ++ ++ const QTextCursor old_cursor = Sess->monWindow->textCursor(); ++ const int old_scrollbar_value = Sess->monWindow->verticalScrollBar()->value(); ++ const bool is_scrolled_down = old_scrollbar_value == Sess->monWindow->verticalScrollBar()->maximum(); ++ ++ // Move the cursor to the end of the document. ++ Sess->monWindow->moveCursor(QTextCursor::End); ++ ++ // Insert the text at the position of the cursor (which is the end of the document). ++ ++ ++ // Write a line at a time so we can action colour chars ++ ++// Buffer[Len] = 0; ++ ++// if (scrollbarAtBottom) ++// Sess->monWindow->moveCursor(QTextCursor::End); ++ ++ if (Sess->MonSaveLen) ++ { ++ // Have part line - append to it ++ memcpy(&Sess->MonSave[Sess->MonSaveLen], Msg, len); ++ Sess->MonSaveLen += len; ++ ptr1 = Sess->MonSave; ++ len = Sess->MonSaveLen; ++ Sess->MonSaveLen = 0; ++ } ++ ++lineloop: ++ ++ if (len <= 0) ++ { ++ // if (scrollbarAtBottom) ++ // Sess->monWindow->moveCursor(QTextCursor::End); ++ ++ ++ if (old_cursor.hasSelection() || !is_scrolled_down) ++ { ++ // The user has selected text or scrolled away from the bottom: maintain position. ++ Sess->monWindow->setTextCursor(old_cursor); ++ Sess->monWindow->verticalScrollBar()->setValue(old_scrollbar_value); ++ } ++ else ++ { ++ // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. ++ Sess->monWindow->moveCursor(QTextCursor::End); ++ Sess->monWindow->verticalScrollBar()->setValue(Sess->monWindow->verticalScrollBar()->maximum()); ++ } ++ ++ return; ++ } ++ ++ // copy text to control a line at a time ++ ++ ptr2 = (char *)memchr(ptr1, 13, len); ++ ++ if (ptr2 == 0) // No CR ++ { ++ memmove(Sess->MonSave, ptr1, len); ++ Sess->MonSaveLen = len; ++ return; ++ } ++ ++ *(ptr2++) = 0; ++ ++ ++ if (Sess->LogMonitor) ++ WriteMonitorLog(Sess, ptr1); ++ ++ num = ptr2 - ptr1 - 1; ++ ++ memcpy(Line, ptr1, num); ++ Line[num++] = 13; ++ Line[num] = 0; ++ ++ if (Line[0] == 0x1b) // Colour Escape ++ { ++ if (Sess->MonitorColour) ++ { ++ if (Line[1] == 17) ++ Sess->monWindow->setTextColor(monRxText); ++ else ++ Sess->monWindow->setTextColor(monTxText); ++ } ++ else ++ Sess->monWindow->setTextColor(monOtherText); ++ ++ Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); ++ } ++ else ++ { ++ Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); ++ } ++ len -= (ptr2 - ptr1); ++ ++ ptr1 = ptr2; ++ ++ goto lineloop; ++ ++} ++ ++int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len); ++void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len); ++ ++// YAPP stuff ++ ++#define SOH 1 ++#define STX 2 ++#define ETX 3 ++#define EOT 4 ++#define ENQ 5 ++#define ACK 6 ++#define DLE 0x10 ++#define NAK 0x15 ++#define CAN 0x18 ++ ++extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len) ++{ ++ if (Sess == 0) ++ return; ++ ++ Sess->SlowTimer = 0; ++ Msg[Len] = 0; ++ ++ if (Sess->InputMode == 'Y') // Yapp ++ { ++ ProcessYAPPMessage(Sess, (unsigned char *)Msg, Len); ++ return; ++ } ++ ++ // Could be a YAPP Header ++ ++ if (Len == 2 && Msg[0] == ENQ && Msg[1] == 1) // YAPP Send_Init ++ { ++ char YAPPRR[2]; ++ ++ // Turn off monitoring ++ ++ Sess->InputMode = 'Y'; ++ ++ YAPPRR[0] = ACK; ++ YAPPRR[1] = 1; ++ QueueMsg(Sess, YAPPRR, 2); ++ ++ return; ++ } ++ ++ if (AutoTeletext && (Msg[0] == 0x1e || Msg[0] == 0x0c)) ++ { ++ if (Sess->TTActive == 0) ++ { ++ Sess->TTActive = 1; ++ DoTermResize(Sess); ++ } ++ } ++ ++ if (Sess->TTActive) ++ { ++ // Feed to Teletext code ++ ++ // We need to decode a whole page. There is no obvious delimiter so process till data stops. ++ // Buffer is cleared when next input is sent ++ ++ if (strlen(&Sess->pageBuffer[0] + Len) > 4090) ++ Sess->pageBuffer[0] = 0; // Protect buffer ++ ++ strcat(Sess->pageBuffer, (char *)Msg); ++ ++ DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end ++ return; ++ } ++ ++ WritetoOutputWindow(Sess, (unsigned char *)Msg, Len); ++ ++} ++ ++QSettings* settings; ++ ++// This makes geting settings for more channels easier ++ ++char Prefix[16] = "AX25_A"; ++ ++void GetPortSettings(int Chan); ++ ++QVariant getAX25Param(const char * key, QVariant Default) ++{ ++ char fullKey[64]; ++ ++ sprintf(fullKey, "%s/%s", Prefix, key); ++ return settings->value(fullKey, Default); ++} ++ ++void getAX25Params(int chan) ++{ ++ Prefix[5] = chan + 'A'; ++ GetPortSettings(chan); ++} ++ ++ ++void GetPortSettings(int Chan) ++{ ++ txdelay[Chan] = getAX25Param("TXDelay", 250).toInt(); ++ sendTXDelay[Chan] = getAX25Param("sendTXDelay", 0).toInt(); ++ maxframe[Chan] = getAX25Param("Maxframe", 4).toInt(); ++ fracks[Chan] = getAX25Param("Retries", 10).toInt(); ++ frack_time[Chan] = getAX25Param("FrackTime", 8).toInt(); ++ persist[Chan] = getAX25Param("Persist", 128).toInt(); ++ kisspaclen[Chan] = getAX25Param("Paclen", 128).toInt(); ++ idletime[Chan] = getAX25Param("IdleTime", 180).toInt(); ++ slottime[Chan] = getAX25Param("SlotTime", 100).toInt(); ++ resptime[Chan] = getAX25Param("RespTime", 1500).toInt(); ++ TXFrmMode[Chan] = getAX25Param("TXFrmMode", 1).toInt(); ++ max_frame_collector[Chan] = getAX25Param("FrameCollector", 6).toInt(); ++ //exclude_callsigns[Chan]= getAX25Param("ExcludeCallsigns/"); ++ //exclude_APRS_frm[Chan]= getAX25Param("ExcludeAPRSFrmType/"); ++ KISS_opt[Chan] = getAX25Param("KISSOptimization", false).toInt();; ++ dyn_frack[Chan] = getAX25Param("DynamicFrack", false).toInt();; ++ IPOLL[Chan] = getAX25Param("IPOLL", 80).toInt(); ++ ++} ++ ++ ++void GetSettings() ++{ ++ QByteArray qb; ++ int i; ++ char Key[16]; ++ char Param[256]; ++ ++ settings = new QSettings(GetConfPath(), QSettings::IniFormat); ++ ++ // Get saved session definitions ++ ++ sessionList = strdup(settings->value("Sessions", "1|3, 0, 5, 5, 600, 800|").toString().toUtf8()); ++ ++ for (i = 0; i < MAXHOSTS; i++) ++ { ++ sprintf(Key, "HostParams%d", i); ++ ++ qb = settings->value(Key).toByteArray(); ++ ++ DecodeSettingsLine(i, qb.data()); ++ } ++ ++ Split = settings->value("Split", 50).toInt(); ++ ChatMode = settings->value("ChatMode", 1).toInt(); ++ AutoTeletext = settings->value("AutoTeletext", 0).toInt(); ++ Bells = settings->value("Bells", 1).toInt(); ++ StripLF = settings->value("StripLF", 1).toInt(); ++ useBeep = settings->value("useBeep", true).toBool(); ++ AlertBeep = settings->value("AlertBeep", 1).toInt(); ++ AlertInterval = settings->value("AlertInterval", 300).toInt(); ++ ConnectBeep = settings->value("ConnectBeep", 1).toInt(); ++ ConnectWAV = settings->value("ConnectWAV", ":/PCBeep").toString().toUtf8(); ++ AlertWAV = settings->value("AlertWAV", ":/PCBeep").toString().toUtf8(); ++ BellWAV = settings->value("BellWAV", ":/PCBeep").toString().toUtf8(); ++ IntervalWAV = settings->value("IntervalWAV", ":/PCBeep").toString().toUtf8(); ++ ++ UseKeywords = settings->value("UseKeywords", 0).toInt(); ++ KeyWordsFile = settings->value("KeyWordsFile", "keywords.sys").toString().toUtf8(); ++ ++ SavedHost = settings->value("CurrentHost", 0).toInt(); ++ strcpy(YAPPPath, settings->value("YAPPPath", "").toString().toUtf8()); ++ MaxRXSize = settings->value("MaxRXSize", 100000).toInt(); ++ ++ listenPort = settings->value("listenPort", 8015).toInt(); ++ listenEnable = settings->value("listenEnable", false).toBool(); ++ strcpy(listenCText, settings->value("listenCText", "").toString().toUtf8()); ++ ++ TermMode = settings->value("TermMode", 0).toInt(); ++ singlemodeFormat = settings->value("singlemodeFormat", Term + Mon).toInt(); ++ ++ AGWEnable = settings->value("AGWEnable", 0).toInt(); ++ AGWMonEnable = settings->value("AGWMonEnable", 0).toInt(); ++ AGWLocalTime = settings->value("AGWLocalTime", 0).toInt(); ++ AGWMonNodes = settings->value("AGWMonNodes", 0).toInt(); ++ strcpy(AGWTermCall, settings->value("AGWTermCall", "").toString().toUtf8()); ++ strcpy(AGWBeaconDest, settings->value("AGWBeaconDest", "").toString().toUtf8()); ++ strcpy(AGWBeaconPath, settings->value("AGWBeaconPath", "").toString().toUtf8()); ++ AGWBeaconInterval = settings->value("AGWBeaconInterval", 0).toInt(); ++ strcpy(AGWBeaconPorts, settings->value("AGWBeaconPorts", "").toString().toUtf8()); ++ strcpy(AGWBeaconMsg, settings->value("AGWBeaconText", "").toString().toUtf8()); ++ strcpy(AGWHost, settings->value("AGWHost", "127.0.0.1").toString().toUtf8()); ++ AGWPortNum = settings->value("AGWPort", 8000).toInt(); ++ AGWPaclen = settings->value("AGWPaclen", 80).toInt(); ++ AGWToCalls = settings->value("AGWToCalls", "").toStringList(); ++ convUTF8 = settings->value("convUTF8", 0).toInt(); ++ ++ KISSEnable = settings->value("KISSEnable", 0).toInt(); ++ KISSMonEnable = settings->value("KISSMonEnable", 1).toInt(); ++ KISSLocalTime = settings->value("KISSLocalTime", 0).toInt(); ++ KISSMonNodes = settings->value("KISSMonNodes", 0).toInt(); ++ ++ KISSListen = settings->value("KISSListen", 1).toInt(); ++ KISSChecksum = settings->value("KISSChecksum", 0).toInt(); ++ KISSAckMode = settings->value("KISSAckMode", 0).toInt(); ++ KISSMH = settings->value("KISSMH", 1).toInt(); ++ strcpy(KISSMYCALL, 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(KISSVia, settings->value("KISSVia", "").toString().toUtf8()); ++ ++ strcpy(SerialPort, settings->value("KISSSerialPort", "None").toString().toUtf8()); ++ KISSBAUD = settings->value("KISSBAUD", 19200).toInt(); ++ getAX25Params(0); ++ ++ VARAEnable = settings->value("VARAEnable", 0).toInt(); ++ strcpy(VARAHost, settings->value("VARAHost", "127.0.0.1").toString().toUtf8()); ++ strcpy(VARAHostFM, settings->value("VARAHostFM", "127.0.0.1").toString().toUtf8()); ++ strcpy(VARAHostHF, settings->value("VARAHostHF", "127.0.0.1").toString().toUtf8()); ++ strcpy(VARAHostSAT, settings->value("VARAHostSAT", "127.0.0.1").toString().toUtf8()); ++ VARAPortNum = settings->value("VARAPort", 8300).toInt(); ++ VARAPortHF = settings->value("VARAPortHF", 8300).toInt(); ++ VARAPortFM = settings->value("VARAPortFM", 8300).toInt(); ++ VARAPortSAT = settings->value("VARAPortSAT", 8300).toInt(); ++ strcpy(VARAPath, settings->value("VARAPath", "C:\\VARA\\VARA.exe").toString().toUtf8()); ++ strcpy(VARAPathHF, settings->value("VARAPathHF", "C:\\VARA\\VARA.exe").toString().toUtf8()); ++ strcpy(VARAPathFM, settings->value("VARAPathFM", "C:\\VARA\\VARAFM.exe").toString().toUtf8()); ++ strcpy(VARAPathSAT, settings->value("VARAPathSAT", "C:\\VARA\\VARASAT.exe").toString().toUtf8()); ++ strcpy(VARATermCall, settings->value("VARATermCall", "").toString().toUtf8()); ++ VARA500 = settings->value("VARA500", 0).toInt(); ++ VARA2300 = settings->value("VARA2300", 1).toInt(); ++ VARA2750 = settings->value("VARA2750", 0).toInt(); ++ VARAHF = settings->value("VARAHF", 1).toInt(); ++ VARAFM = settings->value("VARAFM", 0).toInt(); ++ VARASAT = settings->value("VARASAT", 0).toInt(); ++ strcpy(VARAInit, settings->value("VARAInit", "").toString().toUtf8()); ++ ++ strcpy(PTTPort, settings->value("PTT", "None").toString().toUtf8()); ++ PTTMode = settings->value("PTTMode", 19200).toInt(); ++ PTTBAUD = settings->value("PTTBAUD", 19200).toInt(); ++ CATHex = settings->value("CATHex", 1).toInt(); ++ ++ strcpy(PTTOnString, settings->value("PTTOnString", "").toString().toUtf8()); ++ strcpy(PTTOffString, settings->value("PTTOffString", "").toString().toUtf8()); ++ ++ pttGPIOPin = settings->value("pttGPIOPin", 17).toInt(); ++ pttGPIOPinR = settings->value("pttGPIOPinR", 17).toInt(); ++ ++#ifdef WIN32 ++ strcpy(CM108Addr, settings->value("CM108Addr", "0xD8C:0x08").toString().toUtf8()); ++#else ++ strcpy(CM108Addr, settings->value("CM108Addr", "/dev/hidraw0").toString().toUtf8()); ++#endif ++ ++ HamLibPort = settings->value("HamLibPort", 4532).toInt(); ++ strcpy(HamLibHost, settings->value("HamLibHost", "127.0.0.1").toString().toUtf8()); ++ ++ FLRigPort = settings->value("FLRigPort", 12345).toInt(); ++ strcpy(FLRigHost, settings->value("FLRigHost", "127.0.0.1").toString().toUtf8()); ++ ++ ++ strcpy(Param, settings->value("TabType", "1 1 1 1 1 1 1 2 2").toString().toUtf8()); ++ sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", ++ &TabType[0], &TabType[1], &TabType[2], &TabType[3], &TabType[4], ++ &TabType[5], &TabType[6], &TabType[7], &TabType[8], &TabType[9]); ++ ++ strcpy(Param, settings->value("AutoConnect", "0, 0 ,0, 0, 0, 0, 0, 0, 0, 0").toString().toUtf8()); ++ sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", ++ &AutoConnect[0], &AutoConnect[1], &AutoConnect[2], &AutoConnect[3], &AutoConnect[4], ++ &AutoConnect[5], &AutoConnect[6], &AutoConnect[7], &AutoConnect[8], &AutoConnect[9]); ++ ++ strcpy(Param, settings->value("currentHost", "0, 0 ,0, 0, 0, 0, 0, 0, 0, 0").toString().toUtf8()); ++ sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", ++ ¤tHost[0], ¤tHost[1], ¤tHost[2], ¤tHost[3], ¤tHost[4], ++ ¤tHost[5], ¤tHost[6], ¤tHost[7], ¤tHost[8], ¤tHost[9]); ++ ++ ++ monBackground = settings->value("monBackground", QColor(255, 255, 255)).value(); ++ monRxText = settings->value("monRxText", QColor(0, 0, 255)).value(); ++ monTxText = settings->value("monTxText", QColor(255, 0, 0)).value(); ++ monOtherText = settings->value("monOtherText", QColor(0, 0, 0)).value(); ++ ++ termBackground = settings->value("termBackground", QColor(255, 255, 255)).value(); ++ outputText = settings->value("outputText", QColor(0, 0, 255)).value(); ++ EchoText = settings->value("EchoText", QColor(0, 0, 0)).value(); ++ WarningText = settings->value("WarningText", QColor(255, 0, 0)).value(); ++ ++ inputBackground = settings->value("inputBackground", QColor(255, 255, 255)).value(); ++ inputText = settings->value("inputText", QColor(0, 0, 0)).value(); ++ ++ delete(settings); ++} ++ ++void SavePortSettings(int Chan); ++ ++void saveAX25Param(const char * key, QVariant Value) ++{ ++ char fullKey[64]; ++ ++ sprintf(fullKey, "%s/%s", Prefix, key); ++ ++ settings->setValue(fullKey, Value); ++} ++ ++void saveAX25Params(int chan) ++{ ++ Prefix[5] = chan + 'A'; ++ SavePortSettings(chan); ++} ++ ++void SavePortSettings(int Chan) ++{ ++ saveAX25Param("TXDelay", txdelay[Chan]); ++ saveAX25Param("sendTXDelay", sendTXDelay[Chan]); ++ saveAX25Param("Maxframe", maxframe[Chan]); ++ saveAX25Param("Paclen", kisspaclen[Chan]); ++ saveAX25Param("FrackTime", frack_time[Chan]); ++ saveAX25Param("IdleTime", idletime[Chan]); ++ saveAX25Param("SlotTime", slottime[Chan]); ++ saveAX25Param("Persist", persist[Chan]); ++ saveAX25Param("RespTime", resptime[Chan]); ++ saveAX25Param("TXFrmMode", TXFrmMode[Chan]); ++ saveAX25Param("FrameCollector", max_frame_collector[Chan]); ++ saveAX25Param("ExcludeCallsigns", exclude_callsigns[Chan]); ++ saveAX25Param("ExcludeAPRSFrmType", exclude_APRS_frm[Chan]); ++ saveAX25Param("KISSOptimization", KISS_opt[Chan]); ++ saveAX25Param("DynamicFrack", dyn_frack[Chan]); ++ saveAX25Param("BitRecovery", recovery[Chan]); ++ saveAX25Param("IPOLL", IPOLL[Chan]); ++ saveAX25Param("MyDigiCall", MyDigiCall[Chan]); ++} ++ ++extern "C" void SaveSettings() ++{ ++ int i; ++ char Param[512]; ++ char Key[16]; ++ ++ settings = new QSettings(GetConfPath(), QSettings::IniFormat); ++ ++ for (i = 0; i < MAXHOSTS; i++) ++ { ++ sprintf(Key, "HostParams%d", i); ++ EncodeSettingsLine(i, Param); ++ settings->setValue(Key, Param); ++ } ++ ++ settings->setValue("Split", Split); ++ settings->setValue("ChatMode", ChatMode); ++ settings->setValue("AutoTeletext", AutoTeletext); ++ settings->setValue("Bells", Bells); ++ settings->setValue("StripLF", StripLF); ++ settings->setValue("AlertBeep", AlertBeep); ++ settings->setValue("useBeep", useBeep); ++ settings->setValue("ConnectBeep", ConnectBeep); ++ settings->setValue("BellWAV", BellWAV); ++ settings->setValue("AlertWAV", AlertWAV); ++ settings->setValue("IntervalWAV", IntervalWAV); ++ settings->setValue("ConnectWAV", ConnectWAV); ++ ++ settings->setValue("UseKeywords", UseKeywords); ++ settings->setValue("KeyWordsFile", KeyWordsFile); ++ ++ settings->setValue("AlertInterval", AlertInterval); ++ settings->setValue("CurrentHost", SavedHost); ++ ++ settings->setValue("YAPPPath", YAPPPath); ++ settings->setValue("MaxRXSize", MaxRXSize); ++ ++ settings->setValue("listenPort", listenPort); ++ settings->setValue("listenEnable", listenEnable); ++ settings->setValue("listenCText", listenCText); ++ settings->setValue("convUTF8", convUTF8); ++ ++ settings->setValue("PTT", PTTPort); ++ settings->setValue("PTTBAUD", PTTBAUD); ++ settings->setValue("PTTMode", PTTMode); ++ ++ settings->setValue("CATHex", CATHex); ++ ++ settings->setValue("PTTOffString", PTTOffString); ++ settings->setValue("PTTOnString", PTTOnString); ++ ++ settings->setValue("pttGPIOPin", pttGPIOPin); ++ settings->setValue("pttGPIOPinR", pttGPIOPinR); ++ ++ settings->setValue("CM108Addr", CM108Addr); ++ settings->setValue("HamLibPort", HamLibPort); ++ settings->setValue("HamLibHost", HamLibHost); ++ settings->setValue("FLRigPort", FLRigPort); ++ settings->setValue("FLRigHost", FLRigHost); ++ ++ ++ // Save Sessions ++ ++ char SessionString[1024]; ++ int SessStringLen; ++ ++ SessStringLen = sprintf(SessionString, "%d|", _sessions.size()); ++ ++ if (TermMode == MDI) ++ { ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Ui_ListenSession * Sess = _sessions.at(i); ++ ++ QRect r = Sess->sw->geometry(); ++ ++ SessStringLen += sprintf(&SessionString[SessStringLen], ++ "%d, %d, %d, %d, %d, %d|", Sess->SessionType, Sess->CurrentHost, r.top(), r.left(), r.bottom(), r.right()); ++ } ++ ++ settings->setValue("Sessions", SessionString); ++ } ++ ++ settings->setValue("AGWEnable", AGWEnable); ++ settings->setValue("AGWMonEnable", AGWMonEnable); ++ settings->setValue("AGWLocalTime", AGWLocalTime); ++ settings->setValue("AGWMonNodes", AGWMonNodes); ++ settings->setValue("AGWTermCall", AGWTermCall); ++ settings->setValue("AGWBeaconDest", AGWBeaconDest); ++ settings->setValue("AGWBeaconPath", AGWBeaconPath); ++ settings->setValue("AGWBeaconInterval", AGWBeaconInterval); ++ settings->setValue("AGWBeaconPorts", AGWBeaconPorts); ++ settings->setValue("AGWBeaconText", AGWBeaconMsg); ++ settings->setValue("AGWHost", AGWHost); ++ settings->setValue("AGWPort", AGWPortNum); ++ settings->setValue("AGWPaclen", AGWPaclen); ++ settings->setValue("AGWToCalls", AGWToCalls); ++ ++ settings->setValue("KISSEnable", KISSEnable); ++ settings->setValue("KISSMonEnable", KISSMonEnable); ++ settings->setValue("KISSLocalTime", KISSLocalTime); ++ settings->setValue("KISSMonNodes", KISSMonNodes); ++ ++ settings->setValue("KISSListen", KISSListen); ++ settings->setValue("KISSChecksum", KISSChecksum); ++ settings->setValue("KISSAckMode", KISSAckMode); ++ settings->setValue("KISSMH", KISSMH); ++ settings->setValue("MYCALL", KISSMYCALL); ++ settings->setValue("KISSHost", KISSHost); ++ settings->setValue("KISSMode", KISSMode); ++ settings->setValue("KISSPort", KISSPortNum); ++ settings->setValue("KISSSerialPort", SerialPort); ++ settings->setValue("KISSBAUD", KISSBAUD); ++ settings->setValue("KISSVia", KISSVia); ++ ++ saveAX25Params(0); ++ ++ settings->setValue("VARAEnable", VARAEnable); ++ settings->setValue("VARATermCall", VARATermCall); ++ settings->setValue("VARAHost", VARAHost); ++ settings->setValue("VARAPort", VARAPortNum); ++ settings->setValue("VARAInit", VARAInit); ++ settings->setValue("VARAPath", VARAPath); ++ settings->setValue("VARAHostHF", VARAHostHF); ++ settings->setValue("VARAPortHF", VARAPortHF); ++ settings->setValue("VARAPathHF", VARAPathHF); ++ settings->setValue("VARAHostFM", VARAHostFM); ++ settings->setValue("VARAPortFM", VARAPortFM); ++ settings->setValue("VARAPathFM", VARAPathFM); ++ settings->setValue("VARAHostSAT", VARAHostSAT); ++ settings->setValue("VARAPortSAT", VARAPortSAT); ++ settings->setValue("VARAPathSAT", VARAPathSAT); ++ settings->setValue("VARA500", VARA500); ++ settings->setValue("VARA2300", VARA2300); ++ settings->setValue("VARA2750", VARA2750); ++ settings->setValue("VARAHF", VARAHF); ++ settings->setValue("VARAFM", VARAFM); ++ settings->setValue("VARASAT", VARASAT); ++ ++ sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", ++ TabType[0], TabType[1], TabType[2], TabType[3], TabType[4], TabType[5], TabType[6], TabType[7], TabType[8], TabType[9]); ++ ++ settings->setValue("TabType", Param); ++ ++ sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", ++ AutoConnect[0], AutoConnect[1], AutoConnect[2], AutoConnect[3], AutoConnect[4], AutoConnect[5], AutoConnect[6], AutoConnect[7], AutoConnect[8], AutoConnect[9]); ++ ++ settings->setValue("AutoConnect", Param); ++ ++ sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", ++ currentHost[0], currentHost[1], currentHost[2], currentHost[3], currentHost[4], currentHost[5], currentHost[6], currentHost[7], currentHost[8], currentHost[9]); ++ ++ settings->setValue("currentHost", Param); ++ ++ settings->setValue("monBackground", monBackground); ++ settings->setValue("monRxText", monRxText); ++ settings->setValue("monTxText", monTxText); ++ settings->setValue("monOtherText", monOtherText); ++ ++ settings->setValue("termBackground", termBackground); ++ settings->setValue("outputText", outputText); ++ settings->setValue("EchoText", EchoText); ++ settings->setValue("WarningText", WarningText); ++ ++ settings->setValue("inputBackground", inputBackground); ++ settings->setValue("inputText", inputText); ++ ++ settings->sync(); ++ delete(settings); ++} ++ ++#include ++ ++void QtTermTCP::closeEvent(QCloseEvent *event) ++{ ++ QMessageBox::StandardButton resBtn = QMessageBox::question(this, "QtTermTCP", ++ tr("Are you sure?\n"), ++ QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes, ++ QMessageBox::Yes); ++ if (resBtn != QMessageBox::Yes) { ++ event->ignore(); ++ } ++ else ++ { ++ event->accept(); ++#ifdef USESERIAL ++ if (hPTTDevice) ++ hPTTDevice->close(); ++#endif ++ if (process) ++ process->close(); ++ ++ if (MHWindow) ++ MHWindow->close(); ++ ++ } ++} ++ ++QtTermTCP::~QtTermTCP() ++{ ++ Ui_ListenSession * Sess; ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->monLogfile) ++ Sess->monLogfile->close(); ++ ++ if (Sess->clientSocket) ++ { ++ int loops = 100; ++ Sess->clientSocket->disconnectFromHost(); ++ while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState) ++ QThread::msleep(10); ++ } ++ } ++ ++ if (AGWSock && AGWSock->ConnectedState == QAbstractSocket::ConnectedState) ++ { ++ int loops = 100; ++ AGWSock->disconnectFromHost(); ++ QThread::msleep(10); ++ while (AGWSock && loops-- && AGWSock->state() != QAbstractSocket::UnconnectedState) ++ QThread::msleep(10); ++ } ++ ++ if (_server->isListening()) ++ _server->close(); ++ ++ delete(_server); ++ ++ QSettings mysettings(GetConfPath(), QSettings::IniFormat); ++ mysettings.setValue("geometry", saveGeometry()); ++ mysettings.setValue("windowState", saveState()); ++ ++ if (MHWindow) ++ { ++ mysettings.setValue("MHgeometry", MHWindow->saveGeometry()); ++ MHWindow->close(); ++ } ++ 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(); ++ ++} ++ ++void QtTermTCP::SlowTimerSlot() ++{ ++ // Runs every 60 S ++ ++ Ui_ListenSession * Sess; ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->monLogfile) ++ { ++ Sess->monLogfile->close(); ++ Sess->monLogfile = nullptr; ++ } ++ } ++ ++} ++ ++ ++ ++extern "C" void myBeep(QString * WAV) ++{ ++ if (useBeep) ++ { ++ QApplication::beep(); ++ return; ++ } ++ ++ // Using .wav files ++ ++// QSoundEffect effect; ++// effect.setSource(QUrl::fromLocalFile(*WAV)); ++// effect.setLoopCount(1); ++// effect.setVolume(1.0f); ++// effect.play(); ++ ++ QSound::play(*WAV); ++} ++ ++void QtTermTCP::ListenSlot() ++{ ++ // This runs the Listen Configuration dialog ++ ++ ListenDialog * xx = new ListenDialog(); ++ xx->exec(); ++} ++ ++void QtTermTCP::AGWSlot() ++{ ++ // This runs the AGW Configuration dialog ++ ++ AGWDialog dialog(0); ++ dialog.exec(); ++} ++ ++Ui_Dialog * Dev; ++Ui_AlertDialog * Alert; ++ ++static Ui_KISSDialog * KISS; ++static Ui_ColourDialog * COLOURS; ++ ++ ++char NewPTTPort[80]; ++ ++int newSoundMode = 0; ++int oldSoundMode = 0; ++ ++#ifdef USESERIAL ++QList Ports = QSerialPortInfo::availablePorts(); ++#endif ++ ++ ++void QtTermTCP::KISSSlot() ++{ ++ // This runs the KISS Configuration dialog ++ ++ KISS = new(Ui_KISSDialog); ++ ++ QDialog UI; ++ ++ KISS->setupUi(&UI); ++ ++ UI.setFont(*menufont); ++ ++ deviceUI = &UI; ++ KISS->KISSEnable->setChecked(KISSEnable); ++ KISS->KISSListen->setChecked(KISSListen); ++ KISS->KISSChecksum->setChecked(KISSChecksum); ++ KISS->KISSACKMODE->setChecked(KISSAckMode); ++ KISS->KISSMH->setChecked(KISSMH); ++ KISS->MYCALL->setText(KISSMYCALL); ++ ++ KISS->TXDELAY->setText(QString::number(txdelay[0])); ++ KISS->SetTXDelay->setChecked(sendTXDelay[0]); ++ ++ // connect(KISS->SerialPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); ++ ++ QStringList items; ++ ++#ifdef USESERIAL ++ ++ for (const QSerialPortInfo &info : Ports) ++ { ++ items.append(info.portName()); ++ } ++ ++ items.sort(); ++ items.insert(0, "TCP"); ++ ++#endif ++ ++ for (const QString &info : items) ++ { ++ KISS->SerialPort->addItem(info); ++ } ++ ++ KISS->SerialPort->setCurrentIndex(KISS->SerialPort->findText(SerialPort, Qt::MatchFixedString)); ++ KISS->Speed->setText(QString::number(KISSBAUD)); ++ KISS->Host->setText(KISSHost); ++ KISS->Port->setText(QString::number(KISSPortNum)); ++ ++ KISS->Paclen->setText(QString::number(kisspaclen[0])); ++ KISS->Maxframe->setText(QString::number(maxframe[0])); ++ KISS->Frack->setText(QString::number(frack_time[0])); ++ KISS->Retries->setText(QString::number(fracks[0])); ++ ++ QObject::connect(KISS->okButton, SIGNAL(clicked()), this, SLOT(KISSaccept())); ++ QObject::connect(KISS->cancelButton, SIGNAL(clicked()), this, SLOT(KISSreject())); ++ ++ UI.exec(); ++ ++} ++ ++ ++void QtTermTCP::KISSaccept() ++{ ++ QVariant Q; ++ int OldEnable = KISSEnable; ++ char oldSerialPort[64]; ++ int OldPort = KISSPortNum; ++ char oldHost[128]; ++ ++ strcpy(oldSerialPort, SerialPort); ++ strcpy(oldHost, KISSHost); ++ ++ KISSEnable = KISS->KISSEnable->isChecked(); ++ KISSListen = KISS->KISSListen->isChecked(); ++ KISSChecksum = KISS->KISSChecksum->isChecked(); ++ KISSAckMode = KISS->KISSACKMODE->isChecked(); ++ KISSMH = KISS->KISSMH->isChecked(); ++ actHost[18]->setVisible(KISSEnable); // Show KISS Connect Line ++ ++ strcpy(KISSMYCALL, KISS->MYCALL->text().toUtf8().toUpper()); ++ ++ memset(axMYCALL, 0, 7); ++ ConvToAX25(KISSMYCALL, 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(); ++ ++ Q = KISS->TXDELAY->text(); ++ txdelay[0] = Q.toInt(); ++ sendTXDelay[0] = KISS->SetTXDelay->isChecked(); ++ ++ 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(); ++ } ++ } ++ ++ if (KISSEnable == 0 && MHWindow) ++ { ++ MHWindow->close(); ++ MHWindow = 0; ++ } ++ ++ if (KISSEnable && KISSMH && MHWindow == 0) ++ { ++ newMHWindow(this, 0, "KISS MH"); ++ QSettings mysettings(GetConfPath(), QSettings::IniFormat); ++ MHWindow->restoreGeometry(mysettings.value("MHgeometry").toByteArray()); ++ } ++ ++ if (!KISSMH && MHWindow) ++ { ++ MHWindow->close(); ++ MHWindow = 0; ++ } ++ ++ ++ delete(KISS); ++ SaveSettings(); ++ deviceUI->accept(); ++ ++ // QSize newSize(this->size()); ++ // QSize oldSize(this->size()); ++ ++ // QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); ++ ++ // QCoreApplication::postEvent(this, myResizeEvent); ++} ++ ++void QtTermTCP::KISSreject() ++{ ++ delete(KISS); ++ deviceUI->reject(); ++} ++ ++ ++void QtTermTCP::AlertSlot() ++{ ++ // This runs the VARA Configuration dialog ++ ++ Alert = new(Ui_AlertDialog); ++ ++ QDialog UI; ++ ++ Alert->setupUi(&UI); ++ ++ UI.setFont(*menufont); ++ ++ deviceUI = &UI; ++ ++ Alert->Bells->setChecked(Bells); ++ Alert->InboundBeep->setChecked(ConnectBeep); ++ Alert->InactivityBeep->setChecked(AlertBeep); ++ Alert->Interval->setText(QString::number(AlertInterval)); ++ Alert->KeywordBeep->setChecked(UseKeywords); ++ Alert->keywordFile->setText(KeyWordsFile); ++ ++ Alert->useBeep->setChecked(useBeep); ++ Alert->useFiles->setChecked(!useBeep); ++ ++ Alert->connectFile->setCurrentText(ConnectWAV); ++ Alert->bellsFile->setCurrentText(BellWAV); ++ Alert->intervalFile->setCurrentText(IntervalWAV); ++ Alert->keywordWAV->setCurrentText(AlertWAV); ++ ++ QObject::connect(Alert->chooseInbound, SIGNAL(clicked()), this, SLOT(chooseInboundWAV())); ++ QObject::connect(Alert->chooseBells, SIGNAL(clicked()), this, SLOT(chooseBellsWAV())); ++ QObject::connect(Alert->chooseInterval, SIGNAL(clicked()), this, SLOT(chooseIntervalWAV())); ++ QObject::connect(Alert->chooseKeyAlert, SIGNAL(clicked()), this, SLOT(chooseAlertWAV())); ++ ++ QObject::connect(Alert->testBells, SIGNAL(clicked()), this, SLOT(testBellsWAV())); ++ QObject::connect(Alert->TestInbound, SIGNAL(clicked()), this, SLOT(testInboundWAV())); ++ QObject::connect(Alert->testInterval, SIGNAL(clicked()), this, SLOT(testIntervalWAV())); ++ QObject::connect(Alert->TestKeyAlert, SIGNAL(clicked()), this, SLOT(testAlertWAV())); ++ ++ QObject::connect(Alert->okButton, SIGNAL(clicked()), this, SLOT(alertAccept())); ++ QObject::connect(Alert->cancelButton, SIGNAL(clicked()), this, SLOT(alertReject())); ++ ++ UI.exec(); ++} ++ ++ ++ ++ ++ ++ ++void QtTermTCP::chooseInboundWAV() ++{ ++ ConnectWAV = QFileDialog::getOpenFileName(this, ++ tr("Select Wav"), "", tr("Sound Files (*.wav)")); ++ ++ Alert->connectFile->setCurrentText(ConnectWAV); ++ ++} ++ ++void QtTermTCP::chooseBellsWAV() ++{ ++ BellWAV = QFileDialog::getOpenFileName(this, ++ tr("Select Wav"), "", tr("Sound Files (*.wav)")); ++ ++ Alert->bellsFile->setCurrentText(BellWAV); ++} ++ ++void QtTermTCP::chooseIntervalWAV() ++{ ++ IntervalWAV = QFileDialog::getOpenFileName(this, ++ tr("Select Wav"), "", tr("Sound Files (*.wav)")); ++ ++ Alert->intervalFile->setCurrentText(IntervalWAV); ++} ++ ++void QtTermTCP::chooseAlertWAV() ++{ ++ AlertWAV = QFileDialog::getOpenFileName(this, ++ tr("Select Wav"), "", tr("Sound Files (*.wav)")); ++ ++ Alert->keywordWAV->setCurrentText(AlertWAV); ++} ++ ++void QtTermTCP::testInboundWAV() ++{ ++ QSound::play(Alert->connectFile->currentText()); ++} ++ ++void QtTermTCP::testBellsWAV() ++{ ++ QSound::play(Alert->bellsFile->currentText()); ++} ++ ++void QtTermTCP::testIntervalWAV() ++{ ++ QSound::play(Alert->intervalFile->currentText()); ++} ++ ++void QtTermTCP::testAlertWAV() ++{ ++ QSound::play(Alert->keywordWAV->currentText()); ++} ++ ++ ++ ++void QtTermTCP::alertAccept() ++{ ++ QVariant Q; ++ ++ useBeep = Alert->useBeep->isChecked(); ++ ++ Bells = Alert->Bells->isChecked(); ++ ConnectBeep = Alert->InboundBeep->isChecked(); ++ AlertBeep = Alert->InactivityBeep->isChecked(); ++ AlertInterval = Alert->Interval->text().toInt(); ++ ++ UseKeywords = Alert->KeywordBeep->isChecked(); ++ KeyWordsFile = Alert->keywordFile->text(); ++ ++ ConnectWAV = Alert->connectFile->currentText(); ++ BellWAV = Alert->bellsFile->currentText(); ++ IntervalWAV = Alert->intervalFile->currentText(); ++ AlertWAV = Alert->keywordWAV->currentText(); ++ ++ delete(Alert); ++ SaveSettings(); ++ deviceUI->accept(); ++} ++ ++void QtTermTCP::alertReject() ++{ ++ delete(Alert); ++ deviceUI->reject(); ++} ++ ++ ++ ++void QtTermTCP::VARASlot() ++{ ++ // This runs the VARA Configuration dialog ++ ++ char valChar[80]; ++ ++ Dev = new(Ui_Dialog); ++ ++ QDialog UI; ++ ++ Dev->setupUi(&UI); ++ ++ UI.setFont(*menufont); ++ ++ deviceUI = &UI; ++ ++ Dev->VARAEnable->setChecked(VARAEnable); ++ Dev->TermCall->setText(VARATermCall); ++ ++ SetVARAParams(); ++ ++ connect(Dev->VARAHF, SIGNAL(toggled(bool)), this, SLOT(VARAHFChanged(bool))); ++ connect(Dev->VARAFM, SIGNAL(toggled(bool)), this, SLOT(VARAFMChanged(bool))); ++ connect(Dev->VARASAT, SIGNAL(toggled(bool)), this, SLOT(VARASATChanged(bool))); ++ ++ if (VARA500) ++ Dev->VARA500->setChecked(true); ++ else if (VARA2750) ++ Dev->VARA2750->setChecked(true); ++ else ++ Dev->VARA2300->setChecked(true); ++ ++ if (VARAHF) ++ Dev->VARAHF->setChecked(true); ++ else if (VARAFM) ++ Dev->VARAFM->setChecked(true); ++ else if (VARASAT) ++ Dev->VARASAT->setChecked(true); ++ ++ if (VARAHF == 0) ++ Dev->HFMode->setVisible(false); ++ ++ connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool))); ++ connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); ++ ++ if (PTTMode == PTTCAT) ++ Dev->CAT->setChecked(true); ++ else ++ Dev->RTSDTR->setChecked(true); ++ ++ if (CATHex) ++ Dev->CATHex->setChecked(true); ++ else ++ Dev->CATText->setChecked(true); ++ ++ sprintf(valChar, "%d", pttGPIOPin); ++ Dev->GPIOLeft->setText(valChar); ++ sprintf(valChar, "%d", pttGPIOPinR); ++ Dev->GPIORight->setText(valChar); ++ ++ Dev->VIDPID->setText(CM108Addr); ++ ++ ++ QStringList items; ++ ++#ifdef USESERIAL ++ ++ for (const QSerialPortInfo &info : Ports) ++ { ++ items.append(info.portName()); ++ } ++ ++ items.sort(); ++ ++#endif ++ ++ Dev->PTTPort->addItem("None"); ++ Dev->PTTPort->addItem("CM108"); ++ ++#ifdef __ARM_ARCH ++ ++ // Dev->PTTPort->addItem("GPIO"); ++ ++#endif ++ ++ Dev->PTTPort->addItem("FLRIG"); ++ Dev->PTTPort->addItem("HAMLIB"); ++ ++ for (const QString &info : items) ++ { ++ Dev->PTTPort->addItem(info); ++ } ++ ++ Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString)); ++ ++ PTTPortChanged(0); // Force reevaluation ++ ++ QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept())); ++ QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject())); ++ ++ UI.exec(); ++ ++} ++ ++extern QProcess *process; ++ ++void ClosePTTPort(); ++ ++void QtTermTCP::deviceaccept() ++{ ++ QVariant Q; ++ ++ int OldEnable = VARAEnable; ++ int OldPort = VARAPortNum; ++ char oldHost[128]; ++ char oldPath[256]; ++ ++ strcpy(oldHost, VARAHost); ++ strcpy(oldPath, VARAPath); ++ ++ VARAEnable = Dev->VARAEnable->isChecked(); ++ ++ strcpy(VARATermCall, Dev->TermCall->text().toUtf8().toUpper()); ++ ++ Q = Dev->Port->text(); ++ ++ VARAPortNum = Q.toInt(); ++ strcpy(VARAHost, Dev->Host->text().toUtf8().toUpper()); ++ strcpy(VARAPath, Dev->Path->text().toUtf8()); ++ strcpy(VARAInit, Dev->InitCommands->text().toUtf8()); ++ ++ VARA500 = Dev->VARA500->isChecked(); ++ VARA2300 = Dev->VARA2300->isChecked(); ++ VARA2750 = Dev->VARA2750->isChecked(); ++ ++ VARAHF = Dev->VARAHF->isChecked(); ++ VARAFM = Dev->VARAFM->isChecked(); ++ VARASAT = Dev->VARASAT->isChecked(); ++ ++ if (VARAHF) ++ { ++ strcpy(VARAHostHF, VARAHost); ++ strcpy(VARAPathHF, VARAPath); ++ VARAPortHF = VARAPortNum; ++ } ++ else if (VARAFM) ++ { ++ strcpy(VARAHostFM, VARAHost); ++ strcpy(VARAPathFM, VARAPath); ++ VARAPortFM = VARAPortNum; ++ } ++ else if (VARASAT) ++ { ++ strcpy(VARAHostSAT, VARAHost); ++ strcpy(VARAPathSAT, VARAPath); ++ VARAPortSAT = VARAPortNum; ++ } ++ ++ Q = Dev->PTTPort->currentText(); ++ strcpy(PTTPort, Q.toString().toUtf8()); ++ ++ if (Dev->CAT->isChecked()) ++ PTTMode = PTTCAT; ++ else ++ PTTMode = PTTRTS; ++ ++ if (Dev->CATHex->isChecked()) ++ CATHex = 1; ++ else ++ CATHex = 0; ++ ++ Q = Dev->PTTOn->text(); ++ strcpy(PTTOnString, Q.toString().toUtf8()); ++ Q = Dev->PTTOff->text(); ++ strcpy(PTTOffString, Q.toString().toUtf8()); ++ ++ Q = Dev->CATSpeed->text(); ++ PTTBAUD = Q.toInt(); ++ ++ Q = Dev->GPIOLeft->text(); ++ pttGPIOPin = Q.toInt(); ++ ++ Q = Dev->GPIORight->text(); ++ pttGPIOPinR = Q.toInt(); ++ ++ Q = Dev->VIDPID->text(); ++ ++ if (strcmp(PTTPort, "CM108") == 0) ++ strcpy(CM108Addr, Q.toString().toUtf8()); ++ else if (strcmp(PTTPort, "HAMLIB") == 0) ++ { ++ HamLibPort = Q.toInt(); ++ Q = Dev->PTTOn->text(); ++ strcpy(HamLibHost, Q.toString().toUtf8()); ++ } ++ ++ if (VARAEnable != OldEnable || VARAPortNum != OldPort || strcmp(oldHost, VARAHost) != 0) ++ { ++ // (re)start connection ++ ++ if (OldEnable && VARASock && VARASock->ConnectedState == QAbstractSocket::ConnectedState) ++ { ++ VARASock->disconnectFromHost(); ++ if (VARADataSock) ++ VARADataSock->disconnectFromHost(); ++ Status2->setText("VARA Disconnected"); ++ } ++ } ++ ++ if (process && process->state() == QProcess::Running) ++ if ((VARAEnable == 0 || strcmp(oldPath, VARAPath) != 0)) ++ process->close(); ++ ++ myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable); ++ ++ ClosePTTPort(); ++ OpenPTTPort(); ++ ++ delete(Dev); ++ SaveSettings(); ++ deviceUI->accept(); ++ ++ QSize newSize(this->size()); ++ QSize oldSize(this->size()); ++ ++ QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); ++ ++ QCoreApplication::postEvent(this, myResizeEvent); ++} ++ ++void QtTermTCP::devicereject() ++{ ++ delete(Dev); ++ deviceUI->reject(); ++} ++ ++// This handles incoming connections ++ ++void QtTermTCP::onNewConnection() ++{ ++ myTcpSocket *clientSocket = (myTcpSocket *)_server->nextPendingConnection(); ++ ++ clientSocket->Sess = NULL; ++ ++ Ui_ListenSession * S; ++ Ui_ListenSession * Sess = NULL; ++ ++ char Title[512]; ++ int i = 0; ++ ++ QByteArray Host = clientSocket->peerAddress().toString().toUtf8(); ++ ++ if (TermMode == MDI) ++ { ++ // See if an old session can be reused ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ S = _sessions.at(i); ++ ++ // for (Ui_ListenSession * S: _sessions) ++ // { ++ if ((S->SessionType & Listen) && S->clientSocket == NULL) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ ++ // Create a window if none found, else reuse old ++ ++ if (Sess == NULL) ++ { ++ Sess = newWindow(this, Listen); ++ } ++ ++ QByteArray Host = clientSocket->peerAddress().toString().toUtf8(); ++ } ++ else ++ { ++ // Single or Tabbed - look for free session ++ ++ for (i = 0; i < _sessions.size(); ++i) ++ { ++ S = _sessions.at(i); ++ ++ if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ ++ if (Sess == NULL) ++ { ++ // Clear connection ++ ++ clientSocket->disconnectFromHost(); ++ return; ++ } ++ } ++ ++ _sockets.push_back(clientSocket); ++ ++ clientSocket->Sess = Sess; ++ ++ // See if any data from host - first msg should be callsign ++ ++ clientSocket->waitForReadyRead(1000); ++ ++ QByteArray datas = clientSocket->readAll(); ++ ++ datas.chop(2); ++ datas.truncate(10); // Just in case! ++ ++ strlop(datas.data(), 13); ++ ++ if (datas.data()[0] == 0) ++ datas.append("UNKNOWN\0"); ++ ++ datas.append('\0'); ++ ++ sprintf(Title, "Inward Connect from %s:%d Call %s", ++ Host.data(), clientSocket->peerPort(), datas.data()); ++ ++ if (TermMode == MDI) ++ { ++ Sess->setWindowTitle(Title); ++ } ++ else if (TermMode == Tabbed) ++ { ++ tabWidget->setTabText(i, datas.data()); ++ tabWidget->tabBar()->setTabTextColor(i, newTabText); ++ } ++ ++ else if (TermMode == Single) ++ this->setWindowTitle(Title); ++ ++ connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); ++ connect(clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); ++ ++ Sess->clientSocket = clientSocket; ++ ++ // We need to set Connect and Disconnect if the window is active ++ ++ if (TermMode == MDI && Sess->sw == ActiveSubWindow) ++ setMenus(true); ++ ++ if (TermMode == Tabbed && Sess->Tab == tabWidget->currentIndex()) ++ setMenus(true); ++ ++ if (TermMode == Single) ++ setMenus(true); // Single ++ ++ // Send CText if defined ++ ++ if (listenCText[0]) ++ Sess->clientSocket->write(listenCText); ++ ++ // Send Message to Terminal ++ ++ char Msg[80]; ++ ++ sprintf(Msg, "Listen Connect from %s\r\r", datas.data()); ++ ++ WritetoOutputWindow(Sess, (unsigned char *)Msg, (int)strlen(Msg)); ++ ++ if (ConnectBeep) ++ myBeep(&ConnectWAV); ++ ++ QApplication::alert(mythis, 0); ++} ++ ++void QtTermTCP::onSocketStateChanged(QAbstractSocket::SocketState socketState) ++{ ++ myTcpSocket* sender = static_cast(QObject::sender()); ++ Ui_ListenSession * Sess = (Ui_ListenSession *)sender->Sess; ++ ++ if (socketState == QAbstractSocket::UnconnectedState) ++ { ++ char Msg[] = "Disconnected\r"; ++ ++ WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), ++ Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red ++ ++ if (TermMode == MDI) ++ { ++ if (Sess->SessionType == Mon) // Mon Only ++ Sess->setWindowTitle("Monitor Session Disconnected"); ++ else ++ Sess->setWindowTitle("Disconnected"); ++ } ++ else if (TermMode == Tabbed) ++ { ++ if (Sess->SessionType == Mon) // Mon Only ++ tabWidget->setTabText(Sess->Tab, "Monitor"); ++ else ++ { ++ char Label[16]; ++ sprintf(Label, "Sess %d", Sess->Tab + 1); ++ tabWidget->setTabText(Sess->Tab, Label); ++ } ++ } ++ else if (TermMode == Single) ++ { ++ if (Sess->AGWMonSession) ++ mythis->setWindowTitle("AGW Monitor Window"); ++ else ++ { ++ if (Sess->SessionType == Mon) // Mon Only ++ this->setWindowTitle("Monitor Session Disconnected"); ++ else ++ this->setWindowTitle("Disconnected"); ++ } ++ } ++ ++ if (Sess->TTActive) ++ { ++ Sess->TTActive = 0; ++ DoTermResize(Sess); ++ } ++ ++ Sess->PortMonString[0] = 0; ++ ++ // delete(Sess->clientSocket); ++ Sess->clientSocket = NULL; ++ ++ discAction->setEnabled(false); ++ ++ if ((Sess->SessionType & Listen)) ++ _sockets.removeOne(sender); ++ else ++ { ++ connectMenu->setEnabled(true); ++ YAPPSend->setEnabled(false); ++ } ++ } ++ else if (socketState == QAbstractSocket::ConnectedState) ++ { ++ char Signon[256]; ++ char Title[128]; ++ ++ // only seems to be triggered for outward connect ++ ++ sprintf(Signon, "%s\r%s\rBPQTERMTCP\r", UserName[Sess->CurrentHost], Password[Sess->CurrentHost]); ++ ++ Sess->clientSocket->write(Signon); ++ ++ discAction->setEnabled(true); ++ YAPPSend->setEnabled(true); ++ connectMenu->setEnabled(false); ++ ++ SendTraceOptions(Sess); ++ ++ Sess->InputMode = 0; ++ Sess->SlowTimer = 0; ++ Sess->MonData = 0; ++ Sess->OutputSaveLen = 0; // Clear any part line ++ Sess->MonSaveLen = 0; // Clear any part line ++ ++ if (Sess->SessionType == Mon) // Mon Only ++ sprintf(Title, "Monitor Session Connected to %s", Host[Sess->CurrentHost]); ++ else ++ { ++ char Label[256]; ++ ++ if (SessName[Sess->CurrentHost][0]) ++ sprintf(Label, "%s(%s)", Host[Sess->CurrentHost], SessName[Sess->CurrentHost]); ++ else ++ strcpy(Label, Host[Sess->CurrentHost]); ++ ++ sprintf(Title, "Connected to %s", Label); ++ } ++ ++ if (TermMode == MDI) ++ Sess->setWindowTitle(Title); ++ else if (TermMode == Tabbed) ++ { ++ if (SessName[Sess->CurrentHost][0]) ++ tabWidget->setTabText(Sess->Tab, SessName[Sess->CurrentHost]); ++ else ++ tabWidget->setTabText(Sess->Tab, Host[Sess->CurrentHost]); ++ } ++ else if (TermMode == Single) ++ this->setWindowTitle(Title); ++ } ++} ++ ++void QtTermTCP::updateWindowMenu() ++{ ++ if (TermMode == MDI) ++ { ++ windowMenu->clear(); ++ windowMenu->addAction(newTermAct); ++ windowMenu->addAction(newMonAct); ++ windowMenu->addAction(newCombinedAct); ++ windowMenu->addSeparator(); ++ windowMenu->addAction(closeAct); ++ windowMenu->addAction(closeAllAct); ++ windowMenu->addSeparator(); ++ windowMenu->addAction(tileAct); ++ windowMenu->addAction(cascadeAct); ++ windowMenu->addSeparator(); ++ windowMenu->addAction(nextAct); ++ windowMenu->addAction(previousAct); ++ windowMenu->addAction(quitAction); ++ windowMenu->addAction(windowMenuSeparatorAct); ++ ++ QList windows = mdiArea->subWindowList(); ++ windowMenuSeparatorAct->setVisible(!windows.isEmpty()); ++ ++ Ui_ListenSession * Sess; ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ Sess->actActivate = windowMenu->addAction(Sess->sw->windowTitle()); ++ QAction::connect(Sess->actActivate, SIGNAL(triggered()), this, SLOT(actActivate())); ++ Sess->actActivate->setCheckable(true); ++ Sess->actActivate->setChecked(ActiveSubWindow == Sess->sw); ++ } ++ } ++ else if (TermMode == Tabbed) ++ { ++ windowMenu->clear(); ++ ++ Ui_ListenSession * Sess = (Ui_ListenSession *)tabWidget->currentWidget(); ++ ++ QActionGroup * termGroup = new QActionGroup(this); ++ ++ delete(TabSingle); ++ delete(TabBoth); ++ delete(TabMon); ++ ++ TabSingle = setupMenuLine(nullptr, (char *)"Terminal Only", this, (Sess->SessionType == Term)); ++ TabBoth = setupMenuLine(nullptr, (char *)"Terminal + Monitor", this, (Sess->SessionType == Term + Mon)); ++ TabMon = setupMenuLine(nullptr, (char *)"Monitor Only", this, (Sess->SessionType == Mon)); ++ ++ termGroup->addAction(TabSingle); ++ termGroup->addAction(TabBoth); ++ termGroup->addAction(TabMon); ++ ++ windowMenu->addAction(TabSingle); ++ windowMenu->addAction(TabBoth); ++ windowMenu->addAction(TabMon); ++ ++ } ++} ++ ++Ui_ListenSession::~Ui_ListenSession() ++{ ++ if (this->clientSocket) ++ { ++ int loops = 100; ++ this->clientSocket->disconnectFromHost(); ++ while (loops-- && this->clientSocket->state() != QAbstractSocket::UnconnectedState) ++ QThread::msleep(10); ++ } ++} ++ ++extern "C" void setTraceOff(Ui_ListenSession * Sess) ++{ ++ if ((Sess->SessionType & Mon) == 0) ++ return; // Not Monitor ++ ++ if (Sess->AGWMonSession) ++ return; ++ ++ char Buffer[80]; ++ int Len = sprintf(Buffer, "\\\\\\\\0 0 0 0 0 0 0 0\r"); ++ ++ SocketFlush(Sess); ++ SocketSend(Sess, Buffer, Len); ++ SocketFlush(Sess); ++} ++ ++ ++extern "C" void SendTraceOptions(Ui_ListenSession * Sess) ++{ ++ if ((Sess->SessionType & Mon) == 0) ++ return; // Not Monitor ++ ++ if (Sess->AGWMonSession) ++ return; ++ ++ char Buffer[80]; ++ int Len = sprintf(Buffer, "\\\\\\\\%llx %x %x %x %x %x %x %x\r", Sess->portmask, Sess->mtxparam | (Sess->mlocaltime << 7), ++ Sess->mcomparam, Sess->MonitorNODES, Sess->MonitorColour, Sess->monUI, 0, 1); ++ ++ strcpy(&MonParams[Sess->CurrentHost][0], &Buffer[4]); ++ SaveSettings(); ++ SocketFlush(Sess); ++ SocketSend(Sess, Buffer, Len); ++ SocketFlush(Sess); ++} ++ ++void QtTermTCP::doNewTerm() ++{ ++ newWindow(this, Term); ++} ++ ++void QtTermTCP::doNewMon() ++{ ++ newWindow(this, Mon); ++} ++ ++void QtTermTCP::doNewCombined() ++{ ++ newWindow(this, Term + Mon); ++} ++ ++void QtTermTCP::doCascade() ++{ ++ // Qt Cascade Minimizes windows so do it ourselves ++ ++ int x = 0, y = 0; ++ ++ Ui_ListenSession * Sess; ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ Sess->sw->move(x, y); ++ x += 14; ++ y += 30; ++ } ++} ++ ++void QtTermTCP::actActivate() ++{ ++ QAction * sender = static_cast(QObject::sender()); ++ ++ Ui_ListenSession * Sess; ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->actActivate == sender) ++ { ++ mdiArea->setActiveSubWindow(Sess->sw); ++ return; ++ } ++ } ++} ++ ++ ++void QtTermTCP::xon_mdiArea_changed() ++{ ++ // This is triggered when the Active MDI window changes ++ // and is used to enable/disable Connect, Disconnect and YAPP Send ++ ++ ++ QMdiSubWindow *SW = mdiArea->activeSubWindow(); ++ ++ // Dont waste time if not changed ++ ++ if (ActiveSubWindow == SW) ++ return; ++ ++ ActiveSubWindow = SW; ++ ++ Ui_ListenSession * Sess; ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ // for (Ui_ListenSession * Sess : _sessions) ++ // { ++ if (Sess->sw == SW) ++ { ++ ActiveSession = Sess; ++ ++ if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) ++ { ++ discAction->setEnabled(true); ++ YAPPSend->setEnabled(true); ++ connectMenu->setEnabled(false); ++ } ++ else if (Sess->AGWMonSession) ++ { ++ // Connected AGW Monitor Session ++ ++ discAction->setEnabled(false); ++ YAPPSend->setEnabled(false); ++ connectMenu->setEnabled(false); ++ } ++ else if (Sess->AGWSession || Sess->KISSSession) ++ { ++ // Connected AGW or KISS Terminal Session ++ ++ discAction->setEnabled(true); ++ YAPPSend->setEnabled(true); ++ connectMenu->setEnabled(false); ++ } ++ else ++ { ++ // Not connected ++ ++ discAction->setEnabled(false); ++ YAPPSend->setEnabled(false); ++ ++ if ((Sess->SessionType & Listen)) // Listen Sessions can't connect ++ connectMenu->setEnabled(false); ++ else ++ connectMenu->setEnabled(true); ++ } ++ ++ // If a monitor Window, change Monitor config settings ++ ++ EnableMonLog->setChecked(Sess->LogMonitor); ++ ++ if (AGWUsers && Sess == AGWUsers->MonSess) // AGW Monitor ++ { ++ for (int i = 0; i < 64; i++) ++ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden ++ ++ connectMenu->setEnabled(false); ++ MonTX->setVisible(0); ++ MonSup->setVisible(0); ++ MonUI->setVisible(0); ++ MonColour->setVisible(0); ++ ++ EnableMonitor->setVisible(1); ++ EnableMonitor->setChecked(AGWMonEnable); ++ ++ MonLocalTime->setChecked(Sess->mlocaltime); ++ MonNodes->setChecked(Sess->MonitorNODES); ++ } ++ else if (Sess == KISSMonSess) // KISS Monitor ++ { ++ for (int i = 0; i < 64; i++) ++ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden ++ ++ connectMenu->setEnabled(false); ++ MonTX->setVisible(0); ++ MonSup->setVisible(0); ++ MonUI->setVisible(0); ++ MonColour->setVisible(0); ++ ++ EnableMonitor->setVisible(1); ++ EnableMonitor->setChecked(KISSMonEnable); ++ MonLocalTime->setChecked(Sess->mlocaltime); ++ MonNodes->setChecked(Sess->MonitorNODES); ++ } ++ ++ else ++ { ++ EnableMonitor->setVisible(0); ++ MonTX->setVisible(1); ++ MonSup->setVisible(1); ++ MonUI->setVisible(1); ++ MonColour->setVisible(1); ++ } ++ ++ if (Sess->PortMonString[0]) ++ { ++ char * ptr = (char *)malloc(2048); ++ memcpy(ptr, Sess->PortMonString, 2048); ++ ++ int NumberofPorts = atoi((char *)&ptr[2]); ++ char *p, *Context; ++ char msg[80]; ++ int portnum; ++ char delim[] = "|"; ++ ++ // Remove old Monitor menu ++ ++ for (int i = 0; i < 64; i++) ++ { ++ SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden ++ } ++ ++ p = strtok_s((char *)&ptr[2], delim, &Context); ++ ++ while (NumberofPorts--) ++ { ++ p = strtok_s(NULL, delim, &Context); ++ if (p == NULL) ++ break; ++ ++ portnum = atoi(p); ++ ++ sprintf(msg, "Port %s", p); ++ ++ if (portnum == 0) ++ portnum = 64; ++ ++ if (Sess->portmask & (1ll << (portnum - 1))) ++ SetPortMonLine(portnum, msg, 1, 1); ++ else ++ SetPortMonLine(portnum, msg, 1, 0); ++ } ++ free(ptr); ++ ++ MonLocalTime->setChecked(Sess->mlocaltime); ++ MonTX->setChecked(Sess->mtxparam); ++ MonSup->setChecked(Sess->mcomparam); ++ MonUI->setChecked(Sess->monUI); ++ MonNodes->setChecked(Sess->MonitorNODES); ++ MonColour->setChecked(Sess->MonitorColour); ++ ++ } ++ ++ return; ++ } ++ } ++} ++ ++void QtTermTCP::doFonts() ++{ ++ fontDialog * xx = new fontDialog(0); ++ xx->exec(); ++} ++ ++void QtTermTCP::doMFonts() ++{ ++ fontDialog * xx = new fontDialog(1); ++ xx->exec(); ++} ++ ++QColor TempmonBackground = monBackground; ++QColor TemptermBackground = termBackground; ++QColor TempinputBackground = inputBackground; ++ ++QColor TempmonRxText = monRxText; ++QColor TempmonTxText = monTxText; ++QColor TempmonOtherText = monOtherText; ++ ++QColor TempoutputText = outputText; ++QColor TempEchoText = EchoText; ++QColor TempWarningText = WarningText; ++ ++ ++QColor TempinputText = inputText; ++ ++ ++void setDialogColours() ++{ ++ char monStyle[128]; ++ ++ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", ++ TempmonOtherText.red(), TempmonOtherText.green(), TempmonOtherText.blue(), ++ TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); ++ ++ COLOURS->MonitorBG->setStyleSheet(monStyle); ++ COLOURS->MonOther->setStyleSheet(monStyle); ++ ++ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", ++ TempmonTxText.red(), TempmonTxText.green(), TempmonTxText.blue(), ++ TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); ++ COLOURS->MonTX->setStyleSheet(monStyle); ++ ++ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", ++ TempmonRxText.red(), TempmonRxText.green(), TempmonRxText.blue(), ++ TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); ++ ++ COLOURS->MonRX->setStyleSheet(monStyle); ++ ++ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", ++ TempoutputText.red(), TempoutputText.green(), TempoutputText.blue(), ++ TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); ++ ++ COLOURS->TermBG->setStyleSheet(monStyle); ++ COLOURS->TermNormal->setStyleSheet(monStyle); ++ ++ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", ++ TempEchoText.red(), TempEchoText.green(), TempEchoText.blue(), ++ TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); ++ ++ COLOURS->Echoed->setStyleSheet(monStyle); ++ ++ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", ++ TempWarningText.red(), TempWarningText.green(), TempWarningText.blue(), ++ TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); ++ ++ COLOURS->Warning->setStyleSheet(monStyle); ++ ++ sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", ++ TempinputText.red(), TempinputText.green(), TempinputText.blue(), ++ TempinputBackground.red(), TempinputBackground.green(), TempinputBackground.blue()); ++ ++ COLOURS->InputBG->setStyleSheet(monStyle); ++ COLOURS->InputColour->setStyleSheet(monStyle); ++ ++} ++ ++void QtTermTCP::doColours() ++{ ++ COLOURS = new(Ui_ColourDialog); ++ ++ QDialog UI; ++ ++ COLOURS->setupUi(&UI); ++ ++ UI.setFont(*menufont); ++ ++ deviceUI = &UI; ++ ++ TempmonBackground = monBackground; ++ TempmonRxText = monRxText; ++ TempmonTxText = monTxText; ++ TempmonOtherText = monOtherText; ++ ++ TemptermBackground = termBackground; ++ TempoutputText = outputText; ++ TempEchoText = EchoText; ++ TempWarningText = WarningText; ++ ++ TempinputBackground = inputBackground; ++ TempinputText = inputText; ++ ++ setDialogColours(); ++ ++ QObject::connect(COLOURS->MonitorBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ QObject::connect(COLOURS->TermBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ QObject::connect(COLOURS->InputBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ QObject::connect(COLOURS->MonRX, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ QObject::connect(COLOURS->MonTX, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ QObject::connect(COLOURS->MonOther, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ QObject::connect(COLOURS->TermNormal, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ QObject::connect(COLOURS->Echoed, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ QObject::connect(COLOURS->Warning, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ QObject::connect(COLOURS->InputColour, SIGNAL(clicked()), this, SLOT(ColourPressed())); ++ ++ QObject::connect(COLOURS->okButton, SIGNAL(clicked()), this, SLOT(Colouraccept())); ++ QObject::connect(COLOURS->cancelButton, SIGNAL(clicked()), this, SLOT(Colourreject())); ++ ++ UI.exec(); ++ ++} ++ ++void QtTermTCP::ColourPressed() ++{ ++ char Name[32]; ++ ++ strcpy(Name, sender()->objectName().toUtf8()); ++ ++ if (strcmp(Name, "MonitorBG") == 0) ++ TempmonBackground = setColor(TempmonBackground); ++ ++ else if (strcmp(Name, "MonTX") == 0) ++ TempmonTxText = setColor(TempmonTxText); ++ ++ else if (strcmp(Name, "MonRX") == 0) ++ TempmonRxText = setColor(TempmonRxText); ++ ++ else if (strcmp(Name, "MonOther") == 0) ++ TempmonOtherText = setColor(TempmonOtherText); ++ ++ else if (strcmp(Name, "TermBG") == 0) ++ TemptermBackground = setColor(TemptermBackground); ++ ++ else if (strcmp(Name, "InputBG") == 0) ++ TempinputBackground = setColor(TempinputBackground); ++ ++ else if (strcmp(Name, "InputColour") == 0) ++ TempinputText = setColor(TempinputText); ++ ++ else if (strcmp(Name, "TermNormal") == 0) ++ TempoutputText = setColor(TempoutputText); ++ ++ else if (strcmp(Name, "Echoed") == 0) ++ TempEchoText = setColor(TempEchoText); ++ ++ else if (strcmp(Name, "Warning") == 0) ++ TempWarningText = setColor(TempWarningText); ++ ++ setDialogColours(); ++} ++ ++ ++void QtTermTCP::Colouraccept() ++{ ++ monBackground = TempmonBackground; ++ monRxText = TempmonRxText; ++ monTxText = TempmonTxText; ++ monOtherText = TempmonOtherText; ++ ++ termBackground = TemptermBackground; ++ EchoText = TempEchoText; ++ WarningText = TempWarningText; ++ outputText = TempoutputText; ++ ++ inputBackground = TempinputBackground; ++ inputText = TempinputText; ++ ++ // Set background colour for new windows ++ ++ sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);", ++ monBackground.red(), monBackground.green(), monBackground.blue()); ++ ++ sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);", ++ termBackground.red(), termBackground.green(), termBackground.blue()); ++ ++ sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", ++ inputText.red(), inputText.green(), inputText.blue(), ++ inputBackground.red(), inputBackground.green(), inputBackground.blue()); ++ ++ // Update existing windows ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Ui_ListenSession * S = _sessions.at(i); ++ ++ if (S->monWindow) ++ S->monWindow->setStyleSheet(monStyleSheet); ++ ++ if (S->termWindow) ++ S->termWindow->setStyleSheet(termStyleSheet); ++ ++ if (S->inputWindow) ++ S->inputWindow->setStyleSheet(inputStyleSheet); ++ ++ } ++ ++ ++ delete(COLOURS); ++ ++ SaveSettings(); ++ deviceUI->accept(); ++} ++ ++void QtTermTCP::Colourreject() ++{ ++ delete(COLOURS); ++ deviceUI->reject(); ++} ++ ++ ++void QtTermTCP::ConnecttoVARA() ++{ ++ ++ delete(VARASock); ++ ++ VARASock = new myTcpSocket(); ++ ++ connect(VARASock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(VARAdisplayError(QAbstractSocket::SocketError))); ++ connect(VARASock, SIGNAL(readyRead()), this, SLOT(VARAreadyRead())); ++ connect(VARASock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onVARASocketStateChanged(QAbstractSocket::SocketState))); ++ ++ VARASock->connectToHost(VARAHost, VARAPortNum); ++ ++ Status2->setText("VARA Control Connecting"); ++ ++ return; ++} ++ ++ ++void QtTermTCP::VARATimer() ++{ ++ // Runs every 10 Seconds ++ ++ if (VARAConnected == 0 && VARAConnecting == 0) ++ { ++ if (process == nullptr || process->state() == QProcess::NotRunning) ++ { ++ if (VARAPath[0]) ++ { ++ process = new QProcess(this); ++ QString file = VARAPath; ++ process->start(file); ++ } ++ } ++ QThread::msleep(1000); ++ VARAConnecting = true; ++ ConnecttoVARA(); ++ } ++} ++ ++ ++void QtTermTCP::VARAdisplayError(QAbstractSocket::SocketError socketError) ++{ ++ switch (socketError) ++ { ++ case QAbstractSocket::RemoteHostClosedError: ++ break; ++ ++ case QAbstractSocket::HostNotFoundError: ++ QMessageBox::information(this, tr("QtTermTCP"), ++ tr("VARA host was not found. Please check the " ++ "host name and portsettings->")); ++ ++ Status2->setText("VARA Connection Failed"); ++ ++ break; ++ ++ case QAbstractSocket::ConnectionRefusedError: ++ ++ Status2->setText("VARA Connection Refused"); ++ break; ++ ++ default: ++ ++ Status2->setText("VARA Connection Failed"); ++ } ++ ++ VARAConnecting = 0; ++ VARAConnected = 0; ++} ++ ++void QtTermTCP::VARAreadyRead() ++{ ++ int Read; ++ char Buffer[4096]; ++ char * ptr; ++ char * Msg; ++ myTcpSocket* Socket = static_cast(QObject::sender()); ++ ++ // read the data from the socket ++ ++ Read = Socket->read((char *)Buffer, 4095); ++ ++ Buffer[Read] = 0; ++ ++ Msg = Buffer; ++ ++ ptr = strchr(Msg, 0x0d); ++ ++ while (ptr) ++ { ++ *ptr++ = 0; ++ ++ if (strcmp(Msg, "IAMALIVE") == 0) ++ { ++ } ++ else if (strcmp(Msg, "PTT ON") == 0) ++ { ++ RadioPTT(1); ++ } ++ else if (strcmp(Msg, "PTT OFF") == 0) ++ { ++ RadioPTT(0); ++ } ++ else if (strcmp(Msg, "PENDING") == 0) ++ { ++ } ++ else if (strcmp(Msg, "CANCELPENDING") == 0) ++ { ++ } ++ else if (strcmp(Msg, "OK") == 0) ++ { ++ } ++ else if (memcmp(Msg, "CONNECTED ", 10) == 0) ++ { ++ Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess; ++ char Title[128] = ""; ++ char CallFrom[64] = ""; ++ char CallTo[64] = ""; ++ char Mode[64] = ""; ++ char Message[128]; ++ int n; ++ ++ ++ sscanf(&Msg[10], "%s %s %s", CallFrom, CallTo, Mode); ++ ++ if (Sess) ++ { ++ if (Mode[0]) ++ sprintf(Title, "Connected to %s %s Mode", CallTo, Mode); ++ else ++ sprintf(Title, "Connected to %s", CallTo); ++ ++ n = sprintf(Message, "%s\r\n", Title); ++ WritetoOutputWindow(Sess, (unsigned char *)Message, n); ++ ++ if (TermMode == MDI) ++ Sess->setWindowTitle(Title); ++ else if (TermMode == Tabbed) ++ tabWidget->setTabText(Sess->Tab, CallTo); ++ else if (TermMode == Single) ++ mythis->setWindowTitle(Title); ++ ++ setMenus(true); ++ } ++ else ++ { ++ // Incoming Call ++ ++ Ui_ListenSession * S; ++ int i = 0; ++ ++ if (TermMode == MDI) ++ { ++ // See if an old session can be reused ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ S = _sessions.at(i); ++ ++ // for (Ui_ListenSession * S: _sessions) ++ // { ++ if ((S->SessionType & Listen) && S->clientSocket == NULL) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ ++ // Create a window if none found, else reuse old ++ ++ if (Sess == NULL) ++ { ++ Sess = newWindow(this, Listen); ++ } ++ } ++ else ++ { ++ // Single or Tabbed - look for free session ++ ++ for (i = 0; i < _sessions.size(); ++i) ++ { ++ S = _sessions.at(i); ++ ++ if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ } ++ ++ if (Sess == NULL) ++ { ++ // Clear connection ++ ++ VARASock->write("DISCONNECT\r"); ++ } ++ else ++ { ++ if (Mode[0]) ++ { ++ sprintf(Title, "Connected to %s Mode %s", CallFrom, Mode); ++ n = sprintf(Message, "Incoming VARA Connect from %s %s Mode\r\n", CallFrom, Mode); ++ } ++ else ++ { ++ sprintf(Title, "Connected to %s", CallFrom); ++ n = sprintf(Message, "Incoming VARA Connect from %s\r\n", CallFrom); ++ } ++ ++ WritetoOutputWindow(Sess, (unsigned char *)Message, n); ++ ++ VARASock->Sess = Sess; ++ VARADataSock->Sess = Sess; ++ ++ if (TermMode == MDI) ++ Sess->setWindowTitle(Title); ++ else if (TermMode == Tabbed) ++ { ++ tabWidget->setTabText(Sess->Tab, CallFrom); ++ tabWidget->tabBar()->setTabTextColor(Sess->Tab, newTabText); ++ } ++ else if (TermMode == Single) ++ mythis->setWindowTitle(Title); ++ ++ setMenus(true); ++ ++ if (ConnectBeep) ++ myBeep(&ConnectWAV); ++ ++ if (listenCText[0]) ++ VARADataSock->write(listenCText); ++ ++ QApplication::alert(mythis, 0); ++ ++ } ++ } ++ } ++ else if (strcmp(Msg, "DISCONNECTED") == 0) ++ { ++ Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess; ++ ++ if (Sess) ++ { ++ WritetoOutputWindow(Sess, (unsigned char *)"Disconnected\r\n", 14); ++ VARASock->Sess = 0; ++ VARADataSock->Sess = 0; ++ ++ if (TermMode == MDI) ++ { ++ if (Sess->SessionType == Mon) // Mon Only ++ Sess->setWindowTitle("Monitor Session Disconnected"); ++ else ++ Sess->setWindowTitle("Disconnected"); ++ } ++ else if (TermMode == Tabbed) ++ { ++ if (Sess->SessionType == Mon) // Mon Only ++ tabWidget->setTabText(Sess->Tab, "Monitor"); ++ else ++ { ++ char Label[16]; ++ sprintf(Label, "Sess %d", Sess->Tab + 1); ++ tabWidget->setTabText(Sess->Tab, Label); ++ } ++ } ++ else if (TermMode == Single) ++ { ++ if (Sess->AGWMonSession) ++ mythis->setWindowTitle("AGW Monitor Window"); ++ else ++ { ++ if (Sess->SessionType == Mon) // Mon Only ++ this->setWindowTitle("Monitor Session Disconnected"); ++ else ++ this->setWindowTitle("Disconnected"); ++ } ++ } ++ ++ setMenus(false); ++ } ++ } ++ ++ Msg = ptr; ++ ++ ptr = strchr(Msg, 0x0d); ++ } ++ ++ ++ ++} ++ ++void QtTermTCP::onVARASocketStateChanged(QAbstractSocket::SocketState socketState) ++{ ++ // myTcpSocket* sender = static_cast(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 ++} ++ ++#ifndef ANDRIOD ++ ++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; ++ ++} ++ ++#endif ++ ++void QtTermTCP::RadioPTT(bool PTTState) ++{ ++#ifdef __ARM_ARCH ++ if (useGPIO) ++ { ++ // gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); ++ // return; ++ } ++ ++#endif ++ ++ if ((PTTMode & PTTCM108)) ++ { ++ CM108_set_ptt(PTTState); ++ return; ++ } ++ ++ if ((PTTMode & PTTHAMLIB)) ++ { ++ HAMLIBSetPTT(PTTState); ++ return; ++ } ++ ++ if ((PTTMode & PTTFLRIG)) ++ { ++ FLRigSetPTT(PTTState); ++ return; ++ } ++ ++#ifdef USESERIAL ++ ++ if (hPTTDevice == 0) ++ return; ++ ++ if ((PTTMode & PTTCAT)) ++ { ++ if (PTTState) ++ hPTTDevice->write((char *)PTTOnCmd, PTTOnCmdLen); ++ else ++ hPTTDevice->write((char *)PTTOffCmd, PTTOffCmdLen); ++ ++ hPTTDevice->flush(); ++ // hPTTDevice->error(); ++ return; ++ ++ } ++ ++ ++ if ((PTTMode & PTTRTS)) ++ { ++ int n = hPTTDevice->setRequestToSend(PTTState); ++ n = n; ++ } ++ ++#endif ++ ++} ++ ++ ++ ++extern "C" void WriteDebugLog(char * Mess) ++{ ++ qDebug() << Mess; ++} ++ ++void QtTermTCP::ConnecttoKISS() ++{ ++ if (strcmp(SerialPort, "TCP") == 0) ++ { ++ delete(KISSSock); ++ ++ KISSSock = new myTcpSocket(); ++ KISSSockCopy[0] = (void *)KISSSock; ++ ++ ++ connect(KISSSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(KISSdisplayError(QAbstractSocket::SocketError))); ++ connect(KISSSock, SIGNAL(readyRead()), this, SLOT(KISSreadyRead())); ++ connect(KISSSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onKISSSocketStateChanged(QAbstractSocket::SocketState))); ++ ++ KISSSock->connectToHost(KISSHost, KISSPortNum); ++ ++ Status3->setText("KISS Connecting"); ++ } ++ else ++ openSerialPort(); ++ ++ return; ++} ++ ++ ++void QtTermTCP::KISSTimer() ++{ ++ // Runs every 10 Seconds ++ ++ if (KISSConnected == 0 && KISSConnecting == 0) ++ { ++ ConnecttoKISS(); ++ } ++ else ++ { ++ // Verify Serial port is still ok ++ ++ if (m_serial && KISSConnected) ++ { ++ m_serial->clearError(); ++ boolean rc = m_serial->isDataTerminalReady(); ++ ++ if (m_serial->error()) ++ { ++ Debugprintf("Serial Port Lost - isOpen %d Error %d", m_serial->isOpen(), m_serial->error()); ++ closeSerialPort(); ++ } ++ } ++ } ++} ++ ++ ++ ++void QtTermTCP::KISSdisplayError(QAbstractSocket::SocketError socketError) ++{ ++ switch (socketError) ++ { ++ case QAbstractSocket::RemoteHostClosedError: ++ break; ++ ++ case QAbstractSocket::HostNotFoundError: ++ QMessageBox::information(this, tr("QtTermTCP"), ++ tr("KISS host was not found. Please check the " ++ "host name and portsettings->")); ++ ++ Status3->setText("KISS Connection Failed"); ++ ++ break; ++ ++ case QAbstractSocket::ConnectionRefusedError: ++ ++ Status3->setText("KISS Connection Refused"); ++ break; ++ ++ default: ++ ++ Status3->setText("KISS Connection Failed"); ++ } ++ ++ KISSConnecting = 0; ++ KISSConnected = 0; ++} ++ ++ ++extern "C" void KISSSendtoServer(myTcpSocket* Socket, char * Data, int Length) ++{ ++ if (m_serial) ++ { ++ if (m_serial->isOpen()) ++ { ++ m_serial->clearError(); ++ ++ int n = m_serial->write(Data, Length); ++ ++ n = m_serial->flush(); ++ ++ if (m_serial->error()) ++ { ++ Debugprintf("Serial Flush Error - Requested = %d Actual %d Error %d", Length, n, m_serial->error()); ++ closeSerialPort(); ++ } ++ } ++ } ++ else if (Socket) ++ Socket->write(Data, Length); ++} ++ ++ ++ ++void QtTermTCP::KISSreadyRead() ++{ ++ int Read; ++ unsigned char Buffer[4096]; myTcpSocket* Socket = static_cast(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); ++ ++ // send TXDelay if enabled ++ ++ if (sendTXDelay[0]) ++ { ++ unsigned char Msg[5] = { FEND, 1, 25 , FEND }; ++ ++ Msg[2] = txdelay[0] / 10; ++ KISSSock->write((char *)Msg, 4); ++ } ++ ++ // Attach a Monitor Window if available ++ ++ Ui_ListenSession * Sess = NULL; ++ Ui_ListenSession * S; ++ ++ if (TermMode == MDI) ++ { ++ // See if an old session can be reused ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ S = _sessions.at(i); ++ ++ // for (Ui_ListenSession * S: _sessions) ++ // { ++ if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ ++ // Create a window if none found, else reuse old ++ ++ if (Sess == NULL) ++ { ++ Sess = newWindow((QObject *)mythis, Mon, ""); ++ } ++ } ++ else if (TermMode == Tabbed) ++ { ++ // Tabbed - look for free session ++ ++ for (i = 8; i; i--) ++ { ++ S = _sessions.at(i); ++ ++ if (S->clientSocket == NULL && S->KISSSession == NULL && S->AGWSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ } ++ else if (TermMode == Single && (singlemodeFormat & Mon)) ++ { ++ S = _sessions.at(0); ++ ++ if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) ++ Sess = S; ++ ++ } ++ ++ if (Sess) ++ { ++ KISSMonSess = Sess; // Flag as in use ++ ++ if (TermMode == MDI) ++ Sess->setWindowTitle("KISS Monitor Window"); ++ else if (TermMode == Tabbed) ++ tabWidget->setTabText(Sess->Tab, "KISS Mon"); ++ else if (TermMode == Single) ++ mythis->setWindowTitle("KISS Monitor Window"); ++ ++ Sess->mlocaltime = KISSLocalTime; ++ Sess->MonitorNODES = KISSMonNodes; ++ ++ // if (TermMode == Single) ++ // { ++ // discAction->setEnabled(false); ++ // YAPPSend->setEnabled(false); ++ // connectMenu->setEnabled(false); ++ // } ++ } ++ } ++} ++ ++ ++extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat); ++extern "C" char * ShortDateTime(); ++ ++extern "C" void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded) ++{ ++ UNUSED(excluded); ++ UNUSED(snd_ch); ++ ++ int Len; ++ char Msg[1024]; ++ ++ if (tx) ++ sprintf(Msg, "\x1b\x10%s", frame_monitor(frame, code, tx)); ++ else ++ sprintf(Msg, "\x1b\x11%s", frame_monitor(frame, code, tx)); ++ ++ Len = strlen(Msg); ++ ++ if (Len < 10) // Suppressed NODES ++ return; ++ ++ if (Msg[Len - 1] != '\r') ++ { ++ Msg[Len++] = '\r'; ++ Msg[Len] = 0; ++ } ++ ++ if (KISSMonSess) ++ WritetoMonWindow(KISSMonSess, (unsigned char *)Msg, Len); ++ ++} ++ ++extern "C" Ui_ListenSession * ax25IncomingConnect(TAX25Port * AX25Sess) ++{ ++ // Look for/create Terminal Window for connection ++ ++ Ui_ListenSession * Sess = NULL; ++ Ui_ListenSession * S; ++ char Title[80]; ++ int i = 0; ++ ++ if (TermMode == MDI) ++ { ++ // See if an old session can be reused ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ S = _sessions.at(i); ++ ++ if ((S->SessionType & Listen) && S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ ++ // Create a window if none found, else reuse old ++ ++ if (Sess == NULL) ++ { ++ Sess = newWindow((QObject *)mythis, Listen, ""); ++ } ++ } ++ else ++ { ++ // Single or Tabbed - look for free session ++ ++ ++ for (i = 0; i < _sessions.size(); ++i) ++ { ++ S = _sessions.at(i); ++ ++ if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ ++ if (Sess == NULL) ++ { ++ // Clear connection ++ ++ return NULL; ++ } ++ } ++ ++ if (Sess) ++ { ++ sprintf(Title, "Connected to %s", AX25Sess->corrcall); ++ ++ if (TermMode == MDI) ++ { ++ Sess->setWindowTitle(Title); ++ } ++ else if (TermMode == Tabbed) ++ { ++ tabWidget->setTabText(i, AX25Sess->corrcall); ++ tabWidget->tabBar()->setTabTextColor(i, newTabText); ++ } ++ else if (TermMode == Single) ++ mythis->setWindowTitle(Title); ++ ++ AX25Sess->port = 0; ++ AX25Sess->Sess = Sess; // Crosslink KISS and Term Sessions ++ AX25Sess->PID = 240;; ++ ++ Sess->KISSSession = AX25Sess; ++ ++ setMenus(true); ++ ++ if (ConnectBeep) ++ myBeep(&ConnectWAV); ++ ++ QApplication::alert(mythis, 0); ++ ++ // Send CText if defined ++ ++ if (listenCText[0]) ++ SendtoAX25(Sess->KISSSession, (unsigned char *)listenCText, (int)strlen(listenCText)); ++ } ++ return Sess; ++} ++ ++ ++extern "C" void AX25_disc(TAX25Port * AX25Sess, Byte mode) ++{ ++ char Msg[128]; ++ int Len = 0; ++ Ui_ListenSession * Sess = (Ui_ListenSession *)AX25Sess->Sess; ++ ++ if (AX25Sess->status == STAT_TRY_LINK) ++ { ++ // Connect failed ++ ++ Len = sprintf(Msg, "Connection to %s failed\r", AX25Sess->corrcall); ++ } ++ else ++ { ++ switch (mode) ++ { ++ case MODE_OTHER: ++ case MODE_OUR: ++ ++ Len = sprintf(Msg, "Disconnected from %s\r", AX25Sess->corrcall); ++ break; ++ ++ case MODE_RETRY: ++ ++ Len = sprintf(Msg, "Disconnected from %s - Retry count exceeded\r", AX25Sess->corrcall); ++ break; ++ ++ }; ++ } ++ ++ SendtoTerm(Sess, Msg, Len); ++ ClearSessLabel(Sess); ++ Sess->KISSSession = NULL; ++ AX25Sess->Sess = 0; ++ ++ setMenus(0); ++}; ++ ++int QtTermTCP::openSerialPort() ++{ ++ if (m_serial && m_serial->isOpen()) ++ { ++ m_serial->close(); ++ } ++ ++ m_serial = nullptr; ++ m_serial = new QSerialPort(this); ++ ++ m_serial->setPortName(SerialPort); ++ boolean ok = m_serial->setBaudRate(KISSBAUD); ++ ++ if (m_serial->open(QIODevice::ReadWrite)) ++ { ++ int i; ++ ++ ok = m_serial->setRequestToSend(true); ++ ++ connect(m_serial, &QSerialPort::readyRead, this, &QtTermTCP::readSerialData); ++ // connect(m_serial, &QSerialPort::errorOccurred, this, &QtTermTCP::handleError); ++ ++ KISSConnected = 1; ++ KISSConnecting = 0; ++ ++ Status3->setText("KISS Connected"); ++ actHost[18]->setEnabled(1); // Enable KISS Connect Line ++ ++ KISS_add_stream(m_serial); ++ ++ // send TXDelay if enabled ++ ++ if (sendTXDelay[0]) ++ { ++ unsigned char Msg[5] = { FEND, 1, 25 , FEND }; ++ ++ Msg[2] = txdelay[0] / 10; ++ m_serial->write((char *)Msg, 4); ++ } ++ ++ // Attach a Monitor Window if available ++ ++ Ui_ListenSession * Sess = NULL; ++ Ui_ListenSession * S; ++ ++ if (TermMode == MDI) ++ { ++ // See if an old session can be reused ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ S = _sessions.at(i); ++ ++ // for (Ui_ListenSession * S: _sessions) ++ // ++ if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ ++ // Create a window if none found, else reuse old ++ ++ if (Sess == NULL) ++ { ++ Sess = newWindow((QObject *)mythis, Mon, ""); ++ } ++ } ++ else if (TermMode == Tabbed) ++ { ++ // Tabbed - look for free session ++ ++ for (i = 8; i; i--) ++ { ++ S = _sessions.at(i); ++ ++ if (S->clientSocket == NULL && S->KISSSession == NULL) ++ { ++ Sess = S; ++ break; ++ } ++ } ++ } ++ else if (TermMode == Single && (singlemodeFormat & Mon)) ++ { ++ S = _sessions.at(0); ++ ++ if (S->clientSocket == NULL && S->KISSSession == NULL) ++ Sess = S; ++ ++ } ++ ++ if (Sess) ++ { ++ KISSMonSess = Sess; // Flag as in use ++ ++ if (TermMode == MDI) ++ Sess->setWindowTitle("KISS Monitor Window"); ++ else if (TermMode == Tabbed) ++ tabWidget->setTabText(Sess->Tab, "KISS Mon"); ++ else if (TermMode == Single) ++ mythis->setWindowTitle("KISS Monitor Window"); ++ ++ // if (TermMode == Single) ++ // { ++ // discAction->setEnabled(false); ++ // YAPPSend->setEnabled(false); ++ // connectMenu->setEnabled(false); ++ // } ++ } ++ ++ ++ ++ return 1; ++ } ++ else ++ { ++ Status3->setText("KISS Open Failed"); ++ KISSConnected = 0; ++ KISSConnecting = 0; ++ return 0; ++ } ++} ++ ++ ++ ++void closeSerialPort() ++{ ++ if (m_serial && m_serial->isOpen()) ++ { ++ m_serial->close(); ++ m_serial = nullptr; ++ } ++ ++ m_serial = nullptr; ++ ++ KISSConnected = 0; ++ KISSConnecting = 0; ++ ++ Status3->setText("KISS Closed"); ++ actHost[18]->setEnabled(0); // Enable KISS Connect Line ++} ++ ++void QtTermTCP::readSerialData() ++{ ++ int Read; ++ unsigned char Buffer[8192]; ++ ++ // read the data from the socket ++ ++ m_serial->clearError(); ++ ++ Read = m_serial->read((char *)Buffer, 2047); ++ ++ if (m_serial->error()) ++ { ++ Debugprintf("Serial Read Error - RC %d Error %d", Read, m_serial->error()); ++ closeSerialPort(); ++ return; ++ } ++ ++ ++ while (Read > 0) ++ { ++ KISSDataReceived(m_serial, Buffer, Read); ++ Read = m_serial->read((char *)Buffer, 2047); ++ } ++} ++ ++void QtTermTCP::handleError(QSerialPort::SerialPortError serialPortError) ++{ ++ Debugprintf("Serial port Error %d", serialPortError); ++ closeSerialPort(); ++} ++ ++extern "C" void CheckUIFrame(unsigned char * path, string * data) ++{ ++ // If we have KISS enabled and dest is UIDEST look for a KISS window in UI Mode ++ ++ if (KISSSock == 0) ++ return; ++ ++ char Dest[10]; ++ char From[10]; ++ ++ Dest[ConvFromAX25(path, Dest)] = 0; ++ From[ConvFromAX25(&path[7], From)] = 0; ++ ++ // ok, Find a Kiss Session with this Dest ++ ++ Ui_ListenSession * Sess = NULL; ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->KISSMode == 1 && strcmp(Dest, Sess->UIDEST) == 0) ++ { ++ char Msg[512]; ++ int Len; ++ ++ data->Data[data->Length] = 0; ++ ++ Len = sprintf(Msg, "%s:%s", From, data->Data); ++ SendtoTerm(Sess, Msg, Len); ++ return; ++ } ++ } ++ ++} ++ ++ ++QColor QtTermTCP::setColor(QColor Colour) ++{ ++ // const QColorDialog::ColorDialogOptions options = QFlag(colorDialogOptionsWidget->value()); ++ ++ ++ QColor col = Colour; ++ ++ QColorDialog dialog; ++ dialog.setCurrentColor(Colour); ++ dialog.setOption(QColorDialog::DontUseNativeDialog); ++ ++ if (dialog.exec() == QColorDialog::Accepted) ++ col = QVariant(dialog.currentColor()).toString(); ++ ++ ++ // const QColor color = QColorDialog::getColor(Qt::green, this, "Select Color", 0); ++ ++ return col; ++} ++ ++// Experimental Viewdata/Teletext/Prestel/CEEFAX Mode ++ ++// Uses ideas and some code from ++ ++/*************************************************************** ++ * Name: wxTEDMain.cpp ++ * Purpose: Teletext editor Application Frame ++ * Author: Peter Kwan (peterk.vt80@gmail.com) ++ * Created: 2014-10-30 ++ * Copyright: Peter Kwan ++ * License: ++ * ++ * Copyright (C) 2014-2022, Peter Kwan ++ * ++ * Permission to use, copy, modify, and distribute this software ++ * and its documentation for any purpose and without fee is hereby ++ * granted, provided that the above copyright notice appear in all ++ * copies and that both that the copyright notice and this ++ * permission notice and warranty disclaimer appear in supporting ++ * documentation, and that the name of the author not be used in ++ * advertising or publicity pertaining to distribution of the ++ * software without specific, written prior permission. ++ * ++ * The author disclaims all warranties with regard to this ++ * software, including all implied warranties of merchantability ++ * and fitness. In no event shall the author be liable for any ++ * special, indirect or consequential damages or any damages ++ * whatsoever resulting from loss of use, data or profits, whether ++ * in an action of contract, negligence or other tortious action, ++ * arising out of or in connection with the use or performance of ++ * this software. ++ *************************************************************************** **/ ++ ++ ++ ++int FontWidth = 16; ++int FontHeight = 16; ++ ++bool isMosaic(char ch) ++{ ++ ch &= 0x7f; ++ return (ch >= 0x20 && ch < 0x40) || ch >= 0x60; ++} ++ ++ ++void DecodeTeleText(Ui_ListenSession * Sess, char * page) ++{ ++ ++ // redraw the whole teletext page ++ ++ QColor fg = Qt::white; ++ QColor bg = Qt::black; ++ QColor holdColour; ++ QColor holdfg = fg; // Colour for held graphic ++ int usehold = 0; ++ int sep = 0; ++ ++ QPainter p(Sess->TTBitmap); ++ ++ QSettings settings(GetConfPath(), QSettings::IniFormat); ++ ++ //p.setFont(QFont("Courier", 14, QFont::Bold)); ++ ++ p.setFont(QFont(settings.value("FontFamily", "Courier New").value(), 14)); ++ ++ p.setPen(QPen(fg)); ++ ++ bool graphicsMode = false; ++ bool separated = false; ++ bool doubleHeight = false; ++ int skipnextrow = 99; ++ bool flashing = false; ++ bool hold = false; ++ char holdChar = 0; ++ char holdMode = 0; ++ Sess->timer.stop(); ++ ++ bool concealed = false; ++ char c; ++ ++ fg = Qt::white; ++ bg = Qt::black; ++ ++ char * ptr = page; ++ ++ int col = 0; ++ int line = 0; ++ ++ // XXXXXXXXTEEFAX %%# %%a %d %%b C %H:%M.%S ++ ++ //p.drawText(0, 19, "P199 HAMFAX"); ++ ++ ++ // interpret data, for now, line by line ++ ++ ++ while ((c = *(ptr++))) ++ { ++ char ch = c; ++ ++ if (c == 0x11) // Curson On ?? ++ continue; ++ ++ if (c == 0x14) // Curson Off ?? ++ continue; ++ ++ if (c == 9) // Curson On ?? ++ { ++ col++; ++ continue; ++ } ++ ++ if (c == 0x0a) ++ { ++ line++; ++ ++// if (doubleHeight) ++// line++; ++ ++ if (line > 24) ++ line = 0; ++ ++ continue; ++ } ++ ++ if (c == 0x1e) // Cursor Home ++ { ++ line = col = 0; ++ c = 13; // So we reset page flags below ++ } ++ ++ if (c == 12) ++ { ++ // Clear the page ++ ++ Sess->TTBitmap->fill(Qt::black); ++ Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); ++ ++ line = col = 0; ++ ++ c = 13; // So we reset page flags below ++ } ++ ++ if (c == 13) ++ { ++ col = 0; ++ ++ graphicsMode = false; ++ separated = false; ++ doubleHeight = false; ++ flashing = false; ++ hold = false; ++ holdChar = 0; ++ concealed = false; ++ ++ fg = Qt::white; ++ bg = Qt::black; ++ ++ continue; // Next line ++ } ++ ++ if (c == 0x1b) // Esc ++ { ++ // I think the control char is displayed as it was before being actioned, sa save current state ++ ++ holdfg = holdColour; // Colour if using held - may be changed before displaying ++ usehold = hold; // May be changed ++ sep = holdMode; ++ ++ char echar = *(ptr++); ++ ++ if (echar == 0) ++ { ++ // Esc pair spilt - wait for rest ++ ++ Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); ++ return; ++ } ++ ++ switch (echar) ++ { ++ case '@': ++ fg = Qt::black; ++ concealed = false; // Side effect of colour. It cancels a conceal. ++ graphicsMode = false; ++// hold = false; ++ ++ break; ++ case 'A': ++ fg = Qt::red; ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ ++ break; ++ case 'B': ++ fg = Qt::green; ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ break; ++ case 'C': ++ fg = Qt::yellow; ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ break; ++ case 'D': ++ fg = Qt::blue; ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ break; ++ case 'E': ++ fg = Qt::magenta; ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ break; ++ case 'F': ++ fg = Qt::cyan; ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ break; ++ case 'G': ++ fg = Qt::white; ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ break; ++ case 'H': // Flash ++ flashing = true; ++ Sess->timer.start(1000, Sess); ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ ++ break; ++ ++ case 'I': // Steady ++ flashing = false; ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ ++ break; ++ // ++ case 'J': //ttxCodeEndBox: ++ case 'K': //ttxCodeStartBox: ++ ++ concealed = false; ++ graphicsMode = false; ++ hold = false; ++ ++ break; ++ case 'L': // Normal height ++ doubleHeight = false; ++ hold = false; ++ break; ++ ++ case 'M': // Double height ++ doubleHeight = true; ++ skipnextrow = line + 1; // ETSI: row to ignore ++ hold = false; ++ holdChar = 0; ++ break; ++ case 'P': // Graphics black ++// concealed = false; ++ graphicsMode = true; ++ holdColour = fg = Qt::black; ++ ++ break; ++ case 'Q': // Graphics red ++// concealed = false; ++ graphicsMode = true; ++ holdColour = fg = Qt::red; ++ ++ break; ++ case 'R': // Graphics green ++// concealed = false; ++ graphicsMode = true; ++ holdColour = fg = Qt::green; ++ ++ break; ++ case 'S': // Graphics yellow ++// concealed = false; ++ graphicsMode = true; ++ holdColour = fg = Qt::yellow; ++ ++ break; ++ case 'T': // Graphics blue ++// concealed = false; ++ graphicsMode = true; ++ holdColour = fg = Qt::blue; ++ ++ break; ++ case 'U': // Graphics magenta ++// concealed = false; ++ graphicsMode = true; ++ holdColour = fg = Qt::magenta; ++ ++ break; ++ case 'V': // Graphics cyan ++// concealed = false; ++ graphicsMode = true; ++ holdColour = fg = Qt::cyan; ++ ++ break; ++ case 'W': // Graphics white ++// concealed = false; ++ graphicsMode = true; ++ holdColour = fg = Qt::white; ++ ++ break; ++ ++ case 'X': // Conceal display ++ ++ concealed = 1; ++ break; ++ ++ case 'Y': // Contiguous graphics ++ ++ separated = false; ++ break; ++ ++ case 'Z': // Separated gfx ++ ++ separated = true; ++ break; ++ ++ case 0x5c: // Background black ++ bg = Qt::black; ++ break; ++ ++ case 0x5d: // New background ++ ++ bg = fg; ++ break; ++ ++ case 0x5e: // Hold gfx ++ ++ if (hold == 0) ++ { ++ hold = true; ++ holdColour = fg; ++ holdMode = separated; ++ } ++ break; ++ ++ case 0x5f: // Non-hold gfx ++ hold = false; ++ break; ++ ++ default: ++ echar++; // For testign ++ break; ++ ++ } //end of esc case processing ++ ++ if (usehold) ++ { ++ // We set sep and color for held char earlier ++ ++ ch = holdChar; // Repeat held char ++ } ++ else ++ ch = 0x0; // Default is space ++ ++ ++ if (line > skipnextrow) ++ skipnextrow = 99; ++ ++ if (line == skipnextrow) ++ { ++ line = line; ++ } ++ else ++ { ++ if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) ++ { ++ p.fillRect(col * 15, line * 19, 15, 19, bg); ++ ++ // if double height also draw background for next row ++ ++ if (doubleHeight) ++ p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); ++ ++ ++ if (sep) ++ { ++ if (ch & 1) ++ p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, holdfg); ++ if (ch & 2) ++ p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, holdfg); ++ if (ch & 4) ++ p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, holdfg); ++ if (ch & 8) ++ p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, holdfg); ++ if (ch & 16) ++ p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, holdfg); ++ if (ch & 32) ++ p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, holdfg); ++ ++ } ++ else ++ { ++ if (ch & 1) ++ p.fillRect(col * 15, line * 19, 7, 6, holdfg); ++ if (ch & 2) ++ p.fillRect(col * 15 + 7, line * 19, 8, 6, holdfg); ++ if (ch & 4) ++ p.fillRect(col * 15, line * 19 + 6, 7, 6, holdfg); ++ if (ch & 8) ++ p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, holdfg); ++ if (ch & 16) ++ p.fillRect(col * 15, line * 19 + 12, 7, 7, holdfg); ++ if (ch & 32) ++ p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, holdfg); ++ } ++ } ++ } ++ col++; ++ } ++ else ++ { ++ // Not esc - so normal or graphics ++ ++ if (ch < 0x20) ++ continue; ++ ++ if (line > skipnextrow) ++ skipnextrow = 99; ++ ++ if (line == skipnextrow) ++ { ++ line = line; ++ } ++ else ++ { ++ if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) ++ { ++ p.fillRect(col * 15, line * 19, 15, 19, bg); ++ ++ if (doubleHeight) ++ p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); ++ ++ p.setPen(QPen(fg));; ++ ++ if (graphicsMode) ++ { ++ if (ch < 0x40) ++ ch -= 0x20; ++ else ++ if (ch >= 0x60) ++ ch -= 0x40; ++ else ++ goto isText; ++ ++ holdChar = ch; ++ ++ // Now have 00 - 3f ++ ++ ++ // C is bit mask bit posns are ++ // 01 ++ // 23 ++ // 45 ++ // Char cell is 15 * 19 which is a bit asymetrical ++ ++ // Chars are 20 - 3f and 60 to 7f but I cant see a logic to the mapping ++ ++ ++ if (separated) ++ { ++ if (ch & 1) ++ p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, fg); ++ if (ch & 2) ++ p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, fg); ++ if (ch & 4) ++ p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, fg); ++ if (ch & 8) ++ p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, fg); ++ if (ch & 16) ++ p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, fg); ++ if (ch & 32) ++ p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, fg); ++ ++ } ++ else ++ { ++ if (ch & 1) ++ p.fillRect(col * 15, line * 19, 7, 6, fg); ++ if (ch & 2) ++ p.fillRect(col * 15 + 7, line * 19, 8, 6, fg); ++ if (ch & 4) ++ p.fillRect(col * 15, line * 19 + 6, 7, 6, fg); ++ if (ch & 8) ++ p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, fg); ++ if (ch & 16) ++ p.fillRect(col * 15, line * 19 + 12, 7, 7, fg); ++ if (ch & 32) ++ p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, fg); ++ } ++ } ++ else ++ { ++ // Just write char at current col and line ++ ++ isText: ++ char s[5]; ++ unsigned char su[5] = ""; ++ ++ // Some chars are in wrong char set ++ ++ su[0] = ch; ++ ++ if (ch == '_') ++ su[0] = '#'; ++ ++ else if (ch == 0x7e) // division ++ { ++ su[0] = 0xC3; ++ su[1] = 0xB7; ++ } ++ else if (ch == 0x5e) // up arrow ++ { ++ su[0] = 0xF0; ++ su[1] = 0x9F; ++ su[2] = 0xA0; ++ su[3] = 0x95; ++ } ++ else if (ch == 0x7f) // up arrow ++ { ++ su[0] = 0xE2; ++ su[1] = 0x96; ++ su[2] = 0x88; ++ } ++ ++ memcpy(s, su, 5); ++ ++// if (doubleHeight) ++ // p.drawText(col * 15, line * 19 + 25, s); ++ // else ++ // p.drawText(col * 15, line * 19 + 15, s); ++ ++ // if double height draw normally then copy pixels each row of pixels to two scanlines (starting at the bottom) ++ ++ if (doubleHeight) ++ { ++ int inscanline = line * 19 + 18; ++ int outscanline = line * 19 + 35; ++ unsigned char * inptr = Sess->TTBitmap->scanLine(inscanline); ++ unsigned char * outptr = Sess->TTBitmap->scanLine(outscanline); ++ int linelen = Sess->TTBitmap->bytesPerLine(); ++ int charlen = linelen / 40; // bytes per char position ++ ++ p.drawText(col * 15, line * 19 + 16, s); ++ ++ inptr += col * charlen; ++ outptr += col * charlen; ++ ++ for (int i = 0; i < 18; i++) ++ { ++ memcpy(outptr, inptr, charlen); ++ outptr -= linelen; ++ memcpy(outptr, inptr, charlen); ++ ++ inptr -= linelen; ++ outptr -= linelen; ++ ++ } ++ } ++ else ++ p.drawText(col * 15, line * 19 + 15, s); ++ ++ } ++ } ++ } ++ col++; ++ } ++ ++ if (col > 39) ++ { ++ col = 0; ++ line++; ++ if (line > 24) ++ line = 0; ++ ++ graphicsMode = false; ++ separated = false; ++ doubleHeight = false; ++ flashing = false; ++ hold = false; ++ holdChar = 0; ++ concealed = false; ++ ++ fg = Qt::white; ++ bg = Qt::black; ++ } ++ } ++ Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); ++ return; ++ ++ QFile file("D:/savepage.txt"); ++ file.open(QIODevice::WriteOnly); ++ file.write(Sess->pageBuffer); ++ file.close(); ++} ++ ++ ++void Ui_ListenSession::timerEvent(QTimerEvent *event) ++{ ++ Ui_ListenSession * Sess = NULL; ++ ++ // Used for flashing - resfresh window ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->timer.timerId() == event->timerId()) ++ { ++ if (Sess->TTActive) ++ { ++ Sess->TTFlashToggle ^= 1; ++ ++ // if in Tabbed mode only refresh active tab ++ ++ if (TermMode == Tabbed && Sess != ActiveSession) ++ return; ++ ++ DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end ++ } ++ else ++ Sess->timer.stop(); ++ ++ return; ++ } ++ } ++ QWidget::timerEvent(event); ++} ++ ++// Monitor Log FIle routines ++ ++char * doXMLTransparency(char * string) ++{ ++ // Make sure string doesn't contain forbidden XML chars (<>"'&) ++ ++ char * newstring = (char *)malloc(5 * strlen(string) + 1); // If len is zero still need null terminator ++ ++ char * in = string; ++ char * out = newstring; ++ char c; ++ ++ c = *(in++); ++ ++ while (c) ++ { ++ switch (c) ++ { ++ case '<': ++ ++ strcpy(out, "<"); ++ out += 4; ++ break; ++ ++ case '>': ++ ++ strcpy(out, ">"); ++ out += 4; ++ break; ++ ++ case '"': ++ ++ strcpy(out, """); ++ out += 6; ++ break; ++ ++ case '\'': ++ ++ strcpy(out, "'"); ++ out += 6; ++ break; ++ ++ case '&': ++ ++ strcpy(out, "&"); ++ out += 5; ++ break; ++ ++ default: ++ ++ *(out++) = c; ++ } ++ c = *(in++); ++ } ++ ++ *(out++) = 0; ++ return newstring; ++} ++ ++void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg) ++{ ++ // Write as HTML to preserve formatting ++ ++ char Line[512]; ++ char * HTMLText; ++ ++ if (Sess->monLogfile == nullptr) ++ { ++ QString FN = "QTTermMonLog" + timeLoaded + "_" + QString::number(Sess->sessNo) + ".html"; ++ Sess->monLogfile = new QFile(FN); ++ ++ if (Sess->monLogfile) ++ Sess->monLogfile->open(QIODevice::Append); ++ else ++ return; ++ } ++ ++ if (Msg[0] == 0x1b) ++ { ++ // Colour Escape ++ ++ if (Msg[1] == 17) ++ Sess->monSpan = (char *)"";// , monRxColour.data()); ++ else ++ Sess->monSpan = (char *)"";// , monTxColour.data()); ++ ++ HTMLText = doXMLTransparency(&Msg[2]); ++ } ++ else ++ { ++ // Leave colour at last set value ++ ++ HTMLText = doXMLTransparency(Msg); ++ } ++ ++ sprintf(Line, "%s%s
\r\n", Sess->monSpan, HTMLText); ++ ++ Sess->monLogfile->write(Line); ++ ++ free(HTMLText); ++ ++} ++ ++// Create MH Window ++ ++ ++ ++int newMHWindow(QObject * parent, int Type, const char * Label) ++{ ++ Ui_ListenSession * Sess = new(Ui_ListenSession); ++ ++ MHWindow = Sess; ++ ++ // Need to explicity initialise on Qt4 ++ ++ Sess->termWindow = NULL; ++ Sess->monWindow = NULL; ++ Sess->inputWindow = NULL; ++ ++ Sess->StackIndex = 0; ++ Sess->InputMode = 0; ++ Sess->SlowTimer = 0; ++ Sess->MonData = 0; ++ Sess->OutputSaveLen = 0; ++ Sess->MonSaveLen = 0; ++ Sess->PortMonString[0] = 0; ++ Sess->portmask = 0; ++ Sess->portmask = 1; ++ Sess->mtxparam = 1; ++ Sess->mlocaltime = 0; ++ Sess->mcomparam = 1; ++ Sess->monUI = 0; ++ Sess->MonitorNODES = 0; ++ Sess->MonitorColour = 1; ++ Sess->CurrentHost = 0; ++ ++ Sess->SessionType = Type; ++ Sess->clientSocket = NULL; ++ Sess->AGWSession = NULL; ++ Sess->AGWMonSession = NULL; ++ Sess->KISSSession = NULL; ++ Sess->KISSMode = 0; ++ Sess->TTActive = 0; ++ Sess->TTFlashToggle = 0; ++ Sess->pageBuffer[0] = 0; ++ Sess->Tab = 0; ++ ++ Sess->LogMonitor = false; ++ Sess->monSpan = (char *) ""; ++ Sess->monLogfile = nullptr; ++ Sess->sessNo = sessNo++; ++ ++ 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 ++ ++ Sess->monWindow = new QTextEdit(Sess); ++ Sess->monWindow->setReadOnly(1); ++ Sess->monWindow->document()->setMaximumBlockCount(10000); ++ Sess->monWindow->setFont(font); ++ Sess->monWindow->setStyleSheet(monStyleSheet); ++ ++ Sess->setWindowTitle(Label); ++ ++ Sess->installEventFilter(mythis); ++ ++ Sess->show(); ++ ++ ++ ++ Sess->monWindow->setGeometry(QRect(2, 2, 400, 400)); ++ Sess->setGeometry(QRect(400, 400, 400, 400)); ++ ++ ++ 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 true; ++} ++ ++extern "C" void WritetoMHWindow(char * Buffer) ++{ ++ unsigned char Copy[8192]; ++ unsigned char * ptr1, *ptr2; ++ unsigned char Line[8192]; ++ unsigned char out[8192]; ++ int outlen; ++ ++ int num; ++ ++ if (MHWindow == NULL || MHWindow->monWindow == NULL) ++ return; ++ ++ MHWindow->monWindow->setText(Buffer); ++} +--- qttermtcp-0.0.0.79.orig/QtTermTCP.h ++++ qttermtcp-0.0.0.79/QtTermTCP.h +@@ -1,312 +1,312 @@ +-#pragma once +- +-#include +-#include "ui_QtTermTCP.h" +-#include "ui_AlertSetup.h" +-#include "ui_YAPPRxSize.h" +-#include "ui_ColourConfig.h" +-#include "ui_VARAConfig.h" +-#include "ui_KISSConfig.h" +-#include "QTextEdit" +-#include "QSplitter" +-#include "QLineEdit" +-#include "QTcpSocket" +-#include +-#include +-#include "QThread" +-#include "QTcpServer" +-#include "QMdiArea" +-#include +-#include "QMessageBox" +-#include "QTimer" +-#include "QSettings" +-#include "QThread" +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define MAXHOSTS 16 +-#define MAXPORTS 64 +- +-QT_BEGIN_NAMESPACE +-class QComboBox; +-class QLabel; +-class QLineEdit; +-class QPushButton; +-class QTcpSocket; +-class QNetworkSession; +- +-class myTcpSocket : public QTcpSocket +-{ +-public: +- QWidget * Sess; +-}; +- +- +-class Ui_ListenSession : public QMainWindow +-{ +- Q_OBJECT +- +-public: +- explicit Ui_ListenSession(QWidget *Parent = 0) : QMainWindow(Parent) {} +- ~Ui_ListenSession(); +- +- int SessionType; // Type Mask - Term, Mon, Listen +- int CurrentWidth; +- int CurrentHeight; // Saved so can be restored after Cascade +- +- QTextEdit *termWindow; +- QTextEdit *monWindow; +- QLineEdit *inputWindow; +- QLabel * TTLabel; +- +- myTcpSocket *clientSocket; +- +- QAction * actActivate; // From active Windows menu +- +- char * KbdStack[50]; +- int StackIndex; +- +- QMdiSubWindow *sw; // The MdiSubwindow is the container for this session +- +- int InputMode; +- int SlowTimer; +- int MonData; +- +- int OutputSaveLen; +- char OutputSave[16384]; +- +- int MonSaveLen; +- char MonSave[4096]; +- +- char PortMonString[2048]; // 64 ports 32 Bytes +- uint64_t portmask; +- int EnableMonitor; +- int mlocaltime; +- int mtxparam; +- int mcomparam; +- int monUI; +- int MonitorNODES; +- int MonitorColour; +- int CurrentHost; +- int Tab; // Tab Index if Tabbed Mode +- void * AGWSession; // Terinal sess - Need to cast to TAGWPort to use it +- void * AGWMonSession; +- void * KISSSession; +- int KISSMode; // Connected or UI +- int UIPORT; +- char UIDEST[32]; +- char UIPATH[128]; +- +- // For Teletext Emulator +- +- QImage * TTBitmap; // TT Image buffer +- QDialog TTUI; +- +- int TTActive; +- int TTFlashToggle; +- char pageBuffer[4096]; +- QBasicTimer timer; +- +- int sessNo; // Used to create unique log filename; +- bool LogMonitor; +- QFile * monLogfile; +- char * monSpan; +- +-protected: +- +- void timerEvent(QTimerEvent *event) override; +- +-private: +- +- +- +-private slots: +- +-}; +- +- +-class QtTermTCP : public QMainWindow +-{ +- Q_OBJECT +- +-public: +- QtTermTCP(QWidget *parent = NULL); +- void closeEvent(QCloseEvent * event); +- static void setFonts(); +- +- ~QtTermTCP(); +- +-private slots: +- void Disconnect(); +- void doYAPPSend(); +- void doYAPPSetRX(); +- void doYAPPSetSize(); +- void sizeaccept(); +- void sizereject(); +- void menuChecked(); +- void Connect(); +- void displayError(QAbstractSocket::SocketError socketError); +- void readyRead(); +- void showContextMenu(const QPoint & point); +- void autoConnectChecked(); +- void LreturnPressed(Ui_ListenSession * LUI); +- void LDisconnect(Ui_ListenSession * LUI); +- void SetupHosts(); +- void MyTimerSlot(); +- void SlowTimerSlot(); +- void KISSTimerSlot(); +- void ListenSlot(); +- void AGWSlot(); +- void AlertSlot(); +- void chooseInboundWAV(); +- void chooseBellsWAV(); +- void chooseIntervalWAV(); +- void chooseAlertWAV(); +- void testInboundWAV(); +- void testBellsWAV(); +- void testIntervalWAV(); +- void testAlertWAV(); +- void alertAccept(); +- void alertReject(); +- void VARASlot(); +- void KISSSlot(); +- void deviceaccept(); +- void KISSaccept(); +- void KISSreject(); +- void devicereject(); +- void showContextMenuM(const QPoint &pt); +- void showContextMenuT(const QPoint &pt); +- void showContextMenuL(); +- void doQuit(); +- void onTEselectionChanged(); +- void onLEselectionChanged(); +- void setSplit(); +- void ClearScreen(); +- void setVDMode(); +- void showContextMenuMT(const QPoint & pt); +- void showContextMenuMOnly(const QPoint & pt); +- void onNewConnection(); +- void onSocketStateChanged(QAbstractSocket::SocketState socketState); +- void updateWindowMenu(); +- void doNewTerm(); +- void doNewMon(); +- void doNewCombined(); +- void doCascade(); +- void actActivate(); +- void xon_mdiArea_changed(); +- void doFonts(); +- void doMFonts(); +- void ConnecttoVARA(); +- void VARATimer(); +- void AGWdisplayError(QAbstractSocket::SocketError socketError); +- void AGWreadyRead(); +- void onAGWSocketStateChanged(QAbstractSocket::SocketState socketState); +- void VARAdisplayError(QAbstractSocket::SocketError socketError); +- void VARAreadyRead(); +- void onVARASocketStateChanged(QAbstractSocket::SocketState socketState); +- void KISSdisplayError(QAbstractSocket::SocketError socketError); +- void KISSreadyRead(); +- void onKISSSocketStateChanged(QAbstractSocket::SocketState socketState); +- int openSerialPort(); +- void readSerialData(); +- void handleError(QSerialPort::SerialPortError serialPortError); +- void doColours(); +- void ColourPressed(); +- void Colouraccept(); +- void Colourreject(); +- QColor setColor(QColor Colour); +- void VARADatadisplayError(QAbstractSocket::SocketError socketError); +- void VARADatareadyRead(); +- void onVARADataSocketStateChanged(QAbstractSocket::SocketState socketState); +- void HAMLIBdisplayError(QAbstractSocket::SocketError socketError); +- void HAMLIBreadyRead(); +- void onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState); +- void ConnecttoHAMLIB(); +- void HAMLIBSetPTT(int PTTState); +- void FLRigdisplayError(QAbstractSocket::SocketError socketError); +- void FLRigreadyRead(); +- void onFLRigSocketStateChanged(QAbstractSocket::SocketState socketState); +- void ConnecttoFLRig(); +- void FLRigSetPTT(int PTTState); +- void CATChanged(bool State); +- void PTTPortChanged(int Selected); +- void OpenPTTPort(); +- void RadioPTT(bool PTTState); +- void tabSelected(int); +- void VARAHFChanged(bool state); +- void VARAFMChanged(bool State); +- void VARASATChanged(bool State); +- void SetVARAParams(); +- +-protected: +- bool eventFilter(QObject* obj, QEvent *event); +- +-private: +- +- void ConnecttoAGW(); +- +- void AGWTimer(); +- +- Ui::QtTermTCPClass ui; +- +- QMenu *hostsubMenu; +- +- QAction *closeAct; +- QAction *closeAllAct; +- QAction *tileAct; +- QAction *cascadeAct; +- QAction *nextAct; +- QAction *previousAct; +- QAction *windowMenuSeparatorAct; +- QAction *newTermAct; +- QAction *newMonAct; +- QAction *newCombinedAct; +- QAction *AGWAction; +- QAction *VARAAction; +- QAction *KISSAction; +- QAction *AlertAction; +- QAction *quitAction; +- +- QList _sockets; +- +- QWidget *centralWidget; +- void ConnecttoKISS(); +- void KISSTimer(); +-}; +- +-extern "C" +-{ +- void EncodeSettingsLine(int n, char * String); +- void DecodeSettingsLine(int n, char * String); +- void WritetoOutputWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int Len); +- void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int *OutputSaveLen, char * OutputSave, QColor Colour); +- void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int Len); +- void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len); +- void SendTraceOptions(Ui_ListenSession * LUI); +- void setTraceOff(Ui_ListenSession * Sess); +- void SetPortMonLine(int i, char * Text, int visible, int enabled); +- void SaveSettings(); +- void myBeep(QString * WAV); +- void YAPPSendFile(Ui_ListenSession * Sess, char * FN); +- int SocketSend(Ui_ListenSession * Sess, char * Buffer, int len); +- void SendTraceOptions(Ui_ListenSession * Sess); +- int SocketFlush(Ui_ListenSession * Sess); +- extern void mySleep(int ms); +- extern void setTraceOff(Ui_ListenSession * Sess); +- void GetKeyWordFile(); +-} +- +-extern QString ConnectWAV; +-extern QString BellWAV; +-extern QString AlertWAV; +- +-char * strlop(char * buf, char delim); +-extern "C" void setMenus(int State); +-void Send_AGW_Ds_Frame(void * AGW); ++#pragma once ++ ++#include ++#include "ui_QtTermTCP.h" ++#include "ui_AlertSetup.h" ++#include "ui_YAPPRxSize.h" ++#include "ui_ColourConfig.h" ++#include "ui_VARAConfig.h" ++#include "ui_KISSConfig.h" ++#include "QTextEdit" ++#include "QSplitter" ++#include "QLineEdit" ++#include "QTcpSocket" ++#include ++#include ++#include "QThread" ++#include "QTcpServer" ++#include "QMdiArea" ++#include ++#include "QMessageBox" ++#include "QTimer" ++#include "QSettings" ++#include "QThread" ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define MAXHOSTS 16 ++#define MAXPORTS 64 ++ ++QT_BEGIN_NAMESPACE ++class QComboBox; ++class QLabel; ++class QLineEdit; ++class QPushButton; ++class QTcpSocket; ++class QNetworkSession; ++ ++class myTcpSocket : public QTcpSocket ++{ ++public: ++ QWidget * Sess; ++}; ++ ++ ++class Ui_ListenSession : public QMainWindow ++{ ++ Q_OBJECT ++ ++public: ++ explicit Ui_ListenSession(QWidget *Parent = 0) : QMainWindow(Parent) {} ++ ~Ui_ListenSession(); ++ ++ int SessionType; // Type Mask - Term, Mon, Listen ++ int CurrentWidth; ++ int CurrentHeight; // Saved so can be restored after Cascade ++ ++ QTextEdit *termWindow; ++ QTextEdit *monWindow; ++ QLineEdit *inputWindow; ++ QLabel * TTLabel; ++ ++ myTcpSocket *clientSocket; ++ ++ QAction * actActivate; // From active Windows menu ++ ++ char * KbdStack[50]; ++ int StackIndex; ++ ++ QMdiSubWindow *sw; // The MdiSubwindow is the container for this session ++ ++ int InputMode; ++ int SlowTimer; ++ int MonData; ++ ++ int OutputSaveLen; ++ char OutputSave[16384]; ++ ++ int MonSaveLen; ++ char MonSave[4096]; ++ ++ char PortMonString[2048]; // 64 ports 32 Bytes ++ uint64_t portmask; ++ int EnableMonitor; ++ int mlocaltime; ++ int mtxparam; ++ int mcomparam; ++ int monUI; ++ int MonitorNODES; ++ int MonitorColour; ++ int CurrentHost; ++ int Tab; // Tab Index if Tabbed Mode ++ void * AGWSession; // Terinal sess - Need to cast to TAGWPort to use it ++ void * AGWMonSession; ++ void * KISSSession; ++ int KISSMode; // Connected or UI ++ int UIPORT; ++ char UIDEST[32]; ++ char UIPATH[128]; ++ ++ // For Teletext Emulator ++ ++ QImage * TTBitmap; // TT Image buffer ++ QDialog TTUI; ++ ++ int TTActive; ++ int TTFlashToggle; ++ char pageBuffer[4096]; ++ QBasicTimer timer; ++ ++ int sessNo; // Used to create unique log filename; ++ bool LogMonitor; ++ QFile * monLogfile; ++ char * monSpan; ++ ++protected: ++ ++ void timerEvent(QTimerEvent *event) override; ++ ++private: ++ ++ ++ ++private slots: ++ ++}; ++ ++ ++class QtTermTCP : public QMainWindow ++{ ++ Q_OBJECT ++ ++public: ++ QtTermTCP(QWidget *parent = NULL); ++ void closeEvent(QCloseEvent * event); ++ static void setFonts(); ++ ++ ~QtTermTCP(); ++ ++private slots: ++ void Disconnect(); ++ void doYAPPSend(); ++ void doYAPPSetRX(); ++ void doYAPPSetSize(); ++ void sizeaccept(); ++ void sizereject(); ++ void menuChecked(); ++ void Connect(); ++ void displayError(QAbstractSocket::SocketError socketError); ++ void readyRead(); ++ void showContextMenu(const QPoint & point); ++ void autoConnectChecked(); ++ void LreturnPressed(Ui_ListenSession * LUI); ++ void LDisconnect(Ui_ListenSession * LUI); ++ void SetupHosts(); ++ void MyTimerSlot(); ++ void SlowTimerSlot(); ++ void KISSTimerSlot(); ++ void ListenSlot(); ++ void AGWSlot(); ++ void AlertSlot(); ++ void chooseInboundWAV(); ++ void chooseBellsWAV(); ++ void chooseIntervalWAV(); ++ void chooseAlertWAV(); ++ void testInboundWAV(); ++ void testBellsWAV(); ++ void testIntervalWAV(); ++ void testAlertWAV(); ++ void alertAccept(); ++ void alertReject(); ++ void VARASlot(); ++ void KISSSlot(); ++ void deviceaccept(); ++ void KISSaccept(); ++ void KISSreject(); ++ void devicereject(); ++ void showContextMenuM(const QPoint &pt); ++ void showContextMenuT(const QPoint &pt); ++ void showContextMenuL(); ++ void doQuit(); ++ void onTEselectionChanged(); ++ void onLEselectionChanged(); ++ void setSplit(); ++ void ClearScreen(); ++ void setVDMode(); ++ void showContextMenuMT(const QPoint & pt); ++ void showContextMenuMOnly(const QPoint & pt); ++ void onNewConnection(); ++ void onSocketStateChanged(QAbstractSocket::SocketState socketState); ++ void updateWindowMenu(); ++ void doNewTerm(); ++ void doNewMon(); ++ void doNewCombined(); ++ void doCascade(); ++ void actActivate(); ++ void xon_mdiArea_changed(); ++ void doFonts(); ++ void doMFonts(); ++ void ConnecttoVARA(); ++ void VARATimer(); ++ void AGWdisplayError(QAbstractSocket::SocketError socketError); ++ void AGWreadyRead(); ++ void onAGWSocketStateChanged(QAbstractSocket::SocketState socketState); ++ void VARAdisplayError(QAbstractSocket::SocketError socketError); ++ void VARAreadyRead(); ++ void onVARASocketStateChanged(QAbstractSocket::SocketState socketState); ++ void KISSdisplayError(QAbstractSocket::SocketError socketError); ++ void KISSreadyRead(); ++ void onKISSSocketStateChanged(QAbstractSocket::SocketState socketState); ++ int openSerialPort(); ++ void readSerialData(); ++ void handleError(QSerialPort::SerialPortError serialPortError); ++ void doColours(); ++ void ColourPressed(); ++ void Colouraccept(); ++ void Colourreject(); ++ QColor setColor(QColor Colour); ++ void VARADatadisplayError(QAbstractSocket::SocketError socketError); ++ void VARADatareadyRead(); ++ void onVARADataSocketStateChanged(QAbstractSocket::SocketState socketState); ++ void HAMLIBdisplayError(QAbstractSocket::SocketError socketError); ++ void HAMLIBreadyRead(); ++ void onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState); ++ void ConnecttoHAMLIB(); ++ void HAMLIBSetPTT(int PTTState); ++ void FLRigdisplayError(QAbstractSocket::SocketError socketError); ++ void FLRigreadyRead(); ++ void onFLRigSocketStateChanged(QAbstractSocket::SocketState socketState); ++ void ConnecttoFLRig(); ++ void FLRigSetPTT(int PTTState); ++ void CATChanged(bool State); ++ void PTTPortChanged(int Selected); ++ void OpenPTTPort(); ++ void RadioPTT(bool PTTState); ++ void tabSelected(int); ++ void VARAHFChanged(bool state); ++ void VARAFMChanged(bool State); ++ void VARASATChanged(bool State); ++ void SetVARAParams(); ++ ++protected: ++ bool eventFilter(QObject* obj, QEvent *event); ++ ++private: ++ ++ void ConnecttoAGW(); ++ ++ void AGWTimer(); ++ ++ Ui::QtTermTCPClass ui; ++ ++ QMenu *hostsubMenu; ++ ++ QAction *closeAct; ++ QAction *closeAllAct; ++ QAction *tileAct; ++ QAction *cascadeAct; ++ QAction *nextAct; ++ QAction *previousAct; ++ QAction *windowMenuSeparatorAct; ++ QAction *newTermAct; ++ QAction *newMonAct; ++ QAction *newCombinedAct; ++ QAction *AGWAction; ++ QAction *VARAAction; ++ QAction *KISSAction; ++ QAction *AlertAction; ++ QAction *quitAction; ++ ++ QList _sockets; ++ ++ QWidget *centralWidget; ++ void ConnecttoKISS(); ++ void KISSTimer(); ++}; ++ ++extern "C" ++{ ++ void EncodeSettingsLine(int n, char * String); ++ void DecodeSettingsLine(int n, char * String); ++ void WritetoOutputWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int Len); ++ void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int *OutputSaveLen, char * OutputSave, QColor Colour); ++ void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int Len); ++ void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len); ++ void SendTraceOptions(Ui_ListenSession * LUI); ++ void setTraceOff(Ui_ListenSession * Sess); ++ void SetPortMonLine(int i, char * Text, int visible, int enabled); ++ void SaveSettings(); ++ void myBeep(QString * WAV); ++ void YAPPSendFile(Ui_ListenSession * Sess, char * FN); ++ int SocketSend(Ui_ListenSession * Sess, char * Buffer, int len); ++ void SendTraceOptions(Ui_ListenSession * Sess); ++ int SocketFlush(Ui_ListenSession * Sess); ++ extern void mySleep(int ms); ++ extern void setTraceOff(Ui_ListenSession * Sess); ++ void GetKeyWordFile(); ++} ++ ++extern QString ConnectWAV; ++extern QString BellWAV; ++extern QString AlertWAV; ++ ++char * strlop(char * buf, char delim); ++extern "C" void setMenus(int State); ++void Send_AGW_Ds_Frame(void * AGW); +--- qttermtcp-0.0.0.79.orig/QtTermTCP.sln ++++ qttermtcp-0.0.0.79/QtTermTCP.sln +@@ -1,25 +1,25 @@ +- +-Microsoft Visual Studio Solution File, Format Version 12.00 +-# Visual Studio 15 +-VisualStudioVersion = 15.0.28307.102 +-MinimumVisualStudioVersion = 10.0.40219.1 +-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtTermTCP", "D:\BT Cloud\ActiveSource\QtTermTCP\QtTermTCP.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" +-EndProject +-Global +- GlobalSection(SolutionConfigurationPlatforms) = preSolution +- Debug|x86 = Debug|x86 +- Release|x86 = Release|x86 +- EndGlobalSection +- GlobalSection(ProjectConfigurationPlatforms) = postSolution +- {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.ActiveCfg = Debug|Win32 +- {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.Build.0 = Debug|Win32 +- {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.ActiveCfg = Release|Win32 +- {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.Build.0 = Release|Win32 +- EndGlobalSection +- GlobalSection(SolutionProperties) = preSolution +- HideSolutionNode = FALSE +- EndGlobalSection +- GlobalSection(ExtensibilityGlobals) = postSolution +- SolutionGuid = {DD1F8FD5-5375-4EFC-BBEE-8E35ABA15C82} +- EndGlobalSection +-EndGlobal ++ ++Microsoft Visual Studio Solution File, Format Version 12.00 ++# Visual Studio 15 ++VisualStudioVersion = 15.0.28307.102 ++MinimumVisualStudioVersion = 10.0.40219.1 ++Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QtTermTCP", "D:\BT Cloud\ActiveSource\QtTermTCP\QtTermTCP.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" ++EndProject ++Global ++ GlobalSection(SolutionConfigurationPlatforms) = preSolution ++ Debug|x86 = Debug|x86 ++ Release|x86 = Release|x86 ++ EndGlobalSection ++ GlobalSection(ProjectConfigurationPlatforms) = postSolution ++ {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.ActiveCfg = Debug|Win32 ++ {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.Build.0 = Debug|Win32 ++ {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.ActiveCfg = Release|Win32 ++ {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.Build.0 = Release|Win32 ++ EndGlobalSection ++ GlobalSection(SolutionProperties) = preSolution ++ HideSolutionNode = FALSE ++ EndGlobalSection ++ GlobalSection(ExtensibilityGlobals) = postSolution ++ SolutionGuid = {DD1F8FD5-5375-4EFC-BBEE-8E35ABA15C82} ++ EndGlobalSection ++EndGlobal +--- qttermtcp-0.0.0.79.orig/QtTermTCP.ui ++++ qttermtcp-0.0.0.79/QtTermTCP.ui +@@ -1,66 +1,66 @@ +- +- +- QtTermTCPClass +- +- +- +- 0 +- 0 +- 781 +- 698 +- +- +- +- +- Arial +- 12 +- +- +- +- QtTermTCP +- +- +- +- :/QtTermTCP/QtTermTCP.ico:/QtTermTCP/QtTermTCP.ico +- +- +- +- +- 5 +- +- +- 5 +- +- +- 5 +- +- +- 5 +- +- +- +- +- 6 +- +- +- +- +- +- +- +- +- Listen +- +- +- +- +- Disconnect +- +- +- +- +- +- +- +- +- ++ ++ ++ QtTermTCPClass ++ ++ ++ ++ 0 ++ 0 ++ 781 ++ 698 ++ ++ ++ ++ ++ Arial ++ 12 ++ ++ ++ ++ QtTermTCP ++ ++ ++ ++ :/QtTermTCP/QtTermTCP.ico:/QtTermTCP/QtTermTCP.ico ++ ++ ++ ++ ++ 5 ++ ++ ++ 5 ++ ++ ++ 5 ++ ++ ++ 5 ++ ++ ++ ++ ++ 6 ++ ++ ++ ++ ++ ++ ++ ++ ++ Listen ++ ++ ++ ++ ++ Disconnect ++ ++ ++ ++ ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/QtTermTCP.vcxproj ++++ qttermtcp-0.0.0.79/QtTermTCP.vcxproj +@@ -1,463 +1,463 @@ +- +- +- +- +- Debug +- x64 +- +- +- Release +- Win32 +- +- +- Debug +- Win32 +- +- +- Release +- x64 +- +- +- +- {14F3B24E-473C-324E-A99D-3B679FCF5F67} +- QtTermTCP +- QtVS_v304 +- 10.0.17763.0 +- 10.0.19041.0 +- $(MSBuildProjectDirectory)\QtMsBuild +- +- +- +- v141 +- release\ +- false +- NotSet +- Application +- release\ +- QtTermTCP +- +- +- v141 +- release\ +- false +- NotSet +- Application +- release\ +- QtTermTCP +- +- +- v141 +- debug\ +- false +- NotSet +- Application +- debug\ +- QtTermTCP +- +- +- v141 +- debug\ +- false +- NotSet +- Application +- debug\ +- QtTermTCP +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- $(SolutionDir)$(Platform)\$(Configuration)\ +- $(SolutionDir)Intermed\$(Platform)\$(Configuration)\ +- QtTermTCP +- true +- true +- +- +- $(SolutionDir)$(Platform)\$(Configuration)\ +- $(SolutionDir)Intermed\$(Platform)\$(Configuration)\ +- QtTermTCP +- true +- true +- +- +- $(SolutionDir)$(Platform)\$(Configuration)\ +- $(SolutionDir)Intermed\$(Platform)\$(Configuration)\ +- QtTermTCP +- true +- false +- +- +- $(SolutionDir)$(Platform)\$(Configuration)\ +- $(SolutionDir)Intermed\$(Platform)\$(Configuration)\ +- QtTermTCP +- true +- false +- +- +- 5.14.2 +- core;network;gui;widgets;serialport;multimedia +- +- +- 5.14.2_msvc2017 +- core;network;gui;widgets;serialport +- +- +- 5.14.2 +- core;network;gui;widgets;serialport;multimedia +- +- +- 5.14.2_msvc2017_64 +- core;network;gui;widgets;serialport +- +- +- +- +- +- +- GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;release;/include;%(AdditionalIncludeDirectories) +- -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) +- $(IntDir) +- false +- None +- 4577;4467;%(DisableSpecificWarnings) +- Sync +- $(IntDir) +- MaxSpeed +- _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions) +- false +- +- +- MultiThreadedDLL +- true +- true +- Level3 +- true +- +- +- shell32.lib;setupapi.lib;%(AdditionalDependencies) +- C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) +- -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) +- true +- false +- true +- false +- true +- $(OutDir)\QtTermTCP.exe +- true +- Windows +- true +- +- +- Unsigned +- None +- 0 +- +- +- _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;%(PreprocessorDefinitions) +- +- +- msvc +- ./$(Configuration)/moc_predefs.h +- Moc'ing %(Identity)... +- output +- $(IntDir) +- moc_%(Filename).cpp +- +- +- QtTermTCP +- default +- Rcc'ing %(Identity)... +- $(IntDir) +- qrc_%(Filename).cpp +- +- +- Uic'ing %(Identity)... +- $(IntDir) +- ui_%(Filename).h +- +- +- +- +- GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;release;/include;%(AdditionalIncludeDirectories) +- -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) +- $(IntDir) +- false +- None +- 4577;4467;%(DisableSpecificWarnings) +- Sync +- $(IntDir) +- MaxSpeed +- _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions) +- false +- +- +- MultiThreadedDLL +- true +- true +- Level3 +- true +- +- +- shell32.lib;setupapi.lib;%(AdditionalDependencies) +- C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) +- -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) +- true +- false +- true +- false +- true +- $(OutDir)\QtTermTCP.exe +- true +- Windows +- true +- +- +- Unsigned +- None +- 0 +- +- +- _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;%(PreprocessorDefinitions) +- +- +- msvc +- ./$(Configuration)/moc_predefs.h +- Moc'ing %(Identity)... +- output +- $(IntDir) +- moc_%(Filename).cpp +- +- +- QtTermTCP +- default +- Rcc'ing %(Identity)... +- $(IntDir) +- qrc_%(Filename).cpp +- +- +- Uic'ing %(Identity)... +- $(IntDir) +- ui_%(Filename).h +- +- +- +- +- GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;debug;/include;%(AdditionalIncludeDirectories) +- -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) +- $(IntDir) +- false +- EditAndContinue +- 4577;4467;%(DisableSpecificWarnings) +- Sync +- $(intdir) +- Disabled +- _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;%(PreprocessorDefinitions) +- false +- MultiThreadedDebugDLL +- true +- true +- Level3 +- true +- +- +- shell32.lib;setupapi.lib;%(AdditionalDependencies); +- C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) +- -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) +- true +- true +- true +- $(OutDir)\QtTermTCP.exe +- true +- Windows +- true +- false +- +- +- Unsigned +- None +- 0 +- +- +- _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions) +- +- +- msvc +- ./$(Configuration)/moc_predefs.h +- Moc'ing %(Identity)... +- output +- $(IntDir) +- moc_%(Filename).cpp +- +- +- QtTermTCP +- default +- Rcc'ing %(Identity)... +- $(IntDir) +- qrc_%(Filename).cpp +- +- +- Uic'ing %(Identity)... +- $(IntDir) +- ui_%(Filename).h +- +- +- +- +- GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;debug;/include;%(AdditionalIncludeDirectories) +- -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) +- $(IntDir) +- false +- ProgramDatabase +- 4577;4467;%(DisableSpecificWarnings) +- Sync +- $(intdir) +- Disabled +- _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;%(PreprocessorDefinitions) +- false +- MultiThreadedDebugDLL +- true +- true +- Level3 +- true +- +- +- shell32.lib;setupapi.lib;%(AdditionalDependencies) +- C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) +- -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) +- true +- true +- true +- $(OutDir)\QtTermTCP.exe +- true +- Windows +- true +- false +- +- +- Unsigned +- None +- 0 +- +- +- _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions) +- +- +- msvc +- ./$(Configuration)/moc_predefs.h +- Moc'ing %(Identity)... +- output +- $(IntDir) +- moc_%(Filename).cpp +- +- +- QtTermTCP +- default +- Rcc'ing %(Identity)... +- $(IntDir) +- qrc_%(Filename).cpp +- +- +- Uic'ing %(Identity)... +- $(IntDir) +- ui_%(Filename).h +- +- +- +- +- +- +- EditAndContinue +- ProgramDatabase +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- Document +- true +- true +- $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) +- $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) +- cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h +- cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h +- Generate moc_predefs.h +- Generate moc_predefs.h +- debug\moc_predefs.h;%(Outputs) +- debug\moc_predefs.h;%(Outputs) +- +- +- Document +- $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) +- $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) +- cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h +- cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h +- Generate moc_predefs.h +- Generate moc_predefs.h +- release\moc_predefs.h;%(Outputs) +- release\moc_predefs.h;%(Outputs) +- true +- true +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- ++ ++ ++ ++ ++ Debug ++ x64 ++ ++ ++ Release ++ Win32 ++ ++ ++ Debug ++ Win32 ++ ++ ++ Release ++ x64 ++ ++ ++ ++ {14F3B24E-473C-324E-A99D-3B679FCF5F67} ++ QtTermTCP ++ QtVS_v304 ++ 10.0.17763.0 ++ 10.0.19041.0 ++ $(MSBuildProjectDirectory)\QtMsBuild ++ ++ ++ ++ v141 ++ release\ ++ false ++ NotSet ++ Application ++ release\ ++ QtTermTCP ++ ++ ++ v141 ++ release\ ++ false ++ NotSet ++ Application ++ release\ ++ QtTermTCP ++ ++ ++ v141 ++ debug\ ++ false ++ NotSet ++ Application ++ debug\ ++ QtTermTCP ++ ++ ++ v141 ++ debug\ ++ false ++ NotSet ++ Application ++ debug\ ++ QtTermTCP ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ $(SolutionDir)$(Platform)\$(Configuration)\ ++ $(SolutionDir)Intermed\$(Platform)\$(Configuration)\ ++ QtTermTCP ++ true ++ true ++ ++ ++ $(SolutionDir)$(Platform)\$(Configuration)\ ++ $(SolutionDir)Intermed\$(Platform)\$(Configuration)\ ++ QtTermTCP ++ true ++ true ++ ++ ++ $(SolutionDir)$(Platform)\$(Configuration)\ ++ $(SolutionDir)Intermed\$(Platform)\$(Configuration)\ ++ QtTermTCP ++ true ++ false ++ ++ ++ $(SolutionDir)$(Platform)\$(Configuration)\ ++ $(SolutionDir)Intermed\$(Platform)\$(Configuration)\ ++ QtTermTCP ++ true ++ false ++ ++ ++ 5.14.2 ++ core;network;gui;widgets;serialport;multimedia ++ ++ ++ 5.14.2_msvc2017 ++ core;network;gui;widgets;serialport ++ ++ ++ 5.14.2 ++ core;network;gui;widgets;serialport;multimedia ++ ++ ++ 5.14.2_msvc2017_64 ++ core;network;gui;widgets;serialport ++ ++ ++ ++ ++ ++ ++ GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;release;/include;%(AdditionalIncludeDirectories) ++ -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) ++ $(IntDir) ++ false ++ None ++ 4577;4467;%(DisableSpecificWarnings) ++ Sync ++ $(IntDir) ++ MaxSpeed ++ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions) ++ false ++ ++ ++ MultiThreadedDLL ++ true ++ true ++ Level3 ++ true ++ ++ ++ shell32.lib;setupapi.lib;%(AdditionalDependencies) ++ C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) ++ -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) ++ true ++ false ++ true ++ false ++ true ++ $(OutDir)\QtTermTCP.exe ++ true ++ Windows ++ true ++ ++ ++ Unsigned ++ None ++ 0 ++ ++ ++ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;%(PreprocessorDefinitions) ++ ++ ++ msvc ++ ./$(Configuration)/moc_predefs.h ++ Moc'ing %(Identity)... ++ output ++ $(IntDir) ++ moc_%(Filename).cpp ++ ++ ++ QtTermTCP ++ default ++ Rcc'ing %(Identity)... ++ $(IntDir) ++ qrc_%(Filename).cpp ++ ++ ++ Uic'ing %(Identity)... ++ $(IntDir) ++ ui_%(Filename).h ++ ++ ++ ++ ++ GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;release;/include;%(AdditionalIncludeDirectories) ++ -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) ++ $(IntDir) ++ false ++ None ++ 4577;4467;%(DisableSpecificWarnings) ++ Sync ++ $(IntDir) ++ MaxSpeed ++ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;NDEBUG;QT_NO_DEBUG;%(PreprocessorDefinitions) ++ false ++ ++ ++ MultiThreadedDLL ++ true ++ true ++ Level3 ++ true ++ ++ ++ shell32.lib;setupapi.lib;%(AdditionalDependencies) ++ C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) ++ -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) ++ true ++ false ++ true ++ false ++ true ++ $(OutDir)\QtTermTCP.exe ++ true ++ Windows ++ true ++ ++ ++ Unsigned ++ None ++ 0 ++ ++ ++ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;NDEBUG;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;%(PreprocessorDefinitions) ++ ++ ++ msvc ++ ./$(Configuration)/moc_predefs.h ++ Moc'ing %(Identity)... ++ output ++ $(IntDir) ++ moc_%(Filename).cpp ++ ++ ++ QtTermTCP ++ default ++ Rcc'ing %(Identity)... ++ $(IntDir) ++ qrc_%(Filename).cpp ++ ++ ++ Uic'ing %(Identity)... ++ $(IntDir) ++ ui_%(Filename).h ++ ++ ++ ++ ++ GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;debug;/include;%(AdditionalIncludeDirectories) ++ -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) ++ $(IntDir) ++ false ++ EditAndContinue ++ 4577;4467;%(DisableSpecificWarnings) ++ Sync ++ $(intdir) ++ Disabled ++ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;%(PreprocessorDefinitions) ++ false ++ MultiThreadedDebugDLL ++ true ++ true ++ Level3 ++ true ++ ++ ++ shell32.lib;setupapi.lib;%(AdditionalDependencies); ++ C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) ++ -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) ++ true ++ true ++ true ++ $(OutDir)\QtTermTCP.exe ++ true ++ Windows ++ true ++ false ++ ++ ++ Unsigned ++ None ++ 0 ++ ++ ++ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions) ++ ++ ++ msvc ++ ./$(Configuration)/moc_predefs.h ++ Moc'ing %(Identity)... ++ output ++ $(IntDir) ++ moc_%(Filename).cpp ++ ++ ++ QtTermTCP ++ default ++ Rcc'ing %(Identity)... ++ $(IntDir) ++ qrc_%(Filename).cpp ++ ++ ++ Uic'ing %(Identity)... ++ $(IntDir) ++ ui_%(Filename).h ++ ++ ++ ++ ++ GeneratedFiles\$(ConfigurationName);GeneratedFiles;.;debug;/include;%(AdditionalIncludeDirectories) ++ -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) ++ $(IntDir) ++ false ++ ProgramDatabase ++ 4577;4467;%(DisableSpecificWarnings) ++ Sync ++ $(intdir) ++ Disabled ++ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;%(PreprocessorDefinitions) ++ false ++ MultiThreadedDebugDLL ++ true ++ true ++ Level3 ++ true ++ ++ ++ shell32.lib;setupapi.lib;%(AdditionalDependencies) ++ C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) ++ -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) ++ true ++ true ++ true ++ $(OutDir)\QtTermTCP.exe ++ true ++ Windows ++ true ++ false ++ ++ ++ Unsigned ++ None ++ 0 ++ ++ ++ _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;QT_DEPRECATED_WARNINGS;QT_DISABLE_DEPRECATED_BEFORE=0x050000;QT_WIDGETS_LIB;QT_GUI_LIB;QT_NETWORK_LIB;QT_SERIALPORT_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions) ++ ++ ++ msvc ++ ./$(Configuration)/moc_predefs.h ++ Moc'ing %(Identity)... ++ output ++ $(IntDir) ++ moc_%(Filename).cpp ++ ++ ++ QtTermTCP ++ default ++ Rcc'ing %(Identity)... ++ $(IntDir) ++ qrc_%(Filename).cpp ++ ++ ++ Uic'ing %(Identity)... ++ $(IntDir) ++ ui_%(Filename).h ++ ++ ++ ++ ++ ++ ++ EditAndContinue ++ ProgramDatabase ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Document ++ true ++ true ++ $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) ++ $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) ++ cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h ++ cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h ++ Generate moc_predefs.h ++ Generate moc_predefs.h ++ debug\moc_predefs.h;%(Outputs) ++ debug\moc_predefs.h;%(Outputs) ++ ++ ++ Document ++ $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) ++ $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) ++ cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h ++ cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h ++ Generate moc_predefs.h ++ Generate moc_predefs.h ++ release\moc_predefs.h;%(Outputs) ++ release\moc_predefs.h;%(Outputs) ++ true ++ true ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +\ No newline at end of file +--- qttermtcp-0.0.0.79.orig/QtTermTCP.vcxproj.filters ++++ qttermtcp-0.0.0.79/QtTermTCP.vcxproj.filters +@@ -1,137 +1,137 @@ +- +- +- +- +- {99349809-55BA-4b9d-BF79-8FDBB0286EB3} +- ui +- false +- +- +- {99349809-55BA-4b9d-BF79-8FDBB0286EB3} +- ui +- false +- +- +- {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} +- cpp;c;cxx;moc;h;def;odl;idl;res; +- +- +- {93995380-89BD-4b04-88EB-625FBE52EBFB} +- h;hpp;hxx;hm;inl;inc;xsd +- +- +- {93995380-89BD-4b04-88EB-625FBE52EBFB} +- h;hpp;hxx;hm;inl;inc;xsd +- +- +- {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} +- qrc;* +- false +- +- +- {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} +- qrc;* +- false +- +- +- {4FC737F1-C7A5-4376-A066-2A32D752A2FF} +- cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx +- +- +- {4FC737F1-C7A5-4376-A066-2A32D752A2FF} +- cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx +- +- +- {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} +- cpp;c;cxx;moc;h;def;odl;idl;res; +- +- +- +- +- Source Files +- +- +- Source Files +- +- +- Source Files +- +- +- Source Files +- +- +- Source Files +- +- +- Source Files +- +- +- Source Files +- +- +- Source Files +- +- +- Source Files +- +- +- Source Files +- +- +- +- +- Header Files +- +- +- Form Files\Generated Files +- +- +- +- +- Form Files\Generated Files +- +- +- Form Files\Generated Files +- +- +- +- +- Form Files +- +- +- Form Files +- +- +- Form Files +- +- +- Form Files +- +- +- Form Files +- +- +- Form Files +- +- +- Form Files +- +- +- Form Files +- +- +- Form Files +- +- +- +- +- Resource Files +- +- +- Resource Files +- +- +- +- +- ++ ++ ++ ++ ++ {99349809-55BA-4b9d-BF79-8FDBB0286EB3} ++ ui ++ false ++ ++ ++ {99349809-55BA-4b9d-BF79-8FDBB0286EB3} ++ ui ++ false ++ ++ ++ {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} ++ cpp;c;cxx;moc;h;def;odl;idl;res; ++ ++ ++ {93995380-89BD-4b04-88EB-625FBE52EBFB} ++ h;hpp;hxx;hm;inl;inc;xsd ++ ++ ++ {93995380-89BD-4b04-88EB-625FBE52EBFB} ++ h;hpp;hxx;hm;inl;inc;xsd ++ ++ ++ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} ++ qrc;* ++ false ++ ++ ++ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} ++ qrc;* ++ false ++ ++ ++ {4FC737F1-C7A5-4376-A066-2A32D752A2FF} ++ cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx ++ ++ ++ {4FC737F1-C7A5-4376-A066-2A32D752A2FF} ++ cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx ++ ++ ++ {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} ++ cpp;c;cxx;moc;h;def;odl;idl;res; ++ ++ ++ ++ ++ Source Files ++ ++ ++ Source Files ++ ++ ++ Source Files ++ ++ ++ Source Files ++ ++ ++ Source Files ++ ++ ++ Source Files ++ ++ ++ Source Files ++ ++ ++ Source Files ++ ++ ++ Source Files ++ ++ ++ Source Files ++ ++ ++ ++ ++ Header Files ++ ++ ++ Form Files\Generated Files ++ ++ ++ ++ ++ Form Files\Generated Files ++ ++ ++ Form Files\Generated Files ++ ++ ++ ++ ++ Form Files ++ ++ ++ Form Files ++ ++ ++ Form Files ++ ++ ++ Form Files ++ ++ ++ Form Files ++ ++ ++ Form Files ++ ++ ++ Form Files ++ ++ ++ Form Files ++ ++ ++ Form Files ++ ++ ++ ++ ++ Resource Files ++ ++ ++ Resource Files ++ ++ ++ ++ ++ + +\ No newline at end of file +--- qttermtcp-0.0.0.79.orig/QtTermTCP.vcxproj.user ++++ qttermtcp-0.0.0.79/QtTermTCP.vcxproj.user +@@ -1,31 +1,31 @@ +- +- +- +- C:\DevProgs\BPQ32\Release +- WindowsLocalDebugger +- C:\Dev\Msdev2005\Projects\QtTermTCP\Win32\Debug\QtTermTCP.exe +- +- +- C:\DevProgs\BPQ32\Release +- WindowsLocalDebugger +- C:\Dev\Msdev2005\Projects\QtTermTCP\Win32\Debug\QtTermTCP.exe +- +- +- 2022-05-19T07:28:47.9186341Z +- +- +- 2022-05-19T07:28:58.9302359Z +- +- +- 2025-02-19T10:20:19.7224236Z +- +- +- 2025-02-19T10:20:19.9860750Z +- +- +- 2025-02-19T10:20:19.2704826Z +- +- +- 2025-02-19T10:20:19.4132585Z +- ++ ++ ++ ++ C:\DevProgs\BPQ32\Release ++ WindowsLocalDebugger ++ C:\Dev\Msdev2005\Projects\QtTermTCP\Win32\Debug\QtTermTCP.exe ++ ++ ++ C:\DevProgs\BPQ32\Release ++ WindowsLocalDebugger ++ C:\Dev\Msdev2005\Projects\QtTermTCP\Win32\Debug\QtTermTCP.exe ++ ++ ++ 2022-05-19T07:28:47.9186341Z ++ ++ ++ 2022-05-19T07:28:58.9302359Z ++ ++ ++ 2025-02-19T10:20:19.7224236Z ++ ++ ++ 2025-02-19T10:20:19.9860750Z ++ ++ ++ 2025-02-19T10:20:19.2704826Z ++ ++ ++ 2025-02-19T10:20:19.4132585Z ++ + +\ No newline at end of file +--- qttermtcp-0.0.0.79.orig/TCPHostConfig.ui ++++ qttermtcp-0.0.0.79/TCPHostConfig.ui +@@ -1,85 +1,85 @@ +- +- +- Dialog +- +- +- +- 0 +- 0 +- 400 +- 300 +- +- +- +- TCP Host Config +- +- +- +- QtTermTCP.icoQtTermTCP.ico +- +- +- +- +- 30 +- 240 +- 341 +- 32 +- +- +- +- Qt::Horizontal +- +- +- QDialogButtonBox::Cancel|QDialogButtonBox::Save +- +- +- true +- +- +- +- +- +- 184 +- 44 +- 104 +- 23 +- +- +- +- +- +- +- +- buttonBox +- accepted() +- Dialog +- accept() +- +- +- 248 +- 254 +- +- +- 157 +- 274 +- +- +- +- +- buttonBox +- rejected() +- Dialog +- reject() +- +- +- 316 +- 260 +- +- +- 286 +- 274 +- +- +- +- +- ++ ++ ++ Dialog ++ ++ ++ ++ 0 ++ 0 ++ 400 ++ 300 ++ ++ ++ ++ TCP Host Config ++ ++ ++ ++ QtTermTCP.icoQtTermTCP.ico ++ ++ ++ ++ ++ 30 ++ 240 ++ 341 ++ 32 ++ ++ ++ ++ Qt::Horizontal ++ ++ ++ QDialogButtonBox::Cancel|QDialogButtonBox::Save ++ ++ ++ true ++ ++ ++ ++ ++ ++ 184 ++ 44 ++ 104 ++ 23 ++ ++ ++ ++ ++ ++ ++ ++ buttonBox ++ accepted() ++ Dialog ++ accept() ++ ++ ++ 248 ++ 254 ++ ++ ++ 157 ++ 274 ++ ++ ++ ++ ++ buttonBox ++ rejected() ++ Dialog ++ reject() ++ ++ ++ 316 ++ 260 ++ ++ ++ 286 ++ 274 ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/TabDialog.cpp ++++ qttermtcp-0.0.0.79/TabDialog.cpp +@@ -1,1199 +1,1199 @@ +- +-#define _CRT_SECURE_NO_WARNINGS +- +-#include "TabDialog.h" +-#include "QtTermTCP.h" +-#include +-#include "QSettings" +-#include "QLineEdit" +-#include "QTabWidget" +-#include "QDialogButtonBox" +-#include "QVBoxLayout" +-#include "QLabel" +-#include "QAction" +-#include "QGroupBox" +-#include "QPlainTextEdit" +-#include "QCheckBox" +-#include "QFormLayout" +-#include "QScrollArea" +- +-#include "ax25.h" +- +-#ifndef WIN32 +-#define strtok_s strtok_r +-#endif +- +-extern "C" void SaveSettings(); +- +-extern int screenHeight; +-extern int screenWidth; +- +-extern QList _sessions; +-extern QTcpServer * _server; +- +-extern myTcpSocket * AGWSock; +-extern myTcpSocket * KISSSock; +-extern QLabel * Status1; +-extern QFont * menufont; +-extern QStatusBar * myStatusBar; +- +-QLineEdit *hostEdit; +-QLineEdit *portEdit; +-QLineEdit *userEdit; +-QLineEdit *passEdit; +-QLineEdit *SNameEdit; +- +-extern QAction *actHost[17]; +-extern QAction *actSetup[16]; +- +-extern int ConfigHost; +- +-#define MAXHOSTS 16 +- +-extern char Host[MAXHOSTS + 1][100]; +-extern int Port[MAXHOSTS + 1]; +-extern char UserName[MAXHOSTS + 1][80]; +-extern char Password[MAXHOSTS + 1][80]; +-extern char SessName[MAXHOSTS + 1][80]; +- +-extern char KISSMYCALL[32]; +- +-QLineEdit *TermCall; +-QGroupBox *groupBox; +-QLineEdit *beaconDest; +-QLineEdit *beaconPath; +-QLineEdit *beaconInterval; +-QLineEdit *beaconPorts; +-QLabel *label_2; +-QLabel *label_3; +-QLabel *label_4; +-QLabel *label_5; +-QLabel *label_6; +-QLabel *label_7; +-QLabel *label_11; +-QPlainTextEdit *beaconText; +-QLabel *label_12; +-QGroupBox *groupBox_2; +-QLineEdit *AHost; +-QLineEdit *APort; +-QLineEdit *APath; +-QLineEdit *Paclen; +-QLabel *label_8; +-QLabel *label_9; +-QLabel *label_10; +-QLabel *label; +-QCheckBox *AAGWEnable; +-QLabel *label_13; +-QCheckBox *AAGWMonEnable; +- +-QLineEdit *AVARATermCall; +-QLineEdit *AVARAHost; +-QLineEdit *AVARAPort; +-QCheckBox *AVARAEnable; +- +- +-extern int AGWEnable; +-extern int VARAEnable; +-extern int KISSEnable; +-extern int AGWMonEnable; +-extern char AGWTermCall[12]; +-extern char AGWBeaconDest[12]; +-extern char AGWBeaconPath[80]; +-extern int AGWBeaconInterval; +-extern char AGWBeaconPorts[80]; +-extern char AGWBeaconMsg[260]; +- +-extern char VARATermCall[12]; +- +-extern char AGWHost[128]; +-extern int AGWPortNum; +-extern int AGWPaclen; +-extern char * AGWPortList; +-extern myTcpSocket * AGWSock; +-extern char * AGWPortList; +-extern QStringList AGWToCalls; +- +-extern int KISSMode; +-extern char KISSVia[128]; // Digi String +- +-extern Ui_ListenSession * ActiveSession; +- +-extern int TermMode; +- +-#define Single 0 +-#define MDI 1 +-#define Tabbed 2 +- +-extern int listenPort; +-extern "C" int listenEnable; +-extern char listenCText[4096]; +- +-void Send_AGW_C_Frame(Ui_ListenSession * Sess, int Port, char * CallFrom, char * CallTo, char * Data, int DataLen); +-extern "C" void SetSessLabel(Ui_ListenSession * Sess, char * label); +-extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len); +- +-QString GetConfPath(); +- +-QScrollArea *scrollArea; +-QWidget *scrollAreaWidgetContents; +- +-bool myResize::eventFilter(QObject *obj, QEvent *event) +-{ +- if (event->type() == QEvent::Resize) +- { +- QResizeEvent *resizeEvent = static_cast(event); +- QSize size = resizeEvent->size(); +- int h = size.height(); +- int w = size.width(); +- +- scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); +- return true; +- } +- return QObject::eventFilter(obj, event); +-} +- +-AGWConnect::AGWConnect(QWidget *parent) : QDialog(parent) +-{ +- this->setFont(*menufont); +- +- setWindowTitle(tr("AGW Connection")); +- +- myResize *resize = new myResize(); +- installEventFilter(resize); +- +- scrollArea = new QScrollArea(this); +- scrollArea->setObjectName(QString::fromUtf8("scrollArea")); +- scrollArea->setGeometry(QRect(5, 5, 562, 681)); +- scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- scrollArea->setWidgetResizable(false); +- scrollAreaWidgetContents = new QWidget(); +- scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents")); +- +- QVBoxLayout *layout = new QVBoxLayout(); +- layout->setContentsMargins(10, 10, 10, 10); +- +- setLayout(layout); +- +- QFormLayout *formLayout2 = new QFormLayout(); +- layout->addLayout(formLayout2); +- +- wCallFrom = new QLineEdit(); +- formLayout2->addRow(new QLabel("Call From"), wCallFrom); +- +- wCallTo = new QComboBox(); +- wCallTo->setEditable(true); +- wCallTo->setInsertPolicy(QComboBox::NoInsert); +- +- formLayout2->addRow(new QLabel("Call To"), wCallTo); +- +- Digis = new QLineEdit(); +- formLayout2->addRow(new QLabel("Digis"), Digis); +- +- layout->addSpacing(2); +- layout->addWidget(new QLabel("Radio Ports")); +- +- RadioPorts = new QListWidget(); +- +- layout->addWidget(RadioPorts); +- +- QString str; +- int count; +- +- char * Context; +- char * ptr; +- +- wCallFrom->setText(AGWTermCall); +- +- wCallTo->addItems(AGWToCalls); +- +- if (AGWPortList) +- { +- char * Temp = strdup(AGWPortList); // Need copy as strtok messes with it +- +- count = atoi(Temp); +- +- ptr = strtok_s(Temp, ";", &Context); +- +- for (int n = 0; n < count; n++) +- { +- ptr = strtok_s(NULL, ";", &Context); +- new QListWidgetItem(ptr, RadioPorts); +- } +- +- free(Temp); +- +- // calculate scrollarea height from count +- +- scrollAreaWidgetContents->setGeometry(QRect(0, 0, 400, 220 + 22 * count)); +- this->resize(420, 240 + 22 * count); +- +- } +- +- RadioPorts->setFont(*menufont); +- +- buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); +- buttonBox->setFont(*menufont); +- layout->addWidget(buttonBox); +- +- scrollAreaWidgetContents->setLayout(layout); +- scrollArea->setWidget(scrollAreaWidgetContents); +- +- connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); +- connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); +-} +- +-AGWConnect::~AGWConnect() +-{ +-} +- +-extern QAction *discAction; +- +-void AGWConnect::myaccept() +-{ +- QVariant Q; +- +- int port = RadioPorts->currentRow(); +- char CallFrom[32]; +- char CallTo[32]; +- char Via[128]; +- char DigiMsg[128] = ""; +- int DigiLen = 0; +- char * digiptr = &DigiMsg[1]; +- +- strcpy(CallFrom, wCallFrom->text().toUpper().toUtf8()); +- strcpy(CallTo, wCallTo->currentText().toUpper().toUtf8()); +- strcpy(Via, Digis->text().toUpper().toUtf8()); +- +- if (CallFrom[0] == 0) +- { +- QMessageBox msgBox; +- msgBox.setText("Call From missing"); +- msgBox.exec(); +- return; +- } +- +- if (CallTo[0] == 0) +- { +- QMessageBox msgBox; +- msgBox.setText("Call To missing"); +- msgBox.exec(); +- return; +- } +- +- // if digis have to form block with byte count followed by n 10 byte calls +- +- if (Via[0]) +- { +- char * context; +- char * ptr = strtok_s(Via, ", ", &context); +- +- while (ptr) +- { +- DigiMsg[0]++; +- strcpy(digiptr, ptr); +- digiptr += 10; +- +- ptr = strtok_s(NULL, ", ", &context); +- } +- DigiLen = digiptr - DigiMsg; +- } +- +- // Add CallTo if not already in list +- +- if (AGWToCalls.contains(CallTo)) +- AGWToCalls.removeOne(CallTo); +- +- AGWToCalls.insert(-1, CallTo); +- +- if (port == -1) +- { +- // Port not set. If connecting to SWITCH use any, otherwise tell user +- +- if (strcmp(CallTo, "SWITCH") == 0) +- { +- port = 0; +- } +- else +- { +- QMessageBox msgBox; +- msgBox.setText("Select a port to call on"); +- msgBox.exec(); +- return; +- } +- } +- +- Send_AGW_C_Frame(ActiveSession, port, CallFrom, CallTo, DigiMsg, DigiLen); +- +- discAction->setEnabled(true); +- +- +- AGWConnect::accept(); +-} +- +-void AGWConnect::myreject() +-{ +- AGWConnect::reject(); +-} +- +- +-AGWDialog::AGWDialog(QWidget *parent) : QDialog(parent) +-{ +- this->setFont(*menufont); +- +- setWindowTitle(tr("TermTCP AGW Configuration")); +- +- myResize *resize = new myResize(); +- installEventFilter(resize); +- +- +- scrollArea = new QScrollArea(this); +- scrollArea->setObjectName(QString::fromUtf8("scrollArea")); +- scrollArea->setGeometry(QRect(5, 5, 562, 681)); +- scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- scrollArea->setWidgetResizable(false); +- scrollAreaWidgetContents = new QWidget(); +- scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents")); +- scrollAreaWidgetContents->setGeometry(QRect(0, 0, 552, 581)); +- +- this->resize(572, 601); +- +- QVBoxLayout *layout = new QVBoxLayout; +- QHBoxLayout *hlayout = new QHBoxLayout; +- +- layout->addLayout(hlayout); +- AAGWEnable = new QCheckBox("Enable AGW Interface"); +- AAGWEnable->setLayoutDirection(Qt::LeftToRight); +- +- AAGWMonEnable = new QCheckBox("Enable Monitor"); +- AAGWMonEnable->setGeometry(QRect(255, 18, 216, 21)); +- AAGWMonEnable->setLayoutDirection(Qt::RightToLeft); +- +- hlayout->addWidget(AAGWEnable); +- hlayout->addWidget(AAGWMonEnable); +- +- QFormLayout *flayout = new QFormLayout; +- layout->addLayout(flayout); +- +- label = new QLabel("Terminal Call"); +- TermCall = new QLineEdit(this); +- +- flayout->addRow(label, TermCall); +- +- layout->addWidget(new QLabel("Beacon Setup")); +- +- QFormLayout *flayout1 = new QFormLayout; +- layout->addLayout(flayout1); +- +- label_2 = new QLabel("Destination"); +- beaconDest = new QLineEdit(); +- label_3 = new QLabel("Digipeaters"); +- beaconPath = new QLineEdit(); +- +- flayout1->addRow(label_2, beaconDest); +- flayout1->addRow(label_3, beaconPath); +- +- label_4 = new QLabel("Interval"); +- beaconInterval = new QLineEdit(); +- label_5 = new QLabel("Ports"); +- beaconPorts = new QLineEdit(); +- +- flayout1->addRow(label_4, beaconInterval); +- flayout1->addRow(label_5, beaconPorts); +- +-// label_6 = new QLabel("Minutes", groupBox); +- +-// label_7 = new QLabel("(Separate with commas)", groupBox); +- label_11 = new QLabel("Message"); +- beaconText = new QPlainTextEdit(); +- +- flayout1->addRow(label_11, beaconText); +- +- +- +-// label_12 = new QLabel("(max 256 chars)"); +-// label_12->setGeometry(QRect(14, 158, 95, 21)); +- +- layout->addWidget(new QLabel("TNC Setup")); +- +- QFormLayout *flayout2 = new QFormLayout; +- layout->addLayout(flayout2); +- +- AHost = new QLineEdit(); +- APort = new QLineEdit(); +- Paclen = new QLineEdit(); +- label_8 = new QLabel("host"); +- label_9 = new QLabel("Port"); +- label_10 = new QLabel("Paclen "); +- +- flayout2->addRow(label_8, AHost); +- flayout2->addRow(label_9, APort); +- flayout2->addRow(label_10, Paclen); +- +- AAGWEnable->setChecked(AGWEnable); +- AAGWMonEnable->setChecked(AGWMonEnable); +- TermCall->setText(AGWTermCall); +- beaconDest->setText(AGWBeaconDest); +- beaconPath->setText(AGWBeaconPath); +- beaconPorts->setText(AGWBeaconPorts); +- beaconText->setPlainText(AGWBeaconMsg); +- beaconInterval->setText(QString::number(AGWBeaconInterval)); +- AHost->setText(AGWHost); +- APort->setText(QString::number(AGWPortNum)); +- Paclen->setText(QString::number(AGWPaclen)); +- +- buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel, this); +- buttonBox->setFont(*menufont); +- layout->addWidget(buttonBox); +- scrollAreaWidgetContents->setLayout(layout); +- scrollArea->setWidget(scrollAreaWidgetContents); +- +- connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); +- connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); +- +-} +- +- +-AGWDialog::~AGWDialog() +-{ +-} +- +- +-KISSConnect::KISSConnect(QWidget *parent) : QDialog(parent) +-{ +- this->setFont(*menufont); +- +- setWindowTitle(tr("KISS Connection")); +- +- myResize *resize = new myResize(); +- installEventFilter(resize); +- +- scrollArea = new QScrollArea(this); +- scrollArea->setObjectName(QString::fromUtf8("scrollArea")); +- scrollArea->setGeometry(QRect(5, 5, 260, 200)); +- scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- scrollArea->setWidgetResizable(false); +- scrollAreaWidgetContents = new QWidget(); +- scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents")); +- +- // layout is top level. +- // Add a Horizontal layout for Mode and Verical Layout for Call and Digis +- +- QVBoxLayout *layout = new QVBoxLayout(); +- layout->setContentsMargins(10, 10, 10, 10); +- setLayout(layout); +- +- QHBoxLayout *mylayout = new QHBoxLayout(); +- +- Connected = new QRadioButton("Sesion"); +- UIMode = new QRadioButton("UI"); +- +- mylayout->addWidget(new QLabel("Connection Mode")); +- mylayout->addWidget(Connected); +- mylayout->addWidget(UIMode); +- +- if (KISSMode) // UI = 1 +- UIMode->setChecked(1); +- else +- Connected->setChecked(1); +- +- QFormLayout *formLayout2 = new QFormLayout(); +- layout->addLayout(mylayout); +- layout->addSpacing(10); +- layout->addLayout(formLayout2); +- +- Chan = new QComboBox(); +- Chan->setEditable(false); +- Chan->setInsertPolicy(QComboBox::NoInsert); +- Chan->addItems(QStringList() << "A" << "B" << "C" << "D"); +- +- formLayout2->addRow(new QLabel("Modem Channel"), Chan); +- +- wCallTo = new QComboBox(); +- wCallTo->setEditable(true); +- wCallTo->setInsertPolicy(QComboBox::NoInsert); +- +- formLayout2->addRow(new QLabel("Call To"), wCallTo); +- +- Digis = new QLineEdit(); +- +- formLayout2->addRow(new QLabel("Digis"), Digis); +- +- layout->addSpacing(2); +- +- buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); +- buttonBox->setFont(*menufont); +- layout->addWidget(buttonBox); +- +- scrollAreaWidgetContents->setLayout(layout); +- scrollArea->setWidget(scrollAreaWidgetContents); +- +- wCallTo->addItems(AGWToCalls); +- +- Digis->setText(KISSVia); +- Digis->resize(400, 20); +- +- connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); +- connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); +-} +- +-extern "C" void * KISSConnectOut(void * Sess, char * CallFrom, char * CallTo, char * Digis, int Chan, void * Socket); +- +-KISSConnect::~KISSConnect() +-{ +-} +- +-extern QAction * YAPPSend; +-extern QMenu * connectMenu; +-extern QMenu * disconnectMenu; +- +-TAX25Port DummyPort; +-extern "C" TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo); +- +-void KISSConnect::myaccept() +-{ +- QVariant Q; +- +- char CallTo[128];; +- char Port[3]; +- +- strcpy(CallTo, wCallTo->currentText().toUpper().toUtf8()); +- strcpy(KISSVia, Digis->text().toUpper().toUtf8()); +- memcpy(Port, Chan->currentText().toUpper().toUtf8(), 1); +- +- int PortNo = Port[0] - 'A'; +- +- TAX25Port * AX25Sess = 0; +- +- // Check for duplicate session +- +- AX25Sess = get_user_port_by_calls(0, KISSMYCALL, CallTo); +- +- if (AX25Sess) +- { +- // Duplicate +- +- char Msg[256]; +- +- int Len = sprintf(Msg, "You already have a session between %s and %s so can't connect\r", KISSMYCALL, CallTo); +- +- WritetoOutputWindow(ActiveSession, (unsigned char *)Msg, Len); +-// KISSConnect::accept(); +- return; +- } +- +- KISSMode = UIMode->isChecked(); +- +- // Add CallTo if not already in list +- +- if (AGWToCalls.contains(CallTo)) +- AGWToCalls.removeOne(CallTo); +- +- AGWToCalls.insert(-1, CallTo); +- +- ActiveSession->KISSMode = KISSMode; +- +- if (KISSMode == 0) +- { +- ActiveSession->KISSSession = KISSConnectOut(ActiveSession, KISSMYCALL, CallTo, KISSVia, PortNo, (void *)KISSSock); +- WritetoOutputWindow(ActiveSession, (unsigned char *)"Connecting...\r", 14); +- discAction->setEnabled(true); +- } +- else +- { +- // UI +- +- char Msg[128]; +- int Len = 0; +- +- memset(&DummyPort, 0, sizeof(DummyPort)); +- +- ActiveSession->KISSSession = (void *)&DummyPort; // Dummy marker to show session in use +- +- strcpy(ActiveSession->UIDEST, CallTo); +- strcpy(ActiveSession->UIPATH, KISSVia); +- ActiveSession->UIPORT = PortNo; +- +- if (TermMode == Tabbed) +- Len = sprintf(Msg, "UI %s", CallTo); +- else +- Len = sprintf(Msg, "UI Session with %s\r", CallTo); +- +- SetSessLabel(ActiveSession, Msg); +- +- Len = sprintf(Msg, "UI Session with %s\r", CallTo); +- SendtoTerm(ActiveSession, Msg, Len); +- connectMenu->setEnabled(false); +- discAction->setEnabled(true); +- YAPPSend->setEnabled(false); +- } +- +- KISSConnect::accept(); +-} +- +-void KISSConnect::myreject() +-{ +- KISSConnect::reject(); +-} +- +- +- +-VARAConnect::VARAConnect(QWidget *parent) : QDialog(parent) +-{ +- this->setFont(*menufont); +- +- setWindowTitle(tr("VARA Connection")); +- +- myResize *resize = new myResize(); +- installEventFilter(resize); +- +- scrollArea = new QScrollArea(this); +- scrollArea->setObjectName(QString::fromUtf8("scrollArea")); +- scrollArea->setGeometry(QRect(5, 5, 250, 150)); +- scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); +- scrollArea->setWidgetResizable(false); +- scrollAreaWidgetContents = new QWidget(); +- scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents")); +- +- QVBoxLayout *layout = new QVBoxLayout(); +- layout->setContentsMargins(10, 10, 10, 10); +- +- setLayout(layout); +- +- QFormLayout *formLayout2 = new QFormLayout(); +- layout->addLayout(formLayout2); +- +- wCallFrom = new QLineEdit(); +- formLayout2->addRow(new QLabel("Call From"), wCallFrom); +- +- wCallTo = new QComboBox(); +- wCallTo->setEditable(true); +- wCallTo->setInsertPolicy(QComboBox::NoInsert); +- +- formLayout2->addRow(new QLabel("Call To"), wCallTo); +- +- Digis = new QLineEdit(); +- formLayout2->addRow(new QLabel("Digis"), Digis); +- +- layout->addSpacing(2); +- +- buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); +- buttonBox->setFont(*menufont); +- layout->addWidget(buttonBox); +- +- scrollAreaWidgetContents->setLayout(layout); +- scrollArea->setWidget(scrollAreaWidgetContents); +- +- wCallFrom->setText(VARATermCall); +- wCallTo->addItems(AGWToCalls); +- +- connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); +- connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); +-} +- +-VARAConnect::~VARAConnect() +-{ +-} +- +-extern myTcpSocket * VARASock; +-extern myTcpSocket * VARADataSock; +- +-void VARAConnect::myaccept() +-{ +- QVariant Q; +- +- char CallFrom[32]; +- char CallTo[32]; +- char Via[128]; +- char Msg[256]; +- int Len; +- +- strcpy(CallFrom, wCallFrom->text().toUpper().toUtf8()); +- strcpy(CallTo, wCallTo->currentText().toUpper().toUtf8()); +- strcpy(Via, Digis->text().toUpper().toUtf8()); +- +-// if digis have to form block with byte count followed by n 10 byte calls +- +- +-// Add CallTo if not already in list +- +- if (AGWToCalls.contains(CallTo)) +- AGWToCalls.removeOne(CallTo); +- +- AGWToCalls.insert(-1, CallTo); +- +- +- if (Via[0]) +- Len = sprintf(Msg, "CONNECT %s %s VIA %s\r", CallFrom, CallTo, Via); +- else +- Len = sprintf(Msg, "CONNECT %s %s\r", CallFrom, CallTo); +- +- VARASock->write(Msg, Len); +- +- discAction->setEnabled(true); +- VARAConnect::accept(); +-} +- +-void VARAConnect::myreject() +-{ +- VARAConnect::reject(); +-} +- +- +-extern QProcess *process; +- +- +- +-TabDialog::TabDialog(QWidget *parent) : QDialog(parent) +-{ +- char portnum[10]; +- +- buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel); +- +- connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); +- connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); +- +- QVBoxLayout *layout = new QVBoxLayout; +- QLabel *hostLabel = new QLabel(tr("Host Name:")); +- hostEdit = new QLineEdit(Host[ConfigHost]); +- +- QLabel *portLabel = new QLabel(tr("Port:")); +- sprintf(portnum, "%d", Port[ConfigHost]); +- portEdit = new QLineEdit(portnum); +- +- QLabel *userLabel = new QLabel(tr("User:")); +- userEdit = new QLineEdit(UserName[ConfigHost]); +- +- QLabel *passLabel = new QLabel(tr("Password:")); +- passEdit = new QLineEdit(Password[ConfigHost]); +- +- QLabel *SNameLabel = new QLabel(tr("Session Name")); +- SNameEdit = new QLineEdit(SessName[ConfigHost]); +- +- layout->addWidget(hostLabel); +- layout->addWidget(hostEdit); +- layout->addWidget(portLabel); +- layout->addWidget(portEdit); +- layout->addWidget(userLabel); +- layout->addWidget(userEdit); +- layout->addWidget(passLabel); +- layout->addWidget(passEdit); +- layout->addWidget(SNameLabel); +- layout->addWidget(SNameEdit); +- +- layout->addStretch(1); +- layout->addWidget(buttonBox); +- setLayout(layout); +- +- setWindowTitle(tr("TermTCP Host Configuration")); +-} +- +-void AGWDialog::myaccept() +-{ +- QVariant Q; +- +- int OldEnable = AGWEnable; +- int OldPort = AGWPortNum; +- char oldHost[128]; +- strcpy(oldHost, AGWHost); +- +- // QString val = Sess->portNo->text();A +- // QByteArray qb = val.toLatin1(); +- // char * ptr = qb.data(); +- +- AGWEnable = AAGWEnable->isChecked(); +- AGWMonEnable = AAGWMonEnable->isChecked(); +- +- strcpy(AGWTermCall, TermCall->text().toUtf8().toUpper()); +- strcpy(AGWBeaconDest, beaconDest->text().toUtf8().toUpper()); +- strcpy(AGWBeaconPath, beaconPath->text().toUtf8().toUpper()); +- strcpy(AGWBeaconPorts, beaconPorts->text().toUtf8().toUpper()); +- +- if (beaconText->toPlainText().length() > 256) +- { +- QMessageBox msgBox; +- msgBox.setText("Beacon Text Too Long"); +- msgBox.exec(); +- } +- else +- strcpy(AGWBeaconMsg, beaconText->toPlainText().toUtf8().toUpper()); +- +- Q = beaconInterval->text(); +- AGWBeaconInterval = Q.toInt(); +- +- strcpy(AGWHost, AHost->text().toUtf8()); +- +- Q = APort->text(); +- AGWPortNum = Q.toInt(); +- +- Q = Paclen->text(); +- AGWPaclen = Q.toInt(); +- +- SaveSettings(); +- +- if (AGWEnable != OldEnable || AGWPortNum != OldPort || strcmp(oldHost, AGWHost) != 0) +- { +- // (re)start connection +- +- if (OldEnable && AGWSock && AGWSock->ConnectedState == QAbstractSocket::ConnectedState) +- { +- AGWSock->disconnectFromHost(); +- Status1->setText("AGW Disconnected"); +- } +- // AGWTimer will reopen connection +- } +- +- myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable); +- +- AGWDialog::accept(); +- +-} +- +-void AGWDialog::myreject() +-{ +- AGWDialog::reject(); +-} +- +-void TabDialog::myaccept() +-{ +- QString val = hostEdit->text(); +- QByteArray qb = val.toLatin1(); +- char * ptr = qb.data(); +- strcpy(Host[ConfigHost], ptr); +- +- val = portEdit->text(); +- qb = val.toLatin1(); +- ptr = qb.data(); +- Port[ConfigHost] = atoi(ptr); +- +- val = userEdit->text(); +- qb = val.toLatin1(); +- ptr = qb.data(); +- strcpy(UserName[ConfigHost], ptr); +- +- val = passEdit->text(); +- qb = val.toLatin1(); +- ptr = qb.data(); +- strcpy(Password[ConfigHost], ptr); +- +- val = SNameEdit->text(); +- qb = val.toLatin1(); +- ptr = qb.data(); +- strcpy(SessName[ConfigHost], ptr); +- +- char Label[256]; +- +- if (ptr[0]) +- sprintf(Label, "%s(%s)", Host[ConfigHost], SessName[ConfigHost]); +- else +- strcpy(Label, Host[ConfigHost]); +- +- actHost[ConfigHost]->setText(Label); +- actSetup[ConfigHost]->setText(Label); +- +- SaveSettings(); +- +- TabDialog::accept(); +- +-} +- +-void TabDialog::myreject() +-{ +- TabDialog::reject(); +-} +- +-TabDialog::~TabDialog() +-{ +-} +- +-// Menu dialog +- +- +-fontDialog::fontDialog(int Menu, QWidget *parent) : QDialog(parent) +-{ +- // Menu is set if setting Menufont, zero for setting terminal font. +- +- int i; +- char valChar[16]; +- +- QString family; +- int csize; +- QFont::Weight weight; +- +-#ifdef ANDROID +- this->resize((screenWidth * 7) / 8, 200); +- this->setMaximumWidth((screenWidth * 7) / 8); +-#endif +- this->setFont(*menufont); +- +- Menuflag = Menu; +- +- if (Menu) +- { +- workingFont = *menufont; +- +- QFontInfo info(*menufont); +- family = info.family(); +- csize = info.pointSize(); +- +- setWindowTitle("Menu Font Dialog"); +- } +- else +- { +- // get current term font +- +- QSettings settings(GetConfPath(), QSettings::IniFormat); +- +-#ifdef ANDROID +- family = settings.value("FontFamily", "Driod Sans Mono").toString(); +- csize = settings.value("PointSize", 12).toInt(); +- weight = (QFont::Weight)settings.value("Weight", 50).toInt(); +-#else +- family = settings.value("FontFamily", "Courier New").toString(); +- csize = settings.value("PointSize", 10).toInt(); +- weight = (QFont::Weight)settings.value("Weight", 50).toInt(); +-#endif +- +- workingFont = QFont(family); +- workingFont.setPointSize(csize); +- workingFont.setWeight(weight); +- +- setWindowTitle("Terminal Font Dialog"); +- } +- +- QVBoxLayout *layout = new QVBoxLayout(); +- layout->setContentsMargins(10, 10, 10, 10); +- +- setLayout(layout); +- +- QHBoxLayout *hlayout = new QHBoxLayout(); +- layout->addLayout(hlayout); +- +- font = new QFontComboBox(); +- +- if (Menu == 0) +- font->setFontFilters(QFontComboBox::MonospacedFonts); +- +- font->setMaximumWidth((screenWidth * 5) / 8); +- font->view()->setMaximumWidth((7 * screenWidth) / 8); +- +- style = new QComboBox(); +- style->setMaximumWidth(screenWidth / 4); +- size = new QComboBox(); +- sample = new QTextEdit(); +- sample->setText("ABCDabcd1234"); +- sample->setFont(workingFont); +- +- hlayout->addWidget(font); +- hlayout->addWidget(style); +- hlayout->addWidget(size); +- layout->addWidget(sample); +- +- QFontDatabase database; +- +- const QStringList styles = database.styles(family); +- +- const QList smoothSizes = database.smoothSizes(family, styles[0]); +- +- for (int points : smoothSizes) +- size->addItem(QString::number(points)); +- +- for (QString xstyle : styles) +- style->addItem(xstyle); +- +- i = font->findText(family, Qt::MatchExactly); +- font->setCurrentIndex(i); +- +- sprintf(valChar, "%d", csize); +- i = size->findText(valChar, Qt::MatchExactly); +- size->setCurrentIndex(i); +- +- buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); +- buttonBox->setFont(*menufont); +- layout->addWidget(buttonBox); +- setLayout(layout); +- +- connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); +- connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); +- connect(font, SIGNAL(currentFontChanged(QFont)), this, SLOT(fontchanged(QFont))); +- connect(style, SIGNAL(currentIndexChanged(int)), this, SLOT(stylechanged())); +- connect(size, SIGNAL(currentIndexChanged(int)), this, SLOT(sizechanged())); +-} +- +-void fontDialog::fontchanged(QFont newfont) +-{ +- QFontDatabase database; +- QString family = newfont.family(); +- +- workingFont = newfont; +- +- const QStringList styles = database.styles(family); +- const QList smoothSizes = database.smoothSizes(family, styles[0]); +- +- size->clear(); +- style->clear(); +- +- for (int points : smoothSizes) +- size->addItem(QString::number(points)); +- +- for (QString xstyle : styles) +- style->addItem(xstyle); +- +- sample->setFont(workingFont); +-} +- +-void fontDialog::stylechanged() +-{ +- QFontDatabase database; +- +- QString family = font->currentFont().family(); +- +- bool italic = database.italic(family, style->currentText()); +- int weight = database.weight(family, style->currentText()); +- +- if (weight < 0) +- weight = 50; // Normal +- +- workingFont.setItalic(italic); +- workingFont.setWeight((QFont::Weight) weight); +- +- sample->setFont(workingFont); +-} +- +-void fontDialog::sizechanged() +-{ +- int newsize = size->currentText().toInt(); +- workingFont.setPointSize(newsize); +- sample->setFont(workingFont); +-} +-fontDialog::~fontDialog() +-{ +-} +- +-void fontDialog::myaccept() +-{ +- QSettings settings(GetConfPath(), QSettings::IniFormat); +- +- if (Menuflag) +- { +- delete menufont; +- menufont = new QFont(workingFont); +- +- QtTermTCP::setFonts(); +- +- settings.setValue("MFontFamily", workingFont.family()); +- settings.setValue("MPointSize", workingFont.pointSize()); +- settings.setValue("MWeight", workingFont.weight()); +- } +- else +- { +- Ui_ListenSession * Sess; +- +- for (int i = 0; i < _sessions.size(); ++i) +- { +- Sess = _sessions.at(i); +- +- if (Sess->termWindow) +- Sess->termWindow->setFont(workingFont); +- +- if (Sess->inputWindow) +- Sess->inputWindow->setFont(workingFont); +- +- if (Sess->monWindow) +- Sess->monWindow->setFont(workingFont); +- } +- +- settings.setValue("FontFamily", workingFont.family()); +- settings.setValue("PointSize", workingFont.pointSize()); +- settings.setValue("Weight", workingFont.weight()); +- } +- +- fontDialog::accept(); +-} +- +-void fontDialog::myreject() +-{ +- fontDialog::reject(); +-} +- +- +- +-ListenDialog::ListenDialog(QWidget *parent) : QDialog(parent) +-{ +-#ifdef ANDROID +- this->resize((screenWidth * 3) / 4 , 500); +-#endif +- verticalLayout = new QVBoxLayout(); +- verticalLayout->setContentsMargins(10, 10, 10, 10); +- +- setLayout(verticalLayout); +- +- Enabled = new QCheckBox(); +- Enabled->setText(QString::fromUtf8("Enable Listen")); +- Enabled->setLayoutDirection(Qt::LeftToRight); +- +- verticalLayout->addWidget(Enabled); +- +- formLayout = new QFormLayout(); +- +- portNo = new QLineEdit(); +-// portNo->setMaximumSize(QSize(100, 30)); +- +- formLayout->addRow(new QLabel("Port"), portNo); +- +- CText = new QTextEdit(); +- CText->setMinimumSize(QSize(0, 150)); +- CText->setMaximumSize(QSize(401, 150)); +- +- formLayout->addRow(new QLabel("CText"), CText); +- buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); +- buttonBox->setFont(*menufont); +- verticalLayout->addWidget(buttonBox); +- +- connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); +- connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); +- +- verticalLayout->addLayout(formLayout); +- verticalLayout->addWidget(buttonBox); +- +- portNo->setText(QString::number(listenPort)); +- Enabled->setChecked(listenEnable); +- CText->setText(listenCText); +- +-} +- +-ListenDialog::~ListenDialog() +-{ +-} +- +-void ListenDialog::myaccept() +-{ +- QString val = portNo->text(); +- QByteArray qb = val.toLatin1(); +- char * ptr = qb.data(); +- +- listenPort = atoi(ptr); +- listenEnable = Enabled->isChecked(); +- strcpy(listenCText, CText->toPlainText().toUtf8()); +- +- while ((ptr = strchr(listenCText, '\n'))) +- *ptr = '\r'; +- +- if (_server->isListening()) +- _server->close(); +- +- SaveSettings(); +- +- if (listenEnable) +- _server->listen(QHostAddress::Any, listenPort); +- +- ListenDialog::accept(); +-} +- +-void ListenDialog::myreject() +-{ +- ListenDialog::reject(); +-} ++ ++#define _CRT_SECURE_NO_WARNINGS ++ ++#include "TabDialog.h" ++#include "QtTermTCP.h" ++#include ++#include "QSettings" ++#include "QLineEdit" ++#include "QTabWidget" ++#include "QDialogButtonBox" ++#include "QVBoxLayout" ++#include "QLabel" ++#include "QAction" ++#include "QGroupBox" ++#include "QPlainTextEdit" ++#include "QCheckBox" ++#include "QFormLayout" ++#include "QScrollArea" ++ ++#include "ax25.h" ++ ++#ifndef WIN32 ++#define strtok_s strtok_r ++#endif ++ ++extern "C" void SaveSettings(); ++ ++extern int screenHeight; ++extern int screenWidth; ++ ++extern QList _sessions; ++extern QTcpServer * _server; ++ ++extern myTcpSocket * AGWSock; ++extern myTcpSocket * KISSSock; ++extern QLabel * Status1; ++extern QFont * menufont; ++extern QStatusBar * myStatusBar; ++ ++QLineEdit *hostEdit; ++QLineEdit *portEdit; ++QLineEdit *userEdit; ++QLineEdit *passEdit; ++QLineEdit *SNameEdit; ++ ++extern QAction *actHost[17]; ++extern QAction *actSetup[16]; ++ ++extern int ConfigHost; ++ ++#define MAXHOSTS 16 ++ ++extern char Host[MAXHOSTS + 1][100]; ++extern int Port[MAXHOSTS + 1]; ++extern char UserName[MAXHOSTS + 1][80]; ++extern char Password[MAXHOSTS + 1][80]; ++extern char SessName[MAXHOSTS + 1][80]; ++ ++extern char KISSMYCALL[32]; ++ ++QLineEdit *TermCall; ++QGroupBox *groupBox; ++QLineEdit *beaconDest; ++QLineEdit *beaconPath; ++QLineEdit *beaconInterval; ++QLineEdit *beaconPorts; ++QLabel *label_2; ++QLabel *label_3; ++QLabel *label_4; ++QLabel *label_5; ++QLabel *label_6; ++QLabel *label_7; ++QLabel *label_11; ++QPlainTextEdit *beaconText; ++QLabel *label_12; ++QGroupBox *groupBox_2; ++QLineEdit *AHost; ++QLineEdit *APort; ++QLineEdit *APath; ++QLineEdit *Paclen; ++QLabel *label_8; ++QLabel *label_9; ++QLabel *label_10; ++QLabel *label; ++QCheckBox *AAGWEnable; ++QLabel *label_13; ++QCheckBox *AAGWMonEnable; ++ ++QLineEdit *AVARATermCall; ++QLineEdit *AVARAHost; ++QLineEdit *AVARAPort; ++QCheckBox *AVARAEnable; ++ ++ ++extern int AGWEnable; ++extern int VARAEnable; ++extern int KISSEnable; ++extern int AGWMonEnable; ++extern char AGWTermCall[12]; ++extern char AGWBeaconDest[12]; ++extern char AGWBeaconPath[80]; ++extern int AGWBeaconInterval; ++extern char AGWBeaconPorts[80]; ++extern char AGWBeaconMsg[260]; ++ ++extern char VARATermCall[12]; ++ ++extern char AGWHost[128]; ++extern int AGWPortNum; ++extern int AGWPaclen; ++extern char * AGWPortList; ++extern myTcpSocket * AGWSock; ++extern char * AGWPortList; ++extern QStringList AGWToCalls; ++ ++extern int KISSMode; ++extern char KISSVia[128]; // Digi String ++ ++extern Ui_ListenSession * ActiveSession; ++ ++extern int TermMode; ++ ++#define Single 0 ++#define MDI 1 ++#define Tabbed 2 ++ ++extern int listenPort; ++extern "C" int listenEnable; ++extern char listenCText[4096]; ++ ++void Send_AGW_C_Frame(Ui_ListenSession * Sess, int Port, char * CallFrom, char * CallTo, char * Data, int DataLen); ++extern "C" void SetSessLabel(Ui_ListenSession * Sess, char * label); ++extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len); ++ ++QString GetConfPath(); ++ ++QScrollArea *scrollArea; ++QWidget *scrollAreaWidgetContents; ++ ++bool myResize::eventFilter(QObject *obj, QEvent *event) ++{ ++ if (event->type() == QEvent::Resize) ++ { ++ QResizeEvent *resizeEvent = static_cast(event); ++ QSize size = resizeEvent->size(); ++ int h = size.height(); ++ int w = size.width(); ++ ++ scrollArea->setGeometry(QRect(5, 5, w - 10, h - 10)); ++ return true; ++ } ++ return QObject::eventFilter(obj, event); ++} ++ ++AGWConnect::AGWConnect(QWidget *parent) : QDialog(parent) ++{ ++ this->setFont(*menufont); ++ ++ setWindowTitle(tr("AGW Connection")); ++ ++ myResize *resize = new myResize(); ++ installEventFilter(resize); ++ ++ scrollArea = new QScrollArea(this); ++ scrollArea->setObjectName(QString::fromUtf8("scrollArea")); ++ scrollArea->setGeometry(QRect(5, 5, 562, 681)); ++ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ scrollArea->setWidgetResizable(false); ++ scrollAreaWidgetContents = new QWidget(); ++ scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents")); ++ ++ QVBoxLayout *layout = new QVBoxLayout(); ++ layout->setContentsMargins(10, 10, 10, 10); ++ ++ setLayout(layout); ++ ++ QFormLayout *formLayout2 = new QFormLayout(); ++ layout->addLayout(formLayout2); ++ ++ wCallFrom = new QLineEdit(); ++ formLayout2->addRow(new QLabel("Call From"), wCallFrom); ++ ++ wCallTo = new QComboBox(); ++ wCallTo->setEditable(true); ++ wCallTo->setInsertPolicy(QComboBox::NoInsert); ++ ++ formLayout2->addRow(new QLabel("Call To"), wCallTo); ++ ++ Digis = new QLineEdit(); ++ formLayout2->addRow(new QLabel("Digis"), Digis); ++ ++ layout->addSpacing(2); ++ layout->addWidget(new QLabel("Radio Ports")); ++ ++ RadioPorts = new QListWidget(); ++ ++ layout->addWidget(RadioPorts); ++ ++ QString str; ++ int count; ++ ++ char * Context; ++ char * ptr; ++ ++ wCallFrom->setText(AGWTermCall); ++ ++ wCallTo->addItems(AGWToCalls); ++ ++ if (AGWPortList) ++ { ++ char * Temp = strdup(AGWPortList); // Need copy as strtok messes with it ++ ++ count = atoi(Temp); ++ ++ ptr = strtok_s(Temp, ";", &Context); ++ ++ for (int n = 0; n < count; n++) ++ { ++ ptr = strtok_s(NULL, ";", &Context); ++ new QListWidgetItem(ptr, RadioPorts); ++ } ++ ++ free(Temp); ++ ++ // calculate scrollarea height from count ++ ++ scrollAreaWidgetContents->setGeometry(QRect(0, 0, 400, 220 + 22 * count)); ++ this->resize(420, 240 + 22 * count); ++ ++ } ++ ++ RadioPorts->setFont(*menufont); ++ ++ buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); ++ buttonBox->setFont(*menufont); ++ layout->addWidget(buttonBox); ++ ++ scrollAreaWidgetContents->setLayout(layout); ++ scrollArea->setWidget(scrollAreaWidgetContents); ++ ++ connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); ++ connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); ++} ++ ++AGWConnect::~AGWConnect() ++{ ++} ++ ++extern QAction *discAction; ++ ++void AGWConnect::myaccept() ++{ ++ QVariant Q; ++ ++ int port = RadioPorts->currentRow(); ++ char CallFrom[32]; ++ char CallTo[32]; ++ char Via[128]; ++ char DigiMsg[128] = ""; ++ int DigiLen = 0; ++ char * digiptr = &DigiMsg[1]; ++ ++ strcpy(CallFrom, wCallFrom->text().toUpper().toUtf8()); ++ strcpy(CallTo, wCallTo->currentText().toUpper().toUtf8()); ++ strcpy(Via, Digis->text().toUpper().toUtf8()); ++ ++ if (CallFrom[0] == 0) ++ { ++ QMessageBox msgBox; ++ msgBox.setText("Call From missing"); ++ msgBox.exec(); ++ return; ++ } ++ ++ if (CallTo[0] == 0) ++ { ++ QMessageBox msgBox; ++ msgBox.setText("Call To missing"); ++ msgBox.exec(); ++ return; ++ } ++ ++ // if digis have to form block with byte count followed by n 10 byte calls ++ ++ if (Via[0]) ++ { ++ char * context; ++ char * ptr = strtok_s(Via, ", ", &context); ++ ++ while (ptr) ++ { ++ DigiMsg[0]++; ++ strcpy(digiptr, ptr); ++ digiptr += 10; ++ ++ ptr = strtok_s(NULL, ", ", &context); ++ } ++ DigiLen = digiptr - DigiMsg; ++ } ++ ++ // Add CallTo if not already in list ++ ++ if (AGWToCalls.contains(CallTo)) ++ AGWToCalls.removeOne(CallTo); ++ ++ AGWToCalls.insert(-1, CallTo); ++ ++ if (port == -1) ++ { ++ // Port not set. If connecting to SWITCH use any, otherwise tell user ++ ++ if (strcmp(CallTo, "SWITCH") == 0) ++ { ++ port = 0; ++ } ++ else ++ { ++ QMessageBox msgBox; ++ msgBox.setText("Select a port to call on"); ++ msgBox.exec(); ++ return; ++ } ++ } ++ ++ Send_AGW_C_Frame(ActiveSession, port, CallFrom, CallTo, DigiMsg, DigiLen); ++ ++ discAction->setEnabled(true); ++ ++ ++ AGWConnect::accept(); ++} ++ ++void AGWConnect::myreject() ++{ ++ AGWConnect::reject(); ++} ++ ++ ++AGWDialog::AGWDialog(QWidget *parent) : QDialog(parent) ++{ ++ this->setFont(*menufont); ++ ++ setWindowTitle(tr("TermTCP AGW Configuration")); ++ ++ myResize *resize = new myResize(); ++ installEventFilter(resize); ++ ++ ++ scrollArea = new QScrollArea(this); ++ scrollArea->setObjectName(QString::fromUtf8("scrollArea")); ++ scrollArea->setGeometry(QRect(5, 5, 562, 681)); ++ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ scrollArea->setWidgetResizable(false); ++ scrollAreaWidgetContents = new QWidget(); ++ scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents")); ++ scrollAreaWidgetContents->setGeometry(QRect(0, 0, 552, 581)); ++ ++ this->resize(572, 601); ++ ++ QVBoxLayout *layout = new QVBoxLayout; ++ QHBoxLayout *hlayout = new QHBoxLayout; ++ ++ layout->addLayout(hlayout); ++ AAGWEnable = new QCheckBox("Enable AGW Interface"); ++ AAGWEnable->setLayoutDirection(Qt::LeftToRight); ++ ++ AAGWMonEnable = new QCheckBox("Enable Monitor"); ++ AAGWMonEnable->setGeometry(QRect(255, 18, 216, 21)); ++ AAGWMonEnable->setLayoutDirection(Qt::RightToLeft); ++ ++ hlayout->addWidget(AAGWEnable); ++ hlayout->addWidget(AAGWMonEnable); ++ ++ QFormLayout *flayout = new QFormLayout; ++ layout->addLayout(flayout); ++ ++ label = new QLabel("Terminal Call"); ++ TermCall = new QLineEdit(this); ++ ++ flayout->addRow(label, TermCall); ++ ++ layout->addWidget(new QLabel("Beacon Setup")); ++ ++ QFormLayout *flayout1 = new QFormLayout; ++ layout->addLayout(flayout1); ++ ++ label_2 = new QLabel("Destination"); ++ beaconDest = new QLineEdit(); ++ label_3 = new QLabel("Digipeaters"); ++ beaconPath = new QLineEdit(); ++ ++ flayout1->addRow(label_2, beaconDest); ++ flayout1->addRow(label_3, beaconPath); ++ ++ label_4 = new QLabel("Interval"); ++ beaconInterval = new QLineEdit(); ++ label_5 = new QLabel("Ports"); ++ beaconPorts = new QLineEdit(); ++ ++ flayout1->addRow(label_4, beaconInterval); ++ flayout1->addRow(label_5, beaconPorts); ++ ++// label_6 = new QLabel("Minutes", groupBox); ++ ++// label_7 = new QLabel("(Separate with commas)", groupBox); ++ label_11 = new QLabel("Message"); ++ beaconText = new QPlainTextEdit(); ++ ++ flayout1->addRow(label_11, beaconText); ++ ++ ++ ++// label_12 = new QLabel("(max 256 chars)"); ++// label_12->setGeometry(QRect(14, 158, 95, 21)); ++ ++ layout->addWidget(new QLabel("TNC Setup")); ++ ++ QFormLayout *flayout2 = new QFormLayout; ++ layout->addLayout(flayout2); ++ ++ AHost = new QLineEdit(); ++ APort = new QLineEdit(); ++ Paclen = new QLineEdit(); ++ label_8 = new QLabel("host"); ++ label_9 = new QLabel("Port"); ++ label_10 = new QLabel("Paclen "); ++ ++ flayout2->addRow(label_8, AHost); ++ flayout2->addRow(label_9, APort); ++ flayout2->addRow(label_10, Paclen); ++ ++ AAGWEnable->setChecked(AGWEnable); ++ AAGWMonEnable->setChecked(AGWMonEnable); ++ TermCall->setText(AGWTermCall); ++ beaconDest->setText(AGWBeaconDest); ++ beaconPath->setText(AGWBeaconPath); ++ beaconPorts->setText(AGWBeaconPorts); ++ beaconText->setPlainText(AGWBeaconMsg); ++ beaconInterval->setText(QString::number(AGWBeaconInterval)); ++ AHost->setText(AGWHost); ++ APort->setText(QString::number(AGWPortNum)); ++ Paclen->setText(QString::number(AGWPaclen)); ++ ++ buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel, this); ++ buttonBox->setFont(*menufont); ++ layout->addWidget(buttonBox); ++ scrollAreaWidgetContents->setLayout(layout); ++ scrollArea->setWidget(scrollAreaWidgetContents); ++ ++ connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); ++ connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); ++ ++} ++ ++ ++AGWDialog::~AGWDialog() ++{ ++} ++ ++ ++KISSConnect::KISSConnect(QWidget *parent) : QDialog(parent) ++{ ++ this->setFont(*menufont); ++ ++ setWindowTitle(tr("KISS Connection")); ++ ++ myResize *resize = new myResize(); ++ installEventFilter(resize); ++ ++ scrollArea = new QScrollArea(this); ++ scrollArea->setObjectName(QString::fromUtf8("scrollArea")); ++ scrollArea->setGeometry(QRect(5, 5, 260, 200)); ++ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ scrollArea->setWidgetResizable(false); ++ scrollAreaWidgetContents = new QWidget(); ++ scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents")); ++ ++ // layout is top level. ++ // Add a Horizontal layout for Mode and Verical Layout for Call and Digis ++ ++ QVBoxLayout *layout = new QVBoxLayout(); ++ layout->setContentsMargins(10, 10, 10, 10); ++ setLayout(layout); ++ ++ QHBoxLayout *mylayout = new QHBoxLayout(); ++ ++ Connected = new QRadioButton("Sesion"); ++ UIMode = new QRadioButton("UI"); ++ ++ mylayout->addWidget(new QLabel("Connection Mode")); ++ mylayout->addWidget(Connected); ++ mylayout->addWidget(UIMode); ++ ++ if (KISSMode) // UI = 1 ++ UIMode->setChecked(1); ++ else ++ Connected->setChecked(1); ++ ++ QFormLayout *formLayout2 = new QFormLayout(); ++ layout->addLayout(mylayout); ++ layout->addSpacing(10); ++ layout->addLayout(formLayout2); ++ ++ Chan = new QComboBox(); ++ Chan->setEditable(false); ++ Chan->setInsertPolicy(QComboBox::NoInsert); ++ Chan->addItems(QStringList() << "A" << "B" << "C" << "D"); ++ ++ formLayout2->addRow(new QLabel("Modem Channel"), Chan); ++ ++ wCallTo = new QComboBox(); ++ wCallTo->setEditable(true); ++ wCallTo->setInsertPolicy(QComboBox::NoInsert); ++ ++ formLayout2->addRow(new QLabel("Call To"), wCallTo); ++ ++ Digis = new QLineEdit(); ++ ++ formLayout2->addRow(new QLabel("Digis"), Digis); ++ ++ layout->addSpacing(2); ++ ++ buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); ++ buttonBox->setFont(*menufont); ++ layout->addWidget(buttonBox); ++ ++ scrollAreaWidgetContents->setLayout(layout); ++ scrollArea->setWidget(scrollAreaWidgetContents); ++ ++ wCallTo->addItems(AGWToCalls); ++ ++ Digis->setText(KISSVia); ++ Digis->resize(400, 20); ++ ++ connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); ++ connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); ++} ++ ++extern "C" void * KISSConnectOut(void * Sess, char * CallFrom, char * CallTo, char * Digis, int Chan, void * Socket); ++ ++KISSConnect::~KISSConnect() ++{ ++} ++ ++extern QAction * YAPPSend; ++extern QMenu * connectMenu; ++extern QMenu * disconnectMenu; ++ ++TAX25Port DummyPort; ++extern "C" TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo); ++ ++void KISSConnect::myaccept() ++{ ++ QVariant Q; ++ ++ char CallTo[128];; ++ char Port[3]; ++ ++ strcpy(CallTo, wCallTo->currentText().toUpper().toUtf8()); ++ strcpy(KISSVia, Digis->text().toUpper().toUtf8()); ++ memcpy(Port, Chan->currentText().toUpper().toUtf8(), 1); ++ ++ int PortNo = Port[0] - 'A'; ++ ++ TAX25Port * AX25Sess = 0; ++ ++ // Check for duplicate session ++ ++ AX25Sess = get_user_port_by_calls(0, KISSMYCALL, CallTo); ++ ++ if (AX25Sess) ++ { ++ // Duplicate ++ ++ char Msg[256]; ++ ++ int Len = sprintf(Msg, "You already have a session between %s and %s so can't connect\r", KISSMYCALL, CallTo); ++ ++ WritetoOutputWindow(ActiveSession, (unsigned char *)Msg, Len); ++// KISSConnect::accept(); ++ return; ++ } ++ ++ KISSMode = UIMode->isChecked(); ++ ++ // Add CallTo if not already in list ++ ++ if (AGWToCalls.contains(CallTo)) ++ AGWToCalls.removeOne(CallTo); ++ ++ AGWToCalls.insert(-1, CallTo); ++ ++ ActiveSession->KISSMode = KISSMode; ++ ++ if (KISSMode == 0) ++ { ++ ActiveSession->KISSSession = KISSConnectOut(ActiveSession, KISSMYCALL, CallTo, KISSVia, PortNo, (void *)KISSSock); ++ WritetoOutputWindow(ActiveSession, (unsigned char *)"Connecting...\r", 14); ++ discAction->setEnabled(true); ++ } ++ else ++ { ++ // UI ++ ++ char Msg[128]; ++ int Len = 0; ++ ++ memset(&DummyPort, 0, sizeof(DummyPort)); ++ ++ ActiveSession->KISSSession = (void *)&DummyPort; // Dummy marker to show session in use ++ ++ strcpy(ActiveSession->UIDEST, CallTo); ++ strcpy(ActiveSession->UIPATH, KISSVia); ++ ActiveSession->UIPORT = PortNo; ++ ++ if (TermMode == Tabbed) ++ Len = sprintf(Msg, "UI %s", CallTo); ++ else ++ Len = sprintf(Msg, "UI Session with %s\r", CallTo); ++ ++ SetSessLabel(ActiveSession, Msg); ++ ++ Len = sprintf(Msg, "UI Session with %s\r", CallTo); ++ SendtoTerm(ActiveSession, Msg, Len); ++ connectMenu->setEnabled(false); ++ discAction->setEnabled(true); ++ YAPPSend->setEnabled(false); ++ } ++ ++ KISSConnect::accept(); ++} ++ ++void KISSConnect::myreject() ++{ ++ KISSConnect::reject(); ++} ++ ++ ++ ++VARAConnect::VARAConnect(QWidget *parent) : QDialog(parent) ++{ ++ this->setFont(*menufont); ++ ++ setWindowTitle(tr("VARA Connection")); ++ ++ myResize *resize = new myResize(); ++ installEventFilter(resize); ++ ++ scrollArea = new QScrollArea(this); ++ scrollArea->setObjectName(QString::fromUtf8("scrollArea")); ++ scrollArea->setGeometry(QRect(5, 5, 250, 150)); ++ scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); ++ scrollArea->setWidgetResizable(false); ++ scrollAreaWidgetContents = new QWidget(); ++ scrollAreaWidgetContents->setObjectName(QString::fromUtf8("scrollAreaWidgetContents")); ++ ++ QVBoxLayout *layout = new QVBoxLayout(); ++ layout->setContentsMargins(10, 10, 10, 10); ++ ++ setLayout(layout); ++ ++ QFormLayout *formLayout2 = new QFormLayout(); ++ layout->addLayout(formLayout2); ++ ++ wCallFrom = new QLineEdit(); ++ formLayout2->addRow(new QLabel("Call From"), wCallFrom); ++ ++ wCallTo = new QComboBox(); ++ wCallTo->setEditable(true); ++ wCallTo->setInsertPolicy(QComboBox::NoInsert); ++ ++ formLayout2->addRow(new QLabel("Call To"), wCallTo); ++ ++ Digis = new QLineEdit(); ++ formLayout2->addRow(new QLabel("Digis"), Digis); ++ ++ layout->addSpacing(2); ++ ++ buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); ++ buttonBox->setFont(*menufont); ++ layout->addWidget(buttonBox); ++ ++ scrollAreaWidgetContents->setLayout(layout); ++ scrollArea->setWidget(scrollAreaWidgetContents); ++ ++ wCallFrom->setText(VARATermCall); ++ wCallTo->addItems(AGWToCalls); ++ ++ connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); ++ connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); ++} ++ ++VARAConnect::~VARAConnect() ++{ ++} ++ ++extern myTcpSocket * VARASock; ++extern myTcpSocket * VARADataSock; ++ ++void VARAConnect::myaccept() ++{ ++ QVariant Q; ++ ++ char CallFrom[32]; ++ char CallTo[32]; ++ char Via[128]; ++ char Msg[256]; ++ int Len; ++ ++ strcpy(CallFrom, wCallFrom->text().toUpper().toUtf8()); ++ strcpy(CallTo, wCallTo->currentText().toUpper().toUtf8()); ++ strcpy(Via, Digis->text().toUpper().toUtf8()); ++ ++// if digis have to form block with byte count followed by n 10 byte calls ++ ++ ++// Add CallTo if not already in list ++ ++ if (AGWToCalls.contains(CallTo)) ++ AGWToCalls.removeOne(CallTo); ++ ++ AGWToCalls.insert(-1, CallTo); ++ ++ ++ if (Via[0]) ++ Len = sprintf(Msg, "CONNECT %s %s VIA %s\r", CallFrom, CallTo, Via); ++ else ++ Len = sprintf(Msg, "CONNECT %s %s\r", CallFrom, CallTo); ++ ++ VARASock->write(Msg, Len); ++ ++ discAction->setEnabled(true); ++ VARAConnect::accept(); ++} ++ ++void VARAConnect::myreject() ++{ ++ VARAConnect::reject(); ++} ++ ++ ++extern QProcess *process; ++ ++ ++ ++TabDialog::TabDialog(QWidget *parent) : QDialog(parent) ++{ ++ char portnum[10]; ++ ++ buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel); ++ ++ connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); ++ connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); ++ ++ QVBoxLayout *layout = new QVBoxLayout; ++ QLabel *hostLabel = new QLabel(tr("Host Name:")); ++ hostEdit = new QLineEdit(Host[ConfigHost]); ++ ++ QLabel *portLabel = new QLabel(tr("Port:")); ++ sprintf(portnum, "%d", Port[ConfigHost]); ++ portEdit = new QLineEdit(portnum); ++ ++ QLabel *userLabel = new QLabel(tr("User:")); ++ userEdit = new QLineEdit(UserName[ConfigHost]); ++ ++ QLabel *passLabel = new QLabel(tr("Password:")); ++ passEdit = new QLineEdit(Password[ConfigHost]); ++ ++ QLabel *SNameLabel = new QLabel(tr("Session Name")); ++ SNameEdit = new QLineEdit(SessName[ConfigHost]); ++ ++ layout->addWidget(hostLabel); ++ layout->addWidget(hostEdit); ++ layout->addWidget(portLabel); ++ layout->addWidget(portEdit); ++ layout->addWidget(userLabel); ++ layout->addWidget(userEdit); ++ layout->addWidget(passLabel); ++ layout->addWidget(passEdit); ++ layout->addWidget(SNameLabel); ++ layout->addWidget(SNameEdit); ++ ++ layout->addStretch(1); ++ layout->addWidget(buttonBox); ++ setLayout(layout); ++ ++ setWindowTitle(tr("TermTCP Host Configuration")); ++} ++ ++void AGWDialog::myaccept() ++{ ++ QVariant Q; ++ ++ int OldEnable = AGWEnable; ++ int OldPort = AGWPortNum; ++ char oldHost[128]; ++ strcpy(oldHost, AGWHost); ++ ++ // QString val = Sess->portNo->text();A ++ // QByteArray qb = val.toLatin1(); ++ // char * ptr = qb.data(); ++ ++ AGWEnable = AAGWEnable->isChecked(); ++ AGWMonEnable = AAGWMonEnable->isChecked(); ++ ++ strcpy(AGWTermCall, TermCall->text().toUtf8().toUpper()); ++ strcpy(AGWBeaconDest, beaconDest->text().toUtf8().toUpper()); ++ strcpy(AGWBeaconPath, beaconPath->text().toUtf8().toUpper()); ++ strcpy(AGWBeaconPorts, beaconPorts->text().toUtf8().toUpper()); ++ ++ if (beaconText->toPlainText().length() > 256) ++ { ++ QMessageBox msgBox; ++ msgBox.setText("Beacon Text Too Long"); ++ msgBox.exec(); ++ } ++ else ++ strcpy(AGWBeaconMsg, beaconText->toPlainText().toUtf8().toUpper()); ++ ++ Q = beaconInterval->text(); ++ AGWBeaconInterval = Q.toInt(); ++ ++ strcpy(AGWHost, AHost->text().toUtf8()); ++ ++ Q = APort->text(); ++ AGWPortNum = Q.toInt(); ++ ++ Q = Paclen->text(); ++ AGWPaclen = Q.toInt(); ++ ++ SaveSettings(); ++ ++ if (AGWEnable != OldEnable || AGWPortNum != OldPort || strcmp(oldHost, AGWHost) != 0) ++ { ++ // (re)start connection ++ ++ if (OldEnable && AGWSock && AGWSock->ConnectedState == QAbstractSocket::ConnectedState) ++ { ++ AGWSock->disconnectFromHost(); ++ Status1->setText("AGW Disconnected"); ++ } ++ // AGWTimer will reopen connection ++ } ++ ++ myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable); ++ ++ AGWDialog::accept(); ++ ++} ++ ++void AGWDialog::myreject() ++{ ++ AGWDialog::reject(); ++} ++ ++void TabDialog::myaccept() ++{ ++ QString val = hostEdit->text(); ++ QByteArray qb = val.toLatin1(); ++ char * ptr = qb.data(); ++ strcpy(Host[ConfigHost], ptr); ++ ++ val = portEdit->text(); ++ qb = val.toLatin1(); ++ ptr = qb.data(); ++ Port[ConfigHost] = atoi(ptr); ++ ++ val = userEdit->text(); ++ qb = val.toLatin1(); ++ ptr = qb.data(); ++ strcpy(UserName[ConfigHost], ptr); ++ ++ val = passEdit->text(); ++ qb = val.toLatin1(); ++ ptr = qb.data(); ++ strcpy(Password[ConfigHost], ptr); ++ ++ val = SNameEdit->text(); ++ qb = val.toLatin1(); ++ ptr = qb.data(); ++ strcpy(SessName[ConfigHost], ptr); ++ ++ char Label[256]; ++ ++ if (ptr[0]) ++ sprintf(Label, "%s(%s)", Host[ConfigHost], SessName[ConfigHost]); ++ else ++ strcpy(Label, Host[ConfigHost]); ++ ++ actHost[ConfigHost]->setText(Label); ++ actSetup[ConfigHost]->setText(Label); ++ ++ SaveSettings(); ++ ++ TabDialog::accept(); ++ ++} ++ ++void TabDialog::myreject() ++{ ++ TabDialog::reject(); ++} ++ ++TabDialog::~TabDialog() ++{ ++} ++ ++// Menu dialog ++ ++ ++fontDialog::fontDialog(int Menu, QWidget *parent) : QDialog(parent) ++{ ++ // Menu is set if setting Menufont, zero for setting terminal font. ++ ++ int i; ++ char valChar[16]; ++ ++ QString family; ++ int csize; ++ QFont::Weight weight; ++ ++#ifdef ANDROID ++ this->resize((screenWidth * 7) / 8, 200); ++ this->setMaximumWidth((screenWidth * 7) / 8); ++#endif ++ this->setFont(*menufont); ++ ++ Menuflag = Menu; ++ ++ if (Menu) ++ { ++ workingFont = *menufont; ++ ++ QFontInfo info(*menufont); ++ family = info.family(); ++ csize = info.pointSize(); ++ ++ setWindowTitle("Menu Font Dialog"); ++ } ++ else ++ { ++ // get current term font ++ ++ QSettings settings(GetConfPath(), QSettings::IniFormat); ++ ++#ifdef ANDROID ++ family = settings.value("FontFamily", "Driod Sans Mono").toString(); ++ csize = settings.value("PointSize", 12).toInt(); ++ weight = (QFont::Weight)settings.value("Weight", 50).toInt(); ++#else ++ family = settings.value("FontFamily", "Courier New").toString(); ++ csize = settings.value("PointSize", 10).toInt(); ++ weight = (QFont::Weight)settings.value("Weight", 50).toInt(); ++#endif ++ ++ workingFont = QFont(family); ++ workingFont.setPointSize(csize); ++ workingFont.setWeight(weight); ++ ++ setWindowTitle("Terminal Font Dialog"); ++ } ++ ++ QVBoxLayout *layout = new QVBoxLayout(); ++ layout->setContentsMargins(10, 10, 10, 10); ++ ++ setLayout(layout); ++ ++ QHBoxLayout *hlayout = new QHBoxLayout(); ++ layout->addLayout(hlayout); ++ ++ font = new QFontComboBox(); ++ ++ if (Menu == 0) ++ font->setFontFilters(QFontComboBox::MonospacedFonts); ++ ++ font->setMaximumWidth((screenWidth * 5) / 8); ++ font->view()->setMaximumWidth((7 * screenWidth) / 8); ++ ++ style = new QComboBox(); ++ style->setMaximumWidth(screenWidth / 4); ++ size = new QComboBox(); ++ sample = new QTextEdit(); ++ sample->setText("ABCDabcd1234"); ++ sample->setFont(workingFont); ++ ++ hlayout->addWidget(font); ++ hlayout->addWidget(style); ++ hlayout->addWidget(size); ++ layout->addWidget(sample); ++ ++ QFontDatabase database; ++ ++ const QStringList styles = database.styles(family); ++ ++ const QList smoothSizes = database.smoothSizes(family, styles[0]); ++ ++ for (int points : smoothSizes) ++ size->addItem(QString::number(points)); ++ ++ for (QString xstyle : styles) ++ style->addItem(xstyle); ++ ++ i = font->findText(family, Qt::MatchExactly); ++ font->setCurrentIndex(i); ++ ++ sprintf(valChar, "%d", csize); ++ i = size->findText(valChar, Qt::MatchExactly); ++ size->setCurrentIndex(i); ++ ++ buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); ++ buttonBox->setFont(*menufont); ++ layout->addWidget(buttonBox); ++ setLayout(layout); ++ ++ connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); ++ connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); ++ connect(font, SIGNAL(currentFontChanged(QFont)), this, SLOT(fontchanged(QFont))); ++ connect(style, SIGNAL(currentIndexChanged(int)), this, SLOT(stylechanged())); ++ connect(size, SIGNAL(currentIndexChanged(int)), this, SLOT(sizechanged())); ++} ++ ++void fontDialog::fontchanged(QFont newfont) ++{ ++ QFontDatabase database; ++ QString family = newfont.family(); ++ ++ workingFont = newfont; ++ ++ const QStringList styles = database.styles(family); ++ const QList smoothSizes = database.smoothSizes(family, styles[0]); ++ ++ size->clear(); ++ style->clear(); ++ ++ for (int points : smoothSizes) ++ size->addItem(QString::number(points)); ++ ++ for (QString xstyle : styles) ++ style->addItem(xstyle); ++ ++ sample->setFont(workingFont); ++} ++ ++void fontDialog::stylechanged() ++{ ++ QFontDatabase database; ++ ++ QString family = font->currentFont().family(); ++ ++ bool italic = database.italic(family, style->currentText()); ++ int weight = database.weight(family, style->currentText()); ++ ++ if (weight < 0) ++ weight = 50; // Normal ++ ++ workingFont.setItalic(italic); ++ workingFont.setWeight((QFont::Weight) weight); ++ ++ sample->setFont(workingFont); ++} ++ ++void fontDialog::sizechanged() ++{ ++ int newsize = size->currentText().toInt(); ++ workingFont.setPointSize(newsize); ++ sample->setFont(workingFont); ++} ++fontDialog::~fontDialog() ++{ ++} ++ ++void fontDialog::myaccept() ++{ ++ QSettings settings(GetConfPath(), QSettings::IniFormat); ++ ++ if (Menuflag) ++ { ++ delete menufont; ++ menufont = new QFont(workingFont); ++ ++ QtTermTCP::setFonts(); ++ ++ settings.setValue("MFontFamily", workingFont.family()); ++ settings.setValue("MPointSize", workingFont.pointSize()); ++ settings.setValue("MWeight", workingFont.weight()); ++ } ++ else ++ { ++ Ui_ListenSession * Sess; ++ ++ for (int i = 0; i < _sessions.size(); ++i) ++ { ++ Sess = _sessions.at(i); ++ ++ if (Sess->termWindow) ++ Sess->termWindow->setFont(workingFont); ++ ++ if (Sess->inputWindow) ++ Sess->inputWindow->setFont(workingFont); ++ ++ if (Sess->monWindow) ++ Sess->monWindow->setFont(workingFont); ++ } ++ ++ settings.setValue("FontFamily", workingFont.family()); ++ settings.setValue("PointSize", workingFont.pointSize()); ++ settings.setValue("Weight", workingFont.weight()); ++ } ++ ++ fontDialog::accept(); ++} ++ ++void fontDialog::myreject() ++{ ++ fontDialog::reject(); ++} ++ ++ ++ ++ListenDialog::ListenDialog(QWidget *parent) : QDialog(parent) ++{ ++#ifdef ANDROID ++ this->resize((screenWidth * 3) / 4 , 500); ++#endif ++ verticalLayout = new QVBoxLayout(); ++ verticalLayout->setContentsMargins(10, 10, 10, 10); ++ ++ setLayout(verticalLayout); ++ ++ Enabled = new QCheckBox(); ++ Enabled->setText(QString::fromUtf8("Enable Listen")); ++ Enabled->setLayoutDirection(Qt::LeftToRight); ++ ++ verticalLayout->addWidget(Enabled); ++ ++ formLayout = new QFormLayout(); ++ ++ portNo = new QLineEdit(); ++// portNo->setMaximumSize(QSize(100, 30)); ++ ++ formLayout->addRow(new QLabel("Port"), portNo); ++ ++ CText = new QTextEdit(); ++ CText->setMinimumSize(QSize(0, 150)); ++ CText->setMaximumSize(QSize(401, 150)); ++ ++ formLayout->addRow(new QLabel("CText"), CText); ++ buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this); ++ buttonBox->setFont(*menufont); ++ verticalLayout->addWidget(buttonBox); ++ ++ connect(buttonBox, SIGNAL(accepted()), this, SLOT(myaccept())); ++ connect(buttonBox, SIGNAL(rejected()), this, SLOT(myreject())); ++ ++ verticalLayout->addLayout(formLayout); ++ verticalLayout->addWidget(buttonBox); ++ ++ portNo->setText(QString::number(listenPort)); ++ Enabled->setChecked(listenEnable); ++ CText->setText(listenCText); ++ ++} ++ ++ListenDialog::~ListenDialog() ++{ ++} ++ ++void ListenDialog::myaccept() ++{ ++ QString val = portNo->text(); ++ QByteArray qb = val.toLatin1(); ++ char * ptr = qb.data(); ++ ++ listenPort = atoi(ptr); ++ listenEnable = Enabled->isChecked(); ++ strcpy(listenCText, CText->toPlainText().toUtf8()); ++ ++ while ((ptr = strchr(listenCText, '\n'))) ++ *ptr = '\r'; ++ ++ if (_server->isListening()) ++ _server->close(); ++ ++ SaveSettings(); ++ ++ if (listenEnable) ++ _server->listen(QHostAddress::Any, listenPort); ++ ++ ListenDialog::accept(); ++} ++ ++void ListenDialog::myreject() ++{ ++ ListenDialog::reject(); ++} +--- qttermtcp-0.0.0.79.orig/TabDialog.h ++++ qttermtcp-0.0.0.79/TabDialog.h +@@ -1,209 +1,209 @@ +- +-#ifndef TABDIALOG_H +-#define TABDIALOG_H +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-class QDialogButtonBox; +-class QFileInfo; +-class QTabWidget; +- +-namespace Ui { +-class TabDialog; +-} +- +-class ListenDialog: public QDialog +-{ +- Q_OBJECT +- +-public: +- explicit ListenDialog(QWidget *parent = 0); +- ~ListenDialog(); +- +-private slots: +- void myaccept(); +- void myreject(); +- +-public: +- QVBoxLayout *verticalLayout; +- QFormLayout *formLayout; +- QLineEdit *portNo; +- QTextEdit *CText; +- QVBoxLayout *verticalLayout_2; +- QDialogButtonBox *buttonBox; +- QCheckBox *Enabled; +- +- +-}; +- +- +- +-class TabDialog : public QDialog +-{ +- Q_OBJECT +- +-public: +- explicit TabDialog(QWidget *parent = 0); +- ~TabDialog(); +- +-private slots: +- void myaccept(); +- void myreject(); +- +-private: +- // Ui::TabDialog *ui; +- QDialogButtonBox *buttonBox; +-}; +- +-class AGWDialog : public QDialog +-{ +- Q_OBJECT +- +-public: +- explicit AGWDialog(QWidget *parent = 0); +- ~AGWDialog(); +- +-public: +- QPushButton *okButton; +- QPushButton *cancelButton; +- +-private slots: +- void myaccept(); +- void myreject(); +- +-private: +- // Ui::TabDialog *ui; +- QDialogButtonBox *buttonBox; +-}; +- +-class AGWConnect : public QDialog +-{ +- Q_OBJECT +- +-public: +- explicit AGWConnect(QWidget *parent = 0); +- ~AGWConnect(); +- +-public: +- QLineEdit * wCallFrom; +- QComboBox * wCallTo; +- QLineEdit * Digis; +- QListWidget * RadioPorts; +- +-private slots: +- void myaccept(); +- void myreject(); +- +-private: +- // Ui::TabDialog *ui; +- QDialogButtonBox *buttonBox; +-}; +- +- +- +-class VARAConnect : public QDialog +-{ +- Q_OBJECT +- +-public: +- explicit VARAConnect(QWidget *parent = 0); +- ~VARAConnect(); +- +-public: +- QLineEdit * wCallFrom; +- QComboBox * wCallTo; +- QLineEdit * Digis; +- QListWidget * RadioPorts; +- +-private slots: +- void myaccept(); +- void myreject(); +- +-private: +- // Ui::TabDialog *ui; +- QDialogButtonBox *buttonBox; +-}; +- +- +-class KISSConnect : public QDialog +-{ +- Q_OBJECT +- +-public: +- explicit KISSConnect(QWidget *parent = 0); +- ~KISSConnect(); +- +-public: +- QLineEdit * wCallFrom; +- QComboBox * wCallTo; +- QComboBox * Chan; +- QLineEdit * Digis; +- QLineEdit * UIDest; +- QListWidget * RadioPorts; +- QHBoxLayout *mylayout; +- QRadioButton * Connected; +- QRadioButton * UIMode; +- +-private slots: +- void myaccept(); +- void myreject(); +- +-private: +- // Ui::TabDialog *ui; +- QDialogButtonBox *buttonBox; +-}; +- +- +- +-class fontDialog : public QDialog +-{ +- Q_OBJECT +- +-public: +- explicit fontDialog(int Menu, QWidget *parent = 0); +- ~fontDialog(); +- +-public: +- QFontComboBox *font; +- QComboBox *style; +- QComboBox *size; +- QTextEdit * sample; +- QFont workingFont; +- int workingSize; +- int Menuflag; // Set if menu font +- +-private slots: +- void myaccept(); +- void myreject(); +- void fontchanged(QFont); +- void stylechanged(); +- void sizechanged(); +- +-private: +- +- QDialogButtonBox *buttonBox; +-}; +- +-#endif +- +-class myResize : public QObject +-{ +- Q_OBJECT +- +-protected: +- bool eventFilter(QObject *obj, QEvent *event) override; +-}; +- +- +- +- ++ ++#ifndef TABDIALOG_H ++#define TABDIALOG_H ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++class QDialogButtonBox; ++class QFileInfo; ++class QTabWidget; ++ ++namespace Ui { ++class TabDialog; ++} ++ ++class ListenDialog: public QDialog ++{ ++ Q_OBJECT ++ ++public: ++ explicit ListenDialog(QWidget *parent = 0); ++ ~ListenDialog(); ++ ++private slots: ++ void myaccept(); ++ void myreject(); ++ ++public: ++ QVBoxLayout *verticalLayout; ++ QFormLayout *formLayout; ++ QLineEdit *portNo; ++ QTextEdit *CText; ++ QVBoxLayout *verticalLayout_2; ++ QDialogButtonBox *buttonBox; ++ QCheckBox *Enabled; ++ ++ ++}; ++ ++ ++ ++class TabDialog : public QDialog ++{ ++ Q_OBJECT ++ ++public: ++ explicit TabDialog(QWidget *parent = 0); ++ ~TabDialog(); ++ ++private slots: ++ void myaccept(); ++ void myreject(); ++ ++private: ++ // Ui::TabDialog *ui; ++ QDialogButtonBox *buttonBox; ++}; ++ ++class AGWDialog : public QDialog ++{ ++ Q_OBJECT ++ ++public: ++ explicit AGWDialog(QWidget *parent = 0); ++ ~AGWDialog(); ++ ++public: ++ QPushButton *okButton; ++ QPushButton *cancelButton; ++ ++private slots: ++ void myaccept(); ++ void myreject(); ++ ++private: ++ // Ui::TabDialog *ui; ++ QDialogButtonBox *buttonBox; ++}; ++ ++class AGWConnect : public QDialog ++{ ++ Q_OBJECT ++ ++public: ++ explicit AGWConnect(QWidget *parent = 0); ++ ~AGWConnect(); ++ ++public: ++ QLineEdit * wCallFrom; ++ QComboBox * wCallTo; ++ QLineEdit * Digis; ++ QListWidget * RadioPorts; ++ ++private slots: ++ void myaccept(); ++ void myreject(); ++ ++private: ++ // Ui::TabDialog *ui; ++ QDialogButtonBox *buttonBox; ++}; ++ ++ ++ ++class VARAConnect : public QDialog ++{ ++ Q_OBJECT ++ ++public: ++ explicit VARAConnect(QWidget *parent = 0); ++ ~VARAConnect(); ++ ++public: ++ QLineEdit * wCallFrom; ++ QComboBox * wCallTo; ++ QLineEdit * Digis; ++ QListWidget * RadioPorts; ++ ++private slots: ++ void myaccept(); ++ void myreject(); ++ ++private: ++ // Ui::TabDialog *ui; ++ QDialogButtonBox *buttonBox; ++}; ++ ++ ++class KISSConnect : public QDialog ++{ ++ Q_OBJECT ++ ++public: ++ explicit KISSConnect(QWidget *parent = 0); ++ ~KISSConnect(); ++ ++public: ++ QLineEdit * wCallFrom; ++ QComboBox * wCallTo; ++ QComboBox * Chan; ++ QLineEdit * Digis; ++ QLineEdit * UIDest; ++ QListWidget * RadioPorts; ++ QHBoxLayout *mylayout; ++ QRadioButton * Connected; ++ QRadioButton * UIMode; ++ ++private slots: ++ void myaccept(); ++ void myreject(); ++ ++private: ++ // Ui::TabDialog *ui; ++ QDialogButtonBox *buttonBox; ++}; ++ ++ ++ ++class fontDialog : public QDialog ++{ ++ Q_OBJECT ++ ++public: ++ explicit fontDialog(int Menu, QWidget *parent = 0); ++ ~fontDialog(); ++ ++public: ++ QFontComboBox *font; ++ QComboBox *style; ++ QComboBox *size; ++ QTextEdit * sample; ++ QFont workingFont; ++ int workingSize; ++ int Menuflag; // Set if menu font ++ ++private slots: ++ void myaccept(); ++ void myreject(); ++ void fontchanged(QFont); ++ void stylechanged(); ++ void sizechanged(); ++ ++private: ++ ++ QDialogButtonBox *buttonBox; ++}; ++ ++#endif ++ ++class myResize : public QObject ++{ ++ Q_OBJECT ++ ++protected: ++ bool eventFilter(QObject *obj, QEvent *event) override; ++}; ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/TermTCPCommon.cpp ++++ qttermtcp-0.0.0.79/TermTCPCommon.cpp +@@ -1,1239 +1,1239 @@ +-#include +-#include +-#include +-#include +-#include +- +-#include "QtTermTCP.h" +- +-#define _CRT_SECURE_NO_WARNINGS +- +-#define TRUE 1 +-#define FALSE 0 +-#define UCHAR unsigned char +-#define MAX_PATH 256 +-#define WCHAR char +- +-#ifndef WIN32 +-#define strtok_s strtok_r +-#endif +- +- +-typedef unsigned long DWORD; +-typedef int BOOL; +-typedef unsigned char BYTE; +-typedef unsigned short WORD; +- +-#define MAXHOSTS 16 +- +-#define TCHAR char +- +-void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len); +-int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len); +-void SetPortMonLine(int i, char * Text, int visible, int enabled); +-void AGW_AX25_data_in(void * Sess, UCHAR * data, int Len); +-int checkUTF8(unsigned char * Msg, int Len, unsigned char * out); +-void DoTermResize(Ui_ListenSession * Sess); +-void DecodeTeleText(Ui_ListenSession * Sess, char * page); +- +-int Bells = TRUE; +-int StripLF = FALSE; +-int LogOutput = FALSE; +-int SendDisconnected = TRUE; +-int ChatMode = TRUE; +-int AutoTeletext = 1; +- +-int MonPorts = 1; +-int ListenOn = FALSE; +- +-time_t LastWrite = 0xffffffff; +-int AlertInterval = 300; +-int AlertBeep = TRUE; +-int AlertFreq = 600; +-int AlertDuration = 250; +-TCHAR AlertFileName[256] = { 0 }; +-int ConnectBeep = TRUE; +-int UseKeywords = TRUE; +- +-QString KeyWordsFile = "Keywords.sys"; +- +-char ** KeyWords = NULL; +-int NumberofKeyWords = 0; +- +- +-// YAPP stuff +- +-#define SOH 1 +-#define STX 2 +-#define ETX 3 +-#define EOT 4 +-#define ENQ 5 +-#define ACK 6 +-#define DLE 0x10 +-#define NAK 0x15 +-#define CAN 0x18 +- +-#define YAPPTX 32768 // Sending YAPP file +- +-int MaxRXSize = 100000; +-char BaseDir[256] = ""; +- +-unsigned char InputBuffer[1024]; +- +-char YAPPPath[MAX_PATH] = ""; // Path for saving YAPP Files +- +-int paclen = 128; +- +-int InputLen; // Data we have already = Offset of end of an incomplete packet; +- +-unsigned char * MailBuffer; // Yapp Message being received +-int MailBufferSize; +-int YAPPLen; // Bytes sent/received of YAPP Message +-long YAPPDate; // Date for received file - if set enables YAPPC +-char ARQFilename[200]; // Filename from YAPP Header +- +-unsigned char SavedData[8192]; // Max receive is 4096 is should never get more that 8k +-int SaveLen = 0; +- +-void YAPPSendData(Ui_ListenSession * Sess); +- +- +-char * strlop(char * buf, char delim) +-{ +- // Terminate buf at delim, and return rest of string +- +- char * ptr = strchr(buf, delim); +- +- if (ptr == NULL) return NULL; +- +- *(ptr)++ = 0; +- +- return ptr; +-} +- +-#ifdef WIN32 +- +-char * strcasestr(char *ch1, char *ch2) +-{ +- char *chN1, *chN2; +- char *chNdx; +- char *chRet = NULL; +- +- chN1 = _strdup(ch1); +- chN2 = _strdup(ch2); +- +- if (chN1 && chN2) +- { +- chNdx = chN1; +- while (*chNdx) +- { +- *chNdx = (char)tolower(*chNdx); +- chNdx++; +- } +- chNdx = chN2; +- +- while (*chNdx) +- { +- *chNdx = (char)tolower(*chNdx); +- chNdx++; +- } +- +- chNdx = strstr(chN1, chN2); +- +- if (chNdx) +- chRet = ch1 + (chNdx - chN1); +- } +- +- free(chN1); +- free(chN2); +- return chRet; +-} +- +-#endif +- +-void GetKeyWordFile() +-{ +- DWORD FileSize; +- char * ptr1, *ptr2; +- char * KeyWordFile; +- +- QFile file(KeyWordsFile); +- +- if (!file.open(QIODevice::ReadOnly)) +- { +- if (UseKeywords) // Don't need to alert if not being used +- { +- QMessageBox msgBox; +- msgBox.setText("Keyword File " + KeyWordsFile + " not found"); +- msgBox.exec(); +- } +- return; +- } +- +- FileSize = file.size(); +- +- KeyWordFile = (char *)malloc(FileSize + 1); +- +- file.read(KeyWordFile, FileSize); +- +- file.close(); +- +- KeyWordFile[FileSize] = 0; +- +- ptr1 = KeyWordFile; +- +- while (ptr1) +- { +- if (*ptr1 == '\n') ptr1++; +- +- ptr2 = strtok_s(NULL, "\r\n", &ptr1); +- if (ptr2) +- { +- if (*ptr2 != '#') +- { +- KeyWords = (char **)realloc(KeyWords, (++NumberofKeyWords + 1) * 4); +- KeyWords[NumberofKeyWords] = ptr2; +- } +- } +- else +- break; +- } +-} +- +- +-int CheckKeyWord(char * Word, char * Msg) +-{ +- char * ptr1 = Msg, *ptr2; +- int len = (int)strlen(Word); +- +- while (*ptr1) // Stop at end +- { +- ptr2 = strcasestr(ptr1, Word); +- +- if (ptr2 == NULL) +- return FALSE; // OK +- +- // Only bad if it ia not part of a longer word +- +- if ((ptr2 == Msg) || !(isalpha(*(ptr2 - 1)))) // No alpha before +- if (!(isalpha(*(ptr2 + len)))) // No alpha after +- return TRUE; // Bad word +- +- // Keep searching +- +- ptr1 = ptr2 + len; +- } +- +- return FALSE; // OK +-} +- +-int CheckKeyWords(UCHAR * Msg, int len) +-{ +- int i; +- +- if (UseKeywords == 0 || NumberofKeyWords == 0) +- return FALSE; +- +- // we need to null terminate Msg, so create a copy +- +- unsigned char * copy = (unsigned char *)malloc(len + 1); +- +- memcpy(copy, Msg, len); +- copy[len] = 0; +- +- for (i = 1; i <= NumberofKeyWords; i++) +- { +- if (CheckKeyWord(KeyWords[i], (char *)copy)) +- { +- myBeep(&AlertWAV); +- free (copy); +- return TRUE; // Alert +- } +- } +- +- free(copy); +- return FALSE; // OK +- +-} +- +- +-void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len) +-{ +- int MonLen = 0; +- unsigned char * ptr; +- unsigned char * Buffptr; +- unsigned char * FEptr = 0; +- +- if (Sess->InputMode == 'Y') // Yapp +- { +- ProcessYAPPMessage(Sess, Buffer, len); +- return; +- } +- +- // See if Teletext data +- +- // We need to identify a viewdata frame. Seems to start +- +- //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........ +- //00000170 0a 0a 0a 0a 0a 0a 0a 0a 11 0c 1b +- +- // Page seems to start 1c +- +- // After page get +- +- //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........ +- // 0000049D 0a 0a 0a 0a 0a 0a 0a 0a 11 14 1b 44 1b 5d 1b 43 ........ ...D.].C +- // 000004AD 53 65 6c 65 Sele +- // 000004B1 63 74 20 69 74 65 6d 20 6f 72 1b 47 2a 70 61 67 ct item or .G*pag +- // 000004C1 65 5f 20 3a 20 20 20 20 20 20 20 20 20 20 20 20 e_ : +- // 000004D1 20 0d 09 09 09 09 09 09 09 09 09 09 09 09 09 09 ....... ........ +- // 000004E1 09 09 09 09 09 09 09 09 09 09 09 09 09 11 +- +- Buffer[len] = 0; +- +- if (AutoTeletext && (Buffer[0] == 0x1e || Buffer[0] == 0x0c)) +- { +- if (Sess->TTActive == 0) +- { +- Sess->TTActive = 1; +- DoTermResize(Sess); +- } +- } +- +- if (Sess->TTActive) +- { +- // Feed to Teletext code +- +- // We need to decode a whole page. There is no obvious delimiter so process till data stops. +- // Buffer is cleared when next input is sent +- +- if (strlen(&Sess->pageBuffer[0] + len) > 4090) +- Sess->pageBuffer[0] = 0; // Protect buffer +- +- strcat(Sess->pageBuffer, (char *)Buffer); +- +- DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end +- return; +- } +- +- +- +- // mbstowcs(Buffer, BufferB, len); +- +- // Look for MON delimiters (FF/FE) +- +- +- Buffptr = Buffer; +- +- if (Sess->MonData) +- { +- // Already in MON State +- +- FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len); +- +- if (!FEptr) +- { +- // no FE - so send all to monitor +- +- WritetoMonWindow(Sess, Buffer, len); +- return; +- } +- +- Sess->MonData = FALSE; +- +- MonLen = FEptr - Buffptr; // Mon Data, Excluding the FE +- +- WritetoMonWindow(Sess, Buffptr, MonLen); +- +- Buffptr = ++FEptr; // Char following FE +- +- if (++MonLen < len) +- { +- len -= MonLen; +- goto MonLoop; // See if next in MON or Data +- } +- +- // Nothing Left +- +- return; +- } +- +-MonLoop: +- +- ptr = (UCHAR *)memchr(Buffptr, 0xff, len); +- +- if (ptr) +- { +- unsigned char telcmd[] = "\xff\xfb\x03\xff\xfb\x01"; +- +- // Try to trap connect to normal Telnet Port +- +- if (memcmp(ptr, telcmd, 6) == 0) +- return; +- +- // Buffer contains Mon Data +- +- if (ptr > Buffptr) +- { +- // Some Normal Data before the FF +- +- int NormLen = ptr - Buffptr; // Before the FF +- +- if (NormLen == 1 && Buffptr[0] == 0) +- { +- // Keepalive +- } +- +- else +- { +- CheckKeyWords(Buffptr, NormLen); +- WritetoOutputWindow(Sess, Buffptr, NormLen); +- } +- +- len -= NormLen; +- Buffptr = ptr; +- goto MonLoop; +- } +- +- if (ptr[1] == 0xff) +- { +- // Port Definition String +- +- int NumberofPorts = atoi((char *)&ptr[2]); +- char *p, *Context; +- int i = 1; +- TCHAR msg[80]; +- int portnum; +- char delim[] = "|"; +- int m; +- +- // Save for changes of Window +- +- if (len < 2048) +- memcpy(Sess->PortMonString, ptr, len); +- +- +- // Remove old menu +- +- for (i = 0; i < 65; i++) +- { +- SetPortMonLine(i, (char *)"", 0, 0); +- } +- +- p = strtok_s((char *)&ptr[2], delim, &Context); +- +- while (NumberofPorts--) +- { +- p = strtok_s(NULL, delim, &Context); +- if (p == NULL) +- break; +- +- m = portnum = atoi(p); +- sprintf(msg, "Port %s", p); +- +- if (m == 0) +- m = 64; +- +- if (Sess->portmask & (1ll << (m - 1))) +- SetPortMonLine(portnum, msg, 1, 1); +- else +- SetPortMonLine(portnum, msg, 1, 0); +- } +- return; +- } +- +- MonLen = len; // in case no fe +- +- Sess->MonData = 1; +- +- FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len); +- +- if (FEptr) +- { +- Sess->MonData = 0; +- +- MonLen = FEptr + 1 - Buffptr; // MonLen includes FF and FE +- +- WritetoMonWindow(Sess, Buffptr + 1, MonLen - 2); +- +- len -= MonLen; +- Buffptr += MonLen; // Char Following FE +- +- if (len <= 0) +- { +- return; +- } +- goto MonLoop; +- } +- else +- { +- // No FE, so rest of buffer is MON Data +- +- if (MonLen) +- WritetoMonWindow(Sess, Buffptr + 1, MonLen - 1); +- return; +- } +- } +- +- // No FF, so must be session data +- +- if (Sess->InputMode == 'Y') // Yapp +- { +- ProcessYAPPMessage(Sess, Buffer, len); +- return; +- } +- +- +- if (len == 1 && Buffptr[0] == 0) +- return; // Keepalive +- +- // Could be a YAPP Header +- +- if (len == 2 && Buffptr[0] == ENQ && Buffptr[1] == 1) // YAPP Send_Init +- { +- char YAPPRR[2]; +- +- // Turn off monitoring +- +- setTraceOff(Sess); +- +- Sess->InputMode = 'Y'; +- +- YAPPRR[0] = ACK; +- YAPPRR[1] = 1; +- +- SocketFlush(Sess); // To give Monitor Msg time to be sent +- mySleep(1000); +- QueueMsg(Sess, YAPPRR, 2); +- +- return; +- } +- // Check UTF8 +- { +- CheckKeyWords(Buffptr, len); +- WritetoOutputWindow(Sess, Buffptr, len); +- } +- Sess->SlowTimer = 0; +- return; +-} +- +-extern myTcpSocket * VARASock; +-extern myTcpSocket * VARADataSock; +-extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len); +- +-int SendMsg(Ui_ListenSession * Sess, TCHAR * Buffer, int len) +-{ +- if (Sess->KISSSession) +- { +- // Send to ax.25 code +- +- SendtoAX25(Sess->KISSSession, (unsigned char *)Buffer, len); +- return len; +- } +- else if (Sess->AGWSession) +- { +- // Terminal is in AGWPE mode - send as AGW frame +- +- AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Buffer, len); +- return len; +- } +- else if (VARASock && VARASock->Sess == Sess) +- { +- VARADataSock->write(Buffer, len); +- return len; +- } +- +- return SocketSend(Sess, Buffer, len); +-} +- +- +- +-void QueueMsg(Ui_ListenSession * Sess, char * Msg, int len) +-{ +- int Sent = SendMsg(Sess, Msg, len); +- +- if (Sent != len) +- Sent = 0; +-} +- +-int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len); +- +-int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len) +-{ +- // may have saved data +- +- memcpy(&SavedData[SaveLen], Msg, Len); +- +- SaveLen += Len; +- +- while (SaveLen && Sess->InputMode == 'Y') +- { +- int Used = InnerProcessYAPPMessage(Sess, SavedData, SaveLen); +- +- if (Used == 0) +- return 0; // Waiting for more +- +- SaveLen -= Used; +- +- if (SaveLen) +- memmove(SavedData, &SavedData[Used], SaveLen); +- } +- return 0; +-} +- +-extern int VARAEnable; +- +-int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len) +-{ +- int pktLen = Msg[1]; +- char Reply[2] = { ACK }; +- size_t NameLen, SizeLen, OptLen; +- char * ptr; +- int FileSize; +- WCHAR MsgFile[MAX_PATH]; +- FILE * hFile; +- char Mess[255]; +- int len; +- UCHAR Buffer[2000]; +- struct stat STAT; +- +- switch (Msg[0]) +- { +- case ENQ: // YAPP Send_Init +- +- // Shouldn't occur in session. Reset state and process +- +- if (MailBuffer) +- { +- free(MailBuffer); +- MailBufferSize = 0; +- MailBuffer = 0; +- } +- +- Mess[0] = ACK; +- Mess[1] = 1; +- +- Sess->InputMode = 'Y'; +- QueueMsg(Sess, Mess, 2); +- +- // Turn off monitoring +- +- mySleep(1000); // To give YAPP Msg time to be sent +- +- setTraceOff(Sess); +- +- return Len; +- +- case SOH: +- +- // HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt) +- +- // YAPPC has date/time in dos format +- +- if (Len < Msg[1] + 1) +- return 0; // Wait till we have it all +- +- NameLen = strlen((char *)&Msg[2]); +- strcpy(ARQFilename, (char *)&Msg[2]); +- +- ptr = (char *)&Msg[3 + NameLen]; +- SizeLen = strlen(ptr); +- FileSize = atoi(ptr); +- +- OptLen = pktLen - (NameLen + SizeLen + 2); +- +- YAPPDate = 0; +- +- if (OptLen >= 8) // We have a Date/Time for YAPPC +- { +- ptr = ptr + SizeLen + 1; +- YAPPDate = strtol(ptr, NULL, 16); +- } +- +- // Check Size +- +- if (FileSize > MaxRXSize && VARAEnable == 0) +- { +- Mess[0] = NAK; +- Mess[1] = sprintf(&Mess[2], "File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize); +- mySleep(1000); // To give YAPP Msg time to be sent +- QueueMsg(Sess, Mess, Mess[1] + 2); +- +- len = sprintf((char *)Buffer, "YAPP File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize); +- WritetoOutputWindow(Sess, Buffer, len); +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- +- return Len; +- } +- +- // Check that Path is set +- +- if (YAPPPath[0] == 0) +- { +- Mess[0] = NAK; +- Mess[1] = sprintf(&Mess[2], "%s", "YAPP Receive directory not set"); +- mySleep(1000); // To give YAPP Msg time to be sent +- QueueMsg(Sess, Mess, Mess[1] + 2); +- len = sprintf((char *)Buffer, "YAPP File Receive Failed - YAPP Receive directory not set\r"); +- WritetoOutputWindow(Sess, Buffer, len); +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- +- return Len; +- } +- +- // Make sure file does not exist +- +- sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename); +- +- if (stat(MsgFile, &STAT) == 0) +- { +- FileSize = STAT.st_size; +- +- Mess[0] = NAK; +- Mess[1] = sprintf(&Mess[2], "%s", "File Already Exists"); +- mySleep(1000); // To give YAPP Msg time to be sent +- QueueMsg(Sess, Mess, Mess[1] + 2); +- len = sprintf((char *)Buffer, "YAPP File Receive Failed - %s already exists\r", MsgFile); +- WritetoOutputWindow(Sess, Buffer, len); +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- +- return Len; +- } +- +- +- MailBufferSize = FileSize; +- MailBuffer = (UCHAR *)malloc(FileSize); +- YAPPLen = 0; +- +- if (YAPPDate) // If present use YAPPC +- Reply[1] = ACK; //Receive_TPK +- else +- Reply[1] = 2; //Rcv_File +- +- QueueMsg(Sess, Reply, 2); +- +- len = sprintf((char *)Buffer, "YAPP Receving File %s size %d\r", ARQFilename, FileSize); +- WritetoOutputWindow(Sess, Buffer, len); +- +- return Len; +- +- case STX: +- +- // Data Packet +- +- // Check we have it all +- +- if (YAPPDate) // If present use YAPPC so have checksum +- { +- if (pktLen > (Len - 3)) // -2 for header and checksum +- return 0; // Wait for rest +- } +- else +- { +- if (pktLen > (Len - 2)) // -2 for header +- return 0; // Wait for rest +- } +- +- // Save data and remove from buffer +- +- // if YAPPC check checksum +- +- if (YAPPDate) +- { +- UCHAR Sum = 0; +- int i; +- UCHAR * uptr = &Msg[2]; +- +- i = pktLen; +- +- while (i--) +- Sum += *(uptr++); +- +- if (Sum != *uptr) +- { +- // Checksum Error +- +- Mess[0] = CAN; +- Mess[1] = sprintf(&Mess[2], "YAPPC Checksum Error"); +- QueueMsg(Sess, Mess, Mess[1] + 2); +- +- len = sprintf((char *)Buffer, "YAPPC Checksum Error on file %s\r", MsgFile); +- WritetoOutputWindow(Sess, Buffer, len); +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- return Len; +- } +- } +- +- if ((YAPPLen) + pktLen > MailBufferSize) +- { +- // Too Big ?? +- +- Mess[0] = CAN; +- Mess[1] = sprintf(&Mess[2], "YAPP Too much data received"); +- QueueMsg(Sess, Mess, Mess[1] + 2); +- +- len = sprintf((char *)Buffer, "YAPP Too much data received on file %s\r", MsgFile); +- WritetoOutputWindow(Sess, Buffer, len); +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- return Len; +- } +- +- +- memcpy(&MailBuffer[YAPPLen], &Msg[2], pktLen); +- YAPPLen += pktLen; +- +- if (YAPPDate) +- ++pktLen; // Add Checksum +- +-// if (YAPPLen == MailBufferSize) +-// pktLen = pktLen; +- +- return pktLen + 2; +- +- case ETX: +- +- // End Data +- +- if (YAPPLen == MailBufferSize) +- { +- // All received +- +- int Written = 0; +- +- sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename); +- +- hFile = fopen(MsgFile, "wb"); +- +- if (hFile) +- { +- Written = (int)fwrite(MailBuffer, 1, YAPPLen, hFile); +- fclose(hFile); +- +- if (YAPPDate) +- { +-// struct tm TM; +-// struct timeval times[2]; +- /* +- The MS-DOS date. The date is a packed value with the following format. +- +- cant use DosDateTimeToFileTime on Linux +- +- Bits Description +- 0-4 Day of the month (1–31) +- 5-8 Month (1 = January, 2 = February, and so on) +- 9-15 Year offset from 1980 (add 1980 to get actual year) +- wFatTime +- The MS-DOS time. The time is a packed value with the following format. +- Bits Description +- 0-4 Second divided by 2 +- 5-10 Minute (0–59) +- 11-15 Hour (0–23 on a 24-hour clock) +- */ +- /* +- +- memset(&TM, 0, sizeof(TM)); +- +- TM.tm_sec = (YAPPDate & 0x1f) << 1; +- TM.tm_min = ((YAPPDate >> 5) & 0x3f); +- TM.tm_hour = ((YAPPDate >> 11) & 0x1f); +- +- TM.tm_mday = ((YAPPDate >> 16) & 0x1f); +- TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1; +- TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80; +- +- Debugprintf("%d %d %d %d %d %d", TM.tm_year, TM.tm_mon, TM.tm_mday, TM.tm_hour, TM.tm_min, TM.tm_sec); +- +- times[0].tv_sec = times[1].tv_sec = mktime(&TM); +- times[0].tv_usec = times[1].tv_usec = 0; +- */ +- } +- } +- +- +- free(MailBuffer); +- MailBufferSize = 0; +- MailBuffer = 0; +- +- if (Written != YAPPLen) +- { +- Mess[0] = CAN; +- Mess[1] = sprintf(&Mess[2], "Failed to save YAPP File"); +- QueueMsg(Sess, Mess, Mess[1] + 2); +- +- len = sprintf((char *)Buffer, "Failed to save YAPP File %s\r", MsgFile); +- WritetoOutputWindow(Sess, Buffer, len); +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- } +- } +- +- Reply[1] = 3; //Ack_EOF +- QueueMsg(Sess, Reply, 2); +- +- len = sprintf((char *)Buffer, "Reception of file %s complete\r", MsgFile); +- WritetoOutputWindow(Sess, Buffer, len); +- +- return Len; +- +- case EOT: +- +- // End Session +- +- Reply[1] = 4; // Ack_EOT +- QueueMsg(Sess, Reply, 2); +- SocketFlush(Sess); +- Sess->InputMode = 0; +- +- SendTraceOptions(Sess); +- return Len; +- +- case CAN: +- +- // Abort +- +- Mess[0] = ACK; +- Mess[1] = 5; // CAN Ack +- QueueMsg(Sess, Mess, 2); +- +- if (MailBuffer) +- { +- free(MailBuffer); +- MailBufferSize = 0; +- MailBuffer = 0; +- } +- +- // May have an error message +- +- len = Msg[1]; +- +- if (len) +- { +- len = sprintf((char *)Buffer, "YAPP Transfer cancelled - %s\r", &Msg[2]); +- } +- else +- len = sprintf(Mess, "YAPP Transfer cancelled\r"); +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- +- return Len; +- +- case ACK: +- +- switch (Msg[1]) +- { +- char * ptr; +- +- case 1: // Rcv_Rdy +- +- // HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt) +- +- // Remote only needs filename so remove path +- +- ptr = ARQFilename; +- +- while (strchr(ptr, '/')) +- ptr = strchr(ptr, '/') + 1; +- +- len = (int)strlen(ptr) + 3; +- +- strcpy(&Mess[2], ptr); +- len += sprintf(&Mess[len], "%d", MailBufferSize); +- len++; // include null +-// len += sprintf(&Mess[len], "%8X", YAPPDate); +-// len++; // include null +- Mess[0] = SOH; +- Mess[1] = len - 2; +- +- QueueMsg(Sess, Mess, len); +- +- return Len; +- +- case 2: +- +- YAPPDate = 0; // Switch to Normal (No Checksum) Mode +- +- // Drop through +- +- case 6: // Send using YAPPC +- +- // Start sending message +- +- YAPPSendData(Sess); +- return Len; +- +- case 3: +- +- // ACK EOF - Send EOT +- +- Mess[0] = EOT; +- Mess[1] = 1; +- QueueMsg(Sess, Mess, 2); +- +- return Len; +- +- case 4: +- +- // ACK EOT +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- +- len = sprintf((char *)Buffer, "File transfer complete\r"); +- WritetoOutputWindow(Sess, Buffer, len); +- +- +- return Len; +- +- default: +- return Len; +- +- } +- +- case NAK: +- +- // Either Reject or Restart +- +- // RE Resume NAK len R NULL (File size in ASCII) NULL +- +- if (Len > 2 && Msg[2] == 'R' && Msg[3] == 0) +- { +- int posn = atoi((char *)&Msg[4]); +- +- YAPPLen += posn; +- MailBufferSize -= posn; +- +- YAPPSendData(Sess); +- return Len; +- +- } +- +- // May have an error message +- +- len = Msg[1]; +- +- if (len) +- { +- char ws[256]; +- +- Msg[len + 2] = 0; +- +- strcpy(ws, (char *)&Msg[2]); +- +- len = sprintf((char *)Buffer, "File rejected - %s\r", ws); +- } +- else +- len = sprintf((char *)Buffer, "File rejected\r"); +- +- WritetoOutputWindow(Sess, Buffer, len); +- +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- +- return Len; +- +- } +- +- len = sprintf((char *)Buffer, "Unexpected message during YAPP Transfer. Transfer cancelled\r"); +- WritetoOutputWindow(Sess, Buffer, len); +- +- Sess->InputMode = 0; +- SendTraceOptions(Sess); +- +- return Len; +- +-} +- +-void YAPPSendFile(Ui_ListenSession * Sess, WCHAR * FN) +-{ +- int FileSize = 0; +- char MsgFile[MAX_PATH]; +- FILE * hFile; +- struct stat STAT; +- UCHAR Buffer[2000]; +- int Len; +- +- strcpy(MsgFile, FN); +- +- if (MsgFile[0] == 0) +- { +- Len = sprintf((char *)Buffer, "Filename missing\r"); +- WritetoOutputWindow(Sess, Buffer, Len); +- +- SendTraceOptions(Sess); +- +- return; +- } +- +- if (stat(MsgFile, &STAT) != -1) +- { +- FileSize = STAT.st_size; +- +- hFile = fopen(MsgFile, "rb"); +- +- if (hFile) +- { +- char Mess[255]; +-// time_t UnixTime = STAT.st_mtime; +- +-// FILETIME ft; +-// long long ll; +-// SYSTEMTIME st; +-// WORD FatDate; +-// WORD FatTime; +-// struct tm TM; +- +- strcpy(ARQFilename, MsgFile); +- +- if (MailBuffer) +- { +- free(MailBuffer); +- MailBufferSize = 0; +- MailBuffer = 0; +- } +- +- MailBuffer = (UCHAR *)malloc(FileSize); +- MailBufferSize = FileSize; +- YAPPLen = 0; +- fread(MailBuffer, 1, FileSize, hFile); +- +- // Get Date and Time for YAPPC Mode +- +-/* The MS-DOS date. The date is a packed value with the following format. +- +- cant use DosDateTimeToFileTime on Linux +- +- Bits Description +- 0-4 Day of the month (1–31) +- 5-8 Month (1 = January, 2 = February, and so on) +- 9-15 Year offset from 1980 (add 1980 to get actual year) +- wFatTime +- The MS-DOS time. The time is a packed value with the following format. +- Bits Description +- 0-4 Second divided by 2 +- 5-10 Minute (0–59) +- 11-15 Hour (0–23 on a 24-hour clock) +- +- memset(&TM, 0, sizeof(TM)); +- +- TM.tm_sec = (YAPPDate & 0x1f) << 1; +- TM.tm_min = ((YAPPDate >> 5) & 0x3f); +- TM.tm_hour = ((YAPPDate >> 11) & 0x1f); +- +- TM.tm_mday = ((YAPPDate >> 16) & 0x1f); +- TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1; +- TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80; +- +- +-// Note that LONGLONG is a 64-bit value +- +- ll = Int32x32To64(UnixTime, 10000000) + 116444736000000000; +- ft.dwLowDateTime = (DWORD)ll; +- ll >>= 32; +- ft.dwHighDateTime = (DWORD)ll; +- +- FileTimeToSystemTime(&ft, &st); +- FileTimeToDosDateTime(&ft, &FatDate, &FatTime); +- +- YAPPDate = (FatDate << 16) + FatTime; +- +- memset(&TM, 0, sizeof(TM)); +- +- TM.tm_sec = (YAPPDate & 0x1f) << 1; +- TM.tm_min = ((YAPPDate >> 5) & 0x3f); +- TM.tm_hour = ((YAPPDate >> 11) & 0x1f); +- +- TM.tm_mday = ((YAPPDate >> 16) & 0x1f); +- TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1; +- TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80; +-*/ +- fclose(hFile); +- +- Mess[0] = ENQ; +- Mess[1] = 1; +- +- QueueMsg(Sess, Mess, 2); +- Sess->InputMode = 'Y'; +- +- Len = sprintf((char *)Buffer, "Sending File %s ...\r", FN); +- WritetoOutputWindow(Sess, Buffer, Len); +- +- return; +- } +- } +- +- Len = sprintf((char *)Buffer, "File %s not found\r", FN); +- WritetoOutputWindow(Sess, Buffer, Len); +- +-} +- +-void YAPPSendData(Ui_ListenSession * Sess) +-{ +- char Mess[258]; +- +- while (1) +- { +- int Left = MailBufferSize; +- +- if (Left == 0) +- { +- // Finished - send End Data +- +- Mess[0] = ETX; +- Mess[1] = 1; +- +- QueueMsg(Sess, Mess, 2); +- +- break; +- } +- +- if (Left > paclen - 3) // two bytes header and possible checksum +- Left = paclen - 3; +- +- memcpy(&Mess[2], &MailBuffer[YAPPLen], Left); +- +- YAPPLen += Left; +- MailBufferSize -= Left; +- +- // if YAPPC add checksum +- +- if (YAPPDate) +- { +- UCHAR Sum = 0; +- int i; +- UCHAR * uptr = (UCHAR *)&Mess[2]; +- +- i = Left; +- +- while (i--) +- Sum += *(uptr++); +- +- *(uptr) = Sum; +- +- Mess[0] = STX; +- Mess[1] = Left; +- +- QueueMsg(Sess, Mess, Left + 3); +- } +- else +- { +- Mess[0] = STX; +- Mess[1] = Left; +- +- QueueMsg(Sess, Mess, Left + 2); +- } +- } +-} +- ++#include ++#include ++#include ++#include ++#include ++ ++#include "QtTermTCP.h" ++ ++#define _CRT_SECURE_NO_WARNINGS ++ ++#define TRUE 1 ++#define FALSE 0 ++#define UCHAR unsigned char ++#define MAX_PATH 256 ++#define WCHAR char ++ ++#ifndef WIN32 ++#define strtok_s strtok_r ++#endif ++ ++ ++typedef unsigned long DWORD; ++typedef int BOOL; ++typedef unsigned char BYTE; ++typedef unsigned short WORD; ++ ++#define MAXHOSTS 16 ++ ++#define TCHAR char ++ ++void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len); ++int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len); ++void SetPortMonLine(int i, char * Text, int visible, int enabled); ++void AGW_AX25_data_in(void * Sess, UCHAR * data, int Len); ++int checkUTF8(unsigned char * Msg, int Len, unsigned char * out); ++void DoTermResize(Ui_ListenSession * Sess); ++void DecodeTeleText(Ui_ListenSession * Sess, char * page); ++ ++int Bells = TRUE; ++int StripLF = FALSE; ++int LogOutput = FALSE; ++int SendDisconnected = TRUE; ++int ChatMode = TRUE; ++int AutoTeletext = 1; ++ ++int MonPorts = 1; ++int ListenOn = FALSE; ++ ++time_t LastWrite = 0xffffffff; ++int AlertInterval = 300; ++int AlertBeep = TRUE; ++int AlertFreq = 600; ++int AlertDuration = 250; ++TCHAR AlertFileName[256] = { 0 }; ++int ConnectBeep = TRUE; ++int UseKeywords = TRUE; ++ ++QString KeyWordsFile = "Keywords.sys"; ++ ++char ** KeyWords = NULL; ++int NumberofKeyWords = 0; ++ ++ ++// YAPP stuff ++ ++#define SOH 1 ++#define STX 2 ++#define ETX 3 ++#define EOT 4 ++#define ENQ 5 ++#define ACK 6 ++#define DLE 0x10 ++#define NAK 0x15 ++#define CAN 0x18 ++ ++#define YAPPTX 32768 // Sending YAPP file ++ ++int MaxRXSize = 100000; ++char BaseDir[256] = ""; ++ ++unsigned char InputBuffer[1024]; ++ ++char YAPPPath[MAX_PATH] = ""; // Path for saving YAPP Files ++ ++int paclen = 128; ++ ++int InputLen; // Data we have already = Offset of end of an incomplete packet; ++ ++unsigned char * MailBuffer; // Yapp Message being received ++int MailBufferSize; ++int YAPPLen; // Bytes sent/received of YAPP Message ++long YAPPDate; // Date for received file - if set enables YAPPC ++char ARQFilename[200]; // Filename from YAPP Header ++ ++unsigned char SavedData[8192]; // Max receive is 4096 is should never get more that 8k ++int SaveLen = 0; ++ ++void YAPPSendData(Ui_ListenSession * Sess); ++ ++ ++char * strlop(char * buf, char delim) ++{ ++ // Terminate buf at delim, and return rest of string ++ ++ char * ptr = strchr(buf, delim); ++ ++ if (ptr == NULL) return NULL; ++ ++ *(ptr)++ = 0; ++ ++ return ptr; ++} ++ ++#ifdef WIN32 ++ ++char * strcasestr(char *ch1, char *ch2) ++{ ++ char *chN1, *chN2; ++ char *chNdx; ++ char *chRet = NULL; ++ ++ chN1 = _strdup(ch1); ++ chN2 = _strdup(ch2); ++ ++ if (chN1 && chN2) ++ { ++ chNdx = chN1; ++ while (*chNdx) ++ { ++ *chNdx = (char)tolower(*chNdx); ++ chNdx++; ++ } ++ chNdx = chN2; ++ ++ while (*chNdx) ++ { ++ *chNdx = (char)tolower(*chNdx); ++ chNdx++; ++ } ++ ++ chNdx = strstr(chN1, chN2); ++ ++ if (chNdx) ++ chRet = ch1 + (chNdx - chN1); ++ } ++ ++ free(chN1); ++ free(chN2); ++ return chRet; ++} ++ ++#endif ++ ++void GetKeyWordFile() ++{ ++ DWORD FileSize; ++ char * ptr1, *ptr2; ++ char * KeyWordFile; ++ ++ QFile file(KeyWordsFile); ++ ++ if (!file.open(QIODevice::ReadOnly)) ++ { ++ if (UseKeywords) // Don't need to alert if not being used ++ { ++ QMessageBox msgBox; ++ msgBox.setText("Keyword File " + KeyWordsFile + " not found"); ++ msgBox.exec(); ++ } ++ return; ++ } ++ ++ FileSize = file.size(); ++ ++ KeyWordFile = (char *)malloc(FileSize + 1); ++ ++ file.read(KeyWordFile, FileSize); ++ ++ file.close(); ++ ++ KeyWordFile[FileSize] = 0; ++ ++ ptr1 = KeyWordFile; ++ ++ while (ptr1) ++ { ++ if (*ptr1 == '\n') ptr1++; ++ ++ ptr2 = strtok_s(NULL, "\r\n", &ptr1); ++ if (ptr2) ++ { ++ if (*ptr2 != '#') ++ { ++ KeyWords = (char **)realloc(KeyWords, (++NumberofKeyWords + 1) * 4); ++ KeyWords[NumberofKeyWords] = ptr2; ++ } ++ } ++ else ++ break; ++ } ++} ++ ++ ++int CheckKeyWord(char * Word, char * Msg) ++{ ++ char * ptr1 = Msg, *ptr2; ++ int len = (int)strlen(Word); ++ ++ while (*ptr1) // Stop at end ++ { ++ ptr2 = strcasestr(ptr1, Word); ++ ++ if (ptr2 == NULL) ++ return FALSE; // OK ++ ++ // Only bad if it ia not part of a longer word ++ ++ if ((ptr2 == Msg) || !(isalpha(*(ptr2 - 1)))) // No alpha before ++ if (!(isalpha(*(ptr2 + len)))) // No alpha after ++ return TRUE; // Bad word ++ ++ // Keep searching ++ ++ ptr1 = ptr2 + len; ++ } ++ ++ return FALSE; // OK ++} ++ ++int CheckKeyWords(UCHAR * Msg, int len) ++{ ++ int i; ++ ++ if (UseKeywords == 0 || NumberofKeyWords == 0) ++ return FALSE; ++ ++ // we need to null terminate Msg, so create a copy ++ ++ unsigned char * copy = (unsigned char *)malloc(len + 1); ++ ++ memcpy(copy, Msg, len); ++ copy[len] = 0; ++ ++ for (i = 1; i <= NumberofKeyWords; i++) ++ { ++ if (CheckKeyWord(KeyWords[i], (char *)copy)) ++ { ++ myBeep(&AlertWAV); ++ free (copy); ++ return TRUE; // Alert ++ } ++ } ++ ++ free(copy); ++ return FALSE; // OK ++ ++} ++ ++ ++void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len) ++{ ++ int MonLen = 0; ++ unsigned char * ptr; ++ unsigned char * Buffptr; ++ unsigned char * FEptr = 0; ++ ++ if (Sess->InputMode == 'Y') // Yapp ++ { ++ ProcessYAPPMessage(Sess, Buffer, len); ++ return; ++ } ++ ++ // See if Teletext data ++ ++ // We need to identify a viewdata frame. Seems to start ++ ++ //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........ ++ //00000170 0a 0a 0a 0a 0a 0a 0a 0a 11 0c 1b ++ ++ // Page seems to start 1c ++ ++ // After page get ++ ++ //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........ ++ // 0000049D 0a 0a 0a 0a 0a 0a 0a 0a 11 14 1b 44 1b 5d 1b 43 ........ ...D.].C ++ // 000004AD 53 65 6c 65 Sele ++ // 000004B1 63 74 20 69 74 65 6d 20 6f 72 1b 47 2a 70 61 67 ct item or .G*pag ++ // 000004C1 65 5f 20 3a 20 20 20 20 20 20 20 20 20 20 20 20 e_ : ++ // 000004D1 20 0d 09 09 09 09 09 09 09 09 09 09 09 09 09 09 ....... ........ ++ // 000004E1 09 09 09 09 09 09 09 09 09 09 09 09 09 11 ++ ++ Buffer[len] = 0; ++ ++ if (AutoTeletext && (Buffer[0] == 0x1e || Buffer[0] == 0x0c)) ++ { ++ if (Sess->TTActive == 0) ++ { ++ Sess->TTActive = 1; ++ DoTermResize(Sess); ++ } ++ } ++ ++ if (Sess->TTActive) ++ { ++ // Feed to Teletext code ++ ++ // We need to decode a whole page. There is no obvious delimiter so process till data stops. ++ // Buffer is cleared when next input is sent ++ ++ if (strlen(&Sess->pageBuffer[0] + len) > 4090) ++ Sess->pageBuffer[0] = 0; // Protect buffer ++ ++ strcat(Sess->pageBuffer, (char *)Buffer); ++ ++ DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end ++ return; ++ } ++ ++ ++ ++ // mbstowcs(Buffer, BufferB, len); ++ ++ // Look for MON delimiters (FF/FE) ++ ++ ++ Buffptr = Buffer; ++ ++ if (Sess->MonData) ++ { ++ // Already in MON State ++ ++ FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len); ++ ++ if (!FEptr) ++ { ++ // no FE - so send all to monitor ++ ++ WritetoMonWindow(Sess, Buffer, len); ++ return; ++ } ++ ++ Sess->MonData = FALSE; ++ ++ MonLen = FEptr - Buffptr; // Mon Data, Excluding the FE ++ ++ WritetoMonWindow(Sess, Buffptr, MonLen); ++ ++ Buffptr = ++FEptr; // Char following FE ++ ++ if (++MonLen < len) ++ { ++ len -= MonLen; ++ goto MonLoop; // See if next in MON or Data ++ } ++ ++ // Nothing Left ++ ++ return; ++ } ++ ++MonLoop: ++ ++ ptr = (UCHAR *)memchr(Buffptr, 0xff, len); ++ ++ if (ptr) ++ { ++ unsigned char telcmd[] = "\xff\xfb\x03\xff\xfb\x01"; ++ ++ // Try to trap connect to normal Telnet Port ++ ++ if (memcmp(ptr, telcmd, 6) == 0) ++ return; ++ ++ // Buffer contains Mon Data ++ ++ if (ptr > Buffptr) ++ { ++ // Some Normal Data before the FF ++ ++ int NormLen = ptr - Buffptr; // Before the FF ++ ++ if (NormLen == 1 && Buffptr[0] == 0) ++ { ++ // Keepalive ++ } ++ ++ else ++ { ++ CheckKeyWords(Buffptr, NormLen); ++ WritetoOutputWindow(Sess, Buffptr, NormLen); ++ } ++ ++ len -= NormLen; ++ Buffptr = ptr; ++ goto MonLoop; ++ } ++ ++ if (ptr[1] == 0xff) ++ { ++ // Port Definition String ++ ++ int NumberofPorts = atoi((char *)&ptr[2]); ++ char *p, *Context; ++ int i = 1; ++ TCHAR msg[80]; ++ int portnum; ++ char delim[] = "|"; ++ int m; ++ ++ // Save for changes of Window ++ ++ if (len < 2048) ++ memcpy(Sess->PortMonString, ptr, len); ++ ++ ++ // Remove old menu ++ ++ for (i = 0; i < 65; i++) ++ { ++ SetPortMonLine(i, (char *)"", 0, 0); ++ } ++ ++ p = strtok_s((char *)&ptr[2], delim, &Context); ++ ++ while (NumberofPorts--) ++ { ++ p = strtok_s(NULL, delim, &Context); ++ if (p == NULL) ++ break; ++ ++ m = portnum = atoi(p); ++ sprintf(msg, "Port %s", p); ++ ++ if (m == 0) ++ m = 64; ++ ++ if (Sess->portmask & (1ll << (m - 1))) ++ SetPortMonLine(portnum, msg, 1, 1); ++ else ++ SetPortMonLine(portnum, msg, 1, 0); ++ } ++ return; ++ } ++ ++ MonLen = len; // in case no fe ++ ++ Sess->MonData = 1; ++ ++ FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len); ++ ++ if (FEptr) ++ { ++ Sess->MonData = 0; ++ ++ MonLen = FEptr + 1 - Buffptr; // MonLen includes FF and FE ++ ++ WritetoMonWindow(Sess, Buffptr + 1, MonLen - 2); ++ ++ len -= MonLen; ++ Buffptr += MonLen; // Char Following FE ++ ++ if (len <= 0) ++ { ++ return; ++ } ++ goto MonLoop; ++ } ++ else ++ { ++ // No FE, so rest of buffer is MON Data ++ ++ if (MonLen) ++ WritetoMonWindow(Sess, Buffptr + 1, MonLen - 1); ++ return; ++ } ++ } ++ ++ // No FF, so must be session data ++ ++ if (Sess->InputMode == 'Y') // Yapp ++ { ++ ProcessYAPPMessage(Sess, Buffer, len); ++ return; ++ } ++ ++ ++ if (len == 1 && Buffptr[0] == 0) ++ return; // Keepalive ++ ++ // Could be a YAPP Header ++ ++ if (len == 2 && Buffptr[0] == ENQ && Buffptr[1] == 1) // YAPP Send_Init ++ { ++ char YAPPRR[2]; ++ ++ // Turn off monitoring ++ ++ setTraceOff(Sess); ++ ++ Sess->InputMode = 'Y'; ++ ++ YAPPRR[0] = ACK; ++ YAPPRR[1] = 1; ++ ++ SocketFlush(Sess); // To give Monitor Msg time to be sent ++ mySleep(1000); ++ QueueMsg(Sess, YAPPRR, 2); ++ ++ return; ++ } ++ // Check UTF8 ++ { ++ CheckKeyWords(Buffptr, len); ++ WritetoOutputWindow(Sess, Buffptr, len); ++ } ++ Sess->SlowTimer = 0; ++ return; ++} ++ ++extern myTcpSocket * VARASock; ++extern myTcpSocket * VARADataSock; ++extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len); ++ ++int SendMsg(Ui_ListenSession * Sess, TCHAR * Buffer, int len) ++{ ++ if (Sess->KISSSession) ++ { ++ // Send to ax.25 code ++ ++ SendtoAX25(Sess->KISSSession, (unsigned char *)Buffer, len); ++ return len; ++ } ++ else if (Sess->AGWSession) ++ { ++ // Terminal is in AGWPE mode - send as AGW frame ++ ++ AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Buffer, len); ++ return len; ++ } ++ else if (VARASock && VARASock->Sess == Sess) ++ { ++ VARADataSock->write(Buffer, len); ++ return len; ++ } ++ ++ return SocketSend(Sess, Buffer, len); ++} ++ ++ ++ ++void QueueMsg(Ui_ListenSession * Sess, char * Msg, int len) ++{ ++ int Sent = SendMsg(Sess, Msg, len); ++ ++ if (Sent != len) ++ Sent = 0; ++} ++ ++int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len); ++ ++int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len) ++{ ++ // may have saved data ++ ++ memcpy(&SavedData[SaveLen], Msg, Len); ++ ++ SaveLen += Len; ++ ++ while (SaveLen && Sess->InputMode == 'Y') ++ { ++ int Used = InnerProcessYAPPMessage(Sess, SavedData, SaveLen); ++ ++ if (Used == 0) ++ return 0; // Waiting for more ++ ++ SaveLen -= Used; ++ ++ if (SaveLen) ++ memmove(SavedData, &SavedData[Used], SaveLen); ++ } ++ return 0; ++} ++ ++extern int VARAEnable; ++ ++int InnerProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len) ++{ ++ int pktLen = Msg[1]; ++ char Reply[2] = { ACK }; ++ size_t NameLen, SizeLen, OptLen; ++ char * ptr; ++ int FileSize; ++ WCHAR MsgFile[MAX_PATH]; ++ FILE * hFile; ++ char Mess[255]; ++ int len; ++ UCHAR Buffer[2000]; ++ struct stat STAT; ++ ++ switch (Msg[0]) ++ { ++ case ENQ: // YAPP Send_Init ++ ++ // Shouldn't occur in session. Reset state and process ++ ++ if (MailBuffer) ++ { ++ free(MailBuffer); ++ MailBufferSize = 0; ++ MailBuffer = 0; ++ } ++ ++ Mess[0] = ACK; ++ Mess[1] = 1; ++ ++ Sess->InputMode = 'Y'; ++ QueueMsg(Sess, Mess, 2); ++ ++ // Turn off monitoring ++ ++ mySleep(1000); // To give YAPP Msg time to be sent ++ ++ setTraceOff(Sess); ++ ++ return Len; ++ ++ case SOH: ++ ++ // HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt) ++ ++ // YAPPC has date/time in dos format ++ ++ if (Len < Msg[1] + 1) ++ return 0; // Wait till we have it all ++ ++ NameLen = strlen((char *)&Msg[2]); ++ strcpy(ARQFilename, (char *)&Msg[2]); ++ ++ ptr = (char *)&Msg[3 + NameLen]; ++ SizeLen = strlen(ptr); ++ FileSize = atoi(ptr); ++ ++ OptLen = pktLen - (NameLen + SizeLen + 2); ++ ++ YAPPDate = 0; ++ ++ if (OptLen >= 8) // We have a Date/Time for YAPPC ++ { ++ ptr = ptr + SizeLen + 1; ++ YAPPDate = strtol(ptr, NULL, 16); ++ } ++ ++ // Check Size ++ ++ if (FileSize > MaxRXSize && VARAEnable == 0) ++ { ++ Mess[0] = NAK; ++ Mess[1] = sprintf(&Mess[2], "File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize); ++ mySleep(1000); // To give YAPP Msg time to be sent ++ QueueMsg(Sess, Mess, Mess[1] + 2); ++ ++ len = sprintf((char *)Buffer, "YAPP File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ ++ return Len; ++ } ++ ++ // Check that Path is set ++ ++ if (YAPPPath[0] == 0) ++ { ++ Mess[0] = NAK; ++ Mess[1] = sprintf(&Mess[2], "%s", "YAPP Receive directory not set"); ++ mySleep(1000); // To give YAPP Msg time to be sent ++ QueueMsg(Sess, Mess, Mess[1] + 2); ++ len = sprintf((char *)Buffer, "YAPP File Receive Failed - YAPP Receive directory not set\r"); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ ++ return Len; ++ } ++ ++ // Make sure file does not exist ++ ++ sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename); ++ ++ if (stat(MsgFile, &STAT) == 0) ++ { ++ FileSize = STAT.st_size; ++ ++ Mess[0] = NAK; ++ Mess[1] = sprintf(&Mess[2], "%s", "File Already Exists"); ++ mySleep(1000); // To give YAPP Msg time to be sent ++ QueueMsg(Sess, Mess, Mess[1] + 2); ++ len = sprintf((char *)Buffer, "YAPP File Receive Failed - %s already exists\r", MsgFile); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ ++ return Len; ++ } ++ ++ ++ MailBufferSize = FileSize; ++ MailBuffer = (UCHAR *)malloc(FileSize); ++ YAPPLen = 0; ++ ++ if (YAPPDate) // If present use YAPPC ++ Reply[1] = ACK; //Receive_TPK ++ else ++ Reply[1] = 2; //Rcv_File ++ ++ QueueMsg(Sess, Reply, 2); ++ ++ len = sprintf((char *)Buffer, "YAPP Receving File %s size %d\r", ARQFilename, FileSize); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ return Len; ++ ++ case STX: ++ ++ // Data Packet ++ ++ // Check we have it all ++ ++ if (YAPPDate) // If present use YAPPC so have checksum ++ { ++ if (pktLen > (Len - 3)) // -2 for header and checksum ++ return 0; // Wait for rest ++ } ++ else ++ { ++ if (pktLen > (Len - 2)) // -2 for header ++ return 0; // Wait for rest ++ } ++ ++ // Save data and remove from buffer ++ ++ // if YAPPC check checksum ++ ++ if (YAPPDate) ++ { ++ UCHAR Sum = 0; ++ int i; ++ UCHAR * uptr = &Msg[2]; ++ ++ i = pktLen; ++ ++ while (i--) ++ Sum += *(uptr++); ++ ++ if (Sum != *uptr) ++ { ++ // Checksum Error ++ ++ Mess[0] = CAN; ++ Mess[1] = sprintf(&Mess[2], "YAPPC Checksum Error"); ++ QueueMsg(Sess, Mess, Mess[1] + 2); ++ ++ len = sprintf((char *)Buffer, "YAPPC Checksum Error on file %s\r", MsgFile); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ return Len; ++ } ++ } ++ ++ if ((YAPPLen) + pktLen > MailBufferSize) ++ { ++ // Too Big ?? ++ ++ Mess[0] = CAN; ++ Mess[1] = sprintf(&Mess[2], "YAPP Too much data received"); ++ QueueMsg(Sess, Mess, Mess[1] + 2); ++ ++ len = sprintf((char *)Buffer, "YAPP Too much data received on file %s\r", MsgFile); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ return Len; ++ } ++ ++ ++ memcpy(&MailBuffer[YAPPLen], &Msg[2], pktLen); ++ YAPPLen += pktLen; ++ ++ if (YAPPDate) ++ ++pktLen; // Add Checksum ++ ++// if (YAPPLen == MailBufferSize) ++// pktLen = pktLen; ++ ++ return pktLen + 2; ++ ++ case ETX: ++ ++ // End Data ++ ++ if (YAPPLen == MailBufferSize) ++ { ++ // All received ++ ++ int Written = 0; ++ ++ sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename); ++ ++ hFile = fopen(MsgFile, "wb"); ++ ++ if (hFile) ++ { ++ Written = (int)fwrite(MailBuffer, 1, YAPPLen, hFile); ++ fclose(hFile); ++ ++ if (YAPPDate) ++ { ++// struct tm TM; ++// struct timeval times[2]; ++ /* ++ The MS-DOS date. The date is a packed value with the following format. ++ ++ cant use DosDateTimeToFileTime on Linux ++ ++ Bits Description ++ 0-4 Day of the month (1–31) ++ 5-8 Month (1 = January, 2 = February, and so on) ++ 9-15 Year offset from 1980 (add 1980 to get actual year) ++ wFatTime ++ The MS-DOS time. The time is a packed value with the following format. ++ Bits Description ++ 0-4 Second divided by 2 ++ 5-10 Minute (0–59) ++ 11-15 Hour (0–23 on a 24-hour clock) ++ */ ++ /* ++ ++ memset(&TM, 0, sizeof(TM)); ++ ++ TM.tm_sec = (YAPPDate & 0x1f) << 1; ++ TM.tm_min = ((YAPPDate >> 5) & 0x3f); ++ TM.tm_hour = ((YAPPDate >> 11) & 0x1f); ++ ++ TM.tm_mday = ((YAPPDate >> 16) & 0x1f); ++ TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1; ++ TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80; ++ ++ Debugprintf("%d %d %d %d %d %d", TM.tm_year, TM.tm_mon, TM.tm_mday, TM.tm_hour, TM.tm_min, TM.tm_sec); ++ ++ times[0].tv_sec = times[1].tv_sec = mktime(&TM); ++ times[0].tv_usec = times[1].tv_usec = 0; ++ */ ++ } ++ } ++ ++ ++ free(MailBuffer); ++ MailBufferSize = 0; ++ MailBuffer = 0; ++ ++ if (Written != YAPPLen) ++ { ++ Mess[0] = CAN; ++ Mess[1] = sprintf(&Mess[2], "Failed to save YAPP File"); ++ QueueMsg(Sess, Mess, Mess[1] + 2); ++ ++ len = sprintf((char *)Buffer, "Failed to save YAPP File %s\r", MsgFile); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ } ++ } ++ ++ Reply[1] = 3; //Ack_EOF ++ QueueMsg(Sess, Reply, 2); ++ ++ len = sprintf((char *)Buffer, "Reception of file %s complete\r", MsgFile); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ return Len; ++ ++ case EOT: ++ ++ // End Session ++ ++ Reply[1] = 4; // Ack_EOT ++ QueueMsg(Sess, Reply, 2); ++ SocketFlush(Sess); ++ Sess->InputMode = 0; ++ ++ SendTraceOptions(Sess); ++ return Len; ++ ++ case CAN: ++ ++ // Abort ++ ++ Mess[0] = ACK; ++ Mess[1] = 5; // CAN Ack ++ QueueMsg(Sess, Mess, 2); ++ ++ if (MailBuffer) ++ { ++ free(MailBuffer); ++ MailBufferSize = 0; ++ MailBuffer = 0; ++ } ++ ++ // May have an error message ++ ++ len = Msg[1]; ++ ++ if (len) ++ { ++ len = sprintf((char *)Buffer, "YAPP Transfer cancelled - %s\r", &Msg[2]); ++ } ++ else ++ len = sprintf(Mess, "YAPP Transfer cancelled\r"); ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ ++ return Len; ++ ++ case ACK: ++ ++ switch (Msg[1]) ++ { ++ char * ptr; ++ ++ case 1: // Rcv_Rdy ++ ++ // HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt) ++ ++ // Remote only needs filename so remove path ++ ++ ptr = ARQFilename; ++ ++ while (strchr(ptr, '/')) ++ ptr = strchr(ptr, '/') + 1; ++ ++ len = (int)strlen(ptr) + 3; ++ ++ strcpy(&Mess[2], ptr); ++ len += sprintf(&Mess[len], "%d", MailBufferSize); ++ len++; // include null ++// len += sprintf(&Mess[len], "%8X", YAPPDate); ++// len++; // include null ++ Mess[0] = SOH; ++ Mess[1] = len - 2; ++ ++ QueueMsg(Sess, Mess, len); ++ ++ return Len; ++ ++ case 2: ++ ++ YAPPDate = 0; // Switch to Normal (No Checksum) Mode ++ ++ // Drop through ++ ++ case 6: // Send using YAPPC ++ ++ // Start sending message ++ ++ YAPPSendData(Sess); ++ return Len; ++ ++ case 3: ++ ++ // ACK EOF - Send EOT ++ ++ Mess[0] = EOT; ++ Mess[1] = 1; ++ QueueMsg(Sess, Mess, 2); ++ ++ return Len; ++ ++ case 4: ++ ++ // ACK EOT ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ ++ len = sprintf((char *)Buffer, "File transfer complete\r"); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ ++ return Len; ++ ++ default: ++ return Len; ++ ++ } ++ ++ case NAK: ++ ++ // Either Reject or Restart ++ ++ // RE Resume NAK len R NULL (File size in ASCII) NULL ++ ++ if (Len > 2 && Msg[2] == 'R' && Msg[3] == 0) ++ { ++ int posn = atoi((char *)&Msg[4]); ++ ++ YAPPLen += posn; ++ MailBufferSize -= posn; ++ ++ YAPPSendData(Sess); ++ return Len; ++ ++ } ++ ++ // May have an error message ++ ++ len = Msg[1]; ++ ++ if (len) ++ { ++ char ws[256]; ++ ++ Msg[len + 2] = 0; ++ ++ strcpy(ws, (char *)&Msg[2]); ++ ++ len = sprintf((char *)Buffer, "File rejected - %s\r", ws); ++ } ++ else ++ len = sprintf((char *)Buffer, "File rejected\r"); ++ ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ ++ return Len; ++ ++ } ++ ++ len = sprintf((char *)Buffer, "Unexpected message during YAPP Transfer. Transfer cancelled\r"); ++ WritetoOutputWindow(Sess, Buffer, len); ++ ++ Sess->InputMode = 0; ++ SendTraceOptions(Sess); ++ ++ return Len; ++ ++} ++ ++void YAPPSendFile(Ui_ListenSession * Sess, WCHAR * FN) ++{ ++ int FileSize = 0; ++ char MsgFile[MAX_PATH]; ++ FILE * hFile; ++ struct stat STAT; ++ UCHAR Buffer[2000]; ++ int Len; ++ ++ strcpy(MsgFile, FN); ++ ++ if (MsgFile[0] == 0) ++ { ++ Len = sprintf((char *)Buffer, "Filename missing\r"); ++ WritetoOutputWindow(Sess, Buffer, Len); ++ ++ SendTraceOptions(Sess); ++ ++ return; ++ } ++ ++ if (stat(MsgFile, &STAT) != -1) ++ { ++ FileSize = STAT.st_size; ++ ++ hFile = fopen(MsgFile, "rb"); ++ ++ if (hFile) ++ { ++ char Mess[255]; ++// time_t UnixTime = STAT.st_mtime; ++ ++// FILETIME ft; ++// long long ll; ++// SYSTEMTIME st; ++// WORD FatDate; ++// WORD FatTime; ++// struct tm TM; ++ ++ strcpy(ARQFilename, MsgFile); ++ ++ if (MailBuffer) ++ { ++ free(MailBuffer); ++ MailBufferSize = 0; ++ MailBuffer = 0; ++ } ++ ++ MailBuffer = (UCHAR *)malloc(FileSize); ++ MailBufferSize = FileSize; ++ YAPPLen = 0; ++ fread(MailBuffer, 1, FileSize, hFile); ++ ++ // Get Date and Time for YAPPC Mode ++ ++/* The MS-DOS date. The date is a packed value with the following format. ++ ++ cant use DosDateTimeToFileTime on Linux ++ ++ Bits Description ++ 0-4 Day of the month (1–31) ++ 5-8 Month (1 = January, 2 = February, and so on) ++ 9-15 Year offset from 1980 (add 1980 to get actual year) ++ wFatTime ++ The MS-DOS time. The time is a packed value with the following format. ++ Bits Description ++ 0-4 Second divided by 2 ++ 5-10 Minute (0–59) ++ 11-15 Hour (0–23 on a 24-hour clock) ++ ++ memset(&TM, 0, sizeof(TM)); ++ ++ TM.tm_sec = (YAPPDate & 0x1f) << 1; ++ TM.tm_min = ((YAPPDate >> 5) & 0x3f); ++ TM.tm_hour = ((YAPPDate >> 11) & 0x1f); ++ ++ TM.tm_mday = ((YAPPDate >> 16) & 0x1f); ++ TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1; ++ TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80; ++ ++ ++// Note that LONGLONG is a 64-bit value ++ ++ ll = Int32x32To64(UnixTime, 10000000) + 116444736000000000; ++ ft.dwLowDateTime = (DWORD)ll; ++ ll >>= 32; ++ ft.dwHighDateTime = (DWORD)ll; ++ ++ FileTimeToSystemTime(&ft, &st); ++ FileTimeToDosDateTime(&ft, &FatDate, &FatTime); ++ ++ YAPPDate = (FatDate << 16) + FatTime; ++ ++ memset(&TM, 0, sizeof(TM)); ++ ++ TM.tm_sec = (YAPPDate & 0x1f) << 1; ++ TM.tm_min = ((YAPPDate >> 5) & 0x3f); ++ TM.tm_hour = ((YAPPDate >> 11) & 0x1f); ++ ++ TM.tm_mday = ((YAPPDate >> 16) & 0x1f); ++ TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1; ++ TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80; ++*/ ++ fclose(hFile); ++ ++ Mess[0] = ENQ; ++ Mess[1] = 1; ++ ++ QueueMsg(Sess, Mess, 2); ++ Sess->InputMode = 'Y'; ++ ++ Len = sprintf((char *)Buffer, "Sending File %s ...\r", FN); ++ WritetoOutputWindow(Sess, Buffer, Len); ++ ++ return; ++ } ++ } ++ ++ Len = sprintf((char *)Buffer, "File %s not found\r", FN); ++ WritetoOutputWindow(Sess, Buffer, Len); ++ ++} ++ ++void YAPPSendData(Ui_ListenSession * Sess) ++{ ++ char Mess[258]; ++ ++ while (1) ++ { ++ int Left = MailBufferSize; ++ ++ if (Left == 0) ++ { ++ // Finished - send End Data ++ ++ Mess[0] = ETX; ++ Mess[1] = 1; ++ ++ QueueMsg(Sess, Mess, 2); ++ ++ break; ++ } ++ ++ if (Left > paclen - 3) // two bytes header and possible checksum ++ Left = paclen - 3; ++ ++ memcpy(&Mess[2], &MailBuffer[YAPPLen], Left); ++ ++ YAPPLen += Left; ++ MailBufferSize -= Left; ++ ++ // if YAPPC add checksum ++ ++ if (YAPPDate) ++ { ++ UCHAR Sum = 0; ++ int i; ++ UCHAR * uptr = (UCHAR *)&Mess[2]; ++ ++ i = Left; ++ ++ while (i--) ++ Sum += *(uptr++); ++ ++ *(uptr) = Sum; ++ ++ Mess[0] = STX; ++ Mess[1] = Left; ++ ++ QueueMsg(Sess, Mess, Left + 3); ++ } ++ else ++ { ++ Mess[0] = STX; ++ Mess[1] = Left; ++ ++ QueueMsg(Sess, Mess, Left + 2); ++ } ++ } ++} ++ +--- qttermtcp-0.0.0.79.orig/UZ7HOUtils.c ++++ qttermtcp-0.0.0.79/UZ7HOUtils.c +@@ -1,320 +1,320 @@ +-/* +-Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO +- +-This file is part of QtSoundModem +- +-QtSoundModem is free software: you can redistribute it and/or modify +-it under the terms of the GNU General Public License as published by +-the Free Software Foundation, either version 3 of the License, or +-(at your option) any later version. +- +-QtSoundModem is distributed in the hope that it will be useful, +-but WITHOUT ANY WARRANTY; without even the implied warranty of +-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-GNU General Public License for more details. +- +-You should have received a copy of the GNU General Public License +-along with QtSoundModem. If not, see http://www.gnu.org/licenses +- +-*/ +- +-// UZ7HO Soundmodem Port by John Wiseman G8BPQ +-#include "ax25.h" +- +-// TStringlist And String emulation Functions +- +-// Dephi seems to mix starting counts at 0 or 1. I'll try making everything +-// base zero. +- +-// Initialise a list +- +-void CreateStringList(TStringList * List) +-{ +- List->Count = 0; +- List->Items = 0; +-} +- +- +-int Count(TStringList * List) +-{ +- return List->Count; +-} +- +-string * newString() +-{ +- // Creates and Initialises a string +- +- UCHAR * ptr = malloc(sizeof(string)); // Malloc Data separately so it can be ralloc'ed +- string * New = (string *)ptr; +- New->Length = 0; +- New->AllocatedLength = 256; +- New->Data = malloc(256); +- +- return New; +-} +- +-void initString(string * S) +-{ +- S->Length = 0; +- S->AllocatedLength = 256; +- S->Data = malloc(256); +-} +- +-void initTStringList(TStringList* T) +-{ +- //string * New = newString(); +- +- T->Count = 0; +- T->Items = NULL; +- +- //Add(T, New); +-} +- +- +- +-TStringList * newTStringList() +-{ +- TStringList * T = (TStringList *) malloc(sizeof(TStringList)); +- string * New = newString(); +- +- T->Count = 0; +- T->Items = NULL; +- +- Add(T, New); +- +- return T; +-} +- +- +-void freeString(string * Msg) +-{ +- if (Msg->Data) +- free(Msg->Data); +- +- free(Msg); +-} +- +-string * Strings(TStringList * Q, int Index) +-{ +- if (Index >= Q->Count) +- return NULL; +- +- return Q->Items[Index]; +-} +- +-int Add(TStringList * Q, string * Entry) +-{ +- Q->Items = realloc(Q->Items,(Q->Count + 1) * sizeof(void *)); +- Q->Items[Q->Count++] = Entry; +- +- return (Q->Count); +-} +- +- +-void mydelete(string * Source, int StartChar, int Count) +-{ +- //Description +- //The Delete procedure deletes up to Count characters from the passed parameter Source string starting +- //from position StartChar. +- +- if (StartChar > Source->Length) +- return; +- +- int left = Source->Length - StartChar; +- +- if (Count > left) +- Count = left; +- +- memmove(&Source->Data[StartChar], &Source->Data[StartChar + Count], left - Count); +- +- Source->Length -= Count; +-} +- +- +-void Delete(TStringList * Q, int Index) +-{ +- // Remove item at Index and move rest up list +- // Index starts at zero +- +- if (Index >= Q->Count) +- return; +- +- // We should free it, so user must duplicate msg if needed after delete +- +- freeString(Q->Items[Index]); +- +- Q->Count--; +- +- while (Index < Q->Count) +- { +- Q->Items[Index] = Q->Items[Index + 1]; +- Index++; +- } +-} +- +-void setlength(string * Msg, int Count) +-{ +- // Set length, allocating more space if needed +- +- if (Count > Msg->AllocatedLength) +- { +- Msg->AllocatedLength = Count + 256; +- Msg->Data = realloc(Msg->Data, Msg->AllocatedLength); +- } +- +- Msg->Length = Count; +-} +- +-string * stringAdd(string * Msg, UCHAR * Chars, int Count) +-{ +- // Add Chars to string +- +- if (Msg->Length + Count > Msg->AllocatedLength) +- { +- Msg->AllocatedLength += Count + 256; +- Msg->Data = realloc(Msg->Data, Msg->AllocatedLength); +- } +- +- memcpy(&Msg->Data[Msg->Length], Chars, Count); +- Msg->Length += Count; +- +- return Msg; +-} +- +-void Clear(TStringList * Q) +-{ +- int i = 0; +- +- if (Q->Items == NULL) +- return; +- +- while (Q->Count) +- { +- freeString(Q->Items[i++]); +- Q->Count--; +- } +- +- free(Q->Items); +- +- Q->Items = NULL; +-} +- +-// procedure move ( const SourcePointer; var DestinationPointer; CopyCount : Integer ) ; +-// Description +-// The move procedure is a badly named method of copying a section of memory from one place to another. +- +-// CopyCount bytes are copied from storage referenced by SourcePointer and written to DestinationPointer +- +-void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount) +-{ +- memmove(DestinationPointer, SourcePointer, CopyCount); +-} +- +-void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount) +-{ +- memmove(DestinationPointer, SourcePointer, CopyCount); +-} +- +- +- +-//Description +-//The copy function has 2 forms. In the first, it creates a new string from part of an existing string. In the second, it creates a new array from part of an existing array. +- +-//1.String copy +- +-//The first character of a string has index = 1. +- +-//Up to Count characters are copied from the StartChar of the Source string to the returned string. +-//Less than Count characters if the end of the Source string is encountered before Count characters have been copied. +- +- +-string * copy(string * Source, int StartChar, int Count) +-{ +- string * NewString = newString(); +- int end = StartChar + Count; +- +- if (end > Source->Length) +- Count = Source->Length - StartChar; +- +- memcpy(NewString->Data, &Source->Data[StartChar], Count); +- +- NewString->Length = Count; +- +- return NewString; +-} +- +-// Duplicate from > to +- +-void Assign(TStringList * to, TStringList * from) +-{ +- int i; +- +- Clear(to); +- +- if (from->Count == 0) +- return; +- +- // Duplicate each item +- +- for (i = 0; i < from->Count; i++) +- { +- string * new = newString(); +- +- stringAdd(new, from->Items[i]->Data, from->Items[i]->Length); +- Add(to, new); +- } +-} +- +-string * duplicateString(string * in) +-{ +- string * new = newString(); +- +- stringAdd(new, in->Data, in->Length); +- +- return new; +-} +- +- +-double pila(double x) +-{ +- //x : = frac(x); The frac function returns the fractional part of a floating point number. +- +- double whole; +- double rem; +- +- rem = modf(x, &whole); // returns fraction, writes whole to whole +- +- if (rem != rem) +- rem = 0; +- +- if (rem > 0.5) +- rem = 1 - rem; +- +- return 2 * rem; +-} +- +-boolean compareStrings(string * a, string * b) +-{ +- if (a->Length == b->Length && memcmp(a->Data, b->Data, a->Length) == 0) +- return TRUE; +- +- return FALSE; +-} +- +-// This looks for a string in a stringlist. Returns index if found, otherwise -1 +- +-int my_indexof(TStringList * l, string * s) +-{ +- int i; +- +- for (i = 0; i < l->Count; i++) +- { +- // Need to compare count and data - C doesn't allow struct compare +- +- if (l->Items[i]->Length == s->Length && memcmp(l->Items[i]->Data, s->Data, s->Length) == 0) +- return i; +- } +- return -1; +-} +- ++/* ++Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO ++ ++This file is part of QtSoundModem ++ ++QtSoundModem is free software: you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation, either version 3 of the License, or ++(at your option) any later version. ++ ++QtSoundModem is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with QtSoundModem. If not, see http://www.gnu.org/licenses ++ ++*/ ++ ++// UZ7HO Soundmodem Port by John Wiseman G8BPQ ++#include "ax25.h" ++ ++// TStringlist And String emulation Functions ++ ++// Dephi seems to mix starting counts at 0 or 1. I'll try making everything ++// base zero. ++ ++// Initialise a list ++ ++void CreateStringList(TStringList * List) ++{ ++ List->Count = 0; ++ List->Items = 0; ++} ++ ++ ++int Count(TStringList * List) ++{ ++ return List->Count; ++} ++ ++string * newString() ++{ ++ // Creates and Initialises a string ++ ++ UCHAR * ptr = malloc(sizeof(string)); // Malloc Data separately so it can be ralloc'ed ++ string * New = (string *)ptr; ++ New->Length = 0; ++ New->AllocatedLength = 256; ++ New->Data = malloc(256); ++ ++ return New; ++} ++ ++void initString(string * S) ++{ ++ S->Length = 0; ++ S->AllocatedLength = 256; ++ S->Data = malloc(256); ++} ++ ++void initTStringList(TStringList* T) ++{ ++ //string * New = newString(); ++ ++ T->Count = 0; ++ T->Items = NULL; ++ ++ //Add(T, New); ++} ++ ++ ++ ++TStringList * newTStringList() ++{ ++ TStringList * T = (TStringList *) malloc(sizeof(TStringList)); ++ string * New = newString(); ++ ++ T->Count = 0; ++ T->Items = NULL; ++ ++ Add(T, New); ++ ++ return T; ++} ++ ++ ++void freeString(string * Msg) ++{ ++ if (Msg->Data) ++ free(Msg->Data); ++ ++ free(Msg); ++} ++ ++string * Strings(TStringList * Q, int Index) ++{ ++ if (Index >= Q->Count) ++ return NULL; ++ ++ return Q->Items[Index]; ++} ++ ++int Add(TStringList * Q, string * Entry) ++{ ++ Q->Items = realloc(Q->Items,(Q->Count + 1) * sizeof(void *)); ++ Q->Items[Q->Count++] = Entry; ++ ++ return (Q->Count); ++} ++ ++ ++void mydelete(string * Source, int StartChar, int Count) ++{ ++ //Description ++ //The Delete procedure deletes up to Count characters from the passed parameter Source string starting ++ //from position StartChar. ++ ++ if (StartChar > Source->Length) ++ return; ++ ++ int left = Source->Length - StartChar; ++ ++ if (Count > left) ++ Count = left; ++ ++ memmove(&Source->Data[StartChar], &Source->Data[StartChar + Count], left - Count); ++ ++ Source->Length -= Count; ++} ++ ++ ++void Delete(TStringList * Q, int Index) ++{ ++ // Remove item at Index and move rest up list ++ // Index starts at zero ++ ++ if (Index >= Q->Count) ++ return; ++ ++ // We should free it, so user must duplicate msg if needed after delete ++ ++ freeString(Q->Items[Index]); ++ ++ Q->Count--; ++ ++ while (Index < Q->Count) ++ { ++ Q->Items[Index] = Q->Items[Index + 1]; ++ Index++; ++ } ++} ++ ++void setlength(string * Msg, int Count) ++{ ++ // Set length, allocating more space if needed ++ ++ if (Count > Msg->AllocatedLength) ++ { ++ Msg->AllocatedLength = Count + 256; ++ Msg->Data = realloc(Msg->Data, Msg->AllocatedLength); ++ } ++ ++ Msg->Length = Count; ++} ++ ++string * stringAdd(string * Msg, UCHAR * Chars, int Count) ++{ ++ // Add Chars to string ++ ++ if (Msg->Length + Count > Msg->AllocatedLength) ++ { ++ Msg->AllocatedLength += Count + 256; ++ Msg->Data = realloc(Msg->Data, Msg->AllocatedLength); ++ } ++ ++ memcpy(&Msg->Data[Msg->Length], Chars, Count); ++ Msg->Length += Count; ++ ++ return Msg; ++} ++ ++void Clear(TStringList * Q) ++{ ++ int i = 0; ++ ++ if (Q->Items == NULL) ++ return; ++ ++ while (Q->Count) ++ { ++ freeString(Q->Items[i++]); ++ Q->Count--; ++ } ++ ++ free(Q->Items); ++ ++ Q->Items = NULL; ++} ++ ++// procedure move ( const SourcePointer; var DestinationPointer; CopyCount : Integer ) ; ++// Description ++// The move procedure is a badly named method of copying a section of memory from one place to another. ++ ++// CopyCount bytes are copied from storage referenced by SourcePointer and written to DestinationPointer ++ ++void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount) ++{ ++ memmove(DestinationPointer, SourcePointer, CopyCount); ++} ++ ++void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount) ++{ ++ memmove(DestinationPointer, SourcePointer, CopyCount); ++} ++ ++ ++ ++//Description ++//The copy function has 2 forms. In the first, it creates a new string from part of an existing string. In the second, it creates a new array from part of an existing array. ++ ++//1.String copy ++ ++//The first character of a string has index = 1. ++ ++//Up to Count characters are copied from the StartChar of the Source string to the returned string. ++//Less than Count characters if the end of the Source string is encountered before Count characters have been copied. ++ ++ ++string * copy(string * Source, int StartChar, int Count) ++{ ++ string * NewString = newString(); ++ int end = StartChar + Count; ++ ++ if (end > Source->Length) ++ Count = Source->Length - StartChar; ++ ++ memcpy(NewString->Data, &Source->Data[StartChar], Count); ++ ++ NewString->Length = Count; ++ ++ return NewString; ++} ++ ++// Duplicate from > to ++ ++void Assign(TStringList * to, TStringList * from) ++{ ++ int i; ++ ++ Clear(to); ++ ++ if (from->Count == 0) ++ return; ++ ++ // Duplicate each item ++ ++ for (i = 0; i < from->Count; i++) ++ { ++ string * new = newString(); ++ ++ stringAdd(new, from->Items[i]->Data, from->Items[i]->Length); ++ Add(to, new); ++ } ++} ++ ++string * duplicateString(string * in) ++{ ++ string * new = newString(); ++ ++ stringAdd(new, in->Data, in->Length); ++ ++ return new; ++} ++ ++ ++double pila(double x) ++{ ++ //x : = frac(x); The frac function returns the fractional part of a floating point number. ++ ++ double whole; ++ double rem; ++ ++ rem = modf(x, &whole); // returns fraction, writes whole to whole ++ ++ if (rem != rem) ++ rem = 0; ++ ++ if (rem > 0.5) ++ rem = 1 - rem; ++ ++ return 2 * rem; ++} ++ ++boolean compareStrings(string * a, string * b) ++{ ++ if (a->Length == b->Length && memcmp(a->Data, b->Data, a->Length) == 0) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++// This looks for a string in a stringlist. Returns index if found, otherwise -1 ++ ++int my_indexof(TStringList * l, string * s) ++{ ++ int i; ++ ++ for (i = 0; i < l->Count; i++) ++ { ++ // Need to compare count and data - C doesn't allow struct compare ++ ++ if (l->Items[i]->Length == s->Length && memcmp(l->Items[i]->Data, s->Data, s->Length) == 0) ++ return i; ++ } ++ return -1; ++} ++ + +\ No newline at end of file +--- qttermtcp-0.0.0.79.orig/VARA.ui ++++ qttermtcp-0.0.0.79/VARA.ui +@@ -1,148 +1,148 @@ +- +- +- AGWConnectDkg +- +- +- +- 0 +- 0 +- 500 +- 400 +- +- +- +- Dialog +- +- +- +- +- 10 +- 10 +- 480 +- 380 +- +- +- +- +- +- +- +- +- Call From +- +- +- +- +- +- +- +- +- +- Call To +- +- +- +- +- +- +- true +- +- +- QComboBox::NoInsert +- +- +- +- +- +- +- Digis +- +- +- +- +- +- +- +- +- +- +- +- Radio Ports +- +- +- +- +- +- +- +- +- +- 6 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- +- +- OK +- +- +- +- +- +- +- Cancel +- +- +- +- +- +- +- +- +- +- +- +- okButton +- clicked() +- AGWConnectDkg +- accept() +- +- +- 278 +- 253 +- +- +- 96 +- 254 +- +- +- +- +- cancelButton +- clicked() +- AGWConnectDkg +- reject() +- +- +- 369 +- 253 +- +- +- 179 +- 282 +- +- +- +- +- ++ ++ ++ AGWConnectDkg ++ ++ ++ ++ 0 ++ 0 ++ 500 ++ 400 ++ ++ ++ ++ Dialog ++ ++ ++ ++ ++ 10 ++ 10 ++ 480 ++ 380 ++ ++ ++ ++ ++ ++ ++ ++ ++ Call From ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Call To ++ ++ ++ ++ ++ ++ ++ true ++ ++ ++ QComboBox::NoInsert ++ ++ ++ ++ ++ ++ ++ Digis ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ Radio Ports ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ 6 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ OK ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ okButton ++ clicked() ++ AGWConnectDkg ++ accept() ++ ++ ++ 278 ++ 253 ++ ++ ++ 96 ++ 254 ++ ++ ++ ++ ++ cancelButton ++ clicked() ++ AGWConnectDkg ++ reject() ++ ++ ++ 369 ++ 253 ++ ++ ++ 179 ++ 282 ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/VARAConfig.ui ++++ qttermtcp-0.0.0.79/VARAConfig.ui +@@ -1,608 +1,608 @@ +- +- +- Dialog +- +- +- +- 0 +- 0 +- 571 +- 589 +- +- +- +- VARA Configuration +- +- +- +- +- 170 +- 490 +- 211 +- 33 +- +- +- +- +- 6 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- +- +- OK +- +- +- +- +- +- +- Cancel +- +- +- +- +- +- +- +- +- 10 +- 120 +- 551 +- 161 +- +- +- +- TNC Setup +- +- +- +- +- 130 +- 22 +- 101 +- 22 +- +- +- +- +- +- +- 400 +- 20 +- 47 +- 22 +- +- +- +- +- +- +- 130 +- 57 +- 391 +- 22 +- +- +- +- +- +- +- 16 +- 24 +- 47 +- 13 +- +- +- +- Host +- +- +- +- +- +- 286 +- 19 +- 47 +- 22 +- +- +- +- Port +- +- +- +- +- +- 16 +- 56 +- 47 +- 22 +- +- +- +- Path +- +- +- +- +- +- 130 +- 91 +- 391 +- 22 +- +- +- +- +- +- +- 16 +- 90 +- 101 +- 22 +- +- +- +- Init Commands +- +- +- +- +- +- 80 +- 120 +- 371 +- 31 +- +- +- +- You can specify more than one command, but the separator must be just a comma with no spaces +- +- +- Qt::AlignCenter +- +- +- true +- +- +- +- +- +- +- 8 +- 300 +- 541 +- 181 +- +- +- +- PTT Port +- +- +- +- +- 150 +- 20 +- 111 +- 22 +- +- +- +- +- +- +- 20 +- 23 +- 131 +- 16 +- +- +- +- Select PTT Port +- +- +- +- +- +- 20 +- 80 +- 121 +- 22 +- +- +- +- PTT On String +- +- +- +- +- +- 150 +- 83 +- 247 +- 22 +- +- +- +- +- +- +- 150 +- 114 +- 247 +- 22 +- +- +- +- +- +- +- 20 +- 112 +- 121 +- 22 +- +- +- +- PTT Off String +- +- +- +- +- +- 20 +- 52 +- 111 +- 16 +- +- +- +- GPIO Pin Left +- +- +- +- +- +- 150 +- 50 +- 25 +- 20 +- +- +- +- +- +- +- 310 +- 50 +- 25 +- 20 +- +- +- +- +- +- +- 165 +- 50 +- 83 +- 18 +- +- +- +- GPIO Pin Right +- +- +- +- +- +- 18 +- 50 +- 121 +- 18 +- +- +- +- CAT Port Speed +- +- +- +- +- +- 150 +- 50 +- 47 +- 20 +- +- +- +- +- +- +- 290 +- 22 +- 131 +- 18 +- +- +- +- RTS/DTR +- +- +- buttonGroup_2 +- +- +- +- +- +- 420 +- 22 +- 121 +- 18 +- +- +- +- CAT +- +- +- buttonGroup_2 +- +- +- +- +- +- 150 +- 50 +- 121 +- 20 +- +- +- +- +- +- +- 20 +- 50 +- 111 +- 18 +- +- +- +- CM108 VID/PID +- +- +- +- +- +- 290 +- 50 +- 131 +- 18 +- +- +- +- Hex Strings +- +- +- buttonGroup +- +- +- +- +- +- 420 +- 50 +- 131 +- 18 +- +- +- +- Text Strings +- +- +- buttonGroup +- +- +- +- +- +- +- 140 +- 44 +- 113 +- 22 +- +- +- +- +- +- +- 16 +- 42 +- 131 +- 22 +- +- +- +- Terminal Callsign +- +- +- +- +- +- 18 +- 12 +- 161 +- 21 +- +- +- +- Enable VARA Interface +- +- +- +- +- +- 180 +- 10 +- 23 +- 25 +- +- +- +- Qt::RightToLeft +- +- +- +- +- +- +- +- +- 270 +- 10 +- 131 +- 101 +- +- +- +- VARA Mode +- +- +- +- +- 10 +- 20 +- 121 +- 20 +- +- +- +- VARA HF +- +- +- true +- +- +- buttonGroup_4 +- +- +- +- +- +- 10 +- 43 +- 121 +- 20 +- +- +- +- VARA FM +- +- +- buttonGroup_4 +- +- +- +- +- +- 10 +- 66 +- 121 +- 20 +- +- +- +- VARA SAT +- +- +- buttonGroup_4 +- +- +- +- +- +- +- 410 +- 10 +- 131 +- 101 +- +- +- +- VARA HF BW +- +- +- +- +- 10 +- 20 +- 101 +- 20 +- +- +- +- 500 Hz +- +- +- buttonGroup_3 +- +- +- +- +- +- 10 +- 43 +- 101 +- 20 +- +- +- +- 2300 Hz +- +- +- true +- +- +- buttonGroup_3 +- +- +- +- +- +- 10 +- 66 +- 101 +- 21 +- +- +- +- 2750 Hz +- +- +- buttonGroup_3 +- +- +- +- +- +- +- +- +- +- +- +- +- ++ ++ ++ Dialog ++ ++ ++ ++ 0 ++ 0 ++ 571 ++ 589 ++ ++ ++ ++ VARA Configuration ++ ++ ++ ++ ++ 170 ++ 490 ++ 211 ++ 33 ++ ++ ++ ++ ++ 6 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ OK ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ 10 ++ 120 ++ 551 ++ 161 ++ ++ ++ ++ TNC Setup ++ ++ ++ ++ ++ 130 ++ 22 ++ 101 ++ 22 ++ ++ ++ ++ ++ ++ ++ 400 ++ 20 ++ 47 ++ 22 ++ ++ ++ ++ ++ ++ ++ 130 ++ 57 ++ 391 ++ 22 ++ ++ ++ ++ ++ ++ ++ 16 ++ 24 ++ 47 ++ 13 ++ ++ ++ ++ Host ++ ++ ++ ++ ++ ++ 286 ++ 19 ++ 47 ++ 22 ++ ++ ++ ++ Port ++ ++ ++ ++ ++ ++ 16 ++ 56 ++ 47 ++ 22 ++ ++ ++ ++ Path ++ ++ ++ ++ ++ ++ 130 ++ 91 ++ 391 ++ 22 ++ ++ ++ ++ ++ ++ ++ 16 ++ 90 ++ 101 ++ 22 ++ ++ ++ ++ Init Commands ++ ++ ++ ++ ++ ++ 80 ++ 120 ++ 371 ++ 31 ++ ++ ++ ++ You can specify more than one command, but the separator must be just a comma with no spaces ++ ++ ++ Qt::AlignCenter ++ ++ ++ true ++ ++ ++ ++ ++ ++ ++ 8 ++ 300 ++ 541 ++ 181 ++ ++ ++ ++ PTT Port ++ ++ ++ ++ ++ 150 ++ 20 ++ 111 ++ 22 ++ ++ ++ ++ ++ ++ ++ 20 ++ 23 ++ 131 ++ 16 ++ ++ ++ ++ Select PTT Port ++ ++ ++ ++ ++ ++ 20 ++ 80 ++ 121 ++ 22 ++ ++ ++ ++ PTT On String ++ ++ ++ ++ ++ ++ 150 ++ 83 ++ 247 ++ 22 ++ ++ ++ ++ ++ ++ ++ 150 ++ 114 ++ 247 ++ 22 ++ ++ ++ ++ ++ ++ ++ 20 ++ 112 ++ 121 ++ 22 ++ ++ ++ ++ PTT Off String ++ ++ ++ ++ ++ ++ 20 ++ 52 ++ 111 ++ 16 ++ ++ ++ ++ GPIO Pin Left ++ ++ ++ ++ ++ ++ 150 ++ 50 ++ 25 ++ 20 ++ ++ ++ ++ ++ ++ ++ 310 ++ 50 ++ 25 ++ 20 ++ ++ ++ ++ ++ ++ ++ 165 ++ 50 ++ 83 ++ 18 ++ ++ ++ ++ GPIO Pin Right ++ ++ ++ ++ ++ ++ 18 ++ 50 ++ 121 ++ 18 ++ ++ ++ ++ CAT Port Speed ++ ++ ++ ++ ++ ++ 150 ++ 50 ++ 47 ++ 20 ++ ++ ++ ++ ++ ++ ++ 290 ++ 22 ++ 131 ++ 18 ++ ++ ++ ++ RTS/DTR ++ ++ ++ buttonGroup_2 ++ ++ ++ ++ ++ ++ 420 ++ 22 ++ 121 ++ 18 ++ ++ ++ ++ CAT ++ ++ ++ buttonGroup_2 ++ ++ ++ ++ ++ ++ 150 ++ 50 ++ 121 ++ 20 ++ ++ ++ ++ ++ ++ ++ 20 ++ 50 ++ 111 ++ 18 ++ ++ ++ ++ CM108 VID/PID ++ ++ ++ ++ ++ ++ 290 ++ 50 ++ 131 ++ 18 ++ ++ ++ ++ Hex Strings ++ ++ ++ buttonGroup ++ ++ ++ ++ ++ ++ 420 ++ 50 ++ 131 ++ 18 ++ ++ ++ ++ Text Strings ++ ++ ++ buttonGroup ++ ++ ++ ++ ++ ++ ++ 140 ++ 44 ++ 113 ++ 22 ++ ++ ++ ++ ++ ++ ++ 16 ++ 42 ++ 131 ++ 22 ++ ++ ++ ++ Terminal Callsign ++ ++ ++ ++ ++ ++ 18 ++ 12 ++ 161 ++ 21 ++ ++ ++ ++ Enable VARA Interface ++ ++ ++ ++ ++ ++ 180 ++ 10 ++ 23 ++ 25 ++ ++ ++ ++ Qt::RightToLeft ++ ++ ++ ++ ++ ++ ++ ++ ++ 270 ++ 10 ++ 131 ++ 101 ++ ++ ++ ++ VARA Mode ++ ++ ++ ++ ++ 10 ++ 20 ++ 121 ++ 20 ++ ++ ++ ++ VARA HF ++ ++ ++ true ++ ++ ++ buttonGroup_4 ++ ++ ++ ++ ++ ++ 10 ++ 43 ++ 121 ++ 20 ++ ++ ++ ++ VARA FM ++ ++ ++ buttonGroup_4 ++ ++ ++ ++ ++ ++ 10 ++ 66 ++ 121 ++ 20 ++ ++ ++ ++ VARA SAT ++ ++ ++ buttonGroup_4 ++ ++ ++ ++ ++ ++ ++ 410 ++ 10 ++ 131 ++ 101 ++ ++ ++ ++ VARA HF BW ++ ++ ++ ++ ++ 10 ++ 20 ++ 101 ++ 20 ++ ++ ++ ++ 500 Hz ++ ++ ++ buttonGroup_3 ++ ++ ++ ++ ++ ++ 10 ++ 43 ++ 101 ++ 20 ++ ++ ++ ++ 2300 Hz ++ ++ ++ true ++ ++ ++ buttonGroup_3 ++ ++ ++ ++ ++ ++ 10 ++ 66 ++ 101 ++ 21 ++ ++ ++ ++ 2750 Hz ++ ++ ++ buttonGroup_3 ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/YAPPRxSize.ui ++++ qttermtcp-0.0.0.79/YAPPRxSize.ui +@@ -1,116 +1,116 @@ +- +- +- SizeDialog +- +- +- +- 0 +- 0 +- 243 +- 157 +- +- +- +- Dialog +- +- +- +- +- 20 +- 80 +- 181 +- 33 +- +- +- +- +- 6 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- 0 +- +- +- +- +- OK +- +- +- +- +- +- +- Cancel +- +- +- +- +- +- +- +- +- 20 +- 30 +- 81 +- 20 +- +- +- +- Max RX Size +- +- +- +- +- +- 120 +- 30 +- 61 +- 20 +- +- +- +- +- +- +- +- okButton +- clicked() +- SizeDialog +- accept() +- +- +- 278 +- 253 +- +- +- 96 +- 254 +- +- +- +- +- cancelButton +- clicked() +- SizeDialog +- reject() +- +- +- 369 +- 253 +- +- +- 179 +- 282 +- +- +- +- +- ++ ++ ++ SizeDialog ++ ++ ++ ++ 0 ++ 0 ++ 243 ++ 157 ++ ++ ++ ++ Dialog ++ ++ ++ ++ ++ 20 ++ 80 ++ 181 ++ 33 ++ ++ ++ ++ ++ 6 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ 0 ++ ++ ++ ++ ++ OK ++ ++ ++ ++ ++ ++ ++ Cancel ++ ++ ++ ++ ++ ++ ++ ++ ++ 20 ++ 30 ++ 81 ++ 20 ++ ++ ++ ++ Max RX Size ++ ++ ++ ++ ++ ++ 120 ++ 30 ++ 61 ++ 20 ++ ++ ++ ++ ++ ++ ++ ++ okButton ++ clicked() ++ SizeDialog ++ accept() ++ ++ ++ 278 ++ 253 ++ ++ ++ 96 ++ 254 ++ ++ ++ ++ ++ cancelButton ++ clicked() ++ SizeDialog ++ reject() ++ ++ ++ 369 ++ 253 ++ ++ ++ 179 ++ 282 ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/ax25.c ++++ qttermtcp-0.0.0.79/ax25.c +@@ -1,3245 +1,3245 @@ +-/* +-Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO +- +-This file is part of QtSoundModem +- +-QtSoundModem is free software: you can redistribute it and/or modify +-it under the terms of the GNU General Public License as published by +-the Free Software Foundation, either version 3 of the License, or +-(at your option) any later version. +- +-QtSoundModem is distributed in the hope that it will be useful, +-but WITHOUT ANY WARRANTY; without even the implied warranty of +-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-GNU General Public License for more details. +- +-You should have received a copy of the GNU General Public License +-along with QtSoundModem. If not, see http://www.gnu.org/licenses +- +-*/ +- +-// UZ7HO Soundmodem Port by John Wiseman G8BPQ +- +-// This is a simplified version for QtTermTCP +- +-#include "ax25.h" +-#include +- +-extern int KISSChecksum; +- +-#ifdef WIN32 +- +-__declspec(dllimport) unsigned short __stdcall htons(__in unsigned short hostshort); +-__declspec(dllimport) unsigned short __stdcall ntohs(__in unsigned short hostshort); +- +-#else +- +-#define strtok_s strtok_r +-#include +-#endif +- +-void decode_frame(Byte * frame, int len, Byte * path, string * data, +- Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id, +- Byte * rpt, Byte * pf, Byte * cr); +- +-void SetSessLabel(void * Sess, char * label); +-void setMenus(int State); +-void MHPROC(unsigned char * Packet, int Len); +-/* +- +-unit ax25; +- +-interface +- +-uses classes,sysutils,windows; +- +- procedure get_exclude_list(line: string; var list: TStringList); +- procedure get_exclude_frm(line: string; var list: TStringList); +- procedure get_monitor_path(path: string; var mycall,corrcall,digi: string); +- procedure get_call(src_call: string; var call: string); +- procedure get_call_fm_path(path: string; var callto,callfrom: string); +- procedure set_corrcall(snd_ch,port: byte; path: string); +- procedure set_mycall(snd_ch,port: byte; path: string); +- procedure set_digi(snd_ch,port: byte; path: string); +- procedure decode_frame(frame: string; var path,data: string; var pid,nr,ns,f_type,f_id: byte; var rpt,pf,cr: boolean); +- procedure del_incoming_mycalls(src_call: string); +- procedure del_incoming_mycalls_by_sock(socket: integer); +- procedure ax25_info_init(snd_ch,port: byte); +- procedure write_ax25_info(snd_ch,port: byte); +- procedure clr_frm_win(snd_ch,port: byte); +- procedure ax25_init; +- procedure ax25_free; +- function dec2hex(value: byte): string; +- function get_corrcall(path: string): string; +- function get_mycall(path: string): string; +- function get_digi(path: string): string; +- function is_excluded_call(snd_ch: byte; path: string): boolean; +- function is_excluded_frm(snd_ch,f_id: byte; data: string): boolean; +- function is_last_digi(path: string): boolean; +- function is_digi(snd_ch,port: byte; path: string): boolean; +- function is_corrcall(snd_ch,port: byte; path: string): boolean; +- function is_mycall(snd_ch,port: byte; path: string): boolean; +- function is_correct_path(path: string; pid: byte): boolean; +- function direct_addr(path: string): string; +- function reverse_addr(path: string): string; +- function reverse_digi(path: string): string; +- function number_digi(path: string): byte; +- function info_pid(pid: byte): string; +- function get_fcs(var data: string; len: word): word; +- function set_addr(path: string; rpt,cr: boolean): string; +- function set_ctrl(nr,ns,f_type,f_id: byte; pf: boolean): byte; +- function make_frame(data,path: string; pid,nr,ns,f_type,f_id: byte; rpt,pf,cr: boolean): string; +- function get_incoming_socket_by_call(src_call: string): integer; +- function add_incoming_mycalls(socket: integer; src_call: string): boolean; +- function in_list_incoming_mycall(path: string): boolean; +- function get_UTC_time: string; +- function parse_NETROM(data: string; f_id: byte): string; +- function parse_IP(data: string): string; +- function parse_ARP(data: string): string; +- function add_raw_frames(snd_ch: byte; frame: string; var buf: TStringList): boolean; +- function scrambler(in_buf: string): string; +- function my_indexof(var l: TStringList; s: string): integer; +- +- +-const +- port_num=32; +- PKT_ERR=17; //Minimum packet size, bytes +- I_MAX=7; //Maximum number of packets +- B_IDX_MAX=256; +- ADDR_MAX_LEN=10; +- FRAME_FLAG=126; +- // Status flags +- STAT_NO_LINK=0; +- STAT_LINK=1; +- STAT_CHK_LINK=2; +- STAT_WAIT_ANS=3; +- STAT_TRY_LINK=4; +- STAT_TRY_UNLINK=5; +- // Ñmd,Resp,Poll,Final,Digipeater flags +- SET_P=TRUE; +- SET_F=FALSE; +- SET_C=TRUE; +- SET_R=FALSE; +- SET_NO_RPT=FALSE; +- SET_RPT=TRUE; +- // Frame ID flags +- I_FRM=0; +- S_FRM=1; +- U_FRM=2; +- I_I=0; +- S_RR=1; +- S_RNR=5; +- S_REJ=9; +- U_SABM=47; +- U_DISC=67; +- U_DM=15; +- U_UA=99; +- U_FRMR=135; +- U_UI=3; +- // PID flags +- PID_X25=$01; // 00000001-CCIT X25 PLP +- PID_SEGMENT=$08; // 00001000-Segmentation fragment +- PID_TEXNET=$C3; // 11000011-TEXNET Datagram Protocol +- PID_LQ=$C4; // 11001000-Link Quality Protocol +- PID_APPLETALK=$CA; // 11001010-Appletalk +- PID_APPLEARP=$CB; // 11001011-Appletalk ARP +- PID_IP=$CC; // 11001100-ARPA Internet Protocol +- PID_ARP=$CD; // 11001101-ARPA Address Resolution Protocol +- PID_NET_ROM=$CF; // 11001111-NET/ROM +-*/ +- +-#define ADDR_MAX_LEN 10 +-#define PID_NO_L3 0xF0; // 11110000-No Level 3 Protocol +- +- +-unsigned short CRCTable[256] = { +- 0, 4489, 8978, 12955, 17956, 22445, 25910, 29887, +- 35912, 40385, 44890, 48851, 51820, 56293, 59774, 63735, +- 4225, 264, 13203, 8730, 22181, 18220, 30135, 25662, +- 40137, 36160, 49115, 44626, 56045, 52068, 63999, 59510, +- 8450, 12427, 528, 5017, 26406, 30383, 17460, 21949, +- 44362, 48323, 36440, 40913, 60270, 64231, 51324, 55797, +- 12675, 8202, 4753, 792, 30631, 26158, 21685, 17724, +- 48587, 44098, 40665, 36688, 64495, 60006, 55549, 51572, +- 16900, 21389, 24854, 28831, 1056, 5545, 10034, 14011, +- 52812, 57285, 60766, 64727, 34920, 39393, 43898, 47859, +- 21125, 17164, 29079, 24606, 5281, 1320, 14259, 9786, +- 57037, 53060, 64991, 60502, 39145, 35168, 48123, 43634, +- 25350, 29327, 16404, 20893, 9506, 13483, 1584, 6073, +- 61262, 65223, 52316, 56789, 43370, 47331, 35448, 39921, +- 29575, 25102, 20629, 16668, 13731, 9258, 5809, 1848, +- 65487, 60998, 56541, 52564, 47595, 43106, 39673, 35696, +- 33800, 38273, 42778, 46739, 49708, 54181, 57662, 61623, +- 2112, 6601, 11090, 15067, 20068, 24557, 28022, 31999, +- 38025, 34048, 47003, 42514, 53933, 49956, 61887, 57398, +- 6337, 2376, 15315, 10842, 24293, 20332, 32247, 27774, +- 42250, 46211, 34328, 38801, 58158, 62119, 49212, 53685, +- 10562, 14539, 2640, 7129, 28518, 32495, 19572, 24061, +- 46475, 41986, 38553, 34576, 62383, 57894, 53437, 49460, +- 14787, 10314, 6865, 2904, 32743, 28270, 23797, 19836, +- 50700, 55173, 58654, 62615, 32808, 37281, 41786, 45747, +- 19012, 23501, 26966, 30943, 3168, 7657, 12146, 16123, +- 54925, 50948, 62879, 58390, 37033, 33056, 46011, 41522, +- 23237, 19276, 31191, 26718, 7393, 3432, 16371, 11898, +- 59150, 63111, 50204, 54677, 41258, 45219, 33336, 37809, +- 27462, 31439, 18516, 23005, 11618, 15595, 3696, 8185, +- 63375, 58886, 54429, 50452, 45483, 40994, 37561, 33584, +- 31687, 27214, 22741, 18780, 15843, 11370, 7921, 3960 }; +- +- +-unsigned short pkt_raw_min_len = 8; +-int stat_r_mem = 0; +- +-struct TKISSMode_t KISS; +- +- +-TAX25Port AX25Port[4][port_num]; +- +-TStringList KISS_acked[4]; +-TStringList KISS_iacked[4]; +- +-typedef struct registeredCalls_t +-{ +- UCHAR myCall[7]; // call in ax.25 +- void * socket; +- +-} registeredCalls; +- +- +-TStringList list_incoming_mycalls; // list strings containing a registered call +- +- +-boolean busy = 0; +-boolean dcd[5] = { 0 ,0 ,0, 0 }; +- +-boolean tx = 0; +- +-int stdtones = 0; +-int fullduplex = 0; +- +-UCHAR diddles = 0; +- +-word MEMRecovery[5] = { 200,200,200,200 }; +-int NonAX25[5] = { 0 }; +- +-boolean dyn_frack[4] = { FALSE,FALSE,FALSE,FALSE }; +-Byte recovery[4] = { 0,0,0,0 }; +-Byte users[4] = { 0,0,0,0 }; +- +-short txtail[5] = { 50, 50, 50, 50, 50 }; +-short txdelay[5] = { 400, 400, 400, 400, 400 }; +-int sendTXDelay[4] = { 0, 0, 0, 0 }; +- +- +-short modem_def[5] = { 1, 1, 1, 1, 1 }; +- +-int emph_db[5] = { 0, 0, 0, 0, 0 }; +-UCHAR emph_all[5] = { 0, 0, 0, 0, 0 }; +- +-boolean KISS_opt[4] = { FALSE, FALSE, FALSE, FALSE }; +-int resptime[4] = { 1500,1500,1500,1500 }; +-int slottime[4] = { 100,100,100,100 }; +-int persist[4] = { 100,100,100,100 }; +-int kisspaclen[4] = { 128,128,128,128 }; +-int fracks[4] = { 10,10,10,10 }; +-int frack_time[4] = { 5,5,5,5 }; +-int idletime[4] = { 180,180,180,180 }; +-int redtime[4] = { 0,0,0,0 }; +-int IPOLL[4] = { 30,30,30,30 }; +-int maxframe[4] = { 4,4,4,4 }; +-int TXFrmMode[4] = { 1,1,1,1 }; +-int max_frame_collector[4] = { 6,6,6,6 }; +- +- +-char MyDigiCall[4][512] = { "","","","" }; +-char exclude_callsigns[4][512] = { "","","","" }; +-char exclude_APRS_frm[4][512] = { "","","","" }; +- +-TStringList list_exclude_callsigns[4]; +-TStringList list_exclude_APRS_frm[4]; +-TStringList list_digi_callsigns[4]; +- +-Byte xData[256]; +-Byte xEncoded[256]; +-Byte xDecoded[256]; +- +-int frame_count = 0; +-int single_frame_count = 0; +- +-/* +- mydigi: string; +- //// end of user params +- addr: string[70]; +- ctrl: byte; +- pid: byte=PID_NO_L3; +- fcs: word; +- data: string; +- frame: string; +- +-implementation +- +-uses ax25_l2,sm_main; +- +-*/ +- +-char * strlop(char * buf, char delim) +-{ +- // Terminate buf at delim, and return rest of string +- +- char * ptr = strchr(buf, delim); +- +- if (ptr == NULL) return NULL; +- +- *(ptr)++ = 0; +- return ptr; +-} +- +-void Debugprintf(const char * format, ...) +-{ +- char Mess[10000]; +- va_list(arglist); +- +- va_start(arglist, format); +- vsprintf(Mess, format, arglist); +- WriteDebugLog(Mess); +- +- return; +-} +- +- +- +-void AX25_conn(TAX25Port * AX25Sess, int snd_ch, Byte mode) +-{ +- UNUSED(snd_ch); +- char Msg[128]; +- int Len = 0; +- +- switch (mode) +- { +- case MODE_OTHER: +- +- Len = sprintf(Msg, "Incoming KISS Connection from %s\r", AX25Sess->corrcall); +- break; +- +- case MODE_OUR: +- +- Len = sprintf(Msg, "Connected To %s\r", AX25Sess->corrcall); +- break; +- +- }; +- +- SendtoTerm(AX25Sess->Sess, Msg, Len); +- SetSessLabel(AX25Sess->Sess, AX25Sess->corrcall); +- setMenus(1); +-} +- +-void send_data_buf(TAX25Port * AX25Sess, int nr); +- +-void SendtoAX25(void * conn, Byte * Msg, int Len) +-{ +- TAX25Port * AX25Sess; +- AX25Sess = (TAX25Port * )conn; +- +- // Need to enforce PacLen +- +- if (AX25Sess) +- { +- int n; +- +- while (Len) +- { +- string * data = newString(); +- +- if (Len > kisspaclen[0]) +- n = kisspaclen[0]; +- else +- n = Len; +- +- stringAdd(data, Msg, n); +- Add(&AX25Sess->in_data_buf, data); +- +- Len -= n; +- Msg += n; +- } +- send_data_buf(AX25Sess, AX25Sess->vs); +- } +-} +- +- +- +- +- +-void scrambler(UCHAR * in_buf, int Len) +-{ +- integer i; +- word sreg; +- Byte a = 0, k; +- +- sreg = 0x1ff; +- +- for (i = 0; i < Len; i++) +- { +- for (k = 0; k < 8; k++) +- { +- +- // a: = (a shr 1) or (sreg and 1 shl 7); +- +- a = (a >> 1) | ((sreg & 1) << 7); +- +- // sreg: = (sreg shl 4 and $200) xor (sreg shl 8 and $200) or (sreg shr 1); +- +- +- sreg = (((sreg << 4) & 0x200) ^ ((sreg << 8) & 0x200)) | (sreg >> 1); +- } +- in_buf[i] = in_buf[i] ^ a; +- } +-} +- +- +-/* +-function parse_ARP(data: string): string; +- +-function get_callsign(data: string): string; +-var +- i: integer; +- s: string; +- a: byte; +-begin +- s:=''; +- if length(data)=7 then +- begin +- for i:=1 to 6 do +- begin +- a:=ord(data[i]) shr 1; +- if (a in [$30..$39,$41..$5A]) then s:=s+chr(a); +- end; +- a:=ord(data[7]) shr 1 and 15; +- if a>0 then s:=s+'-'+inttostr(a); +- end +- else +- begin +- if length(data)>0 then +- begin +- for i:=1 to length(data) do +- if i=1 then s:=dec2hex(ord(data[i])) else s:=s+':'+dec2hex(ord(data[i])); +- end; +- end; +- if s<>'' then s:=s+' '; +- result:=s; +-end; +- +-function get_IP(data: string): string; +-var +- i: integer; +- s: string; +-begin +- s:=''; +- if length(data)>0 then +- begin +- for i:=1 to length(data) do +- if i=1 then s:=inttostr(ord(data[i])) else s:=s+'.'+inttostr(ord(data[i])); +- end; +- if s<>'' then s:=s+' '; +- result:=s; +-end; +- +-const +- opcode: array [0..3] of string = ('ARP Request','ARP Response','RARP Request','RARP Response'); +-var +- oper: word; +- hlen,plen: byte; +- sha,spa,tha,tpa: string; +- s: string; +- i: word; +-begin +- s:=data; +- if length(data)>7 then +- begin +- hlen:=ord(data[5]); +- plen:=ord(data[6]); +- oper:=(ord(data[7]) shl 8 or ord(data[8])) and 2; +- i:=9; sha:=get_callsign(copy(data,i,hlen)); +- i:=i+hlen; spa:=get_ip(copy(data,i,plen)); +- i:=i+plen; tha:=get_callsign(copy(data,i,hlen)); +- i:=i+hlen; tpa:=get_ip(copy(data,i,plen)); +- s:=' [ARP] '+opcode[oper]+' from '+sha+spa+'to '+tha+tpa; +- end; +- result:=s; +-end; +- +-function parse_NETROM(data: string; f_id: byte): string; +- +- function deshift_AX25(data: string): string; +- var +- i: byte; +- call: string[6]; +- ssid: string[2]; +- begin +- result:=''; +- if length(data)<7 then exit; +- for i:=1 to 7 do data[i]:=chr(ord(data[i]) shr 1); +- call:=trim(copy(data,1,6)); +- ssid:=trim(inttostr(ord(data[7]) and 15)); +- if ssid='0' then result:=call else result:=call+'-'+ssid; +- end; +- +- function con_req_info(data: string): string; +- var +- s_call: string; +- d_call: string; +- w: byte; +- t_o: byte; +- begin +- result:=''; +- if length(data)>14 then +- begin +- w:=ord(data[1]); +- s_call:=deshift_AX25(copy(data,2,7)); +- d_call:=deshift_AX25(copy(data,9,7)); +- result:=' w='+inttostr(w)+' '+s_call+' at '+d_call; +- end; +- if length(data)>15 then +- begin +- t_o:=ord(data[16]); +- result:=result+' t/o '+inttostr(t_o); +- end; +- end; +- +- function con_ack_info(data: string): string; +- var +- w: byte; +- begin +- result:=''; +- if length(data)>0 then +- begin +- w:=ord(data[1]); +- result:=' w='+inttostr(w); +- end; +- end; +- +-const +- opcode_arr: array[0..7] of string = ('PE','CON REQ','CON ACK','DISC REQ','DISQ ACK','INFO','INFO ACK','RST'); +-var +- s: string; +- netrom_header: string; +- c_idx: byte; +- c_ID: byte; +- TX_nr: byte; +- RX_nr: byte; +- opcode: byte; +- s_call: string; +- s_node: string; +- d_call: string; +- d_node: string; +- b_call: string; +- r_s_nr: string; +- opc_flags: string; +- quality: byte; +- ttl: byte; +- hops: byte; +- rtt: word; +- inp3_nr_field: byte; +- inp3_field_len: byte; +- inp3_ext_fields: boolean; +-begin +- s:=data; +- if length(data)>0 then +- begin +- if data[1]=#$FF then +- begin +- delete(data,1,1); +- //Nodes broadcasting +- if (f_id=U_UI) and (length(data)>5) then +- begin +- s_node:=copy(data,1,6); +- delete(data,1,6); +- s:='NODES broadcast from '+s_node+#13#10; +- while length(data)>20 do +- begin +- d_call:=deshift_AX25(copy(data,1,7)); +- d_node:=copy(data,8,6); +- b_call:=deshift_AX25(copy(data,14,7)); +- quality:=ord(data[21]); +- delete(data,1,21); +- s:=s+' '+d_node+':'+d_call+' via '+b_call+' Q='+inttostr(quality)+#13#10; +- end; +- end; +- // INP3 RIF +- if (f_id=I_I) and (length(data)>10) then +- begin +- s:='[INP3 RIF]'+#13#10; +- while length(data)>10 do +- begin +- d_call:=deshift_AX25(copy(data,1,7)); +- hops:=ord(data[8]); +- rtt:=(ord(data[9]) shl 8) or ord(data[10]); +- delete(data,1,10); +- inp3_ext_fields:=TRUE; +- inp3_nr_field:=0; +- while (length(data)>0) and inp3_ext_fields do +- begin +- inp3_field_len:=ord(data[1]); +- if inp3_field_len>0 then +- begin +- if (inp3_nr_field=0) and (length(data)>1) then +- begin +- if data[2]=#0 then d_call:=copy(data,3,inp3_field_len-2)+':'+d_call; // Copy alias +- end; +- delete(data,1,inp3_field_len); +- inc(inp3_nr_field); +- end +- else inp3_ext_fields:=FALSE; +- end; +- delete(data,1,1); +- s:=s+d_call+' hops='+inttostr(hops)+' rtt='+inttostr(rtt)+#13#10; +- end; +- end; +- end +- else +- begin +- // NETROM frames +- if length(data)>19 then +- begin +- s_call:=deshift_AX25(copy(data,1,7)); +- d_call:=deshift_AX25(copy(data,8,7)); +- ttl:=ord(data[15]); +- netrom_header:=copy(data,16,5); +- delete(data,1,20); +- c_idx:=ord(netrom_header[1]); +- c_ID:=ord(netrom_header[2]); +- TX_nr:=ord(netrom_header[3]); +- RX_nr:=ord(netrom_header[4]); +- opcode:=ord(netrom_header[5]); +- // Opcode flags +- opc_flags:=''; +- if opcode and 128 = 128 then opc_flags:=opc_flags+' C'; +- if opcode and 64 = 64 then opc_flags:=opc_flags+' N'; +- // +- s:=' [NETROM] '+s_call+' to '+d_call+' ttl='+inttostr(ttl)+' cct='+dec2hex(c_idx)+dec2hex(c_ID); +- r_s_nr:=' S'+inttostr(TX_nr)+' R'+inttostr(RX_nr); +- case (opcode and 7) of +- 0 : s:=s+' <'+opcode_arr[opcode and 7]+r_s_nr+'>'+#13#10+data; +- 1 : s:=s+' <'+opcode_arr[opcode and 7]+'>'+con_req_info(data); +- 2 : s:=s+' <'+opcode_arr[opcode and 7]+'>'+con_ack_info(data)+' my cct='+dec2hex(TX_nr)+dec2hex(RX_nr); +- 3 : s:=s+' <'+opcode_arr[opcode and 7]+'>'; +- 4 : s:=s+' <'+opcode_arr[opcode and 7]+'>'; +- 5 : s:=s+' <'+opcode_arr[opcode and 7]+r_s_nr+'>:'+#13#10+data; +- 6 : s:=s+' <'+opcode_arr[opcode and 7]+' R'+inttostr(RX_nr)+'>'+opc_flags; +- 7 : s:=s+' <'+opcode_arr[opcode and 7]+r_s_nr+'>'+#13#10+data; +- end; +- end; +- end; +- end; +- result:=s; +-end; +- +-function parse_IP(data: string): string; +- +- function parse_ICMP(var data: string): string; +- var +- ICMP_type: byte; +- ICMP_code: byte; +- s: string; +- begin +- result:=''; +- if length(data)>3 then +- begin +- ICMP_type:=ord(data[1]); +- ICMP_code:=ord(data[2]); +- delete(data,1,4); +- s:=' [ICMP] Type='+inttostr(ICMP_type)+' Code='+inttostr(ICMP_code)+#13#10; +- result:=s; +- end; +- end; +- +- function parse_TCP(var data: string): string; +- var +- s: string; +- src_port: string; +- dest_port: string; +- wnd: string; +- ihl: word; +- idl: word; +- flags: byte; +- seq: string; +- ack: string; +- s_flags: string; +- s_idl: string; +- begin +- result:=''; +- if length(data)>19 then +- begin +- src_port:=' src_port:'+inttostr((ord(data[1]) shl 8)+ord(data[2])); +- dest_port:=' dest_port:'+inttostr((ord(data[3]) shl 8)+ord(data[4])); +- seq:=' seq='+dec2hex(ord(data[5]))+dec2hex(ord(data[6]))+dec2hex(ord(data[7]))+dec2hex(ord(data[8])); +- ack:=' ack='+dec2hex(ord(data[9]))+dec2hex(ord(data[10]))+dec2hex(ord(data[11]))+dec2hex(ord(data[12])); +- ihl:=(ord(data[13]) shr 4)*4; +- idl:=length(data)-ihl; +- flags:=ord(data[14]); +- wnd:=' wnd='+inttostr((ord(data[15]) shl 8)+ord(data[16])); +- delete(data,1,ihl); +- // +- s_flags:=' '; +- if (flags and 32)=32 then s_flags:=s_flags+'URG '; +- if (flags and 16)=16 then s_flags:=s_flags+'ACK '; +- if (flags and 8)=8 then s_flags:=s_flags+'PSH '; +- if (flags and 4)=4 then s_flags:=s_flags+'RST '; +- if (flags and 2)=2 then s_flags:=s_flags+'SYN '; +- if (flags and 1)=1 then s_flags:=s_flags+'FIN '; +- // +- if idl>0 then s_idl:=' data='+inttostr(idl) else s_idl:=''; +- if (flags and 16)<>16 then ack:=''; +- // +- s:=' [TCP]'+src_port+dest_port+seq+ack+wnd+s_idl+s_flags+#13#10; +- result:=s; +- end; +- end; +- +- function parse_UDP(var data: string): string; +- var +- s: string; +- src_port: string; +- dest_port: string; +- idl: word; +- len: word; +- s_idl: string; +- begin +- result:=''; +- if length(data)>7 then +- begin +- src_port:=' src_port:'+inttostr((ord(data[1]) shl 8)+ord(data[2])); +- dest_port:=' dest_port:'+inttostr((ord(data[3]) shl 8)+ord(data[4])); +- len:=(ord(data[5]) shl 8)+ord(data[6]); +- idl:=len-8; +- delete(data,1,8); +- // +- if idl>0 then s_idl:=' data='+inttostr(idl) else s_idl:=''; +- // +- s:=' [UDP]'+src_port+dest_port+' len='+inttostr(len)+s_idl+#13#10; +- result:=s; +- end; +- end; +- +-const +- prot_idx=#1#6#17; +- prot_name: array [1..3] of string = ('ICMP','TCP','UDP'); +-var +- s: string; +- src_ip: string; +- dest_ip: string; +- s_prot: string; +- len: string; +- c_prot: char; +- ttl: string; +- offset: string; +- ihl: byte; +- p: byte; +- fragment_offset: word; +-begin +- s:=data; +- if length(data)>19 then +- begin +- ihl:=(ord(data[1]) and 15)*4; +- len:=' len='+inttostr((ord(data[3]) shl 8)+ord(data[4])); +- fragment_offset:=((ord(data[7]) shl 8)+ord(data[8])) shl 3; +- ttl:=' ttl='+inttostr(ord(data[9])); +- c_prot:=data[10]; +- src_ip:=' Fm '+inttostr(ord(data[13]))+'.'+inttostr(ord(data[14]))+'.'+inttostr(ord(data[15]))+'.'+inttostr(ord(data[16])); +- dest_ip:=' To '+inttostr(ord(data[17]))+'.'+inttostr(ord(data[18]))+'.'+inttostr(ord(data[19]))+'.'+inttostr(ord(data[20])); +- delete(data,1,ihl); +- // +- p:=pos(c_prot,prot_idx); +- if p>0 then s_prot:=' prot='+prot_name[p] else s_prot:=' prot=Type'+inttostr(ord(c_prot)); +- if fragment_offset>0 then offset:=' offset='+inttostr(fragment_offset) else offset:=''; +- s:=' [IP]'+src_ip+dest_ip+s_prot+ttl+len+offset+#13#10; +- if fragment_offset=0 then +- case p of +- 1 : s:=s+parse_ICMP(data); +- 2 : s:=s+parse_TCP(data); +- 3 : s:=s+parse_UDP(data); +- end; +- s:=s+data; +- end; +- result:=s; +-end; +- +-function get_UTC_time: string; +-var +- st: TSYSTEMTIME; +- sec,hour,minute: string; +-begin +- GetSystemTime(st); +- if st.wSecond<10 then sec:='0'+inttostr(st.wSecond) else sec:=inttostr(st.wSecond); +- if st.wMinute<10 then minute:='0'+inttostr(st.wMinute) else minute:=inttostr(st.wMinute); +- if st.wHour<10 then Hour:='0'+inttostr(st.wHour) else Hour:=inttostr(st.wHour); +- result:=hour+':'+minute+':'+sec; +-end; +- +-function dec2hex(value: byte): string; +-const +- hex='0123456789ABCDEF'; +-var +- lo,hi: byte; +-begin +- lo:=value and 15; +- hi:=value shr 4; +- result:=hex[hi+1]+hex[lo+1]; +-end; +- +-*/ +- +-unsigned short get_fcs(UCHAR * Data, unsigned short len) +-{ +- unsigned short i; +- unsigned short result; +- +- result = 0xFFFF; +- +- if (len == 0) +- return result; +- +- for (i = 0; i < len; i++) +- result = (result >> 8) ^ CRCTable[(result ^ Data[i]) & 0xff]; +- +- +- result ^= 0xffff; +- +- return result; +-} +- +- +-unsigned short CRCTAB[256] = { +- 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, +- 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, +- 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, +- 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, +- 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, +- 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, +-0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, +-0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, +-0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, +-0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, +-0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, +-0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, +-0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, +-0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, +-0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, +-0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, +-0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, +-0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, +-0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, +-0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, +-0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, +-0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, +-0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, +-0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, +-0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, +-0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, +-0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, +-0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, +-0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, +-0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, +-0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, +-0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +-}; +- +-unsigned short int compute_crc(unsigned char *buf, int len) +-{ +- unsigned short fcs = 0xffff; +- int i; +- +- for (i = 0; i < len; i++) +- fcs = (fcs >> 8) ^ CRCTAB[(fcs ^ buf[i]) & 0xff]; +- +- fcs ^= 0xffff; +- +- return fcs; +-} +- +- +- +-int get_addr(char * Calls, UCHAR * AXCalls) +-{ +- // CONVERT CALL + OPTIONAL DIGI STRING (Comma separated) TO AX25, RETURN +- // CONVERTED STRING IN AXCALLS. Return FALSE if invalied +- +- Byte * axptr = AXCalls; +- char * ptr, *Context; +- int n = 8; // Max digis +- +- memset(AXCalls, 0, 72); +- +- ptr = strtok_s(Calls, " ,", &Context); +- +- if (ptr == NULL) +- return FALSE; +- +- // First field is Call +- +- if (ConvToAX25(ptr, axptr) == 0) +- return FALSE; +- +- axptr += 7; +- +- ptr = strtok_s(NULL, " ,", &Context); +- +- if (ptr == 0 || ConvToAX25(ptr, axptr) == 0) +- return FALSE; +- +- axptr += 7; +- +- ptr = strtok_s(NULL, " ,", &Context); +- +- while (ptr && n--) +- { +- // NEXT FIELD = COULD BE CALLSIGN, VIA, +- +- if (memcmp(ptr, "VIA", (int)strlen(ptr)) == 0) +- { +- } //skip via +- else +- { +- // Convert next digi +- +- if (ConvToAX25(ptr, axptr) == 0) +- return FALSE; +- +- axptr += 7; +- } +- +- ptr = strtok_s(NULL, " ,", &Context); +- } +- +- axptr[-1] |= 1; // Set end of address +- +- return axptr - AXCalls; +-} +- +-Byte set_ctrl(Byte nr, Byte ns, Byte f_type, Byte f_id, boolean pf) +-{ +- Byte pf_bit, ctrl; +- +- ctrl = 0; +- pf_bit = 0; +- +- if (pf) +- pf_bit = 16; +- +- switch (f_type) +- { +- case I_FRM: +- +- ctrl = (nr << 5) + pf_bit + (ns << 1); +- break; +- +- case S_FRM: +- +- ctrl = (nr << 5) + pf_bit + f_id; +- break; +- +- case U_FRM: +- +- ctrl = f_id + pf_bit; +- } +- +- return ctrl; +-} +- +-string * make_frame(string * data, Byte * axaddr, Byte pid, Byte nr, Byte ns, Byte f_type, Byte f_id, boolean rpr, boolean pf, boolean cr) +-{ +- UNUSED(rpr); +- +- Byte ctrl; +- +- string * frame = newString(); +- int addrlen; +- Byte addr[80]; +- +- frame->Data[0] = 0; // Lower software expects a kiss control byte here +- frame->Length = 1; +- +- ctrl = set_ctrl(nr, ns, f_type, f_id, pf); +- +- addrlen = strlen((char *)axaddr); +- +- memcpy(addr, axaddr, addrlen); +- +- if (cr) +- addr[6] |= 0x80; // Set Command Bit +- else +- addr[13] |= 0x80; // Set Response Bit +- +- +- switch (f_type) +- { +- case I_FRM: +- +- stringAdd(frame, addr, addrlen); +- stringAdd(frame, (Byte *)&ctrl, 1); +- stringAdd(frame, (Byte *)&pid, 1); +- stringAdd(frame, data->Data, data->Length); +- +- break; +- +- +- case S_FRM: +- +- stringAdd(frame, addr, addrlen); +- stringAdd(frame, (Byte *)&ctrl, 1); +- +- break; +- +- case U_FRM: +- +- if (f_id == U_UI) +- { +- stringAdd(frame, addr, addrlen); +- stringAdd(frame, (Byte *)&ctrl, 1); +- stringAdd(frame, (Byte *)&pid, 1); +- stringAdd(frame, data->Data, data->Length); +- } +- else if (f_id == U_FRMR) +- { +- stringAdd(frame, addr, addrlen); +- stringAdd(frame, (Byte *)&ctrl, 1); +- stringAdd(frame, data->Data, data->Length); +- } +- else +- { +- stringAdd(frame, addr, addrlen); +- stringAdd(frame, (Byte *)&ctrl, 1); +- } +- } +- +- return frame; +-} +- +- +-int add_raw_frames(int snd_ch, string * frame, TStringList * buf) +-{ +- UNUSED(snd_ch); +- +- string *s_data = newString(); +- Byte s_pid, s_nr, s_ns, s_f_type, s_f_id; +- Byte s_rpt, s_cr, s_pf; +- string *d_data = newString(); +- Byte d_pid, d_nr, d_ns, d_f_type, d_f_id; +- Byte d_rpt, d_cr, d_pf; +- +- Byte d_path[80]; +- Byte s_path[80]; +- +- boolean found_I; +- int i; +- +- unsigned char * framecontents; +- int Length; +- +- boolean result = TRUE; +- +- // Have to be careful as at this point frames have KISS Header and maybe trailer +- +- if (buf->Count > 0) +- { +- // Check for duplicate. Ok to just compare as copy will have same header +- +- if (my_indexof(buf, frame) >= 0) +- { +-// Debugprintf("KISSOptimise discarding duplicate frame"); +- return FALSE; +- } +- +- // Need to adjust for KISS bytes +- +- // Normally one, but ackmode has 3 on front and sizeof(void *) on end +- +- framecontents = frame->Data; +- Length = frame->Length; +- +- if ((framecontents[0] & 15) == 12) // Ackmode +- { +- framecontents += 3; +- Length -= (3 + sizeof(void *)); +- } +- else +- { +- framecontents++; +- Length--; +- } +- +- decode_frame(framecontents, Length, s_path, s_data, &s_pid, &s_nr, &s_ns, &s_f_type, &s_f_id, &s_rpt, &s_pf, &s_cr); +- +- found_I = FALSE; +- +- // check for multiple RR (r) +- +- if (s_f_id == S_FRM && s_cr == SET_R) +- { +- for (i = 0; i < buf->Count; i++) +- { +- framecontents = buf->Items[i]->Data; +- Length = buf->Items[i]->Length; +- +- if ((framecontents[0] & 15) == 12) // Ackmode +- { +- framecontents += 3; +- Length -= (3 + sizeof(void *)); +- } +- else +- { +- framecontents++; +- Length--; +- } +- +- decode_frame(framecontents, Length, d_path, d_data, &d_pid, &d_nr, &d_ns, &d_f_type, &d_f_id, &d_rpt, &d_pf, &d_cr); +- +- if (d_f_id == S_FRM && d_cr == SET_R && strcmp((char *)s_path, (char *)d_path) == 0) +- { +- Delete(buf, i); +- Debugprintf("KISSOptimise discarding unneeded RR(R%d)", d_nr); +- +- break; +- } +- } +- } +- +- +- // check for RR after I Frame +- +- if (s_f_id == S_FRM && s_cr == SET_C) +- { +- for (i = 0; i < buf->Count; i++) +- { +- framecontents = buf->Items[i]->Data; +- Length = buf->Items[i]->Length; +- +- if ((framecontents[0] & 15) == 12) // Ackmode +- { +- framecontents += 3; +- Length -= (3 + sizeof(void *)); +- } +- else +- { +- framecontents++; +- Length--; +- } +- +- decode_frame(framecontents, Length, d_path, d_data, &d_pid, &d_nr, &d_ns, &d_f_type, &d_f_id, &d_rpt, &d_pf, &d_cr); +- +- if (d_f_id == I_FRM && strcmp((char *)s_path, (char *)d_path) == 0) +- { +- found_I = TRUE; +- break; +- } +- } +- +- if (found_I) +- { +- Debugprintf("KISSOptimise discarding unneeded RR(C %d) after I frame", s_nr); +- result = FALSE; +- } +- } +- +- // check on I +- +- if (s_f_id == I_FRM) +- { +- for (i = 0; i < buf->Count; i++) +- { +- framecontents = buf->Items[i]->Data; +- Length = buf->Items[i]->Length; +- +- if ((framecontents[0] & 15) == 12) // Ackmode +- { +- framecontents += 3; +- Length -= (3 + sizeof(void *)); +- } +- else +- { +- framecontents++; +- Length--; +- } +- +- decode_frame(framecontents, Length, d_path, d_data, &d_pid, &d_nr, &d_ns, &d_f_type, &d_f_id, &d_rpt, &d_pf, &d_cr); +- +- if (strcmp((char *)s_path, (char *)d_path) == 0 && d_f_id == S_FRM && d_cr == SET_C) +- { +- Delete(buf, i); +- Debugprintf("KISSOptimise discarding unneeded RR(C %d)", d_nr); +- i--; // i was removed +- } +- } +- } +- } +- +- freeString(d_data); +- freeString(s_data); +- +- return result; +-} +- +-//////////////////////// Register incoming callsign //////////////////////////// +- +-// I think a call should only be registered on one socket (or we won't know where to send +-// incoming calls +- +-boolean add_incoming_mycalls(void * socket, char * src_call) +-{ +- registeredCalls * reg = malloc(sizeof(struct registeredCalls_t)); +- int i = 0; +- +- // Build a string containing Call and Socket +- +- ConvToAX25(src_call, reg->myCall); +- reg->socket = socket; +- +- if (list_incoming_mycalls.Count > 0) +- { +- for (i = 0; i < list_incoming_mycalls.Count; i++) +- { +- registeredCalls * check = (registeredCalls *)list_incoming_mycalls.Items[i]; +- +- if (memcmp(check->myCall, reg->myCall, 7) == 0) +- { +- // Update socket +- +- check->socket = socket; +- return FALSE; +- } +- } +- } +- +- Add(&list_incoming_mycalls, (string *)reg); +- return TRUE; +-} +- +- +- +-void del_incoming_mycalls(char * src_call) +-{ +- int i = 0; +- Byte axcall[7]; +- registeredCalls * reg; +- +- ConvToAX25(src_call, axcall); +- +- while (i < list_incoming_mycalls.Count) +- { +- reg = (registeredCalls *)list_incoming_mycalls.Items[i]; +- { +- if (memcmp(reg->myCall, axcall, 7) == 0) +- { +- // cant use Delete as stringlist doesn't contain strings +- +- TStringList * Q = &list_incoming_mycalls; +- int Index = i; +- +- free(Q->Items[Index]); +- +- Q->Count--; +- +- while (Index < Q->Count) +- { +- Q->Items[Index] = Q->Items[Index + 1]; +- Index++; +- } +- +- return; +- } +- } +- i++; +- } +-} +- +- +-void del_incoming_mycalls_by_sock(void * socket) +-{ +- int i = 0, snd_ch, port; +- registeredCalls * reg; +- +- while (i < list_incoming_mycalls.Count) +- { +- reg = (registeredCalls *)list_incoming_mycalls.Items[i]; +- { +- if (reg->socket == socket) +- { +- // cant use Delete as stringlist doesn't contain strings +- +- TStringList * Q = &list_incoming_mycalls; +- int Index = i; +- +- free(Q->Items[Index]); +- +- Q->Count--; +- +- while (Index < Q->Count) +- { +- Q->Items[Index] = Q->Items[Index + 1]; +- Index++; +- } +- +- //Delete(&list_incoming_mycalls, i); +- } +- else +- i++; +- } +- } +- +- // Should clear all connections on socket +- +- for (snd_ch = 0; snd_ch < 4; snd_ch++) +- { +- for (port = 0; port < port_num; port++) +- { +- TAX25Port * AX25Sess = &AX25Port[snd_ch][port]; +- +- if (AX25Sess->socket == socket) +- { +- if (AX25Sess->status != STAT_NO_LINK) +- { +- // Shouldn't we send DM? -0 try it +- +- set_DM(snd_ch, AX25Sess->ReversePath); +- +- rst_timer(AX25Sess); +- rst_values(AX25Sess); +- +- AX25Sess->status = STAT_NO_LINK; +- } +- AX25Sess->socket = 0; +- } +- } +- } +-} +- +- +-/* +-function get_incoming_socket_by_call(src_call: string): integer; +-var +- i: integer; +- found: boolean; +- socket: integer; +- call,ssid: string; +- a_call: array[0..1] of string; +-begin +- socket:=-1; +- i:=0; +- found:=FALSE; +- try explode(a_call,'-',src_call,2); except end; +- call:=trim(a_call[0]); +- if a_call[1]<>'' then ssid:=a_call[1] else ssid:='0'; +- if list_incoming_mycalls.Count>0 then +- repeat +- if (call+'-'+ssid)=list_incoming_mycalls.Strings[i] then +- begin socket:=strtoint(list_incoming_mycalls_sock.Strings[i]); found:=TRUE; end; +- inc(i); +- until found or (i=list_incoming_mycalls.Count); +- result:=socket; +-end; +-*/ +- +- +- +-void * in_list_incoming_mycall(Byte * path) +-{ +- // See if to call is in registered calls list +- +- int i = 0; +- registeredCalls * check; // list_incoming_mycalls contains registeredCalls, not Strings +- +- while (i < list_incoming_mycalls.Count) +- { +- check = (registeredCalls *)list_incoming_mycalls.Items[i]; +- +- if (memcmp(check->myCall, path, 7) == 0) +- return check->socket; +- +- i++; +- } +- +- return NULL; +-} +- +-/* +-//////////////////////////////////////////////////////////////////////////////// +- +-function is_corrcall(snd_ch,port: byte; path: string): boolean; +-var +- call,ssid: string; +-begin +- call:=trim(copy(path,8,6)); +- ssid:=copy(path,14,1); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; +- call:=call+'-'+ssid; +- if call=AX25Sess->corrcall then result:=TRUE else result:=FALSE; +-end; +- +-function is_mycall(snd_ch,port: byte; path: string): boolean; +-var +- call,ssid: string; +-begin +- call:=trim(copy(path,1,6)); +- ssid:=copy(path,7,1); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; +- call:=call+'-'+ssid; +- if call=AX25Sess->mycall then result:=TRUE else result:=FALSE; +-end; +- +-function is_digi(snd_ch,port: byte; path: string): boolean; +-var +- digi,call,ssid: string; +-begin +- digi:=''; +- if length(path)>14 then +- begin +- delete(path,1,14); +- repeat +- call:=trim(copy(path,1,6)); +- ssid:=copy(path,7,1); +- delete(path,1,7); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) +- else ssid:='0'; +- if path<>'' then digi:=digi+call+'-'+ssid+',' +- else digi:=digi+call+'-'+ssid; +- until path=''; +- end; +- if digi=AX25Sess->digi then result:=TRUE else result:=FALSE; +-end; +-*/ +- +-// Check if laast digi used +- +-boolean is_last_digi(Byte *path) +-{ +- int len = strlen((char *)path); +- +- if (len == 14) +- return TRUE; +- +- if ((path[len - 1] & 128) == 128) +- return TRUE; +- +- return FALSE; +-} +- +- +- +-/* +-function get_corrcall(path: string): string; +-var +- call,ssid: string; +-begin +- call:=trim(copy(path,8,6)); +- ssid:=copy(path,14,1); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; +- call:=call+'-'+ssid; +- result:=call; +-end; +- +-function get_mycall(path: string): string; +-var +- call,ssid: string; +-begin +- call:=trim(copy(path,1,6)); +- ssid:=copy(path,7,1); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; +- call:=call+'-'+ssid; +- result:=call; +-end; +- +-function get_digi(path: string): string; +-var +- digi,call,ssid: string; +-begin +- digi:=''; +- if length(path)>14 then +- begin +- delete(path,1,14); +- repeat +- call:=trim(copy(path,1,6)); +- ssid:=copy(path,7,1); +- delete(path,1,7); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) +- else ssid:='0'; +- if path<>'' then digi:=digi+call+'-'+ssid+',' +- else digi:=digi+call+'-'+ssid; +- until path=''; +- end; +- result:=digi; +-end; +-*/ +- +-boolean is_correct_path(Byte * path, Byte pid) +-{ +- Byte networks[] = { 6, 7, 8, 0xc4, 0xcc, 0xcd, 0xce, 0xcf, 0xf0 , 0 }; +- int i; +- +- +- if (pid == 0 || strchr((char *)networks, pid)) +- { +- // Validate calls +- +- // I think checking bottom bit of first 13 bytes is enough +- +- for (i = 0; i < 13; i++) +- { +- if ((*(path) & 1)) +- return FALSE; +- +- path++; +- } +- return TRUE; +- } +- return FALSE; +-} +- +- +-void get_exclude_list(char * line, TStringList * list) +-{ +- // Convert comma separated list of calls to ax25 format in list +- +- string axcall; +- +- char copy[512]; +- +- char * ptr, *Context; +- +- if (line[0] == 0) +- return; +- +- strcpy(copy, line); // copy as strtok messes with it +- strcat(copy, ","); +- +- axcall.Length = 8; +- axcall.AllocatedLength = 8; +- axcall.Data = malloc(8); +- +- memset(axcall.Data, 0, 8); +- +- ptr = strtok_s(copy, " ,", &Context); +- +- while (ptr) +- { +- if (ConvToAX25(ptr, axcall.Data) == 0) +- return; +- +- Add(list, duplicateString(&axcall)); +- +- ptr = strtok_s(NULL, " ,", &Context); +- } +-} +- +- +- +-void get_exclude_frm(char * line, TStringList * list) +-{ +- UNUSED(line); +- UNUSED(list); +- /* +- +- s: string; +- p: integer; +- n: integer; +-begin +- list.Clear; +- if line='' then exit; +- repeat +- p:=pos(',',line); +- if p>0 then +- begin +- s:=trim(copy(line,1,p-1)); +- if s<>'' then +- begin +- try n:=strtoint(s); except n:=-1; end; +- if n in [0..255] then list.Add(chr(n)); +- end; +- delete(line,1,p); +- end +- else +- begin +- s:=trim(line); +- if s<>'' then +- begin +- try n:=strtoint(s); except n:=-1; end; +- if n in [0..255] then list.Add(chr(n)); +- end; +- end; +- until p=0; +-end; +-*/ +-} +- +-/* +- +-function is_excluded_call(snd_ch: byte; path: string): boolean; +-var +- excluded: boolean; +- call: string; +- ssid: string; +-begin +- excluded:=FALSE; +- if (list_exclude_callsigns[snd_ch].Count>0) and (length(path)>13) then +- begin +- // Copy sender +- call:=trim(copy(path,8,6)); +- ssid:=copy(path,14,1); +- if ssid<>'' then call:=call+'-'+inttostr((ord(ssid[1]) and 15)); +- if list_exclude_callsigns[snd_ch].IndexOf(call)>-1 then excluded:=TRUE; +- end; +- result:=excluded; +-end; +- +-function is_excluded_frm(snd_ch,f_id: byte; data: string): boolean; +-var +- excluded: boolean; +-begin +- excluded:=FALSE; +- if list_exclude_APRS_frm[snd_ch].Count>0 then +- if f_id=U_UI then +- if length(data)>0 then +- if list_exclude_APRS_frm[snd_ch].IndexOf(data[1])>=0 then excluded:=TRUE; +- result:=excluded; +-end; +- +-procedure set_corrcall(snd_ch,port: byte; path: string); +-var +- call,ssid: string; +-begin +- call:=trim(copy(path,8,6)); +- ssid:=copy(path,14,1); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) +- else ssid:='0'; +- AX25Sess->corrcall:=call+'-'+ssid; +-end; +- +-procedure set_mycall(snd_ch,port: byte; path: string); +-var +- call,ssid: string; +-begin +- call:=trim(copy(path,1,6)); +- ssid:=copy(path,7,1); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) +- else ssid:='0'; +- AX25Sess->mycall:=call+'-'+ssid; +-end; +- +-procedure set_digi(snd_ch,port: byte; path: string); +-var +- digi,call,ssid: string; +-begin +- digi:=''; +- if length(path)>14 then +- begin +- delete(path,1,14); +- repeat +- call:=trim(copy(path,1,6)); +- ssid:=copy(path,7,1); +- delete(path,1,7); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) +- else ssid:='0'; +- if path<>'' then digi:=digi+call+'-'+ssid+',' +- else digi:=digi+call+'-'+ssid; +- until path=''; +- end; +- AX25Sess->digi:=digi; +-end; +- +-procedure get_call_fm_path(path: string; var callto,callfrom: string); +-var +- a_path: array [0..ADDR_MAX_LEN-1] of string; +- i: byte; +-begin +- for i:=0 to ADDR_MAX_LEN-1 do a_path[i]:=''; +- try explode(a_path,',',path,ADDR_MAX_LEN); except end; +- callto:=a_path[0]; +- callfrom:=a_path[1]; +-end; +- +-procedure get_call(src_call: string; var call: string); +-var +- a_call: array[0..1] of string; +- ssid: string; +-begin +- try explode(a_call,'-',src_call,2); except end; +- call:=trim(a_call[0]); +- if a_call[1]<>'' then ssid:=trim(a_call[1]) else ssid:='0'; +- call:=call+'-'+ssid; +-end; +-*/ +- +-int number_digi(unsigned char * path) +-{ +- UNUSED(path); +- int n = 0; +- +- // a_path: array [0..ADDR_MAX_LEN-3] of string; +- // for i:=0 to ADDR_MAX_LEN-3 do a_path[i]:=''; +- // try explode(a_path,',',path,ADDR_MAX_LEN-2); except end; +- // for i:=0 to ADDR_MAX_LEN-3 do if a_path[i]<>'' then inc(n); +- +- return n; +-} +- +- +- +-void get_monitor_path(Byte * path, char * mycall, char * corrcall, char * digi) +-{ +- char * digiptr = digi; +- +- digi[0] = 0; +- +- mycall[ConvFromAX25(path, mycall)] = 0; +- path += 7; +- corrcall[ConvFromAX25(path, corrcall)] = 0; +- +- while ((path[6] & 1) == 0) // End of call bit +- { +- if (digi != digiptr) +- *(digi++) = ','; +- +- path += 7; +- digi += ConvFromAX25(path, digi); +- +- if (((path[6] & 128) == 128)) // Digi'd +- *(digi++) = '*'; +- } +- *digi = 0; +-} +- +- +-/* +- +-function reverse_digi(path: string): string; +-var +- digi: string; +- a_path: array [0..ADDR_MAX_LEN-3] of string; +- i: word; +-begin +- digi:=''; +- for i:=0 to ADDR_MAX_LEN-3 do a_path[i]:=''; +- try explode(a_path,',',path,ADDR_MAX_LEN-2); except end; +- for i:=0 to ADDR_MAX_LEN-3 do +- if a_path[i]<>'' then +- begin +- if digi='' then digi:=a_path[i]+digi +- else digi:=a_path[i]+','+digi; +- end; +- result:=digi; +-end; +- +-function direct_addr(path: string): string; +-var +- s,call,ssid: string; +-begin +- s:=''; +- repeat +- call:=copy(path,1,6); +- delete(path,1,6); +- ssid:=copy(path,1,1); +- delete(path,1,1); +- if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)); +- if s='' then s:=call+'-'+ssid else s:=s+','+call+'-'+ssid; +- until path=''; +- result:=s; +-end; +-*/ +- +-void reverse_addr(Byte * path, Byte * revpath, int Len) +-{ +- Byte * ptr = path; +- Byte * copy = revpath; +- int endbit = Len - 1; +- int numdigis = (Len - 14) / 7; +- int i; +- +- if (Len < 14) +- return; +- +- Byte digis[57]; // 8 * 7 + null terminator +- memset(digis, 0, 57); +- Byte * digiptr = digis + 49; // Last Digi +- +- // remove end of address bit +- +- path[endbit] &= 0xFE; +- +- // first reverse dest and origin +- +- memcpy(copy + 7, ptr, 7); +- memcpy(copy, ptr + 7, 7); +- +- Len -= 14; +- ptr += 14; +- +- for (i = 0; i < numdigis; i++) +- { +- memcpy(digiptr, ptr, 7); +- ptr += 7; +- digiptr -= 7; +- } +- +- // Digiptr now points to new first digi +- +- memcpy(©[14], &digiptr[7], 7 * numdigis); +- +- path[endbit] |= 1; // restore original end bit +- +- copy[endbit++] |= 1; +- copy[endbit] = 0; // Null terminate +- +- return; +-} +- +- +- +-void decode_frame(Byte * frame, int len, Byte * path, string * data, +- Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id, +- Byte * rpt, Byte * pf, Byte * cr) +-{ +- int i; +- int addr_end; +- Byte ctrl; +- Byte * savepath = path; +- +- i = 0; +- addr_end = FALSE; +- +- *cr = SET_R; +- *pf = SET_F; +- data->Length = 0; +- ctrl = 0; +- *pid = 0; +- *nr = 0; +- *ns = 0; +- *f_type = 0; +- *f_id = 0; +- *rpt = FALSE; +- +- if ((frame[6] & 128) == 128 && (frame[13] & 128) == 0) +- *cr = SET_C; +- +- while (len > i && i < ADDR_MAX_LEN * 7) +- { +- *path++ = frame[i]; +- if ((frame[i] & 1) == 1) +- { +- addr_end = TRUE; +- break; +- } +- i++; +- } +- +- if (addr_end == 0) +- return; +- +- // clear the c and r bits from address +- +- savepath[6] &= 0x7f; // Mask +- savepath[13] &= 0x7f; // Mask +- +- *path = 0; // add null terminate +- +- i++; // Points to ctrl byte +- +- ctrl = frame[i]; +- +- if ((ctrl & 16) == 16) +- *pf = SET_P; +- +- if ((ctrl & 1) == 0) // I frame +- { +- *f_type = I_FRM; +- *f_id = I_I; +- *nr = (ctrl >> 5); +- *ns = (ctrl >> 1) & 7; +- } +- else +- { +- // Not I +- +- *f_type = U_FRM; +- +- *f_id = ctrl & 239; +- +- switch (ctrl & 15) +- { +- case S_RR: +- case S_RNR: +- case S_REJ: +- case S_SREJ: +- +- *f_type = S_FRM; +- } +- +- if (*f_type == S_FRM) +- { +- *f_id = ctrl & 15; +- *nr = ctrl >> 5; +- } +- } +- +- +- if (*f_id == I_I || *f_id == U_UI) +- { +- i++; +- *pid = frame[i]; +- i++; +- if (len > i) +- stringAdd(data, &frame[i], len - i); +- } +- else if (*f_id == U_FRMR) +- { +- *pid = 0; +- i++; +- if (len > i) +- stringAdd(data, &frame[i], len - i); +- } +-} +- +-void ax25_info_init(TAX25Port * AX25Sess) +-{ +- AX25Sess->info.stat_s_pkt = 0; +- AX25Sess->info.stat_s_byte = 0; +- AX25Sess->info.stat_r_pkt = 0; +- AX25Sess->info.stat_r_byte = 0; +- AX25Sess->info.stat_r_fc = 0; +- AX25Sess->info.stat_fec_count = 0; +- AX25Sess->info.stat_l_r_byte = 0; +- AX25Sess->info.stat_l_s_byte = 0; +- AX25Sess->info.stat_begin_ses = 0; +- AX25Sess->info.stat_end_ses = 0; +-} +- +- +-void clr_frm_win(TAX25Port * AX25Sess) +-{ +- int i; +- +- for (i = 0; i < 8; i++) +- initString(&AX25Sess->frm_win[i]); +-} +- +-void ax25_init() +-{ +- int snd_ch, port, i; +- +- for (i = 0; i < 4; i++) +- { +- initTStringList(&list_exclude_callsigns[i]); +- initTStringList(&list_exclude_APRS_frm[i]); +- initTStringList(&list_digi_callsigns[i]); +- initTStringList(&KISS_acked[i]); +- +- get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]); +- get_exclude_list(exclude_callsigns[i], &list_exclude_callsigns[i]); +- get_exclude_frm(exclude_APRS_frm[i], &list_exclude_APRS_frm[i]); +- +- } +- +- initTStringList(&list_incoming_mycalls); +-// initTStringList(&list_incoming_mycalls_sock); +- +- for (snd_ch = 0; snd_ch < 4; snd_ch++) +- { +- for (port = 0; port < port_num; port++) +- { +- TAX25Port * AX25Sess = &AX25Port[snd_ch][port]; +- +- AX25Sess->hi_vs = 0; +- AX25Sess->vs = 0; +- AX25Sess->vr = 0; +- AX25Sess->PID = PID_NO_L3; +- initTStringList(&AX25Sess->in_data_buf); +- initString(&AX25Sess->out_data_buf); +- AX25Sess->t1 = 0; +- AX25Sess->t2 = 0; +- AX25Sess->t3 = 0; +- AX25Sess->i_lo = 0; +- AX25Sess->i_hi = 0; +- AX25Sess->n1 = 0; +- AX25Sess->n2 = 0; +- AX25Sess->status = 0; +- AX25Sess->clk_frack = 0; +- initTStringList(&AX25Sess->frame_buf); +- initTStringList(&AX25Sess->I_frame_buf); +- initTStringList(&AX25Sess->frm_collector); +- AX25Sess->corrcall[0] = 0; +- AX25Sess->mycall[0] = 0; +- AX25Sess->digi[0] = 0; +- AX25Sess->Path[0] = 0; +- AX25Sess->kind[0] = 0; +- AX25Sess->socket = NULL; +- ax25_info_init(AX25Sess); +- clr_frm_win(AX25Sess); +- } +- } +-} +-/* +- +-procedure ax25_free; +-var +- snd_ch,port,i: byte; +-begin +- for snd_ch:=1 to 4 do +- for port:=0 to port_num-1 do +- begin +- AX25Sess->in_data_buf.Free; +- AX25Sess->frame_buf.Free; +- AX25Sess->I_frame_buf.Free; +- AX25Sess->frm_collector.Free; +- end; +- for i:=1 to 4 do +- begin +- all_frame_buf[i].Free; +- list_exclude_callsigns[i].Free; +- list_exclude_APRS_frm[i].Free; +- list_digi_callsigns[i].Free; +- end; +- list_incoming_mycalls.Free; +- list_incoming_mycalls_sock.Free; +-end; +-*/ +-void write_ax25_info(TAX25Port * AX25Sess) +-{ +- UNUSED(AX25Sess); +-} +- +-/*var +- new: boolean; +- t: text; +- s: string; +- time_ses: tdatetime; +- time_ses_sec: extended; +- call,mycall,spkt,sbyte,rpkt,rbyte,rfc,tcps,rcps,acps,startses,timeses: string; +-begin +- if stat_log then +- begin +- time_ses:=AX25Sess->info.stat_end_ses-AX25Sess->info.stat_begin_ses; +- time_ses_sec:=time_ses*86400; //âðåìÿ ñåññèè â ñåêóíäàõ +- if time_ses_sec<1 then exit; +- mycall:=copy(AX25Sess->mycall+' ',1,9); +- call:=copy(AX25Sess->corrcall+' ',1,9); +- spkt:=copy(inttostr(AX25Sess->info.stat_s_pkt)+' ',1,6); +- sbyte:=copy(inttostr(AX25Sess->info.stat_s_byte)+' ',1,9); +- rpkt:=copy(inttostr(AX25Sess->info.stat_r_pkt)+' ',1,6); +- rbyte:=copy(inttostr(AX25Sess->info.stat_r_byte)+' ',1,9); +- rfc:=copy(inttostr(AX25Sess->info.stat_r_fc)+' ',1,6); +- tcps:=copy(inttostr(round(AX25Sess->info.stat_s_byte/time_ses_sec))+' ',1,5); +- rcps:=copy(inttostr(round(AX25Sess->info.stat_r_byte/time_ses_sec))+' ',1,5); +- acps:=copy(inttostr(round(AX25Sess->info.stat_s_byte/time_ses_sec+AX25Sess->info.stat_r_byte/time_ses_sec))+' ',1,5); +- timeses:=FormatDateTime('hh:mm:ss',time_ses); +- startses:=FormatDateTime('dd-mm-yy hh:mm:ss',AX25Sess->info.stat_begin_ses); +- s:=mycall+' '+call+' '+spkt+' '+sbyte+' '+rpkt+' '+rbyte+' '+rfc+' '+tcps+' '+rcps+' '+acps+' '+startses+' '+timeses; +- assignfile(t,'log.txt'); +- if FileSearch('log.txt','')='' then new:=TRUE else new:=FALSE; +- if new then +- begin +- rewrite(t); +- writeln(t,'Mycall CorrCall TXPkt TXByte RXPkt RXByte FCPkt TXCPS RXCPS T.CPS Begin session SesTime'); +- writeln(t,'-------- --------- ------ --------- ------ --------- ------ ----- ----- ----- ----------------- --------'); +- end +- else append(t); +- if (AX25Sess->info.stat_s_byte>0) or (AX25Sess->info.stat_r_byte>0) then writeln(t,s); +- closefile(t); +- end; +-end; +- +-end. +-*/ +- +- +-/* +-Copyright 2001-2018 John Wiseman G8BPQ +- +-This file is part of LinBPQ/BPQ32. +- +-LinBPQ/BPQ32 is free software: you can redistribute it and/or modify +-it under the terms of the GNU General Public License as published by +-the Free Software Foundation, either version 3 of the License, or +-(at your option) any later version. +- +-LinBPQ/BPQ32 is distributed in the hope that it will be useful, +-but WITHOUT ANY WARRANTY; without even the implied warranty of +-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-GNU General Public License for more details. +- +-You should have received a copy of the GNU General Public License +-along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses +-*/ +- +- +- +-// Monitor Code - from moncode.asm +- +- +-#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND +-#define RESP 2 // CURRENT MSG IS RESPONSE +-#define VER1 1 // CURRENT MSG IS VERSION 1 +- +- +-#define UI 3 +-#define SABM 0x2F +-#define DISC 0x43 +-#define DM 0x0F +-#define UA 0x63 +-#define FRMR 0x87 +-#define RR 1 +-#define RNR 5 +-#define REJ 9 +- +-#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE +- +-#define NETROM_PID 0xCF +-#define IP_PID 0xCC +-#define ARP_PID 0xCD +- +-#define NODES_SIG 0xFF +- +-/* +- +-DllExport int APIENTRY SetTraceOptions(int mask, int mtxparam, int mcomparam) +-{ +- +- // Sets the tracing options for DecodeFrame. Mask is a bit +- // mask of ports to monitor (ie 101 binary will monitor ports +- // 1 and 3). MTX enables monitoring on transmitted frames. MCOM +- // enables monitoring of protocol control frames (eg SABM, UA, RR), +- // as well as info frames. +- +- MMASK = mask; +- MTX = mtxparam; +- MCOM = mcomparam; +- +- return (0); +-} +- +-DllExport int APIENTRY SetTraceOptionsEx(int mask, int mtxparam, int mcomparam, int monUIOnly) +-{ +- +- // Sets the tracing options for DecodeFrame. Mask is a bit +- // mask of ports to monitor (ie 101 binary will monitor ports +- // 1 and 3). MTX enables monitoring on transmitted frames. MCOM +- // enables monitoring of protocol control frames (eg SABM, UA, RR), +- // as well as info frames. +- +- +- MMASK = mask; +- MTX = mtxparam; +- MCOM = mcomparam; +- MUIONLY = monUIOnly; +- +- return 0; +-} +- +-*/ +- +-#define USHORT unsigned short +- +-UCHAR MCOM = 1; +-UCHAR MTX = 1; +-ULONG MMASK = 0xF; +-UCHAR MUIONLY = 0; +- +-#define SREJ 0x0D +-#define SABME 0x6F +-#define XID 0xAF +-#define TEST 0xE3 +- +-#define L4BUSY 0x80 // BNA - DONT SEND ANY MORE +-#define L4NAK 0x40 // NEGATIVE RESPONSE FLAG +-#define L4MORE 0x20 // MORE DATA FOLLOWS - FRAGMENTATION FLAG +- +-#define L4CREQ 1 // CONNECT REQUEST +-#define L4CACK 2 // CONNECT ACK +-#define L4DREQ 3 // DISCONNECT REQUEST +-#define L4DACK 4 // DISCONNECT ACK +-#define L4INFO 5 // INFORMATION +-#define L4IACK 6 // INFORMATION ACK +- +-//#pragma pack(1) +-#pragma pack(push, 1) +- +-struct myin_addr { +- union { +- struct { unsigned char s_b1, s_b2, s_b3, s_b4; } S_un_b; +- struct { unsigned short s_w1, s_w2; } S_un_w; +- unsigned long addr; +- }; +-}; +- +- +-typedef struct _IPMSG +-{ +- // FORMAT OF IP HEADER +- // +- // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) +- +- UCHAR VERLEN; // 4 BITS VERSION, 4 BITS LENGTH +- UCHAR TOS; // TYPE OF SERVICE +- USHORT IPLENGTH; // DATAGRAM LENGTH +- USHORT IPID; // IDENTIFICATION +- USHORT FRAGWORD; // 3 BITS FLAGS, 13 BITS OFFSET +- UCHAR IPTTL; +- UCHAR IPPROTOCOL; // HIGHER LEVEL PROTOCOL +- USHORT IPCHECKSUM; // HEADER CHECKSUM +- struct myin_addr IPSOURCE; +- struct myin_addr IPDEST; +- +- UCHAR Data; +- +-} IPMSG, *PIPMSG; +- +- +-typedef struct _TCPMSG +-{ +- +- // FORMAT OF TCP HEADER WITHIN AN IP DATAGRAM +- +- // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) +- +- USHORT SOURCEPORT; +- USHORT DESTPORT; +- +- ULONG SEQNUM; +- ULONG ACKNUM; +- +- UCHAR TCPCONTROL; // 4 BITS DATA OFFSET 4 RESERVED +- UCHAR TCPFLAGS; // (2 RESERVED) URG ACK PSH RST SYN FIN +- +- USHORT WINDOW; +- USHORT CHECKSUM; +- USHORT URGPTR; +- +- +-} TCPMSG, *PTCPMSG; +- +-typedef struct _UDPMSG +-{ +- +- // FORMAT OF UDP HEADER WITHIN AN IP DATAGRAM +- +- // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) +- +- USHORT SOURCEPORT; +- USHORT DESTPORT; +- USHORT LENGTH; +- USHORT CHECKSUM; +- UCHAR UDPData[0]; +- +-} UDPMSG, *PUDPMSG; +- +-// ICMP MESSAGE STRUCTURE +- +-typedef struct _ICMPMSG +-{ +- // FORMAT OF ICMP HEADER WITHIN AN IP DATAGRAM +- +- // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) +- +- UCHAR ICMPTYPE; +- UCHAR ICMPCODE; +- USHORT ICMPCHECKSUM; +- +- USHORT ICMPID; +- USHORT ICMPSEQUENCE; +- UCHAR ICMPData[0]; +- +-} ICMPMSG, *PICMPMSG; +- +- +-typedef struct _L3MESSAGE +-{ +- // +- // NETROM LEVEL 3 MESSAGE - WITHOUT L2 INFO +- // +- UCHAR L3SRCE[7]; // ORIGIN NODE +- UCHAR L3DEST[7]; // DEST NODE +- UCHAR L3TTL; // TX MONITOR FIELD - TO PREVENT MESSAGE GOING // ROUND THE NETWORK FOR EVER DUE TO ROUTING LOOP +-// +-// NETROM LEVEL 4 DATA +-// +- UCHAR L4INDEX; // TRANSPORT SESSION INDEX +- UCHAR L4ID; // TRANSPORT SESSION ID +- UCHAR L4TXNO; // TRANSMIT SEQUENCE NUMBER +- UCHAR L4RXNO; // RECEIVE (ACK) SEQ NUMBER +- UCHAR L4FLAGS; // FRAGMENTATION, ACK/NAK, FLOW CONTROL AND MSG TYPE BITS +- +- UCHAR L4DATA[236]; //DATA +- +-} L3MESSAGE, *PL3MESSAGE; +- +- +-typedef struct _MESSAGE +-{ +- // BASIC LINK LEVEL MESSAGE BUFFER LAYOUT +- +- struct _MESSAGE * CHAIN; +- +- UCHAR PORT; +- USHORT LENGTH; +- +- UCHAR DEST[7]; +- UCHAR ORIGIN[7]; +- +- // MAY BE UP TO 56 BYTES OF DIGIS +- +- UCHAR CTL; +- UCHAR PID; +- +- union +- { /* array named screen */ +- UCHAR L2DATA[256]; +- struct _L3MESSAGE L3MSG; +- }; +- +- +-}MESSAGE, *PMESSAGE; +- +-//#pragma pack() +-#pragma pack(pop) +- +-char * strlop(char * buf, char delim); +-UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, unsigned int msglen); +-char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen); +-UCHAR * DISPLAYIPDATAGRAM(IPMSG * IP, UCHAR * Output, int MsgLen); +-char * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output); +- +-int CountBits(unsigned long in) +-{ +- int n = 0; +- while (in) +- { +- if (in & 1) n++; +- in >>= 1; +- } +- return n; +-} +- +-BOOL ConvToAX25(char * callsign, unsigned char * ax25call) +-{ +- int i; +- +- memset(ax25call, 0x40, 6); // in case short +- ax25call[6] = 0x60; // default SSID +- +- for (i = 0; i < 7; i++) +- { +- if (callsign[i] == '-') +- { +- // +- // process ssid and return +- // +- i = atoi(&callsign[i + 1]); +- +- if (i < 16) +- { +- ax25call[6] |= i << 1; +- return (TRUE); +- } +- return (FALSE); +- } +- +- if (callsign[i] == 0 || callsign[i] == 13 || callsign[i] == ' ' || callsign[i] == ',') +- { +- // +- // End of call - no ssid +- // +- return (TRUE); +- } +- +- ax25call[i] = callsign[i] << 1; +- } +- +- // +- // Too many chars +- // +- +- return (FALSE); +-} +- +- +-int ConvFromAX25(unsigned char * incall, char * outcall) +-{ +- int in, out = 0; +- unsigned char chr; +- +- memset(outcall, 0x20, 10); +- +- for (in = 0; in < 6; in++) +- { +- chr = incall[in]; +- if (chr == 0x40) +- break; +- chr >>= 1; +- outcall[out++] = chr; +- } +- +- chr = incall[6]; // ssid +- +- if (chr == 0x42) +- { +- outcall[out++] = '-'; +- outcall[out++] = 'T'; +- return out; +- } +- +- if (chr == 0x44) +- { +- outcall[out++] = '-'; +- outcall[out++] = 'R'; +- return out; +- } +- +- chr >>= 1; +- chr &= 15; +- +- if (chr > 0) +- { +- outcall[out++] = '-'; +- if (chr > 9) +- { +- chr -= 10; +- outcall[out++] = '1'; +- } +- chr += 48; +- outcall[out++] = chr; +- } +- return (out); +-} +- +-TKISSMode ** KissConnections = NULL; +-int KISSConCount = 0; +- +-#define FEND 0xc0 +-#define FESC 0xDB +-#define TFEND 0xDC +-#define TFESC 0xDD +-#define KISS_ACKMODE 0x0C +-#define KISS_DATA 0 +- +-int KISS_encode(UCHAR * KISSBuffer, int port, string * frame, int TXMON); +- +-void KISS_init() +-{ +- int i; +- +- KISS.data_in = newString(); +- +- // initTStringList(KISS.socket); +- +- for (i = 0; i < 4; i++) +- { +- initTStringList(&KISS.buffer[i]); +- } +-} +- +-void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len); +- +-void KISSDataReceived(void * socket, unsigned char * data, int length) +-{ +- int i; +- unsigned char * ptr1, *ptr2; +- int Length; +- +- TKISSMode * KISS = NULL; +- +- if (KISSConCount == 0) +- return; +- +- for (i = 0; i < KISSConCount; i++) +- { +- if (KissConnections[i]->Socket == socket) +- { +- KISS = KissConnections[i]; +- break; +- } +- } +- +- if (KISS == NULL) +- return; +- +- stringAdd(KISS->data_in, data, length); +- +- if (KISS->data_in->Length > 10000) // Probably AGW Data on KISS Port +- { +- KISS->data_in->Length = 0; +- return; +- } +- +- ptr1 = KISS->data_in->Data; +- Length = KISS->data_in->Length; +- +- +- while ((ptr2 = memchr(ptr1, FEND, Length))) +- { +- int Len = (ptr2 - ptr1); +- +- if (Len == 0) +- { +- // Start of frame +- +- mydelete(KISS->data_in, 0, 1); +- +- ptr1 = KISS->data_in->Data; +- Length = KISS->data_in->Length; +- +- continue; +- } +- +- // Process Frame +- +- if (Len < 350) // Drop obviously corrupt frames +- ProcessKISSFrame(socket, ptr1, Len); +- +- mydelete(KISS->data_in, 0, Len + 1); +- +- ptr1 = KISS->data_in->Data; +- Length = KISS->data_in->Length; +- +- } +-} +- +-void analiz_frame(int snd_ch, string * frame, void * socket, boolean fecflag); +- +-void KISSSendtoServer(void * Socket, char * Data, int Length); +- +-void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len) +-{ +- int n = Len; +- UCHAR c; +- int ESCFLAG = 0; +- UCHAR * ptr1, *ptr2; +- int Chan; +- int Opcode; +- string * TXMSG; +- +- ptr1 = ptr2 = Msg; +- +- while (n--) +- { +- c = *(ptr1++); +- +- if (ESCFLAG) +- { +- // +- // FESC received - next should be TFESC or TFEND +- +- ESCFLAG = 0; +- +- if (c == TFESC) +- c = FESC; +- +- if (c == TFEND) +- c = FEND; +- +- } +- else +- { +- switch (c) +- { +- case FEND: +- +- // +- // Either start of message or message complete +- // +- +- // npKISSINFO->MSGREADY = TRUE; +- return; +- +- case FESC: +- +- ESCFLAG = 1; +- continue; +- +- } +- } +- +- // +- // Ok, a normal char +- // +- +- *(ptr2++) = c; +- +- } +- Len = ptr2 - Msg; +- +- Chan = (Msg[0] >> 4); +- Opcode = Msg[0] & 0x0f; +- +- if (Chan > 3) +- return; +- +- // This is a lot simpler than QtSM, as frames will always be immediately processed locally, so ack mode isn't needed. +- // but if enabled ack can be sent immediately +- // checksum if needed +- +- switch (Opcode) +- { +- case KISS_ACKMODE: +- { +- // send ack +- +- unsigned char ACK[16]; +- unsigned char * ackptr = ACK; +- +- *ackptr++ = FEND; +- *ackptr++ = Msg[0]; // opcode and channel +- +- *ackptr++ = Msg[1]; +- *ackptr++ = Msg[2]; // ACK Bytes +- *ackptr++ = FEND; +- +- KISSSendtoServer(socket, ACK, 5); +- +- // remove ack bytes +- +- memmove(&Msg[1], &Msg[3], Len - 2); +- +- // drop through to KISS Data +- +- Len -= 2; +- } +- case KISS_DATA: +- +- if (KISSChecksum) +- { +- // SUM MESSAGE, AND IF DUFF DISCARD. IF OK DECREMENT COUNT TO REMOVE SUM +- +- int sumlen = Len; +- char * ptr = &Msg[0]; +- UCHAR sum = 0; +- +- while (sumlen--) +- { +- sum ^= *(ptr++); +- } +- +- if (sum) +- { +- Debugprintf("KISS Checksum Error"); +- return; +- } +- +- Len--; // Remove Checksum +- } +- +- TXMSG = newString(); +- stringAdd(TXMSG, &Msg[1], Len - 1); // include Control +- +- MHPROC(TXMSG->Data, TXMSG->Length); +- +- analiz_frame(Chan, TXMSG, socket, 0); +- +- free(TXMSG); +- return; +- } +- +- // Still need to process kiss control frames +-} +- +- +-void KISS_add_stream(void * Socket) +-{ +- // Add a new connection. Called when QT accepts an incoming call} +- +- TKISSMode * KISS; +- +- KissConnections = realloc(KissConnections, (KISSConCount + 1) * sizeof(void *)); +- +- KISS = KissConnections[KISSConCount++] = malloc(sizeof(TKISSMode)); +- +- KISS->Socket = Socket; +- KISS->data_in = newString(); +- +-} +- +-void KISS_del_socket(void * socket) +-{ +- int i; +- +- TKISSMode * KISS = NULL; +- +- if (KISSConCount == 0) +- return; +- +- for (i = 0; i < KISSConCount; i++) +- { +- if (KissConnections[i]->Socket == socket) +- { +- KISS = KissConnections[i]; +- break; +- } +- } +- +- if (KISS == NULL) +- return; +- +- // Need to remove entry and move others down +- +- KISSConCount--; +- +- while (i < KISSConCount) +- { +- KissConnections[i] = KissConnections[i + 1]; +- i++; +- } +-} +- +-TAX25Port * get_free_port(int snd_ch); +- +-TAX25Port * KISSConnectOut(void * Sess, char * CallFrom, char * CallTo, char * Digis, int Chan, void * Socket) +-{ +- TAX25Port * AX25Sess = 0; +- char path[128]; +- Byte axpath[80]; +- +- AX25Sess = get_free_port(Chan); +- +- if (AX25Sess) +- { +- AX25Sess->snd_ch = Chan; +- AX25Sess->Sess = Sess; +- strcpy(AX25Sess->mycall, CallFrom); +- strcpy(AX25Sess->corrcall, CallTo); +- AX25Sess->PID = 0xf0; +- +- sprintf(path, "%s,%s", CallTo, CallFrom); +- +- if (Digis && Digis[0]) +- { +- strcat(path, ","); +- strcat(path, Digis); +- } +- +- AX25Sess->digi[0] = 0; +- +- // rst_timer(snd_ch, free_port); +- +- strcpy(AX25Sess->kind, "Outgoing"); +- AX25Sess->socket = Socket; +- +- AX25Sess->pathLen = get_addr(path, axpath); +- +- if (AX25Sess->pathLen == 0) +- return AX25Sess; // Invalid Path +- +- strcpy((char *)AX25Sess->Path, (char *)axpath); +- reverse_addr(axpath, AX25Sess->ReversePath, AX25Sess->pathLen); +- +- set_link(AX25Sess, AX25Sess->Path); // Sends SABM +- return AX25Sess; +- } +- return 0; +-} +- +- +- +-// Monitor Code - from moncode.asm +- +- +-#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND +-#define RESP 2 // CURRENT MSG IS RESPONSE +-#define VER1 1 // CURRENT MSG IS VERSION 1 +- +- +-#define UI 3 +-#define SABM 0x2F +-#define DISC 0x43 +-#define DM 0x0F +-#define UA 0x63 +-#define FRMR 0x87 +-#define RR 1 +-#define RNR 5 +-#define REJ 9 +- +-#define SREJ 0x0D +-#define SABME 0x6F +-#define XID 0xAF +-#define TEST 0xE3 +- +- +-#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE +- +-#define NETROM_PID 0xCF +-#define IP_PID 0xCC +-#define ARP_PID 0xCD +- +-#define NODES_SIG 0xFF +- +-char ShortDT[] = "HH:MM:SS"; +- +-int KISSLocalTime = 0; +-int KISSMonEnable = 0; +-int KISSMonNodes = 0; +- +-char * ShortDateTime() +-{ +- struct tm * tm; +- time_t NOW = time(NULL); +- +- if (KISSLocalTime) +- tm = localtime(&NOW); +- else +- tm = gmtime(&NOW); +- +- sprintf(ShortDT, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); +- return ShortDT; +-} +- +- +-char FrameData[1024] = ""; +- +-char * frame_monitor(string * frame, char * code, int tx_stat) +-{ +- char mon_frm[512]; +- char Path[256]; +- +- char * frm = "???"; +- Byte * datap; +- Byte _data[512] = ""; +- Byte * p_data = _data; +- int _datalen; +- char CallFrom[10], CallTo[10], Digi[80]; +- +- char TR = 'R'; +- char codestr[16] = ""; +- +- integer i; +- int len; +- +- +- Byte pid, nr, ns, f_type, f_id; +- Byte rpt, cr, pf; +- Byte path[80]; +- char c; +- const char * p; +- +- string * data = newString(); +- +- if (code[0] && strlen(code) < 14) +- sprintf(codestr, "[%s]", code); +- +- if (tx_stat) +- TR = 'T'; +- +- if (tx_stat) // TX frame has control byte +- +- decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); +- else +- decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); +- +- +- datap = data->Data; +- +- len = data->Length; +- +- if (pid == 0xCF) +- { +- if (datap[0] == 255) //Nodes broadcast +- { +- if (KISSMonNodes == 0) +- { +- freeString(data); +- return 0; +- } +- } +- } +- +- +- +- // data = parse_NETROM(data, f_id); +- // IP parsing +- // else if (pid == 0xCC) +- // data = parse_IP(data); +- // ARP parsing +- // else if (pid == 0xCD) +- // data = parse_ARP(data); +- // +- +- if (len > 0) +- { +- for (i = 0; i < len; i++) +- { +- if (datap[i] > 31 || datap[i] == 13 || datap[i] == 9) +- *(p_data++) = datap[i]; +- } +- } +- +- _datalen = p_data - _data; +- +- if (_datalen) +- { +- Byte * ptr = _data; +- i = 0; +- +- // remove successive cr or cr on end while (i < _datalen) +- +- while (i < _datalen) +- { +- if ((_data[i] == 13) && (_data[i + 1] == 13)) +- i++; +- else +- *(ptr++) = _data[i++]; +- } +- +- if (*(ptr - 1) == 13) +- ptr--; +- +- *ptr = 0; +- +- _datalen = ptr - _data; +- } +- +- get_monitor_path(path, CallTo, CallFrom, Digi); +- +- if (cr) +- { +- c = 'C'; +- if (pf) +- p = " P"; +- else p = ""; +- } +- else +- { +- c = 'R'; +- if (pf) +- p = " F"; +- else +- p = ""; +- } +- +- switch (f_id) +- { +- case I_I: +- +- frm = "I"; +- break; +- +- case S_RR: +- +- frm = "RR"; +- break; +- +- case S_RNR: +- +- frm = "RNR"; +- break; +- +- case S_REJ: +- +- frm = "REJ"; +- break; +- +- case S_SREJ: +- +- frm = "SREJ"; +- break; +- +- case U_SABM: +- +- frm = "SABM"; +- break; +- +- case SABME: +- +- frm = "SABME"; +- break; +- +- case U_DISC: +- +- frm = "DISC"; +- break; +- +- case U_DM: +- +- frm = "DM"; +- break; +- +- case U_UA: +- +- frm = "UA"; +- break; +- +- case U_FRMR: +- +- frm = "FRMR"; +- break; +- +- case U_UI: +- +- frm = "UI"; +- } +- +-// 07:29:42T G8BPQ - 2 > TEST Port = 20 < UI > : +-// helllo +-// 07:30: 8T G8BPQ - 2 > ID Port = 20 < UI C > : +-// Network node(BPQ) +- +- if (Digi[0]) +-// sprintf(Path, "Fm %s To %s Via %s <%s %c%s", CallFrom, CallTo, Digi, frm, c, p); +- sprintf(Path, "%s%c %s>%s,%s <%s %c%s", ShortDateTime(), TR, CallFrom, CallTo, Digi, frm, c, p); +- else +-// sprintf(Path, "Fm %s To %s <%s %c %s", CallFrom, CallTo, frm, c, p); +- sprintf(Path, "%s%c %s>%s <%s %c%s", ShortDateTime(), TR, CallFrom, CallTo, frm, c, p); +- +- +- switch (f_type) +- { +- case I_FRM: +- +- //mon_frm = Path + ctrl + ' R' + inttostr(nr) + ' S' + inttostr(ns) + ' pid=' + dec2hex(pid) + ' Len=' + inttostr(len) + ' >' + time_now + #13 + _data + #13#13; +- sprintf(mon_frm, "%s R%d S%d>%s\r%s\r", Path, nr, ns, codestr, _data); +- +- break; +- +- case U_FRM: +- +- if (f_id == U_UI) +- { +- sprintf(mon_frm, "%s>:\r%s\r", Path, _data); // "= Path + ctrl + '>' + time_now + #13; +- } +- else if (f_id == U_FRMR) +- { +- sprintf(mon_frm, "%s>%02x %02x %02x\r", Path, datap[0], datap[1], datap[2]); // "= Path + ctrl + '>' + time_now + #13; +- } +- else +- sprintf(mon_frm, "%s>%s\r", Path, codestr); // "= Path + ctrl + '>' + time_now + #13; +- +- break; +- +- case S_FRM: +- +- // mon_frm = Path + ctrl + ' R' + inttostr(nr) + ' >' + time_now + #13; +- sprintf(mon_frm, "%s R%d>%s\r", Path, nr, codestr); // "= Path + ctrl + '>' + time_now + #13; +- +- break; +- +- } +- sprintf(FrameData, "%s", mon_frm); +- +- freeString(data); +- return FrameData; +-} +- +-typedef struct _MHSTRUC +-{ +- UCHAR MHCALL[7]; +- UCHAR MHDIGIS[7][8]; +- time_t MHTIME; +- int MHCOUNT; +- unsigned char MHDIGI; +- char MHFreq[12]; +- char MHLocator[6]; +-} MHSTRUC, *PMHSTRUC; +- +- +-#define MHENTRIES 30 +- +-MHSTRUC MHEARD[(MHENTRIES + 1) * sizeof(MHSTRUC)] = { 0 }; +- +-int CompareCalls(UCHAR * c1, UCHAR * c2) +-{ +- // COMPARE AX25 CALLSIGNS IGNORING EXTRA BITS IN SSID +- +- if (memcmp(c1, c2, 6)) +- return FALSE; // No Match +- +- if ((c1[6] & 0x1e) == (c2[6] & 0x1e)) +- return TRUE; +- +- return FALSE; +-} +- +-static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +- +-void * MHWindow = 0; +-void WritetoMHWindow(char * Buffer); +-int KISSMH = 0; +- +-char * FormatMH(PMHSTRUC MH) +-{ +- struct tm * TM; +- static char MHTime[50]; +- time_t szClock; +- char LOC[7]; +- +- memcpy(LOC, MH->MHLocator, 6); +- LOC[6] = 0; +- +- szClock = MH->MHTIME; +-// else +-// szClock = time(NULL) - MH->MHTIME; +- +- TM = gmtime(&szClock); +- +- sprintf(MHTime, "%s %02d %.2d:%.2d:%.2d %s %s", +- month[TM->tm_mon], TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec, MH->MHFreq, LOC); +- +- return MHTime; +-} +- +- +- +- +-void MHPROC(unsigned char * Packet, int Len) +-{ +- PMHSTRUC MH = &MHEARD[0]; +- PMHSTRUC MHBASE = MH; +- int i; +- int OldCount = 0; +- char Freq[64] = ""; +- char DIGI = '*'; +- +- MESSAGE Frame; +- MESSAGE * Buffer = &Frame; +- +- memcpy(Buffer->DEST, Packet, Len); +- +- +- // if port has a freq associated with it use it +- +- +- // if (Buffer->ORIGIN[6] & 1) +- DIGI = 0; // Don't think we want to do this +- +-// See if in list +- +- for (i = 0; i < MHENTRIES; i++) +- { +- if ((MH->MHCALL[0] == 0) || (CompareCalls(Buffer->ORIGIN, MH->MHCALL) && MH->MHDIGI == DIGI)) // Spare or our entry +- { +- OldCount = MH->MHCOUNT; +- goto DoMove; +- } +- MH++; +- } +- +- // TABLE FULL AND ENTRY NOT FOUND - MOVE DOWN ONE, AND ADD TO TOP +- +- i = MHENTRIES - 1; +- +- // Move others down and add at front +-DoMove: +- if (i != 0) // First +- memmove(MHBASE + 1, MHBASE, i * sizeof(MHSTRUC)); +- +- memcpy(MHBASE->MHCALL, Buffer->ORIGIN, 7 * 9); // Save Digis +- MHBASE->MHDIGI = DIGI; +- MHBASE->MHTIME = time(NULL); +- MHBASE->MHCOUNT = ++OldCount; +- strcpy(MHBASE->MHFreq, Freq); +- MHBASE->MHLocator[0] = 0; +- +- if (MHWindow) +- { +- int count = MHENTRIES; +- int n; +- char Normcall[20]; +- char From[10]; +- char DigiList[100]; +- char * Output; +- int len; +- char Digi = 0; +- char MHPage[MHENTRIES * 100]; +- char * Bufferptr = MHPage; +- unsigned char * ptr; +- +- MH = &MHEARD[0]; +- +- // Note that the MHDIGIS field may contain rubbish. You have to check End of Address bit to find +- // how many digis there are +- +- Bufferptr += sprintf(Bufferptr, "Callsign Last heard Pkts RX via Digi\r"); +- Bufferptr += sprintf(Bufferptr, "\r"); +- +- while (count--) +- { +- if (MH->MHCALL[0] == 0) +- break; +- +- Digi = 0; +- +- len = ConvFromAX25(MH->MHCALL, Normcall); +- +- Normcall[len++] = MH->MHDIGI; +- Normcall[len++] = 0; +- +- n = 8; // Max number of digi-peaters +- +- ptr = &MH->MHCALL[6]; // End of Address bit +- +- Output = &DigiList[0]; +- +- if ((*ptr & 1) == 0) +- { +- // at least one digi +- +- strcpy(Output, "via "); +- Output += 4; +- +- while ((*ptr & 1) == 0) +- { +- // MORE TO COME +- +- From[ConvFromAX25(ptr + 1, From)] = 0; +- Output += sprintf((char *)Output, "%s", From); +- +- ptr += 7; +- n--; +- +- if (n == 0) +- break; +- +- // See if digi actioned - put a * on last actioned +- +- if (*ptr & 0x80) +- { +- if (*ptr & 1) // if last address, must need * +- { +- *(Output++) = '*'; +- Digi = '*'; +- } +- +- else +- if ((ptr[7] & 0x80) == 0) // Repeased by next? +- { +- *(Output++) = '*'; // No, so need * +- Digi = '*'; +- } +- +- } +- *(Output++) = ','; +- } +- *(--Output) = 0; // remove last comma +- } +- else +- *(Output) = 0; +- +- // if we used a digi set * on call and display via string +- +- +- if (Digi) +- Normcall[len++] = Digi; +- else +- DigiList[0] = 0; // Dont show list if not used +- +- Normcall[len++] = 0; +- +- ptr = FormatMH(MH); +- +- Bufferptr += sprintf(Bufferptr, "%-10s %-10s %-10d %-30s\r", Normcall, ptr, MH->MHCOUNT, DigiList); +- +- MH++; +- } +- +- WritetoMHWindow(MHPage); +- } +- return; +-} +- +- +- +- +- +- +- ++/* ++Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO ++ ++This file is part of QtSoundModem ++ ++QtSoundModem is free software: you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation, either version 3 of the License, or ++(at your option) any later version. ++ ++QtSoundModem is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with QtSoundModem. If not, see http://www.gnu.org/licenses ++ ++*/ ++ ++// UZ7HO Soundmodem Port by John Wiseman G8BPQ ++ ++// This is a simplified version for QtTermTCP ++ ++#include "ax25.h" ++#include ++ ++extern int KISSChecksum; ++ ++#ifdef WIN32 ++ ++__declspec(dllimport) unsigned short __stdcall htons(__in unsigned short hostshort); ++__declspec(dllimport) unsigned short __stdcall ntohs(__in unsigned short hostshort); ++ ++#else ++ ++#define strtok_s strtok_r ++#include ++#endif ++ ++void decode_frame(Byte * frame, int len, Byte * path, string * data, ++ Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id, ++ Byte * rpt, Byte * pf, Byte * cr); ++ ++void SetSessLabel(void * Sess, char * label); ++void setMenus(int State); ++void MHPROC(unsigned char * Packet, int Len); ++/* ++ ++unit ax25; ++ ++interface ++ ++uses classes,sysutils,windows; ++ ++ procedure get_exclude_list(line: string; var list: TStringList); ++ procedure get_exclude_frm(line: string; var list: TStringList); ++ procedure get_monitor_path(path: string; var mycall,corrcall,digi: string); ++ procedure get_call(src_call: string; var call: string); ++ procedure get_call_fm_path(path: string; var callto,callfrom: string); ++ procedure set_corrcall(snd_ch,port: byte; path: string); ++ procedure set_mycall(snd_ch,port: byte; path: string); ++ procedure set_digi(snd_ch,port: byte; path: string); ++ procedure decode_frame(frame: string; var path,data: string; var pid,nr,ns,f_type,f_id: byte; var rpt,pf,cr: boolean); ++ procedure del_incoming_mycalls(src_call: string); ++ procedure del_incoming_mycalls_by_sock(socket: integer); ++ procedure ax25_info_init(snd_ch,port: byte); ++ procedure write_ax25_info(snd_ch,port: byte); ++ procedure clr_frm_win(snd_ch,port: byte); ++ procedure ax25_init; ++ procedure ax25_free; ++ function dec2hex(value: byte): string; ++ function get_corrcall(path: string): string; ++ function get_mycall(path: string): string; ++ function get_digi(path: string): string; ++ function is_excluded_call(snd_ch: byte; path: string): boolean; ++ function is_excluded_frm(snd_ch,f_id: byte; data: string): boolean; ++ function is_last_digi(path: string): boolean; ++ function is_digi(snd_ch,port: byte; path: string): boolean; ++ function is_corrcall(snd_ch,port: byte; path: string): boolean; ++ function is_mycall(snd_ch,port: byte; path: string): boolean; ++ function is_correct_path(path: string; pid: byte): boolean; ++ function direct_addr(path: string): string; ++ function reverse_addr(path: string): string; ++ function reverse_digi(path: string): string; ++ function number_digi(path: string): byte; ++ function info_pid(pid: byte): string; ++ function get_fcs(var data: string; len: word): word; ++ function set_addr(path: string; rpt,cr: boolean): string; ++ function set_ctrl(nr,ns,f_type,f_id: byte; pf: boolean): byte; ++ function make_frame(data,path: string; pid,nr,ns,f_type,f_id: byte; rpt,pf,cr: boolean): string; ++ function get_incoming_socket_by_call(src_call: string): integer; ++ function add_incoming_mycalls(socket: integer; src_call: string): boolean; ++ function in_list_incoming_mycall(path: string): boolean; ++ function get_UTC_time: string; ++ function parse_NETROM(data: string; f_id: byte): string; ++ function parse_IP(data: string): string; ++ function parse_ARP(data: string): string; ++ function add_raw_frames(snd_ch: byte; frame: string; var buf: TStringList): boolean; ++ function scrambler(in_buf: string): string; ++ function my_indexof(var l: TStringList; s: string): integer; ++ ++ ++const ++ port_num=32; ++ PKT_ERR=17; //Minimum packet size, bytes ++ I_MAX=7; //Maximum number of packets ++ B_IDX_MAX=256; ++ ADDR_MAX_LEN=10; ++ FRAME_FLAG=126; ++ // Status flags ++ STAT_NO_LINK=0; ++ STAT_LINK=1; ++ STAT_CHK_LINK=2; ++ STAT_WAIT_ANS=3; ++ STAT_TRY_LINK=4; ++ STAT_TRY_UNLINK=5; ++ // Ñmd,Resp,Poll,Final,Digipeater flags ++ SET_P=TRUE; ++ SET_F=FALSE; ++ SET_C=TRUE; ++ SET_R=FALSE; ++ SET_NO_RPT=FALSE; ++ SET_RPT=TRUE; ++ // Frame ID flags ++ I_FRM=0; ++ S_FRM=1; ++ U_FRM=2; ++ I_I=0; ++ S_RR=1; ++ S_RNR=5; ++ S_REJ=9; ++ U_SABM=47; ++ U_DISC=67; ++ U_DM=15; ++ U_UA=99; ++ U_FRMR=135; ++ U_UI=3; ++ // PID flags ++ PID_X25=$01; // 00000001-CCIT X25 PLP ++ PID_SEGMENT=$08; // 00001000-Segmentation fragment ++ PID_TEXNET=$C3; // 11000011-TEXNET Datagram Protocol ++ PID_LQ=$C4; // 11001000-Link Quality Protocol ++ PID_APPLETALK=$CA; // 11001010-Appletalk ++ PID_APPLEARP=$CB; // 11001011-Appletalk ARP ++ PID_IP=$CC; // 11001100-ARPA Internet Protocol ++ PID_ARP=$CD; // 11001101-ARPA Address Resolution Protocol ++ PID_NET_ROM=$CF; // 11001111-NET/ROM ++*/ ++ ++#define ADDR_MAX_LEN 10 ++#define PID_NO_L3 0xF0; // 11110000-No Level 3 Protocol ++ ++ ++unsigned short CRCTable[256] = { ++ 0, 4489, 8978, 12955, 17956, 22445, 25910, 29887, ++ 35912, 40385, 44890, 48851, 51820, 56293, 59774, 63735, ++ 4225, 264, 13203, 8730, 22181, 18220, 30135, 25662, ++ 40137, 36160, 49115, 44626, 56045, 52068, 63999, 59510, ++ 8450, 12427, 528, 5017, 26406, 30383, 17460, 21949, ++ 44362, 48323, 36440, 40913, 60270, 64231, 51324, 55797, ++ 12675, 8202, 4753, 792, 30631, 26158, 21685, 17724, ++ 48587, 44098, 40665, 36688, 64495, 60006, 55549, 51572, ++ 16900, 21389, 24854, 28831, 1056, 5545, 10034, 14011, ++ 52812, 57285, 60766, 64727, 34920, 39393, 43898, 47859, ++ 21125, 17164, 29079, 24606, 5281, 1320, 14259, 9786, ++ 57037, 53060, 64991, 60502, 39145, 35168, 48123, 43634, ++ 25350, 29327, 16404, 20893, 9506, 13483, 1584, 6073, ++ 61262, 65223, 52316, 56789, 43370, 47331, 35448, 39921, ++ 29575, 25102, 20629, 16668, 13731, 9258, 5809, 1848, ++ 65487, 60998, 56541, 52564, 47595, 43106, 39673, 35696, ++ 33800, 38273, 42778, 46739, 49708, 54181, 57662, 61623, ++ 2112, 6601, 11090, 15067, 20068, 24557, 28022, 31999, ++ 38025, 34048, 47003, 42514, 53933, 49956, 61887, 57398, ++ 6337, 2376, 15315, 10842, 24293, 20332, 32247, 27774, ++ 42250, 46211, 34328, 38801, 58158, 62119, 49212, 53685, ++ 10562, 14539, 2640, 7129, 28518, 32495, 19572, 24061, ++ 46475, 41986, 38553, 34576, 62383, 57894, 53437, 49460, ++ 14787, 10314, 6865, 2904, 32743, 28270, 23797, 19836, ++ 50700, 55173, 58654, 62615, 32808, 37281, 41786, 45747, ++ 19012, 23501, 26966, 30943, 3168, 7657, 12146, 16123, ++ 54925, 50948, 62879, 58390, 37033, 33056, 46011, 41522, ++ 23237, 19276, 31191, 26718, 7393, 3432, 16371, 11898, ++ 59150, 63111, 50204, 54677, 41258, 45219, 33336, 37809, ++ 27462, 31439, 18516, 23005, 11618, 15595, 3696, 8185, ++ 63375, 58886, 54429, 50452, 45483, 40994, 37561, 33584, ++ 31687, 27214, 22741, 18780, 15843, 11370, 7921, 3960 }; ++ ++ ++unsigned short pkt_raw_min_len = 8; ++int stat_r_mem = 0; ++ ++struct TKISSMode_t KISS; ++ ++ ++TAX25Port AX25Port[4][port_num]; ++ ++TStringList KISS_acked[4]; ++TStringList KISS_iacked[4]; ++ ++typedef struct registeredCalls_t ++{ ++ UCHAR myCall[7]; // call in ax.25 ++ void * socket; ++ ++} registeredCalls; ++ ++ ++TStringList list_incoming_mycalls; // list strings containing a registered call ++ ++ ++boolean busy = 0; ++boolean dcd[5] = { 0 ,0 ,0, 0 }; ++ ++boolean tx = 0; ++ ++int stdtones = 0; ++int fullduplex = 0; ++ ++UCHAR diddles = 0; ++ ++word MEMRecovery[5] = { 200,200,200,200 }; ++int NonAX25[5] = { 0 }; ++ ++boolean dyn_frack[4] = { FALSE,FALSE,FALSE,FALSE }; ++Byte recovery[4] = { 0,0,0,0 }; ++Byte users[4] = { 0,0,0,0 }; ++ ++short txtail[5] = { 50, 50, 50, 50, 50 }; ++short txdelay[5] = { 400, 400, 400, 400, 400 }; ++int sendTXDelay[4] = { 0, 0, 0, 0 }; ++ ++ ++short modem_def[5] = { 1, 1, 1, 1, 1 }; ++ ++int emph_db[5] = { 0, 0, 0, 0, 0 }; ++UCHAR emph_all[5] = { 0, 0, 0, 0, 0 }; ++ ++boolean KISS_opt[4] = { FALSE, FALSE, FALSE, FALSE }; ++int resptime[4] = { 1500,1500,1500,1500 }; ++int slottime[4] = { 100,100,100,100 }; ++int persist[4] = { 100,100,100,100 }; ++int kisspaclen[4] = { 128,128,128,128 }; ++int fracks[4] = { 10,10,10,10 }; ++int frack_time[4] = { 5,5,5,5 }; ++int idletime[4] = { 180,180,180,180 }; ++int redtime[4] = { 0,0,0,0 }; ++int IPOLL[4] = { 30,30,30,30 }; ++int maxframe[4] = { 4,4,4,4 }; ++int TXFrmMode[4] = { 1,1,1,1 }; ++int max_frame_collector[4] = { 6,6,6,6 }; ++ ++ ++char MyDigiCall[4][512] = { "","","","" }; ++char exclude_callsigns[4][512] = { "","","","" }; ++char exclude_APRS_frm[4][512] = { "","","","" }; ++ ++TStringList list_exclude_callsigns[4]; ++TStringList list_exclude_APRS_frm[4]; ++TStringList list_digi_callsigns[4]; ++ ++Byte xData[256]; ++Byte xEncoded[256]; ++Byte xDecoded[256]; ++ ++int frame_count = 0; ++int single_frame_count = 0; ++ ++/* ++ mydigi: string; ++ //// end of user params ++ addr: string[70]; ++ ctrl: byte; ++ pid: byte=PID_NO_L3; ++ fcs: word; ++ data: string; ++ frame: string; ++ ++implementation ++ ++uses ax25_l2,sm_main; ++ ++*/ ++ ++char * strlop(char * buf, char delim) ++{ ++ // Terminate buf at delim, and return rest of string ++ ++ char * ptr = strchr(buf, delim); ++ ++ if (ptr == NULL) return NULL; ++ ++ *(ptr)++ = 0; ++ return ptr; ++} ++ ++void Debugprintf(const char * format, ...) ++{ ++ char Mess[10000]; ++ va_list(arglist); ++ ++ va_start(arglist, format); ++ vsprintf(Mess, format, arglist); ++ WriteDebugLog(Mess); ++ ++ return; ++} ++ ++ ++ ++void AX25_conn(TAX25Port * AX25Sess, int snd_ch, Byte mode) ++{ ++ UNUSED(snd_ch); ++ char Msg[128]; ++ int Len = 0; ++ ++ switch (mode) ++ { ++ case MODE_OTHER: ++ ++ Len = sprintf(Msg, "Incoming KISS Connection from %s\r", AX25Sess->corrcall); ++ break; ++ ++ case MODE_OUR: ++ ++ Len = sprintf(Msg, "Connected To %s\r", AX25Sess->corrcall); ++ break; ++ ++ }; ++ ++ SendtoTerm(AX25Sess->Sess, Msg, Len); ++ SetSessLabel(AX25Sess->Sess, AX25Sess->corrcall); ++ setMenus(1); ++} ++ ++void send_data_buf(TAX25Port * AX25Sess, int nr); ++ ++void SendtoAX25(void * conn, Byte * Msg, int Len) ++{ ++ TAX25Port * AX25Sess; ++ AX25Sess = (TAX25Port * )conn; ++ ++ // Need to enforce PacLen ++ ++ if (AX25Sess) ++ { ++ int n; ++ ++ while (Len) ++ { ++ string * data = newString(); ++ ++ if (Len > kisspaclen[0]) ++ n = kisspaclen[0]; ++ else ++ n = Len; ++ ++ stringAdd(data, Msg, n); ++ Add(&AX25Sess->in_data_buf, data); ++ ++ Len -= n; ++ Msg += n; ++ } ++ send_data_buf(AX25Sess, AX25Sess->vs); ++ } ++} ++ ++ ++ ++ ++ ++void scrambler(UCHAR * in_buf, int Len) ++{ ++ integer i; ++ word sreg; ++ Byte a = 0, k; ++ ++ sreg = 0x1ff; ++ ++ for (i = 0; i < Len; i++) ++ { ++ for (k = 0; k < 8; k++) ++ { ++ ++ // a: = (a shr 1) or (sreg and 1 shl 7); ++ ++ a = (a >> 1) | ((sreg & 1) << 7); ++ ++ // sreg: = (sreg shl 4 and $200) xor (sreg shl 8 and $200) or (sreg shr 1); ++ ++ ++ sreg = (((sreg << 4) & 0x200) ^ ((sreg << 8) & 0x200)) | (sreg >> 1); ++ } ++ in_buf[i] = in_buf[i] ^ a; ++ } ++} ++ ++ ++/* ++function parse_ARP(data: string): string; ++ ++function get_callsign(data: string): string; ++var ++ i: integer; ++ s: string; ++ a: byte; ++begin ++ s:=''; ++ if length(data)=7 then ++ begin ++ for i:=1 to 6 do ++ begin ++ a:=ord(data[i]) shr 1; ++ if (a in [$30..$39,$41..$5A]) then s:=s+chr(a); ++ end; ++ a:=ord(data[7]) shr 1 and 15; ++ if a>0 then s:=s+'-'+inttostr(a); ++ end ++ else ++ begin ++ if length(data)>0 then ++ begin ++ for i:=1 to length(data) do ++ if i=1 then s:=dec2hex(ord(data[i])) else s:=s+':'+dec2hex(ord(data[i])); ++ end; ++ end; ++ if s<>'' then s:=s+' '; ++ result:=s; ++end; ++ ++function get_IP(data: string): string; ++var ++ i: integer; ++ s: string; ++begin ++ s:=''; ++ if length(data)>0 then ++ begin ++ for i:=1 to length(data) do ++ if i=1 then s:=inttostr(ord(data[i])) else s:=s+'.'+inttostr(ord(data[i])); ++ end; ++ if s<>'' then s:=s+' '; ++ result:=s; ++end; ++ ++const ++ opcode: array [0..3] of string = ('ARP Request','ARP Response','RARP Request','RARP Response'); ++var ++ oper: word; ++ hlen,plen: byte; ++ sha,spa,tha,tpa: string; ++ s: string; ++ i: word; ++begin ++ s:=data; ++ if length(data)>7 then ++ begin ++ hlen:=ord(data[5]); ++ plen:=ord(data[6]); ++ oper:=(ord(data[7]) shl 8 or ord(data[8])) and 2; ++ i:=9; sha:=get_callsign(copy(data,i,hlen)); ++ i:=i+hlen; spa:=get_ip(copy(data,i,plen)); ++ i:=i+plen; tha:=get_callsign(copy(data,i,hlen)); ++ i:=i+hlen; tpa:=get_ip(copy(data,i,plen)); ++ s:=' [ARP] '+opcode[oper]+' from '+sha+spa+'to '+tha+tpa; ++ end; ++ result:=s; ++end; ++ ++function parse_NETROM(data: string; f_id: byte): string; ++ ++ function deshift_AX25(data: string): string; ++ var ++ i: byte; ++ call: string[6]; ++ ssid: string[2]; ++ begin ++ result:=''; ++ if length(data)<7 then exit; ++ for i:=1 to 7 do data[i]:=chr(ord(data[i]) shr 1); ++ call:=trim(copy(data,1,6)); ++ ssid:=trim(inttostr(ord(data[7]) and 15)); ++ if ssid='0' then result:=call else result:=call+'-'+ssid; ++ end; ++ ++ function con_req_info(data: string): string; ++ var ++ s_call: string; ++ d_call: string; ++ w: byte; ++ t_o: byte; ++ begin ++ result:=''; ++ if length(data)>14 then ++ begin ++ w:=ord(data[1]); ++ s_call:=deshift_AX25(copy(data,2,7)); ++ d_call:=deshift_AX25(copy(data,9,7)); ++ result:=' w='+inttostr(w)+' '+s_call+' at '+d_call; ++ end; ++ if length(data)>15 then ++ begin ++ t_o:=ord(data[16]); ++ result:=result+' t/o '+inttostr(t_o); ++ end; ++ end; ++ ++ function con_ack_info(data: string): string; ++ var ++ w: byte; ++ begin ++ result:=''; ++ if length(data)>0 then ++ begin ++ w:=ord(data[1]); ++ result:=' w='+inttostr(w); ++ end; ++ end; ++ ++const ++ opcode_arr: array[0..7] of string = ('PE','CON REQ','CON ACK','DISC REQ','DISQ ACK','INFO','INFO ACK','RST'); ++var ++ s: string; ++ netrom_header: string; ++ c_idx: byte; ++ c_ID: byte; ++ TX_nr: byte; ++ RX_nr: byte; ++ opcode: byte; ++ s_call: string; ++ s_node: string; ++ d_call: string; ++ d_node: string; ++ b_call: string; ++ r_s_nr: string; ++ opc_flags: string; ++ quality: byte; ++ ttl: byte; ++ hops: byte; ++ rtt: word; ++ inp3_nr_field: byte; ++ inp3_field_len: byte; ++ inp3_ext_fields: boolean; ++begin ++ s:=data; ++ if length(data)>0 then ++ begin ++ if data[1]=#$FF then ++ begin ++ delete(data,1,1); ++ //Nodes broadcasting ++ if (f_id=U_UI) and (length(data)>5) then ++ begin ++ s_node:=copy(data,1,6); ++ delete(data,1,6); ++ s:='NODES broadcast from '+s_node+#13#10; ++ while length(data)>20 do ++ begin ++ d_call:=deshift_AX25(copy(data,1,7)); ++ d_node:=copy(data,8,6); ++ b_call:=deshift_AX25(copy(data,14,7)); ++ quality:=ord(data[21]); ++ delete(data,1,21); ++ s:=s+' '+d_node+':'+d_call+' via '+b_call+' Q='+inttostr(quality)+#13#10; ++ end; ++ end; ++ // INP3 RIF ++ if (f_id=I_I) and (length(data)>10) then ++ begin ++ s:='[INP3 RIF]'+#13#10; ++ while length(data)>10 do ++ begin ++ d_call:=deshift_AX25(copy(data,1,7)); ++ hops:=ord(data[8]); ++ rtt:=(ord(data[9]) shl 8) or ord(data[10]); ++ delete(data,1,10); ++ inp3_ext_fields:=TRUE; ++ inp3_nr_field:=0; ++ while (length(data)>0) and inp3_ext_fields do ++ begin ++ inp3_field_len:=ord(data[1]); ++ if inp3_field_len>0 then ++ begin ++ if (inp3_nr_field=0) and (length(data)>1) then ++ begin ++ if data[2]=#0 then d_call:=copy(data,3,inp3_field_len-2)+':'+d_call; // Copy alias ++ end; ++ delete(data,1,inp3_field_len); ++ inc(inp3_nr_field); ++ end ++ else inp3_ext_fields:=FALSE; ++ end; ++ delete(data,1,1); ++ s:=s+d_call+' hops='+inttostr(hops)+' rtt='+inttostr(rtt)+#13#10; ++ end; ++ end; ++ end ++ else ++ begin ++ // NETROM frames ++ if length(data)>19 then ++ begin ++ s_call:=deshift_AX25(copy(data,1,7)); ++ d_call:=deshift_AX25(copy(data,8,7)); ++ ttl:=ord(data[15]); ++ netrom_header:=copy(data,16,5); ++ delete(data,1,20); ++ c_idx:=ord(netrom_header[1]); ++ c_ID:=ord(netrom_header[2]); ++ TX_nr:=ord(netrom_header[3]); ++ RX_nr:=ord(netrom_header[4]); ++ opcode:=ord(netrom_header[5]); ++ // Opcode flags ++ opc_flags:=''; ++ if opcode and 128 = 128 then opc_flags:=opc_flags+' C'; ++ if opcode and 64 = 64 then opc_flags:=opc_flags+' N'; ++ // ++ s:=' [NETROM] '+s_call+' to '+d_call+' ttl='+inttostr(ttl)+' cct='+dec2hex(c_idx)+dec2hex(c_ID); ++ r_s_nr:=' S'+inttostr(TX_nr)+' R'+inttostr(RX_nr); ++ case (opcode and 7) of ++ 0 : s:=s+' <'+opcode_arr[opcode and 7]+r_s_nr+'>'+#13#10+data; ++ 1 : s:=s+' <'+opcode_arr[opcode and 7]+'>'+con_req_info(data); ++ 2 : s:=s+' <'+opcode_arr[opcode and 7]+'>'+con_ack_info(data)+' my cct='+dec2hex(TX_nr)+dec2hex(RX_nr); ++ 3 : s:=s+' <'+opcode_arr[opcode and 7]+'>'; ++ 4 : s:=s+' <'+opcode_arr[opcode and 7]+'>'; ++ 5 : s:=s+' <'+opcode_arr[opcode and 7]+r_s_nr+'>:'+#13#10+data; ++ 6 : s:=s+' <'+opcode_arr[opcode and 7]+' R'+inttostr(RX_nr)+'>'+opc_flags; ++ 7 : s:=s+' <'+opcode_arr[opcode and 7]+r_s_nr+'>'+#13#10+data; ++ end; ++ end; ++ end; ++ end; ++ result:=s; ++end; ++ ++function parse_IP(data: string): string; ++ ++ function parse_ICMP(var data: string): string; ++ var ++ ICMP_type: byte; ++ ICMP_code: byte; ++ s: string; ++ begin ++ result:=''; ++ if length(data)>3 then ++ begin ++ ICMP_type:=ord(data[1]); ++ ICMP_code:=ord(data[2]); ++ delete(data,1,4); ++ s:=' [ICMP] Type='+inttostr(ICMP_type)+' Code='+inttostr(ICMP_code)+#13#10; ++ result:=s; ++ end; ++ end; ++ ++ function parse_TCP(var data: string): string; ++ var ++ s: string; ++ src_port: string; ++ dest_port: string; ++ wnd: string; ++ ihl: word; ++ idl: word; ++ flags: byte; ++ seq: string; ++ ack: string; ++ s_flags: string; ++ s_idl: string; ++ begin ++ result:=''; ++ if length(data)>19 then ++ begin ++ src_port:=' src_port:'+inttostr((ord(data[1]) shl 8)+ord(data[2])); ++ dest_port:=' dest_port:'+inttostr((ord(data[3]) shl 8)+ord(data[4])); ++ seq:=' seq='+dec2hex(ord(data[5]))+dec2hex(ord(data[6]))+dec2hex(ord(data[7]))+dec2hex(ord(data[8])); ++ ack:=' ack='+dec2hex(ord(data[9]))+dec2hex(ord(data[10]))+dec2hex(ord(data[11]))+dec2hex(ord(data[12])); ++ ihl:=(ord(data[13]) shr 4)*4; ++ idl:=length(data)-ihl; ++ flags:=ord(data[14]); ++ wnd:=' wnd='+inttostr((ord(data[15]) shl 8)+ord(data[16])); ++ delete(data,1,ihl); ++ // ++ s_flags:=' '; ++ if (flags and 32)=32 then s_flags:=s_flags+'URG '; ++ if (flags and 16)=16 then s_flags:=s_flags+'ACK '; ++ if (flags and 8)=8 then s_flags:=s_flags+'PSH '; ++ if (flags and 4)=4 then s_flags:=s_flags+'RST '; ++ if (flags and 2)=2 then s_flags:=s_flags+'SYN '; ++ if (flags and 1)=1 then s_flags:=s_flags+'FIN '; ++ // ++ if idl>0 then s_idl:=' data='+inttostr(idl) else s_idl:=''; ++ if (flags and 16)<>16 then ack:=''; ++ // ++ s:=' [TCP]'+src_port+dest_port+seq+ack+wnd+s_idl+s_flags+#13#10; ++ result:=s; ++ end; ++ end; ++ ++ function parse_UDP(var data: string): string; ++ var ++ s: string; ++ src_port: string; ++ dest_port: string; ++ idl: word; ++ len: word; ++ s_idl: string; ++ begin ++ result:=''; ++ if length(data)>7 then ++ begin ++ src_port:=' src_port:'+inttostr((ord(data[1]) shl 8)+ord(data[2])); ++ dest_port:=' dest_port:'+inttostr((ord(data[3]) shl 8)+ord(data[4])); ++ len:=(ord(data[5]) shl 8)+ord(data[6]); ++ idl:=len-8; ++ delete(data,1,8); ++ // ++ if idl>0 then s_idl:=' data='+inttostr(idl) else s_idl:=''; ++ // ++ s:=' [UDP]'+src_port+dest_port+' len='+inttostr(len)+s_idl+#13#10; ++ result:=s; ++ end; ++ end; ++ ++const ++ prot_idx=#1#6#17; ++ prot_name: array [1..3] of string = ('ICMP','TCP','UDP'); ++var ++ s: string; ++ src_ip: string; ++ dest_ip: string; ++ s_prot: string; ++ len: string; ++ c_prot: char; ++ ttl: string; ++ offset: string; ++ ihl: byte; ++ p: byte; ++ fragment_offset: word; ++begin ++ s:=data; ++ if length(data)>19 then ++ begin ++ ihl:=(ord(data[1]) and 15)*4; ++ len:=' len='+inttostr((ord(data[3]) shl 8)+ord(data[4])); ++ fragment_offset:=((ord(data[7]) shl 8)+ord(data[8])) shl 3; ++ ttl:=' ttl='+inttostr(ord(data[9])); ++ c_prot:=data[10]; ++ src_ip:=' Fm '+inttostr(ord(data[13]))+'.'+inttostr(ord(data[14]))+'.'+inttostr(ord(data[15]))+'.'+inttostr(ord(data[16])); ++ dest_ip:=' To '+inttostr(ord(data[17]))+'.'+inttostr(ord(data[18]))+'.'+inttostr(ord(data[19]))+'.'+inttostr(ord(data[20])); ++ delete(data,1,ihl); ++ // ++ p:=pos(c_prot,prot_idx); ++ if p>0 then s_prot:=' prot='+prot_name[p] else s_prot:=' prot=Type'+inttostr(ord(c_prot)); ++ if fragment_offset>0 then offset:=' offset='+inttostr(fragment_offset) else offset:=''; ++ s:=' [IP]'+src_ip+dest_ip+s_prot+ttl+len+offset+#13#10; ++ if fragment_offset=0 then ++ case p of ++ 1 : s:=s+parse_ICMP(data); ++ 2 : s:=s+parse_TCP(data); ++ 3 : s:=s+parse_UDP(data); ++ end; ++ s:=s+data; ++ end; ++ result:=s; ++end; ++ ++function get_UTC_time: string; ++var ++ st: TSYSTEMTIME; ++ sec,hour,minute: string; ++begin ++ GetSystemTime(st); ++ if st.wSecond<10 then sec:='0'+inttostr(st.wSecond) else sec:=inttostr(st.wSecond); ++ if st.wMinute<10 then minute:='0'+inttostr(st.wMinute) else minute:=inttostr(st.wMinute); ++ if st.wHour<10 then Hour:='0'+inttostr(st.wHour) else Hour:=inttostr(st.wHour); ++ result:=hour+':'+minute+':'+sec; ++end; ++ ++function dec2hex(value: byte): string; ++const ++ hex='0123456789ABCDEF'; ++var ++ lo,hi: byte; ++begin ++ lo:=value and 15; ++ hi:=value shr 4; ++ result:=hex[hi+1]+hex[lo+1]; ++end; ++ ++*/ ++ ++unsigned short get_fcs(UCHAR * Data, unsigned short len) ++{ ++ unsigned short i; ++ unsigned short result; ++ ++ result = 0xFFFF; ++ ++ if (len == 0) ++ return result; ++ ++ for (i = 0; i < len; i++) ++ result = (result >> 8) ^ CRCTable[(result ^ Data[i]) & 0xff]; ++ ++ ++ result ^= 0xffff; ++ ++ return result; ++} ++ ++ ++unsigned short CRCTAB[256] = { ++ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, ++ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, ++ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, ++ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, ++ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, ++ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, ++0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, ++0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, ++0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, ++0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, ++0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, ++0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, ++0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, ++0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, ++0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, ++0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, ++0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, ++0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, ++0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, ++0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, ++0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, ++0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, ++0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, ++0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, ++0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, ++0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, ++0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, ++0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, ++0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, ++0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, ++0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, ++0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 ++}; ++ ++unsigned short int compute_crc(unsigned char *buf, int len) ++{ ++ unsigned short fcs = 0xffff; ++ int i; ++ ++ for (i = 0; i < len; i++) ++ fcs = (fcs >> 8) ^ CRCTAB[(fcs ^ buf[i]) & 0xff]; ++ ++ fcs ^= 0xffff; ++ ++ return fcs; ++} ++ ++ ++ ++int get_addr(char * Calls, UCHAR * AXCalls) ++{ ++ // CONVERT CALL + OPTIONAL DIGI STRING (Comma separated) TO AX25, RETURN ++ // CONVERTED STRING IN AXCALLS. Return FALSE if invalied ++ ++ Byte * axptr = AXCalls; ++ char * ptr, *Context; ++ int n = 8; // Max digis ++ ++ memset(AXCalls, 0, 72); ++ ++ ptr = strtok_s(Calls, " ,", &Context); ++ ++ if (ptr == NULL) ++ return FALSE; ++ ++ // First field is Call ++ ++ if (ConvToAX25(ptr, axptr) == 0) ++ return FALSE; ++ ++ axptr += 7; ++ ++ ptr = strtok_s(NULL, " ,", &Context); ++ ++ if (ptr == 0 || ConvToAX25(ptr, axptr) == 0) ++ return FALSE; ++ ++ axptr += 7; ++ ++ ptr = strtok_s(NULL, " ,", &Context); ++ ++ while (ptr && n--) ++ { ++ // NEXT FIELD = COULD BE CALLSIGN, VIA, ++ ++ if (memcmp(ptr, "VIA", (int)strlen(ptr)) == 0) ++ { ++ } //skip via ++ else ++ { ++ // Convert next digi ++ ++ if (ConvToAX25(ptr, axptr) == 0) ++ return FALSE; ++ ++ axptr += 7; ++ } ++ ++ ptr = strtok_s(NULL, " ,", &Context); ++ } ++ ++ axptr[-1] |= 1; // Set end of address ++ ++ return axptr - AXCalls; ++} ++ ++Byte set_ctrl(Byte nr, Byte ns, Byte f_type, Byte f_id, boolean pf) ++{ ++ Byte pf_bit, ctrl; ++ ++ ctrl = 0; ++ pf_bit = 0; ++ ++ if (pf) ++ pf_bit = 16; ++ ++ switch (f_type) ++ { ++ case I_FRM: ++ ++ ctrl = (nr << 5) + pf_bit + (ns << 1); ++ break; ++ ++ case S_FRM: ++ ++ ctrl = (nr << 5) + pf_bit + f_id; ++ break; ++ ++ case U_FRM: ++ ++ ctrl = f_id + pf_bit; ++ } ++ ++ return ctrl; ++} ++ ++string * make_frame(string * data, Byte * axaddr, Byte pid, Byte nr, Byte ns, Byte f_type, Byte f_id, boolean rpr, boolean pf, boolean cr) ++{ ++ UNUSED(rpr); ++ ++ Byte ctrl; ++ ++ string * frame = newString(); ++ int addrlen; ++ Byte addr[80]; ++ ++ frame->Data[0] = 0; // Lower software expects a kiss control byte here ++ frame->Length = 1; ++ ++ ctrl = set_ctrl(nr, ns, f_type, f_id, pf); ++ ++ addrlen = strlen((char *)axaddr); ++ ++ memcpy(addr, axaddr, addrlen); ++ ++ if (cr) ++ addr[6] |= 0x80; // Set Command Bit ++ else ++ addr[13] |= 0x80; // Set Response Bit ++ ++ ++ switch (f_type) ++ { ++ case I_FRM: ++ ++ stringAdd(frame, addr, addrlen); ++ stringAdd(frame, (Byte *)&ctrl, 1); ++ stringAdd(frame, (Byte *)&pid, 1); ++ stringAdd(frame, data->Data, data->Length); ++ ++ break; ++ ++ ++ case S_FRM: ++ ++ stringAdd(frame, addr, addrlen); ++ stringAdd(frame, (Byte *)&ctrl, 1); ++ ++ break; ++ ++ case U_FRM: ++ ++ if (f_id == U_UI) ++ { ++ stringAdd(frame, addr, addrlen); ++ stringAdd(frame, (Byte *)&ctrl, 1); ++ stringAdd(frame, (Byte *)&pid, 1); ++ stringAdd(frame, data->Data, data->Length); ++ } ++ else if (f_id == U_FRMR) ++ { ++ stringAdd(frame, addr, addrlen); ++ stringAdd(frame, (Byte *)&ctrl, 1); ++ stringAdd(frame, data->Data, data->Length); ++ } ++ else ++ { ++ stringAdd(frame, addr, addrlen); ++ stringAdd(frame, (Byte *)&ctrl, 1); ++ } ++ } ++ ++ return frame; ++} ++ ++ ++int add_raw_frames(int snd_ch, string * frame, TStringList * buf) ++{ ++ UNUSED(snd_ch); ++ ++ string *s_data = newString(); ++ Byte s_pid, s_nr, s_ns, s_f_type, s_f_id; ++ Byte s_rpt, s_cr, s_pf; ++ string *d_data = newString(); ++ Byte d_pid, d_nr, d_ns, d_f_type, d_f_id; ++ Byte d_rpt, d_cr, d_pf; ++ ++ Byte d_path[80]; ++ Byte s_path[80]; ++ ++ boolean found_I; ++ int i; ++ ++ unsigned char * framecontents; ++ int Length; ++ ++ boolean result = TRUE; ++ ++ // Have to be careful as at this point frames have KISS Header and maybe trailer ++ ++ if (buf->Count > 0) ++ { ++ // Check for duplicate. Ok to just compare as copy will have same header ++ ++ if (my_indexof(buf, frame) >= 0) ++ { ++// Debugprintf("KISSOptimise discarding duplicate frame"); ++ return FALSE; ++ } ++ ++ // Need to adjust for KISS bytes ++ ++ // Normally one, but ackmode has 3 on front and sizeof(void *) on end ++ ++ framecontents = frame->Data; ++ Length = frame->Length; ++ ++ if ((framecontents[0] & 15) == 12) // Ackmode ++ { ++ framecontents += 3; ++ Length -= (3 + sizeof(void *)); ++ } ++ else ++ { ++ framecontents++; ++ Length--; ++ } ++ ++ decode_frame(framecontents, Length, s_path, s_data, &s_pid, &s_nr, &s_ns, &s_f_type, &s_f_id, &s_rpt, &s_pf, &s_cr); ++ ++ found_I = FALSE; ++ ++ // check for multiple RR (r) ++ ++ if (s_f_id == S_FRM && s_cr == SET_R) ++ { ++ for (i = 0; i < buf->Count; i++) ++ { ++ framecontents = buf->Items[i]->Data; ++ Length = buf->Items[i]->Length; ++ ++ if ((framecontents[0] & 15) == 12) // Ackmode ++ { ++ framecontents += 3; ++ Length -= (3 + sizeof(void *)); ++ } ++ else ++ { ++ framecontents++; ++ Length--; ++ } ++ ++ decode_frame(framecontents, Length, d_path, d_data, &d_pid, &d_nr, &d_ns, &d_f_type, &d_f_id, &d_rpt, &d_pf, &d_cr); ++ ++ if (d_f_id == S_FRM && d_cr == SET_R && strcmp((char *)s_path, (char *)d_path) == 0) ++ { ++ Delete(buf, i); ++ Debugprintf("KISSOptimise discarding unneeded RR(R%d)", d_nr); ++ ++ break; ++ } ++ } ++ } ++ ++ ++ // check for RR after I Frame ++ ++ if (s_f_id == S_FRM && s_cr == SET_C) ++ { ++ for (i = 0; i < buf->Count; i++) ++ { ++ framecontents = buf->Items[i]->Data; ++ Length = buf->Items[i]->Length; ++ ++ if ((framecontents[0] & 15) == 12) // Ackmode ++ { ++ framecontents += 3; ++ Length -= (3 + sizeof(void *)); ++ } ++ else ++ { ++ framecontents++; ++ Length--; ++ } ++ ++ decode_frame(framecontents, Length, d_path, d_data, &d_pid, &d_nr, &d_ns, &d_f_type, &d_f_id, &d_rpt, &d_pf, &d_cr); ++ ++ if (d_f_id == I_FRM && strcmp((char *)s_path, (char *)d_path) == 0) ++ { ++ found_I = TRUE; ++ break; ++ } ++ } ++ ++ if (found_I) ++ { ++ Debugprintf("KISSOptimise discarding unneeded RR(C %d) after I frame", s_nr); ++ result = FALSE; ++ } ++ } ++ ++ // check on I ++ ++ if (s_f_id == I_FRM) ++ { ++ for (i = 0; i < buf->Count; i++) ++ { ++ framecontents = buf->Items[i]->Data; ++ Length = buf->Items[i]->Length; ++ ++ if ((framecontents[0] & 15) == 12) // Ackmode ++ { ++ framecontents += 3; ++ Length -= (3 + sizeof(void *)); ++ } ++ else ++ { ++ framecontents++; ++ Length--; ++ } ++ ++ decode_frame(framecontents, Length, d_path, d_data, &d_pid, &d_nr, &d_ns, &d_f_type, &d_f_id, &d_rpt, &d_pf, &d_cr); ++ ++ if (strcmp((char *)s_path, (char *)d_path) == 0 && d_f_id == S_FRM && d_cr == SET_C) ++ { ++ Delete(buf, i); ++ Debugprintf("KISSOptimise discarding unneeded RR(C %d)", d_nr); ++ i--; // i was removed ++ } ++ } ++ } ++ } ++ ++ freeString(d_data); ++ freeString(s_data); ++ ++ return result; ++} ++ ++//////////////////////// Register incoming callsign //////////////////////////// ++ ++// I think a call should only be registered on one socket (or we won't know where to send ++// incoming calls ++ ++boolean add_incoming_mycalls(void * socket, char * src_call) ++{ ++ registeredCalls * reg = malloc(sizeof(struct registeredCalls_t)); ++ int i = 0; ++ ++ // Build a string containing Call and Socket ++ ++ ConvToAX25(src_call, reg->myCall); ++ reg->socket = socket; ++ ++ if (list_incoming_mycalls.Count > 0) ++ { ++ for (i = 0; i < list_incoming_mycalls.Count; i++) ++ { ++ registeredCalls * check = (registeredCalls *)list_incoming_mycalls.Items[i]; ++ ++ if (memcmp(check->myCall, reg->myCall, 7) == 0) ++ { ++ // Update socket ++ ++ check->socket = socket; ++ return FALSE; ++ } ++ } ++ } ++ ++ Add(&list_incoming_mycalls, (string *)reg); ++ return TRUE; ++} ++ ++ ++ ++void del_incoming_mycalls(char * src_call) ++{ ++ int i = 0; ++ Byte axcall[7]; ++ registeredCalls * reg; ++ ++ ConvToAX25(src_call, axcall); ++ ++ while (i < list_incoming_mycalls.Count) ++ { ++ reg = (registeredCalls *)list_incoming_mycalls.Items[i]; ++ { ++ if (memcmp(reg->myCall, axcall, 7) == 0) ++ { ++ // cant use Delete as stringlist doesn't contain strings ++ ++ TStringList * Q = &list_incoming_mycalls; ++ int Index = i; ++ ++ free(Q->Items[Index]); ++ ++ Q->Count--; ++ ++ while (Index < Q->Count) ++ { ++ Q->Items[Index] = Q->Items[Index + 1]; ++ Index++; ++ } ++ ++ return; ++ } ++ } ++ i++; ++ } ++} ++ ++ ++void del_incoming_mycalls_by_sock(void * socket) ++{ ++ int i = 0, snd_ch, port; ++ registeredCalls * reg; ++ ++ while (i < list_incoming_mycalls.Count) ++ { ++ reg = (registeredCalls *)list_incoming_mycalls.Items[i]; ++ { ++ if (reg->socket == socket) ++ { ++ // cant use Delete as stringlist doesn't contain strings ++ ++ TStringList * Q = &list_incoming_mycalls; ++ int Index = i; ++ ++ free(Q->Items[Index]); ++ ++ Q->Count--; ++ ++ while (Index < Q->Count) ++ { ++ Q->Items[Index] = Q->Items[Index + 1]; ++ Index++; ++ } ++ ++ //Delete(&list_incoming_mycalls, i); ++ } ++ else ++ i++; ++ } ++ } ++ ++ // Should clear all connections on socket ++ ++ for (snd_ch = 0; snd_ch < 4; snd_ch++) ++ { ++ for (port = 0; port < port_num; port++) ++ { ++ TAX25Port * AX25Sess = &AX25Port[snd_ch][port]; ++ ++ if (AX25Sess->socket == socket) ++ { ++ if (AX25Sess->status != STAT_NO_LINK) ++ { ++ // Shouldn't we send DM? -0 try it ++ ++ set_DM(snd_ch, AX25Sess->ReversePath); ++ ++ rst_timer(AX25Sess); ++ rst_values(AX25Sess); ++ ++ AX25Sess->status = STAT_NO_LINK; ++ } ++ AX25Sess->socket = 0; ++ } ++ } ++ } ++} ++ ++ ++/* ++function get_incoming_socket_by_call(src_call: string): integer; ++var ++ i: integer; ++ found: boolean; ++ socket: integer; ++ call,ssid: string; ++ a_call: array[0..1] of string; ++begin ++ socket:=-1; ++ i:=0; ++ found:=FALSE; ++ try explode(a_call,'-',src_call,2); except end; ++ call:=trim(a_call[0]); ++ if a_call[1]<>'' then ssid:=a_call[1] else ssid:='0'; ++ if list_incoming_mycalls.Count>0 then ++ repeat ++ if (call+'-'+ssid)=list_incoming_mycalls.Strings[i] then ++ begin socket:=strtoint(list_incoming_mycalls_sock.Strings[i]); found:=TRUE; end; ++ inc(i); ++ until found or (i=list_incoming_mycalls.Count); ++ result:=socket; ++end; ++*/ ++ ++ ++ ++void * in_list_incoming_mycall(Byte * path) ++{ ++ // See if to call is in registered calls list ++ ++ int i = 0; ++ registeredCalls * check; // list_incoming_mycalls contains registeredCalls, not Strings ++ ++ while (i < list_incoming_mycalls.Count) ++ { ++ check = (registeredCalls *)list_incoming_mycalls.Items[i]; ++ ++ if (memcmp(check->myCall, path, 7) == 0) ++ return check->socket; ++ ++ i++; ++ } ++ ++ return NULL; ++} ++ ++/* ++//////////////////////////////////////////////////////////////////////////////// ++ ++function is_corrcall(snd_ch,port: byte; path: string): boolean; ++var ++ call,ssid: string; ++begin ++ call:=trim(copy(path,8,6)); ++ ssid:=copy(path,14,1); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; ++ call:=call+'-'+ssid; ++ if call=AX25Sess->corrcall then result:=TRUE else result:=FALSE; ++end; ++ ++function is_mycall(snd_ch,port: byte; path: string): boolean; ++var ++ call,ssid: string; ++begin ++ call:=trim(copy(path,1,6)); ++ ssid:=copy(path,7,1); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; ++ call:=call+'-'+ssid; ++ if call=AX25Sess->mycall then result:=TRUE else result:=FALSE; ++end; ++ ++function is_digi(snd_ch,port: byte; path: string): boolean; ++var ++ digi,call,ssid: string; ++begin ++ digi:=''; ++ if length(path)>14 then ++ begin ++ delete(path,1,14); ++ repeat ++ call:=trim(copy(path,1,6)); ++ ssid:=copy(path,7,1); ++ delete(path,1,7); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) ++ else ssid:='0'; ++ if path<>'' then digi:=digi+call+'-'+ssid+',' ++ else digi:=digi+call+'-'+ssid; ++ until path=''; ++ end; ++ if digi=AX25Sess->digi then result:=TRUE else result:=FALSE; ++end; ++*/ ++ ++// Check if laast digi used ++ ++boolean is_last_digi(Byte *path) ++{ ++ int len = strlen((char *)path); ++ ++ if (len == 14) ++ return TRUE; ++ ++ if ((path[len - 1] & 128) == 128) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++ ++ ++/* ++function get_corrcall(path: string): string; ++var ++ call,ssid: string; ++begin ++ call:=trim(copy(path,8,6)); ++ ssid:=copy(path,14,1); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; ++ call:=call+'-'+ssid; ++ result:=call; ++end; ++ ++function get_mycall(path: string): string; ++var ++ call,ssid: string; ++begin ++ call:=trim(copy(path,1,6)); ++ ssid:=copy(path,7,1); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) else ssid:='0'; ++ call:=call+'-'+ssid; ++ result:=call; ++end; ++ ++function get_digi(path: string): string; ++var ++ digi,call,ssid: string; ++begin ++ digi:=''; ++ if length(path)>14 then ++ begin ++ delete(path,1,14); ++ repeat ++ call:=trim(copy(path,1,6)); ++ ssid:=copy(path,7,1); ++ delete(path,1,7); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) ++ else ssid:='0'; ++ if path<>'' then digi:=digi+call+'-'+ssid+',' ++ else digi:=digi+call+'-'+ssid; ++ until path=''; ++ end; ++ result:=digi; ++end; ++*/ ++ ++boolean is_correct_path(Byte * path, Byte pid) ++{ ++ Byte networks[] = { 6, 7, 8, 0xc4, 0xcc, 0xcd, 0xce, 0xcf, 0xf0 , 0 }; ++ int i; ++ ++ ++ if (pid == 0 || strchr((char *)networks, pid)) ++ { ++ // Validate calls ++ ++ // I think checking bottom bit of first 13 bytes is enough ++ ++ for (i = 0; i < 13; i++) ++ { ++ if ((*(path) & 1)) ++ return FALSE; ++ ++ path++; ++ } ++ return TRUE; ++ } ++ return FALSE; ++} ++ ++ ++void get_exclude_list(char * line, TStringList * list) ++{ ++ // Convert comma separated list of calls to ax25 format in list ++ ++ string axcall; ++ ++ char copy[512]; ++ ++ char * ptr, *Context; ++ ++ if (line[0] == 0) ++ return; ++ ++ strcpy(copy, line); // copy as strtok messes with it ++ strcat(copy, ","); ++ ++ axcall.Length = 8; ++ axcall.AllocatedLength = 8; ++ axcall.Data = malloc(8); ++ ++ memset(axcall.Data, 0, 8); ++ ++ ptr = strtok_s(copy, " ,", &Context); ++ ++ while (ptr) ++ { ++ if (ConvToAX25(ptr, axcall.Data) == 0) ++ return; ++ ++ Add(list, duplicateString(&axcall)); ++ ++ ptr = strtok_s(NULL, " ,", &Context); ++ } ++} ++ ++ ++ ++void get_exclude_frm(char * line, TStringList * list) ++{ ++ UNUSED(line); ++ UNUSED(list); ++ /* ++ ++ s: string; ++ p: integer; ++ n: integer; ++begin ++ list.Clear; ++ if line='' then exit; ++ repeat ++ p:=pos(',',line); ++ if p>0 then ++ begin ++ s:=trim(copy(line,1,p-1)); ++ if s<>'' then ++ begin ++ try n:=strtoint(s); except n:=-1; end; ++ if n in [0..255] then list.Add(chr(n)); ++ end; ++ delete(line,1,p); ++ end ++ else ++ begin ++ s:=trim(line); ++ if s<>'' then ++ begin ++ try n:=strtoint(s); except n:=-1; end; ++ if n in [0..255] then list.Add(chr(n)); ++ end; ++ end; ++ until p=0; ++end; ++*/ ++} ++ ++/* ++ ++function is_excluded_call(snd_ch: byte; path: string): boolean; ++var ++ excluded: boolean; ++ call: string; ++ ssid: string; ++begin ++ excluded:=FALSE; ++ if (list_exclude_callsigns[snd_ch].Count>0) and (length(path)>13) then ++ begin ++ // Copy sender ++ call:=trim(copy(path,8,6)); ++ ssid:=copy(path,14,1); ++ if ssid<>'' then call:=call+'-'+inttostr((ord(ssid[1]) and 15)); ++ if list_exclude_callsigns[snd_ch].IndexOf(call)>-1 then excluded:=TRUE; ++ end; ++ result:=excluded; ++end; ++ ++function is_excluded_frm(snd_ch,f_id: byte; data: string): boolean; ++var ++ excluded: boolean; ++begin ++ excluded:=FALSE; ++ if list_exclude_APRS_frm[snd_ch].Count>0 then ++ if f_id=U_UI then ++ if length(data)>0 then ++ if list_exclude_APRS_frm[snd_ch].IndexOf(data[1])>=0 then excluded:=TRUE; ++ result:=excluded; ++end; ++ ++procedure set_corrcall(snd_ch,port: byte; path: string); ++var ++ call,ssid: string; ++begin ++ call:=trim(copy(path,8,6)); ++ ssid:=copy(path,14,1); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) ++ else ssid:='0'; ++ AX25Sess->corrcall:=call+'-'+ssid; ++end; ++ ++procedure set_mycall(snd_ch,port: byte; path: string); ++var ++ call,ssid: string; ++begin ++ call:=trim(copy(path,1,6)); ++ ssid:=copy(path,7,1); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) ++ else ssid:='0'; ++ AX25Sess->mycall:=call+'-'+ssid; ++end; ++ ++procedure set_digi(snd_ch,port: byte; path: string); ++var ++ digi,call,ssid: string; ++begin ++ digi:=''; ++ if length(path)>14 then ++ begin ++ delete(path,1,14); ++ repeat ++ call:=trim(copy(path,1,6)); ++ ssid:=copy(path,7,1); ++ delete(path,1,7); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)) ++ else ssid:='0'; ++ if path<>'' then digi:=digi+call+'-'+ssid+',' ++ else digi:=digi+call+'-'+ssid; ++ until path=''; ++ end; ++ AX25Sess->digi:=digi; ++end; ++ ++procedure get_call_fm_path(path: string; var callto,callfrom: string); ++var ++ a_path: array [0..ADDR_MAX_LEN-1] of string; ++ i: byte; ++begin ++ for i:=0 to ADDR_MAX_LEN-1 do a_path[i]:=''; ++ try explode(a_path,',',path,ADDR_MAX_LEN); except end; ++ callto:=a_path[0]; ++ callfrom:=a_path[1]; ++end; ++ ++procedure get_call(src_call: string; var call: string); ++var ++ a_call: array[0..1] of string; ++ ssid: string; ++begin ++ try explode(a_call,'-',src_call,2); except end; ++ call:=trim(a_call[0]); ++ if a_call[1]<>'' then ssid:=trim(a_call[1]) else ssid:='0'; ++ call:=call+'-'+ssid; ++end; ++*/ ++ ++int number_digi(unsigned char * path) ++{ ++ UNUSED(path); ++ int n = 0; ++ ++ // a_path: array [0..ADDR_MAX_LEN-3] of string; ++ // for i:=0 to ADDR_MAX_LEN-3 do a_path[i]:=''; ++ // try explode(a_path,',',path,ADDR_MAX_LEN-2); except end; ++ // for i:=0 to ADDR_MAX_LEN-3 do if a_path[i]<>'' then inc(n); ++ ++ return n; ++} ++ ++ ++ ++void get_monitor_path(Byte * path, char * mycall, char * corrcall, char * digi) ++{ ++ char * digiptr = digi; ++ ++ digi[0] = 0; ++ ++ mycall[ConvFromAX25(path, mycall)] = 0; ++ path += 7; ++ corrcall[ConvFromAX25(path, corrcall)] = 0; ++ ++ while ((path[6] & 1) == 0) // End of call bit ++ { ++ if (digi != digiptr) ++ *(digi++) = ','; ++ ++ path += 7; ++ digi += ConvFromAX25(path, digi); ++ ++ if (((path[6] & 128) == 128)) // Digi'd ++ *(digi++) = '*'; ++ } ++ *digi = 0; ++} ++ ++ ++/* ++ ++function reverse_digi(path: string): string; ++var ++ digi: string; ++ a_path: array [0..ADDR_MAX_LEN-3] of string; ++ i: word; ++begin ++ digi:=''; ++ for i:=0 to ADDR_MAX_LEN-3 do a_path[i]:=''; ++ try explode(a_path,',',path,ADDR_MAX_LEN-2); except end; ++ for i:=0 to ADDR_MAX_LEN-3 do ++ if a_path[i]<>'' then ++ begin ++ if digi='' then digi:=a_path[i]+digi ++ else digi:=a_path[i]+','+digi; ++ end; ++ result:=digi; ++end; ++ ++function direct_addr(path: string): string; ++var ++ s,call,ssid: string; ++begin ++ s:=''; ++ repeat ++ call:=copy(path,1,6); ++ delete(path,1,6); ++ ssid:=copy(path,1,1); ++ delete(path,1,1); ++ if ssid<>'' then ssid:=inttostr((ord(ssid[1]) and 15)); ++ if s='' then s:=call+'-'+ssid else s:=s+','+call+'-'+ssid; ++ until path=''; ++ result:=s; ++end; ++*/ ++ ++void reverse_addr(Byte * path, Byte * revpath, int Len) ++{ ++ Byte * ptr = path; ++ Byte * copy = revpath; ++ int endbit = Len - 1; ++ int numdigis = (Len - 14) / 7; ++ int i; ++ ++ if (Len < 14) ++ return; ++ ++ Byte digis[57]; // 8 * 7 + null terminator ++ memset(digis, 0, 57); ++ Byte * digiptr = digis + 49; // Last Digi ++ ++ // remove end of address bit ++ ++ path[endbit] &= 0xFE; ++ ++ // first reverse dest and origin ++ ++ memcpy(copy + 7, ptr, 7); ++ memcpy(copy, ptr + 7, 7); ++ ++ Len -= 14; ++ ptr += 14; ++ ++ for (i = 0; i < numdigis; i++) ++ { ++ memcpy(digiptr, ptr, 7); ++ ptr += 7; ++ digiptr -= 7; ++ } ++ ++ // Digiptr now points to new first digi ++ ++ memcpy(©[14], &digiptr[7], 7 * numdigis); ++ ++ path[endbit] |= 1; // restore original end bit ++ ++ copy[endbit++] |= 1; ++ copy[endbit] = 0; // Null terminate ++ ++ return; ++} ++ ++ ++ ++void decode_frame(Byte * frame, int len, Byte * path, string * data, ++ Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id, ++ Byte * rpt, Byte * pf, Byte * cr) ++{ ++ int i; ++ int addr_end; ++ Byte ctrl; ++ Byte * savepath = path; ++ ++ i = 0; ++ addr_end = FALSE; ++ ++ *cr = SET_R; ++ *pf = SET_F; ++ data->Length = 0; ++ ctrl = 0; ++ *pid = 0; ++ *nr = 0; ++ *ns = 0; ++ *f_type = 0; ++ *f_id = 0; ++ *rpt = FALSE; ++ ++ if ((frame[6] & 128) == 128 && (frame[13] & 128) == 0) ++ *cr = SET_C; ++ ++ while (len > i && i < ADDR_MAX_LEN * 7) ++ { ++ *path++ = frame[i]; ++ if ((frame[i] & 1) == 1) ++ { ++ addr_end = TRUE; ++ break; ++ } ++ i++; ++ } ++ ++ if (addr_end == 0) ++ return; ++ ++ // clear the c and r bits from address ++ ++ savepath[6] &= 0x7f; // Mask ++ savepath[13] &= 0x7f; // Mask ++ ++ *path = 0; // add null terminate ++ ++ i++; // Points to ctrl byte ++ ++ ctrl = frame[i]; ++ ++ if ((ctrl & 16) == 16) ++ *pf = SET_P; ++ ++ if ((ctrl & 1) == 0) // I frame ++ { ++ *f_type = I_FRM; ++ *f_id = I_I; ++ *nr = (ctrl >> 5); ++ *ns = (ctrl >> 1) & 7; ++ } ++ else ++ { ++ // Not I ++ ++ *f_type = U_FRM; ++ ++ *f_id = ctrl & 239; ++ ++ switch (ctrl & 15) ++ { ++ case S_RR: ++ case S_RNR: ++ case S_REJ: ++ case S_SREJ: ++ ++ *f_type = S_FRM; ++ } ++ ++ if (*f_type == S_FRM) ++ { ++ *f_id = ctrl & 15; ++ *nr = ctrl >> 5; ++ } ++ } ++ ++ ++ if (*f_id == I_I || *f_id == U_UI) ++ { ++ i++; ++ *pid = frame[i]; ++ i++; ++ if (len > i) ++ stringAdd(data, &frame[i], len - i); ++ } ++ else if (*f_id == U_FRMR) ++ { ++ *pid = 0; ++ i++; ++ if (len > i) ++ stringAdd(data, &frame[i], len - i); ++ } ++} ++ ++void ax25_info_init(TAX25Port * AX25Sess) ++{ ++ AX25Sess->info.stat_s_pkt = 0; ++ AX25Sess->info.stat_s_byte = 0; ++ AX25Sess->info.stat_r_pkt = 0; ++ AX25Sess->info.stat_r_byte = 0; ++ AX25Sess->info.stat_r_fc = 0; ++ AX25Sess->info.stat_fec_count = 0; ++ AX25Sess->info.stat_l_r_byte = 0; ++ AX25Sess->info.stat_l_s_byte = 0; ++ AX25Sess->info.stat_begin_ses = 0; ++ AX25Sess->info.stat_end_ses = 0; ++} ++ ++ ++void clr_frm_win(TAX25Port * AX25Sess) ++{ ++ int i; ++ ++ for (i = 0; i < 8; i++) ++ initString(&AX25Sess->frm_win[i]); ++} ++ ++void ax25_init() ++{ ++ int snd_ch, port, i; ++ ++ for (i = 0; i < 4; i++) ++ { ++ initTStringList(&list_exclude_callsigns[i]); ++ initTStringList(&list_exclude_APRS_frm[i]); ++ initTStringList(&list_digi_callsigns[i]); ++ initTStringList(&KISS_acked[i]); ++ ++ get_exclude_list(MyDigiCall[i], &list_digi_callsigns[i]); ++ get_exclude_list(exclude_callsigns[i], &list_exclude_callsigns[i]); ++ get_exclude_frm(exclude_APRS_frm[i], &list_exclude_APRS_frm[i]); ++ ++ } ++ ++ initTStringList(&list_incoming_mycalls); ++// initTStringList(&list_incoming_mycalls_sock); ++ ++ for (snd_ch = 0; snd_ch < 4; snd_ch++) ++ { ++ for (port = 0; port < port_num; port++) ++ { ++ TAX25Port * AX25Sess = &AX25Port[snd_ch][port]; ++ ++ AX25Sess->hi_vs = 0; ++ AX25Sess->vs = 0; ++ AX25Sess->vr = 0; ++ AX25Sess->PID = PID_NO_L3; ++ initTStringList(&AX25Sess->in_data_buf); ++ initString(&AX25Sess->out_data_buf); ++ AX25Sess->t1 = 0; ++ AX25Sess->t2 = 0; ++ AX25Sess->t3 = 0; ++ AX25Sess->i_lo = 0; ++ AX25Sess->i_hi = 0; ++ AX25Sess->n1 = 0; ++ AX25Sess->n2 = 0; ++ AX25Sess->status = 0; ++ AX25Sess->clk_frack = 0; ++ initTStringList(&AX25Sess->frame_buf); ++ initTStringList(&AX25Sess->I_frame_buf); ++ initTStringList(&AX25Sess->frm_collector); ++ AX25Sess->corrcall[0] = 0; ++ AX25Sess->mycall[0] = 0; ++ AX25Sess->digi[0] = 0; ++ AX25Sess->Path[0] = 0; ++ AX25Sess->kind[0] = 0; ++ AX25Sess->socket = NULL; ++ ax25_info_init(AX25Sess); ++ clr_frm_win(AX25Sess); ++ } ++ } ++} ++/* ++ ++procedure ax25_free; ++var ++ snd_ch,port,i: byte; ++begin ++ for snd_ch:=1 to 4 do ++ for port:=0 to port_num-1 do ++ begin ++ AX25Sess->in_data_buf.Free; ++ AX25Sess->frame_buf.Free; ++ AX25Sess->I_frame_buf.Free; ++ AX25Sess->frm_collector.Free; ++ end; ++ for i:=1 to 4 do ++ begin ++ all_frame_buf[i].Free; ++ list_exclude_callsigns[i].Free; ++ list_exclude_APRS_frm[i].Free; ++ list_digi_callsigns[i].Free; ++ end; ++ list_incoming_mycalls.Free; ++ list_incoming_mycalls_sock.Free; ++end; ++*/ ++void write_ax25_info(TAX25Port * AX25Sess) ++{ ++ UNUSED(AX25Sess); ++} ++ ++/*var ++ new: boolean; ++ t: text; ++ s: string; ++ time_ses: tdatetime; ++ time_ses_sec: extended; ++ call,mycall,spkt,sbyte,rpkt,rbyte,rfc,tcps,rcps,acps,startses,timeses: string; ++begin ++ if stat_log then ++ begin ++ time_ses:=AX25Sess->info.stat_end_ses-AX25Sess->info.stat_begin_ses; ++ time_ses_sec:=time_ses*86400; //âðåìÿ ñåññèè â ñåêóíäàõ ++ if time_ses_sec<1 then exit; ++ mycall:=copy(AX25Sess->mycall+' ',1,9); ++ call:=copy(AX25Sess->corrcall+' ',1,9); ++ spkt:=copy(inttostr(AX25Sess->info.stat_s_pkt)+' ',1,6); ++ sbyte:=copy(inttostr(AX25Sess->info.stat_s_byte)+' ',1,9); ++ rpkt:=copy(inttostr(AX25Sess->info.stat_r_pkt)+' ',1,6); ++ rbyte:=copy(inttostr(AX25Sess->info.stat_r_byte)+' ',1,9); ++ rfc:=copy(inttostr(AX25Sess->info.stat_r_fc)+' ',1,6); ++ tcps:=copy(inttostr(round(AX25Sess->info.stat_s_byte/time_ses_sec))+' ',1,5); ++ rcps:=copy(inttostr(round(AX25Sess->info.stat_r_byte/time_ses_sec))+' ',1,5); ++ acps:=copy(inttostr(round(AX25Sess->info.stat_s_byte/time_ses_sec+AX25Sess->info.stat_r_byte/time_ses_sec))+' ',1,5); ++ timeses:=FormatDateTime('hh:mm:ss',time_ses); ++ startses:=FormatDateTime('dd-mm-yy hh:mm:ss',AX25Sess->info.stat_begin_ses); ++ s:=mycall+' '+call+' '+spkt+' '+sbyte+' '+rpkt+' '+rbyte+' '+rfc+' '+tcps+' '+rcps+' '+acps+' '+startses+' '+timeses; ++ assignfile(t,'log.txt'); ++ if FileSearch('log.txt','')='' then new:=TRUE else new:=FALSE; ++ if new then ++ begin ++ rewrite(t); ++ writeln(t,'Mycall CorrCall TXPkt TXByte RXPkt RXByte FCPkt TXCPS RXCPS T.CPS Begin session SesTime'); ++ writeln(t,'-------- --------- ------ --------- ------ --------- ------ ----- ----- ----- ----------------- --------'); ++ end ++ else append(t); ++ if (AX25Sess->info.stat_s_byte>0) or (AX25Sess->info.stat_r_byte>0) then writeln(t,s); ++ closefile(t); ++ end; ++end; ++ ++end. ++*/ ++ ++ ++/* ++Copyright 2001-2018 John Wiseman G8BPQ ++ ++This file is part of LinBPQ/BPQ32. ++ ++LinBPQ/BPQ32 is free software: you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation, either version 3 of the License, or ++(at your option) any later version. ++ ++LinBPQ/BPQ32 is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses ++*/ ++ ++ ++ ++// Monitor Code - from moncode.asm ++ ++ ++#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND ++#define RESP 2 // CURRENT MSG IS RESPONSE ++#define VER1 1 // CURRENT MSG IS VERSION 1 ++ ++ ++#define UI 3 ++#define SABM 0x2F ++#define DISC 0x43 ++#define DM 0x0F ++#define UA 0x63 ++#define FRMR 0x87 ++#define RR 1 ++#define RNR 5 ++#define REJ 9 ++ ++#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE ++ ++#define NETROM_PID 0xCF ++#define IP_PID 0xCC ++#define ARP_PID 0xCD ++ ++#define NODES_SIG 0xFF ++ ++/* ++ ++DllExport int APIENTRY SetTraceOptions(int mask, int mtxparam, int mcomparam) ++{ ++ ++ // Sets the tracing options for DecodeFrame. Mask is a bit ++ // mask of ports to monitor (ie 101 binary will monitor ports ++ // 1 and 3). MTX enables monitoring on transmitted frames. MCOM ++ // enables monitoring of protocol control frames (eg SABM, UA, RR), ++ // as well as info frames. ++ ++ MMASK = mask; ++ MTX = mtxparam; ++ MCOM = mcomparam; ++ ++ return (0); ++} ++ ++DllExport int APIENTRY SetTraceOptionsEx(int mask, int mtxparam, int mcomparam, int monUIOnly) ++{ ++ ++ // Sets the tracing options for DecodeFrame. Mask is a bit ++ // mask of ports to monitor (ie 101 binary will monitor ports ++ // 1 and 3). MTX enables monitoring on transmitted frames. MCOM ++ // enables monitoring of protocol control frames (eg SABM, UA, RR), ++ // as well as info frames. ++ ++ ++ MMASK = mask; ++ MTX = mtxparam; ++ MCOM = mcomparam; ++ MUIONLY = monUIOnly; ++ ++ return 0; ++} ++ ++*/ ++ ++#define USHORT unsigned short ++ ++UCHAR MCOM = 1; ++UCHAR MTX = 1; ++ULONG MMASK = 0xF; ++UCHAR MUIONLY = 0; ++ ++#define SREJ 0x0D ++#define SABME 0x6F ++#define XID 0xAF ++#define TEST 0xE3 ++ ++#define L4BUSY 0x80 // BNA - DONT SEND ANY MORE ++#define L4NAK 0x40 // NEGATIVE RESPONSE FLAG ++#define L4MORE 0x20 // MORE DATA FOLLOWS - FRAGMENTATION FLAG ++ ++#define L4CREQ 1 // CONNECT REQUEST ++#define L4CACK 2 // CONNECT ACK ++#define L4DREQ 3 // DISCONNECT REQUEST ++#define L4DACK 4 // DISCONNECT ACK ++#define L4INFO 5 // INFORMATION ++#define L4IACK 6 // INFORMATION ACK ++ ++//#pragma pack(1) ++#pragma pack(push, 1) ++ ++struct myin_addr { ++ union { ++ struct { unsigned char s_b1, s_b2, s_b3, s_b4; } S_un_b; ++ struct { unsigned short s_w1, s_w2; } S_un_w; ++ unsigned long addr; ++ }; ++}; ++ ++ ++typedef struct _IPMSG ++{ ++ // FORMAT OF IP HEADER ++ // ++ // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) ++ ++ UCHAR VERLEN; // 4 BITS VERSION, 4 BITS LENGTH ++ UCHAR TOS; // TYPE OF SERVICE ++ USHORT IPLENGTH; // DATAGRAM LENGTH ++ USHORT IPID; // IDENTIFICATION ++ USHORT FRAGWORD; // 3 BITS FLAGS, 13 BITS OFFSET ++ UCHAR IPTTL; ++ UCHAR IPPROTOCOL; // HIGHER LEVEL PROTOCOL ++ USHORT IPCHECKSUM; // HEADER CHECKSUM ++ struct myin_addr IPSOURCE; ++ struct myin_addr IPDEST; ++ ++ UCHAR Data; ++ ++} IPMSG, *PIPMSG; ++ ++ ++typedef struct _TCPMSG ++{ ++ ++ // FORMAT OF TCP HEADER WITHIN AN IP DATAGRAM ++ ++ // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) ++ ++ USHORT SOURCEPORT; ++ USHORT DESTPORT; ++ ++ ULONG SEQNUM; ++ ULONG ACKNUM; ++ ++ UCHAR TCPCONTROL; // 4 BITS DATA OFFSET 4 RESERVED ++ UCHAR TCPFLAGS; // (2 RESERVED) URG ACK PSH RST SYN FIN ++ ++ USHORT WINDOW; ++ USHORT CHECKSUM; ++ USHORT URGPTR; ++ ++ ++} TCPMSG, *PTCPMSG; ++ ++typedef struct _UDPMSG ++{ ++ ++ // FORMAT OF UDP HEADER WITHIN AN IP DATAGRAM ++ ++ // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) ++ ++ USHORT SOURCEPORT; ++ USHORT DESTPORT; ++ USHORT LENGTH; ++ USHORT CHECKSUM; ++ UCHAR UDPData[0]; ++ ++} UDPMSG, *PUDPMSG; ++ ++// ICMP MESSAGE STRUCTURE ++ ++typedef struct _ICMPMSG ++{ ++ // FORMAT OF ICMP HEADER WITHIN AN IP DATAGRAM ++ ++ // NOTE THESE FIELDS ARE STORED HI ORDER BYTE FIRST (NOT NORMAL 8086 FORMAT) ++ ++ UCHAR ICMPTYPE; ++ UCHAR ICMPCODE; ++ USHORT ICMPCHECKSUM; ++ ++ USHORT ICMPID; ++ USHORT ICMPSEQUENCE; ++ UCHAR ICMPData[0]; ++ ++} ICMPMSG, *PICMPMSG; ++ ++ ++typedef struct _L3MESSAGE ++{ ++ // ++ // NETROM LEVEL 3 MESSAGE - WITHOUT L2 INFO ++ // ++ UCHAR L3SRCE[7]; // ORIGIN NODE ++ UCHAR L3DEST[7]; // DEST NODE ++ UCHAR L3TTL; // TX MONITOR FIELD - TO PREVENT MESSAGE GOING // ROUND THE NETWORK FOR EVER DUE TO ROUTING LOOP ++// ++// NETROM LEVEL 4 DATA ++// ++ UCHAR L4INDEX; // TRANSPORT SESSION INDEX ++ UCHAR L4ID; // TRANSPORT SESSION ID ++ UCHAR L4TXNO; // TRANSMIT SEQUENCE NUMBER ++ UCHAR L4RXNO; // RECEIVE (ACK) SEQ NUMBER ++ UCHAR L4FLAGS; // FRAGMENTATION, ACK/NAK, FLOW CONTROL AND MSG TYPE BITS ++ ++ UCHAR L4DATA[236]; //DATA ++ ++} L3MESSAGE, *PL3MESSAGE; ++ ++ ++typedef struct _MESSAGE ++{ ++ // BASIC LINK LEVEL MESSAGE BUFFER LAYOUT ++ ++ struct _MESSAGE * CHAIN; ++ ++ UCHAR PORT; ++ USHORT LENGTH; ++ ++ UCHAR DEST[7]; ++ UCHAR ORIGIN[7]; ++ ++ // MAY BE UP TO 56 BYTES OF DIGIS ++ ++ UCHAR CTL; ++ UCHAR PID; ++ ++ union ++ { /* array named screen */ ++ UCHAR L2DATA[256]; ++ struct _L3MESSAGE L3MSG; ++ }; ++ ++ ++}MESSAGE, *PMESSAGE; ++ ++//#pragma pack() ++#pragma pack(pop) ++ ++char * strlop(char * buf, char delim); ++UCHAR * DisplayINP3RIF(UCHAR * ptr1, UCHAR * ptr2, unsigned int msglen); ++char * DISPLAY_NETROM(MESSAGE * ADJBUFFER, UCHAR * Output, int MsgLen); ++UCHAR * DISPLAYIPDATAGRAM(IPMSG * IP, UCHAR * Output, int MsgLen); ++char * DISPLAYARPDATAGRAM(UCHAR * Datagram, UCHAR * Output); ++ ++int CountBits(unsigned long in) ++{ ++ int n = 0; ++ while (in) ++ { ++ if (in & 1) n++; ++ in >>= 1; ++ } ++ return n; ++} ++ ++BOOL ConvToAX25(char * callsign, unsigned char * ax25call) ++{ ++ int i; ++ ++ memset(ax25call, 0x40, 6); // in case short ++ ax25call[6] = 0x60; // default SSID ++ ++ for (i = 0; i < 7; i++) ++ { ++ if (callsign[i] == '-') ++ { ++ // ++ // process ssid and return ++ // ++ i = atoi(&callsign[i + 1]); ++ ++ if (i < 16) ++ { ++ ax25call[6] |= i << 1; ++ return (TRUE); ++ } ++ return (FALSE); ++ } ++ ++ if (callsign[i] == 0 || callsign[i] == 13 || callsign[i] == ' ' || callsign[i] == ',') ++ { ++ // ++ // End of call - no ssid ++ // ++ return (TRUE); ++ } ++ ++ ax25call[i] = callsign[i] << 1; ++ } ++ ++ // ++ // Too many chars ++ // ++ ++ return (FALSE); ++} ++ ++ ++int ConvFromAX25(unsigned char * incall, char * outcall) ++{ ++ int in, out = 0; ++ unsigned char chr; ++ ++ memset(outcall, 0x20, 10); ++ ++ for (in = 0; in < 6; in++) ++ { ++ chr = incall[in]; ++ if (chr == 0x40) ++ break; ++ chr >>= 1; ++ outcall[out++] = chr; ++ } ++ ++ chr = incall[6]; // ssid ++ ++ if (chr == 0x42) ++ { ++ outcall[out++] = '-'; ++ outcall[out++] = 'T'; ++ return out; ++ } ++ ++ if (chr == 0x44) ++ { ++ outcall[out++] = '-'; ++ outcall[out++] = 'R'; ++ return out; ++ } ++ ++ chr >>= 1; ++ chr &= 15; ++ ++ if (chr > 0) ++ { ++ outcall[out++] = '-'; ++ if (chr > 9) ++ { ++ chr -= 10; ++ outcall[out++] = '1'; ++ } ++ chr += 48; ++ outcall[out++] = chr; ++ } ++ return (out); ++} ++ ++TKISSMode ** KissConnections = NULL; ++int KISSConCount = 0; ++ ++#define FEND 0xc0 ++#define FESC 0xDB ++#define TFEND 0xDC ++#define TFESC 0xDD ++#define KISS_ACKMODE 0x0C ++#define KISS_DATA 0 ++ ++int KISS_encode(UCHAR * KISSBuffer, int port, string * frame, int TXMON); ++ ++void KISS_init() ++{ ++ int i; ++ ++ KISS.data_in = newString(); ++ ++ // initTStringList(KISS.socket); ++ ++ for (i = 0; i < 4; i++) ++ { ++ initTStringList(&KISS.buffer[i]); ++ } ++} ++ ++void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len); ++ ++void KISSDataReceived(void * socket, unsigned char * data, int length) ++{ ++ int i; ++ unsigned char * ptr1, *ptr2; ++ int Length; ++ ++ TKISSMode * KISS = NULL; ++ ++ if (KISSConCount == 0) ++ return; ++ ++ for (i = 0; i < KISSConCount; i++) ++ { ++ if (KissConnections[i]->Socket == socket) ++ { ++ KISS = KissConnections[i]; ++ break; ++ } ++ } ++ ++ if (KISS == NULL) ++ return; ++ ++ stringAdd(KISS->data_in, data, length); ++ ++ if (KISS->data_in->Length > 10000) // Probably AGW Data on KISS Port ++ { ++ KISS->data_in->Length = 0; ++ return; ++ } ++ ++ ptr1 = KISS->data_in->Data; ++ Length = KISS->data_in->Length; ++ ++ ++ while ((ptr2 = memchr(ptr1, FEND, Length))) ++ { ++ int Len = (ptr2 - ptr1); ++ ++ if (Len == 0) ++ { ++ // Start of frame ++ ++ mydelete(KISS->data_in, 0, 1); ++ ++ ptr1 = KISS->data_in->Data; ++ Length = KISS->data_in->Length; ++ ++ continue; ++ } ++ ++ // Process Frame ++ ++ if (Len < 350) // Drop obviously corrupt frames ++ ProcessKISSFrame(socket, ptr1, Len); ++ ++ mydelete(KISS->data_in, 0, Len + 1); ++ ++ ptr1 = KISS->data_in->Data; ++ Length = KISS->data_in->Length; ++ ++ } ++} ++ ++void analiz_frame(int snd_ch, string * frame, void * socket, boolean fecflag); ++ ++void KISSSendtoServer(void * Socket, char * Data, int Length); ++ ++void ProcessKISSFrame(void * socket, UCHAR * Msg, int Len) ++{ ++ int n = Len; ++ UCHAR c; ++ int ESCFLAG = 0; ++ UCHAR * ptr1, *ptr2; ++ int Chan; ++ int Opcode; ++ string * TXMSG; ++ ++ ptr1 = ptr2 = Msg; ++ ++ while (n--) ++ { ++ c = *(ptr1++); ++ ++ if (ESCFLAG) ++ { ++ // ++ // FESC received - next should be TFESC or TFEND ++ ++ ESCFLAG = 0; ++ ++ if (c == TFESC) ++ c = FESC; ++ ++ if (c == TFEND) ++ c = FEND; ++ ++ } ++ else ++ { ++ switch (c) ++ { ++ case FEND: ++ ++ // ++ // Either start of message or message complete ++ // ++ ++ // npKISSINFO->MSGREADY = TRUE; ++ return; ++ ++ case FESC: ++ ++ ESCFLAG = 1; ++ continue; ++ ++ } ++ } ++ ++ // ++ // Ok, a normal char ++ // ++ ++ *(ptr2++) = c; ++ ++ } ++ Len = ptr2 - Msg; ++ ++ Chan = (Msg[0] >> 4); ++ Opcode = Msg[0] & 0x0f; ++ ++ if (Chan > 3) ++ return; ++ ++ // This is a lot simpler than QtSM, as frames will always be immediately processed locally, so ack mode isn't needed. ++ // but if enabled ack can be sent immediately ++ // checksum if needed ++ ++ switch (Opcode) ++ { ++ case KISS_ACKMODE: ++ { ++ // send ack ++ ++ unsigned char ACK[16]; ++ unsigned char * ackptr = ACK; ++ ++ *ackptr++ = FEND; ++ *ackptr++ = Msg[0]; // opcode and channel ++ ++ *ackptr++ = Msg[1]; ++ *ackptr++ = Msg[2]; // ACK Bytes ++ *ackptr++ = FEND; ++ ++ KISSSendtoServer(socket, ACK, 5); ++ ++ // remove ack bytes ++ ++ memmove(&Msg[1], &Msg[3], Len - 2); ++ ++ // drop through to KISS Data ++ ++ Len -= 2; ++ } ++ case KISS_DATA: ++ ++ if (KISSChecksum) ++ { ++ // SUM MESSAGE, AND IF DUFF DISCARD. IF OK DECREMENT COUNT TO REMOVE SUM ++ ++ int sumlen = Len; ++ char * ptr = &Msg[0]; ++ UCHAR sum = 0; ++ ++ while (sumlen--) ++ { ++ sum ^= *(ptr++); ++ } ++ ++ if (sum) ++ { ++ Debugprintf("KISS Checksum Error"); ++ return; ++ } ++ ++ Len--; // Remove Checksum ++ } ++ ++ TXMSG = newString(); ++ stringAdd(TXMSG, &Msg[1], Len - 1); // include Control ++ ++ MHPROC(TXMSG->Data, TXMSG->Length); ++ ++ analiz_frame(Chan, TXMSG, socket, 0); ++ ++ free(TXMSG); ++ return; ++ } ++ ++ // Still need to process kiss control frames ++} ++ ++ ++void KISS_add_stream(void * Socket) ++{ ++ // Add a new connection. Called when QT accepts an incoming call} ++ ++ TKISSMode * KISS; ++ ++ KissConnections = realloc(KissConnections, (KISSConCount + 1) * sizeof(void *)); ++ ++ KISS = KissConnections[KISSConCount++] = malloc(sizeof(TKISSMode)); ++ ++ KISS->Socket = Socket; ++ KISS->data_in = newString(); ++ ++} ++ ++void KISS_del_socket(void * socket) ++{ ++ int i; ++ ++ TKISSMode * KISS = NULL; ++ ++ if (KISSConCount == 0) ++ return; ++ ++ for (i = 0; i < KISSConCount; i++) ++ { ++ if (KissConnections[i]->Socket == socket) ++ { ++ KISS = KissConnections[i]; ++ break; ++ } ++ } ++ ++ if (KISS == NULL) ++ return; ++ ++ // Need to remove entry and move others down ++ ++ KISSConCount--; ++ ++ while (i < KISSConCount) ++ { ++ KissConnections[i] = KissConnections[i + 1]; ++ i++; ++ } ++} ++ ++TAX25Port * get_free_port(int snd_ch); ++ ++TAX25Port * KISSConnectOut(void * Sess, char * CallFrom, char * CallTo, char * Digis, int Chan, void * Socket) ++{ ++ TAX25Port * AX25Sess = 0; ++ char path[128]; ++ Byte axpath[80]; ++ ++ AX25Sess = get_free_port(Chan); ++ ++ if (AX25Sess) ++ { ++ AX25Sess->snd_ch = Chan; ++ AX25Sess->Sess = Sess; ++ strcpy(AX25Sess->mycall, CallFrom); ++ strcpy(AX25Sess->corrcall, CallTo); ++ AX25Sess->PID = 0xf0; ++ ++ sprintf(path, "%s,%s", CallTo, CallFrom); ++ ++ if (Digis && Digis[0]) ++ { ++ strcat(path, ","); ++ strcat(path, Digis); ++ } ++ ++ AX25Sess->digi[0] = 0; ++ ++ // rst_timer(snd_ch, free_port); ++ ++ strcpy(AX25Sess->kind, "Outgoing"); ++ AX25Sess->socket = Socket; ++ ++ AX25Sess->pathLen = get_addr(path, axpath); ++ ++ if (AX25Sess->pathLen == 0) ++ return AX25Sess; // Invalid Path ++ ++ strcpy((char *)AX25Sess->Path, (char *)axpath); ++ reverse_addr(axpath, AX25Sess->ReversePath, AX25Sess->pathLen); ++ ++ set_link(AX25Sess, AX25Sess->Path); // Sends SABM ++ return AX25Sess; ++ } ++ return 0; ++} ++ ++ ++ ++// Monitor Code - from moncode.asm ++ ++ ++#define CMDBIT 4 // CURRENT MESSAGE IS A COMMAND ++#define RESP 2 // CURRENT MSG IS RESPONSE ++#define VER1 1 // CURRENT MSG IS VERSION 1 ++ ++ ++#define UI 3 ++#define SABM 0x2F ++#define DISC 0x43 ++#define DM 0x0F ++#define UA 0x63 ++#define FRMR 0x87 ++#define RR 1 ++#define RNR 5 ++#define REJ 9 ++ ++#define SREJ 0x0D ++#define SABME 0x6F ++#define XID 0xAF ++#define TEST 0xE3 ++ ++ ++#define PFBIT 0x10 // POLL/FINAL BIT IN CONTROL BYTE ++ ++#define NETROM_PID 0xCF ++#define IP_PID 0xCC ++#define ARP_PID 0xCD ++ ++#define NODES_SIG 0xFF ++ ++char ShortDT[] = "HH:MM:SS"; ++ ++int KISSLocalTime = 0; ++int KISSMonEnable = 0; ++int KISSMonNodes = 0; ++ ++char * ShortDateTime() ++{ ++ struct tm * tm; ++ time_t NOW = time(NULL); ++ ++ if (KISSLocalTime) ++ tm = localtime(&NOW); ++ else ++ tm = gmtime(&NOW); ++ ++ sprintf(ShortDT, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); ++ return ShortDT; ++} ++ ++ ++char FrameData[1024] = ""; ++ ++char * frame_monitor(string * frame, char * code, int tx_stat) ++{ ++ char mon_frm[512]; ++ char Path[256]; ++ ++ char * frm = "???"; ++ Byte * datap; ++ Byte _data[512] = ""; ++ Byte * p_data = _data; ++ int _datalen; ++ char CallFrom[10], CallTo[10], Digi[80]; ++ ++ char TR = 'R'; ++ char codestr[16] = ""; ++ ++ integer i; ++ int len; ++ ++ ++ Byte pid, nr, ns, f_type, f_id; ++ Byte rpt, cr, pf; ++ Byte path[80]; ++ char c; ++ const char * p; ++ ++ string * data = newString(); ++ ++ if (code[0] && strlen(code) < 14) ++ sprintf(codestr, "[%s]", code); ++ ++ if (tx_stat) ++ TR = 'T'; ++ ++ if (tx_stat) // TX frame has control byte ++ ++ decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); ++ else ++ decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); ++ ++ ++ datap = data->Data; ++ ++ len = data->Length; ++ ++ if (pid == 0xCF) ++ { ++ if (datap[0] == 255) //Nodes broadcast ++ { ++ if (KISSMonNodes == 0) ++ { ++ freeString(data); ++ return 0; ++ } ++ } ++ } ++ ++ ++ ++ // data = parse_NETROM(data, f_id); ++ // IP parsing ++ // else if (pid == 0xCC) ++ // data = parse_IP(data); ++ // ARP parsing ++ // else if (pid == 0xCD) ++ // data = parse_ARP(data); ++ // ++ ++ if (len > 0) ++ { ++ for (i = 0; i < len; i++) ++ { ++ if (datap[i] > 31 || datap[i] == 13 || datap[i] == 9) ++ *(p_data++) = datap[i]; ++ } ++ } ++ ++ _datalen = p_data - _data; ++ ++ if (_datalen) ++ { ++ Byte * ptr = _data; ++ i = 0; ++ ++ // remove successive cr or cr on end while (i < _datalen) ++ ++ while (i < _datalen) ++ { ++ if ((_data[i] == 13) && (_data[i + 1] == 13)) ++ i++; ++ else ++ *(ptr++) = _data[i++]; ++ } ++ ++ if (*(ptr - 1) == 13) ++ ptr--; ++ ++ *ptr = 0; ++ ++ _datalen = ptr - _data; ++ } ++ ++ get_monitor_path(path, CallTo, CallFrom, Digi); ++ ++ if (cr) ++ { ++ c = 'C'; ++ if (pf) ++ p = " P"; ++ else p = ""; ++ } ++ else ++ { ++ c = 'R'; ++ if (pf) ++ p = " F"; ++ else ++ p = ""; ++ } ++ ++ switch (f_id) ++ { ++ case I_I: ++ ++ frm = "I"; ++ break; ++ ++ case S_RR: ++ ++ frm = "RR"; ++ break; ++ ++ case S_RNR: ++ ++ frm = "RNR"; ++ break; ++ ++ case S_REJ: ++ ++ frm = "REJ"; ++ break; ++ ++ case S_SREJ: ++ ++ frm = "SREJ"; ++ break; ++ ++ case U_SABM: ++ ++ frm = "SABM"; ++ break; ++ ++ case SABME: ++ ++ frm = "SABME"; ++ break; ++ ++ case U_DISC: ++ ++ frm = "DISC"; ++ break; ++ ++ case U_DM: ++ ++ frm = "DM"; ++ break; ++ ++ case U_UA: ++ ++ frm = "UA"; ++ break; ++ ++ case U_FRMR: ++ ++ frm = "FRMR"; ++ break; ++ ++ case U_UI: ++ ++ frm = "UI"; ++ } ++ ++// 07:29:42T G8BPQ - 2 > TEST Port = 20 < UI > : ++// helllo ++// 07:30: 8T G8BPQ - 2 > ID Port = 20 < UI C > : ++// Network node(BPQ) ++ ++ if (Digi[0]) ++// sprintf(Path, "Fm %s To %s Via %s <%s %c%s", CallFrom, CallTo, Digi, frm, c, p); ++ sprintf(Path, "%s%c %s>%s,%s <%s %c%s", ShortDateTime(), TR, CallFrom, CallTo, Digi, frm, c, p); ++ else ++// sprintf(Path, "Fm %s To %s <%s %c %s", CallFrom, CallTo, frm, c, p); ++ sprintf(Path, "%s%c %s>%s <%s %c%s", ShortDateTime(), TR, CallFrom, CallTo, frm, c, p); ++ ++ ++ switch (f_type) ++ { ++ case I_FRM: ++ ++ //mon_frm = Path + ctrl + ' R' + inttostr(nr) + ' S' + inttostr(ns) + ' pid=' + dec2hex(pid) + ' Len=' + inttostr(len) + ' >' + time_now + #13 + _data + #13#13; ++ sprintf(mon_frm, "%s R%d S%d>%s\r%s\r", Path, nr, ns, codestr, _data); ++ ++ break; ++ ++ case U_FRM: ++ ++ if (f_id == U_UI) ++ { ++ sprintf(mon_frm, "%s>:\r%s\r", Path, _data); // "= Path + ctrl + '>' + time_now + #13; ++ } ++ else if (f_id == U_FRMR) ++ { ++ sprintf(mon_frm, "%s>%02x %02x %02x\r", Path, datap[0], datap[1], datap[2]); // "= Path + ctrl + '>' + time_now + #13; ++ } ++ else ++ sprintf(mon_frm, "%s>%s\r", Path, codestr); // "= Path + ctrl + '>' + time_now + #13; ++ ++ break; ++ ++ case S_FRM: ++ ++ // mon_frm = Path + ctrl + ' R' + inttostr(nr) + ' >' + time_now + #13; ++ sprintf(mon_frm, "%s R%d>%s\r", Path, nr, codestr); // "= Path + ctrl + '>' + time_now + #13; ++ ++ break; ++ ++ } ++ sprintf(FrameData, "%s", mon_frm); ++ ++ freeString(data); ++ return FrameData; ++} ++ ++typedef struct _MHSTRUC ++{ ++ UCHAR MHCALL[7]; ++ UCHAR MHDIGIS[7][8]; ++ time_t MHTIME; ++ int MHCOUNT; ++ unsigned char MHDIGI; ++ char MHFreq[12]; ++ char MHLocator[6]; ++} MHSTRUC, *PMHSTRUC; ++ ++ ++#define MHENTRIES 30 ++ ++MHSTRUC MHEARD[(MHENTRIES + 1) * sizeof(MHSTRUC)] = { 0 }; ++ ++int CompareCalls(UCHAR * c1, UCHAR * c2) ++{ ++ // COMPARE AX25 CALLSIGNS IGNORING EXTRA BITS IN SSID ++ ++ if (memcmp(c1, c2, 6)) ++ return FALSE; // No Match ++ ++ if ((c1[6] & 0x1e) == (c2[6] & 0x1e)) ++ return TRUE; ++ ++ return FALSE; ++} ++ ++static char *month[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; ++ ++void * MHWindow = 0; ++void WritetoMHWindow(char * Buffer); ++int KISSMH = 0; ++ ++char * FormatMH(PMHSTRUC MH) ++{ ++ struct tm * TM; ++ static char MHTime[50]; ++ time_t szClock; ++ char LOC[7]; ++ ++ memcpy(LOC, MH->MHLocator, 6); ++ LOC[6] = 0; ++ ++ szClock = MH->MHTIME; ++// else ++// szClock = time(NULL) - MH->MHTIME; ++ ++ TM = gmtime(&szClock); ++ ++ sprintf(MHTime, "%s %02d %.2d:%.2d:%.2d %s %s", ++ month[TM->tm_mon], TM->tm_mday, TM->tm_hour, TM->tm_min, TM->tm_sec, MH->MHFreq, LOC); ++ ++ return MHTime; ++} ++ ++ ++ ++ ++void MHPROC(unsigned char * Packet, int Len) ++{ ++ PMHSTRUC MH = &MHEARD[0]; ++ PMHSTRUC MHBASE = MH; ++ int i; ++ int OldCount = 0; ++ char Freq[64] = ""; ++ char DIGI = '*'; ++ ++ MESSAGE Frame; ++ MESSAGE * Buffer = &Frame; ++ ++ memcpy(Buffer->DEST, Packet, Len); ++ ++ ++ // if port has a freq associated with it use it ++ ++ ++ // if (Buffer->ORIGIN[6] & 1) ++ DIGI = 0; // Don't think we want to do this ++ ++// See if in list ++ ++ for (i = 0; i < MHENTRIES; i++) ++ { ++ if ((MH->MHCALL[0] == 0) || (CompareCalls(Buffer->ORIGIN, MH->MHCALL) && MH->MHDIGI == DIGI)) // Spare or our entry ++ { ++ OldCount = MH->MHCOUNT; ++ goto DoMove; ++ } ++ MH++; ++ } ++ ++ // TABLE FULL AND ENTRY NOT FOUND - MOVE DOWN ONE, AND ADD TO TOP ++ ++ i = MHENTRIES - 1; ++ ++ // Move others down and add at front ++DoMove: ++ if (i != 0) // First ++ memmove(MHBASE + 1, MHBASE, i * sizeof(MHSTRUC)); ++ ++ memcpy(MHBASE->MHCALL, Buffer->ORIGIN, 7 * 9); // Save Digis ++ MHBASE->MHDIGI = DIGI; ++ MHBASE->MHTIME = time(NULL); ++ MHBASE->MHCOUNT = ++OldCount; ++ strcpy(MHBASE->MHFreq, Freq); ++ MHBASE->MHLocator[0] = 0; ++ ++ if (MHWindow) ++ { ++ int count = MHENTRIES; ++ int n; ++ char Normcall[20]; ++ char From[10]; ++ char DigiList[100]; ++ char * Output; ++ int len; ++ char Digi = 0; ++ char MHPage[MHENTRIES * 100]; ++ char * Bufferptr = MHPage; ++ unsigned char * ptr; ++ ++ MH = &MHEARD[0]; ++ ++ // Note that the MHDIGIS field may contain rubbish. You have to check End of Address bit to find ++ // how many digis there are ++ ++ Bufferptr += sprintf(Bufferptr, "Callsign Last heard Pkts RX via Digi\r"); ++ Bufferptr += sprintf(Bufferptr, "\r"); ++ ++ while (count--) ++ { ++ if (MH->MHCALL[0] == 0) ++ break; ++ ++ Digi = 0; ++ ++ len = ConvFromAX25(MH->MHCALL, Normcall); ++ ++ Normcall[len++] = MH->MHDIGI; ++ Normcall[len++] = 0; ++ ++ n = 8; // Max number of digi-peaters ++ ++ ptr = &MH->MHCALL[6]; // End of Address bit ++ ++ Output = &DigiList[0]; ++ ++ if ((*ptr & 1) == 0) ++ { ++ // at least one digi ++ ++ strcpy(Output, "via "); ++ Output += 4; ++ ++ while ((*ptr & 1) == 0) ++ { ++ // MORE TO COME ++ ++ From[ConvFromAX25(ptr + 1, From)] = 0; ++ Output += sprintf((char *)Output, "%s", From); ++ ++ ptr += 7; ++ n--; ++ ++ if (n == 0) ++ break; ++ ++ // See if digi actioned - put a * on last actioned ++ ++ if (*ptr & 0x80) ++ { ++ if (*ptr & 1) // if last address, must need * ++ { ++ *(Output++) = '*'; ++ Digi = '*'; ++ } ++ ++ else ++ if ((ptr[7] & 0x80) == 0) // Repeased by next? ++ { ++ *(Output++) = '*'; // No, so need * ++ Digi = '*'; ++ } ++ ++ } ++ *(Output++) = ','; ++ } ++ *(--Output) = 0; // remove last comma ++ } ++ else ++ *(Output) = 0; ++ ++ // if we used a digi set * on call and display via string ++ ++ ++ if (Digi) ++ Normcall[len++] = Digi; ++ else ++ DigiList[0] = 0; // Dont show list if not used ++ ++ Normcall[len++] = 0; ++ ++ ptr = FormatMH(MH); ++ ++ Bufferptr += sprintf(Bufferptr, "%-10s %-10s %-10d %-30s\r", Normcall, ptr, MH->MHCOUNT, DigiList); ++ ++ MH++; ++ } ++ ++ WritetoMHWindow(MHPage); ++ } ++ return; ++} ++ ++ ++ ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/ax25.h ++++ qttermtcp-0.0.0.79/ax25.h +@@ -1,293 +1,293 @@ +-// ax.25 code for QtTERMTCP KISS Mode +- +-// based on SoundModem/QtSoundModem ax.25 code +- +-// The underlying code allows for up to four KISS ports, but at the moment +-// the config and user interface only supports 1 +- +-// The code supports KISS over a Serial port or TCP connection +- +-#include +-#include +-#include +-#include +-#include +-#include +- +-#define UNUSED(x) (void)(x) +- +-#define single float +-#define boolean int +-#define Byte unsigned char // 0 to 255 +-#define Word unsigned short // 0 to 65,535 +-#define SmallInt short // -32,768 to 32,767 +-#define LongWord unsigned int // 0 to 4,294,967,295 +-// Int6 : Cardinal; // 0 to 4,294,967,295 +-#define LongInt int // -2,147,483,648 to 2,147,483,647 +-#define Integer int // -2,147,483,648 to 2,147,483,647 +-//#define Int64 long long // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 +- +-//#define Byte unsigned char // 0 to 255 +-#define word unsigned short // 0 to 65,535 +-#define smallint short // -32,768 to 32,767 +-#define longword unsigned int // 0 to 4,294,967,295 +- // Int6 : Cardinal; // 0 to 4,294,967,295 +-#define longint int // -2,147,483,648 to 2,147,483,647 +-#define integer int // -2,147,483,648 to 2,147,483,647 +- +-typedef unsigned long ULONG; +- +-#define UCHAR unsigned char +-#define UINT unsigned int +-#define BOOL int +-#define TRUE 1 +-#define FALSE 0 +- +-#define FEND 0xc0 +-#define FESC 0xDB +-#define TFEND 0xDC +-#define TFESC 0xDD +- +-#define port_num 32 // ?? Max AGW sessions +-#define PKT_ERR 15 // Minimum packet size, bytes +-#define I_MAX 7 // Maximum number of packets +- +- +-// Status flags +- +-#define STAT_NO_LINK 0 +-#define STAT_LINK 1 +-#define STAT_CHK_LINK 2 +-#define STAT_WAIT_ANS 3 +-#define STAT_TRY_LINK 4 +-#define STAT_TRY_UNLINK 5 +- +- +- // Ñmd,Resp,Poll,Final,Digipeater flags +-#define SET_P 1 +-#define SET_F 0 +-#define SET_C 1 +-#define SET_R 0 +-#define SET_NO_RPT 0 +-#define SET_RPT 1 +- // Frame ID flags +-#define I_FRM 0 +-#define S_FRM 1 +-#define U_FRM 2 +-#define I_I 0 +-#define S_RR 1 +-#define S_RNR 5 +-#define S_REJ 9 +-#define S_SREJ 0x0D +-#define U_SABM 47 +-#define U_DISC 67 +-#define U_DM 15 +-#define U_UA 99 +-#define U_FRMR 135 +-#define U_UI 3 +- // PID flags +-#define PID_X25 0x01 // 00000001-CCIT X25 PLP +-#define PID_SEGMENT 0x08 // 00001000-Segmentation fragment +-#define PID_TEXNET 0xC3 // 11000011-TEXNET Datagram Protocol +-#define PID_LQ 0xC4 // 11001000-Link Quality Protocol +-#define PID_APPLETALK 0xCA // 11001010-Appletalk +-#define PID_APPLEARP 0xCB // 11001011-Appletalk ARP +-#define PID_IP 0xCC // 11001100-ARPA Internet Protocol +-#define PID_ARP 0xCD // 11001101-ARPA Address Resolution Protocol +-#define PID_NET_ROM 0xCF // 11001111-NET/ROM +- +-#define FX25_LOAD 1 +- +-#define MODE_OUR 0 +-#define MODE_OTHER 1 +-#define MODE_RETRY 2 +- +-#define TIMER_FREE 0 +-#define TIMER_BUSY 1 +-#define TIMER_OFF 2 +-#define TIMER_EVENT_ON 3 +-#define TIMER_EVENT_OFF 4 +- +- +-typedef struct string_T +-{ +- unsigned char * Data; +- int Length; +- int AllocatedLength; // A reasonable sized block is allocated at the start to speed up adding chars +- +-}string; +- +-typedef struct TStringList_T +-{ +- int Count; +- string ** Items; +- +-} TStringList; +- +- +-typedef struct TAX25Info_t +-{ +- longint stat_s_pkt; +- longint stat_s_byte; +- longint stat_r_pkt; +- longint stat_r_byte; +- longint stat_r_fc; +- longint stat_fec_count; +- time_t stat_begin_ses; +- time_t stat_end_ses; +- longint stat_l_r_byte; +- longint stat_l_s_byte; +- +-} TAX25Info; +- +-typedef struct TAX25Port_t +-{ +- Byte hi_vs; +- Byte vs; +- Byte vr; +- Byte PID; +- TStringList in_data_buf; +- TStringList frm_collector; +- string frm_win[8]; +- string out_data_buf; +- word t1; +- word t2; +- word t3; +- Byte i_lo; +- Byte i_hi; +- word n1; +- word n2; +- word IPOLL_cnt; +- TStringList frame_buf; //áóôåð êàäðîâ íà ïåðåäà÷ó +- TStringList I_frame_buf; +- Byte status; +- word clk_frack; +- char corrcall[10]; +- char mycall[10]; +- UCHAR digi[56]; +- UCHAR Path[80]; // Path in ax25 format - added to save building it each time +- UCHAR ReversePath[80]; +- int snd_ch; // Simplifies parameter passing +- int port; +- int pathLen; +- void * socket; +- void * Sess; +- char kind[16]; +- TAX25Info info; +-} TAX25Port; +- +-typedef struct TKISSMode_t +-{ +- string * data_in; +- void * Socket; // Used as a key +- +- // Not sure what rest are used for. Seems to be one per channel +- +- TStringList buffer[4]; // Outgoing Frames +- +-} TKISSMode; +- +-// Dephi emulation functions +- +-string * Strings(TStringList * Q, int Index); +-void Clear(TStringList * Q); +-int Count(TStringList * List); +- +-string * newString(); +-string * copy(string * Source, int StartChar, int Count); +-TStringList * newTStringList(); +- +-void freeString(string * Msg); +-void initString(string * S); +-void initTStringList(TStringList* T); +- +-// Two delete() This is confusing!! +-// Not really - one acts on String, other TStringList +- +-void Delete(TStringList * Q, int Index); +-void mydelete(string * Source, int StartChar, int Count); +-void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount); +-void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount); +-void setlength(string * Msg, int Count); // Set string length +-string * stringAdd(string * Msg, UCHAR * Chars, int Count); // Extend string +-void Assign(TStringList * to, TStringList * from); // Duplicate from to to +-string * duplicateString(string * in); +-int my_indexof(TStringList * l, string * s); +-boolean compareStrings(string * a, string * b); +-int Add(TStringList * Q, string * Entry); +-void Debugprintf(const char * format, ...); +-void ax25_info_init(TAX25Port * AX25Sess); +-void clr_frm_win(TAX25Port * AX25Sess); +-void decode_frame(Byte * frame, int len, Byte * path, string * data, +- Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id, +- Byte * rpt, Byte * pf, Byte * cr); +-#ifdef __cplusplus +-extern "C" void KISSSendtoServer(myTcpSocket* Socket, char * Data, int Length); +-extern "C" void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded); +-extern "C" void WriteDebugLog(char * Mess); +-extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len); +-extern "C" void ClearSessLabel(Ui_ListenSession * Sess); +-extern "C" void rst_timer(TAX25Port * AX25Sess); +-extern "C" void Send_UI(int port, Byte PID, char * CallFrom, char *CallTo, char * Via, Byte * Msg, int MsgLen); +-#else +-void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded); +-void SendtoTerm(void * Sess, char * Msg, int Len); +-void ClearSessLabel(void * Sess); +-void WriteDebugLog(char * Mess); +-void AX25_disc(TAX25Port * AX25Sess, Byte mode); +-void rst_timer(TAX25Port * AX25Sess); +-void Send_UI(int port, Byte PID, char * CallFrom, char *CallTo, char * via, Byte * Msg, int MsgLen); +-#endif +- +-BOOL ConvToAX25(char * callsign, unsigned char * ax25call); +-int ConvFromAX25(unsigned char * incall, char * outcall); +-void reverse_addr(Byte * path, Byte * revpath, int Len); +-void set_DM(int snd_ch, Byte * path); +-void set_link(TAX25Port * AX25Sess, UCHAR * axpath); +-boolean is_last_digi(Byte *path); +-boolean is_correct_path(Byte * path, Byte pid); +-int number_digi(unsigned char * path); +-void AX25_conn(TAX25Port * AX25Sess, int snd_ch, Byte mode); +-void write_ax25_info(TAX25Port * AX25Sess); +-void rst_values(TAX25Port * AX25Sess); +- +-#ifdef __cplusplus +-extern "C" +-{ +-#endif +- +-extern boolean dyn_frack[4]; +-extern Byte recovery[4]; +-extern Byte users[4]; +- +-extern int resptime[4]; +-extern int slottime[4]; +-extern int persist[4]; +-extern int kisspaclen[4]; +-extern int fracks[4]; +-extern int frack_time[4]; +-extern int idletime[4]; +-extern int redtime[4]; +-extern int IPOLL[4]; +-extern int maxframe[4]; +-extern int TXFrmMode[4]; +- +-extern char MyDigiCall[4][512]; +-extern char exclude_callsigns[4][512]; +-extern char exclude_APRS_frm[4][512]; +- +-extern TStringList list_exclude_callsigns[4]; +-extern TStringList list_exclude_APRS_frm[4]; +-extern TStringList list_digi_callsigns[4]; +- +-extern int max_frame_collector[4]; +-extern boolean KISS_opt[4]; +- +-extern TAX25Port AX25Port[4][port_num]; +- +-extern TStringList KISS_acked[]; +-extern TStringList KISS_iacked[]; +- +-#ifdef __cplusplus +-} ++// ax.25 code for QtTERMTCP KISS Mode ++ ++// based on SoundModem/QtSoundModem ax.25 code ++ ++// The underlying code allows for up to four KISS ports, but at the moment ++// the config and user interface only supports 1 ++ ++// The code supports KISS over a Serial port or TCP connection ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define UNUSED(x) (void)(x) ++ ++#define single float ++#define boolean int ++#define Byte unsigned char // 0 to 255 ++#define Word unsigned short // 0 to 65,535 ++#define SmallInt short // -32,768 to 32,767 ++#define LongWord unsigned int // 0 to 4,294,967,295 ++// Int6 : Cardinal; // 0 to 4,294,967,295 ++#define LongInt int // -2,147,483,648 to 2,147,483,647 ++#define Integer int // -2,147,483,648 to 2,147,483,647 ++//#define Int64 long long // -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807 ++ ++//#define Byte unsigned char // 0 to 255 ++#define word unsigned short // 0 to 65,535 ++#define smallint short // -32,768 to 32,767 ++#define longword unsigned int // 0 to 4,294,967,295 ++ // Int6 : Cardinal; // 0 to 4,294,967,295 ++#define longint int // -2,147,483,648 to 2,147,483,647 ++#define integer int // -2,147,483,648 to 2,147,483,647 ++ ++typedef unsigned long ULONG; ++ ++#define UCHAR unsigned char ++#define UINT unsigned int ++#define BOOL int ++#define TRUE 1 ++#define FALSE 0 ++ ++#define FEND 0xc0 ++#define FESC 0xDB ++#define TFEND 0xDC ++#define TFESC 0xDD ++ ++#define port_num 32 // ?? Max AGW sessions ++#define PKT_ERR 15 // Minimum packet size, bytes ++#define I_MAX 7 // Maximum number of packets ++ ++ ++// Status flags ++ ++#define STAT_NO_LINK 0 ++#define STAT_LINK 1 ++#define STAT_CHK_LINK 2 ++#define STAT_WAIT_ANS 3 ++#define STAT_TRY_LINK 4 ++#define STAT_TRY_UNLINK 5 ++ ++ ++ // Ñmd,Resp,Poll,Final,Digipeater flags ++#define SET_P 1 ++#define SET_F 0 ++#define SET_C 1 ++#define SET_R 0 ++#define SET_NO_RPT 0 ++#define SET_RPT 1 ++ // Frame ID flags ++#define I_FRM 0 ++#define S_FRM 1 ++#define U_FRM 2 ++#define I_I 0 ++#define S_RR 1 ++#define S_RNR 5 ++#define S_REJ 9 ++#define S_SREJ 0x0D ++#define U_SABM 47 ++#define U_DISC 67 ++#define U_DM 15 ++#define U_UA 99 ++#define U_FRMR 135 ++#define U_UI 3 ++ // PID flags ++#define PID_X25 0x01 // 00000001-CCIT X25 PLP ++#define PID_SEGMENT 0x08 // 00001000-Segmentation fragment ++#define PID_TEXNET 0xC3 // 11000011-TEXNET Datagram Protocol ++#define PID_LQ 0xC4 // 11001000-Link Quality Protocol ++#define PID_APPLETALK 0xCA // 11001010-Appletalk ++#define PID_APPLEARP 0xCB // 11001011-Appletalk ARP ++#define PID_IP 0xCC // 11001100-ARPA Internet Protocol ++#define PID_ARP 0xCD // 11001101-ARPA Address Resolution Protocol ++#define PID_NET_ROM 0xCF // 11001111-NET/ROM ++ ++#define FX25_LOAD 1 ++ ++#define MODE_OUR 0 ++#define MODE_OTHER 1 ++#define MODE_RETRY 2 ++ ++#define TIMER_FREE 0 ++#define TIMER_BUSY 1 ++#define TIMER_OFF 2 ++#define TIMER_EVENT_ON 3 ++#define TIMER_EVENT_OFF 4 ++ ++ ++typedef struct string_T ++{ ++ unsigned char * Data; ++ int Length; ++ int AllocatedLength; // A reasonable sized block is allocated at the start to speed up adding chars ++ ++}string; ++ ++typedef struct TStringList_T ++{ ++ int Count; ++ string ** Items; ++ ++} TStringList; ++ ++ ++typedef struct TAX25Info_t ++{ ++ longint stat_s_pkt; ++ longint stat_s_byte; ++ longint stat_r_pkt; ++ longint stat_r_byte; ++ longint stat_r_fc; ++ longint stat_fec_count; ++ time_t stat_begin_ses; ++ time_t stat_end_ses; ++ longint stat_l_r_byte; ++ longint stat_l_s_byte; ++ ++} TAX25Info; ++ ++typedef struct TAX25Port_t ++{ ++ Byte hi_vs; ++ Byte vs; ++ Byte vr; ++ Byte PID; ++ TStringList in_data_buf; ++ TStringList frm_collector; ++ string frm_win[8]; ++ string out_data_buf; ++ word t1; ++ word t2; ++ word t3; ++ Byte i_lo; ++ Byte i_hi; ++ word n1; ++ word n2; ++ word IPOLL_cnt; ++ TStringList frame_buf; //áóôåð êàäðîâ íà ïåðåäà÷ó ++ TStringList I_frame_buf; ++ Byte status; ++ word clk_frack; ++ char corrcall[10]; ++ char mycall[10]; ++ UCHAR digi[56]; ++ UCHAR Path[80]; // Path in ax25 format - added to save building it each time ++ UCHAR ReversePath[80]; ++ int snd_ch; // Simplifies parameter passing ++ int port; ++ int pathLen; ++ void * socket; ++ void * Sess; ++ char kind[16]; ++ TAX25Info info; ++} TAX25Port; ++ ++typedef struct TKISSMode_t ++{ ++ string * data_in; ++ void * Socket; // Used as a key ++ ++ // Not sure what rest are used for. Seems to be one per channel ++ ++ TStringList buffer[4]; // Outgoing Frames ++ ++} TKISSMode; ++ ++// Dephi emulation functions ++ ++string * Strings(TStringList * Q, int Index); ++void Clear(TStringList * Q); ++int Count(TStringList * List); ++ ++string * newString(); ++string * copy(string * Source, int StartChar, int Count); ++TStringList * newTStringList(); ++ ++void freeString(string * Msg); ++void initString(string * S); ++void initTStringList(TStringList* T); ++ ++// Two delete() This is confusing!! ++// Not really - one acts on String, other TStringList ++ ++void Delete(TStringList * Q, int Index); ++void mydelete(string * Source, int StartChar, int Count); ++void move(UCHAR * SourcePointer, UCHAR * DestinationPointer, int CopyCount); ++void fmove(float * SourcePointer, float * DestinationPointer, int CopyCount); ++void setlength(string * Msg, int Count); // Set string length ++string * stringAdd(string * Msg, UCHAR * Chars, int Count); // Extend string ++void Assign(TStringList * to, TStringList * from); // Duplicate from to to ++string * duplicateString(string * in); ++int my_indexof(TStringList * l, string * s); ++boolean compareStrings(string * a, string * b); ++int Add(TStringList * Q, string * Entry); ++void Debugprintf(const char * format, ...); ++void ax25_info_init(TAX25Port * AX25Sess); ++void clr_frm_win(TAX25Port * AX25Sess); ++void decode_frame(Byte * frame, int len, Byte * path, string * data, ++ Byte * pid, Byte * nr, Byte * ns, Byte * f_type, Byte * f_id, ++ Byte * rpt, Byte * pf, Byte * cr); ++#ifdef __cplusplus ++extern "C" void KISSSendtoServer(myTcpSocket* Socket, char * Data, int Length); ++extern "C" void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded); ++extern "C" void WriteDebugLog(char * Mess); ++extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len); ++extern "C" void ClearSessLabel(Ui_ListenSession * Sess); ++extern "C" void rst_timer(TAX25Port * AX25Sess); ++extern "C" void Send_UI(int port, Byte PID, char * CallFrom, char *CallTo, char * Via, Byte * Msg, int MsgLen); ++#else ++void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded); ++void SendtoTerm(void * Sess, char * Msg, int Len); ++void ClearSessLabel(void * Sess); ++void WriteDebugLog(char * Mess); ++void AX25_disc(TAX25Port * AX25Sess, Byte mode); ++void rst_timer(TAX25Port * AX25Sess); ++void Send_UI(int port, Byte PID, char * CallFrom, char *CallTo, char * via, Byte * Msg, int MsgLen); ++#endif ++ ++BOOL ConvToAX25(char * callsign, unsigned char * ax25call); ++int ConvFromAX25(unsigned char * incall, char * outcall); ++void reverse_addr(Byte * path, Byte * revpath, int Len); ++void set_DM(int snd_ch, Byte * path); ++void set_link(TAX25Port * AX25Sess, UCHAR * axpath); ++boolean is_last_digi(Byte *path); ++boolean is_correct_path(Byte * path, Byte pid); ++int number_digi(unsigned char * path); ++void AX25_conn(TAX25Port * AX25Sess, int snd_ch, Byte mode); ++void write_ax25_info(TAX25Port * AX25Sess); ++void rst_values(TAX25Port * AX25Sess); ++ ++#ifdef __cplusplus ++extern "C" ++{ ++#endif ++ ++extern boolean dyn_frack[4]; ++extern Byte recovery[4]; ++extern Byte users[4]; ++ ++extern int resptime[4]; ++extern int slottime[4]; ++extern int persist[4]; ++extern int kisspaclen[4]; ++extern int fracks[4]; ++extern int frack_time[4]; ++extern int idletime[4]; ++extern int redtime[4]; ++extern int IPOLL[4]; ++extern int maxframe[4]; ++extern int TXFrmMode[4]; ++ ++extern char MyDigiCall[4][512]; ++extern char exclude_callsigns[4][512]; ++extern char exclude_APRS_frm[4][512]; ++ ++extern TStringList list_exclude_callsigns[4]; ++extern TStringList list_exclude_APRS_frm[4]; ++extern TStringList list_digi_callsigns[4]; ++ ++extern int max_frame_collector[4]; ++extern boolean KISS_opt[4]; ++ ++extern TAX25Port AX25Port[4][port_num]; ++ ++extern TStringList KISS_acked[]; ++extern TStringList KISS_iacked[]; ++ ++#ifdef __cplusplus ++} + #endif +\ No newline at end of file +--- qttermtcp-0.0.0.79.orig/ax25_l2.c ++++ qttermtcp-0.0.0.79/ax25_l2.c +@@ -1,1752 +1,1752 @@ +-/* +-Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO +- +-This file is part of QtSoundModem +- +-QtSoundModem is free software: you can redistribute it and/or modify +-it under the terms of the GNU General Public License as published by +-the Free Software Foundation, either version 3 of the License, or +-(at your option) any later version. +- +-QtSoundModem is distributed in the hope that it will be useful, +-but WITHOUT ANY WARRANTY; without even the implied warranty of +-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-GNU General Public License for more details. +- +-You should have received a copy of the GNU General Public License +-along with QtSoundModem. If not, see http://www.gnu.org/licenses +- +-*/ +- +-// UZ7HO Soundmodem Port by John Wiseman G8BPQ +- +-// This is a simplified version for QtTermTCP +- +- +- +-#include "ax25.h" +- +-UCHAR TimerEvent = TIMER_EVENT_OFF; +-extern int busy; +-int listenEnable; +-int KISSListen = 1; +-int KISSChecksum = 0; +-int KISSAckMode = 0; +- +-void * KISSSockCopy[4]; +-extern UCHAR axMYCALL[7] = ""; // Mycall in ax.25 +- +-string * make_frame(string * data, Byte * path, Byte pid, Byte nr, Byte ns, Byte f_type, Byte f_id, boolean rpt, boolean pf, boolean cr); +-void rst_t3(TAX25Port * AX25Sess); +-void CheckUIFrame(unsigned char * path, string * data); +-TAX25Port * get_user_port(int snd_ch, Byte * path); +- +-void inc_frack(TAX25Port * AX25Sess) +-{ +- AX25Sess->clk_frack++; +-} +- +- +-void rst_frack(TAX25Port * AX25Sess) +-{ +- AX25Sess->clk_frack = 0; +-} +- +-void inc_t1(TAX25Port * AX25Sess) +-{ +- AX25Sess->t1++; +-} +- +-void rst_t1(TAX25Port * AX25Sess) +-{ +- AX25Sess->t1 = 0; +-} +- +-void inc_t3(TAX25Port * AX25Sess) +-{ +- AX25Sess->t3++; +-} +- +-void rst_t3(TAX25Port * AX25Sess) +-{ +- AX25Sess->t3 = 0; +-} +- +- +-void rst_values(TAX25Port * AX25Sess) +-{ +- AX25Sess->IPOLL_cnt = 0; +- AX25Sess->hi_vs = 0; +- AX25Sess->vs = 0; +- AX25Sess->vr = 0; +- Clear(&AX25Sess->I_frame_buf); +- Clear(&AX25Sess->in_data_buf); +- Clear(&AX25Sess->frm_collector); +- +- ax25_info_init(AX25Sess); +- clr_frm_win(AX25Sess); +-} +- +- +-void rst_timer(TAX25Port * AX25Sess) +-{ +- rst_frack(AX25Sess); +- rst_t1(AX25Sess); +- rst_t3(AX25Sess); +-} +- +-void upd_i_lo(TAX25Port * AX25Sess, int n) //Update the counter of the first frame in the I-frame buffer +-{ +- AX25Sess->i_lo = n; +-} +- +-void upd_i_hi(TAX25Port * AX25Sess, int n) //Update last frame counter in I-frame buffer +-{ +- AX25Sess->i_hi = n; +-} +- +-void upd_vs(TAX25Port * AX25Sess, int n) //Update the counter of the next frame to transmit +-{ +- AX25Sess->vs = ++n & 7; +-} +- +-void upd_vr(TAX25Port * AX25Sess, int n) //Refresh the counter of the next frame at the reception +-{ +- AX25Sess->vr = ++n & 7; +-} +- +- +-void Frame_Optimize(TAX25Port * AX25Sess, TStringList * buf) +-{ +- // I think this removes redundant frames from the TX Queue (eg repeated RR frames) +- +- string * frame; +- Byte path[80]; +- string * data = newString(); +- +- Byte pid, nr, ns, f_type, f_id, rpt, cr, pf; +- boolean curr_req, optimize; +- int i, k; +- char need_frm[8] = ""; +- int index = 0; +- boolean PollRR; +- boolean PollREJ; +- +- PollRR = FALSE; +- PollREJ = FALSE; +- curr_req = FALSE; +- +- // Check Poll RR and REJ frame +- +- i = 0; +- +- while (i < buf->Count && !PollREJ) +- { +- frame = Strings(buf, i); +- // TX frame has kiss control on front +- +- decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); +- +- if (cr == SET_R && pf == SET_P) +- { +- if (f_id == S_REJ) +- PollREJ = TRUE; +- else if (f_id == S_RR && nr == AX25Sess->vr) +- PollRR = TRUE; +- } +- i++; +- } +- +- // Performance of the REJ Cards: Optional Rej Cards +- +- i = 0; +- +- while (i < buf->Count) +- { +- optimize = TRUE; +- frame = Strings(buf, i); +- decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); +- +- if (f_id == S_REJ && cr == SET_R) +- { +- if ((pf == SET_F && PollREJ) || nr != AX25Sess->vr) +- { +- Debugprintf("Optimizer dropping REJ nr %d vr %d pf %d PollREJ %d", nr, AX25Sess->vr, pf, PollREJ); +- Delete(buf, i); +- optimize = FALSE; +- } +- if (nr == AX25Sess->vr) +- curr_req = TRUE; +- } +- if (optimize) +- i++; +- } +- +- // Performance Options +- +- i = 0; +- +- while (i < buf->Count) +- { +- need_frm[0] = 0; +- index = 0; +- k = AX25Sess->i_lo; +- +- while (k != AX25Sess->vs) +- { +- need_frm[index++] = k + 'A'; +- k++; +- k &= 7; +- } +- +- optimize = TRUE; +- +- frame = Strings(buf, i); +- +- decode_frame(frame->Data +1 , frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); +- +- if (f_id == S_RR) +- { +- // RR Cards Methods: Optional RR, F Cards +- if (cr == SET_R) +- { +- if (nr != AX25Sess->vr || ((pf == SET_F) && PollRR) || curr_req) +- { +- Debugprintf("Optimizer dropping RR nr %d vr %d pf %d PollRR %d", nr, AX25Sess->vr, pf, PollRR); +- +- Delete(buf, i); +- optimize = FALSE; +- } +- } +- +- +- // RR Cards Methods : Optional RR, P Cards +- if (cr == SET_C) +- { +- if (AX25Sess->status == STAT_LINK || AX25Sess->status == STAT_WAIT_ANS) +- { +- Debugprintf("Optimizer dropping RR nr %d vr %d pf %d PollRR %d", nr, AX25Sess->vr, pf, PollRR); +- Delete(buf, i); +- optimize = FALSE; +- } +- } +- } +- // I - Cards Methods : Options for I - Cards +- else if (f_id == I_I) +- { +- if (strchr(need_frm, ns + 'A') == 0) +- { +- Delete(buf, i); +- optimize = FALSE; +- } +- else +- { +- if (nr != AX25Sess->vr) +- buf->Items[i] = make_frame(data, path, pid, AX25Sess->vr, ns, f_type, f_id, rpt, pf, cr); +- } +- } +- +- // SABM Applications +- +- if (f_id == U_SABM) +- { +- if (AX25Sess->status != STAT_TRY_LINK) +- { +- Delete(buf, i); +- optimize = FALSE; +- } +- } +- +- if (optimize) +- i++; +- } +-} +- +-int KISS_encode(UCHAR * KISSBuffer, int port, string * frame) +-{ +- // Encode frame +- +- UCHAR * ptr1 = frame->Data; +- UCHAR TXCCC = 0; +- int Len = frame->Length; +- UCHAR * ptr2 = &KISSBuffer[2]; +- UCHAR c; +- +- // TX Frame has control byte on front +- +- ptr1++; +- Len--; +- +- KISSBuffer[0] = FEND; +- KISSBuffer[1] = port << 4; +- +- TXCCC ^= KISSBuffer[1]; +- +- while (Len--) +- { +- c = *(ptr1++); +- TXCCC ^= c; +- +- switch (c) +- { +- case FEND: +- (*ptr2++) = FESC; +- (*ptr2++) = TFEND; +- break; +- +- case FESC: +- +- (*ptr2++) = FESC; +- (*ptr2++) = TFESC; +- break; +- +- // Drop through +- +- default: +- +- (*ptr2++) = c; +- } +- } +- +- // Add checksum if needed +- +- if (KISSChecksum) +- { +- c = TXCCC; +- +- // We don't support TNCX with Checksum +- +- switch (c) +- { +- case FEND: +- (*ptr2++) = FESC; +- (*ptr2++) = TFEND; +- break; +- +- case FESC: +- (*ptr2++) = FESC; +- (*ptr2++) = TFESC; +- break; +- +- default: +- (*ptr2++) = c; +- } +- } +- +- (*ptr2++) = FEND; +- +- return (int)(ptr2 - KISSBuffer); +-} +- +-void KISSSendtoServer(void * Socket, char * Data, int Length); +- +-void add_pkt_buf(TAX25Port * AX25Sess, string * data) +-{ +-// boolean found = 0; +-// int i = 0; +- UCHAR KISSBuffer[512]; +- int Length; +- +- // ? Don't we just send to TNC? +- +- Length = KISS_encode(KISSBuffer, AX25Sess->snd_ch, data); +- +- KISSSendtoServer(AX25Sess->socket, KISSBuffer, Length); +- +- monitor_frame(0, data, "", 1, 0); // Monitor +- freeString(data); +- +-} +- +-void add_I_FRM(TAX25Port * AX25Sess) +-{ +- string * data; +- int i; +- +- upd_i_lo(AX25Sess, AX25Sess->vs); +- +- while (AX25Sess->in_data_buf.Count > 0 && AX25Sess->I_frame_buf.Count != maxframe[AX25Sess->snd_ch]) +- { +- data = duplicateString(Strings(&AX25Sess->in_data_buf, 0)); +- Delete(&AX25Sess->in_data_buf, 0); +- Add(&AX25Sess->I_frame_buf, data); +- } +- if (AX25Sess->I_frame_buf.Count > 0) +- { +- for (i = 0; i < AX25Sess->I_frame_buf.Count; i++) +- { +- upd_i_hi(AX25Sess, AX25Sess->vs); +- upd_vs(AX25Sess, AX25Sess->vs); +- AX25Sess->hi_vs = AX25Sess->vs; // Last transmitted frame +- } +- } +-} +- +- +-void delete_I_FRM(TAX25Port * AX25Sess, int nr) +-{ +- int i; +- +- i = AX25Sess->i_lo; +- +- while (i != nr) +- { +- if (AX25Sess->I_frame_buf.Count > 0) +- { +- AX25Sess->info.stat_s_pkt++; +- AX25Sess->info.stat_s_byte += Strings(&AX25Sess->I_frame_buf, 0)->Length; +- Delete(&AX25Sess->I_frame_buf, 0); +- } +- +- i++; +- i &= 7; +- } +- upd_i_lo(AX25Sess, nr); +-} +- +-void delete_I_FRM_port(TAX25Port * AX25Sess) +-{ +- string * frame; +- char path[80] = ""; +- string data= { 0 }; +- +- Byte pid, nr, ns, f_type, f_id, rpt, cr, pf; +- boolean optimize; +- int i = 0; +- +- while (i < AX25Sess->frame_buf.Count) +- { +- optimize = TRUE; +- frame = Strings(&AX25Sess->frame_buf, i); +- +- decode_frame(frame->Data, frame->Length, path, &data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); +- +- if (f_id == I_I) +- { +- Delete(&AX25Sess->frame_buf, i); +- optimize = FALSE; +- } +- if (optimize) +- i++; +- } +-} +- +-void send_data_buf(TAX25Port * AX25Sess, int nr) +-{ +- int i; +- boolean new_frames; +- boolean PF_bit; +- +- if (AX25Sess->status != STAT_LINK) +- return; +- +- AX25Sess->IPOLL_cnt = 0; +- AX25Sess->vs = nr; +- delete_I_FRM(AX25Sess, nr); // ?? free acked frames +-// delete_I_FRM_port(AX25Sess); +- +- if (TXFrmMode[AX25Sess->snd_ch] == 1) +- { +- new_frames = FALSE; +- +- if (AX25Sess->I_frame_buf.Count < 2) +- { +- add_I_FRM(AX25Sess); +- AX25Sess->status = STAT_LINK; +- new_frames = TRUE; +- } +- +- if (AX25Sess->I_frame_buf.Count > 0) +- { +- if (new_frames) +- { +- for (i = 0; i < AX25Sess->I_frame_buf.Count; i++) +- { +- if (i == AX25Sess->I_frame_buf.Count - 1) +- PF_bit = SET_P; +- else +- PF_bit = SET_F; +- +- add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C)); +- } +- } +- if (!new_frames) +- { +- add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); //SET_P +- upd_vs(AX25Sess, AX25Sess->vs); +- } +- AX25Sess->status = STAT_WAIT_ANS; +- rst_timer(AX25Sess); +- } +- } +- +- if (TXFrmMode[AX25Sess->snd_ch] == 0) +- { +- add_I_FRM(AX25Sess); +- AX25Sess->status = STAT_LINK; +- +- if (AX25Sess->I_frame_buf.Count > 0) +- { +- for (i = 0; i < AX25Sess->I_frame_buf.Count; i++) +- { +- if (i == AX25Sess->I_frame_buf.Count - 1) +- PF_bit = SET_P; +- else +- PF_bit = SET_F; +- add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C)); +- } +- AX25Sess->status = STAT_WAIT_ANS; +- rst_timer(AX25Sess); +- } +- } +-} +- +- +-void send_data_buf_srej(TAX25Port * AX25Sess, int nr) +-{ +- // Similar to send_data_buf but only sends the requested I frame with P set +- +- int i = 0; +- boolean new_frames; +- boolean PF_bit; +- +- if (AX25Sess->status != STAT_LINK) +- return; +- +- AX25Sess->IPOLL_cnt = 0; +- AX25Sess->vs = nr; +- delete_I_FRM(AX25Sess, nr); // ?? free acked frames +- +- new_frames = FALSE; +- +- add_I_FRM(AX25Sess); +- AX25Sess->status = STAT_LINK; +- new_frames = TRUE; +- +- if (AX25Sess->I_frame_buf.Count > 0) +- { +- if (new_frames) +- { +- PF_bit = SET_P; +- +- add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C)); +- } +- else +- { +- +- add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); //SET_P +- upd_vs(AX25Sess, AX25Sess->vs); +- } +- } +- AX25Sess->status = STAT_WAIT_ANS; +- rst_timer(AX25Sess); +-} +- +-void write_frame_collector(TAX25Port * AX25Sess, int ns, string * data) +-{ +- Byte i; +- char frm_ns; +- string * frm; +- boolean found ; +- boolean need_frm; +- +- if (max_frame_collector[AX25Sess->snd_ch] < 1) +- return; +- +- need_frm = FALSE; +- i = 1; +- do +- { +- if (ns == ((AX25Sess->vr + i) & 7)) +- need_frm = TRUE; +- +- i++; +- +- } while (i <= max_frame_collector[AX25Sess->snd_ch] && !need_frm); +- +- if (need_frm) +- { +- frm_ns = ns; +- found = FALSE; +- i = 0; +- +- if (AX25Sess->frm_collector.Count > 0) +- { +- do +- { +- frm = Strings(&AX25Sess->frm_collector, i); +- +- if (frm_ns == frm->Data[0]) +- found = TRUE; +- i++; +- } +- while (!found && i != AX25Sess->frm_collector.Count); +- +- } +- +- if (!found) +- { +- string * frm = newString(); +- +- stringAdd(frm, (char *)&frm_ns, 1); +- stringAdd(frm, data->Data, data->Length); +- Add(&AX25Sess->frm_collector, frm); +- } +- } +-} +- +-string * read_frame_collector(TAX25Port * AX25Sess, boolean fecflag) +-{ +- // Look for required frame no in saved frames +- +- string * frm; +- string * data = newString(); +- +- int i = 0; +- Byte frm_ns; +- +- while (i < AX25Sess->frm_collector.Count) +- { +- frm = duplicateString(Strings(&AX25Sess->frm_collector, i)); +- +- frm_ns = frm->Data[0]; +- +- if (frm_ns == AX25Sess->vr) +- { +- Delete(&AX25Sess->frm_collector, i); +- +- upd_vr(AX25Sess, AX25Sess->vr); +- +- mydelete(frm, 0, 1); // Remove vr from front +- +- stringAdd(data, frm->Data, frm->Length); +- +- AX25Sess->info.stat_r_pkt++; +- AX25Sess->info.stat_r_fc++; +- +- if (fecflag) +- AX25Sess->info.stat_fec_count++; +- +- AX25Sess->info.stat_r_byte += frm->Length; +- AX25Sess->frm_win[frm_ns].Length = frm->Length; //Save the frame to the window buffer +- AX25Sess->frm_win[frm_ns].Data = frm->Data; //Save the frame to the window buffer +- } +- +- i++; +- } +- return data; +-} +- +- +-/////////////////////////// SET-FRAMES ////////////////////////////////// +- +-void set_chk_link(TAX25Port * AX25Sess, Byte * path) +-{ +- boolean b_IPOLL; +- int len; +- +- AX25Sess->status = STAT_CHK_LINK; +- +- // if AX25Sess->digi<>'' then path:=path+','+reverse_digi(AX25Sess->digi); +- +- b_IPOLL = FALSE; +- +- if (AX25Sess->I_frame_buf.Count > 0 && AX25Sess->IPOLL_cnt < 2) +- { +- len = Strings(&AX25Sess->I_frame_buf, 0)->Length; +- +- if (len > 0 && len <= IPOLL[AX25Sess->snd_ch]) +- { +- +- b_IPOLL = TRUE; +- AX25Sess->IPOLL_cnt++; +- } +- } +- if (b_IPOLL) +- add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); +- else +- add_pkt_buf(AX25Sess, make_frame(NULL, path, 0xF0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_C)); +- +- inc_frack(AX25Sess); +-} +- +- +- +-// This seems to start a connection +- +-void set_link(TAX25Port * AX25Sess, UCHAR * axpath) +-{ +- if (AX25Sess->status != STAT_LINK) +- { +- string nullstring; +- nullstring.Length = 0; +- +- rst_values(AX25Sess); +- +- AX25Sess->status = STAT_TRY_LINK; +- +- // if (AX25Sess->digi[0] != 0) +- // path: = path + ',' + reverse_digi(AX25Sess->digi); +- +- add_pkt_buf(AX25Sess, make_frame(&nullstring, axpath, 0, 0, 0, U_FRM, U_SABM, SET_NO_RPT, SET_P, SET_C)); +- +- inc_frack(AX25Sess); +- } +-} +- +-#define MODE_OUR 0 +- +-void set_try_unlink(TAX25Port * AX25Sess, Byte * path) +-{ +- string nullstring; +- nullstring.Length = 0; +- +- AX25Sess->status = STAT_TRY_UNLINK; +- add_pkt_buf(AX25Sess, make_frame(&nullstring, path, 0, 0, 0, U_FRM, U_DISC, SET_NO_RPT, SET_P, SET_C)); +- inc_frack(AX25Sess); +-} +- +- +-void set_unlink(TAX25Port * AX25Sess, Byte * path) +-{ +- if (AX25Sess->status == STAT_TRY_UNLINK +- || AX25Sess->status == STAT_TRY_LINK +- || AX25Sess->status == STAT_NO_LINK) +- { +- string nullstring; +- nullstring.Length = 0; +- +- // if (AX25Sess->digi[0] != 0) +- // path: = path + ',' + reverse_digi(AX25Sess->digi); +- +- AX25_disc(AX25Sess, MODE_OUR); +- +- if (AX25Sess->status != STAT_TRY_UNLINK) +- add_pkt_buf(AX25Sess, make_frame(&nullstring, path, 0, 0, 0, U_FRM, U_DISC, SET_NO_RPT, SET_P, SET_C)); +- +- AX25Sess->info.stat_end_ses = time(NULL); +- +- write_ax25_info(AX25Sess); +- rst_values(AX25Sess); +- +- memset(AX25Sess->corrcall, 0, 10); +- memset(AX25Sess->mycall, 0, 10); +- AX25Sess->digi[0] = 0; +- AX25Sess->status = STAT_NO_LINK; +- +- } +- else +- set_try_unlink(AX25Sess, AX25Sess->Path); +-} +- +-void set_FRMR(int snd_ch, Byte * path, unsigned char frameType) +-{ +- //We may not have a session when sending FRMR so reverse path and send +- +- Byte revpath[80]; +- string * Data = newString(); +- string * Frame; +- +- UCHAR KISSBuffer[512]; +- int Length; +- +- Data->Data[0] = frameType; +- Data->Data[1] = 0; +- Data->Data[2] = 1; // Invalid CTL Byte +- Data->Length = 3; +- +- reverse_addr(path, revpath, strlen(path)); +- +- Frame = make_frame(Data, revpath, 0, 0, 0, U_FRM, U_FRMR, FALSE, SET_P, SET_R); +- +- // ? Don't we just send to TNC? +- +- Length = KISS_encode(KISSBuffer, 0, Frame); +- +- KISSSendtoServer(KISSSockCopy[snd_ch], KISSBuffer, Length); +- +- monitor_frame(0, Frame, "", 1, 0); // Monitor +- freeString(Frame); +- freeString(Data); +-} +- +-void set_DM(int snd_ch, Byte * path) +-{ +- //We may not have a session when sending DM so reverse path and send +- +- Byte revpath[80]; +- +- reverse_addr(path, revpath, strlen(path)); +- +- add_pkt_buf(&AX25Port[snd_ch][0], make_frame(NULL, revpath, 0, 0, 0, U_FRM,U_DM,FALSE,SET_P,SET_R)); +-} +- +-/////////////////////////// S-FRAMES //////////////////////////////////// +- +- +-void on_RR(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) +-{ +- char need_frame[16] = ""; +- int index = 0; +- +- int i; +- +- if (AX25Sess->status == STAT_TRY_LINK) +- return; +- +- if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) +- { +- if (cr == SET_C) +- set_DM(AX25Sess->snd_ch, path); +- +- return; +- } +- +- if (cr == SET_R) +- { +- // Determine which frames could get into the user’s frame buffer. +- i = AX25Sess->vs; +- +- need_frame[index++] = i + '0'; +- +-// Debugprintf("RR Rxed vs = %d hi_vs = %d", AX25Sess->vs, AX25Sess->hi_vs); +- while (i != AX25Sess->hi_vs) +- { +- i++; +- i &= 7; +- +- need_frame[index++] = i + '0'; +- if (index > 10) +- { +- Debugprintf("Index corrupt %d need_frame = %s", index, need_frame); +- break; +- } +- } +- +- //Clear the received frames from the transmission buffer. +- +- if (AX25Sess->status == STAT_WAIT_ANS) +- delete_I_FRM(AX25Sess, nr); +- +- // We restore the link if the number is valid +- +- if (AX25Sess->status == STAT_CHK_LINK || strchr(need_frame, nr + '0') != 0) +- { +- rst_timer(AX25Sess); +- AX25Sess->status = STAT_LINK; +- send_data_buf(AX25Sess, nr); +- } +- } +- +- if (cr == SET_C) +- add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, pf, SET_R)); +- +- rst_t3(AX25Sess); +-} +- +- +-void on_RNR(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) +-{ +- UNUSED(pf); +- +- if (AX25Sess->status == STAT_TRY_LINK) +- return; +- +- if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) +- { +- if (cr == SET_C) +- set_DM(AX25Sess->snd_ch, path); +- +- return; +- } +- +- if (cr == SET_R) +- { +- rst_timer(AX25Sess); +- +- if (AX25Sess->status == STAT_WAIT_ANS) +- delete_I_FRM(AX25Sess, nr); +- +- AX25Sess->status = STAT_CHK_LINK; +- } +- +- if (cr == SET_C) +- add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R)); +- +- rst_t3(AX25Sess); +-} +- +- +-void on_REJ(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) +-{ +- UNUSED(pf); +- if (AX25Sess->status == STAT_TRY_LINK) +- return; +- +- if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) +- { +- if (cr == SET_C) +- set_DM(AX25Sess->snd_ch, path); +- +- return; +- } +- +- if (cr == SET_R) +- { +- rst_timer(AX25Sess); +- AX25Sess->status = STAT_LINK; +- +- send_data_buf(AX25Sess, nr); +- } +- +- if (cr == SET_C) +- add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R)); +-} +- +- +-void on_SREJ(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) +-{ +- UNUSED(pf); +- +- if (AX25Sess->status == STAT_TRY_LINK) +- return; +- +- if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) +- { +- if (cr == SET_C) +- set_DM(AX25Sess->snd_ch, path); +- +- return; +- } +- +- if (cr == SET_R) +- { +- rst_timer(AX25Sess); +- AX25Sess->status = STAT_LINK; +- +- send_data_buf_srej(AX25Sess, nr); +- } +- +- if (cr == SET_C) +- add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R)); +-} +-/////////////////////////// I-FRAMES //////////////////////////////////// +- +-void on_I(void * socket, TAX25Port * AX25Sess, int PID, Byte * path, string * data, int nr, int ns, int pf, int cr, boolean fecflag) +-{ +- UNUSED(cr); +- UNUSED(socket); +- string * collector_data = 0; +- int i; +- Byte need_frame[16] = ""; +- int index = 0; +- +- +- if (AX25Sess->status == STAT_TRY_LINK) +- return; +- +- if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) +- { +- set_DM(0, path); +- return; +- } +- +- if (busy) +- { +- add_pkt_buf(AX25Sess, make_frame(NULL, path, PID, AX25Sess->vr, 0, S_FRM, S_RNR, FALSE, pf, SET_R)); +- return; +- } +- +- // Determine which frames could get into the user’s frame buffer. +- +- i = AX25Sess->vs; +- +- need_frame[index++] = i + '0'; +- +- // Debugprintf("I Rxed vs = %d hi_vs = %d", AX25Sess->vs, AX25Sess->hi_vs); +- +- while (i != AX25Sess->hi_vs) +- { +- i++; +- i &= 7; +- +- need_frame[index++] = i + '0'; +- if (index > 10) +- { +- Debugprintf("Index corrupt %d need_frame = %s", index, need_frame); +- break; +- } +- } +- +- //Clear received frames from the transmission buffer. +- +- if (AX25Sess->status == STAT_WAIT_ANS) +- delete_I_FRM(AX25Sess, nr); +- +- //We restore the link if the number is valid +- +- if (AX25Sess->status == STAT_CHK_LINK || strchr(need_frame, nr + '0') != 0) +- { +- //We restore the link if the number is valid +- +- rst_timer(AX25Sess); +- AX25Sess->status = STAT_LINK; +- send_data_buf(AX25Sess, nr); +- } +- +- if (ns == AX25Sess->vr) +- { +- //If the expected frame, send RR, F +- +- AX25Sess->info.stat_r_pkt++; +- AX25Sess->info.stat_r_byte += data->Length; +- +- if (fecflag) +- AX25Sess->info.stat_fec_count++; +- +- upd_vr(AX25Sess, AX25Sess->vr); +- +- AX25Sess->frm_win[ns].Length = data->Length; //Save the frame to the window buffer +- AX25Sess->frm_win[ns].Data = data->Data; //Save the frame to the window buffer +- +- collector_data = read_frame_collector(AX25Sess, fecflag); +- +- stringAdd(data, collector_data->Data, collector_data->Length); +- +- SendtoTerm(AX25Sess->Sess, (char *)data->Data, data->Length); +- +- // Andy's code queues RR immediately and uses frame optimiser to remove +- // redundant RR (not P) frames. I can't do that so need a proper resptime +- // system. Try setting an RRNeeded timer (t2). +- +- if (pf) +- { +- // Poll set, so respond immediately +- +- add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, pf, SET_R)); +- AX25Sess->t2 = 0; +- } +- else +- AX25Sess->t2 = resptime[0] / 100; // resptime is in mS +- +- freeString(collector_data); +- } +- else +- { +- // If the frame is not expected, send REJ, F +- +- if ((AX25Sess->frm_win[ns].Length != data->Length) && +- memcmp(&AX25Sess->frm_win[ns].Data, data->Data, data->Length) != 0) +- +- write_frame_collector(AX25Sess, ns, data); +- +- add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_REJ, FALSE, pf, SET_R)); +- } +- rst_t3(AX25Sess); +- +-} +-/////////////////////////// U-FRAMES //////////////////////////////////// +- +-void * ax25IncomingConnect(TAX25Port * AX25Sess); +- +-void on_SABM(void * socket, TAX25Port * AX25Sess) +-{ +- if (AX25Sess->status == STAT_TRY_UNLINK) +- { +- AX25Sess->info.stat_end_ses = time(NULL); +- +- write_ax25_info(AX25Sess); +- rst_values(AX25Sess); +- +- memset(AX25Sess->corrcall, 0, 10); +- memset(AX25Sess->mycall, 0, 10); +- AX25Sess->digi[0] = 0; +- +- AX25_disc(AX25Sess, MODE_OTHER); +- Clear(&AX25Sess->frame_buf); +- +- AX25Sess->status = STAT_NO_LINK; +- } +- +- if (AX25Sess->status == STAT_TRY_LINK) +- { +- AX25_disc(AX25Sess, MODE_OTHER); +- +- rst_timer(AX25Sess); +- rst_values(AX25Sess); +- Clear(&AX25Sess->frame_buf); +- AX25Sess->status = STAT_NO_LINK; +- } +- +- if (AX25Sess->status != STAT_NO_LINK) +- { +- if ((strcmp(AX25Sess->kind, "Outgoing") == 0) || +- AX25Sess->status == STAT_TRY_UNLINK || AX25Sess->info.stat_s_byte > 0 || +- AX25Sess->info.stat_r_byte > 0 || AX25Sess->frm_collector.Count > 0) +- { +- AX25Sess->info.stat_end_ses = time(NULL); +- AX25_disc(AX25Sess, MODE_OTHER); +- write_ax25_info(AX25Sess); +- rst_timer(AX25Sess); +- rst_values(AX25Sess); +- Clear(&AX25Sess->frame_buf); +- AX25Sess->status = STAT_NO_LINK; +- } +- } +- +- if (AX25Sess->status == STAT_NO_LINK) +- { +- AX25Sess->vr = 0; +- AX25Sess->vs = 0; +- AX25Sess->hi_vs = 0; +- +- Clear(&AX25Sess->frm_collector); +- clr_frm_win(AX25Sess); +- AX25Sess->status = STAT_LINK; +- AX25Sess->info.stat_begin_ses = time(NULL); +- strcpy(AX25Sess->kind, "Incoming"); +- AX25Sess->socket = socket; +- +- // Must send UA before any ctext +- +- add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R)); +- +- if (ax25IncomingConnect(AX25Sess)) // Attach to Terminal +- AX25_conn(AX25Sess, AX25Sess->snd_ch, MODE_OTHER); +- +- return; +- } +- +- add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R)); +-} +- +-void on_DISC(TAX25Port * AX25Sess) +-{ +- if (AX25Sess->status != STAT_NO_LINK) +- { +- AX25Sess->info.stat_end_ses = time(NULL); +- AX25_disc(AX25Sess, MODE_OTHER); +- write_ax25_info(AX25Sess); +- } +- +- if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_LINK) +- set_DM(AX25Sess->snd_ch, AX25Sess->Path); +- else +- add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R)); +- +- rst_values(AX25Sess); +- memset(AX25Sess->corrcall, 0, 10); +- memset(AX25Sess->mycall, 0, 10); +- AX25Sess->digi[0] = 0; +- AX25Sess->status = STAT_NO_LINK; +-} +- +-void on_DM(TAX25Port * AX25Sess) +-{ +- if (AX25Sess->status == STAT_TRY_LINK) +- { +- +- char Msg[128]; +- int Len; +- +- Len = sprintf(Msg, "*** Busy From %s\r", AX25Sess->corrcall); +- SendtoTerm(AX25Sess->Sess, Msg, Len); +- } +- else if (AX25Sess->status != STAT_NO_LINK) +- { +- AX25Sess->info.stat_end_ses = time(NULL); +- AX25_disc(AX25Sess, MODE_OTHER); +- write_ax25_info(AX25Sess); +- } +- +- rst_timer(AX25Sess); +- rst_values(AX25Sess); +- memset(AX25Sess->corrcall, 0, 10); +- memset(AX25Sess->mycall, 0, 10); +- AX25Sess->digi[0] = 0; +- AX25Sess->status = STAT_NO_LINK; +-} +- +- +-void on_UA(TAX25Port * AX25Sess) +-{ +- switch (AX25Sess->status) +- { +- case STAT_TRY_LINK: +- +- AX25Sess->info.stat_begin_ses = time(NULL); +- AX25Sess->status = STAT_LINK; +- AX25_conn(AX25Sess, AX25Sess->snd_ch, MODE_OUR); +- break; +- +- case STAT_TRY_UNLINK: +- +- AX25Sess->info.stat_end_ses = time(NULL); +- AX25_disc(AX25Sess, MODE_OUR); +- write_ax25_info(AX25Sess); +- +- rst_values(AX25Sess); +- AX25Sess->status = STAT_NO_LINK; +- memset(AX25Sess->corrcall, 0, 10); +- memset(AX25Sess->mycall, 0, 10); +- AX25Sess->digi[0] = 0; +- break; +- } +- +- rst_timer(AX25Sess); +-} +- +-void on_UI(TAX25Port * AX25Sess, int pf, int cr) +-{ +- UNUSED(AX25Sess); +- UNUSED(pf); +- UNUSED(cr); +- +-} +- +-void on_FRMR(void * socket, TAX25Port * AX25Sess, Byte * path) +-{ +- if (AX25Sess->status != STAT_NO_LINK) +- { +- AX25Sess->info.stat_end_ses = time(NULL); +- +- AX25_disc(socket, MODE_OTHER); +- write_ax25_info(AX25Sess); +- } +- +- set_DM(AX25Sess->snd_ch, path); +- +- rst_values(AX25Sess); +- memset(AX25Sess->corrcall, 0, 10); +- memset(AX25Sess->mycall, 0, 10); +- AX25Sess->digi[0] = 0; +- AX25Sess->status = STAT_NO_LINK; +-} +- +- +- +-void UpdateActiveConnects(int snd_ch) +-{ +- int port; +- +- users[snd_ch] = 0; +- +- for (port = 0; port < port_num; port++) +- if (AX25Port[snd_ch][port].status != STAT_NO_LINK) +- users[snd_ch]++; +-} +- +- +-void timer_event() +-{ +- int snd_ch, port; +- single frack; +- Byte active; +- TAX25Port * AX25Sess; +- +- TimerEvent = TIMER_EVENT_OFF; +- +- for (snd_ch = 0; snd_ch < 4; snd_ch++) +- { +- //reset the slottime timer +- +- frack = frack_time[snd_ch]; +- +- for (port = 0; port < port_num; port++) +- { +- AX25Sess = &AX25Port[snd_ch][port]; +- +- if (AX25Sess->status == STAT_NO_LINK) +- continue; +- +- if (AX25Sess->t2) +- { +- AX25Sess->t2--; +- if (AX25Sess->t2 == 0) +- { +- // Expired - send RR (without P) +- +- add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, 0, SET_R)); +- } +- } +- +- if (AX25Sess->frame_buf.Count == 0) //when the transfer buffer is empty +- inc_t1(AX25Sess); // we consider time of the timer of repeated requests +- +- // Wouldn't it make more sense to keep path in ax.25 struct? +- +- if (AX25Sess->t1 >= frack * 10 + (number_digi(AX25Sess->digi) * frack * 20)) +- { +- if (AX25Sess->clk_frack >= fracks[snd_ch]) +- { +- // This disconnects after retries expires +- +- rst_frack(AX25Sess); +- set_unlink(AX25Sess, AX25Sess->Path); +- } +- +- switch (AX25Sess->status) +- { +- case STAT_TRY_LINK: +- +- set_link(AX25Sess, AX25Sess->Path); +- break; +- +- case STAT_TRY_UNLINK: +- +- set_try_unlink(AX25Sess, AX25Sess->Path); +- break; +- +- case STAT_WAIT_ANS: +- +- set_chk_link(AX25Sess, AX25Sess->Path); +- break; +- +- case STAT_CHK_LINK: +- +- set_chk_link(AX25Sess, AX25Sess->Path); +- break; +- } +- +- rst_t1(AX25Sess); +- } +- +- +- if (AX25Sess->t3 >= idletime[snd_ch] * 10) +- { +- set_chk_link(AX25Sess, AX25Sess->Path); +- rst_t1(AX25Sess); +- rst_t3(AX25Sess); +- } +- +- if (AX25Sess->status == STAT_LINK) +- inc_t3(AX25Sess); +- +- } +- } +- // KISS ACKMODE +- //if (snd_status[snd_ch]<>SND_TX) and KISSServ then KISS_send_ack1(snd_ch); +-} +- +-TAX25Port * get_free_port(int snd_ch) +-{ +- int i = 0; +- +- while (i < port_num) +- { +- if (AX25Port[snd_ch][i].status == STAT_NO_LINK) +- return &AX25Port[snd_ch][i]; +- +- i++; +- } +- return FALSE; +-} +- +- +-TAX25Port * get_user_port(int snd_ch, Byte * path) +- { +- TAX25Port * AX25Sess = NULL; +- +- int i = 0; +- +- +- while (i < port_num) +- { +- AX25Sess = &AX25Port[snd_ch][i]; +- +- if (AX25Sess->status != STAT_NO_LINK && memcmp(AX25Sess->ReversePath, path, AX25Sess->pathLen) == 0) +- return AX25Sess; +- +- i++; +- } +- +- return FALSE; +-} +- +-boolean get_user_dupe(int snd_ch, Byte * path) +-{ +- int i = 0; +- TAX25Port * AX25Sess; +- +- while (i < port_num) +- { +- AX25Sess = &AX25Port[snd_ch][i]; +- +- if (AX25Sess->status != STAT_NO_LINK && memcmp(AX25Sess->ReversePath, path, AX25Sess->pathLen) == 0) +- return TRUE; +- +- i++; +- } +- +- return FALSE; +-} +- +-TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo) +-{ +- int i = 0; +- TAX25Port * AX25Sess = NULL; +- +- while (i < port_num) +- { +- AX25Sess = &AX25Port[snd_ch][i]; +- +- if (AX25Sess->status != STAT_NO_LINK && +- strcmp(CallFrom, AX25Sess->mycall) == 0 && strcmp(CallTo, AX25Sess->corrcall) == 0) +- +- return AX25Sess; +- +- i++; +- } +- +- return NULL; +-} +- +-void * get_sock_by_port(TAX25Port * AX25Sess) +-{ +- void * socket = (void *)-1; +- +- if (AX25Sess) +- socket = AX25Sess->socket; +- +- return socket; +-} +- +-void Digipeater(int snd_ch, string * frame) +-{ +- char call[16]; +- Byte * addr = &frame->Data[7]; // Origin +- string * frameCopy; +- +- int n = 8; // Max digis +- +- if (list_digi_callsigns[snd_ch].Count == 0) +- return; +- +- // Look for first unused digi +- +- while ((addr[6] & 1) == 0 && n--) // until end of address +- { +- addr += 7; +- +- if ((addr[6] & 128) == 0) +- { +- // unused digi - is it addressed to us? +- +- memcpy(call, addr, 7); +- call[6] &= 0x7E; // Mask end of call +- +- // See if in digi list +- +- int i; +- +- for (i = 0; i < list_digi_callsigns->Count; i++) +- { +- if (memcmp(list_digi_callsigns->Items[i]->Data, call, 7) == 0) +- { +- UCHAR KISSBuffer[512]; +- int Length; +- +- // for us +- +- addr[6] |= 128; // set digi'ed +- +- // TX Frames need a KISS control on front +- +- frameCopy = newString(); +- +- frameCopy->Data[0] = 0; +- frameCopy->Length = 1; +- +- stringAdd(frameCopy, frame->Data, frame->Length); // Exclude CRC +- +- addr[6] &= 0x7f; // clear digi'ed from original; +- +- // Send to TNC +- +- // ? Don't we just send to TNC? +- +- Length = KISS_encode(KISSBuffer, 0, frameCopy); +- +- KISSSendtoServer(KISSSockCopy[snd_ch], KISSBuffer, Length); +- +- monitor_frame(0, frameCopy, "", 1, 0); // Monitor +- freeString(frameCopy); +- +- return; +- } +- } +- } +- } +-} +- +-void analiz_frame(int snd_ch, string * frame, void * socket, boolean fecflag) +-{ +- Byte path[80]; +- string * data = 0; +- Byte pid, nr, ns, f_type, f_id, rpt, cr, pf; +- Byte * ptr; +- +- int excluded = 0; +- int len; +- +- TAX25Port * AX25Sess; +- +- // mod_icon_status = mod_rx; +- +- len = frame->Length; +- +- if (len < PKT_ERR) +- return; +- +- data = newString(); +- +- decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); +- +- // if is_excluded_call(snd_ch,path) then excluded:=TRUE; +- // if is_excluded_frm(snd_ch,f_id,data) then excluded:=TRUE; +- +- // CRC Collision Check +- +- if (!is_correct_path(path, pid)) +- { +- // Duff path - if Non-AX25 filter active log and discard +- } +- +- monitor_frame(snd_ch, frame, "", 0, excluded); // Monitor +- +- // Digipeat frame +- +- Digipeater(snd_ch, frame); +- +- if (!is_last_digi(path)) +- { +- freeString(data); +- return; // Don't process if still unused digis +- } +- +- // Clear repeated bits from digi path +- +- ptr = &path[13]; +- +- while ((*ptr & 1) == 0) // end of address +- { +- ptr += 7; +- *(ptr) &= 0x7f; // Clear digi'd bit +- } +- +- // search for port of correspondent +- +- AX25Sess = get_user_port(snd_ch, path); +- +- // if not an active session, AX25Sess will be NULL +- +-// if (AX25Sess == NULL) +-// socket = in_list_incoming_mycall(path); +-// else +-// socket = get_sock_by_port(AX25Sess); +- +- // link analysis +- +- if (AX25Sess == NULL) +- { +- if (f_id == U_UI) +- { +- CheckUIFrame(path, data); +- freeString(data); +- return; // Don't precess UI at the moment +- } +- +- // No Session. If socket is set (so call is in incoming calls list) and SABM set up session +- +- // Check addresses to us +- +- if (memcmp(path, axMYCALL, 7) != 0) +- return; // ignore +- +- if (KISSListen == 0) +- { +- set_DM(snd_ch, path); +- freeString(data); +- return; +- } +- +- if (f_id != U_SABM) // Not SABM +- { +- // send DM if P set +- +- if (cr == SET_C) +- { +- switch (f_id) +- { +- case U_DISC: +- case S_RR: +- case S_REJ: +- case S_RNR: +- case I_I: +- +- set_DM(snd_ch, path); +- break; +- +- case U_UI: +- break; +- +- default: +- set_FRMR(snd_ch, path, f_id); +- } +- +- +- } +- freeString(data); +- return; +- } +- +- // Must be SABM. See if it would duplicate an existing session (but could it - wouldn't that be found earlier ?? +- +- // Make sure it is for us +- +- +- +- if (get_user_dupe(snd_ch, path)) // Not SABM or a duplicate call pair +- { +- freeString(data); +- return; +- } +- +- AX25Sess = get_free_port(snd_ch); +- +- if (AX25Sess == NULL) +- { +- // if there are no free ports for connection - reject +- +- Byte Rev[80]; +- +- reverse_addr(path, Rev, strlen(path)); +- set_DM(snd_ch, Rev); +- freeString(data); +- return; +- } +- +- // initialise new session +- +- AX25Sess->snd_ch = snd_ch; +- +- AX25Sess->corrcall[ConvFromAX25(&path[7], AX25Sess->corrcall)] = 0; +- AX25Sess->mycall[ConvFromAX25(path, AX25Sess->mycall)] = 0; +- AX25Sess->digi[0] = 0; +- +- // rst_timer(snd_ch, free_port); +- +- strcpy(AX25Sess->kind, "Incoming"); +- AX25Sess->socket = socket; +- +- Debugprintf("incoming call socket = %x", socket); +- +- // I think we need to reverse the path +- +- AX25Sess->pathLen = strlen(path); +- strcpy(AX25Sess->ReversePath, path); +- reverse_addr(path, AX25Sess->Path, strlen(path)); +- } +- +- // we process a packet on the necessary port +- +- memcpy(path, AX25Sess->Path, AX25Sess->pathLen); +- +- switch (f_id) +- { +- case I_I: +- +- on_I(socket, AX25Sess, pid, path, data, nr, ns, pf, cr, fecflag); +- break; +- +- case S_RR: +- +- on_RR(AX25Sess, path, nr, pf, cr); +- break; +- +- case S_RNR: +- +- on_RNR(AX25Sess, path, nr, pf, cr); +- break; +- +- case S_REJ: +- +- on_REJ(AX25Sess, path, nr, pf, cr); +- break; +- +- case S_SREJ: +- +- on_SREJ(AX25Sess, path, nr, pf, cr); +- break; +- +- case U_SABM: +- +- on_SABM(socket, AX25Sess); +- break; +- +- case U_DISC: +- +- on_DISC(AX25Sess); +- break; +- +- case U_UA: +- +- on_UA(AX25Sess); +- break; +- +- case U_DM: +- +- on_DM(AX25Sess); +- break; +- +- case U_UI: +- +- on_UI(AX25Sess, pf, cr); +- break; +- +- case U_FRMR: +- +- on_FRMR(socket, AX25Sess, path); +- break; +- } +- freeString(data); +-} +- +-int get_addr(char * Calls, UCHAR * AXCalls); +- +-void Send_UI(int port, Byte PID, char * CallFrom, char *CallTo, char * via, Byte * Msg, int MsgLen) +-{ +- char Addrs[256]; +- Byte path[256]; +- int destlen = 0; +- +- string * Data = newString(); +- string * Frame; +- +- UCHAR KISSBuffer[512]; +- int Length; +- +- stringAdd(Data, Msg, MsgLen); +- +- // We Need Dest, Source, Digis in path, with end of address bit set appropriately. +- +- sprintf(Addrs, "%s %s %s", CallTo, CallFrom, via); +- +- destlen = get_addr(Addrs, path); +- +- Frame = make_frame(Data, path, PID, 0, 0, U_FRM, U_UI, FALSE, SET_F, SET_C); +- +- // ? Don't we just send to TNC? +- +- Length = KISS_encode(KISSBuffer, port, Frame); +- +- KISSSendtoServer(KISSSockCopy[0], KISSBuffer, Length); +- +- monitor_frame(0, Frame, "", 1, 0); // Monitor +- freeString(Frame); +- +-} +- +- +- +- ++/* ++Copyright (C) 2019-2020 Andrei Kopanchuk UZ7HO ++ ++This file is part of QtSoundModem ++ ++QtSoundModem is free software: you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation, either version 3 of the License, or ++(at your option) any later version. ++ ++QtSoundModem is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with QtSoundModem. If not, see http://www.gnu.org/licenses ++ ++*/ ++ ++// UZ7HO Soundmodem Port by John Wiseman G8BPQ ++ ++// This is a simplified version for QtTermTCP ++ ++ ++ ++#include "ax25.h" ++ ++UCHAR TimerEvent = TIMER_EVENT_OFF; ++extern int busy; ++int listenEnable; ++int KISSListen = 1; ++int KISSChecksum = 0; ++int KISSAckMode = 0; ++ ++void * KISSSockCopy[4]; ++extern UCHAR axMYCALL[7] = ""; // Mycall in ax.25 ++ ++string * make_frame(string * data, Byte * path, Byte pid, Byte nr, Byte ns, Byte f_type, Byte f_id, boolean rpt, boolean pf, boolean cr); ++void rst_t3(TAX25Port * AX25Sess); ++void CheckUIFrame(unsigned char * path, string * data); ++TAX25Port * get_user_port(int snd_ch, Byte * path); ++ ++void inc_frack(TAX25Port * AX25Sess) ++{ ++ AX25Sess->clk_frack++; ++} ++ ++ ++void rst_frack(TAX25Port * AX25Sess) ++{ ++ AX25Sess->clk_frack = 0; ++} ++ ++void inc_t1(TAX25Port * AX25Sess) ++{ ++ AX25Sess->t1++; ++} ++ ++void rst_t1(TAX25Port * AX25Sess) ++{ ++ AX25Sess->t1 = 0; ++} ++ ++void inc_t3(TAX25Port * AX25Sess) ++{ ++ AX25Sess->t3++; ++} ++ ++void rst_t3(TAX25Port * AX25Sess) ++{ ++ AX25Sess->t3 = 0; ++} ++ ++ ++void rst_values(TAX25Port * AX25Sess) ++{ ++ AX25Sess->IPOLL_cnt = 0; ++ AX25Sess->hi_vs = 0; ++ AX25Sess->vs = 0; ++ AX25Sess->vr = 0; ++ Clear(&AX25Sess->I_frame_buf); ++ Clear(&AX25Sess->in_data_buf); ++ Clear(&AX25Sess->frm_collector); ++ ++ ax25_info_init(AX25Sess); ++ clr_frm_win(AX25Sess); ++} ++ ++ ++void rst_timer(TAX25Port * AX25Sess) ++{ ++ rst_frack(AX25Sess); ++ rst_t1(AX25Sess); ++ rst_t3(AX25Sess); ++} ++ ++void upd_i_lo(TAX25Port * AX25Sess, int n) //Update the counter of the first frame in the I-frame buffer ++{ ++ AX25Sess->i_lo = n; ++} ++ ++void upd_i_hi(TAX25Port * AX25Sess, int n) //Update last frame counter in I-frame buffer ++{ ++ AX25Sess->i_hi = n; ++} ++ ++void upd_vs(TAX25Port * AX25Sess, int n) //Update the counter of the next frame to transmit ++{ ++ AX25Sess->vs = ++n & 7; ++} ++ ++void upd_vr(TAX25Port * AX25Sess, int n) //Refresh the counter of the next frame at the reception ++{ ++ AX25Sess->vr = ++n & 7; ++} ++ ++ ++void Frame_Optimize(TAX25Port * AX25Sess, TStringList * buf) ++{ ++ // I think this removes redundant frames from the TX Queue (eg repeated RR frames) ++ ++ string * frame; ++ Byte path[80]; ++ string * data = newString(); ++ ++ Byte pid, nr, ns, f_type, f_id, rpt, cr, pf; ++ boolean curr_req, optimize; ++ int i, k; ++ char need_frm[8] = ""; ++ int index = 0; ++ boolean PollRR; ++ boolean PollREJ; ++ ++ PollRR = FALSE; ++ PollREJ = FALSE; ++ curr_req = FALSE; ++ ++ // Check Poll RR and REJ frame ++ ++ i = 0; ++ ++ while (i < buf->Count && !PollREJ) ++ { ++ frame = Strings(buf, i); ++ // TX frame has kiss control on front ++ ++ decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); ++ ++ if (cr == SET_R && pf == SET_P) ++ { ++ if (f_id == S_REJ) ++ PollREJ = TRUE; ++ else if (f_id == S_RR && nr == AX25Sess->vr) ++ PollRR = TRUE; ++ } ++ i++; ++ } ++ ++ // Performance of the REJ Cards: Optional Rej Cards ++ ++ i = 0; ++ ++ while (i < buf->Count) ++ { ++ optimize = TRUE; ++ frame = Strings(buf, i); ++ decode_frame(frame->Data + 1, frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); ++ ++ if (f_id == S_REJ && cr == SET_R) ++ { ++ if ((pf == SET_F && PollREJ) || nr != AX25Sess->vr) ++ { ++ Debugprintf("Optimizer dropping REJ nr %d vr %d pf %d PollREJ %d", nr, AX25Sess->vr, pf, PollREJ); ++ Delete(buf, i); ++ optimize = FALSE; ++ } ++ if (nr == AX25Sess->vr) ++ curr_req = TRUE; ++ } ++ if (optimize) ++ i++; ++ } ++ ++ // Performance Options ++ ++ i = 0; ++ ++ while (i < buf->Count) ++ { ++ need_frm[0] = 0; ++ index = 0; ++ k = AX25Sess->i_lo; ++ ++ while (k != AX25Sess->vs) ++ { ++ need_frm[index++] = k + 'A'; ++ k++; ++ k &= 7; ++ } ++ ++ optimize = TRUE; ++ ++ frame = Strings(buf, i); ++ ++ decode_frame(frame->Data +1 , frame->Length - 1, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); ++ ++ if (f_id == S_RR) ++ { ++ // RR Cards Methods: Optional RR, F Cards ++ if (cr == SET_R) ++ { ++ if (nr != AX25Sess->vr || ((pf == SET_F) && PollRR) || curr_req) ++ { ++ Debugprintf("Optimizer dropping RR nr %d vr %d pf %d PollRR %d", nr, AX25Sess->vr, pf, PollRR); ++ ++ Delete(buf, i); ++ optimize = FALSE; ++ } ++ } ++ ++ ++ // RR Cards Methods : Optional RR, P Cards ++ if (cr == SET_C) ++ { ++ if (AX25Sess->status == STAT_LINK || AX25Sess->status == STAT_WAIT_ANS) ++ { ++ Debugprintf("Optimizer dropping RR nr %d vr %d pf %d PollRR %d", nr, AX25Sess->vr, pf, PollRR); ++ Delete(buf, i); ++ optimize = FALSE; ++ } ++ } ++ } ++ // I - Cards Methods : Options for I - Cards ++ else if (f_id == I_I) ++ { ++ if (strchr(need_frm, ns + 'A') == 0) ++ { ++ Delete(buf, i); ++ optimize = FALSE; ++ } ++ else ++ { ++ if (nr != AX25Sess->vr) ++ buf->Items[i] = make_frame(data, path, pid, AX25Sess->vr, ns, f_type, f_id, rpt, pf, cr); ++ } ++ } ++ ++ // SABM Applications ++ ++ if (f_id == U_SABM) ++ { ++ if (AX25Sess->status != STAT_TRY_LINK) ++ { ++ Delete(buf, i); ++ optimize = FALSE; ++ } ++ } ++ ++ if (optimize) ++ i++; ++ } ++} ++ ++int KISS_encode(UCHAR * KISSBuffer, int port, string * frame) ++{ ++ // Encode frame ++ ++ UCHAR * ptr1 = frame->Data; ++ UCHAR TXCCC = 0; ++ int Len = frame->Length; ++ UCHAR * ptr2 = &KISSBuffer[2]; ++ UCHAR c; ++ ++ // TX Frame has control byte on front ++ ++ ptr1++; ++ Len--; ++ ++ KISSBuffer[0] = FEND; ++ KISSBuffer[1] = port << 4; ++ ++ TXCCC ^= KISSBuffer[1]; ++ ++ while (Len--) ++ { ++ c = *(ptr1++); ++ TXCCC ^= c; ++ ++ switch (c) ++ { ++ case FEND: ++ (*ptr2++) = FESC; ++ (*ptr2++) = TFEND; ++ break; ++ ++ case FESC: ++ ++ (*ptr2++) = FESC; ++ (*ptr2++) = TFESC; ++ break; ++ ++ // Drop through ++ ++ default: ++ ++ (*ptr2++) = c; ++ } ++ } ++ ++ // Add checksum if needed ++ ++ if (KISSChecksum) ++ { ++ c = TXCCC; ++ ++ // We don't support TNCX with Checksum ++ ++ switch (c) ++ { ++ case FEND: ++ (*ptr2++) = FESC; ++ (*ptr2++) = TFEND; ++ break; ++ ++ case FESC: ++ (*ptr2++) = FESC; ++ (*ptr2++) = TFESC; ++ break; ++ ++ default: ++ (*ptr2++) = c; ++ } ++ } ++ ++ (*ptr2++) = FEND; ++ ++ return (int)(ptr2 - KISSBuffer); ++} ++ ++void KISSSendtoServer(void * Socket, char * Data, int Length); ++ ++void add_pkt_buf(TAX25Port * AX25Sess, string * data) ++{ ++// boolean found = 0; ++// int i = 0; ++ UCHAR KISSBuffer[512]; ++ int Length; ++ ++ // ? Don't we just send to TNC? ++ ++ Length = KISS_encode(KISSBuffer, AX25Sess->snd_ch, data); ++ ++ KISSSendtoServer(AX25Sess->socket, KISSBuffer, Length); ++ ++ monitor_frame(0, data, "", 1, 0); // Monitor ++ freeString(data); ++ ++} ++ ++void add_I_FRM(TAX25Port * AX25Sess) ++{ ++ string * data; ++ int i; ++ ++ upd_i_lo(AX25Sess, AX25Sess->vs); ++ ++ while (AX25Sess->in_data_buf.Count > 0 && AX25Sess->I_frame_buf.Count != maxframe[AX25Sess->snd_ch]) ++ { ++ data = duplicateString(Strings(&AX25Sess->in_data_buf, 0)); ++ Delete(&AX25Sess->in_data_buf, 0); ++ Add(&AX25Sess->I_frame_buf, data); ++ } ++ if (AX25Sess->I_frame_buf.Count > 0) ++ { ++ for (i = 0; i < AX25Sess->I_frame_buf.Count; i++) ++ { ++ upd_i_hi(AX25Sess, AX25Sess->vs); ++ upd_vs(AX25Sess, AX25Sess->vs); ++ AX25Sess->hi_vs = AX25Sess->vs; // Last transmitted frame ++ } ++ } ++} ++ ++ ++void delete_I_FRM(TAX25Port * AX25Sess, int nr) ++{ ++ int i; ++ ++ i = AX25Sess->i_lo; ++ ++ while (i != nr) ++ { ++ if (AX25Sess->I_frame_buf.Count > 0) ++ { ++ AX25Sess->info.stat_s_pkt++; ++ AX25Sess->info.stat_s_byte += Strings(&AX25Sess->I_frame_buf, 0)->Length; ++ Delete(&AX25Sess->I_frame_buf, 0); ++ } ++ ++ i++; ++ i &= 7; ++ } ++ upd_i_lo(AX25Sess, nr); ++} ++ ++void delete_I_FRM_port(TAX25Port * AX25Sess) ++{ ++ string * frame; ++ char path[80] = ""; ++ string data= { 0 }; ++ ++ Byte pid, nr, ns, f_type, f_id, rpt, cr, pf; ++ boolean optimize; ++ int i = 0; ++ ++ while (i < AX25Sess->frame_buf.Count) ++ { ++ optimize = TRUE; ++ frame = Strings(&AX25Sess->frame_buf, i); ++ ++ decode_frame(frame->Data, frame->Length, path, &data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); ++ ++ if (f_id == I_I) ++ { ++ Delete(&AX25Sess->frame_buf, i); ++ optimize = FALSE; ++ } ++ if (optimize) ++ i++; ++ } ++} ++ ++void send_data_buf(TAX25Port * AX25Sess, int nr) ++{ ++ int i; ++ boolean new_frames; ++ boolean PF_bit; ++ ++ if (AX25Sess->status != STAT_LINK) ++ return; ++ ++ AX25Sess->IPOLL_cnt = 0; ++ AX25Sess->vs = nr; ++ delete_I_FRM(AX25Sess, nr); // ?? free acked frames ++// delete_I_FRM_port(AX25Sess); ++ ++ if (TXFrmMode[AX25Sess->snd_ch] == 1) ++ { ++ new_frames = FALSE; ++ ++ if (AX25Sess->I_frame_buf.Count < 2) ++ { ++ add_I_FRM(AX25Sess); ++ AX25Sess->status = STAT_LINK; ++ new_frames = TRUE; ++ } ++ ++ if (AX25Sess->I_frame_buf.Count > 0) ++ { ++ if (new_frames) ++ { ++ for (i = 0; i < AX25Sess->I_frame_buf.Count; i++) ++ { ++ if (i == AX25Sess->I_frame_buf.Count - 1) ++ PF_bit = SET_P; ++ else ++ PF_bit = SET_F; ++ ++ add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C)); ++ } ++ } ++ if (!new_frames) ++ { ++ add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); //SET_P ++ upd_vs(AX25Sess, AX25Sess->vs); ++ } ++ AX25Sess->status = STAT_WAIT_ANS; ++ rst_timer(AX25Sess); ++ } ++ } ++ ++ if (TXFrmMode[AX25Sess->snd_ch] == 0) ++ { ++ add_I_FRM(AX25Sess); ++ AX25Sess->status = STAT_LINK; ++ ++ if (AX25Sess->I_frame_buf.Count > 0) ++ { ++ for (i = 0; i < AX25Sess->I_frame_buf.Count; i++) ++ { ++ if (i == AX25Sess->I_frame_buf.Count - 1) ++ PF_bit = SET_P; ++ else ++ PF_bit = SET_F; ++ add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C)); ++ } ++ AX25Sess->status = STAT_WAIT_ANS; ++ rst_timer(AX25Sess); ++ } ++ } ++} ++ ++ ++void send_data_buf_srej(TAX25Port * AX25Sess, int nr) ++{ ++ // Similar to send_data_buf but only sends the requested I frame with P set ++ ++ int i = 0; ++ boolean new_frames; ++ boolean PF_bit; ++ ++ if (AX25Sess->status != STAT_LINK) ++ return; ++ ++ AX25Sess->IPOLL_cnt = 0; ++ AX25Sess->vs = nr; ++ delete_I_FRM(AX25Sess, nr); // ?? free acked frames ++ ++ new_frames = FALSE; ++ ++ add_I_FRM(AX25Sess); ++ AX25Sess->status = STAT_LINK; ++ new_frames = TRUE; ++ ++ if (AX25Sess->I_frame_buf.Count > 0) ++ { ++ if (new_frames) ++ { ++ PF_bit = SET_P; ++ ++ add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, i), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, ((AX25Sess->i_lo + i) & 7), I_FRM, I_I, FALSE, PF_bit, SET_C)); ++ } ++ else ++ { ++ ++ add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), AX25Sess->Path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); //SET_P ++ upd_vs(AX25Sess, AX25Sess->vs); ++ } ++ } ++ AX25Sess->status = STAT_WAIT_ANS; ++ rst_timer(AX25Sess); ++} ++ ++void write_frame_collector(TAX25Port * AX25Sess, int ns, string * data) ++{ ++ Byte i; ++ char frm_ns; ++ string * frm; ++ boolean found ; ++ boolean need_frm; ++ ++ if (max_frame_collector[AX25Sess->snd_ch] < 1) ++ return; ++ ++ need_frm = FALSE; ++ i = 1; ++ do ++ { ++ if (ns == ((AX25Sess->vr + i) & 7)) ++ need_frm = TRUE; ++ ++ i++; ++ ++ } while (i <= max_frame_collector[AX25Sess->snd_ch] && !need_frm); ++ ++ if (need_frm) ++ { ++ frm_ns = ns; ++ found = FALSE; ++ i = 0; ++ ++ if (AX25Sess->frm_collector.Count > 0) ++ { ++ do ++ { ++ frm = Strings(&AX25Sess->frm_collector, i); ++ ++ if (frm_ns == frm->Data[0]) ++ found = TRUE; ++ i++; ++ } ++ while (!found && i != AX25Sess->frm_collector.Count); ++ ++ } ++ ++ if (!found) ++ { ++ string * frm = newString(); ++ ++ stringAdd(frm, (char *)&frm_ns, 1); ++ stringAdd(frm, data->Data, data->Length); ++ Add(&AX25Sess->frm_collector, frm); ++ } ++ } ++} ++ ++string * read_frame_collector(TAX25Port * AX25Sess, boolean fecflag) ++{ ++ // Look for required frame no in saved frames ++ ++ string * frm; ++ string * data = newString(); ++ ++ int i = 0; ++ Byte frm_ns; ++ ++ while (i < AX25Sess->frm_collector.Count) ++ { ++ frm = duplicateString(Strings(&AX25Sess->frm_collector, i)); ++ ++ frm_ns = frm->Data[0]; ++ ++ if (frm_ns == AX25Sess->vr) ++ { ++ Delete(&AX25Sess->frm_collector, i); ++ ++ upd_vr(AX25Sess, AX25Sess->vr); ++ ++ mydelete(frm, 0, 1); // Remove vr from front ++ ++ stringAdd(data, frm->Data, frm->Length); ++ ++ AX25Sess->info.stat_r_pkt++; ++ AX25Sess->info.stat_r_fc++; ++ ++ if (fecflag) ++ AX25Sess->info.stat_fec_count++; ++ ++ AX25Sess->info.stat_r_byte += frm->Length; ++ AX25Sess->frm_win[frm_ns].Length = frm->Length; //Save the frame to the window buffer ++ AX25Sess->frm_win[frm_ns].Data = frm->Data; //Save the frame to the window buffer ++ } ++ ++ i++; ++ } ++ return data; ++} ++ ++ ++/////////////////////////// SET-FRAMES ////////////////////////////////// ++ ++void set_chk_link(TAX25Port * AX25Sess, Byte * path) ++{ ++ boolean b_IPOLL; ++ int len; ++ ++ AX25Sess->status = STAT_CHK_LINK; ++ ++ // if AX25Sess->digi<>'' then path:=path+','+reverse_digi(AX25Sess->digi); ++ ++ b_IPOLL = FALSE; ++ ++ if (AX25Sess->I_frame_buf.Count > 0 && AX25Sess->IPOLL_cnt < 2) ++ { ++ len = Strings(&AX25Sess->I_frame_buf, 0)->Length; ++ ++ if (len > 0 && len <= IPOLL[AX25Sess->snd_ch]) ++ { ++ ++ b_IPOLL = TRUE; ++ AX25Sess->IPOLL_cnt++; ++ } ++ } ++ if (b_IPOLL) ++ add_pkt_buf(AX25Sess, make_frame(Strings(&AX25Sess->I_frame_buf, 0), path, AX25Sess->PID, AX25Sess->vr, AX25Sess->i_lo, I_FRM, I_I, FALSE, SET_P, SET_C)); ++ else ++ add_pkt_buf(AX25Sess, make_frame(NULL, path, 0xF0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_C)); ++ ++ inc_frack(AX25Sess); ++} ++ ++ ++ ++// This seems to start a connection ++ ++void set_link(TAX25Port * AX25Sess, UCHAR * axpath) ++{ ++ if (AX25Sess->status != STAT_LINK) ++ { ++ string nullstring; ++ nullstring.Length = 0; ++ ++ rst_values(AX25Sess); ++ ++ AX25Sess->status = STAT_TRY_LINK; ++ ++ // if (AX25Sess->digi[0] != 0) ++ // path: = path + ',' + reverse_digi(AX25Sess->digi); ++ ++ add_pkt_buf(AX25Sess, make_frame(&nullstring, axpath, 0, 0, 0, U_FRM, U_SABM, SET_NO_RPT, SET_P, SET_C)); ++ ++ inc_frack(AX25Sess); ++ } ++} ++ ++#define MODE_OUR 0 ++ ++void set_try_unlink(TAX25Port * AX25Sess, Byte * path) ++{ ++ string nullstring; ++ nullstring.Length = 0; ++ ++ AX25Sess->status = STAT_TRY_UNLINK; ++ add_pkt_buf(AX25Sess, make_frame(&nullstring, path, 0, 0, 0, U_FRM, U_DISC, SET_NO_RPT, SET_P, SET_C)); ++ inc_frack(AX25Sess); ++} ++ ++ ++void set_unlink(TAX25Port * AX25Sess, Byte * path) ++{ ++ if (AX25Sess->status == STAT_TRY_UNLINK ++ || AX25Sess->status == STAT_TRY_LINK ++ || AX25Sess->status == STAT_NO_LINK) ++ { ++ string nullstring; ++ nullstring.Length = 0; ++ ++ // if (AX25Sess->digi[0] != 0) ++ // path: = path + ',' + reverse_digi(AX25Sess->digi); ++ ++ AX25_disc(AX25Sess, MODE_OUR); ++ ++ if (AX25Sess->status != STAT_TRY_UNLINK) ++ add_pkt_buf(AX25Sess, make_frame(&nullstring, path, 0, 0, 0, U_FRM, U_DISC, SET_NO_RPT, SET_P, SET_C)); ++ ++ AX25Sess->info.stat_end_ses = time(NULL); ++ ++ write_ax25_info(AX25Sess); ++ rst_values(AX25Sess); ++ ++ memset(AX25Sess->corrcall, 0, 10); ++ memset(AX25Sess->mycall, 0, 10); ++ AX25Sess->digi[0] = 0; ++ AX25Sess->status = STAT_NO_LINK; ++ ++ } ++ else ++ set_try_unlink(AX25Sess, AX25Sess->Path); ++} ++ ++void set_FRMR(int snd_ch, Byte * path, unsigned char frameType) ++{ ++ //We may not have a session when sending FRMR so reverse path and send ++ ++ Byte revpath[80]; ++ string * Data = newString(); ++ string * Frame; ++ ++ UCHAR KISSBuffer[512]; ++ int Length; ++ ++ Data->Data[0] = frameType; ++ Data->Data[1] = 0; ++ Data->Data[2] = 1; // Invalid CTL Byte ++ Data->Length = 3; ++ ++ reverse_addr(path, revpath, strlen(path)); ++ ++ Frame = make_frame(Data, revpath, 0, 0, 0, U_FRM, U_FRMR, FALSE, SET_P, SET_R); ++ ++ // ? Don't we just send to TNC? ++ ++ Length = KISS_encode(KISSBuffer, 0, Frame); ++ ++ KISSSendtoServer(KISSSockCopy[snd_ch], KISSBuffer, Length); ++ ++ monitor_frame(0, Frame, "", 1, 0); // Monitor ++ freeString(Frame); ++ freeString(Data); ++} ++ ++void set_DM(int snd_ch, Byte * path) ++{ ++ //We may not have a session when sending DM so reverse path and send ++ ++ Byte revpath[80]; ++ ++ reverse_addr(path, revpath, strlen(path)); ++ ++ add_pkt_buf(&AX25Port[snd_ch][0], make_frame(NULL, revpath, 0, 0, 0, U_FRM,U_DM,FALSE,SET_P,SET_R)); ++} ++ ++/////////////////////////// S-FRAMES //////////////////////////////////// ++ ++ ++void on_RR(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) ++{ ++ char need_frame[16] = ""; ++ int index = 0; ++ ++ int i; ++ ++ if (AX25Sess->status == STAT_TRY_LINK) ++ return; ++ ++ if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) ++ { ++ if (cr == SET_C) ++ set_DM(AX25Sess->snd_ch, path); ++ ++ return; ++ } ++ ++ if (cr == SET_R) ++ { ++ // Determine which frames could get into the user’s frame buffer. ++ i = AX25Sess->vs; ++ ++ need_frame[index++] = i + '0'; ++ ++// Debugprintf("RR Rxed vs = %d hi_vs = %d", AX25Sess->vs, AX25Sess->hi_vs); ++ while (i != AX25Sess->hi_vs) ++ { ++ i++; ++ i &= 7; ++ ++ need_frame[index++] = i + '0'; ++ if (index > 10) ++ { ++ Debugprintf("Index corrupt %d need_frame = %s", index, need_frame); ++ break; ++ } ++ } ++ ++ //Clear the received frames from the transmission buffer. ++ ++ if (AX25Sess->status == STAT_WAIT_ANS) ++ delete_I_FRM(AX25Sess, nr); ++ ++ // We restore the link if the number is valid ++ ++ if (AX25Sess->status == STAT_CHK_LINK || strchr(need_frame, nr + '0') != 0) ++ { ++ rst_timer(AX25Sess); ++ AX25Sess->status = STAT_LINK; ++ send_data_buf(AX25Sess, nr); ++ } ++ } ++ ++ if (cr == SET_C) ++ add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, pf, SET_R)); ++ ++ rst_t3(AX25Sess); ++} ++ ++ ++void on_RNR(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) ++{ ++ UNUSED(pf); ++ ++ if (AX25Sess->status == STAT_TRY_LINK) ++ return; ++ ++ if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) ++ { ++ if (cr == SET_C) ++ set_DM(AX25Sess->snd_ch, path); ++ ++ return; ++ } ++ ++ if (cr == SET_R) ++ { ++ rst_timer(AX25Sess); ++ ++ if (AX25Sess->status == STAT_WAIT_ANS) ++ delete_I_FRM(AX25Sess, nr); ++ ++ AX25Sess->status = STAT_CHK_LINK; ++ } ++ ++ if (cr == SET_C) ++ add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R)); ++ ++ rst_t3(AX25Sess); ++} ++ ++ ++void on_REJ(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) ++{ ++ UNUSED(pf); ++ if (AX25Sess->status == STAT_TRY_LINK) ++ return; ++ ++ if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) ++ { ++ if (cr == SET_C) ++ set_DM(AX25Sess->snd_ch, path); ++ ++ return; ++ } ++ ++ if (cr == SET_R) ++ { ++ rst_timer(AX25Sess); ++ AX25Sess->status = STAT_LINK; ++ ++ send_data_buf(AX25Sess, nr); ++ } ++ ++ if (cr == SET_C) ++ add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R)); ++} ++ ++ ++void on_SREJ(TAX25Port * AX25Sess, Byte * path, int nr, int pf, int cr) ++{ ++ UNUSED(pf); ++ ++ if (AX25Sess->status == STAT_TRY_LINK) ++ return; ++ ++ if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) ++ { ++ if (cr == SET_C) ++ set_DM(AX25Sess->snd_ch, path); ++ ++ return; ++ } ++ ++ if (cr == SET_R) ++ { ++ rst_timer(AX25Sess); ++ AX25Sess->status = STAT_LINK; ++ ++ send_data_buf_srej(AX25Sess, nr); ++ } ++ ++ if (cr == SET_C) ++ add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, SET_P, SET_R)); ++} ++/////////////////////////// I-FRAMES //////////////////////////////////// ++ ++void on_I(void * socket, TAX25Port * AX25Sess, int PID, Byte * path, string * data, int nr, int ns, int pf, int cr, boolean fecflag) ++{ ++ UNUSED(cr); ++ UNUSED(socket); ++ string * collector_data = 0; ++ int i; ++ Byte need_frame[16] = ""; ++ int index = 0; ++ ++ ++ if (AX25Sess->status == STAT_TRY_LINK) ++ return; ++ ++ if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_UNLINK) ++ { ++ set_DM(0, path); ++ return; ++ } ++ ++ if (busy) ++ { ++ add_pkt_buf(AX25Sess, make_frame(NULL, path, PID, AX25Sess->vr, 0, S_FRM, S_RNR, FALSE, pf, SET_R)); ++ return; ++ } ++ ++ // Determine which frames could get into the user’s frame buffer. ++ ++ i = AX25Sess->vs; ++ ++ need_frame[index++] = i + '0'; ++ ++ // Debugprintf("I Rxed vs = %d hi_vs = %d", AX25Sess->vs, AX25Sess->hi_vs); ++ ++ while (i != AX25Sess->hi_vs) ++ { ++ i++; ++ i &= 7; ++ ++ need_frame[index++] = i + '0'; ++ if (index > 10) ++ { ++ Debugprintf("Index corrupt %d need_frame = %s", index, need_frame); ++ break; ++ } ++ } ++ ++ //Clear received frames from the transmission buffer. ++ ++ if (AX25Sess->status == STAT_WAIT_ANS) ++ delete_I_FRM(AX25Sess, nr); ++ ++ //We restore the link if the number is valid ++ ++ if (AX25Sess->status == STAT_CHK_LINK || strchr(need_frame, nr + '0') != 0) ++ { ++ //We restore the link if the number is valid ++ ++ rst_timer(AX25Sess); ++ AX25Sess->status = STAT_LINK; ++ send_data_buf(AX25Sess, nr); ++ } ++ ++ if (ns == AX25Sess->vr) ++ { ++ //If the expected frame, send RR, F ++ ++ AX25Sess->info.stat_r_pkt++; ++ AX25Sess->info.stat_r_byte += data->Length; ++ ++ if (fecflag) ++ AX25Sess->info.stat_fec_count++; ++ ++ upd_vr(AX25Sess, AX25Sess->vr); ++ ++ AX25Sess->frm_win[ns].Length = data->Length; //Save the frame to the window buffer ++ AX25Sess->frm_win[ns].Data = data->Data; //Save the frame to the window buffer ++ ++ collector_data = read_frame_collector(AX25Sess, fecflag); ++ ++ stringAdd(data, collector_data->Data, collector_data->Length); ++ ++ SendtoTerm(AX25Sess->Sess, (char *)data->Data, data->Length); ++ ++ // Andy's code queues RR immediately and uses frame optimiser to remove ++ // redundant RR (not P) frames. I can't do that so need a proper resptime ++ // system. Try setting an RRNeeded timer (t2). ++ ++ if (pf) ++ { ++ // Poll set, so respond immediately ++ ++ add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, pf, SET_R)); ++ AX25Sess->t2 = 0; ++ } ++ else ++ AX25Sess->t2 = resptime[0] / 100; // resptime is in mS ++ ++ freeString(collector_data); ++ } ++ else ++ { ++ // If the frame is not expected, send REJ, F ++ ++ if ((AX25Sess->frm_win[ns].Length != data->Length) && ++ memcmp(&AX25Sess->frm_win[ns].Data, data->Data, data->Length) != 0) ++ ++ write_frame_collector(AX25Sess, ns, data); ++ ++ add_pkt_buf(AX25Sess, make_frame(NULL, path, 0, AX25Sess->vr, 0, S_FRM, S_REJ, FALSE, pf, SET_R)); ++ } ++ rst_t3(AX25Sess); ++ ++} ++/////////////////////////// U-FRAMES //////////////////////////////////// ++ ++void * ax25IncomingConnect(TAX25Port * AX25Sess); ++ ++void on_SABM(void * socket, TAX25Port * AX25Sess) ++{ ++ if (AX25Sess->status == STAT_TRY_UNLINK) ++ { ++ AX25Sess->info.stat_end_ses = time(NULL); ++ ++ write_ax25_info(AX25Sess); ++ rst_values(AX25Sess); ++ ++ memset(AX25Sess->corrcall, 0, 10); ++ memset(AX25Sess->mycall, 0, 10); ++ AX25Sess->digi[0] = 0; ++ ++ AX25_disc(AX25Sess, MODE_OTHER); ++ Clear(&AX25Sess->frame_buf); ++ ++ AX25Sess->status = STAT_NO_LINK; ++ } ++ ++ if (AX25Sess->status == STAT_TRY_LINK) ++ { ++ AX25_disc(AX25Sess, MODE_OTHER); ++ ++ rst_timer(AX25Sess); ++ rst_values(AX25Sess); ++ Clear(&AX25Sess->frame_buf); ++ AX25Sess->status = STAT_NO_LINK; ++ } ++ ++ if (AX25Sess->status != STAT_NO_LINK) ++ { ++ if ((strcmp(AX25Sess->kind, "Outgoing") == 0) || ++ AX25Sess->status == STAT_TRY_UNLINK || AX25Sess->info.stat_s_byte > 0 || ++ AX25Sess->info.stat_r_byte > 0 || AX25Sess->frm_collector.Count > 0) ++ { ++ AX25Sess->info.stat_end_ses = time(NULL); ++ AX25_disc(AX25Sess, MODE_OTHER); ++ write_ax25_info(AX25Sess); ++ rst_timer(AX25Sess); ++ rst_values(AX25Sess); ++ Clear(&AX25Sess->frame_buf); ++ AX25Sess->status = STAT_NO_LINK; ++ } ++ } ++ ++ if (AX25Sess->status == STAT_NO_LINK) ++ { ++ AX25Sess->vr = 0; ++ AX25Sess->vs = 0; ++ AX25Sess->hi_vs = 0; ++ ++ Clear(&AX25Sess->frm_collector); ++ clr_frm_win(AX25Sess); ++ AX25Sess->status = STAT_LINK; ++ AX25Sess->info.stat_begin_ses = time(NULL); ++ strcpy(AX25Sess->kind, "Incoming"); ++ AX25Sess->socket = socket; ++ ++ // Must send UA before any ctext ++ ++ add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R)); ++ ++ if (ax25IncomingConnect(AX25Sess)) // Attach to Terminal ++ AX25_conn(AX25Sess, AX25Sess->snd_ch, MODE_OTHER); ++ ++ return; ++ } ++ ++ add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R)); ++} ++ ++void on_DISC(TAX25Port * AX25Sess) ++{ ++ if (AX25Sess->status != STAT_NO_LINK) ++ { ++ AX25Sess->info.stat_end_ses = time(NULL); ++ AX25_disc(AX25Sess, MODE_OTHER); ++ write_ax25_info(AX25Sess); ++ } ++ ++ if (AX25Sess->status == STAT_NO_LINK || AX25Sess->status == STAT_TRY_LINK) ++ set_DM(AX25Sess->snd_ch, AX25Sess->Path); ++ else ++ add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, 0, 0, U_FRM, U_UA, FALSE, SET_P, SET_R)); ++ ++ rst_values(AX25Sess); ++ memset(AX25Sess->corrcall, 0, 10); ++ memset(AX25Sess->mycall, 0, 10); ++ AX25Sess->digi[0] = 0; ++ AX25Sess->status = STAT_NO_LINK; ++} ++ ++void on_DM(TAX25Port * AX25Sess) ++{ ++ if (AX25Sess->status == STAT_TRY_LINK) ++ { ++ ++ char Msg[128]; ++ int Len; ++ ++ Len = sprintf(Msg, "*** Busy From %s\r", AX25Sess->corrcall); ++ SendtoTerm(AX25Sess->Sess, Msg, Len); ++ } ++ else if (AX25Sess->status != STAT_NO_LINK) ++ { ++ AX25Sess->info.stat_end_ses = time(NULL); ++ AX25_disc(AX25Sess, MODE_OTHER); ++ write_ax25_info(AX25Sess); ++ } ++ ++ rst_timer(AX25Sess); ++ rst_values(AX25Sess); ++ memset(AX25Sess->corrcall, 0, 10); ++ memset(AX25Sess->mycall, 0, 10); ++ AX25Sess->digi[0] = 0; ++ AX25Sess->status = STAT_NO_LINK; ++} ++ ++ ++void on_UA(TAX25Port * AX25Sess) ++{ ++ switch (AX25Sess->status) ++ { ++ case STAT_TRY_LINK: ++ ++ AX25Sess->info.stat_begin_ses = time(NULL); ++ AX25Sess->status = STAT_LINK; ++ AX25_conn(AX25Sess, AX25Sess->snd_ch, MODE_OUR); ++ break; ++ ++ case STAT_TRY_UNLINK: ++ ++ AX25Sess->info.stat_end_ses = time(NULL); ++ AX25_disc(AX25Sess, MODE_OUR); ++ write_ax25_info(AX25Sess); ++ ++ rst_values(AX25Sess); ++ AX25Sess->status = STAT_NO_LINK; ++ memset(AX25Sess->corrcall, 0, 10); ++ memset(AX25Sess->mycall, 0, 10); ++ AX25Sess->digi[0] = 0; ++ break; ++ } ++ ++ rst_timer(AX25Sess); ++} ++ ++void on_UI(TAX25Port * AX25Sess, int pf, int cr) ++{ ++ UNUSED(AX25Sess); ++ UNUSED(pf); ++ UNUSED(cr); ++ ++} ++ ++void on_FRMR(void * socket, TAX25Port * AX25Sess, Byte * path) ++{ ++ if (AX25Sess->status != STAT_NO_LINK) ++ { ++ AX25Sess->info.stat_end_ses = time(NULL); ++ ++ AX25_disc(socket, MODE_OTHER); ++ write_ax25_info(AX25Sess); ++ } ++ ++ set_DM(AX25Sess->snd_ch, path); ++ ++ rst_values(AX25Sess); ++ memset(AX25Sess->corrcall, 0, 10); ++ memset(AX25Sess->mycall, 0, 10); ++ AX25Sess->digi[0] = 0; ++ AX25Sess->status = STAT_NO_LINK; ++} ++ ++ ++ ++void UpdateActiveConnects(int snd_ch) ++{ ++ int port; ++ ++ users[snd_ch] = 0; ++ ++ for (port = 0; port < port_num; port++) ++ if (AX25Port[snd_ch][port].status != STAT_NO_LINK) ++ users[snd_ch]++; ++} ++ ++ ++void timer_event() ++{ ++ int snd_ch, port; ++ single frack; ++ Byte active; ++ TAX25Port * AX25Sess; ++ ++ TimerEvent = TIMER_EVENT_OFF; ++ ++ for (snd_ch = 0; snd_ch < 4; snd_ch++) ++ { ++ //reset the slottime timer ++ ++ frack = frack_time[snd_ch]; ++ ++ for (port = 0; port < port_num; port++) ++ { ++ AX25Sess = &AX25Port[snd_ch][port]; ++ ++ if (AX25Sess->status == STAT_NO_LINK) ++ continue; ++ ++ if (AX25Sess->t2) ++ { ++ AX25Sess->t2--; ++ if (AX25Sess->t2 == 0) ++ { ++ // Expired - send RR (without P) ++ ++ add_pkt_buf(AX25Sess, make_frame(NULL, AX25Sess->Path, 0, AX25Sess->vr, 0, S_FRM, S_RR, FALSE, 0, SET_R)); ++ } ++ } ++ ++ if (AX25Sess->frame_buf.Count == 0) //when the transfer buffer is empty ++ inc_t1(AX25Sess); // we consider time of the timer of repeated requests ++ ++ // Wouldn't it make more sense to keep path in ax.25 struct? ++ ++ if (AX25Sess->t1 >= frack * 10 + (number_digi(AX25Sess->digi) * frack * 20)) ++ { ++ if (AX25Sess->clk_frack >= fracks[snd_ch]) ++ { ++ // This disconnects after retries expires ++ ++ rst_frack(AX25Sess); ++ set_unlink(AX25Sess, AX25Sess->Path); ++ } ++ ++ switch (AX25Sess->status) ++ { ++ case STAT_TRY_LINK: ++ ++ set_link(AX25Sess, AX25Sess->Path); ++ break; ++ ++ case STAT_TRY_UNLINK: ++ ++ set_try_unlink(AX25Sess, AX25Sess->Path); ++ break; ++ ++ case STAT_WAIT_ANS: ++ ++ set_chk_link(AX25Sess, AX25Sess->Path); ++ break; ++ ++ case STAT_CHK_LINK: ++ ++ set_chk_link(AX25Sess, AX25Sess->Path); ++ break; ++ } ++ ++ rst_t1(AX25Sess); ++ } ++ ++ ++ if (AX25Sess->t3 >= idletime[snd_ch] * 10) ++ { ++ set_chk_link(AX25Sess, AX25Sess->Path); ++ rst_t1(AX25Sess); ++ rst_t3(AX25Sess); ++ } ++ ++ if (AX25Sess->status == STAT_LINK) ++ inc_t3(AX25Sess); ++ ++ } ++ } ++ // KISS ACKMODE ++ //if (snd_status[snd_ch]<>SND_TX) and KISSServ then KISS_send_ack1(snd_ch); ++} ++ ++TAX25Port * get_free_port(int snd_ch) ++{ ++ int i = 0; ++ ++ while (i < port_num) ++ { ++ if (AX25Port[snd_ch][i].status == STAT_NO_LINK) ++ return &AX25Port[snd_ch][i]; ++ ++ i++; ++ } ++ return FALSE; ++} ++ ++ ++TAX25Port * get_user_port(int snd_ch, Byte * path) ++ { ++ TAX25Port * AX25Sess = NULL; ++ ++ int i = 0; ++ ++ ++ while (i < port_num) ++ { ++ AX25Sess = &AX25Port[snd_ch][i]; ++ ++ if (AX25Sess->status != STAT_NO_LINK && memcmp(AX25Sess->ReversePath, path, AX25Sess->pathLen) == 0) ++ return AX25Sess; ++ ++ i++; ++ } ++ ++ return FALSE; ++} ++ ++boolean get_user_dupe(int snd_ch, Byte * path) ++{ ++ int i = 0; ++ TAX25Port * AX25Sess; ++ ++ while (i < port_num) ++ { ++ AX25Sess = &AX25Port[snd_ch][i]; ++ ++ if (AX25Sess->status != STAT_NO_LINK && memcmp(AX25Sess->ReversePath, path, AX25Sess->pathLen) == 0) ++ return TRUE; ++ ++ i++; ++ } ++ ++ return FALSE; ++} ++ ++TAX25Port * get_user_port_by_calls(int snd_ch, char * CallFrom, char * CallTo) ++{ ++ int i = 0; ++ TAX25Port * AX25Sess = NULL; ++ ++ while (i < port_num) ++ { ++ AX25Sess = &AX25Port[snd_ch][i]; ++ ++ if (AX25Sess->status != STAT_NO_LINK && ++ strcmp(CallFrom, AX25Sess->mycall) == 0 && strcmp(CallTo, AX25Sess->corrcall) == 0) ++ ++ return AX25Sess; ++ ++ i++; ++ } ++ ++ return NULL; ++} ++ ++void * get_sock_by_port(TAX25Port * AX25Sess) ++{ ++ void * socket = (void *)-1; ++ ++ if (AX25Sess) ++ socket = AX25Sess->socket; ++ ++ return socket; ++} ++ ++void Digipeater(int snd_ch, string * frame) ++{ ++ char call[16]; ++ Byte * addr = &frame->Data[7]; // Origin ++ string * frameCopy; ++ ++ int n = 8; // Max digis ++ ++ if (list_digi_callsigns[snd_ch].Count == 0) ++ return; ++ ++ // Look for first unused digi ++ ++ while ((addr[6] & 1) == 0 && n--) // until end of address ++ { ++ addr += 7; ++ ++ if ((addr[6] & 128) == 0) ++ { ++ // unused digi - is it addressed to us? ++ ++ memcpy(call, addr, 7); ++ call[6] &= 0x7E; // Mask end of call ++ ++ // See if in digi list ++ ++ int i; ++ ++ for (i = 0; i < list_digi_callsigns->Count; i++) ++ { ++ if (memcmp(list_digi_callsigns->Items[i]->Data, call, 7) == 0) ++ { ++ UCHAR KISSBuffer[512]; ++ int Length; ++ ++ // for us ++ ++ addr[6] |= 128; // set digi'ed ++ ++ // TX Frames need a KISS control on front ++ ++ frameCopy = newString(); ++ ++ frameCopy->Data[0] = 0; ++ frameCopy->Length = 1; ++ ++ stringAdd(frameCopy, frame->Data, frame->Length); // Exclude CRC ++ ++ addr[6] &= 0x7f; // clear digi'ed from original; ++ ++ // Send to TNC ++ ++ // ? Don't we just send to TNC? ++ ++ Length = KISS_encode(KISSBuffer, 0, frameCopy); ++ ++ KISSSendtoServer(KISSSockCopy[snd_ch], KISSBuffer, Length); ++ ++ monitor_frame(0, frameCopy, "", 1, 0); // Monitor ++ freeString(frameCopy); ++ ++ return; ++ } ++ } ++ } ++ } ++} ++ ++void analiz_frame(int snd_ch, string * frame, void * socket, boolean fecflag) ++{ ++ Byte path[80]; ++ string * data = 0; ++ Byte pid, nr, ns, f_type, f_id, rpt, cr, pf; ++ Byte * ptr; ++ ++ int excluded = 0; ++ int len; ++ ++ TAX25Port * AX25Sess; ++ ++ // mod_icon_status = mod_rx; ++ ++ len = frame->Length; ++ ++ if (len < PKT_ERR) ++ return; ++ ++ data = newString(); ++ ++ decode_frame(frame->Data, frame->Length, path, data, &pid, &nr, &ns, &f_type, &f_id, &rpt, &pf, &cr); ++ ++ // if is_excluded_call(snd_ch,path) then excluded:=TRUE; ++ // if is_excluded_frm(snd_ch,f_id,data) then excluded:=TRUE; ++ ++ // CRC Collision Check ++ ++ if (!is_correct_path(path, pid)) ++ { ++ // Duff path - if Non-AX25 filter active log and discard ++ } ++ ++ monitor_frame(snd_ch, frame, "", 0, excluded); // Monitor ++ ++ // Digipeat frame ++ ++ Digipeater(snd_ch, frame); ++ ++ if (!is_last_digi(path)) ++ { ++ freeString(data); ++ return; // Don't process if still unused digis ++ } ++ ++ // Clear repeated bits from digi path ++ ++ ptr = &path[13]; ++ ++ while ((*ptr & 1) == 0) // end of address ++ { ++ ptr += 7; ++ *(ptr) &= 0x7f; // Clear digi'd bit ++ } ++ ++ // search for port of correspondent ++ ++ AX25Sess = get_user_port(snd_ch, path); ++ ++ // if not an active session, AX25Sess will be NULL ++ ++// if (AX25Sess == NULL) ++// socket = in_list_incoming_mycall(path); ++// else ++// socket = get_sock_by_port(AX25Sess); ++ ++ // link analysis ++ ++ if (AX25Sess == NULL) ++ { ++ if (f_id == U_UI) ++ { ++ CheckUIFrame(path, data); ++ freeString(data); ++ return; // Don't precess UI at the moment ++ } ++ ++ // No Session. If socket is set (so call is in incoming calls list) and SABM set up session ++ ++ // Check addresses to us ++ ++ if (memcmp(path, axMYCALL, 7) != 0) ++ return; // ignore ++ ++ if (KISSListen == 0) ++ { ++ set_DM(snd_ch, path); ++ freeString(data); ++ return; ++ } ++ ++ if (f_id != U_SABM) // Not SABM ++ { ++ // send DM if P set ++ ++ if (cr == SET_C) ++ { ++ switch (f_id) ++ { ++ case U_DISC: ++ case S_RR: ++ case S_REJ: ++ case S_RNR: ++ case I_I: ++ ++ set_DM(snd_ch, path); ++ break; ++ ++ case U_UI: ++ break; ++ ++ default: ++ set_FRMR(snd_ch, path, f_id); ++ } ++ ++ ++ } ++ freeString(data); ++ return; ++ } ++ ++ // Must be SABM. See if it would duplicate an existing session (but could it - wouldn't that be found earlier ?? ++ ++ // Make sure it is for us ++ ++ ++ ++ if (get_user_dupe(snd_ch, path)) // Not SABM or a duplicate call pair ++ { ++ freeString(data); ++ return; ++ } ++ ++ AX25Sess = get_free_port(snd_ch); ++ ++ if (AX25Sess == NULL) ++ { ++ // if there are no free ports for connection - reject ++ ++ Byte Rev[80]; ++ ++ reverse_addr(path, Rev, strlen(path)); ++ set_DM(snd_ch, Rev); ++ freeString(data); ++ return; ++ } ++ ++ // initialise new session ++ ++ AX25Sess->snd_ch = snd_ch; ++ ++ AX25Sess->corrcall[ConvFromAX25(&path[7], AX25Sess->corrcall)] = 0; ++ AX25Sess->mycall[ConvFromAX25(path, AX25Sess->mycall)] = 0; ++ AX25Sess->digi[0] = 0; ++ ++ // rst_timer(snd_ch, free_port); ++ ++ strcpy(AX25Sess->kind, "Incoming"); ++ AX25Sess->socket = socket; ++ ++ Debugprintf("incoming call socket = %x", socket); ++ ++ // I think we need to reverse the path ++ ++ AX25Sess->pathLen = strlen(path); ++ strcpy(AX25Sess->ReversePath, path); ++ reverse_addr(path, AX25Sess->Path, strlen(path)); ++ } ++ ++ // we process a packet on the necessary port ++ ++ memcpy(path, AX25Sess->Path, AX25Sess->pathLen); ++ ++ switch (f_id) ++ { ++ case I_I: ++ ++ on_I(socket, AX25Sess, pid, path, data, nr, ns, pf, cr, fecflag); ++ break; ++ ++ case S_RR: ++ ++ on_RR(AX25Sess, path, nr, pf, cr); ++ break; ++ ++ case S_RNR: ++ ++ on_RNR(AX25Sess, path, nr, pf, cr); ++ break; ++ ++ case S_REJ: ++ ++ on_REJ(AX25Sess, path, nr, pf, cr); ++ break; ++ ++ case S_SREJ: ++ ++ on_SREJ(AX25Sess, path, nr, pf, cr); ++ break; ++ ++ case U_SABM: ++ ++ on_SABM(socket, AX25Sess); ++ break; ++ ++ case U_DISC: ++ ++ on_DISC(AX25Sess); ++ break; ++ ++ case U_UA: ++ ++ on_UA(AX25Sess); ++ break; ++ ++ case U_DM: ++ ++ on_DM(AX25Sess); ++ break; ++ ++ case U_UI: ++ ++ on_UI(AX25Sess, pf, cr); ++ break; ++ ++ case U_FRMR: ++ ++ on_FRMR(socket, AX25Sess, path); ++ break; ++ } ++ freeString(data); ++} ++ ++int get_addr(char * Calls, UCHAR * AXCalls); ++ ++void Send_UI(int port, Byte PID, char * CallFrom, char *CallTo, char * via, Byte * Msg, int MsgLen) ++{ ++ char Addrs[256]; ++ Byte path[256]; ++ int destlen = 0; ++ ++ string * Data = newString(); ++ string * Frame; ++ ++ UCHAR KISSBuffer[512]; ++ int Length; ++ ++ stringAdd(Data, Msg, MsgLen); ++ ++ // We Need Dest, Source, Digis in path, with end of address bit set appropriately. ++ ++ sprintf(Addrs, "%s %s %s", CallTo, CallFrom, via); ++ ++ destlen = get_addr(Addrs, path); ++ ++ Frame = make_frame(Data, path, PID, 0, 0, U_FRM, U_UI, FALSE, SET_F, SET_C); ++ ++ // ? Don't we just send to TNC? ++ ++ Length = KISS_encode(KISSBuffer, port, Frame); ++ ++ KISSSendtoServer(KISSSockCopy[0], KISSBuffer, Length); ++ ++ monitor_frame(0, Frame, "", 1, 0); // Monitor ++ freeString(Frame); ++ ++} ++ ++ ++ ++ +--- qttermtcp-0.0.0.79.orig/debug/moc_predefs.h ++++ qttermtcp-0.0.0.79/debug/moc_predefs.h +@@ -1,12 +1,12 @@ +-#define _MSC_EXTENSIONS +-#define _INTEGRAL_MAX_BITS 64 +-#define _MSC_VER 1916 +-#define _MSC_FULL_VER 191627051 +-#define _MSC_BUILD 0 +-#define _WIN32 +-#define _M_IX86 600 +-#define _M_IX86_FP 2 +-#define _CPPRTTI +-#define _DEBUG +-#define _MT +-#define _DLL ++#define _MSC_EXTENSIONS ++#define _INTEGRAL_MAX_BITS 64 ++#define _MSC_VER 1916 ++#define _MSC_FULL_VER 191627051 ++#define _MSC_BUILD 0 ++#define _WIN32 ++#define _M_IX86 600 ++#define _M_IX86_FP 2 ++#define _CPPRTTI ++#define _DEBUG ++#define _MT ++#define _DLL +--- qttermtcp-0.0.0.79.orig/hid.c ++++ qttermtcp-0.0.0.79/hid.c +@@ -1,910 +1,910 @@ +-/******************************************************* +- HIDAPI - Multi-Platform library for +- communication with HID devices. +- +- Alan Ott +- Signal 11 Software +- +- 8/22/2009 +- +- Copyright 2009, All Rights Reserved. +- +- At the discretion of the user of this library, +- this software may be licensed under the terms of the +- GNU Public License v3, a BSD-Style license, or the +- original HIDAPI license as outlined in the LICENSE.txt, +- LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt +- files located at the root of the source distribution. +- These files may also be found in the public source +- code repository located at: +- http://github.com/signal11/hidapi . +-********************************************************/ +- +-// Hacked about a bit for BPQ32. John Wiseman G8BPQ April 2018 +- +- +- +-#include +- +-#ifndef _NTDEF_ +-typedef LONG NTSTATUS; +-#endif +- +-#ifdef __MINGW32__ +-#include +-#include +-#endif +- +-#ifdef __CYGWIN__ +-#include +-#define _wcsdup wcsdup +-#endif +- +-//#define HIDAPI_USE_DDK +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- #include +- #include +- #ifdef HIDAPI_USE_DDK +- #include +- #endif +- +- // Copied from inc/ddk/hidclass.h, part of the Windows DDK. +- #define HID_OUT_CTL_CODE(id) \ +- CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) +- #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) +- +-#ifdef __cplusplus +-} // extern "C" +-#endif +- +-#include +-#include +- +- +-#include "hidapi.h" +- +-#ifdef _MSC_VER +- // Thanks Microsoft, but I know how to use strncpy(). +- #pragma warning(disable:4996) +-#endif +- +-#ifdef __cplusplus +-extern "C" { +-#endif +- +-#ifndef HIDAPI_USE_DDK +- // Since we're not building with the DDK, and the HID header +- // files aren't part of the SDK, we have to define all this +- // stuff here. In lookup_functions(), the function pointers +- // defined below are set. +- typedef struct _HIDD_ATTRIBUTES{ +- ULONG Size; +- USHORT VendorID; +- USHORT ProductID; +- USHORT VersionNumber; +- } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; +- +- typedef USHORT USAGE; +- typedef struct _HIDP_CAPS { +- USAGE Usage; +- USAGE UsagePage; +- USHORT InputReportByteLength; +- USHORT OutputReportByteLength; +- USHORT FeatureReportByteLength; +- USHORT Reserved[17]; +- USHORT fields_not_used_by_hidapi[10]; +- } HIDP_CAPS, *PHIDP_CAPS; +- typedef char* HIDP_PREPARSED_DATA; +- #define HIDP_STATUS_SUCCESS 0x0 +- +- typedef BOOLEAN(__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib); +- typedef BOOLEAN(__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); +- typedef BOOLEAN(__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); +- typedef BOOLEAN(__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); +- typedef BOOLEAN(__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); +- typedef BOOLEAN(__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); +- typedef BOOLEAN(__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); +- typedef BOOLEAN(__stdcall *HidD_GetPreparsedData_)(HANDLE handle, HIDP_PREPARSED_DATA **preparsed_data); +- typedef BOOLEAN(__stdcall *HidD_FreePreparsedData_)(HIDP_PREPARSED_DATA *preparsed_data); +- typedef BOOLEAN(__stdcall *HidP_GetCaps_)(HIDP_PREPARSED_DATA *preparsed_data, HIDP_CAPS *caps); +- +- static HidD_GetAttributes_ HidD_GetAttributes; +- static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; +- static HidD_GetManufacturerString_ HidD_GetManufacturerString; +- static HidD_GetProductString_ HidD_GetProductString; +- static HidD_SetFeature_ HidD_SetFeature; +- static HidD_GetFeature_ HidD_GetFeature; +- static HidD_GetIndexedString_ HidD_GetIndexedString; +- static HidD_GetPreparsedData_ HidD_GetPreparsedData; +- static HidD_FreePreparsedData_ HidD_FreePreparsedData; +- static HidP_GetCaps_ HidP_GetCaps; +- +- static HMODULE lib_handle = NULL; +- static BOOLEAN initialized = FALSE; +-#endif // HIDAPI_USE_DDK +- +-struct hid_device_ { +- HANDLE device_handle; +- BOOLEAN blocking; +- int input_report_length; +- void *last_error_str; +- DWORD last_error_num; +- BOOLEAN read_pending; +- char *read_buf; +- OVERLAPPED ol; +-}; +- +-static hid_device *new_hid_device() +-{ +- hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); +- dev->device_handle = INVALID_HANDLE_VALUE; +- dev->blocking = TRUE; +- dev->input_report_length = 0; +- dev->last_error_str = NULL; +- dev->last_error_num = 0; +- dev->read_pending = FALSE; +- dev->read_buf = NULL; +- memset(&dev->ol, 0, sizeof(dev->ol)); +- dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL); +- +- return dev; +-} +- +- +-static void register_error(hid_device *device, const char *op) +-{ +- WCHAR *ptr, *msg; +- +- FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | +- FORMAT_MESSAGE_FROM_SYSTEM | +- FORMAT_MESSAGE_IGNORE_INSERTS, +- NULL, +- GetLastError(), +- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), +- (LPWSTR)&msg, 0/*sz*/, +- NULL); +- +- // Get rid of the CR and LF that FormatMessage() sticks at the +- // end of the message. Thanks Microsoft! +- ptr = msg; +- while (*ptr) { +- if (*ptr == '\r') { +- *ptr = 0x0000; +- break; +- } +- ptr++; +- } +- +- // Store the message off in the Device entry so that +- // the hid_error() function can pick it up. +- LocalFree(device->last_error_str); +- device->last_error_str = msg; +-} +- +-#ifndef HIDAPI_USE_DDK +-static int lookup_functions() +-{ +- lib_handle = LoadLibraryA("hid.dll"); +- if (lib_handle) { +-#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; +- RESOLVE(HidD_GetAttributes); +- RESOLVE(HidD_GetSerialNumberString); +- RESOLVE(HidD_GetManufacturerString); +- RESOLVE(HidD_GetProductString); +- RESOLVE(HidD_SetFeature); +- RESOLVE(HidD_GetFeature); +- RESOLVE(HidD_GetIndexedString); +- RESOLVE(HidD_GetPreparsedData); +- RESOLVE(HidD_FreePreparsedData); +- RESOLVE(HidP_GetCaps); +-#undef RESOLVE +- } +- else +- return -1; +- +- return 0; +-} +-#endif +- +-static HANDLE open_device(const char *path) +-{ +- HANDLE handle; +- +- /* First, try to open with sharing mode turned off. This will make it so +- that a HID device can only be opened once. This is to be consistent +- with the behavior on the other platforms. */ +- handle = CreateFileA(path, +- GENERIC_WRITE |GENERIC_READ, +- 0, /*share mode*/ +- NULL, +- OPEN_EXISTING, +- FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL, +- 0); +- +- if (handle == INVALID_HANDLE_VALUE) { +- /* Couldn't open the device. Some devices must be opened +- with sharing enabled (even though they are only opened once), +- so try it here. */ +- handle = CreateFileA(path, +- GENERIC_WRITE |GENERIC_READ, +- FILE_SHARE_READ|FILE_SHARE_WRITE, /*share mode*/ +- NULL, +- OPEN_EXISTING, +- FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL, +- 0); +- } +- +- return handle; +-} +- +-int HID_API_EXPORT hid_init(void) +-{ +-#ifndef HIDAPI_USE_DDK +- if (!initialized) { +- if (lookup_functions() < 0) { +- hid_exit(); +- return -1; +- } +- initialized = TRUE; +- } +-#endif +- return 0; +-} +- +-int HID_API_EXPORT hid_exit(void) +-{ +-#ifndef HIDAPI_USE_DDK +- if (lib_handle) +- FreeLibrary(lib_handle); +- lib_handle = NULL; +- initialized = FALSE; +-#endif +- return 0; +-} +- +-struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) +-{ +- BOOLEAN res; +- struct hid_device_info *root = NULL; // return object +- struct hid_device_info *cur_dev = NULL; +- +- // Windows objects for interacting with the driver. +- GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} }; +- SP_DEVINFO_DATA devinfo_data; +- SP_DEVICE_INTERFACE_DATA device_interface_data; +- SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL; +- HDEVINFO device_info_set = INVALID_HANDLE_VALUE; +- int device_index = 0; +- +- if (hid_init() < 0) +- return NULL; +- +- // Initialize the Windows objects. +- devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); +- device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); +- +- // Get information for all the devices belonging to the HID class. +- device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); +- +- // Iterate over each device in the HID class, looking for the right one. +- +- for (;;) { +- HANDLE write_handle = INVALID_HANDLE_VALUE; +- DWORD required_size = 0; +- HIDD_ATTRIBUTES attrib; +- +- res = SetupDiEnumDeviceInterfaces(device_info_set, +- NULL, +- &InterfaceClassGuid, +- device_index, +- &device_interface_data); +- +- if (!res) { +- // A return of FALSE from this function means that +- // there are no more devices. +- break; +- } +- +- // Call with 0-sized detail size, and let the function +- // tell us how long the detail struct needs to be. The +- // size is put in &required_size. +- res = SetupDiGetDeviceInterfaceDetailA(device_info_set, +- &device_interface_data, +- NULL, +- 0, +- &required_size, +- NULL); +- +- // Allocate a long enough structure for device_interface_detail_data. +- device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size); +- device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); +- +- // Get the detailed data for this device. The detail data gives us +- // the device path for this device, which is then passed into +- // CreateFile() to get a handle to the device. +- res = SetupDiGetDeviceInterfaceDetailA(device_info_set, +- &device_interface_data, +- device_interface_detail_data, +- required_size, +- NULL, +- NULL); +- +- if (!res) { +- //register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail"); +- // Continue to the next device. +- goto cont; +- } +- +- //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath); +- +- // Open a handle to the device +- write_handle = open_device(device_interface_detail_data->DevicePath); +- +- // Check validity of write_handle. +- if (write_handle == INVALID_HANDLE_VALUE) { +- // Unable to open the device. +- //register_error(dev, "CreateFile"); +- goto cont_close; +- } +- +- +- // Get the Vendor ID and Product ID for this device. +- attrib.Size = sizeof(HIDD_ATTRIBUTES); +- HidD_GetAttributes(write_handle, &attrib); +- //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID); +- +- // Check the VID/PID to see if we should add this +- // device to the enumeration list. +- if ((vendor_id == 0x0 && product_id == 0x0) || +- (attrib.VendorID == vendor_id && attrib.ProductID == product_id)) +- { +- #define WSTR_LEN 512 +- const char *str; +- struct hid_device_info *tmp; +- HIDP_PREPARSED_DATA *pp_data = NULL; +- HIDP_CAPS caps; +- BOOLEAN res; +- NTSTATUS nt_res; +- wchar_t wstr[WSTR_LEN]; // TODO: Determine Size +- int len; +- +- /* VID/PID match. Create the record. */ +- tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); +- if (cur_dev) { +- cur_dev->next = tmp; +- } +- else { +- root = tmp; +- } +- cur_dev = tmp; +- +- // Get the Usage Page and Usage for this device. +- res = HidD_GetPreparsedData(write_handle, &pp_data); +- if (res) { +- nt_res = HidP_GetCaps(pp_data, &caps); +- if (nt_res == HIDP_STATUS_SUCCESS) { +- cur_dev->usage_page = caps.UsagePage; +- cur_dev->usage = caps.Usage; +- } +- +- HidD_FreePreparsedData(pp_data); +- } +- +- /* Fill out the record */ +- cur_dev->next = NULL; +- str = device_interface_detail_data->DevicePath; +- if (str) { +- len = (int)strlen(str); +- cur_dev->path = (char*) calloc(len+1, sizeof(char)); +- strncpy(cur_dev->path, str, len+1); +- cur_dev->path[len] = '\0'; +- } +- else +- cur_dev->path = NULL; +- +- /* Serial Number */ +- res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr)); +- wstr[WSTR_LEN-1] = 0x0000; +- if (res) { +- cur_dev->serial_number = _wcsdup(wstr); +- } +- +- /* Manufacturer String */ +- res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr)); +- wstr[WSTR_LEN-1] = 0x0000; +- if (res) { +- cur_dev->manufacturer_string = _wcsdup(wstr); +- } +- +- /* Product String */ +- res = HidD_GetProductString(write_handle, wstr, sizeof(wstr)); +- wstr[WSTR_LEN-1] = 0x0000; +- if (res) { +- cur_dev->product_string = _wcsdup(wstr); +- } +- +- /* VID/PID */ +- cur_dev->vendor_id = attrib.VendorID; +- cur_dev->product_id = attrib.ProductID; +- +- /* Release Number */ +- cur_dev->release_number = attrib.VersionNumber; +- +- /* Interface Number. It can sometimes be parsed out of the path +- on Windows if a device has multiple interfaces. See +- http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or +- search for "Hardware IDs for HID Devices" at MSDN. If it's not +- in the path, it's set to -1. */ +- cur_dev->interface_number = -1; +- if (cur_dev->path) { +- char *interface_component = strstr(cur_dev->path, "&mi_"); +- if (interface_component) { +- char *hex_str = interface_component + 4; +- char *endptr = NULL; +- cur_dev->interface_number = strtol(hex_str, &endptr, 16); +- if (endptr == hex_str) { +- /* The parsing failed. Set interface_number to -1. */ +- cur_dev->interface_number = -1; +- } +- } +- } +- } +- +-cont_close: +- CloseHandle(write_handle); +-cont: +- // We no longer need the detail data. It can be freed +- free(device_interface_detail_data); +- +- device_index++; +- +- } +- +- // Close the device information handle. +- SetupDiDestroyDeviceInfoList(device_info_set); +- +- return root; +- +-} +- +-void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) +-{ +- // TODO: Merge this with the Linux version. This function is platform-independent. +- struct hid_device_info *d = devs; +- while (d) { +- struct hid_device_info *next = d->next; +- free(d->path); +- free(d->serial_number); +- free(d->manufacturer_string); +- free(d->product_string); +- free(d); +- d = next; +- } +-} +- +- +-HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number) +-{ +- // TODO: Merge this functions with the Linux version. This function should be platform independent. +- struct hid_device_info *devs, *cur_dev; +- const char *path_to_open = NULL; +- hid_device *handle = NULL; +- +- devs = hid_enumerate(vendor_id, product_id); +- cur_dev = devs; +- while (cur_dev) { +- if (cur_dev->vendor_id == vendor_id && +- cur_dev->product_id == product_id) { +- if (serial_number) { +- if (wcscmp(serial_number, cur_dev->serial_number) == 0) { +- path_to_open = cur_dev->path; +- break; +- } +- } +- else { +- path_to_open = cur_dev->path; +- break; +- } +- } +- cur_dev = cur_dev->next; +- } +- +- if (path_to_open) { +- /* Open the device */ +- handle = hid_open_path(path_to_open); +- } +- +- hid_free_enumeration(devs); +- +- return handle; +-} +- +-HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) +-{ +- hid_device *dev; +- HIDP_CAPS caps; +- HIDP_PREPARSED_DATA *pp_data = NULL; +- BOOLEAN res; +- NTSTATUS nt_res; +- +- if (hid_init() < 0) { +- return NULL; +- } +- +- dev = new_hid_device(); +- +- // Open a handle to the device +- dev->device_handle = open_device(path); +- +- // Check validity of write_handle. +- if (dev->device_handle == INVALID_HANDLE_VALUE) { +- // Unable to open the device. +- register_error(dev, "CreateFile"); +- goto err; +- } +- +- // Get the Input Report length for the device. +- res = HidD_GetPreparsedData(dev->device_handle, &pp_data); +- if (!res) { +- register_error(dev, "HidD_GetPreparsedData"); +- goto err; +- } +- nt_res = HidP_GetCaps(pp_data, &caps); +- if (nt_res != HIDP_STATUS_SUCCESS) { +- register_error(dev, "HidP_GetCaps"); +- goto err_pp_data; +- } +- dev->input_report_length = caps.InputReportByteLength; +- HidD_FreePreparsedData(pp_data); +- +- dev->read_buf = (char*) malloc(dev->input_report_length); +- +- return dev; +- +-err_pp_data: +- HidD_FreePreparsedData(pp_data); +-err: +- CloseHandle(dev->device_handle); +- free(dev); +- return NULL; +-} +- +-int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length) +-{ +- DWORD bytes_written; +- BOOLEAN res; +- +- OVERLAPPED ol; +- memset(&ol, 0, sizeof(ol)); +- +- res = WriteFile(dev->device_handle, data, length, NULL, &ol); +- +- if (!res) { +- if (GetLastError() != ERROR_IO_PENDING) { +- // WriteFile() failed. Return error. +- register_error(dev, "WriteFile"); +- return -1; +- } +- } +- +- // Wait here until the write is done. This makes +- // hid_write() synchronous. +- res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/); +- if (!res) { +- // The Write operation failed. +- register_error(dev, "WriteFile"); +- return -1; +- } +- +- return bytes_written; +-} +- +-int HID_API_EXPORT HID_API_CALL hid_set_ptt(int state) +-{ +- int res; +- hid_device *handle; +- unsigned char buf[16]; +- +- handle = hid_open(0xd8c, 0x8, NULL); +- if (!handle) { +- printf("unable to open device\n"); +- return 1; +- } +- +- +- // Toggle PTT +- +- buf[0] = 0; +- buf[1] = 0; +- buf[2]= 1 << (3 - 1); +- buf[3] = state << (3 - 1); +- buf[4] = 0; +- +- +- res = hid_write(handle, buf, 5); +- if (res < 0) +- { +- printf("Unable to write()\n"); +- printf("Error: %ls\n", hid_error(handle)); +- } +- +- hid_close(handle); +- return res; +-} +- +- +-int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) +-{ +- DWORD bytes_read = 0; +- BOOLEAN res; +- +- // Copy the handle for convenience. +- HANDLE ev = dev->ol.hEvent; +- +- if (!dev->read_pending) { +- // Start an Overlapped I/O read. +- dev->read_pending = TRUE; +- ResetEvent(ev); +- res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol); +- +- if (!res) { +- if (GetLastError() != ERROR_IO_PENDING) { +- // ReadFile() has failed. +- // Clean up and return error. +- CancelIo(dev->device_handle); +- dev->read_pending = FALSE; +- goto end_of_function; +- } +- } +- } +- +- if (milliseconds >= 0) { +- // See if there is any data yet. +- res = WaitForSingleObject(ev, milliseconds); +- if (res != WAIT_OBJECT_0) { +- // There was no data this time. Return zero bytes available, +- // but leave the Overlapped I/O running. +- return 0; +- } +- } +- +- // Either WaitForSingleObject() told us that ReadFile has completed, or +- // we are in non-blocking mode. Get the number of bytes read. The actual +- // data has been copied to the data[] array which was passed to ReadFile(). +- res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/); +- +- // Set pending back to false, even if GetOverlappedResult() returned error. +- dev->read_pending = FALSE; +- +- if (res && bytes_read > 0) { +- if (dev->read_buf[0] == 0x0) { +- /* If report numbers aren't being used, but Windows sticks a report +- number (0x0) on the beginning of the report anyway. To make this +- work like the other platforms, and to make it work more like the +- HID spec, we'll skip over this byte. */ +- bytes_read--; +- memcpy(data, dev->read_buf+1, length); +- } +- else { +- /* Copy the whole buffer, report number and all. */ +- memcpy(data, dev->read_buf, length); +- } +- } +- +-end_of_function: +- if (!res) { +- register_error(dev, "GetOverlappedResult"); +- return -1; +- } +- +- return bytes_read; +-} +- +-int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length) +-{ +- return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); +-} +- +-int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock) +-{ +- dev->blocking = !nonblock; +- return 0; /* Success */ +-} +- +-int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) +-{ +- BOOLEAN res = HidD_SetFeature(dev->device_handle, (PVOID)data, length); +- if (!res) { +- register_error(dev, "HidD_SetFeature"); +- return -1; +- } +- +- return length; +-} +- +- +-int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) +-{ +- BOOLEAN res; +-#if 0 +- res = HidD_GetFeature(dev->device_handle, data, length); +- if (!res) { +- register_error(dev, "HidD_GetFeature"); +- return -1; +- } +- return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */ +-#else +- DWORD bytes_returned; +- +- OVERLAPPED ol; +- memset(&ol, 0, sizeof(ol)); +- +- res = DeviceIoControl(dev->device_handle, +- IOCTL_HID_GET_FEATURE, +- data, length, +- data, length, +- &bytes_returned, &ol); +- +- if (!res) { +- if (GetLastError() != ERROR_IO_PENDING) { +- // DeviceIoControl() failed. Return error. +- register_error(dev, "Send Feature Report DeviceIoControl"); +- return -1; +- } +- } +- +- // Wait here until the write is done. This makes +- // hid_get_feature_report() synchronous. +- res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/); +- if (!res) { +- // The operation failed. +- register_error(dev, "Send Feature Report GetOverLappedResult"); +- return -1; +- } +- return bytes_returned; +-#endif +-} +- +-void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) +-{ +- if (!dev) +- return; +- CancelIo(dev->device_handle); +- CloseHandle(dev->ol.hEvent); +- CloseHandle(dev->device_handle); +- LocalFree(dev->last_error_str); +- free(dev->read_buf); +- free(dev); +-} +- +-int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) +-{ +- BOOLEAN res; +- +- res = HidD_GetManufacturerString(dev->device_handle, string, 2 * maxlen); +- if (!res) { +- register_error(dev, "HidD_GetManufacturerString"); +- return -1; +- } +- +- return 0; +-} +- +-int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) +-{ +- BOOLEAN res; +- +- res = HidD_GetProductString(dev->device_handle, string, 2 * maxlen); +- if (!res) { +- register_error(dev, "HidD_GetProductString"); +- return -1; +- } +- +- return 0; +-} +- +-int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) +-{ +- BOOLEAN res; +- +- res = HidD_GetSerialNumberString(dev->device_handle, string, 2 * maxlen); +- if (!res) { +- register_error(dev, "HidD_GetSerialNumberString"); +- return -1; +- } +- +- return 0; +-} +- +-int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) +-{ +- BOOLEAN res; +- +- res = HidD_GetIndexedString(dev->device_handle, string_index, string, 2 * maxlen); +- if (!res) { +- register_error(dev, "HidD_GetIndexedString"); +- return -1; +- } +- +- return 0; +-} +- +- +-HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) +-{ +- return (wchar_t*)dev->last_error_str; +-} +- +- +-//#define PICPGM +-//#define S11 +-#define P32 +-#ifdef S11 +- unsigned short VendorID = 0xa0a0; +- unsigned short ProductID = 0x0001; +-#endif +- +-#ifdef P32 +- unsigned short VendorID = 0x04d8; +- unsigned short ProductID = 0x3f; +-#endif +- +- +-#ifdef PICPGM +- unsigned short VendorID = 0x04d8; +- unsigned short ProductID = 0x0033; +-#endif +- +- +-#if 0 +-int __cdecl main(int argc, char* argv[]) +-{ +- int res; +- unsigned char buf[65]; +- +- UNREFERENCED_PARAMETER(argc); +- UNREFERENCED_PARAMETER(argv); +- +- // Set up the command buffer. +- memset(buf,0x00,sizeof(buf)); +- buf[0] = 0; +- buf[1] = 0x81; +- +- +- // Open the device. +- int handle = open(VendorID, ProductID, L"12345"); +- if (handle < 0) +- printf("unable to open device\n"); +- +- +- // Toggle LED (cmd 0x80) +- buf[1] = 0x80; +- res = write(handle, buf, 65); +- if (res < 0) +- printf("Unable to write()\n"); +- +- // Request state (cmd 0x81) +- buf[1] = 0x81; +- write(handle, buf, 65); +- if (res < 0) +- printf("Unable to write() (2)\n"); +- +- // Read requested state +- read(handle, buf, 65); +- if (res < 0) +- printf("Unable to read()\n"); +- +- // Print out the returned buffer. +- for (int i = 0; i < 4; i++) +- printf("buf[%d]: %d\n", i, buf[i]); +- +- return 0; +-} +-#endif +- +-#ifdef __cplusplus +-} // extern "C" +-#endif ++/******************************************************* ++ HIDAPI - Multi-Platform library for ++ communication with HID devices. ++ ++ Alan Ott ++ Signal 11 Software ++ ++ 8/22/2009 ++ ++ Copyright 2009, All Rights Reserved. ++ ++ At the discretion of the user of this library, ++ this software may be licensed under the terms of the ++ GNU Public License v3, a BSD-Style license, or the ++ original HIDAPI license as outlined in the LICENSE.txt, ++ LICENSE-gpl3.txt, LICENSE-bsd.txt, and LICENSE-orig.txt ++ files located at the root of the source distribution. ++ These files may also be found in the public source ++ code repository located at: ++ http://github.com/signal11/hidapi . ++********************************************************/ ++ ++// Hacked about a bit for BPQ32. John Wiseman G8BPQ April 2018 ++ ++ ++ ++#include ++ ++#ifndef _NTDEF_ ++typedef LONG NTSTATUS; ++#endif ++ ++#ifdef __MINGW32__ ++#include ++#include ++#endif ++ ++#ifdef __CYGWIN__ ++#include ++#define _wcsdup wcsdup ++#endif ++ ++//#define HIDAPI_USE_DDK ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ #include ++ #include ++ #ifdef HIDAPI_USE_DDK ++ #include ++ #endif ++ ++ // Copied from inc/ddk/hidclass.h, part of the Windows DDK. ++ #define HID_OUT_CTL_CODE(id) \ ++ CTL_CODE(FILE_DEVICE_KEYBOARD, (id), METHOD_OUT_DIRECT, FILE_ANY_ACCESS) ++ #define IOCTL_HID_GET_FEATURE HID_OUT_CTL_CODE(100) ++ ++#ifdef __cplusplus ++} // extern "C" ++#endif ++ ++#include ++#include ++ ++ ++#include "hidapi.h" ++ ++#ifdef _MSC_VER ++ // Thanks Microsoft, but I know how to use strncpy(). ++ #pragma warning(disable:4996) ++#endif ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#ifndef HIDAPI_USE_DDK ++ // Since we're not building with the DDK, and the HID header ++ // files aren't part of the SDK, we have to define all this ++ // stuff here. In lookup_functions(), the function pointers ++ // defined below are set. ++ typedef struct _HIDD_ATTRIBUTES{ ++ ULONG Size; ++ USHORT VendorID; ++ USHORT ProductID; ++ USHORT VersionNumber; ++ } HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES; ++ ++ typedef USHORT USAGE; ++ typedef struct _HIDP_CAPS { ++ USAGE Usage; ++ USAGE UsagePage; ++ USHORT InputReportByteLength; ++ USHORT OutputReportByteLength; ++ USHORT FeatureReportByteLength; ++ USHORT Reserved[17]; ++ USHORT fields_not_used_by_hidapi[10]; ++ } HIDP_CAPS, *PHIDP_CAPS; ++ typedef char* HIDP_PREPARSED_DATA; ++ #define HIDP_STATUS_SUCCESS 0x0 ++ ++ typedef BOOLEAN(__stdcall *HidD_GetAttributes_)(HANDLE device, PHIDD_ATTRIBUTES attrib); ++ typedef BOOLEAN(__stdcall *HidD_GetSerialNumberString_)(HANDLE device, PVOID buffer, ULONG buffer_len); ++ typedef BOOLEAN(__stdcall *HidD_GetManufacturerString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); ++ typedef BOOLEAN(__stdcall *HidD_GetProductString_)(HANDLE handle, PVOID buffer, ULONG buffer_len); ++ typedef BOOLEAN(__stdcall *HidD_SetFeature_)(HANDLE handle, PVOID data, ULONG length); ++ typedef BOOLEAN(__stdcall *HidD_GetFeature_)(HANDLE handle, PVOID data, ULONG length); ++ typedef BOOLEAN(__stdcall *HidD_GetIndexedString_)(HANDLE handle, ULONG string_index, PVOID buffer, ULONG buffer_len); ++ typedef BOOLEAN(__stdcall *HidD_GetPreparsedData_)(HANDLE handle, HIDP_PREPARSED_DATA **preparsed_data); ++ typedef BOOLEAN(__stdcall *HidD_FreePreparsedData_)(HIDP_PREPARSED_DATA *preparsed_data); ++ typedef BOOLEAN(__stdcall *HidP_GetCaps_)(HIDP_PREPARSED_DATA *preparsed_data, HIDP_CAPS *caps); ++ ++ static HidD_GetAttributes_ HidD_GetAttributes; ++ static HidD_GetSerialNumberString_ HidD_GetSerialNumberString; ++ static HidD_GetManufacturerString_ HidD_GetManufacturerString; ++ static HidD_GetProductString_ HidD_GetProductString; ++ static HidD_SetFeature_ HidD_SetFeature; ++ static HidD_GetFeature_ HidD_GetFeature; ++ static HidD_GetIndexedString_ HidD_GetIndexedString; ++ static HidD_GetPreparsedData_ HidD_GetPreparsedData; ++ static HidD_FreePreparsedData_ HidD_FreePreparsedData; ++ static HidP_GetCaps_ HidP_GetCaps; ++ ++ static HMODULE lib_handle = NULL; ++ static BOOLEAN initialized = FALSE; ++#endif // HIDAPI_USE_DDK ++ ++struct hid_device_ { ++ HANDLE device_handle; ++ BOOLEAN blocking; ++ int input_report_length; ++ void *last_error_str; ++ DWORD last_error_num; ++ BOOLEAN read_pending; ++ char *read_buf; ++ OVERLAPPED ol; ++}; ++ ++static hid_device *new_hid_device() ++{ ++ hid_device *dev = (hid_device*) calloc(1, sizeof(hid_device)); ++ dev->device_handle = INVALID_HANDLE_VALUE; ++ dev->blocking = TRUE; ++ dev->input_report_length = 0; ++ dev->last_error_str = NULL; ++ dev->last_error_num = 0; ++ dev->read_pending = FALSE; ++ dev->read_buf = NULL; ++ memset(&dev->ol, 0, sizeof(dev->ol)); ++ dev->ol.hEvent = CreateEvent(NULL, FALSE, FALSE /*inital state f=nonsignaled*/, NULL); ++ ++ return dev; ++} ++ ++ ++static void register_error(hid_device *device, const char *op) ++{ ++ WCHAR *ptr, *msg; ++ ++ FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | ++ FORMAT_MESSAGE_FROM_SYSTEM | ++ FORMAT_MESSAGE_IGNORE_INSERTS, ++ NULL, ++ GetLastError(), ++ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), ++ (LPWSTR)&msg, 0/*sz*/, ++ NULL); ++ ++ // Get rid of the CR and LF that FormatMessage() sticks at the ++ // end of the message. Thanks Microsoft! ++ ptr = msg; ++ while (*ptr) { ++ if (*ptr == '\r') { ++ *ptr = 0x0000; ++ break; ++ } ++ ptr++; ++ } ++ ++ // Store the message off in the Device entry so that ++ // the hid_error() function can pick it up. ++ LocalFree(device->last_error_str); ++ device->last_error_str = msg; ++} ++ ++#ifndef HIDAPI_USE_DDK ++static int lookup_functions() ++{ ++ lib_handle = LoadLibraryA("hid.dll"); ++ if (lib_handle) { ++#define RESOLVE(x) x = (x##_)GetProcAddress(lib_handle, #x); if (!x) return -1; ++ RESOLVE(HidD_GetAttributes); ++ RESOLVE(HidD_GetSerialNumberString); ++ RESOLVE(HidD_GetManufacturerString); ++ RESOLVE(HidD_GetProductString); ++ RESOLVE(HidD_SetFeature); ++ RESOLVE(HidD_GetFeature); ++ RESOLVE(HidD_GetIndexedString); ++ RESOLVE(HidD_GetPreparsedData); ++ RESOLVE(HidD_FreePreparsedData); ++ RESOLVE(HidP_GetCaps); ++#undef RESOLVE ++ } ++ else ++ return -1; ++ ++ return 0; ++} ++#endif ++ ++static HANDLE open_device(const char *path) ++{ ++ HANDLE handle; ++ ++ /* First, try to open with sharing mode turned off. This will make it so ++ that a HID device can only be opened once. This is to be consistent ++ with the behavior on the other platforms. */ ++ handle = CreateFileA(path, ++ GENERIC_WRITE |GENERIC_READ, ++ 0, /*share mode*/ ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL, ++ 0); ++ ++ if (handle == INVALID_HANDLE_VALUE) { ++ /* Couldn't open the device. Some devices must be opened ++ with sharing enabled (even though they are only opened once), ++ so try it here. */ ++ handle = CreateFileA(path, ++ GENERIC_WRITE |GENERIC_READ, ++ FILE_SHARE_READ|FILE_SHARE_WRITE, /*share mode*/ ++ NULL, ++ OPEN_EXISTING, ++ FILE_FLAG_OVERLAPPED,//FILE_ATTRIBUTE_NORMAL, ++ 0); ++ } ++ ++ return handle; ++} ++ ++int HID_API_EXPORT hid_init(void) ++{ ++#ifndef HIDAPI_USE_DDK ++ if (!initialized) { ++ if (lookup_functions() < 0) { ++ hid_exit(); ++ return -1; ++ } ++ initialized = TRUE; ++ } ++#endif ++ return 0; ++} ++ ++int HID_API_EXPORT hid_exit(void) ++{ ++#ifndef HIDAPI_USE_DDK ++ if (lib_handle) ++ FreeLibrary(lib_handle); ++ lib_handle = NULL; ++ initialized = FALSE; ++#endif ++ return 0; ++} ++ ++struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id) ++{ ++ BOOLEAN res; ++ struct hid_device_info *root = NULL; // return object ++ struct hid_device_info *cur_dev = NULL; ++ ++ // Windows objects for interacting with the driver. ++ GUID InterfaceClassGuid = {0x4d1e55b2, 0xf16f, 0x11cf, {0x88, 0xcb, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30} }; ++ SP_DEVINFO_DATA devinfo_data; ++ SP_DEVICE_INTERFACE_DATA device_interface_data; ++ SP_DEVICE_INTERFACE_DETAIL_DATA_A *device_interface_detail_data = NULL; ++ HDEVINFO device_info_set = INVALID_HANDLE_VALUE; ++ int device_index = 0; ++ ++ if (hid_init() < 0) ++ return NULL; ++ ++ // Initialize the Windows objects. ++ devinfo_data.cbSize = sizeof(SP_DEVINFO_DATA); ++ device_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); ++ ++ // Get information for all the devices belonging to the HID class. ++ device_info_set = SetupDiGetClassDevsA(&InterfaceClassGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); ++ ++ // Iterate over each device in the HID class, looking for the right one. ++ ++ for (;;) { ++ HANDLE write_handle = INVALID_HANDLE_VALUE; ++ DWORD required_size = 0; ++ HIDD_ATTRIBUTES attrib; ++ ++ res = SetupDiEnumDeviceInterfaces(device_info_set, ++ NULL, ++ &InterfaceClassGuid, ++ device_index, ++ &device_interface_data); ++ ++ if (!res) { ++ // A return of FALSE from this function means that ++ // there are no more devices. ++ break; ++ } ++ ++ // Call with 0-sized detail size, and let the function ++ // tell us how long the detail struct needs to be. The ++ // size is put in &required_size. ++ res = SetupDiGetDeviceInterfaceDetailA(device_info_set, ++ &device_interface_data, ++ NULL, ++ 0, ++ &required_size, ++ NULL); ++ ++ // Allocate a long enough structure for device_interface_detail_data. ++ device_interface_detail_data = (SP_DEVICE_INTERFACE_DETAIL_DATA_A*) malloc(required_size); ++ device_interface_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); ++ ++ // Get the detailed data for this device. The detail data gives us ++ // the device path for this device, which is then passed into ++ // CreateFile() to get a handle to the device. ++ res = SetupDiGetDeviceInterfaceDetailA(device_info_set, ++ &device_interface_data, ++ device_interface_detail_data, ++ required_size, ++ NULL, ++ NULL); ++ ++ if (!res) { ++ //register_error(dev, "Unable to call SetupDiGetDeviceInterfaceDetail"); ++ // Continue to the next device. ++ goto cont; ++ } ++ ++ //wprintf(L"HandleName: %s\n", device_interface_detail_data->DevicePath); ++ ++ // Open a handle to the device ++ write_handle = open_device(device_interface_detail_data->DevicePath); ++ ++ // Check validity of write_handle. ++ if (write_handle == INVALID_HANDLE_VALUE) { ++ // Unable to open the device. ++ //register_error(dev, "CreateFile"); ++ goto cont_close; ++ } ++ ++ ++ // Get the Vendor ID and Product ID for this device. ++ attrib.Size = sizeof(HIDD_ATTRIBUTES); ++ HidD_GetAttributes(write_handle, &attrib); ++ //wprintf(L"Product/Vendor: %x %x\n", attrib.ProductID, attrib.VendorID); ++ ++ // Check the VID/PID to see if we should add this ++ // device to the enumeration list. ++ if ((vendor_id == 0x0 && product_id == 0x0) || ++ (attrib.VendorID == vendor_id && attrib.ProductID == product_id)) ++ { ++ #define WSTR_LEN 512 ++ const char *str; ++ struct hid_device_info *tmp; ++ HIDP_PREPARSED_DATA *pp_data = NULL; ++ HIDP_CAPS caps; ++ BOOLEAN res; ++ NTSTATUS nt_res; ++ wchar_t wstr[WSTR_LEN]; // TODO: Determine Size ++ int len; ++ ++ /* VID/PID match. Create the record. */ ++ tmp = (struct hid_device_info*) calloc(1, sizeof(struct hid_device_info)); ++ if (cur_dev) { ++ cur_dev->next = tmp; ++ } ++ else { ++ root = tmp; ++ } ++ cur_dev = tmp; ++ ++ // Get the Usage Page and Usage for this device. ++ res = HidD_GetPreparsedData(write_handle, &pp_data); ++ if (res) { ++ nt_res = HidP_GetCaps(pp_data, &caps); ++ if (nt_res == HIDP_STATUS_SUCCESS) { ++ cur_dev->usage_page = caps.UsagePage; ++ cur_dev->usage = caps.Usage; ++ } ++ ++ HidD_FreePreparsedData(pp_data); ++ } ++ ++ /* Fill out the record */ ++ cur_dev->next = NULL; ++ str = device_interface_detail_data->DevicePath; ++ if (str) { ++ len = (int)strlen(str); ++ cur_dev->path = (char*) calloc(len+1, sizeof(char)); ++ strncpy(cur_dev->path, str, len+1); ++ cur_dev->path[len] = '\0'; ++ } ++ else ++ cur_dev->path = NULL; ++ ++ /* Serial Number */ ++ res = HidD_GetSerialNumberString(write_handle, wstr, sizeof(wstr)); ++ wstr[WSTR_LEN-1] = 0x0000; ++ if (res) { ++ cur_dev->serial_number = _wcsdup(wstr); ++ } ++ ++ /* Manufacturer String */ ++ res = HidD_GetManufacturerString(write_handle, wstr, sizeof(wstr)); ++ wstr[WSTR_LEN-1] = 0x0000; ++ if (res) { ++ cur_dev->manufacturer_string = _wcsdup(wstr); ++ } ++ ++ /* Product String */ ++ res = HidD_GetProductString(write_handle, wstr, sizeof(wstr)); ++ wstr[WSTR_LEN-1] = 0x0000; ++ if (res) { ++ cur_dev->product_string = _wcsdup(wstr); ++ } ++ ++ /* VID/PID */ ++ cur_dev->vendor_id = attrib.VendorID; ++ cur_dev->product_id = attrib.ProductID; ++ ++ /* Release Number */ ++ cur_dev->release_number = attrib.VersionNumber; ++ ++ /* Interface Number. It can sometimes be parsed out of the path ++ on Windows if a device has multiple interfaces. See ++ http://msdn.microsoft.com/en-us/windows/hardware/gg487473 or ++ search for "Hardware IDs for HID Devices" at MSDN. If it's not ++ in the path, it's set to -1. */ ++ cur_dev->interface_number = -1; ++ if (cur_dev->path) { ++ char *interface_component = strstr(cur_dev->path, "&mi_"); ++ if (interface_component) { ++ char *hex_str = interface_component + 4; ++ char *endptr = NULL; ++ cur_dev->interface_number = strtol(hex_str, &endptr, 16); ++ if (endptr == hex_str) { ++ /* The parsing failed. Set interface_number to -1. */ ++ cur_dev->interface_number = -1; ++ } ++ } ++ } ++ } ++ ++cont_close: ++ CloseHandle(write_handle); ++cont: ++ // We no longer need the detail data. It can be freed ++ free(device_interface_detail_data); ++ ++ device_index++; ++ ++ } ++ ++ // Close the device information handle. ++ SetupDiDestroyDeviceInfoList(device_info_set); ++ ++ return root; ++ ++} ++ ++void HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs) ++{ ++ // TODO: Merge this with the Linux version. This function is platform-independent. ++ struct hid_device_info *d = devs; ++ while (d) { ++ struct hid_device_info *next = d->next; ++ free(d->path); ++ free(d->serial_number); ++ free(d->manufacturer_string); ++ free(d->product_string); ++ free(d); ++ d = next; ++ } ++} ++ ++ ++HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, wchar_t *serial_number) ++{ ++ // TODO: Merge this functions with the Linux version. This function should be platform independent. ++ struct hid_device_info *devs, *cur_dev; ++ const char *path_to_open = NULL; ++ hid_device *handle = NULL; ++ ++ devs = hid_enumerate(vendor_id, product_id); ++ cur_dev = devs; ++ while (cur_dev) { ++ if (cur_dev->vendor_id == vendor_id && ++ cur_dev->product_id == product_id) { ++ if (serial_number) { ++ if (wcscmp(serial_number, cur_dev->serial_number) == 0) { ++ path_to_open = cur_dev->path; ++ break; ++ } ++ } ++ else { ++ path_to_open = cur_dev->path; ++ break; ++ } ++ } ++ cur_dev = cur_dev->next; ++ } ++ ++ if (path_to_open) { ++ /* Open the device */ ++ handle = hid_open_path(path_to_open); ++ } ++ ++ hid_free_enumeration(devs); ++ ++ return handle; ++} ++ ++HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path) ++{ ++ hid_device *dev; ++ HIDP_CAPS caps; ++ HIDP_PREPARSED_DATA *pp_data = NULL; ++ BOOLEAN res; ++ NTSTATUS nt_res; ++ ++ if (hid_init() < 0) { ++ return NULL; ++ } ++ ++ dev = new_hid_device(); ++ ++ // Open a handle to the device ++ dev->device_handle = open_device(path); ++ ++ // Check validity of write_handle. ++ if (dev->device_handle == INVALID_HANDLE_VALUE) { ++ // Unable to open the device. ++ register_error(dev, "CreateFile"); ++ goto err; ++ } ++ ++ // Get the Input Report length for the device. ++ res = HidD_GetPreparsedData(dev->device_handle, &pp_data); ++ if (!res) { ++ register_error(dev, "HidD_GetPreparsedData"); ++ goto err; ++ } ++ nt_res = HidP_GetCaps(pp_data, &caps); ++ if (nt_res != HIDP_STATUS_SUCCESS) { ++ register_error(dev, "HidP_GetCaps"); ++ goto err_pp_data; ++ } ++ dev->input_report_length = caps.InputReportByteLength; ++ HidD_FreePreparsedData(pp_data); ++ ++ dev->read_buf = (char*) malloc(dev->input_report_length); ++ ++ return dev; ++ ++err_pp_data: ++ HidD_FreePreparsedData(pp_data); ++err: ++ CloseHandle(dev->device_handle); ++ free(dev); ++ return NULL; ++} ++ ++int HID_API_EXPORT HID_API_CALL hid_write(hid_device *dev, const unsigned char *data, size_t length) ++{ ++ DWORD bytes_written; ++ BOOLEAN res; ++ ++ OVERLAPPED ol; ++ memset(&ol, 0, sizeof(ol)); ++ ++ res = WriteFile(dev->device_handle, data, length, NULL, &ol); ++ ++ if (!res) { ++ if (GetLastError() != ERROR_IO_PENDING) { ++ // WriteFile() failed. Return error. ++ register_error(dev, "WriteFile"); ++ return -1; ++ } ++ } ++ ++ // Wait here until the write is done. This makes ++ // hid_write() synchronous. ++ res = GetOverlappedResult(dev->device_handle, &ol, &bytes_written, TRUE/*wait*/); ++ if (!res) { ++ // The Write operation failed. ++ register_error(dev, "WriteFile"); ++ return -1; ++ } ++ ++ return bytes_written; ++} ++ ++int HID_API_EXPORT HID_API_CALL hid_set_ptt(int state) ++{ ++ int res; ++ hid_device *handle; ++ unsigned char buf[16]; ++ ++ handle = hid_open(0xd8c, 0x8, NULL); ++ if (!handle) { ++ printf("unable to open device\n"); ++ return 1; ++ } ++ ++ ++ // Toggle PTT ++ ++ buf[0] = 0; ++ buf[1] = 0; ++ buf[2]= 1 << (3 - 1); ++ buf[3] = state << (3 - 1); ++ buf[4] = 0; ++ ++ ++ res = hid_write(handle, buf, 5); ++ if (res < 0) ++ { ++ printf("Unable to write()\n"); ++ printf("Error: %ls\n", hid_error(handle)); ++ } ++ ++ hid_close(handle); ++ return res; ++} ++ ++ ++int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *dev, unsigned char *data, size_t length, int milliseconds) ++{ ++ DWORD bytes_read = 0; ++ BOOLEAN res; ++ ++ // Copy the handle for convenience. ++ HANDLE ev = dev->ol.hEvent; ++ ++ if (!dev->read_pending) { ++ // Start an Overlapped I/O read. ++ dev->read_pending = TRUE; ++ ResetEvent(ev); ++ res = ReadFile(dev->device_handle, dev->read_buf, dev->input_report_length, &bytes_read, &dev->ol); ++ ++ if (!res) { ++ if (GetLastError() != ERROR_IO_PENDING) { ++ // ReadFile() has failed. ++ // Clean up and return error. ++ CancelIo(dev->device_handle); ++ dev->read_pending = FALSE; ++ goto end_of_function; ++ } ++ } ++ } ++ ++ if (milliseconds >= 0) { ++ // See if there is any data yet. ++ res = WaitForSingleObject(ev, milliseconds); ++ if (res != WAIT_OBJECT_0) { ++ // There was no data this time. Return zero bytes available, ++ // but leave the Overlapped I/O running. ++ return 0; ++ } ++ } ++ ++ // Either WaitForSingleObject() told us that ReadFile has completed, or ++ // we are in non-blocking mode. Get the number of bytes read. The actual ++ // data has been copied to the data[] array which was passed to ReadFile(). ++ res = GetOverlappedResult(dev->device_handle, &dev->ol, &bytes_read, TRUE/*wait*/); ++ ++ // Set pending back to false, even if GetOverlappedResult() returned error. ++ dev->read_pending = FALSE; ++ ++ if (res && bytes_read > 0) { ++ if (dev->read_buf[0] == 0x0) { ++ /* If report numbers aren't being used, but Windows sticks a report ++ number (0x0) on the beginning of the report anyway. To make this ++ work like the other platforms, and to make it work more like the ++ HID spec, we'll skip over this byte. */ ++ bytes_read--; ++ memcpy(data, dev->read_buf+1, length); ++ } ++ else { ++ /* Copy the whole buffer, report number and all. */ ++ memcpy(data, dev->read_buf, length); ++ } ++ } ++ ++end_of_function: ++ if (!res) { ++ register_error(dev, "GetOverlappedResult"); ++ return -1; ++ } ++ ++ return bytes_read; ++} ++ ++int HID_API_EXPORT HID_API_CALL hid_read(hid_device *dev, unsigned char *data, size_t length) ++{ ++ return hid_read_timeout(dev, data, length, (dev->blocking)? -1: 0); ++} ++ ++int HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *dev, int nonblock) ++{ ++ dev->blocking = !nonblock; ++ return 0; /* Success */ ++} ++ ++int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *dev, const unsigned char *data, size_t length) ++{ ++ BOOLEAN res = HidD_SetFeature(dev->device_handle, (PVOID)data, length); ++ if (!res) { ++ register_error(dev, "HidD_SetFeature"); ++ return -1; ++ } ++ ++ return length; ++} ++ ++ ++int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *dev, unsigned char *data, size_t length) ++{ ++ BOOLEAN res; ++#if 0 ++ res = HidD_GetFeature(dev->device_handle, data, length); ++ if (!res) { ++ register_error(dev, "HidD_GetFeature"); ++ return -1; ++ } ++ return 0; /* HidD_GetFeature() doesn't give us an actual length, unfortunately */ ++#else ++ DWORD bytes_returned; ++ ++ OVERLAPPED ol; ++ memset(&ol, 0, sizeof(ol)); ++ ++ res = DeviceIoControl(dev->device_handle, ++ IOCTL_HID_GET_FEATURE, ++ data, length, ++ data, length, ++ &bytes_returned, &ol); ++ ++ if (!res) { ++ if (GetLastError() != ERROR_IO_PENDING) { ++ // DeviceIoControl() failed. Return error. ++ register_error(dev, "Send Feature Report DeviceIoControl"); ++ return -1; ++ } ++ } ++ ++ // Wait here until the write is done. This makes ++ // hid_get_feature_report() synchronous. ++ res = GetOverlappedResult(dev->device_handle, &ol, &bytes_returned, TRUE/*wait*/); ++ if (!res) { ++ // The operation failed. ++ register_error(dev, "Send Feature Report GetOverLappedResult"); ++ return -1; ++ } ++ return bytes_returned; ++#endif ++} ++ ++void HID_API_EXPORT HID_API_CALL hid_close(hid_device *dev) ++{ ++ if (!dev) ++ return; ++ CancelIo(dev->device_handle); ++ CloseHandle(dev->ol.hEvent); ++ CloseHandle(dev->device_handle); ++ LocalFree(dev->last_error_str); ++ free(dev->read_buf); ++ free(dev); ++} ++ ++int HID_API_EXPORT_CALL HID_API_CALL hid_get_manufacturer_string(hid_device *dev, wchar_t *string, size_t maxlen) ++{ ++ BOOLEAN res; ++ ++ res = HidD_GetManufacturerString(dev->device_handle, string, 2 * maxlen); ++ if (!res) { ++ register_error(dev, "HidD_GetManufacturerString"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int HID_API_EXPORT_CALL HID_API_CALL hid_get_product_string(hid_device *dev, wchar_t *string, size_t maxlen) ++{ ++ BOOLEAN res; ++ ++ res = HidD_GetProductString(dev->device_handle, string, 2 * maxlen); ++ if (!res) { ++ register_error(dev, "HidD_GetProductString"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int HID_API_EXPORT_CALL HID_API_CALL hid_get_serial_number_string(hid_device *dev, wchar_t *string, size_t maxlen) ++{ ++ BOOLEAN res; ++ ++ res = HidD_GetSerialNumberString(dev->device_handle, string, 2 * maxlen); ++ if (!res) { ++ register_error(dev, "HidD_GetSerialNumberString"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++int HID_API_EXPORT_CALL HID_API_CALL hid_get_indexed_string(hid_device *dev, int string_index, wchar_t *string, size_t maxlen) ++{ ++ BOOLEAN res; ++ ++ res = HidD_GetIndexedString(dev->device_handle, string_index, string, 2 * maxlen); ++ if (!res) { ++ register_error(dev, "HidD_GetIndexedString"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++ ++HID_API_EXPORT const wchar_t * HID_API_CALL hid_error(hid_device *dev) ++{ ++ return (wchar_t*)dev->last_error_str; ++} ++ ++ ++//#define PICPGM ++//#define S11 ++#define P32 ++#ifdef S11 ++ unsigned short VendorID = 0xa0a0; ++ unsigned short ProductID = 0x0001; ++#endif ++ ++#ifdef P32 ++ unsigned short VendorID = 0x04d8; ++ unsigned short ProductID = 0x3f; ++#endif ++ ++ ++#ifdef PICPGM ++ unsigned short VendorID = 0x04d8; ++ unsigned short ProductID = 0x0033; ++#endif ++ ++ ++#if 0 ++int __cdecl main(int argc, char* argv[]) ++{ ++ int res; ++ unsigned char buf[65]; ++ ++ UNREFERENCED_PARAMETER(argc); ++ UNREFERENCED_PARAMETER(argv); ++ ++ // Set up the command buffer. ++ memset(buf,0x00,sizeof(buf)); ++ buf[0] = 0; ++ buf[1] = 0x81; ++ ++ ++ // Open the device. ++ int handle = open(VendorID, ProductID, L"12345"); ++ if (handle < 0) ++ printf("unable to open device\n"); ++ ++ ++ // Toggle LED (cmd 0x80) ++ buf[1] = 0x80; ++ res = write(handle, buf, 65); ++ if (res < 0) ++ printf("Unable to write()\n"); ++ ++ // Request state (cmd 0x81) ++ buf[1] = 0x81; ++ write(handle, buf, 65); ++ if (res < 0) ++ printf("Unable to write() (2)\n"); ++ ++ // Read requested state ++ read(handle, buf, 65); ++ if (res < 0) ++ printf("Unable to read()\n"); ++ ++ // Print out the returned buffer. ++ for (int i = 0; i < 4; i++) ++ printf("buf[%d]: %d\n", i, buf[i]); ++ ++ return 0; ++} ++#endif ++ ++#ifdef __cplusplus ++} // extern "C" ++#endif +--- qttermtcp-0.0.0.79.orig/main.cpp ++++ qttermtcp-0.0.0.79/main.cpp +@@ -1,26 +1,26 @@ +-#include "QtTermTCP.h" +-#include +-#include +- +-QApplication * a; +- +-int screenHeight = 0; // used to control dialog sizes on Android +-int screenWidth = 0; +- +-int main(int argc, char *argv[]) +-{ +- a = new QApplication (argc, argv); +- +- QSize r = a->screens()[0]->size(); +- +- screenHeight = r.height(); +- screenWidth = r.width(); +- +- QtTermTCP w; +- +-//#ifdef ANDROID +-// w.setWindowFlags(Qt::Window | Qt::CustomizeWindowHint); // Qt::FramelessWindowHint); +-//#endif +- w.show(); +- return a->exec(); +-} ++#include "QtTermTCP.h" ++#include ++#include ++ ++QApplication * a; ++ ++int screenHeight = 0; // used to control dialog sizes on Android ++int screenWidth = 0; ++ ++int main(int argc, char *argv[]) ++{ ++ a = new QApplication (argc, argv); ++ ++ QSize r = a->screens()[0]->size(); ++ ++ screenHeight = r.height(); ++ screenWidth = r.width(); ++ ++ QtTermTCP w; ++ ++//#ifdef ANDROID ++// w.setWindowFlags(Qt::Window | Qt::CustomizeWindowHint); // Qt::FramelessWindowHint); ++//#endif ++ w.show(); ++ return a->exec(); ++} +--- qttermtcp-0.0.0.79.orig/release/moc_predefs.h ++++ qttermtcp-0.0.0.79/release/moc_predefs.h +@@ -1,11 +1,11 @@ +-#define _MSC_EXTENSIONS +-#define _INTEGRAL_MAX_BITS 64 +-#define _MSC_VER 1916 +-#define _MSC_FULL_VER 191627051 +-#define _MSC_BUILD 0 +-#define _WIN32 +-#define _M_IX86 600 +-#define _M_IX86_FP 2 +-#define _CPPRTTI +-#define _MT +-#define _DLL ++#define _MSC_EXTENSIONS ++#define _INTEGRAL_MAX_BITS 64 ++#define _MSC_VER 1916 ++#define _MSC_FULL_VER 191627051 ++#define _MSC_BUILD 0 ++#define _WIN32 ++#define _M_IX86 600 ++#define _M_IX86_FP 2 ++#define _CPPRTTI ++#define _MT ++#define _DLL +--- qttermtcp-0.0.0.79.orig/utf8Routines.cpp ++++ qttermtcp-0.0.0.79/utf8Routines.cpp +@@ -1,597 +1,597 @@ +-/* +-Copyright 2001-2018 John Wiseman G8BPQ +- +-This file is part of LinBPQ/BPQ32. +- +-LinBPQ/BPQ32 is free software: you can redistribute it and/or modify +-it under the terms of the GNU General Public License as published by +-the Free Software Foundation, either version 3 of the License, or +-(at your option) any later version. +- +-LinBPQ/BPQ32 is distributed in the hope that it will be useful, +-but WITHOUT ANY WARRANTY; without even the implied warranty of +-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +-GNU General Public License for more details. +- +-You should have received a copy of the GNU General Public License +-along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses +-*/ +- +-// Routines to convert to and from UTF8 +- +-#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +- +-#define _CRT_SECURE_NO_DEPRECATE +- +- +-#ifndef WIN32 +- +-#define VOID void +-#define BOOL int +-#define TRUE 1 +-#define FALSE 0 +- +-#include +- +- +-#else +-#include +-#endif +- +-int convUTF8 = 0; +- +-unsigned int CP437toUTF8Data[128] = { +- 34755, 48323, 43459, 41667, +- 42179, 41155, 42435, 42947, +- 43715, 43971, 43203, 44995, +- 44739, 44227, 33987, 34243, +- 35267, 42691, 34499, 46275, // 90 +- 46787, 45763, 48067, 47555, +- 49091, 38595, 40131, 41666, +- 41922, 42434, 10978018, 37574, +- 41411, 44483, 46019, 47811, // A0 +- 45507, 37315, 43714, 47810, +- 49090, 9473250, 44226, 48578, +- 48322, 41410, 43970, 48066, +- 9541346, 9606882, 9672418, 8557794, //B0 +- 10786018, 10589666, 10655202, 9868770, +- 9803234, 10720738, 9541090, 9934306, +- 10327522, 10261986, 10196450, 9475298, +- 9737442, 11834594, 11310306, 10261730, //C0 +- 8426722, 12358882, 10393058, 10458594, +- 10130914, 9737698, 11113954, 10917346, +- 10524130, 9475554, 11310562, 10982882, +- 11048418, 10786274, 10851810, 10065378, //D0 +- 9999842, 9606626, 9672162, 11245026, +- 11179490, 9999586, 9213154, 8951522, +- 8689378, 9213666, 9475810, 8427234, +- 45518, 40899, 37838, 32975, // E0 +- 41934, 33743, 46530, 33999, +- 42702, 39118, 43470, 46286, +- 10389730, 34511, 46542, 11110626, +- 10586594, 45506, 10848738, 10783202, // F0 +- 10521826, 10587362, 47043, 8948194, +- 45250, 10062050, 47042, 10127586, +- 12550626, 45762, 10524386, 41154, +-}; +-unsigned int CP437toUTF8DataLen[128] = { +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 3, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 3, 2, 2, +- 2, 2, 2, 2, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 3, 3, 3, 3, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 3, 2, 2, 3, +- 3, 2, 3, 3, +- 3, 3, 2, 3, +- 2, 3, 2, 3, +- 3, 2, 3, 2, +-}; +- +-unsigned int CP1251toUTF8Data[128] = { +- 33488, 33744, 10125538, 37841, +- 10387682, 10911970, 10518754, 10584290, +- 11305698, 11567330, 35280, 12157154, +- 35536, 36048, 35792, 36816, +- 37585, 9994466, 10060002, 10256610, +- 10322146, 10649826, 9666786, 9732322, +- 39106, 10650850, 39377, 12222690, +- 39633, 40145, 39889, 40913, +- 41154, 36560, 40657, 35024, +- 42178, 37074, 42690, 42946, +- 33232, 43458, 34000, 43970, +- 44226, 44482, 44738, 34768, +- 45250, 45506, 34512, 38609, +- 37330, 46530, 46786, 47042, +- 37329, 9864418, 38097, 48066, +- 39121, 34256, 38353, 38865, +- 37072, 37328, 37584, 37840, +- 38096, 38352, 38608, 38864, +- 39120, 39376, 39632, 39888, +- 40144, 40400, 40656, 40912, +- 41168, 41424, 41680, 41936, +- 42192, 42448, 42704, 42960, +- 43216, 43472, 43728, 43984, +- 44240, 44496, 44752, 45008, +- 45264, 45520, 45776, 46032, +- 46288, 46544, 46800, 47056, +- 47312, 47568, 47824, 48080, +- 48336, 48592, 48848, 49104, +- 32977, 33233, 33489, 33745, +- 34001, 34257, 34513, 34769, +- 35025, 35281, 35537, 35793, +- 36049, 36305, 36561, 36817, +-}; +-unsigned int CP1251toUTF8DataLen[128] = { +- 2, 2, 3, 2, +- 3, 3, 3, 3, +- 3, 3, 2, 3, +- 2, 2, 2, 2, +- 2, 3, 3, 3, +- 3, 3, 3, 3, +- 2, 3, 2, 3, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 3, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +-}; +- +- +-unsigned int CP1252toUTF8Data[128] = { +- 11305698, 33218, 10125538, 37574, +- 10387682, 10911970, 10518754, 10584290, +- 34507, 11567330, 41157, 12157154, +- 37573, 36290, 48581, 36802, +- 37058, 9994466, 10060002, 10256610, +- 10322146, 10649826, 9666786, 9732322, +- 40139, 10650850, 41413, 12222690, +- 37829, 40386, 48837, 47301, +- 41154, 41410, 41666, 41922, +- 42178, 42434, 42690, 42946, +- 43202, 43458, 43714, 43970, +- 44226, 44482, 44738, 44994, +- 45250, 45506, 45762, 46018, +- 46274, 46530, 46786, 47042, +- 47298, 47554, 47810, 48066, +- 48322, 48578, 48834, 49090, +- 32963, 33219, 33475, 33731, +- 33987, 34243, 34499, 34755, +- 35011, 35267, 35523, 35779, +- 36035, 36291, 36547, 36803, +- 37059, 37315, 37571, 37827, +- 38083, 38339, 38595, 38851, +- 39107, 39363, 39619, 39875, +- 40131, 40387, 40643, 40899, +- 41155, 41411, 41667, 41923, +- 42179, 42435, 42691, 42947, +- 43203, 43459, 43715, 43971, +- 44227, 44483, 44739, 44995, +- 45251, 45507, 45763, 46019, +- 46275, 46531, 46787, 47043, +- 47299, 47555, 47811, 48067, +- 48323, 48579, 48835, 49091, +-}; +-unsigned int CP1252toUTF8DataLen[128] = { +- 3, 2, 3, 2, +- 3, 3, 3, 3, +- 2, 3, 2, 3, +- 2, 2, 2, 2, +- 2, 3, 3, 3, +- 3, 3, 3, 3, +- 2, 3, 2, 3, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +- 2, 2, 2, 2, +-}; +- +-#ifdef __BIG_ENDIAN__ +-BOOL initUTF8Done = FALSE; +-#else +-BOOL initUTF8Done = TRUE; +-#endif +- +-VOID initUTF8() +-{ +- // Swap bytes of UTF-8 COde on Big-endian systems +- +- int n; +- char temp[4]; +- char rev[4]; +- +- if (initUTF8Done) +- return; +- +- for (n = 0; n <128; n++) +- { +- memcpy(temp, &CP437toUTF8Data[n], 4); +- rev[0] = temp[3]; +- rev[1] = temp[2]; +- rev[2] = temp[1]; +- rev[3] = temp[0]; +- +- memcpy(&CP437toUTF8Data[n], rev, 4); +- +- memcpy(temp, &CP1251toUTF8Data[n], 4); +- rev[0] = temp[3]; +- rev[1] = temp[2]; +- rev[2] = temp[1]; +- rev[3] = temp[0]; +- +- memcpy(&CP1251toUTF8Data[n], rev, 4); +- +- memcpy(temp, &CP1252toUTF8Data[n], 4); +- rev[0] = temp[3]; +- rev[1] = temp[2]; +- rev[2] = temp[1]; +- rev[3] = temp[0]; +- +- memcpy(&CP1252toUTF8Data[n], rev, 4); +- } +- +- initUTF8Done = TRUE; +-} +- +- +- +-int Is8Bit(unsigned char *cpt, int len) +-{ +- int n; +- +- cpt--; +- +- for (n = 0; n < len; n++) +- { +- cpt++; +- +- if (*cpt > 127) +- return TRUE; +- } +- +- return FALSE; +-} +- +- +-int IsUTF8(unsigned char *ptr, int len) +-{ +- int n; +- unsigned char * cpt = ptr; +- +- // This has to be a bit loose, as UTF8 sequences may split over packets +- +- memcpy(&ptr[len], "\x80\x80\x80", 3); // in case trailing bytes are in next packet +- +- // Don't check first 3 if could be part of sequence +- +- if ((*(cpt) & 0xC0) == 0x80) // Valid continuation +- { +- cpt++; +- len--; +- if ((*(cpt) & 0xC0) == 0x80) // Valid continuation +- { +- cpt++; +- len--; +- if ((*(cpt) & 0xC0) == 0x80) // Valid continuation +- { +- cpt++; +- len--; +- } +- } +- } +- +- cpt--; +- +- for (n = 0; n < len; n++) +- { +- cpt++; +- +- if (*cpt < 128) +- continue; +- +- if ((*cpt & 0xF8) == 0xF0) +- { // start of 4-byte sequence +- if (((*(cpt + 1) & 0xC0) == 0x80) +- && ((*(cpt + 2) & 0xC0) == 0x80) +- && ((*(cpt + 3) & 0xC0) == 0x80)) +- { +- cpt += 3; +- n += 3; +- continue; +- } +- return FALSE; +- } +- else if ((*cpt & 0xF0) == 0xE0) +- { // start of 3-byte sequence +- if (((*(cpt + 1) & 0xC0) == 0x80) +- && ((*(cpt + 2) & 0xC0) == 0x80)) +- { +- cpt += 2; +- n += 2; +- continue; +- } +- return FALSE; +- } +- else if ((*cpt & 0xE0) == 0xC0) +- { // start of 2-byte sequence +- if ((*(cpt + 1) & 0xC0) == 0x80) +- { +- cpt++; +- n++; +- continue; +- } +- return FALSE; +- } +- return FALSE; +- } +- +- return TRUE; +-} +- +-int WebIsUTF8(unsigned char *ptr, int len) +-{ +- int n; +- unsigned char * cpt = ptr; +- +- // This is simpler than the Term version, as it only handles complete lines of text, so cant get split sequences +- +- cpt--; +- +- for (n = 0; n < len; n++) +- { +- cpt++; +- +- if (*cpt < 128) +- continue; +- +- if ((*cpt & 0xF8) == 0xF0) +- { // start of 4-byte sequence +- if (((*(cpt + 1) & 0xC0) == 0x80) +- && ((*(cpt + 2) & 0xC0) == 0x80) +- && ((*(cpt + 3) & 0xC0) == 0x80)) +- { +- cpt += 3; +- n += 3; +- continue; +- } +- return FALSE; +- } +- else if ((*cpt & 0xF0) == 0xE0) +- { // start of 3-byte sequence +- if (((*(cpt + 1) & 0xC0) == 0x80) +- && ((*(cpt + 2) & 0xC0) == 0x80)) +- { +- cpt += 2; +- n += 2; +- continue; +- } +- return FALSE; +- } +- else if ((*cpt & 0xE0) == 0xC0) +- { // start of 2-byte sequence +- if ((*(cpt + 1) & 0xC0) == 0x80) +- { +- cpt++; +- n++; +- continue; +- } +- return FALSE; +- } +- return FALSE; +- } +- +- return TRUE; +-} +- +- +- +-int Convert437toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF) +-{ +- unsigned char * ptr1 = MsgPtr; +- unsigned char * ptr2 = UTF; +- int n; +- unsigned int c; +- +- for (n = 0; n < len; n++) +- { +- c = *(ptr1++); +- +- if (c < 128) +- { +- *(ptr2++) = c; +- continue; +- } +- +- memcpy(ptr2, &CP437toUTF8Data[c - 128], CP437toUTF8DataLen[c - 128]); +- ptr2 += CP437toUTF8DataLen[c - 128]; +- } +- +- return (int)(ptr2 - UTF); +-} +- +-int Convert1251toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF) +-{ +- unsigned char * ptr1 = MsgPtr; +- unsigned char * ptr2 = UTF; +- int n; +- unsigned int c; +- +- for (n = 0; n < len; n++) +- { +- c = *(ptr1++); +- +- if (c < 128) +- { +- *(ptr2++) = c; +- continue; +- } +- +- memcpy(ptr2, &CP1251toUTF8Data[c - 128], CP1251toUTF8DataLen[c - 128]); +- ptr2 += CP1251toUTF8DataLen[c - 128]; +- } +- +- return (int)(ptr2 - UTF); +-} +- +-int Convert1252toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF) +-{ +- unsigned char * ptr1 = MsgPtr; +- unsigned char * ptr2 = UTF; +- int n; +- unsigned int c; +- +- for (n = 0; n < len; n++) +- { +- c = *(ptr1++); +- +- if (c < 128) +- { +- *(ptr2++) = c; +- continue; +- } +- +- memcpy(ptr2, &CP1252toUTF8Data[c - 128], CP1252toUTF8DataLen[c - 128]); +- ptr2 += CP1252toUTF8DataLen[c - 128]; +- } +- +- return (int)(ptr2 - UTF); +-} +- +-int TrytoGuessCode(unsigned char * Char, int Len) +-{ +- int Above127 = 0; +- int LineDraw = 0; +- int NumericAndSpaces = 0; +- int n; +- +- for (n = 0; n < Len; n++) +- { +- if (Char[n] < 65) +- { +- NumericAndSpaces++; +- } +- else +- { +- if (Char[n] > 127) +- { +- Above127++; +- if (Char[n] == 0xF8 || (Char[n] > 178 && Char[n] < 224)) +- { +- LineDraw++; +- } +- } +- } +- } +- +- if (Above127 == 0) // Doesn't really matter! +- return 1252; +- +- if (Above127 == LineDraw) +- return 437; // If only Line Draw chars, assume line draw +- +- // If mainly below 128, it is probably Latin if mainly above, probably Cyrillic +- +- if ((Len - (NumericAndSpaces + Above127)) < Above127) +- return 1251; +- else +- return 1252; +-} +- +-unsigned char outbuffer[16384]; // I don't think this needs to be thread safe +- +-int checkUTF8(unsigned char * in, int len, unsigned char * out) +-{ +- // We mustn't mess with input string +- +- unsigned char Msg[8192]; +- int u, code = convUTF8; +- +- if (convUTF8 == -1 || !Is8Bit(in, len)) +- { +- // just copy to output +- +- memcpy(out, in, len); +- return len; +- } +- +- // Convert +- +- memcpy(Msg, in, len); +- Msg[len] = 0; +- +- if (convUTF8 == 0) // Auto - Try to guess encoding +- code = TrytoGuessCode(Msg, len); +- +- if (code == 437) +- u = Convert437toUTF8(Msg, len, out); +- else if (code == 1251) +- u = Convert1251toUTF8(Msg, len, out); +- else +- u = Convert1252toUTF8(Msg, len, out); +- +- return u; +- +-} +- ++/* ++Copyright 2001-2018 John Wiseman G8BPQ ++ ++This file is part of LinBPQ/BPQ32. ++ ++LinBPQ/BPQ32 is free software: you can redistribute it and/or modify ++it under the terms of the GNU General Public License as published by ++the Free Software Foundation, either version 3 of the License, or ++(at your option) any later version. ++ ++LinBPQ/BPQ32 is distributed in the hope that it will be useful, ++but WITHOUT ANY WARRANTY; without even the implied warranty of ++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++GNU General Public License for more details. ++ ++You should have received a copy of the GNU General Public License ++along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses ++*/ ++ ++// Routines to convert to and from UTF8 ++ ++#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers ++ ++#define _CRT_SECURE_NO_DEPRECATE ++ ++ ++#ifndef WIN32 ++ ++#define VOID void ++#define BOOL int ++#define TRUE 1 ++#define FALSE 0 ++ ++#include ++ ++ ++#else ++#include ++#endif ++ ++int convUTF8 = 0; ++ ++unsigned int CP437toUTF8Data[128] = { ++ 34755, 48323, 43459, 41667, ++ 42179, 41155, 42435, 42947, ++ 43715, 43971, 43203, 44995, ++ 44739, 44227, 33987, 34243, ++ 35267, 42691, 34499, 46275, // 90 ++ 46787, 45763, 48067, 47555, ++ 49091, 38595, 40131, 41666, ++ 41922, 42434, 10978018, 37574, ++ 41411, 44483, 46019, 47811, // A0 ++ 45507, 37315, 43714, 47810, ++ 49090, 9473250, 44226, 48578, ++ 48322, 41410, 43970, 48066, ++ 9541346, 9606882, 9672418, 8557794, //B0 ++ 10786018, 10589666, 10655202, 9868770, ++ 9803234, 10720738, 9541090, 9934306, ++ 10327522, 10261986, 10196450, 9475298, ++ 9737442, 11834594, 11310306, 10261730, //C0 ++ 8426722, 12358882, 10393058, 10458594, ++ 10130914, 9737698, 11113954, 10917346, ++ 10524130, 9475554, 11310562, 10982882, ++ 11048418, 10786274, 10851810, 10065378, //D0 ++ 9999842, 9606626, 9672162, 11245026, ++ 11179490, 9999586, 9213154, 8951522, ++ 8689378, 9213666, 9475810, 8427234, ++ 45518, 40899, 37838, 32975, // E0 ++ 41934, 33743, 46530, 33999, ++ 42702, 39118, 43470, 46286, ++ 10389730, 34511, 46542, 11110626, ++ 10586594, 45506, 10848738, 10783202, // F0 ++ 10521826, 10587362, 47043, 8948194, ++ 45250, 10062050, 47042, 10127586, ++ 12550626, 45762, 10524386, 41154, ++}; ++unsigned int CP437toUTF8DataLen[128] = { ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 3, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 3, 2, 2, ++ 2, 2, 2, 2, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 3, 3, 3, 3, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 3, 2, 2, 3, ++ 3, 2, 3, 3, ++ 3, 3, 2, 3, ++ 2, 3, 2, 3, ++ 3, 2, 3, 2, ++}; ++ ++unsigned int CP1251toUTF8Data[128] = { ++ 33488, 33744, 10125538, 37841, ++ 10387682, 10911970, 10518754, 10584290, ++ 11305698, 11567330, 35280, 12157154, ++ 35536, 36048, 35792, 36816, ++ 37585, 9994466, 10060002, 10256610, ++ 10322146, 10649826, 9666786, 9732322, ++ 39106, 10650850, 39377, 12222690, ++ 39633, 40145, 39889, 40913, ++ 41154, 36560, 40657, 35024, ++ 42178, 37074, 42690, 42946, ++ 33232, 43458, 34000, 43970, ++ 44226, 44482, 44738, 34768, ++ 45250, 45506, 34512, 38609, ++ 37330, 46530, 46786, 47042, ++ 37329, 9864418, 38097, 48066, ++ 39121, 34256, 38353, 38865, ++ 37072, 37328, 37584, 37840, ++ 38096, 38352, 38608, 38864, ++ 39120, 39376, 39632, 39888, ++ 40144, 40400, 40656, 40912, ++ 41168, 41424, 41680, 41936, ++ 42192, 42448, 42704, 42960, ++ 43216, 43472, 43728, 43984, ++ 44240, 44496, 44752, 45008, ++ 45264, 45520, 45776, 46032, ++ 46288, 46544, 46800, 47056, ++ 47312, 47568, 47824, 48080, ++ 48336, 48592, 48848, 49104, ++ 32977, 33233, 33489, 33745, ++ 34001, 34257, 34513, 34769, ++ 35025, 35281, 35537, 35793, ++ 36049, 36305, 36561, 36817, ++}; ++unsigned int CP1251toUTF8DataLen[128] = { ++ 2, 2, 3, 2, ++ 3, 3, 3, 3, ++ 3, 3, 2, 3, ++ 2, 2, 2, 2, ++ 2, 3, 3, 3, ++ 3, 3, 3, 3, ++ 2, 3, 2, 3, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 3, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++}; ++ ++ ++unsigned int CP1252toUTF8Data[128] = { ++ 11305698, 33218, 10125538, 37574, ++ 10387682, 10911970, 10518754, 10584290, ++ 34507, 11567330, 41157, 12157154, ++ 37573, 36290, 48581, 36802, ++ 37058, 9994466, 10060002, 10256610, ++ 10322146, 10649826, 9666786, 9732322, ++ 40139, 10650850, 41413, 12222690, ++ 37829, 40386, 48837, 47301, ++ 41154, 41410, 41666, 41922, ++ 42178, 42434, 42690, 42946, ++ 43202, 43458, 43714, 43970, ++ 44226, 44482, 44738, 44994, ++ 45250, 45506, 45762, 46018, ++ 46274, 46530, 46786, 47042, ++ 47298, 47554, 47810, 48066, ++ 48322, 48578, 48834, 49090, ++ 32963, 33219, 33475, 33731, ++ 33987, 34243, 34499, 34755, ++ 35011, 35267, 35523, 35779, ++ 36035, 36291, 36547, 36803, ++ 37059, 37315, 37571, 37827, ++ 38083, 38339, 38595, 38851, ++ 39107, 39363, 39619, 39875, ++ 40131, 40387, 40643, 40899, ++ 41155, 41411, 41667, 41923, ++ 42179, 42435, 42691, 42947, ++ 43203, 43459, 43715, 43971, ++ 44227, 44483, 44739, 44995, ++ 45251, 45507, 45763, 46019, ++ 46275, 46531, 46787, 47043, ++ 47299, 47555, 47811, 48067, ++ 48323, 48579, 48835, 49091, ++}; ++unsigned int CP1252toUTF8DataLen[128] = { ++ 3, 2, 3, 2, ++ 3, 3, 3, 3, ++ 2, 3, 2, 3, ++ 2, 2, 2, 2, ++ 2, 3, 3, 3, ++ 3, 3, 3, 3, ++ 2, 3, 2, 3, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++ 2, 2, 2, 2, ++}; ++ ++#ifdef __BIG_ENDIAN__ ++BOOL initUTF8Done = FALSE; ++#else ++BOOL initUTF8Done = TRUE; ++#endif ++ ++VOID initUTF8() ++{ ++ // Swap bytes of UTF-8 COde on Big-endian systems ++ ++ int n; ++ char temp[4]; ++ char rev[4]; ++ ++ if (initUTF8Done) ++ return; ++ ++ for (n = 0; n <128; n++) ++ { ++ memcpy(temp, &CP437toUTF8Data[n], 4); ++ rev[0] = temp[3]; ++ rev[1] = temp[2]; ++ rev[2] = temp[1]; ++ rev[3] = temp[0]; ++ ++ memcpy(&CP437toUTF8Data[n], rev, 4); ++ ++ memcpy(temp, &CP1251toUTF8Data[n], 4); ++ rev[0] = temp[3]; ++ rev[1] = temp[2]; ++ rev[2] = temp[1]; ++ rev[3] = temp[0]; ++ ++ memcpy(&CP1251toUTF8Data[n], rev, 4); ++ ++ memcpy(temp, &CP1252toUTF8Data[n], 4); ++ rev[0] = temp[3]; ++ rev[1] = temp[2]; ++ rev[2] = temp[1]; ++ rev[3] = temp[0]; ++ ++ memcpy(&CP1252toUTF8Data[n], rev, 4); ++ } ++ ++ initUTF8Done = TRUE; ++} ++ ++ ++ ++int Is8Bit(unsigned char *cpt, int len) ++{ ++ int n; ++ ++ cpt--; ++ ++ for (n = 0; n < len; n++) ++ { ++ cpt++; ++ ++ if (*cpt > 127) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++ ++int IsUTF8(unsigned char *ptr, int len) ++{ ++ int n; ++ unsigned char * cpt = ptr; ++ ++ // This has to be a bit loose, as UTF8 sequences may split over packets ++ ++ memcpy(&ptr[len], "\x80\x80\x80", 3); // in case trailing bytes are in next packet ++ ++ // Don't check first 3 if could be part of sequence ++ ++ if ((*(cpt) & 0xC0) == 0x80) // Valid continuation ++ { ++ cpt++; ++ len--; ++ if ((*(cpt) & 0xC0) == 0x80) // Valid continuation ++ { ++ cpt++; ++ len--; ++ if ((*(cpt) & 0xC0) == 0x80) // Valid continuation ++ { ++ cpt++; ++ len--; ++ } ++ } ++ } ++ ++ cpt--; ++ ++ for (n = 0; n < len; n++) ++ { ++ cpt++; ++ ++ if (*cpt < 128) ++ continue; ++ ++ if ((*cpt & 0xF8) == 0xF0) ++ { // start of 4-byte sequence ++ if (((*(cpt + 1) & 0xC0) == 0x80) ++ && ((*(cpt + 2) & 0xC0) == 0x80) ++ && ((*(cpt + 3) & 0xC0) == 0x80)) ++ { ++ cpt += 3; ++ n += 3; ++ continue; ++ } ++ return FALSE; ++ } ++ else if ((*cpt & 0xF0) == 0xE0) ++ { // start of 3-byte sequence ++ if (((*(cpt + 1) & 0xC0) == 0x80) ++ && ((*(cpt + 2) & 0xC0) == 0x80)) ++ { ++ cpt += 2; ++ n += 2; ++ continue; ++ } ++ return FALSE; ++ } ++ else if ((*cpt & 0xE0) == 0xC0) ++ { // start of 2-byte sequence ++ if ((*(cpt + 1) & 0xC0) == 0x80) ++ { ++ cpt++; ++ n++; ++ continue; ++ } ++ return FALSE; ++ } ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++int WebIsUTF8(unsigned char *ptr, int len) ++{ ++ int n; ++ unsigned char * cpt = ptr; ++ ++ // This is simpler than the Term version, as it only handles complete lines of text, so cant get split sequences ++ ++ cpt--; ++ ++ for (n = 0; n < len; n++) ++ { ++ cpt++; ++ ++ if (*cpt < 128) ++ continue; ++ ++ if ((*cpt & 0xF8) == 0xF0) ++ { // start of 4-byte sequence ++ if (((*(cpt + 1) & 0xC0) == 0x80) ++ && ((*(cpt + 2) & 0xC0) == 0x80) ++ && ((*(cpt + 3) & 0xC0) == 0x80)) ++ { ++ cpt += 3; ++ n += 3; ++ continue; ++ } ++ return FALSE; ++ } ++ else if ((*cpt & 0xF0) == 0xE0) ++ { // start of 3-byte sequence ++ if (((*(cpt + 1) & 0xC0) == 0x80) ++ && ((*(cpt + 2) & 0xC0) == 0x80)) ++ { ++ cpt += 2; ++ n += 2; ++ continue; ++ } ++ return FALSE; ++ } ++ else if ((*cpt & 0xE0) == 0xC0) ++ { // start of 2-byte sequence ++ if ((*(cpt + 1) & 0xC0) == 0x80) ++ { ++ cpt++; ++ n++; ++ continue; ++ } ++ return FALSE; ++ } ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++ ++ ++int Convert437toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF) ++{ ++ unsigned char * ptr1 = MsgPtr; ++ unsigned char * ptr2 = UTF; ++ int n; ++ unsigned int c; ++ ++ for (n = 0; n < len; n++) ++ { ++ c = *(ptr1++); ++ ++ if (c < 128) ++ { ++ *(ptr2++) = c; ++ continue; ++ } ++ ++ memcpy(ptr2, &CP437toUTF8Data[c - 128], CP437toUTF8DataLen[c - 128]); ++ ptr2 += CP437toUTF8DataLen[c - 128]; ++ } ++ ++ return (int)(ptr2 - UTF); ++} ++ ++int Convert1251toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF) ++{ ++ unsigned char * ptr1 = MsgPtr; ++ unsigned char * ptr2 = UTF; ++ int n; ++ unsigned int c; ++ ++ for (n = 0; n < len; n++) ++ { ++ c = *(ptr1++); ++ ++ if (c < 128) ++ { ++ *(ptr2++) = c; ++ continue; ++ } ++ ++ memcpy(ptr2, &CP1251toUTF8Data[c - 128], CP1251toUTF8DataLen[c - 128]); ++ ptr2 += CP1251toUTF8DataLen[c - 128]; ++ } ++ ++ return (int)(ptr2 - UTF); ++} ++ ++int Convert1252toUTF8(unsigned char * MsgPtr, int len, unsigned char * UTF) ++{ ++ unsigned char * ptr1 = MsgPtr; ++ unsigned char * ptr2 = UTF; ++ int n; ++ unsigned int c; ++ ++ for (n = 0; n < len; n++) ++ { ++ c = *(ptr1++); ++ ++ if (c < 128) ++ { ++ *(ptr2++) = c; ++ continue; ++ } ++ ++ memcpy(ptr2, &CP1252toUTF8Data[c - 128], CP1252toUTF8DataLen[c - 128]); ++ ptr2 += CP1252toUTF8DataLen[c - 128]; ++ } ++ ++ return (int)(ptr2 - UTF); ++} ++ ++int TrytoGuessCode(unsigned char * Char, int Len) ++{ ++ int Above127 = 0; ++ int LineDraw = 0; ++ int NumericAndSpaces = 0; ++ int n; ++ ++ for (n = 0; n < Len; n++) ++ { ++ if (Char[n] < 65) ++ { ++ NumericAndSpaces++; ++ } ++ else ++ { ++ if (Char[n] > 127) ++ { ++ Above127++; ++ if (Char[n] == 0xF8 || (Char[n] > 178 && Char[n] < 224)) ++ { ++ LineDraw++; ++ } ++ } ++ } ++ } ++ ++ if (Above127 == 0) // Doesn't really matter! ++ return 1252; ++ ++ if (Above127 == LineDraw) ++ return 437; // If only Line Draw chars, assume line draw ++ ++ // If mainly below 128, it is probably Latin if mainly above, probably Cyrillic ++ ++ if ((Len - (NumericAndSpaces + Above127)) < Above127) ++ return 1251; ++ else ++ return 1252; ++} ++ ++unsigned char outbuffer[16384]; // I don't think this needs to be thread safe ++ ++int checkUTF8(unsigned char * in, int len, unsigned char * out) ++{ ++ // We mustn't mess with input string ++ ++ unsigned char Msg[8192]; ++ int u, code = convUTF8; ++ ++ if (convUTF8 == -1 || !Is8Bit(in, len)) ++ { ++ // just copy to output ++ ++ memcpy(out, in, len); ++ return len; ++ } ++ ++ // Convert ++ ++ memcpy(Msg, in, len); ++ Msg[len] = 0; ++ ++ if (convUTF8 == 0) // Auto - Try to guess encoding ++ code = TrytoGuessCode(Msg, len); ++ ++ if (code == 437) ++ u = Convert437toUTF8(Msg, len, out); ++ else if (code == 1251) ++ u = Convert1251toUTF8(Msg, len, out); ++ else ++ u = Convert1252toUTF8(Msg, len, out); ++ ++ return u; ++ ++} ++ diff --git a/debian/patches/series b/debian/patches/series index e69de29..7d11cd3 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -0,0 +1 @@ +Sure-whynot