This commit is contained in:
davipatury
2017-02-19 21:54:46 -03:00
parent 2733b77b58
commit bfc130dafb
70 changed files with 4434 additions and 4 deletions
@@ -0,0 +1,102 @@
/datum/computer_file/program/ntnet_dos
filename = "ntn_dos"
filedesc = "DoS Traffic Generator"
program_icon_state = "hostile"
extended_desc = "This advanced script can perform denial of service attacks against NTNet quantum relays. The system administrator will probably notice this. Multiple devices can run this program together against same relay for increased effect"
size = 20
requires_ntnet = 1
available_on_ntnet = 0
available_on_syndinet = 1
var/obj/machinery/ntnet_relay/target = null
var/dos_speed = 0
var/error = ""
var/executed = 0
/datum/computer_file/program/ntnet_dos/process_tick()
dos_speed = 0
switch(ntnet_status)
if(1)
dos_speed = NTNETSPEED_LOWSIGNAL * 10
if(2)
dos_speed = NTNETSPEED_HIGHSIGNAL * 10
if(3)
dos_speed = NTNETSPEED_ETHERNET * 10
if(target && executed)
target.dos_overload += dos_speed
if(target.inoperable())
target.dos_sources.Remove(src)
target = null
error = "Connection to destination relay lost."
/datum/computer_file/program/ntnet_dos/kill_program(forced = FALSE)
if(target)
target.dos_sources.Remove(src)
target = null
executed = 0
..()
/datum/computer_file/program/ntnet_dos/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "ntnet_dos.tmpl", "DoS Traffic Generator", 400, 250)
ui.set_auto_update(1)
ui.open()
/datum/computer_file/program/ntnet_dos/Topic(href, list/href_list)
if(..())
return 1
switch(href_list["action"])
if("PRG_target_relay")
for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
if("[R.uid]" == href_list["targid"])
target = R
return 1
if("PRG_reset")
if(target)
target.dos_sources.Remove(src)
target = null
executed = 0
error = ""
return 1
if("PRG_execute")
if(target)
executed = 1
target.dos_sources.Add(src)
if(ntnet_global.intrusion_detection_enabled)
var/obj/item/weapon/computer_hardware/network_card/network_card = computer.all_components[MC_NET]
ntnet_global.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]")
ntnet_global.intrusion_detection_alarm = 1
return 1
/datum/computer_file/program/ntnet_dos/ui_data(mob/user)
if(!ntnet_global)
return
var/list/data = get_header_data()
if(error)
data["error"] = error
else if(target && executed)
data["target"] = 1
data["speed"] = dos_speed
// This is mostly visual, generate some strings of 1s and 0s
// Probability of 1 is equal of completion percentage of DoS attack on this relay.
// Combined with UI updates this adds quite nice effect to the UI
var/percentage = target.dos_overload * 100 / target.dos_capacity
data["dos_strings"] = list()
for(var/j, j<10, j++)
var/string = ""
for(var/i, i<20, i++)
string = "[string][prob(percentage)]"
data["dos_strings"] += list(list("nums" = string))
else
data["relays"] = list()
for(var/obj/machinery/ntnet_relay/R in ntnet_global.relays)
data["relays"] += list(list("id" = R.uid))
data["focus"] = target ? target.uid : null
return data
@@ -0,0 +1,74 @@
// This is special hardware configuration program.
// It is to be used only with modular computers.
// It allows you to toggle components of your device.
/datum/computer_file/program/computerconfig
filename = "compconfig"
filedesc = "Computer Configuration Tool"
extended_desc = "This program allows configuration of computer's hardware"
program_icon_state = "generic"
unsendable = 1
undeletable = 1
size = 4
available_on_ntnet = 0
requires_ntnet = 0
var/obj/item/device/modular_computer/movable = null
/datum/computer_file/program/computerconfig/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "laptop_configuration.tmpl", "NTOS Configuration Utility", 575, 700)
ui.set_auto_update(1)
ui.open()
/datum/computer_file/program/computerconfig/ui_data(mob/user)
movable = computer
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = movable.all_components[MC_HDD]
var/obj/item/weapon/computer_hardware/battery/battery_module = movable.all_components[MC_CELL]
if(!istype(movable))
movable = null
// No computer connection, we can't get data from that.
if(!movable)
return 0
var/list/data = get_header_data()
data["disk_size"] = hard_drive.max_capacity
data["disk_used"] = hard_drive.used_capacity
data["power_usage"] = movable.last_power_usage
data["battery_exists"] = battery_module ? 1 : 0
if(battery_module && battery_module.battery)
data["battery_rating"] = battery_module.battery.maxcharge
data["battery_percent"] = round(battery_module.battery.percent())
if(battery_module && battery_module.battery)
data["battery"] = list("max" = battery_module.battery.maxcharge, "charge" = round(battery_module.battery.charge))
var/list/all_entries[0]
for(var/I in movable.all_components)
var/obj/item/weapon/computer_hardware/H = movable.all_components[I]
all_entries.Add(list(list(
"name" = H.name,
"desc" = H.desc,
"enabled" = H.enabled,
"critical" = H.critical,
"powerusage" = H.power_usage
)))
data["hardware"] = all_entries
return data
/datum/computer_file/program/computerconfig/Topic(href, list/href_list)
if(..())
return
switch(href_list["action"])
if("PC_toggle_component")
var/obj/item/weapon/computer_hardware/H = movable.find_hardware_by_name(href_list["name"])
if(H && istype(H))
H.enabled = !H.enabled
. = TRUE
@@ -0,0 +1,232 @@
/datum/computer_file/program/filemanager
filename = "filemanager"
filedesc = "NTOS File Manager"
extended_desc = "This program allows management of files."
program_icon_state = "generic"
size = 8
requires_ntnet = 0
available_on_ntnet = 0
undeletable = 1
var/open_file
var/error
/datum/computer_file/program/filemanager/Topic(href, list/href_list)
if(..())
return 1
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD]
var/obj/item/weapon/computer_hardware/hard_drive/RHDD = computer.all_components[MC_SDD]
var/obj/item/weapon/computer_hardware/printer/printer = computer.all_components[MC_PRINT]
switch(href_list["action"])
if("PRG_openfile")
. = 1
open_file = href_list["name"]
if("PRG_newtextfile")
. = 1
var/newname = stripped_input(usr, "Enter file name or leave blank to cancel:", "File rename", max_length=50)
if(!newname)
return 1
if(!HDD)
return 1
var/datum/computer_file/data/F = new/datum/computer_file/data()
F.filename = newname
F.filetype = "TXT"
HDD.store_file(F)
if("PRG_deletefile")
. = 1
if(!HDD)
return 1
var/datum/computer_file/file = HDD.find_file_by_name(href_list["name"])
if(!file || file.undeletable)
return 1
HDD.remove_file(file)
if("PRG_usbdeletefile")
. = 1
if(!RHDD)
return 1
var/datum/computer_file/file = RHDD.find_file_by_name(href_list["name"])
if(!file || file.undeletable)
return 1
RHDD.remove_file(file)
if("PRG_closefile")
. = 1
open_file = null
error = null
if("PRG_clone")
. = 1
if(!HDD)
return 1
var/datum/computer_file/F = HDD.find_file_by_name(href_list["name"])
if(!F || !istype(F))
return 1
var/datum/computer_file/C = F.clone(1)
HDD.store_file(C)
if("PRG_rename")
. = 1
if(!HDD)
return 1
var/datum/computer_file/file = HDD.find_file_by_name(href_list["name"])
if(!file || !istype(file))
return 1
var/newname = stripped_input(usr, "Enter new file name:", "File rename", file.filename, max_length=50)
if(file && newname)
file.filename = newname
if("PRG_edit")
. = 1
if(!open_file)
return 1
if(!HDD)
return 1
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
if(!F || !istype(F))
return 1
if(F.do_not_edit && (alert("WARNING: This file is not compatible with editor. Editing it may result in permanently corrupted formatting or damaged data consistency. Edit anyway?", "Incompatible File", "No", "Yes") == "No"))
return 1
// 16384 is the limit for file length in characters. Currently, papers have value of 2048 so this is 8 times as long, since we can't edit parts of the file independently.
var/newtext = stripped_multiline_input(usr, "Editing file [open_file]. You may use most tags used in paper formatting:", "Text Editor", html_decode(F.stored_data), 16384, TRUE)
if(!newtext)
return
if(F)
var/datum/computer_file/data/backup = F.clone()
HDD.remove_file(F)
F.stored_data = newtext
F.calculate_size()
// We can't store the updated file, it's probably too large. Print an error and restore backed up version.
// This is mostly intended to prevent people from losing texts they spent lot of time working on due to running out of space.
// They will be able to copy-paste the text from error screen and store it in notepad or something.
if(!HDD.store_file(F))
error = "I/O error: Unable to overwrite file. Hard drive is probably full. You may want to backup your changes before closing this window:<br><br>[F.stored_data]<br><br>"
HDD.store_file(backup)
if("PRG_printfile")
. = 1
if(!open_file)
return 1
if(!HDD)
return 1
var/datum/computer_file/data/F = HDD.find_file_by_name(open_file)
if(!F || !istype(F))
return 1
if(!printer)
error = "Missing Hardware: Your computer does not have required hardware to complete this operation."
return 1
if(!printer.print_text("<font face=\"[computer.emagged ? "Comic Sans MS" : "Verdana"]\">" + prepare_printjob(F.stored_data) + "</font>", open_file))
error = "Hardware error: Printer was unable to print the file. It may be out of paper."
return 1
if("PRG_copytousb")
. = 1
if(!HDD || !RHDD)
return 1
var/datum/computer_file/F = HDD.find_file_by_name(href_list["name"])
if(!F || !istype(F))
return 1
var/datum/computer_file/C = F.clone(0)
RHDD.store_file(C)
if("PRG_copyfromusb")
. = 1
if(!HDD || !RHDD)
return 1
var/datum/computer_file/F = RHDD.find_file_by_name(href_list["name"])
if(!F || !istype(F))
return 1
var/datum/computer_file/C = F.clone(0)
HDD.store_file(C)
/datum/computer_file/program/filemanager/proc/parse_tags(t)
t = replacetext(t, "\[center\]", "<center>")
t = replacetext(t, "\[/center\]", "</center>")
t = replacetext(t, "\[br\]", "<BR>")
t = replacetext(t, "\n", "<BR>")
t = replacetext(t, "\[b\]", "<B>")
t = replacetext(t, "\[/b\]", "</B>")
t = replacetext(t, "\[i\]", "<I>")
t = replacetext(t, "\[/i\]", "</I>")
t = replacetext(t, "\[u\]", "<U>")
t = replacetext(t, "\[/u\]", "</U>")
t = replacetext(t, "\[time\]", "[worldtime2text()]")
t = replacetext(t, "\[date\]", "[current_date_string] [worldtime2text()]")
t = replacetext(t, "\[large\]", "<font size=\"4\">")
t = replacetext(t, "\[/large\]", "</font>")
t = replacetext(t, "\[h1\]", "<H1>")
t = replacetext(t, "\[/h1\]", "</H1>")
t = replacetext(t, "\[h2\]", "<H2>")
t = replacetext(t, "\[/h2\]", "</H2>")
t = replacetext(t, "\[h3\]", "<H3>")
t = replacetext(t, "\[/h3\]", "</H3>")
t = replacetext(t, "\[*\]", "<li>")
t = replacetext(t, "\[hr\]", "<HR>")
t = replacetext(t, "\[small\]", "<font size = \"1\">")
t = replacetext(t, "\[/small\]", "</font>")
t = replacetext(t, "\[list\]", "<ul>")
t = replacetext(t, "\[/list\]", "</ul>")
t = replacetext(t, "\[table\]", "<table border=1 cellspacing=0 cellpadding=3 style='border: 1px solid black;'>")
t = replacetext(t, "\[/table\]", "</td></tr></table>")
t = replacetext(t, "\[grid\]", "<table>")
t = replacetext(t, "\[/grid\]", "</td></tr></table>")
t = replacetext(t, "\[row\]", "</td><tr>")
t = replacetext(t, "\[tr\]", "</td><tr>")
t = replacetext(t, "\[td\]", "<td>")
t = replacetext(t, "\[cell\]", "<td>")
t = replacetext(t, "\[tab\]", "&nbsp;&nbsp;&nbsp;&nbsp;")
return t
/datum/computer_file/program/filemanager/proc/prepare_printjob(t) // Additional stuff to parse if we want to print it and make a happy Head of Personnel. Forms FTW.
t = replacetext(t, "\[field\]", "<span class=\"paper_field\"></span>")
t = replacetext(t, "\[sign\]", "<span class=\"paper_field\"></span>")
t = parse_tags(t)
return t
/datum/computer_file/program/filemanager/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "file_manager.tmpl", "NTOS File Manager", 575, 700)
ui.set_auto_update(1)
ui.open()
/datum/computer_file/program/filemanager/ui_data(mob/user)
var/list/data = get_header_data()
var/obj/item/weapon/computer_hardware/hard_drive/HDD = computer.all_components[MC_HDD]
var/obj/item/weapon/computer_hardware/hard_drive/portable/RHDD = computer.all_components[MC_SDD]
if(error)
data["error"] = error
if(open_file)
var/datum/computer_file/data/file
if(!computer || !HDD)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
file = HDD.find_file_by_name(open_file)
if(!istype(file))
data["error"] = "I/O ERROR: Unable to open file."
else
data["filedata"] = parse_tags(file.stored_data)
data["filename"] = "[file.filename].[file.filetype]"
else
if(!computer || !HDD)
data["error"] = "I/O ERROR: Unable to access hard drive."
else
var/list/files[0]
for(var/datum/computer_file/F in HDD.stored_files)
files.Add(list(list(
"name" = F.filename,
"type" = F.filetype,
"size" = F.size,
"undeletable" = F.undeletable
)))
data["files"] = files
if(RHDD)
data["usbconnected"] = 1
var/list/usbfiles[0]
for(var/datum/computer_file/F in RHDD.stored_files)
usbfiles.Add(list(list(
"name" = F.filename,
"type" = F.filetype,
"size" = F.size,
"undeletable" = F.undeletable
)))
data["usbfiles"] = usbfiles
return data
@@ -0,0 +1,176 @@
/datum/computer_file/program/ntnetdownload
filename = "ntndownloader"
filedesc = "NTNet Software Download Tool"
program_icon_state = "generic"
extended_desc = "This program allows downloads of software from official NT repositories"
unsendable = 1
undeletable = 1
size = 4
requires_ntnet = 1
requires_ntnet_feature = NTNET_SOFTWAREDOWNLOAD
available_on_ntnet = 0
ui_header = "downloader_finished.gif"
var/datum/computer_file/program/downloaded_file = null
var/hacked_download = 0
var/download_completion = 0 //GQ of downloaded data.
var/download_netspeed = 0
var/downloaderror = ""
var/obj/item/device/modular_computer/my_computer = null
/datum/computer_file/program/ntnetdownload/proc/begin_file_download(filename)
if(downloaded_file)
return 0
var/datum/computer_file/program/PRG = ntnet_global.find_ntnet_file_by_name(filename)
if(!PRG || !istype(PRG))
return 0
// Attempting to download antag only program, but without having emagged computer. No.
if(PRG.available_on_syndinet && !computer.emagged)
return 0
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
if(!computer || !hard_drive || !hard_drive.can_store_file(PRG))
return 0
ui_header = "downloader_running.gif"
if(PRG in ntnet_global.available_station_software)
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from NTNet Software Repository.")
hacked_download = 0
else if(PRG in ntnet_global.available_antag_software)
generate_network_log("Began downloading file **ENCRYPTED**.[PRG.filetype] from unspecified server.")
hacked_download = 1
else
generate_network_log("Began downloading file [PRG.filename].[PRG.filetype] from unspecified server.")
hacked_download = 0
downloaded_file = PRG.clone()
/datum/computer_file/program/ntnetdownload/proc/abort_file_download()
if(!downloaded_file)
return
generate_network_log("Aborted download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].")
downloaded_file = null
download_completion = 0
ui_header = "downloader_finished.gif"
/datum/computer_file/program/ntnetdownload/proc/complete_file_download()
if(!downloaded_file)
return
generate_network_log("Completed download of file [hacked_download ? "**ENCRYPTED**" : "[downloaded_file.filename].[downloaded_file.filetype]"].")
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
if(!computer || !hard_drive || !hard_drive.store_file(downloaded_file))
// The download failed
downloaderror = "I/O ERROR - Unable to save file. Check whether you have enough free space on your hard drive and whether your hard drive is properly connected. If the issue persists contact your system administrator for assistance."
downloaded_file = null
download_completion = 0
ui_header = "downloader_finished.gif"
/datum/computer_file/program/ntnetdownload/process_tick()
if(!downloaded_file)
return
if(download_completion >= downloaded_file.size)
complete_file_download()
// Download speed according to connectivity state. NTNet server is assumed to be on unlimited speed so we're limited by our local connectivity
download_netspeed = 0
// Speed defines are found in misc.dm
switch(ntnet_status)
if(1)
download_netspeed = NTNETSPEED_LOWSIGNAL
if(2)
download_netspeed = NTNETSPEED_HIGHSIGNAL
if(3)
download_netspeed = NTNETSPEED_ETHERNET
download_completion += download_netspeed
/datum/computer_file/program/ntnetdownload/Topic(href, list/href_list)
if(..())
return 1
switch(href_list["action"])
if("PRG_downloadfile")
if(!downloaded_file)
begin_file_download(href_list["filename"])
return 1
if("PRG_reseterror")
if(downloaderror)
download_completion = 0
download_netspeed = 0
downloaded_file = null
downloaderror = ""
return 1
return 0
/datum/computer_file/program/ntnetdownload/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "ntnet_downloader.tmpl", "NTNet Download Program", 575, 700)
ui.set_auto_update(1)
ui.open()
/datum/computer_file/program/ntnetdownload/ui_data(mob/user)
my_computer = computer
if(!istype(my_computer))
return
var/list/data = get_header_data()
// This IF cuts on data transferred to client, so i guess it's worth it.
if(downloaderror) // Download errored. Wait until user resets the program.
data["error"] = downloaderror
else if(downloaded_file) // Download running. Wait please..
data["downloadname"] = downloaded_file.filename
data["downloaddesc"] = downloaded_file.filedesc
data["downloadsize"] = downloaded_file.size
data["downloadspeed"] = download_netspeed
data["downloadcompletion"] = round(download_completion, 0.1)
else // No download running, pick file.
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = my_computer.all_components[MC_HDD]
data["disk_size"] = hard_drive.max_capacity
data["disk_used"] = hard_drive.used_capacity
var/list/all_entries[0]
for(var/A in ntnet_global.available_station_software)
var/datum/computer_file/program/P = A
// Only those programs our user can run will show in the list
if(!P.can_run(user,transfer = 1))
continue
all_entries.Add(list(list(
"filename" = P.filename,
"filedesc" = P.filedesc,
"fileinfo" = P.extended_desc,
"compatibility" = check_compatibility(P),
"size" = P.size
)))
data["hackedavailable"] = 0
if(computer.emagged) // If we are running on emagged computer we have access to some "bonus" software
var/list/hacked_programs[0]
for(var/S in ntnet_global.available_antag_software)
var/datum/computer_file/program/P = S
data["hackedavailable"] = 1
hacked_programs.Add(list(list(
"filename" = P.filename,
"filedesc" = P.filedesc,
"fileinfo" = P.extended_desc,
"size" = P.size
)))
data["hacked_programs"] = hacked_programs
data["downloadable_programs"] = all_entries
return data
/datum/computer_file/program/ntnetdownload/proc/check_compatibility(datum/computer_file/program/P)
var/hardflag = computer.hardware_flag
if(P && P.is_supported_by_hardware(hardflag,0))
return "Compatible"
return "Incompatible!"
/datum/computer_file/program/ntnetdownload/kill_program(forced)
abort_file_download()
return ..(forced)
@@ -0,0 +1,229 @@
/datum/computer_file/program/chatclient
filename = "ntnrc_client"
filedesc = "NTNet Relay Chat Client"
program_icon_state = "command"
extended_desc = "This program allows communication over NTNRC network"
size = 8
requires_ntnet = 1
requires_ntnet_feature = NTNET_COMMUNICATION
network_destination = "NTNRC server"
ui_header = "ntnrc_idle.gif"
available_on_ntnet = 1
var/last_message = null // Used to generate the toolbar icon
var/username
var/datum/ntnet_conversation/channel = null
var/operator_mode = 0 // Channel operator mode
var/netadmin_mode = 0 // Administrator mode (invisible to other users + bypasses passwords)
/datum/computer_file/program/chatclient/New()
username = "DefaultUser[rand(100, 999)]"
/datum/computer_file/program/chatclient/Topic(href, list/href_list)
if(..())
return 1
switch(href_list["action"])
if("PRG_speak")
. = 1
if(!channel)
return 1
var/mob/living/user = usr
var/message = reject_bad_text(input(user, "Enter message or leave blank to cancel: "))
if(!message || !channel)
return
channel.add_message(message, username)
log_chat("[user]/([user.ckey]) as [username] sent to [channel.title]: [message]")
if("PRG_joinchannel")
. = 1
var/datum/ntnet_conversation/C
for(var/datum/ntnet_conversation/chan in ntnet_global.chat_channels)
if(chan.id == text2num(href_list["id"]))
C = chan
break
if(!C)
return 1
if(netadmin_mode)
channel = C // Bypasses normal leave/join and passwords. Technically makes the user invisible to others.
return 1
if(C.password)
var/mob/living/user = usr
var/password = reject_bad_text(input(user,"Access Denied. Enter password:"))
if(C && (password == C.password))
C.add_client(src)
channel = C
return 1
C.add_client(src)
channel = C
if("PRG_leavechannel")
. = 1
if(channel)
channel.remove_client(src)
channel = null
if("PRG_newchannel")
. = 1
var/mob/living/user = usr
var/channel_title = reject_bad_text(input(user,"Enter channel name or leave blank to cancel:"))
if(!channel_title)
return
var/datum/ntnet_conversation/C = new/datum/ntnet_conversation()
C.add_client(src)
C.operator = src
channel = C
C.title = channel_title
if("PRG_toggleadmin")
. = 1
if(netadmin_mode)
netadmin_mode = 0
if(channel)
channel.remove_client(src) // We shouldn't be in channel's user list, but just in case...
channel = null
return 1
var/mob/living/user = usr
if(can_run(user, 1, access_network))
if(channel)
var/response = alert(user, "Really engage admin-mode? You will be disconnected from your current channel!", "NTNRC Admin mode", "Yes", "No")
if(response == "Yes")
if(channel)
channel.remove_client(src)
channel = null
else
return
netadmin_mode = 1
if("PRG_changename")
. = 1
var/mob/living/user = usr
var/newname = sanitize(input(user,"Enter new nickname or leave blank to cancel:"))
if(!newname)
return 1
if(channel)
channel.add_status_message("[username] is now known as [newname].")
username = newname
if("PRG_savelog")
. = 1
if(!channel)
return
var/mob/living/user = usr
var/logname = input(user,"Enter desired logfile name (.log) or leave blank to cancel:")
if(!logname || !channel)
return 1
var/datum/computer_file/data/logfile = new/datum/computer_file/data/logfile()
// Now we will generate HTML-compliant file that can actually be viewed/printed.
logfile.filename = logname
logfile.stored_data = "\[b\]Logfile dump from NTNRC channel [channel.title]\[/b\]\[BR\]"
for(var/logstring in channel.messages)
logfile.stored_data += "[logstring]\[BR\]"
logfile.stored_data += "\[b\]Logfile dump completed.\[/b\]"
logfile.calculate_size()
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
if(!computer || !hard_drive || !hard_drive.store_file(logfile))
if(!computer)
// This program shouldn't even be runnable without computer.
CRASH("Var computer is null!")
return 1
if(!hard_drive)
computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive connection error\" warning.")
else // In 99.9% cases this will mean our HDD is full
computer.visible_message("\The [computer] shows an \"I/O Error - Hard drive may be full. Please free some space and try again. Required space: [logfile.size]GQ\" warning.")
if("PRG_renamechannel")
. = 1
if(!operator_mode || !channel)
return 1
var/mob/living/user = usr
var/newname = reject_bad_text(input(user, "Enter new channel name or leave blank to cancel:"))
if(!newname || !channel)
return
channel.add_status_message("Channel renamed from [channel.title] to [newname] by operator.")
channel.title = newname
if("PRG_deletechannel")
. = 1
if(channel && ((channel.operator == src) || netadmin_mode))
qdel(channel)
channel = null
if("PRG_setpassword")
. = 1
if(!channel || ((channel.operator != src) && !netadmin_mode))
return 1
var/mob/living/user = usr
var/newpassword = sanitize(input(user, "Enter new password for this channel. Leave blank to cancel, enter 'nopassword' to remove password completely:"))
if(!channel || !newpassword || ((channel.operator != src) && !netadmin_mode))
return 1
if(newpassword == "nopassword")
channel.password = ""
else
channel.password = newpassword
/datum/computer_file/program/chatclient/process_tick()
..()
if(program_state != PROGRAM_STATE_KILLED)
ui_header = "ntnrc_idle.gif"
if(channel)
// Remember the last message. If there is no message in the channel remember null.
last_message = channel.messages.len ? channel.messages[channel.messages.len - 1] : null
else
last_message = null
return 1
if(channel && channel.messages && channel.messages.len)
ui_header = last_message == channel.messages[channel.messages.len - 1] ? "ntnrc_idle.gif" : "ntnrc_new.gif"
else
ui_header = "ntnrc_idle.gif"
/datum/computer_file/program/chatclient/kill_program(forced = FALSE)
if(channel)
channel.remove_client(src)
channel = null
..()
/datum/computer_file/program/chatclient/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "ntnet_chat.tmpl", "NTNet Relay Chat Client", 575, 700)
ui.set_auto_update(1)
ui.open()
/datum/computer_file/program/chatclient/ui_data(mob/user)
if(!ntnet_global || !ntnet_global.chat_channels)
return
var/list/data = get_header_data()
data["adminmode"] = netadmin_mode
if(channel)
data["title"] = channel.title
var/list/messages[0]
for(var/M in channel.messages)
messages.Add(list(list(
"msg" = M
)))
data["messages"] = messages
var/list/clients[0]
for(var/C in channel.clients)
var/datum/computer_file/program/chatclient/cl = C
clients.Add(list(list(
"name" = cl.username
)))
data["clients"] = clients
operator_mode = (channel.operator == src) ? 1 : 0
data["is_operator"] = operator_mode || netadmin_mode
else // Channel selection screen
var/list/all_channels[0]
for(var/C in ntnet_global.chat_channels)
var/datum/ntnet_conversation/conv = C
if(conv && conv.title)
all_channels.Add(list(list(
"chan" = conv.title,
"id" = conv.id
)))
data["all_channels"] = all_channels
return data
@@ -0,0 +1,194 @@
var/global/nttransfer_uid = 0
/datum/computer_file/program/nttransfer
filename = "nttransfer"
filedesc = "NTNet P2P Transfer Client"
extended_desc = "This program allows for simple file transfer via direct peer to peer connection."
program_icon_state = "comm_logs"
size = 7
requires_ntnet = 1
requires_ntnet_feature = NTNET_PEERTOPEER
network_destination = "other device via P2P tunnel"
available_on_ntnet = 1
var/error = "" // Error screen
var/server_password = "" // Optional password to download the file.
var/datum/computer_file/provided_file = null // File which is provided to clients.
var/datum/computer_file/downloaded_file = null // File which is being downloaded
var/list/connected_clients = list() // List of connected clients.
var/datum/computer_file/program/nttransfer/remote // Client var, specifies who are we downloading from.
var/download_completion = 0 // Download progress in GQ
var/download_netspeed = 0 // Our connectivity speed in GQ/s
var/actual_netspeed = 0 // Displayed in the UI, this is the actual transfer speed.
var/unique_token // UID of this program
var/upload_menu = 0 // Whether we show the program list and upload menu
/datum/computer_file/program/nttransfer/New()
unique_token = nttransfer_uid
nttransfer_uid++
..()
/datum/computer_file/program/nttransfer/process_tick()
// Server mode
update_netspeed()
if(provided_file)
for(var/datum/computer_file/program/nttransfer/C in connected_clients)
// Transfer speed is limited by device which uses slower connectivity.
// We can have multiple clients downloading at same time, but let's assume we use some sort of multicast transfer
// so they can all run on same speed.
C.actual_netspeed = min(C.download_netspeed, download_netspeed)
C.download_completion += C.actual_netspeed
if(C.download_completion >= provided_file.size)
C.finish_download()
else if(downloaded_file) // Client mode
if(!remote)
crash_download("Connection to remote server lost")
/datum/computer_file/program/nttransfer/kill_program(forced = FALSE)
if(downloaded_file) // Client mode, clean up variables for next use
finalize_download()
if(provided_file) // Server mode, disconnect all clients
for(var/datum/computer_file/program/nttransfer/P in connected_clients)
P.crash_download("Connection terminated by remote server")
downloaded_file = null
..(forced)
/datum/computer_file/program/nttransfer/proc/update_netspeed()
download_netspeed = 0
switch(ntnet_status)
if(1)
download_netspeed = NTNETSPEED_LOWSIGNAL
if(2)
download_netspeed = NTNETSPEED_HIGHSIGNAL
if(3)
download_netspeed = NTNETSPEED_ETHERNET
// Finishes download and attempts to store the file on HDD
/datum/computer_file/program/nttransfer/proc/finish_download()
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
if(!computer || !hard_drive || !hard_drive.store_file(downloaded_file))
error = "I/O Error: Unable to save file. Check your hard drive and try again."
finalize_download()
// Crashes the download and displays specific error message
/datum/computer_file/program/nttransfer/proc/crash_download(var/message)
error = message ? message : "An unknown error has occurred during download"
finalize_download()
// Cleans up variables for next use
/datum/computer_file/program/nttransfer/proc/finalize_download()
if(remote)
remote.connected_clients.Remove(src)
downloaded_file = null
remote = null
download_completion = 0
/datum/computer_file/program/nttransfer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/headers)
assets.send(user)
ui = new(user, src, ui_key, "ntnet_transfer.tmpl", "NTNet P2P Transfer Client", 575, 700)
ui.set_auto_update(1)
ui.open()
/datum/computer_file/program/nttransfer/Topic(href, list/href_list)
if(..())
return 1
switch(href_list["action"])
if("PRG_downloadfile")
for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
if("[P.unique_token]" == href_list["id"])
remote = P
break
if(!remote || !remote.provided_file)
return
if(remote.server_password)
var/pass = reject_bad_text(input(usr, "Code 401 Unauthorized. Please enter password:", "Password required"))
if(pass != remote.server_password)
error = "Incorrect Password"
return
downloaded_file = remote.provided_file.clone()
remote.connected_clients.Add(src)
return 1
if("PRG_reset")
error = ""
upload_menu = 0
finalize_download()
if(src in ntnet_global.fileservers)
ntnet_global.fileservers.Remove(src)
for(var/datum/computer_file/program/nttransfer/T in connected_clients)
T.crash_download("Remote server has forcibly closed the connection")
provided_file = null
return 1
if("PRG_setpassword")
var/pass = reject_bad_text(input(usr, "Enter new server password. Leave blank to cancel, input 'none' to disable password.", "Server security", "none"))
if(!pass)
return
if(pass == "none")
server_password = ""
return
server_password = pass
return 1
if("PRG_uploadfile")
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
for(var/datum/computer_file/F in hard_drive.stored_files)
if("[F.uid]" == href_list["id"])
if(F.unsendable)
error = "I/O Error: File locked."
return
if(istype(F, /datum/computer_file/program))
var/datum/computer_file/program/P = F
if(!P.can_run(usr,transfer = 1))
error = "Access Error: Insufficient rights to upload file."
provided_file = F
ntnet_global.fileservers.Add(src)
return
error = "I/O Error: Unable to locate file on hard drive."
return 1
if("PRG_uploadmenu")
upload_menu = 1
/datum/computer_file/program/nttransfer/ui_data(mob/user)
var/list/data = get_header_data()
if(error)
data["error"] = error
else if(downloaded_file)
data["downloading"] = 1
data["download_size"] = downloaded_file.size
data["download_progress"] = download_completion
data["download_netspeed"] = actual_netspeed
data["download_name"] = "[downloaded_file.filename].[downloaded_file.filetype]"
else if (provided_file)
data["uploading"] = 1
data["upload_uid"] = unique_token
data["upload_clients"] = connected_clients.len
data["upload_haspassword"] = server_password ? 1 : 0
data["upload_filename"] = "[provided_file.filename].[provided_file.filetype]"
else if (upload_menu)
var/list/all_files[0]
var/obj/item/weapon/computer_hardware/hard_drive/hard_drive = computer.all_components[MC_HDD]
for(var/datum/computer_file/F in hard_drive.stored_files)
all_files.Add(list(list(
"uid" = F.uid,
"filename" = "[F.filename].[F.filetype]",
"size" = F.size
)))
data["upload_filelist"] = all_files
else
var/list/all_servers[0]
for(var/datum/computer_file/program/nttransfer/P in ntnet_global.fileservers)
all_servers.Add(list(list(
"uid" = P.unique_token,
"filename" = "[P.provided_file.filename].[P.provided_file.filetype]",
"size" = P.provided_file.size,
"haspassword" = P.server_password ? 1 : 0
)))
data["servers"] = all_servers
return data