diff --git a/WorkInProgress/francinum/centralized_phones/callstation.dm b/WorkInProgress/francinum/centralized_phones/callstation.dm index 986a768a652f..ed5508693a75 100644 --- a/WorkInProgress/francinum/centralized_phones/callstation.dm +++ b/WorkInProgress/francinum/centralized_phones/callstation.dm @@ -44,7 +44,7 @@ Phone registration flow (Post-Roundstart): return switch(lowertext(signal.data["command"])) if("ping_reply")// A reply to our ping! - if(signal.data[PACKET_NETCLASS] != "PNET_SIPSERVER") //Not who we care about! + if(signal.data[LEGACY_PACKET_NETCLASS] != "PNET_SIPSERVER") //Not who we care about! return register_with_server(signal.data["s_addr"])// It's a server, link! if("sip_adopt") diff --git a/code/__DEFINES/computer4_defines.dm b/code/__DEFINES/computer4_defines.dm index 661abb171df5..c348e2fd9574 100644 --- a/code/__DEFINES/computer4_defines.dm +++ b/code/__DEFINES/computer4_defines.dm @@ -4,8 +4,15 @@ // See proc/peripheral_input #define PERIPHERAL_CMD_RECEIVE_PACKET "receive_packet" +#define PERIPHERAL_CMD_RECEIVE_PDP_PACKET "receive_pdp_packet" #define PERIPHERAL_CMD_SCAN_CARD "scan_card" +// Shell command macros +#define SHELL_CMD_HELP_ERROR 1 //! Could not find a command to display information about +#define SHELL_CMD_HELP_GENERIC 2 //! Generated generic help information +#define SHELL_CMD_HELP_COMMAND 3 //! Generated information about a command + + // MedTrak menus #define MEDTRAK_MENU_HOME 1 #define MEDTRAK_MENU_INDEX 2 @@ -20,6 +27,11 @@ // ITS THREE IN THE MOOOOORNIN' AND YOOUUU'RE EATING ALONE #define DIRECTMAN_MENU_NEW_DIRECTIVE 5 +// packMAN shit +#define PACKMAN_MODE_UNDEFINED 0 +#define PACKMAN_MODE_CLIENT 1 +#define PACKMAN_MODE_SERVER 2 + // Wireless card incoming filter modes #define WIRELESS_FILTER_PROMISC 0 //! Forward all packets #define WIRELESS_FILTER_NETADDR 1 //! Forward only bcast/unicast matched GPRS packets @@ -27,6 +39,11 @@ #define WIRELESS_FILTER_MODEMAX 2 //! Max of WIRELESS_FILTER_* Defines. +// PDP BindPort return values + +#define PDP_BIND_FAILED_CATASTROPHIC 1 //! What the fuck did you do??? +#define PDP_BIND_FAILED_CONFLICT 2 //! Port already bound? + // ThinkDOS // // Constants #define THINKDOS_MAX_COMMANDS 3 //! The maximum amount of commands diff --git a/code/__DEFINES/packetnet.dm b/code/__DEFINES/packetnet.dm index 0bce0df1d9a8..9a5bbe6ad5bb 100644 --- a/code/__DEFINES/packetnet.dm +++ b/code/__DEFINES/packetnet.dm @@ -32,14 +32,33 @@ // not honestly thrilled with having these be defines but kapu wants it that way // I believe every coder is empowered with a right to footgun by our lord Dennis Ritchie +//* HEADER FIELDS *// +/// The version of the packet. +#define PKT_HEAD_VERSION "version" /// Source (sender) address of a packet -#define PACKET_SOURCE_ADDRESS "s_addr" +#define PKT_HEAD_SOURCE_ADDRESS "s_addr" /// Destination (receiver) address of a packet -#define PACKET_DESTINATION_ADDRESS "d_addr" -/// Command (type) of a packet -#define PACKET_CMD "command" +#define PKT_HEAD_DEST_ADDRESS "d_addr" /// Network Class of a device, used as part of ping replies. -#define PACKET_NETCLASS "netclass" +#define PKT_HEAD_NETCLASS "netclass" + +#define PKT_HEAD_SOURCE_PORT "sourceport" +#define PKT_HEAD_DEST_PORT "destport" + +#define PKT_HEAD_PROTOCOL "proto" + #define PKT_PROTOCOL_PDP "pdp" + +#define PKT_PAYLOAD "payload" + +//* PAYLOAD FIELDS*// +/// Command (type) of a packet +#define PKT_ARG_CMD "command" + +// Legacy fields. Do not use. +#define LEGACY_PACKET_SOURCE_ADDRESS PKT_HEAD_SOURCE_ADDRESS +#define LEGACY_PACKET_DESTINATION_ADDRESS PKT_HEAD_DEST_ADDRESS +#define LEGACY_PACKET_NETCLASS PKT_HEAD_NETCLASS +#define LEGACY_PACKET_COMMAND PKT_ARG_CMD // Pagers /// Packet arg for pager types @@ -104,3 +123,17 @@ #define MAGIC_DATA_INVIOLABLE ALL #define PACKET_STRING_FILE "packetnet.json" + + +// ----- +// PDP Port Allocations + +// Kapu insisted these be defines "to not be confusing" +#define PDP_BIND_EPHEMERAL_PORT -1 +#define PDP_FREE_ALL_PORTS -1 + +#define PDP_MAX_PORT 65535 //! Maximum PDP Port number + +#define PDP_EPHEMERAL_START 49152 //! Start of PDP Ephemeral Range, used for outgoing client connections. + +#define PDP_PORT_NETTEST 28910 diff --git a/code/__HELPERS/packetnet.dm b/code/__HELPERS/packetnet.dm new file mode 100644 index 000000000000..de64ba58951e --- /dev/null +++ b/code/__HELPERS/packetnet.dm @@ -0,0 +1,12 @@ +/// Returns the data field for a packet. +/proc/packetv2(source_addr, dest_addr, source_port, dest_port, netclass, protocol, list/payload) as /list + . = list( + PKT_HEAD_VERSION = 2, + PKT_HEAD_SOURCE_ADDRESS = source_addr, + PKT_HEAD_DEST_ADDRESS = dest_addr, + PKT_HEAD_SOURCE_PORT = source_port, + PKT_HEAD_DEST_PORT = dest_port, + PKT_HEAD_NETCLASS = netclass, + PKT_HEAD_PROTOCOL = protocol, + PKT_PAYLOAD = payload, + ) diff --git a/code/game/communications.dm b/code/game/communications.dm index a27666573518..52886a86afa2 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -149,7 +149,7 @@ GLOBAL_LIST_INIT(freq2icon, list( //If range is null, or 0, signal is TRULY global (skips z_level checks) (Be careful with this.) //If range > 0, only post to devices on the same z_level and within range //Use range = -1, to restrain to the same z_level without limiting range -/datum/radio_frequency/proc/post_signal(datum/signal/signal, filter = null as text|null, range = null as num|null) +/datum/radio_frequency/post_signal(datum/signal/signal, filter = null as text|null, range = null as num|null) if(!istype(signal)) CRASH("LEGACY POST SIGNAL SHIT") @@ -194,6 +194,11 @@ GLOBAL_LIST_INIT(freq2icon, list( //SHOULD_CALL_PARENT(TRUE) . = TRUE + +/datum/proc/post_signal(datum/signal/signal) + CRASH("Invoked base datum post_signal handler. Did something call parent?") + + /datum/signal /// The author/sender of this packet. /// This atom will be skipped during packet send. diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm index b3ce1a8b03fd..24bf637914b8 100644 --- a/code/game/machinery/announcement_system.dm +++ b/code/game/machinery/announcement_system.dm @@ -224,7 +224,7 @@ GLOBAL_LIST_EMPTY(announcement_systems) for(var/next_addr in targets) var/datum/signal/outgoing = create_signal(next_addr, list( - PACKET_CMD = NETCMD_PDAMESSAGE, + LEGACY_PACKET_COMMAND = NETCMD_PDAMESSAGE, "name" = "Automated Announcement System", "job" = "Security Department Update", "message" = "Officer [officer.real_name] has been assigned to your department, [department].", @@ -244,7 +244,7 @@ GLOBAL_LIST_EMPTY(announcement_systems) break //No RF card to send to. var/message = "You have been fined [fine_amount] marks for '[cite_message]'. Fines may be paid at security." var/datum/signal/outgoing = create_signal(rfcard.hardware_id, list( - PACKET_CMD = NETCMD_PDAMESSAGE, + LEGACY_PACKET_COMMAND = NETCMD_PDAMESSAGE, "name" = "Automated Announcement System", "job" = "Security Citation", "message" = message, @@ -257,7 +257,7 @@ GLOBAL_LIST_EMPTY(announcement_systems) /obj/machinery/announcement_system/proc/mass_pda_message(list/recipients, message, reason) for(var/next_addr in recipients) var/datum/signal/outgoing = create_signal(next_addr, list( - PACKET_CMD = NETCMD_PDAMESSAGE, + LEGACY_PACKET_COMMAND = NETCMD_PDAMESSAGE, "name" = "Automated Announcement System", "job" = reason, "message" = message, @@ -270,7 +270,7 @@ GLOBAL_LIST_EMPTY(announcement_systems) /// A helper proc for sending an announcement to a single PDA. /obj/machinery/announcement_system/proc/pda_message(recipient, message, reason) var/datum/signal/outgoing = create_signal(recipient, list( - PACKET_CMD = NETCMD_PDAMESSAGE, + LEGACY_PACKET_COMMAND = NETCMD_PDAMESSAGE, "name" = "Automated Announcement System", "job" = reason, "message" = message, diff --git a/code/game/machinery/buttons_radio.dm b/code/game/machinery/buttons_radio.dm index 4332005a3566..62ca4df29dbd 100644 --- a/code/game/machinery/buttons_radio.dm +++ b/code/game/machinery/buttons_radio.dm @@ -13,8 +13,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/radio, 24) var/datum/radio_frequency/radio_connection = SSpackets.return_frequency(frequency) var/datum/signal/signal = new(src, list( - PACKET_SOURCE_ADDRESS = net_id, - PACKET_NETCLASS = NETCLASS_BUTTON, + LEGACY_PACKET_SOURCE_ADDRESS = net_id, + LEGACY_PACKET_NETCLASS = NETCLASS_BUTTON, "tag" = id_tag, )) radio_connection.post_signal(signal) diff --git a/code/game/machinery/datanet/_networked.dm b/code/game/machinery/datanet/_networked.dm index 961ccaabddff..6ff1fc55d40d 100644 --- a/code/game/machinery/datanet/_networked.dm +++ b/code/game/machinery/datanet/_networked.dm @@ -7,8 +7,8 @@ if(!datagram || !destination_id) return //Unfortunately /dev/null isn't network-scale. var/list/sig_data = datagram.Copy() - sig_data[PACKET_SOURCE_ADDRESS] = src.net_id - sig_data[PACKET_DESTINATION_ADDRESS] = destination_id + sig_data[PKT_HEAD_SOURCE_ADDRESS] = src.net_id + sig_data[PKT_HEAD_DEST_ADDRESS] = destination_id return new /datum/signal(src, sig_data, TRANSMISSION_WIRE) @@ -16,11 +16,11 @@ /// If you're sending a forged source address (You should have a good reason for this...) set `preserve_s_addr = TRUE /// /// NONE OF THE ABOVE IS TRUE IF YOU ARE `machinery/power`, AS THEY DEAL DIRECTLY WITH SSPACKETS INSTEAD OF ABSTRACTED TERMINALS -/obj/machinery/proc/post_signal(datum/signal/sending_signal, preserve_s_addr = FALSE) +/obj/machinery/post_signal(datum/signal/sending_signal, preserve_s_addr = FALSE) if(isnull(netjack) || isnull(sending_signal)) //nullcheck for sanic speed return //You need a pipe and something to send down it, though. if(!preserve_s_addr) - sending_signal.data[PACKET_SOURCE_ADDRESS] = src.net_id + sending_signal.data[PKT_HEAD_SOURCE_ADDRESS] = src.net_id sending_signal.transmission_method = TRANSMISSION_WIRE sending_signal.author = WEAKREF(src) // Override the sending signal author. src.netjack.post_signal(sending_signal) @@ -31,16 +31,16 @@ if(isnull(signal)) return var/sigdat = signal.data //cache for sanic speed this joke is getting old. - if(sigdat[PACKET_DESTINATION_ADDRESS] != src.net_id)//This packet doesn't belong to us directly - if(sigdat[PACKET_DESTINATION_ADDRESS] == NET_ADDRESS_PING)// But it could be a ping, if so, reply + if(sigdat[PKT_HEAD_DEST_ADDRESS] != src.net_id)//This packet doesn't belong to us directly + if(sigdat[PKT_HEAD_DEST_ADDRESS] == NET_ADDRESS_PING)// But it could be a ping, if so, reply var/tmp_filter = sigdat["filter"] if(!isnull(tmp_filter) && tmp_filter != net_class) return RECEIVE_SIGNAL_FINISHED //Blame kapu for how stupid this looks :3 - var/payload = list(PACKET_CMD=NET_COMMAND_PING_REPLY,PACKET_NETCLASS=src.net_class) + var/payload = list(PKT_ARG_CMD=NET_COMMAND_PING_REPLY,PKT_HEAD_NETCLASS=src.net_class) if(ping_addition) payload += ping_addition - post_signal(create_signal(sigdat[PACKET_SOURCE_ADDRESS],payload)) + post_signal(create_signal(sigdat[PKT_HEAD_SOURCE_ADDRESS],payload)) return RECEIVE_SIGNAL_FINISHED//regardless, return 1 so that machines don't process packets not intended for them. return RECEIVE_SIGNAL_CONTINUE // We are the designated recipient of this packet, we need to handle it. diff --git a/code/game/machinery/datanet/p2p_phones/_p2p_phones.dm b/code/game/machinery/datanet/p2p_phones/_p2p_phones.dm index 8d017a440f60..14286bd19b39 100644 --- a/code/game/machinery/datanet/p2p_phones/_p2p_phones.dm +++ b/code/game/machinery/datanet/p2p_phones/_p2p_phones.dm @@ -231,27 +231,27 @@ if(. == RECEIVE_SIGNAL_FINISHED)//Handled by default. return //Ping response handled in parent. - switch(signal.data[PACKET_CMD]) + switch(signal.data[LEGACY_PACKET_COMMAND]) if(NET_COMMAND_PING_REPLY)//Add new phone to database - if(signal.data[PACKET_NETCLASS] == NETCLASS_P2P_PHONE) //Another phone! - discovered_phones[signal.data[PACKET_SOURCE_ADDRESS]]=signal.data["user_id"] + if(signal.data[LEGACY_PACKET_NETCLASS] == NETCLASS_P2P_PHONE) //Another phone! + discovered_phones[signal.data[LEGACY_PACKET_SOURCE_ADDRESS]]=signal.data["user_id"] return RECEIVE_SIGNAL_FINISHED if("tel_ring")//Incoming ring if(active_caller || handset_state == HANDSET_OFFHOOK)//We're either calling, or about to call, Just tell them to fuck off. - post_signal(create_signal(signal.data[PACKET_SOURCE_ADDRESS],list(PACKET_CMD="tel_busy"))) //Busy signal, Reject call. + post_signal(create_signal(signal.data[LEGACY_PACKET_SOURCE_ADDRESS],list(LEGACY_PACKET_COMMAND="tel_busy"))) //Busy signal, Reject call. return RECEIVE_SIGNAL_FINISHED - receive_call(list(signal.data[PACKET_SOURCE_ADDRESS],signal.data["caller_id"])) + receive_call(list(signal.data[LEGACY_PACKET_SOURCE_ADDRESS],signal.data["caller_id"])) return RECEIVE_SIGNAL_FINISHED if("tel_ready")//Remote side pickup - if(active_caller && signal.data[PACKET_SOURCE_ADDRESS] == active_caller[CALLER_NETID])// Ensure the packet is sensible + if(active_caller && signal.data[LEGACY_PACKET_SOURCE_ADDRESS] == active_caller[CALLER_NETID])// Ensure the packet is sensible call_connected() return RECEIVE_SIGNAL_FINISHED if("tel_busy")//Answering station busy - if(active_caller && signal.data[PACKET_SOURCE_ADDRESS] == active_caller[CALLER_NETID])// Ensure the packet is sensible + if(active_caller && signal.data[LEGACY_PACKET_SOURCE_ADDRESS] == active_caller[CALLER_NETID])// Ensure the packet is sensible fuck_off_im_busy() return RECEIVE_SIGNAL_FINISHED if("tel_hup")//Remote side hangup - if(active_caller && signal.data[PACKET_SOURCE_ADDRESS] == active_caller[CALLER_NETID])// Ensure the packet is sensible + if(active_caller && signal.data[LEGACY_PACKET_SOURCE_ADDRESS] == active_caller[CALLER_NETID])// Ensure the packet is sensible switch(state) if(STATE_ANSWER) drop_call()// Call never connected, just reset. @@ -588,8 +588,8 @@ //Bundle up what we care about. var/datum/signal/v_signal = new(src, null, TRANSMISSION_WIRE) v_signal.has_magic_data = MAGIC_DATA_INVIOLABLE //We're sending a virtual speaker. This packet MUST be discarded. - v_signal.data[PACKET_SOURCE_ADDRESS] = null //(Set by post_signal), Just setting it to null means it's always first in the list. - v_signal.data[PACKET_DESTINATION_ADDRESS] = callstation.active_caller[CALLER_NETID] + v_signal.data[LEGACY_PACKET_SOURCE_ADDRESS] = null //(Set by post_signal), Just setting it to null means it's always first in the list. + v_signal.data[LEGACY_PACKET_DESTINATION_ADDRESS] = callstation.active_caller[CALLER_NETID] v_signal.data["command"] = "tel_voicedata" v_signal.data["virtualspeaker"] = v_speaker //This is a REAL REFERENCE. Packet MUST be discarded. v_signal.data["message"] = message diff --git a/code/game/machinery/datanet/README.md b/code/game/machinery/datanet/packetv1.md similarity index 67% rename from code/game/machinery/datanet/README.md rename to code/game/machinery/datanet/packetv1.md index e8e8dde7eb63..131076271d60 100644 --- a/code/game/machinery/datanet/README.md +++ b/code/game/machinery/datanet/packetv1.md @@ -1,9 +1,9 @@ # Data Networks, or: Why the OSI Model is for Pussies - ## Important Variables ### Data + These are the basic entries in a signal's data list, which are required for standard network transport. `s_addr` - Source Address, the ID of the machine that transmitted the packet. @@ -14,8 +14,9 @@ Example: ```json { - "s_addr":00000001, // We are being sent by device 1 - "d_addr":00000002, // intended for device 2 - "command":"do_thing", // and we want them to "do_thing" - "other_fields":"Are implimentation specific." + "PKT_HEAD_SOURCE_ADDR": 00000001, // We are being sent by device 1 + "PKT_HEAD_DEST_ADDR": 00000002, // intended for device 2 + "command": "do_thing", // and we want them to "do_thing" + "other_fields": "Are implimentation specific." } +``` diff --git a/code/game/machinery/datanet/packetv2.md b/code/game/machinery/datanet/packetv2.md new file mode 100644 index 000000000000..aaaa0b946e2b --- /dev/null +++ b/code/game/machinery/datanet/packetv2.md @@ -0,0 +1,17 @@ +```json +{ + "PKT_VERSION": 2, + "PKT_HEAD_SOURCE_ADDR": 00000001, // We are being sent by device 1 + "PKT_HEAD_DEST_ADDR": 00000002, // intended for device 2. + "PKT_HEAD_SOURCE_PORT": 1, // The port the packet was broadcast from. + "PKT_HEAD_DEST_PORT": 320, // The port the packet is destined for. This is often a fixed number based on the usage. + "PKT_HEAD_NETCLASS": "NETCLASS_ADAPTER", // The type of device describing the source. + "PKT_HEAD_PROTOCOL": "PKT_PROTOCOL_PDP", // The protocol describing the exchange format. + "PKT_PAYLOAD": { + "PKT_ARG_CMD": "keepalive", // A command to give to the recieving machine, using payload as parameters. + // Any misc. data not specified by the format. + "impl. specific value": "true", + "impl. specific value 2": 27 + } +} +``` diff --git a/code/game/machinery/embedded_controller/embedded_controller_base.dm b/code/game/machinery/embedded_controller/embedded_controller_base.dm index 6cf78c3ba8fe..7c0aef2fa87c 100644 --- a/code/game/machinery/embedded_controller/embedded_controller_base.dm +++ b/code/game/machinery/embedded_controller/embedded_controller_base.dm @@ -7,7 +7,7 @@ master = null . = ..() -/datum/computer/file/embedded_program/proc/post_signal(datum/signal/signal, comm_line) +/datum/computer/file/embedded_program/post_signal(datum/signal/signal, comm_line) SHOULD_CALL_PARENT(FALSE) // This is more of a relay than anything else. if(master) master.post_signal(signal, comm_line) diff --git a/code/game/machinery/telecomms/machines/message_server.dm b/code/game/machinery/telecomms/machines/message_server.dm index d2d74f4d3ff0..74481e9a2f15 100644 --- a/code/game/machinery/telecomms/machines/message_server.dm +++ b/code/game/machinery/telecomms/machines/message_server.dm @@ -158,9 +158,9 @@ TYPEINFO_DEF(/obj/machinery/blackbox_recorder) if(calibrating) // If we're calibrating, just return, the fancy part of us isn't ready yet. return var/list/sig_data = signal.data //cachemere sweater - switch(signal.data[PACKET_CMD]) + switch(signal.data[LEGACY_PACKET_COMMAND]) if(NETCMD_PDAMESSAGE) - var/datum/data_pda_message/log_unit = new(sig_data[PACKET_DESTINATION_ADDRESS], sig_data[PACKET_SOURCE_ADDRESS], sig_data["message"]) + var/datum/data_pda_message/log_unit = new(sig_data[LEGACY_PACKET_DESTINATION_ADDRESS], sig_data[LEGACY_PACKET_SOURCE_ADDRESS], sig_data["message"]) pda_msgs += log_unit return RECEIVE_SIGNAL_FINISHED else @@ -171,7 +171,7 @@ TYPEINFO_DEF(/obj/machinery/blackbox_recorder) if(isnull(sending_signal)) //nullcheck for sanic speed return //You need a pipe and something to send down it, though. if(!preserve_s_addr) - sending_signal.data[PACKET_SOURCE_ADDRESS] = src.net_id + sending_signal.data[LEGACY_PACKET_SOURCE_ADDRESS] = src.net_id sending_signal.transmission_method = TRANSMISSION_RADIO sending_signal.author = WEAKREF(src) // Override the sending signal author. diff --git a/code/modules/computer4/computer4.dm b/code/modules/computer4/computer4.dm index f7289b12f7a6..cecb03fbaeb6 100644 --- a/code/modules/computer4/computer4.dm +++ b/code/modules/computer4/computer4.dm @@ -252,8 +252,8 @@ TYPEINFO_DEF(/obj/machinery/computer4) if(!is_operational) return - for(var/datum/c4_file/terminal_program/program as anything in operating_system?.processing_programs) - program.peripheral_input(invoker, command, packet) + // Operating system can be null here if the computer is mid-reboot. + operating_system?.peripheral_input(invoker, command, packet) /obj/machinery/computer4/ui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src) diff --git a/code/modules/computer4/data/socket.dm b/code/modules/computer4/data/socket.dm new file mode 100644 index 000000000000..21c5164dd091 --- /dev/null +++ b/code/modules/computer4/data/socket.dm @@ -0,0 +1,78 @@ +/* + * Ported Datagram Protocol Socket + */ + +#define PDP_SOCKET_QUEUE_DEPTH 50 +/// 'Real' insert position, subject to BYOND Listism. +#define PDP_S_HEAD_REAL (head_pointer+1) +/// 'Real' read position, subject to BYOND Listism. +#define PDP_S_TAIL_REAL (tail_pointer+1) + +#if PDP_SOCKET_QUEUE_DEPTH < 3 +#error PDP_SOCKET_QUEUE_DEPTH is too short. If you trigger this, good fucking job:tm: +#endif + +/datum/pdp_socket + /// Next Hop datum we send our packets to. Usually a network card. + var/datum/outgoing_datum + /// 'Owner' that registered for this socket. Used to assure ownership. + var/datum/owner + /// PDP Port the socket is bound to, Packets being sent out of this socket will have their source port set to this. + var/bound_port + + + /// Packet ring buffer + VAR_PRIVATE/list/packet_buffer + /// Insertion point, Incremented on packet receive. Will drop instead if =tail_pointer-1 + /// Do not use directly, Must add 1 to account for list jank + VAR_PRIVATE/head_pointer + /// Read pointer, Incremented on packet read, Will not increment if there is no packet to read. + VAR_PRIVATE/tail_pointer + +/datum/pdp_socket/New(bound_port, outgoing_datum, owner) + if(!bound_port) + stack_trace("Created a PDP socket without a port number?") + + src.bound_port = bound_port + src.outgoing_datum = outgoing_datum + src.owner = owner + packet_buffer = new /list(PDP_SOCKET_QUEUE_DEPTH) + head_pointer = 0 + tail_pointer = 0 + +/datum/pdp_socket/Destroy(force, ...) + outgoing_datum = null + owner = null + return ..() + +/// Place received packet into ringqueue. Returns TRUE if inserted, FALSE if dropped due to full queue. +// No lohi I am not implimenting DSCP. Right now, at least. Maybe later. +/datum/pdp_socket/proc/enqueue(datum/signal/packet) + if(((head_pointer + 1) % PDP_SOCKET_QUEUE_DEPTH) == tail_pointer) + return FALSE //Ring full, Drop the packet. + packet_buffer[PDP_S_HEAD_REAL] = packet + head_pointer = (head_pointer+1) % PDP_SOCKET_QUEUE_DEPTH + return TRUE + +/// Get next signal in queue, or null if queue is dry. +/datum/pdp_socket/proc/pop() + . = packet_buffer[PDP_S_TAIL_REAL] + if(!.) + return null + tail_pointer = (tail_pointer+1) % PDP_SOCKET_QUEUE_DEPTH + //return . + +#undef PDP_SOCKET_QUEUE_DEPTH +#undef PDP_S_HEAD_REAL +#undef PDP_S_TAIL_REAL + +/// Send a PDP payload packet to the destionation port and address. +/datum/pdp_socket/proc/send_data(d_address, d_port, list/payload) + // Packets come out of this preeetty skeletonized, Higher layers above this are expected to fill out some remaining details + // Such as source address. + + var/list/packet_data = packetv2(null, d_address, bound_port, d_port, protocol = PKT_PROTOCOL_PDP, payload = payload) + + var/datum/signal/packet = new(null, packet_data) + + outgoing_datum.post_signal(packet) diff --git a/code/modules/computer4/data/terminal/medtrak/medtrak.dm b/code/modules/computer4/data/terminal/medtrak/medtrak.dm index fd8688a948f0..a688eab9d64b 100644 --- a/code/modules/computer4/data/terminal/medtrak/medtrak.dm +++ b/code/modules/computer4/data/terminal/medtrak/medtrak.dm @@ -68,7 +68,10 @@ /// Getter for the log file. This isn't kept as a ref because I don't want to manage the ref. :) /datum/c4_file/terminal_program/medtrak/proc/get_log_file() RETURN_TYPE(/datum/c4_file/text) - var/datum/c4_file/folder/log_dir = get_os().get_log_folder() + + // Sue me. Come up with a better way to do this that doesn't demand dead procs on the OS basetype. + // (Suggestion: Move medtrak and such to a thinkdos-specific subtype of terminal_program) (t_prog/dos/medtrak) + var/datum/c4_file/folder/log_dir = astype(get_os(), /datum/c4_file/terminal_program/operating_system/thinkdos).get_log_folder() if(!log_dir) return null diff --git a/code/modules/computer4/data/terminal/medtrak/medtrak_comment_commands.dm b/code/modules/computer4/data/terminal/medtrak/medtrak_comment_commands.dm index 74b4fd9fabb4..4bde9a1d5765 100644 --- a/code/modules/computer4/data/terminal/medtrak/medtrak_comment_commands.dm +++ b/code/modules/computer4/data/terminal/medtrak/medtrak_comment_commands.dm @@ -1,7 +1,7 @@ /datum/shell_command/medtrak/comment/quit aliases = list("quit", "q", "exit") -/datum/shell_command/medtrak/index/quit/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) +/datum/shell_command/medtrak/comment/quit/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) system.println("Quitting...") system.unload_program(program) diff --git a/code/modules/computer4/data/terminal/netpage/netpage.dm b/code/modules/computer4/data/terminal/netpage/netpage.dm index 6b341467bb6e..f52751e587e1 100644 --- a/code/modules/computer4/data/terminal/netpage/netpage.dm +++ b/code/modules/computer4/data/terminal/netpage/netpage.dm @@ -19,8 +19,6 @@ /datum/c4_file/terminal_program/netpage/execute(datum/c4_file/terminal_program/operating_system/thinkdos/system) . = ..() - if(.) - return var/title_text = list( @"
      ___ ___  __        __   ___
