View difference between Paste ID: 52s3FC8u and 4jEFYW3F
SHOW: | | - or go back to the newest paste.
1
-- Passlock v0
2
-- (C) 2012 User 'Advert' at http://www.computercraft.info/forums2/
3
-- X11/mit licence (use/modify at your will, but please, leave credit where due)
4
5
-- Settings.
6
local dConfig = {} -- Marking defaults, so we can revert to them easily.
7
8
do -- Because I like do statements.
9
	dConfig["sUserPassword"]	= "open"
10
	dConfig["sRootPassword"]	= "2good4u"
11
	dConfig["nOpenTime"]		= 3 -- Number of seconds to keep the door open.
12
	dConfig["nUserPassFailLock"]= 3 -- Number of user password fails before lock. (0 = disable, 1 = 1 fail, 2 = 2 fails, etc.) Reset at success (root can still login)
13
	dConfig["nUserPassFailLockDuration"] = 15 -- Number of seconds to lock after nUserPassFailLock password fails
14
	dConfig["bRootForceOpen"] = false -- Door is forced open by Root user.
15
	dConfig["bLockAtStartup"] = true -- This will lock the computer for nUserPassFailLockDuration seconds at startup, to prevent bypassing of nUserLockPassFailLock.
16
	dConfig["sRedstoneSide"] = "back" -- The side the redstone is at.
17
	-- Stuff not stored here: door state, etc.
18
end
19
-- small helper function ;_;
20
local function copyTable(o)
21
	-- Will simply copy a table, non-recursively.
22
	local t = {}
23
	for k, v in pairs(o) do t[k] = v end
24
	return t
25
end
26
27
local config = copyTable(dConfig)
28
local bRootExit = false
29
local bDoorState = true -- true = locked.
30
local nUserAttempts = 0
31
local nUserLastAttempt = 0
32
-- Misc functions
33
34
local function mergeTable(t1, t2)
35
	-- This function puts everyting in t2 into t1.
36
	for k, v in pairs(t2) do
37
		t1[k] = v
38
	end
