Advertisement
HydrantHunter

ccDHD 1.1

Dec 24th, 2013
1,090
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 99.74 KB | None | 0 0
  1. --[[   LanteaCraft     ]]--
  2. --[[      c c D H D    ]]--
  3. --[[  core ver. 5.0.5  ]]--
  4. --[[   ui ver. 4.4.2   ]]--
  5. --[[     by Dog        ]]--
  6. --[[ aka HydrantHunter ]]--
  7. --[[  with help from   ]]--
  8. --[[    Bomb Bloke     ]]--
  9. --[[ pastebin vMtcSz2e ]]--
  10. --[[      GPL v3       ]]--
  11. local ccDHDVer = "1.1.31"
  12. --[[
  13. Tested with/requires:
  14.   - Minecraft 1.6.4
  15.   - LanteaCraft (snapshot 82+ and RC1_15-RC1_22)
  16.   - ComputerCraft ver. 1.57-1.58 for MC 1.6.4
  17.     - HTTP API enabled (for pastebin installer - not required for ccDHD)
  18.     - 1 Advanced Computer (color, mouse), 4 optional Advanced Monitors (color, touch)
  19.     - gateLiaison running on an Advanced Computer (with 3 optional Advanced Monitors) or an Advanced Wireless Turtle (no monitors)
  20.  
  21.   - ccDHD also supports the Biometric Lock (Fistprint Scanner) in GopherATL's Biolocks MOD ver. 2.1.3 (updated for 1.6.4 by gamax92)
  22. ]]--
  23. if os.clock() < 5 then
  24.   sleep(2)
  25. end
  26. -- AUTOMATIC/STATIC CONFIGURATION
  27. -- Default Settings
  28. local settingsData = "/data/DHDconfig"
  29. local dhdSettings = {
  30.   thisGate = "--ERROR--",
  31.   highlight = "YES",
  32.   password = "password",
  33.   monA = "none",
  34.   monB = "none",
  35.   bio = { lock = "OFF", func = "none", auth = 4 },
  36.   net = "C",
  37.   gate = 65536,
  38.   channels = { send = 1776, recv = 1787 },
  39.   pSync = "OFF",
  40.   pChannels = { send = 24747, recv = 24242 },
  41.   ecShield = "ON",
  42.   startShield = "OFF",
  43.   callEnd = "OFF",
  44.   logs = "OFF",
  45.   lastGate = "/data/DHDlast",
  46.   gateHistory = "/data/DHDhistory",
  47.   gateData = "/data/DHDgates",
  48. }
  49. local allGates = { { addr = "NEWGATE", rating = "U", note = "short note", loc = { x = 99999, y = 99999, z = 99999, dim = "Overworld", } } }
  50. local fistAuth = false
  51. local longName, tY
  52. local drawCLI, drawRatingList, assignRating, assignColor
  53.  -- Peripherals
  54. local termX, termY = term.getSize() -- portable 26x20 / standard 51x19 / cBang & OneOS = 51x18
  55. local modem = nil                   -- Modem (for ccNet)
  56. local monA = dhdSettings.monA       -- List monitor
  57. local monB = dhdSettings.monB       -- Marquee Monitor
  58. local hardware = { netSide = "none", bioSide = "none" } -- Modem and Biolock sides
  59.  -- Status Info
  60. local shieldStatus, gateStatus, secureStatus = "QRY", "QRY", "QRY"
  61. local runState, currentState, displayState = "init", "ZZ", "list"
  62. local kernelState, menuState = false, false
  63. local configChange, gateChange = false, false
  64. local tempState, currentEdit, fuelGauge, dialAddress
  65.  -- Gate List
  66. local pNum = "001"
  67. local numPages, pageNum = 1, 1
  68. local listPages, listPage = 1, 1
  69.  -- Call History
  70. local histPages, histPage = 1, 1
  71. local callHistory, lastCall = { }, { }
  72.  -- Color Definitions
  73. local white = colors.white
  74. local lgray = colors.lightGray
  75. local gray = colors.gray
  76. local black = colors.black
  77. local brown = colors.brown
  78. local yellow = colors.yellow
  79. local orange = colors.orange
  80. local red = colors.red
  81. local magenta = colors.magenta
  82. local purple = colors.purple
  83. local blue = colors.blue
  84. local lblue = colors.lightBlue
  85. local cyan = colors.cyan
  86. local lime = colors.lime
  87. local green = colors.green
  88. -- END AUTOMATIC/STATIC CONFIGURATION
  89.  
  90. local function pSync(pushpull) -- Sync allGates with a portable advanced computer running ccDialer
  91.   if pushpull == "pPull" then
  92.     sleep(0.1)
  93.     local pGateData = textutils.serialize(allGates)
  94.     modem.transmit(dhdSettings.pChannels.send, dhdSettings.pChannels.recv, pGateData)
  95.   elseif pushpull == "pPush" then
  96.     local newGates = { os.pullEvent("modem_message") }
  97.     if newGates[3] == dhdSettings.pChannels.recv and newGates[4] == dhdSettings.pChannels.send then
  98.       allGates = { }
  99.       local newGateData = newGates[5]
  100.       allGates = textutils.unserialize(newGateData)
  101.       gateChange = true
  102.       if pageNum == numPages then term.setBackgroundColor(black) term.clear() end
  103.       drawCLI()
  104.     end
  105.   end
  106. end
  107.  
  108. local function recordSessionData() -- Human readable log files (last gate & history)
  109.   if not fs.exists("/data") then fs.makeDir("/data") end
  110.   local dateStamp = tostring(textutils.formatTime(os.time(), false) .. " / Day " .. tostring(os.day()))
  111.   local lastCall = fs.open(dhdSettings.lastGate, "w")
  112.   lastCall.writeLine(dateStamp)
  113.   lastCall.writeLine(dialAddress)
  114.   lastCall.close()
  115.   if dhdSettings.logs == "ON" then
  116.     local gateArchive = fs.open(dhdSettings.gateHistory, fs.exists(dhdSettings.gateHistory) and "a" or "w")
  117.     gateArchive.writeLine(dateStamp)
  118.     gateArchive.writeLine(dialAddress)
  119.     gateArchive.close()
  120.   end
  121. end
  122.  
  123. local function updateStatus(newInfo)  -- Update status info
  124.   if newInfo == "000" then            -- bit/trit/bit
  125.     shieldStatus = "OFF"              -- 1st/bit = shield
  126.     gateStatus = "Disconnected"       -- 2nd/trit = connection/dialing
  127.     secureStatus = "allclear"
  128.     fuelGauge = false                 -- 3rd/bit = fuel
  129.     dialAddress = ""
  130.   elseif newInfo == "001" then
  131.     shieldStatus = "OFF"
  132.     gateStatus = "Disconnected"
  133.     secureStatus = "allclear"
  134.     dialAddress = ""
  135.     fuelGauge = true
  136.   elseif newInfo == "010" then
  137.     shieldStatus = "OFF"
  138.     gateStatus = "Connected"
  139.     secureStatus = "allclear"
  140.     fuelGauge = false
  141.   elseif newInfo == "011" then
  142.     shieldStatus = "OFF"
  143.     gateStatus = "Connected"
  144.     secureStatus = "allclear"
  145.     fuelGauge = true
  146.   elseif newInfo == "020" then
  147.     shieldStatus = "OFF"
  148.     gateStatus = "Dialing"
  149.     secureStatus = "allclear"
  150.     fuelGauge = false
  151.     if dialAddress == "" then
  152.       dialAddress = "Inbound"
  153.       recordSessionData()
  154.       dialAddress = ""
  155.     else
  156.       recordSessionData()
  157.     end
  158.   elseif newInfo == "021" then
  159.     shieldStatus = "OFF"
  160.     gateStatus = "Dialing"
  161.     secureStatus = "allclear"
  162.     fuelGauge = true
  163.     if dialAddress == "" then
  164.       dialAddress = "Inbound"
  165.       recordSessionData()
  166.       dialAddress = ""
  167.     else
  168.       recordSessionData()
  169.     end
  170.   elseif newInfo == "100" then
  171.     shieldStatus = "ON"
  172.     gateStatus = "Disconnected"
  173.     secureStatus = "allclear"
  174.     dialAddress = ""
  175.     fuelGauge = false
  176.   elseif newInfo == "101" then
  177.     shieldStatus = "ON"
  178.     gateStatus = "Disconnected"
  179.     secureStatus = "allclear"
  180.     dialAddress = ""
  181.     fuelGauge = true
  182.   elseif newInfo == "110" then
  183.     shieldStatus = "ON"
  184.     gateStatus = "Connected"
  185.     secureStatus = "allclear"
  186.     fuelGauge = false
  187.   elseif newInfo == "111" then
  188.     shieldStatus = "ON"
  189.     gateStatus = "Connected"
  190.     secureStatus = "allclear"
  191.     fuelGauge = true
  192.   elseif newInfo == "120" then
  193.     shieldStatus = "ON"
  194.     gateStatus = "Dialing"
  195.     secureStatus = "allclear"
  196.     fuelGauge = false
  197.     if dialAddress == "" then
  198.       dialAddress = "Inbound"
  199.       recordSessionData()
  200.       dialAddress = ""
  201.     else
  202.       recordSessionData()
  203.     end
  204.   elseif newInfo == "121" then
  205.     shieldStatus = "ON"
  206.     gateStatus = "Dialing"
  207.     secureStatus = "allclear"
  208.     fuelGauge = true
  209.     if dialAddress == "" then
  210.       dialAddress = "Inbound"
  211.       recordSessionData()
  212.       dialAddress = ""
  213.     else
  214.       recordSessionData()
  215.     end
  216.   elseif newInfo == "Dialing" then
  217.     gateStatus = "Dialing"
  218.     secureStatus = "allclear"
  219.     if dialAddress == "" then
  220.       dialAddress = "Inbound"
  221.       recordSessionData()
  222.       dialAddress = ""
  223.     else
  224.       recordSessionData()
  225.     end
  226.   elseif newInfo == "YY0" then
  227.     secureStatus = "allclear"
  228.     shieldStatus = "OFF"
  229.     gateStatus = "Disconnected"
  230.     fuelGauge = false
  231.     dialAddress = ""
  232.     term.setBackgroundColor(black)
  233.     term.clear()
  234.   elseif newInfo == "YY1" then
  235.     secureStatus = "allclear"
  236.     shieldStatus = "OFF"
  237.     gateStatus = "Disconnected"
  238.     fuelGauge = true
  239.     dialAddress = ""
  240.     term.setBackgroundColor(black)
  241.     term.clear()
  242.   elseif newInfo == "XX0" then
  243.     secureStatus = "lockdown"
  244.     shieldStatus = "ON"
  245.     gateStatus = "Disconnected"
  246.     fuelGauge = false
  247.     dialAddress = ""
  248.   elseif newInfo == "XX1" then
  249.     secureStatus = "lockdown"
  250.     shieldStatus = "ON"
  251.     gateStatus = "Disconnected"
  252.     fuelGauge = true
  253.     dialAddress = ""
  254.   elseif newInfo == "pPull" or newInfo == "pPush" then
  255.     pSync(newInfo)
  256.     return
  257.   end
  258.   if newInfo ~= "pPush" and newInfo ~= "pPull" and currentState ~= "ZZ" and runState ~= "init" then currentState = newInfo end
  259.   if currentState ~= "ZZ" and runState ~= "init" then drawCLI() end
  260.   return
  261. end
  262.  
  263. local function netSend(dataPack)
  264.   if dhdSettings.net == "R" then
  265.     rednet.send(dhdSettings.gate, dataPack)
  266.   elseif dhdSettings.net == "C" then
  267.     modem.transmit(dhdSettings.channels.send, dhdSettings.channels.recv, dataPack)
  268.   end
  269. end
  270.  
  271. local function netReceive()
  272.   while true do
  273.     if dhdSettings.net == "R" then
  274.       local id, message = rednet.receive()
  275.       if id == dhdSettings.gate then
  276.         if currentState ~= message then
  277.           updateStatus(message)
  278.           return
  279.         end
  280.       end
  281.     elseif dhdSettings.net == "C" then
  282.       local netEvent = { os.pullEvent("modem_message") }
  283.       if netEvent[3] == dhdSettings.channels.recv and netEvent[4] == dhdSettings.channels.send then
  284.         if currentState ~= netEvent[5] then
  285.           updateStatus(netEvent[5])
  286.           return
  287.         end
  288.       end
  289.     end
  290.   end
  291. end
  292.  
  293. local function pSyncReceive()
  294.   while true do
  295.     local pSyncEvent = { os.pullEvent("modem_message") }
  296.     if pSyncEvent[3] == dhdSettings.pChannels.recv and pSyncEvent[4] == dhdSettings.pChannels.send then
  297.       if pSyncEvent[5] == "pPull" or pSyncEvent[5] == "pPush" then
  298.         pSync(pSyncEvent[5])
  299.       else
  300.         if #tostring(pSyncEvent[5]) > 6 and #tostring(pSyncEvent[5]) < 10 then
  301.           dialAddress = pSyncEvent[5]
  302.           netSend(dialAddress)
  303.         end
  304.       end
  305.     end
  306.   end
  307. end
  308.  
  309. local function makeLongName(name) -- This spaces out the name for a 7 character address
  310.   if #name ~= 7 then
  311.     return name
  312.   end
  313.   local letters = { 'A', 'A', 'A', 'A', 'A', 'A', 'A' }
  314.   for i = 1, 7 do
  315.     letters[i] = i == 7 and name:sub(7) or name:sub(i, i) .. " "
  316.   end
  317.   return table.concat(letters)
  318. end
  319.  
  320. local function saveData(filename, filetype)
  321.   menuState = false
  322.   if not fs.exists("/data") then fs.makeDir("/data") end
  323.   if fs.exists("/disk") and filename == ("/disk/data/DHDgates") then
  324.     if not fs.exists("/disk/data") then fs.makeDir("/disk/data") end
  325.   end
  326.   local dhdConfig = fs.open(tostring(filename), "w") or error("saveData(): Cannot open " .. filename .. " for writing", 2)
  327.   if filetype == "cfg" then
  328.     dhdConfig.write(textutils.serialize(dhdSettings))
  329.     configChange = false
  330.   elseif filetype == "gate" then
  331.     dhdConfig.write(textutils.serialize(allGates))
  332.     if fs.exists("/disk/DHDgates") then fs.delete("/disk/DHDgates") end
  333.     if filename == dhdSettings.gateData then gateChange = false end
  334.   end
  335.   dhdConfig.close()
  336. end
  337.  
  338. local function ingestData(fileName, fileType)
  339.   if not fs.exists(tostring(fileName)) then return end
  340.   local dhdConfig = fs.open(tostring(fileName), "r") or error("ingestData(): Cannot open " .. fileName .. " for reading", 2)
  341.   local dhdCfg = dhdConfig.readAll()
  342.   dhdConfig.close()
  343.   if fileType == "cfg" then
  344.     dhdSettings = textutils.unserialize(dhdCfg)
  345.     if dhdSettings.monA ~= "none" then
  346.       monA = peripheral.wrap(dhdSettings.monA)
  347.     end
  348.     if dhdSettings.monB ~= "none" then
  349.       monB = peripheral.wrap(dhdSettings.monB)
  350.     end
  351.     if dhdSettings.gate == nil and dhdSettings.server ~= nil then
  352.       dhdSettings.gate = dhdSettings.server
  353.       dhdSettings.server = nil
  354.       saveData(settingsData, "cfg")
  355.     end
  356.     longName = makeLongName(dhdSettings.thisGate)
  357.   elseif fileType == "gate" then
  358.     allGates = textutils.unserialize(dhdCfg)
  359.     if allGates[1].addr == "NEWGATE" then
  360.       allGates[1].addr = dhdSettings.thisGate
  361.     end
  362.     numPages = math.ceil(#allGates / 24)
  363.     listPages = math.ceil(#allGates / 8)
  364.     pageNum = 1
  365.     listPage = 1
  366.     if fs.exists("/disk/DHDgates") then fs.delete("/disk/DHDgates") end
  367.     if fileName == "/disk/data/DHDgates" then gateChange = true end
  368.   end
  369. end
  370.  
  371. local function ingestLogData()
  372.   if not fs.exists(dhdSettings.gateHistory) then
  373.     local tmpHist = fs.open(dhdSettings.gateHistory, "w")
  374.     tmpHist.close()
  375.   end
  376.   if fs.exists(dhdSettings.gateHistory) then
  377.     local dhdHist = fs.open(dhdSettings.gateHistory, "r") or error("ingestLogData(): Cannot open /data/DHDhistory for reading", 2)
  378.     while true do
  379.       local timeDate = dhdHist.readLine()
  380.       local gateAddr = dhdHist.readLine()
  381.       if gateAddr == "" or gateAddr == nil then gateAddr = "No Data" end
  382.       if timeDate == nil or timeDate == "" then break end
  383.       local tTime = timeDate:sub(1, string.find(timeDate, " / ")) -- separate time from time/day
  384.       local dDate = timeDate:sub(#tTime + 7)                      -- separate day from time/day
  385.       if #tTime == 8 then tTime = " " .. tTime end  -- move single digit hour times to the right one space (this must happen after date so date doesn't get skewed by 1)
  386.       table.insert(callHistory, 1, tTime .. "_" .. dDate .. "/" .. gateAddr) -- insert concatenated data into callHistory table
  387.     end
  388.     dhdHist.close()
  389.   end
  390.   histPages = math.ceil(#callHistory / 10) -- paginate call logs
  391.   if histPages < 1 then histPages = 1 end  -- probably not necessary with math.ceil
  392.   if not fs.exists(dhdSettings.lastGate) then
  393.     local tmpLast = fs.open(dhdSettings.lastGate, "w")
  394.     tmpLast.close()
  395.   end
  396.   local dhdLast = fs.open(dhdSettings.lastGate, "r") or error("ingestLogData(): Cannot open /data/DHDlast for reading", 2)
  397.   for i = 1, 2, 1 do
  398.     local lastInfo = dhdLast.readLine()
  399.     table.insert(lastCall, lastInfo)
  400.   end
  401.   dhdLast.close()
  402. end
  403.  
  404. do
  405.   local colorBurst = {
  406.     B = { blue, "Base/Outpost/Hub" },
  407.     H = { lblue, "Home/Camp" },
  408.     V = { brown, "Village" },
  409.     M = { purple, "Misc/Special" },
  410.     S = { green, "Safe" },
  411.     C = { orange, "Caution" },
  412.     D = { red, "Danger" },
  413.     U = { lgray, "Unknown" },
  414.   }
  415.  
  416.   assignColor = function(gateNumber)
  417.     return colorBurst[allGates[gateNumber].rating][1]
  418.   end
  419.  
  420.   assignRating = function(gateNumber)
  421.     return colorBurst[allGates[gateNumber].rating][2]
  422.   end
  423. end
  424.  
  425. local function displayMarquee()
  426.   if dhdSettings.monB == "none" then return end
  427.   monB.setTextScale(2)
  428.   monB.setBackgroundColor(black)
  429.   monB.clear()
  430.   monB.setTextColor(cyan)
  431.   monB.setCursorPos(1, 1)
  432.   monB.write("Stargate")
  433.   monB.setTextColor(yellow)
  434.   if #dhdSettings.thisGate == 7 then
  435.     monB.setCursorPos(2, 2)
  436.   else
  437.     monB.setCursorPos(4, 2)
  438.   end
  439.   monB.write(longName)
  440. end
  441.  
  442. local function displayGateList()
  443.   local mX, mY = monA.getSize()
  444.   local firstGate = (listPage - 1) * 8 + 1
  445.   local tmY = 1
  446.   monA.setTextScale(0.5)
  447.   monA.setBackgroundColor(black)
  448.   monA.clear()
  449.   for i = firstGate, firstGate + 7, 1 do
  450.     if tmY == 9 then break end
  451.     if i > #allGates then break end
  452.     local tmX = 5
  453.     if #allGates[i].addr > 7 then tmX = 4 end
  454.     monA.setCursorPos(tmX, tmY)
  455.     monA.setTextColor(assignColor(i))
  456.     if dhdSettings.thisGate == allGates[i].addr and dhdSettings.highlight == "YES" then
  457.       monA.setTextColor(gray)
  458.     end
  459.     monA.write(allGates[i].addr)
  460.     tmY = tmY + 1
  461.   end
  462.   monA.setBackgroundColor(cyan)
  463.   monA.setTextColor(white)
  464.   monA.setCursorPos(1, 10)
  465.   monA.write("   /\\     \\/   ")
  466. end
  467.  
  468. local function displayNotes(pY)
  469.   local listEntry = (listPage - 1) * 8 + pY
  470.   if listEntry > #allGates then listEntry = #allGates end
  471.   if listEntry < 1 then listEntry = 1 end
  472.   if dhdSettings.monA ~= "none" then
  473.     monA.setBackgroundColor(black)
  474.     monA.clear()
  475.     if #allGates[listEntry].addr > 7 then
  476.       monA.setTextScale(0.5)
  477.       monA.setCursorPos(4, 5)
  478.     else
  479.       monA.setTextScale(1)
  480.       monA.setCursorPos(1, 3)
  481.     end
  482.     monA.setTextColor(assignColor(listEntry))
  483.     monA.write(allGates[listEntry].addr)
  484.   end
  485.   if dhdSettings.monB ~= "none" then
  486.     monB.setTextScale(1)
  487.     monB.setBackgroundColor(black)
  488.     monB.clear()
  489.     monB.setCursorPos(1, 2)
  490.     monB.setTextColor(lblue)
  491.     monB.write(allGates[listEntry].loc.dim)
  492.     monB.setCursorPos(1, 4)
  493.     monB.setTextColor(white)
  494.     monB.write(allGates[listEntry].note)
  495.   end
  496. end
  497.  
  498. local function displayStatus()
  499.   if dhdSettings.monB == "none" then return end
  500.   local longAddress = ""
  501.   monB.setTextScale(2)
  502.   monB.setBackgroundColor(black)
  503.   monB.clear()
  504.   monB.setCursorPos(1, 1)
  505.   if (gateStatus == "Dialing" or gateStatus == "Connected") and (dialAddress ~= "" and dialAddress ~= nil) then
  506.     monB.setTextColor(lblue)
  507.     if gateStatus == "Dialing" then
  508.       monB.write("Dialing")
  509.     elseif gateStatus == "Connected" then
  510.       monB.write("Connected to")
  511.     end
  512.     local xPos = 9 - #dialAddress
  513.     if xPos < 2 then
  514.       xPos = 4
  515.       longAddress = dialAddress
  516.     end
  517.     monB.setCursorPos(xPos, 2)
  518.     longAddress = makeLongName(dialAddress)
  519.     monB.setTextColor(yellow)
  520.     monB.write(longAddress)
  521.   elseif (gateStatus == "Dialing" or gateStatus == "Connected" ) and (dialAddress == "" or dialAddress == nil) then
  522.     monB.setTextColor(yellow)
  523.     monB.write("Incoming")
  524.     monB.setCursorPos(2, 2)
  525.     monB.write("Connection")
  526.   else
  527.     if displayState == "list" then
  528.       displayMarquee()
  529.     elseif displayState == "info" then
  530.       displayNotes(tY)
  531.     end
  532.   end
  533. end
  534.  
  535. local function drawElement(x, y, w, h, txtColor, bgColor, text)
  536.   local sText = text and tostring(text) or ""
  537.   term.setCursorPos(x, y)
  538.   if type(w) == "string" then
  539.     term.setBackgroundColor(w == "OFF" and gray or green)
  540.     term.write("  ")
  541.     term.setBackgroundColor(w == "OFF" and red or gray)
  542.     term.write("  ")
  543.   else
  544.     if bgColor then term.setBackgroundColor(bgColor) end
  545.     if w > #sText or h > 1 then        -- We're 'drawing' something more than text
  546.       for i = 1, h do                  --
  547.         term.write(string.rep(" ", w)) -- Draw the 'element' (box/rectangle/line-seg)
  548.         term.setCursorPos(x, y + i)    --
  549.       end
  550.     end
  551.     if sText ~= "" then
  552.       if txtColor then term.setTextColor(txtColor) end
  553.       if w < #sText then w = #sText end -- Ensure minimum length
  554.       local xW = (x + math.floor(w / 2)) - math.floor(#sText / 2) -- Center the text horizontally
  555.       local xH = y + math.floor(h / 2)  -- Center the text vertically
  556.       term.setCursorPos(xW, xH)
  557.       term.write(sText)
  558.     end
  559.   end
  560. end
  561.  
  562. local function drawHeader()
  563.   local bgColor
  564.   term.setBackgroundColor(black)
  565.   term.setTextColor(white)
  566.   if secureStatus == "allclear" then
  567.     local runStates = {
  568.       Dial = blue,
  569.       DialCfg = lblue,
  570.       rCmd = blue,
  571.       viewing = blue,
  572.       goPage = blue,
  573.       Edit = brown,
  574.       EditCfg = lblue,
  575.       GateEdit = brown,
  576.       Trim = orange,
  577.       logs = yellow,
  578.       quit = purple,
  579.       init = blue,
  580.     }
  581.     bgColor = runStates[runState]
  582.   elseif secureStatus == "lockdown" then
  583.     bgColor = red
  584.   end
  585.   drawElement(1, 1, termX, 1, runState == "logs" and black or white, bgColor, longName)
  586.   if runState == "logs" then                        -- If we're viewing the logs, show the last call info instead of connect/shield info
  587.     term.setBackgroundColor(gray)
  588.     term.setTextColor(lgray)
  589.     drawElement(1, 2, termX, 3, nil, gray, "")
  590.     drawElement(2, 2, 23, 1, yellow, gray, "C A L L   H I S T O R Y")
  591.     drawElement(termX-6, 2, 7, 1, red, lgray, " Close ")
  592.     drawElement(termX-6, 4, 7, 1, orange, lgray, " Clear ")
  593.     drawElement(2, 3, 11, 1, lgray, gray, "Last Call: ")
  594.     term.setTextColor(white)
  595.     if lastCall[1] == nil and lastCall[2] == nil then
  596.       lastCall[1], lastCall[2] = "none" .. string.rep(" ", 13), "nogate"
  597.     end
  598.     term.write(lastCall[1] .. "  ")
  599.     term.setTextColor(lblue)
  600.     term.write(lastCall[2])
  601.     drawElement(2, 4, 25, 1, black, gray, "Time       Day       Gate")
  602.     return
  603.   end
  604.   if (runState == "Dial" or runState == "Edit") and secureStatus == "allclear" then  -- Dial and Edit modes get the -DHD- menu
  605.     drawElement(2, 1, 5, 1, white, black, "-DHD-")
  606.   end
  607.   drawElement(1, 2, termX, 3, nil, gray, "") -- Draw 'status' area
  608.   if #dhdSettings.thisGate > 7 then
  609.     drawElement(2, 3, 7, 1, lgray, gray, "Iris is")
  610.   else
  611.     drawElement(2, 3, 9, 1, lgray, gray, "Shield is")
  612.   end
  613.   drawElement(20, 3, 5, 1, lgray, gray, "Gate:")
  614.   local tgColor
  615.   term.setBackgroundColor(gray)
  616. -- Shield & Gate Status
  617.   if shieldStatus == "ON" then
  618.     tgColor = lime
  619.   elseif shieldStatus == "OFF" then
  620.     tgColor = orange
  621.   else
  622.     tgColor = red
  623.   end
  624.   if #dhdSettings.thisGate > 7 and shieldStatus == "ON" then -- Iris open/closed
  625.     drawElement(10, 3, 6, 1, tgColor, gray, "CLOSED")
  626.   elseif #dhdSettings.thisGate > 7 and shieldStatus == "OFF" then
  627.     drawElement(10, 3, 4, 1, tgColor, gray, "OPEN")
  628.   else
  629.     drawElement(12, 3, (#shieldStatus) + 1, 1, tgColor, gray, shieldStatus .. " ") -- Shield ON/OFF
  630.   end
  631.   if gateStatus == "Connected" then
  632.     tgColor = orange
  633.   elseif gateStatus == "Disconnected" then
  634.     tgColor = lime
  635.   elseif gateStatus == "Dialing" then
  636.     tgColor = cyan
  637.   else
  638.     tgColor = red
  639.   end
  640.   term.setTextColor(tgColor)
  641.   term.setCursorPos(26, 3)
  642.   if (gateStatus == "Connected" or gateStatus == "Dialing") and (dialAddress == "" or dialAddress == nil) then
  643.     term.write("Incoming Connection")
  644.   else
  645.     if gateStatus == "Connected" and dialAddress ~= "" and dialAddress ~= nil then
  646.       term.write(gateStatus .. " to" .. string.rep(" ", 10))
  647.       term.setCursorPos(39, 3)
  648.     else
  649.       term.write(gateStatus .. string.rep(" ", 13))
  650.       term.setCursorPos(34, 3)
  651.     end
  652.     if gateStatus ~= "Disconnected" then
  653.       term.setTextColor(yellow)
  654.       term.write(dialAddress)
  655.     end
  656.     if gateStatus == "Disconnected" and fuelGauge == false then
  657.       local nf = "N O  F U E L" .. string.rep(" ", 13)
  658.       drawElement(26, 3, 1, 1, red, gray, nf)
  659.     end
  660.   end
  661.   if secureStatus == "allclear" then displayStatus() end
  662. end
  663.  
  664. local function drawControlUI()
  665.   local dhdCommandOptions = {
  666.     " D I A L",
  667.     " E D I T",
  668.     " T R I M",
  669.     "Shield", "Iris",
  670.     "END Call",
  671.     "LOCKDOWN",
  672.     "rCmd",
  673.     "+ Entry",
  674.     "Import",
  675.     "Export",
  676.     "Save",
  677.     "- Undo -",
  678.     "-COMMIT-",
  679.   }
  680.   drawElement(42, 6, 10, 11, nil, gray, "") -- Control UI 'box'
  681.   term.setTextColor(white)
  682.   term.setCursorPos(43, 7)
  683.   if runState == "Dial" then
  684.     if fuelGauge then                 -- FUEL
  685.       term.setBackgroundColor(green)  --  full color
  686.     else                              --
  687.       term.setBackgroundColor(red)    --  empty color
  688.     end
  689.     term.write(dhdCommandOptions[1] .. "     ")  -- D I A L
  690.   elseif runState == "Edit" then
  691.     term.setBackgroundColor(brown)
  692.     term.write(dhdCommandOptions[2] .. "     ")  -- E D I T
  693.   elseif runState == "Trim" then
  694.     term.setBackgroundColor(orange)
  695.     term.write(dhdCommandOptions[3] .. "     ")  -- T R I M
  696.   end
  697.   if runState == "Dial" then
  698.     if #dhdSettings.thisGate == 7 then
  699.       drawElement(43, 9, 1, 1, white, lblue, dhdCommandOptions[4] .. "   ")    -- Shield
  700.     else
  701.       drawElement(43, 9, 1, 1, white, lblue, dhdCommandOptions[5] .. "    ")   -- Iris
  702.     end
  703.     if shieldStatus == "ON" then
  704.       drawElement(termX, 9, 1, 1, nil, green, "")  -- Iris/Shield pip ON
  705.     else
  706.       drawElement(termX, 9, 1, 1, nil, orange, "") -- Iris/Shield pip OFF
  707.     end
  708.     drawElement(43, 11, 1, 1, black, orange, dhdCommandOptions[6] .. " ")      -- endCall
  709.     drawElement(43, 13, 1, 1, orange, red, dhdCommandOptions[7] .. "   ")      -- Lockdown
  710.     drawElement(43, 15, 1, 1, gray, cyan, dhdCommandOptions[8] .. "     ")     -- rCmd
  711.   elseif runState == "Edit" then
  712.     if #allGates < 23977 then
  713.       drawElement(43, 9, 1, 1, white, blue, dhdCommandOptions[9] .. "  ")      -- +Entry
  714.     end
  715.     drawElement(43, 11, 1, 1, white, orange, dhdCommandOptions[10] .. "    ")  -- Import Gate Data
  716.     drawElement(43, 13, 1, 1, white, green, dhdCommandOptions[11] .. "    ")   -- Export Gate Data
  717.     if gateChange then
  718.       drawElement(43, 15, 1, 1, lime, cyan, dhdCommandOptions[12] .. "     ")  -- Save Gate Data
  719.       term.setTextColor(lime)
  720.     else
  721.       drawElement(43, 15, 1, 1, white, cyan, dhdCommandOptions[12] .. "     ") -- Save Gate Data
  722.     end
  723.   elseif runState == "Trim" then
  724.     drawElement(43, 11, 8, 1, gray, lgray, dhdCommandOptions[13] .. " ")       -- Undo
  725.     drawElement(43, 13, 8, 1, black, red, dhdCommandOptions[14] .. " ")        -- Commit
  726.   end
  727.   term.setBackgroundColor(black)
  728. end
  729.  
  730. local function drawNaviUI()
  731.   pNum = tostring(pageNum)
  732.   if pageNum < 100 then pNum = "0" .. pNum end -- Add a "0" before double digit page numbers
  733.   if pageNum < 10 then pNum = "0" .. pNum end  -- Add another "0" before single digit page numbers
  734.   drawElement(((termX / 2) - (math.floor(pNum:len() / 4))) - 5, termY, 3, 1, lgray, black, pNum) -- Page Number
  735.   if pageNum > 1 then
  736.     drawElement((termX / 2) - 14, termY, 7, 1, gray, black, "<< BACK") -- Show "BACK" option if page number is > 1
  737.   elseif pageNum == 1 then
  738.     drawElement((termX / 2) - 14, termY, 7, 1, gray, black, string.rep(" ", 7)) -- Overwrite "BACK" instead of clearing screen
  739.   end
  740.   if pageNum < numPages then
  741.     drawElement(termX / 2, termY, 7, 1, gray, black, "NEXT >>") -- Show "NEXT" option if page number is < numPages
  742.   elseif pageNum == numPages then
  743.     drawElement(termX / 2, termY, 7, 1, gray, black, string.rep(" ", 7)) -- Overwrite "NEXT" instead of clearing screen
  744.   end
  745. end
  746.  
  747. local function drawMainUI() -- Gate Address Book (Dial / Edit / Trim)
  748.   local xPos, yPos = 2, 4
  749.   local j = ((pageNum - 1) * 23) + pageNum
  750.   local k = ((pageNum - 1) * 24)
  751.   for i = j, #allGates, 1 do
  752.     if i > k and i < k + 7 then           -- Column 1
  753.       xPos, yPos = 2, 4
  754.     elseif i > k + 6 and i < k + 13 then  -- Column 2
  755.       xPos, yPos = 12, -8
  756.     elseif i > k + 12 and i < k + 19 then -- Column 3
  757.       xPos, yPos = 22, -20
  758.     elseif i > k + 18 and i < k + 25 then -- Column 4
  759.       xPos, yPos = 32, -32
  760.     end
  761.     term.setCursorPos(xPos, yPos + ((i - ((pageNum - 1) * 24)) * 2))
  762.     if runState == "Dial" then
  763.       term.setBackgroundColor(assignColor(i))
  764.       if dialAddress == allGates[i].addr and dhdSettings.thisGate ~= allGates[i].addr then -- Highlight the gate being dialed
  765.         term.setTextColor(black)
  766.       else
  767.         term.setTextColor(white)
  768.       end
  769.       if dhdSettings.thisGate == allGates[i].addr and dhdSettings.highlight == "YES" then -- Highlight this gate / Dial
  770.         term.setTextColor(lgray)
  771.         term.setBackgroundColor(gray)
  772.       end
  773.     elseif runState == "Edit" then
  774.       term.setBackgroundColor(black)
  775.       term.setTextColor(assignColor(i))
  776.       if dhdSettings.thisGate == allGates[i].addr and dhdSettings.highlight == "YES" then -- Highlight this gate / Edit
  777.         term.setTextColor(gray)
  778.       end
  779.     elseif runState == "Trim" then
  780.       term.setBackgroundColor(gray)
  781.       term.setTextColor(assignColor(i))
  782.       if dhdSettings.thisGate == allGates[i].addr and dhdSettings.highlight == "YES" then -- Highlight this gate / Trim
  783.         term.setTextColor(black)
  784.       end
  785.     end
  786.     if i > (pageNum * 24) or i > #allGates then
  787.       break
  788.     else
  789.       if #allGates[i].addr < 10 then
  790.         local spacer
  791.         local spacerSet = { Dial = " ", Edit = "|", Trim = "/", }
  792.         for l, m in pairs(spacerSet) do
  793.           if runState == tostring(l) then
  794.             spacer = m
  795.           end
  796.         end
  797.         term.write(string.rep(spacer, math.ceil((9 - #allGates[i].addr) / 2)) .. allGates[i].addr .. string.rep(spacer, math.floor((9 - #allGates[i].addr) / 2))) -- Address
  798.       else
  799.         term.write("ERROR #10")  -- ERROR #10 = address is 10 or more characters
  800.       end
  801.     end
  802.   end
  803.   term.setBackgroundColor(black)
  804. end
  805.  
  806. local function drawHelpUI()
  807.   local colorDefs = {
  808.     blue,
  809.     green,
  810.     purple,
  811.     lblue,
  812.     orange,
  813.     lgray,
  814.     brown,
  815.     red
  816.   }
  817.   local colorDesc = {
  818.     "Base/Outpost/Hub",
  819.     "Secured/Safe",
  820.     "Misc./Special",
  821.     "Home/Camp",
  822.     "Caution",
  823.     "Unknown",
  824.     "Village",
  825.     "Danger",
  826.   }
  827.   local colorCount = #colorDesc
  828.   local xMod = 2
  829.   local yMod = 4
  830.   term.setBackgroundColor(black)
  831.   term.clear()
  832.   local hColor
  833.   if runState == "DialHelp" then -- Header color
  834.     hColor = cyan
  835.   elseif runState == "EditHelp" then
  836.     hColor = brown
  837.   end
  838.   drawElement(1, 1, termX, 1, nil, hColor, "") -- Header
  839.   drawElement((termX / 2) - (((#runState - 4) / 2) + 3), 1, 11, 1, white, gray, runState:sub(1, #runState - 4) .. " Help") -- Header text
  840.   drawElement(1, 2, termX, 1, nil, gray, "")
  841.   drawElement(1, termY, termX, 1, nil, gray, "") -- Footer
  842.   drawElement(2, 2, 9, 1, lgray, gray, "-- Key --")
  843.   drawElement(termX-6, 2, 7, 1, red, lgray, " Close ")
  844.   for q, r in ipairs(colorDefs) do -- Color key for gate classifications
  845.     drawElement(xMod, yMod, 1, 1, r, black, colorDesc[q])
  846.     if xMod == 2 then
  847.       xMod = 20
  848.     elseif xMod == 20 then
  849.       xMod = 38
  850.     elseif xMod == 38 then
  851.       xMod = 2
  852.       yMod = yMod + 1
  853.     end
  854.   end
  855.   drawElement(1, colorCount, termX, 1, nil, gray, "")
  856.   drawElement(2, colorCount, 11, 1, lgray, gray, "-- Notes --")
  857.   local lowLine = "ccDHD ver. " .. ccDHDVer .. string.rep(" ", 5) .. "cc# " .. os.getComputerID()
  858.   drawElement(2, termY, 1, 1, lgray, gray, lowLine)
  859.   local tmpLabel = os.getComputerLabel()
  860.   drawElement(termX-#tmpLabel, termY, 1, 1, lgray, gray, tmpLabel)
  861.   if runState == "DialHelp" then
  862.     drawElement(2, colorCount + 2, 31, 1, white, black, "- Left click an address to dial")
  863.     drawElement(2, colorCount + 3, 40, 1, white, black, "- Right click an address to view details")
  864.     drawElement(2, colorCount + 4, 42, 1, white, black, "- rCmd: manually send commands to the gate")
  865.     drawElement(2, colorCount + 5, 43, 1, white, black, "  - ADDRESS / sON / sOFF / endCall / hangup")
  866.     drawElement(2, colorCount + 6, 22, 1, white, black, "  - lockdown / restart")
  867.     drawElement(2, colorCount + 7, 27, 1, white, black, "  - reboot & quit are local")
  868.     drawElement(2, colorCount + 8, 37, 1, white, black, "  - reset = reboots DHD & gateLiaison")
  869.   elseif runState == "EditHelp" then
  870.     drawElement(2, colorCount + 2, 42, 1, white, black, "- EDIT Mode: Left click an address to edit")
  871.     drawElement(2, colorCount + 3, 49, 1, white, black, "             Right click an address for Trim Mode")
  872.     drawElement(2, colorCount + 4, 47, 1, white, black, "  '+ Entry'  Right click '+ Entry' to quick-add")
  873.     drawElement(2, colorCount + 5, 41, 1, white, black, "   'Import'  Load gate data from diskette")
  874.     drawElement(2, colorCount + 6, 39, 1, white, black, "   'Export'  Save gate data to diskette")
  875.     drawElement(2, colorCount + 7, 44, 1, white, black, "- TRIM Mode: Left click an address to delete")
  876.     drawElement(2, colorCount + 8, 49, 1, white, black, " '-COMMIT-'  Saves new gate data, exits Trim Mode")
  877.     drawElement(2, colorCount + 9, 47, 1, white, black, " '- Undo -'  Cancels deletions, exits Trim Mode")
  878.   end
  879. end
  880.  
  881. local function drawSettingsUI()
  882.   term.setBackgroundColor(black)
  883.   term.clear()
  884.   drawElement(1, 1, termX, 1, nil, lblue, "")
  885.   drawElement(1, 2, termX, 1, nil, gray, "")
  886.   local settingsHeader = " " .. dhdSettings.thisGate .. " Settings "
  887.   drawElement((termX / 2) - ((#dhdSettings.thisGate / 2)) - 4, 1, 1, 1, white, gray, settingsHeader)
  888.   drawElement(1, termY, termX, 1, nil, gray, "")
  889.   local tsColor
  890.   if configChange then
  891.     tsColor = lime
  892.   else
  893.     tsColor = gray
  894.   end
  895.   drawElement(39, 2, 6, 1, tsColor, lgray, " Save ") -- Save / Close buttons
  896.   drawElement(45, 2, 7, 1, red, lgray, " Close ")    --
  897.    -- Settings 1st Column
  898.   drawElement(2, 4, 9, 1, gray, black, "This gate")
  899.   drawElement(17, 4, 1, 1, cyan, black, dhdSettings.thisGate) -- thisGate
  900.   drawElement(2, 6, 1, 1, gray, black, "Lockdown pass")
  901.   drawElement(17, 6, 1, 1, orange, black, dhdSettings.password) -- superSecretPassword
  902.   drawElement(2, 8, 1, 1, gray, black, "Biolock Login")
  903.   if dhdSettings.bio.lock == "OFF" then -- Fistprint Authentication (Biolock mod)
  904.     drawElement(17, 8, "OFF")
  905.   elseif dhdSettings.bio.lock == "ON" then
  906.     drawElement(17, 8, "ON")
  907.   end
  908.   drawElement(23, 8, 1, 1, black, gray, "#") -- Biolock auth. level
  909.   drawElement(2, 10, 1, 1, gray, black, "Net:")
  910.   if dhdSettings.net == "R" then     -- redNet (specify server #)
  911.     drawElement(7, 10, 1, 1, red, black, "redNet")
  912.   elseif dhdSettings.net == "C" then -- ccNet (specify send/receive channels)
  913.     drawElement(7, 10, 1, 1, green, black, "ccNet")
  914.   end
  915.   if dhdSettings.net == "R" then     -- Red for redNet
  916.     drawElement(17, 10, "OFF")
  917.   elseif dhdSettings.net == "C" then -- Green for ccNet
  918.     drawElement(17, 10, "ON")
  919.   end
  920.   drawElement(23, 10, 1, 1, black, gray, "#") -- hardware.netSide
  921.   if dhdSettings.net == "R" then     -- if redNet show "Gate Liaison"
  922.     drawElement(2, 12, 1, 1, gray, black, "Gate Liaison")
  923.   elseif dhdSettings.net == "C" then -- if ccNet show "Send/Rec"
  924.     drawElement(2, 12, 1, 1, gray, black, "Send/Rec")
  925.   end
  926.   if dhdSettings.net == "R" then
  927.     drawElement(17, 12, 1, 1, red, black, tostring(dhdSettings.gate)) -- Gate Liaison (redNet)
  928.   elseif dhdSettings.net == "C" then
  929.     local ccSnd = string.rep(" ", 5-#tostring(dhdSettings.channels.send)) .. tostring(dhdSettings.channels.send)
  930.     drawElement(11, 12, 1, 1, green, black, ccSnd)
  931.     drawElement(16, 12, 1, 1, lgray, black, "/")
  932.     local ccRec = string.rep(" ", 5-#tostring(dhdSettings.channels.recv)) .. tostring(dhdSettings.channels.recv)
  933.     drawElement(17, 12, 1, 1, green, black, ccRec)
  934.   end
  935.   drawElement(2, 14, 1, 1, gray, black, "Marquee") -- Marquee (monB)
  936.   if dhdSettings.monB == "none" then
  937.     drawElement(17, 14, "OFF")
  938.   else
  939.     drawElement(17, 14, "ON")
  940.   end
  941.   drawElement(23, 14, 1, 1, black, gray, "#") -- Marquee side (monB)
  942.   drawElement(2, 16, 12, 1, gray, black, "List Monitor") -- List Monitor (monA)
  943.   if dhdSettings.monA == "none" then
  944.     drawElement(17, 16, "OFF")
  945.   else
  946.     drawElement(17, 16, "ON")
  947.   end
  948.   drawElement(23, 16, 1, 1, black, gray, "#") -- List Monitor side (monA)
  949.   -- Settings 2nd column
  950.   drawElement(28, 4, 1, 1, gray, black, "Highlight gate") -- Whether or not to display the local gate differently than the rest of the list
  951.   if dhdSettings.highlight == "YES" then
  952.     drawElement(45, 4, "ON")
  953.   elseif dhdSettings.highlight == "NO" then
  954.     drawElement(45, 4, "OFF")
  955.   end
  956.   drawElement(28, 6, 1, 1, gray, black, "pSync (ccDialer)") -- Enable/Disable ccDialer pSync
  957.   if dhdSettings.pSync == "ON" then
  958.     drawElement(45, 6, "ON")
  959.   elseif dhdSettings.pSync == "OFF" then
  960.     drawElement(45, 6, "OFF")
  961.   end
  962.   drawElement(28, 8, 1, 1, gray, black, "Bio: ") -- Whether Biolock controls shield or initiates lockdown or does nothing (this is separate from BioLogin)
  963.   if dhdSettings.bio.func == "none" then
  964.     drawElement(33, 8, 1, 1, lgray, black, "No Function")
  965.   elseif dhdSettings.bio.func == "shield" then
  966.     if #dhdSettings.thisGate == 7 then
  967.       drawElement(33, 8, 1, 1, green, black, "Shield")
  968.     elseif #dhdSettings.thisGate > 7 then
  969.       drawElement(33, 8, 1, 1, green, black, "Iris")
  970.     end
  971.   elseif dhdSettings.bio.func == "lock" then
  972.     drawElement(33, 8, 1, 1, red, black, "Lockdown")
  973.   end
  974.   term.setCursorPos(45, 8)
  975.   if dhdSettings.bio.func == "none" then -- Bio - Iris/Lockdown/None function switch
  976.     term.setBackgroundColor(green)
  977.     term.write(" ")
  978.     term.setBackgroundColor(gray)
  979.     term.write("  ")
  980.     term.setBackgroundColor(red)
  981.     term.write(" ")
  982.   elseif dhdSettings.bio.func == "shield" then
  983.     drawElement(45, 8, "ON")
  984.   elseif dhdSettings.bio.func == "lock" then
  985.     drawElement(45, 8, "OFF")
  986.   end
  987.   if #dhdSettings.thisGate == 7 then
  988.     drawElement(28, 10, 1, 1, gray, black, "STARTUP Shield")
  989.   elseif #dhdSettings.thisGate > 7 then
  990.     drawElement(28, 10, 1, 1, gray, black, "STARTUP Iris")
  991.   end
  992.   if dhdSettings.startShield == "OFF" then
  993.     drawElement(45, 10, "OFF")
  994.   elseif dhdSettings.startShield == "ON" then
  995.     drawElement(45, 10, "ON")
  996.   end
  997.   if #dhdSettings.thisGate == 7 then -- END Call Shield (ON/OFF)
  998.     drawElement(28, 12, 1, 1, gray, black, "END Call Shield")
  999.   elseif #dhdSettings.thisGate > 7 then
  1000.     drawElement(28, 12, 1, 1, gray, black, "END Call Iris")
  1001.   end
  1002.   if dhdSettings.ecShield == "OFF" then
  1003.     drawElement(45, 12, "OFF")
  1004.   elseif dhdSettings.ecShield == "ON" then
  1005.     drawElement(45, 12, "ON")
  1006.   end
  1007.   drawElement(28, 14, 1, 1, gray, black, "Call Logging") -- ccDHD should/not log outbound calls
  1008.   if dhdSettings.logs == "OFF" then
  1009.     drawElement(45, 14, "OFF")
  1010.   elseif dhdSettings.logs == "ON" then
  1011.     drawElement(45, 14, "ON")
  1012.   end
  1013.   drawElement(28, 16, 1, 1, gray, black, "Initiator Only") -- Only call initiator can end call (ON/OFF)
  1014.   if dhdSettings.callEnd == "OFF" then
  1015.     drawElement(45, 16, "OFF")
  1016.   elseif dhdSettings.callEnd == "ON" then
  1017.     drawElement(45, 16, "ON")
  1018.   end
  1019. end
  1020.  
  1021. local function drawSecureUI()
  1022.   -- Uh, oh...doubleSecretProbation()
  1023.   if monA ~= "none" then
  1024.     monA.setBackgroundColor(black)
  1025.     monA.clear()
  1026.   end
  1027.   if monB ~= "none" then
  1028.     monB.setBackgroundColor(black)
  1029.     monB.setTextColor(red)
  1030.     monB.setTextScale(2)
  1031.     monB.clear()
  1032.     monB.setCursorPos(1, 1)
  1033.     monB.write("!! LOCKDOWN !!")
  1034.   end
  1035.   term.setBackgroundColor(black)
  1036.   term.clear()
  1037.   drawHeader()
  1038.   drawElement((termX / 2) - 7, 9, 1, 1, red, black, "!! LOCKDOWN !!")
  1039.   drawElement((termX / 2) - 10, 15, 1, 1, gray, black, "password:")
  1040. end
  1041.  
  1042. drawCLI = function()
  1043.   if menuState == false then
  1044.     drawHeader()
  1045.   end
  1046.   if runState == "viewing" or runState == "GateEdit" then return end
  1047.   if secureStatus == "lockdown" then
  1048.     return
  1049.   else
  1050.     if menuState == false then
  1051.       if displayState == "list" then
  1052.         if monB ~= "none" then
  1053.           displayStatus()
  1054.         end
  1055.         if monA ~= "none" then
  1056.           displayGateList()
  1057.         end
  1058.       end
  1059.       if runState == "Dial" or runState == "Edit" or runState == "Trim" then
  1060.         drawMainUI()
  1061.         drawControlUI()
  1062.         drawNaviUI()
  1063.         displayStatus()
  1064.       elseif runState == "DialCfg" or runState == "EditCfg" then
  1065.         drawSettingsUI()
  1066.       elseif runState == "DialHelp" or runState == "EditHelp" then
  1067.         drawHelpUI()
  1068.       end
  1069.     end
  1070.   end
  1071. end
  1072.  
  1073. local function drawSideList(pSide)
  1074.   local tPos = { 5, 7, 9, 11, 13, 15 }
  1075.   local tSide = { "top", "bottom", "front", "back", "left", "right" }
  1076.   drawElement(26, 4, 8, 13, nil, gray, "") -- menu body
  1077.   local tsColor
  1078.   for j, k in ipairs(tSide) do
  1079.     if pSide == k then
  1080.       tsColor = lime
  1081.     else
  1082.       tsColor = white
  1083.     end
  1084.     local tWord = string.upper(k):sub(1, 1) .. k:sub(2)
  1085.     drawElement(27, tPos[j], 1, 1, tsColor, gray, tWord)
  1086.   end
  1087. end
  1088.  
  1089. do
  1090.   local ratings = {
  1091.     [1] = { rating = "B", color = blue, word = "Base/Outpost/Hub" },
  1092.     [2] = { rating = "H", color = lblue, word = "Home/Camp" },
  1093.     [3] = { rating = "V", color = brown, word = "Village" },
  1094.     [4] = { rating = "M", color = purple, word = "Misc/Special" },
  1095.     [5] = { rating = "S", color = green, word = "Safe/Secured" },
  1096.     [6] = { rating = "C", color = orange, word = "Caution" },
  1097.     [7] = { rating = "D", color = red, word = "Danger" },
  1098.     [8] = { rating = "U", color = lgray, word = "Unknown" },
  1099.   }
  1100.  
  1101.   drawRatingList = function(gRating)
  1102.     local tColor
  1103.     drawElement(15, 6, 19, 8, nil, gray, "")  -- menu body
  1104.     for i = 1, 8 do
  1105.       drawElement(14, i + 5, 1, 1, nil, ratings[i].color, "") --# color pips
  1106.       if gRating == ratings[i].rating and gRating == "U" then
  1107.         tColor = white
  1108.       elseif gRating == ratings[i].rating and gRating ~= "U" then
  1109.         tColor = ratings[i].color
  1110.       end
  1111.       drawElement(16, i + 5, 1, 1, gRating == ratings[i].rating and tColor or lgray, gray, ratings[i].word) --# rating word
  1112.       if gRating == ratings[i].rating then drawElement(33, i + 5, 1, 1, nil, ratings[i].color, "") end
  1113.     end
  1114.   end
  1115. end
  1116.  
  1117. local function drawAuthList(cAuth)
  1118.   local cPos = { 5, 7, 9, 11, 13 }
  1119.   drawElement(26, 4, 3, 11, nil, gray, "") -- menu body
  1120.   local taColor
  1121.   for j, k in ipairs(cPos) do
  1122.     if cAuth == j then
  1123.       taColor = lime
  1124.     else
  1125.       taColor = white
  1126.     end
  1127.     drawElement(26, k, 3, 1, taColor, gray, tostring(j))
  1128.   end
  1129. end
  1130.  
  1131. local function drawMenu()
  1132.   menuState = true
  1133.   drawElement(2, 1, 5, 1, white, black, "_DHD_")
  1134.   drawElement(2, 2, 1, 9, nil, gray, "")    -- dark gray line along left side of menu
  1135.   drawElement(3, 2, 9, 9, nil, lgray, "")   -- menu body
  1136.   drawElement(2, 3, 1, 1, nil, lblue, "")   -- Settings pip
  1137.   drawElement(3, 3, 8, 1, gray, lgray, "Settings")
  1138.   drawElement(2, 5, 1, 1, nil, yellow, "")  -- Logs pip
  1139.   drawElement(3, 5, 9, 1, gray, lgray, "View Logs")
  1140.   if runState == "Dial" then -- Whether to show Dial Help or Edit Help color pip in menu
  1141.     drawElement(2, 7, 1, 1, nil, cyan, "")  -- Help pip
  1142.   elseif runState == "Edit" or runState == "Trim" then
  1143.     drawElement(2, 7, 1, 1, nil, brown, "") -- Help pip
  1144.   end
  1145.   drawElement(3, 7, 9, 1, gray, lgray, runState .. " Help")
  1146.   drawElement(2, 9, 1, 1, nil, red, "")     -- Exit pip
  1147.   drawElement(3, 9, 8, 1, gray, lgray, "  EXIT  ")
  1148. end
  1149.  
  1150. local function flashChoice(choice)
  1151.   if choice == "cfg" then
  1152.     drawElement(3, 3, 9, 1, white, lblue, "Settings ")
  1153.     sleep(0.1)
  1154.     drawMenu()
  1155.   elseif choice == "logs" then
  1156.     drawElement(3, 5, 9, 1, black, yellow, "View Logs")
  1157.     sleep(0.1)
  1158.     drawMenu()
  1159.   elseif choice == "dhelp" then
  1160.     drawElement(3, 7, 9, 1, white, cyan, "Dial Help")
  1161.     sleep(0.1)
  1162.     drawMenu()
  1163.   elseif choice == "ehelp" then
  1164.     drawElement(3, 7, 9, 1, white, brown, "Edit Help")
  1165.     sleep(0.1)
  1166.     drawMenu()
  1167.   elseif choice == "exit" then
  1168.     drawElement(3, 9, 9, 1, white, red, "  EXIT   ")
  1169.     sleep(0.1)
  1170.     drawMenu()
  1171.   elseif choice == "close" then
  1172.     drawElement(termX-6, 2, 7, 1, white, red, " Close ")
  1173.     sleep(0.1)
  1174.     drawElement(termX-6, 2, 7, 1, red, lgray, " Close ")
  1175.   elseif choice == "clear" then
  1176.     drawElement(termX-6, 4, 7, 1, white, orange, " Clear ")
  1177.     sleep(0.1)
  1178.     drawElement(termX-6, 4, 7, 1, gray, lgray, " Clear ")
  1179.   elseif choice == "cfgsave" then
  1180.     drawElement(termX-12, 2, 6, 1, white, green, " Save ")
  1181.     sleep(0.1)
  1182.     drawElement(termX-12, 2, 6, 1, gray, lgray, " Save ")
  1183.   elseif choice == "new" then
  1184.     drawElement(43, 9, 9, 1, blue, white, "+ Entry  ")
  1185.     sleep(0.1)
  1186.   elseif choice == "end" then
  1187.     drawElement(43, 11, 9, 1, orange, black, "END Call ")
  1188.     sleep(0.1)
  1189.     drawControlUI()
  1190.   elseif choice == "import" then
  1191.     drawElement(43, 11, 9, 1, orange, white, "Import   ")
  1192.     sleep(0.1)
  1193.     drawControlUI()
  1194.   elseif choice == "undo" then
  1195.     drawElement(43, 11, 9, 1, white, brown, "- Undo - ")
  1196.     sleep(0.1)
  1197.   elseif choice == "lock" then
  1198.     drawElement(43, 13, 9, 1, red, orange, "LOCKDOWN ")
  1199.     sleep(0.1)
  1200.   elseif choice == "export" then
  1201.     drawElement(43, 13, 9, 1, green, white, "Export   ")
  1202.     sleep(0.1)
  1203.     drawControlUI()
  1204.   elseif choice == "commit" then
  1205.     drawElement(43, 13, 9, 1, red, black, "-COMMIT- ")
  1206.     sleep(0.1)
  1207.   elseif choice == "rcmd" then
  1208.     drawElement(43, 15, 9, 1, cyan, lgray, "rCmd     ")
  1209.     sleep(0.1)
  1210.     drawControlUI()
  1211.   elseif choice == "save" then
  1212.     drawElement(43, 15, 9, 1, cyan, white, "Save     ")
  1213.     sleep(0.1)
  1214.     drawControlUI()
  1215.   elseif choice == "page" then
  1216.     drawElement(((termX / 2) - (math.floor(#tostring(pNum) / 4))) - 5, termY, 3, 1, black, white, pNum)
  1217.     sleep(0.1)
  1218.     drawCLI()
  1219.   end
  1220. end
  1221.  
  1222. local function areYouSure()
  1223.   runState = "asking"
  1224.   drawElement(termX / 2 - 5, math.floor(termY / 2) - 2, 13, 1, black, yellow, "Clear Logs?")
  1225.   drawElement(termX / 2 - 5, math.floor(termY / 2) - 1, 13, 3, nil, gray, "")
  1226.   drawElement(termX / 2 - 4, math.floor(termY / 2), 5, 1, white, green, "YES")
  1227.   drawElement(termX / 2 + 2, math.floor(termY / 2), 5, 1, white, red, "N O")
  1228.   while true do
  1229.     local _, mButton, mX, mY = os.pullEvent("mouse_click")
  1230.     if mY == math.floor(termY / 2) then
  1231.       if mX > (termX / 2) - 5 and mX < termX / 2 then
  1232.         drawElement(termX / 2 - 5, math.floor(termY / 2) - 2, 13, 4, nil, black, "")
  1233.         runState = "logs"
  1234.         return true
  1235.       elseif mX > termX / 2 and mX < (termX / 2) + 6 then
  1236.         drawElement(termX / 2 - 5, math.floor(termY / 2) - 2, 13, 4, nil, black, "")
  1237.         runState = "logs"
  1238.         return false
  1239.       end
  1240.     end
  1241.   end
  1242. end
  1243.  
  1244. local function viewLogs()
  1245.   if histPage == histPages then
  1246.     term.setBackgroundColor(black)
  1247.     term.clear()
  1248.     drawHeader()
  1249.   end
  1250.   drawElement(1, termY, termX, 1, nil, gray, "")
  1251.   drawElement(5, termY, 7, 1, black, gray, "page # ")
  1252.   term.setTextColor(white)
  1253.   term.write(tostring(histPage))
  1254.   term.setTextColor(black)
  1255.   term.write(" of ")
  1256.   term.setTextColor(white)
  1257.   term.write(tostring(histPages))
  1258.   term.setBackgroundColor(black)
  1259.   local currentEntry = ((histPage - 1) * 10) + 1                        -- Set the first entry to show (based on page number)
  1260.   if callHistory[1] == "" or callHistory[1] == nil then callHistory[1] = "No Logs_/" end -- no logs
  1261.   for i = currentEntry, #callHistory, 1 do                                -- Display logs
  1262.     term.setCursorPos(2, i - ((histPage - 1) * 10) + 5)                 -- position entry
  1263.     term.setTextColor(gray)                                             --
  1264.     term.write(callHistory[i]:sub(1, string.find(callHistory[i], "_") - 1)) -- write time
  1265.     term.setCursorPos(13, i - ((histPage - 1) * 10) + 5)                -- position entry
  1266.     term.write(callHistory[i]:sub(string.find(callHistory[i], "_") + 1, string.find(callHistory[i], "/") - 1)) -- write day
  1267.     term.setCursorPos(23, i - ((histPage - 1) * 10) + 5)                -- position entry
  1268.     local tGate = callHistory[i]:sub(string.find(callHistory[i], "/") + 1) -- get gate
  1269.     if tGate == "No Data" then
  1270.       term.setTextColor(gray)
  1271.     elseif tGate == "Inbound" then
  1272.       term.setTextColor(lgray)
  1273.     else
  1274.       term.setTextColor(lblue)
  1275.     end
  1276.     if #tGate < 9 then tGate = " " .. tGate .. " " end         -- if tGate is LT 9 characters add buffer spaces
  1277.     term.write(tGate)                                          -- write gate
  1278.     if i > currentEntry + 9 or i > #callHistory then break end -- if we've 'filled' the page or reached the end of the log then stop the loop
  1279.   end
  1280. end
  1281.  
  1282. local function viewGateEntry(dataBlock)
  1283.   currentEdit = dataBlock
  1284.   tempState = runState
  1285.   if tempState ~= "GateEdit" then runState = "viewing" end
  1286.   if currentEdit == "new" or currentEdit == "newFast" then
  1287.     if #allGates < 23976 then     -- If we're adding a new gate, create a generic gate to edit
  1288.       local newGate = { addr = "NEWGATE", rating = "U", note = "short note", loc = {x=99999, y=99999, z=99999, dim="Overworld", }, }
  1289.       table.insert(allGates, newGate)
  1290.       numPages = math.ceil(#allGates / 24) -- Re-paginate gates
  1291.       listPages = math.ceil(#allGates / 8)
  1292.       if currentEdit == "newFast" then
  1293.         runState = "Edit"
  1294.         drawCLI()
  1295.         return
  1296.       end
  1297.       currentEdit = #allGates
  1298.     end
  1299.   end
  1300.   term.setBackgroundColor(black)
  1301.   term.clear()
  1302.   drawHeader()
  1303.   -- Display data for viewing/editing
  1304.   term.setBackgroundColor(black)
  1305.   if currentEdit <= #allGates then
  1306.     local teColor = assignColor(currentEdit)
  1307.     if teColor ~= nil then
  1308.       drawElement(2, 7, #allGates[currentEdit].addr, 1, teColor, black, allGates[currentEdit].addr)
  1309.       local ratingWord = assignRating(currentEdit)
  1310.       drawElement(14, 7, #ratingWord, 1, gray, black, ratingWord)
  1311.       if allGates[currentEdit].addr == dhdSettings.thisGate then
  1312.         drawElement(34, 7, 9, 1, yellow, black, "THIS GATE")
  1313.       end
  1314.       drawElement(2, 9, #allGates[currentEdit].note, 1, white, black, allGates[currentEdit].note)
  1315.       drawElement(2, 12, 10, 1, lgray, black, "Dimension:")
  1316.       drawElement(13, 12, #allGates[currentEdit].loc.dim, 1, lblue, black, allGates[currentEdit].loc.dim)
  1317.       drawElement(2, 13, 2, 1, lgray, black, "x:")
  1318.       drawElement(5, 13, #tostring(allGates[currentEdit].loc.x), 1, brown, black, allGates[currentEdit].loc.x)
  1319.       drawElement(2, 14, 2, 1, lgray, black, "y:")
  1320.       drawElement(5, 14, #tostring(allGates[currentEdit].loc.y), 1, brown, black, allGates[currentEdit].loc.y)
  1321.       drawElement(2, 15, 2, 1, lgray, black, "z:")
  1322.       drawElement(5, 15, #tostring(allGates[currentEdit].loc.z), 1, brown, black, allGates[currentEdit].loc.z)
  1323.     end
  1324.   end
  1325.   drawElement((termX / 2) - 8, termY - 1, 19, 1, black, gray, " < < < CLOSE > > > ")
  1326. end
  1327.  
  1328. local function deleteGate(tGate) -- TRIM mode: delete gate
  1329.   if #allGates > 1 then          -- Don't delete if only 1 gate remaining
  1330.     table.remove(allGates, tGate)
  1331.     numPages = math.ceil(#allGates / 24) -- Re-paginate gates
  1332.     listPages = math.ceil(#allGates / 8)
  1333.     if pageNum > numPages then pageNum = numPages end
  1334.     if listPage > listPages then listPage = listPages end
  1335.     drawElement(2, 6, termX, 11, nil, black, "") -- Clear gate entry area of screen
  1336.   end
  1337. end
  1338.  
  1339. local function readInput(cX, cY, cO, bG)  -- cursor X, Y, text color, bg color
  1340.   local word = ""
  1341.   local curX, curY = cX, cY
  1342.   if bG == nil then bG = black end
  1343.   term.setTextColor(cO)
  1344.   term.setCursorBlink(true)
  1345.   term.setCursorPos(curX, curY)
  1346.   while true do
  1347.     local event, data = os.pullEvent()
  1348.     if event == "key" then
  1349.       if data == keys.backspace then
  1350.         if curX > cX then
  1351.           curX = curX - 1
  1352.           word = word:sub(1, #word-1)
  1353.         end
  1354.         term.setTextColor(cO)
  1355.         term.setBackgroundColor(bG)
  1356.         term.setCursorPos(curX, curY)
  1357.         term.write(" ")
  1358.         term.setCursorPos(curX, curY)
  1359.       elseif data == keys.enter then
  1360.         term.setCursorBlink(false)
  1361.         return word
  1362.       end
  1363.     elseif event == "char" then
  1364.       term.setTextColor(cO)
  1365.       term.setBackgroundColor(bG)
  1366.       term.setCursorPos(curX, curY)
  1367.       term.write(data)
  1368.       word = word .. data
  1369.       curX = curX + 1
  1370.     end
  1371.   end
  1372. end
  1373.  
  1374. local function remoteCommand()
  1375.   tempState = runState
  1376.   runState = "rCmd"
  1377.   drawElement((termX / 2) - 11, 8, 15, 1, white, gray, " RemoteCommand ")
  1378.   drawElement((termX / 2) - 11, 9, 15, 2, nil, gray, "")
  1379.   drawElement((termX / 2) - 10, 9, 13, 1, nil, black, "") -- input area bg
  1380.   term.setBackgroundColor(black)
  1381.   local commandLine = tostring(readInput((termX / 2) - 10, 9, lime))
  1382.   drawElement((termX / 2) - 11, 8, 15, 3, nil, black, "")
  1383.   if string.lower(commandLine) == "quit" or string.lower(commandLine) == "exit" then
  1384.     runState = "quit"
  1385.     kernelState = false
  1386.     return
  1387.   elseif string.lower(commandLine) == "reboot" then
  1388.     runState = "reboot"
  1389.     kernelState = false
  1390.     return
  1391.   elseif string.lower(commandLine) == "reset" then
  1392.     runState = "reset"
  1393.     kernelState = false
  1394.     netSend(commandLine)
  1395.     return
  1396.   elseif string.lower(commandLine) == "lockdown" then
  1397.     flashChoice("lock")
  1398.     secureStatus = "lockdown"
  1399.     netSend(secureStatus)
  1400.   elseif string.lower(commandLine) == "restart" then
  1401.     netSend("restart")
  1402.   elseif string.lower(commandLine) == "son" then
  1403.     netSend("sON")
  1404.   elseif string.lower(commandLine) == "soff" then
  1405.     netSend("sOFF")
  1406.   elseif string.lower(commandLine) == "endcall" or string.lower(commandLine) == "hangup" then
  1407.     flashChoice("end")
  1408.     netSend("endCall")
  1409.   elseif string.lower(commandLine) == "help" or commandLine == "?" then
  1410.     runState = "DialHelp"
  1411.     drawHelpUI()
  1412.     return
  1413.   else
  1414.     if commandLine ~= "" and (commandLine:len() == 7 or commandLine:len() == 9) then
  1415.       if gateStatus ~= "Dialing" and gateStatus ~= "Connected" then
  1416.         dialAddress = string.upper(commandLine)
  1417.         netSend(dialAddress)
  1418.       end
  1419.     end
  1420.   end
  1421.   runState = tempState
  1422.   drawCLI()
  1423. end
  1424.  
  1425. local function goToPage()
  1426.   tempState = runState
  1427.   runState = "goPage"
  1428.   drawElement((termX / 2) - 11, 8, 15, 1, white, gray, "  Go To Page:  ")
  1429.   drawElement((termX / 2) - 11, 9, 15, 2, nil, gray, "")
  1430.   drawElement((termX / 2) - 10, 9, 13, 1, nil, black, "") -- input area bg
  1431.   term.setBackgroundColor(black)
  1432.   local newPage = tonumber(readInput((termX / 2 - 10), 9, lime))
  1433.   drawElement((termX / 2) - 11, 8, 15, 3, nil, black, "")
  1434.   if newPage == nil then newPage = pageNum end
  1435.   if newPage < 1 then newPage = 1 end
  1436.   if newPage > numPages then newPage = numPages end
  1437.   if newPage == numPages then
  1438.     term.setBackgroundColor(black)
  1439.     term.clear()
  1440.   end
  1441.   pageNum = newPage
  1442.   runState = tempState
  1443.   drawCLI()
  1444. end
  1445.  
  1446. local function wrapPerp(perp, side)
  1447.   if peripheral.isPresent(side) then
  1448.     if perp == "A" or perp == "B" then
  1449.       if peripheral.getType(side) == "monitor" then
  1450.         if perp == "B" then
  1451.           if dhdSettings.monA ~= side and dhdSettings.monB ~= side then
  1452.             if peripheral.getType(dhdSettings.monB) == "monitor" then
  1453.               monB.setBackgroundColor(black)
  1454.               monB.clear()
  1455.               monB = "none"
  1456.             end
  1457.             monB = peripheral.wrap(side)
  1458.             dhdSettings.monB = side
  1459.             configChange = true
  1460.             displayStatus()
  1461.           end
  1462.         elseif perp == "A" then
  1463.           if dhdSettings.monA ~= side and dhdSettings.monB ~= side then
  1464.             if peripheral.getType(dhdSettings.monA) == "monitor" then
  1465.               monA.setBackgroundColor(black)
  1466.               monA.clear()
  1467.               monA = "none"
  1468.             end
  1469.             monA = peripheral.wrap(side)
  1470.             dhdSettings.monA = side
  1471.             configChange = true
  1472.             if displayState == "list" then
  1473.               displayGateList()
  1474.             elseif displayState == "info" then
  1475.               displayNotes(tY)
  1476.             end
  1477.           end
  1478.         end
  1479.       end
  1480.     elseif perp == "C" then
  1481.       if peripheral.getType(side) == "modem" then
  1482.         if peripheral.call(side, "isWireless") == true then
  1483.           if hardware.netSide ~= side then
  1484.             if modem then
  1485.               modem.close(dhdSettings.channels.recv)
  1486.               modem.close(dhdSettings.pChannels.recv)
  1487.               modem = nil
  1488.             end
  1489.             hardware.netSide = side
  1490.             modem = peripheral.wrap(hardware.netSide)
  1491.             modem.open(dhdSettings.channels.recv)
  1492.             if dhdSettings.pSync == "ON" then modem.open(dhdSettings.pChannels.recv) end
  1493.           end
  1494.         end
  1495.       end
  1496.     elseif perp == "R" then
  1497.       if peripheral.getType(side) == "modem" then
  1498.         if peripheral.call(side, "isWireless") == true then
  1499.           if hardware.netSide ~= side then
  1500.             if peripheral.getType(hardware.netSide) == "modem" then
  1501.               if peripheral.call(hardware.netSide, "isWireless") == true then
  1502.                 rednet.close(hardware.netSide)
  1503.               end
  1504.             end
  1505.             if dhdSettings.pSync == "ON" then
  1506.               modem.close(dhdSettings.pChannels.recv)
  1507.               modem = nil
  1508.             end
  1509.             hardware.netSide = side
  1510.             rednet.open(hardware.netSide)
  1511.             if dhdSettings.pSync == "ON" then
  1512.               modem = peripheral.wrap(hardware.netSide)
  1513.               modem.open(dhdSettings.pChannels.recv)
  1514.             end
  1515.           end
  1516.         end
  1517.       end
  1518.     end
  1519.   end
  1520. end
  1521.  
  1522. local function keyClick()
  1523.   while true do
  1524.     local _, key = os.pullEvent("key")
  1525.     if key == 59 then     -- F1 (Help)
  1526.       if runState == "Dial" then
  1527.         runState = "DialHelp"
  1528.         drawHelpUI()
  1529.       elseif runState == "Edit" then
  1530.         runState = "EditHelp"
  1531.         drawHelpUI()
  1532.       end
  1533.     elseif key == 199 then -- HOME
  1534.       pageNum = 1
  1535.       drawCLI()
  1536.     elseif key == 207 then -- END
  1537.       pageNum = numPages
  1538.       term.setBackgroundColor(black)
  1539.       term.clear()
  1540.       drawCLI()
  1541.     elseif key == 201 then -- pageUP
  1542.       if runState == "Dial" or runState == "Edit" then
  1543.         if pageNum < numPages then
  1544.           pageNum = pageNum + 1
  1545.           if pageNum == numPages then
  1546.             term.setBackgroundColor(black)
  1547.             term.clear()
  1548.           end
  1549.         end
  1550.       end
  1551.       drawCLI()
  1552.     elseif key == 209 then -- pageDN
  1553.       if runState == "Dial" or runState == "Edit" then
  1554.         if pageNum > 1 then
  1555.           pageNum = pageNum - 1
  1556.         end
  1557.       end
  1558.       drawCLI()
  1559.     end
  1560.   end
  1561. end
  1562.  
  1563. local function mClick()
  1564.   while true do
  1565.     local _, mButton, mcX, mcY = os.pullEvent("mouse_click")
  1566.     -- Menu & Menu Selections
  1567.     if menuState then
  1568.       if mcX > 1 and mcX < 11 then
  1569.         if mcY == 3 and runState == "Dial" then
  1570.           runState = "DialCfg"
  1571.           flashChoice("cfg")
  1572.           menuState = false
  1573.           drawSettingsUI()
  1574.           return
  1575.         elseif mcY == 3 and runState == "Edit" then
  1576.           runState = "EditCfg"
  1577.           flashChoice("cfg")
  1578.           menuState = false
  1579.           drawSettingsUI()
  1580.           return
  1581.         elseif mcY == 5 and (runState == "Dial" or runState == "Edit") then
  1582.           tempState = runState
  1583.           runState = "logs"
  1584.           flashChoice("logs")
  1585.           menuState = false
  1586.           ingestLogData()
  1587.           term.setBackgroundColor(black)
  1588.           term.clear()
  1589.           drawHeader()
  1590.           viewLogs()
  1591.           return
  1592.         elseif mcY == 7 and runState == "Dial" then
  1593.           runState = "DialHelp"
  1594.           flashChoice("dhelp")
  1595.           menuState = false
  1596.           drawHelpUI()
  1597.           return
  1598.         elseif mcY == 7 and runState == "Edit" then
  1599.           runState = "EditHelp"
  1600.           flashChoice("ehelp")
  1601.           menuState = false
  1602.           drawHelpUI()
  1603.           return
  1604.         elseif mcY == 9 then
  1605.           flashChoice("exit")
  1606.           runState = "quit"
  1607.           kernelState = false
  1608.           menuState = false
  1609.           break  -- required to exit properly
  1610.         elseif mcY < 2 or mcY > 10 then
  1611.           menuState = false
  1612.           drawElement(2, 5, 11, 6, nil, black, "") -- clear menu
  1613.           drawCLI()
  1614.           return
  1615.         end
  1616.       else
  1617.         menuState = false
  1618.         drawElement(2, 5, 11, 6, nil, black, "") -- clear menu
  1619.         drawCLI()
  1620.         return
  1621.       end
  1622.     else
  1623.       if runState == "DialHelp" then
  1624.         if mcX > 44 and mcY == 2 then
  1625.           flashChoice("close")
  1626.           term.setBackgroundColor(black)
  1627.           term.clear()
  1628.           runState = "Dial"
  1629.           drawCLI()
  1630.           return
  1631.         end
  1632.       elseif runState == "EditHelp" then
  1633.         if mcX > 44 and mcY == 2 then
  1634.           flashChoice("close")
  1635.           term.setBackgroundColor(black)
  1636.           term.clear()
  1637.           runState = "Edit"
  1638.           drawCLI()
  1639.           return
  1640.         end
  1641.       elseif runState == "logs" then
  1642.         if mcX > 44 and mcY == 2 then
  1643.           flashChoice("close")
  1644.           term.setBackgroundColor(black)
  1645.           term.clear()
  1646.           callHistory = { }
  1647.           lastCall = { }
  1648.           runState = tempState
  1649.           drawCLI()
  1650.           return
  1651.         elseif mcX > 44 and mcY == 4 then
  1652.           flashChoice("clear")
  1653.           local makeSure = areYouSure()
  1654.           if makeSure then
  1655.             local clearLog = fs.open("/data/DHDhistory", "w")
  1656.             clearLog.close()
  1657.             callHistory = { }
  1658.             --lastCall = { }
  1659.             histPages = 1
  1660.             histPage = 1
  1661.           end
  1662.           viewLogs()
  1663.           return
  1664.         end
  1665.       elseif runState == "viewing" then
  1666.         if mcX > 16 and mcX < 36 and mcY == termY-1 then
  1667.           -- Clean up select parts of the screen instead of clearing the entire screen
  1668.           runState = tempState
  1669.           drawElement(2, 7, termX, 1, nil, black, "")
  1670.           drawElement(2, 9, termX, 1, nil, black, "")
  1671.           drawElement(2, 12, 16, 4, nil, black, "")
  1672.           drawElement(13, 12, termX, 1, nil, black, "")
  1673.           drawElement(1, termY-1, termX, 1, nil, black, "")
  1674.           drawCLI()
  1675.           return
  1676.         end
  1677.       elseif runState ~= "DialCfg" and runState ~= "EditCfg" and runState ~= "GateEdit" and runState ~= "viewing" then
  1678.         if mcY == 1 and runState ~= "Trim" then
  1679.           if mcX > 1 and mcX < 9 then
  1680.             menuState = true
  1681.             drawMenu()
  1682.             return
  1683.           end
  1684.         end
  1685.       end
  1686.       -- Command Buttons (change modes, mode operation)
  1687.       if mcX > 41 and mcX <= termX and (runState == "Dial" or runState == "Edit" or runState == "Trim") then
  1688.         if mcY == 7 then
  1689.           if runState == "Dial" then
  1690.             runState = "Edit"
  1691.             drawCLI()
  1692.           elseif runState == "Edit" then
  1693.             runState = "Dial"
  1694.             drawCLI()
  1695.           end
  1696.           return
  1697.         elseif mcY == 9 then
  1698.           if runState == "Dial" and shieldStatus == "OFF" then
  1699.             netSend("sON")
  1700.             return
  1701.           elseif runState == "Dial" and shieldStatus == "ON" and secureStatus == "allclear" then
  1702.             netSend("sOFF")
  1703.             return
  1704.           elseif runState == "Edit" then
  1705.             if #allGates < 23977 then
  1706.               flashChoice("new")
  1707.               gateChange = true
  1708.               if mButton == 1 then
  1709.                 runState = "GateEdit"
  1710.                 viewGateEntry("new")
  1711.               elseif mButton == 2 then
  1712.                 viewGateEntry("newFast")
  1713.               end
  1714.             end
  1715.           end
  1716.         elseif mcY == 11 then
  1717.           if runState == "Dial" then
  1718.             if dhdSettings.ecShield == "ON" then
  1719.               netSend("sON")
  1720.             end
  1721.             if dhdSettings.callEnd == "OFF" or (dhdSettings.callEnd == "ON" and dialAddress ~= "") then
  1722.               flashChoice("end")
  1723.               netSend("endCall")
  1724.               dialAddress = ""
  1725.             end
  1726.           elseif runState == "Edit" then
  1727.             if fs.exists("/disk") then
  1728.               flashChoice("import")
  1729.               ingestData("/disk/data/DHDgates", "gate")
  1730.               term.setBackgroundColor(black)
  1731.               term.clear()
  1732.               drawCLI()
  1733.             end
  1734.           elseif runState == "Trim" then
  1735.             flashChoice("undo")
  1736.             runState = "Edit"
  1737.             ingestData(dhdSettings.gateData, "gate")
  1738.             if gateChange then
  1739.               term.setBackgroundColor(black)
  1740.               term.clear()
  1741.             end
  1742.             gateChange = false
  1743.             drawCLI()
  1744.           end
  1745.           return
  1746.         elseif mcY == 13 then
  1747.           if runState == "Dial" then
  1748.             flashChoice("lock")
  1749.             secureStatus = "lockdown"
  1750.             netSend(secureStatus)
  1751.             sleep(0.1) -- this gives ccDHD time to get updated info from gateLiaison before invoking secureUI()
  1752.           elseif runState == "Edit" then
  1753.             if fs.exists("/disk") then
  1754.               flashChoice("export")
  1755.               saveData("/disk/data/DHDgates", "gate")
  1756.             end
  1757.           elseif runState == "Trim" then
  1758.             flashChoice("commit")
  1759.             runState = "Edit"
  1760.             saveData(dhdSettings.gateData, "gate")
  1761.             gateChange = false
  1762.             drawCLI()
  1763.           end
  1764.           return
  1765.         elseif mcY == 15 then
  1766.           if runState == "Dial" then
  1767.             flashChoice("rcmd")
  1768.             remoteCommand()
  1769.           elseif runState == "Edit" then
  1770.             flashChoice("save")
  1771.             gateChange = false
  1772.             saveData(dhdSettings.gateData, "gate")
  1773.             drawControlUI()
  1774.           end
  1775.           if runState == "reboot" or runState == "reset" or runState == "quit" then break end
  1776.         end
  1777.       end
  1778.     end
  1779.      -- Page Navigation via click
  1780.     if mcY == termY then
  1781.       if runState == "Dial" or runState == "Edit" or runState == "Trim" then
  1782.         if mcX < 20 and mcY == termY then -- Bottom row of screen - Back
  1783.           if pageNum > 1 then
  1784.             pageNum = pageNum - 1
  1785.             term.clear()
  1786.             drawCLI()
  1787.             return
  1788.           end
  1789.         elseif mcX > 19 and mcX < 23 and mcY == termY then -- Bottom row of screen - Page Numbers (Go To Page dialogue)
  1790.           flashChoice("page")
  1791.           goToPage()
  1792.         elseif mcX > 22 and mcY == termY then -- Bottom row of screen - Forward
  1793.           if pageNum < numPages then
  1794.             pageNum = pageNum + 1
  1795.             term.clear()
  1796.             drawCLI()
  1797.             return
  1798.           end
  1799.         end
  1800.       end
  1801.     end
  1802.      -- Dial a listed address, view it's info, edit entry, or enter trim mode & delete gates
  1803.     local j = ((pageNum - 1) * 23) + pageNum
  1804.     local k = ((pageNum - 1) * 23)
  1805.     local l = ((pageNum - 1) * 24)
  1806.     if menuState == false then
  1807.       if mcY > 5 and mcY < 17 then
  1808.         for i = j, #allGates, 1 do
  1809.             -- Addresses Column 1
  1810.           if mcX > 1 and mcX < 11 and mcY == 4 + ((i - l) * 2) and i <= #allGates then
  1811.             if runState == "Dial" then
  1812.               if mButton == 1 and gateStatus ~= "Dialing" and gateStatus ~= "Connected" then
  1813.                 if allGates[i].addr ~= dhdSettings.thisGate and allGates[i].addr ~= "NEWGATE" then
  1814.                   dialAddress = allGates[i].addr
  1815.                   netSend(dialAddress)
  1816.                   return
  1817.                 end
  1818.               elseif mButton == 2 then
  1819.                 viewGateEntry(i)
  1820.                 return
  1821.               end
  1822.             elseif runState == "Edit" then
  1823.               if mButton == 1 then
  1824.                 runState = "GateEdit"
  1825.                 viewGateEntry(i)
  1826.                 return
  1827.               elseif mButton == 2 then
  1828.                 runState = "Trim"
  1829.                 drawCLI()
  1830.                 return
  1831.               end
  1832.             elseif runState == "Trim" then
  1833.               if mButton == 1 then
  1834.                 deleteGate(i)
  1835.                 drawCLI()
  1836.                 return
  1837.               end
  1838.             end
  1839.             -- Addresses Column 2
  1840.           elseif mcX > 11 and mcX < 21 and mcY == 4 + ((i - l) * 2) and (i + 6) <= #allGates then
  1841.             if runState == "Dial" then
  1842.               if mButton == 1 and gateStatus ~= "Dialing" and gateStatus ~= "Connected" then
  1843.                 if allGates[i + 6].addr ~= dhdSettings.thisGate and allGates[i + 6].addr ~= "NEWGATE" then
  1844.                   dialAddress = allGates[i + 6].addr
  1845.                   netSend(dialAddress)
  1846.                   return
  1847.                 end
  1848.               elseif mButton == 2 then
  1849.                 viewGateEntry(i + 6)
  1850.                 return
  1851.               end
  1852.             elseif runState == "Edit" then
  1853.               if mButton == 1 then
  1854.                 runState = "GateEdit"
  1855.                 viewGateEntry(i + 6)
  1856.                 return
  1857.               elseif mButton == 2 then
  1858.                 runState = "Trim"
  1859.                 drawCLI()
  1860.                 return
  1861.               end
  1862.             elseif runState == "Trim" then
  1863.               if mButton == 1 then
  1864.                 deleteGate(i + 6)
  1865.                 drawCLI()
  1866.                 return
  1867.               end
  1868.             end
  1869.             -- Addresses Column 3
  1870.           elseif mcX > 21 and mcX < 31 and mcY == 4 + ((i - l) * 2) and (i + 12) <= #allGates then
  1871.             if runState == "Dial" then
  1872.               if mButton == 1 and gateStatus ~= "Dialing" and gateStatus ~= "Connected" then
  1873.                 if allGates[i + 12].addr ~= dhdSettings.thisGate and allGates[i + 12].addr ~= "NEWGATE" then
  1874.                   dialAddress = allGates[i + 12].addr
  1875.                   netSend(dialAddress)
  1876.                   return
  1877.                 end
  1878.               elseif mButton == 2 then
  1879.                 viewGateEntry(i + 12)
  1880.                 return
  1881.               end
  1882.             elseif runState == "Edit" then
  1883.               if mButton == 1 then
  1884.                 runState = "GateEdit"
  1885.                 viewGateEntry(i + 12)
  1886.                 return
  1887.               elseif mButton == 2 then
  1888.                 runState = "Trim"
  1889.                 drawCLI()
  1890.                 return
  1891.               end
  1892.             elseif runState == "Trim" then
  1893.               if mButton == 1 then
  1894.                 deleteGate(i + 12)
  1895.                 drawCLI()
  1896.                 return
  1897.               end
  1898.             end
  1899.             -- Addresses Column 4
  1900.           elseif mcX > 31 and mcX < 41 and mcY == 4 + ((i - l) * 2) and (i + 18) <= #allGates then
  1901.             if runState == "Dial" then
  1902.               if mButton == 1 and gateStatus ~= "Dialing" and gateStatus ~= "Connected" then
  1903.                 if allGates[i + 18].addr ~= dhdSettings.thisGate and allGates[i + 18].addr ~= "NEWGATE" then
  1904.                   dialAddress = allGates[i + 18].addr
  1905.                   netSend(dialAddress)
  1906.                 end
  1907.               elseif mButton == 2 then
  1908.                 viewGateEntry(i + 18)
  1909.                 return
  1910.               end
  1911.             elseif runState == "Edit" then
  1912.               if mButton == 1 then
  1913.                 runState = "GateEdit"
  1914.                 viewGateEntry(i + 18)
  1915.                 return
  1916.               elseif mButton == 2 then
  1917.                 runState = "Trim"
  1918.                 drawCLI()
  1919.                 return
  1920.               end
  1921.             elseif runState == "Trim" then
  1922.               if mButton == 1 then
  1923.                 deleteGate(i + 18)
  1924.                 drawCLI()
  1925.                 return
  1926.               end
  1927.             end
  1928.           end
  1929.         end
  1930.       end
  1931.     end
  1932.     -- Gate Editing
  1933.     if runState == "GateEdit" then
  1934.       if mcY == 7 then
  1935.          -- Edit Gate Address
  1936.         if mcX > 1 and mcX < 11 then
  1937.           drawElement(2, 7, #allGates[currentEdit].addr, 1, gray, black, allGates[currentEdit].addr)
  1938.           local newGate = string.upper(tostring(readInput(2, 7, yellow)))
  1939.           if newGate ~= "" and newGate ~= "NIL" and newGate:len() > 6 and newGate:len() < 10 then
  1940.             allGates[currentEdit].addr = newGate
  1941.             gateChange = true
  1942.           end
  1943.           local gColor = assignColor(currentEdit)
  1944.           drawElement(2, 7, 1, 1, gColor, black, allGates[currentEdit].addr .. "  ")
  1945.          -- Edit Gate Rating/Classification
  1946.         elseif mcX > 13 and mcX < 30 then
  1947.           term.setBackgroundColor(black)
  1948.           term.setTextColor(yellow)
  1949.           drawRatingList(allGates[currentEdit].rating)
  1950.           local newRating = { os.pullEvent("mouse_click") }
  1951.           if newRating[3] > 14 and newRating[3] < 33 then
  1952.             if newRating[4] == 6 then
  1953.               if allGates[currentEdit].rating ~= "B" then
  1954.                 allGates[currentEdit].rating = "B"
  1955.                 gateChange = true
  1956.               end
  1957.             elseif newRating[4] == 7 then
  1958.               if allGates[currentEdit].rating ~= "H" then
  1959.                 allGates[currentEdit].rating = "H"
  1960.                 gateChange = true
  1961.               end
  1962.             elseif newRating[4] == 8 then
  1963.               if allGates[currentEdit].rating ~= "V" then
  1964.                 allGates[currentEdit].rating = "V"
  1965.                 gateChange = true
  1966.               end
  1967.             elseif newRating[4] == 9 then
  1968.               if allGates[currentEdit].rating ~= "M" then
  1969.                 allGates[currentEdit].rating = "M"
  1970.                 gateChange = true
  1971.               end
  1972.             elseif newRating[4] == 10 then
  1973.               if allGates[currentEdit].rating ~= "S" then
  1974.                 allGates[currentEdit].rating = "S"
  1975.                 gateChange = true
  1976.               end
  1977.             elseif newRating[4] == 11 then
  1978.               if allGates[currentEdit].rating ~= "C" then
  1979.                 allGates[currentEdit].rating = "C"
  1980.                 gateChange = true
  1981.               end
  1982.             elseif newRating[4] == 12 then
  1983.               if allGates[currentEdit].rating ~= "D" then
  1984.                 allGates[currentEdit].rating = "D"
  1985.                 gateChange = true
  1986.               end
  1987.             elseif newRating[4] == 13 then
  1988.               if allGates[currentEdit].rating ~= "U" then
  1989.                 allGates[currentEdit].rating = "U"
  1990.                 gateChange = true
  1991.               end
  1992.             end
  1993.           end
  1994.           drawElement(2, 9, termX, 2, nil, black, "")
  1995.           drawElement(14, 5, 20, 10, nil, black, "")
  1996.           local gtColor = assignColor(currentEdit)
  1997.           local gtRating = assignRating(currentEdit)
  1998.           drawElement(2, 7, #allGates[currentEdit].addr, 1, gtColor, black, allGates[currentEdit].addr)
  1999.           drawElement(14, 7, #gtRating, 1, gray, black, gtRating)
  2000.           drawElement(13, 12, #allGates[currentEdit].loc.dim, 1, lblue, black, allGates[currentEdit].loc.dim)
  2001.           drawElement(2, 9, #allGates[currentEdit].note, 1, white, black, allGates[currentEdit].note)
  2002.         end
  2003.        -- Edit Gate Notes
  2004.       elseif mcY > 8 and mcY < 11 then
  2005.         if mcX < 40 then
  2006.           drawElement(2, 9, #allGates[currentEdit].note, 1, gray, black, allGates[currentEdit].note)
  2007.           term.setBackgroundColor(black)
  2008.           local newNote = tostring(readInput(2, 9, white))
  2009.           if newNote ~= "" and newNote ~= "nil" then
  2010.             allGates[currentEdit].note = newNote
  2011.             gateChange = true
  2012.           end
  2013.           drawElement(2, 9, termX, 2, nil, black, "")
  2014.           drawElement(2, 9, #allGates[currentEdit].note, 1, white, black, allGates[currentEdit].note)
  2015.         end
  2016.          -- Gate Dimension
  2017.       elseif mcY == 12 then
  2018.         if mcX > 12 and mcX < 32 then
  2019.           drawElement(13, 12, #allGates[currentEdit].loc.dim, 1, gray, black, allGates[currentEdit].loc.dim)
  2020.           local newDim = tostring(readInput(13, 12, lblue))
  2021.           if newDim ~= "" and tostring(newDim) ~= "nil" then
  2022.             allGates[currentEdit].loc.dim = newDim
  2023.             drawElement(13, 12, 38, 1, nil, black, "")
  2024.             gateChange = true
  2025.           end
  2026.           drawElement(13, 12, 5, 1, nil, black, "")
  2027.           drawElement(13, 12, #allGates[currentEdit].loc.dim, 1, lblue, black, allGates[currentEdit].loc.dim)
  2028.         end
  2029.          -- Gate X position
  2030.       elseif mcY == 13 then
  2031.         if mcX > 4 and mcX < 10 then
  2032.           local oldX = tostring(allGates[currentEdit].loc.x)
  2033.           drawElement(5, 13, 1, 1, gray, black, oldX)
  2034.           local newX = tonumber(readInput(5, 13, brown))
  2035.           if tostring(newX) ~= "" and newX ~= nil and newX ~= allGates[currentEdit].loc.x then
  2036.             allGates[currentEdit].loc.x = newX
  2037.             gateChange = true
  2038.           end
  2039.           drawElement(5, 13, 6, 1, nil, black, "")
  2040.           local tmpX = tostring(allGates[currentEdit].loc.x)
  2041.           drawElement(5, 13, 1, 1, brown, black, tmpX)
  2042.         end
  2043.          -- Gate Y position
  2044.       elseif mcY == 14 then
  2045.         if mcX > 4 and mcX < 10 then
  2046.           local oldY = tostring(allGates[currentEdit].loc.y)
  2047.           drawElement(5, 14, #oldY, 1, gray, black, oldY)
  2048.           local newY = tonumber(readInput(5, 14, brown))
  2049.           if tostring(newY) ~= "" and newY ~= nil and newY ~= allGates[currentEdit].loc.y then
  2050.             allGates[currentEdit].loc.y = newY
  2051.             gateChange = true
  2052.           end
  2053.           drawElement(5, 14, 6, 1, nil, black, "")
  2054.           local tmpY = tostring(allGates[currentEdit].loc.y)
  2055.           drawElement(5, 14, #tmpY, 1, brown, black, tmpY)
  2056.         end
  2057.          -- Gate Z position
  2058.       elseif mcY == 15 then
  2059.         if mcX > 4 and mcX < 10 then
  2060.           local oldZ = tostring(allGates[currentEdit].loc.z)
  2061.           drawElement(5, 15, #oldZ, 1, gray, black, oldZ)
  2062.           local newZ = tonumber(readInput(5, 15, brown))
  2063.           if tostring(newZ) ~= "" and newZ ~= nil and newZ ~= allGates[currentEdit].loc.z then
  2064.             allGates[currentEdit].loc.z = newZ
  2065.             gateChange = true
  2066.           end
  2067.           drawElement(5, 15, 6, 1, nil, black, "")
  2068.           local tmpZ = tostring(allGates[currentEdit].loc.z)
  2069.           drawElement(5, 15, #tmpZ, 1, brown, black, tmpZ)
  2070.         end
  2071.         -- Exit Edit Screen
  2072.       elseif mcY == (termY-1) then
  2073.         runState = "Edit"
  2074.         drawElement(2, 7, termX, termY, nil, black, "")
  2075.         drawCLI()
  2076.       end
  2077.     end
  2078.   end
  2079. end
  2080.  
  2081. local function mClickSettings()
  2082.   while true do
  2083.     local _, mButton, mcX, mcY = os.pullEvent("mouse_click")
  2084.       -- ccDHD Settings
  2085.     if runState == "DialCfg" or runState == "EditCfg" then
  2086.       local cfgPos = { 5, 7, 9, 11, 13, 15 }
  2087.       local cfgSides = { "top", "bottom", "front", "back", "left", "right" }
  2088.         -- Save Settings
  2089.       if mcY == 2 and mcX > 38 and mcX < 45 then
  2090.         flashChoice("cfgsave")
  2091.         saveData(settingsData, "cfg")
  2092.         configChange = false
  2093.         drawSettingsUI()
  2094.         -- Close Settings (no save)
  2095.       elseif mcY == 2 and mcX > 44 and mcX <= termX then
  2096.         flashChoice("close")
  2097.         if runState == "DialCfg" then
  2098.           runState = "Dial"
  2099.         elseif runState == "EditCfg" then
  2100.           runState = "Edit"
  2101.         end
  2102.         term.setBackgroundColor(black)
  2103.         term.clear()
  2104.         drawCLI()
  2105.         return
  2106.       end
  2107.         -- Settings Column 1
  2108.         -- Edit thisGate
  2109.       if mcY == 4 and mcX > 16 and mcX < 27 then
  2110.         drawElement(17, 4, #dhdSettings.thisGate, 1, gray, black, dhdSettings.thisGate)
  2111.         local newGate = string.upper(tostring(readInput(17, 4, cyan)))
  2112.         if newGate ~= "" and newGate ~= "NIL" and newGate ~= dhdSettings.thisGate and newGate:len() > 6 and newGate:len() < 10 then
  2113.           configChange = true
  2114.           dhdSettings.thisGate = newGate
  2115.           longName = makeLongName(dhdSettings.thisGate)
  2116.           if gateStatus == "Disconnected" then displayMarquee() end
  2117.         end
  2118.         drawElement(16, 4, 9, 1, nil, black, "")
  2119.         drawSettingsUI()
  2120.         -- Change LOCKDOWN Password
  2121.       elseif mcY == 6 and mcX > 16 and mcX < 31 then
  2122.         drawElement(17, 6, #dhdSettings.password, 1, gray, black, dhdSettings.password)
  2123.         local newPass = tostring(readInput(17, 6, orange))
  2124.         if newPass ~= "" and newPass ~= "nil" and newPass ~= dhdSettings.password then
  2125.           configChange = true
  2126.           dhdSettings.password = newPass
  2127.         end
  2128.         drawElement(17, 6, 11, 1, nil, black, "")
  2129.         drawSettingsUI()
  2130.         -- Biolock ON/OFF
  2131.       elseif mcY == 8 and mcX > 16 and mcX < 21 and dhdSettings.bio.lock ~= "none" then
  2132.         if hardware.bioSide ~= "none" then
  2133.           if dhdSettings.bio.lock == "ON" then
  2134.             dhdSettings.bio.lock = "OFF"
  2135.             configChange = true
  2136.           elseif dhdSettings.bio.lock == "OFF" then
  2137.             dhdSettings.bio.lock = "ON"
  2138.             configChange = true
  2139.           end
  2140.         end
  2141.         drawSettingsUI()
  2142.       elseif mcY == 8 and mcX > 22 and mcX < 24 and dhdSettings.bio.lock ~= "none" then
  2143.         drawAuthList(dhdSettings.bio.auth)
  2144.         local bioAuth = { os.pullEvent("mouse_click") }
  2145.         if bioAuth[3] > 26 and bioAuth[2] < 31 then
  2146.           local secPos = { 5, 7, 9, 11, 13 }
  2147.           for j, k in ipairs(secPos) do
  2148.             if bioAuth[4] == k then
  2149.               dhdSettings.bio.auth = j
  2150.               configChange = true
  2151.               break
  2152.             end
  2153.           end
  2154.         end
  2155.         drawSettingsUI()
  2156.         -- redNet/ccNet
  2157.       elseif mcY == 10 and mcX > 16 and mcX < 21 then
  2158.         if dhdSettings.net == "R" then
  2159.           netSend("ccNet")
  2160.           rednet.close(hardware.netSide)
  2161.           dhdSettings.net = "C"
  2162.           if not modem then modem = peripheral.wrap(hardware.netSide) end
  2163.           modem.open(dhdSettings.channels.recv)
  2164.           saveData(settingsData, "cfg")
  2165.         elseif dhdSettings.net == "C" then
  2166.           netSend("redNet")
  2167.           modem.close(dhdSettings.channels.recv)
  2168.           if dhdSettings.pSync == "OFF" then modem = nil end
  2169.           dhdSettings.net = "R"
  2170.           rednet.open(hardware.netSide)
  2171.           saveData(settingsData, "cfg")
  2172.         end
  2173.         drawSettingsUI()
  2174.       elseif mcY == 10 and mcX > 22 and mcX < 24 then
  2175.         -- Select redNet Side
  2176.         if dhdSettings.net == "R" then
  2177.           drawSideList(hardware.netSide)
  2178.           local modemSide = { os.pullEvent("mouse_click") }
  2179.           if modemSide[3] > 26 and modemSide[2] < 35 then
  2180.             for jr, kr in ipairs(cfgPos) do
  2181.               if modemSide[4] == kr then
  2182.                 wrapPerp("R", cfgSides[jr])
  2183.                 break
  2184.               end
  2185.             end
  2186.           end
  2187.           drawSettingsUI()
  2188.         -- Select ccNet Side
  2189.         elseif dhdSettings.net == "C" then
  2190.           drawSideList(hardware.netSide)
  2191.           local modemSide = { os.pullEvent("mouse_click") }
  2192.           if modemSide[3] > 26 and modemSide[2] < 35 then
  2193.             for jc, kc in ipairs(cfgPos) do
  2194.               if modemSide[4] == kc then
  2195.                 wrapPerp("C", cfgSides[jc])
  2196.                 break
  2197.               end
  2198.             end
  2199.           end
  2200.           drawSettingsUI()
  2201.         end
  2202.         -- Change redNet gateLiaison / ccNet Receive Channel
  2203.       elseif mcY == 12 and mcX > 16 and mcX < 22 then
  2204.         if dhdSettings.net == "R" then
  2205.           drawElement(17, 12, #tostring(dhdSettings.gate), 1, gray, black, dhdSettings.gate)
  2206.           local newGate = tonumber(readInput(17, 12, red))
  2207.           if tostring(newGate) ~= "" and newGate ~= nil and newGate ~= dhdSettings.gate and newGate < 65536 and newGate >= 0 then
  2208.             dhdSettings.gate = newGate
  2209.             configChange = true
  2210.           end
  2211.           drawSettingsUI()
  2212.         elseif dhdSettings.net == "C" then
  2213.           local ccRec = tostring(dhdSettings.channels.recv) .. string.rep(" ", 5-#tostring(dhdSettings.channels.recv))
  2214.           drawElement(17, 12, #ccRec, 1, gray, black, ccRec)
  2215.           local newChannel = tonumber(readInput(17, 12, green))
  2216.           if tostring(newChannel) ~= "" and newChannel ~= nil and newChannel ~= dhdSettings.channels.recv and newChannel ~= dhdSettings.channels.send and newChannel ~= dhdSettings.pChannels.send and newChannel ~= dhdSettings.pChannels.recv and newChannel < 65536 and newChannel > 0 then
  2217.             netSend("CR")
  2218.             sleep(0.1)
  2219.             netSend(newChannel)
  2220.             modem.close(dhdSettings.channels.recv)
  2221.             dhdSettings.channels.recv = newChannel
  2222.             modem.open(dhdSettings.channels.recv)
  2223.             saveData(settingsData, "cfg")
  2224.           end
  2225.           drawElement(17, 12, 5, 1, nil, black, "")
  2226.           drawSettingsUI()
  2227.         end
  2228.         -- Change ccNet Send Channel
  2229.       elseif mcY == 12 and mcX > 10 and mcX < 16 then
  2230.         if dhdSettings.net == "C" then
  2231.           local ccSnd = tostring(dhdSettings.channels.send) .. string.rep(" ", 5-#tostring(dhdSettings.channels.send))
  2232.           drawElement(11, 12, #ccSnd, 1, gray, black, ccSnd)
  2233.           local newSend = tonumber(readInput(11, 12, green))
  2234.           if tostring(newSend) ~= "" and newSend ~= nil and newSend ~= dhdSettings.channels.send and newSend ~= dhdSettings.channel.recv and newSend~= dhdSettings.pChannels.send and newSend ~= dhdSettings.pChannels.recv and newSend < 65536 and newSend > 0 then
  2235.             netSend("CS")
  2236.             sleep(0.1)
  2237.             netSend(newSend)
  2238.             dhdSettings.channels.send = newSend
  2239.             saveData(settingsData, "cfg")
  2240.           end
  2241.           drawElement(11, 12, 5, 1, nil, black, "")
  2242.           drawSettingsUI()
  2243.         end
  2244.         -- Select Marquee Side
  2245.       elseif mcY == 14 and mcX < 24 then
  2246.         if mcX > 16 and mcX < 21  and dhdSettings.monB ~= "none" then
  2247.           monB.setBackgroundColor(black)
  2248.           monB.clear()
  2249.           monB = nil
  2250.           dhdSettings.monB = "none"
  2251.           configChange = true
  2252.         elseif mcX > 22 and mcX < 24 then
  2253.           drawSideList(dhdSettings.monB)
  2254.           local monBSide = { os.pullEvent("mouse_click") }
  2255.           if monBSide[3] > 26 and monBSide[2] < 35 then
  2256.             for jb, kb in ipairs(cfgPos) do
  2257.               if monBSide[4] == kb then
  2258.                 wrapPerp("B", cfgSides[jb])
  2259.                 break
  2260.               end
  2261.             end
  2262.           end
  2263.         end
  2264.         drawSettingsUI()
  2265.         -- Select List Monitor Side
  2266.       elseif mcY == 16 and mcX < 24 then
  2267.         if mcX > 16 and mcX < 21  and dhdSettings.monA ~= "none" then
  2268.           monA.setBackgroundColor(black)
  2269.           monA.clear()
  2270.           monA = nil
  2271.           dhdSettings.monA = "none"
  2272.           configChange = true
  2273.         elseif mcX > 22 and mcX < 24 then
  2274.           drawSideList(dhdSettings.monA)
  2275.           local monASide = { os.pullEvent("mouse_click") }
  2276.           if monASide[3] > 26 and monASide[2] < 35 then
  2277.             for jb, kb in ipairs(cfgPos) do
  2278.               if monASide[4] == kb then
  2279.                 wrapPerp("A", cfgSides[jb])
  2280.                 break
  2281.               end
  2282.             end
  2283.           end
  2284.         end
  2285.         drawSettingsUI()
  2286.         -- Settings Column 2
  2287.         -- Highlight thisGate in Dial/Edit/Trim modes & on List monitor
  2288.       elseif mcY == 4 and mcX > 44 and mcX < 49 then
  2289.         if dhdSettings.highlight == "YES" then
  2290.           dhdSettings.highlight = "NO"
  2291.           configChange = true
  2292.         elseif dhdSettings.highlight == "NO" then
  2293.           dhdSettings.highlight = "YES"
  2294.           configChange = true
  2295.         end
  2296.         drawSettingsUI()
  2297.         -- pSync ON/OFF for ccDialer
  2298.       elseif mcY == 6 and mcX > 44 and mcX < 49 then
  2299.         if dhdSettings.pSync == "ON" then
  2300.           dhdSettings.pSync = "OFF"
  2301.           modem.close(dhdSettings.pChannels.recv)
  2302.           configChange = true
  2303.         elseif dhdSettings.pSync == "OFF" then
  2304.           dhdSettings.pSync = "ON"
  2305.           if not modem then modem = peripheral.wrap(hardware.netSide) end
  2306.           modem.open(dhdSettings.pChannels.recv)
  2307.           configChange = true
  2308.         end
  2309.         drawSettingsUI()
  2310.         -- Bioscanner function (shield/lockdown)
  2311.       elseif mcY == 8 and mcX > 44 and mcX < 49 then
  2312.         if dhdSettings.bio.func == "none" then
  2313.           dhdSettings.bio.func = "shield"
  2314.           configChange = true
  2315.         elseif dhdSettings.bio.func == "shield" then
  2316.           dhdSettings.bio.func = "lock"
  2317.           configChange = true
  2318.         elseif dhdSettings.bio.func == "lock" then
  2319.           dhdSettings.bio.func = "none"
  2320.           configChange = true
  2321.         end
  2322.         drawSettingsUI()
  2323.         -- Startup Shield (ON/OFF)
  2324.       elseif mcY == 10 and mcX > 44 and mcX < 49 then
  2325.         if dhdSettings.startShield == "ON" then
  2326.           dhdSettings.startShield = "OFF"
  2327.           configChange = true
  2328.         elseif dhdSettings.startShield == "OFF" then
  2329.           dhdSettings.startShield = "ON"
  2330.           configChange = true
  2331.         end
  2332.         drawSettingsUI()
  2333.         -- End Call Shield (ON/OFF)
  2334.       elseif mcY == 12 and mcX > 44 and mcX < 49 then
  2335.         if dhdSettings.ecShield == "ON" then
  2336.           dhdSettings.ecShield = "OFF"
  2337.           configChange = true
  2338.         elseif dhdSettings.ecShield == "OFF" then
  2339.           dhdSettings.ecShield = "ON"
  2340.           configChange = true
  2341.         end
  2342.         drawSettingsUI()
  2343.         -- Call Logging (ON/OFF)
  2344.       elseif mcY == 14 and mcX > 44 and mcX < 49 then
  2345.         if dhdSettings.logs == "ON" then
  2346.           dhdSettings.logs = "OFF"
  2347.           configChange = true
  2348.         elseif dhdSettings.logs == "OFF" then
  2349.           dhdSettings.logs = "ON"
  2350.           configChange = true
  2351.         end
  2352.         drawSettingsUI()
  2353.         -- Call Initiator ONLY for endCall (ON/OFF)
  2354.       elseif mcY == 16 and mcX > 44 and mcX < 49 then
  2355.         if dhdSettings.callEnd == "ON" then
  2356.           dhdSettings.callEnd = "OFF"
  2357.           configChange = true
  2358.         elseif dhdSettings.callEnd == "OFF" then
  2359.           dhdSettings.callEnd = "ON"
  2360.           configChange = true
  2361.         end
  2362.         drawSettingsUI()
  2363.       end
  2364.     end
  2365.   end
  2366. end
  2367.  
  2368. local function mScroll()
  2369.   while true do
  2370.     local _, scrollEvent = os.pullEvent("mouse_scroll")
  2371.     menuState = false
  2372.     if runState == "Dial" or runState == "Edit" or runState == "Trim" then
  2373.       pageNum = scrollEvent == 1 and math.min(pageNum + 1, numPages) or math.max(pageNum - 1, 1)
  2374.       if pageNum == numPages then
  2375.         term.setBackgroundColor(black)
  2376.         term.clear()
  2377.       end
  2378.       drawCLI()
  2379.     elseif runState == "logs" then
  2380.       histPage = scrollEvent == 1 and math.min(histPage + 1, histPages) or math.max(histPage - 1, 1)
  2381.       viewLogs()
  2382.     end
  2383.   end
  2384. end
  2385.  
  2386. local function monTouch()
  2387.   while true do
  2388.     local touchEvent = { os.pullEvent("monitor_touch") }
  2389.     if touchEvent[2] == dhdSettings.monA and displayState == "info" then
  2390.       displayState = "list"
  2391.       drawCLI()  -- Maybe change monitor events to displayStatus() or something separate from CLI
  2392.     elseif touchEvent[2] == dhdSettings.monA and displayState == "list" then
  2393.       local tX = touchEvent[3]
  2394.       tY = touchEvent[4]
  2395.       if tY < 9 then
  2396.         displayState = "info"
  2397.         if dhdSettings.monB ~= "none" then displayNotes(tY) end
  2398.       elseif tY > 8 then
  2399.         if tX < 10 then
  2400.           listPage = listPage - 1
  2401.           if listPage < 1 then listPage = 1 end
  2402.           displayGateList()
  2403.         elseif tX > 9 then
  2404.           listPage = listPage + 1
  2405.           if listPage > listPages then listPage = listPages end
  2406.           displayGateList()
  2407.         end
  2408.       end
  2409.     elseif touchEvent[2] == dhdSettings.monB and displayState == "info" and gateStatus == "Disconnected" and secureStatus == "allclear" then
  2410.       local dialNum = (tY + ((listPage - 1) * 8))
  2411.       if dialNum > #allGates then dialNum = #allGates end
  2412.       dialAddress = allGates[dialNum].addr
  2413.       if dialAddress == dhdSettings.thisGate then return end
  2414.       gateStatus = "Dialing"
  2415.       netSend(dialAddress)
  2416.     elseif touchEvent[2] == dhdSettings.monB and gateStatus ~= "Disconnected" and secureStatus == "allclear" then
  2417.       netSend("endCall")
  2418.     end
  2419.   end
  2420. end
  2421.  
  2422. local function bioAnimation()
  2423.   while true do
  2424.     for i = 2, 20, 1 do
  2425.       term.setCursorPos(i, 4)
  2426.       term.setBackgroundColor(blue)
  2427.       term.write(" ")
  2428.       term.setBackgroundColor(black)
  2429.       term.setCursorPos(i - 1, 4)
  2430.       term.write(" ")
  2431.       sleep(0.04)
  2432.     end
  2433.     for i = 20, 2, -1 do
  2434.       term.setCursorPos(i, 4)
  2435.       term.setBackgroundColor(blue)
  2436.       term.write(" ")
  2437.       term.setBackgroundColor(black)
  2438.       term.setCursorPos(i + 1, 4)
  2439.       term.write(" ")
  2440.       sleep(0.04)
  2441.     end
  2442.   end
  2443. end
  2444.  
  2445. local function bioScan()
  2446.   while true do
  2447.     local fistPrint = {os.pullEvent("biolock")}
  2448.     if runState == "init" then
  2449.       if fistPrint[5] >= dhdSettings.bio.auth then
  2450.         fistAuth = true
  2451.       end
  2452.       return fistAuth
  2453.     else
  2454.       --if fistPrint[5] >= dhdSettings.bio.auth - 1 then -- one level less than 'unlock' to activate shield/lockdown
  2455.         if dhdSettings.bio.func == "shield" then
  2456.           if shieldStatus == "OFF" then
  2457.             netSend("sON")
  2458.           elseif shieldStatus == "ON" then
  2459.             netSend("sOFF")
  2460.           else
  2461.             netSend("sON")
  2462.           end
  2463.         elseif dhdSettings.bio.func == "lock" then
  2464.           if secureStatus == "allclear" then
  2465.             secureStatus = "lockdown"
  2466.             netSend("lockdown")
  2467.             return
  2468.           end
  2469.         end
  2470.       --end
  2471.     end
  2472.   end
  2473. end
  2474.  
  2475. local function bioLogin()
  2476.   local bio = peripheral.wrap(hardware.bioSide)
  2477.   fistAuth = false
  2478.   term.setBackgroundColor(black)
  2479.   term.clear()
  2480.   drawElement(2, 2, 19, 1, yellow, black, "Waiting for Bioscan")
  2481.   if monA ~= "none" then
  2482.     monA.setBackgroundColor(black)
  2483.     monA.setTextColor(yellow)
  2484.     monA.setTextScale(1)
  2485.     monA.setCursorPos(1, 2)
  2486.     monA.write("Waiting")
  2487.     monA.setCursorPos(3, 3)
  2488.     monA.write("for")
  2489.     monA.setCursorPos(1, 4)
  2490.     monA.write("Bioscan")
  2491.   end
  2492.   while fistAuth == false do
  2493.     local fistPrint = parallel.waitForAny(bioScan, bioAnimation)
  2494.     if fistAuth then
  2495.       bio = nil
  2496.       return fistAuth
  2497.     end
  2498.   end
  2499. end
  2500.  
  2501. local function secKernel()       -- LOCKDOWN handler
  2502.   drawSecureUI()
  2503.   local passSymbols = { "!", "@", "#", "$", "%", "*", "?", "+", "x", "X" }
  2504.   while secureStatus == "lockdown" do
  2505.     drawElement(termX / 2, 15, termX, 1, nil, black, "")
  2506.     term.setCursorPos(termX / 2, 15)
  2507.     term.setTextColor(yellow)
  2508.     local securePass = tostring(read(passSymbols[math.random(1, #passSymbols)]))
  2509.     if securePass == dhdSettings.password then
  2510.       netSend("allclear")
  2511.       if dhdSettings.net == "R" then
  2512.         local senderID, message = rednet.receive(1)
  2513.         if senderID == dhdSettings.gate and (message == "YY0" or message == "YY1") then
  2514.           secureStatus = "allclear"
  2515.         end
  2516.       elseif dhdSettings.net == "C" then
  2517.         local ccNetEvent = { os.pullEvent("modem_message") }
  2518.         if ccNetEvent[3] == dhdSettings.channels.recv and ccNetEvent[4] == dhdSettings.channels.send and (ccNetEvent[5] == "YY0" or ccNetEvent[5] == "YY1") then
  2519.           secureStatus = "allclear"
  2520.         end
  2521.       end
  2522.       drawElement(15, 9, termX, 1, nil, black, "")
  2523.       drawElement(15, 15, termX, 1, nil, black, "")
  2524.       netSend("QRY")
  2525.       drawCLI()
  2526.       break
  2527.     end
  2528.   end
  2529. end
  2530.  
  2531. local function dhdKernel()
  2532.   if kernelState == true and secureStatus == "lockdown" then
  2533.     secKernel()
  2534.   elseif kernelState == true and secureStatus == "allclear" then
  2535.     if runState ~= "DialCfg" and runState ~= "EditCfg" and runState ~= "rCmd" and runState ~= "goPage" and dhdSettings.pSync == "ON" then
  2536.       parallel.waitForAny(keyClick, mClick, mScroll, bioScan, monTouch, netReceive, pSyncReceive)
  2537.     elseif runState ~= "DialCfg" and runState ~= "EditCfg" and runState ~= "rCmd" and runState ~= "goPage" and dhdSettings.pSync == "OFF" then
  2538.       parallel.waitForAny(keyClick, mClick, mScroll, bioScan, monTouch, netReceive)
  2539.     elseif (runState == "DialCfg" or runState == "EditCfg") and dhdSettings.pSync == "ON" then
  2540.       parallel.waitForAny(keyClick, mClickSettings, bioScan, monTouch, netReceive, pSyncReceive)
  2541.     elseif (runState == "DialCfg" or runState == "EditCfg") and dhdSettings.pSync == "OFF" then
  2542.       parallel.waitForAny(keyClick, mClickSettings, bioScan, monTouch, netReceive)
  2543.     end
  2544.   end
  2545.   if runState == "reset" then
  2546.     netSend("reset")
  2547.     kernelState = false
  2548.   end
  2549.   if runState == "quit" then
  2550.     kernelState = false
  2551.   end
  2552.   return kernelState
  2553. end
  2554.  
  2555. local function missingComponent(id)
  2556.   term.setBackgroundColor(black)
  2557.   term.clear()
  2558.   if id == "modem" then
  2559.     drawElement(2, 2, 27, 1, red, black, "No wireless modem detected!")
  2560.     drawElement(2, 4, 32, 1, red, black, "ccDHD REQUIRES a wireless modem.")
  2561.   elseif id == "cfg" then
  2562.     drawElement(2, 2, 20, 1, red, black, "Please restart ccDHD")
  2563.     drawElement(2, 4, 18, 1, red, black, "to complete setup.")
  2564.   else
  2565.     drawElement(2, 2, 26, 1, red, black, "Unknown component missing!")
  2566.     drawElement(2, 4, 27, 1, red, black, "ccDHD REQUIRES a something.")
  2567.   end
  2568.   term.setCursorPos(1, 8)
  2569.   runState = "quit"
  2570.   kernelState = false
  2571. end
  2572.  
  2573. local function detectHardware(hType)
  2574.   if hType == "bio" then
  2575.     hardware.bioSide = "none"
  2576.     for _, bSide in ipairs(rs.getSides()) do
  2577.       if peripheral.isPresent(bSide) then
  2578.         if peripheral.getType(bSide) == "biolock" then
  2579.           hardware.bioSide = bSide
  2580.           break
  2581.         end
  2582.       end
  2583.     end
  2584.     if hardware.bioSide == "none" then -- This accounts for a removed scanner
  2585.       dhdSettings.bio.lock = "OFF"     --
  2586.     end
  2587.     return
  2588.   elseif hType == "modem" then
  2589.     if modem then
  2590.       modem.close(dhdSettings.channels.recv)
  2591.       modem.close(dhdSettings.pChannels.recv)
  2592.       modem = nil
  2593.     end
  2594.     hardware.netSide = "none"
  2595.     local side
  2596.     for _, side in ipairs(rs.getSides()) do
  2597.       if peripheral.isPresent(tostring(side)) then
  2598.         local perp = peripheral.getType(tostring(side))
  2599.         if tostring(perp) == "modem" then
  2600.           if peripheral.call(tostring(side), "isWireless") == true then
  2601.             hardware.netSide = side
  2602.             if dhdSettings.net == "R" then
  2603.               rednet.open(hardware.netSide)
  2604.             elseif dhdSettings.net == "C" then
  2605.               modem = peripheral.wrap(hardware.netSide)
  2606.               modem.open(dhdSettings.channels.recv)
  2607.             end
  2608.             break
  2609.           end
  2610.         end
  2611.       end
  2612.     end
  2613.     return
  2614.   elseif hType == "mon" then
  2615.     dhdSettings.monA = "none"
  2616.     dhdSettings.monB = "none"
  2617.     local side
  2618.     for _, side in ipairs(rs.getSides()) do
  2619.       if peripheral.isPresent(tostring(side)) then
  2620.         local perp = peripheral.getType(tostring(side))
  2621.         if tostring(perp) == "monitor" and peripheral.call(side, "isColor") then
  2622.           peripheral.call(side, "setTextScale", 1)
  2623.           local tmX, tmY = peripheral.call(side, "getSize")
  2624.           if tmX == 7 then
  2625.             dhdSettings.monA = side
  2626.           elseif tmX == 29 then
  2627.             dhdSettings.monB = side
  2628.           end
  2629.         end
  2630.       end
  2631.     end
  2632.     return
  2633.   end
  2634. end
  2635.  
  2636. local function firstRun()
  2637.   netSend("1stRun")
  2638.   sleep(0.1)
  2639.   netSend(os.getComputerID())
  2640.   while true do
  2641.     local myGateInfo = { os.pullEvent("modem_message") }
  2642.     if myGateInfo[3] == dhdSettings.channels.recv and myGateInfo[4] == dhdSettings.channels.send then
  2643.       local tempSettings = myGateInfo[5]
  2644.       dhdSettings.thisGate = tempSettings.addr
  2645.       allGates[1].addr = dhdSettings.thisGate
  2646.       dhdSettings.gate = tempSettings.gate
  2647.       break
  2648.     end
  2649.   end
  2650.   if dhdSettings.thisGate == "--ERROR--" then return end
  2651.   saveData(settingsData, "cfg")
  2652.   if not fs.exists(dhdSettings.gateData) then
  2653.     saveData(dhdSettings.gateData, "gate")
  2654.   end
  2655.   -- Check and, if necessary, set computer label
  2656.   local ccLabel = os.getComputerLabel()
  2657.   if ccLabel == nil or tostring(ccLabel) == "" or ccLabel == "DHD" then
  2658.     os.setComputerLabel(dhdSettings.thisGate .. " DHD")
  2659.   end
  2660. end
  2661.  
  2662. local function initMe()
  2663.   term.setBackgroundColor(black)
  2664.   term.clear()
  2665.   drawElement(2, 2, 18, 1, white, black, "Initializing . . .")
  2666.   term.setCursorPos(2, 4)
  2667.   if not fs.exists(settingsData) then
  2668.     detectHardware("mon")
  2669.     detectHardware("modem")
  2670.     if hardware.netSide == "none" then missingComponent("modem") return end
  2671.     firstRun()
  2672.   end
  2673.   if not fs.exists(settingsData) then missingComponent("cfg") dhdSettings.thisGate = "--ERROR--" return end
  2674.   ingestData(settingsData, "cfg")
  2675.   drawElement(2, 4, 24, 1, white, black, "Hardware Discovery . . .")
  2676.   detectHardware("modem")
  2677.   if hardware.netSide == "none" then missingComponent("modem") dhdSettings.thisGate = "--ERROR--" return end
  2678.   if dhdSettings.pSync == "ON" then
  2679.     if dhdSettings.net == "R" then
  2680.       modem = peripheral.wrap(hardware.netSide)
  2681.     end
  2682.     modem.open(dhdSettings.pChannels.recv)
  2683.   end
  2684.   if dhdSettings.monA ~= "none" then
  2685.     monA.setBackgroundColor(black)
  2686.     monA.clear()
  2687.   end
  2688.   if dhdSettings.monB ~= "none" then
  2689.     monB.setBackgroundColor(black)
  2690.     monB.clear()
  2691.   end
  2692.   detectHardware("bio")
  2693.   if dhdSettings.bio.lock == "ON" and hardware.bioSide ~= "none" then bioLogin() end -- Biolock login
  2694.   local trWord = "Querying gateLiaison @ " .. dhdSettings.thisGate .. " . . ."
  2695.   drawElement(2, 6, #trWord, 1, white, black, trWord)
  2696.   netSend("QRY")
  2697.   drawElement(2, 8, 23, 1, white, black, "Awaiting response . . .")
  2698.   if dhdSettings.net == "R" then
  2699.     local senderID, message = rednet.receive()
  2700.     if senderID == dhdSettings.gate then
  2701.       updateStatus(message)
  2702.     end
  2703.   elseif dhdSettings.net == "C" then
  2704.     local netEvent = { os.pullEvent("modem_message") }
  2705.     if netEvent[3] == dhdSettings.channels.recv and netEvent[4] == dhdSettings.channels.send then
  2706.       updateStatus(netEvent[5])
  2707.     end
  2708.   end
  2709.   drawElement(2, 10, 20, 1, white, black, "Setting Shield . . .")
  2710.   if dhdSettings.startShield == "ON" then
  2711.     netSend("sON")
  2712.   end
  2713.   drawElement(2, 12, 25, 1, white, black, "Ingesting gate data . . .")
  2714.   ingestData(dhdSettings.gateData, "gate")
  2715.   term.setBackgroundColor(black)
  2716.   term.clear()
  2717.   kernelState = true
  2718.   runState = "Dial"
  2719.   currentState = "Dial"
  2720.   drawCLI()
  2721. end
  2722.  
  2723. initMe()
  2724.  
  2725. repeat
  2726.   dhdKernel()
  2727.   if runState == "quit" then kernelState = false end
  2728.   if kernelState == false then
  2729.     if monA ~= "none" then
  2730.        monA.setBackgroundColor(black)
  2731.        monA.clear()
  2732.     end
  2733.     if monB ~= "none" then
  2734.        monB.setBackgroundColor(black)
  2735.        monB.clear()
  2736.     end
  2737.     term.setBackgroundColor(black)
  2738.     term.setTextColor(white)
  2739.     if dhdSettings.thisGate ~= "--ERROR--" then
  2740.       term.clear()
  2741.       term.setCursorPos(1, 1)
  2742.     end
  2743.     if hardware.netSide ~= "none" then
  2744.       if dhdSettings.pSync == "ON" then
  2745.         modem.close(dhdSettings.pChannels.recv)
  2746.       end
  2747.       if dhdSettings.net == "R" then
  2748.         rednet.close(hardware.netSide)
  2749.       elseif dhdSettings.net == "C" then
  2750.         modem.close(dhdSettings.channels.recv)
  2751.       end
  2752.       modem = nil
  2753.     end
  2754.     if runState == "reboot" or runState == "reset" then os.reboot() end
  2755.     return
  2756.   end
  2757. until kernelState == false
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement