From 121d7ec075372ad2d25dcf675ad4ad9c03154f2d Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Thu, 27 May 2021 16:02:07 -0400 Subject: [PATCH] Add /whois command 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 | 36 ++++++++++++++++++++++++++++++++++++ lib/irc.js | 7 +++++++ 3 files changed, 54 insertions(+) diff --git a/commands.js b/commands.js index 3dd2645..ac92894 100644 --- a/commands.js +++ b/commands.js @@ -258,4 +258,15 @@ export default { getActiveClient(app).send({ command: "TOPIC", params }); }, }, + "whois": { + usage: "", + description: "Retrieve information about a user", + execute: (app, args) => { + var nick = args[0]; + if (!nick) { + throw new Error("Missing nick"); + } + getActiveClient(app).whois(nick); + }, + }, }; diff --git a/lib/client.js b/lib/client.js index 8dea847..0c82893 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,28 @@ export default class Client extends EventTarget { } } + whois(target, callback) { + var targetCM = this.cm(target); + 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 (this.cm(nick) === targetCM) { + return this.whoisDB.get(nick); + } + break; + case irc.ERR_NOSUCHNICK: + var nick = msg.params[1]; + if (this.cm(nick) === targetCM) { + throw msg; + } + break; + } + }); + } + addAvailableCaps(s) { var l = s.split(" "); l.forEach((s) => { @@ -392,6 +427,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";