Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[ LanteaCraft ]]--
- --[[ and SGCraft ]]--
- --[[ Gate Liaison ]]--
- --[[ by Dog ]]--
- --[[ aka HydrantHunter ]]--
- --[[ with help from ]]--
- --[[ AfterLifeLochie ]]--
- --[[ pastebin NZrxstWF ]]--
- local glVer = "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: 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
- ]]--
- --# AUTOMATIC/STATIC CONFIGURATION (Part 1)
- local tArgs, marquee, gateMon, timerMon = { ... }, { }, { }, { }
- local hardware = { marquee = 0, gateMon = 0, timerMon = 0 }
- local modem, gate, thisGate, incomingAddress, fuelPercent, updateTimer, connectionTimer, ccLabel, netSend, netReceive, updateClientAndScreens, updatePercentages, lockChevron, hangUp, displayChevrons, displayStatus, drawElement
- local lcGate, noMon, outgoingAlarm, irisState, waitingForIris, wifiComms, staticDrawn, bAndW, autoDisengage, dialFromDHD, continueDialing, gateDiscon, spinTime = false, false, false, false, false, false, false, false, false, false, false, false, false
- local grayScale, fullColor, thisCC = (_CC_VERSION or _HOST), term.isColor(), tostring(os.getComputerID())
- local connectionClock, gateStatus, irisStatus, secureStatus, modemSide, dialAddress, callDirection, rsSide = "00:00:0", "QRY", "QRY", "allclear", "none", "none", "none", "none"
- local irisPercent, chevronNumber, connectionTime, sgRemoteAddrLen, MAXFUEL_LC, MAXFUEL_SG = 0, 0, 0, 0, 100, 200000
- local gateSettings = { DHD = 99999999 }
- local sgStates = {
- Idle = "Idle";
- Dialing = "Dialing";
- Dialling = "Dialing";
- Opening = "Dialing";
- Connected = "Connected";
- Closing = "Disconnecting";
- Offline = "Offline";
- }
- --# Color Definitions (color terminal, b&w terminal, color monitors)
- 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
- if not fullColor then
- silver = grayScale and colors.lightGray or colors.white
- gray = grayScale and colors.gray or colors.black
- --brown = colors.white
- yellow = colors.white
- orange = colors.white
- red = colors.white
- --magenta = colors.white
- --purple = colors.white
- blue = colors.black
- sky = colors.white
- cyan = colors.white
- --lime = colors.white
- green = colors.white
- end
- local mwhite = colors.white
- local msilver = colors.lightGray
- local mgray = colors.gray
- local mblack = colors.black
- --local mbrown = colors.brown
- local myellow = colors.yellow
- local morange = colors.orange
- local mred = colors.red
- --local mmagenta = colors.magenta
- --local mpurple = colors.purple
- local mblue = colors.blue
- local msky = colors.lightBlue
- local mcyan = colors.cyan
- --local mlime = colors.lime
- local mgreen = colors.green
- --# END AUTOMATIC/STATIC CONFIGURATION (Part 1)
- -- 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
- -- http://pastebin.com/DMx8M0LP
- 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
- local function getFuelLevel()
- return (lcGate and math.min(100, math.floor((100 / MAXFUEL_LC) * 100)) or math.min(100, math.floor((gate.energyAvailable() / MAXFUEL_SG) * 100)))
- end
- do
- local function irisControl(state) --# LanteaCraft & SGCraft
- if irisStatus ~= "Offline" then
- if lcGate then
- if state then
- pcall(gate.closeIris)
- else
- pcall(gate.openIris)
- end
- waitingForIris = true --# this could be all wrong...without verification there's no way to know what the iris is actually doing
- else
- if state then
- waitingForIris = gate.closeIris()
- else
- waitingForIris = gate.openIris()
- end
- end
- end
- end
- local actions = {
- lockdown = function()
- secureStatus = "lockdown"
- irisControl(true)
- hangUp()
- updateClientAndScreens(true)
- end;
- allclear = function()
- secureStatus = "allclear"
- irisControl(false)
- updateClientAndScreens(true)
- end;
- QRY = function()
- updatePercentages()
- end;
- dialPause = function(_lcGate) --# LanteaCraft
- if _lcGate then
- if gateStatus == "Dialing" then
- continueDialing = false
- gateStatus = "Paused"
- elseif gateStatus == "Paused" then
- continueDialing = true
- if lockChevron(chevronNumber + 1) then
- gateStatus = "Dialing"
- else
- continueDialing = false
- end
- end
- displayStatus("pause")
- updateClientAndScreens()
- end
- end;
- endCall = function()
- hangUp()
- end;
- iCLOSE = function()
- irisControl(true)
- end;
- iOPEN = function(_, _secureStatus)
- if _secureStatus == "allclear" then irisControl(false) end
- end;
- }
- netReceive = function()
- local id, message, encKey, encryptedMessage, decryptedMessage, encodedMessage, success, dataPack, thisCommand, tcLen, dialGate
- while true do
- if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
- id, encodedMessage = rednet.receive("ccDHD")
- if id == gateSettings.DHD 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" and message.command then
- thisCommand = message.command
- if actions[thisCommand] then
- actions[thisCommand](lcGate, secureStatus)
- else
- tcLen = #thisCommand
- if (tcLen == 7 or tcLen == 9) and gateStatus == "Idle" and secureStatus == "allclear" then
- dialGate = false
- dialAddress = thisCommand
- if lcGate then
- continueDialing = true
- dialGate = lockChevron(1)
- if dialGate then
- gateStatus = "Dialing"
- callDirection = "Outgoing"
- displayStatus("dial")
- else
- hangUp()
- end
- else
- dialGate = gate.dial(dialAddress)
- end
- if not dialGate then dialAddress = "none" end
- updatePercentages()
- end
- end
- elseif message.program == "ccDialer" and message.password and gateStatus == "Connected" then
- dataPack = textutils.serialize({ password = message.password })
- pcall(gate.sendMessage, dataPack)
- end
- end
- end
- end
- end
- end
- end
- end
- netSend = function(protocol)
- local dataPack = textutils.serialize({
- program = "ccDHD";
- thisGate = thisGate;
- fuelPercent = fuelPercent;
- gateStatus = gateStatus;
- secureStatus = secureStatus;
- callDirection = callDirection;
- dialAddress = dialAddress;
- incomingAddress = incomingAddress;
- chevronNumber = chevronNumber;
- sgRemoteAddrLen = sgRemoteAddrLen;
- irisState = irisState;
- irisStatus = irisStatus;
- irisPercent = irisPercent;
- waitingForIris = waitingForIris;
- lcGate = lcGate;
- })
- if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
- if gateSettings.DHD ~= 99999999 then
- local encKey = tostring(gateSettings.DHD) .. "ccDHD!General_Comms*Key" .. thisCC
- local encryptedDataPack = encode(encrypt(encKey, dataPack))
- rednet.send(gateSettings.DHD, encryptedDataPack, protocol or "ccDHD")
- end
- end
- local function quickSend(dataPack)
- if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
- if gateSettings.DHD ~= 99999999 then
- local encKey = tostring(gateSettings.DHD) .. "ccDHD!General_Comms*Key" .. thisCC
- local encryptedDataPack = encode(encrypt(encKey, textutils.serialize({ program = "ccDialer", data = dataPack })))
- rednet.send(gateSettings.DHD, encryptedDataPack, "ccDHD")
- end
- end
- local function gateReceive() --# LanteaCraft & SGCraft
- local _, src, message, success, data
- while true do
- if lcGate then
- _, message = os.pullEvent("receive")
- else
- _, src, message = os.pullEvent("sgMessageReceived")
- end
- success, data = pcall(textutils.unserialize, message)
- if success and type(data) == "table" then
- if data.password or data.irisState then
- quickSend(data.password and data.password or data.irisState)
- 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 = gateStatus == "Connected" and mblue or mblack
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(bgColor)
- for j = 1, 12 do
- gateMon[i].setCursorPos(wormhole[j].x, wormhole[j].y)
- gateMon[i].write(wormhole[j].line)
- end
- end
- end
- local function displayGlyph(i, chevron, addrLen, backSpace)
- if addrLen == 7 or addrLen == 9 or backSpace then
- if lcGate then
- gateMon[i].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
- gateMon[i].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
- gateMon[i].write(" ")
- else
- gateMon[i].write(incomingAddress and incomingAddress:sub(chevron, chevron) or dialAddress:sub(chevron, chevron))
- end
- end
- end
- displayChevrons = function(init, backSpace)
- if not gateMon[1] or (bAndW and not grayScale) then return end
- local gm
- if gateStatus == "Idle" then
- if not init then
- for i = 1, hardware.gateMon do
- gm = gateMon[i]
- gm.setBackgroundColor(msilver)
- 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(morange)
- gateMon[i].setTextColor(mblack)
- for j = 1, addrLen 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(msilver)
- for j = 1, 9 do
- gm.setCursorPos(chevrons9LC[j].x, chevrons9LC[j].y)
- gm.write(" ")
- end
- gm.setBackgroundColor(morange)
- gm.setTextColor(mblack)
- for j = 1, addrLen 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(msilver)
- 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(morange)
- gateMon[i].setTextColor(mblack)
- 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 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(state)
- if not marquee[1] then return end
- if state == "idle" then
- if secureStatus == "allclear" then --# Display the local address when there is no other information to display
- local longAddress, tmpX = makeLongName(thisGate), #thisGate - 5
- for i = 1, hardware.marquee do
- marquee[i].clear()
- marquee[i].setCursorPos(1, 1)
- marquee[i].setTextColor(mcyan)
- marquee[i].write("Stargate")
- marquee[i].setTextColor(myellow)
- marquee[i].setCursorPos(tmpX, 2)
- marquee[i].write(longAddress)
- end
- else
- for i = 1, hardware.marquee do
- marquee[i].clear()
- marquee[i].setCursorPos(1, 1)
- marquee[i].setTextColor(mred)
- marquee[i].write("!! LOCKDOWN !!")
- end
- end
- elseif state == "dial" or (state == "con" and not incomingAddress) then
- local longAddress, tmpX = makeLongName(dialAddress), #dialAddress - 5
- for i = 1, hardware.marquee do
- marquee[i].setCursorPos(1, 1)
- marquee[i].setTextColor(msky)
- if state == "dial" then
- marquee[i].write("Dialing ")
- marquee[i].setTextColor(mgray)
- elseif state == "con" then
- marquee[i].write(dialAddress == "none" and "Connected" or "Connected to")
- marquee[i].setTextColor(myellow)
- end
- if dialAddress ~= "none" then
- marquee[i].setCursorPos(tmpX, 2)
- marquee[i].write(longAddress)
- end
- end
- elseif state == "incoming" or (state == "con" and incomingAddress) then
- local longAddress = makeLongName(incomingAddress)
- local iaLen = #incomingAddress
- local sBuffer, iaX = string.rep(" ", 9 - iaLen), iaLen - 5
- for i = 1, hardware.marquee do
- marquee[i].setTextColor(secureStatus == "allclear" and msky or mred)
- marquee[i].setCursorPos(1, 1)
- marquee[i].write(incomingAddress == "Wormhole" and "Incoming " or "Incoming from ")
- marquee[i].setTextColor(secureStatus == "allclear" and myellow or morange)
- if gateStatus == "Dialing" then
- if lcGate then
- marquee[i].setCursorPos(4, 2)
- marquee[i].write(incomingAddress .. sBuffer)
- else
- marquee[i].setCursorPos(iaX, 2)
- if iaLen == 7 then
- marquee[i].write(longAddress:sub(1, chevronNumber * 2))
- marquee[i].setTextColor(mgray)
- marquee[i].write(longAddress:sub((chevronNumber * 2) + 1))
- else
- marquee[i].write(incomingAddress:sub(1, chevronNumber))
- marquee[i].setTextColor(mgray)
- marquee[i].write(incomingAddress:sub(chevronNumber + 1))
- end
- end
- else
- marquee[i].setCursorPos(iaX, 2)
- marquee[i].write(longAddress)
- end
- end
- elseif state == "outgoing" then
- local longAddress, daLen = makeLongName(dialAddress), #dialAddress
- local daX = daLen - 5
- for i = 1, hardware.marquee do
- marquee[i].setCursorPos(daX, 2)
- marquee[i].setTextColor(myellow)
- if daLen == 7 then
- marquee[i].write(longAddress:sub(1, chevronNumber * 2))
- else
- marquee[i].write(dialAddress:sub(1, chevronNumber))
- end
- end
- elseif state == "pause" then
- if gateStatus == "Dialing" or gateStatus == "Paused" then
- for i = 1, hardware.marquee do
- marquee[i].setCursorPos(1, 1)
- marquee[i].setTextColor(msky)
- marquee[i].write(gateStatus == "Dialing" and "Dialing " or "Paused ")
- end
- end
- elseif state == "discon" then
- for i = 1, hardware.marquee do
- marquee[i].clear()
- marquee[i].setCursorPos(1, 1)
- marquee[i].setTextColor(msky)
- marquee[i].write(gateStatus)
- end
- end
- end
- end
- local function displayConnectionTime()
- drawElement(30, 4, 9, 1, white, black, connectionClock)
- 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 mgreen or mgray)
- timerMon[i].write("Connect")
- end
- timerMon[i].setCursorPos(1, 2)
- timerMon[i].setTextColor(connectionTime > 0 and mwhite or mgray)
- timerMon[i].write(connectionClock)
- end
- end
- do
- local termX, termY = term.getSize()
- local validColors = { }
- if fullColor then
- 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; }
- elseif grayScale then
- validColors = { [1] = true; [128] = true; [256] = true; [32768] = true; }
- else
- validColors = { [1] = true; [32768] = true; }
- end
- drawElement = function(x, y, w, h, txtColor, bgColor, text)
- if type(x) == "number" and type(y) == "number" and type(w) == "number" and type(h) == "number" then
- 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, txtRow = 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 == txtRow and txtLine or line) --# Draw 1 of h lines of the 'element' (box/rectangle/line-seg)
- end
- end
- end
- end
- end
- updateClientAndScreens = function(updateMonitors, init)
- netSend()
- if updateMonitors then
- if gateStatus == "Idle" then
- displayStatus("idle")
- elseif gateStatus == "Connected" then
- displayStatus("con")
- elseif gateStatus == "Dialing" then
- displayStatus(incomingAddress and "incoming" or (chevronNumber > 0 and "outgoing" or "dial")) --# incoming or outgoing
- elseif gateStatus == "Paused" then
- displayStatus("pause")
- elseif gateStatus == "Disconnecting" then
- displayStatus("discon")
- end
- displayChevrons(init)
- end
- --# terminal screen
- local txtColor, bgColor = fullColor and white or black, fullColor and blue or white --# Set the header color
- --# Static entries
- if not staticDrawn then
- --# Header/Footer
- local glHeaderTxt = "Gate Liaison ver. " .. glVer
- drawElement(2, 2, 37, 1, txtColor, bgColor, glHeaderTxt) --# Header
- drawElement(2, 10, 37, 1) --# Footer
- drawElement(3, 10, 1, 1, nil, nil, ccLabel) --# Lowline
- local ccID = "cc# " .. thisCC
- drawElement(38 - #ccID, 10, 1, 1, nil, nil, ccID)
- --# Body
- drawElement(2, 3, 12, 7, nil, silver) --# Labels' background
- local readouts = { " This Gate:", " State:", " Target:", " Iris:", " Fuel:", " Status:", " Network:" }
- for i = 1, 7 do
- drawElement(2, i + 2, 1, 1, black, nil, readouts[i])
- end
- drawElement(17, 9, 1, 1, silver, black, modemSide)
- drawElement(24, 9, 1, 1, fullColor and (wifiComms and orange or green) or white, nil, wifiComms and "(WiFi)" or "(Wired)")
- drawElement(32, 9, 1, 1, (fullColor or grayScale) and gray or white, nil, "(" .. tostring(gateSettings.DHD) .. ")")
- staticDrawn = true
- end
- --# Dynamic entries
- drawElement(17, 3, 1, 1, secureStatus == "allclear" and yellow or red, nil, secureStatus == "allclear" and thisGate .. " " or "!! LOCKDOWN !!")
- txtColor = white
- if gateStatus == "Idle" then
- txtColor = green
- elseif gateStatus == "Connected" then
- txtColor = orange
- elseif gateStatus == "Dialing" or gateStatus == "Paused" or gateStatus == "Disconnecting" then
- txtColor = sky
- end
- if gateStatus == "Dialing" and dialAddress == "none" and callDirection == "Incoming" then
- drawElement(17, 4, 1, 1, txtColor, black, incomingAddress and "Incoming " or "Incoming Wormhole")
- else
- drawElement(17, 4, 13, 1, nil, black) --# clear gateStatus line (so lingering characters are removed and the connection timer isn't overwritten by adding string.rep to the output line)
- drawElement(17, 4, 1, 1, txtColor, nil, gateStatus)
- end
- drawElement(30, 4, 9, 1, white, nil, connectionClock) --# connection timer
- drawElement(17, 5, 1, 1, fullColor and gray or white, nil, incomingAddress and incomingAddress .. string.rep(" ", 9 - #incomingAddress) or dialAddress .. string.rep(" ", 9 - #dialAddress))
- if (incomingAddress or dialAddress ~= "none") and chevronNumber > 0 and gateStatus ~= "Connected" then
- drawElement(17, 5, 1, 1, yellow, nil, incomingAddress and incomingAddress:sub(1, chevronNumber) or dialAddress:sub(1, chevronNumber))
- elseif (incomingAddress or dialAddress ~= "none") and gateStatus == "Connected" then
- drawElement(17, 5, 1, 1, yellow, nil, incomingAddress or dialAddress)
- end
- drawElement(17, 6, 1, 1, irisState and green or orange, nil, irisStatus .. " ")
- if lcGate then
- local irisColor = irisPercent > 49 and green or orange
- irisColor = irisPercent < 25 and red or irisColor
- drawElement(25, 6, 1, 1, irisColor, nil, tostring(irisPercent))
- end
- term.setTextColor(silver)
- term.write(waitingForIris and (lcGate and "% (waiting) " or " (waiting) ") or (lcGate and "% " or " "))
- local fuelColor = fuelPercent > 24 and green or orange
- fuelColor = fuelPercent < 6 and red or fuelColor
- drawElement(17, 7, 1, 1, fuelColor, nil, tostring(fuelPercent))
- term.setTextColor(silver)
- term.write("% ")
- drawElement(17, 8, 1, 1, secureStatus == "allclear" and green or red, nil, secureStatus)
- end
- updatePercentages = function(updateMonitors, init)
- if updateTimer then os.cancelTimer(updateTimer) updateTimer = os.startTimer(5) end
- fuelPercent = getFuelLevel()
- if lcGate and irisStatus ~= "Offline" then irisPercent = gate.getIrisHealth() end
- updateClientAndScreens(updateMonitors, init)
- end
- local function recordSessionData() --# Human readable log files (last call)
- local logAddress = incomingAddress or dialAddress
- logAddress = logAddress == "Wormhole" and "N/A" or logAddress
- local callTime = textutils.formatTime(os.time(), false)
- local lastCall = fs.open("/data/gateLastCall", "w")
- lastCall.writeLine(tostring(os.day()) .. " @ " .. callTime .. " <" .. callDirection .. "> " .. logAddress)
- lastCall.close()
- end
- local function disengageChevron(auto) --# LanteaCraft
- if auto then autoDisengage = true end
- --local onHook = pcall(gate.deactivateChevron)
- --if onHook then gateStatus = "Disconnecting" end
- pcall(gate.deactivateChevron)
- if secureStatus == "allclear" then gateStatus = "Disconnecting" end
- end
- hangUp = function() --# LanteaCraft & SGCraft
- if gateStatus == "Idle" or gateStatus == "Disconnecting" then return end
- local onHook = false
- if lcGate then
- if gateStatus == "Connected" then
- --onHook = pcall(gate.disengageStargate)
- --if onHook then gateStatus = "Disconnecting" displayStatus("discon") end
- pcall(gate.disengageStargate)
- gateStatus = "Disconnecting" --# this might be a problem - if gate doesn't disconnect, hangUp won't be processed again due to gate status
- displayStatus("discon")
- if gate.getActivatedChevrons() > 0 then disengageChevron(true) end
- elseif gateStatus == "Dialing" or gateStatus == "Paused" then --# outgoing calls only?
- continueDialing = false
- while spinTime do
- os.queueEvent("spinWait")
- os.pullEvent("spinWait")
- end
- disengageChevron(true)
- if gateStatus == "Disconnecting" then displayStatus("discon") end
- end
- else
- onHook = gate.disconnect()
- if onHook then
- gateStatus = "Disconnecting"
- displayStatus("discon")
- end
- end
- updateClientAndScreens()
- end
- lockChevron = function(num) --# LanteaCraft
- --local dialGate = false
- if continueDialing then
- --dialGate = pcall(gate.selectGlyph, dialAddress:sub(num, num))
- --if not dialGate then return false end
- --dialGate = pcall(gate.activateChevron)
- pcall(gate.selectGlyph, dialAddress:sub(num, num))
- pcall(gate.activateChevron)
- end
- --return dialGate
- return true
- end
- local function lcIrisMonitor() --# LanteaCraft
- local event
- while true do
- event = os.pullEvent()
- if event == "irisOpened" or event == "irisOpening" or event == "irisDestroyed" or event == "irisClosed" or event == "irisClosing" then
- irisState = (event == "irisClosed" or event == "irisOpening")
- irisStatus = event ~= "irisOpened" and event:sub(5) or "Open"
- if irisStatus == "Destroyed" then irisStatus = "Offline" end
- waitingForIris = (irisStatus == "Opening" or irisStatus == "Closing")
- --irisPercent = gate.getIrisHealth()
- updateClientAndScreens()
- --[[
- if gateStatus == "Connected" then
- local iris = irisState and "closed" or "open"
- local dataPack = textutils.serialize({ irisState = iris })
- pcall(gate.sendMessage, dataPack)
- end
- ]]--
- end
- end
- end
- local function lcGateMonitor() --# LanteaCraft
- local event
- while true do
- event = os.pullEvent()
- if event == "spinToGlyph" then
- spinTime = true
- if rsSide ~= "none" and outgoingAlarm then rs.setOutput(rsSide, true) end
- elseif event == "disengageGlyph" then
- chevronNumber = chevronNumber - 1
- if secureStatus == "allclear" then
- if chevronNumber == 0 then
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end
- gateStatus = "Idle"
- gateStatus, autoDisengage, dialFromDHD = "Idle", false, false
- dialAddress, callDirection = "none", "none"
- incomingAddress = nil
- else
- if dialFromDHD then
- dialAddress = dialAddress:sub(1, chevronNumber) .. string.rep("?", 9 - chevronNumber)
- else
- dialAddress = dialAddress:sub(1, chevronNumber)
- end
- displayChevrons(nil, true)
- if autoDisengage then disengageChevron() end
- end
- updateClientAndScreens(true)
- else
- if chevronNumber > 0 then
- disengageChevron()
- end
- end
- elseif event == "connect" then
- gateStatus = "Connected"
- spinTime = false
- if dialAddress:find("?") then dialAddress = gate.getActivatedGlyphs() end
- if dialAddress == "none" then incomingAddress = "Wormhole" end
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end
- displayStatus("con")
- quickSend("Connected")
- sleep(0.02)
- updatePercentages(true)
- --local iris = irisState and "closed" or "open"
- --local dataPack = textutils.serialize({ irisState = iris })
- --pcall(gate.sendMessage, dataPack)
- recordSessionData()
- if callDirection == "Outgoing" then updateTimer = os.startTimer(5) end
- connectionTimer = os.startTimer(0.1)
- elseif event == "disconnect" then
- gateStatus, autoDisengage = "Idle", false
- dialAddress, callDirection = "none", "none"
- dialFromDHD, gateDiscon, incomingAddress = false, false, nil
- chevronNumber = 0
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end
- quickSend("Idle")
- sleep(0.02)
- if connectionTimer then os.cancelTimer(connectionTimer) connectionTimer = nil end
- connectionTime, connectionClock = 0, "00:00:0"
- updateClientAndScreens(true)
- displayConnectionTime()
- end
- end
- end
- local function sgIrisMonitor() --# SGCraft
- local event, _, oldState, iris
- while true do
- event, _, irisStatus, oldState = os.pullEvent("sgIrisStateChange")
- waitingForIris = (irisStatus == "Opening" or irisStatus == "Closing")
- if not waitingForIris then
- irisState = irisStatus == "Closed"
- end
- updateClientAndScreens()
- if gateStatus == "Connected" then
- iris = irisState and "closed" or "open"
- gate.sendMessage(textutils.serialize({ irisState = iris }))
- end
- end
- end
- local function sgGateMonitor() --# SGCraft
- local sgEvent, _, newState, oldState, iris
- while true do
- sgEvent, _, newState, oldState = os.pullEvent("sgStargateStateChange")
- gateStatus = sgStates[newState] or "Unknown"
- if gateStatus == "Idle" or gateStatus == "Offline" then
- callDirection, dialAddress = "none", "none"
- dialFromDHD, gateDiscon, incomingAddress = false, false, nil
- chevronNumber, sgRemoteAddrLen = 0, 0
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end
- quickSend("Idle")
- sleep(0.02)
- if connectionTimer then os.cancelTimer(connectionTimer) connectionTimer = nil end
- connectionTime, connectionClock = 0, "00:00:0"
- displayConnectionTime()
- elseif gateStatus == "Connected" then
- if dialAddress:find("?") then
- dialAddress = dialAddress:sub(1, dialAddress:find("?") - 1)
- end
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end
- displayStatus("con")
- updatePercentages(true)
- iris = irisState and "closed" or "open"
- gate.sendMessage(textutils.serialize({ irisState = iris }))
- quickSend("Connected")
- recordSessionData()
- if callDirection == "Outgoing" then updateTimer = os.startTimer(5) end
- connectionTimer = os.startTimer(0.1)
- if secureStatus == "lockdown" and callDirection == "Outgoing" then hangUp() end
- --elseif gateStatus == "Dialing" then
- --if rsSide ~= "none" then rs.setOutput(rsSide, true) end
- end
- if gateStatus ~= "Dialing" and gateStatus ~= "Connected" and gateStatus ~= "Unknown" then
- updateClientAndScreens(true)
- end
- end
- end
- local function lcChevronEncoder() --# LanteaCraft
- --local establishWormhole
- local daLen
- while true do
- os.pullEvent("engageGlyph")
- spinTime = false
- chevronNumber = chevronNumber + 1
- if secureStatus == "allclear" then
- gateStatus = "Dialing"
- if dialAddress:find("?") or (dialAddress == "none" and not incomingAddress) then --# watch for standard DHD activity
- dialAddress = gate.getActivatedGlyphs() .. string.rep("?", 9 - gate.getActivatedChevrons())
- dialFromDHD = true
- end
- if incomingAddress then
- callDirection = "Incoming"
- else
- callDirection = "Outgoing"
- --if updateTimer then os.cancel(updateTimer) end
- --updateTimer = os.startTimer(5)
- if dialAddress:find("?") and chevronNumber == 1 then
- displayStatus("dial")
- end
- --if gateStatus == "Dialing" and callDirection == "none" then callDirection = "Unknown" end
- daLen = #dialAddress
- if chevronNumber == daLen then --# all chevrons engaged, time to establish the wormhole
- continueDialing = false
- --establishWormhole = pcall(gate.engageStargate)
- --if not establishWormhole then hangUp() end
- pcall(gate.engageStargate)
- elseif chevronNumber < daLen then --# engage the next chevron
- if continueDialing and not lockChevron(chevronNumber + 1) then
- continueDialing = false
- gateStatus = "Paused"
- end
- end
- end
- quickSend(gateStatus == "Dialing" and "Dialing" or "Paused")
- sleep(0.02)
- updateClientAndScreens(true)
- else
- disengageChevron()
- end
- end
- end
- local function sgChevronUnencoded() --# SGCraft
- local sgEvent, _
- while true do
- sgEvent, _, chevronNumber = os.pullEvent("sgChevronUnset")
- if gateStatus == "Dialing" then
- if chevronNumber == 0 then
- dialAddress, callDirection, gateStatus, dialFromDHD, gateDiscon = "none", "none", "Idle", false, false
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end
- else
- dialAddress = dialAddress:sub(1, chevronNumber) .. string.rep("?", 9 - chevronNumber)
- end
- updateClientAndScreens()
- displayChevrons(nil, true)
- end
- end
- end
- local function sgChevronEncoder() --# SGCraft
- local sgEvent, _, chevron
- while true do
- sgEvent, _, chevronNumber, chevron = os.pullEvent("sgChevronEngaged")
- gateStatus = "Dialing"
- if incomingAddress then
- displayStatus("incoming")
- else
- if dialAddress:find("?") then
- dialAddress = dialAddress:sub(1, chevronNumber - 1) .. chevron .. string.rep("?", 9 - chevronNumber)
- if disconTimer then os.cancelTimer(disconTimer) end
- disconTimer = os.startTimer(3)
- elseif dialAddress == "none" then --# watch for standard DHD activity
- dialAddress = chevron .. "????????"
- callDirection = "Outgoing"
- dialFromDHD = true
- displayStatus("dial")
- if rsSide ~= "none" then rs.setOutput(rsSide, true) end
- if disconTimer then os.cancelTimer(disconTimer) end
- disconTimer = os.startTimer(3)
- end
- displayStatus("outgoing")
- end
- updateClientAndScreens()
- displayChevrons()
- end
- end
- local function outgoingCall() --# SGCraft
- local _, sgEvent, outgoingAddress
- while true do
- sgEvent, _, outgoingAddress = os.pullEvent("sgDialOut")
- sgRemoteAddrLen = #outgoingAddress
- if dialAddress == "none" then dialAddress = outgoingAddress end
- gateStatus = "Dialing"
- callDirection = "Outgoing"
- if rsSide ~= "none" and outgoingAlarm then rs.setOutput(rsSide, true) end
- quickSend("Dialing")
- sleep(0.02)
- updateClientAndScreens(true)
- end
- end
- local function incomingCall() --# SGCraft
- local _, sgEvent
- while true do
- sgEvent, _, incomingAddress = os.pullEvent("sgDialIn")
- sgRemoteAddrLen = #incomingAddress --# get the 'native' address length
- incomingAddress = gate.remoteAddress() --# get the full, 9 symbol address if available
- gateStatus = "Dialing"
- callDirection = "Incoming"
- if rsSide ~= "none" then rs.setOutput(rsSide, true) end
- quickSend("Dialing")
- sleep(0.02)
- updateClientAndScreens(true)
- end
- end
- local function charInput()
- local _, char
- while true do
- _, char = os.pullEvent("char")
- if string.lower(char) == "q" then
- if rednet.isOpen(modemSide) then rednet.close(modemSide) end
- if marquee[1] then
- for i = 1, hardware.marquee do
- marquee[i].clear()
- end
- end
- if gateMon[1] then
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(mblack)
- gateMon[i].clear()
- end
- end
- if timerMon[1] then
- for i = 1, hardware.timerMon do
- timerMon[i].clear()
- end
- end
- term.setBackgroundColor(black)
- term.clear()
- drawElement(1, 1, 1, 1, white, nil, "gateLiaison is OFFLINE")
- term.setCursorPos(1, 3)
- return
- end
- end
- end
- local function dataPoller()
- local _, timer, newFuel, newIris, update, monUpdate, hours, minutes, seconds, sMinutes, sSeconds, sTenths
- while true do
- _, timer = os.pullEvent("timer")
- update, monUpdate = false, false
- if timer == updateTimer then
- newFuel = getFuelLevel()
- update = newFuel ~= fuelPercent
- fuelPercent = newFuel
- if lcGate and irisStatus ~= "Offline" then
- newIris = gate.getIrisHealth()
- if newIris ~= irisPercent then update = true end
- irisPercent = newIris
- end
- if gateStatus == "Connected" and callDirection == "Outgoing" then updateTimer = os.startTimer(5) else updateTimer = nil end
- elseif timer == disconTimer then
- if gateStatus == "Disconnecting" and gateDiscon then
- gateStatus = "Idle"
- dialAddress, callDirection = "none", "none"
- update, monUpdate, gateDiscon, dialFromDHD, disconTimer = true, true, false, false, nil
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end
- elseif gateStatus == "Disconnecting" and not gateDiscon then
- gateDiscon = true
- end
- if dialAddress:find("?") then disconTimer = os.startTimer(3) end
- elseif timer == connectionTimer then
- connectionTime = connectionTime + 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()
- if gateStatus == "Connected" then connectionTimer = os.startTimer(0.1) else connectionTimer = nil end
- end
- if update then updateClientAndScreens(monUpdate) end
- end
- end
- --# AUTOMATIC/STATIC CONFIGURATION (Part 2)
- local function waitingAnimation() --# intentionally not using drawELement - more efficient
- while true do
- for i = 5, 21 do
- term.setCursorPos(i, 11)
- term.setBackgroundColor(cyan)
- term.write(" ")
- term.setBackgroundColor(black)
- term.setCursorPos(i - 1, 11)
- term.write(" ")
- sleep(0.04)
- end
- for i = 21, 5, -1 do
- term.setCursorPos(i, 11)
- term.setBackgroundColor(cyan)
- term.write(" ")
- term.setBackgroundColor(black)
- term.setCursorPos(i + 1, 11)
- term.write(" ")
- sleep(0.04)
- end
- end
- end
- local function waitingNet()
- local id, message, encKey, encodedMessage, encryptedMessage, decryptedMessage, success
- while true do
- id, encodedMessage = rednet.receive("ccDHDSetup")
- if 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 == "ccDHD" and message.command == "1stRun" then
- gateSettings.DHD = id
- netSend("ccDHDSetup")
- rednet.unhost("ccDHDSetup", thisGate)
- return
- end
- end
- end
- end
- end
- end
- local function initError(device)
- term.setBackgroundColor(black)
- term.clear()
- drawElement(2, 2, 1, 1, red, black, device == "ONLINE" and "Stargate is OFFLINE!" or "No " .. device .. " detected!")
- drawElement(2, 4, 1, 1, white, nil, "gateLiaison is OFFLINE")
- term.setCursorPos(1, 7)
- end
- local function addMonitor(attachName)
- peripheral.call(attachName, "setTextScale", 1)
- local tmX, tmY = peripheral.call(attachName, "getSize")
- if tmX == 29 and tmY == 5 then --# 3x1 monitor array (marquee)
- hardware.marquee = hardware.marquee + 1
- marquee[hardware.marquee] = peripheral.wrap(attachName)
- if not marquee[hardware.marquee].isColor() then bAndW = true end
- elseif tmX == 29 and tmY == 19 then --# 3x3 monitor array (gateMon)
- hardware.gateMon = hardware.gateMon + 1
- gateMon[hardware.gateMon] = peripheral.wrap(attachName)
- if not gateMon[hardware.gateMon].isColor() then bAndW = true end
- elseif tmX == 18 and tmY == 5 then --# 2x1 monitor array (timerMon)
- hardware.timerMon = hardware.timerMon + 1
- timerMon[hardware.timerMon] = peripheral.wrap(attachName)
- if not timerMon[hardware.timerMon].isColor() then bAndW = true end
- timerMon[hardware.timerMon].setTextScale(2.5)
- end
- end
- if pocket then error("Computer or turtle REQUIRED.\n", 0) end
- print("Init Gate...")
- gate = peripheral.find("stargate")
- if not gate then
- lcGate = true
- gate = peripheral.find("StargateBase")
- if gate and not gate.isValid() then gate = nil end
- end
- if not gate then return initError("STARGATE") 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] == "nomon" then
- noMon = true
- elseif tArgs[i] == "outgoing" then
- outgoingAlarm = true
- elseif validSides[tArgs[i]] then
- rsSide = tArgs[i]
- end
- end
- end
- if lcGate then
- local irisStates = {
- OPEN = "Open";
- CLOSED = "Closed";
- OPENING = "Opening";
- CLOSING = "Closing";
- NONE = "Offline";
- }
- thisGate = gate.getStargateAddressString()
- --# DETERMINE GATE STATUS (INCOMING, CONNECTED, etc.)
- --gateStatus = gate.isConnected() and "Connected" or "Idle"
- --gateStatus = gate.isDialing() and "Dialing" or gateStatus
- local glyphs = gate.getActivatedGlyphs() --# returns a string
- local chevs = gate.getActivatedChevrons() --# returns a number
- if glyphs and chevs > 0 then --# this can be confused - if the gate is hanging up, there will be chevrons encoded, but the status is "Disconnecting" not "Dialing"
- dialAddress = chevs == 9 and glyphs or glyphs .. string.rep("?", 9 - chevs)
- gateStatus = chevs == 9 and "Connected" or "Dialing"
- chevronNumber = chevs
- callDirection = "Unknown"
- if rsSide ~= "none" and outgoingAlarm then rs.setOutput(rsSide, gateStatus == "Dialing") end
- else
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end
- gateStatus = "Idle"
- callDirection = "none"
- end
- irisStatus = irisStates[gate.getIrisState()]
- irisPercent = irisStatus ~= "Offline" and gate.getIrisHealth() or 0
- else
- thisGate = gate.localAddress()
- local gateState
- gateState, chevronNumber, callDirection = gate.stargateState()
- gateStatus = sgStates[gateState] or "Unknown"
- if gateStatus == "Offline" then return initError("ONLINE") end
- if gateStatus == "Dialing" or gateStatus == "Connected" then
- if callDirection == "Incoming" then
- incomingAddress = gate.remoteAddress()
- if rsSide ~= "none" then rs.setOutput(rsSide, gateStatus == "Dialing") end
- elseif callDirection == "Outgoing" then
- dialAddress = gate.remoteAddress()
- if rsSide ~= "none" and outgoingAlarm then rs.setOutput(rsSide, gateStatus == "Dialing") end
- else
- callDirection = "Unknown"
- dialAddress = gate.remoteAddress()
- end
- elseif gateStatus == "Idle" or gateStatus == "Disconnecting" then
- if rsSide ~= "none" then rs.setOutput(rsSide, false) end
- callDirection = "none"
- end
- irisStatus = gate.irisState()
- end
- irisState = irisStatus == "Closed"
- waitingForIris = (irisStatus == "Opening" or irisStatus == "Closing")
- print("Init Modem...")
- for _, side in pairs(rs.getSides()) do --# Look for modems before monitors and wireless before wired - stop at the first modem found
- if peripheral.isPresent(side) and peripheral.getType(side) == "modem" and peripheral.call(side, "isWireless") then
- wifiComms = true
- modemSide = side
- break
- end
- end
- if modemSide == "none" then
- for _, side in pairs(rs.getSides()) do
- if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then
- for _, name in pairs(peripheral.call(side, "getNamesRemote")) do
- if peripheral.getType(name) == "computer" and peripheral.call(side, "isPresentRemote", name) and peripheral.call(side, "callRemote", name, "getID") ~= tonumber(thisCC) then
- modemSide = side
- break
- end
- end
- end
- if modemSide ~= "none" then break end
- end
- end
- if modemSide == "none" then return initError("MODEM") end
- rednet.open(modemSide)
- if noMon then --# turtles can use the full-block modem from cc:Tweaked
- print("Monitor support disabled...")
- else
- print("Init Monitors...")
- for _, side in pairs(rs.getSides()) do --# look for monitors
- if peripheral.isPresent(side) and 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" then
- addMonitor(name)
- end
- end
- elseif peripheral.isPresent(side) and peripheral.getType(side) == "monitor" then
- addMonitor(side)
- end
- end
- end
- if bAndW then --# if a black and white monitor was found, reset monitor colors to black and white
- msilver = grayScale and colors.lightGray or colors.white
- mgray = grayScale and colors.gray or colors.black
- --mbrown = colors.white
- myellow = colors.white
- morange = colors.white
- mred = colors.white
- --mmagenta = colors.white
- --mpurple = colors.white
- mblue = colors.black
- msky = colors.white
- mcyan = colors.white
- --mlime = colors.white
- mgreen = colors.white
- end
- if marquee[1] then
- for i = 1, hardware.marquee do
- marquee[i].setBackgroundColor(mwhite)
- marquee[i].setTextColor(mblack)
- marquee[i].clear()
- marquee[i].setTextScale(2)
- marquee[i].setCursorPos(2, 1)
- marquee[i].write("gateLiaison")
- marquee[i].setCursorPos(2, 2)
- marquee[i].write("Initializing")
- end
- end
- if gateMon[1] then
- for i = 1, hardware.gateMon do
- gateMon[i].setBackgroundColor(mwhite)
- gateMon[i].setTextColor(mblack)
- gateMon[i].clear()
- gateMon[i].setTextScale(2)
- gateMon[i].setCursorPos(2, 1)
- gateMon[i].write("gateLiaison")
- gateMon[i].setCursorPos(2, 2)
- gateMon[i].write("Initializing")
- end
- end
- if timerMon[1] then
- for i = 1, hardware.timerMon do
- timerMon[i].setBackgroundColor(mwhite)
- timerMon[i].setTextColor(mblack)
- timerMon[i].clear()
- timerMon[i].setCursorPos(2, 1)
- timerMon[i].write("Gate")
- timerMon[i].setCursorPos(1, 2)
- timerMon[i].write("Init...")
- end
- end
- print("Inspect Environment...")
- fuelPercent = getFuelLevel()
- if not fs.exists("/data/gateConfig") then --# Check for first time install
- print("First Run...")
- if not fs.exists("/data") then fs.makeDir("/data") end
- if not os.getComputerLabel() then os.setComputerLabel("gateLiaison.cc#" .. thisCC) end
- term.setBackgroundColor(black)
- term.clear()
- drawElement(2, 2, 1, 1, nil, nil, "Please start ccDHD to complete setup.")
- drawElement(2, 4, 1, 1, nil, nil, "gateLiaison will automatically start")
- drawElement(2, 5, 1, 1, nil, nil, "after ccDHD is initialized.")
- drawElement(2, 7, 1, 1, nil, nil, "This gate: " .. thisGate)
- rednet.host("ccDHDSetup", thisGate)
- drawElement(2, 9, 1, 1, silver, nil, "...waiting for ccDHD...")
- parallel.waitForAny(waitingNet, waitingAnimation)
- term.setBackgroundColor(black)
- term.clear()
- local gateConfig = fs.open("/data/gateConfig", "w")
- gateConfig.write(textutils.serialize(gateSettings))
- gateConfig.close()
- else
- print("Ingest Data...")
- local gateConfig = fs.open("/data/gateConfig", "r")
- gateSettings = textutils.unserialize(gateConfig.readAll())
- gateConfig.close()
- end
- ccLabel = os.getComputerLabel():sub(1, 25)
- if marquee[1] or gateMon[1] or timerMon[1] then print("Prepare Monitors...") end
- if marquee[1] then
- for i = 1, hardware.marquee do
- marquee[i].setBackgroundColor(mblack)
- marquee[i].clear()
- end
- end
- if timerMon[1] then
- for i = 1, hardware.timerMon do
- timerMon[i].setBackgroundColor(mblack)
- timerMon[i].clear()
- end
- end
- if gateMon[1] and (not bAndW or (bAndW and grayScale)) then
- 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, },
- }
- gateMon[1].setTextScale(1)
- gateMon[1].setBackgroundColor(mblack)
- gateMon[1].clear()
- local termPrime = term.redirect(gateMon[1])
- paintutils.drawImage(gateImage, 1, 1)
- if gateMon[2] then
- for i = 2, hardware.gateMon do
- gateMon[i].setTextScale(1)
- gateMon[i].setBackgroundColor(mblack)
- gateMon[i].clear()
- term.redirect(gateMon[i])
- paintutils.drawImage(gateImage, 1, 1)
- end
- end
- term.redirect(termPrime)
- end
- displayConnectionTime()
- term.setBackgroundColor(black)
- term.clear()
- updatePercentages(true, true)
- if gateStatus == "Connected" then
- local dataPack = textutils.serialize({ irisState = irisState and "closed" or "open" })
- pcall(gate.sendMessage, dataPack)
- if callDirection == "Outgoing" then updateTimer = os.startTimer(5) end
- connectionTimer = os.startTimer(0.1)
- end
- --# END AUTOMATIC/STATIC CONFIGURATION (Part 2)
- if lcGate then
- parallel.waitForAny(gateReceive, netReceive, lcChevronEncoder, lcGateMonitor, lcIrisMonitor, dataPoller, charInput)
- else
- parallel.waitForAny(gateReceive, netReceive, incomingCall, outgoingCall, sgChevronEncoder, sgChevronUnencoded, sgGateMonitor, sgIrisMonitor, dataPoller, charInput)
- end
Add Comment
Please, Sign In to add comment