1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5const EXPORTED_SYMBOLS = ["ircHandlers"]; 6 7var ircHandlers = { 8 /* 9 * Object to hold the IRC handlers, each handler is an object that implements: 10 * name The display name of the handler. 11 * priority The priority of the handler (0 is default, positive is 12 * higher priority) 13 * isEnabled A function where 'this' is bound to the account object. This 14 * should reflect whether this handler should be used for this 15 * account. 16 * commands An object of commands, each command is a function which 17 * accepts a message object and has 'this' bound to the account 18 * object. It should return whether the message was successfully 19 * handler or not. 20 */ 21 _ircHandlers: [], 22 // Object to hold the ISUPPORT handlers, expects the same fields as 23 // _ircHandlers. 24 _isupportHandlers: [], 25 // Object to hold the Client Capabilities handlers, expects the same fields as 26 // _ircHandlers. 27 _capHandlers: [], 28 // Object to hold the CTCP handlers, expects the same fields as _ircHandlers. 29 _ctcpHandlers: [], 30 // Object to hold the DCC handlers, expects the same fields as _ircHandlers. 31 _dccHandlers: [], 32 // Object to hold the Services handlers, expects the same fields as 33 // _ircHandlers. 34 _servicesHandlers: [], 35 // Object to hold irc message tag handlers, expects the same fields as 36 // _ircHandlers. 37 _tagHandlers: [], 38 39 _registerHandler(aArray, aHandler) { 40 // Protect ourselves from adding broken handlers. 41 if (!("commands" in aHandler)) { 42 Cu.reportError( 43 new Error( 44 'IRC handlers must have a "commands" property: ' + aHandler.name 45 ) 46 ); 47 return false; 48 } 49 if (!("isEnabled" in aHandler)) { 50 Cu.reportError( 51 new Error( 52 'IRC handlers must have a "isEnabled" property: ' + aHandler.name 53 ) 54 ); 55 return false; 56 } 57 58 aArray.push(aHandler); 59 aArray.sort((a, b) => b.priority - a.priority); 60 return true; 61 }, 62 63 _unregisterHandler(aArray, aHandler) { 64 return aArray.filter(h => h.name != aHandler.name); 65 }, 66 67 registerHandler(aHandler) { 68 return this._registerHandler(this._ircHandlers, aHandler); 69 }, 70 unregisterHandler(aHandler) { 71 this._ircHandlers = this._unregisterHandler(this._ircHandlers, aHandler); 72 }, 73 74 registerISUPPORTHandler(aHandler) { 75 return this._registerHandler(this._isupportHandlers, aHandler); 76 }, 77 unregisterISUPPORTHandler(aHandler) { 78 this._isupportHandlers = this._unregisterHandler( 79 this._isupportHandlers, 80 aHandler 81 ); 82 }, 83 84 registerCAPHandler(aHandler) { 85 return this._registerHandler(this._capHandlers, aHandler); 86 }, 87 unregisterCAPHandler(aHandler) { 88 this._capHandlers = this._unregisterHandler(this._capHandlers, aHandler); 89 }, 90 91 registerCTCPHandler(aHandler) { 92 return this._registerHandler(this._ctcpHandlers, aHandler); 93 }, 94 unregisterCTCPHandler(aHandler) { 95 this._ctcpHandlers = this._unregisterHandler(this._ctcpHandlers, aHandler); 96 }, 97 98 registerDCCHandler(aHandler) { 99 return this._registerHandler(this._dccHandlers, aHandler); 100 }, 101 unregisterDCCHandler(aHandler) { 102 this._dccHandlers = this._unregisterHandler(this._dccHandlers, aHandler); 103 }, 104 105 registerServicesHandler(aHandler) { 106 return this._registerHandler(this._servicesHandlers, aHandler); 107 }, 108 unregisterServicesHandler(aHandler) { 109 this._servicesHandlers = this._unregisterHandler( 110 this._servicesHandlers, 111 aHandler 112 ); 113 }, 114 115 registerTagHandler(aHandler) { 116 return this._registerHandler(this._tagHandlers, aHandler); 117 }, 118 unregisterTagHandler(aHandler) { 119 this._tagHandlers = this._unregisterHandler(this._tagHandlers, aHandler); 120 }, 121 122 // Handle a message based on a set of handlers. 123 _handleMessage(aHandlers, aAccount, aMessage, aCommand) { 124 // Loop over each handler and run the command until one handles the message. 125 for (let handler of aHandlers) { 126 try { 127 // Attempt to execute the command, by checking if the handler has the 128 // command. 129 // Parse the command with the JavaScript account object as "this". 130 if ( 131 handler.isEnabled.call(aAccount) && 132 aCommand in handler.commands && 133 handler.commands[aCommand].call(aAccount, aMessage) 134 ) { 135 return true; 136 } 137 } catch (e) { 138 // We want to catch an error here because one of our handlers are 139 // broken, if we don't catch the error, the whole IRC plug-in will die. 140 aAccount.ERROR( 141 "Error running command " + 142 aCommand + 143 " with handler " + 144 handler.name + 145 ":\n" + 146 JSON.stringify(aMessage), 147 e 148 ); 149 } 150 } 151 152 return false; 153 }, 154 155 handleMessage(aAccount, aMessage) { 156 return this._handleMessage( 157 this._ircHandlers, 158 aAccount, 159 aMessage, 160 aMessage.command.toUpperCase() 161 ); 162 }, 163 164 handleISUPPORTMessage(aAccount, aMessage) { 165 return this._handleMessage( 166 this._isupportHandlers, 167 aAccount, 168 aMessage, 169 aMessage.isupport.parameter 170 ); 171 }, 172 173 handleCAPMessage(aAccount, aMessage) { 174 return this._handleMessage( 175 this._capHandlers, 176 aAccount, 177 aMessage, 178 aMessage.cap.parameter 179 ); 180 }, 181 182 // aMessage is a CTCP Message, which inherits from an IRC Message. 183 handleCTCPMessage(aAccount, aMessage) { 184 return this._handleMessage( 185 this._ctcpHandlers, 186 aAccount, 187 aMessage, 188 aMessage.ctcp.command 189 ); 190 }, 191 192 // aMessage is a DCC Message, which inherits from a CTCP Message. 193 handleDCCMessage(aAccount, aMessage) { 194 return this._handleMessage( 195 this._dccHandlers, 196 aAccount, 197 aMessage, 198 aMessage.ctcp.dcc.type 199 ); 200 }, 201 202 // aMessage is a Services Message. 203 handleServicesMessage(aAccount, aMessage) { 204 return this._handleMessage( 205 this._servicesHandlers, 206 aAccount, 207 aMessage, 208 aMessage.serviceName 209 ); 210 }, 211 212 // aMessage is a Tag Message. 213 handleTag(aAccount, aMessage) { 214 return this._handleMessage( 215 this._tagHandlers, 216 aAccount, 217 aMessage, 218 aMessage.tagName 219 ); 220 }, 221 222 // Checking if handlers exist. 223 get hasHandlers() { 224 return this._ircHandlers.length > 0; 225 }, 226 get hasISUPPORTHandlers() { 227 return this._isupportHandlers.length > 0; 228 }, 229 get hasCAPHandlers() { 230 return this._capHandlers.length > 0; 231 }, 232 get hasCTCPHandlers() { 233 return this._ctcpHandlers.length > 0; 234 }, 235 get hasDCCHandlers() { 236 return this._dccHandlers.length > 0; 237 }, 238 get hasServicesHandlers() { 239 return this._servicesHandlers.length > 0; 240 }, 241 get hasTagHandlers() { 242 return this._tagHandlers.length > 0; 243 }, 244 245 // Some constant priorities. 246 get LOW_PRIORITY() { 247 return -100; 248 }, 249 get DEFAULT_PRIORITY() { 250 return 0; 251 }, 252 get HIGH_PRIORITY() { 253 return 100; 254 }, 255}; 256