diff --git a/js/lib/irc.js b/js/lib/irc.js --- a/js/lib/irc.js +++ b/js/lib/irc.js @@ -490,17 +490,17 @@ function CIRCServer (parent, hostname, p s.lag = -1; s.usersStable = true; s.supports = null; s.channelTypes = null; s.channelModes = null; s.channelCount = -1; s.userModes = null; s.maxLineLength = 400; - s.capab = new Object(); + s.caps = new Object(); parent.servers[s.canonicalName] = s; if ("onInit" in s) s.onInit(); return s; } CIRCServer.prototype.MAX_LINES_PER_SEND = 0; /* unlimited */ @@ -1621,38 +1621,16 @@ function serv_251(e) CIRCServer.prototype.on254 = function serv_254(e) { this.channelCount = e.params[2]; e.destObject = this.parent; e.set = "network"; } -/* CAPAB response */ -CIRCServer.prototype.on290 = -function my_290 (e) -{ - // we expect some sort of identifier - if (e.params.length < 2) - return; - - switch (e.params[2]) - { - case "IDENTIFY-MSG": - /* Every message comes prefixed with either + or - - + indicates the user is registered - - indicates the user is not registered */ - this.capab.identifyMsg = true; - break; - - } - e.destObject = this.parent; - e.set = "network"; -} - /* user away message */ CIRCServer.prototype.on301 = function serv_301(e) { e.user = new CIRCUser(this, null, e.params[2]); e.user.awayMessage = e.decodeParam(3, e.user); e.destObject = this.parent; e.set = "network"; @@ -1830,30 +1808,33 @@ function serv_353 (e) for (var n in nicks) { var nick = nicks[n]; if (nick == "") break; var modes = new Array(); + var multiPrefix = (("namesx" in this.supports) && this.supports.namesx) + || (("multi-prefix" in this.caps) + && this.caps["multi-prefix"]); do { var found = false; for (var m in mList) { if (nick[0] == mList[m].symbol) { nick = nick.substr(1); modes.push(mList[m].mode); found = true; break; } } - } while (found && ("namesx" in this.supports) && this.supports.namesx); + } while (found && multiPrefix); new CIRCChanUser(e.channel, null, nick, modes, true); } return true; } /* end of names */ @@ -2001,16 +1982,61 @@ function serv_302(e) } e.destObject = this.parent; e.set = "network"; return true; } +/* CAP response */ +CIRCServer.prototype.onCap = +function my_cap (e) +{ + // We expect some sort of identifier. + if (e.params.length < 2) + return; + + if (e.params[2] == "LS") + { + /* We're getting a list of all server capabilities. Set them all to + * null (if they don't exist) to indicate we don't know if they're + * enabled or not (but this will evaluate to false which matches that + * capabilities are only enabled on request). + */ + for (var i = 3; i < e.params.length; i++) + { + var cap = e.params[i].replace(/^-/, "").trim(); + if (!(cap in this.caps)) + this.caps[cap] = null; + } + } + else if (e.params[2] == "ACK") + { + /* A capability change has been successfully applied. An enabled + * capability is just "cap" whilst a disabled capability is "-cap". + */ + e.cap = e.params[3].replace(/^-/, "").trim(); + e.capEnabled = e.params[3][0] != "-"; + this.caps[e.cap] = e.capEnabled; + } + else if (e.params[2] == "NAK") + { + // A capability change has failed. + e.cap = e.params[3].replace(/^-/, "").trim(); + } + else + { + dd("Unknown CAP reply " + e.params[2]); + } + + e.destObject = this.parent; + e.set = "network"; +} + /* user changed the mode */ CIRCServer.prototype.onMode = function serv_mode (e) { e.destObject = this; /* modes are not allowed in +channels -> no need to test that here.. */ if (arrayIndexOf(this.channelTypes, e.params[1][0]) != -1) { @@ -2424,18 +2450,20 @@ function serv_notice_privmsg (e) return true; } else { e.set = "user"; e.replyTo = e.user; /* send replies to the user who sent the message */ } - // The CAPAB IDENTIFY-MSG stuff for freenode - if (this.capab.identifyMsg) + /* The capability identify-msg adds a + or - in front the message to + * indicate their network registration status. + */ + if (this.caps["identify-msg"]) { e.identifyMsg = false; var flag = e.params[2].substring(0,1); if (flag == "+") { e.identifyMsg = true; e.params[2] = e.params[2].substring(1); } diff --git a/locales/en-US/chrome/chatzilla.properties b/locales/en-US/chrome/chatzilla.properties --- a/locales/en-US/chrome/chatzilla.properties +++ b/locales/en-US/chrome/chatzilla.properties @@ -1307,16 +1307,24 @@ msg.supports.chanModesB = Supported chan msg.supports.chanModesC = Supported channel modes (C: on-param): %S" msg.supports.chanModesD = Supported channel modes (D: boolean): %S" msg.supports.userMode = "%S (%S) msg.supports.userModes = Supported channel user modes: %S" msg.supports.flagsOn = This server DOES support: %S" msg.supports.flagsOff = This server DOESN'T support: %S" msg.supports.miscOption = "%S=%S" msg.supports.miscOptions = Server settings/limits: %S" +msg.supports.caps = Supported capabilities: %S" +msg.supports.capsOn = Enabled capabilities: %S" + + +msg.caps.list = Available capabilities: %S" +msg.caps.on = Capability %S enabled. +msg.caps.off = Capability %S disabled. +msg.caps.error = Capability %S is invalid. msg.conf.mode.on = Conference Mode has been enabled for this view; joins, leaves, quits and nickname changes will be hidden. msg.conf.mode.stayon = Conference Mode is enabled for this view; joins, leaves, quits and nickname changes are hidden. msg.conf.mode.off = Conference Mode has been disabled for this view; joins, leaves, quits and nickname changes will be shown. # Join Network/Channel dialog msg.cd.updated = Network's channel list cached on %S" diff --git a/xul/content/commands.js b/xul/content/commands.js --- a/xul/content/commands.js +++ b/xul/content/commands.js @@ -3775,16 +3775,32 @@ function cmdSupports(e) } } listB1.sort(); listB2.sort(); listN.sort(); display(getMsg(MSG_SUPPORTS_FLAGSON, listB1.join(MSG_COMMASP))); display(getMsg(MSG_SUPPORTS_FLAGSOFF, listB2.join(MSG_COMMASP))); display(getMsg(MSG_SUPPORTS_MISCOPTIONS, listN.join(MSG_COMMASP))); + + var listCaps = new Array(); + var listCapsEnabled = new Array(); + for (var cap in server.caps) + { + listCaps.push(cap); + if (server.caps[cap]) + listCapsEnabled.push(cap); + } + if (listCaps.length > 0) + { + listCaps.sort(); + listCapsEnabled.sort(); + display(getMsg(MSG_SUPPORTS_CAPS, listCaps.join(MSG_COMMASP))); + display(getMsg(MSG_SUPPORTS_CAPSON, listCapsEnabled.join(MSG_COMMASP))); + } } function cmdDoCommand(e) { if (e.cmdName == "cmd_mozillaPrefs") { // open Mozilla/SeaMonkey preferences const PREF_URL = 'chrome://chatzilla/content/pref-irc.xul'; diff --git a/xul/content/handlers.js b/xul/content/handlers.js --- a/xul/content/handlers.js +++ b/xul/content/handlers.js @@ -1120,17 +1120,16 @@ CIRCNetwork.prototype.on004 = /* server CIRCNetwork.prototype.on005 = /* server features */ CIRCNetwork.prototype.on250 = /* highest connection count */ CIRCNetwork.prototype.on251 = /* users */ CIRCNetwork.prototype.on252 = /* opers online (in params[2]) */ CIRCNetwork.prototype.on254 = /* channels found (in params[2]) */ CIRCNetwork.prototype.on255 = /* link info */ CIRCNetwork.prototype.on265 = /* local user details */ CIRCNetwork.prototype.on266 = /* global user details */ -CIRCNetwork.prototype.on290 = /* CAPAB Response */ CIRCNetwork.prototype.on375 = /* start of MOTD */ CIRCNetwork.prototype.on372 = /* MOTD line */ CIRCNetwork.prototype.on376 = /* end of MOTD */ CIRCNetwork.prototype.on422 = /* no MOTD */ function my_showtonet (e) { var p = (3 in e.params) ? e.params[2] + " " : ""; var str = ""; @@ -2341,16 +2340,38 @@ function my_netwallops(e) /* unknown command reply */ CIRCNetwork.prototype.on421 = function my_421(e) { this.display(getMsg(MSG_IRC_421, e.decodeParam(2)), MT_ERROR); return true; } +/* cap reply */ +CIRCNetwork.prototype.onCap = +function my_cap(e) +{ + if (e.params[2] == "LS") + { + display(getMsg(MSG_CAPS_LIST, keys(e.server.caps).join(MSG_COMMASP))); + } + else if (e.params[2] == "ACK") + { + if (e.capEnabled) + display(getMsg(MSG_CAPS_ON, e.cap)); + else + display(getMsg(MSG_CAPS_OFF, e.cap)); + } + else if (e.params[2] == "NAK") + { + display(getMsg(MSG_CAPS_ERROR, e.cap)); + } + return true; +} + CIRCNetwork.prototype.reclaimName = function my_reclaimname() { var network = this; function callback() { network.reclaimName(); };