~emersion/public-inbox

gamja: Add /whois command v3 APPLIED

Drew DeVault: 2
 Add /whois command
 Add /ban, /kickban commands

 4 files changed, 110 insertions(+), 13 deletions(-)
Pushed, thanks!
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~emersion/public-inbox/patches/23034/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH gamja v3 1/2] Add /whois command Export this patch

This also rigs up some helpers in Client for handling the whois
response, which I will use for /ban and /quiet and such shortly.
---
 commands.js   | 11 +++++++++++
 lib/client.js | 35 +++++++++++++++++++++++++++++++++++
 lib/irc.js    |  7 +++++++
 3 files changed, 53 insertions(+)

diff --git a/commands.js b/commands.js
index 483894f..b4ba9f8 100644
--- a/commands.js
+++ b/commands.js
@@ -258,4 +258,15 @@ export default {
			getActiveClient(app).send({ command: "TOPIC", params });
		},
	},
	"whois": {
		usage: "<user>",
		description: "Retrieve information about a user",
		execute: (app, args) => {
			var user = args[0];
			if (!user) {
				throw new Error("Missing user");
			}
			getActiveClient(app).whois(user);
		},
	},
};
diff --git a/lib/client.js b/lib/client.js
index 8dea847..423e6f0 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -48,6 +48,7 @@ export default class Client extends EventTarget {
	reconnectTimeoutID = null;
	pendingHistory = Promise.resolve(null);
	cm = irc.CaseMapping.RFC1459;
	whoisDB = new irc.CaseMapMap(null, irc.CaseMapping.RFC1459);

	constructor(params) {
		super();
@@ -201,6 +202,18 @@ export default class Client extends EventTarget {
				this.send({ command: "CAP", params: ["END"] });
			}
			break;
		case irc.RPL_WHOISUSER:
		case irc.RPL_WHOISSERVER:
		case irc.RPL_WHOISOPERATOR:
		case irc.RPL_WHOISIDLE:
		case irc.RPL_WHOISCHANNELS:
		case irc.RPL_ENDOFWHOIS:
				var nick = msg.params[1];
				if (!this.whoisDB.has(nick)) {
					this.whoisDB.set(nick, {});
				};
				this.whoisDB.get(nick)[msg.command] = msg;
				break;
		case irc.ERR_NICKLOCKED:
		case irc.ERR_SASLFAIL:
		case irc.ERR_SASLTOOLONG:
@@ -271,6 +284,27 @@ export default class Client extends EventTarget {
		}
	}

	whois(target, callback) {
		var msg = { command: "WHOIS", params: [target] };
		return this.roundtrip(msg, event => {
			var msg = event.detail.message;
			switch (msg.command) {
			case irc.RPL_ENDOFWHOIS:
				var nick = msg.params[1];
				if (nick === target) {
					return this.whoisDB.get(nick);
				};
				break;
			case irc.ERR_NOSUCHNICK:
				var nick = msg.params[1];
				if (nick === target) {
					return null;
				};
				break;
			}
		});
	}

	addAvailableCaps(s) {
		var l = s.split(" ");
		l.forEach((s) => {
@@ -392,6 +426,7 @@ export default class Client extends EventTarget {

	setCaseMapping(name) {
		this.cm = irc.CaseMapping.byName(name);
		this.whoisDB = new irc.CaseMapMap(this.whoisDB, this.cm);
		if (!this.cm) {
			console.error("Unsupported case-mapping '" + name + "', falling back to RFC 1459");
			this.cm = irc.CaseMapping.RFC1459;
diff --git a/lib/irc.js b/lib/irc.js
index 5093e93..fd4650a 100644
--- a/lib/irc.js
+++ b/lib/irc.js
@@ -4,6 +4,12 @@ export const RPL_YOURHOST = "002";
export const RPL_CREATED = "003";
export const RPL_MYINFO = "004";
export const RPL_ISUPPORT = "005";
export const RPL_WHOISUSER = "311";
export const RPL_WHOISSERVER = "312";
export const RPL_WHOISOPERATOR = "313";
export const RPL_WHOISIDLE = "317";
export const RPL_ENDOFWHOIS = "318";
export const RPL_WHOISCHANNELS = "319";
export const RPL_ENDOFWHO = "315";
export const RPL_NOTOPIC = "331";
export const RPL_TOPIC = "332";
@@ -12,6 +18,7 @@ export const RPL_WHOREPLY = "352";
export const RPL_NAMREPLY = "353";
export const RPL_ENDOFNAMES = "366";
export const RPL_ENDOFMOTD = "376";
export const ERR_NOSUCHNICK = "401";
export const ERR_NOMOTD = "422";
export const ERR_ERRONEUSNICKNAME = "432";
export const ERR_NICKNAMEINUSE = "433";
-- 
2.31.1
Pushed with some edits. Thanks!

On Thursday, May 27th, 2021 at 10:02 PM, Drew DeVault <sir@cmpwn.com> wrote:

[PATCH gamja v3 2/2] Add /ban, /kickban commands Export this patch

---
 commands.js | 70 +++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 57 insertions(+), 13 deletions(-)

diff --git a/commands.js b/commands.js
index b4ba9f8..a0e65cc 100644
--- a/commands.js
+++ b/commands.js
@@ -9,6 +9,39 @@ function getActiveClient(app) {
	return app.clients.get(buf.network);
}

const ban = {
	usage: "<target>",
	description: "Bans a user from the channel",
	execute: (app, args) => {
		var user = args[0];
		if (!user) {
			throw new Error("Missing target");
		}
		var activeBuffer = app.state.buffers.get(app.state.activeBuffer);
		if (!activeBuffer || !app.isChannel(activeBuffer.name)) {
			throw new Error("Not in a channel");
		}
		var params = [activeBuffer.name, user];
		if (args.length > 1) {
			params.push(args.slice(1).join(" "));
		}
		const client = getActiveClient(app);
		client.whois(user).then(whois => {
			if (whois === null) {
				throw new Error("No such user");
			};
			const info = whois[irc.RPL_WHOISUSER].params;
			const user = info[2];
			const host = info[3];
			client.send({ command: "MODE", params: [
				activeBuffer.name,
				"+b",
				`*!${user}@${host}`
			]});
		});
	},
};

const join = {
	usage: "<name>",
	description: "Join a channel",
@@ -21,7 +54,25 @@ const join = {
	},
};

const kick = {
	usage: "<user>",
	description: "Remove a user from the channel",
	execute: (app, args) => {
		var user = args[0];
		var activeBuffer = app.state.buffers.get(app.state.activeBuffer);
		if (!activeBuffer || !app.isChannel(activeBuffer.name)) {
			throw new Error("Not in a channel");
		}
		var params = [activeBuffer.name, user];
		if (args.length > 1) {
			params.push(args.slice(1).join(" "));
		}
		getActiveClient(app).send({ command: "KICK", params });
	},
};

export default {
	"ban": ban,
	"buffer": {
		usage: "<name>",
		description: "Switch to a buffer",
@@ -77,20 +128,13 @@ export default {
	},
	"j": join,
	"join": join,
	"kick": {
		usage: "<user>",
		description: "Remove a user from the channel",
	"kick": kick,
	"kickban": {
		usage: "<target>",
		description: "Bans a user and removes them from the channel",
		execute: (app, args) => {
			var user = args[0];
			var activeBuffer = app.state.buffers.get(app.state.activeBuffer);
			if (!activeBuffer || !app.isChannel(activeBuffer.name)) {
				throw new Error("Not in a channel");
			}
			var params = [activeBuffer.name, user];
			if (args.length > 1) {
				params.push(args.slice(1).join(" "));
			}
			getActiveClient(app).send({ command: "KICK", params });
			kick.execute(app, args);
			ban.execute(app, args);
		},
	},
	"me": {
-- 
2.31.1
Pushed, thanks!