Advertisement
HydrantHunter

WiRe Server

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