//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