Advertisement
GravityScore

Thunderhawk

Jan 12th, 2013
1,216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 38.35 KB | None | 0 0
  1.  
  2. --  
  3. --  Thunderhawk
  4. --  Made by GravityScore
  5. --  
  6.  
  7.  
  8. --  Variables
  9.  
  10. local version = "3.0"
  11.  
  12. local autoupdate = true
  13. local testing = false
  14.  
  15. local username, password = nil, nil
  16. local w, h = term.getSize()
  17.  
  18. local serverURL = "http://firewolfcc.com/thunderhawk/php/lua"
  19. local thunderhawkURL = "https://raw.github.com/GravityScore/Thunderhawk/master/thunderhawk.lua"
  20. local thunderhawkLocation = "/" .. shell.getRunningProgram()
  21.  
  22. local function isAdvanced() return term.isColor and term.isColor() end
  23.  
  24.  
  25. --  Drawing
  26.  
  27. local function centerPrint(text, ny)
  28.     local x, y = term.getCursorPos()
  29.     term.setCursorPos(math.ceil(w/2 - text:len()/2) + 1, ny or y)
  30.     print(text)
  31. end
  32.  
  33. local function drawButton(v, sel)
  34.     if sel then term.setBackgroundColor(v.highlight or colors.lightBlue)
  35.     else term.setBackgroundColor(v.bg or colors.cyan) end
  36.     term.setTextColor(v.tc or colors.white)
  37.     for i = -1, 1 do
  38.         term.setCursorPos(v[2], v[3] + i)
  39.         term.write(string.rep(" ", v[1]:len() + 4))
  40.     end
  41.  
  42.     term.setCursorPos(v[2], v[3])
  43.     if sel then
  44.         term.setBackgroundColor(v.highlight or colors.lightBlue)
  45.         term.write(" > ")
  46.     else term.write(" - ") end
  47.     term.write(v[1] .. " ")
  48. end
  49.  
  50. local function title(t)
  51.     term.setTextColor(colors.white)
  52.     term.setBackgroundColor(colors.gray)
  53.     term.clear()
  54.  
  55.     term.setBackgroundColor(colors.lightGray)
  56.     for i = 2, 4 do term.setCursorPos(1, i) term.clearLine() end
  57.     term.setCursorPos(3, 3)
  58.     term.write(t)
  59. end
  60.  
  61.  
  62. --  Prompt
  63.  
  64. local function updateDisplayList(items, loc, len)
  65.     local ret = {}
  66.     for i = 1, len do if items[i + loc - 1] then table.insert(ret, items[i + loc - 1]) end end
  67.     return ret
  68. end
  69.  
  70. local function prompt(list, dir)
  71.     local function draw(sel)
  72.         for i, v in ipairs(list) do
  73.             if i == sel then term.setBackgroundColor(v.highlight or colors.lightBlue)
  74.             else term.setBackgroundColor(v.bg or colors.cyan) end
  75.             term.setTextColor(v.tc or colors.white)
  76.             for i = -1, 1 do
  77.                 term.setCursorPos(v[2], v[3] + i)
  78.                 term.write(string.rep(" ", v[1]:len() + 4))
  79.             end
  80.  
  81.             term.setCursorPos(v[2], v[3])
  82.             if i == sel then
  83.                 term.setBackgroundColor(v.highlight or colors.lightBlue)
  84.                 term.write(" > ")
  85.             else term.write(" - ") end
  86.             term.write(v[1] .. " ")
  87.         end
  88.     end
  89.  
  90.     local key1, key2 = dir == "horizontal" and 203 or 200, dir == "horizontal" and 205 or 208
  91.     local sel = 1
  92.     draw(sel)
  93.  
  94.     while true do
  95.         local e, but, x, y = os.pullEvent()
  96.         if e == "key" and but == 28 then return list[sel][1]
  97.         elseif e == "key" and but == key1 and sel > 1 then
  98.             sel = sel - 1
  99.             draw(sel)
  100.         elseif e == "key" and but == key2 and ((err == true and sel < #list - 1) or (sel < #list)) then
  101.             sel = sel + 1
  102.             draw(sel)
  103.         elseif e == "mouse_click" then
  104.             for i, v in ipairs(list) do
  105.                 if x >= v[2] and x <= v[2] + v[1]:len() + 3 and y >= v[3] - 1 and y <= v[3] + 1 then
  106.                     return list[i][1]
  107.                 end
  108.             end
  109.         end
  110.     end
  111. end
  112.  
  113. local function modRead(properties)
  114.     local w, h = term.getSize()
  115.     local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil,
  116.         liveUpdates = nil, exitOnKey = nil}
  117.     if not properties then properties = {} end
  118.     for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end
  119.     if properties.replaceChar then properties.replaceChar = properties.replaceChar:sub(1, 1) end
  120.     if not properties.visibleLength then properties.visibleLength = w end
  121.  
  122.     local sx, sy = term.getCursorPos()
  123.     local line = ""
  124.     local pos = 0
  125.     local historyPos = nil
  126.  
  127.     local function redraw(repl)
  128.         local scroll = 0
  129.         if properties.visibleLength and sx + pos > properties.visibleLength + 1 then
  130.             scroll = (sx + pos) - (properties.visibleLength + 1)
  131.         end
  132.  
  133.         term.setCursorPos(sx, sy)
  134.         local a = repl or properties.replaceChar
  135.         if a then term.write(string.rep(a, line:len() - scroll))
  136.         else term.write(line:sub(scroll + 1, -1)) end
  137.         term.setCursorPos(sx + pos - scroll, sy)
  138.     end
  139.  
  140.     local function sendLiveUpdates(event, ...)
  141.         if type(properties.liveUpdates) == "function" then
  142.             local ox, oy = term.getCursorPos()
  143.             local a, data = properties.liveUpdates(line, event, ...)
  144.             if a == true and data == nil then
  145.                 term.setCursorBlink(false)
  146.                 return line
  147.             elseif a == true and data ~= nil then
  148.                 term.setCursorBlink(false)
  149.                 return data
  150.             end
  151.             term.setCursorPos(ox, oy)
  152.         end
  153.     end
  154.  
  155.     local a = sendLiveUpdates("delete")
  156.     if a then return a end
  157.     term.setCursorBlink(true)
  158.     while true do
  159.         local e, but, x, y, p4, p5 = os.pullEvent()
  160.  
  161.         if e == "char" then
  162.             local s = false
  163.             if properties.textLength and line:len() < properties.textLength then s = true
  164.             elseif not properties.textLength then s = true end
  165.  
  166.             local canType = true
  167.             if not properties.grantPrint and properties.refusePrint then
  168.                 local canTypeKeys = {}
  169.                 if type(properties.refusePrint) == "table" then
  170.                     for _, v in pairs(properties.refusePrint) do
  171.                         table.insert(canTypeKeys, tostring(v):sub(1, 1))
  172.                     end
  173.                 elseif type(properties.refusePrint) == "string" then
  174.                     for char in properties.refusePrint:gmatch(".") do
  175.                         table.insert(canTypeKeys, char)
  176.                     end
  177.                 end
  178.                 for _, v in pairs(canTypeKeys) do if but == v then canType = false end end
  179.             elseif properties.grantPrint then
  180.                 canType = false
  181.                 local canTypeKeys = {}
  182.                 if type(properties.grantPrint) == "table" then
  183.                     for _, v in pairs(properties.grantPrint) do
  184.                         table.insert(canTypeKeys, tostring(v):sub(1, 1))
  185.                     end
  186.                 elseif type(properties.grantPrint) == "string" then
  187.                     for char in properties.grantPrint:gmatch(".") do
  188.                         table.insert(canTypeKeys, char)
  189.                     end
  190.                 end
  191.                 for _, v in pairs(canTypeKeys) do if but == v then canType = true end end
  192.             end
  193.  
  194.             if s and canType then
  195.                 line = line:sub(1, pos) .. but .. line:sub(pos + 1, -1)
  196.                 pos = pos + 1
  197.                 redraw()
  198.             end
  199.         elseif e == "key" then
  200.             if but == keys.enter then break
  201.             elseif but == keys.left then if pos > 0 then pos = pos - 1 redraw() end
  202.             elseif but == keys.right then if pos < line:len() then pos = pos + 1 redraw() end
  203.             elseif (but == keys.up or but == keys.down) and properties.history and
  204.                     #properties.history > 0 then
  205.                 redraw(" ")
  206.                 if but == keys.up then
  207.                     if historyPos == nil and #properties.history > 0 then
  208.                         historyPos = #properties.history
  209.                     elseif historyPos > 1 then
  210.                         historyPos = historyPos - 1
  211.                     end
  212.                 elseif but == keys.down then
  213.                     if historyPos == #properties.history then historyPos = nil
  214.                     elseif historyPos ~= nil then historyPos = historyPos + 1 end
  215.                 end
  216.  
  217.                 if properties.history and historyPos then
  218.                     line = properties.history[historyPos]
  219.                     pos = line:len()
  220.                 else line, pos = "", 0 end
  221.  
  222.                 redraw()
  223.                 local a = sendLiveUpdates("history")
  224.                 if a then return a end
  225.             elseif but == keys.backspace and pos > 0 then
  226.                 redraw(" ")
  227.                 line = line:sub(1, pos - 1) .. line:sub(pos + 1, -1)
  228.                 pos = pos - 1
  229.                 redraw()
  230.                 local a = sendLiveUpdates("delete")
  231.                 if a then return a end
  232.             elseif but == keys.home then
  233.                 pos = 0
  234.                 redraw()
  235.             elseif but == keys.delete and pos < line:len() then
  236.                 redraw(" ")
  237.                 line = line:sub(1, pos) .. line:sub(pos + 2, -1)
  238.                 redraw()
  239.                 local a = sendLiveUpdates("delete")
  240.                 if a then return a end
  241.             elseif but == keys["end"] then
  242.                 pos = line:len()
  243.                 redraw()
  244.             elseif properties.exitOnKey then
  245.                 if but == properties.exitOnKey or (properties.exitOnKey == "control" and
  246.                         (but == 29 or but == 157)) then
  247.                     term.setCursorBlink(false)
  248.                     return nil
  249.                 end
  250.             end
  251.         end
  252.  
  253.         local a = sendLiveUpdates(e, but, x, y, p4, p5)
  254.         if a then return a end
  255.     end
  256.  
  257.     term.setCursorBlink(false)
  258.     if line ~= nil then line = line:gsub("^%s*(.-)%s*$", "%1") end
  259.     return line
  260. end
  261.  
  262.  
  263. --  SHA-256
  264.  
  265. local MOD = 2^32
  266. local MODM = MOD-1
  267.  
  268. local function memoize(f)
  269.     local mt = {}
  270.     local t = setmetatable({}, mt)
  271.     function mt:__index(k)
  272.         local v = f(k)
  273.         t[k] = v
  274.         return v
  275.     end
  276.     return t
  277. end
  278.  
  279. local function make_bitop_uncached(t, m)
  280.     local function bitop(a, b)
  281.         local res,p = 0,1
  282.         while a ~= 0 and b ~= 0 do
  283.             local am, bm = a % m, b % m
  284.             res = res + t[am][bm] * p
  285.             a = (a - am) / m
  286.             b = (b - bm) / m
  287.             p = p*m
  288.         end
  289.         res = res + (a + b) * p
  290.         return res
  291.     end
  292.     return bitop
  293. end
  294.  
  295. local function make_bitop(t)
  296.     local op1 = make_bitop_uncached(t,2^1)
  297.     local op2 = memoize(function(a) return memoize(function(b) return op1(a, b) end) end)
  298.     return make_bitop_uncached(op2, 2 ^ (t.n or 1))
  299. end
  300.  
  301. local bxor1 = make_bitop({[0] = {[0] = 0,[1] = 1}, [1] = {[0] = 1, [1] = 0}, n = 4})
  302.  
  303. local function bxor(a, b, c, ...)
  304.     local z = nil
  305.     if b then
  306.         a = a % MOD
  307.         b = b % MOD
  308.         z = bxor1(a, b)
  309.         if c then z = bxor(z, c, ...) end
  310.         return z
  311.     elseif a then return a % MOD
  312.     else return 0 end
  313. end
  314.  
  315. local function band(a, b, c, ...)
  316.     local z
  317.     if b then
  318.         a = a % MOD
  319.         b = b % MOD
  320.         z = ((a + b) - bxor1(a,b)) / 2
  321.         if c then z = bit32_band(z, c, ...) end
  322.         return z
  323.     elseif a then return a % MOD
  324.     else return MODM end
  325. end
  326.  
  327. local function bnot(x) return (-1 - x) % MOD end
  328.  
  329. local function rshift1(a, disp)
  330.     if disp < 0 then return lshift(a,-disp) end
  331.     return math.floor(a % 2 ^ 32 / 2 ^ disp)
  332. end
  333.  
  334. local function rshift(x, disp)
  335.     if disp > 31 or disp < -31 then return 0 end
  336.     return rshift1(x % MOD, disp)
  337. end
  338.  
  339. local function lshift(a, disp)
  340.     if disp < 0 then return rshift(a,-disp) end
  341.     return (a * 2 ^ disp) % 2 ^ 32
  342. end
  343.  
  344. local function rrotate(x, disp)
  345.     x = x % MOD
  346.     disp = disp % 32
  347.     local low = band(x, 2 ^ disp - 1)
  348.     return rshift(x, disp) + lshift(low, 32 - disp)
  349. end
  350.  
  351. local k = {
  352.     0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
  353.     0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
  354.     0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
  355.     0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
  356.     0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
  357.     0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
  358.     0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
  359.     0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
  360.     0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
  361.     0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
  362.     0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
  363.     0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
  364.     0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
  365.     0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
  366.     0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
  367.     0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
  368. }
  369.  
  370. local function str2hexa(s)
  371.     return (string.gsub(s, ".", function(c) return string.format("%02x", string.byte(c)) end))
  372. end
  373.  
  374. local function num2s(l, n)
  375.     local s = ""
  376.     for i = 1, n do
  377.         local rem = l % 256
  378.         s = string.char(rem) .. s
  379.         l = (l - rem) / 256
  380.     end
  381.     return s
  382. end
  383.  
  384. local function s232num(s, i)
  385.     local n = 0
  386.     for i = i, i + 3 do n = n*256 + string.byte(s, i) end
  387.     return n
  388. end
  389.  
  390. local function preproc(msg, len)
  391.     local extra = 64 - ((len + 9) % 64)
  392.     len = num2s(8 * len, 8)
  393.     msg = msg .. "\128" .. string.rep("\0", extra) .. len
  394.     assert(#msg % 64 == 0)
  395.     return msg
  396. end
  397.  
  398. local function initH256(H)
  399.     H[1] = 0x6a09e667
  400.     H[2] = 0xbb67ae85
  401.     H[3] = 0x3c6ef372
  402.     H[4] = 0xa54ff53a
  403.     H[5] = 0x510e527f
  404.     H[6] = 0x9b05688c
  405.     H[7] = 0x1f83d9ab
  406.     H[8] = 0x5be0cd19
  407.     return H
  408. end
  409.  
  410. local function digestblock(msg, i, H)
  411.     local w = {}
  412.     for j = 1, 16 do w[j] = s232num(msg, i + (j - 1)*4) end
  413.     for j = 17, 64 do
  414.         local v = w[j - 15]
  415.         local s0 = bxor(rrotate(v, 7), rrotate(v, 18), rshift(v, 3))
  416.         v = w[j - 2]
  417.         w[j] = w[j - 16] + s0 + w[j - 7] + bxor(rrotate(v, 17), rrotate(v, 19), rshift(v, 10))
  418.     end
  419.  
  420.     local a, b, c, d, e, f, g, h = H[1], H[2], H[3], H[4], H[5], H[6], H[7], H[8]
  421.     for i = 1, 64 do
  422.         local s0 = bxor(rrotate(a, 2), rrotate(a, 13), rrotate(a, 22))
  423.         local maj = bxor(band(a, b), band(a, c), band(b, c))
  424.         local t2 = s0 + maj
  425.         local s1 = bxor(rrotate(e, 6), rrotate(e, 11), rrotate(e, 25))
  426.         local ch = bxor (band(e, f), band(bnot(e), g))
  427.         local t1 = h + s1 + ch + k[i] + w[i]
  428.         h, g, f, e, d, c, b, a = g, f, e, d + t1, c, b, a, t1 + t2
  429.     end
  430.  
  431.     H[1] = band(H[1] + a)
  432.     H[2] = band(H[2] + b)
  433.     H[3] = band(H[3] + c)
  434.     H[4] = band(H[4] + d)
  435.     H[5] = band(H[5] + e)
  436.     H[6] = band(H[6] + f)
  437.     H[7] = band(H[7] + g)
  438.     H[8] = band(H[8] + h)
  439. end
  440.  
  441. local function sha256(msg)
  442.     msg = preproc(msg, #msg)
  443.     local H = initH256({})
  444.     for i = 1, #msg, 64 do digestblock(msg, i, H) end
  445.     return str2hexa(num2s(H[1], 4) .. num2s(H[2], 4) .. num2s(H[3], 4) .. num2s(H[4], 4) ..
  446.         num2s(H[5], 4) .. num2s(H[6], 4) .. num2s(H[7], 4) .. num2s(H[8], 4))
  447. end
  448.  
  449.  
  450. --  Utilities
  451.  
  452. local function format(text, l)
  453.     if text:len() > l then return text:sub(1, l - 3) .. "..." end
  454.     return text
  455. end
  456.  
  457. local function download(url, path)
  458.     for i = 1, 3 do
  459.         local response = http.get(url)
  460.         if response then
  461.             local data = response.readAll()
  462.             response.close()
  463.             if path then
  464.                 local f = io.open(path, "w")
  465.                 f:write(data)
  466.                 f:close()
  467.             end
  468.             return true
  469.         end
  470.     end
  471.  
  472.     return false
  473. end
  474.  
  475. --  HTTP
  476.  
  477. local function verify(user, pass)
  478.     if testing then return "true" end
  479.     local res = http.post(serverURL .. "/login.php",
  480.         "u=" .. textutils.urlEncode(user) .. "&" ..
  481.         "p=" .. textutils.urlEncode(pass))
  482.     if res then
  483.         local a = res.readAll()
  484.         res.close()
  485.         return a
  486.     else return "Failed to connect" end
  487. end
  488.  
  489. local function getinbox(user, pass)
  490.     if testing then
  491.         local t = {}
  492.         local cont = {}
  493.         for i = 1, 30 do table.insert(cont, "haiz " .. i) end
  494.         for i = 1, 10 do table.insert(t, {subject = "Hello " .. i, from = "1lann", content = cont}) end
  495.         return t
  496.     end
  497.  
  498.     local res = http.post(serverURL .. "/inbox.php",
  499.         "u=" .. textutils.urlEncode(user) .. "&" ..
  500.         "p=" .. textutils.urlEncode(pass) .. "&" ..
  501.         "folder=" .. textutils.urlEncode("inbox"))
  502.     if res then
  503.         local a = res.readAll()
  504.         res.close()
  505.         if a:find("true") then
  506.             a = textutils.unserialize(a:gsub("true\n", ""))
  507.             for i = 1, #a do
  508.                 a[i].content = textutils.unserialize(a[i].content)
  509.             end
  510.             return a
  511.         else return a end
  512.     else return "Failed to Connect" end
  513. end
  514.  
  515. local function getsent(user, pass)
  516.     if testing then return {} end
  517.     local res = http.post(serverURL .. "/sent.php",
  518.         "u=" .. textutils.urlEncode(user) .. "&" ..
  519.         "p=" .. textutils.urlEncode(pass))
  520.     if res then
  521.         local a = res.readAll()
  522.         res.close()
  523.         if a:find("true") then
  524.             a = textutils.unserialize(a:gsub("true\n", ""))
  525.             for i = 1, #a do
  526.                 a[i].content = textutils.unserialize(a[i].content)
  527.             end
  528.             return a
  529.         else return a end
  530.     else return "Failed to Connect" end
  531. end
  532.  
  533. local function gettrash(user, pass)
  534.     if testing then return {} end
  535.     local res = http.post(serverURL .. "/inbox.php",
  536.         "u=" .. textutils.urlEncode(user) .. "&" ..
  537.         "p=" .. textutils.urlEncode(pass) .. "&" ..
  538.         "folder=" .. textutils.urlEncode("trash"))
  539.     if res then
  540.         local a = res.readAll()
  541.         res.close()
  542.         if a:find("true") then
  543.             a = textutils.unserialize(a:gsub("true\n", ""))
  544.             for i = 1, #a do
  545.                 a[i].content = textutils.unserialize(a[i].content)
  546.             end
  547.             return a
  548.         else return a end
  549.     else return "Failed to Connect" end
  550. end
  551.  
  552. local function send(user, pass, message)
  553.     if testing then return "true" end
  554.     local res = http.post(serverURL .. "/send.php",
  555.         "u=" .. textutils.urlEncode(user) .. "&" ..
  556.         "p=" .. textutils.urlEncode(pass) .. "&" ..
  557.         "to=" .. textutils.urlEncode(message.to) .. "&" ..
  558.         "subject=" .. textutils.urlEncode(message.subject) .. "&" ..
  559.         "message=" .. textutils.urlEncode(textutils.serialize(message.content)))
  560.     if res then
  561.         local a = res.readAll()
  562.         res.close()
  563.         return a
  564.     else return "Failed to Connect" end
  565. end
  566.  
  567. local function trash(user, pass, id)
  568.     if testing then return "true" end
  569.     local res = http.post(serverURL .. "/trash.php",
  570.         "u=" .. textutils.urlEncode(user) .. "&" ..
  571.         "p=" .. textutils.urlEncode(pass) .. "&" ..
  572.         "msgid=" .. textutils.urlEncode(tostring(id)))
  573.     if res then
  574.         local a = res.readAll()
  575.         res.close()
  576.         return a
  577.     else return "Failed to Connect" end
  578. end
  579.  
  580. local function delete(user, pass, id)
  581.     if testing then return "true" end
  582.     local res = http.post(serverURL .. "/delete.php",
  583.         "u=" .. textutils.urlEncode(user) .. "&" ..
  584.         "p=" .. textutils.urlEncode(pass) .. "&" ..
  585.         "msgid=" .. textutils.urlEncode(tostring(id)))
  586.     if res then
  587.         local a = res.readAll()
  588.         res.close()
  589.         return a
  590.     else return "Failed to Connect" end
  591. end
  592.  
  593. local function emptytrash(user, pass)
  594.     if testing then return "true" end
  595.     local res = http.post(serverURL .. "/empty_trash.php",
  596.         "u=" .. textutils.urlEncode(user) .. "&" ..
  597.         "p=" .. textutils.urlEncode(pass))
  598.     if res then
  599.         local a = res.readAll()
  600.         res.close()
  601.         return a
  602.     else return "Failed to Connect" end
  603. end
  604.  
  605. local function deleteaccount(user, pass)
  606.     if testing then return "true" end
  607.     local res = http.post(serverURL .. "/delete_account.php",
  608.         "u=" .. textutils.urlEncode(user) .. "&" ..
  609.         "p=" .. textutils.urlEncode(pass))
  610.     if res then
  611.         local a = res.readAll()
  612.         res.close()
  613.         return a
  614.     else return "Failed to Connect" end
  615. end
  616.  
  617.  
  618. --  -------- Account
  619.  
  620. local function account()
  621.     title("Thunderhawk " .. version .. " - Account Management")
  622.  
  623.     local opt = prompt({{"Back", w/2 - 9, 9, bg = colors.pink, highlight = colors.red},
  624.         {"Logout", w/2 + 2, 9}, {"Delete Account", w/2 - 7, 14}}, "horizontal")
  625.     if opt == "Delete Account" then
  626.         term.setBackgroundColor(colors.gray)
  627.         term.setTextColor(colors.white)
  628.         term.setCursorPos(1, 17)
  629.         centerPrint("Deleting Account...")
  630.         local a = deleteaccount(username, password)
  631.  
  632.         term.setCursorPos(1, 17)
  633.         term.clearLine()
  634.         if a == "true" then centerPrint("Account Deleted!")
  635.         elseif a == "false" then centerPrint("Deletion Failed!")
  636.         else centerPrint(a) end
  637.         sleep(1.6)
  638.         return "menu"
  639.     elseif opt == "Logout" then username, password = nil, nil return "menu"
  640.     elseif opt == "Back" then return "inbox" end
  641. end
  642.  
  643.  
  644. --  -------- Menu
  645.  
  646. local menu = {"New", "Inbox", "Sent", "Trash", "Account", "Exit"}
  647.  
  648. local function drawmenu()
  649.     term.setTextColor(colors.white)
  650.     term.setBackgroundColor(colors.lightGray)
  651.     term.setCursorPos(1, 1)
  652.     term.clearLine()
  653.     local curX = 0
  654.     for _, v in pairs(menu) do
  655.         term.setCursorPos(3 + curX, 1)
  656.         term.write(v)
  657.         curX = curX + v:len() + 3
  658.     end
  659. end
  660.  
  661. local function triggermenu(cx, cy)
  662.     local curX = 0
  663.     local open = nil
  664.     for _, v in pairs(menu) do
  665.         if cx >= curX + 3 and cx <= curX + v:len() + 2 then
  666.             open = v
  667.             break
  668.         end
  669.         curX = curX + v:len() + 3
  670.     end
  671.     local menux = curX + 2
  672.     if not open then return false end
  673.  
  674.     term.setCursorBlink(false)
  675.     term.setCursorPos(menux, 1)
  676.     term.setBackgroundColor(colors.gray)
  677.     term.write(string.rep(" ", open:len() + 2))
  678.     term.setCursorPos(menux + 1, 1)
  679.     term.write(open)
  680.     sleep(0.1)
  681.     drawmenu()
  682.  
  683.     return open
  684. end
  685.  
  686.  
  687. --  -------- Compose
  688.  
  689. local function compose(std)
  690.     local x, y = 1, 1
  691.     local offx, offy = 21, 6
  692.     local edw, edh = w - 23, h - 8
  693.     local scrolly = 0
  694.     local lines = {""}
  695.  
  696.     local message = {from = username, to = "", subject = "", content = {""}}
  697.     if std and std.to then message.to = std.to end
  698.     if std and std.subject then message.subject = std.subject end
  699.  
  700.     local function draw()
  701.         drawmenu()
  702.         term.setBackgroundColor(colors.white)
  703.         term.setTextColor(colors.black)
  704.  
  705.         for i = 3, h - 1 do
  706.             term.setCursorPos(21, i)
  707.             term.write(string.rep(" ", w - 21))
  708.         end
  709.         term.setCursorPos(22, 4)
  710.         term.write("Subject: " .. format(message.subject, 19))
  711.         term.setCursorPos(22, 5)
  712.         term.write("     To: " .. format(message.to, 19))
  713.         term.setTextColor(colors.lightGray)
  714.         term.setCursorPos(21, 6)
  715.         term.write(string.rep("-", w - 21))
  716.         term.setCursorPos(24, 6)
  717.         term.write("[Cancel]")
  718.         term.setCursorPos(34, 6)
  719.         term.write("[Send]")
  720.         term.setTextColor(colors.black)
  721.  
  722.         for i = 1, edh do
  723.             local a = lines[i + scrolly]
  724.             if a then
  725.                 term.setCursorPos(offx, i + offy)
  726.                 term.write(string.rep(" ", w - 21))
  727.                 term.setCursorPos(offx + 1, i + offy)
  728.                 term.write(a)
  729.             end
  730.         end
  731.  
  732.         term.setCursorPos(x + offx, y - scrolly + offy)
  733.     end
  734.  
  735.     local function cursorLoc(x, y, force)
  736.         local sy = y - scrolly
  737.         local redraw = false
  738.         if sy < 1 then
  739.             scrolly = y - 1
  740.             sy = 1
  741.             redraw = true
  742.         elseif sy > edh then
  743.             scrolly = y - edh
  744.             sy = edh
  745.             redraw = true
  746.         end if redraw or force then draw() end
  747.         term.setCursorPos(x + offx, sy + offy)
  748.     end
  749.  
  750.     local cancelled = nil
  751.     local function update(line, e, but, cx, cy)
  752.         if e == "mouse_click" then
  753.             if cy == 6 and cx >= 24 and cx <= 31 then
  754.                 cancelled = "inbox"
  755.                 return true
  756.             elseif cy == 1 then
  757.                 local a = triggermenu(cx, cy)
  758.                 if a then cancelled = a:lower() return true end
  759.             end
  760.         end
  761.     end
  762.  
  763.     draw()
  764.     if message.subject == "" then
  765.         term.setCursorPos(31, 4)
  766.         message.subject = modRead({visibleLength = w - 2, textLength = 100, liveUpdates = update})
  767.         if cancelled then term.setCursorBlink(false) return cancelled end
  768.     end if message.to == "" then
  769.         term.setCursorPos(31, 5)
  770.         message.to = modRead({visibleLength = w - 2, textLength = 40, liveUpdates = update})
  771.         if cancelled then term.setCursorBlink(false) return cancelled end
  772.     end
  773.     draw()
  774.  
  775.     term.setCursorBlink(true)
  776.     while true do
  777.         local e, but, cx, cy = os.pullEvent()
  778.         if e == "key" then
  779.             if but == 200 and y > 1 then
  780.                 x, y = math.min(x, lines[y - 1]:len() + 1), y - 1
  781.                 cursorLoc(x, y)
  782.             elseif but == 208 and y < #lines then
  783.                 x, y = math.min(x, lines[y + 1]:len() + 1), y + 1
  784.                 cursorLoc(x, y)
  785.             elseif but == 203 and x > 1 then
  786.                 x = x - 1
  787.                 cursorLoc(x, y)
  788.             elseif but == 205 and x < lines[y]:len() + 1 then
  789.                 x = x + 1
  790.                 cursorLoc(x, y)
  791.             elseif but == 28 or but == 156 and #lines < 50 then
  792.                 local oldLine = lines[y]
  793.                 lines[y] = lines[y]:sub(1, x - 1)
  794.                 table.insert(lines, y + 1, oldLine:sub(x, -1))
  795.                 x, y = 1, y + 1
  796.                 cursorLoc(x, y, true)
  797.             elseif but == 14 then
  798.                 if x > 1 then
  799.                     lines[y], x = lines[y]:sub(1, x - 2) .. lines[y]:sub(x, -1), x - 1
  800.                     cursorLoc(x, y, true)
  801.                 elseif y > 1 then
  802.                     local prevLen = lines[y - 1]:len() + 1
  803.                     lines[y - 1] = lines[y - 1] .. lines[y]:sub(1, edw - lines[y - 1]:len())
  804.                     table.remove(lines, y)
  805.                     x, y = prevLen, y - 1
  806.                     cursorLoc(x, y, true)
  807.                 end
  808.             end
  809.         elseif e == "char" then
  810.             if lines[y]:len() < edw then
  811.                 lines[y], x = lines[y]:sub(1, x - 1) .. but .. lines[y]:sub(x, -1), x + but:len()
  812.                 cursorLoc(x, y, true)
  813.             else
  814.                 local l, nl = lines[y], lines[y]
  815.                 local w = ""
  816.                 for i = 1, l:len() do
  817.                     if l:sub(i, i) == " " then w, nl = l:sub(i + 1, -1) .. but, l:sub(1, i - 1) end
  818.                 end
  819.  
  820.                 lines[y] = nl
  821.                 table.insert(lines, y + 1, w)
  822.                 x, y = w:len() + 1, y + 1
  823.                 cursorLoc(x, y, true)
  824.             end
  825.         elseif e == "mouse_click" then
  826.             if cy == 1 then
  827.                 local a = triggermenu(cx, cy)
  828.                 if a then term.setCursorBlink(false) return a:lower() end
  829.             elseif cy == 6 and cx >= 24 and cx <= 31 then
  830.                 term.setCursorBlink(false)
  831.                 return "inbox"
  832.             elseif cy == 6 and cx >= 34 and cx <= 39 then
  833.                 message.content = lines
  834.                 term.setCursorBlink(false)
  835.                 term.setTextColor(colors.lightGray)
  836.                 term.setCursorPos(35, 6)
  837.                 term.write("Sending...]")
  838.                 local a = send(username, password, message)
  839.                 term.setCursorPos(35, 6)
  840.                 term.write(string.rep("-", 11))
  841.                 term.setCursorPos(35, 6)
  842.                 if a == "true" then term.write("Sent!]")
  843.                 elseif a == "false" then term.write("Failure!]")
  844.                 else term.write(a .. "]") end
  845.                 sleep(1.6)
  846.  
  847.                 return "inbox"
  848.             elseif cy > offy and cy < edh + offy + 1 then
  849.                 y = math.min(math.max(scrolly + cy - offy, 1), #lines)
  850.                 x = math.min(math.max(cx - offx, 1), lines[y]:len() + 1)
  851.                 cursorLoc(x, y)
  852.             end
  853.         elseif e == "mouse_scroll" and but == -1 and scrolly > 0 then
  854.             scrolly = scrolly - 1
  855.             y = y - 1
  856.             x = math.min(lines[y]:len() + 1, x)
  857.             draw()
  858.         elseif e == "mouse_scroll" and but == 1 and scrolly < #lines - edh then
  859.             scrolly = scrolly + 1
  860.             y = y + 1
  861.             x = math.min(lines[y]:len() + 1, x)
  862.             draw()
  863.         end
  864.     end
  865. end
  866.  
  867.  
  868. --  -------- View
  869.  
  870. local function view(mes, f)
  871.     term.setTextColor(colors.black)
  872.     term.setBackgroundColor(colors.white)
  873.     for i = 3, h - 1 do
  874.         term.setCursorPos(21, i)
  875.         term.write(string.rep(" ", w - 21))
  876.     end
  877.  
  878.     local content = {}
  879.     for _, v in pairs(mes.content) do
  880.         local c = v:sub(1, w - 23):gsub("^%s*(.-)%s*$", "%1")
  881.         table.insert(content, c)
  882.         if v:len() > w - 23 then
  883.             local d = v:sub(w - 22, -1):gsub("^%s*(.-)%s*$", "%1")
  884.             table.insert(content, d)
  885.         end
  886.     end
  887.  
  888.     term.setCursorPos(22, 4)
  889.     term.write("Subject: " .. format(mes.subject, w - 32))
  890.     term.setCursorPos(22, 5)
  891.     if f == "sent" then term.write("     To: " .. format(mes.from, w - 32))
  892.     else term.write("   From: " .. format(mes.from, w - 32)) end
  893.     term.setTextColor(colors.lightGray)
  894.     term.setCursorPos(21, 6)
  895.     term.write(string.rep("-", w - 21))
  896.     term.setCursorPos(24, 6)
  897.     term.write("[<-]")
  898.     if f == "inbox" or f == "trash" then
  899.         term.setCursorPos(w - 12, 6)
  900.         term.write("[Options]")
  901.     end
  902.     term.setTextColor(colors.white)
  903.  
  904.     local function drawlines(lines, loc)
  905.         term.setTextColor(colors.black)
  906.         local l = 1
  907.         for i = 7, h - 2 do
  908.             term.setCursorPos(21, i)
  909.             term.write(string.rep(" ", w - 21))
  910.             term.setCursorPos(22, i)
  911.             if lines[l + loc - 1] then term.write(lines[l + loc - 1]:sub(1, w - 23)) end
  912.             l = l + 1
  913.         end
  914.  
  915.         if #lines > h - 2 then
  916.             local a = math.max(0, math.floor((loc / (#lines - 10)) * 10))
  917.             term.setCursorPos(w - 2, a + 7)
  918.             term.setTextColor(colors.lightGray)
  919.             term.write("o")
  920.         end
  921.  
  922.         term.setTextColor(colors.white)
  923.     end
  924.  
  925.     local loc = 1
  926.     drawlines(content, loc)
  927.     while true do
  928.         local e, but, x, y = os.pullEvent()
  929.         if e == "key" and but == 200 and loc > 1 then
  930.             loc = loc - 1
  931.             drawlines(content, loc)
  932.         elseif e== "key" and but == 208 and loc + 10 < #content then
  933.             loc = loc + 1
  934.             drawlines(content, loc)
  935.         elseif e == "mouse_click" then
  936.             if y == 1 then
  937.                 local a = triggermenu(x, y)
  938.                 if a then
  939.                     term.setBackgroundColor(colors.gray)
  940.                     for i = 3, h - 1 do
  941.                         term.setCursorPos(21, i)
  942.                         term.write(string.rep(" ", w - 21))
  943.                     end
  944.                     return "menu", a:lower()
  945.                 end
  946.             elseif y == 6 and x >= 24 and x <= 27 then
  947.                 term.setBackgroundColor(colors.gray)
  948.                 for i = 3, h - 1 do
  949.                     term.setCursorPos(21, i)
  950.                     term.write(string.rep(" ", w - 21))
  951.                 end
  952.                 return
  953.             elseif f == "inbox" and y == 6 and x >= w - 12 and x <= w - 4 then
  954.                 term.setBackgroundColor(colors.white)
  955.                 term.setTextColor(colors.lightGray)
  956.                 term.setCursorPos(w - 12, 7)
  957.                 term.write(" [Trash]   ")
  958.                 term.setCursorPos(w - 12, 8)
  959.                 term.write(" [Reply]   ")
  960.                 term.setCursorPos(w - 12, 9)
  961.                 term.write(" [Forward] ")
  962.                 term.setCursorPos(w - 12, 10)
  963.                 term.write("           ")
  964.  
  965.                 while true do
  966.                     local e, but, cx, cy = os.pullEvent()
  967.                     if e == "mouse_click" then
  968.                         if cy == 7 and cx >= w - 11 and cx <= w - 5 then
  969.                             -- Trash
  970.                             local a = trash(username, password, mes.msgid)
  971.                             if a ~= "true" then
  972.                                 term.setCursorPos(22, h - 1)
  973.                                 term.setBackgroundColor(colors.white)
  974.                                 term.setTextColor(colors.lightGray)
  975.                                 if a == "false" then term.write("Trash Failed!")
  976.                                 else term.write(a) end
  977.                                 sleep(1.6)
  978.                             end
  979.                             return "reload"
  980.                         elseif cy == 8 and cx >= w - 11 and cx <= w - 5 then
  981.                             -- Reply
  982.                             compose({to = mes.from, subject = "Re:" .. mes.subject})
  983.                             return "reload"
  984.                         elseif cy == 9 and cx >= w - 11 and cx <= w - 3 then
  985.                             -- Forward
  986.                             compose({subject = "Fwd:" .. mes.subject})
  987.                             return "reload"
  988.                         else break end
  989.                     end
  990.                 end
  991.                 drawlines(content, loc)
  992.             elseif f == "trash" and y == 6 and x >= w - 12 and x <= w - 4 then
  993.                 term.setBackgroundColor(colors.white)
  994.                 term.setTextColor(colors.lightGray)
  995.                 term.setCursorPos(w - 12, 7)
  996.                 term.write(" [Delete]  ")
  997.                 term.setCursorPos(w - 12, 8)
  998.                 term.write("           ")
  999.  
  1000.                 while true do
  1001.                     local e, but, cx, cy = os.pullEvent()
  1002.                     if e == "mouse_click" then
  1003.                         if cy == 7 and cx >= w - 11 and cx <= w - 4 then
  1004.                             -- Delete
  1005.                             local a = delete(username, password, mes.msgid)
  1006.                             if a ~= "true" then
  1007.                                 term.setCursorPos(22, h - 1)
  1008.                                 term.setBackgroundColor(colors.white)
  1009.                                 term.setTextColor(colors.lightGray)
  1010.                                 if a == "false" then term.write("Deletion Failed!")
  1011.                                 else term.write(a) end
  1012.                                 sleep(1.6)
  1013.                             end
  1014.                             return "reload"
  1015.                         else break end
  1016.                     end
  1017.                 end
  1018.                 drawlines(content, loc)
  1019.             end
  1020.         elseif e == "mouse_scroll" and x >= 21 and y >= 5 then
  1021.             local a = 200
  1022.             if but == 1 then a = 208 end
  1023.             os.queueEvent("key", a)
  1024.         end
  1025.     end
  1026. end
  1027.  
  1028.  
  1029. --  -------- Inbox
  1030.  
  1031. local function folder(f)
  1032.     local wid, sx = 18, 5
  1033.     term.setCursorBlink(false)
  1034.     term.setBackgroundColor(colors.gray)
  1035.     term.setTextColor(colors.white)
  1036.     term.clear()
  1037.     drawmenu()
  1038.  
  1039.     local messages = {}
  1040.  
  1041.     if f == "inbox" then messages = getinbox(username, password)
  1042.     elseif f == "sent" then messages = getsent(username, password)
  1043.     elseif f == "trash" then messages = gettrash(username, password) end
  1044.  
  1045.     term.setBackgroundColor(colors.gray)
  1046.     if f == "trash" then
  1047.         term.setCursorPos(2, 3)
  1048.         term.write("Trash")
  1049.         term.setCursorPos(wid - 7, 3)
  1050.         term.write("[Empty]")
  1051.     else
  1052.         term.setCursorPos(wid/2 - f:len()/2, 3)
  1053.         term.write(f:sub(1, 1):upper() .. f:sub(2, -1))
  1054.     end
  1055.  
  1056.     if type(messages) == "string" then
  1057.         term.setBackgroundColor(colors.lightBlue)
  1058.         for i = 5, 8 do
  1059.             term.setCursorPos(1, i)
  1060.             term.write(string.rep(" ", 28))
  1061.         end
  1062.         term.setCursorPos(2, 6)
  1063.         term.write("Error: Could not get mail!")
  1064.         term.setCursorPos(2, 7)
  1065.         term.write(messages)
  1066.  
  1067.         for i = 10, 12 do
  1068.             term.setCursorPos(1, i)
  1069.             term.write(string.rep(" ", 28))
  1070.         end
  1071.         term.setCursorPos(2, 11)
  1072.         term.write("Click to refresh...")
  1073.  
  1074.         while true do
  1075.             local e, but, cx, cy = os.pullEvent()
  1076.             if (e == "mouse_click" and cy > 1) or e == "key" then
  1077.                 break
  1078.             elseif e == "mouse_click" and cy == 1 then
  1079.                 local a = triggermenu(cx, cy)
  1080.                 if a then return a:lower() end
  1081.             end
  1082.         end
  1083.         return f
  1084.     end
  1085.  
  1086.     local sel, loc = 1, 1
  1087.     local dis = updateDisplayList(messages, loc, 3)
  1088.  
  1089.     local function drawmessages(dis)
  1090.         if #dis > 0 then
  1091.             for i, v in ipairs(dis) do
  1092.                 if i == sel then term.setBackgroundColor(colors.lightBlue)
  1093.                 else term.setBackgroundColor(colors.cyan) end
  1094.                 for x = sx, sx + 3 do
  1095.                     term.setCursorPos(1, (i - 1) * 5 + x)
  1096.                     term.write(string.rep(" ", wid))
  1097.                 end
  1098.  
  1099.                 term.setCursorPos(2, (i - 1) * 5 + sx + 1)
  1100.                 if i == sel then term.write(format(v.subject, 17))
  1101.                 else term.write(format(v.subject, 17)) end
  1102.                 term.setCursorPos(2, (i - 1) * 5 + sx + 2)
  1103.                 term.write(format(v.from, 18))
  1104.             end
  1105.         else
  1106.             term.setBackgroundColor(colors.lightBlue)
  1107.             for i = sx, sx + 2 do
  1108.                 term.setCursorPos(1, i)
  1109.                 term.write(string.rep(" ", wid))
  1110.             end
  1111.             term.setCursorPos(2, sx + 1)
  1112.             term.write("No Messages!")
  1113.         end
  1114.     end
  1115.  
  1116.     drawmessages(dis)
  1117.     term.setBackgroundColor(colors.gray)
  1118.     term.setCursorPos(wid + (w - wid)/2 - 7, 10)
  1119.     term.write("No Message Selected")
  1120.  
  1121.     while true do
  1122.         local e, but, x, y = os.pullEvent()
  1123.         if e == "key" then
  1124.             if but == 200 then
  1125.                 if sel > 1 then
  1126.                     sel = sel - 1
  1127.                     drawmessages(dis)
  1128.                 elseif loc > 1 then
  1129.                     loc = loc - 1
  1130.                     dis = updateDisplayList(messages, loc, 3)
  1131.                     drawmessages(dis)
  1132.                 end
  1133.             elseif but == 208 then
  1134.                 if sel < #dis then
  1135.                     sel = sel + 1
  1136.                     drawmessages(dis)
  1137.                 elseif loc + 3 - 1 < #messages then
  1138.                     loc = loc + 1
  1139.                     dis = updateDisplayList(messages, loc, 3)
  1140.                     drawmessages(dis)
  1141.                 end
  1142.             elseif but == 28 and #dis > 0 then
  1143.                 local a, b = view(dis[sel], f)
  1144.                 if a == "menu" then return b
  1145.                 elseif a == "reload" then return f end
  1146.                 term.setBackgroundColor(colors.gray)
  1147.                 term.setCursorPos(wid + (w - wid)/2 - 7, 10)
  1148.                 term.write("No Message Selected")
  1149.             end
  1150.         elseif e == "mouse_click" then
  1151.             if y == 1 then
  1152.                 local a = triggermenu(x, y)
  1153.                 if a then return a:lower() end
  1154.             elseif y == 3 and x >= wid - 7 and x <= wid - 1 then
  1155.                 -- Empty
  1156.                 local a = emptytrash(username, password)
  1157.                 if a ~= "true" then
  1158.                     term.setBackgroundColor(colors.gray)
  1159.                     term.setCursorPos(2, 4)
  1160.                     if a == "false" then term.write("Deletion Failed!")
  1161.                     else term.write(a) end
  1162.                     sleep(1.6)
  1163.                 end
  1164.                 return f
  1165.             elseif #dis > 0 then
  1166.                 for i, v in ipairs(dis) do
  1167.                     if y >= (i - 1) * 5 + sx and y <= (i - 1) * 5 + sx + 3 and x >= 1 and x <= wid then
  1168.                         sel = i
  1169.                         drawmessages(dis)
  1170.                         local a, b = view(v, f)
  1171.                         if a == "menu" then return b
  1172.                         elseif a == "reload" then return f end
  1173.                         term.setBackgroundColor(colors.gray)
  1174.                         term.setCursorPos(wid + (w - wid)/2 - 7, 10)
  1175.                         term.write("No Message Selected")
  1176.                     end
  1177.                 end
  1178.             end
  1179.         elseif e == "mouse_scroll" and #messages > 1 and x >= 1 and x <= wid + 1 then
  1180.             local a = 200
  1181.             if but == 1 then a = 208 end
  1182.             os.queueEvent("key", a)
  1183.         end
  1184.     end
  1185.  
  1186.     return "inbox"
  1187. end
  1188.  
  1189. local function inbox()
  1190.     local opt = "inbox"
  1191.     while true do
  1192.         if opt == "inbox" or opt == "sent" or opt == "trash" then opt = folder(opt) end
  1193.         if opt == "exit" then return "exit"
  1194.         elseif opt == "logout" then return "menu"
  1195.         elseif opt == "new" then opt = compose()
  1196.         elseif opt == "account" then opt = account() if opt == "menu" then return "menu" end end
  1197.     end
  1198. end
  1199.  
  1200.  
  1201. --  -------- Menu
  1202.  
  1203. local function login()
  1204.     title("Thunderhawk " .. version .. " - Login")
  1205.  
  1206.     term.setBackgroundColor(colors.cyan)
  1207.     for i = 8, 11 do term.setCursorPos(5, i) term.write(string.rep(" ", 36)) end
  1208.     term.setCursorPos(6, 9)
  1209.     term.write("Username: ")
  1210.     term.setCursorPos(6, 10)
  1211.     term.write("Password: ")
  1212.     drawButton({"Cancel", 8, 15, bg = colors.pink, highlight = colors.red}, true)
  1213.     term.setBackgroundColor(colors.cyan)
  1214.  
  1215.     local cancelled = false
  1216.     local function update(line, e, but, x, y)
  1217.         if e == "mouse_click" and x >= 8 and x <= 23 and y >= 14 and y <= 16 then
  1218.             cancelled = true
  1219.             return true
  1220.         end
  1221.     end
  1222.  
  1223.     term.setCursorPos(16, 9)
  1224.     local user = modRead({textLength = 40, visibleLength = 38, liveUpdates = update})
  1225.     if user == "" or cancelled then return "menu" end
  1226.  
  1227.     term.setCursorPos(16, 10)
  1228.     local pass = modRead({replaceChar = "*", textLength = 40, visibleLength = 38, liveUpdates = update})
  1229.     if pass == "" or cancelled then return "menu" end
  1230.     pass = sha256(pass)
  1231.  
  1232.     local stat = verify(user, pass)
  1233.     if stat == "true" then
  1234.         drawButton({"Success", 20, 15})
  1235.         sleep(1.6)
  1236.         return "inbox", user, pass
  1237.     elseif stat == "false" then drawButton({"Invalid Credentials", 20, 15})
  1238.     else drawButton({stat, 20, 15}) end
  1239.     sleep(1.6)
  1240.  
  1241.     return "menu"
  1242. end
  1243.  
  1244. local function register()
  1245.     title("Thunderhawk " .. version .. " - Register")
  1246.  
  1247.     term.setBackgroundColor(colors.gray)
  1248.     term.setCursorPos(3, 6)
  1249.     term.write("To register, please visit the Thunderhawk")
  1250.     term.setCursorPos(3, 7)
  1251.     term.write("website at:")
  1252.     term.setCursorPos(3, 9)
  1253.     term.write("http://firewolfcc.com/thunderhawk")
  1254.     term.setCursorPos(3, 11)
  1255.     term.write("Press any key to return.")
  1256.     os.pullEvent("key")
  1257.     os.queueEvent("thunderhawk_dummyEvent")
  1258.     os.pullEvent()
  1259.  
  1260.     return "menu"
  1261. end
  1262.  
  1263. local function menu()
  1264.     title("Thunderhawk " .. version)
  1265.     local opt = prompt({{"Login", w/2 - 10, 9}, {"Register", w/2 + 2, 9},
  1266.         {"Exit Thunderhawk", w/2 - 8, 14, bg = colors.pink, highlight = colors.red}},
  1267.         "horizontal"):lower()
  1268.     if opt == "exit thunderhawk" then opt = "exit" end
  1269.     return opt
  1270. end
  1271.  
  1272.  
  1273. --  -------- Main
  1274.  
  1275. local function updateclient()
  1276.     local updateLocation = "/.thunderhawk-update"
  1277.     fs.delete(updateLocation)
  1278.  
  1279.     download(thunderhawkURL, updateLocation)
  1280.     local a, b = io.open(updateLocation, "r"), io.open(thunderhawkLocation, "r")
  1281.     local new, cur = a:read("*a"), b:read("*a")
  1282.     a:close()
  1283.     b:close()
  1284.  
  1285.     if cur ~= new then
  1286.         fs.delete(thunderhawkLocation)
  1287.         fs.move(updateLocation, thunderhawkLocation)
  1288.         shell.run(thunderhawkLocation)
  1289.         return true
  1290.     else
  1291.         fs.delete(updateLocation)
  1292.         return false
  1293.     end
  1294. end
  1295.  
  1296. local function main()
  1297.     -- Logo
  1298.     title("Welcome to Thunderhawk " .. version)
  1299.  
  1300.     term.setCursorPos(1, 7)
  1301.     term.setBackgroundColor(colors.lightBlue)
  1302.     centerPrint(string.rep(" ", 34))
  1303.     centerPrint([[               .-"-.              ]])
  1304.     centerPrint([[   __________ /  ,~a\_ ________   ]])
  1305.     centerPrint([[  |\          \  \__))>       /|  ]])
  1306.     centerPrint([[  |  \        ,) ." \       /  |  ]])
  1307.     centerPrint([[  |    \     /  (    \    /    |  ]])
  1308.     centerPrint([[  |      \_ /   )    ; _/      |  ]])
  1309.     centerPrint([[  |        /   /     /         |  ]])
  1310.     centerPrint([[  |      ,/_."' __.-'          |  ]])
  1311.     centerPrint([[  |_____ /_/'"\\___ ___________|  ]])
  1312.     centerPrint([[               '~~~'              ]])
  1313.     centerPrint(string.rep(" ", 34))
  1314.     if autoupdate then if updateclient() then error() end end
  1315.  
  1316.     -- Main run loop
  1317.     local opt = "menu"
  1318.     while true do
  1319.         if opt == "menu" then opt = menu()
  1320.         elseif opt == "login" then opt, username, password = login()
  1321.         elseif opt == "register" then opt, username, password = register()
  1322.         elseif opt == "inbox" and username and password then opt = inbox()
  1323.         elseif opt == "exit" then return end
  1324.     end
  1325. end
  1326.  
  1327. -- Advanced computer
  1328. if not isAdvanced() then
  1329.     print("Thunderhawk " .. version .. " requires an advanced computer!")
  1330.     error()
  1331. end
  1332.  
  1333. -- Read only
  1334. if fs.isReadOnly(thunderhawkLocation) then
  1335.     print("Thunderhawk is located in a read only location!")
  1336.     print("This could be caused by Thunderhawk being placed")
  1337.     print("in the rom, or by another program modifying the")
  1338.     print("fs API")
  1339.     error()
  1340. end
  1341.  
  1342. -- Run
  1343. local _, err = pcall(function() main() end)
  1344.  
  1345. -- Show error
  1346. if err and not err:find("Terminated") then
  1347.     term.setCursorBlink(false)
  1348.     title("Thunderhawk " .. version .. " - Crash")
  1349.  
  1350.     term.setBackgroundColor(colors.cyan)
  1351.     for i = 7, 9 do term.setCursorPos(5, i) term.write(string.rep(" ", 36)) end
  1352.     term.setCursorPos(6, 8)
  1353.     term.write("Thunderhawk Has Crashed!")
  1354.     term.setBackgroundColor(colors.gray)
  1355.     term.setCursorPos(2, 11)
  1356.     print(err)
  1357.  
  1358.     local x, y = term.getCursorPos()
  1359.     y = y + 1
  1360.     term.setBackgroundColor(colors.cyan)
  1361.     for i = y, y + 3 do term.setCursorPos(5, i) term.write(string.rep(" ", 36)) end
  1362.     term.setCursorPos(6, y + 1)
  1363.     term.write("Please report this error to")
  1364.     term.setCursorPos(6, y + 2)
  1365.     term.write("GravityScore! Click to exit.")
  1366.    
  1367.     while true do
  1368.         local e = os.pullEvent()
  1369.         if e == "mouse_click" or e == "key" then break end
  1370.     end
  1371. end
  1372.  
  1373. -- Exit
  1374. term.setTextColor(colors.white)
  1375. term.setBackgroundColor(colors.black)
  1376. term.clear()
  1377. term.setCursorPos(1, 1)
  1378. centerPrint("Thanks For Using Thunderhawk " .. version)
  1379. centerPrint("Made by GravityScore")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement