PK
f/n9 " skin/modern/chatzilla/contents.rdfUT `"?PVDDUx
chrome://chatzilla/skin/browserOverlay.css
chrome://chatzilla/skin/browserOverlay.css
PK
bi0ׅ] ] ! content/chatzilla/lib/js/utils.jsUT N@PVDDUx /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 JSIRC Library
*
* The Initial Developer of the Original Code is New Dimensions Consulting,
* Inc. Portions created by New Dimensions Consulting, Inc. are
* Copyright (C) 1999 New Dimenstions Consulting, Inc. All
* Rights Reserved.
*
* Contributor(s):
* Robert Ginda, rginda@ndcico.com, original author
*
*
* JavaScript utility functions.
*
* 1999-08-15 rginda@ndcico.com v1.0
*/
var utils = new Object();
var DEBUG = true;
var dd;
if (DEBUG) {
var _dd_pfx = "";
var _dd_singleIndent = " ";
var _dd_indentLength = _dd_singleIndent.length;
var _dd_currentIndent = "";
var _dd_lastDumpWasOpen = false;
var _dd_timeStack = new Array();
var _dd_disableDepth = Number.MAX_VALUE;
var _dd_currentDepth = 0;
dd = function _dd(str) {
if (typeof str != "string") {
dump(str + "\n");
} else if (str == "") {
dump("\n");
} else if (str[str.length - 1] == "{") {
++_dd_currentDepth;
if (_dd_currentDepth >= _dd_disableDepth)
return;
if (str.indexOf("OFF") == 0)
_dd_disableDepth = _dd_currentDepth;
_dd_timeStack.push (new Date());
if (_dd_lastDumpWasOpen)
dump("\n");
dump (_dd_pfx + _dd_currentIndent + str);
_dd_currentIndent += _dd_singleIndent;
_dd_lastDumpWasOpen = true;
} else if (str[0] == "}") {
if (--_dd_currentDepth >= _dd_disableDepth)
return;
_dd_disableDepth = Number.MAX_VALUE;
var sufx = (new Date() - _dd_timeStack.pop()) / 1000 + " sec";
_dd_currentIndent =
_dd_currentIndent.substr(0, _dd_currentIndent.length -
_dd_indentLength);
if (_dd_lastDumpWasOpen)
dump(str + " " + sufx + "\n");
else
dump(_dd_pfx + _dd_currentIndent + str + " " +
sufx + "\n");
_dd_lastDumpWasOpen = false;
} else {
if (_dd_currentDepth >= _dd_disableDepth)
return;
if (_dd_lastDumpWasOpen)
dump("\n");
dump(_dd_pfx + _dd_currentIndent + str + "\n");
_dd_lastDumpWasOpen = false;
}
}
} else {
dd = function (){};
}
var jsenv = new Object();
jsenv.HAS_SECURITYMANAGER = ((typeof netscape == "object") &&
(typeof netscape.security == "object"));
jsenv.HAS_XPCOM = ((typeof Components == "object") &&
(typeof Components.classes == "object"));
jsenv.HAS_JAVA = (typeof java == "object");
jsenv.HAS_RHINO = (typeof defineClass == "function");
jsenv.HAS_DOCUMENT = (typeof document == "object");
jsenv.HAS_NSPR_EVENTQ = jsenv.HAS_DOCUMENT;
jsenv.HAS_STREAM_PROVIDER = ("nsIStreamProvider" in Components.interfaces);
function dumpObject (o, pfx, sep)
{
var p;
var s = "";
sep = (typeof sep == "undefined") ? " = " : sep;
pfx = (typeof pfx == "undefined") ? "" : pfx;
for (p in o)
{
if (typeof (o[p]) != "function")
s += pfx + p + sep + o[p] + "\n";
else
s += pfx + p + sep + "function\n";
}
return s;
}
/* Dumps an object in tree format, recurse specifiec the the number of objects
* to recurse, compress is a boolean that can uncompress (true) the output
* format, and level is the number of levels to intitialy indent (only useful
* internally.) A sample dumpObjectTree (o, 1) is shown below.
*
* + parent (object)
* + users (object)
* | + jsbot (object)
* | + mrjs (object)
* | + nakkezzzz (object)
* | *
* + bans (object)
* | *
* + topic (string) 'ircclient.js:59: nothing is not defined'
* + getUsersLength (function) 9 lines
* *
*/
function dumpObjectTree (o, recurse, compress, level)
{
var s = "";
var pfx = "";
if (typeof recurse == "undefined")
recurse = 0;
if (typeof level == "undefined")
level = 0;
if (typeof compress == "undefined")
compress = true;
for (var i = 0; i < level; i++)
pfx += (compress) ? "| " : "| ";
var tee = (compress) ? "+ " : "+- ";
for (i in o)
{
var t, ex;
try
{
t = typeof o[i];
}
catch (ex)
{
t = "ERROR";
}
switch (t)
{
case "function":
var sfunc = String(o[i]).split("\n");
if (sfunc[2] == " [native code]")
sfunc = "[native code]";
else
if (sfunc.length == 1)
sfunc = String(sfunc);
else
sfunc = sfunc.length + " lines";
s += pfx + tee + i + " (function) " + sfunc + "\n";
break;
case "object":
s += pfx + tee + i + " (object)";
if (o[i] == null)
{
s += " null\n";
break;
}
s += "\n";
if (!compress)
s += pfx + "|\n";
if ((i != "parent") && (recurse))
s += dumpObjectTree (o[i], recurse - 1,
compress, level + 1);
break;
case "string":
if (o[i].length > 200)
s += pfx + tee + i + " (" + t + ") " +
o[i].length + " chars\n";
else
s += pfx + tee + i + " (" + t + ") '" + o[i] + "'\n";
break;
case "ERROR":
s += pfx + tee + i + " (" + t + ") ?\n";
break;
default:
s += pfx + tee + i + " (" + t + ") " + o[i] + "\n";
}
if (!compress)
s += pfx + "|\n";
}
s += pfx + "*\n";
return s;
}
function ecmaEscape(str)
{
function replaceNonPrintables(ch)
{
var rv = ch.charCodeAt().toString(16);
if (rv.length == 1)
rv = "0" + rv;
else if (rv.length == 3)
rv = "u0" + rv;
else if (rv.length == 4)
rv = "u" + rv;
return "%" + rv;
};
// Replace any character that is not in the 69 character set
// [ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./]
// with an escape sequence. Two digit sequences in the form %XX are used
// for characters whose codepoint is less than 255, %uXXXX for all others.
// See section B.2.1 of ECMA-262 rev3 for more information.
return str.replace(/[^A-Za-z0-9@*_+.\-\/]/g, replaceNonPrintables);
}
function ecmaUnescape(str)
{
function replaceEscapes(seq)
{
var ary = seq.match(/([\da-f]{1,2})(.*)|u([\da-f]{1,4})/);
if (!ary)
return "";
var rv;
if (ary[1])
{
// two digit escape, possibly with cruft after
rv = String.fromCharCode(parseInt(ary[1], 16)) + ary[2];
}
else
{
// four digits, no cruft
rv = String.fromCharCode(parseInt(ary[3], 16));
}
return rv;
};
// Replace the escape sequences %X, %XX, %uX, %uXX, %uXXX, and %uXXXX with
// the characters they represent, where X is a hexadecimal digit.
// See section B.2.2 of ECMA-262 rev3 for more information.
return str.replace(/%u?([\da-f]{1,4})/ig, replaceEscapes);
}
function replaceVars(str, vars)
{
// replace "string $with a $variable", with
// "string " + vars["with"] + " with a " + vars["variable"]
function doReplace(symbol)
{
var name = symbol.substr(1);
if (name in vars)
return vars[name];
return "$" + name;
};
return str.replace(/(\$\w[\w\d\-]+)/g, doReplace);
}
function formatException (ex)
{
if (ex instanceof Error)
return getMsg (MSG_FMT_JSEXCEPTION, [ex.name, ex.message, ex.fileName,
ex.lineNumber]);
return String(ex);
}
/*
* Clones an existing object (Only the enumerable properties
* of course.) use as a function..
* var c = Clone (obj);
* or a constructor...
* var c = new Clone (obj);
*/
function Clone (obj)
{
var robj = new Object();
for (var p in obj)
robj[p] = obj[p];
return robj;
}
function Copy(source, dest, overwrite)
{
if (!dest)
dest = new Object();
for (var p in source)
{
if (overwrite || !(p in dest))
dest[p] = source[p];
}
return dest;
}
/*
* matches a real object against one or more pattern objects.
* if you pass an array of pattern objects, |negate| controls wether to check
* if the object matches ANY of the patterns, or NONE of the patterns.
*/
function matchObject (o, pattern, negate)
{
negate = Boolean(negate);
function _match (o, pattern)
{
if (pattern instanceof Function)
return pattern(o);
for (p in pattern)
{
var val;
/* nice to have, but slow as molases, allows you to match
* properties of objects with obj$prop: "foo" syntax */
/*
if (p[0] == "$")
val = eval ("o." +
p.substr(1,p.length).replace (/\$/g, "."));
else
*/
val = o[p];
if (pattern[p] instanceof Function)
{
if (!pattern[p](val))
return false;
}
else
{
var ary = (new String(val)).match(pattern[p]);
if (ary == null)
return false;
else
o.matchresult = ary;
}
}
return true;
}
if (!(pattern instanceof Array))
return Boolean (negate ^ _match(o, pattern));
for (var i in pattern)
if (_match (o, pattern[i]))
return !negate;
return negate;
}
function matchEntry (partialName, list)
{
if ((typeof partialName == "undefined") ||
(String(partialName) == ""))
return list;
var ary = new Array();
for (var i in list)
{
if (list[i].indexOf(partialName) == 0)
ary.push (list[i]);
}
return ary;
}
function encodeChar(ch)
{
return "%" + ch.charCodeAt(0).toString(16);
}
function escapeFileName(fileName)
{
return fileName.replace(/[^\w\d.,#\-_]/g, encodeChar);
}
function getCommonPfx (list)
{
var pfx = list[0];
var l = list.length;
for (var i = 0; i < l; i++)
{
for (var c = 0; c < pfx.length; ++c)
{
if (c >= list[i].length)
{
pfx = pfx.substr (0, c);
break;
}
else
{
if (pfx[c] != list[i][c])
pfx = pfx.substr (0, c);
}
}
}
return pfx;
}
function openTopWin (url)
{
return openDialog (getBrowserURL(), "_blank", "chrome,all,dialog=no", url);
}
function getWindowByType (windowType)
{
const MEDIATOR_CONTRACTID =
"@mozilla.org/appshell/window-mediator;1";
const nsIWindowMediator = Components.interfaces.nsIWindowMediator;
var windowManager =
Components.classes[MEDIATOR_CONTRACTID].getService(nsIWindowMediator);
return windowManager.getMostRecentWindow(windowType);
}
function renameProperty (obj, oldname, newname)
{
if (oldname == newname)
return;
obj[newname] = obj[oldname];
delete obj[oldname];
}
function newObject(contractID, iface)
{
if (!jsenv.HAS_XPCOM)
return null;
var obj = Components.classes[contractID].createInstance();
var rv;
switch (typeof iface)
{
case "string":
rv = obj.QueryInterface(Components.interfaces[iface]);
break;
case "object":
rv = obj.QueryInterface[iface];
break;
default:
rv = null;
break;
}
return rv;
}
function getContentWindow(frame)
{
try
{
if (!frame || !("contentWindow" in frame))
return false;
return frame.contentWindow;
}
catch (ex)
{
// throws exception is contentWindow is gone
return null;
}
}
function getPriv (priv)
{
if (!jsenv.HAS_SECURITYMANAGER)
return true;
var rv = true;
try
{
netscape.security.PrivilegeManager.enablePrivilege(priv);
}
catch (e)
{
dd ("getPriv: unable to get privlege '" + priv + "': " + e);
rv = false;
}
return rv;
}
function len(o)
{
var l = 0;
for (var p in o)
++l;
return l;
}
function keys (o)
{
var rv = new Array();
for (var p in o)
rv.push(p);
return rv;
}
function stringTrim (s)
{
if (!s)
return "";
s = s.replace (/^\s+/, "");
return s.replace (/\s+$/, "");
}
/* the offset should be in seconds, it will be rounded to 2 decimal places */
function formatDateOffset (offset, format)
{
var seconds = roundTo(offset % 60, 2);
var minutes = Math.floor(offset / 60);
var hours = Math.floor(minutes / 60);
minutes = minutes % 60;
var days = Math.floor(hours / 24);
hours = hours % 24;
if (!format)
{
var ary = new Array();
if (days > 0)
ary.push (getMsg(MSG_DAYS, days));
if (hours > 0)
ary.push (getMsg(MSG_HOURS, hours));
if (minutes > 0)
ary.push (getMsg(MSG_MINUTES, minutes));
if (seconds > 0 || offset == 0)
ary.push (getMsg(MSG_SECONDS, seconds));
format = ary.join(", ");
}
else
{
format = format.replace ("%d", days);
format = format.replace ("%h", hours);
format = format.replace ("%m", minutes);
format = format.replace ("%s", seconds);
}
return format;
}
function arrayHasElementAt(ary, i)
{
return typeof ary[i] != "undefined";
}
function arrayContains (ary, elem)
{
return (arrayIndexOf (ary, elem) != -1);
}
function arrayIndexOf (ary, elem)
{
for (var i in ary)
if (ary[i] == elem)
return i;
return -1;
}
function arrayInsertAt (ary, i, o)
{
ary.splice (i, 0, o);
}
function arrayRemoveAt (ary, i)
{
ary.splice (i, 1);
}
/* length should be an even number >= 6 */
function abbreviateWord (str, length)
{
if (str.length <= length || length < 6)
return str;
var left = str.substr (0, (length / 2) - 1);
var right = str.substr (str.length - (length / 2) + 1);
return left + "..." + right;
}
/*
* Inserts the string |hyphen| into string |str| every |pos| characters.
* If there are any wordbreaking characters in |str| within -/+5 characters of
* of a |pos| then the hyphen is inserted there instead, in order to produce a
* "cleaner" break.
*/
function hyphenateWord (str, pos, hyphen)
{
if (str.length <= pos)
return str;
if (typeof hyphen == "undefined")
hyphen = " ";
/* search for a nice place to break the word, fuzzfactor of +/-5, centered
* around |pos| */
var splitPos =
str.substring(pos - 5, pos + 5).search(/[^A-Za-z0-9]/);
splitPos = (splitPos != -1) ? pos - 4 + splitPos : pos;
var left = str.substr (0, splitPos);
var right = hyphenateWord(str.substr (splitPos), pos, hyphen);
return left + hyphen + right;
}
/*
* Like hyphenateWord, except individual chunks of the word are returned as
* elements of an array.
*/
function splitLongWord (str, pos)
{
if (str.length <= pos)
return [str];
var ary = new Array();
var right = str;
while (right.length > pos)
{
/* search for a nice place to break the word, fuzzfactor of +/-5,
* centered around |pos| */
var splitPos =
right.substring(pos - 5, pos + 5).search(/[^A-Za-z0-9]/);
splitPos = (splitPos != -1) ? pos - 4 + splitPos : pos;
ary.push(right.substr (0, splitPos));
right = right.substr (splitPos);
}
ary.push (right);
return ary;
}
function getRandomElement (ary)
{
return ary[Math.floor(Math.random() * ary.length)];
}
function roundTo (num, prec)
{
return Math.round(num * Math.pow (10, prec)) / Math.pow (10, prec);
}
function randomRange (min, max)
{
if (typeof min == "undefined")
min = 0;
if (typeof max == "undefined")
max = 1;
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function getStackTrace ()
{
if (!jsenv.HAS_XPCOM)
return "No stack trace available.";
var frame = Components.stack.caller;
var str = "";
while (frame)
{
var name = frame.name ? frame.name : "[anonymous]";
str += "\n" + name + "@" + frame.lineNumber;
frame = frame.caller;
}
return str;
}
function getInterfaces (cls)
{
if (!jsenv.HAS_XPCOM)
return null;
var rv = new Object();
var e;
for (var i in Components.interfaces)
{
try
{
var ifc = Components.interfaces[i];
cls.QueryInterface(ifc);
rv[i] = ifc;
}
catch (e)
{
/* nada */
}
}
return rv;
}
/**
* Calls a named function for each element in an array, sending
* the same parameter each call.
*
* @param ary an array of objects
* @param func_name string name of function to call.
* @param data data object to pass to each object.
*/
function mapObjFunc(ary, func_name, data)
{
/*
* WARNING: Caller assumes resonsibility to verify ary
* and func_name
*/
for (var i in ary)
ary[i][func_name](data);
}
/**
* Passes each element of an array to a given function object.
*
* @param func a function object.
* @param ary an array of values.
*/
function map(func, ary) {
/*
* WARNING: Caller assumnes responsibility to verify
* func and ary.
*/
for (var i in ary)
func(ary[i]);
}
function getSpecialDirectory(name)
{
if (!("directoryService" in utils))
{
const DS_CTR = "@mozilla.org/file/directory_service;1";
const nsIProperties = Components.interfaces.nsIProperties;
utils.directoryService =
Components.classes[DS_CTR].getService(nsIProperties);
}
return utils.directoryService.get(name, Components.interfaces.nsIFile);
}
function getFileFromURLSpec(url)
{
const FILE_CTRID = "@mozilla.org/network/protocol;1?name=file";
const nsIFileProtocolHandler = Components.interfaces.nsIFileProtocolHandler;
var handler = Components.classes[FILE_CTRID].createInstance();
handler = handler.QueryInterface(nsIFileProtocolHandler);
return handler.getFileFromURLSpec(url);
}
function getURLSpecFromFile (file)
{
if (!file)
return null;
const IOS_CTRID = "@mozilla.org/network/io-service;1";
const LOCALFILE_CTRID = "@mozilla.org/file/local;1";
const nsIIOService = Components.interfaces.nsIIOService;
const nsILocalFile = Components.interfaces.nsILocalFile;
if (typeof file == "string")
{
var fileObj =
Components.classes[LOCALFILE_CTRID].createInstance(nsILocalFile);
fileObj.initWithPath(file);
file = fileObj;
}
var service = Components.classes[IOS_CTRID].getService(nsIIOService);
/* In sept 2002, bug 166792 moved this method to the nsIFileProtocolHandler
* interface, but we need to support older versions too. */
if ("getURLSpecFromFile" in service)
return service.getURLSpecFromFile(file);
var nsIFileProtocolHandler = Components.interfaces.nsIFileProtocolHandler;
var fileHandler = service.getProtocolHandler("file");
fileHandler = fileHandler.QueryInterface(nsIFileProtocolHandler);
return fileHandler.getURLSpecFromFile(file);
}
function alert(msg, parent, title)
{
var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
var nsIPromptService = Components.interfaces.nsIPromptService;
var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
if (!parent)
parent = window;
if (!title)
title = MSG_ALERT;
ps.alert (parent, title, msg);
}
function confirm(msg, parent, title)
{
var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
var nsIPromptService = Components.interfaces.nsIPromptService;
var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
if (!parent)
parent = window;
if (!title)
title = MSG_CONFIRM;
return ps.confirm (parent, title, msg);
}
function prompt(msg, initial, parent, title)
{
var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
var nsIPromptService = Components.interfaces.nsIPromptService;
var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
if (!parent)
parent = window;
if (!title)
title = MSG_PROMPT;
rv = { value: initial };
if (!ps.prompt (parent, title, msg, rv, null, {value: null}))
return null;
return rv.value;
}
function promptPassword(msg, initial, parent, title)
{
var PROMPT_CTRID = "@mozilla.org/embedcomp/prompt-service;1";
var nsIPromptService = Components.interfaces.nsIPromptService;
var ps = Components.classes[PROMPT_CTRID].getService(nsIPromptService);
if (!parent)
parent = window;
if (!title)
title = MSG_PROMPT;
rv = { value: initial };
if (!ps.promptPassword (parent, title, msg, rv, null, {value: null}))
return null;
return rv.value;
}
function getHostmaskParts(hostmask)
{
var rv;
// A bit cheeky this, we try the matches here, and then branch
// according to the ones we like.
var ary1 = hostmask.match(/(\S*)!(\S*)@(.*)/);
var ary2 = hostmask.match(/(\S*)@(.*)/);
var ary3 = hostmask.match(/(\S*)!(.*)/);
if (ary1)
rv = { nick: ary1[1], user: ary1[2], host: ary1[3] };
else if (ary2)
rv = { nick: "*", user: ary2[1], host: ary2[2] };
else if (ary3)
rv = { nick: ary3[1], user: ary3[2], host: "*" };
else
rv = { nick: hostmask, user: "*", host: "*" };
// Make sure we got something for all fields.
if (!rv.nick)
rv.nick = "*";
if (!rv.user)
rv.user = "*";
if (!rv.host)
rv.host = "*";
// And re-construct the 'parsed' hostmask.
rv.mask = rv.nick + "!" + rv.user + "@" + rv.host;
return rv;
}
PK
J/12rJ J " content/chatzilla/lib/js/events.jsUT L?PVDDUx /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 JSIRC Library
*
* The Initial Developer of the Original Code is New Dimensions Consulting,
* Inc. Portions created by New Dimensions Consulting, Inc. are
* Copyright (C) 1999 New Dimenstions Consulting, Inc. All
* Rights Reserved.
*
* Contributor(s):
* Robert Ginda, rginda@ndcico.com, original author
*
* depends on utils.js
*
* Event and EventPump classes. The EventPump maintains a queue of event
* objects. To inject an event into this queue, use |EventPump.addEvent|.
* |EventQueue.routeEvents| steps at most |EventPump.eventsPerStep|
* events, and then returns control.
*
* 1999-08-15 rginda@ndcico.com v1.0
*
*/
/*
* event class
*/
function CEvent (set, type, destObject, destMethod)
{
this.set = set;
this.type = type;
this.destObject = destObject;
this.destMethod = destMethod;
this.hooks = new Array();
}
/*
* event pump
*/
function CEventPump (eventsPerStep)
{
/* event routing stops after this many levels, safety valve */
this.MAX_EVENT_DEPTH = 50;
this.eventsPerStep = eventsPerStep;
this.queue = new Array();
this.hooks = new Array();
}
CEventPump.prototype.onHook =
function ep_hook(e, hooks)
{
var h;
if (typeof hooks == "undefined")
hooks = this.hooks;
hook_loop:
for (h = hooks.length - 1; h >= 0; h--)
{
if (!hooks[h].enabled ||
!matchObject (e, hooks[h].pattern, hooks[h].neg))
continue hook_loop;
e.hooks.push (hooks[h]);
var rv = hooks[h].f(e);
if ((typeof rv == "boolean") &&
(rv == false))
{
dd ("hook #" + h + " '" +
((typeof hooks[h].name != "undefined") ? hooks[h].name :
"") + "' stopped hook processing.");
return true;
}
}
return false;
}
CEventPump.prototype.addHook =
function ep_addhook(pattern, f, name, neg, enabled, hooks)
{
if (typeof hooks == "undefined")
hooks = this.hooks;
if (typeof f != "function")
return false;
if (typeof enabled == "undefined")
enabled = true;
else
enabled = Boolean(enabled);
neg = Boolean(neg);
var hook = {
pattern: pattern,
f: f,
name: name,
neg: neg,
enabled: enabled
};
hooks.push(hook);
return hook;
}
CEventPump.prototype.getHook =
function ep_gethook(name, hooks)
{
if (typeof hooks == "undefined")
hooks = this.hooks;
for (var h in hooks)
if (hooks[h].name.toLowerCase() == name.toLowerCase())
return hooks[h];
return null;
}
CEventPump.prototype.removeHookByName =
function ep_remhookname(name, hooks)
{
if (typeof hooks == "undefined")
hooks = this.hooks;
for (var h in hooks)
if (hooks[h].name.toLowerCase() == name.toLowerCase())
{
arrayRemoveAt (hooks, h);
return true;
}
return false;
}
CEventPump.prototype.removeHookByIndex =
function ep_remhooki(idx, hooks)
{
if (typeof hooks == "undefined")
hooks = this.hooks;
return arrayRemoveAt (hooks, idx);
}
CEventPump.prototype.addEvent =
function ep_addevent (e)
{
e.queuedAt = new Date();
arrayInsertAt(this.queue, 0, e);
return true;
}
CEventPump.prototype.routeEvent =
function ep_routeevent (e)
{
var count = 0;
this.currentEvent = e;
e.level = 0;
while (e.destObject)
{
e.level++;
this.onHook (e);
var destObject = e.destObject;
e.currentObject = destObject;
e.destObject = (void 0);
switch (typeof destObject[e.destMethod])
{
case "function":
if (1)
try
{
destObject[e.destMethod] (e);
}
catch (ex)
{
if (typeof ex == "string")
{
dd ("Error routing event " + e.set + "." +
e.type + ": " + ex);
}
else
{
dd ("Error routing event " + e.set + "." +
e.type + ": " + dumpObjectTree(ex) +
" in " + e.destMethod + "\n" + ex);
if ("stack" in ex)
dd(ex.stack);
}
}
else
destObject[e.destMethod] (e);
if (count++ > this.MAX_EVENT_DEPTH)
throw "Too many events in chain";
break;
case "undefined":
//dd ("** " + e.destMethod + " does not exist.");
break;
default:
dd ("** " + e.destMethod + " is not a function.");
}
if ((e.type != "event-end") && (!e.destObject))
{
e.lastSet = e.set;
e.set = "eventpump";
e.lastType = e.type;
e.type = "event-end";
e.destMethod = "onEventEnd";
e.destObject = this;
}
}
delete this.currentEvent;
return true;
}
CEventPump.prototype.stepEvents =
function ep_stepevents()
{
var i = 0;
while (i < this.eventsPerStep)
{
var e = this.queue.pop();
if (!e || e.type == "yield")
break;
this.routeEvent (e);
i++;
}
return true;
}
PK
ft/7R) ) , content/chatzilla/lib/js/connection-xpcom.jsUT FA?PVDDUx /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 JSIRC Library
*
* The Initial Developer of the Original Code is New Dimensions Consulting,
* Inc. Portions created by New Dimensions Consulting, Inc. are
* Copyright (C) 1999 New Dimenstions Consulting, Inc. All
* Rights Reserved.
*
* Contributor(s):
* Robert Ginda, rginda@ndcico.com, original author
* Peter Van der Beken, peter.vanderbeken@pandora.be, necko-only version
*
* depends on utils.js, and XPCOM/XPConnect in the JS environment
*
*/
const NS_ERROR_MODULE_NETWORK = 2152398848;
const NS_ERROR_UNKNOWN_HOST = NS_ERROR_MODULE_NETWORK + 30;
const NS_ERROR_CONNECTION_REFUSED = NS_ERROR_MODULE_NETWORK + 13;
const NS_ERROR_NET_TIMEOUT = NS_ERROR_MODULE_NETWORK + 14;
const NS_NET_STATUS_RESOLVING_HOST = NS_ERROR_MODULE_NETWORK + 3;
const NS_NET_STATUS_CONNECTED_TO = NS_ERROR_MODULE_NETWORK + 4;
const NS_NET_STATUS_SENDING_TO = NS_ERROR_MODULE_NETWORK + 5;
const NS_NET_STATUS_RECEIVING_FROM = NS_ERROR_MODULE_NETWORK + 6;
const NS_NET_STATUS_CONNECTING_TO = NS_ERROR_MODULE_NETWORK + 7;
function toScriptableInputStream (i)
{
var si = Components.classes["@mozilla.org/scriptableinputstream;1"];
si = si.createInstance();
si = si.QueryInterface(Components.interfaces.nsIScriptableInputStream);
si.init(i);
return si;
}
function CBSConnection ()
{
var sockServiceClass =
Components.classesByID["{c07e81e0-ef12-11d2-92b6-00105a1b0d64}"];
if (!sockServiceClass)
throw ("Couldn't get socket service class.");
var sockService = sockServiceClass.getService();
if (!sockService)
throw ("Couldn't get socket service.");
this._sockService = sockService.QueryInterface
(Components.interfaces.nsISocketTransportService);
this.wrappedJSObject = this;
}
CBSConnection.prototype.connect =
function bc_connect(host, port, bind, tcp_flag, observer)
{
if (typeof tcp_flag == "undefined")
tcp_flag = false;
this.host = host.toLowerCase();
this.port = port;
this.bind = bind;
this.tcp_flag = tcp_flag;
// Lets get a transportInfo for this
var cls =
Components.classes["@mozilla.org/network/protocol-proxy-service;1"];
var pps = cls.getService(Components.interfaces.nsIProtocolProxyService);
if (!pps)
throw ("Couldn't get protocol proxy service");
var ios = Components.classes["@mozilla.org/network/io-service;1"].
getService(Components.interfaces.nsIIOService);
var spec = "irc://" + host + ':' + port;
var uri = ios.newURI(spec,null,null);
var info = pps.examineForProxy(uri);
if (jsenv.HAS_STREAM_PROVIDER)
{
this._transport = this._sockService.createTransport (host, port, info,
0, 0);
if (!this._transport)
throw ("Error creating transport.");
if (jsenv.HAS_NSPR_EVENTQ)
{ /* we've got an event queue, so start up an async write */
this._streamProvider = new StreamProvider (observer);
this._write_req =
this._transport.asyncWrite (this._streamProvider, this,
0, -1, 0);
}
else
{
/* no nspr event queues in this environment, we can't use async
* calls, so set up the streams. */
this._outputStream = this._transport.openOutputStream(0, -1, 0);
if (!this._outputStream)
throw "Error getting output stream.";
this._inputStream =
toScriptableInputStream(this._transport.openInputStream(0,
-1, 0));
if (!this._inputStream)
throw "Error getting input stream.";
}
}
else
{
/* use new necko interfaces */
this._transport = this._sockService.createTransport(null, 0, host, port,
info);
if (!this._transport)
throw ("Error creating transport.");
/* if we don't have an event queue, then all i/o must be blocking */
var openFlags;
if (jsenv.HAS_NSPR_EVENTQ)
openFlags = 0;
else
openFlags = Components.interfaces.nsITransport.OPEN_BLOCKING;
/* no limit on the output stream buffer */
this._outputStream =
this._transport.openOutputStream(openFlags, 4096, -1);
if (!this._outputStream)
throw "Error getting output stream.";
this._inputStream = this._transport.openInputStream(openFlags, 0, 0);
if (!this._inputStream)
throw "Error getting input stream.";
}
this.connectDate = new Date();
this.isConnected = true;
return this.isConnected;
}
CBSConnection.prototype.disconnect =
function bc_disconnect()
{
if ("_inputStream" in this && this._inputStream)
this._inputStream.close();
if ("_outputStream" in this && this._outputStream)
this._outputStream.close();
this.isConnected = false;
/*
this._streamProvider.close();
if (this._streamProvider.isBlocked)
this._write_req.resume();
*/
}
CBSConnection.prototype.sendData =
function bc_senddata(str)
{
if (!this.isConnected)
throw "Not Connected.";
if (jsenv.HAS_NSPR_EVENTQ && jsenv.HAS_STREAM_PROVIDER)
this.asyncWrite (str);
else
this.sendDataNow (str);
}
CBSConnection.prototype.readData =
function bc_readdata(timeout, count)
{
if (!this.isConnected)
throw "Not Connected.";
var rv;
try
{
rv = this._scriptableInputStream.read (count);
}
catch (ex)
{
dd ("*** Caught " + ex + " while reading.");
this.disconnect();
throw (ex);
}
return rv;
}
CBSConnection.prototype.startAsyncRead =
function bc_saread (observer)
{
if (jsenv.HAS_STREAM_PROVIDER)
{
this._transport.asyncRead (new StreamListener (observer),
this, 0, -1, 0);
}
else
{
var cls = Components.classes["@mozilla.org/network/input-stream-pump;1"];
var pump = cls.createInstance(Components.interfaces.nsIInputStreamPump);
pump.init(this._inputStream, -1, -1, 0, 0, false);
pump.asyncRead(new StreamListener(observer), this);
}
}
CBSConnection.prototype.asyncWrite =
function bc_awrite (str)
{
this._streamProvider.pendingData += str;
if (this._streamProvider.isBlocked)
{
this._write_req.resume();
this._streamProvider.isBlocked = false;
}
}
CBSConnection.prototype.hasPendingWrite =
function bc_haspwrite ()
{
if (jsenv.HAS_STREAM_PROVIDER)
return (this._streamProvider.pendingData != "");
else
return false; /* data already pushed to necko */
}
CBSConnection.prototype.sendDataNow =
function bc_senddatanow(str)
{
var rv = false;
try
{
this._outputStream.write(str, str.length);
rv = true;
}
catch (ex)
{
dd ("*** Caught " + ex + " while sending.");
this.disconnect();
throw (ex);
}
return rv;
}
function _notimpl ()
{
throw "Not Implemented.";
}
if (!jsenv.HAS_NSPR_EVENTQ)
{
CBSConnection.prototype.startAsyncRead = _notimpl;
CBSConnection.prototype.asyncWrite = _notimpl;
}
else if (jsenv.HAS_STREAM_PROVIDER)
{
CBSConnection.prototype.sendDataNow = _notimpl;
}
else
{
CBSConnection.prototype.asyncWrite = _notimpl;
}
delete _notimpl;
function StreamProvider(observer)
{
this._observer = observer;
}
StreamProvider.prototype.pendingData = "";
StreamProvider.prototype.isBlocked = true;
StreamProvider.prototype.close =
function sp_close ()
{
this.isClosed = true;
}
StreamProvider.prototype.onDataWritable =
function sp_datawrite (request, ctxt, ostream, offset, count)
{
//dd ("StreamProvider.prototype.onDataWritable");
if ("isClosed" in this && this.isClosed)
throw Components.results.NS_BASE_STREAM_CLOSED;
if (!this.pendingData)
{
this.isBlocked = true;
/* this is here to support pre-XPCDOM builds (0.9.0 era), which
* don't have this result code mapped. */
if (!Components.results.NS_BASE_STREAM_WOULD_BLOCK)
throw 2152136711;
throw Components.results.NS_BASE_STREAM_WOULD_BLOCK;
}
var len = ostream.write (this.pendingData, this.pendingData.length);
this.pendingData = this.pendingData.substr (len);
}
StreamProvider.prototype.onStartRequest =
function sp_startreq (request, ctxt)
{
//dd ("StreamProvider::onStartRequest: " + request + ", " + ctxt);
}
StreamProvider.prototype.onStopRequest =
function sp_stopreq (request, ctxt, status)
{
//dd ("StreamProvider::onStopRequest: " + request + ", " + ctxt + ", " +
// status);
if (this._observer)
this._observer.onStreamClose(status);
}
function StreamListener(observer)
{
this._observer = observer;
}
StreamListener.prototype.onStartRequest =
function sl_startreq (request, ctxt)
{
//dd ("StreamListener::onStartRequest: " + request + ", " + ctxt);
}
StreamListener.prototype.onStopRequest =
function sl_stopreq (request, ctxt, status)
{
//dd ("StreamListener::onStopRequest: " + request + ", " + ctxt + ", " +
//status);
if (this._observer)
this._observer.onStreamClose(status);
}
StreamListener.prototype.onDataAvailable =
function sl_dataavail (request, ctxt, inStr, sourceOffset, count)
{
ctxt = ctxt.wrappedJSObject;
if (!ctxt)
{
dd ("*** Can't get wrappedJSObject from ctxt in " +
"StreamListener.onDataAvailable ***");
return;
}
if (!("_scriptableInputStream" in ctxt))
ctxt._scriptableInputStream = toScriptableInputStream (inStr);
if (this._observer)
this._observer.onStreamDataAvailable(request, inStr, sourceOffset,
count);
}
PK
[X/] ] + content/chatzilla/lib/js/command-manager.jsUT o?PVDDUx /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 JSIRC Library
*
* The Initial Developer of the Original Code is New Dimensions Consulting,
* Inc. Portions created by New Dimensions Consulting, Inc. are
* Copyright (C) 1999 New Dimenstions Consulting, Inc. All
* Rights Reserved.
*
* Contributor(s):
* Robert Ginda, rginda@ndcico.com, original author
*/
function getAccessKey (str)
{
var i = str.indexOf("&");
if (i == -1)
return "";
return str[i + 1];
}
function CommandRecord (name, func, usage, help, label, flags, keystr, tip,
format)
{
this.name = name;
this.func = func;
this._usage = usage;
this.scanUsage();
this.help = help;
this.label = label ? label : name;
this.format = format;
this.labelstr = label.replace ("&", "");
this.tip = tip;
this.flags = flags;
this._enabled = true;
this.keyNodes = new Array();
this.keystr = keystr;
this.uiElements = new Array();
}
CommandRecord.prototype.__defineGetter__ ("enabled", cr_getenable);
function cr_getenable ()
{
return this._enabled;
}
CommandRecord.prototype.__defineSetter__ ("enabled", cr_setenable);
function cr_setenable (state)
{
for (var i = 0; i < this.uiElements.length; ++i)
{
if (state)
this.uiElements[i].removeAttribute ("disabled");
else
this.uiElements[i].setAttribute ("disabled", "true");
}
return (this._enabled = state);
}
CommandRecord.prototype.__defineSetter__ ("usage", cr_setusage);
function cr_setusage (usage)
{
this._usage = usage;
this.scanUsage();
}
CommandRecord.prototype.__defineGetter__ ("usage", cr_getusage);
function cr_getusage()
{
return this._usage;
}
/**
* Internal use only.
*
* Scans the argument spec, in the format " [ ]", into an
* array of strings.
*/
CommandRecord.prototype.scanUsage =
function cr_scanusage()
{
var spec = this._usage;
var currentName = "";
var inName = false;
var len = spec.length;
var capNext = false;
this._usage = spec;
this.argNames = new Array();
for (var i = 0; i < len; ++i)
{
switch (spec[i])
{
case '[':
this.argNames.push (":");
break;
case '<':
inName = true;
break;
case '-':
capNext = true;
break;
case '>':
inName = false;
this.argNames.push (currentName);
currentName = "";
capNext = false;
break;
default:
if (inName)
currentName += capNext ? spec[i].toUpperCase() : spec[i];
capNext = false;
break;
}
}
}
/**
* Returns the command formatted for presentation as part of online
* documentation.
*/
CommandRecord.prototype.getDocumentation =
function cr_getdocs(flagFormatter)
{
var str;
str = getMsg(MSG_DOC_COMMANDLABEL,
[this.label.replace("&", ""), this.name]) + "\n";
str += getMsg(MSG_DOC_KEY, this.keystr ? this.keystr : MSG_VAL_NA) + "\n";
str += getMsg(MSG_DOC_SYNTAX, [this.name, this.usage]) + "\n";
str += MSG_DOC_NOTES + "\n";
str += (flagFormatter ? flagFormatter(this.flags) : this.flags) + "\n\n";
str += MSG_DOC_DESCRIPTION + "\n";
str += wrapText(this.help, 75) + "\n";
return str;
}
CommandRecord.prototype.argNames = new Array();
function CommandManager (defaultBundle)
{
this.commands = new Object();
this.defaultBundle = defaultBundle;
}
CommandManager.prototype.defaultFlags = 0;
CommandManager.prototype.defineCommands =
function cmgr_defcmds (cmdary)
{
var len = cmdary.length;
var commands = new Object();
var bundle = "stringBundle" in cmdary ? cmdary.stringBundle : null;
for (var i = 0; i < len; ++i)
{
var name = cmdary[i][0];
var func = cmdary[i][1];
var flags = cmdary[i][2];
var usage;
if (3 in cmdary[i])
usage = cmdary[i][3];
var command = this.defineCommand(name, func, flags, usage, bundle);
commands[name] = command;
}
return commands;
}
CommandManager.prototype.defineCommand =
function cmdmgr_defcmd (name, func, flags, usage, bundle)
{
if (!bundle)
bundle = this.defaultBundle;
var helpDefault;
var labelDefault = name;
var aliasFor;
if (typeof flags != "number")
flags = this.defaultFlags;
if (flags & CMD_NO_HELP)
helpDefault = MSG_NO_HELP;
if (typeof usage != "string")
usage = getMsgFrom(bundle, "cmd." + name + ".params", null, "");
if (typeof func == "string")
{
var ary = func.match(/(\S+)/);
if (ary)
aliasFor = ary[1];
else
aliasFor = null;
helpDefault = getMsg (MSG_DEFAULT_ALIAS_HELP, func);
if (aliasFor)
labelDefault = getMsgFrom (bundle, "cmd." + aliasFor + ".label",
null, name);
}
var label = getMsgFrom(bundle, "cmd." + name + ".label", null,
labelDefault);
var help = getMsgFrom(bundle, "cmd." + name + ".help", null,
helpDefault);
var keystr = getMsgFrom (bundle, "cmd." + name + ".key", null, "");
var format = getMsgFrom (bundle, "cmd." + name + ".format", null, null);
var tip = getMsgFrom (bundle, "cmd." + name + ".tip", null, "");
var command = new CommandRecord (name, func, usage, help, label, flags,
keystr, tip, format);
this.addCommand(command);
if (aliasFor)
command.aliasFor = aliasFor;
return command;
}
CommandManager.prototype.installKeys =
function cmgr_instkeys (document, commands)
{
var parentElem = document.getElementById("dynamic-keys");
if (!parentElem)
{
parentElem = document.createElement("keyset");
parentElem.setAttribute ("id", "dynamic-keys");
document.firstChild.appendChild (parentElem);
}
if (!commands)
commands = this.commands;
for (var c in commands)
this.installKey (parentElem, commands[c]);
}
/**
* Create a node relative to a DOM node. Usually called once per command,
* per document, so that accelerator keys work in all application windows.
*
* @param parentElem A reference to the DOM node which should contain the new
* node.
* @param command reference to the CommandRecord to install.
*/
CommandManager.prototype.installKey =
function cmgr_instkey (parentElem, command)
{
if (!command.keystr)
return;
var ary = command.keystr.match (/(.*\s)?([\S]+)$/);
if (!ASSERT(ary, "couldn't parse key string ``" + command.keystr +
"'' for command ``" + command.name + "''"))
{
return;
}
var key = document.createElement ("key");
key.setAttribute ("id", "key:" + command.name);
key.setAttribute ("oncommand", "dispatch('" + command.name +
"', {isInteractive: true});");
key.setAttribute ("modifiers", ary[1]);
if (ary[2].indexOf("VK_") == 0)
key.setAttribute ("keycode", ary[2]);
else
key.setAttribute ("key", ary[2]);
parentElem.appendChild(key);
command.keyNodes.push(key);
}
CommandManager.prototype.uninstallKeys =
function cmgr_uninstkeys (commands)
{
if (!commands)
commands = this.commands;
for (var c in commands)
this.uninstallKey (commands[c]);
}
CommandManager.prototype.uninstallKey =
function cmgr_uninstkey (command)
{
for (var i in command.keyNodes)
{
try
{
/* document may no longer exist in a useful state. */
command.keyNodes[i].parentNode.removeChild(command.keyNodes[i]);
}
catch (ex)
{
dd ("*** caught exception uninstalling key node: " + ex);
}
}
}
/**
* Register a new command with the manager.
*/
CommandManager.prototype.addCommand =
function cmgr_add (command)
{
this.commands[command.name] = command;
}
CommandManager.prototype.removeCommands =
function cmgr_removes (commands)
{
for (var c in commands)
this.removeCommand(commands[c]);
}
CommandManager.prototype.removeCommand =
function cmgr_remove (command)
{
delete this.commands[command.name];
}
/**
* Register a hook for a particular command name. |id| is a human readable
* identifier for the hook, and can be used to unregister the hook. If you
* re-use a hook id, the previous hook function will be replaced.
* If |before| is |true|, the hook will be called *before* the command executes,
* if |before| is |false|, or not specified, the hook will be called *after*
* the command executes.
*/
CommandManager.prototype.addHook =
function cmgr_hook (commandName, func, id, before)
{
if (!ASSERT(commandName in this.commands,
"Unknown command '" + commandName + "'"))
{
return;
}
var command = this.commands[commandName];
if (before)
{
if (!("beforeHooks" in command))
command.beforeHooks = new Object();
command.beforeHooks[id] = func;
}
else
{
if (!("afterHooks" in command))
command.afterHooks = new Object();
command.afterHooks[id] = func;
}
}
CommandManager.prototype.addHooks =
function cmgr_hooks (hooks, prefix)
{
if (!prefix)
prefix = "";
for (var h in hooks)
{
this.addHook(h, hooks[h], prefix + ":" + h,
("_before" in hooks[h]) ? hooks[h]._before : false);
}
}
CommandManager.prototype.removeHooks =
function cmgr_remhooks (hooks, prefix)
{
if (!prefix)
prefix = "";
for (var h in hooks)
{
this.removeHook(h, prefix + ":" + h,
("before" in hooks[h]) ? hooks[h].before : false);
}
}
CommandManager.prototype.removeHook =
function cmgr_unhook (commandName, id, before)
{
var command = this.commands[commandName];
if (before)
delete command.beforeHooks[id];
else
delete command.afterHooks[id];
}
/**
* Return an array of all CommandRecords which start with the string
* |partialName|, sorted by |label| property.
*
* @param partialName Prefix to search for.
* @param flags logical ANDed with command flags.
* @returns array Array of matching commands, sorted by |label| property.
*/
CommandManager.prototype.list =
function cmgr_list (partialName, flags)
{
/* returns array of command objects which look like |partialName|, or
* all commands if |partialName| is not specified */
function compare (a, b)
{
a = a.labelstr.toLowerCase();
b = b.labelstr.toLowerCase();
if (a == b)
return 0;
if (a > b)
return 1;
return -1;
}
var ary = new Array();
var commandNames = keys(this.commands);
/* a command named "eval" wouldn't show up in the result of keys() because
* eval is not-enumerable, even if overwritten. */
if ("eval" in this.commands && typeof this.commands.eval == "object")
commandNames.push ("eval");
for (var i in commandNames)
{
var name = commandNames[i];
if (!flags || (this.commands[name].flags & flags))
{
if (!partialName ||
this.commands[name].name.indexOf(partialName) == 0)
{
if (partialName &&
partialName.length == this.commands[name].name.length)
{
/* exact match */
return [this.commands[name]];
}
else
{
ary.push (this.commands[name]);
}
}
}
}
ary.sort(compare);
return ary;
}
/**
* Return a sorted array of the command names which start with the string
* |partialName|.
*
* @param partialName Prefix to search for.
* @param flags logical ANDed with command flags.
* @returns array Sorted Array of matching command names.
*/
CommandManager.prototype.listNames =
function cmgr_listnames (partialName, flags)
{
var cmds = this.list(partialName, flags);
var cmdNames = new Array();
for (var c in cmds)
cmdNames.push (cmds[c].name);
cmdNames.sort();
return cmdNames;
}
/**
* Internal use only.
*
* Called to parse the arguments stored in |e.inputData|, as properties of |e|,
* for the CommandRecord stored on |e.command|.
*
* @params e Event object to be processed.
*/
CommandManager.prototype.parseArguments =
function cmgr_parseargs (e)
{
var rv = this.parseArgumentsRaw(e);
//dd("parseArguments '" + e.command.usage + "' " +
// (rv ? "passed" : "failed") + "\n" + dumpObjectTree(e));
delete e.currentArgIndex;
return rv;
}
/**
* Internal use only.
*
* Don't call parseArgumentsRaw directly, use parseArguments instead.
*
* Parses the arguments stored in the |inputData| property of the event object,
* according to the format specified by the |command| property.
*
* On success this method returns true, and propery names corresponding to the
* argument names used in the format spec will be created on the event object.
* All optional parameters will be initialized to |null| if not already present
* on the event.
*
* On failure this method returns false and a description of the problem
* will be stored in the |parseError| property of the event.
*
* For example...
* Given the argument spec " [ ]", and given the
* input string "411 foo", stored as |e.command.usage| and |e.inputData|
* respectively, this method would add the following propertys to the event
* object...
* -name---value--notes-
* e.int 411 Parsed as an integer
* e.word foo Parsed as a string
* e.word2 null Optional parameters not specified will be set to null.
* e.word3 null If word2 had been provided, word3 would be required too.
*
* Each parameter is parsed by calling the function with the same name, located
* in this.argTypes. The first parameter is parsed by calling the function
* this.argTypes["int"], for example. This function is expected to act on
* e.unparsedData, taking it's chunk, and leaving the rest of the string.
* The default parse functions are...
* parses contiguous non-space characters.
* parses as an int.
* parses to the end of input data.
* parses yes, on, true, 1, 0, false, off, no as a boolean.
* parses like a , except allows "toggle" as well.
* <...> parses according to the parameter type before it, until the end
* of the input data. Results are stored in an array named
* paramnameList, where paramname is the name of the parameter
* before <...>. The value of the parameter before this will be
* paramnameList[0].
*
* If there is no parse function for an argument type, "word" will be used by
* default. You can alias argument types with code like...
* commandManager.argTypes["my-integer-name"] = commandManager.argTypes["int"];
*/
CommandManager.prototype.parseArgumentsRaw =
function parse_parseargsraw (e)
{
var argc = e.command.argNames.length;
function initOptionals()
{
for (var i = 0; i < argc; ++i)
{
if (e.command.argNames[i] != ":" &&
e.command.argNames[i] != "..." &&
!(e.command.argNames[i] in e))
{
e[e.command.argNames[i]] = null;
}
if (e.command.argNames[i] == "...")
{
var paramName = e.command.argNames[i - 1];
if (paramName == ":")
paramName = e.command.argNames[i - 2];
var listName = paramName + "List";
if (!(listName in e))
e[listName] = [ e[paramName] ];
}
}
}
if ("inputData" in e && e.inputData)
{
/* if data has been provided, parse it */
e.unparsedData = e.inputData;
var parseResult;
var currentArg;
e.currentArgIndex = 0;
if (argc)
{
currentArg = e.command.argNames[e.currentArgIndex];
while (e.unparsedData)
{
if (currentArg != ":")
{
if (!this.parseArgument (e, currentArg))
return false;
}
if (++e.currentArgIndex < argc)
currentArg = e.command.argNames[e.currentArgIndex];
else
break;
}
if (e.currentArgIndex < argc && currentArg != ":")
{
/* parse loop completed because it ran out of data. We haven't
* parsed all of the declared arguments, and we're not stopped
* at an optional marker, so we must be missing something
* required... */
e.parseError = getMsg(MSG_ERR_REQUIRED_PARAM,
e.command.argNames[e.currentArgIndex]);
return false;
}
}
if (e.unparsedData)
{
/* parse loop completed with unparsed data, which means we've
* successfully parsed all arguments declared. Whine about the
* extra data... */
display (getMsg(MSG_EXTRA_PARAMS, e.unparsedData), MT_WARN);
}
}
var rv = this.isCommandSatisfied(e);
if (rv)
initOptionals();
return rv;
}
/**
* Returns true if |e| has the properties required to call the command
* |command|.
*
* If |command| is not provided, |e.command| is used instead.
*
* @param e Event object to test against the command.
* @param command Command to test.
*/
CommandManager.prototype.isCommandSatisfied =
function cmgr_isok (e, command)
{
if (typeof command == "undefined")
command = e.command;
else if (typeof command == "string")
command = this.commands[command];
if (!command.enabled)
return false;
for (var i = 0; i < command.argNames.length; ++i)
{
if (command.argNames[i] == ":")
return true;
if (!(command.argNames[i] in e))
{
e.parseError = getMsg(MSG_ERR_REQUIRED_PARAM, command.argNames[i]);
//dd("command '" + command.name + "' unsatisfied: " + e.parseError);
return false;
}
}
//dd ("command '" + command.name + "' satisfied.");
return true;
}
/**
* Internal use only.
* See parseArguments above and the |argTypes| object below.
*
* Parses the next argument by calling an appropriate parser function, or the
* generic "word" parser if none other is found.
*
* @param e event object.
* @param name property name to use for the parse result.
*/
CommandManager.prototype.parseArgument =
function cmgr_parsearg (e, name)
{
var parseResult;
if (name in this.argTypes)
parseResult = this.argTypes[name](e, name, this);
else
parseResult = this.argTypes["word"](e, name, this);
if (!parseResult)
e.parseError = getMsg(MSG_ERR_INVALID_PARAM,
[name, e.unparsedData]);
return parseResult;
}
CommandManager.prototype.argTypes = new Object();
/**
* Convenience function used to map a list of new types to an existing parse
* function.
*/
CommandManager.prototype.argTypes.__aliasTypes__ =
function at_alias (list, type)
{
for (var i in list)
{
this[list[i]] = this[type];
}
}
/**
* Internal use only.
*
* Parses an integer, stores result in |e[name]|.
*/
CommandManager.prototype.argTypes["int"] =
function parse_int (e, name)
{
var ary = e.unparsedData.match (/(\d+)(?:\s+(.*))?$/);
if (!ary)
return false;
e[name] = Number(ary[1]);
e.unparsedData = arrayHasElementAt(ary, 2) ? ary[2] : "";
return true;
}
/**
* Internal use only.
*
* Parses a word, which is defined as a list of nonspace characters.
*
* Stores result in |e[name]|.
*/
CommandManager.prototype.argTypes["word"] =
function parse_word (e, name)
{
var ary = e.unparsedData.match (/(\S+)(?:\s+(.*))?$/);
if (!ary)
return false;
e[name] = ary[1];
e.unparsedData = arrayHasElementAt(ary, 2) ? ary[2] : "";
return true;
}
/**
* Internal use only.
*
* Parses a "state" which can be "true", "on", "yes", or 1 to indicate |true|,
* or "false", "off", "no", or 0 to indicate |false|.
*
* Stores result in |e[name]|.
*/
CommandManager.prototype.argTypes["state"] =
function parse_state (e, name)
{
var ary =
e.unparsedData.match (/(true|on|yes|1|false|off|no|0)(?:\s+(.*))?$/i);
if (!ary)
return false;
if (ary[1].search(/true|on|yes|1/i) != -1)
e[name] = true;
else
e[name] = false;
e.unparsedData = arrayHasElementAt(ary, 2) ? ary[2] : "";
return true;
}
/**
* Internal use only.
*
* Parses a "toggle" which can be "true", "on", "yes", or 1 to indicate |true|,
* or "false", "off", "no", or 0 to indicate |false|. In addition, the string
* "toggle" is accepted, in which case |e[name]| will be the string "toggle".
*
* Stores result in |e[name]|.
*/
CommandManager.prototype.argTypes["toggle"] =
function parse_toggle (e, name)
{
var ary = e.unparsedData.match
(/(toggle|true|on|yes|1|false|off|no|0)(?:\s+(.*))?$/i);
if (!ary)
return false;
if (ary[1].search(/toggle/i) != -1)
e[name] = "toggle";
else if (ary[1].search(/true|on|yes|1/i) != -1)
e[name] = true;
else
e[name] = false;
e.unparsedData = arrayHasElementAt(ary, 2) ? ary[2] : "";
return true;
}
/**
* Internal use only.
*
* Returns all unparsed data to the end of the line.
*
* Stores result in |e[name]|.
*/
CommandManager.prototype.argTypes["rest"] =
function parse_rest (e, name)
{
e[name] = e.unparsedData;
e.unparsedData = "";
return true;
}
/**
* Internal use only.
*
* Parses the rest of the unparsed data the same way the previous argument was
* parsed. Can't be used as the first parameter. if |name| is "..." then the
* name of the previous argument, plus the suffix "List" will be used instead.
*
* Stores result in |e[name]| or |e[lastName + "List"]|.
*/
CommandManager.prototype.argTypes["..."] =
function parse_repeat (e, name, cm)
{
ASSERT (e.currentArgIndex > 0, "<...> can't be the first argument.");
var lastArg = e.command.argNames[e.currentArgIndex - 1];
if (lastArg == ":")
lastArg = e.command.argNames[e.currentArgIndex - 2];
var listName = lastArg + "List";
e[listName] = [ e[lastArg] ];
while (e.unparsedData)
{
if (!cm.parseArgument(e, lastArg))
return false;
e[listName].push(e[lastArg]);
}
e[lastArg] = e[listName][0];
return true;
}
PK
r#0+ + ( content/chatzilla/lib/js/pref-manager.jsUT k@?PVDDUx /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 The JavaScript Debugger
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation
* Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* Contributor(s):
* Robert Ginda, , original author
*
*/
const PREF_RELOAD = true;
const PREF_WRITETHROUGH = true;
const PREF_CHARSET = "utf-8"; // string prefs stored in this charset
function PrefRecord (name, defaultValue, label, help)
{
this.name = name;
this.defaultValue = defaultValue;
this.help = help;
this.label = label ? label : name;
this.realValue = null;
}
function PrefManager (branchName, defaultBundle)
{
var prefManager = this;
function pm_observe (prefService, topic, prefName)
{
var r = prefManager.prefRecords[prefName];
if (!r)
return;
var oldValue = (r.realValue != null) ? r.realValue : r.defaultValue;
r.realValue = prefManager.getPref(prefName, PREF_RELOAD);
prefManager.onPrefChanged(prefName, r.realValue, oldValue);
};
const PREF_CTRID = "@mozilla.org/preferences-service;1";
const nsIPrefService = Components.interfaces.nsIPrefService;
const nsIPrefBranch = Components.interfaces.nsIPrefBranch;
const nsIPrefBranchInternal = Components.interfaces.nsIPrefBranchInternal;
this.prefService =
Components.classes[PREF_CTRID].getService(nsIPrefService);
this.prefBranch = this.prefService.getBranch(branchName);
this.defaultValues = new Object();
this.prefs = new Object();
this.prefNames = new Array();
this.prefRecords = new Object();
this.observer = { observe: pm_observe };
this.prefBranchInternal =
this.prefBranch.QueryInterface(nsIPrefBranchInternal);
this.prefBranchInternal.addObserver("", this.observer, false);
this.defaultBundle = defaultBundle;
this.valid = true;
}
PrefManager.prototype.destroy =
function pm_destroy()
{
if (this.valid)
{
this.prefBranchInternal.removeObserver("", this.observer);
this.valid = false;
}
}
PrefManager.prototype.getBranch =
function pm_getbranch(suffix)
{
return this.prefService.getBranch(this.prefBranch.root + suffix);
}
PrefManager.prototype.getBranchManager =
function pm_getbranchmgr(suffix)
{
return new PrefManager(this.prefBranch.root + suffix);
}
PrefManager.prototype.onPrefChanged =
function pm_changed(prefName, prefManager, topic)
{
/* clients can override this to hear about pref changes */
}
PrefManager.prototype.listPrefs =
function pm_listprefs (prefix)
{
var list = new Array();
var names = this.prefNames;
for (var i = 0; i < names.length; ++i)
{
if (!prefix || names[i].indexOf(prefix) == 0)
list.push (names[i]);
}
return list;
}
PrefManager.prototype.readPrefs =
function pm_readprefs ()
{
const nsIPrefBranch = Components.interfaces.nsIPrefBranch;
var list = this.prefBranch.getChildList("", {});
for (var i = 0; i < list.length; ++i)
{
if (!(list[i] in this))
{
var type = this.prefBranch.getPrefType (list[i]);
var defaultValue;
switch (type)
{
case nsIPrefBranch.PREF_INT:
defaultValue = 0;
break;
case nsIPrefBranch.PREF_BOOL:
defaultValue = false;
break;
default:
defaultValue = "";
}
this.addPref(list[i], defaultValue);
}
}
}
PrefManager.prototype.isKnownPref =
function pm_ispref(prefName)
{
return (prefName in this.prefRecords);
}
PrefManager.prototype.addPrefs =
function pm_addprefs(prefSpecs)
{
for (var i = 0; i < prefSpecs.length; ++i)
{
this.addPref(prefSpecs[i][0], prefSpecs[i][1],
2 in prefSpecs[i] ? prefSpecs[i][2] : null);
}
}
PrefManager.prototype.addDeferredPrefs =
function pm_addprefsd(targetManager, writeThrough)
{
function deferGet(prefName)
{
return targetManager.getPref(prefName);
};
function deferSet(prefName, value)
{
return targetManager.setPref(prefName, value);
};
var setter = null;
if (writeThrough)
setter = deferSet;
var prefs = targetManager.prefs;
for (var i = 0; i < prefs.length; ++i)
this.addPref(prefs[i], deferGet, setter);
}
PrefManager.prototype.updateArrayPref =
function pm_arrayupdate(prefName)
{
var record = this.prefRecords[prefName];
if (!ASSERT(record, "Unknown pref: " + prefName))
return;
if (record.realValue == null)
record.realValue = record.defaultValue;
if (!ASSERT(record.realValue instanceof Array, "Pref is not an array"))
return;
this.prefBranch.setCharPref(prefName, this.arrayToString(record.realValue));
this.prefService.savePrefFile(null);
}
PrefManager.prototype.stringToArray =
function pm_s2a(string)
{
if (string.search(/\S/) == -1)
return [];
var ary = string.split(/\s*;\s*/);
for (var i = 0; i < ary.length; ++i)
ary[i] = toUnicode(unescape(ary[i]), PREF_CHARSET);
return ary;
}
PrefManager.prototype.arrayToString =
function pm_a2s(ary)
{
var escapedAry = new Array()
for (var i = 0; i < ary.length; ++i)
escapedAry[i] = escape(fromUnicode(ary[i], PREF_CHARSET));
return escapedAry.join("; ");
}
PrefManager.prototype.getPref =
function pm_getpref(prefName, reload)
{
var prefManager = this;
function updateArrayPref() { prefManager.updateArrayPref(prefName); };
var record = this.prefRecords[prefName];
if (!ASSERT(record, "Unknown pref: " + prefName))
return null;
var defaultValue;
if (typeof record.defaultValue == "function")
{
// deferred pref, call the getter, and don't cache the result.
defaultValue = record.defaultValue(prefName);
}
else
{
if (!reload && record.realValue != null)
return record.realValue;
defaultValue = record.defaultValue;
}
var realValue = null;
try
{
if (typeof defaultValue == "boolean")
{
realValue = this.prefBranch.getBoolPref(prefName);
}
else if (typeof defaultValue == "number")
{
realValue = this.prefBranch.getIntPref(prefName);
}
else if (defaultValue instanceof Array)
{
realValue = this.prefBranch.getCharPref(prefName);
realValue = this.stringToArray(realValue);
realValue.update = updateArrayPref;
}
else if (typeof defaultValue == "string" ||
defaultValue == null)
{
realValue = toUnicode(this.prefBranch.getCharPref(prefName),
PREF_CHARSET);
}
}
catch (ex)
{
// if the pref doesn't exist, ignore the exception.
}
if (realValue == null)
return defaultValue;
record.realValue = realValue;
return realValue;
}
PrefManager.prototype.setPref =
function pm_setpref(prefName, value)
{
var prefManager = this;
function updateArrayPref() { prefManager.updateArrayPref(prefName); };
var record = this.prefRecords[prefName];
if (!ASSERT(record, "Unknown pref: " + prefName))
return null;
var defaultValue = record.defaultValue;
if (typeof defaultValue == "function")
defaultValue = defaultValue(prefName);
if ((record.realValue == null && value == defaultValue) ||
record.realValue == value)
{
// no realvalue, and value is the same as default value ... OR ...
// no change at all. just bail.
return record.realValue;
}
if (value == defaultValue)
{
this.clearPref(prefName);
return value;
}
if (typeof defaultValue == "boolean")
{
this.prefBranch.setBoolPref(prefName, value);
}
else if (typeof defaultValue == "number")
{
this.prefBranch.setIntPref(prefName, value);
}
else if (defaultValue instanceof Array)
{
var str = this.arrayToString(value);
this.prefBranch.setCharPref(prefName, str);
value.update = updateArrayPref;
}
else
{
this.prefBranch.setCharPref(prefName, fromUnicode(value, PREF_CHARSET));
}
this.prefService.savePrefFile(null);
record.realValue = value;
return value;
}
PrefManager.prototype.clearPref =
function pm_reset(prefName)
{
this.prefRecords[prefName].realValue = null;
this.prefBranch.clearUserPref(prefName);
this.prefService.savePrefFile(null);
}
PrefManager.prototype.addPref =
function pm_addpref(prefName, defaultValue, setter, bundle)
{
var prefManager = this;
if (!bundle)
bundle = this.defaultBundle;
function updateArrayPref() { prefManager.updateArrayPref(prefName); };
function prefGetter() { return prefManager.getPref(prefName); };
function prefSetter(value) { return prefManager.setPref(prefName, value); };
if (!ASSERT(!(prefName in this.defaultValues),
"Preference already exists: " + prefName))
{
return;
}
if (!setter)
setter = prefSetter;
if (defaultValue instanceof Array)
defaultValue.update = updateArrayPref;
var label = getMsgFrom(bundle, "pref." + prefName + ".label", null, name);
var help = getMsgFrom(bundle, "pref." + prefName + ".help", null,
MSG_NO_HELP);
this.prefRecords[prefName] = new PrefRecord (prefName, defaultValue,
label, help);
this.prefNames.push(prefName);
this.prefNames.sort();
this.prefs.__defineGetter__(prefName, prefGetter);
this.prefs.__defineSetter__(prefName, setter);
}
PK
J/j) + content/chatzilla/lib/js/message-manager.jsUT L?PVDDUx /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 The JavaScript Debugger
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation
* Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* Contributor(s):
* Robert Ginda, , original author
*
*/
function MessageManager()
{
const UC_CTRID = "@mozilla.org/intl/scriptableunicodeconverter";
const nsIUnicodeConverter =
Components.interfaces.nsIScriptableUnicodeConverter;
this.ucConverter =
Components.classes[UC_CTRID].getService(nsIUnicodeConverter);
this.defaultBundle = null;
this.bundleList = new Array();
}
MessageManager.prototype.addBundle =
function mm_addbundle(bundlePath, targetWindow)
{
var bundle = srGetStrBundle(bundlePath);
this.bundleList.push(bundle);
this.importBundle(bundle, targetWindow, this.bundleList.length - 1);
return bundle;
}
MessageManager.prototype.importBundle =
function mm_importbundle(bundle, targetWindow, index)
{
const nsIPropertyElement = Components.interfaces.nsIPropertyElement;
if (!targetWindow)
targetWindow = window;
if (typeof index == "undefined")
index = arrayIndexOf(this.bundleList, bundle);
var pfx;
if (index == 0)
pfx = "";
else
pfx = index + ":";
var enumer = bundle.getSimpleEnumeration();
while (enumer.hasMoreElements())
{
var prop = enumer.getNext().QueryInterface(nsIPropertyElement);
var ary = prop.key.match (/^(msg|msn)/);
if (ary)
{
var constValue;
var constName = prop.key.toUpperCase().replace (/\./g, "_");
if (ary[1] == "msn" || prop.value.search(/%(\d+\$)?s/i) != -1)
constValue = pfx + prop.key;
else
constValue = prop.value.replace (/^\"/, "").replace (/\"$/, "");
targetWindow[constName] = constValue;
}
}
if (this.bundleList.length == 1)
this.defaultBundle = bundle;
}
MessageManager.prototype.checkCharset =
function mm_checkset(charset)
{
try
{
this.ucConverter.charset = charset;
}
catch (ex)
{
return false;
}
return true;
}
MessageManager.prototype.toUnicode =
function mm_tounicode(msg, charset)
{
if (!charset)
return msg;
try
{
this.ucConverter.charset = charset;
msg = this.ucConverter.ConvertToUnicode(msg);
}
catch (ex)
{
//dd ("caught exception " + ex + " converting " + msg + " to charset " +
// charset);
}
return msg;
}
MessageManager.prototype.fromUnicode =
function mm_fromunicode(msg, charset)
{
if (!charset)
return msg;
if (charset != this.ucConverter.charset)
this.ucConverter.charset = charset;
try
{
if ("Finish" in this.ucConverter)
{
msg = this.ucConverter.ConvertFromUnicode(msg) +
this.ucConverter.Finish();
}
else
{
msg = this.ucConverter.ConvertFromUnicode(msg + " ");
msg = msg.substr(0, msg.length - 1);
}
}
catch (ex)
{
//dd ("caught exception " + ex + " converting " + msg + " to charset " +
// charset);
}
return msg;
}
MessageManager.prototype.getMsg =
function mm_getmsg (msgName, params, deflt)
{
try
{
var bundle;
var ary = msgName.match (/(\d+):(.+)/);
if (ary)
{
return (this.getMsgFrom(this.bundleList[ary[1]], ary[2], params,
deflt));
}
return this.getMsgFrom(this.bundleList[0], msgName, params, deflt);
}
catch (ex)
{
ASSERT (0, "Caught exception getting message: " + msgName + "/" +
params);
return deflt ? deflt : msgName;
}
}
MessageManager.prototype.getMsgFrom =
function mm_getfrom (bundle, msgName, params, deflt)
{
try
{
var rv;
if (params && params instanceof Array)
rv = bundle.formatStringFromName (msgName, params, params.length);
else if (params || params == 0)
rv = bundle.formatStringFromName (msgName, [params], 1);
else
rv = bundle.GetStringFromName (msgName);
/* strip leading and trailing quote characters, see comment at the
* top of venkman.properties.
*/
rv = rv.replace (/^\"/, "");
rv = rv.replace (/\"$/, "");
return rv;
}
catch (ex)
{
if (typeof deflt == "undefined")
{
ASSERT (0, "caught exception getting value for ``" + msgName +
"''\n" + ex + "\n");
return msgName;
}
return deflt;
}
return null;
}
PK
ft/(`G G ( content/chatzilla/lib/js/menu-manager.jsUT FA?PVDDUx /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 The JavaScript Debugger
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation
* Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation.
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the MPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the MPL or the GPL.
*
* Contributor(s):
* Robert Ginda, , original author
*
*/
function MenuManager (commandManager, menuSpecs, contextFunction, commandStr)
{
var menuManager = this;
this.commandManager = commandManager;
this.menuSpecs = menuSpecs;
this.contextFunction = contextFunction;
this.commandStr = commandStr;
this.onPopupShowing =
function mmgr_onshow (event) { return menuManager.showPopup (event); };
this.onPopupHiding =
function mmgr_onhide (event) { return menuManager.hidePopup (event); };
}
MenuManager.prototype.appendMenuItems =
function mmgr_append(menuId, items)
{
for (var i = 0; i < items.length; ++i)
client.menuSpecs[menuId].items.push(items[i]);
}
MenuManager.prototype.createContextMenus =
function mmgr_initcxs (document)
{
for (var id in this.menuSpecs)
{
if (id.indexOf("context:") == 0)
this.createContextMenu(document, id);
}
}
MenuManager.prototype.createContextMenu =
function mmgr_initcx (document, id)
{
if (!document.getElementById(id))
{
if (!ASSERT(id in this.menuSpecs, "unknown context menu " + id))
return;
var dp = document.getElementById("dynamic-popups");
var popup = this.appendPopupMenu (dp, null, id, id);
var items = this.menuSpecs[id].items;
this.createMenuItems (popup, null, items);
}
}
MenuManager.prototype.createMenus =
function mmgr_createtb(document, menuid)
{
var menu = document.getElementById(menuid);
for (id in this.menuSpecs)
{
var domID;
if ("domID" in this.menuSpecs[id])
domID = this.menuSpecs[id].domID;
else
domID = id;
if (id.indexOf(menuid + ":") == 0)
this.createMenu(menu, null, id, domID);
}
}
MenuManager.prototype.createMainToolbar =
function mmgr_createtb(document, id)
{
var toolbar = document.getElementById(id);
var spec = client.menuSpecs[id];
for (var i in spec.items)
{
this.appendToolbarItem (toolbar, null, spec.items[i]);
}
toolbar.className = "toolbar-primary chromeclass-toolbar";
}
/**
* Internal use only.
*
* Registers event handlers on a given menu.
*/
MenuManager.prototype.hookPopup =
function mmgr_hookpop (node)
{
node.addEventListener ("popupshowing", this.onPopupShowing, false);
node.addEventListener ("popuphiding", this.onPopupHiding, false);
}
/**
* Internal use only.
*
* |showPopup| is called from the "onpopupshowing" event of menus
* managed by the CommandManager. If a command is disabled, represents a command
* that cannot be "satisfied" by the current command context |cx|, or has an
* "enabledif" attribute that eval()s to false, then the menuitem is disabled.
* In addition "checkedif" and "visibleif" attributes are eval()d and
* acted upon accordingly.
*/
MenuManager.prototype.showPopup =
function mmgr_showpop (event)
{
//dd ("showPopup {");
/* returns true if the command context has the properties required to
* execute the command associated with |menuitem|.
*/
function satisfied()
{
if (menuitem.hasAttribute("isSeparator") ||
!menuitem.hasAttribute("commandname"))
{
return true;
}
if (!("menuManager" in cx))
{
dd ("no menuManager in cx");
return false;
}
var name = menuitem.getAttribute("commandname");
var commandManager = cx.menuManager.commandManager;
var commands = commandManager.commands;
if (!ASSERT (name in commands,
"menu contains unknown command '" + name + "'"))
{
return false;
}
var rv = commandManager.isCommandSatisfied(cx, commands[name]);
delete cx.parseError;
return rv;
};
/* Convenience function for "enabledif", etc, attributes. */
function has (prop)
{
return (prop in cx);
};
/* evals the attribute named |attr| on the node |node|. */
function evalIfAttribute (node, attr)
{
var ex;
var expr = node.getAttribute(attr);
if (!expr)
return true;
expr = expr.replace (/\Wand\W/gi, " && ");
try
{
return eval("(" + expr + ")");
}
catch (ex)
{
dd ("caught exception evaling '" + node.getAttribute("id") + "'.'" +
attr + "'\n" + ex);
}
return true;
};
var cx;
var popup = event.originalTarget;
var menuitem = popup.firstChild;
/* If the host provided a |contextFunction|, use it now. Remember the
* return result as this.cx for use if something from this menu is actually
* dispatched. this.cx is deleted in |hidePopup|. */
if (typeof this.contextFunction == "function")
{
cx = this.cx = this.contextFunction (popup.getAttribute("menuName"),
event);
}
else
{
cx = this.cx = { menuManager: this, originalEvent: event };
}
do
{
/* should it be visible? */
if (menuitem.hasAttribute("visibleif"))
{
if (evalIfAttribute(menuitem, "visibleif"))
menuitem.removeAttribute ("hidden");
else
{
menuitem.setAttribute ("hidden", "true");
continue;
}
}
/* it's visible, maybe it has a dynamic label? */
if (menuitem.hasAttribute("format"))
{
var label = replaceVars(menuitem.getAttribute("format"), cx);
if (label.indexOf("\$") != -1)
label = menuitem.getAttribute("backupLabel");
menuitem.setAttribute("label", label);
}
/* ok, it's visible, maybe it should be disabled? */
if (satisfied())
{
if (menuitem.hasAttribute("enabledif"))
{
if (evalIfAttribute(menuitem, "enabledif"))
menuitem.removeAttribute ("disabled");
else
menuitem.setAttribute ("disabled", "true");
}
else
menuitem.removeAttribute ("disabled");
}
else
{
menuitem.setAttribute ("disabled", "true");
}
/* should it have a check? */
if (menuitem.hasAttribute("checkedif"))
{
if (evalIfAttribute(menuitem, "checkedif"))
menuitem.setAttribute ("checked", "true");
else
menuitem.removeAttribute ("checked");
}
} while ((menuitem = menuitem.nextSibling));
//dd ("}");
return true;
}
/**
* Internal use only.
*
* |hidePopup| is called from the "onpopuphiding" event of menus
* managed by the CommandManager. Nothing to do here anymore.
* We used to just clean up this.cx, but that's a problem for nested
* menus.
*/
MenuManager.prototype.hidePopup =
function mmgr_hidepop (id)
{
return true;
}
/**
* Appends a sub-menu to an existing menu.
* @param parentNode DOM Node to insert into
* @param beforeNode DOM Node already contained by parentNode, to insert before
* @param id ID of the sub-menu to add.
* @param label Text to use for this sub-menu. The & character can be
* used to indicate the accesskey.
* @param attribs Object containing CSS attributes to set on the element.
*/
MenuManager.prototype.appendSubMenu =
function mmgr_addsmenu (parentNode, beforeNode, menuName, domId, label, attribs)
{
var document = parentNode.ownerDocument;
/* sometimes the menu is already there, for overlay purposes. */
var menu = document.getElementById(domId);
if (!menu)
{
menu = document.createElement ("menu");
menu.setAttribute ("id", domId);
parentNode.insertBefore(menu, beforeNode);
}
var menupopup = menu.firstChild;
if (!menupopup)
{
menupopup = document.createElement ("menupopup");
menupopup.setAttribute ("id", domId + "-popup");
menu.appendChild(menupopup);
menupopup = menu.firstChild;
}
menupopup.setAttribute ("menuName", menuName);
menu.setAttribute ("accesskey", getAccessKey(label));
label = label.replace("&", "");
menu.setAttribute ("label", label);
menu.setAttribute ("isSeparator", true);
if (typeof attribs == "object")
{
for (var p in attribs)
menu.setAttribute (p, attribs[p]);
}
this.hookPopup (menupopup);
return menupopup;
}
/**
* Appends a popup to an existing popupset.
* @param parentNode DOM Node to insert into
* @param beforeNode DOM Node already contained by parentNode, to insert before
* @param id ID of the popup to add.
* @param label Text to use for this popup. Popup menus don't normally have
* labels, but we set a "label" attribute anyway, in case
* the host wants it for some reason. Any "&" characters will
* be stripped.
* @param attribs Object containing CSS attributes to set on the element.
*/
MenuManager.prototype.appendPopupMenu =
function mmgr_addpmenu (parentNode, beforeNode, menuName, id, label, attribs)
{
var document = parentNode.ownerDocument;
var popup = document.createElement ("popup");
popup.setAttribute ("id", id);
if (label)
popup.setAttribute ("label", label.replace("&", ""));
if (typeof attribs == "object")
{
for (var p in attribs)
popup.setAttribute (p, attribs[p]);
}
popup.setAttribute ("menuName", menuName);
parentNode.insertBefore(popup, beforeNode);
this.hookPopup (popup);
return popup;
}
/**
* Appends a menuitem to an existing menu or popup.
* @param parentNode DOM Node to insert into
* @param beforeNode DOM Node already contained by parentNode, to insert before
* @param command A reference to the CommandRecord this menu item will represent.
* @param attribs Object containing CSS attributes to set on the element.
*/
MenuManager.prototype.appendMenuItem =
function mmgr_addmenu (parentNode, beforeNode, commandName, attribs)
{
var menuManager = this;
var document = parentNode.ownerDocument;
if (commandName == "-")
return this.appendMenuSeparator(parentNode, beforeNode, attribs);
var parentId = parentNode.getAttribute("id");
if (!ASSERT(commandName in this.commandManager.commands,
"unknown command " + commandName + " targeted for " +
parentId))
{
return null;
}
var command = this.commandManager.commands[commandName];
var menuitem = document.createElement ("menuitem");
menuitem.setAttribute ("id", parentId + ":" + commandName);
menuitem.setAttribute ("commandname", command.name);
menuitem.setAttribute ("key", "key:" + command.name);
menuitem.setAttribute ("accesskey", getAccessKey(command.label));
var label = command.label.replace("&", "");
menuitem.setAttribute ("label", label);
if (command.format)
{
menuitem.setAttribute("format", command.format);
menuitem.setAttribute("backupLabel", label);
}
menuitem.setAttribute ("oncommand", this.commandStr);
if (typeof attribs == "object")
{
for (var p in attribs)
menuitem.setAttribute (p, attribs[p]);
}
command.uiElements.push(menuitem);
parentNode.insertBefore (menuitem, beforeNode);
return menuitem;
}
/**
* Appends a menuseparator to an existing menu or popup.
* @param parentNode DOM Node to insert into
* @param beforeNode DOM Node already contained by parentNode, to insert before
* @param attribs Object containing CSS attributes to set on the element.
*/
MenuManager.prototype.appendMenuSeparator =
function mmgr_addsep (parentNode, beforeNode, attribs)
{
var document = parentNode.ownerDocument;
var menuitem = document.createElement ("menuseparator");
menuitem.setAttribute ("isSeparator", true);
if (typeof attribs == "object")
{
for (var p in attribs)
menuitem.setAttribute (p, attribs[p]);
}
parentNode.insertBefore (menuitem, beforeNode);
return menuitem;
}
/**
* Appends a toolbaritem to an existing box element.
* @param parentNode DOM Node to insert into
* @param beforeNode DOM Node already contained by parentNode, to insert before
* @param command A reference to the CommandRecord this toolbaritem will
* represent.
* @param attribs Object containing CSS attributes to set on the element.
*/
MenuManager.prototype.appendToolbarItem =
function mmgr_addtb (parentNode, beforeNode, commandName, attribs)
{
if (commandName == "-")
return this.appendToolbarSeparator(parentNode, beforeNode, attribs);
var parentId = parentNode.getAttribute("id");
if (!ASSERT(commandName in this.commandManager.commands,
"unknown command " + commandName + " targeted for " +
parentId))
{
return null;
}
var command = this.commandManager.commands[commandName];
var document = parentNode.ownerDocument;
var tbitem = document.createElement ("toolbarbutton");
var id = parentNode.getAttribute("id") + ":" + commandName;
tbitem.setAttribute ("id", id);
tbitem.setAttribute ("class", "toolbarbutton-1");
if (command.tip)
tbitem.setAttribute ("tooltiptext", command.tip);
tbitem.setAttribute ("label", command.label.replace("&", ""));
tbitem.setAttribute ("oncommand",
"dispatch('" + commandName + "');");
if (typeof attribs == "object")
{
for (var p in attribs)
tbitem.setAttribute (p, attribs[p]);
}
command.uiElements.push(tbitem);
parentNode.insertBefore (tbitem, beforeNode);
return tbitem;
}
/**
* Appends a toolbarseparator to an existing box.
* @param parentNode DOM Node to insert into
* @param beforeNode DOM Node already contained by parentNode, to insert before
* @param attribs Object containing CSS attributes to set on the element.
*/
MenuManager.prototype.appendToolbarSeparator =
function mmgr_addmenu (parentNode, beforeNode, attribs)
{
var document = parentNode.ownerDocument;
var tbitem = document.createElement ("toolbarseparator");
tbitem.setAttribute ("isSeparator", true);
if (typeof attribs == "object")
{
for (var p in attribs)
tbitem.setAttribute (p, attribs[p]);
}
parentNode.appendChild (tbitem);
return tbitem;
}
/**
* Creates menu DOM nodes from a menu specification.
* @param parentNode DOM Node to insert into
* @param beforeNode DOM Node already contained by parentNode, to insert before
* @param menuSpec array of menu items
*/
MenuManager.prototype.createMenu =
function mmgr_newmenu (parentNode, beforeNode, menuName, domId, attribs)
{
if (typeof domId == "undefined")
domId = menuName;
if (!ASSERT(menuName in this.menuSpecs, "unknown menu name " + menuName))
return null;
var menuSpec = this.menuSpecs[menuName];
var subMenu = this.appendSubMenu (parentNode, beforeNode, menuName, domId,
menuSpec.label, attribs);
this.createMenuItems (subMenu, null, menuSpec.items);
return subMenu;
}
MenuManager.prototype.createMenuItems =
function mmgr_newitems (parentNode, beforeNode, menuItems)
{
function itemAttribs()
{
return (1 in menuItems[i]) ? menuItems[i][1] : null;
};
var parentId = parentNode.getAttribute("id");
for (var i in menuItems)
{
var itemName = menuItems[i][0];
if (itemName[0] == ">")
{
itemName = itemName.substr(1);
if (!ASSERT(itemName in this.menuSpecs,
"unknown submenu " + itemName + " referenced in " +
parentId))
{
continue;
}
this.createMenu (parentNode, beforeNode, itemName,
parentId + ":" + itemName, itemAttribs());
}
else if (itemName in this.commandManager.commands)
{
this.appendMenuItem (parentNode, beforeNode, itemName,
itemAttribs());
}
else if (itemName == "-")
{
this.appendMenuSeparator (parentNode, beforeNode, itemAttribs());
}
else
{
dd ("unknown command " + itemName + " referenced in " + parentId);
}
}
}
PK
Хi0p p content/chatzilla/lib/js/irc.jsUT N@PVDDUx /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 JSIRC Library
*
* The Initial Developer of the Original Code is New Dimensions Consulting,
* Inc. Portions created by New Dimensions Consulting, Inc. are
* Copyright (C) 1999 New Dimenstions Consulting, Inc. All
* Rights Reserved.
*
* Contributor(s):
* Robert Ginda, rginda@ndcico.com, original author
*
****
*
* depends on utils.js, events.js, and connection.js
*
* IRC(RFC 1459) library.
* Contains the following classes:
*
* CIRCNetwork
* Networtk object. Takes care of logging into a "primary" server given a
* list of potential hostnames for an IRC network. (among other things.)
*
* CIRCServer
* Server object. Requires an initialized bsIConnection object for
* communicating with the irc server.
* Server.sayTo queues outgoing PRIVMSGs for sending to the server. Using
* sayTo takes care not to send lines faster than one every 1.5 seconds.
* Server.connection.sendData sends raw lines over the connection, avoiding the
* queue.
*
* CIRCUser
* User objects. Children of server objects.
*
* CIRCChannel
* Channel object. Children of server objects.
*
* CIRCChanMode
* Channel mode object. Children of channel objects
*
* CIRCChanUser
* Channel User objects. Children of channel objects, with __proto__ set
* to a CIRCUser object (automatically.)
*
* 1999-09-15 rginda@ndcico.com v1.0
*
*/
const JSIRC_ERR_NO_SOCKET = "JSIRCE:NS";
const JSIRC_ERR_EXHAUSTED = "JSIRCE:E";
function userIsMe (user)
{
switch (user.TYPE)
{
case "IRCUser":
return (user == user.parent.me);
break;
case "IRCChanUser":
return (user.__proto__ == user.parent.parent.me);
break;
default:
return false;
}
return false;
}
/*
* Attached to event objects in onRawData
*/
function decodeParam(number, charsetOrObject)
{
if (!charsetOrObject)
charsetOrObject = this.currentObject;
var rv = toUnicode(this.params[number], charsetOrObject);
return rv;
}
/*
* irc network
*/
function CIRCNetwork (name, serverList, eventPump)
{
this.name = name;
this.servers = new Object();
this.serverList = new Array();
this.ignoreList = new Object();
this.ignoreMaskCache = new Object();
this.connecting = false;
for (var i = 0; i < serverList.length; ++i)
{
var server = serverList[i];
var password = ("password" in server) ? server.password : null;
this.serverList.push(new CIRCServer(this, server.name, server.port,
password));
}
this.eventPump = eventPump;
if ("onInit" in this)
this.onInit();
}
/** Clients should override this stuff themselves **/
CIRCNetwork.prototype.INITIAL_NICK = "js-irc";
CIRCNetwork.prototype.INITIAL_NAME = "INITIAL_NAME";
CIRCNetwork.prototype.INITIAL_DESC = "INITIAL_DESC";
/* set INITIAL_CHANNEL to "" if you don't want a primary channel */
CIRCNetwork.prototype.INITIAL_CHANNEL = "#jsbot";
CIRCNetwork.prototype.INITIAL_UMODE = "+iw";
CIRCNetwork.prototype.MAX_CONNECT_ATTEMPTS = 5;
CIRCNetwork.prototype.stayingPower = false;
CIRCNetwork.prototype.TYPE = "IRCNetwork";
CIRCNetwork.prototype.getURL =
function net_geturl(target)
{
if (this.serverList.length == 1 &&
this.serverList[0].name == this.name &&
this.serverList[0].port != 6667)
{
return this.serverList[0].getURL(target);
}
if (!target)
target = "";
return "irc://" + ecmaEscape(this.name) + "/" + target;
}
CIRCNetwork.prototype.getUser =
function net_getuser (nick)
{
if ("primServ" in this && this.primServ)
return this.primServ.getUser(nick);
return null;
}
CIRCNetwork.prototype.addServer =
function net_addsrv(host, port, password)
{
this.serverList.push(new CIRCServer(this, host, port, password));
}
CIRCNetwork.prototype.connect =
function net_connect()
{
if ("primServ" in this && this.primServ.isConnected)
return;
this.connectAttempt = 0;
this.nextHost = 0;
var ev = new CEvent("network", "do-connect", this, "onDoConnect");
this.eventPump.addEvent(ev);
}
CIRCNetwork.prototype.quit =
function net_quit (reason)
{
if (this.isConnected())
this.primServ.logout(reason);
}
/*
* Handles a request to connect to a primary server.
*/
CIRCNetwork.prototype.onDoConnect =
function net_doconnect(e)
{
var c;
if ("primServ" in this && this.primServ.isConnected)
return true;
var ev;
if (this.connectAttempt++ >= this.MAX_CONNECT_ATTEMPTS)
{
ev = new CEvent ("network", "error", this, "onError");
ev.server = this;
ev.debug = "Connection attempts exhausted, giving up.";
ev.errorCode = JSIRC_ERR_EXHAUSTED;
this.eventPump.addEvent (ev);
return false;
}
this.connecting = true; /* connection is considered "made" when serve
* sends a 001 message (see server.on001) */
var host = this.nextHost++;
if (host >= this.serverList.length)
{
this.nextHost = 1;
host = 0;
}
ev = new CEvent ("network", "startconnect", this, "onStartConnect");
ev.debug = "Connecting to " + this.serverList[host].name + ":" +
this.serverList[host].port + ", attempt " + this.connectAttempt +
" of " + this.MAX_CONNECT_ATTEMPTS + "...";
ev.host = this.serverList[host].hostname;
ev.port = this.serverList[host].port;
ev.connectAttempt = this.connectAttempt;
this.eventPump.addEvent (ev);
var connected = false;
if (!this.serverList[host].connect())
{
/* connect failed, try again */
ev = new CEvent ("network", "do-connect", this, "onDoConnect");
this.eventPump.addEvent (ev);
}
return true;
}
CIRCNetwork.prototype.isConnected =
function net_connected (e)
{
return ("primServ" in this && this.primServ.isConnected);
}
CIRCNetwork.prototype.ignore =
function net_ignore (hostmask)
{
var input = getHostmaskParts(hostmask);
if (input.mask in this.ignoreList)
return false;
this.ignoreList[input.mask] = input;
this.ignoreMaskCache = new Object();
return true;
}
CIRCNetwork.prototype.unignore =
function net_ignore (hostmask)
{
var input = getHostmaskParts(hostmask);
if (!(input.mask in this.ignoreList))
return false;
delete this.ignoreList[input.mask];
this.ignoreMaskCache = new Object();
return true;
}
/*
* irc server
*/
function CIRCServer (parent, hostname, port, password)
{
var serverName = hostname + ":" + port;
var s;
if (serverName in parent.servers)
{
s = parent.servers[serverName];
}
else
{
s = this;
s.channels = new Object();
s.users = new Object();
}
s.name = serverName;
s.hostname = hostname;
s.port = port;
s.parent = parent;
s.password = password;
s.connection = null;
s.isConnected = false;
s.sendQueue = new Array();
s.lastSend = new Date("1/1/1980");
s.lastPingSent = null;
s.lastPing = null;
s.sendsThisRound = 0;
s.savedLine = "";
s.lag = -1;
s.usersStable = true;
s.supports = null;
s.channelTypes = null;
s.channelModes = null;
s.userModes = null;
parent.servers[serverName] = s;
if ("onInit" in s)
s.onInit();
return s;
}
CIRCServer.prototype.MAX_LINES_PER_SEND = 0; /* unlimited */
CIRCServer.prototype.MS_BETWEEN_SENDS = 1500;
CIRCServer.prototype.READ_TIMEOUT = 100;
CIRCServer.prototype.TOO_MANY_LINES_MSG = "\01ACTION has said too much\01";
CIRCServer.prototype.VERSION_RPLY = "JS-IRC Library v0.01, " +
"Copyright (C) 1999 Robert Ginda; rginda@ndcico.com";
CIRCServer.prototype.DEFAULT_REASON = "no reason";
CIRCServer.prototype.TYPE = "IRCServer";
CIRCServer.prototype.toLowerCase =
function serv_tolowercase(str)
{
/* This is an implementation that lower-cases strings according to the
* prevailing CASEMAPPING setting for the server. Values for this are:
*
* o "ascii": The ASCII characters 97 to 122 (decimal) are defined as
* the lower-case characters of ASCII 65 to 90 (decimal). No other
* character equivalency is defined.
* o "strict-rfc1459": The ASCII characters 97 to 125 (decimal) are
* defined as the lower-case characters of ASCII 65 to 93 (decimal).
* No other character equivalency is defined.
* o "rfc1459": The ASCII characters 97 to 126 (decimal) are defined as
* the lower-case characters of ASCII 65 to 94 (decimal). No other
* character equivalency is defined.
*
*/
function replaceFunction(chr)
{
return String.fromCharCode(chr.charCodeAt(0) + 32);
}
var mapping = "rfc1459";
if (this.supports)
mapping = this.supports.casemapping;
/* NOTE: There are NO breaks in this switch. This is CORRECT.
* Each mapping listed is a super-set of those below, thus we only
* transform the extra characters, and then fall through.
*/
switch (mapping)
{
case "rfc1459":
str = str.replace(/\^/g, replaceFunction);
case "strict-rfc1459":
str = str.replace(/[\[\\\]]/g, replaceFunction);
case "ascii":
str = str.replace(/[A-Z]/g, replaceFunction);
}
return str;
}
CIRCServer.prototype.getURL =
function serv_geturl(target)
{
if (!target)
target = "";
var url = "irc://" + this.hostname;
if (this.port != 6667)
url += ":" + this.port;
url += "/" + target;
if (url.indexOf(".") == -1)
url += ",isserver";
if (this.password)
url += ",needpass";
return url;
}
CIRCServer.prototype.getUser =
function chan_getuser (nick)
{
nick = this.toLowerCase(nick);
if (nick in this.users)
return this.users[nick];
return null;
}
CIRCServer.prototype.connect =
function serv_connect (password)
{
try
{
this.connection = new CBSConnection();
}
catch (ex)
{
ev = new CEvent ("server", "error", this, "onError");
ev.server = this;
ev.debug = "Couldn't create socket :" + ex;
ev.errorCode = JSIRC_ERR_NO_SOCKET;
ev.exception = ex;
this.parent.eventPump.addEvent (ev);
return false;
}
if (this.connection.connect(this.hostname, this.port, null, true, null))
{
var ev = new CEvent("server", "connect", this, "onConnect");
if (password)
this.password = password;
ev.server = this;
this.parent.eventPump.addEvent (ev);
this.isConnected = true;
if (jsenv.HAS_NSPR_EVENTQ)
this.connection.startAsyncRead(this);
else
s.parent.eventPump.addEvent(new CEvent ("server", "poll", s,
"onPoll"));
}
return true;
}
/*
* What to do when the client connects to it's primary server
*/
CIRCServer.prototype.onConnect =
function serv_onconnect (e)
{
this.parent.primServ = e.server;
this.login(this.parent.INITIAL_NICK, this.parent.INITIAL_NAME,
this.parent.INITIAL_DESC);
return true;
}
CIRCServer.prototype.onStreamDataAvailable =
function serv_sda (request, inStream, sourceOffset, count)
{
var ev = new CEvent ("server", "data-available", this,
"onDataAvailable");
ev.line = this.connection.readData(0, count);
/* route data-available as we get it. the data-available handler does
* not do much, so we can probably get away with this without starving
* the UI even under heavy input traffic.
*/
this.parent.eventPump.routeEvent (ev);
}
CIRCServer.prototype.onStreamClose =
function serv_sockdiscon(status)
{
var ev = new CEvent ("server", "disconnect", this, "onDisconnect");
ev.server = this;
ev.disconnectStatus = status;
this.parent.eventPump.addEvent (ev);
}
CIRCServer.prototype.flushSendQueue =
function serv_flush()
{
this.sendQueue.length = 0;
dd("sendQueue flushed.");
return true;
}
CIRCServer.prototype.login =
function serv_login(nick, name, desc)
{
nick = nick.replace(" ", "_");
name = name.replace(" ", "_");
if (!nick)
nick = "nick";
if (!name)
name = nick;
if (!desc)
desc = nick;
this.me = new CIRCUser(this, nick, name);
if (this.password)
this.sendData("PASS " + this.password + "\n");
this.sendData("NICK " + nick + "\n");
this.sendData("USER " + name + " * * :" +
fromUnicode(desc, this) + "\n");
}
CIRCServer.prototype.logout =
function serv_logout(reason)
{
if (reason == null || typeof reason == "undefined")
reason = this.DEFAULT_REASON;
this.quitting = true;
this.connection.sendData("QUIT :" +
fromUnicode(reason, this.parent) + "\n");
this.connection.disconnect();
}
CIRCServer.prototype.addChannel =
function serv_addchan(unicodeName, charset)
{
return new CIRCChannel(this, fromUnicode(unicodeName, charset),
unicodeName);
}
CIRCServer.prototype.addUser =
function serv_addusr (nick, name, host)
{
return new CIRCUser(this, nick, name, host);
}
CIRCServer.prototype.getChannelsLength =
function serv_chanlen()
{
var i = 0;
for (var p in this.channels)
i++;
return i;
}
CIRCServer.prototype.getUsersLength =
function serv_chanlen()
{
var i = 0;
for (var p in this.users)
i++;
return i;
}
CIRCServer.prototype.sendData =
function serv_senddata (msg)
{
this.queuedSendData (msg);
}
CIRCServer.prototype.queuedSendData =
function serv_senddata (msg)
{
if (this.sendQueue.length == 0)
this.parent.eventPump.addEvent (new CEvent ("server", "senddata",
this, "onSendData"));
arrayInsertAt (this.sendQueue, 0, new String(msg));
}
/*
* Takes care not to let more than MAX_LINES_PER_SEND lines out per
* cycle. Cycle's are defined as the time between onPoll calls.
*/
CIRCServer.prototype.messageTo =
function serv_messto (code, target, msg, ctcpCode)
{
var lines = String(msg).split ("\n");
var sendable = 0, i;
var pfx = "", sfx = "";
if (this.MAX_LINES_PER_SEND &&
this.sendsThisRound > this.MAX_LINES_PER_SEND)
return false;
if (ctcpCode)
{
pfx = "\01" + ctcpCode;
sfx = "\01";
}
for (i in lines)
if ((lines[i] != "") || ctcpCode) sendable++;
for (i in lines)
{
if (this.MAX_LINES_PER_SEND && (
((this.sendsThisRound == this.MAX_LINES_PER_SEND - 1) &&
(sendable > this.MAX_LINES_PER_SEND)) ||
this.sendsThisRound == this.MAX_LINES_PER_SEND))
{
this.sendData ("PRIVMSG " + target + " :" +
this.TOO_MANY_LINES_MSG + "\n");
this.sendsThisRound++;
return true;
}
if ((lines[i] != "") || ctcpCode)
{
var line = code + " " + target + " :" + pfx;
this.sendsThisRound++;
if (lines[i] != "")
{
if (ctcpCode)
line += " ";
line += lines[i] + sfx;
}
else
line += sfx;
//dd ("-*- irc sending '" + line + "'");
this.sendData(line + "\n");
}
}
return true;
}
CIRCServer.prototype.sayTo =
function serv_sayto (target, msg)
{
this.messageTo("PRIVMSG", target, msg);
}
CIRCServer.prototype.noticeTo =
function serv_noticeto (target, msg)
{
this.messageTo("NOTICE", target, msg);
}
CIRCServer.prototype.actTo =
function serv_actto (target, msg)
{
this.messageTo("PRIVMSG", target, msg, "ACTION");
}
CIRCServer.prototype.ctcpTo =
function serv_ctcpto (target, code, msg, method)
{
msg = msg || "";
method = method || "PRIVMSG";
code = code.toUpperCase();
if (code == "PING" && !msg)
msg = Number(new Date());
this.messageTo(method, target, msg, code);
}
CIRCServer.prototype.updateLagTimer =
function serv_uptimer()
{
this.connection.sendData("PING :LAGTIMER\n");
this.lastPing = this.lastPingSent = new Date();
}
/**
* Abstracts the whois command.
*
* @param target intended user(s).
*/
CIRCServer.prototype.whois =
function serv_whois (target)
{
this.sendData ("WHOIS " + target + "\n");
}
CIRCServer.prototype.onDisconnect =
function serv_disconnect(e)
{
if ((this.parent.connecting) ||
/* fell off while connecting, try again */
(this.parent.primServ == this) &&
(!("quitting" in this) && this.parent.stayingPower))
{ /* fell off primary server, reconnect to any host in the serverList */
var ev = new CEvent ("network", "do-connect", this.parent,
"onDoConnect");
this.parent.eventPump.addEvent (ev);
}
e.server = this;
e.set = "network";
e.destObject = this.parent;
for (var c in this.channels)
this.channels[c].users = new Object();
this.connection = null;
this.isConnected = false;
delete this.quitting;
return true;
}
CIRCServer.prototype.onSendData =
function serv_onsenddata (e)
{
if (!this.isConnected)
{
dd ("Can't send to disconnected socket");
this.flushSendQueue();
return false;
}
var d = new Date();
this.sendsThisRound = 0;
if (((d - this.lastSend) >= this.MS_BETWEEN_SENDS) &&
this.sendQueue.length > 0)
{
var s = this.sendQueue.pop();
if (s)
{
//dd ("queued send: " + s);
this.connection.sendData (s);
this.lastSend = d;
}
}
else
this.parent.eventPump.addEvent (new CEvent ("event-pump", "yield",
null, ""));
if (this.sendQueue.length > 0)
this.parent.eventPump.addEvent (new CEvent ("server", "senddata",
this, "onSendData"));
return true;
}
CIRCServer.prototype.onPoll =
function serv_poll(e)
{
var lines;
var ex;
var ev;
try
{
line = this.connection.readData(this.READ_TIMEOUT);
}
catch (ex)
{
dd ("*** Caught exception " + ex + " reading from server " +
this.hostname);
if (jsenv.HAS_RHINO && (ex instanceof java.lang.ThreadDeath))
{
dd("### catching a ThreadDeath");
throw(ex);
}
else
{
ev = new CEvent ("server", "disconnect", this, "onDisconnect");
ev.server = this;
ev.reason = "error";
ev.exception = ex;
this.parent.eventPump.addEvent (ev);
return false;
}
}
this.parent.eventPump.addEvent (new CEvent ("server", "poll", this,
"onPoll"));
if (line)
{
ev = new CEvent ("server", "data-available", this, "onDataAvailable");
ev.line = line;
this.parent.eventPump.addEvent (ev);
}
return true;
}
CIRCServer.prototype.onDataAvailable =
function serv_ppline(e)
{
var line = e.line;
if (line == "")
return false;
var incomplete = (line[line.length - 1] != '\n');
var lines = line.split("\n");
if (this.savedLine)
{
lines[0] = this.savedLine + lines[0];
this.savedLine = "";
}
if (incomplete)
this.savedLine = lines.pop();
for (i in lines)
{
var ev = new CEvent("server", "rawdata", this, "onRawData");
ev.data = lines[i].replace(/\r/g, "");
if (ev.data)
this.parent.eventPump.addEvent (ev);
}
return true;
}
/*
* onRawData begins shaping the event by parsing the IRC message at it's
* simplest level. After onRawData, the event will have the following
* properties:
* name value
*
* set............"server"
* type..........."parsedata"
* destMethod....."onParsedData"
* destObject.....server (this)
* server.........server (this)
* connection.....CBSConnection (this.connection)
* source.........the of the message (if it exists)
* user...........user object initialized with data from the message
* params.........array containing the parameters of the message
* code...........the first parameter (most messages have this)
*
* See Section 2.3.1 of RFC 1459 for details on , and
* tokens.
*/
CIRCServer.prototype.onRawData =
function serv_onRawData(e)
{
function makeMaskRegExp(text)
{
function escapeChars(c)
{
if (c == "*")
return ".*";
if (c == "?")
return ".";
return "\\" + c;
}
// Anything that's not alpha-numeric gets escaped.
// "*" and "?" are 'escaped' to ".*" and ".".
// Optimisation; * translates as 'match all'.
return new RegExp("^" + text.replace(/[^\w\d]/g, escapeChars) + "$", "i");
};
function hostmaskMatches(user, mask)
{
// Need to match .nick, .user, and .host.
if (!("nickRE" in mask))
{
// We cache all the regexp objects, but use null if the term is
// just "*", so we can skip having the object *and* the .match
// later on.
if (mask.nick == "*")
mask.nickRE = null;
else
mask.nickRE = makeMaskRegExp(mask.nick);
if (mask.user == "*")
mask.userRE = null;
else
mask.userRE = makeMaskRegExp(mask.user);
if (mask.host == "*")
mask.hostRE = null;
else
mask.hostRE = makeMaskRegExp(mask.host);
}
if ((!mask.nickRE || user.nick.match(mask.nickRE)) &&
(!mask.userRE || user.name.match(mask.userRE)) &&
(!mask.hostRE || user.host.match(mask.hostRE)))
return true;
return false;
};
var ary;
var l = e.data;
if (l.length == 0)
{
dd ("empty line on onRawData?");
return false;
}
if (l[0] == ":")
{
ary = l.match (/:(\S+)\s(.*)/);
e.source = ary[1];
l = ary[2];
ary = e.source.match (/(\S+)!(\S+)@(.*)/);
if (ary)
{
e.user = new CIRCUser(this, ary[1], ary[2], ary[3]);
}
else
{
ary = e.source.match (/(\S+)@(.*)/);
if (ary)
{
e.user = new CIRCUser(this, "", ary[1], ary[2]);
}
}
}
e.ignored = false;
if (("user" in e) && e.user && ("ignoreList" in this.parent))
{
// Assumption: if "ignoreList" is in this.parent, we assume that:
// a) it's an array.
// b) ignoreMaskCache also exists, and
// c) it's an array too.
if (!(e.source in this.parent.ignoreMaskCache))
{
for (var m in this.parent.ignoreList)
{
if (hostmaskMatches(e.user, this.parent.ignoreList[m]))
{
e.ignored = true;
break;
}
}
/* Save this exact source in the cache, with results of tests. */
this.parent.ignoreMaskCache[e.source] = e.ignored;
}
else
{
e.ignored = this.parent.ignoreMaskCache[e.source];
}
}
e.server = this;
var sep = l.indexOf(" :");
if (sep != -1) /* param, if there is one */
{
var trail = l.substr (sep + 2, l.length);
e.params = l.substr(0, sep).split(" ");
e.params[e.params.length] = trail;
}
else
{
e.params = l.split(" ");
}
e.decodeParam = decodeParam;
e.code = e.params[0].toUpperCase();
// Ignore all Privmsg and Notice messages here.
if (e.ignored && ((e.code == "PRIVMSG") || (e.code == "NOTICE")))
return true;
e.type = "parseddata";
e.destObject = this;
e.destMethod = "onParsedData";
return true;
}
/*
* onParsedData forwards to next event, based on |e.code|
*/
CIRCServer.prototype.onParsedData =
function serv_onParsedData(e)
{
e.type = this.toLowerCase(e.code);
if (!e.code[0])
{
dd (dumpObjectTree (e));
return false;
}
e.destMethod = "on" + e.code[0].toUpperCase() +
e.code.substr (1, e.code.length).toLowerCase();
if (typeof this[e.destMethod] == "function")
e.destObject = this;
else if (typeof this["onUnknown"] == "function")
e.destMethod = "onUnknown";
else if (typeof this.parent[e.destMethod] == "function")
{
e.set = "network";
e.destObject = this.parent;
}
else
{
e.set = "network";
e.destObject = this.parent;
e.destMethod = "onUnknown";
}
return true;
}
/* User changed topic */
CIRCServer.prototype.onTopic =
function serv_topic (e)
{
e.channel = new CIRCChannel(this, e.params[1]);
e.channel.topicBy = e.user.properNick;
e.channel.topicDate = new Date();
e.channel.topic = toUnicode(e.params[2], e.channel);
e.destObject = e.channel;
e.set = "channel";
return true;
}
/* Successful login */
CIRCServer.prototype.on001 =
function serv_001 (e)
{
this.parent.connectAttempt = 0;
this.parent.connecting = false;
/* servers wont send a nick change notification if user was forced
* to change nick while logging in (eg. nick already in use.) We need
* to verify here that what the server thinks our name is, matches what
* we think it is. If not, the server wins.
*/
if (e.params[1] != e.server.me.properNick)
{
renameProperty (e.server.users, e.server.me.nick,
this.toLowerCase(e.params[1]));
e.server.me.changeNick(e.params[1]);
}
/* Set up supports defaults here.
* This is so that we don't waste /huge/ amounts of RAM for the network's
* servers just because we know about them. Until we connect, that is.
* These defaults are taken from the draft 005 RPL_ISUPPORTS here:
* http://www.ietf.org/internet-drafts/draft-brocklesby-irc-isupport-02.txt
*/
this.supports = new Object();
this.supports.modes = 3;
this.supports.maxchannels = 10;
this.supports.nicklen = 9;
this.supports.casemapping = "rfc1459";
this.supports.channellen = 200;
this.supports.chidlen = 5;
/* Make sure it's possible to tell if we've actually got a 005 message. */
this.supports.rpl_isupport = false;
this.channelTypes = { '#': true, '&': true };
/* This next one isn't in the isupport draft, but instead is defaulting to
* the codes we understand. It should be noted, some servers include the
* mode characters (o, h, v) in the 'a' list, although the draft spec says
* they should be treated as type 'b'. Luckly, in practise this doesn't
* matter, since both 'a' and 'b' types always take a parameter in the
* MODE message, and parsing is not affected. */
this.channelModes = {
a: ['b'],
b: ['k'],
c: ['l'],
d: ['i', 'm', 'n', 'p', 's', 't']
};
this.userModes = [
{ mode: 'o', symbol: '@' },
{ mode: 'v', symbol: '+' }
];
if (this.parent.INITIAL_UMODE)
{
e.server.sendData("mode " + e.server.me.nick + " :" +
this.parent.INITIAL_UMODE + "\n");
}
if (this.parent.INITIAL_CHANNEL)
{
this.parent.primChan = this.addChannel (this.parent.INITIAL_CHANNEL);
this.parent.primChan.join();
}
this.parent.users = this.users;
e.destObject = this.parent;
e.set = "network";
}
/* server features */
CIRCServer.prototype.on005 =
function serv_005 (e)
{
/* Drop params 0 and 1. */
for (var i = 2; i < e.params.length; i++) {
var itemStr = e.params[i];
/* Items may be of the forms:
* NAME
* -NAME
* NAME=value
* Value may be empty on occasion.
* No value allowed for -NAME items.
*/
var item = itemStr.match(/^(-?)([A-Z]+)(=(.*))?$/i);
if (! item)
continue;
var name = item[2].toLowerCase();
if (("3" in item) && item[3])
{
// And other items are stored as-is, though numeric items
// get special treatment to make our life easier later.
if (("4" in item) && item[4].match(/^\d+$/))
this.supports[name] = Number(item[4]);
else
this.supports[name] = item[4];
}
else
{
// Boolean-type items stored as 'true'.
this.supports[name] = !(("1" in item) && item[1] == "-");
}
}
// Supported 'special' items:
// CHANTYPES (--> channelTypes{}),
// PREFIX (--> userModes[{mode,symbol}]),
// CHANMODES (--> channelModes{a:[], b:[], c:[], d:[]}).
var m;
if ("chantypes" in this.supports)
{
this.channelTypes = [];
for (m = 0; m < this.supports.chantypes.length; m++)
this.channelTypes[this.supports.chantypes[m]] = true;
}
if ("prefix" in this.supports)
{
var mlist = this.supports.prefix.match(/^\((.*)\)(.*)$/i);
if ((! mlist) || (mlist[1].length != mlist[2].length))
{
dd ("** Malformed PREFIX entry in 005 SUPPORTS message **");
}
else
{
this.userModes = [];
for (m = 0; m < mlist[1].length; m++)
this.userModes.push( { mode: mlist[1][m],
symbol: mlist[2][m] } );
}
}
if ("chanmodes" in this.supports)
{
var cmlist = this.supports.chanmodes.split(/,/);
if ((!cmlist) || (cmlist.length < 4))
{
dd ("** Malformed CHANMODES entry in 005 SUPPORTS message **");
}
else
{
// 4 types - list, set-unset-param, set-only-param, flag.
this.channelModes = {
a: cmlist[0].split(''),
b: cmlist[1].split(''),
c: cmlist[2].split(''),
d: cmlist[3].split('')
};
}
}
this.supports.rpl_isupport = true;
e.destObject = this.parent;
e.set = "network";
return true;
}
/* TOPIC reply */
CIRCServer.prototype.on332 =
function serv_332 (e)
{
e.channel = new CIRCChannel (this, e.params[2]);
e.channel.topic = toUnicode(e.params[3], e.channel);
e.destObject = e.channel;
e.set = "channel";
return true;
}
/* whois name */
CIRCServer.prototype.on311 =
function serv_311 (e)
{
e.user = new CIRCUser (this, e.params[2], e.params[3], e.params[4]);
e.user.desc = e.decodeParam(6, e.user);
e.destObject = this.parent;
e.set = "network";
}
/* whois server */
CIRCServer.prototype.on312 =
function serv_312 (e)
{
e.user = new CIRCUser (this, e.params[2]);
e.user.connectionHost = e.params[3];
e.destObject = this.parent;
e.set = "network";
}
/* whois idle time */
CIRCServer.prototype.on317 =
function serv_317 (e)
{
e.user = new CIRCUser (this, e.params[2]);
e.user.idleSeconds = e.params[3];
e.destObject = this.parent;
e.set = "network";
}
/* topic information */
CIRCServer.prototype.on333 =
function serv_333 (e)
{
e.channel = new CIRCChannel (this, e.params[2]);
e.channel.topicBy = e.params[3];
e.channel.topicDate = new Date(Number(e.params[4]) * 1000);
e.destObject = e.channel;
e.set = "channel";
return true;
}
/* who reply */
CIRCServer.prototype.on352 =
function serv_352 (e)
{
e.user = new CIRCUser (this, e.params[6], e.params[3], e.params[4]);
e.user.connectionHost = e.params[5];
if (8 in e.params)
{
var ary = e.params[8].match(/(?:\d+\s)?(.*)/);
e.user.desc = fromUnicode(ary[1], e.user);
}
e.destObject = this.parent;
e.set = "network";
return true;
}
/* end of who */
CIRCServer.prototype.on315 =
function serv_315 (e)
{
e.user = new CIRCUser (this, e.params[2]);
e.destObject = this.parent;
e.set = "network";
return true;
}
/* name reply */
CIRCServer.prototype.on353 =
function serv_353 (e)
{
e.channel = new CIRCChannel (this, e.params[3]);
if (e.channel.usersStable)
{
e.channel.users = new Object();
e.channel.usersStable = false;
}
e.destObject = e.channel;
e.set = "channel";
var nicks = e.params[4].split (" ");
var mList = this.userModes;
for (var n in nicks)
{
var nick = nicks[n];
if (nick == "")
break;
var found = false;
for (var m in mList)
{
if (nick[0] == mList[m].symbol)
{
e.user = new CIRCChanUser (e.channel,
nick.substr(1, nick.length),
[ mList[m].mode ]);
found = true;
break;
}
}
if (!found)
e.user = new CIRCChanUser (e.channel, nick, [ ]);
}
return true;
}
/* end of names */
CIRCServer.prototype.on366 =
function serv_366 (e)
{
e.channel = new CIRCChannel (this, e.params[2]);
e.destObject = e.channel;
e.set = "channel";
e.channel.usersStable = true;
return true;
}
/* channel time stamp? */
CIRCServer.prototype.on329 =
function serv_329 (e)
{
e.channel = new CIRCChannel (this, e.params[2]);
e.destObject = e.channel;
e.set = "channel";
e.channel.timeStamp = new Date (Number(e.params[3]) * 1000);
return true;
}
/* channel mode reply */
CIRCServer.prototype.on324 =
function serv_324 (e)
{
e.channel = new CIRCChannel (this, e.params[2]);
e.destObject = this;
e.type = "chanmode";
e.destMethod = "onChanMode";
return true;
}
/* user changed the mode */
CIRCServer.prototype.onMode =
function serv_mode (e)
{
e.destObject = this;
/* modes are not allowed in +channels -> no need to test that here.. */
if ((e.params[1][0] == "#") || (e.params[1][0] == "&") ||
(e.params[1][0] == "!"))
{
e.channel = new CIRCChannel (this, e.params[1]);
if ("user" in e && e.user)
e.user = new CIRCChanUser (e.channel, e.user.nick);
e.type = "chanmode";
e.destMethod = "onChanMode";
}
else
{
e.type = "usermode";
e.destMethod = "onUserMode";
}
return true;
}
CIRCServer.prototype.onUserMode =
function serv_usermode (e)
{
e.user = new CIRCUser(this.parent, e.params[1])
e.user.modestr = e.params[2];
e.destObject = this.parent;
e.set = "network";
// usermode usually happens on connect, after the MOTD, so it's a good
// place to kick off the lag timer.
this.updateLagTimer();
return true;
}
CIRCServer.prototype.onChanMode =
function serv_chanmode (e)
{
var modifier = "";
var params_eaten = 0;
var BASE_PARAM;
if (e.code.toUpperCase() == "MODE")
BASE_PARAM = 2;
else
if (e.code == "324")
BASE_PARAM = 3;
else
{
dd ("** INVALID CODE in ChanMode event **");
return false;
}
var mode_str = e.params[BASE_PARAM];
params_eaten++;
e.modeStr = mode_str;
e.usersAffected = new Array();
var nick;
var user;
var mList = this.userModes;
for (var i = 0; i < mode_str.length ; i++)
{
/* Take care of modifier first. */
if ((mode_str[i] == '+') || (mode_str[i] == '-'))
{
modifier = mode_str[i];
continue;
}
var done = false;
for (var m in mList)
{
if ((mode_str[i] == mList[m].mode) && (modifier != ""))
{
nick = e.params[BASE_PARAM + params_eaten];
user = new CIRCChanUser (e.channel, nick,
[ modifier + mList[m].mode ]);
params_eaten++;
e.usersAffected.push (user);
done = true;
break;
}
}
if (done)
continue;
switch (mode_str[i])
{
/* user modes */
case "b": /* ban */
var ban = e.params[BASE_PARAM + params_eaten];
params_eaten++;
if ((modifier == "+") &&
(typeof e.channel.bans[ban] == "undefined"))
{
e.channel.bans[ban] = {host: ban};
var ban_evt = new CEvent ("channel", "ban", e.channel,
"onBan");
ban_evt.channel = e.channel;
ban_evt.ban = ban;
ban_evt.source = e.user;
this.parent.eventPump.addEvent (e);
}
else
if (modifier == "-")
delete e.channel.bans[ban];
break;
/* channel modes */
case "l": /* limit */
if (modifier == "+")
{
var limit = e.params[BASE_PARAM + params_eaten];
params_eaten++;
e.channel.mode.limit = limit;
}
else
if (modifier == "-")
e.channel.mode.limit = -1;
break;
case "k": /* key */
var key = e.params[BASE_PARAM + params_eaten];
params_eaten++;
if (modifier == "+")
e.channel.mode.key = key;
else
if (modifier == "-")
e.channel.mode.key = "";
break;
case "m": /* moderated */
if (modifier == "+")
e.channel.mode.moderated = true;
else
if (modifier == "-")
e.channel.mode.moderated = false;
break;
case "n": /* no outside messages */
if (modifier == "+")
e.channel.mode.publicMessages = false;
else
if (modifier == "-")
e.channel.mode.publicMessages = true;
break;
case "t": /* topic */
if (modifier == "+")
e.channel.mode.publicTopic = false;
else
if (modifier == "-")
e.channel.mode.publicTopic = true;
break;
case "i": /* invite */
if (modifier == "+")
e.channel.mode.invite = true;
else
if (modifier == "-")
e.channel.mode.invite = false;
break;
case "s": /* secret */
if (modifier == "+")
e.channel.mode.secret = true;
else
if (modifier == "-")
e.channel.mode.secret = false;
break;
case "p": /* private */
if (modifier == "+")
e.channel.mode.pvt = true;
else
if (modifier == "-")
e.channel.mode.pvt = false;
break;
}
}
e.destObject = e.channel;
e.set = "channel";
return true;
}
CIRCServer.prototype.onNick =
function serv_nick (e)
{
var newNick = e.params[1];
var newKey = this.toLowerCase(newNick);
var oldKey = e.user.nick;
var ev;
renameProperty (this.users, oldKey, newKey);
e.oldNick = e.user.properNick;
e.user.changeNick(newNick);
for (var c in this.channels)
{
if (this.channels[c].active &&
((oldKey in this.channels[c].users) || e.user == this.me))
{
var cuser = this.channels[c].users[oldKey];
renameProperty (this.channels[c].users, oldKey, newKey);
ev = new CEvent ("channel", "nick", this.channels[c],
"onNick");
ev.channel = this.channels[c];
ev.user = cuser;
ev.server = this;
ev.oldNick = e.oldNick;
this.parent.eventPump.addEvent(ev);
}
}
if (e.user == this.me)
{
/* if it was me, tell the network about the nick change as well */
ev = new CEvent ("network", "nick", this.parent, "onNick");
ev.user = e.user;
ev.server = this;
ev.oldNick = e.oldNick;
this.parent.eventPump.addEvent(ev);
}
e.destObject = e.user;
e.set = "user";
return true;
}
CIRCServer.prototype.onQuit =
function serv_quit (e)
{
var reason = e.decodeParam(1);
for (var c in e.server.channels)
{
if (e.server.channels[c].active &&
e.user.nick in e.server.channels[c].users)
{
var ev = new CEvent ("channel", "quit", e.server.channels[c],
"onQuit");
ev.user = e.server.channels[c].users[e.user.nick];
ev.channel = e.server.channels[c];
ev.server = ev.channel.parent;
ev.reason = reason;
this.parent.eventPump.addEvent(ev);
delete e.server.channels[c].users[e.user.nick];
}
}
this.users[e.user.nick].lastQuitMessage = reason;
this.users[e.user.nick].lastQuitDate = new Date();
e.reason = reason;
e.destObject = e.user;
e.set = "user";
return true;
}
CIRCServer.prototype.onPart =
function serv_part (e)
{
e.channel = new CIRCChannel (this, e.params[1]);
e.reason = (e.params.length > 2) ? e.decodeParam(2, e.channel) : "";
e.user = new CIRCChanUser (e.channel, e.user.nick);
if (userIsMe(e.user))
{
e.channel.active = false;
e.channel.joined = false;
}
e.channel.removeUser(e.user.nick);
e.destObject = e.channel;
e.set = "channel";
return true;
}
CIRCServer.prototype.onKick =
function serv_kick (e)
{
e.channel = new CIRCChannel (this, e.params[1]);
e.lamer = new CIRCChanUser (e.channel, e.params[2]);
delete e.channel.users[e.lamer.nick];
if (userIsMe(e.lamer))
{
e.channel.active = false;
e.channel.joined = false;
}
e.reason = e.decodeParam(3, e.channel);
e.destObject = e.channel;
e.set = "channel";
return true;
}
CIRCServer.prototype.onJoin =
function serv_join (e)
{
e.channel = new CIRCChannel (this, e.params[1]);
if (e.user == this.me)
e.server.sendData ("MODE " + e.channel.encodedName + "\n" /* +
"BANS " + e.channel.encodedName + "\n" */);
e.user = new CIRCChanUser (e.channel, e.user.nick);
if (userIsMe(e.user))
{
e.channel.active = true;
e.channel.joined = true;
}
e.destObject = e.channel;
e.set = "channel";
return true;
}
CIRCServer.prototype.onPing =
function serv_ping (e)
{
/* non-queued send, so we can calcualte lag */
this.connection.sendData("PONG :" + e.params[1] + "\n");
this.updateLagTimer();
e.destObject = this.parent;
e.set = "network";
return true;
}
CIRCServer.prototype.onPong =
function serv_pong (e)
{
if (e.params[2] != "LAGTIMER")
return true;
if (this.lastPingSent)
this.lag = roundTo ((new Date() - this.lastPingSent) / 1000, 2);
this.lastPingSent = null;
e.destObject = this.parent;
e.set = "network";
return true;
}
CIRCServer.prototype.onNotice =
function serv_notice (e)
{
if (!("user" in e))
{
e.set = "network";
e.destObject = this.parent;
return true;
}
if ((e.params[1][0] == "#") || (e.params[1][0] == "&") ||
(e.params[1][0] == "+") || (e.params[1][0] == "!"))
{
e.channel = new CIRCChannel(this, e.params[1]);
e.user = new CIRCChanUser (e.channel, e.user.nick);
e.replyTo = e.channel;
e.set = "channel";
}
else if (e.params[2].search (/\x01.*\x01/i) != -1)
{
e.type = "ctcp-reply";
e.destMethod = "onCTCPReply";
e.set = "server";
e.destObject = this;
return true;
}
else
{
e.set = "user";
e.replyTo = e.user; /* send replys to the user who sent the message */
}
e.destObject = e.replyTo;
return true;
}
CIRCServer.prototype.onPrivmsg =
function serv_privmsg (e)
{
/* setting replyTo provides a standard place to find the target for */
/* replys associated with this event. */
if ((e.params[1][0] == "#") || (e.params[1][0] == "&") ||
(e.params[1][0] == "+") || (e.params[1][0] == "!"))
{
e.channel = new CIRCChannel(this, e.params[1]);
e.user = new CIRCChanUser(e.channel, e.user.nick);
e.replyTo = e.channel;
e.set = "channel";
}
else
{
e.set = "user";
e.replyTo = e.user; /* send replys to the user who sent the message */
}
if (e.params[2].search (/\x01.*\x01/i) != -1)
{
e.type = "ctcp";
e.destMethod = "onCTCP";
e.set = "server";
e.destObject = this;
}
else
e.destObject = e.replyTo;
return true;
}
CIRCServer.prototype.onCTCPReply =
function serv_ctcpr (e)
{
var ary = e.params[2].match (/^\x01(\S+) ?(.*)\x01$/i);
if (ary == null)
return false;
e.CTCPData = ary[2] ? ary[2] : "";
e.CTCPCode = ary[1].toLowerCase();
e.type = "ctcp-reply-" + e.CTCPCode;
e.destMethod = "onCTCPReply" + ary[1][0].toUpperCase() +
ary[1].substr (1, ary[1].length).toLowerCase();
if (typeof this[e.destMethod] != "function")
{ /* if there's no place to land the event here, try to forward it */
e.destObject = this.parent;
e.set = "network";
if (typeof e.destObject[e.destMethod] != "function")
{ /* if there's no place to forward it, send it to unknownCTCP */
e.type = "unk-ctcp-reply";
e.destMethod = "onUnknownCTCPReply";
if (e.destMethod in this)
{
e.set = "server";
e.destObject = this;
}
else
{
e.set = "network";
e.destObject = this.parent;
}
}
}
else
e.destObject = this;
return true;
}
CIRCServer.prototype.onCTCP =
function serv_ctcp (e)
{
var ary = e.params[2].match (/^\x01(\S+) ?(.*)\x01$/i);
if (ary == null)
return false;
e.CTCPData = ary[2] ? ary[2] : "";
e.CTCPCode = ary[1].toLowerCase();
if (e.CTCPCode.search (/^reply/i) == 0)
{
dd ("dropping spoofed reply.");
return false;
}
e.type = "ctcp-" + e.CTCPCode;
e.destMethod = "onCTCP" + ary[1][0].toUpperCase() +
ary[1].substr (1, ary[1].length).toLowerCase();
if (typeof this[e.destMethod] != "function")
{ /* if there's no place to land the event here, try to forward it */
e.destObject = e.replyTo;
e.set = (e.replyTo == e.user) ? "user" : "channel";
if (typeof e.replyTo[e.destMethod] != "function")
{ /* if there's no place to forward it, send it to unknownCTCP */
e.type = "unk-ctcp";
e.destMethod = "onUnknownCTCP";
}
}
else
e.destObject = this;
return true;
}
CIRCServer.prototype.onCTCPClientinfo =
function serv_ccinfo (e)
{
var clientinfo = new Array();
for (var fname in this)
{
var ary = fname.match(/^onCTCP(.*)/);
if (ary && ary[1].search(/^Reply/) == -1)
clientinfo.push (ary[1].toUpperCase());
}
e.server.ctcpTo (e.user.nick, "CLIENTINFO", clientinfo.join(" "),
"NOTICE");
return true;
}
CIRCServer.prototype.onCTCPAction =
function serv_cact (e)
{
e.destObject = e.replyTo;
e.set = (e.replyTo == e.user) ? "user" : "channel";
}
CIRCServer.prototype.onCTCPTime =
function serv_cping (e)
{
e.server.ctcpTo (e.user.nick, "TIME", new Date(), "NOTICE");
return true;
}
CIRCServer.prototype.onCTCPVersion =
function serv_cver (e)
{
var lines = e.server.VERSION_RPLY.split ("\n");
for (var i in lines)
e.user.notice ("\01VERSION " + lines[i] + "\01");
e.destObject = e.replyTo;
e.set = (e.replyTo == e.user) ? "user" : "channel";
return true;
}
CIRCServer.prototype.onCTCPPing =
function serv_cping (e)
{
/* non-queued send */
e.server.connection.sendData ("NOTICE " + e.user.nick + " :\01PING " +
e.CTCPData + "\01\n");
e.destObject = e.replyTo;
e.set = (e.replyTo == e.user) ? "user" : "channel";
return true;
}
CIRCServer.prototype.onCTCPDcc =
function serv_dcc (e)
{
var ary = e.CTCPData.match (/(\S+)? ?(.*)/);
e.DCCData = ary[2];
e.type = "dcc-" + ary[1].toLowerCase();
e.destMethod = "onDCC" + ary[1][0].toUpperCase() +
ary[1].substr (1, ary[1].length).toLowerCase();
if (typeof this[e.destMethod] != "function")
{ /* if there's no place to land the event here, try to forward it */
e.destObject = e.replyTo;
e.set = (e.replyTo == e.user) ? "user" : "channel";
}
else
e.destObject = this;
return true;
}
CIRCServer.prototype.onDCCChat =
function serv_dccchat (e)
{
var ary = e.DCCData.match (/(chat) (\d+) (\d+)/i);
if (ary == null)
return false;
e.id = ary[2];
e.port = ary[3];
e.destObject = e.replyTo;
e.set = (e.replyTo == e.user) ? "user" : "channel";
return true;
}
CIRCServer.prototype.onDCCSend =
function serv_dccsend (e)
{
var ary = e.DCCData.match (/(\S+) (\d+) (\d+) (\d+)/);
if (ary == null)
return false;
e.file = ary[1];
e.id = ary[2];
e.port = ary[3];
e.size = ary[4];
e.destObject = e.replyTo;
e.set = (e.replyTo == e.user) ? "user" : "channel";
return true;
}
/*
* channel
*/
function CIRCChannel (parent, encodedName, unicodeName)
{
this.normalizedName = parent.toLowerCase(encodedName);
this.name = this.normalizedName;
if (this.normalizedName in parent.channels)
return parent.channels[this.normalizedName];
this.parent = parent;
this.encodedName = encodedName;
if (unicodeName)
this.unicodeName = unicodeName;
else
this.unicodeName = toUnicode(encodedName, this);
this.users = new Object();
this.bans = new Object();
this.mode = new CIRCChanMode (this);
this.usersStable = true;
/* These next two flags represent a subtle difference in state:
* active - in the channel, from the server's point of view.
* joined - in the channel, from the user's point of view.
* e.g. parting the channel clears both, but being disconnected only
* clears |active| - the user still wants to be in the channel, even
* though they aren't physically able to until we've reconnected.
*/
this.active = false;
this.joined = false;
this.parent.channels[this.normalizedName] = this;
if ("onInit" in this)
this.onInit();
return this;
}
CIRCChannel.prototype.TYPE = "IRCChannel";
CIRCChannel.prototype.topic = "";
CIRCChannel.prototype.getURL =
function chan_geturl ()
{
var target;
if (this.normalizedName.match(/^#[^!+&]/))
target = ecmaEscape(this.normalizedName.substr(1));
else
target = ecmaEscape(this.normalizedName);
return this.parent.parent.getURL(target);
}
CIRCChannel.prototype.addUser =
function chan_adduser (nick, modes)
{
return new CIRCChanUser (this, nick, modes);
}
CIRCChannel.prototype.getUser =
function chan_getuser (nick)
{
nick = this.parent.toLowerCase(nick);
if (nick in this.users)
return this.users[nick];
return null;
}
CIRCChannel.prototype.removeUser =
function chan_removeuser (nick)
{
delete this.users[this.parent.toLowerCase(nick)]; // see ya
}
CIRCChannel.prototype.getUsersLength =
function chan_userslen (mode)
{
var i = 0;
var p;
this.opCount = 0;
this.halfopCount = 0;
this.voiceCount = 0;
if (typeof mode == "undefined")
{
for (p in this.users)
{
if (this.users[p].isOp)
this.opCount++;
if (this.users[p].isHalfOp)
this.halfopCount++;
if (this.users[p].isVoice)
this.voiceCount++;
i++;
}
}
else
{
for (p in this.users)
if (arrayContains(this.users[p].modes, mode))
i++;
}
return i;
}
CIRCChannel.prototype.iAmOp =
function chan_amop()
{
return this.users[this.parent.me.nick].isOp;
}
CIRCChannel.prototype.iAmHalfOp =
function chan_amhalfop()
{
return this.users[this.parent.me.nick].isHalfOp;
}
CIRCChannel.prototype.iAmVoice =
function chan_amvoice()
{
return this.parent.users[this.parent.parent.me.nick].isVoice;
}
CIRCChannel.prototype.setTopic =
function chan_topic (str)
{
this.parent.sendData ("TOPIC " + this.encodedName + " :" +
fromUnicode(str, this) + "\n");
}
CIRCChannel.prototype.say =
function chan_say (msg)
{
this.parent.sayTo(this.encodedName, fromUnicode(msg, this));
}
CIRCChannel.prototype.act =
function chan_say (msg)
{
this.parent.actTo(this.encodedName, fromUnicode(msg, this));
}
CIRCChannel.prototype.notice =
function chan_notice (msg)
{
this.parent.noticeTo(this.encodedName, fromUnicode(msg, this));
}
CIRCChannel.prototype.ctcp =
function chan_ctcpto (code, msg, type)
{
msg = msg || "";
type = type || "PRIVMSG";
this.parent.messageTo(type, this.encodedName, fromUnicode(msg, this), code);
}
CIRCChannel.prototype.join =
function chan_join (key)
{
if (!key)
key = "";
this.parent.sendData ("JOIN " + this.encodedName + " " + key + "\n");
return true;
}
CIRCChannel.prototype.part =
function chan_part ()
{
this.parent.sendData ("PART " + this.encodedName + "\n");
this.users = new Object();
return true;
}
/**
* Invites a user to a channel.
*
* @param nick the user name to invite.
*/
CIRCChannel.prototype.invite =
function chan_inviteuser (nick)
{
this.parent.sendData("INVITE " + nick + " " + this.encodedName + "\n");
return true;
}
/*
* channel mode
*/
function CIRCChanMode (parent)
{
this.parent = parent;
this.limit = -1;
this.key = "";
this.moderated = false;
this.publicMessages = true;
this.publicTopic = true;
this.invite = false;
this.secret = false;
this.pvt = false;
}
CIRCChanMode.prototype.TYPE = "IRCChanMode";
CIRCChanMode.prototype.getModeStr =
function chan_modestr (f)
{
var str = "";
if (this.invite)
str += "i";
if (this.moderated)
str += "m";
if (!this.publicMessages)
str += "n";
if (!this.publicTopic)
str += "t";
if (this.secret)
str += "s";
if (this.pvt)
str += "p";
if (this.key)
str += "k";
if (this.limit != -1)
str += "l " + this.limit;
if (str)
str = "+" + str;
return str;
}
CIRCChanMode.prototype.setMode =
function chanm_mode (modestr)
{
this.parent.parent.sendData ("MODE " + this.parent.encodedName + " " +
modestr + "\n");
return true;
}
CIRCChanMode.prototype.setLimit =
function chanm_limit (n)
{
if ((typeof n == "undefined") || (n <= 0))
{
this.parent.parent.sendData("MODE " + this.parent.encodedName +
" -l\n");
}
else
{
this.parent.parent.sendData("MODE " + this.parent.encodedName + " +l " +
Number(n) + "\n");
}
return true;
}
CIRCChanMode.prototype.lock =
function chanm_lock (k)
{
this.parent.parent.sendData("MODE " + this.parent.encodedName + " +k " +
k + "\n");
return true;
}
CIRCChanMode.prototype.unlock =
function chan_unlock (k)
{
this.parent.parent.sendData("MODE " + this.parent.encodedName + " -k " +
k + "\n");
return true;
}
CIRCChanMode.prototype.setModerated =
function chan_moderate (f)
{
var modifier = (f) ? "+" : "-";
this.parent.parent.sendData("MODE " + this.parent.encodedName + " " +
modifier + "m\n");
return true;
}
CIRCChanMode.prototype.setPublicMessages =
function chan_pmessages (f)
{
var modifier = (f) ? "-" : "+";
this.parent.parent.sendData("MODE " + this.parent.encodedName + " " +
modifier + "n\n");
return true;
}
CIRCChanMode.prototype.setPublicTopic =
function chan_ptopic (f)
{
var modifier = (f) ? "-" : "+";
this.parent.parent.sendData("MODE " + this.parent.encodedName + " " +
modifier + "t\n");
return true;
}
CIRCChanMode.prototype.setInvite =
function chan_invite (f)
{
var modifier = (f) ? "+" : "-";
this.parent.parent.sendData("MODE " + this.parent.encodedName + " " +
modifier + "i\n");
return true;
}
CIRCChanMode.prototype.setPvt =
function chan_pvt (f)
{
var modifier = (f) ? "+" : "-";
this.parent.parent.sendData("MODE " + this.parent.encodedName + " " +
modifier + "p\n");
return true;
}
CIRCChanMode.prototype.setSecret =
function chan_secret (f)
{
var modifier = (f) ? "+" : "-";
this.parent.parent.sendData("MODE " + this.parent.encodedName + " " +
modifier + "s\n");
return true;
}
/*
* user
*/
function CIRCUser (parent, nick, name, host)
{
var properNick = nick;
nick = parent.toLowerCase(nick);
if (nick in parent.users)
{
var existingUser = parent.users[nick];
if (name)
existingUser.name = name;
if (host)
existingUser.host = host;
return existingUser;
}
this.parent = parent;
this.nick = nick;
this.properNick = properNick;
this.name = name;
this.host = host;
this.connectionHost = null;
this.modestr = this.parent.parent.INITIAL_UMODE;
parent.users[nick] = this;
if ("onInit" in this)
this.onInit();
return this;
}
CIRCUser.prototype.TYPE = "IRCUser";
CIRCUser.prototype.getURL =
function usr_geturl ()
{
return this.parent.parent.getURL(this.nick) + ",isnick";
}
CIRCUser.prototype.changeNick =
function usr_changenick (nick)
{
this.properNick = nick;
this.nick = this.parent.toLowerCase(nick);
}
CIRCUser.prototype.getHostMask =
function usr_hostmask (pfx)
{
pfx = (typeof pfx != "undefined") ? pfx : "*!" + this.name + "@*.";
var idx = this.host.indexOf(".");
if (idx == -1)
return pfx + this.host;
return (pfx + this.host.substr(idx + 1, this.host.length));
}
CIRCUser.prototype.say =
function usr_say (msg)
{
this.parent.sayTo(this.nick, fromUnicode(msg, this));
}
CIRCUser.prototype.notice =
function usr_notice (msg)
{
this.parent.noticeTo(this.nick, fromUnicode(msg, this));
}
CIRCUser.prototype.act =
function usr_act (msg)
{
this.parent.actTo(this.nick, fromUnicode(msg, this));
}
CIRCUser.prototype.ctcp =
function usr_ctcp (code, msg, type)
{
msg = msg || "";
type = type || "PRIVMSG";
this.parent.messageTo(type, this.name, fromUnicode(msg, this), code);
}
CIRCUser.prototype.whois =
function usr_whois ()
{
this.parent.whois(this.nick);
}
/*
* channel user
*/
function CIRCChanUser (parent, nick, modes)
{
var properNick = nick;
nick = parent.parent.toLowerCase(nick);
if (nick in parent.users)
{
var existingUser = parent.users[nick];
if (modes)
{
// If we start with a single character mode, assume we're replacing
// the list. (i.e. the list is either all +/- modes, or all normal)
if ((modes.length >= 1) && (modes[0].search(/^[-+]/) == -1))
{
// Modes, but no +/- prefixes, so *replace* mode list.
existingUser.modes = modes;
}
else
{
// We have a +/- mode list, so carefully update the mode list.
for (var m in modes)
{
// This will remove '-' modes, and all other modes will be
// added.
var mode = modes[m][1];
if (modes[m][0] == "-")
{
if (arrayContains(existingUser.modes, mode))
{
var i = arrayIndexOf(existingUser.modes, mode);
arrayRemoveAt(existingUser.modes, i);
}
}
else
{
if (!arrayContains(existingUser.modes, mode))
existingUser.modes.push(mode);
}
}
}
}
existingUser.isOp = (arrayContains(existingUser.modes, "o")) ?
true : false;
existingUser.isHalfOp = (arrayContains(existingUser.modes, "h")) ?
true : false;
existingUser.isVoice = (arrayContains(existingUser.modes, "v")) ?
true : false;
return existingUser;
}
var protoUser = new CIRCUser (parent.parent, properNick);
this.__proto__ = protoUser;
this.getURL = cusr_geturl;
this.setOp = cusr_setop;
this.setHalfOp = cusr_sethalfop;
this.setVoice = cusr_setvoice;
this.setBan = cusr_setban;
this.kick = cusr_kick;
this.kickBan = cusr_kban;
this.say = cusr_say;
this.notice = cusr_notice;
this.act = cusr_act;
this.whois = cusr_whois;
this.parent = parent;
this.TYPE = "IRCChanUser";
this.modes = new Array();
if (typeof modes != "undefined")
this.modes = modes;
this.isOp = (arrayContains(this.modes, "o")) ? true : false;
this.isHalfOp = (arrayContains(this.modes, "h")) ? true : false;
this.isVoice = (arrayContains(this.modes, "v")) ? true : false;
parent.users[nick] = this;
return this;
}
function cusr_geturl ()
{
return this.parent.parent.getURL(ecmaEscape(this.nick)) + ",isnick";
}
function cusr_setop (f)
{
var server = this.parent.parent;
var me = server.me;
var modifier = (f) ? " +o " : " -o ";
server.sendData("MODE " + this.parent.name + modifier + this.nick + "\n");
return true;
}
function cusr_sethalfop (f)
{
var server = this.parent.parent;
var me = server.me;
var modifier = (f) ? " +h " : " -h ";
server.sendData("MODE " + this.parent.name + modifier + this.nick + "\n");
return true;
}
function cusr_setvoice (f)
{
var server = this.parent.parent;
var me = server.me;
var modifier = (f) ? " +v " : " -v ";
server.sendData("MODE " + this.parent.name + modifier + this.nick + "\n");
return true;
}
function cusr_kick (reason)
{
var server = this.parent.parent;
var me = server.me;
reason = typeof reason == "string" ? reason : "";
server.sendData("KICK " + this.parent.encodedName + " " + this.nick + " :" +
fromUnicode(reason, this) + "\n");
return true;
}
function cusr_setban (f)
{
var server = this.parent.parent;
var me = server.me;
if (!this.host)
return false;
var modifier = (f) ? " +b " : " -b ";
modifier += this.getHostMask() + " ";
server.sendData("MODE " + this.parent.name + modifier + "\n");
return true;
}
function cusr_kban (reason)
{
var server = this.parent.parent;
var me = server.me;
if (!this.host)
return false;
reason = (typeof reason != "undefined") ? reason : this.nick;
var modifier = " -o+b " + this.nick + " " + this.getHostMask() + " ";
server.sendData("MODE " + this.parent.encodedName + modifier + "\n" +
"KICK " + this.parent.encodedName + " " +
fromUnicode(this.nick, this) + " :" +
reason + "\n");
return true;
}
function cusr_say (msg)
{
this.__proto__.say (msg);
}
function cusr_notice (msg)
{
this.__proto__.notice (msg);
}
function cusr_act (msg)
{
this.__proto__.act (msg);
}
function cusr_whois ()
{
this.__proto__.whois ();
}
PK
+ % content/chatzilla/lib/js/irc-debug.jsUT