mirror of
https://github.com/rn10950/RetroZilla.git
synced 2024-11-15 04:00:12 +01:00
4285 lines
128 KiB
JavaScript
4285 lines
128 KiB
JavaScript
|
/* -*- 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;
|
||
|
}
|
||
|
}
|