", diff --git a/code/modules/computer4/data/terminal/netpage/netpage_commands.dm b/code/modules/computer4/data/terminal/netpage/netpage_commands.dm index ee84fc9373cc..0bb21f3e7b8f 100644 --- a/code/modules/computer4/data/terminal/netpage/netpage_commands.dm +++ b/code/modules/computer4/data/terminal/netpage/netpage_commands.dm @@ -1,5 +1,16 @@ +/datum/shell_command/netpage/help + aliases = list("help") + help_text = "Lists all available commands. Use help \[command\] to view information about a specific command." + +/datum/shell_command/netpage/help/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) + var/list/output = list() + + if(generate_help_list(output, arguments, astype(program, /datum/c4_file/terminal_program/netpage).commands, system) != SHELL_CMD_HELP_ERROR) + system.println(jointext(output, "
")) + /datum/shell_command/netpage/quit aliases = list("quit", "q", "exit") + help_text = "Exits the program." /datum/shell_command/netpage/quit/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) system.println("Quitting...") diff --git a/code/modules/computer4/data/terminal/notepad/notepad.dm b/code/modules/computer4/data/terminal/notepad/notepad.dm index 916fe496e289..bb672b1ea206 100644 --- a/code/modules/computer4/data/terminal/notepad/notepad.dm +++ b/code/modules/computer4/data/terminal/notepad/notepad.dm @@ -16,8 +16,6 @@ /datum/c4_file/terminal_program/notepad/execute(datum/c4_file/terminal_program/operating_system/thinkdos/system) . = ..() - if(.) - return // Hope you saved your work motherfucker. working_line = 0 diff --git a/code/modules/computer4/data/terminal/notepad/notepad_commands.dm b/code/modules/computer4/data/terminal/notepad/notepad_commands.dm index e0520a1f45c4..4b79fffb8ece 100644 --- a/code/modules/computer4/data/terminal/notepad/notepad_commands.dm +++ b/code/modules/computer4/data/terminal/notepad/notepad_commands.dm @@ -3,50 +3,19 @@ help_text = "Lists all available commands. Use help \[command\] to view information about a specific command." /datum/shell_command/notepad/edit_cmd/help/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) - // Stupid fucking byond compiler bug -#if !defined(SPACEMAN_DMM) && !defined(OPENDREAM) -#pragma push -#pragma ignore unused_var -#endif - var/datum/c4_file/terminal_program/notepad/notepad = program -#if !defined(SPACEMAN_DMM) && !defined(OPENDREAM) -#pragma pop -#endif - var/list/output = list() - - if(length(arguments)) - var/found = FALSE - var/searching_for = jointext(arguments, "") - for(var/datum/shell_command/command_iter as anything in notepad.edit_commands) - if(searching_for in command_iter.aliases) - found = TRUE - output += "Displaying information for '[command_iter.aliases[1]]':" - output += command_iter.help_text - break - - if(!found) - system.println("This command is not supported by the help utility. To see a list of commands, type !help.") - return - - else - for(var/datum/shell_command/command_iter as anything in notepad.edit_commands) - if(length(command_iter.aliases) == 1) - output += command_iter.aliases[1] - continue - - output += "[command_iter.aliases[1]] ([jointext(command_iter.aliases.Copy(2), ", ")])" - - sortTim(output, GLOBAL_PROC_REF(cmp_text_asc)) - output.Insert(1, - "Typing text without a '!' prefix will write to the current line.", - "You can change lines by typing '!\[number\]'. Zero will change to highest line number.
", - "Use help \[command\] to see specific information about a command.", - "List of available commands:" - ) - - - system.println(jointext(output, "
")) + switch(generate_help_list(output, arguments, astype(program, /datum/c4_file/terminal_program/notepad).edit_commands, system)) + if(SHELL_CMD_HELP_GENERIC) + output.Insert(1, + "Typing text without a '!' prefix will write to the current line.", + "You can change lines by typing '!\[number\]'. Zero will change to highest line number.
", + "Use help \[command\] to see specific information about a command.", + "List of available commands:" + ) + if(SHELL_CMD_HELP_ERROR) + noop() + else + system.println(jointext(output, "
")) /datum/shell_command/notepad/edit_cmd/quit aliases = list("quit", "q", "exit") diff --git a/code/modules/computer4/data/terminal/operating_system.dm b/code/modules/computer4/data/terminal/operating_system.dm deleted file mode 100644 index 7437791d825a..000000000000 --- a/code/modules/computer4/data/terminal/operating_system.dm +++ /dev/null @@ -1,237 +0,0 @@ -/datum/c4_file/terminal_program/operating_system - name = "operating system" - extension = "TSYS" - size = 0 - - is_executable = FALSE - - /// Gotta be logged in to access anything. - var/logged_in = FALSE - - /// Current directory being operated on. - var/datum/c4_file/folder/current_directory - - /// The current focused program. - var/tmp/datum/c4_file/terminal_program/active_program - /// All programs currently running on the machine. - var/tmp/list/datum/c4_file/terminal_program/processing_programs = list() - - /// Halt And Catch Fire (Prevents STDIN, closest we can get to a HALT state.) - var/deadlocked = FALSE - -/datum/c4_file/terminal_program/operating_system/Destroy() - if(length(processing_programs)) - clean_up() - return ..() - -/// Should run this before executing any commands. -/datum/c4_file/terminal_program/operating_system/proc/is_operational() - return (!!get_computer()?.is_operational) && (!deadlocked) - -/// Change active directory. -/datum/c4_file/terminal_program/operating_system/proc/change_dir(datum/c4_file/folder/directory) - current_directory = directory - return TRUE - -/// Move a file to another location. -/datum/c4_file/terminal_program/operating_system/proc/move_file(datum/c4_file/file, datum/c4_file/folder/destination, error_pointer, overwrite = FALSE, new_name = "") - if(file.containing_folder == destination) - *error_pointer = "Cannot move folder into itself." - return FALSE - - if(!destination.can_add_file(file)) - *error_pointer = "Unable to move file to target." - return FALSE - - var/datum/c4_file/file_at_dest = destination.get_file(new_name || file.name, TRUE) - if(file_at_dest) - if(!overwrite) - *error_pointer = "Target in use." - return FALSE - - if(!destination.can_remove_file(file_at_dest)) - *error_pointer = "Unable to delete target." - return FALSE - - if(!file.containing_folder.can_remove_file(file)) - *error_pointer = "Unable to delete source." - return FALSE - - if(file_at_dest) - destination.try_delete_file(file_at_dest) - - file.containing_folder.try_remove_file(file) - destination.try_add_file(file) - - file.set_name(new_name) - return TRUE - -/// Find a file by it's name in the given directory. Defaults to the current directory. -/datum/c4_file/terminal_program/operating_system/proc/get_file(file_name, datum/c4_file/folder/working_directory, include_folders = FALSE) - if(!file_name) - return - - if(!working_directory) - working_directory = current_directory - - return working_directory.get_file(file_name, include_folders) - -/// Returns a file or folder with the given name inside of the given filepath relative to the working directory. -/datum/c4_file/terminal_program/operating_system/proc/resolve_filepath(file_path, datum/c4_file/folder/working_directory) - if(!file_path) - return - - if(!working_directory) - working_directory = current_directory - - var/list/split_path = splittext(file_path, "/") - - if(length(split_path) == 1) - if(split_path[1] == ".") - return working_directory - return get_file(split_path[1], working_directory, include_folders = TRUE) - - var/datum/file_path/path_info = text_to_filepath(file_path) - - var/datum/c4_file/folder/found_folder = parse_directory(path_info.directory, working_directory) - if(!found_folder) - return null - - if(!path_info.file_name) - return found_folder - - return get_file(path_info.file_name, found_folder, include_folders = TRUE) - -/// Write to the terminal. -/datum/c4_file/terminal_program/operating_system/proc/println(text, update_ui = TRUE) - if(isnull(text) || !is_operational()) - return FALSE - - - var/obj/machinery/computer4/computer = get_computer() - computer.text_buffer += "[text]
" - if(update_ui) - SStgui.update_uis(computer) - return TRUE - -/// Clear the screen completely. -/datum/c4_file/terminal_program/operating_system/proc/clear_screen(fully = FALSE) - if(!is_operational()) - return FALSE - - get_computer().text_buffer = "" - if(!fully) - println("Screen cleared.") - return TRUE - -/datum/c4_file/terminal_program/operating_system/proc/get_log_folder() - return - -/// Wrapper around handling text input to make sure we can actually handle it. -/datum/c4_file/terminal_program/operating_system/proc/try_std_in(text) - if(!text || !is_operational()) - return FALSE - - return active_program?.std_in(text) - -/// Unload everything including myself -/datum/c4_file/terminal_program/operating_system/proc/clean_up() - for(var/datum/c4_file/terminal_program/program as anything in processing_programs - src) - unload_program(program) - - if(src in processing_programs) - unload_program(src) - - get_computer()?.text_buffer = "" - get_computer()?.operating_system = null - -/// Run a program. -/datum/c4_file/terminal_program/operating_system/proc/execute_program(datum/c4_file/terminal_program/program) - if(!program) - return FALSE - - if(!program.can_execute(src)) - return FALSE - - if(!(program in processing_programs)) - add_processing_program(program) - - set_active_program(program) - program.execute(src) - return TRUE - -/// Close a program. -/datum/c4_file/terminal_program/operating_system/proc/unload_program(datum/c4_file/terminal_program/program) - if(!program) - return FALSE - - // Un-deadlock ourselves. - deadlocked = FALSE - - if(!(program in processing_programs)) - CRASH("Tried tried to remove a program we aren't even running.") - - remove_processing_program(program) - - if(active_program == program) - if(active_program == src) - set_active_program(null) - clean_up() - else - set_active_program(src) - - return TRUE - -/// Move a program to background -/datum/c4_file/terminal_program/operating_system/proc/try_background_program(datum/c4_file/terminal_program/program) - if(length(processing_programs) > 6) // Sane limit IMO - return FALSE - - if(active_program == program) - set_active_program(src) - - return TRUE - -/// Setter for the processing programs list. Use execute_program() instead! -/datum/c4_file/terminal_program/operating_system/proc/add_processing_program(datum/c4_file/terminal_program/program) - PRIVATE_PROC(TRUE) - - processing_programs += program - RegisterSignal(program, list(COMSIG_PARENT_QDELETING, COMSIG_COMPUTER4_FILE_ADDED), PROC_REF(processing_program_moved)) - - -/// Setter for the processing programs list. Use unload_program() instead! -/datum/c4_file/terminal_program/operating_system/proc/remove_processing_program(datum/c4_file/terminal_program/program) - processing_programs -= program - program.on_close(src) - UnregisterSignal(program, list(COMSIG_PARENT_QDELETING, COMSIG_COMPUTER4_FILE_ADDED)) - -/// Setter for active program. Use execute_program() or unload_program() instead! -/datum/c4_file/terminal_program/operating_system/proc/set_active_program(datum/c4_file/terminal_program/program) - PRIVATE_PROC(TRUE) - - active_program = program - -/// Handles any running programs being moved in the filesystem. -/datum/c4_file/terminal_program/operating_system/proc/processing_program_moved(datum/source) - SIGNAL_HANDLER - - if(source == src) - var/obj/machinery/computer4/computer = get_computer() - if(QDELING(src)) - clean_up() - return - - // Check if it's still in the root of either disk, this is fine :) - if(src in computer.internal_disk?.root.contents) - return - - if(src in computer.inserted_disk?.root.contents) - return - - // OS is not in a root folder, KILL!!! - clean_up() - return - - - unload_program(active_program) diff --git a/code/modules/computer4/data/terminal/operating_system/_operating_system.dm b/code/modules/computer4/data/terminal/operating_system/_operating_system.dm new file mode 100644 index 000000000000..c32b890deda5 --- /dev/null +++ b/code/modules/computer4/data/terminal/operating_system/_operating_system.dm @@ -0,0 +1,94 @@ +/datum/c4_file/terminal_program/operating_system + name = "operating system" + extension = "TSYS" + size = 0 + + is_executable = FALSE + + /// Gotta be logged in to access anything. + var/logged_in = FALSE + + /// Current directory being operated on. + var/datum/c4_file/folder/current_directory + + /// The current focused program. + var/tmp/datum/c4_file/terminal_program/active_program + /// All programs currently running on the machine. + var/tmp/list/datum/c4_file/terminal_program/processing_programs = list() + + /// Halt And Catch Fire (Prevents STDIN, closest we can get to a HALT state.) + var/deadlocked = FALSE + + /// Associative list of "port_num" : socket_instance + var/list/datum/pdp_socket/pdp_port_map = list() + +/datum/c4_file/terminal_program/operating_system/Destroy() + if(length(processing_programs)) + clean_up() + return ..() + +/// Should run this before executing any commands. +/datum/c4_file/terminal_program/operating_system/proc/is_operational() + return (!!get_computer()?.is_operational) && (!deadlocked) + +/// Write to the terminal. +/datum/c4_file/terminal_program/operating_system/proc/println(text, update_ui = TRUE) + if(isnull(text) || !is_operational()) + return FALSE + + + var/obj/machinery/computer4/computer = get_computer() + computer.text_buffer += "[text]
" + if(update_ui) + SStgui.update_uis(computer) + return TRUE + +/// Clear the screen completely. +/datum/c4_file/terminal_program/operating_system/proc/clear_screen(fully = FALSE) + if(!is_operational()) + return FALSE + + get_computer().text_buffer = "" + if(!fully) + println("Screen cleared.") + return TRUE + +/// Wrapper around handling text input to make sure we can actually handle it. +/datum/c4_file/terminal_program/operating_system/proc/try_std_in(text) + if(!text || !is_operational()) + return FALSE + + return active_program?.std_in(text) + +/// Unload everything including myself +/datum/c4_file/terminal_program/operating_system/proc/clean_up() + for(var/datum/c4_file/terminal_program/program as anything in processing_programs - src) + unload_program(program) + + if(src in processing_programs) + unload_program(src) + + get_computer()?.text_buffer = "" + get_computer()?.operating_system = null + + //Programs should clean these up, but just in case. + QDEL_LIST_ASSOC_VAL(pdp_port_map) + pdp_port_map.Cut() + +/datum/c4_file/terminal_program/operating_system/execute(datum/c4_file/terminal_program/operating_system/system) + if(system != src) + //If we aren't executing ourselves, something is nasty and wrong. + CRASH("System [system.type] tried to execute OS that isn't itself??") + + prepare_networking() + +/datum/c4_file/terminal_program/operating_system/peripheral_input(obj/item/peripheral/invoker, command, datum/signal/packet) + + if(command == PERIPHERAL_CMD_RECEIVE_PDP_PACKET) + pdp_incoming(packet) + return + + for(var/datum/c4_file/terminal_program/program as anything in processing_programs) + if(program == src) + continue + program.peripheral_input(invoker, command, packet) diff --git a/code/modules/computer4/data/terminal/operating_system/filesystem.dm b/code/modules/computer4/data/terminal/operating_system/filesystem.dm new file mode 100644 index 000000000000..aafbe274ccff --- /dev/null +++ b/code/modules/computer4/data/terminal/operating_system/filesystem.dm @@ -0,0 +1,73 @@ +/// Change active directory. +/datum/c4_file/terminal_program/operating_system/proc/change_dir(datum/c4_file/folder/directory) + current_directory = directory + return TRUE + +/// Move a file to another location. +/datum/c4_file/terminal_program/operating_system/proc/move_file(datum/c4_file/file, datum/c4_file/folder/destination, error_pointer, overwrite = FALSE, new_name = "") + if(file.containing_folder == destination) + *error_pointer = "Cannot move folder into itself." + return FALSE + + if(!destination.can_add_file(file)) + *error_pointer = "Unable to move file to target." + return FALSE + + var/datum/c4_file/file_at_dest = destination.get_file(new_name || file.name, TRUE) + if(file_at_dest) + if(!overwrite) + *error_pointer = "Target in use." + return FALSE + + if(!destination.can_remove_file(file_at_dest)) + *error_pointer = "Unable to delete target." + return FALSE + + if(!file.containing_folder.can_remove_file(file)) + *error_pointer = "Unable to delete source." + return FALSE + + if(file_at_dest) + destination.try_delete_file(file_at_dest) + + file.containing_folder.try_remove_file(file) + destination.try_add_file(file) + + file.set_name(new_name) + return TRUE + +/// Find a file by it's name in the given directory. Defaults to the current directory. +/datum/c4_file/terminal_program/operating_system/proc/get_file(file_name, datum/c4_file/folder/working_directory, include_folders = FALSE) + if(!file_name) + return + + if(!working_directory) + working_directory = current_directory + + return working_directory.get_file(file_name, include_folders) + +/// Returns a file or folder with the given name inside of the given filepath relative to the working directory. +/datum/c4_file/terminal_program/operating_system/proc/resolve_filepath(file_path, datum/c4_file/folder/working_directory) + if(!file_path) + return + + if(!working_directory) + working_directory = current_directory + + var/list/split_path = splittext(file_path, "/") + + if(length(split_path) == 1) + if(split_path[1] == ".") + return working_directory + return get_file(split_path[1], working_directory, include_folders = TRUE) + + var/datum/file_path/path_info = text_to_filepath(file_path) + + var/datum/c4_file/folder/found_folder = parse_directory(path_info.directory, working_directory) + if(!found_folder) + return null + + if(!path_info.file_name) + return found_folder + + return get_file(path_info.file_name, found_folder, include_folders = TRUE) diff --git a/code/modules/computer4/data/terminal/operating_system/networking.dm b/code/modules/computer4/data/terminal/operating_system/networking.dm new file mode 100644 index 000000000000..d42ca7ffb1f3 --- /dev/null +++ b/code/modules/computer4/data/terminal/operating_system/networking.dm @@ -0,0 +1,70 @@ +/datum/c4_file/terminal_program/operating_system/proc/prepare_networking() + +/// Request a socket from the OS. +/// A `port_number` of `PDP_BIND_EPHEMERAL_PORT` will result in being allocated an ephemeral port. +/datum/c4_file/terminal_program/operating_system/proc/bind_port(port_number, reliable = FALSE, datum/c4_file/binder) + RETURN_TYPE(/datum/pdp_socket) + if(!binder) + CRASH("Tried to bind a port: [isnull(port_number) ? "!NULL!" : port_number] without a binding program.") + if(isnull(port_number)) + CRASH("Program [binder] tried to bind a null port.") + if(port_number > PDP_MAX_PORT) + CRASH("Program [binder] tried to bind port above max, [port_number] > [PDP_MAX_PORT]") + + // Assign ephemeral port. + if(port_number == PDP_BIND_EPHEMERAL_PORT) + do + port_number = rand(PDP_EPHEMERAL_START, PDP_MAX_PORT) + while(pdp_port_map["[port_number]"]) + else + if(pdp_port_map["[port_number]"]) + return FALSE //Port already bound. + + var/datum/pdp_socket/socket = new(port_number, src, binder) + + pdp_port_map["[port_number]"] = socket + + return socket + +/// Requests the OS to free a socket. +/// A `port_number` of `PDP_FREE_ALL_PORTS` will result in all ports bound by the binder being freed. It is also the default behaviour. +/datum/c4_file/terminal_program/operating_system/proc/free_port(port_number = PDP_FREE_ALL_PORTS, datum/c4_file/binder) + if(isnull(port_number)) + CRASH("Program [binder] tried to free a null or 0 port.") + if(port_number > PDP_MAX_PORT) + CRASH("Program [binder] tried to free port above max, [port_number] > [PDP_MAX_PORT]") + if(port_number != PDP_FREE_ALL_PORTS) + // Free by specific port number + if(pdp_port_map["[port_number]"].owner == binder) //If the binder matches + pdp_port_map["[port_number]"] = null + return TRUE + else + //This should throw an OS error but we have no concept of stderr. + return FALSE + //else: free all ports therein bound. + var/freed_at_least_one = FALSE + for(var/port_num, port_socket in pdp_port_map) + if(astype(port_socket, /datum/pdp_socket).owner == binder) + pdp_port_map[port_num] = null + freed_at_least_one = TRUE + return freed_at_least_one + + + +/// Finish up outgoing program signals. +/// Eventually: Routing table? +/datum/c4_file/terminal_program/operating_system/post_signal(datum/signal/signal) + if(!signal) + CRASH("post signal wi no signal") + + var/obj/item/peripheral/network_card/wireless/wcard = get_computer().get_peripheral(PERIPHERAL_TYPE_WIRELESS_CARD) + if(!wcard) + return //cry + + wcard.post_signal(signal) + +/datum/c4_file/terminal_program/operating_system/proc/pdp_incoming(datum/signal/packet) + var/list/fields = packet.data + var/datum/pdp_socket/socket = pdp_port_map["[fields[PKT_HEAD_DEST_PORT]]"] + socket?.enqueue(packet) + diff --git a/code/modules/computer4/data/terminal/operating_system/program_management.dm b/code/modules/computer4/data/terminal/operating_system/program_management.dm new file mode 100644 index 000000000000..0e640ba1623d --- /dev/null +++ b/code/modules/computer4/data/terminal/operating_system/program_management.dm @@ -0,0 +1,90 @@ +/// Run a program. +/datum/c4_file/terminal_program/operating_system/proc/execute_program(datum/c4_file/terminal_program/program) + if(!program) + return FALSE + + if(!program.can_execute(src)) + return FALSE + + if(!(program in processing_programs)) + add_processing_program(program) + + set_active_program(program) + program.execute(src) + return TRUE + +/// Close a program. +/datum/c4_file/terminal_program/operating_system/proc/unload_program(datum/c4_file/terminal_program/program) + if(!program) + return FALSE + + // Un-deadlock ourselves. + deadlocked = FALSE + + if(!(program in processing_programs)) + CRASH("Tried tried to remove a program we aren't even running.") + + remove_processing_program(program) + + if(active_program == program) + if(active_program == src) + set_active_program(null) + clean_up() + else + set_active_program(src) + + return TRUE + +/// Move a program to background +/datum/c4_file/terminal_program/operating_system/proc/try_background_program(datum/c4_file/terminal_program/program) + if(length(processing_programs) > 6) // Sane limit IMO + return FALSE + + if(active_program == program) + set_active_program(src) + + return TRUE + +/// Setter for the processing programs list. Use execute_program() instead! +/datum/c4_file/terminal_program/operating_system/proc/add_processing_program(datum/c4_file/terminal_program/program) + PRIVATE_PROC(TRUE) + + processing_programs += program + RegisterSignal(program, list(COMSIG_PARENT_QDELETING, COMSIG_COMPUTER4_FILE_ADDED), PROC_REF(processing_program_moved)) + + +/// Setter for the processing programs list. Use unload_program() instead! +/datum/c4_file/terminal_program/operating_system/proc/remove_processing_program(datum/c4_file/terminal_program/program) + processing_programs -= program + program.on_close(src) + UnregisterSignal(program, list(COMSIG_PARENT_QDELETING, COMSIG_COMPUTER4_FILE_ADDED)) + +/// Setter for active program. Use execute_program() or unload_program() instead! +/datum/c4_file/terminal_program/operating_system/proc/set_active_program(datum/c4_file/terminal_program/program) + PRIVATE_PROC(TRUE) + + active_program = program + +/// Handles any running programs being moved in the filesystem. +/datum/c4_file/terminal_program/operating_system/proc/processing_program_moved(datum/source) + SIGNAL_HANDLER + + if(source == src) + var/obj/machinery/computer4/computer = get_computer() + if(QDELING(src)) + clean_up() + return + + // Check if it's still in the root of either disk, this is fine :) + if(src in computer.internal_disk?.root.contents) + return + + if(src in computer.inserted_disk?.root.contents) + return + + // OS is not in a root folder, KILL!!! + clean_up() + return + + + unload_program(active_program) diff --git a/code/modules/computer4/data/terminal/rtos/_rtos.dm b/code/modules/computer4/data/terminal/operating_system/rtos/_rtos.dm similarity index 98% rename from code/modules/computer4/data/terminal/rtos/_rtos.dm rename to code/modules/computer4/data/terminal/operating_system/rtos/_rtos.dm index 0f16f1984f3e..8513c98c4075 100644 --- a/code/modules/computer4/data/terminal/rtos/_rtos.dm +++ b/code/modules/computer4/data/terminal/operating_system/rtos/_rtos.dm @@ -103,7 +103,7 @@ /** RTOS.h - Post Signal * Follows standard post_signal calling conventions. */ -/datum/c4_file/terminal_program/operating_system/rtos/proc/post_signal(datum/signal/sending_signal, filter) +/datum/c4_file/terminal_program/operating_system/rtos/post_signal(datum/signal/sending_signal, filter) if(!is_operational()) return diff --git a/code/modules/computer4/data/terminal/rtos/access_door.dm b/code/modules/computer4/data/terminal/operating_system/rtos/access_door.dm similarity index 97% rename from code/modules/computer4/data/terminal/rtos/access_door.dm rename to code/modules/computer4/data/terminal/operating_system/rtos/access_door.dm index 2423be6ba5a1..c8980e5dc002 100644 --- a/code/modules/computer4/data/terminal/rtos/access_door.dm +++ b/code/modules/computer4/data/terminal/operating_system/rtos/access_door.dm @@ -226,7 +226,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "secure_open" + LEGACY_PACKET_COMMAND = "secure_open" ) ) expected_airlock_state = "open" @@ -235,7 +235,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "secure_close" + LEGACY_PACKET_COMMAND = "secure_close" ) ) expected_airlock_state = "closed" @@ -244,7 +244,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "status" + LEGACY_PACKET_COMMAND = "status" ) ) if(AC_COMMAND_BOLT) @@ -252,7 +252,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "lock" + LEGACY_PACKET_COMMAND = "lock" ) ) expected_bolt_state = "locked" @@ -261,7 +261,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "unlock" + LEGACY_PACKET_COMMAND = "unlock" ) ) expected_bolt_state = "unlocked" @@ -348,7 +348,7 @@ src, list( "tag" = tag_slave, - PACKET_CMD = NETCMD_UPDATE_DATA, + LEGACY_PACKET_COMMAND = NETCMD_UPDATE_DATA, PACKET_ARG_TEXTBUFFER = list2params(print_history), PACKET_ARG_DISPLAY = display_icon, PACKET_ARG_LEDS = display_indicators @@ -362,7 +362,7 @@ return //what if(tag_slave && (data["tag"] == tag_slave)) - switch(data[PACKET_CMD]) + switch(data[LEGACY_PACKET_COMMAND]) if("key") std_in(copytext(data["key"],1,2)) //Only one char, sorry. if(NETCMD_ECSLAVE_ACCESS) diff --git a/code/modules/computer4/data/terminal/rtos/pincode_door.dm b/code/modules/computer4/data/terminal/operating_system/rtos/pincode_door.dm similarity index 98% rename from code/modules/computer4/data/terminal/rtos/pincode_door.dm rename to code/modules/computer4/data/terminal/operating_system/rtos/pincode_door.dm index 9caadc16310f..4efed399d4ac 100644 --- a/code/modules/computer4/data/terminal/rtos/pincode_door.dm +++ b/code/modules/computer4/data/terminal/operating_system/rtos/pincode_door.dm @@ -385,7 +385,7 @@ src, list( "tag" = tag_slave, - PACKET_CMD = NETCMD_UPDATE_DATA, + LEGACY_PACKET_COMMAND = NETCMD_UPDATE_DATA, PACKET_ARG_TEXTBUFFER = list2params(print_history), PACKET_ARG_DISPLAY = display_icon, PACKET_ARG_LEDS = display_indicators @@ -398,7 +398,7 @@ if(!data["tag"]) return //what if(tag_slave && (data["tag"] == tag_slave)) - switch(data[PACKET_CMD]) + switch(data[LEGACY_PACKET_COMMAND]) if("key") std_in(copytext(data["key"],1,2)) //Only one char, sorry. if(NETCMD_UPDATE_REQUEST) @@ -434,7 +434,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "secure_open" + LEGACY_PACKET_COMMAND = "secure_open" ) ) expected_airlock_state = "open" @@ -443,7 +443,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "secure_close" + LEGACY_PACKET_COMMAND = "secure_close" ) ) expected_airlock_state = "closed" @@ -452,7 +452,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "status" + LEGACY_PACKET_COMMAND = "status" ) ) if(AC_COMMAND_BOLT) @@ -460,7 +460,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "lock" + LEGACY_PACKET_COMMAND = "lock" ) ) expected_bolt_state = "locked" @@ -469,7 +469,7 @@ src, list( "tag" = tag_target, - PACKET_CMD = "unlock" + LEGACY_PACKET_COMMAND = "unlock" ) ) expected_bolt_state = "unlocked" diff --git a/code/modules/computer4/data/terminal/rtos/simple_door_control.dm b/code/modules/computer4/data/terminal/operating_system/rtos/simple_door_control.dm similarity index 93% rename from code/modules/computer4/data/terminal/rtos/simple_door_control.dm rename to code/modules/computer4/data/terminal/operating_system/rtos/simple_door_control.dm index 016508082ebb..766a2edcbbb4 100644 --- a/code/modules/computer4/data/terminal/rtos/simple_door_control.dm +++ b/code/modules/computer4/data/terminal/operating_system/rtos/simple_door_control.dm @@ -88,7 +88,7 @@ src, list( "tag" = id_tag, - PACKET_CMD = "update" //Doesn't matter. + LEGACY_PACKET_COMMAND = "update" //Doesn't matter. ) ) post_signal(signal, RADIO_AIRLOCK) @@ -102,7 +102,7 @@ src, list( "tag" = id_tag, - PACKET_CMD = (doorbolt_state == "locked") ? "unlock" : "lock" + LEGACY_PACKET_COMMAND = (doorbolt_state == "locked") ? "unlock" : "lock" ) ) if("#") //Toggle Open @@ -110,7 +110,7 @@ src, list( "tag" = id_tag, - PACKET_CMD = (dooropen_state == "closed") ? "open" : "close" + LEGACY_PACKET_COMMAND = (dooropen_state == "closed") ? "open" : "close" ) ) else //Just probe the airlock to update state. diff --git a/code/modules/computer4/data/terminal/rtos/slave.dm b/code/modules/computer4/data/terminal/operating_system/rtos/slave.dm similarity index 92% rename from code/modules/computer4/data/terminal/rtos/slave.dm rename to code/modules/computer4/data/terminal/operating_system/rtos/slave.dm index 6194f2fde70f..91a77529414c 100644 --- a/code/modules/computer4/data/terminal/rtos/slave.dm +++ b/code/modules/computer4/data/terminal/operating_system/rtos/slave.dm @@ -25,7 +25,7 @@ src, list( "tag" = id_tag, - PACKET_CMD = NETCMD_UPDATE_REQUEST, + LEGACY_PACKET_COMMAND = NETCMD_UPDATE_REQUEST, ) ) post_signal(signal) @@ -40,7 +40,7 @@ /datum/c4_file/terminal_program/operating_system/rtos/slave/proc/handle_packet(datum/signal/packet) var/list/fields = packet.data - if(fields[PACKET_CMD] != NETCMD_UPDATE_DATA) + if(fields[LEGACY_PACKET_COMMAND] != NETCMD_UPDATE_DATA) return var/redraw_screen = FALSE @@ -76,7 +76,7 @@ src, list( "tag" = id_tag, - PACKET_CMD = NETCMD_ECSLAVE_ACCESS, + LEGACY_PACKET_COMMAND = NETCMD_ECSLAVE_ACCESS, "packet" = list2params(packet.data) ) ) @@ -87,7 +87,7 @@ src, list( "tag" = id_tag, - PACKET_CMD = "key", + LEGACY_PACKET_COMMAND = "key", "key" = text ) ) diff --git a/code/modules/computer4/data/terminal/thinkdos/thinkdos.dm b/code/modules/computer4/data/terminal/operating_system/thinkdos/thinkdos.dm similarity index 96% rename from code/modules/computer4/data/terminal/thinkdos/thinkdos.dm rename to code/modules/computer4/data/terminal/operating_system/thinkdos/thinkdos.dm index 5cc1f8c6bc57..0436a0ffba21 100644 --- a/code/modules/computer4/data/terminal/thinkdos/thinkdos.dm +++ b/code/modules/computer4/data/terminal/operating_system/thinkdos/thinkdos.dm @@ -55,6 +55,10 @@ else println("Type 'help' to get started.") +/datum/c4_file/terminal_program/operating_system/thinkdos/clean_up() + LAZYNULL(queued_commands) + return ..() + /datum/c4_file/terminal_program/operating_system/thinkdos/parse_std_in(text) RETURN_TYPE(/list/datum/shell_stdin) @@ -97,6 +101,12 @@ if(.) handle_command_queue() +/datum/c4_file/terminal_program/operating_system/thinkdos/tick(delta_time) + for(var/datum/c4_file/terminal_program/program as anything in processing_programs) + if(program == src) + continue + + program.tick(delta_time) /datum/c4_file/terminal_program/operating_system/thinkdos/proc/handle_command_queue() while(LAZYLEN(queued_commands)) //hmm... @@ -170,6 +180,38 @@ set_current_user(null) return TRUE +/// Returns the logging folder, attempting to create it if it doesn't already exist. +/datum/c4_file/terminal_program/operating_system/thinkdos/proc/get_log_folder() + var/datum/c4_file/folder/log_dir = parse_directory("logs", drive.root) + if(!log_dir) + log_dir = new /datum/c4_file/folder + log_dir.set_name("logs") + if(!drive.root.try_add_file(log_dir)) + qdel(log_dir) + return null + + return log_dir + +/// Create the log file, or append a startup log. +/datum/c4_file/terminal_program/operating_system/thinkdos/proc/initialize_logs() + if(command_log) + return TRUE + + var/datum/c4_file/folder/log_dir = get_log_folder() + var/datum/c4_file/text/log_file = log_dir.get_file("syslog") + if(!log_file) + log_file = new /datum/c4_file/text() + log_file.set_name("syslog") + if(!log_dir.try_add_file(log_file)) + qdel(log_file) + return FALSE + + command_log = log_file + RegisterSignal(command_log, list(COMSIG_COMPUTER4_FILE_RENAMED, COMSIG_COMPUTER4_FILE_ADDED, COMSIG_PARENT_QDELETING), PROC_REF(log_file_gone)) + + log_file.data += "
STARTUP: [stationtime2text()], [stationdate2text()]" + return TRUE + /datum/c4_file/terminal_program/operating_system/thinkdos/proc/initialize_accounts() var/datum/c4_file/folder/account_dir = parse_directory("users") if(!istype(account_dir)) @@ -204,38 +246,6 @@ //set_current_user(user_data) return TRUE -/// Returns the logging folder, attempting to create it if it doesn't already exist. -/datum/c4_file/terminal_program/operating_system/thinkdos/get_log_folder() - var/datum/c4_file/folder/log_dir = parse_directory("logs", drive.root) - if(!log_dir) - log_dir = new /datum/c4_file/folder - log_dir.set_name("logs") - if(!drive.root.try_add_file(log_dir)) - qdel(log_dir) - return null - - return log_dir - -/// Create the log file, or append a startup log. -/datum/c4_file/terminal_program/operating_system/thinkdos/proc/initialize_logs() - if(command_log) - return TRUE - - var/datum/c4_file/folder/log_dir = get_log_folder() - var/datum/c4_file/text/log_file = log_dir.get_file("syslog") - if(!log_file) - log_file = new /datum/c4_file/text() - log_file.set_name("syslog") - if(!log_dir.try_add_file(log_file)) - qdel(log_file) - return FALSE - - command_log = log_file - RegisterSignal(command_log, list(COMSIG_COMPUTER4_FILE_RENAMED, COMSIG_COMPUTER4_FILE_ADDED, COMSIG_PARENT_QDELETING), PROC_REF(log_file_gone)) - - log_file.data += "
STARTUP: [stationtime2text()], [stationdate2text()]" - return TRUE - /datum/c4_file/terminal_program/operating_system/thinkdos/proc/set_current_user(datum/c4_file/user/new_user) if(current_user) UnregisterSignal(current_user, list(COMSIG_COMPUTER4_FILE_RENAMED, COMSIG_COMPUTER4_FILE_ADDED, COMSIG_COMPUTER4_FILE_REMOVED)) @@ -251,6 +261,3 @@ unload_program(running_program) -/datum/c4_file/terminal_program/operating_system/thinkdos/clean_up() - LAZYNULL(queued_commands) - . = ..() diff --git a/code/modules/computer4/data/terminal/thinkdos/thinkdos_commands.dm b/code/modules/computer4/data/terminal/operating_system/thinkdos/thinkdos_commands.dm similarity index 95% rename from code/modules/computer4/data/terminal/thinkdos/thinkdos_commands.dm rename to code/modules/computer4/data/terminal/operating_system/thinkdos/thinkdos_commands.dm index abf075a28dc7..23f46fa7bc78 100644 --- a/code/modules/computer4/data/terminal/thinkdos/thinkdos_commands.dm +++ b/code/modules/computer4/data/terminal/operating_system/thinkdos/thinkdos_commands.dm @@ -5,6 +5,36 @@ /// How to use this command, usually printed by a "help" command. var/help_text = "N/A" +/datum/shell_command/New() + help_text = generate_help_text() + +/datum/shell_command/proc/generate_help_text() + return help_text + +/// Generates an output for a list of help commands. +/datum/shell_command/proc/generate_help_list(list/output, list/arguments, list/commands, datum/c4_file/terminal_program/operating_system/system) as /list + if(length(arguments)) + var/searching_for = jointext(arguments, "") + for(var/datum/shell_command/command_iter as anything in commands) + if(searching_for in command_iter.aliases) + output += "Displaying information for '[command_iter.aliases[1]]':" + output += command_iter.help_text + return SHELL_CMD_HELP_COMMAND + + system.println("This command is not supported by the help utility. To see a list of commands, type !help.") + return SHELL_CMD_HELP_ERROR + + // Listing all commands. + for(var/datum/shell_command/command_iter as anything in commands) + if(length(command_iter.aliases) == 1) + output += command_iter.aliases[1] + continue + + output += "[command_iter.aliases[1]] ([jointext(command_iter.aliases.Copy(2), ", ")])" + + sortTim(output, GLOBAL_PROC_REF(cmp_text_asc)) + return SHELL_CMD_HELP_GENERIC + /// Attempt to execute the command. Return TRUE if *any* action is taken. /datum/shell_command/proc/try_exec(command_name, datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) if(!(lowertext(command_name) in aliases)) @@ -24,33 +54,8 @@ /datum/shell_command/thinkdos/help/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) var/list/output = list() - if(length(arguments)) - var/found = FALSE - var/searching_for = jointext(arguments, "") - for(var/datum/shell_command/command_iter as anything in system.commands) - if(searching_for in command_iter.aliases) - found = TRUE - output += "Displaying information for '[command_iter.aliases[1]]':" - output += command_iter.help_text - break - - if(!found) - system.print_error("This command is not supported by the help utility. To see a list of commands, type help.") - return - - else - for(var/datum/shell_command/command_iter as anything in system.commands) - if(length(command_iter.aliases) == 1) - output += command_iter.aliases[1] - continue - - output += "[command_iter.aliases[1]] ([jointext(command_iter.aliases.Copy(2), ", ")])" - - sortTim(output, GLOBAL_PROC_REF(cmp_text_asc)) - output.Insert(1, "Use help \[command\] to see specific information about a command.", "List of available commands:") - - - system.println(jointext(output, "
")) + if(generate_help_list(output, arguments, system.commands, system) != SHELL_CMD_HELP_ERROR) + system.println(jointext(output, "
")) /// Clear the screen /datum/shell_command/thinkdos/home diff --git a/code/modules/computer4/data/terminal/thinkdos/thinkdos_signals.dm b/code/modules/computer4/data/terminal/operating_system/thinkdos/thinkdos_signals.dm similarity index 100% rename from code/modules/computer4/data/terminal/thinkdos/thinkdos_signals.dm rename to code/modules/computer4/data/terminal/operating_system/thinkdos/thinkdos_signals.dm diff --git a/code/modules/computer4/data/terminal/packMAN/packman.dm b/code/modules/computer4/data/terminal/packMAN/packman.dm new file mode 100644 index 000000000000..011674cf7a7e --- /dev/null +++ b/code/modules/computer4/data/terminal/packMAN/packman.dm @@ -0,0 +1,63 @@ +/datum/c4_file/terminal_program/packman + name = "packMAN" + + var/mode = PACKMAN_MODE_UNDEFINED + var/datum/pdp_socket/socket + + var/static/list/commands + +/datum/c4_file/terminal_program/packman/New() + if(!commands) + commands = list() + for(var/path as anything in subtypesof(/datum/shell_command/packman_cmd)) + commands += new path + +/datum/c4_file/terminal_program/packman/execute(datum/c4_file/terminal_program/operating_system/thinkdos/system) + . = ..() + if(!.) + return + + system.println("packMAN V1.01", FALSE) + system.println("Welcome to packMAN, type 'help' to get started.") + + if(!get_adapter()) + system.println("Error: No network adapter found.") + +/datum/c4_file/terminal_program/packman/on_close(datum/c4_file/terminal_program/operating_system/thinkdos/system) + . = ..() + mode = PACKMAN_MODE_UNDEFINED + socket = null + +/// Getter for a network adapter. +/datum/c4_file/terminal_program/packman/proc/get_adapter() + RETURN_TYPE(/obj/item/peripheral/network_card) + return get_computer().get_peripheral(PERIPHERAL_TYPE_WIRELESS_CARD) + +/datum/c4_file/terminal_program/packman/std_in(text) + . = ..() + if(.) + return + + get_os().println(text) + + var/datum/shell_stdin/parsed_input = parse_std_in(text) + + var/datum/c4_file/terminal_program/operating_system/os = get_os() + + for(var/datum/shell_command/potential_command as anything in commands) + if(potential_command.try_exec(parsed_input.command, os, src, parsed_input.arguments, parsed_input.options)) + return TRUE + + get_os().println("'[html_encode(parsed_input.raw)]' is not recognized as an internal or external command.") + +/datum/c4_file/terminal_program/packman/tick(delta_time) + . = ..() + if(!socket) + return + + var/datum/c4_file/terminal_program/operating_system/system = get_os() + var/datum/signal/packet + while((packet = socket.pop())) + system.println( + html_encode(json_encode(packet.data)) + ) diff --git a/code/modules/computer4/data/terminal/packMAN/packman_commands.dm b/code/modules/computer4/data/terminal/packMAN/packman_commands.dm new file mode 100644 index 000000000000..e8efbf06e6f0 --- /dev/null +++ b/code/modules/computer4/data/terminal/packMAN/packman_commands.dm @@ -0,0 +1,53 @@ +/datum/shell_command/packman_cmd/chat + aliases = list("c", "chat") + +/datum/shell_command/packman_cmd/chat/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) + if(length(arguments) < 2) + system.println("Error: Invalid argument count.") + return + + var/datum/c4_file/terminal_program/packman/packman = program + + var/address = arguments[1] + var/payload = jointext(arguments.Copy(2), " ") + + packman.socket.send_data(address, PDP_PORT_NETTEST, list(payload)) + system.println(html_encode(payload)) + +/datum/shell_command/packman_cmd/init + aliases = list("init") + +/datum/shell_command/packman_cmd/init/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) + if(!length(arguments)) + system.println("Error: Invalid argument count.") + return + + if(!(lowertext(arguments[1]) in list("c", "s"))) + system.println("Error: Invalid argument.") + return + + var/datum/c4_file/terminal_program/packman/packman = program + + if(packman.mode != PACKMAN_MODE_UNDEFINED) + return + + packman.mode = (lowertext(arguments[1]) == "s") ? PACKMAN_MODE_SERVER : PACKMAN_MODE_CLIENT + + if(packman.mode == PACKMAN_MODE_SERVER) + packman.socket = system.bind_port(PDP_PORT_NETTEST, FALSE, packman) + if(!packman.socket) + system.println("Error: Socket binding failed.") + return + + else + packman.socket = system.bind_port(PDP_BIND_EPHEMERAL_PORT, FALSE, packman) + if(!packman.socket) + system.println("Error: Socket binding failed.") + return + + system.println("Bound port to [packman.socket.bound_port] as [packman.mode == PACKMAN_MODE_SERVER ? "SERVER" : "CLIENT"]") + +/datum/shell_command/packman_cmd/quit/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) + system.println("Quitting...") + system.unload_program(program) + return diff --git a/code/modules/computer4/data/terminal/probe/probe.dm b/code/modules/computer4/data/terminal/probe/probe.dm index 22048c7966c1..d9b6c1add768 100644 --- a/code/modules/computer4/data/terminal/probe/probe.dm +++ b/code/modules/computer4/data/terminal/probe/probe.dm @@ -13,8 +13,6 @@ /datum/c4_file/terminal_program/probe/execute(datum/c4_file/terminal_program/operating_system/thinkdos/system) . = ..() - if(!.) - return system.println("NetProbe V2.4", FALSE) system.println("Welcome to NetProbe, type 'help' to get started.") @@ -48,11 +46,11 @@ if(!packet) return - if(!packet.data[PACKET_NETCLASS] || !packet.data[PACKET_SOURCE_ADDRESS] || (packet.data[PACKET_CMD] != NET_COMMAND_PING_REPLY)) + if(!packet.data[LEGACY_PACKET_NETCLASS] || !packet.data[LEGACY_PACKET_SOURCE_ADDRESS] || (packet.data[LEGACY_PACKET_COMMAND] != NET_COMMAND_PING_REPLY)) return - var/reply_netclass = packet.data[PACKET_NETCLASS] - var/reply_id = packet.data[PACKET_SOURCE_ADDRESS] + var/reply_netclass = packet.data[LEGACY_PACKET_NETCLASS] + var/reply_id = packet.data[LEGACY_PACKET_SOURCE_ADDRESS] ping_replies[reply_id] = reply_netclass get_os().println("\[[reply_netclass]\]-TYPE: [reply_id]") diff --git a/code/modules/computer4/data/terminal/probe/probe_commands.dm b/code/modules/computer4/data/terminal/probe/probe_commands.dm index 09b2a4f834f7..31c1faf4fc88 100644 --- a/code/modules/computer4/data/terminal/probe/probe_commands.dm +++ b/code/modules/computer4/data/terminal/probe/probe_commands.dm @@ -1,5 +1,16 @@ +/datum/shell_command/probe_cmd/help + aliases = list("help") + help_text = "Lists all available commands. Use help \[command\] to view information about a specific command." + +/datum/shell_command/probe_cmd/help/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) + var/list/output = list() + + if(generate_help_list(output, arguments, astype(program, /datum/c4_file/terminal_program/probe).commands, system) != SHELL_CMD_HELP_ERROR) + system.println(jointext(output, "
")) + /datum/shell_command/probe_cmd/ping - aliases = list("ping, p") + aliases = list("ping", "p") + help_text = "Pings the radio frequency the network card is tuned to." /datum/shell_command/probe_cmd/ping/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) var/datum/c4_file/terminal_program/probe/probe = program @@ -10,10 +21,12 @@ return if(adapter.ping()) + probe.ping_replies.Cut() system.println("Pinging '[format_frequency(adapter.frequency)]'...") /datum/shell_command/probe_cmd/view - aliases = list("view, v") + aliases = list("view", "v") + help_text = "Lists all ping responses since the last ping." /datum/shell_command/probe_cmd/view/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) var/datum/c4_file/terminal_program/probe/probe = program @@ -34,6 +47,14 @@ /datum/shell_command/probe_cmd/quit aliases = list("quit", "q") +/datum/shell_command/probe_cmd/quit/generate_help_text() + return jointext(list( + "Exits the program, moving it to the background.", + "Usage: 'quit'", + "", + "-f, --force [FOURSPACES]Exits the program without moving it to background.", + ), "
") + /datum/shell_command/probe_cmd/quit/exec(datum/c4_file/terminal_program/operating_system/thinkdos/system, datum/c4_file/terminal_program/program, list/arguments, list/options) var/force = !!length(options & list("f", "force")) diff --git a/code/modules/computer4/peripherals/network_card.dm b/code/modules/computer4/peripherals/network_card.dm index 49b65fd8a687..9ad424bc6617 100644 --- a/code/modules/computer4/peripherals/network_card.dm +++ b/code/modules/computer4/peripherals/network_card.dm @@ -52,17 +52,17 @@ radio_connection = SSpackets.add_object(src, new_frequency) /// Post a signal. Has safety checks, so calling this with a timer is OK. -/obj/item/peripheral/network_card/wireless/proc/post_signal(datum/signal/packet, filter) +/obj/item/peripheral/network_card/wireless/post_signal(datum/signal/packet, filter) if(!master_pc?.is_operational || !radio_connection) return - packet.data[PACKET_SOURCE_ADDRESS] = network_id + packet.data[LEGACY_PACKET_SOURCE_ADDRESS] = network_id // Rewrite the author so we don't get the packet we just sent back. packet.author = WEAKREF(src) radio_connection.post_signal(packet, filter) /obj/item/peripheral/network_card/wireless/proc/deferred_post_signal(datum/signal/packet, filter, time) - addtimer(CALLBACK(src, PROC_REF(post_signal), packet, filter), time) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum, post_signal), packet, filter), time) /obj/item/peripheral/network_card/wireless/receive_signal(datum/signal/signal) if(!master_pc) @@ -74,19 +74,19 @@ switch(listen_mode) if(WIRELESS_FILTER_NETADDR) // Isn't meant for us, but could be a ping - if(signal.data[PACKET_DESTINATION_ADDRESS] != network_id) - if(!signal.data[PACKET_SOURCE_ADDRESS] || (signal.data[PACKET_DESTINATION_ADDRESS] != NET_ADDRESS_PING)) + if(signal.data[LEGACY_PACKET_DESTINATION_ADDRESS] != network_id) + if(!signal.data[LEGACY_PACKET_SOURCE_ADDRESS] || (signal.data[LEGACY_PACKET_DESTINATION_ADDRESS] != NET_ADDRESS_PING)) return // Is not a ping, bye bye! var/list/data = list( - PACKET_SOURCE_ADDRESS = network_id, - PACKET_DESTINATION_ADDRESS = signal.data[PACKET_SOURCE_ADDRESS], - PACKET_CMD = NET_COMMAND_PING_REPLY, - PACKET_NETCLASS = NETCLASS_ADAPTER, + LEGACY_PACKET_SOURCE_ADDRESS = network_id, + LEGACY_PACKET_DESTINATION_ADDRESS = signal.data[LEGACY_PACKET_SOURCE_ADDRESS], + LEGACY_PACKET_COMMAND = NET_COMMAND_PING_REPLY, + LEGACY_PACKET_NETCLASS = NETCLASS_ADAPTER, ) var/datum/signal/packet = new(src, data, TRANSMISSION_RADIO) - addtimer(CALLBACK(src, PROC_REF(post_signal), packet), 1 SECOND) + addtimer(CALLBACK(src, TYPE_PROC_REF(/datum, post_signal), packet), 1 SECOND) return if(WIRELESS_FILTER_ID_TAGS) //Drop packets not in our ID tags list. @@ -97,10 +97,11 @@ //allow all */ - - var/datum/signal/clone = signal.Copy() - master_pc.peripheral_input(src, PERIPHERAL_CMD_RECEIVE_PACKET, clone) + if(signal.data[PKT_HEAD_PROTOCOL] == PKT_PROTOCOL_PDP) + master_pc.peripheral_input(src, PERIPHERAL_CMD_RECEIVE_PDP_PACKET, clone) + else + master_pc.peripheral_input(src, PERIPHERAL_CMD_RECEIVE_PACKET, clone) /obj/item/peripheral/network_card/wireless/proc/ping() if(!COOLDOWN_FINISHED(src, ping_cooldown)) @@ -108,8 +109,8 @@ COOLDOWN_START(src, ping_cooldown, 2 SECONDS) var/list/data = list( - PACKET_SOURCE_ADDRESS = network_id, - PACKET_DESTINATION_ADDRESS = NET_ADDRESS_PING, + LEGACY_PACKET_SOURCE_ADDRESS = network_id, + LEGACY_PACKET_DESTINATION_ADDRESS = NET_ADDRESS_PING, ) var/datum/signal/packet = new(src, data) diff --git a/code/modules/modular_computers/file_system/programs/budgetordering.dm b/code/modules/modular_computers/file_system/programs/budgetordering.dm index 6dfda716ac35..6da89cfd01a7 100644 --- a/code/modules/modular_computers/file_system/programs/budgetordering.dm +++ b/code/modules/modular_computers/file_system/programs/budgetordering.dm @@ -292,7 +292,7 @@ if(.) post_signal(cargo_shuttle) -/datum/computer_file/program/budgetorders/proc/post_signal(command) +/datum/computer_file/program/budgetorders/post_signal(command) SHOULD_CALL_PARENT(FALSE) //TODO: Tie to cablenet var/datum/radio_frequency/frequency = SSpackets.return_frequency(FREQ_STATUS_DISPLAYS) diff --git a/code/modules/modular_computers/file_system/programs/ntmessenger.dm b/code/modules/modular_computers/file_system/programs/ntmessenger.dm index e95b26bebebd..29c3d273963b 100644 --- a/code/modules/modular_computers/file_system/programs/ntmessenger.dm +++ b/code/modules/modular_computers/file_system/programs/ntmessenger.dm @@ -93,7 +93,7 @@ var/list/signal_data = signal.data if(!signal_data) return - var/signal_command = signal_data[PACKET_CMD] + var/signal_command = signal_data[LEGACY_PACKET_COMMAND] //Network ID verification is "hardware accelerated" (AKA: Done for us by the card) var/rigged = FALSE//are we going to explode? @@ -104,7 +104,7 @@ // ESPECIALLY THIS FUCKER RIGHT HERE vvvv if(signal_data[SSpackets.pda_exploitable_register] == SSpackets.detomatix_magic_packet) //This one falls through to standard PDA behaviour, so we need to be checked first. - if(signal_data[PACKET_DESTINATION_ADDRESS] == netcard_cache.hardware_id)//No broadcast bombings, fuck off. + if(signal_data[LEGACY_PACKET_DESTINATION_ADDRESS] == netcard_cache.hardware_id)//No broadcast bombings, fuck off. //Calculate our "difficulty" var/difficulty var/obj/item/computer_hardware/hard_drive/role/our_jobdisk = computer.all_components[MC_HDD_JOB] @@ -114,7 +114,7 @@ difficulty++ //if cartridge has manifest access it has extra snowflake difficulty if(!((SEND_SIGNAL(computer, COMSIG_TABLET_CHECK_DETONATE) & COMPONENT_TABLET_NO_DETONATE) || prob(difficulty * 15))) rigged = TRUE //Cool, we're allowed to blow up. Really glad this whole check wasn't for nothing. - var/trait_timer_key = signal_data[PACKET_SOURCE_ADDRESS] + var/trait_timer_key = signal_data[LEGACY_PACKET_SOURCE_ADDRESS] ADD_TRAIT(computer, TRAIT_PDA_CAN_EXPLODE, trait_timer_key) ADD_TRAIT(computer, TRAIT_PDA_MESSAGE_MENU_RIGGED, trait_timer_key) addtimer(TRAIT_CALLBACK_REMOVE(computer, TRAIT_PDA_MESSAGE_MENU_RIGGED, trait_timer_key), 10 SECONDS) @@ -127,7 +127,7 @@ html_decode("\"[signal_data["message"]]\"") || "#ERROR_MISSING_FIELD", FALSE, signal_data["automated"] || FALSE, - signal_data[PACKET_SOURCE_ADDRESS] || null + signal_data[LEGACY_PACKET_SOURCE_ADDRESS] || null ) if(ringer_status) @@ -189,7 +189,7 @@ L = get(holder.holder, /mob/living/silicon) if(L && L.stat == CONSCIOUS) - var/reply = "(Reply)" + var/reply = "(Reply)" var/hrefstart var/hrefend var/job_string = signal_data["job"] ? " ([signal_data["job"]])" : "" @@ -197,7 +197,7 @@ hrefstart = "" hrefend = "" - if(signal_data[PACKET_SOURCE_ADDRESS] == null) + if(signal_data[LEGACY_PACKET_SOURCE_ADDRESS] == null) reply = "\[#ERRNOADDR\]" if(signal_data["automated"]) @@ -269,11 +269,11 @@ var/datum/signal/pda_message = new( src, list( - PACKET_CMD = NETCMD_PDAMESSAGE, + LEGACY_PACKET_COMMAND = NETCMD_PDAMESSAGE, "name" = fake_name || computer.saved_identification, "job" = fake_job || computer.saved_job, "message" = html_decode(message), - PACKET_DESTINATION_ADDRESS = target_address + LEGACY_PACKET_DESTINATION_ADDRESS = target_address ), logging_data = user ) @@ -354,7 +354,7 @@ if(!istype(pnetcard)) //This catches nulls too, so... to_chat(usr, span_warning("Radio missing or bad driver!")) var/datum/signal/ping_sig = new(src, list( - PACKET_DESTINATION_ADDRESS = NET_ADDRESS_PING, + LEGACY_PACKET_DESTINATION_ADDRESS = NET_ADDRESS_PING, "pda_scan" = "true" )) pnetcard.post_signal(ping_sig) diff --git a/code/modules/modular_computers/hardware/gprs_card.dm b/code/modules/modular_computers/hardware/gprs_card.dm index 4b5ad47f60b7..123f8573d933 100644 --- a/code/modules/modular_computers/hardware/gprs_card.dm +++ b/code/modules/modular_computers/hardware/gprs_card.dm @@ -62,14 +62,14 @@ if(signal.transmission_method != TRANSMISSION_RADIO) CRASH("[src] received non-radio packet, transmission method ID [signal.transmission_method], Expected [TRANSMISSION_RADIO]") var/list/signal_data = signal.data //medium velocity silver hedgehog - var/signal_d_addr = signal_data[PACKET_DESTINATION_ADDRESS] + var/signal_d_addr = signal_data[LEGACY_PACKET_DESTINATION_ADDRESS] if(signal_d_addr == NET_ADDRESS_PING) //Ping. var/datum/signal/outgoing = new( src, list( - PACKET_DESTINATION_ADDRESS = signal_data[PACKET_SOURCE_ADDRESS], - PACKET_CMD = NET_COMMAND_PING_REPLY, - PACKET_NETCLASS = NETCLASS_GRPS_CARD, + LEGACY_PACKET_DESTINATION_ADDRESS = signal_data[LEGACY_PACKET_SOURCE_ADDRESS], + LEGACY_PACKET_COMMAND = NET_COMMAND_PING_REPLY, + LEGACY_PACKET_NETCLASS = NETCLASS_GRPS_CARD, "netaddr" = hardware_id ) ) @@ -83,11 +83,11 @@ //Either it's broadcast or directed to us. if(isnull(signal_d_addr) || signal_d_addr == hardware_id) // If it's a ping reply, check for a PDA. - if(signal.data[PACKET_CMD] == NET_COMMAND_PING_REPLY) + if(signal.data[LEGACY_PACKET_COMMAND] == NET_COMMAND_PING_REPLY) //If it's from a GPRS card, respond, otherwise, who cares. - if(signal.data[PACKET_NETCLASS] == NETCLASS_GRPS_CARD) + if(signal.data[LEGACY_PACKET_NETCLASS] == NETCLASS_GRPS_CARD) var/list/new_pda_info = list( - "target_addr" = signal.data[PACKET_SOURCE_ADDRESS], + "target_addr" = signal.data[LEGACY_PACKET_SOURCE_ADDRESS], "name" = signal.data["reg_name"] || "#UNK", "job" = signal.data["reg_job"] || "#UNK" ) @@ -98,10 +98,10 @@ append_signal(signal) -/obj/item/computer_hardware/network_card/packetnet/proc/post_signal(datum/signal/signal) +/obj/item/computer_hardware/network_card/packetnet/post_signal(datum/signal/signal) if(!radio_connection || !signal) return FALSE // Something went wrong. - signal.data[PACKET_SOURCE_ADDRESS] = hardware_id //Readdress outgoing packets. + signal.data[LEGACY_PACKET_SOURCE_ADDRESS] = hardware_id //Readdress outgoing packets. signal.author = WEAKREF(src) radio_connection.post_signal(signal, RADIO_PDAMESSAGE) return TRUE //We at least tried. diff --git a/code/modules/modular_computers/hardware/virus_disk.dm b/code/modules/modular_computers/hardware/virus_disk.dm index 2bbda2e7c554..4d65293906da 100644 --- a/code/modules/modular_computers/hardware/virus_disk.dm +++ b/code/modules/modular_computers/hardware/virus_disk.dm @@ -30,7 +30,7 @@ var/list/user_input_tuple = user_input(target_addr, user) var/datum/signal/outgoing = new(src, list( SSpackets.pda_exploitable_register = magic_packet, - PACKET_DESTINATION_ADDRESS = target_addr + LEGACY_PACKET_DESTINATION_ADDRESS = target_addr )) var/signal_data = outgoing.data switch(user_input_tuple[1]) @@ -121,7 +121,7 @@ var/list/pda_data_staple = list( // We already have the target address // GPRS Card handles the source address - PACKET_CMD = NETCMD_PDAMESSAGE, + LEGACY_PACKET_COMMAND = NETCMD_PDAMESSAGE, "name" = sender_name, "job" = sender_job, "message" = text_message diff --git a/daedalus.dme b/daedalus.dme index 80c89495262b..2a680d07a51c 100644 --- a/daedalus.dme +++ b/daedalus.dme @@ -403,6 +403,7 @@ #include "code\__HELPERS\mouse_control.dm" #include "code\__HELPERS\nameof.dm" #include "code\__HELPERS\names.dm" +#include "code\__HELPERS\packetnet.dm" #include "code\__HELPERS\piping_colors_lists.dm" #include "code\__HELPERS\priority_announce.dm" #include "code\__HELPERS\pronouns.dm" @@ -2999,6 +3000,7 @@ #include "code\modules\computer4\computer4_types.dm" #include "code\modules\computer4\data\metadata.dm" #include "code\modules\computer4\data\shell_stdin.dm" +#include "code\modules\computer4\data\socket.dm" #include "code\modules\computer4\data\c4_file\_c4_file.dm" #include "code\modules\computer4\data\c4_file\fab_design_bundle.dm" #include "code\modules\computer4\data\c4_file\folder.dm" @@ -3007,7 +3009,6 @@ #include "code\modules\computer4\data\c4_file\text.dm" #include "code\modules\computer4\data\c4_file\user_data.dm" #include "code\modules\computer4\data\terminal\_terminal_program.dm" -#include "code\modules\computer4\data\terminal\operating_system.dm" #include "code\modules\computer4\data\terminal\directive\directman.dm" #include "code\modules\computer4\data\terminal\directive\directman_commands.dm" #include "code\modules\computer4\data\terminal\medtrak\medtrak.dm" @@ -3018,19 +3019,25 @@ #include "code\modules\computer4\data\terminal\medtrak\medtrak_record_commands.dm" #include "code\modules\computer4\data\terminal\netpage\netpage.dm" #include "code\modules\computer4\data\terminal\netpage\netpage_commands.dm" +#include "code\modules\computer4\data\terminal\operating_system\_operating_system.dm" +#include "code\modules\computer4\data\terminal\operating_system\filesystem.dm" +#include "code\modules\computer4\data\terminal\operating_system\networking.dm" +#include "code\modules\computer4\data\terminal\operating_system\program_management.dm" +#include "code\modules\computer4\data\terminal\operating_system\rtos\_rtos.dm" +#include "code\modules\computer4\data\terminal\operating_system\rtos\access_door.dm" +#include "code\modules\computer4\data\terminal\operating_system\rtos\pincode_door.dm" +#include "code\modules\computer4\data\terminal\operating_system\rtos\simple_door_control.dm" +#include "code\modules\computer4\data\terminal\operating_system\rtos\slave.dm" +#include "code\modules\computer4\data\terminal\operating_system\thinkdos\thinkdos.dm" +#include "code\modules\computer4\data\terminal\operating_system\thinkdos\thinkdos_commands.dm" +#include "code\modules\computer4\data\terminal\operating_system\thinkdos\thinkdos_signals.dm" +#include "code\modules\computer4\data\terminal\packMAN\packman.dm" +#include "code\modules\computer4\data\terminal\packMAN\packman_commands.dm" +#include "code\modules\computer4\data\terminal\probe\probe.dm" +#include "code\modules\computer4\data\terminal\probe\probe_commands.dm" #include "code\modules\computer4\data\terminal\notepad\notepad.dm" #include "code\modules\computer4\data\terminal\notepad\notepad_commands.dm" #include "code\modules\computer4\data\terminal\packet_hound\packet_hound.dm" -#include "code\modules\computer4\data\terminal\probe\probe.dm" -#include "code\modules\computer4\data\terminal\probe\probe_commands.dm" -#include "code\modules\computer4\data\terminal\rtos\_rtos.dm" -#include "code\modules\computer4\data\terminal\rtos\access_door.dm" -#include "code\modules\computer4\data\terminal\rtos\pincode_door.dm" -#include "code\modules\computer4\data\terminal\rtos\simple_door_control.dm" -#include "code\modules\computer4\data\terminal\rtos\slave.dm" -#include "code\modules\computer4\data\terminal\thinkdos\thinkdos.dm" -#include "code\modules\computer4\data\terminal\thinkdos\thinkdos_commands.dm" -#include "code\modules\computer4\data\terminal\thinkdos\thinkdos_signals.dm" #include "code\modules\computer4\embedded_controller\access_door.dm" #include "code\modules\computer4\embedded_controller\embedded_controller.dm" #include "code\modules\computer4\embedded_controller\pincode_door.dm" diff --git a/tgui/packages/tgui/interfaces/Terminal/TerminalOutputSection.tsx b/tgui/packages/tgui/interfaces/Terminal/TerminalOutputSection.tsx index 551ad1712e92..e7111e97ad8b 100644 --- a/tgui/packages/tgui/interfaces/Terminal/TerminalOutputSection.tsx +++ b/tgui/packages/tgui/interfaces/Terminal/TerminalOutputSection.tsx @@ -42,6 +42,9 @@ export const TerminalOutputSection = (props: TerminalOutputSectionProps) => { height="100%" color={fontColor} fontSize="1.2em" + style={{ + wordBreak: 'break-all', + }} preserveWhitespace dangerouslySetInnerHTML={{ __html: displayHTML }} />