Advertisement
GravityScore

Firewolf

Oct 3rd, 2012
9,698
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 85.26 KB | None | 0 0
  1.  
  2. --
  3. --  Firewolf Website Browser
  4. --  Made by GravityScore and 1lann
  5. --  License found here: https://raw.github.com/1lann/Firewolf/master/LICENSE
  6. --
  7. --  Original Concept From RednetExplorer 2.4.1
  8. --  RednetExplorer Made by ComputerCraftFan11
  9. --
  10.  
  11.  
  12. --  -------- Variables
  13.  
  14. -- Version
  15. local version = "2.5"
  16. local build = 36
  17. local browserAgent = "Firewolf " .. version
  18. local tArgs = {...}
  19.  
  20. -- Server Identification
  21. local serverID = "other"
  22. local serverList = {experimental = "Experimental", other = "Other"}
  23.  
  24. -- Updating
  25. local autoupdate = "true"
  26. local noInternet = false
  27.  
  28. -- Resources
  29. local graphics = {}
  30. local files = {}
  31. local w, h = term.getSize()
  32.  
  33. -- Debugging
  34. local debugFile = nil
  35.  
  36. -- Environment
  37. local oldEnv = {}
  38. local env = {}
  39. local api = {}
  40. local override = {}
  41. local antivirus = {}
  42.  
  43. -- Themes
  44. local theme = {}
  45.  
  46. -- Databases
  47. local blacklist = {}
  48. local whitelist = {}
  49. local dnsDatabase = {{}, {}}
  50.  
  51. -- Website Loading
  52. local pages = {}
  53. local errorPages = {}
  54.  
  55. local website = ""
  56. local homepage = ""
  57. local timeout = 0.2
  58. local loadingRate, loadingClock = 0, nil
  59. local openAddressBar, clickableAddressBar = true, true
  60. local menuBarOpen = false
  61. local offsetclick = true
  62. local websiteerror = nil
  63.  
  64. -- Tabs
  65. local tabs = {}
  66. local filters = {}
  67. local currentTab = 1
  68.  
  69. -- Protocols
  70. local curProtocol = {}
  71. local protocols = {}
  72.  
  73. -- History
  74. local addressBarHistory = {}
  75.  
  76. -- Events
  77. local event_load = "firewolf_websiteLoadEvent"
  78. local event_redirect = "firewolf_redirectEvent"
  79. local event_error = "firewolf_siteErrorEvent"
  80. local event_exit = "firewolf_exitEvent"
  81.  
  82. -- Download URLs
  83. local firewolfURL = "https://raw.github.com/1lann/Firewolf/master/entities/other.lua"
  84. local serverURL = "https://raw.github.com/1lann/Firewolf/master/server/server-release.lua"
  85. local buildURL = "https://raw.github.com/1lann/Firewolf/master/build"
  86.  
  87. -- Data Locations
  88. local rootFolder = "/.Firewolf_Data"
  89. local cacheFolder = rootFolder .. "/cache"
  90. local serverFolder = rootFolder .. "/servers"
  91. local websiteDataFolder = rootFolder .. "/website_data"
  92. local themeLocation = rootFolder .. "/theme"
  93. local serverLocation = rootFolder .. "/server_software"
  94. local settingsLocation = rootFolder .. "/settings"
  95. local debugLogLocation = "/firewolf-log"
  96. local firewolfLocation = "/" .. shell.getRunningProgram()
  97.  
  98. local userBlacklist = rootFolder .. "/user_blacklist"
  99. local userWhitelist = rootFolder .. "/user_whitelist"
  100.  
  101. local function isAdvanced() return term.isColor and term.isColor() end
  102.  
  103. local function modemPresent()
  104.     if curProtocol == protocols.rdnt then
  105.         for _, v in pairs(rs.getSides()) do
  106.             if peripheral.getType(v) == "modem" then rednet.open(v) return true end
  107.         end
  108.     else return true end
  109.     return false
  110. end
  111.  
  112.  
  113. --  -------- Utilities
  114.  
  115. local function debugLog(n, ...)
  116.     local lArgs = {...}
  117.     if debugFile then
  118.         if not n then return end
  119.         debugFile:write("\n" .. tostring(n) .. " : ")
  120.         for k, v in pairs(lArgs) do
  121.             if type(v) == "string" or type(v) == "number" or not type(v) or type(v) == "boolean" then
  122.                 debugFile:write(tostring(v) .. ", ")
  123.             else debugFile:write("type-" .. type(v) .. ", ") end
  124.         end
  125.     end
  126. end
  127.  
  128. local function clear(site, background, drawmenu)
  129.     local titles = {
  130.         ["firewolf"] = "Firewolf",
  131.         ["server/rdnt"] = "Server Management",
  132.         ["server/http"] = "Server Management",
  133.         ["help"] = "Help",
  134.         ["settings"] = "Settings",
  135.         ["credits"] = "Credits",
  136.         ["crash"] = "Crashed!",
  137.         ["overspeed"] = "Too Fast!"
  138.     }
  139.  
  140.     local title = titles[site] or ""
  141.     term.setBackgroundColor(background or colors.black)
  142.     term.setTextColor(colors[theme["address-bar-text"]])
  143.     if drawmenu ~= true then term.clear() end
  144.  
  145.     if not menuBarOpen then
  146.         term.setBackgroundColor(colors[theme["address-bar-background"]])
  147.         term.setCursorPos(2, 1)
  148.         term.clearLine()
  149.         if site:len() > w - 10 then site = site:sub(1, 38) .. "..." end
  150.         if curProtocol == protocols.http then write("http://" .. site)
  151.         else write("rdnt://" .. site) end
  152.         term.setCursorPos(w - title:len() - 1, 1)
  153.         write(title)
  154.  
  155.         if isAdvanced() then
  156.             term.setCursorPos(w, 1)
  157.             term.setBackgroundColor(colors[theme["top-box"]])
  158.             term.setTextColor(colors[theme["text-color"]])
  159.             write("<")
  160.         end
  161.  
  162.         term.setBackgroundColor(background or colors.black)
  163.         term.setTextColor(colors.white)
  164.     else
  165.         term.setCursorPos(1, 1)
  166.         term.setBackgroundColor(colors[theme["top-box"]])
  167.         term.setTextColor(colors[theme["text-color"]])
  168.         term.clearLine()
  169.         write("> [- Exit Firewolf -]                              ")
  170.     end
  171.  
  172.     print("")
  173. end
  174.  
  175. local function modRead(properties)
  176.     local w, h = term.getSize()
  177.     local defaults = {replaceChar = nil, history = nil, visibleLength = nil, textLength = nil,
  178.         liveUpdates = nil, exitOnKey = nil}
  179.     if not properties then properties = {} end
  180.     for k, v in pairs(defaults) do if not properties[k] then properties[k] = v end end
  181.     if properties.replaceChar then properties.replaceChar = properties.replaceChar:sub(1, 1) end
  182.     if not properties.visibleLength then properties.visibleLength = w end
  183.  
  184.     local sx, sy = term.getCursorPos()
  185.     local line = ""
  186.     local pos = 0
  187.     local historyPos = nil
  188.  
  189.     local function redraw(repl)
  190.         local scroll = 0
  191.         if properties.visibleLength and sx + pos > properties.visibleLength + 1 then
  192.             scroll = (sx + pos) - (properties.visibleLength + 1)
  193.         end
  194.  
  195.         term.setCursorPos(sx, sy)
  196.         local a = repl or properties.replaceChar
  197.         if a then term.write(string.rep(a, line:len() - scroll))
  198.         else term.write(line:sub(scroll + 1, -1)) end
  199.         term.setCursorPos(sx + pos - scroll, sy)
  200.     end
  201.  
  202.     local function sendLiveUpdates(event, ...)
  203.         if type(properties.liveUpdates) == "function" then
  204.             local ox, oy = term.getCursorPos()
  205.             local a, data = properties.liveUpdates(line, event, ...)
  206.             if a == true and not data then
  207.                 term.setCursorBlink(false)
  208.                 return line
  209.             elseif a == true and data then
  210.                 term.setCursorBlink(false)
  211.                 return data
  212.             end
  213.             term.setCursorPos(ox, oy)
  214.         end
  215.     end
  216.  
  217.     local a = sendLiveUpdates("delete")
  218.     if a then return a end
  219.     term.setCursorBlink(true)
  220.     while true do
  221.         local e, but, x, y, p4, p5 = os.pullEvent()
  222.         if e == "char" then
  223.             local s = false
  224.             if properties.textLength and line:len() < properties.textLength then s = true
  225.             elseif not properties.textLength then s = true end
  226.  
  227.             local canType = true
  228.             if not properties.grantPrint and properties.refusePrint then
  229.                 local canTypeKeys = {}
  230.                 if type(properties.refusePrint) == "table" then
  231.                     for _, v in pairs(properties.refusePrint) do
  232.                         table.insert(canTypeKeys, tostring(v):sub(1, 1))
  233.                     end
  234.                 elseif type(properties.refusePrint) == "string" then
  235.                     for char in properties.refusePrint:gmatch(".") do
  236.                         table.insert(canTypeKeys, char)
  237.                     end
  238.                 end
  239.                 for _, v in pairs(canTypeKeys) do if but == v then canType = false end end
  240.             elseif properties.grantPrint then
  241.                 canType = false
  242.                 local canTypeKeys = {}
  243.                 if type(properties.grantPrint) == "table" then
  244.                     for _, v in pairs(properties.grantPrint) do
  245.                         table.insert(canTypeKeys, tostring(v):sub(1, 1))
  246.                     end
  247.                 elseif type(properties.grantPrint) == "string" then
  248.                     for char in properties.grantPrint:gmatch(".") do table.insert(canTypeKeys, char) end
  249.                 end
  250.                 for _, v in pairs(canTypeKeys) do if but == v then canType = true end end
  251.             end
  252.  
  253.             if s and canType then
  254.                 line = line:sub(1, pos) .. but .. line:sub(pos + 1, -1)
  255.                 pos = pos + 1
  256.                 redraw()
  257.             end
  258.         elseif e == "key" then
  259.             if but == keys.enter then break
  260.             elseif but == keys.left then if pos > 0 then pos = pos - 1 redraw() end
  261.             elseif but == keys.right then if pos < line:len() then pos = pos + 1 redraw() end
  262.             elseif (but == keys.up or but == keys.down) and properties.history and
  263.                     #properties.history > 0 then
  264.                 redraw(" ")
  265.                 if but == keys.up then
  266.                     if not historyPos and #properties.history > 0 then
  267.                         historyPos = #properties.history
  268.                     elseif historyPos > 1 then historyPos = historyPos - 1 end
  269.                 elseif but == keys.down then
  270.                     if historyPos == #properties.history then historyPos = nil
  271.                     elseif historyPos then historyPos = historyPos + 1 end
  272.                 end
  273.  
  274.                 if properties.history and historyPos then
  275.                     line = properties.history[historyPos]
  276.                     pos = line:len()
  277.                 else
  278.                     line = ""
  279.                     pos = 0
  280.                 end
  281.  
  282.                 redraw()
  283.                 local a = sendLiveUpdates("history")
  284.                 if a then return a end
  285.             elseif but == keys.backspace and pos > 0 then
  286.                 redraw(" ")
  287.                 line = line:sub(1, pos - 1) .. line:sub(pos + 1, -1)
  288.                 pos = pos - 1
  289.                 redraw()
  290.                 local a = sendLiveUpdates("delete")
  291.                 if a then return a end
  292.             elseif but == keys.home then
  293.                 pos = 0
  294.                 redraw()
  295.             elseif but == keys.delete and pos < line:len() then
  296.                 redraw(" ")
  297.                 line = line:sub(1, pos) .. line:sub(pos + 2, -1)
  298.                 redraw()
  299.                 local a = sendLiveUpdates("delete")
  300.                 if a then return a end
  301.             elseif but == keys["end"] then
  302.                 pos = line:len()
  303.                 redraw()
  304.             elseif properties.exitOnKey then
  305.                 if but == properties.exitOnKey or (properties.exitOnKey == "control" and
  306.                         (but == 29 or but == 157)) then
  307.                     term.setCursorBlink(false)
  308.                     return nil
  309.                 end
  310.             end
  311.         end
  312.  
  313.         local a = sendLiveUpdates(e, but, x, y, p4, p5)
  314.         if a then return a end
  315.     end
  316.  
  317.     term.setCursorBlink(false)
  318.     if line then line = line:gsub("^%s*(.-)%s*$", "%1") end
  319.     return line
  320. end
  321.  
  322.  
  323. --  -------- API
  324.  
  325. --  Drawing
  326.  
  327. local function printWithType(t, func)
  328.     if type(t) == "table" then
  329.         for _, v in pairs(t) do env.pcall(function() printWithType(v, func) end) end
  330.     else func(tostring(t)) end
  331. end
  332.  
  333. api.centerWrite = function(text)
  334.     printWithType(text, function(t)
  335.         local x, y = term.getCursorPos()
  336.         term.setCursorPos(math.ceil((w + 1)/2 - t:len()/2), y)
  337.         write(t)
  338.     end)
  339. end
  340.  
  341. api.centerPrint = function(text)
  342.     printWithType(text, function(t)
  343.         local x, y = term.getCursorPos()
  344.         term.setCursorPos(math.ceil((w + 2)/2 - t:len()/2), y)
  345.         print(t)
  346.     end)
  347. end
  348.  
  349. api.leftWrite = function(text)
  350.     printWithType(text, function(t)
  351.         local x, y = term.getCursorPos()
  352.         term.setCursorPos(1, y)
  353.         write(t)
  354.     end)
  355. end
  356.  
  357. api.leftPrint = function(text)
  358.     printWithType(text, function(t)
  359.         local x, y = term.getCursorPos()
  360.         term.setCursorPos(1, y)
  361.         print(t)
  362.     end)
  363. end
  364.  
  365. api.rightWrite = function(text)
  366.     printWithType(text, function(t)
  367.         local x, y = term.getCursorPos()
  368.         term.setCursorPos(w - t:len() + 1, y)
  369.         write(t)
  370.     end)
  371. end
  372.  
  373. api.rightPrint = function(text)
  374.     printWithType(text, function(t)
  375.         local x, y = term.getCursorPos()
  376.         term.setCursorPos(w - t:len() + 1, y)
  377.         print(t)
  378.     end)
  379. end
  380.  
  381. api.clearArea = function() term.clear() term.setCursorPos(1, 1) end
  382. api.cPrint = function(text) api.centerPrint(text) end
  383. api.cWrite = function(text) api.centerWrite(text) end
  384. api.lPrint = function(text) api.leftPrint(text) end
  385. api.lWrite = function(text) api.leftWrite(text) end
  386. api.rPrint = function(text) api.rightPrint(text) end
  387. api.rWrite = function(text) api.rightWrite(text) end
  388.  
  389.  
  390. --  Server Interation
  391.  
  392. api.loadFileFromServer = function(path)
  393.     if type(path) ~= "string" then error("expected string", 2) end
  394.     sleep(0.05)
  395.     if path:sub(1, 1) == "/" then path = path:sub(2, -1) end
  396.     local id, content = curProtocol.getWebsite(website .. "/" .. path)
  397.     if id then return content end
  398.     return nil
  399. end
  400.  
  401. api.ioReadFileFromServer = function(path)
  402.     local content = api.loadFileFromServer(path)
  403.     if content then
  404.         local f = env.io.open(rootFolder .. "/temp_file", "w")
  405.         f:write(content)
  406.         f:close()
  407.         return env.io.open(rootFolder .. "/temp_file", "r")
  408.     end
  409.     return nil
  410. end
  411.  
  412. api.loadImageFromServer = function(path)
  413.     local content = api.loadFileFromServer(path)
  414.     if content then
  415.         local f = env.io.open(rootFolder .. "/temp_file", "w")
  416.         f:write(content)
  417.         f:close()
  418.  
  419.         local image = paintutils.loadImage(rootFolder .. "/temp_file")
  420.         env.fs.delete("/temp_file")
  421.         return image
  422.     end
  423.     return nil
  424. end
  425.  
  426. api.writeDataFile = function(path, content)
  427.     if type(path) ~= "string" or type(content) ~= "string" then
  428.         error("expected string, string", 2) end
  429.     if path:sub(1, 1) == "/" then path = path:sub(2, -1) end
  430.     local dataPath = websiteDataFolder .. "/" .. path:gsub("/", "$slazh$")
  431.  
  432.     if env.fs.isReadOnly(dataPath) then return false end
  433.     if env.fs.exists(dataPath) then env.fs.delete(dataPath) end
  434.     local f = env.io.open(dataPath, "w")
  435.     if not f then return false end
  436.     f:write(content)
  437.     f:close()
  438.     return true
  439. end
  440.  
  441. api.readDataFile = function(path)
  442.     if type(path) ~= "string" then error("readDataFile: expected string") end
  443.     if path:sub(1, 1) == "/" then path = path:sub(2, -1) end
  444.     local dataPath = websiteDataFolder .. "/" .. path:gsub("/", "$slazh$")
  445.  
  446.     if env.fs.isDir(dataPath) then env.fs.delete(dataPath) end
  447.     if env.fs.exists(dataPath) then
  448.         local f = env.io.open(dataPath, "r")
  449.         local cont = f:read("*a")
  450.         f:close()
  451.         return cont
  452.     end
  453.     return nil
  454. end
  455.  
  456. api.saveFileToUserComputer = function(content)
  457.     if type(content) ~= "string" then error("expected string", 2) end
  458.     local oldback, oldtext = override.term.getBackgroundColor(), override.term.getTextColor()
  459.     local ox, oy = term.getCursorPos()
  460.  
  461.     term.setTextColor(colors[theme["text-color"]])
  462.     term.setBackgroundColor(colors[theme["background"]])
  463.     term.clear()
  464.     term.setCursorPos(1, 1)
  465.     term.setBackgroundColor(colors[theme["top-box"]])
  466.     print("")
  467.     leftPrint(string.rep(" ", 20))
  468.     leftPrint(" Save File Request  ")
  469.     leftPrint(string.rep(" ", 20))
  470.     print("")
  471.  
  472.     term.setBackgroundColor(colors[theme["bottom-box"]])
  473.     for i = 1, 11 do rightPrint(string.rep(" ", 36)) end
  474.     term.setCursorPos(1, 7)
  475.     rightPrint("The website: ")
  476.     rightPrint(website .. "  ")
  477.     rightPrint("Is requesting to save a file ")
  478.     rightPrint("to your computer. ")
  479.  
  480.     local ret = nil
  481.     local opt = prompt({{"Save File", w - 16, 12}, {"Cancel", w - 13, 13}}, "vertical")
  482.     if opt == "Save File" then
  483.         while not ret do
  484.             term.setCursorPos(1, 15)
  485.             rightWrite(string.rep(" ", 36))
  486.             term.setCursorPos(w - 34, 15)
  487.             write("Path: /")
  488.             local p = read()
  489.  
  490.             term.setCursorPos(1, 15)
  491.             rightWrite(string.rep(" ", 36))
  492.             if p == "" then
  493.                 rightWrite("Cancelled ")
  494.                 break
  495.             elseif fs.exists("/" .. p) then
  496.                 rightWrite("File Already Exists! ")
  497.             else
  498.                 rightWrite("File Saved! ")
  499.                 ret = "/" .. p
  500.                 local f = env.io.open(ret, "w")
  501.                 f:write(content)
  502.                 f:close()
  503.             end
  504.  
  505.             openAddressBar = false
  506.             sleep(1.3)
  507.             openAddressBar = true
  508.         end
  509.     elseif opt == "Cancel" then
  510.         term.setCursorPos(1, 15)
  511.         rightWrite("Saving Cancelled! ")
  512.     end
  513.  
  514.     openAddressBar = false
  515.     sleep(1.3)
  516.     openAddressBar = true
  517.  
  518.     term.setBackgroundColor(oldback or colors.black)
  519.     term.setTextColor(oldtext or colors.white)
  520.     term.clear()
  521.     term.setCursorPos(ox, oy)
  522.     return ret
  523. end
  524.  
  525. api.urlDownload = function(url)
  526.     if type(url) ~= "string" then error("expected string", 2) end
  527.     local source = nil
  528.     http.request(url)
  529.     local a = os.startTimer(10)
  530.     while true do
  531.         local e, surl, handle = os.pullEvent()
  532.         if e == "http_success" then
  533.             source = handle.readAll()
  534.             break
  535.         elseif e == "http_failure" or (e == "timer" and surl == a) then
  536.             break
  537.         end
  538.     end
  539.  
  540.     if type(source) == "string" then
  541.         return api.saveFileToUserComputer(source)
  542.     else return nil end
  543. end
  544.  
  545. api.pastebinDownload = function(code)
  546.     return api.urlDownload("http://pastebin.com/raw.php?i=" .. tostring(code))
  547. end
  548.  
  549.  
  550. --  Redirection
  551.  
  552. api.redirect = function(url)
  553.     if type(url) ~= "string" then url = "home" end
  554.     os.queueEvent(event_redirect, url:gsub("rdnt://"):gsub("http://"))
  555.     error()
  556. end
  557.  
  558.  
  559. --  Theme
  560.  
  561. api.themeColor = function(tag)
  562.     if type(tag) ~= "string" then error("themeColor: expected string") end
  563.     return colors[theme[tag] or defaultTheme[tag] or "white"]
  564. end
  565.  
  566. api.themeColour = function(tag) return api.themeColor(tag) end
  567.  
  568.  
  569. --  Prompt
  570.  
  571. api.prompt = function(list, dir)
  572.     if isAdvanced() then
  573.         for _, v in pairs(list) do
  574.             if v.bg then term.setBackgroundColor(v.bg) end
  575.             if v.tc then term.setTextColor(v.tc) end
  576.             if v[2] == -1 then v[2] = math.ceil((w + 1)/2 - (v[1]:len() + 6)/2) end
  577.  
  578.             term.setCursorPos(v[2], v[3])
  579.             write("[- " .. v[1])
  580.             term.setCursorPos(v[2] + v[1]:len() + 3, v[3])
  581.             write(" -]")
  582.         end
  583.  
  584.         while true do
  585.             local e, but, x, y = os.pullEvent()
  586.             if e == "mouse_click" then
  587.                 for _, v in pairs(list) do
  588.                     if x >= v[2] and x <= v[2] + v[1]:len() + 5 and y + (v.coffset or 0) == v[3] then
  589.                         return v[1]
  590.                     end
  591.                 end
  592.             end
  593.         end
  594.     else
  595.         for _, v in pairs(list) do
  596.             term.setBackgroundColor(colors.black)
  597.             term.setTextColor(colors.white)
  598.             if v[2] == -1 then v[2] = math.ceil((w + 1)/2 - (v[1]:len() + 4)/2) end
  599.  
  600.             term.setCursorPos(v[2], v[3])
  601.             write("  " .. v[1])
  602.             term.setCursorPos(v[2] + v[1]:len() + 2, v[3])
  603.             write("  ")
  604.         end
  605.  
  606.         local key1 = dir == "horizontal" and 203 or 200
  607.         local key2 = dir == "horizontal" and 205 or 208
  608.  
  609.         local curSel = 1
  610.         term.setCursorPos(list[curSel][2], list[curSel][3])
  611.         write("[")
  612.         term.setCursorPos(list[curSel][2] + list[curSel][1]:len() + 3, list[curSel][3])
  613.         write("]")
  614.         while true do
  615.             local e, key = os.pullEvent("key")
  616.             term.setCursorPos(list[curSel][2], list[curSel][3])
  617.             write(" ")
  618.             term.setCursorPos(list[curSel][2] + list[curSel][1]:len() + 3, list[curSel][3])
  619.             write(" ")
  620.             if key == key1 and curSel > 1 then curSel = curSel - 1
  621.             elseif key == key2 and curSel < #list then curSel = curSel + 1
  622.             elseif key == 28 then return list[curSel][1] end
  623.             term.setCursorPos(list[curSel][2], list[curSel][3])
  624.             write("[")
  625.             term.setCursorPos(list[curSel][2] + list[curSel][1]:len() + 3, list[curSel][3])
  626.             write("]")
  627.         end
  628.     end
  629. end
  630.  
  631. api.scrollingPrompt = function(list, x, y, len, width, coffset)
  632.     local wid = width
  633.     if not wid then wid = w - 3 end
  634.  
  635.     local function updateDisplayList(items, loc, len)
  636.         local ret = {}
  637.         for i = 1, len do
  638.             local item = items[i + loc - 1]
  639.             if item then table.insert(ret, item) end
  640.         end
  641.         return ret
  642.     end
  643.  
  644.     if isAdvanced() then
  645.         local function draw(a)
  646.             for i, v in ipairs(a) do
  647.                 term.setCursorPos(x, y + i - 1)
  648.                 write(string.rep(" ", wid))
  649.                 term.setCursorPos(x, y + i - 1)
  650.                 write("[ " .. v:sub(1, wid - 5))
  651.                 term.setCursorPos(wid + x - 2, y + i - 1)
  652.                 write("  ]")
  653.             end
  654.         end
  655.  
  656.         local loc = 1
  657.         local disList = updateDisplayList(list, loc, len)
  658.         draw(disList)
  659.        
  660.         while true do
  661.             local e, but, clx, cly = os.pullEvent()
  662.             if e == "key" and but == 200 and loc > 1 then
  663.                 loc = loc - 1
  664.                 disList = updateDisplayList(list, loc, len)
  665.                 draw(disList)
  666.             elseif e == "key" and but == 208 and loc + len - 1 < #list then
  667.                 loc = loc + 1
  668.                 disList = updateDisplayList(list, loc, len)
  669.                 draw(disList)
  670.             elseif e == "mouse_scroll" and but > 0 and loc + len - 1 < #list then
  671.                 loc = loc + but
  672.                 disList = updateDisplayList(list, loc, len)
  673.                 draw(disList)
  674.             elseif e == "mouse_scroll" and but < 0 and loc > 1 then
  675.                 loc = loc + but
  676.                 disList = updateDisplayList(list, loc, len)
  677.                 draw(disList)
  678.             elseif e == "mouse_click" then
  679.                 for i, v in ipairs(disList) do
  680.                     if clx >= x and clx <= x + wid and cly + coffset == i + y - 1 then return v end
  681.                 end
  682.             end
  683.         end
  684.     else
  685.         local function draw(a)
  686.             for i, v in ipairs(a) do
  687.                 term.setCursorPos(x, y + i - 1)
  688.                 write(string.rep(" ", wid))
  689.                 term.setCursorPos(x, y + i - 1)
  690.                 write("[ ] " .. v:sub(1, wid - 5))
  691.             end
  692.         end
  693.  
  694.         local loc = 1
  695.         local curSel = 1
  696.         local disList = updateDisplayList(list, loc, len)
  697.         draw(disList)
  698.         term.setCursorPos(x + 1, y + curSel - 1)
  699.         write("x")
  700.  
  701.         while true do
  702.             local e, key = os.pullEvent()
  703.             term.setCursorPos(x + 1, y + curSel - 1)
  704.             write(" ")
  705.             if e == "key" and key == 200 then
  706.                 if curSel > 1 then curSel = curSel - 1
  707.                 elseif loc > 1 then
  708.                     loc = loc - 1
  709.                     disList = updateDisplayList(list, loc, len)
  710.                     draw(disList)
  711.                 end
  712.             elseif e == "key" and key == 208 then
  713.                 if curSel < #disList then curSel = curSel + 1
  714.                 elseif loc + len - 1 < #list then
  715.                     loc = loc + 1
  716.                     disList = updateDisplayList(list, loc, len)
  717.                     draw(disList)
  718.                 end
  719.             elseif e == "key" and key == 28 then return list[curSel + loc - 1] end
  720.             term.setCursorPos(x + 1, y + curSel - 1)
  721.             write("x")
  722.         end
  723.     end
  724. end
  725.  
  726. -- Set Environment
  727. for k, v in pairs(getfenv(0)) do env[k] = v end
  728. for k, v in pairs(getfenv(1)) do env[k] = v end
  729. for k, v in pairs(env) do oldEnv[k] = v end
  730. for k, v in pairs(api) do env[k] = v end
  731.  
  732.  
  733. --  -------- Override
  734.  
  735. for k, v in pairs(env) do override[k] = v end
  736. local curtext, curbackground = colors.white, colors.black
  737. override.term = {}
  738. for k, v in pairs(env.term) do override.term[k] = v end
  739. override.os = {}
  740. for k, v in pairs(env.os) do override.os[k] = v end
  741.  
  742. override.term.getSize = function()
  743.     local a, b = env.term.getSize()
  744.     return a, b - 2
  745. end
  746.  
  747. override.term.setCursorPos = function(x, y)
  748.     if y < 1 then return env.term.setCursorPos(x, 2)
  749.     else return env.term.setCursorPos(x, y + 1) end
  750. end
  751.  
  752. override.term.getCursorPos = function()
  753.     local x, y = env.term.getCursorPos()
  754.     return x, y - 1
  755. end
  756.  
  757. override.term.getBackgroundColor = function() return curbackground end
  758. override.term.getBackgroundColour = function() return override.term.getBackgroundColor() end
  759.  
  760. override.term.setBackgroundColor = function(col)
  761.     curbackground = col
  762.     return env.term.setBackgroundColor(col)
  763. end
  764.  
  765. override.term.setBackgroundColour = function(col) return override.term.setBackgroundColor(col) end
  766.  
  767. override.term.getTextColor = function() return curtext end
  768. override.term.getTextColour = function() return override.term.getTextColor() end
  769.  
  770. override.term.setTextColor = function(col)
  771.     curtext = col
  772.     return env.term.setTextColor(col)
  773. end
  774.  
  775. override.term.setTextColour = function(col) return override.term.setTextColor(col) end
  776.  
  777. override.term.clear = function()
  778.     local x, y = term.getCursorPos()
  779.     local oldbackground = override.term.getBackgroundColor()
  780.     local oldtext = override.term.getTextColor()
  781.     clear(website, curbackground)
  782.  
  783.     term.setBackgroundColor(oldbackground)
  784.     term.setTextColor(oldtext)
  785.     term.setCursorPos(x, y)
  786. end
  787.  
  788. override.term.scroll = function(n)
  789.     local x, y = term.getCursorPos()
  790.     local oldbackground = override.term.getBackgroundColor()
  791.     local oldtext = override.term.getTextColor()
  792.  
  793.     env.term.scroll(n)
  794.     clear(website, curbackground, true)
  795.     term.setBackgroundColor(oldbackground)
  796.     term.setTextColor(oldtext)
  797.     term.setCursorPos(x, y)
  798. end
  799.  
  800. override.term.isColor = function() return isAdvanced() end
  801. override.term.isColour = function() return override.term.isColor() end
  802.  
  803. override.os.queueEvent = function(event, ...)
  804.     if event == "terminate" or event == event_exit then return end
  805.     if event == event_error and not websiteerror then return end
  806.     env.os.queueEvent(event, ...)
  807. end
  808.  
  809. override.prompt = function(list, dir)
  810.     local a = {}
  811.     for k, v in pairs(list) do
  812.         table.insert(a, {v[1], v[2], v[3] + 1, tc = v.tc or curtext,
  813.             bg = v.bg or curbackground, coffset = 1})
  814.     end
  815.     return env.prompt(a, dir)
  816. end
  817.  
  818. override.scrollingPrompt = function(list, x, y, len, width)
  819.     return env.scrollingPrompt(list, x, y + 1, len, width, 1)
  820. end
  821.  
  822. local barTerm = {}
  823. for k, v in pairs(override.term) do barTerm[k] = v end
  824. barTerm.clear = override.term.clear
  825. barTerm.scroll = override.term.scroll
  826.  
  827. local safeTerm = {}
  828. for k, v in pairs(term) do safeTerm[k] = v end
  829.  
  830. override.showBar = function()
  831.     offsetclick, clickableAddressBar = true, true
  832.     return os.pullEvent, barTerm
  833. end
  834.  
  835. override.hideBar = function()
  836.     offsetclick, clickableAddressBar = false, false
  837.     return os.pullEvent, safeTerm
  838. end
  839.  
  840. setfenv(api.saveFileToUserComputer, override)
  841.  
  842.  
  843. --  -------- Antivirus
  844.  
  845. local antivirusOverrides = {
  846.     ["Run Files"] = {"shell.run", "os.run"},
  847.     ["Modify System"] = {"shell.setAlias", "shell.clearAlias", "os.setComputerLabel",
  848.         "shell.setDir", "shell.setPath"},
  849.     ["Modify Files"] = {"fs.makeDir", "fs.move", "fs.copy", "fs.delete", "fs.open",
  850.         "io.open", "io.write", "io.read", "io.close"},
  851.     ["Shutdown Computer"] = {"os.shutdown", "os.reboot", "shell.exit"}
  852. }
  853.  
  854. local antivirusDestroy = {
  855.     "rawset", "rawget", "setfenv", "loadfile", "loadstring", "dofile", "getfenv"
  856. }
  857.  
  858. local function triggerAntivirus(offence, onlyCancel)
  859.     local oldback, oldtext = curbackground, curtext
  860.     local ox, oy = term.getCursorPos()
  861.     openAddressBar = false
  862.     term.setBackgroundColor(colors[theme["address-bar-background"]])
  863.     term.setTextColor(colors[theme["address-bar-text"]])
  864.     term.setCursorPos(2, 1)
  865.     term.clearLine()
  866.     write("Request: " .. offence)
  867.     term.setCursorPos(w - 8, 1)
  868.     write("[C]ancel")
  869.     if not onlyCancel then
  870.         term.setCursorPos(w - 16, 1)
  871.         write("[A]llow")
  872.     end
  873.  
  874.     offsetclick = false
  875.     local stat = ""
  876.     while true do
  877.         local e, but, x, y = env.os.pullEvent()
  878.         if e == "mouse_click" and y == 1 then
  879.             if x >= w - 8 and x <= w - 1 then stat = "cancel"
  880.             elseif not onlyCancel and x >= w - 16 and x <= w - 9 then stat = "allow" end
  881.         elseif e == "char" and but == "c" then stat = "cancel"
  882.         elseif e == "char" and not onlyCancel and but == "a" then stat = "allow" end
  883.         if stat ~= "" then break end
  884.     end
  885.     offsetclick = true
  886.  
  887.     clear(website, nil, true)
  888.     term.setTextColor(colors.white)
  889.     term.setBackgroundColor(colors.black)
  890.     term.setCursorPos(ox, oy)
  891.     term.setBackgroundColor(oldback)
  892.     term.setTextColor(oldtext)
  893.     if not onlyCancel and stat == "allow" then
  894.         -- To prevent the menu bar from opening
  895.         os.queueEvent("firewolf_requiredEvent")
  896.         os.pullEvent()
  897.  
  898.         openAddressBar = true
  899.         return true
  900.     elseif stat == "cancel" then
  901.         openAddressBar = true
  902.         redirect("home")
  903.     end
  904. end
  905.  
  906. for k, v in pairs(override) do antivirus[k] = v end
  907.  
  908. antivirus.shell = {}
  909. for k, v in pairs(override.shell) do antivirus.shell[k] = v end
  910. antivirus.os = {}
  911. for k, v in pairs(override.os) do antivirus.os[k] = v end
  912. antivirus.fs = {}
  913. for k, v in pairs(override.fs) do antivirus.fs[k] = v end
  914. antivirus.io = {}
  915. for k, v in pairs(override.io) do antivirus.io[k] = v end
  916.  
  917. for warning, v in pairs(antivirusOverrides) do
  918.     for k, func in pairs(v) do
  919.         if func:find(".", 1, true) then
  920.             -- Functions in another table
  921.             local table = func:sub(1, func:find(".", 1, true) - 1)
  922.             local funcname = func:sub(func:find(".", 1, true) + 1, -1)
  923.  
  924.             antivirus[table][funcname] = function(...)
  925.                 env.setfenv(triggerAntivirus, env)
  926.                 if triggerAntivirus(warning) then
  927.                     return override[table][funcname](...)
  928.                 end
  929.             end
  930.         else
  931.             -- Plain functions
  932.             antivirus[func] = function(...)
  933.                 env.setfenv(triggerAntivirus, env)
  934.                 if triggerAntivirus(warning) then
  935.                     return override[func](...)
  936.                 end
  937.             end
  938.         end
  939.     end
  940. end
  941.  
  942. for k, v in pairs(antivirusDestroy) do
  943.     antivirus[v] = function(...)
  944.         env.setfenv(triggerAntivirus, env)
  945.         triggerAntivirus("Destory your System! D:", true)
  946.         return nil
  947.     end
  948. end
  949.  
  950. antivirus.pcall = function(...)
  951.     local suc, err = env.pcall(...)
  952.     if err:lower():find("terminate") then error("terminate") end
  953.     return suc, err
  954. end
  955.  
  956.  
  957. --  -------- Themes
  958.  
  959. local defaultTheme = {
  960.     ["address-bar-text"] = "white",
  961.     ["address-bar-background"] = "gray",
  962.     ["address-bar-base"] = "lightGray",
  963.     ["top-box"] = "red",
  964.     ["bottom-box"] = "orange",
  965.     ["text-color"] = "white",
  966.     ["background"] = "gray"
  967. } local originalTheme = {
  968.     ["address-bar-text"] = "white",
  969.     ["address-bar-background"] = "black",
  970.     ["address-bar-base"] = "black",
  971.     ["top-box"] = "black",
  972.     ["bottom-box"] = "black",
  973.     ["text-color"] = "white",
  974.     ["background"] = "black"
  975. }
  976.  
  977. local function loadTheme(path)
  978.     if fs.exists(path) and not fs.isDir(path) then
  979.         local a = {}
  980.         local f = io.open(path, "r")
  981.         local l = f:read("*l")
  982.         while l do
  983.             l = l:gsub("^%s*(.-)%s*$", "%1")
  984.             if l and l ~= "" and l ~= "\n" and l:sub(1, 2) ~= "--" then
  985.                 local k, v = string.match(l, "^(%a+)=(%a+)")
  986.                 if k and v then a[k] = v
  987.                 else return nil end
  988.             end
  989.             l = f:read("*l")
  990.         end
  991.         f:close()
  992.         return a
  993.     end
  994.     return nil
  995. end
  996.  
  997.  
  998. --  -------- Filesystem
  999.  
  1000. local function download(url, path)
  1001.     for i = 1, 3 do
  1002.         local response = http.get(url)
  1003.         if response then
  1004.             local data = response.readAll()
  1005.             response.close()
  1006.             if path then
  1007.                 local f = io.open(path, "w")
  1008.                 f:write(data)
  1009.                 f:close()
  1010.             end
  1011.             return true
  1012.         end
  1013.     end
  1014.  
  1015.     return false
  1016. end
  1017.  
  1018. local function updateClient()
  1019.     local skipNormal = false
  1020.     if serverID ~= "experimental" then
  1021.         http.request(buildURL)
  1022.         local a = os.startTimer(10)
  1023.         while true do
  1024.             local e, url, handle = os.pullEvent()
  1025.             if e == "http_success" then
  1026.                 local b = handle.readAll():gsub("^%s*(.-)%s*$", "%1")
  1027.                 if not tonumber(b) or tonumber(b) > build then break
  1028.                 else return false end
  1029.             elseif e == "http_failure" or (e == "timer" and url == a) then
  1030.                 skipNormal = true
  1031.                 break
  1032.             end
  1033.         end
  1034.     end
  1035.  
  1036.     local source = nil
  1037.     if not skipNormal then
  1038.         local _, y = term.getCursorPos()
  1039.         term.setCursorPos(1, y - 2)
  1040.         rightWrite(string.rep(" ", 32))
  1041.         rightWrite("Updating Firewolf... ")
  1042.  
  1043.         http.request(firewolfURL)
  1044.         local a = os.startTimer(10)
  1045.         while true do
  1046.             local e, url, handle = os.pullEvent()
  1047.             if e == "http_success" then
  1048.                 source = handle
  1049.                 break
  1050.             elseif e == "http_failure" or (e == "timer" and url == a) then
  1051.                 break
  1052.             end
  1053.         end
  1054.     end
  1055.  
  1056.     if not source then
  1057.         if isAdvanced() then
  1058.             term.setTextColor(colors[theme["text-color"]])
  1059.             term.setBackgroundColor(colors[theme["background"]])
  1060.             term.clear()
  1061.             if not fs.exists(rootFolder) then fs.makeDir(rootFolder) end
  1062.             local f = io.open(rootFolder .. "/temp_file", "w")
  1063.             f:write(graphics.githubImage)
  1064.             f:close()
  1065.             local a = paintutils.loadImage(rootFolder .. "/temp_file")
  1066.             paintutils.drawImage(a, 5, 5)
  1067.             sleep(0.2)
  1068.             fs.delete(rootFolder .. "/temp_file")
  1069.  
  1070.             term.setCursorPos(19, 4)
  1071.             term.setBackgroundColor(colors[theme["top-box"]])
  1072.             write(string.rep(" ", 32))
  1073.             term.setCursorPos(19, 5)
  1074.             write("  Could Not Connect to GitHub!  ")
  1075.             term.setCursorPos(19, 6)
  1076.             write(string.rep(" ", 32))
  1077.             term.setBackgroundColor(colors[theme["bottom-box"]])
  1078.             term.setCursorPos(19, 8)
  1079.             write(string.rep(" ", 32))
  1080.             term.setCursorPos(19, 9)
  1081.             write("    Sorry, Firewolf could not   ")
  1082.             term.setCursorPos(19, 10)
  1083.             write(" connect to GitHub to download  ")
  1084.             term.setCursorPos(19, 11)
  1085.             write(" necessary files. Please check: ")
  1086.             term.setCursorPos(19, 12)
  1087.             write("    http://status.github.com    ")
  1088.             term.setCursorPos(19, 13)
  1089.             write(string.rep(" ", 32))
  1090.             term.setCursorPos(19, 14)
  1091.             write("        Click to exit...        ")
  1092.             term.setCursorPos(19, 15)
  1093.             write(string.rep(" ", 32))
  1094.         else
  1095.             term.clear()
  1096.             term.setCursorPos(1, 1)
  1097.             term.setBackgroundColor(colors.black)
  1098.             term.setTextColor(colors.white)
  1099.             print("\n")
  1100.             centerPrint("Could not connect to GitHub!")
  1101.             print("")
  1102.             centerPrint("Sorry, Firewolf could not connect to")
  1103.             centerPrint("GitHub to download necessary files.")
  1104.             centerPrint("Please check:")
  1105.             centerPrint("http://status.github.com")
  1106.             print("")
  1107.             centerPrint("Press any key to exit...")
  1108.         end
  1109.  
  1110.         while true do
  1111.             local e = os.pullEvent()
  1112.             if e == "mouse_click" or e == "key" then break end
  1113.         end
  1114.  
  1115.         return false
  1116.     elseif source and autoupdate == "true" then
  1117.         local b = io.open(firewolfLocation, "r")
  1118.         local new = source.readAll()
  1119.         local cur = b:read("*a")
  1120.         source.close()
  1121.         b:close()
  1122.  
  1123.         if cur ~= new then
  1124.             fs.delete(firewolfLocation)
  1125.             local f = io.open(firewolfLocation, "w")
  1126.             f:write(new)
  1127.             f:close()
  1128.             return true
  1129.         else
  1130.             return false
  1131.         end
  1132.     end
  1133. end
  1134.  
  1135. local function resetFilesystem()
  1136.     -- Migrate
  1137.     fs.delete(rootFolder .. "/available_themes")
  1138.     fs.delete(rootFolder .. "/default_theme")
  1139.  
  1140.     -- Reset
  1141.     if not fs.exists(rootFolder) then fs.makeDir(rootFolder)
  1142.     elseif not fs.isDir(rootFolder) then fs.move(rootFolder, "/Firewolf_Data.old") end
  1143.  
  1144.     for _, v in pairs({serverFolder, cacheFolder, websiteDataFolder}) do
  1145.         if not fs.isDir(v) then fs.delete(v) end
  1146.         if not fs.exists(v) then fs.makeDir(v) end
  1147.     end
  1148.  
  1149.     if fs.isDir(settingsLocation) then fs.delete(settingsLocation) end
  1150.     if fs.isDir(serverLocation) then fs.delete(serverLocation) end
  1151.  
  1152.     if not fs.exists(settingsLocation) then
  1153.         local f = io.open(settingsLocation, "w")
  1154.         f:write(textutils.serialize({auto = "true", incog = "false", home = "firewolf"}))
  1155.         f:close()
  1156.     end
  1157.  
  1158.     if not fs.exists(serverLocation) then download(serverURL, serverLocation) end
  1159.     fs.delete(rootFolder .. "/temp_file")
  1160.  
  1161.     for _, v in pairs({userWhitelist, userBlacklist}) do
  1162.         if fs.isDir(v) then fs.delete(v) end
  1163.         if not fs.exists(v) then
  1164.             local f = io.open(v, "w")
  1165.             f:write("")
  1166.             f:close()
  1167.         end
  1168.     end
  1169. end
  1170.  
  1171. local function checkForModem(display)
  1172.     while true do
  1173.         local present = false
  1174.         for _, v in pairs(rs.getSides()) do
  1175.             if peripheral.getType(v) == "modem" then rednet.open(v) present = true break end
  1176.         end
  1177.  
  1178.         if not present and type(display) == "function" then display() os.pullEvent("peripheral")
  1179.         else return true end
  1180.     end
  1181. end
  1182.  
  1183.  
  1184. --  -------- Databases
  1185.  
  1186. local function loadDatabases()
  1187.     if fs.exists(userBlacklist) and not fs.isDir(userBlacklist) then
  1188.         local bf = io.open(userBlacklist, "r")
  1189.         local l = bf:read("*l")
  1190.         while l do
  1191.             if l and l ~= "" and l ~= "\n" then
  1192.                 l = l:gsub("^%s*(.-)%s*$", "%1")
  1193.                 table.insert(blacklist, l)
  1194.             end
  1195.             l = bf:read("*l")
  1196.         end
  1197.         bf:close()
  1198.     end
  1199.  
  1200.     if fs.exists(userWhitelist) and not fs.isDir(userWhitelist) then
  1201.         local wf = io.open(userWhitelist, "r")
  1202.         local l = wf:read("*l")
  1203.         while l do
  1204.             if l and l ~= "" and l ~= "\n" then
  1205.                 l = l:gsub("^%s*(.-)%s*$", "%1")
  1206.                 local a, b = l:find("| |")
  1207.                 table.insert(whitelist, {l:sub(1, a - 1), l:sub(b + 1, -1)})
  1208.             end
  1209.             l = wf:read("*l")
  1210.         end
  1211.         wf:close()
  1212.     end
  1213. end
  1214.  
  1215. local function verifyBlacklist(id)
  1216.     for _, v in pairs(blacklist) do if tostring(id) == v then return true end end
  1217.     return false
  1218. end
  1219.  
  1220. local function verifyWhitelist(id, url)
  1221.     for _, v in pairs(whitelist) do
  1222.         if v[2] == tostring(id) and v[1] == tostring(url) then return true end
  1223.     end
  1224.     return false
  1225. end
  1226.  
  1227.  
  1228. --  -------- Graphics and Files
  1229.  
  1230. graphics.githubImage = [[
  1231. f       f
  1232. fffffffff
  1233. fffffffff
  1234. f4244424f
  1235. f4444444f
  1236. fffffefffe
  1237.    fffe e
  1238.  fffff e
  1239. ff f fe e
  1240.      e   e
  1241. ]]
  1242.  
  1243. graphics.nomodem = function()
  1244.     term.setTextColor(colors[theme["text-color"]])
  1245.     term.setBackgroundColor(colors[theme["background"]])
  1246.     term.clear()
  1247.     term.setCursorPos(1, 1)
  1248.     print("\n")
  1249.     term.setBackgroundColor(colors[theme["top-box"]])
  1250.     api.leftPrint(string.rep(" ", 24))
  1251.     api.leftPrint(" No Modem Attached! D:  ")
  1252.     api.leftPrint(string.rep(" ", 24))
  1253.     print("\n")
  1254.  
  1255.     term.setBackgroundColor(colors[theme["bottom-box"]])
  1256.     api.rightPrint(string.rep(" ", 40))
  1257.     api.rightPrint("    No wireless modem was found on this ")
  1258.     api.rightPrint("  computer, and Firewolf cannot use the ")
  1259.     api.rightPrint("             RDNT protocol without one! ")
  1260.     api.rightPrint(string.rep(" ", 40))
  1261.     api.rightPrint("  Waiting for a modem to be attached... ")
  1262.     api.rightPrint(string.rep(" ", 40))
  1263. end
  1264.  
  1265. graphics.nonexistantwebpage = function()
  1266.     term.setBackgroundColor(colors[theme["background"]])
  1267.     term.clear()
  1268.     term.setCursorPos(1, 2)
  1269.     term.setTextColor(colors[theme["text-color"]])
  1270.     term.setBackgroundColor(colors[theme["top-box"]])
  1271.     leftPrint(string.rep(" ", 11))
  1272.     leftPrint(" Oh Noes!  ")
  1273.     leftPrint(string.rep(" ", 11))
  1274.     print("\n")
  1275.  
  1276.     term.setBackgroundColor(colors[theme["bottom-box"]])
  1277.     rightPrint(string.rep(" ", 43))
  1278.     rightPrint([[       ______                          __  ]])
  1279.     rightPrint([[      / ____/_____ _____ ____   _____ / /  ]])
  1280.     rightPrint([[     / __/  / ___// ___// __ \ / ___// /   ]])
  1281.     rightPrint([[    / /___ / /   / /   / /_/ // /   /_/    ]])
  1282.     rightPrint([[   /_____//_/   /_/    \____//_/   (_)     ]])
  1283.     rightPrint(string.rep(" ", 43))
  1284.     rightPrint("  Could not connect to the website! It may ")
  1285.     rightPrint("  be down, or not exist!                   ")
  1286.     rightPrint(string.rep(" ", 43))
  1287. end
  1288.  
  1289. graphics.nosearchresults = function()
  1290.     term.setBackgroundColor(colors[theme["background"]])
  1291.     term.clear()
  1292.     term.setCursorPos(1, 5)
  1293.     term.setTextColor(colors[theme["text-color"]])
  1294.     term.setBackgroundColor(colors[theme["top-box"]])
  1295.     centerPrint(string.rep(" ", 40))
  1296.     centerPrint("  No Websites are Currently Online! D:  ")
  1297.     centerPrint(string.rep(" ", 40))
  1298.     centerPrint("       Why not make one yourself?       ")
  1299.     centerPrint("          Visit rdnt://server!          ")
  1300.     centerPrint(string.rep(" ", 40))
  1301. end
  1302.  
  1303. files.availableThemes = [[
  1304. https://raw.github.com/1lann/firewolf/master/themes/default.txt| |Fire (default)
  1305. https://raw.github.com/1lann/firewolf/master/themes/ice.txt| |Ice
  1306. https://raw.github.com/1lann/firewolf/master/themes/carbon.txt| |Carbon
  1307. https://raw.github.com/1lann/firewolf/master/themes/christmas.txt| |Christmas
  1308. https://raw.github.com/1lann/firewolf/master/themes/original.txt| |Original
  1309. https://raw.github.com/1lann/firewolf/master/themes/ocean.txt| |Ocean
  1310. https://raw.github.com/1lann/firewolf/master/themes/forest.txt| |Forest
  1311. https://raw.github.com/1lann/firewolf/master/themes/pinky.txt| |Pinky
  1312. https://raw.github.com/1lann/firewolf/master/themes/azhftech.txt| |AzhfTech
  1313. ]]
  1314.  
  1315. files.newTheme = [[
  1316. -- Address bar text color
  1317. address-bar-text=
  1318.  
  1319. -- Address bar background color
  1320. address-bar-background=
  1321.  
  1322. -- Color of separator bar on live search dropdown
  1323. address-bar-base=
  1324.  
  1325. -- Top box background color
  1326. top-box=
  1327.  
  1328. -- Bottom box background color
  1329. bottom-box=
  1330.  
  1331. -- Main background color
  1332. background=
  1333.  
  1334. -- Main text color
  1335. text-color=
  1336.  
  1337. ]]
  1338.  
  1339.  
  1340. --  -------- Protocols
  1341.  
  1342. protocols.rdnt = {}
  1343. protocols.http = {}
  1344.  
  1345. protocols.rdnt.getSearchResults = function()
  1346.     dnsDatabase = {[1] = {}, [2] = {}}
  1347.     local resultIDs = {}
  1348.     local conflict = {}
  1349.  
  1350.     rednet.broadcast("firewolf.broadcast.dns.list")
  1351.     local startClock = os.clock()
  1352.     while os.clock() - startClock < timeout do
  1353.         local id, i = rednet.receive(timeout)
  1354.         if id then
  1355.             if i:sub(1, 14) == "firewolf-site:" then
  1356.                 i = i:sub(15, -1)
  1357.                 local bl, wl = verifyBlacklist(id), verifyWhitelist(id, i)
  1358.                 if not i:find(" ") and i:len() < 40 and (not bl or (bl and wl)) then
  1359.                     if not resultIDs[tostring(id)] then resultIDs[tostring(id)] = 1
  1360.                     else resultIDs[tostring(id)] = resultIDs[tostring(id)] + 1 end
  1361.                    
  1362.                     if not i:find("rdnt://") then i = ("rdnt://" .. i) end
  1363.                     local x = false
  1364.                     if conflict[i] then
  1365.                         x = true
  1366.                         table.insert(conflict[i], id)
  1367.                     else
  1368.                         for m, n in pairs(dnsDatabase[1]) do
  1369.                             if n:lower() == i:lower() then
  1370.                                 x = true
  1371.                                 table.remove(dnsDatabase[1], m)
  1372.                                 table.remove(dnsDatabase[2], m)
  1373.                                 if conflict[i] then table.insert(conflict[i], id)
  1374.                                 else conflict[i] = {} table.insert(conflict[i], id) end
  1375.                                 break
  1376.                             end
  1377.                         end
  1378.                     end
  1379.  
  1380.                     if not x and resultIDs[tostring(id)] <= 3 then
  1381.                         table.insert(dnsDatabase[1], i)
  1382.                         table.insert(dnsDatabase[2], id)
  1383.                     end
  1384.                 end
  1385.             end
  1386.         else break end
  1387.     end
  1388.  
  1389.     for k, v in pairs(conflict) do
  1390.         table.sort(v)
  1391.         table.insert(dnsDatabase[1], k)
  1392.         table.insert(dnsDatabase[2], v[1])
  1393.     end
  1394. end
  1395.  
  1396. protocols.rdnt.getWebsite = function(site)
  1397.     local id, content, status = nil, nil, nil
  1398.     local clock = os.clock()
  1399.     local websiteID = nil
  1400.     for k, v in pairs(dnsDatabase[1]) do
  1401.         local web = site:gsub("rdnt://", "")
  1402.         if web:find("/") then web = web:sub(1, web:find("/") - 1) end
  1403.         if web == v:gsub("rdnt://", "") then websiteID = dnsDatabase[2][k] break end
  1404.     end
  1405.     if not websiteID then return nil, nil, nil end
  1406.  
  1407.     sleep(timeout)
  1408.     rednet.send(websiteID, site)
  1409.     clock = os.clock()
  1410.     while os.clock() - clock < timeout do
  1411.         id, content = rednet.receive(timeout)
  1412.         if id and id == websiteID then
  1413.             local bl, wl = verifyBlacklist(id), verifyWhitelist(id, site)
  1414.             status = nil
  1415.             if (bl and not wl) or site == "" or site == "." or site == ".." then
  1416.                 -- Ignore
  1417.             elseif wl then status = "whitelist" break
  1418.             else status = "safe" break end
  1419.         end
  1420.     end
  1421.  
  1422.     return id, content, status
  1423. end
  1424.  
  1425. protocols.http.getSearchResults = function()
  1426.     dnsDatabase = {[1] = {}, [2] = {}}
  1427. end
  1428.  
  1429. protocols.http.getWebsite = function(site)
  1430.     return nil, nil, nil
  1431. end
  1432.  
  1433.  
  1434. --  -------- Homepage
  1435.  
  1436. pages["firewolf"] = function()
  1437.     term.setBackgroundColor(colors[theme["background"]])
  1438.     term.clear()
  1439.     term.setTextColor(colors[theme["text-color"]])
  1440.     term.setBackgroundColor(colors[theme["top-box"]])
  1441.     print("")
  1442.     leftPrint(string.rep(" ", 42))
  1443.     leftPrint([[        _,-='"-.__               /\_/\    ]])
  1444.     leftPrint([[         -.}        =._,.-==-._.,  @ @._, ]])
  1445.     leftPrint([[            -.__  __,-.   )       _,.-'   ]])
  1446.     leftPrint([[ Firewolf ]] .. version .. string.rep(" ", 8 - version:len()) ..
  1447.         [["    G..m-"^m m'        ]])
  1448.     leftPrint(string.rep(" ", 42))
  1449.     print("\n")
  1450.  
  1451.     term.setBackgroundColor(colors[theme["bottom-box"]])
  1452.     rightPrint(string.rep(" ", 42))
  1453.     if isAdvanced() then rightPrint("  News:                       [- Sites -] ")
  1454.     else rightPrint("  News:                                   ") end
  1455.     rightPrint("     Firewolf 2.5 is out! It rewrites the ")
  1456.     rightPrint("    whole Firewolf's internals (again :P) ")
  1457.     rightPrint(string.rep(" ", 42))
  1458.     rightPrint("   Firewolf 3.0 will be out soon! It will ")
  1459.     rightPrint("     bring the long awaited HTTP support! ")
  1460.     rightPrint(string.rep(" ", 42))
  1461.  
  1462.     while true do
  1463.         local e, but, x, y = os.pullEvent()
  1464.         if e == "mouse_click" and x >= 40 and x <= 50 and y == 11 then redirect("sites") end
  1465.     end
  1466. end
  1467.  
  1468. pages["sites"] = function()
  1469.     term.setBackgroundColor(colors[theme["background"]])
  1470.     term.clear()
  1471.     term.setTextColor(colors[theme["text-color"]])
  1472.     term.setBackgroundColor(colors[theme["top-box"]])
  1473.     print("\n")
  1474.     leftPrint(string.rep(" ", 17))
  1475.     leftPrint(" Built-In Sites  ")
  1476.     leftPrint(string.rep(" ", 17))
  1477.  
  1478.     local sx = 8
  1479.     term.setBackgroundColor(colors[theme["bottom-box"]])
  1480.     term.setCursorPos(1, sx)
  1481.     rightPrint(string.rep(" ", 40))
  1482.     rightPrint("  rdnt://firewolf              Homepage ")
  1483.     rightPrint("  rdnt://sites                    Sites ")
  1484.     rightPrint("  rdnt://server       Server Management ")
  1485.     rightPrint("  rdnt://help                 Help Page ")
  1486.     rightPrint("  rdnt://settings              Settings ")
  1487.     rightPrint("  rdnt://credits                Credits ")
  1488.     rightPrint("  rdnt://exit                      Exit ")
  1489.     rightPrint(string.rep(" ", 40))
  1490.  
  1491.     local a = {"firewolf", "sites", "server", "help", "settings", "credits", "exit"}
  1492.     while true do
  1493.         local e, but, x, y = os.pullEvent()
  1494.         if e == "mouse_click" and x >= 14 and x <= 50 then
  1495.             for i, v in ipairs(a) do if y == sx + i and v ~= "exit" then redirect(v) end end
  1496.         end
  1497.     end
  1498. end
  1499.  
  1500.  
  1501. --  -------- Server Management
  1502.  
  1503. local function manageServers(site, protocol, functionList, startServerName)
  1504.     local servers = functionList["reload servers"]()
  1505.     local sy = 7
  1506.  
  1507.     if not startServerName then startServerName = "Start" end
  1508.     if isAdvanced() then
  1509.         local function draw(l, sel)
  1510.             term.setBackgroundColor(colors[theme["bottom-box"]])
  1511.             term.setCursorPos(4, sy)
  1512.             write("[- New Server -]")
  1513.             for i, v in ipairs(l) do
  1514.                 term.setCursorPos(3, i + sy)
  1515.                 write(string.rep(" ", 24))
  1516.                 term.setCursorPos(4, i + sy)
  1517.                 local nv = v
  1518.                 if nv:len() > 18 then nv = nv:sub(1, 15) .. "..." end
  1519.                 if i == sel then write("[ " .. nv .. " ]")
  1520.                 else write("  " .. nv) end
  1521.             end
  1522.  
  1523.             if #l < 1 then
  1524.                 term.setCursorPos(4, sy + 2)
  1525.                 write("A website is literally")
  1526.                 term.setCursorPos(4, sy + 3)
  1527.                 write("just a lua script!")
  1528.                 term.setCursorPos(4, sy + 4)
  1529.                 write("Go ahead and make one!")
  1530.                 term.setCursorPos(4, sy + 6)
  1531.                 write("Also, be sure to check")
  1532.                 term.setCursorPos(4, sy + 7)
  1533.                 write("out Firewolf's APIs to")
  1534.                 term.setCursorPos(4, sy + 8)
  1535.                 write("help you make your")
  1536.                 term.setCursorPos(4, sy + 9)
  1537.                 write("site, at rdnt://help")
  1538.             end
  1539.  
  1540.             term.setCursorPos(30, sy)
  1541.             write(string.rep(" ", 19))
  1542.             term.setCursorPos(30, sy)
  1543.             if l[sel] then
  1544.                 local nl = l[sel]
  1545.                 if nl:len() > 19 then nl = nl:sub(1, 16) .. "..." end
  1546.                 write(nl)
  1547.             else write("No Server Selected!") end
  1548.             term.setCursorPos(30, sy + 2)
  1549.             write("[- " .. startServerName .. " -]")
  1550.             term.setCursorPos(30, sy + 4)
  1551.             write("[- Edit -]")
  1552.             term.setCursorPos(30, sy + 6)
  1553.             if functionList["run on boot"] then write("[- Run on Boot -]") end
  1554.             term.setCursorPos(30, sy + 8)
  1555.             write("[- Delete -]")
  1556.         end
  1557.  
  1558.         local function updateDisplayList(items, loc, len)
  1559.             local ret = {}
  1560.             for i = 1, len do
  1561.                 if items[i + loc - 1] then table.insert(ret, items[i + loc - 1]) end
  1562.             end
  1563.             return ret
  1564.         end
  1565.  
  1566.         while true do
  1567.             term.setBackgroundColor(colors[theme["background"]])
  1568.             term.clear()
  1569.             term.setCursorPos(1, 1)
  1570.             term.setTextColor(colors[theme["text-color"]])
  1571.             term.setBackgroundColor(colors[theme["top-box"]])
  1572.             print("")
  1573.             leftPrint(string.rep(" ", 27))
  1574.             leftPrint(" Server Management - " .. protocol:upper() .. "  ")
  1575.             leftPrint(string.rep(" ", 27))
  1576.             print("")
  1577.  
  1578.             term.setBackgroundColor(colors[theme["bottom-box"]])
  1579.             for i = 1, 12 do
  1580.                 term.setCursorPos(3, i + sy - 2)
  1581.                 write(string.rep(" ", 24))
  1582.                 term.setCursorPos(29, i + sy - 2)
  1583.                 write(string.rep(" ", 21))
  1584.             end
  1585.  
  1586.             local sel, loc, len = 1, 1, 10
  1587.             local disList = updateDisplayList(servers, loc, len)
  1588.             draw(disList, sel)
  1589.  
  1590.             while true do
  1591.                 local e, but, x, y = os.pullEvent()
  1592.                 if e == "key" and but == 200 and #servers > 0 and loc > 1 then
  1593.                     loc = loc - 1
  1594.                     disList = updateDisplayList(servers, loc, len)
  1595.                     draw(disList, sel)
  1596.                 elseif e == "key" and but == 208 and #servers > 0 and loc + len - 1 < #servers then
  1597.                     loc = loc + 1
  1598.                     disList = updateDisplayList(servers, loc, len)
  1599.                     draw(disList, sel)
  1600.                 elseif e == "mouse_click" then
  1601.                     if x >= 4 and x <= 25 then
  1602.                         if y == 7 then
  1603.                             functionList["new server"]()
  1604.                             servers = functionList["reload servers"]()
  1605.                             break
  1606.                         elseif #servers > 0 then
  1607.                             for i, v in ipairs(disList) do
  1608.                                 if y == i + 7 then
  1609.                                     sel = i
  1610.                                     draw(disList, sel)
  1611.                                 end
  1612.                             end
  1613.                         end
  1614.                     elseif x >= 30 and x <= 40 and y == 9 and #servers > 0 then
  1615.                         functionList["start"](disList[sel])
  1616.                         servers = functionList["reload servers"]()
  1617.                         break
  1618.                     elseif x >= 30 and x <= 39 and y == 11 and #servers > 0 then
  1619.                         functionList["edit"](disList[sel])
  1620.                         servers = functionList["reload servers"]()
  1621.                         break
  1622.                     elseif x >= 30 and x <= 46 and y == 13 and #servers > 0 and
  1623.                             functionList["run on boot"] then
  1624.                         functionList["run on boot"](disList[sel])
  1625.                         term.setBackgroundColor(colors[theme["bottom-box"]])
  1626.                         term.setCursorPos(32, 15)
  1627.                         write("Will Run on Boot!")
  1628.                         openAddressBar = false
  1629.                         sleep(1.3)
  1630.                         openAddressBar = true
  1631.                         term.setCursorPos(32, 15)
  1632.                         write(string.rep(" ", 18))
  1633.                         break
  1634.                     elseif x >= 30 and x <= 41 and y == 15 and #servers > 0 then
  1635.                         functionList["delete"](disList[sel])
  1636.                         servers = functionList["reload servers"]()
  1637.                         break
  1638.                     end
  1639.                 end
  1640.             end
  1641.         end
  1642.     else
  1643.         while true do
  1644.             term.setBackgroundColor(colors[theme["background"]])
  1645.             term.clear()
  1646.             term.setCursorPos(1, 1)
  1647.             term.setTextColor(colors[theme["text-color"]])
  1648.             term.setBackgroundColor(colors[theme["top-box"]])
  1649.             print("")
  1650.             centerPrint(string.rep(" ", 27))
  1651.             centerPrint(" Server Management - " .. protocol:upper() .. "  ")
  1652.             centerPrint(string.rep(" ", 27))
  1653.             print("")
  1654.  
  1655.             local a = {"New Server"}
  1656.             for _, v in pairs(servers) do table.insert(a, v) end
  1657.             local server = scrollingPrompt(a, 4, 7, 10)
  1658.             if server == "New Server" then
  1659.                 functionList["new server"]()
  1660.                 servers = functionList["reload servers"]()
  1661.             else
  1662.                 term.setCursorPos(30, 8)
  1663.                 write(server)
  1664.                 local a = {{"Start", 30, 9}, {"Edit", 30, 11}, {"Run on Boot", 30, 12},
  1665.                     {"Delete", 30, 13}, {"Back", 30, 15}}
  1666.                 if not functionList["run on boot"] then
  1667.                     a = {{"Start", 30, 9}, {"Edit", 30, 11}, {"Delete", 30, 13}, {"Back", 30, 15}}
  1668.                 end
  1669.                 local opt = prompt(a, "vertical")
  1670.                 if opt == "Start" then
  1671.                     functionList["start"](server)
  1672.                     servers = functionList["reload servers"]()
  1673.                 elseif opt == "Edit" then
  1674.                     functionList["edit"](server)
  1675.                     servers = functionList["reload servers"](server)
  1676.                 elseif opt == "Run on Boot" and functionList["run on boot"] then
  1677.                     functionList["run on boot"](server)
  1678.                     term.setCursorPos(32, 16)
  1679.                     write("Will Run on Boot!")
  1680.                     openAddressBar = false
  1681.                     sleep(1.3)
  1682.                     openAddressBar = true
  1683.                 elseif opt == "Delete" then
  1684.                     functionList["delete"](server)
  1685.                     servers = functionList["reload servers"]()
  1686.                 end
  1687.             end
  1688.         end
  1689.     end
  1690. end
  1691.  
  1692. local function editPages(dir)
  1693.     local oldLoc = shell.dir()
  1694.     local commandHis = {}
  1695.     term.setBackgroundColor(colors.black)
  1696.     term.setTextColor(colors.white)
  1697.     term.clear()
  1698.     term.setCursorPos(1, 1)
  1699.     print("")
  1700.     print(" Server Shell Editing")
  1701.     print(" Type 'exit' to return to Firewolf.")
  1702.     print(" The 'home' file is the index of your site.")
  1703.     print("")
  1704.  
  1705.     local allowed = {"move", "mv", "cp", "copy", "drive", "delete", "rm", "edit",
  1706.         "eject", "exit", "help", "id", "monitor", "rename", "alias", "clear",
  1707.         "paint", "lua", "redstone", "rs", "redprobe", "redpulse", "programs",
  1708.         "redset", "reboot", "hello", "label", "list", "ls", "easter", "pastebin", "dir"}
  1709.    
  1710.     while true do
  1711.         shell.setDir(dir)
  1712.         term.setBackgroundColor(colors.black)
  1713.         if isAdvanced() then term.setTextColor(colors.yellow)
  1714.         else term.setTextColor(colors.white) end
  1715.         write("> ")
  1716.         term.setTextColor(colors.white)
  1717.         local line = read(nil, commandHis)
  1718.         table.insert(commandHis, line)
  1719.  
  1720.         local words = {}
  1721.         for m in string.gmatch(line, "[^ \t]+") do
  1722.             local a = m:gsub("^%s*(.-)%s*$", "%1")
  1723.             table.insert(words, a)
  1724.         end
  1725.  
  1726.         local com = words[1]
  1727.         if com == "exit" then break
  1728.         elseif com then
  1729.             local a = false
  1730.             for _, v in pairs(allowed) do if com == v then a = true break end end
  1731.  
  1732.             if a then
  1733.                 term.setBackgroundColor(colors.black)
  1734.                 term.setTextColor(colors.white)
  1735.                 shell.run(com, unpack(words, 2))
  1736.             else
  1737.                 term.setTextColor(colors.red)
  1738.                 print("Program Not Allowed!")
  1739.             end
  1740.         end
  1741.     end
  1742.     shell.setDir(oldLoc)
  1743. end
  1744.  
  1745. local function newServer(onCreate)
  1746.     term.setBackgroundColor(colors[theme["background"]])
  1747.     for i = 1, 12 do
  1748.         term.setCursorPos(3, i + 5)
  1749.         term.clearLine()
  1750.     end
  1751.  
  1752.     term.setBackgroundColor(colors[theme["bottom-box"]])
  1753.     term.setCursorPos(1, 7)
  1754.     for i = 1, 8 do centerPrint(string.rep(" ", 47)) end
  1755.     term.setCursorPos(5, 8)
  1756.     write("Name: ")
  1757.     local name = modRead({refusePrint = "`", visibleLength = w - 4, textLength = 200})
  1758.     term.setCursorPos(5, 10)
  1759.     write("URL:")
  1760.     term.setCursorPos(8, 11)
  1761.     write("rdnt://")
  1762.     local url = modRead({grantPrint = "abcdefghijklmnopqrstuvwxyz1234567890-_.+",
  1763.         visibleLength = w - 4, textLength = 200})
  1764.     url = url:gsub(" ", "")
  1765.     if name == "" or url == "" then
  1766.         term.setCursorPos(5, 13)
  1767.         write("URL or Name is Empty!")
  1768.         openAddressBar = false
  1769.         sleep(1.3)
  1770.         openAddressBar = true
  1771.     else
  1772.         local c = onCreate(name, url)
  1773.  
  1774.         term.setCursorPos(5, 13)
  1775.         if c and c == "true" then write("Successfully Created Server!")
  1776.         elseif c == "false" or not c then write("Server Creation Failed!")
  1777.         else write(c) end
  1778.         openAddressBar = false
  1779.         sleep(1.3)
  1780.         openAddressBar = true
  1781.     end
  1782. end
  1783.  
  1784. pages["server/rdnt"] = function(site)
  1785.     manageServers(site, "rdnt", {["reload servers"] = function()
  1786.         local servers = {}
  1787.         for _, v in pairs(fs.list(serverFolder)) do
  1788.             if fs.isDir(serverFolder .. "/" .. v) then table.insert(servers, v) end
  1789.         end
  1790.         return servers
  1791.     end, ["new server"] = function()
  1792.         newServer(function(name, url)
  1793.             if fs.exists(serverFolder .. "/" .. url) then return "Server Already Exists!" end
  1794.             fs.makeDir(serverFolder .. "/" .. url)
  1795.             local f = io.open(serverFolder .. "/" .. url .. "/home", "w")
  1796.             f:write("print(\"\")\ncenterPrint(\"Welcome To " .. name .. "!\")\n\n")
  1797.             f:close()
  1798.             return "true"
  1799.         end)
  1800.     end, ["start"] = function(server)
  1801.         term.clear()
  1802.         term.setCursorPos(1, 1)
  1803.         term.setBackgroundColor(colors.black)
  1804.         term.setTextColor(colors.white)
  1805.         openAddressBar, offsetclick = false, false
  1806.         setfenv(1, oldEnv)
  1807.         shell.run(serverLocation, server, serverFolder .. "/" .. server)
  1808.         setfenv(1, override)
  1809.         openAddressBar, offsetclick = true, true
  1810.         checkForModem()
  1811.     end, ["edit"] = function(server)
  1812.         openAddressBar, offsetclick = false, false
  1813.         editPages(serverFolder .. "/" .. server)
  1814.         openAddressBar, offsetclick = true, true
  1815.         if not fs.exists(serverFolder .. "/" .. server .. "/home") then
  1816.             local f = io.open(serverFolder .. "/" .. server .. "/home", "w")
  1817.             f:write("print(\"\")\ncenterPrint(\"Welcome To " .. server .. "!\")\n\n")
  1818.             f:close()
  1819.         end
  1820.     end, ["run on boot"] = function(server)
  1821.         fs.delete("/old-startup")
  1822.         if fs.exists("/startup") then fs.move("/startup", "/old-startup") end
  1823.         local f = io.open("/startup", "w")
  1824.         f:write("shell.run(\"" .. serverLocation .. "\", \"" .. server .. "\", \"" ..
  1825.             serverFolder .. "/" .. server .. "\")")
  1826.         f:close()
  1827.     end, ["delete"] = function(server)
  1828.         fs.delete(serverFolder .. "/" .. server)
  1829.     end})
  1830. end
  1831.  
  1832. pages["server/http"] = function()
  1833.     term.setTextColor(colors[theme["text-color"]])
  1834.     term.setBackgroundColor(colors[theme["background"]])
  1835.     term.clear()
  1836.     print("\n\n")
  1837.     term.setBackgroundColor(colors[theme["top-box"]])
  1838.     centerPrint(string.rep(" ", 17))
  1839.     centerPrint("  Comming Soon!  ")
  1840.     centerPrint(string.rep(" ", 17))
  1841. end
  1842.  
  1843. pages["server"] = function()
  1844.     setfenv(manageServers, override)
  1845.     setfenv(newServer, override)
  1846.     setfenv(editPages, env)
  1847.     if curProtocol == protocols.rdnt then redirect("server/rdnt")
  1848.     elseif curProtocol == protocols.http then redirect("server/http") end
  1849. end
  1850.  
  1851.  
  1852. --  -------- Help
  1853.  
  1854. pages["help"] = function()
  1855.     term.setBackgroundColor(colors[theme["background"]])
  1856.     term.clear()
  1857.     term.setTextColor(colors[theme["text-color"]])
  1858.     term.setBackgroundColor(colors[theme["top-box"]])
  1859.     print("")
  1860.     leftPrint(string.rep(" ", 16))
  1861.     leftPrint(" Firewolf Help  ")
  1862.     leftPrint(string.rep(" ", 16))
  1863.     print("\n")
  1864.  
  1865.     term.setBackgroundColor(colors[theme["bottom-box"]])
  1866.     for i = 1, 11 do rightPrint(string.rep(" ", 41)) end
  1867.     term.setCursorPos(1, 15)
  1868.     rightPrint("         View the full documentation at: ")
  1869.     rightPrint("  https://github.com/1lann/Firewolf/wiki ")
  1870.  
  1871.     local opt = prompt({{"Getting Started", w - 21, 8}, {"Making a Theme", w - 20, 10},
  1872.         {"API Documentation", w - 23, 12}}, "vertical")
  1873.     local pages = {}
  1874.     if opt == "Getting Started" then
  1875.         pages[1] = {title = "Getting Started - Intoduction", content = {
  1876.             "Hey there!",
  1877.             "",
  1878.             "Firewolf is an app that allows you to create",
  1879.             "and visit websites! Each site has an address",
  1880.             "(the URL) which you can type into the address",
  1881.             "bar above, and then visit the site.",
  1882.             "",
  1883.             "You can open the address bar by clicking on",
  1884.             "it, or by pressing control."
  1885.         }} pages[2] = {title = "Getting Started - Searching", content = {
  1886.             "The address bar can be also be used to",
  1887.             "search for sites, by simply typing in the",
  1888.             "search term.",
  1889.             "",
  1890.             "To view all sites, just open it and hit",
  1891.             "enter (leave the field blank)."
  1892.         }} pages[3] = {title = "Getting Started - Built-In Websites", content = {
  1893.             "Firewolf has a set of built-in websites",
  1894.             "available for use:",
  1895.             "",
  1896.             "rdnt://firewolf   Normal hompage",
  1897.             "rdnt://sites      Built-In Site",
  1898.             "rdnt://server     Create websites",
  1899.             "rdnt://help       Help and documentation"
  1900.         }} pages[4] = {title = "Getting Started - Built-In Websites", content = {
  1901.             "More built-in websites:",
  1902.             "",
  1903.             "rdnt://settings   Firewolf settings",
  1904.             "rdnt://credits    View the credits",
  1905.             "rdnt://exit       Exit the app"
  1906.         }}
  1907.     elseif opt == "Making a Theme" then
  1908.         pages[1] = {title = "Making a Theme - Introduction", content = {
  1909.             "Firewolf themes are files that tell Firewolf",
  1910.             "to color which things what.",
  1911.             "Several themes can already be downloaded for",
  1912.             "Firewolf from rdnt://settings/themes.",
  1913.             "",
  1914.             "You can also make your own theme, use it in",
  1915.             "your copy of Firewolf.Your theme can also be",
  1916.             "submitted it to the themes list!"
  1917.         }} pages[2] = {title = "Making a Theme - Example", content = {
  1918.             "A theme file consists of several lines of",
  1919.             "text. Here is the default theme file:",
  1920.             "address-bar-text=white",
  1921.             "address-bar-background=gray",
  1922.             "address-bar-base=lightGray",
  1923.             "top-box=red",
  1924.             "bottom-box=orange",
  1925.             "background=gray",
  1926.             "text-color=white"
  1927.         }} pages[3] = {title = "Making a Theme - Explanation", content = {
  1928.             "On each line of the example, something is",
  1929.             "given a color, like on the last line, the",
  1930.             "text of the page is told to be white.",
  1931.             "",
  1932.             "The color specified after the = is the same",
  1933.             "as when you call colors.[color name].",
  1934.             "For example, specifying 'red' after the =",
  1935.             "colors that object red."
  1936.         }} pages[4] = {title = "Making a Theme - Have a Go", content = {
  1937.             "Themes can be made at rdnt://settings/themes,",
  1938.             "click on 'Change Theme' button, and click on",
  1939.             "'New Theme'.",
  1940.             "",
  1941.             "Enter a theme name, then exit Firewolf and",
  1942.             "edit the newly created file",
  1943.             "Specify the colors for each of the keys,",
  1944.             "and return to the themes section of the",
  1945.             "downloads center. Click 'Load Theme'."
  1946.         }} pages[5] = {title = "Making a Theme - Submitting", content = {
  1947.             "To submit a theme to the theme list,",
  1948.             "send GravityScore a message on the CCForums",
  1949.             "that contains your theme file and name.",
  1950.             "",
  1951.             "He will message you back saying whether your",
  1952.             "theme has been added, or if anything needs to",
  1953.             "be changed before it is added."
  1954.         }}
  1955.     elseif opt == "API Documentation" then
  1956.         pages[1] = {title = "API Documentation - 1", content = {
  1957.             "The Firewolf API is a bunch of global",
  1958.             "functions that aim to simplify your life when",
  1959.             "designing and coding websites.",
  1960.             "",
  1961.             "For a full documentation on these functions,",
  1962.             "visit the Firewolf Wiki Page here:",
  1963.             "https://github.com/1lann/Firewolf/wiki"
  1964.         }} pages[2] = {title = "API Documentation - 2", content = {
  1965.             "centerPrint(string text)",
  1966.             "cPrint(string text)",
  1967.             "centerWrite(string text)",
  1968.             "cWrite(string text)",
  1969.             "",
  1970.             "leftPrint(string text)",
  1971.             "lPrint(string text)",
  1972.         }} pages[3] = {title = "API Documentation - 3", content = {
  1973.             "leftWrite(string text)",
  1974.             "lWrite(string text)",
  1975.             "",
  1976.             "rightPrint(string text)",
  1977.             "rPrint(string text)",
  1978.             "rightWrite(string text)",
  1979.             "rWrite(string text)"
  1980.         }} pages[4] = {title = "API Documentation - 4", content = {
  1981.             "prompt(table list, string direction)",
  1982.             "scrollingPrompt(table list, integer x,",
  1983.             "   integer y, integer length[,",
  1984.             "   integer width])",
  1985.             "",
  1986.             "urlDownload(string url)",
  1987.             "pastebinDownload(string code)",
  1988.             "redirect(string site)",
  1989.         }} pages[5] = {title = "API Documentation - 5", content = {
  1990.             "loadImageFromServer(string imagePath)",
  1991.             "ioReadFileFromServer(string filePath)",
  1992.             "fileFileFromServer(string filePath)",
  1993.             "saveFileToUserComputer(string content)",
  1994.             "",
  1995.             "writeDataFile(string path, string contents)",
  1996.             "readDataFile(string path)"
  1997.         }} pages[6] = {title = "API Documentation - 6", content = {
  1998.             "themeColor(string tag)",
  1999.             "themeColour(string tag)"
  2000.         }}
  2001.     end
  2002.  
  2003.     local function drawPage(page)
  2004.         term.setBackgroundColor(colors[theme["background"]])
  2005.         term.clear()
  2006.         term.setCursorPos(1, 1)
  2007.         term.setTextColor(colors[theme["text-color"]])
  2008.         term.setBackgroundColor(colors[theme["top-box"]])
  2009.         print("")
  2010.         leftPrint(string.rep(" ", page.title:len() + 3))
  2011.         leftPrint(" " .. page.title .. "  ")
  2012.         leftPrint(string.rep(" ", page.title:len() + 3))
  2013.         print("")
  2014.  
  2015.         term.setBackgroundColor(colors[theme["bottom-box"]])
  2016.         for i = 1, 12 do print(string.rep(" ", w)) end
  2017.         for i, v in ipairs(page.content) do
  2018.             term.setCursorPos(4, i + 6)
  2019.             write(v)
  2020.         end
  2021.     end
  2022.  
  2023.     local curPage = 1
  2024.     local a = {{"Prev", 26, 17}, {"Next", 38, 17}, {"Back",  14, 17}}
  2025.     drawPage(pages[curPage])
  2026.     while true do
  2027.         local b = {a[3]}
  2028.         if curPage == 1 then table.insert(b, a[2])
  2029.         elseif curPage == #pages then table.insert(b, a[1])
  2030.         else table.insert(b, a[1]) table.insert(b, a[2]) end
  2031.  
  2032.         local opt = prompt(b, "horizontal")
  2033.         if opt == "Prev" then curPage = curPage - 1
  2034.         elseif opt == "Next" then curPage = curPage + 1
  2035.         elseif opt == "Back" then break end
  2036.         drawPage(pages[curPage])
  2037.     end
  2038.  
  2039.     redirect("help")
  2040. end
  2041.  
  2042.  
  2043. --  -------- Settings
  2044.  
  2045. pages["settings/themes"] = function()
  2046.     term.setBackgroundColor(colors[theme["background"]])
  2047.     term.clear()
  2048.     term.setTextColor(colors[theme["text-color"]])
  2049.     term.setBackgroundColor(colors[theme["top-box"]])
  2050.     print("")
  2051.     leftPrint(string.rep(" ", 17))
  2052.     leftPrint(" Theme Settings  ")
  2053.     leftPrint(string.rep(" ", 17))
  2054.     print("")
  2055.  
  2056.     if isAdvanced() then
  2057.         term.setBackgroundColor(colors[theme["bottom-box"]])
  2058.         for i = 1, 12 do rightPrint(string.rep(" ", 36)) end
  2059.  
  2060.         local themes = {}
  2061.         local themenames = {"Back", "New Theme", "Load Theme"}
  2062.         local f = io.open(rootFolder .. "/temp_file", "w")
  2063.         f:write(files.availableThemes)
  2064.         f:close()
  2065.         local f = io.open(rootFolder .. "/temp_file", "r")
  2066.         local l = f:read("*l")
  2067.         while l do
  2068.             l = l:gsub("^%s*(.-)%s*$", "%1")
  2069.             local a, b = l:find("| |")
  2070.             table.insert(themenames, l:sub(b + 1, -1))
  2071.             table.insert(themes, {name = l:sub(b + 1, -1), url = l:sub(1, a - 1)})
  2072.             l = f:read("*l")
  2073.         end
  2074.         f:close()
  2075.         fs.delete(rootFolder .. "/temp_file")
  2076.  
  2077.         local t = scrollingPrompt(themenames, w - 33, 7, 10, 32)
  2078.         if t == "Back" then redirect("settings")
  2079.         elseif t == "New Theme" then
  2080.             term.setCursorPos(w - 33, 17)
  2081.             write("Path: /")
  2082.             local n = modRead({visibleLength = w - 2, textLength = 100})
  2083.             if n ~= "" and n then
  2084.                 n = "/" .. n
  2085.                 local f = io.open(n, "w")
  2086.                 f:write(files.newTheme)
  2087.                 f:close()
  2088.  
  2089.                 term.setCursorPos(1, 17)
  2090.                 rightWrite(string.rep(" ", 36))
  2091.                 term.setCursorPos(1, 17)
  2092.                 rightWrite("File Created! ")
  2093.                 openAddressBar = false
  2094.                 sleep(1.1)
  2095.                 openAddressBar = true
  2096.                 redirect("settings/themes")
  2097.             end
  2098.         elseif t == "Load Theme" then
  2099.             term.setCursorPos(w - 33, 17)
  2100.             write("Path: /")
  2101.             local n = modRead({visibleLength = w - 2, textLength = 100})
  2102.             if n ~= "" and n then
  2103.                 n = "/" .. n
  2104.                 term.setCursorPos(1, 17)
  2105.                 rightWrite(string.rep(" ", 36))
  2106.                
  2107.                 term.setCursorPos(1, 17)
  2108.                 if fs.exists(n) and not fs.isDir(n) then
  2109.                     local a = loadTheme(n)
  2110.                     if a then
  2111.                         fs.delete(themeLocation)
  2112.                         fs.copy(n, themeLocation)
  2113.                         theme = a
  2114.                         rightWrite("Theme File Loaded! :D ")
  2115.                     else rightWrite("Theme File is Corrupt! D: ") end
  2116.                 elseif not fs.exists(n) then rightWrite("File does not exist! ")
  2117.                 elseif fs.isDir(n) then rightWrite("File is a directory! ") end
  2118.  
  2119.                 openAddressBar = false
  2120.                 sleep(1.1)
  2121.                 openAddressBar = true
  2122.                 redirect("settings/themes")
  2123.             end
  2124.         else
  2125.             local url = ""
  2126.             for _, v in pairs(themes) do if v.name == t then url = v.url break end end
  2127.             term.setBackgroundColor(colors[theme["top-box"]])
  2128.             term.setCursorPos(1, 3)
  2129.             leftWrite(string.rep(" ", 17))
  2130.             leftWrite(" Downloading...  ")
  2131.  
  2132.             fs.delete(rootFolder .. "/temp_file")
  2133.             download(url, rootFolder .. "/temp_file")
  2134.             local th = loadTheme(rootFolder .. "/temp_file")
  2135.             if not th then
  2136.                 term.setCursorPos(1, 3)
  2137.                 leftWrite(string.rep(" ", 17))
  2138.                 leftWrite(" Theme Corrupt!  ")
  2139.                 openAddressBar = false
  2140.                 sleep(1.3)
  2141.                 openAddressBar = true
  2142.  
  2143.                 fs.delete(rootFolder .. "/temp_file")
  2144.                 redirect("settings/themes")
  2145.             else
  2146.                 term.setCursorPos(1, 3)
  2147.                 leftWrite(string.rep(" ", 17))
  2148.                 leftWrite(" Theme Loaded!   ")
  2149.                 openAddressBar = false
  2150.                 sleep(1.3)
  2151.                 openAddressBar = true
  2152.  
  2153.                 fs.delete(themeLocation)
  2154.                 fs.move(rootFolder .. "/temp_file", themeLocation)
  2155.                 theme = th
  2156.                 redirect("home")
  2157.             end
  2158.         end
  2159.     else
  2160.         print("")
  2161.         rightPrint(string.rep(" ", 30))
  2162.         rightPrint("  Themes are not available on ")
  2163.         rightPrint("         normal computers! :( ")
  2164.         rightPrint(string.rep(" ", 30))
  2165.     end
  2166. end
  2167.  
  2168. pages["settings"] = function()
  2169.     term.setBackgroundColor(colors[theme["background"]])
  2170.     term.clear()
  2171.     term.setTextColor(colors[theme["text-color"]])
  2172.     term.setBackgroundColor(colors[theme["top-box"]])
  2173.     print("")
  2174.     leftPrint(string.rep(" ", 17 + serverList[serverID]:len()))
  2175.     leftPrint(" Firewolf Settings  " .. string.rep(" ", serverList[serverID]:len() - 3))
  2176.     leftPrint(" Designed For: " .. serverList[serverID] .. "  ")
  2177.     leftPrint(string.rep(" ", 17 + serverList[serverID]:len()))
  2178.     print("\n")
  2179.  
  2180.     local a = "Automatic Updating - On"
  2181.     if autoupdate == "false" then a = "Automatic Updating - Off" end
  2182.     local b = "Home - rdnt://" .. homepage
  2183.     if b:len() >= 28 then b = b:sub(1, 24) .. "..." end
  2184.  
  2185.     term.setBackgroundColor(colors[theme["bottom-box"]])
  2186.     for i = 1, 9 do rightPrint(string.rep(" ", 36)) end
  2187.     local c = {{a, w - a:len() - 6, 9}, {"Change Theme", w - 18, 11}, {b, w - b:len() - 6, 13},
  2188.         {"Reset Firewolf", w - 20, 15}}
  2189.     if not isAdvanced() then
  2190.         c = {{a, w - a:len(), 9}, {b, w - b:len(), 11}, {"Reset Firewolf", w - 14, 13}}
  2191.     end
  2192.  
  2193.     local opt = prompt(c, "vertical")
  2194.     if opt == a then
  2195.         if autoupdate == "true" then autoupdate = "false"
  2196.         elseif autoupdate == "false" then autoupdate = "true" end
  2197.     elseif opt == "Change Theme" and isAdvanced() then
  2198.         redirect("settings/themes")
  2199.     elseif opt == b then
  2200.         if isAdvanced() then term.setCursorPos(w - 30, 14)
  2201.         else term.setCursorPos(w - 30, 12) end
  2202.         write("rdnt://")
  2203.         local a = read()
  2204.         if a ~= "" then homepage = a end
  2205.     elseif opt == "Reset Firewolf" then
  2206.         term.setBackgroundColor(colors[theme["background"]])
  2207.         term.clear()
  2208.         term.setCursorPos(1, 1)
  2209.         term.setTextColor(colors[theme["text-color"]])
  2210.         term.setBackgroundColor(colors[theme["top-box"]])
  2211.         print("")
  2212.         leftPrint(string.rep(" ", 17))
  2213.         leftPrint(" Reset Firewolf  ")
  2214.         leftPrint(string.rep(" ", 17))
  2215.         print("\n")
  2216.         term.setBackgroundColor(colors[theme["bottom-box"]])
  2217.         for i = 1, 11 do rightPrint(string.rep(" ", 26)) end
  2218.         local opt = prompt({{"Reset History", w - 19, 8}, {"Reset Servers", w - 19, 9},
  2219.             {"Reset Theme", w - 17, 10}, {"Reset Cache", w - 17, 11},
  2220.             {"Reset Databases", w - 21, 12},
  2221.             {"Reset Settings", w - 20, 13}, {"Back", w - 10, 14}, {"Reset All", w - 15, 16}},
  2222.             "vertical")
  2223.  
  2224.         openAddressBar = false
  2225.         if opt == "Reset All" then
  2226.             fs.delete(rootFolder)
  2227.         elseif opt == "Reset History" then
  2228.             fs.delete(historyLocation)
  2229.         elseif opt == "Reset Servers" then
  2230.             fs.delete(serverFolder)
  2231.             fs.delete(serverLocation)
  2232.         elseif opt == "Reset Cache" then
  2233.             fs.delete(cacheFolder)
  2234.         elseif opt == "Reset Databases" then
  2235.             fs.delete(userWhitelist)
  2236.             fs.delete(userBlacklist)
  2237.         elseif opt == "Reset Settings" then
  2238.             fs.delete(settingsLocation)
  2239.         elseif opt == "Reset Theme" then
  2240.             fs.delete(themeLocation)
  2241.         elseif opt == "Back" then
  2242.             openAddressBar = true
  2243.             redirect("settings")
  2244.         end
  2245.  
  2246.         term.setBackgroundColor(colors[theme["background"]])
  2247.         term.clear()
  2248.         term.setCursorPos(1, 1)
  2249.         term.setBackgroundColor(colors[theme["top-box"]])
  2250.         print("\n\n")
  2251.         leftPrint(string.rep(" ", 17))
  2252.         leftPrint(" Reset Firewolf  ")
  2253.         leftPrint(string.rep(" ", 17))
  2254.         print("")
  2255.  
  2256.         term.setCursorPos(1, 10)
  2257.         term.setBackgroundColor(colors[theme["bottom-box"]])
  2258.         rightPrint(string.rep(" ", 27))
  2259.         rightPrint("  Firewolf has been reset! ")
  2260.         rightWrite(string.rep(" ", 27))
  2261.         if isAdvanced() then rightPrint("          Click to exit... ")
  2262.         else rightPrint("  Press any key to exit... ") end
  2263.         rightPrint(string.rep(" ", 27))
  2264.  
  2265.         while true do
  2266.             local e = os.pullEvent()
  2267.             if e == "mouse_click" or e == "key" then return true end
  2268.         end
  2269.     end
  2270.  
  2271.     -- Save
  2272.     local f = io.open(settingsLocation, "w")
  2273.     f:write(textutils.serialize({auto = autoupdate, incog = incognito, home = homepage}))
  2274.     f:close()
  2275.  
  2276.     redirect("settings")
  2277. end
  2278.  
  2279.  
  2280. --  -------- Credits
  2281.  
  2282. pages["credits"] = function()
  2283.     term.setTextColor(colors[theme["text-color"]])
  2284.     term.setBackgroundColor(colors[theme["background"]])
  2285.     term.clear()
  2286.     print("\n")
  2287.     term.setBackgroundColor(colors[theme["top-box"]])
  2288.     leftPrint(string.rep(" ", 19))
  2289.     leftPrint(" Firewolf Credits  ")
  2290.     leftPrint(string.rep(" ", 19))
  2291.     print("\n")
  2292.  
  2293.     term.setBackgroundColor(colors[theme["bottom-box"]])
  2294.     rightPrint(string.rep(" ", 38))
  2295.     rightPrint("  Coded by:              GravityScore ")
  2296.     rightPrint("                            and 1lann ")
  2297.     rightPrint(string.rep(" ", 38))
  2298.     rightPrint("  Based off:     RednetExplorer 2.4.1 ")
  2299.     rightPrint("           Made by ComputerCraftFan11 ")
  2300.     rightPrint(string.rep(" ", 38))
  2301. end
  2302.  
  2303.  
  2304. --  -------- Error Pages
  2305.  
  2306. errorPages["overspeed"] = function()
  2307.     clear("overspeed", colors[theme["background"]])
  2308.     print("")
  2309.     term.setTextColor(colors[theme["text-color"]])
  2310.     term.setBackgroundColor(colors[theme["top-box"]])
  2311.     leftPrint(string.rep(" ", 14))
  2312.     leftPrint(" Warning! D:  ")
  2313.     leftPrint(string.rep(" ", 14))
  2314.     print("")
  2315.  
  2316.     term.setBackgroundColor(colors[theme["bottom-box"]])
  2317.     rightPrint(string.rep(" ", 40))
  2318.     rightPrint("  Website browsing sleep limit reached! ")
  2319.     rightPrint(string.rep(" ", 40))
  2320.     rightPrint("      To prevent Firewolf from spamming ")
  2321.     rightPrint("   rednet, Firewolf has stopped loading ")
  2322.     rightPrint("                              the page. ")
  2323.     for i = 1, 3 do rightPrint(string.rep(" ", 40)) end
  2324.  
  2325.     openAddressBar = false
  2326.     for i = 1, 5 do
  2327.         term.setCursorPos(1, 14)
  2328.         rightWrite(string.rep(" ", 43))
  2329.         if 6 - i == 1 then rightWrite("                Please wait 1 second... ")
  2330.         else rightWrite("                Please wait " .. tostring(6 - i) .. " seconds... ") end
  2331.         sleep(1)
  2332.     end
  2333.     openAddressBar = true
  2334.  
  2335.     term.setCursorPos(1, 14)
  2336.     rightWrite(string.rep(" ", 43))
  2337.     rightWrite("            You may now browse normally ")
  2338. end
  2339.  
  2340. errorPages["crash"] = function(error)
  2341.     clear("crash", colors[theme["background"]])
  2342.     print("")
  2343.     term.setTextColor(colors[theme["text-color"]])
  2344.     term.setBackgroundColor(colors[theme["top-box"]])
  2345.     leftPrint(string.rep(" ", 30))
  2346.     leftPrint(" The Website Has Crashed! D:  ")
  2347.     leftPrint(string.rep(" ", 30))
  2348.     print("")
  2349.  
  2350.     term.setBackgroundColor(colors[theme["bottom-box"]])
  2351.     rightPrint(string.rep(" ", 31))
  2352.     rightPrint("      The website has crashed! ")
  2353.     rightPrint("  Report this to the operator: ")
  2354.     rightPrint(string.rep(" ", 31))
  2355.     term.setBackgroundColor(colors[theme["background"]])
  2356.     print("")
  2357.     print(" " .. tostring(error))
  2358.     print("")
  2359.  
  2360.     term.setBackgroundColor(colors[theme["bottom-box"]])
  2361.     rightPrint(string.rep(" ", 31))
  2362.     rightPrint("   You may now browse normally ")
  2363.     rightPrint(string.rep(" ", 31))
  2364. end
  2365.  
  2366.  
  2367. --  -------- External
  2368.  
  2369. local function validateexternal(site)
  2370.     -- Modem
  2371.     if not modemPresent() then return "modem" end
  2372.  
  2373.     -- Website
  2374.     local id, content, status = curProtocol.getWebsite(site)
  2375.     if id and status then return "exists", id, content, status end
  2376.  
  2377.     -- Cache
  2378.     local cacheLoc = cacheFolder .. "/" .. site:gsub("/", "$slazh$")
  2379.     if fs.exists(cacheLoc) and not fs.isDir(cacheLoc) then return "cache" end
  2380.  
  2381.     -- Search results
  2382.     local res = {}
  2383.     if site ~= "" then
  2384.         for _, v in pairs(dnsDatabase[1]) do
  2385.             if v:find(site:lower(), 1, true) then table.insert(res, v) end
  2386.         end
  2387.     else for _, v in pairs(dnsDatabase[1]) do table.insert(res, v) end end
  2388.     table.sort(res)
  2389.     table.sort(res, function(a, b)
  2390.         local _, ac = a:gsub("rdnt://", ""):gsub("http://", ""):gsub(site:lower(), "")
  2391.         local _, bc = b:gsub("rdnt://", ""):gsub("http://", ""):gsub(site:lower(), "")
  2392.         return ac > bc
  2393.     end)
  2394.  
  2395.     if #res > 0 then return "search", res
  2396.     elseif site == "" then return "search", res end
  2397.  
  2398.     -- Doesn't exist
  2399.     return "false"
  2400. end
  2401.  
  2402. local function loadexternal(site)
  2403.     local a, res, content, status = validateexternal(site)
  2404.     local func = nil
  2405.  
  2406.     if a == "exists" then
  2407.         local cacheLoc = cacheFolder .. "/" .. site:gsub("/", "$slazh$")
  2408.         local f = io.open(cacheLoc, "w")
  2409.         f:write(content)
  2410.         f:close()
  2411.  
  2412.         local fn, err = loadfile(cacheLoc)
  2413.         if not err then
  2414.             setfenv(fn, antivirus)
  2415.             if status == "whitelist" then setfenv(fn, override) end
  2416.  
  2417.             func = function()
  2418.                 local _, err = pcall(fn)
  2419.                 if err then
  2420.                     websiteerror = err
  2421.                     os.queueEvent(event_error)
  2422.                 end
  2423.             end
  2424.         else
  2425.             func = function()
  2426.                 local errf = errorPages["crash"]
  2427.                 setfenv(errf, override)
  2428.                 pcall(function() errf(err) end)
  2429.             end
  2430.         end
  2431.     elseif a == "modem" then
  2432.         func = function() checkForModem(graphics.nomodem) end
  2433.     elseif a == "search" then
  2434.         if #res > 0 then
  2435.             func = function()
  2436.                 term.setBackgroundColor(colors[theme["background"]])
  2437.                 term.clear()
  2438.                 term.setCursorPos(1, 2)
  2439.                 term.setTextColor(colors[theme["text-color"]])
  2440.                 term.setBackgroundColor(colors[theme["top-box"]])
  2441.                 local t = "1 Search Result"
  2442.                 if #res > 1 then t = #res .. " Search Results" end
  2443.                 leftPrint(string.rep(" ", t:len() + 3))
  2444.                 leftPrint(" " .. t .. "  ")
  2445.                 leftPrint(string.rep(" ", t:len() + 3))
  2446.                 print("")
  2447.  
  2448.                 term.setBackgroundColor(colors[theme["bottom-box"]])
  2449.                 for i = 1, 12 do rightPrint(string.rep(" ", 42)) end
  2450.                 local opt = scrollingPrompt(res, w - 39, 7, 10, 38)
  2451.                 if opt then redirect(opt:gsub("rdnt://", ""):gsub("http://", "")) end
  2452.             end
  2453.         else
  2454.             func = graphics.nosearchresults
  2455.         end
  2456.     elseif a == "false" or a == "cache" then
  2457.         func = graphics.nonexistantwebpage
  2458.     end
  2459.  
  2460.     term.setBackgroundColor(colors.black)
  2461.     term.setTextColor(colors.white)
  2462.     term.clear()
  2463.     term.setCursorPos(1, 1)
  2464.  
  2465.     local a = override
  2466.     a["browserAgent"] = browserAgent
  2467.     setfenv(func, a)
  2468.     curtext, curbackground = colors.white, colors.black
  2469.     tabs[currentTab] = coroutine.create(func)
  2470. end
  2471.  
  2472.  
  2473. --  -------- Website
  2474.  
  2475. local function loadinternal(site)
  2476.     if pages[site] then
  2477.         local func = pages[site]
  2478.         setfenv(func, override)
  2479.         tabs[currentTab] = coroutine.create(function()
  2480.             local _, err = pcall(function() func() end)
  2481.             if err then
  2482.                 websiteerror = err
  2483.                 os.queueEvent(event_error)
  2484.             end
  2485.         end)
  2486.  
  2487.         return true
  2488.     else return false end
  2489. end
  2490.  
  2491. local function loadsite(site)
  2492.     w, h = term.getSize()
  2493.     clear(site)
  2494.     term.setBackgroundColor(colors.black)
  2495.     term.setTextColor(colors.white)
  2496.     fs.delete(websiteDataFolder)
  2497.     fs.makeDir(websiteDataFolder)
  2498.  
  2499.     if site ~= "exit" and site ~= addressBarHistory[#addressBarHistory] then
  2500.         table.insert(addressBarHistory, site)
  2501.     end
  2502.  
  2503.     checkForModem()
  2504.     if os.clock() - loadingClock > 5 then loadingRate, loadingClock = 0, os.clock() end
  2505.     if loadingRate >= 8 then
  2506.         local overspeedFunc = errorPages["overspeed"]
  2507.         setfenv(overspeedFunc, override)
  2508.         overspeedFunc()
  2509.         loadingRate, loadingClock = 0, os.clock()
  2510.     end
  2511.  
  2512.     -- Load
  2513.     os.queueEvent(event_load)
  2514.     website = site
  2515.     setfenv(loadinternal, override)
  2516.     setfenv(loadexternal, override)
  2517.     if not loadinternal(site) then loadexternal(site) end
  2518.     if tabs[currentTab] then _, filters[currentTab] = coroutine.resume(tabs[currentTab]) end
  2519. end
  2520.  
  2521.  
  2522. --  -------- Address Bar
  2523.  
  2524. local function addressbarread()
  2525.     local len, list = 4, {}
  2526.  
  2527.     local function draw(l)
  2528.         local ox, oy = term.getCursorPos()
  2529.         for i = 1, len do
  2530.             term.setTextColor(colors[theme["address-bar-text"]])
  2531.             term.setBackgroundColor(colors[theme["address-bar-background"]])
  2532.             term.setCursorPos(1, i + 1)
  2533.             write(string.rep(" ", w))
  2534.         end
  2535.  
  2536.         term.setBackgroundColor(colors[theme["address-bar-base"] or theme["bottom-box"]])
  2537.         term.setCursorPos(1, len + 2)
  2538.         write(string.rep(" ", w))
  2539.         term.setBackgroundColor(colors[theme["address-bar-background"]])
  2540.         for i, v in ipairs(l) do term.setCursorPos(2, i + 1) write(v) end
  2541.         term.setCursorPos(ox, oy)
  2542.     end
  2543.  
  2544.     local function update(line, event, ...)
  2545.         local params = {...}
  2546.         local y = params[3]
  2547.         if event == "char" or event == "history" or event == "delete" then
  2548.             list = {}
  2549.             for _, v in pairs(dnsDatabase[1]) do
  2550.                 if #list < len and
  2551.                         v:gsub("rdnt://", ""):gsub("http://", ""):find(line:lower(), 1, true) then
  2552.                     table.insert(list, v)
  2553.                 end
  2554.             end
  2555.  
  2556.             table.sort(list)
  2557.             table.sort(list, function(a, b)
  2558.                 local _, ac = a:gsub("rdnt://", ""):gsub("http://", ""):gsub(line:lower(), "")
  2559.                 local _, bc = b:gsub("rdnt://", ""):gsub("http://", ""):gsub(line:lower(), "")
  2560.                 return ac > bc
  2561.             end)
  2562.             draw(list)
  2563.             return false
  2564.         elseif event == "mouse_click" then
  2565.             for i = 1, #list do
  2566.                 if y == i + 1 then return true, list[i]:gsub("rdnt://", ""):gsub("http://", "") end
  2567.             end
  2568.         end
  2569.     end
  2570.  
  2571.     if isAdvanced() and modemPresent() then
  2572.         return modRead({history = addressBarHistory, visibleLength = w - 2, textLength = 300,
  2573.             liveUpdates = update, exitOnKey = "control"})
  2574.     else
  2575.         return modRead({history = addressBarHistory, visibleLength = w - 2, textLength = 300,
  2576.             exitOnKey = "control"})
  2577.     end
  2578. end
  2579.  
  2580.  
  2581. --  -------- Main
  2582.  
  2583. local function searchresults()
  2584.     if modemPresent() then curProtocol.getSearchResults() end
  2585.     local lastCheck = os.clock()
  2586.     while true do
  2587.         local e = os.pullEvent()
  2588.         if e == event_load and modemPresent() and os.clock() - lastCheck > 5 then
  2589.             curProtocol.getSearchResults()
  2590.             lastCheck = os.clock()
  2591.         end
  2592.     end
  2593. end
  2594.  
  2595. local function run()
  2596.     loadingClock = os.clock()
  2597.     loadsite(homepage)
  2598.     while true do
  2599.         local e, but, x, y, p4, p5 = os.pullEvent()
  2600.         if ((e == "mouse_click" and y == 1 and clickableAddressBar) or
  2601.                 (e == "key" and (but == 29 or but == 157))) and openAddressBar then
  2602.             if e == "key" then x = -1 end
  2603.             if not menuBarOpen and x == w then
  2604.                 -- Open menu bar
  2605.                 menuBarOpen = true
  2606.                 term.setBackgroundColor(colors[theme["top-box"]])
  2607.                 term.setTextColor(colors[theme["address-bar-text"]])
  2608.                 term.setCursorPos(1, 1)
  2609.                 write("> [- Exit Firewolf -]                              ")
  2610.             elseif menuBarOpen and (x == 1 or (but == 29 or but == 157)) then
  2611.                 -- Close menu bar
  2612.                 menuBarOpen = false
  2613.                 clear(website, nil, true)
  2614.             elseif menuBarOpen and x > 2 and x < 22 then
  2615.                 return
  2616.             elseif not menuBarOpen then
  2617.                 -- Stop
  2618.                 if tabs[currentTab] then tabs[currentTab] = nil end
  2619.  
  2620.                 -- Clear
  2621.                 term.setBackgroundColor(colors[theme["address-bar-background"]])
  2622.                 term.setTextColor(colors[theme["address-bar-text"]])
  2623.                 term.setCursorPos(2, 1)
  2624.                 term.clearLine()
  2625.                 if curProtocol == protocols.rdnt then write("rdnt://")
  2626.                 elseif curProtocol == protocols.http then write("http://") end
  2627.  
  2628.                 -- Read
  2629.                 local osite = website
  2630.                 local site = addressbarread()
  2631.                 if not site then site = osite
  2632.                 elseif site == "home" or site == "homepage" then site = homepage
  2633.                 elseif site == "exit" then return end
  2634.  
  2635.                 -- Load
  2636.                 loadsite(site)
  2637.             end
  2638.         elseif e == event_error and websiteerror then
  2639.             -- Display
  2640.             if tabs[currentTab] then tabs[currentTab] = nil end
  2641.  
  2642.             local errf = errorPages["crash"]
  2643.             setfenv(errf, override)
  2644.             errf(websiteerror)
  2645.             websiteerror = nil
  2646.         elseif e == event_redirect and openAddressBar then
  2647.             -- Stop
  2648.             if tabs[currentTab] then tabs[currentTab] = nil end
  2649.  
  2650.             -- Load
  2651.             if not but or but == "exit" then but = website
  2652.             elseif but == "home" or but == "homepage" then but = homepage end
  2653.             loadsite(but)
  2654.         elseif tabs[currentTab] then
  2655.             if coroutine.status(tabs[currentTab]) == "suspended" then
  2656.                 if e == "mouse_click" and offsetclick then y = y - 1 end
  2657.                 if (filters[currentTab] or e) == e then
  2658.                     _, filters[currentTab] = coroutine.resume(tabs[currentTab], e, but, x, y,
  2659.                         p4, p5)
  2660.                 end
  2661.             end
  2662.  
  2663.             for i = 1, #tabs do
  2664.                 if tabs[i] and coroutine.status(tabs[i]) == "dead" then
  2665.                     tabs[i] = nil
  2666.                 end
  2667.             end
  2668.         end
  2669.     end
  2670. end
  2671.  
  2672.  
  2673. --  -------- Startup
  2674.  
  2675. local function main()
  2676.     -- Logo
  2677.     term.setBackgroundColor(colors[theme["background"]])
  2678.     term.setTextColor(colors[theme["text-color"]])
  2679.     term.clear()
  2680.     term.setCursorPos(1, 2)
  2681.     term.setBackgroundColor(colors[theme["top-box"]])
  2682.     leftPrint(string.rep(" ", 47))
  2683.     leftPrint([[          ______ ____ ____   ______            ]])
  2684.     leftPrint([[ ------- / ____//  _// __ \ / ____/            ]])
  2685.     leftPrint([[ ------ / /_    / / / /_/ // __/               ]])
  2686.     leftPrint([[ ----- / __/  _/ / / _  _// /___               ]])
  2687.     leftPrint([[ ---- / /    /___//_/ |_|/_____/               ]])
  2688.     leftPrint([[ --- / /       _       __ ____   __     ______ ]])
  2689.     leftPrint([[ -- /_/       | |     / // __ \ / /    / ____/ ]])
  2690.     leftPrint([[              | | /| / // / / // /    / /_     ]])
  2691.     leftPrint([[              | |/ |/ // /_/ // /___ / __/     ]])
  2692.     leftPrint([[              |__/|__/ \____//_____//_/        ]])
  2693.     leftPrint(string.rep(" ", 47))
  2694.     print("\n")
  2695.     term.setBackgroundColor(colors[theme["bottom-box"]])
  2696.  
  2697.     -- Load Settings
  2698.     if fs.exists(settingsLocation) and not fs.isDir(settingsLocation) then
  2699.         local f = io.open(settingsLocation, "r")
  2700.         local a = textutils.unserialize(f:read("*l"))
  2701.         if type(a) == "table" then autoupdate, incognito, homepage = a.auto, a.incog, a.home end
  2702.         f:close()
  2703.     else autoupdate, incognito, homepage = "true", "false", "firewolf" end
  2704.     curProtocol = protocols.rdnt
  2705.  
  2706.     -- Update
  2707.     rightPrint(string.rep(" ", 32))
  2708.     rightPrint("        Checking for Updates... ")
  2709.     rightPrint(string.rep(" ", 32))
  2710.     setfenv(updateClient, env)
  2711.     if not noInternet then
  2712.         if updateClient() then
  2713.             if debugFile then debugFile:close() end
  2714.             shell.run(firewolfLocation)
  2715.             error()
  2716.         end
  2717.     end
  2718.  
  2719.     -- Download Files
  2720.     local x, y = term.getCursorPos()
  2721.     term.setCursorPos(1, y - 2)
  2722.     rightWrite(string.rep(" ", 32))
  2723.     rightWrite("  Downloading Required Files... ")
  2724.     if not noInternet then resetFilesystem() end
  2725.     loadDatabases()
  2726.     checkForModem()
  2727.  
  2728.     -- Run
  2729.     setfenv(run, env)
  2730.     parallel.waitForAny(run, searchresults)
  2731. end
  2732.  
  2733. local function startup()
  2734.     -- HTTP
  2735.     if not http and not noInternet then
  2736.         term.setTextColor(colors[theme["text-color"]])
  2737.         term.setBackgroundColor(colors[theme["background"]])
  2738.         term.clear()
  2739.         term.setCursorPos(1, 2)
  2740.         term.setBackgroundColor(colors[theme["top-box"]])
  2741.         api.leftPrint(string.rep(" ", 24))
  2742.         api.leftPrint(" HTTP API Not Enabled!  ")
  2743.         api.leftPrint(string.rep(" ", 24))
  2744.         print("")
  2745.  
  2746.         term.setBackgroundColor(colors[theme["bottom-box"]])
  2747.         api.rightPrint(string.rep(" ", 36))
  2748.         api.rightPrint("  Firewolf is unable to run without ")
  2749.         api.rightPrint("       the HTTP API Enabled! Please ")
  2750.         api.rightPrint("    enable it in your ComputerCraft ")
  2751.         api.rightPrint("                            Config! ")
  2752.         api.rightPrint(string.rep(" ", 36))
  2753.  
  2754.         if isAdvanced() then api.rightPrint("                   Click to exit... ")
  2755.         else api.rightPrint("           Press any key to exit... ") end
  2756.         api.rightPrint(string.rep(" ", 36))
  2757.  
  2758.         while true do
  2759.             local e, but, x, y = os.pullEvent()
  2760.             if e == "mouse_click" or e == "key" then break end
  2761.         end
  2762.  
  2763.         return false
  2764.     end
  2765.  
  2766.     -- Turtle
  2767.     if turtle then
  2768.         term.clear()
  2769.         term.setCursorPos(1, 2)
  2770.         api.centerPrint("Advanced computer Required!")
  2771.         print("\n")
  2772.         api.centerPrint("  This version of Firewolf requires  ")
  2773.         api.centerPrint("  an Advanced computer to run!       ")
  2774.         print("")
  2775.         api.centerPrint("  Turtles may not be used to run     ")
  2776.         api.centerPrint("  Firewolf! :(                       ")
  2777.         print("")
  2778.         api.centerPrint("Press any key to exit...")
  2779.  
  2780.         os.pullEvent("key")
  2781.         return false
  2782.     end
  2783.  
  2784.     -- Run
  2785.     setfenv(main, env)
  2786.     local _, err = pcall(main)
  2787.     if err and not err:lower():find("terminated") then
  2788.         term.setTextColor(colors[theme["text-color"]])
  2789.         term.setBackgroundColor(colors[theme["background"]])
  2790.         term.clear()
  2791.         term.setCursorPos(1, 2)
  2792.         term.setCursorBlink(false)
  2793.         term.setBackgroundColor(colors[theme["top-box"]])
  2794.         api.leftPrint(string.rep(" ", 27))
  2795.         api.leftPrint(" Firewolf has Crashed! D:  ")
  2796.         api.leftPrint(string.rep(" ", 27))
  2797.         print("")
  2798.         term.setBackgroundColor(colors[theme["background"]])
  2799.         print("")
  2800.         print("  " .. err)
  2801.         print("")
  2802.  
  2803.         term.setBackgroundColor(colors[theme["bottom-box"]])
  2804.         api.rightPrint(string.rep(" ", 41))
  2805.         if autoupdate == "true" then
  2806.             api.rightPrint("    Please report this error to 1lann or ")
  2807.             api.rightPrint("  GravityScore so we are able to fix it! ")
  2808.             api.rightPrint("  If this problem persists, try deleting ")
  2809.             api.rightPrint("                         " .. rootFolder .. " ")
  2810.         else
  2811.             api.rightPrint("        Automatic updating is off! A new ")
  2812.             api.rightPrint("     version may have have been released ")
  2813.             api.rightPrint("                that may fix this error! ")
  2814.             api.rightPrint("        If you didn't turn auto updating ")
  2815.             api.rightPrint("             off, delete " .. rootFolder .. " ")
  2816.         end
  2817.  
  2818.         api.rightPrint(string.rep(" ", 41))
  2819.         if isAdvanced() then api.rightPrint("                        Click to exit... ")
  2820.         else api.rightPrint("                Press any key to exit... ") end
  2821.         api.rightPrint(string.rep(" ", 41))
  2822.  
  2823.         while true do
  2824.             local e, but, x, y = os.pullEvent()
  2825.             if e == "mouse_click" or e == "key" then break end
  2826.         end
  2827.  
  2828.         return false
  2829.     end
  2830. end
  2831.  
  2832. -- Check If Read Only
  2833. if fs.isReadOnly(firewolfLocation) or fs.isReadOnly(rootFolder) then
  2834.     print("Firewolf cannot modify itself or its root folder!")
  2835.     print("")
  2836.     print("This cold be caused by Firewolf being placed in")
  2837.     print("the rom folder, or another program may be")
  2838.     print("preventing the modification of Firewolf.")
  2839.     error()
  2840. end
  2841.  
  2842. -- Theme
  2843. if not isAdvanced() then theme = originalTheme
  2844. else theme = loadTheme(themeLocation) or defaultTheme end
  2845.  
  2846. -- Debug File
  2847. if #tArgs > 0 and tArgs[1] == "debug" then
  2848.     print("Debug Mode Enabled")
  2849.     if fs.exists(debugLogLocation) then debugFile = io.open(debugLogLocation, "a")
  2850.     else debugFile = io.open(debugLogLocation, "w") end
  2851.     debugFile:write("\n-- [" .. textutils.formatTime(os.time()) .. "] New Log --")
  2852.     sleep(1)
  2853. end
  2854.  
  2855. -- Start
  2856. startup()
  2857.  
  2858. -- Exit Message
  2859. term.setBackgroundColor(colors.black)
  2860. term.setTextColor(colors.white)
  2861. term.setCursorBlink(false)
  2862. term.clear()
  2863. term.setCursorPos(1, 1)
  2864. api.centerPrint("Thank You for Using Firewolf " .. version)
  2865. api.centerPrint("Made by 1lann and GravityScore")
  2866.  
  2867. -- Close
  2868. for _, v in pairs(rs.getSides()) do
  2869.     if peripheral.getType(v) == "modem" then rednet.close(v) end
  2870. end
  2871. if debugFile then debugFile:close() end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement