Bug 753807 - Land in comm-central Instantbird's changes to chat/ - Bio 1332 - Implement /whois and /whowas commands, r=clokep,fqueze.

This commit is contained in:
aleth 2012-04-03 22:52:18 +02:00
Родитель caea2ebce7
Коммит f5dbde7463
4 изменённых файлов: 160 добавлений и 20 удалений

Просмотреть файл

@ -66,6 +66,7 @@ command.umode=%S (+|-)<new mode>: Set or unset a user mode.
command.version=%S <nick>: Request the version of a user's client.
command.voice=%S <nick1>[,<nick2>]*: Grant channel voice status to someone. You must be a channel operator to do this.
command.wallops=%S <message>: If you don't know what this is, you probably can't use it (sends a command to all connected with the +w flag and all operators on the server.
command.whois=%S <nick>: Get information on a user.
command.whowas=%S <nick>: Get information on a user that has logged off.
# LOCALIZATION NOTE (message.*):
@ -110,9 +111,17 @@ message.topicRemoved=The topic for %S was removed.
message.invited=%1$S was successfully invited to %2$S.
# %S is the nickname of the user who was summoned.
message.summoned=%S was summoned.
# %S is the nickname of the user whose WHOIS information follows this message.
message.whois=WHOIS information for %S:
# %1$S is the nickname of the (offline) user whose WHOWAS information follows this message.
message.whowas=%1$S is offline. WHOWAS information for %1$S:
# %1$S is the entry description (from tooltip.*), %2$S is its value.
message.whoisEntry=\ua0\ua0\ua0\ua0%1$S: %2$S
# %S is the nickname that is not known to the server.
message.unknownNick=%S is an unknown nickname.
# LOCALIZATION NOTE (error.*):
# These are shown as error messages in the conversation.
# These are shown as error messages in the server tab.
# %S is the channel name.
error.noChannel=There is no channel: %S.
error.tooManyChannels=Cannot join %S; you've joined too many channels.
@ -121,6 +130,8 @@ error.nickCollision=Nick already in use, changing nick to %1$S [%2$S].
error.banned=You are banned from this server.
error.bannedSoon=You will soon be banned from this server.
error.mode.wrongUser=You cannot change modes for other users.
error.noSuchNick=There is no nickname or channel: %S
error.wasNoSuchNick=There was no nickname: %S
# LOCALIZATION NOTE (tooltip.*):
# These are the descriptions given in a tooltip with information received

Просмотреть файл

@ -106,9 +106,12 @@ function ircMessage(aData) {
function ircChannel(aAccount, aName, aNick) {
this._init(aAccount, aName, aNick);
this._observedNicks = [];
}
ircChannel.prototype = {
__proto__: GenericConvChatPrototype,
_observedNicks: [],
sendMsg: function(aMessage) {
this._account.sendMessage("PRIVMSG", [this.name, aMessage]);
@ -149,6 +152,8 @@ ircChannel.prototype = {
unInit: function() {
this._account.removeConversation(this.name);
GenericConvChatPrototype.unInit.call(this);
if (this._observedNicks.length)
Services.obs.removeObserver(this, "user-info-received");
},
getNormalizedChatBuddyName: function(aNick)
@ -222,6 +227,26 @@ ircChannel.prototype = {
get topicSettable() true,
get normalizedName() this._account.normalize(this.name),
waitForBuddyInfo: function(aNick) {
if (!this._observedNicks.length)
Services.obs.addObserver(this, "user-info-received", false);
this._observedNicks.push(this._account.normalize(aNick));
},
observe: function(aSubject, aTopic, aData) {
if (aTopic != "user-info-received")
return;
let nickIndex = this._observedNicks.indexOf(this._account.normalize(aData));
if (nickIndex == -1)
return;
this._observedNicks.splice(nickIndex, 1);
if (!this._observedNicks.length)
Services.obs.removeObserver(this, "user-info-received");
this._account.writeWhois(this, aData,
aSubject.QueryInterface(Ci.nsISimpleEnumerator));
}
};
function ircParticipant(aName, aAccount) {
@ -273,9 +298,12 @@ function ircConversation(aAccount, aName) {
this.buddy = aAccount.getBuddy(aName);
this._init(aAccount, aName);
this._observedNicks = [];
}
ircConversation.prototype = {
__proto__: GenericConvIMPrototype,
_observedNicks: [],
sendMsg: function(aMessage) {
this._account.sendMessage("PRIVMSG", [this.name, aMessage]);
@ -297,11 +325,33 @@ ircConversation.prototype = {
unInit: function() {
this._account.removeConversation(this.name);
GenericConvIMPrototype.unInit.call(this);
if (this._observedNicks.length)
Services.obs.removeObserver(this, "user-info-received");
},
updateNick: function(aNewNick) {
this._name = aNewNick;
this.notifyObservers(null, "update-conv-title");
},
waitForBuddyInfo: function(aNick) {
if (!this._observedNicks.length)
Services.obs.addObserver(this, "user-info-received", false);
this._observedNicks.push(this._account.normalize(aNick));
},
observe: function(aSubject, aTopic, aData) {
if (aTopic != "user-info-received")
return;
let nickIndex = this._observedNicks.indexOf(this._account.normalize(aData));
if (nickIndex == -1)
return;
this._observedNicks.splice(nickIndex, 1);
if (!this._observedNicks.length)
Services.obs.removeObserver(this, "user-info-received");
this._account.writeWhois(this, aData,
aSubject.QueryInterface(Ci.nsISimpleEnumerator));
}
};
@ -495,8 +545,15 @@ ircAccount.prototype = {
// Request WHOIS information on a buddy when the user requests more
// information.
requestBuddyInfo: function(aBuddyName) {
this.removeBuddyInfo(aBuddyName);
this.sendMessage("WHOIS", aBuddyName);
},
// Request WHOWAS information on a buddy when the user requests more
// information.
requestOfflineBuddyInfo: function(aBuddyName) {
this.removeBuddyInfo(aBuddyName);
this.sendMessage("WHOWAS", aBuddyName);
},
// Return an nsISimpleEnumerator of imITooltipInfo for a given nick.
getBuddyInfo: function(aNick) {
let nick = this.normalize(aNick);
@ -506,12 +563,46 @@ ircAccount.prototype = {
let whoisInformation = this.whoisInformation[nick];
let tooltipInfo = [];
for (let field in whoisInformation) {
let value = whoisInformation[field];
tooltipInfo.push(new TooltipInfo(_("tooltip." + field), value));
if (field != "nick" && field != "offline") {
let value = whoisInformation[field];
tooltipInfo.push(new TooltipInfo(_("tooltip." + field), value));
}
}
return new nsSimpleEnumerator(tooltipInfo);
},
// Remove a WHOIS entry.
removeBuddyInfo: function(aNick) {
let nick = this.normalize(aNick);
if (hasOwnProperty(this.whoisInformation, nick))
delete this.whoisInformation[nick];
},
// Write WHOIS information to a conversation.
writeWhois: function(aConv, aNick, aTooltipInfo) {
let nick = this.normalize(aNick);
// RFC 2812 errors 401 and 406 result in there being no entry for the nick.
if (!hasOwnProperty(this.whoisInformation, nick)) {
aConv.writeMessage(null, _("message.unknownNick", nick), {system: true});
return;
}
// If the nick is offline, tell the user. In that case, it's WHOWAS info.
let msgType = "message.whois";
if ("offline" in this.whoisInformation[nick])
msgType = "message.whowas";
let msg = _(msgType, this.whoisInformation[nick]["nick"]);
while (aTooltipInfo.hasMoreElements()) {
let elt = aTooltipInfo.getNext().QueryInterface(Ci.prplITooltipInfo);
switch (elt.type) {
case Ci.prplITooltipInfo.pair:
case Ci.prplITooltipInfo.sectionHeader:
msg += "\n" + _("message.whoisEntry", elt.label, elt.value);
break;
case Ci.prplITooltipInfo.sectionBreak:
break;
}
}
aConv.writeMessage(null, msg, {system: true});
},
addBuddy: function(aTag, aName) {
let buddy = new ircAccountBuddy(this, null, aTag, aName);

Просмотреть файл

@ -142,6 +142,9 @@ function setWhoIs(aAccount, aMessage, aFields) {
if (!hasOwnProperty(aAccount.whoisInformation, buddyName))
aAccount.whoisInformation[buddyName] = {};
// Set non-normalized nickname field.
aAccount.whoisInformation[buddyName]["nick"] = aMessage.params[1];
// Set the WHOIS fields.
for (let field in aFields)
aAccount.whoisInformation[buddyName][field] = aFields[field];
@ -654,6 +657,7 @@ var ircBase = {
},
"314": function(aMessage) { // RPL_WHOWASUSER
// <nick> <user> <host> * :<real name>
setWhoIs(this, aMessage, {offline: true});
let source = aMessage.params[2] + "@" + aMessage.params[3];
return setWhoIs(this, aMessage, {realname: aMessage.params[5],
connectedFrom: source});
@ -678,11 +682,17 @@ var ircBase = {
// <nick> :End of WHOIS list
// We've received everything about WHOIS, tell the tooltip that is waiting
// for this information.
let buddyName = this.normalize(aMessage.params[1]);
let nick = this.normalize(aMessage.params[1]);
// Notify the tooltip.
Services.obs.notifyObservers(this.getBuddyInfo(buddyName),
"user-info-received", buddyName);
if (hasOwnProperty(this.whoisInformation, nick)) {
Services.obs.notifyObservers(this.getBuddyInfo(nick),
"user-info-received", nick);
}
else {
// If there is no whois information stored at this point, the nick
// is either offline or does not exist, so we run WHOWAS.
this.requestOfflineBuddyInfo(nick);
}
return true;
},
"319": function(aMessage) { // RPL_WHOISCHANNELS
@ -862,8 +872,12 @@ var ircBase = {
},
"369": function(aMessage) { // RPL_ENDOFWHOWAS
// <nick> :End of WHOWAS
// TODO
return false;
// We've received everything about WHOWAS, tell the tooltip that is waiting
// for this information.
let nick = this.normalize(aMessage.params[1]);
Services.obs.notifyObservers(this.getBuddyInfo(nick),
"user-info-received", nick);
return true;
},
/*
@ -955,8 +969,10 @@ var ircBase = {
// Error messages, Implement Section 5.2 of RFC 2812
"401": function(aMessage) { // ERR_NOSUCHNICK
// <nickname> :No such nick/channel
// TODO Parse & display an error to the user.
return false;
// Can arise in response to /mode, /invite, /kill, /msg, /whois.
// TODO Only handled in the conversation for /whois so far.
return errorMessage(this, aMessage,
_("error.noSuchNick", aMessage.params[1]));
},
"402": function(aMessage) { // ERR_NOSUCHSERVER
// <server name> :No such server
@ -980,8 +996,9 @@ var ircBase = {
},
"406": function(aMessage) { // ERR_WASNOSUCHNICK
// <nickname> :There was no such nickname
// TODO Error saying the nick never existed.
return false;
// Can arise in response to WHOWAS.
return errorMessage(this, aMessage,
_("error.wasNoSuchNick", aMessage.params[1]));
},
"407": function(aMessage) { // ERR_TOOMANYTARGETS
// <target> :<error code> recipients. <abord message>

Просмотреть файл

@ -38,10 +38,16 @@
// implementing the commands field before we register them.
const EXPORTED_SYMBOLS = ["commands"];
Components.utils.import("resource:///modules/ircUtils.jsm");
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource:///modules/ircUtils.jsm");
Cu.import("resource:///modules/imServices.jsm");
// Shortcut to get the JavaScript conversation object.
function getConv(aConv) aConv.wrappedJSObject;
// Shortcut to get the JavaScript account object.
function getAccount(aConv) aConv.wrappedJSObject._account;
function getAccount(aConv) getConv(aConv)._account;
// Kick a user from a channel
// aMsg is <user> [comment]
@ -94,9 +100,8 @@ function actionCommand(aMsg, aConv) {
return false;
// Show the action on our conversation.
let account = getAccount(aConv);
account.getConversation(aConv.name)
.writeMessage(account._nickname, "/me " + aMsg, {outgoing: true});
getConv(aConv).writeMessage(getAccount(aConv)._nickname, "/me " + aMsg,
{outgoing: true});
return true;
}
@ -129,6 +134,15 @@ function ctcpCommand(aConv, aTarget, aCommand, aMsg) {
return true;
}
function whoisCommand(aMsg, aConv) {
aMsg = aMsg.trim();
if (!aMsg || aMsg.indexOf(" ") != -1)
return false;
getConv(aConv).waitForBuddyInfo(aMsg);
getAccount(aConv).requestBuddyInfo(aMsg);
return true;
}
var commands = [
{
name: "action",
@ -241,7 +255,7 @@ var commands = [
name: "part",
get helpString() _("command.part", "part"),
run: function (aMsg, aConv) {
aConv.wrappedJSObject.part(aMsg);
getConv(aConv).part(aMsg);
return true;
}
},
@ -312,9 +326,16 @@ var commands = [
get helpString() _("command.wallops", "wallops"),
run: function(aMsg, aConv) simpleCommand(aConv, "WALLOPS", aMsg)
},
{
name: "whois",
get helpString() _("command.whois", "whois"),
run: whoisCommand
},
{
name: "whowas",
get helpString() _("command.whowas", "whowas"),
run: function(aMsg, aConv) simpleCommand(aConv, "WHOWAS", aMsg)
// We can run whoisCommand here as that will automatically execute whowas
// if the nick is offline (and show the nick is actually online if not).
run: whoisCommand
}
];