From 47882ee2db0edc63b0b8687bcf41963712831de3 Mon Sep 17 00:00:00 2001 From: jangliss Date: Sat, 12 Jun 2021 21:55:50 -0500 Subject: [PATCH 001/125] Temporarily disable LoTW full downloads on startup --- package.nw/lib/adif.js | 5926 ++++++++++++++++++++-------------------- 1 file changed, 2963 insertions(+), 2963 deletions(-) diff --git a/package.nw/lib/adif.js b/package.nw/lib/adif.js index 6c22c66..ef4ac67 100644 --- a/package.nw/lib/adif.js +++ b/package.nw/lib/adif.js @@ -1,2963 +1,2963 @@ -// GridTracker Copyright © 2021 GridTracker.org -// All rights reserved. -// See LICENSE for more information. - -var selectStartupLink = null; - -function dragOverHandler(ev) -{ - // Prevent default behavior (Prevent file from being opened) - ev.preventDefault(); -} - -function dropHandler(ev) -{ - // Prevent default behavior (Prevent file from being opened) - ev.preventDefault(); - if (ev.dataTransfer.items) - { - // Use DataTransferItemList interface to access the file(s) - for (var i = 0; i < ev.dataTransfer.items.length; i++) - { - // If dropped items aren't files, reject them - Entry = ev.dataTransfer.items[i].webkitGetAsEntry(); - if (Entry && typeof Entry.isFile != "undefined" && Entry.isFile == true) - { - var filename = ev.dataTransfer.items[i].getAsFile().path; - var test = filename.toLowerCase(); - var valid = test.endsWith(".adi") - ? true - : test.endsWith(".adif") - ? true - : test.endsWith(".log") - ? true - : !!test.endsWith(".txt"); - if (valid && fs.existsSync(filename)) - { - onAdiLoadComplete(fs.readFileSync(filename, "UTF-8"), false); - } - } - } - } -} - -function findAdiField(row, field) -{ - var value = ""; - var regex = new RegExp("<" + field + ":", "i"); - var firstSplitArray = row.split(regex); - if (firstSplitArray && firstSplitArray.length == 2) - { - var secondSplitArray = firstSplitArray[1].split(">"); - if (secondSplitArray.length > 1) - { - var newLenSearch = secondSplitArray[0].split(":"); - var newLen = newLenSearch[0]; - value = secondSplitArray[1].slice(0, newLen); - } - } - return value; -} - -function onAdiLoadComplete(adiBuffer, saveAdifFile, adifFileName, newFile) -{ - let rawAdiBuffer = ""; - if (typeof adiBuffer == "object") rawAdiBuffer = String(adiBuffer); - else rawAdiBuffer = adiBuffer; - - let activeAdifArray = Array(); - let activeAdifLogMode = true; - let eQSLfile = false; - - if (rawAdiBuffer.indexOf("PSKReporter") > -1) activeAdifLogMode = false; - - if (rawAdiBuffer.indexOf("Received eQSLs") > -1) eQSLfile = true; - - if (rawAdiBuffer.length > 1) - { - let regex = new RegExp("", "i"); - activeAdifArray = rawAdiBuffer.split(regex); - } - - let dateTime = new Date(); - let dupes = 0; - - for (let x = 0; x < activeAdifArray.length; x++) - { - let finalMode = ""; - - if (activeAdifArray[x].length > 3) - { - if (activeAdifLogMode) - { - let confirmed = false; - let finalGrid = findAdiField( - activeAdifArray[x], - "GRIDSQUARE" - ).toUpperCase(); - let vuccGrids = findAdiField( - activeAdifArray[x], - "VUCC_GRIDS" - ).toUpperCase(); - let finalVucc = []; - let finalDXcall = findAdiField(activeAdifArray[x], "CALL").replace( - "_", - "/" - ); - let finalDEcall = findAdiField( - activeAdifArray[x], - "STATION_CALLSIGN" - ).replace("_", "/"); - - if (finalDEcall == "") finalDEcall = myDEcall; - if ( - g_appSettings.workingCallsignEnable && - !(finalDEcall in g_appSettings.workingCallsigns) - ) - { continue; } - let finalRSTsent = findAdiField(activeAdifArray[x], "RST_SENT"); - let finalRSTrecv = findAdiField(activeAdifArray[x], "RST_RCVD"); - let finalBand = findAdiField(activeAdifArray[x], "BAND").toLowerCase(); - let dateVal = findAdiField(activeAdifArray[x], "QSO_DATE"); - let timeVal = findAdiField(activeAdifArray[x], "TIME_ON"); - let finalState = findAdiField( - activeAdifArray[x], - "STATE" - ).toUpperCase(); - if (finalState.length == 0) finalState = null; - let finalPropMode = findAdiField( - activeAdifArray[x], - "PROP_MODE" - ).toUpperCase(); - let finalSatName = findAdiField( - activeAdifArray[x], - "SAT_NAME" - ).toUpperCase(); - let finalCont = findAdiField(activeAdifArray[x], "CONT").toUpperCase(); - if (finalCont.length == 0) finalCont = null; - let finalCnty = findAdiField(activeAdifArray[x], "CNTY").toUpperCase(); - if (finalCnty.length == 0) finalCnty = null; - else - { - finalCnty = finalCnty.replaceAll(" ", ""); - } - let finalMode = findAdiField(activeAdifArray[x], "MODE").toUpperCase(); - let subMode = findAdiField(activeAdifArray[x], "SUBMODE"); - if (subMode == "FT4" && (finalMode == "MFSK" || finalMode == "DATA")) - { finalMode = "FT4"; } - if (subMode == "JS8" && finalMode == "MFSK") finalMode = "JS8"; - - if (finalBand == "oob" || finalBand == "") - { - finalBand = Number( - findAdiField(activeAdifArray[x], "FREQ") - ).formatBand(); - } - - let finalMsg = findAdiField(activeAdifArray[x], "COMMENT"); - let finalQslMsg = findAdiField(activeAdifArray[x], "QSLMSG"); - let finalQslMsgIntl = findAdiField(activeAdifArray[x], "QSLMSG_INTL"); - if (finalQslMsg.length > 1) finalMsg = finalQslMsg; - if (finalQslMsgIntl.length > 1 && finalMsg == "") - { finalMsg = finalQslMsgIntl; } - - let finalDxcc = Number(findAdiField(activeAdifArray[x], "DXCC")); - if (finalDxcc == 0) finalDxcc = Number(callsignToDxcc(finalDXcall)); - - if (!(finalDxcc in g_dxccToGeoData)) - { finalDxcc = Number(callsignToDxcc(finalDXcall)); } - - // If my callsign isn't present, it must be for me anyway - - let finalCqZone = findAdiField(activeAdifArray[x], "CQZ"); - if (finalCqZone.length == 1) finalCqZone = "0" + finalCqZone; - - if (parseInt(finalCqZone) < 1 || parseInt(finalCqZone) > 40) - { finalCqZone = ""; } - finalCqZone = String(finalCqZone); - let finalItuZone = findAdiField(activeAdifArray[x], "ITUZ"); - if (finalItuZone.length == 1) finalItuZone = "0" + finalItuZone; - - if (parseInt(finalItuZone) < 1 || parseInt(finalItuZone) > 90) - { finalItuZone = ""; } - finalItuZone = String(finalItuZone); - - let finalIOTA = findAdiField(activeAdifArray[x], "IOTA").toUpperCase(); - - let qrzConfirmed = findAdiField( - activeAdifArray[x], - "APP_QRZLOG_STATUS" - ).toUpperCase(); - let lotwConfirmed1 = findAdiField( - activeAdifArray[x], - "QSL_RCVD" - ).toUpperCase(); - let lotw_qsl_rcvd = findAdiField( - activeAdifArray[x], - "LOTW_QSL_RCVD" - ).toUpperCase(); - let eqsl_qsl_rcvd = findAdiField( - activeAdifArray[x], - "EQSL_QSL_RCVD" - ).toUpperCase(); - - if ( - qrzConfirmed == "C" || - lotw_qsl_rcvd == "Y" || - lotw_qsl_rcvd == "V" || - lotwConfirmed1 == "Y" || - eqsl_qsl_rcvd == "Y" || - eqsl_qsl_rcvd == "V" || - eQSLfile == true - ) - { confirmed = true; } - - let dateTime = new Date( - Date.UTC( - dateVal.substr(0, 4), - parseInt(dateVal.substr(4, 2)) - 1, - dateVal.substr(6, 2), - timeVal.substr(0, 2), - timeVal.substr(2, 2), - timeVal.substr(4, 2) - ) - ); - - let finalTime = parseInt(dateTime.getTime() / 1000); - - if ( - g_appSettings.workingDateEnable && - finalTime < g_appSettings.workingDate - ) - { continue; } - - finalGrid = finalGrid.substr(0, 6); - if (!validateGridFromString(finalGrid)) finalGrid = ""; - if (finalGrid == "" && vuccGrids != "") - { - finalVucc = vuccGrids.split(","); - finalGrid = finalVucc[0]; - finalVucc.shift(); - } - let isDigital = false; - let isPhone = false; - if (finalMode in g_modes) - { - isDigital = g_modes[finalMode]; - } - if (finalMode in g_modes_phone) - { - isPhone = g_modes_phone[finalMode]; - } - if (finalDXcall != "") - { - addDeDx( - finalGrid, - finalDXcall, - false, - false, - false, - finalDEcall, - finalRSTsent, - finalTime, - finalMsg, - finalMode, - finalBand, - confirmed, - false, - finalRSTrecv, - finalDxcc, - finalState, - finalCont, - finalCnty, - finalCqZone, - finalItuZone, - finalVucc, - finalPropMode, - isDigital, - isPhone, - finalIOTA, - finalSatName - ); - } - } - else - { - let finalMyGrid = findAdiField( - activeAdifArray[x], - "MY_GRIDSQUARE" - ).toUpperCase(); - let finalGrid = findAdiField( - activeAdifArray[x], - "GRIDSQUARE" - ).toUpperCase(); - let finalDXcall = findAdiField(activeAdifArray[x], "CALL"); - let finalDEcall = findAdiField(activeAdifArray[x], "OPERATOR"); - let finalRSTsent = findAdiField(activeAdifArray[x], "APP_PSKREP_SNR"); - let dateVal = findAdiField(activeAdifArray[x], "QSO_DATE"); - let timeVal = findAdiField(activeAdifArray[x], "TIME_ON"); - let finalMode = findAdiField(activeAdifArray[x], "MODE"); - let finalBand = Number( - findAdiField(activeAdifArray[x], "FREQ") - ).formatBand(); - let finalMsg = "-"; - let finalDxcc = Number(findAdiField(activeAdifArray[x], "DXCC")); - if (finalDxcc == 0) - { - if (finalDXcall == myDEcall) finalDxcc = callsignToDxcc(finalDEcall); - else finalDxcc = callsignToDxcc(finalDXcall); - } - - finalGrid = finalGrid.substr(0, 6); - - let dateTime = new Date( - Date.UTC( - dateVal.substr(0, 4), - parseInt(dateVal.substr(4, 2)) - 1, - dateVal.substr(6, 2), - timeVal.substr(0, 2), - timeVal.substr(2, 2), - timeVal.substr(4, 2) - ) - ); - let finalTime = parseInt(dateTime.getTime() / 1000); - if ( - finalGrid != "" && - finalDXcall != "" && - validateGridFromString(finalGrid) - ) - { - if (finalDXcall == myDEcall) - { - addDeDx( - finalMyGrid, - finalDEcall, - false, - false, - false, - finalDXcall, - null, - finalTime, - finalMsg, - finalMode, - finalBand, - false, - true, - finalRSTsent, - finalDxcc, - null, - null, - null, - null, - null - ); - } - else if (finalDEcall == myDEcall) - { - addDeDx( - finalGrid, - finalDXcall, - false, - false, - false, - "-", - finalRSTsent, - finalTime, - finalMsg, - finalMode, - finalBand, - false, - true, - null, - finalDxcc, - null, - null, - null, - null, - null - ); - } - else - { - addDeDx( - finalGrid, - finalDXcall, - false, - false, - false, - finalDEcall, - finalRSTsent, - finalTime, - finalMsg, - finalMode, - finalBand, - false, - true, - null, - finalDxcc, - null, - null, - null, - null, - null - ); - } - } - } - } - } - - redrawGrids(); - updateCountStats(); - updateLogbook(); - - if (g_fromDirectCallNoFileDialog == false) - { - fileSelector.setAttribute("type", ""); - fileSelector.setAttribute("type", "file"); - fileSelector.setAttribute("accept", ".adi,"); - fileSelector.value = null; - } - g_fromDirectCallNoFileDialog = false; - - updateRosterWorked(); - goProcessRoster(); -} - -function clubLogCallback(buffer, flag, cookie) -{ - var rawAdiBuffer = String(buffer); - if (rawAdiBuffer.indexOf("Invalid login") > -1) - { - if (flag) clubTestResult.innerHTML = "Invalid"; - } - else if (buffer == null) - { - if (flag) clubTestResult.innerHTML = "Unknown Error"; - } - else - { - if (flag) clubTestResult.innerHTML = "Passed"; - else - { - g_fromDirectCallNoFileDialog = true; - - rawAdiBuffer = cleanAndPrepADIF("clublog.adif", rawAdiBuffer); - - tryToWriteAdifToDocFolder("clublog.adif", rawAdiBuffer); - - onAdiLoadComplete(rawAdiBuffer, true, "clublog.adif", true); - } - } -} - -var g_isGettingClub = false; -function grabClubLog(test) -{ - if (g_isGettingClub == false) - { - if (test) clubTestResult.innerHTML = "Testing"; - - var postData = { - email: clubEmail.value, - password: clubPassword.value, - call: clubCall.value - }; - getAPostBuffer( - "https://clublog.org/getadif.php", - clubLogCallback, - test, - "https", - 443, - postData, - ClubLogImg, - "g_isGettingClub" - ); - } -} - -function tryToWriteAdifToDocFolder(filename, buffer, append = false) -{ - var finalFile = g_appData + g_dirSeperator + filename; - try - { - if (append == false) - { - fs.writeFileSync(finalFile, buffer); - return buffer; - } - else - { - fs.appendFileSync(finalFile, buffer); - return fs.readFileSync(finalFile); - } - } - catch (e) - { - return false; - } -} - -function cleanAndPrepADIF(name, adiBuffer, reverse = false, noheader = false) -{ - var rawAdiBuffer = adiBuffer; - var regex = new RegExp("", "i"); - rawAdiBuffer = rawAdiBuffer.replace(regex, ""); - regex = new RegExp("", "i"); - var adiArray = rawAdiBuffer.split(regex); - var activeAdifArray = Array(); - var activeAdifLogMode = true; - var finalBuffer = ""; - - if (noheader == false) finalBuffer = name + "\r\n"; - - if (adiArray.length > 1) - { - regex = new RegExp("", "i"); - activeAdifArray = adiArray[1].split(regex); - - if (reverse == false) - { - for (var x = 0; x < activeAdifArray.length - 1; x++) - { - var row = activeAdifArray[x].replace(/[\n\r]/g, ""); - if (row.length > 0) finalBuffer += row + "\r\n"; - } - } - else - { - for (var x = activeAdifArray.length - 1; x > -1; x--) - { - var row = activeAdifArray[x].replace(/[\n\r]/g, ""); - if (row.length > 0) finalBuffer += row + "\r\n"; - } - } - } - - return finalBuffer; -} - -function addZero(i) -{ - if (i < 10) - { - i = "0" + i; - } - return i; -} - -function getUTCString(d) -{ - var Y = d.getUTCFullYear(); - var M = addZero(d.getUTCMonth() + 1); - var D = addZero(d.getUTCDate()); - var h = addZero(d.getUTCHours()); - var m = addZero(d.getUTCMinutes()); - var s = addZero(d.getUTCSeconds()); - return Y + "-" + M + "-" + D + " " + h + ":" + m + ":" + s; -} - -function lotwCallback(buffer, flag) -{ - var rawAdiBuffer = String(buffer); - if (rawAdiBuffer.indexOf("password incorrect") > -1) - { - if (flag) lotwTestResult.innerHTML = "Invalid"; - } - else - { - if (flag) lotwTestResult.innerHTML = "Passed"; - else - { - var shouldAppend = false; - g_fromDirectCallNoFileDialog = true; - - rawAdiBuffer = cleanAndPrepADIF( - "lotw.adif", - rawAdiBuffer, - true, - shouldAppend - ); - - rawAdiBuffer = tryToWriteAdifToDocFolder( - "lotw.adif", - rawAdiBuffer, - shouldAppend - ); - - onAdiLoadComplete(rawAdiBuffer, true, "lotw.adif", true); - } - } -} - -function shouldWeAppendInsteadOfCreate(filename) -{ - var finalFile = g_appData + g_dirSeperator + filename; - try - { - if (fs.existsSync(finalFile)) return true; - else return false; - } - catch (e) - { - return false; - } -} - -function tryToDeleteLog(filename) -{ - var finalFile = g_appData + g_dirSeperator + filename; - try - { - if (fs.existsSync(finalFile)) - { - fs.unlinkSync(finalFile); - } - } - catch (e) {} -} - -var g_lotwCount = 0; - -var g_isGettingLOTW = false; - -function grabLOtWLog(test) -{ - if (g_isGettingLOTW == false) - { - var lastQSLDateString = - "&qso_qsorxsince=1945-01-01&qso_qslsince=1945-01-01"; - if (test == true) - { - lotwTestResult.innerHTML = "Testing"; - lastQSLDateString = "&qso_qsosince=2100-01-01"; - } - - getABuffer( - "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + - lotwLogin.value + - "&password=" + - encodeURIComponent(lotwPassword.value) + - "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + - lastQSLDateString, - lotwCallback, - test, - "https", - 443, - lotwLogImg, - "g_isGettingLOTW", - 120000 - ); - } -} - -function qrzCallback(buffer, flag) -{ - if (buffer.indexOf("invalid api key") > -1) - { - if (flag) qrzTestResult.innerHTML = "Invalid"; - } - else - { - if (flag) - { - qrzTestResult.innerHTML = "Passed"; - } - else - { - g_fromDirectCallNoFileDialog = true; - var htmlString = String(buffer).replace(/</g, "<"); - htmlString = htmlString.replace(/>/g, ">"); - htmlString = htmlString.replace("ADIF=", "QRZ\r\n"); - - htmlString = cleanAndPrepADIF("qrz.adif", htmlString); - - tryToWriteAdifToDocFolder("qrz.adif", htmlString); - - onAdiLoadComplete(htmlString, true, "qrz.adif", true); - } - } -} - -var g_isGettingQRZCom = false; -function grabQrzComLog(test) -{ - if (g_isGettingQRZCom == false) - { - var action = "FETCH"; - if (test) - { - qrzTestResult.innerHTML = "Testing"; - action = "STATUS"; - } - - getABuffer( - "https://logbook.qrz.com/api?KEY=" + - qrzApiKey.value + - "&ACTION=" + - action, - qrzCallback, - test, - "https", - 443, - qrzLogImg, - "g_isGettingQRZCom", - null - ); - } -} - -function ValidateQrzApi(inputText) -{ - inputText.value = inputText.value.toUpperCase(); - if (inputText.value.length == 19) - { - var passed = false; - var dashcount = 0; - for (var i = 0; i < inputText.value.length; i++) - { - if (inputText.value[i] == "-") dashcount++; - } - if (dashcount == 3) - { - passed = true; - } - if (passed) - { - inputText.style.color = "#FF0"; - inputText.style.backgroundColor = "green"; - - return true; - } - else - { - inputText.style.color = "white"; - inputText.style.backgroundColor = "red"; - return false; - } - } - else - { - inputText.style.color = "white"; - inputText.style.backgroundColor = "red"; - - return false; - } -} - -function ValidateText(inputText) -{ - if (inputText.value.length > 0) - { - inputText.style.color = "#FF0"; - inputText.style.backgroundColor = "green"; - return true; - } - else - { - inputText.style.color = "white"; - inputText.style.backgroundColor = "red"; - return false; - } -} - -function pskCallback(buffer, flag) -{ - g_fromDirectCallNoFileDialog = true; - var rawAdiBuffer = String(buffer); - - onAdiLoadComplete(rawAdiBuffer, false); -} - -var g_isGettingPsk = false; - -function grabPsk24() -{ - if (g_isGettingPsk == true) return; - - if (myDEcall.length > 0 && myDEcall != "NOCALL") - { - var days = 1; - if (pskImg.src == 1) days = 7; - getABuffer( - "https://pskreporter.info/cgi-bin/pskdata.pl?adif=1&days=" + - days + - "&receiverCallsign=" + - myDEcall.toLowerCase(), - pskCallback, - null, - "https", - 443, - pskImg, - "g_isGettingPsk" - ); - } -} - -function adifMenuCheckBoxChanged(what) -{ - g_adifLogSettings.menu[what.id] = what.checked; - var menuItem = what.id + "Div"; - if (what.checked == true) - { - document.getElementById(menuItem).style.display = "inline-block"; - } - else - { - document.getElementById(menuItem).style.display = "none"; - } - - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); - - if (what == buttonAdifCheckBox) setAdifStartup(loadAdifCheckBox); -} - -function adifStartupCheckBoxChanged(what) -{ - g_adifLogSettings.startup[what.id] = what.checked; - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); - - if (what == loadAdifCheckBox) setAdifStartup(loadAdifCheckBox); -} - -function adifLogQsoCheckBoxChanged(what) -{ - g_adifLogSettings.qsolog[what.id] = what.checked; - if (what.id == "logLOTWqsoCheckBox") - { - if (what.checked == true) - { - lotwUpload.style.display = "inline-block"; - trustedTestButton.style.display = "inline-block"; - } - else - { - lotwUpload.style.display = "none"; - trustedTestButton.style.display = "none"; - } - } - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); -} - -function adifNicknameCheckBoxChanged(what) -{ - g_adifLogSettings.nickname[what.id] = what.checked; - if (what.id == "nicknameeQSLCheckBox") - { - if (what.checked == true) - { - eQSLNickname.style.display = "inline-block"; - } - else - { - eQSLNickname.style.display = "none"; - } - } - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); -} - -function adifTextValueChange(what) -{ - what.value = what.value.trim(); - g_adifLogSettings.text[what.id] = what.value; - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); -} - -var fileSelector = document.createElement("input"); -fileSelector.setAttribute("type", "file"); -fileSelector.setAttribute("accept", ".adi,.adif"); -fileSelector.onchange = function () -{ - if (this.files && this.files[0]) - { - let path = this.value.replace(this.files[0].name, ""); - fileSelector.setAttribute("nwworkingdir", path); - - var reader = new FileReader(); - reader.onload = function (e) - { - if (e.target.error == null) - { - onAdiLoadComplete(e.target.result, false); - } - }; - - reader.readAsText(this.files[0]); - } -}; - -function adifLoadDialog() -{ - var exists = fileSelector.getAttribute("nwworkingdir"); - - fileSelector.setAttribute("nwworkingdir", g_appData); - - fileSelector.click(); - - return false; -} - -var startupFileSelector = document.createElement("input"); -startupFileSelector.setAttribute("type", "file"); -startupFileSelector.setAttribute("accept", ".adi,.adif"); -startupFileSelector.onchange = function () -{ - if (this.files && this.files[0]) - { - for (var i in g_startupLogs) - { - if (this.value == g_startupLogs[i].file) return; - } - var newObject = Object(); - newObject.name = this.files[0].name; - newObject.file = this.value; - g_startupLogs.push(newObject); - localStorage.startupLogs = JSON.stringify(g_startupLogs); - - let path = this.value.replace(this.files[0].name, ""); - startupFileSelector.setAttribute("nwworkingdir", path); - - setAdifStartup(loadAdifCheckBox); - } -}; - -function start_and_end(str) -{ - if (str.length > 31) - { - return ( - str.substr(0, 16) + " ... " + str.substr(str.length - 15, str.length) - ); - } - return str; -} - -function setFileSelectors() -{ - selectStartupLink = document.getElementById("selectAdifButton"); - selectStartupLink.onclick = function () - { - var exists = startupFileSelector.getAttribute("nwworkingdir"); - if (exists == null) - { - if (g_workingIniPath.length > 1) - { startupFileSelector.setAttribute("nwworkingdir", g_appData); } - } - - startupFileSelector.click(); - return false; - }; - - selectTqsl = document.getElementById("selectTQSLButton"); - selectTqsl.onclick = function () - { - tqslFileSelector.click(); - return false; - }; - lotwUpload.prepend(selectTqsl); -} - -var tqslFileSelector = document.createElement("input"); -tqslFileSelector.setAttribute("type", "file"); -tqslFileSelector.setAttribute("accept", "*"); -tqslFileSelector.onchange = function () -{ - if (this.files && this.files[0]) - { - g_trustedQslSettings.binaryFile = this.files[0].path; - var fs = require("fs"); - - if ( - fs.existsSync(g_trustedQslSettings.binaryFile) && - (g_trustedQslSettings.binaryFile.endsWith("tqsl.exe") || - g_trustedQslSettings.binaryFile.endsWith("tqsl")) - ) - { - g_trustedQslSettings.binaryFileValid = true; - } - else g_trustedQslSettings.binaryFileValid = false; - - if (g_trustedQslSettings.binaryFileValid == true) - { - tqslFileDiv.style.backgroundColor = "blue"; - } - else - { - tqslFileDiv.style.backgroundColor = "red"; - } - - tqslFileDiv.innerHTML = "" + start_and_end(this.files[0].path) + ""; - localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings); - } -}; - -function loadGtQSOLogFile() -{ - var fs = require("fs"); - - if (fs.existsSync(g_qsoLogFile)) - { - var rawAdiBuffer = fs.readFileSync(g_qsoLogFile); - - g_fromDirectCallNoFileDialog = true; - - onAdiLoadComplete(rawAdiBuffer, false); - } -} - -function loadWsjtLogFile() -{ - var fs = require("fs"); - if (fs.existsSync(g_workingIniPath + "wsjtx_log.adi")) - { - var rawAdiBuffer = fs.readFileSync(g_workingIniPath + "wsjtx_log.adi"); - g_fromDirectCallNoFileDialog = true; - onAdiLoadComplete(rawAdiBuffer, false); - } -} - -function findTrustedQSLPaths() -{ - var process = require("process"); - var base = null; - - if (g_trustedQslSettings.stationFileValid == true) - { - // double check the presence of the station_data; - if (!fs.existsSync(g_trustedQslSettings.stationFile)) - { - g_trustedQslSettings.stationFileValid = false; - } - } - if (g_trustedQslSettings.stationFileValid == false) - { - if (g_platform == "windows") - { - base = process.env.APPDATA + "\\TrustedQSL\\station_data"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.stationFile = base; - g_trustedQslSettings.stationFileValid = true; - } - else - { - base = process.env.LOCALAPPDATA + "\\TrustedQSL\\station_data"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.stationFile = base; - g_trustedQslSettings.stationFileValid = true; - } - } - } - else - { - base = process.env.HOME + "/.tqsl/station_data"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.stationFile = base; - g_trustedQslSettings.stationFileValid = true; - } - } - } - if (g_trustedQslSettings.stationFileValid == true) - { - var validate = false; - var option = document.createElement("option"); - option.value = ""; - option.text = "Select a Station"; - lotwStation.appendChild(option); - - var buffer = fs.readFileSync(g_trustedQslSettings.stationFile, "UTF-8"); - parser = new DOMParser(); - xmlDoc = parser.parseFromString(buffer, "text/xml"); - var x = xmlDoc.getElementsByTagName("StationData"); - for (var i = 0; i < x.length; i++) - { - option = document.createElement("option"); - option.value = x[i].getAttribute("name"); - option.text = x[i].getAttribute("name"); - if (option.value == g_adifLogSettings.text.lotwStation) - { - option.selected = true; - validate = true; - } - lotwStation.appendChild(option); - } - if (validate) - { - ValidateText(lotwStation); - } - } - - if (g_trustedQslSettings.binaryFileValid == true) - { - // double check the presence of the TrustedQSL binary; - if (!fs.existsSync(g_trustedQslSettings.binaryFile)) - { - g_trustedQslSettings.binaryFileValid = false; - } - } - if (g_trustedQslSettings.binaryFileValid == false || g_platform == "mac") - { - if (g_platform == "windows") - { - base = process.env["ProgramFiles(x86)"] + "\\TrustedQSL\\tqsl.exe"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - } - else if (g_platform == "mac") - { - base = "/Applications/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = - process.env.HOME + - "/Applications/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = - process.env.HOME + "/Applications/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = "/Applications/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = - process.env.HOME + - "/Desktop/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = - process.env.HOME + - "/Applications/Ham Radio/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - } - } - } - } - } - } - else if (g_platform == "linux") - { - base = "/usr/bin/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = "/usr/local/bin/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - } - } - } - localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings); -} - -function startupAdifLoadFunction() -{ - var fs = require("fs"); - - for (var i in g_startupLogs) - { - try - { - if (fs.existsSync(g_startupLogs[i].file)) - { - var rawAdiBuffer = fs.readFileSync(g_startupLogs[i].file); - g_fromDirectCallNoFileDialog = true; - onAdiLoadComplete(rawAdiBuffer, false); - } - } - catch (e) {} - } -} - -function setAdifStartup(checkbox) -{ - if (g_trustedQslSettings.binaryFile == null) - { g_trustedQslSettings.binaryFile = ""; } - - if ( - g_trustedQslSettings.binaryFile.endsWith("tqsl.exe") || - g_trustedQslSettings.binaryFile.endsWith("tqsl") - ) - { - g_trustedQslSettings.binaryFileValid = true; - } - else g_trustedQslSettings.binaryFileValid = false; - - if (g_trustedQslSettings.binaryFileValid == true) - { - tqslFileDiv.style.backgroundColor = "blue"; - } - else - { - tqslFileDiv.style.backgroundColor = "red"; - } - tqslFileDiv.innerHTML = - "" + start_and_end(g_trustedQslSettings.binaryFile) + ""; - - if (buttonAdifCheckBox.checked || loadAdifCheckBox.checked) - { - var worker = ""; - if (g_startupLogs.length > 0) - { - worker += ""; - for (var i in g_startupLogs) - { - worker += - ""; - } - worker += "
" + - g_startupLogs[i].name + - "
"; - } - else - { - worker = "No file(s) selected"; - } - startupLogFileDiv.innerHTML = worker; - selectFileOnStartupDiv.style.display = "block"; - } - else - { - startupLogFileDiv.innerHTML = "No file(s) selected"; - startupFileSelector.setAttribute("type", ""); - startupFileSelector.setAttribute("type", "file"); - startupFileSelector.setAttribute("accept", ".adi*"); - startupFileSelector.value = null; - selectFileOnStartupDiv.style.display = "none"; - } -} - -function removeStartupLog(i) -{ - if (i in g_startupLogs) - { - g_startupLogs.splice(i, 1); - localStorage.startupLogs = JSON.stringify(g_startupLogs); - setAdifStartup(loadAdifCheckBox); - } -} - -function startupAdifLoadCheck() -{ - logEventMedia.value = g_alertSettings.logEventMedia; - - loadWsjtLogFile(); - - if (loadGTCheckBox.checked == true) loadGtQSOLogFile(); - - if (loadAdifCheckBox.checked == true && g_startupLogs.length > 0) - { startupAdifLoadFunction(); } - - if (g_mapSettings.offlineMode == false) - { - if (g_appSettings.gtFlagImgSrc == 1) showGtFlags(); - - if (loadLOTWCheckBox.checked == true) grabLOtWLog(false); - - if (loadQRZCheckBox.checked == true) grabQrzComLog(false); - - if (loadClubCheckBox.checked == true) grabClubLog(false); - - if (loadPsk24CheckBox.checked == true) grabPsk24(); - } -} - -function getABuffer( - file_url, - callback, - flag, - mode, - port, - imgToGray, - stringOfFlag, - timeoutX -) -{ - let url = require("url"); - let http = require(mode); - let fileBuffer = null; - let options = null; - - options = { - host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api - port: port, - path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api - method: "get" - }; - - if (typeof stringOfFlag != "undefined") window[stringOfFlag] = true; - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = - "linear-gradient(grey 0%, black 0% 100% )"; - imgToGray.style.webkitFilter = "invert(100%) grayscale(1)"; - } - - let req = http.request(options, function (res) - { - let fsize = res.headers["content-length"]; - let cookies = null; - if (typeof res.headers["set-cookie"] != "undefined") - { cookies = res.headers["set-cookie"]; } - - res - .on("data", function (data) - { - if (fileBuffer == null) fileBuffer = data; - else fileBuffer += data; - - if (typeof imgToGray != "undefined") - { - let percent = 0; - if (fsize > 0) percent = parseInt((fileBuffer.length / fsize) * 100); - else percent = parseInt(((fileBuffer.length / 100000) * 100) % 100); - imgToGray.parentNode.style.background = - "linear-gradient(grey " + - percent + - "%, black " + - Number(percent + 10) + - "% 100% )"; - } - }) - .on("end", function () - { - if (typeof callback === "function") - { - // Call it, since we have confirmed it is callable - callback(fileBuffer, flag, cookies); - } - if (typeof stringOfFlag != "undefined") - { - window[stringOfFlag] = false; - } - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }) - .on("error", function () - { - if (typeof stringOfFlag != "undefined") - { - window[stringOfFlag] = false; - } - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }); - }); - - req.on("socket", function (socket) - { - socket.on("timeout", function () - { - req.abort(); - }); - }); - - req.on("error", function () - { - if (typeof stringOfFlag != "undefined") - { - window[stringOfFlag] = false; - } - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }); - - req.end(); -} - -function getAPostBuffer( - file_url, - callback, - flag, - mode, - port, - theData, - imgToGray, - stringOfFlag -) -{ - var querystring = require("querystring"); - var postData = querystring.stringify(theData); - var url = require("url"); - var http = require(mode); - var fileBuffer = null; - - var options = { - host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api - port: port, - path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api - method: "post", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - "Content-Length": postData.length - } - }; - - window[stringOfFlag] = true; - - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = - "linear-gradient(grey 0%, black 0% 100% )"; - imgToGray.style.webkitFilter = "invert(100%) grayscale(1)"; - } - - var req = http.request(options, function (res) - { - var fsize = res.headers["content-length"]; - var cookies = null; - if (typeof res.headers["set-cookie"] != "undefined") - { cookies = res.headers["set-cookie"]; } - - res - .on("data", function (data) - { - if (fileBuffer == null) fileBuffer = data; - else fileBuffer += data; - - if (typeof imgToGray != "undefined") - { - var percent = 0; - if (fsize > 0) percent = parseInt((fileBuffer.length / fsize) * 100); - else percent = parseInt(((fileBuffer.length / 100000) * 100) % 100); - - imgToGray.parentNode.style.background = - "linear-gradient(grey " + - percent + - "%, black " + - Number(percent + 10) + - "% 100% )"; - } - }) - .on("end", function () - { - if (typeof callback === "function") - { - // Call it, since we have confirmed it is callable - callback(fileBuffer, flag, cookies); - window[stringOfFlag] = false; - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - } - }) - .on("error", function () - { - window[stringOfFlag] = false; - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }); - }); - - req.on("socket", function (socket) - { - socket.on("timeout", function () - { - req.abort(); - }); - }); - - req.on("error", function (err) // eslint-disable-line node/handle-callback-err - { - window[stringOfFlag] = false; - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }); - - req.write(postData); - req.end(); -} - -function sendUdpMessage(msg, length, port, address) -{ - var dgram = require("dgram"); - var socket = dgram.createSocket({ type: "udp4", reuseAddr: true }); - socket.send(msg, 0, length, port, address, (err) => // eslint-disable-line node/handle-callback-err - { - socket.close(); - }); -} - -function sendTcpMessage(msg, length, port, address) -{ - var net = require("net"); - var client = new net.Socket(); - client.setTimeout(30000); - client.connect(port, address, function () - { - client.write(msg); - }); - - client.on("close", function () {}); -} - -function valueToAdiField(field, value) -{ - var adi = "<" + field + ":"; - adi += String(value).length + ">"; - adi += String(value) + " "; - return adi; -} - -function pad(value) -{ - if (value < 10) - { - return "0" + value; - } - else - { - return value; - } -} - -function HMSfromMilli(milli) -{ - var seconds = parseInt(milli / 1000); - var days = Math.floor(seconds / (3600 * 24)); - seconds -= days * 3600 * 24; - var hrs = Math.floor(seconds / 3600); - seconds -= hrs * 3600; - var mnts = Math.floor(seconds / 60); - seconds -= mnts * 60; - - val = String(pad(hrs)) + String(pad(mnts)) + String(pad(seconds)); - return String(val); -} - -function colonHMSfromMilli(milli) -{ - var seconds = parseInt(milli / 1000); - var days = Math.floor(seconds / (3600 * 24)); - seconds -= days * 3600 * 24; - var hrs = Math.floor(seconds / 3600); - seconds -= hrs * 3600; - var mnts = Math.floor(seconds / 60); - seconds -= mnts * 60; - - val = String(pad(hrs)) + ":" + String(pad(mnts)) + ":" + String(pad(seconds)); - return String(val); -} - -function colonHMSfromSeconds(secondsIn) -{ - var seconds = secondsIn; - var days = Math.floor(seconds / (3600 * 24)); - seconds -= days * 3600 * 24; - var hrs = Math.floor(seconds / 3600); - seconds -= hrs * 3600; - var mnts = Math.floor(seconds / 60); - seconds -= mnts * 60; - - val = String(pad(hrs)) + ":" + String(pad(mnts)) + ":" + String(pad(seconds)); - return String(val); -} - -function convertToDate(julian) -{ - var DAY = 86400000; - var HALF_DAY = DAY / 2; - var UNIX_EPOCH_JULIAN_DATE = 2440587.5; - var UNIX_EPOCH_JULIAN_DAY = 2440587; - return new Date((Number(julian) - UNIX_EPOCH_JULIAN_DATE) * DAY); -} - -var CLk = "25bc718451a71954cb6d0d1b50541dd45d4ba148"; - -var lastReportHash = null; - -var g_oldStyleLogMessage = null; - -function oldSendToLogger() -{ - var newMessage = Object.assign({}, g_oldStyleLogMessage); - - var band = Number(newMessage.Frequency / 1000000).formatBand(); - - if ( - newMessage.DXGrid.length == 0 && - newMessage.DXCall + band + newMessage.MO in g_liveCallsigns - ) - { - newMessage.DXGrid = g_liveCallsigns[ - newMessage.DXCall + band + newMessage.MO - ].grid.substr(0, 4); - } - - var report = ""; - - report += valueToAdiField( - "BAND", - Number(newMessage.Frequency / 1000000).formatBand() - ); - report += valueToAdiField("CALL", newMessage.DXCall.toUpperCase()); - report += valueToAdiField( - "FREQ", - Number(newMessage.Frequency / 1000000).toFixed(6) - ); - report += valueToAdiField("MODE", newMessage.MO.toUpperCase()); - var date = convertToDate(parseInt(newMessage.DateOn)); - var dataString = - date.getUTCFullYear() + - ("0" + (date.getUTCMonth() + 1)).slice(-2) + - ("0" + date.getUTCDate()).slice(-2); - report += valueToAdiField("QSO_DATE", dataString); - report += valueToAdiField("TIME_ON", HMSfromMilli(newMessage.TimeOn)); - - date = convertToDate(parseInt(newMessage.DateOff)); - dataString = - date.getUTCFullYear() + - ("0" + (date.getUTCMonth() + 1)).slice(-2) + - ("0" + date.getUTCDate()).slice(-2); - report += valueToAdiField("QSO_DATE_OFF", dataString); - report += valueToAdiField("TIME_OFF", HMSfromMilli(newMessage.TimeOff)); - - report += valueToAdiField("RST_RCVD", newMessage.ReportRecieved); - report += valueToAdiField("RST_SENT", newMessage.ReportSend); - report += valueToAdiField("TX_PWR", parseInt(newMessage.TXPower)); - report += valueToAdiField("GRIDSQUARE", newMessage.DXGrid); - - if (newMessage.Comments.length > 0) - { report += valueToAdiField("COMMENT", newMessage.Comments); } - - if (newMessage.Name.length > 0) - { report += valueToAdiField("NAME", newMessage.Name); } - - if (newMessage.Operatorcall.length > 0) - { - report += valueToAdiField("OPERATOR", newMessage.Operatorcall); - } - - if (newMessage.Mycall.length > 0) - { - report += valueToAdiField("STATION_CALLSIGN", newMessage.Mycall); - } - else if (myDEcall != "NOCALL" && myDEcall.length > 0) - { report += valueToAdiField("STATION_CALLSIGN", myDEcall); } - - if (newMessage.Mygrid.length > 0) - { - report += valueToAdiField("MY_GRIDSQUARE", newMessage.Mygrid); - } - else if (myDEGrid.length > 1) - { report += valueToAdiField("MY_GRIDSQUARE", myDEGrid); } - - report += ""; - - sendToLogger(report); -} - -var g_adifLookupMap = { - name: "NAME", - iota: "IOTA", - sota: "SOTA_REF", - continent: "CONT", - cqzone: "CQZ", - ituzone: "ITUZ", - email: "EMAIL", - county: "CNTY" -}; - -function sendToLogger(ADIF) -{ - let regex = new RegExp("", "i"); - let record = parseADIFRecord(ADIF.split(regex)[1]); - let localMode = record.MODE; - - if (localMode == "MFSK" && "SUBMODE" in record) - { - localMode = record.SUBMODE; - } - - if ( - (!("GRIDSQUARE" in record) || record.GRIDSQUARE.length == 0) && - record.CALL + record.BAND + localMode in g_liveCallsigns - ) - { - record.GRIDSQUARE = g_liveCallsigns[ - record.CALL + record.BAND + localMode - ].grid.substr(0, 4); - } - - if ("TX_PWR" in record) - { - record.TX_PWR = String(parseInt(record.TX_PWR)); - } - - if ( - (!("STATION_CALLSIGN" in record) || - record.STATION_CALLSIGN.length == 0) && - myDEcall != "NOCALL" && - myDEcall.length > 0 - ) - { - record.STATION_CALLSIGN = myDEcall; - } - - if ( - (!("MY_GRIDSQUARE" in record) || record.MY_GRIDSQUARE.length == 0) && - myDEGrid.length > 1 - ) - { - record.MY_GRIDSQUARE = myDEGrid; - } - - if (!("DXCC" in record)) - { - let dxcc = callsignToDxcc(record.CALL); - if (dxcc == -1) dxcc = 0; - record.DXCC = String(dxcc); - } - - // Tag: This is going to bite us in the butt later, but leaving it alone. - if (!("COUNTRY" in record) && Number(record.DXCC) > 0) - { - record.COUNTRY = g_dxccToADIFName[Number(record.DXCC)]; - } - - if (g_appSettings.lookupMerge == true) - { - let request = g_Idb - .transaction(["lookups"], "readwrite") - .objectStore("lookups") - .get(record.CALL); - - request.onsuccess = function (event) - { - if (request.result) - { - let lookup = request.result; - for (let key in lookup) - { - if (key in g_adifLookupMap) - { - record[g_adifLookupMap[key]] = lookup[key]; - } - } - if ("GRIDSQUARE" in record && "grid" in lookup) - { - if ( - record.GRIDSQUARE.substr(0, 4) == lookup.grid.substr(0, 4) - ) - { - record.GRIDSQUARE = lookup.grid; - } - } - if ( - g_appSettings.lookupMissingGrid && - "grid" in lookup && - (!("GRIDSQUARE" in record) || record.GRIDSQUARE.length == 0) - ) - { - record.GRIDSQUARE = lookup.grid; - } - } - finishSendingReport(record, localMode); - }; - - request.onerror = function (event) - { - finishSendingReport(record, localMode); - }; - } - else - { - finishSendingReport(record, localMode); - } -} - -function finishSendingReport(record, localMode) -{ - let report = ""; - - let reportHash = record.CALL + record.MODE + localMode; - - for (let key in record) - { - report += "<" + key + ":" + record[key].length + ">" + record[key] + " "; - } - report += ""; - - if (reportHash != lastReportHash) - { - lastReportHash = reportHash; - - if ( - g_N1MMSettings.enable == true && - g_N1MMSettings.port > 1024 && - g_N1MMSettings.ip.length > 4 - ) - { - sendUdpMessage( - report, - report.length, - parseInt(g_N1MMSettings.port), - g_N1MMSettings.ip - ); - addLastTraffic("Logged to N1MM"); - } - - if ( - g_log4OMSettings.enable == true && - g_log4OMSettings.port > 1024 && - g_log4OMSettings.ip.length > 4 - ) - { - sendUdpMessage( - "ADD " + report, - report.length + 4, - parseInt(g_log4OMSettings.port), - g_log4OMSettings.ip - ); - addLastTraffic("Logged to Log4OM"); - } - - try - { - onAdiLoadComplete("GT" + report); - } - catch (e) - { - addLastTraffic("Exception Internal Log"); - } - try - { - // Log worthy - if (logGTqsoCheckBox.checked == true) - { - var fs = require("fs"); - fs.appendFileSync(g_qsoLogFile, report + "\r\n"); - addLastTraffic( - "Logged to GridTracker backup" - ); - } - } - catch (e) - { - addLastTraffic( - "Exception GridTracker backup" - ); - } - - try - { - sendQrzLogEntry(report); - } - catch (e) - { - addLastTraffic("Exception QRZ Log"); - } - - try - { - sendClubLogEntry(report); - } - catch (e) - { - addLastTraffic("Exception ClubLog Log"); - } - - try - { - sendHrdLogEntry(report); - } - catch (e) - { - addLastTraffic("Exception HrdLog.net Log"); - } - - try - { - sendCloudlogEntry(report); - } - catch (e) - { - addLastTraffic("Exception Cloudlog Log"); - } - - if ( - g_acLogSettings.enable == true && - g_acLogSettings.port > 0 && - g_acLogSettings.ip.length > 4 - ) - { - try - { - sendACLogMessage(record, g_acLogSettings.port, g_acLogSettings.ip); - addLastTraffic("Logged to N3FJP"); - } - catch (e) - { - addLastTraffic("Exception N3FJP Log"); - } - } - - if ( - g_dxkLogSettings.enable == true && - g_dxkLogSettings.port > 0 && - g_dxkLogSettings.ip.length > 4 - ) - { - try - { - sendDXKeeperLogMessage( - report, - g_dxkLogSettings.port, - g_dxkLogSettings.ip - ); - addLastTraffic("Logged to DXKeeper"); - } - catch (e) - { - addLastTraffic("Exception DXKeeper Log"); - } - } - - if ( - g_HRDLogbookLogSettings.enable == true && - g_HRDLogbookLogSettings.port > 0 && - g_HRDLogbookLogSettings.ip.length > 4 - ) - { - try - { - sendHRDLogbookEntry( - record, - g_HRDLogbookLogSettings.port, - g_HRDLogbookLogSettings.ip - ); - addLastTraffic( - "Logged to HRD Logbook" - ); - } - catch (e) - { - addLastTraffic("Exception HRD Log"); - } - } - - try - { - sendLotwLogEntry(report); - } - catch (e) - { - addLastTraffic("Exception LoTW Log"); - } - - if ( - logeQSLQSOCheckBox.checked == true && - nicknameeQSLCheckBox.checked == true && - eQSLNickname.value.trim().length > 0 - ) - { - record.APP_EQSL_QTH_NICKNAME = eQSLNickname.value.trim(); - report = ""; - for (var key in record) - { - report += - "<" + key + ":" + record[key].length + ">" + record[key] + " "; - } - report += ""; - } - - try - { - sendeQSLEntry(report); - } - catch (e) - { - addLastTraffic("Exception LoTW Log"); - } - - try - { - alertLogMessage(); - } - catch (e) - { - addLastTraffic("Exception Alert Log"); - } - - if (lookupCloseLog.checked == true) - { - try - { - openLookupWindow(false); - } - catch (e) - { - addLastTraffic("Exception Hide Lookup"); - } - } - } - - return report; -} - -function alertLogMessage() -{ - if (logEventMedia.value != "none") - { - playAlertMediaFile(logEventMedia.value); - } -} - -function eqslCallback(buffer, flag) -{ - var result = String(buffer); - if (flag) - { - if (result.indexOf("No such Username/Password found") != -1) - { - eQSLTestResult.innerHTML = "Bad
Password
or
Nickname"; - logeQSLQSOCheckBox.checked = false; - adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); - } - else if (result.indexOf("No such Callsign found") != -1) - { - eQSLTestResult.innerHTML = "Unknown
Callsign"; - logeQSLQSOCheckBox.checked = false; - adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); - } - else if (result.indexOf("Your ADIF log file has been built") > -1 || result.indexOf("You have no log entries") > -1) - { - eQSLTestResult.innerHTML = "Passed"; - } - else if (result.indexOf("specify the desired User by using the QTHNickname") != -1) - { - eQSLTestResult.innerHTML = "QTH Nickname
Needed"; - } - else - { - eQSLTestResult.innerHTML = "Unknown
Error"; - logeQSLQSOCheckBox.checked = false; - adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); - } - } - else - { - if (result.indexOf("Error: No match on eQSL_User/eQSL_Pswd") != -1) - { - addLastTraffic( - "Fail log eQSL.cc (credentials)" - ); - } - if ( - result.indexOf("specify the desired User by using the QTHNickname") != -1 - ) - { - addLastTraffic( - "Fail log eQSL.cc (nickname)" - ); - } - else if (result.indexOf("Result: 0 out of 1 records") != -1) - { - addLastTraffic("Fail log eQSL.cc (dupe)"); - } - else if (result.indexOf("Result: 1 out of 1 records added") != -1) - { - addLastTraffic("Logged to eQSL.cc"); - } - else - { - addLastTraffic("Fail log eQSL.cc (?)"); - } - } -} - -function eQSLTest(test) -{ - if (g_mapSettings.offlineMode == true) return; - - eQSLTestResult.innerHTML = "Testing"; - - var fUrl = - "https://www.eQSL.cc/qslcard/DownloadInBox.cfm?UserName=" + - encodeURIComponent(eQSLUser.value) + - "&Password=" + - encodeURIComponent(eQSLPassword.value) + - "&RcvdSince=2020101"; - - if (nicknameeQSLCheckBox.checked == true) - { fUrl += "&QTHNickname=" + encodeURIComponent(eQSLNickname.value); } - getABuffer(fUrl, eqslCallback, true, "https", 443); -} - -function sendeQSLEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logeQSLQSOCheckBox.checked == true) - { - var pid = "GridTracker"; - var pver = String(gtVersion); - var header = "" + pid + "\r\n"; - header += "" + pver + "\r\n"; - header += "\r\n"; - var eReport = encodeURIComponent(header + report); - var fUrl = - "https://www.eQSL.cc/qslcard/importADIF.cfm?ADIFData=" + - eReport + - "&EQSL_USER=" + - encodeURIComponent(eQSLUser.value) + - "&EQSL_PSWD=" + - encodeURIComponent(eQSLPassword.value); - getABuffer(fUrl, eqslCallback, false, "https", 443); - } -} - -function testTrustedQSL(test) -{ - if (g_mapSettings.offlineMode == true) - { - lotwTestResult.innerHTML = "Currently
offline"; - return; - } - - if ( - logLOTWqsoCheckBox.checked == true && - g_trustedQslSettings.binaryFileValid == true && - g_trustedQslSettings.stationFileValid == true && - lotwStation.value.length > 0 - ) - { - lotwTestResult.innerHTML = "Testing Upload"; - - var child_process = require("child_process"); - var options = Array(); - options.push("-q"); - options.push("-v"); - - child_process.execFile( - g_trustedQslSettings.binaryFile, - options, - (error, stdout, stderr) => - { - if (error) - { - lotwTestResult.innerHTML = "Error encountered"; - } - lotwTestResult.innerHTML = stderr; - } - ); - } - else - { - var worker = ""; - if (g_trustedQslSettings.binaryFileValid == false) - { worker += "Invalid tqsl executable
"; } - if (g_trustedQslSettings.stationFileValid == false) - { worker += "TrustQSL not installed
"; } - if (!ValidateText(lotwTrusted)) worker += "TQSL Password missing
"; - if (!ValidateText(lotwStation)) worker += "Select Station
"; - lotwTestResult.innerHTML = worker; - } -} -var g_trustTempPath = ""; - -function sendLotwLogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if ( - logLOTWqsoCheckBox.checked == true && - g_trustedQslSettings.binaryFileValid == true && - g_trustedQslSettings.stationFileValid == true && - lotwStation.value.length > 0 - ) - { - var header = - "Generated " + userTimeString(null) + " for " + myDEcall + "\r\n\r\n"; - var pid = "GridTracker"; - var pver = String(gtVersion); - header += "" + pid + "\r\n"; - header += "" + pver + "\r\n"; - header += "\r\n"; - var finalLog = header + report + "\r\n"; - - g_trustTempPath = os.tmpdir() + g_dirSeperator + unique(report) + ".adif"; - fs.writeFileSync(g_trustTempPath, finalLog); - - var child_process = require("child_process"); - var options = Array(); - options.push("-a"); - options.push("all"); - options.push("-l"); - options.push(lotwStation.value); - if (lotwTrusted.value.length > 0) - { - options.push("-p"); - options.push(lotwTrusted.value); - } - options.push("-q"); - options.push("-x"); - options.push("-d"); - options.push("-u"); - options.push(g_trustTempPath); - - child_process.execFile( - g_trustedQslSettings.binaryFile, - options, - (error, stdout, stderr) => // eslint-disable-line node/handle-callback-err - { - if (stderr.indexOf("Final Status: Success") < 0) - { - alert(stderr); - addLastTraffic("Fail log to TQSL"); - } - else - { - addLastTraffic("Logged to TQSL"); - } - fs.unlinkSync(g_trustTempPath); - } - ); - } -} - -function n1mmLoggerChanged() -{ - g_N1MMSettings.enable = buttonN1MMCheckBox.checked; - g_N1MMSettings.ip = N1MMIpInput.value; - g_N1MMSettings.port = N1MMPortInput.value; - - localStorage.N1MMSettings = JSON.stringify(g_N1MMSettings); -} - -function log4OMLoggerChanged() -{ - g_log4OMSettings.enable = buttonLog4OMCheckBox.checked; - g_log4OMSettings.ip = log4OMIpInput.value; - g_log4OMSettings.port = log4OMPortInput.value; - - localStorage.log4OMSettings = JSON.stringify(g_log4OMSettings); -} - -function acLogLoggerChanged() -{ - g_acLogSettings.enable = buttonacLogCheckBox.checked; - g_acLogSettings.ip = acLogIpInput.value; - g_acLogSettings.port = acLogPortInput.value; - - localStorage.acLogSettings = JSON.stringify(g_acLogSettings); -} - -function dxkLogLoggerChanged() -{ - g_dxkLogSettings.enable = buttondxkLogCheckBox.checked; - g_dxkLogSettings.ip = dxkLogIpInput.value; - g_dxkLogSettings.port = dxkLogPortInput.value; - - localStorage.dxkLogSettings = JSON.stringify(g_dxkLogSettings); -} - -function hrdLogbookLoggerChanged() -{ - g_HRDLogbookLogSettings.enable = buttonHrdLogbookCheckBox.checked; - g_HRDLogbookLogSettings.ip = hrdLogbookIpInput.value; - g_HRDLogbookLogSettings.port = hrdLogbookPortInput.value; - - localStorage.HRDLogbookLogSettings = JSON.stringify(g_HRDLogbookLogSettings); -} - -function CloudUrlErrorCallback( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - timeoutCallback, - message -) -{ - CloudlogTestResult.innerHTML = message; -} - -function CloudlogSendLogResult(buffer, flag) -{ - if (flag && flag == true) - { - if (buffer) - { - if (buffer.indexOf("missing api key") > -1) - { - CloudlogTestResult.innerHTML = "API Key Invalid"; - } - else if (buffer.indexOf("created") > -1) - { - CloudlogTestResult.innerHTML = "Passed"; - } - else - { - CloudlogTestResult.innerHTML = "Invalid Response"; - } - } - else - { - CloudlogTestResult.innerHTML = "Invalid Response"; - } - } - else - { - if (buffer && buffer.indexOf("created") > -1) - { addLastTraffic("Logged to Cloudlog"); } - else addLastTraffic("Fail log to Cloudlog"); - } -} - -function qrzSendLogResult(buffer, flag) -{ - if (typeof buffer != "undefined" && buffer != null) - { - var data = String(buffer); - var kv = data.split("&"); - if (kv.length > 0) - { - var arrData = Object(); - for (var x in kv) - { - var split = kv[x].split("="); - arrData[split[0]] = split[1]; - } - if ( - typeof arrData.RESULT == "undefined" || - arrData.RESULT != "OK" - ) - { - alert( - "Error uploading QSO to QRZ.com (" + - (arrData.REASON || "Unknown error") + - ")" - ); - addLastTraffic("Fail log to QRZ.com"); - } - else - { addLastTraffic("Logged to QRZ.com"); } - } - } - else alert("Error uploading QSO to QRZ.com (No response)"); -} - -function postDialogRetryCallback( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - timeoutCallback, - who -) -{ - if (window.confirm("Error sending QSO to " + who + ", retry?")) - { - getPostBuffer( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - postDialogRetryCallback, - who - ); - } -} - -function postRetryErrorCallaback( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - timeoutCallback, - who -) -{ - getPostBuffer( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - postDialogRetryCallback, - who - ); -} - -function sendQrzLogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logQRZqsoCheckBox.checked == true && ValidateQrzApi(qrzApiKey)) - { - if (typeof nw != "undefined") - { - var postData = { - KEY: qrzApiKey.value, - ACTION: "INSERT", - ADIF: report - }; - getPostBuffer( - "https://logbook.qrz.com/api", - qrzSendLogResult, - null, - "https", - 443, - postData, - 30000, - postRetryErrorCallaback, - "QRZ.com" - ); - } - } -} - -function clubLogQsoResult(buffer, flag) -{ - addLastTraffic("Logged to ClubLog.org"); -} - -function sendClubLogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logClubqsoCheckBox.checked == true) - { - if (typeof nw != "undefined") - { - var postData = { - email: clubEmail.value, - password: clubPassword.value, - callsign: clubCall.value, - adif: report, - api: CLk - }; - - getPostBuffer( - "https://clublog.org/realtime.php", - clubLogQsoResult, - null, - "https", - 443, - postData, - 30000, - postRetryErrorCallaback, - "ClubLog.org" - ); - } - } -} - -function sendCloudlogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logCloudlogQSOCheckBox.checked == true) - { - if (typeof nw != "undefined") - { - var postData = { key: CloudlogAPI.value, type: "adif", string: report }; - getPostJSONBuffer( - CloudlogURL.value, - CloudlogSendLogResult, - null, - "https", - 80, - postData, - 10000, - CloudUrlErrorCallback, - "Failed to Send" - ); - } - } -} - -function hrdSendLogResult(buffer, flag) -{ - if (flag && flag == true) - { - if (buffer.indexOf("Unknown user") > -1) - { - HRDLogTestResult.innerHTML = "Failed"; - logHRDLOGqsoCheckBox.checked = false; - adifLogQsoCheckBoxChanged(logHRDLOGqsoCheckBox); - } - else HRDLogTestResult.innerHTML = "Passed"; - } - else - { - if (buffer.indexOf("Unknown user") == -1) - { addLastTraffic("Logged to HRDLOG.net"); } - else - { addLastTraffic("Fail log to HRDLOG.net"); } - } -} - -function sendHrdLogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logHRDLOGqsoCheckBox.checked == true) - { - if (typeof nw != "undefined") - { - var postData = { - Callsign: HRDLOGCallsign.value, - Code: HRDLOGUploadCode.value, - App: "GridTracker " + gtVersion, - ADIFData: report - }; - getPostBuffer( - "https://www.hrdlog.net/NewEntry.aspx", - hrdSendLogResult, - null, - "https", - 443, - postData, - 30000, - postRetryErrorCallaback, - "HRDLog.net" - ); - } - } -} - -function hrdCredentialTest(test) -{ - if (test && test == true) - { - HRDLogTestResult.innerHTML = "Testing"; - - if (typeof nw != "undefined") - { - var postData = { - Callsign: HRDLOGCallsign.value, - Code: HRDLOGUploadCode.value - }; - getPostBuffer( - "https://www.hrdlog.net/NewEntry.aspx", - hrdSendLogResult, - test, - "https", - 443, - postData - ); - } - } -} - -function ClublogTest(test) -{ - if (test && test == true) - { - CloudlogTestResult.innerHTML = "Testing"; - - if (typeof nw != "undefined") - { - var postData = { key: CloudlogAPI.value, type: "adif", string: "" }; - getPostJSONBuffer( - CloudlogURL.value, - CloudlogSendLogResult, - test, - "https", - 80, - postData, - 10000, - CloudUrlErrorCallback, - "No Response
or
Timeout" - ); - } - } -} - -function getPostJSONBuffer( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - timeoutCallback, - who -) -{ - try - { - var postData = JSON.stringify(theData); - var url = require("url"); - var protocol = url.parse(file_url).protocol; // eslint-disable-line node/no-deprecated-api - var http = require(protocol.replace(":", "")); - var fileBuffer = null; - var options = { - host: url.parse(file_url).hostname, // eslint-disable-line node/no-deprecated-api - port: url.parse(file_url).port, // eslint-disable-line node/no-deprecated-api - path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api - method: "post", - headers: { - "Content-Type": "application/json", - "Content-Length": postData.length - } - }; - var req = http.request(options, function (res) - { - var fsize = res.headers["content-length"]; - var cookies = null; - if (typeof res.headers["set-cookie"] != "undefined") - { cookies = res.headers["set-cookie"]; } - res - .on("data", function (data) - { - if (fileBuffer == null) fileBuffer = data; - else fileBuffer += data; - }) - .on("end", function () - { - if (typeof callback === "function") - { - // Call it, since we have confirmed it is callable - callback(fileBuffer, flag, cookies); - } - }) - .on("error", function () {}); - }); - if (typeof timeoutMs == "number" && timeoutMs > 0) - { - req.on("socket", function (socket) - { - socket.setTimeout(timeoutMs); - socket.on("timeout", function () - { - req.abort(); - }); - }); - req.on("error", function (err) // eslint-disable-line node/handle-callback-err - { - if (typeof timeoutCallback != "undefined") - { - timeoutCallback( - file_url, - callback, - flag, - mode, - 80, - theData, - timeoutMs, - timeoutCallback, - who - ); - } - }); - } - req.write(postData); - req.end(); - } - catch (e) - { - if (typeof timeoutCallback != "undefined") - { - timeoutCallback( - file_url, - callback, - flag, - mode, - 80, - theData, - timeoutMs, - timeoutCallback, - "Invalid Url" - ); - } - } -} - -function valueToXmlField(field, value) -{ - var adi = "<" + field + ">"; - adi += String(value); - adi += ""; - return adi; -} - -function aclUpdateControlValue(control, value) -{ - return ( - valueToXmlField( - "CMD", - "" + - valueToXmlField("CONTROL", control) + - valueToXmlField("VALUE", value) - ) + "\r\n" - ); -} - -function aclAction(action) -{ - return ( - valueToXmlField("CMD", "" + valueToXmlField("VALUE", action)) + - "\r\n" - ); -} - -function adifField(record, key) -{ - if (key in record) return record[key]; - else return ""; -} -function sendACLogMessage(record, port, address) -{ - var report = ""; - - report += aclAction("CLEAR"); - report += aclUpdateControlValue("TXTENTRYBAND", adifField(record, "BAND")); - report += aclUpdateControlValue("TXTENTRYCALL", adifField(record, "CALL")); - report += aclAction("CALLTAB"); - report += aclUpdateControlValue( - "TXTENTRYFREQUENCY", - adifField(record, "FREQ") - ); - if (adifField(record, "SUBMODE").length > 0) - { - report += aclUpdateControlValue( - "TXTENTRYMODE", - adifField(record, "SUBMODE") - ); - } - else - { report += aclUpdateControlValue("TXTENTRYMODE", adifField(record, "MODE")); } - - var date = adifField(record, "QSO_DATE"); - var dataString = - date.substr(0, 4) + "/" + date.substr(4, 2) + "/" + date.substr(6); - - report += aclUpdateControlValue("TXTENTRYDATE", dataString); - - var timeVal = adifField(record, "TIME_ON"); - var whenString = - timeVal.substr(0, 2) + - ":" + - timeVal.substr(2, 2) + - ":" + - timeVal.substr(4, 2); - report += aclUpdateControlValue("TXTENTRYTIMEON", whenString); - - timeVal = adifField(record, "TIME_OFF"); - whenString = - timeVal.substr(0, 2) + - ":" + - timeVal.substr(2, 2) + - ":" + - timeVal.substr(4, 2); - report += aclUpdateControlValue("TXTENTRYTIMEOFF", whenString); - - report += aclUpdateControlValue( - "TXTENTRYRSTR", - adifField(record, "RST_RCVD") - ); - report += aclUpdateControlValue( - "TXTENTRYRSTS", - adifField(record, "RST_SENT") - ); - report += aclUpdateControlValue("TXTENTRYPOWER", adifField(record, "TX_PWR")); - report += aclUpdateControlValue( - "TXTENTRYGRID", - adifField(record, "GRIDSQUARE") - ); - report += aclUpdateControlValue( - "TXTENTRYCOMMENTS", - adifField(record, "COMMENT") - ); - report += aclUpdateControlValue("TXTENTRYNAMER", adifField(record, "NAME")); - report += aclUpdateControlValue("TXTENTRYIOTA", adifField(record, "IOTA")); - report += aclUpdateControlValue( - "TXTENTRYCONTINENT", - adifField(record, "CONT") - ); - report += aclUpdateControlValue("TXTENTRYITUZ", adifField(record, "ITUZ")); - report += aclUpdateControlValue("TXTENTRYCQZONE", adifField(record, "CQZ")); - report += aclUpdateControlValue("TXTENTRYCOUNTYR", adifField(record, "CNTY")); - - var sentSpcNum = false; - if (adifField(record, "SRX").length > 0) - { - report += aclUpdateControlValue( - "TXTENTRYSERIALNOR", - adifField(record, "SRX") - ); - } - else if (adifField(record, "CONTEST_ID").length > 0) - { - report += aclUpdateControlValue( - "TXTENTRYSPCNUM", - adifField(record, "SRX_STRING") - ); - sentSpcNum = true; - report += aclUpdateControlValue( - "TXTENTRYCLASS", - adifField(record, "CLASS") - ); - report += aclUpdateControlValue( - "TXTENTRYSECTION", - adifField(record, "ARRL_SECT") - ); - } - - if (adifField(record, "STATE").length > 0) - { - report += aclUpdateControlValue( - "TXTENTRYSTATE", - adifField(record, "STATE") - ); - if (sentSpcNum == false) - { - report += aclUpdateControlValue( - "TXTENTRYSPCNUM", - adifField(record, "STATE") - ); - } - } - - report += aclAction("ENTER"); - - sendTcpMessage(report, report.length, port, address); -} - -function sendDXKeeperLogMessage(newMessage, port, address) -{ - var report = ""; - - report += valueToAdiField("command", "log"); - report += valueToAdiField("parameters", newMessage); - report += "\r\n"; - - sendTcpMessage(report, report.length, Number(port) + 1, address); -} - -function parseADIFRecord(adif) -{ - var regex = new RegExp("", "i"); - var newLine = adif.split(regex); - var line = newLine[0].trim(); // Catch the naughty case of someone sending two records at the same time - var record = {}; - - // because strings are not escaped for adif.. ie: :'s and <'s .. we have to walk from left to right - // cheesy, but damn i'm tired of parsing things - var x = 0; - while (line.length > 0) - { - while (line.charAt(0) != "<" && line.length > 0) - { - line = line.substr(1); - } - if (line.length > 0) - { - line = line.substr(1); - var where = line.indexOf(":"); - if (where != -1) - { - var fieldName = line.substr(0, where).toUpperCase(); - line = line.substr(fieldName.length + 1); - var fieldLength = parseInt(line); - var end = line.indexOf(">"); - if (end > 0) - { - line = line.substr(end + 1); - var fieldValue = line.substr(0, fieldLength); - line = line.substr(fieldLength); - record[fieldName] = fieldValue; - } - } - } - } - - return record; -} - -function sendHRDLogbookEntry(report, port, address) -{ - var command = "ver\rdb add {"; - var items = Object.assign({}, report); - - items.FREQ = items.FREQ.split(".").join(""); - - for (var item in items) - { - command += item + "=\"" + items[item] + "\" "; - } - - command += "}\rexit\r"; - - sendTcpMessage(command, command.length, Number(port), address); -} +// GridTracker Copyright © 2021 GridTracker.org +// All rights reserved. +// See LICENSE for more information. + +var selectStartupLink = null; + +function dragOverHandler(ev) +{ + // Prevent default behavior (Prevent file from being opened) + ev.preventDefault(); +} + +function dropHandler(ev) +{ + // Prevent default behavior (Prevent file from being opened) + ev.preventDefault(); + if (ev.dataTransfer.items) + { + // Use DataTransferItemList interface to access the file(s) + for (var i = 0; i < ev.dataTransfer.items.length; i++) + { + // If dropped items aren't files, reject them + Entry = ev.dataTransfer.items[i].webkitGetAsEntry(); + if (Entry && typeof Entry.isFile != "undefined" && Entry.isFile == true) + { + var filename = ev.dataTransfer.items[i].getAsFile().path; + var test = filename.toLowerCase(); + var valid = test.endsWith(".adi") + ? true + : test.endsWith(".adif") + ? true + : test.endsWith(".log") + ? true + : !!test.endsWith(".txt"); + if (valid && fs.existsSync(filename)) + { + onAdiLoadComplete(fs.readFileSync(filename, "UTF-8"), false); + } + } + } + } +} + +function findAdiField(row, field) +{ + var value = ""; + var regex = new RegExp("<" + field + ":", "i"); + var firstSplitArray = row.split(regex); + if (firstSplitArray && firstSplitArray.length == 2) + { + var secondSplitArray = firstSplitArray[1].split(">"); + if (secondSplitArray.length > 1) + { + var newLenSearch = secondSplitArray[0].split(":"); + var newLen = newLenSearch[0]; + value = secondSplitArray[1].slice(0, newLen); + } + } + return value; +} + +function onAdiLoadComplete(adiBuffer, saveAdifFile, adifFileName, newFile) +{ + let rawAdiBuffer = ""; + if (typeof adiBuffer == "object") rawAdiBuffer = String(adiBuffer); + else rawAdiBuffer = adiBuffer; + + let activeAdifArray = Array(); + let activeAdifLogMode = true; + let eQSLfile = false; + + if (rawAdiBuffer.indexOf("PSKReporter") > -1) activeAdifLogMode = false; + + if (rawAdiBuffer.indexOf("Received eQSLs") > -1) eQSLfile = true; + + if (rawAdiBuffer.length > 1) + { + let regex = new RegExp("", "i"); + activeAdifArray = rawAdiBuffer.split(regex); + } + + let dateTime = new Date(); + let dupes = 0; + + for (let x = 0; x < activeAdifArray.length; x++) + { + let finalMode = ""; + + if (activeAdifArray[x].length > 3) + { + if (activeAdifLogMode) + { + let confirmed = false; + let finalGrid = findAdiField( + activeAdifArray[x], + "GRIDSQUARE" + ).toUpperCase(); + let vuccGrids = findAdiField( + activeAdifArray[x], + "VUCC_GRIDS" + ).toUpperCase(); + let finalVucc = []; + let finalDXcall = findAdiField(activeAdifArray[x], "CALL").replace( + "_", + "/" + ); + let finalDEcall = findAdiField( + activeAdifArray[x], + "STATION_CALLSIGN" + ).replace("_", "/"); + + if (finalDEcall == "") finalDEcall = myDEcall; + if ( + g_appSettings.workingCallsignEnable && + !(finalDEcall in g_appSettings.workingCallsigns) + ) + { continue; } + let finalRSTsent = findAdiField(activeAdifArray[x], "RST_SENT"); + let finalRSTrecv = findAdiField(activeAdifArray[x], "RST_RCVD"); + let finalBand = findAdiField(activeAdifArray[x], "BAND").toLowerCase(); + let dateVal = findAdiField(activeAdifArray[x], "QSO_DATE"); + let timeVal = findAdiField(activeAdifArray[x], "TIME_ON"); + let finalState = findAdiField( + activeAdifArray[x], + "STATE" + ).toUpperCase(); + if (finalState.length == 0) finalState = null; + let finalPropMode = findAdiField( + activeAdifArray[x], + "PROP_MODE" + ).toUpperCase(); + let finalSatName = findAdiField( + activeAdifArray[x], + "SAT_NAME" + ).toUpperCase(); + let finalCont = findAdiField(activeAdifArray[x], "CONT").toUpperCase(); + if (finalCont.length == 0) finalCont = null; + let finalCnty = findAdiField(activeAdifArray[x], "CNTY").toUpperCase(); + if (finalCnty.length == 0) finalCnty = null; + else + { + finalCnty = finalCnty.replaceAll(" ", ""); + } + let finalMode = findAdiField(activeAdifArray[x], "MODE").toUpperCase(); + let subMode = findAdiField(activeAdifArray[x], "SUBMODE"); + if (subMode == "FT4" && (finalMode == "MFSK" || finalMode == "DATA")) + { finalMode = "FT4"; } + if (subMode == "JS8" && finalMode == "MFSK") finalMode = "JS8"; + + if (finalBand == "oob" || finalBand == "") + { + finalBand = Number( + findAdiField(activeAdifArray[x], "FREQ") + ).formatBand(); + } + + let finalMsg = findAdiField(activeAdifArray[x], "COMMENT"); + let finalQslMsg = findAdiField(activeAdifArray[x], "QSLMSG"); + let finalQslMsgIntl = findAdiField(activeAdifArray[x], "QSLMSG_INTL"); + if (finalQslMsg.length > 1) finalMsg = finalQslMsg; + if (finalQslMsgIntl.length > 1 && finalMsg == "") + { finalMsg = finalQslMsgIntl; } + + let finalDxcc = Number(findAdiField(activeAdifArray[x], "DXCC")); + if (finalDxcc == 0) finalDxcc = Number(callsignToDxcc(finalDXcall)); + + if (!(finalDxcc in g_dxccToGeoData)) + { finalDxcc = Number(callsignToDxcc(finalDXcall)); } + + // If my callsign isn't present, it must be for me anyway + + let finalCqZone = findAdiField(activeAdifArray[x], "CQZ"); + if (finalCqZone.length == 1) finalCqZone = "0" + finalCqZone; + + if (parseInt(finalCqZone) < 1 || parseInt(finalCqZone) > 40) + { finalCqZone = ""; } + finalCqZone = String(finalCqZone); + let finalItuZone = findAdiField(activeAdifArray[x], "ITUZ"); + if (finalItuZone.length == 1) finalItuZone = "0" + finalItuZone; + + if (parseInt(finalItuZone) < 1 || parseInt(finalItuZone) > 90) + { finalItuZone = ""; } + finalItuZone = String(finalItuZone); + + let finalIOTA = findAdiField(activeAdifArray[x], "IOTA").toUpperCase(); + + let qrzConfirmed = findAdiField( + activeAdifArray[x], + "APP_QRZLOG_STATUS" + ).toUpperCase(); + let lotwConfirmed1 = findAdiField( + activeAdifArray[x], + "QSL_RCVD" + ).toUpperCase(); + let lotw_qsl_rcvd = findAdiField( + activeAdifArray[x], + "LOTW_QSL_RCVD" + ).toUpperCase(); + let eqsl_qsl_rcvd = findAdiField( + activeAdifArray[x], + "EQSL_QSL_RCVD" + ).toUpperCase(); + + if ( + qrzConfirmed == "C" || + lotw_qsl_rcvd == "Y" || + lotw_qsl_rcvd == "V" || + lotwConfirmed1 == "Y" || + eqsl_qsl_rcvd == "Y" || + eqsl_qsl_rcvd == "V" || + eQSLfile == true + ) + { confirmed = true; } + + let dateTime = new Date( + Date.UTC( + dateVal.substr(0, 4), + parseInt(dateVal.substr(4, 2)) - 1, + dateVal.substr(6, 2), + timeVal.substr(0, 2), + timeVal.substr(2, 2), + timeVal.substr(4, 2) + ) + ); + + let finalTime = parseInt(dateTime.getTime() / 1000); + + if ( + g_appSettings.workingDateEnable && + finalTime < g_appSettings.workingDate + ) + { continue; } + + finalGrid = finalGrid.substr(0, 6); + if (!validateGridFromString(finalGrid)) finalGrid = ""; + if (finalGrid == "" && vuccGrids != "") + { + finalVucc = vuccGrids.split(","); + finalGrid = finalVucc[0]; + finalVucc.shift(); + } + let isDigital = false; + let isPhone = false; + if (finalMode in g_modes) + { + isDigital = g_modes[finalMode]; + } + if (finalMode in g_modes_phone) + { + isPhone = g_modes_phone[finalMode]; + } + if (finalDXcall != "") + { + addDeDx( + finalGrid, + finalDXcall, + false, + false, + false, + finalDEcall, + finalRSTsent, + finalTime, + finalMsg, + finalMode, + finalBand, + confirmed, + false, + finalRSTrecv, + finalDxcc, + finalState, + finalCont, + finalCnty, + finalCqZone, + finalItuZone, + finalVucc, + finalPropMode, + isDigital, + isPhone, + finalIOTA, + finalSatName + ); + } + } + else + { + let finalMyGrid = findAdiField( + activeAdifArray[x], + "MY_GRIDSQUARE" + ).toUpperCase(); + let finalGrid = findAdiField( + activeAdifArray[x], + "GRIDSQUARE" + ).toUpperCase(); + let finalDXcall = findAdiField(activeAdifArray[x], "CALL"); + let finalDEcall = findAdiField(activeAdifArray[x], "OPERATOR"); + let finalRSTsent = findAdiField(activeAdifArray[x], "APP_PSKREP_SNR"); + let dateVal = findAdiField(activeAdifArray[x], "QSO_DATE"); + let timeVal = findAdiField(activeAdifArray[x], "TIME_ON"); + let finalMode = findAdiField(activeAdifArray[x], "MODE"); + let finalBand = Number( + findAdiField(activeAdifArray[x], "FREQ") + ).formatBand(); + let finalMsg = "-"; + let finalDxcc = Number(findAdiField(activeAdifArray[x], "DXCC")); + if (finalDxcc == 0) + { + if (finalDXcall == myDEcall) finalDxcc = callsignToDxcc(finalDEcall); + else finalDxcc = callsignToDxcc(finalDXcall); + } + + finalGrid = finalGrid.substr(0, 6); + + let dateTime = new Date( + Date.UTC( + dateVal.substr(0, 4), + parseInt(dateVal.substr(4, 2)) - 1, + dateVal.substr(6, 2), + timeVal.substr(0, 2), + timeVal.substr(2, 2), + timeVal.substr(4, 2) + ) + ); + let finalTime = parseInt(dateTime.getTime() / 1000); + if ( + finalGrid != "" && + finalDXcall != "" && + validateGridFromString(finalGrid) + ) + { + if (finalDXcall == myDEcall) + { + addDeDx( + finalMyGrid, + finalDEcall, + false, + false, + false, + finalDXcall, + null, + finalTime, + finalMsg, + finalMode, + finalBand, + false, + true, + finalRSTsent, + finalDxcc, + null, + null, + null, + null, + null + ); + } + else if (finalDEcall == myDEcall) + { + addDeDx( + finalGrid, + finalDXcall, + false, + false, + false, + "-", + finalRSTsent, + finalTime, + finalMsg, + finalMode, + finalBand, + false, + true, + null, + finalDxcc, + null, + null, + null, + null, + null + ); + } + else + { + addDeDx( + finalGrid, + finalDXcall, + false, + false, + false, + finalDEcall, + finalRSTsent, + finalTime, + finalMsg, + finalMode, + finalBand, + false, + true, + null, + finalDxcc, + null, + null, + null, + null, + null + ); + } + } + } + } + } + + redrawGrids(); + updateCountStats(); + updateLogbook(); + + if (g_fromDirectCallNoFileDialog == false) + { + fileSelector.setAttribute("type", ""); + fileSelector.setAttribute("type", "file"); + fileSelector.setAttribute("accept", ".adi,"); + fileSelector.value = null; + } + g_fromDirectCallNoFileDialog = false; + + updateRosterWorked(); + goProcessRoster(); +} + +function clubLogCallback(buffer, flag, cookie) +{ + var rawAdiBuffer = String(buffer); + if (rawAdiBuffer.indexOf("Invalid login") > -1) + { + if (flag) clubTestResult.innerHTML = "Invalid"; + } + else if (buffer == null) + { + if (flag) clubTestResult.innerHTML = "Unknown Error"; + } + else + { + if (flag) clubTestResult.innerHTML = "Passed"; + else + { + g_fromDirectCallNoFileDialog = true; + + rawAdiBuffer = cleanAndPrepADIF("clublog.adif", rawAdiBuffer); + + tryToWriteAdifToDocFolder("clublog.adif", rawAdiBuffer); + + onAdiLoadComplete(rawAdiBuffer, true, "clublog.adif", true); + } + } +} + +var g_isGettingClub = false; +function grabClubLog(test) +{ + if (g_isGettingClub == false) + { + if (test) clubTestResult.innerHTML = "Testing"; + + var postData = { + email: clubEmail.value, + password: clubPassword.value, + call: clubCall.value + }; + getAPostBuffer( + "https://clublog.org/getadif.php", + clubLogCallback, + test, + "https", + 443, + postData, + ClubLogImg, + "g_isGettingClub" + ); + } +} + +function tryToWriteAdifToDocFolder(filename, buffer, append = false) +{ + var finalFile = g_appData + g_dirSeperator + filename; + try + { + if (append == false) + { + fs.writeFileSync(finalFile, buffer); + return buffer; + } + else + { + fs.appendFileSync(finalFile, buffer); + return fs.readFileSync(finalFile); + } + } + catch (e) + { + return false; + } +} + +function cleanAndPrepADIF(name, adiBuffer, reverse = false, noheader = false) +{ + var rawAdiBuffer = adiBuffer; + var regex = new RegExp("", "i"); + rawAdiBuffer = rawAdiBuffer.replace(regex, ""); + regex = new RegExp("", "i"); + var adiArray = rawAdiBuffer.split(regex); + var activeAdifArray = Array(); + var activeAdifLogMode = true; + var finalBuffer = ""; + + if (noheader == false) finalBuffer = name + "\r\n"; + + if (adiArray.length > 1) + { + regex = new RegExp("", "i"); + activeAdifArray = adiArray[1].split(regex); + + if (reverse == false) + { + for (var x = 0; x < activeAdifArray.length - 1; x++) + { + var row = activeAdifArray[x].replace(/[\n\r]/g, ""); + if (row.length > 0) finalBuffer += row + "\r\n"; + } + } + else + { + for (var x = activeAdifArray.length - 1; x > -1; x--) + { + var row = activeAdifArray[x].replace(/[\n\r]/g, ""); + if (row.length > 0) finalBuffer += row + "\r\n"; + } + } + } + + return finalBuffer; +} + +function addZero(i) +{ + if (i < 10) + { + i = "0" + i; + } + return i; +} + +function getUTCString(d) +{ + var Y = d.getUTCFullYear(); + var M = addZero(d.getUTCMonth() + 1); + var D = addZero(d.getUTCDate()); + var h = addZero(d.getUTCHours()); + var m = addZero(d.getUTCMinutes()); + var s = addZero(d.getUTCSeconds()); + return Y + "-" + M + "-" + D + " " + h + ":" + m + ":" + s; +} + +function lotwCallback(buffer, flag) +{ + var rawAdiBuffer = String(buffer); + if (rawAdiBuffer.indexOf("password incorrect") > -1) + { + if (flag) lotwTestResult.innerHTML = "Invalid"; + } + else + { + if (flag) lotwTestResult.innerHTML = "Passed"; + else + { + var shouldAppend = false; + g_fromDirectCallNoFileDialog = true; + + rawAdiBuffer = cleanAndPrepADIF( + "lotw.adif", + rawAdiBuffer, + true, + shouldAppend + ); + + rawAdiBuffer = tryToWriteAdifToDocFolder( + "lotw.adif", + rawAdiBuffer, + shouldAppend + ); + + onAdiLoadComplete(rawAdiBuffer, true, "lotw.adif", true); + } + } +} + +function shouldWeAppendInsteadOfCreate(filename) +{ + var finalFile = g_appData + g_dirSeperator + filename; + try + { + if (fs.existsSync(finalFile)) return true; + else return false; + } + catch (e) + { + return false; + } +} + +function tryToDeleteLog(filename) +{ + var finalFile = g_appData + g_dirSeperator + filename; + try + { + if (fs.existsSync(finalFile)) + { + fs.unlinkSync(finalFile); + } + } + catch (e) {} +} + +var g_lotwCount = 0; + +var g_isGettingLOTW = false; + +function grabLOtWLog(test) +{ + if (g_isGettingLOTW == false) + { + var lastQSLDateString = + "&qso_qsorxsince=1945-01-01&qso_qslsince=1945-01-01"; + if (test == true) + { + lotwTestResult.innerHTML = "Testing"; + lastQSLDateString = "&qso_qsosince=2100-01-01"; + } + + getABuffer( + "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + + lotwLogin.value + + "&password=" + + encodeURIComponent(lotwPassword.value) + + "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + + lastQSLDateString, + lotwCallback, + test, + "https", + 443, + lotwLogImg, + "g_isGettingLOTW", + 120000 + ); + } +} + +function qrzCallback(buffer, flag) +{ + if (buffer.indexOf("invalid api key") > -1) + { + if (flag) qrzTestResult.innerHTML = "Invalid"; + } + else + { + if (flag) + { + qrzTestResult.innerHTML = "Passed"; + } + else + { + g_fromDirectCallNoFileDialog = true; + var htmlString = String(buffer).replace(/</g, "<"); + htmlString = htmlString.replace(/>/g, ">"); + htmlString = htmlString.replace("ADIF=", "QRZ\r\n"); + + htmlString = cleanAndPrepADIF("qrz.adif", htmlString); + + tryToWriteAdifToDocFolder("qrz.adif", htmlString); + + onAdiLoadComplete(htmlString, true, "qrz.adif", true); + } + } +} + +var g_isGettingQRZCom = false; +function grabQrzComLog(test) +{ + if (g_isGettingQRZCom == false) + { + var action = "FETCH"; + if (test) + { + qrzTestResult.innerHTML = "Testing"; + action = "STATUS"; + } + + getABuffer( + "https://logbook.qrz.com/api?KEY=" + + qrzApiKey.value + + "&ACTION=" + + action, + qrzCallback, + test, + "https", + 443, + qrzLogImg, + "g_isGettingQRZCom", + null + ); + } +} + +function ValidateQrzApi(inputText) +{ + inputText.value = inputText.value.toUpperCase(); + if (inputText.value.length == 19) + { + var passed = false; + var dashcount = 0; + for (var i = 0; i < inputText.value.length; i++) + { + if (inputText.value[i] == "-") dashcount++; + } + if (dashcount == 3) + { + passed = true; + } + if (passed) + { + inputText.style.color = "#FF0"; + inputText.style.backgroundColor = "green"; + + return true; + } + else + { + inputText.style.color = "white"; + inputText.style.backgroundColor = "red"; + return false; + } + } + else + { + inputText.style.color = "white"; + inputText.style.backgroundColor = "red"; + + return false; + } +} + +function ValidateText(inputText) +{ + if (inputText.value.length > 0) + { + inputText.style.color = "#FF0"; + inputText.style.backgroundColor = "green"; + return true; + } + else + { + inputText.style.color = "white"; + inputText.style.backgroundColor = "red"; + return false; + } +} + +function pskCallback(buffer, flag) +{ + g_fromDirectCallNoFileDialog = true; + var rawAdiBuffer = String(buffer); + + onAdiLoadComplete(rawAdiBuffer, false); +} + +var g_isGettingPsk = false; + +function grabPsk24() +{ + if (g_isGettingPsk == true) return; + + if (myDEcall.length > 0 && myDEcall != "NOCALL") + { + var days = 1; + if (pskImg.src == 1) days = 7; + getABuffer( + "https://pskreporter.info/cgi-bin/pskdata.pl?adif=1&days=" + + days + + "&receiverCallsign=" + + myDEcall.toLowerCase(), + pskCallback, + null, + "https", + 443, + pskImg, + "g_isGettingPsk" + ); + } +} + +function adifMenuCheckBoxChanged(what) +{ + g_adifLogSettings.menu[what.id] = what.checked; + var menuItem = what.id + "Div"; + if (what.checked == true) + { + document.getElementById(menuItem).style.display = "inline-block"; + } + else + { + document.getElementById(menuItem).style.display = "none"; + } + + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); + + if (what == buttonAdifCheckBox) setAdifStartup(loadAdifCheckBox); +} + +function adifStartupCheckBoxChanged(what) +{ + g_adifLogSettings.startup[what.id] = what.checked; + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); + + if (what == loadAdifCheckBox) setAdifStartup(loadAdifCheckBox); +} + +function adifLogQsoCheckBoxChanged(what) +{ + g_adifLogSettings.qsolog[what.id] = what.checked; + if (what.id == "logLOTWqsoCheckBox") + { + if (what.checked == true) + { + lotwUpload.style.display = "inline-block"; + trustedTestButton.style.display = "inline-block"; + } + else + { + lotwUpload.style.display = "none"; + trustedTestButton.style.display = "none"; + } + } + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); +} + +function adifNicknameCheckBoxChanged(what) +{ + g_adifLogSettings.nickname[what.id] = what.checked; + if (what.id == "nicknameeQSLCheckBox") + { + if (what.checked == true) + { + eQSLNickname.style.display = "inline-block"; + } + else + { + eQSLNickname.style.display = "none"; + } + } + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); +} + +function adifTextValueChange(what) +{ + what.value = what.value.trim(); + g_adifLogSettings.text[what.id] = what.value; + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); +} + +var fileSelector = document.createElement("input"); +fileSelector.setAttribute("type", "file"); +fileSelector.setAttribute("accept", ".adi,.adif"); +fileSelector.onchange = function () +{ + if (this.files && this.files[0]) + { + let path = this.value.replace(this.files[0].name, ""); + fileSelector.setAttribute("nwworkingdir", path); + + var reader = new FileReader(); + reader.onload = function (e) + { + if (e.target.error == null) + { + onAdiLoadComplete(e.target.result, false); + } + }; + + reader.readAsText(this.files[0]); + } +}; + +function adifLoadDialog() +{ + var exists = fileSelector.getAttribute("nwworkingdir"); + + fileSelector.setAttribute("nwworkingdir", g_appData); + + fileSelector.click(); + + return false; +} + +var startupFileSelector = document.createElement("input"); +startupFileSelector.setAttribute("type", "file"); +startupFileSelector.setAttribute("accept", ".adi,.adif"); +startupFileSelector.onchange = function () +{ + if (this.files && this.files[0]) + { + for (var i in g_startupLogs) + { + if (this.value == g_startupLogs[i].file) return; + } + var newObject = Object(); + newObject.name = this.files[0].name; + newObject.file = this.value; + g_startupLogs.push(newObject); + localStorage.startupLogs = JSON.stringify(g_startupLogs); + + let path = this.value.replace(this.files[0].name, ""); + startupFileSelector.setAttribute("nwworkingdir", path); + + setAdifStartup(loadAdifCheckBox); + } +}; + +function start_and_end(str) +{ + if (str.length > 31) + { + return ( + str.substr(0, 16) + " ... " + str.substr(str.length - 15, str.length) + ); + } + return str; +} + +function setFileSelectors() +{ + selectStartupLink = document.getElementById("selectAdifButton"); + selectStartupLink.onclick = function () + { + var exists = startupFileSelector.getAttribute("nwworkingdir"); + if (exists == null) + { + if (g_workingIniPath.length > 1) + { startupFileSelector.setAttribute("nwworkingdir", g_appData); } + } + + startupFileSelector.click(); + return false; + }; + + selectTqsl = document.getElementById("selectTQSLButton"); + selectTqsl.onclick = function () + { + tqslFileSelector.click(); + return false; + }; + lotwUpload.prepend(selectTqsl); +} + +var tqslFileSelector = document.createElement("input"); +tqslFileSelector.setAttribute("type", "file"); +tqslFileSelector.setAttribute("accept", "*"); +tqslFileSelector.onchange = function () +{ + if (this.files && this.files[0]) + { + g_trustedQslSettings.binaryFile = this.files[0].path; + var fs = require("fs"); + + if ( + fs.existsSync(g_trustedQslSettings.binaryFile) && + (g_trustedQslSettings.binaryFile.endsWith("tqsl.exe") || + g_trustedQslSettings.binaryFile.endsWith("tqsl")) + ) + { + g_trustedQslSettings.binaryFileValid = true; + } + else g_trustedQslSettings.binaryFileValid = false; + + if (g_trustedQslSettings.binaryFileValid == true) + { + tqslFileDiv.style.backgroundColor = "blue"; + } + else + { + tqslFileDiv.style.backgroundColor = "red"; + } + + tqslFileDiv.innerHTML = "" + start_and_end(this.files[0].path) + ""; + localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings); + } +}; + +function loadGtQSOLogFile() +{ + var fs = require("fs"); + + if (fs.existsSync(g_qsoLogFile)) + { + var rawAdiBuffer = fs.readFileSync(g_qsoLogFile); + + g_fromDirectCallNoFileDialog = true; + + onAdiLoadComplete(rawAdiBuffer, false); + } +} + +function loadWsjtLogFile() +{ + var fs = require("fs"); + if (fs.existsSync(g_workingIniPath + "wsjtx_log.adi")) + { + var rawAdiBuffer = fs.readFileSync(g_workingIniPath + "wsjtx_log.adi"); + g_fromDirectCallNoFileDialog = true; + onAdiLoadComplete(rawAdiBuffer, false); + } +} + +function findTrustedQSLPaths() +{ + var process = require("process"); + var base = null; + + if (g_trustedQslSettings.stationFileValid == true) + { + // double check the presence of the station_data; + if (!fs.existsSync(g_trustedQslSettings.stationFile)) + { + g_trustedQslSettings.stationFileValid = false; + } + } + if (g_trustedQslSettings.stationFileValid == false) + { + if (g_platform == "windows") + { + base = process.env.APPDATA + "\\TrustedQSL\\station_data"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.stationFile = base; + g_trustedQslSettings.stationFileValid = true; + } + else + { + base = process.env.LOCALAPPDATA + "\\TrustedQSL\\station_data"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.stationFile = base; + g_trustedQslSettings.stationFileValid = true; + } + } + } + else + { + base = process.env.HOME + "/.tqsl/station_data"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.stationFile = base; + g_trustedQslSettings.stationFileValid = true; + } + } + } + if (g_trustedQslSettings.stationFileValid == true) + { + var validate = false; + var option = document.createElement("option"); + option.value = ""; + option.text = "Select a Station"; + lotwStation.appendChild(option); + + var buffer = fs.readFileSync(g_trustedQslSettings.stationFile, "UTF-8"); + parser = new DOMParser(); + xmlDoc = parser.parseFromString(buffer, "text/xml"); + var x = xmlDoc.getElementsByTagName("StationData"); + for (var i = 0; i < x.length; i++) + { + option = document.createElement("option"); + option.value = x[i].getAttribute("name"); + option.text = x[i].getAttribute("name"); + if (option.value == g_adifLogSettings.text.lotwStation) + { + option.selected = true; + validate = true; + } + lotwStation.appendChild(option); + } + if (validate) + { + ValidateText(lotwStation); + } + } + + if (g_trustedQslSettings.binaryFileValid == true) + { + // double check the presence of the TrustedQSL binary; + if (!fs.existsSync(g_trustedQslSettings.binaryFile)) + { + g_trustedQslSettings.binaryFileValid = false; + } + } + if (g_trustedQslSettings.binaryFileValid == false || g_platform == "mac") + { + if (g_platform == "windows") + { + base = process.env["ProgramFiles(x86)"] + "\\TrustedQSL\\tqsl.exe"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + } + else if (g_platform == "mac") + { + base = "/Applications/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = + process.env.HOME + + "/Applications/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = + process.env.HOME + "/Applications/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = "/Applications/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = + process.env.HOME + + "/Desktop/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = + process.env.HOME + + "/Applications/Ham Radio/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + } + } + } + } + } + } + else if (g_platform == "linux") + { + base = "/usr/bin/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = "/usr/local/bin/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + } + } + } + localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings); +} + +function startupAdifLoadFunction() +{ + var fs = require("fs"); + + for (var i in g_startupLogs) + { + try + { + if (fs.existsSync(g_startupLogs[i].file)) + { + var rawAdiBuffer = fs.readFileSync(g_startupLogs[i].file); + g_fromDirectCallNoFileDialog = true; + onAdiLoadComplete(rawAdiBuffer, false); + } + } + catch (e) {} + } +} + +function setAdifStartup(checkbox) +{ + if (g_trustedQslSettings.binaryFile == null) + { g_trustedQslSettings.binaryFile = ""; } + + if ( + g_trustedQslSettings.binaryFile.endsWith("tqsl.exe") || + g_trustedQslSettings.binaryFile.endsWith("tqsl") + ) + { + g_trustedQslSettings.binaryFileValid = true; + } + else g_trustedQslSettings.binaryFileValid = false; + + if (g_trustedQslSettings.binaryFileValid == true) + { + tqslFileDiv.style.backgroundColor = "blue"; + } + else + { + tqslFileDiv.style.backgroundColor = "red"; + } + tqslFileDiv.innerHTML = + "" + start_and_end(g_trustedQslSettings.binaryFile) + ""; + + if (buttonAdifCheckBox.checked || loadAdifCheckBox.checked) + { + var worker = ""; + if (g_startupLogs.length > 0) + { + worker += ""; + for (var i in g_startupLogs) + { + worker += + ""; + } + worker += "
" + + g_startupLogs[i].name + + "
"; + } + else + { + worker = "No file(s) selected"; + } + startupLogFileDiv.innerHTML = worker; + selectFileOnStartupDiv.style.display = "block"; + } + else + { + startupLogFileDiv.innerHTML = "No file(s) selected"; + startupFileSelector.setAttribute("type", ""); + startupFileSelector.setAttribute("type", "file"); + startupFileSelector.setAttribute("accept", ".adi*"); + startupFileSelector.value = null; + selectFileOnStartupDiv.style.display = "none"; + } +} + +function removeStartupLog(i) +{ + if (i in g_startupLogs) + { + g_startupLogs.splice(i, 1); + localStorage.startupLogs = JSON.stringify(g_startupLogs); + setAdifStartup(loadAdifCheckBox); + } +} + +function startupAdifLoadCheck() +{ + logEventMedia.value = g_alertSettings.logEventMedia; + + loadWsjtLogFile(); + + if (loadGTCheckBox.checked == true) loadGtQSOLogFile(); + + if (loadAdifCheckBox.checked == true && g_startupLogs.length > 0) + { startupAdifLoadFunction(); } + + if (g_mapSettings.offlineMode == false) + { + if (g_appSettings.gtFlagImgSrc == 1) showGtFlags(); + + //if (loadLOTWCheckBox.checked == true) grabLOtWLog(false); + + if (loadQRZCheckBox.checked == true) grabQrzComLog(false); + + if (loadClubCheckBox.checked == true) grabClubLog(false); + + if (loadPsk24CheckBox.checked == true) grabPsk24(); + } +} + +function getABuffer( + file_url, + callback, + flag, + mode, + port, + imgToGray, + stringOfFlag, + timeoutX +) +{ + let url = require("url"); + let http = require(mode); + let fileBuffer = null; + let options = null; + + options = { + host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api + port: port, + path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api + method: "get" + }; + + if (typeof stringOfFlag != "undefined") window[stringOfFlag] = true; + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = + "linear-gradient(grey 0%, black 0% 100% )"; + imgToGray.style.webkitFilter = "invert(100%) grayscale(1)"; + } + + let req = http.request(options, function (res) + { + let fsize = res.headers["content-length"]; + let cookies = null; + if (typeof res.headers["set-cookie"] != "undefined") + { cookies = res.headers["set-cookie"]; } + + res + .on("data", function (data) + { + if (fileBuffer == null) fileBuffer = data; + else fileBuffer += data; + + if (typeof imgToGray != "undefined") + { + let percent = 0; + if (fsize > 0) percent = parseInt((fileBuffer.length / fsize) * 100); + else percent = parseInt(((fileBuffer.length / 100000) * 100) % 100); + imgToGray.parentNode.style.background = + "linear-gradient(grey " + + percent + + "%, black " + + Number(percent + 10) + + "% 100% )"; + } + }) + .on("end", function () + { + if (typeof callback === "function") + { + // Call it, since we have confirmed it is callable + callback(fileBuffer, flag, cookies); + } + if (typeof stringOfFlag != "undefined") + { + window[stringOfFlag] = false; + } + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }) + .on("error", function () + { + if (typeof stringOfFlag != "undefined") + { + window[stringOfFlag] = false; + } + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }); + }); + + req.on("socket", function (socket) + { + socket.on("timeout", function () + { + req.abort(); + }); + }); + + req.on("error", function () + { + if (typeof stringOfFlag != "undefined") + { + window[stringOfFlag] = false; + } + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }); + + req.end(); +} + +function getAPostBuffer( + file_url, + callback, + flag, + mode, + port, + theData, + imgToGray, + stringOfFlag +) +{ + var querystring = require("querystring"); + var postData = querystring.stringify(theData); + var url = require("url"); + var http = require(mode); + var fileBuffer = null; + + var options = { + host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api + port: port, + path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api + method: "post", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "Content-Length": postData.length + } + }; + + window[stringOfFlag] = true; + + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = + "linear-gradient(grey 0%, black 0% 100% )"; + imgToGray.style.webkitFilter = "invert(100%) grayscale(1)"; + } + + var req = http.request(options, function (res) + { + var fsize = res.headers["content-length"]; + var cookies = null; + if (typeof res.headers["set-cookie"] != "undefined") + { cookies = res.headers["set-cookie"]; } + + res + .on("data", function (data) + { + if (fileBuffer == null) fileBuffer = data; + else fileBuffer += data; + + if (typeof imgToGray != "undefined") + { + var percent = 0; + if (fsize > 0) percent = parseInt((fileBuffer.length / fsize) * 100); + else percent = parseInt(((fileBuffer.length / 100000) * 100) % 100); + + imgToGray.parentNode.style.background = + "linear-gradient(grey " + + percent + + "%, black " + + Number(percent + 10) + + "% 100% )"; + } + }) + .on("end", function () + { + if (typeof callback === "function") + { + // Call it, since we have confirmed it is callable + callback(fileBuffer, flag, cookies); + window[stringOfFlag] = false; + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + } + }) + .on("error", function () + { + window[stringOfFlag] = false; + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }); + }); + + req.on("socket", function (socket) + { + socket.on("timeout", function () + { + req.abort(); + }); + }); + + req.on("error", function (err) // eslint-disable-line node/handle-callback-err + { + window[stringOfFlag] = false; + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }); + + req.write(postData); + req.end(); +} + +function sendUdpMessage(msg, length, port, address) +{ + var dgram = require("dgram"); + var socket = dgram.createSocket({ type: "udp4", reuseAddr: true }); + socket.send(msg, 0, length, port, address, (err) => // eslint-disable-line node/handle-callback-err + { + socket.close(); + }); +} + +function sendTcpMessage(msg, length, port, address) +{ + var net = require("net"); + var client = new net.Socket(); + client.setTimeout(30000); + client.connect(port, address, function () + { + client.write(msg); + }); + + client.on("close", function () {}); +} + +function valueToAdiField(field, value) +{ + var adi = "<" + field + ":"; + adi += String(value).length + ">"; + adi += String(value) + " "; + return adi; +} + +function pad(value) +{ + if (value < 10) + { + return "0" + value; + } + else + { + return value; + } +} + +function HMSfromMilli(milli) +{ + var seconds = parseInt(milli / 1000); + var days = Math.floor(seconds / (3600 * 24)); + seconds -= days * 3600 * 24; + var hrs = Math.floor(seconds / 3600); + seconds -= hrs * 3600; + var mnts = Math.floor(seconds / 60); + seconds -= mnts * 60; + + val = String(pad(hrs)) + String(pad(mnts)) + String(pad(seconds)); + return String(val); +} + +function colonHMSfromMilli(milli) +{ + var seconds = parseInt(milli / 1000); + var days = Math.floor(seconds / (3600 * 24)); + seconds -= days * 3600 * 24; + var hrs = Math.floor(seconds / 3600); + seconds -= hrs * 3600; + var mnts = Math.floor(seconds / 60); + seconds -= mnts * 60; + + val = String(pad(hrs)) + ":" + String(pad(mnts)) + ":" + String(pad(seconds)); + return String(val); +} + +function colonHMSfromSeconds(secondsIn) +{ + var seconds = secondsIn; + var days = Math.floor(seconds / (3600 * 24)); + seconds -= days * 3600 * 24; + var hrs = Math.floor(seconds / 3600); + seconds -= hrs * 3600; + var mnts = Math.floor(seconds / 60); + seconds -= mnts * 60; + + val = String(pad(hrs)) + ":" + String(pad(mnts)) + ":" + String(pad(seconds)); + return String(val); +} + +function convertToDate(julian) +{ + var DAY = 86400000; + var HALF_DAY = DAY / 2; + var UNIX_EPOCH_JULIAN_DATE = 2440587.5; + var UNIX_EPOCH_JULIAN_DAY = 2440587; + return new Date((Number(julian) - UNIX_EPOCH_JULIAN_DATE) * DAY); +} + +var CLk = "25bc718451a71954cb6d0d1b50541dd45d4ba148"; + +var lastReportHash = null; + +var g_oldStyleLogMessage = null; + +function oldSendToLogger() +{ + var newMessage = Object.assign({}, g_oldStyleLogMessage); + + var band = Number(newMessage.Frequency / 1000000).formatBand(); + + if ( + newMessage.DXGrid.length == 0 && + newMessage.DXCall + band + newMessage.MO in g_liveCallsigns + ) + { + newMessage.DXGrid = g_liveCallsigns[ + newMessage.DXCall + band + newMessage.MO + ].grid.substr(0, 4); + } + + var report = ""; + + report += valueToAdiField( + "BAND", + Number(newMessage.Frequency / 1000000).formatBand() + ); + report += valueToAdiField("CALL", newMessage.DXCall.toUpperCase()); + report += valueToAdiField( + "FREQ", + Number(newMessage.Frequency / 1000000).toFixed(6) + ); + report += valueToAdiField("MODE", newMessage.MO.toUpperCase()); + var date = convertToDate(parseInt(newMessage.DateOn)); + var dataString = + date.getUTCFullYear() + + ("0" + (date.getUTCMonth() + 1)).slice(-2) + + ("0" + date.getUTCDate()).slice(-2); + report += valueToAdiField("QSO_DATE", dataString); + report += valueToAdiField("TIME_ON", HMSfromMilli(newMessage.TimeOn)); + + date = convertToDate(parseInt(newMessage.DateOff)); + dataString = + date.getUTCFullYear() + + ("0" + (date.getUTCMonth() + 1)).slice(-2) + + ("0" + date.getUTCDate()).slice(-2); + report += valueToAdiField("QSO_DATE_OFF", dataString); + report += valueToAdiField("TIME_OFF", HMSfromMilli(newMessage.TimeOff)); + + report += valueToAdiField("RST_RCVD", newMessage.ReportRecieved); + report += valueToAdiField("RST_SENT", newMessage.ReportSend); + report += valueToAdiField("TX_PWR", parseInt(newMessage.TXPower)); + report += valueToAdiField("GRIDSQUARE", newMessage.DXGrid); + + if (newMessage.Comments.length > 0) + { report += valueToAdiField("COMMENT", newMessage.Comments); } + + if (newMessage.Name.length > 0) + { report += valueToAdiField("NAME", newMessage.Name); } + + if (newMessage.Operatorcall.length > 0) + { + report += valueToAdiField("OPERATOR", newMessage.Operatorcall); + } + + if (newMessage.Mycall.length > 0) + { + report += valueToAdiField("STATION_CALLSIGN", newMessage.Mycall); + } + else if (myDEcall != "NOCALL" && myDEcall.length > 0) + { report += valueToAdiField("STATION_CALLSIGN", myDEcall); } + + if (newMessage.Mygrid.length > 0) + { + report += valueToAdiField("MY_GRIDSQUARE", newMessage.Mygrid); + } + else if (myDEGrid.length > 1) + { report += valueToAdiField("MY_GRIDSQUARE", myDEGrid); } + + report += ""; + + sendToLogger(report); +} + +var g_adifLookupMap = { + name: "NAME", + iota: "IOTA", + sota: "SOTA_REF", + continent: "CONT", + cqzone: "CQZ", + ituzone: "ITUZ", + email: "EMAIL", + county: "CNTY" +}; + +function sendToLogger(ADIF) +{ + let regex = new RegExp("", "i"); + let record = parseADIFRecord(ADIF.split(regex)[1]); + let localMode = record.MODE; + + if (localMode == "MFSK" && "SUBMODE" in record) + { + localMode = record.SUBMODE; + } + + if ( + (!("GRIDSQUARE" in record) || record.GRIDSQUARE.length == 0) && + record.CALL + record.BAND + localMode in g_liveCallsigns + ) + { + record.GRIDSQUARE = g_liveCallsigns[ + record.CALL + record.BAND + localMode + ].grid.substr(0, 4); + } + + if ("TX_PWR" in record) + { + record.TX_PWR = String(parseInt(record.TX_PWR)); + } + + if ( + (!("STATION_CALLSIGN" in record) || + record.STATION_CALLSIGN.length == 0) && + myDEcall != "NOCALL" && + myDEcall.length > 0 + ) + { + record.STATION_CALLSIGN = myDEcall; + } + + if ( + (!("MY_GRIDSQUARE" in record) || record.MY_GRIDSQUARE.length == 0) && + myDEGrid.length > 1 + ) + { + record.MY_GRIDSQUARE = myDEGrid; + } + + if (!("DXCC" in record)) + { + let dxcc = callsignToDxcc(record.CALL); + if (dxcc == -1) dxcc = 0; + record.DXCC = String(dxcc); + } + + // Tag: This is going to bite us in the butt later, but leaving it alone. + if (!("COUNTRY" in record) && Number(record.DXCC) > 0) + { + record.COUNTRY = g_dxccToADIFName[Number(record.DXCC)]; + } + + if (g_appSettings.lookupMerge == true) + { + let request = g_Idb + .transaction(["lookups"], "readwrite") + .objectStore("lookups") + .get(record.CALL); + + request.onsuccess = function (event) + { + if (request.result) + { + let lookup = request.result; + for (let key in lookup) + { + if (key in g_adifLookupMap) + { + record[g_adifLookupMap[key]] = lookup[key]; + } + } + if ("GRIDSQUARE" in record && "grid" in lookup) + { + if ( + record.GRIDSQUARE.substr(0, 4) == lookup.grid.substr(0, 4) + ) + { + record.GRIDSQUARE = lookup.grid; + } + } + if ( + g_appSettings.lookupMissingGrid && + "grid" in lookup && + (!("GRIDSQUARE" in record) || record.GRIDSQUARE.length == 0) + ) + { + record.GRIDSQUARE = lookup.grid; + } + } + finishSendingReport(record, localMode); + }; + + request.onerror = function (event) + { + finishSendingReport(record, localMode); + }; + } + else + { + finishSendingReport(record, localMode); + } +} + +function finishSendingReport(record, localMode) +{ + let report = ""; + + let reportHash = record.CALL + record.MODE + localMode; + + for (let key in record) + { + report += "<" + key + ":" + record[key].length + ">" + record[key] + " "; + } + report += ""; + + if (reportHash != lastReportHash) + { + lastReportHash = reportHash; + + if ( + g_N1MMSettings.enable == true && + g_N1MMSettings.port > 1024 && + g_N1MMSettings.ip.length > 4 + ) + { + sendUdpMessage( + report, + report.length, + parseInt(g_N1MMSettings.port), + g_N1MMSettings.ip + ); + addLastTraffic("Logged to N1MM"); + } + + if ( + g_log4OMSettings.enable == true && + g_log4OMSettings.port > 1024 && + g_log4OMSettings.ip.length > 4 + ) + { + sendUdpMessage( + "ADD " + report, + report.length + 4, + parseInt(g_log4OMSettings.port), + g_log4OMSettings.ip + ); + addLastTraffic("Logged to Log4OM"); + } + + try + { + onAdiLoadComplete("GT" + report); + } + catch (e) + { + addLastTraffic("Exception Internal Log"); + } + try + { + // Log worthy + if (logGTqsoCheckBox.checked == true) + { + var fs = require("fs"); + fs.appendFileSync(g_qsoLogFile, report + "\r\n"); + addLastTraffic( + "Logged to GridTracker backup" + ); + } + } + catch (e) + { + addLastTraffic( + "Exception GridTracker backup" + ); + } + + try + { + sendQrzLogEntry(report); + } + catch (e) + { + addLastTraffic("Exception QRZ Log"); + } + + try + { + sendClubLogEntry(report); + } + catch (e) + { + addLastTraffic("Exception ClubLog Log"); + } + + try + { + sendHrdLogEntry(report); + } + catch (e) + { + addLastTraffic("Exception HrdLog.net Log"); + } + + try + { + sendCloudlogEntry(report); + } + catch (e) + { + addLastTraffic("Exception Cloudlog Log"); + } + + if ( + g_acLogSettings.enable == true && + g_acLogSettings.port > 0 && + g_acLogSettings.ip.length > 4 + ) + { + try + { + sendACLogMessage(record, g_acLogSettings.port, g_acLogSettings.ip); + addLastTraffic("Logged to N3FJP"); + } + catch (e) + { + addLastTraffic("Exception N3FJP Log"); + } + } + + if ( + g_dxkLogSettings.enable == true && + g_dxkLogSettings.port > 0 && + g_dxkLogSettings.ip.length > 4 + ) + { + try + { + sendDXKeeperLogMessage( + report, + g_dxkLogSettings.port, + g_dxkLogSettings.ip + ); + addLastTraffic("Logged to DXKeeper"); + } + catch (e) + { + addLastTraffic("Exception DXKeeper Log"); + } + } + + if ( + g_HRDLogbookLogSettings.enable == true && + g_HRDLogbookLogSettings.port > 0 && + g_HRDLogbookLogSettings.ip.length > 4 + ) + { + try + { + sendHRDLogbookEntry( + record, + g_HRDLogbookLogSettings.port, + g_HRDLogbookLogSettings.ip + ); + addLastTraffic( + "Logged to HRD Logbook" + ); + } + catch (e) + { + addLastTraffic("Exception HRD Log"); + } + } + + try + { + sendLotwLogEntry(report); + } + catch (e) + { + addLastTraffic("Exception LoTW Log"); + } + + if ( + logeQSLQSOCheckBox.checked == true && + nicknameeQSLCheckBox.checked == true && + eQSLNickname.value.trim().length > 0 + ) + { + record.APP_EQSL_QTH_NICKNAME = eQSLNickname.value.trim(); + report = ""; + for (var key in record) + { + report += + "<" + key + ":" + record[key].length + ">" + record[key] + " "; + } + report += ""; + } + + try + { + sendeQSLEntry(report); + } + catch (e) + { + addLastTraffic("Exception LoTW Log"); + } + + try + { + alertLogMessage(); + } + catch (e) + { + addLastTraffic("Exception Alert Log"); + } + + if (lookupCloseLog.checked == true) + { + try + { + openLookupWindow(false); + } + catch (e) + { + addLastTraffic("Exception Hide Lookup"); + } + } + } + + return report; +} + +function alertLogMessage() +{ + if (logEventMedia.value != "none") + { + playAlertMediaFile(logEventMedia.value); + } +} + +function eqslCallback(buffer, flag) +{ + var result = String(buffer); + if (flag) + { + if (result.indexOf("No such Username/Password found") != -1) + { + eQSLTestResult.innerHTML = "Bad
Password
or
Nickname"; + logeQSLQSOCheckBox.checked = false; + adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); + } + else if (result.indexOf("No such Callsign found") != -1) + { + eQSLTestResult.innerHTML = "Unknown
Callsign"; + logeQSLQSOCheckBox.checked = false; + adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); + } + else if (result.indexOf("Your ADIF log file has been built") > -1 || result.indexOf("You have no log entries") > -1) + { + eQSLTestResult.innerHTML = "Passed"; + } + else if (result.indexOf("specify the desired User by using the QTHNickname") != -1) + { + eQSLTestResult.innerHTML = "QTH Nickname
Needed"; + } + else + { + eQSLTestResult.innerHTML = "Unknown
Error"; + logeQSLQSOCheckBox.checked = false; + adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); + } + } + else + { + if (result.indexOf("Error: No match on eQSL_User/eQSL_Pswd") != -1) + { + addLastTraffic( + "Fail log eQSL.cc (credentials)" + ); + } + if ( + result.indexOf("specify the desired User by using the QTHNickname") != -1 + ) + { + addLastTraffic( + "Fail log eQSL.cc (nickname)" + ); + } + else if (result.indexOf("Result: 0 out of 1 records") != -1) + { + addLastTraffic("Fail log eQSL.cc (dupe)"); + } + else if (result.indexOf("Result: 1 out of 1 records added") != -1) + { + addLastTraffic("Logged to eQSL.cc"); + } + else + { + addLastTraffic("Fail log eQSL.cc (?)"); + } + } +} + +function eQSLTest(test) +{ + if (g_mapSettings.offlineMode == true) return; + + eQSLTestResult.innerHTML = "Testing"; + + var fUrl = + "https://www.eQSL.cc/qslcard/DownloadInBox.cfm?UserName=" + + encodeURIComponent(eQSLUser.value) + + "&Password=" + + encodeURIComponent(eQSLPassword.value) + + "&RcvdSince=2020101"; + + if (nicknameeQSLCheckBox.checked == true) + { fUrl += "&QTHNickname=" + encodeURIComponent(eQSLNickname.value); } + getABuffer(fUrl, eqslCallback, true, "https", 443); +} + +function sendeQSLEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logeQSLQSOCheckBox.checked == true) + { + var pid = "GridTracker"; + var pver = String(gtVersion); + var header = "" + pid + "\r\n"; + header += "" + pver + "\r\n"; + header += "\r\n"; + var eReport = encodeURIComponent(header + report); + var fUrl = + "https://www.eQSL.cc/qslcard/importADIF.cfm?ADIFData=" + + eReport + + "&EQSL_USER=" + + encodeURIComponent(eQSLUser.value) + + "&EQSL_PSWD=" + + encodeURIComponent(eQSLPassword.value); + getABuffer(fUrl, eqslCallback, false, "https", 443); + } +} + +function testTrustedQSL(test) +{ + if (g_mapSettings.offlineMode == true) + { + lotwTestResult.innerHTML = "Currently
offline"; + return; + } + + if ( + logLOTWqsoCheckBox.checked == true && + g_trustedQslSettings.binaryFileValid == true && + g_trustedQslSettings.stationFileValid == true && + lotwStation.value.length > 0 + ) + { + lotwTestResult.innerHTML = "Testing Upload"; + + var child_process = require("child_process"); + var options = Array(); + options.push("-q"); + options.push("-v"); + + child_process.execFile( + g_trustedQslSettings.binaryFile, + options, + (error, stdout, stderr) => + { + if (error) + { + lotwTestResult.innerHTML = "Error encountered"; + } + lotwTestResult.innerHTML = stderr; + } + ); + } + else + { + var worker = ""; + if (g_trustedQslSettings.binaryFileValid == false) + { worker += "Invalid tqsl executable
"; } + if (g_trustedQslSettings.stationFileValid == false) + { worker += "TrustQSL not installed
"; } + if (!ValidateText(lotwTrusted)) worker += "TQSL Password missing
"; + if (!ValidateText(lotwStation)) worker += "Select Station
"; + lotwTestResult.innerHTML = worker; + } +} +var g_trustTempPath = ""; + +function sendLotwLogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if ( + logLOTWqsoCheckBox.checked == true && + g_trustedQslSettings.binaryFileValid == true && + g_trustedQslSettings.stationFileValid == true && + lotwStation.value.length > 0 + ) + { + var header = + "Generated " + userTimeString(null) + " for " + myDEcall + "\r\n\r\n"; + var pid = "GridTracker"; + var pver = String(gtVersion); + header += "" + pid + "\r\n"; + header += "" + pver + "\r\n"; + header += "\r\n"; + var finalLog = header + report + "\r\n"; + + g_trustTempPath = os.tmpdir() + g_dirSeperator + unique(report) + ".adif"; + fs.writeFileSync(g_trustTempPath, finalLog); + + var child_process = require("child_process"); + var options = Array(); + options.push("-a"); + options.push("all"); + options.push("-l"); + options.push(lotwStation.value); + if (lotwTrusted.value.length > 0) + { + options.push("-p"); + options.push(lotwTrusted.value); + } + options.push("-q"); + options.push("-x"); + options.push("-d"); + options.push("-u"); + options.push(g_trustTempPath); + + child_process.execFile( + g_trustedQslSettings.binaryFile, + options, + (error, stdout, stderr) => // eslint-disable-line node/handle-callback-err + { + if (stderr.indexOf("Final Status: Success") < 0) + { + alert(stderr); + addLastTraffic("Fail log to TQSL"); + } + else + { + addLastTraffic("Logged to TQSL"); + } + fs.unlinkSync(g_trustTempPath); + } + ); + } +} + +function n1mmLoggerChanged() +{ + g_N1MMSettings.enable = buttonN1MMCheckBox.checked; + g_N1MMSettings.ip = N1MMIpInput.value; + g_N1MMSettings.port = N1MMPortInput.value; + + localStorage.N1MMSettings = JSON.stringify(g_N1MMSettings); +} + +function log4OMLoggerChanged() +{ + g_log4OMSettings.enable = buttonLog4OMCheckBox.checked; + g_log4OMSettings.ip = log4OMIpInput.value; + g_log4OMSettings.port = log4OMPortInput.value; + + localStorage.log4OMSettings = JSON.stringify(g_log4OMSettings); +} + +function acLogLoggerChanged() +{ + g_acLogSettings.enable = buttonacLogCheckBox.checked; + g_acLogSettings.ip = acLogIpInput.value; + g_acLogSettings.port = acLogPortInput.value; + + localStorage.acLogSettings = JSON.stringify(g_acLogSettings); +} + +function dxkLogLoggerChanged() +{ + g_dxkLogSettings.enable = buttondxkLogCheckBox.checked; + g_dxkLogSettings.ip = dxkLogIpInput.value; + g_dxkLogSettings.port = dxkLogPortInput.value; + + localStorage.dxkLogSettings = JSON.stringify(g_dxkLogSettings); +} + +function hrdLogbookLoggerChanged() +{ + g_HRDLogbookLogSettings.enable = buttonHrdLogbookCheckBox.checked; + g_HRDLogbookLogSettings.ip = hrdLogbookIpInput.value; + g_HRDLogbookLogSettings.port = hrdLogbookPortInput.value; + + localStorage.HRDLogbookLogSettings = JSON.stringify(g_HRDLogbookLogSettings); +} + +function CloudUrlErrorCallback( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + timeoutCallback, + message +) +{ + CloudlogTestResult.innerHTML = message; +} + +function CloudlogSendLogResult(buffer, flag) +{ + if (flag && flag == true) + { + if (buffer) + { + if (buffer.indexOf("missing api key") > -1) + { + CloudlogTestResult.innerHTML = "API Key Invalid"; + } + else if (buffer.indexOf("created") > -1) + { + CloudlogTestResult.innerHTML = "Passed"; + } + else + { + CloudlogTestResult.innerHTML = "Invalid Response"; + } + } + else + { + CloudlogTestResult.innerHTML = "Invalid Response"; + } + } + else + { + if (buffer && buffer.indexOf("created") > -1) + { addLastTraffic("Logged to Cloudlog"); } + else addLastTraffic("Fail log to Cloudlog"); + } +} + +function qrzSendLogResult(buffer, flag) +{ + if (typeof buffer != "undefined" && buffer != null) + { + var data = String(buffer); + var kv = data.split("&"); + if (kv.length > 0) + { + var arrData = Object(); + for (var x in kv) + { + var split = kv[x].split("="); + arrData[split[0]] = split[1]; + } + if ( + typeof arrData.RESULT == "undefined" || + arrData.RESULT != "OK" + ) + { + alert( + "Error uploading QSO to QRZ.com (" + + (arrData.REASON || "Unknown error") + + ")" + ); + addLastTraffic("Fail log to QRZ.com"); + } + else + { addLastTraffic("Logged to QRZ.com"); } + } + } + else alert("Error uploading QSO to QRZ.com (No response)"); +} + +function postDialogRetryCallback( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + timeoutCallback, + who +) +{ + if (window.confirm("Error sending QSO to " + who + ", retry?")) + { + getPostBuffer( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + postDialogRetryCallback, + who + ); + } +} + +function postRetryErrorCallaback( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + timeoutCallback, + who +) +{ + getPostBuffer( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + postDialogRetryCallback, + who + ); +} + +function sendQrzLogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logQRZqsoCheckBox.checked == true && ValidateQrzApi(qrzApiKey)) + { + if (typeof nw != "undefined") + { + var postData = { + KEY: qrzApiKey.value, + ACTION: "INSERT", + ADIF: report + }; + getPostBuffer( + "https://logbook.qrz.com/api", + qrzSendLogResult, + null, + "https", + 443, + postData, + 30000, + postRetryErrorCallaback, + "QRZ.com" + ); + } + } +} + +function clubLogQsoResult(buffer, flag) +{ + addLastTraffic("Logged to ClubLog.org"); +} + +function sendClubLogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logClubqsoCheckBox.checked == true) + { + if (typeof nw != "undefined") + { + var postData = { + email: clubEmail.value, + password: clubPassword.value, + callsign: clubCall.value, + adif: report, + api: CLk + }; + + getPostBuffer( + "https://clublog.org/realtime.php", + clubLogQsoResult, + null, + "https", + 443, + postData, + 30000, + postRetryErrorCallaback, + "ClubLog.org" + ); + } + } +} + +function sendCloudlogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logCloudlogQSOCheckBox.checked == true) + { + if (typeof nw != "undefined") + { + var postData = { key: CloudlogAPI.value, type: "adif", string: report }; + getPostJSONBuffer( + CloudlogURL.value, + CloudlogSendLogResult, + null, + "https", + 80, + postData, + 10000, + CloudUrlErrorCallback, + "Failed to Send" + ); + } + } +} + +function hrdSendLogResult(buffer, flag) +{ + if (flag && flag == true) + { + if (buffer.indexOf("Unknown user") > -1) + { + HRDLogTestResult.innerHTML = "Failed"; + logHRDLOGqsoCheckBox.checked = false; + adifLogQsoCheckBoxChanged(logHRDLOGqsoCheckBox); + } + else HRDLogTestResult.innerHTML = "Passed"; + } + else + { + if (buffer.indexOf("Unknown user") == -1) + { addLastTraffic("Logged to HRDLOG.net"); } + else + { addLastTraffic("Fail log to HRDLOG.net"); } + } +} + +function sendHrdLogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logHRDLOGqsoCheckBox.checked == true) + { + if (typeof nw != "undefined") + { + var postData = { + Callsign: HRDLOGCallsign.value, + Code: HRDLOGUploadCode.value, + App: "GridTracker " + gtVersion, + ADIFData: report + }; + getPostBuffer( + "https://www.hrdlog.net/NewEntry.aspx", + hrdSendLogResult, + null, + "https", + 443, + postData, + 30000, + postRetryErrorCallaback, + "HRDLog.net" + ); + } + } +} + +function hrdCredentialTest(test) +{ + if (test && test == true) + { + HRDLogTestResult.innerHTML = "Testing"; + + if (typeof nw != "undefined") + { + var postData = { + Callsign: HRDLOGCallsign.value, + Code: HRDLOGUploadCode.value + }; + getPostBuffer( + "https://www.hrdlog.net/NewEntry.aspx", + hrdSendLogResult, + test, + "https", + 443, + postData + ); + } + } +} + +function ClublogTest(test) +{ + if (test && test == true) + { + CloudlogTestResult.innerHTML = "Testing"; + + if (typeof nw != "undefined") + { + var postData = { key: CloudlogAPI.value, type: "adif", string: "" }; + getPostJSONBuffer( + CloudlogURL.value, + CloudlogSendLogResult, + test, + "https", + 80, + postData, + 10000, + CloudUrlErrorCallback, + "No Response
or
Timeout" + ); + } + } +} + +function getPostJSONBuffer( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + timeoutCallback, + who +) +{ + try + { + var postData = JSON.stringify(theData); + var url = require("url"); + var protocol = url.parse(file_url).protocol; // eslint-disable-line node/no-deprecated-api + var http = require(protocol.replace(":", "")); + var fileBuffer = null; + var options = { + host: url.parse(file_url).hostname, // eslint-disable-line node/no-deprecated-api + port: url.parse(file_url).port, // eslint-disable-line node/no-deprecated-api + path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api + method: "post", + headers: { + "Content-Type": "application/json", + "Content-Length": postData.length + } + }; + var req = http.request(options, function (res) + { + var fsize = res.headers["content-length"]; + var cookies = null; + if (typeof res.headers["set-cookie"] != "undefined") + { cookies = res.headers["set-cookie"]; } + res + .on("data", function (data) + { + if (fileBuffer == null) fileBuffer = data; + else fileBuffer += data; + }) + .on("end", function () + { + if (typeof callback === "function") + { + // Call it, since we have confirmed it is callable + callback(fileBuffer, flag, cookies); + } + }) + .on("error", function () {}); + }); + if (typeof timeoutMs == "number" && timeoutMs > 0) + { + req.on("socket", function (socket) + { + socket.setTimeout(timeoutMs); + socket.on("timeout", function () + { + req.abort(); + }); + }); + req.on("error", function (err) // eslint-disable-line node/handle-callback-err + { + if (typeof timeoutCallback != "undefined") + { + timeoutCallback( + file_url, + callback, + flag, + mode, + 80, + theData, + timeoutMs, + timeoutCallback, + who + ); + } + }); + } + req.write(postData); + req.end(); + } + catch (e) + { + if (typeof timeoutCallback != "undefined") + { + timeoutCallback( + file_url, + callback, + flag, + mode, + 80, + theData, + timeoutMs, + timeoutCallback, + "Invalid Url" + ); + } + } +} + +function valueToXmlField(field, value) +{ + var adi = "<" + field + ">"; + adi += String(value); + adi += ""; + return adi; +} + +function aclUpdateControlValue(control, value) +{ + return ( + valueToXmlField( + "CMD", + "" + + valueToXmlField("CONTROL", control) + + valueToXmlField("VALUE", value) + ) + "\r\n" + ); +} + +function aclAction(action) +{ + return ( + valueToXmlField("CMD", "" + valueToXmlField("VALUE", action)) + + "\r\n" + ); +} + +function adifField(record, key) +{ + if (key in record) return record[key]; + else return ""; +} +function sendACLogMessage(record, port, address) +{ + var report = ""; + + report += aclAction("CLEAR"); + report += aclUpdateControlValue("TXTENTRYBAND", adifField(record, "BAND")); + report += aclUpdateControlValue("TXTENTRYCALL", adifField(record, "CALL")); + report += aclAction("CALLTAB"); + report += aclUpdateControlValue( + "TXTENTRYFREQUENCY", + adifField(record, "FREQ") + ); + if (adifField(record, "SUBMODE").length > 0) + { + report += aclUpdateControlValue( + "TXTENTRYMODE", + adifField(record, "SUBMODE") + ); + } + else + { report += aclUpdateControlValue("TXTENTRYMODE", adifField(record, "MODE")); } + + var date = adifField(record, "QSO_DATE"); + var dataString = + date.substr(0, 4) + "/" + date.substr(4, 2) + "/" + date.substr(6); + + report += aclUpdateControlValue("TXTENTRYDATE", dataString); + + var timeVal = adifField(record, "TIME_ON"); + var whenString = + timeVal.substr(0, 2) + + ":" + + timeVal.substr(2, 2) + + ":" + + timeVal.substr(4, 2); + report += aclUpdateControlValue("TXTENTRYTIMEON", whenString); + + timeVal = adifField(record, "TIME_OFF"); + whenString = + timeVal.substr(0, 2) + + ":" + + timeVal.substr(2, 2) + + ":" + + timeVal.substr(4, 2); + report += aclUpdateControlValue("TXTENTRYTIMEOFF", whenString); + + report += aclUpdateControlValue( + "TXTENTRYRSTR", + adifField(record, "RST_RCVD") + ); + report += aclUpdateControlValue( + "TXTENTRYRSTS", + adifField(record, "RST_SENT") + ); + report += aclUpdateControlValue("TXTENTRYPOWER", adifField(record, "TX_PWR")); + report += aclUpdateControlValue( + "TXTENTRYGRID", + adifField(record, "GRIDSQUARE") + ); + report += aclUpdateControlValue( + "TXTENTRYCOMMENTS", + adifField(record, "COMMENT") + ); + report += aclUpdateControlValue("TXTENTRYNAMER", adifField(record, "NAME")); + report += aclUpdateControlValue("TXTENTRYIOTA", adifField(record, "IOTA")); + report += aclUpdateControlValue( + "TXTENTRYCONTINENT", + adifField(record, "CONT") + ); + report += aclUpdateControlValue("TXTENTRYITUZ", adifField(record, "ITUZ")); + report += aclUpdateControlValue("TXTENTRYCQZONE", adifField(record, "CQZ")); + report += aclUpdateControlValue("TXTENTRYCOUNTYR", adifField(record, "CNTY")); + + var sentSpcNum = false; + if (adifField(record, "SRX").length > 0) + { + report += aclUpdateControlValue( + "TXTENTRYSERIALNOR", + adifField(record, "SRX") + ); + } + else if (adifField(record, "CONTEST_ID").length > 0) + { + report += aclUpdateControlValue( + "TXTENTRYSPCNUM", + adifField(record, "SRX_STRING") + ); + sentSpcNum = true; + report += aclUpdateControlValue( + "TXTENTRYCLASS", + adifField(record, "CLASS") + ); + report += aclUpdateControlValue( + "TXTENTRYSECTION", + adifField(record, "ARRL_SECT") + ); + } + + if (adifField(record, "STATE").length > 0) + { + report += aclUpdateControlValue( + "TXTENTRYSTATE", + adifField(record, "STATE") + ); + if (sentSpcNum == false) + { + report += aclUpdateControlValue( + "TXTENTRYSPCNUM", + adifField(record, "STATE") + ); + } + } + + report += aclAction("ENTER"); + + sendTcpMessage(report, report.length, port, address); +} + +function sendDXKeeperLogMessage(newMessage, port, address) +{ + var report = ""; + + report += valueToAdiField("command", "log"); + report += valueToAdiField("parameters", newMessage); + report += "\r\n"; + + sendTcpMessage(report, report.length, Number(port) + 1, address); +} + +function parseADIFRecord(adif) +{ + var regex = new RegExp("", "i"); + var newLine = adif.split(regex); + var line = newLine[0].trim(); // Catch the naughty case of someone sending two records at the same time + var record = {}; + + // because strings are not escaped for adif.. ie: :'s and <'s .. we have to walk from left to right + // cheesy, but damn i'm tired of parsing things + var x = 0; + while (line.length > 0) + { + while (line.charAt(0) != "<" && line.length > 0) + { + line = line.substr(1); + } + if (line.length > 0) + { + line = line.substr(1); + var where = line.indexOf(":"); + if (where != -1) + { + var fieldName = line.substr(0, where).toUpperCase(); + line = line.substr(fieldName.length + 1); + var fieldLength = parseInt(line); + var end = line.indexOf(">"); + if (end > 0) + { + line = line.substr(end + 1); + var fieldValue = line.substr(0, fieldLength); + line = line.substr(fieldLength); + record[fieldName] = fieldValue; + } + } + } + } + + return record; +} + +function sendHRDLogbookEntry(report, port, address) +{ + var command = "ver\rdb add {"; + var items = Object.assign({}, report); + + items.FREQ = items.FREQ.split(".").join(""); + + for (var item in items) + { + command += item + "=\"" + items[item] + "\" "; + } + + command += "}\rexit\r"; + + sendTcpMessage(command, command.length, Number(port), address); +} From 24aedc0e129ac3842cac85437f6a1e5a0ff546fb Mon Sep 17 00:00:00 2001 From: jangliss Date: Sat, 12 Jun 2021 22:08:47 -0500 Subject: [PATCH 002/125] Fix npm wanting a space after comment syntax --- package.nw/lib/adif.js | 5927 ++++++++++++++++++++-------------------- 1 file changed, 2964 insertions(+), 2963 deletions(-) diff --git a/package.nw/lib/adif.js b/package.nw/lib/adif.js index ef4ac67..0259731 100644 --- a/package.nw/lib/adif.js +++ b/package.nw/lib/adif.js @@ -1,2963 +1,2964 @@ -// GridTracker Copyright © 2021 GridTracker.org -// All rights reserved. -// See LICENSE for more information. - -var selectStartupLink = null; - -function dragOverHandler(ev) -{ - // Prevent default behavior (Prevent file from being opened) - ev.preventDefault(); -} - -function dropHandler(ev) -{ - // Prevent default behavior (Prevent file from being opened) - ev.preventDefault(); - if (ev.dataTransfer.items) - { - // Use DataTransferItemList interface to access the file(s) - for (var i = 0; i < ev.dataTransfer.items.length; i++) - { - // If dropped items aren't files, reject them - Entry = ev.dataTransfer.items[i].webkitGetAsEntry(); - if (Entry && typeof Entry.isFile != "undefined" && Entry.isFile == true) - { - var filename = ev.dataTransfer.items[i].getAsFile().path; - var test = filename.toLowerCase(); - var valid = test.endsWith(".adi") - ? true - : test.endsWith(".adif") - ? true - : test.endsWith(".log") - ? true - : !!test.endsWith(".txt"); - if (valid && fs.existsSync(filename)) - { - onAdiLoadComplete(fs.readFileSync(filename, "UTF-8"), false); - } - } - } - } -} - -function findAdiField(row, field) -{ - var value = ""; - var regex = new RegExp("<" + field + ":", "i"); - var firstSplitArray = row.split(regex); - if (firstSplitArray && firstSplitArray.length == 2) - { - var secondSplitArray = firstSplitArray[1].split(">"); - if (secondSplitArray.length > 1) - { - var newLenSearch = secondSplitArray[0].split(":"); - var newLen = newLenSearch[0]; - value = secondSplitArray[1].slice(0, newLen); - } - } - return value; -} - -function onAdiLoadComplete(adiBuffer, saveAdifFile, adifFileName, newFile) -{ - let rawAdiBuffer = ""; - if (typeof adiBuffer == "object") rawAdiBuffer = String(adiBuffer); - else rawAdiBuffer = adiBuffer; - - let activeAdifArray = Array(); - let activeAdifLogMode = true; - let eQSLfile = false; - - if (rawAdiBuffer.indexOf("PSKReporter") > -1) activeAdifLogMode = false; - - if (rawAdiBuffer.indexOf("Received eQSLs") > -1) eQSLfile = true; - - if (rawAdiBuffer.length > 1) - { - let regex = new RegExp("", "i"); - activeAdifArray = rawAdiBuffer.split(regex); - } - - let dateTime = new Date(); - let dupes = 0; - - for (let x = 0; x < activeAdifArray.length; x++) - { - let finalMode = ""; - - if (activeAdifArray[x].length > 3) - { - if (activeAdifLogMode) - { - let confirmed = false; - let finalGrid = findAdiField( - activeAdifArray[x], - "GRIDSQUARE" - ).toUpperCase(); - let vuccGrids = findAdiField( - activeAdifArray[x], - "VUCC_GRIDS" - ).toUpperCase(); - let finalVucc = []; - let finalDXcall = findAdiField(activeAdifArray[x], "CALL").replace( - "_", - "/" - ); - let finalDEcall = findAdiField( - activeAdifArray[x], - "STATION_CALLSIGN" - ).replace("_", "/"); - - if (finalDEcall == "") finalDEcall = myDEcall; - if ( - g_appSettings.workingCallsignEnable && - !(finalDEcall in g_appSettings.workingCallsigns) - ) - { continue; } - let finalRSTsent = findAdiField(activeAdifArray[x], "RST_SENT"); - let finalRSTrecv = findAdiField(activeAdifArray[x], "RST_RCVD"); - let finalBand = findAdiField(activeAdifArray[x], "BAND").toLowerCase(); - let dateVal = findAdiField(activeAdifArray[x], "QSO_DATE"); - let timeVal = findAdiField(activeAdifArray[x], "TIME_ON"); - let finalState = findAdiField( - activeAdifArray[x], - "STATE" - ).toUpperCase(); - if (finalState.length == 0) finalState = null; - let finalPropMode = findAdiField( - activeAdifArray[x], - "PROP_MODE" - ).toUpperCase(); - let finalSatName = findAdiField( - activeAdifArray[x], - "SAT_NAME" - ).toUpperCase(); - let finalCont = findAdiField(activeAdifArray[x], "CONT").toUpperCase(); - if (finalCont.length == 0) finalCont = null; - let finalCnty = findAdiField(activeAdifArray[x], "CNTY").toUpperCase(); - if (finalCnty.length == 0) finalCnty = null; - else - { - finalCnty = finalCnty.replaceAll(" ", ""); - } - let finalMode = findAdiField(activeAdifArray[x], "MODE").toUpperCase(); - let subMode = findAdiField(activeAdifArray[x], "SUBMODE"); - if (subMode == "FT4" && (finalMode == "MFSK" || finalMode == "DATA")) - { finalMode = "FT4"; } - if (subMode == "JS8" && finalMode == "MFSK") finalMode = "JS8"; - - if (finalBand == "oob" || finalBand == "") - { - finalBand = Number( - findAdiField(activeAdifArray[x], "FREQ") - ).formatBand(); - } - - let finalMsg = findAdiField(activeAdifArray[x], "COMMENT"); - let finalQslMsg = findAdiField(activeAdifArray[x], "QSLMSG"); - let finalQslMsgIntl = findAdiField(activeAdifArray[x], "QSLMSG_INTL"); - if (finalQslMsg.length > 1) finalMsg = finalQslMsg; - if (finalQslMsgIntl.length > 1 && finalMsg == "") - { finalMsg = finalQslMsgIntl; } - - let finalDxcc = Number(findAdiField(activeAdifArray[x], "DXCC")); - if (finalDxcc == 0) finalDxcc = Number(callsignToDxcc(finalDXcall)); - - if (!(finalDxcc in g_dxccToGeoData)) - { finalDxcc = Number(callsignToDxcc(finalDXcall)); } - - // If my callsign isn't present, it must be for me anyway - - let finalCqZone = findAdiField(activeAdifArray[x], "CQZ"); - if (finalCqZone.length == 1) finalCqZone = "0" + finalCqZone; - - if (parseInt(finalCqZone) < 1 || parseInt(finalCqZone) > 40) - { finalCqZone = ""; } - finalCqZone = String(finalCqZone); - let finalItuZone = findAdiField(activeAdifArray[x], "ITUZ"); - if (finalItuZone.length == 1) finalItuZone = "0" + finalItuZone; - - if (parseInt(finalItuZone) < 1 || parseInt(finalItuZone) > 90) - { finalItuZone = ""; } - finalItuZone = String(finalItuZone); - - let finalIOTA = findAdiField(activeAdifArray[x], "IOTA").toUpperCase(); - - let qrzConfirmed = findAdiField( - activeAdifArray[x], - "APP_QRZLOG_STATUS" - ).toUpperCase(); - let lotwConfirmed1 = findAdiField( - activeAdifArray[x], - "QSL_RCVD" - ).toUpperCase(); - let lotw_qsl_rcvd = findAdiField( - activeAdifArray[x], - "LOTW_QSL_RCVD" - ).toUpperCase(); - let eqsl_qsl_rcvd = findAdiField( - activeAdifArray[x], - "EQSL_QSL_RCVD" - ).toUpperCase(); - - if ( - qrzConfirmed == "C" || - lotw_qsl_rcvd == "Y" || - lotw_qsl_rcvd == "V" || - lotwConfirmed1 == "Y" || - eqsl_qsl_rcvd == "Y" || - eqsl_qsl_rcvd == "V" || - eQSLfile == true - ) - { confirmed = true; } - - let dateTime = new Date( - Date.UTC( - dateVal.substr(0, 4), - parseInt(dateVal.substr(4, 2)) - 1, - dateVal.substr(6, 2), - timeVal.substr(0, 2), - timeVal.substr(2, 2), - timeVal.substr(4, 2) - ) - ); - - let finalTime = parseInt(dateTime.getTime() / 1000); - - if ( - g_appSettings.workingDateEnable && - finalTime < g_appSettings.workingDate - ) - { continue; } - - finalGrid = finalGrid.substr(0, 6); - if (!validateGridFromString(finalGrid)) finalGrid = ""; - if (finalGrid == "" && vuccGrids != "") - { - finalVucc = vuccGrids.split(","); - finalGrid = finalVucc[0]; - finalVucc.shift(); - } - let isDigital = false; - let isPhone = false; - if (finalMode in g_modes) - { - isDigital = g_modes[finalMode]; - } - if (finalMode in g_modes_phone) - { - isPhone = g_modes_phone[finalMode]; - } - if (finalDXcall != "") - { - addDeDx( - finalGrid, - finalDXcall, - false, - false, - false, - finalDEcall, - finalRSTsent, - finalTime, - finalMsg, - finalMode, - finalBand, - confirmed, - false, - finalRSTrecv, - finalDxcc, - finalState, - finalCont, - finalCnty, - finalCqZone, - finalItuZone, - finalVucc, - finalPropMode, - isDigital, - isPhone, - finalIOTA, - finalSatName - ); - } - } - else - { - let finalMyGrid = findAdiField( - activeAdifArray[x], - "MY_GRIDSQUARE" - ).toUpperCase(); - let finalGrid = findAdiField( - activeAdifArray[x], - "GRIDSQUARE" - ).toUpperCase(); - let finalDXcall = findAdiField(activeAdifArray[x], "CALL"); - let finalDEcall = findAdiField(activeAdifArray[x], "OPERATOR"); - let finalRSTsent = findAdiField(activeAdifArray[x], "APP_PSKREP_SNR"); - let dateVal = findAdiField(activeAdifArray[x], "QSO_DATE"); - let timeVal = findAdiField(activeAdifArray[x], "TIME_ON"); - let finalMode = findAdiField(activeAdifArray[x], "MODE"); - let finalBand = Number( - findAdiField(activeAdifArray[x], "FREQ") - ).formatBand(); - let finalMsg = "-"; - let finalDxcc = Number(findAdiField(activeAdifArray[x], "DXCC")); - if (finalDxcc == 0) - { - if (finalDXcall == myDEcall) finalDxcc = callsignToDxcc(finalDEcall); - else finalDxcc = callsignToDxcc(finalDXcall); - } - - finalGrid = finalGrid.substr(0, 6); - - let dateTime = new Date( - Date.UTC( - dateVal.substr(0, 4), - parseInt(dateVal.substr(4, 2)) - 1, - dateVal.substr(6, 2), - timeVal.substr(0, 2), - timeVal.substr(2, 2), - timeVal.substr(4, 2) - ) - ); - let finalTime = parseInt(dateTime.getTime() / 1000); - if ( - finalGrid != "" && - finalDXcall != "" && - validateGridFromString(finalGrid) - ) - { - if (finalDXcall == myDEcall) - { - addDeDx( - finalMyGrid, - finalDEcall, - false, - false, - false, - finalDXcall, - null, - finalTime, - finalMsg, - finalMode, - finalBand, - false, - true, - finalRSTsent, - finalDxcc, - null, - null, - null, - null, - null - ); - } - else if (finalDEcall == myDEcall) - { - addDeDx( - finalGrid, - finalDXcall, - false, - false, - false, - "-", - finalRSTsent, - finalTime, - finalMsg, - finalMode, - finalBand, - false, - true, - null, - finalDxcc, - null, - null, - null, - null, - null - ); - } - else - { - addDeDx( - finalGrid, - finalDXcall, - false, - false, - false, - finalDEcall, - finalRSTsent, - finalTime, - finalMsg, - finalMode, - finalBand, - false, - true, - null, - finalDxcc, - null, - null, - null, - null, - null - ); - } - } - } - } - } - - redrawGrids(); - updateCountStats(); - updateLogbook(); - - if (g_fromDirectCallNoFileDialog == false) - { - fileSelector.setAttribute("type", ""); - fileSelector.setAttribute("type", "file"); - fileSelector.setAttribute("accept", ".adi,"); - fileSelector.value = null; - } - g_fromDirectCallNoFileDialog = false; - - updateRosterWorked(); - goProcessRoster(); -} - -function clubLogCallback(buffer, flag, cookie) -{ - var rawAdiBuffer = String(buffer); - if (rawAdiBuffer.indexOf("Invalid login") > -1) - { - if (flag) clubTestResult.innerHTML = "Invalid"; - } - else if (buffer == null) - { - if (flag) clubTestResult.innerHTML = "Unknown Error"; - } - else - { - if (flag) clubTestResult.innerHTML = "Passed"; - else - { - g_fromDirectCallNoFileDialog = true; - - rawAdiBuffer = cleanAndPrepADIF("clublog.adif", rawAdiBuffer); - - tryToWriteAdifToDocFolder("clublog.adif", rawAdiBuffer); - - onAdiLoadComplete(rawAdiBuffer, true, "clublog.adif", true); - } - } -} - -var g_isGettingClub = false; -function grabClubLog(test) -{ - if (g_isGettingClub == false) - { - if (test) clubTestResult.innerHTML = "Testing"; - - var postData = { - email: clubEmail.value, - password: clubPassword.value, - call: clubCall.value - }; - getAPostBuffer( - "https://clublog.org/getadif.php", - clubLogCallback, - test, - "https", - 443, - postData, - ClubLogImg, - "g_isGettingClub" - ); - } -} - -function tryToWriteAdifToDocFolder(filename, buffer, append = false) -{ - var finalFile = g_appData + g_dirSeperator + filename; - try - { - if (append == false) - { - fs.writeFileSync(finalFile, buffer); - return buffer; - } - else - { - fs.appendFileSync(finalFile, buffer); - return fs.readFileSync(finalFile); - } - } - catch (e) - { - return false; - } -} - -function cleanAndPrepADIF(name, adiBuffer, reverse = false, noheader = false) -{ - var rawAdiBuffer = adiBuffer; - var regex = new RegExp("", "i"); - rawAdiBuffer = rawAdiBuffer.replace(regex, ""); - regex = new RegExp("", "i"); - var adiArray = rawAdiBuffer.split(regex); - var activeAdifArray = Array(); - var activeAdifLogMode = true; - var finalBuffer = ""; - - if (noheader == false) finalBuffer = name + "\r\n"; - - if (adiArray.length > 1) - { - regex = new RegExp("", "i"); - activeAdifArray = adiArray[1].split(regex); - - if (reverse == false) - { - for (var x = 0; x < activeAdifArray.length - 1; x++) - { - var row = activeAdifArray[x].replace(/[\n\r]/g, ""); - if (row.length > 0) finalBuffer += row + "\r\n"; - } - } - else - { - for (var x = activeAdifArray.length - 1; x > -1; x--) - { - var row = activeAdifArray[x].replace(/[\n\r]/g, ""); - if (row.length > 0) finalBuffer += row + "\r\n"; - } - } - } - - return finalBuffer; -} - -function addZero(i) -{ - if (i < 10) - { - i = "0" + i; - } - return i; -} - -function getUTCString(d) -{ - var Y = d.getUTCFullYear(); - var M = addZero(d.getUTCMonth() + 1); - var D = addZero(d.getUTCDate()); - var h = addZero(d.getUTCHours()); - var m = addZero(d.getUTCMinutes()); - var s = addZero(d.getUTCSeconds()); - return Y + "-" + M + "-" + D + " " + h + ":" + m + ":" + s; -} - -function lotwCallback(buffer, flag) -{ - var rawAdiBuffer = String(buffer); - if (rawAdiBuffer.indexOf("password incorrect") > -1) - { - if (flag) lotwTestResult.innerHTML = "Invalid"; - } - else - { - if (flag) lotwTestResult.innerHTML = "Passed"; - else - { - var shouldAppend = false; - g_fromDirectCallNoFileDialog = true; - - rawAdiBuffer = cleanAndPrepADIF( - "lotw.adif", - rawAdiBuffer, - true, - shouldAppend - ); - - rawAdiBuffer = tryToWriteAdifToDocFolder( - "lotw.adif", - rawAdiBuffer, - shouldAppend - ); - - onAdiLoadComplete(rawAdiBuffer, true, "lotw.adif", true); - } - } -} - -function shouldWeAppendInsteadOfCreate(filename) -{ - var finalFile = g_appData + g_dirSeperator + filename; - try - { - if (fs.existsSync(finalFile)) return true; - else return false; - } - catch (e) - { - return false; - } -} - -function tryToDeleteLog(filename) -{ - var finalFile = g_appData + g_dirSeperator + filename; - try - { - if (fs.existsSync(finalFile)) - { - fs.unlinkSync(finalFile); - } - } - catch (e) {} -} - -var g_lotwCount = 0; - -var g_isGettingLOTW = false; - -function grabLOtWLog(test) -{ - if (g_isGettingLOTW == false) - { - var lastQSLDateString = - "&qso_qsorxsince=1945-01-01&qso_qslsince=1945-01-01"; - if (test == true) - { - lotwTestResult.innerHTML = "Testing"; - lastQSLDateString = "&qso_qsosince=2100-01-01"; - } - - getABuffer( - "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + - lotwLogin.value + - "&password=" + - encodeURIComponent(lotwPassword.value) + - "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + - lastQSLDateString, - lotwCallback, - test, - "https", - 443, - lotwLogImg, - "g_isGettingLOTW", - 120000 - ); - } -} - -function qrzCallback(buffer, flag) -{ - if (buffer.indexOf("invalid api key") > -1) - { - if (flag) qrzTestResult.innerHTML = "Invalid"; - } - else - { - if (flag) - { - qrzTestResult.innerHTML = "Passed"; - } - else - { - g_fromDirectCallNoFileDialog = true; - var htmlString = String(buffer).replace(/</g, "<"); - htmlString = htmlString.replace(/>/g, ">"); - htmlString = htmlString.replace("ADIF=", "QRZ\r\n"); - - htmlString = cleanAndPrepADIF("qrz.adif", htmlString); - - tryToWriteAdifToDocFolder("qrz.adif", htmlString); - - onAdiLoadComplete(htmlString, true, "qrz.adif", true); - } - } -} - -var g_isGettingQRZCom = false; -function grabQrzComLog(test) -{ - if (g_isGettingQRZCom == false) - { - var action = "FETCH"; - if (test) - { - qrzTestResult.innerHTML = "Testing"; - action = "STATUS"; - } - - getABuffer( - "https://logbook.qrz.com/api?KEY=" + - qrzApiKey.value + - "&ACTION=" + - action, - qrzCallback, - test, - "https", - 443, - qrzLogImg, - "g_isGettingQRZCom", - null - ); - } -} - -function ValidateQrzApi(inputText) -{ - inputText.value = inputText.value.toUpperCase(); - if (inputText.value.length == 19) - { - var passed = false; - var dashcount = 0; - for (var i = 0; i < inputText.value.length; i++) - { - if (inputText.value[i] == "-") dashcount++; - } - if (dashcount == 3) - { - passed = true; - } - if (passed) - { - inputText.style.color = "#FF0"; - inputText.style.backgroundColor = "green"; - - return true; - } - else - { - inputText.style.color = "white"; - inputText.style.backgroundColor = "red"; - return false; - } - } - else - { - inputText.style.color = "white"; - inputText.style.backgroundColor = "red"; - - return false; - } -} - -function ValidateText(inputText) -{ - if (inputText.value.length > 0) - { - inputText.style.color = "#FF0"; - inputText.style.backgroundColor = "green"; - return true; - } - else - { - inputText.style.color = "white"; - inputText.style.backgroundColor = "red"; - return false; - } -} - -function pskCallback(buffer, flag) -{ - g_fromDirectCallNoFileDialog = true; - var rawAdiBuffer = String(buffer); - - onAdiLoadComplete(rawAdiBuffer, false); -} - -var g_isGettingPsk = false; - -function grabPsk24() -{ - if (g_isGettingPsk == true) return; - - if (myDEcall.length > 0 && myDEcall != "NOCALL") - { - var days = 1; - if (pskImg.src == 1) days = 7; - getABuffer( - "https://pskreporter.info/cgi-bin/pskdata.pl?adif=1&days=" + - days + - "&receiverCallsign=" + - myDEcall.toLowerCase(), - pskCallback, - null, - "https", - 443, - pskImg, - "g_isGettingPsk" - ); - } -} - -function adifMenuCheckBoxChanged(what) -{ - g_adifLogSettings.menu[what.id] = what.checked; - var menuItem = what.id + "Div"; - if (what.checked == true) - { - document.getElementById(menuItem).style.display = "inline-block"; - } - else - { - document.getElementById(menuItem).style.display = "none"; - } - - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); - - if (what == buttonAdifCheckBox) setAdifStartup(loadAdifCheckBox); -} - -function adifStartupCheckBoxChanged(what) -{ - g_adifLogSettings.startup[what.id] = what.checked; - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); - - if (what == loadAdifCheckBox) setAdifStartup(loadAdifCheckBox); -} - -function adifLogQsoCheckBoxChanged(what) -{ - g_adifLogSettings.qsolog[what.id] = what.checked; - if (what.id == "logLOTWqsoCheckBox") - { - if (what.checked == true) - { - lotwUpload.style.display = "inline-block"; - trustedTestButton.style.display = "inline-block"; - } - else - { - lotwUpload.style.display = "none"; - trustedTestButton.style.display = "none"; - } - } - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); -} - -function adifNicknameCheckBoxChanged(what) -{ - g_adifLogSettings.nickname[what.id] = what.checked; - if (what.id == "nicknameeQSLCheckBox") - { - if (what.checked == true) - { - eQSLNickname.style.display = "inline-block"; - } - else - { - eQSLNickname.style.display = "none"; - } - } - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); -} - -function adifTextValueChange(what) -{ - what.value = what.value.trim(); - g_adifLogSettings.text[what.id] = what.value; - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); -} - -var fileSelector = document.createElement("input"); -fileSelector.setAttribute("type", "file"); -fileSelector.setAttribute("accept", ".adi,.adif"); -fileSelector.onchange = function () -{ - if (this.files && this.files[0]) - { - let path = this.value.replace(this.files[0].name, ""); - fileSelector.setAttribute("nwworkingdir", path); - - var reader = new FileReader(); - reader.onload = function (e) - { - if (e.target.error == null) - { - onAdiLoadComplete(e.target.result, false); - } - }; - - reader.readAsText(this.files[0]); - } -}; - -function adifLoadDialog() -{ - var exists = fileSelector.getAttribute("nwworkingdir"); - - fileSelector.setAttribute("nwworkingdir", g_appData); - - fileSelector.click(); - - return false; -} - -var startupFileSelector = document.createElement("input"); -startupFileSelector.setAttribute("type", "file"); -startupFileSelector.setAttribute("accept", ".adi,.adif"); -startupFileSelector.onchange = function () -{ - if (this.files && this.files[0]) - { - for (var i in g_startupLogs) - { - if (this.value == g_startupLogs[i].file) return; - } - var newObject = Object(); - newObject.name = this.files[0].name; - newObject.file = this.value; - g_startupLogs.push(newObject); - localStorage.startupLogs = JSON.stringify(g_startupLogs); - - let path = this.value.replace(this.files[0].name, ""); - startupFileSelector.setAttribute("nwworkingdir", path); - - setAdifStartup(loadAdifCheckBox); - } -}; - -function start_and_end(str) -{ - if (str.length > 31) - { - return ( - str.substr(0, 16) + " ... " + str.substr(str.length - 15, str.length) - ); - } - return str; -} - -function setFileSelectors() -{ - selectStartupLink = document.getElementById("selectAdifButton"); - selectStartupLink.onclick = function () - { - var exists = startupFileSelector.getAttribute("nwworkingdir"); - if (exists == null) - { - if (g_workingIniPath.length > 1) - { startupFileSelector.setAttribute("nwworkingdir", g_appData); } - } - - startupFileSelector.click(); - return false; - }; - - selectTqsl = document.getElementById("selectTQSLButton"); - selectTqsl.onclick = function () - { - tqslFileSelector.click(); - return false; - }; - lotwUpload.prepend(selectTqsl); -} - -var tqslFileSelector = document.createElement("input"); -tqslFileSelector.setAttribute("type", "file"); -tqslFileSelector.setAttribute("accept", "*"); -tqslFileSelector.onchange = function () -{ - if (this.files && this.files[0]) - { - g_trustedQslSettings.binaryFile = this.files[0].path; - var fs = require("fs"); - - if ( - fs.existsSync(g_trustedQslSettings.binaryFile) && - (g_trustedQslSettings.binaryFile.endsWith("tqsl.exe") || - g_trustedQslSettings.binaryFile.endsWith("tqsl")) - ) - { - g_trustedQslSettings.binaryFileValid = true; - } - else g_trustedQslSettings.binaryFileValid = false; - - if (g_trustedQslSettings.binaryFileValid == true) - { - tqslFileDiv.style.backgroundColor = "blue"; - } - else - { - tqslFileDiv.style.backgroundColor = "red"; - } - - tqslFileDiv.innerHTML = "" + start_and_end(this.files[0].path) + ""; - localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings); - } -}; - -function loadGtQSOLogFile() -{ - var fs = require("fs"); - - if (fs.existsSync(g_qsoLogFile)) - { - var rawAdiBuffer = fs.readFileSync(g_qsoLogFile); - - g_fromDirectCallNoFileDialog = true; - - onAdiLoadComplete(rawAdiBuffer, false); - } -} - -function loadWsjtLogFile() -{ - var fs = require("fs"); - if (fs.existsSync(g_workingIniPath + "wsjtx_log.adi")) - { - var rawAdiBuffer = fs.readFileSync(g_workingIniPath + "wsjtx_log.adi"); - g_fromDirectCallNoFileDialog = true; - onAdiLoadComplete(rawAdiBuffer, false); - } -} - -function findTrustedQSLPaths() -{ - var process = require("process"); - var base = null; - - if (g_trustedQslSettings.stationFileValid == true) - { - // double check the presence of the station_data; - if (!fs.existsSync(g_trustedQslSettings.stationFile)) - { - g_trustedQslSettings.stationFileValid = false; - } - } - if (g_trustedQslSettings.stationFileValid == false) - { - if (g_platform == "windows") - { - base = process.env.APPDATA + "\\TrustedQSL\\station_data"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.stationFile = base; - g_trustedQslSettings.stationFileValid = true; - } - else - { - base = process.env.LOCALAPPDATA + "\\TrustedQSL\\station_data"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.stationFile = base; - g_trustedQslSettings.stationFileValid = true; - } - } - } - else - { - base = process.env.HOME + "/.tqsl/station_data"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.stationFile = base; - g_trustedQslSettings.stationFileValid = true; - } - } - } - if (g_trustedQslSettings.stationFileValid == true) - { - var validate = false; - var option = document.createElement("option"); - option.value = ""; - option.text = "Select a Station"; - lotwStation.appendChild(option); - - var buffer = fs.readFileSync(g_trustedQslSettings.stationFile, "UTF-8"); - parser = new DOMParser(); - xmlDoc = parser.parseFromString(buffer, "text/xml"); - var x = xmlDoc.getElementsByTagName("StationData"); - for (var i = 0; i < x.length; i++) - { - option = document.createElement("option"); - option.value = x[i].getAttribute("name"); - option.text = x[i].getAttribute("name"); - if (option.value == g_adifLogSettings.text.lotwStation) - { - option.selected = true; - validate = true; - } - lotwStation.appendChild(option); - } - if (validate) - { - ValidateText(lotwStation); - } - } - - if (g_trustedQslSettings.binaryFileValid == true) - { - // double check the presence of the TrustedQSL binary; - if (!fs.existsSync(g_trustedQslSettings.binaryFile)) - { - g_trustedQslSettings.binaryFileValid = false; - } - } - if (g_trustedQslSettings.binaryFileValid == false || g_platform == "mac") - { - if (g_platform == "windows") - { - base = process.env["ProgramFiles(x86)"] + "\\TrustedQSL\\tqsl.exe"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - } - else if (g_platform == "mac") - { - base = "/Applications/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = - process.env.HOME + - "/Applications/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = - process.env.HOME + "/Applications/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = "/Applications/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = - process.env.HOME + - "/Desktop/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = - process.env.HOME + - "/Applications/Ham Radio/tqsl.app/Contents/MacOS/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - } - } - } - } - } - } - else if (g_platform == "linux") - { - base = "/usr/bin/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - else - { - base = "/usr/local/bin/tqsl"; - if (fs.existsSync(base)) - { - g_trustedQslSettings.binaryFile = base; - g_trustedQslSettings.binaryFileValid = true; - } - } - } - } - localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings); -} - -function startupAdifLoadFunction() -{ - var fs = require("fs"); - - for (var i in g_startupLogs) - { - try - { - if (fs.existsSync(g_startupLogs[i].file)) - { - var rawAdiBuffer = fs.readFileSync(g_startupLogs[i].file); - g_fromDirectCallNoFileDialog = true; - onAdiLoadComplete(rawAdiBuffer, false); - } - } - catch (e) {} - } -} - -function setAdifStartup(checkbox) -{ - if (g_trustedQslSettings.binaryFile == null) - { g_trustedQslSettings.binaryFile = ""; } - - if ( - g_trustedQslSettings.binaryFile.endsWith("tqsl.exe") || - g_trustedQslSettings.binaryFile.endsWith("tqsl") - ) - { - g_trustedQslSettings.binaryFileValid = true; - } - else g_trustedQslSettings.binaryFileValid = false; - - if (g_trustedQslSettings.binaryFileValid == true) - { - tqslFileDiv.style.backgroundColor = "blue"; - } - else - { - tqslFileDiv.style.backgroundColor = "red"; - } - tqslFileDiv.innerHTML = - "" + start_and_end(g_trustedQslSettings.binaryFile) + ""; - - if (buttonAdifCheckBox.checked || loadAdifCheckBox.checked) - { - var worker = ""; - if (g_startupLogs.length > 0) - { - worker += ""; - for (var i in g_startupLogs) - { - worker += - ""; - } - worker += "
" + - g_startupLogs[i].name + - "
"; - } - else - { - worker = "No file(s) selected"; - } - startupLogFileDiv.innerHTML = worker; - selectFileOnStartupDiv.style.display = "block"; - } - else - { - startupLogFileDiv.innerHTML = "No file(s) selected"; - startupFileSelector.setAttribute("type", ""); - startupFileSelector.setAttribute("type", "file"); - startupFileSelector.setAttribute("accept", ".adi*"); - startupFileSelector.value = null; - selectFileOnStartupDiv.style.display = "none"; - } -} - -function removeStartupLog(i) -{ - if (i in g_startupLogs) - { - g_startupLogs.splice(i, 1); - localStorage.startupLogs = JSON.stringify(g_startupLogs); - setAdifStartup(loadAdifCheckBox); - } -} - -function startupAdifLoadCheck() -{ - logEventMedia.value = g_alertSettings.logEventMedia; - - loadWsjtLogFile(); - - if (loadGTCheckBox.checked == true) loadGtQSOLogFile(); - - if (loadAdifCheckBox.checked == true && g_startupLogs.length > 0) - { startupAdifLoadFunction(); } - - if (g_mapSettings.offlineMode == false) - { - if (g_appSettings.gtFlagImgSrc == 1) showGtFlags(); - - //if (loadLOTWCheckBox.checked == true) grabLOtWLog(false); - - if (loadQRZCheckBox.checked == true) grabQrzComLog(false); - - if (loadClubCheckBox.checked == true) grabClubLog(false); - - if (loadPsk24CheckBox.checked == true) grabPsk24(); - } -} - -function getABuffer( - file_url, - callback, - flag, - mode, - port, - imgToGray, - stringOfFlag, - timeoutX -) -{ - let url = require("url"); - let http = require(mode); - let fileBuffer = null; - let options = null; - - options = { - host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api - port: port, - path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api - method: "get" - }; - - if (typeof stringOfFlag != "undefined") window[stringOfFlag] = true; - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = - "linear-gradient(grey 0%, black 0% 100% )"; - imgToGray.style.webkitFilter = "invert(100%) grayscale(1)"; - } - - let req = http.request(options, function (res) - { - let fsize = res.headers["content-length"]; - let cookies = null; - if (typeof res.headers["set-cookie"] != "undefined") - { cookies = res.headers["set-cookie"]; } - - res - .on("data", function (data) - { - if (fileBuffer == null) fileBuffer = data; - else fileBuffer += data; - - if (typeof imgToGray != "undefined") - { - let percent = 0; - if (fsize > 0) percent = parseInt((fileBuffer.length / fsize) * 100); - else percent = parseInt(((fileBuffer.length / 100000) * 100) % 100); - imgToGray.parentNode.style.background = - "linear-gradient(grey " + - percent + - "%, black " + - Number(percent + 10) + - "% 100% )"; - } - }) - .on("end", function () - { - if (typeof callback === "function") - { - // Call it, since we have confirmed it is callable - callback(fileBuffer, flag, cookies); - } - if (typeof stringOfFlag != "undefined") - { - window[stringOfFlag] = false; - } - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }) - .on("error", function () - { - if (typeof stringOfFlag != "undefined") - { - window[stringOfFlag] = false; - } - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }); - }); - - req.on("socket", function (socket) - { - socket.on("timeout", function () - { - req.abort(); - }); - }); - - req.on("error", function () - { - if (typeof stringOfFlag != "undefined") - { - window[stringOfFlag] = false; - } - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }); - - req.end(); -} - -function getAPostBuffer( - file_url, - callback, - flag, - mode, - port, - theData, - imgToGray, - stringOfFlag -) -{ - var querystring = require("querystring"); - var postData = querystring.stringify(theData); - var url = require("url"); - var http = require(mode); - var fileBuffer = null; - - var options = { - host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api - port: port, - path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api - method: "post", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - "Content-Length": postData.length - } - }; - - window[stringOfFlag] = true; - - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = - "linear-gradient(grey 0%, black 0% 100% )"; - imgToGray.style.webkitFilter = "invert(100%) grayscale(1)"; - } - - var req = http.request(options, function (res) - { - var fsize = res.headers["content-length"]; - var cookies = null; - if (typeof res.headers["set-cookie"] != "undefined") - { cookies = res.headers["set-cookie"]; } - - res - .on("data", function (data) - { - if (fileBuffer == null) fileBuffer = data; - else fileBuffer += data; - - if (typeof imgToGray != "undefined") - { - var percent = 0; - if (fsize > 0) percent = parseInt((fileBuffer.length / fsize) * 100); - else percent = parseInt(((fileBuffer.length / 100000) * 100) % 100); - - imgToGray.parentNode.style.background = - "linear-gradient(grey " + - percent + - "%, black " + - Number(percent + 10) + - "% 100% )"; - } - }) - .on("end", function () - { - if (typeof callback === "function") - { - // Call it, since we have confirmed it is callable - callback(fileBuffer, flag, cookies); - window[stringOfFlag] = false; - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - } - }) - .on("error", function () - { - window[stringOfFlag] = false; - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }); - }); - - req.on("socket", function (socket) - { - socket.on("timeout", function () - { - req.abort(); - }); - }); - - req.on("error", function (err) // eslint-disable-line node/handle-callback-err - { - window[stringOfFlag] = false; - if (typeof imgToGray != "undefined") - { - imgToGray.parentNode.style.background = ""; - imgToGray.style.webkitFilter = ""; - } - }); - - req.write(postData); - req.end(); -} - -function sendUdpMessage(msg, length, port, address) -{ - var dgram = require("dgram"); - var socket = dgram.createSocket({ type: "udp4", reuseAddr: true }); - socket.send(msg, 0, length, port, address, (err) => // eslint-disable-line node/handle-callback-err - { - socket.close(); - }); -} - -function sendTcpMessage(msg, length, port, address) -{ - var net = require("net"); - var client = new net.Socket(); - client.setTimeout(30000); - client.connect(port, address, function () - { - client.write(msg); - }); - - client.on("close", function () {}); -} - -function valueToAdiField(field, value) -{ - var adi = "<" + field + ":"; - adi += String(value).length + ">"; - adi += String(value) + " "; - return adi; -} - -function pad(value) -{ - if (value < 10) - { - return "0" + value; - } - else - { - return value; - } -} - -function HMSfromMilli(milli) -{ - var seconds = parseInt(milli / 1000); - var days = Math.floor(seconds / (3600 * 24)); - seconds -= days * 3600 * 24; - var hrs = Math.floor(seconds / 3600); - seconds -= hrs * 3600; - var mnts = Math.floor(seconds / 60); - seconds -= mnts * 60; - - val = String(pad(hrs)) + String(pad(mnts)) + String(pad(seconds)); - return String(val); -} - -function colonHMSfromMilli(milli) -{ - var seconds = parseInt(milli / 1000); - var days = Math.floor(seconds / (3600 * 24)); - seconds -= days * 3600 * 24; - var hrs = Math.floor(seconds / 3600); - seconds -= hrs * 3600; - var mnts = Math.floor(seconds / 60); - seconds -= mnts * 60; - - val = String(pad(hrs)) + ":" + String(pad(mnts)) + ":" + String(pad(seconds)); - return String(val); -} - -function colonHMSfromSeconds(secondsIn) -{ - var seconds = secondsIn; - var days = Math.floor(seconds / (3600 * 24)); - seconds -= days * 3600 * 24; - var hrs = Math.floor(seconds / 3600); - seconds -= hrs * 3600; - var mnts = Math.floor(seconds / 60); - seconds -= mnts * 60; - - val = String(pad(hrs)) + ":" + String(pad(mnts)) + ":" + String(pad(seconds)); - return String(val); -} - -function convertToDate(julian) -{ - var DAY = 86400000; - var HALF_DAY = DAY / 2; - var UNIX_EPOCH_JULIAN_DATE = 2440587.5; - var UNIX_EPOCH_JULIAN_DAY = 2440587; - return new Date((Number(julian) - UNIX_EPOCH_JULIAN_DATE) * DAY); -} - -var CLk = "25bc718451a71954cb6d0d1b50541dd45d4ba148"; - -var lastReportHash = null; - -var g_oldStyleLogMessage = null; - -function oldSendToLogger() -{ - var newMessage = Object.assign({}, g_oldStyleLogMessage); - - var band = Number(newMessage.Frequency / 1000000).formatBand(); - - if ( - newMessage.DXGrid.length == 0 && - newMessage.DXCall + band + newMessage.MO in g_liveCallsigns - ) - { - newMessage.DXGrid = g_liveCallsigns[ - newMessage.DXCall + band + newMessage.MO - ].grid.substr(0, 4); - } - - var report = ""; - - report += valueToAdiField( - "BAND", - Number(newMessage.Frequency / 1000000).formatBand() - ); - report += valueToAdiField("CALL", newMessage.DXCall.toUpperCase()); - report += valueToAdiField( - "FREQ", - Number(newMessage.Frequency / 1000000).toFixed(6) - ); - report += valueToAdiField("MODE", newMessage.MO.toUpperCase()); - var date = convertToDate(parseInt(newMessage.DateOn)); - var dataString = - date.getUTCFullYear() + - ("0" + (date.getUTCMonth() + 1)).slice(-2) + - ("0" + date.getUTCDate()).slice(-2); - report += valueToAdiField("QSO_DATE", dataString); - report += valueToAdiField("TIME_ON", HMSfromMilli(newMessage.TimeOn)); - - date = convertToDate(parseInt(newMessage.DateOff)); - dataString = - date.getUTCFullYear() + - ("0" + (date.getUTCMonth() + 1)).slice(-2) + - ("0" + date.getUTCDate()).slice(-2); - report += valueToAdiField("QSO_DATE_OFF", dataString); - report += valueToAdiField("TIME_OFF", HMSfromMilli(newMessage.TimeOff)); - - report += valueToAdiField("RST_RCVD", newMessage.ReportRecieved); - report += valueToAdiField("RST_SENT", newMessage.ReportSend); - report += valueToAdiField("TX_PWR", parseInt(newMessage.TXPower)); - report += valueToAdiField("GRIDSQUARE", newMessage.DXGrid); - - if (newMessage.Comments.length > 0) - { report += valueToAdiField("COMMENT", newMessage.Comments); } - - if (newMessage.Name.length > 0) - { report += valueToAdiField("NAME", newMessage.Name); } - - if (newMessage.Operatorcall.length > 0) - { - report += valueToAdiField("OPERATOR", newMessage.Operatorcall); - } - - if (newMessage.Mycall.length > 0) - { - report += valueToAdiField("STATION_CALLSIGN", newMessage.Mycall); - } - else if (myDEcall != "NOCALL" && myDEcall.length > 0) - { report += valueToAdiField("STATION_CALLSIGN", myDEcall); } - - if (newMessage.Mygrid.length > 0) - { - report += valueToAdiField("MY_GRIDSQUARE", newMessage.Mygrid); - } - else if (myDEGrid.length > 1) - { report += valueToAdiField("MY_GRIDSQUARE", myDEGrid); } - - report += ""; - - sendToLogger(report); -} - -var g_adifLookupMap = { - name: "NAME", - iota: "IOTA", - sota: "SOTA_REF", - continent: "CONT", - cqzone: "CQZ", - ituzone: "ITUZ", - email: "EMAIL", - county: "CNTY" -}; - -function sendToLogger(ADIF) -{ - let regex = new RegExp("", "i"); - let record = parseADIFRecord(ADIF.split(regex)[1]); - let localMode = record.MODE; - - if (localMode == "MFSK" && "SUBMODE" in record) - { - localMode = record.SUBMODE; - } - - if ( - (!("GRIDSQUARE" in record) || record.GRIDSQUARE.length == 0) && - record.CALL + record.BAND + localMode in g_liveCallsigns - ) - { - record.GRIDSQUARE = g_liveCallsigns[ - record.CALL + record.BAND + localMode - ].grid.substr(0, 4); - } - - if ("TX_PWR" in record) - { - record.TX_PWR = String(parseInt(record.TX_PWR)); - } - - if ( - (!("STATION_CALLSIGN" in record) || - record.STATION_CALLSIGN.length == 0) && - myDEcall != "NOCALL" && - myDEcall.length > 0 - ) - { - record.STATION_CALLSIGN = myDEcall; - } - - if ( - (!("MY_GRIDSQUARE" in record) || record.MY_GRIDSQUARE.length == 0) && - myDEGrid.length > 1 - ) - { - record.MY_GRIDSQUARE = myDEGrid; - } - - if (!("DXCC" in record)) - { - let dxcc = callsignToDxcc(record.CALL); - if (dxcc == -1) dxcc = 0; - record.DXCC = String(dxcc); - } - - // Tag: This is going to bite us in the butt later, but leaving it alone. - if (!("COUNTRY" in record) && Number(record.DXCC) > 0) - { - record.COUNTRY = g_dxccToADIFName[Number(record.DXCC)]; - } - - if (g_appSettings.lookupMerge == true) - { - let request = g_Idb - .transaction(["lookups"], "readwrite") - .objectStore("lookups") - .get(record.CALL); - - request.onsuccess = function (event) - { - if (request.result) - { - let lookup = request.result; - for (let key in lookup) - { - if (key in g_adifLookupMap) - { - record[g_adifLookupMap[key]] = lookup[key]; - } - } - if ("GRIDSQUARE" in record && "grid" in lookup) - { - if ( - record.GRIDSQUARE.substr(0, 4) == lookup.grid.substr(0, 4) - ) - { - record.GRIDSQUARE = lookup.grid; - } - } - if ( - g_appSettings.lookupMissingGrid && - "grid" in lookup && - (!("GRIDSQUARE" in record) || record.GRIDSQUARE.length == 0) - ) - { - record.GRIDSQUARE = lookup.grid; - } - } - finishSendingReport(record, localMode); - }; - - request.onerror = function (event) - { - finishSendingReport(record, localMode); - }; - } - else - { - finishSendingReport(record, localMode); - } -} - -function finishSendingReport(record, localMode) -{ - let report = ""; - - let reportHash = record.CALL + record.MODE + localMode; - - for (let key in record) - { - report += "<" + key + ":" + record[key].length + ">" + record[key] + " "; - } - report += ""; - - if (reportHash != lastReportHash) - { - lastReportHash = reportHash; - - if ( - g_N1MMSettings.enable == true && - g_N1MMSettings.port > 1024 && - g_N1MMSettings.ip.length > 4 - ) - { - sendUdpMessage( - report, - report.length, - parseInt(g_N1MMSettings.port), - g_N1MMSettings.ip - ); - addLastTraffic("Logged to N1MM"); - } - - if ( - g_log4OMSettings.enable == true && - g_log4OMSettings.port > 1024 && - g_log4OMSettings.ip.length > 4 - ) - { - sendUdpMessage( - "ADD " + report, - report.length + 4, - parseInt(g_log4OMSettings.port), - g_log4OMSettings.ip - ); - addLastTraffic("Logged to Log4OM"); - } - - try - { - onAdiLoadComplete("GT" + report); - } - catch (e) - { - addLastTraffic("Exception Internal Log"); - } - try - { - // Log worthy - if (logGTqsoCheckBox.checked == true) - { - var fs = require("fs"); - fs.appendFileSync(g_qsoLogFile, report + "\r\n"); - addLastTraffic( - "Logged to GridTracker backup" - ); - } - } - catch (e) - { - addLastTraffic( - "Exception GridTracker backup" - ); - } - - try - { - sendQrzLogEntry(report); - } - catch (e) - { - addLastTraffic("Exception QRZ Log"); - } - - try - { - sendClubLogEntry(report); - } - catch (e) - { - addLastTraffic("Exception ClubLog Log"); - } - - try - { - sendHrdLogEntry(report); - } - catch (e) - { - addLastTraffic("Exception HrdLog.net Log"); - } - - try - { - sendCloudlogEntry(report); - } - catch (e) - { - addLastTraffic("Exception Cloudlog Log"); - } - - if ( - g_acLogSettings.enable == true && - g_acLogSettings.port > 0 && - g_acLogSettings.ip.length > 4 - ) - { - try - { - sendACLogMessage(record, g_acLogSettings.port, g_acLogSettings.ip); - addLastTraffic("Logged to N3FJP"); - } - catch (e) - { - addLastTraffic("Exception N3FJP Log"); - } - } - - if ( - g_dxkLogSettings.enable == true && - g_dxkLogSettings.port > 0 && - g_dxkLogSettings.ip.length > 4 - ) - { - try - { - sendDXKeeperLogMessage( - report, - g_dxkLogSettings.port, - g_dxkLogSettings.ip - ); - addLastTraffic("Logged to DXKeeper"); - } - catch (e) - { - addLastTraffic("Exception DXKeeper Log"); - } - } - - if ( - g_HRDLogbookLogSettings.enable == true && - g_HRDLogbookLogSettings.port > 0 && - g_HRDLogbookLogSettings.ip.length > 4 - ) - { - try - { - sendHRDLogbookEntry( - record, - g_HRDLogbookLogSettings.port, - g_HRDLogbookLogSettings.ip - ); - addLastTraffic( - "Logged to HRD Logbook" - ); - } - catch (e) - { - addLastTraffic("Exception HRD Log"); - } - } - - try - { - sendLotwLogEntry(report); - } - catch (e) - { - addLastTraffic("Exception LoTW Log"); - } - - if ( - logeQSLQSOCheckBox.checked == true && - nicknameeQSLCheckBox.checked == true && - eQSLNickname.value.trim().length > 0 - ) - { - record.APP_EQSL_QTH_NICKNAME = eQSLNickname.value.trim(); - report = ""; - for (var key in record) - { - report += - "<" + key + ":" + record[key].length + ">" + record[key] + " "; - } - report += ""; - } - - try - { - sendeQSLEntry(report); - } - catch (e) - { - addLastTraffic("Exception LoTW Log"); - } - - try - { - alertLogMessage(); - } - catch (e) - { - addLastTraffic("Exception Alert Log"); - } - - if (lookupCloseLog.checked == true) - { - try - { - openLookupWindow(false); - } - catch (e) - { - addLastTraffic("Exception Hide Lookup"); - } - } - } - - return report; -} - -function alertLogMessage() -{ - if (logEventMedia.value != "none") - { - playAlertMediaFile(logEventMedia.value); - } -} - -function eqslCallback(buffer, flag) -{ - var result = String(buffer); - if (flag) - { - if (result.indexOf("No such Username/Password found") != -1) - { - eQSLTestResult.innerHTML = "Bad
Password
or
Nickname"; - logeQSLQSOCheckBox.checked = false; - adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); - } - else if (result.indexOf("No such Callsign found") != -1) - { - eQSLTestResult.innerHTML = "Unknown
Callsign"; - logeQSLQSOCheckBox.checked = false; - adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); - } - else if (result.indexOf("Your ADIF log file has been built") > -1 || result.indexOf("You have no log entries") > -1) - { - eQSLTestResult.innerHTML = "Passed"; - } - else if (result.indexOf("specify the desired User by using the QTHNickname") != -1) - { - eQSLTestResult.innerHTML = "QTH Nickname
Needed"; - } - else - { - eQSLTestResult.innerHTML = "Unknown
Error"; - logeQSLQSOCheckBox.checked = false; - adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); - } - } - else - { - if (result.indexOf("Error: No match on eQSL_User/eQSL_Pswd") != -1) - { - addLastTraffic( - "Fail log eQSL.cc (credentials)" - ); - } - if ( - result.indexOf("specify the desired User by using the QTHNickname") != -1 - ) - { - addLastTraffic( - "Fail log eQSL.cc (nickname)" - ); - } - else if (result.indexOf("Result: 0 out of 1 records") != -1) - { - addLastTraffic("Fail log eQSL.cc (dupe)"); - } - else if (result.indexOf("Result: 1 out of 1 records added") != -1) - { - addLastTraffic("Logged to eQSL.cc"); - } - else - { - addLastTraffic("Fail log eQSL.cc (?)"); - } - } -} - -function eQSLTest(test) -{ - if (g_mapSettings.offlineMode == true) return; - - eQSLTestResult.innerHTML = "Testing"; - - var fUrl = - "https://www.eQSL.cc/qslcard/DownloadInBox.cfm?UserName=" + - encodeURIComponent(eQSLUser.value) + - "&Password=" + - encodeURIComponent(eQSLPassword.value) + - "&RcvdSince=2020101"; - - if (nicknameeQSLCheckBox.checked == true) - { fUrl += "&QTHNickname=" + encodeURIComponent(eQSLNickname.value); } - getABuffer(fUrl, eqslCallback, true, "https", 443); -} - -function sendeQSLEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logeQSLQSOCheckBox.checked == true) - { - var pid = "GridTracker"; - var pver = String(gtVersion); - var header = "" + pid + "\r\n"; - header += "" + pver + "\r\n"; - header += "\r\n"; - var eReport = encodeURIComponent(header + report); - var fUrl = - "https://www.eQSL.cc/qslcard/importADIF.cfm?ADIFData=" + - eReport + - "&EQSL_USER=" + - encodeURIComponent(eQSLUser.value) + - "&EQSL_PSWD=" + - encodeURIComponent(eQSLPassword.value); - getABuffer(fUrl, eqslCallback, false, "https", 443); - } -} - -function testTrustedQSL(test) -{ - if (g_mapSettings.offlineMode == true) - { - lotwTestResult.innerHTML = "Currently
offline"; - return; - } - - if ( - logLOTWqsoCheckBox.checked == true && - g_trustedQslSettings.binaryFileValid == true && - g_trustedQslSettings.stationFileValid == true && - lotwStation.value.length > 0 - ) - { - lotwTestResult.innerHTML = "Testing Upload"; - - var child_process = require("child_process"); - var options = Array(); - options.push("-q"); - options.push("-v"); - - child_process.execFile( - g_trustedQslSettings.binaryFile, - options, - (error, stdout, stderr) => - { - if (error) - { - lotwTestResult.innerHTML = "Error encountered"; - } - lotwTestResult.innerHTML = stderr; - } - ); - } - else - { - var worker = ""; - if (g_trustedQslSettings.binaryFileValid == false) - { worker += "Invalid tqsl executable
"; } - if (g_trustedQslSettings.stationFileValid == false) - { worker += "TrustQSL not installed
"; } - if (!ValidateText(lotwTrusted)) worker += "TQSL Password missing
"; - if (!ValidateText(lotwStation)) worker += "Select Station
"; - lotwTestResult.innerHTML = worker; - } -} -var g_trustTempPath = ""; - -function sendLotwLogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if ( - logLOTWqsoCheckBox.checked == true && - g_trustedQslSettings.binaryFileValid == true && - g_trustedQslSettings.stationFileValid == true && - lotwStation.value.length > 0 - ) - { - var header = - "Generated " + userTimeString(null) + " for " + myDEcall + "\r\n\r\n"; - var pid = "GridTracker"; - var pver = String(gtVersion); - header += "" + pid + "\r\n"; - header += "" + pver + "\r\n"; - header += "\r\n"; - var finalLog = header + report + "\r\n"; - - g_trustTempPath = os.tmpdir() + g_dirSeperator + unique(report) + ".adif"; - fs.writeFileSync(g_trustTempPath, finalLog); - - var child_process = require("child_process"); - var options = Array(); - options.push("-a"); - options.push("all"); - options.push("-l"); - options.push(lotwStation.value); - if (lotwTrusted.value.length > 0) - { - options.push("-p"); - options.push(lotwTrusted.value); - } - options.push("-q"); - options.push("-x"); - options.push("-d"); - options.push("-u"); - options.push(g_trustTempPath); - - child_process.execFile( - g_trustedQslSettings.binaryFile, - options, - (error, stdout, stderr) => // eslint-disable-line node/handle-callback-err - { - if (stderr.indexOf("Final Status: Success") < 0) - { - alert(stderr); - addLastTraffic("Fail log to TQSL"); - } - else - { - addLastTraffic("Logged to TQSL"); - } - fs.unlinkSync(g_trustTempPath); - } - ); - } -} - -function n1mmLoggerChanged() -{ - g_N1MMSettings.enable = buttonN1MMCheckBox.checked; - g_N1MMSettings.ip = N1MMIpInput.value; - g_N1MMSettings.port = N1MMPortInput.value; - - localStorage.N1MMSettings = JSON.stringify(g_N1MMSettings); -} - -function log4OMLoggerChanged() -{ - g_log4OMSettings.enable = buttonLog4OMCheckBox.checked; - g_log4OMSettings.ip = log4OMIpInput.value; - g_log4OMSettings.port = log4OMPortInput.value; - - localStorage.log4OMSettings = JSON.stringify(g_log4OMSettings); -} - -function acLogLoggerChanged() -{ - g_acLogSettings.enable = buttonacLogCheckBox.checked; - g_acLogSettings.ip = acLogIpInput.value; - g_acLogSettings.port = acLogPortInput.value; - - localStorage.acLogSettings = JSON.stringify(g_acLogSettings); -} - -function dxkLogLoggerChanged() -{ - g_dxkLogSettings.enable = buttondxkLogCheckBox.checked; - g_dxkLogSettings.ip = dxkLogIpInput.value; - g_dxkLogSettings.port = dxkLogPortInput.value; - - localStorage.dxkLogSettings = JSON.stringify(g_dxkLogSettings); -} - -function hrdLogbookLoggerChanged() -{ - g_HRDLogbookLogSettings.enable = buttonHrdLogbookCheckBox.checked; - g_HRDLogbookLogSettings.ip = hrdLogbookIpInput.value; - g_HRDLogbookLogSettings.port = hrdLogbookPortInput.value; - - localStorage.HRDLogbookLogSettings = JSON.stringify(g_HRDLogbookLogSettings); -} - -function CloudUrlErrorCallback( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - timeoutCallback, - message -) -{ - CloudlogTestResult.innerHTML = message; -} - -function CloudlogSendLogResult(buffer, flag) -{ - if (flag && flag == true) - { - if (buffer) - { - if (buffer.indexOf("missing api key") > -1) - { - CloudlogTestResult.innerHTML = "API Key Invalid"; - } - else if (buffer.indexOf("created") > -1) - { - CloudlogTestResult.innerHTML = "Passed"; - } - else - { - CloudlogTestResult.innerHTML = "Invalid Response"; - } - } - else - { - CloudlogTestResult.innerHTML = "Invalid Response"; - } - } - else - { - if (buffer && buffer.indexOf("created") > -1) - { addLastTraffic("Logged to Cloudlog"); } - else addLastTraffic("Fail log to Cloudlog"); - } -} - -function qrzSendLogResult(buffer, flag) -{ - if (typeof buffer != "undefined" && buffer != null) - { - var data = String(buffer); - var kv = data.split("&"); - if (kv.length > 0) - { - var arrData = Object(); - for (var x in kv) - { - var split = kv[x].split("="); - arrData[split[0]] = split[1]; - } - if ( - typeof arrData.RESULT == "undefined" || - arrData.RESULT != "OK" - ) - { - alert( - "Error uploading QSO to QRZ.com (" + - (arrData.REASON || "Unknown error") + - ")" - ); - addLastTraffic("Fail log to QRZ.com"); - } - else - { addLastTraffic("Logged to QRZ.com"); } - } - } - else alert("Error uploading QSO to QRZ.com (No response)"); -} - -function postDialogRetryCallback( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - timeoutCallback, - who -) -{ - if (window.confirm("Error sending QSO to " + who + ", retry?")) - { - getPostBuffer( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - postDialogRetryCallback, - who - ); - } -} - -function postRetryErrorCallaback( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - timeoutCallback, - who -) -{ - getPostBuffer( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - postDialogRetryCallback, - who - ); -} - -function sendQrzLogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logQRZqsoCheckBox.checked == true && ValidateQrzApi(qrzApiKey)) - { - if (typeof nw != "undefined") - { - var postData = { - KEY: qrzApiKey.value, - ACTION: "INSERT", - ADIF: report - }; - getPostBuffer( - "https://logbook.qrz.com/api", - qrzSendLogResult, - null, - "https", - 443, - postData, - 30000, - postRetryErrorCallaback, - "QRZ.com" - ); - } - } -} - -function clubLogQsoResult(buffer, flag) -{ - addLastTraffic("Logged to ClubLog.org"); -} - -function sendClubLogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logClubqsoCheckBox.checked == true) - { - if (typeof nw != "undefined") - { - var postData = { - email: clubEmail.value, - password: clubPassword.value, - callsign: clubCall.value, - adif: report, - api: CLk - }; - - getPostBuffer( - "https://clublog.org/realtime.php", - clubLogQsoResult, - null, - "https", - 443, - postData, - 30000, - postRetryErrorCallaback, - "ClubLog.org" - ); - } - } -} - -function sendCloudlogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logCloudlogQSOCheckBox.checked == true) - { - if (typeof nw != "undefined") - { - var postData = { key: CloudlogAPI.value, type: "adif", string: report }; - getPostJSONBuffer( - CloudlogURL.value, - CloudlogSendLogResult, - null, - "https", - 80, - postData, - 10000, - CloudUrlErrorCallback, - "Failed to Send" - ); - } - } -} - -function hrdSendLogResult(buffer, flag) -{ - if (flag && flag == true) - { - if (buffer.indexOf("Unknown user") > -1) - { - HRDLogTestResult.innerHTML = "Failed"; - logHRDLOGqsoCheckBox.checked = false; - adifLogQsoCheckBoxChanged(logHRDLOGqsoCheckBox); - } - else HRDLogTestResult.innerHTML = "Passed"; - } - else - { - if (buffer.indexOf("Unknown user") == -1) - { addLastTraffic("Logged to HRDLOG.net"); } - else - { addLastTraffic("Fail log to HRDLOG.net"); } - } -} - -function sendHrdLogEntry(report) -{ - if (g_mapSettings.offlineMode == true) return; - - if (logHRDLOGqsoCheckBox.checked == true) - { - if (typeof nw != "undefined") - { - var postData = { - Callsign: HRDLOGCallsign.value, - Code: HRDLOGUploadCode.value, - App: "GridTracker " + gtVersion, - ADIFData: report - }; - getPostBuffer( - "https://www.hrdlog.net/NewEntry.aspx", - hrdSendLogResult, - null, - "https", - 443, - postData, - 30000, - postRetryErrorCallaback, - "HRDLog.net" - ); - } - } -} - -function hrdCredentialTest(test) -{ - if (test && test == true) - { - HRDLogTestResult.innerHTML = "Testing"; - - if (typeof nw != "undefined") - { - var postData = { - Callsign: HRDLOGCallsign.value, - Code: HRDLOGUploadCode.value - }; - getPostBuffer( - "https://www.hrdlog.net/NewEntry.aspx", - hrdSendLogResult, - test, - "https", - 443, - postData - ); - } - } -} - -function ClublogTest(test) -{ - if (test && test == true) - { - CloudlogTestResult.innerHTML = "Testing"; - - if (typeof nw != "undefined") - { - var postData = { key: CloudlogAPI.value, type: "adif", string: "" }; - getPostJSONBuffer( - CloudlogURL.value, - CloudlogSendLogResult, - test, - "https", - 80, - postData, - 10000, - CloudUrlErrorCallback, - "No Response
or
Timeout" - ); - } - } -} - -function getPostJSONBuffer( - file_url, - callback, - flag, - mode, - port, - theData, - timeoutMs, - timeoutCallback, - who -) -{ - try - { - var postData = JSON.stringify(theData); - var url = require("url"); - var protocol = url.parse(file_url).protocol; // eslint-disable-line node/no-deprecated-api - var http = require(protocol.replace(":", "")); - var fileBuffer = null; - var options = { - host: url.parse(file_url).hostname, // eslint-disable-line node/no-deprecated-api - port: url.parse(file_url).port, // eslint-disable-line node/no-deprecated-api - path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api - method: "post", - headers: { - "Content-Type": "application/json", - "Content-Length": postData.length - } - }; - var req = http.request(options, function (res) - { - var fsize = res.headers["content-length"]; - var cookies = null; - if (typeof res.headers["set-cookie"] != "undefined") - { cookies = res.headers["set-cookie"]; } - res - .on("data", function (data) - { - if (fileBuffer == null) fileBuffer = data; - else fileBuffer += data; - }) - .on("end", function () - { - if (typeof callback === "function") - { - // Call it, since we have confirmed it is callable - callback(fileBuffer, flag, cookies); - } - }) - .on("error", function () {}); - }); - if (typeof timeoutMs == "number" && timeoutMs > 0) - { - req.on("socket", function (socket) - { - socket.setTimeout(timeoutMs); - socket.on("timeout", function () - { - req.abort(); - }); - }); - req.on("error", function (err) // eslint-disable-line node/handle-callback-err - { - if (typeof timeoutCallback != "undefined") - { - timeoutCallback( - file_url, - callback, - flag, - mode, - 80, - theData, - timeoutMs, - timeoutCallback, - who - ); - } - }); - } - req.write(postData); - req.end(); - } - catch (e) - { - if (typeof timeoutCallback != "undefined") - { - timeoutCallback( - file_url, - callback, - flag, - mode, - 80, - theData, - timeoutMs, - timeoutCallback, - "Invalid Url" - ); - } - } -} - -function valueToXmlField(field, value) -{ - var adi = "<" + field + ">"; - adi += String(value); - adi += ""; - return adi; -} - -function aclUpdateControlValue(control, value) -{ - return ( - valueToXmlField( - "CMD", - "" + - valueToXmlField("CONTROL", control) + - valueToXmlField("VALUE", value) - ) + "\r\n" - ); -} - -function aclAction(action) -{ - return ( - valueToXmlField("CMD", "" + valueToXmlField("VALUE", action)) + - "\r\n" - ); -} - -function adifField(record, key) -{ - if (key in record) return record[key]; - else return ""; -} -function sendACLogMessage(record, port, address) -{ - var report = ""; - - report += aclAction("CLEAR"); - report += aclUpdateControlValue("TXTENTRYBAND", adifField(record, "BAND")); - report += aclUpdateControlValue("TXTENTRYCALL", adifField(record, "CALL")); - report += aclAction("CALLTAB"); - report += aclUpdateControlValue( - "TXTENTRYFREQUENCY", - adifField(record, "FREQ") - ); - if (adifField(record, "SUBMODE").length > 0) - { - report += aclUpdateControlValue( - "TXTENTRYMODE", - adifField(record, "SUBMODE") - ); - } - else - { report += aclUpdateControlValue("TXTENTRYMODE", adifField(record, "MODE")); } - - var date = adifField(record, "QSO_DATE"); - var dataString = - date.substr(0, 4) + "/" + date.substr(4, 2) + "/" + date.substr(6); - - report += aclUpdateControlValue("TXTENTRYDATE", dataString); - - var timeVal = adifField(record, "TIME_ON"); - var whenString = - timeVal.substr(0, 2) + - ":" + - timeVal.substr(2, 2) + - ":" + - timeVal.substr(4, 2); - report += aclUpdateControlValue("TXTENTRYTIMEON", whenString); - - timeVal = adifField(record, "TIME_OFF"); - whenString = - timeVal.substr(0, 2) + - ":" + - timeVal.substr(2, 2) + - ":" + - timeVal.substr(4, 2); - report += aclUpdateControlValue("TXTENTRYTIMEOFF", whenString); - - report += aclUpdateControlValue( - "TXTENTRYRSTR", - adifField(record, "RST_RCVD") - ); - report += aclUpdateControlValue( - "TXTENTRYRSTS", - adifField(record, "RST_SENT") - ); - report += aclUpdateControlValue("TXTENTRYPOWER", adifField(record, "TX_PWR")); - report += aclUpdateControlValue( - "TXTENTRYGRID", - adifField(record, "GRIDSQUARE") - ); - report += aclUpdateControlValue( - "TXTENTRYCOMMENTS", - adifField(record, "COMMENT") - ); - report += aclUpdateControlValue("TXTENTRYNAMER", adifField(record, "NAME")); - report += aclUpdateControlValue("TXTENTRYIOTA", adifField(record, "IOTA")); - report += aclUpdateControlValue( - "TXTENTRYCONTINENT", - adifField(record, "CONT") - ); - report += aclUpdateControlValue("TXTENTRYITUZ", adifField(record, "ITUZ")); - report += aclUpdateControlValue("TXTENTRYCQZONE", adifField(record, "CQZ")); - report += aclUpdateControlValue("TXTENTRYCOUNTYR", adifField(record, "CNTY")); - - var sentSpcNum = false; - if (adifField(record, "SRX").length > 0) - { - report += aclUpdateControlValue( - "TXTENTRYSERIALNOR", - adifField(record, "SRX") - ); - } - else if (adifField(record, "CONTEST_ID").length > 0) - { - report += aclUpdateControlValue( - "TXTENTRYSPCNUM", - adifField(record, "SRX_STRING") - ); - sentSpcNum = true; - report += aclUpdateControlValue( - "TXTENTRYCLASS", - adifField(record, "CLASS") - ); - report += aclUpdateControlValue( - "TXTENTRYSECTION", - adifField(record, "ARRL_SECT") - ); - } - - if (adifField(record, "STATE").length > 0) - { - report += aclUpdateControlValue( - "TXTENTRYSTATE", - adifField(record, "STATE") - ); - if (sentSpcNum == false) - { - report += aclUpdateControlValue( - "TXTENTRYSPCNUM", - adifField(record, "STATE") - ); - } - } - - report += aclAction("ENTER"); - - sendTcpMessage(report, report.length, port, address); -} - -function sendDXKeeperLogMessage(newMessage, port, address) -{ - var report = ""; - - report += valueToAdiField("command", "log"); - report += valueToAdiField("parameters", newMessage); - report += "\r\n"; - - sendTcpMessage(report, report.length, Number(port) + 1, address); -} - -function parseADIFRecord(adif) -{ - var regex = new RegExp("", "i"); - var newLine = adif.split(regex); - var line = newLine[0].trim(); // Catch the naughty case of someone sending two records at the same time - var record = {}; - - // because strings are not escaped for adif.. ie: :'s and <'s .. we have to walk from left to right - // cheesy, but damn i'm tired of parsing things - var x = 0; - while (line.length > 0) - { - while (line.charAt(0) != "<" && line.length > 0) - { - line = line.substr(1); - } - if (line.length > 0) - { - line = line.substr(1); - var where = line.indexOf(":"); - if (where != -1) - { - var fieldName = line.substr(0, where).toUpperCase(); - line = line.substr(fieldName.length + 1); - var fieldLength = parseInt(line); - var end = line.indexOf(">"); - if (end > 0) - { - line = line.substr(end + 1); - var fieldValue = line.substr(0, fieldLength); - line = line.substr(fieldLength); - record[fieldName] = fieldValue; - } - } - } - } - - return record; -} - -function sendHRDLogbookEntry(report, port, address) -{ - var command = "ver\rdb add {"; - var items = Object.assign({}, report); - - items.FREQ = items.FREQ.split(".").join(""); - - for (var item in items) - { - command += item + "=\"" + items[item] + "\" "; - } - - command += "}\rexit\r"; - - sendTcpMessage(command, command.length, Number(port), address); -} +// GridTracker Copyright © 2021 GridTracker.org +// All rights reserved. +// See LICENSE for more information. + +var selectStartupLink = null; + +function dragOverHandler(ev) +{ + // Prevent default behavior (Prevent file from being opened) + ev.preventDefault(); +} + +function dropHandler(ev) +{ + // Prevent default behavior (Prevent file from being opened) + ev.preventDefault(); + if (ev.dataTransfer.items) + { + // Use DataTransferItemList interface to access the file(s) + for (var i = 0; i < ev.dataTransfer.items.length; i++) + { + // If dropped items aren't files, reject them + Entry = ev.dataTransfer.items[i].webkitGetAsEntry(); + if (Entry && typeof Entry.isFile != "undefined" && Entry.isFile == true) + { + var filename = ev.dataTransfer.items[i].getAsFile().path; + var test = filename.toLowerCase(); + var valid = test.endsWith(".adi") + ? true + : test.endsWith(".adif") + ? true + : test.endsWith(".log") + ? true + : !!test.endsWith(".txt"); + if (valid && fs.existsSync(filename)) + { + onAdiLoadComplete(fs.readFileSync(filename, "UTF-8"), false); + } + } + } + } +} + +function findAdiField(row, field) +{ + var value = ""; + var regex = new RegExp("<" + field + ":", "i"); + var firstSplitArray = row.split(regex); + if (firstSplitArray && firstSplitArray.length == 2) + { + var secondSplitArray = firstSplitArray[1].split(">"); + if (secondSplitArray.length > 1) + { + var newLenSearch = secondSplitArray[0].split(":"); + var newLen = newLenSearch[0]; + value = secondSplitArray[1].slice(0, newLen); + } + } + return value; +} + +function onAdiLoadComplete(adiBuffer, saveAdifFile, adifFileName, newFile) +{ + let rawAdiBuffer = ""; + if (typeof adiBuffer == "object") rawAdiBuffer = String(adiBuffer); + else rawAdiBuffer = adiBuffer; + + let activeAdifArray = Array(); + let activeAdifLogMode = true; + let eQSLfile = false; + + if (rawAdiBuffer.indexOf("PSKReporter") > -1) activeAdifLogMode = false; + + if (rawAdiBuffer.indexOf("Received eQSLs") > -1) eQSLfile = true; + + if (rawAdiBuffer.length > 1) + { + let regex = new RegExp("", "i"); + activeAdifArray = rawAdiBuffer.split(regex); + } + + let dateTime = new Date(); + let dupes = 0; + + for (let x = 0; x < activeAdifArray.length; x++) + { + let finalMode = ""; + + if (activeAdifArray[x].length > 3) + { + if (activeAdifLogMode) + { + let confirmed = false; + let finalGrid = findAdiField( + activeAdifArray[x], + "GRIDSQUARE" + ).toUpperCase(); + let vuccGrids = findAdiField( + activeAdifArray[x], + "VUCC_GRIDS" + ).toUpperCase(); + let finalVucc = []; + let finalDXcall = findAdiField(activeAdifArray[x], "CALL").replace( + "_", + "/" + ); + let finalDEcall = findAdiField( + activeAdifArray[x], + "STATION_CALLSIGN" + ).replace("_", "/"); + + if (finalDEcall == "") finalDEcall = myDEcall; + if ( + g_appSettings.workingCallsignEnable && + !(finalDEcall in g_appSettings.workingCallsigns) + ) + { continue; } + let finalRSTsent = findAdiField(activeAdifArray[x], "RST_SENT"); + let finalRSTrecv = findAdiField(activeAdifArray[x], "RST_RCVD"); + let finalBand = findAdiField(activeAdifArray[x], "BAND").toLowerCase(); + let dateVal = findAdiField(activeAdifArray[x], "QSO_DATE"); + let timeVal = findAdiField(activeAdifArray[x], "TIME_ON"); + let finalState = findAdiField( + activeAdifArray[x], + "STATE" + ).toUpperCase(); + if (finalState.length == 0) finalState = null; + let finalPropMode = findAdiField( + activeAdifArray[x], + "PROP_MODE" + ).toUpperCase(); + let finalSatName = findAdiField( + activeAdifArray[x], + "SAT_NAME" + ).toUpperCase(); + let finalCont = findAdiField(activeAdifArray[x], "CONT").toUpperCase(); + if (finalCont.length == 0) finalCont = null; + let finalCnty = findAdiField(activeAdifArray[x], "CNTY").toUpperCase(); + if (finalCnty.length == 0) finalCnty = null; + else + { + finalCnty = finalCnty.replaceAll(" ", ""); + } + let finalMode = findAdiField(activeAdifArray[x], "MODE").toUpperCase(); + let subMode = findAdiField(activeAdifArray[x], "SUBMODE"); + if (subMode == "FT4" && (finalMode == "MFSK" || finalMode == "DATA")) + { finalMode = "FT4"; } + if (subMode == "JS8" && finalMode == "MFSK") finalMode = "JS8"; + + if (finalBand == "oob" || finalBand == "") + { + finalBand = Number( + findAdiField(activeAdifArray[x], "FREQ") + ).formatBand(); + } + + let finalMsg = findAdiField(activeAdifArray[x], "COMMENT"); + let finalQslMsg = findAdiField(activeAdifArray[x], "QSLMSG"); + let finalQslMsgIntl = findAdiField(activeAdifArray[x], "QSLMSG_INTL"); + if (finalQslMsg.length > 1) finalMsg = finalQslMsg; + if (finalQslMsgIntl.length > 1 && finalMsg == "") + { finalMsg = finalQslMsgIntl; } + + let finalDxcc = Number(findAdiField(activeAdifArray[x], "DXCC")); + if (finalDxcc == 0) finalDxcc = Number(callsignToDxcc(finalDXcall)); + + if (!(finalDxcc in g_dxccToGeoData)) + { finalDxcc = Number(callsignToDxcc(finalDXcall)); } + + // If my callsign isn't present, it must be for me anyway + + let finalCqZone = findAdiField(activeAdifArray[x], "CQZ"); + if (finalCqZone.length == 1) finalCqZone = "0" + finalCqZone; + + if (parseInt(finalCqZone) < 1 || parseInt(finalCqZone) > 40) + { finalCqZone = ""; } + finalCqZone = String(finalCqZone); + let finalItuZone = findAdiField(activeAdifArray[x], "ITUZ"); + if (finalItuZone.length == 1) finalItuZone = "0" + finalItuZone; + + if (parseInt(finalItuZone) < 1 || parseInt(finalItuZone) > 90) + { finalItuZone = ""; } + finalItuZone = String(finalItuZone); + + let finalIOTA = findAdiField(activeAdifArray[x], "IOTA").toUpperCase(); + + let qrzConfirmed = findAdiField( + activeAdifArray[x], + "APP_QRZLOG_STATUS" + ).toUpperCase(); + let lotwConfirmed1 = findAdiField( + activeAdifArray[x], + "QSL_RCVD" + ).toUpperCase(); + let lotw_qsl_rcvd = findAdiField( + activeAdifArray[x], + "LOTW_QSL_RCVD" + ).toUpperCase(); + let eqsl_qsl_rcvd = findAdiField( + activeAdifArray[x], + "EQSL_QSL_RCVD" + ).toUpperCase(); + + if ( + qrzConfirmed == "C" || + lotw_qsl_rcvd == "Y" || + lotw_qsl_rcvd == "V" || + lotwConfirmed1 == "Y" || + eqsl_qsl_rcvd == "Y" || + eqsl_qsl_rcvd == "V" || + eQSLfile == true + ) + { confirmed = true; } + + let dateTime = new Date( + Date.UTC( + dateVal.substr(0, 4), + parseInt(dateVal.substr(4, 2)) - 1, + dateVal.substr(6, 2), + timeVal.substr(0, 2), + timeVal.substr(2, 2), + timeVal.substr(4, 2) + ) + ); + + let finalTime = parseInt(dateTime.getTime() / 1000); + + if ( + g_appSettings.workingDateEnable && + finalTime < g_appSettings.workingDate + ) + { continue; } + + finalGrid = finalGrid.substr(0, 6); + if (!validateGridFromString(finalGrid)) finalGrid = ""; + if (finalGrid == "" && vuccGrids != "") + { + finalVucc = vuccGrids.split(","); + finalGrid = finalVucc[0]; + finalVucc.shift(); + } + let isDigital = false; + let isPhone = false; + if (finalMode in g_modes) + { + isDigital = g_modes[finalMode]; + } + if (finalMode in g_modes_phone) + { + isPhone = g_modes_phone[finalMode]; + } + if (finalDXcall != "") + { + addDeDx( + finalGrid, + finalDXcall, + false, + false, + false, + finalDEcall, + finalRSTsent, + finalTime, + finalMsg, + finalMode, + finalBand, + confirmed, + false, + finalRSTrecv, + finalDxcc, + finalState, + finalCont, + finalCnty, + finalCqZone, + finalItuZone, + finalVucc, + finalPropMode, + isDigital, + isPhone, + finalIOTA, + finalSatName + ); + } + } + else + { + let finalMyGrid = findAdiField( + activeAdifArray[x], + "MY_GRIDSQUARE" + ).toUpperCase(); + let finalGrid = findAdiField( + activeAdifArray[x], + "GRIDSQUARE" + ).toUpperCase(); + let finalDXcall = findAdiField(activeAdifArray[x], "CALL"); + let finalDEcall = findAdiField(activeAdifArray[x], "OPERATOR"); + let finalRSTsent = findAdiField(activeAdifArray[x], "APP_PSKREP_SNR"); + let dateVal = findAdiField(activeAdifArray[x], "QSO_DATE"); + let timeVal = findAdiField(activeAdifArray[x], "TIME_ON"); + let finalMode = findAdiField(activeAdifArray[x], "MODE"); + let finalBand = Number( + findAdiField(activeAdifArray[x], "FREQ") + ).formatBand(); + let finalMsg = "-"; + let finalDxcc = Number(findAdiField(activeAdifArray[x], "DXCC")); + if (finalDxcc == 0) + { + if (finalDXcall == myDEcall) finalDxcc = callsignToDxcc(finalDEcall); + else finalDxcc = callsignToDxcc(finalDXcall); + } + + finalGrid = finalGrid.substr(0, 6); + + let dateTime = new Date( + Date.UTC( + dateVal.substr(0, 4), + parseInt(dateVal.substr(4, 2)) - 1, + dateVal.substr(6, 2), + timeVal.substr(0, 2), + timeVal.substr(2, 2), + timeVal.substr(4, 2) + ) + ); + let finalTime = parseInt(dateTime.getTime() / 1000); + if ( + finalGrid != "" && + finalDXcall != "" && + validateGridFromString(finalGrid) + ) + { + if (finalDXcall == myDEcall) + { + addDeDx( + finalMyGrid, + finalDEcall, + false, + false, + false, + finalDXcall, + null, + finalTime, + finalMsg, + finalMode, + finalBand, + false, + true, + finalRSTsent, + finalDxcc, + null, + null, + null, + null, + null + ); + } + else if (finalDEcall == myDEcall) + { + addDeDx( + finalGrid, + finalDXcall, + false, + false, + false, + "-", + finalRSTsent, + finalTime, + finalMsg, + finalMode, + finalBand, + false, + true, + null, + finalDxcc, + null, + null, + null, + null, + null + ); + } + else + { + addDeDx( + finalGrid, + finalDXcall, + false, + false, + false, + finalDEcall, + finalRSTsent, + finalTime, + finalMsg, + finalMode, + finalBand, + false, + true, + null, + finalDxcc, + null, + null, + null, + null, + null + ); + } + } + } + } + } + + redrawGrids(); + updateCountStats(); + updateLogbook(); + + if (g_fromDirectCallNoFileDialog == false) + { + fileSelector.setAttribute("type", ""); + fileSelector.setAttribute("type", "file"); + fileSelector.setAttribute("accept", ".adi,"); + fileSelector.value = null; + } + g_fromDirectCallNoFileDialog = false; + + updateRosterWorked(); + goProcessRoster(); +} + +function clubLogCallback(buffer, flag, cookie) +{ + var rawAdiBuffer = String(buffer); + if (rawAdiBuffer.indexOf("Invalid login") > -1) + { + if (flag) clubTestResult.innerHTML = "Invalid"; + } + else if (buffer == null) + { + if (flag) clubTestResult.innerHTML = "Unknown Error"; + } + else + { + if (flag) clubTestResult.innerHTML = "Passed"; + else + { + g_fromDirectCallNoFileDialog = true; + + rawAdiBuffer = cleanAndPrepADIF("clublog.adif", rawAdiBuffer); + + tryToWriteAdifToDocFolder("clublog.adif", rawAdiBuffer); + + onAdiLoadComplete(rawAdiBuffer, true, "clublog.adif", true); + } + } +} + +var g_isGettingClub = false; +function grabClubLog(test) +{ + if (g_isGettingClub == false) + { + if (test) clubTestResult.innerHTML = "Testing"; + + var postData = { + email: clubEmail.value, + password: clubPassword.value, + call: clubCall.value + }; + getAPostBuffer( + "https://clublog.org/getadif.php", + clubLogCallback, + test, + "https", + 443, + postData, + ClubLogImg, + "g_isGettingClub" + ); + } +} + +function tryToWriteAdifToDocFolder(filename, buffer, append = false) +{ + var finalFile = g_appData + g_dirSeperator + filename; + try + { + if (append == false) + { + fs.writeFileSync(finalFile, buffer); + return buffer; + } + else + { + fs.appendFileSync(finalFile, buffer); + return fs.readFileSync(finalFile); + } + } + catch (e) + { + return false; + } +} + +function cleanAndPrepADIF(name, adiBuffer, reverse = false, noheader = false) +{ + var rawAdiBuffer = adiBuffer; + var regex = new RegExp("", "i"); + rawAdiBuffer = rawAdiBuffer.replace(regex, ""); + regex = new RegExp("", "i"); + var adiArray = rawAdiBuffer.split(regex); + var activeAdifArray = Array(); + var activeAdifLogMode = true; + var finalBuffer = ""; + + if (noheader == false) finalBuffer = name + "\r\n"; + + if (adiArray.length > 1) + { + regex = new RegExp("", "i"); + activeAdifArray = adiArray[1].split(regex); + + if (reverse == false) + { + for (var x = 0; x < activeAdifArray.length - 1; x++) + { + var row = activeAdifArray[x].replace(/[\n\r]/g, ""); + if (row.length > 0) finalBuffer += row + "\r\n"; + } + } + else + { + for (var x = activeAdifArray.length - 1; x > -1; x--) + { + var row = activeAdifArray[x].replace(/[\n\r]/g, ""); + if (row.length > 0) finalBuffer += row + "\r\n"; + } + } + } + + return finalBuffer; +} + +function addZero(i) +{ + if (i < 10) + { + i = "0" + i; + } + return i; +} + +function getUTCString(d) +{ + var Y = d.getUTCFullYear(); + var M = addZero(d.getUTCMonth() + 1); + var D = addZero(d.getUTCDate()); + var h = addZero(d.getUTCHours()); + var m = addZero(d.getUTCMinutes()); + var s = addZero(d.getUTCSeconds()); + return Y + "-" + M + "-" + D + " " + h + ":" + m + ":" + s; +} + +function lotwCallback(buffer, flag) +{ + var rawAdiBuffer = String(buffer); + if (rawAdiBuffer.indexOf("password incorrect") > -1) + { + if (flag) lotwTestResult.innerHTML = "Invalid"; + } + else + { + if (flag) lotwTestResult.innerHTML = "Passed"; + else + { + var shouldAppend = false; + g_fromDirectCallNoFileDialog = true; + + rawAdiBuffer = cleanAndPrepADIF( + "lotw.adif", + rawAdiBuffer, + true, + shouldAppend + ); + + rawAdiBuffer = tryToWriteAdifToDocFolder( + "lotw.adif", + rawAdiBuffer, + shouldAppend + ); + + onAdiLoadComplete(rawAdiBuffer, true, "lotw.adif", true); + } + } +} + +function shouldWeAppendInsteadOfCreate(filename) +{ + var finalFile = g_appData + g_dirSeperator + filename; + try + { + if (fs.existsSync(finalFile)) return true; + else return false; + } + catch (e) + { + return false; + } +} + +function tryToDeleteLog(filename) +{ + var finalFile = g_appData + g_dirSeperator + filename; + try + { + if (fs.existsSync(finalFile)) + { + fs.unlinkSync(finalFile); + } + } + catch (e) {} +} + +var g_lotwCount = 0; + +var g_isGettingLOTW = false; + +function grabLOtWLog(test) +{ + if (g_isGettingLOTW == false) + { + var lastQSLDateString = + "&qso_qsorxsince=1945-01-01&qso_qslsince=1945-01-01"; + if (test == true) + { + lotwTestResult.innerHTML = "Testing"; + lastQSLDateString = "&qso_qsosince=2100-01-01"; + } + + getABuffer( + "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + + lotwLogin.value + + "&password=" + + encodeURIComponent(lotwPassword.value) + + "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + + lastQSLDateString, + lotwCallback, + test, + "https", + 443, + lotwLogImg, + "g_isGettingLOTW", + 120000 + ); + } +} + +function qrzCallback(buffer, flag) +{ + if (buffer.indexOf("invalid api key") > -1) + { + if (flag) qrzTestResult.innerHTML = "Invalid"; + } + else + { + if (flag) + { + qrzTestResult.innerHTML = "Passed"; + } + else + { + g_fromDirectCallNoFileDialog = true; + var htmlString = String(buffer).replace(/</g, "<"); + htmlString = htmlString.replace(/>/g, ">"); + htmlString = htmlString.replace("ADIF=", "QRZ\r\n"); + + htmlString = cleanAndPrepADIF("qrz.adif", htmlString); + + tryToWriteAdifToDocFolder("qrz.adif", htmlString); + + onAdiLoadComplete(htmlString, true, "qrz.adif", true); + } + } +} + +var g_isGettingQRZCom = false; +function grabQrzComLog(test) +{ + if (g_isGettingQRZCom == false) + { + var action = "FETCH"; + if (test) + { + qrzTestResult.innerHTML = "Testing"; + action = "STATUS"; + } + + getABuffer( + "https://logbook.qrz.com/api?KEY=" + + qrzApiKey.value + + "&ACTION=" + + action, + qrzCallback, + test, + "https", + 443, + qrzLogImg, + "g_isGettingQRZCom", + null + ); + } +} + +function ValidateQrzApi(inputText) +{ + inputText.value = inputText.value.toUpperCase(); + if (inputText.value.length == 19) + { + var passed = false; + var dashcount = 0; + for (var i = 0; i < inputText.value.length; i++) + { + if (inputText.value[i] == "-") dashcount++; + } + if (dashcount == 3) + { + passed = true; + } + if (passed) + { + inputText.style.color = "#FF0"; + inputText.style.backgroundColor = "green"; + + return true; + } + else + { + inputText.style.color = "white"; + inputText.style.backgroundColor = "red"; + return false; + } + } + else + { + inputText.style.color = "white"; + inputText.style.backgroundColor = "red"; + + return false; + } +} + +function ValidateText(inputText) +{ + if (inputText.value.length > 0) + { + inputText.style.color = "#FF0"; + inputText.style.backgroundColor = "green"; + return true; + } + else + { + inputText.style.color = "white"; + inputText.style.backgroundColor = "red"; + return false; + } +} + +function pskCallback(buffer, flag) +{ + g_fromDirectCallNoFileDialog = true; + var rawAdiBuffer = String(buffer); + + onAdiLoadComplete(rawAdiBuffer, false); +} + +var g_isGettingPsk = false; + +function grabPsk24() +{ + if (g_isGettingPsk == true) return; + + if (myDEcall.length > 0 && myDEcall != "NOCALL") + { + var days = 1; + if (pskImg.src == 1) days = 7; + getABuffer( + "https://pskreporter.info/cgi-bin/pskdata.pl?adif=1&days=" + + days + + "&receiverCallsign=" + + myDEcall.toLowerCase(), + pskCallback, + null, + "https", + 443, + pskImg, + "g_isGettingPsk" + ); + } +} + +function adifMenuCheckBoxChanged(what) +{ + g_adifLogSettings.menu[what.id] = what.checked; + var menuItem = what.id + "Div"; + if (what.checked == true) + { + document.getElementById(menuItem).style.display = "inline-block"; + } + else + { + document.getElementById(menuItem).style.display = "none"; + } + + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); + + if (what == buttonAdifCheckBox) setAdifStartup(loadAdifCheckBox); +} + +function adifStartupCheckBoxChanged(what) +{ + g_adifLogSettings.startup[what.id] = what.checked; + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); + + if (what == loadAdifCheckBox) setAdifStartup(loadAdifCheckBox); +} + +function adifLogQsoCheckBoxChanged(what) +{ + g_adifLogSettings.qsolog[what.id] = what.checked; + if (what.id == "logLOTWqsoCheckBox") + { + if (what.checked == true) + { + lotwUpload.style.display = "inline-block"; + trustedTestButton.style.display = "inline-block"; + } + else + { + lotwUpload.style.display = "none"; + trustedTestButton.style.display = "none"; + } + } + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); +} + +function adifNicknameCheckBoxChanged(what) +{ + g_adifLogSettings.nickname[what.id] = what.checked; + if (what.id == "nicknameeQSLCheckBox") + { + if (what.checked == true) + { + eQSLNickname.style.display = "inline-block"; + } + else + { + eQSLNickname.style.display = "none"; + } + } + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); +} + +function adifTextValueChange(what) +{ + what.value = what.value.trim(); + g_adifLogSettings.text[what.id] = what.value; + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); +} + +var fileSelector = document.createElement("input"); +fileSelector.setAttribute("type", "file"); +fileSelector.setAttribute("accept", ".adi,.adif"); +fileSelector.onchange = function () +{ + if (this.files && this.files[0]) + { + let path = this.value.replace(this.files[0].name, ""); + fileSelector.setAttribute("nwworkingdir", path); + + var reader = new FileReader(); + reader.onload = function (e) + { + if (e.target.error == null) + { + onAdiLoadComplete(e.target.result, false); + } + }; + + reader.readAsText(this.files[0]); + } +}; + +function adifLoadDialog() +{ + var exists = fileSelector.getAttribute("nwworkingdir"); + + fileSelector.setAttribute("nwworkingdir", g_appData); + + fileSelector.click(); + + return false; +} + +var startupFileSelector = document.createElement("input"); +startupFileSelector.setAttribute("type", "file"); +startupFileSelector.setAttribute("accept", ".adi,.adif"); +startupFileSelector.onchange = function () +{ + if (this.files && this.files[0]) + { + for (var i in g_startupLogs) + { + if (this.value == g_startupLogs[i].file) return; + } + var newObject = Object(); + newObject.name = this.files[0].name; + newObject.file = this.value; + g_startupLogs.push(newObject); + localStorage.startupLogs = JSON.stringify(g_startupLogs); + + let path = this.value.replace(this.files[0].name, ""); + startupFileSelector.setAttribute("nwworkingdir", path); + + setAdifStartup(loadAdifCheckBox); + } +}; + +function start_and_end(str) +{ + if (str.length > 31) + { + return ( + str.substr(0, 16) + " ... " + str.substr(str.length - 15, str.length) + ); + } + return str; +} + +function setFileSelectors() +{ + selectStartupLink = document.getElementById("selectAdifButton"); + selectStartupLink.onclick = function () + { + var exists = startupFileSelector.getAttribute("nwworkingdir"); + if (exists == null) + { + if (g_workingIniPath.length > 1) + { startupFileSelector.setAttribute("nwworkingdir", g_appData); } + } + + startupFileSelector.click(); + return false; + }; + + selectTqsl = document.getElementById("selectTQSLButton"); + selectTqsl.onclick = function () + { + tqslFileSelector.click(); + return false; + }; + lotwUpload.prepend(selectTqsl); +} + +var tqslFileSelector = document.createElement("input"); +tqslFileSelector.setAttribute("type", "file"); +tqslFileSelector.setAttribute("accept", "*"); +tqslFileSelector.onchange = function () +{ + if (this.files && this.files[0]) + { + g_trustedQslSettings.binaryFile = this.files[0].path; + var fs = require("fs"); + + if ( + fs.existsSync(g_trustedQslSettings.binaryFile) && + (g_trustedQslSettings.binaryFile.endsWith("tqsl.exe") || + g_trustedQslSettings.binaryFile.endsWith("tqsl")) + ) + { + g_trustedQslSettings.binaryFileValid = true; + } + else g_trustedQslSettings.binaryFileValid = false; + + if (g_trustedQslSettings.binaryFileValid == true) + { + tqslFileDiv.style.backgroundColor = "blue"; + } + else + { + tqslFileDiv.style.backgroundColor = "red"; + } + + tqslFileDiv.innerHTML = "" + start_and_end(this.files[0].path) + ""; + localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings); + } +}; + +function loadGtQSOLogFile() +{ + var fs = require("fs"); + + if (fs.existsSync(g_qsoLogFile)) + { + var rawAdiBuffer = fs.readFileSync(g_qsoLogFile); + + g_fromDirectCallNoFileDialog = true; + + onAdiLoadComplete(rawAdiBuffer, false); + } +} + +function loadWsjtLogFile() +{ + var fs = require("fs"); + if (fs.existsSync(g_workingIniPath + "wsjtx_log.adi")) + { + var rawAdiBuffer = fs.readFileSync(g_workingIniPath + "wsjtx_log.adi"); + g_fromDirectCallNoFileDialog = true; + onAdiLoadComplete(rawAdiBuffer, false); + } +} + +function findTrustedQSLPaths() +{ + var process = require("process"); + var base = null; + + if (g_trustedQslSettings.stationFileValid == true) + { + // double check the presence of the station_data; + if (!fs.existsSync(g_trustedQslSettings.stationFile)) + { + g_trustedQslSettings.stationFileValid = false; + } + } + if (g_trustedQslSettings.stationFileValid == false) + { + if (g_platform == "windows") + { + base = process.env.APPDATA + "\\TrustedQSL\\station_data"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.stationFile = base; + g_trustedQslSettings.stationFileValid = true; + } + else + { + base = process.env.LOCALAPPDATA + "\\TrustedQSL\\station_data"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.stationFile = base; + g_trustedQslSettings.stationFileValid = true; + } + } + } + else + { + base = process.env.HOME + "/.tqsl/station_data"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.stationFile = base; + g_trustedQslSettings.stationFileValid = true; + } + } + } + if (g_trustedQslSettings.stationFileValid == true) + { + var validate = false; + var option = document.createElement("option"); + option.value = ""; + option.text = "Select a Station"; + lotwStation.appendChild(option); + + var buffer = fs.readFileSync(g_trustedQslSettings.stationFile, "UTF-8"); + parser = new DOMParser(); + xmlDoc = parser.parseFromString(buffer, "text/xml"); + var x = xmlDoc.getElementsByTagName("StationData"); + for (var i = 0; i < x.length; i++) + { + option = document.createElement("option"); + option.value = x[i].getAttribute("name"); + option.text = x[i].getAttribute("name"); + if (option.value == g_adifLogSettings.text.lotwStation) + { + option.selected = true; + validate = true; + } + lotwStation.appendChild(option); + } + if (validate) + { + ValidateText(lotwStation); + } + } + + if (g_trustedQslSettings.binaryFileValid == true) + { + // double check the presence of the TrustedQSL binary; + if (!fs.existsSync(g_trustedQslSettings.binaryFile)) + { + g_trustedQslSettings.binaryFileValid = false; + } + } + if (g_trustedQslSettings.binaryFileValid == false || g_platform == "mac") + { + if (g_platform == "windows") + { + base = process.env["ProgramFiles(x86)"] + "\\TrustedQSL\\tqsl.exe"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + } + else if (g_platform == "mac") + { + base = "/Applications/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = + process.env.HOME + + "/Applications/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = + process.env.HOME + "/Applications/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = "/Applications/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = + process.env.HOME + + "/Desktop/TrustedQSL/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = + process.env.HOME + + "/Applications/Ham Radio/tqsl.app/Contents/MacOS/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + } + } + } + } + } + } + else if (g_platform == "linux") + { + base = "/usr/bin/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + else + { + base = "/usr/local/bin/tqsl"; + if (fs.existsSync(base)) + { + g_trustedQslSettings.binaryFile = base; + g_trustedQslSettings.binaryFileValid = true; + } + } + } + } + localStorage.trustedQslSettings = JSON.stringify(g_trustedQslSettings); +} + +function startupAdifLoadFunction() +{ + var fs = require("fs"); + + for (var i in g_startupLogs) + { + try + { + if (fs.existsSync(g_startupLogs[i].file)) + { + var rawAdiBuffer = fs.readFileSync(g_startupLogs[i].file); + g_fromDirectCallNoFileDialog = true; + onAdiLoadComplete(rawAdiBuffer, false); + } + } + catch (e) {} + } +} + +function setAdifStartup(checkbox) +{ + if (g_trustedQslSettings.binaryFile == null) + { g_trustedQslSettings.binaryFile = ""; } + + if ( + g_trustedQslSettings.binaryFile.endsWith("tqsl.exe") || + g_trustedQslSettings.binaryFile.endsWith("tqsl") + ) + { + g_trustedQslSettings.binaryFileValid = true; + } + else g_trustedQslSettings.binaryFileValid = false; + + if (g_trustedQslSettings.binaryFileValid == true) + { + tqslFileDiv.style.backgroundColor = "blue"; + } + else + { + tqslFileDiv.style.backgroundColor = "red"; + } + tqslFileDiv.innerHTML = + "" + start_and_end(g_trustedQslSettings.binaryFile) + ""; + + if (buttonAdifCheckBox.checked || loadAdifCheckBox.checked) + { + var worker = ""; + if (g_startupLogs.length > 0) + { + worker += ""; + for (var i in g_startupLogs) + { + worker += + ""; + } + worker += "
" + + g_startupLogs[i].name + + "
"; + } + else + { + worker = "No file(s) selected"; + } + startupLogFileDiv.innerHTML = worker; + selectFileOnStartupDiv.style.display = "block"; + } + else + { + startupLogFileDiv.innerHTML = "No file(s) selected"; + startupFileSelector.setAttribute("type", ""); + startupFileSelector.setAttribute("type", "file"); + startupFileSelector.setAttribute("accept", ".adi*"); + startupFileSelector.value = null; + selectFileOnStartupDiv.style.display = "none"; + } +} + +function removeStartupLog(i) +{ + if (i in g_startupLogs) + { + g_startupLogs.splice(i, 1); + localStorage.startupLogs = JSON.stringify(g_startupLogs); + setAdifStartup(loadAdifCheckBox); + } +} + +function startupAdifLoadCheck() +{ + logEventMedia.value = g_alertSettings.logEventMedia; + + loadWsjtLogFile(); + + if (loadGTCheckBox.checked == true) loadGtQSOLogFile(); + + if (loadAdifCheckBox.checked == true && g_startupLogs.length > 0) + { startupAdifLoadFunction(); } + + if (g_mapSettings.offlineMode == false) + { + if (g_appSettings.gtFlagImgSrc == 1) showGtFlags(); + + // Commented out to stop execution on startup + // if (loadLOTWCheckBox.checked == true) grabLOtWLog(false); + + if (loadQRZCheckBox.checked == true) grabQrzComLog(false); + + if (loadClubCheckBox.checked == true) grabClubLog(false); + + if (loadPsk24CheckBox.checked == true) grabPsk24(); + } +} + +function getABuffer( + file_url, + callback, + flag, + mode, + port, + imgToGray, + stringOfFlag, + timeoutX +) +{ + let url = require("url"); + let http = require(mode); + let fileBuffer = null; + let options = null; + + options = { + host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api + port: port, + path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api + method: "get" + }; + + if (typeof stringOfFlag != "undefined") window[stringOfFlag] = true; + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = + "linear-gradient(grey 0%, black 0% 100% )"; + imgToGray.style.webkitFilter = "invert(100%) grayscale(1)"; + } + + let req = http.request(options, function (res) + { + let fsize = res.headers["content-length"]; + let cookies = null; + if (typeof res.headers["set-cookie"] != "undefined") + { cookies = res.headers["set-cookie"]; } + + res + .on("data", function (data) + { + if (fileBuffer == null) fileBuffer = data; + else fileBuffer += data; + + if (typeof imgToGray != "undefined") + { + let percent = 0; + if (fsize > 0) percent = parseInt((fileBuffer.length / fsize) * 100); + else percent = parseInt(((fileBuffer.length / 100000) * 100) % 100); + imgToGray.parentNode.style.background = + "linear-gradient(grey " + + percent + + "%, black " + + Number(percent + 10) + + "% 100% )"; + } + }) + .on("end", function () + { + if (typeof callback === "function") + { + // Call it, since we have confirmed it is callable + callback(fileBuffer, flag, cookies); + } + if (typeof stringOfFlag != "undefined") + { + window[stringOfFlag] = false; + } + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }) + .on("error", function () + { + if (typeof stringOfFlag != "undefined") + { + window[stringOfFlag] = false; + } + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }); + }); + + req.on("socket", function (socket) + { + socket.on("timeout", function () + { + req.abort(); + }); + }); + + req.on("error", function () + { + if (typeof stringOfFlag != "undefined") + { + window[stringOfFlag] = false; + } + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }); + + req.end(); +} + +function getAPostBuffer( + file_url, + callback, + flag, + mode, + port, + theData, + imgToGray, + stringOfFlag +) +{ + var querystring = require("querystring"); + var postData = querystring.stringify(theData); + var url = require("url"); + var http = require(mode); + var fileBuffer = null; + + var options = { + host: url.parse(file_url).host, // eslint-disable-line node/no-deprecated-api + port: port, + path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api + method: "post", + headers: { + "Content-Type": "application/x-www-form-urlencoded", + "Content-Length": postData.length + } + }; + + window[stringOfFlag] = true; + + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = + "linear-gradient(grey 0%, black 0% 100% )"; + imgToGray.style.webkitFilter = "invert(100%) grayscale(1)"; + } + + var req = http.request(options, function (res) + { + var fsize = res.headers["content-length"]; + var cookies = null; + if (typeof res.headers["set-cookie"] != "undefined") + { cookies = res.headers["set-cookie"]; } + + res + .on("data", function (data) + { + if (fileBuffer == null) fileBuffer = data; + else fileBuffer += data; + + if (typeof imgToGray != "undefined") + { + var percent = 0; + if (fsize > 0) percent = parseInt((fileBuffer.length / fsize) * 100); + else percent = parseInt(((fileBuffer.length / 100000) * 100) % 100); + + imgToGray.parentNode.style.background = + "linear-gradient(grey " + + percent + + "%, black " + + Number(percent + 10) + + "% 100% )"; + } + }) + .on("end", function () + { + if (typeof callback === "function") + { + // Call it, since we have confirmed it is callable + callback(fileBuffer, flag, cookies); + window[stringOfFlag] = false; + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + } + }) + .on("error", function () + { + window[stringOfFlag] = false; + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }); + }); + + req.on("socket", function (socket) + { + socket.on("timeout", function () + { + req.abort(); + }); + }); + + req.on("error", function (err) // eslint-disable-line node/handle-callback-err + { + window[stringOfFlag] = false; + if (typeof imgToGray != "undefined") + { + imgToGray.parentNode.style.background = ""; + imgToGray.style.webkitFilter = ""; + } + }); + + req.write(postData); + req.end(); +} + +function sendUdpMessage(msg, length, port, address) +{ + var dgram = require("dgram"); + var socket = dgram.createSocket({ type: "udp4", reuseAddr: true }); + socket.send(msg, 0, length, port, address, (err) => // eslint-disable-line node/handle-callback-err + { + socket.close(); + }); +} + +function sendTcpMessage(msg, length, port, address) +{ + var net = require("net"); + var client = new net.Socket(); + client.setTimeout(30000); + client.connect(port, address, function () + { + client.write(msg); + }); + + client.on("close", function () {}); +} + +function valueToAdiField(field, value) +{ + var adi = "<" + field + ":"; + adi += String(value).length + ">"; + adi += String(value) + " "; + return adi; +} + +function pad(value) +{ + if (value < 10) + { + return "0" + value; + } + else + { + return value; + } +} + +function HMSfromMilli(milli) +{ + var seconds = parseInt(milli / 1000); + var days = Math.floor(seconds / (3600 * 24)); + seconds -= days * 3600 * 24; + var hrs = Math.floor(seconds / 3600); + seconds -= hrs * 3600; + var mnts = Math.floor(seconds / 60); + seconds -= mnts * 60; + + val = String(pad(hrs)) + String(pad(mnts)) + String(pad(seconds)); + return String(val); +} + +function colonHMSfromMilli(milli) +{ + var seconds = parseInt(milli / 1000); + var days = Math.floor(seconds / (3600 * 24)); + seconds -= days * 3600 * 24; + var hrs = Math.floor(seconds / 3600); + seconds -= hrs * 3600; + var mnts = Math.floor(seconds / 60); + seconds -= mnts * 60; + + val = String(pad(hrs)) + ":" + String(pad(mnts)) + ":" + String(pad(seconds)); + return String(val); +} + +function colonHMSfromSeconds(secondsIn) +{ + var seconds = secondsIn; + var days = Math.floor(seconds / (3600 * 24)); + seconds -= days * 3600 * 24; + var hrs = Math.floor(seconds / 3600); + seconds -= hrs * 3600; + var mnts = Math.floor(seconds / 60); + seconds -= mnts * 60; + + val = String(pad(hrs)) + ":" + String(pad(mnts)) + ":" + String(pad(seconds)); + return String(val); +} + +function convertToDate(julian) +{ + var DAY = 86400000; + var HALF_DAY = DAY / 2; + var UNIX_EPOCH_JULIAN_DATE = 2440587.5; + var UNIX_EPOCH_JULIAN_DAY = 2440587; + return new Date((Number(julian) - UNIX_EPOCH_JULIAN_DATE) * DAY); +} + +var CLk = "25bc718451a71954cb6d0d1b50541dd45d4ba148"; + +var lastReportHash = null; + +var g_oldStyleLogMessage = null; + +function oldSendToLogger() +{ + var newMessage = Object.assign({}, g_oldStyleLogMessage); + + var band = Number(newMessage.Frequency / 1000000).formatBand(); + + if ( + newMessage.DXGrid.length == 0 && + newMessage.DXCall + band + newMessage.MO in g_liveCallsigns + ) + { + newMessage.DXGrid = g_liveCallsigns[ + newMessage.DXCall + band + newMessage.MO + ].grid.substr(0, 4); + } + + var report = ""; + + report += valueToAdiField( + "BAND", + Number(newMessage.Frequency / 1000000).formatBand() + ); + report += valueToAdiField("CALL", newMessage.DXCall.toUpperCase()); + report += valueToAdiField( + "FREQ", + Number(newMessage.Frequency / 1000000).toFixed(6) + ); + report += valueToAdiField("MODE", newMessage.MO.toUpperCase()); + var date = convertToDate(parseInt(newMessage.DateOn)); + var dataString = + date.getUTCFullYear() + + ("0" + (date.getUTCMonth() + 1)).slice(-2) + + ("0" + date.getUTCDate()).slice(-2); + report += valueToAdiField("QSO_DATE", dataString); + report += valueToAdiField("TIME_ON", HMSfromMilli(newMessage.TimeOn)); + + date = convertToDate(parseInt(newMessage.DateOff)); + dataString = + date.getUTCFullYear() + + ("0" + (date.getUTCMonth() + 1)).slice(-2) + + ("0" + date.getUTCDate()).slice(-2); + report += valueToAdiField("QSO_DATE_OFF", dataString); + report += valueToAdiField("TIME_OFF", HMSfromMilli(newMessage.TimeOff)); + + report += valueToAdiField("RST_RCVD", newMessage.ReportRecieved); + report += valueToAdiField("RST_SENT", newMessage.ReportSend); + report += valueToAdiField("TX_PWR", parseInt(newMessage.TXPower)); + report += valueToAdiField("GRIDSQUARE", newMessage.DXGrid); + + if (newMessage.Comments.length > 0) + { report += valueToAdiField("COMMENT", newMessage.Comments); } + + if (newMessage.Name.length > 0) + { report += valueToAdiField("NAME", newMessage.Name); } + + if (newMessage.Operatorcall.length > 0) + { + report += valueToAdiField("OPERATOR", newMessage.Operatorcall); + } + + if (newMessage.Mycall.length > 0) + { + report += valueToAdiField("STATION_CALLSIGN", newMessage.Mycall); + } + else if (myDEcall != "NOCALL" && myDEcall.length > 0) + { report += valueToAdiField("STATION_CALLSIGN", myDEcall); } + + if (newMessage.Mygrid.length > 0) + { + report += valueToAdiField("MY_GRIDSQUARE", newMessage.Mygrid); + } + else if (myDEGrid.length > 1) + { report += valueToAdiField("MY_GRIDSQUARE", myDEGrid); } + + report += ""; + + sendToLogger(report); +} + +var g_adifLookupMap = { + name: "NAME", + iota: "IOTA", + sota: "SOTA_REF", + continent: "CONT", + cqzone: "CQZ", + ituzone: "ITUZ", + email: "EMAIL", + county: "CNTY" +}; + +function sendToLogger(ADIF) +{ + let regex = new RegExp("", "i"); + let record = parseADIFRecord(ADIF.split(regex)[1]); + let localMode = record.MODE; + + if (localMode == "MFSK" && "SUBMODE" in record) + { + localMode = record.SUBMODE; + } + + if ( + (!("GRIDSQUARE" in record) || record.GRIDSQUARE.length == 0) && + record.CALL + record.BAND + localMode in g_liveCallsigns + ) + { + record.GRIDSQUARE = g_liveCallsigns[ + record.CALL + record.BAND + localMode + ].grid.substr(0, 4); + } + + if ("TX_PWR" in record) + { + record.TX_PWR = String(parseInt(record.TX_PWR)); + } + + if ( + (!("STATION_CALLSIGN" in record) || + record.STATION_CALLSIGN.length == 0) && + myDEcall != "NOCALL" && + myDEcall.length > 0 + ) + { + record.STATION_CALLSIGN = myDEcall; + } + + if ( + (!("MY_GRIDSQUARE" in record) || record.MY_GRIDSQUARE.length == 0) && + myDEGrid.length > 1 + ) + { + record.MY_GRIDSQUARE = myDEGrid; + } + + if (!("DXCC" in record)) + { + let dxcc = callsignToDxcc(record.CALL); + if (dxcc == -1) dxcc = 0; + record.DXCC = String(dxcc); + } + + // Tag: This is going to bite us in the butt later, but leaving it alone. + if (!("COUNTRY" in record) && Number(record.DXCC) > 0) + { + record.COUNTRY = g_dxccToADIFName[Number(record.DXCC)]; + } + + if (g_appSettings.lookupMerge == true) + { + let request = g_Idb + .transaction(["lookups"], "readwrite") + .objectStore("lookups") + .get(record.CALL); + + request.onsuccess = function (event) + { + if (request.result) + { + let lookup = request.result; + for (let key in lookup) + { + if (key in g_adifLookupMap) + { + record[g_adifLookupMap[key]] = lookup[key]; + } + } + if ("GRIDSQUARE" in record && "grid" in lookup) + { + if ( + record.GRIDSQUARE.substr(0, 4) == lookup.grid.substr(0, 4) + ) + { + record.GRIDSQUARE = lookup.grid; + } + } + if ( + g_appSettings.lookupMissingGrid && + "grid" in lookup && + (!("GRIDSQUARE" in record) || record.GRIDSQUARE.length == 0) + ) + { + record.GRIDSQUARE = lookup.grid; + } + } + finishSendingReport(record, localMode); + }; + + request.onerror = function (event) + { + finishSendingReport(record, localMode); + }; + } + else + { + finishSendingReport(record, localMode); + } +} + +function finishSendingReport(record, localMode) +{ + let report = ""; + + let reportHash = record.CALL + record.MODE + localMode; + + for (let key in record) + { + report += "<" + key + ":" + record[key].length + ">" + record[key] + " "; + } + report += ""; + + if (reportHash != lastReportHash) + { + lastReportHash = reportHash; + + if ( + g_N1MMSettings.enable == true && + g_N1MMSettings.port > 1024 && + g_N1MMSettings.ip.length > 4 + ) + { + sendUdpMessage( + report, + report.length, + parseInt(g_N1MMSettings.port), + g_N1MMSettings.ip + ); + addLastTraffic("Logged to N1MM"); + } + + if ( + g_log4OMSettings.enable == true && + g_log4OMSettings.port > 1024 && + g_log4OMSettings.ip.length > 4 + ) + { + sendUdpMessage( + "ADD " + report, + report.length + 4, + parseInt(g_log4OMSettings.port), + g_log4OMSettings.ip + ); + addLastTraffic("Logged to Log4OM"); + } + + try + { + onAdiLoadComplete("GT" + report); + } + catch (e) + { + addLastTraffic("Exception Internal Log"); + } + try + { + // Log worthy + if (logGTqsoCheckBox.checked == true) + { + var fs = require("fs"); + fs.appendFileSync(g_qsoLogFile, report + "\r\n"); + addLastTraffic( + "Logged to GridTracker backup" + ); + } + } + catch (e) + { + addLastTraffic( + "Exception GridTracker backup" + ); + } + + try + { + sendQrzLogEntry(report); + } + catch (e) + { + addLastTraffic("Exception QRZ Log"); + } + + try + { + sendClubLogEntry(report); + } + catch (e) + { + addLastTraffic("Exception ClubLog Log"); + } + + try + { + sendHrdLogEntry(report); + } + catch (e) + { + addLastTraffic("Exception HrdLog.net Log"); + } + + try + { + sendCloudlogEntry(report); + } + catch (e) + { + addLastTraffic("Exception Cloudlog Log"); + } + + if ( + g_acLogSettings.enable == true && + g_acLogSettings.port > 0 && + g_acLogSettings.ip.length > 4 + ) + { + try + { + sendACLogMessage(record, g_acLogSettings.port, g_acLogSettings.ip); + addLastTraffic("Logged to N3FJP"); + } + catch (e) + { + addLastTraffic("Exception N3FJP Log"); + } + } + + if ( + g_dxkLogSettings.enable == true && + g_dxkLogSettings.port > 0 && + g_dxkLogSettings.ip.length > 4 + ) + { + try + { + sendDXKeeperLogMessage( + report, + g_dxkLogSettings.port, + g_dxkLogSettings.ip + ); + addLastTraffic("Logged to DXKeeper"); + } + catch (e) + { + addLastTraffic("Exception DXKeeper Log"); + } + } + + if ( + g_HRDLogbookLogSettings.enable == true && + g_HRDLogbookLogSettings.port > 0 && + g_HRDLogbookLogSettings.ip.length > 4 + ) + { + try + { + sendHRDLogbookEntry( + record, + g_HRDLogbookLogSettings.port, + g_HRDLogbookLogSettings.ip + ); + addLastTraffic( + "Logged to HRD Logbook" + ); + } + catch (e) + { + addLastTraffic("Exception HRD Log"); + } + } + + try + { + sendLotwLogEntry(report); + } + catch (e) + { + addLastTraffic("Exception LoTW Log"); + } + + if ( + logeQSLQSOCheckBox.checked == true && + nicknameeQSLCheckBox.checked == true && + eQSLNickname.value.trim().length > 0 + ) + { + record.APP_EQSL_QTH_NICKNAME = eQSLNickname.value.trim(); + report = ""; + for (var key in record) + { + report += + "<" + key + ":" + record[key].length + ">" + record[key] + " "; + } + report += ""; + } + + try + { + sendeQSLEntry(report); + } + catch (e) + { + addLastTraffic("Exception LoTW Log"); + } + + try + { + alertLogMessage(); + } + catch (e) + { + addLastTraffic("Exception Alert Log"); + } + + if (lookupCloseLog.checked == true) + { + try + { + openLookupWindow(false); + } + catch (e) + { + addLastTraffic("Exception Hide Lookup"); + } + } + } + + return report; +} + +function alertLogMessage() +{ + if (logEventMedia.value != "none") + { + playAlertMediaFile(logEventMedia.value); + } +} + +function eqslCallback(buffer, flag) +{ + var result = String(buffer); + if (flag) + { + if (result.indexOf("No such Username/Password found") != -1) + { + eQSLTestResult.innerHTML = "Bad
Password
or
Nickname"; + logeQSLQSOCheckBox.checked = false; + adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); + } + else if (result.indexOf("No such Callsign found") != -1) + { + eQSLTestResult.innerHTML = "Unknown
Callsign"; + logeQSLQSOCheckBox.checked = false; + adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); + } + else if (result.indexOf("Your ADIF log file has been built") > -1 || result.indexOf("You have no log entries") > -1) + { + eQSLTestResult.innerHTML = "Passed"; + } + else if (result.indexOf("specify the desired User by using the QTHNickname") != -1) + { + eQSLTestResult.innerHTML = "QTH Nickname
Needed"; + } + else + { + eQSLTestResult.innerHTML = "Unknown
Error"; + logeQSLQSOCheckBox.checked = false; + adifLogQsoCheckBoxChanged(logeQSLQSOCheckBox); + } + } + else + { + if (result.indexOf("Error: No match on eQSL_User/eQSL_Pswd") != -1) + { + addLastTraffic( + "Fail log eQSL.cc (credentials)" + ); + } + if ( + result.indexOf("specify the desired User by using the QTHNickname") != -1 + ) + { + addLastTraffic( + "Fail log eQSL.cc (nickname)" + ); + } + else if (result.indexOf("Result: 0 out of 1 records") != -1) + { + addLastTraffic("Fail log eQSL.cc (dupe)"); + } + else if (result.indexOf("Result: 1 out of 1 records added") != -1) + { + addLastTraffic("Logged to eQSL.cc"); + } + else + { + addLastTraffic("Fail log eQSL.cc (?)"); + } + } +} + +function eQSLTest(test) +{ + if (g_mapSettings.offlineMode == true) return; + + eQSLTestResult.innerHTML = "Testing"; + + var fUrl = + "https://www.eQSL.cc/qslcard/DownloadInBox.cfm?UserName=" + + encodeURIComponent(eQSLUser.value) + + "&Password=" + + encodeURIComponent(eQSLPassword.value) + + "&RcvdSince=2020101"; + + if (nicknameeQSLCheckBox.checked == true) + { fUrl += "&QTHNickname=" + encodeURIComponent(eQSLNickname.value); } + getABuffer(fUrl, eqslCallback, true, "https", 443); +} + +function sendeQSLEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logeQSLQSOCheckBox.checked == true) + { + var pid = "GridTracker"; + var pver = String(gtVersion); + var header = "" + pid + "\r\n"; + header += "" + pver + "\r\n"; + header += "\r\n"; + var eReport = encodeURIComponent(header + report); + var fUrl = + "https://www.eQSL.cc/qslcard/importADIF.cfm?ADIFData=" + + eReport + + "&EQSL_USER=" + + encodeURIComponent(eQSLUser.value) + + "&EQSL_PSWD=" + + encodeURIComponent(eQSLPassword.value); + getABuffer(fUrl, eqslCallback, false, "https", 443); + } +} + +function testTrustedQSL(test) +{ + if (g_mapSettings.offlineMode == true) + { + lotwTestResult.innerHTML = "Currently
offline"; + return; + } + + if ( + logLOTWqsoCheckBox.checked == true && + g_trustedQslSettings.binaryFileValid == true && + g_trustedQslSettings.stationFileValid == true && + lotwStation.value.length > 0 + ) + { + lotwTestResult.innerHTML = "Testing Upload"; + + var child_process = require("child_process"); + var options = Array(); + options.push("-q"); + options.push("-v"); + + child_process.execFile( + g_trustedQslSettings.binaryFile, + options, + (error, stdout, stderr) => + { + if (error) + { + lotwTestResult.innerHTML = "Error encountered"; + } + lotwTestResult.innerHTML = stderr; + } + ); + } + else + { + var worker = ""; + if (g_trustedQslSettings.binaryFileValid == false) + { worker += "Invalid tqsl executable
"; } + if (g_trustedQslSettings.stationFileValid == false) + { worker += "TrustQSL not installed
"; } + if (!ValidateText(lotwTrusted)) worker += "TQSL Password missing
"; + if (!ValidateText(lotwStation)) worker += "Select Station
"; + lotwTestResult.innerHTML = worker; + } +} +var g_trustTempPath = ""; + +function sendLotwLogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if ( + logLOTWqsoCheckBox.checked == true && + g_trustedQslSettings.binaryFileValid == true && + g_trustedQslSettings.stationFileValid == true && + lotwStation.value.length > 0 + ) + { + var header = + "Generated " + userTimeString(null) + " for " + myDEcall + "\r\n\r\n"; + var pid = "GridTracker"; + var pver = String(gtVersion); + header += "" + pid + "\r\n"; + header += "" + pver + "\r\n"; + header += "\r\n"; + var finalLog = header + report + "\r\n"; + + g_trustTempPath = os.tmpdir() + g_dirSeperator + unique(report) + ".adif"; + fs.writeFileSync(g_trustTempPath, finalLog); + + var child_process = require("child_process"); + var options = Array(); + options.push("-a"); + options.push("all"); + options.push("-l"); + options.push(lotwStation.value); + if (lotwTrusted.value.length > 0) + { + options.push("-p"); + options.push(lotwTrusted.value); + } + options.push("-q"); + options.push("-x"); + options.push("-d"); + options.push("-u"); + options.push(g_trustTempPath); + + child_process.execFile( + g_trustedQslSettings.binaryFile, + options, + (error, stdout, stderr) => // eslint-disable-line node/handle-callback-err + { + if (stderr.indexOf("Final Status: Success") < 0) + { + alert(stderr); + addLastTraffic("Fail log to TQSL"); + } + else + { + addLastTraffic("Logged to TQSL"); + } + fs.unlinkSync(g_trustTempPath); + } + ); + } +} + +function n1mmLoggerChanged() +{ + g_N1MMSettings.enable = buttonN1MMCheckBox.checked; + g_N1MMSettings.ip = N1MMIpInput.value; + g_N1MMSettings.port = N1MMPortInput.value; + + localStorage.N1MMSettings = JSON.stringify(g_N1MMSettings); +} + +function log4OMLoggerChanged() +{ + g_log4OMSettings.enable = buttonLog4OMCheckBox.checked; + g_log4OMSettings.ip = log4OMIpInput.value; + g_log4OMSettings.port = log4OMPortInput.value; + + localStorage.log4OMSettings = JSON.stringify(g_log4OMSettings); +} + +function acLogLoggerChanged() +{ + g_acLogSettings.enable = buttonacLogCheckBox.checked; + g_acLogSettings.ip = acLogIpInput.value; + g_acLogSettings.port = acLogPortInput.value; + + localStorage.acLogSettings = JSON.stringify(g_acLogSettings); +} + +function dxkLogLoggerChanged() +{ + g_dxkLogSettings.enable = buttondxkLogCheckBox.checked; + g_dxkLogSettings.ip = dxkLogIpInput.value; + g_dxkLogSettings.port = dxkLogPortInput.value; + + localStorage.dxkLogSettings = JSON.stringify(g_dxkLogSettings); +} + +function hrdLogbookLoggerChanged() +{ + g_HRDLogbookLogSettings.enable = buttonHrdLogbookCheckBox.checked; + g_HRDLogbookLogSettings.ip = hrdLogbookIpInput.value; + g_HRDLogbookLogSettings.port = hrdLogbookPortInput.value; + + localStorage.HRDLogbookLogSettings = JSON.stringify(g_HRDLogbookLogSettings); +} + +function CloudUrlErrorCallback( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + timeoutCallback, + message +) +{ + CloudlogTestResult.innerHTML = message; +} + +function CloudlogSendLogResult(buffer, flag) +{ + if (flag && flag == true) + { + if (buffer) + { + if (buffer.indexOf("missing api key") > -1) + { + CloudlogTestResult.innerHTML = "API Key Invalid"; + } + else if (buffer.indexOf("created") > -1) + { + CloudlogTestResult.innerHTML = "Passed"; + } + else + { + CloudlogTestResult.innerHTML = "Invalid Response"; + } + } + else + { + CloudlogTestResult.innerHTML = "Invalid Response"; + } + } + else + { + if (buffer && buffer.indexOf("created") > -1) + { addLastTraffic("Logged to Cloudlog"); } + else addLastTraffic("Fail log to Cloudlog"); + } +} + +function qrzSendLogResult(buffer, flag) +{ + if (typeof buffer != "undefined" && buffer != null) + { + var data = String(buffer); + var kv = data.split("&"); + if (kv.length > 0) + { + var arrData = Object(); + for (var x in kv) + { + var split = kv[x].split("="); + arrData[split[0]] = split[1]; + } + if ( + typeof arrData.RESULT == "undefined" || + arrData.RESULT != "OK" + ) + { + alert( + "Error uploading QSO to QRZ.com (" + + (arrData.REASON || "Unknown error") + + ")" + ); + addLastTraffic("Fail log to QRZ.com"); + } + else + { addLastTraffic("Logged to QRZ.com"); } + } + } + else alert("Error uploading QSO to QRZ.com (No response)"); +} + +function postDialogRetryCallback( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + timeoutCallback, + who +) +{ + if (window.confirm("Error sending QSO to " + who + ", retry?")) + { + getPostBuffer( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + postDialogRetryCallback, + who + ); + } +} + +function postRetryErrorCallaback( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + timeoutCallback, + who +) +{ + getPostBuffer( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + postDialogRetryCallback, + who + ); +} + +function sendQrzLogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logQRZqsoCheckBox.checked == true && ValidateQrzApi(qrzApiKey)) + { + if (typeof nw != "undefined") + { + var postData = { + KEY: qrzApiKey.value, + ACTION: "INSERT", + ADIF: report + }; + getPostBuffer( + "https://logbook.qrz.com/api", + qrzSendLogResult, + null, + "https", + 443, + postData, + 30000, + postRetryErrorCallaback, + "QRZ.com" + ); + } + } +} + +function clubLogQsoResult(buffer, flag) +{ + addLastTraffic("Logged to ClubLog.org"); +} + +function sendClubLogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logClubqsoCheckBox.checked == true) + { + if (typeof nw != "undefined") + { + var postData = { + email: clubEmail.value, + password: clubPassword.value, + callsign: clubCall.value, + adif: report, + api: CLk + }; + + getPostBuffer( + "https://clublog.org/realtime.php", + clubLogQsoResult, + null, + "https", + 443, + postData, + 30000, + postRetryErrorCallaback, + "ClubLog.org" + ); + } + } +} + +function sendCloudlogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logCloudlogQSOCheckBox.checked == true) + { + if (typeof nw != "undefined") + { + var postData = { key: CloudlogAPI.value, type: "adif", string: report }; + getPostJSONBuffer( + CloudlogURL.value, + CloudlogSendLogResult, + null, + "https", + 80, + postData, + 10000, + CloudUrlErrorCallback, + "Failed to Send" + ); + } + } +} + +function hrdSendLogResult(buffer, flag) +{ + if (flag && flag == true) + { + if (buffer.indexOf("Unknown user") > -1) + { + HRDLogTestResult.innerHTML = "Failed"; + logHRDLOGqsoCheckBox.checked = false; + adifLogQsoCheckBoxChanged(logHRDLOGqsoCheckBox); + } + else HRDLogTestResult.innerHTML = "Passed"; + } + else + { + if (buffer.indexOf("Unknown user") == -1) + { addLastTraffic("Logged to HRDLOG.net"); } + else + { addLastTraffic("Fail log to HRDLOG.net"); } + } +} + +function sendHrdLogEntry(report) +{ + if (g_mapSettings.offlineMode == true) return; + + if (logHRDLOGqsoCheckBox.checked == true) + { + if (typeof nw != "undefined") + { + var postData = { + Callsign: HRDLOGCallsign.value, + Code: HRDLOGUploadCode.value, + App: "GridTracker " + gtVersion, + ADIFData: report + }; + getPostBuffer( + "https://www.hrdlog.net/NewEntry.aspx", + hrdSendLogResult, + null, + "https", + 443, + postData, + 30000, + postRetryErrorCallaback, + "HRDLog.net" + ); + } + } +} + +function hrdCredentialTest(test) +{ + if (test && test == true) + { + HRDLogTestResult.innerHTML = "Testing"; + + if (typeof nw != "undefined") + { + var postData = { + Callsign: HRDLOGCallsign.value, + Code: HRDLOGUploadCode.value + }; + getPostBuffer( + "https://www.hrdlog.net/NewEntry.aspx", + hrdSendLogResult, + test, + "https", + 443, + postData + ); + } + } +} + +function ClublogTest(test) +{ + if (test && test == true) + { + CloudlogTestResult.innerHTML = "Testing"; + + if (typeof nw != "undefined") + { + var postData = { key: CloudlogAPI.value, type: "adif", string: "" }; + getPostJSONBuffer( + CloudlogURL.value, + CloudlogSendLogResult, + test, + "https", + 80, + postData, + 10000, + CloudUrlErrorCallback, + "No Response
or
Timeout" + ); + } + } +} + +function getPostJSONBuffer( + file_url, + callback, + flag, + mode, + port, + theData, + timeoutMs, + timeoutCallback, + who +) +{ + try + { + var postData = JSON.stringify(theData); + var url = require("url"); + var protocol = url.parse(file_url).protocol; // eslint-disable-line node/no-deprecated-api + var http = require(protocol.replace(":", "")); + var fileBuffer = null; + var options = { + host: url.parse(file_url).hostname, // eslint-disable-line node/no-deprecated-api + port: url.parse(file_url).port, // eslint-disable-line node/no-deprecated-api + path: url.parse(file_url).path, // eslint-disable-line node/no-deprecated-api + method: "post", + headers: { + "Content-Type": "application/json", + "Content-Length": postData.length + } + }; + var req = http.request(options, function (res) + { + var fsize = res.headers["content-length"]; + var cookies = null; + if (typeof res.headers["set-cookie"] != "undefined") + { cookies = res.headers["set-cookie"]; } + res + .on("data", function (data) + { + if (fileBuffer == null) fileBuffer = data; + else fileBuffer += data; + }) + .on("end", function () + { + if (typeof callback === "function") + { + // Call it, since we have confirmed it is callable + callback(fileBuffer, flag, cookies); + } + }) + .on("error", function () {}); + }); + if (typeof timeoutMs == "number" && timeoutMs > 0) + { + req.on("socket", function (socket) + { + socket.setTimeout(timeoutMs); + socket.on("timeout", function () + { + req.abort(); + }); + }); + req.on("error", function (err) // eslint-disable-line node/handle-callback-err + { + if (typeof timeoutCallback != "undefined") + { + timeoutCallback( + file_url, + callback, + flag, + mode, + 80, + theData, + timeoutMs, + timeoutCallback, + who + ); + } + }); + } + req.write(postData); + req.end(); + } + catch (e) + { + if (typeof timeoutCallback != "undefined") + { + timeoutCallback( + file_url, + callback, + flag, + mode, + 80, + theData, + timeoutMs, + timeoutCallback, + "Invalid Url" + ); + } + } +} + +function valueToXmlField(field, value) +{ + var adi = "<" + field + ">"; + adi += String(value); + adi += ""; + return adi; +} + +function aclUpdateControlValue(control, value) +{ + return ( + valueToXmlField( + "CMD", + "" + + valueToXmlField("CONTROL", control) + + valueToXmlField("VALUE", value) + ) + "\r\n" + ); +} + +function aclAction(action) +{ + return ( + valueToXmlField("CMD", "" + valueToXmlField("VALUE", action)) + + "\r\n" + ); +} + +function adifField(record, key) +{ + if (key in record) return record[key]; + else return ""; +} +function sendACLogMessage(record, port, address) +{ + var report = ""; + + report += aclAction("CLEAR"); + report += aclUpdateControlValue("TXTENTRYBAND", adifField(record, "BAND")); + report += aclUpdateControlValue("TXTENTRYCALL", adifField(record, "CALL")); + report += aclAction("CALLTAB"); + report += aclUpdateControlValue( + "TXTENTRYFREQUENCY", + adifField(record, "FREQ") + ); + if (adifField(record, "SUBMODE").length > 0) + { + report += aclUpdateControlValue( + "TXTENTRYMODE", + adifField(record, "SUBMODE") + ); + } + else + { report += aclUpdateControlValue("TXTENTRYMODE", adifField(record, "MODE")); } + + var date = adifField(record, "QSO_DATE"); + var dataString = + date.substr(0, 4) + "/" + date.substr(4, 2) + "/" + date.substr(6); + + report += aclUpdateControlValue("TXTENTRYDATE", dataString); + + var timeVal = adifField(record, "TIME_ON"); + var whenString = + timeVal.substr(0, 2) + + ":" + + timeVal.substr(2, 2) + + ":" + + timeVal.substr(4, 2); + report += aclUpdateControlValue("TXTENTRYTIMEON", whenString); + + timeVal = adifField(record, "TIME_OFF"); + whenString = + timeVal.substr(0, 2) + + ":" + + timeVal.substr(2, 2) + + ":" + + timeVal.substr(4, 2); + report += aclUpdateControlValue("TXTENTRYTIMEOFF", whenString); + + report += aclUpdateControlValue( + "TXTENTRYRSTR", + adifField(record, "RST_RCVD") + ); + report += aclUpdateControlValue( + "TXTENTRYRSTS", + adifField(record, "RST_SENT") + ); + report += aclUpdateControlValue("TXTENTRYPOWER", adifField(record, "TX_PWR")); + report += aclUpdateControlValue( + "TXTENTRYGRID", + adifField(record, "GRIDSQUARE") + ); + report += aclUpdateControlValue( + "TXTENTRYCOMMENTS", + adifField(record, "COMMENT") + ); + report += aclUpdateControlValue("TXTENTRYNAMER", adifField(record, "NAME")); + report += aclUpdateControlValue("TXTENTRYIOTA", adifField(record, "IOTA")); + report += aclUpdateControlValue( + "TXTENTRYCONTINENT", + adifField(record, "CONT") + ); + report += aclUpdateControlValue("TXTENTRYITUZ", adifField(record, "ITUZ")); + report += aclUpdateControlValue("TXTENTRYCQZONE", adifField(record, "CQZ")); + report += aclUpdateControlValue("TXTENTRYCOUNTYR", adifField(record, "CNTY")); + + var sentSpcNum = false; + if (adifField(record, "SRX").length > 0) + { + report += aclUpdateControlValue( + "TXTENTRYSERIALNOR", + adifField(record, "SRX") + ); + } + else if (adifField(record, "CONTEST_ID").length > 0) + { + report += aclUpdateControlValue( + "TXTENTRYSPCNUM", + adifField(record, "SRX_STRING") + ); + sentSpcNum = true; + report += aclUpdateControlValue( + "TXTENTRYCLASS", + adifField(record, "CLASS") + ); + report += aclUpdateControlValue( + "TXTENTRYSECTION", + adifField(record, "ARRL_SECT") + ); + } + + if (adifField(record, "STATE").length > 0) + { + report += aclUpdateControlValue( + "TXTENTRYSTATE", + adifField(record, "STATE") + ); + if (sentSpcNum == false) + { + report += aclUpdateControlValue( + "TXTENTRYSPCNUM", + adifField(record, "STATE") + ); + } + } + + report += aclAction("ENTER"); + + sendTcpMessage(report, report.length, port, address); +} + +function sendDXKeeperLogMessage(newMessage, port, address) +{ + var report = ""; + + report += valueToAdiField("command", "log"); + report += valueToAdiField("parameters", newMessage); + report += "\r\n"; + + sendTcpMessage(report, report.length, Number(port) + 1, address); +} + +function parseADIFRecord(adif) +{ + var regex = new RegExp("", "i"); + var newLine = adif.split(regex); + var line = newLine[0].trim(); // Catch the naughty case of someone sending two records at the same time + var record = {}; + + // because strings are not escaped for adif.. ie: :'s and <'s .. we have to walk from left to right + // cheesy, but damn i'm tired of parsing things + var x = 0; + while (line.length > 0) + { + while (line.charAt(0) != "<" && line.length > 0) + { + line = line.substr(1); + } + if (line.length > 0) + { + line = line.substr(1); + var where = line.indexOf(":"); + if (where != -1) + { + var fieldName = line.substr(0, where).toUpperCase(); + line = line.substr(fieldName.length + 1); + var fieldLength = parseInt(line); + var end = line.indexOf(">"); + if (end > 0) + { + line = line.substr(end + 1); + var fieldValue = line.substr(0, fieldLength); + line = line.substr(fieldLength); + record[fieldName] = fieldValue; + } + } + } + } + + return record; +} + +function sendHRDLogbookEntry(report, port, address) +{ + var command = "ver\rdb add {"; + var items = Object.assign({}, report); + + items.FREQ = items.FREQ.split(".").join(""); + + for (var item in items) + { + command += item + "=\"" + items[item] + "\" "; + } + + command += "}\rexit\r"; + + sendTcpMessage(command, command.length, Number(port), address); +} From b2039e2e8af6550b3a1a30ada54eee987071e21a Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sat, 12 Jun 2021 22:13:03 -0500 Subject: [PATCH 003/125] update changelog etc for v1.21.0613 --- debian/changelog | 8 ++++++++ package.nw/gt_update.odt | Bin 84769 -> 81206 bytes package.nw/gt_update.pdf | Bin 60797 -> 57109 bytes package.nw/package.json | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index ca3448c..1d5ddaa 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +gridtracker (1.21.0613) unstable; urgency=medium + [Bug Fixes] + - Fix pulling down LoTW log at start-up causing issue for other programs that are trying to sync LoTW logs. + [Enhancements] + - Updated list of contributors + + -- Matthew Chambers Sun, 13 June 2021 03:04:00 -0000 + gridtracker (1.21.0530) unstable; urgency=medium [Bug Fixes] - Fix spots layer not refreshing/clearing when TX idle diff --git a/package.nw/gt_update.odt b/package.nw/gt_update.odt index e54987a39263f785460f0d71b55694249f1ae752..70b150b68fd8b3f5f20728240082476711907ba9 100644 GIT binary patch delta 14517 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 YWg!17>|kJMf3CqlX8*?ZXE4D255=xGX8-^I delta 18162 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 diff --git a/package.nw/gt_update.pdf b/package.nw/gt_update.pdf index 09402dc73ec22352cbf073e7dcce3d3e3115a462..5db90ba2bde23a7688ee66e00f4d2877f0411dbb 100644 GIT binary patch delta 28770 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 L($Y#ON}~QBTe$X@ delta 32225 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 diff --git a/package.nw/package.json b/package.nw/package.json index a3c45ea..cddd5ae 100644 --- a/package.nw/package.json +++ b/package.nw/package.json @@ -1,7 +1,7 @@ { "name": "GridTracker", "product_string_do_not_use": "gridtracker", - "version": "1.21.0530", + "version": "1.21.0613", "betaVersion": "", "description": "GridTracker, an amateur radio companion", "author": "Stephen Loomis (N0TTL) and GridTracker.org", From 8df8ed351990915d5689177afdfa9de8e2de84b6 Mon Sep 17 00:00:00 2001 From: jangliss Date: Sat, 12 Jun 2021 22:20:32 -0500 Subject: [PATCH 004/125] Linting hates me. Remove space on comment. --- package.nw/lib/adif.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/adif.js b/package.nw/lib/adif.js index 0259731..759e475 100644 --- a/package.nw/lib/adif.js +++ b/package.nw/lib/adif.js @@ -1297,7 +1297,7 @@ function startupAdifLoadCheck() { if (g_appSettings.gtFlagImgSrc == 1) showGtFlags(); - // Commented out to stop execution on startup + // Commented out to stop execution on startup // if (loadLOTWCheckBox.checked == true) grabLOtWLog(false); if (loadQRZCheckBox.checked == true) grabQrzComLog(false); From 3fa69fbed2ee985acbb9273a8031ff065e48a472 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sun, 13 Jun 2021 03:27:38 +0000 Subject: [PATCH 005/125] Update acks json --- package.nw/data/acknowledgements.json | 264 +++++++++++++++++++++++--- package.nw/img/emojis/books.png | Bin 0 -> 714 bytes package.nw/img/emojis/grandfather.png | Bin 0 -> 941 bytes package.nw/img/emojis/money-bag.png | Bin 0 -> 772 bytes package.nw/img/emojis/speech.png | Bin 0 -> 496 bytes 5 files changed, 238 insertions(+), 26 deletions(-) create mode 100644 package.nw/img/emojis/books.png create mode 100644 package.nw/img/emojis/grandfather.png create mode 100644 package.nw/img/emojis/money-bag.png create mode 100644 package.nw/img/emojis/speech.png diff --git a/package.nw/data/acknowledgements.json b/package.nw/data/acknowledgements.json index b7a7be8..67aa8da 100644 --- a/package.nw/data/acknowledgements.json +++ b/package.nw/data/acknowledgements.json @@ -1,29 +1,145 @@ { - "N0TTL": { - "badge": "img/emojis/star.png", - "message": "Creator of GridTracker" + "AA5KD": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "AD0WB": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "AF2V": { + "badge": "img/emojis/books.png", + "message": "GridTracker Documentation" + }, + "AJ6RX": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "BD3OOX": { + "badge": "img/emojis/speech.png", + "message": "GridTracker Translator" + }, + "CX4CD": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "DE1JPJ": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "DL6RA": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "GI1MIC": { + "badge": "img/emojis/pizza.png", + "message": "GridTracker Tester" + }, + "HB9VKL": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "HI80": { + "badge": "img/emojis/speech.png", + "message": "GridTracker Translator" + }, + "IW3HMH": { + "badge": "img/emojis/logbook.png", + "message": "Creator of Log4OM" + }, + "K0EG": { + "badge": "img/emojis/books.png", + "message": "GridTracker Documentation" }, "K1JT": { "badge": "img/emojis/star.png", "message": "Creator of FT8 and WSJT-X" }, + "K2PF": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "K4TLS": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "K5DCC": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "K5TUX": { + "badge": "img/emojis/penguin.png", + "message": "GridTracker Partner" + }, + "K7CGA": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "K7YD": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "K8VSY": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "K9AN": { "badge": "img/emojis/star.png", "message": "Co-Creator of FT8" }, - "N2VFL": { - "badge": "img/emojis/trophy.png", - "message": "GridTracker Developer" + "K9MIH": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" }, - "NR0Q": { + "KA0AZS": { + "badge": "img/emojis/pizza.png", + "message": "GridTracker Tester" + }, + "KA4JON": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KA7JAZ": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KB2BK": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KB2YSI": { "badge": "img/emojis/coffee.png", "message": "GridTracker Developer" }, - "KF5QHQ": { - "badge": "img/emojis/trophy.png", - "message": "GridTracker Developer" + "KB4RSM": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" }, - "WA4YA": { + "KB5ITC": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KC4HN": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KC7ZXY": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KD0YTE": { + "badge": "img/emojis/pizza.png", + "message": "GridTracker Tester" + }, + "KD9QGP": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KE0UL": { + "badge": "img/emojis/grandfather.png", + "message": "GridTracker's Grandfather" + }, + "KF5QHQ": { "badge": "img/emojis/trophy.png", "message": "GridTracker Developer" }, @@ -31,21 +147,93 @@ "badge": "img/emojis/flatbread.png", "message": "GridTracker Developer" }, - "K5TUX": { - "badge": "img/emojis/penguin.png", - "message": "GridTracker Partner" + "KJ7KRN": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" }, - "KA0AZS": { - "badge": "img/emojis/pizza.png", - "message": "GridTracker Tester" + "KO4BCN": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" }, - "G1MIC": { - "badge": "img/emojis/pizza.png", - "message": "GridTracker Tester" + "KQ4Y": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" }, - "KD0YTE": { - "badge": "img/emojis/pizza.png", - "message": "GridTracker Tester" + "LA6YJA": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "LU7DK": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "N0TTL": { + "badge": "img/emojis/star.png", + "message": "Creator of GridTracker" + }, + "N2VFL": { + "badge": "img/emojis/trophy.png", + "message": "GridTracker Developer" + }, + "N3CAN": { + "badge": "img/emojis/books.png", + "message": "GridTracker Documentation" + }, + "N3TQM": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "N4MCC": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "N6GEB": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "N7HQ": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "NR0Q": { + "badge": "img/emojis/coffee.png", + "message": "GridTracker Developer" + }, + "OH1LEU": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "OH3NZW": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "ON7IVE": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "OZ1LNR": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "PA0LMA": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "VA7CND": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "VE3FMQ": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "VE7LGP": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "W0YRE": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" }, "W4IPA": { "badge": "img/emojis/beer-mug.png", @@ -55,8 +243,32 @@ "badge": "img/emojis/pizza.png", "message": "GridTracker Tester" }, - "IW3HMH": { - "badge": "img/emojis/logbook.png", - "message": "Creator of Log4OM" + "W6FVO": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "W9LL": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "W9VZR": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "WA4YA": { + "badge": "img/emojis/trophy.png", + "message": "GridTracker Developer" + }, + "WB6RJH": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "WD5FBW": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "WS4S": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" } } \ No newline at end of file diff --git a/package.nw/img/emojis/books.png b/package.nw/img/emojis/books.png new file mode 100644 index 0000000000000000000000000000000000000000..cdcbcb8efce3c3922a226c3f32b72d6cad911427 GIT binary patch literal 714 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAk#fdHQnSN8&+4R!fSX)`CKo%u3> z$JMIST;8H*ZKm=3_ zR0Cu{j0KtlQ~*@A@6_dFrx|TA`+m)pH*MItdH*TR!euk&?)tMtqbhjg*GYW-iyynq zyq31^$>fp~i#P3^)^V_D^~uLuvhN?8+qCD!!lnx|jyzd+=HZ%EbFZD-yMJ}dv%Lln zfqs!K3GxeO5XfkFA5g7eaK2&t{ml*U_Zu|qZ+O3c|N7+t{RL(g?q3-g80UDpIEGZ* zI(t3S>5zc{YeK+=6&*T@nkHRhz0lPZ^u6`>eXm}tZK|56NEabvXWiuI+&fjx1ST z8J+^uIG&t7p(>P=)Ewx1DbZm|=0e`%L17{f0zx?h)9;vW`nY2If8O>h?4Lx-ZfSeDayFTvO>>nwl$DZjIxPm)4xbc?>tO*rxqNW|HwWPREdb^JK@;{&0bkkT@98IY|N-p$wj`elF{r5}E*WbXa8o literal 0 HcmV?d00001 diff --git a/package.nw/img/emojis/grandfather.png b/package.nw/img/emojis/grandfather.png new file mode 100644 index 0000000000000000000000000000000000000000..75647b8dbc58e3aea84b874f09ccc7cdadb43665 GIT binary patch literal 941 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY3?!3`olAk#t^l79SN8&+@AuBZ(Z$PG;A{v3 zSp>ocl33BTtCxXVp4_|$SN7q~`G+?yeZ70`QeXM?tC#OA=|55se)-Ck3QMhn(>u<$ z<)q`H-&?>O%bGG0Xmp==u>_nV`S8#k?uu`3$ zcR{WKZ|eoIXHL%#r9^F>n;w5+W5KFJw-@|Nm5ETX;(j-g%T96Wzo&K<%8bVP=It$J z)75^@Gh}eNwRkDNWW1)d`$o;sgA=u0Ch+w=dDHe;;j2Nd>#^5g7=z^aO_$7EzT2X% z{ef-Y`*}-NvhiDX`7kwEDEeF4w9KiT^pM|i!+tAwzWdovY>wSYnfKB^>0O|{$xNkm ztH72ii#a6?m&)|Y$ef)hzkgrbpVlkS|K5s!QvQF-@p`u-{Ij`h|0p(d&X1b^kl~EE zWa?D~4gEQ>FFI z_RPH#BGUIcW`*CVj_lhs^WrDg>hLKG<@i=_|M%VJe{SoYgse4c^R5(Fdh4`5;=Cpy znxx0Iv&U?|4+vYKI!kRwqeF12r3-cnHA@bGBct26EMXEoi}-*#?i>&gYqM>n@NcQj6$(gf79du@yT zt0+mJrGh0ve!&b42?6)}14T)uD9 z$NiaZlkTjQ{XacDQL1|KTRDv@%v*x4mHsa?Q_<|RWqkYM$m(c=yUUi!9^5ItKTUi7 zm$V13IQcKKb9!wxS+#49mDOj@g?d_^to1=s6ZMjGvotCu%sgWDQtkE19^s&uGZwtp zS@y%Hf8EVv#Vpy*%(qms7w7x0)m1fqye@6}%}x0qF0FXwwrYpx)TWjtS@%6pakaRF zwZ)}fjY_{WgCX?neb0%9oCO{4C9bp-J$1?8?IE9|(=!v3C*PXD;<+Zrewj&^1|$2X z*QakPM0p(EKAj`}e%4l{x+dq9%T=tuJrhhkpOCO?mdm1;<5x|6l73sxdRUVzd{Od5 z%U=c`pL8`9qiYi3CN&B=Mn-nh7bZ;bFsjMBeZ8?!vg3;*cTW8$@xZEex1>q}e=Yc% z{n*gY!+zql#=Do?61-yBueIvsp3yD+E&u3OwX(WG+yVnoq9aa!v zxxmPyQ}(ED^8f$Wy>g$(ZR^UN;r%-=#*HmIQM}%B=CnCGPgl<5S~n|t)t89i*@d&V zTHoJcepqt*3FnVxGLtL4>f}w`=ZW2y30u8qf!UvPM*64N_?Ld#6!pMos_d&LMK>~w zEGI2F#K>yBS|)&3|Afq>kC!Y~?CkB$)hmi%VOZS27@@I&fkTADVWErTVi)H{E}z`L z)a2ZLTv@c2yTJ1H^yeqPo@2G$rr*E#YvP4(MO(tyUv5{k&bj;Ee~QN@p^2hvUr9}j z%{jGNOuOCnX7Q3Lg;4)(YdQnAn(lJ*o@BCeR$yqgPVSApZYMby&n(GUvGB5anyOW7 z^Zbi1rCrsnY!7eT&oWK*=`F)`=ht;q{iv&UT^{+xwquupVwNSc}w!OeElc1hTW`!!5qsh34X% Date: Tue, 15 Jun 2021 21:03:15 -0500 Subject: [PATCH 006/125] Initial workup for LoTW throttling & diff fetching --- package.nw/lib/adif.js | 98 ++++++- package.nw/lib/defaults.js | 526 +++++++++++++++++++------------------ package.nw/lib/gt.js | 7 +- 3 files changed, 365 insertions(+), 266 deletions(-) diff --git a/package.nw/lib/adif.js b/package.nw/lib/adif.js index 759e475..082151a 100644 --- a/package.nw/lib/adif.js +++ b/package.nw/lib/adif.js @@ -86,6 +86,36 @@ function onAdiLoadComplete(adiBuffer, saveAdifFile, adifFileName, newFile) { let finalMode = ""; + let appLoTW_RXQSO = findAdiField( + activeAdifArray[x], + "APP_LoTW_RXQSO" + ); + + if (appLoTW_RXQSO != "") + { + let dRXQSO = Date.parse(appLoTW_RXQSO); + let dLastLOTW_QSO = Date.parse(g_adifLogSettings.lastFetch.lotw_qso); + if ((isNaN(dRXQSO) == false) && (isNaN(dLastLOTW_QSO) == false) && (dRXQSO > dLastLOTW_QSO)) + { + g_adifLogSettings.lastFetch.lotw_qso = appLoTW_RXQSO; + } + } + + let appLoTW_RXQSL = findAdiField( + activeAdifArray[x], + "APP_LoTW_RXQSL" + ); + + if (appLoTW_RXQSL != "") + { + let dRXQSL = Date.parse(appLoTW_RXQSL); + let dLastLOTW_QSL = Date.parse(g_adifLogSettings.lastFetch.lotw_qsl); + if ((isNaN(dRXQSL) == false) && (isNaN(dLastLOTW_QSL) == false) && (dRXQSL > dLastLOTW_QSL)) + { + g_adifLogSettings.lastFetch.lotw_qso = appLoTW_RXQSO; + } + } + if (activeAdifArray[x].length > 3) { if (activeAdifLogMode) @@ -572,6 +602,16 @@ function lotwCallback(buffer, flag) var shouldAppend = false; g_fromDirectCallNoFileDialog = true; + // Extract header showing last fetched date from call + var lotwQSHeader = rawAdiBuffer.match(/^(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2})/m); + if (lotwQSHeader !== null) + { + if (lotwQSHeader[1].toUpperCase() == "QSORX") + { g_adifLogSettings.lastFetch.lotw_qso = lotwQSHeader[2] } + elseif(lotwQSHeader[1].toUpperCase() == "QSL") + g_adifLogSettings.lastFetch.lotw_qsl = lotwQSHeader[2]; + } + rawAdiBuffer = cleanAndPrepADIF( "lotw.adif", rawAdiBuffer, @@ -623,16 +663,26 @@ var g_isGettingLOTW = false; function grabLOtWLog(test) { - if (g_isGettingLOTW == false) + var dLoTWQSO = Date.parse(g_adifLogSettings.lastFetch.lotw_qso); + var dLoTWQSL = Date.parse(g_adifLogSettings.lastFetch.lotw_qsl); + var tmpDate = ((new Date().getTime()) - 300); + + // Be nice to LoTW and only fetch if last fetch was > 5 mins ago + if ((g_isGettingLOTW == false) && + (((isNaN(dLoTWQSO) == false) && (dLoTWQSO < tmpDate)) || + ((isNaN(dLoTWQSL) == false) && (dLoTWQSL < tmpDate)) + )) { var lastQSLDateString = - "&qso_qsorxsince=1945-01-01&qso_qslsince=1945-01-01"; + "&qso_qsorxsince=" + g_adifLogSettings.lastFetch.lotw_qso + + "&qso_qslsince=" + g_adifLogSettings.lastFetch.lotw_qsl; if (test == true) { lotwTestResult.innerHTML = "Testing"; lastQSLDateString = "&qso_qsosince=2100-01-01"; } + // Fetch QSOs getABuffer( "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + lotwLogin.value + @@ -648,6 +698,27 @@ function grabLOtWLog(test) "g_isGettingLOTW", 120000 ); + + // Fetch QSLs + var tQSO = setTimeout(function() + { + if (test == false) lotwLogLoaded = true; + getABuffer( + "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + + lotwLogin.value + + "&password=" + + encodeURIComponent(lotwPassword.value) + + "&qso_query=1&qso_qsl=yes&qso_qsldetail=yes&qso_withown=yes" + + lastQSLDateString, + lotwCallback, + test, + "https", + 443, + lotwLogImg, + "g_isGettingLOTW", + 120000 + ); + }, 10000); } } @@ -1005,6 +1076,22 @@ function loadGtQSOLogFile() } } +var lotwLogLoaded = false; +function loadLoTWLogFile() +{ + var fs = require("fs"); + + if (fs.existsSync(g_LoTWLogFile)) + { + var rawAdiBuffer = fs.readFileSync(g_LoTWLogFile); + + g_fromDirectCallNoFileDialog = true; + + onAdiLoadComplete(rawAdiBuffer, false); + lotwLogLoaded = true; + } +} + function loadWsjtLogFile() { var fs = require("fs"); @@ -1297,8 +1384,11 @@ function startupAdifLoadCheck() { if (g_appSettings.gtFlagImgSrc == 1) showGtFlags(); - // Commented out to stop execution on startup - // if (loadLOTWCheckBox.checked == true) grabLOtWLog(false); + if (loadLOTWCheckBox.checked == true) + { + loadLoTWLogFile(); + grabLOtWLog(false); + } if (loadQRZCheckBox.checked == true) grabQrzComLog(false); diff --git a/package.nw/lib/defaults.js b/package.nw/lib/defaults.js index 58077ae..51a9bee 100644 --- a/package.nw/lib/defaults.js +++ b/package.nw/lib/defaults.js @@ -1,261 +1,265 @@ -var validSettings = [ - "HRDLogbookLogSettings", - "N1MMSettings", - "acLogSettings", - "adifLogSettings", - "alertSettings", - "appSettings", - "audioSettings", - "awardTracker", - "bandActivity", - "blockedCQ", - "blockedCalls", - "blockedDxcc", - "callsignLookups", - "classicAlerts", - "classicAlertsVersion", - "currentVersion", - "dxkLogSettings", - "log4OMSettings", - "mapMemory", - "mapSettings", - "msgSettings", - "receptionSettings", - "rosterSettings", - "savedAlerts", - "speechSettings", - "startupLogs", - "trustedQslSettings", - "screenSettings", - "legendColors" -]; - -var def_appSettings = { - alertMute: 0, - rosterAlwaysOnTop: false, - centerGridsquare: "", - chatUUID: "", - crScript: 0, - distanceUnit: "MI", - earthImgSrc: 0, - gridViewMode: 3, - gridsquareDecayTime: 300, - gtAgree: "", - gtBandFilter: "", - gtFlagImgSrc: 0, - gtModeFilter: "", - gtPropFilter: "mixed", - gtMsgEnable: true, - gtShareEnable: true, - heatEnabled: 0, - loadAdifAtStartup: false, - lookupLoginCq: "", - lookupLoginQrz: "", - lookupLoginQth: "", - lookupOnTx: false, - lookupCloseLog: false, - lookupMerge: true, - lookupMissingGrid: false, - lookupPasswordCq: "", - lookupPasswordQrz: "", - lookupPasswordQth: "", - lookupService: "CALLOOK", - lookupCallookPreferred: false, - moonPath: 0, - moonTrack: 0, - mouseTrack: 0, - multicast: false, - myBand: "OOB", - myDEGrid: "", - myDEcall: "NOCALL", - myMode: "", - myRawCall: "NOCALL", - myRawFreq: "", - myRawGrid: "", - pathWidthWeight: 1.0, - pushPinMode: false, - qrzPathWidthWeight: 1.2, - sixWideMode: 0, - savedAppData: null, - soundCard: "default", - spotsEnabled: 0, - stopAskingVersion: false, - useLocalTime: 0, - wsjtForwardUdpEnable: false, - wsjtForwardUdpIp: "127.0.0.1", - wsjtForwardUdpPort: 2238, - wsjtIP: "", - wsjtUdpPort: 0, - workingCallsignEnable: false, - workingCallsigns: {}, - workingDateEnable: false, - workingDate: 0, - gtSpotEnable: true -}; - -var def_mapSettings = { - animate: true, - animateSpeed: 4, - CQhilite: true, - fitQRZ: false, - focusRig: true, - gridAlpha: 136, - haltAllOnTx: true, - legend: true, - longitude: 0.0, - latitude: 0.0, - loudness: 1, - mapIndex: 19, - mergeOverlay: false, - mouseOver: true, - nightLoudness: 0.8, - nightMapEnable: false, - nightMapIndex: 20, - nightPathColor: 361, - nightQrzPathColor: 1, - offlineMode: false, - pathColor: 0, - qrzDxccFallback: false, - qrzPathColor: 1, - rosterTime: 120, - shadow: 0.1, - splitQSL: true, - strikes: false, - strikesAlert: 2, - strikesGlobal: false, - strikesNotify: false, - trafficDecode: true, - usNexrad: false, - zoom: 4, - mapTrans: 0.5 -}; - -var def_adifLogSettings = { - menu: { - buttonAdifCheckBox: false, - buttonClubCheckBox: false, - buttonLOTWCheckBox: false, - buttonQRZCheckBox: false, - buttonPsk24CheckBox: true - }, - startup: { - loadAdifCheckBox: false, - loadPsk24CheckBox: false, - loadQRZCheckBox: false, - loadLOTWCheckBox: false, - loadClubCheckBox: false, - loadGTCheckBox: true - }, - qsolog: { - logQRZqsoCheckBox: false, - logGTqsoCheckBox: true, - logLOTWqsoCheckBox: false, - logHRDLOGqsoCheckBox: false, - logClubqsoCheckBox: false, - logCloudlogQSOCheckBox: false, - logeQSLQSOCheckBox: false - }, - nickname: { - nicknameeQSLCheckBox: false - }, - text: { - lotwLogin: "", - clubCall: "", - clubEmail: "", - clubPassword: "", - lotwPassword: "", - lotwTrusted: "", - lotwStation: "", - qrzApiKey: "", - HRDLOGCallsign: "", - HRDLOGUploadCode: "", - CloudlogURL: "http://127.0.0.1/index.php/api/qso", - CloudlogAPI: "", - eQSLUser: "", - eQSLPassword: "", - eQSLNickname: "" - }, - downloads: {} -}; - -var def_msgSettings = { - msgAlertSelect: 1, - msgAlertWord: "New chat message", - msgAlertMedia: "none", - msgFrequencySelect: 0, - msgActionSelect: 1, - msgAwaySelect: 0, - msgAwayText: "I am away from the shack at the moment" -}; - -var def_receptionSettings = { - lastSequenceNumber: "0", // Treat as a string, it's friggin big - lastDownloadTimeSec: 0, - viewHistoryTimeSec: 900, - viewPaths: false, - pathColor: -1, - pathNightColor: 361, - spotWidth: 0.8, - mergeSpots: true -}; - -var def_N1MMSettings = { - enable: false, - port: 2333, - ip: "127.0.0.1" -}; -var def_log4OMSettings = { - enable: false, - port: 2236, - ip: "127.0.0.1" -}; -var def_dxkLogSettings = { - enable: false, - port: 52000, - ip: "127.0.0.1" -}; -var def_HRDLogbookLogSettings = { - enable: false, - port: 7826, - ip: "127.0.0.1" -}; -var def_acLogSettings = { - enable: false, - port: 1100, - ip: "127.0.0.1" -}; -var def_trustedQslSettings = { - stationFile: "", - stationFileValid: false, - binaryFile: "", - binaryFileValid: false -}; -var def_callsignLookups = { - lotwUseEnable: true, - lotwWeeklyEnable: true, - lotwLastUpdate: 0, - eqslUseEnable: true, - eqslWeeklyEnable: true, - eqslLastUpdate: 0, - ulsUseEnable: true, - ulsWeeklyEnable: true, - ulsLastUpdate: 0, - oqrsUseEnable: false, - oqrsWeeklyEnable: false, - oqrsLastUpdate: 0 -}; - -var def_bandActivity = { - lastUpdate: {}, - lines: {} -}; - -var def_legendColors = { - QSO: "#EEEE00", - QSL: "#EE0000", - QSX: "#1111EE", - CQ: "#00FF00", - CQDX: "#00FFFF", - QRZ: "#FFFF00", - QTH: "#FFA600" -}; +var validSettings = [ + "HRDLogbookLogSettings", + "N1MMSettings", + "acLogSettings", + "adifLogSettings", + "alertSettings", + "appSettings", + "audioSettings", + "awardTracker", + "bandActivity", + "blockedCQ", + "blockedCalls", + "blockedDxcc", + "callsignLookups", + "classicAlerts", + "classicAlertsVersion", + "currentVersion", + "dxkLogSettings", + "log4OMSettings", + "mapMemory", + "mapSettings", + "msgSettings", + "receptionSettings", + "rosterSettings", + "savedAlerts", + "speechSettings", + "startupLogs", + "trustedQslSettings", + "screenSettings", + "legendColors" +]; + +var def_appSettings = { + alertMute: 0, + rosterAlwaysOnTop: false, + centerGridsquare: "", + chatUUID: "", + crScript: 0, + distanceUnit: "MI", + earthImgSrc: 0, + gridViewMode: 3, + gridsquareDecayTime: 300, + gtAgree: "", + gtBandFilter: "", + gtFlagImgSrc: 0, + gtModeFilter: "", + gtPropFilter: "mixed", + gtMsgEnable: true, + gtShareEnable: true, + heatEnabled: 0, + loadAdifAtStartup: false, + lookupLoginCq: "", + lookupLoginQrz: "", + lookupLoginQth: "", + lookupOnTx: false, + lookupCloseLog: false, + lookupMerge: true, + lookupMissingGrid: false, + lookupPasswordCq: "", + lookupPasswordQrz: "", + lookupPasswordQth: "", + lookupService: "CALLOOK", + lookupCallookPreferred: false, + moonPath: 0, + moonTrack: 0, + mouseTrack: 0, + multicast: false, + myBand: "OOB", + myDEGrid: "", + myDEcall: "NOCALL", + myMode: "", + myRawCall: "NOCALL", + myRawFreq: "", + myRawGrid: "", + pathWidthWeight: 1.0, + pushPinMode: false, + qrzPathWidthWeight: 1.2, + sixWideMode: 0, + savedAppData: null, + soundCard: "default", + spotsEnabled: 0, + stopAskingVersion: false, + useLocalTime: 0, + wsjtForwardUdpEnable: false, + wsjtForwardUdpIp: "127.0.0.1", + wsjtForwardUdpPort: 2238, + wsjtIP: "", + wsjtUdpPort: 0, + workingCallsignEnable: false, + workingCallsigns: {}, + workingDateEnable: false, + workingDate: 0, + gtSpotEnable: true +}; + +var def_mapSettings = { + animate: true, + animateSpeed: 4, + CQhilite: true, + fitQRZ: false, + focusRig: true, + gridAlpha: 136, + haltAllOnTx: true, + legend: true, + longitude: 0.0, + latitude: 0.0, + loudness: 1, + mapIndex: 19, + mergeOverlay: false, + mouseOver: true, + nightLoudness: 0.8, + nightMapEnable: false, + nightMapIndex: 20, + nightPathColor: 361, + nightQrzPathColor: 1, + offlineMode: false, + pathColor: 0, + qrzDxccFallback: false, + qrzPathColor: 1, + rosterTime: 120, + shadow: 0.1, + splitQSL: true, + strikes: false, + strikesAlert: 2, + strikesGlobal: false, + strikesNotify: false, + trafficDecode: true, + usNexrad: false, + zoom: 4, + mapTrans: 0.5 +}; + +var def_adifLogSettings = { + menu: { + buttonAdifCheckBox: false, + buttonClubCheckBox: false, + buttonLOTWCheckBox: false, + buttonQRZCheckBox: false, + buttonPsk24CheckBox: true + }, + startup: { + loadAdifCheckBox: false, + loadPsk24CheckBox: false, + loadQRZCheckBox: false, + loadLOTWCheckBox: false, + loadClubCheckBox: false, + loadGTCheckBox: true + }, + qsolog: { + logQRZqsoCheckBox: false, + logGTqsoCheckBox: true, + logLOTWqsoCheckBox: false, + logHRDLOGqsoCheckBox: false, + logClubqsoCheckBox: false, + logCloudlogQSOCheckBox: false, + logeQSLQSOCheckBox: false + }, + nickname: { + nicknameeQSLCheckBox: false + }, + text: { + lotwLogin: "", + clubCall: "", + clubEmail: "", + clubPassword: "", + lotwPassword: "", + lotwTrusted: "", + lotwStation: "", + qrzApiKey: "", + HRDLOGCallsign: "", + HRDLOGUploadCode: "", + CloudlogURL: "http://127.0.0.1/index.php/api/qso", + CloudlogAPI: "", + eQSLUser: "", + eQSLPassword: "", + eQSLNickname: "" + }, + downloads: {}, + lastFetch: { + lotw_qso: "1970-01-01", + lotw_qsl: "1970-01-01" + } +}; + +var def_msgSettings = { + msgAlertSelect: 1, + msgAlertWord: "New chat message", + msgAlertMedia: "none", + msgFrequencySelect: 0, + msgActionSelect: 1, + msgAwaySelect: 0, + msgAwayText: "I am away from the shack at the moment" +}; + +var def_receptionSettings = { + lastSequenceNumber: "0", // Treat as a string, it's friggin big + lastDownloadTimeSec: 0, + viewHistoryTimeSec: 900, + viewPaths: false, + pathColor: -1, + pathNightColor: 361, + spotWidth: 0.8, + mergeSpots: true +}; + +var def_N1MMSettings = { + enable: false, + port: 2333, + ip: "127.0.0.1" +}; +var def_log4OMSettings = { + enable: false, + port: 2236, + ip: "127.0.0.1" +}; +var def_dxkLogSettings = { + enable: false, + port: 52000, + ip: "127.0.0.1" +}; +var def_HRDLogbookLogSettings = { + enable: false, + port: 7826, + ip: "127.0.0.1" +}; +var def_acLogSettings = { + enable: false, + port: 1100, + ip: "127.0.0.1" +}; +var def_trustedQslSettings = { + stationFile: "", + stationFileValid: false, + binaryFile: "", + binaryFileValid: false +}; +var def_callsignLookups = { + lotwUseEnable: true, + lotwWeeklyEnable: true, + lotwLastUpdate: 0, + eqslUseEnable: true, + eqslWeeklyEnable: true, + eqslLastUpdate: 0, + ulsUseEnable: true, + ulsWeeklyEnable: true, + ulsLastUpdate: 0, + oqrsUseEnable: false, + oqrsWeeklyEnable: false, + oqrsLastUpdate: 0 +}; + +var def_bandActivity = { + lastUpdate: {}, + lines: {} +}; + +var def_legendColors = { + QSO: "#EEEE00", + QSL: "#EE0000", + QSX: "#1111EE", + CQ: "#00FF00", + CQDX: "#00FFFF", + QRZ: "#FFFF00", + QTH: "#FFA600" +}; diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index c332732..a4b4bd4 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -504,6 +504,7 @@ var g_NWappData = ""; var g_screenshotDir = ""; var g_scriptDir = ""; var g_qsoLogFile = ""; +var g_LoTWLogFile = ""; var g_userMediaDir = ""; var g_gtMediaDir = path.resolve("./media"); var g_localeString = navigator.language; @@ -5130,6 +5131,8 @@ function clearLogFilesAndCounts() tryToDeleteLog("qrz.adif"); tryToDeleteLog("clublog.adif"); g_adifLogSettings.downloads = {}; + g_adifLogSettings.lastFetch.lotw_qso = "1940-01-01"; + g_adifLogSettings.lastFetch.lotw_qsl = "1940-01-01"; localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); } @@ -12174,7 +12177,8 @@ function callsignToDxcc(insign) var end = parts.length - 1; if (ancPrefixes.includes(parts[end])) { - if (parts[end].toUpperCase() == "MM") { + if (parts[end].toUpperCase() == "MM") + { return -1; } parts.pop(); @@ -15852,6 +15856,7 @@ function mediaCheck() g_scriptDir += g_dirSeperator; g_qsoLogFile = path.join(g_appData, "GridTracker_QSO.adif"); + g_LoTWLogFile = path.join(g_appData, "lotw.adif"); logEventMedia.appendChild(newOption("none", "None")); msgAlertMedia.appendChild(newOption("none", "Select File")); From 28432cb63b88e2a9c7dd5aae0875c6b020301b2a Mon Sep 17 00:00:00 2001 From: Santiago Mejia Date: Wed, 16 Jun 2021 19:59:05 +0000 Subject: [PATCH 007/125] Upload New File --- package.nw/gt_update__spanish_.pdf | Bin 0 -> 155756 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 package.nw/gt_update__spanish_.pdf diff --git a/package.nw/gt_update__spanish_.pdf b/package.nw/gt_update__spanish_.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5bdf4042e1215b63c77948db4e8545f8a3e4d949 GIT binary patch literal 155756 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 w=JNqgTR6JIo<1BgucoBmN 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 Date: Thu, 17 Jun 2021 17:56:37 -0500 Subject: [PATCH 008/125] More LoTW Fixes to do diff fetching --- package.nw/lib/adif.js | 132 +++++++++++++++++++++++++---------------- package.nw/lib/gt.js | 8 ++- 2 files changed, 88 insertions(+), 52 deletions(-) diff --git a/package.nw/lib/adif.js b/package.nw/lib/adif.js index 082151a..6cdd731 100644 --- a/package.nw/lib/adif.js +++ b/package.nw/lib/adif.js @@ -112,7 +112,7 @@ function onAdiLoadComplete(adiBuffer, saveAdifFile, adifFileName, newFile) let dLastLOTW_QSL = Date.parse(g_adifLogSettings.lastFetch.lotw_qsl); if ((isNaN(dRXQSL) == false) && (isNaN(dLastLOTW_QSL) == false) && (dRXQSL > dLastLOTW_QSL)) { - g_adifLogSettings.lastFetch.lotw_qso = appLoTW_RXQSO; + g_adifLogSettings.lastFetch.lotw_qsl = appLoTW_RXQSL; } } @@ -607,9 +607,13 @@ function lotwCallback(buffer, flag) if (lotwQSHeader !== null) { if (lotwQSHeader[1].toUpperCase() == "QSORX") - { g_adifLogSettings.lastFetch.lotw_qso = lotwQSHeader[2] } - elseif(lotwQSHeader[1].toUpperCase() == "QSL") - g_adifLogSettings.lastFetch.lotw_qsl = lotwQSHeader[2]; + { + g_adifLogSettings.lastFetch.lotw_qso = lotwQSHeader[2] + } + else if (lotwQSHeader[1].toUpperCase() == "QSL") + { + g_adifLogSettings.lastFetch.lotw_qsl = lotwQSHeader[2]; + } } rawAdiBuffer = cleanAndPrepADIF( @@ -663,62 +667,88 @@ var g_isGettingLOTW = false; function grabLOtWLog(test) { - var dLoTWQSO = Date.parse(g_adifLogSettings.lastFetch.lotw_qso); - var dLoTWQSL = Date.parse(g_adifLogSettings.lastFetch.lotw_qsl); - var tmpDate = ((new Date().getTime()) - 300); + var lastQSLDateString = ""; - // Be nice to LoTW and only fetch if last fetch was > 5 mins ago - if ((g_isGettingLOTW == false) && - (((isNaN(dLoTWQSO) == false) && (dLoTWQSO < tmpDate)) || - ((isNaN(dLoTWQSL) == false) && (dLoTWQSL < tmpDate)) - )) + if (test == true && g_isGettingLOTW == false) { - var lastQSLDateString = - "&qso_qsorxsince=" + g_adifLogSettings.lastFetch.lotw_qso + - "&qso_qslsince=" + g_adifLogSettings.lastFetch.lotw_qsl; - if (test == true) - { - lotwTestResult.innerHTML = "Testing"; - lastQSLDateString = "&qso_qsosince=2100-01-01"; - } + lotwTestResult.innerHTML = "Testing"; + lastQSLDateString = "&qso_qsosince=2100-01-01"; - // Fetch QSOs + // Fetch Test Results getABuffer( "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + - lotwLogin.value + - "&password=" + - encodeURIComponent(lotwPassword.value) + - "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + - lastQSLDateString, + lotwLogin.value + + "&password=" + + encodeURIComponent(lotwPassword.value) + + "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + + lastQSLDateString, lotwCallback, test, "https", 443, lotwLogImg, "g_isGettingLOTW", + 150000 + ); + } + + if (test == false) + { + setTimeout(grabLoTWQSO, 500); + setTimeout(grabLoTWQSL, 10000); + } +} + +function grabLoTWQSO() +{ + var dLoTWQSO = Date.parse(g_adifLogSettings.lastFetch.lotw_qso); + var tmpDate = ((new Date().getTime()) - 300); + + if ((g_isGettingLOTW == false) && ((isNaN(dLoTWQSO) == false) && (dLoTWQSO < tmpDate))) + { + // Fetch QSOs + lastQSLDateString = "&qso_qsorxsince=" + g_adifLogSettings.lastFetch.lotw_qso; + getABuffer( + "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + + lotwLogin.value + + "&password=" + + encodeURIComponent(lotwPassword.value) + + "&qso_query=1&qso_qsl=no&qso_qsldetail=yes&qso_withown=yes" + + lastQSLDateString, + lotwCallback, + false, + "https", + 443, + lotwLogImg, + "g_isGettingLOTW", 120000 ); + } +} - // Fetch QSLs - var tQSO = setTimeout(function() - { - if (test == false) lotwLogLoaded = true; - getABuffer( - "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + - lotwLogin.value + - "&password=" + - encodeURIComponent(lotwPassword.value) + - "&qso_query=1&qso_qsl=yes&qso_qsldetail=yes&qso_withown=yes" + - lastQSLDateString, - lotwCallback, - test, - "https", - 443, - lotwLogImg, - "g_isGettingLOTW", - 120000 - ); - }, 10000); +function grabLoTWQSL() +{ + var dLoTWQSL = Date.parse(g_adifLogSettings.lastFetch.lotw_qsl); + var tmpDate = ((new Date().getTime()) - 300); + + if ((g_isGettingLOTW == false) && ((isNaN(dLoTWQSL) == false) && (dLoTWQSL < tmpDate))) + { + lastQSLDateString = "&qso_qslsince=" + g_adifLogSettings.lastFetch.lotw_qsl; + getABuffer( + "https://lotw.arrl.org/lotwuser/lotwreport.adi?login=" + + lotwLogin.value + + "&password=" + + encodeURIComponent(lotwPassword.value) + + "&qso_query=1&qso_qsl=yes&qso_qsldetail=yes&qso_withown=yes" + + lastQSLDateString, + lotwCallback, + false, + "https", + 443, + lotwLogImg, + "g_isGettingLOTW", + 120000 + ); } } @@ -1457,11 +1487,6 @@ function getABuffer( }) .on("end", function () { - if (typeof callback === "function") - { - // Call it, since we have confirmed it is callable - callback(fileBuffer, flag, cookies); - } if (typeof stringOfFlag != "undefined") { window[stringOfFlag] = false; @@ -1471,6 +1496,11 @@ function getABuffer( imgToGray.parentNode.style.background = ""; imgToGray.style.webkitFilter = ""; } + if (typeof callback === "function") + { + // Call it, since we have confirmed it is callable + callback(fileBuffer, flag, cookies); + } }) .on("error", function () { diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index a4b4bd4..dca9266 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -237,6 +237,11 @@ function saveLegendColors() localStorage.legendColors = JSON.stringify(g_legendColors); } +function saveAdifSettings() +{ + localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); +} + function saveStartupLogs() { localStorage.startupLogs = JSON.stringify(g_startupLogs); @@ -306,6 +311,7 @@ function saveAndCloseApp() } saveAppSettings(); + saveAdifSettings(); saveMapSettings(); saveLegendColors(); @@ -5133,7 +5139,7 @@ function clearLogFilesAndCounts() g_adifLogSettings.downloads = {}; g_adifLogSettings.lastFetch.lotw_qso = "1940-01-01"; g_adifLogSettings.lastFetch.lotw_qsl = "1940-01-01"; - localStorage.adifLogSettings = JSON.stringify(g_adifLogSettings); + saveAdifSettings(); } function getCurrentBandModeHTML() From e557035070bc3acdd7ac4dc82a07fbdcb6f483ef Mon Sep 17 00:00:00 2001 From: jangliss Date: Fri, 18 Jun 2021 20:28:25 -0500 Subject: [PATCH 009/125] Date.parse behavior to local time instead of UTC --- package.nw/lib/adif.js | 4 ++-- package.nw/lib/gt.js | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/package.nw/lib/adif.js b/package.nw/lib/adif.js index 6cdd731..cb60dee 100644 --- a/package.nw/lib/adif.js +++ b/package.nw/lib/adif.js @@ -701,7 +701,7 @@ function grabLOtWLog(test) function grabLoTWQSO() { - var dLoTWQSO = Date.parse(g_adifLogSettings.lastFetch.lotw_qso); + var dLoTWQSO = Date.parse(dateToISO8601(g_adifLogSettings.lastFetch.lotw_qso, "Z")); var tmpDate = ((new Date().getTime()) - 300); if ((g_isGettingLOTW == false) && ((isNaN(dLoTWQSO) == false) && (dLoTWQSO < tmpDate))) @@ -728,7 +728,7 @@ function grabLoTWQSO() function grabLoTWQSL() { - var dLoTWQSL = Date.parse(g_adifLogSettings.lastFetch.lotw_qsl); + var dLoTWQSL = Date.parse(dateToISO8601(g_adifLogSettings.lastFetch.lotw_qsl, "Z")); var tmpDate = ((new Date().getTime()) - 300); if ((g_isGettingLOTW == false) && ((isNaN(dLoTWQSL) == false) && (dLoTWQSL < tmpDate))) diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index dca9266..39f45c8 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -910,6 +910,28 @@ function userTimeString(Msec) return dateToString(dateTime); } +function dateToISO8601(dString, tZone) +{ + var retDate = ""; + var tZone = (typeof tZone !== "undefined") ? tZone : "Z"; + var dateParts = dString.match(/(\d{4}-\d{2}-\d{2})(\s+(\d{2}:\d{2}:\d{2}))?/); + + if (dateParts !== null) + { + retDate = dateParts[1] + if ((typeof dateParts[3]) !== "undefined") + { + retDate += "T" + dateParts[3] + ".000" + tZone; + } + else + { + retDate += "T00:00:00.000" + tZone; + } + } + + return retDate; +} + function getWpx(callsign) { var prefix = null; From bfff9fa8feb9fc14fdc987504c40c47d24c0187d Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sat, 19 Jun 2021 11:17:29 -0500 Subject: [PATCH 010/125] add functions to get acks json off website and overwrite file --- package.nw/lib/gt.js | 553 ++++++++++++++++++------------------------- 1 file changed, 231 insertions(+), 322 deletions(-) diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index c332732..325c2d1 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -6,8 +6,7 @@ var gtVersion = parseInt(pjson.version.replace(/\./g, "")); var gtBeta = pjson.betaVersion; var g_startVersion = 0; -if (typeof localStorage.currentVersion != "undefined") -{ g_startVersion = localStorage.currentVersion; } +if (typeof localStorage.currentVersion != "undefined") { g_startVersion = localStorage.currentVersion; } if ( typeof localStorage.currentVersion == "undefined" || @@ -120,7 +119,7 @@ function loadAllSettings() // one-time override of oams pop-up messages: if pop-ups disabled // and new version, reset msgActionSelect to 1 (pop up) if (g_msgSettings.msgActionSelect == 0 && - String(gtVersion) != String(g_startVersion)) + String(gtVersion) != String(g_startVersion)) { g_msgSettings.msgActionSelect = 1; localStorage.msgSettings = JSON.stringify(g_msgSettings); @@ -324,7 +323,7 @@ function saveAndCloseApp() g_baWindowHandle.window.close(true); g_callRosterWindowHandle.window.close(true); } - catch (e) {} + catch (e) { } nw.App.quit(); } @@ -800,8 +799,7 @@ function toggleOffline() if (g_appSettings.gtShareEnable == true) { gtFlagButton.style.display = "inline-block"; - if (g_appSettings.gtMsgEnable == true) - { msgButton.style.display = "inline-block"; } + if (g_appSettings.gtMsgEnable == true) { msgButton.style.display = "inline-block"; } else msgButton.style.display = "none"; } else @@ -876,8 +874,7 @@ function toggleTime() function dateToString(dateTime) { - if (g_appSettings.useLocalTime == 1) - { return dateTime.toLocaleString().replace(/,/g, ""); } + if (g_appSettings.useLocalTime == 1) { return dateTime.toLocaleString().replace(/,/g, ""); } else return dateTime.toUTCString().replace(/GMT/g, "UTC").replace(/,/g, ""); } @@ -921,8 +918,7 @@ function getWpx(callsign) { if (/\d/.test(callsign.charAt(prefixEnd))) { - while (prefixEnd + 1 != end && /\d/.test(callsign.charAt(prefixEnd + 1))) - { prefixEnd++; } + while (prefixEnd + 1 != end && /\d/.test(callsign.charAt(prefixEnd + 1))) { prefixEnd++; } foundPrefix = true; break; } @@ -940,8 +936,7 @@ function setState(details) { var isDigi = details.digital; - if (details.state.substr(0, 2) != "US") - { details.state = "US-" + details.state; } + if (details.state.substr(0, 2) != "US") { details.state = "US-" + details.state; } g_tracker.worked.state[details.state + details.band + details.mode] = true; g_tracker.worked.state[details.state] = true; @@ -1074,8 +1069,7 @@ function addDeDx( details.grid.length < 6 && (details.grid.substr(0, 4) == finalGrid.substr(0, 4) || details.grid.length == 0) - ) - { details.grid = finalGrid; } + ) { details.grid = finalGrid; } } if (finalRSTsent.length > 0) details.RSTsent = finalRSTsent; if (finalRSTrecv.length > 0) details.RSTrecv = finalRSTrecv; @@ -1127,8 +1121,7 @@ function addDeDx( if (details.dxcc > 0 && details.px == null) { details.px = getWpx(finalDXcall); - if (details.px) - { details.zone = Number(details.px.charAt(details.px.length - 1)); } + if (details.px) { details.zone = Number(details.px.charAt(details.px.length - 1)); } } if ( @@ -1500,8 +1493,7 @@ function addDeDx( if (newCallsign.cont == null) { newCallsign.cont = g_worldGeoData[g_dxccToGeoData[finalDxcc]].continent; - if (newCallsign.dxcc == 390 && newCallsign.zone == 1) - { newCallsign.cont = "EU"; } + if (newCallsign.dxcc == 390 && newCallsign.zone == 1) { newCallsign.cont = "EU"; } } } if (finalRSTsent != null) @@ -1572,8 +1564,7 @@ function addDeDx( if ( finalGrid.length == callsign.grid.length && finalGrid != callsign.grid - ) - { callsign.grid = finalGrid; } + ) { callsign.grid = finalGrid; } if (finalRSTsent != null) callsign.RSTsent = finalRSTsent; if (finalRSTrecv != null) callsign.RSTrecv = finalRSTrecv; callsign.vucc_grids = []; @@ -1595,8 +1586,7 @@ function timeoutSetUdpPort() function setUdpPort() { - if (g_setNewUdpPortTimeoutHandle != null) - { window.clearTimeout(g_setNewUdpPortTimeoutHandle); } + if (g_setNewUdpPortTimeoutHandle != null) { window.clearTimeout(g_setNewUdpPortTimeoutHandle); } lastMsgTimeDiv.innerHTML = "..setting.."; g_setNewUdpPortTimeoutHandle = window.setTimeout(timeoutSetUdpPort, 1000); } @@ -1683,8 +1673,7 @@ function changePathWidth() if (width == 0) { - if (typeof g_flightPaths[i].Arrow != "undefined") - { g_layerSources.flight.removeFeature(g_flightPaths[i].Arrow); } + if (typeof g_flightPaths[i].Arrow != "undefined") { g_layerSources.flight.removeFeature(g_flightPaths[i].Arrow); } g_layerSources.flight.removeFeature(g_flightPaths[i]); delete g_flightPaths[i]; g_flightPaths[i] = null; @@ -2095,8 +2084,7 @@ function createTooltTipTable(toolElement) added = true; } } - if (added == true) - { worker = worker.substr(0, worker.length - " / ".length); } + if (added == true) { worker = worker.substr(0, worker.length - " / ".length); } worker += ")"; } if (x + 1 < g_gridToDXCC[toolElement.qth].length) worker += ", "; @@ -2131,8 +2119,7 @@ function createTooltTipTable(toolElement) { for (var KeyIsCall in g_liveGrids[toolElement.qth].rectangle.liveHash) { - if (KeyIsCall in g_liveCallsigns && g_appSettings.gridViewMode == 3) - { newCallList.push(g_liveCallsigns[KeyIsCall]); } + if (KeyIsCall in g_liveCallsigns && g_appSettings.gridViewMode == 3) { newCallList.push(g_liveCallsigns[KeyIsCall]); } } } } @@ -2150,8 +2137,7 @@ function createTooltTipTable(toolElement) } for (var KeyIsCall in toolElement.liveHash) { - if (KeyIsCall in g_liveCallsigns) - { newCallList.push(g_liveCallsigns[KeyIsCall]); } + if (KeyIsCall in g_liveCallsigns) { newCallList.push(g_liveCallsigns[KeyIsCall]); } } } newCallList.sort(compareCallsignTime).reverse(); @@ -2160,15 +2146,11 @@ function createTooltTipTable(toolElement) var callsign = newCallList[x]; var bgDX = " style='font-weight:bold;color:cyan;' "; var bgDE = " style='font-weight:bold;color:yellow;' "; - if (callsign.DXcall == myDEcall) - { bgDX = " style='background-color:cyan;color:#000;font-weight:bold' "; } - if (callsign.DEcall == myDEcall) - { bgDE = " style='background-color:#FFFF00;color:#000;font-weight:bold' "; } - if (typeof callsign.msg == "undefined" || callsign.msg == "") - { callsign.msg = "-"; } + if (callsign.DXcall == myDEcall) { bgDX = " style='background-color:cyan;color:#000;font-weight:bold' "; } + if (callsign.DEcall == myDEcall) { bgDE = " style='background-color:#FFFF00;color:#000;font-weight:bold' "; } + if (typeof callsign.msg == "undefined" || callsign.msg == "") { callsign.msg = "-"; } var ageString = ""; - if (timeNowSec() - callsign.time < 3601) - { ageString = (timeNowSec() - callsign.time).toDHMS(); } + if (timeNowSec() - callsign.time < 3601) { ageString = (timeNowSec() - callsign.time).toDHMS(); } else { ageString = userTimeString(callsign.time * 1000); @@ -2186,8 +2168,7 @@ function createTooltTipTable(toolElement) worker += "" + (callsign.delta > -1 ? callsign.delta : "-") + ""; worker += "" + callsign.RSTsent + ""; worker += "" + callsign.RSTrecv + "" + ""; - if (callsign.DXcall.indexOf("CQ") == 0 || callsign.DXcall == "-") - { worker += callsign.DXcall.formatCallsign(); } + if (callsign.DXcall.indexOf("CQ") == 0 || callsign.DXcall == "-") { worker += callsign.DXcall.formatCallsign(); } else { worker += @@ -2289,13 +2270,10 @@ function createTooltTipTableLogbook(toolElement) var callsign = newCallList[x]; var bgDX = " style='font-weight:bold;color:cyan;' "; var bgDE = " style='font-weight:bold;color:yellow;' "; - if (callsign.DXcall == myDEcall) - { bgDX = " style='background-color:cyan;color:#000;font-weight:bold' "; } - if (callsign.DEcall == myDEcall) - { bgDE = " style='background-color:#FFFF00;color:#000;font-weight:bold' "; } + if (callsign.DXcall == myDEcall) { bgDX = " style='background-color:cyan;color:#000;font-weight:bold' "; } + if (callsign.DEcall == myDEcall) { bgDE = " style='background-color:#FFFF00;color:#000;font-weight:bold' "; } var ageString = ""; - if (timeNowSec() - callsign.time < 3601) - { ageString = (timeNowSec() - callsign.time).toDHMS(); } + if (timeNowSec() - callsign.time < 3601) { ageString = (timeNowSec() - callsign.time).toDHMS(); } else { ageString = userTimeString(callsign.time * 1000); @@ -2313,8 +2291,7 @@ function createTooltTipTableLogbook(toolElement) worker += "" + (callsign.delta > -1 ? callsign.delta : "-") + ""; worker += "" + callsign.RSTsent + ""; worker += "" + callsign.RSTrecv + "" + ""; - if (callsign.DXcall.indexOf("CQ") == 0 || callsign.DXcall == "-") - { worker += callsign.DXcall.formatCallsign(); } + if (callsign.DXcall.indexOf("CQ") == 0 || callsign.DXcall == "-") { worker += callsign.DXcall.formatCallsign(); } else { worker += @@ -2360,15 +2337,15 @@ function createTooltTipTableLogbook(toolElement) if (callsign.DEcall in g_oqrsCallsigns) { worker += - "" + - "✔📬"; + "" + + "✔📬"; } else { worker += - ""; + ""; } } worker += ""; @@ -2398,7 +2375,7 @@ function renderTooltipWindow(feature) g_popupWindowHandle.width = parseInt(positionInfo.width) + 20; g_popupWindowHandle.height = parseInt(positionInfo.height) + 50; } - catch (e) {} + catch (e) { } } } @@ -2486,7 +2463,7 @@ function openConditionsWindow() g_conditionsWindowHandle.hide(); } } - catch (e) {} + catch (e) { } } } @@ -2577,7 +2554,7 @@ function openCallRosterWindow(show = true) g_callRosterWindowHandle.hide(); } } - catch (e) {} + catch (e) { } } } @@ -2589,7 +2566,7 @@ function updateRosterWorked() { g_callRosterWindowHandle.window.updateWorked(); } - catch (e) {} + catch (e) { } } } @@ -2601,7 +2578,7 @@ function updateRosterInstances() { g_callRosterWindowHandle.window.updateInstances(); } - catch (e) {} + catch (e) { } } } @@ -2658,7 +2635,7 @@ function openStatsWindow(show = true) g_statsWindowHandle.hide(); } } - catch (e) {} + catch (e) { } } } @@ -2703,7 +2680,7 @@ function showMessaging(show = true, cid) g_chatWindowHandle.focus(); if (typeof cid != "undefined") g_chatWindowHandle.window.openId(cid); } - catch (e) {} + catch (e) { } } } @@ -2757,7 +2734,7 @@ function onRightClickGridSquare(feature) { renderTooltipWindow(feature); } - catch (e) {} + catch (e) { } } mouseOutOfDataItem(); } @@ -2796,8 +2773,7 @@ function tempGridToBox(iQTH, oldGrid, borderColor, boxColor, layer) var LL = squareToLatLong(iQTH.substr(0, 4)); if (oldGrid) { - if (g_layerSources.temp.hasFeature(oldGrid)) - { g_layerSources.temp.removeFeature(oldGrid); } + if (g_layerSources.temp.hasFeature(oldGrid)) { g_layerSources.temp.removeFeature(oldGrid); } } var bounds = [ [LL.lo1, LL.la1], @@ -2889,8 +2865,7 @@ function onMyKeyDown(event) var param2 = null; if (typeof g_hotKeys[event.code].param2 != "undefined") { - if (typeof event[g_hotKeys[event.code].param2] != "undefined") - { param2 = event[g_hotKeys[event.code].param2]; } + if (typeof event[g_hotKeys[event.code].param2] != "undefined") { param2 = event[g_hotKeys[event.code].param2]; } } g_hotKeys[event.code].func(g_hotKeys[event.code].param1, param2); } @@ -2906,8 +2881,7 @@ function onMyKeyDown(event) var param2 = null; if (typeof g_hotKeys[event.key].param2 != "undefined") { - if (typeof event[g_hotKeys[event.key].param2] != "undefined") - { param2 = event[g_hotKeys[event.key].param2]; } + if (typeof event[g_hotKeys[event.key].param2] != "undefined") { param2 = event[g_hotKeys[event.key].param2]; } } g_hotKeys[event.key].func(g_hotKeys[event.key].param1, param2); } @@ -3068,7 +3042,7 @@ function toggleHelp() else helpDiv.style.display = "none"; } -function onMyKeyUp(event) {} +function onMyKeyUp(event) { } var g_currentOverlay = 0; @@ -3113,8 +3087,7 @@ function makeTitleInfo(mapWindow) news += " Layer: " + g_viewInfo[g_currentOverlay][1]; } - if (g_currentOverlay == 0 && g_appSettings.gridViewMode == 1) - { return news + end; } + if (g_currentOverlay == 0 && g_appSettings.gridViewMode == 1) { return news + end; } var workline = " - Worked " + @@ -3592,7 +3565,7 @@ function trophyOver(feature) { if ( g_gridToDXCC[name][x] == - g_StateData[g_gridToState[name][y]].dxcc && + g_StateData[g_gridToState[name][y]].dxcc && g_gridToDXCC[name][x] == 291 ) { @@ -3841,8 +3814,7 @@ function mouseUpGrid() if (g_tempGridBox) { - if (g_layerSources.temp.hasFeature(g_tempGridBox)) - { g_layerSources.temp.removeFeature(g_tempGridBox); } + if (g_layerSources.temp.hasFeature(g_tempGridBox)) { g_layerSources.temp.removeFeature(g_tempGridBox); } } g_tempGridBox = null; @@ -3933,8 +3905,7 @@ function mouseOverDataItem(mouseEvent, fromHover) if ( typeof mouseEvent.spot != "undefined" && g_receptionReports.spots[mouseEvent.spot].bearing > 180 - ) - { noRoomRight = true; } + ) { noRoomRight = true; } myTooltip.style.left = getMouseX() + 15 + "px"; top = parseInt(getMouseY() - 20 - (callListLength / 2) * 25); if (windowWidth - getMouseX() < positionInfo.width || noRoomRight == true) @@ -3969,8 +3940,7 @@ function mouseMoveDataItem(mouseEvent) if ( typeof mouseEvent.spot != "undefined" && g_receptionReports.spots[mouseEvent.spot].bearing > 180 - ) - { noRoomRight = true; } + ) { noRoomRight = true; } myTooltip.style.left = getMouseX() + 15 + "px"; top = Number(myTooltip.style.top); if (top > 20) top = getMouseY() - 20 + "px"; @@ -4010,7 +3980,7 @@ function reloadInfo(bandOrMode) { g_statsWindowHandle.window.reloadInfo(); } - catch (e) {} + catch (e) { } } } @@ -4260,8 +4230,7 @@ function qthToQsoBox( newRect.rectangle.qth = iQTH; - if (g_pushPinMode == false && entityVisibility == true) - { g_layerSources.qso.addFeature(newRect.rectangle); } + if (g_pushPinMode == false && entityVisibility == true) { g_layerSources.qso.addFeature(newRect.rectangle); } var newPin = g_colorLeafletQPins.worked[band]; if (confirmed) newPin = g_colorLeafletQPins.confirmed[band]; @@ -4276,8 +4245,7 @@ function qthToQsoBox( newRect.rectangle.pin.hashes[iHash] = 1; newRect.rectangle.pin.size = LL.size; - if (g_pushPinMode && entityVisibility == true) - { g_layerSources["qso-pins"].addFeature(newRect.rectangle.pin); } + if (g_pushPinMode && entityVisibility == true) { g_layerSources["qso-pins"].addFeature(newRect.rectangle.pin); } newRect.rectangle.locked = locked; newRect.rectangle.worked = worked; @@ -4305,8 +4273,7 @@ function qthToQsoBox( return rect.rectangle; } if (worked && !rect.rectangle.worked) rect.rectangle.worked = worked; - if (confirmed && !rect.rectangle.confirmed) - { rect.rectangle.confirmed = confirmed; } + if (confirmed && !rect.rectangle.confirmed) { rect.rectangle.confirmed = confirmed; } borderColor = g_mainBorderColor; if (myDEbox) borderWeight = 1; zIndex = 2; @@ -4471,8 +4438,7 @@ function qthToBox(iQTH, iDEcallsign, iCQ, iNew, locked, DE, band, wspr, hash) newRect.rectangle.pin.liveHash[hash] = 1; newRect.rectangle.pin.size = LL.size; - if (g_pushPinMode && entityVisibility == true) - { g_layerSources["live-pins"].addFeature(newRect.rectangle.pin); } + if (g_pushPinMode && entityVisibility == true) { g_layerSources["live-pins"].addFeature(newRect.rectangle.pin); } newRect.rectangle.locked = locked; newRect.rectangle.size = LL.size; @@ -4789,8 +4755,7 @@ function animatePaths() { if (g_flightPaths[i].age < g_timeNow) { - if (typeof g_flightPaths[i].Arrow != "undefined") - { g_layerSources.flight.removeFeature(g_flightPaths[i].Arrow); } + if (typeof g_flightPaths[i].Arrow != "undefined") { g_layerSources.flight.removeFeature(g_flightPaths[i].Arrow); } g_layerSources.flight.removeFeature(g_flightPaths[i]); delete g_flightPaths[i]; g_flightPaths[i] = null; @@ -5030,8 +4995,7 @@ function clearCalls() g_liveCallsigns[i].rect != null ) { - if (i in g_liveCallsigns[i].rect.liveHash) - { delete g_liveCallsigns[i].rect.liveHash[i]; } + if (i in g_liveCallsigns[i].rect.liveHash) { delete g_liveCallsigns[i].rect.liveHash[i]; } } } @@ -5219,8 +5183,7 @@ function displayTime() { if (now - time > 120000) { - if (g_layerSources.strikes.hasFeature(g_bolts[time])) - { g_layerSources.strikes.removeFeature(g_bolts[time]); } + if (g_layerSources.strikes.hasFeature(g_bolts[time])) { g_layerSources.strikes.removeFeature(g_bolts[time]); } delete g_bolts[time]; } } @@ -5400,8 +5363,7 @@ function toggleStrikeGlobal() var worker = "Strike Distance Changed
" + msg + "
"; - if (g_mapSettings.strikes == false) - { worker += "
Detection is not enabled!"; } + if (g_mapSettings.strikes == false) { worker += "
Detection is not enabled!"; } addLastTraffic(worker); g_layerSources.strikes.clear(); @@ -5426,8 +5388,7 @@ function setStrikeDistance() var send = "{\"west\":-180,\"east\":180,\"north\":-90,\"south\":-90}"; - if (g_strikeInterval == null) - { g_strikeInterval = setInterval(setStrikeDistance, 300000); } + if (g_strikeInterval == null) { g_strikeInterval = setInterval(setStrikeDistance, 300000); } try { @@ -5957,8 +5918,7 @@ function toggleNexrad() g_Nexrad = createNexRad(); g_map.addLayer(g_Nexrad); - if (g_nexradInterval == null) - { g_nexradInterval = setInterval(nexradRefresh, 600000); } + if (g_nexradInterval == null) { g_nexradInterval = setInterval(nexradRefresh, 600000); } } else { @@ -6323,8 +6283,7 @@ function setCallAndGrid(callsign, grid, instance = null) length = encodeQUTF8(responseArray, length, callsign); var hash = liveHash(callsign, thisInstance.Band, thisInstance.MO); - if (hash in g_liveCallsigns && g_liveCallsigns[hash].grid.length > 1) - { grid = g_liveCallsigns[hash].grid; } + if (hash in g_liveCallsigns && g_liveCallsigns[hash].grid.length > 1) { grid = g_liveCallsigns[hash].grid; } if (grid.length == 0) grid = " "; @@ -6390,7 +6349,7 @@ function handleWsjtxQSO(newMessage) g_oldQSOTimer = setTimeout(oldSendToLogger, 3000); } -function handleWsjtxNotSupported(newMessage) {} +function handleWsjtxNotSupported(newMessage) { } var g_gtShareCount = 0; var g_lastBand = ""; @@ -6474,7 +6433,7 @@ function handleWsjtxStatus(newMessage) { g_callRosterWindowHandle.window.processStatus(newMessage); } - catch (e) {} + catch (e) { } } if (g_activeInstance == "") @@ -6495,11 +6454,9 @@ function handleWsjtxStatus(newMessage) if (DXcall.length > 1) { - if (!(newMessage.instance in g_lastTransmitCallsign)) - { g_lastTransmitCallsign[newMessage.instance] = ""; } + if (!(newMessage.instance in g_lastTransmitCallsign)) { g_lastTransmitCallsign[newMessage.instance] = ""; } - if (!(newMessage.instance in g_lastStatusCallsign)) - { g_lastStatusCallsign[newMessage.instance] = ""; } + if (!(newMessage.instance in g_lastStatusCallsign)) { g_lastStatusCallsign[newMessage.instance] = ""; } if ( lookupOnTx.checked == true && @@ -6650,8 +6607,7 @@ function handleWsjtxStatus(newMessage) localDXReport.innerHTML = Number( newMessage.Report.trim() ).formatSignalReport(); - if (DXcall.length > 0) - { localDXCountry.innerHTML = g_dxccToAltName[callsignToDxcc(DXcall)]; } + if (DXcall.length > 0) { localDXCountry.innerHTML = g_dxccToAltName[callsignToDxcc(DXcall)]; } else localDXCountry.innerHTML = " "; } else @@ -7006,10 +6962,8 @@ function handleWsjtxDecode(newMessage) } if (validQTH) msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); - if (validQTH == false && decodeWords.length == 3) - { msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); } - if (validQTH == false && decodeWords.length == 2) - { msgDEcallsign = decodeWords[decodeWords.length - 1].trim(); } + if (validQTH == false && decodeWords.length == 3) { msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); } + if (validQTH == false && decodeWords.length == 2) { msgDEcallsign = decodeWords[decodeWords.length - 1].trim(); } if (decodeWords[0] == "CQ") { CQ = true; @@ -7025,8 +6979,7 @@ function handleWsjtxDecode(newMessage) } if (decodeWords.length >= 3 && CQ == true && validQTH == false) { - if (validateNumAndLetter(decodeWords[decodeWords.length - 1].trim())) - { msgDEcallsign = decodeWords[decodeWords.length - 1].trim(); } + if (validateNumAndLetter(decodeWords[decodeWords.length - 1].trim())) { msgDEcallsign = decodeWords[decodeWords.length - 1].trim(); } else msgDEcallsign = decodeWords[decodeWords.length - 2].trim(); } @@ -7043,8 +6996,7 @@ function handleWsjtxDecode(newMessage) if (validQTH == "" && msgDEcallsign in g_gtCallsigns) { - if (g_gtFlagPins[g_gtCallsigns[msgDEcallsign]].grid.length > 0) - { validQTH = g_gtFlagPins[g_gtCallsigns[msgDEcallsign]].grid; } + if (g_gtFlagPins[g_gtCallsigns[msgDEcallsign]].grid.length > 0) { validQTH = g_gtFlagPins[g_gtCallsigns[msgDEcallsign]].grid; } } var canPath = false; @@ -7124,8 +7076,7 @@ function handleWsjtxDecode(newMessage) newCallsign.cont = g_worldGeoData[g_dxccToGeoData[newCallsign.dxcc]].continent; - if (newCallsign.dxcc == 390 && newCallsign.zone == 1) - { details.cont = "EU"; } + if (newCallsign.dxcc == 390 && newCallsign.zone == 1) { details.cont = "EU"; } } newCallsign.ituza = Array(); @@ -7288,8 +7239,7 @@ function handleWsjtxDecode(newMessage) if ( g_gtCallsigns[callsign.DEcall] in g_gtFlagPins && g_gtFlagPins[g_gtCallsigns[callsign.DEcall]].o == 1 - ) - { g_spotCollector[g_gtCallsigns[callsign.DEcall]] = callsign.RSTsent; } + ) { g_spotCollector[g_gtCallsigns[callsign.DEcall]] = callsign.RSTsent; } } } @@ -7449,8 +7399,7 @@ function handleWsjtxDecode(newMessage) else if (CCd.length == 3) { // maybe it's DEL, or WYO. check the first two letters - if (CCd.substr(0, 2) in g_shapeData) - { locality = g_shapeData[CCd.substr(0, 2)]; } + if (CCd.substr(0, 2) in g_shapeData) { locality = g_shapeData[CCd.substr(0, 2)]; } } if (locality == null) @@ -7522,24 +7471,24 @@ function handleWsjtxDecode(newMessage) g_lastMessages.unshift( "" + - userTimeString(theTimeStamp * 1000) + - "" + - newMessage.SR + - "" + - newMessage.DT.toFixed(1) + - "" + - newF + - "" + - newMessage.MO + - "" + - htmlEntities(newMessage.Msg) + - "" + - countryName + - "" + bgColor + + "'>" + + userTimeString(theTimeStamp * 1000) + + "" + + newMessage.SR + + "" + + newMessage.DT.toFixed(1) + + "" + + newF + + "" + + newMessage.MO + + "" + + htmlEntities(newMessage.Msg) + + "" + + countryName + + "" ); while (g_lastMessages.length > 100) g_lastMessages.pop(); @@ -7600,13 +7549,11 @@ function handleWsjtxClear(newMessage) if ( g_liveCallsigns[hash].instance == newMessage.instance || g_liveCallsigns[hash].mode == g_instances[newMessage.instance].status.MO - ) - { delete g_liveCallsigns[hash]; } + ) { delete g_liveCallsigns[hash]; } } for (var call in g_callRoster) { - if (g_callRoster[call].callObj.instance == newMessage.instance) - { delete g_callRoster[call]; } + if (g_callRoster[call].callObj.instance == newMessage.instance) { delete g_callRoster[call]; } } redrawGrids(); @@ -7635,12 +7582,11 @@ function goProcessRoster(isRealtime = false) { if (isRealtime == true) { - if (g_callRosterWindowHandle.window.g_rosterSettings.realtime == false) - { return; } + if (g_callRosterWindowHandle.window.g_rosterSettings.realtime == false) { return; } } g_callRosterWindowHandle.window.processRoster(g_callRoster); } - catch (e) {} + catch (e) { } } } @@ -7681,13 +7627,13 @@ function handleWsjtxWSPR(newMessage) Number(newMessage.SR), timeNowSec(), "Pwr:" + - newMessage.Power + - " Freq:" + - Number(newMessage.Frequency / 1000).formatMhz(3, 3) + - " Delta:" + - Number(newMessage.DT).toFixed(2) + - " Drift:" + - newMessage.Drift, + newMessage.Power + + " Freq:" + + Number(newMessage.Frequency / 1000).formatMhz(3, 3) + + " Delta:" + + Number(newMessage.DT).toFixed(2) + + " Drift:" + + newMessage.Drift, "WSPR", Number(newMessage.Frequency / 1000000).formatBand(), false, @@ -7903,8 +7849,7 @@ function showCallsignBox(redraw) (thisCall in g_tracker.confirmed.call ? "✔" : "") + ""; var ageString = ""; - if (timeNowSec() - newCallList[x].time < 3601) - { ageString = (timeNowSec() - newCallList[x].time).toDHMS(); } + if (timeNowSec() - newCallList[x].time < 3601) { ageString = (timeNowSec() - newCallList[x].time).toDHMS(); } else { ageString = userTimeString(newCallList[x].time * 1000); @@ -8081,8 +8026,7 @@ function myDxccCompare(a, b) function myDxccIntCompare(a, b) { if (!(a in g_dxccToAltName)) return 0; - if (!(b in g_dxccToAltName)) - { return g_dxccToAltName[a].localeCompare(g_dxccToAltName[b]); } + if (!(b in g_dxccToAltName)) { return g_dxccToAltName[a].localeCompare(g_dxccToAltName[b]); } } function myTimeCompare(a, b) @@ -8252,7 +8196,7 @@ function showWorkedBox(sortIndex, nextPage, redraw) var unconfirmedCallsKey = new UnconfirmedCallsKey(list[key].dxcc, list[key].band); if ( g_unconfirmedCalls.has(unconfirmedCallsKey.key) && - list[key].confirmed + list[key].confirmed ) { g_unconfirmedCalls.set(unconfirmedCallsKey.key, unconfirmedCallsSentinel); @@ -8300,14 +8244,12 @@ function showWorkedBox(sortIndex, nextPage, redraw) g_filterMode == "Phone" && value.mode in g_modes_phone && g_modes_phone[value.mode] - ) - { return true; } + ) { return true; } if ( g_filterMode == "Digital" && value.mode in g_modes && g_modes[value.mode] - ) - { return true; } + ) { return true; } return value.mode == g_filterMode; }); } @@ -8852,14 +8794,14 @@ function showDXCCsBox() Object.keys(List).forEach(function (key, i) { var band = - g_appSettings.gtBandFilter == "auto" - ? myBand - : g_appSettings.gtBandFilter.length == 0 - ? "" - : g_appSettings.gtBandFilter; + g_appSettings.gtBandFilter == "auto" + ? myBand + : g_appSettings.gtBandFilter.length == 0 + ? "" + : g_appSettings.gtBandFilter; var unconfirmedCallsKey = new UnconfirmedCallsKey(List[key].dxcc, band); if (g_unconfirmedCalls.has(unconfirmedCallsKey.key) && - g_unconfirmedCalls.get(unconfirmedCallsKey.key) != unconfirmedCallsSentinel + g_unconfirmedCalls.get(unconfirmedCallsKey.key) != unconfirmedCallsSentinel ) { var onMousedown = function (e) @@ -8899,8 +8841,7 @@ function showDXCCsBox() } }; var unconfirmedTd = g_statsWindowHandle.window.document.getElementById("unconfirmed" + List[key].dxcc + "Id"); - if (unconfirmedTd != null) - { unconfirmedTd.addEventListener("mousedown", onMousedown); } + if (unconfirmedTd != null) { unconfirmedTd.addEventListener("mousedown", onMousedown); } } }); } @@ -9209,7 +9150,7 @@ function openBaWindow(show = true) g_baWindowHandle.hide(); } } - catch (e) {} + catch (e) { } } } @@ -9261,7 +9202,7 @@ function openLookupWindow(show = false) g_lookupWindowHandle.window.saveScreenSettings(); } } - catch (e) {} + catch (e) { } } } @@ -9303,8 +9244,7 @@ function openInfoTab(evt, tabName, callFunc, callObj) } if (evt) { - if (typeof evt.currentTarget != "undefined") - { evt.currentTarget.className += " active"; } + if (typeof evt.currentTarget != "undefined") { evt.currentTarget.className += " active"; } else evt.className += " active"; } @@ -9338,8 +9278,7 @@ function openSettingsTab(evt, tabName) displayAlerts(); // Show the current tab, and add an "active" class to the button that opened the tab document.getElementById(tabName).style.display = "block"; - if (typeof evt.currentTarget != "undefined") - { evt.currentTarget.className += " active"; } + if (typeof evt.currentTarget != "undefined") { evt.currentTarget.className += " active"; } else evt.className += " active"; } @@ -9549,10 +9488,8 @@ function renderStatsBox() details.callsigns[call] = ~~details.callsigns[call] + 1; - if (g_QSOhash[i].time < details.oldest) - { details.oldest = g_QSOhash[i].time; } - if (g_QSOhash[i].time > details.newest) - { details.newest = g_QSOhash[i].time; } + if (g_QSOhash[i].time < details.oldest) { details.oldest = g_QSOhash[i].time; } + if (g_QSOhash[i].time > details.newest) { details.newest = g_QSOhash[i].time; } workObject(modet.Mixed, true, band, mode, type, didConfirm); @@ -9647,12 +9584,9 @@ function renderStatsBox() long_distance.worked_hash = i; } - if (!(band in long_distance.band)) - { long_distance.band[band] = newDistanceObject(); } - if (!(mode in long_distance.mode)) - { long_distance.mode[mode] = newDistanceObject(); } - if (!(type in long_distance.type)) - { long_distance.type[type] = newDistanceObject(); } + if (!(band in long_distance.band)) { long_distance.band[band] = newDistanceObject(); } + if (!(mode in long_distance.mode)) { long_distance.mode[mode] = newDistanceObject(); } + if (!(type in long_distance.type)) { long_distance.type[type] = newDistanceObject(); } if (unit > long_distance.mode[mode].worked_unit) { @@ -9704,12 +9638,9 @@ function renderStatsBox() short_distance.worked_hash = i; } - if (!(band in short_distance.band)) - { short_distance.band[band] = newDistanceObject(100000); } - if (!(mode in short_distance.mode)) - { short_distance.mode[mode] = newDistanceObject(100000); } - if (!(type in short_distance.type)) - { short_distance.type[type] = newDistanceObject(100000); } + if (!(band in short_distance.band)) { short_distance.band[band] = newDistanceObject(100000); } + if (!(mode in short_distance.mode)) { short_distance.mode[mode] = newDistanceObject(100000); } + if (!(type in short_distance.type)) { short_distance.type[type] = newDistanceObject(100000); } if (unit < short_distance.mode[mode].worked_unit) { @@ -9752,8 +9683,7 @@ function renderStatsBox() } } - if (!(g_dxccToAltName[finalDxcc] in worldGeoData)) - { worldGeoData[g_dxccToAltName[finalDxcc]] = newStatObject(); } + if (!(g_dxccToAltName[finalDxcc] in worldGeoData)) { worldGeoData[g_dxccToAltName[finalDxcc]] = newStatObject(); } workObject( worldGeoData[g_dxccToAltName[finalDxcc]], @@ -9796,8 +9726,7 @@ function renderStatsBox() { if (g_gridToITUZone[gridCheck].length == 1) { - if (!(g_gridToITUZone[gridCheck][0] in ituZones)) - { ituZones[g_gridToITUZone[gridCheck][0]] = newStatObject(); } + if (!(g_gridToITUZone[gridCheck][0] in ituZones)) { ituZones[g_gridToITUZone[gridCheck][0]] = newStatObject(); } workObject( ituZones[g_gridToITUZone[gridCheck][0]], @@ -10151,11 +10080,9 @@ function createGtStationsTable(obj) var bgDX = " style='font-weight:bold;color:cyan;' "; var bgDE = " style='font-weight:bold;color:yellow;' "; - if (typeof callsign.msg == "undefined" || callsign.msg == "") - { callsign.msg = "-"; } + if (typeof callsign.msg == "undefined" || callsign.msg == "") { callsign.msg = "-"; } var ageString = ""; - if (timeNowSec() - callsign.time < 3601) - { ageString = (timeNowSec() - callsign.time).toDHMS(); } + if (timeNowSec() - callsign.time < 3601) { ageString = (timeNowSec() - callsign.time).toDHMS(); } else { ageString = userTimeString(callsign.time * 1000); @@ -11072,8 +10999,7 @@ function setGtShareButtons() g_mapSettings.offlineMode == false ) { - if (g_appSettings.gtMsgEnable == true) - { msgButton.style.display = "inline-block"; } + if (g_appSettings.gtMsgEnable == true) { msgButton.style.display = "inline-block"; } else msgButton.style.display = "none"; gtFlagButton.style.display = "inline-block"; @@ -11100,7 +11026,7 @@ function setGtShareButtons() { g_chatWindowHandle.hide(); } - catch (e) {} + catch (e) { } } } @@ -11168,8 +11094,7 @@ function setMsgEnable(checkbox) g_appSettings.gtMsgEnable = checkbox.checked; if (g_appSettings.gtShareEnable == true) { - if (g_appSettings.gtMsgEnable == true) - { msgButton.style.display = "inline-block"; } + if (g_appSettings.gtMsgEnable == true) { msgButton.style.display = "inline-block"; } else { msgButton.style.display = "none"; @@ -11207,6 +11132,17 @@ function checkForNewVersion(showUptoDate) } } +function checkForNewAcks() +{ + getBuffer( + "http://app.gridtracker.org/acknowledgements.json?lang=" + g_localeString, + updateAcks, + null, + http, + 80 + ); +} + function renderBandActivity() { var buffer = ""; @@ -11363,9 +11299,9 @@ function pskGetBandActivity() { getBuffer( "https://pskreporter.info/cgi-bin/psk-freq.pl?mode=" + - myMode + - "&grid=" + - myDEGrid.substr(0, 4), + myMode + + "&grid=" + + myDEGrid.substr(0, 4), pskBandActivityCallback, null, "https", @@ -11593,7 +11529,7 @@ function updateBasedOnIni() localStorage.N1MMSettings = JSON.stringify(g_N1MMSettings); alert( which.appName + - " N1MM Logger+ is enabled with same settings, disabled GridTracker N1MM logger" + " N1MM Logger+ is enabled with same settings, disabled GridTracker N1MM logger" ); } } @@ -11642,8 +11578,7 @@ function CheckForwardPortIsNotReceivePort(value) udpForwardIpInput.value == "127.0.0.1" && udpPortInput.value == value && g_appSettings.wsjtIP == "" - ) - { return false; } + ) { return false; } return true; } @@ -12061,8 +11996,7 @@ function workingCallsignsChanged(ele) if (callsigns.length > 0) { g_appSettings.workingCallsigns = Object.assign({}, g_tempWorkingCallsigns); - if (g_appSettings.workingCallsignEnable) - { applyCallsignsAndDateDiv.style.display = ""; } + if (g_appSettings.workingCallsignEnable) { applyCallsignsAndDateDiv.style.display = ""; } } else applyCallsignsAndDateDiv.style.display = "none"; } @@ -12165,8 +12099,7 @@ function callsignToDxcc(insign) return -1; } - if (callsign in g_directCallToDXCC) - { return Number(g_directCallToDXCC[callsign]); } + if (callsign in g_directCallToDXCC) { return Number(g_directCallToDXCC[callsign]); } if (callsign.includes("/")) { @@ -12174,7 +12107,8 @@ function callsignToDxcc(insign) var end = parts.length - 1; if (ancPrefixes.includes(parts[end])) { - if (parts[end].toUpperCase() == "MM") { + if (parts[end].toUpperCase() == "MM") + { return -1; } parts.pop(); @@ -12198,8 +12132,7 @@ function callsignToDxcc(insign) } else callsign = parts[0]; - if (callsign in g_directCallToDXCC) - { return Number(g_directCallToDXCC[callsign]); } + if (callsign in g_directCallToDXCC) { return Number(g_directCallToDXCC[callsign]); } } for (var x = callsign.length; x > 0; x--) @@ -12243,8 +12176,7 @@ function loadMaidenHeadData() delete g_worldGeoData[key].prefix; for (var x = 0; x < g_worldGeoData[key].mh.length; x++) { - if (!(g_worldGeoData[key].mh[x] in g_gridToDXCC)) - { g_gridToDXCC[g_worldGeoData[key].mh[x]] = Array(); } + if (!(g_worldGeoData[key].mh[x] in g_gridToDXCC)) { g_gridToDXCC[g_worldGeoData[key].mh[x]] = Array(); } g_gridToDXCC[g_worldGeoData[key].mh[x]].push(g_worldGeoData[key].dxcc); } @@ -12252,8 +12184,7 @@ function loadMaidenHeadData() g_worldGeoData[key].dxcc != 291 && g_worldGeoData[key].dxcc != 110 && g_worldGeoData[key].dxcc != 6 - ) - { delete g_worldGeoData[key].mh; } + ) { delete g_worldGeoData[key].mh; } } file = "./data/dxcc.json"; @@ -12271,16 +12202,14 @@ function loadMaidenHeadData() for (var id in countyData) { - if (!(countyData[id].properties.st in g_stateToCounty)) - { g_stateToCounty[countyData[id].properties.st] = Array(); } + if (!(countyData[id].properties.st in g_stateToCounty)) { g_stateToCounty[countyData[id].properties.st] = Array(); } g_stateToCounty[countyData[id].properties.st].push(id); var cnty = countyData[id].properties.st + "," + countyData[id].properties.n.toUpperCase().replaceAll(" ", ""); - if (!(cnty in g_cntyToCounty)) - { g_cntyToCounty[cnty] = countyData[id].properties.n.toProperCase(); } + if (!(cnty in g_cntyToCounty)) { g_cntyToCounty[cnty] = countyData[id].properties.n.toProperCase(); } g_countyData[cnty] = {}; g_countyData[cnty].geo = countyData[id]; @@ -12308,33 +12237,28 @@ function loadMaidenHeadData() g_shapeData = JSON.parse(fs.readFileSync(g_shapeFile)); for (var key in g_shapeData) { - if (g_shapeData[key].properties.alias == key) - { g_shapeData[key].properties.alias = null; } + if (g_shapeData[key].properties.alias == key) { g_shapeData[key].properties.alias = null; } else if ( g_shapeData[key].properties.alias && g_shapeData[key].properties.alias.length > 2 && (g_shapeData[key].properties.alias.indexOf("US") == 0 || g_shapeData[key].properties.alias.indexOf("CA") == 0) - ) - { g_shapeData[key].properties.alias = null; } + ) { g_shapeData[key].properties.alias = null; } if ( g_shapeData[key].properties.alias && g_shapeData[key].properties.alias.length < 2 - ) - { g_shapeData[key].properties.alias = null; } + ) { g_shapeData[key].properties.alias = null; } if (g_shapeData[key].properties.alias != null) { if (key.indexOf("CN-") == 0) { - if (g_shapeData[key].properties.alias == key.replace("CN-", "")) - { g_shapeData[key].properties.alias = null; } + if (g_shapeData[key].properties.alias == key.replace("CN-", "")) { g_shapeData[key].properties.alias = null; } } } if ( g_shapeData[key].properties.alias != null && g_shapeData[key].properties.alias.length != 2 - ) - { g_shapeData[key].properties.alias = null; } + ) { g_shapeData[key].properties.alias = null; } } // finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6 @@ -12396,8 +12320,7 @@ function loadMaidenHeadData() { for (var x = 0; x < g_StateData[key].mh.length; x++) { - if (!(g_StateData[key].mh[x] in g_gridToState)) - { g_gridToState[g_StateData[key].mh[x]] = Array(); } + if (!(g_StateData[key].mh[x] in g_gridToState)) { g_gridToState[g_StateData[key].mh[x]] = Array(); } g_gridToState[g_StateData[key].mh[x]].push(g_StateData[key].postal); } g_StateData[key].worked_bands = {}; @@ -12447,8 +12370,7 @@ function loadMaidenHeadData() { for (var x = 0; x < g_cqZones[key].mh.length; x++) { - if (!(g_cqZones[key].mh[x] in g_gridToCQZone)) - { g_gridToCQZone[g_cqZones[key].mh[x]] = Array(); } + if (!(g_cqZones[key].mh[x] in g_gridToCQZone)) { g_gridToCQZone[g_cqZones[key].mh[x]] = Array(); } g_gridToCQZone[g_cqZones[key].mh[x]].push(String(key)); } delete g_cqZones[key].mh; @@ -12461,8 +12383,7 @@ function loadMaidenHeadData() { for (var x = 0; x < g_ituZones[key].mh.length; x++) { - if (!(g_ituZones[key].mh[x] in g_gridToITUZone)) - { g_gridToITUZone[g_ituZones[key].mh[x]] = Array(); } + if (!(g_ituZones[key].mh[x] in g_gridToITUZone)) { g_gridToITUZone[g_ituZones[key].mh[x]] = Array(); } g_gridToITUZone[g_ituZones[key].mh[x]].push(String(key)); } delete g_ituZones[key].mh; @@ -12637,9 +12558,9 @@ function drawAllGrids() { var LL = squareToLatLong( String.fromCharCode(x) + - String.fromCharCode(y) + - String(a) + - String(b) + String.fromCharCode(y) + + String(a) + + String(b) ); var Lat = LL.la2 - (LL.la2 - LL.la1) / 2; var Lon = LL.lo2 - (LL.lo2 - LL.lo1) / 2; @@ -12771,6 +12692,12 @@ function versionCheck(buffer, flag) } } +function updateAcks(buffer) +{ + g_acks = JSON.parse(buffer); + fs.writeFileSync("./data/acknowledgements.json", JSON.stringify(g_acks)); +} + function onExitAppToGoWebsite() { require("nw.gui").Shell.openExternal("https://gridtracker.org/"); @@ -12817,8 +12744,7 @@ function getBuffer(file_url, callback, flag, mode, port, cache = null) { var fsize = res.headers["content-length"]; var cookies = null; - if (typeof res.headers["set-cookie"] != "undefined") - { cookies = res.headers["set-cookie"]; } + if (typeof res.headers["set-cookie"] != "undefined") { cookies = res.headers["set-cookie"]; } res .on("data", function (data) { @@ -12871,8 +12797,7 @@ function getPostBuffer( { var fsize = res.headers["content-length"]; var cookies = null; - if (typeof res.headers["set-cookie"] != "undefined") - { cookies = res.headers["set-cookie"]; } + if (typeof res.headers["set-cookie"] != "undefined") { cookies = res.headers["set-cookie"]; } res .on("data", function (data) { @@ -13105,8 +13030,7 @@ function changeMapValues() g_appSettings.gtFlagImgSrc > 0 && g_mapSettings.offlineMode == false && g_appSettings.gtShareEnable == true - ) - { g_layerVectors.gtflags.setVisible(true); } + ) { g_layerVectors.gtflags.setVisible(true); } else g_layerVectors.gtflags.setVisible(false); saveMapSettings(); @@ -13349,7 +13273,7 @@ function initSoundCards() .catch(errorCallback); } -function errorCallback(e) {} +function errorCallback(e) { } function gotAudioDevices(deviceInfos) { soundCardDiv.innerHTML = ""; @@ -13532,8 +13456,7 @@ function setMsgSettingsView() msgAlertMedia.style.display = "none"; } - if (g_msgSettings.msgAwaySelect > 0) - { msgAwayTextDiv.style.display = "inline-block"; } + if (g_msgSettings.msgAwaySelect > 0) { msgAwayTextDiv.style.display = "inline-block"; } else msgAwayTextDiv.style.display = "none"; } @@ -13573,8 +13496,7 @@ function loadAdifSettings() } for (var key in g_adifLogSettings.startup) { - if (document.getElementById(key) != null) - { document.getElementById(key).checked = g_adifLogSettings.startup[key]; } + if (document.getElementById(key) != null) { document.getElementById(key).checked = g_adifLogSettings.startup[key]; } } for (var key in g_adifLogSettings.nickname) { @@ -13714,7 +13636,7 @@ function startupButtonsAndInputs() setGtShareButtons(); } - catch (e) {} + catch (e) { } } function startupEventsAndTimers() @@ -13973,7 +13895,7 @@ function updateForwardListener() reuseAddr: true }); - g_forwardUdpServer.on("listening", function () {}); + g_forwardUdpServer.on("listening", function () { }); g_forwardUdpServer.on("error", function () { g_forwardUdpServer.close(); @@ -14049,8 +13971,7 @@ var g_currentID = null; function updateWsjtxListener(port) { - if (port == g_wsjtCurrentPort && g_appSettings.wsjtIP == g_wsjtCurrentIP) - { return; } + if (port == g_wsjtCurrentPort && g_appSettings.wsjtIP == g_wsjtCurrentIP) { return; } if (g_wsjtUdpServer != null) { if (multicastEnable.checked == true && g_appSettings.wsjtIP != "") @@ -14059,7 +13980,7 @@ function updateWsjtxListener(port) { g_wsjtUdpServer.dropMembership(g_appSettings.wsjtIP); } - catch (e) {} + catch (e) { } } g_wsjtUdpServer.close(); g_wsjtUdpServer = null; @@ -14417,8 +14338,7 @@ function loadLookupDetails() } ValidateText(lookupLogin); ValidateText(lookupPassword); - if (lookupService.value == "CALLOOK") - { lookupCredentials.style.display = "none"; } + if (lookupService.value == "CALLOOK") { lookupCredentials.style.display = "none"; } else lookupCredentials.style.display = "block"; } @@ -14447,8 +14367,7 @@ function lookupValueChanged(what) g_appSettings.lookupCallookPreferred = lookupCallookPreferred.checked; lookupQrzTestResult.innerHTML = ""; g_qrzLookupSessionId = null; - if (lookupService.value == "CALLOOK") - { lookupCredentials.style.display = "none"; } + if (lookupService.value == "CALLOOK") { lookupCredentials.style.display = "none"; } else lookupCredentials.style.display = "block"; if (ValidateText(lookupLogin) && ValidateText(lookupPassword)) { @@ -14655,10 +14574,10 @@ function GetSessionID(resultTd, useCache) { getBuffer( "https://ssl.qrzcq.com/xml?username=" + - g_appSettings.lookupLoginCq + - "&password=" + - encodeURIComponent(g_appSettings.lookupPasswordCq) + - "&agent=GridTracker1.18", + g_appSettings.lookupLoginCq + + "&password=" + + encodeURIComponent(g_appSettings.lookupPasswordCq) + + "&agent=GridTracker1.18", qrzGetSessionCallback, resultTd, "https", @@ -14670,9 +14589,9 @@ function GetSessionID(resultTd, useCache) { getBuffer( "https://xmldata.qrz.com/xml/current/?username=" + - g_appSettings.lookupLoginQrz + - ";password=" + - encodeURIComponent(g_appSettings.lookupPasswordQrz), + g_appSettings.lookupLoginQrz + + ";password=" + + encodeURIComponent(g_appSettings.lookupPasswordQrz), qrzGetSessionCallback, resultTd, "https", @@ -14684,9 +14603,9 @@ function GetSessionID(resultTd, useCache) { getBuffer( "https://www.hamqth.com/xml.php?u=" + - g_appSettings.lookupLoginQth + - "&p=" + - encodeURIComponent(g_appSettings.lookupPasswordQth), + g_appSettings.lookupLoginQth + + "&p=" + + encodeURIComponent(g_appSettings.lookupPasswordQth), hamQthGetSessionCallback, resultTd, "https", @@ -14799,10 +14718,10 @@ function GetLookup(useCache) { getBuffer( "https://ssl.qrzcq.com/xml?s=" + - g_qrzLookupSessionId + - "&callsign=" + - g_qrzLookupCallsign + - "&agent=GridTracker", + g_qrzLookupSessionId + + "&callsign=" + + g_qrzLookupCallsign + + "&agent=GridTracker", qrzLookupResults, g_qrzLookupGrid, "https", @@ -14814,9 +14733,9 @@ function GetLookup(useCache) { getBuffer( "http://xmldata.qrz.com/xml/current/?s=" + - g_qrzLookupSessionId + - ";callsign=" + - g_qrzLookupCallsign, + g_qrzLookupSessionId + + ";callsign=" + + g_qrzLookupCallsign, qrzLookupResults, g_qrzLookupGrid, "http", @@ -14828,10 +14747,10 @@ function GetLookup(useCache) { getBuffer( "https://www.hamqth.com/xml.php?id=" + - g_qrzLookupSessionId + - "&callsign=" + - g_qrzLookupCallsign + - "&prg=GridTracker", + g_qrzLookupSessionId + + "&callsign=" + + g_qrzLookupCallsign + + "&prg=GridTracker", qthHamLookupResults, g_qrzLookupGrid, "https", @@ -14938,8 +14857,8 @@ function initialDatabases() { alert( "Database error: " + - event.target.errorCode + - " : GridTracker will have issues" + event.target.errorCode + + " : GridTracker will have issues" ); }; @@ -15020,8 +14939,7 @@ function getLookupCachedObject( } return; } - if (request.result != null && resultFunction) - { resultFunction(request.result, gridPass, false); } + if (request.result != null && resultFunction) { resultFunction(request.result, gridPass, false); } else if (noResultFunction) noResultFunction(call, gridPass); }; @@ -15408,7 +15326,7 @@ function displayLookupObject(lookup, gridPass, fromCache = false) if ( getLookProp(lookup, "gtGrid").length > 0 && getLookProp(lookup, "gtGrid").toUpperCase() != - getLookProp(lookup, "grid").toUpperCase() + getLookProp(lookup, "grid").toUpperCase() ) { worker += makeRow("GT Grid", lookup, "gtGrid"); @@ -15467,12 +15385,12 @@ function displayLookupObject(lookup, gridPass, fromCache = false) setLookupDiv( "lookupInfoDiv", "" + - genMessage + - "
" + - card + - "" + - details + - "
" + card + + "" + + details + + "" + + genMessage + + "" ); setLookupDivHeight("lookupBoxDiv", getLookupWindowHeight() + "px"); } @@ -15513,8 +15431,7 @@ function saveToCsv(lookup) if ( getLookProp(lookup, "land").length > 0 && country != getLookProp(lookup, "land") - ) - { country = getLookProp(lookup, "land"); } + ) { country = getLookProp(lookup, "land"); } if (country == "United States") country = ""; tryToWriteAdifToDocFolder( @@ -15602,8 +15519,7 @@ function joinCommaIf(camera1, camera2) function joinIfBothWithDash(camera1, camera2) { - if (camera1.length > 0 && camera2.length > 0) - { return camera1 + " / " + camera2; } + if (camera1.length > 0 && camera2.length > 0) { return camera1 + " / " + camera2; } return ""; } @@ -15706,8 +15622,7 @@ function searchLogForCallsign(call) if (String(dxcc) + g_colorBands[band] in g_tracker.worked.dxcc) { var strike = ""; - if (String(dxcc) + g_colorBands[band] in g_tracker.confirmed.dxcc) - { strike = "text-decoration: underline overline;"; } + if (String(dxcc) + g_colorBands[band] in g_tracker.confirmed.dxcc) { strike = "text-decoration: underline overline;"; } worker += "
Saved Screenshot" + encodeURI(fn).trim() + + "\");''>Saved Screenshot" ); } catch (e) From 6c5b21d7be46b2bb6035f09125fb19f8f3e9f117 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sat, 19 Jun 2021 11:33:04 -0500 Subject: [PATCH 011/125] call checkForNewAcks when checkForNewVersion --- package.nw/lib/gt.js | 1 + 1 file changed, 1 insertion(+) diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index 325c2d1..47ceded 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -13588,6 +13588,7 @@ function startupVersionInit() { checkForNewVersion(false); }, 86400000); + checkForNewAcks(); } } From 9e1c70b69fba8ff6765d840619ec26835ccdd996 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sat, 19 Jun 2021 11:43:05 -0500 Subject: [PATCH 012/125] fix missing " around http line 11141 --- package.nw/lib/gt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index 47ceded..d7e2660 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -11138,7 +11138,7 @@ function checkForNewAcks() "http://app.gridtracker.org/acknowledgements.json?lang=" + g_localeString, updateAcks, null, - http, + "http", 80 ); } From b7e427cc46dd4811796f24deebdc69126380a232 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sat, 19 Jun 2021 12:01:43 -0500 Subject: [PATCH 013/125] general updates for new general release --- debian/changelog | 8 ++++++++ package.nw/gt_update.odt | Bin 81206 -> 83991 bytes package.nw/gt_update.pdf | Bin 57109 -> 58736 bytes package.nw/package.json | 2 +- 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 1d5ddaa..e5c37c5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +gridtracker (1.21.0620) unstable; urgency=medium + [Bug Fixes] + - Fix pulling down of LoTW logs at start-up with a differential log syncing mechanism that only get's changes since last sync, also cool down timer to prevent rapid reloading of LoTW log. + [Enhancements] + - Automatic pulling down of acknowledgements.json file daily when doing version check (if enabled). + + -- Matthew Chambers Sat, 19 June 20201 16:49:00 -0000 + gridtracker (1.21.0613) unstable; urgency=medium [Bug Fixes] - Fix pulling down LoTW log at start-up causing issue for other programs that are trying to sync LoTW logs. diff --git a/package.nw/gt_update.odt b/package.nw/gt_update.odt index 70b150b68fd8b3f5f20728240082476711907ba9..3a83295565c7f90395ab6d1621a51e475fb6f53a 100644 GIT binary patch delta 17041 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 delta 14246 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 delta 27861 zcmV)6K*+!F$^(_Y1CUC8Sxb-OL=e8`SNM#SY*#<*wiH>)j2#3wU?dKR6E6v|pxw*< zed^UO+wm+rXf(;V-Cghcs;b9ap!;8&c!FI!FyN|z}e*CKYTUSl@@sHEf%L#nE z;CnmZiI-oycX#N3R$hMp>1tqttFhA=Kizb8SL10ROaOVk=g+}^#L33187G@w+@_yj zzCA53r|(uA?ck8t1CCGA87VyT=RAe0S(=3hB%SLo@e#>8odq*FB?It?jM@UsWyoY4 z69G%=gCioh=^WC6r-h!W1~Sb!jaTT|RJft1&G>4VKzE@52el={>Fjj_nN6OVBHWZF z^Gmz=xt9FW=igd?{yxGbWcfXrgfw_!GQE(oB$~Uu^ zJN`aDbiEr%KsyRaTag4dk7b4B%TMQlf{iR}2DWCzcO$a#7$;WWJ)0R<+{4i5kwX~$ zMR~doa&Qwv!^ZIJi_kvw`fZWBBj%%O8IV1U98N${$pJclT=jq)mv;eA@!`PAjFXr1 zvU4dMT{?HKPFmd;O#p*W@&+>^(tGCH>!Af8>9SyKLgMH(>;b*5=btoYy^5}sNKA_A z;VS1dE%pMkh_Wcc`0D{;lgl17j{ zyi{-j5$+~f!!HuE${97MHpUJe5!_{yBWezt0`zet*quONqi}-6oUD;TTy$b@MA~E- zAMaAUT(LyEv%0R-Hrv9DDdwuNtp&3M z?phoVB>|uwsF4Jtqj$w5CR-pX0!hjh7+ZjYCF~RtbeviQ*TyaSL3$lEl{w2bzv8NF z)OGSpkblHAHHu|(?gsTvg$?>l)8?J9LL1hl^Xg zVWDz4M`Ty>d7~KfAy+l!Nmz($GBi`(&WfBjJtK9zFD^TD+t>26c1z!$562itKDx*@Q z;V2i|68Wj%W#7FGn~LssEAS;47}IQPt;accPwu*ADf*gd`zlxzPX*Int4Au3bQ`u7 z3Ro=YYEgc9f1;a*PmRRie|<9DnF{%PoR$NA^TS`=4?Er%amw9QYksX^umKQ%@w~I? zY(1MVIB?&nCpJ9t%kVvbL8Yw@;XIz(<2V7EK-E`6_!;up@3jv{vsstjdC%kkkA@)3g`+rigGnOQahh{`rduvSBy{+wneO%(wLM!R2QQnzD3g}nEmf5KLwjr&I=Wtv#Y=|2z9pwJ8bkFrI z5-XYTDS^?@Ud=MZxT*nvdL^i>Gn+f)FAwUf16P43w|GvC$Mu>po!b*!7;SE3qE)Z~1>CJuwUX z<}I|*5}$Y9y!YMwPe&yF1-p+UoRhH~6AUvTFd%PYY6>wpHa4>c3NajiGBY?ZI6giK zb98cLVQmU{ob7xIKvY%U_&N97JC6$kGr$aQxS*qv2!^ToszDeKMIaavD~f@cfiakw zW(JAOwEBAIR@-J~mXF$Ucgf8B%F-<>+bzq|P1~)uZTr?9`z^Ws_iNjh@cRFqbMG(% zqM1Ga53byMp1=3&9IbGFu-lE|(Mm*+t*y%$xaG1Xtq7r45yDArOT&_W>W+Uw`_Bk* z4o{%H>!=?sK!`sZ*7UV^_Igs@?*A0}FrSpt;dZ)yKelNyLYB{9erg8{%#wXtgi;Hk zKenSQe7Qbx`%TcVgZ|~6{x;|JwpVS?e+l~Mb~!H(+)j!Fgwk|>(3gD9E_doDm5ZQ% z212tF0{&3=0(A8;gchDd=L11^;KKE-1JG|mNc%91VR-0IJTx`5&kJ}iR&?_o{%W)p-qX1Q{5pOa|2n@6HBriNHT|V@ptX1&9)s3$YjHVF z$K~8U^cTWe@|kF@W-Z@@j!@a41Kd84M;(*LE$9}_S?F_KgFYqIxP{+LC5EiRbKnMf+IgBJ zv>MOTUJINcG7T+5DKPsoM#6K-1FLkJY_ysmPwoeQ+Bt4{L~ghj?c=7CRicj6uB zPP7As5P%@#p44gto^TiyO2)06waT^Cc7Bue(&D^{g(JF>Q7dglbz2R+(vD-t>YDgW zVewWWYb&wpw({07@1JP${fUM1>zbq;_zZiw3fA6I4ucI%(4;*WhH-m2o1<8_3Rd`2 z)v{H8YU_}0Hr_mD#?40ejEU6J<<-1Lcn~6-7Uk|jJRS#P(BN@TV4ZLi$D`ss2m8-L z#)JI_`zIxv@=Vq|Q=W%MgCUYR_<_7yoAAXyf|>&6OvrQWFTw!WMmCynv!-WQ;*EM_ zAqHc{Q(2ZR#JEMjj;zVb$xJ^heljXfo~W6BkYgO||LpMK9zd|?@MrzTBk;UvN}8_x znY8VaT#TEo8h(s~Oh%Mf!l#;w@R)qgoRT!TWa>227*n1waJ#(s=khIbHQt4C-=D=P3t?8aVv|2fm-S1K#yV}JidmJ^LQpBgjsKk^c zjTvNVvqgt2XPR=v2rw@B5ba^e`^5q6i ziu^|wV=e;uCjd+%%0lPZGE+CA{RyUx!hYSFguVCylENbcXUmuqH#3{cy}yK^08aXi zhmTC!UYpaB!{KI3;ZI2bo~X=$9a1uN%Gu*6izycJ5bluI%-h!ey8Jm7Uk^WjzA4n( z8w&RJl3iTWzxy|}U4*MJfv2i@@a4@LHf*N9%r-=Xge4GBv}iJL%k4(1czh1ApmPMB z@!JeMpq0ZPQu%4`Y7L`&?1}U6|zw{B)|J*4Zn@?-E{0P z{EMJN5n0iFwlnn_l%5-hewX@xx@LXCev|ZS?kidA$Luw&iAQ5nNt!`#h?|{D3@J0m zff)8sIhdwTpU#vz2uAqfkwxp(H=p1Uc3XG89`oUOUW zW)LouBG~S1Y*nQ^ZpztX^Cl}2)|$Y8B%a$8xa`97-8W;eeD~b#S8sU>C*u4!uK!8s zHw!}_har#~@E6td$`{sr1R-Q zx@M-fid1PYAkCU4?Il`2X%|+IrTkLOGVP7zI{pUX7VUa+m#|uMul6aDVc{&o3|%=_ zDa_L~a?QGSu7z_8JzRiWDqN|%fxA(-MfX$gZsA^?xtSRk&eP*O%=`+k!yAsi%hkv= z@_c!%CS~w3eD6_z`RFG6hCETRH9_QQw#YR-XpU#kT>96|318Ua$4z$2~k;P&;fk!#+QO4ZO`GJO){ z6|GVDL~GQkzrrVr^RewpTGbfgk+?~mjcepQ+)D0tZUeVfeRjjMAD%z6=Tmsn1*n${ zMC8pV8E27y41OFMizko*ekwW}Pbbs)NxBMDfkD%Ji|%sG4fsZKgK(o}HDv00$UXdB z!dlH{@&ta0jBQ4sHmb9{Tu@mmw%~TTQtshf1_y}d%MA+u9|8Y7#2gWwVKb90Jhw$y zrA1rxx-?A&L1_YxGalU2zlX(|{*upFipw(zEXSFD@;=25`2l<(_F>1D{a7R~&c&L! zUrv!fXRr@I;F*rEh4^iH5^aWh2PN}H1ri04cYp>;e6743)^36`z7*`C-Z> zJ{J!QJ?0dRmaF0J`0@oVuc~5I_XTfWagBThj>iR8?Zuh$2RIYIKj*4)@5%+$c-!Q(pLtz>;+iyMiBHv7l2Xz@I)jl=b7T@WQmiH; z4KA1&y<+-gi}%Vamn^w**%ExUyjy--eoNksZFoE$hizOxPW#{k`D6Kmk3Ys~@+!Ft z--$ywjPI1YC=DxshB3kspkXXTz1(EfXVLU!#jiHpW$epem$k+kug^#)*5r)z)ZDRu zR!Yxdg#BpUdSya|3e6rn*ZY6R5Mtd7hn5h6=0+y`#>@wnZ1=_Q-%`gR-VtiA99 zoG$-H{z86NehznId;9a;``4;J+&;N~;)G{+opqM{*;}8=@8O%E9tq-yC9sW~AWk0v zxt)QkZ4;2WFIm4@e9X|NkyhtEmerSkymibv&6)yBayn%7bjvuSh2*B>O8T4v(FO)R_sHxuxb$&pkZ)i!zh?)&6E`RUL{mvtU$ zzvqF6A6UETj-T9oRr50!2mjm&rF`Da#5(@DyZ-c%)rt$IPFvFE@qTe(bK}K-XBOZL zNqTnowGT7>Lw?tcXZc-3vdxCFHG(!3bX>R z(5=vi#hbdw?l@l||81>Y?!(}ndn@z)F2>u%ED!><4q`A47hHT?FS{^6TIF(H+x4~J| z&8M@3S3C=7oprb$>MM94onu>K?)XXL>&6GhuN;5-_(#WUn=zx55*>|1c_yXajB>(1 zUA{B$++K*NxT416=j1iE`t|^HJLdeVJ-m%P)X{b1FGm}>xrVHNjGjw3uRr=WH}~mF ze{mn3@sXK>b@JM ztawea%!CHidvI)jnQY=F`z@|#E&OwAm=0+OqF0G#tfyRSHym}Bx)g$u;O$&r;6nL-lcF1XGRKVTyN4_Ia>FKO zB^=rXevZJ;b#TVG!B&!)!DXdqTT&sNrKVb}=@u~=60BxR{Hj#ZlAK12S?LJEqVOXhvI{zb!2b&VRPt%(Tq(jEv08jI62VsTRB0 zZfP_(TIzCt+-A3>B`2{NtMM(J1GbbLmV;B1^9VQu_g=5p+q+3#!Bs;NNxtp&+U2$b zvge6umt9QGyP)0EBwsCme)JXL&~M)S*)tQ9R$MJN;ZUGHa;^}@gFn!mHqn->*_ebj z#_vs9lct}OSWV`bXO75ePfSZbFTFCE#MJpf7m1{QHh6Q-^(yWck^1v{YV?@X$(fBoQd-v;Dls|vHd;5c-Wy?Zv^xSlGyGDcnCO;`djV?dg zOs4%}{rX?9Qzt&QO7?KG!B*o?sVzBi|M9HTDzT~?n8DBTuMet|Y?2v3Vt4d6cbDsVW+>Qpj+ zCK)Q#e;sl`srtHn3+_hjj+k>?QT^AR7cNPh^-q+mV^^53{pI@4BKM{s*+%Vl;1VNU z^fDE)N0%IXZ;VG=x90HskVkU|@{oU^KJFRRCp?WV61tHncu*7n3~CbUVXO-^aW8`u zr=eWo4)hTb(E<2wg5Os7T>-y0Y0iRwJ=;*9t`Yr`yn!;Iy+Koeb_pv0#(T&EaQnD{ zW2@*I*iY|Z$Dx%FyFSEc<5t|yP36{bN4O)zN7j*T{8-+@?-s@i&ucWArJDWPH0@8c z2X&Ipr`xRS*NZAAIj8_}>TRwO*(m42CtMzUc^J!pcpc$)%@FSxY;TR)=3w1_18SQ9 zgoo8O5A7$_wt(W%Z`HO2C89Ufwho!lf2r*_NVNZ>whc-5LGi4#6VTbokEm@Uic5Z9 zZJQ9E+z%KruLpuAC4Z{6F|wE?wap=&d8*nbNHU+Rws~k@thNP|X1+>oYfz4Pwc6I9 zeDij-9fxL^-&ETM>kNxgZ6~0Aj+yh+wh>uoZd2PPq?`FtnLp4Q^tN||r8C+Jq>@RK zCQGfo(j0F%6b`zbU4>GWudPTb?d+85>8g-a?+&?xOWm#_@wly1=~jnxY1b0JuU(qs z>^Q;3a`zHvW4F}S;qsAC7i$)Zq*nvH#q>wg$Bz1A(Nq@xS^>fOql}2FphD4_n4mw@#E@$vk$?q8nMHK7Y z!7guz>A)M3I^01w;A#&#eZYDl@D6OjHjo&|xljuGC8w`f3V_yNgTFNl67zxxoKhPQ zEyBuhhdUytwl;rP0G87Q;SPWfQg-`7AiaDhlKcVy=8~MDkiX4;>jZqF%iq@B<@SZ0 zVM>q3+X+fKgF<8*qz1ny+ymmzFJP1e-GQLr)!pW1U|e2c%-h->c2gR}VH*lT&263C zE=oy{H{9Xx4g)b=UKJ6=5L847V7o)Gp0ZOYb-5|mA~TRsM_~+(LW;B4ACy9F&;zXY z0;wwdBT!S~0BnGN3OXz*qGO19I>4}w+d$Re=??k;p_^@V`K6G*PzrUoE^)Vo=?LY| zR;++94J=A2pBQ~pFa$02q~jfD}ks5D05P%!`ay> zwz^fR0U6*W&S8A|eP9U6mn=Zfg4gF1siS9hl~C{jc&cgWlBV`Q`|z6zVDg*w{+NQmx;&=VSoiGmaX z0TYmdWpD)8*I)UWSe^YL03r1 zAM(R|iaRoYA?8!J&1WJ5%~Y%Y(&`3JqENd*2UI3Y{oWzM+?R*JVrUd_}-mE@E< zY4iYJi7X5_+b(ss17qNaKEFs!_3IhcFjNq*fJAqHr-u?X*Dh7m);Oew+6u>_(t5j8 z)gaZ?*EUv_+smc=(gx_~7fOq&9CK?IIwV+8Us~f>EY(&>r8SGC`BgRLg_6CguHN3z zAlBAPRSW8>tL!jVRZ~{Iu)M0KQknz%YHA%)b=86@2LN@{vaKqpDtiM3w!mIrHW#|3 zbE>L;s~n39#fmCN4ZsBA>ZMYtuC(4!RkpCYv|g%PSYKD$U?`9TerBrs&cNQ5H>kruuyc=mzLWXl-AELlmJ*Quv{;(B}G6bz>w^XbaTVp(&}ny zPL-p}6H70dlOWx0gBCN{~HBqMDIgR$J3xKYt+% zz`6*ELUGYtJ3|2sl)|4fMj2zj2H2%=9JTe1AyO7qHP{QK()y|fs*#HNS|FF|v$leN zS-?V&CskgJN-xzB9XsASU=`i1GFWaetp9|k{y)1lybwegnLa%G78zNwch7x~J z^wVI{;|(!ShZNZ5S8|>da&`hT*hRg6h^>NH>Fk7Up&>GdIg}VlhJm0Lw)6zOVF)IY zvl~W(-Ye8J98}X3<3NgXK(R!FgF=7M9ST5}@-B6E_7=g~AkAfr60Z+xwJw!)Ccd`t zj7X^vmf9I`mp?2*MOP$=BCEK*ap`obrR}#<2Z>4@B%MwjBu48X=``yg@%TD_NDcCB z3{ohPGe#*;qXmojO==}6QY(o+j#^1n^zfb4N}}Sh->6m+zr|WfjMhrhY1T^Ou)5$h zY9;YRwUTt|wUQW9E5*9+uyP6VIRuGst6UP*a!L9|<&rpzTy}2!wo4|_=a;^5$s~TO zC6lO@Ow#F>OybCrNjja9NgTC*WRkv4$s{^T8yC#0rDT`RJ+10UjB@@>sv|K{9ZBD$ zIuc{6Bk8oNBXQK~Nctw#5jECfjxtpEh$k$3q_0uE;b#a@UYmlp*(0>x?=8*!0_%8(xgP%jE1FKS1B9Vm<>bOvfe z1@J9Fli-;QtyWkep*gT7j6(1mL~i6nU8oR7tB?=Y7eT8Ob;2W|`XN{$)^o$x4SSZt z+XXAdQ@}cP2&)4yEd^XlV2=-0Q#zcm=j&lCht?9<*ND1dMH{SjGH7nL!^t?30E!RZ z0a()taJ{fjg8hEL?qqX+BjGeKC?TN859?hgn3Ya>zL8NK0$hGZNeR$C8J^gEkzEr{ z0M*0xDv}7RdZLmE179;xF+47H{Zd$81nd0p4Fa!jwl~P6QUoyEu%{vhT0}|_O&xC! zbdE~i&9vtR>inn&)>2)4I~t&nDq*G<)^xC)UYH9oy2DJ{R02VNwu9OSg}QWvR7Ua< zwXp7C7Iq?TM0iHyUD2KsTCq|)-quCX-RVE#Df!R0@3o`rJIb>cW<=Hsvk_`#T};-O z!k8a4@Kv->&gvMvE(R^?2VO=~2b*)Ne6=$yK2__5s@@fCDcBSnQ|!5r(dB2__p$u} z)z=gZet;TQZOp5GT7i?nP$Vs?FvERW-uVVcaV^k(| zB*47J1sK}c?g%w5#zC0bS}V+k*{p&?JPC$E)tlRZvTg={MUhDlvw;p4b;7D-y4YAO zM-d)^!>m%FwwuYYFh)DH-Np2&=vs`4AR*XYcmh5OhxjaJ5kz8;6@O4*dsV3p*Z#@5 zjz~_SHZWw-VMbTf>Y^O=FnM&H5{8I3cv#f-sT{gvFuK^A;wWTaDv2eqqK&~*)b{G8qw(WZbP;Bmh-OZw%2ClUNu6vj zl}WFfTNLb6<{n0)OSPm znu|l)39>lrWN{@5H!>0$vdDy0bpQ#>^Us{>J`(tSBR{bDiCre@0JBq~I=yE1!pX$j0c$DnrWD(Upv?EsU3eAxb zaa2#~U=dzo-;he9n_1F{>?9KFMvL7pmI-`J@3Hb4O{!vy+M|YIL$U^ATb|s=!sDiJ5 z26j1^@6dge7KKs=j7PB!r>cr!j8L`!di4N*t~y%^u&Wq6N`E1%k7&C_rBjhyJ%dhV zL?Kg{Wk69i>(SAL@U4S&4NRV;jAw<~8pcBf%qzUu83l?a6pG5=TL-x5ib|l%!K6Sj zIn^P|GmPVe6a)zmtNu*&^P9o4^ zwKJM^h(j1E8Gm*rscN>m0pw_h^;JV7iak~_UdvQjD=-ziS8Sp>M!IE;N2=L>^8u?} zwW(4jyWw0=JuPDNN4ZcmP^!MmVq_N8evPW#2t5vl*)fV#7BOG6vsI-`*9}8HQo;Op zflB$pAq$JffQ71k)(%lNT)q)MimW@8*rC9R;2y5Qa%NA}DuoS0(oj~2CxNTPE<5D4 zHg?Vl55?`_nLD;>j8>zub!TCJOstKq1e7RT$<}s_SQi~tPD@J8ik@|1Yq!x(*pbt* zQp-oG-e~oq#BSwG6kGMWSbeV4fT5wP#LwzL|4?Pp!)Bv7J)qv5_=lbIC}tg7 zs)GnGqg4*E@((h72h_8amr0n`lSL}rAc~yJqB5ZpQ0~>bMrb{1eH7XZH1bw~%Ah@l zau<`eh?F}zic@6qDssp5!{0i6+qbqqru!gq*nQB*%Imwk4-!Yc50bv;`yla@?t_L` z@@+9RMejNyD^KkPb+j9Q7V!tWSCWpqR}%mKy;97*QuK!5|IB+Oaae}^;qH~hQBG?= zhI=J()O)2UN8iuAl6aE)g74>ENkm`wUMc#wPT%IeQq!m&+%ur)4TBzV{Uv- zcJJ_Q+|Y!NgKtBB(VGU5;i0{vZ}4xfikVz4h2LUEn~POVMXY`ez}WC=?BxFBXB+)6wS$%tSpGQoQ+&I6hSJQfW=Zw#`)J6|2kXX|L2V2RD=qMh*0 z0ZasEv)L?^4)08q1MdtrlFr^~?48Qq7WOvd6qEo^&8$a%+XN@Gb`pCh;smrD<`Y?u zwh1=icyud_8Q7Qs?M6I~$8iud1U5r3{eQ&rI1Yp)e?uFAK?lO#b~vrSR|N zFl0O`<3V#?Nzkf4D_`QXHym`ndyqQ7{8Ogyn;)H_|c_WVe z4p#hbfE)n$2drfO&*FvsW60~Tr3kN&Bd_gC5?)Io`;y43F#T#ac_oGHeR-#_S0*pN z)GWNblf1l=f5~?2w^re$X7ZAa|E-n$MkX)1$e!Dc!XBBtkVT%C$#XK<{p<{3_W*hJ zkxb!#*%{=SUuOu>a>mSJ^eemg9PJShmUydWckjZA5JS>xk zWb$*7JSdX~HYErT$YfIj*<|B4f}l1IkPWbZWkU{G51;h|pleISf9+|8G>sTX`yNk$b*tj~!c8uHwTkn#{&*I6QFm&g9 z@>BTyR3>+T9PY4?+l}NlEBT2`R>|a6ncO0in`Ls7Om4ivD%>cO8?5AdnOrB6|0p4U z*RCel$mD97tV|~>L~@l(mdoTynJgP1R}7F|ne;4uNa&Ht(uYWQI8*2zAmL0B8X&>t z1c}=I!Z{pOgtsT?GgpIOk5&y+4#0rQD}=N zts-%@m<8u*(t=GwiKb zr3=|sl9iY&WTlg=9S}3_;4=**BYnP*v7Dp>()9TxO(v-(VgYQH0b+(Rvz4T{NV16} z$;1SGlT3^*l9*r=5|c^dZa%?C5?1mCm@y2H_!1Hati@SK+)7?F5Yfgu>t&*oiB={W zK@>DH5kw-`cz%Eo7vW$RCqwiy2-rlBf#4n3b=@jF;s1^w^g|Qy9sXpa{|!C>u9lNA zEgS?nIW#$wQ7tl)ZJ3Rd2reZ9Gc_`kFfJf}lFe>|Fbsh2JVlP(p@Q(cN(iZ?MdGj@ zjqL#_F&)wfQJ@FjezDCqX$R2f#CAT#@yq&L>tXRLIum@gQA zK`$ckib5#pU7x4cJhvnGRJE^_+a8v6?@Im>-d6)6q*$^_Hz}A++ktKM4ZJ)E3XxY; z;el5F_QC^~T>I{`wJue<)F6nn!f{BPg~$N`NU_X$R%+^ea@V7LB8-h`BcnbSStf&td;B^;klCiW9%b0f9xYS|1&cCXXr24 zKSMXk{t2EXH~$Km{bTCS{uw#2e|$t{|MU@g^DpW0w_CQ1Ig=2ZO_N!hN0YiQS+h4L4hIT0ATS_r zVrmL8H!y%C?WxxS{frW2nq}_gKrlft7uwkDw>&+sg;_UwFahb53@{d zYt!9zxBa)Jy?#rszx}z}rf~g#&$%-&D7L+}-QWN7XPlXH&pqe+ex2_fJ%4rePNYYR z5ka=HYJ2TNHTEKe&}oFQrEIoG8rrMkH5mU1-g0^EjOsaa(j5p9xJLVCRLv{@s`{N@ zBgC&kC_$=l+8w`%Kb(P3(tfx)%zm%Iwu> z-QVGw!mFva&#mP+7mrZCLVviHYV6g{`eSut;JOx};UCqy+@2|D$#sM(O6dLCI%jS9 zW&S)|dk_*TU=G8J{^?<;qSqYZ1(jN(6?OUmgVAKR1O{1yLwbdVg-1k2MN2WUaq$Vg z6Z<6f?U&p?B{l7~^o#)m(f>n#cpz#)r{MJ}+KaZ~J#bYH)Az$nGk&q688rar60}Rzq6$*S z0TwE;J@|FprrLm-(fj0HazFV4Ue3qyPw}JCT15h+6s-l=TYu>uRXLsqywleL3Z0w7 zm*TzX3%*o69bmsfIRcz7a7DmTIXVjOIVuzIGz>2%tAJ8^HxivukKt2cKR{3~0YqHeaFTSeBPZJnHK#Ni=87l5kY2$w%;#jYdlczGAp!p7l^&GJDx?QY z55x_9z~mg-AH;^rXo+iG(7g8STgAt(jXfI4Gq#G%tk)vJJf9)IAavg!w%zRW*|j&cIl@F-VfY9HQ~ z4%jZXx24&1l#fDfDexlTseu_3ku~ns7Wm^!uQjWJzMy=#u3sQ;g8e3<&uqg3^qfIg z937?6a%!gM{E?#Lf$$z_K`r9SSH5i84Wcbn?GDOWjC&wN_i694Cb%Yq9i_oWN zlf`6RvVNF$m^e%~Os|uWgyXqBVjo@Kz|^2rYv15LQGKG5q@Ti<8zRH78w8>NOQjy&qdsFco}I za5Rp>)*w|}Z12Q@QJ{fA0|)d@#VL5;fI*-Rvbx}@DXUgZ-#FsRA$k--dQqE+CYqp}-e5PU&$gwf zo2e*Mk6*mf4$?ev$#ls)#5}|@B+XWn7MT{67M&)g#iYfKNVG-TqHNJN$rfXaEsQLT zDvU0a3S$am3lnP-mq#{6HAXi|jejxAW7j1%CtgmB@@@5P@@*)MDvd6cN@HrHYNKnV z+L*;ri=!7yi(`6C1&d`O10mgk2b<#t8bF4CFcA7zVLSN!?Y2;ZpfQrCkr^M= zG>SU#8Xjp(76bMB;m6@$I#XZUmEp(Rs4CMAJ*)UW4J$#x!?2ag5QLdw#&hrjdHGoP zv18|UHZ}^|<=57BG_NYyy5rYe=~{fJVoRwIbH;%0TTv(~vYEqkQGbXg*cilXG$dG5 z<%dzM=@hR?9u88nSu{YLsnO8u<>2QGo3-eufK!Kmntn+JLo!`ThY)c+yg7Vb_~LL= zxS+%&8t#A|P%NWP6^Stf4Sr0ktZqGc@R{dZ50;I?U$?f>2twX#PbKfIEqL+SM+z&- z@F5mYh5?O`6_E~)w14FaW)+kSX2PrKm%w8V6EnwQof%e&X03?nmrhh`)LOGfqs|i5 zJmxj%mjdS)2O*NJ=Z)BLmiZuJvlvlt;lnJGY#8AhyvRU4*DBE5wKZC{-fFcd0_v=bhd!WXd<4>O(u5>6IGMd6EzdHlXZmwu7J6?A>dKGQN0iEQXdTX zRltV<*8@@^Sbu4`I4y>M8CuLc}t~-yDa1vkI@nOfSxJ4e#jp2gj z`|(1&jIA%N>XK(tiWxWrBcwe%k=}f>1cBwZ$VV z)~?X36s%8Up;eDx>eXs#(XWXJw{jY*294z`#+(S|$j1S*;>;JRL7J{yqNLc8Mnu*| zHb=f2c{x%TfkxmF+z9K4a3NWps!4@3;X*F#;#^i&xE6x>RBVl5v3sx;LXt%NIwKva z85?T8p@035{>+Or-<)3d?kxEVxN=ha$5`FM?OwUH)xb@g^75Ml1{~;{jBm#x`1nZq zkHiQZ*>g`y9HibM&RFz|+Ye1M{Vrln=%bM>#jg@1*QaC2#vX3=S`t zd4B<1o--3p539{^e9ICAj;ILwrB0*QiCT?P#De_>_(Fi0dcTE!1kw*3ivx(p0VwSB zupq!2Bj_{@38#JW;FbZw`>hOVJh(1!!CbHqD-IO%xI7_Ow2Aj{_XrcjLa~Oc5z57R zTmv^xXb>8?N4PD*M)4?jRCtGbll)4E6n{7^QSmxK)abPErMGgSB$y8q!ZqRAAe~j8 zfD&*Vmq=px1R+)xt4`1)YU9NiU7UUh8N?6L4AG|<^IJb!Kx znaeK{=BpZ1^VJRNxte*}2JHfIwr-KWky|OOHEc$k@kVX~*~ULAY*B4dKccavHtBa5 z_P|+a7q^S-T=_f7nAI|^xU(fTU?SD;VCVfN3XlkDcHUja2dx06+7f_92jxIMyO{3F_VN{4NQ#LJ6zg#ao^^?1c+2znb8%{wq9m@}I!G|&!&BlPY~8+Y&CxM_EbEMK+n zzw55;MZb7q$f1Srw70*r@PE*d7VeI>KKS6RH$V8`&+^Ce7m-oVC-*(}%X`YEL^v#GK;a5O6}O>$zQ!xB-!tXyNo=#eZQWjPH$l<0O*A zOPYabARbDF@@bk}l#BC79-k|WR@pSvz9*B(e4(ZsmE%fM$QJtaJ;I;eR?^P%Rt=1yjlT56DYypE^gX|K!o zUIj}mA^Wd2vpUXw{eOb6TDT17?;$n`3E_AX3E!l#JZ?T<-DFs=Srf&f2=f3wqgSZT z6a~?;{bKuZ#T2PAp1nlNxdd~}z!G7%P6_Ewk?w8;q#HJ+ zbV+xIGzjnZy1(^&_v7`h_0C$e&zb)m$ILmkW3BTyTT?N;d;iKAf~VLKy<({oKtY^- zw{Rx|Y`Se+ZRigjQ#)@>GsFbT(fg~V8I})VO){EK6KS28;yk;cDB@hq1>5-O>Lb`Y^nIuzYGtBx697?;k%BATh~zQ^0-Yq{z~W+!lS(yjRR0{#-$ z{j;ueA;WRjfpfZpX@ON+(dTlG!QIR0CubHQ8~9#6uJ2_~9%pIC7d$Hj?V)iYb~?#1 z({h=P78y}+QPdVc{dmG>?=iwSkM{WpWGi0d@rm43AAUMZ|8HWf(mRDI1Bp&xh^=i@ zRf0ARf8JaN6eSg^Xird{rRu;-RdN?2))xIkaZ1rK?h*s^U-Tg|a#8?9P7g zb-Bkrw?{PUW(`4C!E~GN^6@n1DC_JW7?b+ZNna4DQxbaayqVxQR*0IaHrAV&|pT9T=lG*?Eym0JdzmO2%?_b22caLk!+~dx|x#B%IQ@Wuz;kE1sE*TI! ztT0@te-MTj%zBnG&+AF#g{f#?M8@J+pa_y!`ZNA08Y@B_A^Bh^#wM>}OG;DM+S(ea zYFONz{nBt7PYY%C*~A*!y4CtjFIV?|@+n21e)Nn#S+z{ho__jIl>+L`mYQ>5E?Ikj zZ|2CNJoVQ~#`H8c^7hEGq#8@w?}liLv9oJVtvdS!H-XzBI*n7%hg*?P!F)n}5L@C? z%LS>gK@(qMW63eGKqSKw#xL3T5wL!P5QR9hxkMRa@v|nr#3-0k_rGk)r4{|CH!1Qw zo8wF(9i|R7*C3s^AtQ8VE?_7Gp5x*P*(^C-lrti(4#hZ=Y_gWdWGPul3sn)}7@&rr z5fR1EMG>MsD=;q%0r&QO?0x#`88g*0D$2Y4m%JZd)H~8HQ3r+yH&Ob0em(p-WX*w} z?ldkYZ#P#SYu)Aaw&!D8P@4pdpNMK*h&56X*Om}@7irfHlgNn3NDgd91-zbQU*~W zksU#UIH5a5mi|DP-)!2vRef6evNR&voNJeJw}GUd#BJAg_lo$E81oBY^6&v7jQZ(}sSw5wI6k^_7;0;Fm+Gz_%M&=Jgau(f`pFtHRL4k8)~QV2^=9 z-&vqO?|^Mgzou&7Qn%Ck!laHxA4e z!!pA&sz42_zMN&pUbaF4lL`4e^c8a_i*>_|C02dxSXO(phDbHdK)h_MTsIPUJglX{>g0T4jHolPU1z!;^_u+to6*f6O8a zQ@LrK4nW2vegAxHx<@Nt@pN1uYac82)GkH$vSxR{wN6ajoit3P0CRpcBgnu$p9S4a zLt2M&YkB!=o)kCGAnuDF{qB}cl9KTFS%$L=D{Z-FZvEF}7dZXn?L=RrA#pKYN?GM< z^2Cl+0DeZn9kN$Db&UBZA{l|x-n*#arkai)(`u|!uMWRawUe&6qZW1UU{anSNCnlF z+=$mjAh>$EWT+yWX{A2y&Op0>^=LwL2HVOasQgT7bLT7SQoj@u_jNEW_tL$PUuHY0NU|&pmu$Dg$<(S zao{a8_V3{ZAbBgNCDNjzlp`|s;xsF=l{4i=-uy$?ZAF{2wR=%^J1>O3K6*D`-R5xd zcAT&??!g!4-1W1S&E^bR5ZUo_vU^OrSb9BvVDi;MulMlC;hOuGYl&vX<%YW(9%m3>q+~aM7oLc=%N^=0v9by}IRNt$0p)k=ndJPAI(;9D*eCmQ_VSN$r`bvrGxGJ91w3GG5eRgMT*-VJt8{V) zc;Yte-08Px2PhM-lE<@?az1g9c)imW!Mtw^0x0*95QV=82KDIz&u58{*;3DpC9Rl4 zSfyBql%8nzwIB7Svsk-cgO)=rfJQfd8`5HKs~8&U&xM79So9|!)^WX@5Rf&HFrTUZ zdToGAOKq=Cq1Cw3>GEs4eA6gMkoUu*9nfIcS8r%VvGle}?R6$!-R(Y{6V!(=G9jo-39z)6 zo^Af*{*g{VGsj#a&oA5j-5jxu)<7ah8SrMZwP{Ll9VkNJEA;KZ9dn?AB}8deRIO9a z{?PL{UyAC)+j`ASNApw;Tr=knP16hxln;Vx)%E0rV%Z`88m@Crp^KciIkZWKPGJ#L z1O;dur1h#x^ugE>{2`3D)ucQeR;@e zp_`d3tx+38vw>sd-v`ZnZ=7z3Jpchczi@SL201~uWyp>EjoX>W&4|TStDq;O2S(iZ z?3n1eGd3wk|A}HCm>#jlgq*};->1KrFF0e=oA06iy#<0ov}f~-^tsx-^lt;NOEQaz zTT9isiJUsdA)=6!VVZIIerZL89|u9bbuS~)_s^U*^K`Pw zI-fZY+wKbFf4k3}p}jAZzXKNHh<4}tT}eZtY(gR$&yKu+$ai}K(H#YaAAg4$0MpFl z!%ibzI8e)J%N$i~MDY(~1`Y6yyTGufgJ z1{QB@P+HH6c$B6{r`qRg1T5v(a4lNTPkr8$onlMa1VZ`4#E3q0O=#Gml@MM|#!9Sl zUQUiUhw^@1e)APkAE^$hc#>Jvf71{9`E9S3?M2gK^Gx|dt@aYo>io9p0T4)-Ve_~~ zxhbt|i)){Udj77-f5pkHTc6?e!Ro{Mw4^%3Hl3bK>;As^SfKqn2G7gr@aDUqVEZLv zy;ld4121D*JJ!F6NUE7jn7iR4yb4a{0CrI9QGpL!9UN`{r-s(;oC#32{#r#_3LQKZWky+D8BI!*} z(HD${O%BmkrP#u_5@Qx;5=jnXLDwfa#q(tR`7+<>+2{EVVJU}((cnCO`~=ih)t{w@ zH@5c%K|Vj@nc$1+=)N{ypkJ8hDsWK!@@SC{xspPwmB&s2ct1Tb(U1>3%(pgMz1b9G z@*p_>mb43p>gS%Rju1?i=__W&OArZrOrN~Uh&Qr}9($H(+JKx@+VJ+0=-%s~+Dd~7 za5?;Pk3Wt2>5TXW((+vhmg$GQ5@Bkp772<8+g`o77M2MJeYixuk3;zGJ(3hU{BGET zPjHqQ2Rnra5DO_n$}ifO2gyxYK*zsj1=n_if5NGQe7=)s#n_ zb$Pd>x!v_U)A#auV(Rqyv+3hby9U3*CSg|};9WV(b4`R^{P`VxWrJF1mS(ds{ur}O zh<2sc2Ola1ZYr$UtREpuaSZ;5;#R8ClRg2m-WjE;THI#44m3T4nOSv@32%R@iLlpO zkSSf7H*bWjj!lvey5(0pZVksZl<51`x?K5nr`8Kr=U;E~Ucq3Q zfYEPJ>esi|O@a^5*Q*x`R`+=~pT7?izebGqvj%yhPn@t59>KoYjHdm$clhUJ(aBqKjM2 z+TAaGt6BrR+pn5^RWpi~5X^)FA-aOk05K_D7RlR3=98dI6pXd+S&k1~7p4Bs$yS51 z)NgzTddrc*Z(p*k2nt`tb3-(+lo$a#^fw=VV7H+!D$a~uoCsuTMbe&a?)bibv50AP z^v;Bm>(z1Ko$yY`E#85jM;m#%3gB1s?dlz4hoIPT=M{yD^bWP#Q=XNk*k;1MQee#0 zo#F{C$xZoA-U+gE2wxy8n*2byFt^SNVTw*Klos{wW|XDKE`DR>O@t-!Dgnf(#9$)3 zYID?$kYoq+idA=8s)pFR1b*>{p6FGkYu)?8EM^l41N{@@)PQ=VA?j z|L&A=9%&+URzJ`2{p4Hu5cpu!0aSc+dr2$$#V~u!U>HgsDB}>md$lFKb-2~8ZK^fx zLBsbViWHH7?lrDwprwC;v)1IF~*RWjVqz&PKQq4xkE zK@2(BuP9Y44@J-Z$-CvNC>MGh-Sa2}=4iv^$`9z~LMyJvvw_Zj?Uzv_Apqw68-tz} zf)_Gq_XB)=^s|XvNV;_ybRN}9(EnA zQ!Gm!WITX^(`;dS+X;+TdGoiss);6X-KsW~WvAr~^)rpNIu)9}$-dp8qr7hUr4llV zuz`04zX=kWEuWMke=a(4w+t>Q;5G1d^$A;0)mPtQcAFZpFPP+h`wg%r&i8X1gEda} zA3DoSq^nl&NHdH#WO0j=s6s32yI54!W}5c+6@pdtwo8&g`)ReUdDr&rC{s*0XOeHi zbZ7m*&3Q4?45rnOTo0jKOdHz!%1uw5^0n(^GkBZ3HEk+WX}%5G1yY558g1H>;lc&- zwM*=$d7jQh@Oq(FWdJW*5VWh%sgWENlK5F+dSJzp=bt)}W}Gpl%5cOCk_SJUW2<>G zrU~#QCVnfiGUU-+DSom;X<`=nDvxkT3?~(_gEVgO&^1wY{%Piped3flpB29=W`1Ey z4Qj$<@E=6bNd21`Mu;G1sFLz_S-BI>-cZ`hh+G_^(lote2SAym$M#j6@Q8`(1%?bP zO-Auk=@LSZin=GZ(o2^x`lr^ducqI-#^qbmZE6`KtyM@}cE`#&6g2HoH{hN>DP{6g zVY}nXD(HDStHo#@T@(`a`pf&LK`s+WB|&GmO(a4)#;?d&VTUqFKQAWCc!&6%gU-~C zN}jdKK+~E22X?zF_71Fu*qEBd6E54)iQLSzOP}MI(t(e-BkGIR`t%*1X@&dwdg6o{zwVPdyd>{cW0o(rVN@{;=`c z7XJfd1~X+tB?X6S?l!5xSL&ZLlM$Rep1=7;XS|Ic5m#fN-+7J0AZVwfhw_Al_C;1YxTMp6#9`#}GL;kcI5=gMjrRdFea znYnOgFk<-o@T+8I6SJrxQt`Rd*V#jOu1!6!#{u+QM^wi!(69LXwXU>S59cS2!%Tz3 znq6xC2f{cv5kF(s(ZZaLzC6LL8V#n>Z1Hl&fMbKkUG1?Epg!NHRkEuI5p0aR)SE{w zYiY&|we*#rEvXyK`D0`+cm$F)I}rb1gMP_+C2x4$YF#=Qn-+!)Top_Oo-h{}cLdJb z04y5nqd!4r<-zmyGv5+_40ILY@WrQ0F$zDCb5}v15p#x5n?0@xr%ua*LZA$rjTG zm6ewUvN-KAzQvNG_If)!4XBP@6|C~weK8`H(j|SztlKG^-9EZo@rhZLXF(In_I!GJ zOs9{&xXe$he13=*S3kw9s8Z!b3QS}lJoH9HJelebJLqe_dv0SjM^T7@lgKM|E8r3{ ztBNeWT#JEYR}s)6+!i71c;_gA`P@>yljF zeNd8^cdW@2y13_mti%-B0MFX#GllwojcdPiWlE;Z6pgvA9;6x5W|bB!(!ptt9U6@k zbcIn*H|A03z-a+X7`3M??d~0%9*m@kKlhQLt?rMLzGbC}*NEeB`1$!X;b3@dxs(^D znfvkeRO}8=8kI+(Ocweu6?@)V@}{~Ujt{>6gAdw9jcZ)ku>am5A+%(L zCObz#!`5{((2njP1w9i(gTWWAEP%H<=}E!d$MA=S0}>7S-Ky@4;~sjvn$)c_rqC@epG}lri*K~-)nJ+KiPiV zHv%*!{6=58-&7tEi|{ODpX{Al`kx&=9SqJFeBI5n2G4cqV-)~P}JAE{XlbB zmtVb$EH;wgI!H?s8h^q3*~t&-ftV$sRs^Z?i|~HUgN(%c=gr&aXV3t{;#14FbER(L z+NhkpeRy69rq16!Us}yRXjKL?5a~RbTK`%tQ;9!I{8D^8hp-@6$szY`VztX82L28p z@WT14NVCz9!d7M2VehS`H1h=M;=aMMt%N%9LABQ(h%mwLlNy+w+_j%B(~(Hk<884b zU8F9NxlZ=ESBEeDej!n_v51*v$_)1tQR0Qe+`dlk6L#%X47axj75<|4NH1Y}cB}}4 zd&GF+v`(MVRjP{CPh|?ejNCYFtY-risj7^V(_muSJB#3`(i8!F-Ed#*9`xpTyG}_* zy3Ar`f2o%>YnZ49GL+2_S-bPfgmhP{aW5i2dG<2=}3UVa)YSlu@ z`BU`I5NP>>hBa%;(MpArB zQ>E#$?&S1DcnDOuqAD5=R`{xzjmT&l=u%y7@Rr! zyL>cR_>lRHTFqyr-ijWDC{iFoxulXr&|-KeNgZFVjmXk$I(N1Lvp@38;qiTjw@R2E zMicY!sPp+D!%oz;gvYsGzr_zBLPtCxi{NVX|4{n|)Zv3j8s zB#b`M+}`3DSF%IL1CaUZ>$}tz?G8=pE^Ymy*5XldnI?BxB3pbt4GPbAo(XOtd4Kl$ zD`Pddh7lVJ)|EokvQgWf&8l{J2Oj~sb@T~I9o~e~M=F~f z5%4GDJ5{keC=OdwQL29ZVG2Q|(L0SDvV~ONsF2bJLqrPLC7+4k9E6Q3d^{G>P#@k% zfw`*{u^8}gboqQrCYA8ZLHU#ud!qXS4izd1siVX{>s49PO&LCyx`CPAF-%umCyLCu zS0?Q?qRE7*Cjoz`LR>x$Lh!?{RT_>5S%ZSWU0U3gyOmpOGrRzyU4j${E&Br~g|rX+ zQq!6&kt)&5x3Cxg#=?X;o^a|_K7Xp=pfL`^Q7kS61UNi5CNrW7Qi^CNr7iZZZz9_G zjIjTU*9^~V_(Mz7`Jk3x@ocLR?v3v_8O%NJODkFxu;p&U7!Rx9BUDjz1K&0`zJtW< z{wCd}t7SbTbpN`aTNr4_x+~1+2G$=oECr=hg!B1OC*K@%vu)z?vXn6)$(_t^Un>kY z4b5yzwz(|Ry3$v9H#S?br_Q}^OYT}zu%Kt^vHMusQ$adlWpa?Vz8kTy2yOtTW>q6^ zXVPJSZ}oIL&byow`uh6YAQ#=*K?`Y^rmh*;<9vA`ZvC-y+2mPUNki%FJEI0i+OtYe zvN8d6OCdKi)iooRtkPOgO81fL=DC*LanICYnk2`9=8@u2&*qT0ZdF3l_-M)Vu#v?8 zh+TSiPpU%DSLS6VjjgKce(jWZ4|}avyZ86ND~0a1hwmf2F`kot(a9N%$iU4EhtG`X zcjZL6uDT4l)2?#SHYd$wxgx}bHmwVEt>YR2R2%xH>QW&S_U>p$5h;?mrE!nTjSV%N@llIz5YS*Ev$F{b(*=~zN!R$)v%USikwVlFUrqJad zY}XdIGE}z}KKT`e3WBEk#Y4+YSBbWXK6Z<`%A?ydG^d%S zX#`Oo%-mAMOh0g`g9Uw(rSCD1K%oGab4t@_lb{JaU#LsFOScaSUCth&{yo$rM-|^G z_K`P8sZ@#&_vq2N^-Z;8`eU=F*RyJ4g0$>=8klh6yT|~Pj~5DSstVUPJIvGYtDc%AgCaV{6VX+w|;-d*by4y zoi6kctI%di1#rc*!#2X?9_ak;r-UAwLv<7=0T0Ue*Wq%k&{(!qsRh-u?a~c6wb%RZ z%!A-YjyAI(UXhgmEfW$8gjbyyaeO;*D6wBK6nZi;$tQmBZD7O>~OQChVRY|bd zqAkoBSlHdjlT%>kLZhP^c-6VlD5sYUvjTaj(pC;^B!fIOY5M_VM-^H&*hWZ7U4;~u zmdW_pnyg5;oE|^Fs{1L;*_zSA2^&se_j{WenBl9(aKtlzxePlhI4hSXhcURJnL=tG zWA@Vcu?^9%J>X!$3j2~Krj_6fg7y1c^(;XyBLPO9a!?}qJXx> zAwYO`HrSdyCb%;0VqXtuddPTjzPPI?d7!EHem)o{@aub+)~m;N&ph7ITB#MjurjXU z{lx#oS|CPRt$Y%t)PF#R%px#U0$KBEoK~z*QY!4bNey6Ktf@g8pKn?tMhj=%C~+4q zGFh~!@8xL231UBC)MWKAGD}hZG65;lI-wg!WegKYx61LWhu$$3H_IHg%UGJM#YsoX zl^6{$rwl{PP{85R`ErZ|vBdUDthj}8q#%ZPm~+Z(aNKyQ@s|v_MA%zU3ROHTUd-@J z6(mjV1|SEcx)sKUf>NG*rZbMkVPfc`&2A)QK&5hvM8P|Xlg^HcNS5y8j(p}cMAAN0c_s{wA@eh-zh+qg96#sH+83Dox{s)DNABmc0$NO~Ufy!1GuC!)FmlBJG zgAmY@BglA&5ZLoWiY8P}3#1jntNayenh$T&7q_n26;o~bKPhTHKwV#7 zcK7lFzkiZX+`4BLEU%IT&Ed^?+BDfKxCn4fByW*8j(7?1&qd}r9y?}+Zli`bdR z$tP>JPyNE#W7-&Kt%_$=JAXW*N!0W>D$}1Z@$L6i51!?FbEO2|^tz%7y)3c|raE<9 zz8&SSct7wzFgwe)2KySeOnYzoUMN|0gAY$70G1!xeThH#_E^sOF8IzfPD84nyP(Ts z;$I)E3197IS7hyW?hCwCS*Z;V<}&vzS{)e|{TfgZOmd%ePi~!bpFgd0{gv=Kzlx;& zq&t_Uy(2tkIY4-TZHH!qZB=~WSVZN@okMnCVWynwYU zj@@p!U9)|$wvKbt`cN!x?+`p4cWC~ZX#82tr_gx2S!w`8$;rV%3Fd)cK|GXD z9u7(fJP#)@C_!9Yl$>DjpNPuM!9@v$AD_nwhWum0#Rd6Kn(IFr4?O?J7YgN~nvH_D?y7FgrUtC6o(F$pwbr1(=hPlZTs<gR$N_;PfXZwVAWG2xmjYA5oBl_GP{KR*PYO!O z!Be|8xAOEkyag~g{`v4g_H-x@m?I|%fb9Xk&Pe9r#% z1+&8kfF1bn3gL#}znwXFI5@fga)xU>?Elih{}&BTN&aOAVrPdhrvJH_Kkc)#gW#j^ zcZG0`>%R>DV+Z2k{Bzgv@IRvf0zshAe`%Z?e~&7N`_C%;%aS^e{0;}f7*ce|9^S{-(?(s4>gzv@~`y)1@XXl#Q&}k zuEBT4UmBQ$=kJE0U@p*qcjTY(hp(-FJ3~0Q{_Y7B0)g+SzZ!u+{(C{HUu&A&IyEq5C1e_D*Vux~w liHY!t@PI+6|8TyBj?V6mm?oyEP)>Fb6qSZXTu}n`{{Y0e Date: Sat, 19 Jun 2021 13:26:06 -0500 Subject: [PATCH 014/125] better get acks code (Thanks Tag) --- package.nw/lib/gt.js | 59 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 13 deletions(-) diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index d7e2660..a8f828e 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -96,7 +96,7 @@ var g_callsignDatabaseUSplus = { 202: true }; -var g_acknowledgedCalls = require("./data/acknowledgements.json"); +var g_acknowledgedCalls = {}; function loadAllSettings() { @@ -11123,7 +11123,7 @@ function checkForNewVersion(showUptoDate) if (typeof nw != "undefined") { getBuffer( - "http://app.gridtracker.org/version.txt?lang=" + g_localeString, + "http://app.gridtracker.org/version.txt?lang=", versionCheck, showUptoDate, "http", @@ -11132,15 +11132,25 @@ function checkForNewVersion(showUptoDate) } } -function checkForNewAcks() +function downloadAcknowledgements() { - getBuffer( - "http://app.gridtracker.org/acknowledgements.json?lang=" + g_localeString, - updateAcks, - null, - "http", - 80 - ); + if (g_mapSettings.offlineMode == false) + { + getBuffer( + "http://app.gridtracker.org/acknowledgements.json", + updateAcks, + null, + "http", + 80 + ); + } +} + +function checkForNewAcknowledgements() +{ + downloadAcknowledgements(); + setTimeout(checkForNewAcknowledgements, 8640000); + readAcksFromDisk(); } function renderBandActivity() @@ -12694,8 +12704,31 @@ function versionCheck(buffer, flag) function updateAcks(buffer) { - g_acks = JSON.parse(buffer); - fs.writeFileSync("./data/acknowledgements.json", JSON.stringify(g_acks)); + try + { + g_acks = JSON.parse(buffer); + fs.writeFileSync(g_NWappData + "acknowledgements.json", JSON.stringify(g_acks)); + } + catch (e) + { + // can't write, somethings broke + } +} + +function readAcksFromDisk() +{ + try + { + var fileBuf = fs.readFileSync(g_NWappData + "acknowledgements.json"); + var loadedData = JSON.parse(fileBuf); + // some validation here? + g_acknowledgedCalls = loadedData; + } + catch (e) + { + // file failed to load, probably not downloaded + downloadAcknowledgements(); + } } function onExitAppToGoWebsite() @@ -13588,7 +13621,6 @@ function startupVersionInit() { checkForNewVersion(false); }, 86400000); - checkForNewAcks(); } } @@ -13716,6 +13748,7 @@ var g_startupTable = [ [startupEventsAndTimers, "Set Events and Timers"], [registerHotKeys, "Registered Hotkeys"], [gtChatSystemInit, "User System Initialized"], + [downloadAcknowledgements, "Contributor Acknowledgements Loaded"], [postInit, "Finalizing System"] ]; From f5690e4bc6aee88094f9478841d20efd48322ed1 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sat, 19 Jun 2021 13:44:44 -0500 Subject: [PATCH 015/125] more better --- package.nw/lib/gt.js | 1 - 1 file changed, 1 deletion(-) diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index a8f828e..cd2a592 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -12727,7 +12727,6 @@ function readAcksFromDisk() catch (e) { // file failed to load, probably not downloaded - downloadAcknowledgements(); } } From e7923f447f3a17b96cf66f37fe94efb737cffb4b Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sat, 19 Jun 2021 14:36:13 -0500 Subject: [PATCH 016/125] fix line 15581 --- package.nw/lib/gt.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index cd2a592..ad79511 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -15578,7 +15578,7 @@ function searchLogForCallsign(call) var worker = "" - if (g_acknowledgedCalls[call]) + if (call in g_acknowledgedCalls) { worker = `

GridTracker would like to acknowledge ${call}: ` + ` ${g_acknowledgedCalls[call].message}

` From 1bb816621263bb7f0754cccd5223be9c96ff2481 Mon Sep 17 00:00:00 2001 From: jangliss Date: Sat, 19 Jun 2021 15:44:51 -0500 Subject: [PATCH 017/125] Fix linting warning --- package.nw/lib/gt.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.nw/lib/gt.js b/package.nw/lib/gt.js index c332732..2bd856e 100644 --- a/package.nw/lib/gt.js +++ b/package.nw/lib/gt.js @@ -12174,7 +12174,8 @@ function callsignToDxcc(insign) var end = parts.length - 1; if (ancPrefixes.includes(parts[end])) { - if (parts[end].toUpperCase() == "MM") { + if (parts[end].toUpperCase() == "MM") + { return -1; } parts.pop(); From 5c33d4a910cc3535cd91751489beb37f8d704ca3 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sat, 19 Jun 2021 20:58:02 +0000 Subject: [PATCH 018/125] Update acks json --- package.nw/data/acknowledgements.json | 56 +++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/package.nw/data/acknowledgements.json b/package.nw/data/acknowledgements.json index 67aa8da..f0852b1 100644 --- a/package.nw/data/acknowledgements.json +++ b/package.nw/data/acknowledgements.json @@ -1,4 +1,8 @@ { + "A41MK": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "AA5KD": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -31,10 +35,18 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "EI8GS": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "GI1MIC": { "badge": "img/emojis/pizza.png", "message": "GridTracker Tester" }, + "GM4SJB": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "HB9VKL": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -43,6 +55,14 @@ "badge": "img/emojis/speech.png", "message": "GridTracker Translator" }, + "I4SOI": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "IW2BUW": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "IW3HMH": { "badge": "img/emojis/logbook.png", "message": "Creator of Log4OM" @@ -139,6 +159,14 @@ "badge": "img/emojis/grandfather.png", "message": "GridTracker's Grandfather" }, + "KE1Q": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KE4WLE": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "KF5QHQ": { "badge": "img/emojis/trophy.png", "message": "GridTracker Developer" @@ -159,6 +187,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "KW4AU": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "LA6YJA": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -167,6 +199,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "N0GTO": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "N0TTL": { "badge": "img/emojis/star.png", "message": "Creator of GridTracker" @@ -183,6 +219,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "N3UGI": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "N4MCC": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -215,6 +255,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "OZ8QI": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "PA0LMA": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -231,10 +275,18 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "W0SP": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "W0YRE": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "W4DHK": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "W4IPA": { "badge": "img/emojis/beer-mug.png", "message": "GridTracker Tester" @@ -259,6 +311,10 @@ "badge": "img/emojis/trophy.png", "message": "GridTracker Developer" }, + "WA6JQB": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "WB6RJH": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" From a4c97fc91e0bd29a161fa59a0c35a09d0a511e66 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sat, 19 Jun 2021 16:19:52 -0500 Subject: [PATCH 019/125] update acknowledgements.json --- package.nw/data/acknowledgements.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/package.nw/data/acknowledgements.json b/package.nw/data/acknowledgements.json index f0852b1..5d79454 100644 --- a/package.nw/data/acknowledgements.json +++ b/package.nw/data/acknowledgements.json @@ -11,6 +11,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "AE4ON": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "AF2V": { "badge": "img/emojis/books.png", "message": "GridTracker Documentation" From a5a04f383671e00ae7d8a89f30e2cfdf09b2b8f8 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Sun, 20 Jun 2021 13:13:40 -0500 Subject: [PATCH 020/125] update acknowledgements.json --- package.nw/data/acknowledgements.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/package.nw/data/acknowledgements.json b/package.nw/data/acknowledgements.json index 5d79454..c354afb 100644 --- a/package.nw/data/acknowledgements.json +++ b/package.nw/data/acknowledgements.json @@ -183,6 +183,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "KL4NE": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "KO4BCN": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -279,6 +283,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "VK2WJ": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "W0SP": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" From 7aaee10d0dee8146d40af15ceb66a98818843aec Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Tue, 22 Jun 2021 11:49:53 -0500 Subject: [PATCH 021/125] update acknowledgements.json for 6/22/2021 --- package.nw/data/acknowledgements.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/package.nw/data/acknowledgements.json b/package.nw/data/acknowledgements.json index c354afb..ec51354 100644 --- a/package.nw/data/acknowledgements.json +++ b/package.nw/data/acknowledgements.json @@ -143,6 +143,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "KB5KUY": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "KC4HN": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -187,6 +191,22 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "KM3T": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KM4TY": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KM6JS": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, + "KM6LBW": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "KO4BCN": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -243,6 +263,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "N8VWQ": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "NR0Q": { "badge": "img/emojis/coffee.png", "message": "GridTracker Developer" From f0508b58669efc88ce38b7cd598a8f7d31a1ab0a Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Thu, 24 Jun 2021 11:06:31 -0500 Subject: [PATCH 022/125] some notes that might aid in refactoring --- package.nw/lib/roster.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index d740b75..0c49fe5 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -436,6 +436,8 @@ function viewRoster() var bands = Object(); var modes = Object(); + // can the following block where we figure out how the roster is being used + // be a function itself that we can call in at the start of this? var callMode = g_rosterSettings.callsign; var onlyHits = false; var isAwardTracker = false; @@ -452,12 +454,18 @@ function viewRoster() isAwardTracker = true; g_rosterSettings.huntNeed = "confirmed"; } - + // this appears to be determine if we should show the OAMS collumn + // if the user is not in offline mode and has OAMS enabled, this could + // be it's own function maybe? var canMsg = window.opener.g_mapSettings.offlineMode == false && window.opener.g_appSettings.gtShareEnable == "true" && window.opener.g_appSettings.gtMsgEnable == "true"; + // The following 3 sections deal with QSLing, do we break them out + // individually or lump them into a qslUser function that sets + // all three at the same time? + // this section is for LoTW users, can be a function if (window.opener.g_callsignLookups.lotwUseEnable == true) { usesLoTWDiv.style.display = ""; @@ -479,18 +487,24 @@ function viewRoster() maxLoTWView.style.display = "none"; } + // eQSL - function if (window.opener.g_callsignLookups.eqslUseEnable == true) useseQSLDiv.style.display = ""; else useseQSLDiv.style.display = "none"; + // OQRS - function if (window.opener.g_callsignLookups.oqrsUseEnable == true) usesOQRSDiv.style.display = ""; else usesOQRSDiv.style.display = "none"; + // dealing with spots if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = ""; else onlySpotDiv.style.display = "none"; + // callmode (all or only new) if (callMode == "all") allOnlyNewDiv.style.display = ""; else allOnlyNewDiv.style.display = "none"; + // hunting mode - can this be comibined with the roster mode stuff on + // on line 441 above in that function or be it's own? var huntIndex, workedIndex, layeredMode; if (g_rosterSettings.huntNeed == "mixed") { @@ -520,6 +534,7 @@ function viewRoster() var now = timeNowSec(); // First loop, exclude calls, mostly based on "Exceptions" settings + // this whole section is full of individual if's that could be broken out for (var callHash in callRoster) { var entry = callRoster[callHash]; @@ -879,6 +894,8 @@ function viewRoster() } } + // these vars, do they rely on anything between the top and here? + // if not could they be put in the var list at the beginning? var hasGtPin = false; var newCallList = Array(); From 0b91db3d47028e4ffed6600fe8d6ab9a7b9deee3 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Thu, 24 Jun 2021 18:04:46 -0500 Subject: [PATCH 023/125] add array with exception test function names, need to create functions yet --- package.nw/lib/roster.js | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index 0c49fe5..f1db9bf 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -389,6 +389,38 @@ var r_sortFunction = [ myContCompare ]; +var r_excptTest = [ + timeChk, + crEnable, + blockedCall, + blockedFrom, + blcokedDXCC, + cqOnly, + useRegex, + reqGrid, + minDB, + maxDT, + minFreq, + maxFreq, + noMsg, + onlyMesg, + myDXCC, + lotwUse, + eqslUse, + oqrsUse, + noMyCQDX, + callWorked, + callConfirmed, + huntGrid, + huntDXCC, + huntDXCCs, + huntWPX, + huntCQ, + huntITU, + huntUSStates, + huntUSState +] + function showRosterBox(sortIndex) { if (g_rosterSettings.lastSortIndex != sortIndex) @@ -454,7 +486,7 @@ function viewRoster() isAwardTracker = true; g_rosterSettings.huntNeed = "confirmed"; } - // this appears to be determine if we should show the OAMS collumn + // this appears to be determine if we should show the OAMS column // if the user is not in offline mode and has OAMS enabled, this could // be it's own function maybe? var canMsg = @@ -745,7 +777,6 @@ function viewRoster() entry.tx = false; continue; } - continue; } @@ -797,7 +828,6 @@ function viewRoster() entry.tx = false; continue; } - continue; } From a767d9dc35d2af6853268070b14c5da316983cc2 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Thu, 24 Jun 2021 18:46:42 -0500 Subject: [PATCH 024/125] missing comma line 422 --- package.nw/lib/roster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index f1db9bf..d015832 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -419,7 +419,7 @@ var r_excptTest = [ huntITU, huntUSStates, huntUSState -] +]; function showRosterBox(sortIndex) { From f554d508622924833d3bb23789ad54e055cebc97 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 17:26:44 -0500 Subject: [PATCH 025/125] big roster refactor - starting Co-authored-by: Sebastian Delmont Matthew Chambers --- package.nw/lib/roster.js | 1814 +---------------- .../lib/roster/prepareRosterSettings.js | 83 + package.nw/lib/roster/processFiltering.js | 363 ++++ package.nw/lib/roster/processHunting.js | 706 +++++++ .../lib/roster/processRosterFiltering.js | 369 ++++ package.nw/lib/roster/processRosterHunting.js | 700 +++++++ package.nw/lib/roster/renderCompactRoster.js | 55 + package.nw/lib/roster/renderNormalRoster.js | 400 ++++ package.nw/lib/roster/renderRoster.js | 102 + package.nw/lib/roster/sendAlerts.js | 135 ++ 10 files changed, 2918 insertions(+), 1809 deletions(-) create mode 100644 package.nw/lib/roster/prepareRosterSettings.js create mode 100644 package.nw/lib/roster/processFiltering.js create mode 100644 package.nw/lib/roster/processHunting.js create mode 100644 package.nw/lib/roster/processRosterFiltering.js create mode 100644 package.nw/lib/roster/processRosterHunting.js create mode 100644 package.nw/lib/roster/renderCompactRoster.js create mode 100644 package.nw/lib/roster/renderNormalRoster.js create mode 100644 package.nw/lib/roster/renderRoster.js create mode 100644 package.nw/lib/roster/sendAlerts.js diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index d015832..d7997f6 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -465,1815 +465,11 @@ function processRoster(roster) function viewRoster() { - var bands = Object(); - var modes = Object(); - - // can the following block where we figure out how the roster is being used - // be a function itself that we can call in at the start of this? - var callMode = g_rosterSettings.callsign; - var onlyHits = false; - var isAwardTracker = false; - - if (callMode == "hits") - { - callMode = "all"; - onlyHits = true; - } - if (referenceNeed.value == LOGBOOK_AWARD_TRACKER) - { - callMode = "all"; - onlyHits = false; - isAwardTracker = true; - g_rosterSettings.huntNeed = "confirmed"; - } - // this appears to be determine if we should show the OAMS column - // if the user is not in offline mode and has OAMS enabled, this could - // be it's own function maybe? - var canMsg = - window.opener.g_mapSettings.offlineMode == false && - window.opener.g_appSettings.gtShareEnable == "true" && - window.opener.g_appSettings.gtMsgEnable == "true"; - - // The following 3 sections deal with QSLing, do we break them out - // individually or lump them into a qslUser function that sets - // all three at the same time? - // this section is for LoTW users, can be a function - if (window.opener.g_callsignLookups.lotwUseEnable == true) - { - usesLoTWDiv.style.display = ""; - if (g_rosterSettings.usesLoTW == true) - { - maxLoTW.style.display = ""; - maxLoTWView.style.display = ""; - } - else - { - maxLoTW.style.display = "none"; - maxLoTWView.style.display = "none"; - } - } - else - { - usesLoTWDiv.style.display = "none"; - maxLoTW.style.display = "none"; - maxLoTWView.style.display = "none"; - } - - // eQSL - function - if (window.opener.g_callsignLookups.eqslUseEnable == true) useseQSLDiv.style.display = ""; - else useseQSLDiv.style.display = "none"; - - // OQRS - function - if (window.opener.g_callsignLookups.oqrsUseEnable == true) usesOQRSDiv.style.display = ""; - else usesOQRSDiv.style.display = "none"; - - // dealing with spots - if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = ""; - else onlySpotDiv.style.display = "none"; - - // callmode (all or only new) - if (callMode == "all") allOnlyNewDiv.style.display = ""; - else allOnlyNewDiv.style.display = "none"; - - // hunting mode - can this be comibined with the roster mode stuff on - // on line 441 above in that function or be it's own? - var huntIndex, workedIndex, layeredMode; - if (g_rosterSettings.huntNeed == "mixed") - { - huntIndex = g_confirmed; - workedIndex = g_worked; - layeredMode = LAYERED_MODE_FOR[String(g_rosterSettings.reference)]; - } - else if (g_rosterSettings.huntNeed == "worked") - { - huntIndex = g_worked; - workedIndex = false; - layeredMode = false; - } - else if (g_rosterSettings.huntNeed == "confirmed") - { - huntIndex = g_confirmed; - workedIndex = g_worked; - layeredMode = false; - } - else - { - huntIndex = false; - workedIndex = false; - layeredMode = false; - } - - var now = timeNowSec(); - - // First loop, exclude calls, mostly based on "Exceptions" settings - // this whole section is full of individual if's that could be broken out - for (var callHash in callRoster) - { - var entry = callRoster[callHash]; - var callObj = entry.callObj; - - var call = entry.DEcall; - - entry.tx = true; - callObj.shouldAlert = false; - callObj.reason = Array(); - callObj.awardReason = "Callsign"; - - if (now - callObj.age > window.opener.g_mapSettings.rosterTime) - { - entry.tx = false; - entry.alerted = false; - callObj.qrz = false; - callObj.reset = true; - continue; - } - if (window.opener.g_instances[callObj.instance].crEnable == false) - { - entry.tx = false; - continue; - } - if (call in g_blockedCalls) - { - entry.tx = false; - continue; - } - if ( - entry.DXcall + " from All" in g_blockedCQ || - entry.DXcall + " from " + window.opener.g_dxccToAltName[callObj.dxcc] in g_blockedCQ - ) - { - entry.tx = false; - continue; - } - if (callObj.dxcc in g_blockedDxcc) - { - entry.tx = false; - continue; - } - if (g_rosterSettings.cqOnly == true && callObj.CQ == false) - { - entry.tx = false; - continue; - } - if (g_rosterSettings.useRegex && g_rosterSettings.callsignRegex.length > 0) - { - try - { - if (!call.match(g_rosterSettings.callsignRegex)) - { - entry.tx = false; - continue; - } - } - catch (e) {} - } - if (g_rosterSettings.requireGrid == true && callObj.grid.length != 4) - { - entry.tx = false; - continue; - } - if (g_rosterSettings.wantMinDB == true && entry.message.SR < g_rosterSettings.minDb) - { - entry.tx = false; - continue; - } - if (g_rosterSettings.wantMaxDT == true && Math.abs(entry.message.DT) > g_rosterSettings.maxDT) - { - entry.tx = false; - continue; - } - if (g_rosterSettings.wantMinFreq == true && entry.message.DF < g_rosterSettings.minFreq) - { - entry.tx = false; - continue; - } - if (g_rosterSettings.wantMaxFreq == true && entry.message.DF > g_rosterSettings.maxFreq) - { - entry.tx = false; - continue; - } - - if (g_rosterSettings.noMsg == true) - { - try - { - if (callObj.msg.match(g_rosterSettings.noMsgValue)) - { - entry.tx = false; - continue; - } - } - catch (e) {} - } - if (g_rosterSettings.onlyMsg == true) - { - try - { - if (!callObj.msg.match(g_rosterSettings.onlyMsgValue)) - { - entry.tx = false; - continue; - } - } - catch (e) {} - } - - if (callObj.dxcc == window.opener.g_myDXCC) - { - if (g_rosterSettings.noMyDxcc == true) - { - entry.tx = false; - continue; - } - } - else - { - if (g_rosterSettings.onlyMyDxcc == true) - { - entry.tx = false; - continue; - } - } - - if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.usesLoTW == true) - { - if (!(call in window.opener.g_lotwCallsigns)) - { - entry.tx = false; - continue; - } - if (g_rosterSettings.maxLoTW < 27) - { - var months = (g_day - window.opener.g_lotwCallsigns[call]) / 30; - if (months > g_rosterSettings.maxLoTW) - { - entry.tx = false; - continue; - } - } - } - - if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.useseQSL == true) - { - if (!(call in window.opener.g_eqslCallsigns)) - { - entry.tx = false; - continue; - } - } - - if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.usesOQRS == true) - { - if (!(call in window.opener.g_oqrsCallsigns)) - { - entry.tx = false; - continue; - } - } - - if (callMode != "all") - { - if (entry.DXcall == "CQ DX" && callObj.dxcc == window.opener.g_myDXCC) - { - entry.tx = false; - continue; - } - - var hash = hashMaker(call, callObj, g_rosterSettings.reference); - if (callMode == "worked" && hash in g_worked.call) - { - entry.tx = false; - continue; - } - if (callMode == "confirmed" && hash in g_confirmed.call) - { - entry.tx = false; - continue; - } - - if (g_rosterSettings.hunting == "grid") - { - var hash = hashMaker(callObj.grid.substr(0, 4), - callObj, g_rosterSettings.reference); - if (huntIndex && hash in huntIndex.grid) - { - entry.tx = false; - continue; - } - if (callObj.grid.length == 0) - { - entry.tx = false; - continue; - } - continue; - } - if (g_rosterSettings.hunting == "dxcc") - { - var hash = hashMaker(String(callObj.dxcc), - callObj, g_rosterSettings.reference); - - if (huntIndex && (hash in huntIndex.dxcc)) - { - entry.tx = false; - continue; - } - continue; - } - - if (g_rosterSettings.hunting == "dxccs" && r_currentDXCCs != -1) - { - if (callObj.dxcc != r_currentDXCCs) - { - entry.tx = false; - continue; - } - } - - if (g_rosterSettings.hunting == "wpx") - { - if (String(callObj.px) == null) - { - entry.tx = false; - continue; - } - var hash = hashMaker(String(callObj.px), - callObj, g_rosterSettings.reference); - - if (huntIndex && (hash in huntIndex.px)) - { - entry.tx = false; - continue; - } - - continue; - } - - if (g_rosterSettings.hunting == "cq") - { - var huntTotal = callObj.cqza.length; - if (huntTotal == 0 || !huntIndex) - { - entry.tx = false; - continue; - } - var huntFound = 0; - for (index in callObj.cqza) - { - var hash = hashMaker(callObj.cqza[index], callObj, g_rosterSettings.reference); - - if (hash in huntIndex.cqz) huntFound++; - } - if (huntFound == huntTotal) - { - entry.tx = false; - continue; - } - continue; - } - - if (g_rosterSettings.hunting == "itu") - { - var huntTotal = callObj.ituza.length; - if (huntTotal == 0 || !huntIndex) - { - entry.tx = false; - continue; - } - var huntFound = 0; - for (index in callObj.ituza) - { - var hash = hashMaker(callObj.ituza[index], callObj, g_rosterSettings.reference); - - if (hash in huntIndex.ituz) huntFound++; - } - if (huntFound == huntTotal) - { - entry.tx = false; - continue; - } - - if (callObj.grid.length == 0) - { - entry.tx = false; - continue; - } - continue; - } - - if (g_rosterSettings.hunting == "usstates" && window.opener.g_callsignLookups.ulsUseEnable == true) - { - var state = callObj.state; - var finalDxcc = callObj.dxcc; - if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) - { - if (state in window.opener.g_StateData) - { - var hash = hashMaker(state, callObj, g_rosterSettings.reference); - - if (huntIndex && hash in huntIndex.state) - { - entry.tx = false; - continue; - } - } - else entry.tx = false; - } - else entry.tx = false; - - continue; - } - - if (g_rosterSettings.hunting == "usstate" && g_currentUSCallsigns) - { - if (call in g_currentUSCallsigns) - { - // Do Nothing - } - else - { - entry.tx = false; - continue; - } - continue; - } - } - if (isAwardTracker) - { - var tx = false; - var baseHash = hashMaker("", callObj, g_rosterSettings.reference); - - for (var award in g_awardTracker) - { - if (g_awardTracker[award].enable) - { - tx = testAward(award, callObj, baseHash); - if (tx) - { - var x = g_awardTracker[award]; - callObj.awardReason = - g_awards[x.sponsor].awards[x.name].tooltip + - " (" + - g_awards[x.sponsor].sponsor + - ")"; - - break; - } - } - } - entry.tx = tx; - } - } - - // these vars, do they rely on anything between the top and here? - // if not could they be put in the var list at the beginning? - var hasGtPin = false; - - var newCallList = Array(); - var inversionAlpha = "DD"; - var row = "#000000"; - var bold = "#000000;font-weight: bold;"; - var unconf = "background-clip:padding-box;box-shadow: 0 0 7px 3px inset "; - var layeredAlpha = "77"; - var layeredInversionAlpha = "66"; - var layeredUnconf = "background-clip:padding-box;box-shadow: 0 0 4px 2px inset "; - var layeredUnconfAlpha = "AA"; - - // Second loop, hunting and highlighting - for (var callHash in callRoster) - { - var entry = callRoster[callHash]; - var callObj = entry.callObj; - - // Special case check for called station - if (callObj.qrz == true && entry.tx == false) - { - // The instance has to be enabled - if (window.opener.g_instances[callObj.instance].crEnable == true) - { - // Calling us, but we wouldn't normally display - // If they are not ignored or we're in a QSO with them, var it through - - if ((!(entry.DEcall in g_blockedCalls) && !(callObj.dxcc in g_blockedDxcc)) || - window.opener.g_instances[callObj.instance].status.DXcall == entry.DEcall) - { - entry.tx = true; - } - } - } - - // Only render entries with `tx == true`, ignore the rest - if (callObj.dxcc != -1 && entry.tx == true) - { - // In layered mode ("Hunting: mixed") the workHashSuffix becomes a more stricter 'live band', - // while the layered suffix is a broader 'mixed band' - var workHashSuffix, layeredHashSuffix; - if (layeredMode) - { - workHashSuffix = hashMaker("", callObj, layeredMode); - layeredHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); - } - else - { - workHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); - layeredHashSuffix = false - } - var workHash = workHashSuffix; // TODO: Remove after replacing all occurrences with Suffix - - var callsign = entry.DEcall; - - callObj.hunting = {} - callObj.callFlags = {} - - var colorObject = Object(); - - var callPointer = callObj.CQ == true ? "cursor:pointer" : ""; - - var didWork = false; - - var call = "#FFFF00"; - var grid = "#00FFFF"; - var calling = "#90EE90"; - var dxcc = "#FFA500"; - var state = "#90EE90"; - var cnty = "#CCDD00"; - var cont = "#00DDDD"; - var cqz = "#DDDDDD"; - var ituz = "#DDDDDD"; - var wpx = "#FFFF00"; - - hasGtPin = false; - var shouldAlert = false; - var callBg, gridBg, callingBg, dxccBg, stateBg, cntyBg, contBg, cqzBg, ituzBg, wpxBg, gtBg; - var callConf, gridConf, callingConf, dxccConf, stateConf, cntyConf, contConf, cqzConf, ituzConf, wpxConf; - - callBg = gridBg = callingBg = dxccBg = stateBg = cntyBg = contBg = cqzBg = ituzBg = wpxBg = gtBg = row; - - callConf = gridConf = callingConf = dxccConf = stateConf = cntyConf = contConf = cqzConf = ituzConf = wpxConf = - ""; - - var hash = callsign + workHashSuffix; - var layeredHash = layeredHashSuffix && (callsign + layeredHashSuffix) - - // Call worked in current logbook settings, regardless of hunting mode - if (hash in g_worked.call) - { - callObj.callFlags.worked = true; - didWork = true; - callConf = `${unconf}${call}${inversionAlpha};`; - - if (hash in g_confirmed.call) - { - callObj.callFlags.confirmed = true; - callPointer = "text-decoration: line-through; "; - callConf = ""; - } - } - - // Calls that have OAMS chat support - if ( - callsign in window.opener.g_gtCallsigns && - window.opener.g_gtCallsigns[callsign] in window.opener.g_gtFlagPins && - window.opener.g_gtFlagPins[window.opener.g_gtCallsigns[callsign]].canmsg == true - ) - { - callObj.callFlags.oams = true; - // grab the CID - colorObject.gt = window.opener.g_gtCallsigns[callsign]; - hasGtPin = true; - } - else - { - colorObject.gt = 0; - } - - // We only do hunt highlighting when showing all entries - // This means "Callsigns: All Traffic", "Callsigns: All Traffic/Only Wanted" and "Logbook: Award Tracker" - // There is no highlighting in other modes - if (callMode == "all") - { - // Skip when "only new calls" - // Questions: Move to the first loop? Why only skip new calls in "all traffic" and not other modes? - if (allOnlyNew.checked == true && didWork && callObj.qrz == false) - { - entry.tx = false; - continue; - } - - // Hunting for callsigns - if (huntCallsign.checked == true) - { - var hash = callsign + workHashSuffix; - var layeredHash = layeredMode && (callsign + layeredHashSuffix) - - if (huntIndex && !(hash in huntIndex.call)) - { - shouldAlert = true; - - callObj.reason.push("call"); - - if (workedIndex && hash in workedIndex.call) - { - if (layeredMode && layeredHash in huntIndex.call) - { - callObj.hunting.call = "worked-and-mixed"; - callConf = `${layeredUnconf}${call}${layeredUnconfAlpha};`; - callBg = `${call}${layeredInversionAlpha}`; - call = bold; - } - // /* Currently we don't have a way to figure out - // * if the call is worked only in this band or also others, - // * so we cannot cover this particular combination - // * and have to default to just showing it as plain "worked" - // */ - // else if (layeredMode && layeredHash in workedIndex.call) - // { - // callObj.hunting.call = "worked-and-mixed-worked"; - // callConf = `${layeredUnconf}${call}${layeredAlpha};`; - // } - else - { - callObj.hunting.call = "worked"; - callConf = `${unconf}${call}${inversionAlpha};`; - } - } - else - { - if (layeredMode && layeredHash in huntIndex.call) - { - callObj.hunting.call = "mixed"; - callBg = `${call}${layeredAlpha};`; - call = bold; - } - else if (layeredMode && layeredHash in workedIndex.call) - { - callObj.hunting.call = "mixed-worked"; - callConf = `${unconf}${call}${layeredAlpha};`; - } - else - { - callObj.hunting.call = "hunted"; - callBg = `${call}${inversionAlpha};`; - call = bold; - } - } - } - } - - // Hunting for "stations calling you" - if (huntQRZ.checked == true && callObj.qrz == true) - { - callObj.callFlags.calling = true - shouldAlert = true; - callObj.reason.push("qrz"); - } - - // Hunting for stations with OAMS - if (huntOAMS.checked == true && hasGtPin == true) - { - callObj.hunting.oams = "hunted"; - shouldAlert = true; - callObj.reason.push("oams"); - } - - // Hunting for grids - if (huntGrid.checked == true && callObj.grid.length > 1) - { - var hash = callObj.grid.substr(0, 4) + workHashSuffix; - var layeredHash = layeredMode && (callObj.grid.substr(0, 4) + layeredHashSuffix) - - if (huntIndex && !(hash in huntIndex.grid)) - { - shouldAlert = true; - - callObj.reason.push("grid"); - - if (workedIndex && hash in workedIndex.grid) - { - if (layeredMode && layeredHash in huntIndex.grid) - { - callObj.hunting.grid = "worked-and-mixed"; - gridConf = `${layeredUnconf}${grid}${layeredUnconfAlpha};`; - gridBg = `${grid}${layeredInversionAlpha}`; - grid = bold; - } - else - { - callObj.hunting.grid = "worked"; - gridConf = `${unconf}${grid}${inversionAlpha};`; - } - } - else - { - if (layeredMode && layeredHash in huntIndex.grid) - { - callObj.hunting.grid = "mixed"; - gridBg = `${grid}${layeredAlpha};`; - grid = bold; - } - else if (layeredMode && layeredHash in workedIndex.grid) - { - callObj.hunting.grid = "mixed-worked"; - gridConf = `${unconf}${grid}${layeredAlpha};`; - } - else - { - callObj.hunting.grid = "hunted"; - gridBg = `${grid}${inversionAlpha};`; - grid = bold; - } - } - } - } - - // Hunting for DXCC - if (huntDXCC.checked == true) - { - var hash = String(callObj.dxcc) + workHashSuffix; - var layeredHash = layeredMode && (String(callObj.dxcc) + layeredHashSuffix) - - if (huntIndex && !(hash in huntIndex.dxcc)) - { - shouldAlert = true; - - callObj.reason.push("dxcc"); - - if (workedIndex && hash in workedIndex.dxcc) - { - if (layeredMode && layeredHash in huntIndex.dxcc) - { - callObj.hunting.dxcc = "worked-and-mixed"; - dxccConf = `${layeredUnconf}${dxcc}${layeredUnconfAlpha};`; - dxccBg = `${dxcc}${layeredInversionAlpha}`; - dxcc = bold; - } - else - { - callObj.hunting.dxcc = "worked"; - dxccConf = `${unconf}${dxcc}${inversionAlpha};`; - } - } - else - { - if (layeredMode && layeredHash in huntIndex.dxcc) - { - callObj.hunting.dxcc = "mixed"; - dxccBg = `${dxcc}${layeredAlpha};`; - dxcc = bold; - } - else if (layeredMode && layeredHash in workedIndex.dxcc) - { - callObj.hunting.dxcc = "mixed-worked"; - dxccConf = `${unconf}${dxcc}${layeredAlpha};`; - } - else - { - callObj.hunting.dxcc = "hunted"; - dxccBg = `${dxcc}${inversionAlpha};`; - dxcc = bold; - } - } - } - } - - // Hunting for US States - if (huntState.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) - { - var stateSearch = callObj.state; - var finalDxcc = callObj.dxcc; - if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) - { - if (stateSearch in window.opener.g_StateData) - { - var hash = stateSearch + workHashSuffix; - var layeredHash = layeredMode && (stateSearch + layeredHashSuffix) - - if (huntIndex && !(hash in huntIndex.state)) - { - shouldAlert = true; - - callObj.reason.push("state"); - - if (workedIndex && hash in workedIndex.state) - { - if (layeredMode && layeredHash in huntIndex.state) - { - callObj.hunting.state = "worked-and-mixed"; - stateConf = `${layeredUnconf}${state}${layeredUnconfAlpha};`; - stateBg = `${state}${layeredInversionAlpha}`; - state = bold; - } - else - { - callObj.hunting.state = "worked"; - stateConf = `${unconf}${state}${inversionAlpha};`; - } - } - else - { - if (layeredMode && layeredHash in huntIndex.state) - { - callObj.hunting.state = "mixed"; - stateBg = `${state}${layeredAlpha};`; - state = bold; - } - else if (layeredMode && layeredHash in workedIndex.state) - { - callObj.hunting.state = "mixed-worked"; - stateConf = `${unconf}${state}${layeredAlpha};`; - } - else - { - callObj.hunting.state = "hunted"; - stateBg = `${state}${inversionAlpha};`; - state = bold; - } - } - } - } - } - } - - // Hunting for US Counties - if (huntCounty.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) - { - var finalDxcc = callObj.dxcc; - if ( - callObj.cnty && - (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6 || finalDxcc == 202) && - callObj.cnty.length > 0 - ) - { - var hash = callObj.cnty + (layeredMode ? layeredHashSuffix : workHashSuffix); - - if ((huntIndex && !(hash in huntIndex.cnty)) || callObj.qual == false) - { - if (callObj.qual == false) - { - var counties = window.opener.g_zipToCounty[callObj.zipcode]; - var foundHit = false; - for (var cnt in counties) - { - var hh = counties[cnt] + workHash; - callObj.cnty = counties[cnt]; - if (huntIndex && !(hh in huntIndex.cnty)) - { - foundHit = true; - break; - } - } - if (foundHit) shouldAlert = true; - } - else - { - shouldAlert = true; - } - - if (shouldAlert) - { - callObj.reason.push("cnty"); - - if (workedIndex && hash in workedIndex.cnty) - { - callObj.hunting.cnty = "worked"; - cntyConf = `${unconf}${cnty}${inversionAlpha};`; - } - else - { - callObj.hunting.cnty = "hunted"; - cntyBg = `${cnty}${inversionAlpha}`; - cnty = bold; - } - } - } - } - } - - // Hunting for CQ Zones - if (huntCQz.checked == true) - { - var huntTotal = callObj.cqza.length; - var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; - - for (index in callObj.cqza) - { - var hash = callObj.cqza[index] + workHashSuffix; - var layeredHash = layeredMode && (callObj.cqza[index] + layeredHashSuffix) - - if (huntIndex && hash in huntIndex.cqz) huntFound++; - if (layeredMode && layeredHash in huntIndex.cqz) layeredFound++; - if (workedIndex && hash in workedIndex.cqz) workedFound++; - if (layeredMode && layeredHash in workedIndex.cqz) layeredWorkedFound++; - } - if (huntFound != huntTotal) - { - shouldAlert = true; - callObj.reason.push("cqz"); - - if (workedIndex && workedFound == huntTotal) - { - if (layeredMode && layeredFound == huntTotal) - { - callObj.hunting.cqz = "worked-and-mixed"; - cqzConf = `${layeredUnconf}${cqz}${layeredUnconfAlpha};`; - cqzBg = `${cqz}${layeredInversionAlpha}`; - cqz = bold; - } - else - { - callObj.hunting.cqz = "worked"; - cqzConf = `${unconf}${cqz}${inversionAlpha};`; - } - } - else - { - if (layeredMode && layeredFound == huntTotal) - { - callObj.hunting.cqz = "mixed"; - cqzBg = `${cqz}${layeredAlpha};`; - cqz = bold; - } - else if (layeredMode && layeredWorkedFound == huntTotal) - { - callObj.hunting.cqz = "mixed-worked"; - cqzConf = `${unconf}${cqz}${layeredAlpha};`; - } - else - { - callObj.hunting.cqz = "hunted"; - cqzBg = `${cqz}${inversionAlpha};`; - cqz = bold; - } - } - } - } - - // Hunting for ITU Zones - if (huntITUz.checked == true) - { - var huntTotal = callObj.ituza.length; - var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; - - for (index in callObj.ituza) - { - var hash = callObj.ituza[index] + workHashSuffix; - var layeredHash = layeredMode && (callObj.ituza[index] + layeredHashSuffix) - - if (huntIndex && hash in huntIndex.ituz) huntFound++; - if (layeredMode && layeredHash in huntIndex.ituz) layeredFound++; - if (workedIndex && hash in workedIndex.ituz) workedFound++; - if (layeredMode && layeredHash in workedIndex.ituz) layeredWorkedFound++; - } - if (huntFound != huntTotal) - { - shouldAlert = true; - callObj.reason.push("ituz"); - - if (workedIndex && workedFound == huntTotal) - { - if (layeredMode && layeredFound == huntTotal) - { - callObj.hunting.ituz = "worked-and-mixed"; - ituzConf = `${layeredUnconf}${ituz}${layeredUnconfAlpha};`; - ituzBg = `${ituz}${layeredInversionAlpha}`; - ituz = bold; - } - else - { - callObj.hunting.ituz = "worked"; - ituzConf = `${unconf}${ituz}${inversionAlpha};`; - } - } - else - { - if (layeredMode && layeredFound == huntTotal) - { - callObj.hunting.ituz = "mixed"; - ituzBg = `${ituz}${layeredAlpha};`; - ituz = bold; - } - else if (layeredMode && layeredWorkedFound == huntTotal) - { - callObj.hunting.ituz = "mixed-worked"; - ituzConf = `${unconf}${ituz}${layeredAlpha};`; - } - else - { - callObj.hunting.ituz = "hunted"; - ituzBg = `${ituz}${inversionAlpha};`; - ituz = bold; - } - } - } - } - - // Hunting for WPX (Prefixes) - if (huntPX.checked == true && callObj.px) - { - var hash = String(callObj.px) + workHashSuffix; - var layeredHash = layeredMode && (String(callObj.px) + layeredHashSuffix) - - if (huntIndex && !(hash in huntIndex.px)) - { - shouldAlert = true; - - callObj.reason.push("wpx"); - - if (workedIndex && hash in workedIndex.px) - { - if (layeredMode && layeredHash in huntIndex.px) - { - callObj.hunting.wpx = "worked-and-mixed"; - wpxConf = `${layeredUnconf}${wpx}${layeredUnconfAlpha};`; - wpxBg = `${wpx}${layeredInversionAlpha}`; - wpx = bold; - } - else - { - callObj.hunting.wpx = "worked"; - wpxConf = `${unconf}${wpx}${inversionAlpha};`; - } - } - else - { - if (layeredMode && layeredHash in huntIndex.px) - { - callObj.hunting.wpx = "mixed"; - wpxBg = `${wpx}${layeredAlpha};`; - wpx = bold; - } - else if (layeredMode && layeredHash in workedIndex.px) - { - callObj.hunting.wpx = "mixed-worked"; - wpxConf = `${unconf}${wpx}${layeredAlpha};`; - } - else - { - callObj.hunting.wpx = "hunted"; - wpxBg = `${wpx}${inversionAlpha};`; - wpx = bold; - } - } - } - } - - // Hunting for Continents - if (huntCont.checked == true && callObj.cont) - { - var hash = String(callObj.cont) + workHashSuffix; - var layeredHash = layeredMode && (String(callObj.cont) + layeredHashSuffix) - - if (huntIndex && !(hash in huntIndex.cont)) - { - shouldAlert = true; - - callObj.reason.push("cont"); - - if (workedIndex && hash in workedIndex.cont) - { - if (layeredMode && layeredHash in huntIndex.cont) - { - callObj.hunting.cont = "worked-and-mixed"; - contConf = `${layeredUnconf}${cont}${layeredUnconfAlpha};`; - contBg = `${cont}${layeredInversionAlpha}`; - cont = bold; - } - else - { - callObj.hunting.cont = "worked"; - contConf = `${unconf}${cont}${inversionAlpha};`; - } - } - else - { - if (layeredMode && layeredHash in huntIndex.cont) - { - callObj.hunting.cont = "mixed"; - contBg = `${cont}${layeredAlpha};`; - cont = bold; - } - else if (layeredMode && layeredHash in workedIndex.cont) - { - callObj.hunting.cont = "mixed-worked"; - contConf = `${unconf}${cont}${layeredAlpha};`; - } - else - { - callObj.hunting.cont = "hunted"; - contBg = `${cont}${inversionAlpha};`; - cont = bold; - } - } - } - } - } - - // Station is calling us - if (callObj.DXcall == window.opener.myDEcall) - { - callingBg = "#0000FF" + inversionAlpha; - calling = "#FFFF00;text-shadow: 0px 0px 2px #FFFF00"; - } - else if (callObj.CQ == true && g_rosterSettings.cqOnly == false) - { - callingBg = calling + inversionAlpha; - calling = bold; - } - - // Assemble all styles - colorObject.call = "style='" + callConf + "background-color:" + callBg + ";color:" + - call + ";" + callPointer + "'"; - colorObject.grid = "style='" + gridConf + "background-color:" + gridBg + ";color:" + grid + ";cursor:pointer'"; - colorObject.calling = "style='" + callingConf + "background-color:" + callingBg + ";color:" + calling + "'"; - colorObject.dxcc = "style='" + dxccConf + "background-color:" + dxccBg + ";color:" + dxcc + "'"; - colorObject.state = "style='" + stateConf + "background-color:" + stateBg + ";color:" + state + "'"; - colorObject.cnty = "style='" + cntyConf + "background-color:" + cntyBg + ";color:" + cnty + "'"; - colorObject.cont = "style='" + contConf + "background-color:" + contBg + ";color:" + cont + "'"; - colorObject.cqz = "style='" + cqzConf + "background-color:" + cqzBg + ";color:" + cqz + "'"; - colorObject.ituz = "style='" + ituzConf + "background-color:" + ituzBg + ";color:" + ituz + "'"; - colorObject.px = "style='" + wpxConf + "background-color:" + wpxBg + ";color:" + wpx + "'"; - - // Just in case, don't alert if we worked this callsign alread - if (didWork && shouldAlert) shouldAlert = false; - - callObj.shouldAlert = shouldAlert; - - callObj.style = colorObject; - - if (g_rosterSettings.columns.Spot) - { - callObj.spot = window.opener.getSpotTime( - callObj.DEcall + callObj.mode + callObj.band + callObj.grid - ); - if (callObj.spot == null) - { - callObj.spot = { when: 0, snr: 0 }; - } - } - else - { - callObj.spot = { when: 0, snr: 0 }; - } - - modes[callObj.mode] = true; - bands[callObj.band] = true; - - newCallList.push(callObj); - } - } - - // Show the roster count in the window title - - var totalCount = Object.keys(callRoster).length; - var visibleCount = newCallList.length; - var huntedCount = newCallList.filter(obj => Object.keys(obj.hunting).length > 0).length - var countParts = []; - - if (totalCount != visibleCount) - { - countParts.push(`${totalCount} heard`); - } - - countParts.push(`${visibleCount} in roster`); - - if (huntedCount != visibleCount) - { - countParts.push(`${huntedCount} wanted`); - } - - window.document.title = `Call Roster: ${countParts.join(" • ")}`; - - // Render the roster - - if (g_rosterSettings.compact == false) - { - newCallList.sort(r_sortFunction[g_rosterSettings.lastSortIndex]); - if (g_rosterSettings.lastSortReverse == 1) - { - newCallList.reverse(); - } - } - else - { - // Age sort for now... make this happen Tag - newCallList.sort(r_sortFunction[6]).reverse(); - } - - var showBands = (Object.keys(bands).length > 1) || g_rosterSettings.columns.Band; - var showModes = (Object.keys(modes).length > 1) || g_rosterSettings.columns.Mode; - - var worker = ""; - - // Render the table headers for the regular roster table - if (g_rosterSettings.compact == false) - { - worker = ""; - - worker += ""; - - if (showBands) - { worker += ""; } - - if (showModes) - { worker += ""; } - - worker += ""; - - if (g_rosterSettings.columns.Calling) - { worker += ""; } - - if (g_rosterSettings.columns.Msg) - { worker += ""; } - - if (g_rosterSettings.columns.DXCC) - { worker += ""; } - - if (g_rosterSettings.columns.Flag) - { worker += ""; } - - if (g_rosterSettings.columns.State) - { worker += ""; } - - if (g_rosterSettings.columns.County) - { worker += ""; } - - if (g_rosterSettings.columns.Cont) - { worker += ""; } - - if (g_rosterSettings.columns.dB) - { worker += ""; } - - if (g_rosterSettings.columns.Freq) - { worker += ""; } - - if (g_rosterSettings.columns.DT) - { worker += ""; } - - if (g_rosterSettings.columns.Dist) - { - worker += ""; - } - - if (g_rosterSettings.columns.Azim) - { worker += ""; } - - if (g_rosterSettings.columns.CQz) - { worker += ""; } - - if (g_rosterSettings.columns.ITUz) - { worker += ""; } - - if (g_rosterSettings.columns.PX) - { worker += ""; } - - if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.columns.LoTW) - { worker += ""; } - - if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.columns.eQSL) - { worker += ""; } - - if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.columns.OQRS) - { worker += ""; } - - if (g_rosterSettings.columns.Spot) - { worker += ""; } - - if (g_rosterSettings.columns.Life) - { worker += ""; } - - if (g_rosterSettings.columns.OAMS) - { worker += ""; } - - if (g_rosterSettings.columns.Age) - { worker += ""; } - } - // No headers for compact roster table - else - { - worker = "
"; - } - - var shouldAlert = 0; - - // Render all rows - for (var x in newCallList) - { - var callObj = newCallList[x]; - - if (callObj.shouldAlert == false && onlyHits == true && callObj.qrz == false) - { continue; } - - var spotString = ""; - if (g_rosterSettings.columns.Spot && callObj.qrz == false) - { - spotString = getSpotString(callObj); - if (g_rosterSettings.onlySpot && spotString == "") continue; - } - var grid = callObj.grid.length > 1 ? callObj.grid.substr(0, 4) : "-"; - - var geo = window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]]; - var cqzone = grid in window.opener.g_gridToCQZone ? window.opener.g_gridToCQZone[grid].join(", ") : "-"; - var ituzone = grid in window.opener.g_gridToITUZone ? window.opener.g_gridToITUZone[grid].join(", ") : "-"; - var thisCall = callObj.DEcall; - - if (thisCall.match("^[A-Z][0-9][A-Z](/w+)?$")) - { callObj.style.call = "class='oneByOne'"; } - if (thisCall == window.opener.g_instances[callObj.instance].status.DXcall) - { - if (window.opener.g_instances[callObj.instance].status.TxEnabled == 1) - { - callObj.style.call = "class='dxCalling'"; - } - else - { - callObj.style.call = "class='dxCaller'"; - } - } - - if (g_rosterSettings.compact == false) - { - var acks = window.opener.g_acknowledgedCalls - - var thisHash = thisCall + callObj.band + callObj.mode; - var callStr = thisCall.formatCallsign() - if (acks[thisCall]) - { - callStr = `${callStr} ` - callObj.awardReason += ` - ${acks[thisCall].message}` - } - - worker += "
"; - worker += - ""; - - if (showBands) - { - worker += - ""; - } - if (showModes) - { - var color = "888888"; - if (callObj.mode in g_modeColors) - { color = g_modeColors[callObj.mode]; } - worker += - ""; - } - - worker += - ""; - if (g_rosterSettings.columns.Calling) - { - var lookString = callObj.CQ ? "name='CQ'" : "name='Calling'"; - worker += - ""; - } - if (g_rosterSettings.columns.Msg) - { worker += ""; } - - if (g_rosterSettings.columns.DXCC) - { - worker += - ""; - } - if (g_rosterSettings.columns.Flag) - { - worker += - ""; - } - if (g_rosterSettings.columns.State) - { - worker += - ""; - } - if (g_rosterSettings.columns.County) - { - worker += - ""; - } - if (g_rosterSettings.columns.Cont) - { - worker += - ""; - } - - if (g_rosterSettings.columns.dB) - { - worker += - ""; - } - if (g_rosterSettings.columns.Freq) - { worker += ""; } - if (g_rosterSettings.columns.DT) - { worker += ""; } - if (g_rosterSettings.columns.Dist) - { - worker += - ""; - } - if (g_rosterSettings.columns.Azim) - { - worker += - ""; - } - - if (g_rosterSettings.columns.CQz) - { - worker += - ""; - } - if (g_rosterSettings.columns.ITUz) - { - worker += - ""; - } - - if (g_rosterSettings.columns.PX) - { - worker += - ""; - } - - if ( - window.opener.g_callsignLookups.lotwUseEnable == true && - g_rosterSettings.columns.LoTW - ) - { - if (thisCall in window.opener.g_lotwCallsigns) - { - if (g_rosterSettings.maxLoTW < 27) - { - var months = (g_day - window.opener.g_lotwCallsigns[thisCall]) / 30; - if (months > g_rosterSettings.maxLoTW) - { - worker += - ""; - } - else - { - worker += - ""; - } - } - else - { - worker += - ""; - } - } - else worker += ""; - } - if ( - window.opener.g_callsignLookups.eqslUseEnable == true && - g_rosterSettings.columns.eQSL - ) - { - worker += - ""; - } - if ( - window.opener.g_callsignLookups.oqrsUseEnable == true && - g_rosterSettings.columns.OQRS - ) - { - worker += - ""; - } - - if (g_rosterSettings.columns.Spot) - { - worker += - ""; - } - if (g_rosterSettings.columns.Life) - { - worker += - ""; - } - - if (g_rosterSettings.columns.OAMS) - { - if (callObj.style.gt != 0) - { - if (callObj.reason.includes("oams")) - { - worker += - ""; - } - else - { - worker += - ""; - } - } - else worker += ""; - } - - if (g_rosterSettings.columns.Age) - { - worker += - ""; - } - - worker += ""; - } - else - { - var tt = - callObj.RSTsent + - "㏈, " + - parseInt(callObj.dt * 100) + - "ms, " + - callObj.delta + - "hz" + - (callObj.grid.length ? ", " + callObj.grid : "") + - ", " + - (timeNowSec() - callObj.age).toDHMS(); - worker += - "
"; - worker += - "
" + - thisCall.formatCallsign() + - "
"; - worker += - "
" + - window.opener.g_dxccToAltName[callObj.dxcc] + - "
"; - worker += "
"; - } - - if (g_rosterSettings.realtime == false) - { - var call = callObj.DEcall; - g_scriptReport[call] = Object.assign({}, callObj); - g_scriptReport[call].dxccName = - window.opener.g_dxccToAltName[callObj.dxcc]; - g_scriptReport[call].distance = parseInt( - callObj.distance * - MyCircle.validateRadius(window.opener.distanceUnit.value) - ); - - delete g_scriptReport[call].DEcall; - g_scriptReport[call].rect = null; - delete g_scriptReport[call].rect; - delete g_scriptReport[call].style; - delete g_scriptReport[call].wspr; - delete g_scriptReport[call].qso; - delete g_scriptReport[call].instance; - - if (callMode != "all") - { - g_scriptReport[call].shouldAlert = true; - g_scriptReport[call].reason.push(g_rosterSettings.hunting); - } - } - - if ( - callObj.alerted == false && - callMode == "all" && - callObj.shouldAlert == true - ) - { - callObj.alerted = true; - shouldAlert++; - } - else if (callObj.alerted == false && callMode != "all") - { - callObj.alerted = true; - shouldAlert++; - } - - callObj.shouldAlert = false; - } - - if (g_rosterSettings.compact == false) - { - worker += "
CallsignBandModeGridCallingMsgDXCCFlagStateCountyContdBFreqDTDist(" + - window.opener.distanceUnit.value.toLowerCase() + ")AzimCQzITUzPXLoTWeQSLOQRSSpotLifeOAMSAge
" + - callStr + - "" + - callObj.band + - "" + callObj.mode + "" + - grid + - "" + - callObj.DXcall.formatCallsign() + - "" + callObj.msg + "" + - window.opener.g_dxccToAltName[callObj.dxcc] + "" + - (callObj.state ? callObj.state.substr(3) : "") + - "" + - (callObj.cnty - ? (callObj.qual ? "" : "~ ") + - window.opener.g_cntyToCounty[callObj.cnty] + - (callObj.qual ? "" : " ~") - : "") + - "" + - (callObj.cont ? callObj.cont : "") + - "" + - callObj.RSTsent + - "" + callObj.delta + "" + callObj.dt + "" + - parseInt( - callObj.distance * - MyCircle.validateRadius(window.opener.distanceUnit.value) - ) + - "" + - parseInt(callObj.heading) + - "" + - callObj.cqza.join(",") + - "" + - callObj.ituza.join(",") + - "" + - (callObj.px ? callObj.px : "") + - "?" + - (thisCall in window.opener.g_eqslCallsigns ? "✔" : "") + - "" + - (thisCall in window.opener.g_oqrsCallsigns ? "✔" : "") + - "" + - spotString + - "" + - (timeNowSec() - callObj.life).toDHMS() + - "" + - (timeNowSec() - callObj.age).toDHMS() + - "
"; - RosterTable.innerHTML = worker; - } - else - { - RosterTable.innerHTML = worker + "
"; - } - - var dirPath = window.opener.g_scriptDir; - var scriptExists = false; - var script = "cr-alert.sh"; - - try - { - if (fs.existsSync(dirPath)) - { - if (window.opener.g_platform == "windows") - { - script = "cr-alert.bat"; - } - if ( - fs.existsSync(dirPath + script) && - g_rosterSettings.realtime == false - ) - { - scriptExists = true; - scriptIcon.innerHTML = - "
" + - (window.opener.g_crScript == 1 - ? "Script Enabled" - : "Script Disabled") + - "
"; - scriptIcon.style.display = "block"; - } - else - { - scriptIcon.style.display = "none"; - } - } - } - catch (e) {} - - if (shouldAlert > 0) - { - if (window.opener.g_classicAlerts.huntRoster == true) - { - var notify = window.opener.huntRosterNotify.value; - if (notify == "0") - { - var media = window.opener.huntRosterNotifyMedia.value; - if (media != "none") window.opener.playAlertMediaFile(media); - } - else if (notify == "1") - { - window.opener.speakAlertString( - window.opener.huntRosterNotifyWord.value - ); - } - } - - if ( - g_rosterSettings.realtime == false && - scriptExists && - window.opener.g_crScript == 1 - ) - { - try - { - fs.writeFileSync( - dirPath + "cr-alert.json", - JSON.stringify(g_scriptReport, null, 2) - ); - - var thisProc = dirPath + script; - var cp = require("child_process"); - var child = cp.spawn(thisProc, [], { - detached: true, - cwd: dirPath.slice(0, -1), - stdio: ["ignore", "ignore", "ignore"] - }); - child.unref(); - } - catch (e) - { - conosle.log(e); - } - g_scriptReport = Object(); - } - else g_scriptReport = Object(); - } + var rosterSettings = prepareRosterSettings(); + processRosterFiltering(callRoster, rosterSettings); + processRosterHunting(callRoster, rosterSettings); + renderRoster(callRoster, rosterSettings); + sendAlerts(callRoster, rosterSettings); } function realtimeRoster() diff --git a/package.nw/lib/roster/prepareRosterSettings.js b/package.nw/lib/roster/prepareRosterSettings.js new file mode 100644 index 0000000..5aa845b --- /dev/null +++ b/package.nw/lib/roster/prepareRosterSettings.js @@ -0,0 +1,83 @@ +function prepareRosterSettings() +{ + var rosterSettings = { + bands: {}, + modes: {}, + callMode: g_rosterSettings.callsign, + onlyHits: false, + isAwardTracker: false, + now: timeNowSec() + } + + if (rosterSettings.callMode == "hits") + { + rosterSettings.callMode = "all" + rosterSettings.onlyHits = true; + } + if (referenceNeed.value == LOGBOOK_AWARD_TRACKER) + { + rosterSettings.callMode = "all"; + rosterSettings.onlyHits = false; + rosterSettings.isAwardTracker = true; + g_rosterSettings.huntNeed = "confirmed"; + } + // this appears to be determine if we should show the OAMS column + // if the user is not in offline mode and has OAMS enabled, this could + // be it's own function maybe? + rosterSettings.canMsg = + window.opener.g_mapSettings.offlineMode == false && + window.opener.g_appSettings.gtShareEnable == "true" && + window.opener.g_appSettings.gtMsgEnable == "true"; + + // The following 3 sections deal with QSLing, do we break them out + // individually or lump them into a qslUser function that sets + // all three at the same time? + // this section is for LoTW users, can be a function + if (window.opener.g_callsignLookups.lotwUseEnable == true) + { + usesLoTWDiv.style.display = ""; + if (g_rosterSettings.usesLoTW == true) + { + maxLoTW.style.display = ""; + maxLoTWView.style.display = ""; + } + else + { + maxLoTW.style.display = "none"; + maxLoTWView.style.display = "none"; + } + } + else + { + usesLoTWDiv.style.display = "none"; + maxLoTW.style.display = "none"; + maxLoTWView.style.display = "none"; + } + + if (g_rosterSettings.huntNeed == "mixed") + { + rosterSettings.huntIndex = g_confirmed; + rosterSettings.workedIndex = g_worked; + rosterSettings.layeredMode = LAYERED_MODE_FOR[String(g_rosterSettings.reference)]; + } + else if (g_rosterSettings.huntNeed == "worked") + { + rosterSettings.huntIndex = g_worked; + rosterSettings.workedIndex = false; + rosterSettings.layeredMode = false; + } + else if (g_rosterSettings.huntNeed == "confirmed") + { + rosterSettings.huntIndex = g_confirmed; + rosterSettings.workedIndex = g_worked; + rosterSettings.layeredMode = false; + } + else + { + rosterSettings.huntIndex = false; + rosterSettings.workedIndex = false; + rosterSettings.layeredMode = false; + } + + return rosterSettings +} diff --git a/package.nw/lib/roster/processFiltering.js b/package.nw/lib/roster/processFiltering.js new file mode 100644 index 0000000..9d6c21e --- /dev/null +++ b/package.nw/lib/roster/processFiltering.js @@ -0,0 +1,363 @@ +function processRosterFiltering() +{ + // First loop, exclude calls, mostly based on "Exceptions" settings + // this whole section is full of individual if's that could be broken out + for (var callHash in callRoster) + { + var entry = callRoster[callHash]; + var callObj = entry.callObj; + + var call = entry.DEcall; + + entry.tx = true; + callObj.shouldAlert = false; + callObj.reason = Array(); + callObj.awardReason = "Callsign"; + + if (now - callObj.age > window.opener.g_mapSettings.rosterTime) + { + entry.tx = false; + entry.alerted = false; + callObj.qrz = false; + callObj.reset = true; + continue; + } + if (window.opener.g_instances[callObj.instance].crEnable == false) + { + entry.tx = false; + continue; + } + if (call in g_blockedCalls) + { + entry.tx = false; + continue; + } + if ( + entry.DXcall + " from All" in g_blockedCQ || + entry.DXcall + " from " + window.opener.g_dxccToAltName[callObj.dxcc] in g_blockedCQ + ) + { + entry.tx = false; + continue; + } + if (callObj.dxcc in g_blockedDxcc) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.cqOnly == true && callObj.CQ == false) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.useRegex && g_rosterSettings.callsignRegex.length > 0) + { + try + { + if (!call.match(g_rosterSettings.callsignRegex)) + { + entry.tx = false; + continue; + } + } + catch (e) {} + } + if (g_rosterSettings.requireGrid == true && callObj.grid.length != 4) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMinDB == true && entry.message.SR < g_rosterSettings.minDb) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMaxDT == true && Math.abs(entry.message.DT) > g_rosterSettings.maxDT) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMinFreq == true && entry.message.DF < g_rosterSettings.minFreq) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMaxFreq == true && entry.message.DF > g_rosterSettings.maxFreq) + { + entry.tx = false; + continue; + } + + if (g_rosterSettings.noMsg == true) + { + try + { + if (callObj.msg.match(g_rosterSettings.noMsgValue)) + { + entry.tx = false; + continue; + } + } + catch (e) {} + } + if (g_rosterSettings.onlyMsg == true) + { + try + { + if (!callObj.msg.match(g_rosterSettings.onlyMsgValue)) + { + entry.tx = false; + continue; + } + } + catch (e) {} + } + + if (callObj.dxcc == window.opener.g_myDXCC) + { + if (g_rosterSettings.noMyDxcc == true) + { + entry.tx = false; + continue; + } + } + else + { + if (g_rosterSettings.onlyMyDxcc == true) + { + entry.tx = false; + continue; + } + } + + if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.usesLoTW == true) + { + if (!(call in window.opener.g_lotwCallsigns)) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.maxLoTW < 27) + { + var months = (g_day - window.opener.g_lotwCallsigns[call]) / 30; + if (months > g_rosterSettings.maxLoTW) + { + entry.tx = false; + continue; + } + } + } + + if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.useseQSL == true) + { + if (!(call in window.opener.g_eqslCallsigns)) + { + entry.tx = false; + continue; + } + } + + if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.usesOQRS == true) + { + if (!(call in window.opener.g_oqrsCallsigns)) + { + entry.tx = false; + continue; + } + } + + if (callMode != "all") + { + if (entry.DXcall == "CQ DX" && callObj.dxcc == window.opener.g_myDXCC) + { + entry.tx = false; + continue; + } + + var hash = hashMaker(call, callObj, g_rosterSettings.reference); + if (callMode == "worked" && hash in g_worked.call) + { + entry.tx = false; + continue; + } + if (callMode == "confirmed" && hash in g_confirmed.call) + { + entry.tx = false; + continue; + } + + if (g_rosterSettings.hunting == "grid") + { + var hash = hashMaker(callObj.grid.substr(0, 4), + callObj, g_rosterSettings.reference); + if (huntIndex && hash in huntIndex.grid) + { + entry.tx = false; + continue; + } + if (callObj.grid.length == 0) + { + entry.tx = false; + continue; + } + continue; + } + if (g_rosterSettings.hunting == "dxcc") + { + var hash = hashMaker(String(callObj.dxcc), + callObj, g_rosterSettings.reference); + + if (huntIndex && (hash in huntIndex.dxcc)) + { + entry.tx = false; + continue; + } + continue; + } + + if (g_rosterSettings.hunting == "dxccs" && r_currentDXCCs != -1) + { + if (callObj.dxcc != r_currentDXCCs) + { + entry.tx = false; + continue; + } + } + + if (g_rosterSettings.hunting == "wpx") + { + if (String(callObj.px) == null) + { + entry.tx = false; + continue; + } + var hash = hashMaker(String(callObj.px), + callObj, g_rosterSettings.reference); + + if (huntIndex && (hash in huntIndex.px)) + { + entry.tx = false; + continue; + } + + continue; + } + + if (g_rosterSettings.hunting == "cq") + { + var huntTotal = callObj.cqza.length; + if (huntTotal == 0 || !huntIndex) + { + entry.tx = false; + continue; + } + var huntFound = 0; + for (index in callObj.cqza) + { + var hash = hashMaker(callObj.cqza[index], callObj, g_rosterSettings.reference); + + if (hash in huntIndex.cqz) huntFound++; + } + if (huntFound == huntTotal) + { + entry.tx = false; + continue; + } + continue; + } + + if (g_rosterSettings.hunting == "itu") + { + var huntTotal = callObj.ituza.length; + if (huntTotal == 0 || !huntIndex) + { + entry.tx = false; + continue; + } + var huntFound = 0; + for (index in callObj.ituza) + { + var hash = hashMaker(callObj.ituza[index], callObj, g_rosterSettings.reference); + + if (hash in huntIndex.ituz) huntFound++; + } + if (huntFound == huntTotal) + { + entry.tx = false; + continue; + } + + if (callObj.grid.length == 0) + { + entry.tx = false; + continue; + } + continue; + } + + if (g_rosterSettings.hunting == "usstates" && window.opener.g_callsignLookups.ulsUseEnable == true) + { + var state = callObj.state; + var finalDxcc = callObj.dxcc; + if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) + { + if (state in window.opener.g_StateData) + { + var hash = hashMaker(state, callObj, g_rosterSettings.reference); + + if (huntIndex && hash in huntIndex.state) + { + entry.tx = false; + continue; + } + } + else entry.tx = false; + } + else entry.tx = false; + + continue; + } + + if (g_rosterSettings.hunting == "usstate" && g_currentUSCallsigns) + { + if (call in g_currentUSCallsigns) + { + // Do Nothing + } + else + { + entry.tx = false; + continue; + } + continue; + } + } + if (isAwardTracker) + { + var tx = false; + var baseHash = hashMaker("", callObj, g_rosterSettings.reference); + + for (var award in g_awardTracker) + { + if (g_awardTracker[award].enable) + { + tx = testAward(award, callObj, baseHash); + if (tx) + { + var x = g_awardTracker[award]; + + // TODO: Move award reason out of exclusions code? + callObj.awardReason = + g_awards[x.sponsor].awards[x.name].tooltip + + " (" + + g_awards[x.sponsor].sponsor + + ")"; + + break; + } + } + } + entry.tx = tx; + } + } +} diff --git a/package.nw/lib/roster/processHunting.js b/package.nw/lib/roster/processHunting.js new file mode 100644 index 0000000..c569e08 --- /dev/null +++ b/package.nw/lib/roster/processHunting.js @@ -0,0 +1,706 @@ +function processHunting() +{ + // these vars, do they rely on anything between the top and here? + // if not could they be put in the var list at the beginning? + var hasGtPin = false; + + var newCallList = Array(); + var inversionAlpha = "DD"; + var row = "#000000"; + var bold = "#000000;font-weight: bold;"; + var unconf = "background-clip:padding-box;box-shadow: 0 0 7px 3px inset "; + var layeredAlpha = "77"; + var layeredInversionAlpha = "66"; + var layeredUnconf = "background-clip:padding-box;box-shadow: 0 0 4px 2px inset "; + var layeredUnconfAlpha = "AA"; + + // TODO: Hunting results might be used to filter, based on the "Callsigns: Only Wanted" option, + // so maybe we can move this loop first, and add a check to the filtering loop? + + // Second loop, hunting and highlighting + for (var callHash in callRoster) + { + var entry = callRoster[callHash]; + var callObj = entry.callObj; + + // Special case check for called station + if (callObj.qrz == true && entry.tx == false) + { + // The instance has to be enabled + if (window.opener.g_instances[callObj.instance].crEnable == true) + { + // Calling us, but we wouldn't normally display + // If they are not ignored or we're in a QSO with them, var it through + + // TODO: This is here because it's after the filtering stage + if ((!(entry.DEcall in g_blockedCalls) && !(callObj.dxcc in g_blockedDxcc)) || + window.opener.g_instances[callObj.instance].status.DXcall == entry.DEcall) + { + entry.tx = true; + } + } + } + + // Only render entries with `tx == true`, ignore the rest + if (callObj.dxcc != -1 && entry.tx == true) + { + // In layered mode ("Hunting: mixed") the workHashSuffix becomes a more stricter 'live band', + // while the layered suffix is a broader 'mixed band' + var workHashSuffix, layeredHashSuffix; + if (layeredMode) + { + workHashSuffix = hashMaker("", callObj, layeredMode); + layeredHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); + } + else + { + workHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); + layeredHashSuffix = false + } + var workHash = workHashSuffix; // TODO: Remove after replacing all occurrences with Suffix + + var callsign = entry.DEcall; + + callObj.hunting = {} + callObj.callFlags = {} + + var colorObject = Object(); + + var callPointer = callObj.CQ == true ? "cursor:pointer" : ""; + + var didWork = false; + + var call = "#FFFF00"; + var grid = "#00FFFF"; + var calling = "#90EE90"; + var dxcc = "#FFA500"; + var state = "#90EE90"; + var cnty = "#CCDD00"; + var cont = "#00DDDD"; + var cqz = "#DDDDDD"; + var ituz = "#DDDDDD"; + var wpx = "#FFFF00"; + + hasGtPin = false; + var shouldAlert = false; + var callBg, gridBg, callingBg, dxccBg, stateBg, cntyBg, contBg, cqzBg, ituzBg, wpxBg, gtBg; + var callConf, gridConf, callingConf, dxccConf, stateConf, cntyConf, contConf, cqzConf, ituzConf, wpxConf; + + callBg = gridBg = callingBg = dxccBg = stateBg = cntyBg = contBg = cqzBg = ituzBg = wpxBg = gtBg = row; + + callConf = gridConf = callingConf = dxccConf = stateConf = cntyConf = contConf = cqzConf = ituzConf = wpxConf = + ""; + + var hash = callsign + workHashSuffix; + var layeredHash = layeredHashSuffix && (callsign + layeredHashSuffix) + + // Call worked in current logbook settings, regardless of hunting mode + if (hash in g_worked.call) + { + callObj.callFlags.worked = true; + didWork = true; + callConf = `${unconf}${call}${inversionAlpha};`; + + if (hash in g_confirmed.call) + { + callObj.callFlags.confirmed = true; + callPointer = "text-decoration: line-through; "; + callConf = ""; + } + } + + // Calls that have OAMS chat support + if ( + callsign in window.opener.g_gtCallsigns && + window.opener.g_gtCallsigns[callsign] in window.opener.g_gtFlagPins && + window.opener.g_gtFlagPins[window.opener.g_gtCallsigns[callsign]].canmsg == true + ) + { + callObj.callFlags.oams = true; + // grab the CID + colorObject.gt = window.opener.g_gtCallsigns[callsign]; + hasGtPin = true; + } + else + { + colorObject.gt = 0; + } + + // We only do hunt highlighting when showing all entries + // This means "Callsigns: All Traffic", "Callsigns: All Traffic/Only Wanted" and "Logbook: Award Tracker" + // There is no highlighting in other modes + if (callMode == "all") + { + // Skip when "only new calls" + // Questions: Move to the first loop? Why only skip new calls in "all traffic" and not other modes? + if (allOnlyNew.checked == true && didWork && callObj.qrz == false) + { + entry.tx = false; + continue; + } + + // Hunting for callsigns + if (huntCallsign.checked == true) + { + var hash = callsign + workHashSuffix; + var layeredHash = layeredMode && (callsign + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.call)) + { + shouldAlert = true; + + callObj.reason.push("call"); + + if (workedIndex && hash in workedIndex.call) + { + if (layeredMode && layeredHash in huntIndex.call) + { + callObj.hunting.call = "worked-and-mixed"; + callConf = `${layeredUnconf}${call}${layeredUnconfAlpha};`; + callBg = `${call}${layeredInversionAlpha}`; + call = bold; + } + // /* Currently we don't have a way to figure out + // * if the call is worked only in this band or also others, + // * so we cannot cover this particular combination + // * and have to default to just showing it as plain "worked" + // */ + // else if (layeredMode && layeredHash in workedIndex.call) + // { + // callObj.hunting.call = "worked-and-mixed-worked"; + // callConf = `${layeredUnconf}${call}${layeredAlpha};`; + // } + else + { + callObj.hunting.call = "worked"; + callConf = `${unconf}${call}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.call) + { + callObj.hunting.call = "mixed"; + callBg = `${call}${layeredAlpha};`; + call = bold; + } + else if (layeredMode && layeredHash in workedIndex.call) + { + callObj.hunting.call = "mixed-worked"; + callConf = `${unconf}${call}${layeredAlpha};`; + } + else + { + callObj.hunting.call = "hunted"; + callBg = `${call}${inversionAlpha};`; + call = bold; + } + } + } + } + + // Hunting for "stations calling you" + if (huntQRZ.checked == true && callObj.qrz == true) + { + callObj.callFlags.calling = true + shouldAlert = true; + callObj.reason.push("qrz"); + } + + // Hunting for stations with OAMS + if (huntOAMS.checked == true && hasGtPin == true) + { + callObj.hunting.oams = "hunted"; + shouldAlert = true; + callObj.reason.push("oams"); + } + + // Hunting for grids + if (huntGrid.checked == true && callObj.grid.length > 1) + { + var hash = callObj.grid.substr(0, 4) + workHashSuffix; + var layeredHash = layeredMode && (callObj.grid.substr(0, 4) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.grid)) + { + shouldAlert = true; + + callObj.reason.push("grid"); + + if (workedIndex && hash in workedIndex.grid) + { + if (layeredMode && layeredHash in huntIndex.grid) + { + callObj.hunting.grid = "worked-and-mixed"; + gridConf = `${layeredUnconf}${grid}${layeredUnconfAlpha};`; + gridBg = `${grid}${layeredInversionAlpha}`; + grid = bold; + } + else + { + callObj.hunting.grid = "worked"; + gridConf = `${unconf}${grid}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.grid) + { + callObj.hunting.grid = "mixed"; + gridBg = `${grid}${layeredAlpha};`; + grid = bold; + } + else if (layeredMode && layeredHash in workedIndex.grid) + { + callObj.hunting.grid = "mixed-worked"; + gridConf = `${unconf}${grid}${layeredAlpha};`; + } + else + { + callObj.hunting.grid = "hunted"; + gridBg = `${grid}${inversionAlpha};`; + grid = bold; + } + } + } + } + + // Hunting for DXCC + if (huntDXCC.checked == true) + { + var hash = String(callObj.dxcc) + workHashSuffix; + var layeredHash = layeredMode && (String(callObj.dxcc) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.dxcc)) + { + shouldAlert = true; + + callObj.reason.push("dxcc"); + + if (workedIndex && hash in workedIndex.dxcc) + { + if (layeredMode && layeredHash in huntIndex.dxcc) + { + callObj.hunting.dxcc = "worked-and-mixed"; + dxccConf = `${layeredUnconf}${dxcc}${layeredUnconfAlpha};`; + dxccBg = `${dxcc}${layeredInversionAlpha}`; + dxcc = bold; + } + else + { + callObj.hunting.dxcc = "worked"; + dxccConf = `${unconf}${dxcc}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.dxcc) + { + callObj.hunting.dxcc = "mixed"; + dxccBg = `${dxcc}${layeredAlpha};`; + dxcc = bold; + } + else if (layeredMode && layeredHash in workedIndex.dxcc) + { + callObj.hunting.dxcc = "mixed-worked"; + dxccConf = `${unconf}${dxcc}${layeredAlpha};`; + } + else + { + callObj.hunting.dxcc = "hunted"; + dxccBg = `${dxcc}${inversionAlpha};`; + dxcc = bold; + } + } + } + } + + // Hunting for US States + if (huntState.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) + { + var stateSearch = callObj.state; + var finalDxcc = callObj.dxcc; + if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) + { + if (stateSearch in window.opener.g_StateData) + { + var hash = stateSearch + workHashSuffix; + var layeredHash = layeredMode && (stateSearch + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.state)) + { + shouldAlert = true; + + callObj.reason.push("state"); + + if (workedIndex && hash in workedIndex.state) + { + if (layeredMode && layeredHash in huntIndex.state) + { + callObj.hunting.state = "worked-and-mixed"; + stateConf = `${layeredUnconf}${state}${layeredUnconfAlpha};`; + stateBg = `${state}${layeredInversionAlpha}`; + state = bold; + } + else + { + callObj.hunting.state = "worked"; + stateConf = `${unconf}${state}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.state) + { + callObj.hunting.state = "mixed"; + stateBg = `${state}${layeredAlpha};`; + state = bold; + } + else if (layeredMode && layeredHash in workedIndex.state) + { + callObj.hunting.state = "mixed-worked"; + stateConf = `${unconf}${state}${layeredAlpha};`; + } + else + { + callObj.hunting.state = "hunted"; + stateBg = `${state}${inversionAlpha};`; + state = bold; + } + } + } + } + } + } + + // Hunting for US Counties + if (huntCounty.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) + { + var finalDxcc = callObj.dxcc; + if ( + callObj.cnty && + (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6 || finalDxcc == 202) && + callObj.cnty.length > 0 + ) + { + var hash = callObj.cnty + (layeredMode ? layeredHashSuffix : workHashSuffix); + + if ((huntIndex && !(hash in huntIndex.cnty)) || callObj.qual == false) + { + if (callObj.qual == false) + { + var counties = window.opener.g_zipToCounty[callObj.zipcode]; + var foundHit = false; + for (var cnt in counties) + { + var hh = counties[cnt] + workHash; + callObj.cnty = counties[cnt]; + if (huntIndex && !(hh in huntIndex.cnty)) + { + foundHit = true; + break; + } + } + if (foundHit) shouldAlert = true; + } + else + { + shouldAlert = true; + } + + if (shouldAlert) + { + callObj.reason.push("cnty"); + + if (workedIndex && hash in workedIndex.cnty) + { + callObj.hunting.cnty = "worked"; + cntyConf = `${unconf}${cnty}${inversionAlpha};`; + } + else + { + callObj.hunting.cnty = "hunted"; + cntyBg = `${cnty}${inversionAlpha}`; + cnty = bold; + } + } + } + } + } + + // Hunting for CQ Zones + if (huntCQz.checked == true) + { + var huntTotal = callObj.cqza.length; + var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; + + for (index in callObj.cqza) + { + var hash = callObj.cqza[index] + workHashSuffix; + var layeredHash = layeredMode && (callObj.cqza[index] + layeredHashSuffix) + + if (huntIndex && hash in huntIndex.cqz) huntFound++; + if (layeredMode && layeredHash in huntIndex.cqz) layeredFound++; + if (workedIndex && hash in workedIndex.cqz) workedFound++; + if (layeredMode && layeredHash in workedIndex.cqz) layeredWorkedFound++; + } + if (huntFound != huntTotal) + { + shouldAlert = true; + callObj.reason.push("cqz"); + + if (workedIndex && workedFound == huntTotal) + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.cqz = "worked-and-mixed"; + cqzConf = `${layeredUnconf}${cqz}${layeredUnconfAlpha};`; + cqzBg = `${cqz}${layeredInversionAlpha}`; + cqz = bold; + } + else + { + callObj.hunting.cqz = "worked"; + cqzConf = `${unconf}${cqz}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.cqz = "mixed"; + cqzBg = `${cqz}${layeredAlpha};`; + cqz = bold; + } + else if (layeredMode && layeredWorkedFound == huntTotal) + { + callObj.hunting.cqz = "mixed-worked"; + cqzConf = `${unconf}${cqz}${layeredAlpha};`; + } + else + { + callObj.hunting.cqz = "hunted"; + cqzBg = `${cqz}${inversionAlpha};`; + cqz = bold; + } + } + } + } + + // Hunting for ITU Zones + if (huntITUz.checked == true) + { + var huntTotal = callObj.ituza.length; + var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; + + for (index in callObj.ituza) + { + var hash = callObj.ituza[index] + workHashSuffix; + var layeredHash = layeredMode && (callObj.ituza[index] + layeredHashSuffix) + + if (huntIndex && hash in huntIndex.ituz) huntFound++; + if (layeredMode && layeredHash in huntIndex.ituz) layeredFound++; + if (workedIndex && hash in workedIndex.ituz) workedFound++; + if (layeredMode && layeredHash in workedIndex.ituz) layeredWorkedFound++; + } + if (huntFound != huntTotal) + { + shouldAlert = true; + callObj.reason.push("ituz"); + + if (workedIndex && workedFound == huntTotal) + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.ituz = "worked-and-mixed"; + ituzConf = `${layeredUnconf}${ituz}${layeredUnconfAlpha};`; + ituzBg = `${ituz}${layeredInversionAlpha}`; + ituz = bold; + } + else + { + callObj.hunting.ituz = "worked"; + ituzConf = `${unconf}${ituz}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.ituz = "mixed"; + ituzBg = `${ituz}${layeredAlpha};`; + ituz = bold; + } + else if (layeredMode && layeredWorkedFound == huntTotal) + { + callObj.hunting.ituz = "mixed-worked"; + ituzConf = `${unconf}${ituz}${layeredAlpha};`; + } + else + { + callObj.hunting.ituz = "hunted"; + ituzBg = `${ituz}${inversionAlpha};`; + ituz = bold; + } + } + } + } + + // Hunting for WPX (Prefixes) + if (huntPX.checked == true && callObj.px) + { + var hash = String(callObj.px) + workHashSuffix; + var layeredHash = layeredMode && (String(callObj.px) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.px)) + { + shouldAlert = true; + + callObj.reason.push("wpx"); + + if (workedIndex && hash in workedIndex.px) + { + if (layeredMode && layeredHash in huntIndex.px) + { + callObj.hunting.wpx = "worked-and-mixed"; + wpxConf = `${layeredUnconf}${wpx}${layeredUnconfAlpha};`; + wpxBg = `${wpx}${layeredInversionAlpha}`; + wpx = bold; + } + else + { + callObj.hunting.wpx = "worked"; + wpxConf = `${unconf}${wpx}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.px) + { + callObj.hunting.wpx = "mixed"; + wpxBg = `${wpx}${layeredAlpha};`; + wpx = bold; + } + else if (layeredMode && layeredHash in workedIndex.px) + { + callObj.hunting.wpx = "mixed-worked"; + wpxConf = `${unconf}${wpx}${layeredAlpha};`; + } + else + { + callObj.hunting.wpx = "hunted"; + wpxBg = `${wpx}${inversionAlpha};`; + wpx = bold; + } + } + } + } + + // Hunting for Continents + if (huntCont.checked == true && callObj.cont) + { + var hash = String(callObj.cont) + workHashSuffix; + var layeredHash = layeredMode && (String(callObj.cont) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.cont)) + { + shouldAlert = true; + + callObj.reason.push("cont"); + + if (workedIndex && hash in workedIndex.cont) + { + if (layeredMode && layeredHash in huntIndex.cont) + { + callObj.hunting.cont = "worked-and-mixed"; + contConf = `${layeredUnconf}${cont}${layeredUnconfAlpha};`; + contBg = `${cont}${layeredInversionAlpha}`; + cont = bold; + } + else + { + callObj.hunting.cont = "worked"; + contConf = `${unconf}${cont}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.cont) + { + callObj.hunting.cont = "mixed"; + contBg = `${cont}${layeredAlpha};`; + cont = bold; + } + else if (layeredMode && layeredHash in workedIndex.cont) + { + callObj.hunting.cont = "mixed-worked"; + contConf = `${unconf}${cont}${layeredAlpha};`; + } + else + { + callObj.hunting.cont = "hunted"; + contBg = `${cont}${inversionAlpha};`; + cont = bold; + } + } + } + } + } + + // Station is calling us + if (callObj.DXcall == window.opener.myDEcall) + { + callingBg = "#0000FF" + inversionAlpha; + calling = "#FFFF00;text-shadow: 0px 0px 2px #FFFF00"; + } + else if (callObj.CQ == true && g_rosterSettings.cqOnly == false) + { + callingBg = calling + inversionAlpha; + calling = bold; + } + + // Assemble all styles + colorObject.call = "style='" + callConf + "background-color:" + callBg + ";color:" + + call + ";" + callPointer + "'"; + colorObject.grid = "style='" + gridConf + "background-color:" + gridBg + ";color:" + grid + ";cursor:pointer'"; + colorObject.calling = "style='" + callingConf + "background-color:" + callingBg + ";color:" + calling + "'"; + colorObject.dxcc = "style='" + dxccConf + "background-color:" + dxccBg + ";color:" + dxcc + "'"; + colorObject.state = "style='" + stateConf + "background-color:" + stateBg + ";color:" + state + "'"; + colorObject.cnty = "style='" + cntyConf + "background-color:" + cntyBg + ";color:" + cnty + "'"; + colorObject.cont = "style='" + contConf + "background-color:" + contBg + ";color:" + cont + "'"; + colorObject.cqz = "style='" + cqzConf + "background-color:" + cqzBg + ";color:" + cqz + "'"; + colorObject.ituz = "style='" + ituzConf + "background-color:" + ituzBg + ";color:" + ituz + "'"; + colorObject.px = "style='" + wpxConf + "background-color:" + wpxBg + ";color:" + wpx + "'"; + + // Just in case, don't alert if we worked this callsign alread + if (didWork && shouldAlert) shouldAlert = false; + + callObj.shouldAlert = shouldAlert; + + callObj.style = colorObject; + + if (g_rosterSettings.columns.Spot) + { + callObj.spot = window.opener.getSpotTime( + callObj.DEcall + callObj.mode + callObj.band + callObj.grid + ); + if (callObj.spot == null) + { + callObj.spot = { when: 0, snr: 0 }; + } + } + else + { + callObj.spot = { when: 0, snr: 0 }; + } + + modes[callObj.mode] = true; + bands[callObj.band] = true; + + // NOTE: This is where calls that were filtered are passed into an array that will be used for the rendering loop + newCallList.push(callObj); + } + } + + return newCallList; +} diff --git a/package.nw/lib/roster/processRosterFiltering.js b/package.nw/lib/roster/processRosterFiltering.js new file mode 100644 index 0000000..9c41142 --- /dev/null +++ b/package.nw/lib/roster/processRosterFiltering.js @@ -0,0 +1,369 @@ +function processRosterFiltering(callRoster, rosterSettings) +{ + // First loop, exclude calls, mostly based on "Exceptions" settings + // this whole section is full of individual if's that could be broken out + for (var callHash in callRoster) + { + var entry = callRoster[callHash]; + var callObj = entry.callObj; + + var call = entry.DEcall; + + entry.tx = true; + callObj.shouldAlert = false; + callObj.reason = Array(); + callObj.awardReason = "Callsign"; + + if (now - callObj.age > window.opener.g_mapSettings.rosterTime) + { + entry.tx = false; + entry.alerted = false; + callObj.qrz = false; + callObj.reset = true; + continue; + } + if (window.opener.g_instances[callObj.instance].crEnable == false) + { + entry.tx = false; + continue; + } + if (call in g_blockedCalls) + { + entry.tx = false; + continue; + } + if ( + entry.DXcall + " from All" in g_blockedCQ || + entry.DXcall + " from " + window.opener.g_dxccToAltName[callObj.dxcc] in g_blockedCQ + ) + { + entry.tx = false; + continue; + } + if (callObj.dxcc in g_blockedDxcc) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.cqOnly == true && callObj.CQ == false) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.useRegex && g_rosterSettings.callsignRegex.length > 0) + { + try + { + if (!call.match(g_rosterSettings.callsignRegex)) + { + entry.tx = false; + continue; + } + } + catch (e) {} + } + if (g_rosterSettings.requireGrid == true && callObj.grid.length != 4) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMinDB == true && entry.message.SR < g_rosterSettings.minDb) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMaxDT == true && Math.abs(entry.message.DT) > g_rosterSettings.maxDT) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMinFreq == true && entry.message.DF < g_rosterSettings.minFreq) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.wantMaxFreq == true && entry.message.DF > g_rosterSettings.maxFreq) + { + entry.tx = false; + continue; + } + + if (g_rosterSettings.noMsg == true) + { + try + { + if (callObj.msg.match(g_rosterSettings.noMsgValue)) + { + entry.tx = false; + continue; + } + } + catch (e) {} + } + if (g_rosterSettings.onlyMsg == true) + { + try + { + if (!callObj.msg.match(g_rosterSettings.onlyMsgValue)) + { + entry.tx = false; + continue; + } + } + catch (e) {} + } + + if (callObj.dxcc == window.opener.g_myDXCC) + { + if (g_rosterSettings.noMyDxcc == true) + { + entry.tx = false; + continue; + } + } + else + { + if (g_rosterSettings.onlyMyDxcc == true) + { + entry.tx = false; + continue; + } + } + + if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.usesLoTW == true) + { + if (!(call in window.opener.g_lotwCallsigns)) + { + entry.tx = false; + continue; + } + if (g_rosterSettings.maxLoTW < 27) + { + var months = (g_day - window.opener.g_lotwCallsigns[call]) / 30; + if (months > g_rosterSettings.maxLoTW) + { + entry.tx = false; + continue; + } + } + } + + if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.useseQSL == true) + { + if (!(call in window.opener.g_eqslCallsigns)) + { + entry.tx = false; + continue; + } + } + + if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.usesOQRS == true) + { + if (!(call in window.opener.g_oqrsCallsigns)) + { + entry.tx = false; + continue; + } + } + + if (callMode != "all") + { + if (entry.DXcall == "CQ DX" && callObj.dxcc == window.opener.g_myDXCC) + { + entry.tx = false; + continue; + } + + var hash = hashMaker(call, callObj, g_rosterSettings.reference); + if (callMode == "worked" && hash in g_worked.call) + { + entry.tx = false; + continue; + } + if (callMode == "confirmed" && hash in g_confirmed.call) + { + entry.tx = false; + continue; + } + + if (g_rosterSettings.hunting == "grid") + { + var hash = hashMaker(callObj.grid.substr(0, 4), + callObj, g_rosterSettings.reference); + if (huntIndex && hash in huntIndex.grid) + { + entry.tx = false; + continue; + } + if (callObj.grid.length == 0) + { + entry.tx = false; + continue; + } + continue; + } + if (g_rosterSettings.hunting == "dxcc") + { + var hash = hashMaker(String(callObj.dxcc), + callObj, g_rosterSettings.reference); + + if (huntIndex && (hash in huntIndex.dxcc)) + { + entry.tx = false; + continue; + } + continue; + } + + if (callObj.dxcc === -1) + { + entry.tx = false; + continue; + } + + if (g_rosterSettings.hunting == "dxccs" && r_currentDXCCs != -1) + { + if (callObj.dxcc != r_currentDXCCs) + { + entry.tx = false; + continue; + } + } + + if (g_rosterSettings.hunting == "wpx") + { + if (String(callObj.px) == null) + { + entry.tx = false; + continue; + } + var hash = hashMaker(String(callObj.px), + callObj, g_rosterSettings.reference); + + if (huntIndex && (hash in huntIndex.px)) + { + entry.tx = false; + continue; + } + + continue; + } + + if (g_rosterSettings.hunting == "cq") + { + var huntTotal = callObj.cqza.length; + if (huntTotal == 0 || !huntIndex) + { + entry.tx = false; + continue; + } + var huntFound = 0; + for (index in callObj.cqza) + { + var hash = hashMaker(callObj.cqza[index], callObj, g_rosterSettings.reference); + + if (hash in huntIndex.cqz) huntFound++; + } + if (huntFound == huntTotal) + { + entry.tx = false; + continue; + } + continue; + } + + if (g_rosterSettings.hunting == "itu") + { + var huntTotal = callObj.ituza.length; + if (huntTotal == 0 || !huntIndex) + { + entry.tx = false; + continue; + } + var huntFound = 0; + for (index in callObj.ituza) + { + var hash = hashMaker(callObj.ituza[index], callObj, g_rosterSettings.reference); + + if (hash in huntIndex.ituz) huntFound++; + } + if (huntFound == huntTotal) + { + entry.tx = false; + continue; + } + + if (callObj.grid.length == 0) + { + entry.tx = false; + continue; + } + continue; + } + + if (g_rosterSettings.hunting == "usstates" && window.opener.g_callsignLookups.ulsUseEnable == true) + { + var state = callObj.state; + var finalDxcc = callObj.dxcc; + if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) + { + if (state in window.opener.g_StateData) + { + var hash = hashMaker(state, callObj, g_rosterSettings.reference); + + if (huntIndex && hash in huntIndex.state) + { + entry.tx = false; + continue; + } + } + else entry.tx = false; + } + else entry.tx = false; + + continue; + } + + if (g_rosterSettings.hunting == "usstate" && g_currentUSCallsigns) + { + if (call in g_currentUSCallsigns) + { + // Do Nothing + } + else + { + entry.tx = false; + continue; + } + continue; + } + } + if (isAwardTracker) + { + var tx = false; + var baseHash = hashMaker("", callObj, g_rosterSettings.reference); + + for (var award in g_awardTracker) + { + if (g_awardTracker[award].enable) + { + tx = testAward(award, callObj, baseHash); + if (tx) + { + var x = g_awardTracker[award]; + + // TODO: Move award reason out of exclusions code? + callObj.awardReason = + g_awards[x.sponsor].awards[x.name].tooltip + + " (" + + g_awards[x.sponsor].sponsor + + ")"; + + break; + } + } + } + entry.tx = tx; + } + } +} diff --git a/package.nw/lib/roster/processRosterHunting.js b/package.nw/lib/roster/processRosterHunting.js new file mode 100644 index 0000000..6adaeab --- /dev/null +++ b/package.nw/lib/roster/processRosterHunting.js @@ -0,0 +1,700 @@ +function processRosterHunting(callRoster, rosterSettings) +{ + // these vars, do they rely on anything between the top and here? + // if not could they be put in the var list at the beginning? + var hasGtPin = false; + + var inversionAlpha = "DD"; + var row = "#000000"; + var bold = "#000000;font-weight: bold;"; + var unconf = "background-clip:padding-box;box-shadow: 0 0 7px 3px inset "; + var layeredAlpha = "77"; + var layeredInversionAlpha = "66"; + var layeredUnconf = "background-clip:padding-box;box-shadow: 0 0 4px 2px inset "; + var layeredUnconfAlpha = "AA"; + + // TODO: Hunting results might be used to filter, based on the "Callsigns: Only Wanted" option, + // so maybe we can move this loop first, and add a check to the filtering loop? + + // Second loop, hunting and highlighting + for (var callHash in callRoster) + { + var entry = callRoster[callHash]; + var callObj = entry.callObj; + + // Special case check for called station + if (callObj.qrz == true && entry.tx == false) + { + // The instance has to be enabled + if (window.opener.g_instances[callObj.instance].crEnable == true) + { + // Calling us, but we wouldn't normally display + // If they are not ignored or we're in a QSO with them, var it through + + // TODO: This is here because it's after the filtering stage + if ((!(entry.DEcall in g_blockedCalls) && !(callObj.dxcc in g_blockedDxcc)) || + window.opener.g_instances[callObj.instance].status.DXcall == entry.DEcall) + { + entry.tx = true; + } + } + } + + // Only render entries with `tx == true`, ignore the rest + if (entry.tx == true) + { + // In layered mode ("Hunting: mixed") the workHashSuffix becomes a more stricter 'live band', + // while the layered suffix is a broader 'mixed band' + var workHashSuffix, layeredHashSuffix; + if (layeredMode) + { + workHashSuffix = hashMaker("", callObj, layeredMode); + layeredHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); + } + else + { + workHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); + layeredHashSuffix = false + } + var workHash = workHashSuffix; // TODO: Remove after replacing all occurrences with Suffix + + var callsign = entry.DEcall; + + callObj.hunting = {} + callObj.callFlags = {} + + var colorObject = Object(); + + var callPointer = callObj.CQ == true ? "cursor:pointer" : ""; + + var didWork = false; + + var call = "#FFFF00"; + var grid = "#00FFFF"; + var calling = "#90EE90"; + var dxcc = "#FFA500"; + var state = "#90EE90"; + var cnty = "#CCDD00"; + var cont = "#00DDDD"; + var cqz = "#DDDDDD"; + var ituz = "#DDDDDD"; + var wpx = "#FFFF00"; + + hasGtPin = false; + var shouldAlert = false; + var callBg, gridBg, callingBg, dxccBg, stateBg, cntyBg, contBg, cqzBg, ituzBg, wpxBg, gtBg; + var callConf, gridConf, callingConf, dxccConf, stateConf, cntyConf, contConf, cqzConf, ituzConf, wpxConf; + + callBg = gridBg = callingBg = dxccBg = stateBg = cntyBg = contBg = cqzBg = ituzBg = wpxBg = gtBg = row; + + callConf = gridConf = callingConf = dxccConf = stateConf = cntyConf = contConf = cqzConf = ituzConf = wpxConf = + ""; + + var hash = callsign + workHashSuffix; + var layeredHash = layeredHashSuffix && (callsign + layeredHashSuffix) + + // Call worked in current logbook settings, regardless of hunting mode + if (hash in g_worked.call) + { + callObj.callFlags.worked = true; + didWork = true; + callConf = `${unconf}${call}${inversionAlpha};`; + + if (hash in g_confirmed.call) + { + callObj.callFlags.confirmed = true; + callPointer = "text-decoration: line-through; "; + callConf = ""; + } + } + + // Calls that have OAMS chat support + if ( + callsign in window.opener.g_gtCallsigns && + window.opener.g_gtCallsigns[callsign] in window.opener.g_gtFlagPins && + window.opener.g_gtFlagPins[window.opener.g_gtCallsigns[callsign]].canmsg == true + ) + { + callObj.callFlags.oams = true; + // grab the CID + colorObject.gt = window.opener.g_gtCallsigns[callsign]; + hasGtPin = true; + } + else + { + colorObject.gt = 0; + } + + // We only do hunt highlighting when showing all entries + // This means "Callsigns: All Traffic", "Callsigns: All Traffic/Only Wanted" and "Logbook: Award Tracker" + // There is no highlighting in other modes + if (callMode == "all") + { + // Skip when "only new calls" + // Questions: Move to the first loop? Why only skip new calls in "all traffic" and not other modes? + if (allOnlyNew.checked == true && didWork && callObj.qrz == false) + { + entry.tx = false; + continue; + } + + // Hunting for callsigns + if (huntCallsign.checked == true) + { + var hash = callsign + workHashSuffix; + var layeredHash = layeredMode && (callsign + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.call)) + { + shouldAlert = true; + + callObj.reason.push("call"); + + if (workedIndex && hash in workedIndex.call) + { + if (layeredMode && layeredHash in huntIndex.call) + { + callObj.hunting.call = "worked-and-mixed"; + callConf = `${layeredUnconf}${call}${layeredUnconfAlpha};`; + callBg = `${call}${layeredInversionAlpha}`; + call = bold; + } + // /* Currently we don't have a way to figure out + // * if the call is worked only in this band or also others, + // * so we cannot cover this particular combination + // * and have to default to just showing it as plain "worked" + // */ + // else if (layeredMode && layeredHash in workedIndex.call) + // { + // callObj.hunting.call = "worked-and-mixed-worked"; + // callConf = `${layeredUnconf}${call}${layeredAlpha};`; + // } + else + { + callObj.hunting.call = "worked"; + callConf = `${unconf}${call}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.call) + { + callObj.hunting.call = "mixed"; + callBg = `${call}${layeredAlpha};`; + call = bold; + } + else if (layeredMode && layeredHash in workedIndex.call) + { + callObj.hunting.call = "mixed-worked"; + callConf = `${unconf}${call}${layeredAlpha};`; + } + else + { + callObj.hunting.call = "hunted"; + callBg = `${call}${inversionAlpha};`; + call = bold; + } + } + } + } + + // Hunting for "stations calling you" + if (huntQRZ.checked == true && callObj.qrz == true) + { + callObj.callFlags.calling = true + shouldAlert = true; + callObj.reason.push("qrz"); + } + + // Hunting for stations with OAMS + if (huntOAMS.checked == true && hasGtPin == true) + { + callObj.hunting.oams = "hunted"; + shouldAlert = true; + callObj.reason.push("oams"); + } + + // Hunting for grids + if (huntGrid.checked == true && callObj.grid.length > 1) + { + var hash = callObj.grid.substr(0, 4) + workHashSuffix; + var layeredHash = layeredMode && (callObj.grid.substr(0, 4) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.grid)) + { + shouldAlert = true; + + callObj.reason.push("grid"); + + if (workedIndex && hash in workedIndex.grid) + { + if (layeredMode && layeredHash in huntIndex.grid) + { + callObj.hunting.grid = "worked-and-mixed"; + gridConf = `${layeredUnconf}${grid}${layeredUnconfAlpha};`; + gridBg = `${grid}${layeredInversionAlpha}`; + grid = bold; + } + else + { + callObj.hunting.grid = "worked"; + gridConf = `${unconf}${grid}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.grid) + { + callObj.hunting.grid = "mixed"; + gridBg = `${grid}${layeredAlpha};`; + grid = bold; + } + else if (layeredMode && layeredHash in workedIndex.grid) + { + callObj.hunting.grid = "mixed-worked"; + gridConf = `${unconf}${grid}${layeredAlpha};`; + } + else + { + callObj.hunting.grid = "hunted"; + gridBg = `${grid}${inversionAlpha};`; + grid = bold; + } + } + } + } + + // Hunting for DXCC + if (huntDXCC.checked == true) + { + var hash = String(callObj.dxcc) + workHashSuffix; + var layeredHash = layeredMode && (String(callObj.dxcc) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.dxcc)) + { + shouldAlert = true; + + callObj.reason.push("dxcc"); + + if (workedIndex && hash in workedIndex.dxcc) + { + if (layeredMode && layeredHash in huntIndex.dxcc) + { + callObj.hunting.dxcc = "worked-and-mixed"; + dxccConf = `${layeredUnconf}${dxcc}${layeredUnconfAlpha};`; + dxccBg = `${dxcc}${layeredInversionAlpha}`; + dxcc = bold; + } + else + { + callObj.hunting.dxcc = "worked"; + dxccConf = `${unconf}${dxcc}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.dxcc) + { + callObj.hunting.dxcc = "mixed"; + dxccBg = `${dxcc}${layeredAlpha};`; + dxcc = bold; + } + else if (layeredMode && layeredHash in workedIndex.dxcc) + { + callObj.hunting.dxcc = "mixed-worked"; + dxccConf = `${unconf}${dxcc}${layeredAlpha};`; + } + else + { + callObj.hunting.dxcc = "hunted"; + dxccBg = `${dxcc}${inversionAlpha};`; + dxcc = bold; + } + } + } + } + + // Hunting for US States + if (huntState.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) + { + var stateSearch = callObj.state; + var finalDxcc = callObj.dxcc; + if (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6) + { + if (stateSearch in window.opener.g_StateData) + { + var hash = stateSearch + workHashSuffix; + var layeredHash = layeredMode && (stateSearch + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.state)) + { + shouldAlert = true; + + callObj.reason.push("state"); + + if (workedIndex && hash in workedIndex.state) + { + if (layeredMode && layeredHash in huntIndex.state) + { + callObj.hunting.state = "worked-and-mixed"; + stateConf = `${layeredUnconf}${state}${layeredUnconfAlpha};`; + stateBg = `${state}${layeredInversionAlpha}`; + state = bold; + } + else + { + callObj.hunting.state = "worked"; + stateConf = `${unconf}${state}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.state) + { + callObj.hunting.state = "mixed"; + stateBg = `${state}${layeredAlpha};`; + state = bold; + } + else if (layeredMode && layeredHash in workedIndex.state) + { + callObj.hunting.state = "mixed-worked"; + stateConf = `${unconf}${state}${layeredAlpha};`; + } + else + { + callObj.hunting.state = "hunted"; + stateBg = `${state}${inversionAlpha};`; + state = bold; + } + } + } + } + } + } + + // Hunting for US Counties + if (huntCounty.checked == true && window.opener.g_callsignLookups.ulsUseEnable == true) + { + var finalDxcc = callObj.dxcc; + if ( + callObj.cnty && + (finalDxcc == 291 || finalDxcc == 110 || finalDxcc == 6 || finalDxcc == 202) && + callObj.cnty.length > 0 + ) + { + var hash = callObj.cnty + (layeredMode ? layeredHashSuffix : workHashSuffix); + + if ((huntIndex && !(hash in huntIndex.cnty)) || callObj.qual == false) + { + if (callObj.qual == false) + { + var counties = window.opener.g_zipToCounty[callObj.zipcode]; + var foundHit = false; + for (var cnt in counties) + { + var hh = counties[cnt] + workHash; + callObj.cnty = counties[cnt]; + if (huntIndex && !(hh in huntIndex.cnty)) + { + foundHit = true; + break; + } + } + if (foundHit) shouldAlert = true; + } + else + { + shouldAlert = true; + } + + if (shouldAlert) + { + callObj.reason.push("cnty"); + + if (workedIndex && hash in workedIndex.cnty) + { + callObj.hunting.cnty = "worked"; + cntyConf = `${unconf}${cnty}${inversionAlpha};`; + } + else + { + callObj.hunting.cnty = "hunted"; + cntyBg = `${cnty}${inversionAlpha}`; + cnty = bold; + } + } + } + } + } + + // Hunting for CQ Zones + if (huntCQz.checked == true) + { + var huntTotal = callObj.cqza.length; + var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; + + for (index in callObj.cqza) + { + var hash = callObj.cqza[index] + workHashSuffix; + var layeredHash = layeredMode && (callObj.cqza[index] + layeredHashSuffix) + + if (huntIndex && hash in huntIndex.cqz) huntFound++; + if (layeredMode && layeredHash in huntIndex.cqz) layeredFound++; + if (workedIndex && hash in workedIndex.cqz) workedFound++; + if (layeredMode && layeredHash in workedIndex.cqz) layeredWorkedFound++; + } + if (huntFound != huntTotal) + { + shouldAlert = true; + callObj.reason.push("cqz"); + + if (workedIndex && workedFound == huntTotal) + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.cqz = "worked-and-mixed"; + cqzConf = `${layeredUnconf}${cqz}${layeredUnconfAlpha};`; + cqzBg = `${cqz}${layeredInversionAlpha}`; + cqz = bold; + } + else + { + callObj.hunting.cqz = "worked"; + cqzConf = `${unconf}${cqz}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.cqz = "mixed"; + cqzBg = `${cqz}${layeredAlpha};`; + cqz = bold; + } + else if (layeredMode && layeredWorkedFound == huntTotal) + { + callObj.hunting.cqz = "mixed-worked"; + cqzConf = `${unconf}${cqz}${layeredAlpha};`; + } + else + { + callObj.hunting.cqz = "hunted"; + cqzBg = `${cqz}${inversionAlpha};`; + cqz = bold; + } + } + } + } + + // Hunting for ITU Zones + if (huntITUz.checked == true) + { + var huntTotal = callObj.ituza.length; + var huntFound = 0, layeredFound = 0, workedFound = 0, layeredWorkedFound = 0; + + for (index in callObj.ituza) + { + var hash = callObj.ituza[index] + workHashSuffix; + var layeredHash = layeredMode && (callObj.ituza[index] + layeredHashSuffix) + + if (huntIndex && hash in huntIndex.ituz) huntFound++; + if (layeredMode && layeredHash in huntIndex.ituz) layeredFound++; + if (workedIndex && hash in workedIndex.ituz) workedFound++; + if (layeredMode && layeredHash in workedIndex.ituz) layeredWorkedFound++; + } + if (huntFound != huntTotal) + { + shouldAlert = true; + callObj.reason.push("ituz"); + + if (workedIndex && workedFound == huntTotal) + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.ituz = "worked-and-mixed"; + ituzConf = `${layeredUnconf}${ituz}${layeredUnconfAlpha};`; + ituzBg = `${ituz}${layeredInversionAlpha}`; + ituz = bold; + } + else + { + callObj.hunting.ituz = "worked"; + ituzConf = `${unconf}${ituz}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredFound == huntTotal) + { + callObj.hunting.ituz = "mixed"; + ituzBg = `${ituz}${layeredAlpha};`; + ituz = bold; + } + else if (layeredMode && layeredWorkedFound == huntTotal) + { + callObj.hunting.ituz = "mixed-worked"; + ituzConf = `${unconf}${ituz}${layeredAlpha};`; + } + else + { + callObj.hunting.ituz = "hunted"; + ituzBg = `${ituz}${inversionAlpha};`; + ituz = bold; + } + } + } + } + + // Hunting for WPX (Prefixes) + if (huntPX.checked == true && callObj.px) + { + var hash = String(callObj.px) + workHashSuffix; + var layeredHash = layeredMode && (String(callObj.px) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.px)) + { + shouldAlert = true; + + callObj.reason.push("wpx"); + + if (workedIndex && hash in workedIndex.px) + { + if (layeredMode && layeredHash in huntIndex.px) + { + callObj.hunting.wpx = "worked-and-mixed"; + wpxConf = `${layeredUnconf}${wpx}${layeredUnconfAlpha};`; + wpxBg = `${wpx}${layeredInversionAlpha}`; + wpx = bold; + } + else + { + callObj.hunting.wpx = "worked"; + wpxConf = `${unconf}${wpx}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.px) + { + callObj.hunting.wpx = "mixed"; + wpxBg = `${wpx}${layeredAlpha};`; + wpx = bold; + } + else if (layeredMode && layeredHash in workedIndex.px) + { + callObj.hunting.wpx = "mixed-worked"; + wpxConf = `${unconf}${wpx}${layeredAlpha};`; + } + else + { + callObj.hunting.wpx = "hunted"; + wpxBg = `${wpx}${inversionAlpha};`; + wpx = bold; + } + } + } + } + + // Hunting for Continents + if (huntCont.checked == true && callObj.cont) + { + var hash = String(callObj.cont) + workHashSuffix; + var layeredHash = layeredMode && (String(callObj.cont) + layeredHashSuffix) + + if (huntIndex && !(hash in huntIndex.cont)) + { + shouldAlert = true; + + callObj.reason.push("cont"); + + if (workedIndex && hash in workedIndex.cont) + { + if (layeredMode && layeredHash in huntIndex.cont) + { + callObj.hunting.cont = "worked-and-mixed"; + contConf = `${layeredUnconf}${cont}${layeredUnconfAlpha};`; + contBg = `${cont}${layeredInversionAlpha}`; + cont = bold; + } + else + { + callObj.hunting.cont = "worked"; + contConf = `${unconf}${cont}${inversionAlpha};`; + } + } + else + { + if (layeredMode && layeredHash in huntIndex.cont) + { + callObj.hunting.cont = "mixed"; + contBg = `${cont}${layeredAlpha};`; + cont = bold; + } + else if (layeredMode && layeredHash in workedIndex.cont) + { + callObj.hunting.cont = "mixed-worked"; + contConf = `${unconf}${cont}${layeredAlpha};`; + } + else + { + callObj.hunting.cont = "hunted"; + contBg = `${cont}${inversionAlpha};`; + cont = bold; + } + } + } + } + } + + // Station is calling us + if (callObj.DXcall == window.opener.myDEcall) + { + callingBg = "#0000FF" + inversionAlpha; + calling = "#FFFF00;text-shadow: 0px 0px 2px #FFFF00"; + } + else if (callObj.CQ == true && g_rosterSettings.cqOnly == false) + { + callingBg = calling + inversionAlpha; + calling = bold; + } + + // Assemble all styles + colorObject.call = "style='" + callConf + "background-color:" + callBg + ";color:" + + call + ";" + callPointer + "'"; + colorObject.grid = "style='" + gridConf + "background-color:" + gridBg + ";color:" + grid + ";cursor:pointer'"; + colorObject.calling = "style='" + callingConf + "background-color:" + callingBg + ";color:" + calling + "'"; + colorObject.dxcc = "style='" + dxccConf + "background-color:" + dxccBg + ";color:" + dxcc + "'"; + colorObject.state = "style='" + stateConf + "background-color:" + stateBg + ";color:" + state + "'"; + colorObject.cnty = "style='" + cntyConf + "background-color:" + cntyBg + ";color:" + cnty + "'"; + colorObject.cont = "style='" + contConf + "background-color:" + contBg + ";color:" + cont + "'"; + colorObject.cqz = "style='" + cqzConf + "background-color:" + cqzBg + ";color:" + cqz + "'"; + colorObject.ituz = "style='" + ituzConf + "background-color:" + ituzBg + ";color:" + ituz + "'"; + colorObject.px = "style='" + wpxConf + "background-color:" + wpxBg + ";color:" + wpx + "'"; + + // Just in case, don't alert if we worked this callsign alread + if (didWork && shouldAlert) shouldAlert = false; + + callObj.shouldAlert = shouldAlert; + + callObj.style = colorObject; + + if (g_rosterSettings.columns.Spot) + { + callObj.spot = window.opener.getSpotTime( + callObj.DEcall + callObj.mode + callObj.band + callObj.grid + ); + if (callObj.spot == null) + { + callObj.spot = { when: 0, snr: 0 }; + } + } + else + { + callObj.spot = { when: 0, snr: 0 }; + } + + modes[callObj.mode] = true; + bands[callObj.band] = true; + } + } +} diff --git a/package.nw/lib/roster/renderCompactRoster.js b/package.nw/lib/roster/renderCompactRoster.js new file mode 100644 index 0000000..271a0bc --- /dev/null +++ b/package.nw/lib/roster/renderCompactRoster.js @@ -0,0 +1,55 @@ +function renderCompactRosterHeaders() +{ + return "
"; +} + +function renderCompactRosterRow(callObj) +{ + var thisCall = callObj.DEcall; + var tt = + callObj.RSTsent + + "㏈, " + + parseInt(callObj.dt * 100) + + "ms, " + + callObj.delta + + "hz" + + (callObj.grid.length ? ", " + callObj.grid : "") + + ", " + + (timeNowSec() - callObj.age).toDHMS(); + worker += + "
"; + worker += + "
" + + thisCall.formatCallsign() + + "
"; + worker += + "
" + + window.opener.g_dxccToAltName[callObj.dxcc] + + "
"; + worker += "
"; + + return worker; +} + +function renderCompactRosterFooter() +{ + return "
"; +} diff --git a/package.nw/lib/roster/renderNormalRoster.js b/package.nw/lib/roster/renderNormalRoster.js new file mode 100644 index 0000000..80fa5a8 --- /dev/null +++ b/package.nw/lib/roster/renderNormalRoster.js @@ -0,0 +1,400 @@ +function renderNormalRosterHeaders() +{ + var worker = "" + worker = ""; + + worker += ""; + + if (showBands) + { worker += ""; } + + if (showModes) + { worker += ""; } + + worker += ""; + + if (g_rosterSettings.columns.Calling) + { worker += ""; } + + if (g_rosterSettings.columns.Msg) + { worker += ""; } + + if (g_rosterSettings.columns.DXCC) + { worker += ""; } + + if (g_rosterSettings.columns.Flag) + { worker += ""; } + + if (g_rosterSettings.columns.State) + { worker += ""; } + + if (g_rosterSettings.columns.County) + { worker += ""; } + + if (g_rosterSettings.columns.Cont) + { worker += ""; } + + if (g_rosterSettings.columns.dB) + { worker += ""; } + + if (g_rosterSettings.columns.Freq) + { worker += ""; } + + if (g_rosterSettings.columns.DT) + { worker += ""; } + + if (g_rosterSettings.columns.Dist) + { + worker += ""; + } + + if (g_rosterSettings.columns.Azim) + { worker += ""; } + + if (g_rosterSettings.columns.CQz) + { worker += ""; } + + if (g_rosterSettings.columns.ITUz) + { worker += ""; } + + if (g_rosterSettings.columns.PX) + { worker += ""; } + + if (window.opener.g_callsignLookups.lotwUseEnable == true && g_rosterSettings.columns.LoTW) + { worker += ""; } + + if (window.opener.g_callsignLookups.eqslUseEnable == true && g_rosterSettings.columns.eQSL) + { worker += ""; } + + if (window.opener.g_callsignLookups.oqrsUseEnable == true && g_rosterSettings.columns.OQRS) + { worker += ""; } + + if (g_rosterSettings.columns.Spot) + { worker += ""; } + + if (g_rosterSettings.columns.Life) + { worker += ""; } + + if (g_rosterSettings.columns.OAMS) + { worker += ""; } + + if (g_rosterSettings.columns.Age) + { worker += ""; } + + return worker +} + +function renderNormalRosterRow(callObj) +{ + var thisCall = callObj.DEcall; + var acks = window.opener.g_acknowledgedCalls; + + var thisHash = thisCall + callObj.band + callObj.mode; + var callStr = thisCall.formatCallsign() + if (acks[thisCall]) + { + callStr = `${callStr} ` + callObj.awardReason += ` - ${acks[thisCall].message}` + } + + var worker = ""; + worker += + ""; + + if (showBands) + { + worker += + ""; + } + if (showModes) + { + var color = "888888"; + if (callObj.mode in g_modeColors) + { color = g_modeColors[callObj.mode]; } + worker += + ""; + } + + worker += + ""; + if (g_rosterSettings.columns.Calling) + { + var lookString = callObj.CQ ? "name='CQ'" : "name='Calling'"; + worker += + ""; + } + if (g_rosterSettings.columns.Msg) + { worker += ""; } + + if (g_rosterSettings.columns.DXCC) + { + worker += + ""; + } + if (g_rosterSettings.columns.Flag) + { + worker += + ""; + } + if (g_rosterSettings.columns.State) + { + worker += + ""; + } + if (g_rosterSettings.columns.County) + { + worker += + ""; + } + if (g_rosterSettings.columns.Cont) + { + worker += + ""; + } + + if (g_rosterSettings.columns.dB) + { + worker += + ""; + } + if (g_rosterSettings.columns.Freq) + { worker += ""; } + if (g_rosterSettings.columns.DT) + { worker += ""; } + if (g_rosterSettings.columns.Dist) + { + worker += + ""; + } + if (g_rosterSettings.columns.Azim) + { + worker += + ""; + } + + if (g_rosterSettings.columns.CQz) + { + worker += + ""; + } + if (g_rosterSettings.columns.ITUz) + { + worker += + ""; + } + + if (g_rosterSettings.columns.PX) + { + worker += + ""; + } + + if ( + window.opener.g_callsignLookups.lotwUseEnable == true && + g_rosterSettings.columns.LoTW + ) + { + if (thisCall in window.opener.g_lotwCallsigns) + { + if (g_rosterSettings.maxLoTW < 27) + { + var months = (g_day - window.opener.g_lotwCallsigns[thisCall]) / 30; + if (months > g_rosterSettings.maxLoTW) + { + worker += + ""; + } + else + { + worker += + ""; + } + } + else + { + worker += + ""; + } + } + else worker += ""; + } + if ( + window.opener.g_callsignLookups.eqslUseEnable == true && + g_rosterSettings.columns.eQSL + ) + { + worker += + ""; + } + if ( + window.opener.g_callsignLookups.oqrsUseEnable == true && + g_rosterSettings.columns.OQRS + ) + { + worker += + ""; + } + + if (g_rosterSettings.columns.Spot) + { + worker += + ""; + } + if (g_rosterSettings.columns.Life) + { + worker += + ""; + } + + if (g_rosterSettings.columns.OAMS) + { + if (callObj.style.gt != 0) + { + if (callObj.reason.includes("oams")) + { + worker += + ""; + } + else + { + worker += + ""; + } + } + else worker += ""; + } + + if (g_rosterSettings.columns.Age) + { + worker += + ""; + } + + worker += ""; + + return worker; +} + +function renderNormalRosterFooter() +{ + return "
CallsignBandModeGridCallingMsgDXCCFlagStateCountyContdBFreqDTDist(" + + window.opener.distanceUnit.value.toLowerCase() + ")AzimCQzITUzPXLoTWeQSLOQRSSpotLifeOAMSAge
" + + callStr + + "" + + callObj.band + + "" + callObj.mode + "" + + grid + + "" + + callObj.DXcall.formatCallsign() + + "" + callObj.msg + "" + + window.opener.g_dxccToAltName[callObj.dxcc] + "" + + (callObj.state ? callObj.state.substr(3) : "") + + "" + + (callObj.cnty + ? (callObj.qual ? "" : "~ ") + + window.opener.g_cntyToCounty[callObj.cnty] + + (callObj.qual ? "" : " ~") + : "") + + "" + + (callObj.cont ? callObj.cont : "") + + "" + + callObj.RSTsent + + "" + callObj.delta + "" + callObj.dt + "" + + parseInt( + callObj.distance * + MyCircle.validateRadius(window.opener.distanceUnit.value) + ) + + "" + + parseInt(callObj.heading) + + "" + + callObj.cqza.join(",") + + "" + + callObj.ituza.join(",") + + "" + + (callObj.px ? callObj.px : "") + + "?" + + (thisCall in window.opener.g_eqslCallsigns ? "✔" : "") + + "" + + (thisCall in window.opener.g_oqrsCallsigns ? "✔" : "") + + "" + + spotString + + "" + + (timeNowSec() - callObj.life).toDHMS() + + "" + + (timeNowSec() - callObj.age).toDHMS() + + "
"; +} diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js new file mode 100644 index 0000000..20f4be9 --- /dev/null +++ b/package.nw/lib/roster/renderRoster.js @@ -0,0 +1,102 @@ +function renderRoster(callRoster, rosterSettings) +{ + // eQSL - function + if (window.opener.g_callsignLookups.eqslUseEnable == true) useseQSLDiv.style.display = ""; + else useseQSLDiv.style.display = "none"; + + // OQRS - function + if (window.opener.g_callsignLookups.oqrsUseEnable == true) usesOQRSDiv.style.display = ""; + else usesOQRSDiv.style.display = "none"; + + // dealing with spots + if (g_rosterSettings.columns.Spot == true) onlySpotDiv.style.display = ""; + else onlySpotDiv.style.display = "none"; + + // callmode (all or only new) + if (rosterSettings.callMode == "all") allOnlyNewDiv.style.display = ""; + else allOnlyNewDiv.style.display = "none"; + + // Show the roster count in the window title + + var visibleCallList = callRoster.filter(entry => entry.tx); + + var totalCount = Object.keys(callRoster).length; + var visibleCount = visibleCallList.length; + var huntedCount = visibleCallList.filter(obj => Object.keys(obj.hunting).length > 0).length + var countParts = []; + + if (totalCount != visibleCount) + { + countParts.push(`${totalCount} heard`); + } + + countParts.push(`${visibleCount} in roster`); + + if (huntedCount != visibleCount) + { + countParts.push(`${huntedCount} wanted`); + } + + window.document.title = `Call Roster: ${countParts.join(" • ")}`; + + if (g_rosterSettings.compact == false) + { + visibleCallList.sort(r_sortFunction[g_rosterSettings.lastSortIndex]); + if (g_rosterSettings.lastSortReverse == 1) + { + visibleCallList.reverse(); + } + } + else + { + // Age sort for now... make this happen Tag + visibleCallList.sort(r_sortFunction[6]).reverse(); + } + + var showBands = (Object.keys(rosterSettings.bands).length > 1) || g_rosterSettings.columns.Band; + var showModes = (Object.keys(rosterSettings.modes).length > 1) || g_rosterSettings.columns.Mode; + + var worker = g_rosterSettings.compact ? renderCompactRosterHeaders() : renderNormalRosterHeaders() + + // Third loop: render all rows + for (var x in visibleCallList) + { + var callObj = visibleCallList[x]; + + // TODO: This is filtering + if (callObj.shouldAlert == false && onlyHits == true && callObj.qrz == false) + { continue; } + + var spotString = ""; + if (g_rosterSettings.columns.Spot && callObj.qrz == false) + { + spotString = getSpotString(callObj); + // TODO: This is filtering + if (g_rosterSettings.onlySpot && spotString == "") continue; + } + var grid = callObj.grid.length > 1 ? callObj.grid.substr(0, 4) : "-"; + + var geo = window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]]; + var cqzone = grid in window.opener.g_gridToCQZone ? window.opener.g_gridToCQZone[grid].join(", ") : "-"; + var ituzone = grid in window.opener.g_gridToITUZone ? window.opener.g_gridToITUZone[grid].join(", ") : "-"; + var thisCall = callObj.DEcall; + + if (thisCall.match("^[A-Z][0-9][A-Z](/w+)?$")) + { callObj.style.call = "class='oneByOne'"; } + if (thisCall == window.opener.g_instances[callObj.instance].status.DXcall) + { + if (window.opener.g_instances[callObj.instance].status.TxEnabled == 1) + { + callObj.style.call = "class='dxCalling'"; + } + else + { + callObj.style.call = "class='dxCaller'"; + } + } + + worker += g_rosterSettings.compact ? renderCompactRosterRow(callObj) : renderNormalRosterRow(callObj) + } + + RosterTable.innerHTML = g_rosterSettings.compact ? renderCompactRosterFooter() : renderNormalRosterFooter() +} diff --git a/package.nw/lib/roster/sendAlerts.js b/package.nw/lib/roster/sendAlerts.js new file mode 100644 index 0000000..ab814f1 --- /dev/null +++ b/package.nw/lib/roster/sendAlerts.js @@ -0,0 +1,135 @@ +function sendAlerts(callRoster, rosterSettings) +{ + var dirPath = window.opener.g_scriptDir; + var scriptExists = false; + var script = "cr-alert.sh"; + + var shouldAlert = 0; + + for (var callObj in callRoster) + { if (!callObj.tx) continue } + + // TODO: Get rid of realtime + if (g_rosterSettings.realtime == false) + { + var call = callObj.DEcall; + g_scriptReport[call] = Object.assign({}, callObj); + g_scriptReport[call].dxccName = + window.opener.g_dxccToAltName[callObj.dxcc]; + g_scriptReport[call].distance = parseInt( + callObj.distance * + MyCircle.validateRadius(window.opener.distanceUnit.value) + ); + + delete g_scriptReport[call].DEcall; + g_scriptReport[call].rect = null; + delete g_scriptReport[call].rect; + delete g_scriptReport[call].style; + delete g_scriptReport[call].wspr; + delete g_scriptReport[call].qso; + delete g_scriptReport[call].instance; + + if (callMode != "all") + { + g_scriptReport[call].shouldAlert = true; + g_scriptReport[call].reason.push(g_rosterSettings.hunting); + } + } + + if ( + callObj.alerted == false && + callMode == "all" && + callObj.shouldAlert == true + ) + { + callObj.alerted = true; + shouldAlert++; + } + else if (callObj.alerted == false && callMode != "all") + { + callObj.alerted = true; + shouldAlert++; + } + + callObj.shouldAlert = false; +} + +// NOTE: Ring alerts if needed +try +{ + if (fs.existsSync(dirPath)) + { + if (window.opener.g_platform == "windows") + { + script = "cr-alert.bat"; + } + if ( + fs.existsSync(dirPath + script) && + g_rosterSettings.realtime == false + ) + { + scriptExists = true; + scriptIcon.innerHTML = + "
" + + (window.opener.g_crScript == 1 + ? "Script Enabled" + : "Script Disabled") + + "
"; + scriptIcon.style.display = "block"; + } + else + { + scriptIcon.style.display = "none"; + } + } +} +catch (e) {} + +if (shouldAlert > 0) +{ + if (window.opener.g_classicAlerts.huntRoster == true) + { + var notify = window.opener.huntRosterNotify.value; + if (notify == "0") + { + var media = window.opener.huntRosterNotifyMedia.value; + if (media != "none") window.opener.playAlertMediaFile(media); + } + else if (notify == "1") + { + window.opener.speakAlertString( + window.opener.huntRosterNotifyWord.value + ); + } + } + + if ( + g_rosterSettings.realtime == false && + scriptExists && + window.opener.g_crScript == 1 + ) + { + try + { + fs.writeFileSync( + dirPath + "cr-alert.json", + JSON.stringify(g_scriptReport, null, 2) + ); + + var thisProc = dirPath + script; + var cp = require("child_process"); + var child = cp.spawn(thisProc, [], { + detached: true, + cwd: dirPath.slice(0, -1), + stdio: ["ignore", "ignore", "ignore"] + }); + child.unref(); + } + catch (e) + { + conosle.log(e); + } + g_scriptReport = Object(); + } + else g_scriptReport = Object(); +} From 7c7baef4c6e6cac214e4f9fe992e03ed6b6676cc Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 19:19:26 -0500 Subject: [PATCH 026/125] refactor so far --- package.nw/gt_roster.html | 7 ++ package.nw/lib/roster.js | 52 ------------- package.nw/lib/roster/sendAlerts.js | 116 ++++++++++++++-------------- 3 files changed, 65 insertions(+), 110 deletions(-) diff --git a/package.nw/gt_roster.html b/package.nw/gt_roster.html index 7cbc9f8..3909386 100644 --- a/package.nw/gt_roster.html +++ b/package.nw/gt_roster.html @@ -22,6 +22,13 @@ + + + + + + + diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index d7997f6..8ce9b2e 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -369,58 +369,6 @@ function myGTCompare(a, b) return 0; } -var r_sortFunction = [ - myCallCompare, - myGridCompare, - myDbCompare, - myDTCompare, - myFreqCompare, - myDxccCompare, - myTimeCompare, - myDistanceCompare, - myHeadingCompare, - myStateCompare, - myCQCompare, - myWPXCompare, - myLifeCompare, - mySpotCompare, - myGTCompare, - myCntyCompare, - myContCompare -]; - -var r_excptTest = [ - timeChk, - crEnable, - blockedCall, - blockedFrom, - blcokedDXCC, - cqOnly, - useRegex, - reqGrid, - minDB, - maxDT, - minFreq, - maxFreq, - noMsg, - onlyMesg, - myDXCC, - lotwUse, - eqslUse, - oqrsUse, - noMyCQDX, - callWorked, - callConfirmed, - huntGrid, - huntDXCC, - huntDXCCs, - huntWPX, - huntCQ, - huntITU, - huntUSStates, - huntUSState -]; - function showRosterBox(sortIndex) { if (g_rosterSettings.lastSortIndex != sortIndex) diff --git a/package.nw/lib/roster/sendAlerts.js b/package.nw/lib/roster/sendAlerts.js index ab814f1..7dcfa0f 100644 --- a/package.nw/lib/roster/sendAlerts.js +++ b/package.nw/lib/roster/sendAlerts.js @@ -52,84 +52,84 @@ function sendAlerts(callRoster, rosterSettings) } callObj.shouldAlert = false; -} -// NOTE: Ring alerts if needed -try -{ - if (fs.existsSync(dirPath)) + // NOTE: Ring alerts if needed + try { - if (window.opener.g_platform == "windows") + if (fs.existsSync(dirPath)) { - script = "cr-alert.bat"; - } - if ( - fs.existsSync(dirPath + script) && + if (window.opener.g_platform == "windows") + { + script = "cr-alert.bat"; + } + if ( + fs.existsSync(dirPath + script) && g_rosterSettings.realtime == false - ) - { - scriptExists = true; - scriptIcon.innerHTML = + ) + { + scriptExists = true; + scriptIcon.innerHTML = "
" + (window.opener.g_crScript == 1 ? "Script Enabled" : "Script Disabled") + "
"; - scriptIcon.style.display = "block"; - } - else - { - scriptIcon.style.display = "none"; + scriptIcon.style.display = "block"; + } + else + { + scriptIcon.style.display = "none"; + } } } -} -catch (e) {} + catch (e) {} -if (shouldAlert > 0) -{ - if (window.opener.g_classicAlerts.huntRoster == true) + if (shouldAlert > 0) { - var notify = window.opener.huntRosterNotify.value; - if (notify == "0") + if (window.opener.g_classicAlerts.huntRoster == true) { - var media = window.opener.huntRosterNotifyMedia.value; - if (media != "none") window.opener.playAlertMediaFile(media); + var notify = window.opener.huntRosterNotify.value; + if (notify == "0") + { + var media = window.opener.huntRosterNotifyMedia.value; + if (media != "none") window.opener.playAlertMediaFile(media); + } + else if (notify == "1") + { + window.opener.speakAlertString( + window.opener.huntRosterNotifyWord.value + ); + } } - else if (notify == "1") - { - window.opener.speakAlertString( - window.opener.huntRosterNotifyWord.value - ); - } - } - if ( - g_rosterSettings.realtime == false && + if ( + g_rosterSettings.realtime == false && scriptExists && window.opener.g_crScript == 1 - ) - { - try + ) { - fs.writeFileSync( - dirPath + "cr-alert.json", - JSON.stringify(g_scriptReport, null, 2) - ); + try + { + fs.writeFileSync( + dirPath + "cr-alert.json", + JSON.stringify(g_scriptReport, null, 2) + ); - var thisProc = dirPath + script; - var cp = require("child_process"); - var child = cp.spawn(thisProc, [], { - detached: true, - cwd: dirPath.slice(0, -1), - stdio: ["ignore", "ignore", "ignore"] - }); - child.unref(); + var thisProc = dirPath + script; + var cp = require("child_process"); + var child = cp.spawn(thisProc, [], { + detached: true, + cwd: dirPath.slice(0, -1), + stdio: ["ignore", "ignore", "ignore"] + }); + child.unref(); + } + catch (e) + { + conosle.log(e); + } + g_scriptReport = Object(); } - catch (e) - { - conosle.log(e); - } - g_scriptReport = Object(); + else g_scriptReport = Object(); } - else g_scriptReport = Object(); } From 26a1b513c2268d147b19744140f4a444d421c29c Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 20:42:07 -0500 Subject: [PATCH 027/125] fixed a bunch of broken refs to rosterSettings --- .../lib/roster/processRosterFiltering.js | 10 +- package.nw/lib/roster/processRosterHunting.js | 128 +++++++++--------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/package.nw/lib/roster/processRosterFiltering.js b/package.nw/lib/roster/processRosterFiltering.js index 9c41142..c593651 100644 --- a/package.nw/lib/roster/processRosterFiltering.js +++ b/package.nw/lib/roster/processRosterFiltering.js @@ -14,7 +14,7 @@ function processRosterFiltering(callRoster, rosterSettings) callObj.reason = Array(); callObj.awardReason = "Callsign"; - if (now - callObj.age > window.opener.g_mapSettings.rosterTime) + if (rosterSettings.now - callObj.age > window.opener.g_mapSettings.rosterTime) { entry.tx = false; entry.alerted = false; @@ -166,7 +166,7 @@ function processRosterFiltering(callRoster, rosterSettings) } } - if (callMode != "all") + if (rosterSettings.callMode != "all") { if (entry.DXcall == "CQ DX" && callObj.dxcc == window.opener.g_myDXCC) { @@ -175,12 +175,12 @@ function processRosterFiltering(callRoster, rosterSettings) } var hash = hashMaker(call, callObj, g_rosterSettings.reference); - if (callMode == "worked" && hash in g_worked.call) + if (rosterSettings.callMode == "worked" && hash in g_worked.call) { entry.tx = false; continue; } - if (callMode == "confirmed" && hash in g_confirmed.call) + if (rosterSettings.callMode == "confirmed" && hash in g_confirmed.call) { entry.tx = false; continue; @@ -338,7 +338,7 @@ function processRosterFiltering(callRoster, rosterSettings) continue; } } - if (isAwardTracker) + if (rosterSettings.isAwardTracker) { var tx = false; var baseHash = hashMaker("", callObj, g_rosterSettings.reference); diff --git a/package.nw/lib/roster/processRosterHunting.js b/package.nw/lib/roster/processRosterHunting.js index 6adaeab..ded6a15 100644 --- a/package.nw/lib/roster/processRosterHunting.js +++ b/package.nw/lib/roster/processRosterHunting.js @@ -46,9 +46,9 @@ function processRosterHunting(callRoster, rosterSettings) // In layered mode ("Hunting: mixed") the workHashSuffix becomes a more stricter 'live band', // while the layered suffix is a broader 'mixed band' var workHashSuffix, layeredHashSuffix; - if (layeredMode) + if (rosterSettings.layeredMode) { - workHashSuffix = hashMaker("", callObj, layeredMode); + workHashSuffix = hashMaker("", callObj, rosterSettings.layeredMode); layeredHashSuffix = hashMaker("", callObj, g_rosterSettings.reference); } else @@ -128,7 +128,7 @@ function processRosterHunting(callRoster, rosterSettings) // We only do hunt highlighting when showing all entries // This means "Callsigns: All Traffic", "Callsigns: All Traffic/Only Wanted" and "Logbook: Award Tracker" // There is no highlighting in other modes - if (callMode == "all") + if (rosterSettings.callMode == "all") { // Skip when "only new calls" // Questions: Move to the first loop? Why only skip new calls in "all traffic" and not other modes? @@ -142,17 +142,17 @@ function processRosterHunting(callRoster, rosterSettings) if (huntCallsign.checked == true) { var hash = callsign + workHashSuffix; - var layeredHash = layeredMode && (callsign + layeredHashSuffix) + var layeredHash = rosterSettings.layeredMode && (callsign + layeredHashSuffix) - if (huntIndex && !(hash in huntIndex.call)) + if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.call)) { shouldAlert = true; callObj.reason.push("call"); - if (workedIndex && hash in workedIndex.call) + if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.call) { - if (layeredMode && layeredHash in huntIndex.call) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.call) { callObj.hunting.call = "worked-and-mixed"; callConf = `${layeredUnconf}${call}${layeredUnconfAlpha};`; @@ -164,7 +164,7 @@ function processRosterHunting(callRoster, rosterSettings) // * so we cannot cover this particular combination // * and have to default to just showing it as plain "worked" // */ - // else if (layeredMode && layeredHash in workedIndex.call) + // else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.call) // { // callObj.hunting.call = "worked-and-mixed-worked"; // callConf = `${layeredUnconf}${call}${layeredAlpha};`; @@ -177,13 +177,13 @@ function processRosterHunting(callRoster, rosterSettings) } else { - if (layeredMode && layeredHash in huntIndex.call) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.call) { callObj.hunting.call = "mixed"; callBg = `${call}${layeredAlpha};`; call = bold; } - else if (layeredMode && layeredHash in workedIndex.call) + else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.call) { callObj.hunting.call = "mixed-worked"; callConf = `${unconf}${call}${layeredAlpha};`; @@ -218,17 +218,17 @@ function processRosterHunting(callRoster, rosterSettings) if (huntGrid.checked == true && callObj.grid.length > 1) { var hash = callObj.grid.substr(0, 4) + workHashSuffix; - var layeredHash = layeredMode && (callObj.grid.substr(0, 4) + layeredHashSuffix) + var layeredHash = rosterSettings.layeredMode && (callObj.grid.substr(0, 4) + layeredHashSuffix) - if (huntIndex && !(hash in huntIndex.grid)) + if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.grid)) { shouldAlert = true; callObj.reason.push("grid"); - if (workedIndex && hash in workedIndex.grid) + if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.grid) { - if (layeredMode && layeredHash in huntIndex.grid) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.grid) { callObj.hunting.grid = "worked-and-mixed"; gridConf = `${layeredUnconf}${grid}${layeredUnconfAlpha};`; @@ -243,13 +243,13 @@ function processRosterHunting(callRoster, rosterSettings) } else { - if (layeredMode && layeredHash in huntIndex.grid) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.grid) { callObj.hunting.grid = "mixed"; gridBg = `${grid}${layeredAlpha};`; grid = bold; } - else if (layeredMode && layeredHash in workedIndex.grid) + else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.grid) { callObj.hunting.grid = "mixed-worked"; gridConf = `${unconf}${grid}${layeredAlpha};`; @@ -268,17 +268,17 @@ function processRosterHunting(callRoster, rosterSettings) if (huntDXCC.checked == true) { var hash = String(callObj.dxcc) + workHashSuffix; - var layeredHash = layeredMode && (String(callObj.dxcc) + layeredHashSuffix) + var layeredHash = rosterSettings.layeredMode && (String(callObj.dxcc) + layeredHashSuffix) - if (huntIndex && !(hash in huntIndex.dxcc)) + if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.dxcc)) { shouldAlert = true; callObj.reason.push("dxcc"); - if (workedIndex && hash in workedIndex.dxcc) + if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.dxcc) { - if (layeredMode && layeredHash in huntIndex.dxcc) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.dxcc) { callObj.hunting.dxcc = "worked-and-mixed"; dxccConf = `${layeredUnconf}${dxcc}${layeredUnconfAlpha};`; @@ -293,13 +293,13 @@ function processRosterHunting(callRoster, rosterSettings) } else { - if (layeredMode && layeredHash in huntIndex.dxcc) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.dxcc) { callObj.hunting.dxcc = "mixed"; dxccBg = `${dxcc}${layeredAlpha};`; dxcc = bold; } - else if (layeredMode && layeredHash in workedIndex.dxcc) + else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.dxcc) { callObj.hunting.dxcc = "mixed-worked"; dxccConf = `${unconf}${dxcc}${layeredAlpha};`; @@ -324,17 +324,17 @@ function processRosterHunting(callRoster, rosterSettings) if (stateSearch in window.opener.g_StateData) { var hash = stateSearch + workHashSuffix; - var layeredHash = layeredMode && (stateSearch + layeredHashSuffix) + var layeredHash = rosterSettings.layeredMode && (stateSearch + layeredHashSuffix) - if (huntIndex && !(hash in huntIndex.state)) + if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.state)) { shouldAlert = true; callObj.reason.push("state"); - if (workedIndex && hash in workedIndex.state) + if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.state) { - if (layeredMode && layeredHash in huntIndex.state) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.state) { callObj.hunting.state = "worked-and-mixed"; stateConf = `${layeredUnconf}${state}${layeredUnconfAlpha};`; @@ -349,13 +349,13 @@ function processRosterHunting(callRoster, rosterSettings) } else { - if (layeredMode && layeredHash in huntIndex.state) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.state) { callObj.hunting.state = "mixed"; stateBg = `${state}${layeredAlpha};`; state = bold; } - else if (layeredMode && layeredHash in workedIndex.state) + else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.state) { callObj.hunting.state = "mixed-worked"; stateConf = `${unconf}${state}${layeredAlpha};`; @@ -382,9 +382,9 @@ function processRosterHunting(callRoster, rosterSettings) callObj.cnty.length > 0 ) { - var hash = callObj.cnty + (layeredMode ? layeredHashSuffix : workHashSuffix); + var hash = callObj.cnty + (rosterSettings.layeredMode ? layeredHashSuffix : workHashSuffix); - if ((huntIndex && !(hash in huntIndex.cnty)) || callObj.qual == false) + if ((rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.cnty)) || callObj.qual == false) { if (callObj.qual == false) { @@ -394,7 +394,7 @@ function processRosterHunting(callRoster, rosterSettings) { var hh = counties[cnt] + workHash; callObj.cnty = counties[cnt]; - if (huntIndex && !(hh in huntIndex.cnty)) + if (rosterSettings.huntIndex && !(hh in rosterSettings.huntIndex.cnty)) { foundHit = true; break; @@ -411,7 +411,7 @@ function processRosterHunting(callRoster, rosterSettings) { callObj.reason.push("cnty"); - if (workedIndex && hash in workedIndex.cnty) + if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.cnty) { callObj.hunting.cnty = "worked"; cntyConf = `${unconf}${cnty}${inversionAlpha};`; @@ -436,21 +436,21 @@ function processRosterHunting(callRoster, rosterSettings) for (index in callObj.cqza) { var hash = callObj.cqza[index] + workHashSuffix; - var layeredHash = layeredMode && (callObj.cqza[index] + layeredHashSuffix) + var layeredHash = rosterSettings.layeredMode && (callObj.cqza[index] + layeredHashSuffix) - if (huntIndex && hash in huntIndex.cqz) huntFound++; - if (layeredMode && layeredHash in huntIndex.cqz) layeredFound++; - if (workedIndex && hash in workedIndex.cqz) workedFound++; - if (layeredMode && layeredHash in workedIndex.cqz) layeredWorkedFound++; + if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.cqz) huntFound++; + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.cqz) layeredFound++; + if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.cqz) workedFound++; + if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.cqz) layeredWorkedFound++; } if (huntFound != huntTotal) { shouldAlert = true; callObj.reason.push("cqz"); - if (workedIndex && workedFound == huntTotal) + if (rosterSettings.workedIndex && workedFound == huntTotal) { - if (layeredMode && layeredFound == huntTotal) + if (rosterSettings.layeredMode && layeredFound == huntTotal) { callObj.hunting.cqz = "worked-and-mixed"; cqzConf = `${layeredUnconf}${cqz}${layeredUnconfAlpha};`; @@ -465,13 +465,13 @@ function processRosterHunting(callRoster, rosterSettings) } else { - if (layeredMode && layeredFound == huntTotal) + if (rosterSettings.layeredMode && layeredFound == huntTotal) { callObj.hunting.cqz = "mixed"; cqzBg = `${cqz}${layeredAlpha};`; cqz = bold; } - else if (layeredMode && layeredWorkedFound == huntTotal) + else if (rosterSettings.layeredMode && layeredWorkedFound == huntTotal) { callObj.hunting.cqz = "mixed-worked"; cqzConf = `${unconf}${cqz}${layeredAlpha};`; @@ -495,21 +495,21 @@ function processRosterHunting(callRoster, rosterSettings) for (index in callObj.ituza) { var hash = callObj.ituza[index] + workHashSuffix; - var layeredHash = layeredMode && (callObj.ituza[index] + layeredHashSuffix) + var layeredHash = rosterSettings.layeredMode && (callObj.ituza[index] + layeredHashSuffix) - if (huntIndex && hash in huntIndex.ituz) huntFound++; - if (layeredMode && layeredHash in huntIndex.ituz) layeredFound++; - if (workedIndex && hash in workedIndex.ituz) workedFound++; - if (layeredMode && layeredHash in workedIndex.ituz) layeredWorkedFound++; + if (rosterSettings.huntIndex && hash in rosterSettings.huntIndex.ituz) huntFound++; + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.ituz) layeredFound++; + if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.ituz) workedFound++; + if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.ituz) layeredWorkedFound++; } if (huntFound != huntTotal) { shouldAlert = true; callObj.reason.push("ituz"); - if (workedIndex && workedFound == huntTotal) + if (rosterSettings.workedIndex && workedFound == huntTotal) { - if (layeredMode && layeredFound == huntTotal) + if (rosterSettings.layeredMode && layeredFound == huntTotal) { callObj.hunting.ituz = "worked-and-mixed"; ituzConf = `${layeredUnconf}${ituz}${layeredUnconfAlpha};`; @@ -524,13 +524,13 @@ function processRosterHunting(callRoster, rosterSettings) } else { - if (layeredMode && layeredFound == huntTotal) + if (rosterSettings.layeredMode && layeredFound == huntTotal) { callObj.hunting.ituz = "mixed"; ituzBg = `${ituz}${layeredAlpha};`; ituz = bold; } - else if (layeredMode && layeredWorkedFound == huntTotal) + else if (rosterSettings.layeredMode && layeredWorkedFound == huntTotal) { callObj.hunting.ituz = "mixed-worked"; ituzConf = `${unconf}${ituz}${layeredAlpha};`; @@ -549,17 +549,17 @@ function processRosterHunting(callRoster, rosterSettings) if (huntPX.checked == true && callObj.px) { var hash = String(callObj.px) + workHashSuffix; - var layeredHash = layeredMode && (String(callObj.px) + layeredHashSuffix) + var layeredHash = rosterSettings.layeredMode && (String(callObj.px) + layeredHashSuffix) - if (huntIndex && !(hash in huntIndex.px)) + if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.px)) { shouldAlert = true; callObj.reason.push("wpx"); - if (workedIndex && hash in workedIndex.px) + if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.px) { - if (layeredMode && layeredHash in huntIndex.px) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.px) { callObj.hunting.wpx = "worked-and-mixed"; wpxConf = `${layeredUnconf}${wpx}${layeredUnconfAlpha};`; @@ -574,13 +574,13 @@ function processRosterHunting(callRoster, rosterSettings) } else { - if (layeredMode && layeredHash in huntIndex.px) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.px) { callObj.hunting.wpx = "mixed"; wpxBg = `${wpx}${layeredAlpha};`; wpx = bold; } - else if (layeredMode && layeredHash in workedIndex.px) + else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.px) { callObj.hunting.wpx = "mixed-worked"; wpxConf = `${unconf}${wpx}${layeredAlpha};`; @@ -599,17 +599,17 @@ function processRosterHunting(callRoster, rosterSettings) if (huntCont.checked == true && callObj.cont) { var hash = String(callObj.cont) + workHashSuffix; - var layeredHash = layeredMode && (String(callObj.cont) + layeredHashSuffix) + var layeredHash = rosterSettings.layeredMode && (String(callObj.cont) + layeredHashSuffix) - if (huntIndex && !(hash in huntIndex.cont)) + if (rosterSettings.huntIndex && !(hash in rosterSettings.huntIndex.cont)) { shouldAlert = true; callObj.reason.push("cont"); - if (workedIndex && hash in workedIndex.cont) + if (rosterSettings.workedIndex && hash in rosterSettings.workedIndex.cont) { - if (layeredMode && layeredHash in huntIndex.cont) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.cont) { callObj.hunting.cont = "worked-and-mixed"; contConf = `${layeredUnconf}${cont}${layeredUnconfAlpha};`; @@ -624,13 +624,13 @@ function processRosterHunting(callRoster, rosterSettings) } else { - if (layeredMode && layeredHash in huntIndex.cont) + if (rosterSettings.layeredMode && layeredHash in rosterSettings.huntIndex.cont) { callObj.hunting.cont = "mixed"; contBg = `${cont}${layeredAlpha};`; cont = bold; } - else if (layeredMode && layeredHash in workedIndex.cont) + else if (rosterSettings.layeredMode && layeredHash in rosterSettings.workedIndex.cont) { callObj.hunting.cont = "mixed-worked"; contConf = `${unconf}${cont}${layeredAlpha};`; @@ -693,8 +693,8 @@ function processRosterHunting(callRoster, rosterSettings) callObj.spot = { when: 0, snr: 0 }; } - modes[callObj.mode] = true; - bands[callObj.band] = true; + rosterSettings.modes[callObj.mode] = true; + rosterSettings.bands[callObj.band] = true; } } } From 79efcb68dd3bd0dae0c9c1a283a9ef30d3cb0ac5 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 21:58:05 -0500 Subject: [PATCH 028/125] fix some more broken stuff --- package.nw/lib/roster/renderRoster.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js index 20f4be9..d245b2d 100644 --- a/package.nw/lib/roster/renderRoster.js +++ b/package.nw/lib/roster/renderRoster.js @@ -18,11 +18,20 @@ function renderRoster(callRoster, rosterSettings) // Show the roster count in the window title - var visibleCallList = callRoster.filter(entry => entry.tx); + // var visibleCallList = callRoster.filter(entry => entry.tx); + + var visibleCallList = []; + for (entry in callRoster) + { + if (entry.tx) + { + visibleCallList.push(callRoster[entry]); + } + } var totalCount = Object.keys(callRoster).length; var visibleCount = visibleCallList.length; - var huntedCount = visibleCallList.filter(obj => Object.keys(obj.hunting).length > 0).length + var huntedCount = visibleCallList.filter(obj => Object.keys(callObj.hunting).length > 0).length var countParts = []; if (totalCount != visibleCount) From 3d098a159e76ea0271ce97044119d201e94e1dd1 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:00:27 -0500 Subject: [PATCH 029/125] re-added r_sortFunction that somehow wondered off --- package.nw/lib/roster.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/package.nw/lib/roster.js b/package.nw/lib/roster.js index 8ce9b2e..05a464d 100644 --- a/package.nw/lib/roster.js +++ b/package.nw/lib/roster.js @@ -246,6 +246,26 @@ function lockNewWindows() } } +var r_sortFunction = [ + myCallCompare, + myGridCompare, + myDbCompare, + myDTCompare, + myFreqCompare, + myDxccCompare, + myTimeCompare, + myDistanceCompare, + myHeadingCompare, + myStateCompare, + myCQCompare, + myWPXCompare, + myLifeCompare, + mySpotCompare, + myGTCompare, + myCntyCompare, + myContCompare +]; + function myCallCompare(a, b) { return a.DEcall.localeCompare(b.DEcall); From b000a5b377fdb474597dd0103ad7b14838f4e9e7 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:08:06 -0500 Subject: [PATCH 030/125] more broke fixed --- package.nw/lib/roster/renderNormalRoster.js | 2 +- package.nw/lib/roster/renderRoster.js | 2 +- package.nw/lib/roster/sendAlerts.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.nw/lib/roster/renderNormalRoster.js b/package.nw/lib/roster/renderNormalRoster.js index 80fa5a8..3174d25 100644 --- a/package.nw/lib/roster/renderNormalRoster.js +++ b/package.nw/lib/roster/renderNormalRoster.js @@ -1,4 +1,4 @@ -function renderNormalRosterHeaders() +function renderNormalRosterHeaders(showBands, showModes) { var worker = "" worker = ""; diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js index d245b2d..cc8f4b9 100644 --- a/package.nw/lib/roster/renderRoster.js +++ b/package.nw/lib/roster/renderRoster.js @@ -65,7 +65,7 @@ function renderRoster(callRoster, rosterSettings) var showBands = (Object.keys(rosterSettings.bands).length > 1) || g_rosterSettings.columns.Band; var showModes = (Object.keys(rosterSettings.modes).length > 1) || g_rosterSettings.columns.Mode; - var worker = g_rosterSettings.compact ? renderCompactRosterHeaders() : renderNormalRosterHeaders() + var worker = g_rosterSettings.compact ? renderCompactRosterHeaders() : renderNormalRosterHeaders(showBands, showModes) // Third loop: render all rows for (var x in visibleCallList) diff --git a/package.nw/lib/roster/sendAlerts.js b/package.nw/lib/roster/sendAlerts.js index 7dcfa0f..99a3188 100644 --- a/package.nw/lib/roster/sendAlerts.js +++ b/package.nw/lib/roster/sendAlerts.js @@ -29,7 +29,7 @@ function sendAlerts(callRoster, rosterSettings) delete g_scriptReport[call].qso; delete g_scriptReport[call].instance; - if (callMode != "all") + if (rosterSettings.callMode != "all") { g_scriptReport[call].shouldAlert = true; g_scriptReport[call].reason.push(g_rosterSettings.hunting); @@ -38,7 +38,7 @@ function sendAlerts(callRoster, rosterSettings) if ( callObj.alerted == false && - callMode == "all" && + rosterSettings.callMode == "all" && callObj.shouldAlert == true ) { From c1f46d4f2d3323723005fd2bb3768c6d09444e0e Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:12:23 -0500 Subject: [PATCH 031/125] fix sendAlerts undefined object --- package.nw/lib/roster/sendAlerts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/roster/sendAlerts.js b/package.nw/lib/roster/sendAlerts.js index 99a3188..b4eccd3 100644 --- a/package.nw/lib/roster/sendAlerts.js +++ b/package.nw/lib/roster/sendAlerts.js @@ -6,7 +6,7 @@ function sendAlerts(callRoster, rosterSettings) var shouldAlert = 0; - for (var callObj in callRoster) + for (callObj in callRoster) { if (!callObj.tx) continue } // TODO: Get rid of realtime From 5462bc08e5c22bf20ea19f558147880791703c95 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:18:32 -0500 Subject: [PATCH 032/125] fix broken array --- package.nw/lib/roster/renderRoster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js index cc8f4b9..de3350d 100644 --- a/package.nw/lib/roster/renderRoster.js +++ b/package.nw/lib/roster/renderRoster.js @@ -23,7 +23,7 @@ function renderRoster(callRoster, rosterSettings) var visibleCallList = []; for (entry in callRoster) { - if (entry.tx) + if (callRoster[entry].tx) { visibleCallList.push(callRoster[entry]); } From 9d80c6df09e10149b374410070a9f2fb50036e97 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:21:19 -0500 Subject: [PATCH 033/125] fix line 34 --- package.nw/lib/roster/renderRoster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js index de3350d..0aa0aaa 100644 --- a/package.nw/lib/roster/renderRoster.js +++ b/package.nw/lib/roster/renderRoster.js @@ -31,7 +31,7 @@ function renderRoster(callRoster, rosterSettings) var totalCount = Object.keys(callRoster).length; var visibleCount = visibleCallList.length; - var huntedCount = visibleCallList.filter(obj => Object.keys(callObj.hunting).length > 0).length + var huntedCount = visibleCallList.filter(obj => Object.keys(obj.callObj.hunting).length > 0).length var countParts = []; if (totalCount != visibleCount) From df1e578d9c1d2d16b9b183d0dad8505aaf40a413 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:24:32 -0500 Subject: [PATCH 034/125] fix line 73 --- package.nw/lib/roster/renderRoster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js index 0aa0aaa..8591b44 100644 --- a/package.nw/lib/roster/renderRoster.js +++ b/package.nw/lib/roster/renderRoster.js @@ -70,7 +70,7 @@ function renderRoster(callRoster, rosterSettings) // Third loop: render all rows for (var x in visibleCallList) { - var callObj = visibleCallList[x]; + var callObj = visibleCallList[x].callObj; // TODO: This is filtering if (callObj.shouldAlert == false && onlyHits == true && callObj.qrz == false) From ed3abd26391dc8dfd818472d72abf0878ec173f0 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:26:40 -0500 Subject: [PATCH 035/125] lost show bands/modes on render call rows --- package.nw/lib/roster/renderNormalRoster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/roster/renderNormalRoster.js b/package.nw/lib/roster/renderNormalRoster.js index 3174d25..9b33e4e 100644 --- a/package.nw/lib/roster/renderNormalRoster.js +++ b/package.nw/lib/roster/renderNormalRoster.js @@ -85,7 +85,7 @@ function renderNormalRosterHeaders(showBands, showModes) return worker } -function renderNormalRosterRow(callObj) +function renderNormalRosterRow(callObj, showBands, showModes) { var thisCall = callObj.DEcall; var acks = window.opener.g_acknowledgedCalls; From 81b34b0dfb352c16b219f183f13521273887725a Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:37:49 -0500 Subject: [PATCH 036/125] fix some small stuff --- package.nw/lib/roster/renderNormalRoster.js | 4 ++-- package.nw/lib/roster/renderRoster.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.nw/lib/roster/renderNormalRoster.js b/package.nw/lib/roster/renderNormalRoster.js index 9b33e4e..c1856ed 100644 --- a/package.nw/lib/roster/renderNormalRoster.js +++ b/package.nw/lib/roster/renderNormalRoster.js @@ -134,9 +134,9 @@ function renderNormalRosterRow(callObj, showBands, showModes) ""; if (g_rosterSettings.columns.Calling) { diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js index 8591b44..b099e5e 100644 --- a/package.nw/lib/roster/renderRoster.js +++ b/package.nw/lib/roster/renderRoster.js @@ -73,7 +73,7 @@ function renderRoster(callRoster, rosterSettings) var callObj = visibleCallList[x].callObj; // TODO: This is filtering - if (callObj.shouldAlert == false && onlyHits == true && callObj.qrz == false) + if (callObj.shouldAlert == false && rosterSettings.onlyHits == true && callObj.qrz == false) { continue; } var spotString = ""; From 17d6defe4d48c0d68a83d23aed1fe40362566cf7 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:50:49 -0500 Subject: [PATCH 037/125] bunch of stuff moved to the right places --- package.nw/lib/roster/renderNormalRoster.js | 11 +++++++++++ package.nw/lib/roster/renderRoster.js | 14 +------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/package.nw/lib/roster/renderNormalRoster.js b/package.nw/lib/roster/renderNormalRoster.js index c1856ed..43b0440 100644 --- a/package.nw/lib/roster/renderNormalRoster.js +++ b/package.nw/lib/roster/renderNormalRoster.js @@ -89,6 +89,17 @@ function renderNormalRosterRow(callObj, showBands, showModes) { var thisCall = callObj.DEcall; var acks = window.opener.g_acknowledgedCalls; + var grid = callObj.grid.length > 1 ? callObj.grid.substr(0, 4) : "-"; + + var geo = window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]]; + var cqzone = grid in window.opener.g_gridToCQZone ? window.opener.g_gridToCQZone[grid].join(", ") : "-"; + var ituzone = grid in window.opener.g_gridToITUZone ? window.opener.g_gridToITUZone[grid].join(", ") : "-"; + + var spotString = ""; + if (g_rosterSettings.columns.Spot && callObj.qrz == false) + { + spotString = getSpotString(callObj); + } var thisHash = thisCall + callObj.band + callObj.mode; var callStr = thisCall.formatCallsign() diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js index b099e5e..a75d5a2 100644 --- a/package.nw/lib/roster/renderRoster.js +++ b/package.nw/lib/roster/renderRoster.js @@ -76,18 +76,6 @@ function renderRoster(callRoster, rosterSettings) if (callObj.shouldAlert == false && rosterSettings.onlyHits == true && callObj.qrz == false) { continue; } - var spotString = ""; - if (g_rosterSettings.columns.Spot && callObj.qrz == false) - { - spotString = getSpotString(callObj); - // TODO: This is filtering - if (g_rosterSettings.onlySpot && spotString == "") continue; - } - var grid = callObj.grid.length > 1 ? callObj.grid.substr(0, 4) : "-"; - - var geo = window.opener.g_worldGeoData[window.opener.g_dxccToGeoData[callObj.dxcc]]; - var cqzone = grid in window.opener.g_gridToCQZone ? window.opener.g_gridToCQZone[grid].join(", ") : "-"; - var ituzone = grid in window.opener.g_gridToITUZone ? window.opener.g_gridToITUZone[grid].join(", ") : "-"; var thisCall = callObj.DEcall; if (thisCall.match("^[A-Z][0-9][A-Z](/w+)?$")) @@ -104,7 +92,7 @@ function renderRoster(callRoster, rosterSettings) } } - worker += g_rosterSettings.compact ? renderCompactRosterRow(callObj) : renderNormalRosterRow(callObj) + worker += g_rosterSettings.compact ? renderCompactRosterRow(callObj) : renderNormalRosterRow(callObj, showBands, showModes) } RosterTable.innerHTML = g_rosterSettings.compact ? renderCompactRosterFooter() : renderNormalRosterFooter() From 8f77f1e30b88c8fd4d909a48d4e96397f6de7e92 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 22:51:52 -0500 Subject: [PATCH 038/125] fix grid --- package.nw/lib/roster/renderNormalRoster.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.nw/lib/roster/renderNormalRoster.js b/package.nw/lib/roster/renderNormalRoster.js index 43b0440..509f585 100644 --- a/package.nw/lib/roster/renderNormalRoster.js +++ b/package.nw/lib/roster/renderNormalRoster.js @@ -145,9 +145,9 @@ function renderNormalRosterRow(callObj, showBands, showModes) ""; if (g_rosterSettings.columns.Calling) { From bae7255c82c3c09008e4c3fd31787febc98aee2b Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 23:08:13 -0500 Subject: [PATCH 039/125] IT WORKS! --- package.nw/lib/roster/renderRoster.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.nw/lib/roster/renderRoster.js b/package.nw/lib/roster/renderRoster.js index a75d5a2..5984ec0 100644 --- a/package.nw/lib/roster/renderRoster.js +++ b/package.nw/lib/roster/renderRoster.js @@ -95,5 +95,6 @@ function renderRoster(callRoster, rosterSettings) worker += g_rosterSettings.compact ? renderCompactRosterRow(callObj) : renderNormalRosterRow(callObj, showBands, showModes) } - RosterTable.innerHTML = g_rosterSettings.compact ? renderCompactRosterFooter() : renderNormalRosterFooter() + worker += g_rosterSettings.compact ? renderCompactRosterFooter() : renderNormalRosterFooter() + RosterTable.innerHTML = worker; } From 0cb9b7518300c37f26a198419add607679074ba1 Mon Sep 17 00:00:00 2001 From: Matthew Chambers Date: Mon, 28 Jun 2021 23:18:43 -0500 Subject: [PATCH 040/125] tweak for compact mode --- package.nw/lib/roster/renderCompactRoster.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.nw/lib/roster/renderCompactRoster.js b/package.nw/lib/roster/renderCompactRoster.js index 271a0bc..616d96b 100644 --- a/package.nw/lib/roster/renderCompactRoster.js +++ b/package.nw/lib/roster/renderCompactRoster.js @@ -16,7 +16,7 @@ function renderCompactRosterRow(callObj) (callObj.grid.length ? ", " + callObj.grid : "") + ", " + (timeNowSec() - callObj.age).toDHMS(); - worker += + var worker = "
Date: Mon, 5 Jul 2021 11:47:16 -0500 Subject: [PATCH 046/125] acks update 5-july-2021 --- package.nw/data/acknowledgements.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/package.nw/data/acknowledgements.json b/package.nw/data/acknowledgements.json index 838e1f8..dfc7fa4 100644 --- a/package.nw/data/acknowledgements.json +++ b/package.nw/data/acknowledgements.json @@ -87,6 +87,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "K4KPG": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "K4TLS": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -191,6 +195,10 @@ "badge": "img/emojis/trophy.png", "message": "GridTracker Developer" }, + "KI0Y": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "KI2D": { "badge": "img/emojis/flatbread.png", "message": "GridTracker Developer" @@ -199,6 +207,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "KK4WZI": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "KL4NE": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" @@ -219,6 +231,10 @@ "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" }, + "KN6NCT": { + "badge": "img/emojis/money-bag.png", + "message": "GridTracker Donor" + }, "KNC6EWM": { "badge": "img/emojis/money-bag.png", "message": "GridTracker Donor" From 727942c95b03b0ab9963b87761a58db6e5a068cd Mon Sep 17 00:00:00 2001 From: christian Date: Wed, 7 Jul 2021 15:08:03 -0400 Subject: [PATCH 047/125] clear call roster on band change: option added --- package.nw/GridTracker.html | 12 ++++++++++++ package.nw/lib/defaults.js | 1 + package.nw/lib/gt.js | 6 ++++++ package.nw/lib/roster/renderRoster.js | 21 ++++++++++++++++++++- 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/package.nw/GridTracker.html b/package.nw/GridTracker.html index c15e01e..f79f356 100644 --- a/package.nw/GridTracker.html +++ b/package.nw/GridTracker.html @@ -2905,6 +2905,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
" + - grid + + callObj.grid + "" + - callObj.grid + + grid + "
+
+ + + + + + + +
Clear Call Roster on Band change
+ +
+