diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c4efe2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,261 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +project.fragment.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +# NuGet v3's project.json files produces more ignoreable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# JetBrains Rider +.idea/ +*.sln.iml + +# CodeRush +.cr/ + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc \ No newline at end of file diff --git a/250x1000Hz.wav b/250x1000Hz.wav new file mode 100644 index 0000000..0079795 Binary files /dev/null and b/250x1000Hz.wav differ diff --git a/250x600Hz.wav b/250x600Hz.wav new file mode 100644 index 0000000..3480a76 Binary files /dev/null and b/250x600Hz.wav differ diff --git a/AGWCode.cpp b/AGWCode.cpp index 9539b07..00e319f 100644 --- a/AGWCode.cpp +++ b/AGWCode.cpp @@ -1,1567 +1,1605 @@ -// 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 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 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); - -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 = (int)strlen(AGWBeaconMsg); - - 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) - { - 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[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"); - } - - 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) - { - 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->AGWSession == NULL) - { - Sess = S; - break; - } - } - } - else if (TermMode == Single && (singlemodeFormat & Mon)) - { - S = _sessions.at(0); - - if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) - 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); - } - - 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]; - - AGW_frame_header(Msg, 0, 'm', 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); - 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 - { - // 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; - } - } - - if (Sess) - { - sprintf(Title, "Connected to %s", CallFrom); - - 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(); - - // 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 Connect 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); - } -} - - -void on_AGW_Mon_frame(byte * Msg, int Len, char Type) -{ - if (AGWUsers && AGWUsers->MonSess && AGWUsers->MonSess->monWindow) - { - if (Type == 'T') - WritetoOutputWindowEx(AGWUsers->MonSess, Msg, Len, - AGWUsers->MonSess->monWindow, &AGWUsers->MonSess->OutputSaveLen, AGWUsers->MonSess->OutputSave, monTxText); // Red - else - WritetoOutputWindowEx(AGWUsers->MonSess, Msg, Len, - AGWUsers->MonSess->monWindow, &AGWUsers->MonSess->OutputSaveLen, AGWUsers->MonSess->OutputSave, monRxText); // Blue - } -} - - -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[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"); - } - - 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 = (int)strlen(AGWBeaconMsg); + + 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) + { + 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); + 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 + { + // 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; + } + } + + 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); + } +} diff --git a/AGWConnect.ui b/AGWConnect.ui index c5e4506..7e436e4 100644 --- a/AGWConnect.ui +++ b/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 + + + + + diff --git a/AGWParams.ui b/AGWParams.ui index 7a5fc45..a72b545 100644 --- a/AGWParams.ui +++ b/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 + + + + + diff --git a/AlertSetup.ui b/AlertSetup.ui new file mode 100644 index 0000000..6addb82 --- /dev/null +++ b/AlertSetup.ui @@ -0,0 +1,545 @@ + + + AlertDialog + + + + 0 + 0 + 554 + 433 + + + + Dialog + + + + + 94 + 376 + 351 + 33 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + OK + + + + + + + Cancel + + + + + + + + + 24 + 40 + 201 + 20 + + + + Beep on Inbound connect + + + + + + 24 + 65 + 221 + 21 + + + + Beep on message after inactivity + + + + + + 24 + 90 + 201 + 20 + + + + Beep on keyword + + + + + + 350 + 65 + 51 + 20 + + + + + + + 350 + 95 + 137 + 20 + + + + + + + 24 + 204 + 82 + 20 + + + + Use Beep + + + buttonGroup + + + + + + 148 + 204 + 193 + 20 + + + + Use Audio Files + + + buttonGroup + + + + + + 258 + 65 + 47 + 20 + + + + Interval + + + + + + 24 + 263 + 107 + 20 + + + + Interval .wav File + + + + + + 24 + 288 + 169 + 20 + + + + Inbound Connect .wav File + + + + + + 24 + 313 + 165 + 20 + + + + Keyword Alert .wav File + + + + + + 258 + 95 + 89 + 20 + + + + Keyword File + + + + + + 20 + 134 + 465 + 65 + + + + The System Beep function doesn't work on all platform, so you can configure QtTermTCP to play a sound file instead of using Beep. You can set different files for each event if you wish. Select from the supplied sounds or choose your own .wav files. + + + true + + + + + + 416 + 263 + 61 + 20 + + + + Choose + + + + + + 416 + 288 + 61 + 20 + + + + Choose + + + + + + 416 + 313 + 61 + 20 + + + + Choose + + + + + + 24 + 15 + 289 + 20 + + + + Use Bells (ascii BELL char makes a sound) + + + + + + 416 + 238 + 61 + 20 + + + + Choose + + + + + + 24 + 238 + 107 + 20 + + + + Bells .wav File + + + + + + 484 + 288 + 47 + 20 + + + + Test + + + + + + 484 + 263 + 47 + 20 + + + + Test + + + + + + 484 + 313 + 47 + 20 + + + + Test + + + + + + 484 + 238 + 47 + 20 + + + + Test + + + + + + 36 + 336 + 471 + 25 + + + + It may take a second or two for sound to play after pressing Test button + + + Qt::AlignCenter + + + + + + 200 + 238 + 207 + 20 + + + + true + + + QComboBox::InsertAtTop + + + + :/PCBeep + + + + + :/LowTone + + + + + :/HighTone + + + + + :/Ring + + + + + :/Ding + + + + + + + 200 + 264 + 207 + 20 + + + + true + + + QComboBox::InsertAtTop + + + + :/PCBeep + + + + + :/LowTone + + + + + :/HighTone + + + + + :/Ring + + + + + :/Ding + + + + + + + 200 + 288 + 207 + 20 + + + + true + + + QComboBox::InsertAtTop + + + + :/PCBeep + + + + + :/LowTone + + + + + :/HighTone + + + + + :/Ring + + + + + :/Ding + + + + + + + 200 + 314 + 207 + 20 + + + + true + + + QComboBox::InsertAtTop + + + + :/PCBeep + + + + + :/LowTone + + + + + :/HighTone + + + + + :/Ring + + + + + :/Ding + + + + + + + + + + diff --git a/ColourConfig.ui b/ColourConfig.ui index d980e87..882ca6e 100644 --- a/ColourConfig.ui +++ b/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 + + + + + + diff --git a/DialogButtonBottom.ui b/DialogButtonBottom.ui index 5159f82..45832a0 100644 --- a/DialogButtonBottom.ui +++ b/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 + + + + + diff --git a/KISSConfig.ui b/KISSConfig.ui index 183778e..b0c1ead 100644 --- a/KISSConfig.ui +++ b/KISSConfig.ui @@ -1,381 +1,410 @@ - - - KISSDialog - - - - 0 - 0 - 432 - 286 - - - - KISS Configuration - - - - - 40 - 238 - 351 - 33 - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - OK - - - - - - - Cancel - - - - - - - - - 10 - 96 - 401 - 57 - - - - TCP Setup - - - - - 90 - 20 - 111 - 22 - - - - - - - 330 - 21 - 47 - 22 - - - - - - - 16 - 24 - 47 - 13 - - - - Host - - - - - - 280 - 24 - 47 - 13 - - - - Port - - - - - - 85 - 63 - 47 - 22 - - - - - - - 20 - 66 - 47 - 13 - - - - Port - - - - - - - 0 - 46 - 411 - 51 - - - - Serial TNC - - - - - 150 - 20 - 111 - 22 - - - - - - - 20 - 23 - 131 - 16 - - - - Select Device - - - - - - 280 - 20 - 47 - 22 - - - - Speed - - - - - - 335 - 21 - 51 - 22 - - - - 19200 - - - - - - - 10 - 12 - 161 - 21 - - - - Enable KISS Interface - - - - - - 150 - 10 - 23 - 25 - - - - Qt::RightToLeft - - - - - - - - - 230 - 13 - 61 - 17 - - - - MYCALL - - - - - - 300 - 10 - 91 - 22 - - - - - - - 25 - 168 - 47 - 13 - - - - Paclen - - - - - - 100 - 165 - 47 - 22 - - - - - - - 265 - 168 - 66 - 16 - - - - MaxFrame - - - - - - 340 - 165 - 47 - 22 - - - - - - - 25 - 202 - 47 - 13 - - - - Frack - - - - - - 100 - 199 - 36 - 22 - - - - - - - 265 - 201 - 47 - 13 - - - - Retries - - - - - - 340 - 198 - 36 - 22 - - - - - - - - okButton - clicked() - KISSDialog - accept() - - - 278 - 253 - - - 96 - 254 - - - - - cancelButton - clicked() - KISSDialog - reject() - - - 369 - 253 - - - 179 - 282 - - - - - + + + KISSDialog + + + + 0 + 0 + 432 + 319 + + + + KISS Configuration + + + + + 40 + 262 + 351 + 33 + + + + + 6 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + OK + + + + + + + Cancel + + + + + + + + + 10 + 120 + 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 + 70 + 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 + 12 + 149 + 21 + + + + Enable KISS Interface + + + + + + 158 + 10 + 23 + 25 + + + + Qt::RightToLeft + + + + + + + + + 214 + 13 + 61 + 17 + + + + MYCALL + + + + + + 286 + 10 + 91 + 22 + + + + + + + 25 + 192 + 47 + 13 + + + + Paclen + + + + + + 98 + 189 + 47 + 22 + + + + + + + 213 + 192 + 66 + 16 + + + + MaxFrame + + + + + + 288 + 189 + 47 + 22 + + + + + + + 25 + 226 + 47 + 13 + + + + Frack + + + + + + 98 + 223 + 36 + 22 + + + + + + + 213 + 225 + 47 + 13 + + + + Retries + + + + + + 288 + 222 + 36 + 22 + + + + + + + 12 + 38 + 149 + 21 + + + + Allow incoming connects + + + + + + 158 + 38 + 23 + 21 + + + + Qt::RightToLeft + + + + + + + + + + okButton + clicked() + KISSDialog + accept() + + + 278 + 253 + + + 96 + 254 + + + + + cancelButton + clicked() + KISSDialog + reject() + + + 369 + 253 + + + 179 + 282 + + + + + diff --git a/ListenPort.ui b/ListenPort.ui index c46838a..e78574f 100644 --- a/ListenPort.ui +++ b/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 + + + + + + + + + + + diff --git a/PCBeep.wav b/PCBeep.wav new file mode 100644 index 0000000..8ff2dd9 Binary files /dev/null and b/PCBeep.wav differ diff --git a/QtTermTCP.cpp b/QtTermTCP.cpp index b029b7e..6328adb 100644 --- a/QtTermTCP.cpp +++ b/QtTermTCP.cpp @@ -1,7138 +1,7864 @@ -// Qt Version of BPQTermTCP - -#define VersionString "0.0.0.66" - -// .12 Save font weight -// .13 Display incomplete lines (ie without CR) -// .14 Add YAPP and Listen Mode -// .15 Reuse windows in Listen Mode -// .17 MDI Version 7/1/20 -// .18 Fix input window losing focus when data arrives on other window -// .19 Fix Scrollback -// .20 WinXP compatibility changes -// .21 Save Window Positions -// .22 Open a window on first start -// .23 Add Tabbed display option -// .24 Fix crash when setting Monitor flags in Tabbed mode -// .25 Add AGW mode -// .26 Add sending CTRL/C CTRL/D and CTRL/Z) -// .27 Limit size of windows to 10000 lines -// Fix YAPP in Tabbed Mode -// .28 Add AGW Beacon -// .29 Fix allocating Listem sessions to tabs connected using AGW -// .30 Fix allocationd AGW Monitor Sessions -// .31 Fix output being written to the wrong place when window is scrolled back -// .32 Fix connect with digis -// .33 Add StripLF option -// .34 Improvements for Andriod -// Option to change Menu Fonts -// Fix receiving part lines when scrolled back -// .35 Fix PE if not in Tabbed Mode -// .36 Improved dialogs mainly for Android -// Try to make sure sessions are closed before exiting -// .37 Replace VT with LF (for pasting from BPQ32 Terminal Window) -// Dont show AGW status line if AGW interface is disabled -// Don't show Window Menu in Single Mode -// .38 Protect against connect to normal Telnet Port. -// Send CTEXT and Beep for inward AGW Connects -// Make sending Idle and Connect beeps configurable -// Change displayed Monitor flags when active window changed. -// Fix duplicate text on long lines -// .39 Add option to Convert non-utf8 charaters -// .40 Prevent crash if AGW monitor Window closed -// .41 Allow AGW Config and Connect dialogs to be resized with scrollbars -// Fix disabling connect flag on current session when AGW connects -// .42 Fix some bugs in AGW session handling -// .43 Include Ross KD5LPB's fixes for MAC -// .44 Ctrl/[ sends ESC (0x1b) -// .45 Add VARA support Nov 2021 -// .46 Fix dialog size on VARA setup -// .47 Move VARA Status indicator. -// Add FLRIG PTT for VARA -// .48 Check that YAPP Receive Directory has been set -// Save separate configs for VARA, VARAFM and VARASAT -// .49 Add BBS Monitor Dec 2021 -// .50 Make Serial port support optional for Android Version -// .51 Add KISS TNC Support May 2022 -// .52 Save partially typed lines on cursor up May 2022 -// .53 Add UI Mode for KISS Sessions May 2022 -// Fix saving KISS Paclen (b) -// Fix Keepalive (c) -// .54 Add option to change screen colours June 2022 -// .55 Build without optimisation -// .56 Add Teletext mode Nov 2022 -// .57 Fix KISS mode incoming call handling -// .58 Add method to toggle Normal/Teletext Mode -// Fix KISS multiple session protection -// .59 Add Teletext double height mode -// .60 Add option to name sessions Jan 2023 -// .61 Add VARA Init Script Feb 2023 -// .62 Fix running AGW in single session mode Feb 2023 -// .63 Fix handling split monitor frame (no fe in buffer) Apr 2023 -// .64 Add Clear Screen command to context menu Apr 2023 -// .65 Fixes for 63 port version of BPQ May 2023 -// .66 Colour Tab of incoming calls June 2023 - -#define _CRT_SECURE_NO_WARNINGS - -#define UNUSED(x) (void)(x) - -#define USESERIAL - -#include "QtTermTCP.h" -#include "TabDialog.h" -#include -#include -#include -#include -#include -#include "QTreeWidget" -#include -#include -#include -#include -#include -#ifdef USESERIAL -#include -#include -#endif -#ifndef WIN32 -#define strtok_s strtok_r -#endif -#include -#include -#ifndef WIN32 -#include -#endif - -#include "ax25.h" - -#define UNREFERENCED_PARAMETER(P) (P) - -void DecodeTeleText(Ui_ListenSession * Sess, char * text); - -char Host[MAXHOSTS + 1][100] = { "" }; -int Port[MAXHOSTS + 1] = { 0 }; -char UserName[MAXHOSTS + 1][80] = { "" }; -char Password[MAXHOSTS + 1][80] = { "" }; -char MonParams[MAXHOSTS + 1][80] = { "" }; -char SessName[MAXHOSTS + 1][80] = { "" }; -int ListenPort = 8015; - -// Session Type Equates - -#define Term 1 -#define Mon 2 -#define Listen 4 - -// Presentation - Single Window, MDI or Tabbed - -int TermMode = 0; - -#define Single 0 -#define MDI 1 -#define Tabbed 2 - -int singlemodeFormat = Mon + Term; - -char monStyleSheet[128] = "background-color: rgb(0,255,255)"; -char termStyleSheet[128] = "background-color: rgb(255,0,255);"; -char inputStyleSheet[128] = "color: rgb(255, 0, 0); background-color: rgb(255,255,0);"; - - -QColor monBackground = qRgb(0, 255, 255); -QColor monRxText = qRgb(0, 0, 255); -QColor monTxText = qRgb(255, 0, 0); -QColor monOtherText = qRgb(0, 0, 0); - -QColor termBackground = qRgb(255, 0, 255); -QColor outputText = qRgb(0, 0, 0); -QColor EchoText = qRgb(0, 0, 255); -QColor WarningText = qRgb(255, 0, 0); -QColor inputBackground = qRgb(255, 255, 0); -QColor inputText = qRgb(0, 0, 255); - -QColor newTabText = qRgb(255, 0, 0); // Red -QColor oldTabText = qRgb(0, 0, 0); // Black - - -// There is something odd about this. It doesn't match BPQTERMTCP though it looks the same - -// Chat uses these (+ 10) -//{ 0, 4, 9, 11, 13, 16, 17, 42, 45, 50, 61, 64, 66, 72, 81, 84, 85, 86, 87, 89 }; - -// As we have a white background we need dark colours - -// 0 is black. 23 is normal output (blue) 81 is red (used by AGW Mon) -// for monitor in colour, host sends 17 for RX Text, 81 for TX Text but code converts to monRx/TxText qrgb values - -QRgb Colours[256] = { 0, - qRgb(0,0,0), qRgb(0,0,128), qRgb(0,0,192), qRgb(0,0,255), // 1 - 4 - qRgb(0,64,0), qRgb(0,64,128), qRgb(0,64,192), qRgb(0,64,255), // 5 - 8 - qRgb(0,128,0), qRgb(0,128,128), qRgb(0,128,192), qRgb(0,128,255), // 9 - 12 - qRgb(0,192,0), qRgb(0,192,128), qRgb(0,192,192), qRgb(0,192,255), // 13 - 16 - qRgb(0,255,0), qRgb(0,255,128), qRgb(0,255,192), qRgb(0,255,255), // 17 - 20 - - qRgb(64,0,0), qRgb(64,0,128), qRgb(64,0,192), qRgb(0,0,255), // 21 - qRgb(64,64,0), qRgb(64,64,128), qRgb(64,64,192), qRgb(64,64,255), - qRgb(64,128,0), qRgb(64,128,128), qRgb(64,128,192), qRgb(64,128,255), - qRgb(64,192,0), qRgb(64,192,128), qRgb(64,192,192), qRgb(64,192,255), - qRgb(64,255,0), qRgb(64,255,128), qRgb(64,255,192), qRgb(64,255,255), - - qRgb(128,0,0), qRgb(128,0,128), qRgb(128,0,192), qRgb(128,0,255), // 41 - qRgb(128,64,0), qRgb(128,64,128), qRgb(128,64,192), qRgb(128,64,255), - qRgb(128,128,0), qRgb(128,128,128), qRgb(128,128,192), qRgb(128,128,255), - qRgb(128,192,0), qRgb(128,192,128), qRgb(128,192,192), qRgb(128,192,255), - qRgb(128,255,0), qRgb(128,255,128), qRgb(128,255,192), qRgb(128,255,255), - - qRgb(192,0,0), qRgb(192,0,128), qRgb(192,0,192), qRgb(192,0,255), // 61 - 80 - qRgb(192,64,0), qRgb(192,64,128), qRgb(192,64,192), qRgb(192,64,255), - qRgb(192,128,0), qRgb(192,128,128), qRgb(192,128,192), qRgb(192,128,255), - qRgb(192,192,0), qRgb(192,192,128), qRgb(192,192,192), qRgb(192,192,255), - qRgb(192,255,0), qRgb(192,255,128), qRgb(192,255,192), qRgb(192,255,255), - - qRgb(255,0,0), qRgb(255,0,128), qRgb(255,0,192), qRgb(255,0,255), // 81 - 100 - qRgb(255,64,0), qRgb(255,64,128), qRgb(255,64,192), qRgb(255,64,255), - qRgb(255,128,0), qRgb(255,128,128), qRgb(255,128,192), qRgb(255,128,255), - qRgb(255,192,0), qRgb(255,192,128), qRgb(255,192,192), qRgb(255,192,255), - qRgb(255,255,0), qRgb(255,255,128), qRgb(255,255,192), qRgb(255,255,255) -}; - - - -int SavedHost = 0; // from config - -char * sessionList = NULL; // Saved sessions - -extern int ChatMode; -extern int Bells; -extern int StripLF; -extern int convUTF8; - -extern time_t LastWrite; -extern int AlertInterval; -extern int AlertBeep; -extern int AlertFreq; -extern int AlertDuration; -extern int ConnectBeep; - -extern int AutoTeletext; - -// AGW Host Interface stuff - -int AGWEnable = 0; -int AGWMonEnable = 0; -char AGWTermCall[12] = ""; -char AGWBeaconDest[12] = ""; -char AGWBeaconPath[80] = ""; -int AGWBeaconInterval = 0; -char AGWBeaconPorts[80]; -char AGWBeaconMsg[260] = ""; - -char AGWHost[128] = "127.0.0.1"; -int AGWPortNum = 8000; -int AGWPaclen = 80; -extern char * AGWPortList; -extern myTcpSocket * AGWSock; - -QStringList AGWToCalls; - -// KISS Interface - -int KISSEnable = 0; -char SerialPort[80] = ""; -char KISSHost[128] = "127.0.0.1"; -int KISSPortNum = 1000; -int KISSBAUD = 19200; -char MYCALL[32]; -extern "C" UCHAR axMYCALL[7]; // Mycall in ax.25 - -int KISSMode = 0; // Connected (0) or UI (1) - -myTcpSocket * KISSSock; - -extern "C" void * KISSSockCopy[4]; - -int KISSConnected = 0; -int KISSConnecting = 0; - -Ui_ListenSession * KISSMonSess; - -QSerialPort * m_serial = nullptr; - -// VARA Interface - -int VARAEnable = 0; -char VARAHost[128] = "127.0.0.1"; -char VARAHostHF[128] = "127.0.0.1"; -char VARAHostFM[128] = "127.0.0.1"; -char VARAHostSAT[128] = "127.0.0.1"; -int VARAPortNum = 8000; -int VARAPortHF = 8000; -int VARAPortFM = 8000; -int VARAPortSAT = 8000; -char VARATermCall[12] = ""; -char VARAPath[256] = ""; -char VARAInit[256] = ""; -char VARAPathHF[256] = ""; -char VARAPathFM[256] = ""; -char VARAPathSAT[256] = ""; - -int VARA500 = 0; -int VARA2300 = 1; -int VARA2750 = 0; - -int VARAHF = 1; -int VARAFM = 0; -int VARASAT = 0; - -myTcpSocket * VARASock; -myTcpSocket * VARADataSock; - -int VARAConnected = 0; -int VARAConnecting = 0; - - -extern char YAPPPath[256]; - -void menuChecked(QAction * Act); - -// PTT Stuff - -#define PTTRTS 1 -#define PTTDTR 2 -#define PTTCAT 4 -#define PTTCM108 8 -#define PTTHAMLIB 16 -#define PTTFLRIG 32 - -#ifdef USESERIAL - -QSerialPort * hPTTDevice = 0; -#else - - -#endif -char PTTPort[80] = ""; // Port for Hardware PTT - may be same as control port. -int PTTBAUD = 19200; -int PTTMode = PTTRTS; // PTT Control Flags. - -char PTTOnString[128] = ""; -char PTTOffString[128] = ""; - -int CATHex = 1; - -unsigned char PTTOnCmd[64]; -int PTTOnCmdLen = 0; - -unsigned char PTTOffCmd[64]; -int PTTOffCmdLen = 0; - -int pttGPIOPin = 17; // Default -int pttGPIOPinR = 17; -bool pttGPIOInvert = false; -bool useGPIO = false; -bool gotGPIO = false; - -int HamLibPort = 4532; -char HamLibHost[32] = "192.168.1.14"; - -int FLRigPort = 12345; -char FLRigHost[32] = "127.0.0.1"; - - -char CM108Addr[80] = ""; - -int VID = 0; -int PID = 0; - -// CM108 Code - -char * CM108Device = NULL; - -QProcess *process = NULL; - -void GetSettings(); - -// These widgets defined here as they are accessed from outside the framework - -QLabel * Status1; -QLabel * Status2; -QLabel * Status3; -QLabel * Status4; - -QAction *actHost[19]; -QAction *actSetup[16]; - -QAction * TabSingle = NULL; -QAction * TabBoth = NULL; -QAction * TabMon = NULL; - -QMenu *monitorMenu; -QMenu * YAPPMenu; -QMenu *connectMenu; -QMenu *disconnectMenu; - -QAction *MonTX; -QAction *MonSup; -QAction *MonNodes; -QAction *MonUI; -QAction *MonColour; -QAction *MonPort[65]; -QAction *actChatMode; -QAction *actAutoTeletext; -QAction *actBells; -QAction *actStripLF; -QAction *actIntervalBeep; -QAction *actConnectBeep; -QAction *actAuto; -QAction *actnoConv; -QAction *actCP1251; -QAction *actCP1252; -QAction *actCP437; - -QAction *actFonts; -QAction *actmenuFont; -QAction *actColours; -QAction *actmyFonts; -QAction *YAPPSend; -QAction *YAPPSetRX; -QAction *singleAct; -QAction *singleAct2; -QAction *MDIAct; -QAction *tabbedAct; -QAction *discAction; -QFont * menufont; -QMenu *windowMenu; -QMenu *setupMenu; -QAction *ListenAction; - -QTabWidget *tabWidget; -QMdiArea *mdiArea; -QWidget * mythis; -QStatusBar * myStatusBar; - -QTcpServer * _server; - -QMenuBar *mymenuBar; -QToolBar *toolBar; -QToolButton * but1; -QToolButton * but2; -QToolButton * but3; -QToolButton * but4; -QToolButton * but5; - -QList _sessions; - -// Session Type Equates - -#define Term 1 -#define Mon 2 -#define Listen 4 - -int TabType[10] = { Term, Term + Mon, Term, Term, Term, Term, Mon, Mon, Mon }; - -int listenPort = 8015; -extern "C" int listenEnable; -char listenCText[4096] = ""; - -int ConfigHost = 0; - -int Split = 50; // Mon/Term size split - -int termX; - -bool Cascading = false; // Set to stop size being saved when cascading - -QMdiSubWindow * ActiveSubWindow = NULL; -Ui_ListenSession * ActiveSession = NULL; - -Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label = nullptr); -void Send_AGW_C_Frame(Ui_ListenSession * Sess, int Port, char * CallFrom, char * CallTo, char * Data, int DataLen); -void AGW_AX25_data_in(void * AX25Sess, unsigned char * data, int Len); -void AGWMonWindowClosing(Ui_ListenSession *Sess); -void AGWWindowClosing(Ui_ListenSession *Sess); -extern "C" void KISSDataReceived(void * socket, unsigned char * data, int length); -void closeSerialPort(); - -extern void initUTF8(); -int checkUTF8(unsigned char * Msg, int Len, unsigned char * out); - -#include -#include -#include - - - - -void EncodeSettingsLine(int n, char * String) -{ - sprintf(String, "%s|%d|%s|%s|%s|%s", Host[n], Port[n], UserName[n], Password[n], MonParams[n], SessName[n]); - return; -} - -// This is used for placing discAction in the preference menu -#ifdef __APPLE__ -bool is_mac = true; -#else -bool is_mac = false; -#endif - -QString GetConfPath() -{ - std::string conf_path = "QtTermTCP.ini"; // Default conf file stored alongside application. - -#ifdef __APPLE__ - - // Get configuration path for MacOS. - - // This will usually be placed in /Users/USER/Library/Application Support/QtTermTCP - - std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString(); - - conf_path = directory + "/QtTermTCP.ini"; - - mkdir(directory.c_str(), 0775); - -#endif - - return QString::fromUtf8(conf_path.c_str()); - -} - - - -void DecodeSettingsLine(int n, char * String) -{ - char * Param = strdup(String); - char * Rest; - char * Save = Param; // for Free - - Rest = strlop(Param, '|'); - - if (Rest == NULL) - return; - - strcpy(Host[n], Param); - Param = Rest; - - Rest = strlop(Param, '|'); - Port[n] = atoi(Param); - Param = Rest; - - Rest = strlop(Param, '|'); - strcpy(UserName[n], Param); - Param = Rest; - - Rest = strlop(Param, '|'); - strcpy(Password[n], Param); - Param = Rest; - - Rest = strlop(Param, '|'); - strcpy(MonParams[n], Param); - - if (Rest) - strcpy(SessName[n], Rest); - - free(Save); - return; -} - -//#ifdef ANDROID -//#define inputheight 60 -//#else -#define inputheight 25 -//#endif - -extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len); - -void DoTermResize(Ui_ListenSession * Sess) -{ - - QRect r = Sess->rect(); - - int H, Mid, monHeight, termHeight, Width, Border = 3; - - Width = r.width(); - H = r.height(); - - if (TermMode == Tabbed) - { - // H -= 20; - Width -= 7; - } - else if (TermMode == Single) - { - Width -= 7; - // H += 20; - } - - if (Sess->SessionType == Listen || Sess->SessionType == Term) - { - // Term and Input - - // Calc Positions of window - - termHeight = H - (inputheight + 3 * Border); - - Sess->termWindow->setGeometry(QRect(Border, Border, Width, termHeight)); - - if (Sess->TTActive) - { - Sess->TTLabel->setGeometry(QRect(Border, Border, 600, 475)); -// Sess->termWindow->setVisible(false); - Sess->TTLabel->setVisible(true); - } - else - { -// Sess->termWindow->setVisible(true); - Sess->TTLabel->setVisible(false); - } - - Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); - } - else if (Sess->SessionType == (Term | Mon)) - { - // All 3 - - // Calc Positions of window - - Mid = (H * Split) / 100; - - monHeight = Mid - Border; - termX = Mid; - termHeight = H - Mid - (inputheight + 3 * Border); - - Sess->monWindow->setGeometry(QRect(Border, Border, Width, monHeight)); - Sess->termWindow->setGeometry(QRect(Border, Mid + Border, Width, termHeight)); - - if (Sess->TTActive) - { - Sess->TTLabel->setGeometry(QRect(3, Mid + Border, 600, 475)); -// Sess->termWindow->setVisible(false); - Sess->TTLabel->setVisible(true); - } - else - { -// Sess->termWindow->setVisible(true); - Sess->TTLabel->setVisible(false); - } - - Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); - - } - else - { - // Should just be Mon only - - Sess->monWindow->setGeometry(QRect(Border, Border, Width, H - 2 * Border)); - } -} - -bool QtTermTCP::eventFilter(QObject* obj, QEvent *event) -{ - // See if from a Listening Session - - Ui_ListenSession * Sess; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - // Sess = _sessions.at(i); for (Ui_ListenSession * Sess : _sessions) - // { - if (Sess == NULL) - continue; - - if (Sess == obj) - { - if (event->type() == QEvent::Close) - { - // Window closing - - // This only closed mon sessinos - - if (Sess->AGWMonSession) - // AGWMonWindowClosing(Sess); - AGWWindowClosing(Sess); - - if (Sess->AGWSession) - AGWWindowClosing(Sess); - - if (Sess->clientSocket) - { - int loops = 100; - Sess->clientSocket->disconnectFromHost(); - while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState) - QThread::msleep(10); - } - _sessions.removeOne(Sess); - return QMainWindow::eventFilter(obj, event); - } - - if (event->type() == QEvent::Resize) - { - DoTermResize(Sess); - } - } - - if (Sess->inputWindow == obj) - { - if (event->type() == QEvent::KeyPress) - { - QKeyEvent* keyEvent = static_cast(event); - - int key = keyEvent->key(); - Qt::KeyboardModifiers modifier = keyEvent->modifiers(); - - if (modifier == Qt::ControlModifier) - { - char Msg[] = "\0\r"; - - if (key == Qt::Key_BracketLeft) - Msg[0] = 0x1b; - if (key == Qt::Key_Z) - Msg[0] = 0x1a; - else if (key == Qt::Key_C) - Msg[0] = 3; - else if (key == Qt::Key_D) - Msg[0] = 4; - - if (Msg[0]) - { - if (Sess->KISSSession) - { - // Send to ax.25 code - - SendtoAX25(Sess->KISSSession, (unsigned char *)Msg, (int)strlen(Msg)); - } - else if (Sess->AGWSession) - { - // Terminal is in AGWPE mode - send as AGW frame - - AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Msg, (int)strlen(Msg)); - - } - else if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) - { - Sess->clientSocket->write(Msg); - } - - return true; - } - } - - if (key == Qt::Key_Up) - { - // Scroll up - - if (Sess->KbdStack[Sess->StackIndex] == NULL) - return true; - - // If anything typed, stack part command - - QByteArray stringData = Sess->inputWindow->text().toUtf8(); - - if (stringData.length() && Sess->StackIndex == 0) - { - if (Sess->KbdStack[49]) - free(Sess->KbdStack[49]); - - for (int i = 48; i >= 0; i--) - { - Sess->KbdStack[i + 1] = Sess->KbdStack[i]; - } - - Sess->KbdStack[0] = qstrdup(stringData.data()); - Sess->StackIndex++; - } - - Sess->inputWindow->setText(Sess->KbdStack[Sess->StackIndex]); - Sess->inputWindow->cursorForward(strlen(Sess->KbdStack[Sess->StackIndex])); - - Sess->StackIndex++; - if (Sess->StackIndex == 50) - Sess->StackIndex = 49; - - return true; - } - else if (key == Qt::Key_Down) - { - // Scroll down - - if (Sess->StackIndex == 0) - { - Sess->inputWindow->setText(""); - return true; - } - - Sess->StackIndex--; - - if (Sess->StackIndex && Sess->KbdStack[Sess->StackIndex - 1]) - { - Sess->inputWindow->setText(Sess->KbdStack[Sess->StackIndex - 1]); - Sess->inputWindow->cursorForward(strlen(Sess->KbdStack[Sess->StackIndex - 1])); - } - else - Sess->inputWindow->setText(""); - - return true; - } - else if (key == Qt::Key_Return || key == Qt::Key_Enter) - { - LreturnPressed(Sess); - return true; - } - - return false; - } - - if (event->type() == QEvent::MouseButtonPress) - { - QMouseEvent *k = static_cast (event); - - // Paste on Right Click - - if (k->button() == Qt::RightButton) - { - Sess->inputWindow->paste(); - return true; - } - return QMainWindow::eventFilter(obj, event); - } - } - } - return QMainWindow::eventFilter(obj, event); -} - -QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State) -{ - QAction * Act = new QAction(Label, parent); - if (Menu) - Menu->addAction(Act); - - Act->setCheckable(true); - if (State) - Act->setChecked(true); - - parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked())); - - Act->setFont(*menufont); - - return Act; -} - -// This now creates all window types - Term, Mon, Combined, Listen - -int xCount = 0; - -Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label) -{ - Ui_ListenSession * Sess = new(Ui_ListenSession); - - // Need to explicity initialise on Qt4 - - Sess->termWindow = NULL; - Sess->monWindow = NULL; - Sess->inputWindow = NULL; - - for (int i = 0; i < 50; i++) - Sess->KbdStack[i] = NULL; - - Sess->StackIndex = 0; - Sess->InputMode = 0; - Sess->SlowTimer = 0; - Sess->MonData = 0; - Sess->OutputSaveLen = 0; - Sess->MonSaveLen = 0; - Sess->PortMonString[0] = 0; - Sess->portmask = 0; - Sess->portmask = 1; - Sess->mtxparam = 1; - Sess->mcomparam = 1; - Sess->monUI = 0; - Sess->MonitorNODES = 0; - Sess->MonitorColour = 1; - Sess->CurrentHost = 0; - - Sess->SessionType = Type; - Sess->clientSocket = NULL; - Sess->AGWSession = NULL; - Sess->AGWMonSession = NULL; - Sess->KISSSession = NULL; - Sess->KISSMode = 0; - Sess->TTActive = 0; - Sess->TTFlashToggle = 0; - Sess->pageBuffer[0] = 0; - - _sessions.push_back(Sess); - -// Sess->TT = new Ui_TeleTextDialog(); - -// Sess->TT->setupUi(&Sess->TTUI); - -// Sess->TTUI.show(); -// Sess->TTUI.raise(); -// Sess->TTUI.activateWindow(); - - // Sess->setObjectName(QString::fromUtf8("Sess")); - - if (TermMode == MDI) - { - Sess->sw = mdiArea->addSubWindow(Sess); - // Sess->installEventFilter(parent); - - Sess->sw->resize(800, 600); - } - else if (TermMode == Tabbed) - { - Sess->Tab = xCount++; - - if (Type == Mon) - tabWidget->addTab(Sess, "Monitor"); - else - tabWidget->addTab(Sess, Label); - } - - Sess->installEventFilter(parent); - - QSettings settings(GetConfPath(), QSettings::IniFormat); - -#ifdef ANDROID - QFont font = QFont(settings->value("FontFamily", "Driod Sans Mono").value(), - settings->value("PointSize", 12).toInt(), - settings->value("Weight", 50).toInt()); -#else - QFont font = QFont(settings.value("FontFamily", "Courier New").value(), - settings.value("PointSize", 10).toInt(), - settings.value("Weight", 50).toInt()); -#endif - - if ((Type & Mon)) - { - Sess->monWindow = new QTextEdit(Sess); - Sess->monWindow->setReadOnly(1); - Sess->monWindow->document()->setMaximumBlockCount(10000); - Sess->monWindow->setFont(font); - Sess->monWindow->setStyleSheet(monStyleSheet); - mythis->connect(Sess->monWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged())); - } - - if ((Type & (Listen | Term))) - { - Sess->termWindow = new QTextEdit(Sess); - Sess->termWindow->setReadOnly(1); - Sess->termWindow->document()->setMaximumBlockCount(10000); - Sess->termWindow->setFont(font); - Sess->termWindow->setStyleSheet(termStyleSheet); - - Sess->TTLabel = new QLabel(Sess); - Sess->TTLabel->setGeometry(QRect(0,0 ,500, 500)); - Sess->TTLabel->setVisible(false); - - Sess->TTBitmap = new QImage(40 * 15, 25 * 19, QImage::Format_RGB32); - Sess->TTBitmap->fill(Qt::black); - -/* - - char Page[4096]; - - QFile file("/savepage.txt"); - file.open(QIODevice::ReadOnly); - file.read(Page, 4096); - file.close(); - - Sess->TTActive = 1; - strcpy(Sess->pageBuffer, Page); - DecodeTeleText(Sess, Sess->pageBuffer); - -*/ - - Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); - - Sess->TTLabel->setContextMenuPolicy(Qt::CustomContextMenu); - mythis->connect(Sess->TTLabel, SIGNAL(customContextMenuRequested(const QPoint&)), - parent, SLOT(showContextMenuL())); - - mythis->connect(Sess->termWindow, SIGNAL(selectionChanged()), parent, SLOT(onTEselectionChanged())); - - Sess->inputWindow = new QLineEdit(Sess); - Sess->inputWindow->installEventFilter(parent); - Sess->inputWindow->setFont(font); - Sess->inputWindow->setStyleSheet(inputStyleSheet); - Sess->inputWindow->setContextMenuPolicy(Qt::PreventContextMenu); - - mythis->connect(Sess->inputWindow, SIGNAL(selectionChanged()), parent, SLOT(onLEselectionChanged())); - } - - if (Type == Term || Type == Listen) - { - // Term Only or Listen Only - - Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu); - - mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)), - parent, SLOT(showContextMenuT(const QPoint &))); - - } - - if (Type == Mon) - { - // Monitor Only - - Sess->monWindow->setContextMenuPolicy(Qt::CustomContextMenu); - - mythis->connect(Sess->monWindow, SIGNAL(customContextMenuRequested(const QPoint&)), - parent, SLOT(showContextMenuMOnly(const QPoint &))); - - } - - if (Type == (Term | Mon)) - { - // Combined Term and Mon. Add Custom Menu to set Mon/Term Split with Right Click - - Sess->monWindow->setContextMenuPolicy(Qt::CustomContextMenu); - Sess->termWindow->setContextMenuPolicy(Qt::CustomContextMenu); - - - mythis->connect(Sess->monWindow, SIGNAL(customContextMenuRequested(const QPoint&)), - parent, SLOT(showContextMenuM(const QPoint &))); - - mythis->connect(Sess->termWindow, SIGNAL(customContextMenuRequested(const QPoint&)), - parent, SLOT(showContextMenuMT(const QPoint &))); - } - - if (Sess->SessionType == Mon) // Mon Only - Sess->setWindowTitle("Monitor Session Disconnected"); - else if (Sess->SessionType == Listen) // Mon Only - Sess->setWindowTitle("Listen Window Disconnected"); - else - Sess->setWindowTitle("Disconnected"); - - Sess->installEventFilter(mythis); - - Sess->show(); - - int pos = (_sessions.size() - 1) * 20; - - if (TermMode == MDI) - { - Sess->sw->move(pos, pos); - } - - QSize Size(800, 602); // Not actually used, but Event constructor needs it - - QResizeEvent event(Size, Size); - - QApplication::sendEvent(Sess, &event); // Resize Widgets to fix Window - - return Sess; -} - -QtTermTCP::QtTermTCP(QWidget *parent) : QMainWindow(parent) -{ - int i; - char Title[80]; - - // Get configuration path for MacOS. - std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString(); - std::string conf_path = directory + "/QtTermTCP.ini"; - - //mkdir(directory.c_str(), 0775); - - _server = new QTcpServer(); - - mythis = this; - - ui.setupUi(this); - - initUTF8(); - - mymenuBar = new QMenuBar(this); - mymenuBar->setGeometry(QRect(0, 0, 781, 26)); - setMenuBar(mymenuBar); - - toolBar = new QToolBar(this); - toolBar->setObjectName("mainToolbar"); - addToolBar(Qt::BottomToolBarArea, toolBar); - - QSettings mysettings(GetConfPath(), QSettings::IniFormat); - - restoreGeometry(mysettings.value("geometry").toByteArray()); - restoreState(mysettings.value("windowState").toByteArray()); - - GetSettings(); - - // Set background colours - - sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);", - monBackground.red(), monBackground.green(), monBackground.blue()); - - sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);", - termBackground.red(), termBackground.green(), termBackground.blue()); - - sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", - inputText.red(), inputText.green(), inputText.blue(), - inputBackground.red(), inputBackground.green(), inputBackground.blue()); - - -#ifdef ANDROID - menufont = new QFont(mysettings.value("MFontFamily", "Driod Sans").value(), - mysettings.value("MPointSize", 12).toInt(), - mysettings.value("MWeight", 50).toInt()); -#else - menufont = new QFont(mysettings.value("MFontFamily", "Aerial").value(), - mysettings.value("MPointSize", 10).toInt(), - mysettings.value("MWeight", 50).toInt()); - -#endif - if (TermMode == MDI) - { - mdiArea = new QMdiArea(ui.centralWidget); - - mdiArea->setGeometry(QRect(0, 0, 771, 571)); - - mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - - connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(xon_mdiArea_changed())); - - setCentralWidget(mdiArea); - } - else if (TermMode == Tabbed) - { - tabWidget = new QTabWidget(this); - - ui.verticalLayout->addWidget(tabWidget); - - tabWidget->setTabPosition(QTabWidget::South); - - newWindow(this, TabType[0], "Sess 1"); - newWindow(this, TabType[1], "Sess 2"); - newWindow(this, TabType[2], "Sess 3"); - newWindow(this, TabType[3], "Sess 4"); - newWindow(this, TabType[4], "Sess 5"); - newWindow(this, TabType[5], "Sess 6"); - newWindow(this, TabType[6], "Sess 7"); - newWindow(this, TabType[7], "Monitor"); - newWindow(this, TabType[8], "Monitor"); - - ActiveSession = _sessions.at(0); - - connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSelected(int))); - - tabWidget->setFont(*menufont); - - } - - sprintf(Title, "QtTermTCP Version %s", VersionString); - - this->setWindowTitle(Title); - - //#ifdef ANDROID - // mymymenuBar->setVisible(false); - //#endif - - if (TermMode == Single) - windowMenu = mymenuBar->addMenu(""); - else - windowMenu = mymenuBar->addMenu(tr("&Window")); - - connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu())); - windowMenu->setFont(*menufont); - - newTermAct = new QAction(tr("New Terminal Window"), this); - connect(newTermAct, SIGNAL(triggered()), this, SLOT(doNewTerm())); - - newMonAct = new QAction(tr("New Monitor Window"), this); - connect(newMonAct, SIGNAL(triggered()), this, SLOT(doNewMon())); - - newCombinedAct = new QAction(tr("New Combined Term/Mon Window"), this); - connect(newCombinedAct, SIGNAL(triggered()), this, SLOT(doNewCombined())); - - if (TermMode == MDI) - { - closeAct = new QAction(tr("Cl&ose"), this); - closeAct->setStatusTip(tr("Close the active window")); - connect(closeAct, SIGNAL(triggered()), mdiArea, SLOT(closeActiveSubWindow())); - - closeAllAct = new QAction(tr("Close &All"), this); - closeAllAct->setStatusTip(tr("Close all the windows")); - connect(closeAllAct, SIGNAL(triggered()), mdiArea, SLOT(closeAllSubWindows())); - - tileAct = new QAction(tr("&Tile"), this); - tileAct->setStatusTip(tr("Tile the windows")); - connect(tileAct, SIGNAL(triggered()), mdiArea, SLOT(tileSubWindows())); - - cascadeAct = new QAction(tr("&Cascade"), this); - cascadeAct->setStatusTip(tr("Cascade the windows")); - connect(cascadeAct, SIGNAL(triggered()), this, SLOT(doCascade())); - - nextAct = new QAction(tr("Ne&xt"), this); - nextAct->setShortcuts(QKeySequence::NextChild); - nextAct->setStatusTip(tr("Move the focus to the next window")); - connect(nextAct, SIGNAL(triggered()), mdiArea, SLOT(activateNextSubWindow())); - - previousAct = new QAction(tr("Pre&vious"), this); - previousAct->setShortcuts(QKeySequence::PreviousChild); - previousAct->setStatusTip(tr("Move the focus to the previous window")); - connect(previousAct, SIGNAL(triggered()), mdiArea, SLOT(activatePreviousSubWindow())); - } - - quitAction = new QAction(tr("&Quit"), this); - connect(quitAction, SIGNAL(triggered()), this, SLOT(doQuit())); - - windowMenuSeparatorAct = new QAction(this); - windowMenuSeparatorAct->setSeparator(true); - - updateWindowMenu(); - - connectMenu = mymenuBar->addMenu(tr("&Connect")); - - actHost[16] = new QAction("AGW Connect", this); - actHost[16]->setFont(*menufont); - actHost[16]->setVisible(0); - connectMenu->addAction(actHost[16]); - - connect(actHost[16], SIGNAL(triggered()), this, SLOT(Connect())); - - actHost[17] = new QAction("VARA Connect", this); - actHost[17]->setFont(*menufont); - actHost[17]->setVisible(0); - connectMenu->addAction(actHost[17]); - - connect(actHost[17], SIGNAL(triggered()), this, SLOT(Connect())); - - actHost[18] = new QAction("KISS Connect", this); - actHost[18]->setFont(*menufont); - actHost[18]->setVisible(KISSEnable); - actHost[18]->setEnabled(0); - connectMenu->addAction(actHost[18]); - - connect(actHost[18], SIGNAL(triggered()), this, SLOT(Connect())); - - for (i = 0; i < MAXHOSTS; i++) - { - if (SessName[i][0]) - { - char Lable[256]; - sprintf(Lable, "%s(%s)", Host[i], SessName[i]); - actHost[i] = new QAction(Lable, this); - } - else - actHost[i] = new QAction(Host[i], this); - - actHost[i]->setFont(*menufont); - connectMenu->addAction(actHost[i]); - connect(actHost[i], SIGNAL(triggered()), this, SLOT(Connect())); - } - - discAction = mymenuBar->addAction("&Disconnect"); - - // Place discAction in mac preferences menu, otherwise it doesn't appear - if (is_mac == true) { - QMenu * app_menu = mymenuBar->addMenu("App Menu"); - discAction->setMenuRole(QAction::ApplicationSpecificRole); - app_menu->addAction(discAction); - - } - - connect(discAction, SIGNAL(triggered()), this, SLOT(Disconnect())); - discAction->setEnabled(false); - - toolBar->setFont(*menufont); - -#ifndef ANDROID - toolBar->setVisible(false); -#endif - but4 = new QToolButton(); - but4->setPopupMode(QToolButton::InstantPopup); - but4->setText("Window"); - but4->addAction(windowMenu->menuAction()); - but4->setFont(*menufont); - toolBar->addWidget(but4); - - but5 = new QToolButton(); - but5->setPopupMode(QToolButton::InstantPopup); - but5->setText("Connect"); - but5->addAction(connectMenu->menuAction()); - but5->setFont(*menufont); - - toolBar->addWidget(but5); - - toolBar->addAction(discAction); - - setupMenu = mymenuBar->addMenu(tr("&Setup")); - hostsubMenu = setupMenu->addMenu("Hosts"); - hostsubMenu->setFont(*menufont); - - for (i = 0; i < MAXHOSTS; i++) - { - if (Host[i][0]) - { - char Label[256]; - - if (SessName[i][0]) - sprintf(Label, "%s(%s)", Host[i], SessName[i]); - else - strcpy(Label, Host[i]); - - actSetup[i] = new QAction(Label, this); - } - else - actSetup[i] = new QAction("New Host", this); - - hostsubMenu->addAction(actSetup[i]); - connect(actSetup[i], SIGNAL(triggered()), this, SLOT(SetupHosts())); - - actSetup[i]->setFont(*menufont); - } - - - // Setup Presentation Options - - setupMenu->addSeparator()->setText(tr("Presentation")); - - QActionGroup * termGroup = new QActionGroup(this); - - singleAct = setupMenuLine(nullptr, (char *)"Single Window (Term + Mon)", this, (TermMode == Single) && (singlemodeFormat == Term + Mon)); - singleAct2 = setupMenuLine(nullptr, (char *)"Single Window (Term only)", this, (TermMode == Single) && (singlemodeFormat == Term)); - MDIAct = setupMenuLine(nullptr, (char *)"MDI", this, TermMode == MDI); - tabbedAct = setupMenuLine(nullptr, (char *)"Tabbed", this, TermMode == Tabbed); - - termGroup->addAction(singleAct); - termGroup->addAction(singleAct2); - termGroup->addAction(MDIAct); - termGroup->addAction(tabbedAct); - - setupMenu->addAction(singleAct); - setupMenu->addAction(singleAct2); - setupMenu->addAction(MDIAct); - setupMenu->addAction(tabbedAct); - - setupMenu->addSeparator(); - - actFonts = new QAction("Terminal Font", this); - setupMenu->addAction(actFonts); - connect(actFonts, SIGNAL(triggered()), this, SLOT(doFonts())); - actFonts->setFont(*menufont); - - actmenuFont = new QAction("Menu Font", this); - setupMenu->addAction(actmenuFont); - connect(actmenuFont, SIGNAL(triggered()), this, SLOT(doMFonts())); - actmenuFont->setFont(*menufont); - - actColours = new QAction("Choose Colours", this); - setupMenu->addAction(actColours); - connect(actColours, SIGNAL(triggered()), this, SLOT(doColours())); - actColours->setFont(*menufont); - - AGWAction = new QAction("AGW Setup", this); - setupMenu->addAction(AGWAction); - connect(AGWAction, SIGNAL(triggered()), this, SLOT(AGWSlot())); - AGWAction->setFont(*menufont); - - VARAAction = new QAction("VARA Setup", this); - setupMenu->addAction(VARAAction); - connect(VARAAction, SIGNAL(triggered()), this, SLOT(VARASlot())); - VARAAction->setFont(*menufont); - - KISSAction = new QAction("KISS Setup", this); - setupMenu->addAction(KISSAction); - connect(KISSAction, SIGNAL(triggered()), this, SLOT(KISSSlot())); - KISSAction->setFont(*menufont); - - - actChatMode = setupMenuLine(setupMenu, (char *)"Chat Terminal Mode", this, ChatMode); - actAutoTeletext = setupMenuLine(setupMenu, (char *)"Auto switch to Teletext", this, AutoTeletext); - actBells = setupMenuLine(setupMenu, (char *)"Enable Bells", this, Bells); - actStripLF = setupMenuLine(setupMenu, (char *)"Strip Line Feeds", this, StripLF); - actIntervalBeep = setupMenuLine(setupMenu, (char *)"Beep after inactivity", this, AlertBeep); - actConnectBeep = setupMenuLine(setupMenu, (char *)"Beep on inbound connect", this, ConnectBeep); - - setupMenu->addAction(new QAction("Interpret non-UTF8 input as:", this)); - setupMenu->setFont(*menufont); - - QActionGroup * cpGroup = new QActionGroup(this); - - actnoConv = setupMenuLine(nullptr, (char *)" Don't Convert (assume is UTF-8)", this, convUTF8 == -1); - actAuto = setupMenuLine(nullptr, (char *)" Auto", this, convUTF8 == 0); - actCP1251 = setupMenuLine(nullptr, (char *)" CP1251 (Cyrillic)", this, convUTF8 == 1251); - actCP1252 = setupMenuLine(nullptr, (char *)" CP1252 (Western Europe)", this, convUTF8 == 1252); - actCP437 = setupMenuLine(nullptr, (char *)" CP437 (Windows Line Draw)", this, convUTF8 == 437); - - cpGroup->addAction(actnoConv); - cpGroup->addAction(actAuto); - cpGroup->addAction(actCP1251); - cpGroup->addAction(actCP1252); - cpGroup->addAction(actCP437); - - setupMenu->addAction(actnoConv); - setupMenu->addAction(actAuto); - setupMenu->addAction(actCP1251); - setupMenu->addAction(actCP1252); - setupMenu->addAction(actCP437); - - monitorMenu = mymenuBar->addMenu(tr("&Monitor")); - - MonTX = setupMenuLine(monitorMenu, (char *)"Monitor TX", this, 1); - MonSup = setupMenuLine(monitorMenu, (char *)"Monitor Supervisory", this, 1); - MonUI = setupMenuLine(monitorMenu, (char *)"Only Monitor UI Frames", this, 0); - MonNodes = setupMenuLine(monitorMenu, (char *)"Monitor NODES Broadcasts", this, 0); - MonColour = setupMenuLine(monitorMenu, (char *)"Enable Colour", this, 1); - - for (i = 0; i < MAXPORTS + 1; i++) - { - MonPort[i] = setupMenuLine(monitorMenu, (char *)"Port", this, 0); - MonPort[i]->setVisible(false); - } - - but1 = new QToolButton(); - but1->setPopupMode(QToolButton::InstantPopup); - but1->setText("Monitor"); - but1->addAction(monitorMenu->menuAction()); - toolBar->addWidget(but1); - - but2 = new QToolButton(); - but2->setPopupMode(QToolButton::InstantPopup); - but2->setText("Setup"); - but2->addAction(setupMenu->menuAction()); - toolBar->addWidget(but2); - - ListenAction = mymenuBar->addAction("&Listen"); - connect(ListenAction, SIGNAL(triggered()), this, SLOT(ListenSlot())); - - toolBar->addAction(ListenAction); - - YAPPMenu = mymenuBar->addMenu(tr("&YAPP")); - - YAPPSend = new QAction("Send File", this); - YAPPSetRX = new QAction("Set Receive Directory", this); - YAPPSend->setFont(*menufont); - YAPPSetRX->setFont(*menufont); - - YAPPMenu->addAction(YAPPSend); - YAPPMenu->addAction(YAPPSetRX); - YAPPSend->setEnabled(false); - - connect(YAPPSend, SIGNAL(triggered()), this, SLOT(doYAPPSend())); - connect(YAPPSetRX, SIGNAL(triggered()), this, SLOT(doYAPPSetRX())); - - - but3 = new QToolButton(); - but3->setPopupMode(QToolButton::InstantPopup); - but3->setText("YAPP"); - but3->addAction(YAPPMenu->menuAction()); - but3->setFont(*menufont); - toolBar->addWidget(but3); - - toolBar->setFont(*menufont); - - // Set up Status Bar - - setStyleSheet("QStatusBar{border-top: 1px outset black;} QStatusBar::item { border: 1px solid black; border-radius: 3px;}"); - // setStyleSheet("QStatusBar{border-top: 1px outset black;}"); - - - Status4 = new QLabel(""); - Status3 = new QLabel(" "); - Status2 = new QLabel(" "); - Status1 = new QLabel(" Disconnected "); - - Status1->setMinimumWidth(100); - Status2->setMinimumWidth(100); - Status3->setMinimumWidth(100); - Status4->setMinimumWidth(100); - - myStatusBar = statusBar(); - - statusBar()->addPermanentWidget(Status4); - statusBar()->addPermanentWidget(Status3); - statusBar()->addPermanentWidget(Status2); - statusBar()->addPermanentWidget(Status1); - - statusBar()->setVisible(AGWEnable | VARAEnable | KISSEnable); - // Restore saved sessions - - if (TermMode == Single) - { - Ui_ListenSession * Sess = newWindow(this, singlemodeFormat); - - ActiveSession = Sess; - ui.verticalLayout->addWidget(Sess); - - connectMenu->setEnabled(true); - discAction->setEnabled(false); - YAPPSend->setEnabled(false); - } - - if (TermMode == MDI) - { - int n = atoi(sessionList); - - char *p, *Context; - char delim[] = "|"; - - int type = 0, host = 0, topx, leftx, bottomx, rightx; - - p = strtok_s((char *)sessionList, delim, &Context); - - while (n--) - { - p = strtok_s(NULL, delim, &Context); - - sscanf(p, "%d,%d,%d,%d,%d,%d", &type, &host, &topx, &leftx, &bottomx, &rightx); - - Ui_ListenSession * Sess = newWindow(this, type); - - Sess->CurrentHost = host; - - QRect r(leftx, topx, rightx - leftx, bottomx - topx); - - Sess->sw->setGeometry(r); - Sess->sw->move(leftx, topx); - - } - } - - QTimer *timer = new QTimer(this); - connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); - timer->start(10000); - - QTimer *timer2 = new QTimer(this); - connect(timer2, SIGNAL(timeout()), this, SLOT(KISSTimerSlot())); - timer2->start(100); - - // Run timer now to connect to AGW if configured - - MyTimerSlot(); - - if (listenEnable) - _server->listen(QHostAddress::Any, listenPort); - - connect(_server, SIGNAL(newConnection()), this, SLOT(onNewConnection())); - - setFonts(); - - if (VARAEnable) - OpenPTTPort(); - - memset(axMYCALL, 0, 7); - ConvToAX25(MYCALL, axMYCALL); -} - -void QtTermTCP::setFonts() -{ - windowMenu->menuAction()->setFont(*menufont); - connectMenu->menuAction()->setFont(*menufont); - setupMenu->menuAction()->setFont(*menufont); - monitorMenu->menuAction()->setFont(*menufont); - YAPPMenu->menuAction()->setFont(*menufont); - - if (tabWidget) - tabWidget->setFont(*menufont); - mymenuBar->setFont(*menufont); - toolBar->setFont(*menufont); - but1->setFont(*menufont); - but2->setFont(*menufont); - but3->setFont(*menufont); - but4->setFont(*menufont); - but5->setFont(*menufont); - discAction->setFont(*menufont); - ListenAction->setFont(*menufont); - - for (int i = 0; i < MAXHOSTS; i++) - { - actHost[i]->setFont(*menufont); - actSetup[i]->setFont(*menufont); - } - - actHost[16]->setFont(*menufont); // AGW Host -} - -void QtTermTCP::doQuit() -{ - if (_server->isListening()) - _server->close(); - - SaveSettings(); - - QCoreApplication::quit(); -} - -// "Copy on select" Code - - -void QtTermTCP::onTEselectionChanged() -{ - QTextEdit * x = static_cast(QObject::sender()); - x->copy(); -} - -void QtTermTCP::onLEselectionChanged() -{ - QLineEdit * x = static_cast(QObject::sender()); - x->copy(); -} - -void QtTermTCP::setVDMode() -{ - QAction * sender = static_cast(QObject::sender()); - - QTextEdit * window = static_cast(sender->parentWidget()); - - // Need to find session with this window as owner - - Ui_ListenSession * Sess = NULL; - - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - if (Sess->termWindow == window) - { - Sess->TTActive ^= 1; - DoTermResize(Sess); - break; - } - } -} - -int splitY; // Value when menu added - -void QtTermTCP::setSplit() -{ - QAction * sender = static_cast(QObject::sender()); - - QWidget * Parent = sender->parentWidget(); - - if (Parent) - Parent = Parent->parentWidget(); - - int y = Parent->rect().height() - 50; - - // y is height of whole windom. splitX is new split position - // So split = 100 * splitx/x - - Split = (splitY * 100) / y; - - if (Split < 10) - Split = 10; - else if (Split > 90) - Split = 90; - - QSize size(800, 602); - QResizeEvent event(size, size); - - eventFilter(Parent, &event); -} - -void QtTermTCP::ClearScreen() -{ - QAction * sender = static_cast(QObject::sender()); - QTextEdit * window = static_cast(sender->parentWidget()); - window->clear(); -} - - -void QtTermTCP::showContextMenuMT(const QPoint &pt) // Term Window -{ - // Monitor and Terminal (Term Half) - - QTextEdit* sender = static_cast(QObject::sender()); - - QMenu *menu = sender->createStandardContextMenu(); - - QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}QMenu::separator {height: 2px;background: rgb(58, 80, 116);margin-left: 10px;margin-right: 5px;}"; - menu->setStyleSheet(style); - - QAction * actSplit = new QAction("Set Monitor/Output Split", sender); - QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender); - QAction * actClear = new QAction("Clear Screen Buffer", sender); - - menu->addAction(actSplit); - menu->addAction(actVDMode); - menu->addAction(actClear); - - splitY = pt.y() + termX; - - connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit())); - connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode())); - connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); - - menu->exec(sender->mapToGlobal(pt)); - delete menu; -} - -void QtTermTCP::showContextMenuMOnly(const QPoint &pt) -{ - // Monitor only - - QTextEdit* sender = static_cast(QObject::sender()); - - QMenu *menu = sender->createStandardContextMenu(); - - QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}QMenu::separator {height: 2px;background: rgb(58, 80, 116);margin-left: 10px;margin-right: 5px;}"; - menu->setStyleSheet(style); - - QAction * actClear = new QAction("Clear Screen Buffer", sender); - - menu->addAction(actClear); - connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); - - menu->exec(sender->mapToGlobal(pt)); - delete menu; -} - - -void QtTermTCP::showContextMenuT(const QPoint &pt) // Term Window -{ - // Just Terminal - - QTextEdit* sender = static_cast(QObject::sender()); - - QMenu *menu = sender->createStandardContextMenu(); - - QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}"; - menu->setStyleSheet(style); - - - QAction * actVDMode = new QAction("Toggle Viewdata Mode", sender); - QAction * actClear = new QAction("Clear Screen Buffer", sender); - - menu->addAction(actVDMode); - menu->addAction(actClear); - - connect(actVDMode, SIGNAL(triggered()), this, SLOT(setVDMode())); - connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); - - menu->exec(sender->mapToGlobal(pt)); - delete menu; -} - - -void QtTermTCP::showContextMenuL() // Term Window -{ - // Teletext Label Right Clicked - cancel TT Mode - - QLabel * sender = static_cast(QObject::sender()); - - // Need to find session with this label as owner - - Ui_ListenSession * Sess = NULL; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - if (Sess->TTLabel == sender) - { - Sess->TTActive ^= 1; - - DoTermResize(Sess); - break; - } - } -} - - -void QtTermTCP::showContextMenuM(const QPoint &pt) // Mon Window -{ - QTextEdit* sender = static_cast(QObject::sender()); - - QMenu *menu = sender->createStandardContextMenu(); - QString style = "QMenu {border-radius:15px; background-color: white;margin: 2px; border: 1px solid rgb(58, 80, 116); color: rgb(58, 80, 116);}"; - menu->setStyleSheet(style); - - QAction * actSplit = new QAction("Set Monitor/Output Split", sender); - QAction * actClear = new QAction("Clear Screen Buffer", sender); - - menu->addAction(actSplit); - menu->addAction(actClear); - - splitY = pt.y(); - - connect(actSplit, SIGNAL(triggered()), this, SLOT(setSplit())); - connect(actClear, SIGNAL(triggered()), this, SLOT(ClearScreen())); - - menu->exec(sender->mapToGlobal(pt)); - delete menu; -} - -extern "C" void setMenus(int State) -{ - // Sets Connect, Disconnect and YAPP Send enable flags to match connection state - - if (State) - { - connectMenu->setEnabled(false); - discAction->setEnabled(true); - YAPPSend->setEnabled(true); - } - else - { - connectMenu->setEnabled(true); - discAction->setEnabled(false); - YAPPSend->setEnabled(false); - } -} - -extern "C" void SetSessLabel(Ui_ListenSession * Sess, char * label) -{ - if (TermMode == MDI) - Sess->setWindowTitle(label); - else if (TermMode == Tabbed) - tabWidget->setTabText(Sess->Tab, label); - else if (TermMode == Single) - mythis->setWindowTitle(label); -} - - -extern "C" void ClearSessLabel(Ui_ListenSession * Sess) -{ - if (TermMode == MDI) - { - if (Sess->SessionType == Mon) // Mon Only - Sess->setWindowTitle("Monitor Session Disconnected"); - else if (Sess->SessionType == Listen) // Mon Only - Sess->setWindowTitle("Listen Window Disconnected"); - else - Sess->setWindowTitle("Disconnected"); - } - else if (TermMode == Tabbed) - { - if (Sess->SessionType == Mon) // Mon Only - tabWidget->setTabText(Sess->Tab, "Monitor"); - else - { - char Label[16]; - sprintf(Label, "Sess %d", Sess->Tab + 1); - tabWidget->setTabText(Sess->Tab, Label); - } - } - else if (TermMode == Single) - { - if (Sess->SessionType == Mon) // Mon Only - mythis->setWindowTitle("Monitor Session Disconnected"); - else - mythis->setWindowTitle("Disconnected"); - } -} - -void QtTermTCP::tabSelected(int Current) -{ - Ui_ListenSession * Sess = NULL; - - if (Current < _sessions.size()) - { - Sess = _sessions.at(Current); - - if (Sess == nullptr) - return; - - ActiveSession = Sess; - - tabWidget->tabBar()->setTabTextColor(tabWidget->currentIndex(), oldTabText); - - if (Sess->clientSocket || Sess->AGWSession || Sess->KISSSession || Sess->KISSMode) - { - connectMenu->setEnabled(false); - discAction->setEnabled(true); - YAPPSend->setEnabled(true); - } - else - { - connectMenu->setEnabled(true); - discAction->setEnabled(false); - YAPPSend->setEnabled(false); - } - - // If a monitor Window, change Monitor config settings - - if (Sess->PortMonString[0]) - { - char * ptr = (char *)malloc(1024); - memcpy(ptr, Sess->PortMonString, 1024); - - int NumberofPorts = atoi((char *)&ptr[2]); - char *p, *Context; - char msg[80]; - int portnum, m; - char delim[] = "|"; - - // Remove old Monitor menu - - for (int i = 0; i < 32; i++) - { - SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden - } - - p = strtok_s((char *)&ptr[2], delim, &Context); - - while (NumberofPorts--) - { - p = strtok_s(NULL, delim, &Context); - if (p == NULL) - break; - - m = portnum = atoi(p); - - sprintf(msg, "Port %s", p); - - if (m == 0) - m = 33; - - if (Sess->portmask & (1ll << (m - 1))) - SetPortMonLine(portnum, msg, 1, 1); - else - SetPortMonLine(portnum, msg, 1, 0); - } - free(ptr); - - MonTX->setChecked(Sess->mtxparam); - MonSup->setChecked(Sess->mcomparam); - MonUI->setChecked(Sess->monUI); - MonNodes->setChecked(Sess->MonitorNODES); - MonColour->setChecked(Sess->MonitorColour); - } - return; - } -} - -void QtTermTCP::SetupHosts() -{ - QAction * Act = static_cast(QObject::sender()); - int i; - - for (i = 0; i < MAXHOSTS; i++) - { - if (Act == actSetup[i]) - break; - } - - if (i > 15) - return; - - ConfigHost = i; - - TabDialog tabdialog(0); - tabdialog.exec(); -} - - -void QtTermTCP::Connect() -{ - QMdiSubWindow * UI; - Ui_ListenSession * Sess = nullptr; - QAction * Act = static_cast(QObject::sender()); - - int i; - - for (i = 0; i < MAXHOSTS; i++) - { - if (Act == actHost[i]) - break; - } - - SavedHost = i; // Last used - - if (TermMode == MDI) - { - UI = mdiArea->activeSubWindow(); - - for (i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - if (Sess->sw == UI) - break; - } - - if (i == _sessions.size()) - return; - } - - else if (TermMode == Tabbed) - { - Sess = (Ui_ListenSession *)tabWidget->currentWidget(); - } - - else if (TermMode == Single) - Sess = _sessions.at(0); - - if ((Sess == nullptr || Sess->SessionType & Listen)) - return; - - Sess->CurrentHost = SavedHost; - - if (Act == actHost[16]) - { - // This runs the AGW Connection dialog - - Sess->CurrentHost = 16; // Iast used - AGWConnect dialog(0); - dialog.exec(); - return; - } - - - if (Act == actHost[17]) - { - // This runs the VARA Connection dialog - - Sess->CurrentHost = 17; // Iast used - VARADataSock->Sess = Sess; - VARASock->Sess = Sess; - - VARAConnect dialog(0); - dialog.exec(); - WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); - - return; - } - - if (Act == actHost[18]) - { - // This runs the KISS Connection dialog - - Sess->CurrentHost = 18; // Iast used - - KISSConnect dialog(0); - dialog.exec(); - return; - } - - // Set Monitor Params for this host - - sscanf(MonParams[Sess->CurrentHost], "%llx %x %x %x %x %x", - &Sess->portmask, &Sess->mtxparam, &Sess->mcomparam, - &Sess->MonitorNODES, &Sess->MonitorColour, &Sess->monUI); - - MonTX->setChecked(Sess->mtxparam); - MonSup->setChecked(Sess->mcomparam); - MonUI->setChecked(Sess->monUI); - MonNodes->setChecked(Sess->MonitorNODES); - MonColour->setChecked(Sess->MonitorColour); - - // Remove old Monitor menu - - for (i = 0; i < 32; i++) - { - SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden - } - - delete(Sess->clientSocket); - - Sess->clientSocket = new myTcpSocket(); - Sess->clientSocket->Sess = Sess; - - connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); - connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); - connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); - - Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]); - return; -} - -extern "C" void rst_timer(TAX25Port * AX25Sess); -extern "C" void set_unlink(TAX25Port * AX25Sess, Byte * path); - -void QtTermTCP::Disconnect() -{ - QMdiSubWindow * UI; - Ui_ListenSession * Sess = nullptr; - - if (TermMode == MDI) - { - int i; - - UI = mdiArea->activeSubWindow(); - - for (i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - if (Sess->sw == UI) - break; - } - - if (i == _sessions.size()) - return; - } - - else if (TermMode == Tabbed) - { - Sess = (Ui_ListenSession *)tabWidget->currentWidget(); - } - - else if (TermMode == Single) - Sess = _sessions.at(0); - - // if AGW send a d frame else disconnect TCP session - - if (Sess->AGWSession) - Send_AGW_Ds_Frame(Sess->AGWSession); - else if (VARASock && VARASock->Sess == Sess) - VARASock->write("DISCONNECT\r"); - else if (Sess->KISSSession) - { - if (Sess->KISSMode == 0) - { - TAX25Port * Port = (TAX25Port *)Sess->KISSSession; - - rst_timer(Port); - set_unlink(Port, Port->Path); - } - else - { - // KISS UI Mode - - char Msg[128]; - int Len = sprintf(Msg, "Disconnected\r"); - - Sess->KISSMode = 0; - SendtoTerm(Sess, Msg, Len); - ClearSessLabel(Sess); - setMenus(0); - Sess->KISSSession = NULL; - } - } - else - - { - if (Sess && Sess->clientSocket) - Sess->clientSocket->disconnectFromHost(); - } - return; -} - - -void QtTermTCP::doYAPPSend() -{ - QFileDialog dialog(this); - QStringList fileNames; - dialog.setFileMode(QFileDialog::AnyFile); - - QMdiSubWindow * UI; - Ui_ListenSession * Sess = nullptr; - int i; - - if (TermMode == MDI) - { - UI = mdiArea->activeSubWindow(); - - for (i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - if (Sess->sw == UI) - break; - } - - if (i == _sessions.size()) - return; - } - - else if (TermMode == Tabbed) - { - Sess = (Ui_ListenSession *)tabWidget->currentWidget(); - } - - else if (TermMode == Single) - Sess = _sessions.at(0); - - if (Sess == nullptr) - return; - - if ((Sess->SessionType & Mon)) - { - // Turn off monitoring - - setTraceOff(Sess); - } - - if (dialog.exec()) - { - char FN[256]; - - fileNames = dialog.selectedFiles(); - if (fileNames[0].length() < 256) - { - strcpy(FN, fileNames[0].toUtf8()); - YAPPSendFile(Sess, FN); - } - } -} - -void QtTermTCP::doYAPPSetRX() -{ - QFileDialog dialog(this); - QStringList fileNames; - dialog.setFileMode(QFileDialog::Directory); - dialog.setDirectory(YAPPPath); - - if (dialog.exec()) - { - fileNames = dialog.selectedFiles(); - if (fileNames[0].length() < 256) - strcpy(YAPPPath, fileNames[0].toUtf8()); - - SaveSettings(); - } -} - -void QtTermTCP::menuChecked() -{ - QAction * Act = static_cast(QObject::sender()); - - int state = Act->isChecked(); - int newTermMode = TermMode; - int newSingleMode = singlemodeFormat; - - if (Act == TabSingle || Act == TabBoth || Act == TabMon) - { - // Tabbed Window format had changed - - int i = tabWidget->currentIndex(); - - if (Act == TabSingle) - TabType[i] = Term; - else if (Act == TabBoth) - TabType[i] = Term + Mon; - else - TabType[i] = Mon; - - QMessageBox msgBox; - msgBox.setText("Tab Types will change next time program is started."); - msgBox.exec(); - - } - - if (Act == singleAct || Act == singleAct2 || Act == MDIAct || Act == tabbedAct) - { - // Term Mode had changed - - if (singleAct->isChecked()) - { - newTermMode = Single; - newSingleMode = Mon + Term; - } - else if (singleAct2->isChecked()) - { - newTermMode = Single; - newSingleMode = Term; - } - else if (MDIAct->isChecked()) - newTermMode = MDI; - else if (tabbedAct->isChecked()) - newTermMode = Tabbed; - - if (newTermMode != TermMode || newSingleMode != singlemodeFormat) - { - QSettings settings(GetConfPath(), QSettings::IniFormat); - settings.setValue("TermMode", newTermMode); - settings.setValue("singlemodeFormat", newSingleMode); - QMessageBox msgBox; - msgBox.setText("Presentation Mode will change next time program is started."); - msgBox.exec(); - } - - return; - } - - - if (Act == MonTX) - ActiveSession->mtxparam = state; - else if (Act == MonSup) - ActiveSession->mcomparam = state; - else if (Act == MonUI) - ActiveSession->monUI = state; - else if (Act == MonNodes) - ActiveSession->MonitorNODES = state; - else if (Act == MonColour) - ActiveSession->MonitorColour = state; - else if (Act == actChatMode) - ChatMode = state; - else if (Act == actAutoTeletext) - AutoTeletext = state; - else if (Act == actBells) - Bells = state; - else if (Act == actStripLF) - StripLF = state; - else if (Act == actIntervalBeep) - AlertBeep = state; - else if (Act == actConnectBeep) - ConnectBeep = state; - else if (Act == actnoConv) - convUTF8 = -1; - else if (Act == actAuto) - convUTF8 = 0; - else if (Act == actCP1251) - convUTF8 = 1251; - else if (Act == actCP1252) - convUTF8 = 1252; - else if (Act == actCP437) - convUTF8 = 437; - else - { - // look for port entry - for (int i = 0; i < MAXPORTS + 1; i++) - { - if (Act == MonPort[i]) - { - unsigned long long mmask; - - if (i == 0) // BBS Mon - use bit 63 (Port 64) - mmask = 1ll << 63; - else - mmask = 1ll << (i - 1); - - if (state) - ActiveSession->portmask |= mmask; - else - ActiveSession->portmask &= ~mmask; - break; - } - } - } - - // Get active Session -/* - - QMdiSubWindow *SW = mdiArea->activeSubWindow(); - - Ui_ListenSession * Sess; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - -// for (Ui_ListenSession * Sess : _sessions) -// { - if (Sess->sw == SW) - { - */ - - if (ActiveSession->clientSocket && ActiveSession->SessionType & Mon) - SendTraceOptions(ActiveSession); - - return; -} - - - - -void QtTermTCP::LDisconnect(Ui_ListenSession * LUI) -{ - if (LUI->clientSocket) - LUI->clientSocket->disconnectFromHost(); -} - -extern QApplication * a; - -void QtTermTCP::LreturnPressed(Ui_ListenSession * Sess) -{ - QByteArray stringData = Sess->inputWindow->text().toUtf8(); - - // if multiline input (eg from copy/paste) replace LF with CR - - char * ptr; - char * Msgptr; - char * Msg; - - QScrollBar *scrollbar = Sess->termWindow->verticalScrollBar(); - bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4)); - - if (scrollbarAtBottom) - Sess->termWindow->moveCursor(QTextCursor::End); // So we don't get blank lines - - // Stack it - - Sess->StackIndex = 0; - - if (Sess->KbdStack[49]) - free(Sess->KbdStack[49]); - - for (int i = 48; i >= 0; i--) - { - Sess->KbdStack[i + 1] = Sess->KbdStack[i]; - } - - Sess->KbdStack[0] = qstrdup(stringData.data()); - - stringData.append('\n'); - - Msgptr = stringData.data(); - - if (Sess->TTActive) // Teletext uses 0x5F for # - while ((ptr = strchr(Msgptr, 0x23))) // Replace VT with LF - *ptr++ = 0x5f; - - - while ((ptr = strchr(Msgptr, 11))) // Replace VT with LF - *ptr++ = 10; - - LastWrite = time(NULL); // Stop initial beep - Sess->SlowTimer = 0; - - Sess->pageBuffer[0] = 0; // Reset Teletext mode screen buffer - - if (Sess->KISSMode == 1) - { - // UI session. Send as UI Message - - while ((ptr = strchr(Msgptr, '\n'))) - { - *ptr++ = 0; - - Msg = (char *)malloc(strlen(Msgptr) + 10); - strcpy(Msg, Msgptr); - strcat(Msg, "\r"); - - Send_UI(0, 0xF0, MYCALL, Sess->UIDEST, (unsigned char *)Msg, (int)strlen(Msg)); - - WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), - Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black - - free(Msg); - - Msgptr = ptr; - } - } - else if (Sess->KISSSession) - { - // Send to ax.25 code - - while ((ptr = strchr(Msgptr, '\n'))) - { - *ptr++ = 0; - - Msg = (char *)malloc(strlen(Msgptr) + 10); - strcpy(Msg, Msgptr); - strcat(Msg, "\r"); - - SendtoAX25(Sess->KISSSession, (unsigned char *)Msg, (int)strlen(Msg)); - - WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), - Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black - - free(Msg); - - Msgptr = ptr; - } - } - - else if (Sess->AGWSession) - { - // Terminal is in AGWPE mode - send as AGW frame - - while ((ptr = strchr(Msgptr, '\n'))) - { - *ptr++ = 0; - - Msg = (char *)malloc(strlen(Msgptr) + 10); - strcpy(Msg, Msgptr); - strcat(Msg, "\r"); - - AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Msg, (int)strlen(Msg)); - - WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), - Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black - -// Sess->termWindow->insertPlainText(Msg); - - free(Msg); - - Msgptr = ptr; - } - } - - else if (VARASock && VARASock->Sess == Sess) - { - while ((ptr = strchr(Msgptr, '\n'))) - { - *ptr++ = 0; - - Msg = (char *)malloc(strlen(Msgptr) + 10); - strcpy(Msg, Msgptr); - strcat(Msg, "\r"); - - VARADataSock->write(Msg); - - WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), - Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black - -// Sess->termWindow->insertPlainText(Msg); - - free(Msg); - - Msgptr = ptr; - } - } - - else if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) - { - while ((ptr = strchr(Msgptr, '\n'))) - { - *ptr++ = 0; - - Msg = (char *)malloc(strlen(Msgptr) + 10); - strcpy(Msg, Msgptr); - strcat(Msg, "\r"); - - Sess->clientSocket->write(Msg); - - WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), - Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black - -// Sess->termWindow->insertPlainText(Msg); - - free(Msg); - - Msgptr = ptr; - } - } - else - { - // Not Connected - - if (Sess->SessionType != Listen) - { - if (Sess->CurrentHost < MAXHOSTS) - { - // Last connect was TCP - - char Msg[] = "Connecting....\r"; - - WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), - Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red - - delete(Sess->clientSocket); - - Sess->clientSocket = new myTcpSocket(); - Sess->clientSocket->Sess = Sess; - - connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); - connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); - connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); - - Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]); - } - - else if (Sess->CurrentHost == 16) // AGW - { - // Invoke AGW connect dialog - - AGWConnect dialog(0); - dialog.exec(); - - WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); - return; - } - - else if (Sess->CurrentHost == 17) // VARA - { - // Invoke VARA connect dialog - - VARAConnect dialog(0); - dialog.exec(); - - WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); - return; - } - - else if (Sess->CurrentHost == 18) // KISS - { - // Do we send as UI or invoke kiss connect dialog ?? - - // Try Connect Dialog for now - may make a menu option - - KISSConnect dialog(0); - dialog.exec(); - - WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); - return; - } - } - else - { - char Msg[] = "Incoming Session - Can't Connect\r"; - - WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), - Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, 81); // Red - - } - } - - if (scrollbarAtBottom) - Sess->termWindow->moveCursor(QTextCursor::End); - - Sess->inputWindow->setText(""); - a->inputMethod()->hide(); -} - - -void QtTermTCP::displayError(QAbstractSocket::SocketError socketError) -{ - myTcpSocket* sender = static_cast(QObject::sender()); - - switch (socketError) - { - case QAbstractSocket::RemoteHostClosedError: - break; - - case QAbstractSocket::HostNotFoundError: - QMessageBox::information(this, tr("QtTermTCP"), - tr("The host was not found. Please check the " - "host name and portsettings->")); - break; - - case QAbstractSocket::ConnectionRefusedError: - QMessageBox::information(this, tr("QtTermTCP"), - tr("The connection was refused by the peer.")); - break; - - default: - QMessageBox::information(this, tr("QtTermTCP"), - tr("The following error occurred: %1.") - .arg(sender->errorString())); - } - - connectMenu->setEnabled(true); -} - -void QtTermTCP::readyRead() -{ - int Read; - unsigned char Buffer[8192]; - myTcpSocket* Socket = static_cast(QObject::sender()); - - Ui_ListenSession * Sess = (Ui_ListenSession *)Socket->Sess; - - // read the data from the socket - - Read = Socket->read((char *)Buffer, 2047); - - while (Read > 0) - { - // if (InputMode == 'Y') // Yapp - // { - // QString myString = QString::fromUtf8((char*)Buffer, Read); - // QByteArray ptr = myString.toLocal8Bit(); - // memcpy(Buffer, ptr.data(), ptr.length()); - // Read = ptr.length(); - // } - - - Buffer[Read] = 0; - - ProcessReceivedData(Sess, Buffer, Read); - - QString myString = QString::fromUtf8((char*)Buffer); - // qDebug() << myString; - Read = Socket->read((char *)Buffer, 2047); - } -} - -extern "C" int SocketSend(Ui_ListenSession * Sess, char * Buffer, int len) -{ - myTcpSocket *Socket = Sess->clientSocket; - - if (Socket && Socket->state() == QAbstractSocket::ConnectedState) - return Socket->write(Buffer, len); - - return 0; -} - -extern "C" int SocketFlush(Ui_ListenSession * Sess) -{ - if (Sess->AGWSession || Sess->KISSSession || (VARASock && VARASock->Sess == Sess)) - return 0; - - myTcpSocket* Socket = Sess->clientSocket; - - if (Socket && Socket->state() == QAbstractSocket::ConnectedState) - return Socket->flush(); - - return 0; -} - -extern "C" void mySleep(int ms) -{ - QThread::msleep(ms); -} - -extern "C" void SetPortMonLine(int i, char * Text, int visible, int enabled) -{ - MonPort[i]->setText(Text); - MonPort[i]->setVisible(visible); - MonPort[i]->setChecked(enabled); -} - -bool scrollbarAtBottom = 0; - -extern "C" void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int * OutputSaveLen, char * OutputSave, QColor Colour); - -extern "C" void WritetoOutputWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int len) -{ - WritetoOutputWindowEx(Sess, Buffer, len, Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, outputText); -} - - -extern "C" void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int * OutputSaveLen, char * OutputSave, QColor Colour) -{ - unsigned char Copy[8192]; - unsigned char * ptr1, *ptr2; - unsigned char Line[8192]; - unsigned char out[8192]; - int outlen; - - int num; - - if (termWindow == NULL) - return; - - time_t NOW = time(NULL); - - // Beep if no output for a while - - if (AlertInterval && (NOW - LastWrite) > AlertInterval) - { - if (AlertBeep) - myBeep(); - } - - // 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(); - } - } while (ptr); - } - - num = ptr2 - ptr1 - 1; - - // if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1); - - memcpy(Line, ptr1, num); - Line[num++] = 13; - Line[num] = 0; - - if (Line[0] == 0x1b) // Colour Escape - { - if (Sess->MonitorColour) - termWindow->setTextColor(Colours[Line[1] - 10]); - - outlen = checkUTF8(&Line[2], num - 2, out); - out[outlen] = 0; - termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); - // termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); - } - else - { - termWindow->setTextColor(Colour); - - outlen = checkUTF8(Line, num, out); - out[outlen] = 0; - termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); - // termWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); - } - - len -= (ptr2 - ptr1); - - ptr1 = ptr2; - - if ((len > 0) && StripLF) - { - if (*ptr1 == 0x0a) // Line Feed - { - ptr1++; - len--; - } - } - - - - goto lineloop; - -} - -extern "C" void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Msg, int len) -{ - char * ptr1 = (char *)Msg, *ptr2; - char Line[512]; - int num; - - // QScrollBar *scrollbar = Sess->monWindow->verticalScrollBar(); - // bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4)); - - if (Sess->monWindow == nullptr) - return; - - Sess->monWindow->setStyleSheet(monStyleSheet); - - const QTextCursor old_cursor = Sess->monWindow->textCursor(); - const int old_scrollbar_value = Sess->monWindow->verticalScrollBar()->value(); - const bool is_scrolled_down = old_scrollbar_value == Sess->monWindow->verticalScrollBar()->maximum(); - - // Move the cursor to the end of the document. - Sess->monWindow->moveCursor(QTextCursor::End); - - // Insert the text at the position of the cursor (which is the end of the document). - - - // Write a line at a time so we can action colour chars - -// Buffer[Len] = 0; - -// if (scrollbarAtBottom) -// Sess->monWindow->moveCursor(QTextCursor::End); - - if (Sess->MonSaveLen) - { - // Have part line - append to it - memcpy(&Sess->MonSave[Sess->MonSaveLen], Msg, len); - Sess->MonSaveLen += len; - ptr1 = Sess->MonSave; - len = Sess->MonSaveLen; - Sess->MonSaveLen = 0; - } - -lineloop: - - if (len <= 0) - { - // if (scrollbarAtBottom) - // Sess->monWindow->moveCursor(QTextCursor::End); - - - if (old_cursor.hasSelection() || !is_scrolled_down) - { - // The user has selected text or scrolled away from the bottom: maintain position. - Sess->monWindow->setTextCursor(old_cursor); - Sess->monWindow->verticalScrollBar()->setValue(old_scrollbar_value); - } - else - { - // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. - Sess->monWindow->moveCursor(QTextCursor::End); - Sess->monWindow->verticalScrollBar()->setValue(Sess->monWindow->verticalScrollBar()->maximum()); - } - - return; - } - - // copy text to control a line at a time - - ptr2 = (char *)memchr(ptr1, 13, len); - - if (ptr2 == 0) // No CR - { - memmove(Sess->MonSave, ptr1, len); - Sess->MonSaveLen = len; - return; - } - - *(ptr2++) = 0; - - // if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1); - - num = ptr2 - ptr1 - 1; - - memcpy(Line, ptr1, num); - Line[num++] = 13; - Line[num] = 0; - - if (Line[0] == 0x1b) // Colour Escape - { - if (Sess->MonitorColour) - { - if (Line[1] == 17) - Sess->monWindow->setTextColor(monRxText); - else - Sess->monWindow->setTextColor(monTxText); - } - else - Sess->monWindow->setTextColor(monOtherText); - - Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); - } - else - { - Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); - } - len -= (ptr2 - ptr1); - - ptr1 = ptr2; - - goto lineloop; - -} - -int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len); -void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len); - -// YAPP stuff - -#define SOH 1 -#define STX 2 -#define ETX 3 -#define EOT 4 -#define ENQ 5 -#define ACK 6 -#define DLE 0x10 -#define NAK 0x15 -#define CAN 0x18 - -extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len) -{ - if (Sess == 0) - return; - - Sess->SlowTimer = 0; - Msg[Len] = 0; - - if (Sess->InputMode == 'Y') // Yapp - { - ProcessYAPPMessage(Sess, (unsigned char *)Msg, Len); - return; - } - - // Could be a YAPP Header - - if (Len == 2 && Msg[0] == ENQ && Msg[1] == 1) // YAPP Send_Init - { - char YAPPRR[2]; - - // Turn off monitoring - - Sess->InputMode = 'Y'; - - YAPPRR[0] = ACK; - YAPPRR[1] = 1; - QueueMsg(Sess, YAPPRR, 2); - - return; - } - - if (AutoTeletext && (Msg[0] == 0x1e || Msg[0] == 0x0c)) - { - if (Sess->TTActive == 0) - { - Sess->TTActive = 1; - DoTermResize(Sess); - } - } - - if (Sess->TTActive) - { - // Feed to Teletext code - - // We need to decode a whole page. There is no obvious delimiter so process till data stops. - // Buffer is cleared when next input is sent - - if (strlen(&Sess->pageBuffer[0] + Len) > 4090) - Sess->pageBuffer[0] = 0; // Protect buffer - - strcat(Sess->pageBuffer, (char *)Msg); - - DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end - return; - } - - WritetoOutputWindow(Sess, (unsigned char *)Msg, Len); - -} - -QSettings* settings; - -// This makes geting settings for more channels easier - -char Prefix[16] = "AX25_A"; - -void GetPortSettings(int Chan); - -QVariant getAX25Param(const char * key, QVariant Default) -{ - char fullKey[64]; - - sprintf(fullKey, "%s/%s", Prefix, key); - return settings->value(fullKey, Default); -} - -void getAX25Params(int chan) -{ - Prefix[5] = chan + 'A'; - GetPortSettings(chan); -} - - -void GetPortSettings(int Chan) -{ - maxframe[Chan] = getAX25Param("Maxframe", 4).toInt(); - fracks[Chan] = getAX25Param("Retries", 10).toInt(); - frack_time[Chan] = getAX25Param("FrackTime", 8).toInt(); - persist[Chan] = getAX25Param("Persist", 128).toInt(); - kisspaclen[Chan] = getAX25Param("Paclen", 128).toInt(); - idletime[Chan] = getAX25Param("IdleTime", 180).toInt(); - slottime[Chan] = getAX25Param("SlotTime", 100).toInt(); - resptime[Chan] = getAX25Param("RespTime", 1500).toInt(); - TXFrmMode[Chan] = getAX25Param("TXFrmMode", 1).toInt(); - max_frame_collector[Chan] = getAX25Param("FrameCollector", 6).toInt(); - //exclude_callsigns[Chan]= getAX25Param("ExcludeCallsigns/"); - //exclude_APRS_frm[Chan]= getAX25Param("ExcludeAPRSFrmType/"); - KISS_opt[Chan] = getAX25Param("KISSOptimization", false).toInt();; - dyn_frack[Chan] = getAX25Param("DynamicFrack", false).toInt();; - IPOLL[Chan] = getAX25Param("IPOLL", 80).toInt(); - -} - - -void GetSettings() -{ - QByteArray qb; - int i; - char Key[16]; - char Param[256]; - - settings = new QSettings(GetConfPath(), QSettings::IniFormat); - - // Get saved session definitions - - sessionList = strdup(settings->value("Sessions", "1|3, 0, 5, 5, 600, 800|").toString().toUtf8()); - - for (i = 0; i < MAXHOSTS; i++) - { - sprintf(Key, "HostParams%d", i); - - qb = settings->value(Key).toByteArray(); - - DecodeSettingsLine(i, qb.data()); - } - - Split = settings->value("Split", 50).toInt(); - ChatMode = settings->value("ChatMode", 1).toInt(); - AutoTeletext = settings->value("AutoTeletext", 0).toInt(); - Bells = settings->value("Bells", 1).toInt(); - StripLF = settings->value("StripLF", 1).toInt(); - AlertBeep = settings->value("AlertBeep", 1).toInt(); - ConnectBeep = settings->value("ConnectBeep", 1).toInt(); - SavedHost = settings->value("CurrentHost", 0).toInt(); - strcpy(YAPPPath, settings->value("YAPPPath", "").toString().toUtf8()); - - listenPort = settings->value("listenPort", 8015).toInt(); - listenEnable = settings->value("listenEnable", false).toBool(); - strcpy(listenCText, settings->value("listenCText", "").toString().toUtf8()); - - TermMode = settings->value("TermMode", 0).toInt(); - singlemodeFormat = settings->value("singlemodeFormat", Term + Mon).toInt(); - - AGWEnable = settings->value("AGWEnable", 0).toInt(); - AGWMonEnable = settings->value("AGWMonEnable", 0).toInt(); - strcpy(AGWTermCall, settings->value("AGWTermCall", "").toString().toUtf8()); - strcpy(AGWBeaconDest, settings->value("AGWBeaconDest", "").toString().toUtf8()); - strcpy(AGWBeaconPath, settings->value("AGWBeaconPath", "").toString().toUtf8()); - AGWBeaconInterval = settings->value("AGWBeaconInterval", 0).toInt(); - strcpy(AGWBeaconPorts, settings->value("AGWBeaconPorts", "").toString().toUtf8()); - strcpy(AGWBeaconMsg, settings->value("AGWBeaconText", "").toString().toUtf8()); - strcpy(AGWHost, settings->value("AGWHost", "127.0.0.1").toString().toUtf8()); - AGWPortNum = settings->value("AGWPort", 8000).toInt(); - AGWPaclen = settings->value("AGWPaclen", 80).toInt(); - AGWToCalls = settings->value("AGWToCalls", "").toStringList(); - convUTF8 = settings->value("convUTF8", 0).toInt(); - - KISSEnable = settings->value("KISSEnable", 0).toInt(); - strcpy(MYCALL, settings->value("MYCALL", "").toString().toUtf8()); - strcpy(KISSHost, settings->value("KISSHost", "127.0.0.1").toString().toUtf8()); - KISSPortNum = settings->value("KISSPort", 8100).toInt(); - KISSMode = settings->value("KISSMode", 0).toInt(); - - strcpy(SerialPort, settings->value("KISSSerialPort", "None").toString().toUtf8()); - KISSBAUD = settings->value("KISSBAUD", 19200).toInt(); - getAX25Params(0); - - VARAEnable = settings->value("VARAEnable", 0).toInt(); - strcpy(VARAHost, settings->value("VARAHost", "127.0.0.1").toString().toUtf8()); - strcpy(VARAHostFM, settings->value("VARAHostFM", "127.0.0.1").toString().toUtf8()); - strcpy(VARAHostHF, settings->value("VARAHostHF", "127.0.0.1").toString().toUtf8()); - strcpy(VARAHostSAT, settings->value("VARAHostSAT", "127.0.0.1").toString().toUtf8()); - VARAPortNum = settings->value("VARAPort", 8300).toInt(); - VARAPortHF = settings->value("VARAPortHF", 8300).toInt(); - VARAPortFM = settings->value("VARAPortFM", 8300).toInt(); - VARAPortSAT = settings->value("VARAPortSAT", 8300).toInt(); - strcpy(VARAPath, settings->value("VARAPath", "C:\\VARA\\VARA.exe").toString().toUtf8()); - strcpy(VARAPathHF, settings->value("VARAPathHF", "C:\\VARA\\VARA.exe").toString().toUtf8()); - strcpy(VARAPathFM, settings->value("VARAPathFM", "C:\\VARA\\VARAFM.exe").toString().toUtf8()); - strcpy(VARAPathSAT, settings->value("VARAPathSAT", "C:\\VARA\\VARASAT.exe").toString().toUtf8()); - strcpy(VARATermCall, settings->value("VARATermCall", "").toString().toUtf8()); - VARA500 = settings->value("VARA500", 0).toInt(); - VARA2300 = settings->value("VARA2300", 1).toInt(); - VARA2750 = settings->value("VARA2750", 0).toInt(); - VARAHF = settings->value("VARAHF", 1).toInt(); - VARAFM = settings->value("VARAFM", 0).toInt(); - VARASAT = settings->value("VARASAT", 0).toInt(); - strcpy(VARAInit, settings->value("VARAInit", "").toString().toUtf8()); - - strcpy(PTTPort, settings->value("PTT", "None").toString().toUtf8()); - PTTMode = settings->value("PTTMode", 19200).toInt(); - PTTBAUD = settings->value("PTTBAUD", 19200).toInt(); - CATHex = settings->value("CATHex", 1).toInt(); - - strcpy(PTTOnString, settings->value("PTTOnString", "").toString().toUtf8()); - strcpy(PTTOffString, settings->value("PTTOffString", "").toString().toUtf8()); - - pttGPIOPin = settings->value("pttGPIOPin", 17).toInt(); - pttGPIOPinR = settings->value("pttGPIOPinR", 17).toInt(); - -#ifdef WIN32 - strcpy(CM108Addr, settings->value("CM108Addr", "0xD8C:0x08").toString().toUtf8()); -#else - strcpy(CM108Addr, settings->value("CM108Addr", "/dev/hidraw0").toString().toUtf8()); -#endif - - HamLibPort = settings->value("HamLibPort", 4532).toInt(); - strcpy(HamLibHost, settings->value("HamLibHost", "127.0.0.1").toString().toUtf8()); - - FLRigPort = settings->value("FLRigPort", 12345).toInt(); - strcpy(FLRigHost, settings->value("FLRigHost", "127.0.0.1").toString().toUtf8()); - - - strcpy(Param, settings->value("TabType", "1 1 1 1 1 1 1 2 2").toString().toUtf8()); - sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", - &TabType[0], &TabType[1], &TabType[2], &TabType[3], &TabType[4], - &TabType[5], &TabType[6], &TabType[7], &TabType[8], &TabType[9]); - - monBackground = settings->value("monBackground", QColor(255, 255, 255)).value(); - monRxText = settings->value("monRxText", QColor(0, 0, 255)).value(); - monTxText = settings->value("monTxText", QColor(255, 0, 0)).value(); - monOtherText = settings->value("monOtherText", QColor(0, 0, 0)).value(); - - termBackground = settings->value("termBackground", QColor(255, 255, 255)).value(); - outputText = settings->value("outputText", QColor(0, 0, 255)).value(); - EchoText = settings->value("EchoText", QColor(0, 0, 0)).value(); - WarningText = settings->value("WarningText", QColor(255, 0, 0)).value(); - - inputBackground = settings->value("inputBackground", QColor(255, 255, 255)).value(); - inputText = settings->value("inputText", QColor(0, 0, 0)).value(); - - delete(settings); -} - -void SavePortSettings(int Chan); - -void saveAX25Param(const char * key, QVariant Value) -{ - char fullKey[64]; - - sprintf(fullKey, "%s/%s", Prefix, key); - - settings->setValue(fullKey, Value); -} - -void saveAX25Params(int chan) -{ - Prefix[5] = chan + 'A'; - SavePortSettings(chan); -} - -void SavePortSettings(int Chan) -{ - saveAX25Param("Retries", fracks[Chan]); - saveAX25Param("Maxframe", maxframe[Chan]); - saveAX25Param("Paclen", kisspaclen[Chan]); - saveAX25Param("FrackTime", frack_time[Chan]); - saveAX25Param("IdleTime", idletime[Chan]); - saveAX25Param("SlotTime", slottime[Chan]); - saveAX25Param("Persist", persist[Chan]); - saveAX25Param("RespTime", resptime[Chan]); - saveAX25Param("TXFrmMode", TXFrmMode[Chan]); - saveAX25Param("FrameCollector", max_frame_collector[Chan]); - saveAX25Param("ExcludeCallsigns", exclude_callsigns[Chan]); - saveAX25Param("ExcludeAPRSFrmType", exclude_APRS_frm[Chan]); - saveAX25Param("KISSOptimization", KISS_opt[Chan]); - saveAX25Param("DynamicFrack", dyn_frack[Chan]); - saveAX25Param("BitRecovery", recovery[Chan]); - saveAX25Param("IPOLL", IPOLL[Chan]); - saveAX25Param("MyDigiCall", MyDigiCall[Chan]); -} - -extern "C" void SaveSettings() -{ - int i; - char Param[512]; - char Key[16]; - - settings = new QSettings(GetConfPath(), QSettings::IniFormat); - - for (i = 0; i < MAXHOSTS; i++) - { - sprintf(Key, "HostParams%d", i); - EncodeSettingsLine(i, Param); - settings->setValue(Key, Param); - } - - settings->setValue("Split", Split); - settings->setValue("ChatMode", ChatMode); - settings->setValue("AutoTeletext", AutoTeletext); - settings->setValue("Bells", Bells); - settings->setValue("StripLF", StripLF); - settings->setValue("AlertBeep", AlertBeep); - settings->setValue("ConnectBeep", ConnectBeep); - settings->setValue("CurrentHost", SavedHost); - - settings->setValue("YAPPPath", YAPPPath); - settings->setValue("listenPort", listenPort); - settings->setValue("listenEnable", listenEnable); - settings->setValue("listenCText", listenCText); - settings->setValue("convUTF8", convUTF8); - - settings->setValue("PTT", PTTPort); - settings->setValue("PTTBAUD", PTTBAUD); - settings->setValue("PTTMode", PTTMode); - - settings->setValue("CATHex", CATHex); - - settings->setValue("PTTOffString", PTTOffString); - settings->setValue("PTTOnString", PTTOnString); - - settings->setValue("pttGPIOPin", pttGPIOPin); - settings->setValue("pttGPIOPinR", pttGPIOPinR); - - settings->setValue("CM108Addr", CM108Addr); - settings->setValue("HamLibPort", HamLibPort); - settings->setValue("HamLibHost", HamLibHost); - settings->setValue("FLRigPort", FLRigPort); - settings->setValue("FLRigHost", FLRigHost); - - - // Save Sessions - - char SessionString[1024]; - int SessStringLen; - - SessStringLen = sprintf(SessionString, "%d|", _sessions.size()); - - if (TermMode == MDI) - { - for (int i = 0; i < _sessions.size(); ++i) - { - Ui_ListenSession * Sess = _sessions.at(i); - - QRect r = Sess->sw->geometry(); - - SessStringLen += sprintf(&SessionString[SessStringLen], - "%d, %d, %d, %d, %d, %d|", Sess->SessionType, Sess->CurrentHost, r.top(), r.left(), r.bottom(), r.right()); - } - - settings->setValue("Sessions", SessionString); - } - - settings->setValue("AGWEnable", AGWEnable); - settings->setValue("AGWMonEnable", AGWMonEnable); - settings->setValue("AGWTermCall", AGWTermCall); - settings->setValue("AGWBeaconDest", AGWBeaconDest); - settings->setValue("AGWBeaconPath", AGWBeaconPath); - settings->setValue("AGWBeaconInterval", AGWBeaconInterval); - settings->setValue("AGWBeaconPorts", AGWBeaconPorts); - settings->setValue("AGWBeaconText", AGWBeaconMsg); - settings->setValue("AGWHost", AGWHost); - settings->setValue("AGWPort", AGWPortNum); - settings->setValue("AGWPaclen", AGWPaclen); - settings->setValue("AGWToCalls", AGWToCalls); - - - settings->setValue("KISSEnable", KISSEnable); - settings->setValue("MYCALL", MYCALL); - settings->setValue("KISSHost", KISSHost); - settings->setValue("KISSMode", KISSMode); - settings->setValue("KISSPort", KISSPortNum); - settings->setValue("KISSSerialPort", SerialPort); - settings->setValue("KISSBAUD", KISSBAUD); - saveAX25Params(0); - - settings->setValue("VARAEnable", VARAEnable); - settings->setValue("VARATermCall", VARATermCall); - settings->setValue("VARAHost", VARAHost); - settings->setValue("VARAPort", VARAPortNum); - settings->setValue("VARAInit", VARAInit); - settings->setValue("VARAPath", VARAPath); - settings->setValue("VARAHostHF", VARAHostHF); - settings->setValue("VARAPortHF", VARAPortHF); - settings->setValue("VARAPathHF", VARAPathHF); - settings->setValue("VARAHostFM", VARAHostFM); - settings->setValue("VARAPortFM", VARAPortFM); - settings->setValue("VARAPathFM", VARAPathFM); - settings->setValue("VARAHostSAT", VARAHostSAT); - settings->setValue("VARAPortSAT", VARAPortSAT); - settings->setValue("VARAPathSAT", VARAPathSAT); - settings->setValue("VARA500", VARA500); - settings->setValue("VARA2300", VARA2300); - settings->setValue("VARA2750", VARA2750); - settings->setValue("VARAHF", VARAHF); - settings->setValue("VARAFM", VARAFM); - settings->setValue("VARASAT", VARASAT); - - - sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", - TabType[0], TabType[1], TabType[2], TabType[3], TabType[4], TabType[5], TabType[6], TabType[7], TabType[8], TabType[9]); - - settings->setValue("TabType", Param); - - settings->setValue("monBackground", monBackground); - settings->setValue("monRxText", monRxText); - settings->setValue("monTxText", monTxText); - settings->setValue("monOtherText", monOtherText); - - settings->setValue("termBackground", termBackground); - settings->setValue("outputText", outputText); - settings->setValue("EchoText", EchoText); - settings->setValue("WarningText", WarningText); - - settings->setValue("inputBackground", inputBackground); - settings->setValue("inputText", inputText); - - settings->sync(); - delete(settings); -} - -#include - -void QtTermTCP::closeEvent(QCloseEvent *event) -{ - QMessageBox::StandardButton resBtn = QMessageBox::question(this, "QtTermTCP", - tr("Are you sure?\n"), - QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes, - QMessageBox::Yes); - if (resBtn != QMessageBox::Yes) { - event->ignore(); - } - else - { - event->accept(); -#ifdef USESERIAL - if (hPTTDevice) - hPTTDevice->close(); -#endif - if (process) - process->close(); - } -} - -QtTermTCP::~QtTermTCP() -{ - Ui_ListenSession * Sess; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - if (Sess->clientSocket) - { - int loops = 100; - Sess->clientSocket->disconnectFromHost(); - while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState) - QThread::msleep(10); - } - - } - - if (AGWSock && AGWSock->ConnectedState == QAbstractSocket::ConnectedState) - { - int loops = 100; - AGWSock->disconnectFromHost(); - QThread::msleep(10); - while (AGWSock && loops-- && AGWSock->state() != QAbstractSocket::UnconnectedState) - QThread::msleep(10); - } - - if (_server->isListening()) - _server->close(); - - delete(_server); - - QSettings mysettings(GetConfPath(), QSettings::IniFormat); - mysettings.setValue("geometry", saveGeometry()); - mysettings.setValue("windowState", saveState()); - - SaveSettings(); -} - -extern "C" void timer_event(); - -void QtTermTCP::KISSTimerSlot() -{ - // Runs every 100 mS - - timer_event(); -} - -void QtTermTCP::MyTimerSlot() -{ - // Runs every 10 seconds - - Ui_ListenSession * Sess; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - // for (Ui_ListenSession * Sess : _sessions) - // { - if (Sess == NULL) - continue; - - if (!ChatMode) - continue; - - if (Sess->KISSSession || - (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState)) - { - Sess->SlowTimer++; - - if (Sess->SlowTimer > 54) // About 9 mins - { - unsigned char Msg[2] = ""; - - Sess->SlowTimer = 0; - - if (Sess->KISSSession) - { - TAX25Port * ax25 = (TAX25Port *)Sess->KISSSession; - - if (ax25->status == STAT_LINK) - SendtoAX25(Sess->KISSSession, Msg, 1); - } - else - Sess->clientSocket->write("\0", 1); - } - } - } - - if (AGWEnable) - AGWTimer(); - - if (VARAEnable) - VARATimer(); - - if (KISSEnable) - KISSTimer(); - -} - -extern "C" void myBeep() -{ - QApplication::beep(); -} - -void QtTermTCP::ListenSlot() -{ - // This runs the Listen Configuration dialog - - ListenDialog * xx = new ListenDialog(); - xx->exec(); -} - -void QtTermTCP::AGWSlot() -{ - // This runs the AGW Configuration dialog - - AGWDialog dialog(0); - dialog.exec(); -} - -Ui_Dialog * Dev; - -static Ui_KISSDialog * KISS; -static Ui_ColourDialog * COLOURS; - -QDialog * deviceUI; - - -char NewPTTPort[80]; - -int newSoundMode = 0; -int oldSoundMode = 0; - -#ifdef USESERIAL -QList Ports = QSerialPortInfo::availablePorts(); -#endif - - -void QtTermTCP::KISSSlot() -{ - // This runs the KISS Configuration dialog - - KISS = new(Ui_KISSDialog); - - QDialog UI; - - KISS->setupUi(&UI); - - UI.setFont(*menufont); - - deviceUI = &UI; - KISS->KISSEnable->setChecked(KISSEnable); - KISS->MYCALL->setText(MYCALL); - - // connect(KISS->SerialPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); - - QStringList items; - -#ifdef USESERIAL - - for (const QSerialPortInfo &info : Ports) - { - items.append(info.portName()); - } - - items.sort(); - items.insert(0, "TCP"); - -#endif - - for (const QString &info : items) - { - KISS->SerialPort->addItem(info); - } - - KISS->SerialPort->setCurrentIndex(KISS->SerialPort->findText(SerialPort, Qt::MatchFixedString)); - KISS->Speed->setText(QString::number(KISSBAUD)); - KISS->Host->setText(KISSHost); - KISS->Port->setText(QString::number(KISSPortNum)); - - KISS->Paclen->setText(QString::number(kisspaclen[0])); - KISS->Maxframe->setText(QString::number(maxframe[0])); - KISS->Frack->setText(QString::number(frack_time[0])); - KISS->Retries->setText(QString::number(fracks[0])); - - QObject::connect(KISS->okButton, SIGNAL(clicked()), this, SLOT(KISSaccept())); - QObject::connect(KISS->cancelButton, SIGNAL(clicked()), this, SLOT(KISSreject())); - - UI.exec(); - -} - - -void QtTermTCP::KISSaccept() -{ - QVariant Q; - int OldEnable = KISSEnable; - char oldSerialPort[64]; - int OldPort = KISSPortNum; - char oldHost[128]; - - strcpy(oldSerialPort, SerialPort); - strcpy(oldHost, KISSHost); - - KISSEnable = KISS->KISSEnable->isChecked(); - actHost[18]->setVisible(KISSEnable); // Show KISS Connect Line - - strcpy(MYCALL, KISS->MYCALL->text().toUtf8().toUpper()); - - memset(axMYCALL, 0, 7); - ConvToAX25(MYCALL, axMYCALL); - - Q = KISS->Port->text(); - KISSPortNum = Q.toInt(); - - Q = KISS->Speed->text(); - KISSBAUD = Q.toInt(); - - strcpy(KISSHost, KISS->Host->text().toUtf8().toUpper()); - - Q = KISS->SerialPort->currentText(); - strcpy(SerialPort, Q.toString().toUtf8()); - - Q = KISS->Paclen->text(); - kisspaclen[0] = Q.toInt(); - Q = KISS->Maxframe->text(); - maxframe[0] = Q.toInt(); - Q = KISS->Frack->text(); - frack_time[0] = Q.toInt(); - Q = KISS->Retries->text(); - fracks[0] = Q.toInt(); - - myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable); - - - if (KISSEnable != OldEnable || KISSPortNum != OldPort || - strcmp(oldHost, KISSHost) != 0 || - strcmp(oldSerialPort, SerialPort) != 0) - { - // (re)start connection - - if (OldEnable) - { - if (KISSEnable) - Status3->setText("KISS Closed"); - else - Status3->setText("KISS Disabled"); - - KISSConnected = 0; - - if (KISSSock && KISSSock->ConnectedState == QAbstractSocket::ConnectedState) - KISSSock->disconnectFromHost(); - else if (m_serial) - closeSerialPort(); - } - } - - delete(KISS); - SaveSettings(); - deviceUI->accept(); - - // QSize newSize(this->size()); - // QSize oldSize(this->size()); - - // QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); - - // QCoreApplication::postEvent(this, myResizeEvent); -} - -void QtTermTCP::KISSreject() -{ - delete(KISS); - deviceUI->reject(); -} - - - - - -void QtTermTCP::VARASlot() -{ - // This runs the VARA Configuration dialog - - char valChar[80]; - - Dev = new(Ui_Dialog); - - QDialog UI; - - Dev->setupUi(&UI); - - UI.setFont(*menufont); - - deviceUI = &UI; - - Dev->VARAEnable->setChecked(VARAEnable); - Dev->TermCall->setText(VARATermCall); - - SetVARAParams(); - - connect(Dev->VARAHF, SIGNAL(toggled(bool)), this, SLOT(VARAHFChanged(bool))); - connect(Dev->VARAFM, SIGNAL(toggled(bool)), this, SLOT(VARAFMChanged(bool))); - connect(Dev->VARASAT, SIGNAL(toggled(bool)), this, SLOT(VARASATChanged(bool))); - - if (VARA500) - Dev->VARA500->setChecked(true); - else if (VARA2750) - Dev->VARA2750->setChecked(true); - else - Dev->VARA2300->setChecked(true); - - if (VARAHF) - Dev->VARAHF->setChecked(true); - else if (VARAFM) - Dev->VARAFM->setChecked(true); - else if (VARASAT) - Dev->VARASAT->setChecked(true); - - if (VARAHF == 0) - Dev->HFMode->setVisible(false); - - connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool))); - connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); - - if (PTTMode == PTTCAT) - Dev->CAT->setChecked(true); - else - Dev->RTSDTR->setChecked(true); - - if (CATHex) - Dev->CATHex->setChecked(true); - else - Dev->CATText->setChecked(true); - - sprintf(valChar, "%d", pttGPIOPin); - Dev->GPIOLeft->setText(valChar); - sprintf(valChar, "%d", pttGPIOPinR); - Dev->GPIORight->setText(valChar); - - Dev->VIDPID->setText(CM108Addr); - - - QStringList items; - -#ifdef USESERIAL - - for (const QSerialPortInfo &info : Ports) - { - items.append(info.portName()); - } - - items.sort(); - -#endif - - Dev->PTTPort->addItem("None"); - Dev->PTTPort->addItem("CM108"); - -#ifdef __ARM_ARCH - - // Dev->PTTPort->addItem("GPIO"); - -#endif - - Dev->PTTPort->addItem("FLRIG"); - Dev->PTTPort->addItem("HAMLIB"); - - for (const QString &info : items) - { - Dev->PTTPort->addItem(info); - } - - Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString)); - - PTTPortChanged(0); // Force reevaluation - - QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept())); - QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject())); - - UI.exec(); - -} - -extern QProcess *process; - -void ClosePTTPort(); - -void QtTermTCP::deviceaccept() -{ - QVariant Q; - - int OldEnable = VARAEnable; - int OldPort = VARAPortNum; - char oldHost[128]; - char oldPath[256]; - - strcpy(oldHost, VARAHost); - strcpy(oldPath, VARAPath); - - VARAEnable = Dev->VARAEnable->isChecked(); - - strcpy(VARATermCall, Dev->TermCall->text().toUtf8().toUpper()); - - Q = Dev->Port->text(); - - VARAPortNum = Q.toInt(); - strcpy(VARAHost, Dev->Host->text().toUtf8().toUpper()); - strcpy(VARAPath, Dev->Path->text().toUtf8()); - strcpy(VARAInit, Dev->InitCommands->text().toUtf8()); - - VARA500 = Dev->VARA500->isChecked(); - VARA2300 = Dev->VARA2300->isChecked(); - VARA2750 = Dev->VARA2750->isChecked(); - - VARAHF = Dev->VARAHF->isChecked(); - VARAFM = Dev->VARAFM->isChecked(); - VARASAT = Dev->VARASAT->isChecked(); - - if (VARAHF) - { - strcpy(VARAHostHF, VARAHost); - strcpy(VARAPathHF, VARAPath); - VARAPortHF = VARAPortNum; - } - else if (VARAFM) - { - strcpy(VARAHostFM, VARAHost); - strcpy(VARAPathFM, VARAPath); - VARAPortFM = VARAPortNum; - } - else if (VARASAT) - { - strcpy(VARAHostSAT, VARAHost); - strcpy(VARAPathSAT, VARAPath); - VARAPortSAT = VARAPortNum; - } - - Q = Dev->PTTPort->currentText(); - strcpy(PTTPort, Q.toString().toUtf8()); - - if (Dev->CAT->isChecked()) - PTTMode = PTTCAT; - else - PTTMode = PTTRTS; - - if (Dev->CATHex->isChecked()) - CATHex = 1; - else - CATHex = 0; - - Q = Dev->PTTOn->text(); - strcpy(PTTOnString, Q.toString().toUtf8()); - Q = Dev->PTTOff->text(); - strcpy(PTTOffString, Q.toString().toUtf8()); - - Q = Dev->CATSpeed->text(); - PTTBAUD = Q.toInt(); - - Q = Dev->GPIOLeft->text(); - pttGPIOPin = Q.toInt(); - - Q = Dev->GPIORight->text(); - pttGPIOPinR = Q.toInt(); - - Q = Dev->VIDPID->text(); - - if (strcmp(PTTPort, "CM108") == 0) - strcpy(CM108Addr, Q.toString().toUtf8()); - else if (strcmp(PTTPort, "HAMLIB") == 0) - { - HamLibPort = Q.toInt(); - Q = Dev->PTTOn->text(); - strcpy(HamLibHost, Q.toString().toUtf8()); - } - - if (VARAEnable != OldEnable || VARAPortNum != OldPort || strcmp(oldHost, VARAHost) != 0) - { - // (re)start connection - - if (OldEnable && VARASock && VARASock->ConnectedState == QAbstractSocket::ConnectedState) - { - VARASock->disconnectFromHost(); - if (VARADataSock) - VARADataSock->disconnectFromHost(); - Status2->setText("VARA Disconnected"); - } - } - - if (process && process->state() == QProcess::Running) - if ((VARAEnable == 0 || strcmp(oldPath, VARAPath) != 0)) - process->close(); - - myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable); - - ClosePTTPort(); - OpenPTTPort(); - - delete(Dev); - SaveSettings(); - deviceUI->accept(); - - QSize newSize(this->size()); - QSize oldSize(this->size()); - - QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); - - QCoreApplication::postEvent(this, myResizeEvent); -} - -void QtTermTCP::devicereject() -{ - delete(Dev); - deviceUI->reject(); -} - -// This handles incoming connections - -void QtTermTCP::onNewConnection() -{ - myTcpSocket *clientSocket = (myTcpSocket *)_server->nextPendingConnection(); - - clientSocket->Sess = NULL; - - Ui_ListenSession * S; - Ui_ListenSession * Sess = NULL; - - char Title[512]; - int i = 0; - - QByteArray Host = clientSocket->peerAddress().toString().toUtf8(); - - if (TermMode == MDI) - { - // See if an old session can be reused - - for (int i = 0; i < _sessions.size(); ++i) - { - S = _sessions.at(i); - - // for (Ui_ListenSession * S: _sessions) - // { - if ((S->SessionType & Listen) && S->clientSocket == NULL) - { - Sess = S; - break; - } - } - - // Create a window if none found, else reuse old - - if (Sess == NULL) - { - Sess = newWindow(this, Listen); - } - - QByteArray Host = clientSocket->peerAddress().toString().toUtf8(); - } - else - { - // Single or Tabbed - look for free session - - for (i = 0; i < _sessions.size(); ++i) - { - S = _sessions.at(i); - - if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL) - { - Sess = S; - break; - } - } - - if (Sess == NULL) - { - // Clear connection - - clientSocket->disconnectFromHost(); - return; - } - } - - _sockets.push_back(clientSocket); - - clientSocket->Sess = Sess; - - // See if any data from host - first msg should be callsign - - clientSocket->waitForReadyRead(1000); - - QByteArray datas = clientSocket->readAll(); - - datas.chop(2); - datas.truncate(10); // Just in case! - - datas.append('\0'); - - sprintf(Title, "Inward Connect from %s:%d Call " + datas, - Host.data(), clientSocket->peerPort()); - - if (TermMode == MDI) - { - Sess->setWindowTitle(Title); - } - else if (TermMode == Tabbed) - { - tabWidget->setTabText(i, datas.data()); - 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(); -} - -void QtTermTCP::onSocketStateChanged(QAbstractSocket::SocketState socketState) -{ - myTcpSocket* sender = static_cast(QObject::sender()); - Ui_ListenSession * Sess = (Ui_ListenSession *)sender->Sess; - - if (socketState == QAbstractSocket::UnconnectedState) - { - char Msg[] = "Disconnected\r"; - - WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), - Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red - - if (TermMode == MDI) - { - if (Sess->SessionType == Mon) // Mon Only - Sess->setWindowTitle("Monitor Session Disconnected"); - else - Sess->setWindowTitle("Disconnected"); - } - else if (TermMode == Tabbed) - { - if (Sess->SessionType == Mon) // Mon Only - tabWidget->setTabText(Sess->Tab, "Monitor"); - else - { - char Label[16]; - sprintf(Label, "Sess %d", Sess->Tab + 1); - tabWidget->setTabText(Sess->Tab, Label); - } - } - else if (TermMode == Single) - { - if (Sess->AGWMonSession) - mythis->setWindowTitle("AGW Monitor Window"); - else - { - if (Sess->SessionType == Mon) // Mon Only - this->setWindowTitle("Monitor Session Disconnected"); - else - this->setWindowTitle("Disconnected"); - } - } - - if (Sess->TTActive) - { - Sess->TTActive = 0; - DoTermResize(Sess); - } - - Sess->PortMonString[0] = 0; - - // delete(Sess->clientSocket); - Sess->clientSocket = NULL; - - discAction->setEnabled(false); - - if ((Sess->SessionType & Listen)) - _sockets.removeOne(sender); - else - { - connectMenu->setEnabled(true); - YAPPSend->setEnabled(false); - } - } - else if (socketState == QAbstractSocket::ConnectedState) - { - char Signon[256]; - char Title[128]; - - // only seems to be triggered for outward connect - - sprintf(Signon, "%s\r%s\rBPQTERMTCP\r", UserName[Sess->CurrentHost], Password[Sess->CurrentHost]); - - Sess->clientSocket->write(Signon); - - discAction->setEnabled(true); - YAPPSend->setEnabled(true); - connectMenu->setEnabled(false); - - SendTraceOptions(Sess); - - Sess->InputMode = 0; - Sess->SlowTimer = 0; - Sess->MonData = 0; - Sess->OutputSaveLen = 0; // Clear any part line - Sess->MonSaveLen = 0; // Clear any part line - - if (Sess->SessionType == Mon) // Mon Only - sprintf(Title, "Monitor Session Connected to %s", Host[Sess->CurrentHost]); - else - { - char Label[256]; - - if (SessName[Sess->CurrentHost][0]) - sprintf(Label, "%s(%s)", Host[Sess->CurrentHost], SessName[Sess->CurrentHost]); - else - strcpy(Label, Host[Sess->CurrentHost]); - - sprintf(Title, "Connected to %s", Label); - } - - if (TermMode == MDI) - Sess->setWindowTitle(Title); - else if (TermMode == Tabbed) - { - if (SessName[Sess->CurrentHost][0]) - tabWidget->setTabText(tabWidget->currentIndex(), SessName[Sess->CurrentHost]); - else - tabWidget->setTabText(tabWidget->currentIndex(), Host[Sess->CurrentHost]); - } - else if (TermMode == Single) - this->setWindowTitle(Title); - } -} - -void QtTermTCP::updateWindowMenu() -{ - if (TermMode == MDI) - { - windowMenu->clear(); - windowMenu->addAction(newTermAct); - windowMenu->addAction(newMonAct); - windowMenu->addAction(newCombinedAct); - windowMenu->addSeparator(); - windowMenu->addAction(closeAct); - windowMenu->addAction(closeAllAct); - windowMenu->addSeparator(); - windowMenu->addAction(tileAct); - windowMenu->addAction(cascadeAct); - windowMenu->addSeparator(); - windowMenu->addAction(nextAct); - windowMenu->addAction(previousAct); - windowMenu->addAction(quitAction); - windowMenu->addAction(windowMenuSeparatorAct); - - QList windows = mdiArea->subWindowList(); - windowMenuSeparatorAct->setVisible(!windows.isEmpty()); - - Ui_ListenSession * Sess; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - Sess->actActivate = windowMenu->addAction(Sess->sw->windowTitle()); - QAction::connect(Sess->actActivate, SIGNAL(triggered()), this, SLOT(actActivate())); - Sess->actActivate->setCheckable(true); - Sess->actActivate->setChecked(ActiveSubWindow == Sess->sw); - } - } - else if (TermMode == Tabbed) - { - windowMenu->clear(); - - Ui_ListenSession * Sess = (Ui_ListenSession *)tabWidget->currentWidget(); - - QActionGroup * termGroup = new QActionGroup(this); - - delete(TabSingle); - delete(TabBoth); - delete(TabMon); - - TabSingle = setupMenuLine(nullptr, (char *)"Terminal Only", this, (Sess->SessionType == Term)); - TabBoth = setupMenuLine(nullptr, (char *)"Terminal + Monitor", this, (Sess->SessionType == Term + Mon)); - TabMon = setupMenuLine(nullptr, (char *)"Monitor Only", this, (Sess->SessionType == Mon)); - - termGroup->addAction(TabSingle); - termGroup->addAction(TabBoth); - termGroup->addAction(TabMon); - - windowMenu->addAction(TabSingle); - windowMenu->addAction(TabBoth); - windowMenu->addAction(TabMon); - - } -} - -Ui_ListenSession::~Ui_ListenSession() -{ - if (this->clientSocket) - { - int loops = 100; - this->clientSocket->disconnectFromHost(); - while (loops-- && this->clientSocket->state() != QAbstractSocket::UnconnectedState) - QThread::msleep(10); - } -} - -extern "C" void setTraceOff(Ui_ListenSession * Sess) -{ - if ((Sess->SessionType & Mon) == 0) - return; // Not Monitor - - if (Sess->AGWMonSession) - return; - - char Buffer[80]; - int Len = sprintf(Buffer, "\\\\\\\\0 0 0 0 0 0 0 0\r"); - - SocketFlush(Sess); - SocketSend(Sess, Buffer, Len); - SocketFlush(Sess); -} - - -extern "C" void SendTraceOptions(Ui_ListenSession * Sess) -{ - if ((Sess->SessionType & Mon) == 0) - return; // Not Monitor - - if (Sess->AGWMonSession) - return; - - char Buffer[80]; - int Len = sprintf(Buffer, "\\\\\\\\%llx %x %x %x %x %x %x %x\r", Sess->portmask, Sess->mtxparam, Sess->mcomparam, - Sess->MonitorNODES, Sess->MonitorColour, Sess->monUI, 0, 1); - - strcpy(&MonParams[Sess->CurrentHost][0], &Buffer[4]); - SaveSettings(); - SocketFlush(Sess); - SocketSend(Sess, Buffer, Len); - SocketFlush(Sess); -} - -void QtTermTCP::doNewTerm() -{ - newWindow(this, Term); -} - -void QtTermTCP::doNewMon() -{ - newWindow(this, Mon); -} - -void QtTermTCP::doNewCombined() -{ - newWindow(this, Term + Mon); -} - -void QtTermTCP::doCascade() -{ - // Qt Cascade Minimizes windows so do it ourselves - - int x = 0, y = 0; - - Ui_ListenSession * Sess; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - Sess->sw->move(x, y); - x += 14; - y += 30; - } -} - -void QtTermTCP::actActivate() -{ - QAction * sender = static_cast(QObject::sender()); - - Ui_ListenSession * Sess; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - if (Sess->actActivate == sender) - { - mdiArea->setActiveSubWindow(Sess->sw); - return; - } - } -} - - -void QtTermTCP::xon_mdiArea_changed() -{ - // This is triggered when the Active MDI window changes - // and is used to enable/disable Connect, Disconnect and YAPP Send - - - QMdiSubWindow *SW = mdiArea->activeSubWindow(); - - // Dont waste time if not changed - - if (ActiveSubWindow == SW) - return; - - ActiveSubWindow = SW; - - Ui_ListenSession * Sess; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - // for (Ui_ListenSession * Sess : _sessions) - // { - if (Sess->sw == SW) - { - ActiveSession = Sess; - - if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) - { - discAction->setEnabled(true); - YAPPSend->setEnabled(true); - connectMenu->setEnabled(false); - } - else if (Sess->AGWMonSession) - { - // Connected AGW Monitor Session - - discAction->setEnabled(false); - YAPPSend->setEnabled(false); - connectMenu->setEnabled(false); - } - else if (Sess->AGWSession || Sess->KISSSession) - { - // Connected AGW or KISS Terminal Session - - discAction->setEnabled(true); - YAPPSend->setEnabled(true); - connectMenu->setEnabled(false); - } - else - { - // Not connected - - discAction->setEnabled(false); - YAPPSend->setEnabled(false); - - if ((Sess->SessionType & Listen)) // Listen Sessions can't connect - connectMenu->setEnabled(false); - else - connectMenu->setEnabled(true); - } - - // If a monitor Window, change Monitor config settings - - if (Sess->PortMonString[0]) - { - char * ptr = (char *)malloc(1024); - memcpy(ptr, Sess->PortMonString, 1024); - - int NumberofPorts = atoi((char *)&ptr[2]); - char *p, *Context; - char msg[80]; - int portnum; - char delim[] = "|"; - - // Remove old Monitor menu - - for (int i = 0; i < 32; i++) - { - SetPortMonLine(i, (char *)"", 0, 0); // Set all hidden - } - - p = strtok_s((char *)&ptr[2], delim, &Context); - - while (NumberofPorts--) - { - p = strtok_s(NULL, delim, &Context); - if (p == NULL) - break; - - portnum = atoi(p); - - sprintf(msg, "Port %s", p); - - if (portnum == 0) - portnum = 33; - - if (Sess->portmask & (1ll << (portnum - 1))) - SetPortMonLine(portnum, msg, 1, 1); - else - SetPortMonLine(portnum, msg, 1, 0); - } - free(ptr); - - MonTX->setChecked(Sess->mtxparam); - MonSup->setChecked(Sess->mcomparam); - MonUI->setChecked(Sess->monUI); - MonNodes->setChecked(Sess->MonitorNODES); - MonColour->setChecked(Sess->MonitorColour); - - } - - return; - } - } -} - -void QtTermTCP::doFonts() -{ - fontDialog * xx = new fontDialog(0); - xx->exec(); -} - -void QtTermTCP::doMFonts() -{ - fontDialog * xx = new fontDialog(1); - xx->exec(); -} - -QColor TempmonBackground = monBackground; -QColor TemptermBackground = termBackground; -QColor TempinputBackground = inputBackground; - -QColor TempmonRxText = monRxText; -QColor TempmonTxText = monTxText; -QColor TempmonOtherText = monOtherText; - -QColor TempoutputText = outputText; -QColor TempEchoText = EchoText; -QColor TempWarningText = WarningText; - - -QColor TempinputText = inputText; - - -void setDialogColours() -{ - char monStyle[128]; - - sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", - TempmonOtherText.red(), TempmonOtherText.green(), TempmonOtherText.blue(), - TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); - - COLOURS->MonitorBG->setStyleSheet(monStyle); - COLOURS->MonOther->setStyleSheet(monStyle); - - sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", - TempmonTxText.red(), TempmonTxText.green(), TempmonTxText.blue(), - TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); - COLOURS->MonTX->setStyleSheet(monStyle); - - sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", - TempmonRxText.red(), TempmonRxText.green(), TempmonRxText.blue(), - TempmonBackground.red(), TempmonBackground.green(), TempmonBackground.blue()); - - COLOURS->MonRX->setStyleSheet(monStyle); - - sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", - TempoutputText.red(), TempoutputText.green(), TempoutputText.blue(), - TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); - - COLOURS->TermBG->setStyleSheet(monStyle); - COLOURS->TermNormal->setStyleSheet(monStyle); - - sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", - TempEchoText.red(), TempEchoText.green(), TempEchoText.blue(), - TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); - - COLOURS->Echoed->setStyleSheet(monStyle); - - sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", - TempWarningText.red(), TempWarningText.green(), TempWarningText.blue(), - TemptermBackground.red(), TemptermBackground.green(), TemptermBackground.blue()); - - COLOURS->Warning->setStyleSheet(monStyle); - - sprintf(monStyle, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", - TempinputText.red(), TempinputText.green(), TempinputText.blue(), - TempinputBackground.red(), TempinputBackground.green(), TempinputBackground.blue()); - - COLOURS->InputBG->setStyleSheet(monStyle); - COLOURS->InputColour->setStyleSheet(monStyle); - -} - -void QtTermTCP::doColours() -{ - COLOURS = new(Ui_ColourDialog); - - QDialog UI; - - COLOURS->setupUi(&UI); - - UI.setFont(*menufont); - - deviceUI = &UI; - - TempmonBackground = monBackground; - TempmonRxText = monRxText; - TempmonTxText = monTxText; - TempmonOtherText = monOtherText; - - TemptermBackground = termBackground; - TempoutputText = outputText; - TempEchoText = EchoText; - TempWarningText = WarningText; - - TempinputBackground = inputBackground; - TempinputText = inputText; - - setDialogColours(); - - QObject::connect(COLOURS->MonitorBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); - QObject::connect(COLOURS->TermBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); - QObject::connect(COLOURS->InputBG, SIGNAL(clicked()), this, SLOT(ColourPressed())); - QObject::connect(COLOURS->MonRX, SIGNAL(clicked()), this, SLOT(ColourPressed())); - QObject::connect(COLOURS->MonTX, SIGNAL(clicked()), this, SLOT(ColourPressed())); - QObject::connect(COLOURS->MonOther, SIGNAL(clicked()), this, SLOT(ColourPressed())); - QObject::connect(COLOURS->TermNormal, SIGNAL(clicked()), this, SLOT(ColourPressed())); - QObject::connect(COLOURS->Echoed, SIGNAL(clicked()), this, SLOT(ColourPressed())); - QObject::connect(COLOURS->Warning, SIGNAL(clicked()), this, SLOT(ColourPressed())); - QObject::connect(COLOURS->InputColour, SIGNAL(clicked()), this, SLOT(ColourPressed())); - - QObject::connect(COLOURS->okButton, SIGNAL(clicked()), this, SLOT(Colouraccept())); - QObject::connect(COLOURS->cancelButton, SIGNAL(clicked()), this, SLOT(Colourreject())); - - UI.exec(); - -} - -void QtTermTCP::ColourPressed() -{ - char Name[32]; - - strcpy(Name, sender()->objectName().toUtf8()); - - if (strcmp(Name, "MonitorBG") == 0) - TempmonBackground = setColor(TempmonBackground); - - else if (strcmp(Name, "MonTX") == 0) - TempmonTxText = setColor(TempmonTxText); - - else if (strcmp(Name, "MonRX") == 0) - TempmonRxText = setColor(TempmonRxText); - - else if (strcmp(Name, "MonOther") == 0) - TempmonOtherText = setColor(TempmonOtherText); - - else if (strcmp(Name, "TermBG") == 0) - TemptermBackground = setColor(TemptermBackground); - - else if (strcmp(Name, "InputBG") == 0) - TempinputBackground = setColor(TempinputBackground); - - else if (strcmp(Name, "InputColour") == 0) - TempinputText = setColor(TempinputText); - - else if (strcmp(Name, "TermNormal") == 0) - TempoutputText = setColor(TempoutputText); - - else if (strcmp(Name, "Echoed") == 0) - TempEchoText = setColor(TempEchoText); - - else if (strcmp(Name, "Warning") == 0) - TempWarningText = setColor(TempWarningText); - - setDialogColours(); -} - - -void QtTermTCP::Colouraccept() -{ - monBackground = TempmonBackground; - monRxText = TempmonRxText; - monTxText = TempmonTxText; - monOtherText = TempmonOtherText; - - termBackground = TemptermBackground; - EchoText = TempEchoText; - WarningText = TempWarningText; - outputText = TempoutputText; - - inputBackground = TempinputBackground; - inputText = TempinputText; - - // Set background colour for new windows - - sprintf(monStyleSheet, "background-color: rgb(%d, %d, %d);", - monBackground.red(), monBackground.green(), monBackground.blue()); - - sprintf(termStyleSheet, "background-color: rgb(%d, %d, %d);", - termBackground.red(), termBackground.green(), termBackground.blue()); - - sprintf(inputStyleSheet, "color: rgb(%d, %d, %d); background-color: rgb(%d, %d, %d);", - inputText.red(), inputText.green(), inputText.blue(), - inputBackground.red(), inputBackground.green(), inputBackground.blue()); - - // Update existing windows - - for (int i = 0; i < _sessions.size(); ++i) - { - Ui_ListenSession * S = _sessions.at(i); - - if (S->monWindow) - S->monWindow->setStyleSheet(monStyleSheet); - - if (S->termWindow) - S->termWindow->setStyleSheet(termStyleSheet); - - if (S->inputWindow) - S->inputWindow->setStyleSheet(inputStyleSheet); - - } - - - delete(COLOURS); - - SaveSettings(); - deviceUI->accept(); -} - -void QtTermTCP::Colourreject() -{ - delete(COLOURS); - deviceUI->reject(); -} - - -void QtTermTCP::ConnecttoVARA() -{ - - delete(VARASock); - - VARASock = new myTcpSocket(); - - connect(VARASock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(VARAdisplayError(QAbstractSocket::SocketError))); - connect(VARASock, SIGNAL(readyRead()), this, SLOT(VARAreadyRead())); - connect(VARASock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onVARASocketStateChanged(QAbstractSocket::SocketState))); - - VARASock->connectToHost(VARAHost, VARAPortNum); - - Status2->setText("VARA Control Connecting"); - - return; -} - - -void QtTermTCP::VARATimer() -{ - // Runs every 10 Seconds - - if (VARAConnected == 0 && VARAConnecting == 0) - { - if (process == nullptr || process->state() == QProcess::NotRunning) - { - if (VARAPath[0]) - { - process = new QProcess(this); - QString file = VARAPath; - process->start(file); - } - } - QThread::msleep(1000); - VARAConnecting = true; - ConnecttoVARA(); - } -} - - -void QtTermTCP::VARAdisplayError(QAbstractSocket::SocketError socketError) -{ - switch (socketError) - { - case QAbstractSocket::RemoteHostClosedError: - break; - - case QAbstractSocket::HostNotFoundError: - QMessageBox::information(this, tr("QtTermTCP"), - tr("VARA host was not found. Please check the " - "host name and portsettings->")); - - Status2->setText("VARA Connection Failed"); - - break; - - case QAbstractSocket::ConnectionRefusedError: - - Status2->setText("VARA Connection Refused"); - break; - - default: - - Status2->setText("VARA Connection Failed"); - } - - VARAConnecting = 0; - VARAConnected = 0; -} - -void QtTermTCP::VARAreadyRead() -{ - int Read; - char Buffer[4096]; - char * ptr; - char * Msg; - myTcpSocket* Socket = static_cast(QObject::sender()); - - // read the data from the socket - - Read = Socket->read((char *)Buffer, 4095); - - Buffer[Read] = 0; - - Msg = Buffer; - - ptr = strchr(Msg, 0x0d); - - while (ptr) - { - *ptr++ = 0; - - if (strcmp(Msg, "IAMALIVE") == 0) - { - } - else if (strcmp(Msg, "PTT ON") == 0) - { - RadioPTT(1); - } - else if (strcmp(Msg, "PTT OFF") == 0) - { - RadioPTT(0); - } - else if (strcmp(Msg, "PENDING") == 0) - { - } - else if (strcmp(Msg, "CANCELPENDING") == 0) - { - } - else if (strcmp(Msg, "OK") == 0) - { - } - else if (memcmp(Msg, "CONNECTED ", 10) == 0) - { - Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess; - char Title[128] = ""; - char CallFrom[64] = ""; - char CallTo[64] = ""; - char Mode[64] = ""; - char Message[128]; - int n; - - - sscanf(&Msg[10], "%s %s %s", CallFrom, CallTo, Mode); - - if (Sess) - { - if (Mode[0]) - sprintf(Title, "Connected to %s %s Mode", CallTo, Mode); - else - sprintf(Title, "Connected to %s", CallTo); - - n = sprintf(Message, "%s\r\n", Title); - WritetoOutputWindow(Sess, (unsigned char *)Message, n); - - if (TermMode == MDI) - Sess->setWindowTitle(Title); - else if (TermMode == Tabbed) - tabWidget->setTabText(Sess->Tab, CallTo); - else if (TermMode == Single) - mythis->setWindowTitle(Title); - - setMenus(true); - } - else - { - // Incoming Call - - Ui_ListenSession * S; - int i = 0; - - if (TermMode == MDI) - { - // See if an old session can be reused - - for (int i = 0; i < _sessions.size(); ++i) - { - S = _sessions.at(i); - - // for (Ui_ListenSession * S: _sessions) - // { - if ((S->SessionType & Listen) && S->clientSocket == NULL) - { - Sess = S; - break; - } - } - - // Create a window if none found, else reuse old - - if (Sess == NULL) - { - Sess = newWindow(this, Listen); - } - } - else - { - // Single or Tabbed - look for free session - - for (i = 0; i < _sessions.size(); ++i) - { - S = _sessions.at(i); - - if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL) - { - Sess = S; - break; - } - } - } - - if (Sess == NULL) - { - // Clear connection - - VARASock->write("DISCONNECT\r"); - } - else - { - if (Mode[0]) - { - sprintf(Title, "Connected to %s Mode %s", CallFrom, Mode); - n = sprintf(Message, "Incoming Connected from %s %s Mode\r\n", CallFrom, Mode); - } - else - { - sprintf(Title, "Connected to %s", CallFrom); - n = sprintf(Message, "Incoming Connected from %s\r\n", CallFrom); - } - - WritetoOutputWindow(Sess, (unsigned char *)Message, n); - - VARASock->Sess = Sess; - VARADataSock->Sess = Sess; - - if (TermMode == MDI) - Sess->setWindowTitle(Title); - else if (TermMode == Tabbed) - { - tabWidget->setTabText(Sess->Tab, CallFrom); - tabWidget->tabBar()->setTabTextColor(Sess->Tab, newTabText); - } - else if (TermMode == Single) - mythis->setWindowTitle(Title); - - setMenus(true); - - } - } - } - else if (strcmp(Msg, "DISCONNECTED") == 0) - { - Ui_ListenSession * Sess = (Ui_ListenSession *)VARASock->Sess; - - if (Sess) - { - WritetoOutputWindow(Sess, (unsigned char *)"Disconnected\r\n", 14); - VARASock->Sess = 0; - VARADataSock->Sess = 0; - - if (TermMode == MDI) - { - if (Sess->SessionType == Mon) // Mon Only - Sess->setWindowTitle("Monitor Session Disconnected"); - else - Sess->setWindowTitle("Disconnected"); - } - else if (TermMode == Tabbed) - { - if (Sess->SessionType == Mon) // Mon Only - tabWidget->setTabText(Sess->Tab, "Monitor"); - else - { - char Label[16]; - sprintf(Label, "Sess %d", Sess->Tab + 1); - tabWidget->setTabText(Sess->Tab, Label); - } - } - else if (TermMode == Single) - { - if (Sess->AGWMonSession) - mythis->setWindowTitle("AGW Monitor Window"); - else - { - if (Sess->SessionType == Mon) // Mon Only - this->setWindowTitle("Monitor Session Disconnected"); - else - this->setWindowTitle("Disconnected"); - } - } - - setMenus(false); - } - } - - Msg = ptr; - - ptr = strchr(Msg, 0x0d); - } - - - -} - -void QtTermTCP::onVARASocketStateChanged(QAbstractSocket::SocketState socketState) -{ - // myTcpSocket* sender = static_cast(QObject::sender()); - - if (socketState == QAbstractSocket::UnconnectedState) - { - // Close any connections - - Status2->setText("VARA Disconnected"); - actHost[17]->setVisible(0); - - VARAConnecting = VARAConnected = 0; - } - else if (socketState == QAbstractSocket::ConnectedState) - { - // Connect Data Session. Leave Connecting till that completes - - VARADataSock = new myTcpSocket(); - - connect(VARADataSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(VARADatadisplayError(QAbstractSocket::SocketError))); - connect(VARADataSock, SIGNAL(readyRead()), this, SLOT(VARADatareadyRead())); - connect(VARADataSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onVARADataSocketStateChanged(QAbstractSocket::SocketState))); - - VARADataSock->connectToHost(VARAHost, VARAPortNum + 1); - Status2->setText("VARA Data Connecting"); - } -} - - -void QtTermTCP::VARADatadisplayError(QAbstractSocket::SocketError socketError) -{ - switch (socketError) - { - case QAbstractSocket::RemoteHostClosedError: - break; - - case QAbstractSocket::HostNotFoundError: - QMessageBox::information(this, tr("QtTermTCP"), - tr("VARA host was not found. Please check the " - "host name and portsettings->")); - - Status2->setText("VARA Connection Failed"); - - break; - - case QAbstractSocket::ConnectionRefusedError: - - Status2->setText("VARA Connection Refused"); - break; - - default: - - Status2->setText("VARA Connection Failed"); - } - - VARAConnecting = 0; - VARAConnected = 0; -} - -void QtTermTCP::VARADatareadyRead() -{ - int Read; - unsigned char Buffer[4096]; - myTcpSocket* Socket = static_cast(QObject::sender()); - - Ui_ListenSession * Sess = (Ui_ListenSession *)Socket->Sess; - - // read the data from the socket - - Read = Socket->read((char *)Buffer, 2047); - - while (Read > 0) - { - // if (InputMode == 'Y') // Yapp - // { - // QString myString = QString::fromUtf8((char*)Buffer, Read); - // QByteArray ptr = myString.toLocal8Bit(); - // memcpy(Buffer, ptr.data(), ptr.length()); - // Read = ptr.length(); - // } - - ProcessReceivedData(Sess, Buffer, Read); - - QString myString = QString::fromUtf8((char*)Buffer); - // qDebug() << myString; - Read = Socket->read((char *)Buffer, 2047); - } -} - - -void QtTermTCP::onVARADataSocketStateChanged(QAbstractSocket::SocketState socketState) -{ - // myTcpSocket* sender = static_cast(QObject::sender()); - - if (socketState == QAbstractSocket::UnconnectedState) - { - // Close any connections - - Status2->setText("VARA Disconnected"); - actHost[17]->setVisible(0); - - VARAConnecting = VARAConnected = 0; - } - else if (socketState == QAbstractSocket::ConnectedState) - { - char VARACommand[256]; - - VARAConnected = 1; - VARAConnecting = 0; - - Status2->setText("VARA Connected"); - - actHost[17]->setVisible(1); // Enable VARA Connect Line - - sprintf(VARACommand, "MYCALL %s\r", VARATermCall); - VARASock->write(VARACommand); - - if (VARA500) - VARASock->write("BW500\r"); - else if (VARA2300) - VARASock->write("BW2300\r"); - else if (VARA2750) - VARASock->write("BW2750\r"); - - VARASock->write("COMPRESSION FILES\r"); - - if (VARAInit[0]) - { - char Copy[512]; - char * param, *context; - - strcpy(Copy, VARAInit); - - param = strtok_s(Copy, ",", &context); - - while (param && param[0]) - { - sprintf(VARACommand, "%s\r", param); - VARASock->write(VARACommand); - param = strtok_s(nullptr, ",", &context); - } - } - - if (listenEnable) - VARASock->write("LISTEN ON\r"); - } -} - -// PTT Stuff - -#include "hidapi.h" - -// Serial Port Stuff - - -QTcpSocket * HAMLIBsock; -int HAMLIBConnected = 0; -int HAMLIBConnecting = 0; - -void QtTermTCP::HAMLIBdisplayError(QAbstractSocket::SocketError socketError) -{ - switch (socketError) - { - case QAbstractSocket::RemoteHostClosedError: - break; - - case QAbstractSocket::HostNotFoundError: - QMessageBox::information(nullptr, tr("QtSM"), - "HAMLIB host was not found. Please check the " - "host name and portsettings->"); - - break; - - case QAbstractSocket::ConnectionRefusedError: - - qDebug() << "HAMLIB Connection Refused"; - break; - - default: - - qDebug() << "HAMLIB Connection Failed"; - break; - - } - - HAMLIBConnecting = 0; - HAMLIBConnected = 0; -} - -void QtTermTCP::HAMLIBreadyRead() -{ - unsigned char Buffer[4096]; - QTcpSocket* Socket = static_cast(QObject::sender()); - - // read the data from the socket. Don't do anyhing with it at the moment - - Socket->read((char *)Buffer, 4095); -} - -void QtTermTCP::onHAMLIBSocketStateChanged(QAbstractSocket::SocketState socketState) -{ - if (socketState == QAbstractSocket::UnconnectedState) - { - // Close any connections - - HAMLIBConnected = 0; - HAMLIBConnecting = 0; - - // delete (HAMLIBsock); - // HAMLIBsock = 0; - - qDebug() << "HAMLIB Connection Closed"; - - } - else if (socketState == QAbstractSocket::ConnectedState) - { - HAMLIBConnected = 1; - HAMLIBConnecting = 0; - qDebug() << "HAMLIB Connected"; - } -} - - -void QtTermTCP::ConnecttoHAMLIB() -{ - delete(HAMLIBsock); - - HAMLIBConnected = 0; - HAMLIBConnecting = 1; - - HAMLIBsock = new QTcpSocket(); - - connect(HAMLIBsock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(HAMLIBdisplayError(QAbstractSocket::SocketError))); - connect(HAMLIBsock, SIGNAL(readyRead()), this, SLOT(HAMLIBreadyRead())); - connect(HAMLIBsock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onHAMLIBSocketStateChanged(QAbstractSocket::SocketState))); - - HAMLIBsock->connectToHost(HamLibHost, HamLibPort); - - return; -} - -void QtTermTCP::HAMLIBSetPTT(int PTTState) -{ - char Msg[16]; - - if (HAMLIBsock == nullptr || HAMLIBsock->state() != QAbstractSocket::ConnectedState) - ConnecttoHAMLIB(); - - if (HAMLIBsock == nullptr || HAMLIBsock->state() != QAbstractSocket::ConnectedState) - return; - - sprintf(Msg, "T %d\r\n", PTTState); - HAMLIBsock->write(Msg); - - HAMLIBsock->waitForBytesWritten(3000); - - QByteArray datas = HAMLIBsock->readAll(); - - qDebug(datas.data()); -} - -QTcpSocket * FLRigsock; -int FLRigConnected = 0; -int FLRigConnecting = 0; - -void QtTermTCP::FLRigdisplayError(QAbstractSocket::SocketError socketError) -{ - switch (socketError) - { - case QAbstractSocket::RemoteHostClosedError: - break; - - case QAbstractSocket::HostNotFoundError: - QMessageBox::information(nullptr, tr("QtSM"), - "FLRig host was not found. Please check the " - "host name and portsettings->"); - - break; - - case QAbstractSocket::ConnectionRefusedError: - - qDebug() << "FLRig Connection Refused"; - break; - - default: - - qDebug() << "FLRig Connection Failed"; - break; - - } - - FLRigConnecting = 0; - FLRigConnected = 0; -} - -void QtTermTCP::FLRigreadyRead() -{ - unsigned char Buffer[4096]; - QTcpSocket* Socket = static_cast(QObject::sender()); - - // read the data from the socket. Don't do anyhing with it at the moment - - Socket->read((char *)Buffer, 4095); -} - -void QtTermTCP::onFLRigSocketStateChanged(QAbstractSocket::SocketState socketState) -{ - if (socketState == QAbstractSocket::UnconnectedState) - { - // Close any connections - - FLRigConnected = 0; - FLRigConnecting = 0; - - // delete (FLRigsock); - // FLRigsock = 0; - - qDebug() << "FLRig Connection Closed"; - - } - else if (socketState == QAbstractSocket::ConnectedState) - { - FLRigConnected = 1; - FLRigConnecting = 0; - qDebug() << "FLRig Connected"; - } -} - - -void QtTermTCP::ConnecttoFLRig() -{ - delete(FLRigsock); - - FLRigConnected = 0; - FLRigConnecting = 1; - - FLRigsock = new QTcpSocket(); - - connect(FLRigsock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(FLRigdisplayError(QAbstractSocket::SocketError))); - connect(FLRigsock, SIGNAL(readyRead()), this, SLOT(FLRigreadyRead())); - connect(FLRigsock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onFLRigSocketStateChanged(QAbstractSocket::SocketState))); - - FLRigsock->connectToHost(FLRigHost, FLRigPort); - - return; -} - -static char MsgHddr[] = "POST /RPC2 HTTP/1.1\r\n" -"User-Agent: XMLRPC++ 0.8\r\n" -"Host: 127.0.0.1:7362\r\n" -"Content-Type: text/xml\r\n" -"Content-length: %d\r\n" -"\r\n%s"; - -static char Req[] = "\r\n" -"%s\r\n" -"%s" -"\r\n"; - -void QtTermTCP::FLRigSetPTT(int PTTState) -{ - int Len; - char ReqBuf[512]; - char SendBuff[512]; - char ValueString[256] = ""; - - sprintf(ValueString, "%d", PTTState); - - Len = sprintf(ReqBuf, Req, "rig.set_ptt", ValueString); - Len = sprintf(SendBuff, MsgHddr, Len, ReqBuf); - - if (FLRigsock == nullptr || FLRigsock->state() != QAbstractSocket::ConnectedState) - ConnecttoFLRig(); - - if (FLRigsock == nullptr || FLRigsock->state() != QAbstractSocket::ConnectedState) - return; - - FLRigsock->write(SendBuff); - - FLRigsock->waitForBytesWritten(3000); - - QByteArray datas = FLRigsock->readAll(); - - qDebug(datas.data()); -} - - - -void QtTermTCP::CATChanged(bool State) -{ - UNUSED(State); - PTTPortChanged(0); -} - -void QtTermTCP::VARAHFChanged(bool State) -{ - Dev->HFMode->setVisible(State); - - if (State) - { - Dev->TNCInfo->setTitle("VARA HF Paramters"); - Dev->Host->setText(VARAHostHF); - Dev->Port->setText(QString::number(VARAPortHF)); - Dev->Path->setText(VARAPathHF); - } -} - -void QtTermTCP::VARAFMChanged(bool State) -{ - if (State) - { - Dev->TNCInfo->setTitle("VARA FM Paramters"); - Dev->Host->setText(VARAHostFM); - Dev->Port->setText(QString::number(VARAPortFM)); - Dev->Path->setText(VARAPathFM); - } -} - -void QtTermTCP::VARASATChanged(bool State) -{ - if (State) - { - Dev->TNCInfo->setTitle("VARA SAT Paramters"); - Dev->Host->setText(VARAHostSAT); - Dev->Port->setText(QString::number(VARAPortSAT)); - Dev->Path->setText(VARAPathSAT); - } -} - -void QtTermTCP::SetVARAParams() -{ - Dev->Host->setText(VARAHost); - Dev->Port->setText(QString::number(VARAPortNum)); - Dev->Path->setText(VARAPath); - Dev->InitCommands->setText(VARAInit); -} - -void QtTermTCP::PTTPortChanged(int Selected) -{ - UNUSED(Selected); - - QVariant Q = Dev->PTTPort->currentText(); - strcpy(NewPTTPort, Q.toString().toUtf8()); - - Dev->RTSDTR->setVisible(false); - Dev->CAT->setVisible(false); - - Dev->PTTOnLab->setVisible(false); - Dev->PTTOn->setVisible(false); - Dev->PTTOff->setVisible(false); - Dev->PTTOffLab->setVisible(false); - Dev->CATLabel->setVisible(false); - Dev->CATSpeed->setVisible(false); - Dev->CATHex->setVisible(false); - Dev->CATText->setVisible(false); - - Dev->GPIOLab->setVisible(false); - Dev->GPIOLeft->setVisible(false); - Dev->GPIORight->setVisible(false); - Dev->GPIOLab2->setVisible(false); - - Dev->CM108Label->setVisible(false); - Dev->VIDPID->setVisible(false); - - if (strcmp(NewPTTPort, "None") == 0) - { - } - else if (strcmp(NewPTTPort, "GPIO") == 0) - { - Dev->GPIOLab->setVisible(true); - Dev->GPIOLeft->setVisible(true); - } - - else if (strcmp(NewPTTPort, "CM108") == 0) - { - Dev->CM108Label->setVisible(true); -#ifdef WIN32 - Dev->CM108Label->setText("CM108 VID/PID"); -#else - Dev->CM108Label->setText("CM108 Device"); -#endif - Dev->VIDPID->setText(CM108Addr); - Dev->VIDPID->setVisible(true); - } - else if (strcmp(NewPTTPort, "HAMLIB") == 0) - { - Dev->CM108Label->setVisible(true); - Dev->CM108Label->setText("rigctrld Port"); - Dev->VIDPID->setText(QString::number(HamLibPort)); - Dev->VIDPID->setVisible(true); - Dev->PTTOnLab->setText("rigctrld Host"); - Dev->PTTOnLab->setVisible(true); - Dev->PTTOn->setText(HamLibHost); - Dev->PTTOn->setVisible(true); - } - else if (strcmp(NewPTTPort, "FLRIG") == 0) - { - Dev->CM108Label->setVisible(true); - Dev->CM108Label->setText("FLRig Port"); - Dev->VIDPID->setText(QString::number(FLRigPort)); - Dev->VIDPID->setVisible(true); - Dev->PTTOnLab->setText("FLRig Host"); - Dev->PTTOnLab->setVisible(true); - Dev->PTTOn->setText(FLRigHost); - Dev->PTTOn->setVisible(true); - } - - else - { - Dev->RTSDTR->setVisible(true); - Dev->CAT->setVisible(true); - - if (Dev->CAT->isChecked()) - { - Dev->CATHex->setVisible(true); - Dev->CATText->setVisible(true); - Dev->PTTOnLab->setVisible(true); - Dev->PTTOnLab->setText("PTT On String"); - Dev->PTTOn->setText(PTTOnString); - Dev->PTTOn->setVisible(true); - Dev->PTTOff->setVisible(true); - Dev->PTTOffLab->setVisible(true); - Dev->PTTOff->setVisible(true); - Dev->PTTOff->setText(PTTOffString); - Dev->CATLabel->setVisible(true); - Dev->CATSpeed->setVisible(true); - Dev->CATSpeed->setText(QString::number(PTTBAUD)); - } - } -} - - - -void DecodeCM108(char * ptr) -{ - // Called if Device Name or PTT = Param is CM108 - -#ifdef WIN32 - - // Next Param is VID and PID - 0xd8c:0x8 or Full device name - // On Windows device name is very long and difficult to find, so - // easier to use VID/PID, but allow device in case more than one needed - - char * next; - long VID = 0, PID = 0; - char product[256] = "Unknown"; - - struct hid_device_info *devs, *cur_dev; - const char *path_to_open = NULL; - hid_device *handle = NULL; - - if (strlen(ptr) > 16) - CM108Device = _strdup(ptr); - else - { - VID = strtol(ptr, &next, 0); - if (next) - PID = strtol(++next, &next, 0); - - // Look for Device - - devs = hid_enumerate((unsigned short)VID, (unsigned short)PID); - cur_dev = devs; - - while (cur_dev) - { - if (cur_dev->product_string) - wcstombs(product, cur_dev->product_string, 255); - - printf("HID Device %s VID %X PID %X", product, cur_dev->vendor_id, cur_dev->product_id); - if (cur_dev->vendor_id == VID && cur_dev->product_id == PID) - { - path_to_open = cur_dev->path; - break; - } - cur_dev = cur_dev->next; - } - - if (path_to_open) - { - handle = hid_open_path(path_to_open); - - if (handle) - { - hid_close(handle); - CM108Device = _strdup(path_to_open); - } - else - { - printf("Unable to open CM108 device %x %x", VID, PID); - } - } - else - printf("Couldn't find CM108 device %x %x", VID, PID); - - hid_free_enumeration(devs); - } -#else - - // Linux - Next Param HID Device, eg /dev/hidraw0 - - CM108Device = strdup(ptr); -#endif -} - - -void QtTermTCP::OpenPTTPort() -{ - PTTMode &= ~PTTCM108; - PTTMode &= ~PTTHAMLIB; - PTTMode &= ~PTTFLRIG; - - if (PTTPort[0] && strcmp(PTTPort, "None") != 0) - { - if (PTTMode == PTTCAT) - { - // convert config strings from Hex - - if (CATHex == 0) // Ascii Strings - { - strcpy((char *)PTTOffCmd, PTTOffString); - PTTOffCmdLen = strlen(PTTOffString); - - strcpy((char *)PTTOnCmd, PTTOnString); - PTTOnCmdLen = strlen(PTTOnString); - } - else - { - char * ptr1 = PTTOffString; - unsigned char * ptr2 = PTTOffCmd; - char c; - int val; - - while ((c = *(ptr1++))) - { - val = c - 0x30; - if (val > 15) val -= 7; - val <<= 4; - c = *(ptr1++) - 0x30; - if (c > 15) c -= 7; - val |= c; - *(ptr2++) = val; - } - - PTTOffCmdLen = ptr2 - PTTOffCmd; - - ptr1 = PTTOnString; - ptr2 = PTTOnCmd; - - while ((c = *(ptr1++))) - { - val = c - 0x30; - if (val > 15) val -= 7; - val <<= 4; - c = *(ptr1++) - 0x30; - if (c > 15) c -= 7; - val |= c; - *(ptr2++) = val; - } - - PTTOnCmdLen = ptr2 - PTTOnCmd; - } - } - - if (strcmp(PTTPort, "GPIO") == 0) - { - // Initialise GPIO for PTT if available - -#ifdef __ARM_ARCH - -// if (gpioInitialise() == 0) -// { -// printf("GPIO interface for PTT available\n"); -// gotGPIO = TRUE; - -// SetupGPIOPTT(); -// } -// else -// printf("Couldn't initialise GPIO interface for PTT\n"); -// -#else - printf("GPIO interface for PTT not available on this platform\n"); -#endif - - } - else if (strcmp(PTTPort, "CM108") == 0) - { - DecodeCM108(CM108Addr); - PTTMode |= PTTCM108; - } - - else if (strcmp(PTTPort, "HAMLIB") == 0) - { - PTTMode |= PTTHAMLIB; - HAMLIBSetPTT(0); // to open port - return; - } - - else if (strcmp(PTTPort, "FLRIG") == 0) - { - PTTMode |= PTTFLRIG; - FLRigSetPTT(0); // to open port - return; - } - - else // Serial Port - { -#ifdef USESERIAL - hPTTDevice = new QSerialPort(this); - hPTTDevice->setPortName(PTTPort); - hPTTDevice->setBaudRate(PTTBAUD); - hPTTDevice->setDataBits(QSerialPort::Data8); - hPTTDevice->setParity(QSerialPort::NoParity); - hPTTDevice->setStopBits(QSerialPort::OneStop); - hPTTDevice->setFlowControl(QSerialPort::NoFlowControl); - if (hPTTDevice->open(QIODevice::ReadWrite)) - { - qDebug() << "PTT Port Opened"; - } - else - { - QMessageBox msgBox; - msgBox.setText("PTT COM Port Open Failed."); - msgBox.exec(); - qDebug() << "PTT Port Open failed"; - delete(hPTTDevice); - hPTTDevice = 0; - } -#endif - } - } -} - -void ClosePTTPort() -{ -#ifdef USESERIAL - if (hPTTDevice) - hPTTDevice->close(); - hPTTDevice = 0; -#endif -} - - -void CM108_set_ptt(int PTTState) -{ - unsigned char io[5]; - int n; - - io[0] = 0; - io[1] = 0; - io[2] = 1 << (3 - 1); - io[3] = PTTState << (3 - 1); - io[4] = 0; - - if (CM108Device == NULL) - return; - -#ifdef WIN32 - hid_device *handle; - - handle = hid_open_path(CM108Device); - - if (!handle) { - printf("unable to open device\n"); - return; - } - - n = hid_write(handle, io, 5); - if (n < 0) - { - printf("Unable to write()\n"); - printf("Error: %ls\n", hid_error(handle)); - } - - hid_close(handle); - -#else - - int fd; - - fd = open(CM108Device, O_WRONLY); - - if (fd == -1) - { - printf("Could not open %s for write, errno=%d\n", CM108Device, errno); - return; - } - - io[0] = 0; - io[1] = 0; - io[2] = 1 << (3 - 1); - io[3] = PTTState << (3 - 1); - io[4] = 0; - - n = write(fd, io, 5); - if (n != 5) - { - printf("Write to %s failed, n=%d, errno=%d\n", CM108Device, n, errno); - } - - close(fd); -#endif - return; - -} - - - -void QtTermTCP::RadioPTT(bool PTTState) -{ -#ifdef __ARM_ARCH - if (useGPIO) - { - // gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); - // return; - } - -#endif - - if ((PTTMode & PTTCM108)) - { - CM108_set_ptt(PTTState); - return; - } - - if ((PTTMode & PTTHAMLIB)) - { - HAMLIBSetPTT(PTTState); - return; - } - - if ((PTTMode & PTTFLRIG)) - { - FLRigSetPTT(PTTState); - return; - } - -#ifdef USESERIAL - - if (hPTTDevice == 0) - return; - - if ((PTTMode & PTTCAT)) - { - if (PTTState) - hPTTDevice->write((char *)PTTOnCmd, PTTOnCmdLen); - else - hPTTDevice->write((char *)PTTOffCmd, PTTOffCmdLen); - - hPTTDevice->flush(); - // hPTTDevice->error(); - return; - - } - - - if ((PTTMode & PTTRTS)) - { - int n = hPTTDevice->setRequestToSend(PTTState); - n = n; - } - -#endif - -} - - - -extern "C" void WriteDebugLog(char * Mess) -{ - qDebug() << Mess; -} - -void QtTermTCP::ConnecttoKISS() -{ - if (strcmp(SerialPort, "TCP") == 0) - { - delete(KISSSock); - - KISSSock = new myTcpSocket(); - KISSSockCopy[0] = (void *)KISSSock; - - - connect(KISSSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(KISSdisplayError(QAbstractSocket::SocketError))); - connect(KISSSock, SIGNAL(readyRead()), this, SLOT(KISSreadyRead())); - connect(KISSSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onKISSSocketStateChanged(QAbstractSocket::SocketState))); - - KISSSock->connectToHost(KISSHost, KISSPortNum); - - Status3->setText("KISS Connecting"); - } - else - openSerialPort(); - - return; -} - - -void QtTermTCP::KISSTimer() -{ - // Runs every 10 Seconds - - if (KISSConnected == 0 && KISSConnecting == 0) - { - ConnecttoKISS(); - } - else - { - // Verify Serial port is still ok - - if (m_serial && KISSConnected) - { - m_serial->clearError(); - m_serial->isDataTerminalReady(); - - if (m_serial->error()) - { - Debugprintf("Serial Port Lost - isOpen %d Error %d", m_serial->isOpen(), m_serial->error()); - closeSerialPort(); - } - } - } -} - - - -void QtTermTCP::KISSdisplayError(QAbstractSocket::SocketError socketError) -{ - switch (socketError) - { - case QAbstractSocket::RemoteHostClosedError: - break; - - case QAbstractSocket::HostNotFoundError: - QMessageBox::information(this, tr("QtTermTCP"), - tr("KISS host was not found. Please check the " - "host name and portsettings->")); - - Status3->setText("KISS Connection Failed"); - - break; - - case QAbstractSocket::ConnectionRefusedError: - - Status3->setText("KISS Connection Refused"); - break; - - default: - - Status3->setText("KISS Connection Failed"); - } - - KISSConnecting = 0; - KISSConnected = 0; -} - - -extern "C" void KISSSendtoServer(myTcpSocket* Socket, char * Data, int Length) -{ - if (m_serial) - { - if (m_serial->isOpen()) - { - m_serial->clearError(); - - int n = m_serial->write(Data, Length); - - n = m_serial->flush(); - - if (m_serial->error()) - { - Debugprintf("Serial Flush Error - Requested = %d Actual %d Error %d", Length, n, m_serial->error()); - closeSerialPort(); - } - } - } - else if (Socket) - Socket->write(Data, Length); -} - - - -void QtTermTCP::KISSreadyRead() -{ - int Read; - unsigned char Buffer[4096]; myTcpSocket* Socket = static_cast(QObject::sender()); - - // read the data from the socket - - Read = Socket->read((char *)Buffer, 4095); - - KISSDataReceived(Socket, Buffer, Read); - -} - -extern "C" void KISS_del_socket(void * socket); -extern "C" void KISS_add_stream(void * Socket); - -void QtTermTCP::onKISSSocketStateChanged(QAbstractSocket::SocketState socketState) -{ - // myTcpSocket* sender = static_cast(QObject::sender()); - - QTcpSocket* sender = static_cast(QObject::sender()); - - if (socketState == QAbstractSocket::UnconnectedState) - { - // Close any connections - - Ui_ListenSession * Sess = NULL; - - Status3->setText("KISS Disconnected"); - actHost[18]->setEnabled(0); - - KISSConnecting = KISSConnected = 0; - - // Free the monitor Window - - if (KISSMonSess) - { - Sess = KISSMonSess; - - if (TermMode == MDI) - Sess->setWindowTitle("Monitor Session Disconnected"); - - else if (TermMode == Tabbed) - tabWidget->setTabText(Sess->Tab, "Monitor"); - - KISSMonSess = nullptr; - } - - KISS_del_socket(sender); - KISSSock = NULL; - } - else if (socketState == QAbstractSocket::ConnectedState) - { - int i; - - KISSConnected = 1; - KISSConnecting = 0; - - Status3->setText("KISS Connected"); - actHost[18]->setEnabled(1); // Enable KISS Connect Line - - KISS_add_stream(sender); - - // Attach a Monitor Window if available - - Ui_ListenSession * Sess = NULL; - Ui_ListenSession * S; - - if (TermMode == MDI) - { - // See if an old session can be reused - - for (int i = 0; i < _sessions.size(); ++i) - { - S = _sessions.at(i); - - // for (Ui_ListenSession * S: _sessions) - // { - if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL) - { - Sess = S; - break; - } - } - - // Create a window if none found, else reuse old - - if (Sess == NULL) - { - Sess = newWindow((QObject *)mythis, Mon, ""); - } - } - else if (TermMode == Tabbed) - { - // Tabbed - look for free session - - for (i = 8; i; i--) - { - S = _sessions.at(i); - - if (S->clientSocket == NULL && S->KISSSession == NULL) - { - Sess = S; - break; - } - } - } - else if (TermMode == Single && (singlemodeFormat & Mon)) - { - S = _sessions.at(0); - - if (S->clientSocket == NULL && S->KISSSession == NULL) - Sess = S; - - } - - if (Sess) - { - KISSMonSess = Sess; // Flag as in use - - if (TermMode == MDI) - Sess->setWindowTitle("KISS Monitor Window"); - else if (TermMode == Tabbed) - tabWidget->setTabText(Sess->Tab, "KISS Mon"); - else if (TermMode == Single) - mythis->setWindowTitle("KISS Monitor Window"); - - // if (TermMode == Single) - // { - // discAction->setEnabled(false); - // YAPPSend->setEnabled(false); - // connectMenu->setEnabled(false); - // } - } - } -} - - -extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat); -extern "C" char * ShortDateTime(); - -extern "C" void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded) -{ - UNUSED(excluded); - UNUSED(snd_ch); - - int Len; - char Msg[1024]; - - if (tx) - sprintf(Msg, "\x1b\x10%s", frame_monitor(frame, code, tx)); - else - sprintf(Msg, "\x1b\x11%s", frame_monitor(frame, code, tx)); - - Len = strlen(Msg); - - if (Msg[Len - 1] != '\r') - { - Msg[Len++] = '\r'; - Msg[Len] = 0; - } - - if (KISSMonSess) - WritetoMonWindow(KISSMonSess, (unsigned char *)Msg, Len); - -} - -extern "C" Ui_ListenSession * ax25IncommingConnect(TAX25Port * AX25Sess) -{ - // Look for/create Terminal Window for connection - - Ui_ListenSession * Sess = NULL; - Ui_ListenSession * S; - char Title[80]; - int i = 0; - - if (TermMode == MDI) - { - // See if an old session can be reused - - for (int i = 0; i < _sessions.size(); ++i) - { - S = _sessions.at(i); - - if ((S->SessionType & Listen) && S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) - { - Sess = S; - break; - } - } - - // Create a window if none found, else reuse old - - if (Sess == NULL) - { - Sess = newWindow((QObject *)mythis, Listen, ""); - } - } - else - { - // Single or Tabbed - look for free session - - - for (i = 0; i < _sessions.size(); ++i) - { - S = _sessions.at(i); - - if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) - { - Sess = S; - break; - } - } - - if (Sess == NULL) - { - // Clear connection - - return NULL; - } - } - - if (Sess) - { - sprintf(Title, "Connected to %s", AX25Sess->corrcall); - - if (TermMode == MDI) - { - Sess->setWindowTitle(Title); - } - else if (TermMode == Tabbed) - { - tabWidget->setTabText(i, AX25Sess->corrcall); - tabWidget->tabBar()->setTabTextColor(i, newTabText); - } - else if (TermMode == Single) - mythis->setWindowTitle(Title); - - AX25Sess->port = 0; - AX25Sess->Sess = Sess; // Crosslink AGW and Term Sessions - AX25Sess->PID = 240;; - - Sess->KISSSession = AX25Sess; - - setMenus(true); - - if (ConnectBeep) - myBeep(); - - // Send CText if defined - - if (listenCText[0]) - SendtoAX25(Sess->KISSSession, (unsigned char *)listenCText, (int)strlen(listenCText)); - } - return Sess; -} - - -extern "C" void AX25_disc(TAX25Port * AX25Sess, Byte mode) -{ - char Msg[128]; - int Len = 0; - Ui_ListenSession * Sess = (Ui_ListenSession *)AX25Sess->Sess; - - if (AX25Sess->status == STAT_TRY_LINK) - { - // Connect failed - - Len = sprintf(Msg, "Connection to %s failed\r", AX25Sess->corrcall); - } - else - { - switch (mode) - { - case MODE_OTHER: - case MODE_OUR: - - Len = sprintf(Msg, "Disconnected from %s\r", AX25Sess->corrcall); - break; - - case MODE_RETRY: - - Len = sprintf(Msg, "Disconnected from %s - Retry count exceeded\r", AX25Sess->corrcall); - break; - - }; - } - - SendtoTerm(Sess, Msg, Len); - ClearSessLabel(Sess); - Sess->KISSSession = NULL; - AX25Sess->Sess = 0; - - setMenus(0); -}; - -int QtTermTCP::openSerialPort() -{ - if (m_serial && m_serial->isOpen()) - { - m_serial->close(); - } - - m_serial = nullptr; - m_serial = new QSerialPort(this); - - m_serial->setPortName(SerialPort); - m_serial->setBaudRate(KISSBAUD); - - if (m_serial->open(QIODevice::ReadWrite)) - { - int i; - connect(m_serial, &QSerialPort::readyRead, this, &QtTermTCP::readSerialData); - // connect(m_serial, &QSerialPort::errorOccurred, this, &QtTermTCP::handleError); - - KISSConnected = 1; - KISSConnecting = 0; - - Status3->setText("KISS Connected"); - actHost[18]->setEnabled(1); // Enable KISS Connect Line - - KISS_add_stream(m_serial); - - // Attach a Monitor Window if available - - Ui_ListenSession * Sess = NULL; - Ui_ListenSession * S; - - if (TermMode == MDI) - { - // See if an old session can be reused - - for (int i = 0; i < _sessions.size(); ++i) - { - S = _sessions.at(i); - - // for (Ui_ListenSession * S: _sessions) - // { - if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL) - { - Sess = S; - break; - } - } - - // Create a window if none found, else reuse old - - if (Sess == NULL) - { - Sess = newWindow((QObject *)mythis, Mon, ""); - } - } - else if (TermMode == Tabbed) - { - // Tabbed - look for free session - - for (i = 8; i; i--) - { - S = _sessions.at(i); - - if (S->clientSocket == NULL && S->KISSSession == NULL) - { - Sess = S; - break; - } - } - } - else if (TermMode == Single && (singlemodeFormat & Mon)) - { - S = _sessions.at(0); - - if (S->clientSocket == NULL && S->KISSSession == NULL) - Sess = S; - - } - - if (Sess) - { - KISSMonSess = Sess; // Flag as in use - - if (TermMode == MDI) - Sess->setWindowTitle("KISS Monitor Window"); - else if (TermMode == Tabbed) - tabWidget->setTabText(Sess->Tab, "KISS Mon"); - else if (TermMode == Single) - mythis->setWindowTitle("KISS Monitor Window"); - - // if (TermMode == Single) - // { - // discAction->setEnabled(false); - // YAPPSend->setEnabled(false); - // connectMenu->setEnabled(false); - // } - } - - - - return 1; - } - else - { - Status3->setText("KISS Open Failed"); - KISSConnected = 0; - KISSConnecting = 0; - return 0; - } -} - - - -void closeSerialPort() -{ - if (m_serial && m_serial->isOpen()) - { - m_serial->close(); - m_serial = nullptr; - } - - m_serial = nullptr; - - KISSConnected = 0; - KISSConnecting = 0; - - Status3->setText("KISS Closed"); - actHost[18]->setEnabled(0); // Enable KISS Connect Line -} - -void QtTermTCP::readSerialData() -{ - int Read; - unsigned char Buffer[8192]; - - // read the data from the socket - - m_serial->clearError(); - - Read = m_serial->read((char *)Buffer, 2047); - - if (m_serial->error()) - { - Debugprintf("Serial Read Error - RC %d Error %d", Read, m_serial->error()); - closeSerialPort(); - return; - } - - - while (Read > 0) - { - KISSDataReceived(m_serial, Buffer, Read); - Read = m_serial->read((char *)Buffer, 2047); - } -} - -void QtTermTCP::handleError(QSerialPort::SerialPortError serialPortError) -{ - Debugprintf("Serial port Error %d", serialPortError); - closeSerialPort(); -} - -extern "C" void CheckUIFrame(unsigned char * path, string * data) -{ - // If we have KISS enabled and dest is UIDEST look for a KISS window in UI Mode - - if (KISSSock == 0) - return; - - char Dest[10]; - char From[10]; - - Dest[ConvFromAX25(path, Dest)] = 0; - From[ConvFromAX25(&path[7], From)] = 0; - - // ok, Find a Kiss Session with this Dest - - Ui_ListenSession * Sess = NULL; - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - if (Sess->KISSMode == 1 && strcmp(Dest, Sess->UIDEST) == 0) - { - char Msg[512]; - int Len; - - data->Data[data->Length] = 0; - - Len = sprintf(Msg, "%s:%s", From, data->Data); - SendtoTerm(Sess, Msg, Len); - return; - } - } - -} - - -QColor QtTermTCP::setColor(QColor Colour) -{ - // const QColorDialog::ColorDialogOptions options = QFlag(colorDialogOptionsWidget->value()); - - - QColor col = Colour; - - QColorDialog dialog; - dialog.setCurrentColor(Colour); - dialog.setOption(QColorDialog::DontUseNativeDialog); - - if (dialog.exec() == QColorDialog::Accepted) - col = QVariant(dialog.currentColor()).toString(); - - - // const QColor color = QColorDialog::getColor(Qt::green, this, "Select Color", 0); - - return col; -} - -// Experimental Viewdata/Teletext/Prestel/CEEFAX Mode - -// Uses ideas and some code from - -/*************************************************************** - * Name: wxTEDMain.cpp - * Purpose: Teletext editor Application Frame - * Author: Peter Kwan (peterk.vt80@gmail.com) - * Created: 2014-10-30 - * Copyright: Peter Kwan - * License: - * - * Copyright (C) 2014-2022, Peter Kwan - * - * Permission to use, copy, modify, and distribute this software - * and its documentation for any purpose and without fee is hereby - * granted, provided that the above copyright notice appear in all - * copies and that both that the copyright notice and this - * permission notice and warranty disclaimer appear in supporting - * documentation, and that the name of the author not be used in - * advertising or publicity pertaining to distribution of the - * software without specific, written prior permission. - * - * The author disclaims all warranties with regard to this - * software, including all implied warranties of merchantability - * and fitness. In no event shall the author be liable for any - * special, indirect or consequential damages or any damages - * whatsoever resulting from loss of use, data or profits, whether - * in an action of contract, negligence or other tortious action, - * arising out of or in connection with the use or performance of - * this software. - *************************************************************************** **/ - - - -int FontWidth = 16; -int FontHeight = 16; - -bool isMosaic(char ch) -{ - ch &= 0x7f; - return (ch >= 0x20 && ch < 0x40) || ch >= 0x60; -} - - -void DecodeTeleText(Ui_ListenSession * Sess, char * page) -{ - - // redraw the whole teletext page - - QColor fg = Qt::white; - QColor bg = Qt::black; - QColor holdColour; - QColor holdfg = fg; // Colour for held graphic - int usehold = 0; - int sep = 0; - - QPainter p(Sess->TTBitmap); - - QSettings settings(GetConfPath(), QSettings::IniFormat); - - //p.setFont(QFont("Courier", 14, QFont::Bold)); - - p.setFont(QFont(settings.value("FontFamily", "Courier New").value(), 14)); - - p.setPen(QPen(fg)); - - bool graphicsMode = false; - bool separated = false; - bool doubleHeight = false; - int skipnextrow = 99; - bool flashing = false; - bool hold = false; - char holdChar = 0; - char holdMode = 0; - Sess->timer.stop(); - - bool concealed = false; - char c; - - fg = Qt::white; - bg = Qt::black; - - char * ptr = page; - - int col = 0; - int line = 0; - - // XXXXXXXXTEEFAX %%# %%a %d %%b C %H:%M.%S - - //p.drawText(0, 19, "P199 HAMFAX"); - - - // interpret data, for now, line by line - - - while ((c = *(ptr++))) - { - char ch = c; - - if (c == 0x11) // Curson On ?? - continue; - - if (c == 0x14) // Curson Off ?? - continue; - - if (c == 9) // Curson On ?? - { - col++; - continue; - } - - if (c == 0x0a) - { - line++; - -// if (doubleHeight) -// line++; - - if (line > 24) - line = 0; - - continue; - } - - if (c == 0x1e) // Cursor Home - { - line = col = 0; - c = 13; // So we reset page flags below - } - - if (c == 12) - { - // Clear the page - - Sess->TTBitmap->fill(Qt::black); - Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); - - line = col = 0; - - c = 13; // So we reset page flags below - } - - if (c == 13) - { - col = 0; - - graphicsMode = false; - separated = false; - doubleHeight = false; - flashing = false; - hold = false; - holdChar = 0; - concealed = false; - - fg = Qt::white; - bg = Qt::black; - - continue; // Next line - } - - if (c == 0x1b) // Esc - { - // I think the control char is displayed as it was before being actioned, sa save current state - - holdfg = holdColour; // Colour if using held - may be changed before displaying - usehold = hold; // May be changed - sep = holdMode; - - char echar = *(ptr++); - - if (echar == 0) - { - // Esc pair spilt - wait for rest - - Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); - return; - } - - switch (echar) - { - case '@': - fg = Qt::black; - concealed = false; // Side effect of colour. It cancels a conceal. - graphicsMode = false; -// hold = false; - - break; - case 'A': - fg = Qt::red; - concealed = false; - graphicsMode = false; - hold = false; - - break; - case 'B': - fg = Qt::green; - concealed = false; - graphicsMode = false; - hold = false; - break; - case 'C': - fg = Qt::yellow; - concealed = false; - graphicsMode = false; - hold = false; - break; - case 'D': - fg = Qt::blue; - concealed = false; - graphicsMode = false; - hold = false; - break; - case 'E': - fg = Qt::magenta; - concealed = false; - graphicsMode = false; - hold = false; - break; - case 'F': - fg = Qt::cyan; - concealed = false; - graphicsMode = false; - hold = false; - break; - case 'G': - fg = Qt::white; - concealed = false; - graphicsMode = false; - hold = false; - break; - case 'H': // Flash - flashing = true; - Sess->timer.start(1000, Sess); - concealed = false; - graphicsMode = false; - hold = false; - - break; - - case 'I': // Steady - flashing = false; - concealed = false; - graphicsMode = false; - hold = false; - - break; - // - case 'J': //ttxCodeEndBox: - case 'K': //ttxCodeStartBox: - - concealed = false; - graphicsMode = false; - hold = false; - - break; - case 'L': // Normal height - doubleHeight = false; - hold = false; - break; - - case 'M': // Double height - doubleHeight = true; - skipnextrow = line + 1; // ETSI: row to ignore - hold = false; - holdChar = 0; - break; - case 'P': // Graphics black -// concealed = false; - graphicsMode = true; - holdColour = fg = Qt::black; - - break; - case 'Q': // Graphics red -// concealed = false; - graphicsMode = true; - holdColour = fg = Qt::red; - - break; - case 'R': // Graphics green -// concealed = false; - graphicsMode = true; - holdColour = fg = Qt::green; - - break; - case 'S': // Graphics yellow -// concealed = false; - graphicsMode = true; - holdColour = fg = Qt::yellow; - - break; - case 'T': // Graphics blue -// concealed = false; - graphicsMode = true; - holdColour = fg = Qt::blue; - - break; - case 'U': // Graphics magenta -// concealed = false; - graphicsMode = true; - holdColour = fg = Qt::magenta; - - break; - case 'V': // Graphics cyan -// concealed = false; - graphicsMode = true; - holdColour = fg = Qt::cyan; - - break; - case 'W': // Graphics white -// concealed = false; - graphicsMode = true; - holdColour = fg = Qt::white; - - break; - - case 'X': // Conceal display - - concealed = 1; - break; - - case 'Y': // Contiguous graphics - - separated = false; - break; - - case 'Z': // Separated gfx - - separated = true; - break; - - case 0x5c: // Background black - bg = Qt::black; - break; - - case 0x5d: // New background - - bg = fg; - break; - - case 0x5e: // Hold gfx - - if (hold == 0) - { - hold = true; - holdColour = fg; - holdMode = separated; - } - break; - - case 0x5f: // Non-hold gfx - hold = false; - break; - - default: - echar++; // For testign - break; - - } //end of esc case processing - - if (usehold) - { - // We set sep and color for held char earlier - - ch = holdChar; // Repeat held char - } - else - ch = 0x0; // Default is space - - - if (line > skipnextrow) - skipnextrow = 99; - - if (line == skipnextrow) - { - line = line; - } - else - { - if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) - { - p.fillRect(col * 15, line * 19, 15, 19, bg); - - // if double height also draw background for next row - - if (doubleHeight) - p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); - - - if (sep) - { - if (ch & 1) - p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, holdfg); - if (ch & 2) - p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, holdfg); - if (ch & 4) - p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, holdfg); - if (ch & 8) - p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, holdfg); - if (ch & 16) - p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, holdfg); - if (ch & 32) - p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, holdfg); - - } - else - { - if (ch & 1) - p.fillRect(col * 15, line * 19, 7, 6, holdfg); - if (ch & 2) - p.fillRect(col * 15 + 7, line * 19, 8, 6, holdfg); - if (ch & 4) - p.fillRect(col * 15, line * 19 + 6, 7, 6, holdfg); - if (ch & 8) - p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, holdfg); - if (ch & 16) - p.fillRect(col * 15, line * 19 + 12, 7, 7, holdfg); - if (ch & 32) - p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, holdfg); - } - } - } - col++; - } - else - { - // Not esc - so normal or graphics - - if (ch < 0x20) - continue; - - if (line > skipnextrow) - skipnextrow = 99; - - if (line == skipnextrow) - { - line = line; - } - else - { - if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) - { - p.fillRect(col * 15, line * 19, 15, 19, bg); - - if (doubleHeight) - p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); - - p.setPen(QPen(fg));; - - if (graphicsMode) - { - if (ch < 0x40) - ch -= 0x20; - else - if (ch >= 0x60) - ch -= 0x40; - else - goto isText; - - holdChar = ch; - - // Now have 00 - 3f - - - // C is bit mask bit posns are - // 01 - // 23 - // 45 - // Char cell is 15 * 19 which is a bit asymetrical - - // Chars are 20 - 3f and 60 to 7f but I cant see a logic to the mapping - - - if (separated) - { - if (ch & 1) - p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, fg); - if (ch & 2) - p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, fg); - if (ch & 4) - p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, fg); - if (ch & 8) - p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, fg); - if (ch & 16) - p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, fg); - if (ch & 32) - p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, fg); - - } - else - { - if (ch & 1) - p.fillRect(col * 15, line * 19, 7, 6, fg); - if (ch & 2) - p.fillRect(col * 15 + 7, line * 19, 8, 6, fg); - if (ch & 4) - p.fillRect(col * 15, line * 19 + 6, 7, 6, fg); - if (ch & 8) - p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, fg); - if (ch & 16) - p.fillRect(col * 15, line * 19 + 12, 7, 7, fg); - if (ch & 32) - p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, fg); - } - } - else - { - // Just write char at current col and line - - isText: - char s[5] = " "; - - // Some chars are in wrong char set - - s[0] = ch; - - if (ch == '_') - s[0] = '#'; - - else if (ch == 0x7e) // division - { - s[0] = 0xC3; - s[1] = 0xB7; - } - else if (ch == 0x5e) // up arrow - { - s[0] = 0xF0; - s[1] = 0x9F; - s[2] = 0xA0; - s[3] = 0x95; - } - else if (ch == 0x7f) // up arrow - { - s[0] = 0xE2; - s[1] = 0x96; - s[2] = 0x88; - } - -// if (doubleHeight) - // p.drawText(col * 15, line * 19 + 25, s); - // else - // p.drawText(col * 15, line * 19 + 15, s); - - // if double height draw normally then copy pixels each row of pixels to two scanlines (starting at the bottom) - - if (doubleHeight) - { - int inscanline = line * 19 + 18; - int outscanline = line * 19 + 35; - unsigned char * inptr = Sess->TTBitmap->scanLine(inscanline); - unsigned char * outptr = Sess->TTBitmap->scanLine(outscanline); - int linelen = Sess->TTBitmap->bytesPerLine(); - int charlen = linelen / 40; // bytes per char position - - p.drawText(col * 15, line * 19 + 16, s); - - inptr += col * charlen; - outptr += col * charlen; - - for (int i = 0; i < 18; i++) - { - memcpy(outptr, inptr, charlen); - outptr -= linelen; - memcpy(outptr, inptr, charlen); - - inptr -= linelen; - outptr -= linelen; - - } - } - else - p.drawText(col * 15, line * 19 + 15, s); - - } - } - } - col++; - } - - if (col > 39) - { - col = 0; - line++; - if (line > 24) - line = 0; - - graphicsMode = false; - separated = false; - doubleHeight = false; - flashing = false; - hold = false; - holdChar = 0; - concealed = false; - - fg = Qt::white; - bg = Qt::black; - } - } - Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); - return; - - QFile file("D:/savepage.txt"); - file.open(QIODevice::WriteOnly); - file.write(Sess->pageBuffer); - file.close(); -} - - -void Ui_ListenSession::timerEvent(QTimerEvent *event) -{ - Ui_ListenSession * Sess = NULL; - - // Used for flashing - resfresh window - - for (int i = 0; i < _sessions.size(); ++i) - { - Sess = _sessions.at(i); - - if (Sess->timer.timerId() == event->timerId()) - { - if (Sess->TTActive) - { - Sess->TTFlashToggle ^= 1; - - // if in Tabbed mode only refresh active tab - - if (TermMode == Tabbed && Sess != ActiveSession) - return; - - DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end - } - else - Sess->timer.stop(); - - return; - } - } - QWidget::timerEvent(event); -} - +// Qt Version of BPQTermTCP + +#define VersionString "0.0.0.73" + + +// .12 Save font weight +// .13 Display incomplete lines (ie without CR) +// .14 Add YAPP and Listen Mode +// .15 Reuse windows in Listen Mode +// .17 MDI Version 7/1/20 +// .18 Fix input window losing focus when data arrives on other window +// .19 Fix Scrollback +// .20 WinXP compatibility changes +// .21 Save Window Positions +// .22 Open a window on first start +// .23 Add Tabbed display option +// .24 Fix crash when setting Monitor flags in Tabbed mode +// .25 Add AGW mode +// .26 Add sending CTRL/C CTRL/D and CTRL/Z) +// .27 Limit size of windows to 10000 lines +// Fix YAPP in Tabbed Mode +// .28 Add AGW Beacon +// .29 Fix allocating Listem sessions to tabs connected using AGW +// .30 Fix allocationd AGW Monitor Sessions +// .31 Fix output being written to the wrong place when window is scrolled back +// .32 Fix connect with digis +// .33 Add StripLF option +// .34 Improvements for Andriod +// Option to change Menu Fonts +// Fix receiving part lines when scrolled back +// .35 Fix PE if not in Tabbed Mode +// .36 Improved dialogs mainly for Android +// Try to make sure sessions are closed before exiting +// .37 Replace VT with LF (for pasting from BPQ32 Terminal Window) +// Dont show AGW status line if AGW interface is disabled +// Don't show Window Menu in Single Mode +// .38 Protect against connect to normal Telnet Port. +// Send CTEXT and Beep for inward AGW Connects +// Make sending Idle and Connect beeps configurable +// Change displayed Monitor flags when active window changed. +// Fix duplicate text on long lines +// .39 Add option to Convert non-utf8 charaters +// .40 Prevent crash if AGW monitor Window closed +// .41 Allow AGW Config and Connect dialogs to be resized with scrollbars +// Fix disabling connect flag on current session when AGW connects +// .42 Fix some bugs in AGW session handling +// .43 Include Ross KD5LPB's fixes for MAC +// .44 Ctrl/[ sends ESC (0x1b) +// .45 Add VARA support Nov 2021 +// .46 Fix dialog size on VARA setup +// .47 Move VARA Status indicator. +// Add FLRIG PTT for VARA +// .48 Check that YAPP Receive Directory has been set +// Save separate configs for VARA, VARAFM and VARASAT +// .49 Add BBS Monitor Dec 2021 +// .50 Make Serial port support optional for Android Version +// .51 Add KISS TNC Support May 2022 +// .52 Save partially typed lines on cursor up May 2022 +// .53 Add UI Mode for KISS Sessions May 2022 +// Fix saving KISS Paclen (b) +// Fix Keepalive (c) +// .54 Add option to change screen colours June 2022 +// .55 Build without optimisation +// .56 Add Teletext mode Nov 2022 +// .57 Fix KISS mode incoming call handling +// .58 Add method to toggle Normal/Teletext Mode +// Fix KISS multiple session protection +// .59 Add Teletext double height mode +// .60 Add option to name sessions Jan 2023 +// .61 Add VARA Init Script Feb 2023 +// .62 Fix running AGW in single session mode Feb 2023 +// .63 Fix handling split monitor frame (no fe in buffer) Apr 2023 +// .64 Add Clear Screen command to context menu Apr 2023 +// .65 Fixes for 63 port version of BPQ May 2023 +// .66 Colour Tab of incoming calls June 2023 +// .67 Add config Yapp RX Size dialog July 2023 +// Fix 63 port montoring + +// .68 Sept 2023 + +// Remember last used host on restart +// Add AutoConnect in Tabbed Mode +// Fix auto copy when QtTerm not active window + +// .69 October 2023 + +// Options related to sound alerts moved to a separte menu in Setup +// Allow use of WAV files instead of Beep sound for sound alerts +// Enable an alarm to be sounded when one of a list of words or phrases is received. + +// .70 October 2023 + +// Include some .wav files in resources +// Add Test button to Alert setup dialog + +// .71 October 2023 + +// Add option to use local time +// Fixes for Mac OS + +// .72 November 2023 +// Don't display "Enable Monitor" on startup + +// .73 November 2023 +// Raise RTS on KISS serial port + + + + +#define _CRT_SECURE_NO_WARNINGS + +#define UNUSED(x) (void)(x) + +#define USESERIAL + +#include "QtTermTCP.h" +#include "TabDialog.h" +#include +#include +#include +#include +#include +#include "QTreeWidget" +#include +#include +#include +#include +#include +#ifdef USESERIAL +#include +#include +#endif +#ifndef WIN32 +#define strtok_s strtok_r +#endif +#include +#include +#ifndef WIN32 +#include +#endif + +#include "ax25.h" + +#define UNREFERENCED_PARAMETER(P) (P) + +void DecodeTeleText(Ui_ListenSession * Sess, char * text); + +char Host[MAXHOSTS + 1][100] = { "" }; +int Port[MAXHOSTS + 1] = { 0 }; +char UserName[MAXHOSTS + 1][80] = { "" }; +char Password[MAXHOSTS + 1][80] = { "" }; +char MonParams[MAXHOSTS + 1][80] = { "" }; +char SessName[MAXHOSTS + 1][80] = { "" }; +int ListenPort = 8015; + +// Session Type Equates + +#define Term 1 +#define Mon 2 +#define Listen 4 + +// Presentation - Single Window, MDI or Tabbed + +int TermMode = 0; + +#define Single 0 +#define MDI 1 +#define Tabbed 2 + +int singlemodeFormat = Mon + Term; + +char monStyleSheet[128] = "background-color: rgb(0,255,255)"; +char termStyleSheet[128] = "background-color: rgb(255,0,255);"; +char inputStyleSheet[128] = "color: rgb(255, 0, 0); background-color: rgb(255,255,0);"; + +QColor monBackground = qRgb(0, 255, 255); +QColor monRxText = qRgb(0, 0, 255); +QColor monTxText = qRgb(255, 0, 0); +QColor monOtherText = qRgb(0, 0, 0); + +QColor termBackground = qRgb(255, 0, 255); +QColor outputText = qRgb(0, 0, 0); +QColor EchoText = qRgb(0, 0, 255); +QColor WarningText = qRgb(255, 0, 0); +QColor inputBackground = qRgb(255, 255, 0); +QColor inputText = qRgb(0, 0, 255); + +QColor newTabText = qRgb(255, 0, 0); // Red +QColor oldTabText = qRgb(0, 0, 0); // Black + + +// There is something odd about this. It doesn't match BPQTERMTCP though it looks the same + +// Chat uses these (+ 10) +//{ 0, 4, 9, 11, 13, 16, 17, 42, 45, 50, 61, 64, 66, 72, 81, 84, 85, 86, 87, 89 }; + +// As we have a white background we need dark colours + +// 0 is black. 23 is normal output (blue) 81 is red (used by AGW Mon) +// for monitor in colour, host sends 17 for RX Text, 81 for TX Text but code converts to monRx/TxText qrgb values + +QRgb Colours[256] = { 0, + qRgb(0,0,0), qRgb(0,0,128), qRgb(0,0,192), qRgb(0,0,255), // 1 - 4 + qRgb(0,64,0), qRgb(0,64,128), qRgb(0,64,192), qRgb(0,64,255), // 5 - 8 + qRgb(0,128,0), qRgb(0,128,128), qRgb(0,128,192), qRgb(0,128,255), // 9 - 12 + qRgb(0,192,0), qRgb(0,192,128), qRgb(0,192,192), qRgb(0,192,255), // 13 - 16 + qRgb(0,255,0), qRgb(0,255,128), qRgb(0,255,192), qRgb(0,255,255), // 17 - 20 + + qRgb(64,0,0), qRgb(64,0,128), qRgb(64,0,192), qRgb(0,0,255), // 21 + qRgb(64,64,0), qRgb(64,64,128), qRgb(64,64,192), qRgb(64,64,255), + qRgb(64,128,0), qRgb(64,128,128), qRgb(64,128,192), qRgb(64,128,255), + qRgb(64,192,0), qRgb(64,192,128), qRgb(64,192,192), qRgb(64,192,255), + qRgb(64,255,0), qRgb(64,255,128), qRgb(64,255,192), qRgb(64,255,255), + + qRgb(128,0,0), qRgb(128,0,128), qRgb(128,0,192), qRgb(128,0,255), // 41 + qRgb(128,64,0), qRgb(128,64,128), qRgb(128,64,192), qRgb(128,64,255), + qRgb(128,128,0), qRgb(128,128,128), qRgb(128,128,192), qRgb(128,128,255), + qRgb(128,192,0), qRgb(128,192,128), qRgb(128,192,192), qRgb(128,192,255), + qRgb(128,255,0), qRgb(128,255,128), qRgb(128,255,192), qRgb(128,255,255), + + qRgb(192,0,0), qRgb(192,0,128), qRgb(192,0,192), qRgb(192,0,255), // 61 - 80 + qRgb(192,64,0), qRgb(192,64,128), qRgb(192,64,192), qRgb(192,64,255), + qRgb(192,128,0), qRgb(192,128,128), qRgb(192,128,192), qRgb(192,128,255), + qRgb(192,192,0), qRgb(192,192,128), qRgb(192,192,192), qRgb(192,192,255), + qRgb(192,255,0), qRgb(192,255,128), qRgb(192,255,192), qRgb(192,255,255), + + qRgb(255,0,0), qRgb(255,0,128), qRgb(255,0,192), qRgb(255,0,255), // 81 - 100 + qRgb(255,64,0), qRgb(255,64,128), qRgb(255,64,192), qRgb(255,64,255), + qRgb(255,128,0), qRgb(255,128,128), qRgb(255,128,192), qRgb(255,128,255), + qRgb(255,192,0), qRgb(255,192,128), qRgb(255,192,192), qRgb(255,192,255), + qRgb(255,255,0), qRgb(255,255,128), qRgb(255,255,192), qRgb(255,255,255) +}; + + + +int SavedHost = 0; // from config + +char * sessionList = NULL; // Saved sessions + +extern int ChatMode; +extern int Bells; +extern int StripLF; +extern int convUTF8; + +extern time_t LastWrite; +extern int AlertInterval; +extern int AlertBeep; +extern int AlertFreq; +extern int AlertDuration; +extern int ConnectBeep; + +bool useBeep; // use wav files if not set + +extern int UseKeywords; +extern QString KeyWordsFile; + +QString ConnectWAV(""); +QString AlertWAV(""); +QString BellWAV(""); +QString IntervalWAV(""); + +extern int MaxRXSize; + +extern int AutoTeletext; + +// AGW Host Interface stuff + +int AGWEnable = 0; +int AGWMonEnable = 0; +int AGWLocalTime = 0; +int AGWMonNodes = 0; +char AGWTermCall[12] = ""; +char AGWBeaconDest[12] = ""; +char AGWBeaconPath[80] = ""; +int AGWBeaconInterval = 0; +char AGWBeaconPorts[80]; +char AGWBeaconMsg[260] = ""; + + +char AGWHost[128] = "127.0.0.1"; +int AGWPortNum = 8000; +int AGWPaclen = 80; +extern char * AGWPortList; +extern myTcpSocket * AGWSock; + +typedef struct AGWUser_t +{ + QTcpSocket *socket; + unsigned char data_in[8192]; + int data_in_len; + unsigned char AGW_frame_buf[512]; + int Monitor; + int Monitor_raw; + Ui_ListenSession * MonSess; // Window for Monitor info + +} AGWUser; + +extern AGWUser *AGWUsers; // List of currently connected clients +void Send_AGW_m_Frame(QTcpSocket* socket); + + +QStringList AGWToCalls; + +// KISS Interface + +int KISSEnable = 0; +extern "C" int KISSMonEnable; +extern "C" int KISSLocalTime; +extern "C" int KISSMonNodes; +extern "C" int KISSListen; + +char SerialPort[80] = ""; +char KISSHost[128] = "127.0.0.1"; +int KISSPortNum = 1000; +int KISSBAUD = 19200; +char MYCALL[32]; +extern "C" UCHAR axMYCALL[7]; // Mycall in ax.25 + +int KISSMode = 0; // Connected (0) or UI (1) + +myTcpSocket * KISSSock; + +extern "C" void * KISSSockCopy[4]; + +int KISSConnected = 0; +int KISSConnecting = 0; + +Ui_ListenSession * KISSMonSess = nullptr; + +QSerialPort * m_serial = nullptr; + +// VARA Interface + +int VARAEnable = 0; +char VARAHost[128] = "127.0.0.1"; +char VARAHostHF[128] = "127.0.0.1"; +char VARAHostFM[128] = "127.0.0.1"; +char VARAHostSAT[128] = "127.0.0.1"; +int VARAPortNum = 8000; +int VARAPortHF = 8000; +int VARAPortFM = 8000; +int VARAPortSAT = 8000; +char VARATermCall[12] = ""; +char VARAPath[256] = ""; +char VARAInit[256] = ""; +char VARAPathHF[256] = ""; +char VARAPathFM[256] = ""; +char VARAPathSAT[256] = ""; + +int VARA500 = 0; +int VARA2300 = 1; +int VARA2750 = 0; + +int VARAHF = 1; +int VARAFM = 0; +int VARASAT = 0; + +myTcpSocket * VARASock; +myTcpSocket * VARADataSock; + +int VARAConnected = 0; +int VARAConnecting = 0; + + +extern char YAPPPath[256]; + +void menuChecked(QAction * Act); + +// PTT Stuff + +#define PTTRTS 1 +#define PTTDTR 2 +#define PTTCAT 4 +#define PTTCM108 8 +#define PTTHAMLIB 16 +#define PTTFLRIG 32 + +#ifdef USESERIAL + +QSerialPort * hPTTDevice = 0; +#else + + +#endif +char PTTPort[80] = ""; // Port for Hardware PTT - may be same as control port. +int PTTBAUD = 19200; +int PTTMode = PTTRTS; // PTT Control Flags. + +char PTTOnString[128] = ""; +char PTTOffString[128] = ""; + +int CATHex = 1; + +unsigned char PTTOnCmd[64]; +int PTTOnCmdLen = 0; + +unsigned char PTTOffCmd[64]; +int PTTOffCmdLen = 0; + +int pttGPIOPin = 17; // Default +int pttGPIOPinR = 17; +bool pttGPIOInvert = false; +bool useGPIO = false; +bool gotGPIO = false; + +int HamLibPort = 4532; +char HamLibHost[32] = "192.168.1.14"; + +int FLRigPort = 12345; +char FLRigHost[32] = "127.0.0.1"; + + +char CM108Addr[80] = ""; + +int VID = 0; +int PID = 0; + +// CM108 Code + +char * CM108Device = NULL; + +QProcess *process = NULL; + +void GetSettings(); + +// These widgets defined here as they are accessed from outside the framework + +QLabel * Status1; +QLabel * Status2; +QLabel * Status3; +QLabel * Status4; + +QAction *actHost[19]; +QAction *actSetup[16]; + +QAction * TabSingle = NULL; +QAction * TabBoth = NULL; +QAction * TabMon = NULL; + +QMenu *monitorMenu; +QMenu * YAPPMenu; +QMenu *connectMenu; +QMenu *disconnectMenu; + +QAction *EnableMonitor; +QAction *EnableMonLog; +QAction *MonLocalTime; +QAction *MonTX; +QAction *MonSup; +QAction *MonNodes; +QAction *MonUI; +QAction *MonColour; +QAction *MonPort[65]; +QAction *actChatMode; +QAction *actAutoTeletext; +QAction *actBells; +QAction *actStripLF; +QAction *actIntervalBeep; +QAction *actConnectBeep; +QAction *actAuto; +QAction *actnoConv; +QAction *actCP1251; +QAction *actCP1252; +QAction *actCP437; + +QAction *actFonts; +QAction *actmenuFont; +QAction *actColours; +QAction *actmyFonts; +QAction *YAPPSend; +QAction *YAPPSetRX; +QAction *YAPPSetSize; +QAction *singleAct; +QAction *singleAct2; +QAction *MDIAct; +QAction *tabbedAct; +QAction *discAction; +QFont * menufont; +QMenu *windowMenu; +QMenu *setupMenu; +QAction *ListenAction; + +QTabWidget *tabWidget; +QMdiArea *mdiArea; +QWidget * mythis; +QStatusBar * myStatusBar; + +QTcpServer * _server; + +QMenuBar *mymenuBar; +QToolBar *toolBar; +QToolButton * but1; +QToolButton * but2; +QToolButton * but3; +QToolButton * but4; +QToolButton * but5; + +QList _sessions; + +// Session Type Equates + +#define Term 1 +#define Mon 2 +#define Listen 4 + +int TabType[10] = { Term, Term + Mon, Term, Term, Term, Term, Mon, Mon, Mon }; + +int AutoConnect[10] = {0, 0 ,0, 0, 0, 0, 0, 0, 0, 0}; + +int currentHost[10] = {0, 0 ,0, 0, 0, 0, 0, 0, 0, 0}; + +int listenPort = 8015; +extern "C" int listenEnable; +char listenCText[4096] = ""; + +int ConfigHost = 0; + +int Split = 50; // Mon/Term size split + +int termX; + +bool Cascading = false; // Set to stop size being saved when cascading + +QMdiSubWindow * ActiveSubWindow = NULL; +Ui_ListenSession * ActiveSession = NULL; + +Ui_ListenSession * newWindow(QObject * parent, int Type, const char * Label = nullptr); +void Send_AGW_C_Frame(Ui_ListenSession * Sess, int Port, char * CallFrom, char * CallTo, char * Data, int DataLen); +void AGW_AX25_data_in(void * AX25Sess, unsigned char * data, int Len); +void AGWMonWindowClosing(Ui_ListenSession *Sess); +void AGWWindowClosing(Ui_ListenSession *Sess); +extern "C" void KISSDataReceived(void * socket, unsigned char * data, int length); +void closeSerialPort(); + +extern void initUTF8(); +int checkUTF8(unsigned char * Msg, int Len, unsigned char * out); + +QDialog * deviceUI; + +#include +#include +#include + + + + +void EncodeSettingsLine(int n, char * String) +{ + sprintf(String, "%s|%d|%s|%s|%s|%s", Host[n], Port[n], UserName[n], Password[n], MonParams[n], SessName[n]); + return; +} + +// This is used for placing discAction in the preference menu +#ifdef __APPLE__ +bool is_mac = true; +#else +bool is_mac = false; +#endif + +QString GetConfPath() +{ + std::string conf_path = "QtTermTCP.ini"; // Default conf file stored alongside application. + +#ifdef __APPLE__ + + // Get configuration path for MacOS. + + // This will usually be placed in /Users/USER/Library/Application Support/QtTermTCP + + std::string directory = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).at(0).toStdString(); + + conf_path = directory + "/QtTermTCP.ini"; + + mkdir(directory.c_str(), 0775); + +#endif + + return QString::fromUtf8(conf_path.c_str()); + +} + + + +void DecodeSettingsLine(int n, char * String) +{ + char * Param = strdup(String); + char * Rest; + char * Save = Param; // for Free + + Rest = strlop(Param, '|'); + + if (Rest == NULL) + return; + + strcpy(Host[n], Param); + Param = Rest; + + Rest = strlop(Param, '|'); + Port[n] = atoi(Param); + Param = Rest; + + Rest = strlop(Param, '|'); + strcpy(UserName[n], Param); + Param = Rest; + + Rest = strlop(Param, '|'); + strcpy(Password[n], Param); + Param = Rest; + + Rest = strlop(Param, '|'); + strcpy(MonParams[n], Param); + + if (Rest) + strcpy(SessName[n], Rest); + + free(Save); + return; +} + +//#ifdef ANDROID +//#define inputheight 60 +//#else +#define inputheight 25 +//#endif + +extern "C" void SendtoAX25(void * conn, unsigned char * Msg, int Len); + +void DoTermResize(Ui_ListenSession * Sess) +{ + + QRect r = Sess->rect(); + + int H, Mid, monHeight, termHeight, Width, Border = 3; + + Width = r.width(); + H = r.height(); + + if (TermMode == Tabbed) + { + // H -= 20; + Width -= 7; + } + else if (TermMode == Single) + { + Width -= 7; + // H += 20; + } + + if (Sess->SessionType == Listen || Sess->SessionType == Term) + { + // Term and Input + + // Calc Positions of window + + termHeight = H - (inputheight + 3 * Border); + + Sess->termWindow->setGeometry(QRect(Border, Border, Width, termHeight)); + + if (Sess->TTActive) + { + Sess->TTLabel->setGeometry(QRect(Border, Border, 600, 475)); +// Sess->termWindow->setVisible(false); + Sess->TTLabel->setVisible(true); + } + else + { +// Sess->termWindow->setVisible(true); + Sess->TTLabel->setVisible(false); + } + + Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); + } + else if (Sess->SessionType == (Term | Mon)) + { + // All 3 + + // Calc Positions of window + + Mid = (H * Split) / 100; + + monHeight = Mid - Border; + termX = Mid; + termHeight = H - Mid - (inputheight + 3 * Border); + + Sess->monWindow->setGeometry(QRect(Border, Border, Width, monHeight)); + Sess->termWindow->setGeometry(QRect(Border, Mid + Border, Width, termHeight)); + + if (Sess->TTActive) + { + Sess->TTLabel->setGeometry(QRect(3, Mid + Border, 600, 475)); +// Sess->termWindow->setVisible(false); + Sess->TTLabel->setVisible(true); + } + else + { +// Sess->termWindow->setVisible(true); + Sess->TTLabel->setVisible(false); + } + + Sess->inputWindow->setGeometry(QRect(Border, H - (inputheight + Border), Width, inputheight)); + + } + else + { + // Should just be Mon only + + Sess->monWindow->setGeometry(QRect(Border, Border, Width, H - 2 * Border)); + } +} + +bool QtTermTCP::eventFilter(QObject* obj, QEvent *event) +{ + // See if from a Listening Session + + Ui_ListenSession * Sess; + + for (int i = 0; i < _sessions.size(); ++i) + { + Sess = _sessions.at(i); + + // Sess = _sessions.at(i); for (Ui_ListenSession * Sess : _sessions) + // { + if (Sess == NULL) + continue; + + if (Sess == obj) + { + if (event->type() == QEvent::Close) + { + // Window closing + + // This only closed mon sessinos + + if (Sess->AGWMonSession) + // AGWMonWindowClosing(Sess); + AGWWindowClosing(Sess); + + if (Sess->AGWSession) + AGWWindowClosing(Sess); + + if (Sess->clientSocket) + { + int loops = 100; + Sess->clientSocket->disconnectFromHost(); + while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState) + QThread::msleep(10); + } + _sessions.removeOne(Sess); + return QMainWindow::eventFilter(obj, event); + } + + if (event->type() == QEvent::Resize) + { + DoTermResize(Sess); + } + } + + if (Sess->inputWindow == obj) + { + if (event->type() == QEvent::KeyPress) + { + QKeyEvent* keyEvent = static_cast(event); + + int key = keyEvent->key(); + Qt::KeyboardModifiers modifier = keyEvent->modifiers(); + + if (modifier == Qt::ControlModifier) + { + char Msg[] = "\0\r"; + + if (key == Qt::Key_BracketLeft) + Msg[0] = 0x1b; + if (key == Qt::Key_Z) + Msg[0] = 0x1a; + else if (key == Qt::Key_C) + Msg[0] = 3; + else if (key == Qt::Key_D) + Msg[0] = 4; + + if (Msg[0]) + { + if (Sess->KISSSession) + { + // Send to ax.25 code + + SendtoAX25(Sess->KISSSession, (unsigned char *)Msg, (int)strlen(Msg)); + } + else if (Sess->AGWSession) + { + // Terminal is in AGWPE mode - send as AGW frame + + AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Msg, (int)strlen(Msg)); + + } + else if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) + { + Sess->clientSocket->write(Msg); + } + + return true; + } + } + + if (key == Qt::Key_Up) + { + // Scroll up + + if (Sess->KbdStack[Sess->StackIndex] == NULL) + return true; + + // If anything typed, stack part command + + QByteArray stringData = Sess->inputWindow->text().toUtf8(); + + if (stringData.length() && Sess->StackIndex == 0) + { + if (Sess->KbdStack[49]) + free(Sess->KbdStack[49]); + + for (int i = 48; i >= 0; i--) + { + Sess->KbdStack[i + 1] = Sess->KbdStack[i]; + } + + Sess->KbdStack[0] = qstrdup(stringData.data()); + Sess->StackIndex++; + } + + Sess->inputWindow->setText(Sess->KbdStack[Sess->StackIndex]); + Sess->inputWindow->cursorForward(strlen(Sess->KbdStack[Sess->StackIndex])); + + Sess->StackIndex++; + if (Sess->StackIndex == 50) + Sess->StackIndex = 49; + + return true; + } + else if (key == Qt::Key_Down) + { + // Scroll down + + if (Sess->StackIndex == 0) + { + Sess->inputWindow->setText(""); + return true; + } + + Sess->StackIndex--; + + if (Sess->StackIndex && Sess->KbdStack[Sess->StackIndex - 1]) + { + Sess->inputWindow->setText(Sess->KbdStack[Sess->StackIndex - 1]); + Sess->inputWindow->cursorForward(strlen(Sess->KbdStack[Sess->StackIndex - 1])); + } + else + Sess->inputWindow->setText(""); + + return true; + } + else if (key == Qt::Key_Return || key == Qt::Key_Enter) + { + LreturnPressed(Sess); + return true; + } + + return false; + } + + if (event->type() == QEvent::MouseButtonPress) + { + QMouseEvent *k = static_cast (event); + + // Paste on Right Click + + if (k->button() == Qt::RightButton) + { + Sess->inputWindow->paste(); + return true; + } + return QMainWindow::eventFilter(obj, event); + } + } + } + return QMainWindow::eventFilter(obj, event); +} + +QAction * setupMenuLine(QMenu * Menu, char * Label, QObject * parent, int State) +{ + QAction * Act = new QAction(Label, parent); + if (Menu) + Menu->addAction(Act); + + Act->setCheckable(true); + if (State) + Act->setChecked(true); + + parent->connect(Act, SIGNAL(triggered()), parent, SLOT(menuChecked())); + + Act->setFont(*menufont); + + return Act; +} + +// This now creates all window types - Term, Mon, Combined, Listen + +int xCount = 0; +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(); + + connectMenu = mymenuBar->addMenu(tr("&Connect")); + + actHost[16] = new QAction("AGW Connect", this); + actHost[16]->setFont(*menufont); + actHost[16]->setVisible(0); + connectMenu->addAction(actHost[16]); + + connect(actHost[16], SIGNAL(triggered()), this, SLOT(Connect())); + + actHost[17] = new QAction("VARA Connect", this); + actHost[17]->setFont(*menufont); + actHost[17]->setVisible(0); + connectMenu->addAction(actHost[17]); + + connect(actHost[17], SIGNAL(triggered()), this, SLOT(Connect())); + + actHost[18] = new QAction("KISS Connect", this); + actHost[18]->setFont(*menufont); + actHost[18]->setVisible(KISSEnable); + actHost[18]->setEnabled(0); + connectMenu->addAction(actHost[18]); + + connect(actHost[18], SIGNAL(triggered()), this, SLOT(Connect())); + + for (i = 0; i < MAXHOSTS; i++) + { + if (SessName[i][0]) + { + char Lable[256]; + sprintf(Lable, "%s(%s)", Host[i], SessName[i]); + actHost[i] = new QAction(Lable, this); + } + else + actHost[i] = new QAction(Host[i], this); + + actHost[i]->setFont(*menufont); + connectMenu->addAction(actHost[i]); + connect(actHost[i], SIGNAL(triggered()), this, SLOT(Connect())); + } + + discAction = mymenuBar->addAction("&Disconnect"); + + // Place discAction in mac app menu, otherwise it doesn't appear + if (is_mac == true) { + QMenu * app_menu = mymenuBar->addMenu("App Menu"); + discAction->setMenuRole(QAction::ApplicationSpecificRole); + app_menu->addAction(discAction); + + } + + connect(discAction, SIGNAL(triggered()), this, SLOT(Disconnect())); + discAction->setEnabled(false); + + toolBar->setFont(*menufont); + +#ifndef ANDROID + toolBar->setVisible(false); +#endif + but4 = new QToolButton(); + but4->setPopupMode(QToolButton::InstantPopup); + but4->setText("Window"); + but4->addAction(windowMenu->menuAction()); + but4->setFont(*menufont); + toolBar->addWidget(but4); + + but5 = new QToolButton(); + but5->setPopupMode(QToolButton::InstantPopup); + but5->setText("Connect"); + but5->addAction(connectMenu->menuAction()); + but5->setFont(*menufont); + + toolBar->addWidget(but5); + + toolBar->addAction(discAction); + + setupMenu = mymenuBar->addMenu(tr("&Setup")); + hostsubMenu = setupMenu->addMenu("Hosts"); + hostsubMenu->setFont(*menufont); + + for (i = 0; i < MAXHOSTS; i++) + { + if (Host[i][0]) + { + char Label[256]; + + if (SessName[i][0]) + sprintf(Label, "%s(%s)", Host[i], SessName[i]); + else + strcpy(Label, Host[i]); + + actSetup[i] = new QAction(Label, this); + } + else + actSetup[i] = new QAction("New Host", this); + + hostsubMenu->addAction(actSetup[i]); + connect(actSetup[i], SIGNAL(triggered()), this, SLOT(SetupHosts())); + + actSetup[i]->setFont(*menufont); + } + + + // Setup Presentation Options + + setupMenu->addSeparator()->setText(tr("Presentation")); + + QActionGroup * termGroup = new QActionGroup(this); + + singleAct = setupMenuLine(nullptr, (char *)"Single Window (Term + Mon)", this, (TermMode == Single) && (singlemodeFormat == Term + Mon)); + singleAct2 = setupMenuLine(nullptr, (char *)"Single Window (Term only)", this, (TermMode == Single) && (singlemodeFormat == Term)); + MDIAct = setupMenuLine(nullptr, (char *)"MDI", this, TermMode == MDI); + tabbedAct = setupMenuLine(nullptr, (char *)"Tabbed", this, TermMode == Tabbed); + + termGroup->addAction(singleAct); + termGroup->addAction(singleAct2); + termGroup->addAction(MDIAct); + termGroup->addAction(tabbedAct); + + setupMenu->addAction(singleAct); + setupMenu->addAction(singleAct2); + setupMenu->addAction(MDIAct); + setupMenu->addAction(tabbedAct); + setupMenu->addSeparator(); + AlertAction = new QAction("Sound Alerts Setup", this); + + setupMenu->addAction(AlertAction); + connect(AlertAction, SIGNAL(triggered()), this, SLOT(AlertSlot())); + AlertAction->setFont(*menufont); + setupMenu->addSeparator(); + + actFonts = new QAction("Terminal Font", this); + setupMenu->addAction(actFonts); + connect(actFonts, SIGNAL(triggered()), this, SLOT(doFonts())); + actFonts->setFont(*menufont); + + actmenuFont = new QAction("Menu Font", this); + setupMenu->addAction(actmenuFont); + connect(actmenuFont, SIGNAL(triggered()), this, SLOT(doMFonts())); + actmenuFont->setFont(*menufont); + + actColours = new QAction("Choose Colours", this); + setupMenu->addAction(actColours); + connect(actColours, SIGNAL(triggered()), this, SLOT(doColours())); + actColours->setFont(*menufont); + + setupMenu->addSeparator(); + + AGWAction = new QAction("AGW Setup", this); + setupMenu->addAction(AGWAction); + connect(AGWAction, SIGNAL(triggered()), this, SLOT(AGWSlot())); + AGWAction->setFont(*menufont); + + VARAAction = new QAction("VARA Setup", this); + setupMenu->addAction(VARAAction); + connect(VARAAction, SIGNAL(triggered()), this, SLOT(VARASlot())); + VARAAction->setFont(*menufont); + + KISSAction = new QAction("KISS Setup", this); + setupMenu->addAction(KISSAction); + connect(KISSAction, SIGNAL(triggered()), this, SLOT(KISSSlot())); + KISSAction->setFont(*menufont); + + setupMenu->addSeparator(); + + actChatMode = setupMenuLine(setupMenu, (char *)"Chat Terminal Mode (Send Keepalives)", this, ChatMode); + actAutoTeletext = setupMenuLine(setupMenu, (char *)"Auto switch to Teletext", this, AutoTeletext); + actStripLF = setupMenuLine(setupMenu, (char *)"Strip Line Feeds", this, StripLF); + + setupMenu->addSeparator(); + + setupMenu->addAction(new QAction("Interpret non-UTF8 input as:", this)); + setupMenu->setFont(*menufont); + + QActionGroup * cpGroup = new QActionGroup(this); + + actnoConv = setupMenuLine(nullptr, (char *)" Don't Convert (assume is UTF-8)", this, convUTF8 == -1); + actAuto = setupMenuLine(nullptr, (char *)" Auto", this, convUTF8 == 0); + actCP1251 = setupMenuLine(nullptr, (char *)" CP1251 (Cyrillic)", this, convUTF8 == 1251); + actCP1252 = setupMenuLine(nullptr, (char *)" CP1252 (Western Europe)", this, convUTF8 == 1252); + actCP437 = setupMenuLine(nullptr, (char *)" CP437 (Windows Line Draw)", this, convUTF8 == 437); + + cpGroup->addAction(actnoConv); + cpGroup->addAction(actAuto); + cpGroup->addAction(actCP1251); + cpGroup->addAction(actCP1252); + cpGroup->addAction(actCP437); + + setupMenu->addAction(actnoConv); + setupMenu->addAction(actAuto); + setupMenu->addAction(actCP1251); + setupMenu->addAction(actCP1252); + setupMenu->addAction(actCP437); + + monitorMenu = mymenuBar->addMenu(tr("&Monitor")); + + EnableMonitor = setupMenuLine(monitorMenu, (char *)"Enable Monitoring", this, 0); + EnableMonitor->setVisible(0); + EnableMonLog = setupMenuLine(monitorMenu, (char *)"Log to File", this, 0); + MonLocalTime = setupMenuLine(monitorMenu, (char *)"Use local time", this, 0); + MonTX = setupMenuLine(monitorMenu, (char *)"Monitor TX", this, 1); + MonSup = setupMenuLine(monitorMenu, (char *)"Monitor Supervisory", this, 1); + MonUI = setupMenuLine(monitorMenu, (char *)"Only Monitor UI Frames", this, 0); + MonNodes = setupMenuLine(monitorMenu, (char *)"Monitor NODES Broadcasts", this, 0); + MonColour = setupMenuLine(monitorMenu, (char *)"Enable Colour", this, 1); + + for (i = 0; i < MAXPORTS + 1; i++) + { + MonPort[i] = setupMenuLine(monitorMenu, (char *)"Port", this, 0); + MonPort[i]->setVisible(false); + } + + but1 = new QToolButton(); + but1->setPopupMode(QToolButton::InstantPopup); + but1->setText("Monitor"); + but1->addAction(monitorMenu->menuAction()); + toolBar->addWidget(but1); + + but2 = new QToolButton(); + but2->setPopupMode(QToolButton::InstantPopup); + but2->setText("Setup"); + but2->addAction(setupMenu->menuAction()); + toolBar->addWidget(but2); + + ListenAction = mymenuBar->addAction("&Listen"); + connect(ListenAction, SIGNAL(triggered()), this, SLOT(ListenSlot())); + + + // Place Listen Action in mac app menu, otherwise it doesn't appear + if (is_mac == true) + { + QMenu * app_menu = mymenuBar->addMenu("App Menu"); + ListenAction->setMenuRole(QAction::ApplicationSpecificRole); + app_menu->addAction(ListenAction); + } + + toolBar->addAction(ListenAction); + + YAPPMenu = mymenuBar->addMenu(tr("&YAPP")); + + YAPPSend = new QAction("Send File", this); + YAPPSetRX = new QAction("Set Receive Directory", this); + YAPPSetSize = new QAction("Set Max Size", this); + YAPPSend->setFont(*menufont); + YAPPSetRX->setFont(*menufont); + YAPPSetSize->setFont(*menufont); + + YAPPMenu->addAction(YAPPSend); + YAPPMenu->addAction(YAPPSetRX); + YAPPMenu->addAction(YAPPSetSize); + YAPPSend->setEnabled(false); + + connect(YAPPSend, SIGNAL(triggered()), this, SLOT(doYAPPSend())); + connect(YAPPSetRX, SIGNAL(triggered()), this, SLOT(doYAPPSetRX())); + connect(YAPPSetSize, SIGNAL(triggered()), this, SLOT(doYAPPSetSize())); + + but3 = new QToolButton(); + but3->setPopupMode(QToolButton::InstantPopup); + but3->setText("YAPP"); + but3->addAction(YAPPMenu->menuAction()); + but3->setFont(*menufont); + toolBar->addWidget(but3); + + toolBar->setFont(*menufont); + + // Set up Status Bar + + setStyleSheet("QStatusBar{border-top: 1px outset black;} QStatusBar::item { border: 1px solid black; border-radius: 3px;}"); + // setStyleSheet("QStatusBar{border-top: 1px outset black;}"); + + + Status4 = new QLabel(""); + Status3 = new QLabel(" "); + Status2 = new QLabel(" "); + Status1 = new QLabel(" Disconnected "); + + Status1->setMinimumWidth(100); + Status2->setMinimumWidth(100); + Status3->setMinimumWidth(100); + Status4->setMinimumWidth(100); + + myStatusBar = statusBar(); + + statusBar()->addPermanentWidget(Status4); + statusBar()->addPermanentWidget(Status3); + statusBar()->addPermanentWidget(Status2); + statusBar()->addPermanentWidget(Status1); + + statusBar()->setVisible(AGWEnable | VARAEnable | KISSEnable); + // Restore saved sessions + + if (TermMode == Single) + { + Ui_ListenSession * Sess = newWindow(this, singlemodeFormat); + + ActiveSession = Sess; + Sess->CurrentHost = currentHost[0]; + + ui.verticalLayout->addWidget(Sess); + + connectMenu->setEnabled(true); + discAction->setEnabled(false); + YAPPSend->setEnabled(false); + } + + if (TermMode == MDI) + { + int n = atoi(sessionList); + int index = 0; + + char *p, *Context; + char delim[] = "|"; + + int type = 0, host = 0, topx, leftx, bottomx, rightx; + + p = strtok_s((char *)sessionList, delim, &Context); + + while (n--) + { + p = strtok_s(NULL, delim, &Context); + + sscanf(p, "%d,%d,%d,%d,%d,%d", &type, &host, &topx, &leftx, &bottomx, &rightx); + + Ui_ListenSession * Sess = newWindow(this, type); + + Sess->CurrentHost = currentHost[index++];; + + QRect r(leftx, topx, rightx - leftx, bottomx - topx); + + Sess->sw->setGeometry(r); + Sess->sw->move(leftx, topx); + + } + } + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(MyTimerSlot())); + timer->start(10000); + + QTimer *timer2 = new QTimer(this); + connect(timer2, SIGNAL(timeout()), this, SLOT(KISSTimerSlot())); + timer2->start(100); + + // Run timer now to connect to AGW if configured + + MyTimerSlot(); + + if (listenEnable) + _server->listen(QHostAddress::Any, listenPort); + + connect(_server, SIGNAL(newConnection()), this, SLOT(onNewConnection())); + + setFonts(); + + if (VARAEnable) + OpenPTTPort(); + + memset(axMYCALL, 0, 7); + ConvToAX25(MYCALL, axMYCALL); + + // Do any autoconnects + + for (int i = 0; i < _sessions.size(); ++i) + { + if (AutoConnect[i] > 0) + { + Ui_ListenSession * Sess = _sessions.at(i); + + Sess->clientSocket = new myTcpSocket(); + Sess->clientSocket->Sess = Sess; + + connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); + connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); + connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); + + Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]); + } + } + +} + +void QtTermTCP::showContextMenu(const QPoint &point) +{ + if (point.isNull()) + return; + + QTabBar* tabBar = tabWidget->tabBar(); + QRect Wrect = tabWidget->rect(); + QRect Brect = tabBar->rect(); + QPoint myPoint = point; + + // Get x coordinate of first tab (on Mac tabs are centre aligned) + + QRect rect = tabWidget->tabBar()->geometry(); + int left = rect.left(); + + + int n = myPoint.y() - (Wrect.height() - Brect.height()); + myPoint.setY(n); + n = myPoint.x() - left; + + myPoint.setX(n); + + int tabIndex = tabBar->tabAt(myPoint); + + QMenu menu(this); + + QAction * Act = new QAction("AutoConnect on load", this); + Act->setObjectName(QString::number(tabIndex)); + + menu.addAction(Act); + + Act->setCheckable(true); + + if (AutoConnect[tabIndex] <= 0) + Act->setChecked(false); + else + Act->setChecked(true); + + connect(Act, SIGNAL(triggered()), this, SLOT(autoConnectChecked())); + + menu.exec(tabWidget->mapToGlobal(point)); + +} + +void QtTermTCP::autoConnectChecked() +{ + QAction * Act = static_cast(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(0, 0xF0, MYCALL, Sess->UIDEST, (unsigned char *)Msg, (int)strlen(Msg)); + + WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), + Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black + + free(Msg); + + Msgptr = ptr; + } + } + else if (Sess->KISSSession) + { + // Send to ax.25 code + + while ((ptr = strchr(Msgptr, '\n'))) + { + *ptr++ = 0; + + Msg = (char *)malloc(strlen(Msgptr) + 10); + strcpy(Msg, Msgptr); + strcat(Msg, "\r"); + + SendtoAX25(Sess->KISSSession, (unsigned char *)Msg, (int)strlen(Msg)); + + WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), + Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black + + free(Msg); + + Msgptr = ptr; + } + } + + else if (Sess->AGWSession) + { + // Terminal is in AGWPE mode - send as AGW frame + + while ((ptr = strchr(Msgptr, '\n'))) + { + *ptr++ = 0; + + Msg = (char *)malloc(strlen(Msgptr) + 10); + strcpy(Msg, Msgptr); + strcat(Msg, "\r"); + + AGW_AX25_data_in(Sess->AGWSession, (unsigned char *)Msg, (int)strlen(Msg)); + + WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), + Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black + +// Sess->termWindow->insertPlainText(Msg); + + free(Msg); + + Msgptr = ptr; + } + } + + else if (VARASock && VARASock->Sess == Sess) + { + while ((ptr = strchr(Msgptr, '\n'))) + { + *ptr++ = 0; + + Msg = (char *)malloc(strlen(Msgptr) + 10); + strcpy(Msg, Msgptr); + strcat(Msg, "\r"); + + VARADataSock->write(Msg); + + WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), + Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black + +// Sess->termWindow->insertPlainText(Msg); + + free(Msg); + + Msgptr = ptr; + } + } + + else if (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState) + { + while ((ptr = strchr(Msgptr, '\n'))) + { + *ptr++ = 0; + + Msg = (char *)malloc(strlen(Msgptr) + 10); + strcpy(Msg, Msgptr); + strcat(Msg, "\r"); + + Sess->clientSocket->write(Msg); + + WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), + Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, EchoText); // Black + +// Sess->termWindow->insertPlainText(Msg); + + free(Msg); + + Msgptr = ptr; + } + } + else + { + // Not Connected + + if (Sess->SessionType != Listen) + { + if (Sess->CurrentHost < MAXHOSTS) + { + // Last connect was TCP + + char Msg[] = "Connecting....\r"; + + WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), + Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, WarningText); // Red + + delete(Sess->clientSocket); + + Sess->clientSocket = new myTcpSocket(); + Sess->clientSocket->Sess = Sess; + + connect(Sess->clientSocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError))); + connect(Sess->clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); + connect(Sess->clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); + + Sess->clientSocket->connectToHost(&Host[Sess->CurrentHost][0], Port[Sess->CurrentHost]); + } + + else if (Sess->CurrentHost == 16) // AGW + { + // Invoke AGW connect dialog + + AGWConnect dialog(0); + dialog.exec(); + + WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); + return; + } + + else if (Sess->CurrentHost == 17) // VARA + { + // Invoke VARA connect dialog + + VARAConnect dialog(0); + dialog.exec(); + + WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); + return; + } + + else if (Sess->CurrentHost == 18) // KISS + { + // Do we send as UI or invoke kiss connect dialog ?? + + // Try Connect Dialog for now - may make a menu option + + KISSConnect dialog(0); + dialog.exec(); + + WritetoOutputWindow(Sess, (unsigned char *)"Connecting...\r", 14); + return; + } + } + else + { + char Msg[] = "Incoming Session - Can't Connect\r"; + + WritetoOutputWindowEx(Sess, (unsigned char *)Msg, (int)strlen(Msg), + Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, 81); // Red + + } + } + + if (scrollbarAtBottom) + Sess->termWindow->moveCursor(QTextCursor::End); + + Sess->inputWindow->setText(""); + a->inputMethod()->hide(); +} + + +void QtTermTCP::displayError(QAbstractSocket::SocketError socketError) +{ + myTcpSocket* sender = static_cast(QObject::sender()); + + switch (socketError) + { + case QAbstractSocket::RemoteHostClosedError: + break; + + case QAbstractSocket::HostNotFoundError: + QMessageBox::information(this, tr("QtTermTCP"), + tr("The host was not found. Please check the " + "host name and portsettings->")); + break; + + case QAbstractSocket::ConnectionRefusedError: + QMessageBox::information(this, tr("QtTermTCP"), + tr("The connection was refused by the peer.")); + break; + + default: + QMessageBox::information(this, tr("QtTermTCP"), + tr("The following error occurred: %1.") + .arg(sender->errorString())); + } + + connectMenu->setEnabled(true); +} + +void QtTermTCP::readyRead() +{ + int Read; + unsigned char Buffer[8192]; + myTcpSocket* Socket = static_cast(QObject::sender()); + + Ui_ListenSession * Sess = (Ui_ListenSession *)Socket->Sess; + + // read the data from the socket + + Read = Socket->read((char *)Buffer, 2047); + + while (Read > 0) + { + // if (InputMode == 'Y') // Yapp + // { + // QString myString = QString::fromUtf8((char*)Buffer, Read); + // QByteArray ptr = myString.toLocal8Bit(); + // memcpy(Buffer, ptr.data(), ptr.length()); + // Read = ptr.length(); + // } + + + Buffer[Read] = 0; + + ProcessReceivedData(Sess, Buffer, Read); + + QString myString = QString::fromUtf8((char*)Buffer); + // qDebug() << myString; + Read = Socket->read((char *)Buffer, 2047); + } +} + +extern "C" int SocketSend(Ui_ListenSession * Sess, char * Buffer, int len) +{ + myTcpSocket *Socket = Sess->clientSocket; + + if (Socket && Socket->state() == QAbstractSocket::ConnectedState) + return Socket->write(Buffer, len); + + return 0; +} + +extern "C" int SocketFlush(Ui_ListenSession * Sess) +{ + if (Sess->AGWSession || Sess->KISSSession || (VARASock && VARASock->Sess == Sess)) + return 0; + + myTcpSocket* Socket = Sess->clientSocket; + + if (Socket && Socket->state() == QAbstractSocket::ConnectedState) + return Socket->flush(); + + return 0; +} + +extern "C" void mySleep(int ms) +{ + QThread::msleep(ms); +} + +extern "C" void SetPortMonLine(int i, char * Text, int visible, int enabled) +{ + MonPort[i]->setText(Text); + MonPort[i]->setVisible(visible); + MonPort[i]->setChecked(enabled); +} + +bool scrollbarAtBottom = 0; + +extern "C" void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int * OutputSaveLen, char * OutputSave, QColor Colour); + +extern "C" void WritetoOutputWindow(Ui_ListenSession * Sess, unsigned char * Buffer, int len) +{ + WritetoOutputWindowEx(Sess, Buffer, len, Sess->termWindow, &Sess->OutputSaveLen, Sess->OutputSave, outputText); +} + + +extern "C" void WritetoOutputWindowEx(Ui_ListenSession * Sess, unsigned char * Buffer, int len, QTextEdit * termWindow, int * OutputSaveLen, char * OutputSave, QColor Colour) +{ + unsigned char Copy[8192]; + unsigned char * ptr1, *ptr2; + unsigned char Line[8192]; + unsigned char out[8192]; + int outlen; + + int num; + + if (termWindow == NULL) + return; + + time_t NOW = time(NULL); + + // Beep if no output for a while + + if (AlertInterval && (NOW - LastWrite) > AlertInterval) + { + if (AlertBeep) + myBeep(&IntervalWAV); + + } + + // Alert if QtTerm not active window (unless Mon window) + + if((Sess->SessionType & Mon) == 0) + FlashifNotActive(); + + // if tabbed and not active tab set tab label red + + if (TermMode == Tabbed) + { + if (Sess->monWindow != termWindow) // Not if Monitor + { + if (ActiveSession != Sess) + { + tabWidget->tabBar()->setTabTextColor(Sess->Tab, newTabText); + } + } + } + + LastWrite = NOW; + + // Mustn't mess with original buffer + + memcpy(Copy, Buffer, len); + + Copy[len] = 0; + + ptr1 = Copy; + + const QTextCursor old_cursor = termWindow->textCursor(); + const int old_scrollbar_value = termWindow->verticalScrollBar()->value(); + const bool is_scrolled_down = old_scrollbar_value == termWindow->verticalScrollBar()->maximum(); + + if (*OutputSaveLen) + { + // Have part line - append to it + memcpy(&OutputSave[*OutputSaveLen], Copy, len); + *OutputSaveLen += len; + ptr1 = (unsigned char *)OutputSave; + len = *OutputSaveLen; + *OutputSaveLen = 0; + + // part line was written to screen so remove it + +// termWindow->setFocus(); + termWindow->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor); + termWindow->moveCursor(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor); + termWindow->moveCursor(QTextCursor::End, QTextCursor::KeepAnchor); + termWindow->textCursor().removeSelectedText(); + // termWindow->textCursor().deletePreviousChar(); + } + + // Move the cursor to the end of the document. + + termWindow->moveCursor(QTextCursor::End); + + // Insert the text at the position of the cursor (which is the end of the document). + +lineloop: + + if (len <= 0) + { + if (old_cursor.hasSelection() || !is_scrolled_down) + { + // The user has selected text or scrolled away from the bottom: maintain position. + termWindow->setTextCursor(old_cursor); + termWindow->verticalScrollBar()->setValue(old_scrollbar_value); + } + else + { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + termWindow->moveCursor(QTextCursor::End); + termWindow->verticalScrollBar()->setValue(termWindow->verticalScrollBar()->maximum()); + } + + return; + } + + + // copy text to control a line at a time + + ptr2 = (unsigned char *)memchr(ptr1, 13, len); + + if (ptr2 == 0) // No CR + { + if (len > 8000) + len = 8000; // Should never get lines this long + + memmove(OutputSave, ptr1, len); + *OutputSaveLen = len; + + // Write part line to screen + + memcpy(Line, ptr1, len); + Line[len] = 0; + + // I don't think I need to worry if UTF8 as will be rewritten when rest arrives + + if (Line[0] == 0x1b) // Colour Escape + { + if (Sess->MonitorColour) + termWindow->setTextColor(Colours[Line[1] - 10]); + + termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); + } + else + { + termWindow->setTextColor(Colour); + termWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); + } + + // *OutputSaveLen = 0; // Test if we need to delete part line + + // if (scrollbarAtBottom) + // termWindow->moveCursor(QTextCursor::End); + + if (old_cursor.hasSelection() || !is_scrolled_down) + { + // The user has selected text or scrolled away from the bottom: maintain position. + termWindow->setTextCursor(old_cursor); + termWindow->verticalScrollBar()->setValue(old_scrollbar_value); + } + else + { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + termWindow->moveCursor(QTextCursor::End); + termWindow->verticalScrollBar()->setValue(termWindow->verticalScrollBar()->maximum()); + } + return; + } + + *(ptr2++) = 0; + + if (Bells) + { + char * ptr; + + do { + ptr = (char *)memchr(ptr1, 7, len); + + if (ptr) + { + *(ptr) = 32; + myBeep(&BellWAV); + } + } while (ptr); + } + + num = ptr2 - ptr1 - 1; + + // if (LogMonitor) WriteMonitorLine(ptr1, ptr2 - ptr1); + + memcpy(Line, ptr1, num); + Line[num++] = 13; + Line[num] = 0; + + if (Line[0] == 0x1b) // Colour Escape + { + if (Sess->MonitorColour) + termWindow->setTextColor(Colours[Line[1] - 10]); + + outlen = checkUTF8(&Line[2], num - 2, out); + out[outlen] = 0; + termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); + // termWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); + } + else + { + termWindow->setTextColor(Colour); + + outlen = checkUTF8(Line, num, out); + out[outlen] = 0; + termWindow->textCursor().insertText(QString::fromUtf8((char*)out)); + // termWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); + } + + len -= (ptr2 - ptr1); + + ptr1 = ptr2; + + if ((len > 0) && StripLF) + { + if (*ptr1 == 0x0a) // Line Feed + { + ptr1++; + len--; + } + } + + + + goto lineloop; + +} + +void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg); + +extern "C" void WritetoMonWindow(Ui_ListenSession * Sess, unsigned char * Msg, int len) +{ + char * ptr1 = (char *)Msg, *ptr2; + char Line[512]; + int num; + + // QScrollBar *scrollbar = Sess->monWindow->verticalScrollBar(); + // bool scrollbarAtBottom = (scrollbar->value() >= (scrollbar->maximum() - 4)); + + if (Sess->monWindow == nullptr) + return; + + Sess->monWindow->setStyleSheet(monStyleSheet); + + const QTextCursor old_cursor = Sess->monWindow->textCursor(); + const int old_scrollbar_value = Sess->monWindow->verticalScrollBar()->value(); + const bool is_scrolled_down = old_scrollbar_value == Sess->monWindow->verticalScrollBar()->maximum(); + + // Move the cursor to the end of the document. + Sess->monWindow->moveCursor(QTextCursor::End); + + // Insert the text at the position of the cursor (which is the end of the document). + + + // Write a line at a time so we can action colour chars + +// Buffer[Len] = 0; + +// if (scrollbarAtBottom) +// Sess->monWindow->moveCursor(QTextCursor::End); + + if (Sess->MonSaveLen) + { + // Have part line - append to it + memcpy(&Sess->MonSave[Sess->MonSaveLen], Msg, len); + Sess->MonSaveLen += len; + ptr1 = Sess->MonSave; + len = Sess->MonSaveLen; + Sess->MonSaveLen = 0; + } + +lineloop: + + if (len <= 0) + { + // if (scrollbarAtBottom) + // Sess->monWindow->moveCursor(QTextCursor::End); + + + if (old_cursor.hasSelection() || !is_scrolled_down) + { + // The user has selected text or scrolled away from the bottom: maintain position. + Sess->monWindow->setTextCursor(old_cursor); + Sess->monWindow->verticalScrollBar()->setValue(old_scrollbar_value); + } + else + { + // The user hasn't selected any text and the scrollbar is at the bottom: scroll to the bottom. + Sess->monWindow->moveCursor(QTextCursor::End); + Sess->monWindow->verticalScrollBar()->setValue(Sess->monWindow->verticalScrollBar()->maximum()); + } + + return; + } + + // copy text to control a line at a time + + ptr2 = (char *)memchr(ptr1, 13, len); + + if (ptr2 == 0) // No CR + { + memmove(Sess->MonSave, ptr1, len); + Sess->MonSaveLen = len; + return; + } + + *(ptr2++) = 0; + + + if (Sess->LogMonitor) + WriteMonitorLog(Sess, ptr1); + + num = ptr2 - ptr1 - 1; + + memcpy(Line, ptr1, num); + Line[num++] = 13; + Line[num] = 0; + + if (Line[0] == 0x1b) // Colour Escape + { + if (Sess->MonitorColour) + { + if (Line[1] == 17) + Sess->monWindow->setTextColor(monRxText); + else + Sess->monWindow->setTextColor(monTxText); + } + else + Sess->monWindow->setTextColor(monOtherText); + + Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)&Line[2])); + } + else + { + Sess->monWindow->textCursor().insertText(QString::fromUtf8((char*)Line)); + } + len -= (ptr2 - ptr1); + + ptr1 = ptr2; + + goto lineloop; + +} + +int ProcessYAPPMessage(Ui_ListenSession * Sess, UCHAR * Msg, int Len); +void QueueMsg(Ui_ListenSession * Sess, char * Msg, int Len); + +// YAPP stuff + +#define SOH 1 +#define STX 2 +#define ETX 3 +#define EOT 4 +#define ENQ 5 +#define ACK 6 +#define DLE 0x10 +#define NAK 0x15 +#define CAN 0x18 + +extern "C" void SendtoTerm(Ui_ListenSession * Sess, char * Msg, int Len) +{ + if (Sess == 0) + return; + + Sess->SlowTimer = 0; + Msg[Len] = 0; + + if (Sess->InputMode == 'Y') // Yapp + { + ProcessYAPPMessage(Sess, (unsigned char *)Msg, Len); + return; + } + + // Could be a YAPP Header + + if (Len == 2 && Msg[0] == ENQ && Msg[1] == 1) // YAPP Send_Init + { + char YAPPRR[2]; + + // Turn off monitoring + + Sess->InputMode = 'Y'; + + YAPPRR[0] = ACK; + YAPPRR[1] = 1; + QueueMsg(Sess, YAPPRR, 2); + + return; + } + + if (AutoTeletext && (Msg[0] == 0x1e || Msg[0] == 0x0c)) + { + if (Sess->TTActive == 0) + { + Sess->TTActive = 1; + DoTermResize(Sess); + } + } + + if (Sess->TTActive) + { + // Feed to Teletext code + + // We need to decode a whole page. There is no obvious delimiter so process till data stops. + // Buffer is cleared when next input is sent + + if (strlen(&Sess->pageBuffer[0] + Len) > 4090) + Sess->pageBuffer[0] = 0; // Protect buffer + + strcat(Sess->pageBuffer, (char *)Msg); + + DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end + return; + } + + WritetoOutputWindow(Sess, (unsigned char *)Msg, Len); + +} + +QSettings* settings; + +// This makes geting settings for more channels easier + +char Prefix[16] = "AX25_A"; + +void GetPortSettings(int Chan); + +QVariant getAX25Param(const char * key, QVariant Default) +{ + char fullKey[64]; + + sprintf(fullKey, "%s/%s", Prefix, key); + return settings->value(fullKey, Default); +} + +void getAX25Params(int chan) +{ + Prefix[5] = chan + 'A'; + GetPortSettings(chan); +} + + +void GetPortSettings(int Chan) +{ + maxframe[Chan] = getAX25Param("Maxframe", 4).toInt(); + fracks[Chan] = getAX25Param("Retries", 10).toInt(); + frack_time[Chan] = getAX25Param("FrackTime", 8).toInt(); + persist[Chan] = getAX25Param("Persist", 128).toInt(); + kisspaclen[Chan] = getAX25Param("Paclen", 128).toInt(); + idletime[Chan] = getAX25Param("IdleTime", 180).toInt(); + slottime[Chan] = getAX25Param("SlotTime", 100).toInt(); + resptime[Chan] = getAX25Param("RespTime", 1500).toInt(); + TXFrmMode[Chan] = getAX25Param("TXFrmMode", 1).toInt(); + max_frame_collector[Chan] = getAX25Param("FrameCollector", 6).toInt(); + //exclude_callsigns[Chan]= getAX25Param("ExcludeCallsigns/"); + //exclude_APRS_frm[Chan]= getAX25Param("ExcludeAPRSFrmType/"); + KISS_opt[Chan] = getAX25Param("KISSOptimization", false).toInt();; + dyn_frack[Chan] = getAX25Param("DynamicFrack", false).toInt();; + IPOLL[Chan] = getAX25Param("IPOLL", 80).toInt(); + +} + + +void GetSettings() +{ + QByteArray qb; + int i; + char Key[16]; + char Param[256]; + + settings = new QSettings(GetConfPath(), QSettings::IniFormat); + + // Get saved session definitions + + sessionList = strdup(settings->value("Sessions", "1|3, 0, 5, 5, 600, 800|").toString().toUtf8()); + + for (i = 0; i < MAXHOSTS; i++) + { + sprintf(Key, "HostParams%d", i); + + qb = settings->value(Key).toByteArray(); + + DecodeSettingsLine(i, qb.data()); + } + + Split = settings->value("Split", 50).toInt(); + ChatMode = settings->value("ChatMode", 1).toInt(); + AutoTeletext = settings->value("AutoTeletext", 0).toInt(); + Bells = settings->value("Bells", 1).toInt(); + StripLF = settings->value("StripLF", 1).toInt(); + useBeep = settings->value("useBeep", true).toBool(); + AlertBeep = settings->value("AlertBeep", 1).toInt(); + AlertInterval = settings->value("AlertInterval", 300).toInt(); + ConnectBeep = settings->value("ConnectBeep", 1).toInt(); + ConnectWAV = settings->value("ConnectWAV", ":/PCBeep").toString().toUtf8(); + AlertWAV = settings->value("AlertWAV", ":/PCBeep").toString().toUtf8(); + BellWAV = settings->value("BellWAV", ":/PCBeep").toString().toUtf8(); + IntervalWAV = settings->value("IntervalWAV", ":/PCBeep").toString().toUtf8(); + + UseKeywords = settings->value("UseKeywords", 0).toInt(); + KeyWordsFile = settings->value("KeyWordsFile", "keywords.sys").toString().toUtf8(); + + SavedHost = settings->value("CurrentHost", 0).toInt(); + strcpy(YAPPPath, settings->value("YAPPPath", "").toString().toUtf8()); + MaxRXSize = settings->value("MaxRXSize", 100000).toInt(); + + listenPort = settings->value("listenPort", 8015).toInt(); + listenEnable = settings->value("listenEnable", false).toBool(); + strcpy(listenCText, settings->value("listenCText", "").toString().toUtf8()); + + TermMode = settings->value("TermMode", 0).toInt(); + singlemodeFormat = settings->value("singlemodeFormat", Term + Mon).toInt(); + + AGWEnable = settings->value("AGWEnable", 0).toInt(); + AGWMonEnable = settings->value("AGWMonEnable", 0).toInt(); + AGWLocalTime = settings->value("AGWLocalTime", 0).toInt(); + AGWMonNodes = settings->value("AGWMonNodes", 0).toInt(); + strcpy(AGWTermCall, settings->value("AGWTermCall", "").toString().toUtf8()); + strcpy(AGWBeaconDest, settings->value("AGWBeaconDest", "").toString().toUtf8()); + strcpy(AGWBeaconPath, settings->value("AGWBeaconPath", "").toString().toUtf8()); + AGWBeaconInterval = settings->value("AGWBeaconInterval", 0).toInt(); + strcpy(AGWBeaconPorts, settings->value("AGWBeaconPorts", "").toString().toUtf8()); + strcpy(AGWBeaconMsg, settings->value("AGWBeaconText", "").toString().toUtf8()); + strcpy(AGWHost, settings->value("AGWHost", "127.0.0.1").toString().toUtf8()); + AGWPortNum = settings->value("AGWPort", 8000).toInt(); + AGWPaclen = settings->value("AGWPaclen", 80).toInt(); + AGWToCalls = settings->value("AGWToCalls", "").toStringList(); + convUTF8 = settings->value("convUTF8", 0).toInt(); + + KISSEnable = settings->value("KISSEnable", 0).toInt(); + KISSMonEnable = settings->value("KISSMonEnable", 1).toInt(); + KISSLocalTime = settings->value("KISSLocalTime", 0).toInt(); + KISSMonNodes = settings->value("KISSMonNodes", 0).toInt(); + + KISSListen = settings->value("KISSListen", 1).toInt(); + strcpy(MYCALL, settings->value("MYCALL", "").toString().toUtf8()); + strcpy(KISSHost, settings->value("KISSHost", "127.0.0.1").toString().toUtf8()); + KISSPortNum = settings->value("KISSPort", 8100).toInt(); + KISSMode = settings->value("KISSMode", 0).toInt(); + + strcpy(SerialPort, settings->value("KISSSerialPort", "None").toString().toUtf8()); + KISSBAUD = settings->value("KISSBAUD", 19200).toInt(); + getAX25Params(0); + + VARAEnable = settings->value("VARAEnable", 0).toInt(); + strcpy(VARAHost, settings->value("VARAHost", "127.0.0.1").toString().toUtf8()); + strcpy(VARAHostFM, settings->value("VARAHostFM", "127.0.0.1").toString().toUtf8()); + strcpy(VARAHostHF, settings->value("VARAHostHF", "127.0.0.1").toString().toUtf8()); + strcpy(VARAHostSAT, settings->value("VARAHostSAT", "127.0.0.1").toString().toUtf8()); + VARAPortNum = settings->value("VARAPort", 8300).toInt(); + VARAPortHF = settings->value("VARAPortHF", 8300).toInt(); + VARAPortFM = settings->value("VARAPortFM", 8300).toInt(); + VARAPortSAT = settings->value("VARAPortSAT", 8300).toInt(); + strcpy(VARAPath, settings->value("VARAPath", "C:\\VARA\\VARA.exe").toString().toUtf8()); + strcpy(VARAPathHF, settings->value("VARAPathHF", "C:\\VARA\\VARA.exe").toString().toUtf8()); + strcpy(VARAPathFM, settings->value("VARAPathFM", "C:\\VARA\\VARAFM.exe").toString().toUtf8()); + strcpy(VARAPathSAT, settings->value("VARAPathSAT", "C:\\VARA\\VARASAT.exe").toString().toUtf8()); + strcpy(VARATermCall, settings->value("VARATermCall", "").toString().toUtf8()); + VARA500 = settings->value("VARA500", 0).toInt(); + VARA2300 = settings->value("VARA2300", 1).toInt(); + VARA2750 = settings->value("VARA2750", 0).toInt(); + VARAHF = settings->value("VARAHF", 1).toInt(); + VARAFM = settings->value("VARAFM", 0).toInt(); + VARASAT = settings->value("VARASAT", 0).toInt(); + strcpy(VARAInit, settings->value("VARAInit", "").toString().toUtf8()); + + strcpy(PTTPort, settings->value("PTT", "None").toString().toUtf8()); + PTTMode = settings->value("PTTMode", 19200).toInt(); + PTTBAUD = settings->value("PTTBAUD", 19200).toInt(); + CATHex = settings->value("CATHex", 1).toInt(); + + strcpy(PTTOnString, settings->value("PTTOnString", "").toString().toUtf8()); + strcpy(PTTOffString, settings->value("PTTOffString", "").toString().toUtf8()); + + pttGPIOPin = settings->value("pttGPIOPin", 17).toInt(); + pttGPIOPinR = settings->value("pttGPIOPinR", 17).toInt(); + +#ifdef WIN32 + strcpy(CM108Addr, settings->value("CM108Addr", "0xD8C:0x08").toString().toUtf8()); +#else + strcpy(CM108Addr, settings->value("CM108Addr", "/dev/hidraw0").toString().toUtf8()); +#endif + + HamLibPort = settings->value("HamLibPort", 4532).toInt(); + strcpy(HamLibHost, settings->value("HamLibHost", "127.0.0.1").toString().toUtf8()); + + FLRigPort = settings->value("FLRigPort", 12345).toInt(); + strcpy(FLRigHost, settings->value("FLRigHost", "127.0.0.1").toString().toUtf8()); + + + strcpy(Param, settings->value("TabType", "1 1 1 1 1 1 1 2 2").toString().toUtf8()); + sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", + &TabType[0], &TabType[1], &TabType[2], &TabType[3], &TabType[4], + &TabType[5], &TabType[6], &TabType[7], &TabType[8], &TabType[9]); + + strcpy(Param, settings->value("AutoConnect", "0, 0 ,0, 0, 0, 0, 0, 0, 0, 0").toString().toUtf8()); + sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", + &AutoConnect[0], &AutoConnect[1], &AutoConnect[2], &AutoConnect[3], &AutoConnect[4], + &AutoConnect[5], &AutoConnect[6], &AutoConnect[7], &AutoConnect[8], &AutoConnect[9]); + + strcpy(Param, settings->value("currentHost", "0, 0 ,0, 0, 0, 0, 0, 0, 0, 0").toString().toUtf8()); + sscanf(Param, "%d %d %d %d %d %d %d %d %d %d", + ¤tHost[0], ¤tHost[1], ¤tHost[2], ¤tHost[3], ¤tHost[4], + ¤tHost[5], ¤tHost[6], ¤tHost[7], ¤tHost[8], ¤tHost[9]); + + + monBackground = settings->value("monBackground", QColor(255, 255, 255)).value(); + monRxText = settings->value("monRxText", QColor(0, 0, 255)).value(); + monTxText = settings->value("monTxText", QColor(255, 0, 0)).value(); + monOtherText = settings->value("monOtherText", QColor(0, 0, 0)).value(); + + termBackground = settings->value("termBackground", QColor(255, 255, 255)).value(); + outputText = settings->value("outputText", QColor(0, 0, 255)).value(); + EchoText = settings->value("EchoText", QColor(0, 0, 0)).value(); + WarningText = settings->value("WarningText", QColor(255, 0, 0)).value(); + + inputBackground = settings->value("inputBackground", QColor(255, 255, 255)).value(); + inputText = settings->value("inputText", QColor(0, 0, 0)).value(); + + delete(settings); +} + +void SavePortSettings(int Chan); + +void saveAX25Param(const char * key, QVariant Value) +{ + char fullKey[64]; + + sprintf(fullKey, "%s/%s", Prefix, key); + + settings->setValue(fullKey, Value); +} + +void saveAX25Params(int chan) +{ + Prefix[5] = chan + 'A'; + SavePortSettings(chan); +} + +void SavePortSettings(int Chan) +{ + saveAX25Param("Retries", fracks[Chan]); + saveAX25Param("Maxframe", maxframe[Chan]); + saveAX25Param("Paclen", kisspaclen[Chan]); + saveAX25Param("FrackTime", frack_time[Chan]); + saveAX25Param("IdleTime", idletime[Chan]); + saveAX25Param("SlotTime", slottime[Chan]); + saveAX25Param("Persist", persist[Chan]); + saveAX25Param("RespTime", resptime[Chan]); + saveAX25Param("TXFrmMode", TXFrmMode[Chan]); + saveAX25Param("FrameCollector", max_frame_collector[Chan]); + saveAX25Param("ExcludeCallsigns", exclude_callsigns[Chan]); + saveAX25Param("ExcludeAPRSFrmType", exclude_APRS_frm[Chan]); + saveAX25Param("KISSOptimization", KISS_opt[Chan]); + saveAX25Param("DynamicFrack", dyn_frack[Chan]); + saveAX25Param("BitRecovery", recovery[Chan]); + saveAX25Param("IPOLL", IPOLL[Chan]); + saveAX25Param("MyDigiCall", MyDigiCall[Chan]); +} + +extern "C" void SaveSettings() +{ + int i; + char Param[512]; + char Key[16]; + + settings = new QSettings(GetConfPath(), QSettings::IniFormat); + + for (i = 0; i < MAXHOSTS; i++) + { + sprintf(Key, "HostParams%d", i); + EncodeSettingsLine(i, Param); + settings->setValue(Key, Param); + } + + settings->setValue("Split", Split); + settings->setValue("ChatMode", ChatMode); + settings->setValue("AutoTeletext", AutoTeletext); + settings->setValue("Bells", Bells); + settings->setValue("StripLF", StripLF); + settings->setValue("AlertBeep", AlertBeep); + settings->setValue("useBeep", useBeep); + settings->setValue("ConnectBeep", ConnectBeep); + settings->setValue("BellWAV", BellWAV); + settings->setValue("AlertWAV", AlertWAV); + settings->setValue("IntervalWAV", IntervalWAV); + settings->setValue("ConnectWAV", ConnectWAV); + + settings->setValue("UseKeywords", UseKeywords); + settings->setValue("KeyWordsFile", KeyWordsFile); + + settings->setValue("AlertInterval", AlertInterval); + settings->setValue("CurrentHost", SavedHost); + + settings->setValue("YAPPPath", YAPPPath); + settings->setValue("MaxRXSize", MaxRXSize); + + settings->setValue("listenPort", listenPort); + settings->setValue("listenEnable", listenEnable); + settings->setValue("listenCText", listenCText); + settings->setValue("convUTF8", convUTF8); + + settings->setValue("PTT", PTTPort); + settings->setValue("PTTBAUD", PTTBAUD); + settings->setValue("PTTMode", PTTMode); + + settings->setValue("CATHex", CATHex); + + settings->setValue("PTTOffString", PTTOffString); + settings->setValue("PTTOnString", PTTOnString); + + settings->setValue("pttGPIOPin", pttGPIOPin); + settings->setValue("pttGPIOPinR", pttGPIOPinR); + + settings->setValue("CM108Addr", CM108Addr); + settings->setValue("HamLibPort", HamLibPort); + settings->setValue("HamLibHost", HamLibHost); + settings->setValue("FLRigPort", FLRigPort); + settings->setValue("FLRigHost", FLRigHost); + + + // Save Sessions + + char SessionString[1024]; + int SessStringLen; + + SessStringLen = sprintf(SessionString, "%d|", _sessions.size()); + + if (TermMode == MDI) + { + for (int i = 0; i < _sessions.size(); ++i) + { + Ui_ListenSession * Sess = _sessions.at(i); + + QRect r = Sess->sw->geometry(); + + SessStringLen += sprintf(&SessionString[SessStringLen], + "%d, %d, %d, %d, %d, %d|", Sess->SessionType, Sess->CurrentHost, r.top(), r.left(), r.bottom(), r.right()); + } + + settings->setValue("Sessions", SessionString); + } + + settings->setValue("AGWEnable", AGWEnable); + settings->setValue("AGWMonEnable", AGWMonEnable); + settings->setValue("AGWLocalTime", AGWLocalTime); + settings->setValue("AGWMonNodes", AGWMonNodes); + settings->setValue("AGWTermCall", AGWTermCall); + settings->setValue("AGWBeaconDest", AGWBeaconDest); + settings->setValue("AGWBeaconPath", AGWBeaconPath); + settings->setValue("AGWBeaconInterval", AGWBeaconInterval); + settings->setValue("AGWBeaconPorts", AGWBeaconPorts); + settings->setValue("AGWBeaconText", AGWBeaconMsg); + settings->setValue("AGWHost", AGWHost); + settings->setValue("AGWPort", AGWPortNum); + settings->setValue("AGWPaclen", AGWPaclen); + settings->setValue("AGWToCalls", AGWToCalls); + + settings->setValue("KISSEnable", KISSEnable); + settings->setValue("KISSMonEnable", KISSMonEnable); + settings->setValue("KISSLocalTime", KISSLocalTime); + settings->setValue("KISSMonNodes", KISSMonNodes); + + settings->setValue("KISSListen", KISSListen); + settings->setValue("MYCALL", MYCALL); + settings->setValue("KISSHost", KISSHost); + settings->setValue("KISSMode", KISSMode); + settings->setValue("KISSPort", KISSPortNum); + settings->setValue("KISSSerialPort", SerialPort); + settings->setValue("KISSBAUD", KISSBAUD); + saveAX25Params(0); + + settings->setValue("VARAEnable", VARAEnable); + settings->setValue("VARATermCall", VARATermCall); + settings->setValue("VARAHost", VARAHost); + settings->setValue("VARAPort", VARAPortNum); + settings->setValue("VARAInit", VARAInit); + settings->setValue("VARAPath", VARAPath); + settings->setValue("VARAHostHF", VARAHostHF); + settings->setValue("VARAPortHF", VARAPortHF); + settings->setValue("VARAPathHF", VARAPathHF); + settings->setValue("VARAHostFM", VARAHostFM); + settings->setValue("VARAPortFM", VARAPortFM); + settings->setValue("VARAPathFM", VARAPathFM); + settings->setValue("VARAHostSAT", VARAHostSAT); + settings->setValue("VARAPortSAT", VARAPortSAT); + settings->setValue("VARAPathSAT", VARAPathSAT); + settings->setValue("VARA500", VARA500); + settings->setValue("VARA2300", VARA2300); + settings->setValue("VARA2750", VARA2750); + settings->setValue("VARAHF", VARAHF); + settings->setValue("VARAFM", VARAFM); + settings->setValue("VARASAT", VARASAT); + + sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", + TabType[0], TabType[1], TabType[2], TabType[3], TabType[4], TabType[5], TabType[6], TabType[7], TabType[8], TabType[9]); + + settings->setValue("TabType", Param); + + sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", + AutoConnect[0], AutoConnect[1], AutoConnect[2], AutoConnect[3], AutoConnect[4], AutoConnect[5], AutoConnect[6], AutoConnect[7], AutoConnect[8], AutoConnect[9]); + + settings->setValue("AutoConnect", Param); + + sprintf(Param, "%d %d %d %d %d %d %d %d %d %d", + currentHost[0], currentHost[1], currentHost[2], currentHost[3], currentHost[4], currentHost[5], currentHost[6], currentHost[7], currentHost[8], currentHost[9]); + + settings->setValue("currentHost", Param); + + settings->setValue("monBackground", monBackground); + settings->setValue("monRxText", monRxText); + settings->setValue("monTxText", monTxText); + settings->setValue("monOtherText", monOtherText); + + settings->setValue("termBackground", termBackground); + settings->setValue("outputText", outputText); + settings->setValue("EchoText", EchoText); + settings->setValue("WarningText", WarningText); + + settings->setValue("inputBackground", inputBackground); + settings->setValue("inputText", inputText); + + settings->sync(); + delete(settings); +} + +#include + +void QtTermTCP::closeEvent(QCloseEvent *event) +{ + QMessageBox::StandardButton resBtn = QMessageBox::question(this, "QtTermTCP", + tr("Are you sure?\n"), + QMessageBox::Cancel | QMessageBox::No | QMessageBox::Yes, + QMessageBox::Yes); + if (resBtn != QMessageBox::Yes) { + event->ignore(); + } + else + { + event->accept(); +#ifdef USESERIAL + if (hPTTDevice) + hPTTDevice->close(); +#endif + if (process) + process->close(); + } +} + +QtTermTCP::~QtTermTCP() +{ + Ui_ListenSession * Sess; + + for (int i = 0; i < _sessions.size(); ++i) + { + Sess = _sessions.at(i); + + if (Sess->monLogfile) + Sess->monLogfile->close(); + + if (Sess->clientSocket) + { + int loops = 100; + Sess->clientSocket->disconnectFromHost(); + while (Sess->clientSocket && loops-- && Sess->clientSocket->state() != QAbstractSocket::UnconnectedState) + QThread::msleep(10); + } + } + + if (AGWSock && AGWSock->ConnectedState == QAbstractSocket::ConnectedState) + { + int loops = 100; + AGWSock->disconnectFromHost(); + QThread::msleep(10); + while (AGWSock && loops-- && AGWSock->state() != QAbstractSocket::UnconnectedState) + QThread::msleep(10); + } + + if (_server->isListening()) + _server->close(); + + delete(_server); + + QSettings mysettings(GetConfPath(), QSettings::IniFormat); + mysettings.setValue("geometry", saveGeometry()); + mysettings.setValue("windowState", saveState()); + + SaveSettings(); +} + +extern "C" void timer_event(); + +void QtTermTCP::KISSTimerSlot() +{ + // Runs every 100 mS + + timer_event(); +} + +void QtTermTCP::MyTimerSlot() +{ + // Runs every 10 seconds + + Ui_ListenSession * Sess; + + for (int i = 0; i < _sessions.size(); ++i) + { + Sess = _sessions.at(i); + + // for (Ui_ListenSession * Sess : _sessions) + // { + if (Sess == NULL) + continue; + + if (!ChatMode) + continue; + + if (Sess->KISSSession || + (Sess->clientSocket && Sess->clientSocket->state() == QAbstractSocket::ConnectedState)) + { + Sess->SlowTimer++; + + if (Sess->SlowTimer > 54) // About 9 mins + { + unsigned char Msg[2] = ""; + + Sess->SlowTimer = 0; + + if (Sess->KISSSession) + { + TAX25Port * ax25 = (TAX25Port *)Sess->KISSSession; + + if (ax25->status == STAT_LINK) + SendtoAX25(Sess->KISSSession, Msg, 1); + } + else + Sess->clientSocket->write("\0", 1); + } + } + } + + if (AGWEnable) + AGWTimer(); + + if (VARAEnable) + VARATimer(); + + if (KISSEnable) + KISSTimer(); + +} + +extern "C" void myBeep(QString * WAV) +{ + if (useBeep) + { + QApplication::beep(); + return; + } + + // Using .wav files + +// QSoundEffect effect; +// effect.setSource(QUrl::fromLocalFile(*WAV)); +// effect.setLoopCount(1); +// effect.setVolume(1.0f); +// effect.play(); + + QSound::play(*WAV); +} + +void QtTermTCP::ListenSlot() +{ + // This runs the Listen Configuration dialog + + ListenDialog * xx = new ListenDialog(); + xx->exec(); +} + +void QtTermTCP::AGWSlot() +{ + // This runs the AGW Configuration dialog + + AGWDialog dialog(0); + dialog.exec(); +} + +Ui_Dialog * Dev; +Ui_AlertDialog * Alert; + +static Ui_KISSDialog * KISS; +static Ui_ColourDialog * COLOURS; + + +char NewPTTPort[80]; + +int newSoundMode = 0; +int oldSoundMode = 0; + +#ifdef USESERIAL +QList Ports = QSerialPortInfo::availablePorts(); +#endif + + +void QtTermTCP::KISSSlot() +{ + // This runs the KISS Configuration dialog + + KISS = new(Ui_KISSDialog); + + QDialog UI; + + KISS->setupUi(&UI); + + UI.setFont(*menufont); + + deviceUI = &UI; + KISS->KISSEnable->setChecked(KISSEnable); + KISS->KISSListen->setChecked(KISSListen); + KISS->MYCALL->setText(MYCALL); + + // connect(KISS->SerialPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); + + QStringList items; + +#ifdef USESERIAL + + for (const QSerialPortInfo &info : Ports) + { + items.append(info.portName()); + } + + items.sort(); + items.insert(0, "TCP"); + +#endif + + for (const QString &info : items) + { + KISS->SerialPort->addItem(info); + } + + KISS->SerialPort->setCurrentIndex(KISS->SerialPort->findText(SerialPort, Qt::MatchFixedString)); + KISS->Speed->setText(QString::number(KISSBAUD)); + KISS->Host->setText(KISSHost); + KISS->Port->setText(QString::number(KISSPortNum)); + + KISS->Paclen->setText(QString::number(kisspaclen[0])); + KISS->Maxframe->setText(QString::number(maxframe[0])); + KISS->Frack->setText(QString::number(frack_time[0])); + KISS->Retries->setText(QString::number(fracks[0])); + + QObject::connect(KISS->okButton, SIGNAL(clicked()), this, SLOT(KISSaccept())); + QObject::connect(KISS->cancelButton, SIGNAL(clicked()), this, SLOT(KISSreject())); + + UI.exec(); + +} + + +void QtTermTCP::KISSaccept() +{ + QVariant Q; + int OldEnable = KISSEnable; + char oldSerialPort[64]; + int OldPort = KISSPortNum; + char oldHost[128]; + + strcpy(oldSerialPort, SerialPort); + strcpy(oldHost, KISSHost); + + KISSEnable = KISS->KISSEnable->isChecked(); + KISSListen = KISS->KISSListen->isChecked(); + actHost[18]->setVisible(KISSEnable); // Show KISS Connect Line + + strcpy(MYCALL, KISS->MYCALL->text().toUtf8().toUpper()); + + memset(axMYCALL, 0, 7); + ConvToAX25(MYCALL, axMYCALL); + + Q = KISS->Port->text(); + KISSPortNum = Q.toInt(); + + Q = KISS->Speed->text(); + KISSBAUD = Q.toInt(); + + strcpy(KISSHost, KISS->Host->text().toUtf8().toUpper()); + + Q = KISS->SerialPort->currentText(); + strcpy(SerialPort, Q.toString().toUtf8()); + + Q = KISS->Paclen->text(); + kisspaclen[0] = Q.toInt(); + Q = KISS->Maxframe->text(); + maxframe[0] = Q.toInt(); + Q = KISS->Frack->text(); + frack_time[0] = Q.toInt(); + Q = KISS->Retries->text(); + fracks[0] = Q.toInt(); + + myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable); + + + if (KISSEnable != OldEnable || KISSPortNum != OldPort || + strcmp(oldHost, KISSHost) != 0 || + strcmp(oldSerialPort, SerialPort) != 0) + { + // (re)start connection + + if (OldEnable) + { + if (KISSEnable) + Status3->setText("KISS Closed"); + else + Status3->setText("KISS Disabled"); + + KISSConnected = 0; + + if (KISSSock && KISSSock->ConnectedState == QAbstractSocket::ConnectedState) + KISSSock->disconnectFromHost(); + else if (m_serial) + closeSerialPort(); + } + } + + delete(KISS); + SaveSettings(); + deviceUI->accept(); + + // QSize newSize(this->size()); + // QSize oldSize(this->size()); + + // QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); + + // QCoreApplication::postEvent(this, myResizeEvent); +} + +void QtTermTCP::KISSreject() +{ + delete(KISS); + deviceUI->reject(); +} + + +void QtTermTCP::AlertSlot() +{ + // This runs the VARA Configuration dialog + + Alert = new(Ui_AlertDialog); + + QDialog UI; + + Alert->setupUi(&UI); + + UI.setFont(*menufont); + + deviceUI = &UI; + + Alert->Bells->setChecked(Bells); + Alert->InboundBeep->setChecked(ConnectBeep); + Alert->InactivityBeep->setChecked(AlertBeep); + Alert->Interval->setText(QString::number(AlertInterval)); + Alert->KeywordBeep->setChecked(UseKeywords); + Alert->keywordFile->setText(KeyWordsFile); + + Alert->useBeep->setChecked(useBeep); + Alert->useFiles->setChecked(!useBeep); + + Alert->connectFile->setCurrentText(ConnectWAV); + Alert->bellsFile->setCurrentText(BellWAV); + Alert->intervalFile->setCurrentText(IntervalWAV); + Alert->keywordWAV->setCurrentText(AlertWAV); + + QObject::connect(Alert->chooseInbound, SIGNAL(clicked()), this, SLOT(chooseInboundWAV())); + QObject::connect(Alert->chooseBells, SIGNAL(clicked()), this, SLOT(chooseBellsWAV())); + QObject::connect(Alert->chooseInterval, SIGNAL(clicked()), this, SLOT(chooseIntervalWAV())); + QObject::connect(Alert->chooseKeyAlert, SIGNAL(clicked()), this, SLOT(chooseAlertWAV())); + + QObject::connect(Alert->testBells, SIGNAL(clicked()), this, SLOT(testBellsWAV())); + QObject::connect(Alert->TestInbound, SIGNAL(clicked()), this, SLOT(testInboundWAV())); + QObject::connect(Alert->testInterval, SIGNAL(clicked()), this, SLOT(testIntervalWAV())); + QObject::connect(Alert->TestKeyAlert, SIGNAL(clicked()), this, SLOT(testAlertWAV())); + + QObject::connect(Alert->okButton, SIGNAL(clicked()), this, SLOT(alertAccept())); + QObject::connect(Alert->cancelButton, SIGNAL(clicked()), this, SLOT(alertReject())); + + UI.exec(); +} + + + + + + +void QtTermTCP::chooseInboundWAV() +{ + ConnectWAV = QFileDialog::getOpenFileName(this, + tr("Select Wav"), "", tr("Sound Files (*.wav)")); + + Alert->connectFile->setCurrentText(ConnectWAV); + +} + +void QtTermTCP::chooseBellsWAV() +{ + BellWAV = QFileDialog::getOpenFileName(this, + tr("Select Wav"), "", tr("Sound Files (*.wav)")); + + Alert->bellsFile->setCurrentText(BellWAV); +} + +void QtTermTCP::chooseIntervalWAV() +{ + IntervalWAV = QFileDialog::getOpenFileName(this, + tr("Select Wav"), "", tr("Sound Files (*.wav)")); + + Alert->intervalFile->setCurrentText(IntervalWAV); +} + +void QtTermTCP::chooseAlertWAV() +{ + AlertWAV = QFileDialog::getOpenFileName(this, + tr("Select Wav"), "", tr("Sound Files (*.wav)")); + + Alert->keywordWAV->setCurrentText(AlertWAV); +} + +void QtTermTCP::testInboundWAV() +{ + QSound::play(Alert->connectFile->currentText()); +} + +void QtTermTCP::testBellsWAV() +{ + QSound::play(Alert->bellsFile->currentText()); +} + +void QtTermTCP::testIntervalWAV() +{ + QSound::play(Alert->intervalFile->currentText()); +} + +void QtTermTCP::testAlertWAV() +{ + QSound::play(Alert->keywordWAV->currentText()); +} + + + +void QtTermTCP::alertAccept() +{ + QVariant Q; + + useBeep = Alert->useBeep->isChecked(); + + Bells = Alert->Bells->isChecked(); + ConnectBeep = Alert->InboundBeep->isChecked(); + AlertBeep = Alert->InactivityBeep->isChecked(); + AlertInterval = Alert->Interval->text().toInt(); + + UseKeywords = Alert->KeywordBeep->isChecked(); + KeyWordsFile = Alert->keywordFile->text(); + + ConnectWAV = Alert->connectFile->currentText(); + BellWAV = Alert->bellsFile->currentText(); + IntervalWAV = Alert->intervalFile->currentText(); + AlertWAV = Alert->keywordWAV->currentText(); + + delete(Alert); + SaveSettings(); + deviceUI->accept(); +} + +void QtTermTCP::alertReject() +{ + delete(Alert); + deviceUI->reject(); +} + + + +void QtTermTCP::VARASlot() +{ + // This runs the VARA Configuration dialog + + char valChar[80]; + + Dev = new(Ui_Dialog); + + QDialog UI; + + Dev->setupUi(&UI); + + UI.setFont(*menufont); + + deviceUI = &UI; + + Dev->VARAEnable->setChecked(VARAEnable); + Dev->TermCall->setText(VARATermCall); + + SetVARAParams(); + + connect(Dev->VARAHF, SIGNAL(toggled(bool)), this, SLOT(VARAHFChanged(bool))); + connect(Dev->VARAFM, SIGNAL(toggled(bool)), this, SLOT(VARAFMChanged(bool))); + connect(Dev->VARASAT, SIGNAL(toggled(bool)), this, SLOT(VARASATChanged(bool))); + + if (VARA500) + Dev->VARA500->setChecked(true); + else if (VARA2750) + Dev->VARA2750->setChecked(true); + else + Dev->VARA2300->setChecked(true); + + if (VARAHF) + Dev->VARAHF->setChecked(true); + else if (VARAFM) + Dev->VARAFM->setChecked(true); + else if (VARASAT) + Dev->VARASAT->setChecked(true); + + if (VARAHF == 0) + Dev->HFMode->setVisible(false); + + connect(Dev->CAT, SIGNAL(toggled(bool)), this, SLOT(CATChanged(bool))); + connect(Dev->PTTPort, SIGNAL(currentIndexChanged(int)), this, SLOT(PTTPortChanged(int))); + + if (PTTMode == PTTCAT) + Dev->CAT->setChecked(true); + else + Dev->RTSDTR->setChecked(true); + + if (CATHex) + Dev->CATHex->setChecked(true); + else + Dev->CATText->setChecked(true); + + sprintf(valChar, "%d", pttGPIOPin); + Dev->GPIOLeft->setText(valChar); + sprintf(valChar, "%d", pttGPIOPinR); + Dev->GPIORight->setText(valChar); + + Dev->VIDPID->setText(CM108Addr); + + + QStringList items; + +#ifdef USESERIAL + + for (const QSerialPortInfo &info : Ports) + { + items.append(info.portName()); + } + + items.sort(); + +#endif + + Dev->PTTPort->addItem("None"); + Dev->PTTPort->addItem("CM108"); + +#ifdef __ARM_ARCH + + // Dev->PTTPort->addItem("GPIO"); + +#endif + + Dev->PTTPort->addItem("FLRIG"); + Dev->PTTPort->addItem("HAMLIB"); + + for (const QString &info : items) + { + Dev->PTTPort->addItem(info); + } + + Dev->PTTPort->setCurrentIndex(Dev->PTTPort->findText(PTTPort, Qt::MatchFixedString)); + + PTTPortChanged(0); // Force reevaluation + + QObject::connect(Dev->okButton, SIGNAL(clicked()), this, SLOT(deviceaccept())); + QObject::connect(Dev->cancelButton, SIGNAL(clicked()), this, SLOT(devicereject())); + + UI.exec(); + +} + +extern QProcess *process; + +void ClosePTTPort(); + +void QtTermTCP::deviceaccept() +{ + QVariant Q; + + int OldEnable = VARAEnable; + int OldPort = VARAPortNum; + char oldHost[128]; + char oldPath[256]; + + strcpy(oldHost, VARAHost); + strcpy(oldPath, VARAPath); + + VARAEnable = Dev->VARAEnable->isChecked(); + + strcpy(VARATermCall, Dev->TermCall->text().toUtf8().toUpper()); + + Q = Dev->Port->text(); + + VARAPortNum = Q.toInt(); + strcpy(VARAHost, Dev->Host->text().toUtf8().toUpper()); + strcpy(VARAPath, Dev->Path->text().toUtf8()); + strcpy(VARAInit, Dev->InitCommands->text().toUtf8()); + + VARA500 = Dev->VARA500->isChecked(); + VARA2300 = Dev->VARA2300->isChecked(); + VARA2750 = Dev->VARA2750->isChecked(); + + VARAHF = Dev->VARAHF->isChecked(); + VARAFM = Dev->VARAFM->isChecked(); + VARASAT = Dev->VARASAT->isChecked(); + + if (VARAHF) + { + strcpy(VARAHostHF, VARAHost); + strcpy(VARAPathHF, VARAPath); + VARAPortHF = VARAPortNum; + } + else if (VARAFM) + { + strcpy(VARAHostFM, VARAHost); + strcpy(VARAPathFM, VARAPath); + VARAPortFM = VARAPortNum; + } + else if (VARASAT) + { + strcpy(VARAHostSAT, VARAHost); + strcpy(VARAPathSAT, VARAPath); + VARAPortSAT = VARAPortNum; + } + + Q = Dev->PTTPort->currentText(); + strcpy(PTTPort, Q.toString().toUtf8()); + + if (Dev->CAT->isChecked()) + PTTMode = PTTCAT; + else + PTTMode = PTTRTS; + + if (Dev->CATHex->isChecked()) + CATHex = 1; + else + CATHex = 0; + + Q = Dev->PTTOn->text(); + strcpy(PTTOnString, Q.toString().toUtf8()); + Q = Dev->PTTOff->text(); + strcpy(PTTOffString, Q.toString().toUtf8()); + + Q = Dev->CATSpeed->text(); + PTTBAUD = Q.toInt(); + + Q = Dev->GPIOLeft->text(); + pttGPIOPin = Q.toInt(); + + Q = Dev->GPIORight->text(); + pttGPIOPinR = Q.toInt(); + + Q = Dev->VIDPID->text(); + + if (strcmp(PTTPort, "CM108") == 0) + strcpy(CM108Addr, Q.toString().toUtf8()); + else if (strcmp(PTTPort, "HAMLIB") == 0) + { + HamLibPort = Q.toInt(); + Q = Dev->PTTOn->text(); + strcpy(HamLibHost, Q.toString().toUtf8()); + } + + if (VARAEnable != OldEnable || VARAPortNum != OldPort || strcmp(oldHost, VARAHost) != 0) + { + // (re)start connection + + if (OldEnable && VARASock && VARASock->ConnectedState == QAbstractSocket::ConnectedState) + { + VARASock->disconnectFromHost(); + if (VARADataSock) + VARADataSock->disconnectFromHost(); + Status2->setText("VARA Disconnected"); + } + } + + if (process && process->state() == QProcess::Running) + if ((VARAEnable == 0 || strcmp(oldPath, VARAPath) != 0)) + process->close(); + + myStatusBar->setVisible(AGWEnable | VARAEnable | KISSEnable); + + ClosePTTPort(); + OpenPTTPort(); + + delete(Dev); + SaveSettings(); + deviceUI->accept(); + + QSize newSize(this->size()); + QSize oldSize(this->size()); + + QResizeEvent *myResizeEvent = new QResizeEvent(newSize, oldSize); + + QCoreApplication::postEvent(this, myResizeEvent); +} + +void QtTermTCP::devicereject() +{ + delete(Dev); + deviceUI->reject(); +} + +// This handles incoming connections + +void QtTermTCP::onNewConnection() +{ + myTcpSocket *clientSocket = (myTcpSocket *)_server->nextPendingConnection(); + + clientSocket->Sess = NULL; + + Ui_ListenSession * S; + Ui_ListenSession * Sess = NULL; + + char Title[512]; + int i = 0; + + QByteArray Host = clientSocket->peerAddress().toString().toUtf8(); + + if (TermMode == MDI) + { + // See if an old session can be reused + + for (int i = 0; i < _sessions.size(); ++i) + { + S = _sessions.at(i); + + // for (Ui_ListenSession * S: _sessions) + // { + if ((S->SessionType & Listen) && S->clientSocket == NULL) + { + Sess = S; + break; + } + } + + // Create a window if none found, else reuse old + + if (Sess == NULL) + { + Sess = newWindow(this, Listen); + } + + QByteArray Host = clientSocket->peerAddress().toString().toUtf8(); + } + else + { + // Single or Tabbed - look for free session + + for (i = 0; i < _sessions.size(); ++i) + { + S = _sessions.at(i); + + if (S->clientSocket == NULL && S->AGWSession == NULL && S->AGWMonSession == NULL && S->KISSSession == NULL) + { + Sess = S; + break; + } + } + + if (Sess == NULL) + { + // Clear connection + + clientSocket->disconnectFromHost(); + return; + } + } + + _sockets.push_back(clientSocket); + + clientSocket->Sess = Sess; + + // See if any data from host - first msg should be callsign + + clientSocket->waitForReadyRead(1000); + + QByteArray datas = clientSocket->readAll(); + + datas.chop(2); + datas.truncate(10); // Just in case! + + datas.append('\0'); + + sprintf(Title, "Inward Connect from %s:%d Call " + datas, + Host.data(), clientSocket->peerPort()); + + if (TermMode == MDI) + { + Sess->setWindowTitle(Title); + } + else if (TermMode == Tabbed) + { + tabWidget->setTabText(i, datas.data()); + tabWidget->tabBar()->setTabTextColor(i, newTabText); + } + + else if (TermMode == Single) + this->setWindowTitle(Title); + + connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyRead())); + connect(clientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); + + Sess->clientSocket = clientSocket; + + // We need to set Connect and Disconnect if the window is active + + if (TermMode == MDI && Sess->sw == ActiveSubWindow) + setMenus(true); + + if (TermMode == Tabbed && Sess->Tab == tabWidget->currentIndex()) + setMenus(true); + + if (TermMode == Single) + setMenus(true); // Single + + // Send CText if defined + + if (listenCText[0]) + Sess->clientSocket->write(listenCText); + + // Send Message to Terminal + + char Msg[80]; + + sprintf(Msg, "Listen Connect from %s\r\r", datas.data()); + + WritetoOutputWindow(Sess, (unsigned char *)Msg, (int)strlen(Msg)); + + if (ConnectBeep) + myBeep(&ConnectWAV); + + QApplication::alert(mythis, 0); +} + +void QtTermTCP::onSocketStateChanged(QAbstractSocket::SocketState socketState) +{ + myTcpSocket* sender = static_cast(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 +} + + +void CM108_set_ptt(int PTTState) +{ + unsigned char io[5]; + int n; + + io[0] = 0; + io[1] = 0; + io[2] = 1 << (3 - 1); + io[3] = PTTState << (3 - 1); + io[4] = 0; + + if (CM108Device == NULL) + return; + +#ifdef WIN32 + hid_device *handle; + + handle = hid_open_path(CM108Device); + + if (!handle) { + printf("unable to open device\n"); + return; + } + + n = hid_write(handle, io, 5); + if (n < 0) + { + printf("Unable to write()\n"); + printf("Error: %ls\n", hid_error(handle)); + } + + hid_close(handle); + +#else + + int fd; + + fd = open(CM108Device, O_WRONLY); + + if (fd == -1) + { + printf("Could not open %s for write, errno=%d\n", CM108Device, errno); + return; + } + + io[0] = 0; + io[1] = 0; + io[2] = 1 << (3 - 1); + io[3] = PTTState << (3 - 1); + io[4] = 0; + + n = write(fd, io, 5); + if (n != 5) + { + printf("Write to %s failed, n=%d, errno=%d\n", CM108Device, n, errno); + } + + close(fd); +#endif + return; + +} + + + +void QtTermTCP::RadioPTT(bool PTTState) +{ +#ifdef __ARM_ARCH + if (useGPIO) + { + // gpioWrite(pttGPIOPin, (pttGPIOInvert ? (1 - PTTState) : (PTTState))); + // return; + } + +#endif + + if ((PTTMode & PTTCM108)) + { + CM108_set_ptt(PTTState); + return; + } + + if ((PTTMode & PTTHAMLIB)) + { + HAMLIBSetPTT(PTTState); + return; + } + + if ((PTTMode & PTTFLRIG)) + { + FLRigSetPTT(PTTState); + return; + } + +#ifdef USESERIAL + + if (hPTTDevice == 0) + return; + + if ((PTTMode & PTTCAT)) + { + if (PTTState) + hPTTDevice->write((char *)PTTOnCmd, PTTOnCmdLen); + else + hPTTDevice->write((char *)PTTOffCmd, PTTOffCmdLen); + + hPTTDevice->flush(); + // hPTTDevice->error(); + return; + + } + + + if ((PTTMode & PTTRTS)) + { + int n = hPTTDevice->setRequestToSend(PTTState); + n = n; + } + +#endif + +} + + + +extern "C" void WriteDebugLog(char * Mess) +{ + qDebug() << Mess; +} + +void QtTermTCP::ConnecttoKISS() +{ + if (strcmp(SerialPort, "TCP") == 0) + { + delete(KISSSock); + + KISSSock = new myTcpSocket(); + KISSSockCopy[0] = (void *)KISSSock; + + + connect(KISSSock, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(KISSdisplayError(QAbstractSocket::SocketError))); + connect(KISSSock, SIGNAL(readyRead()), this, SLOT(KISSreadyRead())); + connect(KISSSock, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onKISSSocketStateChanged(QAbstractSocket::SocketState))); + + KISSSock->connectToHost(KISSHost, KISSPortNum); + + Status3->setText("KISS Connecting"); + } + else + openSerialPort(); + + return; +} + + +void QtTermTCP::KISSTimer() +{ + // Runs every 10 Seconds + + if (KISSConnected == 0 && KISSConnecting == 0) + { + ConnecttoKISS(); + } + else + { + // Verify Serial port is still ok + + if (m_serial && KISSConnected) + { + m_serial->clearError(); + boolean rc = m_serial->isDataTerminalReady(); + + if (m_serial->error()) + { + Debugprintf("Serial Port Lost - isOpen %d Error %d", m_serial->isOpen(), m_serial->error()); + closeSerialPort(); + } + } + } +} + + + +void QtTermTCP::KISSdisplayError(QAbstractSocket::SocketError socketError) +{ + switch (socketError) + { + case QAbstractSocket::RemoteHostClosedError: + break; + + case QAbstractSocket::HostNotFoundError: + QMessageBox::information(this, tr("QtTermTCP"), + tr("KISS host was not found. Please check the " + "host name and portsettings->")); + + Status3->setText("KISS Connection Failed"); + + break; + + case QAbstractSocket::ConnectionRefusedError: + + Status3->setText("KISS Connection Refused"); + break; + + default: + + Status3->setText("KISS Connection Failed"); + } + + KISSConnecting = 0; + KISSConnected = 0; +} + + +extern "C" void KISSSendtoServer(myTcpSocket* Socket, char * Data, int Length) +{ + if (m_serial) + { + if (m_serial->isOpen()) + { + m_serial->clearError(); + + int n = m_serial->write(Data, Length); + + n = m_serial->flush(); + + if (m_serial->error()) + { + Debugprintf("Serial Flush Error - Requested = %d Actual %d Error %d", Length, n, m_serial->error()); + closeSerialPort(); + } + } + } + else if (Socket) + Socket->write(Data, Length); +} + + + +void QtTermTCP::KISSreadyRead() +{ + int Read; + unsigned char Buffer[4096]; myTcpSocket* Socket = static_cast(QObject::sender()); + + // read the data from the socket + + Read = Socket->read((char *)Buffer, 4095); + + KISSDataReceived(Socket, Buffer, Read); + +} + +extern "C" void KISS_del_socket(void * socket); +extern "C" void KISS_add_stream(void * Socket); + +void QtTermTCP::onKISSSocketStateChanged(QAbstractSocket::SocketState socketState) +{ + // myTcpSocket* sender = static_cast(QObject::sender()); + + QTcpSocket* sender = static_cast(QObject::sender()); + + if (socketState == QAbstractSocket::UnconnectedState) + { + // Close any connections + + Ui_ListenSession * Sess = NULL; + + Status3->setText("KISS Disconnected"); + actHost[18]->setEnabled(0); + + KISSConnecting = KISSConnected = 0; + + // Free the monitor Window + + if (KISSMonSess) + { + Sess = KISSMonSess; + + if (TermMode == MDI) + Sess->setWindowTitle("Monitor Session Disconnected"); + + else if (TermMode == Tabbed) + tabWidget->setTabText(Sess->Tab, "Monitor"); + + KISSMonSess = nullptr; + } + + KISS_del_socket(sender); + KISSSock = NULL; + } + else if (socketState == QAbstractSocket::ConnectedState) + { + int i; + + KISSConnected = 1; + KISSConnecting = 0; + + Status3->setText("KISS Connected"); + actHost[18]->setEnabled(1); // Enable KISS Connect Line + + KISS_add_stream(sender); + + // Attach a Monitor Window if available + + Ui_ListenSession * Sess = NULL; + Ui_ListenSession * S; + + if (TermMode == MDI) + { + // See if an old session can be reused + + for (int i = 0; i < _sessions.size(); ++i) + { + S = _sessions.at(i); + + // for (Ui_ListenSession * S: _sessions) + // { + if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) + { + Sess = S; + break; + } + } + + // Create a window if none found, else reuse old + + if (Sess == NULL) + { + Sess = newWindow((QObject *)mythis, Mon, ""); + } + } + else if (TermMode == Tabbed) + { + // Tabbed - look for free session + + for (i = 8; i; i--) + { + S = _sessions.at(i); + + if (S->clientSocket == NULL && S->KISSSession == NULL && S->AGWSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) + { + Sess = S; + break; + } + } + } + else if (TermMode == Single && (singlemodeFormat & Mon)) + { + S = _sessions.at(0); + + if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL && (AGWUsers == NULL || (S != AGWUsers->MonSess)) && S != KISSMonSess) + Sess = S; + + } + + if (Sess) + { + KISSMonSess = Sess; // Flag as in use + + if (TermMode == MDI) + Sess->setWindowTitle("KISS Monitor Window"); + else if (TermMode == Tabbed) + tabWidget->setTabText(Sess->Tab, "KISS Mon"); + else if (TermMode == Single) + mythis->setWindowTitle("KISS Monitor Window"); + + Sess->mlocaltime = KISSLocalTime; + Sess->MonitorNODES = KISSMonNodes; + + // if (TermMode == Single) + // { + // discAction->setEnabled(false); + // YAPPSend->setEnabled(false); + // connectMenu->setEnabled(false); + // } + } + } +} + + +extern "C" char * frame_monitor(string * frame, char * code, bool tx_stat); +extern "C" char * ShortDateTime(); + +extern "C" void monitor_frame(int snd_ch, string * frame, char * code, int tx, int excluded) +{ + UNUSED(excluded); + UNUSED(snd_ch); + + int Len; + char Msg[1024]; + + if (tx) + sprintf(Msg, "\x1b\x10%s", frame_monitor(frame, code, tx)); + else + sprintf(Msg, "\x1b\x11%s", frame_monitor(frame, code, tx)); + + Len = strlen(Msg); + + if (Len < 10) // Suppressed NODES + return; + + if (Msg[Len - 1] != '\r') + { + Msg[Len++] = '\r'; + Msg[Len] = 0; + } + + if (KISSMonSess) + WritetoMonWindow(KISSMonSess, (unsigned char *)Msg, Len); + +} + +extern "C" Ui_ListenSession * ax25IncomingConnect(TAX25Port * AX25Sess) +{ + // Look for/create Terminal Window for connection + + Ui_ListenSession * Sess = NULL; + Ui_ListenSession * S; + char Title[80]; + int i = 0; + + if (TermMode == MDI) + { + // See if an old session can be reused + + for (int i = 0; i < _sessions.size(); ++i) + { + S = _sessions.at(i); + + if ((S->SessionType & Listen) && S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) + { + Sess = S; + break; + } + } + + // Create a window if none found, else reuse old + + if (Sess == NULL) + { + Sess = newWindow((QObject *)mythis, Listen, ""); + } + } + else + { + // Single or Tabbed - look for free session + + + for (i = 0; i < _sessions.size(); ++i) + { + S = _sessions.at(i); + + if (S->clientSocket == NULL && S->AGWSession == NULL && S->KISSSession == NULL) + { + Sess = S; + break; + } + } + + if (Sess == NULL) + { + // Clear connection + + return NULL; + } + } + + if (Sess) + { + sprintf(Title, "Connected to %s", AX25Sess->corrcall); + + if (TermMode == MDI) + { + Sess->setWindowTitle(Title); + } + else if (TermMode == Tabbed) + { + tabWidget->setTabText(i, AX25Sess->corrcall); + tabWidget->tabBar()->setTabTextColor(i, newTabText); + } + else if (TermMode == Single) + mythis->setWindowTitle(Title); + + AX25Sess->port = 0; + AX25Sess->Sess = Sess; // Crosslink KISS and Term Sessions + AX25Sess->PID = 240;; + + Sess->KISSSession = AX25Sess; + + setMenus(true); + + if (ConnectBeep) + myBeep(&ConnectWAV); + + QApplication::alert(mythis, 0); + + // Send CText if defined + + if (listenCText[0]) + SendtoAX25(Sess->KISSSession, (unsigned char *)listenCText, (int)strlen(listenCText)); + } + return Sess; +} + + +extern "C" void AX25_disc(TAX25Port * AX25Sess, Byte mode) +{ + char Msg[128]; + int Len = 0; + Ui_ListenSession * Sess = (Ui_ListenSession *)AX25Sess->Sess; + + if (AX25Sess->status == STAT_TRY_LINK) + { + // Connect failed + + Len = sprintf(Msg, "Connection to %s failed\r", AX25Sess->corrcall); + } + else + { + switch (mode) + { + case MODE_OTHER: + case MODE_OUR: + + Len = sprintf(Msg, "Disconnected from %s\r", AX25Sess->corrcall); + break; + + case MODE_RETRY: + + Len = sprintf(Msg, "Disconnected from %s - Retry count exceeded\r", AX25Sess->corrcall); + break; + + }; + } + + SendtoTerm(Sess, Msg, Len); + ClearSessLabel(Sess); + Sess->KISSSession = NULL; + AX25Sess->Sess = 0; + + setMenus(0); +}; + +int QtTermTCP::openSerialPort() +{ + if (m_serial && m_serial->isOpen()) + { + m_serial->close(); + } + + m_serial = nullptr; + m_serial = new QSerialPort(this); + + m_serial->setPortName(SerialPort); + boolean ok = m_serial->setBaudRate(KISSBAUD); + + if (m_serial->open(QIODevice::ReadWrite)) + { + int i; + + ok = m_serial->setRequestToSend(true); + + connect(m_serial, &QSerialPort::readyRead, this, &QtTermTCP::readSerialData); + // connect(m_serial, &QSerialPort::errorOccurred, this, &QtTermTCP::handleError); + + KISSConnected = 1; + KISSConnecting = 0; + + Status3->setText("KISS Connected"); + actHost[18]->setEnabled(1); // Enable KISS Connect Line + + KISS_add_stream(m_serial); + + // Attach a Monitor Window if available + + Ui_ListenSession * Sess = NULL; + Ui_ListenSession * S; + + if (TermMode == MDI) + { + // See if an old session can be reused + + for (int i = 0; i < _sessions.size(); ++i) + { + S = _sessions.at(i); + + // for (Ui_ListenSession * S: _sessions) + // { + if ((S->SessionType == Mon) && S->clientSocket == NULL && S->KISSSession == NULL) + { + Sess = S; + break; + } + } + + // Create a window if none found, else reuse old + + if (Sess == NULL) + { + Sess = newWindow((QObject *)mythis, Mon, ""); + } + } + else if (TermMode == Tabbed) + { + // Tabbed - look for free session + + for (i = 8; i; i--) + { + S = _sessions.at(i); + + if (S->clientSocket == NULL && S->KISSSession == NULL) + { + Sess = S; + break; + } + } + } + else if (TermMode == Single && (singlemodeFormat & Mon)) + { + S = _sessions.at(0); + + if (S->clientSocket == NULL && S->KISSSession == NULL) + Sess = S; + + } + + if (Sess) + { + KISSMonSess = Sess; // Flag as in use + + if (TermMode == MDI) + Sess->setWindowTitle("KISS Monitor Window"); + else if (TermMode == Tabbed) + tabWidget->setTabText(Sess->Tab, "KISS Mon"); + else if (TermMode == Single) + mythis->setWindowTitle("KISS Monitor Window"); + + // if (TermMode == Single) + // { + // discAction->setEnabled(false); + // YAPPSend->setEnabled(false); + // connectMenu->setEnabled(false); + // } + } + + + + return 1; + } + else + { + Status3->setText("KISS Open Failed"); + KISSConnected = 0; + KISSConnecting = 0; + return 0; + } +} + + + +void closeSerialPort() +{ + if (m_serial && m_serial->isOpen()) + { + m_serial->close(); + m_serial = nullptr; + } + + m_serial = nullptr; + + KISSConnected = 0; + KISSConnecting = 0; + + Status3->setText("KISS Closed"); + actHost[18]->setEnabled(0); // Enable KISS Connect Line +} + +void QtTermTCP::readSerialData() +{ + int Read; + unsigned char Buffer[8192]; + + // read the data from the socket + + m_serial->clearError(); + + Read = m_serial->read((char *)Buffer, 2047); + + if (m_serial->error()) + { + Debugprintf("Serial Read Error - RC %d Error %d", Read, m_serial->error()); + closeSerialPort(); + return; + } + + + while (Read > 0) + { + KISSDataReceived(m_serial, Buffer, Read); + Read = m_serial->read((char *)Buffer, 2047); + } +} + +void QtTermTCP::handleError(QSerialPort::SerialPortError serialPortError) +{ + Debugprintf("Serial port Error %d", serialPortError); + closeSerialPort(); +} + +extern "C" void CheckUIFrame(unsigned char * path, string * data) +{ + // If we have KISS enabled and dest is UIDEST look for a KISS window in UI Mode + + if (KISSSock == 0) + return; + + char Dest[10]; + char From[10]; + + Dest[ConvFromAX25(path, Dest)] = 0; + From[ConvFromAX25(&path[7], From)] = 0; + + // ok, Find a Kiss Session with this Dest + + Ui_ListenSession * Sess = NULL; + + for (int i = 0; i < _sessions.size(); ++i) + { + Sess = _sessions.at(i); + + if (Sess->KISSMode == 1 && strcmp(Dest, Sess->UIDEST) == 0) + { + char Msg[512]; + int Len; + + data->Data[data->Length] = 0; + + Len = sprintf(Msg, "%s:%s", From, data->Data); + SendtoTerm(Sess, Msg, Len); + return; + } + } + +} + + +QColor QtTermTCP::setColor(QColor Colour) +{ + // const QColorDialog::ColorDialogOptions options = QFlag(colorDialogOptionsWidget->value()); + + + QColor col = Colour; + + QColorDialog dialog; + dialog.setCurrentColor(Colour); + dialog.setOption(QColorDialog::DontUseNativeDialog); + + if (dialog.exec() == QColorDialog::Accepted) + col = QVariant(dialog.currentColor()).toString(); + + + // const QColor color = QColorDialog::getColor(Qt::green, this, "Select Color", 0); + + return col; +} + +// Experimental Viewdata/Teletext/Prestel/CEEFAX Mode + +// Uses ideas and some code from + +/*************************************************************** + * Name: wxTEDMain.cpp + * Purpose: Teletext editor Application Frame + * Author: Peter Kwan (peterk.vt80@gmail.com) + * Created: 2014-10-30 + * Copyright: Peter Kwan + * License: + * + * Copyright (C) 2014-2022, Peter Kwan + * + * Permission to use, copy, modify, and distribute this software + * and its documentation for any purpose and without fee is hereby + * granted, provided that the above copyright notice appear in all + * copies and that both that the copyright notice and this + * permission notice and warranty disclaimer appear in supporting + * documentation, and that the name of the author not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * + * The author disclaims all warranties with regard to this + * software, including all implied warranties of merchantability + * and fitness. In no event shall the author be liable for any + * special, indirect or consequential damages or any damages + * whatsoever resulting from loss of use, data or profits, whether + * in an action of contract, negligence or other tortious action, + * arising out of or in connection with the use or performance of + * this software. + *************************************************************************** **/ + + + +int FontWidth = 16; +int FontHeight = 16; + +bool isMosaic(char ch) +{ + ch &= 0x7f; + return (ch >= 0x20 && ch < 0x40) || ch >= 0x60; +} + + +void DecodeTeleText(Ui_ListenSession * Sess, char * page) +{ + + // redraw the whole teletext page + + QColor fg = Qt::white; + QColor bg = Qt::black; + QColor holdColour; + QColor holdfg = fg; // Colour for held graphic + int usehold = 0; + int sep = 0; + + QPainter p(Sess->TTBitmap); + + QSettings settings(GetConfPath(), QSettings::IniFormat); + + //p.setFont(QFont("Courier", 14, QFont::Bold)); + + p.setFont(QFont(settings.value("FontFamily", "Courier New").value(), 14)); + + p.setPen(QPen(fg)); + + bool graphicsMode = false; + bool separated = false; + bool doubleHeight = false; + int skipnextrow = 99; + bool flashing = false; + bool hold = false; + char holdChar = 0; + char holdMode = 0; + Sess->timer.stop(); + + bool concealed = false; + char c; + + fg = Qt::white; + bg = Qt::black; + + char * ptr = page; + + int col = 0; + int line = 0; + + // XXXXXXXXTEEFAX %%# %%a %d %%b C %H:%M.%S + + //p.drawText(0, 19, "P199 HAMFAX"); + + + // interpret data, for now, line by line + + + while ((c = *(ptr++))) + { + char ch = c; + + if (c == 0x11) // Curson On ?? + continue; + + if (c == 0x14) // Curson Off ?? + continue; + + if (c == 9) // Curson On ?? + { + col++; + continue; + } + + if (c == 0x0a) + { + line++; + +// if (doubleHeight) +// line++; + + if (line > 24) + line = 0; + + continue; + } + + if (c == 0x1e) // Cursor Home + { + line = col = 0; + c = 13; // So we reset page flags below + } + + if (c == 12) + { + // Clear the page + + Sess->TTBitmap->fill(Qt::black); + Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); + + line = col = 0; + + c = 13; // So we reset page flags below + } + + if (c == 13) + { + col = 0; + + graphicsMode = false; + separated = false; + doubleHeight = false; + flashing = false; + hold = false; + holdChar = 0; + concealed = false; + + fg = Qt::white; + bg = Qt::black; + + continue; // Next line + } + + if (c == 0x1b) // Esc + { + // I think the control char is displayed as it was before being actioned, sa save current state + + holdfg = holdColour; // Colour if using held - may be changed before displaying + usehold = hold; // May be changed + sep = holdMode; + + char echar = *(ptr++); + + if (echar == 0) + { + // Esc pair spilt - wait for rest + + Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); + return; + } + + switch (echar) + { + case '@': + fg = Qt::black; + concealed = false; // Side effect of colour. It cancels a conceal. + graphicsMode = false; +// hold = false; + + break; + case 'A': + fg = Qt::red; + concealed = false; + graphicsMode = false; + hold = false; + + break; + case 'B': + fg = Qt::green; + concealed = false; + graphicsMode = false; + hold = false; + break; + case 'C': + fg = Qt::yellow; + concealed = false; + graphicsMode = false; + hold = false; + break; + case 'D': + fg = Qt::blue; + concealed = false; + graphicsMode = false; + hold = false; + break; + case 'E': + fg = Qt::magenta; + concealed = false; + graphicsMode = false; + hold = false; + break; + case 'F': + fg = Qt::cyan; + concealed = false; + graphicsMode = false; + hold = false; + break; + case 'G': + fg = Qt::white; + concealed = false; + graphicsMode = false; + hold = false; + break; + case 'H': // Flash + flashing = true; + Sess->timer.start(1000, Sess); + concealed = false; + graphicsMode = false; + hold = false; + + break; + + case 'I': // Steady + flashing = false; + concealed = false; + graphicsMode = false; + hold = false; + + break; + // + case 'J': //ttxCodeEndBox: + case 'K': //ttxCodeStartBox: + + concealed = false; + graphicsMode = false; + hold = false; + + break; + case 'L': // Normal height + doubleHeight = false; + hold = false; + break; + + case 'M': // Double height + doubleHeight = true; + skipnextrow = line + 1; // ETSI: row to ignore + hold = false; + holdChar = 0; + break; + case 'P': // Graphics black +// concealed = false; + graphicsMode = true; + holdColour = fg = Qt::black; + + break; + case 'Q': // Graphics red +// concealed = false; + graphicsMode = true; + holdColour = fg = Qt::red; + + break; + case 'R': // Graphics green +// concealed = false; + graphicsMode = true; + holdColour = fg = Qt::green; + + break; + case 'S': // Graphics yellow +// concealed = false; + graphicsMode = true; + holdColour = fg = Qt::yellow; + + break; + case 'T': // Graphics blue +// concealed = false; + graphicsMode = true; + holdColour = fg = Qt::blue; + + break; + case 'U': // Graphics magenta +// concealed = false; + graphicsMode = true; + holdColour = fg = Qt::magenta; + + break; + case 'V': // Graphics cyan +// concealed = false; + graphicsMode = true; + holdColour = fg = Qt::cyan; + + break; + case 'W': // Graphics white +// concealed = false; + graphicsMode = true; + holdColour = fg = Qt::white; + + break; + + case 'X': // Conceal display + + concealed = 1; + break; + + case 'Y': // Contiguous graphics + + separated = false; + break; + + case 'Z': // Separated gfx + + separated = true; + break; + + case 0x5c: // Background black + bg = Qt::black; + break; + + case 0x5d: // New background + + bg = fg; + break; + + case 0x5e: // Hold gfx + + if (hold == 0) + { + hold = true; + holdColour = fg; + holdMode = separated; + } + break; + + case 0x5f: // Non-hold gfx + hold = false; + break; + + default: + echar++; // For testign + break; + + } //end of esc case processing + + if (usehold) + { + // We set sep and color for held char earlier + + ch = holdChar; // Repeat held char + } + else + ch = 0x0; // Default is space + + + if (line > skipnextrow) + skipnextrow = 99; + + if (line == skipnextrow) + { + line = line; + } + else + { + if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) + { + p.fillRect(col * 15, line * 19, 15, 19, bg); + + // if double height also draw background for next row + + if (doubleHeight) + p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); + + + if (sep) + { + if (ch & 1) + p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, holdfg); + if (ch & 2) + p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, holdfg); + if (ch & 4) + p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, holdfg); + if (ch & 8) + p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, holdfg); + if (ch & 16) + p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, holdfg); + if (ch & 32) + p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, holdfg); + + } + else + { + if (ch & 1) + p.fillRect(col * 15, line * 19, 7, 6, holdfg); + if (ch & 2) + p.fillRect(col * 15 + 7, line * 19, 8, 6, holdfg); + if (ch & 4) + p.fillRect(col * 15, line * 19 + 6, 7, 6, holdfg); + if (ch & 8) + p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, holdfg); + if (ch & 16) + p.fillRect(col * 15, line * 19 + 12, 7, 7, holdfg); + if (ch & 32) + p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, holdfg); + } + } + } + col++; + } + else + { + // Not esc - so normal or graphics + + if (ch < 0x20) + continue; + + if (line > skipnextrow) + skipnextrow = 99; + + if (line == skipnextrow) + { + line = line; + } + else + { + if (concealed == 0 && (flashing == 0 || Sess->TTFlashToggle == 0)) + { + p.fillRect(col * 15, line * 19, 15, 19, bg); + + if (doubleHeight) + p.fillRect(col * 15, line * 19 + 19, 15, 19, bg); + + p.setPen(QPen(fg));; + + if (graphicsMode) + { + if (ch < 0x40) + ch -= 0x20; + else + if (ch >= 0x60) + ch -= 0x40; + else + goto isText; + + holdChar = ch; + + // Now have 00 - 3f + + + // C is bit mask bit posns are + // 01 + // 23 + // 45 + // Char cell is 15 * 19 which is a bit asymetrical + + // Chars are 20 - 3f and 60 to 7f but I cant see a logic to the mapping + + + if (separated) + { + if (ch & 1) + p.fillRect(col * 15 + 2, line * 19 + 2, 5, 4, fg); + if (ch & 2) + p.fillRect(col * 15 + 9, line * 19 + 2, 6, 4, fg); + if (ch & 4) + p.fillRect(col * 15 + 2, line * 19 + 8, 5, 4, fg); + if (ch & 8) + p.fillRect(col * 15 + 9, line * 19 + 8, 6, 4, fg); + if (ch & 16) + p.fillRect(col * 15 + 2, line * 19 + 14, 5, 5, fg); + if (ch & 32) + p.fillRect(col * 15 + 9, line * 19 + 14, 6, 5, fg); + + } + else + { + if (ch & 1) + p.fillRect(col * 15, line * 19, 7, 6, fg); + if (ch & 2) + p.fillRect(col * 15 + 7, line * 19, 8, 6, fg); + if (ch & 4) + p.fillRect(col * 15, line * 19 + 6, 7, 6, fg); + if (ch & 8) + p.fillRect(col * 15 + 7, line * 19 + 6, 8, 6, fg); + if (ch & 16) + p.fillRect(col * 15, line * 19 + 12, 7, 7, fg); + if (ch & 32) + p.fillRect(col * 15 + 7, line * 19 + 12, 8, 7, fg); + } + } + else + { + // Just write char at current col and line + + isText: + char s[5]; + unsigned char su[5] = ""; + + // Some chars are in wrong char set + + su[0] = ch; + + if (ch == '_') + su[0] = '#'; + + else if (ch == 0x7e) // division + { + su[0] = 0xC3; + su[1] = 0xB7; + } + else if (ch == 0x5e) // up arrow + { + su[0] = 0xF0; + su[1] = 0x9F; + su[2] = 0xA0; + su[3] = 0x95; + } + else if (ch == 0x7f) // up arrow + { + su[0] = 0xE2; + su[1] = 0x96; + su[2] = 0x88; + } + + memcpy(s, su, 5); + +// if (doubleHeight) + // p.drawText(col * 15, line * 19 + 25, s); + // else + // p.drawText(col * 15, line * 19 + 15, s); + + // if double height draw normally then copy pixels each row of pixels to two scanlines (starting at the bottom) + + if (doubleHeight) + { + int inscanline = line * 19 + 18; + int outscanline = line * 19 + 35; + unsigned char * inptr = Sess->TTBitmap->scanLine(inscanline); + unsigned char * outptr = Sess->TTBitmap->scanLine(outscanline); + int linelen = Sess->TTBitmap->bytesPerLine(); + int charlen = linelen / 40; // bytes per char position + + p.drawText(col * 15, line * 19 + 16, s); + + inptr += col * charlen; + outptr += col * charlen; + + for (int i = 0; i < 18; i++) + { + memcpy(outptr, inptr, charlen); + outptr -= linelen; + memcpy(outptr, inptr, charlen); + + inptr -= linelen; + outptr -= linelen; + + } + } + else + p.drawText(col * 15, line * 19 + 15, s); + + } + } + } + col++; + } + + if (col > 39) + { + col = 0; + line++; + if (line > 24) + line = 0; + + graphicsMode = false; + separated = false; + doubleHeight = false; + flashing = false; + hold = false; + holdChar = 0; + concealed = false; + + fg = Qt::white; + bg = Qt::black; + } + } + Sess->TTLabel->setPixmap(QPixmap::fromImage(*Sess->TTBitmap)); + return; + + QFile file("D:/savepage.txt"); + file.open(QIODevice::WriteOnly); + file.write(Sess->pageBuffer); + file.close(); +} + + +void Ui_ListenSession::timerEvent(QTimerEvent *event) +{ + Ui_ListenSession * Sess = NULL; + + // Used for flashing - resfresh window + + for (int i = 0; i < _sessions.size(); ++i) + { + Sess = _sessions.at(i); + + if (Sess->timer.timerId() == event->timerId()) + { + if (Sess->TTActive) + { + Sess->TTFlashToggle ^= 1; + + // if in Tabbed mode only refresh active tab + + if (TermMode == Tabbed && Sess != ActiveSession) + return; + + DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end + } + else + Sess->timer.stop(); + + return; + } + } + QWidget::timerEvent(event); +} + +// Monitor Log FIle routines + +char * doXMLTransparency(char * string) +{ + // Make sure string doesn't contain forbidden XML chars (<>"'&) + + char * newstring = (char *)malloc(5 * strlen(string) + 1); // If len is zero still need null terminator + + char * in = string; + char * out = newstring; + char c; + + c = *(in++); + + while (c) + { + switch (c) + { + case '<': + + strcpy(out, "<"); + out += 4; + break; + + case '>': + + strcpy(out, ">"); + out += 4; + break; + + case '"': + + strcpy(out, """); + out += 6; + break; + + case '\'': + + strcpy(out, "'"); + out += 6; + break; + + case '&': + + strcpy(out, "&"); + out += 5; + break; + + default: + + *(out++) = c; + } + c = *(in++); + } + + *(out++) = 0; + return newstring; +} + +void WriteMonitorLog(Ui_ListenSession * Sess, char * Msg) +{ + // Write as HTML to preserve formatting + + char Line[512]; + char * HTMLText; + + if (Sess->monLogfile == nullptr) + { + QString FN = "QTTermMonLog" + timeLoaded + "_" + QString::number(Sess->sessNo) + ".html"; + Sess->monLogfile = new QFile(FN); + + if (Sess->monLogfile) + Sess->monLogfile->open(QIODevice::WriteOnly | QIODevice::Text); + else + return; + } + + if (Msg[0] == 0x1b) + { + // Colour Escape + + if (Msg[1] == 17) + Sess->monSpan = (char *)"";// , 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); + +} + diff --git a/QtTermTCP.h b/QtTermTCP.h index 89e1524..7f477c3 100644 --- a/QtTermTCP.h +++ b/QtTermTCP.h @@ -1,280 +1,310 @@ -#pragma once - -#include -#include "ui_QtTermTCP.h" -//#include "ui_AGWParams.h" -//#include "ui_AGWConnect.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 - -#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[1024]; // 32 ports 32 Bytes - unsigned long long portmask; - int mtxparam; - int mcomparam; - int monUI; - int MonitorNODES; - int MonitorColour; - int CurrentHost; - int Tab; // Tab Index if Tabbed Mode - void * AGWSession; // Terinal sess - Need to cast to TAGWPort to use it - void * AGWMonSession; - void * KISSSession; - int KISSMode; // Connected or UI - char UIDEST[32]; - char UIPATH[128]; - - // For Teletext Emulator - - QImage * TTBitmap; // TT Image buffer - QDialog TTUI; - - int TTActive; - int TTFlashToggle; - char pageBuffer[4096]; - QBasicTimer timer; - -protected: - - void timerEvent(QTimerEvent *event) override; - -private: - - - -private slots: - -}; - - -class QtTermTCP : public QMainWindow -{ - Q_OBJECT - -public: - QtTermTCP(QWidget *parent = NULL); - void closeEvent(QCloseEvent * event); - static void setFonts(); - ~QtTermTCP(); - -private slots: - void Disconnect(); - void doYAPPSend(); - void doYAPPSetRX(); - void menuChecked(); - void Connect(); - void displayError(QAbstractSocket::SocketError socketError); - void readyRead(); - - void LreturnPressed(Ui_ListenSession * LUI); - void LDisconnect(Ui_ListenSession * LUI); - void SetupHosts(); - void MyTimerSlot(); - void KISSTimerSlot(); - void ListenSlot(); - void AGWSlot(); - 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 *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(); - 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); -} - - -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 + 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 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); diff --git a/QtTermTCP.icns b/QtTermTCP.icns new file mode 100644 index 0000000..07d4345 Binary files /dev/null and b/QtTermTCP.icns differ diff --git a/QtTermTCP.ini b/QtTermTCP.ini deleted file mode 100644 index 9d58bbb..0000000 --- a/QtTermTCP.ini +++ /dev/null @@ -1,121 +0,0 @@ -[General] -HostParams0=nottm.g8bpq.net|8011|gm8bpq|password|5 1 1 0 1 0 0 1\r|Pogo4 -geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\xea\0\0\0\xaf\0\0\x3\xf6\0\0\x3h\0\0\0\xea\0\0\0\xaf\0\0\x3\xf6\0\0\x3h\0\0\0\0\0\0\0\0\a\x80\0\0\0\xea\0\0\0\xaf\0\0\x3\xf6\0\0\x3h) -HostParams1=192.168.1.63|8011|john|password||Pogo2 -windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\0\0\0\x3\r\0\0\x2\x8c\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\x1\0\0\0\x3\0\0\0\x1\0\0\0\x16\0m\0\x61\0i\0n\0T\0o\0o\0l\0\x62\0\x61\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0) -HostParams2=127.0.0.1|8011|gm8bpq|password|c000000100000000 1 1 0 1 0 0 1\r| -HostParams3=192.168.1.131|8011|john|password|1 1 1 0 1 0 0 1\r|Slack -HostParams4=127.0.0.1|8021|john|password|c000000100000006 1 1 0 1 0 0 1\r|LinBPQ -HostParams5=192.168.1.18|8011|john|password|c00000010000002e 1 1 0 1 0 0 1\r| -HostParams6=|0|||| -HostParams7=|0|||| -HostParams8=|0|||| -HostParams9=|0|||| -HostParams10=|0|||| -HostParams11=|0|||| -HostParams12=|0|||| -HostParams13=|0|||| -HostParams14=|0|||| -HostParams15=|0|||| -Split=41 -ChatMode=1 -AutoTeletext=1 -Bells=1 -StripLF=1 -AlertBeep=1 -ConnectBeep=1 -CurrentHost=0 -YAPPPath= -listenPort=8015 -listenEnable=1 -listenCText=[PMS-2.3-C]\rHello>\r -convUTF8=0 -PTT=None -PTTBAUD=0 -PTTMode=1 -CATHex=1 -PTTOffString= -PTTOnString= -pttGPIOPin=17 -pttGPIOPinR=17 -CM108Addr=0xD8C:0x08 -HamLibPort=4532 -HamLibHost=127.0.0.1 -FLRigPort=12345 -FLRigHost=127.0.0.1 -AGWEnable=0 -AGWMonEnable=1 -AGWTermCall=G8BPQ -AGWBeaconDest= -AGWBeaconPath= -AGWBeaconInterval=0 -AGWBeaconPorts= -AGWBeaconText= -AGWHost=127.0.0.1 -AGWPort=8001 -AGWPaclen=80 -AGWToCalls=G8BPQ-2, SWITCH, -KISSEnable=0 -MYCALL=GM8BPQ -KISSHost=127.0.0.1 -KISSMode=0 -KISSPort=8110 -KISSSerialPort=TCP -KISSBAUD=19200 -VARAEnable=0 -VARATermCall=G8BPQ -VARAHost=127.0.0.1 -VARAPort=8310 -VARAPath=C:\\VARA\\VARA.exe -VARAHostHF=127.0.0.1 -VARAPortHF=8310 -VARAPathHF=C:\\VARA\\VARA.exe -VARAHostFM=127.0.0.1 -VARAPortFM=8300 -VARAPathFM=C:\\VARA\\VARAFM.exe -VARAHostSAT=127.0.0.1 -VARAPortSAT=8300 -VARAPathSAT=C:\\VARA\\VARASAT.exe -VARA500=0 -VARA2300=1 -VARA2750=0 -VARAHF=1 -VARAFM=0 -VARASAT=0 -TabType=1 3 1 1 1 1 1 2 2 0 -monBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) -monRxText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\xff\xff\0\0) -monTxText=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\0\0\0\0\0\0) -monOtherText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) -termBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) -outputText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\xff\xff\0\0) -EchoText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) -WarningText=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\0\0\0\0\0\0) -inputBackground=@Variant(\0\0\0\x43\x1\xff\xff\xff\xff\xff\xff\xff\xff\0\0) -inputText=@Variant(\0\0\0\x43\x1\xff\xff\0\0\0\0\0\0\0\0) -TermMode=2 -singlemodeFormat=3 -FontFamily=Courier -PointSize=10 -Weight=50 -Sessions="1|1, 17, 40, 205, 625, 990|" -VARAInit="P2P SESSION,WINLINK SESSION" - -[AX25_A] -Retries=10 -Maxframe=4 -Paclen=128 -FrackTime=8 -IdleTime=180 -SlotTime=100 -Persist=128 -RespTime=1500 -TXFrmMode=1 -FrameCollector=6 -ExcludeCallsigns= -ExcludeAPRSFrmType= -KISSOptimization=0 -DynamicFrack=0 -BitRecovery=0 -IPOLL=80 -MyDigiCall= diff --git a/QtTermTCP.pro b/QtTermTCP.pro index da12fb3..aeb5e0b 100644 --- a/QtTermTCP.pro +++ b/QtTermTCP.pro @@ -3,6 +3,7 @@ QT += core gui QT += network QT += widgets QT += serialport +QT += multimedia TARGET = QtTermTCP @@ -40,7 +41,9 @@ FORMS += QtTermTCP.ui\ VARAConfig.ui \ KISSConfig.ui \ ColourConfig.ui \ - AGWConnect.ui + YAPPRxSize.ui \ + AGWConnect.ui \ + AlertSetup.ui RESOURCES += QtTermTCP.qrc diff --git a/QtTermTCP.pro.user b/QtTermTCP.pro.user index 4e70805..4bbf667 100644 --- a/QtTermTCP.pro.user +++ b/QtTermTCP.pro.user @@ -1,357 +1,357 @@ - - - - - - EnvironmentId - {49a2cf38-2251-47e3-97df-4ecaa9d41931} - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - true - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - UTF-8 - false - 4 - false - 80 - true - true - 1 - true - false - 0 - true - true - 0 - 8 - true - 1 - true - true - true - *.md, *.MD, Makefile - false - true - - - - ProjectExplorer.Project.PluginSettings - - - true - true - true - true - true - - - 0 - true - - -fno-delayed-template-parsing - - true - Builtin.Questionable - - true - Builtin.DefaultTidyAndClazy - 3 - - - - true - - - - - ProjectExplorer.Project.Target.0 - - Desktop - Desktop Qt 5.14.2 MSVC2015 64bit - Desktop Qt 5.14.2 MSVC2015 64bit - qt.qt5.5142.win64_msvc2015_64_kit - 0 - 0 - 0 - - true - 0 - C:\Users\John\OneDrive\Dev\Source\QT\build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Debug - C:/Users/John/OneDrive/Dev/Source/QT/build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Debug - - - true - QtProjectManager.QMakeBuildStep - - false - - - - true - Qt4ProjectManager.MakeStep - - false - - - false - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - - true - clean - - false - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - - Debug - Qt4ProjectManager.Qt4BuildConfiguration - 2 - 2 - 2 - - - true - 2 - C:\Users\John\OneDrive\Dev\Source\QT\build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Release - C:/Users/John/OneDrive/Dev/Source/QT/build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Release - - - true - QtProjectManager.QMakeBuildStep - - false - - - - true - Qt4ProjectManager.MakeStep - - false - - - false - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - - true - clean - - false - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - - Release - Qt4ProjectManager.Qt4BuildConfiguration - 0 - 0 - 2 - - - true - 0 - C:\Users\John\OneDrive\Dev\Source\QT\build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Profile - C:/Users/John/OneDrive/Dev/Source/QT/build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Profile - - - true - QtProjectManager.QMakeBuildStep - - false - - - - true - Qt4ProjectManager.MakeStep - - false - - - false - - 2 - Build - Build - ProjectExplorer.BuildSteps.Build - - - - true - Qt4ProjectManager.MakeStep - - true - clean - - false - - 1 - Clean - Clean - ProjectExplorer.BuildSteps.Clean - - 2 - false - - - Profile - Qt4ProjectManager.Qt4BuildConfiguration - 0 - 0 - 0 - - 3 - - - 0 - Deploy - Deploy - ProjectExplorer.BuildSteps.Deploy - - 1 - - false - ProjectExplorer.DefaultDeployConfiguration - - 1 - - - dwarf - - cpu-cycles - - - 250 - - -e - cpu-cycles - --call-graph - dwarf,4096 - -F - 250 - - -F - true - 4096 - false - false - 1000 - - true - - false - false - false - false - true - 0.01 - 10 - true - kcachegrind - 1 - 25 - - 1 - true - false - true - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - - 2 - - Qt4ProjectManager.Qt4RunConfiguration:C:/Users/John/OneDrive/Dev/Source/QT/QtTermTCP/QtTermTCP.pro - C:/Users/John/OneDrive/Dev/Source/QT/QtTermTCP/QtTermTCP.pro - - false - - false - true - true - false - false - true - - C:/Users/John/OneDrive/Dev/Source/QT/build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Debug - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.FileVersion - 22 - - - Version - 22 - - + + + + + + EnvironmentId + {49a2cf38-2251-47e3-97df-4ecaa9d41931} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + *.md, *.MD, Makefile + false + true + + + + ProjectExplorer.Project.PluginSettings + + + true + true + true + true + true + + + 0 + true + + -fno-delayed-template-parsing + + true + Builtin.Questionable + + true + Builtin.DefaultTidyAndClazy + 3 + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 5.14.2 MSVC2015 64bit + Desktop Qt 5.14.2 MSVC2015 64bit + qt.qt5.5142.win64_msvc2015_64_kit + 0 + 0 + 0 + + true + 0 + C:\Users\John\OneDrive\Dev\Source\QT\build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Debug + C:/Users/John/OneDrive/Dev/Source/QT/build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Debug + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Debug + Qt4ProjectManager.Qt4BuildConfiguration + 2 + 2 + 2 + + + true + 2 + C:\Users\John\OneDrive\Dev\Source\QT\build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Release + C:/Users/John/OneDrive/Dev/Source/QT/build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Release + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Release + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 2 + + + true + 0 + C:\Users\John\OneDrive\Dev\Source\QT\build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Profile + C:/Users/John/OneDrive/Dev/Source/QT/build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Profile + + + true + QtProjectManager.QMakeBuildStep + + false + + + + true + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Build + Build + ProjectExplorer.BuildSteps.Build + + + + true + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Clean + Clean + ProjectExplorer.BuildSteps.Clean + + 2 + false + + + Profile + Qt4ProjectManager.Qt4BuildConfiguration + 0 + 0 + 0 + + 3 + + + 0 + Deploy + Deploy + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + dwarf + + cpu-cycles + + + 250 + + -e + cpu-cycles + --call-graph + dwarf,4096 + -F + 250 + + -F + true + 4096 + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + kcachegrind + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + + 2 + + Qt4ProjectManager.Qt4RunConfiguration:C:/Users/John/OneDrive/Dev/Source/QT/QtTermTCP/QtTermTCP.pro + C:/Users/John/OneDrive/Dev/Source/QT/QtTermTCP/QtTermTCP.pro + + false + + false + true + true + false + false + true + + C:/Users/John/OneDrive/Dev/Source/QT/build-QtTermTCP-Desktop_Qt_5_14_2_MSVC2015_64bit-Debug + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/QtTermTCP.qrc b/QtTermTCP.qrc index 1e71b3b..78dc32c 100644 --- a/QtTermTCP.qrc +++ b/QtTermTCP.qrc @@ -1,5 +1,10 @@ - - - QtTermTCP.ico - + + + 250x600Hz.wav + 250x1000Hz.wav + ding.wav + PCBeep.wav + Ring.wav + QtTermTCP.ico + diff --git a/QtTermTCP.sln b/QtTermTCP.sln index 01fdba7..8aa1110 100644 --- a/QtTermTCP.sln +++ b/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 diff --git a/QtTermTCP.ui b/QtTermTCP.ui index a2bfd8c..163ac9a 100644 --- a/QtTermTCP.ui +++ b/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 + + + + + + + + + diff --git a/QtTermTCP.vcxproj b/QtTermTCP.vcxproj index e47863b..506de1f 100644 --- a/QtTermTCP.vcxproj +++ b/QtTermTCP.vcxproj @@ -1,461 +1,463 @@ - - - - - Debug - x64 - - - Release - Win32 - - - Debug - Win32 - - - Release - x64 - - - - {14F3B24E-473C-324E-A99D-3B679FCF5F67} - QtTermTCP - QtVS_v304 - 10.0.19041.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 - - - 5.14.2_msvc2017 - core;network;gui;widgets;serialport - - - 5.14.2 - core;network;gui;widgets;serialport - - - 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 + + + 5.14.2_msvc2017 + core;network;gui;widgets;serialport + + + 5.14.2 + core;network;gui;widgets;serialport + + + 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;C:\Qt\Qt5.14.2\5.14.2\msvc2017\lib\Qt5Multimedia.lib;%(AdditionalDependencies) + C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) + -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + 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:\Qt\Qt5.14.2\5.14.2\msvc2017\lib\Qt5Multimediad.lib + C:\opensslx86\lib;C:\Utils\my_sql\mysql-5.7.25-win32\lib;C:\Utils\postgresqlx86\pgsql\lib;%(AdditionalLibraryDirectories) + -no-pie "/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions) + true + 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 diff --git a/QtTermTCP.vcxproj.filters b/QtTermTCP.vcxproj.filters index 5347f44..1737602 100644 --- a/QtTermTCP.vcxproj.filters +++ b/QtTermTCP.vcxproj.filters @@ -1,131 +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; - - - {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 - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - - - Generated Files - - - Generated 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 diff --git a/QtTermTCP.vcxproj.user b/QtTermTCP.vcxproj.user index a562388..c34359b 100644 --- a/QtTermTCP.vcxproj.user +++ b/QtTermTCP.vcxproj.user @@ -1,22 +1,29 @@ - - - - - 2022-05-19T07:28:47.9186341Z - - - 2022-05-19T07:28:58.9302359Z - - - 2023-04-12T13:14:53.1644359Z - - - 2023-02-08T10:47:28.1396474Z - - - 2023-03-06T08:27:08.3742630Z - - - 2023-02-08T10:47:27.7430420Z - + + + + $(APPDATA) + WindowsLocalDebugger + + + ..\..\..\..\..\DevProgs\BPQ32 + WindowsLocalDebugger + + + 2022-05-19T07:28:47.9186341Z + + + 2022-05-19T07:28:58.9302359Z + + + 2023-10-14T13:14:56.5532991Z + + + 2023-10-14T13:14:56.7231497Z + + + 2023-10-14T13:14:55.9367569Z + + + 2023-10-14T13:14:56.2561805Z + \ No newline at end of file diff --git a/QtTermTCP52.zip b/QtTermTCP52.zip deleted file mode 100644 index e36d5dc..0000000 Binary files a/QtTermTCP52.zip and /dev/null differ diff --git a/Ring.wav b/Ring.wav new file mode 100644 index 0000000..ea59863 Binary files /dev/null and b/Ring.wav differ diff --git a/TCPHostConfig.ui b/TCPHostConfig.ui index e4b706b..94367ac 100644 --- a/TCPHostConfig.ui +++ b/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 + + + + + diff --git a/TabDialog.cpp b/TabDialog.cpp index 2e2d665..98d3ed9 100644 --- a/TabDialog.cpp +++ b/TabDialog.cpp @@ -1,1166 +1,1182 @@ - -#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 MYCALL[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 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 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, 250, 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); - - 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); - - 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[32]; - char Via[128]; - strcpy(CallTo, wCallTo->currentText().toUpper().toUtf8()); - strcpy(Via, Digis->text().toUpper().toUtf8()); - - TAX25Port * AX25Sess = 0; - - // Check for duplicate session - - AX25Sess = get_user_port_by_calls(0, MYCALL, 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", MYCALL, 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, MYCALL, CallTo, Via, 0, (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, Via); - - 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 MYCALL[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 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, 250, 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); + + 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); + + 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[32]; + char Via[128]; + strcpy(CallTo, wCallTo->currentText().toUpper().toUtf8()); + strcpy(Via, Digis->text().toUpper().toUtf8()); + + TAX25Port * AX25Sess = 0; + + // Check for duplicate session + + AX25Sess = get_user_port_by_calls(0, MYCALL, 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", MYCALL, 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, MYCALL, CallTo, Via, 0, (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, Via); + + 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(); +} diff --git a/TabDialog.h b/TabDialog.h index a7ac986..cd21067 100644 --- a/TabDialog.h +++ b/TabDialog.h @@ -1,208 +1,208 @@ - -#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; - 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; + 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; +}; + + + + diff --git a/TermTCPCommon.cpp b/TermTCPCommon.cpp index 78464a0..0c20d35 100644 --- a/TermTCPCommon.cpp +++ b/TermTCPCommon.cpp @@ -1,1144 +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 LogMonitor = FALSE; -int LogOutput = FALSE; -int SendDisconnected = TRUE; -int ChatMode = TRUE; -int AutoTeletext = 1; - -int MonPorts = 1; -int ListenOn = FALSE; - -time_t LastWrite = 0xffffffff; -int AlertInterval = 300; -int AlertBeep = TRUE; -int AlertFreq = 600; -int AlertDuration = 250; -TCHAR AlertFileName[256] = { 0 }; -int ConnectBeep = TRUE; -int UseKeywords = TRUE; - -char KeyWordsName[MAX_PATH] = "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; -} - -int CheckKeyWord(char * Word, char * Msg) -{ - char * ptr1 = Msg, *ptr2; - int len = (int)strlen(Word); - - while (*ptr1) // Stop at end - { - ptr2 = strstr(ptr1, Word); - - if (ptr2 == NULL) - return FALSE; // OK - - // Only bad if it ia not part of a longer word - - if ((ptr2 == Msg) || !(isalpha(*(ptr2 - 1)))) // No alpha before - if (!(isalpha(*(ptr2 + len)))) // No alpha after - return TRUE; // Bad word - - // Keep searching - - ptr1 = ptr2 + len; - } - - return FALSE; // OK -} - -int CheckKeyWords(UCHAR * Msg, int len) -{ - char dupMsg[2048]; - int i; - - if (UseKeywords == 0 || NumberofKeyWords == 0) - return FALSE; - - memcpy(dupMsg, Msg, len); - dupMsg[len] = 0; - //_strlwr(dupMsg); - - for (i = 1; i <= NumberofKeyWords; i++) - { - if (CheckKeyWord(KeyWords[i], dupMsg)) - { -// Beep(660, 250); - return TRUE; // Alert - } - } - - return FALSE; // OK - -} - - -void ProcessReceivedData(Ui_ListenSession * Sess, unsigned char * Buffer, int len) -{ - int MonLen = 0; - unsigned char * ptr; - unsigned char * Buffptr; - unsigned char * FEptr = 0; - - if (Sess->InputMode == 'Y') // Yapp - { - ProcessYAPPMessage(Sess, Buffer, len); - return; - } - - // See if Teletext data - - // We need to identify a viewdata frame. Seems to start - - //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........ - //00000170 0a 0a 0a 0a 0a 0a 0a 0a 11 0c 1b - - // Page seems to start 1c - - // After page get - - //1e 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a 0a ........ ........ - // 0000049D 0a 0a 0a 0a 0a 0a 0a 0a 11 14 1b 44 1b 5d 1b 43 ........ ...D.].C - // 000004AD 53 65 6c 65 Sele - // 000004B1 63 74 20 69 74 65 6d 20 6f 72 1b 47 2a 70 61 67 ct item or .G*pag - // 000004C1 65 5f 20 3a 20 20 20 20 20 20 20 20 20 20 20 20 e_ : - // 000004D1 20 0d 09 09 09 09 09 09 09 09 09 09 09 09 09 09 ....... ........ - // 000004E1 09 09 09 09 09 09 09 09 09 09 09 09 09 11 - - Buffer[len] = 0; - - if (AutoTeletext && (Buffer[0] == 0x1e || Buffer[0] == 0x0c)) - { - if (Sess->TTActive == 0) - { - Sess->TTActive = 1; - DoTermResize(Sess); - } - } - - if (Sess->TTActive) - { - // Feed to Teletext code - - // We need to decode a whole page. There is no obvious delimiter so process till data stops. - // Buffer is cleared when next input is sent - - if (strlen(&Sess->pageBuffer[0] + len) > 4090) - Sess->pageBuffer[0] = 0; // Protect buffer - - strcat(Sess->pageBuffer, (char *)Buffer); - - DecodeTeleText(Sess, (char *)Sess->pageBuffer); // Re-decode same data until we get the end - return; - } - - - - // mbstowcs(Buffer, BufferB, len); - - // Look for MON delimiters (FF/FE) - - - Buffptr = Buffer; - - if (Sess->MonData) - { - // Already in MON State - - FEptr = (UCHAR *)memchr(Buffptr, 0xfe, len); - - if (!FEptr) - { - // no FE - so send all to monitor - - WritetoMonWindow(Sess, Buffer, len); - return; - } - - Sess->MonData = FALSE; - - MonLen = FEptr - Buffptr; // Mon Data, Excluding the FE - - WritetoMonWindow(Sess, Buffptr, MonLen); - - Buffptr = ++FEptr; // Char following FE - - if (++MonLen < len) - { - len -= MonLen; - goto MonLoop; // See if next in MON or Data - } - - // Nothing Left - - return; - } - -MonLoop: - - ptr = (UCHAR *)memchr(Buffptr, 0xff, len); - - if (ptr) - { - unsigned char telcmd[] = "\xff\xfb\x03\xff\xfb\x01"; - - // Try to trap connect to normal Telnet Port - - if (memcmp(ptr, telcmd, 6) == 0) - return; - - // Buffer contains Mon Data - - if (ptr > Buffptr) - { - // Some Normal Data before the FF - - int NormLen = ptr - Buffptr; // Before the FF - - if (NormLen == 1 && Buffptr[0] == 0) - { - // Keepalive - } - - else - { - CheckKeyWords(Buffptr, NormLen); - WritetoOutputWindow(Sess, Buffptr, NormLen); - } - - len -= NormLen; - Buffptr = ptr; - goto MonLoop; - } - - if (ptr[1] == 0xff) - { - // Port Definition String - - int NumberofPorts = atoi((char *)&ptr[2]); - char *p, *Context; - int i = 1; - TCHAR msg[80]; - int portnum; - char delim[] = "|"; - int m; - - // Save for changes of Window - - if (len < 1024) - memcpy(Sess->PortMonString, ptr, len); - - - // Remove old menu - - for (i = 0; i < 33; 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 = 33; - - 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 tome to be sent - QueueMsg(Sess, Mess, Mess[1] + 2); - - len = sprintf((char *)Buffer, "YAPP File %s size %d larger than limit %d\r", ARQFilename, FileSize, MaxRXSize); - WritetoOutputWindow(Sess, Buffer, len); - - Sess->InputMode = 0; - SendTraceOptions(Sess); - - return Len; - } - - // Check that Path is set - - if (YAPPPath[0] == 0) - { - Mess[0] = NAK; - Mess[1] = sprintf(&Mess[2], "%s", "YAPP Receive directory not set"); - mySleep(1000); // To give YAPP Msg time to be sent - QueueMsg(Sess, Mess, Mess[1] + 2); - len = sprintf((char *)Buffer, "YAPP File Receive Failed - YAPP Receive directory not set\r"); - WritetoOutputWindow(Sess, Buffer, len); - - Sess->InputMode = 0; - SendTraceOptions(Sess); - - return Len; - } - - // Make sure file does not exist - - sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename); - - if (stat(MsgFile, &STAT) == 0) - { - FileSize = STAT.st_size; - - Mess[0] = NAK; - Mess[1] = sprintf(&Mess[2], "%s", "File Already Exists"); - mySleep(1000); // To give YAPP Msg time to be sent - QueueMsg(Sess, Mess, Mess[1] + 2); - len = sprintf((char *)Buffer, "YAPP File Receive Failed - %s already exists\r", MsgFile); - WritetoOutputWindow(Sess, Buffer, len); - - Sess->InputMode = 0; - SendTraceOptions(Sess); - - return Len; - } - - - MailBufferSize = FileSize; - MailBuffer = (UCHAR *)malloc(FileSize); - YAPPLen = 0; - - if (YAPPDate) // If present use YAPPC - Reply[1] = ACK; //Receive_TPK - else - Reply[1] = 2; //Rcv_File - - QueueMsg(Sess, Reply, 2); - - len = sprintf((char *)Buffer, "YAPP Receving File %s size %d\r", ARQFilename, FileSize); - WritetoOutputWindow(Sess, Buffer, len); - - return Len; - - case STX: - - // Data Packet - - // Check we have it all - - if (YAPPDate) // If present use YAPPC so have checksum - { - if (pktLen > (Len - 3)) // -2 for header and checksum - return 0; // Wait for rest - } - else - { - if (pktLen > (Len - 2)) // -2 for header - return 0; // Wait for rest - } - - // Save data and remove from buffer - - // if YAPPC check checksum - - if (YAPPDate) - { - UCHAR Sum = 0; - int i; - UCHAR * uptr = &Msg[2]; - - i = pktLen; - - while (i--) - Sum += *(uptr++); - - if (Sum != *uptr) - { - // Checksum Error - - Mess[0] = CAN; - Mess[1] = sprintf(&Mess[2], "YAPPC Checksum Error"); - QueueMsg(Sess, Mess, Mess[1] + 2); - - len = sprintf((char *)Buffer, "YAPPC Checksum Error on file %s\r", MsgFile); - WritetoOutputWindow(Sess, Buffer, len); - - Sess->InputMode = 0; - SendTraceOptions(Sess); - return Len; - } - } - - if ((YAPPLen) + pktLen > MailBufferSize) - { - // Too Big ?? - - Mess[0] = CAN; - Mess[1] = sprintf(&Mess[2], "YAPP Too much data received"); - QueueMsg(Sess, Mess, Mess[1] + 2); - - len = sprintf((char *)Buffer, "YAPP Too much data received on file %s\r", MsgFile); - WritetoOutputWindow(Sess, Buffer, len); - - Sess->InputMode = 0; - SendTraceOptions(Sess); - return Len; - } - - - memcpy(&MailBuffer[YAPPLen], &Msg[2], pktLen); - YAPPLen += pktLen; - - if (YAPPDate) - ++pktLen; // Add Checksum - -// if (YAPPLen == MailBufferSize) -// pktLen = pktLen; - - return pktLen + 2; - - case ETX: - - // End Data - - if (YAPPLen == MailBufferSize) - { - // All received - - int Written = 0; - - sprintf(MsgFile, "%s/%s", YAPPPath, ARQFilename); - - hFile = fopen(MsgFile, "wb"); - - if (hFile) - { - Written = (int)fwrite(MailBuffer, 1, YAPPLen, hFile); - fclose(hFile); - - if (YAPPDate) - { -// struct tm TM; -// struct timeval times[2]; - /* - The MS-DOS date. The date is a packed value with the following format. - - cant use DosDateTimeToFileTime on Linux - - Bits Description - 0-4 Day of the month (1–31) - 5-8 Month (1 = January, 2 = February, and so on) - 9-15 Year offset from 1980 (add 1980 to get actual year) - wFatTime - The MS-DOS time. The time is a packed value with the following format. - Bits Description - 0-4 Second divided by 2 - 5-10 Minute (0–59) - 11-15 Hour (0–23 on a 24-hour clock) - */ - /* - - memset(&TM, 0, sizeof(TM)); - - TM.tm_sec = (YAPPDate & 0x1f) << 1; - TM.tm_min = ((YAPPDate >> 5) & 0x3f); - TM.tm_hour = ((YAPPDate >> 11) & 0x1f); - - TM.tm_mday = ((YAPPDate >> 16) & 0x1f); - TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1; - TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80; - - Debugprintf("%d %d %d %d %d %d", TM.tm_year, TM.tm_mon, TM.tm_mday, TM.tm_hour, TM.tm_min, TM.tm_sec); - - times[0].tv_sec = times[1].tv_sec = mktime(&TM); - times[0].tv_usec = times[1].tv_usec = 0; - */ - } - } - - - free(MailBuffer); - MailBufferSize = 0; - MailBuffer = 0; - - if (Written != YAPPLen) - { - Mess[0] = CAN; - Mess[1] = sprintf(&Mess[2], "Failed to save YAPP File"); - QueueMsg(Sess, Mess, Mess[1] + 2); - - len = sprintf((char *)Buffer, "Failed to save YAPP File %s\r", MsgFile); - WritetoOutputWindow(Sess, Buffer, len); - - Sess->InputMode = 0; - SendTraceOptions(Sess); - } - } - - Reply[1] = 3; //Ack_EOF - QueueMsg(Sess, Reply, 2); - - len = sprintf((char *)Buffer, "Reception of file %s complete\r", MsgFile); - WritetoOutputWindow(Sess, Buffer, len); - - return Len; - - case EOT: - - // End Session - - Reply[1] = 4; // Ack_EOT - QueueMsg(Sess, Reply, 2); - SocketFlush(Sess); - Sess->InputMode = 0; - - SendTraceOptions(Sess); - return Len; - - case CAN: - - // Abort - - Mess[0] = ACK; - Mess[1] = 5; // CAN Ack - QueueMsg(Sess, Mess, 2); - - if (MailBuffer) - { - free(MailBuffer); - MailBufferSize = 0; - MailBuffer = 0; - } - - // May have an error message - - len = Msg[1]; - - if (len) - { - len = sprintf((char *)Buffer, "YAPP Transfer cancelled - %s\r", &Msg[2]); - } - else - len = sprintf(Mess, "YAPP Transfer cancelled\r"); - - Sess->InputMode = 0; - SendTraceOptions(Sess); - - return Len; - - case ACK: - - switch (Msg[1]) - { - char * ptr; - - case 1: // Rcv_Rdy - - // HD Send_Hdr SOH len (Filename) NUL (File Size in ASCII) NUL (Opt) - - // Remote only needs filename so remove path - - ptr = ARQFilename; - - while (strchr(ptr, '/')) - ptr = strchr(ptr, '/') + 1; - - len = (int)strlen(ptr) + 3; - - strcpy(&Mess[2], ptr); - len += sprintf(&Mess[len], "%d", MailBufferSize); - len++; // include null -// len += sprintf(&Mess[len], "%8X", YAPPDate); -// len++; // include null - Mess[0] = SOH; - Mess[1] = len - 2; - - QueueMsg(Sess, Mess, len); - - return Len; - - case 2: - - YAPPDate = 0; // Switch to Normal (No Checksum) Mode - - case 6: // Send using YAPPC - - // Start sending message - - YAPPSendData(Sess); - return Len; - - case 3: - - // ACK EOF - Send EOT - - Mess[0] = EOT; - Mess[1] = 1; - QueueMsg(Sess, Mess, 2); - - return Len; - - case 4: - - // ACK EOT - - Sess->InputMode = 0; - SendTraceOptions(Sess); - - len = sprintf((char *)Buffer, "File transfer complete\r"); - WritetoOutputWindow(Sess, Buffer, len); - - - return Len; - - default: - return Len; - - } - - case NAK: - - // Either Reject or Restart - - // RE Resume NAK len R NULL (File size in ASCII) NULL - - if (Len > 2 && Msg[2] == 'R' && Msg[3] == 0) - { - int posn = atoi((char *)&Msg[4]); - - YAPPLen += posn; - MailBufferSize -= posn; - - YAPPSendData(Sess); - return Len; - - } - - // May have an error message - - len = Msg[1]; - - if (len) - { - char ws[256]; - - Msg[len + 2] = 0; - - strcpy(ws, (char *)&Msg[2]); - - len = sprintf((char *)Buffer, "File rejected - %s\r", ws); - } - else - len = sprintf((char *)Buffer, "File rejected\r"); - - WritetoOutputWindow(Sess, Buffer, len); - - - Sess->InputMode = 0; - SendTraceOptions(Sess); - - return Len; - - } - - len = sprintf((char *)Buffer, "Unexpected message during YAPP Transfer. Transfer cancelled\r"); - WritetoOutputWindow(Sess, Buffer, len); - - Sess->InputMode = 0; - SendTraceOptions(Sess); - - return Len; - -} - -void YAPPSendFile(Ui_ListenSession * Sess, WCHAR * FN) -{ - int FileSize = 0; - char MsgFile[MAX_PATH]; - FILE * hFile; - struct stat STAT; - UCHAR Buffer[2000]; - int Len; - - strcpy(MsgFile, FN); - - if (MsgFile[0] == 0) - { - Len = sprintf((char *)Buffer, "Filename missing\r"); - WritetoOutputWindow(Sess, Buffer, Len); - - SendTraceOptions(Sess); - - return; - } - - if (stat(MsgFile, &STAT) != -1) - { - FileSize = STAT.st_size; - - hFile = fopen(MsgFile, "rb"); - - if (hFile) - { - char Mess[255]; -// time_t UnixTime = STAT.st_mtime; - -// FILETIME ft; -// long long ll; -// SYSTEMTIME st; -// WORD FatDate; -// WORD FatTime; -// struct tm TM; - - strcpy(ARQFilename, MsgFile); - - if (MailBuffer) - { - free(MailBuffer); - MailBufferSize = 0; - MailBuffer = 0; - } - - MailBuffer = (UCHAR *)malloc(FileSize); - MailBufferSize = FileSize; - YAPPLen = 0; - fread(MailBuffer, 1, FileSize, hFile); - - // Get Date and Time for YAPPC Mode - -/* The MS-DOS date. The date is a packed value with the following format. - - cant use DosDateTimeToFileTime on Linux - - Bits Description - 0-4 Day of the month (1–31) - 5-8 Month (1 = January, 2 = February, and so on) - 9-15 Year offset from 1980 (add 1980 to get actual year) - wFatTime - The MS-DOS time. The time is a packed value with the following format. - Bits Description - 0-4 Second divided by 2 - 5-10 Minute (0–59) - 11-15 Hour (0–23 on a 24-hour clock) - - memset(&TM, 0, sizeof(TM)); - - TM.tm_sec = (YAPPDate & 0x1f) << 1; - TM.tm_min = ((YAPPDate >> 5) & 0x3f); - TM.tm_hour = ((YAPPDate >> 11) & 0x1f); - - TM.tm_mday = ((YAPPDate >> 16) & 0x1f); - TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1; - TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80; - - -// Note that LONGLONG is a 64-bit value - - ll = Int32x32To64(UnixTime, 10000000) + 116444736000000000; - ft.dwLowDateTime = (DWORD)ll; - ll >>= 32; - ft.dwHighDateTime = (DWORD)ll; - - FileTimeToSystemTime(&ft, &st); - FileTimeToDosDateTime(&ft, &FatDate, &FatTime); - - YAPPDate = (FatDate << 16) + FatTime; - - memset(&TM, 0, sizeof(TM)); - - TM.tm_sec = (YAPPDate & 0x1f) << 1; - TM.tm_min = ((YAPPDate >> 5) & 0x3f); - TM.tm_hour = ((YAPPDate >> 11) & 0x1f); - - TM.tm_mday = ((YAPPDate >> 16) & 0x1f); - TM.tm_mon = ((YAPPDate >> 21) & 0xf) - 1; - TM.tm_year = ((YAPPDate >> 25) & 0x7f) + 80; -*/ - fclose(hFile); - - Mess[0] = ENQ; - Mess[1] = 1; - - QueueMsg(Sess, Mess, 2); - Sess->InputMode = 'Y'; - - Len = sprintf((char *)Buffer, "Sending File %s ...\r", FN); - WritetoOutputWindow(Sess, Buffer, Len); - - return; - } - } - - Len = sprintf((char *)Buffer, "File %s not found\r", FN); - WritetoOutputWindow(Sess, Buffer, Len); - -} - -void YAPPSendData(Ui_ListenSession * Sess) -{ - char Mess[258]; - - while (1) - { - int Left = MailBufferSize; - - if (Left == 0) - { - // Finished - send End Data - - Mess[0] = ETX; - Mess[1] = 1; - - QueueMsg(Sess, Mess, 2); - - break; - } - - if (Left > paclen - 3) // two bytes header and possible checksum - Left = paclen - 3; - - memcpy(&Mess[2], &MailBuffer[YAPPLen], Left); - - YAPPLen += Left; - MailBufferSize -= Left; - - // if YAPPC add checksum - - if (YAPPDate) - { - UCHAR Sum = 0; - int i; - UCHAR * uptr = (UCHAR *)&Mess[2]; - - i = Left; - - while (i--) - Sum += *(uptr++); - - *(uptr) = Sum; - - Mess[0] = STX; - Mess[1] = Left; - - QueueMsg(Sess, Mess, Left + 3); - } - else - { - Mess[0] = STX; - Mess[1] = Left; - - QueueMsg(Sess, Mess, Left + 2); - } - } -} - +#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); + } + } +} + diff --git a/UZ7HOUtils.c b/UZ7HOUtils.c index 839bb64..1477a8f 100644 --- a/UZ7HOUtils.c +++ b/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 diff --git a/VARA.ui b/VARA.ui index c5e4506..7e436e4 100644 --- a/VARA.ui +++ b/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 + + + + + diff --git a/VARAConfig.ui b/VARAConfig.ui index c4baacd..6ce7d9f 100644 --- a/VARAConfig.ui +++ b/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 + + + + + + + + + + + + + diff --git a/TeleText.ui b/YAPPRxSize.ui similarity index 74% rename from TeleText.ui rename to YAPPRxSize.ui index f3b5797..70c2ac3 100644 --- a/TeleText.ui +++ b/YAPPRxSize.ui @@ -1,106 +1,116 @@ - - - TeleTextDialog - - - - 0 - 0 - 665 - 551 - - - - Dialog - - - - - 224 - 516 - 153 - 31 - - - - - 6 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - OK - - - - - - - Cancel - - - - - - - - - 28 - 20 - 600 - 475 - - - - TextLabel - - - - - - - okButton - clicked() - TeleTextDialog - accept() - - - 278 - 253 - - - 96 - 254 - - - - - cancelButton - clicked() - TeleTextDialog - 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 + + + + + diff --git a/ax25.c b/ax25.c index c379b0a..f212148 100644 --- a/ax25.c +++ b/ax25.c @@ -1,2987 +1,3006 @@ -/* -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" -#include - -#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); - -/* - -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 }; - -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, "Incomming 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, 70); - - 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 (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(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(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) -{ - Byte * 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 ProcessKISSFrame(void * socket, UCHAR * Msg, int Len) -{ - int n = Len; - UCHAR c; - int ESCFLAG = 0; - UCHAR * ptr1, *ptr2; - int Chan; - int Opcode; - string * TXMSG; - unsigned short CRC; - UCHAR CRCString[2]; - - 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; - - switch (Opcode) - { - case KISS_ACKMODE: - - // How best to do ACKMODE?? I think pass whole frame including CMD and ack bytes to all_frame_buf - - // But ack should only be sent to client that sent the message - needs more thought! - - TXMSG = newString(); - stringAdd(TXMSG, &Msg[0], Len); // include Control - - CRC = get_fcs(&Msg[3], Len - 3); // exclude control and ack bytes - - CRCString[0] = CRC & 0xff; - CRCString[1] = CRC >> 8; - - stringAdd(TXMSG, CRCString, 2); - - // Ackmode needs to know where to send ack back to, so save socket on end of data - - stringAdd(TXMSG, (unsigned char *)&socket, sizeof(socket)); - - // if KISS Optimise see if frame is really needed - - if (!KISS_opt[Chan]) - Add(&KISS.buffer[Chan], TXMSG); - else - { - if (add_raw_frames(Chan, TXMSG, &KISS.buffer[Chan])) - Add(&KISS.buffer[Chan], TXMSG); - } - - - return; - - case KISS_DATA: - - TXMSG = newString(); - stringAdd(TXMSG, &Msg[1], Len - 1); // include Control - - 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(KISS)); - - 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) - { - 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); - 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"; - -char * ShortDateTime() -{ - struct tm * tm; - time_t NOW = time(NULL); - - 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) - // 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; -} - - - - - - - - +/* +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" +#include + +#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); + +/* + +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 }; + +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, 70); + + 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 (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 ProcessKISSFrame(void * socket, UCHAR * Msg, int Len) +{ + int n = Len; + UCHAR c; + int ESCFLAG = 0; + UCHAR * ptr1, *ptr2; + int Chan; + int Opcode; + string * TXMSG; + unsigned short CRC; + UCHAR CRCString[2]; + + 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; + + switch (Opcode) + { + case KISS_ACKMODE: + + // How best to do ACKMODE?? I think pass whole frame including CMD and ack bytes to all_frame_buf + + // But ack should only be sent to client that sent the message - needs more thought! + + TXMSG = newString(); + stringAdd(TXMSG, &Msg[0], Len); // include Control + + CRC = get_fcs(&Msg[3], Len - 3); // exclude control and ack bytes + + CRCString[0] = CRC & 0xff; + CRCString[1] = CRC >> 8; + + stringAdd(TXMSG, CRCString, 2); + + // Ackmode needs to know where to send ack back to, so save socket on end of data + + stringAdd(TXMSG, (unsigned char *)&socket, sizeof(socket)); + + // if KISS Optimise see if frame is really needed + + if (!KISS_opt[Chan]) + Add(&KISS.buffer[Chan], TXMSG); + else + { + if (add_raw_frames(Chan, TXMSG, &KISS.buffer[Chan])) + Add(&KISS.buffer[Chan], TXMSG); + } + + + return; + + case KISS_DATA: + + TXMSG = newString(); + stringAdd(TXMSG, &Msg[1], Len - 1); // include Control + + 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); + 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; +} + + + + + + + + diff --git a/ax25.h b/ax25.h index 8895eee..d554b20 100644 --- a/ax25.h +++ b/ax25.h @@ -1,304 +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 AGWUser_t -{ - void *socket; - string * data_in; - TStringList AGW_frame_buf; - boolean Monitor; - boolean Monitor_raw; - boolean reportFreqAndModem; // Can report modem and frequency to host - -} AGWUser; - -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, 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, 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, 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, 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 diff --git a/ax25_l2.c b/ax25_l2.c index b9003c2..e4dabb7 100644 --- a/ax25_l2.c +++ b/ax25_l2.c @@ -1,1735 +1,1737 @@ -/* -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" - -UCHAR TimerEvent = TIMER_EVENT_OFF; -extern int busy; -int listenEnable; -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; - } - } - (*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, 0, data); - - KISSSendtoServer(AX25Sess->socket, KISSBuffer, Length); - - monitor_frame(0, data, "", 1, 0); // Monitor - freeString(data); - - -// while (i < AX25Sess->frame_buf.Count && !found) -// { -// found = compareStrings(Strings(&AX25Sess->frame_buf, i++), data); -// } - -// if (found) -// freeString(data); -// else -// Add(&AX25Sess->frame_buf, 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 * ax25IncommingConnect(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 (ax25IncommingConnect(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 - if (dyn_frack[snd_ch]) - { - UpdateActiveConnects(snd_ch); - if (users[snd_ch] > 0) - active = users[snd_ch] - 1; - else - active = 0; - - frack = frack_time[snd_ch] + frack_time[snd_ch] * active * 0.5; - } - else - 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 (listenEnable == 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, Byte * Msg, int MsgLen) -{ - Byte path[80]; - char Calls[80]; - string * Data = newString(); - string * Frame; - - UCHAR KISSBuffer[512]; - int Length; - - stringAdd(Data, Msg, MsgLen); - - sprintf(Calls, "%s,%s", CallTo, CallFrom); - - get_addr(Calls, 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, 0, Frame); - - KISSSendtoServer(KISSSockCopy[port], 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 + +#include "ax25.h" + +UCHAR TimerEvent = TIMER_EVENT_OFF; +extern int busy; +int listenEnable; +int KISSListen = 1; + +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; + } + } + (*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, 0, data); + + KISSSendtoServer(AX25Sess->socket, KISSBuffer, Length); + + monitor_frame(0, data, "", 1, 0); // Monitor + freeString(data); + + +// while (i < AX25Sess->frame_buf.Count && !found) +// { +// found = compareStrings(Strings(&AX25Sess->frame_buf, i++), data); +// } + +// if (found) +// freeString(data); +// else +// Add(&AX25Sess->frame_buf, 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 + if (dyn_frack[snd_ch]) + { + UpdateActiveConnects(snd_ch); + if (users[snd_ch] > 0) + active = users[snd_ch] - 1; + else + active = 0; + + frack = frack_time[snd_ch] + frack_time[snd_ch] * active * 0.5; + } + else + 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, Byte * Msg, int MsgLen) +{ + Byte path[80]; + char Calls[80]; + string * Data = newString(); + string * Frame; + + UCHAR KISSBuffer[512]; + int Length; + + stringAdd(Data, Msg, MsgLen); + + sprintf(Calls, "%s,%s", CallTo, CallFrom); + + get_addr(Calls, 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, 0, Frame); + + KISSSendtoServer(KISSSockCopy[port], KISSBuffer, Length); + + monitor_frame(0, Frame, "", 1, 0); // Monitor + freeString(Frame); + +} + + + + diff --git a/debug/moc_predefs.h b/debug/moc_predefs.h new file mode 100644 index 0000000..6d708a1 --- /dev/null +++ b/debug/moc_predefs.h @@ -0,0 +1,12 @@ +#define _MSC_EXTENSIONS +#define _INTEGRAL_MAX_BITS 64 +#define _MSC_VER 1916 +#define _MSC_FULL_VER 191627043 +#define _MSC_BUILD 0 +#define _WIN32 +#define _M_IX86 600 +#define _M_IX86_FP 2 +#define _CPPRTTI +#define _DEBUG +#define _MT +#define _DLL diff --git a/ding.wav b/ding.wav new file mode 100644 index 0000000..5331129 Binary files /dev/null and b/ding.wav differ diff --git a/hid.c b/hid.c index 88ab1bc..6794c60 100644 --- a/hid.c +++ b/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 diff --git a/main.cpp b/main.cpp index 270cffe..ed67d5f 100644 --- a/main.cpp +++ b/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(); +} diff --git a/makeit b/makeit index bdf2910..57d400f 100644 --- a/makeit +++ b/makeit @@ -1,10 +1,11 @@ -cp --preserve /mnt/Source/QT/QtTermTCP/*.cpp ./ -cp --preserve /mnt/Source/QT/QtTermTCP/*.c ./ -cp --preserve /mnt/Source/QT/QtTermTCP/*.h ./ -cp --preserve /mnt/Source/QT/QtTermTCP/*.ui ./ -cp --preserve /mnt/Source/QT/QtTermTCP/*.pro ./ -cp --preserve /mnt/Source/QT/QtTermTCP/*.qrc ./ -cp --preserve /mnt/Source/QT/QtTermTCP/*.ico ./ +cp --preserve /mnt/Source/QT/QtTermTCP2/*.cpp ./ +cp --preserve /mnt/Source/QT/QtTermTCP2/*.c ./ +cp --preserve /mnt/Source/QT/QtTermTCP2/*.h ./ +cp --preserve /mnt/Source/QT/QtTermTCP2/*.ui ./ +cp --preserve /mnt/Source/QT/QtTermTCP2/*.pro ./ +cp --preserve /mnt/Source/QT/QtTermTCP2/*.qrc ./ +cp --preserve /mnt/Source/QT/QtTermTCP2/*.ico ./ +cp --preserve /mnt/Source/QT/QtTermTCP2/*.wav ./ qmake make -j4 diff --git a/release/moc_predefs.h b/release/moc_predefs.h new file mode 100644 index 0000000..54e9037 --- /dev/null +++ b/release/moc_predefs.h @@ -0,0 +1,11 @@ +#define _MSC_EXTENSIONS +#define _INTEGRAL_MAX_BITS 64 +#define _MSC_VER 1916 +#define _MSC_FULL_VER 191627043 +#define _MSC_BUILD 0 +#define _WIN32 +#define _M_IX86 600 +#define _M_IX86_FP 2 +#define _CPPRTTI +#define _MT +#define _DLL diff --git a/ui_TCPHostConfig.h b/ui_TCPHostConfig.h deleted file mode 100644 index 1f232a7..0000000 --- a/ui_TCPHostConfig.h +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************** -** Form generated from reading UI file 'TCPHostConfig.ui' -** -** Created by: Qt User Interface Compiler version 5.14.2 -** -** WARNING! All changes made in this file will be lost when recompiling UI file! -********************************************************************************/ - -#ifndef UI_TCPHOSTCONFIG_H -#define UI_TCPHOSTCONFIG_H - -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class Ui_Dialog -{ -public: - QDialogButtonBox *buttonBox; - QTextEdit *Host; - - void setupUi(QDialog *Dialog) - { - if (Dialog->objectName().isEmpty()) - Dialog->setObjectName(QString::fromUtf8("Dialog")); - Dialog->resize(400, 300); - QIcon icon; - icon.addFile(QString::fromUtf8("QtTermTCP.ico"), QSize(), QIcon::Normal, QIcon::Off); - Dialog->setWindowIcon(icon); - buttonBox = new QDialogButtonBox(Dialog); - buttonBox->setObjectName(QString::fromUtf8("buttonBox")); - buttonBox->setGeometry(QRect(30, 240, 341, 32)); - buttonBox->setOrientation(Qt::Horizontal); - buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Save); - buttonBox->setCenterButtons(true); - Host = new QTextEdit(Dialog); - Host->setObjectName(QString::fromUtf8("Host")); - Host->setGeometry(QRect(184, 44, 104, 23)); - - retranslateUi(Dialog); - QObject::connect(buttonBox, SIGNAL(accepted()), Dialog, SLOT(accept())); - QObject::connect(buttonBox, SIGNAL(rejected()), Dialog, SLOT(reject())); - - QMetaObject::connectSlotsByName(Dialog); - } // setupUi - - void retranslateUi(QDialog *Dialog) - { - Dialog->setWindowTitle(QCoreApplication::translate("Dialog", "TCP Host Config", nullptr)); - } // retranslateUi - -}; - -namespace Ui { - class Dialog: public Ui_Dialog {}; -} // namespace Ui - -QT_END_NAMESPACE - -#endif // UI_TCPHOSTCONFIG_H diff --git a/utf8Routines.cpp b/utf8Routines.cpp index 59b1e23..f5eecff 100644 --- a/utf8Routines.cpp +++ b/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; + +} +