selrahc13

WiRe Client (Create compat)

Jan 14th, 2020
153
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[    WiRe Client    ]]--
  2. --[[      by Dog       ]]--
  3. --[[ aka HydrantHunter ]]--
  4. --[[  Wi = Wireless    ]]--
  5. --[[  Re = Redstone    ]]--
  6. --[[ pastebin jtFa7V1n ]]--
  7. local WiReCver = "2.0.05"
  8. --[[
  9. Tested with/requires:
  10.   - Minecraft 1.6.4+
  11.   - ComputerCraft 1.63+
  12.     - A Computer (standard or advanced) with a modem and, optionally, one or more Advanced Monitors
  13.     - WiRe Server running on a computer (standard or advanced) with a modem and one advanced monitor array
  14.  
  15. Special thanks to: SquidDev   (AES encryption/decryption)
  16.                    Alex Kloss (base64 encoder/decoder)
  17. ]]--
  18. local tArgs = { ... }
  19. --# CONFIGURATION
  20. --# Default Settings
  21. local termX, termY = term.getSize()
  22. local thisCC = tostring(os.getComputerID())
  23. local config = "/data/WiReClientCfg"
  24. local ccSettings = {
  25.   name = "WiReClient";  --# this client's name
  26.   note = "short note";  --# short note/description
  27.   color = "Silver";     --# network group
  28.   side = "top";         --# redstone side
  29.   deviceType = "Door";  --# device type
  30.   autoClose = true;     --# automatically close after being opened
  31.   autoDelay = 3;        --# autoClose delay
  32.   onState = false;      --# ON/CLOSED - redstone output
  33.   offState = true;      --# OFF/OPEN - redstone output
  34.   defaultStart = false; --# startup redstone output
  35.   lastState = false;    --# last redstone state (for defaultStart = "last")
  36.   lockState = false;    --# lock state
  37.   getGPSFix = true;     --# get GPS fix on startup
  38.   newColors = true;     --# using new color names
  39. }
  40. local validStates = {
  41.   ON = "OFF";
  42.   OFF = "ON";
  43.   OPEN = "CLOSED";
  44.   CLOSED = "OPEN";
  45.   LOCKED = true;
  46.   UNLOCK = true;
  47.   WiReQRY = true;
  48. }
  49. local mon, loc = { }, { }
  50. local deviceState, deviceType, autoDelay = "QRY", "QRY", 0
  51. local defaultStart, onState, offState, defaultLock, defaultUnlock = false, false, true, false, false
  52. local kernelState, ccSuccess, autoClose, help = false, false, false, false
  53. local network, server, modemSide, thisCommand, pollTimer, updateScreens, staticTermScreen
  54. --# Terminal Colors
  55. local white = colors.white
  56. local black = colors.black
  57. local silver = colors.lightGray
  58. local gray = colors.gray
  59. local brown = colors.brown
  60. local yellow = colors.yellow
  61. local orange = colors.orange
  62. local red = colors.red
  63. local magenta = colors.magenta
  64. local purple = colors.purple
  65. local blue = colors.blue
  66. local sky = colors.lightBlue
  67. local cyan = colors.cyan
  68. local lime = colors.lime
  69. local green = colors.green
  70. if not term.isColor() then
  71.   silver = colors.white
  72.   gray = colors.black
  73.   brown = colors.white
  74.   yellow = colors.white
  75.   orange = colors.white
  76.   red = colors.white
  77.   magenta = colors.white
  78.   purple = colors.white
  79.   green = colors.white
  80.   blue = colors.black
  81.   sky = colors.white
  82.   cyan = colors.white
  83.   lime = colors.white
  84.   green = colors.white
  85. end
  86. --# Monitor colors
  87. local mwhite = colors.white
  88. local mblack = colors.black
  89. local msilver = colors.lightGray
  90. local mgray = colors.gray
  91. local mbrown = colors.brown
  92. local myellow = colors.yellow
  93. local morange = colors.orange
  94. local mred = colors.red
  95. local mmagenta = colors.magenta
  96. local mpurple = colors.purple
  97. local mblue = colors.blue
  98. local msky = colors.lightBlue
  99. local mcyan = colors.cyan
  100. local mlime = colors.lime
  101. local mgreen = colors.green
  102. --# Status colors
  103. local switchStates = {
  104.   OPEN = { orange, morange, " [ ] " };
  105.   CLOSED = { green, mgreen, " [O] " };
  106.   ON = { green, mgreen, " [O] " };
  107.   OFF = { orange, morange, " [ ] " };
  108. }
  109. --# END CONFIGURATION
  110.  
  111. -- Lua 5.1+ base64 v3.0 (c) 2009 by Alex Kloss <alexthkloss@web.de>
  112. -- licensed under the terms of the LGPL2
  113. -- http://lua-users.org/wiki/BaseSixtyFour
  114. -- character table string
  115. local b='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  116. -- encoding
  117. function encode(data)
  118.   return ((data:gsub('.', function(x)
  119.     local r,b='',x:byte()
  120.     for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
  121.     return r;
  122.   end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
  123.     if (#x < 6) then return '' end
  124.     local c=0
  125.     for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
  126.     return b:sub(c+1,c+1)
  127.   end)..({ '', '==', '=' })[#data%3+1])
  128. end
  129. -- decoding
  130. function decode(data)
  131.   data = string.gsub(data, '[^'..b..'=]', '')
  132.   return (data:gsub('.', function(x)
  133.     if (x == '=') then return '' end
  134.     local r,f='',(b:find(x)-1)
  135.     for i=6,1,-1 do r=r..(f%2^i-f%2^(i-1)>0 and '1' or '0') end
  136.     return r;
  137.   end):gsub('%d%d%d?%d?%d?%d?%d?%d?', function(x)
  138.     if (#x ~= 8) then return '' end
  139.     local c=0
  140.     for i=1,8 do c=c+(x:sub(i,i)=='1' and 2^(8-i) or 0) end
  141.     return string.char(c)
  142.   end))
  143. end
  144.  
  145. -- AES Lua implementation by SquidDev
  146. -- https://gist.github.com/SquidDev/86925e07cbabd70773e53d781bd8b2fe
  147. local encrypt, decrypt
  148. do
  149.   local function _W(f) local e=setmetatable({}, {__index = _ENV or getfenv()}) if setfenv then setfenv(f, e) end return f(e) or e end
  150.   local bit=_W(function(_ENV, ...)
  151.   --[[
  152.     This bit API is designed to cope with unsigned integers instead of normal integers
  153.     To do this we add checks for overflows: (x > 2^31 ? x - 2 ^ 32 : x)
  154.     These are written in long form because no constant folding.
  155.   ]]
  156.   local floor = math.floor
  157.   local lshift, rshift
  158.  
  159.   rshift = function(a,disp)
  160.     return floor(a % 4294967296 / 2^disp)
  161.   end
  162.  
  163.   lshift = function(a,disp)
  164.     return (a * 2^disp) % 4294967296
  165.   end
  166.  
  167.   return {
  168.     -- bit operations
  169.     bnot = bit32 and bit32.bnot or bit.bnot,
  170.     band = bit32 and bit32.band or bit.band,
  171.     bor  = bit32 and bit32.bor or bit.bor,
  172.     bxor = bit32 and bit32.bxor or bit.bxor,
  173.     rshift = rshift,
  174.     lshift = lshift,
  175.   }
  176.   end)
  177.  
  178.   local gf=_W(function(_ENV, ...)
  179.   -- finite field with base 2 and modulo irreducible polynom x^8+x^4+x^3+x+1 = 0x11d
  180.   local bxor = bit32 and bit32.bxor or bit.bxor
  181.   local lshift = bit.lshift
  182.   -- private data of gf
  183.   local n = 0x100
  184.   local ord = 0xff
  185.   local irrPolynom = 0x11b
  186.   local exp = {}
  187.   local log = {}
  188.   --
  189.   -- add two polynoms (its simply xor)
  190.   --
  191.   local function add(operand1, operand2)
  192.     return bxor(operand1,operand2)
  193.   end
  194.   --
  195.   -- subtract two polynoms (same as addition)
  196.   --
  197.   local function sub(operand1, operand2)
  198.     return bxor(operand1,operand2)
  199.   end
  200.   --
  201.   -- inverts element
  202.   -- a^(-1) = g^(order - log(a))
  203.   --
  204.   local function invert(operand)
  205.     -- special case for 1
  206.     if (operand == 1) then
  207.       return 1
  208.     end
  209.     -- normal invert
  210.     local exponent = ord - log[operand]
  211.     return exp[exponent]
  212.   end
  213.   --
  214.   -- multiply two elements using a logarithm table
  215.   -- a*b = g^(log(a)+log(b))
  216.   --
  217.   local function mul(operand1, operand2)
  218.     if (operand1 == 0 or operand2 == 0) then
  219.       return 0
  220.     end
  221.     local exponent = log[operand1] + log[operand2]
  222.     if (exponent >= ord) then
  223.       exponent = exponent - ord
  224.     end
  225.     return exp[exponent]
  226.   end
  227.   --
  228.   -- divide two elements
  229.   -- a/b = g^(log(a)-log(b))
  230.   --
  231.   local function div(operand1, operand2)
  232.     if (operand1 == 0)  then
  233.       return 0
  234.     end
  235.     -- TODO: exception if operand2 == 0
  236.     local exponent = log[operand1] - log[operand2]
  237.     if (exponent < 0) then
  238.       exponent = exponent + ord
  239.     end
  240.     return exp[exponent]
  241.   end
  242.   --
  243.   -- print logarithmic table
  244.   --
  245.   local function printLog()
  246.     for i = 1, n do
  247.       print("log(", i-1, ")=", log[i-1])
  248.     end
  249.   end
  250.   --
  251.   -- print exponentiation table
  252.   --
  253.   local function printExp()
  254.     for i = 1, n do
  255.       print("exp(", i-1, ")=", exp[i-1])
  256.     end
  257.   end
  258.   --
  259.   -- calculate logarithmic and exponentiation table
  260.   --
  261.   local function initMulTable()
  262.     local a = 1
  263.     for i = 0,ord-1 do
  264.       exp[i] = a
  265.       log[a] = i
  266.       -- multiply with generator x+1 -> left shift + 1
  267.       a = bxor(lshift(a, 1), a)
  268.       -- if a gets larger than order, reduce modulo irreducible polynom
  269.       if a > ord then
  270.         a = sub(a, irrPolynom)
  271.       end
  272.     end
  273.   end
  274.  
  275.   initMulTable()
  276.  
  277.   return {
  278.     add = add,
  279.     sub = sub,
  280.     invert = invert,
  281.     mul = mul,
  282.     div = div,
  283.     printLog = printLog,
  284.     printExp = printExp,
  285.   }
  286.   end)
  287.  
  288.   util=_W(function(_ENV, ...)
  289.   -- Cache some bit operators
  290.   local bxor = bit.bxor
  291.   local rshift = bit.rshift
  292.   local band = bit.band
  293.   local lshift = bit.lshift
  294.   local sleepCheckIn
  295.   --
  296.   -- calculate the parity of one byte
  297.   --
  298.   local function byteParity(byte)
  299.     byte = bxor(byte, rshift(byte, 4))
  300.     byte = bxor(byte, rshift(byte, 2))
  301.     byte = bxor(byte, rshift(byte, 1))
  302.     return band(byte, 1)
  303.   end
  304.   --
  305.   -- get byte at position index
  306.   --
  307.   local function getByte(number, index)
  308.     return index == 0 and band(number,0xff) or band(rshift(number, index*8),0xff)
  309.   end
  310.   --
  311.   -- put number into int at position index
  312.   --
  313.   local function putByte(number, index)
  314.     return index == 0 and band(number,0xff) or lshift(band(number,0xff),index*8)
  315.   end
  316.   --
  317.   -- convert byte array to int array
  318.   --
  319.   local function bytesToInts(bytes, start, n)
  320.     local ints = {}
  321.     for i = 0, n - 1 do
  322.       ints[i + 1] =
  323.           putByte(bytes[start + (i*4)], 3) +
  324.           putByte(bytes[start + (i*4) + 1], 2) +
  325.           putByte(bytes[start + (i*4) + 2], 1) +
  326.           putByte(bytes[start + (i*4) + 3], 0)
  327.       if n % 10000 == 0 then sleepCheckIn() end
  328.     end
  329.     return ints
  330.   end
  331.   --
  332.   -- convert int array to byte array
  333.   --
  334.   local function intsToBytes(ints, output, outputOffset, n)
  335.     n = n or #ints
  336.     for i = 0, n - 1 do
  337.       for j = 0,3 do
  338.         output[outputOffset + i*4 + (3 - j)] = getByte(ints[i + 1], j)
  339.       end
  340.       if n % 10000 == 0 then sleepCheckIn() end
  341.     end
  342.     return output
  343.   end
  344.   --
  345.   -- convert bytes to hexString
  346.   --
  347.   local function bytesToHex(bytes)
  348.     local hexBytes = ""
  349.     for i,byte in ipairs(bytes) do
  350.       hexBytes = hexBytes .. string.format("%02x ", byte)
  351.     end
  352.     return hexBytes
  353.   end
  354.  
  355.   local function hexToBytes(bytes)
  356.     local out = {}
  357.     for i = 1, #bytes, 2 do
  358.       out[#out + 1] = tonumber(bytes:sub(i, i + 1), 16)
  359.     end
  360.     return out
  361.   end
  362.   --
  363.   -- convert data to hex string
  364.   --
  365.   local function toHexString(data)
  366.     local type = type(data)
  367.     if (type == "number") then
  368.       return string.format("%08x",data)
  369.     elseif (type == "table") then
  370.       return bytesToHex(data)
  371.     elseif (type == "string") then
  372.       local bytes = {string.byte(data, 1, #data)}
  373.       return bytesToHex(bytes)
  374.     else
  375.       return data
  376.     end
  377.   end
  378.  
  379.   local function padByteString(data)
  380.     local dataLength = #data
  381.     local random1 = math.random(0,255)
  382.     local random2 = math.random(0,255)
  383.     local prefix = string.char(random1,
  384.       random2,
  385.       random1,
  386.       random2,
  387.       getByte(dataLength, 3),
  388.       getByte(dataLength, 2),
  389.       getByte(dataLength, 1),
  390.       getByte(dataLength, 0)
  391.     )
  392.     data = prefix .. data
  393.     local padding, paddingLength = "", math.ceil(#data/16)*16 - #data
  394.     for i=1,paddingLength do
  395.       padding = padding .. string.char(math.random(0,255))
  396.     end
  397.     return data .. padding
  398.   end
  399.  
  400.   local function properlyDecrypted(data)
  401.     local random = {string.byte(data,1,4)}
  402.     if (random[1] == random[3] and random[2] == random[4]) then
  403.       return true
  404.     end
  405.     return false
  406.   end
  407.  
  408.   local function unpadByteString(data)
  409.     if (not properlyDecrypted(data)) then
  410.       return nil
  411.     end
  412.     local dataLength = putByte(string.byte(data,5), 3)
  413.              + putByte(string.byte(data,6), 2)
  414.              + putByte(string.byte(data,7), 1)
  415.              + putByte(string.byte(data,8), 0)
  416.     return string.sub(data,9,8+dataLength)
  417.   end
  418.  
  419.   local function xorIV(data, iv)
  420.     for i = 1,16 do
  421.       data[i] = bxor(data[i], iv[i])
  422.     end
  423.   end
  424.  
  425.   local function increment(data)
  426.     local i = 16
  427.     while true do
  428.       local value = data[i] + 1
  429.       if value >= 256 then
  430.         data[i] = value - 256
  431.         i = (i - 2) % 16 + 1
  432.       else
  433.         data[i] = value
  434.         break
  435.       end
  436.     end
  437.   end
  438.  
  439.   -- Called every encryption cycle
  440.   local push, pull, time = os.queueEvent, coroutine.yield, os.time
  441.   local oldTime = time()
  442.   local function sleepCheckIn()
  443.     local newTime = time()
  444.     if newTime - oldTime >= 0.03 then -- (0.020 * 1.5)
  445.       oldTime = newTime
  446.       push("sleep")
  447.       pull("sleep")
  448.     end
  449.   end
  450.  
  451.   local function getRandomData(bytes)
  452.     local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
  453.     local result = {}
  454.     for i=1,bytes do
  455.       insert(result, random(0,255))
  456.       if i % 10240 == 0 then sleep() end
  457.     end
  458.     return result
  459.   end
  460.  
  461.   local function getRandomString(bytes)
  462.     local char, random, sleep, insert = string.char, math.random, sleepCheckIn, table.insert
  463.     local result = {}
  464.     for i=1,bytes do
  465.       insert(result, char(random(0,255)))
  466.       if i % 10240 == 0 then sleep() end
  467.     end
  468.     return table.concat(result)
  469.   end
  470.  
  471.   return {
  472.     byteParity = byteParity,
  473.     getByte = getByte,
  474.     putByte = putByte,
  475.     bytesToInts = bytesToInts,
  476.     intsToBytes = intsToBytes,
  477.     bytesToHex = bytesToHex,
  478.     hexToBytes = hexToBytes,
  479.     toHexString = toHexString,
  480.     padByteString = padByteString,
  481.     properlyDecrypted = properlyDecrypted,
  482.     unpadByteString = unpadByteString,
  483.     xorIV = xorIV,
  484.     increment = increment,
  485.     sleepCheckIn = sleepCheckIn,
  486.     getRandomData = getRandomData,
  487.     getRandomString = getRandomString,
  488.   }
  489.   end)
  490.  
  491.   aes=_W(function(_ENV, ...)
  492.   -- Implementation of AES with nearly pure lua
  493.   -- AES with lua is slow, really slow :-)
  494.   local putByte = util.putByte
  495.   local getByte = util.getByte
  496.   -- some constants
  497.   local ROUNDS = 'rounds'
  498.   local KEY_TYPE = "type"
  499.   local ENCRYPTION_KEY=1
  500.   local DECRYPTION_KEY=2
  501.   -- aes SBOX
  502.   local SBox = {}
  503.   local iSBox = {}
  504.   -- aes tables
  505.   local table0 = {}
  506.   local table1 = {}
  507.   local table2 = {}
  508.   local table3 = {}
  509.   local tableInv0 = {}
  510.   local tableInv1 = {}
  511.   local tableInv2 = {}
  512.   local tableInv3 = {}
  513.   -- round constants
  514.   local rCon = {
  515.     0x01000000,
  516.     0x02000000,
  517.     0x04000000,
  518.     0x08000000,
  519.     0x10000000,
  520.     0x20000000,
  521.     0x40000000,
  522.     0x80000000,
  523.     0x1b000000,
  524.     0x36000000,
  525.     0x6c000000,
  526.     0xd8000000,
  527.     0xab000000,
  528.     0x4d000000,
  529.     0x9a000000,
  530.     0x2f000000,
  531.   }
  532.   --
  533.   -- affine transformation for calculating the S-Box of AES
  534.   --
  535.   local function affinMap(byte)
  536.     mask = 0xf8
  537.     result = 0
  538.     for i = 1,8 do
  539.       result = bit.lshift(result,1)
  540.       parity = util.byteParity(bit.band(byte,mask))
  541.       result = result + parity
  542.       -- simulate roll
  543.       lastbit = bit.band(mask, 1)
  544.       mask = bit.band(bit.rshift(mask, 1),0xff)
  545.       mask = lastbit ~= 0 and bit.bor(mask, 0x80) or bit.band(mask, 0x7f)
  546.     end
  547.     return bit.bxor(result, 0x63)
  548.   end
  549.   --
  550.   -- calculate S-Box and inverse S-Box of AES
  551.   -- apply affine transformation to inverse in finite field 2^8
  552.   --
  553.   local function calcSBox()
  554.     for i = 0, 255 do
  555.       inverse = i ~= 0 and gf.invert(i) or i
  556.       mapped = affinMap(inverse)
  557.       SBox[i] = mapped
  558.       iSBox[mapped] = i
  559.     end
  560.   end
  561.   --
  562.   -- Calculate round tables
  563.   -- round tables are used to calculate shiftRow, MixColumn and SubBytes
  564.   -- with 4 table lookups and 4 xor operations.
  565.   --
  566.   local function calcRoundTables()
  567.     for x = 0,255 do
  568.       byte = SBox[x]
  569.       table0[x] = putByte(gf.mul(0x03, byte), 0)
  570.                 + putByte(             byte , 1)
  571.                 + putByte(             byte , 2)
  572.                 + putByte(gf.mul(0x02, byte), 3)
  573.       table1[x] = putByte(             byte , 0)
  574.                 + putByte(             byte , 1)
  575.                 + putByte(gf.mul(0x02, byte), 2)
  576.                 + putByte(gf.mul(0x03, byte), 3)
  577.       table2[x] = putByte(             byte , 0)
  578.                 + putByte(gf.mul(0x02, byte), 1)
  579.                 + putByte(gf.mul(0x03, byte), 2)
  580.                 + putByte(             byte , 3)
  581.       table3[x] = putByte(gf.mul(0x02, byte), 0)
  582.                 + putByte(gf.mul(0x03, byte), 1)
  583.                 + putByte(             byte , 2)
  584.                 + putByte(             byte , 3)
  585.     end
  586.   end
  587.   --
  588.   -- Calculate inverse round tables
  589.   -- does the inverse of the normal roundtables for the equivalent
  590.   -- decryption algorithm.
  591.   --
  592.   local function calcInvRoundTables()
  593.     for x = 0,255 do
  594.       byte = iSBox[x]
  595.       tableInv0[x] = putByte(gf.mul(0x0b, byte), 0)
  596.                  + putByte(gf.mul(0x0d, byte), 1)
  597.                  + putByte(gf.mul(0x09, byte), 2)
  598.                  + putByte(gf.mul(0x0e, byte), 3)
  599.       tableInv1[x] = putByte(gf.mul(0x0d, byte), 0)
  600.                  + putByte(gf.mul(0x09, byte), 1)
  601.                  + putByte(gf.mul(0x0e, byte), 2)
  602.                  + putByte(gf.mul(0x0b, byte), 3)
  603.       tableInv2[x] = putByte(gf.mul(0x09, byte), 0)
  604.                  + putByte(gf.mul(0x0e, byte), 1)
  605.                  + putByte(gf.mul(0x0b, byte), 2)
  606.                  + putByte(gf.mul(0x0d, byte), 3)
  607.       tableInv3[x] = putByte(gf.mul(0x0e, byte), 0)
  608.                  + putByte(gf.mul(0x0b, byte), 1)
  609.                  + putByte(gf.mul(0x0d, byte), 2)
  610.                  + putByte(gf.mul(0x09, byte), 3)
  611.     end
  612.   end
  613.   --
  614.   -- rotate word: 0xaabbccdd gets 0xbbccddaa
  615.   -- used for key schedule
  616.   --
  617.   local function rotWord(word)
  618.     local tmp = bit.band(word,0xff000000)
  619.     return (bit.lshift(word,8) + bit.rshift(tmp,24))
  620.   end
  621.   --
  622.   -- replace all bytes in a word with the SBox.
  623.   -- used for key schedule
  624.   --
  625.   local function subWord(word)
  626.     return putByte(SBox[getByte(word,0)],0)
  627.       + putByte(SBox[getByte(word,1)],1)
  628.       + putByte(SBox[getByte(word,2)],2)
  629.       + putByte(SBox[getByte(word,3)],3)
  630.   end
  631.   --
  632.   -- generate key schedule for aes encryption
  633.   --
  634.   -- returns table with all round keys and
  635.   -- the necessary number of rounds saved in [ROUNDS]
  636.   --
  637.   local function expandEncryptionKey(key)
  638.     local keySchedule = {}
  639.     local keyWords = math.floor(#key / 4)
  640.     if ((keyWords ~= 4 and keyWords ~= 6 and keyWords ~= 8) or (keyWords * 4 ~= #key)) then
  641.       error("Invalid key size: " .. tostring(keyWords))
  642.       return nil
  643.     end
  644.     keySchedule[ROUNDS] = keyWords + 6
  645.     keySchedule[KEY_TYPE] = ENCRYPTION_KEY
  646.     for i = 0,keyWords - 1 do
  647.       keySchedule[i] = putByte(key[i*4+1], 3)
  648.                + putByte(key[i*4+2], 2)
  649.                + putByte(key[i*4+3], 1)
  650.                + putByte(key[i*4+4], 0)
  651.     end
  652.     for i = keyWords, (keySchedule[ROUNDS] + 1)*4 - 1 do
  653.       local tmp = keySchedule[i-1]
  654.       if ( i % keyWords == 0) then
  655.         tmp = rotWord(tmp)
  656.         tmp = subWord(tmp)
  657.         local index = math.floor(i/keyWords)
  658.         tmp = bit.bxor(tmp,rCon[index])
  659.       elseif (keyWords > 6 and i % keyWords == 4) then
  660.         tmp = subWord(tmp)
  661.       end
  662.       keySchedule[i] = bit.bxor(keySchedule[(i-keyWords)],tmp)
  663.     end
  664.     return keySchedule
  665.   end
  666.   --
  667.   -- Inverse mix column
  668.   -- used for key schedule of decryption key
  669.   --
  670.   local function invMixColumnOld(word)
  671.     local b0 = getByte(word,3)
  672.     local b1 = getByte(word,2)
  673.     local b2 = getByte(word,1)
  674.     local b3 = getByte(word,0)
  675.     return putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b1),
  676.                          gf.mul(0x0d, b2)),
  677.                          gf.mul(0x09, b3)),
  678.                          gf.mul(0x0e, b0)),3)
  679.        + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b2),
  680.                          gf.mul(0x0d, b3)),
  681.                          gf.mul(0x09, b0)),
  682.                          gf.mul(0x0e, b1)),2)
  683.        + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b3),
  684.                          gf.mul(0x0d, b0)),
  685.                          gf.mul(0x09, b1)),
  686.                          gf.mul(0x0e, b2)),1)
  687.        + putByte(gf.add(gf.add(gf.add(gf.mul(0x0b, b0),
  688.                          gf.mul(0x0d, b1)),
  689.                          gf.mul(0x09, b2)),
  690.                          gf.mul(0x0e, b3)),0)
  691.   end
  692.   --
  693.   -- Optimized inverse mix column
  694.   -- look at http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.311.pdf
  695.   -- TODO: make it work
  696.   --
  697.   local function invMixColumn(word)
  698.     local b0 = getByte(word,3)
  699.     local b1 = getByte(word,2)
  700.     local b2 = getByte(word,1)
  701.     local b3 = getByte(word,0)
  702.     local t = bit.bxor(b3,b2)
  703.     local u = bit.bxor(b1,b0)
  704.     local v = bit.bxor(t,u)
  705.     v = bit.bxor(v,gf.mul(0x08,v))
  706.     w = bit.bxor(v,gf.mul(0x04, bit.bxor(b2,b0)))
  707.     v = bit.bxor(v,gf.mul(0x04, bit.bxor(b3,b1)))
  708.     return putByte( bit.bxor(bit.bxor(b3,v), gf.mul(0x02, bit.bxor(b0,b3))), 0)
  709.        + putByte( bit.bxor(bit.bxor(b2,w), gf.mul(0x02, t              )), 1)
  710.        + putByte( bit.bxor(bit.bxor(b1,v), gf.mul(0x02, bit.bxor(b0,b3))), 2)
  711.        + putByte( bit.bxor(bit.bxor(b0,w), gf.mul(0x02, u              )), 3)
  712.   end
  713.   --
  714.   -- generate key schedule for aes decryption
  715.   --
  716.   -- uses key schedule for aes encryption and transforms each
  717.   -- key by inverse mix column.
  718.   --
  719.   local function expandDecryptionKey(key)
  720.     local keySchedule = expandEncryptionKey(key)
  721.     if (keySchedule == nil) then
  722.       return nil
  723.     end
  724.     keySchedule[KEY_TYPE] = DECRYPTION_KEY
  725.     for i = 4, (keySchedule[ROUNDS] + 1)*4 - 5 do
  726.       keySchedule[i] = invMixColumnOld(keySchedule[i])
  727.     end
  728.     return keySchedule
  729.   end
  730.   --
  731.   -- xor round key to state
  732.   --
  733.   local function addRoundKey(state, key, round)
  734.     for i = 0, 3 do
  735.       state[i + 1] = bit.bxor(state[i + 1], key[round*4+i])
  736.     end
  737.   end
  738.   --
  739.   -- do encryption round (ShiftRow, SubBytes, MixColumn together)
  740.   --
  741.   local function doRound(origState, dstState)
  742.     dstState[1] =  bit.bxor(bit.bxor(bit.bxor(
  743.           table0[getByte(origState[1],3)],
  744.           table1[getByte(origState[2],2)]),
  745.           table2[getByte(origState[3],1)]),
  746.           table3[getByte(origState[4],0)])
  747.     dstState[2] =  bit.bxor(bit.bxor(bit.bxor(
  748.           table0[getByte(origState[2],3)],
  749.           table1[getByte(origState[3],2)]),
  750.           table2[getByte(origState[4],1)]),
  751.           table3[getByte(origState[1],0)])
  752.     dstState[3] =  bit.bxor(bit.bxor(bit.bxor(
  753.           table0[getByte(origState[3],3)],
  754.           table1[getByte(origState[4],2)]),
  755.           table2[getByte(origState[1],1)]),
  756.           table3[getByte(origState[2],0)])
  757.     dstState[4] =  bit.bxor(bit.bxor(bit.bxor(
  758.           table0[getByte(origState[4],3)],
  759.           table1[getByte(origState[1],2)]),
  760.           table2[getByte(origState[2],1)]),
  761.           table3[getByte(origState[3],0)])
  762.   end
  763.   --
  764.   -- do last encryption round (ShiftRow and SubBytes)
  765.   --
  766.   local function doLastRound(origState, dstState)
  767.     dstState[1] = putByte(SBox[getByte(origState[1],3)], 3)
  768.           + putByte(SBox[getByte(origState[2],2)], 2)
  769.           + putByte(SBox[getByte(origState[3],1)], 1)
  770.           + putByte(SBox[getByte(origState[4],0)], 0)
  771.     dstState[2] = putByte(SBox[getByte(origState[2],3)], 3)
  772.           + putByte(SBox[getByte(origState[3],2)], 2)
  773.           + putByte(SBox[getByte(origState[4],1)], 1)
  774.           + putByte(SBox[getByte(origState[1],0)], 0)
  775.     dstState[3] = putByte(SBox[getByte(origState[3],3)], 3)
  776.           + putByte(SBox[getByte(origState[4],2)], 2)
  777.           + putByte(SBox[getByte(origState[1],1)], 1)
  778.           + putByte(SBox[getByte(origState[2],0)], 0)
  779.     dstState[4] = putByte(SBox[getByte(origState[4],3)], 3)
  780.           + putByte(SBox[getByte(origState[1],2)], 2)
  781.           + putByte(SBox[getByte(origState[2],1)], 1)
  782.           + putByte(SBox[getByte(origState[3],0)], 0)
  783.   end
  784.   --
  785.   -- do decryption round
  786.   --
  787.   local function doInvRound(origState, dstState)
  788.     dstState[1] =  bit.bxor(bit.bxor(bit.bxor(
  789.           tableInv0[getByte(origState[1],3)],
  790.           tableInv1[getByte(origState[4],2)]),
  791.           tableInv2[getByte(origState[3],1)]),
  792.           tableInv3[getByte(origState[2],0)])
  793.     dstState[2] =  bit.bxor(bit.bxor(bit.bxor(
  794.           tableInv0[getByte(origState[2],3)],
  795.           tableInv1[getByte(origState[1],2)]),
  796.           tableInv2[getByte(origState[4],1)]),
  797.           tableInv3[getByte(origState[3],0)])
  798.     dstState[3] =  bit.bxor(bit.bxor(bit.bxor(
  799.           tableInv0[getByte(origState[3],3)],
  800.           tableInv1[getByte(origState[2],2)]),
  801.           tableInv2[getByte(origState[1],1)]),
  802.           tableInv3[getByte(origState[4],0)])
  803.     dstState[4] =  bit.bxor(bit.bxor(bit.bxor(
  804.           tableInv0[getByte(origState[4],3)],
  805.           tableInv1[getByte(origState[3],2)]),
  806.           tableInv2[getByte(origState[2],1)]),
  807.           tableInv3[getByte(origState[1],0)])
  808.   end
  809.   --
  810.   -- do last decryption round
  811.   --
  812.   local function doInvLastRound(origState, dstState)
  813.     dstState[1] = putByte(iSBox[getByte(origState[1],3)], 3)
  814.           + putByte(iSBox[getByte(origState[4],2)], 2)
  815.           + putByte(iSBox[getByte(origState[3],1)], 1)
  816.           + putByte(iSBox[getByte(origState[2],0)], 0)
  817.     dstState[2] = putByte(iSBox[getByte(origState[2],3)], 3)
  818.           + putByte(iSBox[getByte(origState[1],2)], 2)
  819.           + putByte(iSBox[getByte(origState[4],1)], 1)
  820.           + putByte(iSBox[getByte(origState[3],0)], 0)
  821.     dstState[3] = putByte(iSBox[getByte(origState[3],3)], 3)
  822.           + putByte(iSBox[getByte(origState[2],2)], 2)
  823.           + putByte(iSBox[getByte(origState[1],1)], 1)
  824.           + putByte(iSBox[getByte(origState[4],0)], 0)
  825.     dstState[4] = putByte(iSBox[getByte(origState[4],3)], 3)
  826.           + putByte(iSBox[getByte(origState[3],2)], 2)
  827.           + putByte(iSBox[getByte(origState[2],1)], 1)
  828.           + putByte(iSBox[getByte(origState[1],0)], 0)
  829.   end
  830.   --
  831.   -- encrypts 16 Bytes
  832.   -- key           encryption key schedule
  833.   -- input         array with input data
  834.   -- inputOffset   start index for input
  835.   -- output        array for encrypted data
  836.   -- outputOffset  start index for output
  837.   --
  838.   local function encrypt(key, input, inputOffset, output, outputOffset)
  839.     --default parameters
  840.     inputOffset = inputOffset or 1
  841.     output = output or {}
  842.     outputOffset = outputOffset or 1
  843.     local state = {}
  844.     local tmpState = {}
  845.     if (key[KEY_TYPE] ~= ENCRYPTION_KEY) then
  846.       error("No encryption key: " .. tostring(key[KEY_TYPE]) .. ", expected " .. ENCRYPTION_KEY)
  847.       return
  848.     end
  849.     state = util.bytesToInts(input, inputOffset, 4)
  850.     addRoundKey(state, key, 0)
  851.     local round = 1
  852.     while (round < key[ROUNDS] - 1) do
  853.       -- do a double round to save temporary assignments
  854.       doRound(state, tmpState)
  855.       addRoundKey(tmpState, key, round)
  856.       round = round + 1
  857.       doRound(tmpState, state)
  858.       addRoundKey(state, key, round)
  859.       round = round + 1
  860.     end
  861.     doRound(state, tmpState)
  862.     addRoundKey(tmpState, key, round)
  863.     round = round +1
  864.     doLastRound(tmpState, state)
  865.     addRoundKey(state, key, round)
  866.     util.sleepCheckIn()
  867.     return util.intsToBytes(state, output, outputOffset)
  868.   end
  869.   --
  870.   -- decrypt 16 bytes
  871.   -- key           decryption key schedule
  872.   -- input         array with input data
  873.   -- inputOffset   start index for input
  874.   -- output        array for decrypted data
  875.   -- outputOffset  start index for output
  876.   ---
  877.   local function decrypt(key, input, inputOffset, output, outputOffset)
  878.     -- default arguments
  879.     inputOffset = inputOffset or 1
  880.     output = output or {}
  881.     outputOffset = outputOffset or 1
  882.     local state = {}
  883.     local tmpState = {}
  884.     if (key[KEY_TYPE] ~= DECRYPTION_KEY) then
  885.       error("No decryption key: " .. tostring(key[KEY_TYPE]))
  886.       return
  887.     end
  888.     state = util.bytesToInts(input, inputOffset, 4)
  889.     addRoundKey(state, key, key[ROUNDS])
  890.     local round = key[ROUNDS] - 1
  891.     while (round > 2) do
  892.       -- do a double round to save temporary assignments
  893.       doInvRound(state, tmpState)
  894.       addRoundKey(tmpState, key, round)
  895.       round = round - 1
  896.       doInvRound(tmpState, state)
  897.       addRoundKey(state, key, round)
  898.       round = round - 1
  899.     end
  900.     doInvRound(state, tmpState)
  901.     addRoundKey(tmpState, key, round)
  902.     round = round - 1
  903.     doInvLastRound(tmpState, state)
  904.     addRoundKey(state, key, round)
  905.     util.sleepCheckIn()
  906.     return util.intsToBytes(state, output, outputOffset)
  907.   end
  908.  
  909.   -- calculate all tables when loading this file
  910.   calcSBox()
  911.   calcRoundTables()
  912.   calcInvRoundTables()
  913.  
  914.   return {
  915.     ROUNDS = ROUNDS,
  916.     KEY_TYPE = KEY_TYPE,
  917.     ENCRYPTION_KEY = ENCRYPTION_KEY,
  918.     DECRYPTION_KEY = DECRYPTION_KEY,
  919.     expandEncryptionKey = expandEncryptionKey,
  920.     expandDecryptionKey = expandDecryptionKey,
  921.     encrypt = encrypt,
  922.     decrypt = decrypt,
  923.   }
  924.   end)
  925.  
  926.   local buffer=_W(function(_ENV, ...)
  927.   local function new ()
  928.     return {}
  929.   end
  930.  
  931.   local function addString (stack, s)
  932.     table.insert(stack, s)
  933.   end
  934.  
  935.   local function toString (stack)
  936.     return table.concat(stack)
  937.   end
  938.  
  939.   return {
  940.     new = new,
  941.     addString = addString,
  942.     toString = toString,
  943.   }
  944.   end)
  945.  
  946.   ciphermode=_W(function(_ENV, ...)
  947.   local public = {}
  948.   --
  949.   -- Encrypt strings
  950.   -- key - byte array with key
  951.   -- string - string to encrypt
  952.   -- modefunction - function for cipher mode to use
  953.   --
  954.   local random, unpack = math.random, unpack or table.unpack
  955.   function public.encryptString(key, data, modeFunction, iv)
  956.     if iv then
  957.       local ivCopy = {}
  958.       for i = 1, 16 do ivCopy[i] = iv[i] end
  959.       iv = ivCopy
  960.     else
  961.       iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  962.     end
  963.     local keySched = aes.expandEncryptionKey(key)
  964.     local encryptedData = buffer.new()
  965.     for i = 1, #data/16 do
  966.       local offset = (i-1)*16 + 1
  967.       local byteData = {string.byte(data,offset,offset +15)}
  968.       iv = modeFunction(keySched, byteData, iv)
  969.       buffer.addString(encryptedData, string.char(unpack(byteData)))
  970.     end
  971.     return buffer.toString(encryptedData)
  972.   end
  973.   --
  974.   -- the following 4 functions can be used as
  975.   -- modefunction for encryptString
  976.   --
  977.   -- Electronic code book mode encrypt function
  978.   function public.encryptECB(keySched, byteData, iv)
  979.     aes.encrypt(keySched, byteData, 1, byteData, 1)
  980.   end
  981.  
  982.   -- Cipher block chaining mode encrypt function
  983.   function public.encryptCBC(keySched, byteData, iv)
  984.     util.xorIV(byteData, iv)
  985.     aes.encrypt(keySched, byteData, 1, byteData, 1)
  986.     return byteData
  987.   end
  988.  
  989.   -- Output feedback mode encrypt function
  990.   function public.encryptOFB(keySched, byteData, iv)
  991.     aes.encrypt(keySched, iv, 1, iv, 1)
  992.     util.xorIV(byteData, iv)
  993.     return iv
  994.   end
  995.  
  996.   -- Cipher feedback mode encrypt function
  997.   function public.encryptCFB(keySched, byteData, iv)
  998.     aes.encrypt(keySched, iv, 1, iv, 1)
  999.     util.xorIV(byteData, iv)
  1000.     return byteData
  1001.   end
  1002.  
  1003.   function public.encryptCTR(keySched, byteData, iv)
  1004.     local nextIV = {}
  1005.     for j = 1, 16 do nextIV[j] = iv[j] end
  1006.     aes.encrypt(keySched, iv, 1, iv, 1)
  1007.     util.xorIV(byteData, iv)
  1008.     util.increment(nextIV)
  1009.     return nextIV
  1010.   end
  1011.   --
  1012.   -- Decrypt strings
  1013.   -- key - byte array with key
  1014.   -- string - string to decrypt
  1015.   -- modefunction - function for cipher mode to use
  1016.   --
  1017.   function public.decryptString(key, data, modeFunction, iv)
  1018.     if iv then
  1019.       local ivCopy = {}
  1020.       for i = 1, 16 do ivCopy[i] = iv[i] end
  1021.       iv = ivCopy
  1022.     else
  1023.       iv = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
  1024.     end
  1025.     local keySched
  1026.     if modeFunction == public.decryptOFB or modeFunction == public.decryptCFB or modeFunction == public.decryptCTR then
  1027.       keySched = aes.expandEncryptionKey(key)
  1028.     else
  1029.       keySched = aes.expandDecryptionKey(key)
  1030.     end
  1031.     local decryptedData = buffer.new()
  1032.     for i = 1, #data/16 do
  1033.       local offset = (i-1)*16 + 1
  1034.       local byteData = {string.byte(data,offset,offset +15)}
  1035.       iv = modeFunction(keySched, byteData, iv)
  1036.       buffer.addString(decryptedData, string.char(unpack(byteData)))
  1037.     end
  1038.     return buffer.toString(decryptedData)
  1039.   end
  1040.   --
  1041.   -- the following 4 functions can be used as
  1042.   -- modefunction for decryptString
  1043.   --
  1044.   -- Electronic code book mode decrypt function
  1045.   function public.decryptECB(keySched, byteData, iv)
  1046.     aes.decrypt(keySched, byteData, 1, byteData, 1)
  1047.     return iv
  1048.   end
  1049.  
  1050.   -- Cipher block chaining mode decrypt function
  1051.   function public.decryptCBC(keySched, byteData, iv)
  1052.     local nextIV = {}
  1053.     for j = 1, 16 do nextIV[j] = byteData[j] end
  1054.     aes.decrypt(keySched, byteData, 1, byteData, 1)
  1055.     util.xorIV(byteData, iv)
  1056.     return nextIV
  1057.   end
  1058.  
  1059.   -- Output feedback mode decrypt function
  1060.   function public.decryptOFB(keySched, byteData, iv)
  1061.     aes.encrypt(keySched, iv, 1, iv, 1)
  1062.     util.xorIV(byteData, iv)
  1063.     return iv
  1064.   end
  1065.  
  1066.   -- Cipher feedback mode decrypt function
  1067.   function public.decryptCFB(keySched, byteData, iv)
  1068.     local nextIV = {}
  1069.     for j = 1, 16 do nextIV[j] = byteData[j] end
  1070.     aes.encrypt(keySched, iv, 1, iv, 1)
  1071.     util.xorIV(byteData, iv)
  1072.     return nextIV
  1073.   end
  1074.  
  1075.   public.decryptCTR = public.encryptCTR
  1076.   return public
  1077.   end)
  1078.  
  1079.   -- Simple API for encrypting strings.
  1080.   --
  1081.   AES128 = 16
  1082.   AES192 = 24
  1083.   AES256 = 32
  1084.   ECBMODE = 1
  1085.   CBCMODE = 2
  1086.   OFBMODE = 3
  1087.   CFBMODE = 4
  1088.   CTRMODE = 4
  1089.  
  1090.   local function pwToKey(password, keyLength, iv)
  1091.     local padLength = keyLength
  1092.     if (keyLength == AES192) then
  1093.       padLength = 32
  1094.     end
  1095.     if (padLength > #password) then
  1096.       local postfix = ""
  1097.       for i = 1,padLength - #password do
  1098.         postfix = postfix .. string.char(0)
  1099.       end
  1100.       password = password .. postfix
  1101.     else
  1102.       password = string.sub(password, 1, padLength)
  1103.     end
  1104.     local pwBytes = {string.byte(password,1,#password)}
  1105.     password = ciphermode.encryptString(pwBytes, password, ciphermode.encryptCBC, iv)
  1106.     password = string.sub(password, 1, keyLength)
  1107.     return {string.byte(password,1,#password)}
  1108.   end
  1109.   --
  1110.   -- Encrypts string data with password password.
  1111.   -- password  - the encryption key is generated from this string
  1112.   -- data      - string to encrypt (must not be too large)
  1113.   -- keyLength - length of aes key: 128(default), 192 or 256 Bit
  1114.   -- mode      - mode of encryption: ecb, cbc(default), ofb, cfb
  1115.   --
  1116.   -- mode and keyLength must be the same for encryption and decryption.
  1117.   --
  1118.   function encrypt(password, data, keyLength, mode, iv)
  1119.     assert(password ~= nil, "Empty password.")
  1120.     assert(data ~= nil, "Empty data.")
  1121.     local mode = mode or CBCMODE
  1122.     local keyLength = keyLength or AES128
  1123.     local key = pwToKey(password, keyLength, iv)
  1124.     local paddedData = util.padByteString(data)
  1125.     if mode == ECBMODE then
  1126.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptECB, iv)
  1127.     elseif mode == CBCMODE then
  1128.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptCBC, iv)
  1129.     elseif mode == OFBMODE then
  1130.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptOFB, iv)
  1131.     elseif mode == CFBMODE then
  1132.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptCFB, iv)
  1133.     elseif mode == CTRMODE then
  1134.       return ciphermode.encryptString(key, paddedData, ciphermode.encryptCTR, iv)
  1135.     else
  1136.       error("Unknown mode", 2)
  1137.     end
  1138.   end
  1139.   --
  1140.   -- Decrypts string data with password password.
  1141.   -- password  - the decryption key is generated from this string
  1142.   -- data      - string to encrypt
  1143.   -- keyLength - length of aes key: 128(default), 192 or 256 Bit
  1144.   -- mode      - mode of decryption: ecb, cbc(default), ofb, cfb
  1145.   --
  1146.   -- mode and keyLength must be the same for encryption and decryption.
  1147.   --
  1148.   function decrypt(password, data, keyLength, mode, iv)
  1149.     local mode = mode or CBCMODE
  1150.     local keyLength = keyLength or AES128
  1151.     local key = pwToKey(password, keyLength, iv)
  1152.     local plain
  1153.     if mode == ECBMODE then
  1154.       plain = ciphermode.decryptString(key, data, ciphermode.decryptECB, iv)
  1155.     elseif mode == CBCMODE then
  1156.       plain = ciphermode.decryptString(key, data, ciphermode.decryptCBC, iv)
  1157.     elseif mode == OFBMODE then
  1158.       plain = ciphermode.decryptString(key, data, ciphermode.decryptOFB, iv)
  1159.     elseif mode == CFBMODE then
  1160.       plain = ciphermode.decryptString(key, data, ciphermode.decryptCFB, iv)
  1161.     elseif mode == CTRMODE then
  1162.       plain = ciphermode.decryptString(key, data, ciphermode.decryptCTR, iv)
  1163.     else
  1164.       error("Unknown mode", 2)
  1165.     end
  1166.     result = util.unpadByteString(plain)
  1167.     if (result == nil) then
  1168.       return nil
  1169.     end
  1170.     return result
  1171.   end
  1172. end
  1173.  
  1174. local function saveData()
  1175.   local clientConfig = fs.open(config, "w") or error("saveData(): Cannot open " .. config .. " for writing", 0)
  1176.   clientConfig.write(textutils.serialize(ccSettings))
  1177.   clientConfig.close()
  1178. end
  1179.  
  1180. local function doAction()
  1181.   if (thisCommand == "ON"  or thisCommand == "CLOSED") and not ccSettings.lockState then
  1182.     rs.setOutput(ccSettings.side, onState)
  1183.     deviceState = thisCommand
  1184.     ccSettings.lastState = onState
  1185.     saveData()
  1186.     return true
  1187.   elseif (thisCommand == "OFF" or thisCommand == "OPEN") and not ccSettings.lockState then
  1188.     rs.setOutput(ccSettings.side, offState)
  1189.     deviceState = thisCommand
  1190.     ccSettings.lastState = offState
  1191.     if autoClose then closeTimer = os.startTimer(autoDelay) end
  1192.     saveData()
  1193.     return true
  1194.   elseif thisCommand == "LOCKED" or thisCommand == "UNLOCK" then
  1195.     ccSettings.lockState = thisCommand == "LOCKED"
  1196.     if not ccSettings.lockState and (deviceState == "OPEN" or deviceState == "OFF") and autoClose then
  1197.       closeTimer = os.startTimer(autoDelay)
  1198.     end
  1199.     saveData()
  1200.     return true
  1201.   elseif thisCommand == "WiReQRY" then
  1202.     local rsOut = rs.getOutput(ccSettings.side)
  1203.     if deviceType == "Door" then
  1204.       deviceState = rsOut and "OPEN" or "CLOSED"
  1205.     elseif deviceType == "Piston" or deviceType == "eDoor" then
  1206.       deviceState = rsOut and "CLOSED" or "OPEN"
  1207.     elseif deviceType == "Create" then
  1208.       deviceState = rsOut and "OFF" or "ON"
  1209.     else
  1210.       deviceState = rsOut and "ON" or "OFF"
  1211.     end
  1212.     return true
  1213.   end
  1214.   return false
  1215. end
  1216.  
  1217. local function netSend()
  1218.   local dataPack = textutils.serialize({
  1219.     program = "WiRe";
  1220.     cc = tonumber(thisCC);
  1221.     name = ccSettings.name;
  1222.     color = ccSettings.color;
  1223.     deviceType = deviceType;
  1224.     deviceState = deviceState;
  1225.     lockState = ccSettings.lockState;
  1226.     quietCount = 0;
  1227.     loc = loc;
  1228.   })
  1229.   if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
  1230.   local encKey = tostring(server) .. "WiRe!Comms" .. thisCC
  1231.   local encryptedPackage = encode(encrypt(encKey, dataPack))
  1232.   rednet.send(server, encryptedPackage, network)
  1233. end
  1234.  
  1235. local function netReceive()
  1236.   local id, newCmdData, goodData, encryptedMessage, decryptedMessage, decodedMessage, encKey, success
  1237.   while true do
  1238.     if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
  1239.     newCmdData = { }
  1240.     id, encryptedMessage = rednet.receive(network)
  1241.     goodData = false
  1242.     if type(encryptedMessage) == "string" then
  1243.       success, decodedMessage = pcall(decode, encryptedMessage)
  1244.       if success and type(decodedMessage) == "string" then
  1245.         encKey = thisCC .. "WiRe!Comms" .. tostring(id)
  1246.         success, decryptedMessage = pcall(decrypt, encKey, decodedMessage)
  1247.         if success and type(decryptedMessage) == "string" then
  1248.           success, newCmdData = pcall(textutils.unserialize, decryptedMessage)
  1249.           if success and type(newCmdData) == "table" and newCmdData.program then
  1250.             if newCmdData.program == "WiRe" and newCmdData.cc == id and id == server and newCmdData.color == ccSettings.color then
  1251.               if validStates[newCmdData.cmd] then
  1252.                 thisCommand = newCmdData.cmd
  1253.                 goodData = true
  1254.               end
  1255.             end
  1256.           end
  1257.         else
  1258.           encKey = tostring(id) .. "WiRe!Comms" .. tostring(id)
  1259.           success, decryptedMessage = pcall(decrypt, encKey, decodedMessage)
  1260.           if success and type(decryptedMessage) == "string" then
  1261.             success, newCmdData = pcall(textutils.unserialize, decryptedMessage)
  1262.             if success and type(newCmdData) == "table" and newCmdData.program then
  1263.               if newCmdData.program == "WiRe" and newCmdData.cc == id and id == server and newCmdData.color == ccSettings.color then
  1264.                 if validStates[newCmdData.cmd] then
  1265.                   thisCommand = newCmdData.cmd
  1266.                   goodData = true
  1267.                 end
  1268.               end
  1269.             end
  1270.           end
  1271.         end
  1272.       end
  1273.     end
  1274.     if goodData then
  1275.       ccSuccess = doAction()
  1276.       netSend()
  1277.     else
  1278.       thisCommand = "Noise"
  1279.       ccSuccess = false
  1280.     end
  1281.     updateScreens()
  1282.   end
  1283. end
  1284.  
  1285. do
  1286.   local colorBurst = {
  1287.     Purple = purple;
  1288.     Magenta = magenta;
  1289.     Blue = blue;
  1290.     Sky = sky;
  1291.     Cyan = cyan;
  1292.     Green = green;
  1293.     Lime = lime;
  1294.     Red = red;
  1295.     Orange = orange;
  1296.     Yellow = yellow;
  1297.     Brown = brown;
  1298.     Silver = silver;
  1299.     Gray = gray;
  1300.     White = white;
  1301.     Black = white;
  1302.   }
  1303.  
  1304.   local labels = {
  1305.     [1] = { "Name", 1, 3 };
  1306.     [2] = { "Note:", 1, 4 };
  1307.     [3] = { "Group:", 1, 6 };
  1308.     [4] = { "cc#", 1, 8 };
  1309.     [5] = { "Server cc#", 1, 9 };
  1310.     [6] = { "Modem:", 1, 11 };
  1311.     [7] = { "Redstone:", 1, 12 };
  1312.     [8] = { "Device Type:", 1, 14 };
  1313.     [9] = { "Current State:", 1, 15 };
  1314.     [10] = { "Last Command:", 1, 17 };
  1315.     [11] = { "Success:", 1, 18 };
  1316.     [12] = { "Peripherals", 28, 3 };
  1317.     [13] = { "Location: x:", 28, 11 };
  1318.     [14] = { "y:", 38, 12 };
  1319.     [15] = { "z:", 38, 13 };
  1320.     [16] = { "Check-in:", 31, 17 };
  1321.   }
  1322.  
  1323.   staticTermScreen = function()
  1324.     local hText = "WiRe Client " .. WiReCver
  1325.     local spacer = (termX - #hText) / 2
  1326.     term.setBackgroundColor(blue)
  1327.     term.setTextColor(white)
  1328.     term.setCursorPos(1, 1)
  1329.     term.write(string.rep(" ", math.floor(spacer)) .. hText .. string.rep(" ", math.ceil(spacer)))
  1330.     term.setBackgroundColor(black)
  1331.     term.setTextColor(silver)
  1332.     for i = 1, 16 do
  1333.       term.setCursorPos(labels[i][2], labels[i][3])
  1334.       term.write(labels[i][1])
  1335.     end
  1336.     term.setTextColor(white)
  1337.     term.setCursorPos(7, 3)
  1338.     term.write(ccSettings.name)
  1339.     term.setCursorPos(7, 4)
  1340.     term.write(ccSettings.note)
  1341.     term.setCursorPos(5, 8)
  1342.     term.write(thisCC)
  1343.     term.setCursorPos(12, 9)
  1344.     term.write(tostring(server))
  1345.     term.setCursorPos(11, 11)
  1346.     term.write(modemSide)
  1347.     term.setCursorPos(11, 12)
  1348.     term.write(ccSettings.side)
  1349.     term.setCursorPos(16, 14)
  1350.     term.write(deviceType)
  1351.     if mon[1] then
  1352.       term.setCursorPos(28, 5)
  1353.       term.write("Monitor x" .. tostring(#mon))
  1354.     end
  1355.     term.setCursorPos(41, 11)
  1356.     term.write(tostring(loc.x))
  1357.     term.setCursorPos(41, 12)
  1358.     term.write(tostring(loc.y))
  1359.     term.setCursorPos(41, 13)
  1360.     term.write(tostring(loc.z))
  1361.     term.setTextColor(colorBurst[ccSettings.color] or silver)
  1362.     term.setCursorPos(8, 6)
  1363.     term.write(ccSettings.color)
  1364.   end
  1365. end
  1366.  
  1367. local function termScreen()
  1368.   term.setCursorPos(16, 15)
  1369.   term.setTextColor(switchStates[deviceState][1] or yellow)
  1370.   term.write(deviceState)
  1371.   term.setTextColor(gray)
  1372.   term.write(" | ")
  1373.   term.setTextColor(ccSettings.lockState and red or green)
  1374.   term.write(ccSettings.lockState and "Locked       " or "Unlocked       ")
  1375.   term.setCursorPos(15, 17)
  1376.   term.setTextColor(white)
  1377.   term.write(thisCommand .. string.rep(" ", 8))
  1378.   term.setCursorPos(15, 18)
  1379.   term.setTextColor(ccSuccess and green or red)
  1380.   term.write(tostring(ccSuccess) .. " ")
  1381. end
  1382.  
  1383. local function helpScreen()
  1384.   local hText = "WiRe Client Help"
  1385.   local xPos, spacer = math.floor(termX / 2), (termX - #hText) / 2
  1386.   term.setBackgroundColor(white)
  1387.   term.clear()
  1388.   term.setBackgroundColor(blue)
  1389.   term.setTextColor(white)
  1390.   term.setCursorPos(1, 1)
  1391.   term.write(string.rep(" ", math.floor(spacer)) .. hText .. string.rep(" ", math.ceil(spacer)))
  1392.   term.setBackgroundColor(white)
  1393.   term.setTextColor(black)
  1394.   term.setCursorPos(xPos - 8, 5)
  1395.   term.write("'q' to quit client")
  1396.   term.setCursorPos(xPos - 12, 7)
  1397.   term.write("'F1' to display/exit help")
  1398. end
  1399.  
  1400. do
  1401.   local function touchScreen()
  1402.     local line, symbol = "     "
  1403.     for i = 1, #mon do
  1404.       symbol = ccSettings.lockState and " [0] " or (switchStates[deviceState][3] or " [X] ")
  1405.       mon[i].setBackgroundColor(ccSettings.lockState and mred or (switchStates[deviceState][2] or myellow))
  1406.       mon[i].setTextColor(mwhite)
  1407.       for y = 2, 4 do
  1408.         mon[i].setCursorPos(2, y)
  1409.         mon[i].write(y == 3 and symbol or line)
  1410.       end
  1411.     end
  1412.   end
  1413.  
  1414.   updateScreens = function()
  1415.     if not tArgs[1] and not help then termScreen() end
  1416.     if thisCommand ~= "Noise" and mon[1] then touchScreen() end
  1417.   end
  1418. end
  1419.  
  1420. local function clearMonitors()
  1421.   for i = 1, #mon do
  1422.     mon[i].setBackgroundColor(mblack)
  1423.     mon[i].clear()
  1424.   end
  1425. end
  1426.  
  1427. local function clearTerm()
  1428.   term.setBackgroundColor(black)
  1429.   term.setTextColor(white)
  1430.   term.clear()
  1431.   term.setCursorPos(1, 1)
  1432. end
  1433.  
  1434. local function shutDown()
  1435.   deviceState = "OFFLINE"
  1436.   kernelState = false
  1437.   netSend()
  1438.   if rednet.isOpen(modemSide) then rednet.close(modemSide) end
  1439.   if mon[1] then clearMonitors() end
  1440. end
  1441.  
  1442. local function foregroundShell()
  1443.   clearTerm()
  1444.   if fs.exists(tArgs[1]) then
  1445.     local unpack = unpack or table.unpack
  1446.       shell.run(unpack(tArgs))
  1447.     clearTerm()
  1448.   else
  1449.     term.write(tArgs[1] .. " missing")
  1450.     term.setCursorPos(1, 3)
  1451.   end
  1452.   shutDown()
  1453.   term.write("WiRe Client is OFFLINE")
  1454.   term.setCursorPos(1, 5)
  1455. end
  1456.  
  1457. local function dataPoller()
  1458.   local _, timer, thisTime
  1459.   while true do
  1460.     _, timer = os.pullEvent("timer")
  1461.     thisCommand = "Noise"
  1462.     ccSuccess = false
  1463.     if timer == pollTimer then
  1464.       if kernelState then
  1465.         thisCommand = "WiReQRY"
  1466.         pollTimer = os.startTimer(3.25)
  1467.       end
  1468.     elseif timer == closeTimer then
  1469.       if not ccSettings.lockState then
  1470.         thisCommand = deviceType == "Energy" and "ON" or "CLOSED"
  1471.       end
  1472.     end
  1473.     if thisCommand == "WiReQRY" or thisCommand == "ON" or thisCommand == "CLOSED" then
  1474.       ccSuccess = doAction()
  1475.       if thisCommand == "WiReQRY" then
  1476.         thisTime = tostring(os.time())
  1477.         if (tonumber(thisCC) % 2 == 0 and tonumber(thisTime:sub(#thisTime)) % 2 == 0) or (tonumber(thisCC) % 2 ~= 0 and tonumber(thisTime:sub(#thisTime)) % 2 ~= 0) then
  1478.           if not tArgs[1] then
  1479.             term.setCursorPos(41, 17)
  1480.             term.setTextColor(green)
  1481.             term.write("True ")
  1482.           end
  1483.           netSend()
  1484.         else
  1485.           if not tArgs[1] then
  1486.             term.setCursorPos(41, 17)
  1487.             term.setTextColor(red)
  1488.             term.write("False")
  1489.           end
  1490.           os.cancelTimer(pollTimer)
  1491.           pollTimer = os.startTimer(0.25)
  1492.         end
  1493.       else
  1494.         netSend()
  1495.       end
  1496.     end
  1497.     if thisCommand ~= "Noise" then updateScreens() end
  1498.   end
  1499. end
  1500.  
  1501. local function userInput()
  1502.   local event, data
  1503.   while true do
  1504.     event, data = os.pullEvent()
  1505.     if event == "key" and data == keys.f1 then
  1506.       help = not help
  1507.       if help then
  1508.         helpScreen()
  1509.       else
  1510.         term.setBackgroundColor(black)
  1511.         term.clear()
  1512.         staticTermScreen()
  1513.         termScreen()
  1514.       end
  1515.     elseif event == "char" and data:lower() == "q" then
  1516.       shutDown()
  1517.       clearTerm()
  1518.       term.write("WiRe Client is OFFLINE")
  1519.       term.setCursorPos(1, 3)
  1520.       return
  1521.     end
  1522.   end
  1523. end
  1524.  
  1525. local function monTouch()
  1526.   while true do
  1527.     os.pullEvent("monitor_touch")
  1528.     if not ccSettings.lockState then
  1529.       thisCommand = validStates[deviceState] or "Touch"
  1530.       ccSuccess = doAction()
  1531.       netSend()
  1532.       updateScreens()
  1533.     end
  1534.   end
  1535. end
  1536.  
  1537. local function initError(missing, device)
  1538.   if modemSide and rednet.isOpen(modemSide) then rednet.close(modemSide) end
  1539.   if mon[1] then clearMonitors() end
  1540.   term.clear()
  1541.   term.setTextColor(red)
  1542.   term.setCursorPos(1, 2)
  1543.   print("No " .. missing .. " detected!")
  1544.   print("WiRe Client REQUIRES")
  1545.   print(device .. ".")
  1546.   term.setTextColor(white)
  1547.   term.setCursorPos(1, 6)
  1548. end
  1549.  
  1550. local function firstRun()
  1551.   term.clear()
  1552.   local gotModem = false
  1553.   for _, side in pairs(rs.getSides()) do
  1554.     if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then
  1555.       gotModem = true
  1556.       break
  1557.     end
  1558.   end
  1559.   if not gotModem then return initError("modem", "a modem") end
  1560.   --# Set computer name
  1561.   term.setCursorPos(2, 2)
  1562.   term.write("Please name this device")
  1563.   term.setCursorPos(3, 3)
  1564.   term.write("(12 characters or less)")
  1565.   repeat
  1566.     term.setCursorPos(2, 4)
  1567.     local newName = read()
  1568.     newName = newName and newName:sub(1, 12) or ""
  1569.     ccSettings.name = newName
  1570.   until newName ~= ""
  1571.   --# Set computer label
  1572.   if not os.getComputerLabel() then
  1573.     os.setComputerLabel(ccSettings.name)
  1574.   end
  1575.   --# Set computer description
  1576.   term.clear()
  1577.   term.setCursorPos(2, 2)
  1578.   term.write("Please type in a short")
  1579.   term.setCursorPos(2, 3)
  1580.   term.write("client description")
  1581.   repeat
  1582.     term.setCursorPos(2, 5)
  1583.     local newDesc = read()
  1584.     ccSettings.note = newDesc
  1585.   until newDesc ~= ""
  1586.   --# Select device type
  1587.   local deviceTypes = {
  1588.     c = { "Create", false, true };
  1589.     d = { "Door", false, true };
  1590.     f = { "eDoor", true, false };
  1591.     p = { "Piston", true, false };
  1592.     e = { "Energy", true, false };
  1593.   }
  1594.   term.clear()
  1595.   term.setCursorPos(2, 2)
  1596.   term.write("Is this a Create device?          [c]")
  1597.   term.setCursorPos(2, 3)
  1598.   term.write("Is this a physical Door/Hatch?    [d]")
  1599.   term.setCursorPos(2, 4)
  1600.   term.write("A Forcefield or Energy Door?      [f]")
  1601.   term.setCursorPos(2, 5)
  1602.   term.write("A Piston door or Piston hatch?    [p]")
  1603.   term.setCursorPos(2, 6)
  1604.   term.write("Energy Device/Barrier/Lamp/Other? [e]")
  1605.   term.setCursorPos(2, 8)
  1606.   term.write("[d/f/p] - States are 'OPEN/CLOSED'")
  1607.   term.setCursorPos(2, 10)
  1608.   term.write("Door: OPEN = RS(true) / CLOSED = RS(false)")
  1609.   term.setCursorPos(2, 11)
  1610.   term.write("eDoor: OPEN = RS(false) / CLOSED = RS(true)")
  1611.   term.setCursorPos(2, 12)
  1612.   term.write("Piston: OPEN = RS(false) / CLOSED = RS(true)")
  1613.   term.setCursorPos(2, 14)
  1614.   term.write("[e] - States are 'OFF/ON'")
  1615.   term.setCursorPos(2, 16)
  1616.   term.write("Energy: OFF = RS(false) / ON = RS(true)")
  1617.   repeat
  1618.     term.setCursorPos(2, 18)
  1619.     local newType = string.lower(read())
  1620.     if deviceTypes[newType] then
  1621.       deviceType = deviceTypes[newType][1]
  1622.       onState = deviceTypes[newType][2]
  1623.       offState = deviceTypes[newType][3]
  1624.       ccSettings.onState = onState
  1625.       ccSettings.offState = offState
  1626.       ccSettings.deviceType = deviceType
  1627.     end
  1628.   until deviceTypes[newType]
  1629.   --# Select auto-close setting
  1630.   term.clear()
  1631.   term.setCursorPos(2, 2)
  1632.   if deviceType == "Door" or deviceType == "eDoor" or deviceType == "Piston" then
  1633.     term.write("Would you like the door or piston to")
  1634.     term.setCursorPos(2, 3)
  1635.     term.write("automatically close shortly after")
  1636.     term.setCursorPos(2, 4)
  1637.     term.write("being opened? [y/n]")
  1638.   else
  1639.     term.write("Would you like the device to")
  1640.     term.setCursorPos(2, 3)
  1641.     term.write("automatically re-activate shortly")
  1642.     term.setCursorPos(2, 4)
  1643.     term.write("after being deactivated? [y/n]")
  1644.   end
  1645.   term.setCursorPos(2, 6)
  1646.   local closeRule = string.lower(read())
  1647.   autoClose = closeRule:sub(1, 1) == "y"
  1648.   ccSettings.autoClose = autoClose
  1649.   --# Select auto-close delay
  1650.   if autoClose then
  1651.     term.clear()
  1652.     term.setCursorPos(2, 2)
  1653.     term.write("How many seconds should the")
  1654.     term.setCursorPos(2, 3)
  1655.     if deviceType == "Door" or deviceType == "eDoor" or deviceType == "Piston" then
  1656.       term.write("door or piston stay open before closing")
  1657.     else
  1658.       term.write("device stay off before reactivating")
  1659.     end
  1660.     term.setCursorPos(2, 4)
  1661.     term.write("automatically?")
  1662.     repeat
  1663.       term.setCursorPos(2, 6)
  1664.       local closeTime = tonumber(read())
  1665.       if closeTime then
  1666.         autoDelay = closeTime
  1667.         ccSettings.autoDelay = autoDelay
  1668.       end
  1669.     until closeTime
  1670.   end
  1671.   --# Select default startup state
  1672.   term.clear()
  1673.   term.setCursorPos(2, 1)
  1674.   term.write("What would you like the default")
  1675.   term.setCursorPos(2, 2)
  1676.   term.write("STARTUP state to be?")
  1677.   term.setCursorPos(2, 4)
  1678.   if deviceType == "Door" or deviceType == "eDoor" or deviceType == "Piston" then
  1679.     term.write("[p] Previous State or [c] CLOSED or [o] OPEN")
  1680.   else
  1681.     term.write("[p] Previous State or [n] ON or [f] OFF")
  1682.   end
  1683.   while true do
  1684.     term.setCursorPos(2, 5)
  1685.     local newStart = string.lower(read())
  1686.     if newStart == "o" or newStart == "c" or newStart == "n" or newStart == "f" or newStart == "p" then
  1687.       if newStart == "c" or newStart == "n" then
  1688.         defaultStart = onState
  1689.       elseif newStart == "o" or newStart == "f" then
  1690.         defaultStart = offState
  1691.       elseif newStart == "p" then
  1692.         defaultStart = "last"
  1693.         ccSettings.lastState = false
  1694.       end
  1695.       ccSettings.defaultStart = defaultStart
  1696.       break
  1697.     end
  1698.   end
  1699.   --# Select color
  1700.   local colorWheel = {
  1701.     P = "Purple";
  1702.     M = "Magenta";
  1703.     B = "Blue";
  1704.     S = "Sky";
  1705.     C = "Cyan";
  1706.     E = "Green";
  1707.     L = "Lime";
  1708.     R = "Red";
  1709.     O = "Orange";
  1710.     Y = "Yellow";
  1711.     N = "Brown";
  1712.     K = "Black";
  1713.     G = "Gray";
  1714.     I = "Silver";
  1715.     W = "White";
  1716.   }
  1717.   term.clear()
  1718.   term.setCursorPos(2, 1)
  1719.   term.write("Please select the network group")
  1720.   term.setCursorPos(2, 2)
  1721.   if deviceType == "Door" or device == "eDoor" then
  1722.     term.write("this door will belong to...")
  1723.   else
  1724.     term.write("this device will belong to...")
  1725.   end
  1726.   local ttY = 4
  1727.   for k, v in pairs(colorWheel) do
  1728.     term.setCursorPos(2, ttY)
  1729.     term.write(k .. " = " .. v)
  1730.     ttY = ttY + 1
  1731.   end
  1732.   repeat
  1733.     term.setCursorPos(32, 2)
  1734.     local newColor = string.upper(read())
  1735.     ccSettings.color = colorWheel[newColor:sub(1, 1)]
  1736.   until colorWheel[newColor:sub(1, 1)]
  1737.   --# Select redstone output side
  1738.   local theseSides = { "top", "bottom", "left", "right", "front", "back" }
  1739.   term.clear()
  1740.   term.setCursorPos(2, 2)
  1741.   term.write("Select the redstone output side")
  1742.   local yPos = 3
  1743.   for num, side in pairs(theseSides) do
  1744.     yPos = yPos + 1
  1745.     term.setCursorPos(2, yPos)
  1746.     term.write(tostring(num) .. " = " .. string.upper(side:sub(1, 1)) .. side:sub(2))
  1747.   end
  1748.   repeat
  1749.     term.setCursorPos(2, 11)
  1750.     local rsSide = tonumber(read())
  1751.     ccSettings.side = theseSides[rsSide]
  1752.   until theseSides[rsSide]
  1753.   --# Should WiRe client get a GPS fix on startup?
  1754.   term.clear()
  1755.   term.setCursorPos(2, 1)
  1756.   term.write("Last question!")
  1757.   term.setCursorPos(2, 3)
  1758.   term.write("Do you want WiRe client to")
  1759.   term.setCursorPos(2, 4)
  1760.   term.write("aquire a GPS fix on startup? [y/n]")
  1761.   term.setCursorPos(2, 6)
  1762.   local getFix = string.lower(read())
  1763.   ccSettings.getGPSFix = getFix:sub(1, 1) == "y"
  1764.   if not fs.exists("/data") then fs.makeDir("/data") end
  1765.   saveData()
  1766.   return true
  1767. end
  1768.  
  1769. term.setBackgroundColor(black)
  1770. if pocket or turtle then error("Computer REQUIRED.", 0) end
  1771. if not fs.exists(config) then
  1772.   if not firstRun() then return end
  1773. end
  1774. term.clear()
  1775. term.setCursorPos(2, 2)
  1776. term.setTextColor(white)
  1777. term.write("Ingesting configuration data . . .")
  1778. local clientConfig = fs.open(config, "r") or error("initMe(): Cannot open " .. config .. " for reading", 0)
  1779. ccSettings = textutils.unserialize(clientConfig.readAll())
  1780. clientConfig.close()
  1781. if ccSettings.getFix ~= nil or ccSettings.deviceType == "Bridge" or not ccSettings.newColors then
  1782.   if ccSettings.getFix ~= nil then
  1783.     ccSettings.getGPSFix = ccSettings.getFix
  1784.     ccSettings.getFix = nil
  1785.   end
  1786.   if ccSettings.deviceType == "Bridge" then
  1787.     ccSettings.deviceType = "Energy"
  1788.   end
  1789.   if not ccSettings.newColors then
  1790.     if ccSettings.color == "lgray" or ccSettings.color == "Light Gray" then
  1791.       ccSettings.color = "Silver"
  1792.     elseif ccSettings.color == "lblue" or ccSettings.color == "Light Blue" then
  1793.       ccSettings.color = "Sky"
  1794.     end
  1795.     ccSettings.newColors = true
  1796.   end
  1797.   saveData()
  1798. end
  1799. term.setCursorPos(2, 4)
  1800. term.write("Configuring hardware . . .")
  1801. for _, side in pairs(rs.getSides()) do
  1802.   if peripheral.isPresent(side) then
  1803.     if peripheral.getType(side) == "monitor" and peripheral.call(side, "isColor") then
  1804.       mon[#mon + 1] = peripheral.wrap(side)
  1805.     elseif peripheral.getType(side) == "modem" then
  1806.       if peripheral.call(side, "isWireless") then
  1807.         modemSide = side
  1808.         if not rednet.isOpen(side) then rednet.open(side) end
  1809.       else
  1810.         for _, perp in pairs(peripheral.call(side, "getNamesRemote")) do
  1811.           if peripheral.getType(perp) == "monitor" and peripheral.call(perp, "isColor") then
  1812.             mon[#mon + 1] = peripheral.wrap(perp)
  1813.           elseif peripheral.getType(perp) == "computer" then
  1814.             modemSide = side
  1815.             if not rednet.isOpen(side) then rednet.open(side) end
  1816.           end
  1817.         end
  1818.       end
  1819.     end
  1820.   end
  1821. end
  1822. if not modemSide then return initError("modem", "a modem") end
  1823. if mon[1] then
  1824.   for i = 1, #mon do
  1825.     mon[i].setTextScale(0.5)
  1826.     mon[i].setBackgroundColor(mwhite)
  1827.     mon[i].setTextColor(mblack)
  1828.     mon[i].clear()
  1829.     mon[i].setCursorPos(2, 3)
  1830.     mon[i].write("Initializing...")
  1831.   end
  1832. end
  1833. term.setCursorPos(2, 6)
  1834. if ccSettings.getGPSFix then
  1835.   term.write("Acquiring GPS fix . . .")
  1836.   loc.x, loc.y, loc.z = gps.locate(2)
  1837.   term.setCursorPos(2, 8)
  1838. end
  1839. if not loc.x then
  1840.   loc.x, loc.y, loc.z = "No GPS Fix", "No GPS Fix", "No GPS Fix"
  1841. end
  1842. term.write("Looking for WiRe Server . . .")
  1843. network = "WiRe" .. ccSettings.color
  1844. for i = 1, 3 do
  1845.   server = rednet.lookup(network, ccSettings.color)
  1846.   if server then break elseif i ~= 3 then sleep(2) end
  1847. end
  1848. if not server then
  1849.   term.clear()
  1850.   term.setTextColor(red)
  1851.   term.setCursorPos(1, 2)
  1852.   print("No server detected!")
  1853.   print("WiRe Client REQUIRES a WiRe Server.\n")
  1854.   print("Output set to 'Default Start'")
  1855.   if rednet.isOpen(modemSide) then rednet.close(modemSide) end
  1856.   if mon[1] then clearMonitors() end
  1857.   term.setCursorPos(1, 9)
  1858. end
  1859. deviceType = ccSettings.deviceType
  1860. onState = ccSettings.onState
  1861. offState = ccSettings.offState
  1862. defaultStart = ccSettings.defaultStart
  1863. autoClose = ccSettings.autoClose
  1864. autoDelay = ccSettings.autoDelay
  1865. local startState = false
  1866. if type(defaultStart) == "string" then
  1867.   startState = ccSettings.lastState
  1868. else
  1869.   startState = defaultStart
  1870. end
  1871. rs.setOutput(ccSettings.side, startState)
  1872. if not server then return end
  1873. if deviceType == "Door" then
  1874.   deviceState = startState and "OPEN" or "CLOSED"
  1875. elseif deviceType == "Piston" or deviceType == "eDoor" then
  1876.   deviceState = startState and "CLOSED" or "OPEN"
  1877. else
  1878.   deviceState = startState and "ON" or "OFF"
  1879. end
  1880. if autoClose and (deviceState == "OPEN" or deviceState == "OFF") then closeTimer = os.startTimer(autoDelay) end
  1881. netSend()
  1882. thisCommand = "init"
  1883. ccSuccess, kernelState = true, true
  1884. for i = 1, #mon do
  1885.   mon[i].setTextScale(1)
  1886.   mon[i].setBackgroundColor(mblack)
  1887.   mon[i].clear()
  1888. end
  1889. term.clear()
  1890. if not tArgs[1] then staticTermScreen() updateScreens() end
  1891. pollTimer = os.startTimer(5)
  1892. if tArgs[1] then
  1893.   parallel.waitForAny(netReceive, dataPoller, monTouch, foregroundShell)
  1894. else
  1895.   parallel.waitForAny(netReceive, dataPoller, monTouch, userInput)
  1896. end
Add Comment
Please, Sign In to add comment