SHOW:
|
|
- or go back to the newest paste.
| 1 | local arg={...}--command line arguments
| |
| 2 | quit = false | |
| 3 | local oldPull = os.pullEvent; | |
| 4 | os.pullEvent = os.pullEventRaw; | |
| 5 | ||
| 6 | function quitProgram() | |
| 7 | local event, param1 = os.pullEvent("char")
| |
| 8 | if param1 == "q" then | |
| 9 | quit = true | |
| 10 | end | |
| 11 | end | |
| 12 | ||
| 13 | term.setBackgroundColor(colours.white) | |
| 14 | term.setTextColor(colours.black) | |
| 15 | term.clear() | |
| 16 | term.setCursorPos(1,1) | |
| 17 | term.setCursorBlink(false) | |
| 18 | version="TMNET Browser 1.2" | |
| 19 | siteName="" | |
| 20 | currentSite="" | |
| 21 | siteID=-1 | |
| 22 | pageName="" | |
| 23 | currentX=1 | |
| 24 | currentY=1 | |
| 25 | menuMode=false | |
| 26 | ddns=true | |
| 27 | ddnsID=-1 | |
| 28 | webType=0--0=no site, 1=normal site, 2=menu | |
| 29 | ------------------------- | |
| 30 | --web related functions-- | |
| 31 | ------------------------- | |
| 32 | ||
| 33 | function whois(name)--returns ID if found, -1 if not on dns, and nil if no dns | |
| 34 | --prevent unnecessary communication | |
| 35 | if name~=currentSite then | |
| 36 | if ddns==true then rednet.send(ddnsID,"@whois "..name) | |
| 37 | else rednet.broadcast("@whois "..name) end
| |
| 38 | _,webID=rednet.receive(1) | |
| 39 | siteID=tonumber(webID)--convert it to a number | |
| 40 | currentSite=name | |
| 41 | end | |
| 42 | return siteID | |
| 43 | end | |
| 44 | function getColour(value) | |
| 45 | --TODO prevent crashing on invalid number | |
| 46 | number=tonumber(value) | |
| 47 | if number==nil then--convert hexadecimal | |
| 48 | if value=="A" then | |
| 49 | number=10 | |
| 50 | elseif value=="B" then | |
| 51 | number=11 | |
| 52 | elseif value=="C" then | |
| 53 | number=12 | |
| 54 | elseif value=="D" then | |
| 55 | number=13 | |
| 56 | elseif value=="E" then | |
| 57 | number=14 | |
| 58 | elseif value=="F" then | |
| 59 | number=15 | |
| 60 | else | |
| 61 | return colours.black | |
| 62 | end | |
| 63 | end | |
| 64 | return bit.blshift(1,number) | |
| 65 | end | |
| 66 | function loadPage(webID,page) | |
| 67 | rednet.send(webID,page or "/home") | |
| 68 | pagetext="" | |
| 69 | for i=1,17 do | |
| 70 | from,text=rednet.receive(0.5) | |
| 71 | if text==nil then break end | |
| 72 | pagetext=pagetext..text.."\n" | |
| 73 | end | |
| 74 | ||
| 75 | --term.write(pagetext)--doesn't support newline apparently | |
| 76 | --print(pagetext) | |
| 77 | line=1 | |
| 78 | term.setCursorPos(2,line) | |
| 79 | colourmode=0--1=^ detected 2=nextchar text 3=nextchar backround | |
| 80 | term.setBackgroundColor(colours.white) | |
| 81 | term.setTextColor(colours.black) | |
| 82 | --my slow and tedious method of rendering the page | |
| 83 | for current=1,string.len(pagetext) do | |
| 84 | letter=string.sub(pagetext,current,current)--TODO surely an easier way? | |
| 85 | if letter==nil then letter=" " end | |
| 86 | if colourmode==0 then --normal | |
| 87 | if letter=="^" then | |
| 88 | colourmode=1 | |
| 89 | elseif letter=="\n" then | |
| 90 | line=line+1--next line | |
| 91 | if line==17 then break end--too much! TODO tweak this value | |
| 92 | term.setCursorPos(2,line) | |
| 93 | term.setBackgroundColor(colours.white) | |
| 94 | term.setTextColor(colours.black)--reset colours for next line | |
| 95 | else | |
| 96 | term.write(letter)--nothing special | |
| 97 | end | |
| 98 | elseif colourmode==1 then --might be a colour | |
| 99 | if letter=="f" then--foreground colour | |
| 100 | colourmode=2--next char will set foreground | |
| 101 | elseif letter=="b" then--background colour | |
| 102 | colourmode=3--next char will set background | |
| 103 | else--not correct, probably not intended as a colour | |
| 104 | term.write("^"..letter)--put ^ back as well
| |
| 105 | end | |
| 106 | elseif colourmode==2 then--set text colour | |
| 107 | --print(letter)--debug | |
| 108 | term.setTextColor(getColour(letter)) | |
| 109 | colourmode=0--back to normal | |
| 110 | elseif colourmode==3 then--set background colour | |
| 111 | term.setBackgroundColor(getColour(letter)) | |
| 112 | colourmode=0--back to normal | |
| 113 | end | |
| 114 | end | |
| 115 | end | |
| 116 | ||
| 117 | ----------------- | |
| 118 | --GUI functions-- | |
| 119 | ----------------- | |
| 120 | function drawError(text) | |
| 121 | term.setBackgroundColor(colours.white) | |
| 122 | term.setTextColor(colours.red) | |
| 123 | term.setCursorPos(2,1) | |
| 124 | term.write("ERROR:")
| |
| 125 | term.setCursorPos(2,2) | |
| 126 | term.write(text) | |
| 127 | webType=0 | |
| 128 | end | |
| 129 | function drawButton(x,y,text,conditionA,conditionB,active) | |
| 130 | term.setCursorPos(x,y) | |
| 131 | if conditionA==conditionB and active then | |
| 132 | term.setBackgroundColor(colours.grey) | |
| 133 | term.write("[")
| |
| 134 | else | |
| 135 | term.setBackgroundColor(colours.lightGrey) | |
| 136 | term.write(" ")
| |
| 137 | end | |
| 138 | ||
| 139 | term.write(text) | |
| 140 | ||
| 141 | if conditionA==conditionB and active then | |
| 142 | term.write("]")
| |
| 143 | else | |
| 144 | --term.write(" ")
| |
| 145 | end | |
| 146 | end | |
| 147 | ||
| 148 | function renderGUI() | |
| 149 | --draw left bar | |
| 150 | term.setTextColor(colours.white) | |
| 151 | term.setBackgroundColor(colours.lightGrey) | |
| 152 | for line=1,18 do | |
| 153 | term.setCursorPos(1,line) | |
| 154 | term.write(" ")
| |
| 155 | end | |
| 156 | --draw right cursor | |
| 157 | if menuMode==false then | |
| 158 | term.setCursorPos(1,currentY) | |
| 159 | term.setBackgroundColor(colours.grey) | |
| 160 | term.write(">")
| |
| 161 | end | |
| 162 | --draw bottom bar | |
| 163 | term.setBackgroundColor(colours.lightGrey) | |
| 164 | term.setCursorPos(1,19) | |
| 165 | for line=1,51 do | |
| 166 | term.write(" ")
| |
| 167 | end | |
| 168 | --term.setCursorPos(1,19) | |
| 169 | --term.write(siteName..pageName) | |
| 170 | --draw menu bar items | |
| 171 | drawButton(42,19,"Refresh",currentX,3,menuMode) | |
| 172 | drawButton(36,19,"Menu",currentX,2,menuMode) | |
| 173 | drawButton(1,19,siteName..pageName,currentX,1,menuMode) | |
| 174 | end | |
| 175 | ||
| 176 | function popup(text)--a nice GUI popup asking for text | |
| 177 | term.setTextColor(colours.white) | |
| 178 | term.setCursorPos(7,5) | |
| 179 | term.setBackgroundColor(colours.blue) | |
| 180 | for y=5,13 do | |
| 181 | term.setCursorPos(7,y) | |
| 182 | for x=7,47 do | |
| 183 | if y==8 then--user input row | |
| 184 | if x==7 or x== 47 then | |
| 185 | term.setBackgroundColor(colours.lightGrey) | |
| 186 | else | |
| 187 | term.setBackgroundColor(colours.grey) | |
| 188 | end | |
| 189 | end | |
| 190 | term.write(" ")
| |
| 191 | end | |
| 192 | term.setBackgroundColor(colours.lightGrey) | |
| 193 | end | |
| 194 | --finished drawing window. add text | |
| 195 | term.setBackgroundColor(colours.blue) | |
| 196 | term.setCursorPos(7,5)--TODO: center text | |
| 197 | term.write(text) | |
| 198 | term.setBackgroundColor(colours.grey) | |
| 199 | term.setCursorPos(8,8) | |
| 200 | return io.read() | |
| 201 | end | |
| 202 | ||
| 203 | function refresh() | |
| 204 | webType=1--website | |
| 205 | term.setTextColor(colours.black) | |
| 206 | term.setBackgroundColor(colours.white) | |
| 207 | ||
| 208 | term.clear() | |
| 209 | term.setCursorPos(1,1) | |
| 210 | ||
| 211 | renderGUI() | |
| 212 | ||
| 213 | webID=whois(siteName) | |
| 214 | if webID==nil or webID==-1 then--find what went wrong | |
| 215 | if webID==nil and ddns==false then drawError("Server Not Found (Spelling?)")
| |
| 216 | elseif webID==nil and ddns==true then drawError("No Response from DDNS")
| |
| 217 | elseif webID==-1 and ddns==true then drawError("Site Not Found on DDNS (Spelling?)")
| |
| 218 | else drawError("Unknown Error, Contact TMNET Support") end
| |
| 219 | ||
| 220 | else loadPage(webID,pageName) end | |
| 221 | ||
| 222 | renderGUI() | |
| 223 | end | |
| 224 | ------------------- | |
| 225 | --other functions-- | |
| 226 | ------------------- | |
| 227 | function getDeviceSide(deviceType) | |
| 228 | -- List of all sides | |
| 229 | local lstSides = {"left","right","top","bottom","front","back"};
| |
| 230 | -- Now loop through all the sides | |
| 231 | for i, side in pairs(lstSides) do | |
| 232 | if (peripheral.isPresent(side)) then | |
| 233 | -- Yup, there is something on this side | |
| 234 | if (peripheral.getType(side) == string.lower(deviceType)) then | |
| 235 | -- Yes, this is the device type we need, so return the side | |
| 236 | return side; | |
| 237 | end | |
| 238 | end | |
| 239 | end | |
| 240 | --nothing found, return nill | |
| 241 | return nil; | |
| 242 | end | |
| 243 | function split(text,splitAt) | |
| 244 | state=false | |
| 245 | outA="" | |
| 246 | outB="" | |
| 247 | for i=1,string.len(text) do | |
| 248 | if string.sub(text,i,i)==splitAt then | |
| 249 | state=true | |
| 250 | end | |
| 251 | if state==false then | |
| 252 | outA=outA..string.sub(text,i,i) | |
| 253 | else | |
| 254 | outB=outB..string.sub(text,i,i) | |
| 255 | end | |
| 256 | end | |
| 257 | return outA,outB | |
| 258 | end | |
| 259 | --like split, but removes extra char | |
| 260 | function split2(text,splitAt) | |
| 261 | outA,outB=split(text,splitAt) | |
| 262 | outB=string.sub(outB,2,-1)--remove first char (= to splitAt) | |
| 263 | return outA,outB | |
| 264 | end | |
| 265 | ||
| 266 | function interpret(text) | |
| 267 | command,args=split2(text,":") | |
| 268 | if command=="glob" then | |
| 269 | siteName,pageName=split2(args,"/") | |
| 270 | pageName="/"..pageName | |
| 271 | refresh() | |
| 272 | end | |
| 273 | if command=="loc" then | |
| 274 | pageName="/"..args | |
| 275 | refresh() | |
| 276 | end | |
| 277 | if command=="ref" then | |
| 278 | refresh() | |
| 279 | end | |
| 280 | if command=="ask" then | |
| 281 | arg1,arg2=split2(args,":")--expected format: ask:cookie:question | |
| 282 | rednet.send(siteID,"ans:"..arg1..":"..popup(arg2)) | |
| 283 | print("please wait...")--TODO place this nicely in the text entry field
| |
| 284 | --note: server should send refresh as soon as it is done | |
| 285 | end | |
| 286 | --TODO add input command | |
| 287 | end | |
| 288 | function enterPage() | |
| 289 | siteName,pageName=split(popup("web address"),"/")
| |
| 290 | if pageName==nil or pageName=="" then | |
| 291 | pageName="/home" | |
| 292 | end | |
| 293 | refresh() | |
| 294 | end | |
| 295 | function renderMenu() | |
| 296 | term.setTextColor(colours.black) | |
| 297 | term.setBackgroundColor(colours.white) | |
| 298 | ||
| 299 | term.clear() | |
| 300 | term.setCursorPos(1,1) | |
| 301 | --add one space before every line due to side bar | |
| 302 | print(" "..version)
| |
| 303 | print(" Designed by Train Master Network Systems, Inc.")
| |
| 304 | print("")
| |
| 305 | if ddnsID~=nil then print(" ID of Dedicated DNS: "..ddnsID) end
| |
| 306 | if siteID~=nil then print(" ID of Current Website: "..siteID) end
| |
| 307 | print(" Using Modem on Side: "..portSide)
| |
| 308 | renderGUI() | |
| 309 | end | |
| 310 | function handleSelect() | |
| 311 | if menuMode==true then | |
| 312 | --edit web adress | |
| 313 | if currentX==1 then | |
| 314 | enterPage() | |
| 315 | end | |
| 316 | if currentX==2 then | |
| 317 | renderMenu() | |
| 318 | end | |
| 319 | --refresh | |
| 320 | if currentX==3 then | |
| 321 | refresh() | |
| 322 | end | |
| 323 | else--clicked on site | |
| 324 | if webType==1 then | |
| 325 | rednet.send(siteID,"exec:"..pageName..":"..currentY) | |
| 326 | end | |
| 327 | --TODO add interactive menu | |
| 328 | end | |
| 329 | end | |
| 330 | ----------------------- | |
| 331 | --program begins here-- | |
| 332 | ----------------------- | |
| 333 | portSide=getDeviceSide("modem")
| |
| 334 | if portSide==nil then | |
| 335 | print("No Modems Found!")
| |
| 336 | end | |
| 337 | rednet.open(portSide) | |
| 338 | rednet.broadcast("@ddns")--search for dedicated dns
| |
| 339 | ddnsID,result=rednet.receive(1) | |
| 340 | if result==nil then | |
| 341 | ddns=false | |
| 342 | print(" Warning: No DDNS Found")
| |
| 343 | end | |
| 344 | renderGUI() | |
| 345 | enterPage() | |
| 346 | renderGUI() | |
| 347 | while true do | |
| 348 | parallel.waitForAny(quitProgram, otherStuff) | |
| 349 | if quit then | |
| 350 | print("Quitting....")
| |
| 351 | break | |
| 352 | end | |
| 353 | event, p1, p2, p3 = os.pullEventRaw() | |
| 354 | if event=="key" or event=="char" then | |
| 355 | --up | |
| 356 | if p1==200 then | |
| 357 | if currentY~=1 then currentY=currentY-1 end | |
| 358 | menuMode=false | |
| 359 | end | |
| 360 | --down | |
| 361 | if p1==208 then | |
| 362 | if currentY~=18 then currentY=currentY+1 end | |
| 363 | menuMode=false | |
| 364 | end | |
| 365 | ||
| 366 | --left | |
| 367 | if p1==203 then | |
| 368 | if currentX~=1 then currentX=currentX-1 end | |
| 369 | menuMode=true | |
| 370 | end | |
| 371 | --right | |
| 372 | if p1==205 then | |
| 373 | if currentX~=3 then currentX=currentX+1 end | |
| 374 | menuMode=true | |
| 375 | end | |
| 376 | --enter or space (select) | |
| 377 | if p1==28 or p1==" " then --removed 57 | |
| 378 | handleSelect() | |
| 379 | end | |
| 380 | renderGUI() | |
| 381 | elseif event=="mouse_click" then | |
| 382 | if p3==19 then | |
| 383 | menuMode=true | |
| 384 | currentX=1--default if below is false | |
| 385 | if p2>36 then currentX=2 end | |
| 386 | if p2>42 then currentX=3 end | |
| 387 | else | |
| 388 | menuMode=false | |
| 389 | currentY=p3 | |
| 390 | - | end |
| 390 | + | |
| 391 | handleSelect() | |
| 392 | renderGUI() | |
| 393 | --only receive messages from current website | |
| 394 | elseif event=="rednet_message" and p1==siteID then | |
| 395 | interpret(p2) | |
| 396 | elseif event=="terminate" then | |
| 397 | term.setBackgroundColor(colours.black) | |
| 398 | term.setTextColor(colours.white) | |
| 399 | term.clear() | |
| 400 | term.setCursorPos(1,1) | |
| 401 | break | |
| 402 | end | |
| 403 | --TODO make an options menu | |
| 404 | --TODO add error handling | |
| 405 | end | |
| 406 | os.pullEvent = oldPull; |