Skip to content

Instantly share code, notes, and snippets.

@freaktechnik
Created September 13, 2016 20:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save freaktechnik/ac12d95b408ac74c127fc8ad4aba50ee to your computer and use it in GitHub Desktop.
Save freaktechnik/ac12d95b408ac74c127fc8ad4aba50ee to your computer and use it in GitHub Desktop.
# HG changeset patch
# User Martin Giger <martin@humanoids.be>
# Parent b9cd88a0878f441423c99b7335ee393f4c7d1df1
Bug 1302447 - Add tag handling infrastructure r=clokep
diff --git a/chat/protocols/irc/irc.js b/chat/protocols/irc/irc.js
--- a/chat/protocols/irc/irc.js
+++ b/chat/protocols/irc/irc.js
@@ -148,16 +148,22 @@ function _setMode(aAddNewMode, aNewModes
if (hasMode && !aAddNewMode)
this._modes.delete(newMode);
// If the mode is not in the list of modes and we want to add it.
else if (!hasMode && aAddNewMode)
this._modes.add(newMode);
}
}
+function TagMessage(aMessage, aTagName) {
+ this.message = aMessage;
+ this.tagName = aTagName;
+ this.tagValue = aMessage.tags.get(aTagName);
+}
+
// Properties / methods shared by both ircChannel and ircConversation.
var GenericIRCConversation = {
_observedNicks: [],
// This is set to true after a message is sent to notify the 401
// ERR_NOSUCHNICK handler to write an error message to the conversation.
_pendingMessage: false,
_waitingForNick: false,
@@ -172,16 +178,25 @@ var GenericIRCConversation = {
" " + this._account.buildMessage("PRIVMSG", this.name) +
" :\r\n";
return this._account.maxMessageLength -
this._account.countBytes(baseMessage);
},
// Apply CTCP formatting before displaying.
prepareForDisplaying: function(aMsg) {
aMsg.displayMessage = ctcpFormatToHTML(aMsg.displayMessage);
+
+ if("tags" in aMsg && ircHandlers.hasTagHandlers) {
+ for (let tag in aMsg.tags) {
+ // Unhandled tags may be common, since a tag does not have to be handled
+ // with a tag handler, it may also be handled by a message command handler.
+ ircHandlers.handleTag(this._account, new TagMessage(aMessage, tag));
+ }
+ }
+
GenericConversationPrototype.prepareForDisplaying.apply(this, arguments);
},
prepareForSending: function(aOutgoingMessage, aCount) {
// Split the message by line breaks and send each one individually.
let messages = aOutgoingMessage.message.split(/[\r\n]+/);
let maxLength = this.getMaxMessageLength();
diff --git a/chat/protocols/irc/ircBase.jsm b/chat/protocols/irc/ircBase.jsm
--- a/chat/protocols/irc/ircBase.jsm
+++ b/chat/protocols/irc/ircBase.jsm
@@ -23,17 +23,17 @@ var {interfaces: Ci, utils: Cu} = Compon
Cu.import("resource:///modules/imXPCOMUtils.jsm");
Cu.import("resource:///modules/imServices.jsm");
Cu.import("resource:///modules/ircHandlers.jsm");
Cu.import("resource:///modules/ircUtils.jsm");
Cu.import("resource:///modules/jsProtoHelper.jsm");
function privmsg(aAccount, aMessage, aIsNotification) {
- let params = {incoming: true};
+ let params = {incoming: true, tags: aMessage.tags};
if (aIsNotification)
params.notification = true;
aAccount.getConversation(aAccount.isMUCName(aMessage.params[0]) ?
aMessage.params[0] : aMessage.origin)
.writeMessage(aMessage.origin, aMessage.params[1], params);
return true;
}
@@ -74,16 +74,17 @@ function leftRoom(aAccount, aNicks, aCha
}
}
return true;
}
function writeMessage(aAccount, aMessage, aString, aType) {
let type = {};
type[aType] = true;
+ type.tags = aMessage.tags;
aAccount.getConversation(aMessage.origin)
.writeMessage(aMessage.origin, aString, type);
return true;
}
// If aNoLastParam is true, the last parameter is not printed out.
function serverMessage(aAccount, aMsg, aNoLastParam) {
// If we don't want to show messages from the server, just mark it as handled.
diff --git a/chat/protocols/irc/ircCTCP.jsm b/chat/protocols/irc/ircCTCP.jsm
--- a/chat/protocols/irc/ircCTCP.jsm
+++ b/chat/protocols/irc/ircCTCP.jsm
@@ -118,17 +118,17 @@ var ctcpBase = {
// These represent CTCP commands.
commands: {
"ACTION": function(aMessage) {
// ACTION <text>
// Display message in conversation
this.getConversation(this.isMUCName(aMessage.params[0]) ?
aMessage.params[0] : aMessage.origin)
.writeMessage(aMessage.origin, "/me " + aMessage.ctcp.param,
- {incoming: true});
+ {incoming: true, tags: aMessage.tags});
return true;
},
// Used when an error needs to be replied with.
"ERRMSG": function(aMessage) {
this.WARN(aMessage.origin + " failed to handle CTCP message: " +
aMessage.ctcp.param);
return true;
@@ -203,17 +203,17 @@ var ctcpBase = {
else {
// TIME :<human-readable-time-string>
// Received a TIME reply, display it.
// Remove the : prefix, if it exists and display the result.
let time = aMessage.ctcp.param.slice(aMessage.ctcp.param[0] == ":");
this.getConversation(aMessage.origin)
.writeMessage(aMessage.origin,
_("ctcp.time", aMessage.origin, time),
- {system: true});
+ {system: true, tags: aMessage.tags});
}
return true;
},
// This is commented out since CLIENTINFO automatically returns the
// supported CTCP parameters and this is not supported.
// A string set by the user (never the client coder)
@@ -230,14 +230,15 @@ var ctcpBase = {
this.sendCTCPMessage(aMessage.origin, true, "VERSION", version);
}
else if (aMessage.command == "NOTICE" && aMessage.ctcp.param.length) {
// VERSION #:#:#
// Received VERSION response, display to the user.
let response = _("ctcp.version", aMessage.origin,
aMessage.ctcp.param);
this.getConversation(aMessage.origin)
- .writeMessage(aMessage.origin, response, {system: true});
+ .writeMessage(aMessage.origin, response,
+ {system: true, tags: aMessage.tags});
}
return true;
}
}
};
diff --git a/chat/protocols/irc/ircHandlers.jsm b/chat/protocols/irc/ircHandlers.jsm
--- a/chat/protocols/irc/ircHandlers.jsm
+++ b/chat/protocols/irc/ircHandlers.jsm
@@ -31,16 +31,19 @@ var ircHandlers = {
_capHandlers: [],
// Object to hold the CTCP handlers, expects the same fields as _ircHandlers.
_ctcpHandlers: [],
// Object to hold the DCC handlers, expects the same fields as _ircHandlers.
_dccHandlers: [],
// Object to hold the Services handlers, expects the same fields as
// _ircHandlers.
_servicesHandlers: [],
+ // Object to hold irc message tag handlers, expects the same fields as
+ // _ircHandlers.
+ _tagHandlers: [],
_registerHandler: function(aArray, aHandler) {
// Protect ourselves from adding broken handlers.
if (!("commands" in aHandler)) {
Cu.reportError(new Error("IRC handlers must have a \"commands\" " +
"property: " + aHandler.name));
return false;
}
@@ -98,26 +101,32 @@ var ircHandlers = {
registerServicesHandler: function(aHandler) {
return this._registerHandler(this._servicesHandlers, aHandler);
},
unregisterServicesHandler: function(aHandler) {
this._servicesHandlers = this._unregisterHandler(this._servicesHandlers,
aHandler);
},
+ registerTagHandler: function(aHandler) {
+ return this._registerHandler(this._tagHandlers, aHandler);
+ },
+ unregisterTagHandler: function(aHandler) {
+ this._tagHandlers = this._unregisterHandler(this._tagHandlers, aHandler);
+ },
+
// Handle a message based on a set of handlers.
_handleMessage: function(aHandlers, aAccount, aMessage, aCommand) {
// Loop over each handler and run the command until one handles the message.
for (let handler of aHandlers) {
try {
// Attempt to execute the command, by checking if the handler has the
// command.
// Parse the command with the JavaScript account object as "this".
- if (handler.isEnabled.call(aAccount) &&
- Object.prototype.hasOwnProperty.call(handler.commands, aCommand) &&
+ if (handler.isEnabled.call(aAccount) && aCommand in handler.commands &&
handler.commands[aCommand].call(aAccount, aMessage))
return true;
} catch (e) {
// We want to catch an error here because one of our handlers are
// broken, if we don't catch the error, the whole IRC plug-in will die.
aAccount.ERROR("Error running command " + aCommand + " with handler " +
handler.name + ":\n" + JSON.stringify(aMessage), e);
}
@@ -154,21 +163,28 @@ var ircHandlers = {
},
// aMessage is a Services Message.
handleServicesMessage: function(aAccount, aMessage) {
return this._handleMessage(this._servicesHandlers, aAccount, aMessage,
aMessage.serviceName);
},
+ // aMessage is a Tag Message.
+ handleTag: function(aAccount, aMessage) {
+ return this._handleMessage(this._tagHandlers, aAccount, aMessage,
+ aMessage.tagName);
+ },
+
// Checking if handlers exist.
get hasHandlers() { return this._ircHandlers.length > 0; },
get hasISUPPORTHandlers() { return this._isupportHandlers.length > 0; },
get hasCAPHandlers() { return this._capHandlers.length > 0; },
get hasCTCPHandlers() { return this._ctcpHandlers.length > 0; },
get hasDCCHandlers() { return this._dccHandlers.length > 0; },
get hasServicesHandlers() { return this._servicesHandlers.length > 0; },
+ get hasTagHandlers() { return this._tagHandlers.length > 0 },
// Some constant priorities.
get LOW_PRIORITY() { return -100; },
get DEFAULT_PRIORITY() { return 0; },
get HIGH_PRIORITY() { return 100; }
};
diff --git a/chat/protocols/irc/ircNonStandard.jsm b/chat/protocols/irc/ircNonStandard.jsm
--- a/chat/protocols/irc/ircNonStandard.jsm
+++ b/chat/protocols/irc/ircNonStandard.jsm
@@ -75,17 +75,17 @@ var ircNonStandard = {
// message, which falls through to normal NOTICE processing.
// Note that if the user's nick is auth this COULD be a notice directed at
// them. For reference: moznet sends Auth (previously sent AUTH), freenode
// sends *.
let isAuth = target == "auth" && this._nickname.toLowerCase() != "auth";
if (!aMessage.params[1].startsWith("***") && !isAuth) {
this.getConversation(aMessage.origin)
.writeMessage(aMessage.origin, aMessage.params[1],
- {incoming: true});
+ {incoming: true, tags: aMessage.tags});
return true;
}
return false;
},
"042": function(aMessage) { // RPL_YOURID (IRCnet)
// <nick> <id> :your unique ID
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment