Add support for WHOX
This allows querying the account of the user.
This commit is contained in:
parent
0b32d9295a
commit
329f9063d0
4 changed files with 105 additions and 17 deletions
|
@ -30,7 +30,21 @@ const NORMAL_CLOSURE = 1000;
|
|||
const GOING_AWAY = 1001;
|
||||
const UNSUPPORTED_DATA = 1003;
|
||||
|
||||
// See https://github.com/quakenet/snircd/blob/master/doc/readme.who
|
||||
// Sorted by order of appearance in RPL_WHOSPCRPL
|
||||
const WHOX_FIELDS = {
|
||||
"channel": "c",
|
||||
"username": "u",
|
||||
"hostname": "h",
|
||||
"server": "s",
|
||||
"nick": "n",
|
||||
"flags": "f",
|
||||
"account": "a",
|
||||
"realname": "r",
|
||||
};
|
||||
|
||||
let lastLabel = 0;
|
||||
let lastWhoxToken = 0;
|
||||
|
||||
export default class Client extends EventTarget {
|
||||
static Status = {
|
||||
|
@ -65,6 +79,7 @@ export default class Client extends EventTarget {
|
|||
cm = irc.CaseMapping.RFC1459;
|
||||
monitored = new irc.CaseMapMap(null, irc.CaseMapping.RFC1459);
|
||||
whoisDB = new irc.CaseMapMap(null, irc.CaseMapping.RFC1459);
|
||||
whoxQueries = new Map();
|
||||
|
||||
constructor(params) {
|
||||
super();
|
||||
|
@ -332,14 +347,43 @@ export default class Client extends EventTarget {
|
|||
}
|
||||
}
|
||||
|
||||
who(mask) {
|
||||
let msg = { command: "WHO", params: [mask] };
|
||||
who(mask, options) {
|
||||
let params = [mask];
|
||||
|
||||
let fields = "", token = "";
|
||||
if (options && this.isupport.has("WHOX")) {
|
||||
let match = ""; // Matches exact channel or nick
|
||||
|
||||
fields = "t"; // Always include token in reply
|
||||
if (options.fields) {
|
||||
options.fields.forEach((k) => {
|
||||
if (!WHOX_FIELDS[k]) {
|
||||
throw new Error(`Unknown WHOX field ${k}`);
|
||||
}
|
||||
fields += WHOX_FIELDS[k];
|
||||
});
|
||||
}
|
||||
|
||||
token = String(lastWhoxToken % 1000);
|
||||
lastWhoxToken++;
|
||||
|
||||
params.push(`${match}%${fields},${token}`);
|
||||
this.whoxQueries.set(token, fields);
|
||||
}
|
||||
|
||||
let msg = { command: "WHO", params };
|
||||
let l = [];
|
||||
return this.roundtrip(msg, (msg) => {
|
||||
switch (msg.command) {
|
||||
case irc.RPL_WHOREPLY:
|
||||
// TODO: match with mask
|
||||
l.push(msg);
|
||||
l.push(this.parseWhoReply(msg));
|
||||
break;
|
||||
case irc.RPL_WHOSPCRPL:
|
||||
if (msg.params.length !== fields.length || msg.params[1] !== token) {
|
||||
break;
|
||||
}
|
||||
l.push(this.parseWhoReply(msg));
|
||||
break;
|
||||
case irc.RPL_ENDOFWHO:
|
||||
if (msg.params[1] === mask) {
|
||||
|
@ -347,9 +391,45 @@ export default class Client extends EventTarget {
|
|||
}
|
||||
break;
|
||||
}
|
||||
}).finally(() => {
|
||||
this.whoxQueries.delete(token);
|
||||
});
|
||||
}
|
||||
|
||||
parseWhoReply(msg) {
|
||||
switch (msg.command) {
|
||||
case irc.RPL_WHOREPLY:
|
||||
let last = msg.params[msg.params.length - 1];
|
||||
return {
|
||||
username: msg.params[2],
|
||||
hostname: msg.params[3],
|
||||
server: msg.params[4],
|
||||
nick: msg.params[5],
|
||||
flags: msg.params[6],
|
||||
realname: last.slice(last.indexOf(" ") + 1),
|
||||
};
|
||||
case irc.RPL_WHOSPCRPL:
|
||||
let token = msg.params[1];
|
||||
let fields = this.whoxQueries.get(token);
|
||||
if (!fields) {
|
||||
throw new Error("Unknown WHOX token: " + token);
|
||||
}
|
||||
let who = {};
|
||||
let i = 0;
|
||||
Object.keys(WHOX_FIELDS).forEach((k) => {
|
||||
if (fields.indexOf(WHOX_FIELDS[k]) < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
who[k] = msg.params[2 + i];
|
||||
i++;
|
||||
});
|
||||
return who;
|
||||
default:
|
||||
throw new Error("Not a WHO reply: " + msg.command);
|
||||
}
|
||||
}
|
||||
|
||||
whois(target) {
|
||||
let targetCM = this.cm(target);
|
||||
let msg = { command: "WHOIS", params: [target] };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue