-- pchat by hugeblank, Feb 2023 -- Requires computer have a wireless modem, -- and be licensed with a chatbox. -- Usage: -- ^pcjoin - Join a channel. -- ^pchat - Send a message to joined channel. -- ^pclist - List current users in joined channel. -- ^pcleave - Disconnect from joined channel. -- All command names can be modified, see commandNames table. Ex, changing ^pchat to ^p sleep(0.5) local aes = require("aes") local sha = require("sha") local aliases = require("aliases") assert(chatbox, "Missing a chatbox! Run `/chatbox license` in chat to get started.") local modem do local modems = {peripheral.find("modem")} local i = 1 while i <= #modems and not modem do if modems[i].isWireless() then modem = modems[i] end i = i+1 end if not modem then printError("Wireless Modem not found") end end local owner = chatbox.getLicenseOwner() local commands = {} local key, channel local users = {} local function packet(type, message) local data = { type = type, message = message, } local encData = aes.encrypt_str(textutils.serialise(data), key) modem.transmit(channel, channel, encData) end local function unpacket(encData) local data local ok = pcall(function() data = textutils.unserialise(aes.decrypt_str(encData, key)) end) if ok then return data.type, data.message end end local function printError(...) chatbox.tell(owner, "&c"..table.concat(table.pack(...), " "), "pchat", nil, "format") end local function print(...) chatbox.tell(owner, table.concat(table.pack(...), " "), "pchat") end local function status(...) chatbox.tell(owner, "&e"..table.concat(table.pack(...), " "), "pchat", nil, "format") end local function isJoined() if not key then printError("Not joined to any channel!") return false end return true end -- pchat commands[aliases.pchat] = function(args) if isJoined() then local msg = table.concat(args, " ") packet("message", { user = owner, message = msg }) print("<"..owner.."> "..msg) end end -- pcleave commands[aliases.pcleave] = function(args) if isJoined() then packet("leave", owner) status("Left channel "..channel) key, channel = nil, nil users = {} end end -- pcjoin commands[aliases.pcjoin] = function(args) local nchannel, nkey = tonumber(args[1]), args[2] if not nchannel then printError("Expected channel number, got "..(args[1] or "nil")) return elseif not nkey then printError("Missing passcode.") return end if key then packet("leave", owner) modem.close(channel) status("Switched channels from", channel, "to", nchannel, ".") else status("Joined channel "..nchannel) end key = aes.strToBlocks(sha.digestStr("000-PCHAT-"..nkey))[1] channel = nchannel users = { [owner] = true } modem.open(channel) packet("join", owner) packet("getList") end -- pclist commands[aliases.pclist] = function() local out = { "Current users in channel:", } for user in pairs(users) do out[#out+1] = user end local str = table.concat(out, "\n"):gsub("&", "") print(str) end local args = {...} if #args == 2 then commands[aliases.pcjoin](args) else _G.print("PChat is now running! Usage:") _G.print("^pcjoin ") _G.print("^pcleave") _G.print("^pclist") _G.print("^pchat ") end while true do local e, user, command, args, data = os.pullEventRaw() if e == "command" then if data.ownerOnly and user == owner then for key, alias in pairs(aliases) do for i = 1, #alias do if command == alias[i] then commands[aliases[key]](args) break end end end elseif user == owner and commands[command] then printError("pchat command leaked! When using pchat commands *always* use ^ instead of \\!") end elseif e == "modem_message" then local m_type, message = unpacket(data) if m_type == "message" and type(message) == "table" and message.user and message.message then print("<"..tostring(message.user).."> "..tostring(message.message)) elseif m_type == "join" and type(message) == "string" then status(message:gsub("&", "").." has joined the channel.") users[message] = true elseif m_type == "leave" and type(message) == "string" then status(message:gsub("&", "").." has left the channel.") users[message] = nil elseif m_type == "getList" then packet("list", owner) elseif m_type == "list" and type(message) == "string" then users[message] = true end end end