summaryrefslogtreecommitdiffstats
path: root/comm/suite/chatzilla/xul/content/commands.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:32:43 +0000
commit6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /comm/suite/chatzilla/xul/content/commands.js
parentInitial commit. (diff)
downloadthunderbird-upstream.tar.xz
thunderbird-upstream.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'comm/suite/chatzilla/xul/content/commands.js')
-rw-r--r--comm/suite/chatzilla/xul/content/commands.js4760
1 files changed, 4760 insertions, 0 deletions
diff --git a/comm/suite/chatzilla/xul/content/commands.js b/comm/suite/chatzilla/xul/content/commands.js
new file mode 100644
index 0000000000..a99ca52c3e
--- /dev/null
+++ b/comm/suite/chatzilla/xul/content/commands.js
@@ -0,0 +1,4760 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * 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 CMD_CONSOLE = 0x01;
+const CMD_NEED_NET = 0x02;
+const CMD_NEED_SRV = 0x04;
+const CMD_NEED_CHAN = 0x08;
+const CMD_NEED_USER = 0x10;
+
+function initCommands()
+{
+ // Keep this in sync with the command.js section in chatzilla.properties.
+ var cmdary =
+ [/* "real" commands */
+ ["about", cmdAbout, CMD_CONSOLE],
+ ["alias", cmdAlias, CMD_CONSOLE,
+ "[<alias-name> [<command-list>]]"],
+ ["attach", cmdAttach, CMD_CONSOLE,
+ "<irc-url>"],
+ ["away", cmdAway, CMD_CONSOLE,
+ "[<reason>]"],
+ ["back", cmdAway, CMD_CONSOLE],
+ ["ban", cmdBanOrExcept, CMD_NEED_CHAN | CMD_CONSOLE,
+ "[<nickname>]"],
+ ["cancel", cmdCancel, CMD_CONSOLE],
+ ["charset", cmdCharset, CMD_CONSOLE,
+ "[<new-charset>]"],
+ ["channel-motif", cmdMotif, CMD_NEED_CHAN | CMD_CONSOLE,
+ "[<motif> [<channel>]]"],
+ ["channel-pref", cmdPref, CMD_NEED_CHAN | CMD_CONSOLE,
+ "[<pref-name> [<pref-value>]]"],
+ ["cmd-undo", "cmd-docommand cmd_undo", 0],
+ ["cmd-redo", "cmd-docommand cmd_redo", 0],
+ ["cmd-cut", "cmd-docommand cmd_cut", 0],
+ ["cmd-copy", "cmd-docommand cmd_copy", 0],
+ ["cmd-paste", "cmd-docommand cmd_paste", 0],
+ ["cmd-delete", "cmd-docommand cmd_delete", 0],
+ ["cmd-selectall", "cmd-docommand cmd_selectAll", 0],
+ ["cmd-copy-link-url", "cmd-docommand cmd_copyLink", 0,
+ "<url>"],
+ ["cmd-mozilla-prefs", "cmd-docommand cmd_mozillaPrefs", 0],
+ ["cmd-prefs", "cmd-docommand cmd_chatzillaPrefs", 0],
+ ["cmd-chatzilla-prefs", "cmd-docommand cmd_chatzillaPrefs", 0],
+ ["cmd-chatzilla-opts", "cmd-docommand cmd_chatzillaPrefs", 0],
+ ["cmd-docommand", cmdDoCommand, 0,
+ "<cmd-name>"],
+ ["create-tab-for-view", cmdCreateTabForView, 0,
+ "<view>"],
+ ["custom-away", cmdAway, 0],
+ ["op", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+ ["dcc-accept", cmdDCCAccept, CMD_CONSOLE,
+ "[<nickname> [<type> [<file>]]]"],
+ ["dcc-accept-list", cmdDCCAutoAcceptList, CMD_NEED_NET | CMD_CONSOLE],
+ ["dcc-accept-list-add", cmdDCCAutoAcceptAdd,
+ CMD_NEED_NET | CMD_CONSOLE,
+ "<nickname>"],
+ ["dcc-accept-list-remove", cmdDCCAutoAcceptDel,
+ CMD_NEED_NET | CMD_CONSOLE,
+ "<nickname>"],
+ ["dcc-chat", cmdDCCChat, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<nickname>]"],
+ ["dcc-close", cmdDCCClose, CMD_CONSOLE,
+ "[<nickname> [<type> [<file>]]]"],
+ ["dcc-decline", cmdDCCDecline, CMD_CONSOLE,
+ "[<nickname>]"],
+ ["dcc-list", cmdDCCList, CMD_CONSOLE,
+ "[<type>]"],
+ ["dcc-send", cmdDCCSend, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<nickname> [<file>]]"],
+ ["dcc-show-file", cmdDCCShowFile, CMD_CONSOLE,
+ "<file>"],
+ ["delayed", cmdDelayed, CMD_CONSOLE,
+ "<delay> <rest>"],
+ ["deop", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+ ["describe", cmdDescribe, CMD_NEED_SRV | CMD_CONSOLE,
+ "<target> <action>"],
+ ["hop", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+ ["dehop", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+ ["voice", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+ ["devoice", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+ ["clear-view", cmdClearView, CMD_CONSOLE,
+ "[<view>]"],
+ ["client", cmdClient, CMD_CONSOLE],
+ ["commands", cmdCommands, CMD_CONSOLE,
+ "[<pattern>]"],
+ ["ctcp", cmdCTCP, CMD_NEED_SRV | CMD_CONSOLE,
+ "<target> <code> [<params>]"],
+ ["default-charset", cmdCharset, CMD_CONSOLE,
+ "[<new-charset>]"],
+ ["delete-view", cmdDeleteView, CMD_CONSOLE,
+ "[<view>]"],
+ ["desc", cmdDesc, CMD_CONSOLE,
+ "[<description>]"],
+ ["disable-plugin", cmdDisablePlugin, CMD_CONSOLE],
+ ["disconnect", cmdDisconnect, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<reason>]"],
+ ["disconnect-all", cmdDisconnectAll, CMD_CONSOLE,
+ "[<reason>]"],
+ ["echo", cmdEcho, CMD_CONSOLE,
+ "<message>"],
+ ["edit-networks", cmdEditNetworks, CMD_CONSOLE],
+ ["enable-plugin", cmdEnablePlugin, CMD_CONSOLE,
+ "<plugin>"],
+ ["eval", cmdEval, CMD_CONSOLE,
+ "<expression>"],
+ ["evalsilent", cmdEval, CMD_CONSOLE,
+ "<expression>"],
+ ["except", cmdBanOrExcept, CMD_NEED_CHAN | CMD_CONSOLE,
+ "[<nickname>]"],
+ ["find", cmdFind, 0,
+ "[<rest>]"],
+ ["find-again", cmdFindAgain, 0],
+ ["focus-input", cmdFocusInput, 0],
+ ["font-family", cmdFont, CMD_CONSOLE,
+ "[<font>]"],
+ ["font-family-other", cmdFont, 0],
+ ["font-size", cmdFont, CMD_CONSOLE,
+ "[<font-size>]"],
+ ["font-size-other", cmdFont, 0],
+ ["goto-startup", cmdGotoStartup, CMD_CONSOLE],
+ ["goto-url", cmdGotoURL, 0,
+ "<url> [<anchor>]"],
+ ["goto-url-newwin", cmdGotoURL, 0,
+ "<url> [<anchor>]"],
+ ["goto-url-newtab", cmdGotoURL, 0,
+ "<url> [<anchor>]"],
+ ["help", cmdHelp, CMD_CONSOLE,
+ "[<pattern>]"],
+ ["hide-view", cmdHideView, CMD_CONSOLE,
+ "[<view>]"],
+ ["identify", cmdIdentify, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<password>]"],
+ ["idle-away", cmdAway, 0],
+ ["idle-back", cmdAway, 0],
+ ["ignore", cmdIgnore, CMD_NEED_NET | CMD_CONSOLE,
+ "[<mask>]"],
+ ["input-text-direction", cmdInputTextDirection, 0,
+ "<dir>"],
+ ["install-plugin", cmdInstallPlugin, CMD_CONSOLE,
+ "[<url> [<name>]]"],
+ ["invite", cmdInvite, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname> [<channel-name>]"],
+ ["join", cmdJoin, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<channel-name> [<key>]]"],
+ ["join-charset", cmdJoin, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<channel-name> <charset> [<key>]]"],
+ ["jump-to-anchor", cmdJumpToAnchor, CMD_NEED_NET,
+ "<anchor> [<channel-name>]"],
+ ["kick", cmdKick, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<nickname> [<reason>]"],
+ ["kick-ban", cmdKick, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<nickname> [<reason>]"],
+ ["knock", cmdKnock, CMD_NEED_SRV | CMD_CONSOLE,
+ "<channel-name> [<reason>]"],
+ ["leave", cmdLeave, CMD_NEED_NET | CMD_CONSOLE,
+ "[<channel-name>] [<reason>]"],
+ ["links", cmdSimpleCommand, CMD_NEED_SRV | CMD_CONSOLE],
+ ["list", cmdList, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<channel-name>]"],
+ ["list-plugins", cmdListPlugins, CMD_CONSOLE,
+ "[<plugin>]"],
+ ["load", cmdLoad, CMD_CONSOLE,
+ "<url>"],
+ ["log", cmdLog, CMD_CONSOLE,
+ "[<state>]"],
+ ["map", cmdSimpleCommand, CMD_NEED_SRV | CMD_CONSOLE],
+ ["marker", cmdMarker, CMD_CONSOLE],
+ ["marker-clear", cmdMarker, CMD_CONSOLE],
+ ["marker-set", cmdMarker, CMD_CONSOLE],
+ ["match-users", cmdMatchUsers, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<mask>"],
+ ["me", cmdMe, CMD_CONSOLE,
+ "<action>"],
+ ["motd", cmdSimpleCommand, CMD_NEED_SRV | CMD_CONSOLE],
+ ["mode", cmdMode, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<target>] [<modestr> [<param> [<...>]]]"],
+ ["motif", cmdMotif, CMD_CONSOLE,
+ "[<motif>]"],
+ ["msg", cmdMsg, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname> <message>"],
+ ["name", cmdName, CMD_CONSOLE,
+ "[<username>]"],
+ ["names", cmdNames, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<channel-name>]"],
+ ["network", cmdNetwork, CMD_CONSOLE,
+ "<network-name>"],
+ ["network-motif", cmdMotif, CMD_NEED_NET | CMD_CONSOLE,
+ "[<motif> [<network>]]"],
+ ["network-pref", cmdPref, CMD_NEED_NET | CMD_CONSOLE,
+ "[<pref-name> [<pref-value>]]"],
+ ["networks", cmdNetworks, CMD_CONSOLE],
+ ["nick", cmdNick, CMD_CONSOLE,
+ "[<nickname>]"],
+ ["notice", cmdNotice, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname> <message>"],
+ ["notify", cmdNotify, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<nickname> [<...>]]"],
+ ["open-at-startup", cmdOpenAtStartup, CMD_CONSOLE,
+ "[<toggle>]"],
+ ["oper", cmdOper, CMD_NEED_SRV | CMD_CONSOLE,
+ "<opername> [<password>]"],
+ ["ping", cmdPing, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname>"],
+ ["plugin-pref", cmdPref, CMD_CONSOLE,
+ "<plugin> [<pref-name> [<pref-value>]]"],
+ ["pref", cmdPref, CMD_CONSOLE,
+ "[<pref-name> [<pref-value>]]"],
+ ["print", cmdPrint, CMD_CONSOLE],
+ ["query", cmdQuery, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname> [<message>]"],
+ ["quit", cmdQuit, CMD_CONSOLE,
+ "[<reason>]"],
+ ["quote", cmdQuote, CMD_NEED_NET | CMD_CONSOLE,
+ "<irc-command>"],
+ ["rename", cmdRename, CMD_CONSOLE,
+ "[<label>]"],
+ ["reload-plugin", cmdReload, CMD_CONSOLE,
+ "<plugin>"],
+ ["rlist", cmdRlist, CMD_NEED_SRV | CMD_CONSOLE,
+ "<regexp>"],
+ ["reconnect", cmdReconnect, CMD_NEED_NET | CMD_CONSOLE,
+ "[<reason>]"],
+ ["reconnect-all", cmdReconnectAll, CMD_CONSOLE,
+ "[<reason>]"],
+ ["rejoin", cmdRejoin,
+ CMD_NEED_SRV | CMD_NEED_CHAN | CMD_CONSOLE,
+ "[<reason>]"],
+ ["reload-ui", cmdReloadUI, 0],
+ ["save", cmdSave, CMD_CONSOLE,
+ "[<filename> [<savetype>]]"],
+ ["say", cmdSay, CMD_CONSOLE,
+ "<message>"],
+ ["server", cmdServer, CMD_CONSOLE,
+ "<hostname> [<port> [<password>]]"],
+ ["set-current-view", cmdSetCurrentView, 0,
+ "<view>"],
+ ["stats", cmdSimpleCommand, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<params>]"],
+ ["squery", cmdSquery, CMD_NEED_SRV | CMD_CONSOLE,
+ "<service> [<commands>]"],
+ ["sslserver", cmdServer, CMD_CONSOLE,
+ "<hostname> [<port> [<password>]]"],
+ ["ssl-exception", cmdSSLException, 0,
+ "[<hostname> <port> [<connect>]]"],
+ ["stalk", cmdStalk, CMD_CONSOLE,
+ "[<text>]"],
+ ["supports", cmdSupports, CMD_NEED_SRV | CMD_CONSOLE],
+ ["sync-font", cmdSync, 0],
+ ["sync-header", cmdSync, 0],
+ ["sync-log", cmdSync, 0],
+ ["sync-motif", cmdSync, 0],
+ ["sync-timestamp", cmdSync, 0],
+ ["sync-window", cmdSync, 0],
+ ["testdisplay", cmdTestDisplay, CMD_CONSOLE],
+ ["text-direction", cmdTextDirection, 0,
+ "<dir>"],
+ ["time", cmdTime, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<nickname>]"],
+ ["timestamps", cmdTimestamps, CMD_CONSOLE,
+ "[<toggle>]"],
+ ["toggle-ui", cmdToggleUI, CMD_CONSOLE,
+ "<thing>"],
+ ["toggle-pref", cmdTogglePref, 0,
+ "<pref-name>"],
+ ["toggle-group", cmdToggleGroup, 0,
+ "<group-id>"],
+ ["topic", cmdTopic, CMD_NEED_CHAN | CMD_CONSOLE,
+ "[<new-topic>]"],
+ ["unalias", cmdAlias, CMD_CONSOLE,
+ "<alias-name>"],
+ ["unignore", cmdIgnore, CMD_NEED_NET | CMD_CONSOLE,
+ "<mask>"],
+ ["unban", cmdBanOrExcept, CMD_NEED_CHAN | CMD_CONSOLE,
+ "<nickname>"],
+ ["unexcept", cmdBanOrExcept, CMD_NEED_CHAN | CMD_CONSOLE],
+ ["uninstall-plugin", cmdUninstallPlugin, CMD_CONSOLE,
+ "<plugin>"],
+ ["unstalk", cmdUnstalk, CMD_CONSOLE,
+ "<text>"],
+ ["urls", cmdURLs, CMD_CONSOLE,
+ "[<number>]"],
+ ["user", cmdUser, CMD_CONSOLE,
+ "[<username> <description>]"],
+ ["userhost", cmdUserhost, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+ ["userip", cmdUserip, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+ ["usermode", cmdUsermode, CMD_CONSOLE,
+ "[<new-mode>]"],
+ ["user-motif", cmdMotif, CMD_NEED_USER | CMD_CONSOLE,
+ "[<motif> [<user>]]"],
+ ["user-pref", cmdPref, CMD_NEED_USER | CMD_CONSOLE,
+ "[<pref-name> [<pref-value>]]"],
+ ["version", cmdVersion, CMD_NEED_SRV | CMD_CONSOLE,
+ "[<nickname>]"],
+ ["websearch", cmdWebSearch, CMD_CONSOLE,
+ "<selected-text>"],
+ ["who", cmdWho, CMD_NEED_SRV | CMD_CONSOLE,
+ "<rest>"],
+ ["whois", cmdWhoIs, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+ ["whowas", cmdWhoWas, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname> [<limit>]"],
+ ["wii", cmdWhoIsIdle, CMD_NEED_SRV | CMD_CONSOLE,
+ "<nickname> [<...>]"],
+
+ /* aliases */
+ ["exit", "quit", CMD_CONSOLE,
+ "[<reason>]"],
+ ["j", "join", CMD_CONSOLE,
+ "[<channel-name> [<key>]]"],
+ ["pass", "quote PASS", CMD_CONSOLE,
+ "<password>"],
+ ["part", "leave", CMD_CONSOLE],
+ ["raw", "quote", CMD_CONSOLE],
+ // Shortcuts to useful URLs:
+ ["faq", "goto-url-newtab faq", 0],
+ ["homepage", "goto-url-newtab homepage", 0],
+ // Used to display a nickname in the menu only.
+ ["label-user", "echo", 0,
+ "<unspecified>"],
+ ["label-user-multi", "echo", 0,
+ "<unspecified>"],
+ // These are all the font family/size menu commands...
+ ["font-family-default", "font-family default", 0],
+ ["font-family-serif", "font-family serif", 0],
+ ["font-family-sans-serif", "font-family sans-serif", 0],
+ ["font-family-monospace", "font-family monospace", 0],
+ ["font-size-default", "font-size default", 0],
+ ["font-size-small", "font-size small", 0],
+ ["font-size-medium", "font-size medium", 0],
+ ["font-size-large", "font-size large", 0],
+ ["font-size-bigger", "font-size bigger", 0],
+ // This next command is not visible; it maps to Ctrl-=, which is what
+ // you get when the user tries to do Ctrl-+ (previous command's key).
+ ["font-size-bigger2", "font-size bigger", 0],
+ ["font-size-smaller", "font-size smaller", 0],
+ ["toggle-oas", "open-at-startup toggle", 0],
+ ["toggle-ccm", "toggle-pref collapseMsgs", 0],
+ ["toggle-copy", "toggle-pref copyMessages", 0],
+ ["toggle-usort", "toggle-pref sortUsersByMode", 0],
+ ["toggle-umode", "toggle-pref showModeSymbols", 0],
+ ["toggle-timestamps","timestamps toggle", 0],
+ ["motif-dark", "motif dark", 0],
+ ["motif-light", "motif light", 0],
+ ["sync-output", "evalsilent syncOutputFrame(this)", 0],
+ ["userlist", "toggle-ui userlist", CMD_CONSOLE],
+ ["tabstrip", "toggle-ui tabstrip", CMD_CONSOLE],
+ ["statusbar", "toggle-ui status", CMD_CONSOLE],
+ ["header", "toggle-ui header", CMD_CONSOLE],
+
+ // text-direction aliases
+ ["rtl", "text-direction rtl", CMD_CONSOLE],
+ ["ltr", "text-direction ltr", CMD_CONSOLE],
+ ["toggle-text-dir", "text-direction toggle", 0],
+ ["irtl", "input-text-direction rtl", CMD_CONSOLE],
+ ["iltr", "input-text-direction ltr", CMD_CONSOLE],
+ // Services aliases
+ ["cs", "quote cs", 0],
+ ["ms", "quote ms", 0],
+ ["ns", "quote ns", 0]
+ ];
+
+ // set the stringbundle associated with these commands.
+ cmdary.stringBundle = client.defaultBundle;
+
+ client.commandManager = new CommandManager(client.defaultBundle);
+ client.commandManager.defaultFlags = CMD_CONSOLE;
+ client.commandManager.isCommandSatisfied = isCommandSatisfied;
+ client.commandManager.defineCommands(cmdary);
+
+ var restList = ["reason", "action", "text", "message", "params", "font",
+ "expression", "ircCommand", "prefValue", "newTopic", "file",
+ "password", "commandList", "commands", "description",
+ "selectedText"];
+ var stateList = ["connect"];
+
+ client.commandManager.argTypes.__aliasTypes__(restList, "rest");
+ client.commandManager.argTypes.__aliasTypes__(stateList, "state");
+ client.commandManager.argTypes["plugin"] = parsePlugin;
+}
+
+function isCommandSatisfied(e, command)
+{
+ if (typeof command == "undefined")
+ command = e.command;
+ else if (typeof command == "string")
+ command = this.commands[command];
+
+ if (command.flags & CMD_NEED_USER)
+ {
+ if (!("user" in e) || !e.user)
+ {
+ e.parseError = getMsg(MSG_ERR_NEED_USER, command.name);
+ return false;
+ }
+ }
+
+ if (command.flags & CMD_NEED_CHAN)
+ {
+ if (!("channel" in e) || !e.channel)
+ {
+ e.parseError = getMsg(MSG_ERR_NEED_CHANNEL, command.name);
+ return false;
+ }
+ }
+
+ if (command.flags & CMD_NEED_SRV)
+ {
+ if (!("server" in e) || !e.server)
+ {
+ e.parseError = getMsg(MSG_ERR_NEED_SERVER, command.name);
+ return false;
+ }
+
+ if (e.network.state != NET_ONLINE)
+ {
+ e.parseError = MSG_ERR_NOT_CONNECTED;
+ return false;
+ }
+ }
+
+ if (command.flags & (CMD_NEED_NET | CMD_NEED_SRV | CMD_NEED_CHAN))
+ {
+ if (!("network" in e) || !e.network)
+ {
+ e.parseError = getMsg(MSG_ERR_NEED_NETWORK, command.name);
+ return false;
+ }
+ }
+
+ return CommandManager.prototype.isCommandSatisfied(e, command);
+}
+
+CIRCChannel.prototype.dispatch =
+CIRCNetwork.prototype.dispatch =
+CIRCUser.prototype.dispatch =
+CIRCDCCChat.prototype.dispatch =
+CIRCDCCFileTransfer.prototype.dispatch =
+client.dispatch =
+function this_dispatch(text, e, isInteractive, flags)
+{
+ e = getObjectDetails(this, e);
+ return dispatch(text, e, isInteractive, flags);
+}
+
+function dispatch(text, e, isInteractive, flags)
+{
+ if (typeof isInteractive == "undefined")
+ isInteractive = false;
+
+ if (!e)
+ e = new Object();
+
+ if (!("sourceObject" in e))
+ e.__proto__ = getObjectDetails(client.currentObject);
+
+ if (!("isInteractive" in e))
+ e.isInteractive = isInteractive;
+
+ if (!("inputData" in e))
+ e.inputData = "";
+
+ /* split command from arguments */
+ var ary = text.match(/(\S+) ?(.*)/);
+ if (!ary)
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_COMMAND, ""));
+ return null;
+ }
+
+ e.commandText = ary[1];
+ if (ary[2])
+ e.inputData = stringTrim(ary[2]);
+
+ /* list matching commands */
+ ary = client.commandManager.list(e.commandText, flags, true);
+ var rv = null;
+ var i;
+
+ switch (ary.length)
+ {
+ case 0:
+ /* no match, try again */
+ if (e.server && e.server.isConnected &&
+ client.prefs["guessCommands"])
+ {
+ /* Want to keep the source details. */
+ var e2 = getObjectDetails(e.sourceObject);
+ e2.inputData = e.commandText + " " + e.inputData;
+ return dispatch("quote", e2);
+ }
+
+ display(getMsg(MSG_ERR_UNKNOWN_COMMAND, e.commandText), MT_ERROR);
+ break;
+
+ case 1:
+ /* one match, good for you */
+ var cm = client.commandManager;
+
+ if (cm.currentDispatchDepth >= cm.maxDispatchDepth)
+ {
+ /* We've reatched the max dispatch depth, so we need to unwind
+ * the entire stack of commands.
+ */
+ cm.dispatchUnwinding = true;
+ }
+ // Don't start any new commands while unwinding.
+ if (cm.dispatchUnwinding)
+ break;
+
+ cm.currentDispatchDepth++;
+
+ var ex;
+ try
+ {
+ rv = dispatchCommand(ary[0], e, flags);
+ }
+ catch (ex)
+ {
+ display(getMsg(MSG_ERR_INTERNAL_DISPATCH, ary[0].name),
+ MT_ERROR);
+ display(formatException(ex), MT_ERROR);
+ if (typeof ex == "object" && "stack" in ex)
+ dd(formatException(ex) + "\n" + ex.stack);
+ else
+ dd(formatException(ex), MT_ERROR);
+ }
+
+ cm.currentDispatchDepth--;
+ if (cm.dispatchUnwinding && (cm.currentDispatchDepth == 0))
+ {
+ /* Last level to unwind, and this is where we display the
+ * message. We need to leave it until here because displaying
+ * a message invokes a couple of commands itself, and we need
+ * to not be right on the dispatch limit for that.
+ */
+ cm.dispatchUnwinding = false;
+ display(getMsg(MSG_ERR_MAX_DISPATCH_DEPTH, ary[0].name),
+ MT_ERROR);
+ }
+ break;
+
+ default:
+ /* more than one match, show the list */
+ var str = "";
+ for (i in ary)
+ str += (str) ? ", " + ary[i].name : ary[i].name;
+ display(getMsg(MSG_ERR_AMBIGCOMMAND,
+ [e.commandText, ary.length, str]), MT_ERROR);
+ }
+
+ return rv;
+}
+
+function dispatchCommand (command, e, flags)
+{
+ function displayUsageError (e, details)
+ {
+ if (!("isInteractive" in e) || !e.isInteractive)
+ {
+ var caller = Components.stack.caller.caller;
+ if (caller.name == "dispatch")
+ caller = caller.caller;
+ var error = new Error (details);
+ error.fileName = caller.filename;
+ error.lineNumber = caller.lineNumber;
+ error.name = caller.name;
+ display (formatException(error), MT_ERROR);
+ }
+ else
+ {
+ display (details, MT_ERROR);
+ }
+
+ //display (getMsg(MSG_FMT_USAGE, [e.command.name, e.command.usage]),
+ // MT_USAGE);
+ return null;
+ };
+
+ function callHooks (command, isBefore)
+ {
+ var names, hooks;
+
+ if (isBefore)
+ hooks = command.beforeHooks;
+ else
+ hooks = command.afterHooks;
+
+ for (var h in hooks)
+ {
+ if ("dbgDispatch" in client && client.dbgDispatch)
+ {
+ dd ("calling " + (isBefore ? "before" : "after") +
+ " hook " + h);
+ }
+ try
+ {
+ hooks[h](e);
+ }
+ catch (ex)
+ {
+ if (e.command.name != "hook-session-display")
+ {
+ display(getMsg(MSG_ERR_INTERNAL_HOOK, h), MT_ERROR);
+ display(formatException(ex), MT_ERROR);
+ }
+ else
+ {
+ dd(getMsg(MSG_ERR_INTERNAL_HOOK, h));
+ }
+
+ dd("Caught exception calling " +
+ (isBefore ? "before" : "after") + " hook " + h);
+ dd(formatException(ex));
+ if (typeof ex == "object" && "stack" in ex)
+ dd(ex.stack);
+ else
+ dd(getStackTrace());
+ }
+ }
+ };
+
+ e.command = command;
+
+ if (!e.command.enabled)
+ {
+ /* disabled command */
+ display (getMsg(MSG_ERR_DISABLED, e.command.name),
+ MT_ERROR);
+ return null;
+ }
+
+ function parseAlias(aliasLine, e) {
+ /* Only 1 of these will be presented to the user. Math.max is used to
+ supply the 'worst' error */
+ const ALIAS_ERR_REQ_PRMS = 1;
+ const ALIAS_ERR_REQ_SRV = 2;
+ const ALIAS_ERR_REQ_RECIP = 3;
+
+ /* double slashes because of the string to regexp conversion, which
+ turns these into single slashes */
+ const SIMPLE_REPLACE = "\\$\\((\\d+)\\)";
+ const CUMUL_REPLACE = "\\$\\((\\d+)\\+\\)";
+ const RANGE_REPLACE = "\\$\\((\\d+)\\-(\\d+)\\)";
+ const NICK_REPLACE = "\\$\\((nick)\\)";
+ const RECIP_REPLACE = "\\$\\((recip)\\)";
+ const ALL_REPLACE = "\\$\\((all)\\)";
+ if (!aliasLine.match(/\$/))
+ {
+ if (e.inputData)
+ display(getMsg(MSG_EXTRA_PARAMS, e.inputData), MT_WARN);
+ return aliasLine;
+ }
+
+ function replaceAll(match, single, cumulative, start, end, nick, recip, all)
+ {
+ if (single)
+ {
+ // Simple 1-parameter replace
+ if (arrayHasElementAt(parameters, single - 1))
+ {
+ paramsUsed = Math.max(paramsUsed, single);
+ return parameters[single-1];
+ }
+ maxParamsAsked = Math.max(maxParamsAsked, single);
+ errorMsg = Math.max(ALIAS_ERR_REQ_PRMS, errorMsg);
+ return match;
+ }
+ if (cumulative)
+ {
+ // Cumulative Replace: parameters cumulative and up
+ if (arrayHasElementAt(parameters, cumulative - 1))
+ {
+ paramsUsed = parameters.length;
+ // there are never leftover parameters for $(somenumber+)
+ return parameters.slice(cumulative - 1).join(" ");
+ }
+ maxParamsAsked = Math.max(maxParamsAsked, cumulative);
+ errorMsg = Math.max(ALIAS_ERR_REQ_PRMS, errorMsg);
+ return match;
+ }
+ if (start && end)
+ {
+ // Ranged replace: parameters start through end
+ //'decrement to correct 0-based index.
+ if (start > end)
+ {
+ var iTemp = end;
+ end = start;
+ start = iTemp;
+ // We obviously have a very stupid user, but we're nice
+ }
+ start--;
+ if (arrayHasElementAt(parameters, start) &&
+ arrayHasElementAt(parameters, end - 1))
+ {
+ paramsUsed = Math.max(paramsUsed,end);
+ return parameters.slice(start, end).join(" ");
+ }
+ maxParamsAsked = Math.max(maxParamsAsked, end);
+ errorMsg = Math.max(ALIAS_ERR_REQ_PRMS, errorMsg);
+ return match;
+ }
+ if (nick)
+ {
+ // Replace with own nickname
+ if (e.network && e.server && e.network.state == NET_ONLINE)
+ return e.server.me.unicodeName;
+
+ errorMsg = Math.max(ALIAS_ERR_REQ_SRV, errorMsg);
+ return null;
+ }
+ if (recip)
+ {
+ // Replace with current recipient
+ if (e.channel)
+ return e.channel.unicodeName;
+
+ if (e.user)
+ return e.user.unicodeName;
+
+ errorMsg = ALIAS_ERR_REQ_RECIP;
+ return null;
+ }
+ // Replace with all parameters
+ paramsUsed = parameters.length;
+ return parameters.join(" ");
+ };
+
+ // If the replace function has a problem, this is an error constant:
+ var errorMsg = 0;
+
+ var paramsUsed = 0;
+ var maxParamsAsked = 0;
+
+ /* set parameters array and escaping \ and ; in parameters so the
+ * parameters don't get split up by the command list split later on */
+ e.inputData = e.inputData.replace(/([\\;])/g, "\\$1");
+ var parameters = e.inputData.match(/\S+/g);
+ if (!parameters)
+ parameters = [];
+
+ // replace in the command line.
+ var expr = [SIMPLE_REPLACE, CUMUL_REPLACE, RANGE_REPLACE, NICK_REPLACE,
+ RECIP_REPLACE, ALL_REPLACE].join("|");
+ aliasLine = aliasLine.replace(new RegExp(expr, "gi"), replaceAll);
+
+ if (errorMsg)
+ {
+ switch (errorMsg)
+ {
+ case ALIAS_ERR_REQ_PRMS:
+ display(getMsg(MSG_ERR_REQUIRED_NR_PARAM,
+ [maxParamsAsked - parameters.length,
+ maxParamsAsked]), MT_ERROR);
+ break;
+ case ALIAS_ERR_REQ_SRV:
+ display(getMsg(MSG_ERR_NEED_SERVER, e.command.name),
+ MT_ERROR);
+ break;
+ case ALIAS_ERR_REQ_RECIP:
+ display(getMsg(MSG_ERR_NEED_RECIP, e.command.name),
+ MT_ERROR);
+ break;
+ }
+ return null;
+ }
+
+ // return the revised command line.
+ if (paramsUsed < parameters.length)
+ {
+ var pmstring = parameters.slice(paramsUsed,
+ parameters.length).join(" ");
+ display(getMsg(MSG_EXTRA_PARAMS, pmstring), MT_WARN);
+ }
+ return aliasLine;
+ };
+
+ function callBeforeHooks()
+ {
+ if ("beforeHooks" in client.commandManager)
+ callHooks(client.commandManager, true);
+ if ("beforeHooks" in e.command)
+ callHooks(e.command, true);
+ };
+
+ function callAfterHooks()
+ {
+ if ("afterHooks" in e.command)
+ callHooks(e.command, false);
+ if ("afterHooks" in client.commandManager)
+ callHooks(client.commandManager, false);
+ };
+
+ var h, i;
+
+ if (typeof e.command.func == "function")
+ {
+ /* dispatch a real function */
+
+ client.commandManager.parseArguments(e);
+ if ("parseError" in e)
+ return displayUsageError(e, e.parseError);
+
+ if (("dbgDispatch" in client) && client.dbgDispatch)
+ {
+ var str = "";
+ for (i = 0; i < e.command.argNames.length; ++i)
+ {
+ var name = e.command.argNames[i];
+ if (name in e)
+ str += " " + name + ": " + e[name];
+ else if (name != ":")
+ str += " ?" + name;
+ }
+ dd(">>> " + e.command.name + str + " <<<");
+ }
+
+ callBeforeHooks();
+ try
+ {
+ e.returnValue = e.command.func(e);
+ }
+ finally
+ {
+ callAfterHooks();
+ /* set client.lastEvent *after* dispatching, so the dispatched
+ * function actually get's a chance to see the last event. */
+ if (("dbgDispatch" in client) && client.dbgDispatch)
+ client.lastEvent = e;
+ }
+ }
+ else if (typeof e.command.func == "string")
+ {
+ /* dispatch an alias (semicolon delimited list of subcommands) */
+
+ var commandList;
+ //Don't make use of e.inputData if we have multiple commands in 1 alias
+ if (e.command.func.match(/\$\(.*\)|(?:^|[^\\])(?:\\\\)*;/))
+ commandList = parseAlias(e.command.func, e);
+ else
+ commandList = e.command.func + " " + e.inputData;
+
+ if (commandList == null)
+ return null;
+ commandList = commandList.split(";");
+
+ i = 0;
+ while (i < commandList.length) {
+ if (commandList[i].match(/(?:^|[^\\])(?:\\\\)*$/) ||
+ (i == commandList.length - 1))
+ {
+ commandList[i] = commandList[i].replace(/\\(.)/g, "$1");
+ i++;
+ }
+ else
+ {
+ commandList[i] = commandList[i] + ";" + commandList[i + 1];
+ commandList.splice(i + 1, 1);
+ }
+ }
+
+ callBeforeHooks();
+ try
+ {
+ for (i = 0; i < commandList.length; ++i)
+ {
+ var newEvent = Clone(e);
+ delete newEvent.command;
+ commandList[i] = stringTrim(commandList[i]);
+ dispatch(commandList[i], newEvent, flags);
+ }
+ }
+ finally
+ {
+ callAfterHooks();
+ }
+ }
+ else
+ {
+ display(getMsg(MSG_ERR_NOTIMPLEMENTED, e.command.name), MT_ERROR);
+ return null;
+ }
+
+ return ("returnValue" in e) ? e.returnValue : null;
+}
+
+/* parse function for <plugin> parameters */
+function parsePlugin(e, name)
+{
+ var ary = e.unparsedData.match(/(?:(\S+))(?:\s+(.*))?$/);
+ if (!ary)
+ return false;
+
+ var plugin;
+
+ if (ary[1])
+ {
+ plugin = getPluginById(ary[1]);
+ if (!plugin)
+ return false;
+
+ }
+
+ e.unparsedData = ary[2] || "";
+ e[name] = plugin;
+ return true;
+}
+
+function getToggle (toggle, currentState)
+{
+ if (toggle == "toggle")
+ toggle = !currentState;
+
+ return toggle;
+}
+
+/******************************************************************************
+ * command definitions from here on down.
+ */
+
+function cmdDisablePlugin(e)
+{
+ disablePlugin(e.plugin, false);
+}
+
+function cmdEnablePlugin(e)
+{
+ if (e.plugin.enabled)
+ {
+ display(getMsg(MSG_IS_ENABLED, e.plugin.id));
+ return;
+ }
+
+ if (e.plugin.API > 0)
+ {
+ if (!e.plugin.enable())
+ {
+ display(getMsg(MSG_CANT_ENABLE, e.plugin.id));
+ e.plugin.prefs["enabled"] = false;
+ return;
+ }
+ e.plugin.prefs["enabled"] = true;
+ }
+ else if (!("enablePlugin" in e.plugin.scope))
+ {
+ display(getMsg(MSG_CANT_ENABLE, e.plugin.id));
+ return;
+ }
+ else
+ {
+ e.plugin.scope.enablePlugin();
+ }
+
+ display(getMsg(MSG_PLUGIN_ENABLED, e.plugin.id));
+ e.plugin.enabled = true;
+}
+
+function cmdBanOrExcept(e)
+{
+ var modestr;
+ switch (e.command.name)
+ {
+ case "ban":
+ modestr = "+bbbb";
+ break;
+
+ case "unban":
+ modestr = "-bbbb";
+ break;
+
+ case "except":
+ modestr = "+eeee";
+ break;
+
+ case "unexcept":
+ modestr = "-eeee";
+ break;
+
+ default:
+ ASSERT(0, "Dispatch from unknown name " + e.command.name);
+ return;
+ }
+
+ /* If we're unbanning, or banning in odd cases, we may actually be talking
+ * about a user who is not in the channel, so we need to check the server
+ * for information as well.
+ */
+ if (!e.user && e.nickname)
+ e.user = e.channel.getUser(e.nickname);
+ if (!e.user && e.nickname)
+ e.user = e.server.getUser(e.nickname);
+
+ var masks = new Array();
+
+ if (e.userList)
+ {
+ for (var i = 0; i < e.userList.length; i++)
+ masks.push(fromUnicode(e.userList[i].getBanMask(), e.server));
+ }
+ else if (e.user)
+ {
+ // We have a real user object, so get their proper 'ban mask'.
+ masks = [fromUnicode(e.user.getBanMask(), e.server)];
+ }
+ else if (e.nickname)
+ {
+ /* If we have either ! or @ in the nickname assume the user has given
+ * us a complete mask and pass it directly, otherwise assume it is
+ * only the nickname and use * for username/host.
+ */
+ masks = [fromUnicode(e.nickname, e.server)];
+ if (!/[!@]/.test(e.nickname))
+ masks[0] = masks[0] + "!*@*";
+ }
+ else
+ {
+ // Nothing specified, so we want to list the bans/excepts.
+ masks = [""];
+ }
+
+ // Collapses into groups we can do individually.
+ masks = combineNicks(masks);
+
+ for (var i = 0; i < masks.length; i++)
+ {
+ e.server.sendData("MODE " + e.channel.encodedName + " " +
+ modestr.substr(0, masks[i].count + 1) +
+ " " + masks[i] + "\n");
+ }
+}
+
+function cmdCancel(e)
+{
+ if (e.network && e.network.isRunningList())
+ {
+ // We're running a /list, terminate the output so we return to sanity.
+ display(MSG_CANCELLING_LIST);
+ return e.network.abortList();
+ }
+
+ if (e.network && ((e.network.state == NET_CONNECTING) ||
+ (e.network.state == NET_WAITING)))
+ {
+ // We're trying to connect to a network, and want to cancel. Do so:
+ if (e.deleteWhenDone)
+ e.network.deleteWhenDone = true;
+
+ display(getMsg(MSG_CANCELLING, e.network.unicodeName));
+ return e.network.cancel();
+ }
+
+ // If we're transferring a file, abort it.
+ var source = e.sourceObject;
+ if ((source.TYPE == "IRCDCCFileTransfer") && source.isActive())
+ return source.abort();
+
+ display(MSG_NOTHING_TO_CANCEL, MT_ERROR);
+}
+
+function cmdChanUserMode(e)
+{
+ var modestr;
+ switch (e.command.name)
+ {
+ case "op":
+ modestr = "+oooo";
+ break;
+
+ case "deop":
+ modestr = "-oooo";
+ break;
+
+ case "hop":
+ modestr = "+hhhh";
+ break;
+
+ case "dehop":
+ modestr = "-hhhh";
+ break;
+
+ case "voice":
+ modestr = "+vvvv";
+ break;
+
+ case "devoice":
+ modestr = "-vvvv";
+ break;
+
+ default:
+ ASSERT(0, "Dispatch from unknown name " + e.command.name);
+ return;
+ }
+
+ var nicks;
+ var user;
+ var nickList = new Array();
+ // Prefer pre-canonicalised list, then a * passed to the command directly,
+ // then a normal list, then finally a singular item (canon. or otherwise).
+ if (e.canonNickList)
+ {
+ nicks = combineNicks(e.canonNickList);
+ }
+ else if (e.nickname && (e.nickname == "*"))
+ {
+ var me = e.server.me;
+ var mode = modestr.substr(1, 1);
+ var adding = modestr[0] == "+";
+ for (userKey in e.channel.users)
+ {
+ var user = e.channel.users[userKey];
+ /* Never change our own mode and avoid trying to change someone
+ * else in a no-op manner (e.g. voicing an already voiced user).
+ */
+ if ((user.encodedName != me.encodedName) &&
+ (arrayContains(user.modes, mode) ^ adding))
+ {
+ nickList.push(user.encodedName);
+ }
+ }
+ nicks = combineNicks(nickList);
+ }
+ else if (e.nicknameList)
+ {
+ for (var i = 0; i < e.nicknameList.length; i++)
+ {
+ user = e.channel.getUser(e.nicknameList[i]);
+ if (!user)
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_USER, e.nicknameList[i]), MT_ERROR);
+ return;
+ }
+ nickList.push(user.encodedName);
+ }
+ nicks = combineNicks(nickList);
+ }
+ else if (e.nickname)
+ {
+ user = e.channel.getUser(e.nickname);
+ if (!user)
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_USER, e.nickname), MT_ERROR);
+ return;
+ }
+ var str = new String(user.encodedName);
+ str.count = 1;
+ nicks = [str];
+ }
+ else
+ {
+ // Panic?
+ dd("Help! Channel user mode command with no users...?");
+ }
+
+ for (var i = 0; i < nicks.length; ++i)
+ {
+ e.server.sendData("MODE " + e.channel.encodedName + " " +
+ modestr.substr(0, nicks[i].count + 1) +
+ " " + nicks[i] + "\n");
+ }
+}
+
+function cmdCharset(e)
+{
+ var pm;
+
+ if (e.command.name == "default-charset")
+ {
+ pm = client.prefManager;
+ msg = MSG_CURRENT_CHARSET;
+ }
+ else
+ {
+ pm = e.sourceObject.prefManager;
+ msg = MSG_CURRENT_CHARSET_VIEW;
+ }
+
+ if (e.newCharset)
+ {
+ if (e.newCharset == "-")
+ {
+ pm.clearPref("charset");
+ }
+ else
+ {
+ if(!checkCharset(e.newCharset))
+ {
+ display(getMsg(MSG_ERR_INVALID_CHARSET, e.newCharset),
+ MT_ERROR);
+ return;
+ }
+ pm.prefs["charset"] = e.newCharset;
+ }
+ }
+
+ display(getMsg(msg, pm.prefs["charset"]));
+
+ // If we're on a channel, get the topic again so it can be re-decoded.
+ if (e.newCharset && e.server && e.channel)
+ e.server.sendData("TOPIC " + e.channel.encodedName + "\n");
+}
+
+function cmdCreateTabForView(e)
+{
+ return getTabForObject(e.view, true);
+}
+
+function cmdDelayed(e)
+{
+ function _dispatch()
+ {
+ // Clear inputData so that commands without arguments work properly
+ e.inputData = "";
+ dispatch(e.rest, e, e.isInteractive);
+ }
+ setTimeout(_dispatch, e.delay * 1000);
+}
+
+function cmdSync(e)
+{
+ var fun;
+
+ switch (e.command.name)
+ {
+ case "sync-font":
+ fun = function ()
+ {
+ if (view.prefs["displayHeader"])
+ view.setHeaderState(false);
+ view.changeCSS(view.getFontCSS("data"), "cz-fonts");
+ if (view.prefs["displayHeader"])
+ view.setHeaderState(true);
+ };
+ break;
+
+ case "sync-header":
+ fun = function ()
+ {
+ view.setHeaderState(view.prefs["displayHeader"]);
+ };
+ break;
+
+ case "sync-motif":
+ fun = function ()
+ {
+ view.changeCSS(view.prefs["motif.current"]);
+ updateAppMotif(view.prefs["motif.current"]);
+ // Refresh the motif settings.
+ view.updateMotifSettings();
+ };
+ break;
+
+ case "sync-timestamp":
+ fun = function ()
+ {
+ updateTimestamps(view);
+ };
+ break;
+
+ case "sync-window":
+ fun = function ()
+ {
+ if (window && window.location &&
+ window.location.href != view.prefs["outputWindowURL"])
+ {
+ syncOutputFrame(view);
+ }
+ };
+ break;
+
+ case "sync-log":
+ fun = function ()
+ {
+ if (view.prefs["log"] ^ Boolean(view.logFile))
+ {
+ if (view.prefs["log"])
+ client.openLogFile(view, true);
+ else
+ client.closeLogFile(view, true);
+ updateLoggingIcon();
+ }
+ };
+ break;
+ }
+
+ var view = e.sourceObject;
+ var window;
+ if (("frame" in view) && view.frame)
+ window = getContentWindow(view.frame);
+
+ try
+ {
+ fun();
+ }
+ catch(ex)
+ {
+ dd("Exception in " + e.command.name + " for " + e.sourceObject.unicodeName + ": " + ex);
+ }
+}
+
+function cmdSimpleCommand(e)
+{
+ e.server.sendData(e.command.name + " " + e.inputData + "\n");
+}
+
+function cmdSquery(e)
+{
+ var data;
+
+ if (e.commands)
+ data = "SQUERY " + e.service + " :" + e.commands + "\n";
+ else
+ data = "SQUERY " + e.service + "\n";
+
+ e.server.sendData(data);
+}
+
+function cmdHelp(e)
+{
+ if (!e.pattern)
+ {
+ if ("hello" in e)
+ display(MSG_HELP_INTRO, "HELLO");
+ else
+ display(MSG_HELP_INTRO);
+ return;
+ }
+
+ var ary = client.commandManager.list(e.pattern, CMD_CONSOLE, true);
+
+ if (ary.length == 0)
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_COMMAND, e.pattern), MT_ERROR);
+ return;
+ }
+
+ for (var i in ary)
+ {
+ display(getMsg(MSG_FMT_USAGE, [ary[i].name, ary[i].helpUsage]),
+ MT_USAGE);
+ display(ary[i].help, MT_HELP);
+ }
+
+ return;
+}
+
+function cmdTestDisplay(e)
+{
+ startMsgGroup("testdisplay", MSG_COLLAPSE_TEST);
+ display(MSG_TEST_HELLO, MT_HELLO);
+ display(MSG_TEST_INFO, MT_INFO);
+ display(MSG_TEST_ERROR, MT_ERROR);
+ display(MSG_TEST_HELP, MT_HELP);
+ display(MSG_TEST_USAGE, MT_USAGE);
+ display(MSG_TEST_STATUS, MT_STATUS);
+
+ if (e.server && e.server.me)
+ {
+ var me = e.server.me;
+ var sampleUser = {TYPE: "IRCUser",
+ encodedName: "ircmonkey", collectionKey: ":ircmonkey",
+ unicodeName: "IRCMonkey", viewName: "IRCMonkey",
+ host: "", name: "IRCMonkey"};
+ var sampleChannel = {TYPE: "IRCChannel",
+ encodedName: "#mojo", collectionKey: ":#mojo",
+ unicodeName: "#Mojo", viewName: "#Mojo",
+ name: "#Mojo"};
+
+ function test (from, to)
+ {
+ var fromText = (from != me) ? from.TYPE + " ``" + from.name + "''" :
+ MSG_YOU;
+ var toText = (to != me) ? to.TYPE + " ``" + to.name + "''" :
+ MSG_YOU;
+
+ display (getMsg(MSG_TEST_PRIVMSG, [fromText, toText]),
+ "PRIVMSG", from, to);
+ display (getMsg(MSG_TEST_ACTION, [fromText, toText]),
+ "ACTION", from, to);
+ display (getMsg(MSG_TEST_NOTICE, [fromText, toText]),
+ "NOTICE", from, to);
+ }
+
+ test (sampleUser, me); /* from user to me */
+ test (me, sampleUser); /* me to user */
+
+ display(MSG_TEST_URL, "PRIVMSG", sampleUser, me);
+ display(MSG_TEST_STYLES, "PRIVMSG", sampleUser, me);
+ display(MSG_TEST_EMOTICON, "PRIVMSG", sampleUser, me);
+ display(MSG_TEST_RHEET, "PRIVMSG", sampleUser, me);
+ display(unescape(MSG_TEST_CTLCHR), "PRIVMSG", sampleUser, me);
+ display(unescape(MSG_TEST_COLOR), "PRIVMSG", sampleUser, me);
+ display(MSG_TEST_QUOTE, "PRIVMSG", sampleUser, me);
+
+ if (e.channel)
+ {
+ test (sampleUser, sampleChannel); /* user to channel */
+ test (me, sampleChannel); /* me to channel */
+ display(MSG_TEST_TOPIC, "TOPIC", sampleUser, sampleChannel);
+ display(MSG_TEST_JOIN, "JOIN", sampleUser, sampleChannel);
+ display(MSG_TEST_PART, "PART", sampleUser, sampleChannel);
+ display(MSG_TEST_KICK, "KICK", sampleUser, sampleChannel);
+ display(MSG_TEST_QUIT, "QUIT", sampleUser, sampleChannel);
+ display(getMsg(MSG_TEST_STALK, me.unicodeName),
+ "PRIVMSG", sampleUser, sampleChannel);
+ display(MSG_TEST_STYLES, "PRIVMSG", me, sampleChannel);
+ }
+ }
+ endMsgGroup();
+}
+
+function cmdNetwork(e)
+{
+ let network = client.getNetwork(e.networkName);
+
+ if (!network)
+ {
+ display (getMsg(MSG_ERR_UNKNOWN_NETWORK, e.networkName), MT_ERROR);
+ return;
+ }
+
+ dispatch("create-tab-for-view", { view: network });
+ dispatch("set-current-view", { view: network });
+}
+
+function cmdNetworks(e)
+{
+ var wrapper = newInlineText(MSG_NETWORKS_HEADA);
+
+ var netnames = keys(client.networks).sort();
+
+ for (let i = 0; i < netnames.length; i++)
+ {
+ let net = client.networks[netnames[i]];
+ let hasSecure = networkHasSecure(net.serverList);
+
+ var linkData = {
+ "data": net.unicodeName,
+ "href": (hasSecure ? "ircs://" : "irc://") + net.canonicalName
+ };
+ wrapper.appendChild(newInlineText(linkData, "chatzilla-link", "a"));
+
+ if (i < netnames.length - 1)
+ wrapper.appendChild(document.createTextNode(", "));
+ }
+
+ // Display an "Edit" link.
+ var spanb = document.createElementNS(XHTML_NS, "html:span");
+
+ client.munger.getRule(".inline-buttons").enabled = true;
+ var msg = getMsg(MSG_NETWORKS_HEADB2, "edit-networks");
+ client.munger.munge(msg, spanb, getObjectDetails(client.currentObject));
+ client.munger.getRule(".inline-buttons").enabled = false;
+
+ wrapper.appendChild(spanb);
+ display(wrapper, MT_INFO);
+}
+
+function cmdEditNetworks(e)
+{
+ toOpenWindowByType("irc:chatzilla:networks",
+ "chrome://chatzilla/content/networks-edit.xul",
+ "chrome,resizable,dialog", client);
+}
+
+function cmdServer(e)
+{
+ let scheme = (e.command.name == "sslserver") ? "ircs" : "irc";
+
+ var ary = e.hostname.match(/^(.*):(\d+)$/);
+ if (ary)
+ {
+ // Foolish user obviously hasn't read the instructions, but we're nice.
+ e.password = e.port;
+ e.port = ary[2];
+ e.hostname = ary[1];
+ }
+
+ gotoIRCURL({scheme: scheme, host: e.hostname, port: e.port,
+ pass: e.password, isserver: true});
+}
+
+function cmdSSLException(e)
+{
+ var opts = "chrome,centerscreen,modal";
+ var location = e.hostname ? e.hostname + ':' + e.port : undefined;
+ var args = {location: location, prefetchCert: true};
+
+ window.openDialog("chrome://pippki/content/exceptionDialog.xul",
+ "", opts, args);
+
+ if (!args.exceptionAdded)
+ return;
+
+ if (e.connect)
+ {
+ // When we come via the inline button, we just want to reconnect
+ if (e.source == "mouse")
+ dispatch("reconnect");
+ else
+ dispatch("sslserver " + e.hostname + " " + e.port);
+ }
+}
+
+
+function cmdQuit(e)
+{
+ // if we're not connected to anything, just close the window
+ if (!("getConnectionCount" in client) || (client.getConnectionCount() == 0))
+ {
+ client.userClose = true;
+ window.close();
+ return;
+ }
+
+ // Otherwise, try to close gracefully:
+ client.wantToQuit(e.reason, true);
+}
+
+function cmdDisconnect(e)
+{
+ if ((typeof e.reason != "string") || !e.reason)
+ e.reason = e.network.prefs["defaultQuitMsg"];
+ if (!e.reason)
+ e.reason = client.userAgent;
+
+ e.network.quit(e.reason);
+}
+
+function cmdDisconnectAll(e)
+{
+ var netReason;
+ if (confirmEx(MSG_CONFIRM_DISCONNECT_ALL, ["!yes", "!no"]) != 0)
+ return;
+
+ var conNetworks = client.getConnectedNetworks();
+ if (conNetworks.length <= 0)
+ {
+ display(MSG_NO_CONNECTED_NETS, MT_ERROR);
+ return;
+ }
+
+ for (var i = 0; i < conNetworks.length; i++)
+ {
+ netReason = e.reason;
+ if ((typeof netReason != "string") || !netReason)
+ netReason = conNetworks[i].prefs["defaultQuitMsg"];
+ netReason = (netReason ? netReason : client.userAgent);
+ conNetworks[i].quit(netReason);
+ }
+}
+
+function cmdDeleteView(e)
+{
+ if (!e.view)
+ e.view = e.sourceObject;
+
+ if (("lockView" in e.view) && e.view.lockView)
+ {
+ setTabState(e.view, "attention");
+ return;
+ }
+
+ if (e.view.TYPE == "IRCChannel" && e.view.joined)
+ {
+ e.view.dispatch("part", { deleteWhenDone: true });
+ return;
+ }
+
+ if (e.view.TYPE.substr(0, 6) == "IRCDCC")
+ {
+ if (e.view.isActive())
+ e.view.abort();
+ // abort() calls disconnect() if it is appropriate.
+ // Fall through: we don't delete on disconnect.
+ }
+
+ if (e.view.TYPE == "IRCNetwork" && (e.view.state == NET_CONNECTING ||
+ e.view.state == NET_WAITING))
+ {
+ e.view.dispatch("cancel", { deleteWhenDone: true });
+ return;
+ }
+
+ if (client.viewsArray.length < 2)
+ {
+ display(MSG_ERR_LAST_VIEW, MT_ERROR);
+ return;
+ }
+
+ var tb = getTabForObject(e.view);
+ if (tb)
+ {
+ var i = deleteTab (tb);
+ if (i != -1)
+ {
+ if (e.view.logFile)
+ {
+ e.view.logFile.close();
+ e.view.logFile = null;
+ }
+ delete e.view.messageCount;
+ delete e.view.messages;
+ deleteFrame(e.view);
+
+ var oldView = client.currentObject;
+ if (client.currentObject == e.view)
+ {
+ if (i >= client.viewsArray.length)
+ i = client.viewsArray.length - 1;
+ oldView = client.viewsArray[i].source
+ }
+ client.currentObject = null;
+ oldView.dispatch("set-current-view", { view: oldView });
+ }
+ }
+}
+
+function cmdHideView(e)
+{
+ if (!e.view)
+ e.view = e.sourceObject;
+
+ if (client.viewsArray.length < 2)
+ {
+ display(MSG_ERR_LAST_VIEW_HIDE, MT_ERROR);
+ return;
+ }
+
+ if ("messages" in e.view)
+ {
+ // Detach messages from output window content.
+ if (e.view.messages.parentNode)
+ e.view.messages.parentNode.removeChild(e.view.messages);
+
+ /* XXX Bug 335998: Adopt the messages into our own internal document
+ * so that when the real one the messages were in gets incorrectly
+ * GC-collected (see bug) the nodes still have an ownerDocument.
+ */
+ client.adoptNode(e.view.messages, client.hiddenDocument);
+ }
+
+ var tb = getTabForObject(e.view);
+
+ if (tb)
+ {
+ var i = deleteTab (tb);
+ if (i != -1)
+ {
+ deleteFrame(e.view);
+
+ var oldView = client.currentObject;
+ if (client.currentObject == e.view)
+ {
+ if (i >= client.viewsArray.length)
+ i = client.viewsArray.length - 1;
+ oldView = client.viewsArray[i].source
+ }
+ client.currentObject = null;
+ oldView.dispatch("set-current-view", { view: oldView });
+ }
+ }
+}
+
+function cmdClearView(e)
+{
+ if (!e.view)
+ e.view = e.sourceObject;
+
+ e.view.messages = null;
+ e.view.messageCount = 0;
+
+ e.view.displayHere(MSG_MESSAGES_CLEARED);
+
+ syncOutputFrame(e.view);
+}
+
+function cmdDesc(e)
+{
+ if (e.network != null) // somewhere on a network
+ {
+ dispatch("network-pref", {prefValue: e.description, prefName: "desc",
+ network: e.network,
+ isInteractive: e.isInteractive});
+ }
+ else // no network, change the general pref
+ {
+ dispatch("pref", {prefName: "desc", prefValue: e.description,
+ isInteractive: e.isInteractive});
+ }
+}
+
+function cmdName(e)
+{
+ if (e.network != null) // somewhere on a network
+ {
+ dispatch("network-pref", {prefName: "username", prefValue: e.username,
+ network: e.network,
+ isInteractive: e.isInteractive});
+ }
+ else // no network, change the general pref
+ {
+ dispatch("pref", {prefName: "username", prefValue: e.username,
+ isInteractive: e.isInteractive});
+ }
+}
+
+function cmdNames(e)
+{
+ if (e.hasOwnProperty("channelName"))
+ {
+ e.channel = new CIRCChannel(e.server, e.channelName);
+ }
+ else
+ {
+ if (!e.channel)
+ {
+ display(getMsg(MSG_ERR_REQUIRED_PARAM, "channel-name"), MT_ERROR);
+ return;
+ }
+ }
+
+ e.channel.pendingNamesReply = true;
+ e.server.sendData("NAMES " + e.channel.encodedName + "\n");
+}
+
+function cmdReconnect(e)
+{
+ if (e.network.isConnected())
+ {
+ // Set reconnect flag
+ e.network.reconnect = true;
+ if (typeof e.reason != "string")
+ e.reason = MSG_RECONNECTING;
+ // Now we disconnect.
+ e.network.quit(e.reason);
+ }
+ else
+ {
+ e.network.connect(e.network.requireSecurity);
+ }
+}
+
+function cmdReconnectAll(e)
+{
+ var reconnected = false;
+ for (var net in client.networks)
+ {
+ if (client.networks[net].isConnected() ||
+ ("messages" in client.networks[net]))
+ {
+ client.networks[net].dispatch("reconnect", { reason: e.reason });
+ reconnected = true;
+ }
+ }
+ if (!reconnected)
+ display(MSG_NO_RECONNECTABLE_NETS, MT_ERROR);
+}
+
+function cmdRejoin(e)
+{
+ if (e.channel.joined)
+ {
+ if (!e.reason)
+ e.reason = "";
+ e.channel.dispatch("part", { reason: e.reason, deleteWhenDone: false });
+ }
+
+ e.channel.join(e.channel.mode.key);
+}
+
+function cmdRename(e)
+{
+ var tab = getTabForObject(e.sourceObject);
+ if (!tab)
+ {
+ feedback(e, getMsg(MSG_ERR_INTERNAL_DISPATCH, "rename"));
+ return;
+ }
+ var label = e.label || prompt(MSG_TAB_NAME_PROMPT, tab.label);
+ if (!label)
+ {
+ return;
+ }
+ e.sourceObject.prefs["tabLabel"] = label;
+}
+
+
+function cmdTogglePref (e)
+{
+ var state = !client.prefs[e.prefName];
+ client.prefs[e.prefName] = state;
+ feedback(e, getMsg (MSG_FMT_PREF,
+ [e.prefName, state ? MSG_VAL_ON : MSG_VAL_OFF]));
+}
+
+function cmdToggleGroup(e)
+{
+ var document = getContentDocument(e.sourceObject.frame);
+ var msgs = document.querySelectorAll("[msg-groups*=\"" + e.groupId + "\"]");
+ if (!msgs.length)
+ return;
+
+ var isHidden = (msgs[0].style.display == "none");
+ for (i = 0; i < msgs.length; i++)
+ {
+ if (isHidden)
+ msgs[i].style.display = "";
+ else
+ msgs[i].style.display = "none";
+ }
+
+ var els = msgs[0].previousSibling.querySelectorAll(".chatzilla-link");
+ var button = els[els.length - 1];
+ if (button.text == MSG_COLLAPSE_HIDE)
+ {
+ button.text = MSG_COLLAPSE_SHOW;
+ button.title = MSG_COLLAPSE_SHOWTITLE;
+ }
+ else
+ {
+ button.text = MSG_COLLAPSE_HIDE;
+ button.title = MSG_COLLAPSE_HIDETITLE;
+ }
+}
+
+function cmdToggleUI(e)
+{
+ var ids = new Array();
+
+ switch (e.thing)
+ {
+ case "tabstrip":
+ ids = ["view-tabs"];
+ break;
+
+ case "userlist":
+ ids = ["main-splitter", "user-list-box"];
+ break;
+
+ case "header":
+ client.currentObject.prefs["displayHeader"] =
+ !client.currentObject.prefs["displayHeader"];
+ return;
+
+ case "status":
+ ids = ["status-bar"];
+ break;
+
+ default:
+ ASSERT (0,"Unknown element ``" + e.thing +
+ "'' passed to onToggleVisibility.");
+ return;
+ }
+
+ var newState;
+ var elem = document.getElementById(ids[0]);
+ var sourceObject = e.sourceObject;
+ var newState = !elem.collapsed;
+
+ for (var i in ids)
+ {
+ elem = document.getElementById(ids[i]);
+ elem.collapsed = newState;
+ }
+
+ updateTitle();
+ dispatch("focus-input");
+}
+
+function cmdCommands(e)
+{
+ display(MSG_COMMANDS_HEADER);
+
+ var matchResult = client.commandManager.listNames(e.pattern, CMD_CONSOLE);
+ matchResult = matchResult.join(", ");
+
+ if (e.pattern)
+ display(getMsg(MSG_MATCHING_COMMANDS, [e.pattern, matchResult]));
+ else
+ display(getMsg(MSG_ALL_COMMANDS, matchResult));
+}
+
+function cmdAttach(e)
+{
+ if (e.ircUrl.search(/ircs?:\/\//i) != 0)
+ e.ircUrl = "irc://" + e.ircUrl;
+
+ var parsedURL = parseIRCURL(e.ircUrl);
+ if (!parsedURL)
+ {
+ display(getMsg(MSG_ERR_BAD_IRCURL, e.ircUrl), MT_ERROR);
+ return;
+ }
+
+ gotoIRCURL(e.ircUrl);
+}
+
+function cmdMatchUsers(e)
+{
+ var matches = e.channel.findUsers(e.mask);
+ var uc = matches.unchecked;
+ var msgNotChecked = "";
+
+ // Get a pretty list of nicknames:
+ var nicknames = [];
+ for (var i = 0; i < matches.users.length; i++)
+ nicknames.push(matches.users[i].unicodeName);
+
+ var nicknameStr = arraySpeak(nicknames);
+
+ // Were we unable to check one or more of the users?
+ if (uc != 0)
+ msgNotChecked = getMsg(MSG_MATCH_UNCHECKED, uc);
+
+ if (matches.users.length == 0)
+ display(getMsg(MSG_NO_MATCHING_NICKS, msgNotChecked));
+ else
+ display(getMsg(MSG_MATCHING_NICKS, [nicknameStr, msgNotChecked]));
+}
+
+function cmdMe(e)
+{
+ if (!("act" in e.sourceObject))
+ {
+ display(getMsg(MSG_ERR_IMPROPER_VIEW, "me"), MT_ERROR);
+ return;
+ }
+ _sendMsgTo(e.action, "ACTION", e.sourceObject);
+}
+
+function cmdDescribe(e)
+{
+ var target = e.server.addTarget(e.target);
+ _sendMsgTo(e.action, "ACTION", target, e.sourceObject);
+}
+
+function cmdMode(e)
+{
+ var chan;
+
+ // Make sure the user can leave the channel name out from a channel view.
+ if ((!e.target || /^[\+\-].+/.test(e.target)) &&
+ !(chan && e.server.getChannel(chan)))
+ {
+ if (e.channel)
+ {
+ chan = e.channel.canonicalName;
+ if (e.param && e.modestr)
+ {
+ e.paramList.unshift(e.modestr);
+ }
+ else if (e.modestr)
+ {
+ e.paramList = [e.modestr];
+ e.param = e.modestr;
+ }
+ e.modestr = e.target;
+ }
+ else
+ {
+ display(getMsg(MSG_ERR_REQUIRED_PARAM, "target"), MT_ERROR);
+ return;
+ }
+ }
+ else
+ {
+ chan = fromUnicode(e.target, e.server);
+ }
+
+ // Check whether our mode string makes sense
+ if (!e.modestr)
+ {
+ e.modestr = "";
+ if (!e.channel && arrayContains(e.server.channelTypes, chan[0]))
+ e.channel = new CIRCChannel(e.server, null, chan);
+ if (e.channel)
+ e.channel.pendingModeReply = true;
+ }
+ else if (!(/^([+-][a-z]+)+$/i).test(e.modestr))
+ {
+ display(getMsg(MSG_ERR_INVALID_MODE, e.modestr), MT_ERROR);
+ return;
+ }
+
+ var params = (e.param) ? " " + e.paramList.join(" ") : "";
+ e.server.sendData("MODE " + chan + " " + fromUnicode(e.modestr, e.server) +
+ params + "\n");
+}
+
+function cmdMotif(e)
+{
+ var pm;
+ var msg;
+
+ if (e.command.name == "channel-motif")
+ {
+ pm = e.channel.prefManager;
+ msg = MSG_CURRENT_CSS_CHAN;
+ }
+ else if (e.command.name == "network-motif")
+ {
+ pm = e.network.prefManager;
+ msg = MSG_CURRENT_CSS_NET;
+ }
+ else if (e.command.name == "user-motif")
+ {
+ pm = e.user.prefManager;
+ msg = MSG_CURRENT_CSS_USER;
+ }
+ else
+ {
+ pm = client.prefManager;
+ msg = MSG_CURRENT_CSS;
+ }
+
+ if (e.motif)
+ {
+ if (e.motif == "-")
+ {
+ // delete local motif in favor of default
+ pm.clearPref("motif.current");
+ e.motif = pm.prefs["motif.current"];
+ }
+ else if (e.motif.search(/^(file|https?|ftp):/i) != -1)
+ {
+ // specific css file
+ pm.prefs["motif.current"] = e.motif;
+ }
+ else
+ {
+ // motif alias
+ var prefName = "motif." + e.motif;
+ if (client.prefManager.isKnownPref(prefName))
+ {
+ e.motif = client.prefManager.prefs[prefName];
+ }
+ else
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_MOTIF, e.motif), MT_ERROR);
+ return;
+ }
+
+ pm.prefs["motif.current"] = e.motif;
+ }
+
+ }
+
+ display (getMsg(msg, pm.prefs["motif.current"]));
+}
+
+function cmdList(e)
+{
+ if (!e.channelName)
+ {
+ e.channelName = "";
+ var c = e.server.channelCount;
+ if ((c > client.SAFE_LIST_COUNT) && !("listWarned" in e.network))
+ {
+ client.munger.getRule(".inline-buttons").enabled = true;
+ display(getMsg(MSG_LIST_CHANCOUNT, [c, "list"]), MT_WARN);
+ client.munger.getRule(".inline-buttons").enabled = false;
+ e.network.listWarned = true;
+ return;
+ }
+ }
+
+ e.network.list(e.channelName);
+}
+
+function cmdListPlugins(e)
+{
+ function listPlugin(plugin, i)
+ {
+ var enabled;
+ if ((plugin.API > 0) || ("disablePlugin" in plugin.scope))
+ enabled = plugin.enabled;
+ else
+ enabled = MSG_ALWAYS;
+
+ display(getMsg(MSG_FMT_PLUGIN1, [i, plugin.url]));
+ display(getMsg(MSG_FMT_PLUGIN2,
+ [plugin.id, plugin.version, enabled, plugin.status]));
+ display(getMsg(MSG_FMT_PLUGIN3, plugin.description));
+ }
+
+ if (e.plugin)
+ {
+ listPlugin(e.plugin, 0);
+ return;
+ }
+
+ var i = 0;
+ for (var k in client.plugins)
+ listPlugin(client.plugins[k], i++);
+
+ if (i == 0)
+ display(MSG_NO_PLUGINS);
+}
+
+function cmdRlist(e)
+{
+ try
+ {
+ var re = new RegExp(e.regexp, "i");
+ }
+ catch (ex)
+ {
+ display(MSG_ERR_INVALID_REGEX, MT_ERROR);
+ return;
+ }
+
+ var c = e.server.channelCount;
+ if ((c > client.SAFE_LIST_COUNT) && !("listWarned" in e.network))
+ {
+ client.munger.getRule(".inline-buttons").enabled = true;
+ display(getMsg(MSG_LIST_CHANCOUNT, [c, "rlist " + e.regexp]), MT_WARN);
+ client.munger.getRule(".inline-buttons").enabled = false;
+ e.network.listWarned = true;
+ return;
+ }
+ e.network.list(re);
+}
+
+function cmdReloadUI(e)
+{
+ if (!("getConnectionCount" in client) ||
+ client.getConnectionCount() == 0)
+ {
+ window.location.href = window.location.href;
+ }
+}
+
+function cmdQuery(e)
+{
+ // We'd rather *not* trigger the user.start event this time.
+ blockEventSounds("user", "start");
+ var user = openQueryTab(e.server, e.nickname);
+ dispatch("set-current-view", { view: user });
+
+ if (e.message)
+ _sendMsgTo(e.message, "PRIVMSG", user);
+
+ return user;
+}
+
+function cmdSay(e)
+{
+ if (!("say" in e.sourceObject))
+ {
+ display(getMsg(MSG_ERR_IMPROPER_VIEW, "say"), MT_ERROR);
+ return;
+ }
+
+ _sendMsgTo(e.message, "PRIVMSG", e.sourceObject)
+}
+
+function cmdMsg(e)
+{
+ var target = e.server.addTarget(e.nickname);
+ _sendMsgTo(e.message, "PRIVMSG", target, e.sourceObject);
+}
+
+function _sendMsgTo(message, msgType, target, displayObj)
+{
+ if (!displayObj)
+ displayObj = target;
+
+
+ var msg = filterOutput(message, msgType, target);
+
+ var o = getObjectDetails(target);
+ var lines = o.server ? o.server.splitLinesForSending(msg, true) : [msg];
+
+ for (var i = 0; i < lines.length; i++)
+ {
+ msg = lines[i];
+ if (!(o.server && o.server.caps["echo-message"]))
+ {
+ client.munger.getRule(".mailto").enabled = client.prefs["munger.mailto"];
+ displayObj.display(msg, msgType, "ME!", target);
+ client.munger.getRule(".mailto").enabled = false;
+ }
+ if (msgType == "PRIVMSG")
+ target.say(msg);
+ else if (msgType == "NOTICE")
+ target.notice(msg);
+ else if (msgType == "ACTION")
+ target.act(msg);
+ }
+}
+
+function cmdNick(e)
+{
+ if (!e.nickname)
+ {
+ var curNick;
+ if (e.server && e.server.isConnected)
+ curNick = e.server.me.unicodeName;
+ else if (e.network)
+ curNick = e.network.prefs["nickname"];
+ else
+ curNick = client.prefs["nickname"];
+
+ e.nickname = prompt(MSG_NICK_PROMPT, curNick);
+ if (e.nickname == null)
+ return;
+ e.nickname = e.nickname.replace(/ /g, "_");
+ }
+
+ if (e.server && e.server.isConnected)
+ e.server.changeNick(e.nickname);
+
+ if (e.network)
+ {
+ /* We want to save in all non-online cases, including NET_CONNECTING,
+ * as we will only get a NICK reply if we are completely connected.
+ */
+ if (e.network.state == NET_ONLINE)
+ {
+ e.network.pendingNickChange = e.nickname;
+ }
+ else
+ {
+ e.network.prefs["nickname"] = e.nickname;
+ e.network.preferredNick = e.nickname;
+ }
+ }
+ else
+ {
+ client.prefs["nickname"] = e.nickname;
+ updateTitle(client);
+ }
+}
+
+function cmdNotice(e)
+{
+ var target = e.server.addTarget(e.nickname);
+ _sendMsgTo(e.message, "NOTICE", target, e.sourceObject);
+}
+
+function cmdQuote(e)
+{
+ /* Check we are connected, or at least pretending to be connected, so this
+ * can actually send something. The only thing that's allowed to send
+ * before the 001 is PASS, so if the command is not that and the net is not
+ * online, we stop too.
+ */
+ if ((e.network.state != NET_ONLINE) &&
+ (!e.server.isConnected || !e.ircCommand.match(/^\s*PASS/i)))
+ {
+ feedback(e, MSG_ERR_NOT_CONNECTED);
+ return;
+ }
+ e.server.sendData(fromUnicode(e.ircCommand) + "\n", e.sourceObject);
+}
+
+function cmdEval(e)
+{
+ var sourceObject = e.sourceObject;
+
+ try
+ {
+ sourceObject.doEval = function (__s) { return eval(__s); }
+ if (e.command.name == "eval")
+ sourceObject.display(e.expression, MT_EVALIN);
+ var rv = String(sourceObject.doEval (e.expression));
+ if (e.command.name == "eval")
+ sourceObject.display(rv, MT_EVALOUT);
+
+ }
+ catch (ex)
+ {
+ sourceObject.display(String(ex), MT_ERROR);
+ }
+}
+
+function cmdFocusInput(e)
+{
+ const WWATCHER_CTRID = "@mozilla.org/embedcomp/window-watcher;1";
+ const nsIWindowWatcher = Components.interfaces.nsIWindowWatcher;
+
+ var watcher =
+ Components.classes[WWATCHER_CTRID].getService(nsIWindowWatcher);
+ if (watcher.activeWindow == window)
+ client.input.focus();
+ else
+ document.commandDispatcher.focusedElement = client.input;
+}
+
+function cmdGotoStartup(e)
+{
+ openStartupURLs();
+}
+
+function cmdGotoURL(e)
+{
+ if (/^ircs?:/.test(e.url))
+ {
+ gotoIRCURL(e.url);
+ return;
+ }
+
+ if (/^x-irc-dcc-(chat|file):[0-9a-fA-F]+$/.test(e.url))
+ {
+ var view = client.dcc.findByID(e.url.substr(15));
+ if (view)
+ dispatch("set-current-view", {view: view});
+ return;
+ }
+
+ if (/^x-cz-command:/.test(e.url))
+ {
+ var ary = e.url.match(/^x-cz-command:(.*)$/i);
+ e.sourceObject.dispatch(decodeURI(ary[1]),
+ {isInteractive: true, source: e.source});
+ return;
+ }
+
+ try
+ {
+ var uri = Services.io.newURI(e.url, "UTF-8");
+ }
+ catch (ex)
+ {
+ // Given "goto-url faq bar", expand to "http://.../faq/#bar"
+ var localeURLKey = "msg.localeurl." + e.url;
+ var hash = (("anchor" in e) && e.anchor) ? "#" + e.anchor : "";
+ if (localeURLKey != getMsg(localeURLKey))
+ dispatch(e.command.name + " " + getMsg(localeURLKey) + hash);
+ else
+ display(getMsg(MSG_ERR_INVALID_URL, e.url), MT_ERROR);
+
+ dispatch("focus-input");
+ return;
+ }
+
+ var browserWin = getWindowByType("navigator:browser");
+ var location = browserWin ? browserWin.gBrowser.currentURI.spec : null;
+ var action = e.command.name;
+ let where = "current";
+
+ // We don't want to replace ChatZilla running in a tab.
+ if ((action == "goto-url-newwin") ||
+ ((action == "goto-url") && location &&
+ location.startsWith("chrome://chatzilla/content/")))
+ {
+ where = "window";
+ }
+
+ if (action == "goto-url-newtab")
+ {
+ where = e.shiftKey ? "tabshifted" : "tab";
+ }
+
+ try
+ {
+ let loadInBackground =
+ Services.prefs.getBoolPref("browser.tabs.loadDivertedInBackground");
+ openLinkIn(e.url, where, { inBackground: loadInBackground });
+ }
+ catch (ex)
+ {
+ dd(formatException(ex));
+ }
+ dispatch("focus-input");
+}
+
+function cmdCTCP(e)
+{
+ var obj = e.server.addTarget(e.target);
+ obj.ctcp(e.code, e.params);
+}
+
+function cmdJoin(e)
+{
+ /* This check makes sure we only check if the *user* entered anything, and
+ * ignore any contextual information, like the channel the command was
+ * run on.
+ */
+ if ((!e.hasOwnProperty("channelName") || !e.channelName) &&
+ !e.channelToJoin)
+ {
+ if (client.joinDialog)
+ {
+ client.joinDialog.setNetwork(e.network);
+ client.joinDialog.focus();
+ return;
+ }
+
+ window.openDialog("chrome://chatzilla/content/channels.xul", "",
+ "resizable=yes",
+ { client: client, network: e.network || null,
+ opener: window });
+ return null;
+ }
+
+ var chan;
+ if (!e.channelToJoin)
+ {
+ if (!("charset" in e))
+ {
+ e.charset = null;
+ }
+ else if (e.charset && !checkCharset(e.charset))
+ {
+ display (getMsg(MSG_ERR_INVALID_CHARSET, e.charset), MT_ERROR);
+ return null;
+ }
+
+ if (e.channelName.search(",") != -1)
+ {
+ // We can join multiple channels! Woo!
+ var chans = e.channelName.split(",");
+ var keys = [];
+ if (e.key)
+ keys = e.key.split(",");
+ for (var c in chans)
+ {
+ chan = dispatch("join", { network: e.network,
+ server: e.server,
+ charset: e.charset,
+ channelName: chans[c],
+ key: keys.shift() });
+ }
+ return chan;
+ }
+
+ if ((arrayIndexOf(["#", "&", "+", "!"], e.channelName[0]) == -1) &&
+ (arrayIndexOf(e.server.channelTypes, e.channelName[0]) == -1))
+ {
+ e.channelName = e.server.channelTypes[0] + e.channelName;
+ }
+
+ var charset = e.charset ? e.charset : e.network.prefs["charset"];
+ chan = e.server.addChannel(e.channelName, charset);
+ if (e.charset)
+ chan.prefs["charset"] = e.charset;
+ }
+ else
+ {
+ chan = e.channelToJoin;
+ }
+
+ e.key = client.tryToGetLogin(chan.getURL(), "chan", "*", e.key, false, "");
+ chan.join(e.key);
+
+ /* !-channels are "safe" channels, and get a server-generated prefix. For
+ * this reason, we shouldn't do anything client-side until the server
+ * replies (since the reply will have the appropriate prefix). */
+ if (chan.unicodeName[0] != "!")
+ {
+ dispatch("create-tab-for-view", { view: chan });
+ dispatch("set-current-view", { view: chan });
+ }
+
+ return chan;
+}
+
+function cmdLeave(e)
+{
+ function leaveChannel(channelName)
+ {
+ var channelToLeave;
+ // This function will return true if we should continue processing
+ // channel names. If we discover that we were passed an invalid channel
+ // name, but have a channel on the event, we'll just leave that channel
+ // with the full message (including what we thought was a channel name)
+ // and return false in order to not process the rest of what we thought
+ // was a channel name. If there's a genuine error, e.g. because the user
+ // specified a non-existing channel and isn't in a channel either, we
+ // will also return a falsy value
+ var shouldContinue = true;
+ if (arrayIndexOf(e.server.channelTypes, channelName[0]) == -1)
+ {
+ // No valid prefix character. Check they really meant a channel...
+ var valid = false;
+ for (var i = 0; i < e.server.channelTypes.length; i++)
+ {
+ // Hmm, not ideal...
+ var chan = e.server.getChannel(e.server.channelTypes[i] +
+ channelName);
+ if (chan)
+ {
+ // Yes! They just missed that single character.
+ channelToLeave = chan;
+ valid = true;
+ break;
+ }
+ }
+
+ // We can only let them get away here if we've got a channel.
+ if (!valid)
+ {
+ if (e.channel)
+ {
+ /* Their channel name was invalid, but we have a channel
+ * view, so we'll assume they did "/leave part msg".
+ * NB: we use e.channelName here to get the full channel
+ * name before we (may have) split it.
+ */
+ e.reason = e.channelName + (e.reason ? " " + e.reason : "");
+ channelToLeave = e.channel;
+ shouldContinue = false;
+ }
+ else
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_CHANNEL, channelName),
+ MT_ERROR);
+ return;
+ }
+ }
+ }
+ else
+ {
+ // Valid prefix, so get real channel (if it exists...).
+ channelToLeave = e.server.getChannel(channelName);
+ if (!channelToLeave)
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_CHANNEL, channelName),
+ MT_ERROR);
+ return;
+ }
+ }
+
+ if (!("deleteWhenDone" in e))
+ e.deleteWhenDone = client.prefs["deleteOnPart"];
+
+ /* If it's not active, we're not actually in it, even though the view is
+ * still here.
+ */
+ if (channelToLeave.active)
+ {
+ channelToLeave.deleteWhenDone = e.deleteWhenDone;
+
+ if (!e.reason)
+ e.reason = "";
+
+ e.server.sendData("PART " + channelToLeave.encodedName + " :" +
+ fromUnicode(e.reason, channelToLeave) + "\n");
+ }
+ else
+ {
+ /* We can leave the channel when not active
+ * this will close the view and prevent rejoin after a reconnect
+ */
+ if (channelToLeave.joined)
+ channelToLeave.joined = false;
+
+ if (e.deleteWhenDone)
+ channelToLeave.dispatch("delete-view");
+ }
+
+ return shouldContinue;
+ };
+
+ if (!e.server)
+ {
+ display(getMsg(MSG_ERR_IMPROPER_VIEW, e.command.name), MT_ERROR);
+ return;
+ }
+
+ if (!e.hasOwnProperty("channelName") && e.channel)
+ e.channelName = e.channel.unicodeName;
+
+ if (e.hasOwnProperty("channelName"))
+ {
+ if (!e.channelName)
+ {
+ // No channel specified and command not sent from a channel view
+ display(getMsg(MSG_ERR_NEED_CHANNEL, e.command.name), MT_ERROR);
+ return;
+ }
+
+
+ var channels = e.channelName.split(",");
+ for (var i = 0; i < channels.length; i++)
+ {
+ // Skip empty channel names:
+ if (!channels[i])
+ continue;
+
+ // If we didn't successfully leave, stop processing the
+ // rest of the channels:
+ if (!leaveChannel(channels[i]))
+ break;
+ }
+ }
+}
+
+function cmdMarker(e)
+{
+ if (!client.initialized)
+ return;
+
+ var view = e.sourceObject;
+ if (!("setActivityMarker" in e.sourceObject))
+ return;
+
+ var marker = e.sourceObject.getActivityMarker();
+ if ((e.command.name == "marker") && (marker == null))
+ {
+ // Marker is not currently set but user wants to scroll to it,
+ // so we just call set like normal.
+ e.command.name = "marker-set";
+ }
+
+ switch(e.command.name)
+ {
+ case "marker": /* Scroll to the marker. */
+ e.sourceObject.scrollToElement("marker", "center");
+ break;
+ case "marker-set": /* Set (or reset) the marker. */
+ e.sourceObject.setActivityMarker(true);
+ e.sourceObject.scrollToElement("marker", "center");
+ break;
+ case "marker-clear": /* Clear the marker. */
+ e.sourceObject.setActivityMarker(false);
+ break;
+ default:
+ view.display(MSG_ERR_UNKNOWN_COMMAND, e.command.name);
+ }
+}
+
+function cmdReload(e)
+{
+ dispatch("load " + e.plugin.url);
+}
+
+function cmdLoad(e)
+{
+ if (!e.scope)
+ e.scope = new Object();
+
+ if (!("plugin" in e.scope))
+ {
+ e.scope.plugin = { url: e.url, id: MSG_UNKNOWN, version: -1,
+ description: "", status: MSG_LOADING, enabled: false,
+ PluginAPI: 1, cwd: e.url.match(/^(.*?)[^\/]+$/)[1]};
+
+ }
+
+ var plugin = e.scope.plugin;
+ plugin.scope = e.scope;
+
+ try
+ {
+ var rvStr;
+ var rv = rvStr = client.load(e.url, e.scope);
+ let oldPlugin = getPluginByURL(e.url);
+ if (oldPlugin && !disablePlugin(oldPlugin, true))
+ {
+ display(getMsg(MSG_ERR_SCRIPTLOAD, e.url));
+ return null;
+ }
+
+ if ("init" in plugin)
+ {
+ // Sanity check plugin's methods and properties:
+ var okay = false;
+ if (!("id" in plugin) || (plugin.id == MSG_UNKNOWN))
+ display(getMsg(MSG_ERR_PLUGINAPI_NOID, e.url));
+ else if (!(plugin.id.match(/^[A-Za-z0-9-_]+$/)))
+ display(getMsg(MSG_ERR_PLUGINAPI_FAULTYID, e.url));
+ else if (!("enable" in plugin))
+ display(getMsg(MSG_ERR_PLUGINAPI_NOENABLE, e.url));
+ else if (!("disable" in plugin))
+ display(getMsg(MSG_ERR_PLUGINAPI_NODISABLE, e.url));
+ else
+ okay = true;
+
+ if (!okay)
+ {
+ display (getMsg(MSG_ERR_SCRIPTLOAD, e.url));
+ return null;
+ }
+
+ plugin.API = 1;
+ plugin.prefary = [["enabled", true, "hidden"]];
+ rv = rvStr = plugin.init(e.scope);
+
+ var branch = "extensions.irc.plugins." + plugin.id + ".";
+ var prefManager = new PrefManager(branch, client.defaultBundle);
+ prefManager.addPrefs(plugin.prefary);
+ plugin.prefManager = prefManager;
+ plugin.prefs = prefManager.prefs;
+ if ("onPrefChanged" in plugin)
+ prefManager.addObserver(plugin);
+ client.prefManager.addObserver(prefManager);
+ client.prefManagers.push(prefManager);
+ }
+ else
+ {
+ plugin.API = 0;
+ if ("initPlugin" in e.scope)
+ rv = rvStr = e.scope.initPlugin(e.scope);
+ plugin.enabled = true;
+ }
+ plugin.status = "loaded";
+
+ if (typeof rv == "function")
+ rvStr = "function";
+
+ if (!plugin.id)
+ plugin.id = 'plugin' + randomString(8);
+
+ client.plugins[plugin.id] = plugin;
+
+ feedback(e, getMsg(MSG_SUBSCRIPT_LOADED, [e.url, rvStr]), MT_INFO);
+
+ if ((plugin.API > 0) && plugin.prefs["enabled"])
+ dispatch("enable-plugin " + plugin.id);
+ return {rv: rv};
+ }
+ catch (ex)
+ {
+ display (getMsg(MSG_ERR_SCRIPTLOAD, e.url));
+ display (formatException(ex), MT_ERROR);
+ }
+
+ return null;
+}
+
+function cmdWho(e)
+{
+ e.network.pendingWhoReply = true;
+ e.server.LIGHTWEIGHT_WHO = false;
+ e.server.who(e.rest);
+}
+
+function cmdWhoIs(e)
+{
+ if (!isinstance(e.network.whoisList, Object))
+ e.network.whoisList = {};
+
+ for (var i = 0; i < e.nicknameList.length; i++)
+ {
+ if ((i < e.nicknameList.length - 1) &&
+ (e.server.toLowerCase(e.nicknameList[i]) ==
+ e.server.toLowerCase(e.nicknameList[i + 1])))
+ {
+ e.server.whois(e.nicknameList[i] + " " + e.nicknameList[i]);
+ i++;
+ }
+ else
+ {
+ e.server.whois(e.nicknameList[i]);
+ }
+ e.network.whoisList[e.server.toLowerCase(e.nicknameList[i])] = null;
+ }
+}
+
+function cmdWhoIsIdle(e)
+{
+ for (var i = 0; i < e.nicknameList.length; i++)
+ e.server.whois(e.nicknameList[i] + " " + e.nicknameList[i]);
+}
+
+function cmdWhoWas(e)
+{
+ e.server.whowas(e.nickname, e.limit);
+}
+
+function cmdTopic(e)
+{
+ if (!e.newTopic)
+ e.server.sendData("TOPIC " + e.channel.encodedName + "\n");
+ else
+ e.channel.setTopic(e.newTopic);
+}
+
+function cmdAbout(e)
+{
+ if (e.source)
+ {
+ if ("aboutDialog" in client)
+ return client.aboutDialog.focus();
+
+ window.openDialog("chrome://chatzilla/content/about/about.xul", "",
+ "chrome,dialog", { client: client });
+ }
+ else
+ {
+ var ver = CIRCServer.prototype.VERSION_RPLY;
+ client.munger.getRule(".inline-buttons").enabled = true;
+ display(getMsg(MSG_ABOUT_VERSION, [ver, "about"]));
+ display(MSG_ABOUT_HOMEPAGE);
+ client.munger.getRule(".inline-buttons").enabled = false;
+ }
+}
+
+function cmdAlias(e)
+{
+ var aliasDefs = client.prefs["aliases"];
+ function getAlias(commandName)
+ {
+ for (var i = 0; i < aliasDefs.length; ++i)
+ {
+ var ary = aliasDefs[i].match(/^(.*?)\s*=\s*(.*)$/);
+ if (ary[1] == commandName)
+ return [i, ary[2]];
+ }
+
+ return null;
+ };
+
+ var ary;
+
+ if ((e.commandList == "-") || (e.command.name == "unalias"))
+ {
+ /* remove alias */
+ ary = getAlias(e.aliasName);
+ if (!ary)
+ {
+ display(getMsg(MSG_NOT_AN_ALIAS, e.aliasName), MT_ERROR);
+ return;
+ }
+
+ // Command Manager is updated when the preference changes.
+ arrayRemoveAt(aliasDefs, ary[0]);
+ aliasDefs.update();
+
+ feedback(e, getMsg(MSG_ALIAS_REMOVED, e.aliasName));
+ }
+ else if (e.aliasName && e.commandList)
+ {
+ /* add/change alias */
+ ary = getAlias(e.aliasName);
+ if (ary)
+ aliasDefs[ary[0]] = e.aliasName + " = " + e.commandList;
+ else
+ aliasDefs.push(e.aliasName + " = " + e.commandList);
+
+ // Command Manager is updated when the preference changes.
+ aliasDefs.update();
+
+ feedback(e, getMsg(MSG_ALIAS_CREATED, [e.aliasName, e.commandList]));
+ }
+ else if (e.aliasName)
+ {
+ /* display alias */
+ ary = getAlias(e.aliasName);
+ if (!ary)
+ display(getMsg(MSG_NOT_AN_ALIAS, e.aliasName), MT_ERROR);
+ else
+ display(getMsg(MSG_FMT_ALIAS, [e.aliasName, ary[1]]));
+ }
+ else
+ {
+ /* list aliases */
+ if (aliasDefs.length == 0)
+ {
+ display(MSG_NO_ALIASES);
+ }
+ else
+ {
+ for (var i = 0; i < aliasDefs.length; ++i)
+ {
+ ary = aliasDefs[i].match(/^(.*?)\s*=\s*(.*)$/);
+ if (ary)
+ display(getMsg(MSG_FMT_ALIAS, [ary[1], ary[2]]));
+ else
+ display(getMsg(MSG_ERR_BADALIAS, aliasDefs[i]));
+ }
+ }
+ }
+}
+
+function cmdAway(e)
+{
+ function sendToAllNetworks(command, reason)
+ {
+ for (var n in client.networks)
+ {
+ var net = client.networks[n];
+ if (net.primServ && (net.state == NET_ONLINE))
+ {
+ // If we can override the network's away state, or they are
+ // already idly-away, or they're not away to begin with:
+ if (overrideAway || net.isIdleAway || !net.prefs["away"])
+ {
+ net.dispatch(command, {reason: reason });
+ net.isIdleAway = (e.command.name == "idle-away");
+ }
+ }
+ }
+ };
+
+ // Idle away shouldn't override away state set by the user.
+ var overrideAway = (e.command.name.indexOf("idle") != 0);
+
+ if ((e.command.name == "away") || (e.command.name == "custom-away") ||
+ (e.command.name == "idle-away"))
+ {
+ /* going away */
+ if (e.command.name == "custom-away")
+ {
+ e.reason = prompt(MSG_AWAY_PROMPT);
+ // prompt() returns null for cancelling, a string otherwise (even if empty).
+ if (e.reason == null)
+ return;
+ }
+ // No parameter, or user entered nothing in the prompt.
+ if (!e.reason)
+ e.reason = MSG_AWAY_DEFAULT;
+
+ // Update away list (remove from current location).
+ for (var i = 0; i < client.awayMsgs.length; i++)
+ {
+ if (client.awayMsgs[i].message == e.reason)
+ {
+ client.awayMsgs.splice(i, 1);
+ break;
+ }
+ }
+ // Always put new item at start.
+ var newMsg = { message: e.reason };
+ client.awayMsgs.unshift(newMsg);
+ // Make sure we've not exceeded the limit set.
+ if (client.awayMsgs.length > client.awayMsgCount)
+ client.awayMsgs.splice(client.awayMsgCount);
+ // And now, to save the list!
+ try
+ {
+ var awayFile = new nsLocalFile(client.prefs["profilePath"]);
+ awayFile.append("awayMsgs.txt");
+ var awayLoader = new TextSerializer(awayFile);
+ if (awayLoader.open(">"))
+ {
+ awayLoader.serialize(client.awayMsgs);
+ awayLoader.close();
+ }
+ }
+ catch(ex)
+ {
+ display(getMsg(MSG_ERR_AWAY_SAVE, formatException(ex)), MT_ERROR);
+ }
+
+ // Actually do away stuff, is this on a specific network?
+ if (e.server)
+ {
+ var normalNick = e.network.prefs["nickname"];
+ var awayNick = e.network.prefs["awayNick"];
+ if (e.network.state == NET_ONLINE)
+ {
+ // Postulate that if normal nick and away nick are the same,
+ // user doesn't want to change nicks:
+ if (awayNick && (normalNick != awayNick))
+ e.server.changeNick(awayNick);
+ e.server.sendData("AWAY :" + fromUnicode(e.reason, e.network) +
+ "\n");
+ }
+ if (awayNick && (normalNick != awayNick))
+ e.network.preferredNick = awayNick;
+ e.network.prefs["away"] = e.reason;
+ }
+ else
+ {
+ // Client view, do command for all networks.
+ sendToAllNetworks("away", e.reason);
+ client.prefs["away"] = e.reason;
+
+ // Don't tell people how to get back if they're idle:
+ var idleMsgParams = [e.reason, client.prefs["awayIdleTime"]];
+ if (e.command.name == "idle-away")
+ var msg = getMsg(MSG_IDLE_AWAY_ON, idleMsgParams);
+ else
+ msg = getMsg(MSG_AWAY_ON, e.reason);
+
+ // Display on the *client* tab, or on the current tab iff
+ // there's nowhere else they'll hear about it:
+ if (("frame" in client) && client.frame)
+ client.display(msg);
+ else if (!client.getConnectedNetworks())
+ display(msg);
+ }
+ }
+ else
+ {
+ /* returning */
+ if (e.server)
+ {
+ if (e.network.state == NET_ONLINE)
+ {
+ var curNick = e.server.me.unicodeName;
+ var awayNick = e.network.prefs["awayNick"];
+ if (awayNick && (curNick == awayNick))
+ e.server.changeNick(e.network.prefs["nickname"]);
+ e.server.sendData("AWAY\n");
+ }
+ // Go back to old nick, even if not connected:
+ if (awayNick && (curNick == awayNick))
+ e.network.preferredNick = e.network.prefs["nickname"];
+ e.network.prefs["away"] = "";
+ }
+ else
+ {
+ client.prefs["away"] = "";
+ // Client view, do command for all networks.
+ sendToAllNetworks("back");
+ if (("frame" in client) && client.frame)
+ client.display(MSG_AWAY_OFF);
+ else if (!client.getConnectedNetworks())
+ display(MSG_AWAY_OFF);
+ }
+ }
+}
+
+function cmdOpenAtStartup(e)
+{
+ var origURL = e.sourceObject.getURL();
+ var url = makeCanonicalIRCURL(origURL);
+ var list = client.prefs["initialURLs"];
+ ensureCachedCanonicalURLs(list);
+ var index = arrayIndexOf(list.canonicalURLs, url);
+
+ if (e.toggle == null)
+ {
+ if (index == -1)
+ display(getMsg(MSG_STARTUP_NOTFOUND, url));
+ else
+ display(getMsg(MSG_STARTUP_EXISTS, url));
+ return;
+ }
+
+ e.toggle = getToggle(e.toggle, (index != -1));
+
+ if (e.toggle)
+ {
+ // yes, please open at startup
+ if (index == -1)
+ {
+ list.push(origURL);
+ list.update();
+ display(getMsg(MSG_STARTUP_ADDED, url));
+ }
+ else
+ {
+ display(getMsg(MSG_STARTUP_EXISTS, url));
+ }
+ }
+ else
+ {
+ // no, please don't open at startup
+ if (index != -1)
+ {
+ arrayRemoveAt(list, index);
+ list.update();
+ display(getMsg(MSG_STARTUP_REMOVED, url));
+ }
+ else
+ {
+ display(getMsg(MSG_STARTUP_NOTFOUND, url));
+ }
+ }
+}
+
+function cmdOper(e)
+{
+ e.password = client.tryToGetLogin(e.server.getURL(), "oper", e.opername,
+ e.password, true, MSG_NEED_OPER_PASSWORD);
+
+ if (!e.password)
+ return;
+
+ e.server.sendData("OPER " + fromUnicode(e.opername, e.server) + " " +
+ fromUnicode(e.password, e.server) + "\n");
+}
+
+function cmdPing (e)
+{
+ e.network.dispatch("ctcp", { target: e.nickname, code: "PING" });
+}
+
+function cmdPref (e)
+{
+ var msg;
+ var pm;
+
+ if (e.command.name == "network-pref")
+ {
+ pm = e.network.prefManager;
+ msg = MSG_FMT_NETPREF;
+ }
+ else if (e.command.name == "channel-pref")
+ {
+ pm = e.channel.prefManager;
+ msg = MSG_FMT_CHANPREF;
+ }
+ else if (e.command.name == "plugin-pref")
+ {
+ pm = e.plugin.prefManager;
+ msg = MSG_FMT_PLUGINPREF;
+ }
+ else if (e.command.name == "user-pref")
+ {
+ pm = e.user.prefManager;
+ msg = MSG_FMT_USERPREF;
+ }
+ else
+ {
+ pm = client.prefManager;
+ msg = MSG_FMT_PREF;
+ }
+
+ var ary = pm.listPrefs(e.prefName);
+ if (ary.length == 0)
+ {
+ display (getMsg(MSG_ERR_UNKNOWN_PREF, [e.prefName]),
+ MT_ERROR);
+ return false;
+ }
+
+ if (e.prefValue == "-")
+ e.deletePref = true;
+
+ if (e.deletePref)
+ {
+ if (!(e.prefName in pm.prefRecords))
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_PREF, [e.prefName]), MT_ERROR);
+ return false;
+ }
+
+ try
+ {
+ pm.clearPref(e.prefName);
+ }
+ catch (ex)
+ {
+ // ignore exception generated by clear of nonexistant pref
+ if (!("result" in ex) ||
+ ex.result != Components.results.NS_ERROR_UNEXPECTED)
+ {
+ throw ex;
+ }
+ }
+
+ var prefValue = pm.prefs[e.prefName];
+ feedback (e, getMsg(msg, [e.prefName, pm.prefs[e.prefName]]));
+ return true;
+ }
+
+ if (e.prefValue)
+ {
+ if (!(e.prefName in pm.prefRecords))
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_PREF, [e.prefName]), MT_ERROR);
+ return false;
+ }
+
+ var r = pm.prefRecords[e.prefName];
+ var def, type;
+
+ if (typeof r.defaultValue == "function")
+ def = r.defaultValue(e.prefName);
+ else
+ def = r.defaultValue;
+
+ type = typeof def;
+
+ switch (type)
+ {
+ case "number":
+ e.prefValue = Number(e.prefValue);
+ break;
+ case "boolean":
+ e.prefValue = (e.prefValue.toLowerCase() == "true");
+ break;
+ case "string":
+ break;
+ default:
+ if (isinstance(e.prefValue, Array))
+ e.prefValue = e.prefValue.join("; ");
+ if (isinstance(def, Array))
+ e.prefValue = pm.stringToArray(e.prefValue);
+ break;
+ }
+
+ pm.prefs[e.prefName] = e.prefValue;
+ if (isinstance(e.prefValue, Array))
+ e.prefValue = e.prefValue.join("; ");
+ feedback (e, getMsg(msg, [e.prefName, e.prefValue]));
+ }
+ else
+ {
+ for (var i = 0; i < ary.length; ++i)
+ {
+ var value;
+ if (isinstance(pm.prefs[ary[i]], Array))
+ value = pm.prefs[ary[i]].join("; ");
+ else
+ value = pm.prefs[ary[i]];
+
+ feedback(e, getMsg(msg, [ary[i], value]));
+ }
+ }
+
+ return true;
+}
+
+function cmdPrint(e)
+{
+ if (("frame" in e.sourceObject) && e.sourceObject.frame &&
+ getContentWindow(e.sourceObject.frame))
+ {
+ getContentWindow(e.sourceObject.frame).print();
+ }
+ else
+ {
+ display(MSG_ERR_UNABLE_TO_PRINT);
+ }
+}
+
+function cmdVersion(e)
+{
+ if (e.nickname)
+ e.network.dispatch("ctcp", { target: e.nickname, code: "VERSION"});
+ else
+ e.server.sendData(fromUnicode("VERSION") + "\n", e.sourceObject);
+}
+
+function cmdEcho(e)
+{
+ client.munger.getRule(".mailto").enabled = client.prefs["munger.mailto"];
+ display(e.message);
+ client.munger.getRule(".mailto").enabled = false;
+}
+
+function cmdInvite(e)
+{
+ var channel;
+
+ if (e.channelName)
+ {
+ channel = e.server.getChannel(e.channelName);
+ if (!channel)
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_CHANNEL, e.channelName), MT_ERROR);
+ return;
+ }
+ }
+ else if (e.channel)
+ {
+ channel = e.channel;
+ }
+ else
+ {
+ display(getMsg(MSG_ERR_NO_CHANNEL, e.command.name), MT_ERROR);
+ return;
+ }
+
+ channel.invite(e.nickname);
+}
+
+function cmdKick(e)
+{
+ if (e.userList)
+ {
+ if (e.command.name == "kick-ban")
+ {
+ e.sourceObject.dispatch("ban", { userList: e.userList,
+ canonNickList: e.canonNickList,
+ user: e.user,
+ nickname: e.user.encodedName });
+ }
+
+ /* Note that we always do /kick below; the /ban is covered above.
+ * Also note that we are required to pass the nickname, to satisfy
+ * the dispatching of the command (which is defined with a required
+ * <nickname> parameter). It's not required for /ban, above, but it
+ * seems prudent to include it anyway.
+ */
+ for (var i = 0; i < e.userList.length; i++)
+ {
+ var e2 = { user: e.userList[i],
+ nickname: e.userList[i].encodedName };
+ e.sourceObject.dispatch("kick", e2);
+ }
+ return;
+ }
+
+ if (!e.user)
+ e.user = e.channel.getUser(e.nickname);
+
+ if (!e.user)
+ {
+ display(getMsg(MSG_ERR_UNKNOWN_USER, e.nickname), MT_ERROR);
+ return;
+ }
+
+ if (e.command.name == "kick-ban")
+ e.sourceObject.dispatch("ban", { nickname: e.user.encodedName });
+
+ e.user.kick(e.reason);
+}
+
+function cmdKnock(e)
+{
+ var rest = (e.reason ? " :" + fromUnicode(e.reason, e.server) : "") + "\n";
+ e.server.sendData("KNOCK " + fromUnicode(e.channelName, e.server) + rest);
+}
+
+function cmdClient(e)
+{
+ if (!("messages" in client))
+ {
+ client.display(MSG_WELCOME, "HELLO");
+ dispatch("set-current-view", { view: client });
+ dispatch("help", { hello: true });
+ dispatch("networks");
+ }
+ else
+ {
+ dispatch("set-current-view", { view: client });
+ }
+}
+
+function cmdNotify(e)
+{
+ var net = e.network;
+ var supports_monitor = net.primServ.supports["monitor"];
+
+ if (!e.nickname)
+ {
+ if (net.prefs["notifyList"].length > 0)
+ {
+ if (supports_monitor)
+ {
+ // Just get the status of the monitor list from the server.
+ net.primServ.sendData("MONITOR S\n");
+ }
+ else
+ {
+ /* delete the lists and force a ISON check, this will
+ * print the current online/offline status when the server
+ * responds */
+ delete net.onList;
+ delete net.offList;
+ onNotifyTimeout();
+ }
+ }
+ else
+ {
+ display(MSG_NO_NOTIFY_LIST);
+ }
+ }
+ else
+ {
+ var adds = new Array();
+ var subs = new Array();
+
+ for (var i in e.nicknameList)
+ {
+ var nickname = e.server.toLowerCase(e.nicknameList[i]);
+ var list = net.prefs["notifyList"];
+ list = e.server.toLowerCase(list.join(";")).split(";");
+ var idx = arrayIndexOf (list, nickname);
+ if (idx == -1)
+ {
+ net.prefs["notifyList"].push (nickname);
+ adds.push(nickname);
+ }
+ else
+ {
+ arrayRemoveAt (net.prefs["notifyList"], idx);
+ subs.push(nickname);
+ }
+ }
+ net.prefs["notifyList"].update();
+
+ var msgname;
+
+ if (adds.length > 0)
+ {
+ if (supports_monitor)
+ net.primServ.sendMonitorList(adds, true);
+
+ msgname = (adds.length == 1) ? MSG_NOTIFY_ADDONE :
+ MSG_NOTIFY_ADDSOME;
+ display(getMsg(msgname, arraySpeak(adds)));
+ }
+
+ if (subs.length > 0)
+ {
+ if (supports_monitor)
+ net.primServ.sendMonitorList(subs, false);
+
+ msgname = (subs.length == 1) ? MSG_NOTIFY_DELONE :
+ MSG_NOTIFY_DELSOME;
+ display(getMsg(msgname, arraySpeak(subs)));
+ }
+
+ delete net.onList;
+ delete net.offList;
+ if (!supports_monitor)
+ onNotifyTimeout();
+ }
+}
+
+function cmdStalk(e)
+{
+ var list = client.prefs["stalkWords"];
+
+ if (!e.text)
+ {
+ if (list.length == 0)
+ display(MSG_NO_STALK_LIST);
+ else
+ {
+ function alphabetize(a, b)
+ {
+ var A = a.toLowerCase();
+ var B = b.toLowerCase();
+ if (A < B) return -1;
+ if (B < A) return 1;
+ return 0;
+ }
+
+ list.sort(alphabetize);
+ display(getMsg(MSG_STALK_LIST, list.join(", ")));
+ }
+ return;
+ }
+
+ var notStalkingWord = true;
+ var loweredText = e.text.toLowerCase();
+
+ for (var i = 0; i < list.length; ++i)
+ if (list[i].toLowerCase() == loweredText)
+ notStalkingWord = false;
+
+ if (notStalkingWord)
+ {
+ list.push(e.text);
+ list.update();
+ display(getMsg(MSG_STALK_ADD, e.text));
+ }
+ else
+ {
+ display(getMsg(MSG_STALKING_ALREADY, e.text));
+ }
+}
+
+function cmdUnstalk(e)
+{
+ e.text = e.text.toLowerCase();
+ var list = client.prefs["stalkWords"];
+
+ for (var i = 0; i < list.length; ++i)
+ {
+ if (list[i].toLowerCase() == e.text)
+ {
+ list.splice(i, 1);
+ list.update();
+ display(getMsg(MSG_STALK_DEL, e.text));
+ return;
+ }
+ }
+
+ display(getMsg(MSG_ERR_UNKNOWN_STALK, e.text), MT_ERROR);
+}
+
+function cmdUser(e)
+{
+ dispatch("name", {username: e.username, network: e.network,
+ isInteractive: e.isInteractive});
+ dispatch("desc", {description: e.description, network: e.network,
+ isInteractive: e.isInteractive});
+}
+
+function cmdUserhost(e)
+{
+ var nickList = combineNicks(e.nicknameList, 5);
+ for (var i = 0; i < nickList.length; i++)
+ {
+ e.server.userhost(nickList[i]);
+ }
+}
+
+function cmdUserip(e)
+{
+ // Check if the server supports this
+ if (!e.server.servCmds.userip)
+ {
+ display(getMsg(MSG_ERR_UNSUPPORTED_COMMAND, "USERIP"), MT_ERROR);
+ return;
+ }
+ var nickList = combineNicks(e.nicknameList, 5);
+ for (var i = 0; i < nickList.length; i++)
+ e.server.userip(nickList[i]);
+}
+
+function cmdUsermode(e)
+{
+ if (e.newMode)
+ {
+ if (e.sourceObject.network)
+ e.sourceObject.network.prefs["usermode"] = e.newMode;
+ else
+ client.prefs["usermode"] = e.newMode;
+ }
+ else
+ {
+ if (e.server && e.server.isConnected)
+ {
+ e.server.sendData("mode " + e.server.me.encodedName + "\n");
+ }
+ else
+ {
+ var prefs;
+
+ if (e.network)
+ prefs = e.network.prefs;
+ else
+ prefs = client.prefs;
+
+ display(getMsg(MSG_USER_MODE,
+ [prefs["nickname"], prefs["usermode"]]),
+ MT_MODE);
+ }
+ }
+}
+
+function cmdLog(e)
+{
+ var view = e.sourceObject;
+
+ if (e.state != null)
+ {
+ e.state = getToggle(e.state, view.prefs["log"])
+ view.prefs["log"] = e.state;
+ }
+ else
+ {
+ if (view.prefs["log"])
+ display(getMsg(MSG_LOGGING_ON, getLogPath(view)));
+ else
+ display(MSG_LOGGING_OFF);
+ }
+}
+
+function cmdSave(e)
+{
+ var OutputProgressListener =
+ {
+ onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
+ {
+ // Use this to access onStateChange flags
+ var requestSpec;
+ try
+ {
+ var channel = aRequest.QueryInterface(nsIChannel);
+ requestSpec = channel.URI.spec;
+ }
+ catch (ex) { }
+
+ // Detect end of file saving of any file:
+ if (aStateFlags & nsIWebProgressListener.STATE_STOP)
+ {
+ if (aStatus == kErrorBindingAborted)
+ aStatus = 0;
+
+ // We abort saving for all errors except if image src file is
+ // not found
+ var abortSaving = (aStatus != 0 && aStatus != kFileNotFound);
+ if (abortSaving)
+ {
+ // Cancel saving
+ wbp.cancelSave();
+ display(getMsg(MSG_SAVE_ERR_FAILED, aMessage), MT_ERROR);
+ return;
+ }
+
+ if (aStateFlags & nsIWebProgressListener.STATE_IS_NETWORK
+ && wbp.currentState == nsIWBP.PERSIST_STATE_FINISHED)
+ {
+ // Let the user know:
+ pm = [e.sourceObject.viewName, getURLSpecFromFile(file)];
+ display(getMsg(MSG_SAVE_SUCCESSFUL, pm), MT_INFO);
+ }
+ /* Check if we've finished. WebBrowserPersist screws up when we
+ * don't save additional files. Cope when saving html only or
+ * text.
+ */
+ else if (!requestSpec && saveType > 0)
+ {
+ if (wbp)
+ wbp.progressListener = null;
+ pm = [e.sourceObject.viewName, getURLSpecFromFile(file)];
+ display(getMsg(MSG_SAVE_SUCCESSFUL, pm), MT_INFO);
+ }
+ }
+ },
+
+ onProgressChange: function(aWebProgress, aRequest, aCurSelfProgress,
+ aMaxSelfProgress, aCurTotalProgress,
+ aMaxTotalProgress) {},
+ onLocationChange: function(aWebProgress, aRequest, aLocation) {},
+ onStatusChange: function(aWebProgress, aRequest, aStatus, aMessage) {},
+ onSecurityChange: function(aWebProgress, aRequest, state) {},
+
+ QueryInterface: function(aIID)
+ {
+ if (aIID.equals(Components.interfaces.nsIWebProgressListener)
+ || aIID.equals(Components.interfaces.nsISupports)
+ || aIID.equals(Components.interfaces.nsISupportsWeakReference))
+ {
+ return this;
+ }
+
+ throw Components.results.NS_NOINTERFACE;
+ }
+ };
+
+ const kFileNotFound = 2152857618;
+ const kErrorBindingAborted = 2152398850;
+
+ const nsIWBP = Components.interfaces.nsIWebBrowserPersist;
+ const nsIWebProgressListener = Components.interfaces.nsIWebProgressListener;
+ const nsIChannel = Components.interfaces.nsIChannel;
+
+ var wbp = newObject("@mozilla.org/embedding/browser/nsWebBrowserPersist;1",
+ nsIWBP);
+ wbp.progressListener = OutputProgressListener;
+
+ var file, saveType, saveFolder, docToBeSaved, title;
+ var flags, fileType, charLimit;
+ var dialogTitle, rv, pm;
+
+ // We want proper descriptions and no "All Files" option.
+ const TYPELIST = [[MSG_SAVE_COMPLETEVIEW,"*.htm;*.html"],
+ [MSG_SAVE_HTMLONLYVIEW,"*.htm;*.html"],
+ [MSG_SAVE_PLAINTEXTVIEW,"*.txt"], "$noAll"];
+ // constants and variables for the wbp.saveDocument call
+ var saveTypes =
+ {
+ complete: 0,
+ htmlonly: 1,
+ text: 2
+ };
+
+ if (!e.filename)
+ {
+ dialogTitle = getMsg(MSG_SAVE_DIALOGTITLE, e.sourceObject.viewName);
+ rv = pickSaveAs(dialogTitle, TYPELIST, e.sourceObject.viewName +
+ ".html");
+ if (!rv.ok)
+ return;
+ saveType = rv.picker.filterIndex;
+ file = rv.file;
+ e.filename = rv.file.path;
+ }
+ else
+ {
+ try
+ {
+ // Try to use this as a path
+ file = nsLocalFile(e.filename);
+ }
+ catch (ex)
+ {
+ // try to use it as a URL
+ try
+ {
+ file = getFileFromURLSpec(e.filename);
+ }
+ catch(ex)
+ {
+ // What is the user thinking? It's not rocket science...
+ display(getMsg(MSG_SAVE_ERR_INVALID_PATH, e.filename),
+ MT_ERROR);
+ return;
+ }
+ }
+
+ // Get extension and determine savetype
+ if (!e.savetype)
+ {
+ var extension = file.path.substr(file.path.lastIndexOf("."));
+ if (extension == ".txt")
+ {
+ saveType = saveTypes["text"];
+ }
+ else if (extension.match(/\.x?html?$/))
+ {
+ saveType = saveTypes["complete"];
+ }
+ else
+ {
+ // No saveType and no decent extension --> out!
+ var errMsg;
+ if (extension.indexOf(".") < 0)
+ errMsg = MSG_SAVE_ERR_NO_EXT;
+ else
+ errMsg = getMsg(MSG_SAVE_ERR_INVALID_EXT, extension);
+ display(errMsg, MT_ERROR);
+ return;
+ }
+ }
+ else
+ {
+ if (!(e.savetype in saveTypes))
+ {
+ // no valid saveType
+ display(getMsg(MSG_SAVE_ERR_INVALID_SAVETYPE, e.savetype),
+ MT_ERROR);
+ return;
+ }
+ saveType = saveTypes[e.savetype];
+ }
+
+ var askforreplace = (e.isInteractive && file.exists());
+ if (askforreplace && !confirm(getMsg(MSG_SAVE_FILEEXISTS, e.filename)))
+ return;
+ }
+
+ // We don't want to convert anything, leave everything as is and replace
+ // old files, as the user has been prompted about that already.
+ wbp.persistFlags |= nsIWBP.PERSIST_FLAGS_NO_CONVERSION
+ | nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES
+ | nsIWBP.PERSIST_FLAGS_NO_BASE_TAG_MODIFICATIONS
+ | nsIWBP.PERSIST_FLAGS_REPLACE_EXISTING_FILES
+ | nsIWBP.PERSIST_FLAGS_DONT_FIXUP_LINKS
+ | nsIWBP.PERSIST_FLAGS_DONT_CHANGE_FILENAMES;
+
+ // Set the document from the current view, and set a usable title
+ docToBeSaved = getContentDocument(e.sourceObject.frame);
+ var headElement = docToBeSaved.getElementsByTagName("HEAD")[0];
+ var titleElements = docToBeSaved.getElementsByTagName("title");
+ // Remove an existing title, there shouldn't be more than one.
+ if (titleElements.length > 0)
+ titleElements[0].parentNode.removeChild(titleElements[0]);
+ title = docToBeSaved.createElement("title");
+ title.appendChild(docToBeSaved.createTextNode(document.title +
+ " (" + new Date() + ")"));
+ headElement.appendChild(title);
+ // Set standard flags, file type, saveFolder and character limit
+ flags = nsIWBP.ENCODE_FLAGS_ENCODE_BASIC_ENTITIES;
+ fileType = "text/html";
+ saveFolder = null;
+ charLimit = 0;
+
+ // Do saveType specific stuff
+ switch (saveType)
+ {
+ case saveTypes["complete"]:
+ // Get the directory into which to save associated files.
+ saveFolder = file.clone();
+ var baseName = saveFolder.leafName;
+ baseName = baseName.substring(0, baseName.lastIndexOf("."));
+ saveFolder.leafName = getMsg(MSG_SAVE_FILES_FOLDER, baseName);
+ break;
+ // html only does not need any additional configuration
+ case saveTypes["text"]:
+ // set flags for Plain Text
+ flags = nsIWBP.ENCODE_FLAGS_FORMATTED;
+ flags |= nsIWBP.ENCODE_FLAGS_ABSOLUTE_LINKS;
+ flags |= nsIWBP.ENCODE_FLAGS_NOFRAMES_CONTENT;
+ // set the file type and set character limit to 80
+ fileType = "text/plain";
+ charLimit = 80;
+ break;
+ }
+
+ try
+ {
+ wbp.saveDocument(docToBeSaved, file, saveFolder, fileType, flags,
+ charLimit);
+ }
+ catch (ex)
+ {
+ pm = [e.sourceObject.viewName, e.filename, ex.message];
+ display(getMsg(MSG_SAVE_ERR_FAILED, pm), MT_ERROR);
+ }
+ // Error handling and finishing message is done by the listener
+}
+
+function cmdSupports(e)
+{
+ var server = e.server;
+ var data = server.supports;
+
+ if ("channelTypes" in server)
+ display(getMsg(MSG_SUPPORTS_CHANTYPES,
+ server.channelTypes.join(", ")));
+ if ("channelModes" in server)
+ {
+ display(getMsg(MSG_SUPPORTS_CHANMODESA,
+ server.channelModes.a.join(", ")));
+ display(getMsg(MSG_SUPPORTS_CHANMODESB,
+ server.channelModes.b.join(", ")));
+ display(getMsg(MSG_SUPPORTS_CHANMODESC,
+ server.channelModes.c.join(", ")));
+ display(getMsg(MSG_SUPPORTS_CHANMODESD,
+ server.channelModes.d.join(", ")));
+ }
+
+ if ("userModes" in server)
+ {
+ var list = new Array();
+ for (var m in server.userModes)
+ {
+ list.push(getMsg(MSG_SUPPORTS_USERMODE, [
+ server.userModes[m].mode,
+ server.userModes[m].symbol
+ ]));
+ }
+ display(getMsg(MSG_SUPPORTS_USERMODES, list.join(", ")));
+ }
+
+ var listB1 = new Array();
+ var listB2 = new Array();
+ var listN = new Array();
+ for (var k in data)
+ {
+ if (typeof data[k] == "boolean")
+ {
+ if (data[k])
+ listB1.push(k);
+ else
+ listB2.push(k);
+ }
+ else
+ {
+ listN.push(getMsg(MSG_SUPPORTS_MISCOPTION, [ k, data[k] ] ));
+ }
+ }
+ listB1.sort();
+ listB2.sort();
+ listN.sort();
+ display(getMsg(MSG_SUPPORTS_FLAGSON, listB1.join(", ")));
+ display(getMsg(MSG_SUPPORTS_FLAGSOFF, listB2.join(", ")));
+ display(getMsg(MSG_SUPPORTS_MISCOPTIONS, listN.join(", ")));
+
+ var listCaps = new Array();
+ var listCapsEnabled = new Array();
+ for (var cap in server.caps)
+ {
+ listCaps.push(cap);
+ if (server.caps[cap])
+ listCapsEnabled.push(cap);
+ }
+ if (listCaps.length > 0)
+ {
+ listCaps.sort();
+ listCapsEnabled.sort();
+ display(getMsg(MSG_SUPPORTS_CAPS, listCaps.join(", ")));
+ display(getMsg(MSG_SUPPORTS_CAPSON, listCapsEnabled.join(", ")));
+ }
+}
+
+function cmdDoCommand(e)
+{
+ if (e.cmdName == "cmd_mozillaPrefs")
+ {
+ // Open SeaMonkey preferences.
+ goPreferences("navigator_pane");
+ }
+ else if (e.cmdName == "cmd_chatzillaPrefs")
+ {
+ var prefWin = getWindowByType("irc:chatzilla:config");
+ if (!prefWin)
+ {
+ window.openDialog('chrome://chatzilla/content/config.xul', '',
+ 'chrome,resizable,dialog=no', window);
+ }
+ else
+ {
+ prefWin.focus();
+ }
+ }
+ else if (e.cmdName == "cmd_selectAll")
+ {
+ var userList = document.getElementById("user-list");
+ var elemFocused = document.commandDispatcher.focusedElement;
+
+ if (userList.view && (elemFocused == userList))
+ userList.view.selection.selectAll();
+ else
+ doCommand("cmd_selectAll");
+ }
+ else
+ {
+ doCommand(e.cmdName);
+ }
+}
+
+function cmdTime(e)
+{
+ if (e.nickname)
+ e.network.dispatch("ctcp", { target: e.nickname, code: "TIME"});
+ else
+ e.server.sendData(fromUnicode("TIME") + "\n", e.sourceObject);
+}
+
+function cmdTimestamps(e)
+{
+ var view = e.sourceObject;
+
+ if (e.toggle != null)
+ {
+ e.toggle = getToggle(e.toggle, view.prefs["timestamps"])
+ view.prefs["timestamps"] = e.toggle;
+ }
+ else
+ {
+ display(getMsg(MSG_FMT_PREF, ["timestamps",
+ view.prefs["timestamps"]]));
+ }
+}
+
+function cmdSetCurrentView(e)
+{
+ if ("lockView" in e.view)
+ delete e.view.lockView;
+
+ setCurrentObject(e.view);
+}
+
+function cmdJumpToAnchor(e)
+{
+ if (e.hasOwnProperty("channelName"))
+ {
+ e.channel = new CIRCChannel(e.server, e.channelName);
+ }
+ else if (!e.channel)
+ {
+ display(getMsg(MSG_ERR_REQUIRED_PARAM, "channel-name"), MT_ERROR);
+ return;
+ }
+ if (!e.channel.frame)
+ {
+ display(getMsg(MSG_JUMPTO_ERR_NOCHAN, e.channel.unicodeName), MT_ERROR);
+ return;
+ }
+
+ var document = getContentDocument(e.channel.frame);
+ var row = document.getElementById(e.anchor);
+
+ if (!row)
+ {
+ display(getMsg(MSG_JUMPTO_ERR_NOANCHOR), MT_ERROR);
+ return;
+ }
+
+ dispatch("set-current-view", {view: e.channel});
+ e.channel.scrollToElement(row, "center");
+}
+
+function cmdIdentify(e)
+{
+ e.password = client.tryToGetLogin(e.server.parent.getURL(), "nick",
+ e.server.me.name, e.password, true,
+ MSG_NEED_IDENTIFY_PASSWORD);
+ if (!e.password)
+ return;
+
+ e.server.sendData("NS IDENTIFY " + fromUnicode(e.password, e.server) +
+ "\n");
+}
+
+function cmdIgnore(e)
+{
+ if (("mask" in e) && e.mask)
+ {
+ e.mask = e.server.toLowerCase(e.mask);
+
+ if (e.command.name == "ignore")
+ {
+ if (e.network.ignore(e.mask))
+ display(getMsg(MSG_IGNORE_ADD, e.mask));
+ else
+ display(getMsg(MSG_IGNORE_ADDERR, e.mask));
+ }
+ else
+ {
+ if (e.network.unignore(e.mask))
+ display(getMsg(MSG_IGNORE_DEL, e.mask));
+ else
+ display(getMsg(MSG_IGNORE_DELERR, e.mask));
+ }
+ // Update pref:
+ var ignoreList = keys(e.network.ignoreList);
+ e.network.prefs["ignoreList"] = ignoreList;
+ e.network.prefs["ignoreList"].update();
+ }
+ else
+ {
+ var list = new Array();
+ for (var m in e.network.ignoreList)
+ list.push(m);
+ if (list.length == 0)
+ display(MSG_IGNORE_LIST_1);
+ else
+ display(getMsg(MSG_IGNORE_LIST_2, arraySpeak(list)));
+ }
+}
+
+function cmdFont(e)
+{
+ var view = client;
+ var pref, val, pVal;
+
+ if (e.command.name == "font-family")
+ {
+ pref = "font.family";
+ val = e.font;
+
+ // Save new value, then display pref value.
+ if (val)
+ view.prefs[pref] = val;
+
+ display(getMsg(MSG_FONTS_FAMILY_FMT, view.prefs[pref]));
+ }
+ else if (e.command.name == "font-size")
+ {
+ pref = "font.size";
+ val = e.fontSize;
+
+ // Ok, we've got an input.
+ if (val)
+ {
+ // Get the current value, use user's default if needed.
+ pVal = view.prefs[pref];
+ if (pVal == 0)
+ pVal = getDefaultFontSize();
+
+ // Handle user's input...
+ switch(val) {
+ case "default":
+ val = 0;
+ break;
+
+ case "small":
+ val = getDefaultFontSize() - 2;
+ break;
+
+ case "medium":
+ val = getDefaultFontSize();
+ break;
+
+ case "large":
+ val = getDefaultFontSize() + 2;
+ break;
+
+ case "smaller":
+ val = pVal - 2;
+ break;
+
+ case "bigger":
+ val = pVal + 2;
+ break;
+
+ default:
+ if (isNaN(val))
+ val = 0;
+ else
+ val = Number(val);
+ }
+ // Save the new value.
+ view.prefs[pref] = val;
+ }
+
+ // Show the user what the pref is set to.
+ if (view.prefs[pref] == 0)
+ display(MSG_FONTS_SIZE_DEFAULT);
+ else
+ display(getMsg(MSG_FONTS_SIZE_FMT, view.prefs[pref]));
+ }
+ else if (e.command.name == "font-family-other")
+ {
+ val = prompt(MSG_FONTS_FAMILY_PICK, view.prefs["font.family"]);
+ if (!val)
+ return;
+
+ dispatch("font-family", { font: val });
+ }
+ else if (e.command.name == "font-size-other")
+ {
+ pVal = view.prefs["font.size"];
+ if (pVal == 0)
+ pVal = getDefaultFontSize();
+
+ val = prompt(MSG_FONTS_SIZE_PICK, pVal);
+ if (!val)
+ return;
+
+ dispatch("font-size", { fontSize: val });
+ }
+}
+
+function cmdDCCChat(e)
+{
+ if (!client.prefs["dcc.enabled"])
+ return display(MSG_DCC_NOT_ENABLED);
+
+ if (!e.nickname && !e.user)
+ return display(MSG_DCC_ERR_NOUSER);
+
+ var user;
+ if (e.nickname)
+ user = e.server.addUser(e.nickname);
+ else
+ user = e.server.addUser(e.user.unicodeName);
+
+ var u = client.dcc.addUser(user);
+ var c = client.dcc.addChat(u, client.dcc.getNextPort());
+ c.request();
+
+ client.munger.getRule(".inline-buttons").enabled = true;
+ var cmd = getMsg(MSG_DCC_COMMAND_CANCEL, "dcc-close " + c.id);
+ display(getMsg(MSG_DCCCHAT_SENT_REQUEST, c._getParams().concat(cmd)),
+ "DCC-CHAT");
+ client.munger.getRule(".inline-buttons").enabled = false;
+
+ return true;
+}
+
+function cmdDCCClose(e)
+{
+ if (!client.prefs["dcc.enabled"])
+ return display(MSG_DCC_NOT_ENABLED);
+
+ // If there is no nickname specified, use current view.
+ if (!e.nickname)
+ {
+ // Both DCC chat and file transfers can be aborted like this.
+ if (e.sourceObject.TYPE.substr(0, 6) == "IRCDCC")
+ {
+ if (e.sourceObject.isActive())
+ return e.sourceObject.abort();
+ return true;
+ }
+ // ...if there is one.
+ return display(MSG_DCC_ERR_NOTDCC);
+ }
+
+ var o = client.dcc.findByID(e.nickname);
+ if (o)
+ // Direct ID --> object request.
+ return o.abort();
+
+ if (e.type)
+ e.type = [e.type.toLowerCase()];
+ else
+ e.type = ["chat", "file"];
+
+ // Go ask the DCC code for some matching requets.
+ var list = client.dcc.getMatches
+ (e.nickname, e.file, e.type, [DCC_DIR_GETTING, DCC_DIR_SENDING],
+ [DCC_STATE_REQUESTED, DCC_STATE_ACCEPTED, DCC_STATE_CONNECTED]);
+
+ // Disconnect if only one match.
+ if (list.length == 1)
+ return list[0].abort();
+
+ // Oops, couldn't figure the user's requets out, so give them some help.
+ display(getMsg(MSG_DCC_ACCEPTED_MATCHES, [list.length]));
+ display(MSG_DCC_MATCHES_HELP);
+ return true;
+}
+
+function cmdDCCSend(e)
+{
+ if (!client.prefs["dcc.enabled"])
+ return display(MSG_DCC_NOT_ENABLED);
+
+ const DIRSVC_CID = "@mozilla.org/file/directory_service;1";
+ const nsIProperties = Components.interfaces.nsIProperties;
+
+ if (!e.nickname && !e.user)
+ return display(MSG_DCC_ERR_NOUSER);
+
+ // Accept the request passed in...
+ var file;
+ if (!e.file)
+ {
+ var pickerRv = pickOpen(MSG_DCCFILE_SEND);
+ if (!pickerRv.ok)
+ return false;
+ file = pickerRv.file;
+ }
+ else
+ {
+ // Wrap in try/catch because nsIFile creation throws a freaking
+ // error if it doesn't get a FULL path.
+ try
+ {
+ file = nsLocalFile(e.file);
+ }
+ catch(ex)
+ {
+ // Ok, try user's home directory.
+ var fl = Components.classes[DIRSVC_CID].getService(nsIProperties);
+ file = fl.get("Home", Components.interfaces.nsIFile);
+
+ // Another freaking try/catch wrapper.
+ try
+ {
+ // NOTE: This is so pathetic it can't cope with any path
+ // separators in it, so don't even THINK about lobing a
+ // relative path at it.
+ file.append(e.file);
+
+ // Wow. We survived.
+ }
+ catch (ex)
+ {
+ return display(MSG_DCCFILE_ERR_NOTFOUND);
+ }
+ }
+ }
+ if (!file.exists())
+ return display(MSG_DCCFILE_ERR_NOTFOUND);
+ if (!file.isFile())
+ return display(MSG_DCCFILE_ERR_NOTAFILE);
+ if (!file.isReadable())
+ return display(MSG_DCCFILE_ERR_NOTREADABLE);
+
+ var user;
+ if (e.nickname)
+ user = e.server.addUser(e.nickname);
+ else
+ user = e.server.addUser(e.user.unicodeName);
+
+ var u = client.dcc.addUser(user);
+ var c = client.dcc.addFileTransfer(u, client.dcc.getNextPort());
+ c.request(file);
+
+ client.munger.getRule(".inline-buttons").enabled = true;
+ var cmd = getMsg(MSG_DCC_COMMAND_CANCEL, "dcc-close " + c.id);
+ display(getMsg(MSG_DCCFILE_SENT_REQUEST, [c.user.unicodeName, c.localIP,
+ c.port, c.filename,
+ getSISize(c.size), cmd]),
+ "DCC-FILE");
+ client.munger.getRule(".inline-buttons").enabled = false;
+
+ return true;
+}
+
+function cmdDCCList(e) {
+ if (!client.prefs["dcc.enabled"])
+ return display(MSG_DCC_NOT_ENABLED);
+
+ var counts = { pending: 0, connected: 0, failed: 0 };
+ var k;
+
+ // Get all the DCC sessions.
+ var list = client.dcc.getMatches();
+
+ for (k = 0; k < list.length; k++) {
+ var c = list[k];
+ var type = c.TYPE.substr(6, c.TYPE.length - 6);
+
+ var dir = MSG_UNKNOWN;
+ var tf = MSG_UNKNOWN;
+ if (c.state.dir == DCC_DIR_SENDING)
+ {
+ dir = MSG_DCCLIST_DIR_OUT;
+ tf = MSG_DCCLIST_TO;
+ }
+ else if (c.state.dir == DCC_DIR_GETTING)
+ {
+ dir = MSG_DCCLIST_DIR_IN;
+ tf = MSG_DCCLIST_FROM;
+ }
+
+ var state = MSG_UNKNOWN;
+ var cmds = "";
+ switch (c.state.state)
+ {
+ case DCC_STATE_REQUESTED:
+ state = MSG_DCC_STATE_REQUEST;
+ if (c.state.dir == DCC_DIR_GETTING)
+ {
+ cmds = getMsg(MSG_DCC_COMMAND_ACCEPT, "dcc-accept " + c.id) + " " +
+ getMsg(MSG_DCC_COMMAND_DECLINE, "dcc-decline " + c.id);
+ }
+ else
+ {
+ cmds = getMsg(MSG_DCC_COMMAND_CANCEL, "dcc-close " + c.id);
+ }
+ counts.pending++;
+ break;
+ case DCC_STATE_ACCEPTED:
+ state = MSG_DCC_STATE_ACCEPT;
+ counts.connected++;
+ break;
+ case DCC_STATE_DECLINED:
+ state = MSG_DCC_STATE_DECLINE;
+ break;
+ case DCC_STATE_CONNECTED:
+ state = MSG_DCC_STATE_CONNECT;
+ cmds = getMsg(MSG_DCC_COMMAND_CLOSE, "dcc-close " + c.id);
+ if (c.TYPE == "IRCDCCFileTransfer")
+ {
+ state = getMsg(MSG_DCC_STATE_CONNECTPRO,
+ [c.progress,
+ getSISize(c.position), getSISize(c.size),
+ getSISpeed(c.speed)]);
+ }
+ counts.connected++;
+ break;
+ case DCC_STATE_DONE:
+ state = MSG_DCC_STATE_DISCONNECT;
+ break;
+ case DCC_STATE_ABORTED:
+ state = MSG_DCC_STATE_ABORT;
+ counts.failed++;
+ break;
+ case DCC_STATE_FAILED:
+ state = MSG_DCC_STATE_FAIL;
+ counts.failed++;
+ break;
+ }
+ client.munger.getRule(".inline-buttons").enabled = true;
+ display(getMsg(MSG_DCCLIST_LINE, [k + 1, state, dir, type, tf,
+ c.unicodeName, c.remoteIP, c.port,
+ cmds]));
+ client.munger.getRule(".inline-buttons").enabled = false;
+ }
+ display(getMsg(MSG_DCCLIST_SUMMARY, [counts.pending, counts.connected,
+ counts.failed]));
+ return true;
+}
+
+function cmdDCCAutoAcceptList(e)
+{
+ if (!client.prefs["dcc.enabled"])
+ return display(MSG_DCC_NOT_ENABLED);
+
+ var list = e.network.prefs["dcc.autoAccept.list"];
+
+ if (list.length == 0)
+ display(MSG_DCCACCEPT_DISABLED);
+ else
+ display(getMsg(MSG_DCCACCEPT_LIST, arraySpeak(list)));
+
+ return true;
+}
+
+function cmdDCCAutoAcceptAdd(e)
+{
+ if (!client.prefs["dcc.enabled"])
+ return display(MSG_DCC_NOT_ENABLED);
+
+ var list = e.network.prefs["dcc.autoAccept.list"];
+
+ if (!e.user && e.server)
+ e.user = e.server.getUser(e.nickname);
+
+ var mask = e.user ? "*!" + e.user.name + "@" + e.user.host : e.nickname;
+ var index = arrayIndexOf(list, mask);
+ if (index == -1)
+ {
+ list.push(mask);
+ list.update();
+ display(getMsg(MSG_DCCACCEPT_ADD, mask));
+ }
+ else
+ {
+ display(getMsg(MSG_DCCACCEPT_ADDERR,
+ e.user ? e.user.unicodeName : e.nickname));
+ }
+ return true;
+}
+
+function cmdDCCAutoAcceptDel(e)
+{
+ if (!client.prefs["dcc.enabled"])
+ return display(MSG_DCC_NOT_ENABLED);
+
+ var list = e.network.prefs["dcc.autoAccept.list"];
+
+ if (!e.user && e.server)
+ e.user = e.server.getUser(e.nickname);
+
+ var maskObj, newList = new Array();
+ for (var m = 0; m < list.length; ++m)
+ {
+ maskObj = getHostmaskParts(list[m]);
+ if (e.nickname == list[m] ||
+ (e.user && hostmaskMatches(e.user, maskObj, e.server)))
+ {
+ display(getMsg(MSG_DCCACCEPT_DEL, list[m]));
+ }
+ else
+ {
+ newList.push(list[m]);
+ }
+ }
+
+ if (list.length > newList.length)
+ e.network.prefs["dcc.autoAccept.list"] = newList;
+ else
+ display(getMsg(MSG_DCCACCEPT_DELERR,
+ e.user ? e.user.unicodeName : e.nickname));
+
+ return true;
+}
+
+function cmdDCCAccept(e)
+{
+ if (!client.prefs["dcc.enabled"])
+ return display(MSG_DCC_NOT_ENABLED);
+
+ function accept(c)
+ {
+ if (c.TYPE == "IRCDCCChat")
+ {
+ if (!c.accept())
+ return false;
+
+ display(getMsg(MSG_DCCCHAT_ACCEPTED, c._getParams()), "DCC-CHAT");
+ return true;
+ }
+
+ // Accept the request passed in...
+ var filename = c.filename;
+ var ext = "*";
+ var m = filename.match(/...\.([a-z]+)$/i);
+ if (m)
+ ext = "*." + m[1];
+
+ var pickerRv = pickSaveAs(getMsg(MSG_DCCFILE_SAVE_TO, filename),
+ ["$all", ext], filename);
+ if (!pickerRv.ok)
+ return false;
+
+ if (!c.accept(pickerRv.file))
+ return false;
+
+ display(getMsg(MSG_DCCFILE_ACCEPTED, c._getParams()), "DCC-FILE");
+ return true;
+ };
+
+ // If there is no nickname specified, use the "last" item.
+ // This is the last DCC request that arrvied.
+ if (!e.nickname && client.dcc.last)
+ {
+ if ((new Date() - client.dcc.lastTime) >= 10000)
+ return accept(client.dcc.last);
+ return display(MSG_DCC_ERR_ACCEPT_TIME);
+ }
+
+ var o = client.dcc.findByID(e.nickname);
+ if (o)
+ // Direct ID --> object request.
+ return accept(o);
+
+ if (e.type)
+ e.type = [e.type.toLowerCase()];
+ else
+ e.type = ["chat", "file"];
+
+ // Go ask the DCC code for some matching requets.
+ var list = client.dcc.getMatches(e.nickname, e.file, e.type,
+ [DCC_DIR_GETTING], [DCC_STATE_REQUESTED]);
+ // Accept if only one match.
+ if (list.length == 1)
+ return accept(list[0]);
+
+ // Oops, couldn't figure the user's request out, so give them some help.
+ display(getMsg(MSG_DCC_PENDING_MATCHES, [list.length]));
+ display(MSG_DCC_MATCHES_HELP);
+ return true;
+}
+
+function cmdDCCDecline(e)
+{
+ if (!client.prefs["dcc.enabled"])
+ return display(MSG_DCC_NOT_ENABLED);
+
+ function decline(c)
+ {
+ // Decline the request passed in...
+ c.decline();
+ if (c.TYPE == "IRCDCCChat")
+ display(getMsg(MSG_DCCCHAT_DECLINED, c._getParams()), "DCC-CHAT");
+ else
+ display(getMsg(MSG_DCCFILE_DECLINED, c._getParams()), "DCC-FILE");
+ };
+
+ // If there is no nickname specified, use the "last" item.
+ // This is the last DCC request that arrvied.
+ if (!e.nickname && client.dcc.last)
+ return decline(client.dcc.last);
+
+ var o = client.dcc.findByID(e.nickname);
+ if (o)
+ // Direct ID --> object request.
+ return decline(o);
+
+ if (!e.type)
+ e.type = ["chat", "file"];
+
+ // Go ask the DCC code for some matching requets.
+ var list = client.dcc.getMatches(e.nickname, e.file, e.type,
+ [DCC_DIR_GETTING], [DCC_STATE_REQUESTED]);
+ // Decline if only one match.
+ if (list.length == 1)
+ return decline(list[0]);
+
+ // Oops, couldn't figure the user's requets out, so give them some help.
+ display(getMsg(MSG_DCC_PENDING_MATCHES, [list.length]));
+ display(MSG_DCC_MATCHES_HELP);
+ return true;
+}
+
+function cmdDCCShowFile(e)
+{
+ var f = getFileFromURLSpec(e.file);
+ if (f)
+ f = nsLocalFile(f.path);
+ if (f && f.parent && f.parent.exists())
+ {
+ try
+ {
+ f.reveal();
+ }
+ catch (ex)
+ {
+ dd(formatException(ex));
+ }
+ }
+}
+
+function cmdTextDirection(e)
+{
+ var direction;
+ var sourceObject = getContentDocument(e.sourceObject.frame).body;
+
+ switch (e.dir)
+ {
+ case "toggle":
+ if (sourceObject.getAttribute("dir") == "rtl")
+ direction = 'ltr';
+ else
+ direction = 'rtl';
+ break;
+ case "rtl":
+ direction = 'rtl';
+ break;
+ default:
+ // that is "case "ltr":",
+ // but even if !e.dir OR e.dir is an invalid value -> set to
+ // default direction
+ direction = 'ltr';
+ }
+ client.input.setAttribute("dir", direction);
+ sourceObject.setAttribute("dir", direction);
+
+ return true;
+}
+
+function cmdInputTextDirection(e)
+{
+ var direction;
+
+ switch (e.dir)
+ {
+ case "rtl":
+ client.input.setAttribute("dir", "rtl");
+ break
+ default:
+ // that is "case "ltr":", but even if !e.dir OR e.dir is an
+ //invalid value -> set to default direction
+ client.input.setAttribute("dir", "ltr");
+ }
+
+ return true;
+}
+
+function cmdInstallPlugin(e)
+{
+ var ipURL = "chrome://chatzilla/content/install-plugin/install-plugin.xul";
+ var ctx = {};
+ var pluginDownloader =
+ {
+ onStartRequest: function _onStartRequest(request, context)
+ {
+ var tempName = "plugin-install.temp";
+ if (urlMatches)
+ tempName += urlMatches[2];
+
+ ctx.outFile = getTempFile(client.prefs["profilePath"], tempName);
+ ctx.outFileH = fopen(ctx.outFile, ">");
+ },
+ onDataAvailable: function _onDataAvailable(request, context, stream,
+ offset, count)
+ {
+ if (!ctx.inputStream)
+ ctx.inputStream = toSInputStream(stream, true);
+
+ ctx.outFileH.write(ctx.inputStream.readBytes(count));
+ },
+ onStopRequest: function _onStopRequest(request, context, statusCode)
+ {
+ ctx.outFileH.close();
+
+ if (statusCode == 0)
+ {
+ client.installPlugin(e.name, ctx.outFile);
+ }
+ else
+ {
+ display(getMsg(MSG_INSTALL_PLUGIN_ERR_DOWNLOAD, statusCode),
+ MT_ERROR);
+ }
+
+ try
+ {
+ ctx.outFile.remove(false);
+ }
+ catch (ex)
+ {
+ display(getMsg(MSG_INSTALL_PLUGIN_ERR_REMOVE_TEMP, ex),
+ MT_ERROR);
+ }
+ }
+ };
+
+ if (!e.url)
+ {
+ if ("installPluginDialog" in client)
+ return client.installPluginDialog.focus();
+
+ window.openDialog(ipURL, "", "chrome,dialog", client);
+ return;
+ }
+
+ var urlMatches = e.url.match(/([^\/]+?)((\..{0,3}){0,2})$/);
+ if (!e.name)
+ {
+ if (urlMatches)
+ {
+ e.name = urlMatches[1];
+ }
+ else
+ {
+ display(MSG_INSTALL_PLUGIN_ERR_NO_NAME, MT_ERROR);
+ return;
+ }
+ }
+
+ // Do real install here.
+ switch (e.url.match(/^[^:]+/)[0])
+ {
+ case "file":
+ client.installPlugin(e.name, e.url);
+ break;
+
+ case "http":
+ case "https":
+ try
+ {
+ var channel = Services.io.newChannel(
+ e.url, "UTF-8", null, null,
+ Services.scriptSecurityManager.getSystemPrincipal(), null,
+ Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
+ Ci.nsIContentPolicy.TYPE_OTHER);
+ display(getMsg(MSG_INSTALL_PLUGIN_DOWNLOADING, e.url),
+ MT_INFO);
+ channel.asyncOpen(pluginDownloader, { e: e });
+ }
+ catch (ex)
+ {
+ display(getMsg(MSG_INSTALL_PLUGIN_ERR_DOWNLOAD, ex), MT_ERROR);
+ return;
+ }
+ break;
+
+ default:
+ display(MSG_INSTALL_PLUGIN_ERR_PROTOCOL, MT_ERROR);
+ }
+}
+
+function cmdUninstallPlugin(e)
+{
+ if (e.plugin)
+ {
+ client.uninstallPlugin(e.plugin);
+ }
+}
+
+function cmdFind(e)
+{
+ if (!e.rest)
+ {
+ findInPage(getFindData(e));
+ return;
+ }
+
+ // Used from the inputbox, set the search string and find the first
+ // occurrence using find-again.
+ const FINDSVC_ID = "@mozilla.org/find/find_service;1";
+ var findService = getService(FINDSVC_ID, "nsIFindService");
+ // Make sure it searches the entire document, but don't lose the old setting
+ var oldWrap = findService.wrapFind;
+ findService.wrapFind = true;
+ findService.searchString = e.rest;
+ findAgainInPage(getFindData(e));
+ // Restore wrap setting:
+ findService.wrapFind = oldWrap;
+}
+
+function cmdFindAgain(e)
+{
+ if (canFindAgainInPage())
+ findAgainInPage(getFindData(e));
+}
+
+function cmdURLs(e)
+{
+ var urls = client.urlLogger.read().reverse();
+
+ if (urls.length == 0)
+ {
+ display(MSG_URLS_NONE);
+ }
+ else
+ {
+ /* Temporarily remove the URL logger to avoid changing the list when
+ * displaying it.
+ */
+ var logger = client.urlLogger;
+ delete client.urlLogger;
+
+ var num = e.number || client.prefs["urls.display"];
+ if (num > urls.length)
+ num = urls.length;
+ display(getMsg(MSG_URLS_HEADER, num));
+
+ for (var i = 0; i < num; i++)
+ display(getMsg(MSG_URLS_ITEM, [i + 1, urls[i]]));
+
+ client.urlLogger = logger;
+ }
+}
+
+function cmdWebSearch(e)
+{
+ let submission = Services.search.currentEngine
+ .getSubmission(e.selectedText);
+ let newTabPref = Services.prefs.getBoolPref("browser.search.opentabforcontextsearch");
+ dispatch(newTabPref ? "goto-url-newtab" : "goto-url-newwin",
+ {url: submission.uri.asciiSpec,
+ shiftKey: e.shiftKey});
+}