gamja/commands.js

435 lines
11 KiB
JavaScript
Raw Normal View History

import * as irc from "./lib/irc.js";
import { SERVER_BUFFER, BufferType, Unread } from "./state.js";
2020-07-13 11:22:24 -04:00
2021-01-22 11:36:53 -05:00
function getActiveClient(app) {
2021-06-10 12:11:11 -04:00
let buf = app.state.buffers.get(app.state.activeBuffer);
2021-01-22 11:36:53 -05:00
if (!buf) {
throw new Error("Not connected to server");
2021-01-22 11:36:53 -05:00
}
return app.clients.get(buf.server);
2021-01-22 11:36:53 -05:00
}
function getActiveTarget(app) {
2021-06-10 12:11:11 -04:00
let activeBuffer = app.state.buffers.get(app.state.activeBuffer);
if (!activeBuffer) {
throw new Error("Not in a buffer");
}
return activeBuffer.name;
}
function getActiveChannel(app) {
2021-06-10 12:11:11 -04:00
let activeBuffer = app.state.buffers.get(app.state.activeBuffer);
if (!activeBuffer || activeBuffer.type !== BufferType.CHANNEL) {
throw new Error("Not in a channel");
}
return activeBuffer.name;
}
2023-04-19 06:51:13 -04:00
async function setUserHostMode(app, args, mode) {
2021-06-10 12:11:11 -04:00
let nick = args[0];
2021-06-03 04:11:48 -04:00
if (!nick) {
throw new Error("Missing nick");
}
2021-06-10 12:11:11 -04:00
let activeChannel = getActiveChannel(app);
let client = getActiveClient(app);
2023-04-19 06:51:13 -04:00
let whois = await client.whois(nick);
const info = whois[irc.RPL_WHOISUSER].params;
const user = info[2];
const host = info[3];
client.send({
command: "MODE",
params: [activeChannel, mode, `*!${user}@${host}`],
2021-06-03 04:11:48 -04:00
});
}
2021-05-27 16:02:08 -04:00
function markServerBufferUnread(app) {
2021-06-22 07:38:05 -04:00
let activeBuffer = app.state.buffers.get(app.state.activeBuffer);
if (!activeBuffer || activeBuffer.type === BufferType.SERVER) {
return;
}
app.setBufferState({ server: activeBuffer.server }, (buf) => {
return { unread: Unread.union(buf.unread, Unread.MESSAGE) };
});
}
2021-05-27 08:13:22 -04:00
const join = {
2022-02-02 11:40:19 -05:00
usage: "<name> [password]",
2021-05-27 08:13:22 -04:00
description: "Join a channel",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let channel = args[0];
2021-05-27 08:13:22 -04:00
if (!channel) {
throw new Error("Missing channel name");
}
2022-02-02 11:40:19 -05:00
if (args.length > 1) {
app.open(channel, null, args[1]);
} else {
app.open(channel);
}
2021-05-27 08:13:22 -04:00
},
};
2021-05-27 16:02:08 -04:00
const kick = {
usage: "<nick> [comment]",
2021-05-27 16:02:08 -04:00
description: "Remove a user from the channel",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let nick = args[0];
let activeChannel = getActiveChannel(app);
let params = [activeChannel, nick];
2021-05-27 16:02:08 -04:00
if (args.length > 1) {
params.push(args.slice(1).join(" "));
}
getActiveClient(app).send({ command: "KICK", params });
},
};
const ban = {
usage: "[nick]",
description: "Ban a user from the channel, or display the current ban list",
execute: (app, args) => {
2024-10-13 18:56:18 -04:00
if (args.length === 0) {
let activeChannel = getActiveChannel(app);
getActiveClient(app).send({
command: "MODE",
params: [activeChannel, "+b"],
});
} else {
return setUserHostMode(app, args, "+b");
}
},
};
function givemode(app, args, mode) {
// TODO: Handle several users at once
2021-06-10 12:11:11 -04:00
let nick = args[0];
if (!nick) {
throw new Error("Missing nick");
}
2021-06-10 12:11:11 -04:00
let activeChannel = getActiveChannel(app);
getActiveClient(app).send({
command: "MODE",
params: [activeChannel, mode, nick],
});
}
2020-07-13 11:22:24 -04:00
export default {
2021-12-13 11:31:35 -05:00
"away": {
usage: "[message]",
description: "Set away message",
execute: (app, args) => {
2024-09-29 05:48:45 -04:00
const params = [];
2021-12-13 11:31:35 -05:00
if (args.length) {
params.push(args.join(" "));
}
getActiveClient(app).send({command: "AWAY", params});
},
},
"ban": ban,
2021-03-08 11:25:00 -05:00
"buffer": {
usage: "<name>",
description: "Switch to a buffer",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let name = args[0];
for (let buf of app.state.buffers.values()) {
2021-03-08 11:25:00 -05:00
if (buf.name === name) {
app.switchBuffer(buf);
return;
}
2021-03-07 15:06:26 -05:00
}
2021-03-08 11:25:00 -05:00
throw new Error("Unknown buffer");
},
2020-07-13 11:22:24 -04:00
},
2021-03-08 11:25:00 -05:00
"close": {
description: "Close the current buffer",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let activeBuffer = app.state.buffers.get(app.state.activeBuffer);
2024-10-13 18:56:18 -04:00
if (!activeBuffer || activeBuffer.type === BufferType.SERVER) {
2021-03-08 11:25:00 -05:00
throw new Error("Not in a user or channel buffer");
}
app.close(activeBuffer.id);
},
2020-07-13 11:22:24 -04:00
},
2021-05-27 13:48:49 -04:00
"deop": {
usage: "<nick>",
description: "Remove operator status for a user on this channel",
execute: (app, args) => givemode(app, args, "-o"),
},
"devoice": {
usage: "<nick>",
description: "Remove voiced status for a user on this channel",
execute: (app, args) => givemode(app, args, "-v"),
2021-05-27 13:48:49 -04:00
},
2021-03-08 11:25:00 -05:00
"disconnect": {
description: "Disconnect from the server",
execute: (app, args) => {
app.disconnect();
},
2021-03-07 15:06:26 -05:00
},
2021-03-08 11:25:00 -05:00
"help": {
description: "Show help menu",
execute: (app, args) => {
app.openHelp();
},
},
2021-05-28 12:21:05 -04:00
"invite": {
usage: "<nick>",
description: "Invite a user to the channel",
2021-05-28 12:21:05 -04:00
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let nick = args[0];
2021-05-28 12:21:05 -04:00
if (!nick) {
throw new Error("Missing nick");
}
2021-06-10 12:11:11 -04:00
let activeChannel = getActiveChannel(app);
2021-05-28 12:21:05 -04:00
getActiveClient(app).send({ command: "INVITE", params: [
nick, activeChannel,
2021-05-28 12:21:05 -04:00
]});
},
},
2021-05-27 08:13:22 -04:00
"j": join,
"join": join,
2021-05-27 16:02:08 -04:00
"kick": kick,
"kickban": {
usage: "<target>",
description: "Ban a user and removes them from the channel",
execute: (app, args) => {
2021-05-27 16:02:08 -04:00
kick.execute(app, args);
ban.execute(app, args);
},
},
2021-05-28 19:02:16 -04:00
"lusers": {
usage: "[<mask> [<target>]]",
description: "Request user statistics about the network",
2021-05-28 19:02:16 -04:00
execute: (app, args) => {
getActiveClient(app).send({ command: "LUSERS", params: args });
markServerBufferUnread(app);
2021-05-28 19:02:16 -04:00
},
},
2021-03-08 11:25:00 -05:00
"me": {
usage: "<action>",
description: "Send an action message to the current buffer",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let action = args.join(" ");
let target = getActiveTarget(app);
let text = `\x01ACTION ${action}\x01`;
app.privmsg(target, text);
2021-03-08 11:25:00 -05:00
},
2020-07-13 11:22:24 -04:00
},
2021-05-23 05:41:04 -04:00
"mode": {
usage: "[target] [modes] [mode args...]",
description: "Query or change a channel or user mode",
2021-05-23 05:41:04 -04:00
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let target = args[0];
if (!target || target.startsWith("+") || target.startsWith("-")) {
2021-06-10 12:11:11 -04:00
let activeChannel = getActiveChannel(app);
args = [activeChannel, ...args];
2021-05-27 09:37:09 -04:00
}
2021-05-23 05:41:04 -04:00
getActiveClient(app).send({ command: "MODE", params: args });
},
},
2021-05-28 05:17:37 -04:00
"motd": {
usage: "[server]",
description: "Get the Message Of The Day",
execute: (app, args) => {
getActiveClient(app).send({ command: "MOTD", params: args });
markServerBufferUnread(app);
2021-05-28 05:17:37 -04:00
},
},
2021-03-08 11:25:00 -05:00
"msg": {
usage: "<target> <message>",
description: "Send a message to a nickname or a channel",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let target = args[0];
let text = args.slice(1).join(" ");
2021-03-08 11:25:00 -05:00
getActiveClient(app).send({ command: "PRIVMSG", params: [target, text] });
},
2021-03-07 15:06:26 -05:00
},
2021-03-08 11:25:00 -05:00
"nick": {
usage: "<nick>",
description: "Change current nickname",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let newNick = args[0];
2021-03-08 11:25:00 -05:00
getActiveClient(app).send({ command: "NICK", params: [newNick] });
},
2020-07-13 11:22:24 -04:00
},
2021-03-08 11:25:00 -05:00
"notice": {
usage: "<target> <message>",
description: "Send a notice to a nickname or a channel",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let target = args[0];
let text = args.slice(1).join(" ");
2021-03-08 11:25:00 -05:00
getActiveClient(app).send({ command: "NOTICE", params: [target, text] });
},
2020-08-13 05:04:39 -04:00
},
2021-05-27 13:48:49 -04:00
"op": {
usage: "<nick>",
description: "Give a user operator status on this channel",
execute: (app, args) => givemode(app, args, "+o"),
2021-05-27 13:48:49 -04:00
},
2021-03-08 11:25:00 -05:00
"part": {
usage: "[reason]",
description: "Leave a channel",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let reason = args.join(" ");
let activeChannel = getActiveChannel(app);
let params = [activeChannel];
2021-03-08 11:25:00 -05:00
if (reason) {
params.push(reason);
}
getActiveClient(app).send({ command: "PART", params });
},
2021-03-07 15:06:26 -05:00
},
2021-03-08 11:25:00 -05:00
"query": {
usage: "<nick> [message]",
2021-03-08 11:25:00 -05:00
description: "Open a buffer to send messages to a nickname",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let nick = args[0];
2021-03-08 11:25:00 -05:00
if (!nick) {
throw new Error("Missing nickname");
}
app.open(nick);
if (args.length > 1) {
2021-09-06 10:53:25 -04:00
let text = args.slice(1).join(" ");
app.privmsg(nick, text);
}
2021-03-08 11:25:00 -05:00
},
2021-03-07 15:06:26 -05:00
},
2021-06-10 18:27:19 -04:00
"quiet": {
usage: "[nick]",
description: "Quiet a user in the channel, or display the current quiet list",
execute: (app, args) => {
2024-10-13 18:56:18 -04:00
if (args.length === 0) {
2021-06-10 18:27:19 -04:00
getActiveClient(app).send({
command: "MODE",
params: [getActiveChannel(app), "+q"],
});
} else {
return setUserHostMode(app, args, "+q");
}
},
},
2021-03-08 11:25:00 -05:00
"quit": {
description: "Quit",
execute: (app, args) => {
app.close({ name: SERVER_BUFFER });
},
2021-03-07 15:06:26 -05:00
},
"quote": {
usage: "<command>",
description: "Send a raw IRC command to the server",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let msg;
try {
msg = irc.parseMessage(args.join(" "));
} catch (err) {
throw new Error("Failed to parse IRC command: " + err.message);
}
getActiveClient(app).send(msg);
},
},
2021-03-08 11:25:00 -05:00
"reconnect": {
description: "Reconnect to the server",
execute: (app, args) => {
app.reconnect();
},
2020-07-13 11:22:24 -04:00
},
2021-05-25 14:22:21 -04:00
"setname": {
usage: "<realname>",
description: "Change current realname",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let newRealname = args.join(" ");
let client = getActiveClient(app);
2021-12-10 09:34:51 -05:00
if (!client.caps.enabled.has("setname")) {
2021-05-25 14:22:21 -04:00
throw new Error("Server doesn't support changing the realname");
}
client.send({ command: "SETNAME", params: [newRealname] });
2021-12-10 09:34:51 -05:00
// TODO: save to local storage
2021-05-25 14:22:21 -04:00
},
},
2021-05-27 08:36:46 -04:00
"stats": {
2021-05-28 07:58:39 -04:00
usage: "<query> [server]",
description: "Request server statistics",
2021-05-27 08:36:46 -04:00
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let query = args[0];
2021-05-27 08:36:46 -04:00
if (!query) {
throw new Error("Missing query");
}
2021-06-10 12:11:11 -04:00
let params = [query];
2021-05-27 08:36:46 -04:00
if (args.length > 1) {
params.push(args.slice(1).join(" "));
}
getActiveClient(app).send({ command: "STATS", params });
markServerBufferUnread(app);
2021-05-27 08:36:46 -04:00
},
},
2021-03-08 11:25:00 -05:00
"topic": {
usage: "<topic>",
description: "Change the topic of the current channel",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let activeChannel = getActiveChannel(app);
let params = [activeChannel];
2021-03-08 11:25:00 -05:00
if (args.length > 0) {
params.push(args.join(" "));
}
getActiveClient(app).send({ command: "TOPIC", params });
},
2020-07-13 11:22:24 -04:00
},
2021-06-03 04:25:33 -04:00
"unban": {
usage: "<nick>",
description: "Remove a user from the ban list",
execute: (app, args) => {
return setUserHostMode(app, args, "-b");
},
},
2021-06-10 18:27:19 -04:00
"unquiet": {
usage: "<nick>",
description: "Remove a user from the quiet list",
execute: (app, args) => {
return setUserHostMode(app, args, "-q");
},
},
"voice": {
usage: "<nick>",
description: "Give a user voiced status on this channel",
execute: (app, args) => givemode(app, args, "+v"),
},
2021-05-31 11:02:56 -04:00
"who": {
usage: "<mask>",
2021-05-31 11:02:56 -04:00
description: "Retrieve a list of users",
execute: (app, args) => {
getActiveClient(app).send({ command: "WHO", params: args });
markServerBufferUnread(app);
2021-05-31 11:02:56 -04:00
},
},
"whois": {
usage: "<nick>",
description: "Retrieve information about a user",
execute: (app, args) => {
2021-06-10 12:11:11 -04:00
let nick = args[0];
if (!nick) {
throw new Error("Missing nick");
}
2021-05-31 11:02:56 -04:00
getActiveClient(app).send({ command: "WHOIS", params: [nick] });
markServerBufferUnread(app);
},
},
2021-07-03 13:24:20 -04:00
"whowas": {
usage: "<nick> [count]",
description: "Retrieve information about an offline user",
execute: (app, args) => {
if (args.length < 1) {
throw new Error("Missing nick");
}
getActiveClient(app).send({ command: "WHOWAS", params: args });
markServerBufferUnread(app);
},
},
"list": {
usage: "[filter]",
description: "Retrieve a list of channels from a network",
execute: (app, args) => {
getActiveClient(app).send({ command: "LIST", params: args });
markServerBufferUnread(app);
},
},
2020-07-13 11:22:24 -04:00
};