From 35e87c46eaafc99fe14b271651d3a7970d96c30d Mon Sep 17 00:00:00 2001 From: Reto Date: Thu, 29 Aug 2024 16:59:45 +0200 Subject: [PATCH] whowas: return all responses from the server (#372) whowas: return all responses from the server --------- Co-authored-by: ItsOnlyBinary --- docs/events.md | 13 +++++++++- src/commands/handlers/user.js | 49 +++++++++++++++++++++++++---------- 2 files changed, 48 insertions(+), 14 deletions(-) diff --git a/docs/events.md b/docs/events.md index ceebd271..caec0b75 100644 --- a/docs/events.md +++ b/docs/events.md @@ -596,7 +596,13 @@ Not all of these options will be available. Some will be missing depending on th **whowas** -If the requested user was not found, error will contain 'no_such_nick'. +The response root includes the latest data from `whowas[0]` to maintain backwards compatibility. +The `whowas` array contains all RPL_WHOWASUSER responses with the newest being first. + +If the requested user was not found, `error` will contain 'no_such_nick'. + +> Note: The available data can vary depending on the network. + ~~~javascript { nick: 'prawnsalad', @@ -604,11 +610,16 @@ If the requested user was not found, error will contain 'no_such_nick'. hostname: 'manchester.isp.net', actual_ip: 'sometimes set when using webirc, could be the same as actual_hostname', actual_hostname: 'sometimes set when using webirc', + actual_username: 'prawn', real_name: 'A real prawn', server: 'irc.server.net', server_info: 'Thu Jun 14 09:15:51 2018', account: 'logged on account', error: '' + whowas: [ + { ... }, + { ... }, + ] } ~~~ diff --git a/src/commands/handlers/user.js b/src/commands/handlers/user.js index 43ea205b..575a168e 100644 --- a/src/commands/handlers/user.js +++ b/src/commands/handlers/user.js @@ -328,12 +328,29 @@ const handlers = { RPL_WHOWASUSER: function(command, handler) { const cache_key = command.params[1].toLowerCase(); - const cache = handler.cache('whois.' + cache_key); + let whois_cache = handler.cache('whois.' + cache_key); + + // multiple RPL_WHOWASUSER replies are received prior to the RPL_ENDOFWHOWAS command + // one for each timestamp the server is aware of, from newest to oldest. + // They are optionally interleaved with various other numerics such as RPL_WHOISACTUALLY etc. + // Hence if we already find something we are receiving older data and need to make sure that we + // store anything already in the cache into its own entry + const whowas_cache = handler.cache('whowas.' + cache_key); + if (!whowas_cache.whowas) { + // this will get populated by the next RPL_WHOWASUSER or RPL_ENDOFWHOWAS + whowas_cache.whowas = []; + } else { + // push the previous event prior to modifying anything + whowas_cache.whowas.push(whois_cache); + // ensure we are starting with a clean cache for the next data + whois_cache.destroy(); + whois_cache = handler.cache('whois.' + cache_key); + } - cache.nick = command.params[1]; - cache.ident = command.params[2]; - cache.hostname = command.params[3]; - cache.real_name = command.params[command.params.length - 1]; + whois_cache.nick = command.params[1]; + whois_cache.ident = command.params[2]; + whois_cache.hostname = command.params[3]; + whois_cache.real_name = command.params[command.params.length - 1]; }, RPL_ENDOFWHOWAS: function(command, handler) { @@ -347,16 +364,22 @@ const handlers = { // server_info, actual_username // More optional fields MAY exist, depending on the type of ircd. const cache_key = command.params[1].toLowerCase(); - const cache = handler.cache('whois.' + cache_key); - - // Should, in theory, never happen. - if (!cache.nick) { - cache.nick = command.params[1]; - cache.error = 'no_such_nick'; + const whois_cache = handler.cache('whois.' + cache_key); + const whowas_cache = handler.cache('whowas.' + cache_key); + + // after all prior RPL_WHOWASUSER pushed newer events onto the history stack + // push the last one to complete the set (server returns from newest to oldest) + whowas_cache.whowas = whowas_cache.whowas || []; + if (!whois_cache.error) { + whowas_cache.whowas.push(whois_cache); + Object.assign(whowas_cache, whowas_cache.whowas[0]); + } else { + Object.assign(whowas_cache, whois_cache); } - handler.emit('whowas', cache); - cache.destroy(); + handler.emit('whowas', whowas_cache); + whois_cache.destroy(); + whowas_cache.destroy(); }, ERR_WASNOSUCHNICK: function(command, handler) {