1
-- pchat by hugeblank, Feb 2023
2
-- Requires computer have a wireless modem,
3
-- and be licensed with a chatbox.
4
-- Usage:
5
-- ^pcjoin <channel [1-65535]> <passkey> - Join a channel.
6
-- ^pchat <message> - Send a message to joined channel.
7
-- ^pclist - List current users in joined channel.
8
-- ^pcleave - Disconnect from joined channel.
9
-- All command names can be modified, see commandNames table. Ex, changing ^pchat to ^p
10
sleep(0.5)
11
local aes = require("aes")
12
local sha = require("sha")
13
local aliases = require("aliases")
14
assert(chatbox, "Missing a chatbox! Run `/chatbox license` in chat to get started.")
15
16
local modem
17
do
18
local modems = {peripheral.find("modem")}
19
local i = 1
20
while i <= #modems and not modem do
21
if modems[i].isWireless() then
22
modem = modems[i]
23
end
24
i = i+1
25
end
26
if not modem then
27
printError("Wireless Modem not found")
28
end
29
end
30
31
local owner = chatbox.getLicenseOwner()
32
local commands = {}
33
local key, channel
34
local users = {}
35
36
local function packet(type, message)
37
local data = {
38
type = type,
39
message = message,
40
}
41
local encData = aes.encrypt_str(textutils.serialise(data), key)
42
modem.transmit(channel, channel, encData)
43
end
44
45
local function unpacket(encData)
46
local data
47
pcall(function()
48
data = textutils.unserialise(aes.decrypt_str(encData, key))
49
end)
50
if type(data) == "table" then
51
return data.type, data.message
52
end
53
end
54
55
local function printError(...)
56
chatbox.tell(owner, "&c"..table.concat(table.pack(...), " "), "pchat", nil, "format")
57
end
58
59
local function print(...)
60
chatbox.tell(owner, table.concat(table.pack(...), " "), "pchat")
61
end
62
63
local function status(...)
64
chatbox.tell(owner, "&e"..table.concat(table.pack(...), " "), "pchat", nil, "format")
65
end
66
67
local function isJoined()
68
if not key then
69
printError("Not joined to any channel!")
70
return false
71
end
72
return true
73
end
74
75
-- pchat
76
commands[aliases.pchat] = function(args)
77
if isJoined() then
78
packet("message", {
79
user = owner,
80
message = table.concat(args, " ")
81
})
82
print("<"..owner.."> "..table.concat(args, " "))
83
end
84
end
85
86
-- pcleave
87
commands[aliases.pcleave] = function(args)
88
if isJoined() then
89
packet("leave", owner)
90
status("Left channel "..channel)
91
key, channel = nil, nil
92
users = {}
93
end
94
end
95
96
-- pcjoin
97
commands[aliases.pcjoin] = function(args)
98
local nchannel, nkey = tonumber(args[1]), args[2]
99
if not nchannel then
100
printError("Expected channel number, got "..(args[1] or "nil"))
101
return
102
elseif not nkey then
103
printError("Missing passcode.")
104
return
105
end
106
if key then
107
packet("leave", owner)
108
modem.close(channel)
109
status("Switched channels from", channel, "to", nchannel, ".")
110
else
111
status("Joined channel "..nchannel)
112
end
113
key = aes.strToBlocks(sha.digestStr("000-PCHAT-"..nkey))[1]
114
channel = nchannel
115
users = {
116
[owner] = true
117
}
118
modem.open(channel)
119
packet("join", owner)
120
packet("getList")
121
end
122
123
-- pclist
124
commands[aliases.pclist] = function()
125
local out = {
126
"Current users in channel:",
127
}
128
for user in pairs(users) do
129
out[#out+1] = user
130
end
131
local str = table.concat(out, "\n"):gsub("&", "")
132
print(str)
133
end
134
135
local args = {...}
136
if #args == 2 then
137
commands[aliases.pcjoin](args)
138
else
139
_G.print("PChat is now running! Usage:")
140
_G.print("^pcjoin <channel> <passcode>")
141
_G.print("^pcleave")
142
_G.print("^pclist")
143
_G.print("^pchat <message>")
144
end
145
146
while true do
147
local e, user, command, args, data = os.pullEventRaw()
148
if e == "command" then
149
if data.ownerOnly and user == owner then
150
for key, alias in pairs(aliases) do
151
for i = 1, #alias do
152
if command == alias[i] then
153
commands[aliases[key]](args)
154
break
155
end
156
end
157
end
158
elseif user == owner and commands[command] then
159
printError("pchat command leaked! When using pchat commands *always* use ^ instead of \\!")
160
end
161
elseif e == "modem_message" then
162
local m_type, message = unpacket(data)
163
if m_type == "message" and type(message) == "table" and message.owner and message.message then
164
print("<"..tostring(message.owner)..">"..tostring(message.message))
165
elseif m_type == "join" and type(message) == "string" then
166
status(message:gsub("&", "").." has joined the channel.")
167
users[message] = true
168
elseif m_type == "leave" and type(message) == "string" then
169
status(message:gsub("&", "").." has left the channel.")
170
users[message] = nil
171
elseif m_type == "getList" then
172
packet("list", owner)
173
elseif m_type == "list" and type(message) == "string" then
174
users[message] = true
175
end
176
end
177
end