mirror of
https://github.com/goonstation/goonstation-2016.git
synced 2026-07-12 17:42:19 +01:00
Initial Commit
This commit is contained in:
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 : "<not set>"]</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'><not set></a>"
|
||||
dat += "<br>"
|
||||
dat += "<b>Action:</b> <a href='?src=\ref[src];action=1'>[filter_action ? filter_action : "<not set>"]</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 : "<not set>"]</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 ("'")
|
||||
var/newString
|
||||
while (command_stream.len)
|
||||
if (command_stream[1] == "\'" || command_stream[1] == "'")
|
||||
command_stream.Cut(1,2)
|
||||
break
|
||||
else if (dd_hassuffix(command_stream[1], "'"))
|
||||
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
Reference in New Issue
Block a user