2019-03-23 00:30:31 +00:00
--[[
sysMail
by LDDestroier
Make sure that the server has the keys of all clients !
To do :
+ update read prompt
+ implement auto - update
--]]
local mainPath = " .sysmail " -- where everything is based
local yourID = os.getComputerID ( ) -- duhhhhh
local onlyUseWiredModems = false -- if true, will refuse to use wireless modems
local defaultTimer = 3 -- will wait this amount of seconds for a server response
local maximumMailLines = 16 -- will cap all emails to this amount of lines
2019-03-05 22:55:36 +00:00
2019-03-23 00:16:02 +00:00
local scr_x , scr_y = term.getSize ( )
2019-03-03 08:10:32 +00:00
2019-03-23 00:30:31 +00:00
local config = {
channel = 1024 ,
keyPath = fs.combine ( mainPath , " keys " ) ,
mailPath = fs.combine ( mainPath , " mail " ) ,
apiPath = fs.combine ( mainPath , " api " ) ,
nameFile = fs.combine ( mainPath , " names " ) ,
attachmentPath = " attachments "
2019-03-23 00:16:02 +00:00
}
2019-03-04 21:10:41 +00:00
2019-03-23 00:30:31 +00:00
--
local getTableLength = function ( tbl )
local output = 0
for k , v in pairs ( tbl ) do
output = output + 1
end
return output
end
-- used for picking attachments
local lddfm = { scroll = 0 , ypaths = { } }
lddfm.scr_x , lddfm.scr_y = term.getSize ( )
lddfm.setPalate = function ( _p )
if type ( _p ) ~= " table " then _p = { } end
lddfm.p = { --the DEFAULT color palate
bg = _p.bg or colors.gray , -- whole background color
d_txt = _p.d_txt or colors.yellow , -- directory text color
d_bg = _p.d_bg or colors.gray , -- directory bg color
f_txt = _p.f_txt or colors.white , -- file text color
f_bg = _p.f_bg or colors.gray , -- file bg color
p_txt = _p.p_txt or colors.black , -- path text color
p_bg = _p.p_bg or colors.lightGray , -- path bg color
close_txt = _p.close_txt or colors.gray , -- close button text color
close_bg = _p.close_bg or colors.lightGray , -- close button bg color
scr = _p.scr or colors.lightGray , -- scrollbar color
scrbar = _p.scrbar or colors.gray , -- scroll tab color
}
end
lddfm.setPalate ( )
lddfm.foldersOnTop = function ( floop , path )
local output = { }
for a = 1 , # floop do
if fs.isDir ( fs.combine ( path , floop [ a ] ) ) then
table.insert ( output , 1 , floop [ a ] )
else
table.insert ( output , floop [ a ] )
end
end
return output
end
lddfm.filterFileFolders = function ( list , path , _noFiles , _noFolders , _noCD , _doHidden )
local output = { }
for a = 1 , # list do
local entry = fs.combine ( path , list [ a ] )
if fs.isDir ( entry ) then
if entry == " .. " then
if not ( _noCD or _noFolders ) then table.insert ( output , list [ a ] ) end
else
if not ( ( not _doHidden ) and list [ a ] : sub ( 1 , 1 ) == " . " ) then
if not _noFolders then table.insert ( output , list [ a ] ) end
end
end
else
if not ( ( not _doHidden ) and list [ a ] : sub ( 1 , 1 ) == " . " ) then
if not _noFiles then table.insert ( output , list [ a ] ) end
end
end
end
return output
end
lddfm.isColor = function ( col )
for k , v in pairs ( colors ) do
if v == col then
return true , k
end
end
return false
end
lddfm.clearLine = function ( x1 , x2 , _y , _bg , _char )
local cbg , bg = term.getBackgroundColor ( )
local x , y = term.getCursorPos ( )
local sx , sy = term.getSize ( )
if type ( _char ) == " string " then char = _char else char = " " end
if type ( _bg ) == " number " then
if lddfm.isColor ( _bg ) then bg = _bg
else bg = cbg end
else bg = cbg end
term.setCursorPos ( x1 or 1 , _y or y )
term.setBackgroundColor ( bg )
if x2 then --it pains me to add an if statement to something as simple as this
term.write ( ( char or " " ) : rep ( x2 - x1 ) )
else
term.write ( ( char or " " ) : rep ( sx - ( x1 or 0 ) ) )
end
term.setBackgroundColor ( cbg )
term.setCursorPos ( x , y )
end
lddfm.render = function ( _x1 , _y1 , _x2 , _y2 , _rlist , _path , _rscroll , _canClose , _scrbarY )
local px , py = term.getCursorPos ( )
local x1 , x2 , y1 , y2 = _x1 or 1 , _x2 or lddfm.scr_x , _y1 or 1 , _y2 or lddfm.scr_y
local rlist = _rlist or { " Invalid directory. " }
local path = _path or " And that's terrible. "
ypaths = { }
local rscroll = _rscroll or 0
for a = y1 , y2 do
lddfm.clearLine ( x1 , x2 , a , lddfm.p . bg )
end
term.setCursorPos ( x1 , y1 )
term.setTextColor ( lddfm.p . p_txt )
lddfm.clearLine ( x1 , x2 + 1 , y1 , lddfm.p . p_bg )
term.setBackgroundColor ( lddfm.p . p_bg )
term.write ( ( " / " .. path ) : sub ( 1 , x2 - x1 ) )
for a = 1 , ( y2 - y1 ) do
if rlist [ a + rscroll ] then
term.setCursorPos ( x1 , a + ( y1 ) )
if fs.isDir ( fs.combine ( path , rlist [ a + rscroll ] ) ) then
lddfm.clearLine ( x1 , x2 , a + ( y1 ) , lddfm.p . d_bg )
term.setTextColor ( lddfm.p . d_txt )
term.setBackgroundColor ( lddfm.p . d_bg )
else
lddfm.clearLine ( x1 , x2 , a + ( y1 ) , lddfm.p . f_bg )
term.setTextColor ( lddfm.p . f_txt )
term.setBackgroundColor ( lddfm.p . f_bg )
end
term.write ( rlist [ a + rscroll ] : sub ( 1 , x2 - x1 ) )
ypaths [ a + ( y1 ) ] = rlist [ a + rscroll ]
else
lddfm.clearLine ( x1 , x2 , a + ( y1 ) , lddfm.p . bg )
end
end
local scrbarY = _scrbarY or math.ceil ( ( y1 + 1 ) + ( ( _rscroll / ( # _rlist - ( y2 - ( y1 + 1 ) ) ) ) * ( y2 - ( y1 + 1 ) ) ) )
for a = y1 + 1 , y2 do
term.setCursorPos ( x2 , a )
if a == scrbarY then
term.setBackgroundColor ( lddfm.p . scrbar )
else
term.setBackgroundColor ( lddfm.p . scr )
end
term.write ( " " )
end
if _canClose then
term.setCursorPos ( x2 - 4 , y1 )
term.setTextColor ( lddfm.p . close_txt )
term.setBackgroundColor ( lddfm.p . close_bg )
term.write ( " close " )
end
term.setCursorPos ( px , py )
return scrbarY
end
lddfm.coolOutro = function ( x1 , y1 , x2 , y2 , _bg , _txt , char )
local cx , cy = term.getCursorPos ( )
local bg , txt = term.getBackgroundColor ( ) , term.getTextColor ( )
term.setTextColor ( _txt or colors.white )
term.setBackgroundColor ( _bg or colors.black )
local _uwah = 0
for y = y1 , y2 do
for x = x1 , x2 do
_uwah = _uwah + 1
term.setCursorPos ( x , y )
term.write ( char or " " )
if _uwah >= math.ceil ( ( x2 - x1 ) * 1.63 ) then sleep ( 0 ) _uwah = 0 end
end
end
term.setTextColor ( txt )
term.setBackgroundColor ( bg )
term.setCursorPos ( cx , cy )
end
lddfm.scrollMenu = function ( amount , list , y1 , y2 )
if # list >= y2 - y1 then
lddfm.scroll = lddfm.scroll + amount
if lddfm.scroll < 0 then
lddfm.scroll = 0
end
if lddfm.scroll > # list - ( y2 - y1 ) then
lddfm.scroll = # list - ( y2 - y1 )
end
end
end
lddfm.makeMenu = function ( _x1 , _y1 , _x2 , _y2 , _path , _noFiles , _noFolders , _noCD , _noSelectFolders , _doHidden , _p , _canClose )
if _noFiles and _noFolders then
return false , " C'mon, man... "
end
if _x1 == true then
return false , " arguments: x1, y1, x2, y2, path, noFiles, noFolders, noCD, noSelectFolders, doHidden, palate, canClose " -- a little help
end
lddfm.setPalate ( _p )
local path , list = _path or " "
lddfm.scroll = 0
local _pbg , _ptxt = term.getBackgroundColor ( ) , term.getTextColor ( )
local x1 , x2 , y1 , y2 = _x1 or 1 , _x2 or lddfm.scr_x , _y1 or 1 , _y2 or lddfm.scr_y
local keysDown = { }
local _barrY
while true do
list = lddfm.foldersOnTop ( lddfm.filterFileFolders ( fs.list ( path ) , path , _noFiles , _noFolders , _noCD , _doHidden ) , path )
if ( fs.getDir ( path ) ~= " .. " ) and not ( _noCD or _noFolders ) then
table.insert ( list , 1 , " .. " )
end
_res , _barrY = pcall ( function ( ) return lddfm.render ( x1 , y1 , x2 , y2 , list , path , lddfm.scroll , _canClose ) end )
if not _res then
error ( _barrY )
end
local evt = { os.pullEvent ( ) }
if evt [ 1 ] == " mouse_scroll " then
lddfm.scrollMenu ( evt [ 2 ] , list , y1 , y2 )
elseif evt [ 1 ] == " mouse_click " then
local butt , mx , my = evt [ 2 ] , evt [ 3 ] , evt [ 4 ]
if ( butt == 1 and my == y1 and mx <= x2 and mx >= x2 - 4 ) and _canClose then
--lddfm.coolOutro(x1,y1,x2,y2)
term.setTextColor ( _ptxt ) term.setBackgroundColor ( _pbg )
return false
elseif ypaths [ my ] and ( mx >= x1 and mx < x2 ) then --x2 is reserved for the scrollbar, breh
if fs.isDir ( fs.combine ( path , ypaths [ my ] ) ) then
if _noCD or butt == 3 then
if not _noSelectFolders or _noFolders then
--lddfm.coolOutro(x1,y1,x2,y2)
term.setTextColor ( _ptxt ) term.setBackgroundColor ( _pbg )
return fs.combine ( path , ypaths [ my ] )
end
else
path = fs.combine ( path , ypaths [ my ] )
lddfm.scroll = 0
end
else
term.setTextColor ( _ptxt ) term.setBackgroundColor ( _pbg )
return fs.combine ( path , ypaths [ my ] )
end
end
elseif evt [ 1 ] == " key " then
keysDown [ evt [ 2 ] ] = true
if evt [ 2 ] == keys.enter and not ( _noFolders or _noCD or _noSelectFolders ) then --the logic for _noCD being you'd normally need to go back a directory to select the current directory.
--lddfm.coolOutro(x1,y1,x2,y2)
term.setTextColor ( _ptxt ) term.setBackgroundColor ( _pbg )
return path
end
if evt [ 2 ] == keys.up then
lddfm.scrollMenu ( - 1 , list , y1 , y2 )
elseif evt [ 2 ] == keys.down then
lddfm.scrollMenu ( 1 , list , y1 , y2 )
end
if evt [ 2 ] == keys.pageUp then
lddfm.scrollMenu ( y1 - y2 , list , y1 , y2 )
elseif evt [ 2 ] == keys.pageDown then
lddfm.scrollMenu ( y2 - y1 , list , y1 , y2 )
end
if evt [ 2 ] == keys.home then
lddfm.scroll = 0
elseif evt [ 2 ] == keys [ " end " ] then
if # list > ( y2 - y1 ) then
lddfm.scroll = # list - ( y2 - y1 )
end
end
if evt [ 2 ] == keys.h then
if keysDown [ keys.leftCtrl ] or keysDown [ keys.rightCtrl ] then
_doHidden = not _doHidden
end
elseif _canClose and ( evt [ 2 ] == keys.x or evt [ 2 ] == keys.q or evt [ 2 ] == keys.leftCtrl ) then
--lddfm.coolOutro(x1,y1,x2,y2)
term.setTextColor ( _ptxt ) term.setBackgroundColor ( _pbg )
return false
end
elseif evt [ 1 ] == " key_up " then
keysDown [ evt [ 2 ] ] = false
end
end
end
local alphasort = function ( tbl )
table.sort ( tbl , function ( a , b )
if type ( a ) == " table " then
return string.lower ( a.time ) > string.lower ( b.time )
else
return string.lower ( a ) > string.lower ( b )
end
end )
return tbl
end
local readFile = function ( path )
if fs.exists ( path ) then
local file = fs.open ( path , " r " )
local contents = file.readAll ( )
file.close ( )
return contents
else
return nil
end
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
local cwrite = function ( text , y )
local cx , cy = term.getCursorPos ( )
term.setCursorPos ( math.floor ( scr_x / 2 - # text / 2 + 1 ) , y or cy )
term.write ( text )
end
local dialogueBox = function ( msg , timeout )
local height = 7
local baseY = scr_y / 2 - height / 2
term.setTextColor ( colors.white )
term.setBackgroundColor ( colors.gray )
for y = 1 , height do
term.setCursorPos ( 1 , ( scr_y / 2 ) - ( baseY / 2 ) + ( y - 1 ) )
term.clearLine ( )
end
cwrite ( ( " = " ) : rep ( scr_x ) , baseY )
cwrite ( msg , baseY + height / 2 )
cwrite ( ( " = " ) : rep ( scr_x ) , baseY + height - 1 )
local evt
local tID = os.startTimer ( timeout or 2 )
repeat
evt = { os.pullEvent ( ) }
until ( evt [ 1 ] == " key " ) or ( evt [ 1 ] == " timer " and evt [ 2 ] == tID )
term.setBackgroundColor ( colors.black )
end
local keyList , names = { } , { }
2019-03-03 08:10:32 +00:00
2019-03-23 00:30:31 +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-23 00:16:02 +00:00
2019-03-23 00:30:31 +00:00
local readNames = function ( )
return textutils.unserialize ( readFile ( config.nameFile ) or " {} " ) or { }
end
2019-03-03 08:10:32 +00:00
2019-03-23 00:30:31 +00:00
local writeNames = function ( _names )
return writeFile ( config.nameFile , textutils.serialize ( _names or names ) )
end
-- keyList[id] = key
-- names[id] = name
-- get personal key file
keyList [ yourID ] = " "
if fs.exists ( fs.combine ( config.keyPath , tostring ( yourID ) ) ) then
keyList [ yourID ] = readFile ( fs.combine ( config.keyPath , tostring ( yourID ) ) )
else
for i = 1 , 64 do
keyList [ yourID ] = keyList [ yourID ] .. string.char ( math.random ( 11 , 255 ) )
end
writeFile ( fs.combine ( config.keyPath , tostring ( yourID ) ) , keyList [ yourID ] )
end
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
names = readNames ( )
keyList = getAllKeys ( )
local apiData = {
[ " aeslua " ] = {
path = " aeslua.lua " ,
url = " https://raw.githubusercontent.com/LDDestroier/CC/master/API/aeslua.lua " , -- thanks SquidDev
useLoadAPI = true ,
}
}
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
if data.useLoadAPI then
local res = os.loadAPI ( data.path )
--error(res)
else
_ENV [ name ] = dofile ( data.path )
end
end
local function interpretArgs ( tInput , tArgs )
2019-03-03 08:10:32 +00:00
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
2019-03-23 00:30:31 +00:00
local argList = {
[ " --server " ] = false
}
2019-03-04 21:10:41 +00:00
2019-03-23 00:30:31 +00:00
local argData , argErrors = interpretArgs ( { ... } , argList )
local isServer = argData [ " --server " ]
local serverName = argData [ 1 ] or " server "
2019-03-03 08:10:32 +00:00
2019-03-23 00:30:31 +00:00
if ccemux and ( not peripheral.find ( " modem " ) ) then
ccemux.attach ( " top " , " wireless_modem " )
2019-03-03 08:10:32 +00:00
end
2019-03-23 00:30:31 +00:00
local modem
local getModem = function ( doNotPickWireless )
local output , periphList
if not peripheral.find ( " modem " ) and ccemux then
ccemux.attach ( " top " , " wireless_modem " )
end
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
if try == 1 then
write ( " Looking for modem... " )
else
write ( " . " )
end
sleep ( 0.15 )
2019-03-04 21:10:41 +00:00
end
2019-03-23 00:30:31 +00:00
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 = { }
local transmit = function ( msg , msgID )
modem = getModem ( onlyUseWiredModems )
modem.transmit ( config.channel , config.channel , {
msg = msg ,
encrypted = false ,
msgID = msgID
} )
2019-03-04 21:10:41 +00:00
end
2019-03-23 00:30:31 +00:00
local encTransmit = function ( msg , msgID , recipient , encID )
modem = getModem ( onlyUseWiredModems )
local key = keyList [ encID or recipient ]
if not key then
error ( " You do not possess the key of the recipient. " )
else
modem.transmit ( config.channel , config.channel , {
msg = aeslua.encrypt ( key , textutils.serialize ( msg ) ) ,
encrypted = true ,
msgID = msgID ,
recipient = recipient
} )
2019-03-05 07:09:32 +00:00
end
end
2019-03-23 00:30:31 +00:00
local receive = function ( msgID , specifyCommand , encID , timer )
local evt , msg , tID
if timer then
tID = os.startTimer ( timer )
end
modem = getModem ( )
while true do
evt = { os.pullEvent ( ) }
if evt [ 1 ] == " modem_message " then
if type ( evt [ 5 ] ) == " table " then
if evt [ 5 ] . encrypted then
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
end
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
end
elseif evt [ 1 ] == " timer " and evt [ 2 ] == tID then
return nil , nil , nil
end
end
2019-03-03 08:10:32 +00:00
end
2019-03-23 00:30:31 +00:00
local getNameID = function ( name )
for k , v in pairs ( names ) do
if v == name then
return k
end
2019-03-05 17:38:29 +00:00
end
2019-03-23 00:30:31 +00:00
return nil
end
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
client.findServer = function ( srv )
local msgID = math.random ( 1 , 2 ^ 30 )
srv = type ( srv ) == " number " and srv or getNameID ( srv )
assert ( tonumber ( srv ) or ( not srv ) , " invalid server " )
transmit ( {
id = yourID ,
command = " find_server "
} , msgID )
local reply , isEncrypted = receive ( msgID , " find_server_respond " , srv , defaultTimer )
if type ( reply ) == " table " then
if reply.server then
return reply.server
end
2019-03-23 00:16:02 +00:00
end
2019-03-23 00:30:31 +00:00
return nil
2019-03-05 03:02:39 +00:00
end
2019-03-23 00:30:31 +00:00
-- Registers your ID to a name.
client.register = function ( srv , username )
local msgID = math.random ( 1 , 2 ^ 30 )
assert ( srv , " register( server, username ) " )
srv = type ( srv ) == " number " and srv or getNameID ( srv )
assert ( srv , " invalid server " )
encTransmit ( {
id = yourID ,
command = " register " ,
name = username
} , msgID , srv , yourID )
local reply , isEncrypted = receive ( msgID , " register_respond " , yourID , defaultTimer )
if reply then
return reply.result
else
return false
end
end
-- Gets a list of all registered ID names
client.getNames = function ( srv )
local msgID = math.random ( 1 , 2 ^ 30 )
assert ( srv , " getNames( server ) " )
srv = type ( srv ) == " number " and srv or getNameID ( srv )
assert ( srv , " invalid server " )
encTransmit ( {
id = yourID ,
command = " get_names "
} , msgID , srv , yourID )
local reply , isEncrypted = receive ( msgID , " get_names_respond " , yourID , defaultTimer )
if type ( reply ) == " table " then
return reply.names
2019-03-05 03:02:39 +00:00
else
return nil
end
2019-03-04 21:10:41 +00:00
end
2019-03-23 00:30:31 +00:00
-- Sends an email to a recipient ID.
client.sendMail = function ( srv , recipient , subject , message , attachments )
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 " )
local msgID = math.random ( 1 , 2 ^ 30 )
if type ( recipient ) == " string " then
recipient = getNameID ( recipient )
end
assert ( recipient , " invalid recipient " )
encTransmit ( {
command = " send_mail " ,
id = yourID ,
recipient = recipient ,
subject = subject ,
message = message ,
attachments = attachments
} , msgID , srv , yourID )
local reply , isEncrypted = receive ( msgID , " send_mail_respond " , yourID , defaultTimer )
if ( isEncrypted and type ( reply ) == " table " ) then
return reply.result
2019-03-05 03:02:39 +00:00
else
2019-03-23 00:30:31 +00:00
return false
2019-03-05 03:02:39 +00:00
end
2019-03-04 21:10:41 +00:00
end
2019-03-23 00:30:31 +00:00
client.getMail = function ( srv )
local msgID = math.random ( 1 , 2 ^ 30 )
assert ( srv , " getMail( server ) " )
srv = type ( srv ) == " number " and srv or getNameID ( srv )
assert ( srv , " invalid server " )
encTransmit ( {
command = " get_mail " ,
id = yourID ,
} , msgID , srv , yourID )
local reply , isEncrypted = receive ( msgID , " get_mail_respond " , yourID , defaultTimer )
if ( isEncrypted and type ( reply ) == " table " ) then
if reply.mail then
return alphasort ( reply.mail )
2019-03-05 07:09:32 +00:00
end
2019-03-04 21:10:41 +00:00
end
end
2019-03-23 00:30:31 +00:00
client.deleteMail = function ( srv , mail )
local msgID = math.random ( 1 , 2 ^ 30 )
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 " )
encTransmit ( {
command = " delete_mail " ,
id = yourID ,
mail = mail ,
} , msgID , srv , yourID )
local reply , isEncrypted = receive ( msgID , " delete_mail_respond " , yourID , defaultTimer )
if ( isEncrypted and type ( reply ) == " table " ) then
return reply.result
2019-03-04 21:10:41 +00:00
else
2019-03-23 00:30:31 +00:00
return false
2019-03-03 08:10:32 +00:00
end
end
2019-03-23 00:30:31 +00:00
---- ----
---- SERVER COMMANDS ----
---- ----
-- check whether or not a name is valid to be used
server.checkValidName = function ( name )
if type ( name ) == " string " then
if # name >= 3 or # name <= 24 then
return true
2019-03-23 00:16:02 +00:00
end
2019-03-04 21:10:41 +00:00
end
2019-03-23 00:30:31 +00:00
return false
end
2019-03-04 21:10:41 +00:00
2019-03-23 00:30:31 +00:00
-- check whether or not an ID is registered
server.checkRegister = function ( id )
-- I make the code this stupid looking in case I add other stipulations
if names [ id ] or getNameID ( names [ id ] ) then
return true
else
return false
end
end
2019-03-04 21:10:41 +00:00
2019-03-23 00:30:31 +00:00
server.registerID = function ( id , name )
local path = fs.combine ( config.mailPath , tostring ( id ) )
if ( ( not server.checkRegister ( name ) ) or getNameID ( name ) == id ) then
fs.makeDir ( path )
names [ id ] = name
writeNames ( )
return true , names [ id ]
else
return false , " name already exists "
end
end
2019-03-03 08:10:32 +00:00
2019-03-23 00:30:31 +00:00
-- records a full email to file
server.recordMail = function ( sender , _recipient , subject , message , attachments )
local time = os.epoch ( " utc " )
local recipient
if _recipient == " * " then
recipient = fs.list ( config.mailPath )
elseif type ( _recipient ) ~= " table " then
recipient = { tostring ( _recipient ) }
2019-03-05 03:02:39 +00:00
end
2019-03-23 00:30:31 +00:00
local msg = textutils.serialize ( {
sender = sender ,
time = time ,
read = false ,
subject = subject ,
message = message ,
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
end
-- returns every email in an ID's inbox
server.getMail = function ( id )
local output , list = { } , { }
local mails = fs.list ( fs.combine ( config.mailPath , tostring ( id ) ) )
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 ( )
2019-03-23 00:16:02 +00:00
end
2019-03-23 00:30:31 +00:00
end
return output
end
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
2019-03-23 00:16:02 +00:00
return false
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
end
2019-03-04 21:10:41 +00:00
2019-03-23 00:30:31 +00:00
server.setName = function ( newName )
if server.checkValidName ( newName ) then
names [ yourID ] = newName
end
end
-- receives messages and sends the appropriate response
server.makeServer = function ( verbose )
local msg , isEncrypted , msgID
local say = function ( text , id )
if verbose then
return print ( text .. ( id and ( " ( " .. id .. " ) " ) or " " ) )
2019-03-04 21:10:41 +00:00
end
end
2019-03-23 00:30:31 +00:00
if verbose then
term.clear ( )
term.setCursorPos ( 1 , 1 )
print ( " Make sure client keys are copied to key folder! " )
end
2019-03-06 00:59:31 +00:00
2019-03-23 00:30:31 +00:00
say ( " SysMail server started. " )
2019-03-06 00:59:31 +00:00
2019-03-23 00:30:31 +00:00
while true do
2019-03-04 21:10:41 +00:00
2019-03-23 00:30:31 +00:00
msg , isEncrypted , msgID = receive ( nil , nil , nil , 5 )
2019-03-04 21:10:41 +00:00
2019-03-23 00:30:31 +00:00
if not msg then
keyList = getAllKeys ( )
else
if not isEncrypted then
if msg.command == " find_server " then
transmit ( {
command = msg.command .. " _respond " ,
server = yourID ,
} , msgID , msg.id , yourID )
say ( " find_server " )
2019-03-05 17:38:29 +00:00
end
2019-03-23 00:30:31 +00:00
elseif type ( msg.id ) == " number " and type ( msg.command ) == " string " then
if msg.command == " register " then
if (
type ( msg.id ) == " number " and
type ( msg.name ) == " string "
) then
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 )
2019-03-05 17:38:29 +00:00
else
2019-03-23 00:30:31 +00:00
reply = {
command = msg.command .. " _respond " ,
result = result ,
}
say ( " user " .. tostring ( msg.id ) .. " failed to register as " .. tostring ( msg.name ) .. " : " .. name )
2019-03-05 17:38:29 +00:00
end
2019-03-23 00:30:31 +00:00
encTransmit ( reply , msgID , msg.id , msg.id )
2019-03-05 17:38:29 +00:00
end
2019-03-23 00:30:31 +00:00
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 " )
2019-03-05 17:38:29 +00:00
else
2019-03-23 00:30:31 +00:00
-- 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 " ,
names = names ,
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 )
local reply = {
command = msg.command .. " _respond " ,
result = true ,
mail = mail ,
}
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 )
end
2019-03-05 17:38:29 +00:00
end
2019-03-03 08:10:32 +00:00
end
end
2019-03-23 00:30:31 +00:00
2019-03-03 08:10:32 +00:00
end
2019-03-23 00:30:31 +00:00
end
2019-03-03 08:10:32 +00:00
2019-03-23 00:30:31 +00:00
local clientInterface = function ( srv )
local scr_x , scr_y = term.getSize ( )
local inbox = { }
local refresh = function ( )
dialogueBox ( " Refreshing... " , 0 )
inbox = client.getMail ( srv )
end
local explode = function ( div , str , replstr , includeDiv )
if div == ' ' then
return false
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
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
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
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! " )
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:16:02 +00:00
2019-03-23 00:30:31 +00:00
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 ( )
break
else
term.clear ( )
cwrite ( " Bad name! Enter your name: " , 3 )
end
2019-03-05 22:55:36 +00:00
end
end
2019-03-23 00:30:31 +00:00
client.register ( srv , names [ yourID ] )
2019-03-23 00:16:02 +00:00
2019-03-23 00:30:31 +00:00
for k , v in pairs ( client.getNames ( srv ) or { } ) do
names [ k ] = v
end
term.clear ( )
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 writeHeader = function ( left , right , y )
if y then
term.setCursorPos ( 1 , y )
2019-03-23 00:16:02 +00:00
end
2019-03-23 00:30:31 +00:00
term.setTextColor ( colors.lightGray )
term.write ( left )
term.setTextColor ( colors.white )
term.write ( " " .. right )
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
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 , 18 ) )
term.setCursorPos ( 30 , y )
term.setTextColor ( colors.gray )
term.write ( inbox [ i ] . message : sub ( 1 , scr_x - 30 ) )
end
y = y + 1
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
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 )
term.setCursorPos ( scr_x - # names [ yourID ] , scr_y )
term.setTextColor ( colors.lightGray )
term.write ( names [ yourID ] )
2019-03-05 07:09:32 +00:00
end
2019-03-06 00:59:31 +00:00
2019-03-23 00:30:31 +00:00
-- logic(k)
local barCommands = {
[ keys.q ] = { 1 , scr_y , 4 } ,
[ keys.n ] = { 6 , scr_y , 3 } ,
[ keys.r ] = { 10 , scr_y , 7 } ,
}
local evt , key , mx , my
local adjY -- mouse Y adjusted for scroll
while true do
render ( scroll )
inbox = alphasort ( inbox )
evt , key , mx , my = os.pullEvent ( )
if evt == " mouse_click " then
adjY = my + scroll
if inbox [ adjY ] then
return " view_mail " , { adjY }
2019-03-23 00:16:02 +00:00
else
2019-03-23 00:30:31 +00:00
for key , data in pairs ( barCommands ) do
if my == data [ 2 ] and mx >= data [ 1 ] and mx <= data [ 1 ] + data [ 3 ] - 1 then
os.queueEvent ( " key " , key )
break
2019-03-23 00:16:02 +00:00
end
end
end
2019-03-23 00:30:31 +00:00
elseif evt == " mouse_scroll " then
scroll = math.min ( math.max ( 0 , scroll + key ) , math.max ( 0 , # inbox - ( scr_y - 1 ) ) )
elseif evt == " key " then
if key == keys.n then
return " new_mail "
elseif key == keys.r then
return " refresh "
elseif key == keys.q then
return " exit "
2019-03-23 00:16:02 +00:00
end
end
end
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
local niftyRead = function ( prebuffer , startX , startY , startCursorMX , startCursorMY , allowEnter , maxLines , maxLength , history )
local cx , cy = term.getCursorPos ( )
local histPos = 0
startX , startY = startX or cx , startY or cy
local scroll = 0
local buffer = { { } }
local unassemble = function ( pBuffer )
local output = { { " " } }
local y = 1
local x = 1
for i = 1 , # pBuffer do
if pBuffer : sub ( i , i ) == " \n " then
x = 1
y = y + 1
output [ y ] = { " " }
else
output [ y ] [ x ] = pBuffer : sub ( i , i )
x = x + 1
2019-03-23 00:16:02 +00:00
end
end
2019-03-23 00:30:31 +00:00
return output
2019-03-23 00:16:02 +00:00
end
2019-03-23 00:30:31 +00:00
if prebuffer then
buffer = unassemble ( prebuffer )
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:30:31 +00:00
local curY = startCursorMY and math.max ( 1 , math.min ( startCursorMY - ( startY - 1 ) , # buffer ) ) or 1
local curX = startCursorMX and math.max ( 1 , math.min ( startCursorMX - ( startX - 1 ) , # buffer [ curY ] ) ) or 1
local biggestHeight = math.max ( 1 , # buffer )
local getLength = function ( )
local output = 0
for ln = 1 , # buffer do
output = output + # buffer [ ln ]
if ln ~= # buffer then -- account for newline chars
output = output + 1
2019-03-05 07:09:32 +00:00
end
end
2019-03-23 00:30:31 +00:00
return output
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
local render = function ( )
for y = startY , startY + ( biggestHeight - 1 ) do
term.setCursorPos ( startX , y )
term.write ( ( " " ) : rep ( maxLength ) )
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
term.setCursorPos ( startX , startY )
local x , y , words = startX , startY
for ln = scroll + 1 , # buffer + scroll do
if buffer [ ln ] then
words = explode ( " " , table.concat ( buffer [ ln ] ) , nil , true )
for i = 1 , # words do
if x + # words [ i ] > scr_x and y < maxLines then
x = startX
y = y + 1
2019-03-23 00:16:02 +00:00
end
2019-03-23 00:30:31 +00:00
term.setCursorPos ( x , y )
term.write ( words [ i ] )
x = x + # words [ i ]
2019-03-23 00:16:02 +00:00
end
2019-03-23 00:30:31 +00:00
term.write ( " " )
if ln ~= # buffer then
y = y + 1
x = startX
2019-03-23 00:16:02 +00:00
end
2019-03-05 22:55:36 +00:00
end
end
2019-03-23 00:30:31 +00:00
term.setCursorPos ( curX + startX - 1 , curY + startY - 1 )
biggestHeight = math.max ( # buffer , biggestHeight )
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:16:02 +00:00
2019-03-23 00:30:31 +00:00
local assemble = function ( buffer )
local output = " "
for ln = 1 , # buffer do
output = output .. table.concat ( buffer [ ln ] )
if ln ~= # buffer then
output = output .. " \n "
2019-03-05 22:55:36 +00:00
end
end
2019-03-23 00:30:31 +00:00
return output
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:16:02 +00:00
2019-03-23 00:30:31 +00:00
if history then
history [ 0 ] = assemble ( buffer )
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:30:31 +00:00
local evt , key , mx , my
local keysDown = { }
term.setCursorBlink ( true )
while true do
render ( )
evt , key , mx , my = os.pullEvent ( )
if evt == " char " then
if getLength ( ) < maxLength then
table.insert ( buffer [ curY ] , curX , key )
curX = curX + 1
if histPos == 0 and history then
history [ histPos ] = assemble ( buffer )
end
end
elseif evt == " key_up " then
keysDown [ key ] = nil
elseif evt == " mouse_click " then
if key == 1 then
if my - ( startY - 1 ) > maxLines or my < startY then
term.setCursorBlink ( false )
return assemble ( buffer ) , " mouse_click " , mx , my
2019-03-05 22:55:36 +00:00
else
2019-03-23 00:30:31 +00:00
curY = math.max ( 1 , math.min ( my - ( startY - 1 ) , # buffer ) )
curX = math.max ( 1 , math.min ( mx - ( startX - 0 ) , # buffer [ curY ] ) )
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:30:31 +00:00
end
elseif evt == " key " then
keysDown [ key ] = true
if key == keys.left then
if curX == 1 then
if curY > 1 then
curY = curY - 1
curX = # buffer [ curY ] + 1
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:30:31 +00:00
elseif curX > 1 then
curX = curX - 1
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:30:31 +00:00
elseif key == keys.right then
if curX == # buffer [ curY ] + 1 then
if curY < # buffer then
curY = curY + 1
curX = 1
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:30:31 +00:00
elseif curX < # buffer [ curY ] then
curX = curX + 1
end
elseif key == keys.up then
if history then
if histPos < # history then
histPos = histPos + 1
buffer = unassemble ( history [ histPos ] )
curY = # buffer
curX = # buffer [ curY ] + 1
2019-03-05 22:55:36 +00:00
end
else
2019-03-23 00:30:31 +00:00
if curY > 1 then
curY = curY - 1
curX = math.min ( curX , # buffer [ curY ] + 1 )
else
curX = 1
end
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:30:31 +00:00
elseif key == keys.down then
if history then
if histPos > 0 then
histPos = histPos - 1
buffer = unassemble ( history [ histPos ] )
curY = # buffer
curX = # buffer [ curY ] + 1
2019-03-05 22:55:36 +00:00
end
else
2019-03-23 00:30:31 +00:00
if curY < # buffer then
curY = curY + 1
curX = math.min ( curX , # buffer [ curY ] + 1 )
else
curX = # buffer [ curY ] + 1
2019-03-05 22:55:36 +00:00
end
end
2019-03-23 00:30:31 +00:00
elseif key == keys.enter then
if allowEnter and not ( keysDown [ keys.leftAlt ] or keysDown [ keys.rightAlt ] ) and # buffer < maxLines then
curY = curY + 1
table.insert ( buffer , curY , { } )
for i = curX , # buffer [ curY - 1 ] do
buffer [ curY ] [ # buffer [ curY ] + 1 ] = buffer [ curY - 1 ] [ i ]
buffer [ curY - 1 ] [ i ] = nil
end
curX = 1
elseif not allowEnter then
term.setCursorBlink ( false )
return assemble ( buffer ) , " key " , keys.enter
end
elseif key == keys.tab or ( key == keys.q and ( keysDown [ keys.leftAlt ] or keysDown [ keys.rightAlt ] ) ) then
term.setCursorBlink ( false )
return assemble ( buffer ) , " key " , key
elseif key == keys.backspace then
if curX > 1 then
table.remove ( buffer [ curY ] , curX - 1 )
curX = curX - 1
elseif curY > 1 then
curX = # buffer [ curY - 1 ] + 1
for i = 1 , # buffer [ curY ] do
buffer [ curY - 1 ] [ # buffer [ curY - 1 ] + 1 ] = buffer [ curY ] [ i ]
end
table.remove ( buffer , curY )
curY = curY - 1
end
elseif key == keys.delete then
if buffer [ curY ] [ curX ] then
table.remove ( buffer [ curY ] , curX )
end
end
end
end
end
2019-03-05 22:55:36 +00:00
2019-03-23 00:30:31 +00:00
local area_new_mail = function ( recipient , subject , message )
recipient = recipient or " "
subject = subject or " "
message = message or " "
local attachments = { }
sleep ( 0.05 )
local mode = " recipient "
render = function ( )
term.setTextColor ( colors.white )
term.setBackgroundColor ( colors.black )
term.clear ( )
writeHeader ( " To: " , recipient , 1 )
writeHeader ( " Subject: " , subject , 2 )
writeHeader ( " Attachments: " , " " , 3 )
for name , contents in pairs ( attachments ) do
term.write ( name .. " " )
end
term.setCursorPos ( 1 , 4 )
term.setBackgroundColor ( colors.gray )
term.setTextColor ( colors.lightGray )
term.clearLine ( )
cwrite ( " (Alt+Enter = SEND, Alt+Q = QUIT) " )
term.setTextColor ( colors.white )
term.setBackgroundColor ( colors.black )
if mode ~= " message " then
term.setCursorPos ( 1 , 5 )
write ( message )
end
end
local mx , my , evt = 1 , 1
local _mx , _my , userList
while true do
render ( )
if mode == " message " then
message , evt , _mx , _my = niftyRead ( message , 1 , 5 , mx , my , true , maximumMailLines , 512 )
elseif mode == " subject " then
subject , evt , _mx , _my = niftyRead ( subject , 10 , 2 , mx , 1 , false , 1 , 64 )
elseif mode == " recipient " then
names = client.getNames ( srv ) or names
userList = { }
for k , v in pairs ( names ) do
userList [ # userList + 1 ] = v
end
recipient , evt , _mx , _my = niftyRead ( recipient , 5 , 1 , mx , 1 , false , 1 , 24 , userList )
end
if evt == " mouse_click " then
mx , my = _mx , _my
if my == 1 then
mode = " recipient "
elseif my == 2 then
mode = " subject "
elseif my == 3 then
local newAttachment = lddfm.makeMenu ( 1 , 4 , scr_x , scr_y , " " , false , false , false , true , false , nil , true )
if newAttachment then
local name = fs.getName ( newAttachment )
if attachments [ name ] then
attachments [ name ] = nil
2019-03-05 22:55:36 +00:00
else
2019-03-23 00:30:31 +00:00
attachments [ name ] = readFile ( newAttachment )
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:30:31 +00:00
end
elseif my >= 5 then
mode = " message "
end
elseif evt == " key " then
if _mx == keys.enter or _mx == keys.tab then
if mode == " recipient " then
mode = " subject "
elseif mode == " subject " then
mode = " message "
elseif mode == " message " and _mx == keys.enter then
local recip
names = client.getNames ( srv ) or names
if tonumber ( recipient ) then
recip = tonumber ( recipient )
if not names [ recip ] then
recip = nil
end
2019-03-05 22:55:36 +00:00
else
2019-03-23 00:30:31 +00:00
recip = getNameID ( recipient )
2019-03-05 22:55:36 +00:00
end
2019-03-23 00:30:31 +00:00
if recip then
client.sendMail ( srv , recip , subject , message , attachments )
dialogueBox ( " Message sent! " , 2 )
refresh ( )
return
2019-03-05 22:55:36 +00:00
else
2019-03-23 00:30:31 +00:00
dialogueBox ( " There's no such recipient. " , 2 )
2019-03-05 22:55:36 +00:00
end
end
2019-03-23 00:30:31 +00:00
elseif _mx == keys.q then
return
end
end
end
niftyRead ( nil , 1 , 1 , nil , true )
end
2019-03-05 22:55:36 +00:00
2019-03-23 00:30:31 +00:00
local area_view_mail = function ( mailEntry )
local scroll = 0
local mail = inbox [ mailEntry ]
local render = function ( scroll )
term.setBackgroundColor ( colors.black )
term.setTextColor ( colors.lightGray )
term.clear ( )
local y
writeHeader ( " From: " , names [ mail.sender ] , 1 )
writeHeader ( " Subject: " , mail.subject , 2 )
if getTableLength ( mail.attachments ) > 0 then
writeHeader ( " Attachments: " , " " , 3 )
for name , contents in pairs ( mail.attachments ) do
term.write ( name .. " " )
2019-03-06 00:59:31 +00:00
end
2019-03-23 00:30:31 +00:00
y = 5
else
y = 4
end
term.setTextColor ( colors.gray )
term.setCursorPos ( 1 , y - 1 )
term.write ( ( " = " ) : rep ( scr_x ) )
term.setTextColor ( colors.white )
local words = { }
local lines = explode ( " \n " , mail.message , nil , true )
for i = 1 , # lines do
local inWords = explode ( " " , lines [ i ] , nil , true )
for ii = 1 , # inWords do
words [ # words + 1 ] = inWords [ ii ]
2019-03-06 00:59:31 +00:00
end
2019-03-23 00:30:31 +00:00
if i ~= # lines then
words [ # words + 1 ] = " \n "
2019-03-06 00:59:31 +00:00
end
2019-03-23 00:30:31 +00:00
end
local buffer = { " " }
for i = 1 , # words do
if words [ i ] == " \n " then
buffer [ # buffer + 1 ] = " "
elseif # buffer [ # buffer ] + # words [ i ] > scr_x then
buffer [ # buffer + 1 ] = words [ i ]
2019-03-05 07:09:32 +00:00
else
2019-03-23 00:30:31 +00:00
buffer [ # buffer ] = buffer [ # buffer ] .. words [ i ]
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
end
for i = scroll + 1 , scroll + scr_y - y do
if buffer [ i ] then
term.setCursorPos ( 1 , y )
term.write ( buffer [ i ] )
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
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 )
if getTableLength ( mail.attachments ) > 0 then
keyWrite ( " DL.Attachments " , 4 )
2019-03-06 00:59:31 +00:00
end
2019-03-23 00:30:31 +00:00
keyWrite ( " Delete " , 1 )
return # buffer
end
local downloadAttachments = function ( )
local path = fs.combine ( config.attachmentPath , names [ mail.sender ] )
for name , contents in pairs ( mail.attachments ) do
writeFile ( fs.combine ( path , name ) , contents )
end
return path
end
local barCommands = {
[ keys.q ] = { 1 , scr_y , 4 } ,
[ keys.r ] = { 6 , scr_y , 5 } ,
}
if getTableLength ( mail.attachments ) > 0 then
barCommands [ keys.a ] = { 12 , scr_y , 14 }
barCommands [ keys.d ] = { 27 , scr_y , 6 }
else
barCommands [ keys.d ] = { 12 , scr_y , 6 }
end
local evt , key , mx , my , msgHeight
while true do
msgHeight = render ( scroll )
evt , key , mx , my = os.pullEvent ( )
if evt == " key " then
if key == keys.r then
area_new_mail ( names [ mail.sender ] , " Re: " .. mail.subject , " \n \n ~~~ \n At UTC epoch " .. mail.time .. " , " .. names [ mail.sender ] .. " wrote: \n \n " .. mail.message )
elseif key == keys.d then
client.deleteMail ( srv , mailEntry )
refresh ( )
return
elseif key == keys.a and getTableLength ( mail.attachments ) > 0 then
local path = downloadAttachments ( )
dialogueBox ( " DL'd to ' " .. path .. " /' " )
elseif key == keys.q then
return " exit "
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
elseif evt == " mouse_click " then
if my == 3 and getTableLength ( mail.attachments ) > 0 then
local path = downloadAttachments ( )
dialogueBox ( " DL'd to ' " .. path .. " /' " )
else
for key , data in pairs ( barCommands ) do
if my == data [ 2 ] and mx >= data [ 1 ] and mx <= data [ 1 ] + data [ 3 ] - 1 then
os.queueEvent ( " key " , key )
break
end
end
end
elseif evt == " mouse_scroll " then
scroll = math.min ( math.max ( 0 , scroll + key ) , math.max ( 0 , msgHeight - ( scr_y - 5 ) ) )
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
end
2019-03-05 07:09:32 +00:00
end
2019-03-23 00:30:31 +00:00
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 == " refresh " then
refresh ( )
elseif res == " view_mail " then
area_view_mail ( table.unpack ( output or { } ) )
elseif res == " new_mail " then
area_new_mail ( table.unpack ( output or { } ) )
end
end
end
2019-03-04 21:10:41 +00:00
2019-03-23 00:30:31 +00:00
if isServer then
names [ yourID ] = names [ yourID ] or serverName
writeNames ( )
server.makeServer ( true )
elseif shell then
clientInterface ( )
2019-03-23 00:16:02 +00:00
end
2019-03-23 00:30:31 +00:00
return { client = client , server = server }