Bug 1205727 - Implement invite and me commands for XMPP muc. r=aleth

This commit is contained in:
Abdelrhman Ahmed 2015-09-28 19:50:42 +02:00
Родитель 07154e24ee
Коммит 57c77eaa53
3 изменённых файлов: 134 добавлений и 13 удалений

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

@ -74,6 +74,12 @@ conversation.error.banKickCommandNotAllowed=You don't have the required privileg
conversation.error.banKickCommandConflict=Sorry, you can't remove yourself from the room.
conversation.error.changeNickFailedConflict=Could not change your nick to %S as this nick is already in use.
conversation.error.changeNickFailedNotAcceptable=Could not change your nick to %S as nicks are locked down in this room.
conversation.error.inviteFailedForbidden=You don't have the required privileges to invite users to this room.
# %S is the jid of user that is invited.
conversation.error.failedJIDNotFound=Could not reach %S.
# %S is the jid that is invalid.
conversation.error.invalidJID=%S is an invalid jid (Jabber identifiers must be of the form user@domain).
conversation.error.commandFailedNotInRoom=You have to rejoin the room to be able to use this command.
conversation.error.unknownError=Unknown error
# LOCALIZATION NOTE (tooltip.*):
@ -135,6 +141,12 @@ conversation.message.parted.you.reason=You have left the room: %S
conversation.message.parted=%1$S has left the room.
conversation.message.parted.reason=%1$S has left the room: %2$S
# LOCALIZATION NOTE (conversation.message.invitationDeclined*):
# %1$S is the invitee that declined the invitation.
# %2$S is the decline message supplied by the invitee.
conversation.message.invitationDeclined=%1$S has declined your invitation.
conversation.message.invitationDeclined.reason=%1$S has declined your invitation: %2$S
# LOCALIZATION NOTE (conversation.message.banned.*):
# These are displayed as a system message when a participant is banned from
# a room.
@ -229,5 +241,7 @@ command.part2=%S [<message>]: Leave the current room with an optional mess
command.topic=%S [<new topic>]: Set this room's topic.
command.ban=%S <nick>[<message>]: Ban someone from the room. You must be a room administrator to do this.
command.kick=%S <nick>[<message>]: Remove someone from the room. You must be a room moderator to do this.
command.invite=%S <jid>[<message>]: Invite a user to join the current room with an optional message.
command.me=%S <action to perform>: Perform an action.
command.nick=%S <new nickname>: Change your nickname.
command.msg=%S <nick> <message>: Send a private message to a participant in the room.

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

