RetroZilla/extensions/irc/xul/content/commands.js

4285 lines
128 KiB
JavaScript
Raw Normal View History

2015-10-21 05:03:22 +02:00
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is ChatZilla.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Robert Ginda, <rginda@netscape.com>, original author
* Chiaki Koufugata, chiaki@mozilla.gr.jp, UI i18n
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const CMD_CONSOLE = 0x01;
const CMD_NEED_NET = 0x02;
const CMD_NEED_SRV = 0x04;
const CMD_NEED_CHAN = 0x08;
const CMD_NEED_USER = 0x10;
const CMD_NO_HELP = 0x20;
function initCommands()
{
var cmdary =
[/* "real" commands */
["about", cmdAbout, CMD_CONSOLE],
["alias", cmdAlias, CMD_CONSOLE],
["attach", cmdAttach, CMD_CONSOLE],
["away", cmdAway, CMD_CONSOLE],
["back", cmdAway, CMD_CONSOLE],
["ban", cmdBanOrExcept, CMD_NEED_CHAN | CMD_CONSOLE],
["cancel", cmdCancel, CMD_NEED_NET | CMD_CONSOLE],
["charset", cmdCharset, CMD_CONSOLE],
["channel-motif", cmdMotif, CMD_NEED_CHAN | CMD_CONSOLE],
["channel-pref", cmdPref, CMD_NEED_CHAN | CMD_CONSOLE],
["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],
["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],
["create-tab-for-view", cmdCreateTabForView, 0],
["custom-away", cmdAway, 0],
["op", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE],
["dcc-accept", cmdDCCAccept, CMD_CONSOLE],
["dcc-accept-list", cmdDCCAutoAcceptList, CMD_NEED_NET | CMD_CONSOLE],
["dcc-accept-list-add", cmdDCCAutoAcceptAdd,
CMD_NEED_NET | CMD_CONSOLE],
["dcc-accept-list-remove", cmdDCCAutoAcceptDel,
CMD_NEED_NET | CMD_CONSOLE],
["dcc-chat", cmdDCCChat, CMD_NEED_SRV | CMD_CONSOLE],
["dcc-close", cmdDCCClose, CMD_CONSOLE],
["dcc-decline", cmdDCCDecline, CMD_CONSOLE],
["dcc-list", cmdDCCList, CMD_CONSOLE],
["dcc-send", cmdDCCSend, CMD_NEED_SRV | CMD_CONSOLE],
["deop", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE],
["describe", cmdDescribe, CMD_NEED_SRV | CMD_CONSOLE],
["hop", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE],
["dehop", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE],
["voice", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE],
["devoice", cmdChanUserMode, CMD_NEED_CHAN | CMD_CONSOLE],
["clear-view", cmdClearView, CMD_CONSOLE],
["client", cmdClient, CMD_CONSOLE],
["commands", cmdCommands, CMD_CONSOLE],
["ctcp", cmdCTCP, CMD_NEED_SRV | CMD_CONSOLE],
["default-charset", cmdCharset, CMD_CONSOLE],
["delete-view", cmdDeleteView, CMD_CONSOLE],
["desc", cmdDesc, CMD_CONSOLE],
["disable-plugin", cmdAblePlugin, CMD_CONSOLE],
["disconnect", cmdDisconnect, CMD_NEED_SRV | CMD_CONSOLE],
["disconnect-all", cmdDisconnectAll, CMD_CONSOLE],
["echo", cmdEcho, CMD_CONSOLE],
["enable-plugin", cmdAblePlugin, CMD_CONSOLE],
["eval", cmdEval, CMD_CONSOLE],
["except", cmdBanOrExcept, CMD_NEED_CHAN | CMD_CONSOLE],
["find", cmdFind, 0],
["find-again", cmdFindAgain, 0],
["focus-input", cmdFocusInput, 0],
["font-family", cmdFont, CMD_CONSOLE],
["font-family-other", cmdFont, 0],
["font-size", cmdFont, CMD_CONSOLE],
["font-size-other", cmdFont, 0],
["goto-url", cmdGotoURL, 0],
["goto-url-newwin", cmdGotoURL, 0],
["goto-url-newtab", cmdGotoURL, 0],
["goto-url-external", cmdGotoURL, 0],
["help", cmdHelp, CMD_CONSOLE],
["hide-view", cmdHideView, CMD_CONSOLE],
["ignore", cmdIgnore, CMD_NEED_NET | CMD_CONSOLE],
["input-text-direction", cmdInputTextDirection, 0],
["invite", cmdInvite, CMD_NEED_SRV | CMD_CONSOLE],
["join", cmdJoin, CMD_NEED_SRV | CMD_CONSOLE],
["join-charset", cmdJoin, CMD_NEED_SRV | CMD_CONSOLE],
["kick", cmdKick, CMD_NEED_CHAN | CMD_CONSOLE],
["kick-ban", cmdKick, CMD_NEED_CHAN | CMD_CONSOLE],
["knock", cmdKnock, CMD_NEED_SRV | CMD_CONSOLE],
["leave", cmdLeave, CMD_NEED_CHAN | CMD_CONSOLE],
["links", cmdSimpleCommand, CMD_NEED_SRV | CMD_CONSOLE],
["list", cmdList, CMD_NEED_SRV | CMD_CONSOLE],
["list-plugins", cmdListPlugins, CMD_CONSOLE],
["load", cmdLoad, CMD_CONSOLE],
["log", cmdLog, CMD_CONSOLE],
["map", cmdSimpleCommand, CMD_NEED_SRV | CMD_CONSOLE],
["me", cmdMe, CMD_CONSOLE],
["motd", cmdSimpleCommand, CMD_NEED_SRV | CMD_CONSOLE],
["mode", cmdMode, CMD_NEED_SRV | CMD_CONSOLE],
["motif", cmdMotif, CMD_CONSOLE],
["msg", cmdMsg, CMD_NEED_SRV | CMD_CONSOLE],
["name", cmdName, CMD_CONSOLE],
["names", cmdNames, CMD_NEED_SRV | CMD_CONSOLE],
["network", cmdNetwork, CMD_CONSOLE],
["network-motif", cmdMotif, CMD_NEED_NET | CMD_CONSOLE],
["network-pref", cmdPref, CMD_NEED_NET | CMD_CONSOLE],
["networks", cmdNetworks, CMD_CONSOLE],
["nick", cmdNick, CMD_CONSOLE],
["notice", cmdNotice, CMD_NEED_SRV | CMD_CONSOLE],
["notify", cmdNotify, CMD_NEED_SRV | CMD_CONSOLE],
["open-at-startup", cmdOpenAtStartup, CMD_CONSOLE],
["oper", cmdOper, CMD_NEED_SRV | CMD_CONSOLE],
["pass", cmdPass, CMD_NEED_NET | CMD_CONSOLE],
["ping", cmdPing, CMD_NEED_SRV | CMD_CONSOLE],
["plugin-pref", cmdPref, CMD_CONSOLE],
["pref", cmdPref, CMD_CONSOLE],
["print", cmdPrint, CMD_CONSOLE],
["query", cmdQuery, CMD_NEED_SRV | CMD_CONSOLE],
["quit", cmdQuit, CMD_CONSOLE],
["quote", cmdQuote, CMD_NEED_SRV | CMD_CONSOLE],
["reload-plugin", cmdReload, CMD_CONSOLE],
["rlist", cmdRlist, CMD_NEED_SRV | CMD_CONSOLE],
["reconnect", cmdReconnect, CMD_NEED_NET | CMD_CONSOLE],
["reconnect-all", cmdReconnectAll, CMD_CONSOLE],
["rejoin", cmdRejoin,
CMD_NEED_SRV | CMD_NEED_CHAN | CMD_CONSOLE],
["reload-ui", cmdReloadUI, 0],
["save", cmdSave, CMD_CONSOLE],
["say", cmdSay, CMD_NEED_SRV | CMD_CONSOLE],
["server", cmdServer, CMD_CONSOLE],
["set-current-view", cmdSetCurrentView, 0],
["stats", cmdSimpleCommand, CMD_NEED_SRV | CMD_CONSOLE],
["squery", cmdSquery, CMD_NEED_SRV | CMD_CONSOLE],
["sslserver", cmdSSLServer, CMD_CONSOLE],
["stalk", cmdStalk, CMD_CONSOLE],
["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],
["time", cmdTime, CMD_NEED_SRV | CMD_CONSOLE],
["timestamps", cmdTimestamps, CMD_CONSOLE],
["timestamp-format", cmdTimestampFormat, CMD_CONSOLE],
["toggle-ui", cmdToggleUI, CMD_CONSOLE],
["toggle-pref", cmdTogglePref, 0],
["topic", cmdTopic, CMD_NEED_CHAN | CMD_CONSOLE],
["unignore", cmdIgnore, CMD_NEED_NET | CMD_CONSOLE],
["unban", cmdBanOrExcept, CMD_NEED_CHAN | CMD_CONSOLE],
["unexcept", cmdBanOrExcept, CMD_NEED_CHAN | CMD_CONSOLE],
["unstalk", cmdUnstalk, CMD_CONSOLE],
["urls", cmdURLs, CMD_CONSOLE],
["user", cmdUser, CMD_CONSOLE],
["userhost", cmdUserhost, CMD_NEED_SRV | CMD_CONSOLE],
["userip", cmdUserip, CMD_NEED_SRV | CMD_CONSOLE],
["usermode", cmdUsermode, CMD_CONSOLE],
["user-motif", cmdMotif, CMD_NEED_USER | CMD_CONSOLE],
["user-pref", cmdPref, CMD_NEED_USER | CMD_CONSOLE],
["version", cmdVersion, CMD_NEED_SRV | CMD_CONSOLE],
["who", cmdWho, CMD_NEED_SRV | CMD_CONSOLE],
["whois", cmdWhoIs, CMD_NEED_SRV | CMD_CONSOLE],
["whowas", cmdWhoWas, CMD_NEED_SRV | CMD_CONSOLE],
["wii", cmdWhoIsIdle, CMD_NEED_SRV | CMD_CONSOLE],
/* aliases */
["css", "motif", CMD_CONSOLE],
["exit", "quit", CMD_CONSOLE],
["j", "join", CMD_CONSOLE],
["part", "leave", CMD_CONSOLE],
["raw", "quote", CMD_CONSOLE],
// Shortcuts to useful URLs:
["faq", "goto-url http://chatzilla.hacksrus.com/faq/", 0],
["homepage", "goto-url http://chatzilla.hacksrus.com/", 0],
// Used to display a nickname in the menu only.
["label-user", "echo", 0],
// 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],
["motif-default", "motif default", 0],
["sync-output", "eval 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],
// Instrumentation aliases
["allow-inst1", "pref instrumentation.inst1 1", 0],
["deny-inst1", "pref instrumentation.inst1 2", 0]
];
// set the stringbundle associated with these commands.
cmdary.stringBundle = client.defaultBundle;
client.commandManager = new CommandManager(client.defaultBundle);
client.commandManager.defaultFlags = CMD_NO_HELP | CMD_CONSOLE;
client.commandManager.isCommandSatisfied = isCommandSatisfied;
client.commandManager.defineCommands(cmdary);
var restList = ["reason", "action", "text", "message", "params", "font",
"expression", "ircCommand", "prefValue", "newTopic",
"commandList", "file", "commands", "description"];
client.commandManager.argTypes.__aliasTypes__(restList, "rest");
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_NO_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);
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_NO_CMDMATCH, 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) ? MSG_COMMASP + 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);
};
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;
};
var h, i;
if (typeof e.command.func == "function")
{
/* dispatch a real function */
client.commandManager.parseArguments (e);
if ("parseError" in e)
{
displayUsageError(e, e.parseError);
}
else
{
if ("beforeHooks" in client.commandManager)
callHooks(client.commandManager, true);
if ("beforeHooks" in e.command)
callHooks(e.command, true);
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 + " <<<");
e.returnValue = e.command.func(e);
/* set client.lastEvent *after* dispatching, so the dispatched
* function actually get's a chance to see the last event. */
client.lastEvent = e;
}
else
{
e.returnValue = e.command.func(e);
}
}
}
else if (typeof e.command.func == "string")
{
/* dispatch an alias (semicolon delimited list of subcommands) */
if ("beforeHooks" in client.commandManager)
callHooks(client.commandManager, true);
if ("beforeHooks" in e.command)
callHooks(e.command, true);
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);
}
}
for (i = 0; i < commandList.length; ++i)
{
var newEvent = Clone(e);
delete newEvent.command;
commandList[i] = stringTrim(commandList[i]);
dispatch(commandList[i], newEvent, flags);
}
}
else
{
display (getMsg(MSG_ERR_NOTIMPLEMENTED, e.command.name),
MT_ERROR);
return null;
}
if ("afterHooks" in e.command)
callHooks(e.command, false);
if ("afterHooks" in client.commandManager)
callHooks(client.commandManager, false);
return ("returnValue" in e) ? e.returnValue : null;
}
/* parse function for <plugin> parameters */
function parsePlugin(e, name)
{
var ary = e.unparsedData.match (/(?:(\d+)|(\S+))(?:\s+(.*))?$/);
if (!ary)
return false;
var plugin;
if (ary[1])
{
var i = parseInt(ary[1]);
if (!(i in client.plugins))
return false;
plugin = client.plugins[i];
}
else
{
plugin = getPluginById(ary[2]);
if (!plugin)
return false;
}
e.unparsedData = arrayHasElementAt(ary, 3) ? ary[3] : "";
e[name] = plugin;
return true;
}
function getToggle (toggle, currentState)
{
if (toggle == "toggle")
toggle = !currentState;
return toggle;
}
/******************************************************************************
* command definitions from here on down.
*/
function cmdAblePlugin(e)
{
if (e.command.name == "disable-plugin")
{
if (!e.plugin.enabled)
{
display(getMsg(MSG_IS_DISABLED, e.plugin.id));
return;
}
if (e.plugin.API > 0)
{
if (!e.plugin.disable())
{
display(getMsg(MSG_CANT_DISABLE, e.plugin.id));
return;
}
e.plugin.prefs["enabled"] = false;
}
else if (!("disablePlugin" in e.plugin.scope))
{
display(getMsg(MSG_CANT_DISABLE, e.plugin.id));
return;
}
else
{
e.plugin.scope.disablePlugin();
}
e.plugin.enabled = false;
}
else
{
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();
}
e.plugin.enabled = true;
}
}
function cmdBanOrExcept(e)
{
/* 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 mask = "";
if (e.user)
{
// We have a real user object, so get their proper 'ban mask'.
mask = 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.
*/
mask = fromUnicode(e.nickname, e.server);
if (!/[!@]/.test(e.nickname))
mask = mask + "!*@*";
}
var op;
switch (e.command.name)
{
case "ban":
op = " +b ";
break;
case "unban":
op = " -b ";
break;
case "except":
op = " +e ";
break;
case "unexcept":
op = " -e ";
break;
}
e.server.sendData("MODE " + e.channel.encodedName + op + mask + "\n");
}
function cmdCancel(e)
{
var network = e.network;
if ((network.state == NET_ONLINE) && network.isRunningList())
{
// We're running a /list, terminate the output so we return to sanity
display(MSG_CANCELLING_LIST);
network.abortList();
}
else if ((network.state == NET_CONNECTING) ||
(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, network.unicodeName));
network.cancel();
}
else
{
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;
// Prefer pre-canonicalised list, then a normal list, then finally a
// sigular item (canon. or otherwise).
if (e.canonNickList)
{
nicks = combineNicks(e.canonNickList);
}
else if (e.nicknameList)
{
var nickList = new Array();
for (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 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"]);
// Refresh the motif settings.
view.updateMotifSettings();
};
break;
case "sync-timestamp":
fun = function ()
{
view.changeCSS(view.getTimestampCSS("data"),
"cz-timestamp-format");
};
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);
else
client.closeLogFile(view);
}
};
break;
}
var view = e.sourceObject;
var window;
if (("frame" in view) && view.frame)
window = view.frame.contentWindow;
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 cmdStatus(e)
{
function serverStatus (s)
{
if (!s.connection.isConnected)
{
display(getMsg(MSG_NOT_CONNECTED, s.parent.name), MT_STATUS);
return;
}
var serverType = (s.parent.primServ == s) ? MSG_PRIMARY : MSG_SECONDARY;
display(getMsg(MSG_CONNECTION_INFO,
[s.parent.name, s.me.unicodeName, s.connection.host,
s.connection.port, serverType]),
MT_STATUS);
var connectTime = Math.floor((new Date() - s.connection.connectDate) /
1000);
connectTime = formatDateOffset(connectTime);
var pingTime = ("lastPing" in s) ?
formatDateOffset(Math.floor((new Date() - s.lastPing) / 1000)) :
MSG_NA;
var lag = (s.lag >= 0) ? s.lag : MSG_NA;
display(getMsg(MSG_SERVER_INFO,
[s.parent.name, connectTime, pingTime, lag]),
MT_STATUS);
}
function channelStatus (c)
{
var cu;
var net = c.parent.parent.name;
if ((cu = c.users[c.parent.me.canonicalName]))
{
var mtype;
if (cu.isOp && cu.isVoice)
mtype = MSG_VOICEOP;
else if (cu.isOp)
mtype = MSG_OPERATOR;
else if (cu.isVoice)
mtype = MSG_VOICED;
else
mtype = MSG_MEMBER;
var mode = c.mode.getModeStr();
if (!mode)
mode = MSG_NO_MODE;
display(getMsg(MSG_CHANNEL_INFO,
[net, mtype, c.unicodeName, mode,
(c.parent.isSecure ? "irc://" : "ircs://" )
+ escape(net) + "/" + escape(c.encodedName) + "/"]),
MT_STATUS);
display(getMsg(MSG_CHANNEL_DETAIL,
[net, c.unicodeName, c.getUsersLength(),
c.opCount, c.voiceCount]),
MT_STATUS);
if (c.topic)
{
display(getMsg(MSG_TOPIC_INFO, [net, c.unicodeName, c.topic]),
MT_STATUS);
}
else
{
display(getMsg(MSG_NOTOPIC_INFO, [net, c.unicodeName]),
MT_STATUS);
}
}
else
{
display(getMsg(MSG_NONMEMBER, [net, c.unicodeName]), MT_STATUS);
}
};
display(client.userAgent, MT_STATUS);
display(getMsg(MSG_USER_INFO,
[client.prefs["nickname"], client.prefs["username"],
client.prefs["desc"]]),
MT_STATUS);
var n, s, c;
if (e.channel)
{
serverStatus(e.server);
channelStatus(e.channel);
}
else if (e.network)
{
for (s in e.network.servers)
{
serverStatus(e.network.servers[s]);
for (c in e.network.servers[s].channels)
channelStatus (e.network.servers[s].channels[c]);
}
}
else
{
for (n in client.networks)
{
for (s in client.networks[n].servers)
{
var server = client.networks[n].servers[s]
serverStatus(server);
for (c in server.channels)
channelStatus(server.channels[c]);
}
}
}
display(MSG_END_STATUS, MT_STATUS);
}
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);
if (ary.length == 0)
{
display(getMsg(MSG_ERR_NO_COMMAND, e.pattern), MT_ERROR);
return;
}
for (var i in ary)
{
display(getMsg(MSG_FMT_USAGE, [ary[i].name, ary[i].usage]), MT_USAGE);
display(ary[i].help, MT_HELP);
}
return;
}
function cmdTestDisplay(e)
{
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", canonicalName: "ircmonkey",
unicodeName: "IRCMonkey", viewName: "IRCMonkey",
host: "", name: "chatzilla"};
var sampleChannel = {TYPE: "IRCChannel",
encodedName: "#mojo", canonicalName: "#mojo",
unicodeName: "#Mojo", viewName: "#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);
}
}
}
function cmdNetwork(e)
{
if (!(e.networkName in client.networks))
{
display (getMsg(MSG_ERR_UNKNOWN_NETWORK, e.networkName), MT_ERROR);
return;
}
var network = client.networks[e.networkName];
if (!("messages" in network))
network.displayHere(getMsg(MSG_NETWORK_OPENED, network.name));
dispatch("set-current-view", { view: network });
}
function cmdNetworks(e)
{
const ns = "http://www.w3.org/1999/xhtml";
var span = document.createElementNS(ns, "html:span");
span.appendChild(newInlineText(MSG_NETWORKS_HEADA));
var netnames = keys(client.networks).sort();
var lastname = netnames[netnames.length - 1];
for (n in netnames)
{
var net = client.networks[netnames[n]];
var a = document.createElementNS(ns, "html:a");
/* Test for an all-SSL network */
var isSecure = true;
for (var s in client.networks[netnames[n]].serverList)
{
if (!client.networks[netnames[n]].serverList[s].isSecure)
{
isSecure = false;
break;
}
}
a.setAttribute("class", "chatzilla-link");
a.setAttribute("href", (isSecure ? "ircs://" : "irc://") + net.canonicalName);
var t = newInlineText(net.unicodeName);
a.appendChild(t);
span.appendChild(a);
if (netnames[n] != lastname)
span.appendChild(newInlineText (MSG_COMMASP));
}
span.appendChild(newInlineText(MSG_NETWORKS_HEADB));
display(span, MT_INFO);
}
function cmdServer(e)
{
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];
}
var name = e.hostname.toLowerCase();
if (!e.port)
e.port = 6667;
else if (e.port != 6667)
name += ":" + e.port;
if (!(name in client.networks))
{
/* if there wasn't already a network created for this server,
* make one. */
client.addNetwork(name, [{name: e.hostname, port: e.port,
password: e.password}], true);
}
else
{
// We are trying to connect without SSL, adjust for temporary networks
if (client.networks[name].temporary)
client.networks[name].serverList[0].isSecure = false;
// update password on existing server.
if (e.password)
client.networks[name].serverList[0].password = e.password;
}
return client.connectToNetwork(name, false);
}
function cmdSSLServer(e)
{
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];
}
var name = e.hostname.toLowerCase();
if (!e.port)
e.port = 9999;
if (e.port != 6667)
name += ":" + e.port;
if (!(name in client.networks))
{
/* if there wasn't already a network created for this server,
* make one. */
client.addNetwork(name, [{name: e.hostname, port: e.port,
password: e.password, isSecure: true}], true);
}
else
{
// We are trying to connect using SSL, adjust for temporary networks
if (client.networks[name].temporary)
client.networks[name].serverList[0].isSecure = true;
// update password on existing server.
if (e.password)
client.networks[name].serverList[0].password = e.password;
}
return client.connectToNetwork(name, true);
}
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.active)
{
e.view.dispatch("part", { deleteWhenDone: true });
return;
}
if (e.view.TYPE == "IRCDCCChat" && e.view.active)
e.view.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;
client.deck.removeChild(e.view.frame);
delete e.view.frame;
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;
}
var tb = getTabForObject(e.view);
if (tb)
{
var i = deleteTab (tb);
if (i != -1)
{
client.deck.removeChild(e.view.frame);
delete e.view.frame;
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 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 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;
if (elem.getAttribute("collapsed") == "true")
{
if (e.thing == "userlist")
{
if (sourceObject.TYPE == "IRCChannel")
{
client.rdf.setTreeRoot("user-list",
sourceObject.getGraphResource());
setSelectedNicknames(document.getElementById("user-list"),
sourceObject.userlistSelection);
}
else
{
client.rdf.setTreeRoot("user-list", client.rdf.resNullChan);
}
}
newState = "false";
}
else
{
if ((e.thing == "userlist") && (sourceObject.TYPE == "IRCChannel"))
{
var rv = getSelectedNicknames(document.getElementById("user-list"));
sourceObject.userlistSelection = rv;
}
newState = "true";
}
for (var i in ids)
{
elem = document.getElementById(ids[i]);
elem.setAttribute ("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(MSG_COMMASP);
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 cmdMe(e)
{
if (!("act" in e.sourceObject))
{
display(getMsg(MSG_ERR_IMPROPER_VIEW, "me"), MT_ERROR);
return;
}
var msg = filterOutput(e.action, "ACTION", e.sourceObject);
e.sourceObject.display(msg, "ACTION", "ME!", e.sourceObject);
e.sourceObject.act(msg);
}
function cmdDescribe(e)
{
var target = e.server.addTarget(e.target);
var msg = filterOutput(e.action, "ACTION", target);
e.sourceObject.display(msg, "ACTION", "ME!", target);
target.act(msg);
}
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(/\.css$/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 = "";
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;
}
if (client.plugins.length > 0)
{
for (var i = 0; i < client.plugins.length; ++i)
listPlugin(client.plugins[i], i);
}
else
{
display(MSG_NO_PLUGINS);
}
}
function cmdRlist(e)
{
e.network.list(new RegExp(e.regexp, "i"));
}
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)
{
e.message = filterOutput(e.message, "PRIVMSG", user);
user.display(e.message, "PRIVMSG", "ME!", user);
user.say(e.message);
}
return user;
}
function cmdSay(e)
{
if (!("say" in e.sourceObject))
{
display(getMsg(MSG_ERR_IMPROPER_VIEW, "say"), MT_ERROR);
return;
}
var msg = filterOutput(e.message, "PRIVMSG", e.sourceObject);
e.sourceObject.display(msg, "PRIVMSG", "ME!", e.sourceObject);
e.sourceObject.say(msg);
}
function cmdMsg(e)
{
var target = e.server.addTarget(e.nickname);
var msg = filterOutput(e.message, "PRIVMSG", target);
e.sourceObject.display(msg, "PRIVMSG", "ME!", target);
target.say(msg);
}
function cmdNick(e)
{
if (!e.nickname)
{
var curNick;
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;
}
if (e.server)
e.server.changeNick(e.nickname);
if (e.network)
e.network.prefs["nickname"] = e.nickname;
else
client.prefs["nickname"] = e.nickname;
}
function cmdNotice(e)
{
var target = e.server.addTarget(e.nickname);
var msg = filterOutput(e.message, "NOTICE", target);
e.sourceObject.display(msg, "NOTICE", "ME!", target);
target.notice(msg);
}
function cmdQuote(e)
{
e.server.sendData(fromUnicode(e.ircCommand) + "\n", e.sourceObject);
}
function cmdEval(e)
{
var sourceObject = e.sourceObject;
try
{
sourceObject.doEval = function (__s) { return eval(__s); }
sourceObject.display(e.expression, MT_EVALIN);
var rv = String(sourceObject.doEval (e.expression));
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 cmdGotoURL(e)
{
const IO_SVC = "@mozilla.org/network/io-service;1";
const EXT_PROTO_SVC = "@mozilla.org/uriloader/external-protocol-service;1";
if (e.url.search(/^ircs?:/i) == 0)
{
gotoIRCURL(e.url);
return;
}
if (e.url.search(/^x-cz-command:/i) == 0)
{
var ary = e.url.match(/^x-cz-command:(.*)$/i);
e.sourceObject.frame.contentWindow.location.href =
"javascript:void(view.dispatch('" + decodeURI(ary[1]) + "', null, true))";
return;
}
if ((e.command.name == "goto-url-external") || (client.host == "XULrunner"))
{
const ioSvc = getService(IO_SVC, "nsIIOService");
const extProtoSvc = getService(EXT_PROTO_SVC,
"nsIExternalProtocolService");
var uri = ioSvc.newURI(e.url, "UTF-8", null);
extProtoSvc.loadUrl(uri);
return;
}
if (e.command.name == "goto-url-newwin")
{
openTopWin(e.url);
dispatch("focus-input");
return;
}
var window = getWindowByType("navigator:browser");
if (!window)
{
openTopWin(e.url);
dispatch("focus-input");
return;
}
if (client.prefs["link.focus"])
{
try
{
window.focus();
}
catch (ex)
{
dd(formatException(ex));
}
}
if (e.command.name == "goto-url-newtab")
{
try
{
if (client.host == "Mozilla")
window.openNewTabWith(e.url, false, false);
else
window.openNewTabWith(e.url, null, null, null, null, false);
}
catch (ex)
{
dd(formatException(ex));
}
dispatch("focus-input");
return;
}
var location = window.content.document.location;
if (location.href.indexOf("chrome://chatzilla/content/") == 0)
{
// don't replace chatzilla running in a tab
openTopWin(e.url);
dispatch("focus-input");
return;
}
try
{
location.href = e.url;
}
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)
{
window.openDialog("chrome://chatzilla/content/channels.xul", "",
"modal,resizable=yes",
{ client: client, network: e.network })
return null;
}
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 chan;
var chans = e.channelName.split(",");
var keys = [];
if (e.key)
keys = e.key.split(",");
for (var c in chans)
{
chan = dispatch("join", { 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"];
e.channel = e.server.addChannel(e.channelName, charset);
if (e.charset)
e.channel.prefs["charset"] = e.charset;
e.channel.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 (e.channelName[0] != "!")
{
if (!("messages" in e.channel))
{
e.channel.displayHere(getMsg(MSG_CHANNEL_OPENED,
e.channel.unicodeName), MT_INFO);
}
dispatch("set-current-view", { view: e.channel });
}
return e.channel;
}
function cmdLeave(e)
{
if (!e.server)
{
display(MSG_ERR_IMPROPER_VIEW, MT_ERROR);
return;
}
if (e.hasOwnProperty("channelName"))
{
if (arrayIndexOf(e.server.channelTypes, e.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] +
e.channelName);
if (chan)
{
// Yes! They just missed that single character.
e.channel = 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".
*/
e.reason = e.channelName + (e.reason ? " " + e.reason : "");
}
else
{
display(getMsg(MSG_ERR_UNKNOWN_CHANNEL, e.channelName),
MT_ERROR);
return;
}
}
}
else
{
// Valid prefix, so get real channel (if it exists...).
e.channel = e.server.getChannel(e.channelName);
if (!e.channel)
{
display(getMsg(MSG_ERR_UNKNOWN_CHANNEL, e.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 (e.channel.active)
{
e.channel.deleteWhenDone = e.deleteWhenDone;
if (!e.reason)
e.reason = "";
e.server.sendData("PART " + e.channel.encodedName + " :" +
fromUnicode(e.reason, e.channel) + "\n");
}
else
{
if (e.deleteWhenDone)
e.channel.dispatch("delete-view");
}
}
function cmdReload(e)
{
dispatch("load " + e.plugin.url);
}
function cmdLoad(e)
{
var ex;
var plugin;
function removeOldPlugin(url)
{
var oldPlugin;
var i = getPluginIndexByURL(url);
if (i == -1)
return -1;
oldPlugin = client.plugins[i];
if (oldPlugin.enabled)
{
if (oldPlugin.API > 0)
{
if (!oldPlugin.disable())
{
display(getMsg(MSG_CANT_DISABLE, oldPlugin.id));
display (getMsg(MSG_ERR_SCRIPTLOAD, e.url));
return null;
}
client.prefManager.removeObserver(oldPlugin.prefManager);
oldPlugin.prefManager.destroy();
}
else if ("disablePlugin" in oldPlugin.scope)
{
oldPlugin.scope.disablePlugin();
}
else
{
display(getMsg(MSG_CANT_DISABLE, oldPlugin.id));
display (getMsg(MSG_ERR_SCRIPTLOAD, e.url));
return null;
}
}
return i;
}
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]};
}
plugin = e.scope.plugin;
plugin.scope = e.scope;
try
{
var rvStr;
var rv = rvStr = client.load(e.url, e.scope);
var index = removeOldPlugin(e.url);
if (index == null)
return null;
if ("init" in plugin)
{
if (!("enable" in plugin) || !("disable" in plugin) ||
!("id" in plugin) || !(plugin.id.match(/^[A-Za-z-_]+$/)))
{
display (getMsg(MSG_ERR_PLUGINAPI, e.url));
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 (index != -1)
client.plugins[index] = plugin;
else
index = client.plugins.push(plugin) - 1;
feedback(e, getMsg(MSG_SUBSCRIPT_LOADED, [e.url, rvStr]), MT_INFO);
if ((plugin.API > 0) && plugin.prefs["enabled"])
dispatch("enable-plugin " + index);
return 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)
{
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]);
}
}
}
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)
{
display(CIRCServer.prototype.VERSION_RPLY);
display(MSG_HOMEPAGE);
}
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 == "-")
{
/* remove alias */
ary = getAlias(e.aliasName);
if (!ary)
{
display(getMsg(MSG_NOT_AN_ALIAS, e.aliasName), MT_ERROR);
return;
}
delete client.commandManager.commands[e.aliasName];
arrayRemoveAt(aliasDefs, ary[0]);
aliasDefs.update();
feedback(e, getMsg(MSG_ALIAS_REMOVED, e.aliasName));
}
else if (e.aliasName)
{
/* add/change alias */
client.commandManager.defineCommand(e.aliasName, e.commandList);
ary = getAlias(e.aliasName);
if (ary)
aliasDefs[ary[0]] = e.aliasName + " = " + e.commandList;
else
aliasDefs.push(e.aliasName + " = " + e.commandList);
aliasDefs.update();
feedback(e, getMsg(MSG_ALIAS_CREATED, [e.aliasName, e.commandList]));
}
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)
{
if (client.networks[n].primServ &&
(client.networks[n].state == NET_ONLINE))
{
client.networks[n].dispatch(command, { reason: reason });
}
}
};
if ((e.command.name == "away") || (e.command.name == "custom-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);
}
if (e.server)
{
if (e.network.state == NET_ONLINE)
{
if (e.network.prefs["awayNick"])
e.server.sendData("NICK " + e.network.prefs["awayNick"] + "\n");
e.server.sendData("AWAY :" + fromUnicode(e.reason, e.network) + "\n");
}
e.network.prefs["away"] = e.reason;
}
else
{
// Client view, do command for all networks.
sendToAllNetworks("away", e.reason);
display(getMsg(MSG_AWAY_ON, e.reason));
}
}
else
{
/* returning */
if (e.server)
{
if (e.network.state == NET_ONLINE)
{
if (e.network.prefs["awayNick"])
e.server.sendData("NICK " + e.network.prefs["nickname"] + "\n");
e.server.sendData("AWAY\n");
}
e.network.prefs["away"] = "";
}
else
{
// Client view, do command for all networks.
sendToAllNetworks("back");
display(MSG_AWAY_OFF);
}
}
}
function cmdOpenAtStartup(e)
{
var url = e.sourceObject.getURL();
var list = client.prefs["initialURLs"];
var index = arrayIndexOf(list, 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(url);
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)
{
// Password is optional, if it is not given, we use a safe prompt.
if (!e.password)
e.password = promptPassword(getMsg(MSG_NEED_OPER_PASSWORD), "");
if (!e.password)
return;
e.server.sendData("OPER " + fromUnicode(e.opername, e.server) + " " +
fromUnicode(e.password, e.server) + "\n");
}
function cmdPass(e)
{
/* Check we are connected, or at least pretending to be connected, so this
* can actually send something.
*/
if ((e.network.state != NET_ONLINE) && !e.server.isConnected)
{
feedback(e, MSG_ERR_NOT_CONNECTED);
return;
}
e.server.sendData("PASS " + 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 &&
("contentWindow" in e.sourceObject.frame) &&
e.sourceObject.frame.contentWindow)
{
e.sourceObject.frame.contentWindow.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)
{
display(e.message);
}
function cmdInvite(e)
{
var channel;
if (!e.channelName)
{
channel = e.channel;
}
else
{
channel = e.server.getChannel(e.channelName);
if (!channel)
{
display(getMsg(MSG_ERR_UNKNOWN_CHANNEL, e.channelName), MT_ERROR);
return;
}
}
channel.invite(e.nickname);
}
function cmdKick(e)
{
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)
{
dispatch("create-tab-for-view", { view: client });
if (!client.messages)
{
client.display(MSG_CLIENT_OPENED);
dispatch("set-current-view", { view: client });
client.display(MSG_WELCOME, "HELLO");
dispatch("networks");
dispatch("commands");
} else {
dispatch("set-current-view", { view: client });
}
}
function cmdNotify(e)
{
var net = e.network;
if (!e.nickname)
{
if (net.prefs["notifyList"].length > 0)
{
/* 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)
{
msgname = (adds.length == 1) ? MSG_NOTIFY_ADDONE :
MSG_NOTIFY_ADDSOME;
display(getMsg(msgname, arraySpeak(adds)));
}
if (subs.length > 0)
{
msgname = (subs.length == 1) ? MSG_NOTIFY_DELONE :
MSG_NOTIFY_DELSOME;
display(getMsg(msgname, arraySpeak(subs)));
}
delete net.onList;
delete net.offList;
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(MSG_COMMASP)));
}
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, e.filename];
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)
{
pm = [e.sourceObject.viewName, e.filename];
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 an 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 = e.sourceObject.frame.contentDocument;
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(MSG_COMMASP)));
if ("channelModes" in server)
{
display(getMsg(MSG_SUPPORTS_CHANMODESA,
server.channelModes.a.join(MSG_COMMASP)));
display(getMsg(MSG_SUPPORTS_CHANMODESB,
server.channelModes.b.join(MSG_COMMASP)));
display(getMsg(MSG_SUPPORTS_CHANMODESC,
server.channelModes.c.join(MSG_COMMASP)));
display(getMsg(MSG_SUPPORTS_CHANMODESD,
server.channelModes.d.join(MSG_COMMASP)));
}
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(MSG_COMMASP)));
}
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(MSG_COMMASP)));
display(getMsg(MSG_SUPPORTS_FLAGSOFF, listB2.join(MSG_COMMASP)));
display(getMsg(MSG_SUPPORTS_MISCOPTIONS, listN.join(MSG_COMMASP)));
}
function cmdDoCommand(e)
{
if (e.cmdName == "cmd_mozillaPrefs")
{
goPreferences('navigator',
'chrome://chatzilla/content/prefpanel/pref-irc.xul',
'navigator');
}
else if (e.cmdName == "cmd_chatzillaPrefs")
{
window.openDialog('chrome://chatzilla/content/config.xul', '',
'chrome,resizable,dialog=no', window);
}
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 cmdTimestampFormat(e)
{
var view = e.sourceObject;
if (e.format != null)
{
view.prefs["timestampFormat"] = e.format;
}
else
{
display(getMsg(MSG_FMT_PREF, ["timestampFormat",
view.prefs["timestampFormat"]]));
}
}
function cmdSetCurrentView(e)
{
if ("lockView" in e.view)
delete e.view.lockView;
setCurrentObject(e.view);
}
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:
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 (!jsenv.HAS_SERVER_SOCKETS)
return display(MSG_DCC_NOT_POSSIBLE);
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.entries[".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.entries[".inline-buttons"].enabled = false;
return true;
}
function cmdDCCClose(e)
{
if (!jsenv.HAS_SERVER_SOCKETS)
return display(MSG_DCC_NOT_POSSIBLE);
if (!client.prefs["dcc.enabled"])
return display(MSG_DCC_NOT_ENABLED);
// If there is no nickname specified, use current view.
if (!e.nickname)
{
if (client.currentObject.TYPE == "IRCDCCChat")
return client.currentObject.abort();
// ...if there is one.
return display(MSG_DCC_ERR_NOCHAT);
}
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 (!jsenv.HAS_SERVER_SOCKETS)
return display(MSG_DCC_NOT_POSSIBLE);
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 nsILocalFile 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.nsILocalFile);
// 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.entries[".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.entries[".inline-buttons"].enabled = false;
return true;
}
function cmdDCCList(e) {
if (!jsenv.HAS_SERVER_SOCKETS)
return display(MSG_DCC_NOT_POSSIBLE);
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,
[Math.floor(100 * c.position / c.size),
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.entries[".inline-buttons"].enabled = true;
display(getMsg(MSG_DCCLIST_LINE, [k + 1, state, dir, type, tf,
c.unicodeName, c.remoteIP, c.port,
cmds]));
client.munger.entries[".inline-buttons"].enabled = false;
}
display(getMsg(MSG_DCCLIST_SUMMARY, [counts.pending, counts.connected,
counts.failed]));
return true;
}
function cmdDCCAutoAcceptList(e)
{
if (!jsenv.HAS_SERVER_SOCKETS)
return display(MSG_DCC_NOT_POSSIBLE);
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 (!jsenv.HAS_SERVER_SOCKETS)
return display(MSG_DCC_NOT_POSSIBLE);
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 (!jsenv.HAS_SERVER_SOCKETS)
return display(MSG_DCC_NOT_POSSIBLE);
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 (!jsenv.HAS_SERVER_SOCKETS)
return display(MSG_DCC_NOT_POSSIBLE);
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 (!jsenv.HAS_SERVER_SOCKETS)
return display(MSG_DCC_NOT_POSSIBLE);
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 cmdTextDirection(e)
{
var direction;
var sourceObject = e.sourceObject.frame.contentDocument.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 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)
{
if (client.prefs["urls.list"].length == 0)
{
display(MSG_URLS_NONE);
}
else
{
/* Store the current URL list, so we can put it back afterwards. This
* is needed because the process of displaying the list changes the
* list! (think about it for a second)
*/
var oldList = client.prefs["urls.list"];
client.prefs["urls.list"] = new Array();
var num = e.number || client.prefs["urls.display"];
if (num > oldList.length)
num = oldList.length;
display(getMsg(MSG_URLS_HEADER, num));
for (var i = 0; i < num; i++)
display(getMsg(MSG_URLS_ITEM, [i + 1, oldList[i]]));
// Restore old URL list so displaying it has no effect.
client.prefs["urls.list"] = oldList;
}
}