Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[ LanteaCraft ]]--
- --[[ and SGCraft ]]--
- --[[ c c D H D ]]--
- --[[ by Dog ]]--
- --[[ aka HydrantHunter ]]--
- --[[ with help from ]]--
- --[[ Bomb Bloke ]]--
- --[[ pastebin 39UhE8Nz ]]--
- local ccDHDVer = "2.0.00"
- --[[
- Tested with/requires:
- - Minecraft 1.7.10+ AND ComputerCraft 1.75+ || LanteaCraft LC2-16+ | OR | SGCraft1.11.x-mc1.7.10+
- For setup and usage instructions, please visit http://tinyurl.com/jf3rjr7
- Special thanks to: theoriginalbit (custom read function)
- Anavrins (pbkdf2/sha256 hashing)
- SquidDev (AES encryption/decryption)
- Alex Kloss (base64 encoder/decoder)
- IMPORTANT NOTE:
- - all of the following variables are set by the program as necessary
- - editing any of them below will most likely cause unexpected results
- ]]--
- local tArgs = { ... }
- --# Default Settings
- local settingsData = "/data/DHDconfig"
- local gateData = "/data/DHDgates"
- local gateHistory = "/data/DHDhistory"
- local lastGate = "/data/DHDlastCall"
- local validStates = { }
- local dhdSettings = {
- gate = 99999999; --# gateLiaison
- detailedMarquee = true; --# show gate details on the marquee monitor
- password = "password"; --# lockdown password
- irisPassword = "password"; --# remote iris control password
- hashedPWs = false; --# Whether passwords have been hashed or not
- newHash = false; --# Whether passwords are hashed with the old or new hash
- bio = { lock = false, func = "none", auth = 4, fAuth = 2 }; --# BioLock (Startup locked, Standard function, Startup unlock auth level, Standard function activation auth level)
- sync = false; --# Sync (true, false, "Dial ONLY")
- ecIris = "none"; --# 'endCall Iris' - open/close iris upon disconnect (or do nothing)
- incomingIris = false; --# incoming call auto-iris-close
- logs = true; --# keep a record of calls
- }
- local updateStatus, netSend, sendToAllSyncClients, drawElement, drawCLI, drawLogScreen, drawSettingsScreen, drawRemoteIrisStatus, displayMarquee, displayStatus, displayStatusDetail, displayConnectionTime, displayAddressBook, displayGateMonAddrBook, displayNotes, displayGate, displayChevrons, repositionCursor, saveData
- local stdPullEvent = os.pullEvent
- --# Peripherals
- local termX, termY = term.getSize() --# standard 51x19 / tab 51x18
- local hardware = { wifiSide = "none", modemSide = "none", bio = 0, listMon = 0, marquee = 0, gateMon = 0, timerMon = 0 } --# Modem side(s), Biolock count, and Monitor count
- local listMon, listMonSides = { }, { } --# List monitor(s) (Address Book) 1x1 array
- local marquee, marqueeSides = { }, { } --# Marquee monitor(s) (Marquee / Info) 3x1 array
- local gateMon, gateMonSides = { }, { } --# Gate monitor(s) (Gate + Chevrons / Address Book) 3x3 array
- local timerMon, timerMonSides = { }, { } --# Connection Timer monitors(s) 2x1 array
- local thisCC, thisGate, ccLabel, gateLiaison = tostring(os.getComputerID())
- --# Status Info
- local gateStatus, irisStatus, secureStatus, displayState, runState, currentState, tempState, callDirection, dialAddress, remoteIrisStatus, rsSide = "QRY", "QRY", "QRY", "list", "init", "init", "none", "none", "none", "unk", "none"
- local menuState, kernelState, irisState, lcGate, gateMonList, dialFromDHD, outgoingAlarm = false, false, false, false, false, false, false
- local configChange, gateChange, waitingForIris, gettingInput, fullRedraw, initMarquee = false, false, false, false, false, false
- local currentEdit, selectedGate, incomingAddress, sgRemoteAddrLen, connectionTimer, pingTimer, fuelPercent, curX, curY, txtCol, bgCol, word, passChange
- local chevronNumber, irisPercent, clientCount, connectionTime, connectionClock = 0, 0, 0, 0, "00:00:0"
- local clients = { } --# Sync clients
- local dialStates = {
- Dial = colors.blue;
- remotePass = colors.blue;
- goPage = colors.blue;
- importExport = colors.blue;
- exodus = colors.blue;
- }
- --# Address Book
- local addressBook = { { name = "NEW GATE", addr = "ADDRESS", rating = "U", iris = "none", callDrop = false, note = "short note", loc = { x = 0, y = 0, z = 0, dim = "Unspecified" } } }
- local gatePage, gatePages, listPage, listPages, gateMonPage, gateMonPages, abCount = 1, 1, 1, 1, 1, 1, 1
- local pNum = tostring(gatePage) .. " of " .. tostring(gatePages)
- local classifications = {
- B = { order = 1, color = colors.blue, label = "Base/Outpost/Hub" };
- H = { order = 2, color = colors.lightBlue, label = "Home/Camp" };
- V = { order = 3, color = colors.brown, label = "Village" };
- M = { order = 4, color = colors.purple, label = "Misc/Special" };
- S = { order = 5, color = colors.green, label = "Safe/Secured" };
- C = { order = 6, color = colors.orange, label = "Caution" };
- D = { order = 7, color = colors.red, label = "Danger" };
- U = { order = 8, color = colors.lightGray, label = "Unk/Unclassified", long = "Unknown/Unclassified" };
- }
- --# Call History
- local logPage, logPages = 1, 1
- local callHistory = { }
- local lastCall
- --# Color Definitions
- local white = colors.white
- local silver = colors.lightGray
- local gray = colors.gray
- local black = colors.black
- local brown = colors.brown
- local yellow = colors.yellow
- local orange = colors.orange
- local red = colors.red
- --local magenta = colors.magenta
- --local purple = colors.purple
- local blue = colors.blue
- local sky = colors.lightBlue
- local cyan = colors.cyan
- local lime = colors.lime
- local green = colors.green
- -- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
- -- licensed under the terms of the LGPL2
- -- http://lua-users.org/wiki/BaseSixtyFour
- -- character table string
- local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
- -- encoding
- local function encode(data)
- return ((data:gsub('.', function(x)
- local r,b='',x:byte()
- for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
- return r;
- end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
- if (#x < 6) then return '' end
- local c=0
- for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
- return b:sub(c+1,c+1)
- end)..({ '', '==', '=' })[#data%3+1])
- end
- -- decoding
- local function decode(data)
- data = string.gsub(data, '[^'..b..'=]', '')
- return (data:gsub('.', function(x)
- if (x == '=') then return '' end
- local r,f='',(b:find(x)-1)
- for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
- return r;
- end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
- if (#x ~= 8) then return '' end
- local c=0
- for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
- return string.char(c)
- end))
- end
- -- AES Lua implementation by SquidDev
- -- https://gist.github.com/SquidDev/86925e07cbabd70773e53d781bd8b2fe
- local encrypt, decrypt
- do
- local function _W(f) local e=setmetatable({}, {__index = _ENV or getfenv()}) if setfenv then setfenv(f, e) end return f(e) or e end
- local bit=_W(function(_ENV, ...)
- --[[
- This bit API is designed to cope with unsigned integers instead of normal integers
- To do this we add checks for overflows: (x > 2^31 ? x - 2 ^ 32 : x)
- These are written in long form because no constant folding.
- ]]
- local floor = math.floor
- local lshift, rshift
- rshift = function(a,disp)
- return floor(a % 4294967296 / 2^disp)
- end
- lshift = function(a,disp)
- return (a * 2^disp) % 4294967296
- end
- return {
- -- bit operations
- bnot = bit32 and bit32.bnot or bit.bnot,
- band = bit32 and bit32.band or bit.band,
- bor = bit32 and bit32.bor or bit.bor,
- bxor = bit32 and bit32.bxor or bit.bxor,
- rshift = rshift,
- lshift = lshift,
- }
- end)
- local gf=_W(function(_ENV, ...)
- -- finite field with base 2 and modulo irreducible polynom x^8+x^4+x^3+x+1 = 0x11d
- local bxor = bit32 and bit32.bxor or bit.bxor
- local lshift = bit.lshift
- -- private data of gf
- local n = 0x100
- local ord = 0xff
- local irrPolynom = 0x11b
- local exp, log = {}, {}
- --
- -- add two polynoms (its simply xor)
- --
- local function add(operand1, operand2)
- return bxor(operand1,operand2)
- end
- --
- -- subtract two polynoms (same as addition)
- --
- local function sub(operand1, operand2)
- return bxor(operand1,operand2)
- end
- --
- -- inverts element
- -- a^(-1) = g^(order - log(a))
- --
- local function invert(operand)
- -- special case for 1 or normal invert
- return operand == 1 and 1 or exp[ord - log[operand]]
- end
- --
- -- multiply two elements using a logarithm table
- -- a*b = g^(log(a)+log(b))
- --
- local function mul(operand1, operand2)
- if (operand1 == 0 or operand2 == 0) then
- return 0
- end
- local exponent = log[operand1] + log[operand2]
- if (exponent >= ord) then
- exponent = exponent - ord
- end
- return exp[exponent]
- end
- --
- -- divide two elements
- -- a/b = g^(log(a)-log(b))
- --
- local function div(operand1, operand2)
- if (operand1 == 0) then
- return 0
- end
- -- TODO: exception if operand2 == 0
- local exponent = log[operand1] - log[operand2]
- if (exponent < 0) then
- exponent = exponent + ord
- end
- return exp[exponent]
- end
- --
- -- print logarithmic table
- --
- local function printLog()
- for i = 1, n do
- print("log(", i-1, ")=", log[i-1])
- end
- end
- --
- -- print exponentiation table
- --
- local function printExp()
- for i = 1, n do
- print("exp(", i-1, ")=", exp[i-1])
- end
- end
- --
- -- calculate logarithmic and exponentiation table
- --
- local function initMulTable()
- local a = 1
- for i = 0,ord-1 do
- exp[i] = a
- log[a] = i
- -- multiply with generator x+1 -> left shift + 1
- a = bxor(lshift(a, 1), a)
- -- if a gets larger than order, reduce modulo irreducible polynom
- if a > ord then
- a = sub(a, irrPolynom)
- end
- end
- end
- initMulTable()
- return {
- add = add,
- sub = sub,
- invert = invert,
- mul = mul,
- div = div,
- printLog = printLog,
- printExp = printExp,
- }
- end)
- util=_W(function(_ENV, ...)
- -- Cache some bit operators
- local bxor = bit.bxor
- local rshift = bit.rshift
- local band = bit.band
- local lshift = bit.lshift
- local sleepCheckIn
- --
- -- calculate the parity of one byte
- --
- local function byteParity(byte)
- byte = bxor(byte, rshift(byte, 4))
- byte = bxor(byte, rshift(byte, 2))
- byte = bxor(byte, rshift(byte, 1))
- return band(byte, 1)
- end
- --
- -- get byte at position index
- --
- local function getByte(number, index)
- return index == 0 and band(number,0xff) or band(rshift(number, index*8),0xff)
- end
- --
- -- put number into int at position index
- --
- local function putByte(number, index)
- return index == 0 and band(number,0xff) or lshift(band(number,0xff),index*8)
- end
- --
- -- convert byte array to int array
- --
- local function bytesToInts(bytes, start, n)
- local ints = {}
- for i = 0, n - 1 do
- ints[i + 1] =
- putByte(bytes[start + (i*4)], 3) +
- putByte(bytes[start + (i*4) + 1], 2) +
- putByte(bytes[start + (i*4) + 2], 1) +
- putByte(bytes[start + (i*4) + 3], 0)
- if n % 10000 == 0 then sleepCheckIn() end
- end
- return ints
- end
- --
- -- convert int array to byte array
- --
- local function intsToBytes(ints, output, outputOffset, n)
- n = n or #ints
- for i = 0, n - 1 do
- for j = 0,3 do
- output[outputOffset + i*4 + (3 - j)] = getByte(ints[i + 1], j)
- end
- if n % 10000 == 0 then sleepCheckIn() end
- end
- return output
- end
- --
- -- convert bytes to hexString
- --
- local function bytesToHex(bytes)
- local hexBytes = ""
- for i,byte in ipairs(bytes) do
- hexBytes = hexBytes .. string.format("%02x ", byte)
- end
- return hexBytes
- end
- local function hexToBytes(bytes)
- local out = {}
- for i = 1, #bytes, 2 do
- out[#out + 1] = tonumber(bytes:sub(i, i + 1), 16)
- end
- return out
- end
- --
- -- convert data to hex string
- --
- local function toHexString(data)
- local type = type(data)
- if (type == "number") then
- return string.format("%08x",data)
- elseif (type == "table") then
- return bytesToHex(data)
- elseif (type == "string") then
- local bytes = {string.byte(data, 1, #data)}
- return bytesToHex(bytes)
- else
- return data
- end
- end
- local function padByteString(data)
- local dataLength = #data
- local random1 = math.random(0,255)
- local random2 = math.random(0,255)
- local prefix = string.char(random1,
- random2,
- random1,
- random2,
- getByte(dataLength, 3),
- getByte(dataLength, 2),
- getByte(dataLength, 1),
- getByte(dataLength, 0)
- )
- data = prefix .. data
- local padding, paddingLength = "", math.ceil(#data/16)*16 - #data
- for i=1,paddingLength do
- padding = padding .. string.char(math.random(0,255))
- end
- return data .. padding
- end
- local function properlyDecrypted(data)
- local random = {string.byte(data,1,4)}
- if (random[1] == random[3] and random[2] == random[4]) then
- return true
- end
- return false
- end
- local function unpadByteString(data)
- if (not properlyDecrypted(data)) then
- return nil
- end
- local dataLength = putByte(string.byte(data,5), 3)
- + putByte(string.byte(data,6), 2)
- + putByte(string.byte(data,7), 1)
- + putByte(string.byte(data,8), 0)
- return string.sub(data,9,8+dataLength)
- end
- local function xorIV(data, iv)
- for i = 1,16 do
- data[i] = bxor(data[i], iv[i])
- end
- end
- local function increment(data)
- local i = 16
- while true do
- local value = data[i] + 1
- if value >= 256 then
- data[i] = value - 256
- i = (i - 2) % 16 + 1
- else
- data[i] = value
- break
- end
- end
- end
- -- Called every encryption cycle
- local push, pull, time = os.queueEvent, coroutine.yield, os.time
- local oldTime = time()
- local function sleepCheckIn()
- local newTime = time()
- if newTime - oldTime >= 0.03 then -- (0.020 * 1.5)
- oldTime = newTime
- push("sleep")
- pull("sleep")
- end
- end
- local function getRandomData(bytes)
- local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
- local result = {}
- for i=1,bytes do
- insert(result, random(0,255))
- if i % 10240 == 0 then sleep() end
- end
- return result
- end
- local function getRandomString(bytes)
- local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
- local result = {}
- for i=1,bytes do
- insert(result, char(random(0,255)))
- if i % 10240 == 0 then sleep() end
- end
- return table.concat(result)
- end
- return {
- byteParity = byteParity,
- getByte = getByte,
- putByte = putByte,
- bytesToInts = bytesToInts,
- intsToBytes = intsToBytes,
- bytesToHex = bytesToHex,
- hexToBytes = hexToBytes,
- toHexString = toHexString,
- padByteString = padByteString,
- properlyDecrypted = properlyDecrypted,
- unpadByteString = unpadByteString,
- xorIV = xorIV,
- increment = increment,
- sleepCheckIn = sleepCheckIn,
- getRandomData = getRandomData,
- getRandomString = getRandomString,
- }
- end)
- aes=_W(function(_ENV, ...)
- -- Implementation of AES with nearly pure lua
- -- AES with lua is slow, really slow :-)
- local putByte = util.putByte
- local getByte = util.getByte
- -- some constants
- local ROUNDS = 'rounds'
- local KEY_TYPE = "type"
- local ENCRYPTION_KEY=1
- local DECRYPTION_KEY=2
- -- aes SBOX
- local SBox = {}
- local iSBox = {}
- -- aes tables
- local table0 = {}
- local table1 = {}
- local table2 = {}
- local table3 = {}
- local tableInv0 = {}
- local tableInv1 = {}
- local tableInv2 = {}
- local tableInv3 = {}
- -- round constants
- local rCon = {
- 0x01000000,
- 0x02000000,
- 0x04000000,
- 0x08000000,
- 0x10000000,
- 0x20000000,
- 0x40000000,
- 0x80000000,
- 0x1b000000,
- 0x36000000,
- 0x6c000000,
- 0xd8000000,
- 0xab000000,
- 0x4d000000,
- 0x9a000000,
- 0x2f000000,
- }
- --
- -- affine transformation for calculating the S-Box of AES
- --
- local function affinMap(byte)
- mask = 0xf8
- result = 0
- for i = 1,8 do
- result = bit.lshift(result,1)
- parity = util.byteParity(bit.band(byte,mask))
- result = result + parity
- -- simulate roll
- lastbit = bit.band(mask, 1)
- mask = bit.band(bit.rshift(mask, 1),0xff)
- mask = lastbit ~= 0 and bit.bor(mask, 0x80) or bit.band(mask, 0x7f)
- end
- return bit.bxor(result, 0x63)
- end
- --
- -- calculate S-Box and inverse S-Box of AES
- -- apply affine transformation to inverse in finite field 2^8
- --
- local function calcSBox()
- for i = 0, 255 do
- inverse = i ~= 0 and gf.invert(i) or 0
- mapped = affinMap(inverse)
- SBox[i] = mapped
- iSBox[mapped] = i
- end
- end
- --
- -- Calculate round tables
- -- round tables are used to calculate shiftRow, MixColumn and SubBytes
- -- with 4 table lookups and 4 xor operations.
- --
- local function calcRoundTables()
- for x = 0,255 do
- byte = SBox[x]
- table0[x] = putByte(gf.mul(0x03, byte), 0)
- + putByte( byte , 1)
- + putByte( byte , 2)
- + putByte(gf.mul(0x02, byte), 3)
- table1[x] = putByte( byte , 0)
- + putByte( byte , 1)
- + putByte(gf.mul(0x02, byte), 2)
- + putByte(gf.mul(0x03, byte), 3)
- table2[x] = putByte( byte , 0)
- + putByte(gf.mul(0x02, byte), 1)
- + putByte(gf.mul(0x03, byte), 2)
- + putByte( byte , 3)
- table3[x] = putByte(gf.mul(0x02, byte), 0)
- + putByte(gf.mul(0x03, byte), 1)
- + putByte( byte , 2)
- + putByte( byte , 3)
- end
- end
- --
- -- Calculate inverse round tables
- -- does the inverse of the normal roundtables for the equivalent
- -- decryption algorithm.
- --
- local function calcInvRoundTables()
- for x = 0,255 do
- byte = iSBox[x]
- tableInv0[x] = putByte(gf.mul(0x0b, byte), 0)
- + putByte(gf.mul(0x0d, byte), 1)
- + putByte(gf.mul(0x09, byte), 2)
- + putByte(gf.mul(0x0e, byte), 3)
- tableInv1[x] = putByte(gf.mul(0x0d, byte), 0)
- + putByte(gf.mul(0x09, byte), 1)
- + putByte(gf.mul(0x0e, byte), 2)
- + putByte(gf.mul(0x0b, byte), 3)
- tableInv2[x] = putByte(gf.mul(0x09, byte), 0)
- + putByte(gf.mul(0x0e, byte), 1)
- + putByte(gf.mul(0x0b, byte), 2)
- + putByte(gf.mul(0x0d, byte), 3)
- tableInv3[x] = putByte(gf.mul(0x0e, byte), 0)
- + putByte(gf.mul(0x0b, byte), 1)
- + putByte(gf.mul(0x0d, byte), 2)
- + putByte(gf.mul(0x09, byte), 3)
- end
- end
- --
- -- rotate word: 0xaabbccdd gets 0xbbccddaa
- -- used for key schedule
- --
- local function rotWord(word)
- local tmp = bit.band(word,0xff000000)
- return (bit.lshift(word,8) + bit.rshift(tmp,24))
- end
- --
- -- replace all bytes in a word with the SBox.
- -- used for key schedule
- --
- local function subWord(word)
- return putByte(SBox[getByte(word,0)],0)
- + putByte(SBox[getByte(word,1)],1)
- + putByte(SBox[getByte(word,2)],2)
- + putByte(SBox[getByte(word,3)],3)
- end
- --
- -- generate key schedule for aes encryption
- --
- -- returns table with all round keys and
- -- the necessary number of rounds saved in [ROUNDS]
- --
- local function expandEncryptionKey(key)
- local keySchedule = {}
- local keyWords = math.floor(#key / 4)
- if ((keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8) or (keyWords * 4 ~= #key)) then
- error("Invalid key size: " .. tostring(keyWords))
- return nil
- end
- keySchedule[ROUNDS] = keyWords + 6
- keySchedule[KEY_TYPE] = ENCRYPTION_KEY
- for i = 0,keyWords - 1 do
- keySchedule[i] = putByte(key[i*4+1], 3)
- + putByte(key[i*4+2], 2)
- + putByte(key[i*4+3], 1)
- + putByte(key[i*4+4], 0)
- end
- for i = keyWords, (keySchedule[ROUNDS] + 1)*4 - 1 do
- local tmp = keySchedule[i-1]
- if ( i % keyWords == 0) then
- tmp = rotWord(tmp)
- tmp = subWord(tmp)
- local index = math.floor(i/keyWords)
- tmp = bit.bxor(tmp,rCon[index])
- elseif (keyWords > 6 and i % keyWords == 4) then
- tmp = subWord(tmp)
- end
- keySchedule[i] = bit.bxor(keySchedule[(i-keyWords)],tmp)
- end
- return keySchedule
- end
- --
- -- Inverse mix column
- -- used for key schedule of decryption key
- --
- local function invMixColumnOld(word)
- local b0 = getByte(word,3)
- local b1 = getByte(word,2)
- local b2 = getByte(word,1)
- local b3 = getByte(word,0)
- return putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b1),
- gf.mul(0x0d, b2)),
- gf.mul(0x09, b3)),
- gf.mul(0x0e, b0)),3)
- + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b2),
- gf.mul(0x0d, b3)),
- gf.mul(0x09, b0)),
- gf.mul(0x0e, b1)),2)
- + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b3),
- gf.mul(0x0d, b0)),
- gf.mul(0x09, b1)),
- gf.mul(0x0e, b2)),1)
- + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b0),
- gf.mul(0x0d, b1)),
- gf.mul(0x09, b2)),
- gf.mul(0x0e, b3)),0)
- end
- --
- -- Optimized inverse mix column
- -- look at http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
- -- TODO: make it work
- --
- local function invMixColumn(word)
- local b0 = getByte(word,3)
- local b1 = getByte(word,2)
- local b2 = getByte(word,1)
- local b3 = getByte(word,0)
- local t = bit.bxor(b3,b2)
- local u = bit.bxor(b1,b0)
- local v = bit.bxor(t,u)
- v = bit.bxor(v,gf.mul(0x08,v))
- w = bit.bxor(v,gf.mul(0x04, bit.bxor(b2,b0)))
- v = bit.bxor(v,gf.mul(0x04, bit.bxor(b3,b1)))
- return putByte( bit.bxor(bit.bxor(b3,v), gf.mul(0x02, bit.bxor(b0,b3))), 0)
- + putByte( bit.bxor(bit.bxor(b2,w), gf.mul(0x02, t )), 1)
- + putByte( bit.bxor(bit.bxor(b1,v), gf.mul(0x02, bit.bxor(b0,b3))), 2)
- + putByte( bit.bxor(bit.bxor(b0,w), gf.mul(0x02, u )), 3)
- end
- --
- -- generate key schedule for aes decryption
- --
- -- uses key schedule for aes encryption and transforms each
- -- key by inverse mix column.
- --
- local function expandDecryptionKey(key)
- local keySchedule = expandEncryptionKey(key)
- if (keySchedule == nil) then
- return nil
- end
- keySchedule[KEY_TYPE] = DECRYPTION_KEY
- for i = 4, (keySchedule[ROUNDS] + 1)*4 - 5 do
- keySchedule[i] = invMixColumnOld(keySchedule[i])
- end
- return keySchedule
- end
- --
- -- xor round key to state
- --
- local function addRoundKey(state, key, round)
- for i = 0, 3 do
- state[i + 1] = bit.bxor(state[i + 1], key[round*4+i])
- end
- end
- --
- -- do encryption round (ShiftRow, SubBytes, MixColumn together)
- --
- local function doRound(origState, dstState)
- dstState[1] = bit.bxor(bit.bxor(bit.bxor(
- table0[getByte(origState[1],3)],
- table1[getByte(origState[2],2)]),
- table2[getByte(origState[3],1)]),
- table3[getByte(origState[4],0)])
- dstState[2] = bit.bxor(bit.bxor(bit.bxor(
- table0[getByte(origState[2],3)],
- table1[getByte(origState[3],2)]),
- table2[getByte(origState[4],1)]),
- table3[getByte(origState[1],0)])
- dstState[3] = bit.bxor(bit.bxor(bit.bxor(
- table0[getByte(origState[3],3)],
- table1[getByte(origState[4],2)]),
- table2[getByte(origState[1],1)]),
- table3[getByte(origState[2],0)])
- dstState[4] = bit.bxor(bit.bxor(bit.bxor(
- table0[getByte(origState[4],3)],
- table1[getByte(origState[1],2)]),
- table2[getByte(origState[2],1)]),
- table3[getByte(origState[3],0)])
- end
- --
- -- do last encryption round (ShiftRow and SubBytes)
- --
- local function doLastRound(origState, dstState)
- dstState[1] = putByte(SBox[getByte(origState[1],3)], 3)
- + putByte(SBox[getByte(origState[2],2)], 2)
- + putByte(SBox[getByte(origState[3],1)], 1)
- + putByte(SBox[getByte(origState[4],0)], 0)
- dstState[2] = putByte(SBox[getByte(origState[2],3)], 3)
- + putByte(SBox[getByte(origState[3],2)], 2)
- + putByte(SBox[getByte(origState[4],1)], 1)
- + putByte(SBox[getByte(origState[1],0)], 0)
- dstState[3] = putByte(SBox[getByte(origState[3],3)], 3)
- + putByte(SBox[getByte(origState[4],2)], 2)
- + putByte(SBox[getByte(origState[1],1)], 1)
- + putByte(SBox[getByte(origState[2],0)], 0)
- dstState[4] = putByte(SBox[getByte(origState[4],3)], 3)
- + putByte(SBox[getByte(origState[1],2)], 2)
- + putByte(SBox[getByte(origState[2],1)], 1)
- + putByte(SBox[getByte(origState[3],0)], 0)
- end
- --
- -- do decryption round
- --
- local function doInvRound(origState, dstState)
- dstState[1] = bit.bxor(bit.bxor(bit.bxor(
- tableInv0[getByte(origState[1],3)],
- tableInv1[getByte(origState[4],2)]),
- tableInv2[getByte(origState[3],1)]),
- tableInv3[getByte(origState[2],0)])
- dstState[2] = bit.bxor(bit.bxor(bit.bxor(
- tableInv0[getByte(origState[2],3)],
- tableInv1[getByte(origState[1],2)]),
- tableInv2[getByte(origState[4],1)]),
- tableInv3[getByte(origState[3],0)])
- dstState[3] = bit.bxor(bit.bxor(bit.bxor(
- tableInv0[getByte(origState[3],3)],
- tableInv1[getByte(origState[2],2)]),
- tableInv2[getByte(origState[1],1)]),
- tableInv3[getByte(origState[4],0)])
- dstState[4] = bit.bxor(bit.bxor(bit.bxor(
- tableInv0[getByte(origState[4],3)],
- tableInv1[getByte(origState[3],2)]),
- tableInv2[getByte(origState[2],1)]),
- tableInv3[getByte(origState[1],0)])
- end
- --
- -- do last decryption round
- --
- local function doInvLastRound(origState, dstState)
- dstState[1] = putByte(iSBox[getByte(origState[1],3)], 3)
- + putByte(iSBox[getByte(origState[4],2)], 2)
- + putByte(iSBox[getByte(origState[3],1)], 1)
- + putByte(iSBox[getByte(origState[2],0)], 0)
- dstState[2] = putByte(iSBox[getByte(origState[2],3)], 3)
- + putByte(iSBox[getByte(origState[1],2)], 2)
- + putByte(iSBox[getByte(origState[4],1)], 1)
- + putByte(iSBox[getByte(origState[3],0)], 0)
- dstState[3] = putByte(iSBox[getByte(origState[3],3)], 3)
- + putByte(iSBox[getByte(origState[2],2)], 2)
- + putByte(iSBox[getByte(origState[1],1)], 1)
- + putByte(iSBox[getByte(origState[4],0)], 0)
- dstState[4] = putByte(iSBox[getByte(origState[4],3)], 3)
- + putByte(iSBox[getByte(origState[3],2)], 2)
- + putByte(iSBox[getByte(origState[2],1)], 1)
- + putByte(iSBox[getByte(origState[1],0)], 0)
- end
- --
- -- encrypts 16 Bytes
- -- key encryption key schedule
- -- input array with input data
- -- inputOffset start index for input
- -- output array for encrypted data
- -- outputOffset start index for output
- --
- local function encrypt(key, input, inputOffset, output, outputOffset)
- --default parameters
- inputOffset = inputOffset or 1
- output = output or {}
- outputOffset = outputOffset or 1
- local state, tmpState = {}, {}
- if (key[KEY_TYPE] ~= ENCRYPTION_KEY) then
- error("No encryption key: " .. tostring(key[KEY_TYPE]) .. ", expected " .. ENCRYPTION_KEY)
- return
- end
- state = util.bytesToInts(input, inputOffset, 4)
- addRoundKey(state, key, 0)
- local round = 1
- while (round < key[ROUNDS] - 1) do
- -- do a double round to save temporary assignments
- doRound(state, tmpState)
- addRoundKey(tmpState, key, round)
- round = round + 1
- doRound(tmpState, state)
- addRoundKey(state, key, round)
- round = round + 1
- end
- doRound(state, tmpState)
- addRoundKey(tmpState, key, round)
- round = round +1
- doLastRound(tmpState, state)
- addRoundKey(state, key, round)
- util.sleepCheckIn()
- return util.intsToBytes(state, output, outputOffset)
- end
- --
- -- decrypt 16 bytes
- -- key decryption key schedule
- -- input array with input data
- -- inputOffset start index for input
- -- output array for decrypted data
- -- outputOffset start index for output
- ---
- local function decrypt(key, input, inputOffset, output, outputOffset)
- -- default arguments
- inputOffset = inputOffset or 1
- output = output or {}
- outputOffset = outputOffset or 1
- local state, tmpState = {}, {}
- if (key[KEY_TYPE] ~= DECRYPTION_KEY) then
- error("No decryption key: " .. tostring(key[KEY_TYPE]))
- return
- end
- state = util.bytesToInts(input, inputOffset, 4)
- addRoundKey(state, key, key[ROUNDS])
- local round = key[ROUNDS] - 1
- while (round > 2) do
- -- do a double round to save temporary assignments
- doInvRound(state, tmpState)
- addRoundKey(tmpState, key, round)
- round = round - 1
- doInvRound(tmpState, state)
- addRoundKey(state, key, round)
- round = round - 1
- end
- doInvRound(state, tmpState)
- addRoundKey(tmpState, key, round)
- round = round - 1
- doInvLastRound(tmpState, state)
- addRoundKey(state, key, round)
- util.sleepCheckIn()
- return util.intsToBytes(state, output, outputOffset)
- end
- -- calculate all tables when loading this file
- calcSBox()
- calcRoundTables()
- calcInvRoundTables()
- return {
- ROUNDS = ROUNDS,
- KEY_TYPE = KEY_TYPE,
- ENCRYPTION_KEY = ENCRYPTION_KEY,
- DECRYPTION_KEY = DECRYPTION_KEY,
- expandEncryptionKey = expandEncryptionKey,
- expandDecryptionKey = expandDecryptionKey,
- encrypt = encrypt,
- decrypt = decrypt,
- }
- end)
- local buffer=_W(function(_ENV, ...)
- local function new()
- return {}
- end
- local function addString(stack, s)
- table.insert(stack, s)
- end
- local function toString(stack)
- return table.concat(stack)
- end
- return {
- new = new,
- addString = addString,
- toString = toString,
- }
- end)
- ciphermode=_W(function(_ENV, ...)
- local public = {}
- --
- -- Encrypt strings
- -- key - byte array with key
- -- string - string to encrypt
- -- modefunction - function for cipher mode to use
- --
- local random, unpack = math.random, unpack or table.unpack
- function public.encryptString(key, data, modeFunction, iv)
- if iv then
- local ivCopy = {}
- for i = 1, 16 do ivCopy[i] = iv[i] end
- iv = ivCopy
- else
- iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
- end
- local keySched = aes.expandEncryptionKey(key)
- local encryptedData = buffer.new()
- for i = 1, #data/16 do
- local offset = (i-1)*16 + 1
- local byteData = {string.byte(data,offset,offset +15)}
- iv = modeFunction(keySched, byteData, iv)
- buffer.addString(encryptedData, string.char(unpack(byteData)))
- end
- return buffer.toString(encryptedData)
- end
- --
- -- the following 4 functions can be used as
- -- modefunction for encryptString
- --
- -- Electronic code book mode encrypt function
- function public.encryptECB(keySched, byteData, iv)
- aes.encrypt(keySched, byteData, 1, byteData, 1)
- end
- -- Cipher block chaining mode encrypt function
- function public.encryptCBC(keySched, byteData, iv)
- util.xorIV(byteData, iv)
- aes.encrypt(keySched, byteData, 1, byteData, 1)
- return byteData
- end
- -- Output feedback mode encrypt function
- function public.encryptOFB(keySched, byteData, iv)
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- return iv
- end
- -- Cipher feedback mode encrypt function
- function public.encryptCFB(keySched, byteData, iv)
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- return byteData
- end
- function public.encryptCTR(keySched, byteData, iv)
- local nextIV = {}
- for j = 1, 16 do nextIV[j] = iv[j] end
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- util.increment(nextIV)
- return nextIV
- end
- --
- -- Decrypt strings
- -- key - byte array with key
- -- string - string to decrypt
- -- modefunction - function for cipher mode to use
- --
- function public.decryptString(key, data, modeFunction, iv)
- if iv then
- local ivCopy = {}
- for i = 1, 16 do ivCopy[i] = iv[i] end
- iv = ivCopy
- else
- iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
- end
- local keySched
- if modeFunction == public.decryptOFB or modeFunction == public.decryptCFB or modeFunction == public.decryptCTR then
- keySched = aes.expandEncryptionKey(key)
- else
- keySched = aes.expandDecryptionKey(key)
- end
- local decryptedData = buffer.new()
- for i = 1, #data/16 do
- local offset = (i-1)*16 + 1
- local byteData = {string.byte(data,offset,offset +15)}
- iv = modeFunction(keySched, byteData, iv)
- buffer.addString(decryptedData, string.char(unpack(byteData)))
- end
- return buffer.toString(decryptedData)
- end
- --
- -- the following 4 functions can be used as
- -- modefunction for decryptString
- --
- -- Electronic code book mode decrypt function
- function public.decryptECB(keySched, byteData, iv)
- aes.decrypt(keySched, byteData, 1, byteData, 1)
- return iv
- end
- -- Cipher block chaining mode decrypt function
- function public.decryptCBC(keySched, byteData, iv)
- local nextIV = {}
- for j = 1, 16 do nextIV[j] = byteData[j] end
- aes.decrypt(keySched, byteData, 1, byteData, 1)
- util.xorIV(byteData, iv)
- return nextIV
- end
- -- Output feedback mode decrypt function
- function public.decryptOFB(keySched, byteData, iv)
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- return iv
- end
- -- Cipher feedback mode decrypt function
- function public.decryptCFB(keySched, byteData, iv)
- local nextIV = {}
- for j = 1, 16 do nextIV[j] = byteData[j] end
- aes.encrypt(keySched, iv, 1, iv, 1)
- util.xorIV(byteData, iv)
- return nextIV
- end
- public.decryptCTR = public.encryptCTR
- return public
- end)
- -- Simple API for encrypting strings.
- --
- AES128 = 16
- AES192 = 24
- AES256 = 32
- ECBMODE = 1
- CBCMODE = 2
- OFBMODE = 3
- CFBMODE = 4
- CTRMODE = 4
- local function pwToKey(password, keyLength, iv)
- local padLength = keyLength
- if (keyLength == AES192) then
- padLength = 32
- end
- if (padLength > #password) then
- local postfix = ""
- for i = 1,padLength - #password do
- postfix = postfix .. string.char(0)
- end
- password = password .. postfix
- else
- password = string.sub(password, 1, padLength)
- end
- local pwBytes = {string.byte(password,1,#password)}
- password = ciphermode.encryptString(pwBytes, password, ciphermode.encryptCBC, iv)
- password = string.sub(password, 1, keyLength)
- return {string.byte(password,1,#password)}
- end
- --
- -- Encrypts string data with password password.
- -- password - the encryption key is generated from this string
- -- data - string to encrypt (must not be too large)
- -- keyLength - length of aes key: 128(default), 192 or 256 Bit
- -- mode - mode of encryption: ecb, cbc(default), ofb, cfb
- --
- -- mode and keyLength must be the same for encryption and decryption.
- --
- function encrypt(password, data, keyLength, mode, iv)
- assert(password ~= nil, "Empty password.")
- assert(data ~= nil, "Empty data.")
- local mode = mode or CBCMODE
- local keyLength = keyLength or AES128
- local key = pwToKey(password, keyLength, iv)
- local paddedData = util.padByteString(data)
- if mode == ECBMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptECB, iv)
- elseif mode == CBCMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptCBC, iv)
- elseif mode == OFBMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptOFB, iv)
- elseif mode == CFBMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptCFB, iv)
- elseif mode == CTRMODE then
- return ciphermode.encryptString(key, paddedData, ciphermode.encryptCTR, iv)
- else
- error("Unknown mode", 2)
- end
- end
- --
- -- Decrypts string data with password password.
- -- password - the decryption key is generated from this string
- -- data - string to encrypt
- -- keyLength - length of aes key: 128(default), 192 or 256 Bit
- -- mode - mode of decryption: ecb, cbc(default), ofb, cfb
- --
- -- mode and keyLength must be the same for encryption and decryption.
- --
- function decrypt(password, data, keyLength, mode, iv)
- local mode = mode or CBCMODE
- local keyLength = keyLength or AES128
- local key = pwToKey(password, keyLength, iv)
- local plain
- if mode == ECBMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptECB, iv)
- elseif mode == CBCMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptCBC, iv)
- elseif mode == OFBMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptOFB, iv)
- elseif mode == CFBMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptCFB, iv)
- elseif mode == CTRMODE then
- plain = ciphermode.decryptString(key, data, ciphermode.decryptCTR, iv)
- else
- error("Unknown mode", 2)
- end
- result = util.unpadByteString(plain)
- if (result == nil) then
- return nil
- end
- return result
- end
- end
- -- SHA-256, HMAC and PBKDF2 functions in ComputerCraft
- -- By Anavrins
- -- For help and details, you can PM me on the CC forums
- -- http://www.computercraft.info/forums2/index.php?/user/12870-anavrins
- -- You may use this code in your projects without asking me, as long as credit is given and this header is kept intact
- -- Pastebin: http://pastebin.com/6UV4qfNF
- local digest, hmac, pbkdf2
- do
- local mod32 = 2^32
- local sha_hashlen = 32
- local sha_blocksize = 64
- local band = bit32 and bit32.band or bit.band
- local bnot = bit32 and bit32.bnot or bit.bnot
- local bxor = bit32 and bit32.bxor or bit.bxor
- local blshift = bit32 and bit32.lshift or bit.blshift
- local upack = unpack
- local function rrotate(n, b)
- local s = n/(2^b)
- local f = s%1
- return (s-f) + f*mod32
- end
- local function brshift(int, by) -- Thanks bit32 for bad rshift
- local s = int / (2^by)
- return s - s%1
- end
- local H = {
- 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
- 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
- }
- local K = {
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
- 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
- 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
- 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
- 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
- }
- local function counter(incr)
- local t1, t2 = 0, 0
- if 0xFFFFFFFF - t1 < incr then
- t2 = t2 + 1
- t1 = incr - (0xFFFFFFFF - t1) - 1
- else t1 = t1 + incr
- end
- return t2, t1
- end
- local function BE_toInt(bs, i)
- return blshift((bs[i] or 0), 24) + blshift((bs[i+1] or 0), 16) + blshift((bs[i+2] or 0), 8) + (bs[i+3] or 0)
- end
- local function preprocess(data)
- local len = #data
- local proc = {}
- data[#data+1] = 0x80
- while #data%64~=56 do data[#data+1] = 0 end
- local blocks = math.ceil(#data/64)
- for i = 1, blocks do
- proc[i] = {}
- for j = 1, 16 do
- proc[i][j] = BE_toInt(data, 1+((i-1)*64)+((j-1)*4))
- end
- end
- proc[blocks][15], proc[blocks][16] = counter(len*8)
- return proc
- end
- local function digestblock(w, C)
- for j = 17, 64 do
- local v = w[j-15]
- local s0 = bxor(bxor(rrotate(w[j-15], 7), rrotate(w[j-15], 18)), brshift(w[j-15], 3))
- local s1 = bxor(bxor(rrotate(w[j-2], 17), rrotate(w[j-2], 19)), brshift(w[j-2], 10))
- w[j] = (w[j-16] + s0 + w[j-7] + s1)%mod32
- end
- local a, b, c, d, e, f, g, h = upack(C)
- for j = 1, 64 do
- local S1 = bxor(bxor(rrotate(e, 6), rrotate(e, 11)), rrotate(e, 25))
- local ch = bxor(band(e, f), band(bnot(e), g))
- local temp1 = (h + S1 + ch + K[j] + w[j])%mod32
- local S0 = bxor(bxor(rrotate(a, 2), rrotate(a, 13)), rrotate(a, 22))
- local maj = bxor(bxor(band(a, b), band(a, c)), band(b, c))
- local temp2 = (S0 + maj)%mod32
- h, g, f, e, d, c, b, a = g, f, e, (d+temp1)%mod32, c, b, a, (temp1+temp2)%mod32
- end
- C[1] = (C[1] + a)%mod32
- C[2] = (C[2] + b)%mod32
- C[3] = (C[3] + c)%mod32
- C[4] = (C[4] + d)%mod32
- C[5] = (C[5] + e)%mod32
- C[6] = (C[6] + f)%mod32
- C[7] = (C[7] + g)%mod32
- C[8] = (C[8] + h)%mod32
- return C
- end
- local mt = {
- __tostring = function(a) return string.char(unpack(a)) end,
- __index = {
- toHex = function(self, s) return ("%02x"):rep(#self):format(unpack(self)) end,
- isEqual = function(self, t)
- if type(t) ~= "table" then return false end
- if #self ~= #t then return false end
- local ret = 0
- for i = 1, #self do
- ret = bit32.bor(ret, bxor(self[i], t[i]))
- end
- return ret == 0
- end
- }
- }
- local function toBytes(t, n)
- local b = {}
- for i = 1, n do
- b[(i-1)*4+1] = band(brshift(band(t[i], 0xFF000000), 24), 0xFF)
- b[(i-1)*4+2] = band(brshift(band(t[i], 0xFF0000), 16), 0xFF)
- b[(i-1)*4+3] = band(brshift(band(t[i], 0xFF00), 8), 0xFF)
- b[(i-1)*4+4] = band(t[i], 0xFF)
- end
- return setmetatable(b, mt)
- end
- digest = function(data)
- data = data or ""
- data = type(data) == "string" and {data:byte(1,-1)} or data
- data = preprocess(data)
- local C = {upack(H)}
- for i = 1, #data do C = digestblock(data[i], C) end
- return toBytes(C, 8)
- end
- hmac = function(data, key)
- local data = type(data) == "table" and {upack(data)} or {tostring(data):byte(1,-1)}
- local key = type(key) == "table" and {upack(key)} or {tostring(key):byte(1,-1)}
- local blocksize = sha_blocksize
- key = #key > blocksize and digest(key) or key
- local ipad = {}
- local opad = {}
- local padded_key = {}
- for i = 1, blocksize do
- ipad[i] = bxor(0x36, key[i] or 0)
- opad[i] = bxor(0x5C, key[i] or 0)
- end
- for i = 1, #data do
- ipad[blocksize+i] = data[i]
- end
- ipad = digest(ipad)
- for i = 1, blocksize do
- padded_key[i] = opad[i]
- padded_key[blocksize+i] = ipad[i]
- end
- return digest(padded_key)
- end
- pbkdf2 = function(pass, salt, iter, dklen)
- local out = {}
- local hashlen = sha_hashlen
- local block = 1
- dklen = dklen or 32
- while dklen > 0 do
- local ikey = {}
- local isalt = type(salt) == "table" and {upack(salt)} or {tostring(salt):byte(1,-1)}
- local clen = dklen > hashlen and hashlen or dklen
- local iCount = #isalt
- isalt[iCount+1] = band(brshift(band(block, 0xFF000000), 24), 0xFF)
- isalt[iCount+2] = band(brshift(band(block, 0xFF0000), 16), 0xFF)
- isalt[iCount+3] = band(brshift(band(block, 0xFF00), 8), 0xFF)
- isalt[iCount+4] = band(block, 0xFF)
- for j = 1, iter do
- isalt = hmac(isalt, pass)
- for k = 1, clen do ikey[k] = bxor(isalt[k], ikey[k] or 0) end
- if j % 200 == 0 then os.queueEvent("PBKDF2", j) coroutine.yield("PBKDF2") end
- end
- dklen = dklen - clen
- block = block+1
- for k = 1, clen do out[#out+1] = ikey[k] end
- end
- return setmetatable(out, mt)
- end
- end
- local function clearMonitors()
- if hardware.listMon > 0 then
- for i = 1, hardware.listMon do
- listMon[i].setBackgroundColor(black)
- listMon[i].clear()
- end
- end
- if hardware.marquee > 0 then
- for i = 1, hardware.marquee do
- marquee[i].setBackgroundColor(black)
- marquee[i].clear()
- end
- end
- if hardware.gateMon > 0 then
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(black)
- gateMon[i].clear()
- end
- end
- if hardware.timerMon > 0 then
- for i = 1, hardware.timerMon do
- timerMon[i].setBackgroundColor(black)
- timerMon[i].clear()
- end
- end
- end
- local function clearScreen(bgColor)
- term.setBackgroundColor(bgColor or black)
- term.clear()
- end
- local function shutDown()
- sendToAllSyncClients("Offline")
- kernelState = false
- if dhdSettings.sync then rednet.unhost("ccDialerWiFi", thisGate) end
- if hardware.modemSide ~= "none" and rednet.isOpen(hardware.modemSide) then rednet.close(hardware.modemSide) end
- if hardware.wifiSide ~= "none" and rednet.isOpen(hardware.wifiSide) then rednet.close(hardware.wifiSide) end
- clearMonitors()
- clearScreen()
- os.pullEvent = stdPullEvent
- term.setTextColor(white)
- term.setCursorPos(1, 1)
- end
- local function clearLockdown()
- secureStatus = "allclear"
- term.setCursorBlink(false)
- drawElement((termX / 2) - 7, 9, 14, 1, nil, black)
- drawElement((termX / 2) - 10, 15, 22, 1)
- gettingInput = false
- validStates[runState][2]()
- if dhdSettings.detailedMarquee then
- initMarquee = true
- displayStatusDetail()
- else
- displayStatus()
- end
- if gateStatus ~= "Idle" then displayAddressBook() end
- end
- local function setupLockdown()
- secureStatus, displayState = "lockdown", "list"
- menuState, fullRedraw, initMarquee = false, false, true
- runState = validStates[runState][1]
- sendToAllSyncClients("Offline")
- if hardware.listMon > 0 then
- for i = 1, hardware.listMon do
- listMon[i].setBackgroundColor(black)
- listMon[i].setTextColor(red)
- listMon[i].clear()
- listMon[i].setCursorPos(1, 5)
- listMon[i].write("!! LOCKDOWN !!")
- end
- end
- if gateMonList then
- gateMonList = false
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(black)
- gateMon[i].clear()
- end
- displayGate()
- end
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- end
- local function recordSessionData() --# Human readable log files (last gate & history)
- local logAddress = incomingAddress or dialAddress --# set logAddress
- logAddress = logAddress == "Wormhole" and "N/A" or logAddress
- local callTime = textutils.formatTime(os.time(), false) --# format the time
- if #callTime == 7 then callTime = " " .. callTime end --# move single digit hour times to the right one space
- local dataLine = tostring(os.day()) .. " @ " .. callTime .. " <" .. callDirection .. "> " .. logAddress --# build the data line to be recorded
- local previousCall = fs.open(lastGate, "w") --# record last call
- previousCall.writeLine(dataLine)
- previousCall.close()
- if dhdSettings.logs then --# record call in log file if logging is turned on
- local callArchive = fs.open(gateHistory, fs.exists(gateHistory) and "a" or "w")
- callArchive.writeLine(dataLine)
- callArchive.close()
- end
- end
- local function paginateAddressBook()
- gatePages = math.ceil(abCount / 18)
- listPages = math.ceil(abCount / 8)
- gateMonPages = math.ceil(abCount / 17)
- end
- local function mergeAddressBooks(newGates)
- local matchFound, abName, abNote, abDim, ngName, ngNote, ngDim = false --# matchFound indicates if a matching gate was found or not
- for i = 1, #newGates do --# start cycling through the list of 'new' gates
- for j = 1, abCount do --# search the address book for a matching address
- if newGates[i].addr == addressBook[j].addr then --# if the gate is already in the address book...
- matchFound = true --# ...set matchFound to true and...
- abName, ngName = addressBook[j].name, newGates[i].name
- if (abName == "Name" or abName == "NO GATES" or abName == "NEW GATE" or abName == addressBook[j].addr) and ngName ~= newGates[i].addr and ngName ~= "NEW GATE" and ngName ~= "NO GATES" and ngName ~= "Name" then
- addressBook[j].name = ngName
- gateChange = true
- end
- abNote, ngNote = addressBook[j].note, newGates[i].note
- if (abNote == "short note" or abNote == "Discovered gate" or abNote == "Added from logs") and ngNote ~= "short note" and ngNote ~= "Discovered gate" and ngNote ~= "Added from logs" then
- addressBook[j].note = ngNote
- gateChange = true
- end
- if addressBook[j].rating == "U" and newGates[i].rating ~= "U" then
- addressBook[j].rating = newGates[i].rating
- gateChange = true
- end
- abDim, ngDim = addressBook[j].loc.dim, newGates[i].loc.dim
- if (abDim == "Overworld" and ngDim ~= "Overworld" and ngDim ~= "Unspecified") or (abDim == "Unspecified" and ngDim ~= "Unspecified") then
- addressBook[j].loc.dim = ngDim
- gateChange = true
- end
- if addressBook[j].loc.x == 0 and addressBook[j].loc.y == 0 and addressBook[j].loc.z == 0 and (newGates[i].loc.x ~= 0 or newGates[i].loc.y ~= 0 or newGates[i].loc.z ~= 0) then
- addressBook[j].loc.x, addressBook[j].loc.y, addressBook[j].loc.z = newGates[i].loc.x, newGates[i].loc.y, newGates[i].loc.z
- gateChange = true
- end
- break --# stop the address book search loop and move on...
- end
- end
- if matchFound then --# if a match was found...
- matchFound = false --# reset the variable for the next iteration of the loop
- else --# if a match wasn't found...
- addressBook[abCount + 1], abCount = { }, abCount + 1 --# initialize a new address book entry
- for k, v in pairs(newGates[i]) do --# loop through the gate entries...
- addressBook[abCount][k] = v --# ...and add them to the new address book entry
- end
- addressBook[abCount].iris = "none" --# set iris control to 'none'
- addressBook[abCount].callDrop = false --# set callDrop to false
- gateChange = true --# indicate that address book data has changed
- end
- end
- paginateAddressBook() --# repaginate AddressBook
- end
- sendToAllSyncClients = function(data)
- if clientCount < 1 then return end
- for id in pairs(clients) do
- netSend(id, { program = "ccDialer", data = data }, "ccDialerWiFi")
- if data == "Offline" then
- clients[id] = nil
- clientCount = math.max(0, clientCount - 1)
- end
- end
- end
- netSend = function(target, dataPack, protocol)
- if hardware.modemSide ~= "none" and not rednet.isOpen(hardware.modemSide) then rednet.open(hardware.modemSide) end
- if target == dhdSettings.gate then
- if hardware.modemSide ~= "none" and hardware.wifiSide ~= "none" then
- if rednet.isOpen(hardware.wifiSide) then rednet.close(hardware.wifiSide) end
- elseif hardware.modemSide == "none" and hardware.wifiSide ~= "none" then
- if not rednet.isOpen(hardware.wifiSide) then rednet.open(hardware.wifiSide) end
- end
- else
- if hardware.wifiSide ~= "none" and not rednet.isOpen(hardware.wifiSide) then rednet.open(hardware.wifiSide) end
- end
- local encKey = tostring(target) .. "ccDHD!General_Comms*Key" .. thisCC
- local encryptedDataPack = encode(encrypt(encKey, textutils.serialize(dataPack)))
- rednet.send(target, encryptedDataPack, protocol or "ccDHD")
- if target == dhdSettings.gate and hardware.wifiSide ~= "none" then
- if not rednet.isOpen(hardware.wifiSide) then rednet.open(hardware.wifiSide) end
- end
- end
- local function netReceive()
- local id, message, encKey, encryptedMessage, decryptedMessage, encodedMessage, success, iColor, mData, iPass, lockPass
- while true do
- if hardware.modemSide ~= "none" and not rednet.isOpen(hardware.modemSide) then rednet.open(hardware.modemSide) end
- if hardware.wifiSide ~= "none" and not rednet.isOpen(hardware.wifiSide) then rednet.open(hardware.wifiSide) end
- id, encodedMessage = rednet.receive("ccDHD")
- if id == dhdSettings.gate and type(encodedMessage) == "string" then
- success, encryptedMessage = pcall(decode, encodedMessage)
- if success then
- encKey = thisCC .. "ccDHD!General_Comms*Key" .. tostring(id)
- success, decryptedMessage = pcall(decrypt, encKey, encryptedMessage)
- if success then
- success, message = pcall(textutils.unserialize, decryptedMessage)
- if success and type(message) == "table" and message.program then
- if message.program == "ccDHD" then
- updateStatus(message)
- if message.gateStatus == "Disconnecting" and type(dhdSettings.ecIris) == "boolean" then
- if (irisState and dhdSettings.ecIris and secureStatus == "allclear") or (not irisState and not dhdSettings.ecIris) then
- netSend(dhdSettings.gate, { program = "ccDHD", command = dhdSettings.ecIris and "iOPEN" or "iCLOSE" })
- end
- end
- elseif message.program == "ccDialer" and message.data then
- mData, iPass, lockPass = message.data, dhdSettings.irisPassword, dhdSettings.password
- if mData == iPass or mData == lockPass then
- if secureStatus == "lockdown" and mData == lockPass then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "allclear" })
- return clearLockdown()
- elseif secureStatus == "allclear" and mData == lockPass then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "lockdown" })
- return setupLockdown()
- elseif secureStatus == "allclear" and mData == iPass then
- netSend(dhdSettings.gate, { program = "ccDHD", command = irisState and "iOPEN" or "iCLOSE" })
- end
- elseif mData == "open" or mData == "closed" or mData == "unk" then
- sendToAllSyncClients(mData)
- remoteIrisStatus = mData
- drawRemoteIrisStatus()
- elseif mData == "Idle" or mData == "Dialing" or mData == "Paused" or mData == "Connected" then
- sendToAllSyncClients(mData)
- end
- end
- end
- end
- end
- end
- end
- end
- local function syncReceive()
- local id, encKey, message, encryptedMessage, decryptedMessage, encodedMessage, mLength, mCommand, mGate, success
- while true do
- if dhdSettings.sync and hardware.wifiSide ~= "none" and not rednet.isOpen(hardware.wifiSide) then rednet.open(hardware.wifiSide) end
- id, encodedMessage = rednet.receive("ccDialerWiFi")
- if dhdSettings.sync and type(encodedMessage) == "string" then
- success, encryptedMessage = pcall(decode, encodedMessage)
- if success then
- encKey = thisCC .. "ccDHD!General_Comms*Key" .. tostring(id)
- success, decryptedMessage = pcall(decrypt, encKey, encryptedMessage)
- if success then
- success, message = pcall(textutils.unserialize, decryptedMessage)
- if success and type(message) == "table" and message.program and message.program == "ccDialer" then
- if message.command and type(message.command) == "string" then
- mCommand, mGate = message.command, message.gate
- mLength = #tostring(mCommand)
- if mCommand == "QRY" and mGate == "NO HOST" then
- if secureStatus == "allclear" then
- if not clients[id] then clientCount = clientCount + 1 end
- clients[id] = 0
- end
- netSend(id, { program = "ccDialer", data = secureStatus == "allclear" and thisGate or "lockdown", ccDHD = dhdSettings.sync == true, gStatus = gateStatus, iris = remoteIrisStatus }, "ccDialerWiFi")
- elseif mCommand == "ping" and thisGate == mGate and clients[id] then
- netSend(id, { program = "ccDialer", data = "pong" }, "ccDialerWiFi")
- elseif mCommand == "pong" and thisGate == mGate and clients[id] then
- clients[id] = 0
- elseif mCommand == "logout" and thisGate == mGate and clients[id] then
- clients[id] = nil
- clientCount = math.max(0, clientCount - 1)
- elseif mCommand == "pull" and thisGate == mGate and clients[id] and type(dhdSettings.sync) ~= "string" and secureStatus == "allclear" then
- netSend(id, { program = "ccDialer", command = "push", data = addressBook }, "ccDialerWiFi")
- elseif mCommand == "push" and thisGate == mGate and clients[id] and type(dhdSettings.sync) ~= "string" and secureStatus == "allclear" and message.data and type(message.data) == "table" then
- mergeAddressBooks(message.data)
- if gateChange then
- saveData(gateData, "gate")
- if dialStates[runState] then fullRedraw = menuState drawCLI(true) end
- if gettingInput then repositionCursor() end
- end
- elseif mCommand ~= thisGate and thisGate == mGate and clients[id] and (mLength == 7 or mLength == 9) then
- if mCommand == "endCall" and gateStatus ~= "Disconnecting" and gateStatus ~= "Idle" then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "endCall" })
- elseif mCommand ~= "endCall" and gateStatus == "Idle" and secureStatus == "allclear" then
- dialAddress = mCommand
- netSend(dhdSettings.gate, { program = "ccDHD", command = dialAddress })
- elseif lcGate and mCommand == dialAddress and (gateStatus == "Dialing" or gateStatus == "Paused") and secureStatus == "allclear" then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "dialPause" })
- end
- end
- elseif message.password and thisGate == message.gate and clients[id] and secureStatus == "allclear" then
- netSend(dhdSettings.gate, { program = "ccDialer", password = message.password })
- end
- end
- end
- end
- end
- end
- end
- local function updateDisplays(init, backSpace)
- if displayState == "list" then
- if dhdSettings.detailedMarquee then
- initMarquee = init == true
- displayStatusDetail()
- else
- displayStatus()
- end
- if gateStatus ~= "Idle" then displayAddressBook() end
- else
- displayNotes()
- end
- if gateMonList then
- displayGateMonAddrBook()
- else
- displayChevrons(init, backSpace)
- end
- end
- updateStatus = function(newInfo)
- local monUpdate, recordInfo, backSpace, addr = initMarquee, false, false
- sgRemoteAddrLen = newInfo.sgRemoteAddrLen
- if fuelPercent ~= newInfo.fuelPercent or waitingForIris ~= newInfo.waitingForIris or irisState ~= newInfo.irisState or irisStatus ~= newInfo.irisStatus or irisPercent ~= newInfo.irisPercent or gateStatus ~= newInfo.gateStatus or dialAddress ~= newInfo.dialAddress or incomingAddress ~= newInfo.incomingAddress or chevronNumber ~= newInfo.chevronNumber then
- monUpdate = true
- end
- if menuState and ((newInfo.gateStatus == "Idle" and gateStatus ~= newInfo.gateStatus) or waitingForIris ~= newInfo.waitingForIris or irisState ~= newInfo.irisState) then
- fullRedraw = true --# trigger a full redraw later
- end
- waitingForIris = newInfo.waitingForIris
- irisState = newInfo.irisState
- irisStatus = newInfo.irisStatus
- irisPercent = newInfo.irisPercent
- fuelPercent = newInfo.fuelPercent
- dialAddress = newInfo.dialAddress
- incomingAddress = newInfo.incomingAddress
- callDirection = newInfo.callDirection
- if chevronNumber > newInfo.chevronNumber then backSpace = true end
- chevronNumber = newInfo.chevronNumber
- if currentState == "DHD" then
- if newInfo.gateStatus ~= gateStatus then
- if newInfo.gateStatus == "Connected" then
- connectionTimer = os.startTimer(0.1) --# not done during init due to delay caused by Sync later during init/startup phase
- local iLength = #tostring(incomingAddress)
- if dialAddress ~= "none" or incomingAddress == "Wormhole" or iLength == 7 or iLength == 9 then
- recordInfo = true
- end
- elseif newInfo.gateStatus == "Idle" or newInfo.gateStatus == "Offline" then
- if connectionTimer then os.cancelTimer(connectionTimer) connectionTimer = nil end
- connectionTime, connectionClock = 0, "00:00:0"
- displayConnectionTime()
- end
- end
- else
- lcGate = newInfo.lcGate
- thisGate = newInfo.thisGate
- secureStatus = newInfo.secureStatus --# why did I move this to init? Shouldn't this be set every time, or were there problems?
- currentState = "DHD" --# one of the last steps of initialization - don't record connections that are already established upon startup
- end
- if newInfo.gateStatus ~= gateStatus then
- if newInfo.gateStatus == "Connected" then
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end --# Dialing alarm
- elseif newInfo.gateStatus == "Dialing" and callDirection == "Outgoing" and dialAddress:find("?") then
- dialFromDHD = true
- elseif (newInfo.gateStatus == "Dialing" or newInfo.gateStatus == "Connected") and incomingAddress and incomingAddress ~= "Wormhole" then --# Blacklist
- for i = 1, abCount do
- addr = addressBook[i].addr
- if addressBook[i].callDrop and (addr == incomingAddress or addr == incomingAddress:sub(1, 7) or addr:sub(1, 7) == incomingAddress) then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "endCall" })
- break
- end
- end
- elseif newInfo.gateStatus == "Idle" or newInfo.gateStatus == "Offline" then
- dialFromDHD = false
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end --# Dialing alarm
- end
- if newInfo.gateStatus == "Dialing" and (callDirection == "Incoming" or (callDirection == "Outgoing" and outgoingAlarm)) then
- if rsSide ~= "none" then rs.setOutput(rsSide, true) end --# Dailing alarm
- end
- gateStatus = newInfo.gateStatus
- end
- local irisClose, irisManage = false, false
- if (recordInfo or runState == "init") and incomingAddress and secureStatus == "allclear" then --# Iris management
- if dhdSettings.incomingIris then irisClose = true end
- irisManage = true
- end
- if irisManage then
- for i = 1, abCount do
- addr = addressBook[i].addr
- if addr == incomingAddress or addr == incomingAddress:sub(1, 7) or addr:sub(1, 7) == incomingAddress then
- if type(addressBook[i].iris) == "boolean" then --# addressBook entry automatic iris control is set to 'open' (true) or 'close' (false)
- if addressBook[i].iris then
- if irisState then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "iOPEN" })
- end
- irisClose = false
- else
- irisClose = true
- end
- end
- break
- end
- end
- end
- if irisClose and not irisState then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "iCLOSE" })
- end
- if recordInfo then recordSessionData() end
- if validStates[runState] then
- if validStates[runState][5] then
- drawCLI(monUpdate, nil, backSpace)
- elseif monUpdate then
- updateDisplays(nil, backSpace)
- end
- end
- end
- saveData = function(fileName, fileType)
- local dhdData = fs.open(fileName, "w")
- if fileType == "cfg" then
- dhdData.write(textutils.serialize(dhdSettings))
- configChange = false
- elseif fileType == "gate" then
- dhdData.write(textutils.serialize(addressBook))
- if fileName == gateData then gateChange = false end
- end
- dhdData.close()
- end
- local function ingestData(fileName, fileType)
- if fileName == "logs" then --# Logs
- if fs.exists(gateHistory) then
- for logEntry in io.lines(gateHistory) do
- table.insert(callHistory, 1, logEntry)
- end
- logPages = math.max(1, math.ceil(#callHistory / 11)) --# paginate call logs
- end
- if fs.exists(lastGate) then
- local dhdLast = fs.open(lastGate, "r")
- lastCall = dhdLast.readLine()
- dhdLast.close()
- end
- else
- local dhdData = fs.open(fileName, "r")
- local dhdInfo = dhdData.readAll()
- dhdData.close()
- if fileType == "cfg" then --# Config
- dhdSettings = textutils.unserialize(dhdInfo)
- if dhdSettings.startIris ~= nil or not dhdSettings.irisPassword or not dhdSettings.hashedPWs or dhdSettings.pSync ~= nil or dhdSettings.highlight ~= nil then
- --# Upgrade path from 1.5 to 2.0 for SGCraft users
- if dhdSettings.startIris ~= nil then
- dhdSettings.incomingIris = dhdSettings.startIris
- dhdSettings.startIris = nil
- end
- if not dhdSettings.irisPassword then
- dhdSettings.irisPassword = "password"
- if dhdSettings.hashedPWs then
- if dhdSettings.newHash then
- dhdSettings.irisPassword = table.concat(pbkdf2(dhdSettings.irisPassword, "ccDHD!Pass.Hash", 15))
- else
- dhdSettings.irisPassword = table.concat(pbkdf2(dhdSettings.irisPassword, "ccDHD!pSync", 15))
- end
- end
- end
- if not dhdSettings.hashedPWs then
- dhdSettings.hashedPWs, dhdSettings.newHash = true, true
- dhdSettings.password = table.concat(pbkdf2(dhdSettings.password, "ccDHD!Pass.Hash", 15))
- dhdSettings.irisPassword = table.concat(pbkdf2(dhdSettings.irisPassword, "ccDHD!Pass.Hash", 15))
- end
- if dhdSettings.pSync ~= nil then
- dhdSettings.sync = dhdSettings.pSync
- dhdSettings.pSync = nil
- end
- if dhdSettings.highlight ~= nil then
- dhdSettings.detailedMarquee = true
- dhdSettings.highlight = nil
- end
- --# End upgrade path
- saveData(settingsData, "cfg")
- end
- elseif fileType == "gate" then --# Address book (main or backup)
- for i = abCount, 1, -1 do
- addressBook[i] = nil
- end
- addressBook = textutils.unserialize(dhdInfo)
- abCount = #addressBook
- --# Upgrade path from 1.5 to 2.0 for SGCraft users
- local saveIt = false
- if addressBook[1].callDrop == nil then
- for i = 1, abCount do
- addressBook[i].callDrop = false
- end
- saveIt = true
- end
- for i = 1, abCount do
- if addressBook[i].iris == "open" then
- addressBook[i].iris, saveIt = true, true
- elseif addressBook[i].iris == "close" then
- addressBook[i].iris, saveIt = false, true
- end
- end
- if saveIt and fileName == gateData then saveData(gateData, "gate") end
- --# End upgrade path
- gatePage, listPage, gateMonPage = 1, 1, 1
- gateChange = false
- paginateAddressBook()
- end
- end
- end
- local function assignColor(gateNumber)
- return classifications[addressBook[gateNumber].rating].color or silver
- end
- local function assignRating(gateNumber)
- return classifications[addressBook[gateNumber].rating].long or (classifications[addressBook[gateNumber].rating].label or "Unknown/Unclassified")
- end
- repositionCursor = function() --# account for screen writes repositioning the cursor
- term.setBackgroundColor(bgCol)
- term.setTextColor(txtCol)
- term.setCursorPos((runState == "goPage" or runState == "remotePass") and curX or curX + #word, curY)
- if (runState == "goPage" or runState == "remotePass") and word ~= "" then term.write(runState == "goPage" and word or string.rep("*", #word)) end
- end
- displayGateMonAddrBook = function()
- if hardware.gateMon == 0 or not gateMonList then return end
- local yPos, firstGate, spacer, gm, addr = 0, ((gateMonPage - 1) * 17) + 1, string.rep(" ", 29)
- for i = 1, hardware.gateMon do
- yPos, gm = 0, gateMon[i]
- for j = firstGate, firstGate + 16 do
- yPos = yPos + 1
- gm.setCursorPos(1, yPos)
- if j > abCount then
- gm.setBackgroundColor(black)
- gm.write(spacer)
- else
- addr = addressBook[j].addr
- if (addr == thisGate or addr:sub(1, 7) == thisGate or addr == thisGate:sub(1, 7)) and dialAddress == "none" and not incomingAddress then
- gm.setBackgroundColor(gray)
- else
- gm.setBackgroundColor((dialAddress == "none" and not incomingAddress) and green or red)
- end
- gm.setTextColor(((addr == thisGate or addr:sub(1, 7) == thisGate or addr == thisGate:sub(1, 7)) and dialAddress == "none" and not incomingAddress) and silver or white)
- gm.write((dialAddress == "none" and not incomingAddress) and " Dial " or "Hangup")
- gm.setCursorPos(8, yPos)
- gm.setBackgroundColor(black)
- if addr == thisGate then
- gm.setTextColor(gray)
- else
- gm.setTextColor(((dialAddress == "none" and not incomingAddress) or (dialAddress == addr or dialAddress:sub(1, 7) == addr or dialAddress == addr:sub(1, 7) or (incomingAddress and (incomingAddress == addr or incomingAddress:sub(1, 7) == addr or incomingAddress == addr:sub(1, 7))))) and assignColor(j) or gray)
- end
- gm.write(addressBook[j].name .. string.rep(" ", 12 - #addressBook[j].name))
- gm.setCursorPos(21, yPos)
- if addr == thisGate then
- gm.setTextColor(gray)
- else
- gm.setTextColor(((dialAddress == "none" and not incomingAddress) or (dialAddress == addr or dialAddress:sub(1, 7) == addr or dialAddress == addr:sub(1, 7) or (incomingAddress and (incomingAddress == addr or incomingAddress:sub(1, 7) == addr or incomingAddress == addr:sub(1, 7))))) and yellow or gray)
- end
- gm.write(addr .. " ")
- end
- end
- gm.setCursorPos(1, 19)
- gm.setBackgroundColor(cyan)
- gm.setTextColor(white)
- gm.write(" /\\ \\/ ")
- gm.setCursorPos(12, 19)
- gm.setBackgroundColor(gray)
- gm.write(" Close ")
- end
- end
- displayAddressBook = function()
- if hardware.listMon == 0 then return end
- local firstGate, yPos, lm, addr = ((listPage - 1) * 8) + 1, 0
- for i = 1, hardware.listMon do
- yPos, lm = 0, listMon[i]
- lm.setBackgroundColor(black)
- lm.clear()
- for j = firstGate, math.min(firstGate + 7, abCount) do
- yPos, addr = yPos + 1, addressBook[j].addr
- lm.setTextColor((addr == thisGate or addr:sub(1, 7) == thisGate or addr == thisGate:sub(1, 7)) and gray or assignColor(j))
- lm.setCursorPos(2, yPos)
- lm.write(addressBook[j].name)
- end
- lm.setBackgroundColor(cyan)
- lm.setTextColor(white)
- lm.setCursorPos(1, 10)
- lm.write(" /\\ \\/ ")
- end
- end
- displayNotes = function()
- if hardware.listMon > 0 then
- local gateColor, name, address, lm = assignColor(selectedGate), addressBook[selectedGate].name, addressBook[selectedGate].addr
- for i = 1, hardware.listMon do
- lm = listMon[i]
- lm.setBackgroundColor(black)
- lm.clear()
- lm.setBackgroundColor(gateColor)
- for j = 1, 10, 9 do
- lm.setCursorPos(1, j)
- lm.write(" ")
- end
- lm.setBackgroundColor(black)
- lm.setCursorPos(2, 3)
- lm.setTextColor(cyan)
- lm.write(name)
- lm.setCursorPos(2, 5)
- lm.setTextColor(yellow)
- lm.write(address)
- if address == thisGate then
- lm.setTextColor(gray)
- lm.setCursorPos(2, 7)
- lm.write("THIS GATE")
- end
- end
- end
- if hardware.marquee > 0 then
- local dimension, note = addressBook[selectedGate].loc.dim, addressBook[selectedGate].note
- local noteLength, noteA, noteB, m = #note
- if noteLength > 29 then --# Note
- local breakPoint = note:sub(25, 30):find(" ") + 23
- noteA = note:sub(1, breakPoint)
- noteB = note:sub(breakPoint + 2)
- end
- for i = 1, hardware.marquee do
- m = marquee[i]
- m.setTextScale(1)
- m.setBackgroundColor(black)
- m.clear()
- m.setCursorPos(1, 2)
- m.setTextColor(brown)
- m.write(dimension)
- m.setCursorPos(1, 4)
- m.setTextColor(white)
- if noteLength > 29 then
- m.write(noteA)
- m.setCursorPos(2, 5)
- m.write(noteB)
- else
- m.write(note)
- end
- end
- end
- end
- do
- local chevrons7LC = {
- [1] = { x = 22, y = 5 }; --# 1
- [2] = { x = 25, y = 8 }; --# 2
- [3] = { x = 25, y = 13 }; --# 3
- [4] = { x = 5, y = 13 }; --# 6
- [5] = { x = 5, y = 8 }; --# 7
- [6] = { x = 8, y = 5 }; --# 8
- [7] = { x = 15, y = 3 }; --# 0
- }
- local chevrons9LC = {
- [1] = { x = 22, y = 5 }; --# 1
- [2] = { x = 25, y = 8 }; --# 2
- [3] = { x = 25, y = 13 }; --# 3
- [4] = { x = 5, y = 13 }; --# 6
- [5] = { x = 5, y = 8 }; --# 7
- [6] = { x = 8, y = 5 }; --# 8
- [7] = { x = 22, y = 16 }; --# 4
- [8] = { x = 8, y = 16 }; --# 5
- [9] = { x = 15, y = 3 }; --# 0
- }
- local chevrons7SG = {
- [1] = { x = 22, y = 5 }; --# 1
- [2] = { x = 25, y = 8 }; --# 2
- [3] = { x = 25, y = 13 }; --# 3
- [4] = { x = 5, y = 13 }; --# 6
- [5] = { x = 5, y = 8 }; --# 7
- [6] = { x = 8, y = 5 }; --# 8
- [7] = { x = 15, y = 3 }; --# 0
- }
- local chevrons9SG = {
- [1] = { x = 22, y = 5 }; --# 1
- [2] = { x = 25, y = 8 }; --# 2
- [3] = { x = 25, y = 13 }; --# 3
- [4] = { x = 5, y = 13 }; --# 6
- [5] = { x = 5, y = 8 }; --# 7
- [6] = { x = 8, y = 5 }; --# 8
- [7] = { x = 22, y = 16 }; --# 4
- [8] = { x = 8, y = 16 }; --# 5
- [9] = { x = 15, y = 3 }; --# 0
- }
- local wormhole = {
- [1] = { x = 11, y = 5, line = " " };
- [2] = { x = 10, y = 6, line = " " };
- [3] = { x = 9, y = 7, line = " " };
- [4] = { x = 8, y = 8, line = " " };
- [5] = { x = 7, y = 9, line = " " };
- [6] = { x = 6, y = 10, line = " " };
- [7] = { x = 6, y = 11, line = " " };
- [8] = { x = 7, y = 12, line = " " };
- [9] = { x = 8, y = 13, line = " " };
- [10] = { x = 9, y = 14, line = " " };
- [11] = { x = 10, y = 15, line = " " };
- [12] = { x = 11, y = 16, line = " " };
- }
- local function displayWormhole()
- local bgColor, gm, w = gateStatus == "Connected" and blue or black
- for i = 1, hardware.gateMon do
- gm = gateMon[i]
- gm.setBackgroundColor(bgColor)
- for j = 1, 12 do
- w = wormhole[j]
- gm.setCursorPos(w.x, w.y)
- gm.write(w.line)
- end
- end
- end
- local function displayGlyph(i, chevron, addrLen, backSpace)
- if addrLen == 7 or addrLen == 9 or backSpace then
- local gm = gateMon[i]
- if lcGate then
- gm.setCursorPos(addrLen == 7 and chevrons7LC[chevron].x or chevrons9LC[chevron].x, addrLen == 7 and chevrons7LC[chevron].y or chevrons9LC[chevron].y)
- else
- if chevron > sgRemoteAddrLen then sgRemoteAddrLen = 9 end
- gm.setCursorPos((addrLen == 7 or sgRemoteAddrLen == 7) and chevrons7SG[chevron].x or chevrons9SG[chevron].x, (addrLen == 7 or sgRemoteAddrLen == 7) and chevrons7SG[chevron].y or chevrons9SG[chevron].y)
- end
- if backSpace then
- gm.write(" ")
- else
- gm.write(incomingAddress and incomingAddress:sub(chevron, chevron) or dialAddress:sub(chevron, chevron))
- end
- end
- end
- displayChevrons = function(init, backSpace)
- if hardware.gateMon == 0 or gateMonList then return end
- local gm
- if gateStatus == "Idle" then
- if not init then
- for i = 1, hardware.gateMon do
- gm = gateMon[i]
- gm.setBackgroundColor(silver)
- for j = 1, 9 do
- gm.setCursorPos(chevrons9LC[j].x, chevrons9LC[j].y)
- gm.write(" ")
- end
- end
- displayWormhole()
- end
- elseif gateStatus == "Connected" then
- local addrLen = incomingAddress and #incomingAddress or #dialAddress
- if init then
- if addrLen == 7 or addrLen == 9 then
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(orange)
- gateMon[i].setTextColor(black)
- for j = 1, sgRemoteAddrLen == 0 and addrLen or sgRemoteAddrLen do
- displayGlyph(i, j, addrLen)
- end
- end
- end
- else
- if addrLen == 7 and dialFromDHD then
- for i = 1, hardware.gateMon do
- gm = gateMon[i]
- gm.setBackgroundColor(silver)
- for j = 1, 9 do
- gm.setCursorPos(chevrons9LC[j].x, chevrons9LC[j].y)
- gm.write(" ")
- end
- gm.setBackgroundColor(orange)
- gm.setTextColor(black)
- for j = 1, sgRemoteAddrLen == 0 and addrLen or sgRemoteAddrLen do
- displayGlyph(i, j, addrLen)
- end
- end
- end
- end
- displayWormhole()
- elseif gateStatus == "Dialing" and backSpace then
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(silver)
- displayGlyph(i, chevronNumber + 1, 9, true)
- end
- elseif gateStatus ~= "Disconnecting" then
- if chevronNumber > 0 then
- local addrLen = incomingAddress and #incomingAddress or #dialAddress
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(orange)
- gateMon[i].setTextColor(black)
- if init then
- for j = 1, chevronNumber do
- displayGlyph(i, j, addrLen)
- end
- else
- displayGlyph(i, chevronNumber, addrLen)
- end
- end
- end
- end
- end
- end
- do
- local gateImage = {
- {},
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, },
- { 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 256, 128, 128, 128, 128, 128, 128, 128, },
- { 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, },
- { 0, 0, 0, 0, 0, 128, 128, 256, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 256, 128, 128, },
- { 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, },
- { 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, },
- { 0, 0, 128, 128, 256, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 256, 128, 128, },
- { 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, },
- { 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, },
- { 0, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, },
- { 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, },
- { 0, 0, 128, 128, 256, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 256, 128, 128, },
- { 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, },
- { 0, 0, 0, 0, 128, 128, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, },
- { 0, 0, 0, 0, 0, 128, 128, 256, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 256, 128, 128, },
- { 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, },
- { 0, 0, 0, 0, 0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, },
- }
- displayGate = function()
- if hardware.gateMon == 0 then return end
- local oldTerm = term.redirect(gateMon[1])
- paintutils.drawImage(gateImage, 1, 1)
- if hardware.gateMon > 1 then
- for i = 2, hardware.gateMon do
- term.redirect(gateMon[i])
- paintutils.drawImage(gateImage, 1, 1)
- end
- end
- term.redirect(oldTerm)
- end
- end
- displayConnectionTime = function()
- if validStates[runState][5] or secureStatus == "lockdown" then
- drawElement(42, 1, 9, 1, connectionTime > 0 and white or gray, black, connectionClock)
- if gettingInput then repositionCursor() end
- end
- if not timerMon[1] then return end
- for i = 1, hardware.timerMon do
- if connectionTime < 2 then
- timerMon[i].setCursorPos(1, 1)
- timerMon[i].setTextColor(connectionTime > 0 and green or gray)
- timerMon[i].write("Connect")
- end
- timerMon[i].setCursorPos(1, 2)
- timerMon[i].setTextColor(connectionTime > 0 and white or gray)
- timerMon[i].write(connectionClock)
- end
- end
- do
- local gateStatusColors = {
- Idle = { green, green };
- Dialing = { orange, orange };
- Connected = { sky, red };
- Disconnecting = { sky, orange };
- }
- displayStatusDetail = function()
- if gateStatus == "Idle" and secureStatus == "allclear" then
- if displayState == "list" then
- displayAddressBook()
- else
- displayNotes()
- return
- end
- end
- if hardware.marquee == 0 then return end
- local irisStateString, irisStateColor, irisPercentColor, irisPercentString = irisState and "Closed" or "Open", irisState and green or orange, irisPercent > 49 and green or (irisPercent < 25 and red or orange), tostring(irisPercent)
- local fuelPercentString, fuelColor, gName, line, gIndex, m = tostring(fuelPercent), fuelPercent > 24 and green or (fuelPercent < 6 and red or orange), thisGate, string.rep(" ", 57)
- if initMarquee then
- for i = 1, abCount do
- if addressBook[i].addr == thisGate then
- gName, gIndex = addressBook[i].name, i
- break
- end
- end
- local textX, outlineColor = math.floor((57 - #gName) / 2), secureStatus == "allclear" and (gIndex and assignColor(gIndex) or blue) or red
- for i = 1, hardware.marquee do
- m = marquee[i]
- m.setTextScale(0.5) --# 3 x 1 = 57 x 10
- m.setBackgroundColor(black)
- m.clear()
- m.setBackgroundColor(outlineColor)
- m.setTextColor(white)
- m.setCursorPos(1, 1)
- m.write(line)
- m.setCursorPos(1, 10)
- m.write(line)
- m.setCursorPos(textX, 1)
- m.write(gName)
- m.setBackgroundColor(secureStatus == "allclear" and green or red)
- m.setCursorPos(24, 9)
- m.write(secureStatus == "allclear" and " All Clear " or " LOCKDOWN ")
- m.setBackgroundColor(black)
- m.setTextColor(gray)
- m.setCursorPos(2, 3)
- m.write("This Gate Target")
- m.setCursorPos(2, 5)
- m.write("Iris Status Gate Status")
- m.setCursorPos(2, 7)
- m.write("Fuel Direction")
- m.setTextColor(secureStatus == "allclear" and yellow or red)
- m.setCursorPos(15, 3)
- m.write(secureStatus == "allclear" and thisGate or "LOCKDOWN") --# thisGate
- end
- initMarquee = false
- end
- for i = 1, hardware.marquee do
- m = marquee[i]
- --# Column 1
- m.setBackgroundColor(black)
- m.setTextColor(irisStateColor)
- m.setCursorPos(15, 5)
- m.write(irisStateString .. " ") --# iris status
- if lcGate then
- m.setTextColor(gray)
- m.write("/ ")
- m.setTextColor(irisPercentColor)
- m.write(irisPercentString) --# iris percent
- m.setTextColor(gray)
- m.write("% ")
- end
- m.setTextColor(fuelColor)
- m.setCursorPos(15, 7)
- m.write(fuelPercentString) --# fuel percent
- m.setTextColor(gray)
- m.write("% ")
- --# Column 2
- m.setTextColor(gateStatus == "Idle" and silver or gray)
- m.setCursorPos(42, 3)
- m.write((incomingAddress or dialAddress) .. " ") --# target address
- if gateStatus == "Dialing" or gateStatus == "Connected" then
- m.setTextColor(secureStatus == "allclear" and yellow or orange)
- m.setCursorPos(42, 3)
- if incomingAddress then
- if lcGate then --# LanteaCraft
- m.write(incomingAddress)
- else --# SGCraft
- if gateStatus == "Connected" and chevronNumber == 0 then chevronNumber = #incomingAddress end
- if chevronNumber > 0 then marquee[i].write(incomingAddress:sub(1, chevronNumber)) end
- m.setTextColor(gray)
- m.write(incomingAddress:sub(chevronNumber + 1))
- end
- else
- if gateStatus == "Connected" and chevronNumber == 0 then chevronNumber = #dialAddress end
- if chevronNumber > 0 then marquee[i].write(dialAddress:sub(1, chevronNumber)) end
- m.setTextColor(gray)
- m.write(dialAddress:sub(chevronNumber + 1))
- end
- end
- m.setTextColor(secureStatus == "allclear" and (gateStatusColors[gateStatus][1] or red) or (gateStatusColors[gateStatus][2] or red))
- m.setCursorPos(42, 5)
- m.write(gateStatus .. " ") --# gateStatus
- m.setTextColor(callDirection == "none" and silver or orange) --(secureStatus == "allclear" and orange or red))
- m.setCursorPos(42, 7)
- m.write(callDirection .. " ") --# call direction
- end
- end
- end
- do
- local function makeLongName(name) --# This spaces out a 7 character address
- return #name ~= 7 and name or table.concat({ name:sub(1, 1), " ", name:sub(2, 2), " ", name:sub(3, 3), " ", name:sub(4, 4), " ", name:sub(5, 5), " ", name:sub(6, 6), " ", name:sub(7) })
- end
- displayStatus = function()
- if gateStatus == "Idle" and secureStatus == "allclear" then
- if displayState == "list" then --# Display the local address when there is no other information to display
- if hardware.marquee > 0 then
- local longAddress, xPos, m = makeLongName(thisGate), #thisGate - 5
- for i = 1, hardware.marquee do
- m = marquee[i]
- m.setTextScale(2)
- m.setBackgroundColor(black)
- m.clear()
- m.setTextColor(cyan)
- m.setCursorPos(1, 1)
- m.write("Stargate")
- m.setTextColor(yellow)
- m.setCursorPos(xPos, 2)
- m.write(longAddress)
- end
- end
- displayAddressBook()
- else
- displayNotes()
- end
- return
- end
- if hardware.marquee > 0 then
- local longAddress = incomingAddress and makeLongName(incomingAddress) or makeLongName(dialAddress)
- local addrLen = incomingAddress and #incomingAddress or #dialAddress
- local tX, sBuffer, m = addrLen - 5, string.rep(" ", 9 - addrLen)
- for i = 1, hardware.marquee do
- m = marquee[i]
- m.setTextScale(2)
- m.setBackgroundColor(black)
- m.setCursorPos(1, 1)
- end
- if gateStatus == "Dialing" or gateStatus == "Paused" then
- if incomingAddress then --# incoming call
- for i = 1, hardware.marquee do
- m = marquee[i]
- m.setTextColor(secureStatus == "allclear" and sky or red)
- m.write(incomingAddress == "Wormhole" and "Incoming " or "Incoming from ")
- m.setTextColor(secureStatus == "allclear" and yellow or orange)
- if lcGate then --# LanteaCraft
- m.setCursorPos(4, 2)
- m.write(incomingAddress .. sBuffer)
- else --# SGCraft
- m.setCursorPos(tX, 2)
- m.write(addrLen == 7 and longAddress:sub(1, chevronNumber * 2) or incomingAddress:sub(1, chevronNumber))
- m.setTextColor(gray)
- m.write(addrLen == 7 and longAddress:sub((chevronNumber * 2) + 1) or incomingAddress:sub(chevronNumber + 1))
- end
- end
- else --# outgoing call
- for i = 1, hardware.marquee do
- m = marquee[i]
- m.setTextColor(sky)
- m.write(gateStatus .. " ")
- if dialAddress ~= "none" then
- m.setCursorPos(tX, 2)
- m.setTextColor(yellow)
- m.write(addrLen == 7 and longAddress:sub(1, chevronNumber * 2) or dialAddress:sub(1, chevronNumber))
- m.setTextColor(gray)
- m.write(addrLen == 7 and longAddress:sub((chevronNumber * 2) + 1) or dialAddress:sub(chevronNumber + 1))
- end
- end
- end
- elseif gateStatus == "Connected" then
- if incomingAddress then --# incoming connection
- for i = 1, hardware.marquee do
- m = marquee[i]
- m.setTextColor(secureStatus == "allclear" and sky or red)
- m.write(incomingAddress == "Wormhole" and "Incoming " or "Incoming from ")
- m.setTextColor(secureStatus == "allclear" and yellow or orange)
- m.setCursorPos(tX, 2)
- m.write(longAddress)
- end
- else --# outgoing connection
- for i = 1, hardware.marquee do
- m = marquee[i]
- m.setTextColor(sky)
- if dialAddress == "none" then
- m.write("Connected ")
- else
- m.write("Connected to")
- m.setTextColor(yellow)
- m.setCursorPos(tX, 2)
- m.write(longAddress)
- end
- end
- end
- elseif gateStatus == "Disconnecting" then
- for i = 1, hardware.marquee do
- m = marquee[i]
- m.clear()
- m.setTextColor(sky)
- m.write("Disconnecting")
- end
- end
- end
- end
- end
- do
- local validColors = { [1] = true; [2] = true; [4] = true; [8] = true; [16] = true; [32] = true; [64] = true; [128] = true; [256] = true; [512] = true; [1024] = true; [2048] = true; [4096] = true; [8192] = true; [16384] = true, [32768] = true; }
- drawElement = function(x, y, w, h, txtColor, bgColor, text)
- if type(x) == "number" and type(y) == "number" then
- if type(w) == "string" then --# Switch (Neutral)
- x = math.floor(math.max(1, math.min(x, termX - 2))) --# Validate x coord
- y = math.floor(math.max(1, math.min(y, termY))) --# Validate y coord
- term.setCursorPos(x, y)
- term.setBackgroundColor(green)
- term.write(" ")
- term.setBackgroundColor(gray)
- term.write(" ")
- term.setBackgroundColor(red)
- term.write(" ")
- elseif type(w) == "boolean" then --# Switch (ON/OFF)
- x = math.floor(math.max(1, math.min(x, termX - 2))) --# Validate x coord
- y = math.floor(math.max(1, math.min(y, termY))) --# Validate y coord
- term.setCursorPos(x, y)
- term.setBackgroundColor(w and green or gray)
- term.write(" ")
- term.setBackgroundColor(w and gray or red)
- term.write(" ")
- elseif type(w) == "number" and type(h) == "number" then --# Text and/or box/rectangle
- local sText = text and tostring(text) or "" --# Ensure text is a string
- w = math.floor(math.min(math.max(1, math.max(#sText, w)), termX)) --# Validate width
- h = math.floor(math.max(1, math.min(h, termY))) --# valid height
- x = math.floor(math.max(1, math.min(x, termX - w + 1))) --# validate x coord
- y = math.floor(math.max(1, math.min(y, termY - h + 1))) --# validate y coord
- local spacer = (w - #sText) / 2
- local txtLine = string.rep(" ", math.floor(spacer)) .. sText .. string.rep(" ", math.ceil(spacer))
- if type(txtColor) == "number" and validColors[txtColor] then term.setTextColor(txtColor) end --# validate the text color
- if type(bgColor) == "number" and validColors[bgColor] then term.setBackgroundColor(bgColor) end --# validate the background color
- if h == 1 then --# if the height is 1 then...
- term.setCursorPos(x, y) --# Position cursor
- term.write(txtLine) --# Draw the single line of the 'element'
- else --# otherwise...
- local line, textRow = string.rep(" ", w), math.floor(h / 2) + y --# Define one line of the 'element' (box/rectangle/line-seg) and the row the text will be drawn on
- for i = y, y + h - 1 do --# Loop through the height of the 'element' line by line (top to bottom)
- term.setCursorPos(x, i) --# Position cursor
- term.write(i == textRow and txtLine or line) --# Draw 1 of h lines of the 'element' (box/rectangle/line-seg)
- end
- end
- end
- end
- end
- end
- drawRemoteIrisStatus = function()
- if validStates[runState][5] and gateStatus == "Connected" then
- local iColor = remoteIrisStatus == "open" and green or silver
- iColor = remoteIrisStatus == "closed" and red or iColor
- drawElement(termX - 2, 3, 1, 1, silver, gray, "[ ]")
- drawElement(termX - 1, 3, 1, 1, iColor, nil, "I")
- if gettingInput then repositionCursor() end
- end
- end
- local function drawSubheader()
- drawElement(1, 2, termX, 3, nil, gray) --# 'Status' area
- drawElement(3, 3, 1, 1, silver, nil, lcGate and "F/I: Gate:" or "Fuel: Gate:")
- --# Fuel, Iris, & Gate Status
- local fuelColor = fuelPercent > 24 and lime or orange
- fuelColor = fuelPercent < 6 and red or fuelColor
- drawElement(lcGate and 8 or 9, 3, 1, 1, fuelColor, gray, tostring(fuelPercent)) --# Fuel level
- if lcGate then
- local irisColor = irisPercent > 49 and lime or orange
- irisColor = irisPercent < 11 and red or irisColor
- term.setTextColor(silver)
- term.write("|")
- term.setTextColor(irisColor)
- term.write(tostring(irisPercent))
- end
- term.setTextColor(silver)
- term.write("% ")
- local allStatusColors = { ["Idle"] = lime, ["Disconnecting"] = sky }
- local clearStatusColors = { ["Dialing"] = cyan, ["Paused"] = orange, ["Connected"] = orange }
- local txtColor = allStatusColors[gateStatus] or red
- if secureStatus == "allclear" and clearStatusColors[gateStatus] then
- txtColor = clearStatusColors[gateStatus]
- end
- term.setTextColor(txtColor)
- term.setCursorPos(25, 3)
- if (gateStatus == "Connected" or gateStatus == "Dialing") and dialAddress == "none" then --# incoming calls
- if incomingAddress then
- term.write("Incoming from ")
- term.setTextColor(secureStatus == "allclear" and yellow or orange)
- if lcGate or gateStatus == "Connected" then
- term.write(incomingAddress)
- else
- term.write(incomingAddress:sub(1, chevronNumber))
- term.setTextColor(silver)
- term.write(incomingAddress:sub(chevronNumber + 1))
- end
- else
- term.write(gateStatus)
- end
- else
- if gateStatus == "Connected" and dialAddress ~= "none" then --# outgoing calls and connection data
- term.write("Connected to ")
- term.setTextColor(yellow)
- term.write(dialAddress)
- else
- term.write(gateStatus)
- end
- if gateStatus == "Dialing" or gateStatus == "Paused" then --# dialing data
- term.setCursorPos(33, 3)
- term.setTextColor(yellow)
- term.write(dialAddress:sub(1, chevronNumber))
- term.setTextColor(silver)
- term.write(dialAddress:sub(chevronNumber + 1))
- end
- end
- drawRemoteIrisStatus()
- end
- local function drawHeader()
- local selected = false
- local bgColor = secureStatus == "allclear" and (dialStates[runState] or assignColor(currentEdit)) or red
- local headerText = currentEdit and (addressBook[currentEdit].name .. " (" .. addressBook[currentEdit].addr .. ")") or thisGate
- if dialStates[runState] then
- for i = 1, abCount do
- if addressBook[i].addr == thisGate then
- headerText = secureStatus == "allclear" and (addressBook[i].name .. " (" .. thisGate .. ")") or addressBook[i].name
- bgColor = secureStatus == "allclear" and assignColor(i) or red
- selected = true
- break
- end
- end
- end
- if not selected and secureStatus == "lockdown" then headerText = "LOCKDOWN" end
- drawElement(1, 1, termX, 1, white, bgColor, headerText) --# Title
- if validStates[runState][5] or secureStatus == "lockdown" then
- drawElement(42, 1, 9, 1, connectionTime > 0 and white or gray, black, connectionClock) --# connection timer
- end
- if dialStates[runState] and secureStatus == "allclear" then --# Dial mode gets the -DHD- menu
- drawElement(2, 1, 5, 1, white, nil, "-DHD-") --# Drop down menu button
- end
- end
- local function drawFullHeader(drawSub)
- drawHeader()
- if drawSub then drawSubheader() end
- end
- local function drawLogHeader()
- drawElement(1, 1, termX, 1, nil, yellow) --# yellow header
- drawElement(1, 2, termX, 3, nil, gray) --# sub-header body
- local title = thisGate
- for i = 1, abCount do
- if addressBook[i].addr == thisGate then
- title = addressBook[i].name
- break
- end
- end
- drawElement(((termX - #title) / 2) - 3, 1, 1, 1, yellow, nil, " " .. title .. " Logs ") --# Header text
- drawElement(2, 2, 1, 1, silver, nil, "Last Call:") --# Last call label
- drawElement(2, 4, 25, 1, nil, nil, "Day Time Vector Address") --# Column labels
- drawElement(termX - 6, 2, 7, 1, red, silver, " Close ") --# Close button
- drawElement(termX - 6, 4, 7, 1, callHistory[1] and orange or gray, nil, " Clear ") --# Clear logs button
- drawElement(1, 3, 37, 1, nil, black) --# lastCall bg
- if lastCall then --# Last call
- local callDir = lastCall:sub(lastCall:find("<") + 1, lastCall:find(">") - 1)
- drawElement(2, 3, 1, 1, (callDir == "Inbound" or callDir == "Incoming") and silver or ((callDir == "Outgoing" or callDir == "Outbound") and gray or red), nil, lastCall:sub(1, lastCall:find("@") - 2)) --# Last call day
- drawElement(8, 3, 1, 1, nil, nil, lastCall:sub(lastCall:find("@") + 2, lastCall:find("M"))) --# Last call time
- drawElement(18, 3, 1, 1, nil, nil, callDir) --# Last call direciton
- drawElement(28, 3, 1, 1, (callDir == "Inbound" or callDir == "Incoming") and sky or ((callDir == "Outgoing" or callDir == "Outbound") and cyan or orange), nil, lastCall:sub(lastCall:find(">") + 2)) --# Last call address
- else --# No last call
- drawElement(2, 3, 1, 1, gray, nil, "none none none none")
- end
- drawLogScreen()
- end
- local function drawSecureUI(mon, backSpace)
- if hardware.marquee > 0 then
- if dhdSettings.detailedMarquee then
- if mon then initMarquee = true end
- displayStatusDetail()
- else
- if incomingAddress then
- displayStatus()
- else
- for i = 1, hardware.marquee do
- marquee[i].setBackgroundColor(black)
- marquee[i].setTextColor(red)
- marquee[i].setTextScale(2)
- marquee[i].clear()
- marquee[i].setCursorPos(1, 1)
- marquee[i].write("!! LOCKDOWN !!")
- end
- end
- end
- end
- if mon then
- displayChevrons(nil, backSpace)
- if not backSpace then
- if hardware.listMon > 0 then
- for i = 1, hardware.listMon do
- listMon[i].setBackgroundColor(black)
- listMon[i].setTextColor(red)
- listMon[i].clear()
- listMon[i].setCursorPos(1, 5)
- listMon[i].write("!! LOCKDOWN !!")
- end
- end
- end
- end
- drawFullHeader(true)
- drawElement((termX / 2) - 7, 9, 1, 1, red, black, "!! LOCKDOWN !!")
- drawElement((termX / 2) - 10, 15, 1, 1, gray, nil, "password:")
- end
- local function drawAddrBookButton()
- drawElement(43, 13, 1, 1, gateChange and lime or white, blue, "AddrBook ")
- end
- local function drawControlUI()
- local iColor = irisStatus == "Offline" and silver or white
- if waitingForIris then
- iColor = irisStatus == "Opening" and orange or green
- end
- drawElement(42, 6, 10, 11, nil, gray) --# Control UI menu body
- drawElement(43, 7, 1, 1, iColor, sky, "Iris ") --# Iris
- drawElement(termX - 1, 7, 2, 1, nil, irisState and green or orange) --# Iris pip
- drawElement(43, 9, 1, 1, black, orange, "END Call ") --# endCall
- drawElement(43, 11, 1, 1, orange, red, "LOCKDOWN ") --# Lockdown
- drawElement(43, 13, 1, 1, gateChange and lime or white, blue, "AddrBook ") --# Address Book
- drawElement(43, 15, 1, 1, white, green, "New Gate ") --# New Gate
- end
- local function drawNaviUI()
- pNum = tostring(gatePage) .. " of " .. tostring(gatePages)
- drawElement((termX / 2) - 15, termY, 1, 1, gray, black, gatePage > 1 and "<< <" or " ")
- drawElement((termX / 2) + 3, termY, 1, 1, nil, nil, gatePage < gatePages and "> >>" or " ")
- drawElement(((termX / 2) - 3) - (#pNum / 2) - 2, termY, 1, 1, runState == "goPage" and gray or silver, nil, " " .. pNum .. " ")
- end
- local function drawAddressBook() --# Gate Address Book
- local xPos, yPos, magicNumber = 2, 6, ((gatePage - 1) * 17) + gatePage
- local txtColor, bgColor, addr, highlight
- for i = magicNumber, math.min(abCount, magicNumber + 17) do
- addr = addressBook[i].addr
- highlight = (addr == dialAddress or addr:sub(1, 7) == dialAddress:sub(1, 7) or addr == incomingAddress or addr:sub(1, 7) == tostring(incomingAddress):sub(1, 7))
- txtColor = (thisGate == addr or thisGate:sub(1, 7) == addr or thisGate == addr:sub(1, 7)) and silver or (highlight and black or white)
- bgColor = thisGate == addr and gray or assignColor(i)
- drawElement(xPos, yPos, 12, 1, txtColor, bgColor, addressBook[i].name) --# Button
- yPos = yPos + 2
- if yPos > 16 then yPos = 6 xPos = xPos + 13 end
- end
- end
- local function drawHelpScreen()
- clearScreen(white) --# Body
- drawElement(1, 1, termX, 1, nil, cyan) --# Header
- drawElement((termX / 2) - 4, 1, 1, 1, cyan, gray, " ccDHD Help ") --# Header text
- drawElement(1, termY, termX, 1) --# Footer
- drawElement(2, termY, 1, 1, silver, nil, "ccDHD ver. " .. ccDHDVer .. " cc# " .. thisCC) --# Footer text
- drawElement(termX - 1 - #ccLabel, termY, 1, 1, nil, nil, ccLabel)
- drawElement(1, 2, termX, 1) --# Header/Separator
- drawElement(termX - 6, 2, 7, 1, red, silver, " Close ") --# Close button
- drawElement(1, 3, termX, 1, nil, black)
- drawElement(1, termY - 1, termX, 1)
- drawElement(1, 4, 14, termY - 5, nil, gray) --# draw help left pane
- drawElement(2, 5, 1, 1, white, nil, "Main Screen ")
- drawElement(2, 10, 1, 1, nil, nil, "AddrBook Btn")
- drawElement(2, 14, 1, 1, nil, nil, "Log Screen ")
- drawElement(2, 6, 1, 1, silver, nil, "LEFT click")
- drawElement(2, 7, 1, 1, nil, nil, "RIGHT click")
- drawElement(2, 8, 1, 1, nil, nil, "MIDDLE click")
- drawElement(2, 11, 1, 1, nil, nil, "LEFT click")
- drawElement(2, 12, 1, 1, nil, nil, "RIGHT click")
- drawElement(2, 15, 1, 1, nil, nil, "LEFT click")
- drawElement(2, 16, 1, 1, nil, nil, "RIGHT click")
- drawElement(16, 6, 1, 1, nil, white, lcGate and "an address to dial / pause" or "an address to dial")
- drawElement(16, 7, 1, 1, nil, nil, "an address to view or edit details")
- drawElement(16, 8, 1, 1, nil, nil, "an address to delete")
- drawElement(16, 11, 1, 1, nil, nil, "to import/export/save address book")
- drawElement(16, 12, 1, 1, nil, nil, "to quick-save address book")
- drawElement(16, 15, 1, 1, nil, nil, "an address to dial")
- drawElement(16, 16, 1, 1, nil, nil, "an address to add to address book")
- end
- do
- local labels = {
- "Change pass:";
- { "Biolock Login", "This Computer..." };
- { "Bio:", "CC Label:" };
- { "Bio Login Lvl", "CC#/Gate:" };
- { "Bio Func. Lvl", "Space:" };
- "Sync:";
- "Detailed Marquee";
- "Call Logging";
- "Incoming Iris";
- "END Call Iris";
- }
- local function drawSettingsData()
- --# Settings 1st column
- if hardware.bio > 0 then
- drawElement(22, 10, dhdSettings.bio.lock) --# Fistprint Authentication (Bioscanner) - LOGIN
- if dhdSettings.bio.func == "none" then --# Bioscanner function (Iris / Lockdown)
- drawElement(7, 12, 1, 1, silver, black, "No Function")
- drawElement(22, 12, "MID")
- elseif dhdSettings.bio.func == "iris" then
- drawElement(7, 12, 1, 1, green, black, "Iris ")
- drawElement(22, 12, true)
- elseif dhdSettings.bio.func == "lock" then
- drawElement(7, 12, 1, 1, red, black, "Lockdown ")
- drawElement(22, 12, false)
- end
- drawElement(19 + dhdSettings.bio.auth, 14, 1, 1, black, silver, tostring(dhdSettings.bio.auth)) --# Login authorization level
- drawElement(19 + dhdSettings.bio.fAuth, 16, 1, 1, nil, nil, tostring(dhdSettings.bio.fAuth)) --# Bio-Function authorization level
- else
- local gateLiaisonString = tostring(dhdSettings.gate)
- drawElement(12, 12, 1, 1, white, black, ccLabel)
- drawElement(12, 14, 1, 1, silver, nil, thisCC .. "/" .. gateLiaisonString .. " ( )")
- local wifi = (hardware.modemSide == "none" and hardware.wifiSide ~= "none")
- drawElement(15 + #thisCC + #gateLiaisonString, 14, 1, 1, wifi and orange or green, nil, wifi and "Wi-Fi" or "Wired")
- local drivespace, diskspace = tostring(fs.getFreeSpace("/")), fs.exists("/disk") and tostring(fs.getFreeSpace("/disk")) or 0
- local spaceline = drivespace .. "/" .. diskspace
- drawElement(12, 16, 1, 1, silver, nil, #spaceline < 16 and spaceline or drivespace)
- end
- --# Settings 2nd column
- drawElement(34, 6, 1, 1, type(dhdSettings.sync) == "string" and orange or (dhdSettings.sync and green or red), black, type(dhdSettings.sync) == "string" and "Dial ONLY" or (dhdSettings.sync and "Dial & Sync" or "OFF")) --# Sync setting
- drawElement(46, 6, dhdSettings.sync) --# Sync
- drawElement(46, 10, dhdSettings.detailedMarquee) --# Highlight gate
- drawElement(46, 12, dhdSettings.logs) --# Call logging
- drawElement(46, 14, dhdSettings.incomingIris) --# Incoming Iris auto-close
- drawElement(46, 16, dhdSettings.ecIris) --# endCall Iris auto-open
- end
- drawSettingsScreen = function()
- local gName
- for i = 1, abCount do
- if addressBook[i].addr == thisGate then gName = addressBook[i].name break end
- end
- drawElement(1, 1, termX, 1, nil, sky) --# Header
- drawElement(1, 2, termX, 3, nil, gray) --# Sub-Header
- drawElement(1, 8, termX, 1) --# Separator
- drawElement(gName and (((termX - #gName) / 2) - 5) or (((termX - #thisGate) / 2) - 5), 1, 1, 1, sky, nil, " " .. (gName or thisGate) .. " Settings ") --# Title
- drawElement(1, termY, termX, 1, silver, nil, "ccDHD " .. ccDHDVer) --# Footer / Lowline
- drawElement(gName and (((termX - #gName) / 2) - (1 + (#thisGate / 2))) or (((termX - 5) / 2) - (2 + (#thisGate / 2))), 3, 1, 1, gName and cyan or silver, nil, gName or "This Gate:") --# Header (This Gate:)
- term.setTextColor(cyan)
- term.write(gName and " (" .. thisGate .. ")" or " " .. thisGate) --# Header (thisGate)
- drawElement(45, 2, 7, 1, red, silver, " Close ") --# Close button
- drawElement(45, 4, 7, 1, configChange and lime or gray, nil, " Save ") --# Save button
- local xOffset, yOffset = 2, 6
- term.setTextColor(gray)
- term.setBackgroundColor(black)
- for i = 1, #labels do
- drawElement(xOffset, yOffset, 1, 1, nil, nil, (xOffset == 2 and yOffset > 9 and yOffset < 17) and (hardware.bio > 0 and labels[i][1] or labels[i][2]) or labels[i])
- yOffset = yOffset + 2
- if yOffset == 8 then yOffset = 10 end
- if yOffset == 18 and xOffset == 2 then
- xOffset, yOffset = 28, 6
- end
- end
- if hardware.bio > 0 then
- drawElement(19, 14, 1, 1, nil, nil, "|-----|") --# Biolock login level
- drawElement(19, 16, 1, 1, nil, nil, "|-----|") --# Biolock iris/lockdown level
- end
- drawElement(16, 6, 1, 1, orange, nil, "*********") --# password
- drawSettingsData()
- end
- end
- local function drawPopUp()
- if runState == "clearLogs" then
- drawElement((termX / 2) - 5, (termY / 2) - 2, 13, 1, black, yellow, "Clear Logs?")
- drawElement((termX / 2) - 5, (termY / 2) - 1, 13, 3, nil, gray)
- drawElement((termX / 2) - 4, termY / 2, 5, 1, nil, green, "YES")
- drawElement((termX / 2) + 2, termY / 2, 5, 1, nil, red, "N O")
- elseif runState == "goPage" or runState == "goLogPage" then
- local a = runState == "goLogPage" and 4 or 8
- local b = runState == "goLogPage" and 3 or 7
- drawElement((termX / 2) - a, termY - 3, 8, 1, white, gray, " :Page: ")
- drawElement((termX / 2) - a, termY - 2, 8, 2)
- drawElement((termX / 2) - b, termY - 2, 6, 1, nil, black) --# input area bg
- elseif runState == "importExport" then
- drawElement((termX / 2) - 13, (termY / 2) - 1, 19, 1, white, blue, "Address Book Mgt.")
- drawElement((termX / 2) - 13, termY / 2, 19, 7, nil, gray)
- if fs.exists("/disk/data/DHDgates") then
- drawElement((termX / 2) - 12, (termY / 2) + 1, 8, 1, black, yellow, "Import")
- else
- drawElement((termX / 2) - 12, (termY / 2) + 1, 8, 1, gray, silver, "Import")
- end
- if fs.exists("/disk") then
- drawElement((termX / 2) - 3, (termY / 2) + 1, 8, 1, black, orange, "Export")
- else
- drawElement((termX / 2) - 3, (termY / 2) + 1, 8, 1, gray, silver, "Export")
- end
- if gateChange then
- drawElement((termX / 2) - 12, (termY / 2) + 3, 8, 1, white, sky, "Load")
- drawElement((termX / 2) - 3, (termY / 2) + 3, 8, 1, white, green, "Save")
- else
- drawElement((termX / 2) - 12, (termY / 2) + 3, 8, 1, gray, silver, "Load")
- drawElement((termX / 2) - 3, (termY / 2) + 3, 8, 1, gray, silver, "Save")
- end
- drawElement((termX / 2) - 7, (termY / 2) + 5, 7, 1, white, red, "CLOSE")
- elseif runState == "newPassword" then
- drawElement((termX / 2) - 7, 6, 1, 1, white, blue, " Change Pass ")
- drawElement((termX / 2) - 7, 7, 1, 1, black, silver, " Lockdown P/W ")
- drawElement((termX / 2) - 7, 8, 16, 4) --# body
- drawElement((termX / 2) - 7, 9, 1, 1, nil, nil, " I r i s P/W ")
- drawElement((termX / 2) - 6, 8, 14, 1, yellow, gray, "Select") --# Lockdown PW
- drawElement((termX / 2) - 6, 10, 14, 1, nil, nil, "Select") --# Iris PW
- drawElement((termX / 2) - 3, 11, 1, 1, white, orange, " Cancel ")
- elseif runState == "newLockPass" then
- drawElement((termX / 2) - 7, 6, 1, 1, white, blue, " Lockdown P/W ")
- drawElement((termX / 2) - 7, 7, 1, 1, black, silver, " OLD Password ")
- drawElement((termX / 2) - 7, 9, 1, 1, nil, nil, " NEW Password ")
- drawElement((termX / 2) - 6, 8, 14, 1, nil, black) --# oldPass input area bg
- drawElement((termX / 2) - 6, 10, 14, 1) --# newPass input area bg
- drawElement((termX / 2) - 3, 11, 1, 1, white, orange, " Cancel ")
- elseif runState == "newIrisPass" then
- drawElement((termX / 2) - 7, 6, 1, 1, white, blue, " I r i s P/W ")
- drawElement((termX / 2) - 7, 7, 1, 1, black, silver, " OLD Password ")
- drawElement((termX / 2) - 7, 9, 1, 1, nil, nil, " NEW Password ")
- drawElement((termX / 2) - 6, 8, 14, 1, nil, black) --# oldPass input area bg
- drawElement((termX / 2) - 6, 10, 14, 1) --# newPass input area bg
- drawElement((termX / 2) - 3, 11, 1, 1, white, orange, " Cancel ")
- elseif runState == "remotePass" then
- drawElement((termX / 2) - 8, 10, 16, 1, silver, gray, "Remote Pass")
- drawElement((termX / 2) - 8, 11, 16, 2, nil, nil) --# body
- drawElement((termX / 2) - 7, 11, 14, 1, nil, silver) --# input area
- elseif runState == "exodus" then
- if gateChange and not configChange then
- drawElement((termX / 2) - 13, (termY / 2) - 1, 19, 1, white, blue, "Save Addr Book?")
- elseif configChange and not gateChange then
- drawElement((termX / 2) - 13, (termY / 2) - 1, 19, 1, white, blue, "Save Settings?")
- else
- drawElement((termX / 2) - 13, (termY / 2) - 1, 19, 1, white, blue, "Save Gates & Cfg?")
- end
- drawElement((termX / 2) - 13, termY / 2, 19, 3, nil, gray)
- drawElement((termX / 2) - 12, (termY / 2) + 1, 1, 1, nil, green, " Save ")
- drawElement((termX / 2) - 3, (termY / 2) + 1, 1, 1, nil, orange, " Quit ")
- end
- end
- local function drawRatingList(rating)
- local txtColor
- drawElement(18, 6, 1, 1, white, assignColor(currentEdit), " Classification ")
- drawElement(18, 7, 20, 10, nil, gray) --# menu body
- for k, v in pairs(classifications) do
- if rating == k then
- txtColor = rating == "U" and white or v.color
- drawElement(37, v.order + 7, 1, 1, nil, v.color) --# selected rating color pip
- else
- txtColor = silver
- end
- drawElement(18, v.order + 7, 1, 1, nil, v.color) --# color pip
- drawElement(20, v.order + 7, 1, 1, txtColor, gray, v.label)
- end
- end
- local function drawMenu()
- menuState = true
- drawElement(2, 1, 5, 1, white, black, "_DHD_")
- drawElement(2, 2, 1, 9, nil, gray) --# dark gray line along left side of menu
- drawElement(2, 3, 1, 1, nil, sky) --# Settings pip
- drawElement(2, 5, 1, 1, nil, yellow) --# Logs pip
- drawElement(2, 7, 1, 1, nil, cyan) --# Help pip
- drawElement(2, 9, 1, 1, nil, red) --# Exit pip
- drawElement(3, 2, 9, 9, nil, silver) --# menu body
- drawElement(3, 3, 1, 1, gray, nil, "Settings")
- drawElement(3, 5, 1, 1, nil, nil, "View Logs")
- drawElement(3, 7, 1, 1, nil, nil, "DHD Help")
- drawElement(3, 9, 1, 1, nil, nil, " EXIT")
- end
- local function clearMenu()
- menuState = false
- drawElement(2, 5, 11, 6, nil, black) --# clear menu
- drawElement(2, 1, 5, 1, white, nil, "-DHD-") --# Drop down menu button
- drawSubheader()
- drawAddressBook()
- end
- drawCLI = function(mon, init, backSpace)
- --# Terminal output
- if secureStatus == "lockdown" then
- drawSecureUI(mon, backSpace)
- if gettingInput then repositionCursor() end
- else
- if menuState then
- if fullRedraw then
- validStates[runState][3]()
- fullRedraw = false
- elseif incomingAddress or dialAddress ~= "none" then
- drawSubheader()
- if chevronNumber == 0 then drawAddressBook() end
- end
- drawMenu()
- else
- validStates[runState][3]()
- if gettingInput then repositionCursor() end
- end
- --# Monitor output
- if mon then updateDisplays(init, backSpace) end
- end
- end
- drawLogScreen = function()
- if logPage == logPages and logPages > 1 then drawElement(1, 5, termX, termY - 4, nil, black) end --# clear lower screen
- drawElement(1, termY, termX, 1, nil, gray) --# Footer
- if callHistory[1] then --# Logs to display
- --# populate footer
- drawElement(11, termY, 1, 1, silver, nil, "<< < > >>")
- local lPage, lPages = tostring(logPage), tostring(logPages)
- drawElement((termX / 2) - (((#lPage + #lPages) / 2) + 2), termY, 1, 1, nil, nil, lPage .. " of " .. lPages .. " ")
- --# end of footer
- term.setBackgroundColor(black)
- local currentEntry = ((logPage - 1) * 11) + 1 --# Set the first entry to show (based on page number)
- local callDay, callTime, callDir, callAddr, caLen, abMatch, addr
- for i = currentEntry, math.min(currentEntry + 10, #callHistory) do --# Display logs
- callDay = callHistory[i]:sub(1, callHistory[i]:find("@") - 2)
- callTime = callHistory[i]:sub(callHistory[i]:find("@") + 2, callHistory[i]:find("M"))
- callDir = callHistory[i]:sub(callHistory[i]:find("<") + 1, callHistory[i]:find(">") - 1)
- callAddr = callHistory[i]:sub(callHistory[i]:find(">") + 2)
- caLen = #callAddr
- drawElement(2, i - currentEntry + 6, 1, 1, (caLen == 7 or caLen == 9) and ((callDir == "Inbound" or callDir == "Incoming") and silver or ((callDir == "Outgoing" or callDir == "Outbound") and gray or red)) or red, nil, callDay .. " ")
- drawElement(8, i - currentEntry + 6, 1, 1, nil, nil, callTime .. " ")
- drawElement(18, i - currentEntry + 6, 1, 1, nil, nil, callDir .. " ")
- drawElement(28, i - currentEntry + 6, 1, 1, (caLen == 7 or caLen == 9) and ((callDir == "Inbound" or callDir == "Incoming") and sky or ((callDir == "Outgoing" or callDir == "Outbound") and cyan or orange)) or orange, nil, callAddr .. string.rep(" ", 9 - #callAddr))
- abMatch = false
- for j = 1, abCount do
- addr = addressBook[j].addr
- if addr == callAddr or addr:sub(1, 7) == callAddr or addr == callAddr:sub(1, 7) then
- drawElement(39, i - currentEntry + 6, 1, 1, (callDir == "Inbound" or callDir == "Incoming") and silver or ((callDir == "Outgoing" or callDir == "Outbound") and gray or red), nil, addressBook[j].name .. string.rep(" ", 12 - #addressBook[j].name))
- abMatch = true
- break
- end
- end
- if not abMatch then drawElement(39, i - currentEntry + 6, 12, 1) end
- end
- else --# No logs to display
- drawElement(2, 6, 1, 1, gray, black, "No Logs")
- end
- end
- local function drawGateData()
- drawHeader()
- local name, addr, note, dim, rating = addressBook[currentEdit].name, addressBook[currentEdit].addr, addressBook[currentEdit].note, addressBook[currentEdit].loc.dim, assignRating(currentEdit)
- if addr == thisGate or addr:sub(1, 7) == thisGate or addr == thisGate:sub(1, 7) then
- drawElement(termX - 14, 8, 1, 1, gray, black, "< This Gate >")
- elseif addr == dialAddress or addr:sub(1, 7) == dialAddress or addr == dialAddress:sub(1, 7) then
- drawElement(termX - 14, 8, 1, 1, gray, black, "< Target > ")
- elseif incomingAddress and (addr == incomingAddress or addr:sub(1, 7) == incomingAddress or addr == incomingAddress:sub(1, 7)) then
- drawElement(termX - 14, 8, 1, 1, gray, black, "< Incoming > ")
- else
- drawElement(termX - 14, 8, 13, 1, nil, black)
- end
- local xStr, yStr, zStr, ceStr = tostring(addressBook[currentEdit].loc.x), tostring(addressBook[currentEdit].loc.y), tostring(addressBook[currentEdit].loc.z), tostring(currentEdit)
- drawElement(11, 6, 1, 1, cyan, nil, name .. string.rep(" ", 12 - #name)) --# Name
- drawElement(11, 8, 1, 1, yellow, nil, addr .. " ") --# Address
- drawElement(termX - 6, 6, 1, 1, white, nil, ceStr .. string.rep(" ", 5 - #ceStr)) --# Position in address book
- drawElement(8, 10, 1, 1, nil, nil, note .. string.rep(" ", 43 - #note)) --# Note(s)
- drawElement(18, 12, 1, 1, assignColor(currentEdit), nil, rating .. string.rep(" ", 20 - #rating)) --# Classification
- drawElement(13, 14, 1, 1, brown, nil, dim .. string.rep(" ", 19 - #dim)) --# Dimension
- drawElement(15, 16, 1, 1, silver, nil, xStr .. string.rep(" ", 9 - #xStr)) --# X
- drawElement(28, 16, 1, 1, nil, nil, yStr .. string.rep(" ", 9 - #yStr)) --# Y
- drawElement(41, 16, 1, 1, nil, nil, zStr .. string.rep(" ", 9 - #zStr)) --# Z
- if not lcGate then
- drawElement(31, 6, addressBook[currentEdit].iris)
- drawElement(31, 8, addressBook[currentEdit].callDrop)
- end
- end
- local function drawGateLabels()
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- drawElement(2, 6, 1, 1, gray, nil, lcGate and "Name: #" or "Name: Iris: #")
- drawElement(2, 8, 1, 1, nil, nil, lcGate and "Address:" or "Address: Drop:")
- drawElement(2, 10, 1, 1, nil, nil, "Note:")
- drawElement(2, 12, 1, 1, nil, nil, "Classification:")
- drawElement(2, 14, 10, 1, nil, nil, "Dimension:")
- drawElement(2, 16, 1, 1, nil, nil, "Coords: x: y: z:")
- drawElement((termX / 2) - 8, termY - 1, 6, 1, gateChange and green or silver, gray, " Save ")
- drawElement((termX / 2) + 1, termY - 1, 7, 1, red, nil, " Close ")
- drawGateData()
- end
- local function addNewAddress(newAddress, fast)
- abCount = abCount + 1
- addressBook[abCount] = { name = newAddress or "NEW GATE", addr = newAddress or "ADDRESS", rating = "U", iris = "none", callDrop = false, note = newAddress and "Added from logs" or "short note", loc = { x = 0, y = 0, z = 0, dim = "Unspecified" } } --# ...create new entry
- paginateAddressBook() --# paginate the address book
- gateChange = true --# indicate the address book has changed
- if fast then --# if it's a quick-add...
- if gatePage == gatePages then drawAddressBook() end --# ...redraw the address book if we're on the last page
- drawNaviUI() --# update the page navigation UI (page number)
- else --# if it's not a quick-add...
- currentEdit = abCount --# ...set the entry number being edited
- drawSubheader()
- drawGateLabels() --# draw the gate information
- end
- if displayState == "list" and listPage == listPages then displayAddressBook() end
- if gateMonList and gateMonPage == gateMonPages then displayGateMonAddrBook() end
- end
- local function deleteGate(gateNum) --# Delete gate
- table.remove(addressBook, gateNum)
- gateChange, abCount = true, abCount - 1
- paginateAddressBook()
- gatePage = math.min(gatePage, gatePages)
- listPage = math.min(listPage, listPages)
- gateMonPage = math.min(gateMonPage, gateMonPages)
- if displayState == "info" then
- if selectedGate == gateNum then
- displayState = "list"
- if dhdSettings.detailedMarquee then
- initMarquee = true
- displayStatusDetail()
- else
- displayStatus()
- end
- if gateStatus ~= "Idle" then displayAddressBook() end
- elseif selectedGate > gateNum then
- selectedGate = selectedGate - 1
- displayNotes()
- end
- else
- displayAddressBook()
- end
- if gateMonList then displayGateMonAddrBook() end
- end
- local function gateDataChange()
- gateChange = true
- drawElement((termX / 2) - 8, termY - 1, 1, 1, green, gray, " Save ")
- end
- local function settingsChange()
- configChange = true
- drawElement(45, 4, 1, 1, lime, silver, " Save ")
- end
- local function clearCallHistory()
- for i = #callHistory, 1, -1 do
- callHistory[i] = nil
- end
- end
- local function addAddressFromLogs(address)
- clearCallHistory()
- lastCall = nil
- runState = "GateEdit"
- for i = 1, abCount do
- if addressBook[i].addr == address then
- currentEdit = i
- drawSubheader()
- drawGateLabels()
- return
- end
- end
- addNewAddress(address)
- end
- local function dialAddressFromLogs(address)
- runState = "Dial"
- lastCall = nil
- clearCallHistory()
- netSend(dhdSettings.gate, { program = "ccDHD", command = address })
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- drawCLI(true)
- end
- local function flashDial(name, x, y, gateNum)
- local gColor = assignColor(gateNum)
- drawElement(x, y, 12, 1, gColor, black, name)
- sleep(0.1)
- drawElement(x, y, 12, 1, black, gColor, name)
- end
- local function flashChoice(x, y, tColor, bColor, text)
- drawElement(x, y, 1, 1, tColor, bColor, text)
- sleep(0.1)
- end
- --# custom read function courtesy of theoriginalbit (modified by Dog)
- local function read(_mask, _history, _limit, _noTerminate, _noMouse, _gField)
- if _mask and type(_mask) ~= "string" then
- error("Invalid parameter #1: Expected string, got " .. type(_mask), 2)
- end
- if _history and type(_history) ~= "table" then
- error("Invalid parameter #2: Expected table, got " .. type(_history), 2)
- end
- if _limit and type(_limit) ~= "number" then
- error("Invalid parameter #3: Expected number, got " .. type(_limit), 2)
- end
- if _noTerminate and type(_noTerminate) ~= "boolean" then
- error("Invalid argument #4: Expected boolean, got " .. nativeType(_noTerminate), 2)
- end
- if _noMouse and type(_noMouse) ~= "boolean" then
- error("Invalid argument #5: Expected boolean, got " .. nativeType(_noMouse), 2)
- end
- if _gField and type(_gField) ~= "boolean" then
- error("Invalid argument #6: Expected boolean, got " .. nativeType(_gField), 2)
- end
- term.setCursorBlink(true)
- gettingInput = true
- local symbols = { ["A"] = true, ["B"] = true, ["C"] = true, ["D"] = true, ["E"] = true , ["F"] = true, ["G"] = true, ["H"] = true, ["I"] = true, ["J"] = true, ["K"] = true, ["L"] = true, ["M"] = true, ["N"] = true, ["O"] = true, ["P"] = true, ["Q"] = true, ["R"] = true, ["S"] = true, ["T"] = true, ["U"] = true, ["V"] = true, ["W"] = true, ["X"] = true, ["Y"] = true, ["Z"] = true, ["0"] = true, ["1"] = true, ["2"] = true, ["3"] = true, ["4"] = true, ["5"] = true, ["6"] = true, ["7"] = true, ["8"] = true, ["9"] = true, ["-"] = true, ["+"] = true }
- local passSymbols = { "!", "@", "#", "$", "%", "^", "&", "*", "?", "=", "+", "-", "_", "x", "X" }
- local mouseLimit = _limit or 0
- local input, secWord, lineCleared = "", "", false
- word = ""
- local pos = 0
- local historyPos = nil
- local pullEvent = _noTerminate and os.pullEventRaw or os.pullEvent
- local sw, sh = term.getSize()
- local sx, sy = term.getCursorPos()
- curX, curY = sx, sy
- local function redraw(_special)
- local scroll = (sx + pos >= sw and (sx + pos) - sw or 0)
- local replace = _special or _mask
- local output = replace and (string.rep(replace, math.ceil(#input / #replace) - scroll)):sub(1, #input) or input:sub(scroll + 1)
- term.setCursorPos(sx, sy)
- term.write(output)
- term.setCursorPos(sx + pos - scroll, sy)
- end
- local nativeScroll = term.scroll
- term.scroll = function(_n) local ok, err = pcall(function() return nativeScroll(_n) end) if ok then sy = sy - _n return err end error(err, 2) end
- local function historyHandler(value)
- redraw(' ')
- if value == -1 or value == keys.up then
- if not historyPos then
- historyPos = #_history
- elseif historyPos > 1 then
- historyPos = historyPos - 1
- end
- else
- if historyPos ~= nil and historyPos < #_history then
- historyPos = historyPos + 1
- elseif historyPos == #_history then
- historyPos = nil
- end
- end
- if historyPos and #_history > 0 then
- input = string.sub(_history[historyPos], 1, _limit) or ""
- pos = #input
- word = input
- if not _limit then mouseLimit = pos end
- else
- input = ""
- pos = 0
- word = input
- if not _limit then mouseLimit = 0 end
- end
- end
- local goodData, event, code, x, y, secSymbols, newWord, glyph = false
- while true do
- event, code, x, y = pullEvent()
- if event == "char" and (not _limit or #input < _limit) then
- if not lineCleared and pos == 0 then term.write(string.rep(" ", _limit)) lineCleared = true end
- goodData = false
- if secureStatus == "lockdown" then
- secWord = secWord:sub(1, pos) .. passSymbols[math.random(1, #passSymbols)] .. secWord:sub(pos + 1)
- goodData = true
- elseif _gField then
- if symbols[code:upper()] then
- code = code:upper()
- goodData = true
- end
- else
- goodData = true
- end
- if goodData then
- input = input:sub(1, pos) .. code .. input:sub(pos + 1)
- pos = pos + 1
- word = secureStatus == "allclear" and input or secWord
- if not _limit then mouseLimit = math.min(mouseLimit + 1, sw - (sw - sx)) end
- end
- elseif event == "paste" and (not _limit or #input < _limit) then
- if _limit and #input + #code > _limit then
- code = code:sub(1, _limit - #input)
- end
- if not lineCleared and pos == 0 then term.write(string.rep(" ", _limit)) lineCleared = true end
- if secureStatus == "lockdown" then
- if secSymbols[1] then for i = #secSymbols, 1, -1 do secSymbols[i] = nil end end
- for i = 1, #input do
- secSymbols[i] = passSymbols[math.random(1, #passSymbols)]
- end
- secWord = secWord:sub(1, pos) .. table.concat(secSymbols) .. secWord:sub(pos + 1)
- elseif _gField then
- glyph = ""
- if newWord[1] then for i = #newWord, 1, -1 do newWord[i] = nil end end
- for i = 1, #code do
- glyph = string.upper(code:sub(i, i))
- newWord[i] = symbols[glyph] and glyph or "?"
- end
- code = table.concat(newWord)
- end
- input = input:sub(1, pos) .. code .. input:sub(pos + 1)
- pos = pos + #code
- word = secureStatus == "allclear" and input or secWord
- if not _limit then mouseLimit = math.min(mouseLimit + #code, sw - (sw - sx)) end
- elseif event == "key" then
- if code == keys.enter or code == keys.numPadEnter then
- break
- elseif code == keys.backspace and pos > 0 then
- redraw(' ')
- input = input:sub(1, math.max(pos - 1, 0)) .. input:sub(pos + 1)
- pos = math.max(pos - 1, 0)
- if secureStatus == "lockdown" then
- secWord = #secWord > 0 and secWord:sub(1, #secWord - 1) or ""
- end
- word = secureStatus == "allclear" and input or secWord
- if not _limit then mouseLimit = math.max(mouseLimit - 1, 0) end
- elseif code == keys.delete and pos < #input then
- redraw(' ')
- input = input:sub(1, pos) .. input:sub(pos + 2)
- if secureStatus == "lockdown" then
- secWord = secWord:sub(1, pos) .. secWord:sub(pos + 2)
- end
- word = secureStatus == "allclear" and input or secWord
- if not _limit then mouseLimit = math.max(mouseLimit - 1, 0) end
- elseif code == keys.home then
- pos = 0
- elseif code == keys["end"] then
- pos = #input
- elseif code == keys.left and pos > 0 then
- pos = math.max(pos - 1, 0)
- elseif code == keys.right and pos < #input then
- pos = math.min(pos + 1, #input)
- elseif _history and (code == keys.up or code == keys.down) then
- historyHandler(code)
- elseif code == keys.tab and (runState == "newLockPass" or runState == "newIrisPass") then
- break
- end
- elseif event == "mouse_click" and not _noMouse and ((x < sx or x >= sx + mouseLimit) or (y ~= sy)) and code == 1 then
- if runState == "newLockPass" or runState == "newIrisPass" then
- if y == 11 and x > math.floor(termX / 2) - 4 and x < math.floor(termX / 2) + 5 then
- term.scroll = nativeScroll
- term.setCursorBlink(false)
- gettingInput = false
- word = ""
- flashChoice((termX / 2) - 3, 11, orange, white, " Cancel ")
- runState = "DHDsettings"
- drawElement((termX / 2) - 7, 6, 16, 6, nil, black) --# clear pop-up
- return drawSettingsScreen()
- elseif x > math.floor(termX / 2) - 6 and x < math.floor(termX / 2) + 6 and ((y == 8 and curY == 10) or (y == 10 and curY == 8)) then
- break
- end
- else
- break
- end
- elseif event == "mouse_scroll" and _history then
- historyHandler(code)
- end
- redraw(secureStatus == "lockdown" and secWord or _mask)
- end
- term.scroll = nativeScroll
- term.setCursorBlink(false)
- if sy + 1 > sh then
- term.scroll(sy + 1 - sh)
- term.setCursorPos(1, sy)
- else
- term.setCursorPos(1, sy + 1)
- end
- word = ""
- gettingInput = false
- return input
- end
- local function inputClearLogsPopUp()
- local _, button, x, y
- while true do
- _, button, x, y = os.pullEvent("mouse_click")
- if y == math.floor(termY / 2) and button == 1 then
- if x > math.floor(termX / 2) - 5 and x < math.floor(termX / 2) + 1 then
- flashChoice((termX / 2) - 4, termY / 2, green, white, " YES ")
- local clearLog = fs.open(gateHistory, "w")
- clearLog.close()
- clearCallHistory()
- logPage, logPages = 1, 1
- runState = "logs"
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- drawElement(termX - 6, 4, 7, 1, gray, silver, " Clear ") --# 'clear logs' button
- return drawLogScreen()
- elseif x > math.floor(termX / 2) + 1 and x < math.floor(termX / 2) + 7 then
- flashChoice((termX / 2) + 2, termY / 2, red, white, " N O ")
- drawElement((termX / 2) - 5, (termY / 2) - 2, 13, 4, nil, black) --# clear dialogue box
- runState = "logs"
- return drawLogScreen()
- end
- end
- end
- end
- local function inputSaveAndQuitPopUp()
- local _, button, x, y
- while true do
- _, button, x, y = os.pullEvent("mouse_click")
- if x > math.floor(termX / 2) - 14 and x < math.floor(termX / 2) + 6 and y > math.floor(termY / 2) - 2 and y < math.floor(termY / 2) + 3 then
- if x > math.floor(termX / 2) - 13 and x < math.floor(termX / 2) - 4 and y == math.floor(termY / 2) + 1 and button == 1 then
- flashChoice((termX / 2) - 12, (termY / 2) + 1, green, white, " Save ")
- if gateChange then saveData(gateData, "gate") end
- if configChange then saveData(settingsData, "cfg") end
- return shutDown()
- elseif x > math.floor(termX / 2) - 4 and x < math.floor(termX / 2) + 5 and y == math.floor(termY / 2) + 1 and button == 1 then
- flashChoice((termX / 2) - 3, (termY / 2) + 1, orange, white, " Quit ")
- return shutDown()
- end
- else
- runState = "Dial"
- drawElement((termX / 2) - 13, (termY / 2) - 1, 19, 4, nil, black) --#clear pop-up
- return drawAddressBook()
- end
- end
- end
- local function inputImportExportPopUp()
- local _, button, x, y
- while true do
- _, button, x, y = os.pullEvent("mouse_click")
- if x > math.floor(termX / 2) - 14 and x < math.floor(termX / 2) + 5 and y < math.floor(termY / 2) + 7 and y > math.floor(termY / 2) - 1 and button == 1 then --# Import (Merge)
- if x > math.floor(termX / 2) - 13 and x < math.floor(termX / 2) - 4 and y == math.floor(termY / 2) + 1 then
- if fs.exists("/disk/data/DHDgates") then
- flashChoice((termX / 2) - 12, (termY / 2) + 1, yellow, black, " Import ")
- local diskData = fs.open("/disk/data/DHDgates", "r")
- local dhdData = textutils.unserialize(diskData.readAll())
- diskData.close()
- mergeAddressBooks(dhdData)
- if gateChange then
- drawHeader() --# redraw header in case thisGate has been imported or updated
- drawAddressBook()
- drawNaviUI()
- drawAddrBookButton()
- if displayState == "list" then displayAddressBook() end
- if gateMonList then displayGateMonAddrBook() end
- end
- drawPopUp()
- end
- elseif x > math.floor(termX / 2) - 4 and x < math.floor(termX / 2) + 5 and y == math.floor(termY / 2) + 1 then --# Export
- if fs.exists("/disk") then
- flashChoice((termX / 2) - 3, (termY / 2) + 1, orange, black, " Export ")
- if not fs.exists("/disk/data") then fs.makeDir("/disk/data") end
- saveData("/disk/data/DHDgates", "gate")
- drawPopUp()
- end
- elseif x > math.floor(termX / 2) - 13 and x < math.floor(termX / 2) - 4 and y == math.floor(termY / 2) + 3 and gateChange then --# Load Address Book
- flashChoice((termX / 2) - 12, (termY / 2) + 3, sky, white, " Load ")
- ingestData(gateData, "gate")
- drawElement(2, 6, 39, 11, nil, black) --# clear data area in case loaded address book has fewer entries that address book in memory
- gateChange = false
- drawHeader()
- drawAddressBook()
- drawNaviUI()
- drawAddrBookButton()
- drawPopUp()
- if displayState == "info" then
- displayState = "list"
- if dhdSettings.detailedMarquee then
- initMarquee = true
- displayStatusDetail()
- else
- displayStatus()
- end
- if gateStatus ~= "Idle" then displayAddressBook() end
- else
- displayAddressBook()
- end
- if gateMonList then displayGateMonAddrBook() end
- elseif x > math.floor(termX / 2) - 4 and x < math.floor(termX / 2) + 5 and y == math.floor(termY / 2) + 3 and gateChange then --# Save Address Book
- flashChoice((termX / 2) - 3, (termY / 2) + 3, green, white, " Save ")
- saveData(gateData, "gate")
- drawAddrBookButton()
- drawPopUp()
- elseif x > math.floor(termX / 2) - 8 and x < math.floor(termX / 2) and y == math.floor(termY / 2) + 5 then --# Exit popup
- runState = "Dial"
- flashChoice((termX / 2) - 7, (termY / 2) + 5, red, white, " CLOSE ")
- drawElement((termX / 2) - 13, (termY / 2) - 1, 19, 8, nil, black) -- clear pop-up
- return drawAddressBook()
- end
- end
- end
- end
- local function inputGoToLogPage()
- bgCol, txtCol = black, white
- term.setBackgroundColor(black)
- term.setTextColor(white)
- term.setCursorPos(math.floor(termX / 2) - 2, termY - 2)
- local newPage = tonumber(read(nil, nil, 4))
- drawElement((termX / 2) - 4, termY - 3, 8, 3) --# clear pop-up
- logPage = newPage or logPage
- logPage = math.floor(math.max(1, math.min(logPage, logPages)))
- runState = "logs"
- drawLogScreen()
- end
- local function inputGoToPage()
- bgCol, txtCol = black, white
- term.setBackgroundColor(black)
- term.setTextColor(white)
- term.setCursorPos(math.floor(termX / 2) - 6, termY - 2)
- local newPage = tonumber(read(nil, nil, 4))
- drawElement((termX / 2) - 8, termY - 3, 8, 3) --# clear pop-up
- gatePage = newPage or gatePage
- gatePage = math.floor(math.max(1, math.min(gatePage, gatePages)))
- if gatePage == gatePages and gatePages > 1 then drawElement(2, 6, 39, 11) end --# clear data area
- runState = "Dial"
- drawAddressBook()
- drawNaviUI()
- end
- local function inputRemotePassword()
- bgCol, txtCol = silver, black
- term.setBackgroundColor(silver)
- term.setTextColor(black)
- term.setCursorPos(math.floor(termX / 2) - 6, 11)
- local remotePass = read("*", nil, 12)
- if remotePass ~= "" then
- local pass = table.concat(pbkdf2(remotePass, "ccDHD!Pass.Hash", 15))
- netSend(dhdSettings.gate, { program = "ccDialer", password = pass })
- end
- drawElement((termX / 2) - 8, 10, 16, 3, nil, black) --# clear pop-up
- runState = tempState
- if runState == "GateEdit" then drawGateData() else drawAddressBook() end
- end
- local function inputChangeLockdownPassword()
- local oldPass, newPass, newHashed, oldHashed, goodChange = "", "", "", "", false
- bgCol, txtCol = black, yellow
- term.setTextColor(yellow)
- while true do
- drawElement((termX / 2) - 6, 8, 14, 1, yellow, black) --# old password entry area
- term.setCursorPos(math.floor(termX / 2) - 5, 8)
- oldPass = read("*", nil, 12)
- if runState == "DHDsettings" then return end --# Cancel has been clicked
- if oldPass ~= "" then
- drawElement((termX / 2) - 5, 8, 1, 1, gray, nil, string.rep("*", #oldPass))
- oldHashed = table.concat(pbkdf2(oldPass, "ccDHD!Pass.Hash", 15))
- else
- oldHashed = ""
- end
- if newPass ~= "" and newHashed ~= "" and newHashed ~= dhdSettings.password and oldHashed == dhdSettings.password then
- goodChange = true
- break
- end
- drawElement((termX / 2) - 6, 10, 14, 1, yellow) --# new password entry area
- term.setCursorPos(math.floor(termX / 2) - 5, 10)
- newPass = read("*", nil, 12)
- if runState == "DHDsettings" then return end --# Cancel has been clicked
- if newPass ~= "" then
- drawElement((termX / 2) - 5, 10, 1, 1, gray, nil, string.rep("*", #newPass))
- newHashed = table.concat(pbkdf2(newPass, "ccDHD!Pass.Hash", 15))
- else
- newHashed = ""
- end
- if newPass ~= "" and newHashed ~= "" and newHashed ~= dhdSettings.password and oldHashed == dhdSettings.password then
- goodChange = true
- break
- end
- end
- if goodChange then
- configChange = true
- dhdSettings.password = newHashed
- runState = "DHDsettings"
- drawElement((termX / 2) - 7, 6, 16, 6) --# clear password change box
- drawSettingsScreen()
- end
- end
- local function inputChangeIrisPassword()
- local oldPass, newPass, oldHashed, newHashed, goodChange = "", "", "", "", false
- bgCol, txtCol = black, yellow
- term.setTextColor(yellow)
- while true do
- drawElement((termX / 2) - 6, 8, 14, 1, yellow, black) --# old password entry area
- term.setCursorPos(math.floor(termX / 2) - 5, 8)
- oldPass = read("*", nil, 12)
- if runState == "DHDsettings" then return end --# Cancel has been clicked
- if oldPass ~= "" then
- drawElement((termX / 2) - 5, 8, 1, 1, gray, nil, string.rep("*", #oldPass))
- oldHashed = table.concat(pbkdf2(oldPass, "ccDHD!Pass.Hash", 15))
- else
- oldHashed = ""
- end
- if newPass ~= "" and newHashed ~= "" and newHashed ~= dhdSettings.irisPassword and oldHashed == dhdSettings.irisPassword then
- goodChange = true
- break
- end
- drawElement((termX / 2) - 6, 10, 14, 1, yellow) --# new password entry area
- term.setCursorPos(math.floor(termX / 2) - 5, 10)
- newPass = read("*", nil, 12)
- if runState == "DHDsettings" then return end --# Cancel has been clicked
- if newPass ~= "" then
- drawElement((termX / 2) - 5, 10, 1, 1, gray, nil, string.rep("*", #newPass))
- newHashed = table.concat(pbkdf2(newPass, "ccDHD!Pass.Hash", 15))
- else
- newHashed = ""
- end
- if newPass ~= "" and newHashed ~= "" and newHashed ~= dhdSettings.irisPassword and oldHashed == dhdSettings.irisPassword then
- goodChange = true
- break
- end
- end
- if goodChange then
- configChange = true
- dhdSettings.irisPassword = newHashed
- runState = "DHDsettings"
- drawElement((termX / 2) - 7, 6, 16, 6) --# clear password change box
- drawSettingsScreen()
- end
- end
- local function inputSelectPassword()
- local _, button, x, y
- while true do
- _, button, x, y = os.pullEvent("mouse_click")
- if y > 7 and y < 12 and x > math.floor(termX / 2) - 7 and x < math.floor(termX / 2) + 8 and button == 1 then
- if y == 8 and x > math.floor(termX / 2) - 7 and x < math.floor(termX / 2) + 8 then --# lockdown
- runState = "newLockPass"
- return drawPopUp()
- elseif y == 10 and x > math.floor(termX / 2) - 7 and x < math.floor(termX / 2) + 8 then --# iris
- runState = "newIrisPass"
- return drawPopUp()
- elseif y == 11 and x > math.floor(termX / 2) - 4 and x < math.floor(termX / 2) + 5 then --# cancel
- flashChoice((termX / 2) - 3, 11, orange, white, " Cancel ")
- runState = "DHDsettings"
- drawElement((termX / 2) - 7, 6, 16, 6, nil, black) --# clear password change box
- return drawSettingsScreen()
- end
- end
- end
- end
- local function inputEditGateEntry()
- local event, data, x, y, addr
- while true do
- event, data, x, y = os.pullEvent()
- if event == "mouse_click" then
- addr = addressBook[currentEdit].addr
- if y == 3 and x > termX - 3 and data == 1 and gateStatus == "Connected" and secureStatus == "allclear" then --# Remote Iris
- tempState = runState
- runState = "remotePass"
- return drawPopUp()
- elseif y == 6 and data == 1 then
- if x > 10 and x < 23 then --# Gate Name
- drawElement(11, 6, 1, 1, gray, black, addressBook[currentEdit].name)
- bgCol, txtCol = black, cyan
- term.setTextColor(cyan)
- term.setCursorPos(11, 6)
- local newGateName = read(nil, { addr, addressBook[currentEdit].name }, 12)
- if newGateName ~= "" and newGateName ~= addressBook[currentEdit].name then
- addressBook[currentEdit].name = newGateName
- if displayState == "list" then
- if addr == thisGate or addr:sub(1, 7) == thisGate or addr == thisGate:sub(1, 7) then
- if dhdSettings.detailedMarquee then
- initMarquee = true --# in case entry being edited is this gate
- displayStatusDetail()
- else
- displayStatus()
- end
- end
- displayAddressBook()
- elseif displayState == "info" and currentEdit == selectedGate then
- displayNotes()
- end
- if gateMonList then displayGateMonAddrBook() end
- gateDataChange()
- drawHeader()
- end
- drawElement(11, 6, 1, 1, cyan, black, addressBook[currentEdit].name .. string.rep(" ", 12 - #addressBook[currentEdit].name))
- elseif x > 30 and x < 35 and not lcGate then --# Iris control
- if addressBook[currentEdit].iris == "none" then
- addressBook[currentEdit].iris = true
- elseif addressBook[currentEdit].iris then
- addressBook[currentEdit].iris = false
- else
- addressBook[currentEdit].iris = "none"
- end
- drawElement(31, 6, addressBook[currentEdit].iris)
- gateDataChange()
- elseif x > termX - 7 and x < termX - 6 + #tostring(currentEdit) then --# Address Book entry position (for reordering)
- drawElement(termX - 6, 6, 1, 1, gray, black, tostring(currentEdit))
- bgCol, txtCol = black, white
- term.setTextColor(white)
- term.setCursorPos(termX - 6, 6)
- local newPos = tonumber(read(nil, { tostring(currentEdit) }, 5))
- if newPos then newPos = math.floor(newPos) end
- if newPos and newPos ~= currentEdit and newPos > 0 and newPos <= abCount then
- local tempGateData = { }
- for k, v in pairs(addressBook[currentEdit]) do
- tempGateData[k] = v
- end
- table.remove(addressBook, currentEdit)
- table.insert(addressBook, newPos, tempGateData)
- if displayState == "info" then
- if currentEdit == selectedGate then
- selectedGate = newPos
- elseif currentEdit > selectedGate and newPos < selectedGate then
- selectedGate = selectedGate + 1
- elseif currentEdit < selectedGate and newPos > selectedGate then
- selectedGate = selectedGate - 1
- end
- displayNotes()
- else
- displayAddressBook()
- end
- if gateMonList then displayGateMonAddrBook() end
- currentEdit = newPos
- gateDataChange()
- end
- drawElement(termX - 6, 6, 1, 1, white, black, tostring(currentEdit) .. string.rep(" ", 5 - #tostring(currentEdit)))
- end
- elseif y == 8 then
- if x > 10 and x < 20 then --# Gate Address
- if data == 1 then
- drawElement(11, 8, 1, 1, gray, black, addr)
- bgCol, txtCol = black, yellow
- term.setTextColor(yellow)
- term.setCursorPos(11, 8)
- local newGateAddress = read(nil, { addr }, 9, nil, nil, true)
- local ngLen, name = #newGateAddress, addressBook[currentEdit].name
- if newGateAddress ~= "" and (ngLen == 7 or ngLen == 9) and newGateAddress ~= addr and not newGateAddress:find("?") then
- addressBook[currentEdit].addr = newGateAddress
- if name == "NEW GATE" or name == "Name" or name == "NO GATES" then
- addressBook[currentEdit].name = newGateAddress
- drawElement(11, 6, 1, 1, sky, nil, addressBook[currentEdit].name .. string.rep(" ", 12 - #addressBook[currentEdit].name))
- end
- if displayState == "list" then
- if addr == thisGate or addr:sub(1, 7) == thisGate or addr == thisGate:sub(1, 7) then
- if dhdSettings.detailedMarquee then
- initMarquee = true --# in case entry being edited is this gate
- displayStatusDetail()
- else
- displayStatus()
- end
- end
- displayAddressBook()
- elseif displayState == "info" and currentEdit == selectedGate then
- displayNotes()
- end
- if gateMonList then displayGateMonAddrBook() end
- gateDataChange()
- drawHeader()
- end
- drawElement(11, 8, 1, 1, yellow, black, addressBook[currentEdit].addr .. " ")
- elseif data == 2 and addr ~= thisGate then
- runState = "Dial"
- dialAddress = addr
- netSend(dhdSettings.gate, { program = "ccDHD", command = dialAddress })
- return drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- end
- elseif x > 30 and x < 35 and data == 1 and not lcGate then --# callDrop control
- addressBook[currentEdit].callDrop = not addressBook[currentEdit].callDrop
- drawElement(31, 8, addressBook[currentEdit].callDrop)
- gateDataChange()
- end
- elseif y == 10 and data == 1 then --# Edit Gate Note
- if x > 7 and x < 8 + #addressBook[currentEdit].note:sub(1, 43) then
- drawElement(8, 10, 1, 1, gray, black, addressBook[currentEdit].note)
- bgCol, txtCol = black, white
- term.setTextColor(white)
- term.setCursorPos(8, 10)
- local newNote = read(nil, { addressBook[currentEdit].note }, 43)
- if newNote ~= "" and newNote ~= addressBook[currentEdit].note then
- addressBook[currentEdit].note = newNote
- if displayState == "info" and currentEdit == selectedGate then
- displayNotes()
- end
- gateDataChange()
- end
- drawElement(8, 10, 1, 1, white, black, addressBook[currentEdit].note .. string.rep(" ", 43 - #addressBook[currentEdit].note))
- end
- elseif y == 12 and data == 1 then --# Change Gate Rating/Classification
- if x > 17 and x < 18 + #assignRating(currentEdit) then
- drawRatingList(addressBook[currentEdit].rating)
- local selected, _, mButton, mX, mY = false
- while true do
- _, mButton, mX, mY = os.pullEvent("mouse_click")
- if mX > 17 and mX < 38 and mY > 5 and mY < 17 then --# Bounds of pop-up, so clicking on the popup won't close it
- if mButton == 1 and mY > 7 and mY < 16 then --# actual selection bounds
- for k, v in pairs(classifications) do
- if mY == v.order + 7 then
- if addressBook[currentEdit].rating ~= k then
- addressBook[currentEdit].rating = k
- drawHeader()
- if displayState == "list" then
- if addr == thisGate or addr:sub(1, 7) == thisGate or addr == thisGate:sub(1, 7) then
- if dhdSettings.detailedMarquee then
- initMarquee = true --# in case entry being edited is this gate
- displayStatusDetail()
- else
- displayStatus()
- end
- end
- displayAddressBook()
- elseif displayState == "info" and currentEdit == selectedGate then
- displayNotes()
- end
- if gateMonList then displayGateMonAddrBook() end
- gateDataChange()
- end
- selected = true
- break
- end
- end
- if selected then break end
- end
- else
- break
- end
- end
- drawElement(18, 6, 20, 11, nil, black) --# clear rating popup
- drawElement(11, 6, 1, 1, cyan, nil, addressBook[currentEdit].name) --# clean up after the rating pop-up
- drawElement(11, 8, 1, 1, yellow, nil, addr)
- drawElement(18, 12, 1, 1, assignColor(currentEdit), nil, assignRating(currentEdit))
- drawElement(25, 16, 2, 1, gray, nil, "y:")
- if addr == thisGate or addr:sub(1, 7) == thisGate or addr == thisGate:sub(1, 7) or addr == dialAddress or addr:sub(1, 7) == dialAddress or addr == dialAddress:sub(1, 7) or (incomingAddress and (addr == incomingAddress or addr:sub(1, 7) == incomingAddress or addr == incomingAddress:sub(1, 7))) then
- drawElement(termX - 14, 8, 1, 1, nil, nil, "<")
- end
- drawElement(8, 10, 1, 1, white, nil, addressBook[currentEdit].note)
- drawElement(13, 14, 1, 1, brown, nil, addressBook[currentEdit].loc.dim)
- drawElement(15, 16, 1, 1, silver, nil, tostring(addressBook[currentEdit].loc.x))
- drawElement(28, 16, 1, 1, nil, nil, tostring(addressBook[currentEdit].loc.y))
- if not lcGate then
- drawElement(25, 6, 1, 1, gray, nil, "Iris:")
- drawElement(25, 8, 1, 1, nil, nil, "Drop:")
- drawElement(31, 6, addressBook[currentEdit].iris)
- drawElement(31, 8, addressBook[currentEdit].callDrop)
- end
- end
- elseif y == 14 and data == 1 then --# Gate Dimension
- if x > 12 and x < 13 + #addressBook[currentEdit].loc.dim then
- drawElement(13, 14, 1, 1, gray, black, addressBook[currentEdit].loc.dim)
- bgCol, txtCol = black, brown
- term.setTextColor(brown)
- term.setCursorPos(13, 14)
- local newDim = read(nil, { "Overworld", "Nether", "The End", addressBook[currentEdit].loc.dim }, 19)
- if newDim ~= "" and newDim ~= addressBook[currentEdit].loc.dim then
- addressBook[currentEdit].loc.dim = newDim
- if displayState == "info" and currentEdit == selectedGate then
- displayNotes()
- end
- gateDataChange()
- end
- drawElement(13, 14, 1, 1, brown, black, addressBook[currentEdit].loc.dim .. string.rep(" ", 19 - #addressBook[currentEdit].loc.dim))
- end
- elseif y == 16 and data == 1 then --# Gate X/Y/Z Coordinates
- local xStr, yStr, zStr = tostring(addressBook[currentEdit].loc.x), tostring(addressBook[currentEdit].loc.y), tostring(addressBook[currentEdit].loc.z)
- if x > 14 and x < 15 + #xStr then --# X coordinate
- drawElement(15, 16, 1, 1, gray, black, xStr)
- bgCol, txtCol = black, silver
- term.setTextColor(silver)
- term.setCursorPos(15, 16)
- local newX = tonumber(read(nil, { xStr }, 9))
- if newX and newX ~= addressBook[currentEdit].loc.x then
- addressBook[currentEdit].loc.x = newX
- xStr = tostring(newX)
- gateDataChange()
- end
- drawElement(15, 16, 1, 1, silver, black, xStr .. string.rep(" ", 9 - #xStr))
- elseif x > 27 and x < 28 + #yStr then --# Y coordinate
- drawElement(28, 16, 1, 1, gray, black, yStr)
- bgCol, txtCol = black, silver
- term.setTextColor(silver)
- term.setCursorPos(28, 16)
- local newY = tonumber(read(nil, { yStr }, 9))
- if newY and newY ~= addressBook[currentEdit].loc.y then
- addressBook[currentEdit].loc.y = newY
- yStr = tostring(newY)
- gateDataChange()
- end
- drawElement(28, 16, 1, 1, silver, black, yStr .. string.rep(" ", 9 - #yStr))
- elseif x > 40 and x < 41 + #zStr then --# Z coordinate
- drawElement(41, 16, 1, 1, gray, black, zStr)
- bgCol, txtCol = black, silver
- term.setTextColor(silver)
- term.setCursorPos(41, 16)
- local newZ = tonumber(read(nil, { zStr }, 9))
- if newZ and newZ ~= addressBook[currentEdit].loc.z then
- addressBook[currentEdit].loc.z = newZ
- zStr = tostring(newZ)
- gateDataChange()
- end
- drawElement(41, 16, 1, 1, silver, black, zStr .. string.rep(" ", 9 - #zStr))
- end
- elseif y == termY - 1 and data == 1 then
- if x > math.floor(termX / 2) - 9 and x < math.floor(termX / 2) - 2 and gateChange then --# Save Address Book
- flashChoice((termX / 2) - 8, termY - 1, white, green, " Save ")
- drawElement((termX / 2) - 8, termY - 1, 1, 1, silver, gray, " Save ")
- saveData(gateData, "gate")
- elseif x > math.floor(termX / 2) and x < math.floor(termX / 2) + 8 then --# Exit Gate View/Edit Screen
- runState = "Dial"
- currentEdit = nil
- flashChoice((termX / 2) + 1, termY - 1, white, red, " Close ")
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- return drawCLI()
- end
- end
- elseif event == "mouse_scroll" and ((data == 1 and currentEdit < abCount) or (data == -1 and currentEdit > 1)) then
- currentEdit = currentEdit + data
- if gettingInput then
- term.setCursorBlink(false)
- gettingInput = false
- end
- drawGateData()
- end
- end
- end
- local function inputSettings()
- local _, button, x, y
- while true do
- _, button, x, y = os.pullEvent("mouse_click")
- --# Save / Close buttons
- if y == 2 and x > 44 and button == 1 then --# Close Settings (no save)
- flashChoice(termX - 6, 2, white, red, " Close ")
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- runState = "Dial"
- return drawCLI()
- elseif y == 4 and x > 44 and button == 1 and configChange then --# Save Settings
- flashChoice(45, 4, white, green, " Save ")
- drawElement(45, 4, 1, 1, gray, silver, " Save ")
- saveData(settingsData, "cfg")
- configChange = false
- end
- --# Column 1
- if y == 6 and x > 15 and x < 25 and button == 1 then --# Change LOCKDOWN or remote Iris Password
- runState = "newPassword"
- return drawPopUp()
- end
- if hardware.bio > 0 then
- if y == 10 and x > 21 and x < 26 and button == 1 then --# Biolock ON/OFF
- dhdSettings.bio.lock = not dhdSettings.bio.lock
- drawElement(22, 10, dhdSettings.bio.lock)
- settingsChange()
- elseif y == 12 and x > 21 and x < 26 and button == 1 then --# Bioscanner function (iris/lockdown)
- if dhdSettings.bio.func == "none" then
- dhdSettings.bio.func = "iris"
- drawElement(7, 12, 1, 1, green, black, "Iris ")
- drawElement(22, 12, true)
- elseif dhdSettings.bio.func == "iris" then
- dhdSettings.bio.func = "lock"
- drawElement(7, 12, 1, 1, red, black, "Lockdown ")
- drawElement(22, 12, false)
- elseif dhdSettings.bio.func == "lock" then
- dhdSettings.bio.func = "none"
- drawElement(7, 12, 1, 1, silver, black, "No Function")
- drawElement(22, 12, "MID")
- end
- settingsChange()
- elseif y == 14 and x > 19 and x < 25 and button == 1 then --# Set Biolock login authorization level
- if dhdSettings.bio.auth ~= x - 19 then
- drawElement(19 + dhdSettings.bio.auth, 14, 1, 1, gray, black, "-")
- dhdSettings.bio.auth = x - 19
- drawElement(19 + dhdSettings.bio.auth, 14, 1, 1, black, silver, tostring(dhdSettings.bio.auth))
- settingsChange()
- end
- elseif y == 16 and x > 19 and x < 25 and button == 1 then --# Set Biolock iris/lockdown authorization level
- if dhdSettings.bio.fAuth ~= x - 19 then
- drawElement(19 + dhdSettings.bio.fAuth, 16, 1, 1, gray, black, "-")
- dhdSettings.bio.fAuth = x - 19
- drawElement(19 + dhdSettings.bio.fAuth, 16, 1, 1, black, silver, tostring(dhdSettings.bio.fAuth))
- settingsChange()
- end
- end
- else
- if y == 12 and x > 11 and x < 12 + #ccLabel and button == 1 then --# Change computer label
- drawElement(12, 12, 1, 1, gray, black, ccLabel)
- txtCol, bgCol = white, black
- term.setTextColor(white)
- term.setCursorPos(12, 12)
- local newLabel = read(nil, { ccLabel }, 15)
- drawElement(12, 12, 15, 1)
- if newLabel ~= "" and newLabel ~= ccLabel then ccLabel = newLabel os.setComputerLabel(newLabel) end
- drawElement(12, 12, 1, 1, white, black, ccLabel)
- end
- end
- --# Column 2
- if x > 45 and x < 50 and y > 5 and y < 17 and button == 1 then
- if y == 6 and hardware.wifiSide ~= "none" then --# Sync for ccDialer
- if type(dhdSettings.sync) == "string" then --# if Sync is already set to 'Dial ONLY' then set it to 'Dial & Sync'...
- dhdSettings.sync = true
- drawElement(34, 6, 1, 1, green, black, "Dial & Sync")
- drawElement(46, 6, true)
- settingsChange()
- elseif dhdSettings.sync then --# otherwise if Sync is set to 'Dial & Sync' then turn it off...
- sendToAllSyncClients("Offline")
- dhdSettings.sync = false
- rednet.unhost("ccDialerWiFi", thisGate)
- if hardware.modemSide ~= "none" and rednet.isOpen(hardware.wifiSide) then rednet.close(hardware.wifiSide) end
- if clientCount > 0 then
- for id in pairs(clients) do
- clients[id] = nil
- clientCount = math.max(0, clientCount - 1)
- end
- end
- drawElement(34, 6, 1, 1, red, black, "OFF ")
- drawElement(46, 6, false)
- settingsChange()
- else --# otherwise if Sync is off then set it to 'Dial ONLY'...
- dhdSettings.sync, configChange = "Dial ONLY", true
- drawElement(46, 6, 4, 1, nil, orange) --# 'Sync initializing' switch position (orange)
- drawElement(47, 6, 2, 1, nil, gray)
- drawElement((termX / 2) - 7, (termY / 2) - 2, 20, 1, white, blue, "Sync")
- drawElement((termX / 2) - 7, (termY / 2) - 1, 20, 3, nil, silver, "Initializing...")
- if not rednet.isOpen(hardware.wifiSide) then rednet.open(hardware.wifiSide) end
- rednet.host("ccDialerWiFi", thisGate)
- drawElement((termX / 2) - 7, (termY / 2) - 2, 20, 4, nil, black) --# clear pop-up
- drawSettingsScreen()
- end
- elseif y == 10 then --# Show detailed gate info on the marquee monitor
- dhdSettings.detailedMarquee = not dhdSettings.detailedMarquee
- drawElement(46, 10, dhdSettings.detailedMarquee)
- if displayState == "list" then
- if dhdSettings.detailedMarquee then
- initMarquee = true
- displayStatusDetail()
- else
- displayStatus()
- end
- end
- settingsChange()
- elseif y == 12 then --# Call Logging (ON/OFF)
- dhdSettings.logs = not dhdSettings.logs
- drawElement(46, 12, dhdSettings.logs)
- settingsChange()
- elseif y == 14 then --# Incoming Call Auto-Iris (CLOSE/DO NOTHING)
- dhdSettings.incomingIris = not dhdSettings.incomingIris
- drawElement(46, 14, dhdSettings.incomingIris)
- settingsChange()
- elseif y == 16 then --# End Call Iris (OPEN/CLOSE/DO NOTHING)
- if type(dhdSettings.ecIris) == "boolean" then
- if dhdSettings.ecIris then
- dhdSettings.ecIris = false
- else
- dhdSettings.ecIris = "none"
- end
- elseif type(dhdSettings.ecIris) == "string" then
- dhdSettings.ecIris = true
- end
- drawElement(46, 16, dhdSettings.ecIris)
- settingsChange()
- end
- end
- end
- end
- local function inputLogs()
- local event, data, x, y
- while true do
- event, data, x, y = os.pullEvent()
- if event == "mouse_click" then
- if y == 2 and x > 44 and data == 1 then
- flashChoice(termX - 6, 2, white, red, " Close ")
- runState = "Dial"
- lastCall = nil
- clearCallHistory()
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- return drawCLI()
- elseif y == 4 and x > 44 and data == 1 and callHistory[1] then
- flashChoice(termX - 6, 4, white, orange, " Clear ")
- drawElement(termX - 6, 4, 1, 1, orange, silver, " Clear ")
- runState = "clearLogs"
- return drawPopUp()
- elseif y == termY and data == 1 then
- if (x > 10 and x < 13 and logPage > 1) or (x > 36 and x < 39 and logPage < logPages) then --# Home / End
- logPage = x < 13 and 1 or logPages
- drawLogScreen()
- elseif (x > 13 and x < 15 and logPage > 1) or (x > 34 and x < 36 and logPage < logPages) then --# PageBack / PageForward
- logPage = x < 15 and logPage - 1 or logPage + 1
- drawLogScreen()
- elseif x > 18 and x < 33 and logPages > 1 then --# Page Entry
- local lPage, lPages = tostring(logPage), tostring(logPages)
- flashChoice((termX / 2) - 3 - ((#lPage + #lPages) / 2), termY, gray, silver, " " .. lPage .. " of " .. lPages .. " ")
- drawElement((termX / 2) - 3 - ((#lPage + #lPages) / 2), termY, 1, 1, silver, gray, " " .. lPage .. " of " .. lPages .. " ")
- runState = "goLogPage"
- return drawPopUp()
- end
- elseif y == 3 and x > 27 and x < 37 and lastCall then --# last call
- local callAddress = lastCall:sub(lastCall:find(">") + 2)
- local caLen = #callAddress
- if data == 1 and (caLen == 7 or caLen == 9) then
- return dialAddressFromLogs(callAddress)
- elseif data == 2 and (caLen == 7 or caLen == 9) then
- return addAddressFromLogs(callAddress)
- end
- elseif y > 5 and y < termY - 2 and x > 27 and x < 37 and callHistory[1] then --# call log
- local currentEntry = ((logPage - 1) * 11) + 1 --# Set the first entry (based on page number)
- if callHistory[currentEntry + y - 6] then
- local callAddress = callHistory[currentEntry + y - 6]:sub(callHistory[currentEntry + y - 6]:find(">") + 2)
- local caLen = #callAddress
- if data == 1 and (caLen == 7 or caLen == 9) then
- return dialAddressFromLogs(callAddress)
- elseif data == 2 and (caLen == 7 or caLen == 9) then
- return addAddressFromLogs(callAddress)
- end
- end
- end
- elseif event == "mouse_scroll" and ((data == 1 and logPage < logPages) or (data == -1 and logPage > 1)) then
- logPage = logPage + data
- drawLogScreen()
- elseif event == "key" and logPages > 1 then
- if (data == keys.home and logPage > 1) or (data == keys["end"] and logPage < logPages) then
- logPage = data == keys.home and 1 or logPages
- drawLogScreen()
- elseif (data == keys.pageUp and logPage > 1) or (data == keys.pageDown and logPage < logPages) then
- logPage = data == keys.pageUp and logPage - 1 or logPage + 1
- drawLogScreen()
- end
- end
- end
- end
- local function inputDial()
- local event, data, x, y
- while true do
- event, data, x, y = os.pullEvent()
- if event == "mouse_click" then
- --# Menu & Menu Selections
- if menuState then
- if x > 1 and x < 12 and y > 1 and y < 11 then
- if y == 3 and data == 1 then
- flashChoice(3, 3, white, sky, "Settings ")
- runState = "DHDsettings"
- menuState = false
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- return drawSettingsScreen()
- elseif y == 5 and data == 1 then
- flashChoice(3, 5, black, yellow, "View Logs")
- runState = "logs"
- menuState = false
- ingestData("logs")
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- return drawLogHeader()
- elseif y == 7 and data == 1 then
- flashChoice(3, 7, white, cyan, "DHD Help ")
- runState = "DHDhelp"
- menuState = false
- return drawHelpScreen()
- elseif y == 9 and data == 1 then
- flashChoice(3, 9, white, red, " EXIT ")
- if gateChange or configChange then
- clearMenu()
- runState = "exodus"
- return drawPopUp()
- else
- return shutDown()
- end
- end
- else
- clearMenu()
- end
- else
- if y == 1 and x > 1 and x < 7 and data == 1 then --# Open menu
- drawMenu()
- end
- --# Remote Iris
- if gateStatus == "Connected" and x > termX - 3 and y == 3 and data == 1 then
- tempState = runState
- runState = "remotePass"
- return drawPopUp()
- end
- --# Command Buttons
- if x > 42 and y > 6 and y < 16 and secureStatus == "allclear" then
- if y == 7 and data == 1 then --# Iris
- if irisStatus == "Open" or irisStatus == "Opening" then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "iCLOSE" })
- elseif (irisStatus == "Closed" or irisStatus == "Closing") and secureStatus == "allclear" then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "iOPEN" })
- end
- elseif y == 9 and data == 1 then --# END Call
- if gateStatus ~= "Disconnecting" and gateStatus ~= "Idle" then
- flashChoice(43, 9, orange, black, "END Call ")
- drawElement(43, 9, 1, 1, black, orange, "END Call ")
- netSend(dhdSettings.gate, { program = "ccDHD", command = "endCall" })
- end
- elseif y == 11 and data == 1 then --# LOCKDOWN
- flashChoice(43, 11, red, orange, "LOCKDOWN ")
- drawElement(43, 11, 1, 1, orange, red, "LOCKDOWN ")
- netSend(dhdSettings.gate, { program = "ccDHD", command = "lockdown" })
- return setupLockdown()
- elseif y == 13 then --# AddrBook
- if data == 1 or (data == 2 and gateChange) then
- flashChoice(43, 13, blue, white, "AddrBook ")
- if data == 1 then
- drawAddrBookButton()
- runState = "importExport"
- return drawPopUp()
- else
- saveData(gateData, "gate")
- drawAddrBookButton()
- end
- end
- elseif y == 15 then --# New Gate
- if data == 1 or data == 3 then
- flashChoice(43, 15, green, white, "New Gate ")
- if data == 1 then
- runState = "GateEdit"
- return addNewAddress()
- else
- drawElement(43, 15, 1, 1, white, green, "New Gate ")
- addNewAddress(nil, true)
- drawAddrBookButton()
- end
- end
- end
- end
- --# Page Navigation via click
- if y == termY and x > 9 and x < 32 and data == 1 and secureStatus == "allclear" then
- if (x > 9 and x < 12 and gatePage > 1) or (x > 29 and x < 32 and gatePage < gatePages) then --# Home / End
- gatePage = x < 12 and 1 or gatePages
- if gatePage == gatePages then drawElement(2, 6, 39, 11, nil, black) end --# clear data area
- drawAddressBook()
- drawNaviUI()
- elseif (x > 12 and x < 14 and gatePage > 1) or (x > 27 and x < 29 and gatePage < gatePages) then --# Back / Forward
- gatePage = x < 14 and gatePage - 1 or gatePage + 1
- if gatePage == gatePages then drawElement(2, 6, 39, 11, nil, black) end --# clear data area
- drawAddressBook()
- drawNaviUI()
- elseif x > 16 and x < 25 and gatePages > 1 then --# Page Numbers (Go To Page dialogue)
- flashChoice(((termX / 2) - 3) - (#pNum / 2) - 2, termY, black, gray, " " .. pNum .. " ")
- drawElement(((termX / 2) - 3) - (#pNum / 2) - 2, termY, 1, 1, gray, black, " " .. pNum .. " ")
- runState = "goPage"
- return drawPopUp()
- end
- end
- --# Dial a listed address, view it's info, or delete
- if x > 1 and x < 41 and y > 5 and y < 17 then
- local magicNumber = ((gatePage - 1) * 17) + gatePage
- local xPos, yPos = 2, 6
- for i = magicNumber, math.min(abCount, gatePage * 18) do
- if x >= xPos and x <= xPos + 11 and y == yPos then
- if data == 1 and gateStatus == "Idle" then --# Dial entry
- if addressBook[i].addr == thisGate then break end
- flashDial(addressBook[i].name, xPos, yPos, i)
- dialAddress = addressBook[i].addr
- netSend(dhdSettings.gate, { program = "ccDHD", command = dialAddress })
- break
- elseif data == 1 and lcGate and (gateStatus == "Dialing" or gateStatus == "Paused") and dialAddress == addressBook[i].addr then
- flashDial(addressBook[i].name, xPos, yPos, i)
- netSend(dhdSettings.gate, { program = "ccDHD", command = "dialPause" })
- break
- elseif data == 2 then --# View/Edit entry
- flashDial(addressBook[i].name, xPos, yPos, i)
- runState = "GateEdit"
- currentEdit = i
- return drawGateLabels()
- elseif data == 3 and abCount > 1 then --# Delete entry if there is more than one entry in the addressBook
- local gMatch = addressBook[i].addr == thisGate
- deleteGate(i)
- if gatePage == gatePages then drawElement(2, 6, 39, 11, nil, black) end --# clear data area
- if gMatch then drawFullHeader(false) end
- drawAddressBook()
- drawAddrBookButton()
- drawNaviUI()
- break
- end
- end
- yPos = yPos + 2
- if yPos > 16 then yPos = 6 xPos = xPos + 13 end
- end
- end
- end
- elseif event == "mouse_scroll" and ((data == 1 and gatePage < gatePages) or (data == -1 and gatePage > 1)) then
- gatePage = gatePage + data
- if menuState then
- menuState = false
- drawElement(2, 2, 10, 11, nil, black) --# clear menu
- drawFullHeader(true)
- end
- if gatePage == gatePages then drawElement(2, 6, 39, 11, nil, black) end --# clear data area
- drawAddressBook()
- drawNaviUI()
- elseif event == "key" then
- if data == keys.f1 then
- runState = "DHDhelp"
- return drawHelpScreen()
- elseif (data == keys.home and gatePage > 1) or (data == keys["end"] and gatePage < gatePages) then
- gatePage = data == keys.home and 1 or gatePages
- if gatePage == gatePages then drawElement(2, 6, 39, 11, nil, black) end --# clear data area
- drawAddressBook()
- drawNaviUI()
- elseif (data == keys.pageUp and gatePage > 1) or (data == keys.pageDown and gatePage < gatePages) then
- gatePage = data == keys.pageUp and gatePage - 1 or gatePage + 1
- if gatePage == gatePages then drawElement(2, 6, 39, 11, nil, black) end --# clear data area
- drawAddressBook()
- drawNaviUI()
- end
- end
- end
- end
- local function inputHelp()
- local event, data, x, y
- while true do
- event, data, x, y = os.pullEvent()
- if (event == "mouse_click" and x > 44 and y == 2 and data == 1) or (event == "key" and data == keys.f1) then --# DHD Help Screen (close button)
- flashChoice(termX - 6, 2, white, red, " Close ")
- drawElement(1, 5, termX, termY - 4, nil, black) --# clear lower screen
- runState = "Dial"
- return drawCLI()
- end
- end
- end
- local function inputLockdown()
- bgCol, txtCol = black, yellow
- term.setBackgroundColor(black)
- term.setTextColor(yellow)
- repeat
- term.setCursorPos(math.floor(termX / 2), 15)
- local passwordInput = table.concat(pbkdf2(read(nil, nil, 12, true, true), "ccDHD!Pass.Hash", 15))
- if passwordInput == dhdSettings.password then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "allclear" })
- clearLockdown()
- end
- term.setCursorPos(math.floor(termX / 2), 15)
- term.write(string.rep(" ", 12))
- until secureStatus == "allclear"
- end
- local function inputMonTouch()
- local _, monSide, touchX, touchY, touchRegistered
- while true do
- _, monSide, touchX, touchY = os.pullEvent("monitor_touch")
- touchRegistered = false
- if secureStatus == "allclear" and hardware.listMon > 0 then
- for i = 1, hardware.listMon do
- if monSide == listMonSides[i] then touchRegistered = true break end
- end
- if touchRegistered and displayState == "info" then
- displayState = "list"
- if dhdSettings.detailedMarquee then
- initMarquee = true
- displayStatusDetail()
- else
- displayStatus()
- end
- if gateStatus ~= "Idle" then displayAddressBook() end
- elseif touchRegistered and displayState == "list" then
- if touchY < 9 then
- selectedGate = (listPage - 1) * 8 + touchY
- if selectedGate <= abCount then
- displayState = "info"
- displayNotes()
- end
- elseif touchY > 8 and ((touchX < 10 and listPage > 1) or (touchX > 9 and listPage < listPages)) then
- listPage = touchX < 10 and math.max(1, listPage - 1) or math.min(listPage + 1, listPages)
- displayAddressBook()
- end
- end
- end
- if not touchRegistered and hardware.marquee > 0 then
- for i = 1, hardware.marquee do
- if monSide == marqueeSides[i] then touchRegistered = true break end
- end
- if touchRegistered and displayState == "info" and gateStatus == "Idle" and secureStatus == "allclear" then
- if addressBook[selectedGate].addr ~= thisGate then
- dialAddress = addressBook[selectedGate].addr
- netSend(dhdSettings.gate, { program = "ccDHD", command = dialAddress })
- end
- elseif touchRegistered and displayState == "info" and lcGate and (gateStatus == "Dialing" or gateStatus == "Paused") and addressBook[selectedGate].addr == dialAddress and secureStatus == "allclear" then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "dialPause" })
- elseif touchRegistered and (gateStatus == "Connected" or gateStatus == "Dialing" or gateStatus == "Paused") then --# not sure about (lcGate with gateStatus == "Dialing")
- netSend(dhdSettings.gate, { program = "ccDHD", command = "endCall" })
- end
- end
- if not touchRegistered and hardware.gateMon > 0 then
- for i = 1, hardware.gateMon do
- if monSide == gateMonSides[i] then touchRegistered = true break end
- end
- if touchRegistered and gateMonList then
- if touchY < 18 and touchX < 7 then
- local magicNumber = (gateMonPage - 1) * 17 + touchY
- if magicNumber <= abCount then
- if dialAddress ~= "none" or incomingAddress then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "endCall" })
- else
- if addressBook[magicNumber].addr ~= thisGate and secureStatus == "allclear" then
- dialAddress = addressBook[magicNumber].addr
- netSend(dhdSettings.gate, { program = "ccDHD", command = dialAddress })
- end
- end
- end
- elseif touchY > 18 then
- if (touchX < math.floor(29 / 2) - 2 and gateMonPage > 1) or (touchX > math.ceil(29 / 2) + 3 and gateMonPage < gateMonPages) then
- gateMonPage = touchX < math.floor(29 / 2) - 2 and math.max(gateMonPage - 1, 1) or math.min(gateMonPage + 1, gateMonPages)
- displayGateMonAddrBook()
- elseif touchX > math.floor(29 / 2) - 3 and touchX < math.ceil(29 / 2) + 4 then
- gateMonList = false
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(black)
- gateMon[i].clear()
- end
- displayGate()
- end
- end
- elseif touchRegistered and not gateMonList and secureStatus == "allclear" then
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(black)
- gateMon[i].clear()
- end
- gateMonList = true
- displayGateMonAddrBook()
- end
- end
- end
- end
- local function inputBioScan() --# "biolock", userIDprint, scannerAttachName, userName, userAccessLevel
- while true do
- local fistPrint = { os.pullEvent("biolock") }
- if fistPrint[1] == "biolock" then --# this is here because ^T otherwise causes an error 2/4 lines down during lockdown
- if runState == "init" then
- if fistPrint[5] >= dhdSettings.bio.auth then return end
- else
- if fistPrint[5] >= dhdSettings.bio.fAuth then
- if dhdSettings.bio.func == "iris" then
- if irisStatus == "Open" or irisStatus == "Opening" then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "iCLOSE" })
- elseif (irisStatus == "Closed" or irisStatus == "Closing") and secureStatus == "allclear" then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "iOPEN" })
- end
- elseif dhdSettings.bio.func == "lock" then
- if secureStatus == "allclear" then
- netSend(dhdSettings.gate, { program = "ccDHD", command = "lockdown" })
- return setupLockdown()
- else
- netSend(dhdSettings.gate, { program = "ccDHD", command = "allclear" })
- return clearLockdown()
- end
- end
- end
- end
- end
- end
- end
- local function userInput()
- repeat
- if secureStatus == "lockdown" then
- inputLockdown()
- elseif validStates[runState] then
- validStates[runState][4]()
- end
- until not kernelState
- end
- local function dataPoller()
- local _, timer, hours, minutes, seconds, sMinutes, sSeconds, sTenths
- while true do
- _, timer = os.pullEvent("timer")
- if timer == connectionTimer and gateStatus == "Connected" then
- connectionTime = connectionTime + 1
- connectionTimer = os.startTimer(0.1)
- hours = connectionTime > 35999 and math.floor(connectionTime / 36000) or 0
- minutes = connectionTime > 599 and math.floor((connectionTime - (hours * 36000)) / 600) or 0
- sMinutes = minutes > 9 and tostring(minutes) or "0" .. tostring(minutes)
- seconds = connectionTime > 9 and math.floor((connectionTime - ((hours * 36000) + (minutes * 600))) / 10) or 0
- sSeconds = seconds > 9 and tostring(seconds) or "0" .. tostring(seconds)
- sTenths = tostring(math.floor(connectionTime - ((hours * 36000) + (minutes * 600) + (seconds * 10))))
- connectionClock = sMinutes .. ":" .. sSeconds .. ":" .. sTenths
- displayConnectionTime()
- elseif timer == pingTimer then
- if clientCount > 0 then
- for id, timeout in pairs(clients) do
- clients[id] = timeout + 1
- if clients[id] > 2 then
- clients[id] = nil
- clientCount = math.max(0, clientCount - 1)
- else
- netSend(id, { program = "ccDialer", data = "ping" }, "ccDialerWiFi")
- end
- end
- end
- pingTimer = os.startTimer(5)
- end
- end
- end
- local function startupError(id)
- clearScreen()
- if id == "firstRunModem" then
- drawElement(2, 2, 1, 1, red, black, "gateLiaison or modem not detected!")
- drawElement(2, 4, 1, 1, gray, nil, "A modem and gateLiaison are REQUIRED.")
- elseif id == "modem" then
- drawElement(2, 2, 1, 1, red, black, "No modem detected!")
- drawElement(2, 4, 1, 1, gray, nil, "A modem is REQUIRED.")
- elseif id == "hardware" then
- local isColor = term.isColor()
- drawElement(2, 2, 1, 1, isColor and red or white, black, "Incorrect hardware detected!")
- drawElement(2, 4, 1, 1, isColor and gray or white, nil, "Advanced computer REQUIRED.")
- elseif id == "resolution" then
- drawElement(2, 2, 1, 1, red, black, "Screen size is wrong!")
- drawElement(2, 4, 1, 1, gray, nil, "51 x 18 or 51 x 19 REQUIRED.")
- end
- term.setCursorPos(1, 7)
- end
- local function addMonitor(attachName)
- peripheral.call(attachName, "setTextScale", 1)
- local monX, monY = peripheral.call(attachName, "getSize")
- if monX == 7 and monY == 5 then --# 1x1 monitor
- hardware.listMon = hardware.listMon + 1
- listMon[hardware.listMon] = peripheral.wrap(attachName)
- listMonSides[hardware.listMon] = attachName
- elseif monX == 18 and monY == 5 then --# 2x1 monitor array
- hardware.timerMon = hardware.timerMon + 1
- timerMon[hardware.timerMon] = peripheral.wrap(attachName)
- timerMonSides[hardware.timerMon] = attachName
- timerMon[hardware.timerMon].setTextScale(2.5)
- elseif monX == 29 and monY == 5 then --# 3x1 monitor array
- hardware.marquee = hardware.marquee + 1
- marquee[hardware.marquee] = peripheral.wrap(attachName)
- marqueeSides[hardware.marquee] = attachName
- elseif monX == 29 and monY == 19 then --# 3x3 monitor array
- hardware.gateMon = hardware.gateMon + 1
- gateMon[hardware.gateMon] = peripheral.wrap(attachName)
- gateMonSides[hardware.gateMon] = attachName
- end
- end
- local function detectHardware(hwType, firstRunNow)
- if hwType == "bio" then
- local tempBio = { peripheral.find("biolock") }
- hardware.bio = #tempBio
- drawElement(16, 8, 1, 1, hardware.bio > 0 and green or red, gray, hardware.bio > 0 and "O" or "0")
- elseif hwType == "modem" then
- local missed, id
- for _, side in pairs(rs.getSides()) do
- if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then
- if peripheral.call(side, "isWireless") then
- if hardware.wifiSide == "none" then
- hardware.wifiSide = side
- rednet.open(side)
- end
- elseif hardware.modemSide == "none" then
- for _, name in pairs(peripheral.call(side, "getNamesRemote")) do
- if peripheral.getType(name) == "computer" and peripheral.call(side, "isPresentRemote", name) then
- id = peripheral.call(side, "callRemote", name, "getID")
- rednet.open(side)
- if firstRunNow then
- missed = 0
- repeat
- gateLiaison = rednet.lookup("ccDHDSetup")
- if not gateLiaison then missed = missed + 1 sleep(1) end
- until (gateLiaison or missed > 9)
- end
- if (firstRunNow and id == gateLiaison) or id == dhdSettings.gate then
- hardware.modemSide = side
- break
- else
- rednet.close(side)
- end
- end
- end
- end
- if hardware.modemSide ~= "none" and hardware.wifiSide ~= "none" then break end
- end
- end
- elseif hwType == "mon" then
- for _, side in pairs(rs.getSides()) do
- if peripheral.isPresent(side) then
- if peripheral.getType(side) == "monitor" and peripheral.call(side, "isColor") then
- addMonitor(side)
- elseif peripheral.getType(side) == "modem" and not peripheral.call(side, "isWireless") then
- for _, name in pairs(peripheral.call(side, "getNamesRemote")) do
- if peripheral.getType(name) == "monitor" and peripheral.call(name, "isColor") then
- addMonitor(name)
- end
- end
- end
- end
- end
- end
- end
- local function waitAnimation() --# intentionally not using drawElement - less expense
- local xA, xB, y, bgColor
- if currentState == "init" then
- xA, xB, y, bgColor = 9, 25, 8, cyan --# gateLiaison QRY
- else
- xA, xB, y, bgColor = 2, 20, 4, blue --# Biolock
- end
- while true do
- for i = xA, xB do
- term.setCursorPos(i, y)
- term.setBackgroundColor(bgColor)
- term.write(" ")
- term.setBackgroundColor(black)
- term.setCursorPos(i - 1, y)
- term.write(" ")
- sleep(0.04)
- end
- for i = xB, xA, -1 do
- term.setCursorPos(i, y)
- term.setBackgroundColor(bgColor)
- term.write(" ")
- term.setBackgroundColor(black)
- term.setCursorPos(i + 1, y)
- term.write(" ")
- sleep(0.04)
- end
- end
- end
- local function waitingNet()
- local id, message, encKey, encryptedMessage, decryptedMessage, encodedMessage, success
- while true do
- if not gateLiaison then gateLiaison = rednet.lookup("ccDHDSetup") end
- if gateLiaison then
- dhdSettings.gate = gateLiaison
- while true do
- netSend(dhdSettings.gate, { program = "ccDHD", command = "1stRun" }, "ccDHDSetup")
- id, encodedMessage = rednet.receive("ccDHDSetup", 3)
- if id == dhdSettings.gate and type(encodedMessage) == "string" then
- success, encryptedMessage = pcall(decode, encodedMessage)
- if success then
- encKey = thisCC .. "ccDHD!General_Comms*Key" .. tostring(id)
- success, decryptedMessage = pcall(decrypt, encKey, encryptedMessage)
- if success then
- success, message = pcall(textutils.unserialize, decryptedMessage)
- if success and type(message) == "table" and message.program and message.program == "ccDHD" and message.thisGate then
- thisGate = message.thisGate
- return
- end
- end
- end
- end
- end
- else
- sleep(3)
- end
- end
- end
- if not term.isColor() or pocket or turtle then return startupError("hardware") end
- if termX ~= 51 or termY < 18 or termY > 19 then return startupError("resolution") end
- clearScreen()
- local firstRunNow = false
- if not fs.exists(settingsData) then --# First run
- if not fs.exists("/data") then fs.makeDir("/data") end
- if not os.getComputerLabel() then os.setComputerLabel("ccDHD.cc#" .. thisCC) end --# Check and, if necessary, set computer label
- firstRunNow = true
- term.setCursorPos(1, 1)
- term.write("ccDHD . . . First Run . . . Initializing . . .")
- detectHardware("modem", true)
- if hardware.wifiSide == "none" and hardware.modemSide == "none" then return startupError("firstRunModem") end
- term.clear()
- drawElement(2, 2, 1, 1, nil, nil, "Please start gateLiaison to complete setup.")
- drawElement(2, 4, 1, 1, nil, nil, "ccDHD will automatically start")
- drawElement(2, 5, 1, 1, nil, nil, "after gateLiaison is initialized.")
- drawElement(2, 7, 1, 1, gray, nil, "... waiting for gateLiaison ...")
- parallel.waitForAny(waitingNet, waitAnimation)
- dhdSettings.password = table.concat(pbkdf2(dhdSettings.password, "ccDHD!Pass.Hash", 15))
- dhdSettings.irisPassword = table.concat(pbkdf2(dhdSettings.irisPassword, "ccDHD!Pass.Hash", 15))
- dhdSettings.hashedPWs, dhdSettings.newHash = true, true
- saveData(settingsData, "cfg")
- clearScreen()
- else
- ingestData(settingsData, "cfg")
- end
- if not dhdSettings.newHash then
- local lockPW, irisPW
- drawElement(2, 2, 1, 1, red, nil, "ccDHD PASSWORD UPGRADE")
- drawElement(2, 4, 1, 1, white, nil, "Please enter the LOCKDOWN password:")
- while true do
- term.setCursorPos(38, 4)
- lockPW = read("*", nil, 12, nil, true)
- if table.concat(pbkdf2(lockPW, "ccDHD!pSync", 15)) == dhdSettings.password then
- dhdSettings.password = table.concat(pbkdf2(lockPW, "ccDHD!Pass.Hash", 15))
- break
- end
- end
- drawElement(2, 6, 1, 1, nil, nil, "Please enter the IRIS password:")
- while true do
- term.setCursorPos(34, 6)
- irisPW = read("*", nil, 12, nil, true)
- if table.concat(pbkdf2(irisPW, "ccDHD!pSync", 15)) == dhdSettings.irisPassword then
- dhdSettings.irisPassword = table.concat(pbkdf2(irisPW, "ccDHD!Pass.Hash", 15))
- break
- end
- end
- dhdSettings.newHash = true
- saveData(settingsData, "cfg")
- clearScreen()
- end
- ccLabel = os.getComputerLabel():sub(1, 15)
- drawElement(15, 4, 22, 1, white, blue, "ccDHD Initializing")
- drawElement(15, 5, 22, 10, nil, gray)
- local initSteps = {
- "Hardware Discovery";
- "Monitors";
- "Biometric Scanner"; --# Make this config data and move to top once bio is removed?
- "Modem/Network";
- "Query gateLiaison";
- "Await Response";
- "Host Sync";
- "Load address book";
- }
- for i = 6, 13 do
- drawElement(16, i, 1, 1, red, nil, "0")
- drawElement(18, i, 1, 1, silver, nil, initSteps[i - 5])
- end
- if tArgs[1] then
- local validSides = { left = true, right = true, top = true, bottom = true, front = true, back = true }
- for i = 1, #tArgs do
- if tArgs[i] == "outgoing" then
- outgoingAlarm = true
- elseif validSides[tArgs[i]] then
- rsSide = tArgs[i]
- end
- end
- end
- drawElement(18, 6, 1, 1, white, nil, "Hardware Discovery")
- drawElement(18, 7, 1, 1, nil, nil, "Monitors")
- drawElement(16, 6, 1, 1, orange, nil, "0") --# Hardware Discovery
- drawElement(16, 7, 1, 1, nil, nil, "0") --# Monitors
- detectHardware("mon")
- if hardware.listMon > 0 or hardware.marquee > 0 or hardware.gateMon > 0 then
- drawElement(16, 7, 1, 1, green, nil, "O") --# Monitors
- else
- drawElement(16, 7, 1, 1, red, nil, "0")
- end
- if hardware.listMon > 0 then
- for i = 1, hardware.listMon do
- listMon[i].setBackgroundColor(white)
- listMon[i].setTextColor(black)
- listMon[i].clear()
- listMon[i].setTextScale(1)
- listMon[i].setCursorPos(1, 3)
- listMon[i].write("Init...")
- end
- end
- if hardware.timerMon > 0 then
- for i = 1, hardware.timerMon do
- timerMon[i].setBackgroundColor(white)
- timerMon[i].setTextColor(black)
- timerMon[i].clear()
- timerMon[i].setCursorPos(2, 1)
- timerMon[i].write("ccDHD")
- timerMon[i].setCursorPos(1, 2)
- timerMon[i].write("Init...")
- end
- end
- if hardware.marquee > 0 then
- for i = 1, hardware.marquee do
- marquee[i].setBackgroundColor(white)
- marquee[i].setTextColor(black)
- marquee[i].clear()
- marquee[i].setTextScale(2)
- marquee[i].setCursorPos(5, 1)
- marquee[i].write("ccDHD")
- marquee[i].setCursorPos(2, 2)
- marquee[i].write("Initializing")
- end
- end
- if hardware.gateMon > 0 then
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(white)
- gateMon[i].setTextColor(black)
- gateMon[i].clear()
- gateMon[i].setTextScale(2)
- gateMon[i].setCursorPos(5, 1)
- gateMon[i].write("ccDHD")
- gateMon[i].setCursorPos(2, 2)
- gateMon[i].write("Initializing")
- end
- end
- drawElement(16, 8, 1, 1, orange, nil, "0") --# Biolocks
- drawElement(18, 8, 1, 1, white, nil, "Biometric Scanner")
- detectHardware("bio")
- drawElement(18, 9, 1, 1, white, nil, "Modem/Network")
- if firstRunNow then
- drawElement(16, 6, 1, 1, green, nil, "O") --# Hardware Discovery complete
- drawElement(16, 9, 1, 1, nil, nil, "O") --# Modem/Network
- else
- detectHardware("modem")
- if hardware.wifiSide == "none" and hardware.modemSide == "none" then
- clearMonitors()
- return startupError("modem")
- else
- drawElement(16, 6, 1, 1, green, gray, "O") --# Hardware Discovery complete
- drawElement(16, 9, 1, 1, nil, nil, "O") --# Modem/Network
- end
- end
- if hardware.wifiSide == "none" then dhdSettings.sync = false end
- drawElement(16, 10, 1, 1, orange, nil, "0") --# Query gateLiaison
- drawElement(18, 10, 1, 1, white, nil, "Query gateLiaison")
- netSend(dhdSettings.gate, { program = "ccDHD", command = "QRY" })
- drawElement(16, 10, 1, 1, green, nil, "O") --# Query gateLiaison
- drawElement(16, 11, 1, 1, orange, nil, "0") --# Await response
- drawElement(18, 11, 1, 1, white, nil, "Await response")
- local missed, id, message, encryptedMessage, decryptedMessage, encodedMessage, encKey, success = 0
- while true do
- id, encodedMessage = rednet.receive("ccDHD", 1)
- if id == dhdSettings.gate and type(encodedMessage) == "string" then
- success, encryptedMessage = pcall(decode, encodedMessage)
- if success then
- encKey = thisCC .. "ccDHD!General_Comms*Key" .. tostring(id)
- success, decryptedMessage = pcall(decrypt, encKey, encryptedMessage)
- if success then
- success, message = pcall(textutils.unserialize, decryptedMessage)
- if success and type(message) == "table" then
- updateStatus(message)
- drawElement(16, 11, 1, 1, green, nil, "O") --# Await response
- break
- end
- end
- end
- end
- missed = missed + 1
- if missed > 9 then
- clearMonitors()
- clearScreen()
- if hardware.modemSide ~= "none" and rednet.isOpen(hardware.modemSide) then rednet.close(hardware.modemSide) end
- if hardware.wifiSide ~= "none" and rednet.isOpen(hardware.wifiSide) then rednet.close(hardware.wifiSide) end
- drawElement(2, 2, 1, 1, red, nil, "Unable to syncronize with gateLiaison")
- term.setCursorPos(1, 4)
- return
- end
- netSend(dhdSettings.gate, { program = "ccDHD", command = "QRY" })
- end
- drawElement(18, 12, 1, 1, white, nil, "Host Sync")
- if dhdSettings.sync then
- drawElement(16, 12, 1, 1, orange, nil, "0") --# Host Sync
- rednet.host("ccDialerWiFi", thisGate)
- drawElement(16, 12, 1, 1, green, nil, "O") --# Host Sync
- else
- drawElement(16, 12, 1, 1, red, nil, "0") --# Host Sync
- end
- drawElement(16, 13, 1, 1, orange, nil, "0") --# Load address book
- drawElement(18, 13, 1, 1, white, nil, "Load address book")
- if fs.exists(gateData) then
- ingestData(gateData, "gate")
- else
- addressBook[1].name, addressBook[1].addr = thisGate, thisGate
- saveData(gateData, "gate")
- end
- drawElement(16, 13, 1, 1, green, nil, "O") --# Load address book
- os.pullEvent = os.pullEventRaw
- clearMonitors()
- if hardware.bio > 0 and dhdSettings.bio.lock then --# Bioscanner login
- clearScreen()
- drawElement(2, 2, 1, 1, orange, nil, "Waiting for Bioscan")
- if hardware.listMon > 0 then
- for i = 1, hardware.listMon do
- listMon[i].setTextColor(blue)
- listMon[i].setCursorPos(1, 2)
- listMon[i].write("Waiting")
- listMon[i].setCursorPos(3, 3)
- listMon[i].write("for")
- listMon[i].setCursorPos(1, 4)
- listMon[i].write("Bioscan")
- end
- end
- parallel.waitForAny(inputBioScan, waitAnimation)
- end
- validStates = { --# [1] = lockdown, [2] = clear lockdown, [3] = drawCLI, [4] = userInput, [5] = update screen during gate/iris activity
- Dial = { "Dial", function() end, function() drawFullHeader(true) drawAddressBook() drawControlUI() drawNaviUI() end, function() inputDial() end, true };
- remotePass = { "Dial", function() end, function() drawSubheader() drawAddressBook() drawControlUI() if gateChange then drawNaviUI() end drawPopUp() end, function() inputRemotePassword() end, true };
- goPage = { "Dial", function() end, function() drawSubheader() drawAddressBook() drawControlUI() if gateChange then drawNaviUI() end drawPopUp() end, function() inputGoToPage() end, true };
- importExport = { "Dial", function() end, function() drawSubheader() drawAddressBook() drawControlUI() if gateChange then drawNaviUI() end drawPopUp() end, function () inputImportExportPopUp() end, true };
- exodus = { "Dial", function() end, function() drawSubheader() drawAddressBook() drawControlUI() if gateChange then drawNaviUI() end drawPopUp() end, function() inputSaveAndQuitPopUp() end, true };
- GateEdit = { "GateEdit", function() drawGateLabels() end, function() drawSubheader() end, function() inputEditGateEntry() end, true }; --# draw subheader for incoming/outgoing calls
- DHDhelp = { "DHDhelp", function() drawHelpScreen() end, function() end, function() inputHelp() end, false };
- DHDsettings = { "DHDsettings", function() drawSettingsScreen() end, function() end, function () inputSettings() end, false };
- newPassword = { "DHDsettings", function() end, function() end, function () inputSelectPassword() end, false };
- newLockPass = { "DHDsettings", function() end, function() end, function () inputChangeLockdownPassword() end, false };
- newIrisPass = { "DHDsettings", function() end, function() end, function () inputChangeIrisPassword() end, false };
- logs = { "logs", function() drawLogHeader() end, function() end, function() inputLogs() end, false };
- clearLogs = { "logs", function() end, function() end, function() inputClearLogsPopUp() end, false };
- goLogPage = { "logs", function() end, function() end, function() inputGoToLogPage() end, false };
- }
- if hardware.listMon > 0 then
- for i = 1, hardware.listMon do
- listMon[i].setTextScale(0.5)
- end
- end
- if hardware.gateMon > 0 then
- for i = 1, hardware.gateMon do
- gateMon[i].setTextScale(1)
- end
- end
- kernelState = true
- runState = "Dial"
- displayConnectionTime()
- displayGate()
- clearScreen()
- drawCLI(true, true)
- pingTimer = os.startTimer(5)
- if gateStatus == "Connected" then connectionTimer = os.startTimer(0.1) end
- repeat
- parallel.waitForAny(userInput, inputMonTouch, inputBioScan, netReceive, syncReceive, dataPoller)
- until not kernelState
Add Comment
Please, Sign In to add comment