39
	return t1 -- We return t1 because that's the table you'll want afterwards (even though it doesn't make a new table)
40
end
41
42
-- Major functions
43
-- Making functions local (I don't like messing up _G)
44
local renderDisplay, checkEvents, loadFromFile, saveToFile
45
local checkDoorTimer, checkUserLockTimer
46
-- Core loop components
47
function renderDisplay()
48
	-- Frame timer
49
	os.startTimer(0.2) -- 5 fps is good enough, can even do less, but meh.
50-
function checkEvents()
50+
	-- Clean the terminal
51
	term.clear()
52-
	local event, p1, p2 = os.pullEvent()
52+
53
54-
	print("Event: ", event, "\n p1 & p2: ", p1, ",", p2)
54+
55
	--TODO
56
end
57
58
--
59
function checkEvents(event, p1, p2)
60
	-- Used in our loop to check for new OS events.
61
	if event == "char" then
62
		if p1 == "x" then
63
			error("User pressed 'x'. 'x' is a bad key to press.")
64
		elseif p1 == "s" then
65
			saveToFile()
66
			loadFromFile()
67
		end
68
	end
69
70
end
71
72
function checkDoorTimer()
73
	--TODO
74
end
75
76
function checkUserLockTimer()
77
	--TODO
78
end
79
80
-- Door toggler.
81
function toggleDoor(bState)
82
	-- This will toggle the door, or set it's state to bState
83
	if bState ~= nil then
84
		bDoorState = bState
85
	else
86
		bDoorState = not bDoorState -- not negates the state in boolean: true, any data not nil -> false; false, nil -> true
87
	end
88
	return bDoorState -- Good practice to return result, in this case the door's state.
89
end
90
91
92-
		local err, res = pcall(dofile, "passlock-data") -- Yes, I'm doing this the easy and hard way.
92+
93-
		if err then
93+
94
do -- This just to make the code neater, really. (And so I can easily collapse the code in ScITE)
95
96
	function loadFromFile()
97
		if not fs.exists("passlock-data") then return end -- We can't load nothing.
98
		local err, res = pcall(function() return loadfile("passlock-data")() end) -- Yes, I'm doing this the easy and hard way.
99
		if not err then
100
			print("Error loading configuration: \n", res)
101
			print("Enter to continue...")
102-
	local saveAs = {}
102+
103-
	saveAs.boolean = [[config[%q] = %s]]
103+
104-
	saveAs.string = [[config[%q] = %q]]
104+
105-
	saveAs.number = [[config[%q] = %d]]
105+
106
107
	-- Saving helper format strings
108
	local saveHelper = {}
109
	saveHelper.boolean = [[config[%q] = %s]]
110
	saveHelper.string = [[config[%q] = %q]]
111-
		local sData = [[local config = {} -- This file, generated by Passlock. Edit at your own risk.\n]]
111+
	saveHelper.number = [[config[%q] = %d]]
112
113
	-- Saving function
114
	function saveToFile()
115
		-- This is the 'harder' part of the two :(
116
117
		local sData = [[local config = {} -- This file, generated by Passlock. Edit at your own risk.]] .. "\n"
118
119
		for k, v in pairs(config) do
120
			local sDataType = type(v)
121-
				sData = sData .. string.format(sSaveHelper, k, v) .. "\n"
121+
122
			if not sSaveHelper then
123
				-- We have problem, let's just print it, and continue without saving it.
124
				print("Warning: (saveToFile) unknown data type, in key: " .. k)
125
			else
126
				-- No errors, save it.
127
				sData = sData .. string.format(sSaveHelper, k, tostring(v)) .. "\n"
128
			end
129
		end
130
131-
		local hHandle = fs.open("passlock-data", "w")
131+
132
		-- Delete and save.
133
		if fs.exists("passlock-data") then
134
			fs.delete("passlock-data")
135
		end
136
		local hHandle = io.open("passlock-data", "w")
137
		if not hHandle then
138
			-- We're pissed, let's error.
139
			error("Unable to open file handle; call to saveToFile", 2)
140
		end
141
		hHandle:write(sData)
142
		hHandle:close()
143
	end
144
end
145
146
147
-- Looping function
148-
		checkDoorTimer() -- Lock the door if it has been open long enough
148+
149-
		checkUserLockTimer() -- Allow user to login again, if enough time has passed.
149+
150-
		--renderDisplay() -- We need to see something.
150+
151-
		checkEvents() -- Get our user input, or yet another timer event for updating the screen.
151+
152
		end
153
		local event, p1, p2 = os.pullEvent()
154
		print("Event: ", event, "\n p1 & p2: ", p1, ",", p2)
155
		if event == "timer" then
156
			checkDoorTimer() -- Lock the door if it has been open long enough
157
			checkUserLockTimer() -- Allow user to login again, if enough time has passed.
158
			renderDisplay() -- Moved inside checkEvents, to provide a static #FPS (i.e typing will cause an overload of timers)
159
		end
160
		checkEvents(event, p1, p2) -- Get our user input, or yet another timer event for updating the screen.
161
		-- Doesn't seem like much, does it? D:
162
	end
163
end
164
165-
	if err ~= true then
165+
166-
		print("error: ", string.format("%q", res))
166+
-- Startup function, one-time.
167-
		print("enter to continue... (ctrl-t is SUPER EFFECTIVE right now!)")
167+
function startup()
168-
		read()
168+
	loadFromFile() -- Loads config if it exists.
169
end
170
171
-- Loop
172
while true do
173
	local err, res = pcall(doImportantStuff)
174
	if bRootExit then -- Quit if user logged in as Root wishes to.
175
		break
176
	end
177
	if not err then
178
		if res ~= "Terminated" then
179
			print("error: ", string.format("%q", res))
180
			print("enter to continue... (ctrl-t is SUPER EFFECTIVE right now!)")
181
			read()
182
		end
183
	end
184
end