diff --git a/chat/locales/en-US/conversations.properties b/chat/locales/en-US/conversations.properties index 19b5acabe7..1a5564a6ec 100644 --- a/chat/locales/en-US/conversations.properties +++ b/chat/locales/en-US/conversations.properties @@ -56,6 +56,17 @@ topicChanged=%1$S has changed the topic to: %2$S. # %1$S is the user who cleared the topic. topicCleared=%1$S has cleared the topic. +# LOCALIZATION NOTE (nickSet): +# This is displayed as a system message when a participant changes his/her +# nickname in a conversation. +# %1$S is the old nick. +# %2$S is the new nick. +nickSet=%1$S is now known as %2$S. +# LOCALIZATION NOTE (nickSet.you): +# This is displayed as a system message when your nickname is changed. +# %S is your new nick. +nickSet.you=You are now known as %S. + # LOCALIZATION NOTE (messenger.conversations.selections.ellipsis): # ellipsis is used when copying a part of a message to show that the message was cut messenger.conversations.selections.ellipsis=[…] diff --git a/chat/locales/en-US/irc.properties b/chat/locales/en-US/irc.properties index 544ca7d27e..b705d125e7 100644 --- a/chat/locales/en-US/irc.properties +++ b/chat/locales/en-US/irc.properties @@ -96,10 +96,6 @@ message.usermode=Mode %1$S for %2$S set by %3$S. message.channelmode=Channel mode %1$S set by %2$S. # %S is the user's mode. message.yourmode=Your mode is %S. -# %1$S is the old nick and %2$S is the new nick. -message.nick=%1$S is now known as %2$S. -# %S is your new nick. -message.nick.you=You are now known as %S. # Could not change the nickname. %S is the user's nick. message.nick.fail=Could not use the desired nickname. Your nick remains %S. # The parameter is the message.parted.reason, if a part message is given. diff --git a/chat/modules/jsProtoHelper.jsm b/chat/modules/jsProtoHelper.jsm index 7d21d4c7fb..06bc2a14f2 100644 --- a/chat/modules/jsProtoHelper.jsm +++ b/chat/modules/jsProtoHelper.jsm @@ -626,6 +626,66 @@ const GenericConvChatPrototype = { }, getNormalizedChatBuddyName: aChatBuddyName => aChatBuddyName, + // Updates the nick of a participant in conversation to a new one. + updateNick: function(aOldNick, aNewNick, isOwnNick) { + let message; + let isParticipant = this._participants.has(aOldNick); + if (isOwnNick) { + // If this is the user's nick, change it. + this.nick = aNewNick; + message = _("nickSet.you", aNewNick); + + // If the account was disconnected, it's OK the user is not a participant. + if (!isParticipant) + return; + } + else if (!isParticipant) { + this.ERROR("Trying to rename nick that doesn't exist! " + aOldNick + + " to " + aNewNick); + return; + } + else + message = _("nickSet", aOldNick, aNewNick); + + // Get the original participant and then remove it. + let participant = this._participants.get(aOldNick); + this._participants.delete(aOldNick); + + // Update the nickname and add it under the new nick. + participant.name = aNewNick; + this._participants.set(aNewNick, participant); + + this.notifyObservers(participant, "chat-buddy-update", aOldNick); + this.writeMessage(aOldNick, message, {system: true}); + }, + + // Removes a participant from conversation. + removeParticipant: function(aNick) { + if (!this._participants.has(aNick)) + return; + + let stringNickname = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + stringNickname.data = aNick; + this.notifyObservers(new nsSimpleEnumerator([stringNickname]), + "chat-buddy-remove"); + this._participants.delete(aNick); + }, + + // Removes all participant in conversation. + removeAllParticipants: function() { + let stringNicknames = []; + this._participants.forEach(function(aParticipant) { + let stringNickname = Cc["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + stringNickname.data = aParticipant.name; + stringNicknames.push(stringNickname); + }); + this.notifyObservers(new nsSimpleEnumerator(stringNicknames), + "chat-buddy-remove"); + this._participants.clear(); + }, + writeMessage: function (aWho, aText, aProperties) { aProperties.containsNick = "incoming" in aProperties && this._pingRegexp.test(aText); @@ -637,7 +697,8 @@ const GenericConvChatBuddyPrototype = { __proto__: ClassInfo("prplIConvChatBuddy", "generic ConvChatBuddy object"), _name: "", - get name() { return this._name; }, + get name() this._name, + set name(aName) this._name = aName, alias: "", buddy: false, diff --git a/chat/protocols/irc/irc.js b/chat/protocols/irc/irc.js index c9b8945db4..eccad8e6c2 100644 --- a/chat/protocols/irc/irc.js +++ b/chat/protocols/irc/irc.js @@ -375,56 +375,6 @@ ircChannel.prototype = { } return participant; }, - updateNick: function(aOldNick, aNewNick) { - let isParticipant = this._participants.has(aOldNick); - if (this.normalizeNick(aOldNick) == this.normalizeNick(this.nick)) { - // If this is the user's nick, change it. - this.nick = aNewNick; - // If the account was disconnected, it's OK the user is not a participant. - if (!isParticipant) - return; - } - else if (!isParticipant) { - this.ERROR("Trying to rename nick that doesn't exist! " + aOldNick + - " to " + aNewNick); - return; - } - - // Get the original ircParticipant and then remove it. - let participant = this.getParticipant(aOldNick); - this._participants.delete(aOldNick); - - // Update the nickname and add it under the new nick. - participant._name = aNewNick; - this._participants.set(aNewNick, participant); - - this.notifyObservers(participant, "chat-buddy-update", aOldNick); - }, - removeParticipant: function(aNick) { - if (!this._participants.has(aNick)) - return; - - let stringNickname = Cc["@mozilla.org/supports-string;1"] - .createInstance(Ci.nsISupportsString); - stringNickname.data = aNick; - this.notifyObservers(new nsSimpleEnumerator([stringNickname]), - "chat-buddy-remove"); - this._participants.delete(aNick); - }, - // Use this before joining to avoid errors of trying to re-add an existing - // participant - removeAllParticipants: function() { - let stringNicknames = []; - this._participants.forEach(function(aParticipant) { - let stringNickname = Cc["@mozilla.org/supports-string;1"] - .createInstance(Ci.nsISupportsString); - stringNickname.data = aParticipant.name; - stringNicknames.push(stringNickname); - }); - this.notifyObservers(new nsSimpleEnumerator(stringNicknames), - "chat-buddy-remove"); - this._participants.clear(); - }, /* * Add/remove modes from this channel. @@ -1285,25 +1235,24 @@ ircAccount.prototype = { return buddy; }, changeBuddyNick: function(aOldNick, aNewNick) { - let msg; if (this.normalizeNick(aOldNick) == this.normalizeNick(this._nickname)) { // Your nickname changed! this._nickname = aNewNick; - msg = _("message.nick.you", aNewNick); this.conversations.forEach(conversation => { // Update the nick for chats, and inform the user in every conversation. if (conversation.isChat) - conversation.updateNick(aOldNick, aNewNick); - conversation.writeMessage(aOldNick, msg, {system: true}); + conversation.updateNick(aOldNick, aNewNick, true); + else { + conversation.writeMessage(aOldNick, _conv("nickSet.you", aNewNick), + {system: true}); + } }); } else { - msg = _("message.nick", aOldNick, aNewNick); this.conversations.forEach(conversation => { if (conversation.isChat && conversation._participants.has(aOldNick)) { // Update the nick in every chat conversation it is in. - conversation.updateNick(aOldNick, aNewNick); - conversation.writeMessage(aOldNick, msg, {system: true}); + conversation.updateNick(aOldNick, aNewNick, false); } }); } diff --git a/chat/protocols/irc/ircUtils.jsm b/chat/protocols/irc/ircUtils.jsm index 7cb8acf216..edf8729c1b 100644 --- a/chat/protocols/irc/ircUtils.jsm +++ b/chat/protocols/irc/ircUtils.jsm @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -const EXPORTED_SYMBOLS = ["_", "ctcpFormatToText", "ctcpFormatToHTML", +const EXPORTED_SYMBOLS = ["_", "_conv", "ctcpFormatToText", "ctcpFormatToHTML", "conversationErrorMessage", "kListRefreshInterval"]; const {classes: Cc, interfaces: Ci} = Components; @@ -13,6 +13,10 @@ XPCOMUtils.defineLazyGetter(this, "_", () => l10nHelper("chrome://chat/locale/irc.properties") ); +XPCOMUtils.defineLazyGetter(this, "_conv", () => + l10nHelper("chrome://chat/locale/conversations.properties") +); + XPCOMUtils.defineLazyGetter(this, "TXTToHTML", function() { let cs = Cc["@mozilla.org/txttohtmlconv;1"].getService(Ci.mozITXTToHTMLConv); return aTXT => cs.scanTXT(aTXT, cs.kEntities); diff --git a/chat/protocols/xmpp/xmpp.jsm b/chat/protocols/xmpp/xmpp.jsm index 883a35d073..4df4863ebe 100644 --- a/chat/protocols/xmpp/xmpp.jsm +++ b/chat/protocols/xmpp/xmpp.jsm @@ -249,6 +249,17 @@ const XMPPMUCConversationPrototype = { let codes = x.getElements(["status"]).map(elt => elt.attributes["code"]); let item = x.getElement(["item"]); + // Changes the nickname of a participant for this muc. + let changeNick = () => { + if (!item || !item.attributes["nick"]) { + this.WARN("Received a MUC presence code 303 or 210 stanza without an " + + "item element or a nick attribute."); + return; + } + let newNick = item.attributes["nick"]; + this.updateNick(nick, newNick, nick == this.nick); + }; + if (aStanza.attributes["type"] == "unavailable") { if (!this._participants.has(nick)) { this.WARN("received unavailable presence for an unknown MUC participant: " + @@ -258,13 +269,7 @@ const XMPPMUCConversationPrototype = { if (codes.indexOf("303") != -1) { // XEP-0045 (7.6): Changing Nickname. // Service Updates Nick for user. - if (!item || !item.attributes["nick"]) { - this.WARN("Received a MUC presence code 303 stanza without an item " + - "element or a nick attribute."); - return; - } - let participant = this._participants.get(nick); - participant.name = item.attributes["nick"]; + changeNick(); return; } if (item && item.attributes["role"] == "none") { @@ -350,6 +355,13 @@ const XMPPMUCConversationPrototype = { return true; }); } + else if (codes.indexOf("210") != -1) { + // XEP-0045 (7.6): Changing Nickname. + // Service modifies this user's nickname in accordance with local service + // policies. + changeNick(); + return; + } else if (codes.indexOf("110") != -1) { // XEP-0045: Room exists and joined successfully. this.left = false; @@ -414,33 +426,6 @@ const XMPPMUCConversationPrototype = { return this._account.normalizeFullJid(this.name + "/" + aNick); }, - // Removes a participant from MUC conversation. - removeParticipant: function(aNick) { - if (!this._participants.has(aNick)) - return; - - this._participants.delete(aNick); - let nickString = Cc["@mozilla.org/supports-string;1"] - .createInstance(Ci.nsISupportsString); - nickString.data = aNick; - this.notifyObservers(new nsSimpleEnumerator([nickString]), - "chat-buddy-remove"); - }, - - // Removes all participant in MUC conversation. - removeAllParticipants: function() { - let stringNicknames = []; - this._participants.forEach(function(aParticipant) { - let stringNickname = Cc["@mozilla.org/supports-string;1"] - .createInstance(Ci.nsISupportsString); - stringNickname.data = aParticipant.name; - stringNicknames.push(stringNickname); - }); - this.notifyObservers(new nsSimpleEnumerator(stringNicknames), - "chat-buddy-remove"); - this._participants.clear(); - }, - // Leaves MUC conversation. part: function(aMsg = null) { let s = Stanza.presence({to: this.name + "/" + this._nick, type: "unavailable"}, diff --git a/chat/protocols/yahoo/yahoo.js b/chat/protocols/yahoo/yahoo.js index bde8a3c37d..a15be5ced7 100644 --- a/chat/protocols/yahoo/yahoo.js +++ b/chat/protocols/yahoo/yahoo.js @@ -121,23 +121,6 @@ YahooConference.prototype = { {system: true}); }, - removeParticipant: function(aName) { - // In case we receive two logoff packets, make sure that the user is - // actually here before continuing. - if (!this._participants.has(aName)) - return; - - let stringNickname = Cc["@mozilla.org/supports-string;1"] - .createInstance(Ci.nsISupportsString); - stringNickname.data = aName; - this.notifyObservers(new nsSimpleEnumerator([stringNickname]), - "chat-buddy-remove"); - this._participants.delete(aName); - this.writeMessage(this._roomName, - _("system.message.conferenceLogoff", aName), - {system: true}); - }, - getParticipantNames: function() { return [for (p of this._participants.values()) p.name]; } }; @@ -304,6 +287,9 @@ YahooAccount.prototype = { return; let conf = this._conferences.get(aRoom); conf.removeParticipant(aUsername); + conf.writeMessage(this._roomName, + _("system.message.conferenceLogoff", aName), + {system: true}); }, deleteConference: function(aName) {