diff --git a/gui_vue/electron/preload.ts b/gui_vue/electron/preload.ts
index ff1f1286..f1c701f8 100644
--- a/gui_vue/electron/preload.ts
+++ b/gui_vue/electron/preload.ts
@@ -37,24 +37,24 @@ function useLoading() {
@keyframes square-spin {
0% {
transform: rotate(0deg);
- background-image: url('../public/icon_cube_border.png'); /* Replace with the URL of your image */
+ background-image: url('icon_cube_border.png'); /* Replace with the URL of your image */
background-size: cover; /* Scale the image to cover the entire container */
}
25% { transform: perspective(100px) rotateX(180deg) rotateY(0);
- background-image: url('../public/icon_cube_border.png'); /* Replace with the URL of your image */
+ background-image: url('icon_cube_border.png'); /* Replace with the URL of your image */
background-size: cover; /* Scale the image to cover the entire container */
}
50% { transform: perspective(100px) rotateX(180deg) rotateY(180deg);
- background-image: url('../public/icon_cube_border.png'); /* Replace with the URL of your image */
+ background-image: url('icon_cube_border.png'); /* Replace with the URL of your image */
background-size: cover; /* Scale the image to cover the entire container */
}
75% { transform: perspective(100px) rotateX(0) rotateY(180deg);
- background-image: url('../public/icon_cube_border.png'); /* Replace with the URL of your image */
+ background-image: url('icon_cube_border.png'); /* Replace with the URL of your image */
background-size: cover; /* Scale the image to cover the entire container */
}
100% { transform: perspective(100px) rotateX(0) rotateY(0);
- background-image: url('../public/icon_cube_border.png'); /* Replace with the URL of your image */
+ background-image: url('icon_cube_border.png'); /* Replace with the URL of your image */
background-size: cover; /* Scale the image to cover the entire container */
}
}
@@ -63,7 +63,7 @@ function useLoading() {
width: 50px;
height: 50px;
background: #fff;
- animation: square-spin 6s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
+ animation: square-spin 3s 0s cubic-bezier(0.09, 0.57, 0.49, 0.9) infinite;
}
.app-loading-wrap {
position: fixed;
@@ -107,4 +107,4 @@ window.onmessage = ev => {
ev.data.payload === 'removeLoading' && removeLoading()
}
-setTimeout(removeLoading, 4999)
+setTimeout(removeLoading, 3000)
diff --git a/gui_vue/src/js/daemon.js b/gui_vue/src/js/daemon.js
new file mode 100644
index 00000000..bf1a12cc
--- /dev/null
+++ b/gui_vue/src/js/daemon.js
@@ -0,0 +1,363 @@
+//var net = require("net");
+var net = require('node:net');
+
+const path = require("path");
+const { ipcRenderer } = require("electron");
+// ----------------- init pinia stores -------------
+import { setActivePinia } from 'pinia';
+import pinia from '../store/index';
+setActivePinia(pinia);
+import { useAudioStore } from '../store/audioStore.js';
+const audioStore = useAudioStore(pinia);
+
+import { useSettingsStore } from '../store/settingsStore.js';
+const settings = useSettingsStore(pinia);
+
+
+var daemon = new net.Socket();
+var socketchunk = ""; // Current message, per connection.
+
+// global to keep track of daemon connection error emissions
+var daemonShowConnectStateError = 1;
+
+
+setTimeout(connectDAEMON, 500);
+
+function connectDAEMON() {
+ if (daemonShowConnectStateError == 1) {
+ console.log("connecting to daemon");
+ }
+
+ //clear message buffer after reconnecting or initial connection
+ socketchunk = "";
+
+ if (settings.tnclocation == "localhost") {
+ daemon.connect(3001, "127.0.0.1");
+ } else {
+ daemon.connect(daemon_port, daemon_host);
+ }
+
+ //client.setTimeout(5000);
+}
+
+daemon.on("connect", function (err) {
+ console.log("daemon connection established");
+ let Data = {
+ daemon_connection: daemon.readyState,
+ };
+ ipcRenderer.send("request-update-daemon-connection", Data);
+
+ daemonShowConnectStateError = 1;
+});
+
+daemon.on("error", function (err) {
+ if (daemonShowConnectStateError == 1) {
+ console.log("daemon connection error");
+ console.log("Make sure the daemon is started.");
+ console.log('Run "python daemon.py" in the tnc directory.');
+
+ daemonShowConnectStateError = 0;
+ }
+ setTimeout(connectDAEMON, 500);
+ daemon.destroy();
+ let Data = {
+ daemon_connection: daemon.readyState,
+ };
+ ipcRenderer.send("request-update-daemon-connection", Data);
+});
+
+/*
+client.on('close', function(data) {
+ console.log(' TNC connection closed');
+ setTimeout(connectTNC, 2000)
+ let Data = {
+ daemon_connection: daemon.readyState,
+ };
+ ipcRenderer.send('request-update-daemon-connection', Data);
+});
+*/
+
+daemon.on("end", function (data) {
+ daemonLog.warn("daemon connection ended");
+ daemon.destroy();
+ setTimeout(connectDAEMON, 500);
+ let Data = {
+ daemon_connection: daemon.readyState,
+ };
+ ipcRenderer.send("request-update-daemon-connection", Data);
+});
+
+//exports.writeDaemonCommand = function(command){
+//writeDaemonCommand = function (command) {
+function writeDaemonCommand(command) {
+
+ // we use the writingCommand function to update our TCPIP state because we are calling this function a lot
+ // if socket opened, we are able to run commands
+ if (daemon.readyState == "open") {
+ //uiMain.setDAEMONconnection('open')
+ daemon.write(command + "\n");
+ }
+
+ if (daemon.readyState == "closed") {
+ //uiMain.setDAEMONconnection('closed')
+ }
+
+ if (daemon.readyState == "opening") {
+ //uiMain.setDAEMONconnection('opening')
+ }
+
+ let Data = {
+ daemon_connection: daemon.readyState,
+ };
+ ipcRenderer.send("request-update-daemon-connection", Data);
+};
+
+// "https://stackoverflow.com/questions/9070700/nodejs-net-createserver-large-amount-of-data-coming-in"
+
+daemon.on("data", function (socketdata) {
+ /*
+ inspired by:
+ stackoverflow.com questions 9070700 nodejs-net-createserver-large-amount-of-data-coming-in
+ */
+
+ socketdata = socketdata.toString("utf8"); // convert data to string
+ socketchunk += socketdata; // append data to buffer so we can stick long data together
+
+ // check if we received begin and end of json data
+ if (socketchunk.startsWith('{"') && socketchunk.endsWith('"}\n')) {
+ var data = "";
+
+ // split data into chunks if we received multiple commands
+ socketchunk = socketchunk.split("\n");
+ data = JSON.parse(socketchunk[0]);
+
+ // search for empty entries in socketchunk and remove them
+ for (var i = 0; i < socketchunk.length; i++) {
+ if (socketchunk[i] === "") {
+ socketchunk.splice(i, 1);
+ }
+ }
+
+ //iterate through socketchunks array to execute multiple commands in row
+ for (i = 0; i < socketchunk.length; i++) {
+ //check if data is not empty
+ if (socketchunk[i].length > 0) {
+ //try to parse JSON
+ try {
+ data = JSON.parse(socketchunk[i]);
+ } catch (e) {
+ console.log(e); // "SyntaxError
+ daemonLog.debug(socketchunk[i]);
+ socketchunk = "";
+ }
+ }
+
+ if (data["command"] == "daemon_state") {
+ let Data = {
+ input_devices: data["input_devices"],
+ output_devices: data["output_devices"],
+ python_version: data["python_version"],
+ hamlib_version: data["hamlib_version"],
+ serial_devices: data["serial_devices"],
+ tnc_running_state: data["daemon_state"][0]["status"],
+ ram_usage: data["ram"],
+ cpu_usage: data["cpu"],
+ version: data["version"],
+ };
+
+ // update audio devices by putting them to audio store
+ audioStore.inputDevices = data["input_devices"];
+ audioStore.outputDevices = data["output_devices"];
+
+
+ }
+
+ if (data["command"] == "test_hamlib") {
+ let Data = {
+ hamlib_result: data["result"],
+ };
+ ipcRenderer.send("request-update-hamlib-test", Data);
+ }
+ }
+
+ //finally delete message buffer
+ socketchunk = "";
+ }
+});
+
+function hexToBytes(hex) {
+ for (var bytes = [], c = 0; c < hex.length; c += 2)
+ bytes.push(parseInt(hex.substr(c, 2), 16));
+ return bytes;
+}
+
+//exports.getDaemonState = function () {
+function getDaemonState() {
+
+ //function getDaemonState(){
+ command = '{"type" : "get", "command" : "daemon_state"}';
+ writeDaemonCommand(command);
+};
+
+// START TNC
+// ` `== multi line string
+function startTNC(
+//exports.startTNC = function (
+ mycall,
+ mygrid,
+ rx_audio,
+ tx_audio,
+ radiocontrol,
+ devicename,
+ deviceport,
+ pttprotocol,
+ pttport,
+ serialspeed,
+ data_bits,
+ stop_bits,
+ handshake,
+ rigctld_ip,
+ rigctld_port,
+ enable_fft,
+ enable_scatter,
+ low_bandwidth_mode,
+ tuning_range_fmin,
+ tuning_range_fmax,
+ enable_fsk,
+ tx_audio_level,
+ respond_to_cq,
+ rx_buffer_size,
+ enable_explorer,
+ explorer_stats,
+ auto_tune,
+ tx_delay,
+ tci_ip,
+ tci_port,
+ enable_mesh,
+) {
+ var json_command = JSON.stringify({
+ type: "set",
+ command: "start_tnc",
+ parameter: [
+ {
+ mycall: mycall,
+ mygrid: mygrid,
+ rx_audio: rx_audio,
+ tx_audio: tx_audio,
+ radiocontrol: radiocontrol,
+ devicename: devicename,
+ deviceport: deviceport,
+ pttprotocol: pttprotocol,
+ pttport: pttport,
+ serialspeed: serialspeed,
+ data_bits: data_bits,
+ stop_bits: stop_bits,
+ handshake: handshake,
+ rigctld_port: rigctld_port,
+ rigctld_ip: rigctld_ip,
+ enable_scatter: enable_scatter,
+ enable_fft: enable_fft,
+ enable_fsk: enable_fsk,
+ low_bandwidth_mode: low_bandwidth_mode,
+ tuning_range_fmin: tuning_range_fmin,
+ tuning_range_fmax: tuning_range_fmax,
+ tx_audio_level: tx_audio_level,
+ respond_to_cq: respond_to_cq,
+ rx_buffer_size: rx_buffer_size,
+ enable_explorer: enable_explorer,
+ enable_stats: explorer_stats,
+ enable_auto_tune: auto_tune,
+ tx_delay: tx_delay,
+ tci_ip: tci_ip,
+ tci_port: tci_port,
+ enable_mesh: enable_mesh,
+ },
+ ],
+ });
+
+ daemonLog.debug(json_command);
+ writeDaemonCommand(json_command);
+};
+
+// STOP TNC
+//exports.stopTNC = function () {
+function stopTNC() {
+
+ command = '{"type" : "set", "command": "stop_tnc" , "parameter": "---" }';
+ writeDaemonCommand(command);
+};
+
+// TEST HAMLIB
+function testHamlib(
+
+//exports.testHamlib = function (
+ radiocontrol,
+ devicename,
+ deviceport,
+ serialspeed,
+ pttprotocol,
+ pttport,
+ data_bits,
+ stop_bits,
+ handshake,
+ rigctld_ip,
+ rigctld_port,
+) {
+ var json_command = JSON.stringify({
+ type: "get",
+ command: "test_hamlib",
+ parameter: [
+ {
+ radiocontrol: radiocontrol,
+ devicename: devicename,
+ deviceport: deviceport,
+ pttprotocol: pttprotocol,
+ pttport: pttport,
+ serialspeed: serialspeed,
+ data_bits: data_bits,
+ stop_bits: stop_bits,
+ handshake: handshake,
+ rigctld_port: rigctld_port,
+ rigctld_ip: rigctld_ip,
+ },
+ ],
+ });
+ daemonLog.debug(json_command);
+ writeDaemonCommand(json_command);
+};
+
+//Save myCall
+function saveMyCall(callsign){
+//exports.saveMyCall = function (callsign) {
+ command =
+ '{"type" : "set", "command": "mycallsign" , "parameter": "' +
+ callsign +
+ '"}';
+ writeDaemonCommand(command);
+};
+
+// Save myGrid
+//exports.saveMyGrid = function (grid) {
+function saveMyGrid(grid){
+
+ command =
+ '{"type" : "set", "command": "mygrid" , "parameter": "' + grid + '"}';
+ writeDaemonCommand(command);
+};
+
+ipcRenderer.on("action-update-daemon-ip", (event, arg) => {
+ daemon.destroy();
+ let Data = {
+ busy_state: "-",
+ arq_state: "-",
+ //channel_state: "-",
+ frequency: "-",
+ mode: "-",
+ bandwidth: "-",
+ dbfs_level: 0,
+ };
+ ipcRenderer.send("request-update-tnc-state", Data);
+ daemon_port = arg.port;
+ daemon_host = arg.adress;
+ connectDAEMON();
+});
diff --git a/gui_vue/src/js/freedata.js b/gui_vue/src/js/freedata.js
new file mode 100644
index 00000000..6b02a8d2
--- /dev/null
+++ b/gui_vue/src/js/freedata.js
@@ -0,0 +1,37 @@
+const fs = require("fs");
+const { ipcRenderer } = require("electron");
+
+/**
+ * Save config and update config setting globally
+ * @param {string} config - config data
+ * @param {string} configPath
+ */
+exports.saveConfig = function (config, configPath) {
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
+ ipcRenderer.send("set-config-global", config);
+};
+
+/**
+ * Binary to ASCII replacement
+ * @param {string} data in normal/usual utf-8 format
+ * @returns base64 encoded string
+ */
+exports.btoa_FD = function (data) {
+ return Buffer.from(data, "utf-8").toString("base64");
+};
+/**
+ * ASCII to Binary replacement
+ * @param {string} data in base64 encoding
+ * @returns utf-8 normal/usual string
+ */
+exports.atob_FD = function (data) {
+ return Buffer.from(data, "base64").toString("utf-8");
+};
+/**
+ * UTF8 to ASCII btoa
+ * @param {string} data in base64 encoding
+ * @returns base64 bota compatible data for use in browser
+ */
+exports.atob = function (data) {
+ return window.btoa(Buffer.from(data, "base64").toString("utf8"));
+};
diff --git a/gui_vue/src/js/preload-chat.js b/gui_vue/src/js/preload-chat.js
new file mode 100644
index 00000000..72ef9101
--- /dev/null
+++ b/gui_vue/src/js/preload-chat.js
@@ -0,0 +1,2976 @@
+const path = require("path");
+const { ipcRenderer } = require("electron");
+const { v4: uuidv4 } = require("uuid");
+const imageCompression = require("browser-image-compression");
+const blobUtil = require("blob-util");
+const FD = require("./freedata");
+const fs = require("fs");
+
+// https://stackoverflow.com/a/26227660
+var appDataFolder =
+ process.env.APPDATA ||
+ (process.platform == "darwin"
+ ? process.env.HOME + "/Library/Application Support"
+ : process.env.HOME + "/.config");
+var configFolder = path.join(appDataFolder, "FreeDATA");
+var configPath = path.join(configFolder, "config.json");
+var config = require(configPath);
+// set date format
+const dateFormat = new Intl.DateTimeFormat(navigator.language, {
+ timeStyle: "long",
+ dateStyle: "short",
+});
+// set date format information
+const dateFormatShort = new Intl.DateTimeFormat(navigator.language, {
+ year: "numeric",
+ month: "numeric",
+ day: "numeric",
+ hour: "numeric",
+ minute: "numeric",
+ second: "numeric",
+ hour12: false,
+});
+
+const dateFormatHours = new Intl.DateTimeFormat(navigator.language, {
+ hour: "numeric",
+ minute: "numeric",
+ hour12: false,
+});
+// split character
+const split_char = "\0;\1;";
+// global for our selected file we want to transmit
+// ----------------- some chat globals
+var filetype = "";
+var file = "";
+var filename = "";
+var callsign_counter = 0;
+var selected_callsign = "";
+var lastIsWritingBroadcast = new Date().getTime();
+var defaultUserIcon =
+ "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iY3VycmVudENvbG9yIiBjbGFzcz0iYmkgYmktcGVyc29uLWJvdW5kaW5nLWJveCIgdmlld0JveD0iMCAwIDE2IDE2Ij4KICA8cGF0aCBkPSJNMS41IDFhLjUuNSAwIDAgMC0uNS41djNhLjUuNSAwIDAgMS0xIDB2LTNBMS41IDEuNSAwIDAgMSAxLjUgMGgzYS41LjUgMCAwIDEgMCAxaC0zek0xMSAuNWEuNS41IDAgMCAxIC41LS41aDNBMS41IDEuNSAwIDAgMSAxNiAxLjV2M2EuNS41IDAgMCAxLTEgMHYtM2EuNS41IDAgMCAwLS41LS41aC0zYS41LjUgMCAwIDEtLjUtLjV6TS41IDExYS41LjUgMCAwIDEgLjUuNXYzYS41LjUgMCAwIDAgLjUuNWgzYS41LjUgMCAwIDEgMCAxaC0zQTEuNSAxLjUgMCAwIDEgMCAxNC41di0zYS41LjUgMCAwIDEgLjUtLjV6bTE1IDBhLjUuNSAwIDAgMSAuNS41djNhMS41IDEuNSAwIDAgMS0xLjUgMS41aC0zYS41LjUgMCAwIDEgMC0xaDNhLjUuNSAwIDAgMCAuNS0uNXYtM2EuNS41IDAgMCAxIC41LS41eiIvPgogIDxwYXRoIGQ9Ik0zIDE0cy0xIDAtMS0xIDEtNCA2LTQgNiAzIDYgNC0xIDEtMSAxSDN6bTgtOWEzIDMgMCAxIDEtNiAwIDMgMyAwIDAgMSA2IDB6Ii8+Cjwvc3ZnPg==";
+var defaultGroupIcon =
+ "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iY3VycmVudENvbG9yIiBjbGFzcz0iYmkgYmktcGVvcGxlLWZpbGwiIHZpZXdCb3g9IjAgMCAxNiAxNiI+CiAgPHBhdGggZD0iTTcgMTRzLTEgMC0xLTEgMS00IDUtNCA1IDMgNSA0LTEgMS0xIDFIN1ptNC02YTMgMyAwIDEgMCAwLTYgMyAzIDAgMCAwIDAgNlptLTUuNzg0IDZBMi4yMzggMi4yMzggMCAwIDEgNSAxM2MwLTEuMzU1LjY4LTIuNzUgMS45MzYtMy43MkE2LjMyNSA2LjMyNSAwIDAgMCA1IDljLTQgMC01IDMtNSA0czEgMSAxIDFoNC4yMTZaTTQuNSA4YTIuNSAyLjUgMCAxIDAgMC01IDIuNSAyLjUgMCAwIDAgMCA1WiIvPgo8L3N2Zz4=";
+
+// -----------------------------------
+// Initially fill sharedFolderFileList
+//TODO: Make this automatically ever N seconds
+var sharedFolderFileList = "";
+ipcRenderer.send("read-files-in-folder", {
+ folder: config.shared_folder_path,
+});
+
+var chatDB = path.join(configFolder, "chatDB");
+var userDB = path.join(configFolder, "userDB");
+// ---- MessageDB
+try {
+ var PouchDB = require("pouchdb");
+} catch (err) {
+ console.log(err);
+
+ /*
+ This is a fix for raspberryPi where we get an error when loading pouchdb because of
+ leveldown package isnt running on ARM devices.
+ pouchdb-browser does not depend on leveldb and seems to be working.
+ */
+ console.log("using pouchdb-browser fallback");
+ var PouchDB = require("pouchdb-browser");
+}
+
+PouchDB.plugin(require("pouchdb-find"));
+//PouchDB.plugin(require('pouchdb-replication'));
+PouchDB.plugin(require("pouchdb-upsert"));
+
+
+
+var db = new PouchDB(chatDB);
+var users = new PouchDB(userDB);
+
+/* -------- CREATE DATABASE INDEXES */
+createChatIndex();
+createUserIndex();
+
+// REMOTE SYNC ATTEMPTS
+
+//var remoteDB = new PouchDB('http://172.20.10.4:5984/chatDB')
+
+/*
+
+// we need express packages for running pouchdb sync "express-pouchdb"
+var express = require('express');
+var app = express();
+app.use('/', require('express-pouchdb')(PouchDB));
+app.listen(5984);
+var db = new PouchDB(chatDB);
+
+
+app.use('/chatDB', require('pouchdb-express-router')(PouchDB));
+app.listen(5984);
+
+
+
+db.sync('http://172.20.10.4:5984/jojo', {
+//var sync = PouchDB.sync('chatDB', 'http://172.20.10.4:5984/chatDB', {
+ live: true,
+ retry: false
+}).on('change', function (change) {
+ // yo, something changed!
+ console.log(change)
+}).on('paused', function (err) {
+ // replication was paused, usually because of a lost connection
+ console.log(err)
+}).on('active', function (info) {
+ // replication was resumed
+ console.log(info)
+}).on('error', function (err) {
+ // totally unhandled error (shouldn't happen)
+ console.log(err)
+}).on('denied', function (err) {
+ // a document failed to replicate (e.g. due to permissions)
+ console.log(err)
+}).on('complete', function (info) {
+ // handle complete;
+ console.log(info)
+});
+*/
+
+var dxcallsigns = new Set();
+
+//Set default chat filter
+var chatFilter = [
+ { type: "newchat" },
+ { type: "received" },
+ { type: "transmit" },
+ { type: "ping-ack" },
+ { type: "broadcast_received" },
+ { type: "broadcast_transmit" },
+
+ //{ type: "request" },
+ //{ type: "response" },
+];
+
+// WINDOW LISTENER
+window.addEventListener("DOMContentLoaded", () => {
+ updateAllChat(false);
+ // theme selector
+ // TODO: Remove for one pager, also remove function!
+ //changeGuiDesign(config.theme);
+
+ const userInfoFields = [
+ "user_info_image",
+ "user_info_callsign",
+ "user_info_gridsquare",
+ "user_info_name",
+ "user_info_age",
+ "user_info_location",
+ "user_info_radio",
+ "user_info_antenna",
+ "user_info_email",
+ "user_info_website",
+ "user_info_comments",
+ ];
+ users
+ .find({
+ selector: {
+ user_info_callsign: config.mycall,
+ },
+ })
+ .then(function (result) {
+ console.log(result);
+ if (typeof result.docs[0] !== "undefined") {
+ // handle result
+ userInfoFields.forEach(function (elem) {
+ if (elem !== "user_info_image") {
+ document.getElementById(elem).value = result.docs[0][elem];
+ } else {
+ document.getElementById(elem).src = result.docs[0][elem];
+ }
+ });
+ } else {
+ console.log(
+ config.mycall + " not found in user db - creating new entry",
+ );
+ // add initial entry for own callsign and grid
+ let obj = new Object();
+ obj.user_info_callsign = config.mycall;
+ obj.user_info_gridsquare = config.mygrid;
+ addUserToDatabaseIfNotExists(obj);
+
+ document.getElementById("user_info_callsign").value = config.mycall;
+ document.getElementById("user_info_gridsquare").value = config.mygrid;
+ }
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+
+ //save user info
+ document.getElementById("userInfoSave").addEventListener("click", () => {
+ let obj = new Object();
+ userInfoFields.forEach(function (subelem) {
+ if (subelem !== "user_info_image") {
+ obj[subelem] = document.getElementById(subelem).value;
+ } else {
+ obj[subelem] = document.getElementById(subelem).src;
+ }
+ });
+ addUserToDatabaseIfNotExists(obj);
+ });
+
+ //Add event listener for filter apply button
+ document.getElementById("btnFilter").addEventListener("click", () => {
+ chatFilter.length = 0;
+ if (document.getElementById("chkMessage").checked == true) {
+ chatFilter = [{ type: "newchat" }];
+ chatFilter.push(
+ { type: "received" },
+ { type: "transmit" },
+ { type: "broadcast_received" },
+ { type: "broadcast_transmit" },
+ );
+ }
+ if (document.getElementById("chkPing").checked == true)
+ chatFilter.push({ type: "ping" });
+ if (document.getElementById("chkPingAck").checked == true)
+ chatFilter.push({ type: "ping-ack" });
+ if (document.getElementById("chkBeacon").checked == true)
+ chatFilter.push({ type: "beacon" });
+ if (document.getElementById("chkRequest").checked == true)
+ chatFilter.push({ type: "request" });
+ if (document.getElementById("chkResponse").checked == true)
+ chatFilter.push({ type: "response" });
+ if (document.getElementById("chkNewMessage").checked == true)
+ chatFilter.push({ new: 1 });
+ updateAllChat(true);
+ });
+
+ document
+ .querySelector("emoji-picker")
+ .addEventListener("emoji-click", (event) => {
+ var msg = document.getElementById("chatModuleMessage");
+ //Convert to utf-8--so we can just use utf-8 everywhere
+ msg.setRangeText(event.detail.emoji.unicode.toString("utf-8"));
+ //console.log(event.detail);
+ //msg.focus();
+ });
+ document.getElementById("emojipickerbutton").addEventListener("click", () => {
+ var element = document.getElementById("emojipickercontainer");
+ console.log(element.style.display);
+ if (element.style.display === "none") {
+ element.style.display = "block";
+ } else {
+ element.style.display = "none";
+ }
+ });
+
+ document
+ .getElementById("delete_selected_chat")
+ .addEventListener("click", () => {
+ db.find({
+ selector: {
+ dxcallsign: selected_callsign,
+ },
+ })
+ .then(function (result) {
+ // handle result
+ if (typeof result !== "undefined") {
+ result.docs.forEach(function (item) {
+ console.log(item);
+ db.get(item._id)
+ .then(function (doc) {
+ db.remove(doc)
+ .then(function (doc) {
+ updateAllChat(true);
+ return true;
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ });
+ }
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ });
+ document.getElementById("selectFilesButton").addEventListener("click", () => {
+ //document.getElementById('selectFiles').click();
+ ipcRenderer.send("select-file", {
+ title: "Title",
+ });
+ });
+
+ document.getElementById("requestUserInfo").addEventListener("click", () => {
+ ipcRenderer.send("run-tnc-command", {
+ command: "requestUserInfo",
+ dxcallsign: selected_callsign,
+ });
+
+ pauseButton(document.getElementById("requestUserInfo"), 60000);
+ });
+
+ document.getElementById("ping").addEventListener("click", () => {
+ ipcRenderer.send("run-tnc-command", {
+ command: "ping",
+ dxcallsign: selected_callsign,
+ });
+ });
+
+ document.addEventListener("keyup", function (event) {
+ // Number 13 == Enter
+ if (
+ event.keyCode === 13 &&
+ !event.shiftKey &&
+ document.activeElement.id == "chatModuleMessage"
+ ) {
+ // Cancel the default action, if needed
+ event.preventDefault();
+ // Trigger the button element with a click
+ document.getElementById("sendMessage").click();
+ }
+ });
+
+ // ADJUST TEXTAREA SIZE
+ document.getElementById("chatModuleMessage").addEventListener("input", () => {
+ var textarea = document.getElementById("chatModuleMessage");
+ var text = textarea.value;
+
+ if (document.getElementById("expand_textarea").checked) {
+ var lines = 6;
+ } else {
+ var lines = text.split("\n").length;
+
+ if (lines >= 6) {
+ lines = 6;
+ }
+ }
+ var message_container_height_offset = 180 + 20 * lines;
+ var message_container_height = `calc(100% - ${message_container_height_offset}px)`;
+ document.getElementById("message-container").style.height =
+ message_container_height;
+ textarea.rows = lines;
+
+ console.log(textarea.value);
+ if (lastIsWritingBroadcast < new Date().getTime() - 5 * 2000) {
+ //console.log("Sending FECIsWriting");
+ console.log(config.enable_is_writing);
+ if (config.enable_is_writing == "True") {
+ ipcRenderer.send("tnc-fec-iswriting");
+ }
+ lastIsWritingBroadcast = new Date().getTime();
+ }
+ });
+
+ document.getElementById("expand_textarea").addEventListener("click", () => {
+ var textarea = document.getElementById("chatModuleMessage");
+
+ if (document.getElementById("expand_textarea").checked) {
+ var lines = 6;
+ document.getElementById("expand_textarea_button").className =
+ "bi bi-chevron-compact-down";
+ } else {
+ var lines = 1;
+ document.getElementById("expand_textarea_button").className =
+ "bi bi-chevron-compact-up";
+ }
+
+ var message_container_height_offset = 180 + 20 * lines;
+ //var message_container_height_offset = 90 + (23*lines);
+ var message_container_height = `calc(100% - ${message_container_height_offset}px)`;
+ document.getElementById("message-container").style.height =
+ message_container_height;
+ textarea.rows = lines;
+ console.log(textarea.rows);
+ });
+
+ // NEW CHAT
+
+ document
+ .getElementById("createNewChatButton")
+ .addEventListener("click", () => {
+ var dxcallsign = document.getElementById("chatModuleNewDxCall").value;
+ var uuid = uuidv4();
+ db.post({
+ _id: uuid,
+ timestamp: Math.floor(Date.now() / 1000),
+ dxcallsign: dxcallsign.toUpperCase(),
+ dxgrid: "---",
+ msg: "null",
+ checksum: "null",
+ type: "newchat",
+ status: "null",
+ uuid: uuid,
+ })
+ .then(function (response) {
+ // handle response
+ console.log("new database entry");
+ console.log(response);
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ update_chat_obj_by_uuid(uuid);
+ });
+
+ // open file selector for user image
+ document.getElementById("userImageSelector").addEventListener("click", () => {
+ ipcRenderer.send("select-user-image", {
+ title: "Title",
+ });
+ });
+
+ // open file selector for shared folder
+ document
+ .getElementById("sharedFolderButton")
+ .addEventListener("click", () => {
+ ipcRenderer.send("read-files-in-folder", {
+ folder: config.shared_folder_path,
+ });
+ });
+
+ document
+ .getElementById("openSharedFilesFolder")
+ .addEventListener("click", () => {
+ ipcRenderer.send("open-folder", {
+ path: config.shared_folder_path,
+ });
+ });
+
+ document
+ .getElementById("requestSharedFolderList")
+ .addEventListener("click", () => {
+ ipcRenderer.send("run-tnc-command", {
+ command: "requestSharedFolderList",
+ dxcallsign: selected_callsign,
+ });
+
+ pauseButton(document.getElementById("requestSharedFolderList"), 60000);
+ });
+
+ // SEND MSG
+ document.getElementById("sendMessage").addEventListener("click", () => {
+ document.getElementById("emojipickercontainer").style.display = "none";
+
+ var dxcallsign = selected_callsign.toUpperCase();
+ var textarea = document.getElementById("chatModuleMessage");
+ var chatmessage = textarea.value;
+ //Remove non-printable chars from begining and end of string--should save us a byte here and there
+ chatmessage = chatmessage.toString().trim();
+ // reset textarea size
+ var message_container_height_offset = 200;
+ var message_container_height = `calc(100% - ${message_container_height_offset}px)`;
+ document.getElementById("message-container").style.height =
+ message_container_height;
+ textarea.rows = 1;
+ document.getElementById("expand_textarea_button").className =
+ "bi bi-chevron-compact-up";
+ document.getElementById("expand_textarea").checked = false;
+
+ //console.log(file);
+ //console.log(filename);
+ //console.log(filetype);
+ if (filetype == "") {
+ filetype = "plain/text";
+ }
+ var timestamp = Math.floor(Date.now() / 1000);
+
+ var uuid = uuidv4();
+ let uuidlast = uuid.lastIndexOf("-");
+ uuidlast += 1;
+ if (uuidlast > 0) {
+ uuid = uuid.substring(uuidlast);
+ }
+
+ // check if broadcast
+ if (dxcallsign.startsWith("BC-")) {
+ //let broadcastChannelId = dxcallsign.split("BC-")[1];
+ //broadcastChannelIdCRC = crc32(broadcastChannelId)
+ // .toString(16)
+ // .toUpperCase();
+ //dxcallsignWithID = "BC-" + broadcastChannelIdCRC;
+ var tnc_command = "broadcast";
+ var message_type = "broadcast_transmit";
+
+ // slice uuid for reducing overhead
+ uuid = uuid.slice(-4);
+
+ let Data = {
+ command: tnc_command,
+ broadcastChannel: dxcallsign,
+ data: chatmessage,
+ uuid: uuid,
+ };
+ ipcRenderer.send("run-tnc-command", Data);
+ } else {
+ var message_type = "transmit";
+ var file_checksum = crc32(file).toString(16).toUpperCase();
+ var tnc_command = "msg";
+ var data_with_attachment =
+ timestamp +
+ split_char +
+ chatmessage +
+ split_char +
+ filename +
+ split_char +
+ filetype +
+ split_char +
+ file;
+
+ document.getElementById("selectFilesButton").innerHTML = ``;
+
+ console.log(data_with_attachment);
+ let Data = {
+ command: tnc_command,
+ dxcallsign: dxcallsign,
+ mode: 255,
+ frames: 5,
+ data: data_with_attachment,
+ checksum: file_checksum,
+ uuid: uuid,
+ };
+ ipcRenderer.send("run-tnc-command", Data);
+ }
+
+ db.post({
+ _id: uuid,
+ timestamp: timestamp,
+ dxcallsign: dxcallsign,
+ dxgrid: "null",
+ msg: chatmessage,
+ checksum: file_checksum,
+ type: message_type,
+ status: "transmit",
+ attempt: 1,
+ uuid: uuid,
+ _attachments: {
+ [filename]: {
+ content_type: filetype,
+ //data: btoa(file)
+ data: FD.btoa_FD(file),
+ },
+ },
+ })
+ .then(function (response) {
+ // handle response
+ console.log("new database entry");
+ console.log(response);
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ update_chat_obj_by_uuid(uuid);
+
+ // clear input
+ document.getElementById("chatModuleMessage").value = "";
+
+ // after adding file data to our attachment variable, delete it from global
+ filetype = "";
+ file = "";
+ filename = "";
+ });
+ // cleanup after transmission
+ filetype = "";
+ file = "";
+ filename = "";
+});
+
+ipcRenderer.on("return-selected-files", (event, arg) => {
+ filetype = arg.mime;
+ console.log(filetype);
+
+ file = arg.data;
+ filename = arg.filename;
+ document.getElementById("selectFilesButton").innerHTML = `
+
+ New file selected
+
+ `;
+});
+
+ipcRenderer.on("return-shared-folder-files", (event, arg) => {
+ console.log(arg);
+ sharedFolderFileList = arg.files;
+
+ var tbl = document.getElementById("sharedFolderTable");
+ if (tbl == undefined) return;
+ tbl.innerHTML = "";
+ let counter = 0;
+ arg.files.forEach((file) => {
+ //console.log(file["name"]);
+ var row = document.createElement("tr");
+
+ let id = document.createElement("td");
+ let idText = document.createElement("span");
+ idText.innerText = counter += 1;
+ id.appendChild(idText);
+ row.appendChild(id);
+
+ let filename = document.createElement("td");
+ let filenameText = document.createElement("span");
+ filenameText.innerText = file["name"];
+ filename.appendChild(filenameText);
+ row.appendChild(filename);
+
+ let filetype = document.createElement("td");
+ let filetypeText = document.createElement("span");
+ filetypeText.innerHTML = `
+
+ `;
+ filetype.appendChild(filetypeText);
+ row.appendChild(filetype);
+
+ let filesize = document.createElement("td");
+ let filesizeText = document.createElement("span");
+ filesizeText.innerText = formatBytes(file["size"], 2);
+ filesize.appendChild(filesizeText);
+ row.appendChild(filesize);
+
+ tbl.appendChild(row);
+ });
+});
+
+ipcRenderer.on("return-select-user-image", (event, arg) => {
+ let imageFiletype = arg.mime;
+ let imageFile = arg.data;
+
+ imageFile = blobUtil.base64StringToBlob(imageFile, imageFiletype);
+
+ var options = {
+ maxSizeMB: 0.01,
+ maxWidthOrHeight: 125,
+ useWebWorker: false,
+ };
+
+ imageCompression(imageFile, options)
+ .then(function (compressedFile) {
+ console.log(
+ "compressedFile instanceof Blob",
+ compressedFile instanceof Blob,
+ ); // true
+ console.log(
+ `compressedFile size ${compressedFile.size / 1024 / 1024} MB`,
+ ); // smaller than maxSizeMB
+
+ console.log(compressedFile.size);
+
+ blobUtil
+ .blobToBase64String(compressedFile)
+ .then(function (base64String) {
+ // update image
+
+ document.getElementById("user_info_image").src =
+ "data:" + imageFiletype + ";base64," + base64String;
+ })
+ .catch(function (err) {
+ document.getElementById("user_info_image").src = "img/icon.png";
+ });
+ })
+ .catch(function (error) {
+ console.log(error.message);
+ });
+});
+
+
+
+
+ipcRenderer.on("action-update-transmission-status", (event, arg) => {
+ var data = arg["data"][0];
+
+ if (data.status == "opening") return;
+ if (typeof data.uuid === undefined) return;
+
+ //console.log(data.status);
+ if (data.uuid !== "no-uuid") {
+ db.get(data.uuid, {
+ attachments: true,
+ })
+ .then(function (doc) {
+ return db.put({
+ _id: doc.uuid.toString(),
+ _rev: doc._rev,
+ timestamp: doc.timestamp,
+ dxcallsign: doc.dxcallsign,
+ dxgrid: doc.dxgrid,
+ msg: doc.msg,
+ checksum: doc.checksum,
+ type: "transmit",
+ status: data.status,
+ percent: data.percent,
+ bytesperminute: data.bytesperminute,
+ uuid: doc.uuid,
+ _attachments: doc._attachments,
+ });
+ })
+ .then(function (response) {
+ update_chat_obj_by_uuid(data.uuid);
+ })
+ .catch(function (err) {
+ console.log(err);
+ console.log(data);
+ });
+ }
+});
+
+//Render is typing message in correct chat window
+ipcRenderer.on("action-show-feciswriting", (event, arg) => {
+ //console.log("In action-show-feciswriting");
+ //console.log(arg);
+ let uuid = uuidv4.toString();
+ let dxcallsign = arg["data"][0]["dxcallsign"];
+ var new_message = `
+
+
${dxcallsign} is typing....
+
+
+ `;
+ var id = "chat-" + dxcallsign;
+ let chatwin = document.getElementById(id);
+ if (chatwin == undefined) {
+ //console.log("Element not found!!!!! :(");
+ return;
+ }
+ chatwin.insertAdjacentHTML("beforeend", new_message);
+ scrollMessagesToBottom();
+ let animIcon = document.getElementById("msg-" + uuid + "-icon");
+ //Remove notification after about 4.5 seconds hopefully enough time before a second notification can come in
+ setTimeout(function () {
+ animIcon.classList = "m-1 bi bi-wifi-2";
+ }, 1000);
+ setTimeout(function () {
+ animIcon.classList = "m-1 bi bi-wifi";
+ }, 2000);
+ setTimeout(function () {
+ animIcon.classList = "m-1 bi bi-wifi-2";
+ }, 3000);
+ setTimeout(function () {
+ animIcon.classList = "m-1 bi bi-wifi-1";
+ }, 4000);
+ setTimeout(() => {
+ let feciw = document.getElementById("msg-" + uuid);
+ feciw.remove();
+ }, 4500);
+});
+
+ipcRenderer.on("action-new-msg-received", (event, arg) => {
+ console.log(arg.data);
+
+ var new_msg = arg.data;
+ new_msg.forEach(function (item) {
+ let obj = new Object();
+
+ //handle broadcast
+ if (item.fec == "broadcast") {
+ console.log("BROADCAST RECEIVED");
+ console.log(item);
+ var transmitting_station = item.dxcallsign;
+ var encoded_data = FD.atob_FD(item.data);
+ var splitted_data = encoded_data.split(split_char);
+ console.log(splitted_data);
+ console.log(transmitting_station);
+ // add callsign to message:
+ var message = splitted_data[3];
+ console.log(message);
+ obj.timestamp = Math.floor(Date.now() / 1000);
+ obj.dxcallsign = splitted_data[1];
+ obj.dxgrid = "null";
+ obj.uuid = splitted_data[2];
+ obj.broadcast_sender = transmitting_station;
+ obj.command = "msg";
+ obj.checksum = "null";
+ obj.msg = message;
+ obj.status = "received";
+ obj.snr = item.snr;
+ obj.type = "broadcast_received";
+ obj.filename = "null";
+ obj.filetype = "null";
+ obj.file = "null";
+ obj.new = 1;
+ console.log(obj);
+ add_obj_to_database(obj);
+ update_chat_obj_by_uuid(obj.uuid);
+
+ db.find({
+ selector: {
+ dxcallsign: obj.dxcallsign,
+ },
+ }).then(function (result) {
+ // handle result
+ console.log(result);
+ });
+
+ //handle ping
+ } else if (item.ping == "received") {
+ obj.timestamp = parseInt(item.timestamp);
+ obj.dxcallsign = item.dxcallsign;
+ obj.dxgrid = item.dxgrid;
+ obj.uuid = item.uuid;
+ obj.command = "ping";
+ obj.checksum = "null";
+ obj.msg = "null";
+ obj.status = item.status;
+ obj.hmac_signed = item.hmac_signed;
+ obj.snr = item.snr;
+ obj.type = "ping";
+ obj.filename = "null";
+ obj.filetype = "null";
+ obj.file = "null";
+ obj.new = 0;
+
+ add_obj_to_database(obj);
+ update_chat_obj_by_uuid(obj.uuid);
+ // check for messages which failed and try to transmit them
+ if (config.enable_auto_retry.toUpperCase() == "TRUE") {
+ checkForWaitingMessages(obj.dxcallsign);
+ }
+
+ // handle ping-ack
+ } else if (item.ping == "acknowledge") {
+ obj.timestamp = parseInt(item.timestamp);
+ obj.dxcallsign = item.dxcallsign;
+ obj.dxgrid = item.dxgrid;
+ obj.uuid = item.uuid;
+ obj.command = "ping-ack";
+ obj.checksum = "null";
+ obj.msg = "null";
+ obj.status = item.status;
+ obj.snr = item.dxsnr + "/" + item.snr;
+ obj.type = "ping-ack";
+ obj.filename = "null";
+ obj.filetype = "null";
+ obj.file = "null";
+ obj.new = 0;
+ add_obj_to_database(obj);
+ update_chat_obj_by_uuid(obj.uuid);
+
+ // handle beacon
+ } else if (item.beacon == "received") {
+ obj.timestamp = parseInt(item.timestamp);
+ obj.dxcallsign = item.dxcallsign;
+ obj.dxgrid = item.dxgrid;
+ obj.uuid = item.uuid;
+ obj.command = "beacon";
+ obj.checksum = "null";
+ obj.msg = "null";
+ obj.status = item.status;
+ obj.snr = item.snr;
+ obj.type = "beacon";
+ obj.filename = "null";
+ obj.filetype = "null";
+ obj.file = "null";
+ obj.new = 0;
+ add_obj_to_database(obj);
+ update_chat_obj_by_uuid(obj.uuid);
+ // check for messages which failed and try to transmit them
+ if (config.enable_auto_retry.toUpperCase() == "TRUE") {
+ checkForWaitingMessages(obj.dxcallsign);
+ }
+ // handle ARQ transmission
+ } else if (item.arq == "transmission" && item.status == "received") {
+ //var encoded_data = atob(item.data);
+ //var encoded_data = Buffer.from(item.data,'base64').toString('utf-8');
+ var encoded_data = FD.atob_FD(item.data);
+ var splitted_data = encoded_data.split(split_char);
+
+ console.log(splitted_data);
+
+ if (splitted_data[1] == "msg") {
+ obj.timestamp = parseInt(splitted_data[4]);
+ obj.dxcallsign = item.dxcallsign;
+ obj.dxgrid = item.dxgrid;
+ obj.command = splitted_data[1];
+ obj.checksum = splitted_data[2];
+ obj.uuid = splitted_data[3];
+ obj.msg = splitted_data[5];
+ obj.status = "null";
+ obj.snr = "null";
+ obj.type = "received";
+ obj.filename = splitted_data[6];
+ obj.filetype = splitted_data[7];
+ //obj.file = btoa(splitted_data[8]);
+ obj.file = FD.btoa_FD(splitted_data[8]);
+ obj.hmac_signed = item.hmac_signed;
+ obj.new = 1;
+ } else if (splitted_data[1] == "req" && splitted_data[2] == "0") {
+ obj.uuid = uuidv4().toString();
+ obj.timestamp = Math.floor(Date.now() / 1000);
+ obj.dxcallsign = item.dxcallsign;
+ obj.command = splitted_data[1];
+ obj.type = "request";
+ obj.status = "received";
+ obj.snr = "null";
+ obj.msg = "Request for station info";
+ obj.filename = "null";
+ obj.filetype = "null";
+ obj.file = "null";
+ obj.hmac_signed = item.hmac_signed;
+ obj.new = 0;
+ if (config.enable_request_profile == "True") {
+ sendUserData(item.dxcallsign);
+ }
+ } else if (splitted_data[1] == "req" && splitted_data[2] == "1") {
+ obj.uuid = uuidv4().toString();
+ obj.timestamp = Math.floor(Date.now() / 1000);
+ obj.dxcallsign = item.dxcallsign;
+ obj.command = splitted_data[1];
+ obj.type = "request";
+ obj.status = "received";
+ obj.snr = "null";
+ obj.msg = "Request for shared folder list";
+ obj.filename = "null";
+ obj.filetype = "null";
+ obj.file = "null";
+ obj.hmac_signed = item.hmac_signed;
+ obj.new = 0;
+ if (config.enable_request_shared_folder == "True") {
+ sendSharedFolderList(item.dxcallsign);
+ }
+ } else if (
+ splitted_data[1] == "req" &&
+ splitted_data[2].substring(0, 1) == "2"
+ ) {
+ let name = splitted_data[2].substring(1);
+ //console.log("In handle req for shared folder file");
+ obj.uuid = uuidv4().toString();
+ obj.timestamp = Math.floor(Date.now() / 1000);
+ obj.dxcallsign = item.dxcallsign;
+ obj.command = splitted_data[1];
+ obj.type = "request";
+ obj.status = "received";
+ obj.snr = "null";
+ obj.msg = "Request for shared file " + name;
+ obj.filename = "null";
+ obj.filetype = "null";
+ obj.file = "null";
+ obj.hmac_signed = item.hmac_signed;
+ obj.new = 0;
+ if (config.enable_request_shared_folder == "True") {
+ sendSharedFolderFile(item.dxcallsign, name);
+ }
+ } else if (splitted_data[1] == "res-0") {
+ obj.uuid = uuidv4().toString();
+ obj.timestamp = Math.floor(Date.now() / 1000);
+ obj.dxcallsign = item.dxcallsign;
+ obj.command = splitted_data[1];
+ obj.type = "response";
+ obj.status = "received";
+ obj.snr = "null";
+ obj.msg = "Response for station info";
+ obj.filename = "null";
+ obj.filetype = "null";
+ obj.file = "null";
+ obj.hmac_signed = item.hmac_signed;
+ obj.new = 0;
+ console.log(splitted_data);
+ let userData = new Object();
+ userData.user_info_image = splitted_data[2];
+ userData.user_info_callsign = splitted_data[3];
+ userData.user_info_gridsquare = splitted_data[4];
+ userData.user_info_name = splitted_data[5];
+ userData.user_info_age = splitted_data[6];
+ userData.user_info_location = splitted_data[7];
+ userData.user_info_radio = splitted_data[8];
+ userData.user_info_antenna = splitted_data[9];
+ userData.user_info_email = splitted_data[10];
+ userData.user_info_website = splitted_data[11];
+ userData.user_info_comments = splitted_data[12];
+
+ addUserToDatabaseIfNotExists(userData);
+ getSetUserInformation(splitted_data[3]);
+ } else if (splitted_data[1] == "res-1") {
+ obj.uuid = uuidv4().toString();
+ obj.timestamp = Math.floor(Date.now() / 1000);
+ obj.dxcallsign = item.dxcallsign;
+ obj.command = splitted_data[1];
+ obj.type = "response";
+ obj.status = "received";
+ obj.snr = "null";
+ obj.msg = "Response for shared file list";
+ obj.filename = "null";
+ obj.filetype = "null";
+ obj.file = "null";
+ obj.hmac_signed = item.hmac_signed;
+ obj.new = 0;
+ console.log(splitted_data);
+
+ let userData = new Object();
+
+ userData.user_info_callsign = obj.dxcallsign;
+ let filelist = JSON.parse(splitted_data[3]);
+ console.log(filelist);
+ userData.user_shared_folder = filelist;
+ addFileListToUserDatabaseIfNotExists(userData);
+ getSetUserSharedFolder(obj.dxcallsign);
+
+ //getSetUserInformation(selected_callsign);
+ } else if (splitted_data[1] == "res-2") {
+ console.log("In received response-2");
+ let sharedFileInfo = splitted_data[2].split("/", 2);
+
+ obj.uuid = uuidv4().toString();
+ obj.timestamp = Math.floor(Date.now() / 1000);
+ obj.dxcallsign = item.dxcallsign;
+ obj.command = splitted_data[1];
+ obj.type = "received";
+ obj.status = "received";
+ obj.snr = "null";
+ obj.msg = "Response for shared file download";
+ obj.filename = sharedFileInfo[0];
+ obj.filetype = "application/octet-stream";
+ obj.file = FD.btoa_FD(sharedFileInfo[1]);
+ obj.hmac_signed = item.hmac_signed;
+ obj.new = 0;
+ } else {
+ console.log("no rule matched for handling received data!");
+ }
+
+ add_obj_to_database(obj);
+ update_chat_obj_by_uuid(obj.uuid);
+ }
+ });
+ //window.location = window.location;
+});
+
+// Update chat list
+update_chat = function (obj) {
+ var dxcallsign = obj.dxcallsign;
+ var timestamp = dateFormat.format(obj.timestamp * 1000);
+ //var timestampShort = dateFormatShort.format(obj.timestamp * 1000);
+ var timestampHours = dateFormatHours.format(obj.timestamp * 1000);
+
+ var dxgrid = obj.dxgrid;
+
+ // check if obj.attempt exists
+ if (typeof obj.attempt == "undefined") {
+ db.upsert(obj._id, function (doc) {
+ if (!doc.attempt) {
+ doc.attempt = 1;
+ }
+ return doc;
+ });
+ var attempt = 1;
+ obj.attempt = attempt;
+ } else {
+ var attempt = obj.attempt;
+ }
+
+
+ // add percent and bytes per minute if not existing
+ //console.log(obj.percent)
+ if (typeof obj.percent == "undefined") {
+ obj.percent = 0;
+ obj.bytesperminute = 0;
+ }
+
+ // check if wrong status message
+ if (
+ obj.status == "transmitting" &&
+ obj.type == "transmit" &&
+ obj.percent < 100
+ ) {
+ var TimeDifference = new Date().getTime() / 1000 - obj.timestamp;
+ if (TimeDifference > 21600) {
+ //Six hours
+ console.log(
+ "Resetting message to failed state since in transmit status for over 6 hours:",
+ );
+ console.log(obj);
+ db.upsert(obj._id, function (doc) {
+ doc.status = "failed";
+ return doc;
+ });
+ obj.status = "failed";
+ }
+ }
+ // check if in transmitting status and @ 100%
+ if (
+ obj.status == "transmitting" &&
+ obj.type == "transmit" &&
+ obj.percent == 100
+ ) {
+ var TimeDifference = new Date().getTime() / 1000 - obj.timestamp;
+ if (TimeDifference > 21600) {
+ //Six hours
+ console.log(
+ "Resetting message to transmitted since in transmit state and at 100%:",
+ );
+ console.log(obj);
+ db.upsert(obj._id, function (doc) {
+ doc.status = "transmitted";
+ return doc;
+ });
+ obj.status = "transmitted";
+ }
+ }
+ if (typeof obj.new == "undefined") {
+ obj.new = 0;
+ }
+
+ if (typeof config.max_retry_attempts == "undefined") {
+ var max_retry_attempts = 3;
+ } else {
+ var max_retry_attempts = parseInt(config.max_retry_attempts);
+ }
+ //console.log(obj.msg);
+ // define shortmessage
+ if (obj.msg == "null" || obj.msg == "NULL") {
+ var shortmsg = obj.type;
+ } else {
+ var shortmsg = obj.msg;
+ var maxlength = 30;
+ var shortmsg =
+ shortmsg.length > maxlength
+ ? shortmsg.substring(0, maxlength - 3) + "..."
+ : shortmsg;
+ }
+ try {
+ //console.log(Object.keys(obj._attachments)[0].length)
+ if (
+ typeof obj._attachments !== "undefined" &&
+ Object.keys(obj._attachments)[0].length > 0
+ ) {
+ //var filename = obj._attachments;
+ var filename = Object.keys(obj._attachments)[0];
+ var filetype = filename.split(".")[1];
+ var filesize = obj._attachments[filename]["length"] + " Bytes";
+ if (filesize == "undefined Bytes") {
+ // get filesize of new submitted data
+ // not that nice....
+ // we really should avoid converting back from base64 for performance reasons...
+ //var filesize = Math.ceil(atob(obj._attachments[filename]["data"]).length) + "Bytes";
+ var filesize =
+ Math.ceil(FD.atob_FD(obj._attachments[filename]["data"]).length) +
+ " Bytes";
+ }
+
+ // check if image, then display it
+ if (filetype == "image/png" || filetype == "png") {
+ var fileheader = `
+
+
+ `;
+ } else {
+ var fileheader = `
+
+
+ `;
+ }
+
+ var controlarea_transmit = `
+
+
+
+
+
+
+ `;
+
+ var controlarea_receive = `
+
+
+
+
+
+
+ `;
+ } else {
+ var filename = "";
+ var fileheader = "";
+ var filetype = "text/plain";
+ var controlarea_transmit = `
+
+
+
+
+ `;
+ var controlarea_receive = `
+
+
+
+ `;
+ }
+ } catch (err) {
+ console.log("error with database parsing...");
+ console.log(err);
+ }
+ // CALLSIGN LIST
+ if (!document.getElementById("chat-" + dxcallsign + "-list")) {
+ // increment callsign counter
+ callsign_counter++;
+ dxcallsigns.add(dxcallsign);
+ if (
+ (callsign_counter == 1 && selected_callsign == "") ||
+ selected_callsign == dxcallsign
+ ) {
+ var callsign_selected = "active show";
+ //document.getElementById('chatModuleDxCall').value = dxcallsign;
+ selected_callsign = dxcallsign;
+ }
+
+ if (dxcallsign.startsWith("BC-")) {
+ var user_image =
+ ' ';
+ } else {
+ var user_image =
+ ' ';
+
+ getSetUserInformation(dxcallsign);
+ getSetUserSharedFolder(dxcallsign);
+ }
+
+ var new_callsign = `
+
+
+
+
+ ${user_image}
+
+
+
+
${dxcallsign}
+
${dxgrid}
+
${timestampHours}
+
${shortmsg}
+
+
+
+
+ `;
+
+ document
+ .getElementById("list-tab-chat")
+ .insertAdjacentHTML("beforeend", new_callsign);
+ var message_area = `
+
+ `;
+ document
+ .getElementById("nav-tabContent-Chat")
+ .insertAdjacentHTML("beforeend", message_area);
+
+ // finally get and set user information to first selected item
+ getSetUserInformation(selected_callsign);
+ getSetUserSharedFolder(selected_callsign);
+
+ // create eventlistener for listening on clicking on a callsign
+ document
+ .getElementById("chat-" + dxcallsign + "-list")
+ .addEventListener("click", function () {
+ //document.getElementById('chatModuleDxCall').value = dxcallsign;
+ selected_callsign = dxcallsign;
+ //Reset unread messages and new message indicator
+ let clear = selected_callsign;
+ clearUnreadMessages(clear);
+ document.getElementById(
+ `chat-${selected_callsign}-list-displaydxcall`,
+ ).textContent = selected_callsign;
+ document
+ .getElementById(`chat-${selected_callsign}-list`)
+ .classList.remove("list-group-item-warning");
+ setTimeout(scrollMessagesToBottom, 200);
+
+ //get user information
+ getSetUserInformation(selected_callsign);
+ getSetUserSharedFolder(selected_callsign);
+ if (selected_callsign.startsWith("BC-")) {
+ document
+ .getElementById("chatModuleMessage")
+ .setAttribute("maxlength", 16);
+ //console.log("Setting max message size to 16")
+ } else {
+ document
+ .getElementById("chatModuleMessage")
+ .setAttribute("maxlength", 524288);
+ //console.log("Setting max message size to big#")
+ }
+ });
+
+ // if callsign entry already exists - update
+ } else {
+ // gridsquare - update only on receive
+ if (obj.type !== "transmit") {
+ document.getElementById("chat-" + dxcallsign + "-list-dxgrid").innerHTML =
+ dxgrid;
+ }
+ // time
+ document.getElementById("chat-" + dxcallsign + "-list-time").innerHTML =
+ timestampHours;
+ // short message
+ document.getElementById("chat-" + dxcallsign + "-list-shortmsg").innerHTML =
+ shortmsg;
+ if (obj.new == 1) {
+ document.getElementById(
+ `chat-${obj.dxcallsign}-list-displaydxcall`,
+ ).textContent = "*" + obj.dxcallsign;
+ document
+ .getElementById(`chat-${dxcallsign}-list`)
+ .classList.add("list-group-item-warning");
+ }
+ }
+ // APPEND MESSAGES TO CALLSIGN
+
+ if (!document.getElementById("msg-" + obj._id)) {
+ if (obj.type == "ping") {
+ //if (obj.new == 1)
+ //{
+ // showOsPopUp("Ping from " + obj.dxcallsign,"You've been ping'd!");
+ //}
+ var new_message = `
+
+
snr: ${obj.snr} - ${timestamp}
+
+ `;
+ }
+ if (obj.type == "ping-ack") {
+ var new_message = `
+
+
Ping ack dx/mine snr: ${obj.snr} - ${timestamp}
+
+ `;
+ }
+ if (obj.type == "beacon") {
+ var new_message = `
+
+
snr: ${obj.snr} - ${timestamp}
+
+ `;
+ }
+ if (obj.type == "request") {
+ var new_message = `
+
+
${obj.msg} - ${timestamp}
+
+ `;
+ }
+ if (obj.type == "response") {
+ var new_message = `
+
+
Response - ${timestamp}
+
+ `;
+ }
+ if (obj.type == "newchat") {
+ var new_message = `
+
+
new chat opened - ${timestamp}
+
+ `;
+ }
+
+ // CHECK FOR NEW LINE AND REPLACE WITH
+ var message_html = obj.msg.replaceAll(/\n/g, " ");
+
+ if (obj.type == "received") {
+ if (obj.new == 1) {
+ showOsPopUp("Message received from " + obj.dxcallsign, obj.msg);
+ }
+
+
+ // check if message is signed or not for adjusting icon
+ if(typeof obj.hmac_signed !== "undefined" && obj.hmac_signed !== "False"){
+ console.log(hmac_signed)
+ var hmac_signed = ' ';
+ } else {
+
+ var hmac_signed = ' ';
+
+ }
+
+
+ var new_message = `
+
+
+
+
+ ${fileheader}
+
+
+
${message_html}
+
+ ${timestamp}
+
+
+
+
+
+
+ ${hmac_signed}
+
+
+
+
+
+ ${controlarea_receive}
+
+ `;
+ }
+
+ if (obj.type == "broadcast_received") {
+ console.log(obj);
+ var new_message = `
+
+
+
+
+
+
${message_html}
+
+ ${timestamp}
+
+
+
+
+
+ ${obj.broadcast_sender}
+ dxcallsign
+
+
+
+
+
+
+
+
+ `;
+ }
+ if (obj.type == "broadcast_transmit") {
+ var new_message = `
+
+
+
+
+
+
+
+
+
${message_html}
+
+ ${timestamp} -
+ ${get_icon_for_state(
+ obj.status,
+ )}
+
+
+
+ ${attempt}/${max_retry_attempts}
+ retries
+
+
+
+
+
+ `;
+ }
+
+ if (obj.type == "transmit") {
+ //console.log(obj);
+ //console.log('msg-' + obj._id + '-status')
+
+ if (obj.status == "failed") {
+ var progressbar_bg = "bg-danger";
+ var percent_value = "TRANSMISSION FAILED";
+ //Set to 100 so progressbar background populates
+ obj.percent = 100;
+ } else if (obj.status == "transmitted") {
+ var progressbar_bg = "bg-success";
+ var percent_value = "TRANSMITTED";
+ } else {
+ var progressbar_bg = "bg-primary";
+ var percent_value = obj.percent + " %";
+ }
+
+ //Sneak in low graphics mode if so enabled for progress bars
+ if (config.high_graphics.toString().toUpperCase() != "TRUE") {
+ progressbar_bg += " disable-effects";
+ //console.log("Low graphics enabled for chat module");
+ }
+
+ var new_message = `
+
+ ${controlarea_transmit}
+
+
+ ${fileheader}
+
+
${message_html}
+
+ ${timestamp} -
+ ${get_icon_for_state(
+ obj.status,
+ )}
+
+
+
+ ${attempt}/${max_retry_attempts}
+ retries
+
+
+
+
${percent_value} - ${
+ obj.bytesperminute
+ } Bpm
+
+
+
+
+
+ `;
+ }
+ // CHECK CHECK CHECK --> This could be done better
+ var id = "chat-" + obj.dxcallsign;
+ document.getElementById(id).insertAdjacentHTML("beforeend", new_message);
+
+ /* UPDATE EXISTING ELEMENTS */
+ } else if (document.getElementById("msg-" + obj._id)) {
+ //console.log("element already exists......");
+ //console.log(obj);
+
+ // console.log(obj.status)
+ // console.log(obj.attempt)
+
+ if (
+ obj.status != "broadcast_transmit" ||
+ obj.status != "broadcast_received"
+ ) {
+ document.getElementById("msg-" + obj._id + "-status").innerHTML =
+ get_icon_for_state(obj.status);
+
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .setAttribute("aria-valuenow", obj.percent);
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .setAttribute("style", "width:" + obj.percent + "%;");
+ document.getElementById(
+ "msg-" + obj._id + "-progress-information",
+ ).innerHTML = obj.percent + "% - " + obj.bytesperminute + " Bpm";
+
+ document.getElementById("msg-" + obj._id + "-attempts").innerHTML =
+ obj.attempt + "/" + max_retry_attempts;
+ }
+
+ if (obj.status == "transmit") {
+ document.getElementById("msg-" + obj._id + "-status").innerHTML =
+ get_icon_for_state(obj.status);
+
+ if (typeof obj.percent !== "undefined") {
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .setAttribute("aria-valuenow", obj.percent);
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .setAttribute("style", "width:" + obj.percent + "%;");
+ document.getElementById(
+ "msg-" + obj._id + "-progress-information",
+ ).innerHTML = obj.percent + "% - " + obj.bytesperminute + " Bpm";
+ } else {
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .setAttribute("aria-valuenow", 0);
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .setAttribute("style", "width:0%;");
+ document.getElementById(
+ "msg-" + obj._id + "-progress-information",
+ ).innerHTML = "0% - 0 Bpm";
+ }
+
+ document.getElementById("msg-" + obj._id + "-attempts").innerHTML =
+ obj.attempt + "/" + max_retry_attempts;
+ }
+
+ if (obj.status == "transmitted") {
+ //document.getElementById('msg-' + obj._id + '-progress').classList.remove("progress-bar-striped");
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .classList.remove("progress-bar-animated");
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .classList.remove("bg-danger");
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .classList.add("bg-success");
+
+ document.getElementById("msg-" + obj._id + "-progress").innerHTML = "";
+ document.getElementById(
+ "msg-" + obj._id + "-progress-information",
+ ).innerHTML = "TRANSMITTED - " + obj.bytesperminute + " Bpm";
+ } else if (
+ obj.status != "broadcast_transmit" ||
+ obj.status != "broadcast_received"
+ ) {
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .classList.add("progress-bar-striped");
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .classList.add("progress-bar-animated");
+ }
+
+ if (obj.status == "failed") {
+ //document.getElementById('msg-' + obj._id + '-progress').classList.remove("progress-bar-striped");
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .classList.remove("progress-bar-animated");
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .classList.remove("bg-primary");
+ document
+ .getElementById("msg-" + obj._id + "-progress")
+ .classList.add("bg-danger");
+
+ console.log(
+ document.getElementById("msg-" + obj._id + "-progress").classList,
+ );
+
+ document.getElementById(
+ "msg-" + obj._id + "-progress-information",
+ ).innerHTML = "TRANSMISSION FAILED - " + obj.bytesperminute + " Bpm";
+ }
+
+ //document.getElementById(id).className = message_class;
+ }
+
+ //Delete message event listener
+ if (
+ document.getElementById("del-msg-" + obj._id) &&
+ !document
+ .getElementById("del-msg-" + obj._id)
+ .hasAttribute("listenerOnClick")
+ ) {
+ // set Attribute to determine if we already created an EventListener for this element
+ document
+ .getElementById("del-msg-" + obj._id)
+ .setAttribute("listenerOnClick", "true");
+ document
+ .getElementById("del-msg-" + obj._id)
+ .addEventListener("click", () => {
+ db.get(obj._id, {
+ attachments: true,
+ })
+ .then(function (doc) {
+ db.remove(doc._id, doc._rev, function (err) {
+ if (err) console.log("Error removing item " + err);
+ });
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+
+ document.getElementById("msg-" + obj._id).remove();
+ document.getElementById("msg-" + obj._id + "-control-area").remove();
+ console.log("Removed message " + obj._id.toString());
+
+ // stop transmission if deleted message is still in progress
+ if (obj.status == "transmitting") {
+ let Data = {
+ command: "stop_transmission",
+ };
+ ipcRenderer.send("run-tnc-command", Data);
+ }
+ });
+ //scrollMessagesToBottom();
+ }
+
+ // CREATE SAVE TO FOLDER EVENT LISTENER
+ if (
+ document.getElementById("save-file-msg-" + obj._id) &&
+ !document
+ .getElementById("save-file-msg-" + obj._id)
+ .hasAttribute("listenerOnClick")
+ ) {
+ // set Attribute to determine if we already created an EventListener for this element
+ document
+ .getElementById("save-file-msg-" + obj._id)
+ .setAttribute("listenerOnClick", "true");
+
+ document
+ .getElementById("save-file-msg-" + obj._id)
+ .addEventListener("click", () => {
+ saveFileToFolder(obj._id);
+ });
+ }
+ // CREATE RESEND MSG EVENT LISTENER
+
+ // check if element exists and if we already created NOT created an event listener
+ if (
+ document.getElementById("retransmit-msg-" + obj._id) &&
+ !document
+ .getElementById("retransmit-msg-" + obj._id)
+ .hasAttribute("listenerOnClick")
+ ) {
+ // set Attribute to determine if we already created an EventListener for this element
+ document
+ .getElementById("retransmit-msg-" + obj._id)
+ .setAttribute("listenerOnClick", "true");
+ document
+ .getElementById("retransmit-msg-" + obj._id)
+ .addEventListener("click", () => {
+ // increment attempt
+ db.upsert(obj._id, function (doc) {
+ if (!doc.attempt) {
+ doc.attempt = 1;
+ }
+ doc.attempt++;
+ return doc;
+ })
+ .then(function (res) {
+ // success, res is {rev: '1-xxx', updated: true, id: 'myDocId'}
+ console.log(res);
+ update_chat_obj_by_uuid(obj.uuid);
+ })
+ .catch(function (err) {
+ // error
+ console.log(err);
+ });
+
+ db.get(obj._id, {
+ attachments: true,
+ })
+ .then(function (doc) {
+ // handle doc
+ console.log(doc);
+
+ var filename = Object.keys(obj._attachments)[0];
+ var filetype = filename.content_type;
+
+ console.log(filename);
+ console.log(filetype);
+ var file = obj._attachments[filename].data;
+ console.log(file);
+ console.log(Object.keys(obj._attachments)[0].data);
+
+ //var file = atob(obj._attachments[filename]["data"])
+ db.getAttachment(obj._id, filename).then(function (data) {
+ console.log(data);
+ //Rewrote this part to use buffers to ensure encoding is corect -- n1qm
+ var binaryString = FD.atob_FD(data);
+
+ console.log(binaryString);
+ var data_with_attachment =
+ doc.timestamp +
+ split_char +
+ doc.msg +
+ split_char +
+ filename +
+ split_char +
+ filetype +
+ split_char +
+ binaryString;
+ let Data = {
+ command: "msg",
+ dxcallsign: doc.dxcallsign,
+ mode: 255,
+ frames: 5,
+ data: data_with_attachment,
+ checksum: doc.checksum,
+ uuid: doc.uuid,
+ };
+ console.log(Data);
+ ipcRenderer.send("run-tnc-command", Data);
+ });
+ /*
+ // convert blob data to binary string
+ blobUtil.blobToBinaryString(data).then(function (binaryString) {
+ console.log(binaryString)
+ }).catch(function (err) {
+ // error
+ console.log(err);
+ binaryString = blobUtil.arrayBufferToBinaryString(data);
+
+ }).then(function(){
+
+ console.log(binaryString)
+ console.log(binaryString.length)
+
+ var data_with_attachment = doc.timestamp + split_char + utf8.encode(doc.msg) + split_char + filename + split_char + filetype + split_char + binaryString;
+ let Data = {
+ command: "msg",
+ dxcallsign: doc.dxcallsign,
+ mode: 255,
+ frames: 1,
+ data: data_with_attachment,
+ checksum: doc.checksum,
+ uuid: doc.uuid
+ };
+ console.log(Data)
+ ipcRenderer.send('run-tnc-command', Data);
+
+ });
+ });
+ */
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ });
+ }
+ //window.location = window.location
+
+ // scroll to bottom on new message
+ scrollMessagesToBottom();
+};
+
+function saveFileToFolder(id) {
+ db.get(id, {
+ attachments: true,
+ })
+ .then(function (obj) {
+ console.log(obj);
+ console.log(Object.keys(obj._attachments)[0].content_type);
+ var filename = Object.keys(obj._attachments)[0];
+ var filetype = filename.content_type;
+ var file = filename.data;
+ console.log(file);
+ console.log(filename.data);
+ db.getAttachment(id, filename)
+ .then(function (data) {
+ // handle result
+ console.log(data.length);
+ //data = new Blob([data.buffer], { type: 'image/png' } /* (1) */)
+ console.log(data);
+ // we need to encode data because of error "an object could not be cloned"
+ let Data = {
+ file: data,
+ filename: filename,
+ filetype: filetype,
+ };
+ console.log(Data);
+ ipcRenderer.send("save-file-to-folder", Data);
+ })
+ .catch(function (err) {
+ console.log(err);
+ return false;
+ });
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+}
+
+// function for setting an ICON to the corresponding state
+function get_icon_for_state(state) {
+ if (state == "transmit") {
+ var status_icon = '
';
+ } else if (state == "transmitting") {
+ //var status_icon = '
';
+ var status_icon = `
+
+ `;
+ } else if (state == "failed") {
+ var status_icon =
+ '
';
+ } else if (state == "transmitted") {
+ var status_icon = '
';
+ } else {
+ var status_icon = '
';
+ }
+ return status_icon;
+}
+
+update_chat_obj_by_uuid = function (uuid) {
+ db.get(uuid, {
+ attachments: true,
+ })
+ .then(function (doc) {
+ update_chat(doc);
+ //return doc
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+};
+
+add_obj_to_database = function (obj) {
+ console.log(obj);
+ db.put({
+ _id: obj.uuid,
+ timestamp: parseInt(obj.timestamp),
+ broadcast_sender: obj.broadcast_sender,
+ uuid: obj.uuid,
+ dxcallsign: obj.dxcallsign,
+ dxgrid: obj.dxgrid,
+ msg: obj.msg,
+ checksum: obj.checksum,
+ type: obj.type,
+ command: obj.command,
+ status: obj.status,
+ snr: obj.snr,
+ attempt: obj.attempt,
+ hmac_signed: obj.hmac_signed,
+ new: obj.new,
+ _attachments: {
+ [obj.filename]: {
+ content_type: obj.filetype,
+ data: obj.file,
+ },
+ },
+ })
+ .then(function (response) {
+ console.log("new database entry");
+ console.log(response);
+ })
+ .catch(function (err) {
+ console.log("already exists");
+ console.log(err);
+ console.log(obj);
+ db.upsert(obj.uuid, function (doc) {
+ doc = obj;
+ return doc;
+ })
+ .then(function (response) {
+ console.log("upsert");
+ console.log(response);
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ });
+};
+/* users database functions */
+addUserToDatabaseIfNotExists = function (obj) {
+ /*
+ "user_info_callsign",
+ "user_info_gridsquare",
+ "user_info_name",
+ "user_info_age",
+ "user_info_location",
+ "user_info_radio",
+ "user_info_antenna",
+ "user_info_email",
+ "user_info_website",
+ "user_info_comments",
+*/
+ console.log(obj);
+ users
+ .find({
+ selector: {
+ user_info_callsign: obj.user_info_callsign,
+ },
+ })
+ .then(function (result) {
+ // handle result
+ console.log(result);
+ if (result.docs.length > 0) {
+ users
+ .put({
+ _id: result.docs[0]._id,
+ _rev: result.docs[0]._rev,
+ user_info_callsign: obj.user_info_callsign,
+ user_info_gridsquare: obj.user_info_gridsquare,
+ user_info_name: obj.user_info_name,
+ user_info_age: obj.user_info_age,
+ user_info_location: obj.user_info_location,
+ user_info_radio: obj.user_info_radio,
+ user_info_antenna: obj.user_info_antenna,
+ user_info_email: obj.user_info_email,
+ user_info_website: obj.user_info_website,
+ user_info_comments: obj.user_info_comments,
+ user_info_image: obj.user_info_image,
+ })
+ .then(function (response) {
+ console.log("UPDATED USER");
+ console.log(response);
+ console.log(obj);
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ } else {
+ users
+ .post({
+ user_info_callsign: obj.user_info_callsign,
+ user_info_gridsquare: obj.user_info_gridsquare,
+ user_info_name: obj.user_info_name,
+ user_info_age: obj.user_info_age,
+ user_info_location: obj.user_info_location,
+ user_info_radio: obj.user_info_radio,
+ user_info_antenna: obj.user_info_antenna,
+ user_info_email: obj.user_info_email,
+ user_info_website: obj.user_info_website,
+ user_info_comments: obj.user_info_comments,
+ })
+ .then(function (response) {
+ console.log("NEW USER ADDED");
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ }
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+};
+
+addFileListToUserDatabaseIfNotExists = function (obj) {
+ console.log(obj);
+ users
+ .find({
+ selector: {
+ user_info_callsign: obj.user_info_callsign,
+ },
+ })
+ .then(function (result) {
+ // handle result
+ if (result.docs.length > 0) {
+ users
+ .put({
+ _id: result.docs[0]._id,
+ _rev: result.docs[0]._rev,
+ user_shared_folder: obj.user_shared_folder,
+ user_info_callsign: result.docs[0].user_info_callsign,
+ user_info_gridsquare: result.docs[0].user_info_gridsquare,
+ user_info_name: result.docs[0].user_info_name,
+ user_info_age: result.docs[0].user_info_age,
+ user_info_location: result.docs[0].user_info_location,
+ user_info_radio: result.docs[0].user_info_radio,
+ user_info_antenna: result.docs[0].user_info_antenna,
+ user_info_email: result.docs[0].user_info_email,
+ user_info_website: result.docs[0].user_info_website,
+ user_info_comments: result.docs[0].user_info_comments,
+ })
+ .then(function (response) {
+ console.log("File List: UPDATED USER");
+ console.log(response);
+ console.log(obj);
+ getSetUserSharedFolder(obj.user_info_callsign);
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ } else {
+ users
+ .post({
+ user_info_callsign: obj.user_info_callsign,
+ user_shared_folder: obj.user_shared_folder,
+ })
+ .then(function (response) {
+ console.log("File List: NEW USER ADDED");
+ getSetUserSharedFolder(obj.user_info_callsign);
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ }
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+};
+
+// Scroll to bottom of message-container
+function scrollMessagesToBottom() {
+ var messageBody = document.getElementById("message-container");
+ messageBody.scrollTop = messageBody.scrollHeight - messageBody.clientHeight;
+}
+
+// CRC CHECKSUMS
+// https://stackoverflow.com/a/50579690
+// crc32 calculation
+//console.log(crc32('abc'));
+//var crc32=function(r){for(var a,o=[],c=0;c<256;c++){a=c;for(var f=0;f<8;f++)a=1&a?3988292384^a>>>1:a>>>1;o[c]=a}for(var n=-1,t=0;t
>>8^o[255&(n^r.charCodeAt(t))];return(-1^n)>>>0};
+//console.log(crc32('abc').toString(16).toUpperCase()); // hex
+
+var makeCRCTable = function () {
+ var c;
+ var crcTable = [];
+ for (var n = 0; n < 256; n++) {
+ c = n;
+ for (var k = 0; k < 8; k++) {
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
+ }
+ crcTable[n] = c;
+ }
+ return crcTable;
+};
+
+var crc32 = function (str) {
+ var crcTable = window.crcTable || (window.crcTable = makeCRCTable());
+ var crc = 0 ^ -1;
+
+ for (var i = 0; i < str.length; i++) {
+ crc = (crc >>> 8) ^ crcTable[(crc ^ str.charCodeAt(i)) & 0xff];
+ }
+
+ return (crc ^ -1) >>> 0;
+};
+
+function returnObjFromCallsign(database, callsign) {
+ return new Promise((resolve, reject) => {
+ users
+ .find({
+ selector: {
+ user_info_callsign: callsign,
+ },
+ })
+ .then(function (result) {
+ //return new Promise((resolve, reject) => {
+ if (typeof result.docs[0] !== "undefined") {
+ resolve(result.docs[0]);
+ } else {
+ reject("Promise rejected");
+ }
+
+ /*
+ if (typeof result.docs[0] !== "undefined") {
+ return result.docs[0];
+
+
+
+
+ } else {
+ return false;
+ }
+
+ */
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ });
+}
+
+function createChatIndex() {
+ db.createIndex({
+ index: {
+ fields: [
+ "timestamp",
+ "uuid",
+ "dxcallsign",
+ "dxgrid",
+ "msg",
+ "checksum",
+ "type",
+ "command",
+ "status",
+ "percent",
+ "attempt",
+ "hmac_signed",
+ "bytesperminute",
+ "_attachments",
+ "new",
+ ],
+ },
+ })
+ .then(function (result) {
+ // handle result
+ console.log(result);
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+}
+
+function createUserIndex() {
+ users
+ .createIndex({
+ index: {
+ fields: [
+ "timestamp",
+ "user_info_callsign",
+ "user_info_gridsquare",
+ "user_info_name",
+ "user_info_age",
+ "user_info_location",
+ "user_info_radio",
+ "user_info_antenna",
+ "user_info_email",
+ "user_info_website",
+ "user_info_comments",
+ "user_info_image",
+ ],
+ },
+ })
+ .then(function (result) {
+ // handle result
+ console.log(result);
+ return true;
+ })
+ .catch(function (err) {
+ console.log(err);
+ return false;
+ });
+}
+
+async function updateAllChat(clear) {
+ if (clear == true) {
+ filetype = "";
+ file = "";
+ filename = "";
+ callsign_counter = 0;
+ //selected_callsign = "";
+ dxcallsigns.clear();
+ document.getElementById("list-tab-chat").innerHTML = "";
+ document.getElementById("nav-tabContent-Chat").innerHTML = "";
+ //document.getElementById("list-tab-chat").childNodes.remove();
+ //document.getElementById("nav-tab-content").childrenNodes.remove();
+ }
+ //Ensure we create an index before running db.find
+ //We can't rely on the default index existing before we get here...... :'(
+ await db
+ .createIndex({
+ index: {
+ fields: [{ dxcallsign: "asc" }, { timestamp: "asc" }],
+ },
+ })
+ .then(async function (result) {
+ // handle result
+ await db
+ .find({
+ selector: {
+ $and: [
+ { dxcallsign: { $exists: true } },
+ { timestamp: { $exists: true } },
+ { $or: chatFilter },
+ ],
+ //$or: chatFilter
+ },
+ sort: [{ dxcallsign: "asc" }, { timestamp: "asc" }],
+ })
+ .then(async function (result) {
+ console.log(result);
+ // handle result async
+ //document.getElementById("blurOverlay").classList.add("bg-primary");
+ console.log(result);
+ if (typeof result !== "undefined") {
+ for (const item of result.docs) {
+ //await otherwise history will not be in chronological order
+ await db
+ .get(item._id, {
+ attachments: true,
+ })
+ .then(function (item_with_attachments) {
+ update_chat(item_with_attachments);
+ });
+ }
+ }
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ if (clear == true && dxcallsigns.has(selected_callsign) == false) {
+ //Selected call sign is not visible, reset to first call sign
+ let tmp = dxcallsigns.entries().next().value[0];
+ selected_callsign = tmp;
+ document
+ .getElementById("chat-" + tmp + "-list")
+ .classList.add("active", "show");
+ document.getElementById("chat-" + tmp).classList.add("active", "show");
+ scrollMessagesToBottom();
+ }
+}
+
+function getSetUserSharedFolder(selected_callsign) {
+ // TODO: This is a dirty hotfix for avoiding, this function is canceld too fast.
+ //Should be fixed
+ //console.log("get set user information:" + selected_callsign);
+
+ if (
+ selected_callsign == "" ||
+ selected_callsign == null ||
+ typeof selected_callsign == "undefined"
+ ) {
+ console.log("return triggered");
+ return;
+ }
+
+ // disable button if broadcast
+ if (selected_callsign.startsWith("BC-")) {
+ document.getElementById("sharedFolderDXButton").disabled = true;
+ } else {
+ document.getElementById("sharedFolderDXButton").disabled = false;
+ }
+
+ returnObjFromCallsign(users, selected_callsign)
+ .then(function (data) {
+ console.log(data);
+
+ if (typeof data.user_shared_folder !== "undefined") {
+ console.log(data.user_shared_folder);
+ // shared folder table
+ var icons = [
+ "aac",
+ "ai",
+ "bmp",
+ "cs",
+ "css",
+ "csv",
+ "doc",
+ "docx",
+ "exe",
+ "gif",
+ "heic",
+ "html",
+ "java",
+ "jpg",
+ "js",
+ "json",
+ "jsx",
+ "key",
+ "m4p",
+ "md",
+ "mdx",
+ "mov",
+ "mp3",
+ "mp4",
+ "otf",
+ "pdf",
+ "php",
+ "png",
+ "ppt",
+ "pptx",
+ "psd",
+ "py",
+ "raw",
+ "rb",
+ "sass",
+ "scss",
+ "sh",
+ "sql",
+ "svg",
+ "tiff",
+ "tsx",
+ "ttf",
+ "txt",
+ "wav",
+ "woff",
+ "xls",
+ "xlsx",
+ "xml",
+ "yml",
+ ];
+ var tbl = document.getElementById("sharedFolderTableDX");
+ tbl.innerHTML = "";
+ let counter = 0;
+ data.user_shared_folder.forEach((file) => {
+ var row = document.createElement("tr");
+
+ let dxcall = selected_callsign;
+ let name = file["name"];
+ let type = file["extension"];
+
+ if (icons.indexOf(type) == -1) {
+ type = "bi-file-earmark";
+ } else {
+ type = "bi-filetype-" + type;
+ }
+
+ let id = document.createElement("td");
+ let idText = document.createElement("span");
+ counter += 1;
+ idText.innerHTML +=
+ ' ' +
+ counter;
+ id.appendChild(idText);
+ row.appendChild(id);
+
+ let filename = document.createElement("td");
+ let filenameText = document.createElement("span");
+ filenameText.innerText = file["name"];
+ filename.appendChild(filenameText);
+ row.appendChild(filename);
+
+ let filetype = document.createElement("td");
+ let filetypeText = document.createElement("span");
+ filetypeText.innerHTML = ` `;
+ filetype.appendChild(filetypeText);
+ row.appendChild(filetype);
+
+ let filesize = document.createElement("td");
+ let filesizeText = document.createElement("span");
+ filesizeText.innerText = formatBytes(file["size"], 2);
+ filesize.appendChild(filesizeText);
+ row.appendChild(filesize);
+ id.addEventListener("click", function () {
+ //console.log(name," clicked");
+ sendFileReq(dxcall, name);
+ });
+ tbl.appendChild(row);
+ });
+ } else {
+ document.getElementById("sharedFolderTableDX").innerHTML = "no data";
+ }
+ })
+ .catch(function (err) {
+ console.log(err);
+ document.getElementById("sharedFolderTableDX").innerHTML = "no data";
+ });
+}
+
+function getSetUserInformation(selected_callsign) {
+ //Get user information
+ //console.log("get set user information:" + selected_callsign);
+
+ if (
+ selected_callsign == "" ||
+ selected_callsign == null ||
+ typeof selected_callsign == "undefined"
+ ) {
+ console.log("return triggered");
+ return;
+ }
+
+ // disable button if broadcast
+ if (selected_callsign.startsWith("BC-")) {
+ document.getElementById("userModalDXButton").disabled = true;
+ document.getElementById("ping").disabled = true;
+ } else {
+ document.getElementById("userModalDXButton").disabled = false;
+ document.getElementById("ping").disabled = false;
+ }
+
+ document.getElementById("dx_user_info_callsign").innerHTML =
+ selected_callsign;
+
+ returnObjFromCallsign(users, selected_callsign)
+ .then(function (data) {
+ console.log(data);
+
+ // image
+ if (typeof data.user_info_image !== "undefined") {
+ try {
+ console.log("try checking for image if base64 data");
+ // determine if we have a base64 encoded image
+ console.log(data.user_info_image);
+ console.log(data.user_info_image.split(";base64,")[1]);
+ // split data string by "base64" for separating image type from base64 string
+ atob(data.user_info_image.split(";base64,")[1]);
+
+ if (selected_callsign.startsWith("BC-")) {
+ data.user_info_image = defaultGroupIcon;
+ }
+
+ document.getElementById("dx_user_info_image").src =
+ data.user_info_image;
+ document.getElementById("user-image-" + selected_callsign).src =
+ data.user_info_image;
+ } catch (e) {
+ console.log(e);
+ console.log("corrupted image data");
+
+ if (selected_callsign.startsWith("BC-")) {
+ var userIcon = defaultGroupIcon;
+ } else {
+ var userIcon = defaultUserIcon;
+ }
+
+ document.getElementById("user-image-" + selected_callsign).src =
+ userIcon;
+ document.getElementById("dx_user_info_image").src = userIcon;
+ }
+ } else {
+ // throw error and use placeholder data
+ // throw new Error("Data not available or corrupted");
+ document.getElementById("dx_user_info_image").src = defaultUserIcon;
+ document.getElementById("user-image-" + selected_callsign).src =
+ defaultUserIcon;
+ }
+
+ // Callsign list elements
+ document.getElementById(
+ "chat-" + selected_callsign + "-list-dxgrid",
+ ).innerHTML = "" + data.user_info_gridsquare + " ";
+ document.getElementById("user-image-" + selected_callsign).className =
+ "p-1 rounded-circle";
+ document.getElementById("user-image-" + selected_callsign).style =
+ "width: 60px";
+
+ // DX Station tab
+ document.getElementById("dx_user_info_name").innerHTML =
+ data.user_info_name;
+ document.getElementById("dx_user_info_age").innerHTML =
+ data.user_info_age;
+ document.getElementById("dx_user_info_gridsquare").innerHTML =
+ data.user_info_gridsquare;
+ document.getElementById("dx_user_info_location").innerHTML =
+ data.user_info_location;
+ document.getElementById("dx_user_info_email").innerHTML =
+ data.user_info_email;
+ document.getElementById("dx_user_info_website").innerHTML =
+ data.user_info_website;
+ document.getElementById("dx_user_info_radio").innerHTML =
+ data.user_info_radio;
+ document.getElementById("dx_user_info_antenna").innerHTML =
+ data.user_info_antenna;
+ document.getElementById("dx_user_info_comments").innerHTML =
+ data.user_info_comments;
+
+ document.getElementById("dx_user_info_gridsquare").className = "";
+ document.getElementById("dx_user_info_name").className =
+ "badge bg-secondary";
+ document.getElementById("dx_user_info_age").className =
+ "badge bg-secondary";
+ document.getElementById("dx_user_info_gridsquare").className = "";
+ document.getElementById("dx_user_info_location").className = "";
+ document.getElementById("dx_user_info_email").className = "";
+ document.getElementById("dx_user_info_website").className = "";
+ document.getElementById("dx_user_info_radio").className = "";
+ document.getElementById("dx_user_info_antenna").className = "";
+ document.getElementById("dx_user_info_comments").className = "";
+ })
+ .catch(function (err) {
+ console.log("writing user info to modal failed");
+ console.log(err);
+
+ if (selected_callsign.startsWith("BC-")) {
+ var userIcon = defaultGroupIcon;
+ } else {
+ var userIcon = defaultUserIcon;
+ }
+
+ // Callsign list elements
+ document.getElementById("user-image-" + selected_callsign).src = userIcon;
+ document.getElementById("user-image-" + selected_callsign).className =
+ "p-1 rounded-circle w-100";
+ document.getElementById("user-image-" + selected_callsign).style =
+ "height:60px";
+ document.getElementById(
+ "chat-" + selected_callsign + "-list-dxgrid",
+ ).innerHTML = "no grid ";
+
+ // DX Station tab
+
+ document.getElementById("dx_user_info_image").src = defaultUserIcon;
+ document.getElementById("dx_user_info_gridsquare").className =
+ "placeholder col-4";
+ document.getElementById("dx_user_info_name").className =
+ "placeholder col-4";
+ document.getElementById("dx_user_info_age").className =
+ "placeholder col-2";
+ document.getElementById("dx_user_info_gridsquare").className =
+ "placeholder col-3";
+ document.getElementById("dx_user_info_location").className =
+ "placeholder col-3";
+ document.getElementById("dx_user_info_email").className =
+ "placeholder col-7";
+ document.getElementById("dx_user_info_website").className =
+ "placeholder col-7";
+ document.getElementById("dx_user_info_radio").className =
+ "placeholder col-4";
+ document.getElementById("dx_user_info_antenna").className =
+ "placeholder col-4";
+ document.getElementById("dx_user_info_comments").className =
+ "placeholder col-7";
+ });
+}
+
+function sendSharedFolderList(dxcallsign) {
+ ipcRenderer.send("read-files-in-folder", {
+ folder: config.shared_folder_path,
+ });
+
+ console.log(sharedFolderFileList);
+ let fileListWithCallsign = "";
+ fileListWithCallsign += dxcallsign;
+ fileListWithCallsign += split_char;
+ fileListWithCallsign += JSON.stringify(sharedFolderFileList);
+
+ console.log(fileListWithCallsign);
+
+ ipcRenderer.send("run-tnc-command", {
+ command: "responseSharedFolderList",
+ dxcallsign: dxcallsign,
+ folderFileList: fileListWithCallsign,
+ });
+}
+
+function sendSharedFolderFile(dxcallsign, filename) {
+ let filePath = path.join(config.shared_folder_path, filename);
+ console.log("In function sendSharedFolderFile ", filePath);
+
+ //Make sure nothing sneaky is going on
+ if (!filePath.startsWith(config.shared_folder_path)) {
+ console.error("File is outside of shared folder path!");
+ return;
+ }
+
+ if (!fs.existsSync(filePath)) {
+ console.warn("File doesn't seem to exist");
+ return;
+ }
+
+ //Read file's data
+ let fileData = null;
+ try {
+ //Has to be binary
+ let data = fs.readFileSync(filePath);
+ fileData = data.toString("utf-8");
+ } catch (err) {
+ console.log(err);
+ return;
+ }
+
+ ipcRenderer.send("run-tnc-command", {
+ command: "responseSharedFile",
+ dxcallsign: dxcallsign,
+ file: filename,
+ filedata: fileData,
+ });
+}
+
+function sendUserData(dxcallsign) {
+ const userInfoFields = [
+ "user_info_image",
+ "user_info_callsign",
+ "user_info_gridsquare",
+ "user_info_name",
+ "user_info_age",
+ "user_info_location",
+ "user_info_radio",
+ "user_info_antenna",
+ "user_info_email",
+ "user_info_website",
+ "user_info_comments",
+ ];
+
+ let info = "";
+ userInfoFields.forEach(function (subelem) {
+ if (subelem !== "user_info_image") {
+ info += document.getElementById(subelem).value;
+ info += split_char;
+ } else {
+ info += document.getElementById(subelem).src;
+ info += split_char;
+ }
+ });
+
+ console.log(info);
+
+ ipcRenderer.send("run-tnc-command", {
+ command: "responseUserInfo",
+ dxcallsign: dxcallsign,
+ userinfo: info,
+ });
+}
+
+//Temporarily disable a button with timeout
+function pauseButton(btn, timems) {
+ btn.disabled = true;
+ var curText = btn.innerHTML;
+ if (config.high_graphics.toUpperCase() == "TRUE") {
+ btn.innerHTML =
+ '';
+ }
+ setTimeout(() => {
+ btn.innerHTML = curText;
+ btn.disabled = false;
+ }, timems);
+}
+ipcRenderer.on("update-config", (event, data) => {
+ config = data;
+});
+
+ipcRenderer.on("action-update-unread-messages", (event) => {
+ checkForNewMessages().then(function (count) {
+ ipcRenderer.send("request-update-unread-messages-main", count);
+ });
+});
+
+ipcRenderer.on("action-clean-db", (event) => {
+ dbClean();
+});
+
+// https://stackoverflow.com/a/18650828
+function formatBytes(bytes, decimals = 2) {
+ if (!+bytes) return "0 Bytes";
+
+ const k = 1024;
+ const dm = decimals < 0 ? 0 : decimals;
+ const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
+
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+
+ return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;
+}
+function sendFileReq(dxcall, file) {
+ //console.log(file," clicked");
+ ipcRenderer.send("run-tnc-command", {
+ command: "requestSharedFile",
+ dxcallsign: dxcall,
+ file: file,
+ });
+}
+
+function changeGuiDesign(design) {
+ console.log(design);
+ if (
+ design != "default" &&
+ design != "default_light" &&
+ design != "default_dark" &&
+ design != "default_auto"
+ ) {
+ var theme_path =
+ "../node_modules/bootswatch/dist/" + design + "/bootstrap.min.css";
+ document.getElementById("bootstrap_theme").href = escape(theme_path);
+ } else if (design == "default" || design == "default_light") {
+ var theme_path = "../node_modules/bootstrap/dist/css/bootstrap.min.css";
+ document.getElementById("bootstrap_theme").href = escape(theme_path);
+ document.documentElement.setAttribute("data-bs-theme", "light");
+ } else if (design == "default_dark") {
+ var theme_path = "../node_modules/bootstrap/dist/css/bootstrap.min.css";
+ document.getElementById("bootstrap_theme").href = escape(theme_path);
+ document.querySelector("html").setAttribute("data-bs-theme", "dark");
+ } else if (design == "default_auto") {
+ var theme_path = "../node_modules/bootstrap/dist/css/bootstrap.min.css";
+ document.getElementById("bootstrap_theme").href = escape(theme_path);
+
+ // https://stackoverflow.com/a/57795495
+ // check if dark mode or light mode used in OS
+ if (
+ window.matchMedia &&
+ window.matchMedia("(prefers-color-scheme: dark)").matches
+ ) {
+ // dark mode
+ document.documentElement.setAttribute("data-bs-theme", "dark");
+ } else {
+ document.documentElement.setAttribute("data-bs-theme", "light");
+ }
+
+ // also register event listener for automatic change
+ window
+ .matchMedia("(prefers-color-scheme: dark)")
+ .addEventListener("change", (event) => {
+ let newColorScheme = event.matches ? "dark" : "light";
+ if (newColorScheme == "dark") {
+ document.documentElement.setAttribute("data-bs-theme", "dark");
+ } else {
+ document.documentElement.setAttribute("data-bs-theme", "light");
+ }
+ });
+ } else {
+ var theme_path = "../node_modules/bootstrap/dist/css/bootstrap.min.css";
+ document.getElementById("bootstrap_theme").href = escape(theme_path);
+ document.documentElement.setAttribute("data-bs-theme", "light");
+ }
+
+ //update path to css file
+ document.getElementById("bootstrap_theme").href = escape(theme_path);
+}
+
+function checkForWaitingMessages(dxcall) {
+ db.find({
+ selector: {
+ dxcallsign: dxcall,
+ type: "transmit",
+ status: "failed",
+ //attempt: { $lt: parseInt(config.max_retry_attempts) }
+ },
+ })
+ .then(function (result) {
+ console.log(
+ "Found " + result.docs.length + " messages waiting for " + dxcall,
+ );
+ // handle result
+ if (result.docs.length > 0) {
+ // only want to process the first available item object, then return
+ // this ensures, we are only sending one message at once
+
+ if (typeof result.docs[0].attempt == "undefined") {
+ db.upsert(result.docs[0]._id, function (doc) {
+ if (!doc.attempt) {
+ doc.attempt = 1;
+ }
+ doc.attempt++;
+ return doc;
+ });
+ console.log("old message found - adding attempt field");
+ result.docs[0].attempt = 1;
+ }
+
+ if (result.docs[0].attempt < config.max_retry_attempts) {
+ console.log("RESENDING MESSAGE TRIGGERED BY BEACON OR PING");
+ console.log(result.docs[0]);
+ document
+ .getElementById("retransmit-msg-" + result.docs[0]._id)
+ .click();
+ } else {
+ console.log("max retries reached...can't auto repeat");
+ document
+ .getElementById("msg-" + result.docs[0]._id + "-attempts-badge")
+ .classList.remove("bg-primary");
+ document
+ .getElementById("msg-" + result.docs[0]._id + "-attempts-badge")
+ .classList.add("bg-danger");
+ }
+ return;
+ } else {
+ //console.log("nope");
+ }
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+}
+
+async function checkForNewMessages() {
+ var newmsgs;
+ await db
+ .find({
+ selector: {
+ new: { $eq: 1 },
+ },
+ limit: 1,
+ })
+ .then(function (result) {
+ if (result.docs.length > 0) newmsgs = true;
+ else newmsgs = false;
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ return newmsgs;
+}
+
+function clearUnreadMessages(dxcall) {
+ //console.log(dxcall);
+ //Selector of dxcall and new $eq: 1 isn't working, don't know why
+ //For now parse all messages of callsign to clear new flag
+ db.find({
+ //{
+ selector:
+ //$and:[
+ { dxcallsign: dxcall }, //, {new: { $gte: 1}}
+ //]
+ // }
+ })
+ .then(function (result) {
+ //console.log(result);
+ //console.log ("New messages count to clear for " + dxcall + ": " + result.docs.length)
+ result.docs.forEach(function (item) {
+ if (item.new == 1) {
+ db.upsert(item._id, function (doc) {
+ doc.new = 0;
+ //console.log("Clearing new on _id " + item._id);
+ return doc;
+ });
+ }
+ });
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+
+
+}
+
+//Have the operating system show a notification popup
+function showOsPopUp(title, message) {
+ if (config.enable_sys_notification == 0) return;
+ const NOTIFICATION_TITLE = title;
+ const NOTIFICATION_BODY = message;
+ new Notification(NOTIFICATION_TITLE, { body: NOTIFICATION_BODY });
+}
+
+//Function to clean old beacons and optimize database
+async function dbClean() {
+ //Only keep the most x latest days of beacons
+ let beaconKeep = 7;
+ let itemCount = 0;
+ let timestampPurge = Math.floor(
+ (Date.now() - beaconKeep * 24 * 60 * 60 * 1000) / 1000,
+ );
+ if (
+ confirm(
+ "Delete beacons and pings older than " +
+ beaconKeep +
+ " days and compact database?",
+ )
+ ) {
+ } else {
+ ipcRenderer.send("request-update-dbclean-spinner");
+ return;
+ }
+
+ //Items to purge from database
+ var purgeFilter = [
+ { type: "beacon" },
+ { type: "ping-ack" },
+ { type: "ping" },
+ ];
+
+ await db
+ .find({
+ selector: {
+ $and: [{ timestamp: { $lt: timestampPurge } }, { $or: purgeFilter }],
+ },
+ })
+ .then(async function (result) {
+ //console.log("Purging " + result.docs.length + " beacons received before " + timestampPurge);
+ itemCount = result.docs.length;
+ result.docs.forEach(async function (item) {
+ await db
+ .get(item._id)
+ .then(async function (doc) {
+ await db.remove(doc);
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+ });
+ })
+ .catch(function (err) {
+ console.log(err);
+ });
+
+ //Compact database
+ await db.compact();
+ window.alert(
+ "Database maintenance is complete. " +
+ itemCount +
+ " items removed from database. It's recommended you now restart the GUI.",
+ );
+ ipcRenderer.send("request-update-dbclean-spinner");
+}
diff --git a/gui_vue/src/js/preload-log.js b/gui_vue/src/js/preload-log.js
new file mode 100644
index 00000000..9e2bcbc2
--- /dev/null
+++ b/gui_vue/src/js/preload-log.js
@@ -0,0 +1,186 @@
+const path = require("path");
+const { ipcRenderer } = require("electron");
+
+// https://stackoverflow.com/a/26227660
+var appDataFolder =
+ process.env.APPDATA ||
+ (process.platform == "darwin"
+ ? process.env.HOME + "/Library/Application Support"
+ : process.env.HOME + "/.config");
+var configFolder = path.join(appDataFolder, "FreeDATA");
+var configPath = path.join(configFolder, "config.json");
+const config = require(configPath);
+
+// WINDOW LISTENER
+window.addEventListener("DOMContentLoaded", () => {
+ document
+ .getElementById("enable_filter_info")
+ .addEventListener("click", () => {
+ if (document.getElementById("enable_filter_info").checked) {
+ display_class("table-info", true);
+ } else {
+ display_class("table-info", false);
+ }
+ });
+
+ document
+ .getElementById("enable_filter_debug")
+ .addEventListener("click", () => {
+ if (document.getElementById("enable_filter_debug").checked) {
+ display_class("table-debug", true);
+ } else {
+ display_class("table-debug", false);
+ }
+ });
+
+ document
+ .getElementById("enable_filter_warning")
+ .addEventListener("click", () => {
+ if (document.getElementById("enable_filter_warning").checked) {
+ display_class("table-warning", true);
+ } else {
+ display_class("table-warning", false);
+ }
+ });
+
+ document
+ .getElementById("enable_filter_error")
+ .addEventListener("click", () => {
+ if (document.getElementById("enable_filter_error").checked) {
+ display_class("table-danger", true);
+ } else {
+ display_class("table-danger", false);
+ }
+ });
+});
+
+function display_class(class_name, state) {
+ var collection = document.getElementsByClassName(class_name);
+ console.log(collection);
+ for (let i = 0; i < collection.length; i++) {
+ if (state == true) {
+ collection[i].style.display = "table-row";
+ } else {
+ collection[i].style.display = "None";
+ }
+ }
+}
+
+ipcRenderer.on("action-update-log", (event, arg) => {
+ var entry = arg.entry;
+
+ // remove ANSI characters from string, caused by color logging
+ // https://stackoverflow.com/a/29497680
+ entry = entry.replace(
+ /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
+ "",
+ );
+
+ var tbl = document.getElementById("log");
+ var row = document.createElement("tr");
+
+ var timestamp = document.createElement("td");
+ var timestampText = document.createElement("span");
+
+ //datetime = new Date();
+ //timestampText.innerText = datetime.toISOString();
+ timestampText.innerText = entry.slice(0, 19);
+ timestamp.appendChild(timestampText);
+
+ var type = document.createElement("td");
+ var typeText = document.createElement("span");
+ // typeText.innerText = entry.slice(10, 30).match(/[\[](.*)[^\]]/g);
+ console.log(entry.match(/\[[^\]]+\]/g));
+
+ try {
+ typeText.innerText = entry.match(/\[[^\]]+\]/g)[0];
+ } catch (e) {
+ typeText.innerText = "-";
+ }
+
+ // let res = str.match(/[\[](.*)[^\]]/g);
+
+ type.appendChild(typeText);
+
+ var area = document.createElement("td");
+ var areaText = document.createElement("span");
+ //areaText.innerText = entry.slice(10, 50).match(/[\] \[](.*)[^\]]/g);
+ //areaText.innerText = entry.match(/\[[^\]]+\]/g)[1];
+
+ try {
+ areaText.innerText = entry.match(/\[[^\]]+\]/g)[1];
+ } catch (e) {
+ areaText.innerText = "-";
+ }
+ area.appendChild(areaText);
+
+ var logEntry = document.createElement("td");
+ var logEntryText = document.createElement("span");
+ try {
+ logEntryText.innerText = entry.split("]")[2];
+ } catch (e) {
+ logEntryText.innerText = "-";
+ }
+ logEntry.appendChild(logEntryText);
+
+ row.appendChild(timestamp);
+ row.appendChild(type);
+ row.appendChild(area);
+ row.appendChild(logEntry);
+
+ //row.classList.add("table-blablubb");
+ /*
+ if (logEntryText.innerText.includes('ALSA lib pcm')) {
+ row.classList.add("table-secondary");
+ }
+ */
+ if (typeText.innerText.includes("info")) {
+ row.classList.add("table-info");
+ }
+ if (typeText.innerText.includes("debug")) {
+ row.classList.add("table-secondary");
+ }
+
+ if (typeText.innerText.includes("warning")) {
+ row.classList.add("table-warning");
+ }
+
+ if (typeText.innerText.includes("error")) {
+ row.classList.add("table-danger");
+ }
+
+ if (document.getElementById("enable_filter_info").checked) {
+ row.style.display = "table-row";
+ display_class("table-info", true);
+ } else {
+ row.style.display = "None";
+ display_class("table-info", false);
+ }
+ if (document.getElementById("enable_filter_debug").checked) {
+ row.style.display = "table-row";
+ display_class("table-secondary", true);
+ } else {
+ row.style.display = "None";
+ display_class("table-secondary", false);
+ }
+ if (document.getElementById("enable_filter_warning").checked) {
+ row.style.display = "table-row";
+ display_class("table-warning", true);
+ } else {
+ row.style.display = "None";
+ display_class("table-warning", false);
+ }
+ if (document.getElementById("enable_filter_error").checked) {
+ row.style.display = "table-row";
+ display_class("table-danger", true);
+ } else {
+ row.style.display = "None";
+ display_class("table-danger", false);
+ }
+
+ tbl.appendChild(row);
+
+ // scroll to bottom of page
+ // https://stackoverflow.com/a/11715670
+ window.scrollTo(0, document.body.scrollHeight);
+});
diff --git a/gui_vue/src/js/preload-mesh.js b/gui_vue/src/js/preload-mesh.js
new file mode 100644
index 00000000..6035b058
--- /dev/null
+++ b/gui_vue/src/js/preload-mesh.js
@@ -0,0 +1,231 @@
+const path = require("path");
+const { ipcRenderer } = require("electron");
+
+// https://stackoverflow.com/a/26227660
+var appDataFolder =
+ process.env.APPDATA ||
+ (process.platform == "darwin"
+ ? process.env.HOME + "/Library/Application Support"
+ : process.env.HOME + "/.config");
+var configFolder = path.join(appDataFolder, "FreeDATA");
+var configPath = path.join(configFolder, "config.json");
+const config = require(configPath);
+
+var callsignPath = path.join(configFolder, "callsigns.json");
+const callsigns = require(callsignPath);
+
+// WINDOW LISTENER
+window.addEventListener("DOMContentLoaded", () => {
+ // startPing button clicked
+ document
+ .getElementById("transmit_mesh_ping")
+ .addEventListener("click", () => {
+ var dxcallsign = document
+ .getElementById("dxCallMesh")
+ .value.toUpperCase();
+ if (dxcallsign == "" || dxcallsign == null || dxcallsign == undefined)
+ return;
+ //pauseButton(document.getElementById("transmit_mesh_ping"), 2000);
+ ipcRenderer.send("run-tnc-command", {
+ command: "mesh_ping",
+ dxcallsign: dxcallsign,
+ });
+ });
+});
+
+ipcRenderer.on("action-update-mesh-table", (event, arg) => {
+ var routes = arg.routing_table;
+
+ if (typeof routes == "undefined") {
+ return;
+ }
+
+ var tbl = document.getElementById("mesh-table");
+ if (tbl !== null) {
+ tbl.innerHTML = "";
+ }
+
+ for (i = 0; i < routes.length; i++) {
+ var row = document.createElement("tr");
+ var datetime = new Date(routes[i]["timestamp"] * 1000).toLocaleString(
+ navigator.language,
+ {
+ hourCycle: "h23",
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ hour: "2-digit",
+ minute: "2-digit",
+ second: "2-digit",
+ },
+ );
+ var timestamp = document.createElement("td");
+ var timestampText = document.createElement("span");
+ timestampText.innerText = datetime;
+ timestamp.appendChild(timestampText);
+
+ var dxcall = document.createElement("td");
+ var dxcallText = document.createElement("span");
+ dxcallText.innerText = routes[i]["dxcall"];
+
+ // check for callsign in callsign list, else use checksum
+ for (let call in callsigns) {
+ if (callsigns[call] == routes[i]["dxcall"]) {
+ dxcallText.innerText += " (" + call + ")";
+ continue;
+ }
+ }
+ dxcall.appendChild(dxcallText);
+
+ var router = document.createElement("td");
+ var routerText = document.createElement("span");
+ routerText.innerText = routes[i]["router"];
+
+ // check for callsign in callsign list, else use checksum
+ for (let call in callsigns) {
+ if (callsigns[call] == routes[i]["router"]) {
+ routerText.innerHTML += `${call} `;
+ continue;
+ }
+ }
+ router.appendChild(routerText);
+
+ var hops = document.createElement("td");
+ var hopsText = document.createElement("span");
+ hopsText.innerText = routes[i]["hops"];
+ hops.appendChild(hopsText);
+
+ var score = document.createElement("td");
+ var scoreText = document.createElement("span");
+ scoreText.innerText = routes[i]["score"];
+ score.appendChild(scoreText);
+
+ var snr = document.createElement("td");
+ var snrText = document.createElement("span");
+ snrText.innerText = routes[i]["snr"];
+ snr.appendChild(snrText);
+
+ row.appendChild(timestamp);
+ row.appendChild(dxcall);
+ row.appendChild(router);
+ row.appendChild(hops);
+ row.appendChild(score);
+ row.appendChild(snr);
+
+ tbl.appendChild(row);
+ }
+ /*-------------------------------------------*/
+ var routes = arg.mesh_signalling_table;
+
+ //console.log(routes);
+ if (typeof routes == "undefined") {
+ return;
+ }
+
+ var tbl = document.getElementById("mesh-signalling-table");
+ if (tbl !== null) {
+ tbl.innerHTML = "";
+ }
+
+ for (i = 0; i < routes.length; i++) {
+ var row = document.createElement("tr");
+ var datetime = new Date(routes[i]["timestamp"] * 1000).toLocaleString(
+ navigator.language,
+ {
+ hourCycle: "h23",
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ hour: "2-digit",
+ minute: "2-digit",
+ second: "2-digit",
+ },
+ );
+ var timestamp = document.createElement("td");
+ var timestampText = document.createElement("span");
+ timestampText.innerText = datetime;
+ timestamp.appendChild(timestampText);
+
+ var destination = document.createElement("td");
+ var destinationText = document.createElement("span");
+ destinationText.innerText = routes[i]["destination"];
+ // check for callsign in callsign list, else use checksum
+ for (let call in callsigns) {
+ if (callsigns[call] == routes[i]["destination"]) {
+ destinationText.innerHTML += `${call} `;
+ continue;
+ }
+ }
+ destination.appendChild(destinationText);
+
+ var origin = document.createElement("td");
+ var originText = document.createElement("span");
+ originText.innerText = routes[i]["origin"];
+ // check for callsign in callsign list, else use checksum
+ for (let call in callsigns) {
+ if (callsigns[call] == routes[i]["origin"]) {
+ originText.innerHTML += `${call} `;
+ continue;
+ }
+ }
+
+ origin.appendChild(originText);
+
+ var frametype = document.createElement("td");
+ var frametypeText = document.createElement("span");
+ frametypeText.innerText = routes[i]["frametype"];
+ frametype.appendChild(frametypeText);
+
+ var payload = document.createElement("td");
+ var payloadText = document.createElement("span");
+ payloadText.innerText = routes[i]["payload"];
+ payload.appendChild(payloadText);
+
+ var attempt = document.createElement("td");
+ var attemptText = document.createElement("span");
+ attemptText.innerText = routes[i]["attempt"];
+ attempt.appendChild(attemptText);
+
+ var status = document.createElement("td");
+ var statusText = document.createElement("span");
+ //statusText.innerText = routes[i]["status"];
+ switch (routes[i]["status"]) {
+ case "acknowledged":
+ var status_icon = ' ';
+ var status_color = "bg-success";
+ break;
+ case "acknowledging":
+ var status_icon = ' ';
+ var status_color = "bg-warning";
+ break;
+ case "forwarding":
+ var status_icon = ' ';
+ var status_color = "bg-secondary";
+ break;
+ case "awaiting_ack":
+ var status_icon = ' ';
+ var status_color = "bg-info";
+ break;
+ default:
+ var status_icon = ' ';
+ var status_color = "bg-primary";
+ break;
+ }
+
+ statusText.innerHTML = `
+ ${status_icon}
+ ${routes[i]["status"]}
+ `;
+ status.appendChild(statusText);
+
+ row.appendChild(timestamp);
+ row.appendChild(destination);
+ row.appendChild(origin);
+ row.appendChild(frametype);
+ row.appendChild(payload);
+ row.appendChild(attempt);
+ row.appendChild(status);
+
+ tbl.appendChild(row);
+ }
+});
diff --git a/gui_vue/src/js/sock.js b/gui_vue/src/js/sock.js
new file mode 100644
index 00000000..95bdbe9c
--- /dev/null
+++ b/gui_vue/src/js/sock.js
@@ -0,0 +1,957 @@
+var net = require("net");
+const path = require("path");
+const { ipcRenderer } = require("electron");
+const FD = require("./src/js/freedata.js");
+//import FD from './freedata.js';
+
+// ----------------- init pinia stores -------------
+import { setActivePinia } from 'pinia';
+import pinia from '../store/index';
+setActivePinia(pinia);
+import { useStateStore } from '../store/stateStore.js';
+const stateStore = useStateStore(pinia);
+
+import { useSettingsStore } from '../store/settingsStore.js';
+const settings = useSettingsStore(pinia);
+
+
+var client = new net.Socket();
+var socketchunk = ""; // Current message, per connection.
+
+// split character
+//const split_char = "\0;\1;";
+const split_char = "0;1;";
+
+
+// globals for getting new data only if available so we are saving bandwidth
+var rxBufferLengthTnc = 0;
+var rxBufferLengthGui = 0;
+//var rxMsgBufferLengthTnc = 0;
+//var rxMsgBufferLengthGui = 0;
+
+// global to keep track of TNC connection error emissions
+var tncShowConnectStateError = 1;
+
+
+// network connection Timeout
+setTimeout(connectTNC, 2000);
+
+function connectTNC() {
+ //exports.connectTNC = function(){
+ //console.log('connecting to TNC...')
+
+ //clear message buffer after reconnecting or initial connection
+ socketchunk = "";
+
+ if (settings.tnclocation == "localhost") {
+ client.connect(3000, "127.0.0.1");
+ } else {
+ client.connect(settings.tnc_port, settings.tnc_host);
+ }
+}
+
+client.on("connect", function (data) {
+ console.log("TNC connection established");
+
+ stateStore.busy_state = "-";
+ stateStore.arq_state = "-";
+ stateStore.frequency = "-";
+ stateStore.mode = "-";
+ stateStore.bandwidth = "-";
+ stateStore.dbfs_level = 0;
+ stateStore.updateTncState(client.readyState)
+
+ tncShowConnectStateError = 1;
+});
+
+client.on("error", function (data) {
+ if (tncShowConnectStateError == 1) {
+ console.log("TNC connection error");
+ tncShowConnectStateError = 0;
+ }
+ setTimeout(connectTNC, 500);
+ client.destroy();
+ stateStore.busy_state = "-";
+ stateStore.arq_state = "-";
+ stateStore.frequency = "-";
+ stateStore.mode = "-";
+ stateStore.bandwidth = "-";
+ stateStore.dbfs_level = 0;
+ stateStore.updateTncState(client.readyState)
+
+});
+
+/*
+client.on('close', function(data) {
+ console.log(' TNC connection closed');
+ setTimeout(connectTNC, 2000)
+});
+*/
+
+client.on("end", function (data) {
+ console.log("TNC connection ended");
+ stateStore.busy_state = "-";
+ stateStore.arq_state = "-";
+ stateStore.frequency = "-";
+ stateStore.mode = "-";
+ stateStore.bandwidth = "-";
+ stateStore.dbfs_level = 0;
+ stateStore.updateTncState(client.readyState)
+ client.destroy();
+
+ setTimeout(connectTNC, 500);
+});
+
+//exports.writeTncCommand = function (command) {
+//writeTncCommand = function (command) {
+function writeTncCommand(command) {
+ //console.log(command)
+ // we use the writingCommand function to update our TCPIP state because we are calling this function a lot
+ // if socket opened, we are able to run commands
+
+ if (client.readyState == "open") {
+ client.write(command + "\n");
+ }
+
+ if (client.readyState == "closed") {
+ console.log("CLOSED!");
+ }
+
+ if (client.readyState == "opening") {
+ console.log("connecting to TNC...");
+ }
+};
+
+client.on("data", function (socketdata) {
+ stateStore.updateTncState(client.readyState)
+
+
+ /*
+ inspired by:
+ stackoverflow.com questions 9070700 nodejs-net-createserver-large-amount-of-data-coming-in
+ */
+
+ socketdata = socketdata.toString("utf8"); // convert data to string
+ socketchunk += socketdata; // append data to buffer so we can stick long data together
+
+ // check if we received begin and end of json data
+ if (socketchunk.startsWith('{"') && socketchunk.endsWith('"}\n')) {
+ var data = "";
+
+ // split data into chunks if we received multiple commands
+ socketchunk = socketchunk.split("\n");
+ //don't think this is needed anymore
+ //data = JSON.parse(socketchunk[0])
+
+ // search for empty entries in socketchunk and remove them
+ for (var i = 0; i < socketchunk.length; i++) {
+ if (socketchunk[i] === "") {
+ socketchunk.splice(i, 1);
+ }
+ }
+
+ //iterate through socketchunks array to execute multiple commands in row
+ for (var i = 0; i < socketchunk.length; i++) {
+ //check if data is not empty
+ if (socketchunk[i].length > 0) {
+ //try to parse JSON
+ try {
+ data = JSON.parse(socketchunk[i]);
+ } catch (e) {
+ console.log("Throwing away data!!!!\n" + e); // "SyntaxError
+ //console.log(e); // "SyntaxError
+ console.log(socketchunk[i]);
+ socketchunk = "";
+ //If we're here, I don't think we want to process any data that may be in data variable
+ continue;
+ }
+ }
+
+ if (data["command"] == "tnc_state") {
+ //console.log(data)
+ // set length of RX Buffer to global variable
+ rxBufferLengthTnc = data["rx_buffer_length"];
+ //rxMsgBufferLengthTnc = data["rx_msg_buffer_length"];
+
+ let Data = {
+ mycallsign: data["mycallsign"],
+ mygrid: data["mygrid"],
+ ptt_state: data["ptt_state"],
+ busy_state: data["tnc_state"],
+ arq_state: data["arq_state"],
+ arq_session: data["arq_session"],
+ //channel_state: data['CHANNEL_STATE'],
+ frequency: data["frequency"],
+ speed_level: data["speed_level"],
+ mode: data["mode"],
+ bandwidth: data["bandwidth"],
+ dbfs_level: data["audio_dbfs"],
+ fft: data["fft"],
+ channel_busy: data["channel_busy"],
+ channel_busy_slot: data["channel_busy_slot"],
+ scatter: data["scatter"],
+ info: data["info"],
+ rx_buffer_length: data["rx_buffer_length"],
+ rx_msg_buffer_length: data["rx_msg_buffer_length"],
+ tx_n_max_retries: data["tx_n_max_retries"],
+ arq_tx_n_frames_per_burst: data["arq_tx_n_frames_per_burst"],
+ arq_tx_n_bursts: data["arq_tx_n_bursts"],
+ arq_tx_n_current_arq_frame: data["arq_tx_n_current_arq_frame"],
+ arq_tx_n_total_arq_frames: data["arq_tx_n_total_arq_frames"],
+ arq_rx_frame_n_bursts: data["arq_rx_frame_n_bursts"],
+ arq_rx_n_current_arq_frame: data["arq_rx_n_current_arq_frame"],
+ arq_n_arq_frames_per_data_frame:
+ data["arq_n_arq_frames_per_data_frame"],
+ arq_bytes_per_minute: data["arq_bytes_per_minute"],
+ arq_seconds_until_finish: data["arq_seconds_until_finish"],
+ arq_compression_factor: data["arq_compression_factor"],
+ total_bytes: data["total_bytes"],
+ arq_transmission_percent: data["arq_transmission_percent"],
+ stations: data["stations"],
+ routing_table: data["routing_table"],
+ mesh_signalling_table: data["mesh_signalling_table"],
+ beacon_state: data["beacon_state"],
+ hamlib_status: data["hamlib_status"],
+ listen: data["listen"],
+ audio_recording: data["audio_recording"],
+ speed_list: data["speed_list"],
+ strength: data["strength"],
+ is_codec2_traffic: data["is_codec2_traffic"],
+ //speed_table: [{"bpm" : 5200, "snr": -3, "timestamp":1673555399},{"bpm" : 2315, "snr": 12, "timestamp":1673555500}],
+ };
+
+ ipcRenderer.send("request-update-tnc-state", Data);
+ //continue to next for loop iteration, nothing else needs to be done here
+ continue;
+ }
+
+ // ----------- catch tnc messages START -----------
+ if (data["freedata"] == "tnc-message") {
+ switch (data["fec"]) {
+ case "is_writing":
+ // RX'd FECiswriting
+ ipcRenderer.send("request-show-fec-toast-iswriting", {
+ data: [data],
+ });
+ break;
+
+ case "broadcast":
+ // RX'd FEC BROADCAST
+ var encoded_data = FD.atob_FD(data["data"]);
+ var splitted_data = encoded_data.split(split_char);
+ var messageArray = [];
+ if (splitted_data[0] == "m") {
+ messageArray.push(data);
+ console.log(data);
+ }
+
+ let Messages = {
+ data: messageArray,
+ };
+ ipcRenderer.send("request-new-msg-received", Messages);
+ break;
+ }
+
+ switch (data["cq"]) {
+ case "transmitting":
+ // CQ TRANSMITTING
+ ipcRenderer.send("request-show-cq-toast-transmitting", {
+ data: [data],
+ });
+ break;
+
+ case "received":
+ // CQ RECEIVED
+ ipcRenderer.send("request-show-cq-toast-received", {
+ data: [data],
+ });
+ break;
+ }
+
+ switch (data["qrv"]) {
+ case "transmitting":
+ // QRV TRANSMITTING
+ ipcRenderer.send("request-show-qrv-toast-transmitting", {
+ data: [data],
+ });
+ break;
+
+ case "received":
+ // QRV RECEIVED
+ ipcRenderer.send("request-show-qrv-toast-received", {
+ data: [data],
+ });
+ break;
+ }
+
+ switch (data["beacon"]) {
+ case "transmitting":
+ // BEACON TRANSMITTING
+ ipcRenderer.send("request-show-beacon-toast-transmitting", {
+ data: [data],
+ });
+ break;
+
+ case "received":
+ // BEACON RECEIVED
+ ipcRenderer.send("request-show-beacon-toast-received", {
+ data: [data],
+ });
+ ipcRenderer.send("request-new-msg-received", { data: [data] });
+ break;
+ }
+
+ switch (data["ping"]) {
+ case "transmitting":
+ // PING TRANSMITTING
+ ipcRenderer.send("request-show-ping-toast-transmitting", {
+ data: [data],
+ });
+ break;
+
+ case "received":
+ // PING RECEIVED
+ ipcRenderer.send("request-show-ping-toast-received", {
+ data: [data],
+ });
+ ipcRenderer.send("request-new-msg-received", { data: [data] });
+ break;
+
+ case "acknowledge":
+ // PING ACKNOWLEDGE
+ ipcRenderer.send("request-show-ping-toast-received-ack", {
+ data: [data],
+ });
+ ipcRenderer.send("request-new-msg-received", { data: [data] });
+ break;
+ }
+
+ // ARQ SESSION && freedata == tnc-message
+ if (data["arq"] == "session") {
+ switch (data["status"]) {
+ case "connecting":
+ // ARQ Open
+ ipcRenderer.send("request-show-arq-toast-session-connecting", {
+ data: [data],
+ });
+ break;
+
+ case "connected":
+ // ARQ Opening
+ ipcRenderer.send("request-show-arq-toast-session-connected", {
+ data: [data],
+ });
+ break;
+
+ case "waiting":
+ // ARQ Opening
+ ipcRenderer.send("request-show-arq-toast-session-waiting", {
+ data: [data],
+ });
+ break;
+
+ case "close":
+ // ARQ Closing
+ ipcRenderer.send("request-show-arq-toast-session-close", {
+ data: [data],
+ });
+ break;
+
+ case "failed":
+ // ARQ Failed
+ ipcRenderer.send("request-show-arq-toast-session-failed", {
+ data: [data],
+ });
+ break;
+ }
+ }
+ // ARQ TRANSMISSION && freedata == tnc-message
+ if (data["arq"] == "transmission") {
+ switch (data["status"]) {
+ case "opened":
+ // ARQ Open
+ ipcRenderer.send("request-show-arq-toast-datachannel-opened", {
+ data: [data],
+ });
+ break;
+
+ case "opening":
+ // ARQ Opening IRS/ISS
+ if (data["irs"] == "False") {
+ ipcRenderer.send("request-show-arq-toast-datachannel-opening", {
+ data: [data],
+ });
+ ipcRenderer.send("request-update-transmission-status", {
+ data: [data],
+ });
+ } else {
+ ipcRenderer.send(
+ "request-show-arq-toast-datachannel-received-opener",
+ { data: [data] },
+ );
+ ipcRenderer.send("request-update-reception-status", {
+ data: [data],
+ });
+ }
+
+ break;
+
+ case "waiting":
+ // ARQ waiting
+ ipcRenderer.send("request-show-arq-toast-datachannel-waiting", {
+ data: [data],
+ });
+ break;
+
+ case "receiving":
+ // ARQ RX
+ ipcRenderer.send("request-update-reception-status", {
+ data: [data],
+ });
+ break;
+
+ case "failed":
+ // ARQ TX Failed
+ if (data["reason"] == "protocol version missmatch") {
+ ipcRenderer.send(
+ "request-show-arq-toast-transmission-failed-ver",
+ { data: [data] },
+ );
+ } else {
+ ipcRenderer.send("request-show-arq-toast-transmission-failed", {
+ data: [data],
+ });
+ }
+ switch (data["irs"]) {
+ case "True":
+ ipcRenderer.send("request-update-reception-status", {
+ data: [data],
+ });
+ break;
+ default:
+ ipcRenderer.send("request-update-transmission-status", {
+ data: [data],
+ });
+ break;
+ }
+ break;
+
+ case "received":
+ // ARQ Received
+ ipcRenderer.send("request-show-arq-toast-transmission-received", {
+ data: [data],
+ });
+
+ ipcRenderer.send("request-update-reception-status", {
+ data: [data],
+ });
+
+ dataArray = [];
+ messageArray = [];
+
+ console.log(data);
+ // we need to encode here to do a deep check for checking if file or message
+ //var encoded_data = atob(data['data'])
+ var encoded_data = FD.atob_FD(data["data"]);
+ var splitted_data = encoded_data.split(split_char);
+
+ if (splitted_data[0] == "f") {
+ dataArray.push(data);
+ }
+
+ if (splitted_data[0] == "m") {
+ messageArray.push(data);
+ console.log(data);
+ }
+
+ rxBufferLengthGui = dataArray.length;
+ let Files = {
+ data: dataArray,
+ };
+ ipcRenderer.send("request-update-rx-buffer", Files);
+ ipcRenderer.send("request-new-msg-received", Files);
+
+ //rxMsgBufferLengthGui = messageArray.length;
+ let Messages = {
+ data: messageArray,
+ };
+ ipcRenderer.send("request-new-msg-received", Messages);
+ break;
+
+ case "transmitting":
+ // ARQ transmitting
+ ipcRenderer.send(
+ "request-show-arq-toast-transmission-transmitting",
+ { data: [data] },
+ );
+ ipcRenderer.send("request-update-transmission-status", {
+ data: [data],
+ });
+ break;
+
+ case "transmitted":
+ // ARQ transmitted
+ ipcRenderer.send(
+ "request-show-arq-toast-transmission-transmitted",
+ { data: [data] },
+ );
+ ipcRenderer.send("request-update-transmission-status", {
+ data: [data],
+ });
+ break;
+ }
+ }
+ }
+
+ // ----------- catch tnc info messages END -----------
+
+ // if we manually checking for the rx buffer we are getting an array of multiple data
+ if (data["command"] == "rx_buffer") {
+ console.log(data);
+ // iterate through buffer list and sort it to file or message array
+ dataArray = [];
+ messageArray = [];
+
+ for (var i = 0; i < data["data-array"].length; i++) {
+ try {
+ // we need to encode here to do a deep check for checking if file or message
+ //var encoded_data = atob(data['data-array'][i]['data'])
+ var encoded_data = FD.atob_FD(data["data-array"][i]["data"]);
+ var splitted_data = encoded_data.split(split_char);
+
+ if (splitted_data[0] == "f") {
+ dataArray.push(data["data-array"][i]);
+ }
+
+ if (splitted_data[0] == "m") {
+ messageArray.push(data["data-array"][i]);
+ }
+ } catch (e) {
+ console.log(e);
+ }
+ }
+
+ rxBufferLengthGui = dataArray.length;
+ let Files = {
+ data: dataArray,
+ };
+ ipcRenderer.send("request-update-rx-buffer", Files);
+
+ //rxMsgBufferLengthGui = messageArray.length;
+ let Messages = {
+ data: messageArray,
+ };
+ //ipcRenderer.send('request-update-rx-msg-buffer', Messages);
+ ipcRenderer.send("request-new-msg-received", Messages);
+ }
+ }
+
+ //finally delete message buffer
+ socketchunk = "";
+ }
+});
+
+function hexToBytes(hex) {
+ for (var bytes = [], c = 0; c < hex.length; c += 2)
+ bytes.push(parseInt(hex.substr(c, 2), 16));
+ return bytes;
+}
+
+//Get TNC State
+//exports.getTncState = function () {
+function getTncState(){
+ command = '{"type" : "get", "command" : "tnc_state"}';
+ writeTncCommand(command);
+};
+
+//Get DATA State
+//exports.getDataState = function () {
+function getDataState(){
+ command = '{"type" : "get", "command" : "data_state"}';
+ //writeTncCommand(command)
+};
+
+// Send Ping
+//exports.sendPing = function (dxcallsign) {
+function sendPing(dxcallsign){
+ command =
+ '{"type" : "ping", "command" : "ping", "dxcallsign" : "' +
+ dxcallsign +
+ '"}';
+ writeTncCommand(command);
+};
+
+// Send Mesh Ping
+//exports.sendMeshPing = function (dxcallsign) {
+function sendMeshPing(dxcallsign){
+ command =
+ '{"type" : "mesh", "command" : "ping", "dxcallsign" : "' +
+ dxcallsign +
+ '"}';
+ writeTncCommand(command);
+};
+
+// Send CQ
+//exports.sendCQ = function () {
+function sendCQ(){
+ command = '{"type" : "broadcast", "command" : "cqcqcq"}';
+ writeTncCommand(command);
+};
+
+// Set AUDIO Level
+//exports.setTxAudioLevel = function (value) {
+function setTxAudioLevel(value){
+ command =
+ '{"type" : "set", "command" : "tx_audio_level", "value" : "' + value + '"}';
+ writeTncCommand(command);
+};
+
+// Send File
+//exports.sendFile = function (
+function sendFile(
+ dxcallsign,
+ mode,
+ frames,
+ filename,
+ filetype,
+ data,
+ checksum,
+) {
+ console.log(data);
+ console.log(filetype);
+ console.log(filename);
+
+ var datatype = "f";
+
+ data =
+ datatype +
+ split_char +
+ filename +
+ split_char +
+ filetype +
+ split_char +
+ checksum +
+ split_char +
+ data;
+ console.log(data);
+ //console.log(btoa(data))
+ //Btoa / atob will not work with charsets > 8 bits (i.e. the emojis); should probably move away from using it
+ //TODO: Will need to update anyother occurences and throughly test
+ //data = btoa(data)
+ data = FD.btoa_FD(data);
+
+ command =
+ '{"type" : "arq", "command" : "send_raw", "parameter" : [{"dxcallsign" : "' +
+ dxcallsign +
+ '", "mode" : "' +
+ mode +
+ '", "n_frames" : "' +
+ frames +
+ '", "data" : "' +
+ data +
+ '"}]}';
+ writeTncCommand(command);
+};
+
+// Send Message
+//exports.sendMessage = function (
+function sendMessage(
+ dxcallsign,
+ mode,
+ frames,
+ data,
+ checksum,
+ uuid,
+ command,
+) {
+ data = FD.btoa_FD(
+ "m" +
+ split_char +
+ command +
+ split_char +
+ checksum +
+ split_char +
+ uuid +
+ split_char +
+ data,
+ );
+ command =
+ '{"type" : "arq", "command" : "send_raw", "uuid" : "' +
+ uuid +
+ '", "parameter" : [{"dxcallsign" : "' +
+ dxcallsign +
+ '", "mode" : "' +
+ mode +
+ '", "n_frames" : "' +
+ frames +
+ '", "data" : "' +
+ data +
+ '", "attempts": "10"}]}';
+ console.log(command);
+ console.log("-------------------------------------");
+ writeTncCommand(command);
+};
+
+// Send Request message
+//It would be then „m + split + request + split + request-type“
+function sendRequest(dxcallsign, mode, frames, data, command) {
+ data = FD.btoa_FD("m" + split_char + command + split_char + data);
+ command =
+ '{"type" : "arq", "command" : "send_raw", "parameter" : [{"dxcallsign" : "' +
+ dxcallsign +
+ '", "mode" : "' +
+ mode +
+ '", "n_frames" : "' +
+ frames +
+ '", "data" : "' +
+ data +
+ '", "attempts": "10"}]}';
+ console.log(command);
+ console.log("--------------REQ--------------------");
+ writeTncCommand(command);
+}
+
+// Send Response message
+//It would be then „m + split + request + split + request-type“
+function sendResponse(dxcallsign, mode, frames, data, command) {
+ data = FD.btoa_FD("m" + split_char + command + split_char + data);
+ command =
+ '{"type" : "arq", "command" : "send_raw", "parameter" : [{"dxcallsign" : "' +
+ dxcallsign +
+ '", "mode" : "' +
+ mode +
+ '", "n_frames" : "' +
+ frames +
+ '", "data" : "' +
+ data +
+ '", "attempts": "10"}]}';
+ console.log(command);
+ console.log("--------------RES--------------------");
+ writeTncCommand(command);
+}
+
+//Send station info request
+//exports.sendRequestInfo = function (dxcallsign) {
+function sendRequestInfo(dxcallsign){
+ //Command 0 = user/station information
+ //Command 1 = shared folder list
+ //Command 2 = shared file transfer
+ sendRequest(dxcallsign, 255, 1, "0", "req");
+};
+
+//Send shared folder file list request
+//exports.sendRequestSharedFolderList = function (dxcallsign) {
+function sendRequestSharedFolderList(dxcallsign){
+
+ //Command 0 = user/station information
+ //Command 1 = shared folder list
+ //Command 2 = shared file transfer
+ sendRequest(dxcallsign, 255, 1, "1", "req");
+};
+
+//Send shared file request
+//exports.sendRequestSharedFile = function (dxcallsign, file) {
+function sendRequestSharedFile(dxcallsign, file){
+ //Command 0 = user/station information
+ //Command 1 = shared folder list
+ //Command 2 = shared file transfer
+ sendRequest(dxcallsign, 255, 1, "2" + file, "req");
+};
+
+//Send station info response
+//exports.sendResponseInfo = function (dxcallsign, userinfo) {
+function sendResponseInfo(dxcallsign, userinfo){
+ //Command 0 = user/station information
+ //Command 1 = shared folder list
+ //Command 2 = shared file transfer
+ sendResponse(dxcallsign, 255, 1, userinfo, "res-0");
+};
+
+//Send shared folder response
+//exports.sendResponseSharedFolderList = function (dxcallsign, sharedFolderList) {
+function sendResponseSharedFolderList(dxcallsign, sharedFolderList){
+ //Command 0 = user/station information
+ //Command 1 = shared folder list
+ //Command 2 = shared file transfer
+ sendResponse(dxcallsign, 255, 1, sharedFolderList, "res-1");
+};
+
+//Send shared file response
+//exports.sendResponseSharedFile = function (
+function sendResponseSharedFile(
+ dxcallsign,
+ sharedFile,
+ sharedFileData,
+) {
+ console.log(
+ "In sendResponseSharedFile",
+ dxcallsign,
+ sharedFile,
+ sharedFileData,
+ );
+ //Command 0 = user/station information
+ //Command 1 = shared folder list
+ //Command 2 = shared file transfer
+ sendResponse(dxcallsign, 255, 1, sharedFile + "/" + sharedFileData, "res-2");
+};
+
+//STOP TRANSMISSION
+//exports.stopTransmission = function () {
+function stopTransmission(){
+ command = '{"type" : "arq", "command": "stop_transmission"}';
+ writeTncCommand(command);
+};
+
+// Get RX BUffer
+//exports.getRxBuffer = function () {
+function getRxBuffer(){
+ command = '{"type" : "get", "command" : "rx_buffer"}';
+
+ // call command only if new data arrived
+ if (rxBufferLengthGui != rxBufferLengthTnc) {
+ writeTncCommand(command);
+ }
+};
+
+// START BEACON
+//exports.startBeacon = function (interval) {
+function startBeacon(interval){
+ command =
+ '{"type" : "broadcast", "command" : "start_beacon", "parameter": "' +
+ interval +
+ '"}';
+ writeTncCommand(command);
+};
+
+// STOP BEACON
+//exports.stopBeacon = function () {
+function stopBeacon(){
+ command = '{"type" : "broadcast", "command" : "stop_beacon"}';
+ writeTncCommand(command);
+};
+
+// OPEN ARQ SESSION
+//exports.connectARQ = function (dxcallsign) {
+function connectARQ(dxcallsign){
+ command =
+ '{"type" : "arq", "command" : "connect", "dxcallsign": "' +
+ dxcallsign +
+ '", "attempts": "10"}';
+ writeTncCommand(command);
+};
+
+// CLOSE ARQ SESSION
+//exports.disconnectARQ = function () {
+function disconnectARQ(){
+ command = '{"type" : "arq", "command" : "disconnect"}';
+ writeTncCommand(command);
+};
+
+// SEND TEST FRAME
+//exports.sendTestFrame = function () {
+function sendTestFrame(){
+ command = '{"type" : "set", "command" : "send_test_frame"}';
+ writeTncCommand(command);
+};
+
+// SEND FEC
+//exports.sendFEC = function (mode, payload) {
+function sendFEC(mode, payload){
+ command =
+ '{"type" : "fec", "command" : "transmit", "mode" : "' +
+ mode +
+ '", "payload" : "' +
+ payload +
+ '"}';
+ writeTncCommand(command);
+};
+
+// SEND FEC IS WRITING
+//exports.sendFecIsWriting = function (mycallsign) {
+function sendFecIsWriting(mycallsign){
+ command =
+ '{"type" : "fec", "command" : "transmit_is_writing", "mycallsign" : "' +
+ mycallsign +
+ '"}';
+ writeTncCommand(command);
+};
+
+// SEND FEC TO BROADCASTCHANNEL
+//exports.sendBroadcastChannel = function (channel, data_out, uuid) {
+function sendBroadcastChannel(channel, data_out, uuid){
+ let checksum = "";
+ let command = "";
+ let data = FD.btoa_FD(
+ "m" +
+ split_char +
+ channel +
+ //split_char +
+ //checksum +
+ split_char +
+ uuid +
+ split_char +
+ data_out,
+ );
+ console.log(data.length);
+ let payload = data;
+ command =
+ '{"type" : "fec", "command" : "transmit", "mode": "datac4", "wakeup": "True", "payload" : "' +
+ payload +
+ '"}';
+ writeTncCommand(command);
+};
+
+// RECORD AUDIO
+//exports.record_audio = function () {
+function record_audio(){
+ command = '{"type" : "set", "command" : "record_audio"}';
+ writeTncCommand(command);
+};
+
+// SET FREQUENCY
+//exports.set_frequency = function (frequency) {
+function set_frequency(frequency){
+ command =
+ '{"type" : "set", "command" : "frequency", "frequency": ' + frequency + "}";
+ writeTncCommand(command);
+};
+
+// SET MODE
+//exports.set_mode = function (mode) {
+function set_mode(mode){
+ command = '{"type" : "set", "command" : "mode", "mode": "' + mode + '"}';
+ console.log(command);
+ writeTncCommand(command);
+};
+
+ipcRenderer.on("action-update-tnc-ip", (event, arg) => {
+ client.destroy();
+ let Data = {
+ busy_state: "-",
+ arq_state: "-",
+ //channel_state: "-",
+ frequency: "-",
+ mode: "-",
+ bandwidth: "-",
+ dbfs_level: 0,
+ };
+ ipcRenderer.send("request-update-tnc-state", Data);
+ tnc_port = arg.port;
+ tnc_host = arg.adress;
+ connectTNC();
+});
+
+// https://stackoverflow.com/a/50579690
+// crc32 calculation
+//console.log(crc32('abc'));
+//console.log(crc32('abc').toString(16).toUpperCase()); // hex
+var crc32 = function (r) {
+ for (var a, o = [], c = 0; c < 256; c++) {
+ a = c;
+ for (var f = 0; f < 8; f++) a = 1 & a ? 3988292384 ^ (a >>> 1) : a >>> 1;
+ o[c] = a;
+ }
+ for (var n = -1, t = 0; t < r.length; t++)
+ n = (n >>> 8) ^ o[255 & (n ^ r.charCodeAt(t))];
+ return (-1 ^ n) >>> 0;
+};
diff --git a/gui_vue/src/store/settingsStore.js b/gui_vue/src/store/settingsStore.js
index d06a7525..c03923d4 100644
--- a/gui_vue/src/store/settingsStore.js
+++ b/gui_vue/src/store/settingsStore.js
@@ -1,80 +1,80 @@
-import { defineStore } from 'pinia';
-import { ref, computed } from 'vue';
+import { defineStore } from 'pinia'
+import { ref, computed } from 'vue'
export const useSettingsStore = defineStore('settingsStore', () => {
// network
- var tnc_host = ref("127.0.0.1");
- var tnc_port = ref(3000);
- var daemon_host = ref("127.0.0.1");
- var daemon_port = ref(3001);
- var tnclocation = ref("localhost");
+ var tnc_host = ref("127.0.0.1")
+ var tnc_port = ref(3000)
+ var daemon_host = ref("127.0.0.1")
+ var daemon_port = ref(3001)
+ var tnclocation = ref("localhost")
// app
- var screen_height = ref(430);
- var screen_width = ref(1050);
- var theme = ref("default");
- var wftheme = ref(2);
- var high_graphics = ref("False");
- var auto_start = ref(0);
- var enable_sys_notification = ref(1);
+ var screen_height = ref(430)
+ var screen_width = ref(1050)
+ var theme = ref("default")
+ var wftheme = ref(2)
+ var high_graphics = ref("False")
+ var auto_start = ref(0)
+ var enable_sys_notification = ref(1)
// chat
- var shared_folder_path = ref(".");
- var enable_request_profile = ref("True");
- var enable_request_shared_folder = ref("False");
- var max_retry_attempts = ref(5);
- var enable_auto_retry = ref("False");
+ var shared_folder_path = ref(".")
+ var enable_request_profile = ref("True")
+ var enable_request_shared_folder = ref("False")
+ var max_retry_attempts = ref(5)
+ var enable_auto_retry = ref("False")
// station
- var mycall = ref("AA0AA-0");
- var mygrid = ref("JN20aa");
+ var mycall = ref("AA0AA-0")
+ var mygrid = ref("JN20aa")
// rigctld
- var hamlib_rigctld_port = ref(4532);
- var hamlib_rigctld_ip = ref("127.0.0.1");
- var radiocontrol = ref("disabled");
- var hamlib_deviceid = ref("RIG_MODEL_DUMMY_NOVFO");
- var hamlib_deviceport = ref("ignore");
- var hamlib_stop_bits = ref("ignore");
- var hamlib_data_bits = ref("ignore");
- var hamlib_handshake = ref("ignore");
- var hamlib_serialspeed = ref("ignore");
- var hamlib_dtrstate = ref("ignore");
- var hamlib_pttprotocol = ref("ignore");
- var hamlib_ptt_port = ref("ignore");
- var hamlib_dcd = ref("ignore");
- var hamlbib_serialspeed_ptt = ref(9600);
- var hamlib_rigctld_port = ref(4532);
- var hamlib_rigctld_ip = ref("127.0.0.1");
- var hamlib_rigctld_path = ref("");
- var hamlib_rigctld_server_port = ref(4532);
- var hamlib_rigctld_custom_args = ref("");
+ var hamlib_rigctld_port = ref(4532)
+ var hamlib_rigctld_ip = ref("127.0.0.1")
+ var radiocontrol = ref("disabled")
+ var hamlib_deviceid = ref("RIG_MODEL_DUMMY_NOVFO")
+ var hamlib_deviceport = ref("ignore")
+ var hamlib_stop_bits = ref("ignore")
+ var hamlib_data_bits = ref("ignore")
+ var hamlib_handshake = ref("ignore")
+ var hamlib_serialspeed = ref("ignore")
+ var hamlib_dtrstate = ref("ignore")
+ var hamlib_pttprotocol = ref("ignore")
+ var hamlib_ptt_port = ref("ignore")
+ var hamlib_dcd = ref("ignore")
+ var hamlbib_serialspeed_ptt = ref(9600)
+ var hamlib_rigctld_port = ref(4532)
+ var hamlib_rigctld_ip = ref("127.0.0.1")
+ var hamlib_rigctld_path = ref("")
+ var hamlib_rigctld_server_port = ref(4532)
+ var hamlib_rigctld_custom_args = ref("")
// tci
- var tci_ip = ref('127.0.0.1');
- var tci_port = ref(50001);
+ var tci_ip = ref('127.0.0.1')
+ var tci_port = ref(50001)
//tnc
- var spectrum = ref("waterfall");
- var enable_scatter = ref("False");
- var enable_fft = ref("False");
- var enable_fsk = ref("False");
- var low_bandwidth_mode = ref("False");
- var update_channel = ref("latest");
- var beacon_interval = ref(300);
- var received_files_folder = ref("None");
- var tuning_range_fmin = ref(-50.0);
- var tuning_range_fmax = ref(50.0);
- var respond_to_cq = ref("True");
- var rx_buffer_size = ref(16);
- var enable_explorer = ref("False");
- var explorer_stats = ref("False");
- var auto_tune = ref("False");
- var enable_is_writing = ref("True");
- var tx_delay = ref(0);
- var enable_mesh_features = ref("False");
+ var spectrum = ref("waterfall")
+ var enable_scatter = ref("False")
+ var enable_fft = ref("False")
+ var enable_fsk = ref("False")
+ var low_bandwidth_mode = ref("False")
+ var update_channel = ref("latest")
+ var beacon_interval = ref(300)
+ var received_files_folder = ref("None")
+ var tuning_range_fmin = ref(-50.0)
+ var tuning_range_fmax = ref(50.0)
+ var respond_to_cq = ref("True")
+ var rx_buffer_size = ref(16)
+ var enable_explorer = ref("False")
+ var explorer_stats = ref("False")
+ var auto_tune = ref("False")
+ var enable_is_writing = ref("True")
+ var tx_delay = ref(0)
+ var enable_mesh_features = ref("False")
function getJSON(){
var config_export = {
@@ -134,7 +134,7 @@ var config_export = {
"auto_start": auto_start.value,
"enable_sys_notification": enable_sys_notification.value,
"enable_mesh_features": enable_mesh_features.value
- };
+ }
return config_export
}
@@ -202,6 +202,6 @@ var config_export = {
tx_delay,
enable_mesh_features,
getJSON
- };
+ }
-});
+})