2019-03-03 08:10:32 +00:00
|
|
|
local mainPath = ".sysmail"
|
|
|
|
local yourID = os.getComputerID()
|
|
|
|
local onlyUseWiredModems = false
|
|
|
|
|
|
|
|
local config = {
|
|
|
|
channel = 1024,
|
|
|
|
keyPath = fs.combine(mainPath, "keys"),
|
|
|
|
mailPath = fs.combine(mainPath, "mail"),
|
2019-03-04 21:10:41 +00:00
|
|
|
apiPath = fs.combine(mainPath, "api"),
|
|
|
|
nameFile = fs.combine(mainPath, "names")
|
2019-03-03 08:10:32 +00:00
|
|
|
}
|
|
|
|
|
2019-03-05 03:02:39 +00:00
|
|
|
local alphasort = function(tbl)
|
|
|
|
table.sort(tbl, function(a,b) return string.lower(a) < string.lower(b) end)
|
|
|
|
return tbl
|
|
|
|
end
|
2019-03-03 08:10:32 +00:00
|
|
|
|
|
|
|
local readFile = function(path)
|
2019-03-05 03:02:39 +00:00
|
|
|
if fs.exists(path) then
|
|
|
|
local file = fs.open(path, "r")
|
|
|
|
local contents = file.readAll()
|
|
|
|
file.close()
|
|
|
|
return contents
|
|
|
|
else
|
|
|
|
return nil
|
|
|
|
end
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local writeFile = function(path, contents)
|
|
|
|
if fs.isReadOnly(path) then
|
|
|
|
return false
|
|
|
|
else
|
|
|
|
local file = fs.open(path, "w")
|
|
|
|
file.write(contents)
|
|
|
|
file.close()
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-05 07:09:32 +00:00
|
|
|
local keyList, names = {}, {}
|
|
|
|
|
2019-03-03 08:10:32 +00:00
|
|
|
local makeKey = function(ID, key)
|
|
|
|
return writeFile(fs.combine(config.keyPath, ID), key)
|
|
|
|
end
|
|
|
|
|
|
|
|
local getKey = function(ID)
|
|
|
|
return readFile(fs.combine(config.keyPath, ID))
|
|
|
|
end
|
|
|
|
|
2019-03-05 07:09:32 +00:00
|
|
|
local readNames = function()
|
|
|
|
return textutils.unserialize(readFile(config.nameFile) or "{}") or {}
|
|
|
|
end
|
2019-03-05 03:02:39 +00:00
|
|
|
|
2019-03-05 07:09:32 +00:00
|
|
|
local writeNames = function(_names)
|
|
|
|
return writeFile(config.nameFile, textutils.serialize(_names or names))
|
|
|
|
end
|
|
|
|
|
|
|
|
-- keyList[id] = key
|
|
|
|
-- names[id] = name
|
2019-03-05 03:02:39 +00:00
|
|
|
|
2019-03-03 08:10:32 +00:00
|
|
|
-- get personal key file
|
2019-03-05 07:09:32 +00:00
|
|
|
keyList[yourID] = ""
|
2019-03-03 08:10:32 +00:00
|
|
|
if fs.exists(fs.combine(config.keyPath, tostring(yourID))) then
|
2019-03-05 07:09:32 +00:00
|
|
|
keyList[yourID] = readFile(fs.combine(config.keyPath, tostring(yourID)))
|
2019-03-03 08:10:32 +00:00
|
|
|
else
|
|
|
|
for i = 1, 64 do
|
2019-03-05 07:09:32 +00:00
|
|
|
keyList[yourID] = keyList[yourID] .. string.char(math.random(11, 255))
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
2019-03-05 07:09:32 +00:00
|
|
|
writeFile(fs.combine(config.keyPath, tostring(yourID)), keyList[yourID])
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
|
|
|
|
2019-03-04 21:10:41 +00:00
|
|
|
local getAllKeys = function()
|
|
|
|
local list = fs.list(config.keyPath)
|
|
|
|
local output = {}
|
|
|
|
for i = 1, #list do
|
|
|
|
if tonumber(list[i]) then
|
|
|
|
output[tonumber(list[i])] = getKey(list[i])
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return output
|
|
|
|
end
|
|
|
|
|
2019-03-05 07:09:32 +00:00
|
|
|
names = readNames()
|
|
|
|
keyList = getAllKeys()
|
2019-03-04 21:10:41 +00:00
|
|
|
|
2019-03-03 08:10:32 +00:00
|
|
|
local apiData = {
|
2019-03-05 03:02:39 +00:00
|
|
|
["aeslua"] = {
|
|
|
|
path = "aeslua.lua",
|
|
|
|
url = "https://gist.githubusercontent.com/SquidDev/86925e07cbabd70773e53d781bd8b2fe/raw/aeslua.lua",
|
|
|
|
useLoadAPI = true,
|
2019-03-03 08:10:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for name, data in pairs(apiData) do
|
|
|
|
data.path = fs.combine(config.apiPath, data.path)
|
|
|
|
if not fs.exists(data.path) then
|
|
|
|
local net = http.get(data.url)
|
|
|
|
if net then
|
|
|
|
local file = fs.open(data.path, "w")
|
|
|
|
file.write(net.readAll())
|
|
|
|
file.close()
|
|
|
|
net.close()
|
|
|
|
else
|
|
|
|
error("Could not download " .. name)
|
|
|
|
end
|
|
|
|
end
|
2019-03-05 03:02:39 +00:00
|
|
|
if data.useLoadAPI then
|
|
|
|
local res = os.loadAPI(data.path)
|
|
|
|
--error(res)
|
|
|
|
else
|
|
|
|
_ENV[name] = dofile(data.path)
|
|
|
|
end
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
local function interpretArgs(tInput, tArgs)
|
|
|
|
local output = {}
|
|
|
|
local errors = {}
|
|
|
|
local usedEntries = {}
|
|
|
|
for aName, aType in pairs(tArgs) do
|
|
|
|
output[aName] = false
|
|
|
|
for i = 1, #tInput do
|
|
|
|
if not usedEntries[i] then
|
|
|
|
if tInput[i] == aName and not output[aName] then
|
|
|
|
if aType then
|
|
|
|
usedEntries[i] = true
|
|
|
|
if type(tInput[i+1]) == aType or type(tonumber(tInput[i+1])) == aType then
|
|
|
|
usedEntries[i+1] = true
|
|
|
|
if aType == "number" then
|
|
|
|
output[aName] = tonumber(tInput[i+1])
|
|
|
|
else
|
|
|
|
output[aName] = tInput[i+1]
|
|
|
|
end
|
|
|
|
else
|
|
|
|
output[aName] = nil
|
|
|
|
errors[1] = errors[1] and (errors[1] + 1) or 1
|
|
|
|
errors[aName] = "expected " .. aType .. ", got " .. type(tInput[i+1])
|
|
|
|
end
|
|
|
|
else
|
|
|
|
usedEntries[i] = true
|
|
|
|
output[aName] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for i = 1, #tInput do
|
|
|
|
if not usedEntries[i] then
|
|
|
|
output[#output+1] = tInput[i]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return output, errors
|
|
|
|
end
|
|
|
|
|
|
|
|
local argList = {
|
|
|
|
["--server"] = false
|
|
|
|
}
|
|
|
|
|
|
|
|
local argData, argErrors = interpretArgs({...}, argList)
|
|
|
|
local isServer = argData["--server"]
|
2019-03-05 07:09:32 +00:00
|
|
|
local serverName = argData[1] or "server"
|
2019-03-04 21:10:41 +00:00
|
|
|
|
|
|
|
if ccemux and (not peripheral.find("modem")) then
|
|
|
|
ccemux.attach("top", "wireless_modem")
|
|
|
|
end
|
2019-03-03 08:10:32 +00:00
|
|
|
|
|
|
|
local modem
|
|
|
|
local getModem = function(doNotPickWireless)
|
|
|
|
local output, periphList
|
|
|
|
for try = 1, 40 do
|
|
|
|
periphList = peripheral.getNames()
|
|
|
|
for i = 1, #periphList do
|
|
|
|
if peripheral.getType(periphList[i]) == "modem" then
|
|
|
|
output = peripheral.wrap(periphList[i])
|
|
|
|
if not (doNotPickWireless and output.isWireless()) then
|
|
|
|
output.open(config.channel)
|
|
|
|
return output
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
sleep(0.15)
|
|
|
|
end
|
|
|
|
error("No modems were found after 40 tries. That's as many as four tens. And that's terrible.")
|
|
|
|
end
|
|
|
|
|
|
|
|
-- allowed IDs
|
|
|
|
local userIDs = {}
|
|
|
|
|
|
|
|
-- all data recorded
|
|
|
|
local DATA = {}
|
|
|
|
|
2019-03-04 21:10:41 +00:00
|
|
|
local transmit = function(msg, msgID)
|
2019-03-03 08:10:32 +00:00
|
|
|
modem = getModem(onlyUseWiredModems)
|
|
|
|
modem.transmit(config.channel, config.channel, {
|
|
|
|
msg = msg,
|
2019-03-04 21:10:41 +00:00
|
|
|
encrypted = false,
|
|
|
|
msgID = msgID
|
2019-03-03 08:10:32 +00:00
|
|
|
})
|
|
|
|
end
|
|
|
|
|
2019-03-05 17:38:29 +00:00
|
|
|
local encTransmit = function(msg, msgID, recipient, encID)
|
2019-03-03 08:10:32 +00:00
|
|
|
modem = getModem(onlyUseWiredModems)
|
2019-03-05 17:38:29 +00:00
|
|
|
local key = keyList[encID or recipient]
|
|
|
|
if not key then
|
2019-03-05 03:02:39 +00:00
|
|
|
error("You do not possess the key of the recipient.")
|
2019-03-04 21:10:41 +00:00
|
|
|
else
|
|
|
|
modem.transmit(config.channel, config.channel, {
|
2019-03-05 17:38:29 +00:00
|
|
|
msg = aeslua.encrypt(key, textutils.serialize(msg)),
|
2019-03-04 21:10:41 +00:00
|
|
|
encrypted = true,
|
|
|
|
msgID = msgID,
|
|
|
|
recipient = recipient
|
|
|
|
})
|
|
|
|
end
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
|
|
|
|
2019-03-05 17:38:29 +00:00
|
|
|
local receive = function(msgID, specifyCommand, encID, timer)
|
2019-03-04 21:10:41 +00:00
|
|
|
local evt, msg, tID
|
|
|
|
if timer then
|
|
|
|
tID = os.startTimer(timer)
|
|
|
|
end
|
|
|
|
modem = getModem()
|
2019-03-03 08:10:32 +00:00
|
|
|
while true do
|
|
|
|
evt = {os.pullEvent()}
|
|
|
|
if evt[1] == "modem_message" then
|
2019-03-04 21:10:41 +00:00
|
|
|
if type(evt[5]) == "table" then
|
|
|
|
if evt[5].encrypted then
|
2019-03-05 17:38:29 +00:00
|
|
|
if true then
|
|
|
|
if encID then
|
|
|
|
msg = aeslua.decrypt(keyList[encID], evt[5].msg)
|
|
|
|
else
|
|
|
|
for id, key in pairs(keyList) do
|
|
|
|
if msg then break end
|
|
|
|
if id ~= encID then
|
|
|
|
msg = aeslua.decrypt(key, evt[5].msg)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if msg then
|
|
|
|
msg = textutils.unserialize(msg)
|
|
|
|
end
|
2019-03-05 03:02:39 +00:00
|
|
|
end
|
2019-03-04 21:10:41 +00:00
|
|
|
else
|
|
|
|
msg = evt[5].msg
|
|
|
|
end
|
|
|
|
if (not msgID) or (evt[5].msgID == msgID) then
|
|
|
|
if (not specifyCommand) or (msg.command == specifyCommand) then
|
|
|
|
return msg, evt[5].encrypted, evt[5].msgID
|
|
|
|
end
|
|
|
|
end
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
2019-03-04 21:10:41 +00:00
|
|
|
elseif evt[1] == "timer" and evt[2] == tID then
|
|
|
|
return nil, nil, nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-05 07:09:32 +00:00
|
|
|
local getNameID = function(name)
|
|
|
|
for k,v in pairs(names) do
|
|
|
|
if v == name then
|
|
|
|
return k
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-04 21:10:41 +00:00
|
|
|
local client = {} -- all client-specific commands
|
|
|
|
local server = {} -- all server-specific commands
|
|
|
|
|
|
|
|
---- ----
|
|
|
|
---- CLIENT COMMANDS ----
|
|
|
|
---- ----
|
|
|
|
|
|
|
|
-- if you want a super duper secure network, manually enter the server ID into this
|
2019-03-05 17:38:29 +00:00
|
|
|
client.findServer = function(srv)
|
2019-03-04 21:10:41 +00:00
|
|
|
local msgID = math.random(1, 2^30)
|
2019-03-05 17:38:29 +00:00
|
|
|
srv = type(srv) == "number" and srv or getNameID(srv)
|
|
|
|
assert(tonumber(srv) or (not srv), "invalid server")
|
2019-03-04 21:10:41 +00:00
|
|
|
transmit({
|
|
|
|
id = yourID,
|
|
|
|
command = "find_server"
|
|
|
|
}, msgID)
|
2019-03-05 17:38:29 +00:00
|
|
|
local reply, isEncrypted = receive(msgID, "find_server_respond", srv)
|
2019-03-04 21:10:41 +00:00
|
|
|
if type(reply) == "table" then
|
|
|
|
if reply.server then
|
|
|
|
return reply.server
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-05 03:02:39 +00:00
|
|
|
-- Registers your ID to a name.
|
2019-03-04 21:10:41 +00:00
|
|
|
client.register = function(srv, username)
|
|
|
|
local msgID = math.random(1, 2^30)
|
2019-03-05 17:38:29 +00:00
|
|
|
assert(srv, "register( server, username )")
|
|
|
|
srv = type(srv) == "number" and srv or getNameID(srv)
|
|
|
|
assert(srv, "invalid server")
|
2019-03-04 21:10:41 +00:00
|
|
|
encTransmit({
|
|
|
|
id = yourID,
|
2019-03-05 03:02:39 +00:00
|
|
|
command = "register",
|
2019-03-04 21:10:41 +00:00
|
|
|
name = username
|
2019-03-05 17:38:29 +00:00
|
|
|
}, msgID, srv, yourID)
|
|
|
|
local reply, isEncrypted = receive(msgID, "register_respond", yourID)
|
|
|
|
if reply then
|
|
|
|
return reply.result
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
end
|
2019-03-05 03:02:39 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
-- Gets a list of all registered ID names
|
|
|
|
client.getNames = function(srv)
|
|
|
|
local msgID = math.random(1, 2^30)
|
2019-03-05 17:38:29 +00:00
|
|
|
assert(srv, "getNames( server )")
|
|
|
|
srv = type(srv) == "number" and srv or getNameID(srv)
|
|
|
|
assert(srv, "invalid server")
|
2019-03-05 03:02:39 +00:00
|
|
|
encTransmit({
|
|
|
|
id = yourID,
|
|
|
|
command = "get_names"
|
2019-03-05 17:38:29 +00:00
|
|
|
}, msgID, srv, yourID)
|
|
|
|
local reply, isEncrypted = receive(msgID, "get_names_respond", yourID)
|
2019-03-05 03:02:39 +00:00
|
|
|
if type(reply) == "table" then
|
|
|
|
return reply.names
|
|
|
|
else
|
|
|
|
return nil
|
|
|
|
end
|
2019-03-04 21:10:41 +00:00
|
|
|
end
|
|
|
|
|
2019-03-05 03:02:39 +00:00
|
|
|
-- Sends an email to a recipient ID.
|
2019-03-04 21:10:41 +00:00
|
|
|
client.sendMail = function(srv, recipient, subject, message, attachments)
|
2019-03-05 17:38:29 +00:00
|
|
|
assert(srv, "sendMail( server, recipient, subject, message, attachments )")
|
|
|
|
srv = type(srv) == "number" and srv or getNameID(srv)
|
|
|
|
assert(srv, "invalid server")
|
|
|
|
assert(type(subject) == "string", "invalid subject")
|
|
|
|
assert(type(message) == "string", "invalid message")
|
2019-03-04 21:10:41 +00:00
|
|
|
local msgID = math.random(1, 2^30)
|
2019-03-05 03:02:39 +00:00
|
|
|
if type(recipient) == "string" then
|
2019-03-05 07:09:32 +00:00
|
|
|
recipient = getNameID(recipient)
|
2019-03-05 03:02:39 +00:00
|
|
|
end
|
2019-03-05 17:38:29 +00:00
|
|
|
assert(recipient, "invalid recipient")
|
2019-03-04 21:10:41 +00:00
|
|
|
encTransmit({
|
|
|
|
command = "send_mail",
|
|
|
|
id = yourID,
|
|
|
|
recipient = recipient,
|
|
|
|
subject = subject,
|
|
|
|
message = message,
|
|
|
|
attachments = attachments
|
2019-03-05 17:38:29 +00:00
|
|
|
}, msgID, srv, yourID)
|
|
|
|
local reply, isEncrypted = receive(msgID, "send_mail_respond", yourID)
|
2019-03-05 03:02:39 +00:00
|
|
|
if (isEncrypted and type(reply) == "table") then
|
|
|
|
return reply.result
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
end
|
2019-03-04 21:10:41 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
client.getMail = function(srv)
|
|
|
|
local msgID = math.random(1, 2^30)
|
2019-03-05 17:38:29 +00:00
|
|
|
assert(srv, "getMail( server )")
|
|
|
|
srv = type(srv) == "number" and srv or getNameID(srv)
|
|
|
|
assert(srv, "invalid server")
|
2019-03-04 21:10:41 +00:00
|
|
|
encTransmit({
|
|
|
|
command = "get_mail",
|
|
|
|
id = yourID,
|
2019-03-05 17:38:29 +00:00
|
|
|
}, msgID, srv, yourID)
|
|
|
|
local reply, isEncrypted = receive(msgID, "get_mail_respond", yourID)
|
2019-03-05 03:02:39 +00:00
|
|
|
if (isEncrypted and type(reply) == "table") then
|
|
|
|
return reply.mail
|
|
|
|
else
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
client.deleteMail = function(srv, mail)
|
|
|
|
local msgID = math.random(1, 2^30)
|
2019-03-05 17:38:29 +00:00
|
|
|
assert(srv, "deleteMail( server, mailEntryNumber )")
|
|
|
|
srv = type(srv) == "number" and srv or getNameID(srv)
|
|
|
|
assert(srv, "invalid server")
|
|
|
|
assert(type(mail) == "number", "invalid mail entry")
|
2019-03-05 03:02:39 +00:00
|
|
|
encTransmit({
|
|
|
|
command = "delete_mail",
|
|
|
|
id = yourID,
|
|
|
|
mail = mail,
|
2019-03-05 17:38:29 +00:00
|
|
|
}, msgID, srv, yourID)
|
|
|
|
local reply, isEncrypted = receive(msgID, "delete_mail_respond", yourID)
|
2019-03-05 03:02:39 +00:00
|
|
|
if (isEncrypted and type(reply) == "table") then
|
|
|
|
return reply.result
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
end
|
2019-03-04 21:10:41 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
---- ----
|
|
|
|
---- SERVER COMMANDS ----
|
|
|
|
---- ----
|
|
|
|
|
2019-03-05 07:09:32 +00:00
|
|
|
-- check whether or not a name is valid to be used
|
2019-03-04 21:10:41 +00:00
|
|
|
server.checkValidName = function(name)
|
2019-03-05 07:09:32 +00:00
|
|
|
if type(name) == "string" then
|
|
|
|
if #name >= 3 or #name <= 24 then
|
|
|
|
return true
|
|
|
|
end
|
2019-03-04 21:10:41 +00:00
|
|
|
end
|
2019-03-05 07:09:32 +00:00
|
|
|
return false
|
2019-03-04 21:10:41 +00:00
|
|
|
end
|
|
|
|
|
2019-03-05 07:09:32 +00:00
|
|
|
-- check whether or not an ID is registered
|
2019-03-04 21:10:41 +00:00
|
|
|
server.checkRegister = function(id)
|
|
|
|
-- I make the code this stupid looking in case I add other stipulations
|
2019-03-05 07:09:32 +00:00
|
|
|
if names[id] or getNameID(names[id]) then
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return false
|
2019-03-04 21:10:41 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
server.registerID = function(id, name)
|
2019-03-05 03:02:39 +00:00
|
|
|
local path = fs.combine(config.mailPath, tostring(id))
|
2019-03-05 07:09:32 +00:00
|
|
|
if ((not server.checkRegister(name)) or getNameID(name) == id) then
|
2019-03-03 08:10:32 +00:00
|
|
|
fs.makeDir(path)
|
2019-03-05 07:09:32 +00:00
|
|
|
names[id] = name
|
|
|
|
writeNames()
|
|
|
|
return true, names[id]
|
2019-03-04 21:10:41 +00:00
|
|
|
else
|
|
|
|
return false, "name already exists"
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- records a full email to file
|
2019-03-04 21:10:41 +00:00
|
|
|
server.recordMail = function(sender, _recipient, subject, message, attachments)
|
2019-03-03 08:10:32 +00:00
|
|
|
local time = os.epoch("utc")
|
2019-03-04 21:10:41 +00:00
|
|
|
local recipient
|
|
|
|
|
|
|
|
if _recipient == "*" then
|
|
|
|
recipient = fs.list(config.mailPath)
|
|
|
|
elseif type(_recipient) ~= "table" then
|
|
|
|
recipient = {tostring(_recipient)}
|
|
|
|
end
|
|
|
|
|
|
|
|
local msg = textutils.serialize({
|
2019-03-05 07:09:32 +00:00
|
|
|
sender = sender,
|
2019-03-03 08:10:32 +00:00
|
|
|
time = time,
|
|
|
|
read = false,
|
|
|
|
subject = subject,
|
|
|
|
message = message,
|
2019-03-04 21:10:41 +00:00
|
|
|
attachments = attachments
|
|
|
|
})
|
|
|
|
|
|
|
|
local requiredSpace = #msg + 2
|
|
|
|
if fs.getFreeSpace(config.mailPath) < requiredSpace then
|
|
|
|
return false, "Cannot write mail, not enough space!"
|
|
|
|
end
|
|
|
|
|
|
|
|
local path, file
|
|
|
|
for i = 1, #recipient do
|
|
|
|
server.registerID(recipient[i])
|
|
|
|
path = fs.combine(config.mailPath, recipient[i])
|
|
|
|
file = fs.open(fs.combine(path, tostring(time)), "w")
|
|
|
|
file.write(msg)
|
|
|
|
file.close()
|
|
|
|
end
|
|
|
|
return true
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
|
|
|
|
2019-03-04 21:10:41 +00:00
|
|
|
-- returns every email in an ID's inbox
|
|
|
|
server.getMail = function(id)
|
2019-03-03 08:10:32 +00:00
|
|
|
local output, list = {}, {}
|
2019-03-04 21:10:41 +00:00
|
|
|
local mails = fs.list(fs.combine(config.mailPath, tostring(id)))
|
2019-03-03 08:10:32 +00:00
|
|
|
local file
|
|
|
|
for k,v in pairs(mails) do
|
|
|
|
list[v] = k
|
|
|
|
end
|
|
|
|
for k,v in pairs(list) do
|
|
|
|
file = fs.open(fs.combine(config.mailPath, "/" .. id .. "/" .. k), "r")
|
|
|
|
if file then
|
|
|
|
output[#output + 1] = textutils.unserialize(file.readAll())
|
|
|
|
file.close()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return output
|
|
|
|
end
|
|
|
|
|
2019-03-05 03:02:39 +00:00
|
|
|
server.deleteMail = function(id, del)
|
|
|
|
local mails = alphasort(fs.list(fs.combine(config.mailPath, tostring(id))))
|
|
|
|
if mails[del] then
|
|
|
|
fs.delete(fs.combine(config.mailPath, tostring(id) .. "/" .. mails[del]))
|
|
|
|
return true
|
|
|
|
else
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-05 07:09:32 +00:00
|
|
|
server.setName = function(newName)
|
|
|
|
if server.checkValidName(newName) then
|
|
|
|
names[yourID] = newName
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-03 08:10:32 +00:00
|
|
|
-- receives messages and sends the appropriate response
|
2019-03-05 03:02:39 +00:00
|
|
|
server.makeServer = function(verbose)
|
2019-03-04 21:10:41 +00:00
|
|
|
local msg, isEncrypted, msgID
|
|
|
|
|
|
|
|
local say = function(text, id)
|
|
|
|
if verbose then
|
2019-03-05 03:02:39 +00:00
|
|
|
return print(text .. (id and (" (" .. id .. ")") or ""))
|
2019-03-04 21:10:41 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-03 08:10:32 +00:00
|
|
|
while true do
|
2019-03-05 17:38:29 +00:00
|
|
|
names = names
|
2019-03-04 21:10:41 +00:00
|
|
|
|
|
|
|
msg, isEncrypted, msgID = receive()
|
|
|
|
|
2019-03-05 17:38:29 +00:00
|
|
|
if msg then
|
|
|
|
if not isEncrypted then
|
2019-03-05 03:02:39 +00:00
|
|
|
if msg.command == "find_server" then
|
2019-03-05 17:38:29 +00:00
|
|
|
transmit({
|
2019-03-04 21:10:41 +00:00
|
|
|
command = msg.command .. "_respond",
|
|
|
|
server = yourID,
|
2019-03-05 17:38:29 +00:00
|
|
|
}, msgID, msg.id, yourID)
|
|
|
|
say("find_server")
|
|
|
|
end
|
|
|
|
elseif type(msg.id) == "number" and type(msg.command) == "string" then
|
|
|
|
if msg.command == "register" then
|
2019-03-04 21:10:41 +00:00
|
|
|
if (
|
2019-03-05 17:38:29 +00:00
|
|
|
type(msg.id) == "number" and
|
|
|
|
type(msg.name) == "string"
|
2019-03-04 21:10:41 +00:00
|
|
|
) then
|
2019-03-05 17:38:29 +00:00
|
|
|
local reply
|
|
|
|
local result, name = server.registerID(msg.id, msg.name)
|
|
|
|
if result then
|
|
|
|
reply = {
|
|
|
|
command = msg.command .. "_respond",
|
|
|
|
result = result,
|
|
|
|
name = name,
|
|
|
|
}
|
|
|
|
say("user " .. tostring(msg.id) .. " registered as " .. name)
|
|
|
|
else
|
|
|
|
reply = {
|
|
|
|
command = msg.command .. "_respond",
|
|
|
|
result = result,
|
|
|
|
}
|
|
|
|
say("user " .. tostring(msg.id) .. " failed to register as " .. tostring(msg.name) .. ": " .. name)
|
|
|
|
end
|
|
|
|
encTransmit(reply, msgID, msg.id, msg.id)
|
|
|
|
end
|
|
|
|
elseif not server.checkRegister(msg.id) then
|
|
|
|
encTransmit({
|
|
|
|
command = msg.command .. "_respond",
|
|
|
|
result = false,
|
|
|
|
errorMsg = "not registered"
|
|
|
|
}, msgID, msg.id, msg.id)
|
|
|
|
say("unregistered user attempt to use")
|
|
|
|
else
|
|
|
|
|
|
|
|
-- all the real nice stuff
|
|
|
|
|
|
|
|
if msg.command == "find_server" then
|
|
|
|
encTransmit({
|
|
|
|
command = msg.command .. "_respond",
|
|
|
|
server = yourID,
|
|
|
|
result = true
|
|
|
|
}, msgID, msg.id, msg.id)
|
|
|
|
say("find_server (aes)")
|
|
|
|
elseif msg.command == "get_names" then
|
|
|
|
encTransmit({
|
|
|
|
command = msg.command .. "_respond",
|
|
|
|
result = true,
|
|
|
|
}, msgID, msg.id, msg.id)
|
|
|
|
say("get_names", msg.id)
|
|
|
|
elseif msg.command == "send_mail" then
|
|
|
|
if (
|
|
|
|
msg.recipient and
|
|
|
|
type(msg.subject) == "string" and
|
|
|
|
type(msg.message) == "string"
|
|
|
|
) then
|
|
|
|
local reply = {
|
|
|
|
command = msg.command .. "_respond",
|
|
|
|
result = server.recordMail(msg.id, msg.recipient, msg.subject, msg.message, msg.attachments)
|
|
|
|
}
|
|
|
|
encTransmit(reply, msgID, msg.id, msg.id)
|
|
|
|
say("send_mail", msg.id)
|
|
|
|
end
|
|
|
|
elseif msg.command == "get_mail" then
|
|
|
|
local mail = server.getMail(msg.id)
|
2019-03-04 21:10:41 +00:00
|
|
|
local reply = {
|
|
|
|
command = msg.command .. "_respond",
|
2019-03-05 17:38:29 +00:00
|
|
|
result = true,
|
|
|
|
mail = mail,
|
2019-03-04 21:10:41 +00:00
|
|
|
}
|
2019-03-05 17:38:29 +00:00
|
|
|
encTransmit(reply, msgID, msg.id, msg.id)
|
|
|
|
say("get_mail", msg.id)
|
|
|
|
elseif msg.command == "delete_mail" then
|
|
|
|
local result = false
|
|
|
|
if type(msg.mail) == "number" then
|
|
|
|
result = server.deleteMail(msg.id, msg.mail, yourID)
|
|
|
|
end
|
|
|
|
encTransmit({
|
|
|
|
command = msg.command .. "_respond",
|
|
|
|
result = result,
|
|
|
|
}, msgID, msg.id, msg.id)
|
|
|
|
say("delete_mail", msg.id)
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
2019-03-04 21:10:41 +00:00
|
|
|
|
2019-03-05 17:38:29 +00:00
|
|
|
end
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
|
|
|
end
|
2019-03-04 21:10:41 +00:00
|
|
|
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-05 07:09:32 +00:00
|
|
|
local clientInterface = function(srv)
|
|
|
|
local scr_x, scr_y = term.getSize()
|
|
|
|
local inbox = {}
|
|
|
|
local refresh = function()
|
|
|
|
inbox = client.getMail(srv)
|
|
|
|
end
|
|
|
|
local cwrite = function(text, y)
|
|
|
|
local cx, cy = term.getCursorPos()
|
|
|
|
term.setCursorPos(scr_x / 2 - #text / 2, y or cy)
|
|
|
|
term.write(text)
|
|
|
|
end
|
|
|
|
local explode = function(div, str, replstr, includeDiv)
|
|
|
|
if (div == '') then
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
local pos, arr = 0, {}
|
|
|
|
for st, sp in function() return string.find(str, div, pos, false) end do
|
|
|
|
table.insert(arr, string.sub(replstr or str, pos, st - 1 + (includeDiv and #div or 0)))
|
|
|
|
pos = sp + 1
|
|
|
|
end
|
|
|
|
table.insert(arr, string.sub(replstr or str, pos))
|
|
|
|
return arr
|
|
|
|
end
|
|
|
|
srv = srv or tonumber( client.findServer(argData[1]) )
|
|
|
|
if not srv then
|
|
|
|
error("No server was found!")
|
|
|
|
end
|
|
|
|
for k,v in pairs(client.getNames(srv) or {}) do
|
|
|
|
names[k] = v
|
|
|
|
end
|
|
|
|
|
|
|
|
if not names[yourID] then
|
|
|
|
term.setBackgroundColor(colors.black)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
term.clear()
|
|
|
|
local attempt
|
|
|
|
cwrite("Enter your name:", 3)
|
|
|
|
while true do
|
|
|
|
term.setCursorPos(2, 5)
|
|
|
|
term.write(":")
|
|
|
|
attempt = read()
|
|
|
|
if server.checkValidName(attempt) then
|
|
|
|
names[yourID] = attempt
|
|
|
|
writeNames()
|
|
|
|
client.register(srv, attempt)
|
|
|
|
break
|
|
|
|
else
|
|
|
|
term.clear()
|
|
|
|
cwrite("Bad name! Enter your name:", 3)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
refresh()
|
|
|
|
|
|
|
|
local keyWrite = function(text, pos)
|
|
|
|
local txcol = term.getTextColor()
|
|
|
|
term.write(text:sub(1, pos - 1))
|
|
|
|
term.setTextColor(colors.yellow)
|
|
|
|
term.write(text:sub(pos, pos))
|
|
|
|
term.setTextColor(txcol)
|
|
|
|
term.write(text:sub(pos + 1))
|
|
|
|
end
|
|
|
|
|
|
|
|
local area_inbox = function()
|
|
|
|
local scroll = 0
|
|
|
|
local render = function(scroll)
|
|
|
|
local y = 1
|
|
|
|
term.setBackgroundColor(colors.black)
|
|
|
|
term.clear()
|
|
|
|
for i = 1 + scroll, scroll + scr_y - 1 do
|
|
|
|
if inbox[i] then
|
|
|
|
term.setCursorPos(1, y)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
term.write(names[inbox[i].sender]:sub(1, 10))
|
|
|
|
|
|
|
|
term.setCursorPos(11, y)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
term.write(inbox[i].subject:sub(1, 12))
|
|
|
|
|
|
|
|
term.setCursorPos(24, y)
|
|
|
|
term.setTextColor(colors.gray)
|
|
|
|
term.write(inbox[i].message:sub(1, scr_x - 23))
|
|
|
|
end
|
|
|
|
y = y + 1
|
|
|
|
end
|
|
|
|
term.setCursorPos(1, scr_y)
|
|
|
|
term.setBackgroundColor(colors.gray)
|
|
|
|
term.clearLine()
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
--term.write(names[yourID] .. ": ")
|
|
|
|
keyWrite("Quit ", 1)
|
|
|
|
keyWrite("New ", 1)
|
|
|
|
keyWrite("Refresh ", 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
-- logic(k)
|
|
|
|
local evt, key, mx, my
|
|
|
|
local adjY -- mouse Y adjusted for scroll
|
|
|
|
while true do
|
|
|
|
render(scroll)
|
|
|
|
evt, key, mx, my = os.pullEvent()
|
|
|
|
if evt == "mouse_click" then
|
|
|
|
adjY = my + scroll
|
|
|
|
if inbox[adjY] then
|
|
|
|
return "view_mail", inbox[adjY]
|
|
|
|
end
|
|
|
|
elseif evt == "mouse_scroll" then
|
|
|
|
scroll = scroll + key
|
|
|
|
elseif evt == "key" then
|
|
|
|
if key == keys.q then
|
|
|
|
return "exit"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local area_view_mail = function(mail)
|
|
|
|
local scroll = 0
|
|
|
|
local writeHeader = function(left, right, y)
|
|
|
|
if y then
|
|
|
|
term.setCursorPos(1, y)
|
|
|
|
end
|
|
|
|
term.setTextColor(colors.lightGray)
|
|
|
|
term.write(left)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
term.write(" " .. right)
|
|
|
|
end
|
|
|
|
local render = function(scroll)
|
|
|
|
term.setBackgroundColor(colors.black)
|
|
|
|
term.setTextColor(colors.lightGray)
|
|
|
|
term.clear()
|
|
|
|
writeHeader("From", names[mail.sender], 1)
|
|
|
|
writeHeader("Subject", mail.subject, 2)
|
|
|
|
local words = explode(" ", mail.message, nil, true)
|
|
|
|
local buffer = {""}
|
|
|
|
for i = 1, #words do
|
|
|
|
words[i] = words[i]:gsub("\n", (" "):rep(scr_x))
|
|
|
|
if #buffer[#buffer] + #words[i] > scr_x then
|
|
|
|
buffer[#buffer+1] = words[i]
|
|
|
|
else
|
|
|
|
buffer[#buffer] = buffer[#buffer] .. words[i]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
local y = 3
|
|
|
|
for i = scroll + 1, scroll + scr_y - 3 do
|
|
|
|
if buffer[i] then
|
|
|
|
term.setCursorPos(1, y)
|
|
|
|
term.write(buffer[i])
|
|
|
|
end
|
|
|
|
y = y + 1
|
|
|
|
end
|
|
|
|
term.setCursorPos(1, scr_y)
|
|
|
|
term.setBackgroundColor(colors.gray)
|
|
|
|
term.setTextColor(colors.white)
|
|
|
|
term.clearLine()
|
|
|
|
keyWrite("Quit ", 1)
|
|
|
|
keyWrite("Reply ", 1)
|
|
|
|
keyWrite("Delete ", 1)
|
|
|
|
end
|
|
|
|
|
|
|
|
local evt, key, mx, my
|
|
|
|
while true do
|
|
|
|
render(scroll)
|
|
|
|
evt, key, mx, my = os.pullEvent()
|
|
|
|
if evt == "key" then
|
|
|
|
if key == keys.q then
|
|
|
|
return "exit"
|
|
|
|
end
|
|
|
|
elseif evt == "mouse_scroll" then
|
|
|
|
scroll = scroll + key
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local res, output
|
|
|
|
while true do
|
|
|
|
res, output = area_inbox()
|
|
|
|
if res == "exit" then
|
|
|
|
term.setCursorPos(1, scr_y)
|
|
|
|
term.setBackgroundColor(colors.black)
|
|
|
|
term.clearLine()
|
|
|
|
sleep(0.05)
|
|
|
|
return
|
|
|
|
elseif res == "view_mail" then
|
|
|
|
area_view_mail(output)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-03-03 08:10:32 +00:00
|
|
|
if isServer then
|
2019-03-05 07:09:32 +00:00
|
|
|
names[yourID] = names[yourID] or serverName
|
|
|
|
writeNames()
|
2019-03-05 03:02:39 +00:00
|
|
|
server.makeServer(true)
|
2019-03-05 07:09:32 +00:00
|
|
|
elseif shell then
|
|
|
|
clientInterface()
|
2019-03-03 08:10:32 +00:00
|
|
|
end
|
2019-03-04 21:10:41 +00:00
|
|
|
|
|
|
|
return {client = client, server = server}
|