@ -22,6 +22,17 @@ function getAccount(aConv) {
return getConv(aConv)._account;
}
function getMUC(aConv) {
let conv = getConv(aConv);
if (conv.left) {
conv.writeMessage(conv.name,
_("conversation.error.commandFailedNotInRoom"),
{system: true});
return null;
}
return conv;
}
// Trims the string and splits it in two parts on the first space
// if there is one. Returns the non-empty parts in an array.
function splitInput(aString) {
@ -33,7 +44,7 @@ function splitInput(aString) {
let offset = params.indexOf(" ");
if (offset != -1) {
splitParams.push(params.slice(0, offset));
splitParams.push(params.slice(offset + 1));
splitParams.push(params.slice(offset + 1).trimLeft());
}
else
splitParams.push(params);
@ -90,9 +101,10 @@ var commands = [
get helpString() { return _("command.topic", "topic"); },
usageContext: Ci.imICommand.CMD_CONTEXT_CHAT,
run: function(aMsg, aConv) {
let conv = getConv(aConv);
if (!conv.left)
conv.topic = aMsg;
let conv = getMUC(aConv);
if (!conv)
return true;
conv.topic = aMsg;
return true;
}
},
@ -105,9 +117,9 @@ var commands = [
if (!params.length)
return false;
let conv = getConv(aConv);
if (!conv.left)
conv.ban(params[0], params[1]);
let conv = getMUC(aConv);
if (conv)
conv.ban(...params);
return true;
}
},
@ -120,9 +132,53 @@ var commands = [
if (!params.length)
return false;
let conv = getMUC(aConv);
if (conv)
conv.kick(...params);
return true;
}
},
{
name: "invite",
get helpString() { return _("command.invite", "invite"); },
usageContext: Ci.imICommand.CMD_CONTEXT_CHAT,
run: function(aMsg, aConv) {
let params = splitInput(aMsg);
if (!params.length)
return false;
let conv = getMUC(aConv);
if (!conv)
return true;
// Check user's jid is valid.
let account = getAccount(aConv);
let jid = account._parseJID(params[0]);
if (!jid) {
conv.writeMessage(conv.name,
_("conversation.error.invalidJID", params[0]),
{system: true});
return true;
}
conv.invite(...params);
return true;
}
},
{
name: "me",
get helpString() { return _("command.me", "me"); },
usageContext: Ci.imICommand.CMD_CONTEXT_CHAT,
run: function(aMsg, aConv) {
let params = aMsg.trim();
if (!params)
return false;
// XEP-0245: The /me Command.
// We need to append "/me " in the first four characters of the message
// body.
let conv = getConv(aConv);
if (!conv.left)
conv.ban(params[0], params[1]);
conv.sendMsg("/me " + params);
return true;
}
},
@ -135,8 +191,8 @@ var commands = [
if (!params[0])
return false;
let conv = getConv(aConv);
if (!conv.left)
let conv = getMUC(aConv);
if (conv)
conv.setNick(params[0]);
return true;
}
@ -151,8 +207,8 @@ var commands = [
return false;
let [nickName, msg] = params;
let conv = getConv(aConv);
if (conv.left)
let conv = getMUC(aConv);
if (!conv)
return true;
if (!conv._participants.has(nickName)) {

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

@ -423,6 +423,24 @@ const XMPPMUCConversationPrototype = {
delete this.chatRoomFields;
},
// Invites a user to MUC conversation.
invite: function(aJID, aMsg = null) {
// XEP-0045 (7.8): Inviting Another User to a Room.
// XEP-0045 (7.8.2): Mediated Invitation.
let invite = Stanza.node("invite", null, {to: aJID},
aMsg ? Stanza.node("reason", null, null, aMsg) : null);
let x = Stanza.node("x", Stanza.NS.muc_user, null, invite);
let s = Stanza.node("message", null, {to: this.name}, x);
this._account.sendStanza(s, this._account.handleErrors({
forbidden: _("conversation.error.inviteFailedForbidden"),
// ejabberd uses error not-allowed to indicate that this account does not
// have the required privileges to invite users instead of forbidden error,
// and this is not mentioned in the spec (XEP-0045).
notAllowed: _("conversation.error.inviteFailedForbidden"),
itemNotFound: _("conversation.error.failedJIDNotFound", aJID)
}, this));
},
// Bans a participant from MUC conversation.
ban: function(aNickName, aMsg = null) {
// XEP-0045 (9.1): Banning a User.
@ -485,6 +503,29 @@ const XMPPMUCConversationPrototype = {
}, this));
},
// Called by the account when a message stanza is received for this muc and
// needs to be handled.
onMessageStanza: function(aStanza) {
let x = aStanza.getElement(["x"]);
let decline = x.getElement(["decline"]);
if (decline) {
// XEP-0045 (7.8): Inviting Another User to a Room.
// XEP-0045 (7.8.2): Mediated Invitation.
let invitee = decline.attributes["jid"];
let reasonNode = decline.getElement(["reason"]);
let reason = reasonNode ? reasonNode.innerText : "";
let msg;
if (reason)
msg = _("conversation.message.invitationDeclined.reason", invitee, reason);
else
msg = _("conversation.message.invitationDeclined", invitee);
this.writeMessage(this.name, msg, {system: true});
}
else
this.WARN("Unhandled message stanza.");
},
/* Called when the user closed the conversation */
close: function() {
if (!this.left)
@ -1647,6 +1688,7 @@ const XMPPAccountPrototype = {
let norm = this.normalize(from);
let type = aStanza.attributes["type"];
let x = aStanza.getElement(["x"]);
let body;
let b = aStanza.getElement(["body"]);
if (b) {
@ -1735,6 +1777,15 @@ const XMPPAccountPrototype = {
if (conv)
conv.incomingMessage(null, aStanza);
}
else if (x && x.uri == Stanza.NS.muc_user) {
let muc = this._mucs.get(norm);
if (!muc) {
this.WARN("Received a groupchat message for unknown MUC " + norm);
return;
}
muc.onMessageStanza(aStanza);
return;
}
// Don't create a conversation to only display the typing notifications.
if (!this._conv.has(norm) && !this._conv.has(from))