Files
2016-03-06 20:52:14 +01:00

1239 lines
39 KiB
Plaintext

//CONTENTS
//OS Constants
//OS Kernel
//User login program
//Progsignal errors
#define ESIG_SUCCESS 0
#define ESIG_GENERIC 1
#define ESIG_NOTARGET 2
#define ESIG_BADCOMMAND 4
#define ESIG_NOUSR 8
#define ESIG_IOERR 16
#define ESIG_NOFILE 32
#define ESIG_NOWRITE 64
#define ESIG_USR1 128
#define ESIG_USR2 256
#define ESIG_USR3 512
#define ESIG_USR4 1024
#define ESIG_DATABIT 32768
#define DWAINE_COMMAND_MSG_TERM 1
#define DWAINE_COMMAND_ULOGIN 2
#define DWAINE_COMMAND_UGROUP 3
#define DWAINE_COMMAND_ULIST 4
#define DWAINE_COMMAND_UMSG 5
#define DWAINE_COMMAND_UINPUT 6
#define DWAINE_COMMAND_DMSG 7
#define DWAINE_COMMAND_DLIST 8
#define DWAINE_COMMAND_DGET 9
#define DWAINE_COMMAND_DSCAN 10
#define DWAINE_COMMAND_EXIT 11
#define DWAINE_COMMAND_TSPAWN 12
#define DWAINE_COMMAND_TKILL 13
#define DWAINE_COMMAND_TLIST 14
#define DWAINE_COMMAND_TEXIT 15
#define DWAINE_COMMAND_FGET 16
#define DWAINE_COMMAND_FKILL 17
#define DWAINE_COMMAND_FMODE 18
#define DWAINE_COMMAND_FOWNER 19
#define DWAINE_COMMAND_FWRITE 20
#define DWAINE_COMMAND_CONFGET 21
#define DWAINE_COMMAND_MOUNT 22
#define DWAINE_COMMAND_RECVFILE 23
#define DWAINE_COMMAND_BREAK 24
#define DWAINE_COMMAND_REPLY 30
var/global/list/generic_exit_list = list("command"=DWAINE_COMMAND_EXIT)
#define mainframe_prog_exit signal_program(1, generic_exit_list)
#define setup_filepath_users "/usr"
#define setup_filepath_users_home "/home"
#define setup_filepath_drivers "/dev" //Device file zone
#define setup_filepath_drivers_proto "/sys/drvr" //Device file prototypes, named after the pnet id of their respective device (Sans "pnet_" prefix)
#define setup_filepath_volumes "/mnt" //Mounted filesystems, i.e. databanks.
#define setup_filepath_system "/sys"
#define setup_filepath_config "/conf"
#define setup_filepath_commands "/bin"
#define setup_filepath_process "/proc"
//Kernel
/datum/computer/file/mainframe_program/os/kernel
name = "Kernel"
size = 16
var/tmp/list/users
var/tmp/user_max = 0
var/tmp/ping_accept = 0
var/tmp/rescan_timer = 60
var/tmp/datum/computer/folder/sysfolder = null
var/tmp/list/processing_drivers = list()
var/setup_progname_hello = "login"
var/setup_progname_shell = "msh"
var/setup_progname_init = "init"
disposing()
users = null
if (processing_drivers)
processing_drivers.len = 0
processing_drivers = null
sysfolder = null
if (master && master.os == src)
master.os = null
..()
initialize()
if(..())
return
users = list()
src.processing_drivers.len = 0
sysfolder = parse_directory(setup_filepath_system, src.holder.root, 1)
if (!sysfolder)
user_max = 0
return
sysfolder.metadata["permission"] = COMP_HIDDEN
user_max = max( round((src.holder.file_amount-128)/32), 0)
if(src.initialize_drivers() || src.initialize_users())
user_max = 0 //These only return 1 if we can't start up properly, so...
return
src.ping_accept = 4
src.master.timeout = 1
src.master.timeout_alert = 0
spawn(5)
src.master.post_status("ping","data","DWAINE","net","[src.master.net_number]")
//Run "init" program, if present.
master.run_program(get_file_name(setup_progname_init, sysfolder), null, src)
return
term_input(var/data, var/termid, var/datum/computer/file/file, isBreak) //Input from any terminal, be it user or device.
if (..())
return
if (termid in src.users)
var/datum/mainframe2_user_data/the_user = src.users[termid]
if (!istype(the_user))
login_user(termid, "TEMP")
return
if (the_user.current_prog)
if (isBreak)
the_user.current_prog.receive_progsignal(1, list("command"=DWAINE_COMMAND_BREAK, "user"=termid))
return
if (file)
the_user.current_prog.receive_progsignal(1, list("command"=DWAINE_COMMAND_RECVFILE, "user"=termid), file)
else
the_user.current_prog.input_text(data)
else
if (isBreak)
the_user.current_prog.receive_progsignal(1, list("command"=DWAINE_COMMAND_BREAK, "user"=termid))
return
if (the_user.full_user)
the_user.current_prog = master.run_program(get_file_name(setup_progname_shell, sysfolder), the_user, src)
else
the_user.current_prog = master.run_program(get_file_name(setup_progname_hello, sysfolder), the_user, src)
return
var/datum/computer/file/mainframe_program/driver/D = parse_file_directory("[setup_filepath_drivers]/[termid]", src.holder.root, 0)
if (istype(D))
D.terminal_input(data, file)
return
return
//Called by the mainframe object when a new terminal connection datum is ready for us to handle.
new_connection(datum/terminal_connection/conn, datum/computer/file/connect_file)
if (!conn)
return
var/term_type = lowertext(conn.term_type)
if (dd_hasprefix(term_type , "pnet_"))
term_type = copytext(term_type, 6)
//if (copytext(term_type, 4) == "_terminal")
if (term_type == "hui_terminal")
if (!(conn.net_id in src.users) || !istype(src.users[conn.net_id], /datum/mainframe2_user_data))
//User does not yet exist, set them up as temporary so they can log in.
login_temp_user(conn.net_id, connect_file)
else //User already exists.
var/datum/mainframe2_user_data/the_user = src.users[conn.net_id]
if (!the_user.current_prog)
if (the_user.full_user) //They are logged in, with nothing currently running for them. Send them to the shell.
the_user.current_prog = master.run_program(get_file_name(setup_progname_shell, sysfolder, src))
else //They already exist, but they never logged in! Give them a chance to do that now.
the_user.current_prog = master.run_program(get_file_name(setup_progname_hello, sysfolder, src))
return
//Find relevant directories for device initialization...
var/datum/computer/folder/pF = parse_directory(setup_filepath_drivers_proto, src.holder.root, 1)
var/datum/computer/folder/dF = parse_directory(setup_filepath_drivers, src.holder.root, 1)
if (!pF || !dF)
return
//See if we have a known device prototype...
var/datum/computer/file/mainframe_program/driver/D = get_file_name(term_type, pF)
if (!istype(D)) //We do not! What a pity.
return
//Now build our working driver instance in dF.
D = D.copy_file()
D.name = conn.net_id
D.termtag = term_type
if (get_file_name(D.name, dF) || !dF.add_file(D))
//qdel(D)
D.dispose()
return
D.master = src.master
if (D.setup_processes) //The driver either processes, or wants to make use of the processing list for communication.
if(!(D in src.processing_drivers))
src.processing_drivers += D
if(!(D in src.master.processing))
var/success = 0
for (var/x = 1, x <= src.master.processing.len, x++)
if (src.master.processing[x] != null)
continue
src.master.processing[x] = D
D.progid = x
success = 1
break
if (!success)
src.master.processing.len++
src.master.processing[src.master.processing.len]= D
D.progid = src.master.processing.len
D.initialize(connect_file)
return
//Called by mainframe object when one of the terminal connection datums is about to be deleted.
closed_connection(datum/terminal_connection/conn)
if (!conn)
return
if (conn.net_id in src.users)
if (istype(src.users[conn.net_id], /datum/mainframe2_user_data))
var/datum/mainframe2_user_data/the_user = src.users[conn.net_id]
logout_user(the_user, 1)
return
var/datum/computer/file/F = parse_file_directory("[setup_filepath_drivers]/[conn.net_id]", src.holder.root, 0)
if (F)
//qdel(F)
F.dispose()
return
ping_reply(var/senderid,var/sendertype)
if(..() || !ping_accept)
return
if (dd_hasprefix(sendertype, "pnet_"))
sendertype = copytext(sendertype, 6)
if( !(senderid in master.terminals) && (get_file_name(sendertype, parse_directory(setup_filepath_drivers_proto, src.holder.root, 0))) )
if(master.stat & (NOPOWER|BROKEN|MAINT))
return
if(!(holder in src.master.contents))
return
spawn(rand(1,4))
src.master.post_status(senderid, "command", "term_connect", "device", master.device_tag)
return
return
//Receive a signal sent by another program or driver on the mainframe.
//This is where system calls are interpreted.
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/file)
if (!src.master || (sendid == src.progid))
return ESIG_GENERIC
if (!data["command"])
return ESIG_GENERIC
switch (data["command"])
if (DWAINE_COMMAND_MSG_TERM)
if (!data["term"])
return ESIG_NOTARGET
if (file)
return file_term(file, data["term"], data["data"])
else
//boutput(world, "message term of \[[data["data"]]] to \[[data["term"]]]")
return message_term(data["data"], data["term"], data["render"])
if (DWAINE_COMMAND_ULOGIN)
if (!sendid)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!caller || !data["name"])
return ESIG_GENERIC
if (data["name"] == "TEMP" && data["data"])
return (login_temp_user(data["data"], null, caller)) ? ESIG_GENERIC : ESIG_SUCCESS
else
if (!caller.useracc)
return ESIG_NOUSR
if (login_user(caller.useracc, data["name"], (data["sysop"] == 1), (data["service"] != 1)))
return ESIG_GENERIC
return ESIG_SUCCESS
if (DWAINE_COMMAND_UGROUP) //Manipulate the group of the caller's user account to ["group"]
if (!sendid)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!caller || !isnum(data["group"]))
return ESIG_GENERIC
if (!caller.useracc || !caller.useracc.user_file)
return ESIG_NOUSR
caller.useracc.user_file.fields["group"] = min(255, max(data["group"], 0))
return ESIG_SUCCESS
if (DWAINE_COMMAND_ULIST) //List current users.
var/list/ulist = list()
for (var/uid in src.users)
var/datum/mainframe2_user_data/udat = src.users[uid]
if (!istype(udat) || !istype(udat.user_file))
continue
var/groupnum = udat.user_file.fields["group"]
if (!isnum(groupnum))
groupnum = "N"
var/logtime = udat.user_file.fields["logtime"]
if (isnum(logtime))
logtime = time2text(logtime, "hh:mm")
else
logtime = "??:??"
ulist[uid] = "[logtime] [groupnum] [udat.user_file.fields["name"]]"
if (ulist.len)
return ulist
else
return ESIG_GENERIC
if (DWAINE_COMMAND_UMSG) //Send message to a user terminal, and ONLY user terminals (In contrast with msg_term)
var/uid = data["term"]
var/message = data["data"]
if (!ckeyEx(message))
return ESIG_GENERIC
if (!uid)
return ESIG_NOTARGET
var/datum/mainframe2_user_data/target = src.users[uid]
if (!istype(target))
for (var/n in src.users)
var/datum/mainframe2_user_data/testTarget = src.users[n]
if (testTarget && testTarget.user_file && (lowertext(testTarget.user_file.fields["name"]) == uid))
target = testTarget
uid = n
break
if (!istype(target))
return ESIG_NOTARGET
else if (!istype(target.user_file))
return ESIG_NOTARGET
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!caller || !caller.useracc)
return ESIG_NOUSR
if (caller.useracc == target)
return ESIG_NOTARGET
var/senderName = caller.useracc.user_name
if (!senderName)
return ESIG_NOUSR
if (target.user_file.fields["accept_msg"] == "1")
message_term("MSG from \[[senderName]]: [message]", uid, "multiline")
return ESIG_SUCCESS
else
return ESIG_IOERR
return ESIG_GENERIC
if (DWAINE_COMMAND_UINPUT) //Alternate path for user input
. = ckey(data["term"])
if (. in src.users)
var/datum/mainframe2_user_data/the_user = src.users[.]
if (!istype(the_user))
login_user(., "TEMP")
return ESIG_SUCCESS
if (the_user.current_prog)
if (file)
the_user.current_prog.receive_progsignal(1, list("command"=DWAINE_COMMAND_RECVFILE, "user"=.), file)
else
the_user.current_prog.input_text(data["data"])
else
if (the_user.full_user)
the_user.current_prog = master.run_program(get_file_name(setup_progname_shell, sysfolder), the_user, src)
else
the_user.current_prog = master.run_program(get_file_name(setup_progname_hello, sysfolder), the_user, src)
return ESIG_SUCCESS
return ESIG_NOUSR
if (DWAINE_COMMAND_DMSG) //Send message to processing driver.
var/driver_id = data["target"]
if (data["mode"] == 1)
for (var/datum/computer/file/mainframe_program/driver/D in processing_drivers)
if (cmptext("[driver_id]",D.name))
data["command"] = data["dcommand"]
data["target"] = data["dtarget"]
return D.receive_progsignal(sendid, data, file)
return ESIG_NOTARGET
if (!isnum(driver_id) || driver_id < 1 || driver_id > src.processing_drivers.len)
return ESIG_NOTARGET
var/datum/computer/file/mainframe_program/driver/D = src.processing_drivers[driver_id]
if (istype(D))
data["command"] = data["dcommand"]
data["target"] = data["dtarget"]
return D.receive_progsignal(sendid, data, file)
return ESIG_NOTARGET
if (DWAINE_COMMAND_DLIST) //List processing drivers.
var/list/dlist = list()
var/target_tag = lowertext(data["dtag"])
var/omitWrongTags = (data["mode"] == 1 ? 1 : 0)
for (var/x = 1, x <= processing_drivers.len, x++)
if (target_tag && !omitWrongTags)
dlist.len = x
var/datum/computer/file/mainframe_program/driver/D = processing_drivers[x]
if (istype(D))
if (D.disposed)
processing_drivers[x] = null
continue
if (target_tag && omitWrongTags)
if(target_tag != D.termtag)
continue
dlist.Add("[D.name]")
dlist["[D.name]"] = D.status
else
if (target_tag && target_tag != D.termtag)
continue
dlist[x] = "[D.name]"
dlist[dlist[x]] = D.status
else if (!omitWrongTags)
if (x > dlist.len)
break
dlist[x] = ""
if (dlist.len)
return dlist
else
return ESIG_GENERIC
if (DWAINE_COMMAND_DGET) //Get ID of processing driver.
var/target_tag = lowertext(data["dtag"])
if (!target_tag)
target_tag = lowertext(data["dnetid"])
if (!target_tag)
return ESIG_NOTARGET
for (var/x = 1, x <= processing_drivers.len, x++)
var/datum/computer/file/mainframe_program/driver/D = processing_drivers[x]
if (istype(D) && (D.termtag == target_tag || D.name == target_tag))
if (D.disposed)
processing_drivers[x] = null
continue
return (x | ESIG_DATABIT)
return ESIG_NOTARGET
if (DWAINE_COMMAND_DSCAN) //Instruct the mainframe to recheck for devices now instead of waiting for the full timeout.
if (src.ping_accept)
return ESIG_GENERIC
src.master.reconnect_all_devices()
src.master.timeout_alert = 0
src.master.timeout = 1
src.ping_accept = 5
spawn(20)
src.master.post_status("ping","data","DWAINE","net","[src.master.net_number]")
return ESIG_SUCCESS
if (DWAINE_COMMAND_EXIT)
if (!sendid)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/quitter = master.processing[sendid]
if (!quitter || quitter == src)
return ESIG_GENERIC
if (!quitter.useracc)
quitter.handle_quit()
return ESIG_NOUSR
var/datum/mainframe2_user_data/quituser = quitter.useracc
var/datum/computer/file/mainframe_program/shellbase = get_file_name(setup_progname_shell, sysfolder)
var/shellexit = (shellbase && shellbase.type == quitter.type)
var/datum/computer/file/mainframe_program/quitparent = quitter.parent_task
quitter.handle_quit()
if (istype(quitparent) && (quitparent != src) && !istype(quitparent, /datum/computer/file/mainframe_program/driver/mountable/radio)) //Hello, this last istype() is a dirty hack.
quituser.current_prog = quitparent
quitparent.useracc = quituser
quitparent.receive_progsignal(1, list("command"=DWAINE_COMMAND_TEXIT))
else if (shellexit && quituser) //Shell should only exit if things go really wrong or the user logs out.
var/quituser_id = quituser.user_id
logout_user(quituser, 0)
login_temp_user(quituser_id) //As they didn't disconnect the the terminal, we should present a new login screen there.
else
src.master.run_program(shellbase, quituser, quitparent ? quitparent : src)
return ESIG_SUCCESS
if (DWAINE_COMMAND_TSPAWN) //Spawn task
if (!data["path"])
return ESIG_NOTARGET
if (!sendid)
return ESIG_GENERIC
var/pass_user = (data["passusr"] == 1)
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!caller)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/task_model = parse_file_directory(data["path"], src.holder.root, 0)
if (!task_model || !task_model.executable)
return ESIG_NOTARGET
task_model = src.master.run_program(task_model, (pass_user ? caller.useracc : null), caller, data["args"])
if (!task_model)
return ESIG_GENERIC
return task_model
if (DWAINE_COMMAND_TKILL) //Kill a child task of the calling program.
if (!sendid)
return ESIG_NOTARGET
var/target_id = data["target"]
if (!isnum(target_id) || target_id < 0 || target_id > master.processing.len)
return ESIG_NOTARGET
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!caller)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/target_task = master.processing[target_id]
if (!target_task)
return ESIG_SUCCESS
if (target_task.parent_task != caller)
return ESIG_GENERIC
var/datum/mainframe2_user_data/target_user = target_task.useracc
target_task.handle_quit()
if (target_user && (!caller.useracc || target_user.current_prog == caller))
target_user.current_prog = caller
caller.useracc = target_user
return ESIG_SUCCESS
if (DWAINE_COMMAND_TLIST) //List all child tasks of the calling program.
if (!sendid)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!caller)
return ESIG_GENERIC
. = list()
for (var/x = 1, x <= master.processing.len, x++)
var/datum/computer/file/mainframe_program/MP = master.processing[x]
if (MP && MP.parent_task == caller)
.[x] = MP
else
.[x] = null
return .
if (DWAINE_COMMAND_FGET) //Return the computer datum at the provided path, if it exists.
//boutput(world, "entering fget with path \"[data["path"]]\"")
if (!sendid)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!data["path"] || !caller)
return ESIG_NOTARGET
. = parse_datum_directory(data["path"], src.holder.root, 0, caller.useracc)
if (.)
//boutput(world, "F is [F.name], a [istype(F, /datum/computer/file) ? "FILE" : "FOLDER"]")
return .
else
//boutput(world, "a bad F")
return ESIG_NOFILE
if (DWAINE_COMMAND_FKILL) //Delete the computer datum at the provided path, if possible.
if (!sendid)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!data["path"] || !caller)
return ESIG_NOTARGET
var/datum/mainframe2_user_data/the_user = caller.useracc
var/datum/computer/F = parse_datum_directory(data["path"], src.holder.root, 0, the_user)
if (F && (F.holding_folder != master.runfolder && F != master.runfolder && F != src.holder.root) && (!the_user || check_mode_permission(F, the_user)))
if (istype(F.holding_folder, /datum/computer/file/mainframe_program/driver/mountable))
F.holding_folder.remove_file(F)
return ESIG_SUCCESS
// qdel(F)
F.dispose()
return ESIG_SUCCESS
else
return ESIG_NOFILE
if (DWAINE_COMMAND_FMODE) //Adjust the permissions of the file at the provided path, if possible.
if (!sendid)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!data["path"] || !caller)
return ESIG_NOTARGET
if (!isnum(data["permission"]))
return ESIG_GENERIC
var/datum/computer/target_datum = parse_datum_directory(data["path"], src.holder.root, 0, caller.useracc)
if (!istype(target_datum))
return ESIG_NOFILE
if (caller.useracc && !check_mode_permission(target_datum, caller.useracc))
return ESIG_GENERIC
change_metadata(target_datum, "permission", data["permission"])
return ESIG_SUCCESS
if (DWAINE_COMMAND_FOWNER)
if (!sendid)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!data["path"] || !caller)
return ESIG_NOTARGET
if (!isnum(data["group"]) && !data["owner"])
return ESIG_GENERIC
var/datum/computer/target_datum = parse_datum_directory(data["path"], src.holder.root, 0, caller.useracc)
if (!istype(target_datum))
return ESIG_NOFILE
if (caller.useracc && !check_mode_permission(target_datum, caller.useracc))
return ESIG_GENERIC
if (data["owner"])
change_metadata(target_datum, "owner", copytext(data["owner"], 1, 16))
if (isnum(data["group"]))
change_metadata(target_datum, "group", min(max(0, data["group"]), 255))
return ESIG_SUCCESS
if (DWAINE_COMMAND_FWRITE) //Write a provided file to the provided path. If it already exists and ["replace"] is 1, overwrite it. If ["append"] is 1, add to it.
if (!sendid)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/caller = master.processing[sendid]
if (!data["path"] || !caller || !file)
return ESIG_NOTARGET
if (is_name_invalid(file.name))
return ESIG_GENERIC
var/datum/mainframe2_user_data/the_user = caller.useracc
var/create_path = (data["mkdir"] == 1)
var/datum/computer/folder/destination = parse_directory(data["path"], src.holder.root, create_path, the_user)
if (!destination || destination == master.runfolder)
return ESIG_NOTARGET
var/datum/computer/file/record/destfile = get_computer_datum(file.name, destination)
var/delete_dest = 0
if (destfile)
if (istype(destfile, /datum/computer/folder))
destination = destfile
if (istype(destination, /datum/computer/folder/link) && destination:target)
if (the_user && !check_write_permission(destination:target, the_user))
return ESIG_NOWRITE
else
if (the_user && !check_write_permission(destination, the_user))
return ESIG_NOWRITE
//We can append if instructed (And currently just if both files are records).
if (data["append"] == 1 && (!the_user || check_write_permission(destfile, the_user)) && (istype(destfile) && istype(file, /datum/computer/file/record)))
file:fields = destfile.fields + file:fields
delete_dest = 1
//We could also instead just overwrite the file.
else if (data["replace"] == 1 && (!the_user || check_mode_permission(destfile, the_user)))
delete_dest = 1
else if (istype(destfile, /datum/computer/file))
return ESIG_GENERIC
if (!destination.can_add_file(file, the_user))
return ESIG_GENERIC
if (the_user && !check_write_permission(destination, the_user))
return ESIG_NOWRITE
if (delete_dest && destfile)
//qdel(destfile)
destfile.dispose()
destination.add_file(file, the_user)
return ESIG_SUCCESS
if (DWAINE_COMMAND_CONFGET)
if (!data["fname"])
return ESIG_NOTARGET
var/datum/computer/folder/confDir = parse_directory(setup_filepath_config, src.holder.root, 0)
if (!confDir)
return ESIG_NOTARGET
var/datum/computer/file/F = get_file_name(data["fname"], confDir)
if (F)
return F
else
return ESIG_NOFILE
if (DWAINE_COMMAND_MOUNT)
if (!data["id"])
return ESIG_NOTARGET
var/datum/computer/file/mainframe_program/driver/mountable/Mcheck = parse_file_directory("[setup_filepath_drivers]/_[data["id"]]", src.holder.root, 0)
if (!istype(Mcheck))
return ESIG_NOTARGET
var/datum/computer/folder/mountfolder = parse_directory(setup_filepath_volumes, src.holder.root, 1)
if (!istype(mountfolder))
return ESIG_NOTARGET
var/datum/computer/folder/mountpoint/mountpoint = get_computer_datum("_[data["id"]]", mountfolder)
if (!istype(mountpoint))
if (istype(mountpoint, /datum/computer)) //Name is taken B(
return ESIG_GENERIC
else
//qdel(mountpoint)
mountpoint.dispose()
mountpoint = new /datum/computer/folder/mountpoint( Mcheck )
mountpoint.name = "_[data["id"]]"
if (!mountfolder.add_file(mountpoint))
//qdel(mountpoint)
mountpoint.dispose()
return ESIG_GENERIC
if (data["link"])
var/datum/computer/folder/link/symlink = get_computer_datum(data["link"], mountfolder)
if (istype(symlink) || (!istype(symlink, /datum/computer)) )
//qdel(symlink)
if (symlink)
symlink.dispose()
symlink = new /datum/computer/folder/link( mountpoint )
symlink.name = data["link"]
if (!mountfolder.add_file(symlink))
//qdel(symlink)
symlink.dispose()
mountpoint.metadata["permission"] = Mcheck.default_permission
mountpoint.metadata["group"] = 1
mountpoint.metadata["owner"] = "Nobody"
return ESIG_SUCCESS
else
return ESIG_BADCOMMAND
return ESIG_SUCCESS
process()
if (..())
return
if (src.ping_accept)
src.ping_accept--
if (src.rescan_timer)
src.rescan_timer--
if (src.rescan_timer <= 0)
src.rescan_timer = initial(src.rescan_timer)
src.ping_accept = 4
spawn(1)
src.master.post_status("ping","data","DWAINE","net","[src.master.net_number]")
return
proc
initialize_users()
for (var/i in src.users) //Clear out the user list...
var/datum/mainframe2_user_data/D = src.users[i]
//qdel(D)
D.dispose()
users.len = 0
//User data folder.
var/datum/computer/folder/uF = parse_directory(setup_filepath_users, src.holder.root, 1)
//User home folder
var/datum/computer/folder/hF = parse_directory(setup_filepath_users_home, src.holder.root, 1)
if (!uF || !hF)
return 1
uF.metadata["permission"] = COMP_HIDDEN
//To-do: Kinda merge this and stuff.
for (var/i in master.terminals)
var/datum/terminal_connection/conn = master.terminals[i]
if(!istype(conn) || conn.term_type != "HUI_TERMINAL")
continue
//src.users += conn.net_id
login_temp_user(conn.net_id)
for (var/datum/computer/file/record/uRec in uF.contents)
if (isnull(uRec.fields["name"]) || isnull(uRec.fields["id"]) || isnull(uRec.fields["group"])) //This record isn't a valid user file!
//qdel(uRec) //Clean house!!
uRec.dispose()
continue
//Make sure our PRECISE NAME SCHEME is preserved!
if (!dd_hassuffix(uRec.fields["id"]))
if ( isnull(get_file_name("usr[uRec.fields["id"]]", uF)) )
uRec.name = "usr[uRec.fields["id"]]"
else
//qdel(uRec)
uRec.dispose()
continue
//Now to create a home directory for this user
var/datum/computer/folder/new_home = get_folder_name("usr[uRec.fields["name"]]", hF)
if (istype(new_home))
return 0
new_home = new /datum/computer/folder( )
new_home.name = "usr[uRec.fields["name"]]"
new_home.metadata["owner"] = uRec.fields["name"]
uRec.metadata["owner"] = uRec.fields["name"]
new_home.metadata["permission"] = COMP_ROWNER|COMP_WOWNER|COMP_DOWNER
uRec.metadata["permission"] = COMP_ROWNER|COMP_WOWNER
if (!hF.add_file(new_home))
//qdel(new_home)
new_home.dispose()
continue
return 0
login_temp_user(var/user_netid, var/datum/computer/file/record/login_record, var/datum/computer/file/mainframe_program/caller_override)
if (users.len >= user_max)
return 1
if (!user_netid)
return 1
var/datum/computer/file/mainframe_program/helloprog = get_file_name(setup_progname_hello, sysfolder)
if (!istype(helloprog))
return 1
var/datum/mainframe2_user_data/new_user = new /datum/mainframe2_user_data( )
new_user.user_name = "TEMP"
new_user.user_id = user_netid
//new_user.user_file = uRec
users[user_netid] = new_user
if (istype(login_record) && login_record.fields && login_record.fields["registered"] && login_record.fields["assignment"])
if (login_user(new_user, login_record.fields["registered"], 0) != 1)
var/datum/computer/file/mainframe_program/shellbase = get_file_name(setup_progname_shell, sysfolder)
if (istype(shellbase))
master.run_program(shellbase, new_user, istype(caller_override) ? caller_override : src)
return 0
helloprog = master.run_program(helloprog, new_user, istype(caller_override) ? caller_override : src)
if (!istype(helloprog))
return 1
return 0
login_user(var/datum/mainframe2_user_data/account, var/user_name, var/sysop = 0, var/interactive = 1)
if (!account || account.full_user || !user_name)
return 1
//User data folder.
var/datum/computer/folder/uF = parse_directory(setup_filepath_users, src.holder.root, 1)
//User home folder
var/datum/computer/folder/hF = parse_directory(setup_filepath_users_home, src.holder.root, 1)
if (!uF || !hF || !sysfolder)
return 1
user_name = format_username(user_name)
uF.metadata["permission"] = COMP_HIDDEN
hF.metadata["permission"] = COMP_ROWNER|COMP_RGROUP|COMP_ROTHER
var/name_attempt = 0
var/attemptedname = null
var/datum/computer/file/record/uRec = null
while (name_attempt < 10)
attemptedname = "usr[user_name][name_attempt]"
if (length(attemptedname) > 16)
attemptedname = copytext(attemptedname, 1, 15) + "[name_attempt]"
var/datum/computer/file/record/check = get_computer_datum(attemptedname, uF)
if (check)
if (!interactive) //Prevent a billion duplicate copies from a service terminal reconnecting
check.dispose()
else
name_attempt++
continue
uRec = new /datum/computer/file/record(src)
uRec.name = attemptedname
if (get_computer_datum(uRec.name, uF))
//qdel(uRec)
uRec.dispose()
name_attempt++
continue
if (!uF.add_file(uRec))
//qdel(uRec)
uRec.dispose()
return 1
break
if (!uRec)
return 1
user_name = "[user_name][name_attempt]"
account.user_name = user_name
account.user_file = uRec
account.user_file_folder = uRec.holding_folder
account.user_filename = uRec.name
account.full_user = 1
uRec.fields["name"] = user_name
uRec.fields["id"] = account.user_id
uRec.fields["group"] = !sysop
uRec.fields["logtime"] = world.realtime
uRec.fields["accept_msg"] = "1"
uRec.metadata["owner"] = uRec.fields["name"]
uRec.metadata["permission"] = COMP_ROWNER|COMP_WOWNER
//Now to create a home directory for the user
if (interactive)
var/datum/computer/folder/new_home = get_computer_datum(attemptedname, hF)
if (!istype(new_home))
new_home = new /datum/computer/folder( )
new_home.name = attemptedname
new_home.metadata["owner"] = uRec.fields["name"]
new_home.metadata["permission"] = COMP_ROWNER|COMP_WOWNER|COMP_DOWNER
if (!hF.add_file(new_home))
//qdel(new_home)
new_home.dispose()
return 1
/*
helloprog = master.run_program(helloprog, account)
if (!istype(helloprog))
return 1
*/
return 0
logout_user(var/datum/mainframe2_user_data/the_user, disconnect = 0)
if (!the_user)
return 1
if (disconnect) //The terminal device is no longer connected, so no need to wait for a new login from them.
src.users -= the_user.user_id
if (the_user.current_prog)
the_user.current_prog.handle_quit()
if (the_user.user_file)
//qdel(the_user.user_file)
the_user.user_file.dispose()
the_user.dispose()
return 0
initialize_drivers()
//Active driver folder
var/datum/computer/folder/dF = parse_directory(setup_filepath_drivers, src.holder.root, 1)
//Driver prototype folder
var/datum/computer/folder/pF = parse_directory(setup_filepath_drivers_proto, src.holder.root, 1)
if (!dF || !pF)
return 1
dF.metadata["permission"] = COMP_HIDDEN
//Might as well clear out any active drivers, they might have out of date information or something.
for (var/datum/computer/file/mainframe_program/driver/D in dF.contents)
//qdel(D)
D.dispose()
. = 0
for (var/datum/computer/file/mainframe_program/driver/special_driver in pF.contents)
if (!cmptext(copytext(special_driver.name, 1, 5), "int_"))
continue
special_driver = special_driver.copy_file()
var/newtag = special_driver.name
special_driver.name = "000000[. > 9 ? .++ : "0[.++]"]"
special_driver.master = src.master
special_driver.termtag = copytext(newtag, 5)
if (!dF.add_file(special_driver))
special_driver.dispose()
else
if (special_driver.setup_processes)
if (!(special_driver in src.processing_drivers))
src.processing_drivers += special_driver
if(!(special_driver in src.master.processing))
var/success = 0
for (var/x = 1, x <= src.master.processing.len, x++)
if (src.master.processing[x] != null)
continue
src.master.processing[x] = special_driver
special_driver.progid = x
success = 1
break
if (!success)
src.master.processing += special_driver
special_driver.progid = src.master.processing.len
special_driver.initialize()
/*
//See if there's a user terminal driver to set up
var/datum/computer/file/mainframe_program/driver/hui_driver = get_file_name("hui_terminal", pF)
if (istype(hui_driver))
hui_driver = hui_driver.copy_file()
hui_driver.name = "00000000"
hui_driver.termtag = "hui_terminal"
hui_driver.master = src.master
if (!dF.add_file(hui_driver))
hui_driver.dispose()
else
if (hui_driver.setup_processes)
if (!(hui_driver in src.processing_drivers))
src.processing_drivers += hui_driver
if(!(hui_driver in src.master.processing))
var/success = 0
for (var/x = 1, x <= src.master.processing.len, x++)
if (src.master.processing[x] != null)
continue
src.master.processing[x] = hui_driver
hui_driver.progid = x
success = 1
break
if (!success)
src.master.processing += hui_driver
hui_driver.progid = src.master.processing.len
hui_driver.initialize()
*/
//Iterate through current devices and use that to make some active device files.
for (var/i in src.master.terminals)
var/datum/terminal_connection/TC = src.master.terminals[i]
if (!istype(TC))
continue
if (TC.term_type == "HUI_TERMINAL")
continue
var/TCtype = lowertext(TC.term_type)
if (copytext(TCtype, 1, 6) == "pnet_")
TCtype = copytext(TCtype,6)
var/datum/computer/file/mainframe_program/driver/newdriver = get_file_name(TCtype, pF)
if (!istype(newdriver))
continue
newdriver = newdriver.copy_file()
newdriver.name = i
newdriver.termtag = TCtype
newdriver.master = src.master
newdriver.initialized = 1
if (!dF.add_file(newdriver))
//qdel(newdriver)
newdriver.dispose()
continue
if (newdriver.setup_processes)
if (!(newdriver in src.processing_drivers))
src.processing_drivers += newdriver
if(!(newdriver in src.master.processing))
var/success = 0
for (var/x = 1, x <= src.master.processing.len, x++)
if (src.master.processing[x] != null)
continue
src.master.processing[x] = newdriver
newdriver.progid = x
success = 1
break
if (!success)
src.master.processing += newdriver
newdriver.progid = src.master.processing.len
newdriver.initialize()
return 0
is_sysop(var/datum/mainframe2_user_data/udat)
if (!udat || !udat.user_file)
return 0
if (udat.user_file.fields["group"] != 0)
return 0
return 1
change_metadata(var/datum/computer/file/file, var/field, var/newval)
if (!field || !file)
return 0
if (istype(file.holding_folder, /datum/computer/file/mainframe_program/driver/mountable))
var/datum/computer/file/mainframe_program/driver/mountable/M = file.holding_folder
return M.change_metadata(file, field, newval)
file.metadata[field] = newval
return 1
message_all_users(var/message, var/senderName, var/ignore_user_file_setting)
if (!senderName)
senderName = "System"
for (var/user_id in src.users)
var/datum/mainframe2_user_data/target = src.users[user_id]
if (!istype(target))
continue
if (!istype(target.user_file))
continue
if (ignore_user_file_setting || target.user_file.fields["accept_msg"] == "1")
message_term("MSG from \[[senderName]]: [message]", user_id, "multiline")
return
//User login manager
/datum/computer/file/mainframe_program/login
name = "Login"
size = 2
executable = 0
var/motd = "Welcome to DWAINE System VI!|nCopyright 2050 Thinktronic Systems, LTD."
var/setup_filename_motd = "motd"
initialize()
if(..())
return
var/datum/computer/file/record/R = signal_program(1, list("command"=DWAINE_COMMAND_CONFGET,"fname"=setup_filename_motd))
if (istype(R))
src.motd = ""
var/imax = min(5, R.fields.len)
for (var/i = 1, i <= imax, i++)
src.motd += (R.fields[i] + (i < imax ? "|n" : null))
src.motd = copytext(src.motd, 1, 255)
else
src.motd = initial(src.motd)
message_user("[src.motd]|nPlease enter card and \"term_login\"", "multiline")
return
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/file)
if (..() || (data["command"] != DWAINE_COMMAND_RECVFILE) || !istype(file, /datum/computer/file/record))
return ESIG_GENERIC
if (!src.useracc)
return ESIG_NOUSR
var/datum/computer/file/record/usdat = file
if (!usdat.fields["registered"] || !usdat.fields["assignment"])
return ESIG_GENERIC
if (signal_program(1, list("command"=DWAINE_COMMAND_ULOGIN, "name"=usdat.fields["registered"])) != ESIG_SUCCESS)
message_user("Error: Login failure. Please try again.")
return ESIG_GENERIC
mainframe_prog_exit
return
#undef setup_filepath_users
#undef setup_filepath_users_home
#undef setup_filepath_drivers
#undef setup_filepath_drivers_proto
#undef setup_filepath_volumes
#undef setup_filepath_system
#undef setup_filepath_config
#undef setup_filepath_commands
#undef setup_filepath_process