Initial Commit

This commit is contained in:
Tobba
2016-03-06 20:52:14 +01:00
commit b181d0b552
4325 changed files with 579453 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,655 @@
//CONTENTS:
//Mainframe program parent type
//Mainframe user account datum
/*
* Mainframe Software
*/
/datum/computer/file/mainframe_program
name = "mainframe program"
extension = "MPG"
var/obj/machinery/networked/mainframe/master = null
var/executable = 1
var/needs_holder = 1
var/tmp/datum/computer/file/mainframe_program/parent_task = null
var/tmp/progid = 0
var/tmp/initialized = 0
var/tmp/datum/mainframe2_user_data/useracc = null
os
name = "Base OS"
size = 16
extension = "SYS"
executable = 0
var/tmp/setup_string = null
proc
//Called by the mainframe when a new terminal connection is made so as to alert the OS
new_connection(datum/terminal_connection/conn)
return
//Called by the mainframe upon termination of a connection, conn is deleted afterwards
closed_connection(datum/terminal_connection/conn)
return
//The data string (And, optionally, file) sent to us by a connected terminal (Identified by network ID in termid)
//Note: The passed file will be completely temporary and is deleted after the function returns.
term_input(var/data, var/termid, var/datum/computer/file/file)
if(!src.master || !data || !termid)
return 1
if(master.stat & (NOPOWER|BROKEN|MAINT))
return 1
if(src.needs_holder)
if(!(holder in src.master.contents))
return 1
if(!src.holder.root)
src.holder.root = new /datum/computer/folder
src.holder.root.holder = src
src.holder.root.name = "root"
return 0
//Called by the mainframe upon receipt of a ping_reply network signal. This does not a terminal_connection because we are not necessarily connected to the responding device.
ping_reply(var/senderid,var/sendertype)
return (!master || !senderid || !sendertype)
//Send a message to a connected terminal device (Using term_message)
message_term(var/message, var/termid, var/render=null)
if(!istype(master) || !message || !termid)
return 1
if(master.stat & (NOPOWER|BROKEN|MAINT))
return 1
if(src.needs_holder)
if (!holder || !(holder in src.master.contents))
return 1
if(!src.holder.root)
src.holder.root = new /datum/computer/folder
src.holder.root.holder = src
src.holder.root.name = "root"
spawn(1)
src.master.post_status(termid, "command", "term_message", "data", message, "render", render)
return 0
//Send a file and message to a connected terminal device (Using term_file)
file_term(var/datum/computer/file/file, var/termid, var/exdata)
if(!istype(master) || !istype(file) || !termid)
return 1
if(master.stat & (NOPOWER|BROKEN|MAINT))
return 1
if(src.needs_holder)
if (!holder || !(holder in src.master.contents))
return 1
if(!src.holder.root)
src.holder.root = new /datum/computer/folder
src.holder.root.holder = src
src.holder.root.name = "root"
spawn(1)
src.master.post_file(termid, "data", exdata, file)
return 0
/*
* The parse_* functions parse the filesystem to locate a computer datum of some sort (Be it directory, file, or either)
* with a supplied filepath string, origin point, and user. Create_if_missing determines whether intermediary folders in the path should be created if not present.
* Notes: A '/' prefixing the filepath will cause the search to start at the origin point
* '.' refers to the current folder in the search, while '..' refers to its parent folder
* Results will be filtered based on the supplied user's permissions -- If they do not have permission to read a file, they will not find said file.
* If a user datum is not supplied, it is assumed that the system made the call desiring full access.
*/
parse_directory(string, var/datum/computer/folder/origin, var/create_if_missing, var/datum/mainframe2_user_data/user)
if(!string)
return null
var/datum/computer/folder/current = origin
if(!origin)
origin = src.holder.root
if(dd_hasprefix(string , "/")) //if it starts with a /
if (string == "/")
return origin
current = origin
string = copytext(string,2)
var/list/sort1 = list()
sort1 = dd_text2list(string,"/")
if (sort1.len && !sort1[sort1.len])
sort1.len--
while(current)
if(!sort1.len)
return current
if(sort1[1] == "..")
if (current == origin)
return null
current = current.holding_folder
sort1 -= sort1[1]
continue
else if (sort1[1] == ".")
sort1 -= sort1[1]
continue
else if (!sort1[1] && !create_if_missing)
return current
var/new_current = 0
for(var/datum/computer/folder/F in current.contents)
if(ckey(F.name) == ckey(sort1[1]) && (!user || check_read_permission(F, user)))
sort1 -= sort1[1]
current = F
new_current = 1
break
if(!new_current)
if (!create_if_missing)
return null
var/datum/computer/folder/F = new /datum/computer/folder( )
F.name = sort1[1]
if (is_name_invalid(F.name))
//qdel(F)
F.dispose()
return null
. = current.add_file(F)
if (!.)
if (F)
F.dispose()
return null
else if (istype(., /datum/computer/folder))
F = .
sort1 -= sort1[1]
current = F
new_current = 1
return null
//Find a file at the end of a given dirstring.
parse_file_directory(string, var/datum/computer/folder/origin, var/create_if_missing, var/datum/mainframe2_user_data/user)
if(!string)
return null
var/datum/computer/folder/current = origin
if(!origin)
origin = src.holder.root
if(dd_hasprefix(string , "/")) //if it starts with a /
current = origin
string = copytext(string,2)
var/list/sort1 = list()
sort1 = dd_text2list(string,"/")
var/file_name = sort1[sort1.len]
if(!file_name)
return null
sort1 -= sort1[sort1.len]
while(current)
if(!sort1.len)
var/datum/computer/file/check = get_file_name(file_name, current, user)
if(check && istype(check))
return check
else
return null
if(sort1[1] == "..")
if (current == origin)
return null
current = current.holding_folder
sort1 -= sort1[1]
continue
else if (sort1[1] == ".")
sort1 -= sort1[1]
continue
var/new_current = 0
for(var/datum/computer/folder/F in current.contents)
if(ckey(F.name) == ckey(sort1[1]) && (!user || check_read_permission(F, user)))
sort1 -= sort1[1]
current = F
new_current = 1
break
if(!new_current)
if (!create_if_missing)
return null
var/datum/computer/folder/F = new /datum/computer/folder
F.name = sort1[1]
if (is_name_invalid(F.name) || !current.add_file(F))
//qdel(F)
F.dispose()
return null
sort1 -= sort1[1]
current = F
new_current = 1
return null
//If we are willing to accept either a file or folder as the return value.
parse_datum_directory(string, var/datum/computer/folder/origin, var/create_if_missing, var/datum/mainframe2_user_data/user)
if(!string)
return null
var/datum/computer/folder/current = origin
if(!origin)
origin = src.holder.root
if(dd_hasprefix(string , "/")) //if it starts with a /
if (string == "/")
return origin
current = origin
string = copytext(string,2)
var/list/sort1 = list()
sort1 = dd_text2list(string,"/")
var/datum_name = sort1[sort1.len]
if(!datum_name)
//return null
sort1.len--
while (sort1.len)
datum_name = sort1[sort1.len]
if (!datum_name)
sort1.len--
continue
break
sort1.len = max(0, sort1.len-1)
while(current)
if(!sort1.len)
switch(datum_name)
if ("..")
if (current == origin)
return null
return current.holding_folder
if (".")
return current
var/datum/computer/check = get_computer_datum(datum_name, current, user)
if(check && istype(check))
return check
else
return null
if(sort1[1] == "..")
current = current.holding_folder
sort1 -= sort1[1]
continue
else if (sort1[1] == ".")
sort1 -= sort1[1]
continue
var/new_current = 0
for(var/datum/computer/folder/F in current.contents)
if(ckey(F.name) == ckey(sort1[1]) && (!user || check_read_permission(F, user)))
sort1 -= sort1[1]
current = F
new_current = 1
break
if(!new_current)
if (!create_if_missing)
return null
var/datum/computer/folder/F = new /datum/computer/folder
F.name = sort1[1]
if (is_name_invalid(F.name) || !current.add_file(F))
//qdel(F)
F.dispose()
return null
sort1 -= sort1[1]
current = F
new_current = 1
return null
New(obj/holding as obj)
if(holding)
src.holder = holding
if(istype(src.holder.loc,/obj/machinery/networked/mainframe))
src.master = src.holder.loc
disposing()
if(master && (src in master.processing))
master.processing[src] = null
master = null
..()
asText()
return initialized ? "[progid]" : ..()
proc
input_text(var/text)
if(!istype(src.master) || !text || !useracc)
return 1
if(src.needs_holder)
if(!istype(holder))
return 1
if(!(holder in src.master.contents))
return 1
if(master.stat & (NOPOWER|BROKEN|MAINT))
return 1
if(src.needs_holder && !src.holder.root)
src.holder.root = new /datum/computer/folder
src.holder.root.holder = src
src.holder.root.name = "root"
return 0
initialize(var/initparams) //Called when a program starts running.
if(src.initialized || !master)
return 1
src.initialized = 1
return 0
//Note: If you want your application to end inteionally, send the OS an "exit" signal.
//Use the mainframe_prog_exit macro. The program will not exit otherwise, even if nothing bothers to send it more input
handle_quit()
if(src.master)
src.master.unload_program(src)
return
process()
if (!istype(master))
return 1
if (src.needs_holder)
if (!istype(holder))
return 1
if(!(holder in src.master.contents))
master.processing.Remove(src)
return 1
if(!src.holder.root)
src.holder.root = new /datum/computer/folder
src.holder.root.holder = src
src.holder.root.name = "root"
return 0
parse_string(string, var/list/replaceList = null)
var/list/sorted = list()
sorted = command2list(string, " ", replaceList)
if (!sorted.len) sorted.len++
return sorted
//Find a folder with a given name
get_folder_name(string, var/datum/computer/folder/check_folder, var/datum/mainframe2_user_data/user)
if(!string || !istype(check_folder))
return null
var/datum/computer/taken = null
for(var/datum/computer/folder/F in check_folder.contents)
if(ckey(string) == ckey(F.name) && (!user || check_read_permission(F, user)))
taken = F
break
return taken
//Find a file with a given name
get_file_name(string, var/datum/computer/folder/check_folder, var/datum/mainframe2_user_data/user)
if(!string || !istype(check_folder))
return null
var/datum/computer/taken = null
for(var/datum/computer/file/F in check_folder.contents)
if(ckey(string) == ckey(F.name) && (!user || check_read_permission(F, user)))
taken = F
break
return taken
//Just find any computer datum with this name, gosh
get_computer_datum(string, var/datum/computer/folder/check_folder, var/datum/mainframe2_user_data/user)
if(!string || !istype(check_folder))
return null
var/datum/computer/taken = null
for(var/datum/computer/C in check_folder.contents)
if(ckey(string) == ckey(C.name) && (!user || check_read_permission(C, user)))
taken = C
break
return taken
is_name_invalid(string) //Check if a filename is invalid somehow
if(!string)
return 1
//ckeyEx because it allows for - and _ and we love those!!
if(lowertext(ckeyEx(string)) != dd_replacetext(lowertext(string), " ", null))
return 1
if(findtext(string, "/"))
return 1
return 0
//Pass an output string to the user terminal, with optional render value.
//Notes: The string is not immediately set to the user! It is instead passed by signal to the parent task of the program.
//This allows for piping operations, etc. It is the duty of the OS to actually tranmit the information to the terminal.
message_user(var/msg, var/render, var/file)
if (!useracc)
return ESIG_NOTARGET
if (parent_task)
if (render)
return signal_program(parent_task.progid, list("command"=DWAINE_COMMAND_MSG_TERM, "data" = msg, "term" = useracc.user_id, "render" = render), file )
else
return signal_program(parent_task.progid, list("command"=DWAINE_COMMAND_MSG_TERM, "data" = msg, "term" = useracc.user_id), file )
return ESIG_GENERIC
read_user_field(var/field)
if (!useracc || (!istype(useracc.user_file) && !useracc.reload_user_file()))
return null
return useracc.user_file.fields[field]
write_user_field(var/field, var/data)
if (!useracc || !field || (!istype(useracc.user_file) && !useracc.reload_user_file()) || !useracc.user_file.fields)
return 0
useracc.user_file.fields[field] = data
return 1
signal_program(var/progid, var/list/data, var/datum/computer/file/file)
if(!data || !master)
return 1
if(useracc && useracc.user_file && ("id" in useracc.user_file.fields))
data["user"] = useracc.user_file.fields["id"]
return master.relay_progsignal(src, progid, data, file)
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/file)
return (!src.master || !(src in master.processing))
unloaded()
return
check_read_permission(var/datum/computer/cdatum, var/datum/mainframe2_user_data/usdat)
if (!usdat)
return 0
if (istype(cdatum, /datum/computer/folder/link) && cdatum:target)
cdatum = cdatum:target
if (!istype(cdatum) || !cdatum.metadata)
return 0
var/permissions = COMP_ALLACC
if (isnum(cdatum.metadata["permission"]))
permissions = cdatum.metadata["permission"]
if (istype(usdat.user_file) || usdat.reload_user_file())
if (!usdat.user_file.fields)
usdat.user_file.fields = list()
if (usdat.user_file.fields["group"] == 0) //Sysop usergroup
return 1
if (cdatum.metadata["owner"] && (usdat.user_file.fields["name"] == cdatum.metadata["owner"]) && (permissions & COMP_ROWNER))
return 1
if (cdatum.metadata["group"] && (usdat.user_file.fields["group"] == cdatum.metadata["group"]) && (permissions & COMP_RGROUP))
return 1
return (permissions & COMP_ROTHER)
check_write_permission(var/datum/computer/cdatum, var/datum/mainframe2_user_data/usdat)
if (!cdatum || !usdat)
return 0
var/permissions = COMP_ALLACC
if (istype(cdatum, /datum/computer/folder/link) && cdatum:target)
cdatum = cdatum:target
if (!istype(cdatum) || !cdatum.metadata)
return 0
if (istype(cdatum.metadata, /list) && isnum(cdatum.metadata["permission"]))
permissions = cdatum.metadata["permission"]
if (istype(usdat.user_file) || usdat.reload_user_file())
if (usdat.user_file.fields["group"] == 0) //Sysop usergroup can ~do anything~
return 1
if (cdatum.metadata["owner"] && (usdat.user_file.fields["name"] == cdatum.metadata["owner"]) && (permissions & COMP_WOWNER))
return 1
if (cdatum.metadata["group"] && (usdat.user_file.fields["group"] == cdatum.metadata["group"]) && (permissions & COMP_WGROUP))
return 1
return (permissions & COMP_WOTHER)
return 0
check_mode_permission(var/datum/computer/cdatum, var/datum/mainframe2_user_data/usdat)
if (!cdatum || !usdat)
return 0
if (istype(cdatum, /datum/computer/folder/link) && cdatum:target)
cdatum = cdatum:target
if (!istype(cdatum) || !cdatum.metadata)
return 0
var/permissions = COMP_ALLACC
if (istype(cdatum.metadata, /list) && isnum(cdatum.metadata["permission"]))
permissions = cdatum.metadata["permission"]
if (istype(usdat.user_file) || usdat.reload_user_file())
if (usdat.user_file.fields["group"] == 0) //Sysop usergroup can ~do anything~
return 1
if (cdatum.metadata["owner"] && (usdat.user_file.fields["name"] == cdatum.metadata["owner"]) && (permissions & COMP_DOWNER && permissions & COMP_WOWNER) )
return 1
if (cdatum.metadata["group"] && (usdat.user_file.fields["group"] == cdatum.metadata["group"]) && (permissions & COMP_DGROUP && permissions & COMP_WGROUP) )
return 1
return ((permissions & COMP_DOTHER) && (permissions & COMP_WOTHER))
return 0
//Command2list is a modified version of dd_text2list() designed to eat empty list entries generated by superfluous whitespace.
//It also can insert shell alias/variables if provided with a replacement value list.
#define QUOTE_SYMBOL "\""
#define QUOTE_SYMBOL_LENGTH 1
/proc/command2list(text, separator, list/replaceList, list/substitution_feedback_thing)
var/textlength = length(text)
var/separatorlength = length(separator)
var/list/textList = new()
var/searchPosition = 1
var/findPosition = 1
var/buggyText
//substitution_feedback_thing = list() //debug
while(1)
findPosition = findtext(text, separator, searchPosition, 0)
var/quotePoint = findtext(text, QUOTE_SYMBOL, searchPosition, findPosition)
if (quotePoint)
text = copytext(text, 1, quotePoint) + copytext(text, quotePoint + QUOTE_SYMBOL_LENGTH, 0)
var/quotePointEnd = findtext(text, QUOTE_SYMBOL, quotePoint, 0)
buggyText = copytext(text, searchPosition, quotePointEnd)
findPosition = quotePointEnd+QUOTE_SYMBOL_LENGTH
else
var/subStartPoint = findtext(text, "$(", searchPosition, findPosition)
if (substitution_feedback_thing && subStartPoint)
var/subEndPoint = findtext(text, ")", subStartPoint)
substitution_feedback_thing[++substitution_feedback_thing.len] = copytext(text, subStartPoint+2, subEndPoint)
text = copytext(text, 1, subStartPoint) + "_sub[substitution_feedback_thing.len]" + copytext(text, subEndPoint ? subEndPoint + 1 : 0)
//boutput(world, "text changed to \"[text]\"")
//boutput(world, "added: \[[substitution_feedback_thing[substitution_feedback_thing.len]]]")
continue
else
buggyText = trim(copytext(text, searchPosition, findPosition))
if(buggyText)
if (replaceList && dd_hasprefix(buggyText, "$") && (copytext(buggyText,2) in replaceList))
textList += "[replaceList[copytext(buggyText, 2)]]"
else
textList += "[buggyText]"
if(!findPosition)
//boutput(world, english_list(textList))
return textList
searchPosition = findPosition + separatorlength
if(searchPosition > textlength)
//boutput(world, english_list(textList))
return textList
return
#undef QUOTE_SYMBOL
#undef QUOTE_SYMBOL_LENGTH
@@ -0,0 +1,138 @@
//CONTENTS:
//DWAINE system help file
//Guardbot readme
//Guardbot demo patrol script file
//Guardbot demo bodyguard script file
//Guardbot demo configuration file
//Artifact research readme
/*
* Help record - Individual entries accessed by shell "help" command. "index" entry generated programmatically.
*/
/datum/computer/file/record/dwaine_help
name = "help"
New()
..()
src.fields["basics1"] = "DWAINE is a multi-user Unix-like operating system produced by Thinktronic Data Systems. The primary user interface is through a text-based terminal shell.|nApplications may be invoked simply by typing their filename, followed by a list of arguments if necessary. A set of primary commands, those covering basic system tasks (Such as ls and cd), are made available to all users regardless of location in the filesystem. Otherwise, applications must be in the user's current working directory to run."
src.fields["basics2"] = "Directory navigation is accomplished primarily through the ls and cd commands.|nLS, an abbreviation of \"list\" will list the contents of the current directory. The argument -l will cause it to also display extended file information and hidden files.|nCD, or \"change directory\" will set the current directory to the provided path, if valid. A filepath takes a form such as \"/mnt/drive0\" Paths starting with / descend from the root directory \"..\" refers to the directory one level up from the current, while \".\" refers to the current directory.|nEx: \"cd ../hams\" would specify a directory named ham with the same parent as the current working one."
src.fields["basics3"] = "DWAINE is, primarily, a networked system. All devices, from user terminals to lineprinters and tape drives, are connected remotely to the central mainframe. Devices that interact with files, such as drives or printers, may appear as part of the filesystem as a sub-directory of /mnt.|nFor example, the contents of tape databank \"Main\" would appear within /mnt/main and applications and other files could be accessed by setting it to your working directory with \"cd /mnt/main\""
src.fields["basics4"] = "Application software is often bundled with a \"readme\" file of some sort, which can be viewed with the CAT command.|nEx: \"cat readme\" will view the contents of a readme file in the user's working directory."
src.fields["ls"] = "View contents of a directory. If no filepath is supplied, the working directory will be listed.|nExpanded file information, as well as hidden files, may be viewed through use of the -l argument.|nUsage: ls \[-l] \[filepath]"
src.fields["cd"] = "Change working directory to the filepath supplied as argument.|nUsage: cd \"filepath\""
src.fields["cat"] = "Combine the contents of one or more data files and print result to current output (Default output would be the user terminal). Use with executable files is inadvisable.|nUsage: cat \"filepath\" \[filepath...]"
src.fields["echo"] = "Print text to current stream. Stream defaults to standard output (User terminal screen) if not piping.|nIf piping, output is passed on. If the piping target is not an executable, an attempt will be made to write to that file.|nUsage: echo \"text\" OR echo \"text\" | pipe_file_name"
src.fields["eval"] = "Evaluate an expression. Stack based with RPN input--the operation is expressed following the inputs, like \"1 2 +\" will result in 3.|nInput values are placed in order in a \"stack,\" with most recent input on top and first input on the bottom. Values are taken back off the stack from the top down. Operations act on the top 1 or 2 values on the stack, usually removing them and placing the result as the new top.|nValid operations are +, -, *, /, %, for arithmetic operations.|neq (equal), neq (not equal), gt (greater than), ge (greater or equal), lt (less than), le (less or equal) for comparison operations,|nAnd, Or, Not, and Xor for logical operations.|nThe operator DUP will copy the top value on the stack without removing anything from the stack.|nText surrounded by apostrophes will be interpreted as a string. Variables may be set by pushing the desired value to the stack and then using the TO operator and a variable name. For example, \"5 to HAMDAD\" would create a variable with the name HAMDAD and value 5.|nThere are also four file checking operators: d, e, f, and x. Each take a filepath string from the top of the stack and leave a boolean value in its place. d leaves a true if the path is to a folder, x is true if the path is to an executable, f is true if the path is to a file, and e is true if the path is to anything at all."
src.fields["who"] = "Print list of current users to current output.|nUsage: who"
src.fields["mesg"] = "Control acceptance of messages sent by other users.|nUsage mesg \"(y/n)\""
src.fields["talk"] = "Send a message to another current user.|nUsage talk \"user name or user terminal ID\" \"message\""
src.fields["cp"] = "Copy datafile to a new location. If new filepath specifies only a directory, the copy will retain original name.|nUsage: cp \"target filepath\" \"new filepath\""
src.fields["mv"] = "Move datafile to a new location. If new filepath specifies only a directory, the file will retain original name.|nUsage: mv \"target filepath\" \"new filepath\""
src.fields["rm"] = "Delete datafile or directory. Use of -r switch required for directory deletion. -i switch enables confirmation prompt, while -f suppresses this and error messages.|nUsage: rm \"target filepath\""
src.fields["su"] = "Assume superuser status. An authorized ID must be provided.|nUsage: \"su\""
src.fields["mkdir"] = "Create a directory or set of directories with the provided paths.|nUsage: mkdir \[filepath...]"
src.fields["chmod"] = "Change the permissions of a file. File permissions take the form of three octal digits in the order of: owner, group, any user.|nBit one (The least significant bit) of each field controls modify access, bit two controls write access, and the third bit controls read access.|nUsage: chmod \"access value, i.e 777\" \"filename\""
src.fields["chown"] = "Change the owner and/or group of a file. System operator status required to invoke.|nUsage: chown \[exact username]:\[group ID] \"filename\""
src.fields["mount"] = "Mount device driver file space to filesystem. System operator status required to invoke.|nUsage: mount \"device net ID\" \"mountpoint name (Name for folder in /mnt)\""
src.fields["scnt"] = "Scan network for unconnected peripheral devices, and then automatically connect to them. System operator status required to invoke.|nSpecific net IDs may be provided as arguments to connect to them directly. |nUsage: \"scnt\""
src.fields["logoff"] = "Log out current user and ready system to accept new login.|nUsage: \"logoff\""
src.fields["index"] = "Usage: help \"topic\"|nValid Topics: [english_list(src.fields, "None")]"
/datum/computer/file/record/pr6_readme
name = "readme"
New()
..()
src.fields = list("Readme for PR-6 Control Interface",
"Notice: Superuser access may be required to run prman application",
"Please ready authorized heads ID and type \"su\"",
"",
"A series of demo files have been supplied, as well as PR-6 task packages.",
"patrol_script takes one argument, the net id of the target bot. It may be invoked by \"patrol_script (bot id)\"",
"guard_script takes two arguments, the net id of the target bot and the full name, with no spaces, of the person to protect.",
"demo_conf is a demonstration configuration file to set bodyguard tasks to guard \"John Doe\"",
"Valid PR-6 net ids may be listed via \"prman list\"",
"PR-6 units may be recalled via \"prman recall (id)\" The id may either correspond to the actual PR-6 unit or its last used dock.",
"If no arguments are supplied to prman, it will list valid commands.")
/datum/computer/file/record/patrol_script
name = "patrol_script"
New()
..()
src.fields = list("#!",
"#demonstration patrol script",
"#takes bot net id as argument",
"if $argc 1 lt | echo Error: No Net ID specified! | break",
"if $su 1 ne | echo Please authenticate (su) prior to invocation. | break",
//FUN NOTE; Why do we use /conf instead of just the local directory?
//"echo patrol=1|/conf/confpatrol",
//Because this file is, by default, on a tape drive. The write time on secondary storage is such that
//"prman upload $arg0 secure -f /conf/confpatrol",
//by the time the file is visible, prman would've already looked and failed to find it.
"prman upload $arg0 secure patrol=1;",
"prman wake $arg0")
/datum/computer/file/record/bodyguard_script
name = "guard_script"
New()
..()
src.fields = list("#!",
"#simple bodyguard script",
"#takes bot net id and spaceless target name as argument",
"#ex: guard_script 02000050 johndoe",
"if argc 2 lt | echo Error: No Net ID or target name specified! | break",
"if su 1 ne | echo Please authenticate (su) prior to invocation. | break",
//"echo name= | echo $arg1|/conf/confguard",
//"prman upload $arg0 bodyguard -f /conf/confguard",
"prman upload $arg0 bodyguard name= $arg1",
"prman wake $arg0")
/datum/computer/file/record/roomguard_script
name = "roomguard_script"
New()
..()
src.fields = list("#!",
"#Bot will only look for targets in the same area.",
"#takes bot net id as argument",
"if $argc 1 lt | echo Error: No Net ID specified! | break",
"if $su 1 ne | echo Please authenticate (su) prior to invocation. | break",
"prman upload $arg0 areaguard",
"prman wake $arg0")
/datum/computer/file/record/bodyguard_conf
name = "demo_conf"
New()
..()
src.fields = list("#demonstration of configuration file",
"#for bodyguard and secure tasks",
"name=john doe",
"#this is the name of the protected individual",
"",
"#this is for use with the secure task",
"patrol=1",
"",
"#prman upload bot_id bodyguard patrol=1",
"or",
"#prman upload bot_id bodyguard -f demo_conf")
/*
* Emails!!
*/
/proc/get_random_email_list()
return strings("mainframe/documents/randomEmail.txt", "availableMail")
/datum/computer/file/record/random_email
New(mailName as text)
..()
src.name = "[copytext("\ref[src]", 4, 12)]GENERIC"
if (mailName)
src.fields = strings("mainframe/documents/randomEmail.txt", mailName)
@@ -0,0 +1,250 @@
//CONTENTS
//Email daemon thing
/datum/computer/file/mainframe_program/srv/email
name = "mail"
size = 1
var/setup_email_folder = "/etc/mail"
var/setup_mailgroup_table = "groups"
var/defaultDomain = "NT13"
initialize(var/initparams)
if (..() || !useracc)
mainframe_prog_exit
return
//todo: all of this. All of this forever.
//boutput(world, "[initparams]")
var/command = null
var/list/initlist = dd_text2list(initparams, " ")
if (!initparams || !initlist.len)
command = "index"
else
command = ckey(initlist[1])
var/user_name = dd_hasprefix(useracc.user_name, "SRV") ? copytext(useracc.user_name, 4, length(useracc.user_name)) : copytext(useracc.user_name, 1, length(useracc.user_name))
//boutput(world, "Username: \"[useracc.user_name]\" -> \"[user_name]\"")
switch (command)
if ("index")
var/group = null
if (initlist.len > 1)
group = initlist[2]
var/list/mail_subjects = list_mail_subjects(user_name, group)
var/message = "mail_index"
if (mail_subjects.len)
message += "|n" + dd_list2text(mail_subjects, "|n")
message_user(message, "record")
if ("get")
var/index = 0
var/group = null
if (initlist.len > 1)
index = max( round(text2num(initlist[2])), 1)
if (initlist.len > 2)
group = initlist[3]
var/list/mailList = list_mail_for(user_name, group)
if (!istype(mailList) || mailList.len < index)
mainframe_prog_exit
return
var/datum/computer/file/record/targetMail = mailList[index]
if (istype(targetMail) && parent_task)
targetMail = format_outgoing_mail(targetMail)
message_user("mail_entry",null,targetMail)
if ("send")
if (initlist.len > 1)
var/sentMailPath = initlist[2]
if (!dd_hasprefix(sentMailPath, "/"))
sentMailPath = "/[sentMailPath]"
var/datum/computer/file/record/sentMail = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[sentMailPath]"))
if (istype(sentMail))
sentMail = sentMail.copy_file()
sentMail.fields = sentMail.fields.Copy()
if (send_mail_to(sentMail) == 0)
message_user("ack")
else
message_user("nack")
if ("delete")
var/index = 0
var/group = null
if (initlist.len > 1)
index = max( round(text2num(initlist[2])), 1)
if (initlist.len > 2)
group = initlist[3]
var/list/mailList = list_mail_for(user_name, group)
if (!istype(mailList) || mailList.len < index)
mainframe_prog_exit
return
var/datum/computer/file/record/targetMail = mailList[index]
if (istype(targetMail) && dd_hassuffix(targetMail.name, user_name))
if (signal_program(1, list("command"=DWAINE_COMMAND_FKILL, "path"="[setup_email_folder]/[targetMail.name]")) == ESIG_SUCCESS)
message_user("ack")
else
message_user("nack")
else
message_user("nack")
mainframe_prog_exit
return
proc
format_outgoing_mail(var/datum/computer/file/record/mail)
if (!istype(mail) || !mail.fields || (mail.fields.len < 6))
return null
var/datum/computer/file/record/newMail = mail.copy_file()
newMail.fields = newMail.fields.Copy()
var/compactHeader = "mailnet=[mail.fields[1] ? mail.fields[1] : "???"]&group=[mail.fields[2] ? mail.fields[2] : "???"]"
compactHeader += "&sender=[mail.fields[3] ? mail.fields[3] : "???"]&target=[mail.fields[4] ? mail.fields[4] : "???"]"
compactHeader += "&priority=[mail.fields[5] ? mail.fields[5] : "LOW"]&subj=[mail.fields[6] ? mail.fields[6] : "???"]"
newMail.fields[1] = compactHeader
newMail.fields.Cut(2, 7)
return newMail
send_mail_to(var/datum/computer/file/record/mail)
if (!istype(mail) || !mail.fields.len)
return 1
var/list/mailHeader = params2list(mail.fields[1])
if (!mailHeader)
return 2
var/target = mailHeader["target"]
var/target_name = target
var/atLocation = findtext(target, "@")
if (atLocation)
target_name = copytext(target,1, atLocation)
var/mailgroup = ckey(mailHeader["group"]) ? mailHeader["group"] : "*NONE"
if (!target && !mailgroup)
return 3
var/datum/computer/folder/mailgroupTable = null
if (mailgroup && lowertext(mailgroup) != "*all" && lowertext(mailgroup) != "*none")
mailgroupTable = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]/[setup_mailgroup_table]"))
if (!istype(mailgroupTable))
return 4
mail.fields.Cut(1,2)
mail.name = "[copytext("\ref[mail]", 4, 12)][target_name ? lowertext(target_name) : "all"]"
mail.fields.Insert(1, "PUBLIC_NT", "[uppertext(mailgroup)]","[ckeyEx(mailHeader["sender"]) ? copytext(uppertext(ckeyEx(mailHeader["sender"])), 1, 33) : "???"][dd_hassuffix(mailHeader["sender"], "@[defaultDomain]") ? null : "@[defaultDomain]"]",\
"[target ? target : "ALL"]",\
"[ckeyEx(mailHeader["priority"]) ? copytext(uppertext(ckeyEx(mailHeader["priority"])), 1, 9) : "LOW"]",\
"[ckeyEx(mailHeader["subj"]) ? copytext(uppertext(mailHeader["subj"]), 1, 33) : "???"]")
if (signal_program(1, list("command"=DWAINE_COMMAND_FWRITE, "path"="[setup_email_folder]", "mkdir"=1), mail) == ESIG_SUCCESS)
return 0
return 5
list_mail_for(var/target, var/mailgroup=null)//"*all")
if (!target && !mailgroup)
return
var/list/mailList = list()
var/datum/computer/folder/mailFolder = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]"))
if (!istype(mailFolder))
return mailList
var/datum/computer/file/record/mailgroupTable = null
var/list/groupTargets = null
if (!(mailgroup && lowertext(mailgroup) != "*all"))
groupTargets = list()
mailgroupTable = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]/[setup_mailgroup_table]"))
if (istype(mailgroupTable))
for (var/groupDef in mailgroupTable.fields)
if (findtext(groupDef, "[target],"))
groupTargets += "[copytext(groupDef, 1, findtext(groupDef, ":"))]"
break
for(var/datum/computer/file/record/emailRec in mailFolder.contents)
if (!check_read_permission(emailRec, useracc))
continue
if ((emailRec.fields.len >= 2) && lowertext(emailRec.fields[2]) == "*all")
mailList += emailRec
continue
if (groupTargets && groupTargets.len)
var/success = 0
for (var/groupMember in groupTargets)
if (emailRec.fields.len >= 2 && (lowertext(groupMember) == lowertext(emailRec.fields[2])))
mailList += emailRec
success = 1
break
if (success)
continue
if (target && dd_hassuffix(emailRec.name, target))
mailList += emailRec
continue
return mailList
list_mail_subjects(var/target, var/mailgroup=null)//"*all")
if (!target && !mailgroup)
return
var/list/mailSubjs = list()
var/datum/computer/folder/mailFolder = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]"))
if (!istype(mailFolder))
return mailSubjs
var/datum/computer/file/record/mailgroupTable = null
var/list/groupTargets = null
if (!(mailgroup && lowertext(mailgroup) != "*all"))
groupTargets = list()
mailgroupTable = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[setup_email_folder]/[setup_mailgroup_table]"))
if (istype(mailgroupTable))
for (var/groupDef in mailgroupTable.fields)
if (findtext(groupDef, "[target],"))
groupTargets += "[copytext(groupDef, 1, findtext(groupDef, ":"))]"
break
for(var/datum/computer/file/record/emailRec in mailFolder.contents)
if (!check_read_permission(emailRec, useracc))
continue
if (!emailRec.fields || emailRec.fields.len < 6)
continue
if (lowertext(emailRec.fields[2]) == "*all")
mailSubjs.len++
mailSubjs[mailSubjs.len] = copytext(emailRec.fields[6], 1, 33)
continue
if (groupTargets && groupTargets.len)
var/success = 0
for (var/groupMember in groupTargets)
if (lowertext(groupMember) == lowertext(emailRec.fields[2]))
mailSubjs.len++
mailSubjs[mailSubjs.len] = copytext(emailRec.fields[6], 1, 33)
success = 1
break
if (success)
continue
if (target && dd_hassuffix(emailRec.name, target))
mailSubjs.len++
mailSubjs[mailSubjs.len] = copytext(emailRec.fields[6], 1, 33)
continue
return mailSubjs
@@ -0,0 +1,67 @@
//Filetype used to store information on current user
/datum/computer/file/user_data
name = "user account"
extension = "USR"
size = 1
//Store the data an ID card would.
var/registered = null
var/assignment = null
var/list/access = list()
//And some more
var/net_id = null
var/tmp/authlevel = 0
var/tmp/datum/computer/file/mainframe_program/active_program = null
var/tmp/datum/computer/folder/current_folder = null
disposing()
active_program = null
current_folder = null
access = null
..()
/*
* User Account Datum
*/
/datum/mainframe2_user_data
var/datum/computer/file/record/user_file = null
var/datum/computer/folder/user_file_folder = null
var/user_filename = null
var/user_name = "GENERIC"
var/user_id = null
var/full_user = 0
var/datum/computer/file/mainframe_program/current_prog = null
disposing()
current_prog = null
user_file = null
user_file_folder = null
..()
proc/reload_user_file()
if (!user_file_folder || !user_filename)
return 0
for (var/datum/computer/file/record/potential in user_file_folder.contents)
if (potential.name == user_filename)
user_file = potential
return 1
return 0
/datum/computer/file/document
name = "Document"
extension = "DOC"
var/list/textlist = list() //Actual document text
var/list/metalist = list() //Instructions on how to process each line.
disposing()
textlist = null
metalist = null
..()
@@ -0,0 +1,754 @@
#define ACCESSLOG_RECORDS_LIMIT 256
#define DEFAULT_LOG_PATH "/var/log/door-access"
#define MAINFRAME_ACCESSLOG_DRIVER_HACK
/datum/computer/file/record/accesslog_default_config
name = "accesslog"
New()
..()
fields = list("logdir" = DEFAULT_LOG_PATH)
/obj/machinery/networked/logreader
icon = 'icons/obj/computer.dmi'
icon_state = "computer_generic"
name = "door access logs"
density = 1
anchored = 1
device_tag = "PNET_LOGREADER"
timeout = 10
mats = 14
power_usage = 100
var/static/list/required_fields = list("card_name", "door_name", "time_t", "timestamp", "door_id", "action")
var/filter_name = null
var/ftb_min = null
var/ftb_sec = null
var/fte_min = null
var/fte_sec = null
var/filter_door_id = null
var/filter_action = null
var/machine_screen = 1
var/list/records = list()
var/refreshing = 0
var/refresh_id = 0
var/timed_out = 0
var/spoofed = 0
New()
..()
spawn(5)
src.net_id = generate_net_id(src)
if(!src.link)
var/turf/T = get_turf(src)
var/obj/machinery/power/data_terminal/test_link = locate() in T
if(test_link && !test_link.is_valid_master(test_link.master))
src.link = test_link
src.link.master = src
attack_hand(var/mob/user)
if(..() || (stat & (NOPOWER|BROKEN)))
return
user.machine = src
var/dat = {"<html><head><title>Access Log Reader</title><style>
.conn-box {
float: right;
width: 12px;
height: 12px;
display: block;
display: inline-block;
border: 1px solid #888888;
}
.conn-ok {
background-color: #33FF00;
}
.conn-no {
background-color: #F80000;
}
.conn-error {
background-color: #888888;
}
</style></head><body>"}
var/readout_class = "conn-error"
var/readout = "ERROR"
if(src.host_id)
readout_class = "conn-ok"
readout = "OK CONNECTION"
else
readout_class = "conn-no"
readout = "NO CONNECTION"
dat += "<div class='conn-box [readout_class]'></div>"
if (!refreshing)
if (machine_screen == 1)
dat += "<b>Connection</b> | <a href='?src=\ref[src];screen=2'>Data</a>"
else if (machine_screen == 2)
dat += "<a href='?src=\ref[src];screen=1'>Connection</a> | <b>Data</b>"
else if (!refreshing)
dat += "<a href='?src=\ref[src];screen=1'>Connection</a> | <a href='?src=\ref[src];screen=2'>Data</a>"
dat += "<hr><br>"
if (machine_screen == 1)
dat += "<b>Host Connection:</b>"
dat += "<table border='1' class='[readout_class]'><tr><td><font color=white>[readout]</font></td></tr></table><br>"
dat += "<a href='?src=\ref[src];reset=1'>Reset Connection</a><br>"
if (src.panel_open)
dat += net_switch_html()
else if (machine_screen == 2)
dat += "<h3>Door access logs</h3>"
if (spoofed)
dat += "<i>Warning: could not verify authenticity of displayed data.</i><br>"
if (timed_out)
dat += "<i>Warning: last request to refresh records timed out with no response.</i><br>"
if (spoofed || timed_out)
dat += "<br>"
dat += "<b>Filters</b><br>"
dat += "<b>Card name (partial):</b> <a href='?src=\ref[src];card_name=1'>[filter_name ? filter_name : "&lt;not set&gt;"]</a>[filter_name ? " <a href='?src=\ref[src];card_name_clear=1'>\[X\]</a>" : null]<br>"
dat += "<b>Time interval:</b> "
if (ftb_min != null && ftb_sec != null && fte_min != null && fte_sec != null)
dat += "<a href='?src=\ref[src];time_begin_min=1'>[ftb_min]</a>:"
dat += "<a href='?src=\ref[src];time_begin_sec=1'>[ftb_sec]</a> - "
dat += "<a href='?src=\ref[src];time_end_min=1'>[fte_min]</a>:"
dat += "<a href='?src=\ref[src];time_end_sec=1'>[fte_sec]</a> "
dat += "<a href='?src=\ref[src];time_clear=1'>\[X\]</a>"
else
dat += "<a href='?src=\ref[src];time=1'>&lt;not set&gt;</a>"
dat += "<br>"
dat += "<b>Action:</b> <a href='?src=\ref[src];action=1'>[filter_action ? filter_action : "&lt;not set&gt;"]</a>[filter_action ? " <a href='?src=\ref[src];action_clear=1'>\[X\]</a>" : null]<br>"
dat += "<b>Door net ID:</b> <a href='?src=\ref[src];door_id=1'>[filter_door_id ? filter_door_id : "&lt;not set&gt;"]</a>[filter_door_id ? " <a href='?src=\ref[src];door_id_clear=1'>\[X\]</a>" : null]<br>"
dat += "<a href='?src=\ref[src];refresh=1'>Refresh records</a><br><br>"
dat += "<b>Record listing: </b><br>"
if (!records.len)
dat += "<i>No records currently loaded. Refresh the records to load data.</i><br>"
else
for (var/rec in records)
dat += "[rec]<br>"
else if (refreshing)
dat += "<i>Refreshing data, please wait...</i>"
user << browse(dat,"window=net_logreader;size=545x302")
onclose(user,"net_logreader")
return
Topic(href, href_list)
if(..())
return
if (!(usr in range(1)))
return
usr.machine = src
src.add_fingerprint(usr)
if (href_list["reset"])
if(last_reset && (last_reset + NETWORK_MACHINE_RESET_DELAY >= world.time))
return
src.last_reset = world.time
var/rem_host = src.host_id ? src.host_id : src.old_host_id
src.host_id = null
src.old_host_id = null
src.post_status(rem_host, "command","term_disconnect")
spawn(5)
src.post_status(rem_host, "command","term_connect","device",src.device_tag)
src.updateUsrDialog()
return
if (href_list["screen"])
machine_screen = text2num(href_list["screen"])
if (href_list["card_name"])
filter_name = input("Partial name of card holder", "Card holder name", filter_name) as text|null
if (href_list["card_name_clear"])
filter_name = null
if (href_list["action"])
filter_action = input("Door action", "Door action", filter_action) as null|anything in list("open","close","lock","unlock","reject")
if (href_list["action_clear"])
filter_action = null
if (href_list["door_id"])
filter_door_id = input("Net ID of door", "Door net ID", filter_door_id) as text|null
if (href_list["door_id_clear"])
filter_door_id = null
if (href_list["time"])
ftb_min = input("Filter start time: minutes", "Begin time minutes", 0) as num|null
if (ftb_min == null)
return
ftb_sec = input("Filter start time: seconds", "Begin time seconds", 0) as num|null
if (ftb_sec == null)
ftb_min = null
return
fte_min = input("Filter end time: minutes", "End time minutes", 0) as num|null
if (fte_min == null)
ftb_min = null
ftb_sec = null
return
fte_sec = input("Filter end time: seconds", "End time seconds", 0) as num|null
if (fte_sec == null)
ftb_min = null
ftb_sec = null
fte_min = null
return
if (href_list["time_begin_min"])
var/n_ftb_min = input("Filter start time: minutes", "Begin time minutes", ftb_min) as num|null
if (n_ftb_min != null)
ftb_min = n_ftb_min
if (href_list["time_begin_sec"])
var/n_ftb_sec = input("Filter start time: seconds", "Begin time seconds", ftb_sec) as num|null
if (n_ftb_sec != null)
ftb_sec = n_ftb_sec
if (href_list["time_end_min"])
var/n_fte_min = input("Filter end time: minutes", "End time minutes", fte_min) as num|null
if (n_fte_min != null)
fte_min = n_fte_min
if (href_list["time_end_sec"])
var/n_fte_sec = input("Filter end time: seconds", "End time seconds", fte_sec) as num|null
if (n_fte_sec != null)
fte_sec = n_fte_sec
if (href_list["time_clear"])
ftb_min = null
ftb_sec = null
fte_min = null
fte_sec = null
if (href_list["refresh"])
if (!src.host_id)
return
if (refreshing)
return
refreshing = 1
refresh_id++
var/my_refresh_id = refresh_id
var/datum/signal/signal = get_free_signal()
signal.source = src
signal.transmission_method = TRANSMISSION_WIRE
var/arguments = "-l 32 -f"
if (ftb_min != null && ftb_sec != null && fte_min != null && fte_sec != null)
var/st = ftb_min * 600 + ftb_sec * 10
var/et = fte_min * 600 + fte_sec * 10
arguments += " -t [st]:[et]"
if (filter_action)
arguments += " -m [filter_action]"
if (filter_door_id)
arguments += " -s [uppertext(ckey(filter_door_id))]"
if (filter_name)
arguments += " -- [bash_sanitize(filter_name)]"
var/data = list2params(list("command"="record_query","query"="[arguments]"))
src.post_status(src.host_id, "command", "term_message", "data", data, "netid", "[net_id]", "device", device_tag)
spawn (300)
if (refresh_id == my_refresh_id && refreshing)
timed_out = 1
refreshing = 0
attack_hand(usr)
return
process()
..()
if(stat & NOPOWER)
return
use_power(100)
if(!host_id || !link)
return
if(src.timeout == 0)
src.post_status(host_id, "command","term_disconnect","data","timeout")
src.host_id = null
src.updateUsrDialog()
src.timeout = initial(src.timeout)
src.timeout_alert = 0
else
src.timeout--
if(src.timeout <= 5 && !src.timeout_alert)
src.timeout_alert = 1
src.post_status(src.host_id, "command","term_ping","data","reply")
return
receive_signal(datum/signal/signal)
if(stat & (NOPOWER) || !src.link)
return
if(!signal || !src.net_id || signal.encryption)
return
var/target = signal.data["sender"] ? signal.data["sender"] : signal.data["netid"]
if(!target)
return
if(signal.data["target_device"] && signal.data["target_device"] != device_tag)
return
//We care very deeply about address_1.
if(lowertext(signal.data["address_1"]) != lowertext(src.net_id))
if((signal.data["address_1"] == "ping") && ((signal.data["net"] == null) || ("[signal.data["net"]]" == "[src.net_number]")))
spawn(5) //Send a reply for those curious jerks
if (signal.transmission_method == TRANSMISSION_WIRE)
src.post_status(target, "command", "ping_reply", "device", src.device_tag, "netid", src.net_id, "net", "[net_number]")
// else ????
return
if (!signal.data["target_device"])
return
var/sigcommand = lowertext(signal.data["command"])
if(!sigcommand || !target)
return
switch(sigcommand)
if("term_connect") //Terminal interface stuff.
if(target == src.host_id)
src.host_id = null
src.updateUsrDialog()
spawn(3)
src.post_status(target, "command","term_disconnect")
return
if(src.host_id)
return
src.timeout = initial(src.timeout)
src.timeout_alert = 0
src.host_id = target
src.old_host_id = target
if(signal.data["data"] != "noreply")
src.post_status(target, "command","term_connect","data","noreply","device",src.device_tag)
src.updateUsrDialog()
spawn(2) //Sign up with the driver (if a mainframe contacted us)
src.post_status(target,"command","term_message","data","command=register")
return
if("term_message","term_file")
if(target != src.host_id) //Huh, who is this?
return
var/data = signal.data["data"]
if(!data || sigcommand == "term_message") // currently no action is taken without a file, so throw back term_message
src.post_status(target,"command","term_message","data","command=status&status=failure")
return
var/datum/computer/file/archive/archive = signal.data_file
if (!istype(archive))
src.post_status(target,"command","term_message","data","command=status&status=failure")
return
records.len = 0
for (var/datum/computer/file/record/R in archive.contained_files)
var/bad = 0
for (var/F in required_fields)
if (!(F in R.fields))
bad = 1
break
if (bad)
continue
records += accesslog_digest(R, 1)
if (data == "ack")
spoofed = 0
else
spoofed = 1
timed_out = 0
refreshing = 0
src.post_status(target,"command","term_message","data","command=status&status=success")
for (var/mob/M in range(1))
if (M.machine == src)
attack_hand(M)
return
if("term_ping")
if(target != src.host_id)
return
if(signal.data["data"] == "reply")
src.post_status(target, "command","term_ping")
src.timeout = initial(src.timeout)
src.timeout_alert = 0
return
if("term_disconnect")
if(target == src.host_id)
src.host_id = null
src.timeout = initial(src.timeout)
src.timeout_alert = 0 //No need to be alerted about this anymore.
src.updateUsrDialog()
return
return
proc/accesslog_digest(var/datum/computer/file/record/R, formatted = 0)
if (!istype(R))
return "unknown type [R.name], possibly not a record"
var/action = R.fields["action"]
var/card_name = R.fields["card_name"]
var/time_t = R.fields["time_t"]
var/door_name = R.fields["door_name"]
if (!action)
return "corrupted record [R.name] missing action"
if (!card_name)
return "corrupted record [R.name] missing user ID"
if (!time_t)
return "corrupted record [R.name] missing human readable time"
if (!door_name)
return "corrupted record [R.name] missing door designated name"
if (action != "reject")
if (!formatted)
return "[time_t] [card_name] [action]s [door_name]"
else
return "<b>[time_t]</b> [card_name] <b>[action]s</b> [door_name]"
else
if (!formatted)
return "[time_t] [door_name] rejected entry for [card_name]"
else
return "<b>[time_t]</b> [door_name] <b>rejected entry for</b> [card_name]"
/datum/computer/file/mainframe_program/srv/accesslog
name = "accesslog"
size = 1
var/static/nextlog = 1
var/opt_data = null
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/file)
. = ..()
if (!.)
if (data["command"] == DWAINE_COMMAND_REPLY)
if (data["sender_tag"] == "getopt")
opt_data = data["data"]
return ESIG_USR4
else
return ESIG_GENERIC
else if (data["command"] == DWAINE_COMMAND_MSG_TERM)
message_user(data["data"])
else
return ESIG_GENERIC
return ESIG_SUCCESS
proc/usage()
message_user("Usage:")
message_user("[name] -a -s DOOR_ID -m (open|close|lock|unlock|reject) -t TIME USER_ID")
message_user("[name] -l COUNT \[-f\] \[-s DOOR_ID\] \[-m (open|close|lock|unlock|reject)\] \[-b TIME_START:TIME_END\] \[USER_ID_FRAGMENT \]")
proc/loglist(timestamp, action, door_id, card_name)
var/list/ret = list()
ret["action"] = action
ret["door_id"] = door_id
ret["card_name"] = card_name
var/atom/door = locate("\[0x[door_id]\]")
if (istype(door, /obj/machinery/door/airlock))
ret["door_name"] = door.name
else if (istype(door, /obj/machinery/networked))
ret["door_name"] = "[door.name] (ALERT: network indicates this may not be door)"
else
ret["door_name"] = "Unknown device (0x[door_id])"
var/time_n = istext(timestamp) ? text2num(timestamp) : timestamp
ret["timestamp"] = time_n
var/min = round(time_n / 600)
var/sec = round(time_n / 10) - min * 60
ret["time_t"] = "[min < 10 ? 0 : null][min]:[sec < 10 ? 0 : null][sec]"
return ret
proc/message_reply_and_user(var/message)
var/list/data = list("command"=DWAINE_COMMAND_REPLY, "data" = message, "sender_tag" = "accesslog")
if (useracc)
data["term"] = useracc.user_id
var/sig = signal_program(parent_task.progid, data)
if (sig != ESIG_USR4)
message_user(message)
initialize(var/initparams)
if (..())
mainframe_prog_exit
return
if (!initparams)
usage()
mainframe_prog_exit
return
var/log_to = DEFAULT_LOG_PATH
var/datum/computer/file/record/conf_file = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="/etc/accesslog"))
if (istype(conf_file))
if (conf_file.fields["logdir"])
log_to = conf_file.fields["logdir"]
if (chs(log_to, 1) != "/")
log_to = "/log_to"
opt_data = null
var/status = signal_program(1, list("command"=DWAINE_COMMAND_TSPAWN, "passusr" = 1, "path" = "/bin/getopt", "args" = "afl:m:s:t: [initparams]"))
if (status == ESIG_NOTARGET)
message_user("getopt: command not found")
mainframe_prog_exit
return
if (!opt_data)
message_user("accesslog: No response from getopt.")
mainframe_prog_exit
return
if (copytext(opt_data, 1, 7) == "getopt")
message_user(opt_data)
mainframe_prog_exit
return
var/list/l = optparse(opt_data)
if (!istype(l))
message_user("accesslog: Error parsing options: [opt_data].")
mainframe_prog_exit
return
var/list/opts = l[1]
var/list/params = l[2]
if (opts["a"] && opts["l"])
usage()
mainframe_prog_exit
return
if (opts["a"])
if (opts["s"] && opts["t"] && opts["m"] && params.len)
if (!(opts["m"] in list("open","close","lock","unlock","reject")))
message_user("")
var/mylog = nextlog
nextlog++
var/datum/computer/file/record/logfile = new()
var/fname = "access[mylog]"
logfile.name = fname
if (useracc)
logfile.metadata["owner"] = read_user_field("name")
logfile.metadata["permissions"] = COMP_ROWNER | COMP_RGROUP
logfile.fields = loglist(opts["t"], opts["m"], opts["s"], dd_list2text(params, " "))
var/datum/computer/folder/logs_dir = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"=log_to))
if (istype(logs_dir))
var/idx = 0
while (logs_dir.contents.len >= ACCESSLOG_RECORDS_LIMIT)
idx++
if (idx > logs_dir.contents.len)
message_user("Could not make space for new entry.")
mainframe_prog_exit
return
var/datum/computer/to_delete = logs_dir.contents[idx]
if (istype(to_delete, /datum/computer/file/record))
logs_dir.remove_file(to_delete)
if (to_delete)
qdel(to_delete)
idx--
var/result = signal_program(1, list("command"=DWAINE_COMMAND_FWRITE, "path"=log_to,"replace"=1,"mkdir"=1), logfile)
if (result == ESIG_SUCCESS)
message_user("Data recorded.")
else
message_user("File system error occurred while recording data.")
else
usage()
mainframe_prog_exit
return
else if (opts["l"])
var/time_begin = null
var/time_end = null
if (opts["t"])
var/time_filter = opts["t"]
var/list/tf_list = dd_text2list(time_filter, ":")
if (tf_list.len != 2)
message_user("Invalid timestamp filter format [time_filter], usage: TIMESTAMP_BEGIN:TIMESTAMP_END.")
mainframe_prog_exit
return
time_begin = text2num(tf_list[1])
time_end = text2num(tf_list[2])
if (!isnum(time_begin) || !isnum(time_end))
message_user("Invalid timestamp filter [time_filter].")
mainframe_prog_exit
return
var/datum/computer/folder/logs_folder = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"=log_to))
if (logs_folder == ESIG_NOFILE)
message_user("No recorded data.")
mainframe_prog_exit
return
if (!istype(logs_folder))
message_user("Error: cannot access logs directory. Please check your permissions and try again.")
mainframe_prog_exit
return
var/count = text2num(opts["l"])
if (!count)
message_user("Invalid count: [opts["l"]]")
mainframe_prog_exit
return
if (count < 0)
message_user("Listing the last [count] records (do you honestly expect this to break anything?).")
mainframe_prog_exit
return
if (count > 32)
count = 32
message_user("Listing the last [count] records:")
var/paramsearch = null
if (params.len)
paramsearch = dd_list2text(params, " ")
var/list/records = logs_folder.contents.Copy()
if (!records.len)
message_user("No recorded data.")
else
var/printed = 0
var/now = ticker.round_elapsed_ticks
var/max = -1
var/datum/computer/file/record/C = null
for (var/Q in records)
if (!istype(Q, /datum/computer/file/record))
records -= Q
continue
var/datum/computer/file/record/R = Q
if (!R.fields["door_id"] || !R.fields["timestamp"] || !R.fields["card_name"] || !R.fields["action"] || !R.fields["time_t"] || !R.fields["door_name"])
records -= Q
var/TS = R.fields["timestamp"]
if (!TS)
records -= Q
continue
if (!isnum(TS))
TS = text2num(TS)
R.fields["timestamp"] = TS
if (TS < 0)
records -= Q
continue
if (opts["t"])
if (TS < time_begin || TS > time_end)
records -= Q
continue
if (opts["s"])
if (R.fields["door_id"] != opts["s"])
records -= Q
continue
if (opts["m"])
if (R.fields["action"] != opts["m"])
records -= Q
continue
if (params.len)
if (!findtext(R.fields["card_name"], paramsearch))
records -= Q
continue
var/list/printing = list()
while (printed < count && records.len)
max = -1
for (var/datum/computer/file/record/R in records)
var/TS = R.fields["timestamp"]
if (!isnum(TS))
TS = text2num(TS)
R.fields["timestamp"] = TS
if (R.fields["timestamp"] > max && R.fields["timestamp"] < now - 300)
max = R.fields["timestamp"]
C = R
if (C)
printing += C
records -= C
printed++
else
break
for (var/i = printing.len, i >= 1, i--)
var/datum/computer/file/record/R = printing[i]
if (opts["f"])
message_reply_and_user("[log_to]/[R.name]")
else
message_reply_and_user(accesslog_digest(R))
mainframe_prog_exit
return
/datum/computer/file/mainframe_program/driver/mountable/logreader
name = "logreader"
setup_processes = 1
var/tmp/list/records = list()
var/tmp/archive_path = null
initialize(var/initparams)
if (..())
return
signal_program(1, list("command"=DWAINE_COMMAND_MOUNT, "id"=src.name, "link"="logreader"))
return
process()
return
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/file)
. = ..()
if (!.)
if (data["command"] == DWAINE_COMMAND_REPLY)
if (data["sender_tag"] == "accesslog")
records += data["data"]
return ESIG_USR4
else if (data["sender_tag"] == "tar")
archive_path = data["data"]
return ESIG_USR4
else
return ESIG_GENERIC
else if (data["command"] == DWAINE_COMMAND_MSG_TERM)
message_user(data["data"])
else
return ESIG_GENERIC
return ESIG_SUCCESS
terminal_input(var/data, var/datum/computer/file/theFile)
if (..() || !data)
return 1
var/list/dataList = params2list(data)
if (!dataList || !dataList.len)
return 1
switch (lowertext(dataList["command"]))
if ("record_query")
records.len = 0
var/datum/computer/file/mainframe_program/P = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="/sys/srv/accesslog"))
if (istype(P))
var/list/siglist = list("command"=DWAINE_COMMAND_TSPAWN, "passusr"=1, "path"="/sys/srv/accesslog", "args"=strip_html(dataList["query"]))
signal_program(1, siglist)
// see what i did here? heh? HEH?
// doubly so, it almost sounds like tar gz
var/targs = dd_list2text(records, " ")
archive_path = null
siglist = list("command"=DWAINE_COMMAND_TSPAWN, "passusr"=1, "path"="/bin/tar", "args"="-cqt -- [targs]")
signal_program(1, siglist)
if (!archive_path)
return 1
var/datum/computer/file/archive/archive = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[archive_path]"))
if (!istype(archive))
return 1
message_device("ack", archive)
//archive.dispose() // we don't need that tempfile anymore
return 0
add_file(var/datum/computer/file/theFile)
if (!initialized)
return 0
if (istype(theFile, /datum/computer/file/archive))
var/datum/computer/file/archive/R = theFile
message_device("suppl", R)
theFile.dispose()
return 1
return 0
change_metadata(var/datum/computer/file/file, var/field, var/newval)
return 0
#undef DEFAULT_LOG_PATH
#undef ACCESSLOG_RECORDS_LIMIT
@@ -0,0 +1,949 @@
/*
* The Terminal Connection datum, used to keep track of, well, terminal connections.
*/
/datum/terminal_connection
var/obj/machinery/networked/master = null
var/net_id = null //Network ID of connected device.
var/term_type = null //Terminal type ID of connected device. i.e. PNET_MAINFRAME or HUI_TERMINAL
New(var/obj/machinery/networked/newmaster, var/new_id, var/newterm_type)
..()
if(istype(newmaster))
src.master = newmaster
if(new_id)
src.net_id = new_id
if(newterm_type)
src.term_type = newterm_type
return
disposing()
master = null
..()
/*
* The physical mainframe, communication through wired network.
*/
/obj/machinery/networked/mainframe
name = "Mainframe"
desc = "A mainframe computer. It's pretty big!"
density = 1
anchored = 1
icon_state = "dwaine"
device_tag = "PNET_MAINFRAME"
timeout = 30
req_access = list(access_heads)
var/list/terminals = list() //list of netIDs/terminal profiles of connected terminal devices.
var/list/processing = list() //As the name implies, this is the list of programs that should be updated every process call on the mainframe object.
var/list/timeout_list = list() //Terminals currently set to time out
var/datum/computer/file/mainframe_program/os/os = null //Ref to current operating system program
var/datum/computer/file/mainframe_program/os/bootstrap = null //Ref to bootloader program, instanciated when a main OS cannot be located on the memory card
var/datum/computer/folder/runfolder = null //Storage folder for currently running programs.
var/obj/item/disk/data/memcard/hd = null //Only internal storage for the mainframe--core memory, used as primary storage.
var/posted = 1 //Have we run through the POST sequence? Set to 1 initially so it doesn't freak out during map powernet generation.
var/setup_drive_size = 4096
var/setup_drive_type = /obj/item/disk/data/memcard //Use this path for the hd
var/setup_bootstrap_path = /datum/computer/file/mainframe_program/os/bootstrap //The bootstrapping system.
var/setup_os_string = null
power_usage = 500
zeta
//setup_starting_os = /datum/computer/file/mainframe_program/os/main_os
setup_drive_type = /obj/item/disk/data/memcard/main2
New()
..()
spawn(10)
src.net_id = generate_net_id(src)
if(!src.link)
var/turf/T = get_turf(src)
var/obj/machinery/power/data_terminal/test_link = locate() in T
if(test_link && !test_link.is_valid_master(test_link.master))
src.link = test_link
src.link.master = src
if(!hd && (setup_drive_size > 0))
if(src.setup_drive_type)
src.hd = new src.setup_drive_type
src.hd.set_loc(src)
else
src.hd = new /obj/item/disk/data/memcard(src)
src.hd.file_amount = src.setup_drive_size
if(ispath(setup_bootstrap_path))
src.bootstrap = new setup_bootstrap_path
src.bootstrap.master = src
sleep(54)
src.posted = 0
src.post_system()
return
disposing()
if (terminals)
for (var/datum/conn in terminals)
conn.dispose()
terminals.len = 0
terminals = null
if (processing)
processing.len = 0
processing = null
if (timeout_list)
timeout_list.len = 0
timeout_list = null
if (os)
os.dispose()
os = null
if (bootstrap)
bootstrap.dispose()
bootstrap = null
if (runfolder)
runfolder = null
if (hd)
hd.dispose()
hd = null
..()
attack_ai(mob/user as mob)
return
attack_hand(mob/user as mob)
if (user.stat || user.restrained())
return
if(stat & BROKEN)
if(!src.hd)
return
boutput(user, "<span style=\"color:red\">The mainframe is trashed, but the memory core could probably salvaged.</span>")
return
var/dat = "<html><head><title>Mainframe Access Panel</title></head><body><hr>"
dat += "<b>ACTIVE:</b> [src.os ? "YES" : "NO"]<br>"
dat += "<b>BOOTING:</b> [(src.bootstrap && src.os && istype(src.os, src.bootstrap.type)) ? "YES" : "NO"]<br><br>"
if(stat & NOPOWER)
dat += "<b>Memory Core:</b> <a href='?src=\ref[src];core=1'>[src.hd ? "LOADED" : "---------"]</a><br>"
dat += "Core Shield Maglock is <b>OFF</b><hr>[net_switch_html()]<hr>"
else
dat += "<b>Memory Core:</b> [src.hd ? "LOADED" : "---------"]<br>"
dat += "Core Shield Maglock is <b>ON</b><hr>"
user << browse(dat, "window=mainframe;size=245x202")
onclose(user, "mainframe")
return
Topic(href, href_list)
if(stat & BROKEN)
return
if (istype(src.loc, /turf) && get_dist(src, usr) <= 1)
if (usr.stat || usr.restrained())
return
usr.machine = src
if(href_list["core"])
if(!(stat & NOPOWER))
boutput(usr, "<span style=\"color:red\">The electromagnetic lock is still on!</span>")
return
//Ai/cyborgs cannot physically remove a memory board from a room away.
if(istype(usr,/mob/living/silicon) && get_dist(src, usr) > 1)
boutput(usr, "<span style=\"color:red\">You cannot physically touch the board.</span>")
return
if(src.hd)
src.hd.set_loc(src.loc)
boutput(usr, "You remove the memory core from the mainframe.")
usr.unlock_medal("421", 1)
stat |= MAINT
src.unload_all()
src.hd = null
src.runfolder = null
src.posted = 0
else
var/obj/item/I = usr.equipped()
if (istype(I, /obj/item/disk/data/memcard))
usr.drop_item()
I.set_loc(src)
src.hd = I
stat &= ~MAINT
boutput(usr, "You insert [I].")
else if (href_list["dipsw"] && (stat & NOPOWER))
var/switchNum = text2num(href_list["dipsw"])
if (switchNum < 1 || switchNum > 8)
return 1
switchNum = round(switchNum)
if (net_number & switchNum)
net_number &= ~switchNum
else
net_number |= switchNum
src.updateUsrDialog()
src.add_fingerprint(usr)
return
attackby(obj/item/W as obj, mob/user as mob)
if (istype(W, /obj/item/crowbar))
if (!(stat & BROKEN))
return
if (!src.hd)
boutput(usr, "<span style=\"color:red\">The memory core has already been removed.</span>")
return
stat |= MAINT
src.unload_all()
src.hd.set_loc(src.loc)
src.hd = null
src.posted = 0
boutput(usr, "You pry out the memory core.")
src.updateUsrDialog()
return
else
..()
return
process()
..()
if(stat & (NOPOWER|BROKEN|MAINT) || !processing)
return
use_power(500)
if(prob(3))
spawn(1)
playsound(src.loc, pick(ambience_computer), 50, 1)
for (var/progIndex = 1, progIndex <= src.processing.len, progIndex++)
var/datum/computer/file/mainframe_program/prog = src.processing[progIndex]
if (prog)
if (prog.disposed)
src.processing[progIndex] = null
continue
prog.process()
/*
for(var/datum/computer/file/mainframe_program/P in src.processing)
if (P)
P.process()
*/
if(src.timeout == 0)
src.timeout = initial(src.timeout)
src.timeout_alert = 0
for(var/timed in timeout_list)
var/datum/terminal_connection/conn = src.terminals[timed]
src.terminals -= timed
if(src.os && conn)
src.os.closed_connection(conn)
//qdel(conn)
if (conn)
conn.dispose()
else
src.timeout--
if(src.timeout <= 5 && !src.timeout_alert)
src.timeout_alert = 1
src.timeout_list = src.terminals.Copy()
for(var/id in timeout_list)
src.post_status(id, "command","term_ping","data","reply")
return
receive_signal(datum/signal/signal)
if(stat & (NOPOWER|BROKEN|MAINT) || !src.link)
return
if(!signal || !src.net_id || signal.encryption)
return
if(signal.transmission_method != TRANSMISSION_WIRE) //No radio for us thanks
return
var/target = signal.data["sender"]
//They don't need to target us specifically to ping us.
//Otherwise, if they aren't addressing us, ignore them
if(signal.data["address_1"] != src.net_id)
if((signal.data["address_1"] == "ping") && ((signal.data["net"] == null) || ("[signal.data["net"]]" == "[src.net_number]")) && signal.data["sender"])
spawn(5) //Send a reply for those curious jerks
src.post_status(target, "command", "ping_reply", "device", src.device_tag, "netid", src.net_id)
return
var/sigcommand = lowertext(signal.data["command"])
if(!sigcommand || !signal.data["sender"])
return
switch(sigcommand)
if("term_connect") //Terminal interface stuff.
if(target in src.terminals)
//something might be wrong here, disconnect them!
var/datum/terminal_connection/conn = src.terminals[target]
src.terminals.Remove(target)
if(src.os)
src.os.closed_connection(conn)
//qdel(conn)
if (conn)
conn.dispose()
spawn(3)
src.post_status(target, "command","term_disconnect")
return
var/devtype = signal.data["device"]
if(!devtype) return
var/datum/terminal_connection/newconn = new /datum/terminal_connection(src, target, devtype)
src.terminals[target] = newconn //Accept the connection!
if(signal.data["data"] != "noreply")
src.post_status(target, "command","term_connect","data","noreply")
//also say hi.
if(src.os)
var/datum/computer/theFile = null
if (signal.data_file)
theFile = signal.data_file.copy_file()
src.os.new_connection(newconn, theFile)
//qdel(file)
if (theFile)
theFile.dispose()
return
if("term_message","term_file")
if(!(target in src.terminals)) //Huh, who is this?
return
//src.visible_message("[src] beeps.")
var/data = signal.data["data"]
var/file = null
if(signal.data_file)
file = signal.data_file.copy_file()
if(src.os && data)
src.os.term_input(data, target, file)
//qdel(file)
return
if ("term_break")
if (!(target in src.terminals))
return
if (src.os)
src.os.term_input(1, target, null, 1)
if("term_ping")
if(!(target in src.terminals))
spawn(3) //Go away!!
src.post_status(target, "command","term_disconnect")
return
if(target in src.timeout_list)
src.timeout_list -= target
if(signal.data["data"] == "reply")
src.post_status(target, "command","term_ping")
return
if("term_disconnect")
if(target in src.terminals)
var/datum/terminal_connection/conn = src.terminals[target]
if(src.os)
src.os.closed_connection(conn)
src.terminals -= target
//qdel(conn)
if (conn)
conn.dispose()
return
if("ping_reply")
if(src.os)
os.ping_reply(signal.data["netid"],signal.data["device"])
return
return
power_change()
if(stat & BROKEN)
icon_state = initial(src.icon_state)
src.icon_state += "b"
return
else if(powered())
icon_state = initial(src.icon_state)
stat &= ~NOPOWER
src.post_system() //Will simply return if POSTed already.
else
spawn(rand(0, 15))
icon_state = initial(src.icon_state)
src.icon_state += "0"
stat |= NOPOWER
src.posted = 0
src.os = null
clone()
var/obj/machinery/networked/mainframe/cloneframe = ..()
if (!cloneframe)
return
cloneframe.setup_bootstrap_path = src.setup_bootstrap_path
cloneframe.setup_os_string = src.setup_os_string
if (src.hd)
cloneframe.hd = src.hd.clone()
return cloneframe
meteorhit(var/obj/O as obj)
if(stat & BROKEN)
//dispose()
src.dispose()
set_broken()
var/datum/effects/system/harmless_smoke_spread/smoke = new /datum/effects/system/harmless_smoke_spread()
smoke.set_up(5, 0, src)
smoke.start()
return
ex_act(severity)
switch(severity)
if(1.0)
//dispose()
src.dispose()
return
if(2.0)
if (prob(50))
set_broken()
if(3.0)
if (prob(25))
set_broken()
else
return
blob_act(var/power)
if (prob(power * 2.5))
set_broken()
src.density = 0
proc
run_program(datum/computer/file/mainframe_program/program, var/datum/mainframe2_user_data/user, var/datum/computer/file/mainframe_program/caller, var/runparams)
if(!hd || !program || (!program.holder && program.needs_holder))
return 0
if(!runfolder)
for (var/datum/computer/folder/F in src.hd.root.contents)
if (F.name == "proc")
runfolder = F
runfolder.metadata["permission"] = COMP_HIDDEN
break
if(!runfolder)
runfolder = new /datum/computer/folder( )
runfolder.name = "proc"
runfolder.metadata["permission"] = COMP_HIDDEN
if(!hd.root.add_file( runfolder ))
//qdel(runfolder)
runfolder.dispose()
return 0
if (!(program in src.processing))
program = program.copy_file()
if(!runfolder.add_file( program ))
//qdel(program)
program.dispose()
return 0
if(program.master != src)
program.master = src
if(istype(program, /datum/computer/file/mainframe_program/os))
if (!src.os)
src.os = program
else
//qdel(program)
program.dispose()
return 0
if(!(program in src.processing))
if (src.os == program && src.processing.len)
src.processing.len++
for (var/x = src.processing.len, x > 0, x--)
var/datum/computer/file/mainframe_program/P = src.processing[x]
if (istype(P))
P.progid = x+1
if (src.processing.len == x)
src.processing.len++
src.processing[x+1] = P
src.processing[1] = src.os
src.os.progid = 1
else
var/success = 0
for (var/x = 1, x <= src.processing.len, x++)
if (!isnull(src.processing[x]))
continue
src.processing[x] = program
program.progid = x
success = 1
break
if (!success)
src.processing += program
program.progid = src.processing.len
if (user)
program.useracc = user
user.current_prog = program
if (caller)
program.parent_task = caller
program.initialize(runparams)
//program.initialized = 1
return program
unload_program(datum/computer/file/mainframe_program/program)
if(!program)
return 0
if(program == src.os)
return 0
if (src.processing[src.processing.len] == program)
src.processing -= program
else if (program.progid && program.progid <= src.processing.len)
src.processing[program.progid] = null
// if(src.active_program == program)
// src.active_program = src.host_program
program.initialized = 0
program.unloaded()
if (program.holding_folder == src.runfolder)
//qdel(program)
program.dispose()
return 1
unload_all()
src.os = null
for(var/datum/computer/file/mainframe_program/M in src.processing)
src.unload_program(M)
return
delete_file(datum/computer/file/theFile)
if((!theFile) || (!theFile.holder) || (theFile.holder.read_only))
//boutput(world, "Cannot delete :(")
return 0
//qdel(file)
theFile.dispose()
return 1
relay_progsignal(var/datum/computer/file/mainframe_program/caller, var/progid, var/list/data = null, var/datum/computer/file/file)
if (progid < 1 || progid > src.processing.len || !caller)
return ESIG_GENERIC
var/datum/computer/file/mainframe_program/P = src.processing[progid]
if(!istype(P))
return ESIG_GENERIC
var/callID = src.processing.Find(caller)
return P.receive_progsignal(callID, data, file)
set_broken()
icon_state = initial(src.icon_state)
icon_state += "b"
stat |= BROKEN
reconnect_all_devices()
for (var/device_id in src.terminals)
var/datum/terminal_connection/conn = src.terminals[device_id]
if (istype(conn) && cmptext(conn.term_type, "hui_terminal"))
continue
reconnect_device(device_id)
return ESIG_SUCCESS
reconnect_device(var/device_netid)
if (!device_netid)
return ESIG_GENERIC
device_netid = lowertext(device_netid)
if (device_netid in src.terminals)
var/datum/terminal_connection/conn = src.terminals[device_netid]
if(src.os)
src.os.closed_connection(conn)
src.terminals -= device_netid
//qdel(conn)
if (conn)
conn.dispose()
src.post_status(device_netid, "command", "term_connect", "device", src.device_tag)
return ESIG_SUCCESS
/*
* Overview of startup process:
* If we already have an OS reference, initialize it and return.
* If not, begin looking for an OS file in memory (Of type /datum/computer/file/mainframe_program/os)
* Ideally, there is a folder named "sys" in the root directory to look in.
* If we can't find the OS there, we pass control over the our bootstrapping program.
*/
post_system()
if(src.posted || !src.hd)
return
src.posted = 1
if(src.os) //Let the starting programs set up vars or whatever
src.os.initialize()
else
if (src.runfolder)
//qdel(src.runfolder)
src.runfolder.dispose()
src.runfolder = null
if(src.hd && src.hd.root)
var/datum/computer/folder/sysfolder = null
for (var/datum/computer/folder/F in src.hd.root.contents)
if (F.name == "sys")
sysfolder = F
break
if (sysfolder)
var/datum/computer/file/mainframe_program/os/newos = locate(/datum/computer/file/mainframe_program/os) in sysfolder.contents
if (istype(newos))
src.visible_message("[src] beeps")
newos.initialized = 0
src.run_program(newos)
return
if(!istype(src.bootstrap))
src.bootstrap = new src.setup_bootstrap_path
//Run the bootstrapping code!
if(bootstrap)
src.run_program(bootstrap)
return
/*
* Bootstrapping System
*/
/datum/computer/file/mainframe_program/os/bootstrap
name = "NETBOOT"
size = 4
needs_holder = 0
var/tmp/list/known_banks = list()
var/tmp/current = null //Net ID of current bank.
var/tmp/stage = 0
var/tmp/ping_wait = 0
var/tmp/stage_wait = 0
var/tmp/rescan_wait = 0
var/setup_system_directory = "/sys"
var/setup_driver_directory = "/sys/drvr"
var/setup_bin_directory = "/bin"
disposing()
known_banks = null
..()
initialize()
if(..())
return
src.known_banks.len = 0
src.clear_core()
src.find_existing_databanks()
src.stage_wait = 4
src.stage = 1
src.ping_wait = 4
src.current = null
spawn(1)
src.master.post_status("ping","data","NETBOOT","net","[src.master.net_number]")
return
process()
if(..())
return
if(src.ping_wait)
src.ping_wait--
return
if(src.rescan_wait)
if (--src.rescan_wait < 1)
src.initialized = 0
src.initialize()
return
if(src.stage_wait)
src.stage_wait--
if(stage_wait <= 0)
stage = 0
if(!stage)
if(!known_banks.len)
src.master.os = null
src.handle_quit()
//qdel (src)
src.dispose()
return
new_current()
src.message_term("command=bootreq",current)
return
return
new_connection(datum/terminal_connection/conn)
if(!istype(conn))
return
if(conn.term_type == "PNET_DATA_BANK" && !(conn.net_id in known_banks) )
known_banks += conn.net_id
return
closed_connection(datum/terminal_connection/conn)
if(!istype(conn)) return
var/del_netid = conn.net_id
if(del_netid in src.known_banks)
src.known_banks -= del_netid
return
ping_reply(var/senderid,var/sendertype)
if(..() || !ping_wait)
return
if( !(senderid in master.terminals) && (sendertype == "PNET_DATA_BANK" || sendertype == "HUI_TERMINAL"))
spawn(rand(1,4))
src.master.post_status(senderid,"command","term_connect","device",master.device_tag)
return
term_input(var/data, var/termid, var/datum/computer/file/the_file)
if(..() || !stage)
return
var/datum/terminal_connection/conn = master.terminals[termid]
if(!conn || !conn.term_type)
return
var/device_type = conn.term_type
if(device_type == "PNET_DATA_BANK")
var/list/commandlist = params2list(data)
if(!commandlist || !commandlist["command"])
return
var/command = lowertext(commandlist["command"])
//boutput(world, "\[[conn.net_id]]")
switch(command)
if("register")
return
if("file")
//boutput(world, "FILE")
if(!the_file)
new_current()
return
var/datum/computer/file/archive/arc = the_file.copy_file()
if(!istype(arc))
//qdel(arc)
arc.dispose()
new_current()
return
var/datum/computer/file/mainframe_program/os/newos = locate() in arc.contained_files
if(!istype(newos))
//qdel(arc)
arc.dispose()
new_current()
return
var/datum/computer/folder/sysdir = parse_directory(src.setup_system_directory, src.holder.root, 1)
var/datum/computer/folder/drivedir = parse_directory(src.setup_driver_directory, src.holder.root, 1)
var/datum/computer/folder/bindir = parse_directory(src.setup_bin_directory, src.holder.root, 1)
var/datum/computer/folder/srvdir = parse_directory("srv", sysdir, 1)
if(!sysdir || !drivedir || !bindir || !srvdir)
master.visible_message("[master] boops")
master.os = null
src.handle_quit()
//dispose()
src.dispose()
return
for(var/datum/computer/file/mainframe_program/MP in arc.contained_files)
if (istype(MP, /datum/computer/file/mainframe_program/os))
continue
var/datum/computer/file/mainframe_program/MP_copy = MP.copy_file()
if (istype(MP_copy, /datum/computer/file/mainframe_program/driver))
if(get_computer_datum(MP_copy.name, drivedir))
continue
if(!drivedir.add_file(MP_copy))
//qdel(MP_copy)
MP_copy.dispose()
break
else if (istype(MP_copy, /datum/computer/file/mainframe_program/utility))
if(get_computer_datum(MP_copy.name, bindir))
continue
if(!bindir.add_file(MP_copy))
///qdel(MP_copy)
MP_copy.dispose()
break
else if (istype(MP_copy, /datum/computer/file/mainframe_program/srv))
if(get_computer_datum(MP_copy.name, sysdir))
continue
if(!srvdir.add_file(MP_copy))
MP_copy.dispose()
else
if(get_computer_datum(MP_copy.name, sysdir))
continue
if(!sysdir.add_file(MP_copy))
//qdel(MP_copy)
MP_copy.dispose()
break
newos = newos.copy_file()
if(sysdir.add_file(newos))
master.os = null
//qdel(arc)
arc.dispose()
master.visible_message("[master] beeps")
master.run_program(newos)
src.handle_quit()
//dispose()
src.dispose()
return
else
//qdel(arc)
//qdel(newos)
if (arc)
arc.dispose()
if (newos)
newos.dispose()
/*
src.quit()
qdel(src)
*/
master.visible_message("[master] boops sadly.")
src.rescan_wait = 20
return
if ("status")
src.stage_wait = 1
return
return
proc
new_current() //Move on to a new current in the list.
if(src.current)
src.known_banks.Cut(1,2)
src.current = null
if(!known_banks.len)
/*
src.master.os = null
src.quit()
qdel(src)
*/
src.rescan_wait = 20
return
stage_wait = 4
stage = 1
src.current = known_banks[1]
return
clear_core() //Clear the core memory board.
if(!src.holder || !src.holder.root)
return 0
for(var/datum/computer/C in src.holder.root)
if(C == src || C == src.holding_folder)
continue
//qdel(C)
C.dispose()
return 1
find_existing_databanks() //Find databank connections already in master.terminals
if(!src.master)
return
for(var/x in master.terminals)
var/datum/terminal_connection/conn = master.terminals[x]
if(!istype(conn))
continue
master.terminals -= x
//qdel(conn)
conn.dispose()
var/tempx = x
spawn(rand(1,4))
src.master.post_status(tempx, "command", "term_disconnect")
return
/*
* A little mass message proc for some SPOOKY ANTICS
*/
/proc/send_spooky_mainframe_message(var/the_message, var/a_spooky_custom_name)
if (!the_message)
return 1
for (var/obj/machinery/networked/mainframe/aMainframe in world)
if (aMainframe.z != 1)
continue
if (!aMainframe.os || !hascall(aMainframe.os, "message_all_users"))
continue
aMainframe.os:message_all_users(the_message, a_spooky_custom_name, 1)
return 0
return 2
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,969 @@
//CONTENTS
//User shell
//User shell program
//Allows execution of various mainframe programs, as well as some scripting and a set of built-in commands.
/datum/computer/file/mainframe_program/shell
name = "Msh"
size = 8
executable = 0
var/tmp/piping = 0
var/tmp/pipetemp = ""
var/tmp/scriptline = 0
var/tmp/list/shscript
var/tmp/list/scriptvars
var/tmp/scriptstat = 0
var/tmp/script_iteration = 1
var/tmp/list/stack = list()
var/tmp/list/previous_shscripts
var/tmp/list/previous_scriptline
var/tmp/previous_pipeout
var/tmp/suppress_out = 0
var/setup_helprec_name = "help"
var/setup_max_piped_commands = 16
#define SCRIPT_IF_TRUE 1
#define SCRIPT_IN_LOOP 2
#define MAX_SCRIPT_ITERATIONS 2048
#define MAX_STACK_DEPTH 128
#define EVAL_BOOL_TRUE 1
#define EVAL_BOOL_FALSE 0
#define ERR_STACK_OVER -1
#define ERR_STACK_UNDER -2
#define ERR_UNDEFINED -3
initialize()
if(..() || !useracc)
return
previous_pipeout = null
piping = 0
suppress_out = 0
pipetemp = ""
scriptline = 0
script_iteration = 1
scriptstat = 0
scriptvars = list()
shscript = list()
previous_shscripts = list()
previous_scriptline = list()
if (useracc.user_file)
if(!read_user_field("name"))
write_user_field("name", useracc.user_name)
useracc.user_file.fields["curpath"] = "/home/usr[read_user_field("name")]"
message_user("[read_user_field("name")]@DWAINE - [time2text(world.realtime, "hh:mm MM/DD/53")]|nType \"help\" for command listing.", "multiline")
return
process()
if (..() || !useracc)
return
script_process()
return
input_text(var/text, var/scripting = 0)
//boutput(world, "input_text([text], [scripting])")
if(..() || !useracc || ((scripting != 0) != (scriptline != 0)))
return 1
var/list/subcommands = list()
var/list/piped_list = command2list(text, "^", scriptvars, subcommands)//scripting ? scriptvars : null)
piped_list.len = min(piped_list.len, setup_max_piped_commands)
piping = piped_list.len
pipetemp = ""
var/script_counter = 0
while(piped_list.len && (script_counter < MAX_SCRIPT_ITERATIONS))
script_counter++
text = piped_list[1]
piped_list -= piped_list[1]
piping--
var/subPlace = findtext(text, "_sub")
while (subPlace)
var/subIndex = text2num( copytext( text, subPlace+4, subPlace+5) )
if (isnum(subIndex) && subIndex > 0 && subIndex <= subcommands.len)
previous_pipeout = ""
suppress_out = 1
if (!input_text(subcommands[subIndex], 0))
if (dd_hassuffix(previous_pipeout, "|n"))
previous_pipeout = copytext(previous_pipeout, 1, -2)
text = "[copytext(text, 1, subPlace)][previous_pipeout][copytext(text, subPlace+5)]"
//boutput(world, " --> \"[text]\"")
suppress_out = 0
else
suppress_out = 0
return 1
subPlace = findtext(text, "_sub")
var/list/command_list = parse_string(text, (scripting ? src.scriptvars : null))
var/command = lowertext(command_list[1])
command_list.Cut(1,2) //Remove the command that we are now processing.
while (!command && command_list.len)
command = command_list[1]
command_list.Cut(1,2)
var/current = read_user_field("curpath")
if (!dd_hassuffix(current, "/") && current != "/")
current = "[current]/"
if (execpath("/bin/[command]", current, command, command_list, scripting ? script_iteration : 0))
continue
else
switch(execpath("[current][dd_hasprefix(command,"/") ? copytext(command, 1) : command]", current, command, command_list, scripting ? script_iteration : 0))
if (1)
continue
if (2)
if (script_iteration < 2)
script_process()
return 0
if (3)
message_user("Error: Stack overflow.")
return 1
switch(lowertext(command))
if ("eval")
var/result = null
var/pipe_result = (command_list.len == 1)
if (!command_list.len)
continue
if (stack)
stack.len = 0
else
stack = list()
switch (script_evaluate2(command_list, 0))
if (0,1)
if (stack.len)
result = stack[stack.len]
else
result = 0
if (ERR_STACK_OVER)
message_user("Error: Stack overflow.")
return 1
if (ERR_STACK_UNDER)
message_user("Error: Stack underflow.")
return 1
if (ERR_UNDEFINED)
message_user("Error: Undefined result.")
return 1
if (piping && pipe_result)
pipetemp = "[result]"
else if (!scripting && !isnull(result))
message_user("[result]")
continue
if ("goonsay")
var/anger_text = null
if (pipetemp)
anger_text = pipetemp
if(istype(command_list) && (command_list.len > 0))
anger_text += dd_list2text(command_list, " ")
if (piping && piped_list.len && (ckey(piped_list[1]) != "break") )
pipetemp = anger_text
else
if (!anger_text)
anger_text = "A clown? On a space station? what|n"
else if (!dd_hassuffix(anger_text, "|n"))
anger_text += "|n"
message_user("[anger_text] __________|n(--\[ .]-\[ .] /|n(_______0__)", "multiline")
continue
if ("echo")
var/echo_text = null
if (pipetemp)
echo_text = pipetemp
if(istype(command_list) && (command_list.len > 0))
echo_text += dd_list2text(command_list, " ")
if (piping && piped_list.len && (ckey(piped_list[1]) != "break") )
pipetemp = echo_text
else
if (echo_text && !dd_hassuffix(echo_text, "|n"))
echo_text += "|n"
message_user(echo_text, "multiline")
continue
//User identification & communication commands
if ("who")
var/whotext = null
var/list/wholist = signal_program(1, list("command"=DWAINE_COMMAND_ULIST))
if (istype(wholist))
for (var/uid in wholist)
whotext += "[uid]-[wholist[uid]]|n"
else
whotext = "Error: Unable to determine current users."
if (piping)
pipetemp = whotext
else
if (!whotext)
whotext = "Error: Unable to determine current users."
message_user(whotext, "multiline")
continue
if ("mesg")
var/input = (command_list.len ? command_list[1] : null)
if (pipetemp)
input = pipetemp
if (piping)
if (input)
switch (lowertext(input))
if ("y")
if (write_user_field("accept_msg","1"))
pipetemp = "Now allowing messages."
else
pipetemp = "Error: Unable to write user configuration."
if ("n")
if (write_user_field("accept_msg","0"))
pipetemp = "Now disallowing messages."
else
pipetemp = "Error: Unable to write user configuration."
else
pipetemp = "Error: Invalid argument for mesg (Must be \"y\" or \"n\")"
else
pipetemp = "is [read_user_field("accept_msg") == "1" ? "y" : "n"]"
else
if (input)
switch (lowertext(input))
if ("y")
if (write_user_field("accept_msg","1"))
message_user("Now allowing messages.")
else
message_user("Error: Unable to write user configuration.")
if ("n")
if (write_user_field("accept_msg","0"))
message_user("Now disallowing messages.")
else
message_user("Error: Unable to write user configuration.")
else
message_user("Error: Invalid argument for mesg (Must be \"y\" or \"n\")")
else
message_user("is [read_user_field("accept_msg") == "1" ? "y" : "n"]")
continue
if ("talk")
if (pipetemp)
if(istype(command_list))
command_list += dd_text2list(pipetemp, " ")
if (command_list.len < 2)
message_user("Error: Insufficient arguments for Talk (Requires Target ID and Message).")
return 1
var/targetUser = lowertext(command_list[1])
command_list.Cut(1,2)
switch (signal_program(1, list("command"=DWAINE_COMMAND_UMSG, "term"=targetUser, data=dd_list2text(command_list, " "))))
if (ESIG_SUCCESS)
continue
if (ESIG_NOTARGET)
message_user("Error: Invalid Target ID")
return 1
if (ESIG_IOERR)
if (piping)
pipetemp = "Error: Message refused by Target."
else
message_user("Error: Message refused by Target.")
continue
else
message_user("Error: Unexpected response from kernel.")
return 1
continue
//SCRIPTING COMMANDS FOLLOW:
//If - Evaluate an expression. If true, set SCRIPT_IF_TRUE in scriptstat and continue piping
//if false, unset SCRIPT_IF_TRUE and continue to the next line
//if null (From an evaluation error or invalid input), halt the script
if ("if")
if (!command_list.len)
return 1
switch (script_evaluate2(command_list, 1))
if (1)
pipetemp = null
scriptstat |= SCRIPT_IF_TRUE
var/elsePosition = piped_list.Find("else")
if (elsePosition)
piped_list.Cut(elsePosition)
piping = piped_list.len
continue //Continue processing any piped commands following this.
if (0)
scriptstat &= ~SCRIPT_IF_TRUE
var/elsePosition = piped_list.Find("else")
if (elsePosition)
piped_list.Cut(1,elsePosition+1)
piping = piped_list.len
pipetemp = null
continue
return 0 //Move to the next line of the script, dropping any following commands on this line.
if (null)
return 1
if ("else")
if (scriptstat & SCRIPT_IF_TRUE)
return 0
continue
if ("while")
if (!command_list.len || (scriptstat & SCRIPT_IN_LOOP))
return 1
switch (script_evaluate2(command_list, 1))
if (1)
scriptstat |= SCRIPT_IN_LOOP
continue
if (0)
scriptstat &= ~SCRIPT_IN_LOOP
return 0
else
return 1
if ("break")
return 1
if ("sleep")
if (!command_list.len)
continue
. = text2num(command_list[1])
if (!isnum(.) || . < 0)
continue
sleep ( max(0, min(., 30)) )
continue
if ("help", "man")
var/datum/computer/file/record/helpRec = signal_program(1, list("command"=DWAINE_COMMAND_CONFGET,"fname"=setup_helprec_name))
if (istype(helpRec))
var/target_entry = "index"
if (command_list.len && ckey(command_list[1]))
target_entry = lowertext(command_list[1])
if (target_entry in helpRec.fields)
message_user("[capitalize(target_entry)]: [helpRec.fields[target_entry]]", "multiline")
else
message_user("Error: Unknown topic.")
else
message_user("Error: Help library missing or invalid.")
continue
if ("logout","logoff")
message_user("Thank you for using DWAINE!", "clear")
mainframe_prog_exit
return 1
else
if (pipetemp)
var/prefixroot = dd_hasprefix(command, "/")
if (!prefixroot)
command = "[current]" + ((dd_hassuffix(current, "/") || current == "/") ? null : "/") + command
var/list/templist = dd_text2list(command, "/")
if (!templist.len)
message_user("Syntax error.")
break
var/recname = null
recname = copytext(templist[templist.len], 1, 16)
while (dd_hasprefix(recname, " "))
recname = copytext(recname, 2)
templist.len--
command = dd_list2text(templist, "/")
if (!recname)
recname = "out"
if ((prefixroot || !command) && !dd_hasprefix(command, "/"))
command = "/[command]"
//boutput(world, "here is the path: \"[command]\" and the name \"[recname]\"")
var/datum/computer/file/record/rec = new /datum/computer/file/record( )
rec.fields = dd_text2list(pipetemp, "|n")
rec.name = recname
rec.metadata["owner"] = read_user_field("name")
rec.metadata["permission"] = COMP_ALLACC
if (signal_program(1, list("command"=DWAINE_COMMAND_FWRITE,"path"=command, "append"=1), rec) != ESIG_SUCCESS)
message_user("Unable to pipe stream to file.")
//qdel(rec)
rec.dispose()
break
continue
message_user("Syntax error.")
return 1
//message_user("[dirpath]$ " + text)
previous_pipeout += pipetemp
return 0
proc
execpath(var/fpath, var/current, var/command, var/list/command_list, var/scripting=0)
//boutput(world, "execpath([fpath], [current], [command], ,[scripting])")
var/datum/computer/file/record/exec = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"=fpath))
if (istype(exec, /datum/computer/file/mainframe_program))
var/list/siglist = list("command"=DWAINE_COMMAND_TSPAWN, "passusr"=1, "path"=fpath)//"[current][command]")
if (command_list.len)
siglist["args"] = strip_html(dd_list2text(command_list, " ")) + (pipetemp ? " [pipetemp]" : null)
else if (pipetemp)
siglist["args"] = pipetemp
pipetemp = ""
signal_program(1, siglist)
//qdel(siglist)
return 1
else if (istype(exec) && (!pipetemp || scripting) && exec.fields && (exec.fields.len > 1) && dd_hasprefix(exec.fields[1], "#!")) //Maybe it's a shell script?
if (previous_shscripts.len + 1 > MAX_SCRIPT_ITERATIONS)
//script_iteration = 1
previous_shscripts.len = 0
return 3
previous_scriptline.Insert(1, scriptline)
scriptline = 1
//script_iteration++
//scriptstat = 0
if (shscript.len)
previous_shscripts.Insert(1, 0)
previous_shscripts[1] = shscript
shscript = script_format( exec.fields.Copy() )
//shscript.Insert(2, script_format( exec.fields.Copy() ))
else
//script_iteration = 1
//scriptline = 1
stack.len = 0
shscript = script_format( exec.fields.Copy() )
scriptvars["su"] = (read_user_field("group") == 0)
command_list.len = min(command_list.len, 8)
. = ""
for (var/i = 1, i <= command_list.len, i++)
scriptvars["arg[i-1]"] = command_list[i]
. += "[. ? " " : null][command_list[i]]"
scriptvars["*"] = .
scriptvars["argc"] = command_list.len
scriptvars["$"] = src.progid
return 2
return 0
script_process()
spawn(0)
while (shscript.len)
for (var/i = 1, i <= 5, i++)
if (!shscript.len)
if (previous_shscripts.len && istype(previous_shscripts[1], /list))
shscript = previous_shscripts[1]
previous_shscripts.Cut(1,2)
scriptline = previous_scriptline[1]
previous_scriptline.Cut(1,2)
break
//Input_text should return 1 on an error, so break if we get that, I guess.
if (src.input_text(shscript[1], script_iteration+1))
message_user("Break at line [scriptline+1]")
shscript.len = 0
scriptline = 0
script_iteration = 1
return
if (scriptstat & SCRIPT_IN_LOOP)
scriptstat &= ~SCRIPT_IN_LOOP //Turn this back off now
continue
if (shscript.len)
shscript.Cut(1, 2)
scriptline++
scriptline *= (shscript.len > 0)
sleep(10)
return
script_format(var/list/scriptlist)
if (!scriptlist || scriptlist.len < 2)
return list()
//The first line should just be #!, so...
scriptlist.Cut(1,2) //Don't need to copy the whole shebang, ha ha get it??
for (var/i = 1, i <= scriptlist.len, i++)
//Check if it's a comment line...
if (dd_hasprefix(trim_left(scriptlist[i]), "#"))
scriptlist.Cut(i, i+1)
i--
continue
scriptlist[i] = dd_replacetext(scriptlist[i], "|", "^")
return scriptlist
//Something something immersion something something 32-bit signed someting fixed point something.
script_clampvalue(var/clampnum)
//return round( min( max(text2num(clampnum), -2147483647), 2147483648) )
return round( min( max(clampnum, -2147483647), 2147483648), 0.01 )
script_isNumResult(var/current, var/result)
if (isnum(text2num(current)) && isnum(text2num(result)))
return 1
return 0
script_evaluate2(var/list/command_stream, return_bool)
stack.len = 0
while (command_stream && command_stream.len)
var/current_command = command_stream[1]
//boutput(world, "current_command = \[[current_command]]")
command_stream.Cut(1,2)
if (text2num(current_command) != null)
if (stack.len > MAX_STACK_DEPTH)
return ERR_STACK_OVER
stack += script_clampvalue( text2num(current_command) )
continue
var/result = null
switch ( lowertext(current_command) )
if ("+") //(1X 2X -- (1X + 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = stack[stack.len] + stack[stack.len-1]
stack[--stack.len] = script_clampvalue( result )
else
result = "[stack[stack.len-1] ][ stack[stack.len] ]"
stack[--stack.len] = result
if ("-") //(1X 2X -- (1X - 2X)
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = stack[stack.len-1] - stack[stack.len]
stack[--stack.len] = script_clampvalue( result )
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
result = copytext(stack[stack.len-1], 1, max( length(stack[stack.len-1]) - stack[stack.len], 1) )
stack[--stack.len] = result
else
return ERR_UNDEFINED
if ("*") //(1X 2X -- (1X * 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = stack[stack.len-1] * stack[stack.len]
stack[--stack.len] = script_clampvalue( result )
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
result = ""
var/repeatCount = stack[stack.len]
while (repeatCount-- > 0)
result += "[stack[stack.len-1]]"
stack[--stack.len] = copytext(result, 1, MAX_MESSAGE_LEN)
else
return ERR_UNDEFINED
if ("/") //(1X 2X -- (1X / 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
if (stack[stack.len] == 0)
return ERR_UNDEFINED
result = stack[stack.len-1] / stack[stack.len]
stack[--stack.len] = script_clampvalue( result )
else if (istext(stack[stack.len]) && istext(stack[stack.len-1]))
var/list/explodedString = dd_text2list("[stack[stack.len-1]]", "[stack[stack.len]]")
if (explodedString.len + stack.len > MAX_STACK_DEPTH)
return ERR_STACK_OVER
// reverselist is getting removed because it didnt actually do anything other than copy the list, if this line actually intended to reverse it, use reverse_list
//explodedString = reverselist(explodedString)
stack.len -= 2
stack += explodedString
else
return ERR_UNDEFINED
if ("%")
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
if (stack[stack.len] == 0)
return ERR_UNDEFINED
result = stack[stack.len-1] % stack[stack.len]
stack[--stack.len] = script_clampvalue( result )
else
return ERR_UNDEFINED
if ("eq") //(1X 2X -- (1X == 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
result = stack[stack.len-1] == stack[stack.len]
stack[--stack.len] = result
if ("ne") //(1X 2X -- (1X != 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
result = stack[stack.len-1] != stack[stack.len]
stack[--stack.len] = result
if ("gt") //(1X 2X -- (1X > 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = stack[stack.len-1] > stack[stack.len]
stack[--stack.len] = result
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
result = length(stack[stack.len-1]) > stack[stack.len]
stack[--stack.len] = result
else if (isnum(stack[stack.len-1]) && istext(stack[stack.len]))
result = stack[stack.len-1] > length(stack[stack.len])
stack[--stack.len] = result
else
result = length(stack[stack.len-1]) > length(stack[stack.len])
stack[--stack.len] = result
if ("ge") //(1X 2X -- (1X >= 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = stack[stack.len-1] >= stack[stack.len]
stack[--stack.len] = result
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
result = length(stack[stack.len-1]) >= stack[stack.len]
stack[--stack.len] = result
else if (isnum(stack[stack.len-1]) && istext(stack[stack.len]))
result = stack[stack.len-1] >= length(stack[stack.len])
stack[--stack.len] = result
else
result = length(stack[stack.len-1]) >= length(stack[stack.len])
stack[--stack.len] = result
if ("lt") //(1X 2X -- (1X < 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = stack[stack.len-1] < stack[stack.len]
stack[--stack.len] = result
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
result = length(stack[stack.len-1]) < stack[stack.len]
stack[--stack.len] = result
else if (isnum(stack[stack.len-1]) && istext(stack[stack.len]))
result = stack[stack.len-1] < length(stack[stack.len])
stack[--stack.len] = result
else
result = length(stack[stack.len-1]) < length(stack[stack.len])
stack[--stack.len] = result
if ("le") //(1X 2X -- (1X <= 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = stack[stack.len-1] <= stack[stack.len]
stack[--stack.len] = result
else if (istext(stack[stack.len-1]) && isnum(stack[stack.len]))
result = length(stack[stack.len-1]) <= stack[stack.len]
stack[--stack.len] = result
else if (isnum(stack[stack.len-1]) && istext(stack[stack.len]))
result = stack[stack.len-1] <= length(stack[stack.len])
stack[--stack.len] = result
else
result = length(stack[stack.len-1]) <= length(stack[stack.len])
stack[--stack.len] = result
if ("and") //(1X 2X -- (1X && 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = script_clampvalue( stack[stack.len] & stack[stack.len-1] )
else
result = stack[stack.len] && stack[stack.len-1]
stack[--stack.len] = result
if ("or") //(1X 2X -- (1X || 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = script_clampvalue( stack[stack.len] | stack[stack.len-1] )
else
result = stack[stack.len] || stack[stack.len-1]
stack[--stack.len] = result
if ("not","!") //(1X -- (!1X))
if (!stack.len)
return ERR_STACK_UNDER
if (isnum(stack[stack.len]))
stack[stack.len] = ~stack[stack.len]
else
stack[stack.len] = !stack[stack.len]
if ("xor","eor") //(1X 2X -- (1X ^ 2X))
if (stack.len < 2)
return ERR_STACK_UNDER
if (script_isNumResult(stack[stack.len], stack[stack.len-1]))
result = stack[stack.len-1] ^ stack[stack.len]
stack[--stack.len] = result
else
return ERR_UNDEFINED
if ("dup")
if (stack.len)
stack.len++
stack[stack.len] = stack[stack.len-1]
if ("&#39;")
var/newString
while (command_stream.len)
if (command_stream[1] == "\'" || command_stream[1] == "&#39;")
command_stream.Cut(1,2)
break
else if (dd_hassuffix(command_stream[1], "&#39;"))
if (newString)
newString += " [copytext( command_stream[1],1,length(command_stream[1]-5) )]"
else
newString = "[copytext( command_stream[1],1,length(command_stream[1]-5) )]"
command_stream.Cut(1,2)
break
else
if (newString)
newString += " [command_stream[1]]"
else
newString = "[command_stream[1]]"
command_stream.Cut(1,2)
if (newString)
stack += newString
if ("d","e","f","x")
if (!stack.len)
return ERR_STACK_UNDER
. = stack[stack.len]
if (!istext(.))
return ERR_UNDEFINED
. = signal_program(1, list("command"=DWAINE_COMMAND_FGET, "path"="[.]"))
if (!istype(., /datum/computer))
. = 0
else if (cmptext(current_command, "d"))
. = istype(., /datum/computer/folder)
else if (cmptext(current_command, "x"))
. = (istype(., /datum/computer/file/mainframe_program))// || (istype(., /datum/computer/file/record) && .:fields && .:fields[1] == "#!"))
else if (cmptext(current_command, "f"))
. = istype(., /datum/computer/file)
else
. = 1
stack[stack.len] = .
continue
if (":")
//todo
continue
if ("value", "to") //Define/Set a variable value.
if (!stack.len)
return ERR_STACK_UNDER
if (!command_stream.len)
return ERR_UNDEFINED
var/valueName = lowertext(ckeyEx(command_stream[1]))
if (!valueName)
return ERR_UNDEFINED
scriptvars["[valueName]"] = stack[stack.len]
stack.len--
else
//boutput(world, "\[[lowertext(ckeyEx(current_command))]] in script vars?")
if (lowertext(ckeyEx(current_command)) in scriptvars) //Lowertext(ckeyEx()) is equivalent to a ckey() that preserves underscores
//boutput(world, "yes")
result = scriptvars["[lowertext( ckeyEx(current_command) )]"]
stack.len++
stack[stack.len] = result
else if (istext(current_command))
stack += "[current_command]"
//boutput(world, "STACK: [english_list(stack)]")
if (return_bool)
if (!stack.len)
return EVAL_BOOL_FALSE
return (stack[stack.len] ? EVAL_BOOL_TRUE : EVAL_BOOL_FALSE)
return 0
receive_progsignal(var/sendid, var/list/data, var/datum/computer/file/theFile)
if (..())
return ESIG_GENERIC
if (!data["command"])
return ESIG_GENERIC
switch (data["command"])
if (DWAINE_COMMAND_MSG_TERM)
if (piping)
pipetemp += data["data"]
else
return message_user(data["data"], data["render"])
if (DWAINE_COMMAND_BREAK)
if (shscript.len)
message_user("Break at line [scriptline+1]")
shscript.len = 0
scriptline = 0
script_iteration = 1
return
if (DWAINE_COMMAND_RECVFILE)
//save to current dir.
var/current_path = read_user_field("curpath")
if (!current_path)
return ESIG_GENERIC
if (!istype(theFile))
return ESIG_NOFILE
return signal_program(1, list("command"=DWAINE_COMMAND_FWRITE, "path"=current_path,"replace"=1,"mkdir"=0), theFile)
return
message_user(var/msg, var/render=null)
if (!useracc)
return ESIG_NOTARGET
if (suppress_out)
if (dd_hassuffix(msg, "|n"))
msg = copytext(msg, 1, -2)
previous_pipeout += dd_replacetext(msg, "|n", " ")
return ESIG_SUCCESS
previous_pipeout += msg
if (render)
return signal_program(parent_task.progid, list("command"=DWAINE_COMMAND_MSG_TERM, "data" = msg, "term" = useracc.user_id, "render" = render) )
else
return signal_program(parent_task.progid, list("command"=DWAINE_COMMAND_MSG_TERM, "data" = msg, "term" = useracc.user_id) )
#undef SCRIPT_IF_TRUE
#undef SCRIPT_IN_LOOP
#undef MAX_SCRIPT_ITERATIONS
#undef MAX_STACK_DEPTH
#undef ERR_STACK_OVER
#undef ERR_STACK_UNDER
#undef ERR_UNDEFINED
@@ -0,0 +1,257 @@
//CONTENTS
//Mainframe 2 memory core
//Mainframe 2 master tape -- TODO
//Mainframe 2 boot tape
//Mainframe 2 artifact research tape.
//Guardbot configuration tape.
//Boot kit box
/*
* Mainframe 2 starting memory
*/
/obj/item/disk/data/memcard/main2
file_amount = 4096
New()
..()
var/datum/computer/folder/newfolder = new /datum/computer/folder( )
newfolder.name = "sys"
newfolder.metadata["permission"] = COMP_HIDDEN
src.root.add_file( newfolder )
newfolder.add_file( new /datum/computer/file/mainframe_program/os/kernel(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/shell(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/login(src) )
var/datum/computer/folder/subfolder = new /datum/computer/folder
subfolder.name = "drvr" //Driver prototypes.
newfolder.add_file( subfolder )
//subfolder.add_file ( new FILEPATH GOES HERE )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/mountable/databank(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/mountable/printer(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/nuke(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/mountable/guard_dock(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/mountable/radio(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/test_apparatus(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/mountable/service_terminal(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/mountable/user_terminal(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/telepad(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/mountable/comm_dish(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/artifact_console(src) )
//subfolder.add_file( new /datum/computer/file/mainframe_program/driver/mountable/logreader(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/driver/apc(src) )
subfolder = new /datum/computer/folder
subfolder.name = "srv"
newfolder.add_file( subfolder )
subfolder.add_file( new /datum/computer/file/mainframe_program/srv/email(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/srv/print(src) )
//subfolder.add_file( new /datum/computer/file/mainframe_program/srv/accesslog(src) )
subfolder.add_file( new /datum/computer/file/mainframe_program/srv/telecontrol(src) )
newfolder = new /datum/computer/folder
newfolder.name = "bin" //Applications available to all users.
newfolder.metadata["permission"] = COMP_ROWNER|COMP_RGROUP|COMP_ROTHER
src.root.add_file( newfolder )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/cd(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/ls(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/rm(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/cat(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/mkdir(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/ln(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/chmod(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/chown(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/su(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/cp(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/mv(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/mount(src) )
//newfolder.add_file( new /datum/computer/file/mainframe_program/utility/grep(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/scnt(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/getopt(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/date(src) )
newfolder.add_file( new /datum/computer/file/mainframe_program/utility/tar(src) )
newfolder = new /datum/computer/folder
newfolder.name = "var"
newfolder.metadata["permission"] = COMP_ROWNER|COMP_RGROUP|COMP_ROTHER
src.root.add_file( newfolder )
newfolder = new /datum/computer/folder
newfolder.name = "tmp"
newfolder.metadata["permission"] = COMP_ALLACC &~(COMP_DOTHER|COMP_DGROUP)
src.root.add_file( newfolder )
/*
subfolder = new /datum/computer/folder
subfolder.name = "log"
subfolder.metadata["permission"] = COMP_ROWNER|COMP_RGROUP
newfolder.add_file( subfolder )
*/
newfolder = new /datum/computer/folder
newfolder.name = "etc"
newfolder.metadata["permission"] = COMP_ROWNER|COMP_RGROUP|COMP_ROTHER
src.root.add_file( newfolder )
subfolder = new /datum/computer/folder
subfolder.name = "mail"
newfolder.add_file( subfolder )
var/datum/computer/file/record/groupRec = new /datum/computer/file/record( )
groupRec.name = "groups"
subfolder.add_file( groupRec )
var/list/randomMails = get_random_email_list()
var/typeCount = 5
while (typeCount-- > 0 && randomMails.len)
var/mailName = pick(randomMails)
var/datum/computer/file/record/mailfile = new /datum/computer/file/record/random_email(mailName)
subfolder.add_file(mailfile)
randomMails -= mailName
/* var/list/randomMailTypes = typesof(/datum/computer/file/record/random_email) - /datum/computer/file/record/random_email
var/typeCount = 5
while (typeCount-- > 0 && randomMailTypes.len)
var/mailType = pick(randomMailTypes)
var/datum/computer/file/record/mailfile = new mailType
subfolder.add_file( mailfile )
randomMailTypes -= mailType*/
newfolder = new /datum/computer/folder
newfolder.name = "mnt"
newfolder.metadata["permission"] = COMP_ROWNER|COMP_RGROUP|COMP_ROTHER
src.root.add_file( newfolder )
newfolder = new /datum/computer/folder
newfolder.name = "conf"
newfolder.metadata["permission"] = COMP_ROWNER|COMP_RGROUP|COMP_ROTHER
src.root.add_file( newfolder )
var/datum/computer/file/record/testR = new
testR.name = "motd"
testR.fields += "Welcome to DWAINE System VI!"
testR.fields += pick("Better than System V ever was.","GLUEEEE GLUEEEE GLUEEEEE","Only YOU can prevent lp0 fires!","Please try not to kill yourselves today.", "Please don't set the lab facilities on fire.")
newfolder.add_file( testR )
newfolder.add_file( new /datum/computer/file/record/dwaine_help(src) )
return
/obj/item/disk/data/tape/master
name = "ThinkTape-'Master Tape'"
//Not sure what all to put here yet.
New()
..()
//First off, buddy stuff.
src.root.add_file( new /datum/computer/file/guardbot_task/security(src) )
src.root.add_file( new /datum/computer/file/guardbot_task/security/purge(src) )
src.root.add_file( new /datum/computer/file/guardbot_task/bodyguard(src) )
src.root.add_file( new /datum/computer/file/guardbot_task/security/area_guard(src) )
src.root.add_file( new /datum/computer/file/guardbot_task/bodyguard/heckle(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/guardbot_interface(src))
src.root.add_file( new /datum/computer/file/record/pr6_readme(src))
src.root.add_file( new /datum/computer/file/record/patrol_script(src))
src.root.add_file( new /datum/computer/file/record/bodyguard_script(src))
src.root.add_file( new /datum/computer/file/record/roomguard_script(src))
src.root.add_file( new /datum/computer/file/record/bodyguard_conf(src))
//Nuke interface, because sometimes the nuke is alround.
src.root.add_file( new /datum/computer/file/mainframe_program/nuke_interface(src) )
//src.root.add_file( new /datum/computer/file/mainframe_program/srv/telecontrol(src) )
for (var/datum/computer/file/F in src.root.contents)
F.metadata["permission"] = COMP_ROWNER|COMP_RGROUP|COMP_ROTHER
readonly
desc = "A reel of magnetic data tape. The casing has been modified so as to prevent write access."
icon_state = "r_tape"
New()
..()
src.read_only = 1
/obj/item/disk/data/tape/boot2
name = "ThinkTape-'OS Backup'"
desc = "A reel of magnetic data tape containing operating software. The casing has been modified so as to prevent write access."
icon_state = "r_tape"
New()
..()
src.root.add_file( new /datum/computer/file/mainframe_program/os/kernel(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/shell(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/login(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/mountable/databank(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/mountable/printer(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/nuke(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/mountable/guard_dock(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/mountable/radio(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/test_apparatus(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/mountable/service_terminal(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/mountable/user_terminal(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/telepad(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/driver/mountable/comm_dish(src) )
//src.root.add_file( new /datum/computer/file/mainframe_program/driver/mountable/logreader(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/cd(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/ls(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/rm(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/cat(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/mkdir(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/ln(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/chmod(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/chown(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/su(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/cp(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/mv(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/mount(src) )
//src.root.add_file( new /datum/computer/file/mainframe_program/utility/grep(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/scnt(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/getopt(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/date(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/utility/tar(src) )
//src.root.add_file( new /datum/computer/file/mainframe_program/srv/accesslog(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/srv/telecontrol(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/srv/email(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/srv/print(src) )
src.read_only = 1
/obj/item/disk/data/tape/test
name = "ThinkTape-'Test'"
desc = "A reel of magnetic data tape containing various test files."
New()
..()
src.root.add_file( new /datum/computer/file/mainframe_program/shell(src) )
src.root.add_file( new /datum/computer/file/document(src) )
src.root.add_file( new /datum/computer/file/record/c3help(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/nuke_interface(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/test_interface(src) )
/obj/item/disk/data/tape/guardbot_tools
name = "ThinkTape-'PR-6S Config'"
desc = "A reel of magnetic data tape containing configuration and support files for PR-6S Guardbuddies."
New()
..()
src.root.add_file( new /datum/computer/file/guardbot_task/security(src) )
src.root.add_file( new /datum/computer/file/guardbot_task/security/purge(src) )
src.root.add_file( new /datum/computer/file/guardbot_task/bodyguard(src) )
src.root.add_file( new /datum/computer/file/guardbot_task/security/area_guard(src) )
src.root.add_file( new /datum/computer/file/mainframe_program/guardbot_interface(src))
src.root.add_file( new /datum/computer/file/record/pr6_readme(src))
src.root.add_file( new /datum/computer/file/record/patrol_script(src))
src.root.add_file( new /datum/computer/file/record/bodyguard_script(src))
src.root.add_file( new /datum/computer/file/record/bodyguard_conf(src))
for (var/datum/computer/file/F in src.root.contents)
F.metadata["permission"] = COMP_ROWNER|COMP_RGROUP|COMP_ROTHER
/obj/item/disk/data/tape/artifact_research
name = "ThinkTape-'Artifact Research'"
desc = "A reel of magnetic data tape containing modern research software."
New()
..()
src.root.add_file( new /datum/computer/file/mainframe_program/test_interface(src) )
//src.root.add_file( new /datum/computer/file/mainframe_program/artifact_research(src) )
for (var/datum/computer/file/F in src.root.contents)
F.metadata["permission"] = COMP_ROWNER|COMP_RGROUP|COMP_ROTHER
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff