HydrantHunter

WiRe Client

May 16th, 2014
4,688
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 58.54 KB | None | 0 0
  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.     else
  1208.       deviceState = rsOut and "ON" or "OFF"
  1209.     end
  1210.     return true
  1211.   end
  1212.   return false
  1213. end
  1214.  
  1215. local function netSend()
  1216.   local dataPack = textutils.serialize({
  1217.     program = "WiRe";
  1218.     cc = tonumber(thisCC);
  1219.     name = ccSettings.name;
  1220.     color = ccSettings.color;
  1221.     deviceType = deviceType;
  1222.     deviceState = deviceState;
  1223.     lockState = ccSettings.lockState;
  1224.     quietCount = 0;
  1225.     loc = loc;
  1226.   })
  1227.   if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
  1228.   local encKey = tostring(server) .. "WiRe!Comms" .. thisCC
  1229.   local encryptedPackage = encode(encrypt(encKey, dataPack))
  1230.   rednet.send(server, encryptedPackage, network)
  1231. end
  1232.  
  1233. local function netReceive()
  1234.   local id, newCmdData, goodData, encryptedMessage, decryptedMessage, decodedMessage, encKey, success
  1235.   while true do
  1236.     if not rednet.isOpen(modemSide) then rednet.open(modemSide) end
  1237.     newCmdData = { }
  1238.     id, encryptedMessage = rednet.receive(network)
  1239.     goodData = false
  1240.     if type(encryptedMessage) == "string" then
  1241.       success, decodedMessage = pcall(decode, encryptedMessage)
  1242.       if success and type(decodedMessage) == "string" then
  1243.         encKey = thisCC .. "WiRe!Comms" .. tostring(id)
  1244.         success, decryptedMessage = pcall(decrypt, encKey, decodedMessage)
  1245.         if success and type(decryptedMessage) == "string" then
  1246.           success, newCmdData = pcall(textutils.unserialize, decryptedMessage)
  1247.           if success and type(newCmdData) == "table" and newCmdData.program then
  1248.             if newCmdData.program == "WiRe" and newCmdData.cc == id and id == server and newCmdData.color == ccSettings.color then
  1249.               if validStates[newCmdData.cmd] then
  1250.                 thisCommand = newCmdData.cmd
  1251.                 goodData = true
  1252.               end
  1253.             end
  1254.           end
  1255.         else
  1256.           encKey = tostring(id) .. "WiRe!Comms" .. tostring(id)
  1257.           success, decryptedMessage = pcall(decrypt, encKey, decodedMessage)
  1258.           if success and type(decryptedMessage) == "string" then
  1259.             success, newCmdData = pcall(textutils.unserialize, decryptedMessage)
  1260.             if success and type(newCmdData) == "table" and newCmdData.program then
  1261.               if newCmdData.program == "WiRe" and newCmdData.cc == id and id == server and newCmdData.color == ccSettings.color then
  1262.                 if validStates[newCmdData.cmd] then
  1263.                   thisCommand = newCmdData.cmd
  1264.                   goodData = true
  1265.                 end
  1266.               end
  1267.             end
  1268.           end
  1269.         end
  1270.       end
  1271.     end
  1272.     if goodData then
  1273.       ccSuccess = doAction()
  1274.       netSend()
  1275.     else
  1276.       thisCommand = "Noise"
  1277.       ccSuccess = false
  1278.     end
  1279.     updateScreens()
  1280.   end
  1281. end
  1282.  
  1283. do
  1284.   local colorBurst = {
  1285.     Purple = purple;
  1286.     Magenta = magenta;
  1287.     Blue = blue;
  1288.     Sky = sky;
  1289.     Cyan = cyan;
  1290.     Green = green;
  1291.     Lime = lime;
  1292.     Red = red;
  1293.     Orange = orange;
  1294.     Yellow = yellow;
  1295.     Brown = brown;
  1296.     Silver = silver;
  1297.     Gray = gray;
  1298.     White = white;
  1299.     Black = white;
  1300.   }
  1301.  
  1302.   local labels = {
  1303.     [1] = { "Name", 1, 3 };
  1304.     [2] = { "Note:", 1, 4 };
  1305.     [3] = { "Group:", 1, 6 };
  1306.     [4] = { "cc#", 1, 8 };
  1307.     [5] = { "Server cc#", 1, 9 };
  1308.     [6] = { "Modem:", 1, 11 };
  1309.     [7] = { "Redstone:", 1, 12 };
  1310.     [8] = { "Device Type:", 1, 14 };
  1311.     [9] = { "Current State:", 1, 15 };
  1312.     [10] = { "Last Command:", 1, 17 };
  1313.     [11] = { "Success:", 1, 18 };
  1314.     [12] = { "Peripherals", 28, 3 };
  1315.     [13] = { "Location: x:", 28, 11 };
  1316.     [14] = { "y:", 38, 12 };
  1317.     [15] = { "z:", 38, 13 };
  1318.     [16] = { "Check-in:", 31, 17 };
  1319.   }
  1320.  
  1321.   staticTermScreen = function()
  1322.     local hText = "WiRe Client " .. WiReCver
  1323.     local spacer = (termX - #hText) / 2
  1324.     term.setBackgroundColor(blue)
  1325.     term.setTextColor(white)
  1326.     term.setCursorPos(1, 1)
  1327.     term.write(string.rep(" ", math.floor(spacer)) .. hText .. string.rep(" ", math.ceil(spacer)))
  1328.     term.setBackgroundColor(black)
  1329.     term.setTextColor(silver)
  1330.     for i = 1, 16 do
  1331.       term.setCursorPos(labels[i][2], labels[i][3])
  1332.       term.write(labels[i][1])
  1333.     end
  1334.     term.setTextColor(white)
  1335.     term.setCursorPos(7, 3)
  1336.     term.write(ccSettings.name)
  1337.     term.setCursorPos(7, 4)
  1338.     term.write(ccSettings.note)
  1339.     term.setCursorPos(5, 8)
  1340.     term.write(thisCC)
  1341.     term.setCursorPos(12, 9)
  1342.     term.write(tostring(server))
  1343.     term.setCursorPos(11, 11)
  1344.     term.write(modemSide)
  1345.     term.setCursorPos(11, 12)
  1346.     term.write(ccSettings.side)
  1347.     term.setCursorPos(16, 14)
  1348.     term.write(deviceType)
  1349.     if mon[1] then
  1350.       term.setCursorPos(28, 5)
  1351.       term.write("Monitor x" .. tostring(#mon))
  1352.     end
  1353.     term.setCursorPos(41, 11)
  1354.     term.write(tostring(loc.x))
  1355.     term.setCursorPos(41, 12)
  1356.     term.write(tostring(loc.y))
  1357.     term.setCursorPos(41, 13)
  1358.     term.write(tostring(loc.z))
  1359.     term.setTextColor(colorBurst[ccSettings.color] or silver)
  1360.     term.setCursorPos(8, 6)
  1361.     term.write(ccSettings.color)
  1362.   end
  1363. end
  1364.  
  1365. local function termScreen()
  1366.   term.setCursorPos(16, 15)
  1367.   term.setTextColor(switchStates[deviceState][1] or yellow)
  1368.   term.write(deviceState)
  1369.   term.setTextColor(gray)
  1370.   term.write(" | ")
  1371.   term.setTextColor(ccSettings.lockState and red or green)
  1372.   term.write(ccSettings.lockState and "Locked       " or "Unlocked       ")
  1373.   term.setCursorPos(15, 17)
  1374.   term.setTextColor(white)
  1375.   term.write(thisCommand .. string.rep(" ", 8))
  1376.   term.setCursorPos(15, 18)
  1377.   term.setTextColor(ccSuccess and green or red)
  1378.   term.write(tostring(ccSuccess) .. " ")
  1379. end
  1380.  
  1381. local function helpScreen()
  1382.   local hText = "WiRe Client Help"
  1383.   local xPos, spacer = math.floor(termX / 2), (termX - #hText) / 2
  1384.   term.setBackgroundColor(white)
  1385.   term.clear()
  1386.   term.setBackgroundColor(blue)
  1387.   term.setTextColor(white)
  1388.   term.setCursorPos(1, 1)
  1389.   term.write(string.rep(" ", math.floor(spacer)) .. hText .. string.rep(" ", math.ceil(spacer)))
  1390.   term.setBackgroundColor(white)
  1391.   term.setTextColor(black)
  1392.   term.setCursorPos(xPos - 8, 5)
  1393.   term.write("'q' to quit client")
  1394.   term.setCursorPos(xPos - 12, 7)
  1395.   term.write("'F1' to display/exit help")
  1396. end
  1397.  
  1398. do
  1399.   local function touchScreen()
  1400.     local line, symbol = "     "
  1401.     for i = 1, #mon do
  1402.       symbol = ccSettings.lockState and " [0] " or (switchStates[deviceState][3] or " [X] ")
  1403.       mon[i].setBackgroundColor(ccSettings.lockState and mred or (switchStates[deviceState][2] or myellow))
  1404.       mon[i].setTextColor(mwhite)
  1405.       for y = 2, 4 do
  1406.         mon[i].setCursorPos(2, y)
  1407.         mon[i].write(y == 3 and symbol or line)
  1408.       end
  1409.     end
  1410.   end
  1411.  
  1412.   updateScreens = function()
  1413.     if not tArgs[1] and not help then termScreen() end
  1414.     if thisCommand ~= "Noise" and mon[1] then touchScreen() end
  1415.   end
  1416. end
  1417.  
  1418. local function clearMonitors()
  1419.   for i = 1, #mon do
  1420.     mon[i].setBackgroundColor(mblack)
  1421.     mon[i].clear()
  1422.   end
  1423. end
  1424.  
  1425. local function clearTerm()
  1426.   term.setBackgroundColor(black)
  1427.   term.setTextColor(white)
  1428.   term.clear()
  1429.   term.setCursorPos(1, 1)
  1430. end
  1431.  
  1432. local function shutDown()
  1433.   deviceState = "OFFLINE"
  1434.   kernelState = false
  1435.   netSend()
  1436.   if rednet.isOpen(modemSide) then rednet.close(modemSide) end
  1437.   if mon[1] then clearMonitors() end
  1438. end
  1439.  
  1440. local function foregroundShell()
  1441.   clearTerm()
  1442.   if fs.exists(tArgs[1]) then
  1443.     local unpack = unpack or table.unpack
  1444.       shell.run(unpack(tArgs))
  1445.     clearTerm()
  1446.   else
  1447.     term.write(tArgs[1] .. " missing")
  1448.     term.setCursorPos(1, 3)
  1449.   end
  1450.   shutDown()
  1451.   term.write("WiRe Client is OFFLINE")
  1452.   term.setCursorPos(1, 5)
  1453. end
  1454.  
  1455. local function dataPoller()
  1456.   local _, timer, thisTime
  1457.   while true do
  1458.     _, timer = os.pullEvent("timer")
  1459.     thisCommand = "Noise"
  1460.     ccSuccess = false
  1461.     if timer == pollTimer then
  1462.       if kernelState then
  1463.         thisCommand = "WiReQRY"
  1464.         pollTimer = os.startTimer(3.25)
  1465.       end
  1466.     elseif timer == closeTimer then
  1467.       if not ccSettings.lockState then
  1468.         thisCommand = deviceType == "Energy" and "ON" or "CLOSED"
  1469.       end
  1470.     end
  1471.     if thisCommand == "WiReQRY" or thisCommand == "ON" or thisCommand == "CLOSED" then
  1472.       ccSuccess = doAction()
  1473.       if thisCommand == "WiReQRY" then
  1474.         thisTime = tostring(os.time())
  1475.         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
  1476.           if not tArgs[1] then
  1477.             term.setCursorPos(41, 17)
  1478.             term.setTextColor(green)
  1479.             term.write("True ")
  1480.           end
  1481.           netSend()
  1482.         else
  1483.           if not tArgs[1] then
  1484.             term.setCursorPos(41, 17)
  1485.             term.setTextColor(red)
  1486.             term.write("False")
  1487.           end
  1488.           os.cancelTimer(pollTimer)
  1489.           pollTimer = os.startTimer(0.25)
  1490.         end
  1491.       else
  1492.         netSend()
  1493.       end
  1494.     end
  1495.     if thisCommand ~= "Noise" then updateScreens() end
  1496.   end
  1497. end
  1498.  
  1499. local function userInput()
  1500.   local event, data
  1501.   while true do
  1502.     event, data = os.pullEvent()
  1503.     if event == "key" and data == keys.f1 then
  1504.       help = not help
  1505.       if help then
  1506.         helpScreen()
  1507.       else
  1508.         term.setBackgroundColor(black)
  1509.         term.clear()
  1510.         staticTermScreen()
  1511.         termScreen()
  1512.       end
  1513.     elseif event == "char" and data:lower() == "q" then
  1514.       shutDown()
  1515.       clearTerm()
  1516.       term.write("WiRe Client is OFFLINE")
  1517.       term.setCursorPos(1, 3)
  1518.       return
  1519.     end
  1520.   end
  1521. end
  1522.  
  1523. local function monTouch()
  1524.   while true do
  1525.     os.pullEvent("monitor_touch")
  1526.     if not ccSettings.lockState then
  1527.       thisCommand = validStates[deviceState] or "Touch"
  1528.       ccSuccess = doAction()
  1529.       netSend()
  1530.       updateScreens()
  1531.     end
  1532.   end
  1533. end
  1534.  
  1535. local function initError(missing, device)
  1536.   if modemSide and rednet.isOpen(modemSide) then rednet.close(modemSide) end
  1537.   if mon[1] then clearMonitors() end
  1538.   term.clear()
  1539.   term.setTextColor(red)
  1540.   term.setCursorPos(1, 2)
  1541.   print("No " .. missing .. " detected!")
  1542.   print("WiRe Client REQUIRES")
  1543.   print(device .. ".")
  1544.   term.setTextColor(white)
  1545.   term.setCursorPos(1, 6)
  1546. end
  1547.  
  1548. local function firstRun()
  1549.   term.clear()
  1550.   local gotModem = false
  1551.   for _, side in pairs(rs.getSides()) do
  1552.     if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then
  1553.       gotModem = true
  1554.       break
  1555.     end
  1556.   end
  1557.   if not gotModem then return initError("modem", "a modem") end
  1558.   --# Set computer name
  1559.   term.setCursorPos(2, 2)
  1560.   term.write("Please name this device")
  1561.   term.setCursorPos(3, 3)
  1562.   term.write("(12 characters or less)")
  1563.   repeat
  1564.     term.setCursorPos(2, 4)
  1565.     local newName = read()
  1566.     newName = newName and newName:sub(1, 12) or ""
  1567.     ccSettings.name = newName
  1568.   until newName ~= ""
  1569.   --# Set computer label
  1570.   if not os.getComputerLabel() then
  1571.     os.setComputerLabel(ccSettings.name)
  1572.   end
  1573.   --# Set computer description
  1574.   term.clear()
  1575.   term.setCursorPos(2, 2)
  1576.   term.write("Please type in a short")
  1577.   term.setCursorPos(2, 3)
  1578.   term.write("client description")
  1579.   repeat
  1580.     term.setCursorPos(2, 5)
  1581.     local newDesc = read()
  1582.     ccSettings.note = newDesc
  1583.   until newDesc ~= ""
  1584.   --# Select device type
  1585.   local deviceTypes = {
  1586.     d = { "Door", false, true };
  1587.     f = { "eDoor", true, false };
  1588.     p = { "Piston", true, false };
  1589.     e = { "Energy", true, false };
  1590.   }
  1591.   term.clear()
  1592.   term.setCursorPos(2, 2)
  1593.   term.write("Is this a physical Door/Hatch?    [d]")
  1594.   term.setCursorPos(2, 3)
  1595.   term.write("A Forcefield or Energy Door?      [f]")
  1596.   term.setCursorPos(2, 4)
  1597.   term.write("A Piston door or Piston hatch?    [p]")
  1598.   term.setCursorPos(2, 5)
  1599.   term.write("Energy Device/Barrier/Lamp/Other? [e]")
  1600.   term.setCursorPos(2, 7)
  1601.   term.write("[d/f/p] - States are 'OPEN/CLOSED'")
  1602.   term.setCursorPos(2, 9)
  1603.   term.write("Door: OPEN = RS(true) / CLOSED = RS(false)")
  1604.   term.setCursorPos(2, 10)
  1605.   term.write("eDoor: OPEN = RS(false) / CLOSED = RS(true)")
  1606.   term.setCursorPos(2, 11)
  1607.   term.write("Piston: OPEN = RS(false) / CLOSED = RS(true)")
  1608.   term.setCursorPos(2, 13)
  1609.   term.write("[e] - States are 'OFF/ON'")
  1610.   term.setCursorPos(2, 15)
  1611.   term.write("Energy: OFF = RS(false) / ON = RS(true)")
  1612.   repeat
  1613.     term.setCursorPos(2, 17)
  1614.     local newType = string.lower(read())
  1615.     if deviceTypes[newType] then
  1616.       deviceType = deviceTypes[newType][1]
  1617.       onState = deviceTypes[newType][2]
  1618.       offState = deviceTypes[newType][3]
  1619.       ccSettings.onState = onState
  1620.       ccSettings.offState = offState
  1621.       ccSettings.deviceType = deviceType
  1622.     end
  1623.   until deviceTypes[newType]
  1624.   --# Select auto-close setting
  1625.   term.clear()
  1626.   term.setCursorPos(2, 2)
  1627.   if deviceType == "Door" or deviceType == "eDoor" or deviceType == "Piston" then
  1628.     term.write("Would you like the door or piston to")
  1629.     term.setCursorPos(2, 3)
  1630.     term.write("automatically close shortly after")
  1631.     term.setCursorPos(2, 4)
  1632.     term.write("being opened? [y/n]")
  1633.   else
  1634.     term.write("Would you like the device to")
  1635.     term.setCursorPos(2, 3)
  1636.     term.write("automatically re-activate shortly")
  1637.     term.setCursorPos(2, 4)
  1638.     term.write("after being deactivated? [y/n]")
  1639.   end
  1640.   term.setCursorPos(2, 6)
  1641.   local closeRule = string.lower(read())
  1642.   autoClose = closeRule:sub(1, 1) == "y"
  1643.   ccSettings.autoClose = autoClose
  1644.   --# Select auto-close delay
  1645.   if autoClose then
  1646.     term.clear()
  1647.     term.setCursorPos(2, 2)
  1648.     term.write("How many seconds should the")
  1649.     term.setCursorPos(2, 3)
  1650.     if deviceType == "Door" or deviceType == "eDoor" or deviceType == "Piston" then
  1651.       term.write("door or piston stay open before closing")
  1652.     else
  1653.       term.write("device stay off before reactivating")
  1654.     end
  1655.     term.setCursorPos(2, 4)
  1656.     term.write("automatically?")
  1657.     repeat
  1658.       term.setCursorPos(2, 6)
  1659.       local closeTime = tonumber(read())
  1660.       if closeTime then
  1661.         autoDelay = closeTime
  1662.         ccSettings.autoDelay = autoDelay
  1663.       end
  1664.     until closeTime
  1665.   end
  1666.   --# Select default startup state
  1667.   term.clear()
  1668.   term.setCursorPos(2, 1)
  1669.   term.write("What would you like the default")
  1670.   term.setCursorPos(2, 2)
  1671.   term.write("STARTUP state to be?")
  1672.   term.setCursorPos(2, 4)
  1673.   if deviceType == "Door" or deviceType == "eDoor" or deviceType == "Piston" then
  1674.     term.write("[p] Previous State or [c] CLOSED or [o] OPEN")
  1675.   else
  1676.     term.write("[p] Previous State or [n] ON or [f] OFF")
  1677.   end
  1678.   while true do
  1679.     term.setCursorPos(2, 5)
  1680.     local newStart = string.lower(read())
  1681.     if newStart == "o" or newStart == "c" or newStart == "n" or newStart == "f" or newStart == "p" then
  1682.       if newStart == "c" or newStart == "n" then
  1683.         defaultStart = onState
  1684.       elseif newStart == "o" or newStart == "f" then
  1685.         defaultStart = offState
  1686.       elseif newStart == "p" then
  1687.         defaultStart = "last"
  1688.         ccSettings.lastState = false
  1689.       end
  1690.       ccSettings.defaultStart = defaultStart
  1691.       break
  1692.     end
  1693.   end
  1694.   --# Select color
  1695.   local colorWheel = {
  1696.     P = "Purple";
  1697.     M = "Magenta";
  1698.     B = "Blue";
  1699.     S = "Sky";
  1700.     C = "Cyan";
  1701.     E = "Green";
  1702.     L = "Lime";
  1703.     R = "Red";
  1704.     O = "Orange";
  1705.     Y = "Yellow";
  1706.     N = "Brown";
  1707.     K = "Black";
  1708.     G = "Gray";
  1709.     I = "Silver";
  1710.     W = "White";
  1711.   }
  1712.   term.clear()
  1713.   term.setCursorPos(2, 1)
  1714.   term.write("Please select the network group")
  1715.   term.setCursorPos(2, 2)
  1716.   if deviceType == "Door" or device == "eDoor" then
  1717.     term.write("this door will belong to...")
  1718.   else
  1719.     term.write("this device will belong to...")
  1720.   end
  1721.   local ttY = 4
  1722.   for k, v in pairs(colorWheel) do
  1723.     term.setCursorPos(2, ttY)
  1724.     term.write(k .. " = " .. v)
  1725.     ttY = ttY + 1
  1726.   end
  1727.   repeat
  1728.     term.setCursorPos(32, 2)
  1729.     local newColor = string.upper(read())
  1730.     ccSettings.color = colorWheel[newColor:sub(1, 1)]
  1731.   until colorWheel[newColor:sub(1, 1)]
  1732.   --# Select redstone output side
  1733.   local theseSides = { "top", "bottom", "left", "right", "front", "back" }
  1734.   term.clear()
  1735.   term.setCursorPos(2, 2)
  1736.   term.write("Select the redstone output side")
  1737.   local yPos = 3
  1738.   for num, side in pairs(theseSides) do
  1739.     yPos = yPos + 1
  1740.     term.setCursorPos(2, yPos)
  1741.     term.write(tostring(num) .. " = " .. string.upper(side:sub(1, 1)) .. side:sub(2))
  1742.   end
  1743.   repeat
  1744.     term.setCursorPos(2, 11)
  1745.     local rsSide = tonumber(read())
  1746.     ccSettings.side = theseSides[rsSide]
  1747.   until theseSides[rsSide]
  1748.   --# Should WiRe client get a GPS fix on startup?
  1749.   term.clear()
  1750.   term.setCursorPos(2, 1)
  1751.   term.write("Last question!")
  1752.   term.setCursorPos(2, 3)
  1753.   term.write("Do you want WiRe client to")
  1754.   term.setCursorPos(2, 4)
  1755.   term.write("aquire a GPS fix on startup? [y/n]")
  1756.   term.setCursorPos(2, 6)
  1757.   local getFix = string.lower(read())
  1758.   ccSettings.getGPSFix = getFix:sub(1, 1) == "y"
  1759.   if not fs.exists("/data") then fs.makeDir("/data") end
  1760.   saveData()
  1761.   return true
  1762. end
  1763.  
  1764. term.setBackgroundColor(black)
  1765. if pocket or turtle then error("Computer REQUIRED.", 0) end
  1766. if not fs.exists(config) then
  1767.   if not firstRun() then return end
  1768. end
  1769. term.clear()
  1770. term.setCursorPos(2, 2)
  1771. term.setTextColor(white)
  1772. term.write("Ingesting configuration data . . .")
  1773. local clientConfig = fs.open(config, "r") or error("initMe(): Cannot open " .. config .. " for reading", 0)
  1774. ccSettings = textutils.unserialize(clientConfig.readAll())
  1775. clientConfig.close()
  1776. if ccSettings.getFix ~= nil or ccSettings.deviceType == "Bridge" or not ccSettings.newColors then
  1777.   if ccSettings.getFix ~= nil then
  1778.     ccSettings.getGPSFix = ccSettings.getFix
  1779.     ccSettings.getFix = nil
  1780.   end
  1781.   if ccSettings.deviceType == "Bridge" then
  1782.     ccSettings.deviceType = "Energy"
  1783.   end
  1784.   if not ccSettings.newColors then
  1785.     if ccSettings.color == "lgray" or ccSettings.color == "Light Gray" then
  1786.       ccSettings.color = "Silver"
  1787.     elseif ccSettings.color == "lblue" or ccSettings.color == "Light Blue" then
  1788.       ccSettings.color = "Sky"
  1789.     end
  1790.     ccSettings.newColors = true
  1791.   end
  1792.   saveData()
  1793. end
  1794. term.setCursorPos(2, 4)
  1795. term.write("Configuring hardware . . .")
  1796. for _, side in pairs(rs.getSides()) do
  1797.   if peripheral.isPresent(side) then
  1798.     if peripheral.getType(side) == "monitor" and peripheral.call(side, "isColor") then
  1799.       mon[#mon + 1] = peripheral.wrap(side)
  1800.     elseif peripheral.getType(side) == "modem" then
  1801.       if peripheral.call(side, "isWireless") then
  1802.         modemSide = side
  1803.         if not rednet.isOpen(side) then rednet.open(side) end
  1804.       else
  1805.         for _, perp in pairs(peripheral.call(side, "getNamesRemote")) do
  1806.           if peripheral.getType(perp) == "monitor" and peripheral.call(perp, "isColor") then
  1807.             mon[#mon + 1] = peripheral.wrap(perp)
  1808.           elseif peripheral.getType(perp) == "computer" then
  1809.             modemSide = side
  1810.             if not rednet.isOpen(side) then rednet.open(side) end
  1811.           end
  1812.         end
  1813.       end
  1814.     end
  1815.   end
  1816. end
  1817. if not modemSide then return initError("modem", "a modem") end
  1818. if mon[1] then
  1819.   for i = 1, #mon do
  1820.     mon[i].setTextScale(0.5)
  1821.     mon[i].setBackgroundColor(mwhite)
  1822.     mon[i].setTextColor(mblack)
  1823.     mon[i].clear()
  1824.     mon[i].setCursorPos(2, 3)
  1825.     mon[i].write("Initializing...")
  1826.   end
  1827. end
  1828. term.setCursorPos(2, 6)
  1829. if ccSettings.getGPSFix then
  1830.   term.write("Acquiring GPS fix . . .")
  1831.   loc.x, loc.y, loc.z = gps.locate(2)
  1832.   term.setCursorPos(2, 8)
  1833. end
  1834. if not loc.x then
  1835.   loc.x, loc.y, loc.z = "No GPS Fix", "No GPS Fix", "No GPS Fix"
  1836. end
  1837. term.write("Looking for WiRe Server . . .")
  1838. network = "WiRe" .. ccSettings.color
  1839. for i = 1, 3 do
  1840.   server = rednet.lookup(network, ccSettings.color)
  1841.   if server then break elseif i ~= 3 then sleep(2) end
  1842. end
  1843. if not server then
  1844.   term.clear()
  1845.   term.setTextColor(red)
  1846.   term.setCursorPos(1, 2)
  1847.   print("No server detected!")
  1848.   print("WiRe Client REQUIRES a WiRe Server.\n")
  1849.   print("Output set to 'Default Start'")
  1850.   if rednet.isOpen(modemSide) then rednet.close(modemSide) end
  1851.   if mon[1] then clearMonitors() end
  1852.   term.setCursorPos(1, 9)
  1853. end
  1854. deviceType = ccSettings.deviceType
  1855. onState = ccSettings.onState
  1856. offState = ccSettings.offState
  1857. defaultStart = ccSettings.defaultStart
  1858. autoClose = ccSettings.autoClose
  1859. autoDelay = ccSettings.autoDelay
  1860. local startState = false
  1861. if type(defaultStart) == "string" then
  1862.   startState = ccSettings.lastState
  1863. else
  1864.   startState = defaultStart
  1865. end
  1866. rs.setOutput(ccSettings.side, startState)
  1867. if not server then return end
  1868. if deviceType == "Door" then
  1869.   deviceState = startState and "OPEN" or "CLOSED"
  1870. elseif deviceType == "Piston" or deviceType == "eDoor" then
  1871.   deviceState = startState and "CLOSED" or "OPEN"
  1872. else
  1873.   deviceState = startState and "ON" or "OFF"
  1874. end
  1875. if autoClose and (deviceState == "OPEN" or deviceState == "OFF") then closeTimer = os.startTimer(autoDelay) end
  1876. netSend()
  1877. thisCommand = "init"
  1878. ccSuccess, kernelState = true, true
  1879. for i = 1, #mon do
  1880.   mon[i].setTextScale(1)
  1881.   mon[i].setBackgroundColor(mblack)
  1882.   mon[i].clear()
  1883. end
  1884. term.clear()
  1885. if not tArgs[1] then staticTermScreen() updateScreens() end
  1886. pollTimer = os.startTimer(5)
  1887. if tArgs[1] then
  1888.   parallel.waitForAny(netReceive, dataPoller, monTouch, foregroundShell)
  1889. else
  1890.   parallel.waitForAny(netReceive, dataPoller, monTouch, userInput)
  1891. end
Add Comment
Please, Sign In to add comment